blob: 958488efa6a6b79f821d022ebbbb550549a29eea (
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
|
package org.jetbrains.dokka.base.renderers.html
import org.jetbrains.dokka.base.renderers.sourceSets
import org.jetbrains.dokka.base.transformers.documentables.isException
import org.jetbrains.dokka.base.translators.documentables.DocumentableLanguage
import org.jetbrains.dokka.base.translators.documentables.documentableLanguage
import org.jetbrains.dokka.model.*
import org.jetbrains.dokka.pages.*
abstract class NavigationDataProvider {
open fun navigableChildren(input: RootPageNode): NavigationNode = input.withDescendants()
.first { it is ModulePage || it is MultimoduleRootPage }.let { visit(it as ContentPage) }
open fun visit(page: ContentPage): NavigationNode =
NavigationNode(
name = page.displayableName(),
dri = page.dri.first(),
sourceSets = page.sourceSets(),
icon = chooseNavigationIcon(page),
children = page.navigableChildren()
)
/**
* Parenthesis is applied in 1 case:
* - page only contains functions (therefore documentable from this page is [DFunction])
*/
private fun ContentPage.displayableName(): String =
if (this is WithDocumentables && documentables.all { it is DFunction }) {
"$name()"
} else {
name
}
private fun chooseNavigationIcon(contentPage: ContentPage): NavigationNodeIcon? {
return if (contentPage is WithDocumentables) {
val documentable = contentPage.documentables.firstOrNull()
val isJava = documentable?.hasAnyJavaSources() ?: false
when (documentable) {
is DClass -> when {
documentable.isException -> NavigationNodeIcon.EXCEPTION
documentable.isAbstract() -> {
if (isJava) NavigationNodeIcon.ABSTRACT_CLASS else NavigationNodeIcon.ABSTRACT_CLASS_KT
}
else -> if (isJava) NavigationNodeIcon.CLASS else NavigationNodeIcon.CLASS_KT
}
is DFunction -> NavigationNodeIcon.FUNCTION
is DProperty -> {
val isVar = documentable.extra[IsVar] != null
if (isVar) NavigationNodeIcon.VAR else NavigationNodeIcon.VAL
}
is DInterface -> if (isJava) NavigationNodeIcon.INTERFACE else NavigationNodeIcon.INTERFACE_KT
is DEnum,
is DEnumEntry -> if (isJava) NavigationNodeIcon.ENUM_CLASS else NavigationNodeIcon.ENUM_CLASS_KT
is DAnnotation -> {
if (isJava) NavigationNodeIcon.ANNOTATION_CLASS else NavigationNodeIcon.ANNOTATION_CLASS_KT
}
is DObject -> NavigationNodeIcon.OBJECT
else -> null
}
} else {
null
}
}
private fun Documentable.hasAnyJavaSources(): Boolean {
val withSources = this as? WithSources ?: return false
return this.sourceSets.any { withSources.documentableLanguage(it) == DocumentableLanguage.JAVA }
}
private fun DClass.isAbstract(): Boolean {
return modifier.values.all { it is KotlinModifier.Abstract || it is JavaModifier.Abstract }
}
private fun ContentPage.navigableChildren(): List<NavigationNode> {
return if (this is ClasslikePage) {
return this.navigableChildren()
} else {
children
.filterIsInstance<ContentPage>()
.map { visit(it) }
.sortedBy { it.name.toLowerCase() }
}
}
private fun ClasslikePage.navigableChildren(): List<NavigationNode> {
// Classlikes should only have other classlikes as navigable children
val navigableChildren = children
.filterIsInstance<ClasslikePage>()
.map { visit(it) }
val isEnumPage = documentables.any { it is DEnum }
return if (isEnumPage) {
// no sorting for enum entries, should be the same order as in source code
navigableChildren
} else {
navigableChildren.sortedBy { it.name.toLowerCase() }
}
}
}
|