Skip to content

Commit 90a6d36

Browse files
authored
Merge pull request #10807 from lampepfl/source-links-fix
Scala3doc: Remove liquid templates from source links generation.
2 parents bf8f04d + 4ffe90f commit 90a6d36

File tree

3 files changed

+45
-43
lines changed

3 files changed

+45
-43
lines changed

project/Build.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1533,7 +1533,7 @@ object Build {
15331533
val projectRoot = (ThisBuild/baseDirectory).value.toPath
15341534
val stdLibRoot = projectRoot.relativize(managedSources.toPath.normalize())
15351535
val scalaSourceLink =
1536-
s"$stdLibRoot=github://scala/scala/v${stdlibVersion(Bootstrapped)}#src/library"
1536+
s"$stdLibRoot=github://scala/scala/v${stdlibVersion(Bootstrapped)}#src/library"
15371537
val sourcesAndRevision = s"-source-links $scalaSourceLink,github://lampepfl/dotty -revision $ref -project-version $projectVersion"
15381538
val cmd = s""" -d $outDir -project "$name" $sourcesAndRevision $params $targets"""
15391539
run.in(Compile).toTask(cmd)

scala3doc/src/dotty/dokka/SourceLinks.scala

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,61 @@ package dotty.dokka
22

33
import java.nio.file.Path
44
import java.nio.file.Paths
5-
import liqp.Template
65
import dotty.dokka.model.api._
76
import dotty.tools.dotc.core.Contexts.Context
7+
import scala.util.matching.Regex
88

99
def pathToString(p: Path) = p.toString.replace('\\', '/')
1010

1111
trait SourceLink:
1212
val path: Option[Path] = None
13-
def render(path: Path, operation: String, line: Option[Int]): String
13+
def render(memberName: String, path: Path, operation: String, line: Option[Int]): String
1414

1515
case class PrefixedSourceLink(val myPath: Path, nested: SourceLink) extends SourceLink:
1616
val myPrefix = pathToString(myPath)
1717
override val path = Some(myPath)
18-
override def render(path: Path, operation: String, line: Option[Int]): String =
19-
nested.render(myPath.relativize(path), operation, line)
18+
override def render(memberName: String, path: Path, operation: String, line: Option[Int]): String =
19+
nested.render(memberName, myPath.relativize(path), operation, line)
2020

2121

22-
case class TemplateSourceLink(val urlTemplate: Template) extends SourceLink:
22+
case class TemplateSourceLink(val urlTemplate: String) extends SourceLink:
2323
override val path: Option[Path] = None
24-
override def render(path: Path, operation: String, line: Option[Int]): String =
25-
val config = java.util.HashMap[String, Object]()
26-
config.put("path", pathToString(path))
27-
line.foreach(l => config.put("line", l.toString))
28-
config.put("operation", operation)
24+
override def render(memberName: String, path: Path, operation: String, line: Option[Int]): String =
25+
val pathString = "/" + pathToString(path)
26+
val mapping = Map(
27+
"\\{\\{ path \\}\\}".r -> pathString,
28+
"\\{\\{ line \\}\\}".r -> line.fold("")(_.toString),
29+
"\\{\\{ ext \\}\\}".r -> Some(
30+
pathString).filter(_.lastIndexOf(".") == -1).fold("")(p => p.substring(p.lastIndexOf("."))
31+
),
32+
"\\{\\{ path_no_ext \\}\\}".r -> Some(
33+
pathString).filter(_.lastIndexOf(".") == -1).fold(pathString)(p => p.substring(0, p.lastIndexOf("."))
34+
),
35+
"\\{\\{ name \\}\\}".r -> memberName
36+
)
37+
mapping.foldLeft(urlTemplate) {
38+
case (sourceLink, (regex, value)) => regex.replaceAllIn(sourceLink, Regex.quoteReplacement(value))
39+
}
2940

30-
urlTemplate.render(config)
3141

3242
case class WebBasedSourceLink(prefix: String, revision: String, subPath: String) extends SourceLink:
3343
override val path: Option[Path] = None
34-
override def render(path: Path, operation: String, line: Option[Int]): String =
44+
override def render(memberName: String, path: Path, operation: String, line: Option[Int]): String =
3545
val action = if operation == "view" then "blob" else operation
3646
val linePart = line.fold("")(l => s"#L$l")
37-
s"$prefix/$action/$revision$subPath/$path$linePart"
47+
s"$prefix/$action/$revision$subPath/${pathToString(path)}$linePart"
3848

3949
object SourceLink:
4050
val SubPath = "([^=]+)=(.+)".r
4151
val KnownProvider = raw"(\w+):\/\/([^\/#]+)\/([^\/#]+)(\/[^\/#]+)?(#.+)?".r
4252
val BrokenKnownProvider = raw"(\w+):\/\/.+".r
43-
val ScalaDocPatten = raw"€\{(TPL_NAME|TPL_NAME|FILE_PATH|FILE_EXT|FILE_LINE|FILE_PATH_EXT)\}".r
53+
val ScalaDocPatten = raw"€\{(TPL_NAME|TPL_OWNER|FILE_PATH|FILE_EXT|FILE_LINE|FILE_PATH_EXT)\}".r
4454
val SupportedScalaDocPatternReplacements = Map(
4555
"€{FILE_PATH_EXT}" -> "{{ path }}",
46-
"€{FILE_LINE}" -> "{{ line }}"
56+
"€{FILE_LINE}" -> "{{ line }}",
57+
"€{TPL_NAME}" -> "{{ name }}",
58+
"€{FILE_EXT}" -> "{{ ext }}",
59+
"€{FILE_PATH}" -> "{{ path_no_ext }}"
4760
)
4861

4962
def githubPrefix(org: String, repo: String) = s"https://github.com/$org/$repo"
@@ -54,10 +67,6 @@ object SourceLink:
5467
private def parseLinkDefinition(s: String): Option[SourceLink] = ???
5568

5669
def parse(string: String, revision: Option[String]): Either[String, SourceLink] =
57-
def asTemplate(template: String) =
58-
try Right(TemplateSourceLink(Template.parse(template))) catch
59-
case e: RuntimeException =>
60-
Left(s"Failed to parse template: ${e.getMessage}")
6170

6271
string match
6372
case KnownProvider(name, organization, repo, rawRevision, rawSubPath) =>
@@ -90,28 +99,28 @@ object SourceLink:
9099
val all = ScalaDocPatten.findAllIn(scaladocSetting)
91100
val (supported, unsupported) = all.partition(SupportedScalaDocPatternReplacements.contains)
92101
if unsupported.nonEmpty then Left(s"Unsupported patterns from scaladoc format are used: ${unsupported.mkString(" ")}")
93-
else asTemplate(supported.foldLeft(string)((template, pattern) =>
94-
template.replace(pattern, SupportedScalaDocPatternReplacements(pattern))))
95-
96-
case template => asTemplate(template)
102+
else Right(TemplateSourceLink(supported.foldLeft(string)((template, pattern) =>
103+
template.replace(pattern, SupportedScalaDocPatternReplacements(pattern)))))
104+
case other =>
105+
Right(TemplateSourceLink(""))
97106

98107

99108
type Operation = "view" | "edit"
100109

101110
case class SourceLinks(links: Seq[SourceLink], projectRoot: Path):
102-
def pathTo(rawPath: Path, line: Option[Int] = None, operation: Operation = "view"): Option[String] =
111+
def pathTo(rawPath: Path, memberName: String = "", line: Option[Int] = None, operation: Operation = "view"): Option[String] =
103112
def resolveRelativePath(path: Path) =
104113
links
105114
.find(_.path.forall(p => path.startsWith(p)))
106-
.map(_.render(path, operation, line))
115+
.map(_.render(memberName, path, operation, line))
107116

108117
if rawPath.isAbsolute then
109118
if rawPath.startsWith(projectRoot) then resolveRelativePath(projectRoot.relativize(rawPath))
110119
else None
111120
else resolveRelativePath(rawPath)
112121

113122
def pathTo(member: Member): Option[String] =
114-
member.sources.flatMap(s => pathTo(Paths.get(s.path), Option(s.lineNumber).map(_ + 1)))
123+
member.sources.flatMap(s => pathTo(Paths.get(s.path), member.name, Option(s.lineNumber).map(_ + 1)))
115124

116125
object SourceLinks:
117126

@@ -130,15 +139,10 @@ object SourceLinks:
130139
| will match https://gitlab.com/$organization/$repository/-/[blob|edit]/$revision[/$subpath]/$filePath[$lineNumber]
131140
| when revision is not provided then requires revision to be specified as argument for scala3doc
132141
| - <scaladoc-template>
133-
| - <template>
134142
|
135143
|<scaladoc-template> is a format for `doc-source-url` parameter scaladoc.
136144
|NOTE: We only supports `€{FILE_PATH_EXT}` and €{FILE_LINE} patterns
137145
|
138-
|<template> is a liqid template string that can accepts follwoing arguments:
139-
| - `operation`: either "view" or "edit"
140-
| - `path`: relative path of file to provide link to
141-
| - `line`: optional parameter that specify line number within a file
142146
|
143147
|
144148
|Template can defined only by subset of sources defined by path prefix represented by `<sub-path>`.

scala3doc/test/dotty/dokka/SourceLinksTests.scala

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ class SourceLinkTest:
1818
testFailure("ala://ma/kota", "known provider")
1919
testFailure("ala=ala=ala://ma/kota", "known provider")
2020
testFailure("ala=ala=ala", "subpath")
21-
testFailure("""{{ ala "ala"}}""", "parse")
22-
testFailure("""€{TPL_NAME}""", "scaladoc")
21+
testFailure("""€{TPL_OWNER}""", "scaladoc")
2322

2423

2524
@Test
@@ -31,7 +30,6 @@ class SourceLinkTest:
3130

3231

3332
Seq(
34-
"""https://github.com/organization/repo/{{ operation | replace: "view", "blob" }}/$revision/{{ path }}{{ line | prepend: "L#"}}""",
3533
"github://lampepfl/dotty",
3634
"gitlab://lampepfl/dotty",
3735
"https://github.com/scala/scala/blob/2.13.x€{FILE_PATH_EXT}#€{FILE_LINE}"
@@ -124,14 +122,14 @@ class SourceLinksTest:
124122
("project/Build.scala", 54, edit) -> "https://gitlab.com/lampepfl/dotty/-/edit/develop/project/Build.scala#L54",
125123
)
126124

127-
testLink(Seq("/{{operation}}/{{path}}#{{line}}"), Some("develop"))(
128-
"project/Build.scala" -> "/view/project/Build.scala#",
129-
("project/Build.scala", 54) -> "/view/project/Build.scala#54",
130-
("project/Build.scala", edit) -> "/edit/project/Build.scala#",
131-
("project/Build.scala", 54, edit) -> "/edit/project/Build.scala#54",
125+
testLink(Seq("€{FILE_PATH}#€{FILE_LINE}"), Some("develop"))(
126+
"project/Build.scala" -> "/project/Build.scala#",
127+
("project/Build.scala", 54) -> "/project/Build.scala#54",
128+
("project/Build.scala", edit) -> "/project/Build.scala#",
129+
("project/Build.scala", 54, edit) -> "/project/Build.scala#54",
132130
)
133131

134-
testLink(Seq("https://github.com/scala/scala/blob/2.13.x/€{FILE_PATH_EXT}#L€{FILE_LINE}"), Some("develop"))(
132+
testLink(Seq("https://github.com/scala/scala/blob/2.13.x€{FILE_PATH_EXT}#L€{FILE_LINE}"), Some("develop"))(
135133
"project/Build.scala" -> "https://github.com/scala/scala/blob/2.13.x/project/Build.scala#L",
136134
("project/Build.scala", 54) -> "https://github.com/scala/scala/blob/2.13.x/project/Build.scala#L54",
137135
("project/Build.scala", edit) -> "https://github.com/scala/scala/blob/2.13.x/project/Build.scala#L",
@@ -151,12 +149,12 @@ class SourceLinksTest:
151149
@Test
152150
def prefixedPaths =
153151
testLink(Seq(
154-
"src/generated=/{{operation}}/{{path}}#{{line}}",
152+
"src/generated=€{FILE_PATH}#€{FILE_LINE}",
155153
"src=gitlab://lampepfl/dotty",
156154
"github://lampepfl/dotty"
157155
), Some("develop"))(
158156
("project/Build.scala", 54, edit) -> "https://github.com/lampepfl/dotty/edit/develop/project/Build.scala#L54",
159157
("src/lib/core.scala", 33, edit) -> "https://gitlab.com/lampepfl/dotty/-/edit/develop/lib/core.scala#L33",
160158
("src/generated.scala", 33, edit) -> "https://gitlab.com/lampepfl/dotty/-/edit/develop/generated.scala#L33",
161-
("src/generated/template.scala", 1, edit) -> "/edit/template.scala#1"
159+
("src/generated/template.scala", 1, edit) -> "/template.scala#1"
162160
)

0 commit comments

Comments
 (0)