From 0206be47827e5b072dac3deb9ccc1792ba95b13c Mon Sep 17 00:00:00 2001 From: Marcin Aman Date: Thu, 18 Jun 2020 12:00:46 +0200 Subject: Javadoc classlikes and function pages All implemented interfaces, first attempt at inherited methods --- .../main/kotlin/javadoc/JavadocLocationProvider.kt | 2 +- .../src/main/kotlin/javadoc/JavadocPageCreator.kt | 81 +++++++++-- .../main/kotlin/javadoc/KorteJavadocRenderer.kt | 114 ++++++++++++++- .../kotlin/javadoc/pages/JavadocContentNodes.kt | 23 ++- .../main/kotlin/javadoc/pages/JavadocPageNodes.kt | 112 ++++++++++++-- .../main/kotlin/javadoc/pages/OverviewSummary.kt | 161 --------------------- 6 files changed, 300 insertions(+), 193 deletions(-) delete mode 100644 plugins/javadoc/src/main/kotlin/javadoc/pages/OverviewSummary.kt (limited to 'plugins/javadoc/src/main/kotlin') diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt index 520486f6..a92320dd 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt @@ -91,7 +91,7 @@ class JavadocLocationProvider(pageRoot: RootPageNode, private val context: Dokka } }?.joinToString("/")?.let {if (skipExtension) "$it.html" else it}?.let { Paths.get(dir).relativize(Paths.get(it)).toString() - } ?: run {throw IllegalStateException("Page for ${link.name} not found")} + } ?: run {""} //TODO just a glue to compile it on HMPP override fun resolveRoot(node: PageNode): String { TODO("Not yet implemented") diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt index 64fc539f..a3bef099 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt @@ -3,14 +3,21 @@ package javadoc import javadoc.pages.* import org.jetbrains.dokka.Platform import org.jetbrains.dokka.base.signatures.SignatureProvider +import org.jetbrains.dokka.base.signatures.function import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.doc.Description +import org.jetbrains.dokka.model.doc.Param +import org.jetbrains.dokka.model.doc.TagWrapper +import org.jetbrains.dokka.model.doc.Text +import org.jetbrains.dokka.model.properties.PropertyContainer +import org.jetbrains.dokka.model.properties.WithExtraProperties import org.jetbrains.dokka.pages.ContentKind import org.jetbrains.dokka.pages.DCI import org.jetbrains.dokka.utilities.DokkaLogger import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import org.jetbrains.kotlin.utils.addToStdlib.safeAs open class JavadocPageCreator( commentsToContentConverter: CommentsToContentConverter, @@ -28,21 +35,28 @@ open class JavadocPageCreator( fun pageForPackage(p: DPackage) = JavadocPackagePageNode(p.name, contentForPackage(p), setOf(p.dri), p, - p.classlikes.map { pageForClasslike(it) } // TODO: nested classlikes - ).also { - it - } + p.classlikes.mapNotNull { pageForClasslike(it) } // TODO: nested classlikes + ) - fun pageForClasslike(c: DClasslike): JavadocClasslikePageNode { - val constructors = when (c) { - is DClass -> c.constructors - is DEnum -> c.constructors - else -> emptyList() + fun pageForClasslike(c: DClasslike): JavadocClasslikePageNode? = + c.sourceSets.firstOrNull { it.platform == Platform.jvm }?.let {jvm -> + JavadocClasslikePageNode( + name = c.name.orEmpty(), + content = contentForClasslike(c), + dri = setOf(c.dri), + modifiers = listOfNotNull(c.visibility[jvm]?.name), + signature = signatureProvider.signature(c), + description = c.description(jvm), + constructors = c.safeAs()?.constructors?.map { it.toJavadocFunction(jvm) }.orEmpty(), + methods = c.functions.map { it.toJavadocFunction(jvm) }, + entries = c.safeAs()?.entries?.map { JavadocEntryNode(signatureProvider.signature(it), it.description(jvm)) }.orEmpty(), + classlikes = c.classlikes.mapNotNull { pageForClasslike(it) }, + properties = c.properties.map { JavadocPropertyNode(signatureProvider.signature(it), TextNode(it.description(jvm), setOf(jvm))) }, + documentable = c, + extras = c.safeAs>()?.extra ?: PropertyContainer.empty() + ) } - return JavadocClasslikePageNode(c.name.orEmpty(), contentForClasslike(c), setOf(c.dri), c, emptyList()) - } - fun contentForModule(m: DModule): JavadocContentNode = JavadocContentGroup( setOf(m.dri), @@ -96,5 +110,48 @@ open class JavadocPageCreator( kind = JavadocContentKind.Class ) } + + private fun signatureForProjection(p: Projection): String = + when (p) { + is OtherParameter -> p.name + is TypeConstructor -> if (p.function) + "TODO" + else { + val other = if(p.projections.isNotEmpty()){ + p.projections.joinToString(prefix = "<", postfix = ">") { signatureForProjection(it) } + } else { + "" + } + "${p.dri.classNames.orEmpty()} $other" + } + + is Variance -> "${p.kind} ${signatureForProjection(p.inner)}" + is Star -> "*" + is Nullable -> "${signatureForProjection(p.inner)}?" + is JavaObject -> "Object" + is Void -> "Void" + is PrimitiveJavaType -> p.name + is Dynamic -> "dynamic" + is UnresolvedBound -> p.name + } + + private fun DFunction.toJavadocFunction(sourceSetData: SourceSetData) = JavadocFunctionNode( + name = name, + signature = signatureProvider.signature(this), + brief = TextNode(description(sourceSetData), setOf(sourceSetData)), + parameters = parameters.map { + JavadocParameterNode( + name = it.name.orEmpty(), + type = signatureForProjection(it.type), + description = TextNode(it.findNodeInDocumentation(sourceSetData), setOf(sourceSetData)) + ) + }, + extras = extra + ) + + private fun Documentable.description(sourceSetData: SourceSetData): String = findNodeInDocumentation(sourceSetData) + + private inline fun Documentable.findNodeInDocumentation(sourceSetData: SourceSetData): String = + documentation[sourceSetData]?.children?.firstIsInstanceOrNull()?.root?.children?.firstIsInstanceOrNull()?.body.orEmpty() } diff --git a/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt b/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt index aa7c2dfe..1026ea5c 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt @@ -8,13 +8,19 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import org.jetbrains.dokka.base.renderers.OutputWriter import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.sureClassNames +import org.jetbrains.dokka.model.ImplementedInterfaces +import org.jetbrains.dokka.model.InheritedFunction import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.renderers.Renderer +import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.nio.file.Path import java.nio.file.Paths import java.time.LocalDate +typealias PageContent = Map + class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaContext, val resourceDir: String) : Renderer { private lateinit var locationProvider: JavadocLocationProvider @@ -67,8 +73,7 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon "docName" to "docName", // todo docname "pathToRoot" to pathToRoot, "dir" to dir - ) + node.contentMap -// DokkaConsoleLogger.info("${node::class.java.canonicalName}::${node.name} - $link") + ) + renderContentNodes(node) writeFromTemplate(outputWriter, link, templateForNode(node), contentMap.toList()) node.children.forEach { renderNode(it, link.toNormalized()) } } @@ -120,11 +125,11 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon ) } - private fun renderContentNode(content: ContentNode) = when(content) { - is ContentText -> content.text - is ContentComposite -> renderContent(content.children) - else -> "" - } +// private fun renderContentNode(content: ContentNode) = when(content) { +// is ContentText -> content.text +// is ContentComposite -> renderContent(content.children) +// else -> "" +// } private fun renderContent(content: List): String = content.joinToString("") { renderContentNode(it) } @@ -179,7 +184,10 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon } rootNodes.joinToString{ drawRec(it) } }, - Filter("length") { subject.dynamicLength() } + Filter("length") { subject.dynamicLength() }, + TeFunction("hasAnyDescription"){ args -> + args.first().safeAs>>()?.any { it["description"]?.trim()?.isNotEmpty() ?: false } + } ).forEach { when (it) { is TeFunction -> config.register(it) @@ -197,4 +205,94 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon javaClass.classLoader.getResourceAsStream("$basePath/$template")?.bufferedReader()?.lines()?.toArray() ?.joinToString("\n") ?: throw IllegalStateException("Template not found: $basePath/$template") } + + private fun renderContentNodes(node: JavadocPageNode): PageContent = + when(node){ + is JavadocClasslikePageNode -> renderClasslikeNode(node) + is JavadocFunctionNode -> renderFunctionNode(node) + else -> node.contentMap + } + + private fun renderFunctionNode(node: JavadocFunctionNode): PageContent { + val (modifiers, signature) = node.modifiersAndSignature + return mapOf( + "signature" to renderContentNode(node.signature), + "brief" to renderContentNode(node.brief), + "parameters" to node.parameters.map { renderParameterNode(it) }, + "inlineParameters" to node.parameters.joinToString { "${it.type} ${it.name}" }, + "modifiers" to renderContentNode(modifiers), + "signatureWithoutModifiers" to renderContentNode(signature)) + node.contentMap + } + + private fun renderParameterNode(node: JavadocParameterNode): PageContent = + mapOf( + "description" to renderContentNode(node.description), + ) + node.contentMap + + private fun renderClasslikeNode(node: JavadocClasslikePageNode): PageContent = + mapOf( + "constructors" to node.constructors.map { renderContentNodes(it) }, + "signature" to renderContentNode(node.signature), + "methods" to renderClasslikeMethods(node.methods), + "entries" to node.entries.map { renderEntryNode(it) }, + "properties" to node.properties.map { renderPropertyNode(it)}, + "classlikes" to node.classlikes.map { renderNestedClasslikeNode(it) }, + "implementedInterfaces" to renderImplementedInterfaces(node) + ) + node.contentMap + + private fun renderImplementedInterfaces(node: JavadocClasslikePageNode) = + node.extras[ImplementedInterfaces]?.interfaces?.map { it.displayable() }.orEmpty() + + private fun renderClasslikeMethods(nodes: List): PageContent { + val (inherited, own) = nodes.partition { it.extras[InheritedFunction]?.isInherited ?: false } + return mapOf( + "own" to own.map { renderContentNodes(it) }, + "inherited" to inherited.map { renderInheritedMethod(it) }.groupBy { it["inheritedFrom"] as String }.entries.map { + mapOf("inheritedFrom" to it.key, "names" to it.value.map{ it["name"] as String }.sorted().joinToString() ) + } + ) + } + + private fun renderInheritedMethod(node: JavadocFunctionNode): PageContent { + val inheritedFrom = node.extras[InheritedFunction]?.inheritedFrom + return mapOf( + "inheritedFrom" to inheritedFrom?.displayable().orEmpty(), + "name" to node.name + ) + } + + private fun renderNestedClasslikeNode(node: JavadocClasslikePageNode): PageContent { + return mapOf( + "modifiers" to (node.modifiers + "static" + node.contentMap["kind"]).joinToString(separator = " "), + "signature" to node.name, + "description" to node.description + ) + } + + private fun renderPropertyNode(node: JavadocPropertyNode): PageContent { + val (modifiers, signature) = node.modifiersAndSignature + return mapOf( + "modifiers" to renderContentNode(modifiers), + "signature" to renderContentNode(signature), + "description" to renderContentNode(node.brief) + ) + } + + private fun renderEntryNode(node: JavadocEntryNode): PageContent = + mapOf( + "signature" to renderContentNode(node.signature), + ) + node.contentMap + + + //TODO is it possible to use html renderer? + private fun renderContentNode(node: ContentNode): String = + when(node){ + is ContentGroup -> node.children.joinToString(separator = "") { renderContentNode(it) } + is ContentText -> node.text + is TextNode -> node.text + is ContentLink -> """${node.children.joinToString { renderContentNode(it) }} """ + else -> "" + } + + private fun DRI.displayable(): String = "${packageName}.${sureClassNames}" } \ No newline at end of file diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt index 031ce970..1c42adb3 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt @@ -37,6 +37,8 @@ class EmptyNode( override fun withNewExtras(newExtras: PropertyContainer): ContentNode = EmptyNode(dci.dri.first(), dci.kind, sourceSets, newExtras) + + override fun hasAnyContent(): Boolean = false } class JavadocContentGroup( @@ -56,6 +58,8 @@ class JavadocContentGroup( ): JavadocContentGroup = JavadocContentGroup(dri, kind, sourceSets, JavaContentGroupBuilder(sourceSets).apply(block).list) } + + override fun hasAnyContent(): Boolean = children.isNotEmpty() } class JavaContentGroupBuilder(val sourceSets: Set) { @@ -71,6 +75,8 @@ class TitleNode( sourceSets: Set ) : JavadocContentNode(dri, kind, sourceSets) { + override fun hasAnyContent(): Boolean = !title.isBlank() || !version.isBlank() + override val contentMap: Map by lazy { mapOf( "title" to title, @@ -78,8 +84,6 @@ class TitleNode( "packageName" to parent ) } - -// override fun withNewExtras(newExtras: PropertyContainer): ContentNode = TODO() } fun JavaContentGroupBuilder.title( @@ -92,6 +96,18 @@ fun JavaContentGroupBuilder.title( list.add(TitleNode(title, version, parent, dri, kind, sourceSets)) } +data class TextNode( + val text: String, + override val sourceSets: Set +) : JavadocContentNode(emptySet(), ContentKind.Main, sourceSets) { + + override fun hasAnyContent(): Boolean = !text.isBlank() + + override val contentMap: Map = mapOf( + "text" to text, + ) +} + class ListNode( val tabTitle: String, val colTitle: String, @@ -100,6 +116,9 @@ class ListNode( val kind: Kind, sourceSets: Set ) : JavadocContentNode(dri, kind, sourceSets) { + + override fun hasAnyContent(): Boolean = children.isNotEmpty() + override val contentMap: Map by lazy { mapOf( "tabTitle" to tabTitle, diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt index 118bc4d3..7f6abb15 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt @@ -6,10 +6,12 @@ import org.jetbrains.dokka.Platform import org.jetbrains.dokka.base.renderers.platforms import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.pages.* import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.resolve.DescriptorUtils.getClassDescriptorForType +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance interface JavadocPageNode : ContentPage { val contentMap: Map @@ -79,20 +81,98 @@ class JavadocPackagePageNode( ) } +data class JavadocEntryNode( + val signature: ContentNode, + val brief: String +) { + val contentMap: Map = mapOf( + "brief" to brief + ) +} + +data class JavadocParameterNode( + val name: String, + val type: String, + val description: ContentNode +) { + val contentMap: Map = mapOf( + "name" to name, + "type" to type + ) +} + +data class JavadocPropertyNode( + val signature: ContentNode, + val brief: ContentNode +){ + val modifiersAndSignature: Pair + get() = (signature as ContentGroup).splitSignatureIntoModifiersAndName() +} + +data class JavadocFunctionNode( + val signature: ContentNode, + val brief: ContentNode, + val parameters: List, + override val name: String, + override val dri: Set = emptySet(), + override val content: ContentNode = EmptyNode(DRI.topLevel, ContentKind.Classlikes, emptySet()), + override val children: List = emptyList(), + override val documentable: Documentable? = null, + override val embeddedResources: List = emptyList(), + val extras: PropertyContainer = PropertyContainer.empty() +): JavadocPageNode { + override val contentMap: Map = mapOf( + "name" to name + ) + + override fun modified( + name: String, + children: List + ): PageNode = TODO() + + override fun modified( + name: String, + content: ContentNode, + dri: Set, + embeddedResources: List, + children: List + ): ContentPage = TODO() + + val modifiersAndSignature: Pair + get() = (signature as ContentGroup).splitSignatureIntoModifiersAndName() + +} + class JavadocClasslikePageNode( override val name: String, override val content: JavadocContentNode, override val dri: Set, - + val modifiers: List, + val signature: ContentNode, + val description: String, + val constructors: List, + val methods: List, + val entries: List, + val classlikes: List, + val properties: List, override val documentable: Documentable? = null, override val children: List = emptyList(), - override val embeddedResources: List = listOf() + override val embeddedResources: List = listOf(), + val extras: PropertyContainer, ) : JavadocPageNode { - override val contentMap: Map by lazy { mapOf("kind" to "class") + content.contentMap } + override val contentMap: Map by lazy { + mapOf( + "kind" to documentable?.kind(), + "name" to name, + "package" to dri.first().packageName, + "classlikeDocumentation" to description + ) + content.contentMap + } + override fun modified( name: String, children: List - ): PageNode = JavadocClasslikePageNode(name, content, dri, documentable, children, embeddedResources) + ): PageNode = JavadocClasslikePageNode(name, content, dri, modifiers, signature, description, constructors, methods, entries, classlikes, properties, documentable, children, embeddedResources, extras) override fun modified( name: String, @@ -101,7 +181,7 @@ class JavadocClasslikePageNode( embeddedResources: List, children: List ): ContentPage = - JavadocClasslikePageNode(name, content as JavadocContentNode, dri, documentable, children, embeddedResources) + JavadocClasslikePageNode(name, content as JavadocContentNode, dri, modifiers, signature, description, constructors, methods, entries, classlikes, properties, documentable, children, embeddedResources, extras) } class AllClassesPage(val classes: List) : JavadocPageNode { @@ -295,10 +375,8 @@ class TreeViewPage( descriptorInheritanceTree.forEach { addToMap(it, mergeMap) } psiInheritanceTree.forEach { addToMap(it, mergeMap) } - val g = mergeMap.entries.find { it.key.classNames == "Any" || it.key.classNames == "Object" }?.value?.dri?.let(::collect) - val rootClasses = listOf("Any", "Object") val rootNodes = mergeMap.entries.filter { - it.key.classNames in rootClasses //TODO: Probably should be matched by DRI, not just className + it.key.classNames in setOf("Any", "Object") //TODO: Probably should be matched by DRI, not just className }.map { collect(it.value.dri) } @@ -350,4 +428,20 @@ class TreeViewPage( interface ContentValue data class StringValue(val text: String) : ContentValue -data class ListValue(val list: List) : ContentValue \ No newline at end of file +data class ListValue(val list: List) : ContentValue + +private fun ContentGroup.splitSignatureIntoModifiersAndName(): Pair { + val signature = children.firstIsInstance() + val modifiers = signature.children.takeWhile { it !is ContentLink } + return Pair(signature.copy(children = modifiers), signature.copy(children = signature.children.drop(modifiers.size))) +} + +private fun Documentable.kind(): String? = + when(this){ + is DClass -> "class" + is DEnum -> "enum" + is DAnnotation -> "annotation" + is DObject -> "object" + is DInterface -> "interface" + else -> null + } \ No newline at end of file diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/OverviewSummary.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/OverviewSummary.kt deleted file mode 100644 index ae573007..00000000 --- a/plugins/javadoc/src/main/kotlin/javadoc/pages/OverviewSummary.kt +++ /dev/null @@ -1,161 +0,0 @@ -package javadoc.pages - -import java.time.LocalDate - -internal fun overviewSummary(title: String, version: String) = """ - - - - -Overview ($title $version API) - - - - - - - - -
- - - - - - - -
- - -
-

terrain-generator 0.0.1 API

-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Packages 
PackageDescription
adaptation 
app 
common 
model 
processor 
transformation 
-
- -
- - - - - - - -
- - - - -""" \ No newline at end of file -- cgit