Skip to content

Commit 81f6a24

Browse files
committed
Use in-house json printer rather then jackson
1 parent 99baf23 commit 81f6a24

File tree

4 files changed

+81
-24
lines changed

4 files changed

+81
-24
lines changed

project/Build.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1563,7 +1563,6 @@ object Build {
15631563
"com.vladsch.flexmark" % "flexmark-ext-yaml-front-matter" % flexmarkVersion,
15641564
"nl.big-o" % "liqp" % "0.6.7",
15651565
"org.jsoup" % "jsoup" % "1.13.1", // Needed to process .html files for static site
1566-
"args4j" % "args4j" % "2.33",
15671566
Dependencies.`jackson-dataformat-yaml`,
15681567

15691568
"com.novocode" % "junit-interface" % "0.11" % "test",

scala3doc/src/dotty/dokka/JSON.scala

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package dotty.dokka
2+
3+
import scala.annotation.tailrec
4+
5+
opaque type JSON = String
6+
7+
def jsonList(elems: Seq[JSON]): JSON = elems.mkString("[", ",\n", "]")
8+
9+
def jsonObject(fields: (String, JSON)*): JSON =
10+
fields.map{ case (k, v) => quoteStr(k)+":"+v}.mkString("{", ",", "}")
11+
12+
13+
def quoteStr(str: String) = s""""$str""""
14+
15+
// based on Spray Json
16+
def jsonString(s: String): JSON =
17+
def requiresEncoding(c: Char): Boolean =
18+
// from RFC 4627
19+
// unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
20+
c match
21+
case '"' => true
22+
case '\\' => true
23+
case c => c < 0x20
24+
25+
val sb = new StringBuilder
26+
@tailrec def firstToBeEncoded(ix: Int = 0): Int =
27+
if (ix == s.length) -1 else if (requiresEncoding(s.charAt(ix))) ix else firstToBeEncoded(ix + 1)
28+
29+
sb.append('"')
30+
firstToBeEncoded() match
31+
case -1 sb.append(s)
32+
case first =>
33+
// sb.append(s, 0, first) for "abc", 0, 2 produce "(abc,0,2)" rather then "ab" as in Java
34+
sb.append(s.substring(0, first))
35+
@tailrec def append(ix: Int): Unit =
36+
if (ix < s.length) {
37+
s.charAt(ix) match
38+
case c if !requiresEncoding(c) => sb.append(c)
39+
case '"' => sb.append("\\\"")
40+
case '\\' => sb.append("\\\\")
41+
case '\b' => sb.append("\\b")
42+
case '\f' => sb.append("\\f")
43+
case '\n' => sb.append("\\n")
44+
case '\r' => sb.append("\\r")
45+
case '\t' => sb.append("\\t")
46+
case x if x <= 0xF => sb.append("\\u000").append(Integer.toHexString(x))
47+
case x if x <= 0xFF => sb.append("\\u00").append(Integer.toHexString(x))
48+
case x if x <= 0xFFF => sb.append("\\u0").append(Integer.toHexString(x))
49+
case x => sb.append("\\u").append(Integer.toHexString(x))
50+
51+
append(ix + 1)
52+
}
53+
append(first)
54+
55+
sb.append('"').toString

scala3doc/src/dotty/renderers/Resources.scala

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import java.nio.file.Path
1414
import java.nio.file.Files
1515
import java.io.File
1616
import dotty.dokka.translators.FilterAttributes
17-
import com.fasterxml.jackson.databind.ObjectMapper
1817

1918
enum Resource(val path: String):
2019
case Text(override val path: String, content: String) extends Resource(path)
@@ -24,10 +23,9 @@ enum Resource(val path: String):
2423

2524
trait Resources(using ctx: DocContext) extends Locations, Writer:
2625
private def dynamicJsData =
27-
// If data at any point will become more complex we should use a proper mapping
28-
val data: Map[String, Map[String, String]] =
29-
Map("filterDefaults" -> FilterAttributes.defaultValues)
30-
val str = new ObjectMapper().writeValueAsString(data.transform((_, v) => v.asJava).asJava)
26+
val str = jsonObject("filterDefaults" -> jsonObject(
27+
FilterAttributes.defaultValues.toSeq.map { case (n, v) => n -> jsonString(v) }:_*
28+
))
3129
Resource.Text("scripts/data.js", s"var scala3DocData = $str")
3230

3331
private def scala3docVersionFile = Resource.Text("scala3doc.version", BuildInfo.version)
@@ -87,17 +85,6 @@ trait Resources(using ctx: DocContext) extends Locations, Writer:
8785
val searchDataPath = "scripts/searchData.js"
8886
val memberResourcesPaths = Seq(searchDataPath) ++ memberResources.map(_.path)
8987

90-
case class PageEntry(
91-
dri: DRI,
92-
name: String,
93-
text: String,
94-
descr: String,
95-
):
96-
// for jackson
97-
def getL: String = absolutePath(dri)
98-
def getN: String = name
99-
def getT: String = text
100-
def getD: String = descr
10188

10289
def searchData(pages: Seq[Page]) =
10390
def flattenToText(signature: Signature): String =
@@ -106,28 +93,34 @@ trait Resources(using ctx: DocContext) extends Locations, Writer:
10693
case s: String => s
10794
}.mkString
10895

