aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin/renderers/PackageListService.kt
blob: 3ed6cd212fabcde0e5294a88c5991e63f29f14b6 (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
/*
 * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
 */

package org.jetbrains.dokka.base.renderers

import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.resolvers.shared.LinkFormat
import org.jetbrains.dokka.base.resolvers.shared.PackageList.Companion.DOKKA_PARAM_PREFIX
import org.jetbrains.dokka.base.resolvers.shared.PackageList.Companion.MODULE_DELIMITER
import org.jetbrains.dokka.base.resolvers.shared.PackageList.Companion.SINGLE_MODULE_NAME
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.plugin
import org.jetbrains.dokka.plugability.querySingle

public class PackageListService(
    public val context: DokkaContext,
    public val rootPage: RootPageNode
) {

    public fun createPackageList(module: ModulePage, format: LinkFormat): String {

        val packages = mutableSetOf<String>()
        val nonStandardLocations = mutableMapOf<String, String>()

        val locationProvider =
            context.plugin<DokkaBase>().querySingle { locationProviderFactory }.getLocationProvider(rootPage)

        fun visit(node: PageNode) {
            if (node is PackagePage) {
                node.name
                    .takeUnless { name -> name.startsWith("[") && name.endsWith("]") } // Do not include the package name for declarations without one
                    ?.let { packages.add(it) }
            }

            val contentPage = node as? ContentPage
            contentPage?.dri?.forEach { dri ->
                val nodeLocation = locationProvider.resolve(node, context = module, skipExtension = true)
                    ?: run { context.logger.error("Cannot resolve path for ${node.name}!"); null }

                if (dri != DRI.topLevel && locationProvider.expectedLocationForDri(dri) != nodeLocation) {
                    nonStandardLocations[dri.toString()] = "$nodeLocation.${format.linkExtension}"
                }
            }

            node.children.forEach { visit(it) }
        }

        visit(module)
        return renderPackageList(
            nonStandardLocations = nonStandardLocations,
            modules = mapOf(SINGLE_MODULE_NAME to packages),
            format = format.formatName,
            linkExtension = format.linkExtension
        )
    }

    public companion object {
        public fun renderPackageList(
            nonStandardLocations: Map<String, String>,
            modules: Map<String, Set<String>>,
            format: String,
            linkExtension: String
        ): String = buildString {
            appendLine("$DOKKA_PARAM_PREFIX.format:${format}")
            appendLine("$DOKKA_PARAM_PREFIX.linkExtension:${linkExtension}")
            nonStandardLocations.map { (signature, location) ->
                "$DOKKA_PARAM_PREFIX.location:$signature\u001f$location"
            }.sorted().joinTo(this, separator = "\n", postfix = "\n")

            modules.mapNotNull { (module, packages) ->
                ("$MODULE_DELIMITER$module\n".takeIf { module != SINGLE_MODULE_NAME }.orEmpty() +
                        packages.filter(String::isNotBlank).sorted().joinToString(separator = "\n"))
                        .takeIf { packages.isNotEmpty() }
            }.joinTo(this, separator = "\n", postfix = "\n")
        }
    }
}