Initial commit

This commit is contained in:
Peter Niederwieser
2016-01-19 14:51:19 +01:00
committed by Dan Chao
commit ecad035dca
2972 changed files with 211653 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import kotlinx.html.*
import org.pkl.core.PClass
internal class ClassPageGenerator(
docsiteInfo: DocsiteInfo,
docPackage: DocPackage,
docModule: DocModule,
clazz: PClass,
pageScope: ClassScope,
isTestMode: Boolean
) : ModuleOrClassPageGenerator<ClassScope>(docsiteInfo, docModule, clazz, pageScope, isTestMode) {
override val html: HTML.() -> Unit = {
renderHtmlHead()
body {
onLoad = "onLoad()"
renderPageHeader(docPackage.name, docPackage.version, clazz.moduleName, clazz.simpleName)
main {
renderParentLinks()
renderAnchors(clazz)
h1 {
id = "declaration-title"
+clazz.simpleName
span {
id = "declaration-version"
+docPackage.version
}
}
val memberDocs =
MemberDocs(
clazz.docComment,
pageScope,
clazz.annotations,
isDeclaration = true,
mapOf(
MemberInfoKey("Known subtypes", runtimeDataClasses) to
{
id = HtmlConstants.KNOWN_SUBTYPES
classes = runtimeDataClasses
},
MemberInfoKey("Known usages", runtimeDataClasses) to
{
id = HtmlConstants.KNOWN_USAGES
classes = runtimeDataClasses
},
MemberInfoKey("All versions", runtimeDataClasses) to
{
id = HtmlConstants.KNOWN_VERSIONS
classes = runtimeDataClasses
},
)
)
renderMemberGroupLinks(
Triple("Overview", "#_overview", memberDocs.isExpandable),
Triple("Properties", "#_properties", clazz.hasListedProperty),
Triple("Methods", "#_methods", clazz.hasListedMethod)
)
renderAnchor("_overview")
div {
id = "_declaration"
classes = setOf("member")
memberDocs.renderExpandIcon(this)
div {
classes =
if (memberDocs.isDeprecatedMember) {
setOf("member-signature", "member-deprecated")
} else setOf("member-signature")
renderModifiers(clazz.modifiers, "class")
span {
classes = setOf("name-decl")
+clazz.simpleName
}
renderTypeParameters(clazz.typeParameters)
renderClassExtendsClause(clazz, pageScope)
}
memberDocs.renderDocComment(this)
}
renderProperties()
renderMethods()
}
}
}
// example output:
// class HostAlias (io.k8s/api/core/v1/PodSpec:befa7c51) • Pkl Hub
override fun HTMLTag.renderPageTitle() {
val classScope = pageScope
val moduleScope = classScope.parent!!
val packageScope = moduleScope.parent!!
+classScope.clazz.simpleName
+" ("
+packageScope.name
+moduleScope.name.drop(packageScope.name.length).replace('.', '/')
+":"
+packageScope.version
+") • "
+(docsiteInfo.title ?: "Pkldoc")
}
}

View File

@@ -0,0 +1,277 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.net.URI
import java.net.URISyntaxException
import java.nio.file.Path
import kotlin.Pair
import org.pkl.commons.cli.CliBaseOptions.Companion.getProjectFile
import org.pkl.commons.cli.CliCommand
import org.pkl.commons.cli.CliException
import org.pkl.core.*
import org.pkl.core.module.ModuleKeyFactories
import org.pkl.core.packages.*
/**
* Entry point for the high-level Pkldoc API.
*
* The high-level API offers the same configuration options as the Pkldoc CLI.
*
* For the low-level Pkldoc API, see [DocGenerator].
*/
class CliDocGenerator(private val options: CliDocGeneratorOptions) : CliCommand(options.base) {
private val packageResolver = PackageResolver.getInstance(securityManager, moduleCacheDir)
private val stdlibDependency =
DocPackageInfo.PackageDependency(
name = "pkl",
uri = null,
version = if (options.isTestMode) "0.24.0" else Release.current().version().toString(),
sourceCode =
if (options.isTestMode) URI("https://github.com/apple/pkl/blob/dev/stdlib/")
else URI(Release.current().sourceCode().homepage()),
sourceCodeUrlScheme =
if (options.isTestMode)
"https://github.com/apple/pkl/blob/0.24.0/stdlib%{path}#L%{line}-L%{endLine}"
else Release.current().sourceCode().sourceCodeUrlScheme,
documentation =
if (options.isTestMode) URI("https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/")
else
URI(
PklInfo.current()
.packageIndex
.getPackagePage("pkl", Release.current().version().toString())
)
)
private fun DependencyMetadata.getPackageDependencies(): List<DocPackageInfo.PackageDependency> {
return buildList {
for ((_, dependency) in dependencies) {
val metadata =
try {
packageResolver.getDependencyMetadata(dependency.packageUri, dependency.checksums)
} catch (e: Exception) {
throw CliException(
"Failed to fetch dependency metadata for ${dependency.packageUri}: ${e.message}"
)
}
val packageDependency =
DocPackageInfo.PackageDependency(
name = metadata.name,
uri = dependency.packageUri.uri,
version = metadata.version.toString(),
sourceCode = metadata.sourceCode,
sourceCodeUrlScheme = metadata.sourceCodeUrlScheme,
documentation = metadata.documentation
)
add(packageDependency)
}
add(stdlibDependency)
}
}
private fun PackageUri.toDocPackageInfo(): DocPackageInfo {
val metadataAndChecksum =
try {
packageResolver.getDependencyMetadataAndComputeChecksum(this)
} catch (e: PackageLoadError) {
throw CliException("Failed to package metadata for $this: ${e.message}")
}
val metadata = metadataAndChecksum.first
val checksum = metadataAndChecksum.second
return DocPackageInfo(
name = "${uri.authority}${uri.path.substringBeforeLast('@')}",
moduleNamePrefix = "${metadata.name}.",
version = metadata.version.toString(),
importUri = toPackageAssetUri("/").toString(),
uri = uri,
authors = metadata.authors,
issueTracker = metadata.issueTracker,
dependencies = metadata.getPackageDependencies(),
overview = metadata.description,
extraAttributes = mapOf("Checksum" to checksum.sha256),
sourceCode = metadata.sourceCode,
sourceCodeUrlScheme = metadata.sourceCodeUrlScheme
)
}
private fun PackageUri.gatherAllModules(): List<PackageAssetUri> {
fun PackageAssetUri.gatherModulesRecursively(): List<PackageAssetUri> {
val self = this
return buildList {
for (element in packageResolver.listElements(self, null)) {
val elementAssetUri = self.resolve(element.name)
if (element.isDirectory) {
addAll(elementAssetUri.gatherModulesRecursively())
} else if (element.name.endsWith(".pkl")) {
add(elementAssetUri)
}
}
}
}
return toPackageAssetUri("/").gatherModulesRecursively()
}
override fun doRun() {
val docsiteInfoModuleUris = mutableListOf<URI>()
val packageInfoModuleUris = mutableListOf<URI>()
val regularModuleUris = mutableListOf<URI>()
val pklProjectPaths = mutableSetOf<Path>()
val packageUris = mutableListOf<PackageUri>()
for (moduleUri in options.base.normalizedSourceModules) {
if (moduleUri.scheme == "file") {
val dir = Path.of(moduleUri).parent
val projectFile = dir.getProjectFile(options.base.normalizedRootDir)
if (projectFile != null) {
pklProjectPaths.add(projectFile)
}
}
when {
moduleUri.path?.endsWith("/docsite-info.pkl", ignoreCase = true) ?: false ->
docsiteInfoModuleUris.add(moduleUri)
moduleUri.path?.endsWith("/doc-package-info.pkl", ignoreCase = true) ?: false ->
packageInfoModuleUris.add(moduleUri)
moduleUri.scheme == "package" -> {
if (moduleUri.fragment != null) {
throw CliException("Cannot generate documentation for just one module within a package")
}
try {
packageUris.add(PackageUri(moduleUri))
} catch (e: URISyntaxException) {
throw CliException(e.message!!)
}
}
else -> regularModuleUris.add(moduleUri)
}
}
if (docsiteInfoModuleUris.size > 1) {
throw CliException(
"`sourceModules` contains multiple modules named `docsite-info.pkl`:\n" +
docsiteInfoModuleUris.joinToString("\n")
)
}
if (packageInfoModuleUris.isEmpty() && packageUris.isEmpty()) {
throw CliException(
"`sourceModules` must contain at least one module named `doc-package-info.pkl`, or an argument must be a package URI."
)
}
if (regularModuleUris.isEmpty() && packageUris.isEmpty()) {
throw CliException(
"`sourceModules` must contain at least one module to generate documentation for."
)
}
val builder = evaluatorBuilder()
var docsiteInfo: DocsiteInfo
val schemasByDocPackageInfoAndPath =
mutableMapOf<Pair<DocPackageInfo, Path>, MutableSet<ModuleSchema>>()
val schemasByDocPackageInfo = mutableMapOf<DocPackageInfo, Set<ModuleSchema>>()
// Evaluate module imports eagerly, which is cheap if docs are also generated for most imported
// modules.
// Alternatively, imports could be evaluated lazily,
// at the expense of interleaving schema/module evaluation and Pkldoc generation.
val importedModules: MutableMap<URI, ModuleSchema> = mutableMapOf()
try {
fun Evaluator.collectImportedModules(imports: Map<String, URI>) {
for ((_, uri) in imports) {
importedModules.computeIfAbsent(uri) { evaluateSchema(ModuleSource.uri(uri)) }
}
}
builder.build().use { evaluator ->
for (packageUri in packageUris) {
val docPackageInfo = packageUri.toDocPackageInfo()
val pklModules = packageUri.gatherAllModules()
val pklModuleSchemas =
pklModules
.map { evaluator.evaluateSchema(ModuleSource.uri(it.uri)) }
.filter { !it.isAmend }
.onEach { evaluator.collectImportedModules(it.imports) }
.toSet()
schemasByDocPackageInfo[docPackageInfo] = pklModuleSchemas
}
docsiteInfo =
when {
docsiteInfoModuleUris.isEmpty() -> DocsiteInfo(null, null, mapOf())
else -> {
val module = evaluator.evaluate(ModuleSource.uri(docsiteInfoModuleUris.single()))
DocsiteInfo.fromPkl(module).apply {
evaluator.collectImportedModules(overviewImports)
}
}
}
for (uri in packageInfoModuleUris) {
val module = evaluator.evaluate(ModuleSource.uri(uri))
val docPackageInfo =
DocPackageInfo.fromPkl(module).apply {
evaluator.collectImportedModules(overviewImports)
}
schemasByDocPackageInfoAndPath[docPackageInfo to Path.of(uri.path).parent] =
mutableSetOf()
}
for (uri in regularModuleUris) {
val entry =
schemasByDocPackageInfoAndPath.keys.find { uri.path.startsWith(it.second.toString()) }
?: throw CliException("Could not find a doc-package-info.pkl for module $uri")
val schema =
evaluator.evaluateSchema(ModuleSource.uri(uri)).apply {
evaluator.collectImportedModules(imports)
}
schemasByDocPackageInfoAndPath[entry]!!.add(schema)
}
// doc generator resolves `pkl.base` even if not imported explicitly
val pklBaseUri = URI("pkl:base")
importedModules[pklBaseUri] = evaluator.evaluateSchema(ModuleSource.uri(pklBaseUri))
}
} finally {
ModuleKeyFactories.closeQuietly(builder.moduleKeyFactories)
}
val versions = mutableMapOf<String, Version>()
val versionComparator =
Comparator<String> { v1, v2 ->
versions
.getOrPut(v1) { Version.parse(v1) }
.compareTo(versions.getOrPut(v2) { Version.parse(v2) })
}
schemasByDocPackageInfo.putAll(schemasByDocPackageInfoAndPath.mapKeys { it.key.first })
try {
DocGenerator(
docsiteInfo,
schemasByDocPackageInfo,
importedModules::getValue,
versionComparator,
options.normalizedOutputDir,
options.isTestMode
)
.run()
} catch (e: DocGeneratorException) {
throw CliException(e.message!!)
}
}
}

View File

@@ -0,0 +1,42 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.nio.file.Path
import org.pkl.commons.cli.CliBaseOptions
import org.pkl.commons.resolveSafely
/** Configuration options for [CliDocGenerator]. */
data class CliDocGeneratorOptions
@JvmOverloads
constructor(
/** Base options shared between CLI commands. */
val base: CliBaseOptions,
/** The directory where generated documentation is placed. */
val outputDir: Path,
/**
* Internal option only used for testing.
*
* Generates source URLs with fixed line numbers `#L123-L456` to avoid churn in expected output
* files (e.g., when stdlib line numbers change).
*/
val isTestMode: Boolean = false
) {
/** [outputDir] after undergoing normalization. */
val normalizedOutputDir: Path = base.normalizedWorkingDir.resolveSafely(outputDir)
}

View File

@@ -0,0 +1,32 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
internal object HtmlConstants {
/** The `known-versions` element ID. */
const val KNOWN_VERSIONS: String = "known-versions"
/** The `known-subtypes` element ID. */
const val KNOWN_SUBTYPES: String = "known-subtypes"
/** The `known-usages` element ID. */
const val KNOWN_USAGES: String = "known-usages"
}
internal object CssConstants {
/** The `current-version` CSS class. */
const val CURRENT_VERSION: String = "current-version"
}

View File

@@ -0,0 +1,218 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.io.IOException
import java.net.URI
import java.nio.file.Path
import kotlin.io.path.createSymbolicLinkPointingTo
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
/**
* Entry point for the low-level Pkldoc API.
*
* For the high-level Pkldoc API, see [CliDocGenerator].
*/
class DocGenerator(
/**
* The documentation website to generate.
*
* API equivalent of `pkl:DocsiteInfo`.
*/
private val docsiteInfo: DocsiteInfo,
/** The modules to generate documentation for, grouped by package. */
modules: Map<DocPackageInfo, Collection<ModuleSchema>>,
/**
* A function to resolve imports in [modules], [packageInfos], and [docsiteInfo].
*
* Module `pkl.base` is resolved with this function even if not explicitly imported.
*/
private val importResolver: (URI) -> ModuleSchema,
/** A comparator for package versions. */
versionComparator: Comparator<String>,
/** The directory where generated documentation is placed. */
private val outputDir: Path,
/**
* Internal option used only for testing.
*
* Generates source URLs with fixed line numbers `#L123-L456` to avoid churn in expected output
* files (e.g., when stdlib line numbers change).
*/
private val isTestMode: Boolean = false
) {
companion object {
internal fun List<PackageData>.current(
versionComparator: Comparator<String>
): List<PackageData> {
val comparator =
compareBy<PackageData> { it.ref.pkg }.thenBy(versionComparator) { it.ref.version }
return asSequence()
// If matching a semver pattern, remove any version that has a prerelease
// version (e.g. SNAPSHOT in 1.2.3-SNAPSHOT)
.filter { Version.parseOrNull(it.ref.version)?.preRelease == null }
.sortedWith(comparator)
.distinctBy { it.ref.pkg }
.toList()
}
}
private val descendingVersionComparator: Comparator<String> = versionComparator.reversed()
private val docPackages: List<DocPackage> = modules.map { DocPackage(it.key, it.value.toList()) }
/** Runs this documentation generator. */
fun run() {
try {
val htmlGenerator =
HtmlGenerator(docsiteInfo, docPackages, importResolver, outputDir, isTestMode)
val searchIndexGenerator = SearchIndexGenerator(outputDir)
val packageDataGenerator = PackageDataGenerator(outputDir)
val runtimeDataGenerator = RuntimeDataGenerator(descendingVersionComparator, outputDir)
for (docPackage in docPackages) {
if (docPackage.isUnlisted) continue
docPackage.deletePackageDir()
htmlGenerator.generate(docPackage)
searchIndexGenerator.generate(docPackage)
packageDataGenerator.generate(docPackage)
}
val packagesData = packageDataGenerator.readAll()
val currentPackagesData = packagesData.current(descendingVersionComparator)
createSymlinks(currentPackagesData)
htmlGenerator.generateSite(currentPackagesData)
searchIndexGenerator.generateSiteIndex(currentPackagesData)
runtimeDataGenerator.deleteDataDir()
runtimeDataGenerator.generate(packagesData)
} catch (e: IOException) {
throw DocGeneratorException("I/O error generating documentation.", e)
}
}
private fun DocPackage.deletePackageDir() {
outputDir.resolve("$name/$version").deleteRecursively()
}
private fun createSymlinks(currentPackagesData: List<PackageData>) {
for (packageData in currentPackagesData) {
val basePath = outputDir.resolve(packageData.ref.pkg)
val src = basePath.resolve(packageData.ref.version)
val dest = basePath.resolve("current")
if (dest.exists() && dest.isSameFileAs(src)) continue
dest.deleteIfExists()
dest.createSymbolicLinkPointingTo(basePath.relativize(src))
}
}
}
internal class DocPackage(val docPackageInfo: DocPackageInfo, val modules: List<ModuleSchema>) {
val name: String
get() = docPackageInfo.name
val version: String
get() = docPackageInfo.version
val uri: URI?
get() = docPackageInfo.uri
val overview: String?
get() = docPackageInfo.overview
val minPklVersion: Version? by lazy { docModules.mapNotNull { it.minPklVersion }.maxOrNull() }
val deprecation: String? = docPackageInfo.annotations.deprecation
val isUnlisted: Boolean = docPackageInfo.annotations.isUnlisted
val hasListedModule: Boolean by lazy { docModules.any { !it.isUnlisted } }
private val exampleModulesBySubject: Map<String, List<ModuleSchema>> by lazy {
val result = mutableMapOf<String, MutableList<ModuleSchema>>()
for (mod in modules) {
val ann = mod.annotations.find { it.classInfo == PClassInfo.DocExample } ?: continue
@Suppress("UNCHECKED_CAST") val subjects = ann["subjects"] as List<String>
for (subject in subjects) {
val examples = result[subject]
if (examples == null) {
result[subject] = mutableListOf(mod)
} else {
examples.add(mod)
}
}
}
result
}
val docModules: List<DocModule> by lazy {
val regularModules =
modules.filter { mod -> !mod.annotations.any { it.classInfo == PClassInfo.DocExample } }
regularModules.map { mod ->
DocModule(
this,
mod,
docPackageInfo.version,
docPackageInfo.getModuleImportUri(mod.moduleName),
docPackageInfo.getModuleSourceCode(mod.moduleName)?.toUri(),
exampleModulesBySubject[mod.moduleName] ?: listOf()
)
}
}
}
internal class DocModule(
val parent: DocPackage,
val schema: ModuleSchema,
val version: String,
val importUri: URI,
val sourceUrl: URI?,
val examples: List<ModuleSchema>
) {
val name: String
get() = schema.moduleName
val path: String by lazy {
name.substring(parent.docPackageInfo.moduleNamePrefix.length).replace('.', '/')
}
val overview: String?
get() = schema.docComment
val minPklVersion: Version? by lazy {
val version =
schema.annotations.find { it.classInfo == PClassInfo.ModuleInfo }?.get("minPklVersion")
as String?
version?.let { Version.parse(it) }
}
val deprecation: String? = schema.annotations.deprecation
val isUnlisted: Boolean = schema.annotations.isUnlisted
}

View File

@@ -0,0 +1,19 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
class DocGeneratorException(message: String, cause: Throwable? = null) :
RuntimeException(message, cause)

View File

@@ -0,0 +1,238 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.net.URI
import kotlinx.serialization.Contextual
import org.pkl.commons.toUri
import org.pkl.core.Member
import org.pkl.core.Member.SourceLocation
import org.pkl.core.PModule
import org.pkl.core.PObject
import org.pkl.core.TypeAlias
/** API equivalent of standard library module `pkl.DocPackageInfo`. */
data class DocPackageInfo(
/** The name of this doc package. */
val name: String,
/** The prefix for all modules within this doc package. */
val moduleNamePrefix: String = "$name.",
/** The URI of the package, if it is a `package://` URI. */
val uri: URI?,
/**
* The version of this package.
*
* Use `"0.0.0"` for unversioned packages.
*/
val version: String,
/** The import base URI for modules in this package. */
val importUri: String,
/** The maintainers' emails for this package. */
val authors: List<String>?,
/** The web URL of the source code for this package. */
val sourceCode: URI?,
/** The source code scheme for this package. */
val sourceCodeUrlScheme: String?,
/** The web URL of the issue tracker for this package. */
val issueTracker: URI?,
/**
* The packages depended-on by this package.
*
* Used to display package dependencies and to create documentation links.
*/
val dependencies: List<PackageDependency> = listOf(),
/**
* The overview documentation for this package.
*
* Supports the same Morkdown syntax as Pkldoc comments. By default, only the first paragraph is
* displayed.
*/
val overview: String?,
/** Imports used to resolve Pkldoc links in [overview]. */
val overviewImports: Map<String, URI> = mapOf(),
/** Annotations for this package, such as `@Deprecated`. */
val annotations: List<PObject> = listOf(),
/** Extra attributes to add to the documentation of the package. */
val extraAttributes: Map<String, String> = mapOf(),
) {
companion object {
@Suppress("UNCHECKED_CAST")
fun fromPkl(module: PModule): DocPackageInfo =
DocPackageInfo(
name = module["name"] as String,
version = module["version"] as String,
importUri = module["importUri"] as String,
uri = (module["uri"] as String?)?.toUri(),
authors = module["authors"] as List<String>,
sourceCode = (module["sourceCode"] as String?)?.toUri(),
sourceCodeUrlScheme = module["sourceCodeUrlScheme"] as String?,
issueTracker = (module["issueTracker"] as String?)?.toUri(),
dependencies =
(module["dependencies"] as List<PObject>).map { dependency ->
PackageDependency(
name = dependency["name"] as String,
uri = null, // dependencies declared in a doc-package-info file do not have URIs
version = dependency["version"] as String,
sourceCode = (dependency["sourceCode"] as String?)?.toUri(),
sourceCodeUrlScheme = dependency["sourceCodeUrlScheme"] as String?,
documentation = (dependency["documentation"] as String?)?.toUri()
)
},
overview = module["overview"] as String,
overviewImports =
(module["overviewImports"] as Map<String, String>).mapValues { it.value.toUri() },
annotations = module["annotations"] as List<PObject>,
extraAttributes = module["extraAttributes"] as Map<String, String>
)
}
internal fun getModuleRef(moduleName: String): ModuleRef? {
if (moduleName.startsWith(moduleNamePrefix)) {
return ModuleRef(name, uri, version, getModulePath(moduleName, moduleNamePrefix))
}
for (dependency in dependencies) {
if (moduleName.startsWith(dependency.prefix)) {
return ModuleRef(
dependency.name,
dependency.uri,
dependency.version,
getModulePath(moduleName, dependency.prefix)
)
}
}
return null
}
internal fun getTypeRef(type: Member /* PClass|TypeAlias */): TypeRef? {
val moduleName = type.moduleName
if (moduleName.startsWith(moduleNamePrefix)) {
return TypeRef(
name,
uri,
version,
getModulePath(moduleName, moduleNamePrefix),
type.simpleName,
isTypeAlias = type is TypeAlias
)
}
for (dependency in dependencies) {
if (moduleName.startsWith(dependency.prefix)) {
return TypeRef(
dependency.name,
dependency.uri,
dependency.version,
getModulePath(moduleName, dependency.prefix),
type.simpleName,
isTypeAlias = type is TypeAlias
)
}
}
return null
}
internal fun getModuleImportUri(moduleName: String): URI =
when (importUri) {
"pkl:/" -> "pkl:${moduleName.substring(4)}".toUri()
else -> "$importUri${getModulePath(moduleName, moduleNamePrefix)}.pkl".toUri()
}
internal fun getModuleSourceCode(moduleName: String): String? {
val path = "/" + getModulePath(moduleName, moduleNamePrefix) + ".pkl"
// assumption: the fragment is only used for line numbers
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. */
val name: String,
/** The URI of the dependend-upon package, if any. */
val uri: @Contextual URI?,
/** The version of the depended-on package. */
val version: String,
/**
* The web URL of the source code for the depended-on package *version*. Must end with a slash.
*/
val sourceCode: @Contextual URI?,
/** The source URL scheme of the depended-upon package _version_, with placeholders. */
val sourceCodeUrlScheme: String?,
/**
* The web URL of the Pkldoc page for the depended-on package *version*. Must end with a slash.
* Only needs to be set if the depended-on package belongs to a different Pkldoc website.
*/
val documentation: @Contextual URI?,
) {
internal val prefix = "$name."
/** Note: Returns an absolute URI, or an URI relative to the current site. */
internal fun getModuleDocUrl(moduleName: String): URI? =
when {
!moduleName.startsWith(prefix) -> null
else -> {
val modulePath = moduleName.substring(prefix.length).replace('.', '/')
if (documentation == null) {
"$name/$version/$modulePath/index.html".toUri()
} else {
documentation.resolve("$modulePath/index.html")
}
}
}
internal fun getModuleSourceCode(moduleName: String): URI? =
when {
!moduleName.startsWith(prefix) -> null
else -> {
val modulePath = moduleName.substring(prefix.length).replace('.', '/')
sourceCode?.resolve("$modulePath.pkl")
}
}
internal fun getModuleSourceCodeWithSourceLocation(
moduleName: String,
sourceLocation: SourceLocation
): URI? {
return when {
!moduleName.startsWith(prefix) -> null
else -> {
val modulePath = moduleName.substring(prefix.length).replace('.', '/')
val path = "/$modulePath.pkl"
sourceCodeUrlScheme?.replaceSourceCodePlaceholders(path, sourceLocation)?.toUri()
}
}
}
}
}

View File