109-
def processPage(page: Page): Seq[PageEntry] =
96+
def mkEntry(dri: DRI, name: String, text: String, descr: String) = jsonObject(
97+
"l" -> jsonString(absolutePath(dri)),
98+
"n" -> jsonString(name),
99+
"t" -> jsonString(text),
100+
"d" -> jsonString(descr)
101+
)
102+
103+
def processPage(page: Page): Seq[JSON] =
110104
val res = page.content match
111105
case m: Member =>
112106
val descr = m.dri.asFileLocation
113-
def processMember(member: Member): Seq[PageEntry] =
107+
def processMember(member: Member): Seq[JSON] =
114108
val signatureBuilder = ScalaSignatureProvider.rawSignature(member, InlineSignatureBuilder()).asInstanceOf[InlineSignatureBuilder]
115109
val sig = Signature(member.kind.name, " ") ++ Seq(Link(member.name, member.dri)) ++ signatureBuilder.names.reverse
116-
val entry = PageEntry(member.dri, member.name, flattenToText(sig), descr)
110+
val entry = mkEntry(member.dri, member.name, flattenToText(sig), descr)
117111
val children = member
118112
.membersBy(m => m.kind != dotty.dokka.model.api.Kind.Package && !m.kind.isInstanceOf[Classlike])
119113
.filter(m => m.origin == Origin.RegularlyDefined && m.inheritedFrom.isEmpty)
120114
Seq(entry) ++ children.flatMap(processMember)
121115

122116
processMember(m)
123117
case _ =>
124-
Seq(PageEntry(page.link.dri, page.link.name, page.link.name, ""))
118+
Seq(mkEntry(page.link.dri, page.link.name, page.link.name, ""))
125119

126120
res ++ page.children.flatMap(processPage)
127121

128-
val entries = pages.flatMap(processPage).toArray
129-
val entriesText = new ObjectMapper().writeValueAsString(entries)
130-
Resource.Text(searchDataPath, s"pages = $entriesText;")
122+
val entries = pages.flatMap(processPage)
123+
Resource.Text(searchDataPath, s"pages = ${jsonList(entries)};")
131124

132125

133126
def allResources(pages: Seq[Page]): Seq[Resource] = memberResources ++ Seq(
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package dotty.dokka
2+
3+
import org.junit.Test
4+
import org.junit.Assert._
5+
6+
class JSONTest:
7+
@Test
8+
def testStrings =
9+
assertEquals(quoteStr("""ala"""), jsonString("""ala"""))
10+
assertEquals(quoteStr("""\""""), jsonString("""""""))

0 commit comments

Comments
 (0)