@@ -6,7 +6,7 @@ import scala.util.matching.Regex
6
6
7
7
import org .jetbrains .dokka .pages .{RootPageNode , PageNode , ContentPage , ContentText , ContentNode , ContentComposite }
8
8
9
- import dotty .dokka .model .api .Link
9
+ import dotty .dokka .model .api ._
10
10
11
11
private enum Signature :
12
12
case Expected (name : String , signature : String )
@@ -17,7 +17,8 @@ abstract class SignatureTest(
17
17
testName : String ,
18
18
signatureKinds : Seq [String ],
19
19
sourceFiles : List [String ] = Nil ,
20
- ignoreMissingSignatures : Boolean = false
20
+ ignoreMissingSignatures : Boolean = false ,
21
+ filterFunc : (Member ) => Boolean = _ => true
21
22
) extends ScaladocTest (testName):
22
23
override def assertions = Assertion .AfterPagesTransformation { root =>
23
24
val sources = sourceFiles match
@@ -63,63 +64,64 @@ abstract class SignatureTest(
63
64
64
65
} :: Nil
65
66
67
+ // e.g. to remove '(0)' from object IAmACaseObject extends CaseImplementThis/*<-*/(0)/*->*/
68
+ private val commentRegex = raw " \/\*<-\*\/[^\/]+\/\*->\*\/ " .r
69
+ private val whitespaceRegex = raw " \s+ " .r
70
+ private val expectedRegex = raw " .+//expected: (.+) " .r
71
+ private val unexpectedRegex = raw " (.+)//unexpected " .r
72
+ private val identifierRegex = raw " ^\s*(`.*`|(?:\w+)(?:_[^\[\(\s]+)|\w+|[^\[\(\s]+) " .r
73
+
74
+ private def findMissingSingatures (expected : Seq [String ], actual : Seq [String ]): Set [String ] =
75
+ expected.toSet &~ actual.toSet
76
+
77
+ extension (s : String ):
78
+ private def startWithAnyOfThese (c : String * ) = c.exists(s.startsWith)
79
+ private def compactWhitespaces = whitespaceRegex.replaceAllIn(s, " " )
80
+
81
+ private def findName (signature : String , kinds : Seq [String ]): Option [String ] =
82
+ for
83
+ kindMatch <- kinds.flatMap(k => s " \\ b $k\\ b " .r.findFirstMatchIn(signature)).headOption
84
+ afterKind <- Option (kindMatch.after(0 )) // to filter out nulls
85
+ nameMatch <- identifierRegex.findFirstMatchIn(afterKind)
86
+ yield nameMatch.group(1 )
87
+
88
+ private def signaturesFromSources (source : Source , kinds : Seq [String ]): Seq [Signature ] =
89
+ source.getLines.map(_.trim)
90
+ .filterNot(_.isEmpty)
91
+ .filterNot(_.startWithAnyOfThese(" =" ," :" ," {" ," }" , " //" ))
92
+ .toSeq
93
+ .flatMap {
94
+ case unexpectedRegex(signature) => findName(signature, kinds).map(Unexpected (_))
95
+ case expectedRegex(signature) => findName(signature, kinds).map(Expected (_, signature))
96
+ case signature =>
97
+ findName(signature, kinds).map(Expected (_, commentRegex.replaceAllIn(signature, " " ).compactWhitespaces))
98
+ }
99
+
100
+ private def signaturesFromDocumentation (root : PageNode ): Seq [String ] =
101
+ def flattenToText (node : ContentNode ) : Seq [String ] = node match
102
+ case t : ContentText => Seq (t.getText)
103
+ case c : ContentComposite =>
104
+ c.getChildren.asScala.flatMap(flattenToText).toSeq
105
+ case l : DocumentableElement =>
106
+ (l.annotations ++ Seq (" " ) ++ l.modifiers ++ Seq (l.name) ++ l.signature).map {
107
+ case s : String => s
108
+ case Link (s : String , _) => s
109
+ }
110
+ case _ => Seq ()
111
+
112
+ def all (p : ContentNode => Boolean )(n : ContentNode ): Seq [ContentNode ] =
113
+ if p(n) then Seq (n) else n.getChildren.asScala.toSeq.flatMap(all(p))
114
+
115
+ extension (page : PageNode ) def allPages : List [PageNode ] = page :: page.getChildren.asScala.toList.flatMap(_.allPages)
116
+
117
+ val nodes = root.allPages
118
+ .collect { case p : ContentPage => p }
119
+ .filter( p => Option (p.getDocumentable).map(filterFunc).getOrElse(true ))
120
+ .flatMap(p => all(_.isInstanceOf [DocumentableElement ])(p.getContent))
121
+ nodes.map(flattenToText(_).mkString.compactWhitespaces.trim)
122
+
66
123
object SignatureTest {
67
124
val classlikeKinds = Seq (" class" , " object" , " trait" , " enum" ) // TODO add docs for packages
68
125
val members = Seq (" type" , " def" , " val" , " var" )
69
126
val all = classlikeKinds ++ members
70
127
}
71
-
72
- // e.g. to remove '(0)' from object IAmACaseObject extends CaseImplementThis/*<-*/(0)/*->*/
73
- private val commentRegex = raw " \/\*<-\*\/[^\/]+\/\*->\*\/ " .r
74
- private val whitespaceRegex = raw " \s+ " .r
75
- private val expectedRegex = raw " .+//expected: (.+) " .r
76
- private val unexpectedRegex = raw " (.+)//unexpected " .r
77
- private val identifierRegex = raw " ^\s*(`.*`|(?:\w+)(?:_[^\[\(\s]+)|\w+|[^\[\(\s]+) " .r
78
-
79
- private def findMissingSingatures (expected : Seq [String ], actual : Seq [String ]): Set [String ] =
80
- expected.toSet &~ actual.toSet
81
-
82
- extension (s : String ):
83
- private def startWithAnyOfThese (c : String * ) = c.exists(s.startsWith)
84
- private def compactWhitespaces = whitespaceRegex.replaceAllIn(s, " " )
85
-
86
- private def findName (signature : String , kinds : Seq [String ]): Option [String ] =
87
- for
88
- kindMatch <- kinds.flatMap(k => s " \\ b $k\\ b " .r.findFirstMatchIn(signature)).headOption
89
- afterKind <- Option (kindMatch.after(0 )) // to filter out nulls
90
- nameMatch <- identifierRegex.findFirstMatchIn(afterKind)
91
- yield nameMatch.group(1 )
92
-
93
- private def signaturesFromSources (source : Source , kinds : Seq [String ]): Seq [Signature ] =
94
- source.getLines.map(_.trim)
95
- .filterNot(_.isEmpty)
96
- .filterNot(_.startWithAnyOfThese(" =" ," :" ," {" ," }" , " //" ))
97
- .toSeq
98
- .flatMap {
99
- case unexpectedRegex(signature) => findName(signature, kinds).map(Unexpected (_))
100
- case expectedRegex(signature) => findName(signature, kinds).map(Expected (_, signature))
101
- case signature =>
102
- findName(signature, kinds).map(Expected (_, commentRegex.replaceAllIn(signature, " " ).compactWhitespaces))
103
- }
104
-
105
- private def signaturesFromDocumentation (root : PageNode ): Seq [String ] =
106
- def flattenToText (node : ContentNode ) : Seq [String ] = node match
107
- case t : ContentText => Seq (t.getText)
108
- case c : ContentComposite =>
109
- c.getChildren.asScala.flatMap(flattenToText).toSeq
110
- case l : DocumentableElement =>
111
- (l.annotations ++ Seq (" " ) ++ l.modifiers ++ Seq (l.name) ++ l.signature).map {
112
- case s : String => s
113
- case Link (s : String , _) => s
114
- }
115
- case _ => Seq ()
116
-
117
- def all (p : ContentNode => Boolean )(n : ContentNode ): Seq [ContentNode ] =
118
- if p(n) then Seq (n) else n.getChildren.asScala.toSeq.flatMap(all(p))
119
-
120
- extension (page : PageNode ) def allPages : List [PageNode ] = page :: page.getChildren.asScala.toList.flatMap(_.allPages)
121
-
122
- val nodes = root.allPages
123
- .collect { case p : ContentPage => p }
124
- .flatMap(p => all(_.isInstanceOf [DocumentableElement ])(p.getContent))
125
- nodes.map(flattenToText(_).mkString.compactWhitespaces.trim)
0 commit comments