diff options
author | Błażej Kardyś <bkardys@virtuslab.com> | 2019-10-29 11:28:42 +0100 |
---|---|---|
committer | Błażej Kardyś <bkardys@virtuslab.com> | 2019-10-29 11:28:42 +0100 |
commit | eec585065fa1865bd8cee188b94634f1c9a90c95 (patch) | |
tree | 5a9217a98008fb6889ff1b449bbe4185d0fd1dca /core/src/main/kotlin | |
parent | 8de3af68d4415418cfe2ff548f9653d33210b44d (diff) | |
download | dokka-eec585065fa1865bd8cee188b94634f1c9a90c95.tar.gz dokka-eec585065fa1865bd8cee188b94634f1c9a90c95.tar.bz2 dokka-eec585065fa1865bd8cee188b94634f1c9a90c95.zip |
New dokka model
Diffstat (limited to 'core/src/main/kotlin')
-rw-r--r-- | core/src/main/kotlin/Model/Content.kt | 2 | ||||
-rw-r--r-- | core/src/main/kotlin/Model/DocumentationNode.kt | 314 | ||||
-rw-r--r-- | core/src/main/kotlin/Model/DocumentationReference.kt | 13 | ||||
-rw-r--r-- | core/src/main/kotlin/Model/SourceLinks.kt | 64 |
4 files changed, 186 insertions, 207 deletions
diff --git a/core/src/main/kotlin/Model/Content.kt b/core/src/main/kotlin/Model/Content.kt index 5530e1b4..3881ee20 100644 --- a/core/src/main/kotlin/Model/Content.kt +++ b/core/src/main/kotlin/Model/Content.kt @@ -209,7 +209,7 @@ fun ContentBlock.code(body: ContentBlock.() -> Unit) { } fun ContentBlock.link(to: DocumentationNode, body: ContentBlock.() -> Unit) { - val block = if (to.kind == NodeKind.ExternalLink) + val block = if (to is DocumentationNodes.ExternalLink) ContentExternalLink(to.name) else ContentNodeDirectLink(to) diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt index 311b46e4..66ee33e1 100644 --- a/core/src/main/kotlin/Model/DocumentationNode.kt +++ b/core/src/main/kotlin/Model/DocumentationNode.kt @@ -1,89 +1,160 @@ package org.jetbrains.dokka +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import java.util.* +import kotlin.reflect.KClass +import kotlin.reflect.full.primaryConstructor -enum class NodeKind { - Unknown, +class DocumentationNodes { - Package, - Class, - Interface, - Enum, - AnnotationClass, - Exception, - EnumItem, - Object, - TypeAlias, + class Unknown(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) - Constructor, - Function, - Property, - Field, + class Package(name: String) : + DocumentationNode(name) - CompanionObjectProperty, - CompanionObjectFunction, + class Class(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val classLike: Boolean = true + } - Parameter, - Receiver, - TypeParameter, - Type, - Supertype, - UpperBound, - LowerBound, + class Interface(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val classLike: Boolean = true + override val superclassType: DocumentationNode? = null + } - TypeAliasUnderlyingType, + class Enum(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val classLike: Boolean = true + } - Modifier, - NullabilityModifier, + class AnnotationClass(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val classLike: Boolean = true + } - Module, + class Exception(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val classLike: Boolean = true + } - ExternalClass, - Annotation, + class EnumItem(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val memberLike = true + } - Value, + class Object(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val classLike: Boolean = true + } - SourceUrl, - SourcePosition, - Signature, + class TypeAlias(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) - ExternalLink, - QualifiedName, - Platform, + class Constructor(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val memberLike = true + } - AllTypes, + class Function(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val memberLike = true + } - /** - * A note which is rendered once on a page documenting a group of overloaded functions. - * Needs to be generated equally on all overloads. - */ - OverloadGroupNote, + class Property(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val memberLike = true + } - GroupNode; + class Field(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val memberLike = true + } - companion object { - val classLike = setOf(Class, Interface, Enum, AnnotationClass, Exception, Object, TypeAlias) - val memberLike = setOf(Function, Property, Field, Constructor, CompanionObjectFunction, CompanionObjectProperty, EnumItem) + class CompanionObjectProperty(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val memberLike = true } -} -open class DocumentationNode(val name: String, - content: Content, - val kind: NodeKind) { + class CompanionObjectFunction(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val memberLike = true + } - private val references = LinkedHashSet<DocumentationReference>() + class Parameter(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) - var content: Content = content - private set + class Receiver(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) - val summary: ContentNode get() = when (kind) { - NodeKind.GroupNode -> this.origins - .map { it.content } - .firstOrNull { !it.isEmpty() } - ?.summary ?: ContentEmpty - else -> content.summary + class TypeParameter(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class Type(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class Supertype(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) { + override val superclassType: DocumentationNode? = + (links + listOfNotNull(externalType)).firstOrNull { it.classLike }?.superclassType } + class UpperBound(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class LowerBound(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class TypeAliasUnderlyingType(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class NullabilityModifier(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class Module(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class ExternalClass(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class Annotation(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class Value(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class SourceUrl(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class SourcePosition(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class ExternalLink(name: String) : DocumentationNode(name) + + class QualifiedName(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class Platform(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class AllTypes(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) + + class OverloadGroupNote(name: String, descriptor: DeclarationDescriptor?) : + DocumentationNode(name, descriptor) +} + +abstract class DocumentationNode( + var name: String, + val descriptor: DeclarationDescriptor? = null +) { + + private val references = LinkedHashSet<DocumentationReference>() + + open val classLike = false + + open val memberLike = false val owner: DocumentationNode? get() = references(RefKind.Owner).singleOrNull()?.to @@ -119,29 +190,12 @@ open class DocumentationNode(val name: String, val externalType: DocumentationNode? get() = references(RefKind.ExternalType).map { it.to }.firstOrNull() - var sinceKotlin: String? - get() = references(RefKind.SinceKotlin).singleOrNull()?.to?.name - set(value) { - dropReferences { it.kind == RefKind.SinceKotlin } - if (value != null) { - append(DocumentationNode(value, Content.Empty, NodeKind.Value), RefKind.SinceKotlin) - } - } - - val supertypes: List<DocumentationNode> - get() = details(NodeKind.Supertype) - - val superclassType: DocumentationNode? - get() = when (kind) { - NodeKind.Supertype -> { - (links + listOfNotNull(externalType)).firstOrNull { it.kind in NodeKind.classLike }?.superclassType - } - NodeKind.Interface -> null - in NodeKind.classLike -> supertypes.firstOrNull { + open val superclassType: DocumentationNode? + get() = if (classLike) { + supertypes.firstOrNull { (it.links + listOfNotNull(it.externalType)).any { it.isSuperclassFor(this) } } - else -> null - } + } else null val superclassTypeSequence: Sequence<DocumentationNode> get() = generateSequence(superclassType) { @@ -165,36 +219,46 @@ open class DocumentationNode(val name: String, references.addAll(other.references) } - fun updateContent(body: MutableContent.() -> Unit) { - if (content !is MutableContent) { - content = MutableContent() - } - (content as MutableContent).body() - } - fun details(kind: NodeKind): List<DocumentationNode> = details.filter { it.kind == kind } - fun members(kind: NodeKind): List<DocumentationNode> = members.filter { it.kind == kind } - fun inheritedMembers(kind: NodeKind): List<DocumentationNode> = inheritedMembers.filter { it.kind == kind } - fun inheritedCompanionObjectMembers(kind: NodeKind): List<DocumentationNode> = inheritedCompanionObjectMembers.filter { it.kind == kind } - fun links(kind: NodeKind): List<DocumentationNode> = links.filter { it.kind == kind } + private fun Collection<DocumentationNode>.filterByKind(kind: KClass<out DocumentationNode>) = + filter { node: DocumentationNode -> node::class == kind } + + private fun Collection<DocumentationNode>.singleByKind(kind: KClass<out DocumentationNode>) = + single { node: DocumentationNode -> node::class == kind } + + fun details(kind: KClass<out DocumentationNode>) = details.filterByKind(kind) + fun members(kind: KClass<out DocumentationNode>) = members.filterByKind(kind) + fun inheritedMembers(kind: KClass<out DocumentationNode>): List<DocumentationNode> = + inheritedMembers.filterByKind(kind) + + fun inheritedCompanionObjectMembers(kind: KClass<out DocumentationNode>): List<DocumentationNode> = + inheritedCompanionObjectMembers.filterByKind(kind) + + fun links(kind: KClass<out DocumentationNode>): List<DocumentationNode> = links.filterByKind(kind) + + fun detail(kind: KClass<out DocumentationNode>): DocumentationNode = details.singleByKind(kind) + fun detailOrNull(kind: KClass<out DocumentationNode>): DocumentationNode? = + details.singleOrNull { it::class == kind } - fun detail(kind: NodeKind): DocumentationNode = details.single { it.kind == kind } - fun detailOrNull(kind: NodeKind): DocumentationNode? = details.singleOrNull { it.kind == kind } - fun member(kind: NodeKind): DocumentationNode = members.single { it.kind == kind } - fun link(kind: NodeKind): DocumentationNode = links.single { it.kind == kind } + fun member(kind: KClass<out DocumentationNode>): DocumentationNode = members.singleByKind(kind) + fun link(kind: KClass<out DocumentationNode>): DocumentationNode = links.singleByKind(kind) fun references(kind: RefKind): List<DocumentationReference> = references.filter { it.kind == kind } fun allReferences(): Set<DocumentationReference> = references override fun toString(): String { - return "$kind:$name" + return "${javaClass.name}:$name" } } -class DocumentationModule(name: String, content: Content = Content.Empty, val nodeRefGraph: NodeReferenceGraph = NodeReferenceGraph()) - : DocumentationNode(name, content, NodeKind.Module) { +fun KClass<out DocumentationNode>.createNode(name: String, descriptor: DeclarationDescriptor? = null) = + primaryConstructor?.call(name, descriptor) + ?: throw IllegalArgumentException("Cannot create node of type ${this::class}: invalid primary constructor") -} +val DocumentationNode.supertypes: List<DocumentationNode> + get() = details(DocumentationNodes.Supertype::class) + +class DocumentationModule(name: String) : DocumentationNode(name) val DocumentationNode.path: List<DocumentationNode> get() { @@ -202,23 +266,6 @@ val DocumentationNode.path: List<DocumentationNode> return parent.path + this } -fun findOrCreatePackageNode(module: DocumentationNode?, packageName: String, packageContent: Map<String, Content>, refGraph: NodeReferenceGraph): DocumentationNode { - val node = refGraph.lookup(packageName) ?: run { - val newNode = DocumentationNode( - packageName, - packageContent.getOrElse(packageName) { Content.Empty }, - NodeKind.Package - ) - - refGraph.register(packageName, newNode) - newNode - } - if (module != null && node !in module.members) { - module.append(node, RefKind.Member) - } - return node -} - fun DocumentationNode.append(child: DocumentationNode, kind: RefKind) { addReferenceTo(child, kind) when (kind) { @@ -231,19 +278,23 @@ fun DocumentationNode.append(child: DocumentationNode, kind: RefKind) { } } -fun DocumentationNode.appendTextNode(text: String, - kind: NodeKind, - refKind: RefKind = RefKind.Detail) { - append(DocumentationNode(text, Content.Empty, kind), refKind) +fun DocumentationNode.appendTextNode( + text: String, + kind: KClass<out DocumentationNode>, + descriptor: DeclarationDescriptor? = null, + refKind: RefKind = RefKind.Detail +) { + append(kind.createNode(text, descriptor), refKind) } fun DocumentationNode.qualifiedName(): String { - if (kind == NodeKind.Type) { + if (this is DocumentationNodes.Type) { return qualifiedNameFromType() - } else if (kind == NodeKind.Package) { + } else if (this is DocumentationNodes.Package) { return name } - return path.dropWhile { it.kind == NodeKind.Module }.map { it.name }.filter { it.isNotEmpty() }.joinToString(".") + return path.dropWhile { it is DocumentationNodes.Module }.map { it.name }.filter { it.isNotEmpty() } + .joinToString(".") } fun DocumentationNode.simpleName() = name.substringAfterLast('.') @@ -257,20 +308,23 @@ private fun DocumentationNode.recursiveInheritedMembers(): List<DocumentationNod private fun DocumentationNode.recursiveInheritedMembers(allInheritedMembers: MutableList<DocumentationNode>) { allInheritedMembers.addAll(inheritedMembers) System.out.println(allInheritedMembers.size) - inheritedMembers.groupBy { it.owner!! } .forEach { (node, _) -> + inheritedMembers.groupBy { it.owner!! }.forEach { (node, _) -> node.recursiveInheritedMembers(allInheritedMembers) } } private fun DocumentationNode.isSuperclassFor(node: DocumentationNode): Boolean { - return when(node.kind) { - NodeKind.Object, NodeKind.Class, NodeKind.Enum -> kind == NodeKind.Class - NodeKind.Exception -> kind == NodeKind.Class || kind == NodeKind.Exception + return when (node) { + is DocumentationNodes.Object, + is DocumentationNodes.Class, + is DocumentationNodes.Enum -> this is DocumentationNodes.Class + is DocumentationNodes.Exception -> this is DocumentationNodes.Class || this is DocumentationNodes.Exception else -> false } } fun DocumentationNode.classNodeNameWithOuterClass(): String { - assert(kind in NodeKind.classLike) - return path.dropWhile { it.kind == NodeKind.Package || it.kind == NodeKind.Module }.joinToString(separator = ".") { it.name } + assert(classLike) + return path.dropWhile { it is DocumentationNodes.Package || it is DocumentationNodes.Module } + .joinToString(separator = ".") { it.name } }
\ No newline at end of file diff --git a/core/src/main/kotlin/Model/DocumentationReference.kt b/core/src/main/kotlin/Model/DocumentationReference.kt index 0b890a78..e46a4a21 100644 --- a/core/src/main/kotlin/Model/DocumentationReference.kt +++ b/core/src/main/kotlin/Model/DocumentationReference.kt @@ -112,15 +112,4 @@ class NodeReferenceGraph { fun resolveReferences() { references.forEach { it.resolve(this) } } -} - -@Singleton -class PlatformNodeRegistry { - private val platformNodes = hashMapOf<String, DocumentationNode>() - - operator fun get(platform: String): DocumentationNode { - return platformNodes.getOrPut(platform) { - DocumentationNode(platform, Content.Empty, NodeKind.Platform) - } - } -} +}
\ No newline at end of file diff --git a/core/src/main/kotlin/Model/SourceLinks.kt b/core/src/main/kotlin/Model/SourceLinks.kt index 99ee362e..68cdab4a 100644 --- a/core/src/main/kotlin/Model/SourceLinks.kt +++ b/core/src/main/kotlin/Model/SourceLinks.kt @@ -7,72 +7,8 @@ import org.jetbrains.dokka.DokkaConfiguration.SourceLinkDefinition import org.jetbrains.kotlin.psi.psiUtil.startOffset import java.io.File - -fun DocumentationNode.appendSourceLink(psi: PsiElement?, sourceLinks: List<SourceLinkDefinition>) { - val path = psi?.containingFile?.virtualFile?.path ?: return - val canonicalPath = File(path).canonicalPath - - val target = if (psi is PsiNameIdentifierOwner) psi.nameIdentifier else psi - val pair = determineSourceLinkDefinition(canonicalPath, sourceLinks) - if (pair != null) { - val (sourceLinkDefinition, sourceLinkCanonicalPath) = pair - var url = determineUrl(canonicalPath, sourceLinkDefinition, sourceLinkCanonicalPath) - if (sourceLinkDefinition.lineSuffix != null) { - val line = target?.lineNumber() - if (line != null) { - url += sourceLinkDefinition.lineSuffix + line.toString() - } - } - append(DocumentationNode(url, Content.Empty, NodeKind.SourceUrl), RefKind.Detail) - } - - if (target != null) { - append(DocumentationNode(target.sourcePosition(), Content.Empty, NodeKind.SourcePosition), RefKind.Detail) - } -} - -private fun determineSourceLinkDefinition( - canonicalPath: String, - sourceLinks: List<SourceLinkDefinition> -): Pair<SourceLinkDefinition, String>? { - return sourceLinks - .asSequence() - .map { it to File(it.path).canonicalPath } - .firstOrNull { (_, sourceLinkCanonicalPath) -> - canonicalPath.startsWith(sourceLinkCanonicalPath) - } -} - -private fun determineUrl( - canonicalPath: String, - sourceLinkDefinition: SourceLinkDefinition, - sourceLinkCanonicalPath: String -): String { - val relativePath = canonicalPath.substring(sourceLinkCanonicalPath.length) - val relativeUrl = relativePath.replace('\\', '/').removePrefix("/") - return "${sourceLinkDefinition.url.removeSuffix("/")}/$relativeUrl" -} - -private fun PsiElement.sourcePosition(): String { - val path = containingFile.virtualFile.path - val lineNumber = lineNumber() - val columnNumber = columnNumber() - - return when { - lineNumber == null -> path - columnNumber == null -> "$path:$lineNumber" - else -> "$path:$lineNumber:$columnNumber" - } -} - fun PsiElement.lineNumber(): Int? { val doc = PsiDocumentManager.getInstance(project).getDocument(containingFile) // IJ uses 0-based line-numbers; external source browsers use 1-based return doc?.getLineNumber(textRange.startOffset)?.plus(1) -} - -fun PsiElement.columnNumber(): Int? { - val doc = PsiDocumentManager.getInstance(project).getDocument(containingFile) ?: return null - val lineNumber = doc.getLineNumber(textRange.startOffset) - return startOffset - doc.getLineStartOffset(lineNumber) }
\ No newline at end of file |