Fixes for pkldoc (#96)

* Add URI encoding to paths and fragments
* Render quotes around identifiers when appropriate
This commit is contained in:
Daniel Chao
2024-02-08 11:28:34 -08:00
committed by GitHub
parent 9dc7eb2938
commit dddae1190f
126 changed files with 3234 additions and 2560 deletions

View File

@@ -41,7 +41,7 @@ internal class ClassPageGenerator(
h1 {
id = "declaration-title"
+clazz.simpleName
+clazz.simpleName.asIdentifier
span {
id = "declaration-version"
@@ -98,7 +98,7 @@ internal class ClassPageGenerator(
span {
classes = setOf("name-decl")
+clazz.simpleName
+clazz.simpleName.asIdentifier
}
renderTypeParameters(clazz.typeParameters)

View File

@@ -23,7 +23,6 @@ import kotlin.io.path.deleteIfExists
import kotlin.io.path.exists
import kotlin.io.path.isSameFileAs
import org.pkl.commons.deleteRecursively
import org.pkl.commons.toUri
import org.pkl.core.ModuleSchema
import org.pkl.core.PClassInfo
import org.pkl.core.Version
@@ -180,7 +179,7 @@ internal class DocPackage(val docPackageInfo: DocPackageInfo, val modules: List<
mod,
docPackageInfo.version,
docPackageInfo.getModuleImportUri(mod.moduleName),
docPackageInfo.getModuleSourceCode(mod.moduleName)?.toUri(),
docPackageInfo.getModuleSourceCode(mod.moduleName)?.toEncodedUri(),
exampleModulesBySubject[mod.moduleName] ?: listOf()
)
}

View File

@@ -159,7 +159,14 @@ data class DocPackageInfo(
internal fun getModuleImportUri(moduleName: String): URI =
when (importUri) {
"pkl:/" -> "pkl:${moduleName.substring(4)}".toUri()
else -> "$importUri${getModulePath(moduleName, moduleNamePrefix)}.pkl".toUri()
else -> {
val path =
getModulePath(moduleName, moduleNamePrefix)
.split("/")
.map { it.uriEncoded }
.joinToString("/") { it } + ".pkl"
URI(importUri).resolve(path)
}
}
internal fun getModuleSourceCode(moduleName: String): String? {
@@ -168,9 +175,6 @@ data class DocPackageInfo(
return sourceCodeUrlScheme?.replace("%{path}", path)?.substringBefore('#')
}
private fun getModulePath(moduleName: String, packagePrefix: String): String =
moduleName.substring(packagePrefix.length).replace('.', '/')
/** Information about a depended-on package. */
data class PackageDependency(
/** The name of the depended-on package. */

View File

@@ -253,9 +253,7 @@ internal class PackageScope(
private val moduleScopes: Map<String, ModuleScope> by lazy {
modules.associate { module ->
val docUrl =
url.resolve(
"${module.moduleName.substring(modulePrefix.length).replace('.', '/')}/index.html"
)
url.resolve(getModulePath(module.moduleName, modulePrefix).uriEncodedPath + "/index.html")
module.moduleName to ModuleScope(module, docUrl, this)
}
}
@@ -328,7 +326,7 @@ internal class ModuleScope(
get() = module.moduleName
val path: String by lazy {
name.substring(parent!!.docPackageInfo.moduleNamePrefix.length).replace('.', '/')
getModulePath(module.moduleName, parent!!.docPackageInfo.moduleNamePrefix).uriEncodedPath
}
override val dataUrl: URI by lazy { parent!!.dataUrl.resolve("./$path/index.js") }
@@ -388,10 +386,12 @@ internal class ClassScope(
) : PageScope() {
override val url: URI by lazy {
// `isModuleClass` distinction is relevant when this scope is a link target
if (clazz.isModuleClass) parentUrl else parentUrl.resolve("${clazz.simpleName}.html")
if (clazz.isModuleClass) parentUrl else parentUrl.resolve("${clazz.simpleName.uriEncoded}.html")
}
override val dataUrl: URI by lazy { parent!!.dataUrl.resolve("${clazz.simpleName}.js") }
override val dataUrl: URI by lazy {
parent!!.dataUrl.resolve("${clazz.simpleName.uriEncoded}.js")
}
override fun getMethod(name: String): MethodScope? =
clazz.allMethods[name]?.let { MethodScope(it, this) }

View File

@@ -70,7 +70,11 @@ internal abstract class MainOrPackagePageGenerator<S>(
} else {
link
}
+name
if (moduleOrPackageScope is ModuleScope) {
+name.asModuleName
} else {
+name
}
}
}

View File

@@ -99,7 +99,7 @@ internal abstract class ModuleOrClassPageGenerator<S>(
span {
classes = setOf("name-decl")
+propertyName
+propertyName.asIdentifier
}
+": "
@@ -210,7 +210,7 @@ internal abstract class ModuleOrClassPageGenerator<S>(
span {
classes = setOf("name-decl")
+method.simpleName
+method.simpleName.asIdentifier
}
renderTypeParameters(method.typeParameters)

View File

@@ -47,7 +47,7 @@ internal class ModulePageGenerator(
h1 {
id = "declaration-title"
+docModule.name
+docModule.name.asModuleName
span {
id = "declaration-version"
@@ -87,7 +87,7 @@ internal class ModulePageGenerator(
span {
classes = setOf("name-decl")
+docModule.name
+docModule.name.asModuleName
}
renderModuleAmendsOrExtendsClause(module)

View File

@@ -268,12 +268,12 @@ internal abstract class PageGenerator<out S>(
a {
href = targetScope.urlRelativeTo(pageScope).toString()
classes = setOf(cssClass)
+clazz.simpleDisplayName
+clazz.simpleDisplayName.asIdentifier
}
} else {
span {
classes = setOf(cssClass)
+clazz.simpleDisplayName
+clazz.simpleDisplayName.asIdentifier
}
}
}
@@ -289,12 +289,12 @@ internal abstract class PageGenerator<out S>(
a {
href = targetScope.urlRelativeTo(pageScope).toString()
classes = setOf(cssClass)
+typeAlias.simpleName
+typeAlias.simpleName.asIdentifier
}
} else {
span {
classes = setOf(cssClass)
+typeAlias.simpleName
+typeAlias.simpleName.asIdentifier
}
}
}
@@ -426,7 +426,7 @@ internal abstract class PageGenerator<out S>(
// anchors, and requires no JS
protected fun HtmlBlockTag.renderAnchor(anchorId: String, cssClass: String = "anchor") {
div {
id = anchorId
id = anchorId.uriEncoded
classes = setOf(cssClass)
+" " // needs some content to be considered a valid anchor by browsers
}
@@ -457,7 +457,7 @@ internal abstract class PageGenerator<out S>(
protected fun HtmlBlockTag.renderSelfLink(memberName: String) {
a {
classes = setOf("member-selflink", "material-icons")
href = "#$memberName"
href = "#${memberName.uriEncoded}"
+"link"
}
}

View File

@@ -16,11 +16,15 @@
package org.pkl.doc
import java.io.InputStream
import java.net.URI
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import java.nio.file.Path
import kotlin.io.path.bufferedWriter
import kotlin.io.path.outputStream
import org.pkl.commons.createParentDirectories
import org.pkl.core.*
import org.pkl.core.parser.Lexer
import org.pkl.core.util.json.JsonWriter
// overwrites any existing file
@@ -114,3 +118,32 @@ internal fun String.replaceSourceCodePlaceholders(
.replace("%{line}", sourceLocation.startLine.toString())
.replace("%{endLine}", sourceLocation.endLine.toString())
}
internal val String.uriEncoded
get(): String {
val ret = URLEncoder.encode(this, StandardCharsets.UTF_8)
// Replace `+` with `%20` to be safe
// (see
// https://stackoverflow.com/questions/2678551/when-should-space-be-encoded-to-plus-or-20#:~:text=%20%20is%20a%20valid%20way,encodeURIComponent()%20does%20in%20JavaScript.)
return ret.replace("+", "%20")
}
internal val String.uriEncodedPath
get(): String = split("/").map { it.uriEncoded }.joinToString("/") { it }
fun getModulePath(moduleName: String, packagePrefix: String): String =
moduleName.substring(packagePrefix.length).replace('.', '/')
internal fun String.toEncodedUri(): URI = URI(uriEncodedPath)
/**
* Turns `"foo.bar.baz-biz"` into ``"foo.bar.`baz-biz`"``.
*
* There's a chance that this is wrong; a module might look like: ``"module foo.`bar.baz`.biz"``.
* However, we don't keep around enough information to render this faithfully.
*/
internal val String.asModuleName: String
get() = split(".").map(Lexer::maybeQuoteIdentifier).joinToString(".") { it }
internal val String.asIdentifier: String
get() = Lexer.maybeQuoteIdentifier(this)