aboutsummaryrefslogtreecommitdiff
path: root/plugins/javadoc/src/main/kotlin
diff options
context:
space:
mode:
authorMarcin Aman <maman@virtuslab.com>2020-07-09 10:45:06 +0200
committerPaweł Marks <Kordyjan@users.noreply.github.com>2020-07-16 13:17:39 +0200
commit04cf1cdd3a909fa62e5ffda5b7d04695c749177e (patch)
tree5c38372dd70f5528bf55c084a1893a7af8e41359 /plugins/javadoc/src/main/kotlin
parent42c6bcdbd564628907491289555c6d6713294fef (diff)
downloaddokka-04cf1cdd3a909fa62e5ffda5b7d04695c749177e.tar.gz
dokka-04cf1cdd3a909fa62e5ffda5b7d04695c749177e.tar.bz2
dokka-04cf1cdd3a909fa62e5ffda5b7d04695c749177e.zip
Implement javadoc search
Diffstat (limited to 'plugins/javadoc/src/main/kotlin')
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt34
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocIndexExtra.kt10
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt41
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/pages/htmlPreprocessors.kt7
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt22
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt13
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt9
-rw-r--r--plugins/javadoc/src/main/kotlin/javadoc/renderer/SearchScriptsCreator.kt261
8 files changed, 358 insertions, 39 deletions
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt
index 6fe18001..7420f78e 100644
--- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt
+++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt
@@ -4,11 +4,11 @@ import javadoc.pages.*
import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
import org.jetbrains.dokka.Platform
import org.jetbrains.dokka.base.signatures.SignatureProvider
-import org.jetbrains.dokka.base.signatures.function
import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter
import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter
import org.jetbrains.dokka.model.*
import org.jetbrains.dokka.model.doc.Description
+import org.jetbrains.dokka.model.doc.Index
import org.jetbrains.dokka.model.doc.Param
import org.jetbrains.dokka.model.doc.TagWrapper
import org.jetbrains.dokka.model.properties.PropertyContainer
@@ -51,7 +51,8 @@ open class JavadocPageCreator(
it.dri,
it.name,
signatureForNode(it, jvm),
- it.descriptionToContentNodes(jvm)
+ it.descriptionToContentNodes(jvm),
+ PropertyContainer.withAll(it.indexesInDocumentation())
)
}.orEmpty(),
classlikes = c.classlikes.mapNotNull { pageForClasslike(it) },
@@ -60,11 +61,12 @@ open class JavadocPageCreator(
it.dri,
it.name,
signatureForNode(it, jvm),
- it.descriptionToContentNodes(jvm)
+ it.descriptionToContentNodes(jvm),
+ PropertyContainer.withAll(it.indexesInDocumentation())
)
},
documentable = c,
- extras = (c as? WithExtraProperties<Documentable>)?.extra ?: PropertyContainer.empty()
+ extra = ((c as? WithExtraProperties<Documentable>)?.extra ?: PropertyContainer.empty()) + c.indexesInDocumentation()
)
}
@@ -148,11 +150,12 @@ open class JavadocPageCreator(
type = type,
description = it.brief(),
typeBound = it.type,
- dri = it.dri
+ dri = it.dri,
+ extra = PropertyContainer.withAll(it.indexesInDocumentation())
)
}
},
- extras = extra
+ extra = extra + indexesInDocumentation()
)
}
@@ -212,5 +215,24 @@ open class JavadocPageCreator(
private fun signatureForNode(documentable: Documentable, sourceSet: DokkaSourceSet): JavadocSignatureContentNode =
signatureProvider.signature(documentable).nodeForJvm(sourceSet).asJavadocNode()
+
+ private fun Documentable.indexesInDocumentation(): JavadocIndexExtra {
+ val indexes = documentation[highestJvmSourceSet]?.withDescendants()?.filterIsInstance<Index>()?.toList().orEmpty()
+ return JavadocIndexExtra(
+ indexes.map {
+ ContentGroup(
+ children = DocTagToContentConverter.buildContent(
+ it,
+ DCI(setOf(dri), JavadocContentKind.OverviewSummary),
+ sourceSets.toSet()
+ ),
+ dci = DCI(setOf(dri), JavadocContentKind.OverviewSummary),
+ sourceSets = sourceSets.toSet(),
+ style = emptySet(),
+ extra = PropertyContainer.empty()
+ )
+ }
+ )
+ }
}
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocIndexExtra.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocIndexExtra.kt
new file mode 100644
index 00000000..3ae04cae
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocIndexExtra.kt
@@ -0,0 +1,10 @@
+package javadoc.pages
+
+import org.jetbrains.dokka.model.Documentable
+import org.jetbrains.dokka.model.properties.ExtraProperty
+import org.jetbrains.dokka.pages.ContentNode
+
+data class JavadocIndexExtra(val index: List<ContentNode>) : ExtraProperty<Documentable> {
+ override val key: ExtraProperty.Key<Documentable, *> = JavadocIndexExtra
+ companion object : ExtraProperty.Key<Documentable, JavadocIndexExtra>
+} \ No newline at end of file
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt
index 216b9319..daa4fda5 100644
--- a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt
+++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt
@@ -9,6 +9,7 @@ import org.jetbrains.dokka.base.renderers.sourceSets
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.*
import org.jetbrains.dokka.model.properties.PropertyContainer
+import org.jetbrains.dokka.model.properties.WithExtraProperties
import org.jetbrains.dokka.pages.*
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassKind
@@ -17,6 +18,11 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
interface JavadocPageNode : ContentPage
+interface WithJavadocExtra<T : Documentable> : WithExtraProperties<T> {
+ override fun withNewExtras(newExtras: PropertyContainer<T>): T =
+ throw IllegalStateException("Merging extras is not applicable for javadoc")
+}
+
class JavadocModulePageNode(
override val name: String,
override val content: JavadocContentNode,
@@ -85,23 +91,26 @@ data class JavadocEntryNode(
override val dri: DRI,
val name: String,
val signature: JavadocSignatureContentNode,
- val brief: List<ContentNode>
-): AnchorableJavadocNode(dri)
+ val brief: List<ContentNode>,
+ override val extra: PropertyContainer<DEnumEntry> = PropertyContainer.empty()
+): AnchorableJavadocNode(dri), WithJavadocExtra<DEnumEntry>
data class JavadocParameterNode(
override val dri: DRI,
val name: String,
val type: ContentNode,
val description: List<ContentNode>,
- val typeBound: Bound
-): AnchorableJavadocNode(dri)
+ val typeBound: Bound,
+ override val extra: PropertyContainer<DParameter> = PropertyContainer.empty()
+): AnchorableJavadocNode(dri), WithJavadocExtra<DParameter>
data class JavadocPropertyNode(
override val dri: DRI,
val name: String,
val signature: JavadocSignatureContentNode,
- val brief: List<ContentNode>
-): AnchorableJavadocNode(dri)
+ val brief: List<ContentNode>,
+ override val extra: PropertyContainer<DProperty> = PropertyContainer.empty()
+): AnchorableJavadocNode(dri), WithJavadocExtra<DProperty>
data class JavadocFunctionNode(
val signature: JavadocSignatureContentNode,
@@ -109,8 +118,16 @@ data class JavadocFunctionNode(
val parameters: List<JavadocParameterNode>,
val name: String,
override val dri: DRI,
- val extras: PropertyContainer<DFunction> = PropertyContainer.empty()
-): AnchorableJavadocNode(dri)
+ override val extra: PropertyContainer<DFunction> = PropertyContainer.empty()
+): AnchorableJavadocNode(dri), WithJavadocExtra<DFunction> {
+ val isInherited: Boolean
+ get() {
+ val extra = extra[InheritedFunction]
+ return extra?.inheritedFrom?.keys?.firstOrNull { it.analysisPlatform == Platform.jvm }?.let { jvm ->
+ extra.isInherited(jvm)
+ } ?: false
+ }
+}
class JavadocClasslikePageNode(
override val name: String,
@@ -126,8 +143,8 @@ class JavadocClasslikePageNode(
override val documentable: Documentable? = null,
override val children: List<PageNode> = emptyList(),
override val embeddedResources: List<String> = listOf(),
- val extras: PropertyContainer<Documentable>,
-) : JavadocPageNode {
+ override val extra: PropertyContainer<DClasslike> = PropertyContainer.empty(),
+) : JavadocPageNode, WithJavadocExtra<DClasslike> {
val kind: String? = documentable?.kind()
val packageName = dri.first().packageName
@@ -149,7 +166,7 @@ class JavadocClasslikePageNode(
documentable,
children,
embeddedResources,
- extras
+ extra
)
override fun modified(
@@ -173,7 +190,7 @@ class JavadocClasslikePageNode(
documentable,
children,
embeddedResources,
- extras
+ extra
)
}
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/htmlPreprocessors.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/htmlPreprocessors.kt
index 3ccd1d71..18096ad4 100644
--- a/plugins/javadoc/src/main/kotlin/javadoc/pages/htmlPreprocessors.kt
+++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/htmlPreprocessors.kt
@@ -35,7 +35,12 @@ object TreeViewInstaller : PageTransformer {
root = root
)
- return node.modified(children = node.children.map { node -> install(node, root) } + overviewTree) as JavadocModulePageNode
+ return node.modified(children = node.children.map { node ->
+ install(
+ node,
+ root
+ )
+ } + overviewTree) as JavadocModulePageNode
}
private fun installPackageTreeNode(node: JavadocPackagePageNode, root: RootPageNode): JavadocPackagePageNode {
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt
index aeff192a..ceb6f9ad 100644
--- a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt
+++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt
@@ -4,6 +4,7 @@ import javadoc.location.JavadocLocationProvider
import javadoc.pages.JavadocSignatureContentNode
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.utilities.formatToEndWithHtml
import org.jetbrains.dokka.utilities.htmlEscape
internal class JavadocContentToHtmlTranslator(
@@ -13,21 +14,30 @@ internal class JavadocContentToHtmlTranslator(
fun htmlForContentNode(node: ContentNode, relative: PageNode?): String =
when (node) {
- is ContentGroup -> htmlForContentNodes(node.children, relative)
- is ContentText -> node.text.htmlEscape()
+ is ContentGroup -> htmlForContentNodes(node.children, node.style, relative)
+ is ContentText -> buildText(node)
is ContentDRILink -> buildLink(
locationProvider.resolve(node.address, node.sourceSets, relative),
- htmlForContentNodes(node.children, relative)
+ htmlForContentNodes(node.children, node.style, relative)
)
- is ContentResolvedLink -> buildLink(node.address, htmlForContentNodes(node.children, relative))
+ is ContentResolvedLink -> buildLink(node.address, htmlForContentNodes(node.children, node.style, relative))
is ContentCode -> htmlForCode(node.children)
is JavadocSignatureContentNode -> htmlForSignature(node, relative)
else -> ""
}
- fun htmlForContentNodes(list: List<ContentNode>, relative: PageNode?) =
+ fun htmlForContentNodes(list: List<ContentNode>, styles: Set<Style>, relative: PageNode?) =
list.joinToString(separator = "") { htmlForContentNode(it, relative) }
+ private fun buildText(node: ContentText): String {
+ val escapedText = node.text.htmlEscape()
+ return if (node.style.contains(ContentStyle.InDocumentationAnchor)) {
+ """<em><a id="$escapedText" class="searchTagResult">${escapedText}</a></em>"""
+ } else {
+ escapedText
+ }
+ }
+
private fun htmlForCode(code: List<ContentNode>): String = code.map { element ->
when (element) {
is ContentText -> element.text
@@ -49,7 +59,5 @@ internal class JavadocContentToHtmlTranslator(
fun buildLink(address: String, content: String) =
"""<a href=${address.formatToEndWithHtml()}>$content</a>"""
- private fun String.formatToEndWithHtml() =
- if (endsWith(".html") || contains(Regex("\\.html#"))) this else "$this.html"
}
} \ No newline at end of file
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt
index 56df469b..f59fd27e 100644
--- a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt
+++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt
@@ -129,16 +129,11 @@ internal class JavadocContentToTemplateMapTranslator(
)
private fun templateMapForImplementedInterfaces(node: JavadocClasslikePageNode) =
- node.extras[ImplementedInterfaces]?.interfaces?.entries?.firstOrNull { it.key.analysisPlatform == Platform.jvm }?.value?.map { it.displayable() } // TODO: REMOVE HARDCODED JVM DEPENDENCY
+ node.extra[ImplementedInterfaces]?.interfaces?.entries?.firstOrNull { it.key.analysisPlatform == Platform.jvm }?.value?.map { it.displayable() } // TODO: REMOVE HARDCODED JVM DEPENDENCY
.orEmpty()
private fun templateMapForClasslikeMethods(nodes: List<JavadocFunctionNode>): TemplateMap {
- val (inherited, own) = nodes.partition {
- val extra = it.extras[InheritedFunction]
- extra?.inheritedFrom?.keys?.firstOrNull { it.analysisPlatform == Platform.jvm }?.let { jvm ->
- extra.isInherited(jvm)
- } ?: false
- }
+ val (inherited, own) = nodes.partition { it.isInherited }
return mapOf(
"own" to own.map { templateMapForFunctionNode(it) },
"inherited" to inherited.map { templateMapForInheritedMethod(it) }
@@ -152,7 +147,7 @@ internal class JavadocContentToTemplateMapTranslator(
}
private fun templateMapForInheritedMethod(node: JavadocFunctionNode): TemplateMap {
- val inheritedFrom = node.extras[InheritedFunction]?.inheritedFrom
+ val inheritedFrom = node.extra[InheritedFunction]?.inheritedFrom
return mapOf(
"inheritedFrom" to inheritedFrom?.entries?.firstOrNull { it.key.analysisPlatform == Platform.jvm }?.value?.displayable() // TODO: REMOVE HARDCODED JVM DEPENDENCY
.orEmpty(),
@@ -219,7 +214,7 @@ internal class JavadocContentToTemplateMapTranslator(
htmlTranslator.htmlForContentNode(node, relativeNode)
private fun htmlForContentNodes(nodes: List<ContentNode>, relativeNode: PageNode) =
- htmlTranslator.htmlForContentNodes(nodes, relativeNode)
+ htmlTranslator.htmlForContentNodes(nodes, emptySet(), relativeNode)
}
private fun DRI.displayable(): String = "${packageName}.${sureClassNames}"
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt
index f7d75924..80d5a2b7 100644
--- a/plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt
+++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt
@@ -40,6 +40,7 @@ class KorteJavadocRenderer(private val outputWriter: OutputWriter, val context:
locationProvider = context.plugin<JavadocPlugin>().querySingle { locationProviderFactory }.getLocationProvider(newRoot)
runBlocking(Dispatchers.IO) {
renderModulePageNode(newRoot as JavadocModulePageNode)
+ SearchScriptsCreator(locationProvider).invoke(newRoot).forEach { renderSpecificPage(it, "") }
}
}
@@ -80,7 +81,7 @@ class KorteJavadocRenderer(private val outputWriter: OutputWriter, val context:
private fun CoroutineScope.renderSpecificPage(node: RendererSpecificPage, path: String) = launch {
when (val strategy = node.strategy) {
is RenderingStrategy.Copy -> outputWriter.writeResources(strategy.from, "")
- is RenderingStrategy.Write -> outputWriter.writeHtml(path, strategy.text)
+ is RenderingStrategy.Write -> outputWriter.writeHtml(node.name, strategy.text)
is RenderingStrategy.Callback -> outputWriter.writeResources(
path,
strategy.instructions(this@KorteJavadocRenderer, node)
@@ -94,7 +95,7 @@ class KorteJavadocRenderer(private val outputWriter: OutputWriter, val context:
private fun DRI.toLink(context: PageNode? = null) = locationProvider.resolve(this, emptySet(), context)
- private suspend fun OutputWriter.writeHtml(path: String, text: String) = write(path, text, ".html")
+ private suspend fun OutputWriter.writeHtml(path: String, text: String) = write(path, text, "")
private fun CoroutineScope.writeFromTemplate(
writer: OutputWriter,
path: String,
@@ -102,7 +103,7 @@ class KorteJavadocRenderer(private val outputWriter: OutputWriter, val context:
args: List<Pair<String, *>>
) = launch {
val tmp = templateRenderer.render(template, *(args.toTypedArray()))
- writer.writeHtml(path, tmp)
+ writer.writeHtml("$path.html", tmp)
}
private fun getTemplateConfig() = TemplateConfig().also { config ->
@@ -118,7 +119,7 @@ class KorteJavadocRenderer(private val outputWriter: OutputWriter, val context:
(buildLink(
locationProvider.resolve(link, contextRoot),
link.name
- ) to contentToHtmlTranslator.htmlForContentNodes(doc, contextRoot)).pairToTag().trim()
+ ) to contentToHtmlTranslator.htmlForContentNodes(doc, emptySet(), contextRoot)).pairToTag().trim()
},
TeFunction("createListRow") { args ->
val link = args.first() as LinkJavadocListEntry
diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/SearchScriptsCreator.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/SearchScriptsCreator.kt
new file mode 100644
index 00000000..28b88909
--- /dev/null
+++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/SearchScriptsCreator.kt
@@ -0,0 +1,261 @@
+package javadoc.renderer
+
+import javadoc.location.JavadocLocationProvider
+import javadoc.pages.*
+import javadoc.renderer.SearchRecord.Companion.allTypes
+import org.jetbrains.dokka.DokkaConfiguration
+import org.jetbrains.dokka.base.renderers.sourceSets
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.model.Documentable
+import org.jetbrains.dokka.model.InheritedFunction
+import org.jetbrains.dokka.model.doc.Index
+import org.jetbrains.dokka.model.properties.WithExtraProperties
+import org.jetbrains.dokka.pages.*
+import org.jetbrains.dokka.utilities.formatToEndWithHtml
+import org.jetbrains.dokka.utilities.htmlEscape
+import java.lang.StringBuilder
+
+class SearchScriptsCreator(private val locationProvider: JavadocLocationProvider) {
+
+ fun invoke(input: RootPageNode): List<RendererSpecificPage> {
+ val data = when (input) {
+ is JavadocModulePageNode -> processModules(listOf(input))
+ else -> SearchData()
+ }
+ 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<JavadocModulePageNode>): SearchData {
+ val modules = SearchData(moduleRecords = input.map { SearchRecord(l = it.name, url = locationProvider.resolve(it).formatToEndWithHtml()) })
+ val processablePackages = input.flatMap { it.children.filterIsInstance<JavadocPackagePageNode>() }
+ return processPackages(processablePackages, modules)
+ }
+
+ private fun processPackages(input: List<JavadocPackagePageNode>, accumulator: SearchData): SearchData {
+ val packages = input.map { SearchRecord(l = it.name, url = locationProvider.resolve(it).formatToEndWithHtml()) } + SearchRecord.allPackages
+ val types = input.flatMap {
+ it.children.filterIsInstance<JavadocClasslikePageNode>().map { classlike -> it to classlike }
+ }
+ val updated = accumulator.copy(packageRecords = packages)
+ return processTypes(types, updated)
+ }
+
+ private fun processTypes(
+ input: List<Pair<JavadocPackagePageNode, JavadocClasslikePageNode>>,
+ accumulator: SearchData
+ ): SearchData {
+ val types = input.map {
+ SearchRecord(
+ p = it.first.name,
+ l = it.second.name,
+ url = locationProvider.resolve(it.second).formatToEndWithHtml()
+ )
+ } + allTypes
+ val updated = accumulator.copy(typeRecords = types)
+ return processMembers(input, updated).copy(searchIndexes = indexSearchForClasslike(input))
+ }
+
+ private fun processMembers(
+ input: List<Pair<JavadocPackagePageNode, JavadocClasslikePageNode>>,
+ 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.resolve(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.resolve(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.resolve(entry.dri, it.first.sourceSets())
+ )
+ }
+ }
+
+ return accumulator.copy(memberRecords = functions + properties + entries)
+ }
+
+ private fun indexSearchForClasslike(
+ input: List<Pair<JavadocPackagePageNode, JavadocClasslikePageNode>>,
+ ): List<SearchRecord> {
+ 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 <T : Documentable> WithJavadocExtra<T>.indexes(): List<ContentNode> = extra[JavadocIndexExtra]?.index.orEmpty()
+
+ private fun List<JavadocFunctionNode>.withoutInherited(): List<JavadocFunctionNode> = filter { !it.isInherited }
+
+ private fun resolveUrlForSearchIndex(dri: DRI, sourceSets: Set<DokkaConfiguration.DokkaSourceSet>, label: String): String =
+ locationProvider.resolve(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<SearchRecord> = emptyList(),
+ val packageRecords: List<SearchRecord> = emptyList(),
+ val typeRecords: List<SearchRecord> = emptyList(),
+ val memberRecords: List<SearchRecord> = emptyList(),
+ val searchIndexes: List<SearchRecord> = 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<SearchRecord>, 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) }
+ } \ No newline at end of file