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)
}
}
}
}
|