Skip to content

Commit b49a8dc

Browse files
committed
Add support for legacy external mappings -doc-external-doc
1 parent 7acfd78 commit b49a8dc

File tree

5 files changed

+66
-14
lines changed

5 files changed

+66
-14
lines changed

scaladoc/src/dotty/tools/scaladoc/ExternalDocLink.scala

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,31 +18,44 @@ enum DocumentationKind:
1818
case Scaladoc3 extends DocumentationKind
1919

2020
object ExternalDocLink:
21-
def parse(mapping: String): Either[String, ExternalDocLink] =
22-
def fail(msg: String) = Left(s"Unable to process external mapping $mapping. $msg")
21+
private def fail(mapping: String, msg: String) = Left(s"Unable to process external mapping $mapping. $msg")
22+
23+
private def tryParse[T](mapping: String, descr: String)(op: => T): Either[String, T] = Try(op) match {
24+
case Success(v) => Right(v)
25+
case Failure(e) => fail(mapping, s"Unable to parse $descr. Exception $e occured")
26+
}
2327

24-
def tryParse[T](descr: String)(op: => T): Either[String, T] = Try(op) match {
25-
case Success(v) => Right(v)
26-
case Failure(e) => fail(s"Unable to parse $descr. Exception $e occured")
27-
}
28+
def parseLegacy(mapping: String): Either[String, ExternalDocLink] =
29+
mapping.split("#").toList match
30+
case path :: apiUrl :: Nil => for {
31+
url <- tryParse(mapping, "url")(URL(apiUrl))
32+
} yield ExternalDocLink(
33+
List(s"$path.*".r),
34+
url,
35+
DocumentationKind.Scaladoc2,
36+
None
37+
)
38+
case _ => fail(mapping, "Wrong format of legacy external mapping. path#apiUrl format is accepted.")
39+
40+
def parse(mapping: String): Either[String, ExternalDocLink] =
2841

2942
def parsePackageList(elements: List[String]) = elements match
30-
case List(urlStr) => tryParse("packageList")(Some(URL(urlStr)))
43+
case List(urlStr) => tryParse(mapping, "packageList")(Some(URL(urlStr)))
3144
case Nil => Right(None)
32-
case other => fail(s"Provided multiple package lists: $other")
45+
case other => fail(mapping, s"Provided multiple package lists: $other")
3346

3447
def doctoolByName(name: String) = name match
3548
case "javadoc" => Right(DocumentationKind.Javadoc)
3649
case "scaladoc2" => Right(DocumentationKind.Scaladoc2)
3750
case "scaladoc3" => Right(DocumentationKind.Scaladoc3)
38-
case other => fail(s"Unknown doctool: $other")
51+
case other => fail(mapping, s"Unknown doctool: $other")
3952

4053

4154
mapping.split("::").toList match
4255
case regexStr :: docToolStr :: urlStr :: rest =>
4356
for {
44-
regex <- tryParse("regex")(regexStr.r)
45-
url <- tryParse("url")(URL(urlStr))
57+
regex <- tryParse(mapping, "regex")(regexStr.r)
58+
url <- tryParse(mapping, "url")(URL(urlStr))
4659
doctool <- doctoolByName(docToolStr)
4760
packageList <- parsePackageList(rest)
4861
} yield ExternalDocLink(
@@ -52,4 +65,4 @@ object ExternalDocLink:
5265
packageList
5366
)
5467
case _ =>
55-
fail("Accepted format: `regexStr::docToolStr::urlStr[::rest]`")
68+
fail(mapping, "Accepted format: `regexStr::docToolStr::urlStr[::rest]`")