@@ -0,0 +1,539 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.net.URI
import java.nio.file.Path
import org.pkl.commons.toUri
import org.pkl.core.*
import org.pkl.core.Member.SourceLocation
import org.pkl.core.util.IoUtils
/**
* A lexical scope that can be the source or target of a doc link (that is, a link to a Pkl member
* embedded in a doc comment). Used to resolve doc links as well as class names in type signatures.
* Scoping rules conform to the Pkl language as much as possible.
*
* Implementation note: equals and hashCode implementations are based on identity comparisons of
* underlying [ModuleSchema] types.
*/
internal sealed class DocScope {
abstract val url: URI
abstract val parent: DocScope?
private val siteScope: SiteScope? by lazy {
var scope = this
while (scope !is SiteScope) {
scope = scope.parent ?: return@lazy null
}
scope
}
private val packageScope: PackageScope? by lazy {
var scope = this
while (scope !is PackageScope) {
scope = scope.parent ?: return@lazy null
}
scope
}
val relativeSiteUrl: URI by lazy { siteScope!!.urlRelativeTo(this) }
val relativePackageUrl: URI by lazy { packageScope!!.urlRelativeTo(this) }
fun urlRelativeTo(other: DocScope): URI = IoUtils.relativize(url, other.url)
/** Looks up the method with the given name in the program element associated with this scope. */
abstract fun getMethod(name: String): MethodScope?
/**
* Looks up the property or class with the given name in the program element associated with this
* scope.
*/
abstract fun getProperty(name: String): DocScope?
abstract fun resolveModuleNameToDocUrl(name: String): URI?
fun resolveModuleNameToRelativeDocUrl(name: String): URI? =
resolveModuleNameToDocUrl(name)?.let { IoUtils.relativize(it, url) }
abstract fun resolveModuleNameToSourceUrl(
name: String,
sourceLocation: Member.SourceLocation
): URI?
/** Resolves the given method name relative to this scope. */
abstract fun resolveMethod(name: String): MethodScope?
/**
* Resolves the given property name, class name, type alias name, method parameter name, or type
* parameter name relative to this scope.
*/
abstract fun resolveVariable(name: String): DocScope?
/**
* Resolves a doc link such as `someImport.SomeClass` or `SomeClass.someMethod()` originating in
* this scope.
*/
fun resolveDocLink(text: String): DocScope? {
var currScope: DocScope = this
val parts = text.split('.')
if (parts.isEmpty()) return null
val first = parts[0]
currScope =
when {
first.endsWith("()") -> currScope.resolveMethod(first.dropLast(2)) ?: return null
else -> currScope.resolveVariable(first) ?: return null
}
for (i in 1..parts.lastIndex) {
val part = parts[i]
currScope =
when {
part.endsWith("()") -> currScope.getMethod(part.dropLast(2)) ?: return null
else -> currScope.getProperty(part) ?: return null
}
}
return currScope
}
override fun toString() = "${this::class.java.simpleName} { url=$url }"
}
/** A scope that corresponds to an entire Pkldoc page. */
internal abstract class PageScope : DocScope() {
/** The location of the runtime data file for this page. */
abstract val dataUrl: URI
}
// equality is identity
internal class SiteScope(
docPackages: List<DocPackage>,
private val overviewImports: Map<String, URI>,
private val importResolver: (URI) -> ModuleSchema,
outputDir: Path
) : PageScope() {
private val pklVersion = Release.current().version().withBuild(null).toString()
private val pklBaseModule: ModuleSchema by lazy { importResolver("pkl:base".toUri()) }
val packageScopes: Map<String, PackageScope> by lazy {
docPackages.associate { docPackage ->
docPackage.name to
PackageScope(
docPackage.docPackageInfo,
docPackage.docModules.map { it.schema },
pklBaseModule,
docPackage.docPackageInfo.overviewImports,
this
)
}
}
private val pklBaseScope: ModuleScope by lazy {
ModuleScope(pklBaseModule, resolveModuleNameToDocUrl("pkl.base")!!, null)
}
override val parent: DocScope?
get() = null
override val url: URI by lazy {
IoUtils.ensurePathEndsWithSlash(outputDir.toUri()).resolve("index.html")
}
override val dataUrl: URI
get() = throw UnsupportedOperationException("perVersionDataUrl")
fun createEmptyPackageScope(
name: String,
version: String,
sourceCodeUrlScheme: String?,
sourceCode: URI?
): PackageScope =
PackageScope(
DocPackageInfo(
name = name,
version = version,
sourceCode = sourceCode,
sourceCodeUrlScheme = sourceCodeUrlScheme,
authors = emptyList(),
extraAttributes = emptyMap(),
importUri = "",
issueTracker = null,
overview = null,
uri = null
),
emptyList(),
pklBaseModule,
emptyMap(),
this
)
override fun getMethod(name: String): MethodScope? = null
override fun getProperty(name: String): DocScope? = null
fun getPackage(name: String): PackageScope = packageScopes.getValue(name)
fun resolveImport(uri: URI): ModuleSchema = importResolver(uri)
override fun resolveModuleNameToDocUrl(name: String): URI? =
when {
name.startsWith("pkl.") -> {
val packagePage =
packageScopes["pkl"]?.url // link to locally generated stdlib docs if available
?: PklInfo.current().packageIndex.getPackagePage("pkl", pklVersion).toUri()
packagePage.resolve(name.substring(4) + "/")
}
// doesn't make much sense to search in [packageScopes]
// because we don't know the requested module version
else -> null
}
override fun resolveModuleNameToSourceUrl(
name: String,
sourceLocation: Member.SourceLocation
): URI? =
when {
name.startsWith("pkl.") -> {
val path = "/stdlib/${name.substring(4)}.pkl"
Release.current()
.sourceCode()
.sourceCodeUrlScheme
.replaceSourceCodePlaceholders(path, sourceLocation)
.toUri()
}
// doesn't make much sense to search in [packageScopes]
// because we don't know the requested module version
else -> null
}
// used to resolve Pkldoc links in docsite-info.pkl
override fun resolveMethod(name: String): MethodScope? = pklBaseScope.getMethod(name)
// used to resolve Pkldoc links in docsite-info.pkl
override fun resolveVariable(name: String): DocScope? =
overviewImports[name]?.let { uri ->
val mod = resolveImport(uri)
resolveModuleNameToDocUrl(mod.moduleName)?.let { url -> ModuleScope(mod, url, null) }
}
?: pklBaseScope.getProperty(name)
}
internal class PackageScope(
val docPackageInfo: DocPackageInfo,
modules: List<ModuleSchema>,
pklBaseModule: ModuleSchema,
private val overviewImports: Map<String, URI>,
override val parent: SiteScope
) : PageScope() {
val name = docPackageInfo.name
val version = docPackageInfo.version
private val modulePrefix = docPackageInfo.moduleNamePrefix
private val moduleScopes: Map<String, ModuleScope> by lazy {
modules.associate { module ->
val docUrl =
url.resolve(
"${module.moduleName.substring(modulePrefix.length).replace('.', '/')}/index.html"
)
module.moduleName to ModuleScope(module, docUrl, this)
}
}
private val pklBaseScope: ModuleScope by lazy {
ModuleScope(pklBaseModule, resolveModuleNameToDocUrl("pkl.base")!!, null)
}
override val url: URI by lazy { parent.url.resolve("./$name/$version/index.html") }
override val dataUrl: URI by lazy { parent.url.resolve("./data/$name/$version/index.js") }
fun getModule(name: String): ModuleScope = moduleScopes.getValue(name)
fun getPklBaseMethod(name: String): MethodScope? = pklBaseScope.getMethod(name)
fun getPklBaseProperty(name: String): DocScope? = pklBaseScope.getProperty(name)
override fun getMethod(name: String): MethodScope? = null
override fun getProperty(name: String): DocScope? = null
fun resolveImport(uri: URI): ModuleSchema = parent.resolveImport(uri)
override fun resolveModuleNameToDocUrl(name: String): URI? {
moduleScopes[name]?.url?.let {
return it
}
for (dependency in docPackageInfo.dependencies) {
dependency.getModuleDocUrl(name)?.let {
return parent.url.resolve(it)
}
}
return parent.resolveModuleNameToDocUrl(name)
}
override fun resolveModuleNameToSourceUrl(name: String, sourceLocation: SourceLocation): URI? {
for (dependency in docPackageInfo.dependencies) {
dependency.getModuleSourceCodeWithSourceLocation(name, sourceLocation)?.let {
return it
}
}
return parent.resolveModuleNameToSourceUrl(name, sourceLocation)
}
// used to resolve Pkldoc links in package-info.pkl
override fun resolveMethod(name: String): MethodScope? = getPklBaseMethod(name)
// used to resolve Pkldoc links in package-info.pkl
override fun resolveVariable(name: String): DocScope? =
overviewImports[name]?.let { uri ->
val mod = resolveImport(uri)
resolveModuleNameToDocUrl(mod.moduleName)?.let { url -> ModuleScope(mod, url, null) }
}
?: getPklBaseProperty(name)
override fun equals(other: Any?): Boolean =
other is PackageScope && docPackageInfo.name == other.docPackageInfo.name
override fun hashCode(): Int =
PackageScope::class.hashCode() * 31 + docPackageInfo.name.hashCode()
}
internal class ModuleScope(
val module: ModuleSchema,
override val url: URI,
override val parent: PackageScope?
) : PageScope() {
val name: String
get() = module.moduleName
val path: String by lazy {
name.substring(parent!!.docPackageInfo.moduleNamePrefix.length).replace('.', '/')
}
override val dataUrl: URI by lazy { parent!!.dataUrl.resolve("./$path/index.js") }
override fun getMethod(name: String): MethodScope? =
module.moduleClass.allMethods[name]?.let { MethodScope(it, this) }
override fun getProperty(name: String): DocScope? =
module.moduleClass.allProperties[name]?.let { PropertyScope(it, this) }
?: module.allClasses[name]?.let { ClassScope(it, url, this) }
?: module.allTypeAliases[name]?.let { TypeAliasScope(it, url, this) }
private fun resolveImport(uri: URI): ModuleSchema = parent!!.resolveImport(uri)
override fun resolveModuleNameToDocUrl(name: String): URI? =
when (name) {
module.moduleName -> url
else -> parent!!.resolveModuleNameToDocUrl(name)
}
override fun resolveModuleNameToSourceUrl(name: String, sourceLocation: SourceLocation): URI? =
when (name) {
module.moduleName ->
parent!!
.docPackageInfo
.sourceCodeUrlScheme
?.replaceSourceCodePlaceholders("/$path.pkl", sourceLocation)
?.toUri()
else -> parent!!.resolveModuleNameToSourceUrl(name, sourceLocation)
}
override fun resolveMethod(name: String): MethodScope? =
module.moduleClass.methods[name]?.let { MethodScope(it, this) }
?: parent!!.getPklBaseMethod(name) ?: getMethod(name)
override fun resolveVariable(name: String): DocScope? =
name.takeIf { it == "module" }?.let { this }
?: module.imports[name]?.let { uri ->
val mod = resolveImport(uri)
resolveModuleNameToDocUrl(mod.moduleName)?.let { url -> ModuleScope(mod, url, null) }
}
?: module.moduleClass.properties[name]?.let { PropertyScope(it, this) }
// inherited classes/type aliases are in scope when resolving types -> search `all`
?: module.allClasses[name]?.let { ClassScope(it, url, this) }
?: module.allTypeAliases[name]?.let { TypeAliasScope(it, url, this) }
?: parent!!.getPklBaseProperty(name) ?: getProperty(name)
override fun equals(other: Any?): Boolean = other is ModuleScope && module == other.module
override fun hashCode(): Int = module.hashCode()
}
internal class ClassScope(
val clazz: PClass,
private val parentUrl: URI,
override val parent: ModuleScope?
) : 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")
}
override val dataUrl: URI by lazy { parent!!.dataUrl.resolve("${clazz.simpleName}.js") }
override fun getMethod(name: String): MethodScope? =
clazz.allMethods[name]?.let { MethodScope(it, this) }
override fun getProperty(name: String): DocScope? =
clazz.allProperties[name]?.let { PropertyScope(it, this) }
override fun resolveModuleNameToDocUrl(name: String): URI? =
parent!!.resolveModuleNameToDocUrl(name)
override fun resolveModuleNameToSourceUrl(
name: String,
sourceLocation: Member.SourceLocation
): URI? = parent!!.resolveModuleNameToSourceUrl(name, sourceLocation)
override fun resolveMethod(name: String): MethodScope? =
clazz.methods[name]?.let { MethodScope(it, this) }
?: parent!!.resolveMethod(name) ?: getMethod(name)
override fun resolveVariable(name: String): DocScope? =
clazz.typeParameters.find { it.name == name }?.let { ParameterScope(name, this) }
?: clazz.properties[name]?.let { PropertyScope(it, this) } ?: parent!!.resolveVariable(name)
?: clazz.allProperties[name]?.let { PropertyScope(it, this) }
override fun equals(other: Any?): Boolean = other is ClassScope && clazz == other.clazz
override fun hashCode(): Int = clazz.hashCode()
}
internal class TypeAliasScope(
val typeAlias: TypeAlias,
private val parentDocUrl: URI,
override val parent: ModuleScope?
) : DocScope() {
override val url: URI
get() = parentDocUrl.resolve("#${typeAlias.simpleName}")
override fun getMethod(name: String): MethodScope? = parent?.getMethod(name)
override fun getProperty(name: String): DocScope? = parent?.getProperty(name)
override fun resolveModuleNameToDocUrl(name: String) =
// only used for page scopes
throw UnsupportedOperationException("resolveModuleNameToDocUrl")
override fun resolveModuleNameToSourceUrl(name: String, sourceLocation: Member.SourceLocation) =
// only used for page scopes
throw UnsupportedOperationException("resolveModuleNameToSourceUrl")
override fun resolveMethod(name: String): MethodScope? = parent?.resolveMethod(name)
override fun resolveVariable(name: String): DocScope? = parent?.resolveVariable(name)
override fun equals(other: Any?): Boolean =
other is TypeAliasScope && typeAlias == other.typeAlias
override fun hashCode(): Int = typeAlias.hashCode()
}
internal class MethodScope(val method: PClass.Method, override val parent: DocScope) : DocScope() {
override val url: URI
get() = parent.url.resolve("#${method.simpleName}()")
override fun getMethod(name: String): MethodScope? = null
override fun getProperty(name: String): DocScope? = null
override fun resolveModuleNameToDocUrl(name: String) =
// only used for page scopes
throw UnsupportedOperationException("resolveModuleNameToDocUrl")
override fun resolveModuleNameToSourceUrl(name: String, sourceLocation: Member.SourceLocation) =
// only used for page scopes
throw UnsupportedOperationException("resolveModuleNameToSourceUrl")
override fun resolveMethod(name: String): MethodScope? = parent.resolveMethod(name)
override fun resolveVariable(name: String): DocScope? =
method.typeParameters.find { it.name == name }?.let { ParameterScope(name, this) }
?: method.parameters[name]?.let { ParameterScope(name, this) } ?: parent.resolveVariable(name)
override fun equals(other: Any?): Boolean = other is MethodScope && method == other.method
override fun hashCode(): Int = method.hashCode()
}
internal class PropertyScope(
val property: PClass.Property,
override val parent: DocScope // ModuleScope|ClassScope
) : DocScope() {
override val url: URI
get() = parent.url.resolve("#${property.simpleName}")
override fun getProperty(name: String): DocScope? = null
override fun getMethod(name: String): MethodScope? = null
override fun resolveModuleNameToDocUrl(name: String) =
// only used for page scopes
throw UnsupportedOperationException("resolveModuleNameToDocUrl")
override fun resolveModuleNameToSourceUrl(name: String, sourceLocation: Member.SourceLocation) =
// only used for page scopes
throw UnsupportedOperationException("resolveModuleNameToSourceUrl")
override fun resolveMethod(name: String): MethodScope? = parent.resolveMethod(name)
override fun resolveVariable(name: String): DocScope? = parent.resolveVariable(name)
override fun equals(other: Any?): Boolean = other is PropertyScope && property == other.property
override fun hashCode(): Int = property.hashCode()
}
/** A method parameter or type parameter. */
internal class ParameterScope(val name: String, override val parent: DocScope) : DocScope() {
override val url: URI
get() =
if (parent is ClassScope) {
parent.url.resolve("#$name")
} else {
"${parent.url}.$name".toUri()
}
override fun getMethod(name: String): MethodScope? = null
override fun getProperty(name: String): DocScope? = null
override fun resolveModuleNameToDocUrl(name: String) =
// only used for page scopes
throw UnsupportedOperationException("resolveModuleNameToDocUrl")
override fun resolveModuleNameToSourceUrl(name: String, sourceLocation: Member.SourceLocation) =
// only used for page scopes
throw UnsupportedOperationException("resolveModuleNameToSourceUrl")
override fun resolveMethod(name: String): MethodScope? = parent.resolveMethod(name)
override fun resolveVariable(name: String): DocScope? = parent.resolveVariable(name)
override fun equals(other: Any?): Boolean =
other is ParameterScope && name == other.name && parent == other.parent
override fun hashCode(): Int = name.hashCode() * 31 + parent.hashCode()
}

View File

@@ -0,0 +1,48 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.net.URI
import org.pkl.commons.toUri
import org.pkl.core.PModule
/** API equivalent of standard library module `pkl.DocsiteInfo`. */
data class DocsiteInfo(
/** The display title of this Pkldoc website. */
val title: String?,
/**
* The overview documentation on the main page of this website.
*
* Uses the same Morkdown format as Pkldoc comments. Unless expanded, only the first paragraph is
* shown.
*/
val overview: String?,
/** Imports used to resolve Pkldoc links in [overview]. */
val overviewImports: Map<String, URI>
) {
companion object {
@Suppress("UNCHECKED_CAST")
fun fromPkl(module: PModule): DocsiteInfo =
DocsiteInfo(
title = module["title"] as String?,
overview = module["overview"] as String?,
overviewImports =
(module["overviewImports"] as Map<String, String>).mapValues { it.value.toUri() },
)
}
}

View File

@@ -0,0 +1,91 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.net.URI
import java.nio.file.Path
import org.pkl.core.ModuleSchema
internal class HtmlGenerator(
private val docsiteInfo: DocsiteInfo,
docPackages: List<DocPackage>,
importResolver: (URI) -> ModuleSchema,
private val outputDir: Path,
private val isTestMode: Boolean
) {
private val siteScope =
SiteScope(docPackages, docsiteInfo.overviewImports, importResolver, outputDir)
fun generate(docPackage: DocPackage) {
val packageScope = siteScope.getPackage(docPackage.name)
PackagePageGenerator(docsiteInfo, docPackage, packageScope).run()
for (docModule in docPackage.docModules) {
if (docModule.isUnlisted) continue
val moduleScope = packageScope.getModule(docModule.name)
ModulePageGenerator(docsiteInfo, docPackage, docModule, moduleScope, isTestMode).run()
for ((_, clazz) in docModule.schema.classes) {
if (clazz.isUnlisted) continue
ClassPageGenerator(
docsiteInfo,
docPackage,
docModule,
clazz,
ClassScope(clazz, moduleScope.url, moduleScope),
isTestMode
)
.run()
}
}
}
fun generateSite(packagesData: List<PackageData>) {
MainPageGenerator(docsiteInfo, packagesData, siteScope).run()
generateStaticResources()
}
private fun generateStaticResources() {
copyResource("fonts/lato-v14-latin_latin-ext-regular.woff2", outputDir)
copyResource("fonts/lato-v14-latin_latin-ext-700.woff2", outputDir)
copyResource("fonts/open-sans-v15-latin_latin-ext-regular.woff2", outputDir)
copyResource("fonts/open-sans-v15-latin_latin-ext-italic.woff2", outputDir)
copyResource("fonts/open-sans-v15-latin_latin-ext-700.woff2", outputDir)
copyResource("fonts/open-sans-v15-latin_latin-ext-700italic.woff2", outputDir)
copyResource("fonts/source-code-pro-v7-latin_latin-ext-regular.woff2", outputDir)
copyResource("fonts/source-code-pro-v7-latin_latin-ext-700.woff2", outputDir)
copyResource("fonts/MaterialIcons-Regular.woff2", outputDir)
copyResource("scripts/pkldoc.js", outputDir)
copyResource("scripts/search-worker.js", outputDir)
copyResource("scripts/scroll-into-view.min.js", outputDir)
copyResource("styles/pkldoc.css", outputDir)
copyResource("images/apple-touch-icon.png", outputDir)
copyResource("images/favicon.svg", outputDir)
copyResource("images/favicon-16x16.png", outputDir)
copyResource("images/favicon-32x32.png", outputDir)
}
}

View File

@@ -0,0 +1,73 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
@file:JvmName("Main")
package org.pkl.doc
import com.github.ajalt.clikt.parameters.arguments.argument
import com.github.ajalt.clikt.parameters.arguments.convert
import com.github.ajalt.clikt.parameters.arguments.multiple
import com.github.ajalt.clikt.parameters.groups.provideDelegate
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.options.required
import com.github.ajalt.clikt.parameters.types.path
import java.net.URI
import java.nio.file.Path
import org.pkl.commons.cli.cliMain
import org.pkl.commons.cli.commands.BaseCommand
import org.pkl.commons.cli.commands.ProjectOptions
import org.pkl.core.Release
/** Main method for the Pkldoc CLI. */
internal fun main(args: Array<String>) {
cliMain { DocCommand().main(args) }
}
class DocCommand :
BaseCommand(name = "pkldoc", helpLink = Release.current().documentation().homepage(), help = "") {
private val modules: List<URI> by
argument(
name = "<modules>",
help = "Module paths/uris, or package uris to generate documentation for"
)
.convert { parseModuleName(it) }
.multiple(required = true)
private val outputDir: Path by
option(
names = arrayOf("-o", "--output-dir"),
metavar = "<directory>",
help = "Directory where generated documentation is placed."
)
.path()
.required()
private val projectOptions by ProjectOptions()
override fun run() {
val options =
CliDocGeneratorOptions(
baseOptions.baseOptions(
modules,
projectOptions,
),
outputDir,
true
)
CliDocGenerator(options).run()
}
}

View File

@@ -0,0 +1,82 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import kotlinx.html.*
internal abstract class MainOrPackagePageGenerator<S>(
docsiteInfo: DocsiteInfo,
pageScope: S,
private val siteScope: SiteScope
) : PageGenerator<S>(docsiteInfo, pageScope) where S : PageScope {
protected fun UL.renderModuleOrPackage(
name: String,
moduleOrPackageScope: DocScope,
memberDocs: MemberDocs
) {
li {
renderAnchor(name)
div {
classes = setOf("member", "with-page-link")
memberDocs.renderExpandIcon(this)
renderSelfLink(name)
div {
classes = setOf("member-left")
div {
classes =
if (memberDocs.isDeprecatedMember) {
setOf("member-modifiers", "member-deprecated")
} else setOf("member-modifiers")
renderModifiers(
setOf(),
if (moduleOrPackageScope is PackageScope) "package" else "module"
)
}
}
div {
classes = setOf("member-main")
div {
classes =
if (memberDocs.isDeprecatedMember) {
setOf("member-signature", "member-deprecated")
} else setOf("member-signature")
a {
classes = setOf("name-decl")
val link = "./" + moduleOrPackageScope.urlRelativeTo(pageScope).toString()
href =
if (pageScope is SiteScope) {
link.replaceFirst((moduleOrPackageScope as PackageScope).version, "current")
} else {
link
}
+name
}
}
memberDocs.renderDocComment(this)
}
}
}
}
}

View File

@@ -0,0 +1,106 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import kotlinx.html.*
internal class MainPageGenerator(
docsiteInfo: DocsiteInfo,
private val packagesData: List<PackageData>,
pageScope: SiteScope
) : MainOrPackagePageGenerator<SiteScope>(docsiteInfo, pageScope, pageScope) {
override val html: HTML.() -> Unit = {
renderHtmlHead()
body {
onLoad = "onLoad()"
renderPageHeader(null, null, null, null)
main {
h1 {
id = "declaration-title"
+(docsiteInfo.title ?: "")
}
val memberDocs = MemberDocs(docsiteInfo.overview, pageScope, listOf(), isDeclaration = true)
renderMemberGroupLinks(
Triple("Overview", "#_overview", memberDocs.isExpandable),
Triple("Packages", "#_packages", packagesData.isNotEmpty())
)
if (docsiteInfo.overview != null) {
renderAnchor("_overview")
div {
id = "_declaration"
classes = setOf("member")
memberDocs.renderExpandIcon(this)
memberDocs.renderDocComment(this)
}
}
renderPackages()
}
}
}
override fun HTMLTag.renderPageTitle() {
+(docsiteInfo.title ?: "Pkldoc")
}
private fun HtmlBlockTag.renderPackages() {
if (packagesData.isEmpty()) return
div {
classes = setOf("member-group")
renderAnchor("_packages")
h2 {
classes = setOf("member-group-title")
+"Packages"
}
ul {
for (pkg in packagesData) {
val packageScope =
pageScope.packageScopes[pkg.ref.pkg]
// create scope for previously generated package
?: pageScope.createEmptyPackageScope(
pkg.ref.pkg,
pkg.ref.version,
pkg.sourceCodeUrlScheme,
pkg.sourceCode
)
val memberDocs =
MemberDocs(
pkg.summary,
packageScope,
listOfNotNull(pkg.deprecation?.let { createDeprecatedAnnotation(it) }),
isDeclaration = false
)
renderModuleOrPackage(pkg.ref.pkg, packageScope, memberDocs)
}
}
}
}
}

View File

@@ -0,0 +1,112 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import org.commonmark.internal.InlineParserImpl
import org.commonmark.node.Code
import org.commonmark.node.Link
import org.commonmark.node.LinkReferenceDefinition
import org.commonmark.node.Text
import org.commonmark.parser.InlineParser
import org.commonmark.parser.InlineParserContext
import org.commonmark.parser.InlineParserFactory
import org.commonmark.parser.delimiter.DelimiterProcessor
import org.commonmark.renderer.html.CoreHtmlNodeRenderer
import org.commonmark.renderer.html.HtmlNodeRendererContext
internal class MarkdownParserFactory(private val pageScope: DocScope) : InlineParserFactory {
// the scope of the doc comment to be parsed next; mutated by [MemberDocs]
var docScope: DocScope = pageScope
override fun create(inlineParserContext: InlineParserContext): InlineParser {
return InlineParserImpl(MarkdownParserContext(docScope, pageScope, inlineParserContext))
}
}
internal class MarkdownParserContext(
private val docScope: DocScope,
private val pageScope: DocScope,
private val delegate: InlineParserContext
) : InlineParserContext {
companion object {
private val keywords = setOf("null", "true", "false", "this", "unknown", "nothing")
}
private val seenLinkTargets = mutableSetOf<DocScope>()
override fun getCustomDelimiterProcessors(): List<DelimiterProcessor> {
return delegate.customDelimiterProcessors
}
/**
* This method communicates with [MarkdownNodeRenderer] through the method's return value:
* * `title = "pkldoc:1:$label"` -> replace link with `Code(label)`
* * `title = "pkldoc:2:$label"` -> replace link text with `Code(label)`
*
* We only want to modify *short* reference links as described above. Whereas this method can't
* tell whether it's resolving a short or full reference link, PklNodeRenderer can, by comparing
* the link text to the passed through label.
*/
override fun getLinkReferenceDefinition(label: String): LinkReferenceDefinition {
if (label in keywords) {
return LinkReferenceDefinition(label, label, "pkldoc:1:$label")
}
val destScope = docScope.resolveDocLink(label)
val destination = destScope?.urlRelativeTo(pageScope)?.toString() ?: "not_found"
val command =
when {
// dangling link
destScope == null -> 2
// don't link to ourselves
destScope == docScope -> 1
// don't link to our own method parameters
destScope is ParameterScope && destScope.parent == docScope -> 1
// only link to a target once
!seenLinkTargets.add(destScope) -> 1
else -> 2
}
return LinkReferenceDefinition(label, destination, "pkldoc:$command:$label")
}
}
internal class MarkdownNodeRenderer(context: HtmlNodeRendererContext) :
CoreHtmlNodeRenderer(context) {
override fun visit(link: Link) {
val title = link.title
if (title == null || !title.startsWith("pkldoc:")) {
super.visit(link)
return
}
// see [MarkdownParserContext] for contents of `title`
val command = title[7]
val label = title.substring(9)
val isShortReferenceLink =
link.firstChild === link.lastChild && (link.firstChild as? Text)?.literal == label
when {
!isShortReferenceLink -> super.visit(link.apply { this.title = null })
command == '1' -> visit(Code(label))
command == '2' -> visit(Link(link.destination, null).apply { appendChild(Code(label)) })
else -> throw AssertionError("Unknown command: $command")
}
}
}

View File

@@ -0,0 +1,303 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.io.StringWriter
import kotlinx.html.*
import org.pkl.core.Member
import org.pkl.core.PClass
import org.pkl.core.PClass.ClassMember
import org.pkl.core.PClass.Method
import org.pkl.core.TypeParameter
import org.pkl.core.TypeParameter.Variance
import org.pkl.core.ValueRenderers
internal abstract class ModuleOrClassPageGenerator<S>(
docsiteInfo: DocsiteInfo,
private val docModule: DocModule,
protected val clazz: PClass,
scope: S,
private val isTestMode: Boolean
) : PageGenerator<S>(docsiteInfo, scope) where S : PageScope {
protected fun HtmlBlockTag.renderProperties() {
if (!clazz.hasListedProperty) return
div {
classes = setOf("member-group")
renderAnchor("_properties")
h2 {
classes = setOf("member-group-title")
+"Properties"
if (clazz.superclass.hasListedProperty) {
renderShowInheritedButton()
}
}
ul {
for ((propertyName, property) in clazz.allProperties) {
if (property.isUnlisted) continue
li {
renderAnchor(propertyName)
div {
val isInherited = property.owner.info != clazz.info
classes =
when {
isInherited -> setOf("member", "inherited", "expandable", "hidden", "collapsed")
property.isHidden -> setOf("member", "hidden-member")
else -> setOf("member")
}
val propertyScope = PropertyScope(property, pageScope)
val memberDocs =
MemberDocs(property.inheritedDocComment, propertyScope, property.annotations)
memberDocs.renderExpandIcon(this)
renderSelfLink(propertyName)
div {
classes = setOf("member-left")
div {
classes =
if (memberDocs.isDeprecatedMember) {
setOf("member-modifiers", "member-deprecated")
} else setOf("member-modifiers")
renderModifiers(property.modifiers)
}
}
div {
classes = setOf("member-main")
div {
classes =
if (memberDocs.isDeprecatedMember) {
setOf("member-signature", "member-deprecated")
} else setOf("member-signature")
if (isInherited) renderClassContext(property)
span {
classes = setOf("name-decl")
+propertyName
}
+": "
renderType(property.type, propertyScope)
if (isInherited) {
renderModuleContext(property)
}
renderMemberSourceLink(property)
}
memberDocs.renderDocComment(this)
}
}
}
}
}
}
}
private fun HtmlBlockTag.renderClassContext(member: ClassMember) {
if (pageScope is ClassScope) {
span {
classes = setOf("context")
renderClassName(member.owner)
+"."
}
}
}
protected fun HtmlBlockTag.renderModuleContext(member: Member) {
span {
classes = setOf("context")
+" ("
renderModuleName(member.moduleName)
+")"
}
}
private fun renderExportedValue(value: Any): String {
val writer = StringWriter()
ValueRenderers.pcf(writer, " ", false, false).renderValue(value)
return writer.toString()
}
protected fun HtmlBlockTag.renderMethods() {
if (!clazz.hasListedMethod) return
div {
classes = setOf("member-group")
renderAnchor("_methods")
h2 {
classes = setOf("member-group-title")
+"Methods"
if (clazz.superclass.hasListedMethod) {
renderShowInheritedButton()
}
}
ul {
for ((methodName, method) in clazz.allMethods) {
if (method.isUnlisted) continue
li {
renderAnchors(method)
div {
val isInherited = method.owner.info != clazz.info
classes =
if (isInherited) {
setOf("member", "inherited", "expandable", "hidden", "collapsed")
} else setOf("member")
val methodScope = MethodScope(method, pageScope)
val memberDocs =
MemberDocs(method.inheritedDocComment, methodScope, method.annotations)
memberDocs.renderExpandIcon(this)
renderSelfLink("$methodName()")
div {
classes = setOf("member-left")
div {
classes =
if (memberDocs.isDeprecatedMember) {
setOf("member-modifiers", "member-deprecated")
} else setOf("member-modifiers")
renderModifiers(method.modifiers, "function")
}
}
div {
classes = setOf("member-main")
div {
classes =
if (memberDocs.isDeprecatedMember)
setOf("member-signature", "member-deprecated")
else setOf("member-signature")
if (isInherited) renderClassContext(method)
span {
classes = setOf("name-decl")
+method.simpleName
}
renderTypeParameters(method.typeParameters)
renderMethodParameters(method, methodScope)
+": "
renderType(method.returnType, methodScope)
if (isInherited) {
renderModuleContext(method)
}
renderMemberSourceLink(method)
}
memberDocs.renderDocComment(this)
}
}
}
}
}
}
}
protected fun HtmlBlockTag.renderTypeParameters(parameters: List<TypeParameter>) {
if (parameters.isEmpty()) return
+"<"
var first = true
parameters.forEachIndexed { idx, param ->
if (first) first = false else +", "
when (param.variance) {
Variance.CONTRAVARIANT -> +"in "
Variance.COVARIANT -> +"out "
else -> {}
}
a {
classes = setOf("param${idx + 1}")
+param.name
}
}
+">"
}
private fun HtmlBlockTag.renderMethodParameters(method: Method, methodScope: MethodScope) {
+"("
var first = true
val indexOffset = method.typeParameters.size
method.parameters.entries.forEachIndexed { idx, (name, type) ->
if (first) first = false else +", "
span {
classes = setOf("param${indexOffset + idx + 1}")
+name
}
+": "
renderType(type, methodScope)
}
+")"
}
protected fun HtmlBlockTag.renderMemberSourceLink(member: Member) {
// Prevent churn by setting static line numbers.
// This is so our doc generator tests don't break if, say, we change sources in the stdlib.
val startLine = if (isTestMode) 123 else member.sourceLocation.startLine
val endLine = if (isTestMode) 456 else member.sourceLocation.endLine
val moduleSourceUrl =
pageScope.resolveModuleNameToSourceUrl(
member.moduleName,
Member.SourceLocation(startLine, endLine)
)
?: return
a {
classes = setOf("member-source-link")
href = moduleSourceUrl.toString()
+"Source"
}
}
protected fun HtmlBlockTag.renderShowInheritedButton() {
span {
classes = setOf("toggle-inherited-members")
+"("
span {
classes = setOf("toggle-inherited-members-link", "button-link")
+"show inherited"
}
+")"
}
}
}

View File

