package org.jetbrains.dokka import java.util.LinkedHashMap import org.jetbrains.dokka.DocumentationNode.Kind public data class FormatLink(val text: String, val location: Location) public abstract class StructuredFormatService(val locationService: LocationService, val signatureGenerator: SignatureGenerator) : FormatService { abstract public fun appendBlockCode(to: StringBuilder, line: String) abstract public fun appendBlockCode(to: StringBuilder, lines: Iterable) 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(link: FormatLink): String public abstract fun formatBold(text: String): String public abstract fun formatCode(code: String): String public abstract fun formatBreadcrumbs(items: Iterable): 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) { val described = nodes.filter { it.doc.hasDescription } if (described.any()) { appendHeader(to, "Description") for (node in described) { appendBlockCode(to, signatureGenerator.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) { val breakdownBySummary = nodes.groupByTo(LinkedHashMap()) { node -> node.doc.summary } for ((summary, items) in breakdownBySummary) { appendLine(to, summary) appendBlockCode(to, items.map { signatureGenerator.render(it) }) } } open public fun appendLocation(to: StringBuilder, nodes: Iterable) { 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) { 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 |") appendLine(to, "|------|---------|") val children = node.members.sortBy { it.name } val membersMap = children.groupByTo(LinkedHashMap()) { link(node, it) } for ((location, members) in membersMap) { val mainMember = members.first() val displayName = when (mainMember.kind) { Kind.Constructor -> "*.init*" else -> signatureGenerator.renderName(mainMember).htmlEscape() } appendText(to, "|${formatLink(location)}|") val breakdownBySummary = members.groupByTo(LinkedHashMap()) { it.doc.summary } for ((summary, items) in breakdownBySummary) { appendLine(to, summary) appendBlockCode(to, items.map { formatBold("${signatureGenerator.render(it)}") }) } appendLine(to, "|") } } } } }