@@ -22,6 +22,8 @@ import org.pegdown.Printer
22
22
import org .pegdown .ast .DirectiveNode .Source
23
23
import org .pegdown .ast .{DirectiveNode , Visitor }
24
24
25
+ import scala .util .matching .Regex
26
+
25
27
class ApidocDirective (allClassesAndObjects : IndexedSeq [String ], ctx : Writer .Context ) extends InlineDirective (" apidoc" ) {
26
28
final val JavadocProperty = raw """ javadoc\.(.*)\.base_url """ .r
27
29
final val JavadocBaseUrls = ctx.properties.collect {
@@ -33,16 +35,21 @@ class ApidocDirective(allClassesAndObjects: IndexedSeq[String], ctx: Writer.Cont
33
35
private case class Query (label : Option [String ], pattern : String , generics : String , linkToObject : Boolean ) {
34
36
def scalaLabel (matched : String ): String =
35
37
label match {
36
- case None => matched.split('.' ).last + generics
38
+ case None => matched.split('.' ).last.replace( " $ " , " . " ) + generics
37
39
case Some (la) => la + generics
38
40
}
39
41
42
+ def scalaFqcn (matched : String ): String =
43
+ matched.replace(" $" , " ." )
44
+
40
45
def javaLabel (matched : String ): String =
41
46
scalaLabel(matched)
42
47
.replaceAll(" \\ [" , " <" )
43
48
.replaceAll(" \\ ]" , " >" )
44
49
.replaceAll(" _" , " ?" )
45
50
51
+ def javaFqcn (matched : String ): String = scalaFqcn(matched)
52
+
46
53
override def toString =
47
54
if (linkToObject) pattern + " $" + generics
48
55
else pattern + generics
@@ -77,27 +84,50 @@ class ApidocDirective(allClassesAndObjects: IndexedSeq[String], ctx: Writer.Cont
77
84
case s : Source .Direct => Query (node.label, s.value)
78
85
}
79
86
if (query.pattern.contains('.' )) {
80
- if (allClasses.contains(query.pattern)) {
87
+ val classNameWithDollarForInnerClasses = query.pattern.replaceAll(" (\\ b[A-Z].+)\\ ." , " $1\\ $" )
88
+ if (allClasses.contains(classNameWithDollarForInnerClasses)) {
81
89
renderMatches(query, Seq (query.pattern), node, visitor, printer)
82
- } else
83
- allClasses.filter(_.contains(query.pattern )) match {
90
+ } else {
91
+ allClasses.filter(_.contains(classNameWithDollarForInnerClasses )) match {
84
92
case Seq () =>
85
93
// No matches? then try globbing
86
- val regex = (query.pattern.replaceAll( " \\ . " , " \\\\ . " ).replaceAll( " \\ * " , " .* " ) + " $ " ).r
94
+ val regex = convertToRegex(classNameWithDollarForInnerClasses)
87
95
allClasses.filter(cls => regex.findFirstMatchIn(cls).isDefined) match {
88
96
case Seq () =>
89
- ctx.error(s " Class not found for @apidoc[ $query] " , node)
97
+ ctx.error(s " Class not found for @apidoc[ $query] (pattern $regex ) " , node)
90
98
case results =>
91
99
renderMatches(query, results, node, visitor, printer)
92
100
}
93
101
case results =>
94
102
renderMatches(query, results, node, visitor, printer)
95
103
}
104
+ }
96
105
} else {
97
106
renderMatches(query, allClasses.filter(_.endsWith('.' + query.pattern)), node, visitor, printer)
98
107
}
99
108
}
100
109
110
+ private def convertToRegex (classNameWithDollarForInnerClasses : String ): Regex =
111
+ (classNameWithDollarForInnerClasses
112
+ .replaceAll(" \\ ." , " \\\\ ." )
113
+ .replaceAll(" \\ *" , " .*" )
114
+ .replaceAll(" \\ $" , " \\\\\\ $" ) + " $" ).r
115
+
116
+ private def scaladocNode (
117
+ group : String ,
118
+ label : String ,
119
+ fqcn : String ,
120
+ anchor : String ,
121
+ node : DirectiveNode
122
+ ): DirectiveNode = syntheticNode(group, " scala" , label, fqcn, anchor, node)
123
+
124
+ private def javadocNode (
125
+ label : String ,
126
+ fqcn : String ,
127
+ anchor : String ,
128
+ node : DirectiveNode
129
+ ): DirectiveNode = syntheticNode(" java" , " java" , label, fqcn, anchor, node)
130
+
101
131
private def syntheticNode (
102
132
group : String ,
103
133
doctype : String ,
@@ -147,28 +177,31 @@ class ApidocDirective(allClassesAndObjects: IndexedSeq[String], ctx: Writer.Cont
147
177
)
148
178
case 1 =>
149
179
val pkg = matches(0 )
150
- syntheticNode(" scala" , " scala" , query.scalaLabel(pkg), pkg + scalaClassSuffix, sAnchor, node).accept(visitor)
180
+ scaladocNode(" scala" , query.scalaLabel(pkg), query.scalaFqcn(pkg) + scalaClassSuffix, sAnchor, node)
181
+ .accept(visitor)
151
182
if (hasJavadocUrl(pkg)) {
152
- syntheticNode( " java " , " java " , query.javaLabel(pkg), pkg, jAnchor, node).accept(visitor)
183
+ javadocNode( query.javaLabel(pkg), query.javaFqcn( pkg) , jAnchor, node).accept(visitor)
153
184
} else
154
- syntheticNode(" java" , " scala" , query.scalaLabel(pkg), pkg + scalaClassSuffix, jAnchor, node).accept(visitor)
185
+ scaladocNode(" java" , query.javaLabel(pkg), query.scalaFqcn(pkg) + scalaClassSuffix, jAnchor, node)
186
+ .accept(visitor)
155
187
case 2 if matches.forall(_.contains(" adsl" )) =>
156
188
matches.foreach(pkg => {
157
189
if (! pkg.contains(" javadsl" ))
158
- syntheticNode (" scala" , " scala " , query.scalaLabel(pkg), pkg + scalaClassSuffix, sAnchor, node)
190
+ scaladocNode (" scala" , query.scalaLabel(pkg), query.scalaFqcn( pkg) + scalaClassSuffix, sAnchor, node)
159
191
.accept(visitor)
160
192
if (! pkg.contains(" scaladsl" )) {
161
193
if (hasJavadocUrl(pkg))
162
- syntheticNode( " java " , " java " , query.javaLabel(pkg), pkg, jAnchor, node).accept(visitor)
194
+ javadocNode( query.javaLabel(pkg), query.javaFqcn( pkg) , jAnchor, node).accept(visitor)
163
195
else
164
- syntheticNode (" java" , " scala " , query.scalaLabel (pkg), pkg + scalaClassSuffix, jAnchor, node)
196
+ scaladocNode (" java" , query.javaLabel (pkg), query.scalaFqcn( pkg) + scalaClassSuffix, jAnchor, node)
165
197
.accept(visitor)
166
198
}
167
199
})
168
200
case n =>
169
201
ctx.error(
170
202
s " $n matches found for $query, but not javadsl/scaladsl: ${matches.mkString(" , " )}. " +
171
- s " You may want to use the fully qualified class name as @apidoc[fqcn] instead of @apidoc[ $query]. " ,
203
+ s " You may want to use the fully qualified class name as @apidoc[fqcn] instead of @apidoc[ $query]. " +
204
+ s " For examples see https://github.com/lightbend/sbt-paradox-apidoc#examples " ,
172
205
node
173
206
)
174
207
}
0 commit comments