@@ -0,0 +1,288 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import kotlinx.html.*
internal class ModulePageGenerator(
docsiteInfo: DocsiteInfo,
docPackage: DocPackage,
docModule: DocModule,
pageScope: ModuleScope,
isTestMode: Boolean
) :
ModuleOrClassPageGenerator<ModuleScope>(
docsiteInfo,
docModule,
docModule.schema.moduleClass,
pageScope,
isTestMode
) {
private val module = docModule.schema
override val html: HTML.() -> Unit = {
renderHtmlHead()
body {
onLoad = "onLoad()"
renderPageHeader(docPackage.name, docPackage.version, docModule.name, null)
main {
renderParentLinks()
h1 {
id = "declaration-title"
+docModule.name
span {
id = "declaration-version"
+docPackage.version
}
}
val memberDocs =
MemberDocs(
clazz.docComment,
pageScope,
clazz.annotations,
isDeclaration = true,
collectMemberInfo(docModule)
)
renderMemberGroupLinks(
Triple("Overview", "#_overview", memberDocs.isExpandable),
Triple("Properties", "#_properties", clazz.hasListedProperty),
Triple("Methods", "#_methods", clazz.hasListedMethod),
Triple("Classes", "#_classes", module.hasListedClass),
Triple("Type Aliases", "#_type-aliases", module.hasListedTypeAlias)
)
renderAnchor("_overview")
div {
id = "_declaration"
classes = setOf("member")
memberDocs.renderExpandIcon(this)
div {
classes = setOf("member-signature")
renderModifiers(module.moduleClass.modifiers, "module")
span {
classes = setOf("name-decl")
+docModule.name
}
renderModuleAmendsOrExtendsClause(module)
}
memberDocs.renderDocComment(this)
}
renderProperties()
renderMethods()
renderClasses()
renderTypeAliases()
}
}
}
// example output:
// module PodSpec (io.k8s/api/core/v1:befa7c51) • Pkl Hub
override fun HTMLTag.renderPageTitle() {
val moduleScope = pageScope
val packageScope = moduleScope.parent!!
+moduleScope.name.substringAfterLast('.')
+" ("
+packageScope.name
+moduleScope.name.drop(packageScope.name.length).substringBeforeLast('.').replace('.', '/')
+":"
+packageScope.version
+") • "
+(docsiteInfo.title ?: "Pkldoc")
}
private fun HtmlBlockTag.renderTypeAliases() {
if (!module.hasListedTypeAlias) return
div {
classes = setOf("member-group")
renderAnchor("_type-aliases")
h2 {
classes = setOf("member-group-title")
+"Type Aliases"
if (module.supermodule.hasListedTypeAlias) {
renderShowInheritedButton()
}
}
ul {
for ((typeAliasName, typeAlias) in module.allTypeAliases) {
if (typeAlias.isUnlisted) continue
li {
renderAnchors(typeAlias)
div {
val isInherited = typeAliasName !in module.typeAliases
classes =
if (isInherited) {
setOf("member", "inherited", "expandable", "hidden", "collapsed")
} else setOf("member")
val typeAliasScope = TypeAliasScope(typeAlias, pageScope.url, pageScope)
val memberDocs =
MemberDocs(typeAlias.docComment, typeAliasScope, typeAlias.annotations)
memberDocs.renderExpandIcon(this)
renderSelfLink(typeAliasName)
div {
classes = setOf("member-left")
div {
classes =
if (memberDocs.isDeprecatedMember) {
setOf("member-modifiers", "member-deprecated")
} else setOf("member-modifiers")
renderModifiers(typeAlias.modifiers, "typealias")
}
}
div {
classes = setOf("member-main")
div {
classes =
if (memberDocs.isDeprecatedMember) {
setOf("member-signature", "member-deprecated")
} else setOf("member-signature")
renderTypeAliasName(typeAlias, "name-decl")
renderTypeParameters(typeAlias.typeParameters)
+" = "
renderType(typeAlias.aliasedType, typeAliasScope)
if (isInherited) {
renderModuleContext(typeAlias)
}
renderMemberSourceLink(typeAlias)
}
memberDocs.renderDocComment(this)
}
}
}
}
}
}
}
private fun HtmlBlockTag.renderClasses() {
if (!module.hasListedClass) return
div {
classes = setOf("member-group")
renderAnchor("_classes")
h2 {
classes = setOf("member-group-title")
+"Classes"
if (module.supermodule.hasListedClass) {
renderShowInheritedButton()
}
}
ul {
for ((className, clazz) in module.allClasses) {
if (clazz.isUnlisted) continue
li {
renderAnchor(className)
div {
val isInherited = className !in module.classes
classes =
if (isInherited) {
setOf(
"member",
"with-page-link",
"inherited",
"expandable",
"hidden",
"collapsed"
)
} else setOf("member", "with-page-link")
val classScope = ClassScope(clazz, pageScope.url, pageScope)
val memberDocs =
MemberDocs(clazz.docComment, classScope, clazz.annotations, isDeclaration = false)
memberDocs.renderExpandIcon(this)
renderSelfLink(className)
div {
classes = setOf("member-left")
div {
classes =
if (memberDocs.isDeprecatedMember) {
setOf("member-modifiers", "member-deprecated")
} else setOf("member-modifiers")
renderModifiers(clazz.modifiers, "class")
}
}
div {
classes = setOf("member-main")
div {
classes =
if (memberDocs.isDeprecatedMember) {
setOf("member-signature", "member-deprecated")
} else setOf("member-signature")
renderClassName(clazz, "name-decl")
renderTypeParameters(clazz.typeParameters)
renderClassExtendsClause(clazz, classScope)
if (isInherited) {
renderModuleContext(clazz)
}
renderMemberSourceLink(clazz)
}
memberDocs.renderDocComment(this)
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,438 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.io.IOException
import java.net.URI
import java.nio.file.Path
import kotlin.io.path.writer
import kotlin.streams.toList
import kotlinx.serialization.*
import kotlinx.serialization.json.Json
import org.pkl.commons.createParentDirectories
import org.pkl.commons.readString
import org.pkl.commons.toUri
import org.pkl.commons.walk
import org.pkl.core.*
import org.pkl.core.util.IoUtils
/**
* Reads and writes package-data.json, which contains enough information to include a package's
* previously generated docs in a newly generated doc website. This is useful if there's a problem
* with fetching or evaluating the latest package version.
*/
internal class PackageDataGenerator(private val outputDir: Path) {
fun generate(pkg: DocPackage) {
val path =
outputDir.resolve(pkg.name).resolve(pkg.version).resolve("package-data.json").apply {
createParentDirectories()
}
PackageData(pkg).write(path)
}
fun readAll(): List<PackageData> {
return outputDir.walk().use { paths ->
paths
.filter { it.fileName?.toString() == "package-data.json" }
.map { PackageData.read(it) }
.toList()
}
}
}
/** Uniquely identifies a specific version of a package, module, class, or type alias. */
internal sealed class ElementRef {
/** The package name. */
abstract val pkg: String
/// The URI of the package, if any
abstract val pkgUri: URI?
/** The package version. */
abstract val version: String
/** The Pkldoc page URL of the element relative to its Pkldoc website root. */
abstract val pageUrl: URI
/**
* The Pkldoc page URL of the element relative to [other]'s page URL. Assumes that both elements
* have the same Pkldoc website root.
*/
fun pageUrlRelativeTo(other: ElementRef): String {
return IoUtils.relativize(pageUrl, other.pageUrl).toString()
}
}
/** Uniquely identifies a specific version of a package. */
@Serializable
internal data class PackageRef(
/** The package name. */
override val pkg: String,
/** The package's URI, if any. */
override val pkgUri: @Contextual URI?,
/** The package version. */
override val version: String
) : ElementRef() {
override val pageUrl: URI by lazy { "$pkg/$version/index.html".toUri() }
}
/** Uniquely identifies a specific version of a module. */
@Serializable
internal data class ModuleRef(
/** The package name. */
override val pkg: String,
/** The package's URI, if any. */
override val pkgUri: @Contextual URI?,
/** The package version. */
override val version: String,
/** The module path. */
val module: String
) : ElementRef() {
override val pageUrl: URI by lazy { "$pkg/$version/$module/index.html".toUri() }
val moduleClassRef: TypeRef by lazy {
TypeRef(pkg, pkgUri, version, module, PClassInfo.MODULE_CLASS_NAME)
}
val id: ModuleId by lazy { ModuleId(pkg, module) }
val fullName: String by lazy { "$pkg.${module.replace('/', '.')}" }
}
/** Uniquely identifies a specific version of a class or type alias. */
@Serializable
internal data class TypeRef(
/** The package name. */
override val pkg: String,
/** The package's URI, if any. */
override val pkgUri: @Contextual URI?,
/** The package version. */
override val version: String,
/** The module path. */
val module: String,
/** The simple type name. */
val type: String,
/** Whether this is a type alias rather than a class. */
val isTypeAlias: Boolean = false
) : ElementRef() {
val id: TypeId by lazy { TypeId(pkg, module, type) }
val displayName: String by lazy { if (isModuleClass) module.substringAfterLast('/') else type }
override val pageUrl: URI by lazy {
when {
isTypeAlias -> "$pkg/$version/$module/index.html#$type".toUri()
isModuleClass -> "$pkg/$version/$module/index.html".toUri()
else -> "$pkg/$version/$module/$type.html".toUri()
}
}
private val isModuleClass: Boolean
get() = type == PClassInfo.MODULE_CLASS_NAME
}
/** Uniquely identifies a package (modulo its version). */
internal typealias PackageId = String
/** Uniquely identifies a module (modulo its version). */
internal data class ModuleId(val pkg: String, val module: String)
/** Uniquely identifies a class or type alias (modulo its version). */
internal data class TypeId(val pkg: String, val module: String, val type: String)
/**
* Persisted data for a package. Used by subsequent Pkldoc runs to generate main page and runtime
* data (e.g., package versions and usages).
*/
@Serializable
internal class PackageData(
/** The ref of this package. */
val ref: PackageRef,
/** The first paragraph of the overview documentation for this package. */
val summary: String? = null,
/** The deprecation message of this package, or `null` if this package isn't deprecated. */
val deprecation: String? = null,
/** The web URL of the source code for this package. */
val sourceCode: @Contextual URI?,
/** The source code pattern, with placeholders (e.g. `%{path}`) */
val sourceCodeUrlScheme: String?,
/** The dependencies of this package. */
val dependencies: List<DependencyData> = listOf(),
/** The modules in this package. */
val modules: List<ModuleData> = listOf()
) {
companion object {
val json = Json { serializersModule = serializers }
fun read(path: Path): PackageData {
val jsonStr: String =
try {
path.readString()
} catch (e: IOException) {
throw DocGeneratorException("I/O error reading `$path`.", e)
}
return try {
json.decodeFromString(jsonStr)
} catch (e: SerializationException) {
throw DocGeneratorException("Error deserializing `$path`.", e)
}
}
}
constructor(
pkg: DocPackage
) : this(
PackageRef(pkg.name, pkg.uri, pkg.version),
getDocCommentSummary(pkg.overview),
pkg.docPackageInfo.annotations.deprecation,
pkg.docPackageInfo.sourceCode,
pkg.docPackageInfo.sourceCodeUrlScheme,
pkg.docPackageInfo.dependencies.map { DependencyData(PackageRef(it.name, it.uri, it.version)) },
pkg.docModules.mapNotNull { if (it.isUnlisted) null else ModuleData(pkg, it) }
)
fun write(path: Path) {
val jsonStr =
try {
json.encodeToString(this)
} catch (e: SerializationException) {
throw DocGeneratorException("Error serializing `$path`.", e)
}
try {
path.createParentDirectories()
path.writer().use { it.write(jsonStr) }
} catch (e: IOException) {
throw DocGeneratorException("I/O error writing `$path`.", e)
}
}
}
/** A package depended upon by [PackageData]. */
@Serializable
internal class DependencyData(
/** The ref of the depended-on package. */
val ref: PackageRef
)
/** Persisted data for a module. */
@Serializable
internal class ModuleData(
/** The ref of this module. */
val ref: ModuleRef,
/** The first paragraph of the overview documentation for this module. */
val summary: String? = null,
/** The deprecation message, or `null` if this module isn't deprecated. */
val deprecation: String? = null,
/** The supermodules of this module, starting from the direct supermodule. */
@Suppress("unused") val supermodules: List<ModuleRef> = listOf(),
/** The class of this module, or `null` if this module amends another module. */
val moduleClass: ClassData? = null,
/** The classes declared in this module. */
val classes: List<ClassData> = listOf(),
/** The type aliases declared in this module. */
val typeAliases: List<TypeAliasData> = listOf()
) {
constructor(
pkg: DocPackage,
module: DocModule
) : this(
ModuleRef(pkg.name, pkg.uri, pkg.version, module.path),
getDocCommentSummary(module.overview),
module.schema.annotations.deprecation,
generateSequence(module.schema.supermodule) { it.supermodule }
.map { pkg.docPackageInfo.getModuleRef(module.name) }
.filterNotNull()
.toList(),
if (module.schema.isAmend) null else ClassData(pkg, module, module.schema.moduleClass),
module.schema.classes.mapNotNull {
if (it.value.isUnlisted) null else ClassData(pkg, module, it.value)
},
module.schema.typeAliases.mapNotNull {
if (it.value.isUnlisted) null else TypeAliasData(pkg, module, it.value)
}
)
}
/** Persisted data for a class or type alias. */
@Serializable
internal sealed class TypeData {
/** The ref of this type. */
abstract val ref: TypeRef
/**
* The classes (including module classes) used in the API of this type. Standard library classes
* are not included.
*/
abstract val usedTypes: List<TypeRef>
}
/** Persisted data for a class. */
@Serializable
internal class ClassData(
override val ref: TypeRef,
/**
* The superclasses of this class, starting from the direct superclass. Every class except
* `pkl.Any` has a superclass.
*/
val superclasses: List<TypeRef> = listOf(),
override val usedTypes: List<TypeRef> = listOf(),
) : TypeData() {
constructor(
pkg: DocPackage,
module: DocModule,
clazz: PClass
) : this(
TypeRef(pkg.name, pkg.uri, pkg.version, module.path, clazz.simpleName),
generateSequence(clazz.superclass) { it.superclass }
.map { pkg.docPackageInfo.getTypeRef(it) }
.filterNotNull()
.toList(),
findTypesUsedBy(clazz, pkg.docPackageInfo).toList()
)
}
/** Persisted data for a type alias. */
@Serializable
internal class TypeAliasData(
/** The ref of this type alias. */
override val ref: TypeRef,
/** The types used by this type alias. */
override val usedTypes: List<TypeRef> = listOf()
) : TypeData() {
constructor(
pkg: DocPackage,
module: DocModule,
alias: TypeAlias
) : this(
TypeRef(pkg.name, pkg.uri, pkg.version, module.path, alias.simpleName, isTypeAlias = true),
findTypesUsedBy(alias, pkg.docPackageInfo).toList()
)
}
private fun findTypesUsedBy(clazz: PClass, enclosingPackage: DocPackageInfo): Set<TypeRef> {
val result = mutableSetOf<TypeRef>()
clazz.supertype?.let { supertype ->
for (typeArgument in supertype.typeArguments) {
findTypesUsedBy(typeArgument, clazz, enclosingPackage, result)
}
}
for ((_, property) in clazz.properties) {
findTypesUsedBy(property.type, clazz, enclosingPackage, result)
}
for ((_, method) in clazz.methods) {
for ((_, type) in method.parameters) {
findTypesUsedBy(type, clazz, enclosingPackage, result)
}
findTypesUsedBy(method.returnType, clazz, enclosingPackage, result)
}
return result
}
private fun findTypesUsedBy(alias: TypeAlias, enclosingPackage: DocPackageInfo): Set<TypeRef> {
val result = mutableSetOf<TypeRef>()
findTypesUsedBy(alias.aliasedType, alias, enclosingPackage, result)
return result
}
private fun findTypesUsedBy(
type: PType,
enclosingType: Member /* PClass|TypeAlias */,
enclosingPackage: DocPackageInfo,
result: MutableSet<TypeRef>
) {
when (type) {
is PType.Class -> {
val target = type.pClass
if (!target.isStandardLibraryMember && !target.isUnlisted && target != enclosingType) {
enclosingPackage.getTypeRef(target)?.let { result.add(it) }
}
for (typeArgument in type.typeArguments) {
findTypesUsedBy(typeArgument, enclosingType, enclosingPackage, result)
}
}
is PType.Alias -> {
val target = type.typeAlias
if (!target.isStandardLibraryMember && !target.isUnlisted && target != enclosingType) {
enclosingPackage.getTypeRef(target)?.let { result.add(it) }
}
}
is PType.Constrained -> {
findTypesUsedBy(type.baseType, enclosingType, enclosingPackage, result)
}
is PType.Function -> {
for (parameterType in type.parameterTypes) {
findTypesUsedBy(parameterType, enclosingType, enclosingPackage, result)
}
findTypesUsedBy(type.returnType, enclosingType, enclosingPackage, result)
}
PType.MODULE -> {
if (enclosingType.simpleName != PClassInfo.MODULE_CLASS_NAME) {
result.add(
TypeRef(
enclosingPackage.name,
enclosingPackage.uri,
enclosingPackage.version,
enclosingType.moduleName.substring(enclosingPackage.name.length + 1).replace('.', '/'),
PClassInfo.MODULE_CLASS_NAME
)
)
}
}
PType.NOTHING -> {}
is PType.Nullable -> {
findTypesUsedBy(type.baseType, enclosingType, enclosingPackage, result)
}
is PType.Union -> {
for (elementType in type.elementTypes) {
findTypesUsedBy(elementType, enclosingType, enclosingPackage, result)
}
}
is PType.StringLiteral -> {}
is PType.TypeVariable -> {}
PType.UNKNOWN -> {}
else -> {
throw AssertionError("Unknown PType: $type")
}
}
}

View File

@@ -0,0 +1,132 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import kotlinx.html.*
internal class PackagePageGenerator(
docsiteInfo: DocsiteInfo,
private val docPackage: DocPackage,
pageScope: PackageScope
) : MainOrPackagePageGenerator<PackageScope>(docsiteInfo, pageScope, pageScope.parent) {
override val html: HTML.() -> Unit = {
renderHtmlHead()
body {
onLoad = "onLoad()"
renderPageHeader(docPackage.name, docPackage.version, null, null)
main {
renderParentLinks()
h1 {
id = "declaration-title"
+docPackage.name
span {
id = "declaration-version"
+docPackage.version
}
}
val packageInfo = docPackage.docPackageInfo
val memberDocs =
MemberDocs(
packageInfo.overview,
pageScope,
packageInfo.annotations,
isDeclaration = true,
collectMemberInfoForPackage(docPackage)
)
renderMemberGroupLinks(
Triple("Overview", "#_overview", memberDocs.isExpandable),
Triple("Modules", "#_modules", docPackage.hasListedModule)
)
renderAnchor("_overview")
div {
id = "_declaration"
classes = setOf("member")
memberDocs.renderExpandIcon(this)
div {
classes = setOf("member-signature")
renderModifiers(setOf(), "package")
span {
classes = setOf("name-decl")
+docPackage.name
}
}
memberDocs.renderDocComment(this)
}
renderModules()
}
}
}
// example output:
// package io.k8s (befa7c51) • Pkl Hub
override fun HTMLTag.renderPageTitle() {
+pageScope.name
+" ("
+pageScope.version
+") • "
+(docsiteInfo.title ?: "Pkldoc")
}
private fun HtmlBlockTag.renderModules() {
if (!docPackage.hasListedModule) return
div {
classes = setOf("member-group")
renderAnchor("_modules")
h2 {
classes = setOf("member-group-title")
+"Modules"
}
ul {
for (docModule in docPackage.docModules) {
if (docModule.isUnlisted) continue
val module = docModule.schema
val moduleScope = pageScope.getModule(module.moduleName)
val memberDocs =
MemberDocs(
module.docComment,
moduleScope,
module.annotations,
isDeclaration = false,
collectMemberInfo(docModule)
)
renderModuleOrPackage(module.moduleName, moduleScope, memberDocs)
}
}
}
}
}

View File

@@ -0,0 +1,770 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import kotlin.io.path.bufferedWriter
import kotlinx.html.*
import kotlinx.html.stream.appendHTML
import org.commonmark.ext.gfm.tables.TablesExtension
import org.commonmark.parser.Parser
import org.commonmark.renderer.html.HtmlRenderer
import org.pkl.commons.createParentDirectories
import org.pkl.commons.toPath
import org.pkl.core.*
import org.pkl.core.util.IoUtils
internal abstract class PageGenerator<out S>(
protected val docsiteInfo: DocsiteInfo,
protected val pageScope: S
) where S : PageScope {
private val markdownInlineParserFactory = MarkdownParserFactory(pageScope)
private val markdownParser =
Parser.builder()
.extensions(listOf(TablesExtension.create()))
.inlineParserFactory(markdownInlineParserFactory)
.build()
private val markdownRenderer =
HtmlRenderer.builder()
.extensions(listOf(TablesExtension.create()))
.nodeRendererFactory { MarkdownNodeRenderer(it) }
.build()
fun run() {
val path = pageScope.url.toPath()
path.createParentDirectories()
path.bufferedWriter().use {
it.appendLine("<!DOCTYPE html>")
it.appendHTML().html(null, html)
}
}
protected abstract val html: HTML.() -> Unit
protected abstract fun HTMLTag.renderPageTitle()
protected fun HTML.renderHtmlHead() {
head {
title { renderPageTitle() }
script {
src = pageScope.relativeSiteUrl.resolve("scripts/pkldoc.js").toString()
defer = true
}
script {
src = pageScope.relativeSiteUrl.resolve("scripts/scroll-into-view.min.js").toString()
defer = true
}
if (pageScope !is SiteScope) {
script {
src = IoUtils.relativize(pageScope.dataUrl, pageScope.url).toString()
defer = true
}
}
link {
href = pageScope.relativeSiteUrl.resolve("styles/pkldoc.css").toString()
media = "screen"
type = "text/css"
rel = "stylesheet"
}
link {
rel = "icon"
type = "image/svg+xml"
href = pageScope.relativeSiteUrl.resolve("images/favicon.svg").toString()
}
link {
rel = "apple-touch-icon"
sizes = "180x180"
href = pageScope.relativeSiteUrl.resolve("images/apple-touch-icon.png").toString()
}
link {
rel = "icon"
type = "image/png"
sizes = "32x32"
href = pageScope.relativeSiteUrl.resolve("images/favicon-32x32.png").toString()
}
link {
rel = "icon"
type = "image/png"
sizes = "16x16"
href = pageScope.relativeSiteUrl.resolve("images/favicon-16x16.png").toString()
}
meta { charset = "UTF-8" }
}
}
protected fun HtmlBlockTag.renderPageHeader(
packageName: String?,
packageVersion: String?,
moduleName: String?,
className: String?
) {
header {
if (docsiteInfo.title != null) {
div {
id = "doc-title"
a {
href = pageScope.relativeSiteUrl.toString()
+docsiteInfo.title
}
}
}
div {
id = "search"
i {
id = "search-icon"
classes = setOf("material-icons")
+"search"
}
input {
id = "search-input"
type = InputType.search
placeholder =
if (packageName == null) {
"Click or press 'S' to search"
} else {
"Click or press 'S' to search this package"
}
autoComplete = false
if (packageName != null) {
require(packageVersion != null)
attributes["data-package-name"] = packageName
attributes["data-package-version"] = packageVersion
attributes["data-package-url-prefix"] =
"../".repeat(pageScope.relativePackageUrl.path.count { it == '/' })
}
if (moduleName != null) {
attributes["data-module-name"] = moduleName
}
if (className != null) {
attributes["data-class-name"] = className
}
attributes["data-root-url-prefix"] =
"../".repeat(pageScope.relativeSiteUrl.path.count { it == '/' })
}
}
}
}
protected fun HtmlBlockTag.renderParentLinks() {
a {
classes = setOf("declaration-parent-link")
href = pageScope.relativeSiteUrl.toString()
+(docsiteInfo.title ?: "Pkldoc")
}
val packageScope =
when (pageScope) {
is ClassScope -> pageScope.parent!!.parent
is ModuleScope -> pageScope.parent
else -> null
}
if (packageScope != null) {
+" > "
a {
classes = setOf("declaration-parent-link")
href = packageScope.urlRelativeTo(pageScope).toString()
+packageScope.name
}
}
val moduleScope =
when (pageScope) {
is ClassScope -> pageScope.parent
else -> null
}
if (moduleScope != null) {
+" > "
a {
classes = setOf("declaration-parent-link")
href = moduleScope.urlRelativeTo(pageScope).toString()
+moduleScope.name
}
}
}
protected fun HtmlBlockTag.renderClassExtendsClause(clazz: PClass, currScope: DocScope) {
val superclass = clazz.superclass ?: return
if (superclass.info != PClassInfo.Typed) {
+" extends "
renderType(clazz.supertype!!, currScope)
}
}
protected fun HtmlBlockTag.renderModuleAmendsOrExtendsClause(module: ModuleSchema) {
module.supermodule?.let { supermodule ->
if (module.isAmend) +" amends " else +" extends "
renderModuleName(supermodule.moduleName)
}
}
protected fun HtmlBlockTag.renderMemberGroupLinks(
vararg groups: Triple<String, String, Boolean>
) {
ul {
classes = setOf("member-group-links")
for ((name, _href, show) in groups) {
if (show) {
li {
a {
href = _href
+name
}
}
}
}
}
}
protected fun HtmlBlockTag.renderModuleName(moduleName: String) {
val moduleDocUrl = pageScope.resolveModuleNameToRelativeDocUrl(moduleName)
if (moduleDocUrl != null) {
a {
href = moduleDocUrl.toString()
classes = setOf("name-ref")
+moduleName
}
} else {
span {
classes = setOf("member-ref")
+moduleName
}
}
}
private val PClass.simpleDisplayName: String
get() = if (isModuleClass) moduleName.substring(moduleName.lastIndexOf('.') + 1) else simpleName
protected fun HtmlBlockTag.renderClassName(clazz: PClass, cssClass: String = "name-ref") {
val moduleDocUrl = pageScope.resolveModuleNameToDocUrl(clazz.moduleName)
if (moduleDocUrl != null) {
val targetScope = ClassScope(clazz, moduleDocUrl, null)
a {
href = targetScope.urlRelativeTo(pageScope).toString()
classes = setOf(cssClass)
+clazz.simpleDisplayName
}
} else {
span {
classes = setOf(cssClass)
+clazz.simpleDisplayName
}
}
}
protected fun HtmlBlockTag.renderTypeAliasName(
typeAlias: TypeAlias,
cssClass: String = "name-ref"
) {
val moduleDocUrl = pageScope.resolveModuleNameToDocUrl(typeAlias.moduleName)
if (moduleDocUrl != null) {
val targetScope = TypeAliasScope(typeAlias, moduleDocUrl, null)
a {
href = targetScope.urlRelativeTo(pageScope).toString()
classes = setOf(cssClass)
+typeAlias.simpleName
}
} else {
span {
classes = setOf(cssClass)
+typeAlias.simpleName
}
}
}
protected fun HtmlBlockTag.renderType(
type: PType,
currScope: DocScope,
isNested: Boolean = false
) {
when (type) {
PType.UNKNOWN -> {
+"unknown"
}
PType.NOTHING -> {
+"nothing"
}
PType.MODULE -> {
+"module"
}
is PType.StringLiteral -> {
+"\"${type.literal}\""
}
is PType.Class -> {
renderClassName(type.pClass)
renderTypeArguments(type.typeArguments, currScope)
}
is PType.Nullable -> {
renderType(type.baseType, currScope, true)
+"?"
}
is PType.Union -> {
if (isNested) +"("
var first = true
for (elem in type.elementTypes) {
if (first) first = false else +"|"
renderType(elem, currScope, true)
}
if (isNested) +")"
}
is PType.Function -> {
+"("
var first = true
for (paramType in type.parameterTypes) {
if (first) first = false else +", "
renderType(paramType, currScope, true)
}
+")"
+" -> "
renderType(type.returnType, currScope, true)
}
is PType.Constrained -> {
renderType(type.baseType, currScope, true)
+"("
var first = true
for (constraint in type.constraints) {
if (first) first = false else +", "
+constraint
}
+")"
}
is PType.Alias -> {
renderTypeAliasName(type.typeAlias)
renderTypeArguments(type.typeArguments, currScope)
}
is PType.TypeVariable -> renderTypeVariable(type, currScope)
else -> throw AssertionError("Unknown PType: $type")
}
}
private fun HtmlBlockTag.renderTypeArguments(typeArguments: List<PType>, currentScope: DocScope) {
if (typeArguments.isEmpty()) return
+"<"
var first = true
for (typeArg in typeArguments) {
if (first) first = false else +", "
renderType(typeArg, currentScope, true)
}
+">"
// method.parameters.entries.forEachIndexed { idx, (name, type) ->
// if (first) first = false else +", "
// span {
// classes = setOf("param${indexOffset + idx + 1}")
// +name
// }
// +": "
// renderType(type, methodScope)
// }
}
private fun HtmlBlockTag.renderTypeVariable(
typeVariable: PType.TypeVariable,
currentScope: DocScope
) {
val parameterScope = currentScope.resolveVariable(typeVariable.name) as? ParameterScope
if (parameterScope != null) {
a {
href = parameterScope.urlRelativeTo(pageScope).toString()
classes = setOf("name-ref")
+typeVariable.name
}
} else {
span {
classes = setOf("name-ref")
+typeVariable.name
}
}
}
protected fun HtmlBlockTag.renderModifiers(modifiers: Set<Modifier>, vararg additional: String) {
for (modifier in modifiers) {
+modifier.toString()
+" "
}
for (modifier in additional) {
+modifier
+" "
}
}
// best way I could find to offset anchors so that they aren't hidden behind fixed header when
// navigated to
// (tried several other CSS and JS solutions but all of them fell short in one way or another)
// this solution works both for same-page and cross-page links, allows :target selector on
// anchors, and requires no JS
protected fun HtmlBlockTag.renderAnchor(anchorId: String, cssClass: String = "anchor") {
div {
id = anchorId
classes = setOf(cssClass)
+" " // needs some content to be considered a valid anchor by browsers
}
}
protected fun HtmlBlockTag.renderAnchors(clazz: PClass) {
clazz.typeParameters.forEachIndexed { idx, param ->
renderAnchor(param.name, "anchor-param${idx + 1}")
}
}
protected fun HtmlBlockTag.renderAnchors(typeAlias: TypeAlias) {
val baseId = typeAlias.simpleName
renderAnchor(baseId)
typeAlias.typeParameters
.map { it.name }
.forEachIndexed { idx, param -> renderAnchor("$baseId.$param", "anchor-param${idx + 1}") }
}
protected fun HtmlBlockTag.renderAnchors(method: PClass.Method) {
val baseId = "${method.simpleName}()"
renderAnchor(baseId)
(method.typeParameters.map { it.name } + method.parameters.keys).forEachIndexed { idx, param ->
renderAnchor("$baseId.$param", "anchor-param${idx + 1}")
}
}
protected fun HtmlBlockTag.renderSelfLink(memberName: String) {
a {
classes = setOf("member-selflink", "material-icons")
href = "#$memberName"
+"link"
}
}
protected val runtimeDataClasses: Set<String> = setOf("runtime-data", "hidden")
protected fun collectMemberInfoForPackage(
docPackage: DocPackage
): Map<MemberInfoKey, HtmlBlockTag.() -> Unit> {
val result: MutableMap<MemberInfoKey, HtmlBlockTag.() -> Unit> = mutableMapOf()
if (docPackage.minPklVersion != null) {
result[MemberInfoKey("Pkl version")] = { +"${docPackage.minPklVersion} or higher" }
}
if (docPackage.uri != null) {
result[MemberInfoKey("URI")] = {
span {
classes = setOf("import-uri")
+docPackage.uri.toString()
}
i {
classes = setOf("copy-uri-button", "material-icons")
+"content_copy"
}
}
}
if (docPackage.docPackageInfo.authors?.isNotEmpty() == true) {
result[MemberInfoKey("Authors")] = {
var first = true
for (author in docPackage.docPackageInfo.authors) {
if (first) first = false else +", "
+author
}
}
}
result[MemberInfoKey("Version")] = { +docPackage.version }
if (docPackage.docPackageInfo.sourceCode != null) {
val sources = docPackage.docPackageInfo.sourceCode.toString()
result[MemberInfoKey("Source code")] = {
a {
href = sources
+sources
}
}
}
if (docPackage.docPackageInfo.issueTracker != null) {
val issues = docPackage.docPackageInfo.issueTracker.toString()
result[MemberInfoKey("Issue tracker")] = {
a {
href = issues
+issues
}
}
}
if (docPackage.docPackageInfo.dependencies.isNotEmpty()) {
result[MemberInfoKey("Dependencies")] = {
var first = true
for (dep in docPackage.docPackageInfo.dependencies) {
if (first) first = false else +", "
a {
href =
dep.documentation?.toString()
?: pageScope.relativeSiteUrl
.resolve("${dep.name}/${dep.version}/index.html")
.toString()
+dep.name
+":"
+dep.version
}
}
}
}
for ((key, value) in docPackage.docPackageInfo.extraAttributes) {
result[MemberInfoKey(key)] = { +value }
}
result[MemberInfoKey("Known usages", runtimeDataClasses)] = {
id = HtmlConstants.KNOWN_USAGES
classes = runtimeDataClasses
}
result[MemberInfoKey("All versions", runtimeDataClasses)] = {
id = HtmlConstants.KNOWN_VERSIONS
classes = runtimeDataClasses
}
return result
}
protected class MemberInfoKey(val name: String, val classes: Set<String> = setOf())
protected fun collectMemberInfo(
docModule: DocModule
): Map<MemberInfoKey, HtmlBlockTag.() -> Unit> {
val importUri = docModule.importUri
val sourceUrl = docModule.sourceUrl
val examples = docModule.examples
val result: MutableMap<MemberInfoKey, HtmlBlockTag.() -> Unit> = mutableMapOf()
result[MemberInfoKey("Module URI")] = {
span {
classes = setOf("import-uri")
+(importUri.toString())
}
i {
classes = setOf("copy-uri-button", "material-icons")
+"content_copy"
}
}
val moduleInfoAnnotation =
docModule.schema.annotations.find { it.classInfo == PClassInfo.ModuleInfo }
if (moduleInfoAnnotation != null) {
val minPklVersion = moduleInfoAnnotation["minPklVersion"] as String
result[MemberInfoKey("Pkl version")] = { +"$minPklVersion or higher" }
}
if (sourceUrl != null) {
result[MemberInfoKey("Source code")] = {
a {
href = sourceUrl.toString()
val path = sourceUrl.path
val name = path.substring(path.lastIndexOf("/") + 1)
+name
}
}
}
if (examples.isNotEmpty() && docModule.parent.docPackageInfo.sourceCodeUrlScheme != null) {
result[MemberInfoKey("Examples")] = {
var first = true
for (example in examples) {
if (first) first = false else +", "
a {
href = docModule.parent.docPackageInfo.getModuleSourceCode(example.moduleName)!!
+example.shortModuleName
}
}
}
}
result[MemberInfoKey("Known subtypes", runtimeDataClasses)] = {
id = HtmlConstants.KNOWN_SUBTYPES
classes = runtimeDataClasses
}
result[MemberInfoKey("Known usages", runtimeDataClasses)] = {
id = HtmlConstants.KNOWN_USAGES
classes = runtimeDataClasses
}
result[MemberInfoKey("All versions", runtimeDataClasses)] = {
id = HtmlConstants.KNOWN_VERSIONS
classes = runtimeDataClasses
}
return result
}
protected inner class MemberDocs(
docComment: String?,
docScope: DocScope,
annotations: List<PObject>,
/** Whether these member docs are for the main declaration at the top of a page. */
private val isDeclaration: Boolean = false,
private val extraMemberInfo: Map<MemberInfoKey, HtmlBlockTag.() -> Unit> = mapOf()
) {
init {
markdownInlineParserFactory.docScope = docScope
}
private val summary: String? =
docComment
?.let { getDocCommentSummary(it) }
?.let { markdownRenderer.render(markdownParser.parse(it)).trim().ifEmpty { null } }
// whether to only show basic information without the option to expand
private val showSummaryOnly: Boolean = !isDeclaration && docScope is PageScope
private val overflow: String? =
if (showSummaryOnly) {
null // don't render if not needed
} else {
docComment
?.let { getDocCommentOverflow(it) }
?.let { markdownRenderer.render(markdownParser.parse(it)).trim().ifEmpty { null } }
}
private val deprecatedAnnotation: PObject? =
annotations.find { it.classInfo == PClassInfo.Deprecated }
private val alsoKnownAsAnnotation: PObject? =
annotations.find { it.classInfo == PClassInfo.AlsoKnownAs }
val isDeprecatedMember: Boolean = deprecatedAnnotation != null
// whether there is a "member info" section consisting of key-value pairs
private val hasMemberInfo: Boolean =
extraMemberInfo.isNotEmpty() || alsoKnownAsAnnotation != null
// whether the first paragraph of the user-provided doc comment
// needs to give way for other information
private val summaryMovesDown: Boolean = summary != null && deprecatedAnnotation != null
val isExpandable: Boolean =
!showSummaryOnly && (overflow != null || summaryMovesDown || hasMemberInfo && !isDeclaration)
fun renderExpandIcon(tag: HtmlBlockTag) {
if (isExpandable) {
tag.classes += "with-expandable-docs"
tag.i {
classes = setOf("material-icons", "expandable-docs-icon")
+"expand_more"
}
}
}
fun renderDocComment(tag: HtmlBlockTag) {
if (deprecatedAnnotation != null) {
val message = deprecatedAnnotation["message"] as String?
val replaceWith = deprecatedAnnotation["replaceWith"] as String?
tag.div {
classes = setOf("doc-comment")
if (message != null) {
+"Deprecated: "
unsafe { raw(renderInlineMarkdownText(message)) }
} else {
+"Deprecated."
}
if (replaceWith != null) {
+" Replace with: "
code { +replaceWith }
}
}
} else if (summary != null) {
tag.div {
classes = setOf("doc-comment")
unsafe { raw(summary) }
}
}
if (showSummaryOnly) return
if (hasMemberInfo) {
tag.dl {
classes =
if (isExpandable && !isDeclaration) {
setOf("member-info", "expandable", "hidden", "collapsed")
} else {
setOf("member-info")
}
for ((key, content) in extraMemberInfo) {
dt {
classes = key.classes
+key.name
+":"
}
dd { content() }
}
if (alsoKnownAsAnnotation != null) {
dt { +"Also known as:" }
dd {
@Suppress("UNCHECKED_CAST") val names = alsoKnownAsAnnotation["names"] as List<String>
var first = true
for (name in names) {
if (first) first = false else +", "
code { +name }
}
}
}
}
}
if (summaryMovesDown || overflow != null) {
tag.div {
classes = setOf("doc-comment", "expandable", "hidden", "collapsed")
unsafe {
if (summaryMovesDown) raw(summary!!)
if (overflow != null) raw(overflow)
}
}
}
}
private fun renderInlineMarkdownText(text: String): String {
var node = markdownParser.parse(text.trimIndent().trim())
// unwrap top-level paragraphs because resulting HTML will be used as inline content
while (node.firstChild != null && node.firstChild === node.lastChild) {
node = node.firstChild
}
return markdownRenderer.render(node)
}
}
}

View File

@@ -0,0 +1,231 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.nio.file.Path
import org.pkl.commons.deleteRecursively
import org.pkl.core.util.json.JsonWriter
// Note: we don't currently make use of persisted type alias data (needs more thought).
internal class RuntimeDataGenerator(
private val descendingVersionComparator: Comparator<String>,
private val outputDir: Path
) {
private val packageVersions = mutableMapOf<PackageId, MutableSet<String>>()
private val moduleVersions = mutableMapOf<ModuleId, MutableSet<String>>()
private val classVersions = mutableMapOf<TypeId, MutableSet<String>>()
private val packageUsages = mutableMapOf<PackageRef, MutableSet<PackageRef>>()
private val typeUsages = mutableMapOf<TypeRef, MutableSet<TypeRef>>()
private val subtypes = mutableMapOf<TypeRef, MutableSet<TypeRef>>()
fun deleteDataDir() {
outputDir.resolve("data").deleteRecursively()
}
fun generate(packages: List<PackageData>) {
collectData(packages)
writeData(packages)
}
private fun collectData(packages: List<PackageData>) {
for (pkg in packages) {
packageVersions.add(pkg.ref.pkg, pkg.ref.version)
for (dependency in pkg.dependencies) {
packageUsages.add(dependency.ref, pkg.ref)
}
for (module in pkg.modules) {
moduleVersions.add(module.ref.id, module.ref.version)
if (module.moduleClass != null) {
collectData(module.moduleClass)
}
for (clazz in module.classes) {
collectData(clazz)
}
}
}
}
private fun collectData(clazz: ClassData) {
classVersions.add(clazz.ref.id, clazz.ref.version)
for (superclass in clazz.superclasses) {
subtypes.add(superclass, clazz.ref)
}
for (type in clazz.usedTypes) {
typeUsages.add(type, clazz.ref)
}
}
private fun writeData(packages: List<PackageData>) {
for (pkg in packages) {
writePackageFile(pkg.ref)
for (mod in pkg.modules) {
writeModuleFile(mod.ref)
for (clazz in mod.classes) {
writeClassFile(clazz.ref)
}
}
}
}
private fun writePackageFile(ref: PackageRef) {
outputDir.resolve("data/${ref.pkg}/${ref.version}/index.js").jsonWriter().use { writer ->
writer.isLenient = true
writer.writeLinks(
HtmlConstants.KNOWN_VERSIONS,
packageVersions.getOrDefault(ref.pkg, setOf()).sortedWith(descendingVersionComparator),
{ it },
{ if (it == ref.version) null else ref.copy(version = it).pageUrlRelativeTo(ref) },
{ if (it == ref.version) CssConstants.CURRENT_VERSION else null }
)
writer.writeLinks(
HtmlConstants.KNOWN_USAGES,
packageUsages.getOrDefault(ref, setOf()).packagesWithHighestVersions().sortedBy { it.pkg },
PackageRef::pkg,
{ it.pageUrlRelativeTo(ref) },
{ null }
)
}
}
private fun writeModuleFile(ref: ModuleRef) {
outputDir.resolve("data/${ref.pkg}/${ref.version}/${ref.module}/index.js").jsonWriter().use {
writer ->
writer.isLenient = true
writer.writeLinks(
HtmlConstants.KNOWN_VERSIONS,
moduleVersions.getOrDefault(ref.id, setOf()).sortedWith(descendingVersionComparator),
{ it },
{ if (it == ref.version) null else ref.copy(version = it).pageUrlRelativeTo(ref) },
{ if (it == ref.version) CssConstants.CURRENT_VERSION else null }
)
writer.writeLinks(
HtmlConstants.KNOWN_USAGES,
typeUsages.getOrDefault(ref.moduleClassRef, setOf()).typesWithHighestVersions().sortedBy {
it.displayName
},
TypeRef::displayName,
{ it.pageUrlRelativeTo(ref) },
{ null }
)
writer.writeLinks(
HtmlConstants.KNOWN_SUBTYPES,
subtypes.getOrDefault(ref.moduleClassRef, setOf()).typesWithHighestVersions().sortedBy {
it.displayName
},
TypeRef::displayName,
{ it.pageUrlRelativeTo(ref) },
{ null }
)
}
}
private fun writeClassFile(ref: TypeRef) {
outputDir
.resolve("data/${ref.pkg}/${ref.version}/${ref.module}/${ref.type}.js")
.jsonWriter()
.use { writer ->
writer.isLenient = true
writer.writeLinks(
HtmlConstants.KNOWN_VERSIONS,
classVersions.getOrDefault(ref.id, setOf()).sortedWith(descendingVersionComparator),
{ it },
{ if (it == ref.version) null else ref.copy(version = it).pageUrlRelativeTo(ref) },
{ if (it == ref.version) CssConstants.CURRENT_VERSION else null }
)
writer.writeLinks(
HtmlConstants.KNOWN_USAGES,
typeUsages.getOrDefault(ref, setOf()).typesWithHighestVersions().sortedBy {
it.displayName
},
TypeRef::displayName,
{ it.pageUrlRelativeTo(ref) },
{ null }
)
writer.writeLinks(
HtmlConstants.KNOWN_SUBTYPES,
subtypes.getOrDefault(ref, setOf()).typesWithHighestVersions().sortedBy {
it.displayName
},
TypeRef::displayName,
{ it.pageUrlRelativeTo(ref) },
{ null }
)
}
}
private fun <T> JsonWriter.writeLinks(
// HTML element ID
id: String,
// items based on which links are generated
items: List<T>,
// link text
text: (T) -> String,
// link href
href: (T) -> String?,
// link CSS classes
classes: (T) -> String?
) {
if (items.isEmpty()) return
rawText("runtimeData.links('")
rawText(id)
rawText("','")
array {
for (item in items) {
obj {
name("text").value(text(item))
name("href").value(href(item))
name("classes").value(classes(item))
}
}
}
rawText("');\n")
}
private fun Set<PackageRef>.packagesWithHighestVersions(): Collection<PackageRef> {
val highestVersions = mutableMapOf<PackageId, PackageRef>()
for (ref in this) {
val prev = highestVersions[ref.pkg]
if (prev == null || descendingVersionComparator.compare(prev.version, ref.version) > 0) {
highestVersions[ref.pkg] = ref
}
}
return highestVersions.values
}
private fun Set<TypeRef>.typesWithHighestVersions(): Collection<TypeRef> {
val highestVersions = mutableMapOf<TypeId, TypeRef>()
for (ref in this) {
val prev = highestVersions[ref.id]
if (prev == null || descendingVersionComparator.compare(prev.version, ref.version) > 0) {
highestVersions[ref.id] = ref
}
}
return highestVersions.values
}
private fun <K, V> MutableMap<K, MutableSet<V>>.add(key: K, value: V) {
val newValue =
when (val oldValue = this[key]) {
null -> mutableSetOf(value)
else -> oldValue.apply { add(value) }
}
put(key, newValue)
}
}

View File

@@ -0,0 +1,290 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.nio.file.Path
import kotlin.io.path.bufferedWriter
import org.pkl.commons.createParentDirectories
import org.pkl.core.Member
import org.pkl.core.PClass.Method
import org.pkl.core.PClass.Property
import org.pkl.core.PClassInfo
import org.pkl.core.PType
import org.pkl.core.util.json.JsonWriter
internal class SearchIndexGenerator(private val outputDir: Path) {
fun generateSiteIndex(packagesData: List<PackageData>) {
val path = outputDir.resolve("search-index.js").createParentDirectories()
path.jsonWriter().use { writer ->
writer.apply {
// provide data as JSON string rather than JS literal (more flexible and secure)
rawText("searchData='")
array {
for (pkg in packagesData) {
val pkgPath = "${pkg.ref.pkg}/current"
obj {
name("name").value(pkg.ref.pkg)
name("kind").value(0)
name("url").value("$pkgPath/index.html")
if (pkg.deprecation != null) {
name("deprecated").value(true)
}
}
for (module in pkg.modules) {
obj {
name("name").value(module.ref.fullName)
name("kind").value(1)
name("url").value("$pkgPath/${module.ref.module}/index.html")
if (module.deprecation != null) {
name("deprecated").value(true)
}
}
}
}
}
rawText("';\n")
}
}
}
fun generate(docPackage: DocPackage) {
val path =
outputDir
.resolve("${docPackage.name}/${docPackage.version}/search-index.js")
.createParentDirectories()
JsonWriter(path.bufferedWriter()).use { writer ->
writer.apply {
serializeNulls = false
// provide data as JSON string rather than JS literal (more flexible and secure)
rawText("searchData='")
var nextId = 0
array {
for (docModule in docPackage.docModules) {
if (docModule.isUnlisted) continue
val module = docModule.schema
val moduleId = nextId
nextId += 1
obj {
name("name").value(module.moduleName)
name("kind").value(1)
name("url").value("${docModule.path}/index.html")
writeAnnotations(module.moduleClass)
}
for ((propertyName, property) in module.moduleClass.properties) {
if (property.isUnlisted) continue
nextId += 1
obj {
name("name").value(propertyName)
name("kind").value(5)
name("url").value("${docModule.path}/index.html#$propertyName")
name("sig").value(renderSignature(property))
name("parId").value(moduleId)
writeAnnotations(property)
}
}
for ((methodName, method) in module.moduleClass.methods) {
if (method.isUnlisted) continue
nextId += 1
obj {
name("name").value(methodName)
name("kind").value(4)
name("url").value("${docModule.path}/index.html#$methodName()")
name("sig").value(renderSignature(method))
name("parId").value(moduleId)
writeAnnotations(method)
}
}
for ((className, clazz) in module.classes) {
if (clazz.isUnlisted) continue
val classId = nextId
nextId += 1
obj {
name("name").value(className)
name("kind").value(3)
name("url").value("${docModule.path}/$className.html")
name("parId").value(moduleId)
writeAnnotations(clazz)
}
for ((propertyName, property) in clazz.properties) {
if (property.isUnlisted) continue
nextId += 1
obj {
name("name").value(propertyName)
name("kind").value(5)
name("url").value("${docModule.path}/$className.html#$propertyName")
name("sig").value(renderSignature(property))
name("parId").value(classId)
writeAnnotations(property)
}
}
for ((methodName, method) in clazz.methods) {
if (method.isUnlisted) continue
nextId += 1
obj {
name("name").value(methodName)
name("kind").value(4)
name("url").value("${docModule.path}/$className.html#$methodName()")
name("sig").value(renderSignature(method))
name("parId").value(classId)
writeAnnotations(method)
}
}
}
for ((typeAliasName, typeAlias) in module.typeAliases) {
if (typeAlias.isUnlisted) continue
nextId += 1
obj {
name("name").value(typeAliasName)
name("kind").value(2)
name("url").value("${docModule.path}/index.html#$typeAliasName")
name("parId").value(moduleId)
writeAnnotations(typeAlias)
}
}
}
}
rawText("';\n")
}
}
}
private fun renderSignature(method: Method): String =
StringBuilder()
.apply {
append('(')
var first = true
for ((name, _) in method.parameters) {
if (first) first = false else append(", ")
append(name)
}
append(')')
append(": ")
appendType(method.returnType)
}
.toString()
private fun renderSignature(property: Property): String =
StringBuilder()
.apply {
append(": ")
appendType(property.type)
}
.toString()
private fun StringBuilder.appendType(type: PType) {
when (type) {
PType.UNKNOWN -> {
append("unknown")
}
PType.NOTHING -> {
append("nothing")
}
PType.MODULE -> {
append("module")
}
is PType.StringLiteral -> {
append("\\\"${type.literal}\\\"")
}
is PType.Class -> {
val pClass = type.pClass
val name =
if (pClass.isModuleClass) {
// use simple module name rather than class name (which is always `ModuleClass`)
pClass.moduleName.substring(pClass.moduleName.lastIndexOf('.') + 1)
} else {
pClass.simpleName
}
append(name)
if (type.typeArguments.isNotEmpty()) {
append('<')
var first = true
for (typeArg in type.typeArguments) {
if (first) first = false else append(", ")
appendType(typeArg)
}
append('>')
}
}
is PType.Constrained -> appendType(type.baseType)
is PType.Union -> {
var first = true
for (elemType in type.elementTypes) {
if (first) first = false else append("|")
appendType(elemType)
}
}
is PType.Nullable -> {
appendType(type.baseType)
append("?")
}
is PType.Function -> {
if (type.parameterTypes.size == 1) {
appendType(type.parameterTypes[0])
} else {
append('(')
var first = true
for (paramType in type.parameterTypes) {
if (first) first = false else append(", ")
appendType(paramType)
}
append(')')
}
append(" -> ")
appendType(type.returnType)
}
is PType.Alias -> append(type.typeAlias.simpleName)
is PType.TypeVariable -> append(type.typeParameter.name)
else -> throw AssertionError("Unknown PType: $type")
}
}
private fun JsonWriter.writeAnnotations(member: Member?): JsonWriter {
if (member == null) return this
if (member.annotations.any { it.classInfo == PClassInfo.Deprecated }) {
name("deprecated")
value(true)
}
member.annotations
.find { it.classInfo == PClassInfo.AlsoKnownAs }
?.let { alsoKnownAs ->
name("aka")
array {
@Suppress("UNCHECKED_CAST") for (name in alsoKnownAs["names"] as List<String>) value(name)
}
}
return this
}
}

View File

@@ -0,0 +1,39 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.net.URI
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.*
import kotlinx.serialization.encoding.*
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.contextual
import org.pkl.commons.toUri
val serializers: SerializersModule = SerializersModule { contextual(UriSerializer) }
object UriSerializer : KSerializer<URI> {
override val descriptor: SerialDescriptor =
PrimitiveSerialDescriptor("java.net.URI", PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: URI) {
encoder.encodeString(value.toString())
}
override fun deserialize(decoder: Decoder): URI {
return decoder.decodeString().toUri()
}
}

View File

@@ -0,0 +1,116 @@
/**
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pkl.doc
import java.io.InputStream
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.util.json.JsonWriter
// overwrites any existing file
internal fun copyResource(resourceName: String, targetDir: Path) {
val targetFile = targetDir.resolve(resourceName).apply { createParentDirectories() }
getResourceAsStream(resourceName).use { sourceStream ->
targetFile.outputStream().use { targetStream -> sourceStream.copyTo(targetStream) }
}
}
internal fun getResourceAsStreamOrNull(resourceName: String): InputStream? =
Thread.currentThread().contextClassLoader.getResourceAsStream("org/pkl/doc/$resourceName")
internal fun getResourceAsStream(resourceName: String): InputStream =
getResourceAsStreamOrNull(resourceName)
?: throw DocGeneratorException("Failed to load class path resource `$resourceName`.")
internal val ModuleSchema?.hasListedClass: Boolean
get() = this != null && allClasses.any { !it.value.isUnlisted }
internal val ModuleSchema?.hasListedTypeAlias: Boolean
get() = this != null && allTypeAliases.any { !it.value.isUnlisted }
internal val PClass?.hasListedProperty: Boolean
get() = this != null && allProperties.any { !it.value.isUnlisted }
internal val PClass?.hasListedMethod: Boolean
get() = this != null && allMethods.any { !it.value.isUnlisted }
internal val Member.isUnlisted: Boolean
get() = annotations.isUnlisted
internal val List<PObject>.isUnlisted: Boolean
get() = any { it.classInfo == PClassInfo.Unlisted }
internal val List<PObject>.deprecation: String?
get() = find { it.classInfo == PClassInfo.Deprecated }?.get("message") as String?
@Suppress("UNCHECKED_CAST")
internal val List<PObject>.alsoKnownAs: List<String>?
get() = find { it.classInfo == PClassInfo.AlsoKnownAs }?.get("names") as List<String>?
internal fun createDeprecatedAnnotation(message: String): PObject =
PObject(PClassInfo.Deprecated, mapOf("message" to message, "replaceWith" to PNull.getInstance()))
private val paragraphSeparatorRegex: Regex = Regex("(?m:^\\s*(`{3,}\\w*)?\\s*\n)")
internal fun getDocCommentSummary(docComment: String?): String? {
if (docComment == null) return null
return when (val match = paragraphSeparatorRegex.find(docComment)) {
null -> docComment.trim().ifEmpty { null }
else -> docComment.substring(0, match.range.first).trim().ifEmpty { null }
}
}
internal fun getDocCommentOverflow(docComment: String?): String? {
if (docComment == null) return null
return when (val match = paragraphSeparatorRegex.find(docComment)) {
null -> null
else -> {
val index = if (match.groups[1] != null) match.range.first else match.range.last + 1
docComment.substring(index).trim().ifEmpty { null }
}
}
}
internal fun Path.jsonWriter(): JsonWriter {
createParentDirectories()
return JsonWriter(bufferedWriter()).apply { serializeNulls = false }
}
internal inline fun JsonWriter.obj(body: JsonWriter.() -> Unit) {
beginObject()
body()
endObject()
}
internal inline fun JsonWriter.array(body: JsonWriter.() -> Unit) {
beginArray()
body()
endArray()
}
internal fun String.replaceSourceCodePlaceholders(
path: String,
sourceLocation: Member.SourceLocation
): String {
return replace("%{path}", path)
.replace("%{line}", sourceLocation.startLine.toString())
.replace("%{endLine}", sourceLocation.endLine.toString())
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100.58 98.63">
<path d="m75.57,19.78l2.43-13.25c-3.69-2.46-7.7-4.42-11.91-5.83l-8.97,10.05c-4.37-.8-8.85-.83-13.23-.08L35.03.5c-4.23,1.35-8.26,3.26-11.99,5.68l2.26,13.28c-3.35,2.92-6.17,6.4-8.32,10.3l-13.46.58c-1.58,4.15-2.6,8.49-3.03,12.91l11.8,6.51c.19,4.44,1.16,8.81,2.86,12.92l-7.94,10.89c2.26,3.82,5.02,7.33,8.2,10.42l12.45-5.16c3.59,2.62,7.62,4.59,11.89,5.82l3.56,13c4.4.62,8.86.64,13.26.08l3.72-12.95c4.29-1.17,8.34-3.09,11.96-5.67l12.38,5.32c3.22-3.05,6.03-6.52,8.33-10.32l-7.8-10.99c1.75-4.08,2.78-8.45,3.03-12.88l11.88-6.36c-.38-4.42-1.34-8.78-2.87-12.95l-13.45-.75c-2.1-3.92-4.87-7.44-8.19-10.4Z"
style="fill:#6b9543; stroke-width:0px;"/>
<circle cx="51.05" cy="47.72" r="31.49" style="fill:#e9f4ca; stroke-width:0px;"/>
<g id="_Radial_Repeat_">
<path d="m28.79,62.54c8.22,14.22,24.82,18.97,20.85-10.47h0c-.31-2.29-1.56-4.35-3.45-5.68-24.66-17.36-26.37.64-17.4,16.15Zm15.42-8.25h0c.7-.17,1.24.13,1.49.83,3.27,9.16-2.6,12.49-6.71,10.44-3.77-1.88-3.77-9.01,5.22-11.27Zm-2.14-5.45c.48.57.47,1.19-.03,1.7h0c-6.44,6.67-12.62,3.1-12.37-1.09.27-4.58,6.09-8.01,12.4-.61Z"
style="fill:#c8d987; stroke-width:0px;"/>
<ellipse cx="38.62" cy="55.01" rx="7.64" ry="14.03" transform="translate(-22.33 26.68) rotate(-30)"
style="fill:#c8d987; stroke-width:0px;"/>
</g>
<g id="_Radial_Repeat_-2">
<path d="m49.34,21.03c-16.42.01-28.84,12.01-1.36,23.29h0c2.14.88,4.54.82,6.64-.15,27.37-12.67,12.63-23.16-5.29-23.15Zm-.56,17.48h0c-.2.69-.73,1.01-1.46.88-9.57-1.75-9.52-8.5-5.69-11.03,3.51-2.32,9.69,1.24,7.15,10.16Zm5.79.87c-.73.13-1.27-.18-1.46-.88h0c-2.56-8.91,3.62-12.48,7.13-10.17,3.83,2.53,3.9,9.28-5.67,11.04Z"
style="fill:#c8d987; stroke-width:0px;"/>
<ellipse cx="50.94" cy="33.31" rx="14.03" ry="7.64" style="fill:#c8d987; stroke-width:0px;"/>
</g>
<g id="_Radial_Repeat_-3">
<path d="m75.02,59.59c8.2-14.23,4.02-30.98-19.5-12.82h0c-1.83,1.41-2.99,3.52-3.19,5.83-2.71,30.04,13.74,22.52,22.69,7Zm-14.86-9.23h0c-.5-.52-.51-1.14-.03-1.7,6.3-7.41,12.12-3.99,12.4.59.26,4.2-5.92,7.77-12.37,1.11Zm-3.65,4.58c.25-.7.79-1,1.49-.83h0c8.99,2.24,9,9.38,5.24,11.26-4.1,2.05-9.98-1.26-6.73-10.43Z"
style="fill:#c8d987; stroke-width:0px;"/>
<ellipse cx="63.58" cy="54.83" rx="14.03" ry="7.64" transform="translate(-15.7 82.48) rotate(-60)"
style="fill:#c8d987; stroke-width:0px;"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,718 @@
// noinspection DuplicatedCode
'use strict';
// Whether the current browser is WebKit.
let isWebKitBrowser;
// The lazily initialized worker for running searches, if any.
let searchWorker = null;
// Tells whether non-worker search is ready for use.
// Only relevant if we determined that we can't use a worker.
let nonWorkerSearchInitialized = false;
// The search div containing search input and search results.
let searchElement;
// The search input element.
let searchInput;
// The package name associated with the current page, if any.
let packageName;
let packageVersion;
// The module name associated with the current page, if any.
let moduleName;
// The class name associated with the current page, if any.
let className;
// Prefix to turn a site-relative URL into a page-relative URL.
// One of "", "../", "../../", etc.
let rootUrlPrefix;
// Prefix to turn a package-relative URL into a page-relative URL.
// One of "", "../", "../../", etc.
let packageUrlPrefix;
// The search result currently selected in the search results list.
let selectedSearchResult = null;
// Initializes the UI.
// Wrapped in a function to avoid execution in tests.
// noinspection JSUnusedGlobalSymbols
function onLoad() {
isWebKitBrowser = navigator.userAgent.indexOf('AppleWebKit') !== -1;
searchElement = document.getElementById('search');
searchInput = document.getElementById('search-input');
packageName = searchInput.dataset.packageName || null;
packageVersion = searchInput.dataset.packageVersion || null;
moduleName = searchInput.dataset.moduleName || null;
className = searchInput.dataset.className || null;
rootUrlPrefix = searchInput.dataset.rootUrlPrefix;
packageUrlPrefix = searchInput.dataset.packageUrlPrefix;
initExpandTargetMemberDocs();
initNavigateToMemberPage();
initToggleMemberDocs();
initToggleInheritedMembers();
initCopyModuleUriToClipboard();
initSearchUi();
}
// If page URL contains a fragment, expand the target member's docs.
// Handled in JS rather than CSS so that target member can still be manually collapsed.
function initExpandTargetMemberDocs() {
const expandTargetDocs = () => {
const hash = window.location.hash;
if (hash.length === 0) return;
const target = document.getElementById(hash.substring(1));
if (!target) return;
const member = target.nextElementSibling;
if (!member || !member.classList.contains('with-expandable-docs')) return;
expandMemberDocs(member);
}
window.addEventListener('hashchange', expandTargetDocs);
expandTargetDocs();
}
// For members that have their own page, navigate to that page when the member's box is clicked.
function initNavigateToMemberPage() {
const elements = document.getElementsByClassName('with-page-link');
for (const element of elements) {
const memberLink = element.getElementsByClassName('name-decl')[0];
// check if this is actually a link
// (it isn't if the generator couldn't resolve the link target)
if (memberLink.tagName === 'A') {
element.addEventListener('click', (e) => {
// don't act if user clicked a link
if (e.target !== null && e.target.closest('a') !== null) return;
// don't act if user clicked to select some text
if (window.getSelection().toString()) return;
memberLink.click();
});
}
}
}
// Expands and collapses member docs.
function initToggleMemberDocs() {
const elements = document.getElementsByClassName('with-expandable-docs');
for (const element of elements) {
element.addEventListener('click', (e) => {
// don't act if user clicked a link
if (e.target !== null && e.target.closest('a') !== null) return;
// don't act if user clicked to select some text
if (window.getSelection().toString()) return;
toggleMemberDocs(element);
});
}
}
// Shows and hides inherited members.
function initToggleInheritedMembers() {
const memberGroups = document.getElementsByClassName('member-group');
for (const group of memberGroups) {
const button = group.getElementsByClassName('toggle-inherited-members-link')[0];
if (button !== undefined) {
const members = group.getElementsByClassName('inherited');
button.addEventListener('click', () => toggleInheritedMembers(button, members));
}
}
}
// Copies the module URI optionally displayed on a module page to the clipboard.
function initCopyModuleUriToClipboard() {
const copyUriButtons = document.getElementsByClassName('copy-uri-button');
for (const button of copyUriButtons) {
const moduleUri = button.previousElementSibling;
button.addEventListener('click', e => {
e.stopPropagation();
const range = document.createRange();
range.selectNodeContents(moduleUri);
const selection = getSelection();
selection.removeAllRanges();
selection.addRange(range);
try {
document.execCommand('copy');
} catch (e) {
} finally {
selection.removeAllRanges();
}
});
}
}
// Expands or collapses member docs.
function toggleMemberDocs(memberElem) {
const comments = memberElem.getElementsByClassName('expandable');
const icon = memberElem.getElementsByClassName('expandable-docs-icon')[0];
const isCollapsed = icon.textContent === 'expand_more';
if (isCollapsed) {
for (const comment of comments) expandElement(comment);
icon.textContent = 'expand_less';
} else {
for (const comment of comments) collapseElement(comment);
icon.textContent = 'expand_more';
}
}
// Expands member docs unless they are already expanded.
function expandMemberDocs(memberElem) {
const icon = memberElem.getElementsByClassName('expandable-docs-icon')[0];
const isCollapsed = icon.textContent === 'expand_more';
if (!isCollapsed) return;
const comments = memberElem.getElementsByClassName('expandable');
for (const comment of comments) expandElement(comment);
icon.textContent = 'expand_less';
}
// Shows and hides inherited members.
function toggleInheritedMembers(button, members) {
const isCollapsed = button.textContent === 'show inherited';
if (isCollapsed) {
for (const member of members) expandElement(member);
button.textContent = 'hide inherited';
} else {
for (const member of members) collapseElement(member);
button.textContent = 'show inherited'
}
}
// Expands an element.
// Done in two steps to make transition work (can't transition from 'hidden').
// For some reason (likely related to removing 'hidden') the transition isn't animated in FF.
// When using timeout() instead of requestAnimationFrame()
// there is *some* animation in FF but still doesn't look right.
function expandElement(element) {
element.classList.remove('hidden');
requestAnimationFrame(() => {
element.classList.remove('collapsed');
});
}
// Collapses an element.
// Done in two steps to make transition work (can't transition to 'hidden').
function collapseElement(element) {
element.classList.add('collapsed');
const listener = () => {
element.removeEventListener('transitionend', listener);
element.classList.add('hidden');
};
element.addEventListener('transitionend', listener);
}
// Initializes the search UI and sets up delayed initialization of the search engine.
function initSearchUi() {
// initialize search engine the first time that search input receives focus
const onFocus = () => {
searchInput.removeEventListener('focus', onFocus);
initSearchWorker();
};
searchInput.addEventListener('focus', onFocus);
// clear search when search input loses focus,
// except if this happens due to a search result being clicked,
// in which case clearSearch() will be called by the link's click handler,
// and calling it here would prevent the click handler from firing
searchInput.addEventListener('focusout', () => {
if (document.querySelector('#search-results:hover') === null) clearSearch();
});
// trigger search when user hasn't typed in a while
let timeoutId = null;
// Using anything other than `overflow: visible` for `#search-results`
// slows down painting significantly in WebKit browsers (at least Safari/Mac).
// Compensate by using a higher search delay, which is less annoying than a blocking UI.
const delay = isWebKitBrowser ? 200 : 100;
searchInput.addEventListener('input', () => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => triggerSearch(searchInput.value), delay);
});
// keyboard shortcut for entering search
document.addEventListener('keyup', e => {
// could additionally support '/' like GitHub and Gmail do,
// but this would require overriding the default behavior of '/' on Firefox
if (e.key === 's') searchInput.focus();
});
// keyboard navigation for search results
searchInput.addEventListener('keydown', e => {
const results = document.getElementById('search-results');
if (results !== null) {
if (e.key === 'ArrowDown') {
selectNextResult(results.firstElementChild);
e.preventDefault();
} else if (e.key === 'ArrowUp') {
selectPrevResult(results.firstElementChild);
e.preventDefault();
}
}
});
searchInput.addEventListener('keyup', e => {
if (e.key === 'Enter' && selectedSearchResult !== null) {
selectedSearchResult.firstElementChild.click();
clearSearch();
}
});
}
// Initializes the search worker.
function initSearchWorker() {
const workerScriptUrl = rootUrlPrefix + 'scripts/search-worker.js';
try {
searchWorker = new Worker(workerScriptUrl, {name: packageName === null ? "main" : packageName + '/' + packageVersion});
searchWorker.addEventListener('message', e => handleSearchResults(e.data.query, e.data.results));
} catch (e) {
// could not initialize worker, presumably because we are a file:/// page and content security policy got in the way
// fall back to running searches synchronously without a worker
// this requires loading search related scripts that would otherwise be loaded by the worker
searchWorker = null;
let pendingScripts = 3;
const onScriptLoaded = () => {
if (--pendingScripts === 0) {
initSearchIndex();
nonWorkerSearchInitialized = true;
if (searchInput.focused) {
triggerSearch(searchInput.value);
}
}
};
const script1 = document.createElement('script');
script1.src = (packageName === null ? rootUrlPrefix : packageUrlPrefix) + 'search-index.js';
script1.async = true;
script1.onload = onScriptLoaded;
document.head.append(script1);
const script2 = document.createElement('script');
script2.src = rootUrlPrefix;
script2.async = true;
script2.onload = onScriptLoaded;
document.head.append(script2);
const script3 = document.createElement('script');
script3.src = workerScriptUrl;
script3.async = true;
script3.onload = onScriptLoaded;
document.head.append(script3);
}
}
// Updates search results unless they are stale.
function handleSearchResults(query, results) {
if (query.inputValue !== searchInput.value) return;
updateSearchResults(renderSearchResults(query, results));
}
// TODO: Should this (or its callers) use requestAnimationFrame() ?
// Removes any currently displayed search results, then displays the given results if non-null.
function updateSearchResults(resultsDiv) {
selectedSearchResult = null;
const oldResultsDiv = document.getElementById('search-results');
if (oldResultsDiv !== null) {
searchElement.removeChild(oldResultsDiv);
}
if (resultsDiv != null) {
searchElement.append(resultsDiv);
selectNextResult(resultsDiv.firstElementChild);
}
}
// Returns the module of the given member, or `null` if the given member is a module.
function getModule(member) {
switch (member.level) {
case 0:
return null;
case 1:
return member.parent;
case 2:
return member.parent.parent;
}
}
// Triggers a search unless search input is invalid or incomplete.
function triggerSearch(inputValue) {
const query = parseSearchInput(inputValue);
if (!isActionableQuery(query)) {
handleSearchResults(query, null);
return;
}
if (searchWorker !== null) {
searchWorker.postMessage({query, packageName, moduleName, className});
} else if (nonWorkerSearchInitialized) {
const results = runSearch(query, packageName, moduleName, className);
handleSearchResults(query, results);
}
}
// Tells if the given Unicode character is a whitespace character.
function isWhitespace(ch) {
const cp = ch.codePointAt(0);
if (cp >= 9 && cp <= 13 || cp === 32 || cp === 133 || cp === 160) return true;
if (cp < 5760) return false;
return cp === 5760 || cp >= 8192 && cp <= 8202
|| cp === 8232 || cp === 8233 || cp === 8239 || cp === 8287 || cp === 12288;
}
// Trims the given Unicode characters.
function trim(chars) {
const length = chars.length;
let startIdx, endIdx;
for (startIdx = 0; startIdx < length; startIdx += 1) {
if (!isWhitespace(chars[startIdx])) break;
}
for (endIdx = chars.length - 1; endIdx > startIdx; endIdx -= 1) {
if (!isWhitespace(chars[endIdx])) break;
}
return chars.slice(startIdx, endIdx + 1);
}
// Parses the user provided search input.
// Preconditions:
// inputValue !== ''
function parseSearchInput(inputValue) {
const chars = trim(Array.from(inputValue));
const char0 = chars[0]; // may be undefined
const char1 = chars[1]; // may be undefined
const prefix = char1 === ':' ? char0 + char1 : null;
const kind =
prefix === null ? null :
char0 === 'm' ? 1 :
char0 === 't' ? 2 :
char0 === 'c' ? 3 :
char0 === 'f' ? 4 :
char0 === 'p' ? 5 :
undefined;
const unprefixedChars = kind !== null && kind !== undefined ?
trim(chars.slice(2, chars.length)) :
chars;
const normalizedCps = toNormalizedCodePoints(unprefixedChars);
return {inputValue, prefix, kind, normalizedCps};
}
// Converts a Unicode character array to an array of normalized Unicode code points.
// Normalization turns characters into their base forms, e.g., é into e.
// Since JS doesn't support case folding, `toLocaleLowerCase()` is used instead.
// Note: Keep in sync with same function in search-worker.js.
function toNormalizedCodePoints(characters) {
return Uint32Array.from(characters, ch => ch.normalize('NFD')[0].toLocaleLowerCase().codePointAt(0));
}
// Tells if the given query is valid and long enough to be worth running.
// Prefixed queries require fewer minimum characters than unprefixed queries.
// This avoids triggering a search while typing a prefix yet still enables searching for single-character names.
// For example, `p:e` finds `pkl.math#E`.
function isActionableQuery(query) {
const kind = query.kind;
const queryCps = query.normalizedCps;
return kind !== undefined && (kind !== null && queryCps.length > 0 || queryCps.length > 1);
}
// Renders the given search results for the given query.
// Preconditions:
// isActionableQuery(query) ? results !== null : results === null
function renderSearchResults(query, results) {
const resultsDiv = document.createElement('div');
resultsDiv.id = 'search-results';
const ul = document.createElement('ul');
resultsDiv.append(ul);
if (results === null) {
if (query.kind !== undefined) return null;
const li = document.createElement('li');
li.className = 'heading';
li.textContent = 'Unknown search prefix. Use one of <b>m:</b> (module), <b>c:</b> (class), <b>f:</b> (function), or <b>p:</b> (property).';
ul.append(li);
return resultsDiv;
}
const {exactMatches, classMatches, moduleMatches, otherMatches} = results;
if (exactMatches.length + classMatches.length + moduleMatches.length + otherMatches.length === 0) {
renderHeading('No results found', ul);
return resultsDiv;
}
if (exactMatches.length > 0) {
renderHeading('Top hits', ul);
renderMembers(query.normalizedCps, exactMatches, ul);
}
if (classMatches.length > 0) {
renderHeading('Class', ul, className);
renderMembers(query.normalizedCps, classMatches, ul);
}
if (moduleMatches.length > 0) {
renderHeading('Module', ul, moduleName);
renderMembers(query.normalizedCps, moduleMatches, ul);
}
if (otherMatches.length > 0) {
renderHeading('Other results', ul);
renderMembers(query.normalizedCps, otherMatches, ul);
}
return resultsDiv;
}
// Adds a heading such as `Top matches` to the search results list.
function renderHeading(title, ul, name = null) {
const li = document.createElement('li');
li.className = 'heading';
li.append(title);
if (name != null) {
li.append(' ');
li.append(span('heading-name', name))
}
ul.append(li);
}
// Adds matching members to the search results list.
function renderMembers(queryCps, members, ul) {
for (const member of members) {
ul.append(renderMember(queryCps, member));
}
}
// Renders a member to be added to the search result list.
function renderMember(queryCps, member) {
const result = document.createElement('li');
result.className = 'result';
if (member.deprecated) result.className = 'deprecated';
const link = document.createElement('a');
result.append(link);
link.href = (packageName === null ? rootUrlPrefix : packageUrlPrefix) + member.url;
link.addEventListener('mousedown', () => selectResult(result));
link.addEventListener('click', clearSearch);
const keyword = getKindKeyword(member.kind);
// noinspection JSValidateTypes (IntelliJ bug?)
if (keyword !== null) {
link.append(span('keyword', keyword), ' ');
}
// prefix with class name if a class member
if (member.level === 2) {
link.append(span("context", member.parent.name + '.'));
}
const name = span('result-name');
if (member.matchNameIdx === 0) { // main name matched
highlightMatch(queryCps, member.names[0], member.matchStartIdx, name);
} else { // aka name matched
name.append(member.name);
}
link.append(name);
if (member.signature !== null) {
link.append(member.signature);
}
if (member.matchNameIdx > 0) { // aka name matched
link.append(' ');
const aka = span('aka');
aka.append('(known as: ');
const name = span('aka-name');
highlightMatch(queryCps, member.names[member.matchNameIdx], member.matchStartIdx, name);
aka.append(name, ')');
link.append(aka);
}
// add module name if not a module
const module = getModule(member);
if (module !== null) {
link.append(' ', span('context', '(' + module.name + ')'));
}
return result;
}
// Returns the keyword for the given member kind.
function getKindKeyword(kind) {
switch (kind) {
case 0:
return "package";
case 1:
return "module";
case 2:
return "typealias";
case 3:
return "class";
case 4:
return "function";
case 5:
// properties have no keyword
return null;
}
}
// Highlights the matching characters in a member name.
// Preconditions:
// queryCps.length > 0
// computeMatchFrom(queryCps, name.normalizedCps, name.wordStarts, matchStartIdx)
function highlightMatch(queryCps, name, matchStartIdx, parentElem) {
const queryLength = queryCps.length;
const codePoints = name.codePoints;
const nameCps = name.normalizedCps;
const nameLength = nameCps.length;
const wordStarts = name.wordStarts;
let queryIdx = 0;
let queryCp = queryCps[0];
let startIdx = matchStartIdx;
if (startIdx > 0) {
parentElem.append(String.fromCodePoint(...codePoints.subarray(0, startIdx)));
}
for (let nameIdx = startIdx; nameIdx < nameLength; nameIdx += 1) {
const nameCp = nameCps[nameIdx];
if (queryCp !== nameCp) {
const newNameIdx = wordStarts[nameIdx];
parentElem.append(
span('highlight', String.fromCodePoint(...codePoints.subarray(startIdx, nameIdx))));
startIdx = newNameIdx;
parentElem.append(String.fromCodePoint(...codePoints.subarray(nameIdx, newNameIdx)));
nameIdx = newNameIdx;
}
queryIdx += 1;
if (queryIdx === queryLength) {
parentElem.append(
span('highlight', String.fromCodePoint(...codePoints.subarray(startIdx, nameIdx + 1))));
if (nameIdx + 1 < nameLength) {
parentElem.append(String.fromCodePoint(...codePoints.subarray(nameIdx + 1, nameLength)));
}
return;
}
queryCp = queryCps[queryIdx];
}
throw 'Precondition violated: `computeMatchFrom()`';
}
// Creates a span element.
function span(className, text = null) {
const result = document.createElement('span');
result.className = className;
result.textContent = text;
return result;
}
// Creates a text node.
function text(content) {
return document.createTextNode(content);
}
// Navigates to the next member entry in the search results list, skipping headings.
function selectNextResult(ul) {
let next = selectedSearchResult === null ? ul.firstElementChild : selectedSearchResult.nextElementSibling;
while (next !== null) {
if (!next.classList.contains('heading')) {
selectResult(next);
scrollIntoView(next, {
behavior: 'instant', // better for keyboard navigation
scrollMode: 'if-needed',
block: 'nearest',
inline: 'nearest',
});
return;
}
next = next.nextElementSibling;
}
}
// Navigates to the previous member entry in the search results list, skipping headings.
function selectPrevResult(ul) {
let prev = selectedSearchResult === null ? ul.lastElementChild : selectedSearchResult.previousElementSibling;
while (prev !== null) {
if (!prev.classList.contains('heading')) {
selectResult(prev);
const prev2 = prev.previousElementSibling;
// make any immediately preceding heading visible as well (esp. important for first heading)
const scrollTo = prev2 !== null && prev2.classList.contains('heading') ? prev2 : prev;
scrollIntoView(scrollTo, {
behavior: 'instant', // better for keyboard navigation
scrollMode: 'if-needed',
block: 'nearest',
inline: 'nearest',
});
return;
}
prev = prev.previousElementSibling;
}
}
// Selects the given entry in the search results list.
function selectResult(li) {
if (selectedSearchResult !== null) {
selectedSearchResult.classList.remove('selected');
}
li.classList.add('selected');
selectedSearchResult = li;
}
// Clears the search input and hides/removes the search results list.
function clearSearch() {
searchInput.value = '';
updateSearchResults(null);
}
// Functions called by JS data scripts.
// noinspection JSUnusedGlobalSymbols
const runtimeData = {
links: (id, linksJson) => {
const links = JSON.parse(linksJson);
const fragment = document.createDocumentFragment();
let first = true;
for (const link of links) {
const {text, href, classes} = link
const a = document.createElement("a");
a.textContent = text;
if (href) a.href = href;
if (classes) a.className = classes;
if (first) {
first = false;
} else {
fragment.append(", ");
}
fragment.append(a);
}
const element = document.getElementById(id);
element.append(fragment);
element.classList.remove("hidden"); // dd
element.previousElementSibling.classList.remove("hidden"); // dt
}
}

View File

@@ -0,0 +1,30 @@
/**
* MIT License
*
* Copyright (c) 2023 Cody Olsen
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
var COMPLETE="complete",CANCELED="canceled";function raf(e){if("requestAnimationFrame"in window)return window.requestAnimationFrame(e);setTimeout(e,16)}function setElementScroll(e,t,n){e.self===e?e.scrollTo(t,n):(e.scrollLeft=t,e.scrollTop=n)}function getTargetScrollLocation(e,t){var n,l,i,o,r,a,s,f=e.align,c=e.target.getBoundingClientRect(),d=f&&null!=f.left?f.left:.5,u=f&&null!=f.top?f.top:.5,g=f&&null!=f.leftOffset?f.leftOffset:0,m=f&&null!=f.topOffset?f.topOffset:0,h=d,p=u;if(e.isWindow(t))a=Math.min(c.width,t.innerWidth),s=Math.min(c.height,t.innerHeight),l=c.left+t.pageXOffset-t.innerWidth*h+a*h,i=c.top+t.pageYOffset-t.innerHeight*p+s*p,i-=m,o=(l-=g)-t.pageXOffset,r=i-t.pageYOffset;else{a=c.width,s=c.height,n=t.getBoundingClientRect();var E=c.left-(n.left-t.scrollLeft),S=c.top-(n.top-t.scrollTop);l=E+a*h-t.clientWidth*h,i=S+s*p-t.clientHeight*p,l-=g,i-=m,l=Math.max(Math.min(l,t.scrollWidth-t.clientWidth),0),i=Math.max(Math.min(i,t.scrollHeight-t.clientHeight),0),o=l-t.scrollLeft,r=i-t.scrollTop}return{x:l,y:i,differenceX:o,differenceY:r}}function animate(e){var t=e._scrollSettings;if(t){var n=t.maxSynchronousAlignments,l=getTargetScrollLocation(t,e),i=Date.now()-t.startTime,o=Math.min(1/t.time*i,1);if(t.endIterations>=n)return setElementScroll(e,l.x,l.y),e._scrollSettings=null,t.end(COMPLETE);var r=1-t.ease(o);if(setElementScroll(e,l.x-l.differenceX*r,l.y-l.differenceY*r),i>=t.time)return t.endIterations++,animate(e);raf(animate.bind(null,e))}}function defaultIsWindow(e){return e.self===e}function transitionScrollTo(e,t,n,l){var i,o=!t._scrollSettings,r=t._scrollSettings,a=Date.now(),s={passive:!0};function f(e){t._scrollSettings=null,t.parentElement&&t.parentElement._scrollSettings&&t.parentElement._scrollSettings.end(e),n.debug&&console.log("Scrolling ended with type",e,"for",t),l(e),i&&(t.removeEventListener("touchstart",i,s),t.removeEventListener("wheel",i,s))}r&&r.end(CANCELED);var c=n.maxSynchronousAlignments;return null==c&&(c=3),t._scrollSettings={startTime:a,endIterations:0,target:e,time:n.time,ease:n.ease,align:n.align,isWindow:n.isWindow||defaultIsWindow,maxSynchronousAlignments:c,end:f},"cancellable"in n&&!n.cancellable||(i=f.bind(null,CANCELED),t.addEventListener("touchstart",i,s),t.addEventListener("wheel",i,s)),o&&animate(t),i}function defaultIsScrollable(e){return"pageXOffset"in e||(e.scrollHeight!==e.clientHeight||e.scrollWidth!==e.clientWidth)&&"hidden"!==getComputedStyle(e).overflow}function defaultValidTarget(){return!0}function findParentElement(e){if(e.assignedSlot)return findParentElement(e.assignedSlot);if(e.parentElement)return"BODY"===e.parentElement.tagName?e.parentElement.ownerDocument.defaultView||e.parentElement.ownerDocument.ownerWindow:e.parentElement;if(e.getRootNode){var t=e.getRootNode();if(11===t.nodeType)return t.host}}module.exports=function(e,t,n){if(e){"function"==typeof t&&(n=t,t=null),t||(t={}),t.time=isNaN(t.time)?1e3:t.time,t.ease=t.ease||function(e){return 1-Math.pow(1-e,e/2)};var l,i=findParentElement(e),o=1,r=t.validTarget||defaultValidTarget,a=t.isScrollable;for(t.debug&&(console.log("About to scroll to",e),i||console.error("Target did not have a parent, is it mounted in the DOM?"));i;)if(t.debug&&console.log("Scrolling parent node",i),r(i,o)&&(a?a(i,defaultIsScrollable):defaultIsScrollable(i))&&(o++,l=transitionScrollTo(e,i,t,s)),!(i=findParentElement(i))){s(COMPLETE);break}return l}function s(e){--o||n&&n(e)}};
},{}],2:[function(require,module,exports){
window.scrollIntoView=require("./scrollIntoView");
},{"./scrollIntoView":1}]},{},[2]);

View File

@@ -0,0 +1,282 @@
// noinspection DuplicatedCode
'use strict';
// populated by `initSearchIndex()`
let searchIndex;
// noinspection ThisExpressionReferencesGlobalObjectJS
const isWorker = 'DedicatedWorkerGlobalScope' in this;
if (isWorker) {
const workerName = self.name;
// relative to this file
const searchIndexUrl = workerName === "main" ?
'../search-index.js' :
'../' + workerName + '/search-index.js';
initSearchIndex();
addEventListener('message', e => {
const {query, packageName, moduleName, className} = e.data;
const results = runSearch(query, packageName, moduleName, className);
postMessage({query, results});
});
} else {
// non-worker environment
// `pkldoc.js` loads scripts and calls `initSearchIndex()`
}
// Initializes the search index.
function initSearchIndex() {
// noinspection JSUnresolvedVariable
const data = JSON.parse(searchData);
const index = Array(data.length);
let idx = 0;
for (const entry of data) {
const name = entry.name;
const names = toIndexedNames(entry);
// 0 -> package, 1 -> module, 2 -> type alias, 3 -> class, 4 -> function, 5 -> property
const kind = entry.kind;
const url = entry.url;
// noinspection JSUnresolvedVariable
const signature = entry.sig === undefined ? null : entry.sig;
// noinspection JSUnresolvedVariable
const parent = entry.parId === undefined ? null : index[entry.parId];
const level = parent === null ? 0 : parent.parent === null ? 1 : 2;
const deprecated = entry.deprecated !== undefined;
index[idx++] = {
name,
names,
kind,
url,
signature,
parent,
level,
deprecated,
// remaining attributes are set by `computeMatchFrom` and hence aren't strictly part of the search index
matchNameIdx: -1, // names[matchNameIdx] is the name that matched
matchStartIdx: -1, // names[matchNameIdx].codePoints[matchStartIdx] is the first code point that matched
similarity: 0 // number of code points matched relative to total number of code points (between 0.0 and 1.0)
};
}
searchIndex = index;
}
// Runs a search and returns its results.
function runSearch(query, packageName, moduleName, className) {
const queryCps = query.normalizedCps;
const queryKind = query.kind;
let exactMatches = [];
let classMatches = [];
let moduleMatches = [];
let otherMatches = [];
for (const member of searchIndex) {
if (queryKind !== null && queryKind !== member.kind) continue;
if (!isMatch(queryCps, member)) continue;
if (member.similarity === 1) {
exactMatches.push(member);
} else if (moduleName !== null && member.level === 1 && moduleName === member.parent.name) {
moduleMatches.push(member);
} else if (moduleName !== null && member.level === 2 && moduleName === member.parent.parent.name) {
if (className !== null && className === member.parent.name) {
classMatches.push(member);
} else {
moduleMatches.push(member);
}
} else {
otherMatches.push(member);
}
}
// Sorts members best-first.
function compareMembers(member1, member2) {
const normDiff = member2.similarity - member1.similarity; // higher is better
if (normDiff !== 0) return normDiff;
const lengthDiff = member1.matchNameLength - member2.matchNameLength; // lower is better
if (lengthDiff !== 0) return lengthDiff;
const kindDiff = member2.kind - member1.kind; // higher is better
if (kindDiff !== 0) return kindDiff;
return member1.matchNameIdx - member2.matchNameIdx; // lower is better
}
exactMatches.sort(compareMembers);
classMatches.sort(compareMembers);
moduleMatches.sort(compareMembers);
otherMatches.sort(compareMembers);
return {exactMatches, classMatches, moduleMatches, otherMatches};
}
// Indexes a member's names.
function toIndexedNames(entry) {
const result = [];
result.push(toIndexedName(entry.name));
// noinspection JSUnresolvedVariable
const alsoKnownAs = entry.aka;
if (alsoKnownAs !== undefined) {
for (const name of alsoKnownAs) {
result.push(toIndexedName(name));
}
}
return result;
}
// Indexes the given name.
function toIndexedName(name) {
const characters = Array.from(name);
const codePoints = Uint32Array.from(characters, ch => ch.codePointAt(0));
const normalizedCps = toNormalizedCodePoints(characters);
const wordStarts = toWordStarts(characters);
return {codePoints, normalizedCps, wordStarts};
}
// Converts a Unicode character array to an array of normalized Unicode code points.
// Normalization turns characters into their base forms, e.g., é into e.
// Since JS doesn't support case folding, `toLocaleLowerCase()` is used instead.
function toNormalizedCodePoints(characters) {
return Uint32Array.from(characters, ch => ch.normalize('NFD')[0].toLocaleLowerCase().codePointAt(0));
}
// Returns an array of same length as `characters` that for every index, holds the index of the next word start.
// Preconditions:
// characters.length > 0
function toWordStarts(characters) {
const length = characters.length;
// -1 is used as 'no next word start exists' -> use signed int array
const result = length <= 128 ? new Int8Array(length) : new Int16Array(length);
if (length > 1) {
let class1 = toCharClass(characters[length - 1]);
let class2;
let wordStart = -1;
for (let idx = length - 1; idx >= 1; idx -= 1) {
class2 = class1;
class1 = toCharClass(characters[idx - 1]);
const diff = class1 - class2;
// transitions other than uppercase -> other
if (diff !== 0 && diff !== 3) wordStart = idx;
result[idx] = wordStart;
// uppercase -> other
if (diff === 3) wordStart = idx - 1;
}
}
// first character is always a word start
result[0] = 0;
return result;
}
const regexIsUppercase = /\p{Lu}/u
const regexIsNumericCharacter = /\p{N}/u
// Partitions characters into uppercase, digit, dot, and other.
function toCharClass(ch) {
return regexIsUppercase.test(ch) ? 3 : regexIsNumericCharacter.test(ch) ? 2 : ch === '.' ? 1 : 0;
}
// Tests if `queryCps` matches any of `member`'s names.
// If so, records information about the match in `member`.
// Preconditions:
// queryCps.length > 0
function isMatch(queryCps, member) {
const queryLength = queryCps.length;
let nameIdx = 0;
for (const name of member.names) {
const nameCps = name.normalizedCps;
const nameLength = nameCps.length;
const wordStarts = name.wordStarts;
const maxStartIdx = nameLength - queryLength;
for (let startIdx = 0; startIdx <= maxStartIdx; startIdx += 1) {
const matchLength = computeMatchFrom(queryCps, nameCps, wordStarts, startIdx);
if (matchLength > 0) {
member.matchNameIdx = nameIdx;
member.matchStartIdx = startIdx;
// Treat exact match of last module name component as exact match (similarity == 1).
// For example, treat "PodSpec" as exact match for "io.k8s.api.core.v1.PodSpec".
// Because "ps" is considered an exact match for "PodSpec",
// it is also considered an exact match for "io.k8s.api.core.v1.PodSpec".
const isExactMatchOfLastModuleNameComponent =
startIdx > 0 && nameCps[startIdx - 1] === 46 /* '.' */ && matchLength === nameLength - startIdx;
member.similarity = isExactMatchOfLastModuleNameComponent ? 1 : matchLength / nameLength;
member.matchNameLength = nameLength;
return true;
}
}
nameIdx += 1;
}
return false;
}
// Tests if the given query matches the given name from `startIdx` on.
// Returns the number of code points matched.
// Word start matches get special treatment.
// For example, `sb` is considered to match all code points of `StringBuilder`.
// Preconditions:
// queryCps.length > 0
// nameCps.length > 0
// wordStarts.length === nameCps.length
// startIdx < nameCps.length
function computeMatchFrom(queryCps, nameCps, wordStarts, startIdx) {
const queryLength = queryCps.length;
const nameLength = nameCps.length;
const beginsWithWordStart = wordStarts[startIdx] === startIdx;
let queryIdx = 0;
let matchLength = 0;
let queryCp = queryCps[0];
for (let nameIdx = startIdx; nameIdx < nameLength; nameIdx += 1) {
const nameCp = nameCps[nameIdx];
if (queryCp === nameCp) {
matchLength += 1;
} else { // check for word start match
if (nameIdx === startIdx || !beginsWithWordStart) return 0;
const newNameIdx = wordStarts[nameIdx];
if (newNameIdx === -1) return 0;
const newNameCp = nameCps[newNameIdx];
if (queryCp !== newNameCp) return 0;
matchLength += newNameIdx - nameIdx + 1;
nameIdx = newNameIdx;
}
queryIdx += 1;
if (queryIdx === queryLength) {
// in case of a word start match, increase matchLength by number of remaining chars of the last matched word
const nextIdx = nameIdx + 1;
if (beginsWithWordStart && nextIdx < nameLength) {
const nextStart = wordStarts[nextIdx];
if (nextStart === -1) {
matchLength += nameLength - nextIdx;
} else {
matchLength += nextStart - nextIdx;
}
}
return matchLength;
}
queryCp = queryCps[queryIdx];
}
return 0;
}

View File

@@ -0,0 +1,666 @@
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 400;
src: local('Lato Regular'), local('Lato-Regular'),
url('../fonts/lato-v14-latin_latin-ext-regular.woff2') format('woff2')
}
@font-face {
font-family: 'Lato';
font-style: normal;
font-weight: 700;
src: local('Lato Bold'), local('Lato-Bold'),
url('../fonts/lato-v14-latin_latin-ext-700.woff2') format('woff2')
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: local('Open Sans Regular'), local('OpenSans-Regular'),
url('../fonts/open-sans-v15-latin_latin-ext-regular.woff2') format('woff2')
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 400;
src: local('Open Sans Italic'), local('OpenSans-Italic'),
url('../fonts/open-sans-v15-latin_latin-ext-italic.woff2') format('woff2')
}
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 700;
src: local('Open Sans Bold'), local('OpenSans-Bold'),
url('../fonts/open-sans-v15-latin_latin-ext-700.woff2') format('woff2')
}
@font-face {
font-family: 'Open Sans';
font-style: italic;
font-weight: 700;
src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'),
url('../fonts/open-sans-v15-latin_latin-ext-700italic.woff2') format('woff2')
}
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 400;
src: local('Source Code Pro'), local('SourceCodePro-Regular'),
url('../fonts/source-code-pro-v7-latin_latin-ext-regular.woff2') format('woff2')
}
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 700;
src: local('Source Code Pro Bold'), local('SourceCodePro-Bold'),
url('../fonts/source-code-pro-v7-latin_latin-ext-700.woff2') format('woff2')
}
@font-face {
font-family: 'Material Icons';
font-style: normal;
font-weight: 400;
src: local('Material Icons'),
local('MaterialIcons-Regular'),
url(../fonts/MaterialIcons-Regular.woff2) format('woff2');
}
.material-icons {
/*noinspection CssNoGenericFontName*/
font-family: 'Material Icons';
font-weight: normal;
font-style: normal;
font-size: 24px;
display: inline-block;
width: 1em;
height: 1em;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
-moz-osx-font-smoothing: grayscale;
font-feature-settings: 'liga';
}
input[type=search] {
-webkit-appearance: textfield;
}
input[type=search]::-webkit-search-decoration {
-webkit-appearance: none;
}
input::-moz-placeholder {
opacity: 1;
}
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
border: 0;
font-family: inherit;
font-size: 100%;
font-style: inherit;
font-weight: inherit;
margin: 0;
outline: 0;
padding: 0;
vertical-align: baseline;
}
body {
margin: 0;
font-family: Lato, Arial, sans-serif;
background-color: #f0f3f6;
scroll-behavior: smooth;
}
a, a:visited, a:hover, a:active {
color: inherit;
}
a:hover {
text-decoration: none;
transition: 0s;
}
code, .member-modifiers, .member-signature, .doc-comment pre, #search-results li.result, .result-name, .heading-name, .aka-name {
font-family: "Source Code Pro", monospace;
letter-spacing: -0.03em;
}
header {
position: fixed;
top: 0;
left: 0;
width: 100vw; /* vw to make sure that positioning is the same whether or not vertical scrollbar is displayed */
height: 32px;
z-index: 1;
background-color: #364550;
padding: 7px 0 7px;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.18), 0 4px 8px rgba(0, 0, 0, 0.28);
}
#doc-title {
position: absolute;
margin-top: 8px;
margin-left: 15px;
}
#doc-title a {
color: #fff;
text-decoration: none;
}
#search {
position: relative;
width: 50vw;
margin: 0 auto;
}
#search-icon {
position: absolute;
left: 0;
top: 2px;
padding: 4px;
font-size: 21px;
color: #a5a9a9;
}
#search-input {
margin-top: 2px;
width: 100%;
height: 28px;
text-indent: 28px;
font-size: 0.85em;
background-color: rgba(255, 255, 255, 0.2);
border: none;
border-radius: 3px;
color: #fff;
}
#search-input:focus {
background-color: #6D7880;
outline: none;
}
#search-input::placeholder {
text-align: center;
color: #A5A9A9;
}
#search-input:focus::placeholder {
color: transparent;
}
#search-results {
position: fixed;
box-sizing: border-box;
top: 38px;
left: 25vw;
right: 25vw;
width: 50vw;
max-height: 80%;
color: #103a51;
background: white;
border: solid 1px #6D7880;
border-radius: 3px;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.18), 0 4px 8px rgba(0, 0, 0, 0.28);
white-space: nowrap;
overflow: auto; /* in safari, this slows down painting, blocking the ui */
/*noinspection CssUnknownProperty*/
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
}
#search-results a {
text-decoration: none;
}
#search-results a:hover {
text-decoration: underline;
}
#search-results ul {
list-style: none;
font-size: 0.9em;
}
#search-results li {
padding: 0.2ch 3ch;
height: 17px; /* used same height regardless of which fonts are used in content */
}
#search-results li.heading {
background-color: #f0f3f6;
padding: 0.4ch 1ch;
}
#search-results li.result {
font-size: 0.9em;
}
#search-results .keyword {
color: #000082;
}
#search-results .highlight {
font-weight: bold;
}
#search-results .context {
color: gray;
}
#search-results .selected, #search-results .selected .keyword, #search-results .selected .aka, #search-results .selected .context {
background: darkblue;
color: white;
}
#search-results .deprecated {
text-decoration: line-through;
}
/* make sure that line-through of highlighted region of selected search result has the right color */
#search-results .deprecated.selected .highlight {
text-decoration: line-through;
}
main {
width: 70%;
margin: 60px auto 20px;
}
.declaration-parent-link {
margin: 0 0 1rem;
}
#declaration-title {
font-size: 2em;
font-weight: bold;
color: #103a51;
margin: 0.5rem 0;
}
#declaration-version {
color: #A5A9A9;
font-size: 0.9em;
vertical-align: bottom;
padding-left: 0.25em;
}
.member-group-links {
margin: 0.75em 0 1em 0;
}
.member-group-links li {
display: inline-block;
margin-right: 1em;
}
.member-info {
display: grid;
grid-template-columns: auto 1fr;
line-height: 1.5;
margin-top: 0.5em;
font-size: 0.9em;
}
.member-info dt {
grid-column: 1;
text-align: right;
}
.member-info dd {
grid-column: 2;
margin-left: 0.5em;
}
.copy-uri-button {
cursor: pointer;
font-size: inherit;
margin-left: 0.5em;
}
.member-group {
/* for absolutely positioned anchors */
position: relative;
}
.member-group-title {
margin: 1rem;
font-weight: bold;
color: #103a51;
}
.toggle-inherited-members {
font-size: 0.9em;
font-weight: normal;
margin-left: 0.5em;
}
.button-link {
text-decoration: underline;
}
.button-link:hover, .button-link:active {
text-decoration: none;
cursor: pointer;
}
.member-group ul {
list-style: none;
}
.member-group li {
/* for absolutely positioned anchors */
position: relative;
}
.anchor,
.anchor-param1,
.anchor-param2,
.anchor-param3,
.anchor-param4,
.anchor-param5,
.anchor-param6,
.anchor-param7,
.anchor-param8,
.anchor-param9 {
position: absolute;
top: -60px;
left: 0;
}
.anchor:target ~ .member,
.anchor-param1:target ~ .member,
.anchor-param2:target ~ .member,
.anchor-param3:target ~ .member,
.anchor-param4:target ~ .member,
.anchor-param5:target ~ .member,
.anchor-param6:target ~ .member,
.anchor-param7:target ~ .member,
.anchor-param8:target ~ .member,
.anchor-param9:target ~ .member {
border-left: 3px solid #222832;
}
.anchor:target ~ .member .name-decl,
.anchor-param1:target ~ .member .param1,
.anchor-param2:target ~ .member .param2,
.anchor-param3:target ~ .member .param3,
.anchor-param4:target ~ .member .param4,
.anchor-param5:target ~ .member .param5,
.anchor-param6:target ~ .member .param6,
.anchor-param7:target ~ .member .param7,
.anchor-param8:target ~ .member .param8,
.anchor-param9:target ~ .member .param9 {
font-weight: bold;
}
.member {
border-left: 3px solid transparent;
margin: 0 auto 0.5rem;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
font-size: 0.9em;
padding: 10px;
color: #222832;
}
.member:hover {
background-color: #f2f2f2;
}
.member-left {
width: 25%;
display: inline;
float: left;
padding-right: 6px;
min-height: 1px;
text-align: right;
}
.member-modifiers {
color: #000082;
}
.member-main {
display: block;
overflow: hidden;
}
.member-deprecated {
text-decoration: line-through;
}
.member-selflink {
visibility: hidden;
display: inline;
float: left;
padding-right: 20px;
color: #222832;
text-decoration: none;
}
.member-source-link {
visibility: hidden;
color: #fff;
background-color: #868e96;
display: inline-block;
margin-left: 1em;
padding: .25em .4em;
font-size: 75%;
font-weight: 700;
line-height: 1;
text-align: center;
vertical-align: bottom;
border-radius: .25rem
}
.member-source-link:visited, .member-source-link:hover, .member-source-link:active {
color: #fff;
}
.member:hover .member-source-link, .member:hover .member-selflink {
visibility: visible;
}
.member.inherited, .member.hidden-member {
opacity: 0.75;
}
.member.inherited .context {
color: gray;
}
.member.with-page-link, .member.with-expandable-docs {
cursor: pointer;
}
.member .expandable-docs-icon {
float: right;
}
/*
Don't style a.name-decl as link
because the entire .member.with-page-link is effectively a link (via JS).
*/
.member.with-page-link a.name-decl {
text-decoration: none;
}
.expandable {
transform: scaleY(1);
transition: transform 0.25s;
}
.expandable.collapsed {
transform: scaleY(0);
}
.expandable.hidden {
display: none;
}
/* show an otherwise hidden inherited member if it's a link target */
.anchor:target + .expandable.collapsed.hidden {
display: inherit;
transform: scaleY(1);
}
.doc-comment {
color: #103a51;
margin-top: 0.5rem;
font-family: "Open Sans", sans-serif;
font-size: 0.9em;
}
.doc-comment p {
margin: 0.7em 0;
}
.doc-comment p:first-child {
margin-top: 0;
}
.doc-comment p:last-child {
margin-bottom: 0;
}
.doc-comment h1,
.doc-comment h2,
.doc-comment h3,
.doc-comment h4,
.doc-comment h5,
.doc-comment h6 {
margin-bottom: 0.7em;
margin-top: 1.4em;
display: block;
text-align: left;
font-weight: bold;
}
.doc-comment pre {
padding: 0.5em;
border: 0 solid #ddd;
background-color: #364550;
color: #ddd;
margin: 5px 0;
display: block;
border-radius: 0.2em;
overflow-x: auto;
}
.doc-comment ul {
display: block;
list-style: circle;
padding-left: 20px;
}
.doc-comment ol {
display: block;
padding-left:20px;
}
.doc-comment ol.decimal {
list-style: decimal;
}
.doc-comment ol.lowerAlpha {
list-style: lower-alpha;
}
.doc-comment ol.upperAlpha {
list-style: upper-alpha;
}
.doc-comment ol.lowerRoman {
list-style: lower-roman;
}
.doc-comment ol.upperRoman {
list-style: upper-roman;
}
.doc-comment li {
display: list-item;
}
.doc-comment code {
font-weight: normal;
}
.doc-comment em, .doc-comment i {
font-style: italic;
}
.doc-comment strong, .doc-comment b {
font-weight: bold;
}
.runtime-data.hidden {
display: none;
}
.runtime-data .current-version {
font-weight: bold;
}
/*
Styling for Markdown tables in doc comments.
From: https://gist.github.com/andyferra/2554919
*/
table {
padding: 0;
}
table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0;
}
table tr:nth-child(2n) {
background-color: #f8f8f8;
}
table tr th {
font-weight: bold;
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px;
}
table tr td {
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px;
}
table tr th :first-child, table tr td :first-child {
margin-top: 0;
}
table tr th :last-child, table tr td :last-child {
margin-bottom: 0;
}

