blob: 41ffc61df17334e84a6a3b4df95ad6b189dc4705 [file] [log] [blame]
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +04001package org.jetbrains.dokka
2
Dmitry Jemerov0c584d02015-01-12 17:23:07 +01003import org.jetbrains.dokka.LanguageService.RenderMode
Dmitry Jemerov8827d302015-10-20 12:53:17 +02004import java.util.*
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +04005
Dmitry Jemerovf99ec732015-10-29 11:54:27 +01006data class FormatLink(val text: String, val href: String)
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +04007
Dmitry Jemerov66593372015-03-03 19:35:56 +01008enum class ListKind {
Dmitry Jemerov64414ce2015-05-29 13:52:43 +02009 Ordered,
Dmitry Jemerov66593372015-03-03 19:35:56 +010010 Unordered
11}
12
Dmitry Jemerovf99ec732015-10-29 11:54:27 +010013abstract class StructuredFormatService(locationService: LocationService,
Dmitry Jemerovea1f4cc2015-02-19 19:51:01 +010014 val languageService: LanguageService,
15 override val extension: String) : FormatService {
16 val locationService: LocationService = locationService.withExtension(extension)
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040017
Dmitry Jemerovf99ec732015-10-29 11:54:27 +010018 abstract fun appendBlockCode(to: StringBuilder, line: String, language: String)
19 abstract fun appendHeader(to: StringBuilder, text: String, level: Int = 1)
20 abstract fun appendParagraph(to: StringBuilder, text: String)
21 abstract fun appendLine(to: StringBuilder, text: String)
22 abstract fun appendLine(to: StringBuilder)
23 abstract fun appendAnchor(to: StringBuilder, anchor: String)
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +040024
Dmitry Jemerovf99ec732015-10-29 11:54:27 +010025 abstract fun appendTable(to: StringBuilder, body: () -> Unit)
26 abstract fun appendTableHeader(to: StringBuilder, body: () -> Unit)
27 abstract fun appendTableBody(to: StringBuilder, body: () -> Unit)
28 abstract fun appendTableRow(to: StringBuilder, body: () -> Unit)
29 abstract fun appendTableCell(to: StringBuilder, body: () -> Unit)
Ilya Ryzhenkov499d0822014-07-15 16:18:53 +040030
Dmitry Jemerovf99ec732015-10-29 11:54:27 +010031 abstract fun formatText(text: String): String
32 abstract fun formatSymbol(text: String): String
33 abstract fun formatKeyword(text: String): String
34 abstract fun formatIdentifier(text: String, kind: IdentifierKind): String
35 fun formatEntity(text: String): String = text
36 abstract fun formatLink(text: String, href: String): String
37 open fun formatLink(link: FormatLink): String = formatLink(formatText(link.text), link.href)
38 abstract fun formatStrong(text: String): String
39 abstract fun formatStrikethrough(text: String): String
40 abstract fun formatEmphasis(text: String): String
41 abstract fun formatCode(code: String): String
42 abstract fun formatUnorderedList(text: String): String
43 abstract fun formatOrderedList(text: String): String
44 abstract fun formatListItem(text: String, kind: ListKind): String
45 abstract fun formatBreadcrumbs(items: Iterable<FormatLink>): String
46 abstract fun formatNonBreakingSpace(): String
47 open fun formatSoftLineBreak(): String = ""
48 open fun formatIndentedSoftLineBreak(): String = ""
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +040049
Dmitry Jemerov66593372015-03-03 19:35:56 +010050 open fun formatText(location: Location, nodes: Iterable<ContentNode>, listKind: ListKind = ListKind.Unordered): String {
Dmitry Jemerovb8f24352015-10-21 18:26:10 +020051 return nodes.map { formatText(location, it, listKind) }.joinToString("")
Ilya Ryzhenkov778e2b32014-09-29 20:54:59 +040052 }
53
Dmitry Jemerov66593372015-03-03 19:35:56 +010054 open fun formatText(location: Location, content: ContentNode, listKind: ListKind = ListKind.Unordered): String {
Dmitry Jemerovb8f24352015-10-21 18:26:10 +020055 return StringBuilder().apply {
Ilya Ryzhenkovd6fd0452014-10-03 20:20:02 +040056 when (content) {
Dmitry Jemerov8ef68182014-12-30 12:36:14 +010057 is ContentText -> append(formatText(content.text))
Ilya Ryzhenkovd6fd0452014-10-03 20:20:02 +040058 is ContentSymbol -> append(formatSymbol(content.text))
59 is ContentKeyword -> append(formatKeyword(content.text))
Dmitry Jemerov4494fd02015-02-26 21:34:27 +010060 is ContentIdentifier -> append(formatIdentifier(content.text, content.kind))
Dmitry Jemerov722c9af2015-02-26 16:28:05 +010061 is ContentNonBreakingSpace -> append(formatNonBreakingSpace())
Dmitry Jemerov8291bee2015-10-27 18:37:35 +010062 is ContentSoftLineBreak -> append(formatSoftLineBreak())
63 is ContentIndentedSoftLineBreak -> append(formatIndentedSoftLineBreak())
Dmitry Jemerov2e6eda92015-03-10 17:00:14 +010064 is ContentEntity -> append(formatEntity(content.text))
Ilya Ryzhenkov9f0ff552014-10-13 13:38:40 +040065 is ContentStrong -> append(formatStrong(formatText(location, content.children)))
Dmitry Jemerove17eaa52015-01-09 20:59:58 +010066 is ContentStrikethrough -> append(formatStrikethrough(formatText(location, content.children)))
Ilya Ryzhenkov9f0ff552014-10-13 13:38:40 +040067 is ContentCode -> append(formatCode(formatText(location, content.children)))
68 is ContentEmphasis -> append(formatEmphasis(formatText(location, content.children)))
Dmitry Jemerov66593372015-03-03 19:35:56 +010069 is ContentUnorderedList -> append(formatUnorderedList(formatText(location, content.children, ListKind.Unordered)))
70 is ContentOrderedList -> append(formatOrderedList(formatText(location, content.children, ListKind.Ordered)))
71 is ContentListItem -> append(formatListItem(formatText(location, content.children), listKind))
Ilya Ryzhenkov18399492014-12-22 09:50:17 +020072
Ilya Ryzhenkovd6fd0452014-10-03 20:20:02 +040073 is ContentNodeLink -> {
Dmitry Jemerov184a24c2015-02-25 19:03:51 +010074 val node = content.node
75 val linkTo = if (node != null) locationHref(location, node) else "#"
Ilya Ryzhenkovd6fd0452014-10-03 20:20:02 +040076 val linkText = formatText(location, content.children)
Dmitry Jemerov4b61be32015-02-26 21:17:13 +010077 if (linkTo == ".") {
78 append(linkText)
79 } else {
80 append(formatLink(linkText, linkTo))
81 }
Ilya Ryzhenkovd6fd0452014-10-03 20:20:02 +040082 }
Ilya Ryzhenkov71cd87e2014-10-03 22:51:44 +040083 is ContentExternalLink -> {
84 val linkText = formatText(location, content.children)
Dmitry Jemerov4b61be32015-02-26 21:17:13 +010085 if (content.href == ".") {
86 append(linkText)
87 } else {
88 append(formatLink(linkText, content.href))
89 }
Ilya Ryzhenkov71cd87e2014-10-03 22:51:44 +040090 }
Dmitry Jemerov76e4d3c2015-03-23 18:52:05 +010091 is ContentParagraph -> appendParagraph(this, formatText(location, content.children))
92 is ContentBlockCode -> appendBlockCode(this, formatText(location, content.children), content.language)
93 is ContentHeading -> appendHeader(this, formatText(location, content.children), content.level)
Dmitry Jemerov0d0fc1f2015-02-10 18:32:12 +010094 is ContentBlock -> append(formatText(location, content.children))
Ilya Ryzhenkov455d74a2014-09-19 22:25:27 +030095 }
96 }.toString()
97 }
98
Dmitry Jemerovf99ec732015-10-29 11:54:27 +010099 open fun link(from: DocumentationNode, to: DocumentationNode): FormatLink = link(from, to, extension)
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400100
Dmitry Jemerovf99ec732015-10-29 11:54:27 +0100101 open fun link(from: DocumentationNode, to: DocumentationNode, extension: String): FormatLink {
Dmitry Jemerovea1f4cc2015-02-19 19:51:01 +0100102 return FormatLink(to.name, locationService.relativePathToLocation(from, to))
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400103 }
104
Dmitry Jemerov85a3ae72015-02-20 14:08:30 +0100105 fun locationHref(from: Location, to: DocumentationNode): String {
106 val topLevelPage = to.references(DocumentationReference.Kind.TopLevelPage).singleOrNull()?.to
107 if (topLevelPage != null) {
108 return from.relativePathTo(locationService.location(topLevelPage), to.name)
109 }
110 return from.relativePathTo(locationService.location(to))
111 }
112
Dmitry Jemerove1a38842015-02-10 18:55:12 +0100113 fun appendDocumentation(location: Location, to: StringBuilder, overloads: Iterable<DocumentationNode>) {
114 val breakdownBySummary = overloads.groupByTo(LinkedHashMap()) { node -> node.content }
Dmitry Jemerovbfd9ffd2015-01-30 17:59:15 +0100115
Dmitry Jemerove1a38842015-02-10 18:55:12 +0100116 for ((summary, items) in breakdownBySummary) {
Dmitry Jemerovf99ec732015-10-29 11:54:27 +0100117 appendAsOverloadGroup(to) {
118 items.forEach {
119 val rendered = languageService.render(it)
120 appendAsSignature(to, rendered) {
121 to.append(formatCode(formatText(location, rendered)))
122 it.appendSourceLink(to)
123 }
124 it.appendOverrides(to)
125 it.appendDeprecation(location, to)
Dmitry Jemerovf90ee502015-02-26 13:55:37 +0100126 }
Dmitry Jemerovf99ec732015-10-29 11:54:27 +0100127 // All items have exactly the same documentation, so we can use any item to render it
128 val item = items.first()
129 item.details(DocumentationNode.Kind.OverloadGroupNote).forEach {
130 to.append(formatText(location, it.content))
131 }
132 to.append(formatText(location, item.content.summary))
133 appendDescription(location, to, item)
134 appendLine(to)
135 appendLine(to)
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400136 }
Dmitry Jemerove1a38842015-02-10 18:55:12 +0100137 }
138 }
139
Dmitry Jemerov76e4d3c2015-03-23 18:52:05 +0100140 private fun DocumentationNode.isModuleOrPackage(): Boolean =
141 kind == DocumentationNode.Kind.Module || kind == DocumentationNode.Kind.Package
142
Dmitry Jemerov8291bee2015-10-27 18:37:35 +0100143 protected open fun appendAsSignature(to: StringBuilder, node: ContentNode, block: () -> Unit) {
Dmitry Jemerovf90ee502015-02-26 13:55:37 +0100144 block()
145 }
146
Dmitry Jemerovf99ec732015-10-29 11:54:27 +0100147 protected open fun appendAsOverloadGroup(to: StringBuilder, block: () -> Unit) {
148 block()
149 }
150
Dmitry Jemerove1a38842015-02-10 18:55:12 +0100151 fun appendDescription(location: Location, to: StringBuilder, node: DocumentationNode) {
152 if (node.content.description != ContentEmpty) {
Dmitry Jemerove1a38842015-02-10 18:55:12 +0100153 appendLine(to, formatText(location, node.content.description))
154 appendLine(to)
155 }
156 node.content.getSectionsWithSubjects().forEach {
Dmitry Jemerovb8f24352015-10-21 18:26:10 +0200157 appendSectionWithSubject(it.key, location, it.value, to)
Dmitry Jemerove1a38842015-02-10 18:55:12 +0100158 }
159
160 for (section in node.content.sections.filter { it.subjectName == null }) {
161 appendLine(to, formatStrong(formatText(section.tag)))
162 appendLine(to, formatText(location, section))
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400163 }
164 }
165
Dmitry Jemerov0fac1d92015-01-30 19:01:40 +0100166 fun Content.getSectionsWithSubjects(): Map<String, List<ContentSection>> =
167 sections.filter { it.subjectName != null }.groupBy { it.tag }
168
169 fun appendSectionWithSubject(title: String, location: Location, subjectSections: List<ContentSection>, to: StringBuilder) {
Dmitry Jemerovbfd9ffd2015-01-30 17:59:15 +0100170 appendHeader(to, title, 3)
Dmitry Jemerov0fac1d92015-01-30 19:01:40 +0100171 subjectSections.forEach {
172 val subjectName = it.subjectName
173 if (subjectName != null) {
Dmitry Jemerov85a3ae72015-02-20 14:08:30 +0100174 appendAnchor(to, subjectName)
Dmitry Jemerov0fac1d92015-01-30 19:01:40 +0100175 to.append(formatCode(subjectName)).append(" - ")
176 to.append(formatText(location, it))
Dmitry Jemerovbfd9ffd2015-01-30 17:59:15 +0100177 appendLine(to)
178 }
179 }
Dmitry Jemerovc43a4372014-12-29 20:22:43 +0100180 }
181
Dmitry Jemerov0dd5ea32015-01-14 13:30:43 +0100182 private fun DocumentationNode.appendOverrides(to: StringBuilder) {
183 overrides.forEach {
184 to.append("Overrides ")
Dmitry Jemerovea1f4cc2015-02-19 19:51:01 +0100185 val location = locationService.relativePathToLocation(this, it)
Dmitry Jemerov0dd5ea32015-01-14 13:30:43 +0100186 appendLine(to, formatLink(FormatLink(it.owner!!.name + "." + it.name, location)))
187 }
188 }
189
Dmitry Jemerova60d8ba2015-02-24 16:24:00 +0100190 private fun DocumentationNode.appendDeprecation(location: Location, to: StringBuilder) {
Dmitry Jemerov0dd5ea32015-01-14 13:30:43 +0100191 if (deprecation != null) {
192 val deprecationParameter = deprecation!!.details(DocumentationNode.Kind.Parameter).firstOrNull()
193 val deprecationValue = deprecationParameter?.details(DocumentationNode.Kind.Value)?.firstOrNull()
194 if (deprecationValue != null) {
Dmitry Jemerov7003ad82015-02-26 13:20:41 +0100195 to.append(formatStrong("Deprecated:")).append(" ")
Dmitry Jemerov64414ce2015-05-29 13:52:43 +0200196 appendLine(to, formatText(deprecationValue.name.removeSurrounding("\"")))
Dmitry Jemerovf7c2f2a2015-02-26 19:45:36 +0100197 appendLine(to)
Dmitry Jemerova60d8ba2015-02-24 16:24:00 +0100198 } else if (deprecation?.content != Content.Empty) {
Dmitry Jemerov7003ad82015-02-26 13:20:41 +0100199 to.append(formatStrong("Deprecated:")).append(" ")
Dmitry Jemerova60d8ba2015-02-24 16:24:00 +0100200 to.append(formatText(location, deprecation!!.content))
Dmitry Jemerov0dd5ea32015-01-14 13:30:43 +0100201 } else {
202 appendLine(to, formatStrong("Deprecated"))
Dmitry Jemerovf7c2f2a2015-02-26 19:45:36 +0100203 appendLine(to)
Dmitry Jemerov0dd5ea32015-01-14 13:30:43 +0100204 }
205 }
206 }
207
Dmitry Jemerov6146fa82015-01-14 18:46:36 +0100208 private fun DocumentationNode.appendSourceLink(to: StringBuilder) {
209 val sourceUrl = details(DocumentationNode.Kind.SourceUrl).firstOrNull()
210 if (sourceUrl != null) {
Dmitry Jemerovebbf2652015-02-10 19:35:27 +0100211 to.append(" ")
212 appendLine(to, formatLink("(source)", sourceUrl.name))
213 } else {
214 appendLine(to)
Dmitry Jemerov6146fa82015-01-14 18:46:36 +0100215 }
216 }
217
Ilya Ryzhenkovd6fd0452014-10-03 20:20:02 +0400218 fun appendLocation(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
Dmitry Jemerov76e4d3c2015-03-23 18:52:05 +0100219 val singleNode = nodes.singleOrNull()
220 if (singleNode != null && singleNode.isModuleOrPackage()) {
221 if (singleNode.kind == DocumentationNode.Kind.Package) {
222 appendHeader(to, "Package " + formatText(singleNode.name), 2)
223 }
224 to.append(formatText(location, singleNode.content))
225 } else {
226 val breakdownByName = nodes.groupBy { node -> node.name }
227 for ((name, items) in breakdownByName) {
228 appendHeader(to, formatText(name))
229 appendDocumentation(location, to, items)
230 }
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400231 }
232 }
233
Dmitry Jemerov3faa3f22015-10-27 17:12:31 +0100234 private fun appendSection(location: Location, caption: String, nodes: List<DocumentationNode>, node: DocumentationNode, to: StringBuilder) {
Ilya Ryzhenkova52e1d52014-10-03 15:57:16 +0400235 if (nodes.any()) {
236 appendHeader(to, caption, 3)
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400237
Dmitry Jemerov97257372015-09-07 20:57:17 +0200238 val children = nodes.sortedBy { it.name }
Ilya Ryzhenkova52e1d52014-10-03 15:57:16 +0400239 val membersMap = children.groupBy { link(node, it) }
Ilya Ryzhenkovaa59acb2014-07-15 20:05:55 +0400240
Ilya Ryzhenkova52e1d52014-10-03 15:57:16 +0400241 appendTable(to) {
242 appendTableBody(to) {
Ilya Ryzhenkovd6fd0452014-10-03 20:20:02 +0400243 for ((memberLocation, members) in membersMap) {
Ilya Ryzhenkova52e1d52014-10-03 15:57:16 +0400244 appendTableRow(to) {
245 appendTableCell(to) {
Dmitry Jemerov8ef68182014-12-30 12:36:14 +0100246 to.append(formatLink(memberLocation))
Ilya Ryzhenkova52e1d52014-10-03 15:57:16 +0400247 }
248 appendTableCell(to) {
Ilya Ryzhenkov280dc292014-10-14 16:08:10 +0400249 val breakdownBySummary = members.groupBy { formatText(location, it.summary) }
Ilya Ryzhenkova52e1d52014-10-03 15:57:16 +0400250 for ((summary, items) in breakdownBySummary) {
Dmitry Jemerov3faa3f22015-10-27 17:12:31 +0100251 appendSummarySignatures(items, location, to)
Ilya Ryzhenkova52e1d52014-10-03 15:57:16 +0400252 if (!summary.isEmpty()) {
Dmitry Jemerov8ef68182014-12-30 12:36:14 +0100253 to.append(summary)
Ilya Ryzhenkovaa59acb2014-07-15 20:05:55 +0400254 }
255 }
256 }
Ilya Ryzhenkove8447fd2014-07-15 16:37:50 +0400257 }
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400258 }
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400259 }
260 }
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400261 }
262 }
263
Dmitry Jemerov3faa3f22015-10-27 17:12:31 +0100264 private fun appendSummarySignatures(items: List<DocumentationNode>, location: Location, to: StringBuilder) {
265 val summarySignature = languageService.summarizeSignatures(items)
266 if (summarySignature != null) {
Dmitry Jemerov0efda362015-10-28 11:38:40 +0100267 appendAsSignature(to, summarySignature) {
268 appendLine(to, summarySignature.signatureToText(location))
Dmitry Jemerov3faa3f22015-10-27 17:12:31 +0100269 }
270 return
271 }
Dmitry Jemerov8291bee2015-10-27 18:37:35 +0100272 val renderedSignatures = items.map { languageService.render(it, RenderMode.SUMMARY) }
273 renderedSignatures.subList(0, renderedSignatures.size - 1).forEach {
274 appendAsSignature(to, it) {
275 appendLine(to, it.signatureToText(location))
Dmitry Jemerov3faa3f22015-10-27 17:12:31 +0100276 }
277 }
Dmitry Jemerov8291bee2015-10-27 18:37:35 +0100278 appendAsSignature(to, renderedSignatures.last()) {
279 to.append(renderedSignatures.last().signatureToText(location))
Dmitry Jemerov3faa3f22015-10-27 17:12:31 +0100280 }
Dmitry Jemerov8291bee2015-10-27 18:37:35 +0100281 }
282
283 private fun ContentNode.signatureToText(location: Location): String {
284 return if (this is ContentBlock && this.isEmpty()) {
285 ""
286 } else {
287 val signatureAsCode = ContentCode()
288 signatureAsCode.append(this)
289 formatText(location, signatureAsCode)
Dmitry Jemerov3faa3f22015-10-27 17:12:31 +0100290 }
291 }
292
Ilya Ryzhenkovd6fd0452014-10-03 20:20:02 +0400293 override fun appendNodes(location: Location, to: StringBuilder, nodes: Iterable<DocumentationNode>) {
294 val breakdownByLocation = nodes.groupBy { node ->
Dmitry Jemerovd9bfa022015-02-19 18:59:00 +0100295 formatBreadcrumbs(node.path.filterNot { it.name.isEmpty() }.map { link(node, it) })
Ilya Ryzhenkovd6fd0452014-10-03 20:20:02 +0400296 }
297
298 for ((breadcrumbs, items) in breakdownByLocation) {
299 appendLine(to, breadcrumbs)
300 appendLine(to)
Dmitry Jemerov4b0dcee2015-01-09 19:48:44 +0100301 appendLocation(location, to, items.filter { it.kind != DocumentationNode.Kind.ExternalClass })
Ilya Ryzhenkovd6fd0452014-10-03 20:20:02 +0400302 }
303
304 for (node in nodes) {
Dmitry Jemerov4b0dcee2015-01-09 19:48:44 +0100305 if (node.kind == DocumentationNode.Kind.ExternalClass) {
306 appendSection(location, "Extensions for ${node.name}", node.members, node, to)
307 continue
308 }
309
Ilya Ryzhenkov49077362014-10-14 19:53:13 +0400310 appendSection(location, "Packages", node.members(DocumentationNode.Kind.Package), node, to)
311 appendSection(location, "Types", node.members.filter {
312 it.kind in setOf(
313 DocumentationNode.Kind.Class,
314 DocumentationNode.Kind.Interface,
315 DocumentationNode.Kind.Enum,
Dmitry Jemerov716483c2014-12-30 17:41:14 +0100316 DocumentationNode.Kind.Object,
317 DocumentationNode.Kind.AnnotationClass)
Ilya Ryzhenkov49077362014-10-14 19:53:13 +0400318 }, node, to)
Dmitry Jemerov4b0dcee2015-01-09 19:48:44 +0100319 appendSection(location, "Extensions for External Classes", node.members(DocumentationNode.Kind.ExternalClass), node, to)
Dmitry Jemerovc81053d2015-10-28 17:34:44 +0100320 appendSection(location, "Enum Values", node.members(DocumentationNode.Kind.EnumItem), node, to)
Ilya Ryzhenkov49077362014-10-14 19:53:13 +0400321 appendSection(location, "Constructors", node.members(DocumentationNode.Kind.Constructor), node, to)
322 appendSection(location, "Properties", node.members(DocumentationNode.Kind.Property), node, to)
Dmitry Jemerov36f4b912015-10-28 15:23:50 +0100323 appendSection(location, "Inherited Properties", node.inheritedMembers(DocumentationNode.Kind.Property), node, to)
Ilya Ryzhenkov49077362014-10-14 19:53:13 +0400324 appendSection(location, "Functions", node.members(DocumentationNode.Kind.Function), node, to)
Dmitry Jemerov36f4b912015-10-28 15:23:50 +0100325 appendSection(location, "Inherited Functions", node.inheritedMembers(DocumentationNode.Kind.Function), node, to)
Dmitry Jemerovc7916f72015-03-17 19:54:11 +0100326 appendSection(location, "Companion Object Properties", node.members(DocumentationNode.Kind.CompanionObjectProperty), node, to)
327 appendSection(location, "Companion Object Functions", node.members(DocumentationNode.Kind.CompanionObjectFunction), node, to)
Ilya Ryzhenkov49077362014-10-14 19:53:13 +0400328 appendSection(location, "Other members", node.members.filter {
329 it.kind !in setOf(
330 DocumentationNode.Kind.Class,
331 DocumentationNode.Kind.Interface,
Dmitry Jemerov716483c2014-12-30 17:41:14 +0100332 DocumentationNode.Kind.Enum,
Ilya Ryzhenkov49077362014-10-14 19:53:13 +0400333 DocumentationNode.Kind.Object,
Dmitry Jemerov716483c2014-12-30 17:41:14 +0100334 DocumentationNode.Kind.AnnotationClass,
Ilya Ryzhenkov49077362014-10-14 19:53:13 +0400335 DocumentationNode.Kind.Constructor,
336 DocumentationNode.Kind.Property,
337 DocumentationNode.Kind.Package,
338 DocumentationNode.Kind.Function,
Dmitry Jemerovc7916f72015-03-17 19:54:11 +0100339 DocumentationNode.Kind.CompanionObjectProperty,
340 DocumentationNode.Kind.CompanionObjectFunction,
Dmitry Jemerovc4f40a02015-01-12 16:32:30 +0100341 DocumentationNode.Kind.ExternalClass,
342 DocumentationNode.Kind.EnumItem
Ilya Ryzhenkov49077362014-10-14 19:53:13 +0400343 )
344 }, node, to)
Dmitry Jemerovd1177b32015-10-28 17:28:38 +0100345
346 val allExtensions = collectAllExtensions(node)
347 appendSection(location, "Extension Properties", allExtensions.filter { it.kind == DocumentationNode.Kind.Property }, node, to)
348 appendSection(location, "Extension Functions", allExtensions.filter { it.kind == DocumentationNode.Kind.Function }, node, to)
349 appendSection(location, "Companion Object Extension Properties", allExtensions.filter { it.kind == DocumentationNode.Kind.CompanionObjectProperty }, node, to)
350 appendSection(location, "Companion Object Extension Functions", allExtensions.filter { it.kind == DocumentationNode.Kind.CompanionObjectFunction }, node, to)
Dmitry Jemerovc4f40a02015-01-12 16:32:30 +0100351 appendSection(location, "Inheritors",
352 node.inheritors.filter { it.kind != DocumentationNode.Kind.EnumItem }, node, to)
Ilya Ryzhenkovd6fd0452014-10-03 20:20:02 +0400353 appendSection(location, "Links", node.links, node, to)
354
355 }
356 }
Dmitry Jemerovd1177b32015-10-28 17:28:38 +0100357
358 private fun collectAllExtensions(node: DocumentationNode): Collection<DocumentationNode> {
359 val result = LinkedHashSet<DocumentationNode>()
360 val visited = hashSetOf<DocumentationNode>()
361
362 fun collect(node: DocumentationNode) {
363 if (!visited.add(node)) return
364 result.addAll(node.extensions)
365 node.references(DocumentationReference.Kind.Superclass).forEach { collect(it.to) }
366 }
367
368 collect(node)
369
370 return result
371
372 }
Ilya Ryzhenkov62cb5092014-07-15 15:54:05 +0400373}