diff options
Diffstat (limited to 'plugins')
7 files changed, 94 insertions, 66 deletions
diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index 8588534b..7c797233 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -43,7 +43,7 @@ class DefaultPsiToDocumentableTranslator( override fun invoke(sourceSet: DokkaSourceSet, context: DokkaContext): DModule { - fun isFileInSourceRoots(file: File): Boolean { + fun isFileInSourceRoots(file: File) : Boolean { return sourceSet.sourceRoots.any { root -> file.path.startsWith(File(root.path).absolutePath) } } @@ -256,7 +256,7 @@ class DefaultPsiToDocumentableTranslator( inheritedFrom: DRI? = null ): DFunction { val dri = DRI.from(psi) - val docs = javadocParser.parseDocumentation(psi).toSourceSetDependent() + val docs = javadocParser.parseDocumentation(psi) return DFunction( dri, if (isConstructor) "<init>" else psi.name, @@ -265,13 +265,17 @@ class DefaultPsiToDocumentableTranslator( DParameter( dri.copy(target = dri.target.nextTarget()), psiParameter.name, - DocumentationNode(docs.entries.mapNotNull { it.value.children.filterIsInstance<Param>().firstOrNull { it.root.children.firstIsInstanceOrNull<DocumentationLink>()?.children?.firstIsInstanceOrNull<Text>()?.body == psiParameter.name } }).toSourceSetDependent(), + DocumentationNode( + listOfNotNull(docs.firstChildOfType<Param> { + it.firstChildOfType<DocumentationLink>() + ?.firstChildOfType<Text>()?.body == psiParameter.name + })).toSourceSetDependent(), null, getBound(psiParameter.type), setOf(sourceSetData) ) }, - docs, + docs.toSourceSetDependent(), null, PsiDocumentableSource(psi).toSourceSetDependent(), psi.getVisibility().toSourceSetDependent(), @@ -301,7 +305,6 @@ class DefaultPsiToDocumentableTranslator( ExtraModifiers.JavaOnlyModifiers.Transitive.takeIf { hasModifier(JvmModifier.TRANSITIVE) } ).toSet() - private fun Set<ExtraModifiers>.toListOfAnnotations() = map { if (it !is ExtraModifiers.JavaOnlyModifiers.Static) Annotations.Annotation(DRI("kotlin.jvm", it.name.toLowerCase().capitalize()), emptyMap()) @@ -394,7 +397,7 @@ class DefaultPsiToDocumentableTranslator( val dri = DRI.from(psi) return DProperty( dri, - psi.name!!, // TODO: Investigate if this is indeed nullable + psi.name, javadocParser.parseDocumentation(psi).toSourceSetDependent(), null, PsiDocumentableSource(psi).toSourceSetDependent(), diff --git a/plugins/base/src/test/kotlin/model/JavaTest.kt b/plugins/base/src/test/kotlin/model/JavaTest.kt index aefcc642..bd7e3b55 100644 --- a/plugins/base/src/test/kotlin/model/JavaTest.kt +++ b/plugins/base/src/test/kotlin/model/JavaTest.kt @@ -6,13 +6,10 @@ 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") { @@ -37,7 +34,7 @@ class JavaTest : AbstractModelTest("/src/main/kotlin/java/Test.java", "java") { with((this / "fn").cast<DFunction>()) { name equals "fn" val params = parameters.map { it.documentation.values.first().children.first() as Param } - params.mapNotNull { it.root.children.firstIsInstanceOrNull<Text>()?.body } equals listOf("is String parameter", "is int parameter") + params.mapNotNull { it.firstChildOfType<Text>()?.body } equals listOf("is String parameter", "is int parameter") } } } diff --git a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt index 6cf34ed1..3074a760 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/JavadocPageCreator.kt @@ -9,21 +9,19 @@ 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.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.ContentNode +import org.jetbrains.dokka.pages.ContentText 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, - val signatureProvider: SignatureProvider, + private val signatureProvider: SignatureProvider, val logger: DokkaLogger ) { @@ -41,81 +39,63 @@ open class JavadocPageCreator( ) fun pageForClasslike(c: DClasslike): JavadocClasslikePageNode? = - c.sourceSets.firstOrNull { it.analysisPlatform == Platform.jvm }?.let { jvm -> + c.mostTopSourceSet?.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(), - description = c.description(jvm), + description = c.descriptionToContentNodes(), constructors = c.safeAs<WithConstructors>()?.constructors?.map { it.toJavadocFunction(jvm) }.orEmpty(), methods = c.functions.map { it.toJavadocFunction(jvm) }, - entries = c.safeAs<DEnum>()?.entries?.map { - JavadocEntryNode( - signatureProvider.signature(it).jvmSignature(), - it.description(jvm) - ) - }.orEmpty(), + entries = c.safeAs<DEnum>()?.entries?.map { JavadocEntryNode(signatureProvider.signature(it).jvmSignature(), it.descriptionToContentNodes(jvm)) }.orEmpty(), classlikes = c.classlikes.mapNotNull { pageForClasslike(it) }, - properties = c.properties.map { - JavadocPropertyNode( - signatureProvider.signature(it).jvmSignature(), - TextNode(it.description(jvm), setOf(jvm)) - ) - }, + properties = c.properties.map { JavadocPropertyNode(signatureProvider.signature(it).jvmSignature(), it.descriptionToContentNodes(jvm)) }, documentable = c, extras = c.safeAs<WithExtraProperties<Documentable>>()?.extra ?: PropertyContainer.empty() ) } - fun contentForModule(m: DModule): JavadocContentNode = + private fun contentForModule(m: DModule): JavadocContentNode = JavadocContentGroup( setOf(m.dri), JavadocContentKind.OverviewSummary, - m.sourceSets.filter { it.analysisPlatform == Platform.jvm }.toSet() + m.jvmSource.toSet() ) { - title(m.name, "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 -> - val description = p.documentation.entries.find { (k, _) -> k.analysisPlatform == Platform.jvm }?.value?.let { - it.children.firstIsInstanceOrNull<Description>()?.let { description -> - DocTagToContentConverter.buildContent( - description.root, - DCI(setOf(p.dri), JavadocContentKind.OverviewSummary), - sourceSets - ) - } - }.orEmpty() RowJavadocListEntry( LinkJavadocListEntry(p.name, setOf(p.dri), JavadocContentKind.PackageSummary, sourceSets), - description + p.brief() ) }) } - fun contentForPackage(p: DPackage): JavadocContentNode = + private fun contentForPackage(p: DPackage): JavadocContentNode = JavadocContentGroup( setOf(p.dri), JavadocContentKind.PackageSummary, - p.sourceSets.filter { it.analysisPlatform == Platform.jvm }.toSet() + p.jvmSource.toSet() ) { - title(p.name, "0.0.1", dri = setOf(p.dri), kind = ContentKind.Packages) + title(p.name, p.brief(),"0.0.1", dri = setOf(p.dri), kind = ContentKind.Packages) list("Packages", "Package", setOf(p.dri), ContentKind.Packages, p.classlikes.sortedBy { it.name }.map { c -> RowJavadocListEntry( LinkJavadocListEntry(c.name.orEmpty(), setOf(c.dri), JavadocContentKind.Class, sourceSets), - listOf(signatureProvider.signature(c).jvmSignature()) + c.brief() ) }) } - fun contentForClasslike(c: DClasslike): JavadocContentNode = + private fun contentForClasslike(c: DClasslike): JavadocContentNode = JavadocContentGroup( setOf(c.dri), JavadocContentKind.Class, - c.sourceSets.filter { it.analysisPlatform == Platform.jvm }.toSet() + c.jvmSource.toSet() ) { title( c.name.orEmpty(), + c.brief(), "0.0.1", parent = c.dri.packageName, dri = setOf(c.dri), @@ -150,24 +130,51 @@ open class JavadocPageCreator( private fun DFunction.toJavadocFunction(sourceSetData: DokkaSourceSet) = JavadocFunctionNode( name = name, signature = signatureProvider.signature(this).jvmSignature(), - brief = TextNode(description(sourceSetData), setOf(sourceSetData)), + brief = brief(sourceSetData), parameters = parameters.map { JavadocParameterNode( name = it.name.orEmpty(), type = signatureForProjection(it.type), - description = TextNode(it.findNodeInDocumentation<Param>(sourceSetData), setOf(sourceSetData)) + description = it.brief() ) }, extras = extra ) - fun List<ContentNode>.jvmSignature(): ContentNode = - first { it.sourceSets.any { it.analysisPlatform == Platform.jvm } } + // THIS MUST BE DISCUSSED + private val Documentable.jvmSource + get() = sourceSets.filter { it.analysisPlatform == Platform.jvm } - private fun Documentable.description(sourceSetData: DokkaSourceSet): String = - findNodeInDocumentation<Description>(sourceSetData) + private val Documentable.mostTopSourceSet + get() = jvmSource.let { sources -> + sources.firstOrNull { it != expectPresentInSet } ?: sources.firstOrNull() + } + + private val firstSentenceRegex = Regex("^((?:[^.?!]|[.!?](?!\\s))*[.!?])") - private inline fun <reified T : TagWrapper> Documentable.findNodeInDocumentation(sourceSetData: DokkaSourceSet): String = - documentation[sourceSetData]?.children?.firstIsInstanceOrNull<T>()?.root?.children?.firstIsInstanceOrNull<Text>()?.body.orEmpty() + private inline fun <reified T: TagWrapper> Documentable.findNodeInDocumentation(sourceSetData: SourceSetData?): T? = + documentation[sourceSetData]?.firstChildOfType<T>() + + private fun Documentable.descriptionToContentNodes(sourceSet: SourceSetData? = mostTopSourceSet) = findNodeInDocumentation<Description>(sourceSet)?.let { + DocTagToContentConverter.buildContent( + it.root, + DCI(setOf(dri), JavadocContentKind.OverviewSummary), + sourceSets.toSet() + ) + }.orEmpty() + + private fun Documentable.brief(sourceSet: SourceSetData? = mostTopSourceSet): List<ContentNode> { + val description = descriptionToContentNodes(sourceSet) + val contents = mutableListOf<ContentNode>() + for (node in description) { + if ( node is ContentText && firstSentenceRegex.containsMatchIn(node.text) ) { + contents.add(node.copy(text = firstSentenceRegex.find(node.text)?.value.orEmpty())) + break + } else { + contents.add(node) + } + } + return contents + } } diff --git a/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt b/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt index 23a7c9ed..cec5bbca 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/KorteJavadocRenderer.kt @@ -238,7 +238,7 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon val (modifiers, signature) = node.modifiersAndSignature return mapOf( "signature" to htmlForContentNode(node.signature), - "brief" to htmlForContentNode(node.brief), + "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), @@ -249,7 +249,7 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon private fun renderParameterNode(node: JavadocParameterNode): TemplateMap = mapOf( - "description" to htmlForContentNode(node.description), + "description" to htmlForContentNodes(node.description), "name" to node.name, "type" to node.type ) @@ -259,6 +259,7 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon "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) }, @@ -304,7 +305,7 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon return mapOf( "modifiers" to (node.modifiers + "static" + node.kind).joinToString(separator = " "), "signature" to node.name, - "description" to node.description + "description" to renderContentNodes(node.description) ) } @@ -313,7 +314,7 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon return mapOf( "modifiers" to htmlForContentNode(modifiers), "signature" to htmlForContentNode(signature), - "description" to htmlForContentNode(node.brief) + "description" to htmlForContentNodes(node.brief) ) } @@ -324,6 +325,8 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon ) } + private fun renderContentNodes(nodes: List<ContentNode>): String = nodes.joinToString(separator = "") { htmlForContentNode(it) } + fun htmlForContentNode(node: ContentNode): String = when (node) { is ContentGroup -> node.children.joinToString(separator = "") { htmlForContentNode(it) } @@ -333,9 +336,18 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon node.address, node.sourceSets )}">${node.children.joinToString { htmlForContentNode(it) }} </a>""".trimMargin() + is ContentCode -> renderCode(node.children) else -> "" } + private fun renderCode(code: List<ContentNode>) : String = code.map { element -> + when (element) { + is ContentText -> element.text + is ContentBreakLine -> "" + else -> run { context.logger.error("Cannot cast $element as ContentText!"); "" } + } + }.joinToString("<br>", "<span class=\"code\">", "</span>") { it } + fun renderJavadocContentNode(node: JavadocContentNode): TemplateMap = when (node) { is TitleNode -> renderTitleNode(node) is JavadocContentGroup -> renderJavadocContentGroup(node) @@ -347,6 +359,7 @@ class KorteJavadocRenderer(val outputWriter: OutputWriter, val context: DokkaCon 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 ) diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt index 286223fa..5b45bdf7 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocContentNodes.kt @@ -65,23 +65,25 @@ class JavaContentGroupBuilder(val sourceSets: Set<DokkaSourceSet>) { class TitleNode( val title: String, + val subtitle: List<ContentNode>, val version: String, val parent: String?, val dri: Set<DRI>, val kind: Kind, sourceSets: Set<DokkaSourceSet> ) : JavadocContentNode(dri, kind, sourceSets) { - override fun hasAnyContent(): Boolean = !title.isBlank() || !version.isBlank() + override fun hasAnyContent(): Boolean = !title.isBlank() || !version.isBlank() || subtitle.isNotEmpty() } fun JavaContentGroupBuilder.title( title: String, + subtitle: List<ContentNode>, version: String, parent: String? = null, dri: Set<DRI>, kind: Kind ) { - list.add(TitleNode(title, version, parent, dri, kind, sourceSets)) + list.add(TitleNode(title, subtitle, version, parent, dri, kind, sourceSets)) } data class TextNode( diff --git a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt index f583144f..5ac232d4 100644 --- a/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt +++ b/plugins/javadoc/src/main/kotlin/javadoc/pages/JavadocPageNodes.kt @@ -83,18 +83,18 @@ class JavadocPackagePageNode( data class JavadocEntryNode( val signature: ContentNode, - val brief: String + val brief: List<ContentNode> ) data class JavadocParameterNode( val name: String, val type: String, - val description: ContentNode + val description: List<ContentNode> ) data class JavadocPropertyNode( val signature: ContentNode, - val brief: ContentNode + val brief: List<ContentNode> ) { val modifiersAndSignature: Pair<ContentNode, ContentNode> get() = (signature as ContentGroup).splitSignatureIntoModifiersAndName() @@ -102,7 +102,7 @@ data class JavadocPropertyNode( data class JavadocFunctionNode( val signature: ContentNode, - val brief: ContentNode, + val brief: List<ContentNode>, val parameters: List<JavadocParameterNode>, override val name: String, override val dri: Set<DRI> = emptySet(), @@ -138,7 +138,7 @@ class JavadocClasslikePageNode( override val dri: Set<DRI>, val modifiers: List<String>, val signature: ContentNode, - val description: String, + val description: List<ContentNode>, val constructors: List<JavadocFunctionNode>, val methods: List<JavadocFunctionNode>, val entries: List<JavadocEntryNode>, diff --git a/plugins/javadoc/src/main/resources/views/components/indexPage.korte b/plugins/javadoc/src/main/resources/views/components/indexPage.korte index 49d0fea2..adba2457 100644 --- a/plugins/javadoc/src/main/resources/views/components/indexPage.korte +++ b/plugins/javadoc/src/main/resources/views/components/indexPage.korte @@ -2,6 +2,12 @@ <div class="header"> <h1 {{ h1Title(kind)|raw }}class="title">{{ title }} {{ version }} API</h1> </div> + <div class="header"> + <div class="subtitle"> + <div class="block">{{ subtitle }}</div> + </div> + <p>See: <a href="#overview_description">Description</a></p> + </div> <div class="contentContainer"> <div class="overviewSummary"> {% include "components/indexTable.korte" %} |