View File

@@ -0,0 +1,22 @@
amends "pkl:DocPackageInfo"
name = "com.externalpackage"
version = "1.2.3"
importUri = "https://pkl.io/"
authors {
"publisher-externalpackage@group.apple.com"
}
sourceCode = "https://example.com/externalpackage/"
sourceCodeUrlScheme = "https://example.com/blob/\(version)%{path}#L%{line}-L%{endLine}"
issueTracker = "https://example.com/externalpackage/issues"
dependencies {
new {
name = "pkl"
// use fixed version to avoid churn in expected test outputs
version = "0.24.0"
sourceCode = "https://github.com/apple/\(name)/blob/dev/stdlib/"
sourceCodeUrlScheme = "https://github.com/apple/\(name)/blob/\(version)/stdlib%{path}#L%{line}-L%{endLine}"
documentation = "https://pkl-lang.org/stdlib/\(name)/\(version)/"
}
}

View File

@@ -0,0 +1,3 @@
module com.externalpackage.external1
class MyClass

View File

@@ -0,0 +1,3 @@
module com.externalpackage.external2
class MyClass

View File

@@ -0,0 +1,7 @@
open module com.package1.baseModule
baseProperty = 42
function baseMethod() = 42
class BaseClass {}

View File

@@ -0,0 +1,30 @@
open module com.package1.classAnnotations
/// This [AnnotatedClss] thought to have a correctly spelled name.
@Deprecated {
message = "Spelling mistake."
replaceWith = "AnnotatedClass"
}
@AlsoKnownAs {
names { "OtherName" }
}
class AnnotatedClss
/// This [AnnotatedClssWithExpandableComment] thought to have a correctly spelled name.
///
/// Unfortunately, it did not, as we explain in this expandable comment.
@Deprecated {
message = "Spelling mistake."
replaceWith = "AnnotatedClass"
}
@AlsoKnownAs {
names { "OtherName" }
}
class AnnotatedClssWithExpandableComment
// This [AnnotatedClass] indeed has a properly spelled name, but no doc comment.
@AlsoKnownAs {
names { "OtherName" }
}
@Deprecated // omit optional arguments
class AnnotatedClass

