aboutsummaryrefslogtreecommitdiff
path: root/src/Formats/StructuredFormatService.kt
blob: 32742fead4f119603d3845ffe2227dc62b0da078 (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
106
107
108
109
110
111
112
113
114
115
116
117
118
package org.jetbrains.dokka

import java.util.LinkedHashMap

public data class FormatLink(val text: String, val location: Location)

public abstract class StructuredFormatService(val locationService: LocationService,
                                              val languageService: LanguageService) : FormatService {

    abstract public fun appendBlockCode(to: StringBuilder, line: String)
    abstract public fun appendBlockCode(to: StringBuilder, lines: Iterable<String>)
    abstract public fun appendHeader(to: StringBuilder, text: String, level: Int = 1)
    abstract public fun appendText(to: StringBuilder, text: String)
    abstract public fun appendLine(to: StringBuilder, text: String)
    public abstract fun appendLine(to: StringBuilder)

    public abstract fun formatLink(text: String, location: Location): String
    public open fun formatLink(link: FormatLink): String = formatLink(link.text, link.location)

    public abstract fun formatBold(text: String): String
    public abstract fun formatCode(code: String): String
    public abstract fun formatBreadcrumbs(items: Iterable<FormatLink>): String

    open public fun link(from: DocumentationNode, to: DocumentationNode): FormatLink = link(from, to, extension)

    open public fun link(from: DocumentationNode, to: DocumentationNode, extension: String): FormatLink {
        return FormatLink(to.name, locationService.relativeLocation(from, to, extension))
    }

    open public fun appendDescription(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
        val described = nodes.filter { it.doc.hasDescription }
        if (described.any()) {
            appendHeader(to, "Description")
            for (node in described) {
                appendBlockCode(to, languageService.render(node))
                appendLine(to, node.doc.description)
                appendLine(to)
                for (section in node.doc.sections) {
                    appendLine(to, formatBold(section.label))
                    appendLine(to, section.text)
                    appendLine(to)
                }
            }
        }
    }

    open public fun appendSummary(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
        val breakdownBySummary = nodes.groupByTo(LinkedHashMap()) { node ->
            node.doc.summary
        }

        for ((summary, items) in breakdownBySummary) {
            appendLine(to, summary)
            appendBlockCode(to, items.map { languageService.render(it) })
        }
    }

    open public fun appendLocation(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
        val breakdownByName = nodes.groupByTo(LinkedHashMap()) { node -> node.name }
        for ((name, items) in breakdownByName) {
            appendHeader(to, "${name}")
            appendSummary(to, items)
            appendDescription(to, items)
        }
    }

    override fun appendNodes(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
        val breakdownByLocation = nodes.groupByTo(LinkedHashMap()) { node ->
            formatBreadcrumbs(node.path.map { link(node, it) })
        }

        for ((breadcrumbs, items) in breakdownByLocation) {
            appendLine(to, breadcrumbs)
            appendLine(to)
            appendLocation(to, items)
        }

        for (node in nodes) {
            if (node.members.any()) {
                appendHeader(to, "Members")

                appendLine(to, "| Name | Summary |") // TODO: hardcoded
                appendLine(to, "|------|---------|")
                val children = node.members.sortBy { it.name }
                val membersMap = children.groupByTo(LinkedHashMap()) { link(node, it) }

                for ((location, members) in membersMap) {
                    appendText(to, "|${formatLink(location)}|")
                    val breakdownBySummary = members.groupByTo(LinkedHashMap()) { it.doc.summary }
                    for ((summary, items) in breakdownBySummary) {
                        if (!summary.isEmpty()) {
                            appendText(to, summary)
                            appendText(to, "<br/>") // TODO: hardcoded
                        }

                        val signatures = items.map { formatBold(formatCode("${languageService.render(it)}")) }
                        appendText(to, signatures.join("<br/>")) // TODO: hardcoded
                    }

                    appendLine(to, "|")
                }
            }

        }
    }

    abstract public fun appendOutlineHeader(to: StringBuilder, node: DocumentationNode)
    abstract public fun appendOutlineChildren(to: StringBuilder, nodes: Iterable<DocumentationNode>)

    override public fun appendOutline(to: StringBuilder, nodes: Iterable<DocumentationNode>) {
        for (node in nodes) {
            appendOutlineHeader(to, node)
            if (node.members.any()) {
                appendOutlineChildren(to, node.members)
            }
        }
    }
}