aboutsummaryrefslogtreecommitdiff
path: root/core/src/main/kotlin/renderers/DefaultRenderer.kt
blob: 1152bcc5c9960cd8b7e823abb3a93217a31bf29b (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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package org.jetbrains.dokka.renderers

import org.jetbrains.dokka.CoreExtensions
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.single
import org.jetbrains.dokka.resolvers.LocationProvider


abstract class DefaultRenderer<T>(
    protected val outputWriter: OutputWriter,
    protected val context: DokkaContext
) : Renderer {

    protected lateinit var locationProvider: LocationProvider
        private set

    protected abstract fun T.buildHeader(level: Int, content: T.() -> Unit)
    protected abstract fun T.buildLink(address: String, content: T.() -> Unit)
    protected abstract fun T.buildList(node: ContentList, pageContext: PageNode)
    protected abstract fun T.buildNewLine()
    protected abstract fun T.buildResource(node: ContentEmbeddedResource, pageContext: PageNode)
    protected abstract fun T.buildTable(node: ContentTable, pageContext: PageNode)
    protected abstract fun T.buildText(textNode: ContentText)
    protected abstract fun T.buildNavigation(page: PageNode)

    protected abstract fun buildPage(page: PageNode, content: (T, PageNode) -> Unit): String
    protected abstract fun buildError(node: ContentNode)

    protected open fun T.buildGroup(node: ContentGroup, pageContext: PageNode){
        node.children.forEach { it.build(this, pageContext) }
    }

    protected open fun T.buildLinkText(nodes: List<ContentNode>, pageContext: PageNode) {
        nodes.forEach { it.build(this, pageContext) }
    }

    protected open fun T.buildCode(code: List<ContentNode>, language: String, pageContext: PageNode) {
        code.forEach { it.build(this, pageContext) }
    }

    protected open fun T.buildHeader(node: ContentHeader, pageContext: PageNode) {
        buildHeader(node.level) { node.children.forEach { it.build(this, pageContext) } }
    }

    protected open fun ContentNode.build(builder: T, pageContext: PageNode) = builder.buildContentNode(this, pageContext)

    protected open fun T.buildContentNode(node: ContentNode, pageContext: PageNode) {
        when (node) {
            is ContentText -> buildText(node)
            is ContentHeader -> buildHeader(node, pageContext)
            is ContentCode -> buildCode(node.children, node.language, pageContext)
            is ContentDRILink -> buildLink(
                locationProvider.resolve(node.address, node.platforms.toList(), pageContext)) {
                buildLinkText(node.children, pageContext)
            }
            is ContentResolvedLink -> buildLink(node.address) {buildLinkText(node.children, pageContext)}
            is ContentEmbeddedResource -> buildResource(node, pageContext)
            is ContentList -> buildList(node, pageContext)
            is ContentTable -> buildTable(node, pageContext)
            is ContentGroup -> buildGroup(node, pageContext)
            else -> buildError(node)
        }
    }

    protected open fun buildPageContent(context: T, page: PageNode) {
        context.buildNavigation(page)
        page.content.build(context, page)
    }

    protected open fun renderPage(page: PageNode) =
        outputWriter.write(locationProvider.resolve(page), buildPage(page, ::buildPageContent), "")

    protected open fun renderPages(root: PageNode) {
        renderPage(root)
        root.children.forEach { renderPages(it) }
    }

    protected open fun buildSupportFiles() {}

    protected open fun renderPackageList(root: PageNode) =
        getPackageNamesAndPlatforms(root)
            .keys
            .joinToString("\n")
            .also { outputWriter.write("${root.name}/package-list", it, "") }

    protected open fun getPackageNamesAndPlatforms(root: PageNode): Map<String, List<PlatformData>> =
        root.children
            .map(::getPackageNamesAndPlatforms)
            .fold(emptyMap<String, List<PlatformData>>()) { e, acc -> acc + e } +
                if (root is PackagePageNode) {
                    mapOf(root.name to root.platforms())
                } else {
                    emptyMap()
                }

    override fun render(root: PageNode) {
        locationProvider = context.single(CoreExtensions.locationProviderFactory).getLocationProvider(root as ModulePageNode)
        renderPackageList(root)
        buildSupportFiles()
        renderPages(root)
    }
}

fun PageNode.platforms() = this.content.platforms.toList()