View File

@@ -0,0 +1,145 @@
/// The greatest breakthrough since ever.
///
/// ### Installation
///
/// Just follow these simple steps:
///
/// 1. Install it
/// 1. I promise it's easy.
/// 2. You'll figure it out.
/// 1. Install it
/// ```
/// name = "Pigeon"
/// age = 42
/// ```
/// 1. Install it
///
/// Let me **emphasize** how *simple* this is.
///
/// 😀😀😀 emoji day 😎😎😎 don't get 😡😡😡
///
/// ### Code
///
/// The code is beautiful:
///
/// ```
/// /// example module
/// module foo.bar
///
/// person {
/// name = "Pigeon"
/// age = 42
/// }
///
/// function sing() = "tra-la-la"
///
/// class Person {
/// name: String
/// age: Int
/// }
/// ```
///
/// ### Random Tips
///
/// - don't give up
/// - just don't
/// - don't give up
///
/// # Level 1
/// ## Level 2
/// ### Level 3
/// #### Level 4
/// ##### Level 5
/// ###### Level 6
///
/// | Command | Description |
/// | --- | --- |
/// | `git status` | List all *new or modified* files |
/// | `git diff` | Show file differences that **haven't been** staged |
open module com.package1.classComments
// Class with single-line code comment.
class Comments1
/*
Class with
multi-line
code comment.
*/
class Comments2
/// Class with single-line doc comment.
class Comments3
/// Class with multi-line and multi-paragraph doc comment (paragraph1, line1).
/// Class with multi-line and multi-paragraph doc comment (paragraph1, line2).
///
/// Class with multi-line and multi-paragraph doc comment (paragraph2, line1).
/// Class with multi-line and multi-paragraph doc comment (paragraph2, line2).
class Comments4
/// Class with [single-line](https://apple.com) *Markdown* doc comment.
class Comments5
/// Class with
/// [multi-line](https://apple.com)
/// *Markdown* doc comment.
class Comments6
/// 😀😀😀 Class with 😎😎😎 Unicode doc comment. 😡😡😡
class Comments7
/// The greatest breakthrough since ever.
///
/// ## Installation
///
/// Just follow these simple steps:
///
/// 1. Install it
/// 1. I promise it's easy.
/// 2. You'll figure it out.
/// 1. Install it
/// ```
/// name = "Pigeon"
/// age = 42
/// ```
/// 1. Install it
///
/// Let me **emphasize** how *simple* this is.
///
/// 😀😀😀 emoji day 😎😎😎 don't get 😡😡😡
///
/// ## Code
///
/// The code is beautiful:
///
/// ```
/// /// example module
/// module foo.bar
///
/// person {
/// name = "Pigeon"
/// age = 42
/// }
///
/// function sing() = "tra-la-la"
///
/// class Person {
/// name: String
/// age: Int
/// }
/// ```
///
/// ## Random Tips
///
/// - don't give up
/// - just don't
/// - don't give up
///
/// # Level 1
/// ## Level 2
/// ### Level 3
/// #### Level 4
/// ##### Level 5
/// ###### Level 6
class Comments8

