Skip to content

Commit 3ac9571

Browse files
committed
Add file path escaping to Scaladoc
As Jekyll (and in extension GitHub pages) makes starting a file/folder name with a couple characters illegal, those character are now being replaced with a "$charname" format. Some tests concerning links were adjusted to accomodate the changes.
1 parent d698cba commit 3ac9571

File tree

6 files changed

+30
-13
lines changed

6 files changed

+30
-13
lines changed

scaladoc/src/dotty/tools/scaladoc/renderers/Locations.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ trait Locations(using ctx: DocContext):
4747
case "<empty>" :: tail => "_empty_" :: tail
4848
case other => other
4949
if ctx.args.apiSubdirectory then "api" :: fqn else fqn
50-
cache.put(dri, path)
51-
path
50+
val escapedPath = escapePath(path)
51+
cache.put(dri, escapedPath)
52+
escapedPath
5253
case cached => cached
5354

5455
private def unknownPage(dri: DRI): String =

scaladoc/src/dotty/tools/scaladoc/util/escape.scala

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,19 @@ object Escape:
99
.replace("/", "$div")
1010
.replace("\\", "$bslash")
1111
if escaped != filename then escaped + "$" else escaped
12+
13+
def escapePath(path: Seq[String]) = path.escapeIllegalJekyllChars
14+
15+
/**
16+
* Jekyll (also used by GitHub Pages) by default makes a couple characters
17+
* illegal to use in file name beginnings. Those can be disabled manually,
18+
* however as suggested by #14612 and like supported in Scala 2 scaladoc
19+
* it's better to have those characters escaped here by default.
20+
*/
21+
extension (path: Seq[String]) private def escapeIllegalJekyllChars: Seq[String] =
22+
path.map(
23+
_.replaceAll("^~", "\\$tilde")
24+
.replaceAll("^\\_", "\\$underline")
25+
.replaceAll("^\\.", "\\$dot")
26+
.replaceAll("^\\#", "\\$hash")
27+
)

scaladoc/test/dotty/tools/scaladoc/ReportingTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ class ReportingTest:
8080
)){ diag =>
8181
assertNoWarning(diag)
8282
val Seq(msg) = diag.errorMsgs.map(_.toLowerCase)
83-
Seq("conflict","api", "static", "page", "_docs/tests/adoc.html")
83+
Seq("conflict","api", "static", "page", "$underlinedocs/tests/adoc.html")
8484
.foreach( word =>
8585
Assert.assertTrue(s"Error message: $msg should contains $word", msg.contains(word))
8686
)

scaladoc/test/dotty/tools/scaladoc/renderers/LocationTests.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ class LocationTests:
4444
locations.escapedAbsolutePathWithAnchor(new DRI(location, anchor))
4545

4646
assertEquals(
47-
"scala/%23::.html#abcde",
48-
pathWithAnchor("scala.#::", "abcde")
47+
"scala/$hash%23::.html#abcde",
48+
pathWithAnchor("scala.##::", "abcde")
4949
)
5050

5151
assertEquals(

scaladoc/test/dotty/tools/scaladoc/site/NavigationTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,5 +44,5 @@ class NavigationTest extends BaseHtmlTest:
4444
)),
4545
))
4646

47-
testNavMenu("_docs/Adoc.html", topLevelNav)
47+
testNavMenu("$underlinedocs/Adoc.html", topLevelNav)
4848
}

scaladoc/test/dotty/tools/scaladoc/site/SiteGeneratationTest.scala

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ class SiteGeneratationTest extends BaseHtmlTest:
3232
}
3333

3434
def testDocPages()(using ProjectContext) =
35-
checkFile("_docs/Adoc.html")(title = "Adoc", header = "Header in Adoc", parents = Seq(projectName))
36-
checkFile("_docs/dir/index.html")(title = "A directory", header = "A directory", parents = Seq(projectName))
37-
checkFile("_docs/dir/nested.html")(
35+
checkFile("$underlinedocs/Adoc.html")(title = "Adoc", header = "Header in Adoc", parents = Seq(projectName))
36+
checkFile("$underlinedocs/dir/index.html")(title = "A directory", header = "A directory", parents = Seq(projectName))
37+
checkFile("$underlinedocs/dir/nested.html")(
3838
title = "Nested in a directory", header = "Nested in a directory", parents = Seq(projectName, "A directory"))
3939

4040
def testDocIndexPage()(using ProjectContext) =
41-
checkFile("_docs/index.html")(title = projectName, header = s"$projectName in header")
41+
checkFile("$underlinedocs/index.html")(title = projectName, header = s"$projectName in header")
4242

4343
def testApiPages(
4444
mainTitle: String = "API",
@@ -66,13 +66,13 @@ class SiteGeneratationTest extends BaseHtmlTest:
6666
testDocIndexPage()
6767
testApiPages()
6868

69-
withHtmlFile("_docs/Adoc.html"){ content =>
69+
withHtmlFile("$underlinedocs/Adoc.html"){ content =>
7070
content.assertAttr("p a","href", "../tests/site/SomeClass.html")
7171
}
7272

7373
withHtmlFile("tests/site/SomeClass.html"){ content =>
7474
content.assertAttr(".breadcrumbs a","href",
75-
"../../_docs/index.html", "../../index.html", "../site.html", "SomeClass.html"
75+
"../../$underlinedocs/index.html", "../../index.html", "../site.html", "SomeClass.html"
7676
)
7777
}
7878
}
@@ -98,7 +98,7 @@ class SiteGeneratationTest extends BaseHtmlTest:
9898
@Test
9999
def staticLinking() = withGeneratedSite(testDocPath.resolve("static-links")){
100100

101-
withHtmlFile("_docs/Adoc.html"){ content =>
101+
withHtmlFile("$underlinedocs/Adoc.html"){ content =>
102102
content.assertAttr("p a","href",
103103
"dir/html.html",
104104
"dir/name...with..dots..html",

0 commit comments

Comments
 (0)