From 3940153fd08e0c0596ac289766d9ef2877b56591 Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Fri, 13 Mar 2020 10:46:33 +0100 Subject: First version of javadoc output generation --- plugins/javadoc/src/main/resources/views/class.korte | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 plugins/javadoc/src/main/resources/views/class.korte (limited to 'plugins/javadoc/src/main/resources/views/class.korte') diff --git a/plugins/javadoc/src/main/resources/views/class.korte b/plugins/javadoc/src/main/resources/views/class.korte new file mode 100644 index 00000000..9b19df08 --- /dev/null +++ b/plugins/javadoc/src/main/resources/views/class.korte @@ -0,0 +1,2 @@ +{% extends "components/base.korte" %} +{% block content %} default {% end %} \ No newline at end of file -- cgit 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 --- core/src/main/kotlin/model/Documentable.kt | 12 +- .../main/kotlin/model/documentableProperties.kt | 17 +- core/src/main/kotlin/pages/PageNodes.kt | 4 +- .../DefaultDescriptorToDocumentableTranslator.kt | 43 +++- .../psi/DefaultPsiToDocumentableTranslator.kt | 63 ++--- .../kotlin/content/params/ContentForParamsTest.kt | 51 ++++ plugins/base/src/test/kotlin/model/ClassesTest.kt | 19 +- plugins/base/src/test/kotlin/model/JavaTest.kt | 25 +- .../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 ------------ .../src/main/resources/static_res/script.js | 139 +++++++++++ .../javadoc/src/main/resources/views/class.korte | 274 ++++++++++++++++++++- .../kotlin/signatures/JavaSignatureProvider.kt | 4 +- 17 files changed, 897 insertions(+), 247 deletions(-) delete mode 100644 plugins/javadoc/src/main/kotlin/javadoc/pages/OverviewSummary.kt create mode 100644 plugins/javadoc/src/main/resources/static_res/script.js (limited to 'plugins/javadoc/src/main/resources/views/class.korte') diff --git a/core/src/main/kotlin/model/Documentable.kt b/core/src/main/kotlin/model/Documentable.kt index 17b49f97..90958210 100644 --- a/core/src/main/kotlin/model/Documentable.kt +++ b/core/src/main/kotlin/model/Documentable.kt @@ -114,7 +114,7 @@ data class DPackage( ) : Documentable(), WithScope, WithExtraProperties { override val name = dri.packageName.orEmpty() override val children: List - get() = (properties + functions + classlikes) as List + get() = (properties + functions + classlikes) override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } @@ -140,7 +140,7 @@ data class DClass( WithExtraProperties { override val children: List - get() = (functions + properties + classlikes + constructors) as List + get() = (functions + properties + classlikes + constructors) override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } @@ -163,7 +163,7 @@ data class DEnum( override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithCompanion, WithConstructors, WithSupertypes, WithExtraProperties { override val children: List - get() = (entries + functions + properties + classlikes + constructors) as List + get() = (entries + functions + properties + classlikes + constructors) override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } @@ -180,7 +180,7 @@ data class DEnumEntry( override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithScope, WithExtraProperties { override val children: List - get() = (functions + properties + classlikes) as List + get() = (functions + properties + classlikes) override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } @@ -224,7 +224,7 @@ data class DInterface( override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithCompanion, WithGenerics, WithSupertypes, WithExtraProperties { override val children: List - get() = (functions + properties + classlikes) as List + get() = (functions + properties + classlikes) override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } @@ -266,7 +266,7 @@ data class DAnnotation( override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithCompanion, WithConstructors, WithExtraProperties, WithGenerics { override val children: List - get() = (functions + properties + classlikes + constructors) as List + get() = (functions + properties + classlikes + constructors) override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } diff --git a/core/src/main/kotlin/model/documentableProperties.kt b/core/src/main/kotlin/model/documentableProperties.kt index f630ba3b..699a1df1 100644 --- a/core/src/main/kotlin/model/documentableProperties.kt +++ b/core/src/main/kotlin/model/documentableProperties.kt @@ -1,13 +1,28 @@ package org.jetbrains.dokka.model +import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.properties.ExtraProperty import org.jetbrains.dokka.model.properties.MergeStrategy -data class InheritedFunction(val isInherited: Boolean): ExtraProperty { +data class InheritedFunction(val inheritedFrom: DRI?): ExtraProperty { companion object : ExtraProperty.Key { override fun mergeStrategyFor(left: InheritedFunction, right: InheritedFunction) = MergeStrategy.Fail { throw IllegalArgumentException("Function inheritance should be consistent!") } } + + val isInherited: Boolean + get() = inheritedFrom != null + override val key: ExtraProperty.Key = InheritedFunction +} + +data class ImplementedInterfaces(val interfaces: List): ExtraProperty { + companion object : ExtraProperty.Key { + override fun mergeStrategyFor(left: ImplementedInterfaces, right: ImplementedInterfaces) = MergeStrategy.Fail { + throw IllegalArgumentException("Implemented interfaces should be consistent!") + } + } + + override val key: ExtraProperty.Key = ImplementedInterfaces } \ No newline at end of file diff --git a/core/src/main/kotlin/pages/PageNodes.kt b/core/src/main/kotlin/pages/PageNodes.kt index 42ca25cc..b9f1025f 100644 --- a/core/src/main/kotlin/pages/PageNodes.kt +++ b/core/src/main/kotlin/pages/PageNodes.kt @@ -1,9 +1,7 @@ package org.jetbrains.dokka.pages -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.model.Documentable -import org.jetbrains.dokka.Platform import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.Documentable import java.util.* interface PageNode { diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index dfa7b480..4f292ca1 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -147,7 +147,8 @@ private class DokkaDescriptorVisitor( sourceSets = setOf(sourceSet), extra = PropertyContainer.withAll( descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations() + descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), + ImplementedInterfaces(info.interfaces) ) ) } @@ -173,7 +174,8 @@ private class DokkaDescriptorVisitor( sourceSets = setOf(sourceSet), extra = PropertyContainer.withAll( descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations() + descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), + ImplementedInterfaces(info.interfaces) ) ) } @@ -201,7 +203,8 @@ private class DokkaDescriptorVisitor( sourceSets = setOf(sourceSet), extra = PropertyContainer.withAll( descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations() + descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), + ImplementedInterfaces(info.interfaces) ) ) } @@ -284,7 +287,8 @@ private class DokkaDescriptorVisitor( sourceSets = setOf(sourceSet), extra = PropertyContainer.withAll( descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), - descriptor.getAnnotations().toSourceSetDependent().toAnnotations() + descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), + ImplementedInterfaces(info.interfaces) ) ) } @@ -322,14 +326,14 @@ private class DokkaDescriptorVisitor( ) } - fun CallableMemberDescriptor.createDRI(wasOverriden: Boolean = false): Pair = + fun CallableMemberDescriptor.createDRI(wasOverridenBy: DRI? = null): Pair = if (kind == CallableMemberDescriptor.Kind.DECLARATION || overriddenDescriptors.isEmpty()) - Pair(DRI.from(this), wasOverriden) + Pair(DRI.from(this), wasOverridenBy) else - overriddenDescriptors.first().createDRI(true) + overriddenDescriptors.first().createDRI(DRI.from(this)) override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, parent: DRIWithPlatformInfo): DFunction { - val (dri, isInherited) = descriptor.createDRI() + val (dri, inheritedFrom) = descriptor.createDRI() val isExpect = descriptor.isExpect val actual = descriptor.createSources() @@ -352,7 +356,7 @@ private class DokkaDescriptorVisitor( type = descriptor.returnType!!.toBound(), sourceSets = setOf(sourceSet), extra = PropertyContainer.withAll( - InheritedFunction(isInherited), + InheritedFunction(inheritedFrom), descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), descriptor.getAnnotations().toSourceSetDependent().toAnnotations() ) @@ -550,8 +554,17 @@ private class DokkaDescriptorVisitor( getDocumentation()?.toSourceSetDependent() ?: emptyMap() private fun ClassDescriptor.resolveClassDescriptionData(): ClassInfo { + val superClasses = hashSetOf() + + fun processSuperClasses(supers: List) { + supers.forEach { + superClasses.add(it) + processSuperClasses(it.getSuperInterfaces() + it.getAllSuperclassesWithoutAny()) + } + } + processSuperClasses(getSuperInterfaces() + getAllSuperclassesWithoutAny()) return ClassInfo( - (getSuperInterfaces() + getAllSuperclassesWithoutAny()).map { DRI.from(it) }, + superClasses.map { Supertype(DRI.from(it), it.kind == ClassKind.INTERFACE) }.toList(), resolveDescriptorData() ) } @@ -726,7 +739,13 @@ private class DokkaDescriptorVisitor( private fun ValueArgument.childrenAsText() = this.safeAs()?.children?.map {it.text }.orEmpty() - private data class ClassInfo(val supertypes: List, val docs: SourceSetDependent) + private data class ClassInfo(private val allSupertypes: List, val docs: SourceSetDependent){ + val supertypes: List + get() = allSupertypes.map { it.dri } + + val interfaces: List + get() = allSupertypes.filter { it.isInterface }.map { it.dri } + } private fun Visibility.toDokkaVisibility(): org.jetbrains.dokka.model.Visibility = when (this) { Visibilities.PUBLIC -> KotlinVisibility.Public @@ -740,6 +759,8 @@ private class DokkaDescriptorVisitor( "${this.enumClassId.relativeClassName.asString()}.${this.enumEntryName.identifier}" private fun fallbackPackageName(): String = "[${sourceSet.displayName} root]"// TODO: error-prone, find a better way to do it + + private data class Supertype(val dri: DRI, val isInterface: Boolean) } private fun DRI.withPackageFallbackTo(fallbackPackage: String): DRI { diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index 6ec5c4f5..8b397859 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -1,18 +1,20 @@ package org.jetbrains.dokka.base.translators.psi -import com.intellij.icons.AllIcons.Nodes.Static -import com.intellij.lang.jvm.annotation.JvmAnnotationAttribute import com.intellij.lang.jvm.JvmModifier +import com.intellij.lang.jvm.annotation.JvmAnnotationAttribute import com.intellij.lang.jvm.types.JvmReferenceType import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.* import com.intellij.psi.impl.source.PsiClassReferenceType import com.intellij.psi.impl.source.PsiImmediateClassType -import com.intellij.psi.impl.source.tree.java.PsiArrayInitializerMemberValueImpl import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.nextTarget import org.jetbrains.dokka.links.withClass import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.doc.DocumentationLink +import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.model.doc.Param +import org.jetbrains.dokka.model.doc.Text import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator @@ -27,9 +29,9 @@ import org.jetbrains.kotlin.load.java.propertyNamesBySetMethodName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.psiUtil.getChildOfType import org.jetbrains.kotlin.resolve.DescriptorUtils +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.io.File -import java.lang.ClassValue object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { @@ -120,23 +122,24 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { fun parseClasslike(psi: PsiClass, parent: DRI): DClasslike = with(psi) { val dri = parent.withClass(name.toString()) - val ancestorsSet = hashSetOf() + val ancestorsSet = hashSetOf() val superMethodsKeys = hashSetOf() - val superMethods = mutableListOf() + val superMethods = mutableListOf>() methods.forEach { superMethodsKeys.add(it.hash) } fun parseSupertypes(superTypes: Array) { superTypes.forEach { type -> (type as? PsiClassType)?.takeUnless { type.shouldBeIgnored }?.resolve()?.let { + val definedAt = DRI.from(it) it.methods.forEach { method -> val hash = method.hash if (!method.isConstructor && !superMethodsKeys.contains(hash) && method.getVisibility() != Visibilities.PRIVATE ) { superMethodsKeys.add(hash) - superMethods.add(method) + superMethods.add(Pair(method, definedAt)) } } - ancestorsSet.add(DRI.from(it)) + ancestorsSet.add(Ancestor(DRI.from(it), it.isInterface)) parseSupertypes(it.superTypes) } } @@ -145,12 +148,13 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { val (regularFunctions, accessors) = splitFunctionsAndAccessors() val documentation = javadocParser.parseDocumentation(this).toSourceSetDependent() val allFunctions = regularFunctions.mapNotNull { if (!it.isConstructor) parseFunction(it) else null } + - superMethods.map { parseFunction(it, isInherited = true) } + superMethods.map { parseFunction(it.first, inheritedFrom = it.second) } val source = PsiDocumentableSource(this).toSourceSetDependent() val classlikes = innerClasses.map { parseClasslike(it, dri) } val visibility = getVisibility().toSourceSetDependent() - val ancestors = ancestorsSet.toList().toSourceSetDependent() + val ancestors = ancestorsSet.toList().map { it.dri }.toSourceSetDependent() val modifiers = getModifier().toSourceSetDependent() + val implementedInterfacesExtra = ImplementedInterfaces(ancestorsSet.filter { it.isInterface }.map { it.dri }.toList()) return when { isAnnotationType -> DAnnotation( @@ -167,8 +171,8 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { constructors.map { parseFunction(it, true) }, mapTypeParameters(dri), setOf(sourceSetData), - PropertyContainer.empty() + annotations.toList().getAnnotations() - .toSourceSetDependent().toAnnotations() + PropertyContainer.withAll(implementedInterfacesExtra, annotations.toList().toListOfAnnotations().toSourceSetDependent() + .toAnnotations()) ) isEnum -> DEnum( dri, @@ -183,8 +187,8 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { emptyList(), emptyList(), setOf(sourceSetData), - PropertyContainer.empty() + entry.annotations.toList().getAnnotations() - .toSourceSetDependent().toAnnotations() + PropertyContainer.withAll(implementedInterfacesExtra, annotations.toList().toListOfAnnotations().toSourceSetDependent() + .toAnnotations()) ) }, documentation, @@ -198,8 +202,8 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { constructors.map { parseFunction(it, true) }, ancestors, setOf(sourceSetData), - PropertyContainer.empty() + annotations.toList().getAnnotations().toSourceSetDependent() - .toAnnotations() + PropertyContainer.withAll(implementedInterfacesExtra, annotations.toList().toListOfAnnotations().toSourceSetDependent() + .toAnnotations()) ) isInterface -> DInterface( dri, @@ -215,8 +219,8 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { mapTypeParameters(dri), ancestors, setOf(sourceSetData), - PropertyContainer.empty() + annotations.toList().getAnnotations().toSourceSetDependent() - .toAnnotations() + PropertyContainer.withAll(implementedInterfacesExtra, annotations.toList().toListOfAnnotations().toSourceSetDependent() + .toAnnotations()) ) else -> DClass( dri, @@ -234,8 +238,8 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { null, modifiers, setOf(sourceSetData), - PropertyContainer.empty() + annotations.toList().getAnnotations().toSourceSetDependent() - .toAnnotations() + PropertyContainer.withAll(implementedInterfacesExtra, annotations.toList().toListOfAnnotations().toSourceSetDependent() + .toAnnotations()) ) } } @@ -243,9 +247,10 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { private fun parseFunction( psi: PsiMethod, isConstructor: Boolean = false, - isInherited: Boolean = false + inheritedFrom: DRI? = null ): DFunction { val dri = DRI.from(psi) + val docs = javadocParser.parseDocumentation(psi).toSourceSetDependent() return DFunction( dri, if (isConstructor) "" else psi.name, @@ -254,13 +259,13 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { DParameter( dri.copy(target = dri.target.nextTarget()), psiParameter.name, - javadocParser.parseDocumentation(psiParameter).toSourceSetDependent(), + DocumentationNode(docs.entries.mapNotNull { it.value.children.filterIsInstance().firstOrNull { it.root.children.firstIsInstanceOrNull()?.children?.firstIsInstanceOrNull()?.body == psiParameter.name } }).toSourceSetDependent(), null, getBound(psiParameter.type), setOf(sourceSetData) ) }, - javadocParser.parseDocumentation(psi).toSourceSetDependent(), + docs, null, PsiDocumentableSource(psi).toSourceSetDependent(), psi.getVisibility().toSourceSetDependent(), @@ -271,9 +276,9 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { setOf(sourceSetData), psi.additionalExtras().let { PropertyContainer.withAll( - InheritedFunction(isInherited), + InheritedFunction(inheritedFrom), it.toSourceSetDependent().toAdditionalModifiers(), - (psi.annotations.toList().getAnnotations() + it.getAnnotations()).toSourceSetDependent() + (psi.annotations.toList().toListOfAnnotations() + it.toListOfAnnotations()).toSourceSetDependent() .toAnnotations() ) } @@ -291,7 +296,7 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { ).toSet() - private fun Set.getAnnotations() = map { + private fun Set.toListOfAnnotations() = map { if (it !is ExtraModifiers.JavaOnlyModifiers.Static) Annotations.Annotation(DRI("kotlin.jvm", it.name.toLowerCase().capitalize()), emptyMap()) else @@ -398,14 +403,14 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { psi.additionalExtras().let { PropertyContainer.withAll( it.toSourceSetDependent().toAdditionalModifiers(), - (psi.annotations.toList().getAnnotations() + it.getAnnotations()).toSourceSetDependent() + (psi.annotations.toList().toListOfAnnotations() + it.toListOfAnnotations()).toSourceSetDependent() .toAnnotations() ) } ) } - private fun Collection.getAnnotations() = + private fun Collection.toListOfAnnotations() = filter { it !is KtLightAbstractAnnotation }.mapNotNull { it.toAnnotation() } private fun JvmAnnotationAttribute.toValue(): AnnotationParameterValue = when (this) { @@ -436,4 +441,6 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { DRI.from(it) } } + + private data class Ancestor(val dri: DRI, val isInterface: Boolean) } diff --git a/plugins/base/src/test/kotlin/content/params/ContentForParamsTest.kt b/plugins/base/src/test/kotlin/content/params/ContentForParamsTest.kt index 335d834e..f66f88db 100644 --- a/plugins/base/src/test/kotlin/content/params/ContentForParamsTest.kt +++ b/plugins/base/src/test/kotlin/content/params/ContentForParamsTest.kt @@ -1,8 +1,18 @@ package content.params import matchers.content.* +import org.jetbrains.dokka.Platform +import org.jetbrains.dokka.model.DFunction +import org.jetbrains.dokka.model.Documentable +import org.jetbrains.dokka.model.SourceSetData +import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.model.doc.Param +import org.jetbrains.dokka.model.doc.Text import org.jetbrains.dokka.pages.ContentPage +import org.jetbrains.dokka.pages.MemberPageNode +import org.jetbrains.dokka.pages.dfs import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.junit.jupiter.api.Test import utils.* @@ -558,4 +568,45 @@ class ContentForParamsTest : AbstractCoreTest() { } } } + + @Test + fun javaDocCommentWithDocumentedParameters(){ + testInline( + """ + |/src/main/java/test/Main.java + |package test + | public class Main { + | + | /** + | * comment to function + | * @param first comment to first param + | * @param second comment to second param + | */ + | public void sample(String first, String second) { + | + | } + | } + """.trimIndent(), testConfiguration + ){ + pagesTransformationStage = { + module -> + val sampleFunction = module.dfs { + it is MemberPageNode && it.dri.first().toString() == "test/Main/sample/#java.lang.String#java.lang.String/PointingToDeclaration/" + } as MemberPageNode + val forJvm = (sampleFunction.documentable as DFunction).parameters.mapNotNull { + val jvm = it.documentation.keys.first { it.platform == Platform.jvm } + it.documentation[jvm] + } + + assert(forJvm.size == 2) + val (first, second) = forJvm.map { it.paramsDescription() } + assert(first == "comment to first param") + assert(second == "comment to second param") + } + } + } + + private fun DocumentationNode.paramsDescription(): String = + children.firstIsInstanceOrNull()?.root?.children?.firstIsInstanceOrNull()?.body.orEmpty() + } \ No newline at end of file diff --git a/plugins/base/src/test/kotlin/model/ClassesTest.kt b/plugins/base/src/test/kotlin/model/ClassesTest.kt index 5616a6c3..9121f9ae 100644 --- a/plugins/base/src/test/kotlin/model/ClassesTest.kt +++ b/plugins/base/src/test/kotlin/model/ClassesTest.kt @@ -1,6 +1,7 @@ package model import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.sureClassNames import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.KotlinModifier.* import org.junit.jupiter.api.Assertions.assertNull @@ -425,7 +426,7 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class """@Suppress("abc") class Foo() {}""" ) { with((this / "classes" / "Foo").cast()) { - with(extra[Annotations]!!.content.entries.single().value.firstOrNull().assertNotNull("annotations")) { + with(extra[Annotations]?.content?.firstOrNull().assertNotNull("annotations")) { dri.toString() equals "kotlin/Suppress///PointingToDeclaration/" (params["names"].assertNotNull("param") as ArrayValue).value equals listOf(StringValue("\"abc\"")) } @@ -483,4 +484,20 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class } } } + + @Test fun allImplementedInterfaces() { + inlineModelTest( + """ + | interface Highest { } + | open class HighestImpl: Highest { } + | interface Lower { } + | interface LowerImplInterface: Lower { } + | class Tested : HighestImpl(), LowerImplInterface { } + """.trimIndent() + ){ + with((this / "classes" / "Tested").cast()){ + extra[ImplementedInterfaces]?.interfaces?.map { it.sureClassNames }?.sorted() equals listOf("Highest", "Lower", "LowerImplInterface").sorted() + } + } + } } \ No newline at end of file diff --git a/plugins/base/src/test/kotlin/model/JavaTest.kt b/plugins/base/src/test/kotlin/model/JavaTest.kt index 8f52fcc8..77fcc666 100644 --- a/plugins/base/src/test/kotlin/model/JavaTest.kt +++ b/plugins/base/src/test/kotlin/model/JavaTest.kt @@ -2,16 +2,22 @@ package model import org.jetbrains.dokka.base.transformers.documentables.InheritorsInfo import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.sureClassNames import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.doc.Param +import org.jetbrains.dokka.model.doc.Text +import org.jetbrains.dokka.pages.dfs +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test import utils.AbstractModelTest import utils.assertNotNull +import utils.docs import utils.name class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { - @Test //todo params in comments + @Test fun function() { inlineModelTest( """ @@ -30,12 +36,27 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { children counts 1 with((this / "fn").cast()) { name equals "fn" - this + val params = parameters.map { it.documentation.values.first().children.first() as Param } + params.mapNotNull { it.root.children.firstIsInstanceOrNull()?.body } equals listOf("is String parameter", "is int parameter") } } } } + @Test fun allImplementedInterfacesInJava() { + inlineModelTest( + """ + |interface Highest { } + |interface Lower extends Highest { } + |class Extendable { } + |class Tested extends Extendable implements Lower { } + """){ + with((this / "java" / "Tested").cast()){ + extra[ImplementedInterfaces]?.interfaces?.map { it.sureClassNames }?.sorted() equals listOf("Highest", "Lower").sorted() + } + } + } + //@Test fun function() { // verifyJavaPackageMember("testdata/java/member.java", defaultModelConfig) { cls -> // assertEquals("Test", cls.name) 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 diff --git a/plugins/javadoc/src/main/resources/static_res/script.js b/plugins/javadoc/src/main/resources/static_res/script.js new file mode 100644 index 00000000..15fe6ac1 --- /dev/null +++ b/plugins/javadoc/src/main/resources/static_res/script.js @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +var moduleSearchIndex; +var packageSearchIndex; +var typeSearchIndex; +var memberSearchIndex; +var tagSearchIndex; +function loadScripts(doc, tag) { + createElem(doc, tag, 'jquery/jszip/dist/jszip.js'); + createElem(doc, tag, 'jquery/jszip-utils/dist/jszip-utils.js'); + if (window.navigator.userAgent.indexOf('MSIE ') > 0 || window.navigator.userAgent.indexOf('Trident/') > 0 || + window.navigator.userAgent.indexOf('Edge/') > 0) { + createElem(doc, tag, 'jquery/jszip-utils/dist/jszip-utils-ie.js'); + } + createElem(doc, tag, 'search.js'); + + $.get(pathtoroot + "module-search-index.zip") + .done(function() { + JSZipUtils.getBinaryContent(pathtoroot + "module-search-index.zip", function(e, data) { + var zip = new JSZip(data); + zip.load(data); + moduleSearchIndex = JSON.parse(zip.file("module-search-index.json").asText()); + }); + }); + $.get(pathtoroot + "package-search-index.zip") + .done(function() { + JSZipUtils.getBinaryContent(pathtoroot + "package-search-index.zip", function(e, data) { + var zip = new JSZip(data); + zip.load(data); + packageSearchIndex = JSON.parse(zip.file("package-search-index.json").asText()); + }); + }); + $.get(pathtoroot + "type-search-index.zip") + .done(function() { + JSZipUtils.getBinaryContent(pathtoroot + "type-search-index.zip", function(e, data) { + var zip = new JSZip(data); + zip.load(data); + typeSearchIndex = JSON.parse(zip.file("type-search-index.json").asText()); + }); + }); + $.get(pathtoroot + "member-search-index.zip") + .done(function() { + JSZipUtils.getBinaryContent(pathtoroot + "member-search-index.zip", function(e, data) { + var zip = new JSZip(data); + zip.load(data); + memberSearchIndex = JSON.parse(zip.file("member-search-index.json").asText()); + }); + }); + $.get(pathtoroot + "tag-search-index.zip") + .done(function() { + JSZipUtils.getBinaryContent(pathtoroot + "tag-search-index.zip", function(e, data) { + var zip = new JSZip(data); + zip.load(data); + tagSearchIndex = JSON.parse(zip.file("tag-search-index.json").asText()); + }); + }); + if (!moduleSearchIndex) { + createElem(doc, tag, 'module-search-index.js'); + } + if (!packageSearchIndex) { + createElem(doc, tag, 'package-search-index.js'); + } + if (!typeSearchIndex) { + createElem(doc, tag, 'type-search-index.js'); + } + if (!memberSearchIndex) { + createElem(doc, tag, 'member-search-index.js'); + } + if (!tagSearchIndex) { + createElem(doc, tag, 'tag-search-index.js'); + } + $(window).resize(function() { + $('.navPadding').css('padding-top', $('.fixedNav').css("height")); + }); +} + +function createElem(doc, tag, path) { + var script = doc.createElement(tag); + var scriptElement = doc.getElementsByTagName(tag)[0]; + script.src = pathtoroot + path; + scriptElement.parentNode.insertBefore(script, scriptElement); +} + +function show(type) { + count = 0; + for (var key in data) { + var row = document.getElementById(key); + if ((data[key] & type) !== 0) { + row.style.display = ''; + row.className = (count++ % 2) ? rowColor : altColor; + } + else + row.style.display = 'none'; + } + updateTabs(type); +} + +function updateTabs(type) { + for (var value in tabs) { + var sNode = document.getElementById(tabs[value][0]); + var spanNode = sNode.firstChild; + if (value == type) { + sNode.className = activeTableTab; + spanNode.innerHTML = tabs[value][1]; + } + else { + sNode.className = tableTab; + spanNode.innerHTML = "" + tabs[value][1] + ""; + } + } +} + +function updateModuleFrame(pFrame, cFrame) { + top.packageFrame.location = pFrame; + top.classFrame.location = cFrame; +} diff --git a/plugins/javadoc/src/main/resources/views/class.korte b/plugins/javadoc/src/main/resources/views/class.korte index 9b19df08..a9120fb2 100644 --- a/plugins/javadoc/src/main/resources/views/class.korte +++ b/plugins/javadoc/src/main/resources/views/class.korte @@ -1,2 +1,274 @@ {% extends "components/base.korte" %} -{% block content %} default {% end %} \ No newline at end of file +{% block content %} + +
+
+
Package {{ package }}
+

{{ kind|capitalize }} {{ name }}

+
+
+ +
+
    +
  • + {% if implementedInterfaces.size != 0 %} +
    +
    All Implemented Interfaces:
    +
    + {% for name in implementedInterfaces %} + {{ name }} + {% if !loop.last %} + , + {% endif %} + {% endfor %} +
    +
    + {% endif %} +
    +
    {{ signature|raw }}
    +
    {{ classlikeDocumentation }}
    +
  • +
+
+
+
    +
  • + + {% if classlikes.size != 0 %} +
    +
      +
    • + + +

      Nested Class Summary

      + + + + + + + + {% for classlike in classlikes %} + + + + + + {% endfor %} +
      Nested Classes 
      Modifier and TypeClassDescription
      {{ classlike.modifiers }}{{ classlike.signature }} + {{ classlike.description }}
      +
    • +
    +
    + {% endif %} + + {% if properties.size != 0 %} +
    +
      +
    • + + +

      Field Summary

      + + + + + + + + {% for property in properties %} + + + + + + {% endfor %} +
      Fields 
      Modifier and TypeFieldDescription
      {{ property.modifiers|raw }}{{ property.signature|raw }}{{ description|raw }}
      +
    • +
    +
    + {% endif %} + + {% if constructors.size != 0 %} +
    +
      +
    • + + +

      Constructor Summary

      + + + + + + + + + {% for constructor in constructors %} + + + + + {% endfor %} + + +
      Constructors 
      ConstructorDescription
      {{ constructor.name }}({{ constructor.inlineParameters }}){{ constructor.brief }}
      +
    • +
    +
    + {% endif %} + + {% if entries.size != 0 %} +
    +
      +
    • + + +

      Enum Constant Summary

      + + + + + + + {% for entry in entries %} + + + + + {% endfor %} +
      Enum Constants 
      Enum ConstantDescription
      {{ entry.signature|raw }}{{ entry.brief }}
      +
    • +
    +
    + {% endif %} + + {% if methods.own.size !=0 || methods.inherited.size != 0 %} +
    +
      +
    • + + +

      Method Summary

      + + + + + + + + + {% for method in methods.own %} + + + + + + {% endfor %} + +
      All Methods Static Methods Concrete Methods 
      Modifier and TypeMethodDescription
      {{ method.modifiers|raw }} + {{ method.signatureWithoutModifiers|raw }} + {{ method.brief|raw }}
      +
        + {% for method in methods.inherited %} +
      • + + +

        Methods inherited from class {{ method.inheritedFrom}}

        + {{ method.names }}
      • + {% endfor %} +
      • + + +

        Methods inherited from class java.lang.Object

        + clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, + wait, wait, wait
      • +
      +
    • +
    +
    + {% endif %} +
  • +
+
+
+
    +
  • + + {% if constructors.size != 0 %} +
    +
      +
    • + + +

      Constructor Detail

      + {% for constructor in constructors %} + + + +
        +
      • +

        {{ constructor.name }}

        +
        {{ constructor.name }}({{ constructor.inlineParameters }})
        +
        {{ constructor.brief }}
        + {% if constructor.parameters.size != 0 && hasAnyDescription(constructor.parameters) %} +
        +
        Parameters:
        + {% for parameter in constructor.parameters %} + {% if parameter.description != "" %} +
        {{ parameter.name }} - {{ parameter.description }}
        + {% endif %} + {% endfor %} +
        + {% endif %} +
      • +
      + {% endfor %} +
    • +
    +
    + {% endif %} + + {% if methods.own.size != 0 %} +
    +
      +
    • + + +

      Method Detail

      + {% for method in methods.own %} + + + +
        +
      • +

        {{ method.name }}

        +
        {{ method.signature|raw }}
        +
        {{ method.brief|raw }}
        + +
      • +
      + {% endfor %} +
    • +
    +
    + {% endif %} +
  • +
+
+
+
+{% end %} \ No newline at end of file diff --git a/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt b/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt index 94eda40f..07636071 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt @@ -33,7 +33,9 @@ class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogge ) } - private fun signature(e: DEnumEntry) = contentBuilder.contentFor(e, ContentKind.Symbol, setOf(TextStyle.Monospace)) + private fun signature(e: DEnumEntry) = contentBuilder.contentFor(e, ContentKind.Symbol, setOf(TextStyle.Monospace)){ + link(e.name, e.dri) + } private fun signature(c: DClasslike) = contentBuilder.contentFor(c, ContentKind.Symbol, setOf(TextStyle.Monospace)) { -- cgit From a1c316e829827ddb0e3e288e684ac287e8fd28ff Mon Sep 17 00:00:00 2001 From: Błażej Kardyś Date: Tue, 23 Jun 2020 22:25:18 +0200 Subject: Briefs raw rendering and basic url handling --- .gitignore | 1 + plugins/base/.gitignore | 3 +- .../src/main/kotlin/renderers/DefaultRenderer.kt | 2 +- .../src/main/kotlin/renderers/html/HtmlRenderer.kt | 2 +- .../resolvers/local/DefaultLocationProvider.kt | 2 +- .../kotlin/resolvers/local/LocationProvider.kt | 2 +- .../resolvers/local/MultimoduleLocationProvider.kt | 2 +- .../main/kotlin/javadoc/JavadocLocationProvider.kt | 2 +- .../src/main/kotlin/javadoc/JavadocPageCreator.kt | 22 +- .../src/main/kotlin/javadoc/JavadocPlugin.kt | 8 +- .../main/kotlin/javadoc/KorteJavadocRenderer.kt | 402 --------------------- .../renderer/JavadocContentToHtmlTranslator.kt | 66 ++++ .../JavadocContentToTemplateMapTranslator.kt | 203 +++++++++++ .../javadoc/renderer/KorteJavadocRenderer.kt | 186 ++++++++++ .../javadoc/src/main/resources/views/class.korte | 8 +- .../resources/views/components/indexPage.korte | 2 +- 16 files changed, 487 insertions(+), 426 deletions(-) create mode 100644 plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt create mode 100644 plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt create mode 100644 plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt (limited to 'plugins/javadoc/src/main/resources/views/class.korte') diff --git a/.gitignore b/.gitignore index 13060d89..7d0c8a6a 100644 --- a/.gitignore +++ b/.gitignore @@ -103,3 +103,4 @@ runners/**/out/ .idea plugins/base/src/main/resources/dokka/scripts/main.js plugins/base/src/main/resources/dokka/scripts/main.js.map +/.idea/compiler.xml diff --git a/plugins/base/.gitignore b/plugins/base/.gitignore index a259cd26..d68571db 100644 --- a/plugins/base/.gitignore +++ b/plugins/base/.gitignore @@ -1,2 +1,3 @@ src/main/resources/dokka/scripts/main.js -src/main/resources/dokka/scripts/main.js.map \ No newline at end of file +src/main/resources/dokka/scripts/main.js.map +search-component/dist/ \ No newline at end of file diff --git a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt index 09d6cad1..4313f1e3 100644 --- a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt @@ -104,7 +104,7 @@ abstract class DefaultRenderer( is ContentHeader -> buildHeader(node, pageContext, sourceSetRestriction) is ContentCode -> buildCode(node, pageContext) is ContentDRILink -> - buildLink(locationProvider.resolve(node.address, node.sourceSets.toList(), pageContext)) { + buildLink(locationProvider.resolve(node.address, node.sourceSets, pageContext)) { buildLinkText(node.children, pageContext, sourceSetRestriction) } is ContentResolvedLink -> buildLink(node.address) { diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt index d56ab50c..de892bb1 100644 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt @@ -526,7 +526,7 @@ open class HtmlRenderer( platforms: List, from: PageNode? = null, block: FlowContent.() -> Unit - ) = buildLink(locationProvider.resolve(to, platforms, from), block) + ) = buildLink(locationProvider.resolve(to, platforms.toSet(), from), block) override fun buildError(node: ContentNode) { context.logger.error("Unknown ContentNode type: $node") diff --git a/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt index 4d44fdef..6c4869d8 100644 --- a/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt +++ b/plugins/base/src/main/kotlin/resolvers/local/DefaultLocationProvider.kt @@ -46,7 +46,7 @@ open class DefaultLocationProvider( override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean): String = pathTo(node, context) + if (!skipExtension) extension else "" - override fun resolve(dri: DRI, sourceSets: List, context: PageNode?): String = + override fun resolve(dri: DRI, sourceSets: Set, context: PageNode?): String = pagesIndex[dri]?.let { resolve(it, context) } ?: // Not found in PageGraph, that means it's an external link getLocation( diff --git a/plugins/base/src/main/kotlin/resolvers/local/LocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/LocationProvider.kt index d6d616f3..745636d0 100644 --- a/plugins/base/src/main/kotlin/resolvers/local/LocationProvider.kt +++ b/plugins/base/src/main/kotlin/resolvers/local/LocationProvider.kt @@ -6,7 +6,7 @@ import org.jetbrains.dokka.pages.PageNode import org.jetbrains.dokka.pages.RootPageNode interface LocationProvider { - fun resolve(dri: DRI, sourceSets: List, context: PageNode? = null): String + fun resolve(dri: DRI, sourceSets: Set, context: PageNode? = null): String fun resolve(node: PageNode, context: PageNode? = null, skipExtension: Boolean = false): String fun resolveRoot(node: PageNode): String fun ancestors(node: PageNode): List diff --git a/plugins/base/src/main/kotlin/resolvers/local/MultimoduleLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/MultimoduleLocationProvider.kt index 39b005a1..1d41bce0 100644 --- a/plugins/base/src/main/kotlin/resolvers/local/MultimoduleLocationProvider.kt +++ b/plugins/base/src/main/kotlin/resolvers/local/MultimoduleLocationProvider.kt @@ -14,7 +14,7 @@ class MultimoduleLocationProvider(private val root: RootPageNode, context: Dokka it.name to it.path }.toMap() - override fun resolve(dri: DRI, sourceSets: List, context: PageNode?): String = + override fun resolve(dri: DRI, sourceSets: Set, context: PageNode?): String = dri.takeIf { it.packageName == MULTIMODULE_PACKAGE_PLACEHOLDER }?.classNames?.let { paths[it] }?.let { "$it/${dri.classNames}/index.html" } ?: defaultLocationProvider.resolve(dri, sourceSets, context) diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt index f8ecf868..d731ec5f 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocLocationProvider.kt @@ -65,7 +65,7 @@ class JavadocLocationProvider(pageRoot: RootPageNode, private val context: Dokka private operator fun IdentityHashMap>.get(dri: DRI) = this[nodeIndex[dri]] - override fun resolve(dri: DRI, sourceSets: List, context: PageNode?): String = + override fun resolve(dri: DRI, sourceSets: Set, context: PageNode?): String = context?.let { resolve(it, skipExtension = false) } ?: nodeIndex[dri]?.let { resolve(it, skipExtension = true) } ?: with(externalLocationProvider!!) { diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt index 3074a760..12c53ab7 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt @@ -39,19 +39,19 @@ open class JavadocPageCreator( ) fun pageForClasslike(c: DClasslike): JavadocClasslikePageNode? = - c.mostTopSourceSet?.let { jvm -> + c.highestJvmSourceSet?.let { jvm -> JavadocClasslikePageNode( name = c.name.orEmpty(), content = contentForClasslike(c), dri = setOf(c.dri), modifiers = listOfNotNull(c.visibility[jvm]?.name), - signature = signatureProvider.signature(c).jvmSignature(), + signature = signatureProvider.signature(c).nodeForJvm(jvm), description = c.descriptionToContentNodes(), 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).jvmSignature(), it.descriptionToContentNodes(jvm)) }.orEmpty(), + entries = c.safeAs()?.entries?.map { JavadocEntryNode(signatureProvider.signature(it).nodeForJvm(jvm), it.descriptionToContentNodes(jvm)) }.orEmpty(), classlikes = c.classlikes.mapNotNull { pageForClasslike(it) }, - properties = c.properties.map { JavadocPropertyNode(signatureProvider.signature(it).jvmSignature(), it.descriptionToContentNodes(jvm)) }, + properties = c.properties.map { JavadocPropertyNode(signatureProvider.signature(it).nodeForJvm(jvm), it.descriptionToContentNodes(jvm)) }, documentable = c, extras = c.safeAs>()?.extra ?: PropertyContainer.empty() ) @@ -129,7 +129,7 @@ open class JavadocPageCreator( private fun DFunction.toJavadocFunction(sourceSetData: DokkaSourceSet) = JavadocFunctionNode( name = name, - signature = signatureProvider.signature(this).jvmSignature(), + signature = signatureProvider.signature(this).nodeForJvm(sourceSetData), brief = brief(sourceSetData), parameters = parameters.map { JavadocParameterNode( @@ -141,21 +141,20 @@ open class JavadocPageCreator( extras = extra ) - // THIS MUST BE DISCUSSED private val Documentable.jvmSource get() = sourceSets.filter { it.analysisPlatform == Platform.jvm } - private val Documentable.mostTopSourceSet + private val Documentable.highestJvmSourceSet get() = jvmSource.let { sources -> sources.firstOrNull { it != expectPresentInSet } ?: sources.firstOrNull() } private val firstSentenceRegex = Regex("^((?:[^.?!]|[.!?](?!\\s))*[.!?])") - private inline fun Documentable.findNodeInDocumentation(sourceSetData: SourceSetData?): T? = + private inline fun Documentable.findNodeInDocumentation(sourceSetData: DokkaSourceSet?): T? = documentation[sourceSetData]?.firstChildOfType() - private fun Documentable.descriptionToContentNodes(sourceSet: SourceSetData? = mostTopSourceSet) = findNodeInDocumentation(sourceSet)?.let { + private fun Documentable.descriptionToContentNodes(sourceSet: DokkaSourceSet? = highestJvmSourceSet) = findNodeInDocumentation(sourceSet)?.let { DocTagToContentConverter.buildContent( it.root, DCI(setOf(dri), JavadocContentKind.OverviewSummary), @@ -163,7 +162,10 @@ open class JavadocPageCreator( ) }.orEmpty() - private fun Documentable.brief(sourceSet: SourceSetData? = mostTopSourceSet): List { + fun List.nodeForJvm(jvm: DokkaSourceSet): ContentNode = + first { it.sourceSets.contains(jvm) } + + private fun Documentable.brief(sourceSet: DokkaSourceSet? = highestJvmSourceSet): List { val description = descriptionToContentNodes(sourceSet) val contents = mutableListOf() for (node in description) { diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt index a90e46db..504eecfd 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt @@ -1,7 +1,7 @@ package org.jetbrains.dokka.javadoc import javadoc.JavadocDocumentableToPageTranslator -import javadoc.KorteJavadocRenderer +import javadoc.renderer.KorteJavadocRenderer import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.plugability.DokkaPlugin @@ -12,7 +12,11 @@ class JavadocPlugin : DokkaPlugin() { val dokkaJavadocPlugin by extending { val dokkaBasePlugin = plugin() CoreExtensions.renderer providing { ctx -> - KorteJavadocRenderer(dokkaBasePlugin.querySingle { outputWriter }, ctx, "views") + KorteJavadocRenderer( + dokkaBasePlugin.querySingle { outputWriter }, + ctx, + "views" + ) } applyIf { format == "javadoc" } } diff --git a/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt b/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt index cec5bbca..e69de29b 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt @@ -1,402 +0,0 @@ -package javadoc - -import com.soywiz.korte.* -import javadoc.pages.* -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import org.jetbrains.dokka.Platform -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.DokkaConfiguration.DokkaSourceSet -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 TemplateMap = Map - -class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaContext, val resourceDir: String) : - Renderer { - private lateinit var locationProvider: JavadocLocationProvider - - override fun render(root: RootPageNode) = root.let { preprocessors.fold(root) { r, t -> t.invoke(r) } }.let { r -> - locationProvider = JavadocLocationProvider(r, context) - runBlocking(Dispatchers.IO) { - renderModulePageNode(r as JavadocModulePageNode) - } - } - - private fun templateForNode(node: JavadocPageNode) = when (node) { - is JavadocClasslikePageNode -> "class.korte" - is JavadocPackagePageNode -> "tabPage.korte" - is JavadocModulePageNode -> "tabPage.korte" - is AllClassesPage -> "listPage.korte" - is TreeViewPage -> "treePage.korte" - else -> "" - } - - private fun CoroutineScope.renderNode(node: PageNode, path: String = "") { - if (node is JavadocPageNode) { - renderJavadocNode(node) - } else if (node is RendererSpecificPage) { - renderSpecificPage(node, path) - } - } - - private fun CoroutineScope.renderModulePageNode(node: JavadocModulePageNode) { - val link = "." - val name = "index" - val pathToRoot = "" - - val contentMap = mapOf( - "docName" to "docName", // todo docname - "pathToRoot" to pathToRoot, - "kind" to "main", - ) + ContentNodesRenderer(pathToRoot).renderJavadocContentNode(node.content) - - writeFromTemplate(outputWriter, "$link/$name".toNormalized(), "tabPage.korte", contentMap.toList()) - node.children.forEach { renderNode(it, link) } - } - - private fun CoroutineScope.renderJavadocNode(node: JavadocPageNode) { - val link = locationProvider.resolve(node, skipExtension = true) - val dir = Paths.get(link).parent?.let { it.toNormalized() }.orEmpty() - val pathToRoot = dir.split("/").filter { it.isNotEmpty() }.joinToString("/") { ".." }.let { - if (it.isNotEmpty()) "$it/" else it - } - - val contentMap = mapOf( - "docName" to "docName", // todo docname - "pathToRoot" to pathToRoot, - "dir" to dir - ) + ContentNodesRenderer(dir).renderContentNodes(node) - writeFromTemplate(outputWriter, link, templateForNode(node), contentMap.toList()) - node.children.forEach { renderNode(it, link.toNormalized()) } - } - - fun CoroutineScope.renderSpecificPage(node: RendererSpecificPage, path: String) = launch { - when (val strategy = node.strategy) { - is RenderingStrategy.Copy -> outputWriter.writeResources(strategy.from, "") - is RenderingStrategy.Write -> outputWriter.writeHtml(path, strategy.text) - is RenderingStrategy.Callback -> outputWriter.writeResources( - path, - strategy.instructions(this@KorteJavadocRenderer, node) - ) - RenderingStrategy.DoNothing -> Unit - } - } - - fun Pair.pairToTag() = - "\n${first}\n${second}" - - fun DRI.toLink(context: PageNode? = null) = locationProvider.resolve(this, emptyList(), context) - - fun createLinkTag(address: String, name: String) = - address.let { if (it.endsWith(".html")) it else "$it.html" }.let { - """$name""" - } - - private fun Path.toNormalized() = this.normalize().toFile().toString() - private fun String.toNormalized() = Paths.get(this).toNormalized() - private fun String.relativizePath(parent: String) = Paths.get(parent).relativize(Paths.get(this)).toNormalized() - - private suspend fun OutputWriter.writeHtml(path: String, text: String) = write(path, text, ".html") - private fun CoroutineScope.writeFromTemplate( - writer: OutputWriter, - path: String, - template: String, - args: List> - ) = launch { - val tmp = templateRenderer.render(template, *(args.toTypedArray())) - writer.writeHtml(path, tmp) - } - - private fun htmlForContentNodes(content: List, render: (ContentNode) -> String): String = - content.joinToString("") { render(it) } - - fun getTemplateConfig() = TemplateConfig().also { config -> - listOf( - TeFunction("curDate") { LocalDate.now() }, - TeFunction("jQueryVersion") { "3.1" }, - TeFunction("jQueryMigrateVersion") { "1.2.1" }, - TeFunction("rowColor") { args -> if ((args.first() as Int) % 2 == 0) "altColor" else "rowColor" }, - TeFunction("h1Title") { args -> if ((args.first() as? String) == "package") "title=\"Package\" " else "" }, - TeFunction("createTabRow") { args -> - val (link, doc) = args.first() as RowJavadocListEntry - val dir = args[1] as String? - val renderer = ContentNodesRenderer(dir) - (createLinkTag( - locationProvider.resolve(link, dir.orEmpty()), - link.name - ) to htmlForContentNodes(doc, renderer::htmlForContentNode)).pairToTag().trim() - }, - TeFunction("createListRow") { args -> - val link = args.first() as LinkJavadocListEntry - val dir = args[1] as String? - createLinkTag(locationProvider.resolve(link, dir.orEmpty()), link.name) - }, - TeFunction("createPackageHierarchy") { args -> - val list = args.first() as List - list.mapIndexed { i, p -> - val content = if (i + 1 == list.size) "" else ", " - val name = p.name - "
  • $name$content
  • " - }.joinToString("\n") - }, - TeFunction("renderInheritanceGraph") { args -> - val rootNodes = args.first() as List - - fun drawRec(node: TreeViewPage.InheritanceNode): String { - val returnValue = "
  • " + node.dri.let { dri -> - listOfNotNull( - dri.packageName, - dri.classNames - ).joinToString(".") + node.interfaces.takeUnless { node.isInterface || it.isEmpty() } - ?.let { - " implements " + it.joinToString(", ") { n -> - listOfNotNull( - n.packageName, - createLinkTag(n.toLink(), n.classNames.orEmpty()) - ).joinToString(".") - } - }.orEmpty() - } + node.children.filterNot { it.isInterface }.takeUnless { it.isEmpty() }?.let { - "
      " + it.joinToString("\n", transform = ::drawRec) + "
    " - }.orEmpty() + "
  • " - return returnValue - } - rootNodes.joinToString { drawRec(it) } - }, - Filter("length") { subject.dynamicLength() }, - TeFunction("hasAnyDescription") { args -> - args.first().safeAs>>() - ?.any { it["description"]?.trim()?.isNotEmpty() ?: false } - } - ).forEach { - when (it) { - is TeFunction -> config.register(it) - is Filter -> config.register(it) - is Tag -> config.register(it) - } - } - } - - val config = getTemplateConfig() - val templateRenderer = Templates(ResourceTemplateProvider(resourceDir), config = config, cache = true) - - class ResourceTemplateProvider(val basePath: String) : TemplateProvider { - override suspend fun get(template: String): String = - javaClass.classLoader.getResourceAsStream("$basePath/$template")?.bufferedReader()?.lines()?.toArray() - ?.joinToString("\n") ?: throw IllegalStateException("Template not found: $basePath/$template") - } - - private inner class ContentNodesRenderer(private val currentLocation: String?) { - fun renderContentNodes(node: JavadocPageNode): TemplateMap = - when (node) { - is JavadocClasslikePageNode -> renderClasslikeNode(node) - is JavadocFunctionNode -> renderFunctionNode(node) - is JavadocPackagePageNode -> renderPackagePageNode(node) - is TreeViewPage -> renderTreeViewPage(node) - is AllClassesPage -> renderAllClassesPage(node) - else -> emptyMap() - } - - - private fun renderAllClassesPage(node: AllClassesPage): TemplateMap { - return mapOf( - "title" to "All Classes", - "list" to node.classEntries - ) - } - - private fun renderTreeViewPage(node: TreeViewPage): TemplateMap { - return mapOf( - "title" to node.title, - "name" to node.name, - "kind" to node.kind, - "list" to node.packages.orEmpty() + node.classes.orEmpty(), - "classGraph" to node.classGraph, - "interfaceGraph" to node.interfaceGraph - ) - } - - private fun renderPackagePageNode(node: JavadocPackagePageNode): TemplateMap { - return mapOf( - "kind" to "package" - ) + renderJavadocContentNode(node.content) - } - - private fun renderFunctionNode(node: JavadocFunctionNode): TemplateMap { - val (modifiers, signature) = node.modifiersAndSignature - return mapOf( - "signature" to htmlForContentNode(node.signature), - "brief" to htmlForContentNodes(node.brief), - "parameters" to node.parameters.map { renderParameterNode(it) }, - "inlineParameters" to node.parameters.joinToString { "${it.type} ${it.name}" }, - "modifiers" to htmlForContentNode(modifiers), - "signatureWithoutModifiers" to htmlForContentNode(signature), - "name" to node.name - ) - } - - private fun renderParameterNode(node: JavadocParameterNode): TemplateMap = - mapOf( - "description" to htmlForContentNodes(node.description), - "name" to node.name, - "type" to node.type - ) - - private fun renderClasslikeNode(node: JavadocClasslikePageNode): TemplateMap = - mapOf( - "constructors" to node.constructors.map { renderContentNodes(it) }, - "signature" to htmlForContentNode(node.signature), - "methods" to renderClasslikeMethods(node.methods), - "classlikeDocumentation" to renderContentNodes(node.description), - "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), - "kind" to node.kind, - "packageName" to node.packageName, - "name" to node.name - ) + renderJavadocContentNode(node.content) - - private fun renderImplementedInterfaces(node: JavadocClasslikePageNode) = - node.extras[ImplementedInterfaces]?.interfaces?.entries?.firstOrNull { it.key.analysisPlatform == Platform.jvm }?.value?.map { it.displayable() } // TODO: REMOVE HARDCODED JVM DEPENDENCY - .orEmpty() - - private fun renderClasslikeMethods(nodes: List): TemplateMap { - val (inherited, own) = nodes.partition { - val extra = it.extras[InheritedFunction] - extra?.inheritedFrom?.keys?.first { it.analysisPlatform == Platform.jvm }?.let { jvm -> - extra.isInherited(jvm) - } ?: 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): TemplateMap { - val inheritedFrom = node.extras[InheritedFunction]?.inheritedFrom - return mapOf( - "inheritedFrom" to inheritedFrom?.entries?.firstOrNull { it.key.analysisPlatform == Platform.jvm }?.value?.displayable() // TODO: REMOVE HARDCODED JVM DEPENDENCY - .orEmpty(), - "name" to node.name - ) - } - - private fun renderNestedClasslikeNode(node: JavadocClasslikePageNode): TemplateMap { - return mapOf( - "modifiers" to (node.modifiers + "static" + node.kind).joinToString(separator = " "), - "signature" to node.name, - "description" to renderContentNodes(node.description) - ) - } - - private fun renderPropertyNode(node: JavadocPropertyNode): TemplateMap { - val (modifiers, signature) = node.modifiersAndSignature - return mapOf( - "modifiers" to htmlForContentNode(modifiers), - "signature" to htmlForContentNode(signature), - "description" to htmlForContentNodes(node.brief) - ) - } - - private fun renderEntryNode(node: JavadocEntryNode): TemplateMap { - return mapOf( - "signature" to htmlForContentNode(node.signature), - "brief" to node.brief - ) - } - - private fun renderContentNodes(nodes: List): String = nodes.joinToString(separator = "") { htmlForContentNode(it) } - - fun htmlForContentNode(node: ContentNode): String = - when (node) { - is ContentGroup -> node.children.joinToString(separator = "") { htmlForContentNode(it) } - is ContentText -> node.text - is TextNode -> node.text - is ContentDRILink -> """${node.children.joinToString { htmlForContentNode(it) }} """.trimMargin() - is ContentCode -> renderCode(node.children) - else -> "" - } - - private fun renderCode(code: List) : String = code.map { element -> - when (element) { - is ContentText -> element.text - is ContentBreakLine -> "" - else -> run { context.logger.error("Cannot cast $element as ContentText!"); "" } - } - }.joinToString("
    ", "", "") { it } - - fun renderJavadocContentNode(node: JavadocContentNode): TemplateMap = when (node) { - is TitleNode -> renderTitleNode(node) - is JavadocContentGroup -> renderJavadocContentGroup(node) - is TextNode -> renderTextNode(node) - is ListNode -> renderListNode(node) - else -> emptyMap() - } - - private fun renderTitleNode(node: TitleNode): TemplateMap { - return mapOf( - "title" to node.title, - "subtitle" to htmlForContentNodes(node.subtitle), - "version" to node.version, - "packageName" to node.parent - ) - } - - private fun renderJavadocContentGroup(note: JavadocContentGroup): TemplateMap { - return note.children.fold(emptyMap()) { map, child -> - map + renderJavadocContentNode(child) - } - } - - private fun renderTextNode(node: TextNode): TemplateMap { - return mapOf("text" to node.text) - } - - private fun renderListNode(node: ListNode): TemplateMap { - return mapOf( - "tabTitle" to node.tabTitle, - "colTitle" to node.colTitle, - "list" to node.children - ) - } - - private fun resolveLink(address: DRI, sourceSets: Set) = - locationProvider.resolve(address, sourceSets.toList()).let { - val afterFormattingToHtml = formatToEndWithHtml(it) - if (currentLocation != null) afterFormattingToHtml.relativizePath(currentLocation) - else afterFormattingToHtml - } - - private fun formatToEndWithHtml(address: String) = - if (address.endsWith(".html")) { - address - } else { - "$address.html" - } - - private fun DRI.displayable(): String = "${packageName}.${sureClassNames}" - } -} \ No newline at end of file diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt new file mode 100644 index 00000000..5f628626 --- /dev/null +++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt @@ -0,0 +1,66 @@ +package javadoc.renderer + +import javadoc.pages.TextNode +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.base.resolvers.local.LocationProvider +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext +import java.nio.file.Path +import java.nio.file.Paths + +internal class JavadocContentToHtmlTranslator( + private val locationProvider: LocationProvider, + private val context: DokkaContext +) { + + fun htmlForContentNode(node: ContentNode, relative: T?, locate: ContentDRILink.(T?) -> String): String = + when (node) { + is ContentGroup -> htmlForContentNodes(node.children, relative, locate) + is ContentText -> node.text + is TextNode -> node.text + is ContentDRILink -> buildLink( + node.locate(relative), + htmlForContentNodes(node.children, relative, locate) + ) + is ContentResolvedLink -> buildLink(node.address, htmlForContentNodes(node.children, relative, locate)) + is ContentCode -> htmlForCode(node.children) + else -> "" + } + + fun htmlForContentNodes(list: List, relative: T?, locate: ContentDRILink.(T?) -> String) = + list.joinToString(separator = "") { htmlForContentNode(it, relative, locate) } + + private fun locate(link: ContentDRILink, relativePath: String?) = + resolveLink(link.address, link.sourceSets, relativePath) + + fun htmlForContentNodes(list: List, relative: String?) = + htmlForContentNodes(list, relative, ::locate) + + private fun htmlForCode(code: List): String = code.map { element -> + when (element) { + is ContentText -> element.text + is ContentBreakLine -> "" + else -> run { context.logger.error("Cannot cast $element as ContentText!"); "" } + } + }.joinToString("
    ", """""", "") { it } + + private fun resolveLink(address: DRI, sourceSets: Set, relativePath: String?) = + locationProvider.resolve(address, sourceSets).let { + val afterFormattingToHtml = it.formatToEndWithHtml() + if (relativePath != null) afterFormattingToHtml.relativizePath(relativePath) + else afterFormattingToHtml + } + + private fun String.relativizePath(parent: String) = + Paths.get(parent).relativize(Paths.get(this)).normalize().toFile().toString() + + companion object { + + fun buildLink(address: String, content: String) = + """$content""" + + private fun String.formatToEndWithHtml() = + if (endsWith(".html")) this else "$this.html" + } +} \ No newline at end of file diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt new file mode 100644 index 00000000..4d1ccca5 --- /dev/null +++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt @@ -0,0 +1,203 @@ +package javadoc.renderer + +import javadoc.pages.* +import org.jetbrains.dokka.Platform +import org.jetbrains.dokka.base.resolvers.local.LocationProvider +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 + +internal class JavadocContentToTemplateMapTranslator( + private val locationProvider: LocationProvider, + private val context: DokkaContext, +) { + + fun templateMapForPageNode(node: JavadocPageNode, pathToRoot: String): TemplateMap = + mapOf( + "docName" to "docName", // todo docname + "pathToRoot" to pathToRoot, + "kind" to "main", + ) + templateMapForNode(node) + + + fun templateMapForNode(node: JavadocPageNode): TemplateMap = + when (node) { + is JavadocModulePageNode -> InnerTranslator(node).templateMapForJavadocContentNode(node.content) + is JavadocClasslikePageNode -> InnerTranslator(node).templateMapForClasslikeNode(node) + is JavadocFunctionNode -> InnerTranslator(node).templateMapForFunctionNode(node) + is JavadocPackagePageNode -> InnerTranslator(node).templateMapForPackagePageNode(node) + is TreeViewPage -> InnerTranslator(node).templateMapForTreeViewPage(node) + is AllClassesPage -> InnerTranslator(node).templateMapForAllClassesPage(node) + else -> emptyMap() + } + + private inner class InnerTranslator(val contextNode: PageNode) { + + private val htmlTranslator = JavadocContentToHtmlTranslator(locationProvider, context) + + internal fun templateMapForAllClassesPage(node: AllClassesPage): TemplateMap { + return mapOf( + "title" to "All Classes", + "list" to node.classEntries + ) + } + + internal fun templateMapForTreeViewPage(node: TreeViewPage): TemplateMap { + return mapOf( + "title" to node.title, + "name" to node.name, + "kind" to node.kind, + "list" to node.packages.orEmpty() + node.classes.orEmpty(), + "classGraph" to node.classGraph, + "interfaceGraph" to node.interfaceGraph + ) + } + + internal fun templateMapForPackagePageNode(node: JavadocPackagePageNode): TemplateMap { + return mapOf( + "kind" to "package" + ) + templateMapForJavadocContentNode(node.content) + } + + internal fun templateMapForFunctionNode(node: JavadocFunctionNode): TemplateMap { + val (modifiers, signature) = node.modifiersAndSignature + return mapOf( + "signature" to htmlForContentNode(node.signature, node), + "brief" to htmlForContentNodes(node.brief, node), + "parameters" to node.parameters.map { templateMapForParameterNode(it) }, + "inlineParameters" to node.parameters.joinToString { "${it.type} ${it.name}" }, + "modifiers" to htmlForContentNode(modifiers, node), + "signatureWithoutModifiers" to htmlForContentNode(signature, node), + "name" to node.name + ) + } + + internal fun templateMapForClasslikeNode(node: JavadocClasslikePageNode): TemplateMap = + mapOf( + "constructors" to node.constructors.map { templateMapForNode(it) }, + "signature" to htmlForContentNode(node.signature, node), + "methods" to templateMapForClasslikeMethods(node.methods), + "classlikeDocumentation" to htmlForContentNodes(node.description, node), + "entries" to node.entries.map { templateMapForEntryNode(it) }, + "properties" to node.properties.map { templateMapForPropertyNode(it) }, + "classlikes" to node.classlikes.map { templateMapForNestedClasslikeNode(it) }, + "implementedInterfaces" to templateMapForImplementedInterfaces(node), + "kind" to node.kind, + "packageName" to node.packageName, + "name" to node.name + ) + templateMapForJavadocContentNode(node.content) + + internal fun templateMapForJavadocContentNode(node: JavadocContentNode): TemplateMap = + when (node) { + is TitleNode -> templateMapForTitleNode(node) + is JavadocContentGroup -> templateMapForJavadocContentGroup(node) + is TextNode -> templateMapForTextNode(node) + is ListNode -> templateMapForListNode(node) + else -> emptyMap() + } + + private fun templateMapForParameterNode(node: JavadocParameterNode): TemplateMap = + mapOf( + "description" to htmlForContentNodes(node.description, contextNode), + "name" to node.name, + "type" to node.type + ) + + private fun templateMapForImplementedInterfaces(node: JavadocClasslikePageNode) = + node.extras[ImplementedInterfaces]?.interfaces?.entries?.firstOrNull { it.key.analysisPlatform == Platform.jvm }?.value?.map { it.displayable() } // TODO: REMOVE HARDCODED JVM DEPENDENCY + .orEmpty() + + private fun templateMapForClasslikeMethods(nodes: List): TemplateMap { + val (inherited, own) = nodes.partition { + val extra = it.extras[InheritedFunction] + extra?.inheritedFrom?.keys?.first { it.analysisPlatform == Platform.jvm }?.let { jvm -> + extra.isInherited(jvm) + } ?: false + } + return mapOf( + "own" to own.map { templateMapForNode(it) }, + "inherited" to inherited.map { templateMapForInheritedMethod(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 templateMapForInheritedMethod(node: JavadocFunctionNode): TemplateMap { + val inheritedFrom = node.extras[InheritedFunction]?.inheritedFrom + return mapOf( + "inheritedFrom" to inheritedFrom?.entries?.firstOrNull { it.key.analysisPlatform == Platform.jvm }?.value?.displayable() // TODO: REMOVE HARDCODED JVM DEPENDENCY + .orEmpty(), + "name" to node.name + ) + } + + private fun templateMapForNestedClasslikeNode(node: JavadocClasslikePageNode): TemplateMap { + return mapOf( + "modifiers" to (node.modifiers + "static" + node.kind).joinToString(separator = " "), + "signature" to node.name, + "description" to htmlForContentNodes(node.description, node) + ) + } + + private fun templateMapForPropertyNode(node: JavadocPropertyNode): TemplateMap { + val (modifiers, signature) = node.modifiersAndSignature + return mapOf( + "modifiers" to htmlForContentNode(modifiers, contextNode), + "signature" to htmlForContentNode(signature, contextNode), + "description" to htmlForContentNodes(node.brief, contextNode) + ) + } + + private fun templateMapForEntryNode(node: JavadocEntryNode): TemplateMap { + return mapOf( + "signature" to htmlForContentNode(node.signature, contextNode), + "brief" to node.brief + ) + } + + private fun templateMapForTitleNode(node: TitleNode): TemplateMap { + return mapOf( + "title" to node.title, + "subtitle" to htmlForContentNodes(node.subtitle, contextNode), + "version" to node.version, + "packageName" to node.parent + ) + } + + private fun templateMapForJavadocContentGroup(note: JavadocContentGroup): TemplateMap { + return note.children.fold(emptyMap()) { map, child -> + map + templateMapForJavadocContentNode(child) + } + } + + private fun templateMapForTextNode(node: TextNode): TemplateMap { + return mapOf("text" to node.text) + } + + private fun templateMapForListNode(node: ListNode): TemplateMap { + return mapOf( + "tabTitle" to node.tabTitle, + "colTitle" to node.colTitle, + "list" to node.children + ) + } + fun locate(link: ContentDRILink, relativeNode: PageNode?) = + locationProvider.resolve(link.address, link.sourceSets, relativeNode) + + private fun htmlForContentNode(node: ContentNode, relativeNode: PageNode) = + htmlTranslator.htmlForContentNode(node, relativeNode, ::locate) + + private fun htmlForContentNodes(nodes: List, relativeNode: PageNode) = + htmlTranslator.htmlForContentNodes(nodes, relativeNode, ::locate) + } + + private fun DRI.displayable(): String = "${packageName}.${sureClassNames}" +} + diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt new file mode 100644 index 00000000..7b122b7d --- /dev/null +++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/KorteJavadocRenderer.kt @@ -0,0 +1,186 @@ +package javadoc.renderer + +import com.soywiz.korte.* +import javadoc.JavadocLocationProvider +import javadoc.pages.* +import javadoc.renderer.JavadocContentToHtmlTranslator.Companion.buildLink +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +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.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 TemplateMap = Map + +class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaContext, val resourceDir: String) : + Renderer { + private lateinit var locationProvider: JavadocLocationProvider + + override fun render(root: RootPageNode) = root.let { preprocessors.fold(root) { r, t -> t.invoke(r) } }.let { r -> + locationProvider = JavadocLocationProvider(r, context) + runBlocking(Dispatchers.IO) { + renderModulePageNode(r as JavadocModulePageNode) + } + } + + private fun templateForNode(node: JavadocPageNode) = when (node) { + is JavadocModulePageNode, + is JavadocPackagePageNode -> "tabPage.korte" + is JavadocClasslikePageNode -> "class.korte" + is AllClassesPage -> "listPage.korte" + is TreeViewPage -> "treePage.korte" + else -> "" + } + + private fun CoroutineScope.renderNode(node: PageNode, path: String = "") { + if (node is JavadocPageNode) { + renderJavadocPageNode(node) + } else if (node is RendererSpecificPage) { + renderSpecificPage(node, path) + } + } + + private fun CoroutineScope.renderModulePageNode(node: JavadocModulePageNode) { + val link = "." + val name = "index" + val pathToRoot = "" + + val contentMap = JavadocContentToTemplateMapTranslator(locationProvider, context).templateMapForPageNode(node, pathToRoot) + + writeFromTemplate(outputWriter, "$link/$name".toNormalized(), "tabPage.korte", contentMap.toList()) + node.children.forEach { renderNode(it, link) } + } + + private fun CoroutineScope.renderJavadocPageNode(node: JavadocPageNode) { + val link = locationProvider.resolve(node, skipExtension = true) + val dir = Paths.get(link).parent?.let { it.toNormalized() }.orEmpty() + val pathToRoot = dir.split("/").filter { it.isNotEmpty() }.joinToString("/") { ".." }.let { + if (it.isNotEmpty()) "$it/" else it + } + + val contentMap = JavadocContentToTemplateMapTranslator(locationProvider, context).templateMapForPageNode(node, pathToRoot) + writeFromTemplate(outputWriter, link, templateForNode(node), contentMap.toList()) + node.children.forEach { renderNode(it, link.toNormalized()) } + } + + fun CoroutineScope.renderSpecificPage(node: RendererSpecificPage, path: String) = launch { + when (val strategy = node.strategy) { + is RenderingStrategy.Copy -> outputWriter.writeResources(strategy.from, "") + is RenderingStrategy.Write -> outputWriter.writeHtml(path, strategy.text) + is RenderingStrategy.Callback -> outputWriter.writeResources( + path, + strategy.instructions(this@KorteJavadocRenderer, node) + ) + RenderingStrategy.DoNothing -> Unit + } + } + + fun Pair.pairToTag() = + """${first}\n${second}""" + + fun DRI.toLink(context: PageNode? = null) = locationProvider.resolve(this, emptySet(), context) + + private fun Path.toNormalized() = this.normalize().toFile().toString() + private fun String.toNormalized() = Paths.get(this).toNormalized() + + private suspend fun OutputWriter.writeHtml(path: String, text: String) = write(path, text, ".html") + private fun CoroutineScope.writeFromTemplate( + writer: OutputWriter, + path: String, + template: String, + args: List> + ) = launch { + val tmp = templateRenderer.render(template, *(args.toTypedArray())) + writer.writeHtml(path, tmp) + } + + fun getTemplateConfig() = TemplateConfig().also { config -> + listOf( + TeFunction("curDate") { LocalDate.now() }, + TeFunction("jQueryVersion") { "3.1" }, + TeFunction("jQueryMigrateVersion") { "1.2.1" }, + TeFunction("rowColor") { args -> if ((args.first() as Int) % 2 == 0) "altColor" else "rowColor" }, + TeFunction("h1Title") { args -> if ((args.first() as? String) == "package") "title=\"Package\" " else "" }, + TeFunction("createTabRow") { args -> + val (link, doc) = args.first() as RowJavadocListEntry + val dir = args[1] as String? + val translator = JavadocContentToHtmlTranslator(locationProvider, context) + (buildLink( + locationProvider.resolve(link, dir.orEmpty()), + link.name + ) to translator.htmlForContentNodes(doc, dir)).pairToTag().trim() + }, + TeFunction("createListRow") { args -> + val link = args.first() as LinkJavadocListEntry + val dir = args[1] as String? + buildLink( + locationProvider.resolve(link, dir.orEmpty()), + link.name + ) + }, + TeFunction("createPackageHierarchy") { args -> + val list = args.first() as List + list.mapIndexed { i, p -> + val content = if (i + 1 == list.size) "" else ", " + val name = p.name + "
  • $name$content
  • " + }.joinToString("\n") + }, + TeFunction("renderInheritanceGraph") { args -> + val rootNodes = args.first() as List + + fun drawRec(node: TreeViewPage.InheritanceNode): String = + "
  • " + node.dri.let { dri -> + listOfNotNull( + dri.packageName, + dri.classNames + ).joinToString(".") + node.interfaces.takeUnless { node.isInterface || it.isEmpty() } + ?.let { + " implements " + it.joinToString(", ") { n -> + listOfNotNull( + n.packageName, + buildLink(n.toLink(), n.classNames.orEmpty()) + ).joinToString(".") + } + }.orEmpty() + } + node.children.filterNot { it.isInterface }.takeUnless { it.isEmpty() }?.let { + "
      " + it.joinToString("\n", transform = ::drawRec) + "
    " + }.orEmpty() + "
  • " + + rootNodes.joinToString { drawRec(it) } + }, + Filter("length") { subject.dynamicLength() }, + TeFunction("hasAnyDescription") { args -> + args.first().safeAs>>() + ?.any { it["description"]?.trim()?.isNotEmpty() ?: false } + } + ).forEach { + when (it) { + is TeFunction -> config.register(it) + is Filter -> config.register(it) + is Tag -> config.register(it) + } + } + } + + val config = getTemplateConfig() + val templateRenderer = Templates( + ResourceTemplateProvider( + resourceDir + ), config = config, cache = true) + + class ResourceTemplateProvider(val basePath: String) : TemplateProvider { + override suspend fun get(template: String): String = + javaClass.classLoader.getResourceAsStream("$basePath/$template")?.bufferedReader()?.lines()?.toArray() + ?.joinToString("\n") ?: throw IllegalStateException("Template not found: $basePath/$template") + } + +} \ No newline at end of file diff --git a/plugins/javadoc/src/main/resources/views/class.korte b/plugins/javadoc/src/main/resources/views/class.korte index a9120fb2..6585e6b4 100644 --- a/plugins/javadoc/src/main/resources/views/class.korte +++ b/plugins/javadoc/src/main/resources/views/class.korte @@ -33,7 +33,7 @@ {% endif %}
    {{ signature|raw }}
    -
    {{ classlikeDocumentation }}
    +
    {{ classlikeDocumentation|raw }}
    @@ -115,7 +115,7 @@ {{ constructor.name }}({{ constructor.inlineParameters }}) - {{ constructor.brief }} + {{ constructor.brief|raw }} {% endfor %} @@ -143,7 +143,7 @@ {{ entry.signature|raw }} - {{ entry.brief }} + {{ entry.brief|raw }} {% endfor %} @@ -223,7 +223,7 @@
  • {{ constructor.name }}

    {{ constructor.name }}({{ constructor.inlineParameters }})
    -
    {{ constructor.brief }}
    +
    {{ constructor.brief|raw}}
    {% if constructor.parameters.size != 0 && hasAnyDescription(constructor.parameters) %}
    Parameters:
    diff --git a/plugins/javadoc/src/main/resources/views/components/indexPage.korte b/plugins/javadoc/src/main/resources/views/components/indexPage.korte index adba2457..02b94b75 100644 --- a/plugins/javadoc/src/main/resources/views/components/indexPage.korte +++ b/plugins/javadoc/src/main/resources/views/components/indexPage.korte @@ -4,7 +4,7 @@
    -
    {{ subtitle }}
    +
    {{ subtitle|raw }}

    See: Description

    -- cgit From 63823e14794136c23359aab9f40b8d8dcfe504dd Mon Sep 17 00:00:00 2001 From: Marcin Aman Date: Tue, 7 Jul 2020 15:45:32 +0200 Subject: Javadoc signature provider (#1041) Javadoc signature provider #1025 --- .../main/kotlin/signatures/JvmSignatureUtils.kt | 3 - .../psi/DefaultPsiToDocumentableTranslator.kt | 15 +- .../src/main/kotlin/javadoc/JavadocPageCreator.kt | 94 +++-- .../src/main/kotlin/javadoc/JavadocPlugin.kt | 24 +- .../kotlin/javadoc/pages/JavadocContentNodes.kt | 18 +- .../main/kotlin/javadoc/pages/JavadocPageNodes.kt | 36 +- .../main/kotlin/javadoc/pages/htmlGeneration.kt | 391 --------------------- .../renderer/JavadocContentToHtmlTranslator.kt | 15 +- .../JavadocContentToTemplateMapTranslator.kt | 54 +-- .../javadoc/signatures/JavadocSignatureProvider.kt | 196 +++++++++++ .../documentables/JavadocPageContentBuilder.kt | 80 +++++ .../javadoc/src/main/resources/views/class.korte | 30 +- .../javadoc/AbstractJavadocTemplateMapTest.kt | 2 +- .../javadoc/JavadocClasslikeTemplateMapTest.kt | 239 ++++++++++++- .../kotlin/javadoc/location/JavadocLocationTest.kt | 4 +- 15 files changed, 669 insertions(+), 532 deletions(-) delete mode 100644 plugins/javadoc/src/main/kotlin/javadoc/pages/htmlGeneration.kt create mode 100644 plugins/javadoc/src/main/kotlin/javadoc/signatures/JavadocSignatureProvider.kt create mode 100644 plugins/javadoc/src/main/kotlin/javadoc/translators/documentables/JavadocPageContentBuilder.kt (limited to 'plugins/javadoc/src/main/resources/views/class.korte') diff --git a/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt b/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt index 2a242948..689f6db5 100644 --- a/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt +++ b/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt @@ -21,9 +21,6 @@ interface JvmSignatureUtils { fun WithExtraProperties.annotations(): SourceSetDependent> = extra[Annotations]?.content ?: emptyMap() - private fun Annotations.Annotation.toSignatureString(): String = - "@" + this.dri.classNames + "(" + this.params.entries.joinToString { it.key + "=" + it.value } + ")" - private fun PageContentBuilder.DocumentableContentBuilder.annotations( d: Documentable, ignored: Set, diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index 5a55e3ec..5e03be6e 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -317,10 +317,15 @@ class DefaultPsiToDocumentableTranslator( is PsiClassReferenceType -> { val resolved: PsiClass = type.resolve() ?: return UnresolvedBound(type.presentableText) - if (resolved.qualifiedName == "java.lang.Object") { - JavaObject - } else { - TypeConstructor(DRI.from(resolved), type.parameters.map { getProjection(it) }) + when { + resolved.qualifiedName == "java.lang.Object" -> JavaObject + resolved is PsiTypeParameter && resolved.owner != null -> + OtherParameter( + declarationDRI = DRI.from(resolved.owner!!), + name = resolved.name.orEmpty() + ) + else -> + TypeConstructor(DRI.from(resolved), type.parameters.map { getProjection(it) }) } } is PsiArrayType -> TypeConstructor( @@ -443,7 +448,7 @@ class DefaultPsiToDocumentableTranslator( attributes.filter { it !is KtLightAbstractAnnotation }.mapNotNull { it.attributeName to it.toValue() } .toMap(), (psiElement as PsiClass).annotations.any { - hasQualifiedName("java.lang.annotation.Documented") + it.hasQualifiedName("java.lang.annotation.Documented") } ) } diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt index ebe223e5..1bafa111 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt @@ -9,13 +9,12 @@ import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentCon 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.NamedTagWrapper +import org.jetbrains.dokka.model.doc.Param import org.jetbrains.dokka.model.doc.TagWrapper 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.ContentNode -import org.jetbrains.dokka.pages.ContentText -import org.jetbrains.dokka.pages.DCI +import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.utilities.DokkaLogger open class JavadocPageCreator( @@ -43,20 +42,20 @@ open class JavadocPageCreator( name = c.name.orEmpty(), content = contentForClasslike(c), dri = setOf(c.dri), - modifiers = listOfNotNull(c.visibility[jvm]?.name), - signature = signatureProvider.signature(c).nodeForJvm(jvm), + signature = signatureForNode(c, jvm), description = c.descriptionToContentNodes(), constructors = (c as? WithConstructors)?.constructors?.mapNotNull { it.toJavadocFunction() }.orEmpty(), methods = c.functions.mapNotNull { it.toJavadocFunction() }, entries = (c as? DEnum)?.entries?.map { JavadocEntryNode( - signatureProvider.signature(it).nodeForJvm(jvm), it.descriptionToContentNodes(jvm) + signatureForNode(it, jvm), + it.descriptionToContentNodes(jvm) ) }.orEmpty(), classlikes = c.classlikes.mapNotNull { pageForClasslike(it) }, properties = c.properties.map { JavadocPropertyNode( - signatureProvider.signature(it).nodeForJvm(jvm), + signatureForNode(it, jvm), it.descriptionToContentNodes(jvm) ) }, @@ -71,7 +70,7 @@ open class JavadocPageCreator( JavadocContentKind.OverviewSummary, m.jvmSourceSets.toSet() ) { - title(m.name, m.brief(),"0.0.1", dri = setOf(m.dri), kind = ContentKind.Main) + title(m.name, m.brief(), "0.0.1", dri = setOf(m.dri), kind = ContentKind.Main) list("Packages", "Package", setOf(m.dri), ContentKind.Packages, m.packages.sortedBy { it.name }.map { p -> RowJavadocListEntry( LinkJavadocListEntry(p.name, setOf(p.dri), JavadocContentKind.PackageSummary, sourceSets), @@ -111,42 +110,21 @@ open class JavadocPageCreator( ) } - 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() = highestJvmSourceSet?.let { jvm -> JavadocFunctionNode( name = name, dri = dri, - signature = signatureProvider.signature(this).nodeForJvm(jvm), + signature = signatureForNode(this, jvm), brief = brief(jvm), - parameters = parameters.map { - JavadocParameterNode( - name = it.name.orEmpty(), - type = signatureForProjection(it.type), - description = it.brief() - ) + parameters = parameters.mapNotNull { + val signature = signatureForNode(it, jvm) + signature.modifiers?.let { type -> + JavadocParameterNode( + name = it.name.orEmpty(), + type = type, + description = it.brief() + ) + } }, extras = extra ) @@ -165,19 +143,28 @@ open class JavadocPageCreator( private inline fun Documentable.findNodeInDocumentation(sourceSetData: DokkaSourceSet?): T? = documentation[sourceSetData]?.firstChildOfTypeOrNull() - private fun Documentable.descriptionToContentNodes(sourceSet: DokkaSourceSet? = highestJvmSourceSet) = findNodeInDocumentation(sourceSet)?.let { - DocTagToContentConverter.buildContent( - it.root, - DCI(setOf(dri), JavadocContentKind.OverviewSummary), - sourceSets.toSet() - ) - }.orEmpty() + private fun Documentable.descriptionToContentNodes(sourceSet: DokkaSourceSet? = highestJvmSourceSet) = + contentNodesFromType(sourceSet) + + private fun DParameter.paramsToContentNodes(sourceSet: DokkaSourceSet? = highestJvmSourceSet) = + contentNodesFromType(sourceSet) + + private inline fun Documentable.contentNodesFromType(sourceSet: DokkaSourceSet?) = + findNodeInDocumentation(sourceSet)?.let { + DocTagToContentConverter.buildContent( + it.root, + DCI(setOf(dri), JavadocContentKind.OverviewSummary), + sourceSets.toSet() + ) + }.orEmpty() fun List.nodeForJvm(jvm: DokkaSourceSet): ContentNode = first { it.sourceSets.contains(jvm) } - private fun Documentable.brief(sourceSet: DokkaSourceSet? = highestJvmSourceSet): List { - val description = descriptionToContentNodes(sourceSet) + private fun Documentable.brief(sourceSet: DokkaSourceSet? = highestJvmSourceSet): List = + briefFromContentNodes(descriptionToContentNodes(sourceSet)) + + private fun briefFromContentNodes(description: List): List { val contents = mutableListOf() for (node in description) { if (node is ContentText && firstSentenceRegex.containsMatchIn(node.text)) { @@ -189,5 +176,14 @@ open class JavadocPageCreator( } return contents } + + private fun DParameter.brief(sourceSet: DokkaSourceSet? = highestJvmSourceSet): List = + briefFromContentNodes(paramsToContentNodes(sourceSet).dropWhile { it is ContentDRILink }) + + private fun ContentNode.asJavadocNode(): JavadocSignatureContentNode = + (this as ContentGroup).firstChildOfTypeOrNull() ?: throw IllegalStateException("No content for javadoc signature found") + + private fun signatureForNode(documentable: Documentable, sourceSet: DokkaSourceSet): JavadocSignatureContentNode = + signatureProvider.signature(documentable).nodeForJvm(sourceSet).asJavadocNode() } diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt index 7b4aa64d..1a14e97e 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPlugin.kt @@ -3,21 +3,24 @@ package org.jetbrains.dokka.javadoc import javadoc.JavadocDocumentableToPageTranslator import javadoc.location.JavadocLocationProviderFactory import javadoc.renderer.KorteJavadocRenderer +import javadoc.signatures.JavadocSignatureProvider import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.base.DokkaBase +import org.jetbrains.dokka.kotlinAsJava.KotlinAsJavaPlugin import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.plugability.querySingle class JavadocPlugin : DokkaPlugin() { val dokkaBasePlugin by lazy { plugin() } + val kotinAsJavaPlugin by lazy { plugin() } val locationProviderFactory by extensionPoint() val dokkaJavadocPlugin by extending { (CoreExtensions.renderer providing { ctx -> KorteJavadocRenderer(dokkaBasePlugin.querySingle { outputWriter }, ctx, "views") } - applyIf { format == "javadoc" } + applyIf { format == javadocFormat } override dokkaBasePlugin.htmlRenderer) } @@ -28,13 +31,28 @@ class JavadocPlugin : DokkaPlugin() { dokkaBasePlugin.querySingle { signatureProvider }, context.logger ) - } override dokkaBasePlugin.documentableToPageTranslator + } override dokkaBasePlugin.documentableToPageTranslator applyIf { format == javadocFormat } } val javadocLocationProviderFactory by extending { locationProviderFactory providing { context -> JavadocLocationProviderFactory(context) - } + } applyIf { format == javadocFormat } + } + + val javadocSignatureProvider by extending { + val dokkaBasePlugin = plugin() + dokkaBasePlugin.signatureProvider providing { ctx -> + JavadocSignatureProvider( + ctx.single( + dokkaBasePlugin.commentsToContentConverter + ), ctx.logger + ) + } override kotinAsJavaPlugin.javaSignatureProvider applyIf { format == javadocFormat } + } + + companion object { + private val javadocFormat = "javadoc" } } diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt index c8593498..5e24ce9e 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt @@ -86,13 +86,6 @@ fun JavaContentGroupBuilder.title( list.add(TitleNode(title, subtitle, 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() -} - class ListNode( val tabTitle: String, val colTitle: String, @@ -137,3 +130,14 @@ class LinkJavadocListEntry( data class RowJavadocListEntry(val link: LinkJavadocListEntry, val doc: List) : JavadocListEntry { override val stringTag: String = "" } + +data class JavadocSignatureContentNode( + val dri: DRI, + val kind: Kind = ContentKind.Symbol, + val annotations: ContentNode?, + val modifiers: ContentNode?, + val signatureWithoutModifiers: ContentNode, + val supertypes: ContentNode? +): JavadocContentNode(setOf(dri), kind, signatureWithoutModifiers.sourceSets) { + override fun hasAnyContent(): Boolean = true +} diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt index 24e481e8..02e4b2d6 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt @@ -26,8 +26,6 @@ class JavadocModulePageNode( RootPageNode(), JavadocPageNode { - val version: String = "0.0.1" - override val documentable: Documentable? = null override val embeddedResources: List = emptyList() override fun modified(name: String, children: List): RootPageNode = @@ -82,44 +80,35 @@ class JavadocPackagePageNode( } data class JavadocEntryNode( - val signature: ContentNode, + val signature: JavadocSignatureContentNode, val brief: List ) data class JavadocParameterNode( val name: String, - val type: String, + val type: ContentNode, val description: List ) data class JavadocPropertyNode( - val signature: ContentNode, + val signature: JavadocSignatureContentNode, val brief: List -) { - val modifiersAndSignature: Pair - get() = (signature as ContentGroup).splitSignatureIntoModifiersAndName() -} +) data class JavadocFunctionNode( - val signature: ContentNode, + val signature: JavadocSignatureContentNode, val brief: List, val parameters: List, val name: String, val dri: DRI, val extras: PropertyContainer = PropertyContainer.empty() -) { - - 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 signature: JavadocSignatureContentNode, val description: List, val constructors: List, val methods: List, @@ -142,7 +131,6 @@ class JavadocClasslikePageNode( name, content, dri, - modifiers, signature, description, constructors, @@ -167,7 +155,6 @@ class JavadocClasslikePageNode( name, content as JavadocContentNode, dri, - modifiers, signature, description, constructors, @@ -413,15 +400,6 @@ class TreeViewPage( } } -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" diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/htmlGeneration.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/htmlGeneration.kt deleted file mode 100644 index 98aa2344..00000000 --- a/plugins/javadoc/src/main/kotlin/javadoc/pages/htmlGeneration.kt +++ /dev/null @@ -1,391 +0,0 @@ -package javadoc.pages - -import kotlinx.html.html -import kotlinx.html.stream.createHTML -import org.jetbrains.dokka.pages.ClasslikePageNode -import org.jetbrains.dokka.pages.ModulePageNode -import org.jetbrains.dokka.pages.PackagePageNode -import org.jetbrains.dokka.pages.PageNode -import java.time.LocalDate - -class NavbarGenerator(val page: PageNode) { - val activeClass = "navBarCell1Rev" - fun pathToRoot() = "???" // TODO - val navItems = listOf("Overview", "Package", "Class", "Tree", "Deprecated", "Index", "Help") - - // private fun items = navItems.map {itemLink} -// fun navItemLink() - val x = createHTML().html {} - - private fun navList(content: String) = """ - """.trimIndent() - -// private fun navList(): String { -// when (page) { -// is PackagePageNode -> -// } -// """ -//
  • Overview
  • -//
  • Package
  • -// -//""" -// val classItem = if (page is ClasslikePageNode) { -// "Class".wrapInTag("li", mapOf("class" to activeClass)) -// } -// val treeItem = if (page is ModulePageNode) { -// "
  • Tree
  • \n" -// } else { -// "
  • Tree
  • \n" -// } -// -// val navListEnd = """ -//
  • Deprecated
  • -//
  • Index
  • -//
  • Help
  • -//""".trimIndent() -// } - - private fun bottomNavbar(page: PageNode): String = - """ - |""" -} - -internal fun pageStart(title: String, version: String, documentTitle: String, pathToRoot: String) = """ - | - | - | - | - |$documentTitle ($title $version API) - | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - |
    - | - |
    - |
    - |
    - |

    $title $version API

    - |
    - |
    - |
    - | - | - | - | - | - | - | - ${packages.mapIndexed { i, e -> e.generateLink(i) }.joinToString("\n")} - | - |
    $tabTitle 
    $colTitleDescription
    - |
    - |
    - |
    - | - | - | - |""".trimMargin("|") - -fun classData(name: String, extends: String) = """ - | - |
    - |
    adaptation
    - |

    Class $name

    - |
    - |
    - ${classInheritance()} - |
    - |
      - |
    • - |
      - |
      - |
      public class $name
      -    |extends $name
      - |
    • - |
    - |
    - |
    - | - |
    - |
    - |
      - |
    • - | - |
        - |
      • - | - | - |

        Constructor Detail

        - | - | - | - |
          - |
        • - |

          Adaptation

          - |
          public Adaptation()
          - |
        • - |
        - |
      • - |
      - | - | - |
    • - |
    - |
    - |
    - | -""".trimIndent() - -fun classInheritance() = """ - |
      - |
    • java.lang.Object
    • - |
    • - |
        - |
      • adaptation.Adaptation
      • - |
      - |
    • - |
    - """ - -internal fun String.wrapInTag(tag: String, options: Map) = - "<$tag ${options.map { it.key + "=\"" + it.value + '"' }.joinToString(" ")}>$this" - -fun PageNode.generateLink(i: Int) = "\n\n" + run { - val path = /*if (this is JavadocPageNode && this.pageType != PageType.Package) "$filename.html" else*/ "$name/package-summary.html" - - name.wrapInTag("a", mapOf("href" to path)) - .wrapInTag( - "th", - mapOf("class" to "colFirst", "scope" to "row") - ) + " \n" -} - -internal enum class NavigableType { - Overview, Package, Class, Tree, Deprecated, Index, Help -} - -internal interface Navigable { - val type: NavigableType -} \ No newline at end of file diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt index 7d6f37c0..df6490cf 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt @@ -1,9 +1,10 @@ package javadoc.renderer -import javadoc.pages.TextNode +import javadoc.pages.JavadocSignatureContentNode import org.jetbrains.dokka.base.resolvers.local.LocationProvider import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.utilities.htmlEscape internal class JavadocContentToHtmlTranslator( private val locationProvider: LocationProvider, @@ -13,14 +14,14 @@ internal class JavadocContentToHtmlTranslator( fun htmlForContentNode(node: ContentNode, relative: PageNode?): String = when (node) { is ContentGroup -> htmlForContentNodes(node.children, relative) - is ContentText -> node.text - is TextNode -> node.text + is ContentText -> node.text.htmlEscape() is ContentDRILink -> buildLink( locationProvider.resolve(node.address, node.sourceSets, relative), htmlForContentNodes(node.children, relative) ) is ContentResolvedLink -> buildLink(node.address, htmlForContentNodes(node.children, relative)) is ContentCode -> htmlForCode(node.children) + is JavadocSignatureContentNode -> htmlForSignature(node, relative) else -> "" } @@ -35,6 +36,14 @@ internal class JavadocContentToHtmlTranslator( } }.joinToString("
    ", """""", "") { it } + private fun htmlForSignature(node: JavadocSignatureContentNode, relative: PageNode?): String = + listOfNotNull( + node.annotations, + node.modifiers, + node.signatureWithoutModifiers, + node.supertypes + ).joinToString(separator = " ") { htmlForContentNode(it, relative) } + companion object { fun buildLink(address: String, content: String) = diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt index e60b27c6..760647fa 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt @@ -49,20 +49,18 @@ internal class JavadocContentToTemplateMapTranslator( } } - private fun String.toNormalized() = Paths.get(this).toNormalized() - private inner class InnerTranslator(val contextNode: PageNode) { private val htmlTranslator = JavadocContentToHtmlTranslator(locationProvider, context) - internal fun templateMapForAllClassesPage(node: AllClassesPage): TemplateMap { + fun templateMapForAllClassesPage(node: AllClassesPage): TemplateMap { return mapOf( "title" to "All Classes", "list" to node.classEntries ) } - internal fun templateMapForTreeViewPage(node: TreeViewPage): TemplateMap { + fun templateMapForTreeViewPage(node: TreeViewPage): TemplateMap { return mapOf( "title" to node.title, "name" to node.name, @@ -73,45 +71,49 @@ internal class JavadocContentToTemplateMapTranslator( ) } - internal fun templateMapForPackagePageNode(node: JavadocPackagePageNode): TemplateMap { + fun templateMapForPackagePageNode(node: JavadocPackagePageNode): TemplateMap { return mapOf( "kind" to "package" ) + templateMapForJavadocContentNode(node.content) } - internal fun templateMapForFunctionNode(node: JavadocFunctionNode): TemplateMap { - val (modifiers, signature) = node.modifiersAndSignature + fun templateMapForFunctionNode(node: JavadocFunctionNode): TemplateMap { return mapOf( - "signature" to htmlForContentNode(node.signature, contextNode), "brief" to htmlForContentNodes(node.brief, contextNode), "parameters" to node.parameters.map { templateMapForParameterNode(it) }, - "inlineParameters" to node.parameters.joinToString { "${it.type} ${it.name}" }, - "modifiers" to htmlForContentNode(modifiers, contextNode), - "signatureWithoutModifiers" to htmlForContentNode(signature, contextNode), + "inlineParameters" to node.parameters.joinToString { renderInlineParameter(it) }, + "signature" to templateMapForSignatureNode(node.signature), "name" to node.name ) } - internal fun templateMapForClasslikeNode(node: JavadocClasslikePageNode): TemplateMap = + fun templateMapForClasslikeNode(node: JavadocClasslikePageNode): TemplateMap = mapOf( "constructors" to node.constructors.map { templateMapForFunctionNode(it) }, - "signature" to htmlForContentNode(node.signature, node), + "signature" to templateMapForSignatureNode(node.signature), "methods" to templateMapForClasslikeMethods(node.methods), "classlikeDocumentation" to htmlForContentNodes(node.description, node), "entries" to node.entries.map { templateMapForEntryNode(it) }, "properties" to node.properties.map { templateMapForPropertyNode(it) }, "classlikes" to node.classlikes.map { templateMapForNestedClasslikeNode(it) }, - "implementedInterfaces" to templateMapForImplementedInterfaces(node), + "implementedInterfaces" to templateMapForImplementedInterfaces(node).sorted(), "kind" to node.kind, "packageName" to node.packageName, "name" to node.name ) + templateMapForJavadocContentNode(node.content) - internal fun templateMapForJavadocContentNode(node: JavadocContentNode): TemplateMap = + fun templateMapForSignatureNode(node: JavadocSignatureContentNode): TemplateMap = + mapOf( + "annotations" to node.annotations?.let { htmlForContentNode(it, contextNode) }, + "signatureWithoutModifiers" to htmlForContentNode(node.signatureWithoutModifiers, contextNode), + "modifiers" to node.modifiers?.let { htmlForContentNode(it, contextNode) }, + "supertypes" to node.supertypes?.let { htmlForContentNode(it, contextNode) } + ) + + fun templateMapForJavadocContentNode(node: JavadocContentNode): TemplateMap = when (node) { is TitleNode -> templateMapForTitleNode(node) is JavadocContentGroup -> templateMapForJavadocContentGroup(node) - is TextNode -> templateMapForTextNode(node) is ListNode -> templateMapForListNode(node) else -> emptyMap() } @@ -120,7 +122,7 @@ internal class JavadocContentToTemplateMapTranslator( mapOf( "description" to htmlForContentNodes(node.description, contextNode), "name" to node.name, - "type" to node.type + "type" to htmlForContentNode(node.type, contextNode) ) private fun templateMapForImplementedInterfaces(node: JavadocClasslikePageNode) = @@ -157,25 +159,24 @@ internal class JavadocContentToTemplateMapTranslator( private fun templateMapForNestedClasslikeNode(node: JavadocClasslikePageNode): TemplateMap { return mapOf( - "modifiers" to (node.modifiers + "static" + node.kind).joinToString(separator = " "), + "modifiers" to node.signature.modifiers?.let { htmlForContentNode(it, contextNode) }, "signature" to node.name, "description" to htmlForContentNodes(node.description, node) ) } private fun templateMapForPropertyNode(node: JavadocPropertyNode): TemplateMap { - val (modifiers, signature) = node.modifiersAndSignature return mapOf( - "modifiers" to htmlForContentNode(modifiers, contextNode), - "signature" to htmlForContentNode(signature, contextNode), + "modifiers" to node.signature.modifiers?.let { htmlForContentNode(it, contextNode) }, + "signature" to htmlForContentNode(node.signature.signatureWithoutModifiers, contextNode), "description" to htmlForContentNodes(node.brief, contextNode) ) } private fun templateMapForEntryNode(node: JavadocEntryNode): TemplateMap { return mapOf( - "signature" to htmlForContentNode(node.signature, contextNode), - "brief" to node.brief + "signature" to templateMapForSignatureNode(node.signature), + "brief" to htmlForContentNodes(node.brief, contextNode) ) } @@ -194,10 +195,6 @@ internal class JavadocContentToTemplateMapTranslator( } } - private fun templateMapForTextNode(node: TextNode): TemplateMap { - return mapOf("text" to node.text) - } - private fun templateMapForListNode(node: ListNode): TemplateMap { return mapOf( "tabTitle" to node.tabTitle, @@ -206,6 +203,9 @@ internal class JavadocContentToTemplateMapTranslator( ) } + private fun renderInlineParameter(parameter: JavadocParameterNode): String = + htmlForContentNode(parameter.type, contextNode) + " ${parameter.name}" + private fun htmlForContentNode(node: ContentNode, relativeNode: PageNode) = htmlTranslator.htmlForContentNode(node, relativeNode) diff --git a/plugins/javadoc/src/main/kotlin/javadoc/signatures/JavadocSignatureProvider.kt b/plugins/javadoc/src/main/kotlin/javadoc/signatures/JavadocSignatureProvider.kt new file mode 100644 index 00000000..11db9fe1 --- /dev/null +++ b/plugins/javadoc/src/main/kotlin/javadoc/signatures/JavadocSignatureProvider.kt @@ -0,0 +1,196 @@ +package javadoc.signatures + +import javadoc.translators.documentables.JavadocPageContentBuilder +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.base.signatures.JvmSignatureUtils +import org.jetbrains.dokka.base.signatures.SignatureProvider +import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter +import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder +import org.jetbrains.dokka.kotlinAsJava.signatures.JavaSignatureUtils +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.properties.PropertyContainer +import org.jetbrains.dokka.pages.ContentKind +import org.jetbrains.dokka.pages.ContentNode +import org.jetbrains.dokka.utilities.DokkaLogger + +class JavadocSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogger) : SignatureProvider, + JvmSignatureUtils by JavaSignatureUtils { + + private val contentBuilder = JavadocPageContentBuilder(ctcc, this, logger) + + private val ignoredVisibilities = setOf(JavaVisibility.Default) + + private val ignoredModifiers = + setOf(KotlinModifier.Open, JavaModifier.Empty, KotlinModifier.Empty, KotlinModifier.Sealed) + + override fun signature(documentable: Documentable): List = when (documentable) { + is DFunction -> signature(documentable) + is DProperty -> signature(documentable) + is DClasslike -> signature(documentable) + is DEnumEntry -> signature(documentable) + is DTypeParameter -> signature(documentable) + is DParameter -> signature(documentable) + else -> throw NotImplementedError( + "Cannot generate signature for ${documentable::class.qualifiedName} ${documentable.name}" + ) + } + + private fun signature(c: DClasslike): List = + javadocSignature(c) { + annotations { + annotationsBlock(c) + } + modifiers { + text(c.visibility[it]?.takeIf { it !in ignoredVisibilities }?.name?.plus(" ") ?: "") + + if (c is DClass) { + text(c.modifier[it]?.takeIf { it !in ignoredModifiers }?.name?.plus(" ") ?: "") + text(c.modifiers()[it]?.toSignatureString() ?: "") + } + + when (c) { + is DClass -> text("class") + is DInterface -> text("interface") + is DEnum -> text("enum") + is DObject -> text("class") + is DAnnotation -> text("@interface") + } + } + signatureWithoutModifiers { + link(c.name!!, c.dri) + if (c is WithGenerics) { + list(c.generics, prefix = "<", suffix = ">") { + +buildSignature(it) + } + } + } + supertypes { + if (c is WithSupertypes) { + c.supertypes.map { (p, dris) -> + list(dris, sourceSets = setOf(p)) { + link(it.fqName(), it, sourceSets = setOf(p)) + } + } + } + } + } + + private fun signature(f: DFunction): List = + javadocSignature(f) { + annotations { + annotationsBlock(f) + } + modifiers { + text(f.modifier[it]?.takeIf { it !in ignoredModifiers }?.name?.plus(" ") ?: "") + text(f.modifiers()[it]?.toSignatureString() ?: "") + list(f.generics, prefix = "<", suffix = "> ") { + +buildSignature(it) + } + signatureForProjection(f.type) + } + signatureWithoutModifiers { + link(f.name, f.dri) + text("(") + list(f.parameters) { + annotationsInline(it) + text(it.modifiers()[it]?.toSignatureString() ?: "") + signatureForProjection(it.type) + text(Typography.nbsp.toString()) + link(it.name!!, it.dri) + } + text(")") + } + } + + private fun signature(p: DProperty): List = + javadocSignature(p) { + annotations { + annotationsBlock(p) + } + modifiers { + text(p.visibility[it]?.takeIf { it !in ignoredVisibilities }?.name?.plus(" ") ?: "") + text(p.modifier[it]?.name + " ") + text(p.modifiers()[it]?.toSignatureString() ?: "") + signatureForProjection(p.type) + } + signatureWithoutModifiers { + link(p.name, p.dri) + } + } + + private fun signature(e: DEnumEntry): List = + javadocSignature(e) { + annotations { + annotationsBlock(e) + } + modifiers { + text(e.modifiers()[it]?.toSignatureString() ?: "") + } + signatureWithoutModifiers { + link(e.name, e.dri) + } + } + + private fun signature(t: DTypeParameter): List = + javadocSignature(t) { + annotations { + annotationsBlock(t) + } + signatureWithoutModifiers { + text(t.name) + } + supertypes { + list(t.bounds, prefix = "extends ") { + signatureForProjection(it) + } + } + } + + private fun signature(p: DParameter): List = + javadocSignature(p) { + modifiers { + signatureForProjection(p.type) + } + signatureWithoutModifiers { + link(p.name.orEmpty(), p.dri) + } + } + + private fun javadocSignature( + d: Documentable, + extra: PropertyContainer = PropertyContainer.empty(), + block: JavadocPageContentBuilder.JavadocContentBuilder.(DokkaConfiguration.DokkaSourceSet) -> Unit + ): List = + d.sourceSets.map { sourceSet -> + contentBuilder.contentFor(d, ContentKind.Main) { + with(contentBuilder) { + javadocGroup(d.dri, d.sourceSets, extra) { + block(sourceSet) + } + } + } + } + + private fun PageContentBuilder.DocumentableContentBuilder.signatureForProjection(p: Projection): Unit = when (p) { + is OtherParameter -> link(p.name, p.declarationDRI) + is TypeConstructor -> group { + link(p.dri.fqName(), p.dri) + list(p.projections, prefix = "<", suffix = ">") { + signatureForProjection(it) + } + } + is Variance -> group { + text(p.kind.toString() + " ") + signatureForProjection(p.inner) + } + is Star -> text("?") + is Nullable -> signatureForProjection(p.inner) + is JavaObject, is Dynamic -> link("java.lang.Object", DRI("java.lang", "Object")) + is Void -> text("void") + is PrimitiveJavaType -> text(p.name) + is UnresolvedBound -> text(p.name) + } + + private fun DRI.fqName(): String = "${packageName.orEmpty()}.${classNames.orEmpty()}" +} diff --git a/plugins/javadoc/src/main/kotlin/javadoc/translators/documentables/JavadocPageContentBuilder.kt b/plugins/javadoc/src/main/kotlin/javadoc/translators/documentables/JavadocPageContentBuilder.kt new file mode 100644 index 00000000..17b474b0 --- /dev/null +++ b/plugins/javadoc/src/main/kotlin/javadoc/translators/documentables/JavadocPageContentBuilder.kt @@ -0,0 +1,80 @@ +package javadoc.translators.documentables + +import javadoc.pages.JavadocSignatureContentNode +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.base.signatures.SignatureProvider +import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter +import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.properties.PropertyContainer +import org.jetbrains.dokka.pages.ContentKind +import org.jetbrains.dokka.pages.ContentNode +import org.jetbrains.dokka.utilities.DokkaLogger +import java.lang.IllegalStateException + +class JavadocPageContentBuilder( + commentsConverter: CommentsToContentConverter, + signatureProvider: SignatureProvider, + logger: DokkaLogger +) : PageContentBuilder(commentsConverter, signatureProvider, logger) { + + fun PageContentBuilder.DocumentableContentBuilder.javadocGroup( + dri: DRI = mainDRI.first(), + sourceSets: Set = mainSourcesetData, + extra: PropertyContainer = mainExtra, + block: JavadocContentBuilder.() -> Unit + ) { + +JavadocContentBuilder( + mainDri = dri, + mainExtra = extra, + mainSourceSet = sourceSets, + ).apply(block).build() + } + + open inner class JavadocContentBuilder( + private val mainDri: DRI, + private val mainExtra: PropertyContainer, + private val mainSourceSet: Set, + ) { + var annotations: ContentNode? = null + var modifiers: ContentNode? = null + var signatureWithoutModifiers: ContentNode? = null + var supertypes: ContentNode? = null + + fun annotations(block: PageContentBuilder.DocumentableContentBuilder.() -> Unit) { + val built = buildContentForBlock(block) + if(built.hasAnyContent()) annotations = built + } + + fun modifiers(block: PageContentBuilder.DocumentableContentBuilder.() -> Unit) { + val built = buildContentForBlock(block) + if(built.hasAnyContent()) modifiers = built + } + + fun signatureWithoutModifiers(block: PageContentBuilder.DocumentableContentBuilder.() -> Unit) { + signatureWithoutModifiers = buildContentForBlock(block) + } + + fun supertypes(block: PageContentBuilder.DocumentableContentBuilder.() -> Unit) { + val built = buildContentForBlock(block) + if(built.hasAnyContent()) supertypes = built + } + + private fun buildContentForBlock(block: PageContentBuilder.DocumentableContentBuilder.() -> Unit) = + contentFor( + dri = mainDri, + sourceSets = mainSourceSet, + kind = ContentKind.Symbol, + extra = mainExtra, + block = block + ) + + fun build(): JavadocSignatureContentNode = JavadocSignatureContentNode( + dri = mainDri, + annotations = annotations, + modifiers = modifiers, + signatureWithoutModifiers = signatureWithoutModifiers ?: throw IllegalStateException("JavadocSignatureContentNode should have at least a signature"), + supertypes = supertypes + ) + } +} \ No newline at end of file diff --git a/plugins/javadoc/src/main/resources/views/class.korte b/plugins/javadoc/src/main/resources/views/class.korte index 6585e6b4..22793d69 100644 --- a/plugins/javadoc/src/main/resources/views/class.korte +++ b/plugins/javadoc/src/main/resources/views/class.korte @@ -32,7 +32,11 @@
    {% endif %}
    -
    {{ signature|raw }}
    +
    +{% if signature.annotations != null %}{{ signature.annotations|raw }} {% endif %}
    +{{ signature.modifiers }} {{ signature.signatureWithoutModifiers|raw }}
    +{% if signature.supertypes != null %}extends {{signature.supertypes|raw}} {% endif %}
    +                    
    {{ classlikeDocumentation|raw }}
  • @@ -114,7 +118,7 @@ {% for constructor in constructors %} {{ constructor.name }}({{ constructor.inlineParameters }}) + href="#%3Cinit%3E({{ constructor.inlineParameters }})">{{ constructor.name }}({{ constructor.inlineParameters|raw }}) {{ constructor.brief|raw }} {% endfor %} @@ -142,7 +146,7 @@ {% for entry in entries %} {{ entry.signature|raw }} + href="TODO">{{ entry.signature.signatureWithoutModifiers|raw }} {{ entry.brief|raw }} {% endfor %} @@ -173,9 +177,9 @@ {% for method in methods.own %} - {{ method.modifiers|raw }} + {{ method.signature.modifiers|raw }} - {{ method.signatureWithoutModifiers|raw }} + {{ method.signature.signatureWithoutModifiers|raw }} {{ method.brief|raw }} @@ -222,14 +226,14 @@
    • {{ constructor.name }}

      -
      {{ constructor.name }}({{ constructor.inlineParameters }})
      +
      {{ constructor.name }}({{ constructor.inlineParameters|raw }})
      {{ constructor.brief|raw}}
      {% if constructor.parameters.size != 0 && hasAnyDescription(constructor.parameters) %}
      Parameters:
      {% for parameter in constructor.parameters %} {% if parameter.description != "" %} -
      {{ parameter.name }} - {{ parameter.description }}
      +
      {{ parameter.name }} - {{ parameter.description|raw }}
      {% endif %} {% endfor %}
      @@ -256,8 +260,18 @@
      • {{ method.name }}

        -
        {{ method.signature|raw }}
        +
        {{ method.signature.annotations|raw }} {{ method.signature.modifiers|raw }} {{ method.signature.signatureWithoutModifiers|raw}}
        {{ method.brief|raw }}
        + {% if method.parameters.size != 0 && hasAnyDescription(method.parameters) %} +
        +
        Parameters:
        + {% for parameter in method.parameters %} + {% if parameter.description != "" %} +
        {{ parameter.name }} - {{ parameter.description|raw }}
        + {% endif %} + {% endfor %} +
        + {% endif %}
      diff --git a/plugins/javadoc/src/test/kotlin/javadoc/AbstractJavadocTemplateMapTest.kt b/plugins/javadoc/src/test/kotlin/javadoc/AbstractJavadocTemplateMapTest.kt index 4fa65c58..7cd42942 100644 --- a/plugins/javadoc/src/test/kotlin/javadoc/AbstractJavadocTemplateMapTest.kt +++ b/plugins/javadoc/src/test/kotlin/javadoc/AbstractJavadocTemplateMapTest.kt @@ -101,7 +101,7 @@ internal abstract class AbstractJavadocTemplateMapTest : AbstractCoreTest() { throw AssertionError( "Kotlin and Java Code failed assertions\n" + "Kotlin: ${kotlinException.message}\n" + - "Java: ${javaException.message}", + "Java : ${javaException.message}", kotlinException ) } diff --git a/plugins/javadoc/src/test/kotlin/javadoc/JavadocClasslikeTemplateMapTest.kt b/plugins/javadoc/src/test/kotlin/javadoc/JavadocClasslikeTemplateMapTest.kt index 0f95894b..dc1573e1 100644 --- a/plugins/javadoc/src/test/kotlin/javadoc/JavadocClasslikeTemplateMapTest.kt +++ b/plugins/javadoc/src/test/kotlin/javadoc/JavadocClasslikeTemplateMapTest.kt @@ -36,7 +36,7 @@ internal class JavadocClasslikeTemplateMapTest : AbstractJavadocTemplateMapTest( assertEquals("com.test.package0", map["packageName"]) assertEquals("Documentation for TestClass", map["classlikeDocumentation"]) assertEquals("Documentation for TestClass", map["subtitle"]) - assertEquals("public final class TestClass", map["signature"]) + assertEquals("public final class TestClass", map.signatureWithModifiers()) } } @@ -81,21 +81,252 @@ internal class JavadocClasslikeTemplateMapTest : AbstractJavadocTemplateMapTest( assertEquals("com.test.package0", map["packageName"]) assertEquals("Documentation for TestClass", map["classlikeDocumentation"]) assertEquals("Documentation for TestClass", map["subtitle"]) - assertEquals("public final class TestClass", map["signature"]) + assertEquals("public final class", map.modifiers()) + assertEquals("TestClass", map.signatureWithoutModifiers()) val methods = assertIsInstance>(map["methods"]) val ownMethods = assertIsInstance>(methods["own"]) assertEquals(1, ownMethods.size, "Expected only one method") - val method = assertIsInstance>(ownMethods.single()) + val method = assertIsInstance>(ownMethods.single()) assertEquals("Documentation for testFunction", method["brief"]) assertEquals("testFunction", method["name"]) assertEquals( 0, assertIsInstance>(method["parameters"]).size, "Expected no parameters" ) + assertEquals("final java.lang.String", method.modifiers()) + assertEquals("testFunction()", method.signatureWithoutModifiers()) + } + } + + @Test + fun `class with annotation`(){ + dualTestTemplateMapInline( + kotlin = + """ + /src/source0.kt + package com.test.package0 + @MustBeDocumented + annotation class Author(val name: String) + + @Author( + name = "Benjamin Franklin" + ) + class TestClass {` + + @Author( + name = "Franklin D. Roosevelt" + ) + fun testFunction(): String = "" + } + """, + java = + """ + /src/com/test/package0/Author.java + package com.test.package0 + import java.lang.annotation.Documented; + + @Documented + public @interface Author { + String name(); + } + /src/com/test/package0/TestClass.java + package com.test.package0 + + @Author( + name = "Benjamin Franklin" + ) + public final class TestClass { + + @Author( + name = "Franklin D. Roosevelt" + ) + public final String testFunction() { + return ""; + } + } + """ + ){ + val map = allPagesOfType().first { it.name == "TestClass" }.templateMap + assertEquals("TestClass", map["name"]) + val signature = assertIsInstance>(map["signature"]) + assertEquals("@Author(name = \"Benjamin Franklin\")", signature["annotations"]) + + val methods = assertIsInstance>(map["methods"]) + val ownMethods = assertIsInstance>(methods["own"]) + val method = assertIsInstance>(ownMethods.single()) + val methodSignature = assertIsInstance>(method["signature"]) + assertEquals("@Author(name = \"Franklin D. Roosevelt\")", methodSignature["annotations"]) + } + } + + @Test + fun `simple enum`(){ + dualTestTemplateMapInline( + kotlin = + """ + /src/source0.kt + package com.test.package0 + enum class ClockDays { + /** + * Sample docs for first + */ + FIRST, + /** + * Sample docs for second + */ + SECOND + } + """, + java = + """ + /src/com/test/package0/TestClass.java + package com.test.package0; + enum ClockDays { + /** + * Sample docs for first + */ + FIRST, + /** + * Sample docs for second + */ + SECOND + } + """ + ){ + val map = singlePageOfType().templateMap + assertEquals("ClockDays", map["name"]) + assertEquals("enum", map["kind"]) + val entries = assertIsInstance>>(map["entries"]) + assertEquals(2, entries.size) + + val (first, second) = entries + assertEquals("Sample docs for first", first["brief"]) + assertEquals("Sample docs for second", second["brief"]) + + assertEquals("FIRST", first.signatureWithoutModifiers()) + assertEquals("SECOND", second.signatureWithoutModifiers()) + } + } + + @Test + fun `documented function parameters`(){ + dualTestTemplateMapInline( + kotlin = + """ + /src/source0.kt + package com.test.package0 + class TestClass { + /** + * Simple parameters list to check out + * @param simple simple String parameter + * @param parameters simple Integer parameter + * @param list simple Boolean parameter + * @return just a String + */ + fun testFunction(simple: String?, parameters: Int?, list: Boolean?): String { + return "" + } + } + """, + java = + """ + /src/com/test/package0/TestClass.java + package com.test.package0; + public final class TestClass { + /** + * Simple parameters list to check out + * @param simple simple String parameter + * @param parameters simple Integer parameter + * @param list simple Boolean parameter + * @return just a String + */ + public final String testFunction(String simple, Integer parameters, Boolean list) { + return ""; + } + } + """ + ) { + val map = singlePageOfType().templateMap + assertEquals("TestClass", map["name"]) + + val methods = assertIsInstance>(map["methods"]) + val testFunction = assertIsInstance>>(methods["own"]).single() + assertEquals("Simple parameters list to check out", testFunction["brief"]) + + val (first, second, third) = assertIsInstance>>(testFunction["parameters"]) + assertParameterNode( + node = first, + expectedName = "simple", + expectedType = "java.lang.String", + expectedDescription = "simple String parameter" + ) + assertParameterNode( + node = second, + expectedName = "parameters", + expectedType = "java.lang.Integer", + expectedDescription = "simple Integer parameter" + ) + assertParameterNode( + node = third, + expectedName = "list", + expectedType = "java.lang.Boolean", + expectedDescription = "simple Boolean parameter" + ) + } + } + + @Test + fun `with generic parameters`(){ + dualTestTemplateMapInline( + kotlin = + """ + /src/source0.kt + package com.test.package0 + import java.io.Serializable + + class Generic { + fun sampleFunction(): D = TODO() + } + """, + java = + """ + /src/com/test/package0/Generic.java + package com.test.package0; + import java.io.Serializable; + + public final class Generic { + public final D sampleFunction(){ + return null; + } + } + """ + ) { + val map = singlePageOfType().templateMap + assertEquals("Generic", map["name"]) + assertEquals( - "final String testFunction()", method["signature"] + "public final class Generic<T extends java.io.Serializable>", + map.signatureWithModifiers() ) + val methods = assertIsInstance>(map["methods"]) + val ownMethods = assertIsInstance>(methods["own"]).first() + val sampleFunction = assertIsInstance>(ownMethods) + + assertEquals("final <D extends T> D sampleFunction()", sampleFunction.signatureWithModifiers()) } } + + private fun assertParameterNode(node: Map, expectedName: String, expectedType: String, expectedDescription: String){ + assertEquals(expectedName, node["name"]) + assertEquals(expectedType, node["type"]) + assertEquals(expectedDescription, node["description"]) + } + + private fun Map.signatureWithModifiers(): String = "${modifiers()} ${signatureWithoutModifiers()}" + + private fun Map.signatureWithoutModifiers(): String = (get("signature") as Map)["signatureWithoutModifiers"] as String + + private fun Map.modifiers(): String = (get("signature") as Map)["modifiers"] as String + } diff --git a/plugins/javadoc/src/test/kotlin/javadoc/location/JavadocLocationTest.kt b/plugins/javadoc/src/test/kotlin/javadoc/location/JavadocLocationTest.kt index a47f0142..92620f78 100644 --- a/plugins/javadoc/src/test/kotlin/javadoc/location/JavadocLocationTest.kt +++ b/plugins/javadoc/src/test/kotlin/javadoc/location/JavadocLocationTest.kt @@ -54,8 +54,8 @@ class JavadocTest : AbstractCoreTest() { val testClass = rootPageNode.firstChildOfType() .firstChildOfType() assert( - "public final class Test extends Cloneable" - == transformer.htmlForContentNode(testClass.signature, null) + "java.lang.Cloneable" + == transformer.htmlForContentNode(testClass.signature.supertypes!!, null) ) } } -- cgit From b67f44943bc80dedd70c4a9e120b9c6aec78ca72 Mon Sep 17 00:00:00 2001 From: Marcin Aman Date: Thu, 2 Jul 2020 13:21:00 +0200 Subject: Draft for showing only first level of inheritance --- core/src/main/kotlin/links/DRI.kt | 5 + core/src/main/kotlin/model/Documentable.kt | 11 +- .../kotlin/signatures/KotlinSignatureProvider.kt | 2 +- .../InheritorsExtractorTransformer.kt | 2 +- .../DefaultDescriptorToDocumentableTranslator.kt | 66 ++++++---- .../psi/DefaultPsiToDocumentableTranslator.kt | 33 +++-- plugins/base/src/test/kotlin/model/ClassesTest.kt | 36 +++++- plugins/base/src/test/kotlin/model/JavaTest.kt | 134 +++------------------ .../javadoc/signatures/JavadocSignatureProvider.kt | 9 +- .../javadoc/src/main/resources/views/class.korte | 2 +- .../kotlin/javadoc/location/JavadocLocationTest.kt | 3 +- .../kotlin/converters/KotlinToJavaConverter.kt | 8 +- .../kotlin/signatures/JavaSignatureProvider.kt | 8 +- 13 files changed, 149 insertions(+), 170 deletions(-) (limited to 'plugins/javadoc/src/main/resources/views/class.korte') diff --git a/core/src/main/kotlin/links/DRI.kt b/core/src/main/kotlin/links/DRI.kt index 3f6d886f..3892fc00 100644 --- a/core/src/main/kotlin/links/DRI.kt +++ b/core/src/main/kotlin/links/DRI.kt @@ -1,5 +1,9 @@ package org.jetbrains.dokka.links +import org.jetbrains.dokka.model.ClassKind +import org.jetbrains.dokka.model.Documentable +import org.jetbrains.dokka.model.WithSupertypes + /** * [DRI] stands for DokkaResourceIdentifier */ @@ -100,3 +104,4 @@ fun DriTarget.nextTarget(): DriTarget = when (this) { else -> this } +data class DriWithKind(val dri: DRI, val kind: ClassKind) diff --git a/core/src/main/kotlin/model/Documentable.kt b/core/src/main/kotlin/model/Documentable.kt index 21660f86..2c3e1323 100644 --- a/core/src/main/kotlin/model/Documentable.kt +++ b/core/src/main/kotlin/model/Documentable.kt @@ -2,6 +2,7 @@ package org.jetbrains.dokka.model import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.DriWithKind import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.model.properties.WithExtraProperties @@ -75,7 +76,7 @@ interface WithGenerics { } interface WithSupertypes { - val supertypes: SourceSetDependent> + val supertypes: SourceSetDependent> } interface Callable : WithVisibility, WithType, WithAbstraction, WithExpectActual { @@ -128,7 +129,7 @@ data class DClass( override val visibility: SourceSetDependent, override val companion: DObject?, override val generics: List, - override val supertypes: SourceSetDependent>, + override val supertypes: SourceSetDependent>, override val documentation: SourceSetDependent, override val expectPresentInSet: DokkaSourceSet?, override val modifier: SourceSetDependent, @@ -156,7 +157,7 @@ data class DEnum( override val visibility: SourceSetDependent, override val companion: DObject?, override val constructors: List, - override val supertypes: SourceSetDependent>, + override val supertypes: SourceSetDependent>, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithCompanion, WithConstructors, WithSupertypes, WithExtraProperties { @@ -217,7 +218,7 @@ data class DInterface( override val visibility: SourceSetDependent, override val companion: DObject?, override val generics: List, - override val supertypes: SourceSetDependent>, + override val supertypes: SourceSetDependent>, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithCompanion, WithGenerics, WithSupertypes, WithExtraProperties { @@ -237,7 +238,7 @@ data class DObject( override val properties: List, override val classlikes: List, override val visibility: SourceSetDependent, - override val supertypes: SourceSetDependent>, + override val supertypes: SourceSetDependent>, override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : DClasslike(), WithSupertypes, WithExtraProperties { diff --git a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt index 14c130a2..37e0ea83 100644 --- a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt +++ b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt @@ -184,7 +184,7 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog if (c is WithSupertypes) { c.supertypes.filter { it.key == sourceSet }.map { (s, dris) -> list(dris, prefix = " : ", sourceSets = setOf(s)) { - link(it.sureClassNames, it, sourceSets = setOf(s)) + link(it.dri.sureClassNames, it.dri, sourceSets = setOf(s)) } } } diff --git a/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt index f1bccd66..85256d51 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt @@ -63,7 +63,7 @@ class InheritorsExtractorTransformer : DocumentableTransformer { private fun T.toInheritanceEntries() = (this as? WithSupertypes)?.let { - it.supertypes.map { (k, v) -> k to v.map { it to dri } } + it.supertypes.map { (k, v) -> k to v.map { it.dri to dri } } }.orEmpty() } diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index b0374014..9ca8cdde 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -1,7 +1,11 @@ package org.jetbrains.dokka.base.translators.descriptors import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.analysis.* +import org.jetbrains.dokka.analysis.DescriptorDocumentableSource +import org.jetbrains.dokka.analysis.DokkaResolutionFacade +import org.jetbrains.dokka.analysis.KotlinAnalysis +import org.jetbrains.dokka.analysis.from +import org.jetbrains.dokka.base.parsers.MarkdownParser import org.jetbrains.dokka.links.* import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.model.* @@ -9,7 +13,6 @@ import org.jetbrains.dokka.model.Nullable import org.jetbrains.dokka.model.TypeConstructor import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.model.properties.PropertyContainer -import org.jetbrains.dokka.base.parsers.MarkdownParser import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator import org.jetbrains.dokka.utilities.DokkaLogger @@ -33,7 +36,7 @@ import org.jetbrains.kotlin.resolve.constants.ConstantValue import org.jetbrains.kotlin.resolve.constants.KClassValue.Value.LocalClass import org.jetbrains.kotlin.resolve.constants.KClassValue.Value.NormalClass import org.jetbrains.kotlin.resolve.descriptorUtil.annotationClass -import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.MemberScope @@ -150,7 +153,7 @@ private class DokkaDescriptorVisitor( extra = PropertyContainer.withAll( descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - ImplementedInterfaces(info.interfaces.toSourceSetDependent()) + ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()) ) ) } @@ -177,7 +180,7 @@ private class DokkaDescriptorVisitor( extra = PropertyContainer.withAll( descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - ImplementedInterfaces(info.interfaces.toSourceSetDependent()) + ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()) ) ) } @@ -206,7 +209,7 @@ private class DokkaDescriptorVisitor( extra = PropertyContainer.withAll( descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - ImplementedInterfaces(info.interfaces.toSourceSetDependent()) + ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()) ) ) } @@ -290,7 +293,7 @@ private class DokkaDescriptorVisitor( extra = PropertyContainer.withAll( descriptor.additionalExtras().toSourceSetDependent().toAdditionalModifiers(), descriptor.getAnnotations().toSourceSetDependent().toAnnotations(), - ImplementedInterfaces(info.interfaces.toSourceSetDependent()) + ImplementedInterfaces(info.allImplementedInterfaces.toSourceSetDependent()) ) ) } @@ -535,11 +538,6 @@ private class DokkaDescriptorVisitor( .filter { it is ClassDescriptor && it.kind != ClassKind.ENUM_ENTRY } .map { visitClassDescriptor(it as ClassDescriptor, parent) } - private fun MemberScope.packages(parent: DRIWithPlatformInfo): List = - getContributedDescriptors(DescriptorKindFilter.PACKAGES) { true } - .filterIsInstance() - .map { visitPackageFragmentDescriptor(it, parent) } - private fun MemberScope.typealiases(parent: DRIWithPlatformInfo, packageLevel: Boolean = false): List = getContributedDescriptors(DescriptorKindFilter.TYPE_ALIASES, packageLevel) .filterIsInstance() @@ -556,15 +554,30 @@ private class DokkaDescriptorVisitor( getDocumentation()?.toSourceSetDependent() ?: emptyMap() private fun ClassDescriptor.resolveClassDescriptionData(): ClassInfo { - val interfaces = hashSetOf() - fun processSuperClasses(supers: List) { - supers.forEach { - if(it.kind == ClassKind.INTERFACE) interfaces.add(DRI.from(it)) - processSuperClasses(it.getSuperInterfaces() + it.getAllSuperclassesWithoutAny()) - } + tailrec fun processSuperClasses( + inheritorClass: ClassDescriptor?, + interfaces: List, + level: Int = 0, + inheritanceTree: Set = emptySet() + ): Set { + if (inheritorClass == null && interfaces.isEmpty()) return inheritanceTree + + val updatedTree = inheritanceTree + InheritanceLevel( + level, + inheritorClass?.let { DRI.from(it) }, + interfaces.map { DRI.from(it) }) + val superInterfacesFromClass = inheritorClass?.getSuperInterfaces().orEmpty() + return processSuperClasses( + inheritorClass = inheritorClass?.getSuperClassNotAny(), + interfaces = interfaces.flatMap { it.getSuperInterfaces() } + superInterfacesFromClass, + level = level + 1, + inheritanceTree = updatedTree + ) } - processSuperClasses(getSuperInterfaces() + getAllSuperclassesWithoutAny()) - return ClassInfo(getAllSuperclassesWithoutAny().map { DRI.from(it) }, interfaces.toList(), resolveDescriptorData()) + return ClassInfo( + processSuperClasses(getSuperClassNotAny(), getSuperInterfaces()).sortedBy { it.level }, + resolveDescriptorData() + ) } private fun TypeParameterDescriptor.toTypeParameter() = @@ -733,9 +746,16 @@ private class DokkaDescriptorVisitor( private fun ValueArgument.childrenAsText() = this.safeAs()?.children?.map { it.text }.orEmpty() - private data class ClassInfo(val superclasses: List, val interfaces: List, val docs: SourceSetDependent){ - val supertypes: List - get() = (superclasses + interfaces).distinct() + private data class InheritanceLevel(val level: Int, val superclass: DRI?, val interfaces: List) + + private data class ClassInfo(val inheritance: List, val docs: SourceSetDependent){ + val supertypes: List + get() = inheritance.firstOrNull { it.level == 0 }?.let { + listOfNotNull(it.superclass?.let { DriWithKind(it, KotlinClassKindTypes.CLASS) }) + it.interfaces.map { DriWithKind(it, KotlinClassKindTypes.INTERFACE) } + }.orEmpty() + + val allImplementedInterfaces: List + get() = inheritance.flatMap { it.interfaces }.distinct() } private fun Visibility.toDokkaVisibility(): org.jetbrains.dokka.model.Visibility = when (this) { diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index d426d41b..91b24476 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -12,6 +12,7 @@ import org.jetbrains.dokka.analysis.KotlinAnalysis import org.jetbrains.dokka.analysis.PsiDocumentableSource import org.jetbrains.dokka.analysis.from import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.DriWithKind import org.jetbrains.dokka.links.nextTarget import org.jetbrains.dokka.links.withClass import org.jetbrains.dokka.model.* @@ -127,11 +128,23 @@ class DefaultPsiToDocumentableTranslator( fun parseClasslike(psi: PsiClass, parent: DRI): DClasslike = with(psi) { val dri = parent.withClass(name.toString()) - val ancestorsSet = hashSetOf() + val inheritanceTree = mutableListOf() val superMethodsKeys = hashSetOf() val superMethods = mutableListOf>() methods.forEach { superMethodsKeys.add(it.hash) } - fun parseSupertypes(superTypes: Array) { + fun parseSupertypes(superTypes: Array, level: Int = 0) { + if(superTypes.isEmpty()) return + val parsedClasses = superTypes.filter { !it.shouldBeIgnored }.mapNotNull { + it.resolve()?.let { + when { + it.isInterface -> DRI.from(it) to JavaClassKindTypes.INTERFACE + else -> DRI.from(it) to JavaClassKindTypes.CLASS + } + } + } + val (classes, interfaces) = parsedClasses.partition { it.second == JavaClassKindTypes.CLASS } + inheritanceTree.add(AncestorLevel(level, classes.firstOrNull()?.first, interfaces.map { it.first })) + superTypes.forEach { type -> (type as? PsiClassType)?.takeUnless { type.shouldBeIgnored }?.resolve()?.let { val definedAt = DRI.from(it) @@ -144,8 +157,7 @@ class DefaultPsiToDocumentableTranslator( superMethods.add(Pair(method, definedAt)) } } - ancestorsSet.add(Ancestor(DRI.from(it), it.isInterface)) - parseSupertypes(it.superTypes) + parseSupertypes(it.superTypes, level + 1) } } } @@ -157,9 +169,16 @@ class DefaultPsiToDocumentableTranslator( val source = PsiDocumentableSource(this).toSourceSetDependent() val classlikes = innerClasses.map { parseClasslike(it, dri) } val visibility = getVisibility().toSourceSetDependent() - val ancestors = ancestorsSet.toList().map { it.dri }.toSourceSetDependent() + val ancestors = inheritanceTree.filter { it.level == 0 }.flatMap { + listOfNotNull(it.superclass?.let { + DriWithKind( + dri = it, + kind = JavaClassKindTypes.CLASS + ) + }) + it.interfaces.map { DriWithKind(dri = it, kind = JavaClassKindTypes.INTERFACE) } + }.toSourceSetDependent() val modifiers = getModifier().toSourceSetDependent() - val implementedInterfacesExtra = ImplementedInterfaces(ancestorsSet.filter { it.isInterface }.map { it.dri }.toList().toSourceSetDependent()) + val implementedInterfacesExtra = ImplementedInterfaces(inheritanceTree.flatMap { it.interfaces }.distinct().toSourceSetDependent()) return when { isAnnotationType -> DAnnotation( @@ -457,5 +476,5 @@ class DefaultPsiToDocumentableTranslator( get() = getChildOfType()?.resolve() } - private data class Ancestor(val dri: DRI, val isInterface: Boolean) + private data class AncestorLevel(val level: Int, val superclass: DRI?, val interfaces: List) } diff --git a/plugins/base/src/test/kotlin/model/ClassesTest.kt b/plugins/base/src/test/kotlin/model/ClassesTest.kt index 979ea89b..5dc8812e 100644 --- a/plugins/base/src/test/kotlin/model/ClassesTest.kt +++ b/plugins/base/src/test/kotlin/model/ClassesTest.kt @@ -221,7 +221,7 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class with((this / "f").cast()) { modifier.values.forEach { it equals Open } } - D.supertypes.flatMap { it.component2() }.firstOrNull() equals C.dri + D.supertypes.flatMap { it.component2() }.firstOrNull()?.dri equals C.dri } } } @@ -258,8 +258,8 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class modifier.values.forEach { it equals Final } } - D.supers.single() equals C.dri - E.supers.firstOrNull() equals D.dri + D.supers.single().dri equals C.dri + E.supers.single().dri equals D.dri } } @@ -500,4 +500,34 @@ class ClassesTest : AbstractModelTest("/src/main/kotlin/classes/Test.kt", "class } } } + + @Test fun multipleClassInheritance() { + inlineModelTest( + """ + | open class A { } + | open class B: A() { } + | class Tested : B() { } + """.trimIndent() + ) { + with((this / "classes" / "Tested").cast()) { + supertypes.entries.single().value.map { it.dri.sureClassNames }.single() equals "B" + } + } + } + + @Test fun multipleClassInheritanceWithInterface(){ + inlineModelTest( + """ + | open class A { } + | open class B: A() { } + | interface X { } + | interface Y : X { } + | class Tested : B(), Y { } + """.trimIndent() + ){ + with((this / "classes" / "Tested").cast()) { + supertypes.entries.single().value.map { it.dri.sureClassNames to it.kind }.sortedBy { it.first } equals listOf("B" to KotlinClassKindTypes.CLASS, "Y" to KotlinClassKindTypes.INTERFACE) + } + } + } } \ No newline at end of file diff --git a/plugins/base/src/test/kotlin/model/JavaTest.kt b/plugins/base/src/test/kotlin/model/JavaTest.kt index 4cad784b..1f042304 100644 --- a/plugins/base/src/test/kotlin/model/JavaTest.kt +++ b/plugins/base/src/test/kotlin/model/JavaTest.kt @@ -54,38 +54,19 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { } } - //@Test fun function() { - // verifyJavaPackageMember("testdata/java/member.java", defaultModelConfig) { cls -> - // assertEquals("Test", cls.name) - // assertEquals(NodeKind.Class, cls.kind) - // with(cls.members(NodeKind.Function).single()) { - // assertEquals("fn", name) - // assertEquals("Summary for Function", content.summary.toTestString().trimEnd()) - // assertEquals(3, content.sections.size) - // with(content.sections[0]) { - // assertEquals("Parameters", tag) - // assertEquals("name", subjectName) - // assertEquals("render(Type:String,SUMMARY): is String parameter", toTestString()) - // } - // with(content.sections[1]) { - // assertEquals("Parameters", tag) - // assertEquals("value", subjectName) - // assertEquals("render(Type:Int,SUMMARY): is int parameter", toTestString()) - // } - // assertEquals("Unit", detail(NodeKind.Type).name) - // assertTrue(members.none()) - // assertTrue(links.none()) - // with(details.first { it.name == "name" }) { - // assertEquals(NodeKind.Parameter, kind) - // assertEquals("String", detail(NodeKind.Type).name) - // } - // with(details.first { it.name == "value" }) { - // assertEquals(NodeKind.Parameter, kind) - // assertEquals("Int", detail(NodeKind.Type).name) - // } - // } - // } - // } + @Test fun multipleClassInheritanceWithInterface() { + inlineModelTest( + """ + |interface Highest { } + |interface Lower extends Highest { } + |class Extendable { } + |class Tested extends Extendable implements Lower { } + """){ + with((this / "java" / "Tested").cast()) { + supertypes.entries.single().value.map { it.dri.sureClassNames to it.kind }.sortedBy { it.first } equals listOf("Extendable" to JavaClassKindTypes.CLASS, "Lower" to JavaClassKindTypes.INTERFACE) + } + } + } @Test // todo fun memberWithModifiers() { @@ -107,19 +88,6 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { } } - // @Test fun memberWithModifiers() { - // verifyJavaPackageMember("testdata/java/memberWithModifiers.java", defaultModelConfig) { cls -> - // val modifiers = cls.details(NodeKind.Modifier).map { it.name } - // assertTrue("abstract" in modifiers) - // with(cls.members.single { it.name == "fn" }) { - // assertEquals("protected", details[0].name) - // } - // with(cls.members.single { it.name == "openFn" }) { - // assertEquals("open", details[1].name) - // } - // } - // } - @Test fun superClass() { inlineModelTest( @@ -130,7 +98,7 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { with((this / "java" / "Foo").cast()) { val sups = listOf("Exception", "Cloneable") assertTrue( - sups.all { s -> supertypes.values.flatten().any { it.classNames == s } }) + sups.all { s -> supertypes.values.flatten().any { it.dri.classNames == s } }) "Foo must extend ${sups.joinToString(", ")}" } } @@ -178,25 +146,6 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { } } - // @Test fun typeParameter() { - // verifyJavaPackageMember("testdata/java/typeParameter.java", defaultModelConfig) { cls -> - // val typeParameters = cls.details(NodeKind.TypeParameter) - // with(typeParameters.single()) { - // assertEquals("T", name) - // with(detail(NodeKind.UpperBound)) { - // assertEquals("Comparable", name) - // assertEquals("T", detail(NodeKind.Type).name) - // } - // } - // with(cls.members(NodeKind.Function).single()) { - // val methodTypeParameters = details(NodeKind.TypeParameter) - // with(methodTypeParameters.single()) { - // assertEquals("E", name) - // } - // } - // } - // } - @Test fun constructors() { inlineModelTest( @@ -290,19 +239,6 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { } } - // @Test fun fields() { - // verifyJavaPackageMember("testdata/java/field.java", defaultModelConfig) { cls -> - // val i = cls.members(NodeKind.Property).single { it.name == "i" } - // assertEquals("Int", i.detail(NodeKind.Type).name) - // assertTrue("var" in i.details(NodeKind.Modifier).map { it.name }) - // - // val s = cls.members(NodeKind.Property).single { it.name == "s" } - // assertEquals("String", s.detail(NodeKind.Type).name) - // assertFalse("var" in s.details(NodeKind.Modifier).map { it.name }) - // assertTrue("static" in s.details(NodeKind.Modifier).map { it.name }) - // } - // } - @Test fun staticMethod() { inlineModelTest( @@ -321,25 +257,6 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { } } - // @Test fun staticMethod() { todo - // verifyJavaPackageMember("testdata/java/staticMethod.java", defaultModelConfig) { cls -> - // val m = cls.members(NodeKind.Function).single { it.name == "foo" } - // assertTrue("static" in m.details(NodeKind.Modifier).map { it.name }) - // } - // } - // - // /** - // * `@suppress` not supported in Java! - // * - // * [Proposed tags](https://www.oracle.com/technetwork/java/javase/documentation/proposed-tags-142378.html) - // * Proposed tag `@exclude` for it, but not supported yet - // */ - // @Ignore("@suppress not supported in Java!") @Test fun suppressTag() { - // verifyJavaPackageMember("testdata/java/suppressTag.java", defaultModelConfig) { cls -> - // assertEquals(1, cls.members(NodeKind.Function).size) - // } - // } - @Test fun annotatedAnnotation() { inlineModelTest( @@ -367,13 +284,6 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { } } - // @Test fun deprecation() { - // verifyJavaPackageMember("testdata/java/deprecation.java", defaultModelConfig) { cls -> - // val fn = cls.members(NodeKind.Function).single() - // assertEquals("This should no longer be used", fn.deprecation!!.content.toTestString()) - // } - // } - @Test fun javaLangObject() { inlineModelTest( @@ -389,13 +299,6 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { } } - // @Test fun javaLangObject() { - // verifyJavaPackageMember("testdata/java/javaLangObject.java", defaultModelConfig) { cls -> - // val fn = cls.members(NodeKind.Function).single() - // assertEquals("Any", fn.detail(NodeKind.Type).name) - // } - // } - @Test fun enumValues() { inlineModelTest( @@ -440,13 +343,4 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { } } } - - // todo - // @Test fun inheritorLinks() { - // verifyJavaPackageMember("testdata/java/InheritorLinks.java", defaultModelConfig) { cls -> - // val fooClass = cls.members.single { it.name == "Foo" } - // val inheritors = fooClass.references(RefKind.Inheritor) - // assertEquals(1, inheritors.size) - // } - // } } diff --git a/plugins/javadoc/src/main/kotlin/javadoc/signatures/JavadocSignatureProvider.kt b/plugins/javadoc/src/main/kotlin/javadoc/signatures/JavadocSignatureProvider.kt index 11db9fe1..c2483cc2 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/signatures/JavadocSignatureProvider.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/signatures/JavadocSignatureProvider.kt @@ -8,6 +8,7 @@ import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentCon import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder import org.jetbrains.dokka.kotlinAsJava.signatures.JavaSignatureUtils import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.sureClassNames import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.pages.ContentKind @@ -68,8 +69,12 @@ class JavadocSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLo supertypes { if (c is WithSupertypes) { c.supertypes.map { (p, dris) -> - list(dris, sourceSets = setOf(p)) { - link(it.fqName(), it, sourceSets = setOf(p)) + val (classes, interfaces) = dris.partition { it.kind == JavaClassKindTypes.CLASS } + list(classes, prefix = " extends ", sourceSets = setOf(p)) { + link(it.dri.sureClassNames, it.dri, sourceSets = setOf(p)) + } + list(interfaces, prefix = " implements ", sourceSets = setOf(p)){ + link(it.dri.sureClassNames, it.dri, sourceSets = setOf(p)) } } } diff --git a/plugins/javadoc/src/main/resources/views/class.korte b/plugins/javadoc/src/main/resources/views/class.korte index 22793d69..62d90f7d 100644 --- a/plugins/javadoc/src/main/resources/views/class.korte +++ b/plugins/javadoc/src/main/resources/views/class.korte @@ -35,7 +35,7 @@
       {% if signature.annotations != null %}{{ signature.annotations|raw }} {% endif %}
       {{ signature.modifiers }} {{ signature.signatureWithoutModifiers|raw }}
      -{% if signature.supertypes != null %}extends {{signature.supertypes|raw}} {% endif %}
      +{% if signature.supertypes != null %}{{signature.supertypes|raw}} {% endif %}
                           
      {{ classlikeDocumentation|raw }}
    • diff --git a/plugins/javadoc/src/test/kotlin/javadoc/location/JavadocLocationTest.kt b/plugins/javadoc/src/test/kotlin/javadoc/location/JavadocLocationTest.kt index 92620f78..d60e1070 100644 --- a/plugins/javadoc/src/test/kotlin/javadoc/location/JavadocLocationTest.kt +++ b/plugins/javadoc/src/test/kotlin/javadoc/location/JavadocLocationTest.kt @@ -39,6 +39,7 @@ class JavadocTest : AbstractCoreTest() { """ |/jvmSrc/javadoc/Test.kt |package javadoc + |import java.io.Serializable |class Test() : Serializable, Cloneable """.trimIndent(), config, @@ -54,7 +55,7 @@ class JavadocTest : AbstractCoreTest() { val testClass = rootPageNode.firstChildOfType() .firstChildOfType() assert( - "java.lang.Cloneable" + " implements Serializable, Cloneable" == transformer.htmlForContentNode(testClass.signature.supertypes!!, null) ) } diff --git a/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt index 693fffac..1ca4ef51 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/converters/KotlinToJavaConverter.kt @@ -167,7 +167,7 @@ internal fun DClass.asJava(): DClass = copy( properties = properties.map { it.asJava() }, classlikes = classlikes.map { it.asJava() }, generics = generics.map { it.asJava() }, - supertypes = supertypes.mapValues { it.value.map { it.possiblyAsJava() } }, + supertypes = supertypes.mapValues { it.value.map { it.copy(dri = it.dri.possiblyAsJava()) } }, modifier = if (modifier.all { (_, v) -> v is KotlinModifier.Empty }) sourceSets.map { it to JavaModifier.Final } .toMap() else sourceSets.map { it to modifier.values.first() }.toMap() @@ -195,7 +195,7 @@ internal fun DEnum.asJava(): DEnum = copy( }, properties = properties.map { it.asJava() }, classlikes = classlikes.map { it.asJava() }, - supertypes = supertypes.mapValues { it.value.map { it.possiblyAsJava() } } + supertypes = supertypes.mapValues { it.value.map { it.copy(dri = it.dri.possiblyAsJava()) } } // , entries = entries.map { it.asJava() } ) @@ -225,7 +225,7 @@ internal fun DObject.asJava(): DObject = copy( }) ), classlikes = classlikes.map { it.asJava() }, - supertypes = supertypes.mapValues { it.value.map { it.possiblyAsJava() } } + supertypes = supertypes.mapValues { it.value.map { it.copy(dri = it.dri.possiblyAsJava()) } } ) internal fun DInterface.asJava(): DInterface = copy( @@ -235,7 +235,7 @@ internal fun DInterface.asJava(): DInterface = copy( properties = emptyList(), classlikes = classlikes.map { it.asJava() }, // TODO: public static final class DefaultImpls with impls for methods generics = generics.map { it.asJava() }, - supertypes = supertypes.mapValues { it.value.map { it.possiblyAsJava() } } + supertypes = supertypes.mapValues { it.value.map { it.copy(dri = it.dri.possiblyAsJava()) } } ) internal fun DAnnotation.asJava(): DAnnotation = copy( diff --git a/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt b/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt index ca817219..0e257945 100644 --- a/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt +++ b/plugins/kotlin-as-java/src/main/kotlin/signatures/JavaSignatureProvider.kt @@ -77,8 +77,12 @@ class JavaSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogge } if (c is WithSupertypes) { c.supertypes.map { (p, dris) -> - list(dris, prefix = " extends ", sourceSets = setOf(p)) { - link(it.sureClassNames, it, sourceSets = setOf(p)) + val (classes, interfaces) = dris.partition { it.kind == JavaClassKindTypes.CLASS } + list(classes, prefix = " extends ", sourceSets = setOf(p)) { + link(it.dri.sureClassNames, it.dri, sourceSets = setOf(p)) + } + list(interfaces, prefix = " implements ", sourceSets = setOf(p)){ + link(it.dri.sureClassNames, it.dri, sourceSets = setOf(p)) } } } -- cgit From 086651dcc3ce496c5ba256dcfddb6afd5c83f7ff Mon Sep 17 00:00:00 2001 From: Błażej Kardyś Date: Wed, 1 Jul 2020 23:57:29 +0200 Subject: Javadoc anchors --- .../psi/DefaultPsiToDocumentableTranslator.kt | 2 +- .../src/main/kotlin/javadoc/JavadocPageCreator.kt | 8 +- .../javadoc/location/JavadocLocationProvider.kt | 53 ++++++++++-- .../main/kotlin/javadoc/pages/JavadocPageNodes.kt | 20 +++-- .../renderer/JavadocContentToHtmlTranslator.kt | 5 +- .../JavadocContentToTemplateMapTranslator.kt | 4 +- .../javadoc/signatures/JavadocSignatureProvider.kt | 8 +- .../javadoc/src/main/resources/views/class.korte | 4 +- .../javadoc/JavadocClasslikeTemplateMapTest.kt | 19 ++--- .../kotlin/javadoc/location/JavadocLocationTest.kt | 98 ++++++++++++++++++---- 10 files changed, 168 insertions(+), 53 deletions(-) (limited to 'plugins/javadoc/src/main/resources/views/class.korte') diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index 91b24476..6f980383 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -203,7 +203,7 @@ class DefaultPsiToDocumentableTranslator( name.orEmpty(), fields.filterIsInstance().map { entry -> DEnumEntry( - dri.withClass("$name.${entry.name}"), + dri.withClass("${entry.name}"), entry.name, javadocParser.parseDocumentation(entry).toSourceSetDependent(), null, diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt index b1549729..52a8a50b 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt @@ -48,6 +48,8 @@ open class JavadocPageCreator( methods = c.functions.mapNotNull { it.toJavadocFunction() }, entries = (c as? DEnum)?.entries?.map { JavadocEntryNode( + it.dri, + it.name, signatureForNode(it, jvm), it.descriptionToContentNodes(jvm) ) @@ -55,6 +57,8 @@ open class JavadocPageCreator( classlikes = c.classlikes.mapNotNull { pageForClasslike(it) }, properties = c.properties.map { JavadocPropertyNode( + it.dri, + it.name, signatureForNode(it, jvm), it.descriptionToContentNodes(jvm) ) @@ -142,7 +146,9 @@ open class JavadocPageCreator( JavadocParameterNode( name = it.name.orEmpty(), type = type, - description = it.brief() + description = it.brief(), + typeBound = it.type, + dri = it.dri ) } }, diff --git a/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt b/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt index 56a9015a..f77970eb 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt @@ -2,18 +2,22 @@ package javadoc.location import javadoc.pages.* import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.base.DokkaBase -import org.jetbrains.dokka.base.resolvers.local.LocationProvider import org.jetbrains.dokka.base.resolvers.local.BaseLocationProvider import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.Nullable +import org.jetbrains.dokka.links.parent +import org.jetbrains.dokka.model.OtherParameter +import org.jetbrains.dokka.model.PrimitiveJavaType +import org.jetbrains.dokka.model.TypeConstructor +import org.jetbrains.dokka.model.UnresolvedBound import org.jetbrains.dokka.pages.ContentPage import org.jetbrains.dokka.pages.PageNode import org.jetbrains.dokka.pages.RootPageNode import org.jetbrains.dokka.plugability.DokkaContext import java.util.* -class JavadocLocationProvider(pageRoot: RootPageNode, private val context: DokkaContext) : BaseLocationProvider(context) { +class JavadocLocationProvider(pageRoot: RootPageNode, dokkaContext: DokkaContext) : + BaseLocationProvider(dokkaContext) { private val pathIndex = IdentityHashMap>().apply { fun registerPath(page: PageNode, prefix: List = emptyList()) { @@ -53,13 +57,46 @@ class JavadocLocationProvider(pageRoot: RootPageNode, private val context: Dokka private fun List.relativeTo(context: List): String { val contextPath = context.dropLast(1) - val commonPathElements = zip(contextPath).takeWhile { (a,b) -> a == b }.count() - return (List(contextPath.size - commonPathElements ) { ".." } + this.drop(commonPathElements)).joinToString("/") + val commonPathElements = zip(contextPath).takeWhile { (a, b) -> a == b }.count() + return (List(contextPath.size - commonPathElements) { ".." } + this.drop(commonPathElements)).joinToString("/") } - override fun resolve(dri: DRI, sourceSets: Set, context: PageNode?): String = - nodeIndex[dri]?.let { resolve(it, context) } + private fun JavadocClasslikePageNode.findAnchorableByDRI(dri: DRI): AnchorableJavadocNode? = + (constructors + methods + entries + properties).firstOrNull { it.dri == dri } + + override fun resolve(dri: DRI, sourceSets: Set, context: PageNode?): String { + return nodeIndex[dri]?.let { resolve(it, context) } + ?: nodeIndex[dri.parent]?.let { + val anchor = when (val anchorElement = (it as? JavadocClasslikePageNode)?.findAnchorableByDRI(dri)) { + is JavadocFunctionNode -> anchorElement.getAnchor() + is JavadocEntryNode -> anchorElement.name + is JavadocPropertyNode -> anchorElement.name + else -> anchorForDri(dri) + } + "${resolve(it, context, skipExtension = true)}.html#$anchor" + } ?: getExternalLocation(dri, sourceSets) + } + + private fun JavadocFunctionNode.getAnchor(): String = + "$name-${parameters.joinToString(",%20") { + when (val bound = it.typeBound) { + is TypeConstructor -> bound.dri.classNames.orEmpty() + is OtherParameter -> bound.name + is PrimitiveJavaType -> bound.name + is UnresolvedBound -> bound.name + else -> bound.toString() + } + }}-" + + fun anchorForFunctionNode(node: JavadocFunctionNode) = node.getAnchor() + + private fun anchorForDri(dri: DRI): String = + dri.callable?.let { callable -> + "${callable.name}-${callable.params.joinToString(",%20") { + ((it as? Nullable)?.wrapped ?: it).toString() + }}-" + } ?: dri.classNames.orEmpty() override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean): String = pathIndex[node]?.relativeTo(pathIndex[context].orEmpty())?.let { diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt index 02e4b2d6..216b9319 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt @@ -79,30 +79,38 @@ class JavadocPackagePageNode( ) } +sealed class AnchorableJavadocNode(open val dri: DRI) + data class JavadocEntryNode( + override val dri: DRI, + val name: String, val signature: JavadocSignatureContentNode, val brief: List -) +): AnchorableJavadocNode(dri) data class JavadocParameterNode( + override val dri: DRI, val name: String, val type: ContentNode, - val description: List -) + val description: List, + val typeBound: Bound +): AnchorableJavadocNode(dri) data class JavadocPropertyNode( + override val dri: DRI, + val name: String, val signature: JavadocSignatureContentNode, val brief: List -) +): AnchorableJavadocNode(dri) data class JavadocFunctionNode( val signature: JavadocSignatureContentNode, val brief: List, val parameters: List, val name: String, - val dri: DRI, + override val dri: DRI, val extras: PropertyContainer = PropertyContainer.empty() -) +): AnchorableJavadocNode(dri) class JavadocClasslikePageNode( override val name: String, diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt index df6490cf..7d3a51a6 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToHtmlTranslator.kt @@ -1,5 +1,6 @@ package javadoc.renderer +import javadoc.location.JavadocLocationProvider import javadoc.pages.JavadocSignatureContentNode import org.jetbrains.dokka.base.resolvers.local.LocationProvider import org.jetbrains.dokka.pages.* @@ -7,7 +8,7 @@ import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.utilities.htmlEscape internal class JavadocContentToHtmlTranslator( - private val locationProvider: LocationProvider, + private val locationProvider: JavadocLocationProvider, private val context: DokkaContext ) { @@ -50,6 +51,6 @@ internal class JavadocContentToHtmlTranslator( """$content""" private fun String.formatToEndWithHtml() = - if (endsWith(".html")) this else "$this.html" + if (endsWith(".html") || contains(Regex("\\.html#"))) this else "$this.html" } } \ No newline at end of file diff --git a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt index 0c952fe9..56df469b 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/renderer/JavadocContentToTemplateMapTranslator.kt @@ -1,5 +1,6 @@ package javadoc.renderer +import javadoc.location.JavadocLocationProvider import javadoc.pages.* import javadoc.toNormalized import org.jetbrains.dokka.Platform @@ -13,7 +14,7 @@ import org.jetbrains.dokka.plugability.DokkaContext import java.nio.file.Paths internal class JavadocContentToTemplateMapTranslator( - private val locationProvider: LocationProvider, + private val locationProvider: JavadocLocationProvider, private val context: DokkaContext, ) { @@ -82,6 +83,7 @@ internal class JavadocContentToTemplateMapTranslator( "brief" to htmlForContentNodes(node.brief, contextNode), "parameters" to node.parameters.map { templateMapForParameterNode(it) }, "inlineParameters" to node.parameters.joinToString { renderInlineParameter(it) }, + "anchorLink" to locationProvider.anchorForFunctionNode(node), "signature" to templateMapForSignatureNode(node.signature), "name" to node.name ) diff --git a/plugins/javadoc/src/main/kotlin/javadoc/signatures/JavadocSignatureProvider.kt b/plugins/javadoc/src/main/kotlin/javadoc/signatures/JavadocSignatureProvider.kt index c2483cc2..f9bee318 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/signatures/JavadocSignatureProvider.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/signatures/JavadocSignatureProvider.kt @@ -99,10 +99,10 @@ class JavadocSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLo text("(") list(f.parameters) { annotationsInline(it) - text(it.modifiers()[it]?.toSignatureString() ?: "") + text(it.modifiers()[it]?.toSignatureString().orEmpty()) signatureForProjection(it.type) text(Typography.nbsp.toString()) - link(it.name!!, it.dri) + text(it.name.orEmpty()) } text(")") } @@ -180,7 +180,7 @@ class JavadocSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLo private fun PageContentBuilder.DocumentableContentBuilder.signatureForProjection(p: Projection): Unit = when (p) { is OtherParameter -> link(p.name, p.declarationDRI) is TypeConstructor -> group { - link(p.dri.fqName(), p.dri) + link(p.dri.classNames.orEmpty(), p.dri) list(p.projections, prefix = "<", suffix = ">") { signatureForProjection(it) } @@ -191,7 +191,7 @@ class JavadocSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLo } is Star -> text("?") is Nullable -> signatureForProjection(p.inner) - is JavaObject, is Dynamic -> link("java.lang.Object", DRI("java.lang", "Object")) + is JavaObject, is Dynamic -> link("Object", DRI("java.lang", "Object")) is Void -> text("void") is PrimitiveJavaType -> text(p.name) is UnresolvedBound -> text(p.name) diff --git a/plugins/javadoc/src/main/resources/views/class.korte b/plugins/javadoc/src/main/resources/views/class.korte index 62d90f7d..7c0ca368 100644 --- a/plugins/javadoc/src/main/resources/views/class.korte +++ b/plugins/javadoc/src/main/resources/views/class.korte @@ -254,9 +254,7 @@

      Method Detail

      {% for method in methods.own %} - - - +
      • {{ method.name }}

        diff --git a/plugins/javadoc/src/test/kotlin/javadoc/JavadocClasslikeTemplateMapTest.kt b/plugins/javadoc/src/test/kotlin/javadoc/JavadocClasslikeTemplateMapTest.kt index dc1573e1..340e4697 100644 --- a/plugins/javadoc/src/test/kotlin/javadoc/JavadocClasslikeTemplateMapTest.kt +++ b/plugins/javadoc/src/test/kotlin/javadoc/JavadocClasslikeTemplateMapTest.kt @@ -2,7 +2,6 @@ package javadoc import javadoc.pages.JavadocClasslikePageNode import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import testApi.utils.assertIsInstance @@ -94,8 +93,8 @@ internal class JavadocClasslikeTemplateMapTest : AbstractJavadocTemplateMapTest( 0, assertIsInstance>(method["parameters"]).size, "Expected no parameters" ) - assertEquals("final
        java.lang.String", method.modifiers()) - assertEquals("testFunction()", method.signatureWithoutModifiers()) + assertEquals("final String", method.modifiers()) + assertEquals("testFunction()", method.signatureWithoutModifiers()) } } @@ -204,8 +203,8 @@ internal class JavadocClasslikeTemplateMapTest : AbstractJavadocTemplateMapTest( assertEquals("Sample docs for first", first["brief"]) assertEquals("Sample docs for second", second["brief"]) - assertEquals("FIRST", first.signatureWithoutModifiers()) - assertEquals("SECOND", second.signatureWithoutModifiers()) + assertEquals("FIRST", first.signatureWithoutModifiers()) + assertEquals("SECOND", second.signatureWithoutModifiers()) } } @@ -258,19 +257,19 @@ internal class JavadocClasslikeTemplateMapTest : AbstractJavadocTemplateMapTest( assertParameterNode( node = first, expectedName = "simple", - expectedType = "java.lang.String", + expectedType = "String", expectedDescription = "simple String parameter" ) assertParameterNode( node = second, expectedName = "parameters", - expectedType = "java.lang.Integer", + expectedType = "Integer", expectedDescription = "simple Integer parameter" ) assertParameterNode( node = third, expectedName = "list", - expectedType = "java.lang.Boolean", + expectedType = "Boolean", expectedDescription = "simple Boolean parameter" ) } @@ -306,14 +305,14 @@ internal class JavadocClasslikeTemplateMapTest : AbstractJavadocTemplateMapTest( assertEquals("Generic", map["name"]) assertEquals( - "public final class Generic<T extends java.io.Serializable>", + "public final class Generic<T extends Serializable>", map.signatureWithModifiers() ) val methods = assertIsInstance>(map["methods"]) val ownMethods = assertIsInstance>(methods["own"]).first() val sampleFunction = assertIsInstance>(ownMethods) - assertEquals("final <D extends T> D sampleFunction()", sampleFunction.signatureWithModifiers()) + assertEquals("final <D extends T> D sampleFunction()", sampleFunction.signatureWithModifiers()) } } diff --git a/plugins/javadoc/src/test/kotlin/javadoc/location/JavadocLocationTest.kt b/plugins/javadoc/src/test/kotlin/javadoc/location/JavadocLocationTest.kt index d60e1070..65d5481d 100644 --- a/plugins/javadoc/src/test/kotlin/javadoc/location/JavadocLocationTest.kt +++ b/plugins/javadoc/src/test/kotlin/javadoc/location/JavadocLocationTest.kt @@ -7,16 +7,17 @@ import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.ExternalDocumentationLinkImpl import org.jetbrains.dokka.javadoc.JavadocPlugin import org.jetbrains.dokka.model.firstChildOfType +import org.jetbrains.dokka.pages.RootPageNode +import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest import org.junit.jupiter.api.Test +import org.junit.jupiter.api.Assertions.assertEquals class JavadocTest : AbstractCoreTest() { - @Test - fun `resolved signature with external links`() { - + private fun locationTestInline(testHandler: (RootPageNode, DokkaContext) -> Unit) { fun externalLink(link: String) = DokkaConfiguration.ExternalDocumentationLink .Builder(link) .build() as ExternalDocumentationLinkImpl @@ -34,31 +35,94 @@ class JavadocTest : AbstractCoreTest() { } } } - testInline( """ |/jvmSrc/javadoc/Test.kt |package javadoc |import java.io.Serializable - |class Test() : Serializable, Cloneable + |class Test() : Serializable, Cloneable { + | fun test() {} + | fun test2(s: String) {} + | fun test3(a: A, t: T) {} + |} """.trimIndent(), config, cleanupOutput = false, pluginOverrides = listOf(JavadocPlugin()) - ) { - renderingStage = { rootPageNode, dokkaContext -> - val transformer = JavadocContentToHtmlTranslator( - dokkaContext.plugin().querySingle { locationProviderFactory } - .getLocationProvider(rootPageNode), - dokkaContext + ) { renderingStage = testHandler } + } + + @Test + fun `resolved signature with external links`() { + + locationTestInline { rootPageNode, dokkaContext -> + val transformer = htmlTranslator(rootPageNode, dokkaContext) + val testClass = rootPageNode.firstChildOfType() + .firstChildOfType() + assertEquals( + " implements Serializable, Cloneable", + transformer.htmlForContentNode(testClass.signature.supertypes!!, null) + ) + } + } + + @Test + fun `resolved signature to no argument function`() { + + locationTestInline { rootPageNode, dokkaContext -> + val transformer = htmlTranslator(rootPageNode, dokkaContext) + val testClassNode = rootPageNode.firstChildOfType() + .firstChildOfType { it.name == "Test" } + val testFunctionNode = testClassNode.methods.first { it.name == "test" } + assertEquals( + """test()""", + transformer.htmlForContentNode( + testFunctionNode.signature.signatureWithoutModifiers, + testClassNode ) - val testClass = rootPageNode.firstChildOfType() - .firstChildOfType() - assert( - " implements Serializable, Cloneable" - == transformer.htmlForContentNode(testClass.signature.supertypes!!, null) + ) + } + } + + @Test + fun `resolved signature to one argument function`() { + + locationTestInline { rootPageNode, dokkaContext -> + val transformer = htmlTranslator(rootPageNode, dokkaContext) + val testClassNode = rootPageNode.firstChildOfType() + .firstChildOfType { it.name == "Test" } + val testFunctionNode = testClassNode.methods.first { it.name == "test2" } + assertEquals( + """test2(String s)""", + transformer.htmlForContentNode( + testFunctionNode.signature.signatureWithoutModifiers, + testClassNode ) - } + ) } } + + @Test + fun `resolved signature to generic function`() { + + locationTestInline { rootPageNode, dokkaContext -> + val transformer = htmlTranslator(rootPageNode, dokkaContext) + val testClassNode = rootPageNode.firstChildOfType() + .firstChildOfType { it.name == "Test" } + val testFunctionNode = testClassNode.methods.first { it.name == "test3" } + assertEquals( + """test3(A a, T t)""", + transformer.htmlForContentNode( + testFunctionNode.signature.signatureWithoutModifiers, + testClassNode + ) + ) + } + } + + private fun htmlTranslator(rootPageNode: RootPageNode, dokkaContext: DokkaContext) = JavadocContentToHtmlTranslator( + dokkaContext.plugin().querySingle { locationProviderFactory } + .getLocationProvider(rootPageNode), + dokkaContext + ) } -- cgit From e6184e5171d5a16bb4cc1fbd296309a66795eae5 Mon Sep 17 00:00:00 2001 From: Błażej Kardyś Date: Wed, 15 Jul 2020 09:00:51 +0200 Subject: Javadoc constructor anchor link fix --- .../main/kotlin/javadoc/location/JavadocLocationProvider.kt | 12 +++++------- plugins/javadoc/src/main/resources/views/class.korte | 8 +++----- 2 files changed, 8 insertions(+), 12 deletions(-) (limited to 'plugins/javadoc/src/main/resources/views/class.korte') diff --git a/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt b/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt index f77970eb..3a48261c 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/location/JavadocLocationProvider.kt @@ -6,10 +6,7 @@ import org.jetbrains.dokka.base.resolvers.local.BaseLocationProvider import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.Nullable import org.jetbrains.dokka.links.parent -import org.jetbrains.dokka.model.OtherParameter -import org.jetbrains.dokka.model.PrimitiveJavaType -import org.jetbrains.dokka.model.TypeConstructor -import org.jetbrains.dokka.model.UnresolvedBound +import org.jetbrains.dokka.model.* import org.jetbrains.dokka.pages.ContentPage import org.jetbrains.dokka.pages.PageNode import org.jetbrains.dokka.pages.RootPageNode @@ -79,12 +76,13 @@ class JavadocLocationProvider(pageRoot: RootPageNode, dokkaContext: DokkaContext } private fun JavadocFunctionNode.getAnchor(): String = - "$name-${parameters.joinToString(",%20") { - when (val bound = it.typeBound) { + "$name-${parameters.joinToString("-") { + when (val bound = if (it.typeBound is org.jetbrains.dokka.model.Nullable) it.typeBound.inner else it.typeBound) { is TypeConstructor -> bound.dri.classNames.orEmpty() is OtherParameter -> bound.name is PrimitiveJavaType -> bound.name is UnresolvedBound -> bound.name + is JavaObject -> "Object" else -> bound.toString() } }}-" @@ -93,7 +91,7 @@ class JavadocLocationProvider(pageRoot: RootPageNode, dokkaContext: DokkaContext private fun anchorForDri(dri: DRI): String = dri.callable?.let { callable -> - "${callable.name}-${callable.params.joinToString(",%20") { + "${callable.name}-${callable.params.joinToString("-") { ((it as? Nullable)?.wrapped ?: it).toString() }}-" } ?: dri.classNames.orEmpty() diff --git a/plugins/javadoc/src/main/resources/views/class.korte b/plugins/javadoc/src/main/resources/views/class.korte index 7c0ca368..a909bf3c 100644 --- a/plugins/javadoc/src/main/resources/views/class.korte +++ b/plugins/javadoc/src/main/resources/views/class.korte @@ -118,7 +118,7 @@ {% for constructor in constructors %} {{ constructor.name }}({{ constructor.inlineParameters|raw }}) + href="#{{ constructor.anchorLink }}">{{ constructor.name }}({{ constructor.inlineParameters|raw }}) {{ constructor.brief|raw }} {% endfor %} @@ -220,9 +220,7 @@

        Constructor Detail

        {% for constructor in constructors %} - - - +
        • {{ constructor.name }}

          @@ -254,7 +252,7 @@

          Method Detail

          {% for method in methods.own %} - +
          • {{ method.name }}

            -- cgit From c5b233aca9c81792b6313dc45dd5055cbb24901a Mon Sep 17 00:00:00 2001 From: Kamil Doległo Date: Tue, 14 Jul 2020 19:17:49 +0200 Subject: Fix table rendering with JDK12 stylesheets --- .../src/main/kotlin/javadoc/JavadocPageCreator.kt | 2 +- .../javadoc/src/main/resources/views/class.korte | 157 +++++++++++---------- .../resources/views/components/indexTable.korte | 10 +- .../javadoc/JavadocPackageTemplateMapTest.kt | 4 +- 4 files changed, 94 insertions(+), 79 deletions(-) (limited to 'plugins/javadoc/src/main/resources/views/class.korte') diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt index 52a8a50b..6fe18001 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt @@ -116,7 +116,7 @@ open class JavadocPageCreator( } private val KClass.tabTitle: String - get() = colTitle + if(colTitle.last() != 's') "s" else "es" + get() = "$colTitle Summary" private fun contentForClasslike(c: DClasslike): JavadocContentNode = JavadocContentGroup( diff --git a/plugins/javadoc/src/main/resources/views/class.korte b/plugins/javadoc/src/main/resources/views/class.korte index a909bf3c..adf719af 100644 --- a/plugins/javadoc/src/main/resources/views/class.korte +++ b/plugins/javadoc/src/main/resources/views/class.korte @@ -52,22 +52,24 @@

            Nested Class Summary

            - - - - - - - - {% for classlike in classlikes %} - - - - - - {% endfor %} -
            Nested Classes 
            Modifier and TypeClassDescription
            {{ classlike.modifiers }}{{ classlike.signature }} - {{ classlike.description }}
            +
            + + + + + + + + {% for classlike in classlikes %} + + + + + + {% endfor %} +
            Nested Classes 
            Modifier and TypeClassDescription
            {{ classlike.modifiers }}{{ classlike.signature }} + {{ classlike.description }}
            +
          @@ -80,21 +82,23 @@

          Field Summary

          - - - - - - - - {% for property in properties %} - - - - - - {% endfor %} -
          Fields 
          Modifier and TypeFieldDescription
          {{ property.modifiers|raw }}{{ property.signature|raw }}{{ description|raw }}
          +
          + + + + + + + + {% for property in properties %} + + + + + + {% endfor %} +
          Fields 
          Modifier and TypeFieldDescription
          {{ property.modifiers|raw }}{{ property.signature|raw }}{{ description|raw }}
          +
        @@ -107,24 +111,26 @@

        Constructor Summary

        - - - - - - - - - {% for constructor in constructors %} - - - +
        +
        Constructors 
        ConstructorDescription
        {{ constructor.name }}({{ constructor.inlineParameters|raw }}){{ constructor.brief|raw }}
        + + + + + - {% endfor %} - -
        Constructors 
        ConstructorDescription
        + {% for constructor in constructors %} + + {{ constructor.name }}({{ constructor.inlineParameters|raw }}) + {{ constructor.brief|raw }} + + {% endfor %} + + + +
      @@ -163,29 +169,30 @@

      Method Summary

      - - - - - - - - - {% for method in methods.own %} - - - - - - {% endfor %} - -
      All Methods Static Methods Concrete Methods 
      Modifier and TypeMethodDescription
      {{ method.signature.modifiers|raw }} - {{ method.signature.signatureWithoutModifiers|raw }} - {{ method.brief|raw }}
      +
      +
      + + +
      +
      + + + + + + + {% for method in methods.own %} + + + + + + {% endfor %} + +
      Modifier and TypeMethodDescription
      {{ method.signature.modifiers|raw }} + {{ method.signature.signatureWithoutModifiers|raw }} + {{ method.brief|raw }}
      +
        {% for method in methods.inherited %}
      • @@ -252,8 +259,14 @@

        Method Detail

        {% for method in methods.own %} - -
          + + + +
          • {{ method.name }}

            {{ method.signature.annotations|raw }} {{ method.signature.modifiers|raw }} {{ method.signature.signatureWithoutModifiers|raw}}
            diff --git a/plugins/javadoc/src/main/resources/views/components/indexTable.korte b/plugins/javadoc/src/main/resources/views/components/indexTable.korte index e1b507b9..21c94b7c 100644 --- a/plugins/javadoc/src/main/resources/views/components/indexTable.korte +++ b/plugins/javadoc/src/main/resources/views/components/indexTable.korte @@ -1,8 +1,7 @@ {% if isTypeSummary %} - -{% else %} -
            +
            {% endif %} +
            @@ -13,4 +12,7 @@ {{ createTabRow(item, contextRoot)|raw }} {% end -%} -
            {{ tabTitle }} 
            {{ colTitle }}
            \ No newline at end of file + +{% if isTypeSummary %} +
      +{% endif %} \ No newline at end of file diff --git a/plugins/javadoc/src/test/kotlin/javadoc/JavadocPackageTemplateMapTest.kt b/plugins/javadoc/src/test/kotlin/javadoc/JavadocPackageTemplateMapTest.kt index a1b99ba0..e0ef030e 100644 --- a/plugins/javadoc/src/test/kotlin/javadoc/JavadocPackageTemplateMapTest.kt +++ b/plugins/javadoc/src/test/kotlin/javadoc/JavadocPackageTemplateMapTest.kt @@ -28,7 +28,7 @@ internal class JavadocPackageTemplateMapTest : AbstractJavadocTemplateMapTest() """ ) { val map = singlePageOfType().templateMap - assertEquals("Classes", ((map["lists"] as List<*>).first() as Map)["tabTitle"]) + assertEquals("Class Summary", ((map["lists"] as List<*>).first() as Map)["tabTitle"]) assertEquals("Class", ((map["lists"] as List<*>).first() as Map)["colTitle"]) assertEquals("com.test.package0", map["title"]) assertEquals("", map["subtitle"]) @@ -69,7 +69,7 @@ internal class JavadocPackageTemplateMapTest : AbstractJavadocTemplateMapTest() val packagePages = allPagesOfType() packagePages.forEach { page -> val map = page.templateMap - assertEquals("Classes", ((map["lists"] as List<*>).first() as Map)["tabTitle"]) + assertEquals("Class Summary", ((map["lists"] as List<*>).first() as Map)["tabTitle"]) assertEquals("Class", ((map["lists"] as List<*>).first() as Map)["colTitle"]) assertEquals("", map["subtitle"]) assertEquals("package", map["kind"]) -- cgit From 70f4b9b34e7fdcbf5cd3c577c3261546696dea6a Mon Sep 17 00:00:00 2001 From: Kamil Doległo Date: Thu, 16 Jul 2020 15:35:29 +0200 Subject: Fix not working javadoc anchors --- plugins/javadoc/src/main/resources/views/class.korte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugins/javadoc/src/main/resources/views/class.korte') diff --git a/plugins/javadoc/src/main/resources/views/class.korte b/plugins/javadoc/src/main/resources/views/class.korte index adf719af..1ddf6796 100644 --- a/plugins/javadoc/src/main/resources/views/class.korte +++ b/plugins/javadoc/src/main/resources/views/class.korte @@ -123,7 +123,7 @@ {% for constructor in constructors %} {{ constructor.name }}({{ constructor.inlineParameters|raw }}) + href="#{{ constructor.anchorLink }}">{{ constructor.name }}({{ constructor.inlineParameters|raw }}) {{ constructor.brief|raw }} {% endfor %} -- cgit