View File

@@ -0,0 +1,29 @@
/// Class inheritance involving abstract, open, and final classes.
module com.package1.classInheritance
abstract class MyClass1 {
/// Inherited property comment.
abstract property1: Boolean
/// function method1 in class MyClass1.
abstract function method1(arg: String): Boolean
}
open class MyClass2 extends MyClass1 {
property1: Boolean = false
property2: String = ""
/// function method1 in class MyClass2.
function method1(arg: String): Boolean = Undefined()
function method2(arg: String): Boolean = Undefined()
}
abstract class MyClass3 extends MyClass2 {
property1: Boolean = true
function method1(arg: String): Boolean = Undefined()
}
class MyClass4 extends MyClass2 {
property4: String = ""
function method3(arg: String): Boolean = Undefined()
}

View File

@@ -0,0 +1,33 @@
/// Class methods with different kinds of comments.
module com.package1.classMethodComments
class Comments {
// Method with single-line code comment.
function method1(): Float = Undefined()
/*
Method with
multi-line
code comment.
*/
function method2(): Float = Undefined()
/// Method with single-line doc comment.
function method3(): Float = Undefined()
/// Method with
/// multi-line
/// doc comment.
function method4(): Float = Undefined()
/// Method with [single-line](https://apple.com) *Markdown* doc comment.
function method5(): Float = Undefined()
/// Method with
/// [multi-line](https://apple.com)
/// *Markdown* doc comment.
function method6(): Float = Undefined()
/// 😀😀😀 Method with 😎😎😎 Unicode doc comment. 😡😡😡
function method7(): Float = Undefined()
}

View File

@@ -0,0 +1,15 @@
/// Class methods with different modifiers.
module com.package1.classMethodModifiers
abstract class Modifiers {
/// Method with `abstract` modifier.
abstract function method1(arg: String): Boolean
/*
/// Method with `external` modifier.
external function method2(arg: String): Boolean
/// Method with multiple modifiers.
abstract external function method3(arg: String): Boolean
*/
}

View File

@@ -0,0 +1,43 @@
/// Class methods with different kinds of type annotations.
module com.package1.classMethodTypeAnnotations
class TypeAnnotations {
/// Zero-arg method without declared types.
function method1() = Undefined()
/// One-arg method without declared types.
function method2(arg1) = Undefined()
/// Two-arg method without declared types.
function method3(arg1, arg2) = Undefined()
/// Zero-arg method with simple types.
function method4(): String = Undefined()
/// One-arg method with simple types.
function method5(arg1: Boolean): Int = Undefined()
/// Two-arg method with simple types.
function method6(arg1: Int, arg2: Float): Duration = Undefined()
/// Two-arg method with list types.
function method7(arg1: List<Int>, arg2: List<Float>): List<Duration> = Undefined()
/// Two-arg method with set types.
function method8(arg1: Set<Int>, arg2: Set<Float>): Set<Duration> = Undefined()
/// Two-arg method with map types.
function method9(arg1: Map<Int, Int>, arg2: Map<Float, Float>): Map<Duration, Duration> = Undefined()
/// Two-arg method with optional types.
function method10(arg1: Int?, arg2: Float?): Duration? = Undefined()
/// Two-arg method with function types.
function method11(arg1: () -> Int, arg2: (Int) -> Float): (Int, Float) -> Duration = Undefined()
/// Two-arg method with partially declared types.
function method12(arg1: String, arg2): Boolean = Undefined()
/// One-arg method with complex types.
function method13(arg1: Map<List<String?>?, (Boolean?) -> Map<Int, Float>>): Map<List<Duration?>?, (DataSize?) -> Map<Any, Number>> = Undefined()
}

View File

@@ -0,0 +1,28 @@
/// Class methods whose types reference classes from
/// the same module, a different module, and external modules.
module com.package1.classMethodTypeReferences
import "shared.pkl"
import "../com.externalpackage/external1.pkl"
import "../com.externalpackage/external2.pkl"
class MyClass
class TypeReferences {
/// Method with intra-module types.
function method1(arg1: MyClass, arg2: MyClass): MyClass = Undefined()
/// Method with inter-module types.
function method2(arg1: shared.MyClass, arg2: shared.MyClass): shared.MyClass = Undefined()
/// Method with external-module types.
function method3(arg1: external1.MyClass, arg2: external2.MyClass): List<external1.MyClass> = Undefined()
/// Method with intra-module, inter-module, and external-module types.
function method4(arg1: MyClass, arg2: shared.MyClass): external1.MyClass = Undefined()
/// Method with complex intra-module, inter-module, and external-module types.
function method5(arg1: MyClass?, arg2: Map<shared.MyClass, external1.MyClass>): (external1.MyClass) -> external2.MyClass = Undefined()
}

View File

@@ -0,0 +1,13 @@
module com.package1.classPropertyAnnotations
class UserDefinedAnnotation extends Annotation {
messageOpt: String?
messageReq: String
}
class ClassWithAnnotatedProperty {
@UserDefinedAnnotation {
messageReq = "Hi!"
}
propertyUserDefinedAnnotation: Int = 42
}

View File

@@ -0,0 +1,33 @@
/// Class properties with different kinds of comments.
module com.package1.classPropertyComments
class Comments {
// Property with single-line code comment.
property1: Float = 3.14159265359
/*
Property with
multi-line
code comment.
*/
property2: Float = 3.14159265359
/// Property with single-line doc comment.
property3: Float = 3.14159265359
/// Property with
/// multi-line
/// doc comment.
property4: Float = 3.14159265359
/// Property with [single-line](https://apple.com) *Markdown* doc comment.
property5: Float = 3.14159265359
/// Property with
/// [multi-line](https://apple.com)
/// *Markdown* doc comment.
property6: Float = 3.14159265359
/// 😀😀😀 Property with 😎😎😎 Unicode doc comment. 😡😡😡
property7: Float = 3.14159265359
}

View File

@@ -0,0 +1,21 @@
/// Class properties with different modifiers.
module com.package1.classPropertyModifiers
abstract class Modifiers {
/// Property with `local` modifier.
local property1 = 3.14159265359
/// Property with `hidden` modifier.
hidden property2: Float = 3.14159265359
/// Property with `abstract` modifier.
abstract property3: Float
/// Property with multiple modifiers.
abstract hidden property4: Float
/*
/// Property with `external` modifier.
external property5: Float
*/
}

View File

@@ -0,0 +1,34 @@
/// Class properties with different kinds of type annotations.
module com.package1.classPropertyTypeAnnotations
class TypeAnnotations {
/// Property without declared type.
property1 = 3.14159265359
/// Property with simple type.
property2: Float = 3.14159265359
/// Property with list type.
property3: List<String> = List("1", "2", "3")
/// Property with set type.
property4: Set<String> = Set("1", "2", "3")
/// Property with map type.
property5: Map<String, Duration> = Map("one", 1.s, "two", 2.min, "three", 3.h)
/// Property with optional type.
property6: String? = "string"
/// Property with zero-arg function type.
property7: () -> String = () -> "string"
/// Property with one-arg function type.
property8: (String) -> Int = (str) -> str.length
/// Property with two-arg function type.
property9: (String, String) -> Int = (str1, str2) -> str1.length + str2.length
/// Property with complex type.
property10: Map<List<String?>?, (Boolean?) -> Map<Int, Float>> = Map(List("str"), (b) -> Map(3, 3.0))
}

View File

@@ -0,0 +1,38 @@
/// Class properties whose types reference classes from
/// the same module, a different module, and external modules.
module com.package1.classPropertyTypeReferences
import "shared.pkl"
import "../com.externalpackage/external1.pkl"
class MyClass
class TypeReferences {
/// Property with intra-module simple type.
property1: MyClass = new MyClass {}
/// Property with inter-module list type.
property2: List<shared.MyClass> = List(new shared.MyClass {})
/// Property with external-module set type.
property3: Set<external1.MyClass> = Set(new external1.MyClass {})
/// Property with intra-module and inter-module map type.
property4: Map<MyClass, shared.MyClass> = Map(new MyClass {}, new shared.MyClass {})
/// Property with external-module optional type.
property5: external1.MyClass? = new external1.MyClass {}
/// Property with zero-arg intra-module function type.
property6: () -> MyClass = () -> new MyClass {}
/// Property with one-arg inter-module and external-module function type.
property7: (shared.MyClass) -> external1.MyClass = (myClass) -> new external1.MyClass {}
/// Property with two-arg intra-module, inter-module, and external-module function type.
property8: (MyClass, shared.MyClass) -> external1.MyClass = (myClass1, myClass2) -> new external1.MyClass {}
/// Property with intra-module mapping type.
property9: Mapping<String, MyClass>
}

View File

