<lambda>null1 package org.jetbrains.dokka
2
3 import java.util.*
4
5 enum class NodeKind {
6 Unknown,
7
8 Package,
9 Class,
10 Interface,
11 Enum,
12 AnnotationClass,
13 Exception,
14 EnumItem,
15 Object,
16 TypeAlias,
17
18 Constructor,
19 Function,
20 Property,
21 Field,
22
23 CompanionObjectProperty,
24 CompanionObjectFunction,
25
26 Parameter,
27 Receiver,
28 TypeParameter,
29 Type,
30 Supertype,
31 UpperBound,
32 LowerBound,
33
34 TypeAliasUnderlyingType,
35
36 Modifier,
37 NullabilityModifier,
38
39 Module,
40
41 ExternalClass,
42 Annotation,
43
44 Value,
45
46 SourceUrl,
47 SourcePosition,
48 Signature,
49
50 ExternalLink,
51 QualifiedName,
52 Platform,
53
54 AllTypes,
55
56 /**
57 * A note which is rendered once on a page documenting a group of overloaded functions.
58 * Needs to be generated equally on all overloads.
59 */
60 OverloadGroupNote,
61
62 Attribute,
63
64 AttributeRef,
65
66 ApiLevel,
67
68 DeprecatedLevel,
69
70 ArtifactId,
71
72 GroupNode;
73
74 companion object {
75 val classLike = setOf(Class, Interface, Enum, AnnotationClass, Exception, Object, TypeAlias)
76 val memberLike = setOf(Function, Property, Field, Constructor, CompanionObjectFunction, CompanionObjectProperty, EnumItem, Attribute)
77 }
78 }
79
80 open class DocumentationNode(val name: String,
81 content: Content,
82 val kind: NodeKind) {
83
84 private val references = LinkedHashSet<DocumentationReference>()
85
86 var content: Content = content
87 private set
88
89 val summary: ContentNode get() = content.summary
90
91 val owner: DocumentationNode?
92 get() = references(RefKind.Owner).singleOrNull()?.to
93 val details: List<DocumentationNode>
<lambda>null94 get() = references(RefKind.Detail).map { it.to }
95 val members: List<DocumentationNode>
<lambda>null96 get() = references(RefKind.Member).map { it.to }.sortedBy { it.name }
97 val inheritedMembers: List<DocumentationNode>
<lambda>null98 get() = references(RefKind.InheritedMember).map { it.to }
99 val allInheritedMembers: List<DocumentationNode>
<lambda>null100 get() = recursiveInheritedMembers().sortedBy { it.name }
101 val inheritedCompanionObjectMembers: List<DocumentationNode>
<lambda>null102 get() = references(RefKind.InheritedCompanionObjectMember).map { it.to }
103 val extensions: List<DocumentationNode>
<lambda>null104 get() = references(RefKind.Extension).map { it.to }
105 val inheritors: List<DocumentationNode>
<lambda>null106 get() = references(RefKind.Inheritor).map { it.to }
107 val overrides: List<DocumentationNode>
<lambda>null108 get() = references(RefKind.Override).map { it.to }
109 val links: List<DocumentationNode>
<lambda>null110 get() = references(RefKind.Link).map { it.to }
111 val hiddenLinks: List<DocumentationNode>
<lambda>null112 get() = references(RefKind.HiddenLink).map { it.to }
113 val annotations: List<DocumentationNode>
<lambda>null114 get() = references(RefKind.Annotation).map { it.to }
115 val deprecation: DocumentationNode?
<lambda>null116 get() = references(RefKind.Deprecation).map { it.to }.firstOrNull()
117 val platforms: List<String>
<lambda>null118 get() = references(RefKind.Platform).map { it.to.name }
119 val externalType: DocumentationNode?
<lambda>null120 get() = references(RefKind.ExternalType).map { it.to }.firstOrNull()
121 val apiLevel: DocumentationNode
122 get() = detailOrNull(NodeKind.ApiLevel) ?: DocumentationNode("", Content.Empty, NodeKind.ApiLevel)
123 val deprecatedLevel: DocumentationNode
124 get() = detailOrNull(NodeKind.DeprecatedLevel) ?: DocumentationNode("", Content.Empty, NodeKind.DeprecatedLevel)
125 val artifactId: DocumentationNode
126 get() = detailOrNull(NodeKind.ArtifactId) ?: DocumentationNode("", Content.Empty, NodeKind.ArtifactId)
127 val attributes: List<DocumentationNode>
<lambda>null128 get() = details(NodeKind.Attribute).sortedBy { it.attributeRef!!.name }
129 val attributeRef: DocumentationNode?
<lambda>null130 get() = references(RefKind.AttributeRef).map { it.to }.firstOrNull()
131 val relatedAttributes: List<DocumentationNode>
132 get() = hiddenLinks(NodeKind.Attribute)
133 val supertypes: List<DocumentationNode>
134 get() = details(NodeKind.Supertype)
135 val signatureName = detailOrNull(NodeKind.Signature)?.name
136
137 val superclassType: DocumentationNode?
138 get() = when (kind) {
139 NodeKind.Supertype -> {
<lambda>null140 (links + listOfNotNull(externalType)).firstOrNull { it.kind in NodeKind.classLike }?.superclassType
141 }
142 NodeKind.Interface -> null
<lambda>null143 in NodeKind.classLike -> supertypes.firstOrNull {
144 (it.links + listOfNotNull(it.externalType)).any { it.isSuperclassFor(this) }
145 }
146 else -> null
147 }
148
149 val superclassTypeSequence: Sequence<DocumentationNode>
<lambda>null150 get() = generateSequence(superclassType) {
151 it.superclassType
152 }
153
154 // TODO: Should we allow node mutation? Model merge will copy by ref, so references are transparent, which could nice
addReferenceTonull155 fun addReferenceTo(to: DocumentationNode, kind: RefKind) {
156 references.add(DocumentationReference(this, to, kind))
157 }
158
dropReferencesnull159 fun dropReferences(predicate: (DocumentationReference) -> Boolean) {
160 references.removeAll(predicate)
161 }
162
addAllReferencesFromnull163 fun addAllReferencesFrom(other: DocumentationNode) {
164 references.addAll(other.references)
165 }
166
updateContentnull167 fun updateContent(body: MutableContent.() -> Unit) {
168 if (content !is MutableContent) {
169 content = MutableContent()
170 }
171 (content as MutableContent).body()
172 }
<lambda>null173 fun details(kind: NodeKind): List<DocumentationNode> = details.filter { it.kind == kind }
<lambda>null174 fun members(kind: NodeKind): List<DocumentationNode> = members.filter { it.kind == kind }
<lambda>null175 fun hiddenLinks(kind: NodeKind): List<DocumentationNode> = hiddenLinks.filter { it.kind == kind }
<lambda>null176 fun inheritedMembers(kind: NodeKind): List<DocumentationNode> = inheritedMembers.filter { it.kind == kind }
<lambda>null177 fun inheritedCompanionObjectMembers(kind: NodeKind): List<DocumentationNode> = inheritedCompanionObjectMembers.filter { it.kind == kind }
<lambda>null178 fun links(kind: NodeKind): List<DocumentationNode> = links.filter { it.kind == kind }
179
<lambda>null180 fun detail(kind: NodeKind): DocumentationNode = details.filter { it.kind == kind }.single()
detailOrNullnull181 fun detailOrNull(kind: NodeKind): DocumentationNode? = details.filter { it.kind == kind }.singleOrNull()
<lambda>null182 fun member(kind: NodeKind): DocumentationNode = members.filter { it.kind == kind }.single()
<lambda>null183 fun link(kind: NodeKind): DocumentationNode = links.filter { it.kind == kind }.single()
184
<lambda>null185 fun references(kind: RefKind): List<DocumentationReference> = references.filter { it.kind == kind }
allReferencesnull186 fun allReferences(): Set<DocumentationReference> = references
187
188 override fun toString(): String {
189 return "$kind:$name"
190 }
191 }
192
193 class DocumentationModule(name: String, content: Content = Content.Empty)
194 : DocumentationNode(name, content, NodeKind.Module) {
195 val nodeRefGraph = NodeReferenceGraph()
196 }
197
198 val DocumentationNode.path: List<DocumentationNode>
199 get() {
200 val parent = owner ?: return listOf(this)
201 return parent.path + this
202 }
203
findOrCreatePackageNodenull204 fun findOrCreatePackageNode(module: DocumentationNode?, packageName: String, packageContent: Map<String, Content>, refGraph: NodeReferenceGraph): DocumentationNode {
205 val existingNode = refGraph.lookup(packageName)
206 if (existingNode != null) {
207 return existingNode
208 }
209 val newNode = DocumentationNode(packageName,
210 packageContent.getOrElse(packageName) { Content.Empty },
211 NodeKind.Package)
212
213 refGraph.register(packageName, newNode)
214 module?.append(newNode, RefKind.Member)
215 return newNode
216 }
217
appendnull218 fun DocumentationNode.append(child: DocumentationNode, kind: RefKind) {
219 addReferenceTo(child, kind)
220 when (kind) {
221 RefKind.Detail -> child.addReferenceTo(this, RefKind.Owner)
222 RefKind.Member -> child.addReferenceTo(this, RefKind.Owner)
223 RefKind.Owner -> child.addReferenceTo(this, RefKind.Member)
224 else -> { /* Do not add any links back for other types */
225 }
226 }
227 }
228
appendTextNodenull229 fun DocumentationNode.appendTextNode(text: String,
230 kind: NodeKind,
231 refKind: RefKind = RefKind.Detail) {
232 append(DocumentationNode(text, Content.Empty, kind), refKind)
233 }
234
qualifiedNamenull235 fun DocumentationNode.qualifiedName(): String {
236 if (kind == NodeKind.Type) {
237 return qualifiedNameFromType()
238 } else if (kind == NodeKind.Package) {
239 return name
240 }
241 return path.drop(1).map { it.name }.filter { it.length > 0 }.joinToString(".")
242 }
243
simpleNamenull244 fun DocumentationNode.simpleName() = name.substringAfterLast('.')
245
246 private fun DocumentationNode.recursiveInheritedMembers(): List<DocumentationNode> {
247 val allInheritedMembers = mutableListOf<DocumentationNode>()
248 recursiveInheritedMembers(allInheritedMembers)
249 return allInheritedMembers
250 }
251
recursiveInheritedMembersnull252 private fun DocumentationNode.recursiveInheritedMembers(allInheritedMembers: MutableList<DocumentationNode>) {
253 allInheritedMembers.addAll(inheritedMembers)
254 inheritedMembers.groupBy { it.owner!! } .forEach { (node, _) ->
255 node.recursiveInheritedMembers(allInheritedMembers)
256 }
257 }
258
isSuperclassFornull259 private fun DocumentationNode.isSuperclassFor(node: DocumentationNode): Boolean {
260 return when(node.kind) {
261 NodeKind.Object, NodeKind.Class, NodeKind.Enum -> kind == NodeKind.Class
262 NodeKind.Exception -> kind == NodeKind.Class || kind == NodeKind.Exception
263 else -> false
264 }
265 }
266
classNodeNameWithOuterClassnull267 fun DocumentationNode.classNodeNameWithOuterClass(): String {
268 assert(kind in NodeKind.classLike)
269 return path.dropWhile { it.kind == NodeKind.Package || it.kind == NodeKind.Module }.joinToString(separator = ".") { it.name }
270 }
271
deprecatedLevelMessagenull272 fun DocumentationNode.deprecatedLevelMessage(): String {
273 val kindName = when(kind) {
274 NodeKind.Enum -> "enum"
275 NodeKind.Interface -> "interface"
276 NodeKind.AnnotationClass -> "annotation"
277 NodeKind.Exception -> "exception"
278 else -> "class"
279 }
280 return "This $kindName was deprecated in API level ${deprecatedLevel.name}."
281 }
282