Skip to content

Commit daa9934

Browse files
authored
Refactor: Improve error messaging in sidebar YAML parser (#17229)
Fixes: #15326
1 parent d1af75d commit daa9934

File tree

2 files changed

+108
-8
lines changed

2 files changed

+108
-8
lines changed

Diff for: scaladoc/src/dotty/tools/scaladoc/site/SidebarParser.scala

+23-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import com.fasterxml.jackson.core.`type`.TypeReference;
77
import scala.jdk.CollectionConverters._
88
import java.util.Optional
99
import scala.beans._
10+
import java.nio.file.{Files, Paths}
11+
import scala.io.Source
1012

1113
enum Sidebar:
1214
case Category(
@@ -30,16 +32,31 @@ object Sidebar:
3032

3133
private object RawInputTypeRef extends TypeReference[RawInput]
3234

33-
private def toSidebar(r: RawInput)(using CompilerContext): Sidebar = r match
35+
private def toSidebar(r: RawInput, content: String | java.io.File)(using CompilerContext): Sidebar = r match
3436
case RawInput(title, page, index, subsection, dir, hidden) if page.nonEmpty && index.isEmpty && subsection.isEmpty() =>
37+
val sidebarPath = content match
38+
case s: String => Paths.get(s)
39+
case f: java.io.File => f.toPath()
40+
val basePath = sidebarPath.getParent().resolve("_docs")
41+
val pagePath = basePath.resolve(page)
42+
if !Files.exists(pagePath) then
43+
report.error(s"Page $page does not exist.")
3544
Sidebar.Page(Option.when(title.nonEmpty)(title), page, hidden)
3645
case RawInput(title, page, index, subsection, dir, hidden) if page.isEmpty && (!subsection.isEmpty() || !index.isEmpty()) =>
37-
Sidebar.Category(Option.when(title.nonEmpty)(title), Option.when(index.nonEmpty)(index), subsection.asScala.map(toSidebar).toList, Option.when(dir.nonEmpty)(dir))
46+
Sidebar.Category(Option.when(title.nonEmpty)(title), Option.when(index.nonEmpty)(index), subsection.asScala.map(toSidebar(_, content)).toList, Option.when(dir.nonEmpty)(dir))
3847
case RawInput(title, page, index, subsection, dir, hidden) =>
39-
report.error(s"Error parsing YAML configuration file.\n$schemaMessage")
48+
if title.isEmpty() && index.isEmpty() then
49+
val msg = "`title` property is missing for some page."
50+
report.error(s"$msg\n$schemaMessage")
51+
else if title.nonEmpty && (page.isEmpty() || index.isEmpty()) then
52+
val msg = s"Error parsing YAML configuration file: 'index' or 'page' path is missing for title '$title'."
53+
report.error(s"$msg\n$schemaMessage")
54+
else
55+
val msg = "Problem when parsing YAML configuration file."
56+
report.warning(s"$msg\n$schemaMessage")
4057
Sidebar.Page(None, page, hidden)
4158

42-
private def schemaMessage: String =
59+
def schemaMessage: String =
4360
s"""Static site YAML configuration file should comply with the following description:
4461
|The root element of static site needs to be <subsection>
4562
|`title` and `directory` properties are ignored in root subsection.
@@ -57,8 +74,7 @@ object Sidebar:
5774
| hidden: <boolean> # optional - Default value is false.
5875
|
5976
|For more information visit:
60-
|https://docs.scala-lang.org/scala3/guides/scaladoc/static-site.html
61-
|""".stripMargin
77+
|https://docs.scala-lang.org/scala3/guides/scaladoc/static-site.html""".stripMargin
6278

6379
def load(content: String | java.io.File)(using CompilerContext): Sidebar.Category =
6480
import scala.util.Try
@@ -75,7 +91,7 @@ object Sidebar:
7591
},
7692
identity
7793
)
78-
toSidebar(root) match
94+
toSidebar(root, content) match
7995
case c: Sidebar.Category => c
8096
case _ =>
8197
report.error(s"Root element is not a subsection.\n$schemaMessage")

