org.jetbrains.dokka.javadoc.renderer.SearchScriptsCreator.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javadoc-plugin Show documentation
Show all versions of javadoc-plugin Show documentation
Dokka is an API documentation engine for Kotlin
/*
* Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
package org.jetbrains.dokka.javadoc.renderer
import org.jetbrains.dokka.base.renderers.sourceSets
import org.jetbrains.dokka.base.resolvers.local.LocationProvider
import org.jetbrains.dokka.base.resolvers.local.resolveOrThrow
import org.jetbrains.dokka.javadoc.pages.*
import org.jetbrains.dokka.javadoc.renderer.SearchRecord.Companion.allTypes
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.DisplaySourceSet
import org.jetbrains.dokka.model.Documentable
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.utilities.formatToEndWithHtml
public class SearchScriptsCreator(
private val locationProvider: LocationProvider
) {
public fun invoke(input: RootPageNode): List {
val data = when (input) {
is JavadocModulePageNode -> processModules(listOf(input))
else -> processModules(input.children.filterIsInstance())
}
val serializer = SearchRecordJsonSerializer()
val modules = RendererSpecificResourcePage(
name = "module-search-index.js",
children = emptyList(),
strategy = RenderingStrategy.Write(serializer.serialize(data.moduleRecords, "moduleSearchIndex"))
)
val packages = RendererSpecificResourcePage(
name = "package-search-index.js",
children = emptyList(),
strategy = RenderingStrategy.Write(serializer.serialize(data.packageRecords, "packageSearchIndex"))
)
val types = RendererSpecificResourcePage(
name = "type-search-index.js",
children = emptyList(),
strategy = RenderingStrategy.Write(serializer.serialize(data.typeRecords, "typeSearchIndex"))
)
val members = RendererSpecificResourcePage(
name = "member-search-index.js",
children = emptyList(),
strategy = RenderingStrategy.Write(serializer.serialize(data.memberRecords, "memberSearchIndex"))
)
val indexes = RendererSpecificResourcePage(
name = "tag-search-index.js",
children = emptyList(),
strategy = RenderingStrategy.Write(serializer.serialize(data.searchIndexes, "tagSearchIndex"))
)
return listOf(modules, packages, types, members, indexes)
}
private fun processModules(input: List): SearchData {
val modules = SearchData(moduleRecords = input.map {
SearchRecord(
l = it.name,
url = locationProvider.resolveOrThrow(it).formatToEndWithHtml()
)
})
val processablePackages = input.flatMap { it.children.filterIsInstance() }
return processPackages(processablePackages, modules)
}
private fun processPackages(input: List, accumulator: SearchData): SearchData {
val packages = input.map {
SearchRecord(
l = it.name,
url = locationProvider.resolveOrThrow(it).formatToEndWithHtml()
)
} + SearchRecord.allPackages
fun allClasses(c: JavadocClasslikePageNode): List =
c.children.filterIsInstance().flatMap { allClasses(it) } + c
val types = input.flatMap {
it.children.filterIsInstance().flatMap { allClasses(it) }.map { classlike -> it to classlike }
}
val updated = accumulator.copy(packageRecords = packages)
return processTypes(types, updated)
}
private fun processTypes(
input: List>,
accumulator: SearchData
): SearchData {
val types = input.map {
SearchRecord(
p = it.first.name,
l = it.second.name,
url = locationProvider.resolveOrThrow(it.second).formatToEndWithHtml()
)
} + allTypes
val updated = accumulator.copy(typeRecords = types)
return processMembers(input, updated).copy(searchIndexes = indexSearchForClasslike(input))
}
private fun processMembers(
input: List>,
accumulator: SearchData
): SearchData {
val functions = input.flatMap {
(it.second.constructors + it.second.methods).withoutInherited().map { function ->
SearchRecordCreator.function(
packageName = it.first.name,
classlikeName = it.second.name,
input = function,
url = locationProvider.resolveOrThrow(function.dri, it.first.sourceSets())
)
}
}
val properties = input.flatMap {
it.second.properties.map { property ->
SearchRecordCreator.property(
packageName = it.first.name,
classlikeName = it.second.name,
property,
locationProvider.resolveOrThrow(property.dri, it.first.sourceSets())
)
}
}
val entries = input.flatMap {
it.second.entries.map { entry ->
SearchRecordCreator.entry(
packageName = it.first.name,
classlikeName = it.second.name,
entry,
locationProvider.resolveOrThrow(entry.dri, it.first.sourceSets())
)
}
}
return accumulator.copy(memberRecords = functions + properties + entries)
}
private fun indexSearchForClasslike(
input: List>,
): List {
val indexesForClasslike = input.flatMap {
val indexes = it.second.indexes()
indexes.map { index ->
val label = renderNode(index)
SearchRecord(
p = it.first.name,
c = it.second.name,
l = label,
url = resolveUrlForSearchIndex(it.second.dri.first(), it.second.sourceSets(), label)
)
}
}
val indexesForMemberNodes = input.flatMap { packageWithClasslike ->
(packageWithClasslike.second.constructors +
packageWithClasslike.second.methods.withoutInherited() +
packageWithClasslike.second.properties +
packageWithClasslike.second.entries
).map { it to it.indexes() }
.flatMap { entryWithIndex ->
entryWithIndex.second.map {
val label = renderNode(it)
SearchRecord(
p = packageWithClasslike.first.name,
c = packageWithClasslike.second.name,
l = label,
url = resolveUrlForSearchIndex(
entryWithIndex.first.dri,
packageWithClasslike.second.sourceSets(),
label
)
)
}
}
}
return indexesForClasslike + indexesForMemberNodes
}
private fun WithJavadocExtra.indexes(): List =
extra[JavadocIndexExtra]?.index.orEmpty()
private fun List.withoutInherited(): List = filter { !it.isInherited }
private fun resolveUrlForSearchIndex(
dri: DRI,
sourceSets: Set,
label: String
): String =
locationProvider.resolveOrThrow(dri, sourceSets).formatToEndWithHtml() + "#" + label
}
private data class SearchRecord(
val p: String? = null,
val c: String? = null,
val l: String,
val url: String? = null
) {
companion object {
val allPackages = SearchRecord(l = "All packages", url = "index.html")
val allTypes = SearchRecord(l = "All classes", url = "allclasses.html")
}
}
private object SearchRecordCreator {
fun function(
packageName: String,
classlikeName: String,
input: JavadocFunctionNode,
url: String
): SearchRecord =
SearchRecord(
p = packageName,
c = classlikeName,
l = input.name + input.parameters.joinToString(
prefix = "(",
postfix = ")"
) { renderNode(it.type) },
url = url.formatToEndWithHtml()
)
fun property(
packageName: String,
classlikeName: String,
input: JavadocPropertyNode,
url: String
): SearchRecord =
SearchRecord(
p = packageName,
c = classlikeName,
l = input.name,
url = url.formatToEndWithHtml()
)
fun entry(packageName: String, classlikeName: String, input: JavadocEntryNode, url: String): SearchRecord =
SearchRecord(
p = packageName,
c = classlikeName,
l = input.name,
url = url.formatToEndWithHtml()
)
}
private data class SearchData(
val moduleRecords: List = emptyList(),
val packageRecords: List = emptyList(),
val typeRecords: List = emptyList(),
val memberRecords: List = emptyList(),
val searchIndexes: List = emptyList()
)
private class SearchRecordJsonSerializer {
fun serialize(record: SearchRecord): String {
val serialized = StringBuilder()
serialized.append("{")
with(record) {
if (p != null) serialized.append("\"p\":\"$p\",")
if (c != null) serialized.append("\"c\":\"$c\",")
serialized.append("\"l\":\"$l\"")
if (url != null) serialized.append(",\"url\":\"$url\"")
}
serialized.append("}")
return serialized.toString()
}
fun serialize(records: List, variable: String): String =
"var " + variable + " = " + records.joinToString(prefix = "[", postfix = "]") { serialize(it) }
}
private fun renderNode(node: ContentNode): String =
when (node) {
is ContentText -> node.text
else -> node.children.joinToString(separator = "") { renderNode(it) }
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy