mirror of
https://github.com/apple/pkl.git
synced 2026-03-31 22:23:18 +02:00
Fixes for pkldoc (#96)
* Add URI encoding to paths and fragments * Render quotes around identifiers when appropriate
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -70,7 +70,11 @@ internal abstract class MainOrPackagePageGenerator<S>(
|
||||
} else {
|
||||
link
|
||||
}
|
||||
+name
|
||||
if (moduleOrPackageScope is ModuleScope) {
|
||||
+name.asModuleName
|
||||
} else {
|
||||
+name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user