Diff for: scaladoc/test/dotty/tools/scaladoc/site/SidebarParserTest.scala

+85-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@ package site
33

44
import org.junit.Test
55
import org.junit.Assert._
6+
import dotty.tools.scaladoc.site.Sidebar
7+
import dotty.tools.scaladoc.site.Sidebar.RawInput
8+
import java.io.ByteArrayOutputStream
9+
import java.io.PrintStream
610

7-
// TODO add negaitve and more details tests
11+
// TODO add negative and more details tests
812
class SidebarParserTest:
913

1014
private val sidebar =
@@ -34,6 +38,64 @@ class SidebarParserTest:
3438
| - page: my-page6/my-page6/my-page6.md
3539
""".stripMargin
3640

41+
private val sidebarNoTitle =
42+
"""index: index.md
43+
|subsection:
44+
| - title: My title
45+
| page: my-page1.md
46+
| - page: my-page2.md
47+
| - page: my-page3/subsection
48+
| - title: Reference
49+
| subsection:
50+
| - page: my-page3.md
51+
| hidden: true
52+
| - index: my-page4/index.md
53+
| subsection:
54+
| - page: my-page4/my-page4.md
55+
| - title: My subsection
56+
| index: my-page5/index.md
57+
| subsection:
58+
| - page: my-page5/my-page5.md
59+
| - subsection:
60+
| page: my-page7/my-page7.md
61+
| - index: my-page6/index.md
62+
| subsection:
63+
| - index: my-page6/my-page6/index.md
64+
| subsection:
65+
| - page: my-page6/my-page6/my-page6.md
66+
""".stripMargin
67+
68+
private val sidebarErrorNoPage =
69+
"""index: index.md
70+
|subsection:
71+
| - title: My title
72+
| - page: my-page2.md
73+
| - page: my-page3/subsection
74+
| - title: Reference
75+
| subsection:
76+
| - page: my-page3.md
77+
| hidden: true
78+
| - index: my-page4/index.md
79+
| subsection:
80+
| - page: my-page4/my-page4.md
81+
| - title: My subsection
82+
| index: my-page5/index.md
83+
| subsection:
84+
| - page: my-page5/my-page5.md
85+
| - subsection:
86+
| - page: my-page7/my-page7.md
87+
| - index: my-page6/index.md
88+
| subsection:
89+
| - index: my-page6/my-page6/index.md
90+
| subsection:
91+
| - page: my-page6/my-page6/my-page6.md
92+
""".stripMargin
93+
94+
private val msgNoTitle = "`title` property is missing for some page."
95+
private val msgNoPage = "Error parsing YAML configuration file: 'index' or 'page' path is missing for title 'My title'."
96+
97+
private def schemaMessage: String = Sidebar.schemaMessage
98+
3799
@Test
38100
def loadSidebar(): Unit = assertEquals(
39101
Sidebar.Category(
@@ -53,3 +115,25 @@ class SidebarParserTest:
53115
),
54116
Sidebar.load(sidebar)(using testContext)
55117
)
118+
119+
@Test
120+
def loadSidebarNoPageError: Unit =
121+
val out = new ByteArrayOutputStream()
122+
Console.withErr(new PrintStream(out)) {
123+
Sidebar.load(sidebarErrorNoPage)(using testContext)
124+
}
125+
println(out.toString())
126+
val error = out.toString().trim()
127+
128+
assert(error.contains(msgNoPage) && error.contains(schemaMessage))
129+
130+
131+
@Test
132+
def loadSidebarNoTitleError(): Unit =
133+
val out = new ByteArrayOutputStream()
134+
Console.withErr(new PrintStream(out)) {
135+
Sidebar.load(sidebarNoTitle)(using testContext)
136+
}
137+
val error = out.toString().trim()
138+
139+
assert(error.contains(msgNoTitle) && error.contains(schemaMessage))

0 commit comments

Comments
 (0)