aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin/renderers/html/SearchbarDataInstaller.kt
blob: 3c562315bf8dafaad5ccedaa77197ec68bc837a7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package org.jetbrains.dokka.base.renderers.html

import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.jetbrains.dokka.Platform
import org.jetbrains.dokka.model.DisplaySourceSet
import org.jetbrains.dokka.model.dfs
import org.jetbrains.dokka.pages.*
import java.util.concurrent.ConcurrentHashMap

data class SearchRecord(val name: String, val description: String? = null, val location: String, val searchKeys: List<String> = listOf(name)) {
    companion object { }
}

open class SearchbarDataInstaller {
    private val mapper = jacksonObjectMapper()

    private val pageList = ConcurrentHashMap<String, Pair<String, String>>()

    open fun generatePagesList(): String {
        val pages = pageList.entries
            .filter { it.key.isNotEmpty() }
            .sortedWith(compareBy({ it.key }, { it.value.first }, { it.value.second }))
            .groupBy { it.key.substringAfterLast(".") }
            .entries
            .flatMap { entry ->
                entry.value.map { subentry ->
                    val name = subentry.value.first
                    createSearchRecord(
                        name = name,
                        description = subentry.key,
                        location = subentry.value.second,
                        searchKeys = listOf(entry.key, name)
                    )
                }
            }
        return mapper.writeValueAsString(pages)
    }

    open fun createSearchRecord(name: String, description: String?, location: String, searchKeys: List<String>): SearchRecord =
        SearchRecord(name, description, location, searchKeys)


    private fun getSymbolSignature(page: ContentPage) = page.content.dfs { it.dci.kind == ContentKind.Symbol }

    private fun flattenToText(node: ContentNode): String {
        fun getContentTextNodes(node: ContentNode, sourceSetRestriction: DisplaySourceSet): List<ContentText> =
            when (node) {
                is ContentText -> listOf(node)
                is ContentComposite -> node.children
                    .filter { sourceSetRestriction in it.sourceSets }
                    .flatMap { getContentTextNodes(it, sourceSetRestriction) }
                    .takeIf { node.dci.kind != ContentKind.Annotations }
                    .orEmpty()
                else -> emptyList()
            }

        val sourceSetRestriction =
            node.sourceSets.find { it.platform == Platform.common } ?: node.sourceSets.first()
        return getContentTextNodes(node, sourceSetRestriction).joinToString("") { it.text }
    }

    open fun processPage(page: ContentPage, link: String) {
        val signature = getSymbolSignature(page)
        val textNodes = signature?.let { flattenToText(it) }
        val documentable = page.documentable
        if (documentable != null) {
            listOf(
                documentable.dri.packageName,
                documentable.dri.classNames,
                documentable.dri.callable?.name
            ).filter { !it.isNullOrEmpty() }
                .takeIf { it.isNotEmpty() }
                ?.joinToString(".")
                ?.let { id -> pageList.put(id, Pair(textNodes ?: page.name, link)) }
        }
    }
}