aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt
blob: de2242f2aa9773581272cdc9073aa7b7be2af52e (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
78
79
80
81
package org.jetbrains.dokka.base.allModulePage

import org.jetbrains.dokka.DokkaConfiguration
import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
import org.jetbrains.dokka.DokkaException
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.resolvers.local.MultimoduleLocationProvider.Companion.MULTIMODULE_PACKAGE_PLACEHOLDER
import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter
import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.doc.DocumentationNode
import org.jetbrains.dokka.model.doc.P
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.base.parsers.MarkdownParser
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.querySingle
import org.jetbrains.dokka.transformers.pages.PageCreator
import org.jetbrains.dokka.utilities.DokkaLogger
import java.io.File

class MultimodulePageCreator(
    val context: DokkaContext
) : PageCreator {
    private val logger: DokkaLogger = context.logger

    override fun invoke(): RootPageNode {
        val parser = MarkdownParser(logger = logger)
        val modules = context.configuration.modules
        modules.forEach(::throwOnMissingModuleDocFile)

        val commentsConverter = context.plugin(DokkaBase::class)?.querySingle { commentsToContentConverter }
        val signatureProvider = context.plugin(DokkaBase::class)?.querySingle { signatureProvider }
        if (commentsConverter == null || signatureProvider == null)
            throw IllegalStateException("Both comments converter and signature provider must not be null")

        val sourceSetData = emptySet<DokkaSourceSet>()
        val builder = PageContentBuilder(commentsConverter, signatureProvider, context.logger)
        val contentNode = builder.contentFor(
            dri = DRI(MULTIMODULE_PACKAGE_PLACEHOLDER),
            kind = ContentKind.Cover,
            sourceSets = sourceSetData
        ) {
            header(2, "All modules:")
            table(styles = setOf(MultimoduleTable)) {
                modules.mapNotNull { module ->
                    val paragraph = module.docFile.let(::File).readText().let { parser.parse(it).firstParagraph() }
                    paragraph?.let {
                        val dri = DRI(packageName = MULTIMODULE_PACKAGE_PLACEHOLDER, classNames = module.name)
                        val dci = DCI(setOf(dri), ContentKind.Main)
                        val header =
                            ContentHeader(listOf(linkNode(module.name, dri)), 2, dci, emptySet(), emptySet())
                        val content = ContentGroup(
                            DocTagToContentConverter.buildContent(it, dci, emptySet()),
                            dci,
                            emptySet(),
                            emptySet()
                        )
                        ContentGroup(listOf(header, content), dci, emptySet(), emptySet())
                    }
                }
            }
        }
        return MultimoduleRootPageNode(
            "Modules",
            setOf(DRI(packageName = MULTIMODULE_PACKAGE_PLACEHOLDER, classNames = "allModules")),
            contentNode
        )
    }

    private fun throwOnMissingModuleDocFile(module: DokkaConfiguration.DokkaModuleDescription) {
        val docFile = File(module.docFile)
        if (!docFile.exists() || !docFile.isFile) {
            throw DokkaException(
                "Missing documentation file for module ${module.name}: ${docFile.absolutePath}"
            )
        }
    }

    private fun DocumentationNode.firstParagraph() =
        this.children.flatMap { it.root.children }.filterIsInstance<P>().firstOrNull()
}