@@ -0,0 +1,24 @@
module com.package1.classTypeConstraints
class Person1 {
name: String(length >= 3)
address: Address(street != city)
}
emailAddress = (str) -> str.matches(Regex(#".+@.+"#))
class Person2 {
email: String(emailAddress)
}
class Address {
street: String(!isEmpty)
city: String = "San Francisco"
}
class Project {
// constraint for element type of optional type
type: String(oneOf(List("open-source", "closed-source")))?
// constraints for map type and its constituent key/value types
contacts: Map<String(!isEmpty), String(emailAddress)>(length > 10, length < 20)
}

View File

@@ -0,0 +1,48 @@
/// Docs for Package 1.
///
/// * [docLinks]
/// * [docLinks.age]
/// * [docLinks.sing()]
/// * [docLinks.Person]
/// * [docLinks.Person.name]
/// * [docLinks.PersonList]
///
/// * [external1]
/// * [external1.MyClass]
@Deprecated { message = "com.package1 is deprecated" }
amends "pkl:DocPackageInfo"
import "docLinks.pkl"
import "../com.externalpackage/external1.pkl"
name = "com.package1"
version = "1.2.3"
importUri = "https://pkl.io/"
authors {
"package1-publisher@group.apple.com"
}
sourceCode = "https://example.com/package1/"
sourceCodeUrlScheme = "https://example.com/package1%{path}#L%{line}-L%{endLine}"
issueTracker = "https://issues.apple.com/package1/"
dependencies {
new {
name = "com.package2"
version = "4.5.6"
sourceCode = "https://example.com/package2/"
}
new {
name = "com.externalpackage"
version = "7.8.9"
sourceCode = "https://example.com/externalpackage/"
documentation = "https://example.com/docs/externalpackage/"
}
new {
name = "pkl"
// use fixed version to avoid churn in expected test outputs
version = "0.24.0"
sourceCode = "https://github.com/apple/pkl/blob/dev/stdlib/"
sourceCodeUrlScheme = "https://github.com/apple/pkl/blob/0.24.0/stdlib%{path}#L%{line}-L%{endLine}"
documentation = "https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/"
}
}

View File

@@ -0,0 +1,13 @@
@DocExample {
subjects {
"com.package1.docExampleSubject1"
"com.package1.docExampleSubject2"
}
}
module com.package1.docExample
amends "docExampleSubject1.pkl"
import "docExampleSubject2.pkl"
x = docExampleSubject2.y

View File

@@ -0,0 +1,6 @@
@DocExample { subjects { "com.package1.docExampleSubject1" } }
module com.package1.docExample2
amends "docExampleSubject1.pkl"
x = 42

View File

@@ -0,0 +1,3 @@
module com.package1.docExampleSubject1
x: Int

View File

@@ -0,0 +1,3 @@
module com.package1.docExampleSubject2
y: Int

View File

@@ -0,0 +1,84 @@
/// [external1], [external1.MyClass]
/// [shared], [shared.MyClass]
/// [age], [sing()], [Person], [Person.name], [Person.call()], [PersonList]
/// [docLinks], [docLinks.age], [docLinks.sing()],
/// [docLinks.Person], [docLinks.Person.name], [docLinks.PersonList],
/// [custom *link* text][docLinks.sing()]
/// [module], [module.age], [module.sing()],
/// [module.Person], [module.Person.name], [module.PersonList],
/// [custom *link* text][module.sing()]
module com.package1.docLinks
import "../com.externalpackage/external1.pkl"
import "shared.pkl"
import "docLinks.pkl"
/// [external1], [external1.MyClass]
/// [shared], [shared.MyClass]
/// [age], [sing()], [Person], [Person.name], [Person.call()], [PersonList]
/// [docLinks], [docLinks.age], [docLinks.sing()],
/// [docLinks.Person], [docLinks.Person.name], [docLinks.PersonList],
/// [custom *link* text][docLinks.sing()]
/// [module], [module.age], [module.sing()],
/// [module.Person], [module.Person.name], [module.PersonList],
/// [custom *link* text][module.sing()]
age: Int
/// [external1], [external1.MyClass]
/// [shared], [shared.MyClass]
/// [age], [sing()], [Person], [Person.name], [Person.call()], [PersonList]
/// [docLinks], [docLinks.age], [docLinks.sing()],
/// [docLinks.Person], [docLinks.Person.name], [docLinks.PersonList],
/// [custom *link* text][docLinks.sing()]
/// [module], [module.age], [module.sing()],
/// [module.Person], [module.Person.name], [module.PersonList],
/// [custom *link* text][module.sing()]
/// [song]
function sing(song: String) = "tra-la-la"
/// [external1], [external1.MyClass]
/// [shared], [shared.MyClass]
/// [age], [sing()], [Person], [Person.name], [Person.call()], [Person.call()], [PersonList]
/// [docLinks], [docLinks.age], [docLinks.sing()],
/// [docLinks.Person], [docLinks.Person.name], [docLinks.PersonList],
/// [custom *link* text][docLinks.sing()]
/// [module], [module.age], [module.sing()],
/// [module.Person], [module.Person.name], [module.PersonList],
/// [custom *link* text][module.sing()]
/// [name], [call()]
class Person {
/// [external1], [external1.MyClass]
/// [age], [sing()], [Person], [Person.name], [Person.call()], [PersonList]
/// [docLinks], [docLinks.age], [docLinks.sing()],
/// [docLinks.Person], [docLinks.Person.name], [docLinks.PersonList],
/// [custom *link* text][docLinks.sing()]
/// [module], [module.age], [module.sing()],
/// [module.Person], [module.Person.name], [module.PersonList],
/// [custom *link* text][module.sing()]
/// [name], [call()]
name: String
/// [external1], [external1.MyClass]
/// [shared], [shared.MyClass]
/// [age], [sing()], [Person], [Person.name], [Person.call()], [PersonList]
/// [docLinks], [docLinks.age], [docLinks.sing()],
/// [docLinks.Person], [docLinks.Person.name], [docLinks.PersonList],
/// [custom *link* text][docLinks.sing()]
/// [module], [module.age], [module.sing()],
/// [module.Person], [module.Person.name], [module.PersonList],
/// [custom *link* text][module.sing()]
/// [name], [call()]
/// [number]
function call(number: String) = "calling $number"
}
/// [external1], [external1.MyClass]
/// [shared], [shared.MyClass]
/// [age], [sing()], [Person], [Person.name], [Person.call()], [PersonList]
/// [docLinks], [docLinks.age], [docLinks.sing()],
/// [docLinks.Person], [docLinks.Person.name], [docLinks.PersonList],
/// [custom *link* text][docLinks.sing()]
/// [module], [module.age], [module.sing()],
/// [module.Person], [module.Person.name], [module.PersonList],
/// [custom *link* text][module.sing()]
typealias PersonList = List<Person>

View File

@@ -0,0 +1,31 @@
module com.package1.methodAnnotations
/// This [mthod()] thought to have a correctly spelled name.
@Deprecated {
message = "Spelling mistake."
replaceWith = "method()"
}
@AlsoKnownAs {
names { "function" }
}
function mthod(): Int = 42
/// This [mthod()] thought to have a correctly spelled name.
///
/// Unfortunately, it did not, as we explain in this expandable comment.
@Deprecated {
message = "Spelling mistake."
replaceWith = "method()"
}
@AlsoKnownAs {
names { "function" }
}
function mthodWithExpandableComment(): Int = 42
// This [method()] indeed has a properly spelled name, but no doc comment.
@AlsoKnownAs {
names { "function" }
}
function method(): Int = 42

View File

@@ -0,0 +1,54 @@
/// The greatest breakthrough since ever.
///
/// ### Installation
///
/// Just follow these simple steps:
///
/// 1. Install it
/// 1. I promise it's easy.
/// 2. You'll figure it out.
/// 1. Install it
/// ```
/// name = "Pigeon"
/// age = 42
/// ```
/// 1. Install it
///
/// Let me **emphasize** how *simple* this is.
///
/// 😀😀😀 emoji day 😎😎😎 don't get 😡😡😡
///
/// ### Code
///
/// The code is beautiful:
///
/// ```
/// /// example module
/// module foo.bar
///
/// person {
/// name = "Pigeon"
/// age = 42
/// }
///
/// function sing() = "tra-la-la"
///
/// class Person {
/// name: String
/// age: Int
/// }
/// ```
///
/// ### Random Tips
///
/// - don't give up
/// - just don't
/// - don't give up
///
/// # Level 1
/// ## Level 2
/// ### Level 3
/// #### Level 4
/// ##### Level 5
/// ###### Level 6
module com.package1.moduleComments

View File

@@ -0,0 +1,9 @@
module com.package1.moduleExtend
extends "baseModule.pkl"
extendProperty = 42
function extendMethod() = 42
class ExtendClass {}

View File

@@ -0,0 +1,2 @@
@ModuleInfo { minPklVersion = "0.10.0" }
module com.package1.moduleInfoAnnotation

View File

@@ -0,0 +1,5 @@
module com.package1.moduleMethodCommentInheritance
extends "moduleMethodComments.pkl"
function method3(arg: String): Boolean = Undefined()

View File

@@ -0,0 +1,31 @@
/// Module methods with different kinds of comments.
open module com.package1.moduleMethodComments
// Method with single-line code comment.
function method1(): Float = Undefined()
/*
Method with
multi-line
code comment.
*/
function method2(): Float = Undefined()
/// Method with single-line doc comment.
function method3(): Float = Undefined()
/// Method with
/// multi-line
/// doc comment.
function method4(): Float = Undefined()
/// Method with [single-line](https://apple.com) *Markdown* doc comment.
function method5(): Float = Undefined()
/// Method with
/// [multi-line](https://apple.com)
/// *Markdown* doc comment.
function method6(): Float = Undefined()
/// 😀😀😀 Method with 😎😎😎 Unicode doc comment. 😡😡😡
function method7(): Float = Undefined()

View File

@@ -0,0 +1,13 @@
/// Module methods with different modifiers.
module com.package1.moduleMethodModifiers
/// Method with `abstract` modifier.
abstract function method1(arg: String): Boolean
/*
/// Method with `external` modifier.
external function method2(arg: String): Boolean
/// Method with multiple modifiers.
abstract external function method3(arg: String): Boolean
*/

View File

@@ -0,0 +1,41 @@
/// Module methods with different kinds of type annotations.
module com.package1.moduleMethodTypeAnnotations
/// Zero-arg method without declared types.
function method1() = Undefined()
/// One-arg method without declared types.
function method2(arg1) = Undefined()
/// Two-arg method without declared types.
function method3(arg1, arg2) = Undefined()
/// Zero-arg method with simple types.
function method4(): String = Undefined()
/// One-arg method with simple types.
function method5(arg1: Boolean): Int = Undefined()
/// Two-arg method with simple types.
function method6(arg1: Int, arg2: Float): Duration = Undefined()
/// Two-arg method with list types.
function method7(arg1: List<Int>, arg2: List<Float>): List<Duration> = Undefined()
/// Two-arg method with set types.
function method8(arg1: Set<Int>, arg2: Set<Float>): Set<Duration> = Undefined()
/// Two-arg method with map types.
function method9(arg1: Map<Int, Int>, arg2: Map<Float, Float>): Map<Duration, Duration> = Undefined()
/// Two-arg method with optional types.
function method10(arg1: Int?, arg2: Float?): Duration? = Undefined()
/// Two-arg method with function types.
function method11(arg1: () -> Int, arg2: (Int) -> Float): (Int, Float) -> Duration = Undefined()
/// Two-arg method with partially declared types.
function method12(arg1: String, arg2): Boolean = Undefined()
/// One-arg method with complex types.
function method13(arg1: Map<List<String?>?, (Boolean?) -> Map<Int, Float>>): Map<List<Duration?>?, (DataSize?) -> Map<Any, Number>> = Undefined()

View File

@@ -0,0 +1,26 @@
/// Module methods whose types reference classes from
/// the same module, a different module, and external modules.
module com.package1.moduleMethodTypeReferences
import "shared.pkl"
import "../com.externalpackage/external1.pkl"
import "../com.externalpackage/external2.pkl"
class MyClass
/// Method with intra-module types.
function method1(arg1: MyClass, arg2: MyClass): MyClass = Undefined()
/// Method with inter-module types.
function method2(arg1: shared.MyClass, arg2: shared.MyClass): shared.MyClass = Undefined()
/// Method with external-module types.
function method3(arg1: external1.MyClass, arg2: external2.MyClass): List<external1.MyClass> = Undefined()
/// Method with intra-module, inter-module, and external-module types.
function method4(arg1: MyClass, arg2: shared.MyClass): external1.MyClass = Undefined()
/// Method with complex intra-module, inter-module, and external-module types.
function method5(arg1: MyClass?, arg2: Map<shared.MyClass, external1.MyClass>): (external1.MyClass) -> external2.MyClass = Undefined()

View File

@@ -0,0 +1,77 @@
module com.package1.modulePropertyAnnotations
/// This [prperty] thought to have a correctly spelled name.
@Deprecated {
message = "Spelling mistake."
replaceWith = "property"
}
@AlsoKnownAs {
names { "field"; "item" }
}
hidden prperty = 42
/// This [prperty] thought to have a correctly spelled name.
///
/// Unfortunately, it did not, as we explain in this expandable comment.
@Deprecated {
message = "Spelling mistake."
replaceWith = "property"
}
@AlsoKnownAs {
names { "field"; "item" }
}
hidden prpertyWithExpandableComment = 42
// This [property] indeed has a properly spelled name, but no doc comment.
@AlsoKnownAs {
names { "field"; "item" }
}
hidden property = 42
class UserDefinedAnnotation extends Annotation {
messageOpt: String?
messageReq: String
}
@UserDefinedAnnotation {
messageReq = "Hi!"
}
propertyUserDefinedAnnotation: Int = 42
class UserDefinedAnnotation1 extends Annotation {
nested: UserDefinedAnnotation
}
@UserDefinedAnnotation1 {
nested = new UserDefinedAnnotation {
messageReq = "Hi!"
}
}
propertyUserDefinedAnnotation1: Int = 42
class UserDefinedAnnotation2 extends Annotation {
nested: UserDefinedAnnotation2?
}
@UserDefinedAnnotation2 {
nested = new UserDefinedAnnotation2 {
nested = new UserDefinedAnnotation2 {
nested = new UserDefinedAnnotation2 {
nested = new UserDefinedAnnotation2 {
}
}
}
}
}
propertyUserDefinedAnnotation2: Int = 42

View File

@@ -0,0 +1,5 @@
module com.package1.modulePropertyCommentInheritance
extends "modulePropertyComments.pkl"
property3: Float = 1.23

View File

@@ -0,0 +1,54 @@
/// Module properties with different kinds of comments.
open module com.package1.modulePropertyComments
// Property with single-line code comment.
property1: Float = 3.14159265359
/*
Property with
multi-line
code comment.
*/
property2: Float = 3.14159265359
/// Property with single-line doc comment.
property3: Float = 3.14159265359
/// Property with
/// multi-line
/// doc comment.
property4: Float = 3.14159265359
/// Property with [single-line](https://apple.com) *Markdown* doc comment.
property5: Float = 3.14159265359
/// Property with
/// [multi-line](https://apple.com)
/// *Markdown* doc comment.
property6: Float = 3.14159265359
/// 😀😀😀 Property with 😎😎😎 Unicode doc comment. 😡😡😡
property7: Float = 3.14159265359
/// Summary
/// ```
///
/// code = 4 * 10
/// ```
/// Rest of the body
property8: Int = 0
/// Sumary
/// ```java
///
/// code = 0
/// ```
/// Rest
property9: Int = 1
/// ```
///
/// code = 2
/// ```
/// Rest
property10: Int = 2

View File

@@ -0,0 +1,19 @@
/// Module properties with different modifiers.
module com.package1.modulePropertyModifiers
/// Property with `local` modifier.
local property1 = 3.14159265359
/// Property with `hidden` modifier.
hidden property2: Float = 3.14159265359
/*
/// Property with `external` modifier.
external property3: Float
/// Property with `abstract` modifier.
abstract property4: Float
/// Property with multiple modifiers.
abstract external hidden property5: Float
*/

View File

@@ -0,0 +1,32 @@
/// Module properties with different kinds of type annotations.
module com.package1.modulePropertyTypeAnnotations
/// Property without declared type.
property1 = 3.14159265359
/// Property with simple type.
property2: Float = 3.14159265359
/// Property with list type.
property3: List<String> = List("1", "2", "3")
/// Property with set type.
property4: Set<String> = Set("1", "2", "3")
/// Property with map type.
property5: Map<String, Duration> = Map("one", 1.s, "two", 2.min, "three", 3.h)
/// Property with optional type.
property6: String? = "string"
/// Property with zero-arg function type.
property7: () -> String = () -> "string"
/// Property with one-arg function type.
property8: (String) -> Int = (str) -> str.length
/// Property with two-arg function type.
property9: (String, String) -> Int = (str1, str2) -> str1.length + str2.length
/// Property with complex type.
property10: Map<List<String?>?, (Boolean?) -> Map<Int, Float>> = Map(List("str"), (b) -> Map(3, 3.0))

View File

@@ -0,0 +1,36 @@
/// Module properties whose types reference classes from
/// the same module, a different module, and external modules.
module com.package1.modulePropertyTypeReferences
import "shared.pkl"
import "../com.externalpackage/external1.pkl"
class MyClass
/// Property with intra-module simple type.
property1: MyClass = new MyClass {}
/// Property with inter-module list type.
property2: List<shared.MyClass> = List(new shared.MyClass {})
/// Property with external-module set type.
property3: Set<external1.MyClass> = Set(new external1.MyClass {})
/// Property with intra-module and inter-module map type.
property4: Map<MyClass, shared.MyClass> = Map(new MyClass {}, new shared.MyClass {})
/// Property with external-module optional type.
property5: external1.MyClass? = new external1.MyClass {}
/// Property with zero-arg intra-module function type.
property6: () -> MyClass = () -> new MyClass {}
/// Property with one-arg inter-module and external-module function type.
property7: (shared.MyClass) -> external1.MyClass = (myClass) -> new external1.MyClass {}
/// Property with two-arg intra-module, inter-module, and external-module function type.
property8: (MyClass, shared.MyClass) -> external1.MyClass = (myClass1, myClass2) -> new external1.MyClass {}
/// Property with intra-module mapping type.
property9: Mapping<String, MyClass>

View File

@@ -0,0 +1,3 @@
module com.package1.moduleTypes1
n: Int

View File

@@ -0,0 +1,37 @@
module com.package1.moduleTypes2
import "moduleTypes1.pkl"
x1: moduleTypes1
x2: moduleTypes1?
x3: Listing<moduleTypes1>
x4: Mapping<moduleTypes1, moduleTypes1>
x5: String|moduleTypes1|Int
x6: module
x7: List<module>
x8: String|module|Int
class Foo {
x1: moduleTypes1
x2: moduleTypes1?
x3: Listing<moduleTypes1>
x4: Mapping<moduleTypes1, moduleTypes1>
x5: String|moduleTypes1|Int
x6: module
x7: List<module>
x8: String|module|Int
}

View File

@@ -0,0 +1,7 @@
module com.package1.nested.nested2.nestedModule
myProperty = 42
function myMethod() = 42
class MyClass {}

View File

@@ -0,0 +1,3 @@
module com.package1.shared
class MyClass

View File

@@ -0,0 +1,31 @@
open module com.package1.typealiases
/// A [String] representing an [Email] address.
@AlsoKnownAs { names { "OtherName" } }
typealias Email = String(contains("@"))
uint: UInt
uints: List<UInt>
/// My [Email].
email: Email
emails: List<Email>
/// Sends an [Email].
function send(email: Email): Email = "abc"
open class Person {
uint: UInt
list: List<UInt>
/// A person's [Email].
email: Email
emails: List<Email>
/// Sends an [Email].
function send(email: Email): Email = "abc"
}

View File

@@ -0,0 +1,32 @@
module com.package1.typealiases2
class Person { name: String }
typealias List2<E> = List<E>
typealias Map2<V, K> = Map<K, V>
typealias StringMap<V> = Map<String, V>
typealias MMap<X> = Map<X, X>
res1: List2<Int>
res2: List2<List2<String>>
res3: Map2<String, Int>
res4: StringMap<Duration>
res5: MMap<Person?>
res6: List2
res7: Map2
res8: StringMap
res9: MMap
class Foo {
res1: List2<Int>
res2: List2<List2<String>>
res3: Map2<String, Int>
res4: StringMap<Duration>
res5: MMap<Person?>
res6: List2
res7: Map2
res8: StringMap
res9: MMap
}

View File

@@ -0,0 +1,13 @@
module com.package1.typeAliasInheritance
extends "typeAliases.pkl"
email2: Email
emails2: List<Email>
class Person2 extends Person {
email2: Email
emails2: List<Email>
}

View File

@@ -0,0 +1,13 @@
module com.package1.unionTypes
res1: Boolean|Number
res2: "foo"|"bar"|"baz"
res3: Boolean|List<String>
res4: Boolean|List<String>?
res5: (Boolean|List<String>)?
res6: (Boolean|List<String>)?|Number

View File

@@ -0,0 +1,8 @@
module com.package1.unlistedClass
myProperty = 42
function myMethod() = 42
@Unlisted
class MyClass {}

View File

@@ -0,0 +1,8 @@
module com.package1.unlistedMethod
myProperty = 42
@Unlisted
function myMethod() = 42
class MyClass {}

View File

@@ -0,0 +1,8 @@
@Unlisted
module com.package1.unlistedModule
myProperty = 42
function myMethod() = 42
class MyClass {}

View File

@@ -0,0 +1,8 @@
module com.package1.unlistedProperty
@Unlisted
myProperty = 42
function myMethod() = 42
class MyClass {}

View File

@@ -0,0 +1,11 @@
module com.package2.Module3
property3: String
function function3(n: Int): String = n.toString()
class Class3 {
property3: String
function function3(n: Int): String = n.toString()
}

View File

@@ -0,0 +1,23 @@
/// Docs for Package 2.
amends "pkl:DocPackageInfo"
name = "com.package2"
version = "4.5.6"
importUri = "modulepath:/com/package2/"
authors {
"package2-publisher@group.apple.com"
}
sourceCode = "https://sources.apple.com/package2/"
sourceCodeUrlScheme = "https://example.com/blob/\(version)%{path}#L%{line}-L%{endLine}"
issueTracker = "https://issues.apple.com/package2/"
dependencies {
new {
name = "pkl"
// use fixed version to avoid churn in expected test outputs
version = "0.24.0"
sourceCode = "https://github.com/apple/\(name)/blob/dev/stdlib/"
sourceCodeUrlScheme = "https://github.com/apple/\(name)/blob/\(version)/stdlib%{path}#L%{line}-L%{endLine}"
documentation = "https://pkl-lang.org/stdlib/\(name)/\(version)/"
}
}

View File

@@ -0,0 +1,65 @@
/// Let the games begin.
///
/// ## Great Library
///
/// Just follow these simple steps. You'll love it.
///
/// 1. Install it
/// 1. I promise it's easy.
/// 2. You'll figure it out.
/// 1. Install it
/// ```
/// name = "Pigeon"
/// age = 42
/// ```
/// 1. Install it
///
/// Let me **emphasize** how *simple* this is.
///
/// 😀😀😀 emoji day 😎😎😎 don't get 😡😡😡
///
/// ## Code
///
/// The code is beautiful:
///
/// ```
/// /// example module
/// module foo.bar
///
/// person {
/// name = "Pigeon"
/// age = 42
/// }
///
/// function sing() = "tra-la-la"
///
/// class Person {
/// name: String
/// age: Int
/// }
/// ```
///
/// ## Random Tips
///
/// - don't give up
/// - just don't
/// - don't give up
///
/// # Level 1
/// ## Level 2
/// ### Level 3
/// #### Level 4
/// ##### Level 5
/// ###### Level 6
///
/// * [docLinks]
/// * [docLinks.age]
/// * [docLinks.sing()]
/// * [docLinks.Person]
/// * [docLinks.Person.name]
/// * [docLinks.PersonList]
amends "pkl:DocsiteInfo"
import "com.package1/docLinks.pkl"
title = "Docsite Title"

View File

@@ -0,0 +1,150 @@
<!DOCTYPE html>
<html>
<head>
<title>BaseClass (com.package1/baseModule:1.2.3) • Docsite Title</title>
<script src="../../../scripts/pkldoc.js" defer="defer"></script>
<script src="../../../scripts/scroll-into-view.min.js" defer="defer"></script>
<script src="../../../data/com.package1/1.2.3/baseModule/BaseClass.js" defer="defer"></script>
<link href="../../../styles/pkldoc.css" media="screen" type="text/css" rel="stylesheet">
<link rel="icon" type="image/svg+xml" href="../../../images/favicon.svg">
<link rel="apple-touch-icon" sizes="180x180" href="../../../images/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../../images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../../images/favicon-16x16.png">
<meta charset="UTF-8">
</head>
<body onload="onLoad()">
<header>
<div id="doc-title"><a href="../../../index.html">Docsite Title</a></div>
<div id="search"><i id="search-icon" class="material-icons">search</i><input id="search-input" type="search" placeholder="Click or press 'S' to search this package" autocomplete="off" data-package-name="com.package1" data-package-version="1.2.3" data-package-url-prefix="../" data-module-name="com.package1.baseModule" data-class-name="BaseClass" data-root-url-prefix="../../../"></div>
</header>
<main><a class="declaration-parent-link" href="../../../index.html">Docsite Title</a> &gt; <a class="declaration-parent-link" href="../index.html">com.package1</a> &gt; <a class="declaration-parent-link" href="index.html">com.package1.baseModule</a>
<h1 id="declaration-title">BaseClass<span id="declaration-version">1.2.3</span></h1>
<ul class="member-group-links">
<li><a href="#_methods">Methods</a></li>
</ul>
<div id="_overview" class="anchor"> </div>
<div id="_declaration" class="member">
<div class="member-signature">class <span class="name-decl">BaseClass</span></div>
<dl class="member-info">
<dt class="runtime-data hidden">Known subtypes:</dt>
<dd id="known-subtypes" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">Known usages:</dt>
<dd id="known-usages" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">All versions:</dt>
<dd id="known-versions" class="runtime-data hidden"></dd>
</dl>
</div>
<div class="member-group">
<div id="_methods" class="anchor"> </div>
<h2 class="member-group-title">Methods<span class="toggle-inherited-members">(<span class="toggle-inherited-members-link button-link">show inherited</span>)</span></h2>
<ul>
<li>
<div id="getClass()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#getClass()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">getClass</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Class.html" class="name-ref">Class</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the class of <code>this</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="toString()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#toString()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">toString</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns a string representation of <code>this</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is used to convert the values of string interpolation expressions to strings.</p></div>
</div>
</div>
</li>
<li>
<div id="ifNonNull()" class="anchor"> </div>
<div id="ifNonNull().Result" class="anchor-param1"> </div>
<div id="ifNonNull().transform" class="anchor-param2"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#ifNonNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">ifNonNull</span>&lt;<a class="param1">Result</a>&gt;(<span class="param2">transform</span>: (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html#NonNull" class="name-ref">NonNull</a>) -&gt; <a href="BaseClass.html#ifNonNull().Result" class="name-ref">Result</a>): <a href="BaseClass.html#ifNonNull().Result" class="name-ref">Result</a>?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns <code>this |&gt; transform</code> if <code>this</code> is non-null, and <code>null</code> otherwise.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is the complement of the <code>??</code> operator and the equivalent of an <code>Option</code> type's <code>map</code> and <code>flatMap</code> methods.</p></div>
</div>
</div>
</li>
<li>
<div id="hasProperty()" class="anchor"> </div>
<div id="hasProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#hasProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">hasProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Boolean.html" class="name-ref">Boolean</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Tells if this object has a property with the given <code>name</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="getProperty()" class="anchor"> </div>
<div id="getProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">getProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Throws if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="getPropertyOrNull()" class="anchor"> </div>
<div id="getPropertyOrNull().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getPropertyOrNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">getPropertyOrNull</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Returns <code>null</code> if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="toDynamic()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toDynamic()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">toDynamic</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html" class="name-ref">Dynamic</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html"><code>Dynamic</code></a> object.</p></div>
</div>
</div>
</li>
<li>
<div id="toMap()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toMap()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">toMap</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html" class="name-ref">Map</a>&lt;<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>, unknown&gt;<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html"><code>Map</code></a>.</p></div>
</div>
</div>
</li>
</ul>
</div>
</main>
</body>
</html>

View File

@@ -0,0 +1,235 @@
<!DOCTYPE html>
<html>
<head>
<title>baseModule (com.package1:1.2.3) • Docsite Title</title>
<script src="../../../scripts/pkldoc.js" defer="defer"></script>
<script src="../../../scripts/scroll-into-view.min.js" defer="defer"></script>
<script src="../../../data/com.package1/1.2.3/baseModule/index.js" defer="defer"></script>
<link href="../../../styles/pkldoc.css" media="screen" type="text/css" rel="stylesheet">
<link rel="icon" type="image/svg+xml" href="../../../images/favicon.svg">
<link rel="apple-touch-icon" sizes="180x180" href="../../../images/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../../images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../../images/favicon-16x16.png">
<meta charset="UTF-8">
</head>
<body onload="onLoad()">
<header>
<div id="doc-title"><a href="../../../index.html">Docsite Title</a></div>
<div id="search"><i id="search-icon" class="material-icons">search</i><input id="search-input" type="search" placeholder="Click or press 'S' to search this package" autocomplete="off" data-package-name="com.package1" data-package-version="1.2.3" data-package-url-prefix="../" data-module-name="com.package1.baseModule" data-root-url-prefix="../../../"></div>
</header>
<main><a class="declaration-parent-link" href="../../../index.html">Docsite Title</a> &gt; <a class="declaration-parent-link" href="../index.html">com.package1</a>
<h1 id="declaration-title">com.package1.baseModule<span id="declaration-version">1.2.3</span></h1>
<ul class="member-group-links">
<li><a href="#_properties">Properties</a></li>
<li><a href="#_methods">Methods</a></li>
<li><a href="#_classes">Classes</a></li>
</ul>
<div id="_overview" class="anchor"> </div>
<div id="_declaration" class="member">
<div class="member-signature">open module <span class="name-decl">com.package1.baseModule</span></div>
<dl class="member-info">
<dt class="">Module URI:</dt>
<dd><span class="import-uri">https://pkl.io/baseModule.pkl</span><i class="copy-uri-button material-icons">content_copy</i></dd>
<dt class="">Source code:</dt>
<dd><a href="https://example.com/package1/baseModule.pkl">baseModule.pkl</a></dd>
<dt class="runtime-data hidden">Known subtypes:</dt>
<dd id="known-subtypes" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">Known usages:</dt>
<dd id="known-usages" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">All versions:</dt>
<dd id="known-versions" class="runtime-data hidden"></dd>
</dl>
</div>
<div class="member-group">
<div id="_properties" class="anchor"> </div>
<h2 class="member-group-title">Properties<span class="toggle-inherited-members">(<span class="toggle-inherited-members-link button-link">show inherited</span>)</span></h2>
<ul>
<li>
<div id="output" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#output">link</a>
<div class="member-left">
<div class="member-modifiers">hidden </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">output</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/ModuleOutput.html" class="name-ref">ModuleOutput</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>The output of this module.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Defaults to all module properties rendered as either Pcf or the format specified on the command line.</p></div>
</div>
</div>
</li>
<li>
<div id="baseProperty" class="anchor"> </div>
<div class="member"><a class="member-selflink material-icons" href="#baseProperty">link</a>
<div class="member-left">
<div class="member-modifiers"></div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">baseProperty</span>: unknown<a class="member-source-link" href="https://example.com/package1/baseModule.pkl#L123-L456">Source</a></div>
</div>
</div>
</li>
</ul>
</div>
<div class="member-group">
<div id="_methods" class="anchor"> </div>
<h2 class="member-group-title">Methods<span class="toggle-inherited-members">(<span class="toggle-inherited-members-link button-link">show inherited</span>)</span></h2>
<ul>
<li>
<div id="getClass()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#getClass()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">getClass</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Class.html" class="name-ref">Class</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the class of <code>this</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="toString()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#toString()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">toString</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns a string representation of <code>this</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is used to convert the values of string interpolation expressions to strings.</p></div>
</div>
</div>
</li>
<li>
<div id="ifNonNull()" class="anchor"> </div>
<div id="ifNonNull().Result" class="anchor-param1"> </div>
<div id="ifNonNull().transform" class="anchor-param2"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#ifNonNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">ifNonNull</span>&lt;<a class="param1">Result</a>&gt;(<span class="param2">transform</span>: (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html#NonNull" class="name-ref">NonNull</a>) -&gt; <a href="index.html#ifNonNull().Result" class="name-ref">Result</a>): <a href="index.html#ifNonNull().Result" class="name-ref">Result</a>?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns <code>this |&gt; transform</code> if <code>this</code> is non-null, and <code>null</code> otherwise.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is the complement of the <code>??</code> operator and the equivalent of an <code>Option</code> type's <code>map</code> and <code>flatMap</code> methods.</p></div>
</div>
</div>
</li>
<li>
<div id="hasProperty()" class="anchor"> </div>
<div id="hasProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#hasProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">hasProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Boolean.html" class="name-ref">Boolean</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Tells if this object has a property with the given <code>name</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="getProperty()" class="anchor"> </div>
<div id="getProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">getProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Throws if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="getPropertyOrNull()" class="anchor"> </div>
<div id="getPropertyOrNull().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getPropertyOrNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">getPropertyOrNull</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Returns <code>null</code> if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="toDynamic()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toDynamic()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">toDynamic</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html" class="name-ref">Dynamic</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html"><code>Dynamic</code></a> object.</p></div>
</div>
</div>
</li>
<li>
<div id="toMap()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toMap()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">toMap</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html" class="name-ref">Map</a>&lt;<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>, unknown&gt;<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html"><code>Map</code></a>.</p></div>
</div>
</div>
</li>
<li>
<div id="relativePathTo()" class="anchor"> </div>
<div id="relativePathTo().other" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#relativePathTo()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">relativePathTo</span>(<span class="param1">other</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Module.html" class="name-ref">Module</a>): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/List.html" class="name-ref">List</a>&lt;<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>&gt;<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the relative, descendent directory path between this module and <code>other</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Throws if no such path exists.</p>
<p>For example, if module <code>mod1</code> has path <code>/dir1/mod1.pkl</code>, and module <code>mod2</code> has path <code>/dir1/dir2/dir3/mod2.pkl</code>,
then <code>mod1.relativePathTo(mod2)</code> will return <code>List(&quot;dir2&quot;, &quot;dir3&quot;)</code>.</p>
<p>A common use case is to compute the directory path between a template located at the root of a hierarchy
(say <code>rootModule.pkl</code>) and the currently evaluated module (accessible via the <code>module</code> keyword):</p>
<pre><code>import &quot;rootModule.pkl&quot; // self-import
path = rootModule.relativePathTo(module)
</code></pre></div>
</div>
</div>
</li>
<li>
<div id="baseMethod()" class="anchor"> </div>
<div class="member"><a class="member-selflink material-icons" href="#baseMethod()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">baseMethod</span>(): unknown<a class="member-source-link" href="https://example.com/package1/baseModule.pkl#L123-L456">Source</a></div>
</div>
</div>
</li>
</ul>
</div>
<div class="member-group">
<div id="_classes" class="anchor"> </div>
<h2 class="member-group-title">Classes</h2>
<ul>
<li>
<div id="BaseClass" class="anchor"> </div>
<div class="member with-page-link"><a class="member-selflink material-icons" href="#BaseClass">link</a>
<div class="member-left">
<div class="member-modifiers">class </div>
</div>
<div class="member-main">
<div class="member-signature"><a href="BaseClass.html" class="name-decl">BaseClass</a><a class="member-source-link" href="https://example.com/package1/baseModule.pkl#L123-L456">Source</a></div>
</div>
</div>
</li>
</ul>
</div>
</main>
</body>
</html>

View File

@@ -0,0 +1,153 @@
<!DOCTYPE html>
<html>
<head>
<title>AnnotatedClass (com.package1/classAnnotations:1.2.3) • Docsite Title</title>
<script src="../../../scripts/pkldoc.js" defer="defer"></script>
<script src="../../../scripts/scroll-into-view.min.js" defer="defer"></script>
<script src="../../../data/com.package1/1.2.3/classAnnotations/AnnotatedClass.js" defer="defer"></script>
<link href="../../../styles/pkldoc.css" media="screen" type="text/css" rel="stylesheet">
<link rel="icon" type="image/svg+xml" href="../../../images/favicon.svg">
<link rel="apple-touch-icon" sizes="180x180" href="../../../images/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../../images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../../images/favicon-16x16.png">
<meta charset="UTF-8">
</head>
<body onload="onLoad()">
<header>
<div id="doc-title"><a href="../../../index.html">Docsite Title</a></div>
<div id="search"><i id="search-icon" class="material-icons">search</i><input id="search-input" type="search" placeholder="Click or press 'S' to search this package" autocomplete="off" data-package-name="com.package1" data-package-version="1.2.3" data-package-url-prefix="../" data-module-name="com.package1.classAnnotations" data-class-name="AnnotatedClass" data-root-url-prefix="../../../"></div>
</header>
<main><a class="declaration-parent-link" href="../../../index.html">Docsite Title</a> &gt; <a class="declaration-parent-link" href="../index.html">com.package1</a> &gt; <a class="declaration-parent-link" href="index.html">com.package1.classAnnotations</a>
<h1 id="declaration-title">AnnotatedClass<span id="declaration-version">1.2.3</span></h1>
<ul class="member-group-links">
<li><a href="#_methods">Methods</a></li>
</ul>
<div id="_overview" class="anchor"> </div>
<div id="_declaration" class="member">
<div class="member-signature member-deprecated">class <span class="name-decl">AnnotatedClass</span></div>
<div class="doc-comment">Deprecated.</div>
<dl class="member-info">
<dt class="runtime-data hidden">Known subtypes:</dt>
<dd id="known-subtypes" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">Known usages:</dt>
<dd id="known-usages" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">All versions:</dt>
<dd id="known-versions" class="runtime-data hidden"></dd>
<dt>Also known as:</dt>
<dd><code>OtherName</code></dd>
</dl>
</div>
<div class="member-group">
<div id="_methods" class="anchor"> </div>
<h2 class="member-group-title">Methods<span class="toggle-inherited-members">(<span class="toggle-inherited-members-link button-link">show inherited</span>)</span></h2>
<ul>
<li>
<div id="getClass()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#getClass()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">getClass</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Class.html" class="name-ref">Class</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the class of <code>this</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="toString()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#toString()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">toString</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns a string representation of <code>this</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is used to convert the values of string interpolation expressions to strings.</p></div>
</div>
</div>
</li>
<li>
<div id="ifNonNull()" class="anchor"> </div>
<div id="ifNonNull().Result" class="anchor-param1"> </div>
<div id="ifNonNull().transform" class="anchor-param2"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#ifNonNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">ifNonNull</span>&lt;<a class="param1">Result</a>&gt;(<span class="param2">transform</span>: (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html#NonNull" class="name-ref">NonNull</a>) -&gt; <a href="AnnotatedClass.html#ifNonNull().Result" class="name-ref">Result</a>): <a href="AnnotatedClass.html#ifNonNull().Result" class="name-ref">Result</a>?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns <code>this |&gt; transform</code> if <code>this</code> is non-null, and <code>null</code> otherwise.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is the complement of the <code>??</code> operator and the equivalent of an <code>Option</code> type's <code>map</code> and <code>flatMap</code> methods.</p></div>
</div>
</div>
</li>
<li>
<div id="hasProperty()" class="anchor"> </div>
<div id="hasProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#hasProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">hasProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Boolean.html" class="name-ref">Boolean</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Tells if this object has a property with the given <code>name</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="getProperty()" class="anchor"> </div>
<div id="getProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">getProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Throws if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="getPropertyOrNull()" class="anchor"> </div>
<div id="getPropertyOrNull().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getPropertyOrNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">getPropertyOrNull</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Returns <code>null</code> if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="toDynamic()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toDynamic()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">toDynamic</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html" class="name-ref">Dynamic</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html"><code>Dynamic</code></a> object.</p></div>
</div>
</div>
</li>
<li>
<div id="toMap()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toMap()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">toMap</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html" class="name-ref">Map</a>&lt;<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>, unknown&gt;<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html"><code>Map</code></a>.</p></div>
</div>
</div>
</li>
</ul>
</div>
</main>
</body>
</html>

View File

@@ -0,0 +1,155 @@
<!DOCTYPE html>
<html>
<head>
<title>AnnotatedClss (com.package1/classAnnotations:1.2.3) • Docsite Title</title>
<script src="../../../scripts/pkldoc.js" defer="defer"></script>
<script src="../../../scripts/scroll-into-view.min.js" defer="defer"></script>
<script src="../../../data/com.package1/1.2.3/classAnnotations/AnnotatedClss.js" defer="defer"></script>
<link href="../../../styles/pkldoc.css" media="screen" type="text/css" rel="stylesheet">
<link rel="icon" type="image/svg+xml" href="../../../images/favicon.svg">
<link rel="apple-touch-icon" sizes="180x180" href="../../../images/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../../images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../../images/favicon-16x16.png">
<meta charset="UTF-8">
</head>
<body onload="onLoad()">
<header>
<div id="doc-title"><a href="../../../index.html">Docsite Title</a></div>
<div id="search"><i id="search-icon" class="material-icons">search</i><input id="search-input" type="search" placeholder="Click or press 'S' to search this package" autocomplete="off" data-package-name="com.package1" data-package-version="1.2.3" data-package-url-prefix="../" data-module-name="com.package1.classAnnotations" data-class-name="AnnotatedClss" data-root-url-prefix="../../../"></div>
</header>
<main><a class="declaration-parent-link" href="../../../index.html">Docsite Title</a> &gt; <a class="declaration-parent-link" href="../index.html">com.package1</a> &gt; <a class="declaration-parent-link" href="index.html">com.package1.classAnnotations</a>
<h1 id="declaration-title">AnnotatedClss<span id="declaration-version">1.2.3</span></h1>
<ul class="member-group-links">
<li><a href="#_overview">Overview</a></li>
<li><a href="#_methods">Methods</a></li>
</ul>
<div id="_overview" class="anchor"> </div>
<div id="_declaration" class="member with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i>
<div class="member-signature member-deprecated">class <span class="name-decl">AnnotatedClss</span></div>
<div class="doc-comment">Deprecated: Spelling mistake. Replace with: <code>AnnotatedClass</code></div>
<dl class="member-info">
<dt class="runtime-data hidden">Known subtypes:</dt>
<dd id="known-subtypes" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">Known usages:</dt>
<dd id="known-usages" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">All versions:</dt>
<dd id="known-versions" class="runtime-data hidden"></dd>
<dt>Also known as:</dt>
<dd><code>OtherName</code></dd>
</dl>
<div class="doc-comment expandable hidden collapsed"><p>This <code>AnnotatedClss</code> thought to have a correctly spelled name.</p></div>
</div>
<div class="member-group">
<div id="_methods" class="anchor"> </div>
<h2 class="member-group-title">Methods<span class="toggle-inherited-members">(<span class="toggle-inherited-members-link button-link">show inherited</span>)</span></h2>
<ul>
<li>
<div id="getClass()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#getClass()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">getClass</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Class.html" class="name-ref">Class</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the class of <code>this</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="toString()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#toString()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">toString</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns a string representation of <code>this</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is used to convert the values of string interpolation expressions to strings.</p></div>
</div>
</div>
</li>
<li>
<div id="ifNonNull()" class="anchor"> </div>
<div id="ifNonNull().Result" class="anchor-param1"> </div>
<div id="ifNonNull().transform" class="anchor-param2"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#ifNonNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">ifNonNull</span>&lt;<a class="param1">Result</a>&gt;(<span class="param2">transform</span>: (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html#NonNull" class="name-ref">NonNull</a>) -&gt; <a href="AnnotatedClss.html#ifNonNull().Result" class="name-ref">Result</a>): <a href="AnnotatedClss.html#ifNonNull().Result" class="name-ref">Result</a>?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns <code>this |&gt; transform</code> if <code>this</code> is non-null, and <code>null</code> otherwise.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is the complement of the <code>??</code> operator and the equivalent of an <code>Option</code> type's <code>map</code> and <code>flatMap</code> methods.</p></div>
</div>
</div>
</li>
<li>
<div id="hasProperty()" class="anchor"> </div>
<div id="hasProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#hasProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">hasProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Boolean.html" class="name-ref">Boolean</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Tells if this object has a property with the given <code>name</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="getProperty()" class="anchor"> </div>
<div id="getProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">getProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Throws if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="getPropertyOrNull()" class="anchor"> </div>
<div id="getPropertyOrNull().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getPropertyOrNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">getPropertyOrNull</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Returns <code>null</code> if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="toDynamic()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toDynamic()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">toDynamic</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html" class="name-ref">Dynamic</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html"><code>Dynamic</code></a> object.</p></div>
</div>
</div>
</li>
<li>
<div id="toMap()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toMap()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">toMap</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html" class="name-ref">Map</a>&lt;<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>, unknown&gt;<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html"><code>Map</code></a>.</p></div>
</div>
</div>
</li>
</ul>
</div>
</main>
</body>
</html>

View File

@@ -0,0 +1,155 @@
<!DOCTYPE html>
<html>
<head>
<title>AnnotatedClssWithExpandableComment (com.package1/classAnnotations:1.2.3) • Docsite Title</title>
<script src="../../../scripts/pkldoc.js" defer="defer"></script>
<script src="../../../scripts/scroll-into-view.min.js" defer="defer"></script>
<script src="../../../data/com.package1/1.2.3/classAnnotations/AnnotatedClssWithExpandableComment.js" defer="defer"></script>
<link href="../../../styles/pkldoc.css" media="screen" type="text/css" rel="stylesheet">
<link rel="icon" type="image/svg+xml" href="../../../images/favicon.svg">
<link rel="apple-touch-icon" sizes="180x180" href="../../../images/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../../images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../../images/favicon-16x16.png">
<meta charset="UTF-8">
</head>
<body onload="onLoad()">
<header>
<div id="doc-title"><a href="../../../index.html">Docsite Title</a></div>
<div id="search"><i id="search-icon" class="material-icons">search</i><input id="search-input" type="search" placeholder="Click or press 'S' to search this package" autocomplete="off" data-package-name="com.package1" data-package-version="1.2.3" data-package-url-prefix="../" data-module-name="com.package1.classAnnotations" data-class-name="AnnotatedClssWithExpandableComment" data-root-url-prefix="../../../"></div>
</header>
<main><a class="declaration-parent-link" href="../../../index.html">Docsite Title</a> &gt; <a class="declaration-parent-link" href="../index.html">com.package1</a> &gt; <a class="declaration-parent-link" href="index.html">com.package1.classAnnotations</a>
<h1 id="declaration-title">AnnotatedClssWithExpandableComment<span id="declaration-version">1.2.3</span></h1>
<ul class="member-group-links">
<li><a href="#_overview">Overview</a></li>
<li><a href="#_methods">Methods</a></li>
</ul>
<div id="_overview" class="anchor"> </div>
<div id="_declaration" class="member with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i>
<div class="member-signature member-deprecated">class <span class="name-decl">AnnotatedClssWithExpandableComment</span></div>
<div class="doc-comment">Deprecated: Spelling mistake. Replace with: <code>AnnotatedClass</code></div>
<dl class="member-info">
<dt class="runtime-data hidden">Known subtypes:</dt>
<dd id="known-subtypes" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">Known usages:</dt>
<dd id="known-usages" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">All versions:</dt>
<dd id="known-versions" class="runtime-data hidden"></dd>
<dt>Also known as:</dt>
<dd><code>OtherName</code></dd>
</dl>
<div class="doc-comment expandable hidden collapsed"><p>This <code>AnnotatedClssWithExpandableComment</code> thought to have a correctly spelled name.</p><p>Unfortunately, it did not, as we explain in this expandable comment.</p></div>
</div>
<div class="member-group">
<div id="_methods" class="anchor"> </div>
<h2 class="member-group-title">Methods<span class="toggle-inherited-members">(<span class="toggle-inherited-members-link button-link">show inherited</span>)</span></h2>
<ul>
<li>
<div id="getClass()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#getClass()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">getClass</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Class.html" class="name-ref">Class</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the class of <code>this</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="toString()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#toString()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">toString</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns a string representation of <code>this</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is used to convert the values of string interpolation expressions to strings.</p></div>
</div>
</div>
</li>
<li>
<div id="ifNonNull()" class="anchor"> </div>
<div id="ifNonNull().Result" class="anchor-param1"> </div>
<div id="ifNonNull().transform" class="anchor-param2"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#ifNonNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">ifNonNull</span>&lt;<a class="param1">Result</a>&gt;(<span class="param2">transform</span>: (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html#NonNull" class="name-ref">NonNull</a>) -&gt; <a href="AnnotatedClssWithExpandableComment.html#ifNonNull().Result" class="name-ref">Result</a>): <a href="AnnotatedClssWithExpandableComment.html#ifNonNull().Result" class="name-ref">Result</a>?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns <code>this |&gt; transform</code> if <code>this</code> is non-null, and <code>null</code> otherwise.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is the complement of the <code>??</code> operator and the equivalent of an <code>Option</code> type's <code>map</code> and <code>flatMap</code> methods.</p></div>
</div>
</div>
</li>
<li>
<div id="hasProperty()" class="anchor"> </div>
<div id="hasProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#hasProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">hasProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Boolean.html" class="name-ref">Boolean</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Tells if this object has a property with the given <code>name</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="getProperty()" class="anchor"> </div>
<div id="getProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">getProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Throws if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="getPropertyOrNull()" class="anchor"> </div>
<div id="getPropertyOrNull().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getPropertyOrNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">getPropertyOrNull</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Returns <code>null</code> if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="toDynamic()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toDynamic()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">toDynamic</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html" class="name-ref">Dynamic</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html"><code>Dynamic</code></a> object.</p></div>
</div>
</div>
</li>
<li>
<div id="toMap()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toMap()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">toMap</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html" class="name-ref">Map</a>&lt;<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>, unknown&gt;<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html"><code>Map</code></a>.</p></div>
</div>
</div>
</li>
</ul>
</div>
</main>
</body>
</html>

View File

@@ -0,0 +1,238 @@
<!DOCTYPE html>
<html>
<head>
<title>classAnnotations (com.package1:1.2.3) • Docsite Title</title>
<script src="../../../scripts/pkldoc.js" defer="defer"></script>
<script src="../../../scripts/scroll-into-view.min.js" defer="defer"></script>
<script src="../../../data/com.package1/1.2.3/classAnnotations/index.js" defer="defer"></script>
<link href="../../../styles/pkldoc.css" media="screen" type="text/css" rel="stylesheet">
<link rel="icon" type="image/svg+xml" href="../../../images/favicon.svg">
<link rel="apple-touch-icon" sizes="180x180" href="../../../images/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../../images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../../images/favicon-16x16.png">
<meta charset="UTF-8">
</head>
<body onload="onLoad()">
<header>
<div id="doc-title"><a href="../../../index.html">Docsite Title</a></div>
<div id="search"><i id="search-icon" class="material-icons">search</i><input id="search-input" type="search" placeholder="Click or press 'S' to search this package" autocomplete="off" data-package-name="com.package1" data-package-version="1.2.3" data-package-url-prefix="../" data-module-name="com.package1.classAnnotations" data-root-url-prefix="../../../"></div>
</header>
<main><a class="declaration-parent-link" href="../../../index.html">Docsite Title</a> &gt; <a class="declaration-parent-link" href="../index.html">com.package1</a>
<h1 id="declaration-title">com.package1.classAnnotations<span id="declaration-version">1.2.3</span></h1>
<ul class="member-group-links">
<li><a href="#_properties">Properties</a></li>
<li><a href="#_methods">Methods</a></li>
<li><a href="#_classes">Classes</a></li>
</ul>
<div id="_overview" class="anchor"> </div>
<div id="_declaration" class="member">
<div class="member-signature">open module <span class="name-decl">com.package1.classAnnotations</span></div>
<dl class="member-info">
<dt class="">Module URI:</dt>
<dd><span class="import-uri">https://pkl.io/classAnnotations.pkl</span><i class="copy-uri-button material-icons">content_copy</i></dd>
<dt class="">Source code:</dt>
<dd><a href="https://example.com/package1/classAnnotations.pkl">classAnnotations.pkl</a></dd>
<dt class="runtime-data hidden">Known subtypes:</dt>
<dd id="known-subtypes" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">Known usages:</dt>
<dd id="known-usages" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">All versions:</dt>
<dd id="known-versions" class="runtime-data hidden"></dd>
</dl>
</div>
<div class="member-group">
<div id="_properties" class="anchor"> </div>
<h2 class="member-group-title">Properties<span class="toggle-inherited-members">(<span class="toggle-inherited-members-link button-link">show inherited</span>)</span></h2>
<ul>
<li>
<div id="output" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#output">link</a>
<div class="member-left">
<div class="member-modifiers">hidden </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">output</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/ModuleOutput.html" class="name-ref">ModuleOutput</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>The output of this module.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Defaults to all module properties rendered as either Pcf or the format specified on the command line.</p></div>
</div>
</div>
</li>
</ul>
</div>
<div class="member-group">
<div id="_methods" class="anchor"> </div>
<h2 class="member-group-title">Methods<span class="toggle-inherited-members">(<span class="toggle-inherited-members-link button-link">show inherited</span>)</span></h2>
<ul>
<li>
<div id="getClass()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#getClass()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">getClass</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Class.html" class="name-ref">Class</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the class of <code>this</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="toString()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#toString()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">toString</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns a string representation of <code>this</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is used to convert the values of string interpolation expressions to strings.</p></div>
</div>
</div>
</li>
<li>
<div id="ifNonNull()" class="anchor"> </div>
<div id="ifNonNull().Result" class="anchor-param1"> </div>
<div id="ifNonNull().transform" class="anchor-param2"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#ifNonNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">ifNonNull</span>&lt;<a class="param1">Result</a>&gt;(<span class="param2">transform</span>: (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html#NonNull" class="name-ref">NonNull</a>) -&gt; <a href="index.html#ifNonNull().Result" class="name-ref">Result</a>): <a href="index.html#ifNonNull().Result" class="name-ref">Result</a>?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns <code>this |&gt; transform</code> if <code>this</code> is non-null, and <code>null</code> otherwise.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is the complement of the <code>??</code> operator and the equivalent of an <code>Option</code> type's <code>map</code> and <code>flatMap</code> methods.</p></div>
</div>
</div>
</li>
<li>
<div id="hasProperty()" class="anchor"> </div>
<div id="hasProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#hasProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">hasProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Boolean.html" class="name-ref">Boolean</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Tells if this object has a property with the given <code>name</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="getProperty()" class="anchor"> </div>
<div id="getProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">getProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Throws if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="getPropertyOrNull()" class="anchor"> </div>
<div id="getPropertyOrNull().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getPropertyOrNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">getPropertyOrNull</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Returns <code>null</code> if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="toDynamic()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toDynamic()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">toDynamic</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html" class="name-ref">Dynamic</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html"><code>Dynamic</code></a> object.</p></div>
</div>
</div>
</li>
<li>
<div id="toMap()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toMap()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">toMap</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html" class="name-ref">Map</a>&lt;<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>, unknown&gt;<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html"><code>Map</code></a>.</p></div>
</div>
</div>
</li>
<li>
<div id="relativePathTo()" class="anchor"> </div>
<div id="relativePathTo().other" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#relativePathTo()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="name-decl">relativePathTo</span>(<span class="param1">other</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Module.html" class="name-ref">Module</a>): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/List.html" class="name-ref">List</a>&lt;<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>&gt;<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the relative, descendent directory path between this module and <code>other</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Throws if no such path exists.</p>
<p>For example, if module <code>mod1</code> has path <code>/dir1/mod1.pkl</code>, and module <code>mod2</code> has path <code>/dir1/dir2/dir3/mod2.pkl</code>,
then <code>mod1.relativePathTo(mod2)</code> will return <code>List(&quot;dir2&quot;, &quot;dir3&quot;)</code>.</p>
<p>A common use case is to compute the directory path between a template located at the root of a hierarchy
(say <code>rootModule.pkl</code>) and the currently evaluated module (accessible via the <code>module</code> keyword):</p>
<pre><code>import &quot;rootModule.pkl&quot; // self-import
path = rootModule.relativePathTo(module)
</code></pre></div>
</div>
</div>
</li>
</ul>
</div>
<div class="member-group">
<div id="_classes" class="anchor"> </div>
<h2 class="member-group-title">Classes</h2>
<ul>
<li>
<div id="AnnotatedClss" class="anchor"> </div>
<div class="member with-page-link"><a class="member-selflink material-icons" href="#AnnotatedClss">link</a>
<div class="member-left">
<div class="member-modifiers member-deprecated">class </div>
</div>
<div class="member-main">
<div class="member-signature member-deprecated"><a href="AnnotatedClss.html" class="name-decl">AnnotatedClss</a><a class="member-source-link" href="https://example.com/package1/classAnnotations.pkl#L123-L456">Source</a></div>
<div class="doc-comment">Deprecated: Spelling mistake. Replace with: <code>AnnotatedClass</code></div>
</div>
</div>
</li>
<li>
<div id="AnnotatedClssWithExpandableComment" class="anchor"> </div>
<div class="member with-page-link"><a class="member-selflink material-icons" href="#AnnotatedClssWithExpandableComment">link</a>
<div class="member-left">
<div class="member-modifiers member-deprecated">class </div>
</div>
<div class="member-main">
<div class="member-signature member-deprecated"><a href="AnnotatedClssWithExpandableComment.html" class="name-decl">AnnotatedClssWithExpandableComment</a><a class="member-source-link" href="https://example.com/package1/classAnnotations.pkl#L123-L456">Source</a></div>
<div class="doc-comment">Deprecated: Spelling mistake. Replace with: <code>AnnotatedClass</code></div>
</div>
</div>
</li>
<li>
<div id="AnnotatedClass" class="anchor"> </div>
<div class="member with-page-link"><a class="member-selflink material-icons" href="#AnnotatedClass">link</a>
<div class="member-left">
<div class="member-modifiers member-deprecated">class </div>
</div>
<div class="member-main">
<div class="member-signature member-deprecated"><a href="AnnotatedClass.html" class="name-decl">AnnotatedClass</a><a class="member-source-link" href="https://example.com/package1/classAnnotations.pkl#L123-L456">Source</a></div>
<div class="doc-comment">Deprecated.</div>
</div>
</div>
</li>
</ul>
</div>
</main>
</body>
</html>

View File

@@ -0,0 +1,150 @@
<!DOCTYPE html>
<html>
<head>
<title>Comments1 (com.package1/classComments:1.2.3) • Docsite Title</title>
<script src="../../../scripts/pkldoc.js" defer="defer"></script>
<script src="../../../scripts/scroll-into-view.min.js" defer="defer"></script>
<script src="../../../data/com.package1/1.2.3/classComments/Comments1.js" defer="defer"></script>
<link href="../../../styles/pkldoc.css" media="screen" type="text/css" rel="stylesheet">
<link rel="icon" type="image/svg+xml" href="../../../images/favicon.svg">
<link rel="apple-touch-icon" sizes="180x180" href="../../../images/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="../../../images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="../../../images/favicon-16x16.png">
<meta charset="UTF-8">
</head>
<body onload="onLoad()">
<header>
<div id="doc-title"><a href="../../../index.html">Docsite Title</a></div>
<div id="search"><i id="search-icon" class="material-icons">search</i><input id="search-input" type="search" placeholder="Click or press 'S' to search this package" autocomplete="off" data-package-name="com.package1" data-package-version="1.2.3" data-package-url-prefix="../" data-module-name="com.package1.classComments" data-class-name="Comments1" data-root-url-prefix="../../../"></div>
</header>
<main><a class="declaration-parent-link" href="../../../index.html">Docsite Title</a> &gt; <a class="declaration-parent-link" href="../index.html">com.package1</a> &gt; <a class="declaration-parent-link" href="index.html">com.package1.classComments</a>
<h1 id="declaration-title">Comments1<span id="declaration-version">1.2.3</span></h1>
<ul class="member-group-links">
<li><a href="#_methods">Methods</a></li>
</ul>
<div id="_overview" class="anchor"> </div>
<div id="_declaration" class="member">
<div class="member-signature">class <span class="name-decl">Comments1</span></div>
<dl class="member-info">
<dt class="runtime-data hidden">Known subtypes:</dt>
<dd id="known-subtypes" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">Known usages:</dt>
<dd id="known-usages" class="runtime-data hidden"></dd>
<dt class="runtime-data hidden">All versions:</dt>
<dd id="known-versions" class="runtime-data hidden"></dd>
</dl>
</div>
<div class="member-group">
<div id="_methods" class="anchor"> </div>
<h2 class="member-group-title">Methods<span class="toggle-inherited-members">(<span class="toggle-inherited-members-link button-link">show inherited</span>)</span></h2>
<ul>
<li>
<div id="getClass()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#getClass()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">getClass</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Class.html" class="name-ref">Class</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the class of <code>this</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="toString()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#toString()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">toString</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns a string representation of <code>this</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is used to convert the values of string interpolation expressions to strings.</p></div>
</div>
</div>
</li>
<li>
<div id="ifNonNull()" class="anchor"> </div>
<div id="ifNonNull().Result" class="anchor-param1"> </div>
<div id="ifNonNull().transform" class="anchor-param2"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#ifNonNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Any.html" class="name-ref">Any</a>.</span><span class="name-decl">ifNonNull</span>&lt;<a class="param1">Result</a>&gt;(<span class="param2">transform</span>: (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html#NonNull" class="name-ref">NonNull</a>) -&gt; <a href="Comments1.html#ifNonNull().Result" class="name-ref">Result</a>): <a href="Comments1.html#ifNonNull().Result" class="name-ref">Result</a>?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns <code>this |&gt; transform</code> if <code>this</code> is non-null, and <code>null</code> otherwise.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>This method is the complement of the <code>??</code> operator and the equivalent of an <code>Option</code> type's <code>map</code> and <code>flatMap</code> methods.</p></div>
</div>
</div>
</li>
<li>
<div id="hasProperty()" class="anchor"> </div>
<div id="hasProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#hasProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">hasProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Boolean.html" class="name-ref">Boolean</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Tells if this object has a property with the given <code>name</code>.</p></div>
</div>
</div>
</li>
<li>
<div id="getProperty()" class="anchor"> </div>
<div id="getProperty().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getProperty()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">getProperty</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Throws if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="getPropertyOrNull()" class="anchor"> </div>
<div id="getPropertyOrNull().name" class="anchor-param1"> </div>
<div class="member inherited expandable hidden collapsed with-expandable-docs"><i class="material-icons expandable-docs-icon">expand_more</i><a class="member-selflink material-icons" href="#getPropertyOrNull()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">getPropertyOrNull</span>(<span class="param1">name</span>: <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>): unknown?<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Returns the value of the property with the given <code>name</code>.</p></div>
<div class="doc-comment expandable hidden collapsed"><p>Returns <code>null</code> if a property with this name does not exist.</p></div>
</div>
</div>
</li>
<li>
<div id="toDynamic()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toDynamic()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">toDynamic</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html" class="name-ref">Dynamic</a><span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Dynamic.html"><code>Dynamic</code></a> object.</p></div>
</div>
</div>
</li>
<li>
<div id="toMap()" class="anchor"> </div>
<div class="member inherited expandable hidden collapsed"><a class="member-selflink material-icons" href="#toMap()">link</a>
<div class="member-left">
<div class="member-modifiers">function </div>
</div>
<div class="member-main">
<div class="member-signature"><span class="context"><a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Typed.html" class="name-ref">Typed</a>.</span><span class="name-decl">toMap</span>(): <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html" class="name-ref">Map</a>&lt;<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/String.html" class="name-ref">String</a>, unknown&gt;<span class="context"> (<a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/index.html" class="name-ref">pkl.base</a>)</span><a class="member-source-link" href="https://github.com/apple/pkl/blob/0.24.0/stdlib/base.pkl#L123-L456">Source</a></div>
<div class="doc-comment"><p>Converts this object to a <a href="https://pages.github.com/apple/pkl/stdlib/pkl/0.24.0/base/Map.html"><code>Map</code></a>.</p></div>
</div>
</div>
</li>
</ul>
</div>
</main>
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More