• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<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 prettyName : String
138         get() = when(kind) {
139             NodeKind.Constructor -> owner!!.name
140             else -> name
141         }
142 
143     val superclassType: DocumentationNode?
144         get() = when (kind) {
145             NodeKind.Supertype -> {
<lambda>null146                 (links + listOfNotNull(externalType)).firstOrNull { it.kind in NodeKind.classLike }?.superclassType
147             }
148             NodeKind.Interface -> null
<lambda>null149             in NodeKind.classLike -> supertypes.firstOrNull {
150                 (it.links + listOfNotNull(it.externalType)).any { it.isSuperclassFor(this) }
151             }
152             else -> null
153         }
154 
155     val superclassTypeSequence: Sequence<DocumentationNode>
<lambda>null156         get() = generateSequence(superclassType) {
157             it.superclassType
158         }
159 
160     // TODO: Should we allow node mutation? Model merge will copy by ref, so references are transparent, which could nice
addReferenceTonull161     fun addReferenceTo(to: DocumentationNode, kind: RefKind) {
162         references.add(DocumentationReference(this, to, kind))
163     }
164 
dropReferencesnull165     fun dropReferences(predicate: (DocumentationReference) -> Boolean) {
166         references.removeAll(predicate)
167     }
168 
addAllReferencesFromnull169     fun addAllReferencesFrom(other: DocumentationNode) {
170         references.addAll(other.references)
171     }
172 
updateContentnull173     fun updateContent(body: MutableContent.() -> Unit) {
174         if (content !is MutableContent) {
175             content = MutableContent()
176         }
177         (content as MutableContent).body()
178     }
<lambda>null179     fun details(kind: NodeKind): List<DocumentationNode> = details.filter { it.kind == kind }
<lambda>null180     fun members(kind: NodeKind): List<DocumentationNode> = members.filter { it.kind == kind }
<lambda>null181     fun hiddenLinks(kind: NodeKind): List<DocumentationNode> = hiddenLinks.filter { it.kind == kind }
<lambda>null182     fun inheritedMembers(kind: NodeKind): List<DocumentationNode> = inheritedMembers.filter { it.kind == kind }
<lambda>null183     fun inheritedCompanionObjectMembers(kind: NodeKind): List<DocumentationNode> = inheritedCompanionObjectMembers.filter { it.kind == kind }
<lambda>null184     fun links(kind: NodeKind): List<DocumentationNode> = links.filter { it.kind == kind }
185 
<lambda>null186     fun detail(kind: NodeKind): DocumentationNode = details.filter { it.kind == kind }.single()
detailOrNullnull187     fun detailOrNull(kind: NodeKind): DocumentationNode? = details.filter { it.kind == kind }.singleOrNull()
<lambda>null188     fun member(kind: NodeKind): DocumentationNode = members.filter { it.kind == kind }.single()
<lambda>null189     fun link(kind: NodeKind): DocumentationNode = links.filter { it.kind == kind }.single()
190 
<lambda>null191     fun references(kind: RefKind): List<DocumentationReference> = references.filter { it.kind == kind }
allReferencesnull192     fun allReferences(): Set<DocumentationReference> = references
193 
194     override fun toString(): String {
195         return "$kind:$name"
196     }
197 }
198 
199 class DocumentationModule(name: String, content: Content = Content.Empty)
200     : DocumentationNode(name, content, NodeKind.Module) {
201     val nodeRefGraph = NodeReferenceGraph()
202 }
203 
204 val DocumentationNode.path: List<DocumentationNode>
205     get() {
206         val parent = owner ?: return listOf(this)
207         return parent.path + this
208     }
209 
findOrCreatePackageNodenull210 fun findOrCreatePackageNode(module: DocumentationNode?, packageName: String, packageContent: Map<String, Content>, refGraph: NodeReferenceGraph): DocumentationNode {
211     val existingNode = refGraph.lookup(packageName)
212     if (existingNode != null) {
213         return existingNode
214     }
215     val newNode = DocumentationNode(packageName,
216             packageContent.getOrElse(packageName) { Content.Empty },
217             NodeKind.Package)
218 
219     refGraph.register(packageName, newNode)
220     module?.append(newNode, RefKind.Member)
221     return newNode
222 }
223 
appendnull224 fun DocumentationNode.append(child: DocumentationNode, kind: RefKind) {
225     addReferenceTo(child, kind)
226     when (kind) {
227         RefKind.Detail -> child.addReferenceTo(this, RefKind.Owner)
228         RefKind.Member -> child.addReferenceTo(this, RefKind.Owner)
229         RefKind.Owner -> child.addReferenceTo(this, RefKind.Member)
230         else -> { /* Do not add any links back for other types */
231         }
232     }
233 }
234 
appendTextNodenull235 fun DocumentationNode.appendTextNode(text: String,
236                                      kind: NodeKind,
237                                      refKind: RefKind = RefKind.Detail) {
238     append(DocumentationNode(text, Content.Empty, kind), refKind)
239 }
240 
qualifiedNamenull241 fun DocumentationNode.qualifiedName(): String {
242     if (kind == NodeKind.Type) {
243         return qualifiedNameFromType()
244     } else if (kind == NodeKind.Package) {
245         return name
246     }
247     return path.drop(1).map { it.name }.filter { it.length > 0 }.joinToString(".")
248 }
249 
simpleNamenull250 fun DocumentationNode.simpleName() = name.substringAfterLast('.')
251 
252 private fun DocumentationNode.recursiveInheritedMembers(): List<DocumentationNode> {
253     val allInheritedMembers = mutableListOf<DocumentationNode>()
254     recursiveInheritedMembers(allInheritedMembers)
255     return allInheritedMembers
256 }
257 
recursiveInheritedMembersnull258 private fun DocumentationNode.recursiveInheritedMembers(allInheritedMembers: MutableList<DocumentationNode>) {
259     allInheritedMembers.addAll(inheritedMembers)
260     inheritedMembers.groupBy { it.owner!! } .forEach { (node, _) ->
261         node.recursiveInheritedMembers(allInheritedMembers)
262     }
263 }
264 
isSuperclassFornull265 private fun DocumentationNode.isSuperclassFor(node: DocumentationNode): Boolean {
266     return when(node.kind) {
267         NodeKind.Object, NodeKind.Class, NodeKind.Enum -> kind == NodeKind.Class
268         NodeKind.Exception -> kind == NodeKind.Class || kind == NodeKind.Exception
269         else -> false
270     }
271 }
272 
classNodeNameWithOuterClassnull273 fun DocumentationNode.classNodeNameWithOuterClass(): String {
274     assert(kind in NodeKind.classLike)
275     return path.dropWhile { it.kind !in NodeKind.classLike }.joinToString(separator = ".") { it.name }
276 }
277 
deprecatedLevelMessagenull278 fun DocumentationNode.deprecatedLevelMessage(): String {
279     val kindName = when(kind) {
280         NodeKind.Enum -> "enum"
281         NodeKind.Interface -> "interface"
282         NodeKind.AnnotationClass -> "annotation"
283         NodeKind.Exception -> "exception"
284         else -> "class"
285     }
286     return "This $kindName was deprecated in API level ${deprecatedLevel.name}."
287 }
288 
convertDeprecationDetailsToChildrennull289 fun DocumentationNode.convertDeprecationDetailsToChildren() {
290     val toProcess = details.toMutableList()
291     while (!toProcess.isEmpty()) {
292         var child = toProcess.removeAt(0)
293         if (child.details.isEmpty() && child.name != "") {
294             updateContent { text(child.name.cleanForAppending()) }
295         }
296         else toProcess.addAll(0, child.details)
297     }
298 }
299 
300    /*
301     * Removes extraneous quotation marks and adds a ". " to make appending children readable.
302     */
Stringnull303 fun String.cleanForAppending(): String {
304     var result = this
305     if (this.first() == this.last() && this.first() == '"') result = result.substring(1, result.length - 1)
306     if (result[result.length - 2] != '.' && result.last() != ' ') result += ". "
307     return result
308 }