scaladoc/src/dotty/tools/scaladoc/Scaladoc.scala

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ object Scaladoc:
170170
}
171171
}
172172
val legacySourceLinkList = if legacySourceLink.get.nonEmpty then List(legacySourceLink.get) else Nil
173+
173174
val externalMappings =
174175
externalDocumentationMappings.get.flatMap( s =>
175176
ExternalDocLink.parse(s).fold(left => {
@@ -179,6 +180,15 @@ object Scaladoc:
179180
)
180181
)
181182

183+
val legacyExternalMappings =
184+
legacyExternalDocumentationMappings.get.flatMap { s =>
185+
ExternalDocLink.parseLegacy(s).fold(left => {
186+
report.warning(left)
187+
None
188+
}, right => Some(right)
189+
)
190+
}
191+
182192
val socialLinksParsed =
183193
socialLinks.get.flatMap { s =>
184194
SocialLinks.parse(s).fold(left => {
@@ -211,7 +221,7 @@ object Scaladoc:
211221
parseSyntax,
212222
sourceLinks.get ++ legacySourceLinkList,
213223
revision.nonDefault,
214-
externalMappings,
224+
externalMappings ++ legacyExternalMappings,
215225
socialLinksParsed,
216226
skipById.get ++ deprecatedSkipPackages.get,
217227
skipByRegex.get,

scaladoc/src/dotty/tools/scaladoc/ScaladocSettings.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ class ScaladocSettings extends SettingGroup with AllScalaSettings:
5555
"Mapping between regexes matching classpath entries and external documentation. " +
5656
"'regex::[scaladoc|scaladoc|javadoc]::path' syntax is used")
5757

58+
val legacyExternalDocumentationMappings: Setting[List[String]] =
59+
MultiStringSetting("-doc-external-doc", "legacy-external-mappings", "Legacy option from Scala 2. Mapping betweeen path and external documentation. Use -external-mappings instead.")
60+
5861
val socialLinks: Setting[List[String]] =
5962
MultiStringSetting("-social-links", "social-links",
6063
"Links to social sites. '[github|twitter|gitter|discord]::link' syntax is used. " +

scaladoc/src/dotty/tools/scaladoc/tasty/SymOps.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ class SymOpsWithLinkCache:
271271
val extLink = if externalLinkCache.contains(csym.associatedFile)
272272
then externalLinkCache(csym.associatedFile)
273273
else {
274-
val calculatedLink = Option(csym.associatedFile).map(_.path).flatMap { path =>
274+
def calculatePath(file: AbstractFile): String = file.underlyingSource.filter(_ != file).fold("")(f => calculatePath(f) + "/") + file.path
275+
val calculatedLink = Option(csym.associatedFile).map(f => calculatePath(f)).flatMap { path =>
275276
dctx.externalDocumentationLinks.find(_.originRegexes.exists(r => r.matches(path)))
276277
}
277278
externalLinkCache += (csym.associatedFile -> calculatedLink)

scaladoc/test/dotty/tools/scaladoc/ExternalLocationProviderIntegrationTest.scala

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ class Scaladoc3ExternalLocationProviderIntegrationTest extends ExternalLocationP
4545
)
4646
)
4747

48+
class Scaladoc2LegacyExternalLocationProviderIntegrationTest extends LegacyExternalLocationProviderIntegrationTest(
49+
"externalScaladoc2",
50+
List(".*scala.*#https://www.scala-lang.org/api/current/"),
51+
List(
52+
"https://www.scala-lang.org/api/current/scala/util/matching/Regex$$Match.html",
53+
"https://www.scala-lang.org/api/current/scala/Predef$.html#String",
54+
"https://www.scala-lang.org/api/current/scala/collection/immutable/Map.html",
55+
"https://www.scala-lang.org/api/current/scala/collection/IterableOnceOps.html#addString(b:StringBuilder,start:String,sep:String,end:String):StringBuilder",
56+
"https://www.scala-lang.org/api/current/scala/collection/IterableOnceOps.html#mkString(start:String,sep:String,end:String):String"
57+
)
58+
)
59+
4860

4961
abstract class ExternalLocationProviderIntegrationTest(
5062
name: String,
@@ -85,3 +97,16 @@ abstract class ExternalLocationProviderIntegrationTest(
8597
}
8698
} :: Nil
8799

100+
abstract class LegacyExternalLocationProviderIntegrationTest(
101+
name: String,
102+
mappings: Seq[String],
103+
expectedLinks: Seq[String]
104+
) extends ExternalLocationProviderIntegrationTest(name, mappings, expectedLinks):
105+
106+
override def args = super.args.copy(
107+
externalMappings = mappings.flatMap( s =>
108+
ExternalDocLink.parseLegacy(s).fold(left => None, right => Some(right)
109+
)
110+
).toList
111+
)
112+

0 commit comments

Comments
 (0)