From da22ee180cf956b0a0d0f40cd7de36b58956bdf2 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Fri, 21 Aug 2020 10:19:07 +0200 Subject: [PATCH 01/19] Implement ParseModuleAndPackageDocFragments API --- core/src/main/kotlin/DokkaException.kt | 2 +- core/src/main/kotlin/model/doc/DocTag.kt | 167 ++++++++------- .../ModuleAndPackageDocumentationParser.kt | 76 +++++++ .../base/src/main/kotlin/parsers/Parser.kt | 41 ++-- ...oduleAndPackageDocumentationTransformer.kt | 9 +- .../ParseModuleAndPackageDocFragmentsTest.kt | 199 ++++++++++++++++++ 6 files changed, 394 insertions(+), 100 deletions(-) create mode 100644 plugins/base/src/main/kotlin/parsers/ModuleAndPackageDocumentationParser.kt create mode 100644 plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocFragmentsTest.kt diff --git a/core/src/main/kotlin/DokkaException.kt b/core/src/main/kotlin/DokkaException.kt index 0010249cff..9a5e3d045e 100644 --- a/core/src/main/kotlin/DokkaException.kt +++ b/core/src/main/kotlin/DokkaException.kt @@ -1,3 +1,3 @@ package org.jetbrains.dokka -class DokkaException(message: String) : RuntimeException(message) +open class DokkaException(message: String) : RuntimeException(message) diff --git a/core/src/main/kotlin/model/doc/DocTag.kt b/core/src/main/kotlin/model/doc/DocTag.kt index dc2cd2be5a..0d3b0612e2 100644 --- a/core/src/main/kotlin/model/doc/DocTag.kt +++ b/core/src/main/kotlin/model/doc/DocTag.kt @@ -9,88 +9,105 @@ sealed class DocTag( ) : WithChildren { override fun equals(other: Any?): Boolean = ( - other != null && - other::class == this::class && - this.children == (other as DocTag).children && - this.params == other.params - ) + other != null && + other::class == this::class && + this.children == (other as DocTag).children && + this.params == other.params + ) override fun hashCode(): Int = children.hashCode() + params.hashCode() } -class A(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Big(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class B(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class BlockQuote(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -object Br : DocTag(emptyList(), emptyMap()) -class Cite(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -sealed class Code(children: List, params: Map) : DocTag(children, params) -class CodeInline(children: List = emptyList(), params: Map = emptyMap()) : Code(children, params) -class CodeBlock(children: List = emptyList(), params: Map = emptyMap()) : Code(children, params) -class Dd(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Dfn(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Dir(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Div(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Dl(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Dt(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Em(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Font(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Footer(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Frame(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class FrameSet(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class H1(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class H2(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class H3(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class H4(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class H5(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class H6(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Head(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Header(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Html(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class I(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class IFrame(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Img(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Input(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Li(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Link(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Listing(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Main(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Menu(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Meta(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Nav(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class NoFrames(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class NoScript(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Ol(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class P(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Pre(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Script(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Section(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Small(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Span(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Strikethrough(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Strong(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Sub(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Sup(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Table(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Text(val body: String = "", children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) { +class A(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Big(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class B(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class BlockQuote(children: List = emptyList(), params: Map = emptyMap()) : + DocTag(children, params) + +object Br : DocTag(emptyList(), emptyMap()) +class Cite(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +sealed class Code(children: List, params: Map) : DocTag(children, params) +class CodeInline(children: List = emptyList(), params: Map = emptyMap()) : + Code(children, params) + +class CodeBlock(children: List = emptyList(), params: Map = emptyMap()) : Code(children, params) +class Dd(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Dfn(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Dir(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Div(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Dl(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Dt(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Em(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Font(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Footer(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Frame(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class FrameSet(children: List = emptyList(), params: Map = emptyMap()) : + DocTag(children, params) + +class H1(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class H2(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class H3(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class H4(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class H5(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class H6(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Head(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Header(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Html(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class I(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class IFrame(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Img(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Input(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Li(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Link(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Listing(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Main(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Menu(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Meta(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Nav(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class NoFrames(children: List = emptyList(), params: Map = emptyMap()) : + DocTag(children, params) + +class NoScript(children: List = emptyList(), params: Map = emptyMap()) : + DocTag(children, params) + +class Ol(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class P(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Pre(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Script(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Section(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Small(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Span(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Strikethrough(children: List = emptyList(), params: Map = emptyMap()) : + DocTag(children, params) + +class Strong(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Sub(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Sup(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Table(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Text(val body: String = "", children: List = emptyList(), params: Map = emptyMap()) : + DocTag(children, params) { override fun equals(other: Any?): Boolean = super.equals(other) && this.body == (other as Text).body override fun hashCode(): Int = super.hashCode() + body.hashCode() } -class TBody(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Td(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class TFoot(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Th(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class THead(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Title(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Tr(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Tt(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class U(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Ul(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class Var(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class DocumentationLink(val dri: DRI, children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) { + +class TBody(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Td(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class TFoot(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Th(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class THead(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Title(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Tr(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Tt(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class U(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Ul(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class Var(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class DocumentationLink(val dri: DRI, children: List = emptyList(), params: Map = emptyMap()) : + DocTag(children, params) { override fun equals(other: Any?): Boolean = super.equals(other) && this.dri == (other as DocumentationLink).dri override fun hashCode(): Int = super.hashCode() + dri.hashCode() } -object HorizontalRule : DocTag(emptyList(), emptyMap()) -class Index(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) -class CustomDocTag(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) + +object HorizontalRule : DocTag(emptyList(), emptyMap()) +class Index(children: List = emptyList(), params: Map = emptyMap()) : DocTag(children, params) +class CustomDocTag(children: List = emptyList(), params: Map = emptyMap()) : + DocTag(children, params) diff --git a/plugins/base/src/main/kotlin/parsers/ModuleAndPackageDocumentationParser.kt b/plugins/base/src/main/kotlin/parsers/ModuleAndPackageDocumentationParser.kt new file mode 100644 index 0000000000..4b46537bb2 --- /dev/null +++ b/plugins/base/src/main/kotlin/parsers/ModuleAndPackageDocumentationParser.kt @@ -0,0 +1,76 @@ +package org.jetbrains.dokka.base.parsers + +import org.jetbrains.dokka.DokkaException +import java.io.File + +internal class IllegalModuleAndPackageDocumentation( + source: ModuleAndPackageDocumentationSource, message: String +) : DokkaException("[$source] $message") + +data class ModuleAndPackageDocFragment( + val classifier: Classifier, + val name: String, + val documentation: String +) { + enum class Classifier { Module, Package } +} + +internal abstract class ModuleAndPackageDocumentationSource { + abstract val sourceDescription: String + abstract val documentation: String + + override fun toString(): String { + return sourceDescription + } +} + +internal class ModuleAndPackageDocumentationFile(private val file: File) : ModuleAndPackageDocumentationSource() { + override val sourceDescription: String = file.path + override val documentation: String by lazy(LazyThreadSafetyMode.PUBLICATION) { file.readText() } +} + +internal fun parseModuleAndPackageDocFragments(source: File): List { + return parseModuleAndPackageDocFragments(ModuleAndPackageDocumentationFile(source)) +} + +internal fun parseModuleAndPackageDocFragments(source: ModuleAndPackageDocumentationSource): List { + val fragmentStrings = source.documentation.split(Regex("(|^)#\\s*(?=(Module|Package))")) + return fragmentStrings + .filter(String::isNotBlank) + .map { fragmentString -> parseModuleAndPackageDocFragment(source, fragmentString) } +} + +private fun parseModuleAndPackageDocFragment( + source: ModuleAndPackageDocumentationSource, + fragment: String +): ModuleAndPackageDocFragment { + val firstLineAndDocumentation = fragment.split("\r\n", "\n", "\r", limit = 2) + val firstLine = firstLineAndDocumentation[0] + + val classifierAndName = firstLine.split(Regex("\\s+"), limit = 2) + if (classifierAndName.size != 2) { + throw IllegalModuleAndPackageDocumentation(source, "Missing ${classifierAndName.first()} name") + } + + val classifier = when (classifierAndName[0].trim()) { + "Module" -> ModuleAndPackageDocFragment.Classifier.Module + "Package" -> ModuleAndPackageDocFragment.Classifier.Package + else -> throw IllegalStateException("Unexpected classifier ${classifierAndName[0]}") + } + + val name = classifierAndName[1].trim() + if (name.contains(Regex("\\s"))) { + throw IllegalModuleAndPackageDocumentation( + source, "Module/Package name cannot contain whitespace in '$firstLine'" + ) + } + + return ModuleAndPackageDocFragment( + classifier = classifier, + name = name, + documentation = firstLineAndDocumentation.getOrNull(1)?.trim().orEmpty() + ) +} + + + diff --git a/plugins/base/src/main/kotlin/parsers/Parser.kt b/plugins/base/src/main/kotlin/parsers/Parser.kt index 1dd0c34a6c..706f093b23 100644 --- a/plugins/base/src/main/kotlin/parsers/Parser.kt +++ b/plugins/base/src/main/kotlin/parsers/Parser.kt @@ -5,6 +5,7 @@ import org.jetbrains.dokka.model.doc.* abstract class Parser { abstract fun parseStringToDocNode(extractedString: String): DocTag + abstract fun preparse(text: String): String fun parse(text: String): DocumentationNode { @@ -12,22 +13,28 @@ abstract class Parser { val list = jkdocToListOfPairs(preparse(text)) val mappedList: List = list.map { - when(it.first) { - "description" -> Description(parseStringToDocNode(it.second)) - "author" -> Author(parseStringToDocNode(it.second)) - "version" -> Version(parseStringToDocNode(it.second)) - "since" -> Since(parseStringToDocNode(it.second)) - "see" -> See(parseStringToDocNode(it.second.substringAfter(' ')), it.second.substringBefore(' '), null) - "param" -> Param(parseStringToDocNode(it.second.substringAfter(' ')), it.second.substringBefore(' ')) - "property" -> Property(parseStringToDocNode(it.second.substringAfter(' ')), it.second.substringBefore(' ')) - "return" -> Return(parseStringToDocNode(it.second)) - "constructor" -> Constructor(parseStringToDocNode(it.second)) - "receiver" -> Receiver(parseStringToDocNode(it.second)) - "throws", "exception" -> Throws(parseStringToDocNode(it.second.substringAfter(' ')), it.second.substringBefore(' ')) - "deprecated" -> Deprecated(parseStringToDocNode(it.second)) - "sample" -> Sample(parseStringToDocNode(it.second.substringAfter(' ')), it.second.substringBefore(' ')) - "suppress" -> Suppress(parseStringToDocNode(it.second)) - else -> CustomTagWrapper(parseStringToDocNode(it.second), it.first) + when (it.first) { + "description" -> Description(parseStringToDocNode(it.second)) + "author" -> Author(parseStringToDocNode(it.second)) + "version" -> Version(parseStringToDocNode(it.second)) + "since" -> Since(parseStringToDocNode(it.second)) + "see" -> See(parseStringToDocNode(it.second.substringAfter(' ')), it.second.substringBefore(' '), null) + "param" -> Param(parseStringToDocNode(it.second.substringAfter(' ')), it.second.substringBefore(' ')) + "property" -> Property( + parseStringToDocNode(it.second.substringAfter(' ')), + it.second.substringBefore(' ') + ) + "return" -> Return(parseStringToDocNode(it.second)) + "constructor" -> Constructor(parseStringToDocNode(it.second)) + "receiver" -> Receiver(parseStringToDocNode(it.second)) + "throws", "exception" -> Throws( + parseStringToDocNode(it.second.substringAfter(' ')), + it.second.substringBefore(' ') + ) + "deprecated" -> Deprecated(parseStringToDocNode(it.second)) + "sample" -> Sample(parseStringToDocNode(it.second.substringAfter(' ')), it.second.substringBefore(' ')) + "suppress" -> Suppress(parseStringToDocNode(it.second)) + else -> CustomTagWrapper(parseStringToDocNode(it.second), it.first) } } return DocumentationNode(mappedList) @@ -39,4 +46,4 @@ abstract class Parser { .map { it.substringBefore(' ') to it.substringAfter(' ') } -} \ No newline at end of file +} diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt index 7182492209..5f1a540d03 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt @@ -37,12 +37,7 @@ internal class ModuleAndPackageDocumentationTransformer( .readText() .split(Regex("(\n|^)# (?=(Module|Package))")) // Matches heading with Module/Package to split by .filter { it.isNotEmpty() } - .map { - it.split( - Regex(" "), - 2 - ) - } // Matches space between Module/Package and fully qualified name + .map { it.split(Regex(" "), 2) } // Matches space between Module/Package and fully qualified name }.groupBy({ it[0] }, { it[1].split(Regex("\n"), 2) // Matches new line after fully qualified name .let { it[0].trim() to it[1].trim() } @@ -99,7 +94,7 @@ internal class ModuleAndPackageDocumentationTransformer( } } - private fun mergeDocumentation(origin: Map, new: Map) = + private fun mergeDocumentation(origin: Map, new: Map): Map = (origin.asSequence() + new.asSequence()) .distinct() .groupBy({ it.key }, { it.value }) diff --git a/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocFragmentsTest.kt b/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocFragmentsTest.kt new file mode 100644 index 0000000000..49eddaeabf --- /dev/null +++ b/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocFragmentsTest.kt @@ -0,0 +1,199 @@ +package parsers + +import org.jetbrains.dokka.base.parsers.IllegalModuleAndPackageDocumentation +import org.jetbrains.dokka.base.parsers.ModuleAndPackageDocFragment +import org.jetbrains.dokka.base.parsers.ModuleAndPackageDocFragment.Classifier.Module +import org.jetbrains.dokka.base.parsers.ModuleAndPackageDocFragment.Classifier.Package +import org.jetbrains.dokka.base.parsers.ModuleAndPackageDocumentationSource +import org.jetbrains.dokka.base.parsers.parseModuleAndPackageDocFragments +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.api.io.TempDir +import java.nio.file.Path + +class ParseModuleAndPackageDocFragmentsTest { + + @Test + fun `basic example`() { + + val fragments = parseModuleAndPackageDocFragments( + source( + """ + # Module kotlin-demo + Module description + + # Package org.jetbrains.kotlin.demo + Package demo description + ## Level 2 heading + Heading 2 + + # Package org.jetbrains.kotlin.demo2 + Package demo2 description + """.trimIndent() + ) + ) + + assertEquals( + listOf( + ModuleAndPackageDocFragment( + classifier = Module, + name = "kotlin-demo", + documentation = "Module description" + ), + ModuleAndPackageDocFragment( + classifier = Package, + name = "org.jetbrains.kotlin.demo", + documentation = "Package demo description\n## Level 2 heading\nHeading 2" + ), + ModuleAndPackageDocFragment( + classifier = Package, + name = "org.jetbrains.kotlin.demo2", + documentation = "Package demo2 description" + ) + ), + fragments + ) + } + + @Test + fun `no module name specified fails`() { + val exception = assertThrows { + parseModuleAndPackageDocFragments( + source( + """ + # Module + No module name given + """.trimIndent() + ) + ) + } + + assertTrue( + "Missing Module name" in exception.message.orEmpty(), + "Expected 'Missing Module name' in error message" + ) + } + + @Test + fun `no package name specified fails`() { + val exception = assertThrows { + parseModuleAndPackageDocFragments( + source( + """ + # Package + No package name given + """.trimIndent() + ) + ) + } + + assertTrue( + "Missing Package name" in exception.message.orEmpty(), + "Expected 'Missing Package name' in error message" + ) + } + + @Test + fun `white space in module name fails`() { + val exception = assertThrows { + parseModuleAndPackageDocFragments( + source( + """ + # Module My Module + """.trimIndent() + ) + ) + } + + assertTrue( + "Module My Module" in exception.message.orEmpty(), + "Expected problematic statement in error message" + ) + } + + @Test + fun `white space in package name fails`() { + val exception = assertThrows { + parseModuleAndPackageDocFragments( + source( + """ + # Package my package + """.trimIndent() + ) + ) + } + + assertTrue( + "Package my package" in exception.message.orEmpty(), + "Expected problematic statement in error message" + ) + } + + @Test + fun `multiple whitespaces are supported in first line`() { + val fragments = parseModuleAndPackageDocFragments( + source( + """ + # Module my-module + My Module + # Package com.my.package + My Package + """.trimIndent() + ) + ) + + assertEquals( + listOf( + ModuleAndPackageDocFragment( + classifier = Module, + name = "my-module", + documentation = "My Module" + ), + ModuleAndPackageDocFragment( + classifier = Package, + name = "com.my.package", + documentation = "My Package" + ) + ), + fragments + ) + } + + @Test + fun `parse from file`(@TempDir temporaryFolder: Path) { + val file = temporaryFolder.resolve("other.md").toFile() + file.writeText( + """ + # Module MyModule + D1 + # Package com.sample + D2 + """.trimIndent() + ) + + assertEquals( + listOf( + ModuleAndPackageDocFragment( + classifier = Module, + name = "MyModule", + documentation = "D1" + ), + ModuleAndPackageDocFragment( + classifier = Package, + name = "com.sample", + documentation = "D2" + ) + ), + parseModuleAndPackageDocFragments(file) + ) + } + + + private fun source(documentation: String): ModuleAndPackageDocumentationSource = + object : ModuleAndPackageDocumentationSource() { + override val sourceDescription: String = "inline test" + override val documentation: String = documentation + } +} From 208149d02ca48ede9a7248cf9dfcb3229c2f22f1 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Tue, 25 Aug 2020 14:28:44 +0200 Subject: [PATCH 02/19] Implement ModuleAndPackageDocumentationReader --- .../kotlin/utilities/associateWithNotNull.kt | 6 ++ plugins/base/src/main/kotlin/DokkaBase.kt | 6 +- .../ModuleAndPackageDocumentationParser.kt | 76 --------------- .../IllegalModuleAndPackageDocumentation.kt | 7 ++ .../ModuleAndPackageDocumentation.kt | 11 +++ .../ModuleAndPackageDocumentationFragment.kt | 10 ++ ...leAndPackageDocumentationParsingContext.kt | 36 +++++++ .../ModuleAndPackageDocumentationSource.kt | 17 ++++ .../parseModuleAndPackageDocumentation.kt | 15 +++ ...eModuleAndPackageDocumentationFragments.kt | 53 +++++++++++ .../ModuleAndPackageDocumentationReader.kt | 72 ++++++++++++++ ...oduleAndPackageDocumentationTransformer.kt | 93 +++---------------- ...leAndPackageDocumentationFragmentsTest.kt} | 78 ++++++++-------- 13 files changed, 283 insertions(+), 197 deletions(-) create mode 100644 core/src/main/kotlin/utilities/associateWithNotNull.kt delete mode 100644 plugins/base/src/main/kotlin/parsers/ModuleAndPackageDocumentationParser.kt create mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt create mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentation.kt create mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment.kt create mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext.kt create mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt create mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentation.kt create mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt create mode 100644 plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt rename plugins/base/src/test/kotlin/parsers/{ParseModuleAndPackageDocFragmentsTest.kt => ParseModuleAndPackageDocumentationFragmentsTest.kt} (68%) diff --git a/core/src/main/kotlin/utilities/associateWithNotNull.kt b/core/src/main/kotlin/utilities/associateWithNotNull.kt new file mode 100644 index 0000000000..ea2e8c3c08 --- /dev/null +++ b/core/src/main/kotlin/utilities/associateWithNotNull.kt @@ -0,0 +1,6 @@ +package org.jetbrains.dokka.utilities + +inline fun Iterable.associateWithNotNull(valueSelector: (K) -> V?): Map { + @Suppress("UNCHECKED_CAST") + return associateWith { valueSelector(it) }.filterValues { it != null } as Map +} diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index e74bc6d980..44a532f8ef 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -81,7 +81,9 @@ class DokkaBase : DokkaPlugin() { val modulesAndPackagesDocumentation by extending { CoreExtensions.preMergeDocumentableTransformer providing { ctx -> - ModuleAndPackageDocumentationTransformer(ctx, ctx.single(kotlinAnalysis)) + ModuleAndPackageDocumentationTransformer( + ModuleAndPackageDocumentationReader(ctx, ctx.single(kotlinAnalysis)) + ) } } @@ -127,7 +129,7 @@ class DokkaBase : DokkaPlugin() { } val sourceSetMerger by extending { - CoreExtensions.pageTransformer providing ::SourceSetMergingPageTransformer + CoreExtensions.pageTransformer providing ::SourceSetMergingPageTransformer } val fallbackMerger by extending { diff --git a/plugins/base/src/main/kotlin/parsers/ModuleAndPackageDocumentationParser.kt b/plugins/base/src/main/kotlin/parsers/ModuleAndPackageDocumentationParser.kt deleted file mode 100644 index 4b46537bb2..0000000000 --- a/plugins/base/src/main/kotlin/parsers/ModuleAndPackageDocumentationParser.kt +++ /dev/null @@ -1,76 +0,0 @@ -package org.jetbrains.dokka.base.parsers - -import org.jetbrains.dokka.DokkaException -import java.io.File - -internal class IllegalModuleAndPackageDocumentation( - source: ModuleAndPackageDocumentationSource, message: String -) : DokkaException("[$source] $message") - -data class ModuleAndPackageDocFragment( - val classifier: Classifier, - val name: String, - val documentation: String -) { - enum class Classifier { Module, Package } -} - -internal abstract class ModuleAndPackageDocumentationSource { - abstract val sourceDescription: String - abstract val documentation: String - - override fun toString(): String { - return sourceDescription - } -} - -internal class ModuleAndPackageDocumentationFile(private val file: File) : ModuleAndPackageDocumentationSource() { - override val sourceDescription: String = file.path - override val documentation: String by lazy(LazyThreadSafetyMode.PUBLICATION) { file.readText() } -} - -internal fun parseModuleAndPackageDocFragments(source: File): List { - return parseModuleAndPackageDocFragments(ModuleAndPackageDocumentationFile(source)) -} - -internal fun parseModuleAndPackageDocFragments(source: ModuleAndPackageDocumentationSource): List { - val fragmentStrings = source.documentation.split(Regex("(|^)#\\s*(?=(Module|Package))")) - return fragmentStrings - .filter(String::isNotBlank) - .map { fragmentString -> parseModuleAndPackageDocFragment(source, fragmentString) } -} - -private fun parseModuleAndPackageDocFragment( - source: ModuleAndPackageDocumentationSource, - fragment: String -): ModuleAndPackageDocFragment { - val firstLineAndDocumentation = fragment.split("\r\n", "\n", "\r", limit = 2) - val firstLine = firstLineAndDocumentation[0] - - val classifierAndName = firstLine.split(Regex("\\s+"), limit = 2) - if (classifierAndName.size != 2) { - throw IllegalModuleAndPackageDocumentation(source, "Missing ${classifierAndName.first()} name") - } - - val classifier = when (classifierAndName[0].trim()) { - "Module" -> ModuleAndPackageDocFragment.Classifier.Module - "Package" -> ModuleAndPackageDocFragment.Classifier.Package - else -> throw IllegalStateException("Unexpected classifier ${classifierAndName[0]}") - } - - val name = classifierAndName[1].trim() - if (name.contains(Regex("\\s"))) { - throw IllegalModuleAndPackageDocumentation( - source, "Module/Package name cannot contain whitespace in '$firstLine'" - ) - } - - return ModuleAndPackageDocFragment( - classifier = classifier, - name = name, - documentation = firstLineAndDocumentation.getOrNull(1)?.trim().orEmpty() - ) -} - - - diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt new file mode 100644 index 0000000000..f642c3745b --- /dev/null +++ b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt @@ -0,0 +1,7 @@ +package org.jetbrains.dokka.base.parsers.moduleAndPackage + +import org.jetbrains.dokka.DokkaException + +internal class IllegalModuleAndPackageDocumentation( + source: ModuleAndPackageDocumentationSource, message: String +) : DokkaException("[$source] $message") diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentation.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentation.kt new file mode 100644 index 0000000000..5139c87273 --- /dev/null +++ b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentation.kt @@ -0,0 +1,11 @@ +package org.jetbrains.dokka.base.parsers.moduleAndPackage + +import org.jetbrains.dokka.model.doc.DocumentationNode + +internal data class ModuleAndPackageDocumentation( + val name: String, + val classifier: Classifier, + val documentation: DocumentationNode +) { + enum class Classifier { Module, Package } +} diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment.kt new file mode 100644 index 0000000000..fa99a8e220 --- /dev/null +++ b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment.kt @@ -0,0 +1,10 @@ +package org.jetbrains.dokka.base.parsers.moduleAndPackage + +import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.* + +internal data class ModuleAndPackageDocumentationFragment( + val name: String, + val classifier: Classifier, + val documentation: String, + val source: ModuleAndPackageDocumentationSource +) diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext.kt new file mode 100644 index 0000000000..f11a5d130d --- /dev/null +++ b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext.kt @@ -0,0 +1,36 @@ +@file:Suppress("FunctionName") + +package org.jetbrains.dokka.base.parsers.moduleAndPackage + +import org.jetbrains.dokka.analysis.DokkaResolutionFacade +import org.jetbrains.dokka.base.parsers.MarkdownParser +import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.* +import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.utilities.DokkaLogger +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.name.Name + +internal fun interface ModuleAndPackageDocumentationParsingContext { + fun markdownParserFor(fragment: ModuleAndPackageDocumentationFragment): MarkdownParser +} + +internal fun ModuleAndPackageDocumentationParsingContext.parse( + fragment: ModuleAndPackageDocumentationFragment +): DocumentationNode { + return markdownParserFor(fragment).parse(fragment.documentation) +} + +internal fun ModuleAndPackageDocumentationParsingContext( + logger: DokkaLogger, + facade: DokkaResolutionFacade? = null, +) = ModuleAndPackageDocumentationParsingContext { fragment -> + val descriptor = when (fragment.classifier) { + Module -> facade?.moduleDescriptor?.getPackage(FqName.topLevel(Name.identifier(""))) + Package -> facade?.moduleDescriptor?.getPackage(FqName(fragment.name)) + } + MarkdownParser( + resolutionFacade = facade, + declarationDescriptor = descriptor, + logger = logger + ) +} diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt new file mode 100644 index 0000000000..7c3f6d9795 --- /dev/null +++ b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt @@ -0,0 +1,17 @@ +package org.jetbrains.dokka.base.parsers.moduleAndPackage + +import java.io.File + +internal abstract class ModuleAndPackageDocumentationSource { + abstract val sourceDescription: String + abstract val documentation: String + + override fun toString(): String { + return sourceDescription + } +} + +internal data class ModuleAndPackageDocumentationFile(private val file: File) : ModuleAndPackageDocumentationSource() { + override val sourceDescription: String = file.path + override val documentation: String by lazy(LazyThreadSafetyMode.PUBLICATION) { file.readText() } +} diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentation.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentation.kt new file mode 100644 index 0000000000..a287630892 --- /dev/null +++ b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentation.kt @@ -0,0 +1,15 @@ +@file:Suppress("FunctionName") + +package org.jetbrains.dokka.base.parsers.moduleAndPackage + +internal fun parseModuleAndPackageDocumentation( + context: ModuleAndPackageDocumentationParsingContext, + fragment: ModuleAndPackageDocumentationFragment +): ModuleAndPackageDocumentation { + return ModuleAndPackageDocumentation( + name = fragment.name, + classifier = fragment.classifier, + documentation = context.parse(fragment) + ) +} + diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt new file mode 100644 index 0000000000..2667681cc0 --- /dev/null +++ b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt @@ -0,0 +1,53 @@ +package org.jetbrains.dokka.base.parsers.moduleAndPackage + +import java.io.File + + +internal fun parseModuleAndPackageDocumentationFragments(source: File): List { + return parseModuleAndPackageDocumentationFragments(ModuleAndPackageDocumentationFile(source)) +} + +internal fun parseModuleAndPackageDocumentationFragments( + source: ModuleAndPackageDocumentationSource +): List { + val fragmentStrings = source.documentation.split(Regex("(|^)#\\s*(?=(Module|Package))")) + return fragmentStrings + .filter(String::isNotBlank) + .map { fragmentString -> parseModuleAndPackageDocFragment(source, fragmentString) } +} + +private fun parseModuleAndPackageDocFragment( + source: ModuleAndPackageDocumentationSource, + fragment: String +): ModuleAndPackageDocumentationFragment { + val firstLineAndDocumentation = fragment.split("\r\n", "\n", "\r", limit = 2) + val firstLine = firstLineAndDocumentation[0] + + val classifierAndName = firstLine.split(Regex("\\s+"), limit = 2) + if (classifierAndName.size != 2) { + throw IllegalModuleAndPackageDocumentation(source, "Missing ${classifierAndName.first()} name") + } + + val classifier = when (classifierAndName[0].trim()) { + "Module" -> ModuleAndPackageDocumentation.Classifier.Module + "Package" -> ModuleAndPackageDocumentation.Classifier.Package + else -> throw IllegalStateException("Unexpected classifier ${classifierAndName[0]}") + } + + val name = classifierAndName[1].trim() + if (name.contains(Regex("\\s"))) { + throw IllegalModuleAndPackageDocumentation( + source, "Module/Package name cannot contain whitespace in '$firstLine'" + ) + } + + return ModuleAndPackageDocumentationFragment( + name = name, + classifier = classifier, + documentation = firstLineAndDocumentation.getOrNull(1)?.trim().orEmpty(), + source = source + ) +} + + + diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt new file mode 100644 index 0000000000..e8297f3fbd --- /dev/null +++ b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt @@ -0,0 +1,72 @@ +@file:Suppress("FunctionName") + +package org.jetbrains.dokka.base.transformers.documentables + +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.analysis.KotlinAnalysis +import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier +import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentationFragment +import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentationParsingContext +import org.jetbrains.dokka.base.parsers.moduleAndPackage.parseModuleAndPackageDocumentation +import org.jetbrains.dokka.base.parsers.moduleAndPackage.parseModuleAndPackageDocumentationFragments +import org.jetbrains.dokka.model.DModule +import org.jetbrains.dokka.model.DPackage +import org.jetbrains.dokka.model.SourceSetDependent +import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.utilities.associateWithNotNull + +internal interface ModuleAndPackageDocumentationReader { + operator fun get(module: DModule): SourceSetDependent + operator fun get(pkg: DPackage): SourceSetDependent +} + +// TODO NOW: Test +internal fun ModuleAndPackageDocumentationReader( + context: DokkaContext, kotlinAnalysis: KotlinAnalysis? = null +): ModuleAndPackageDocumentationReader = ContextModuleAndPackageDocumentationReader(context, kotlinAnalysis) + +private class ContextModuleAndPackageDocumentationReader( + private val context: DokkaContext, + private val kotlinAnalysis: KotlinAnalysis? +) : ModuleAndPackageDocumentationReader { + + private val documentationFragments: SourceSetDependent> = + context.configuration.sourceSets.associateWith { sourceSet -> + sourceSet.includes.flatMap { include -> parseModuleAndPackageDocumentationFragments(include) } + } + + private fun findDocumentationNodes( + sourceSets: Set, + predicate: (ModuleAndPackageDocumentationFragment) -> Boolean + ): SourceSetDependent { + return sourceSets.associateWithNotNull { sourceSet -> + val fragments = documentationFragments[sourceSet].orEmpty().filter(predicate) + val resolutionFacade = kotlinAnalysis?.get(sourceSet)?.facade + val documentations = fragments.map { fragment -> + parseModuleAndPackageDocumentation( + context = ModuleAndPackageDocumentationParsingContext(context.logger, resolutionFacade), + fragment = fragment + ) + } + when (documentations.size) { + 0 -> null + 1 -> documentations.single().documentation + else -> DocumentationNode(documentations.flatMap { it.documentation.children }) + } + } + } + + override fun get(module: DModule): SourceSetDependent { + return findDocumentationNodes(module.sourceSets) { fragment -> + fragment.classifier == Classifier.Module && fragment.name == module.name + } + } + + override fun get(pkg: DPackage): SourceSetDependent { + return findDocumentationNodes(pkg.sourceSets) { fragment -> + // TODO NOW: handle JS Root thing + fragment.classifier == Classifier.Package && fragment.name == pkg.dri.packageName + } + } +} diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt index 5f1a540d03..9bdec75ad8 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt @@ -1,101 +1,32 @@ package org.jetbrains.dokka.base.transformers.documentables -import org.jetbrains.dokka.analysis.KotlinAnalysis +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.model.doc.DocumentationNode -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.base.parsers.MarkdownParser -import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name -import java.nio.file.Files -import java.nio.file.Paths - +// TODO NOW: Test internal class ModuleAndPackageDocumentationTransformer( - private val context: DokkaContext, - private val kotlinAnalysis: KotlinAnalysis + private val moduleAndPackageDocumentationReader: ModuleAndPackageDocumentationReader ) : PreMergeDocumentableTransformer { override fun invoke(modules: List): List { - - val modulesAndPackagesDocumentation = - context.configuration.sourceSets - .map { sourceSet -> - Pair(sourceSet.moduleDisplayName, sourceSet) to - sourceSet.includes.map { it.toPath() } - .also { - it.forEach { - if (Files.notExists(it)) - context.logger.warn("Not found file under this path ${it.toAbsolutePath()}") - } - } - .filter { Files.exists(it) } - .flatMap { - it.toFile() - .readText() - .split(Regex("(\n|^)# (?=(Module|Package))")) // Matches heading with Module/Package to split by - .filter { it.isNotEmpty() } - .map { it.split(Regex(" "), 2) } // Matches space between Module/Package and fully qualified name - }.groupBy({ it[0] }, { - it[1].split(Regex("\n"), 2) // Matches new line after fully qualified name - .let { it[0].trim() to it[1].trim() } - }).mapValues { - it.value.toMap() - } - }.toMap() - return modules.map { module -> - - val moduleDocumentation = - module.sourceSets.mapNotNull { pd -> - val doc = modulesAndPackagesDocumentation[Pair(module.name, pd)] - val facade = kotlinAnalysis[pd].facade - try { - doc?.get("Module")?.get(module.name)?.run { - pd to MarkdownParser( - facade, - facade.moduleDescriptor.getPackage(FqName.topLevel(Name.identifier(""))), - context.logger - ).parse(this) - } - } catch (e: IllegalArgumentException) { - context.logger.error(e.message.orEmpty()) - null - } - }.toMap() - - val packagesDocumentation = module.packages.map { - it.name to it.sourceSets.mapNotNull { pd -> - val doc = modulesAndPackagesDocumentation[Pair(module.name, pd)] - val facade = kotlinAnalysis[pd].facade - val descriptor = facade.moduleDescriptor.getPackage(FqName(it.name.let { if(it == "[JS root]") "" else it })) - doc?.get("Package")?.get(it.name)?.run { - pd to MarkdownParser( - facade, - descriptor, - context.logger - ).parse(this) - } - }.toMap() - }.toMap() - module.copy( - documentation = mergeDocumentation(module.documentation, moduleDocumentation), - packages = module.packages.map { - val packageDocumentation = packagesDocumentation[it.name] - if (packageDocumentation != null && packageDocumentation.isNotEmpty()) - it.copy(documentation = mergeDocumentation(it.documentation, packageDocumentation)) - else - it + documentation = module.documentation + moduleAndPackageDocumentationReader[module], + packages = module.packages.map { pkg -> + pkg.copy( + documentation = pkg.documentation + moduleAndPackageDocumentationReader[pkg] + ) } ) } } - private fun mergeDocumentation(origin: Map, new: Map): Map = - (origin.asSequence() + new.asSequence()) + private operator fun Map.plus( + other: Map + ): Map = + (asSequence() + other.asSequence()) .distinct() .groupBy({ it.key }, { it.value }) .mapValues { (_, values) -> DocumentationNode(values.flatMap { it.children }) } diff --git a/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocFragmentsTest.kt b/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt similarity index 68% rename from plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocFragmentsTest.kt rename to plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt index 49eddaeabf..5c0a064621 100644 --- a/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocFragmentsTest.kt +++ b/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt @@ -1,11 +1,8 @@ package parsers -import org.jetbrains.dokka.base.parsers.IllegalModuleAndPackageDocumentation -import org.jetbrains.dokka.base.parsers.ModuleAndPackageDocFragment -import org.jetbrains.dokka.base.parsers.ModuleAndPackageDocFragment.Classifier.Module -import org.jetbrains.dokka.base.parsers.ModuleAndPackageDocFragment.Classifier.Package -import org.jetbrains.dokka.base.parsers.ModuleAndPackageDocumentationSource -import org.jetbrains.dokka.base.parsers.parseModuleAndPackageDocFragments +import org.jetbrains.dokka.base.parsers.moduleAndPackage.* +import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Module +import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Package import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test @@ -13,14 +10,13 @@ import org.junit.jupiter.api.assertThrows import org.junit.jupiter.api.io.TempDir import java.nio.file.Path -class ParseModuleAndPackageDocFragmentsTest { +class ParseModuleAndPackageDocumentationFragmentsTest { @Test fun `basic example`() { - val fragments = parseModuleAndPackageDocFragments( - source( - """ + val source = source( + """ # Module kotlin-demo Module description @@ -32,25 +28,28 @@ class ParseModuleAndPackageDocFragmentsTest { # Package org.jetbrains.kotlin.demo2 Package demo2 description """.trimIndent() - ) ) + val fragments = parseModuleAndPackageDocumentationFragments(source) assertEquals( listOf( - ModuleAndPackageDocFragment( + ModuleAndPackageDocumentationFragment( classifier = Module, name = "kotlin-demo", - documentation = "Module description" + documentation = "Module description", + source = source ), - ModuleAndPackageDocFragment( + ModuleAndPackageDocumentationFragment( classifier = Package, name = "org.jetbrains.kotlin.demo", - documentation = "Package demo description\n## Level 2 heading\nHeading 2" + documentation = "Package demo description\n## Level 2 heading\nHeading 2", + source = source ), - ModuleAndPackageDocFragment( + ModuleAndPackageDocumentationFragment( classifier = Package, name = "org.jetbrains.kotlin.demo2", - documentation = "Package demo2 description" + documentation = "Package demo2 description", + source = source ) ), fragments @@ -60,7 +59,7 @@ class ParseModuleAndPackageDocFragmentsTest { @Test fun `no module name specified fails`() { val exception = assertThrows { - parseModuleAndPackageDocFragments( + parseModuleAndPackageDocumentationFragments( source( """ # Module @@ -79,7 +78,7 @@ class ParseModuleAndPackageDocFragmentsTest { @Test fun `no package name specified fails`() { val exception = assertThrows { - parseModuleAndPackageDocFragments( + parseModuleAndPackageDocumentationFragments( source( """ # Package @@ -98,7 +97,7 @@ class ParseModuleAndPackageDocFragmentsTest { @Test fun `white space in module name fails`() { val exception = assertThrows { - parseModuleAndPackageDocFragments( + parseModuleAndPackageDocumentationFragments( source( """ # Module My Module @@ -116,7 +115,7 @@ class ParseModuleAndPackageDocFragmentsTest { @Test fun `white space in package name fails`() { val exception = assertThrows { - parseModuleAndPackageDocFragments( + parseModuleAndPackageDocumentationFragments( source( """ # Package my package @@ -133,28 +132,29 @@ class ParseModuleAndPackageDocFragmentsTest { @Test fun `multiple whitespaces are supported in first line`() { - val fragments = parseModuleAndPackageDocFragments( - source( - """ - # Module my-module - My Module - # Package com.my.package - My Package + val source = source( + """ + # Module my-module + My Module + # Package com.my.package + My Package """.trimIndent() - ) ) + val fragments = parseModuleAndPackageDocumentationFragments(source) assertEquals( listOf( - ModuleAndPackageDocFragment( + ModuleAndPackageDocumentationFragment( classifier = Module, name = "my-module", - documentation = "My Module" + documentation = "My Module", + source = source ), - ModuleAndPackageDocFragment( + ModuleAndPackageDocumentationFragment( classifier = Package, name = "com.my.package", - documentation = "My Package" + documentation = "My Package", + source = source ) ), fragments @@ -175,18 +175,20 @@ class ParseModuleAndPackageDocFragmentsTest { assertEquals( listOf( - ModuleAndPackageDocFragment( + ModuleAndPackageDocumentationFragment( classifier = Module, name = "MyModule", - documentation = "D1" + documentation = "D1", + source = ModuleAndPackageDocumentationFile(file) ), - ModuleAndPackageDocFragment( + ModuleAndPackageDocumentationFragment( classifier = Package, name = "com.sample", - documentation = "D2" + documentation = "D2", + source = ModuleAndPackageDocumentationFile(file) ) ), - parseModuleAndPackageDocFragments(file) + parseModuleAndPackageDocumentationFragments(file) ) } From afecd4784c888988cc833b736c8c2386578e6139 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Wed, 26 Aug 2020 08:29:23 +0200 Subject: [PATCH 03/19] Implement ModuleAndPackageDocumentationTransformerTest.kt --- .../model/properties/PropertyContainer.kt | 2 +- ...oduleAndPackageDocumentationTransformer.kt | 1 - ...eAndPackageDocumentationTransformerTest.kt | 270 ++++++++++++++++++ 3 files changed, 271 insertions(+), 2 deletions(-) create mode 100644 plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerTest.kt diff --git a/core/src/main/kotlin/model/properties/PropertyContainer.kt b/core/src/main/kotlin/model/properties/PropertyContainer.kt index b14a30f546..19189b3958 100644 --- a/core/src/main/kotlin/model/properties/PropertyContainer.kt +++ b/core/src/main/kotlin/model/properties/PropertyContainer.kt @@ -1,6 +1,6 @@ package org.jetbrains.dokka.model.properties -class PropertyContainer internal constructor( +data class PropertyContainer internal constructor( @PublishedApi internal val map: Map, ExtraProperty> ) { operator fun plus(prop: ExtraProperty): PropertyContainer = diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt index 9bdec75ad8..bf6579af74 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt @@ -5,7 +5,6 @@ import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer -// TODO NOW: Test internal class ModuleAndPackageDocumentationTransformer( private val moduleAndPackageDocumentationReader: ModuleAndPackageDocumentationReader ) : PreMergeDocumentableTransformer { diff --git a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerTest.kt b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerTest.kt new file mode 100644 index 0000000000..a947633d1f --- /dev/null +++ b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerTest.kt @@ -0,0 +1,270 @@ +package transformers + +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet +import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationReader +import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationTransformer +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.DModule +import org.jetbrains.dokka.model.DPackage +import org.jetbrains.dokka.model.SourceSetDependent +import org.jetbrains.dokka.model.doc.Description +import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.model.doc.Text +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import renderers.defaultSourceSet + + +class ModuleAndPackageDocumentationTransformerTest { + + @Test + fun `empty list of modules`() { + val transformer = ModuleAndPackageDocumentationTransformer( + object : ModuleAndPackageDocumentationReader { + override fun get(module: DModule): SourceSetDependent = throw NotImplementedError() + override fun get(pkg: DPackage): SourceSetDependent = throw NotImplementedError() + } + ) + + assertEquals( + emptyList(), transformer(emptyList()), + ) + } + + @Test + fun `single module documentation`() { + val transformer = ModuleAndPackageDocumentationTransformer( + object : ModuleAndPackageDocumentationReader { + override fun get(pkg: DPackage): SourceSetDependent = throw NotImplementedError() + override fun get(module: DModule): SourceSetDependent { + return module.sourceSets.associateWith { sourceSet -> + documentationNode("doc" + sourceSet.displayName) + } + } + + } + ) + + val result = transformer( + listOf( + DModule( + "ModuleName", + documentation = emptyMap(), + packages = emptyList(), + sourceSets = setOf( + sourceSet("A"), + sourceSet("B") + ) + ) + ) + ) + + assertEquals( + DModule( + "ModuleName", + documentation = mapOf( + sourceSet("A") to documentationNode("docA"), + sourceSet("B") to documentationNode("docB") + ), + sourceSets = setOf(sourceSet("A"), sourceSet("B")), + packages = emptyList() + ), + result.single() + ) + + } + + @Test + fun `merges with already existing module documentation`() { + val transformer = ModuleAndPackageDocumentationTransformer( + object : ModuleAndPackageDocumentationReader { + override fun get(pkg: DPackage): SourceSetDependent = throw NotImplementedError() + override fun get(module: DModule): SourceSetDependent { + /* Only add documentation for first source set */ + return module.sourceSets.take(1).associateWith { sourceSet -> + documentationNode("doc" + sourceSet.displayName) + } + } + } + ) + + val result = transformer( + listOf( + DModule( + "MyModule", + documentation = mapOf( + sourceSet("A") to documentationNode("pre-existing:A"), + sourceSet("B") to documentationNode("pre-existing:B") + ), + sourceSets = setOf(sourceSet("A"), sourceSet("B")), + packages = emptyList() + ) + ) + ) + + assertEquals( + DModule( + "MyModule", + documentation = mapOf( + /* Expect previous documentation and newly attached one */ + sourceSet("A") to documentationNode("pre-existing:A", "docA"), + /* Only first source set will get documentation attached */ + sourceSet("B") to documentationNode("pre-existing:B") + ), + sourceSets = setOf(sourceSet("A"), sourceSet("B")), + packages = emptyList() + ), + result.single() + ) + } + + @Test + fun `package documentation`() { + val transformer = ModuleAndPackageDocumentationTransformer( + object : ModuleAndPackageDocumentationReader { + override fun get(module: DModule): SourceSetDependent = emptyMap() + override fun get(pkg: DPackage): SourceSetDependent { + /* Only attach documentation to packages with 'attach' */ + if ("attach" !in pkg.dri.packageName.orEmpty()) return emptyMap() + /* Only attach documentation to two source sets */ + return pkg.sourceSets.take(2).associateWith { sourceSet -> + documentationNode("doc:${sourceSet.displayName}:${pkg.dri.packageName}") + } + } + } + ) + + val result = transformer( + listOf( + DModule( + "MyModule", + documentation = emptyMap(), + sourceSets = emptySet(), + packages = listOf( + dPackage( + name = "com.sample", + documentation = mapOf( + sourceSet("A") to documentationNode("pre-existing:A:com.sample") + ), + sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")), + ), + dPackage( + name = "com.attach", + documentation = mapOf( + sourceSet("A") to documentationNode("pre-existing:A:com.attach") + ), + sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")) + ), + dPackage( + name = "com.attach.sub", + documentation = mapOf( + sourceSet("A") to documentationNode("pre-existing:A:com.attach.sub"), + sourceSet("B") to documentationNode("pre-existing:B:com.attach.sub"), + sourceSet("C") to documentationNode("pre-existing:C:com.attach.sub") + ), + sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")), + ) + ) + ) + ) + ) + + result.single().packages.forEach { pkg -> + assertEquals( + setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")), pkg.sourceSets, + "Expected source sets A, B, C for package ${pkg.dri.packageName}" + ) + } + + val comSample = result.single().packages.single { it.dri.packageName == "com.sample" } + assertEquals( + mapOf(sourceSet("A") to documentationNode("pre-existing:A:com.sample")), + comSample.documentation, + "Expected no documentation added to package 'com.sample' because of wrong package" + ) + + val comAttach = result.single().packages.single { it.dri.packageName == "com.attach" } + assertEquals( + mapOf( + sourceSet("A") to documentationNode("pre-existing:A:com.attach", "doc:A:com.attach"), + sourceSet("B") to documentationNode("doc:B:com.attach") + ), + comAttach.documentation, + "Expected documentation added to source sets A and B" + ) + + assertEquals( + DModule( + "MyModule", + documentation = emptyMap(), + sourceSets = emptySet(), + packages = listOf( + dPackage( + name = "com.sample", + documentation = mapOf( + /* No documentation added, since in wrong package */ + sourceSet("A") to documentationNode("pre-existing:A:com.sample") + ), + sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")), + + ), + dPackage( + name = "com.attach", + documentation = mapOf( + /* Documentation added */ + sourceSet("A") to documentationNode("pre-existing:A:com.attach", "doc:A:com.attach"), + sourceSet("B") to documentationNode("doc:B:com.attach") + ), + sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")), + ), + dPackage( + name = "com.attach.sub", + documentation = mapOf( + /* Documentation added */ + sourceSet("A") to documentationNode( + "pre-existing:A:com.attach.sub", + "doc:A:com.attach.sub" + ), + /* Documentation added */ + sourceSet("B") to documentationNode( + "pre-existing:B:com.attach.sub", + "doc:B:com.attach.sub" + ), + /* No documentation added, since in wrong source set */ + sourceSet("C") to documentationNode("pre-existing:C:com.attach.sub") + ), + sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")), + ) + ) + ), result.single() + ) + } + +} + + +private fun sourceSet(name: String): DokkaSourceSet { + return defaultSourceSet.copy( + displayName = name, + sourceSetID = defaultSourceSet.sourceSetID.copy(sourceSetName = name) + ) +} + +private fun documentationNode(vararg texts: String): DocumentationNode { + return DocumentationNode(texts.toList().map { Description(Text(it)) }) +} + +private fun dPackage( + name: String, + documentation: SourceSetDependent, + sourceSets: Set +): DPackage = DPackage( + dri = DRI(name), + documentation = documentation, + sourceSets = sourceSets, + classlikes = emptyList(), + functions = emptyList(), + properties = emptyList(), + typealiases = emptyList() + +) From a3f398c3268fc089f48daae4dc7b50a6ad0686a7 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Wed, 26 Aug 2020 10:23:50 +0200 Subject: [PATCH 04/19] Make testApi dokkaConfiguration available outside of AbstractCoreTest Fix rebasing issue --- .../TestDokkaConfigurationBuilder.kt | 97 +++++++++++++++++++ .../kotlin/testApi/testRunner/TestRunner.kt | 92 +----------------- 2 files changed, 100 insertions(+), 89 deletions(-) create mode 100644 core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt diff --git a/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt new file mode 100644 index 0000000000..e2720ff09a --- /dev/null +++ b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt @@ -0,0 +1,97 @@ +package testApi.testRunner + +import com.intellij.openapi.application.PathManager +import org.jetbrains.dokka.* +import java.io.File +import java.net.URL + +fun dokkaConfiguration(block: TestDokkaConfigurationBuilder.() -> Unit): DokkaConfigurationImpl = + TestDokkaConfigurationBuilder().apply(block).build() + +@DslMarker +annotation class DokkaConfigurationDsl + +@DokkaConfigurationDsl +class TestDokkaConfigurationBuilder { + var outputDir: String = "out" + var format: String = "html" + var offlineMode: Boolean = false + var cacheRoot: String? = null + var pluginsClasspath: List = emptyList() + var pluginsConfigurations: Map = emptyMap() + var failOnWarning: Boolean = false + private val sourceSets = mutableListOf() + fun build() = DokkaConfigurationImpl( + outputDir = File(outputDir), + cacheRoot = cacheRoot?.let(::File), + offlineMode = offlineMode, + sourceSets = sourceSets.toList(), + pluginsClasspath = pluginsClasspath, + pluginsConfiguration = pluginsConfigurations, + modules = emptyList(), + failOnWarning = failOnWarning + ) + + fun sourceSets(block: SourceSetsBuilder.() -> Unit) { + sourceSets.addAll(SourceSetsBuilder().apply(block)) + } +} + +@DokkaConfigurationDsl +class SourceSetsBuilder : ArrayList() { + fun sourceSet(block: DokkaSourceSetBuilder.() -> Unit): DokkaConfiguration.DokkaSourceSet = + DokkaSourceSetBuilder().apply(block).build().apply(::add) +} + +@DokkaConfigurationDsl +class DokkaSourceSetBuilder( + var moduleName: String = "root", + var moduleDisplayName: String? = null, + var name: String = "main", + var displayName: String = "JVM", + var classpath: List = emptyList(), + var sourceRoots: List = emptyList(), + var dependentSourceSets: Set = emptySet(), + var samples: List = emptyList(), + var includes: List = emptyList(), + var includeNonPublic: Boolean = false, + var includeRootPackage: Boolean = true, + var reportUndocumented: Boolean = false, + var skipEmptyPackages: Boolean = false, + var skipDeprecated: Boolean = false, + var jdkVersion: Int = 8, + var languageVersion: String? = null, + var apiVersion: String? = null, + var noStdlibLink: Boolean = false, + var noJdkLink: Boolean = false, + var suppressedFiles: List = emptyList(), + var analysisPlatform: String = "jvm", + var perPackageOptions: List = emptyList(), + var externalDocumentationLinks: List = emptyList(), + var sourceLinks: List = emptyList() +) { + fun build() = DokkaSourceSetImpl( + moduleDisplayName = moduleDisplayName ?: moduleName, + displayName = displayName, + sourceSetID = DokkaSourceSetID(moduleName, name), + classpath = classpath.map(::File), + sourceRoots = sourceRoots.map(::File).toSet(), + dependentSourceSets = dependentSourceSets, + samples = samples.map(::File).toSet(), + includes = includes.map(::File).toSet(), + includeNonPublic = includeNonPublic, + reportUndocumented = reportUndocumented, + skipEmptyPackages = skipEmptyPackages, + skipDeprecated = skipDeprecated, + jdkVersion = jdkVersion, + sourceLinks = sourceLinks.toSet(), + perPackageOptions = perPackageOptions.toList(), + externalDocumentationLinks = externalDocumentationLinks.toSet(), + languageVersion = languageVersion, + apiVersion = apiVersion, + noStdlibLink = noStdlibLink, + noJdkLink = noJdkLink, + suppressedFiles = suppressedFiles.map(::File).toSet(), + analysisPlatform = Platform.fromString(analysisPlatform) + ) +} diff --git a/core/test-api/src/main/kotlin/testApi/testRunner/TestRunner.kt b/core/test-api/src/main/kotlin/testApi/testRunner/TestRunner.kt index a23c27137e..27fc70243a 100644 --- a/core/test-api/src/main/kotlin/testApi/testRunner/TestRunner.kt +++ b/core/test-api/src/main/kotlin/testApi/testRunner/TestRunner.kt @@ -11,6 +11,7 @@ import org.jetbrains.dokka.testApi.logger.TestLogger import org.jetbrains.dokka.utilities.DokkaConsoleLogger import org.jetbrains.dokka.utilities.DokkaLogger import org.junit.rules.TemporaryFolder +import testApi.testRunner.TestDokkaConfigurationBuilder import java.io.File import java.net.URL import java.nio.charset.Charset @@ -160,96 +161,9 @@ abstract class AbstractCoreTest( ) } - protected fun dokkaConfiguration(block: DokkaConfigurationBuilder.() -> Unit): DokkaConfigurationImpl = - DokkaConfigurationBuilder().apply(block).build() + protected fun dokkaConfiguration(block: TestDokkaConfigurationBuilder.() -> Unit): DokkaConfigurationImpl = + testApi.testRunner.dokkaConfiguration(block) - @DslMarker - protected annotation class DokkaConfigurationDsl - - @DokkaConfigurationDsl - protected class DokkaConfigurationBuilder { - var outputDir: String = "out" - var format: String = "html" - var offlineMode: Boolean = false - var cacheRoot: String? = null - var pluginsClasspath: List = emptyList() - var pluginsConfigurations: Map = emptyMap() - var failOnWarning: Boolean = false - private val sourceSets = mutableListOf() - fun build() = DokkaConfigurationImpl( - outputDir = File(outputDir), - cacheRoot = cacheRoot?.let(::File), - offlineMode = offlineMode, - sourceSets = sourceSets.toList(), - pluginsClasspath = pluginsClasspath, - pluginsConfiguration = pluginsConfigurations, - modules = emptyList(), - failOnWarning = failOnWarning - ) - - fun sourceSets(block: SourceSetsBuilder.() -> Unit) { - sourceSets.addAll(SourceSetsBuilder().apply(block)) - } - } - - @DokkaConfigurationDsl - protected class SourceSetsBuilder : ArrayList() { - fun sourceSet(block: DokkaSourceSetBuilder.() -> Unit): DokkaSourceSet = - DokkaSourceSetBuilder().apply(block).build().apply(::add) - } - - @DokkaConfigurationDsl - protected class DokkaSourceSetBuilder( - var moduleName: String = "root", - var moduleDisplayName: String? = null, - var name: String = "main", - var displayName: String = "JVM", - var classpath: List = emptyList(), - var sourceRoots: List = emptyList(), - var dependentSourceSets: Set = emptySet(), - var samples: List = emptyList(), - var includes: List = emptyList(), - var includeNonPublic: Boolean = false, - var includeRootPackage: Boolean = true, - var reportUndocumented: Boolean = false, - var skipEmptyPackages: Boolean = false, - var skipDeprecated: Boolean = false, - var jdkVersion: Int = 8, - var languageVersion: String? = null, - var apiVersion: String? = null, - var noStdlibLink: Boolean = false, - var noJdkLink: Boolean = false, - var suppressedFiles: List = emptyList(), - var analysisPlatform: String = "jvm", - var perPackageOptions: List = emptyList(), - var externalDocumentationLinks: List = emptyList(), - var sourceLinks: List = emptyList() - ) { - fun build() = DokkaSourceSetImpl( - moduleDisplayName = moduleDisplayName ?: moduleName, - displayName = displayName, - sourceSetID = DokkaSourceSetID(moduleName, name), - classpath = classpath.map(::File), - sourceRoots = sourceRoots.map(::File).toSet(), - dependentSourceSets = dependentSourceSets, - samples = samples.map(::File).toSet(), - includes = includes.map(::File).toSet(), - includeNonPublic = includeNonPublic, - reportUndocumented = reportUndocumented, - skipEmptyPackages = skipEmptyPackages, - skipDeprecated = skipDeprecated, - jdkVersion = jdkVersion, - sourceLinks = sourceLinks.toSet(), - perPackageOptions = perPackageOptions.toList(), - externalDocumentationLinks = externalDocumentationLinks.toSet(), - languageVersion = languageVersion, - apiVersion = apiVersion, - noStdlibLink = noStdlibLink, - noJdkLink = noJdkLink, - suppressedFiles = suppressedFiles.map(::File).toSet(), - analysisPlatform = Platform.fromString(analysisPlatform) - ) - } protected val jvmStdlibPath: String? by lazy { PathManager.getResourceRoot(Strictfp::class.java, "/kotlin/jvm/Strictfp.class") From 63147f3ff86e01baa16330040c6971e7d4f93b08 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Wed, 26 Aug 2020 11:47:49 +0200 Subject: [PATCH 05/19] Implement tests for ModuleAndPackageDocumentationReader --- core/src/main/kotlin/model/Documentable.kt | 18 +- .../TestDokkaConfigurationBuilder.kt | 54 ++++- .../main/kotlin/renderers/defaultSourceSet.kt | 29 +-- .../ModuleAndPackageDocumentationReader.kt | 7 +- ...ModuleAndPackageDocumentationReaderTest.kt | 22 ++ ...oduleAndPackageDocumentationReaderTest1.kt | 188 ++++++++++++++++++ ...oduleAndPackageDocumentationReaderTest2.kt | 63 ++++++ ...eAndPackageDocumentationTransformerTest.kt | 59 ++---- 8 files changed, 354 insertions(+), 86 deletions(-) create mode 100644 plugins/base/src/test/kotlin/transformers/AbstractContextModuleAndPackageDocumentationReaderTest.kt create mode 100644 plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt create mode 100644 plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest2.kt diff --git a/core/src/main/kotlin/model/Documentable.kt b/core/src/main/kotlin/model/Documentable.kt index adc46d2a30..293b8a30ed 100644 --- a/core/src/main/kotlin/model/Documentable.kt +++ b/core/src/main/kotlin/model/Documentable.kt @@ -87,10 +87,10 @@ sealed class DClasslike : Documentable(), WithScope, WithVisibility, WithExpectA data class DModule( override val name: String, - val packages: List, - override val documentation: SourceSetDependent, + val packages: List = emptyList(), + override val documentation: SourceSetDependent = emptyMap(), override val expectPresentInSet: DokkaSourceSet? = null, - override val sourceSets: Set, + override val sourceSets: Set = emptySet(), override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithExtraProperties { override val dri: DRI = DRI.topLevel @@ -102,13 +102,13 @@ data class DModule( data class DPackage( override val dri: DRI, - override val functions: List, - override val properties: List, - override val classlikes: List, - val typealiases: List, - override val documentation: SourceSetDependent, + override val functions: List = emptyList(), + override val properties: List = emptyList(), + override val classlikes: List = emptyList(), + val typealiases: List = emptyList(), + override val documentation: SourceSetDependent = emptyMap(), override val expectPresentInSet: DokkaSourceSet? = null, - override val sourceSets: Set, + override val sourceSets: Set = emptySet(), override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithScope, WithExtraProperties { override val name = dri.packageName.orEmpty() diff --git a/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt index e2720ff09a..5bf7e52d03 100644 --- a/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt +++ b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt @@ -1,9 +1,12 @@ package testApi.testRunner -import com.intellij.openapi.application.PathManager import org.jetbrains.dokka.* +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.doc.Description +import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.model.doc.Text import java.io.File -import java.net.URL fun dokkaConfiguration(block: TestDokkaConfigurationBuilder.() -> Unit): DokkaConfigurationImpl = TestDokkaConfigurationBuilder().apply(block).build() @@ -35,6 +38,10 @@ class TestDokkaConfigurationBuilder { fun sourceSets(block: SourceSetsBuilder.() -> Unit) { sourceSets.addAll(SourceSetsBuilder().apply(block)) } + + fun add(sourceSet: DokkaSourceSetImpl) { + sourceSets.add(sourceSet) + } } @DokkaConfigurationDsl @@ -43,6 +50,10 @@ class SourceSetsBuilder : ArrayList() { DokkaSourceSetBuilder().apply(block).build().apply(::add) } +fun sourceSet(block: DokkaSourceSetBuilder.() -> Unit): DokkaSourceSetImpl { + return DokkaSourceSetBuilder().apply(block).build() +} + @DokkaConfigurationDsl class DokkaSourceSetBuilder( var moduleName: String = "root", @@ -55,7 +66,6 @@ class DokkaSourceSetBuilder( var samples: List = emptyList(), var includes: List = emptyList(), var includeNonPublic: Boolean = false, - var includeRootPackage: Boolean = true, var reportUndocumented: Boolean = false, var skipEmptyPackages: Boolean = false, var skipDeprecated: Boolean = false, @@ -95,3 +105,41 @@ class DokkaSourceSetBuilder( analysisPlatform = Platform.fromString(analysisPlatform) ) } + +val defaultSourceSet = DokkaSourceSetImpl( + moduleDisplayName = "DEFAULT", + displayName = "DEFAULT", + sourceSetID = DokkaSourceSetID("DEFAULT", "DEFAULT"), + classpath = emptyList(), + sourceRoots = emptySet(), + dependentSourceSets = emptySet(), + samples = emptySet(), + includes = emptySet(), + includeNonPublic = false, + reportUndocumented = false, + skipEmptyPackages = true, + skipDeprecated = false, + jdkVersion = 8, + sourceLinks = emptySet(), + perPackageOptions = emptyList(), + externalDocumentationLinks = emptySet(), + languageVersion = null, + apiVersion = null, + noStdlibLink = false, + noJdkLink = false, + suppressedFiles = emptySet(), + analysisPlatform = Platform.DEFAULT +) + +// TODO NOW: Clean up +fun sourceSet(name: String): DokkaConfiguration.DokkaSourceSet { + return defaultSourceSet.copy( + displayName = name, + sourceSetID = defaultSourceSet.sourceSetID.copy(sourceSetName = name) + ) +} + +fun documentationNode(vararg texts: String): DocumentationNode { + return DocumentationNode(texts.toList().map { Description(Text(it)) }) +} + diff --git a/plugins/base/base-test-utils/src/main/kotlin/renderers/defaultSourceSet.kt b/plugins/base/base-test-utils/src/main/kotlin/renderers/defaultSourceSet.kt index a7a20f88cb..41ca714695 100644 --- a/plugins/base/base-test-utils/src/main/kotlin/renderers/defaultSourceSet.kt +++ b/plugins/base/base-test-utils/src/main/kotlin/renderers/defaultSourceSet.kt @@ -1,30 +1,3 @@ package renderers -import org.jetbrains.dokka.DokkaSourceSetID -import org.jetbrains.dokka.DokkaSourceSetImpl -import org.jetbrains.dokka.Platform - -val defaultSourceSet = DokkaSourceSetImpl( - moduleDisplayName = "DEFAULT", - displayName = "DEFAULT", - sourceSetID = DokkaSourceSetID("DEFAULT", "DEFAULT"), - classpath = emptyList(), - sourceRoots = emptySet(), - dependentSourceSets = emptySet(), - samples = emptySet(), - includes = emptySet(), - includeNonPublic = false, - reportUndocumented = false, - skipEmptyPackages = true, - skipDeprecated = false, - jdkVersion = 8, - sourceLinks = emptySet(), - perPackageOptions = emptyList(), - externalDocumentationLinks = emptySet(), - languageVersion = null, - apiVersion = null, - noStdlibLink = false, - noJdkLink = false, - suppressedFiles = emptySet(), - analysisPlatform = Platform.DEFAULT -) +val defaultSourceSet = testApi.testRunner.defaultSourceSet diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt index e8297f3fbd..4900e9a8ef 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt @@ -21,7 +21,6 @@ internal interface ModuleAndPackageDocumentationReader { operator fun get(pkg: DPackage): SourceSetDependent } -// TODO NOW: Test internal fun ModuleAndPackageDocumentationReader( context: DokkaContext, kotlinAnalysis: KotlinAnalysis? = null ): ModuleAndPackageDocumentationReader = ContextModuleAndPackageDocumentationReader(context, kotlinAnalysis) @@ -59,7 +58,11 @@ private class ContextModuleAndPackageDocumentationReader( override fun get(module: DModule): SourceSetDependent { return findDocumentationNodes(module.sourceSets) { fragment -> - fragment.classifier == Classifier.Module && fragment.name == module.name + fragment.classifier == Classifier.Module && ( + /* Match fragment name against module name or distinct module displayName */ + fragment.name == module.name || + fragment.name == module.sourceSets.map { it.moduleDisplayName }.distinct().singleOrNull() + ) } } diff --git a/plugins/base/src/test/kotlin/transformers/AbstractContextModuleAndPackageDocumentationReaderTest.kt b/plugins/base/src/test/kotlin/transformers/AbstractContextModuleAndPackageDocumentationReaderTest.kt new file mode 100644 index 0000000000..7f4350130d --- /dev/null +++ b/plugins/base/src/test/kotlin/transformers/AbstractContextModuleAndPackageDocumentationReaderTest.kt @@ -0,0 +1,22 @@ +package transformers + +import org.jetbrains.dokka.model.SourceSetDependent +import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.model.doc.Text +import org.jetbrains.dokka.model.withDescendants +import org.junit.jupiter.api.io.TempDir +import java.nio.file.Path + +abstract class AbstractContextModuleAndPackageDocumentationReaderTest { + @TempDir + protected lateinit var temporaryDirectory: Path + + + protected val SourceSetDependent.texts: List + get() = values.flatMap { it.withDescendants() } + .flatMap { it.children } + .flatMap { it.children } + .mapNotNull { it as? Text } + .map { it.body } + +} diff --git a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt new file mode 100644 index 0000000000..e04e751cd5 --- /dev/null +++ b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt @@ -0,0 +1,188 @@ +package transformers + +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet +import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationReader +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.DModule +import org.jetbrains.dokka.model.DPackage +import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.testApi.logger.TestLogger +import org.jetbrains.dokka.utilities.DokkaConsoleLogger +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testApi.testRunner.dokkaConfiguration +import testApi.testRunner.sourceSet + +class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAndPackageDocumentationReaderTest() { + + + + private val includeSourceSetA by lazy { temporaryDirectory.resolve("includeA.md").toFile() } + private val includeSourceSetB by lazy { temporaryDirectory.resolve("includeB.md").toFile() } + + @BeforeEach + fun materializeIncludes() { + includeSourceSetA.writeText( + """ + # Module moduleA + This is moduleA + + # Package sample.a + This is package sample.a + + # Package noise.b + This will just add some noise + """.trimIndent() + ) + + includeSourceSetB.writeText( + """ + # Module moduleB + This is moduleB + + # Package sample.b + This is package sample.b + + # Package noise.b + This will just add some more noise + """.trimIndent() + ) + } + + private val sourceSetA by lazy { + sourceSet { + moduleName = "moduleA" + name = "sourceSetA" + includes = listOf(includeSourceSetA.canonicalPath) + } + } + + private val sourceSetB by lazy { + sourceSet { + moduleName = "moduleB" + name = "sourceSetB" + includes = listOf(includeSourceSetB.canonicalPath) + } + } + + private val sourceSetB2 by lazy { + sourceSet { + moduleName = "moduleB" + name = "sourceSetB2" + includes = emptyList() + } + } + + + private val context by lazy { + DokkaContext.create( + configuration = dokkaConfiguration { + sourceSets { + add(sourceSetA) + add(sourceSetB) + add(sourceSetB2) + } + }, + logger = TestLogger(DokkaConsoleLogger), + pluginOverrides = emptyList() + ) + } + + private val reader by lazy { ModuleAndPackageDocumentationReader(context) } + + @Test + fun `assert moduleA with sourceSetA`() { + val documentation = reader[DModule(name = "moduleA", sourceSets = setOf(sourceSetA))] + assertEquals( + 1, documentation.keys.size, + "Expected moduleA only containing documentation in a single source set" + ) + assertEquals( + "sourceSetA", documentation.keys.single().sourceSetID.sourceSetName, + "Expected moduleA documentation coming from sourceSetA" + ) + + assertEquals( + "This is moduleA", documentation.texts.single(), + "Expected moduleA documentation being present" + ) + } + + @Test + fun `assert moduleA with no source sets`() { + val documentation = reader[DModule("moduleA")] + assertEquals( + emptyMap(), documentation, + "Expected no documentation received for module not declaring a matching sourceSet" + ) + } + + @Test + fun `assert moduleA with unknown source set`() { + val documentation = reader[DModule("moduleA", sourceSets = setOf(sourceSet { name = "unknown" }))] + assertEquals( + emptyMap(), documentation, + "Expected no documentation received for module with unknown sourceSet" + ) + } + + @Test + fun `assert moduleA with all sourceSets`() { + val documentation = reader[DModule("moduleA", sourceSets = setOf(sourceSetA, sourceSetB, sourceSetB2))] + assertEquals(1, documentation.entries.size, "Expected only one entry from sourceSetA") + assertEquals(sourceSetA, documentation.keys.single(), "Expected only one entry from sourceSetA") + assertEquals("This is moduleA", documentation.texts.single()) + } + + @Test + fun `assert moduleB with sourceSetB and sourceSetB2`() { + val documentation = reader[DModule("moduleB", sourceSets = setOf(sourceSetB, sourceSetB2))] + assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSetB") + assertEquals(sourceSetB, documentation.keys.single(), "Expected only one entry from sourceSetB") + assertEquals("This is moduleB", documentation.texts.single()) + } + + @Test + fun `assert sample_A in sourceSetA`() { + val documentation = reader[DPackage(DRI("sample.a"), sourceSets = setOf(sourceSetA))] + assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSetA") + assertEquals(sourceSetA, documentation.keys.single(), "Expected only one entry from sourceSetA") + assertEquals("This is package sample.a", documentation.texts.single()) + } + + @Test + fun `assert sample_a_sub in sourceSetA`() { + val documentation = reader[DPackage(DRI("sample.a.sub"), sourceSets = setOf(sourceSetA))] + assertEquals( + emptyMap(), documentation, + "Expected no documentation found for different package" + ) + } + + @Test + fun `assert sample_a in sourceSetB`() { + val documentation = reader[DPackage(DRI("sample.a"), sourceSets = setOf(sourceSetB))] + assertEquals( + emptyMap(), documentation, + "Expected no documentation found for different sourceSet" + ) + } + + @Test + fun `assert sample_b in sourceSetB`() { + val documentation = reader[DPackage(DRI("sample.b"), sourceSets = setOf(sourceSetB))] + assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSetB") + assertEquals(sourceSetB, documentation.keys.single(), "Expected only one entry from sourceSetB") + assertEquals("This is package sample.b", documentation.texts.single()) + } + + @Test + fun `assert sample_b in sourceSetB and sourceSetB2`() { + val documentation = reader[DPackage(DRI("sample.b"), sourceSets = setOf(sourceSetB, sourceSetB2))] + assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSetB") + assertEquals(sourceSetB, documentation.keys.single(), "Expected only one entry from sourceSetB") + assertEquals("This is package sample.b", documentation.texts.single()) + } +} diff --git a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest2.kt b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest2.kt new file mode 100644 index 0000000000..e209a170e4 --- /dev/null +++ b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest2.kt @@ -0,0 +1,63 @@ +package transformers + +import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationReader +import org.jetbrains.dokka.model.DModule +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.utilities.DokkaConsoleLogger +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testApi.testRunner.dokkaConfiguration +import testApi.testRunner.sourceSet + + +class ContextModuleAndPackageDocumentationReaderTest2: AbstractContextModuleAndPackageDocumentationReaderTest() { + + private val include by lazy { temporaryDirectory.resolve("include.md").toFile() } + + @BeforeEach + fun materializeInclude() { + include.writeText( + """ + # Module MyModuleDisplayName + Matching: moduleDisplayName + + # Module myModuleName + Matching: moduleName + """.trimIndent() + ) + } + + private val sourceSet by lazy { + sourceSet { + moduleName = "myModuleName" + moduleDisplayName = "MyModuleDisplayName" + includes = listOf(include.canonicalPath) + } + } + + private val context by lazy { + DokkaContext.create( + configuration = dokkaConfiguration { + sourceSets { + add(sourceSet) + } + }, + logger = DokkaConsoleLogger, + pluginOverrides = emptyList() + ) + } + + private val reader by lazy { ModuleAndPackageDocumentationReader(context) } + + + @Test + fun `module matches for moduleName and moduleDisplayName`() { + val documentation = reader[DModule("myModuleName", sourceSets = setOf(sourceSet))] + assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSet") + assertEquals(sourceSet, documentation.keys.single(), "Expected only one entry from sourceSet") + assertEquals( + listOf("Matching: moduleDisplayName", "Matching: moduleName"), documentation.texts + ) + } +} diff --git a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerTest.kt b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerTest.kt index a947633d1f..d2b41273a3 100644 --- a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerTest.kt +++ b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerTest.kt @@ -1,18 +1,16 @@ package transformers -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationReader import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationTransformer import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.model.DPackage import org.jetbrains.dokka.model.SourceSetDependent -import org.jetbrains.dokka.model.doc.Description import org.jetbrains.dokka.model.doc.DocumentationNode -import org.jetbrains.dokka.model.doc.Text import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test -import renderers.defaultSourceSet +import testApi.testRunner.documentationNode +import testApi.testRunner.sourceSet class ModuleAndPackageDocumentationTransformerTest { @@ -141,22 +139,22 @@ class ModuleAndPackageDocumentationTransformerTest { documentation = emptyMap(), sourceSets = emptySet(), packages = listOf( - dPackage( - name = "com.sample", + DPackage( + dri = DRI("com.sample"), documentation = mapOf( sourceSet("A") to documentationNode("pre-existing:A:com.sample") ), sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")), ), - dPackage( - name = "com.attach", + DPackage( + dri = DRI("com.attach"), documentation = mapOf( sourceSet("A") to documentationNode("pre-existing:A:com.attach") ), sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")) ), - dPackage( - name = "com.attach.sub", + DPackage( + dri = DRI("com.attach.sub"), documentation = mapOf( sourceSet("A") to documentationNode("pre-existing:A:com.attach.sub"), sourceSet("B") to documentationNode("pre-existing:B:com.attach.sub"), @@ -178,7 +176,7 @@ class ModuleAndPackageDocumentationTransformerTest { val comSample = result.single().packages.single { it.dri.packageName == "com.sample" } assertEquals( - mapOf(sourceSet("A") to documentationNode("pre-existing:A:com.sample")), + mapOf(sourceSet("A") to documentationNode("pre-existing:A:com.sample")), comSample.documentation, "Expected no documentation added to package 'com.sample' because of wrong package" ) @@ -199,8 +197,8 @@ class ModuleAndPackageDocumentationTransformerTest { documentation = emptyMap(), sourceSets = emptySet(), packages = listOf( - dPackage( - name = "com.sample", + DPackage( + dri = DRI("com.sample"), documentation = mapOf( /* No documentation added, since in wrong package */ sourceSet("A") to documentationNode("pre-existing:A:com.sample") @@ -208,8 +206,8 @@ class ModuleAndPackageDocumentationTransformerTest { sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")), ), - dPackage( - name = "com.attach", + DPackage( + dri = DRI("com.attach"), documentation = mapOf( /* Documentation added */ sourceSet("A") to documentationNode("pre-existing:A:com.attach", "doc:A:com.attach"), @@ -217,8 +215,8 @@ class ModuleAndPackageDocumentationTransformerTest { ), sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")), ), - dPackage( - name = "com.attach.sub", + DPackage( + dri = DRI("com.attach.sub"), documentation = mapOf( /* Documentation added */ sourceSet("A") to documentationNode( @@ -241,30 +239,3 @@ class ModuleAndPackageDocumentationTransformerTest { } } - - -private fun sourceSet(name: String): DokkaSourceSet { - return defaultSourceSet.copy( - displayName = name, - sourceSetID = defaultSourceSet.sourceSetID.copy(sourceSetName = name) - ) -} - -private fun documentationNode(vararg texts: String): DocumentationNode { - return DocumentationNode(texts.toList().map { Description(Text(it)) }) -} - -private fun dPackage( - name: String, - documentation: SourceSetDependent, - sourceSets: Set -): DPackage = DPackage( - dri = DRI(name), - documentation = documentation, - sourceSets = sourceSets, - classlikes = emptyList(), - functions = emptyList(), - properties = emptyList(), - typealiases = emptyList() - -) From c2a0167ed8ffe883c40dedcbd769b9e0dd0bc2c5 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Wed, 26 Aug 2020 15:40:23 +0200 Subject: [PATCH 06/19] Let `DRI.packageName` always be a real package name for root packages ("") --- .../org/jetbrains/dokka/analysis/DRIFactory.kt | 4 ++-- .../resolvers/local/DokkaLocationProvider.kt | 5 ++++- .../DefaultDescriptorToDocumentableTranslator.kt | 16 +++------------- .../base/src/test/kotlin/markdown/LinkTest.kt | 2 +- .../base/src/test/kotlin/model/PackagesTest.kt | 6 +++--- 5 files changed, 13 insertions(+), 20 deletions(-) diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt index 217a3b7dec..e74f9f6a02 100644 --- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt @@ -12,7 +12,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull fun DRI.Companion.from(descriptor: DeclarationDescriptor) = descriptor.parentsWithSelf.run { val callable = firstIsInstanceOrNull() DRI( - firstIsInstanceOrNull()?.fqName?.asString(), + firstIsInstanceOrNull()?.fqName?.asString() ?: "", (filterIsInstance() + filterIsInstance()).toList() .takeIf { it.isNotEmpty() } ?.asReversed() @@ -27,7 +27,7 @@ fun DRI.Companion.from(psi: PsiElement) = psi.parentsWithSelf.run { val psiField = firstIsInstanceOrNull() val classes = filterIsInstance().filterNot { it is PsiTypeParameter }.toList() // We only want exact PsiClass types, not PsiTypeParameter subtype DRI( - classes.lastOrNull()?.qualifiedName?.substringBeforeLast('.', ""), + classes.lastOrNull()?.qualifiedName?.substringBeforeLast('.', "") ?: "", classes.toList().takeIf { it.isNotEmpty() }?.asReversed()?.mapNotNull { it.name }?.joinToString("."), psiMethod?.let { Callable.from(it) } ?: psiField?.let { Callable.from(it) }, DriTarget.from(psi) diff --git a/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt index 096104ccbc..f25f85a656 100644 --- a/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt +++ b/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt @@ -89,7 +89,10 @@ open class DokkaLocationProvider( private fun PageNode.parent() = pageGraphRoot.parentMap[this] private val PageNode.pathName: String - get() = if (this is PackagePageNode) name else identifierToFilename(name) + get() = when (this) { + is PackagePageNode -> if (name.isBlank()) "[root]" else name + else -> identifierToFilename(name) + } companion object { internal val reservedFilenames = setOf("index", "con", "aux", "lst", "prn", "nul", "eof", "inp", "out") diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index fccbe716be..18b05df45d 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -104,7 +104,7 @@ private class DokkaDescriptorVisitor( descriptor: PackageFragmentDescriptor, parent: DRIWithPlatformInfo ): DPackage { - val name = descriptor.fqName.asString().takeUnless { it.isBlank() } ?: fallbackPackageName() + val name = descriptor.fqName.asString().takeUnless { it.isBlank() } ?: "" val driWithPlatform = DRI(packageName = name).withEmptyInfo() val scope = descriptor.getMemberScope() @@ -590,7 +590,7 @@ private class DokkaDescriptorVisitor( private fun TypeParameterDescriptor.toVariantTypeParameter() = DTypeParameter( variantTypeParameter( - TypeParameter(DRI.from(this).withPackageFallbackTo(fallbackPackageName()), name.identifier) + TypeParameter(DRI.from(this), name.identifier) ), resolveDescriptorData(), null, @@ -603,7 +603,7 @@ private class DokkaDescriptorVisitor( is DynamicType -> Dynamic else -> when (val ctor = constructor.declarationDescriptor) { is TypeParameterDescriptor -> TypeParameter( - dri = DRI.from(ctor).withPackageFallbackTo(fallbackPackageName()), + dri = DRI.from(ctor), name = ctor.name.asString() ) else -> TypeConstructor( @@ -776,14 +776,4 @@ private class DokkaDescriptorVisitor( private fun ConstantsEnumValue.fullEnumEntryName() = "${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 fun DRI.withPackageFallbackTo(fallbackPackage: String): DRI { - return if (packageName.isNullOrBlank()) { - copy(packageName = fallbackPackage) - } else { - this - } } diff --git a/plugins/base/src/test/kotlin/markdown/LinkTest.kt b/plugins/base/src/test/kotlin/markdown/LinkTest.kt index deef1d2d5b..b84eead4b9 100644 --- a/plugins/base/src/test/kotlin/markdown/LinkTest.kt +++ b/plugins/base/src/test/kotlin/markdown/LinkTest.kt @@ -73,7 +73,7 @@ class LinkTest : AbstractCoreTest() { val foo = innerClass.children.first { it.name == "foo" } as MemberPageNode val destinationDri = (root.documentable as WithGenerics).generics.first().dri.toString() - assertEquals(destinationDri, "[JVM root]/Outer///PointingToGenericParameters(0)/") + assertEquals(destinationDri, "/Outer///PointingToGenericParameters(0)/") assertNotNull(foo.content.dfs { it is ContentDRILink && it.address.toString() == destinationDri } ) } } diff --git a/plugins/base/src/test/kotlin/model/PackagesTest.kt b/plugins/base/src/test/kotlin/model/PackagesTest.kt index 86222d9505..188ee2c6b8 100644 --- a/plugins/base/src/test/kotlin/model/PackagesTest.kt +++ b/plugins/base/src/test/kotlin/model/PackagesTest.kt @@ -22,8 +22,8 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac } } ) { - with((this / "[JVM root]").cast()) { - name equals "[JVM root]" + with((this / "").cast()) { + name equals "" children counts 0 } } @@ -131,4 +131,4 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac // assertEquals(0, model.members.count()) // } // } -} \ No newline at end of file +} From e140fb32d3b819789c92fba30b5c3731c371c4e3 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Wed, 26 Aug 2020 14:49:31 +0200 Subject: [PATCH 07/19] WIP --- core/src/main/kotlin/links/DRI.kt | 2 - .../main/kotlin/links/canonicalPackageName.kt | 5 + .../jetbrains/dokka/analysis/DRIFactory.kt | 3 +- ...eModuleAndPackageDocumentationFragments.kt | 14 +-- ...uleAndPackageDocumentationFragmentsTest.kt | 31 +++--- ...eDocumentationTransformerFunctionalTest.kt | 96 +++++++++++++++++++ ...ackageDocumentationTransformerUnitTest.kt} | 2 +- 7 files changed, 129 insertions(+), 24 deletions(-) create mode 100644 core/src/main/kotlin/links/canonicalPackageName.kt create mode 100644 plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerFunctionalTest.kt rename plugins/base/src/test/kotlin/transformers/{ModuleAndPackageDocumentationTransformerTest.kt => ModuleAndPackageDocumentationTransformerUnitTest.kt} (99%) diff --git a/core/src/main/kotlin/links/DRI.kt b/core/src/main/kotlin/links/DRI.kt index 8dfac80cb3..6e1038d920 100644 --- a/core/src/main/kotlin/links/DRI.kt +++ b/core/src/main/kotlin/links/DRI.kt @@ -1,7 +1,5 @@ package org.jetbrains.dokka.links -import org.jetbrains.dokka.model.ClassKind - /** * [DRI] stands for DokkaResourceIdentifier */ diff --git a/core/src/main/kotlin/links/canonicalPackageName.kt b/core/src/main/kotlin/links/canonicalPackageName.kt new file mode 100644 index 0000000000..5ef53933a9 --- /dev/null +++ b/core/src/main/kotlin/links/canonicalPackageName.kt @@ -0,0 +1,5 @@ +package org.jetbrains.dokka.links + +val DRI.canonicalPackageName: String get() { + TODO() +} diff --git a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt index e74f9f6a02..f47bf34bb4 100644 --- a/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt +++ b/kotlin-analysis/src/main/kotlin/org/jetbrains/dokka/analysis/DRIFactory.kt @@ -25,7 +25,8 @@ fun DRI.Companion.from(descriptor: DeclarationDescriptor) = descriptor.parentsWi fun DRI.Companion.from(psi: PsiElement) = psi.parentsWithSelf.run { val psiMethod = firstIsInstanceOrNull() val psiField = firstIsInstanceOrNull() - val classes = filterIsInstance().filterNot { it is PsiTypeParameter }.toList() // We only want exact PsiClass types, not PsiTypeParameter subtype + val classes = filterIsInstance().filterNot { it is PsiTypeParameter } + .toList() // We only want exact PsiClass types, not PsiTypeParameter subtype DRI( classes.lastOrNull()?.qualifiedName?.substringBeforeLast('.', "") ?: "", classes.toList().takeIf { it.isNotEmpty() }?.asReversed()?.mapNotNull { it.name }?.joinToString("."), diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt index 2667681cc0..6155af5273 100644 --- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt +++ b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt @@ -1,5 +1,6 @@ package org.jetbrains.dokka.base.parsers.moduleAndPackage +import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.* import java.io.File @@ -24,17 +25,18 @@ private fun parseModuleAndPackageDocFragment( val firstLine = firstLineAndDocumentation[0] val classifierAndName = firstLine.split(Regex("\\s+"), limit = 2) - if (classifierAndName.size != 2) { - throw IllegalModuleAndPackageDocumentation(source, "Missing ${classifierAndName.first()} name") - } val classifier = when (classifierAndName[0].trim()) { - "Module" -> ModuleAndPackageDocumentation.Classifier.Module - "Package" -> ModuleAndPackageDocumentation.Classifier.Package + "Module" -> Module + "Package" -> Package else -> throw IllegalStateException("Unexpected classifier ${classifierAndName[0]}") } - val name = classifierAndName[1].trim() + if (classifierAndName.size != 2 && classifier == Module) { + throw IllegalModuleAndPackageDocumentation(source, "Missing Module name") + } + + val name = classifierAndName.getOrNull(1)?.trim().orEmpty() if (name.contains(Regex("\\s"))) { throw IllegalModuleAndPackageDocumentation( source, "Module/Package name cannot contain whitespace in '$firstLine'" diff --git a/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt b/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt index 5c0a064621..17f9631ac6 100644 --- a/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt +++ b/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt @@ -76,21 +76,24 @@ class ParseModuleAndPackageDocumentationFragmentsTest { } @Test - fun `no package name specified fails`() { - val exception = assertThrows { - parseModuleAndPackageDocumentationFragments( - source( - """ - # Package - No package name given - """.trimIndent() - ) - ) - } + fun `no package name specified does not fail`() { + val source = source( + """ + # Package + This is a root package + """.trimIndent() + ) + val fragments = parseModuleAndPackageDocumentationFragments(source) + assertEquals(1, fragments.size, "Expected a single package fragment") - assertTrue( - "Missing Package name" in exception.message.orEmpty(), - "Expected 'Missing Package name' in error message" + assertEquals( + ModuleAndPackageDocumentationFragment( + name = "", + classifier = Package, + documentation = "This is a root package", + source = source + ), + fragments.single() ) } diff --git a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerFunctionalTest.kt b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerFunctionalTest.kt new file mode 100644 index 0000000000..e622e79dbe --- /dev/null +++ b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerFunctionalTest.kt @@ -0,0 +1,96 @@ +package transformers + +import org.jetbrains.dokka.DokkaSourceSetID +import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.io.TempDir +import java.nio.file.Path +import kotlin.test.assertEquals + +class ModuleAndPackageDocumentationTransformerFunctionalTest : AbstractCoreTest() { + + @Test + fun `multiplatform project`(@TempDir tempDir: Path) { + val include = tempDir.resolve("include.md").toFile() + include.writeText( + """ + # Module moduleA + This is moduleA + + # Package + This is the root package + + # Package common + This is the common package + + # Package jvm + This is the jvm package + + # Package js + This is the js package + """.trimIndent() + ) + val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + moduleName = "moduleA" + name = "commonMain" + displayName = "common" + analysisPlatform = "common" + sourceRoots = listOf("src/commonMain/kotlin") + includes = listOf(include.canonicalPath) + } + sourceSet { + moduleName = "moduleA" + name = "jsMain" + displayName = "js" + analysisPlatform = "js" + sourceRoots = listOf("src/jsMain/kotlin") + dependentSourceSets = setOf(DokkaSourceSetID("moduleA", "commonMain")) + } + sourceSet { + moduleName = "moduleA" + name = "jvmMain" + displayName = "jvm" + analysisPlatform = "jvm" + sourceRoots = listOf("src/jvmMain/kotlin") + dependentSourceSets = setOf(DokkaSourceSetID("moduleA", "commonMain")) + } + } + } + + testInline( + """ + /src/commonMain/kotlin/common/CommonApi.kt + package common + val commonApi = "common" + + /src/jsMain/kotlin/js/JsApi.kt + package js + val jsApi = "js" + + /src/jvmMain/kotlin/jvm/JvmApi.kt + package jvm + val jvmApi = "jvm" + + /src/commonMain/kotlin/CommonRoot.kt + val commonRoot = "commonRoot" + + /src/jsMain/kotlin/JsRoot.kt + val jsRoot = "jsRoot" + + /src/jvmMain/kotlin/JvmRoot.kt + val jvmRoot = "jvmRoot" + """.trimIndent(), + configuration + ) { + this.documentablesMergingStage = { module -> + val packageNames = module.packages.map { it.dri.packageName ?: "NULL" } + assertEquals( + listOf("", "common", "js", "jvm").sorted(), packageNames.sorted(), + "Expected all packages to be present" + ) + } + } + } +} diff --git a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerTest.kt b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerUnitTest.kt similarity index 99% rename from plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerTest.kt rename to plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerUnitTest.kt index d2b41273a3..b75f8e5b51 100644 --- a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerTest.kt +++ b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerUnitTest.kt @@ -13,7 +13,7 @@ import testApi.testRunner.documentationNode import testApi.testRunner.sourceSet -class ModuleAndPackageDocumentationTransformerTest { +class ModuleAndPackageDocumentationTransformerUnitTest { @Test fun `empty list of modules`() { From a650caa55b7866e17f69bbc0377ae3d35507649d Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Wed, 26 Aug 2020 16:09:04 +0200 Subject: [PATCH 08/19] Implement `root package is matched by empty string and the root keyword` test --- .../ModuleAndPackageDocumentationReader.kt | 10 +++- ...ModuleAndPackageDocumentationReaderTest.kt | 15 ++--- ...oduleAndPackageDocumentationReaderTest3.kt | 59 +++++++++++++++++++ ...eDocumentationTransformerFunctionalTest.kt | 37 ++++++++++++ 4 files changed, 112 insertions(+), 9 deletions(-) create mode 100644 plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt index 4900e9a8ef..e712d6e5cb 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt @@ -56,6 +56,13 @@ private class ContextModuleAndPackageDocumentationReader( } } + private val ModuleAndPackageDocumentationFragment.canonicalPackageName: String + get() { + check(classifier == Classifier.Package) + if (name == "[root]") return "" + return name + } + override fun get(module: DModule): SourceSetDependent { return findDocumentationNodes(module.sourceSets) { fragment -> fragment.classifier == Classifier.Module && ( @@ -68,8 +75,7 @@ private class ContextModuleAndPackageDocumentationReader( override fun get(pkg: DPackage): SourceSetDependent { return findDocumentationNodes(pkg.sourceSets) { fragment -> - // TODO NOW: handle JS Root thing - fragment.classifier == Classifier.Package && fragment.name == pkg.dri.packageName + fragment.classifier == Classifier.Package && fragment.canonicalPackageName == pkg.dri.packageName } } } diff --git a/plugins/base/src/test/kotlin/transformers/AbstractContextModuleAndPackageDocumentationReaderTest.kt b/plugins/base/src/test/kotlin/transformers/AbstractContextModuleAndPackageDocumentationReaderTest.kt index 7f4350130d..0f26b2f5b9 100644 --- a/plugins/base/src/test/kotlin/transformers/AbstractContextModuleAndPackageDocumentationReaderTest.kt +++ b/plugins/base/src/test/kotlin/transformers/AbstractContextModuleAndPackageDocumentationReaderTest.kt @@ -12,11 +12,12 @@ abstract class AbstractContextModuleAndPackageDocumentationReaderTest { protected lateinit var temporaryDirectory: Path - protected val SourceSetDependent.texts: List - get() = values.flatMap { it.withDescendants() } - .flatMap { it.children } - .flatMap { it.children } - .mapNotNull { it as? Text } - .map { it.body } - + companion object { + val SourceSetDependent.texts: List + get() = values.flatMap { it.withDescendants() } + .flatMap { it.children } + .flatMap { it.children } + .mapNotNull { it as? Text } + .map { it.body } + } } diff --git a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt new file mode 100644 index 0000000000..e1b9d199a9 --- /dev/null +++ b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt @@ -0,0 +1,59 @@ +package transformers + +import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationReader +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.DPackage +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.utilities.DokkaConsoleLogger +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import testApi.testRunner.dokkaConfiguration +import testApi.testRunner.sourceSet +import kotlin.test.assertEquals + +class ContextModuleAndPackageDocumentationReaderTest3 : AbstractContextModuleAndPackageDocumentationReaderTest() { + + private val include by lazy { temporaryDirectory.resolve("include.md").toFile() } + + @BeforeEach + fun materializeInclude() { + include.writeText( + """ + # Package + This is the root package + + # Package [root] + This is also the root package + """.trimIndent() + ) + } + + private val sourceSet by lazy { + sourceSet { + includes = listOf(include.canonicalPath) + } + } + + private val context by lazy { + DokkaContext.create( + configuration = dokkaConfiguration { + sourceSets { + add(sourceSet) + } + }, + logger = DokkaConsoleLogger, + pluginOverrides = emptyList() + ) + } + + private val reader by lazy { ModuleAndPackageDocumentationReader(context) } + + + @Test + fun `root package is matched by empty string and the root keyword`() { + val documentation = reader[DPackage(DRI(""), sourceSets = setOf(sourceSet))] + assertEquals( + listOf("This is the root package", "This is also the root package"), documentation.texts + ) + } +} diff --git a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerFunctionalTest.kt b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerFunctionalTest.kt index e622e79dbe..2d356a8170 100644 --- a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerFunctionalTest.kt +++ b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerFunctionalTest.kt @@ -4,6 +4,7 @@ import org.jetbrains.dokka.DokkaSourceSetID import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest import org.junit.jupiter.api.Test import org.junit.jupiter.api.io.TempDir +import transformers.AbstractContextModuleAndPackageDocumentationReaderTest.Companion.texts import java.nio.file.Path import kotlin.test.assertEquals @@ -20,6 +21,9 @@ class ModuleAndPackageDocumentationTransformerFunctionalTest : AbstractCoreTest( # Package This is the root package + # Package [root] + This is also the root package + # Package common This is the common package @@ -47,6 +51,7 @@ class ModuleAndPackageDocumentationTransformerFunctionalTest : AbstractCoreTest( analysisPlatform = "js" sourceRoots = listOf("src/jsMain/kotlin") dependentSourceSets = setOf(DokkaSourceSetID("moduleA", "commonMain")) + includes = listOf(include.canonicalPath) } sourceSet { moduleName = "moduleA" @@ -55,6 +60,7 @@ class ModuleAndPackageDocumentationTransformerFunctionalTest : AbstractCoreTest( analysisPlatform = "jvm" sourceRoots = listOf("src/jvmMain/kotlin") dependentSourceSets = setOf(DokkaSourceSetID("moduleA", "commonMain")) + includes = listOf(include.canonicalPath) } } } @@ -90,6 +96,37 @@ class ModuleAndPackageDocumentationTransformerFunctionalTest : AbstractCoreTest( listOf("", "common", "js", "jvm").sorted(), packageNames.sorted(), "Expected all packages to be present" ) + + /* Assert module documentation */ + assertEquals(3, module.documentation.keys.size, "Expected all three source sets") + assertEquals("This is moduleA", module.documentation.texts.distinct().joinToString()) + + /* Assert root package */ + val rootPackage = module.packages.single { it.dri.packageName == "" } + assertEquals(3, rootPackage.documentation.keys.size, "Expected all three source sets") + assertEquals( + listOf("This is the root package", "This is also the root package"), + rootPackage.documentation.texts.distinct() + ) + + /* Assert common package */ + val commonPackage = module.packages.single { it.dri.packageName == "common" } + assertEquals(3, commonPackage.documentation.keys.size, "Expected all three source sets") + assertEquals("This is the common package", commonPackage.documentation.texts.distinct().joinToString()) + + /* Assert js package */ + val jsPackage = module.packages.single { it.dri.packageName == "js" } + assertEquals( + "This is the js package", + jsPackage.documentation.texts.joinToString() + ) + + /* Assert the jvm package */ + val jvmPackage = module.packages.single { it.dri.packageName == "jvm" } + assertEquals( + "This is the jvm package", + jvmPackage.documentation.texts.joinToString() + ) } } } From 4fca6b4407643a564f1de159498ccf9d2d854442 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Wed, 26 Aug 2020 16:25:52 +0200 Subject: [PATCH 09/19] Remove DRI.canonicalPackageName --- core/src/main/kotlin/links/canonicalPackageName.kt | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 core/src/main/kotlin/links/canonicalPackageName.kt diff --git a/core/src/main/kotlin/links/canonicalPackageName.kt b/core/src/main/kotlin/links/canonicalPackageName.kt deleted file mode 100644 index 5ef53933a9..0000000000 --- a/core/src/main/kotlin/links/canonicalPackageName.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.jetbrains.dokka.links - -val DRI.canonicalPackageName: String get() { - TODO() -} From 1c73c5ea1750eae9cf149aedba955ad19daa0914 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Wed, 26 Aug 2020 16:56:39 +0200 Subject: [PATCH 10/19] Let root package be represented as [root] to the user --- core/src/main/kotlin/model/Documentable.kt | 15 ++++++++++++--- core/src/main/kotlin/pages/PageNodes.kt | 5 +++++ .../dokka/it/cli/CliIntegrationTest.kt | 1 + .../src/main/kotlin/RootPackageClass.kt | 8 ++++++++ .../src/main/kotlin/it/basic/PublicClass.kt | 5 +++++ .../it/gradle/Android0GradleIntegrationTest.kt | 1 + .../it/gradle/BasicGradleIntegrationTest.kt | 1 + .../it/gradle/BasicGroovyIntegrationTest.kt | 1 + .../it/gradle/Collector0IntegrationTest.kt | 1 + .../it/gradle/MultiModule0IntegrationTest.kt | 1 + .../Multiplatform0GradleIntegrationTest.kt | 1 + .../dokka/it/maven/MavenIntegrationTest.kt | 1 + .../dokka/it/AbstractIntegrationTest.kt | 8 ++++++++ .../src/main/kotlin/utils/TestOutputWriter.kt | 3 ++- .../resolvers/local/DokkaLocationProvider.kt | 5 +---- .../base/src/test/kotlin/model/PackagesTest.kt | 18 ++++++++++-------- .../base/src/test/kotlin/translators/utils.kt | 4 ++-- .../dokka/javadoc/JavadocPageCreator.kt | 2 +- .../dokka/javadoc/pages/JavadocPageNodes.kt | 6 +++++- 19 files changed, 67 insertions(+), 20 deletions(-) create mode 100644 integration-tests/gradle/projects/it-basic/src/main/kotlin/RootPackageClass.kt diff --git a/core/src/main/kotlin/model/Documentable.kt b/core/src/main/kotlin/model/Documentable.kt index 293b8a30ed..34ad6c2b0f 100644 --- a/core/src/main/kotlin/model/Documentable.kt +++ b/core/src/main/kotlin/model/Documentable.kt @@ -111,9 +111,18 @@ data class DPackage( override val sourceSets: Set = emptySet(), override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithScope, WithExtraProperties { - override val name = dri.packageName.orEmpty() - override val children: List - get() = (properties + functions + classlikes + typealiases) + + val packageName: String = dri.packageName.orEmpty() + + /** + * !!! WARNING !!! + * This name is not guaranteed to be a be a canonical/real package name. + * e.g. this will return a human readable version for root packages. + * Use [packageName] or `dri.packageName` instead to obtain the real packageName + */ + override val name: String = if (packageName.isBlank()) "[root]" else packageName + + override val children: List = properties + functions + classlikes + typealiases override fun withNewExtras(newExtras: PropertyContainer) = copy(extra = newExtras) } diff --git a/core/src/main/kotlin/pages/PageNodes.kt b/core/src/main/kotlin/pages/PageNodes.kt index 176c099377..a91887b49f 100644 --- a/core/src/main/kotlin/pages/PageNodes.kt +++ b/core/src/main/kotlin/pages/PageNodes.kt @@ -92,6 +92,11 @@ class PackagePageNode( override val children: List, override val embeddedResources: List = listOf() ) : PackagePage { + + init { + require(name.isNotBlank()) { "PackagePageNode.name cannot be blank" } + } + override fun modified(name: String, children: List): PackagePageNode = modified(name = name, content = this.content, children = children) diff --git a/integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt b/integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt index 462ab8423c..6510c0440f 100644 --- a/integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt +++ b/integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt @@ -85,6 +85,7 @@ class CliIntegrationTest : AbstractCliIntegrationTest() { assertContainsNoErrorClass(file) assertNoUnresolvedLinks(file) assertNoEmptyLinks(file) + assertNoEmptySpans(file) } } } diff --git a/integration-tests/gradle/projects/it-basic/src/main/kotlin/RootPackageClass.kt b/integration-tests/gradle/projects/it-basic/src/main/kotlin/RootPackageClass.kt new file mode 100644 index 0000000000..8ff6c750ad --- /dev/null +++ b/integration-tests/gradle/projects/it-basic/src/main/kotlin/RootPackageClass.kt @@ -0,0 +1,8 @@ +@file:Suppress("unused") + +/** + * A class that lives inside the root package + */ +class RootPackageClass { + val description = "I do live in the root package!" +} diff --git a/integration-tests/gradle/projects/it-basic/src/main/kotlin/it/basic/PublicClass.kt b/integration-tests/gradle/projects/it-basic/src/main/kotlin/it/basic/PublicClass.kt index 71bc7e6394..fc4b36bd83 100644 --- a/integration-tests/gradle/projects/it-basic/src/main/kotlin/it/basic/PublicClass.kt +++ b/integration-tests/gradle/projects/it-basic/src/main/kotlin/it/basic/PublicClass.kt @@ -2,6 +2,11 @@ package it.basic +import RootPackageClass + +/** + * This class, unlike [RootPackageClass] is located in a sub-package + */ class PublicClass { /** * This function is public and documented diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt index 145992fc0a..bfeed55e5a 100644 --- a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt +++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Android0GradleIntegrationTest.kt @@ -59,6 +59,7 @@ class Android0GradleIntegrationTest(override val versions: BuildVersions) : Abst assertNoUnresolvedLinks(file, knownUnresolvedDRIs) assertNoHrefToMissingLocalFileOrDirectory(file) assertNoEmptyLinks(file) + assertNoEmptySpans(file) } assertTrue( diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt index a0a43764ba..1265d675a2 100644 --- a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt +++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt @@ -79,6 +79,7 @@ class BasicGradleIntegrationTest(override val versions: BuildVersions) : Abstrac assertNoHrefToMissingLocalFileOrDirectory(file) assertNoSuppressedMarker(file) assertNoEmptyLinks(file) + assertNoEmptySpans(file) } assertTrue( diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGroovyIntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGroovyIntegrationTest.kt index 5c1480f405..0e1252588f 100644 --- a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGroovyIntegrationTest.kt +++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGroovyIntegrationTest.kt @@ -82,6 +82,7 @@ class BasicGroovyIntegrationTest(override val versions: BuildVersions) : Abstrac assertNoUnresolvedLinks(file) assertNoHrefToMissingLocalFileOrDirectory(file) assertNoEmptyLinks(file) + assertNoEmptySpans(file) } } diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Collector0IntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Collector0IntegrationTest.kt index d47a0e5f5f..c3971eae3f 100644 --- a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Collector0IntegrationTest.kt +++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Collector0IntegrationTest.kt @@ -52,6 +52,7 @@ class Collector0IntegrationTest(override val versions: BuildVersions) : Abstract assertNoUnresolvedLinks(file) assertNoHrefToMissingLocalFileOrDirectory(file) assertNoEmptyLinks(file) + assertNoEmptySpans(file) } assertTrue( diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule0IntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule0IntegrationTest.kt index 6d15de268f..eedc6da3a2 100644 --- a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule0IntegrationTest.kt +++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/MultiModule0IntegrationTest.kt @@ -57,6 +57,7 @@ class MultiModule0IntegrationTest(override val versions: BuildVersions) : Abstra assertNoUnresolvedLinks(file) assertNoHrefToMissingLocalFileOrDirectory(file) assertNoEmptyLinks(file) + assertNoEmptySpans(file) } val modulesFile = File(outputDir, "-modules.html") diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multiplatform0GradleIntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multiplatform0GradleIntegrationTest.kt index 2f716fa7dd..8f7ccbd33d 100644 --- a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multiplatform0GradleIntegrationTest.kt +++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/Multiplatform0GradleIntegrationTest.kt @@ -39,6 +39,7 @@ class Multiplatform0GradleIntegrationTest(override val versions: BuildVersions) assertNoUnresolvedLinks(file) assertNoHrefToMissingLocalFileOrDirectory(file) assertNoEmptyLinks(file) + assertNoEmptySpans(file) } } } diff --git a/integration-tests/maven/src/integrationTest/kotlin/org/jetbrains/dokka/it/maven/MavenIntegrationTest.kt b/integration-tests/maven/src/integrationTest/kotlin/org/jetbrains/dokka/it/maven/MavenIntegrationTest.kt index 1a4fec44b8..88fdc207c6 100644 --- a/integration-tests/maven/src/integrationTest/kotlin/org/jetbrains/dokka/it/maven/MavenIntegrationTest.kt +++ b/integration-tests/maven/src/integrationTest/kotlin/org/jetbrains/dokka/it/maven/MavenIntegrationTest.kt @@ -52,6 +52,7 @@ class MavenIntegrationTest : AbstractIntegrationTest() { assertContainsNoErrorClass(file) assertNoUnresolvedLinks(file) assertNoEmptyLinks(file) + assertNoEmptySpans(file) } } diff --git a/integration-tests/src/main/kotlin/org/jetbrains/dokka/it/AbstractIntegrationTest.kt b/integration-tests/src/main/kotlin/org/jetbrains/dokka/it/AbstractIntegrationTest.kt index 04ae4a8869..2a01993ede 100644 --- a/integration-tests/src/main/kotlin/org/jetbrains/dokka/it/AbstractIntegrationTest.kt +++ b/integration-tests/src/main/kotlin/org/jetbrains/dokka/it/AbstractIntegrationTest.kt @@ -90,4 +90,12 @@ abstract class AbstractIntegrationTest { "Unexpected `§SUPPRESSED§` in file ${file.path}" ) } + + protected fun assertNoEmptySpans(file: File) { + val fileText = file.readText() + assertFalse( + fileText.contains(Regex("""\s*""")), + "Unexpected empty in file ${file.path}" + ) + } } diff --git a/plugins/base/base-test-utils/src/main/kotlin/utils/TestOutputWriter.kt b/plugins/base/base-test-utils/src/main/kotlin/utils/TestOutputWriter.kt index 00b865b488..67e62c364e 100644 --- a/plugins/base/base-test-utils/src/main/kotlin/utils/TestOutputWriter.kt +++ b/plugins/base/base-test-utils/src/main/kotlin/utils/TestOutputWriter.kt @@ -3,6 +3,7 @@ package utils import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.renderers.OutputWriter import org.jetbrains.dokka.plugability.DokkaPlugin +import java.util.* class TestOutputWriterPlugin(failOnOverwrite: Boolean = true) : DokkaPlugin() { val writer = TestOutputWriter(failOnOverwrite) @@ -19,7 +20,7 @@ class TestOutputWriterPlugin(failOnOverwrite: Boolean = true) : DokkaPlugin() { class TestOutputWriter(private val failOnOverwrite: Boolean = true) : OutputWriter { val contents: Map get() = _contents - private val _contents = mutableMapOf() + private val _contents = Collections.synchronizedMap(mutableMapOf()) override suspend fun write(path: String, text: String, ext: String) { val fullPath = "$path$ext" _contents.putIfAbsent(fullPath, text)?.also { diff --git a/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt index f25f85a656..096104ccbc 100644 --- a/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt +++ b/plugins/base/src/main/kotlin/resolvers/local/DokkaLocationProvider.kt @@ -89,10 +89,7 @@ open class DokkaLocationProvider( private fun PageNode.parent() = pageGraphRoot.parentMap[this] private val PageNode.pathName: String - get() = when (this) { - is PackagePageNode -> if (name.isBlank()) "[root]" else name - else -> identifierToFilename(name) - } + get() = if (this is PackagePageNode) name else identifierToFilename(name) companion object { internal val reservedFilenames = setOf("index", "con", "aux", "lst", "prn", "nul", "eof", "inp", "out") diff --git a/plugins/base/src/test/kotlin/model/PackagesTest.kt b/plugins/base/src/test/kotlin/model/PackagesTest.kt index 188ee2c6b8..1adf76268b 100644 --- a/plugins/base/src/test/kotlin/model/PackagesTest.kt +++ b/plugins/base/src/test/kotlin/model/PackagesTest.kt @@ -22,8 +22,8 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac } } ) { - with((this / "").cast()) { - name equals "" + with((this / "[root]").cast()) { + packageName equals "" children counts 0 } } @@ -38,7 +38,7 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac prependPackage = false ) { with((this / "simple").cast()) { - name equals "simple" + packageName equals "simple" children counts 0 } } @@ -53,7 +53,7 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac prependPackage = false ) { with((this / "dot.name").cast()) { - name equals "dot.name" + packageName equals "dot.name" children counts 0 } } @@ -72,11 +72,11 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac ) { children counts 2 with((this / "dot.name").cast()) { - name equals "dot.name" + packageName equals "dot.name" children counts 0 } with((this / "simple").cast()) { - name equals "simple" + packageName equals "simple" children counts 0 } } @@ -94,7 +94,7 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac ) { children counts 1 with((this / "simple").cast()) { - name equals "simple" + packageName equals "simple" children counts 0 } } @@ -111,12 +111,14 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac prependPackage = false ) { with((this / "simple.name").cast()) { - name equals "simple.name" + packageName equals "simple.name" children counts 1 } } } + // TODO NOW test displayName + // todo // @Test fun suppressAtPackageLevel() { // verifyModel( diff --git a/plugins/base/src/test/kotlin/translators/utils.kt b/plugins/base/src/test/kotlin/translators/utils.kt index 71b4a28b03..cbb6efa719 100644 --- a/plugins/base/src/test/kotlin/translators/utils.kt +++ b/plugins/base/src/test/kotlin/translators/utils.kt @@ -20,7 +20,7 @@ fun DModule.descriptionOf(className: String, functionName: String? = null): Desc } fun DModule.findPackage(packageName: String? = null) = - packageName?.let { packages.firstOrNull { pkg -> pkg.name == packageName } + packageName?.let { packages.firstOrNull { pkg -> pkg.packageName == packageName } ?: throw NoSuchElementException("No packageName with name $packageName") } ?: packages.single() fun DModule.findClasslike(packageName: String? = null, className: String? = null): DClasslike { @@ -37,4 +37,4 @@ fun DModule.findFunction(packageName: String? = null, className: String, functio classlike.functions.firstOrNull { fn -> fn.name == functionName } ?: throw NoSuchElementException("No classlike with name $functionName") } ?: classlike.functions.single() -} \ No newline at end of file +} diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/JavadocPageCreator.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/JavadocPageCreator.kt index 05de8fa173..2fb0033535 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/JavadocPageCreator.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/JavadocPageCreator.kt @@ -84,7 +84,7 @@ open class JavadocPageCreator( leafList(setOf(m.dri), ContentKind.Packages, JavadocList( "Packages", "Package", - m.packages.sortedBy { it.name }.map { p -> + m.packages.sortedBy { it.packageName }.map { p -> RowJavadocListEntry( LinkJavadocListEntry(p.name, setOf(p.dri), JavadocContentKind.PackageSummary, sourceSets), p.brief() diff --git a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocPageNodes.kt b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocPageNodes.kt index 3875c30713..2f26ea7931 100644 --- a/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocPageNodes.kt +++ b/plugins/javadoc/src/main/kotlin/org/jetbrains/dokka/javadoc/pages/JavadocPageNodes.kt @@ -74,6 +74,10 @@ class JavadocPackagePageNode( NavigableJavadocNode, PackagePage { + init { + require(name.isNotBlank()) { "Empty name is not supported " } + } + override fun getAllNavigables(): List = children.filterIsInstance().flatMap { if (it is WithNavigable) it.getAllNavigables() @@ -568,4 +572,4 @@ private fun Documentable.kind(): String? = is DObject -> "object" is DInterface -> "interface" else -> null - } \ No newline at end of file + } From 01a36d328bc1b453ca6b742cd60755caf18d8148 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Thu, 27 Aug 2020 15:50:40 +0200 Subject: [PATCH 11/19] Let module name be configurable withing `AbstractDokkaTask` and remove concept of `moduleDisplayName` --- README.md | 4 +- core/src/main/kotlin/configuration.kt | 8 ++- core/src/main/kotlin/defaultConfiguration.kt | 4 +- .../main/kotlin/model/CompositeSourceSetID.kt | 2 +- .../utilities/DokkaConfigurationJsonTest.kt | 8 +-- .../TestDokkaConfigurationBuilder.kt | 39 +++++++----- .../dokka/it/cli/CliIntegrationTest.kt | 3 +- .../gradle/projects/it-basic/build.gradle.kts | 2 +- .../it/gradle/BasicGradleIntegrationTest.kt | 2 +- .../maven/projects/it-maven/pom.xml | 2 +- .../allModulePage/MultimodulePageCreator.kt | 1 - ...eModuleAndPackageDocumentationFragments.kt | 4 +- .../DefaultDocumentableMerger.kt | 25 +++----- ...DeprecatedDocumentableFilterTransformer.kt | 2 +- .../ModuleAndPackageDocumentationReader.kt | 6 +- .../pages/samples/SamplesTransformer.kt | 6 +- ...faultDescriptorToDocumentableTranslator.kt | 31 +++++++-- .../psi/DefaultPsiToDocumentableTranslator.kt | 2 +- .../linkableContent/LinkableContentTest.kt | 10 ++- ...uleAndPackageDocumentationFragmentsTest.kt | 33 ++++++---- .../html/HtmlRenderingOnlyTestBase.kt | 3 - .../html/SourceSetDependentHintTest.kt | 3 - .../signatures/DivergentSignatureTest.kt | 14 ++--- .../test/kotlin/signatures/SignatureTest.kt | 3 +- ...oduleAndPackageDocumentationReaderTest1.kt | 49 ++++++--------- ...oduleAndPackageDocumentationReaderTest2.kt | 63 ------------------- ...oduleAndPackageDocumentationReaderTest3.kt | 15 ++--- ...eDocumentationTransformerFunctionalTest.kt | 4 +- .../ReportUndocumentedTransformerTest.kt | 6 +- .../kotlin/renderers/gfm/DivergentTest.kt | 3 - .../renderers/gfm/GfmRenderingOnlyTestBase.kt | 2 +- .../gfm/SourceSetDependentHintTest.kt | 3 - runners/cli/src/main/kotlin/cli/main.kt | 39 ++++++------ runners/gradle-plugin/MIGRATION.md | 2 +- .../dokka/gradle/AbstractDokkaTask.kt | 4 ++ .../dokka/gradle/DokkaCollectorTask.kt | 1 + .../dokka/gradle/DokkaMultiModuleTask.kt | 4 +- .../org/jetbrains/dokka/gradle/DokkaTask.kt | 3 +- .../gradle/GradleDokkaSourceSetBuilder.kt | 40 +++--------- .../GradleDokkaSourceSetBuilderExtensions.kt | 17 +++++ .../GradleDokkaSourceSetBuilderFactory.kt | 9 +++ .../dokka/gradle/dokkaSourceSetIDFactory.kt | 11 +++- .../dokka/gradle/toDokkaSourceSetImpl.kt | 6 -- .../ConfigureWithKotlinSourceSetGistTest.kt | 2 - .../dokka/gradle/DokkaCollectorTaskTest.kt | 2 + .../gradle/DokkaConfigurationJsonTest.kt | 1 - .../DokkaConfigurationSerializableTest.kt | 1 - .../dokka/gradle/DokkaMultiModuleTaskTest.kt | 2 + .../gradle/GradleDokkaSourceSetBuilder.kt | 11 ++++ .../gradle/GradleDokkaSourceSetBuilderTest.kt | 39 ++++-------- .../KotlinDslDokkaTaskConfigurationTest.kt | 6 +- .../maven-plugin/src/main/kotlin/DokkaMojo.kt | 9 +-- 52 files changed, 246 insertions(+), 325 deletions(-) delete mode 100644 plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest2.kt create mode 100644 runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderExtensions.kt create mode 100644 runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderFactory.kt create mode 100644 runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt diff --git a/README.md b/README.md index 19aff3b6ab..ed2d38c273 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,6 @@ dokkaHtml { cacheRoot.set(file("default")) dokkaSourceSets { configureEach { // Or source set name, for single-platform the default source sets are `main` and `test` - moduleDisplayName.set("data") // Used when configuring source sets manually for declaring which source sets this one depends on dependsOn("otherSourceSetName") @@ -407,7 +406,7 @@ The available configuration options are shown below: false - data + data some/out/dir @@ -556,7 +555,6 @@ Dokka supports the following command line arguments: * `-globalSrcLink` - source links added to all source sets * `-sourceSet` - (repeatable) - configuration for a single source set. Following this argument, you can pass other arguments: * `-moduleName` - (required) - module name used as a part of source set ID when declaring dependent source sets - * `-moduleDisplayName` - displayed module name * `-sourceSetName` - source set name as a part of source set ID when declaring dependent source sets * `-displayName` - source set name displayed in the generated documentation * `-src` - list of source files or directories separated by `;` diff --git a/core/src/main/kotlin/configuration.kt b/core/src/main/kotlin/configuration.kt index 2aa252e124..9a1ff602d3 100644 --- a/core/src/main/kotlin/configuration.kt +++ b/core/src/main/kotlin/configuration.kt @@ -9,6 +9,7 @@ import java.io.Serializable import java.net.URL object DokkaDefaults { + val moduleName: String = "root" val outputDir = File("./dokka") const val format: String = "html" val cacheRoot: File? = null @@ -58,12 +59,13 @@ interface DokkaConfigurationBuilder { fun Iterable>.build(): List = this.map { it.build() } + data class DokkaSourceSetID( - val moduleName: String, + val scopeId: String, val sourceSetName: String ) : Serializable { override fun toString(): String { - return "$moduleName/$sourceSetName" + return "$scopeId/$sourceSetName" } } @@ -72,6 +74,7 @@ fun DokkaConfigurationImpl(json: String): DokkaConfigurationImpl = parseJson(jso fun DokkaConfiguration.toJsonString(): String = toJsonString(this) interface DokkaConfiguration : Serializable { + val moduleName: String val outputDir: File val cacheRoot: File? val offlineMode: Boolean @@ -84,7 +87,6 @@ interface DokkaConfiguration : Serializable { interface DokkaSourceSet : Serializable { val sourceSetID: DokkaSourceSetID val displayName: String - val moduleDisplayName: String val classpath: List val sourceRoots: Set val dependentSourceSets: Set diff --git a/core/src/main/kotlin/defaultConfiguration.kt b/core/src/main/kotlin/defaultConfiguration.kt index 8bd2d97645..3fcc7aacd1 100644 --- a/core/src/main/kotlin/defaultConfiguration.kt +++ b/core/src/main/kotlin/defaultConfiguration.kt @@ -5,6 +5,7 @@ import java.io.File import java.net.URL data class DokkaConfigurationImpl( + override val moduleName: String = DokkaDefaults.moduleName, override val outputDir: File = DokkaDefaults.outputDir, override val cacheRoot: File? = DokkaDefaults.cacheRoot, override val offlineMode: Boolean = DokkaDefaults.offlineMode, @@ -12,12 +13,11 @@ data class DokkaConfigurationImpl( override val pluginsClasspath: List = emptyList(), override val pluginsConfiguration: Map = emptyMap(), override val modules: List = emptyList(), - override val failOnWarning: Boolean = DokkaDefaults.failOnWarning + override val failOnWarning: Boolean = DokkaDefaults.failOnWarning, ) : DokkaConfiguration data class DokkaSourceSetImpl( - override val moduleDisplayName: String, override val displayName: String = DokkaDefaults.sourceSetDisplayName, override val sourceSetID: DokkaSourceSetID, override val classpath: List = emptyList(), diff --git a/core/src/main/kotlin/model/CompositeSourceSetID.kt b/core/src/main/kotlin/model/CompositeSourceSetID.kt index 3c1cf7de23..9f38dafb39 100644 --- a/core/src/main/kotlin/model/CompositeSourceSetID.kt +++ b/core/src/main/kotlin/model/CompositeSourceSetID.kt @@ -14,7 +14,7 @@ data class CompositeSourceSetID( } val merged = DokkaSourceSetID( - moduleName = children.map { it.moduleName }.reduce { acc, s -> "$acc+$s" }, + scopeId = children.map { it.scopeId }.reduce { acc, s -> "$acc+$s" }, sourceSetName = children.map { it.sourceSetName }.reduce { acc, s -> "$acc+$s" } ) diff --git a/core/src/test/kotlin/utilities/DokkaConfigurationJsonTest.kt b/core/src/test/kotlin/utilities/DokkaConfigurationJsonTest.kt index 8efc84c651..ba33ab929e 100644 --- a/core/src/test/kotlin/utilities/DokkaConfigurationJsonTest.kt +++ b/core/src/test/kotlin/utilities/DokkaConfigurationJsonTest.kt @@ -9,11 +9,11 @@ class DokkaConfigurationJsonTest { @Test fun `simple configuration toJsonString then parseJson`() { val configuration = DokkaConfigurationImpl( + moduleName = "moduleName", outputDir = File("customOutputDir"), pluginsClasspath = listOf(File("plugins/customPlugin.jar")), sourceSets = listOf( DokkaSourceSetImpl( - moduleDisplayName = "customModuleDisplayName", sourceRoots = setOf(File("customSourceRoot")), sourceSetID = DokkaSourceSetID("customModuleName", "customSourceSetName") ) @@ -29,13 +29,13 @@ class DokkaConfigurationJsonTest { fun `parse simple configuration json`() { val json = """ { + "moduleName": "moduleName", "outputDir": "customOutputDir", "pluginsClasspath": [ "plugins/customPlugin.jar" ], "sourceSets": [ { - "moduleDisplayName": "customModuleDisplayName", "sourceSetID": { - "moduleName": "customModuleName", + "scopeId": "customModuleName", "sourceSetName": "customSourceSetName" }, "sourceRoots": [ "customSourceRoot" ], @@ -48,11 +48,11 @@ class DokkaConfigurationJsonTest { val parsedConfiguration = DokkaConfigurationImpl(json) assertEquals( DokkaConfigurationImpl( + moduleName = "moduleName", outputDir = File("customOutputDir"), pluginsClasspath = listOf(File("plugins/customPlugin.jar")), sourceSets = listOf( DokkaSourceSetImpl( - moduleDisplayName = "customModuleDisplayName", sourceRoots = setOf(File("customSourceRoot")), sourceSetID = DokkaSourceSetID("customModuleName", "customSourceSetName"), classpath = listOf(File("classpath/custom1.jar"), File("classpath/custom2.jar")) diff --git a/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt index 5bf7e52d03..f6cb99db4e 100644 --- a/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt +++ b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt @@ -16,6 +16,13 @@ annotation class DokkaConfigurationDsl @DokkaConfigurationDsl class TestDokkaConfigurationBuilder { + + var moduleName: String = "root" + set(value) { + check(lazySourceSets.isEmpty()) { "Cannot set moduleName after adding source sets" } + field = value + } + var outputDir: String = "out" var format: String = "html" var offlineMode: Boolean = false @@ -23,12 +30,13 @@ class TestDokkaConfigurationBuilder { var pluginsClasspath: List = emptyList() var pluginsConfigurations: Map = emptyMap() var failOnWarning: Boolean = false - private val sourceSets = mutableListOf() + private val lazySourceSets = mutableListOf>() fun build() = DokkaConfigurationImpl( + moduleName = moduleName, outputDir = File(outputDir), cacheRoot = cacheRoot?.let(::File), offlineMode = offlineMode, - sourceSets = sourceSets.toList(), + sourceSets = lazySourceSets.map { it.value }.toList(), pluginsClasspath = pluginsClasspath, pluginsConfiguration = pluginsConfigurations, modules = emptyList(), @@ -36,28 +44,29 @@ class TestDokkaConfigurationBuilder { ) fun sourceSets(block: SourceSetsBuilder.() -> Unit) { - sourceSets.addAll(SourceSetsBuilder().apply(block)) + lazySourceSets.addAll(SourceSetsBuilder(moduleName).apply(block)) } - fun add(sourceSet: DokkaSourceSetImpl) { - sourceSets.add(sourceSet) + fun sourceSet(block: DokkaSourceSetBuilder.() -> Unit): Lazy { + val lazySourceSet = lazy { DokkaSourceSetBuilder(moduleName).apply(block).build() } + lazySourceSets.add(lazySourceSet) + return lazySourceSet } -} -@DokkaConfigurationDsl -class SourceSetsBuilder : ArrayList() { - fun sourceSet(block: DokkaSourceSetBuilder.() -> Unit): DokkaConfiguration.DokkaSourceSet = - DokkaSourceSetBuilder().apply(block).build().apply(::add) + fun unattachedSourceSet(block: DokkaSourceSetBuilder.() -> Unit): DokkaSourceSetImpl { + return DokkaSourceSetBuilder(moduleName).apply(block).build() + } } -fun sourceSet(block: DokkaSourceSetBuilder.() -> Unit): DokkaSourceSetImpl { - return DokkaSourceSetBuilder().apply(block).build() +@DokkaConfigurationDsl +class SourceSetsBuilder(val moduleName: String) : ArrayList>() { + fun sourceSet(block: DokkaSourceSetBuilder.() -> Unit): Lazy = + lazy { DokkaSourceSetBuilder(moduleName).apply(block).build() }.apply(::add) } @DokkaConfigurationDsl class DokkaSourceSetBuilder( - var moduleName: String = "root", - var moduleDisplayName: String? = null, + private val moduleName: String, var name: String = "main", var displayName: String = "JVM", var classpath: List = emptyList(), @@ -81,7 +90,6 @@ class DokkaSourceSetBuilder( var sourceLinks: List = emptyList() ) { fun build() = DokkaSourceSetImpl( - moduleDisplayName = moduleDisplayName ?: moduleName, displayName = displayName, sourceSetID = DokkaSourceSetID(moduleName, name), classpath = classpath.map(::File), @@ -107,7 +115,6 @@ class DokkaSourceSetBuilder( } val defaultSourceSet = DokkaSourceSetImpl( - moduleDisplayName = "DEFAULT", displayName = "DEFAULT", sourceSetID = DokkaSourceSetID("DEFAULT", "DEFAULT"), classpath = emptyList(), diff --git a/integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt b/integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt index 6510c0440f..aabc30c18f 100644 --- a/integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt +++ b/integration-tests/cli/src/integrationTest/kotlin/org/jetbrains/dokka/it/cli/CliIntegrationTest.kt @@ -34,10 +34,9 @@ class CliIntegrationTest : AbstractCliIntegrationTest() { "java", "-jar", cliJarFile.path, "-outputDir", dokkaOutputDir.path, "-pluginsClasspath", basePluginJarFile.path, + "-moduleName", "Basic Project", "-sourceSet", buildString { - append(" -moduleName it-cli") - append(" -moduleDisplayName CLI-Example") append(" -sourceSetName cliMain") append(" -src ${File(projectDir, "src").path}") append(" -jdkVersion 8") diff --git a/integration-tests/gradle/projects/it-basic/build.gradle.kts b/integration-tests/gradle/projects/it-basic/build.gradle.kts index 2118756125..2769677f5b 100644 --- a/integration-tests/gradle/projects/it-basic/build.gradle.kts +++ b/integration-tests/gradle/projects/it-basic/build.gradle.kts @@ -15,9 +15,9 @@ dependencies { } tasks.withType { + moduleName.set("Basic Project") dokkaSourceSets { configureEach { - moduleDisplayName.set("Basic Project") suppressedFiles.from(file("src/main/kotlin/it/suppressedByPath")) perPackageOption { prefix.set("it.suppressedByPackage") diff --git a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt index 1265d675a2..f3bcfd59df 100644 --- a/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt +++ b/integration-tests/gradle/src/integrationTest/kotlin/org/jetbrains/dokka/it/gradle/BasicGradleIntegrationTest.kt @@ -84,7 +84,7 @@ class BasicGradleIntegrationTest(override val versions: BuildVersions) : Abstrac assertTrue( allHtmlFiles().any { file -> "Basic Project" in file.readText() }, - "Expected configured moduleDisplayName to be present in html" + "Expected configured moduleName to be present in html" ) assertTrue( diff --git a/integration-tests/maven/projects/it-maven/pom.xml b/integration-tests/maven/projects/it-maven/pom.xml index 350701f96b..80620c8214 100644 --- a/integration-tests/maven/projects/it-maven/pom.xml +++ b/integration-tests/maven/projects/it-maven/pom.xml @@ -91,7 +91,7 @@ false - Maven Integration Test Module + Maven Integration Test Module ${project.basedir}/output diff --git a/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt b/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt index d1832cbc7a..a87d4319b4 100644 --- a/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt +++ b/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt @@ -16,7 +16,6 @@ import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.transformers.pages.PageCreator import org.jetbrains.dokka.utilities.DokkaLogger -import java.io.File class MultimodulePageCreator( val context: DokkaContext diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt index 6155af5273..e66b76127f 100644 --- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt +++ b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt @@ -37,9 +37,9 @@ private fun parseModuleAndPackageDocFragment( } val name = classifierAndName.getOrNull(1)?.trim().orEmpty() - if (name.contains(Regex("\\s"))) { + if (classifier == Package && name.contains(Regex("\\s"))) { throw IllegalModuleAndPackageDocumentation( - source, "Module/Package name cannot contain whitespace in '$firstLine'" + source, "Package name cannot contain whitespace in '$firstLine'" ) } diff --git a/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt index c8e4f565b1..17ead66746 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt @@ -10,20 +10,15 @@ internal object DefaultDocumentableMerger : DocumentableMerger { override fun invoke(modules: Collection, context: DokkaContext): DModule { - val projectName = - modules.fold(modules.first().name) { acc, module -> acc.commonPrefixWith(module.name) } - .takeIf { it.isNotEmpty() } - ?: "project" - return modules.reduce { left, right -> val list = listOf(left, right) DModule( - name = projectName, + name = modules.map { it.name }.distinct().joinToString("|"), packages = merge( list.flatMap { it.packages }, DPackage::mergeWith ), - documentation = list.map { it.documentation }.flatMap { it.entries }.associate { (k,v) -> k to v }, + documentation = list.map { it.documentation }.flatMap { it.entries }.associate { (k, v) -> k to v }, expectPresentInSet = list.firstNotNullResult { it.expectPresentInSet }, sourceSets = list.flatMap { it.sourceSets }.toSet() ).mergeExtras(left, right) @@ -61,7 +56,7 @@ fun DFunction.mergeWith(other: DFunction): DFunction = copy( receiver = receiver?.let { r -> other.receiver?.let { r.mergeWith(it) } ?: r } ?: other.receiver, documentation = documentation + other.documentation, expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet, - sources = sources+ other.sources, + sources = sources + other.sources, visibility = visibility + other.visibility, modifier = modifier + other.modifier, sourceSets = sourceSets + other.sourceSets, @@ -72,7 +67,7 @@ fun DProperty.mergeWith(other: DProperty): DProperty = copy( receiver = receiver?.let { r -> other.receiver?.let { r.mergeWith(it) } ?: r } ?: other.receiver, documentation = documentation + other.documentation, expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet, - sources = sources+ other.sources, + sources = sources + other.sources, visibility = visibility + other.visibility, modifier = modifier + other.modifier, sourceSets = sourceSets + other.sourceSets, @@ -104,7 +99,7 @@ fun DClass.mergeWith(other: DClass): DClass = copy( supertypes = supertypes + other.supertypes, documentation = documentation + other.documentation, expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet, - sources = sources+ other.sources, + sources = sources + other.sources, visibility = visibility + other.visibility, sourceSets = sourceSets + other.sourceSets ).mergeExtras(this, other) @@ -122,7 +117,7 @@ fun DEnum.mergeWith(other: DEnum): DEnum = copy( supertypes = supertypes + other.supertypes, documentation = documentation + other.documentation, expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet, - sources = sources+ other.sources, + sources = sources + other.sources, visibility = visibility + other.visibility, sourceSets = sourceSets + other.sourceSets ).mergeExtras(this, other) @@ -143,7 +138,7 @@ fun DObject.mergeWith(other: DObject): DObject = copy( supertypes = supertypes + other.supertypes, documentation = documentation + other.documentation, expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet, - sources = sources+ other.sources, + sources = sources + other.sources, visibility = visibility + other.visibility, sourceSets = sourceSets + other.sourceSets ).mergeExtras(this, other) @@ -157,7 +152,7 @@ fun DInterface.mergeWith(other: DInterface): DInterface = copy( supertypes = supertypes + other.supertypes, documentation = documentation + other.documentation, expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet, - sources = sources+ other.sources, + sources = sources + other.sources, visibility = visibility + other.visibility, sourceSets = sourceSets + other.sourceSets ).mergeExtras(this, other) @@ -173,7 +168,7 @@ fun DAnnotation.mergeWith(other: DAnnotation): DAnnotation = copy( companion = companion?.let { c -> other.companion?.let { c.mergeWith(it) } ?: c } ?: other.companion, documentation = documentation + other.documentation, expectPresentInSet = expectPresentInSet ?: other.expectPresentInSet, - sources = sources+ other.sources, + sources = sources + other.sources, visibility = visibility + other.visibility, sourceSets = sourceSets + other.sourceSets, generics = merge(generics + other.generics, DTypeParameter::mergeWith) @@ -197,4 +192,4 @@ fun DTypeAlias.mergeWith(other: DTypeAlias): DTypeAlias = copy( underlyingType = underlyingType + other.underlyingType, visibility = visibility + other.visibility, sourceSets = sourceSets + other.sourceSets -).mergeExtras(this, other) \ No newline at end of file +).mergeExtras(this, other) diff --git a/plugins/base/src/main/kotlin/transformers/documentables/DeprecatedDocumentableFilterTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/DeprecatedDocumentableFilterTransformer.kt index 66156832ef..6a6231c5c2 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/DeprecatedDocumentableFilterTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/DeprecatedDocumentableFilterTransformer.kt @@ -249,4 +249,4 @@ class DeprecatedDocumentableFilterTransformer(val context: DokkaContext) : PreMe } } } -} \ No newline at end of file +} diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt index e712d6e5cb..e126d05f8e 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt @@ -65,11 +65,7 @@ private class ContextModuleAndPackageDocumentationReader( override fun get(module: DModule): SourceSetDependent { return findDocumentationNodes(module.sourceSets) { fragment -> - fragment.classifier == Classifier.Module && ( - /* Match fragment name against module name or distinct module displayName */ - fragment.name == module.name || - fragment.name == module.sourceSets.map { it.moduleDisplayName }.distinct().singleOrNull() - ) + fragment.classifier == Classifier.Module && (fragment.name == module.name) } } diff --git a/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt b/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt index 2099cab5f5..ca239d8393 100644 --- a/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt @@ -62,12 +62,12 @@ abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer { private fun ContentNode.addSample( contentPage: ContentPage, - platform: DokkaSourceSet, + sourceSet: DokkaSourceSet, fqName: String, analysis: Map ): ContentNode { - val facade = analysis[platform]?.facade - ?: return this.also { context.logger.warn("Cannot resolve facade for platform ${platform.moduleDisplayName}") } + val facade = analysis[sourceSet]?.facade + ?: return this.also { context.logger.warn("Cannot resolve facade for platform ${sourceSet.sourceSetID}") } val psiElement = fqNameToPsiElement(facade, fqName) ?: return this.also { context.logger.warn("Cannot find PsiElement corresponding to $fqName") } val imports = diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index 18b05df45d..8e5a1927a3 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -70,7 +70,15 @@ class DefaultDescriptorToDocumentableTranslator( DRIWithPlatformInfo(DRI.topLevel, emptyMap()) ) } - }.let { DModule(sourceSet.moduleDisplayName, it, emptyMap(), null, setOf(sourceSet)) } + }.let { + DModule( + name = context.configuration.moduleName, + packages = it, + documentation = emptyMap(), + expectPresentInSet = null, + sourceSets = setOf(sourceSet) + ) + } } } @@ -557,7 +565,9 @@ private class DokkaDescriptorVisitor( private fun ClassDescriptor.resolveClassDescriptionData(): ClassInfo { fun toTypeConstructor(kt: KotlinType) = - TypeConstructor(DRI.from(kt.constructor.declarationDescriptor as DeclarationDescriptor), kt.arguments.map { it.toProjection() }) + TypeConstructor( + DRI.from(kt.constructor.declarationDescriptor as DeclarationDescriptor), + kt.arguments.map { it.toProjection() }) tailrec fun buildAncestryInformation( supertypes: Collection, @@ -753,13 +763,22 @@ private class DokkaDescriptorVisitor( private fun ValueArgument.childrenAsText() = this.safeAs()?.children?.map { it.text }.orEmpty() - private data class AncestryLevel(val level: Int, val superclass: TypeConstructor?, val interfaces: List) + private data class AncestryLevel( + val level: Int, + val superclass: TypeConstructor?, + val interfaces: List + ) - private data class ClassInfo(val ancestry: List, val docs: SourceSetDependent){ + private data class ClassInfo(val ancestry: List, val docs: SourceSetDependent) { val supertypes: List get() = ancestry.firstOrNull { it.level == 0 }?.let { - listOfNotNull(it.superclass?.let { TypeConstructorWithKind(it, KotlinClassKindTypes.CLASS) }) + it.interfaces.map { TypeConstructorWithKind(it, KotlinClassKindTypes.INTERFACE) } - }.orEmpty() + listOfNotNull(it.superclass?.let { + TypeConstructorWithKind( + it, + KotlinClassKindTypes.CLASS + ) + }) + it.interfaces.map { TypeConstructorWithKind(it, KotlinClassKindTypes.INTERFACE) } + }.orEmpty() val allImplementedInterfaces: List get() = ancestry.flatMap { it.interfaces }.distinct() diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index c1ed4a082e..30e46404b3 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -68,7 +68,7 @@ class DefaultPsiToDocumentableTranslator( context.logger ) return DModule( - sourceSet.moduleDisplayName, + context.configuration.moduleName, psiFiles.mapNotNull { it.safeAs() }.groupBy { it.packageName }.map { (packageName, psiFiles) -> val dri = DRI(packageName = packageName) DPackage( diff --git a/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt b/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt index 952780c73c..25400ca54b 100644 --- a/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt +++ b/plugins/base/src/test/kotlin/linkableContent/LinkableContentTest.kt @@ -26,9 +26,9 @@ class LinkableContentTest : AbstractCoreTest() { val includesDir = getTestDataDir("linkable/includes").toAbsolutePath() val configuration = dokkaConfiguration { + moduleName = "example" sourceSets { sourceSet { - moduleName = "example" analysisPlatform = "js" sourceRoots = listOf("jsMain", "commonMain", "jvmAndJsSecondCommonMain").map { Paths.get("$testDataDir/$it/kotlin").toString() @@ -37,7 +37,6 @@ class LinkableContentTest : AbstractCoreTest() { includes = listOf(Paths.get("$includesDir/include2.md").toString()) } sourceSet { - moduleName = "example" analysisPlatform = "jvm" sourceRoots = listOf("jvmMain", "commonMain", "jvmAndJsSecondCommonMain").map { Paths.get("$testDataDir/$it/kotlin").toString() @@ -65,9 +64,10 @@ class LinkableContentTest : AbstractCoreTest() { val testDataDir = getTestDataDir("linkable/sources").toAbsolutePath() val configuration = dokkaConfiguration { + moduleName = "example" + sourceSets { sourceSet { - moduleName = "example" analysisPlatform = "js" sourceRoots = listOf("$testDataDir/jsMain/kotlin") sourceLinks = listOf( @@ -80,7 +80,6 @@ class LinkableContentTest : AbstractCoreTest() { name = "js" } sourceSet { - moduleName = "example" analysisPlatform = "jvm" sourceRoots = listOf("$testDataDir/jvmMain/kotlin") sourceLinks = listOf( @@ -130,16 +129,15 @@ class LinkableContentTest : AbstractCoreTest() { val testDataDir = getTestDataDir("linkable/samples").toAbsolutePath() val configuration = dokkaConfiguration { + moduleName = "example" sourceSets { sourceSet { - moduleName = "example" analysisPlatform = "js" sourceRoots = listOf("$testDataDir/jsMain/kotlin") name = "js" samples = listOf("$testDataDir/jsMain/resources/Samples.kt") } sourceSet { - moduleName = "example" analysisPlatform = "jvm" sourceRoots = listOf("$testDataDir/jvmMain/kotlin") name = "jvm" diff --git a/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt b/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt index 17f9631ac6..a2c2f97d34 100644 --- a/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt +++ b/plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt @@ -98,20 +98,29 @@ class ParseModuleAndPackageDocumentationFragmentsTest { } @Test - fun `white space in module name fails`() { - val exception = assertThrows { - parseModuleAndPackageDocumentationFragments( - source( - """ - # Module My Module - """.trimIndent() - ) + fun `white space in module name is supported`() { + val fragment = parseModuleAndPackageDocumentationFragments( + source( + """ + # Module My Module + Documentation for my module + """.trimIndent() ) - } + ) - assertTrue( - "Module My Module" in exception.message.orEmpty(), - "Expected problematic statement in error message" + assertEquals( + Module, fragment.single().classifier, + "Expected module being parsec" + ) + + assertEquals( + "My Module", fragment.single().name, + "Expected module name with white spaces being parsed" + ) + + assertEquals( + "Documentation for my module", fragment.single().documentation, + "Expected documentation being available" ) } diff --git a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt index 4f55695d27..8426923dff 100644 --- a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt +++ b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt @@ -21,14 +21,12 @@ import java.io.File abstract class HtmlRenderingOnlyTestBase : RenderingOnlyTestBase() { protected val js = defaultSourceSet.copy( - "root", "JS", defaultSourceSet.sourceSetID.copy(sourceSetName = "js"), analysisPlatform = Platform.js, sourceRoots = setOf(File("pl1")) ) protected val jvm = defaultSourceSet.copy( - "root", "JVM", defaultSourceSet.sourceSetID.copy(sourceSetName = "jvm"), @@ -36,7 +34,6 @@ abstract class HtmlRenderingOnlyTestBase : RenderingOnlyTestBase() { sourceRoots = setOf(File("pl1")) ) protected val native = defaultSourceSet.copy( - "root", "NATIVE", defaultSourceSet.sourceSetID.copy(sourceSetName = "native"), analysisPlatform = Platform.native, diff --git a/plugins/base/src/test/kotlin/renderers/html/SourceSetDependentHintTest.kt b/plugins/base/src/test/kotlin/renderers/html/SourceSetDependentHintTest.kt index 77ba390e35..4fd349e454 100644 --- a/plugins/base/src/test/kotlin/renderers/html/SourceSetDependentHintTest.kt +++ b/plugins/base/src/test/kotlin/renderers/html/SourceSetDependentHintTest.kt @@ -14,21 +14,18 @@ import java.io.File class SourceSetDependentHintTest : HtmlRenderingOnlyTestBase() { private val pl1 = defaultSourceSet.copy( - "root", "pl1", defaultSourceSet.sourceSetID.copy(sourceSetName = "pl1"), analysisPlatform = Platform.js, sourceRoots = setOf(File("pl1")) ) private val pl2 = defaultSourceSet.copy( - "root", "pl2", defaultSourceSet.sourceSetID.copy(sourceSetName = "pl2"), analysisPlatform = Platform.jvm, sourceRoots = setOf(File("pl1")) ) private val pl3 = defaultSourceSet.copy( - "root", "pl3", defaultSourceSet.sourceSetID.copy(sourceSetName = "pl3"), analysisPlatform = Platform.native, diff --git a/plugins/base/src/test/kotlin/signatures/DivergentSignatureTest.kt b/plugins/base/src/test/kotlin/signatures/DivergentSignatureTest.kt index 7635ab0591..2e8e0ef3d7 100644 --- a/plugins/base/src/test/kotlin/signatures/DivergentSignatureTest.kt +++ b/plugins/base/src/test/kotlin/signatures/DivergentSignatureTest.kt @@ -16,9 +16,9 @@ class DivergentSignatureTest : AbstractCoreTest() { val testDataDir = getTestDataDir("multiplatform/basicMultiplatformTest").toAbsolutePath() val configuration = dokkaConfiguration { + moduleName = "example" sourceSets { sourceSet { - moduleName = "example" displayName = "js" name = "js" analysisPlatform = "js" @@ -27,7 +27,6 @@ class DivergentSignatureTest : AbstractCoreTest() { } } sourceSet { - moduleName = "example" displayName = "jvm" name = "jvm" analysisPlatform = "jvm" @@ -36,7 +35,6 @@ class DivergentSignatureTest : AbstractCoreTest() { } } sourceSet { - moduleName = "example" displayName = "common" name = "common" analysisPlatform = "common" @@ -68,9 +66,9 @@ class DivergentSignatureTest : AbstractCoreTest() { val testDataDir = getTestDataDir("multiplatform/basicMultiplatformTest").toAbsolutePath() val configuration = dokkaConfiguration { + moduleName = "example" sourceSets { sourceSet { - moduleName = "example" displayName = "js" name = "js" analysisPlatform = "js" @@ -79,7 +77,6 @@ class DivergentSignatureTest : AbstractCoreTest() { } } sourceSet { - moduleName = "example" displayName = "jvm" name = "jvm" analysisPlatform = "jvm" @@ -88,7 +85,6 @@ class DivergentSignatureTest : AbstractCoreTest() { } } sourceSet { - moduleName = "example" displayName = "common" name = "common" analysisPlatform = "common" @@ -120,9 +116,9 @@ class DivergentSignatureTest : AbstractCoreTest() { val testDataDir = getTestDataDir("multiplatform/basicMultiplatformTest").toAbsolutePath() val configuration = dokkaConfiguration { + moduleName = "example" sourceSets { sourceSet { - moduleName = "example" displayName = "js" name = "js" analysisPlatform = "js" @@ -131,7 +127,6 @@ class DivergentSignatureTest : AbstractCoreTest() { } } sourceSet { - moduleName = "example" displayName = "jvm" name = "jvm" analysisPlatform = "jvm" @@ -140,7 +135,6 @@ class DivergentSignatureTest : AbstractCoreTest() { } } sourceSet { - moduleName = "example" displayName = "common" name = "common" analysisPlatform = "common" @@ -172,4 +166,4 @@ class DivergentSignatureTest : AbstractCoreTest() { private val Element.brief: String get() = children().select(".brief-with-platform-tags").text() -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/signatures/SignatureTest.kt b/plugins/base/src/test/kotlin/signatures/SignatureTest.kt index 1c3842c4a6..5a4b614fe5 100644 --- a/plugins/base/src/test/kotlin/signatures/SignatureTest.kt +++ b/plugins/base/src/test/kotlin/signatures/SignatureTest.kt @@ -329,16 +329,15 @@ class SignatureTest : AbstractCoreTest() { fun `type with an actual typealias`() { val configuration = dokkaConfiguration { + moduleName = "test" sourceSets { sourceSet { - moduleName = "test" name = "common" sourceRoots = listOf("src/main/kotlin/common/Test.kt") classpath = listOf(commonStdlibPath!!) externalDocumentationLinks = listOf(stdlibExternalDocumentationLink) } sourceSet { - moduleName = "test" name = "jvm" dependentSourceSets = setOf(DokkaSourceSetID("test", "common")) sourceRoots = listOf("src/main/kotlin/jvm/Test.kt") diff --git a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt index e04e751cd5..51a5e85ab4 100644 --- a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt +++ b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt @@ -12,13 +12,11 @@ import org.jetbrains.dokka.utilities.DokkaConsoleLogger import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test -import testApi.testRunner.dokkaConfiguration -import testApi.testRunner.sourceSet +import testApi.testRunner.TestDokkaConfigurationBuilder class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAndPackageDocumentationReaderTest() { - private val includeSourceSetA by lazy { temporaryDirectory.resolve("includeA.md").toFile() } private val includeSourceSetB by lazy { temporaryDirectory.resolve("includeB.md").toFile() } @@ -51,40 +49,31 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd ) } - private val sourceSetA by lazy { - sourceSet { - moduleName = "moduleA" - name = "sourceSetA" - includes = listOf(includeSourceSetA.canonicalPath) - } + private val configurationBuilder = TestDokkaConfigurationBuilder().apply { + moduleName = "moduleA" } - private val sourceSetB by lazy { - sourceSet { - moduleName = "moduleB" - name = "sourceSetB" - includes = listOf(includeSourceSetB.canonicalPath) - } + private val sourceSetA by configurationBuilder.sourceSet { + name = "sourceSetA" + includes = listOf(includeSourceSetA.canonicalPath) } - private val sourceSetB2 by lazy { - sourceSet { - moduleName = "moduleB" - name = "sourceSetB2" - includes = emptyList() - } + + private val sourceSetB by configurationBuilder.sourceSet { + name = "sourceSetB" + includes = listOf(includeSourceSetB.canonicalPath) + } + + + private val sourceSetB2 by configurationBuilder.sourceSet { + name = "sourceSetB2" + includes = emptyList() } private val context by lazy { DokkaContext.create( - configuration = dokkaConfiguration { - sourceSets { - add(sourceSetA) - add(sourceSetB) - add(sourceSetB2) - } - }, + configuration = configurationBuilder.build(), logger = TestLogger(DokkaConsoleLogger), pluginOverrides = emptyList() ) @@ -121,7 +110,9 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert moduleA with unknown source set`() { - val documentation = reader[DModule("moduleA", sourceSets = setOf(sourceSet { name = "unknown" }))] + val documentation = reader[ + DModule("moduleA", sourceSets = setOf(configurationBuilder.unattachedSourceSet { name = "unknown" })) + ] assertEquals( emptyMap(), documentation, "Expected no documentation received for module with unknown sourceSet" diff --git a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest2.kt b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest2.kt deleted file mode 100644 index e209a170e4..0000000000 --- a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest2.kt +++ /dev/null @@ -1,63 +0,0 @@ -package transformers - -import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationReader -import org.jetbrains.dokka.model.DModule -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.utilities.DokkaConsoleLogger -import org.junit.jupiter.api.Assertions.* -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import testApi.testRunner.dokkaConfiguration -import testApi.testRunner.sourceSet - - -class ContextModuleAndPackageDocumentationReaderTest2: AbstractContextModuleAndPackageDocumentationReaderTest() { - - private val include by lazy { temporaryDirectory.resolve("include.md").toFile() } - - @BeforeEach - fun materializeInclude() { - include.writeText( - """ - # Module MyModuleDisplayName - Matching: moduleDisplayName - - # Module myModuleName - Matching: moduleName - """.trimIndent() - ) - } - - private val sourceSet by lazy { - sourceSet { - moduleName = "myModuleName" - moduleDisplayName = "MyModuleDisplayName" - includes = listOf(include.canonicalPath) - } - } - - private val context by lazy { - DokkaContext.create( - configuration = dokkaConfiguration { - sourceSets { - add(sourceSet) - } - }, - logger = DokkaConsoleLogger, - pluginOverrides = emptyList() - ) - } - - private val reader by lazy { ModuleAndPackageDocumentationReader(context) } - - - @Test - fun `module matches for moduleName and moduleDisplayName`() { - val documentation = reader[DModule("myModuleName", sourceSets = setOf(sourceSet))] - assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSet") - assertEquals(sourceSet, documentation.keys.single(), "Expected only one entry from sourceSet") - assertEquals( - listOf("Matching: moduleDisplayName", "Matching: moduleName"), documentation.texts - ) - } -} diff --git a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt index e1b9d199a9..a557379bfa 100644 --- a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt +++ b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt @@ -7,6 +7,7 @@ import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.utilities.DokkaConsoleLogger import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import testApi.testRunner.TestDokkaConfigurationBuilder import testApi.testRunner.dokkaConfiguration import testApi.testRunner.sourceSet import kotlin.test.assertEquals @@ -28,19 +29,15 @@ class ContextModuleAndPackageDocumentationReaderTest3 : AbstractContextModuleAnd ) } - private val sourceSet by lazy { - sourceSet { - includes = listOf(include.canonicalPath) - } + private val configurationBuilder = TestDokkaConfigurationBuilder() + + private val sourceSet by configurationBuilder.sourceSet { + includes = listOf(include.canonicalPath) } private val context by lazy { DokkaContext.create( - configuration = dokkaConfiguration { - sourceSets { - add(sourceSet) - } - }, + configuration = configurationBuilder.build(), logger = DokkaConsoleLogger, pluginOverrides = emptyList() ) diff --git a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerFunctionalTest.kt b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerFunctionalTest.kt index 2d356a8170..68e41ad1e8 100644 --- a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerFunctionalTest.kt +++ b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerFunctionalTest.kt @@ -35,9 +35,9 @@ class ModuleAndPackageDocumentationTransformerFunctionalTest : AbstractCoreTest( """.trimIndent() ) val configuration = dokkaConfiguration { + moduleName = "moduleA" sourceSets { sourceSet { - moduleName = "moduleA" name = "commonMain" displayName = "common" analysisPlatform = "common" @@ -45,7 +45,6 @@ class ModuleAndPackageDocumentationTransformerFunctionalTest : AbstractCoreTest( includes = listOf(include.canonicalPath) } sourceSet { - moduleName = "moduleA" name = "jsMain" displayName = "js" analysisPlatform = "js" @@ -54,7 +53,6 @@ class ModuleAndPackageDocumentationTransformerFunctionalTest : AbstractCoreTest( includes = listOf(include.canonicalPath) } sourceSet { - moduleName = "moduleA" name = "jvmMain" displayName = "jvm" analysisPlatform = "jvm" diff --git a/plugins/base/src/test/kotlin/transformers/ReportUndocumentedTransformerTest.kt b/plugins/base/src/test/kotlin/transformers/ReportUndocumentedTransformerTest.kt index 7294837206..265baa4276 100644 --- a/plugins/base/src/test/kotlin/transformers/ReportUndocumentedTransformerTest.kt +++ b/plugins/base/src/test/kotlin/transformers/ReportUndocumentedTransformerTest.kt @@ -484,7 +484,7 @@ class ReportUndocumentedTransformerTest : AbstractCoreTest() { fun `multiplatform undocumented class gets reported`() { val configuration = dokkaConfiguration { sourceSets { - val commonMain = sourceSet { + val commonMain by sourceSet { reportUndocumented = true analysisPlatform = Platform.common.toString() name = "commonMain" @@ -527,7 +527,7 @@ class ReportUndocumentedTransformerTest : AbstractCoreTest() { fun `multiplatform undocumented class does not get reported if expect is documented`() { val configuration = dokkaConfiguration { sourceSets { - val commonMain = sourceSet { + val commonMain by sourceSet { reportUndocumented = true analysisPlatform = Platform.common.toString() name = "commonMain" @@ -569,7 +569,7 @@ class ReportUndocumentedTransformerTest : AbstractCoreTest() { fun `multiplatform undocumented function gets reported`() { val configuration = dokkaConfiguration { sourceSets { - val commonMain = sourceSet { + val commonMain by sourceSet { reportUndocumented = true analysisPlatform = Platform.common.toString() name = "commonMain" diff --git a/plugins/gfm/src/test/kotlin/renderers/gfm/DivergentTest.kt b/plugins/gfm/src/test/kotlin/renderers/gfm/DivergentTest.kt index cd9b9dfcc7..dee43b1def 100644 --- a/plugins/gfm/src/test/kotlin/renderers/gfm/DivergentTest.kt +++ b/plugins/gfm/src/test/kotlin/renderers/gfm/DivergentTest.kt @@ -12,21 +12,18 @@ import java.io.File class DivergentTest : GfmRenderingOnlyTestBase() { private val js = defaultSourceSet.copy( - "root", "js", DokkaSourceSetID("root", "js"), analysisPlatform = Platform.js, sourceRoots = setOf(File("pl1")) ) private val jvm = defaultSourceSet.copy( - "root", "jvm", DokkaSourceSetID("root", "jvm"), analysisPlatform = Platform.jvm, sourceRoots = setOf(File("pl1")) ) private val native = defaultSourceSet.copy( - "root", "native", DokkaSourceSetID("root", "native"), analysisPlatform = Platform.native, diff --git a/plugins/gfm/src/test/kotlin/renderers/gfm/GfmRenderingOnlyTestBase.kt b/plugins/gfm/src/test/kotlin/renderers/gfm/GfmRenderingOnlyTestBase.kt index 35c2da3d65..a118a20e3e 100644 --- a/plugins/gfm/src/test/kotlin/renderers/gfm/GfmRenderingOnlyTestBase.kt +++ b/plugins/gfm/src/test/kotlin/renderers/gfm/GfmRenderingOnlyTestBase.kt @@ -21,7 +21,7 @@ abstract class GfmRenderingOnlyTestBase : RenderingOnlyTestBase() { DokkaBase().externalLocationProviderFactory to { ::DefaultExternalLocationProviderFactory }, GfmPlugin().gfmPreprocessors to { _ -> RootCreator }, - testConfiguration = DokkaConfigurationImpl() + testConfiguration = DokkaConfigurationImpl(moduleName = "root") ) override val renderedContent: String by lazy { diff --git a/plugins/gfm/src/test/kotlin/renderers/gfm/SourceSetDependentHintTest.kt b/plugins/gfm/src/test/kotlin/renderers/gfm/SourceSetDependentHintTest.kt index de473db0ba..93edd00119 100644 --- a/plugins/gfm/src/test/kotlin/renderers/gfm/SourceSetDependentHintTest.kt +++ b/plugins/gfm/src/test/kotlin/renderers/gfm/SourceSetDependentHintTest.kt @@ -12,21 +12,18 @@ import java.io.File class SourceSetDependentHintTest : GfmRenderingOnlyTestBase() { private val pl1 = defaultSourceSet.copy( - "root", "pl1", DokkaSourceSetID("root", "pl1"), analysisPlatform = Platform.js, sourceRoots = setOf(File("pl1")) ) private val pl2 = defaultSourceSet.copy( - "root", "pl2", DokkaSourceSetID("root", "pl2"), analysisPlatform = Platform.jvm, sourceRoots = setOf(File("pl1")) ) private val pl3 = defaultSourceSet.copy( - "root", "pl3", DokkaSourceSetID("root", "pl3"), analysisPlatform = Platform.native, diff --git a/runners/cli/src/main/kotlin/cli/main.kt b/runners/cli/src/main/kotlin/cli/main.kt index 069ef1665e..9f7755f6ae 100644 --- a/runners/cli/src/main/kotlin/cli/main.kt +++ b/runners/cli/src/main/kotlin/cli/main.kt @@ -2,13 +2,11 @@ package org.jetbrains.dokka import kotlinx.cli.* import org.jetbrains.dokka.DokkaConfiguration.ExternalDocumentationLink -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet.* import org.jetbrains.dokka.utilities.DokkaConsoleLogger import org.jetbrains.dokka.utilities.cast import java.io.* import java.net.MalformedURLException import java.net.URL -import java.nio.file.Files import java.nio.file.Paths class GlobalArguments(args: Array) : DokkaConfiguration { @@ -17,6 +15,14 @@ class GlobalArguments(args: Array) : DokkaConfiguration { val json: String? by parser.argument(ArgType.String, description = "Json file name").optional() + private val _moduleName = parser.option( + ArgType.String, + description = "Name of the documentation module", + fullName = "moduleName" + ).required() + + override val moduleName: String by _moduleName + override val outputDir by parser.option(ArgTypeFile, description = "Output directory path") .default(DokkaDefaults.outputDir) @@ -26,7 +32,7 @@ class GlobalArguments(args: Array) : DokkaConfiguration { ) override val sourceSets by parser.option( - ArgTypeArgument, + ArgTypeArgument(_moduleName), description = "Single dokka source set", fullName = "sourceSet" ).multiple() @@ -68,7 +74,7 @@ class GlobalArguments(args: Array) : DokkaConfiguration { ).delimiter(";") val helpSourceSet by parser.option( - ArgTypeHelpSourceSet, + ArgTypeHelpSourceSet(_moduleName), description = "Prints help for single -sourceSet" ) @@ -103,21 +109,10 @@ class GlobalArguments(args: Array) : DokkaConfiguration { } } -private fun parseSourceSet(args: Array): DokkaConfiguration.DokkaSourceSet { +private fun parseSourceSet(moduleName: String, args: Array): DokkaConfiguration.DokkaSourceSet { val parser = ArgParser("sourceSet", prefixStyle = ArgParser.OptionPrefixStyle.JVM) - val moduleName by parser.option( - ArgType.String, - description = "Name of the documentation module", - fullName = "moduleName" - ).required() - - val moduleDisplayName by parser.option( - ArgType.String, - description = "Name of the documentation module" - ) - val sourceSetName by parser.option( ArgType.String, description = "Name of the source set" @@ -218,7 +213,6 @@ private fun parseSourceSet(args: Array): DokkaConfiguration.DokkaSourceS parser.parse(args) return object : DokkaConfiguration.DokkaSourceSet { - override val moduleDisplayName = moduleDisplayName ?: moduleName override val displayName = displayName override val sourceSetID = DokkaSourceSetID(moduleName, sourceSetName) override val classpath = classpath.toMutableList() @@ -281,17 +275,20 @@ object ArgTypeSourceLinkDefinition : ArgType(true) { +data class ArgTypeArgument(val moduleName: CLIEntity) : + ArgType(true) { override fun convert(value: kotlin.String, name: kotlin.String): DokkaConfiguration.DokkaSourceSet = - parseSourceSet(value.split(" ").filter { it.isNotBlank() }.toTypedArray()) + parseSourceSet(moduleName.value, value.split(" ").filter { it.isNotBlank() }.toTypedArray()) override val description: kotlin.String get() = "" } // Workaround for printing nested parsers help -object ArgTypeHelpSourceSet : ArgType(false) { - override fun convert(value: kotlin.String, name: kotlin.String): Any = Any().also { parseSourceSet(arrayOf("-h")) } +data class ArgTypeHelpSourceSet(val moduleName: CLIEntity) : ArgType(false) { + override fun convert(value: kotlin.String, name: kotlin.String): Any = Any().also { + parseSourceSet(moduleName.value, arrayOf("-h")) + } override val description: kotlin.String get() = "" diff --git a/runners/gradle-plugin/MIGRATION.md b/runners/gradle-plugin/MIGRATION.md index 555ce66ea6..527c3e66ab 100644 --- a/runners/gradle-plugin/MIGRATION.md +++ b/runners/gradle-plugin/MIGRATION.md @@ -68,7 +68,7 @@ tasks.dokkaHtml.configure { #### Properties ```kotlin /* 0.10.x */ moduleName = "myModule" -/* 1.4.x */ moduleDisplayName.set("myModule") +/* 1.4.x */ /* Use AbstractDokkaTask#moduleName instead */ /* 0.10.x */ includeNonPublic = false /* 1.4.x */ includeNonPublic.set(false) diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt index 89308e2a4f..b480012455 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/AbstractDokkaTask.kt @@ -24,6 +24,10 @@ abstract class AbstractDokkaTask( private val bootstrapClass: KClass = DokkaBootstrap::class ) : DefaultTask() { + @Input + val moduleName: Property = project.objects.safeProperty() + .safeConvention(project.name) + @OutputDirectory val outputDirectory: Property = project.objects.safeProperty() .safeConvention(defaultDokkaOutputDirectory()) diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt index 532e9e842d..cd53398a72 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTask.kt @@ -11,6 +11,7 @@ abstract class DokkaCollectorTask : AbstractDokkaParentTask() { override fun buildDokkaConfiguration(): DokkaConfigurationImpl { val initialDokkaConfiguration = DokkaConfigurationImpl( + moduleName = moduleName.getSafe(), outputDir = outputDirectory.getSafe(), cacheRoot = cacheRoot.getSafe(), failOnWarning = failOnWarning.getSafe(), diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt index 2e7b749071..82e2148f2b 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt @@ -3,6 +3,8 @@ package org.jetbrains.dokka.gradle import org.gradle.api.internal.tasks.TaskDependencyInternal import org.gradle.api.provider.Property import org.gradle.api.tasks.* +import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.DokkaConfigurationImpl import org.jetbrains.dokka.DokkaModuleDescriptionImpl import org.jetbrains.dokka.DokkaMultimoduleBootstrapImpl @@ -51,6 +53,7 @@ abstract class DokkaMultiModuleTask : AbstractDokkaParentTask(DokkaMultimoduleBo } override fun buildDokkaConfiguration(): DokkaConfigurationImpl = DokkaConfigurationImpl( + moduleName = moduleName.getSafe(), outputDir = outputDirectory.getSafe(), cacheRoot = cacheRoot.getSafe(), pluginsConfiguration = pluginsConfiguration.getSafe(), @@ -67,4 +70,3 @@ abstract class DokkaMultiModuleTask : AbstractDokkaParentTask(DokkaMultimoduleBo ) } - diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt index d07873d8e5..beec3a7eb1 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaTask.kt @@ -12,7 +12,7 @@ abstract class DokkaTask : AbstractDokkaTask(DokkaBootstrapImpl::class) { @get:Internal val dokkaSourceSets: NamedDomainObjectContainer = - project.container(GradleDokkaSourceSetBuilder::class.java, GradleDokkaSourceSetBuilderFactory()) + project.container(GradleDokkaSourceSetBuilder::class.java, gradleDokkaSourceSetBuilderFactory()) .also { container -> DslObject(this).extensions.add("dokkaSourceSets", container) project.kotlinOrNull?.sourceSets?.all { kotlinSourceSet -> @@ -36,6 +36,7 @@ abstract class DokkaTask : AbstractDokkaTask(DokkaBootstrapImpl::class) { override fun buildDokkaConfiguration(): DokkaConfigurationImpl { return DokkaConfigurationImpl( + moduleName = moduleName.getSafe(), outputDir = outputDirectory.getSafe(), cacheRoot = cacheRoot.getSafe(), offlineMode = offlineMode.getSafe(), diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt index bb44eb522c..d3a6c587ad 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt @@ -1,12 +1,10 @@ @file:Suppress("FunctionName", "UnstableApiUsage") +@file:JvmName("GradleDokkaSourceSetBuilderKt") package org.jetbrains.dokka.gradle -import com.android.build.gradle.api.AndroidSourceSet import groovy.lang.Closure -import org.gradle.api.Action -import org.gradle.api.Project -import org.gradle.api.Task +import org.gradle.api.* import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property @@ -16,21 +14,17 @@ import org.gradle.kotlin.dsl.listProperty import org.gradle.kotlin.dsl.setProperty import org.gradle.util.ConfigureUtil import org.jetbrains.dokka.* -import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import java.io.File import java.net.URL -internal fun Task.GradleDokkaSourceSetBuilderFactory(): (name: String) -> GradleDokkaSourceSetBuilder = - { name -> GradleDokkaSourceSetBuilder(name, project) } - - -open class GradleDokkaSourceSetBuilder constructor( +open class GradleDokkaSourceSetBuilder( @Transient @get:Input val name: String, - @Transient @get:Internal internal val project: Project + @Transient @get:Internal internal val project: Project, + @Transient @get:Internal internal val sourceSetIdFactory: NamedDomainObjectFactory, ) : DokkaConfigurationBuilder { - @Internal - val sourceSetID: DokkaSourceSetID = DokkaSourceSetID(project, name) + @Input + val sourceSetID: DokkaSourceSetID = sourceSetIdFactory.create(name) @Input val suppress: Property = project.objects.safeProperty() @@ -40,10 +34,6 @@ open class GradleDokkaSourceSetBuilder constructor( @Optional val classpath: ConfigurableFileCollection = project.files() - @Input - @Optional - val moduleDisplayName: Property = project.objects.safeProperty() - @Input @Optional val displayName: Property = project.objects.safeProperty() @@ -125,9 +115,7 @@ open class GradleDokkaSourceSetBuilder constructor( val platform: Property = project.objects.safeProperty() .safeConvention(Platform.DEFAULT) - fun DokkaSourceSetID(sourceSetName: String): DokkaSourceSetID = - DokkaSourceSetID(project, sourceSetName) - + fun DokkaSourceSetID(sourceSetName: String): DokkaSourceSetID = sourceSetIdFactory.create(sourceSetName) fun dependsOn(sourceSet: SourceSet) { dependsOn(DokkaSourceSetID(sourceSet.name)) @@ -208,15 +196,3 @@ open class GradleDokkaSourceSetBuilder constructor( override fun build(): DokkaSourceSetImpl = toDokkaSourceSetImpl() } - -fun GradleDokkaSourceSetBuilder.dependsOn(sourceSet: KotlinSourceSet) { - dependsOn(DokkaSourceSetID(sourceSet.name)) -} - -fun GradleDokkaSourceSetBuilder.dependsOn(sourceSet: AndroidSourceSet) { - dependsOn(DokkaSourceSetID(sourceSet.name)) -} - -fun GradleDokkaSourceSetBuilder.kotlinSourceSet(kotlinSourceSet: KotlinSourceSet) { - configureWithKotlinSourceSet(kotlinSourceSet) -} diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderExtensions.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderExtensions.kt new file mode 100644 index 0000000000..c5c7428f28 --- /dev/null +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderExtensions.kt @@ -0,0 +1,17 @@ +package org.jetbrains.dokka.gradle + +import com.android.build.gradle.api.AndroidSourceSet +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet + +fun GradleDokkaSourceSetBuilder.dependsOn(sourceSet: KotlinSourceSet) { + dependsOn(DokkaSourceSetID(sourceSet.name)) +} + +fun GradleDokkaSourceSetBuilder.dependsOn(sourceSet: AndroidSourceSet) { + dependsOn(DokkaSourceSetID(sourceSet.name)) +} + +fun GradleDokkaSourceSetBuilder.kotlinSourceSet(kotlinSourceSet: KotlinSourceSet) { + configureWithKotlinSourceSet(kotlinSourceSet) +} + diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderFactory.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderFactory.kt new file mode 100644 index 0000000000..49c489c75e --- /dev/null +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderFactory.kt @@ -0,0 +1,9 @@ +package org.jetbrains.dokka.gradle + +import org.gradle.api.NamedDomainObjectFactory +import org.gradle.api.Task + +@Suppress("ObjectLiteralToLambda") // Will fail at runtime in Gradle versions <= 6.6 +fun AbstractDokkaTask.gradleDokkaSourceSetBuilderFactory(): NamedDomainObjectFactory = + NamedDomainObjectFactory { name -> GradleDokkaSourceSetBuilder(name, project, DokkaSourceSetIdFactory()) } + diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/dokkaSourceSetIDFactory.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/dokkaSourceSetIDFactory.kt index 3fadb4fd4e..41cc19e31f 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/dokkaSourceSetIDFactory.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/dokkaSourceSetIDFactory.kt @@ -2,9 +2,14 @@ package org.jetbrains.dokka.gradle -import org.gradle.api.Project +import org.gradle.api.NamedDomainObjectFactory +import org.gradle.api.Task import org.jetbrains.dokka.DokkaSourceSetID -internal fun DokkaSourceSetID(project: Project, sourceSetName: String): DokkaSourceSetID { - return DokkaSourceSetID(moduleName = project.path, sourceSetName = sourceSetName) +internal fun DokkaSourceSetID(task: Task, sourceSetName: String): DokkaSourceSetID { + return DokkaSourceSetID(task.path, sourceSetName) +} + +internal fun Task.DokkaSourceSetIdFactory() = NamedDomainObjectFactory { name -> + DokkaSourceSetID(this@DokkaSourceSetIdFactory, name) } diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/toDokkaSourceSetImpl.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/toDokkaSourceSetImpl.kt index 0f9d4053d6..2813d04eff 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/toDokkaSourceSetImpl.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/toDokkaSourceSetImpl.kt @@ -6,7 +6,6 @@ import java.io.File internal fun GradleDokkaSourceSetBuilder.toDokkaSourceSetImpl(): DokkaSourceSetImpl = DokkaSourceSetImpl( classpath = classpath.toList(), - moduleDisplayName = moduleNameOrDefault(), displayName = displayNameOrDefault(), sourceSetID = sourceSetID, sourceRoots = sourceRoots.toSet(), @@ -29,11 +28,6 @@ internal fun GradleDokkaSourceSetBuilder.toDokkaSourceSetImpl(): DokkaSourceSetI analysisPlatform = platform.getSafe() ) - -private fun GradleDokkaSourceSetBuilder.moduleNameOrDefault(): String { - return moduleDisplayName.getSafe() ?: project.name -} - private fun GradleDokkaSourceSetBuilder.displayNameOrDefault(): String { displayName.getSafe()?.let { return it } if (name.endsWith("Main") && name != "Main") { diff --git a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/ConfigureWithKotlinSourceSetGistTest.kt b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/ConfigureWithKotlinSourceSetGistTest.kt index efe03c5636..c06a3992ba 100644 --- a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/ConfigureWithKotlinSourceSetGistTest.kt +++ b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/ConfigureWithKotlinSourceSetGistTest.kt @@ -1,9 +1,7 @@ package org.jetbrains.dokka.gradle import org.gradle.api.artifacts.FileCollectionDependency -import org.gradle.api.file.ConfigurableFileCollection import org.gradle.kotlin.dsl.get -import org.gradle.kotlin.dsl.property import org.gradle.testfixtures.ProjectBuilder import org.jetbrains.dokka.Platform import org.jetbrains.dokka.gradle.kotlin.KotlinSourceSetGist diff --git a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTaskTest.kt b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTaskTest.kt index 04dd1eed8d..6e9bef38b6 100644 --- a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTaskTest.kt +++ b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaCollectorTaskTest.kt @@ -33,6 +33,7 @@ class DokkaCollectorTaskTest { val collectorTasks = rootProject.tasks.withType() collectorTasks.configureEach { task -> + task.moduleName by "custom Module Name" task.outputDirectory by File("customOutputDirectory") task.cacheRoot by File("customCacheRoot") task.failOnWarning by true @@ -45,6 +46,7 @@ class DokkaCollectorTaskTest { val dokkaConfiguration = task.buildDokkaConfiguration() assertEquals( DokkaConfigurationImpl( + moduleName = "custom Module Name", outputDir = File("customOutputDirectory"), cacheRoot = File("customCacheRoot"), failOnWarning = true, diff --git a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaConfigurationJsonTest.kt b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaConfigurationJsonTest.kt index 29532877ad..d1bfb0e11c 100644 --- a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaConfigurationJsonTest.kt +++ b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaConfigurationJsonTest.kt @@ -28,7 +28,6 @@ class DokkaConfigurationJsonTest { this.pluginsConfiguration.put("0", "a") this.pluginsConfiguration.put("1", "b") this.dokkaSourceSets.create("main") { sourceSet -> - sourceSet.moduleDisplayName by "moduleDisplayName" sourceSet.displayName by "customSourceSetDisplayName" sourceSet.reportUndocumented by true diff --git a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaConfigurationSerializableTest.kt b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaConfigurationSerializableTest.kt index f22a5b8c75..99fca12d8b 100644 --- a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaConfigurationSerializableTest.kt +++ b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaConfigurationSerializableTest.kt @@ -35,7 +35,6 @@ class DokkaConfigurationSerializableTest { this.pluginsConfiguration.put("0", "a") this.pluginsConfiguration.put("1", "b") this.dokkaSourceSets.create("main") { sourceSet -> - sourceSet.moduleDisplayName by "moduleDisplayName" sourceSet.displayName by "customSourceSetDisplayName" sourceSet.reportUndocumented by true diff --git a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTaskTest.kt b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTaskTest.kt index 62c867ba77..5b9413c8c3 100644 --- a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTaskTest.kt +++ b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTaskTest.kt @@ -58,6 +58,7 @@ class DokkaMultiModuleTaskTest { assertTrue(multimoduleTasks.isNotEmpty(), "Expected at least one multimodule task") multimoduleTasks.configureEach { task -> + task.moduleName by "custom Module Name" task.documentationFileName by "customDocumentationFileName.md" task.outputDirectory by task.project.buildDir.resolve("customOutputDirectory") task.cacheRoot by File("customCacheRoot") @@ -70,6 +71,7 @@ class DokkaMultiModuleTaskTest { val dokkaConfiguration = task.buildDokkaConfiguration() assertEquals( DokkaConfigurationImpl( + moduleName = "custom Module Name", outputDir = task.project.buildDir.resolve("customOutputDirectory"), cacheRoot = File("customCacheRoot"), pluginsConfiguration = mapOf("pluginA" to "configA"), diff --git a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt new file mode 100644 index 0000000000..c555985b2c --- /dev/null +++ b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt @@ -0,0 +1,11 @@ +@file:Suppress("TestFunctionName") + +package org.jetbrains.dokka.gradle + +import org.gradle.api.Project +import org.jetbrains.dokka.DokkaSourceSetID + +fun GradleDokkaSourceSetBuilder(name: String, project: Project, sourceSetScopeId: String = "${project.path}:test"): + GradleDokkaSourceSetBuilder { + return GradleDokkaSourceSetBuilder(name, project) { DokkaSourceSetID(sourceSetScopeId, it) } +} diff --git a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderTest.kt b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderTest.kt index c1053069bf..920c48b479 100644 --- a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderTest.kt +++ b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilderTest.kt @@ -1,6 +1,9 @@ +@file:Suppress("TestFunctionName") + package org.jetbrains.dokka.gradle import com.android.build.gradle.internal.api.DefaultAndroidSourceSet +import org.gradle.api.Project import org.gradle.kotlin.dsl.closureOf import org.gradle.testfixtures.ProjectBuilder import org.jetbrains.dokka.* @@ -15,14 +18,14 @@ class GradleDokkaSourceSetBuilderTest { @Test fun sourceSetId() { - val sourceSet = GradleDokkaSourceSetBuilder("myName", project) + val sourceSet = GradleDokkaSourceSetBuilder("myName", project, "scopeId") assertEquals( - DokkaSourceSetID(project, "myName"), sourceSet.sourceSetID, + DokkaSourceSetID("scopeId", "myName"), sourceSet.sourceSetID, "Expected sourceSet.sourceSetID to match output of DokkaSourceSetID factory function" ) assertEquals( - ":/myName", sourceSet.sourceSetID.toString(), + "scopeId/myName", sourceSet.sourceSetID.toString(), "Expected SourceSetId's string representation" ) } @@ -45,29 +48,6 @@ class GradleDokkaSourceSetBuilderTest { ) } - @Test - fun moduleDisplayName() { - val sourceSet = GradleDokkaSourceSetBuilder("myName", project) - - assertNull( - sourceSet.moduleDisplayName.getSafe(), - "Expected no ${GradleDokkaSourceSetBuilder::moduleDisplayName.name} being set by default" - ) - - assertEquals( - "root", sourceSet.build().moduleDisplayName, - "Expected project name being used for ${DokkaConfiguration.DokkaSourceSet::moduleDisplayName.name} " + - "after building source set with no ${GradleDokkaSourceSetBuilder::moduleDisplayName.name} being set" - ) - - sourceSet.moduleDisplayName by "displayName" - - assertEquals( - "displayName", sourceSet.build().moduleDisplayName, - "Expected previously set ${GradleDokkaSourceSetBuilder::displayName.name} to be present after build" - ) - } - @Test fun displayName() { val sourceSet = GradleDokkaSourceSetBuilder("myName", project) @@ -128,9 +108,9 @@ class GradleDokkaSourceSetBuilderTest { val sourceSet = GradleDokkaSourceSetBuilder("", project) assertEquals(emptySet(), sourceSet.build().dependentSourceSets, "Expected no dependent sourceSets by default") - sourceSet.dependentSourceSets.add(DokkaSourceSetID(project, "s1")) + sourceSet.dependentSourceSets.add(sourceSet.DokkaSourceSetID("s1")) sourceSet.dependsOn("s2") - sourceSet.dependsOn(DokkaSourceSetID(project, "s3")) + sourceSet.dependsOn(sourceSet.DokkaSourceSetID("s3")) sourceSet.dependsOn(GradleDokkaSourceSetBuilder("s4", project)) sourceSet.dependsOn(GradleDokkaSourceSetBuilder("s5", project).build()) sourceSet.dependsOn(DefaultKotlinSourceSet(project, "s6")) @@ -456,3 +436,6 @@ class GradleDokkaSourceSetBuilderTest { ) } } + +private fun GradleDokkaSourceSetBuilder(name: String, project: Project) = + GradleDokkaSourceSetBuilder(name, project, project.path) diff --git a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/KotlinDslDokkaTaskConfigurationTest.kt b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/KotlinDslDokkaTaskConfigurationTest.kt index 6a356b796d..9c788a0169 100644 --- a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/KotlinDslDokkaTaskConfigurationTest.kt +++ b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/KotlinDslDokkaTaskConfigurationTest.kt @@ -50,7 +50,7 @@ class KotlinDslDokkaTaskConfigurationTest { ) assertEquals( - DokkaSourceSetID(project.path, "commonMain"), commonMain.sourceSetID + DokkaSourceSetID(dokkaTask, "commonMain"), commonMain.sourceSetID ) } } @@ -83,14 +83,14 @@ class KotlinDslDokkaTaskConfigurationTest { val kotlin = project.extensions.getByName("kotlin") as KotlinJvmProjectExtension - project.tasks.withType(DokkaTask::class.java).first().run { + project.tasks.withType(DokkaTask::class.java).first().apply { dokkaSourceSets.run { val special = create("special") { it.dependsOn(kotlin.sourceSets.getByName("main")) } assertEquals( - DokkaSourceSetID(project, "main"), special.dependentSourceSets.get().single() + DokkaSourceSetID(this@apply, "main"), special.dependentSourceSets.get().single() ) } } diff --git a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt index b95b94c0cc..4e5e053ac7 100644 --- a/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt +++ b/runners/maven-plugin/src/main/kotlin/DokkaMojo.kt @@ -101,9 +101,6 @@ abstract class AbstractDokkaMojo(private val defaultDokkaPlugins: List Date: Fri, 28 Aug 2020 11:28:54 +0200 Subject: [PATCH 12/19] Re-use includes form child tasks for all modules page generation --- core/src/main/kotlin/configuration.kt | 12 +- core/src/main/kotlin/defaultConfiguration.kt | 4 +- .../TestDokkaConfigurationBuilder.kt | 1 - .../moduleA/moduleB/Module.md | 6 + .../moduleA/moduleB/README.md | 2 - .../moduleA/moduleB/build.gradle.kts | 9 ++ .../moduleA/moduleC/{README.md => Module.md} | 0 .../moduleA/moduleC/build.gradle.kts | 8 + .../moduleA/moduleD/build.gradle.kts | 10 ++ .../org/jetbrains/dokka/it/moduleD/ModuleC.kt | 6 + .../it-multimodule-0/settings.gradle.kts | 1 + .../allModulePage/MultimodulePageCreator.kt | 60 ++++---- .../local/MultimoduleLocationProvider.kt | 2 +- .../src/test/kotlin/model/PackagesTest.kt | 2 - .../dokka/gradle/DokkaMultiModuleTask.kt | 27 ++-- .../dokka/gradle/DokkaMultiModuleTaskTest.kt | 145 ++++++++++-------- 16 files changed, 178 insertions(+), 117 deletions(-) create mode 100644 integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/Module.md delete mode 100644 integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/README.md rename integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/{README.md => Module.md} (100%) create mode 100644 integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/build.gradle.kts create mode 100644 integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/src/main/kotlin/org/jetbrains/dokka/it/moduleD/ModuleC.kt diff --git a/core/src/main/kotlin/configuration.kt b/core/src/main/kotlin/configuration.kt index 9a1ff602d3..b53fd1eef3 100644 --- a/core/src/main/kotlin/configuration.kt +++ b/core/src/main/kotlin/configuration.kt @@ -61,6 +61,14 @@ fun Iterable>.build(): List = this.map data class DokkaSourceSetID( + /** + * Unique identifier of the scope that this source set is placed in. + * Each scope provide only unique source set names. + * + * E.g. One DokkaTask inside the Gradle plugin represents one source set scope, since there cannot be multiple + * source sets with the same name. However, a Gradle project will not be a proper scope, since there can be + * multple DokkaTasks that contain source sets with the same name (but different configuration) + */ val scopeId: String, val sourceSetName: String ) : Serializable { @@ -116,8 +124,8 @@ interface DokkaConfiguration : Serializable { interface DokkaModuleDescription : Serializable { val name: String - val path: File - val docFile: File + val relativePathToOutputDirectory: File + val includes: Set } interface PackageOptions : Serializable { diff --git a/core/src/main/kotlin/defaultConfiguration.kt b/core/src/main/kotlin/defaultConfiguration.kt index 3fcc7aacd1..5b32ebae1f 100644 --- a/core/src/main/kotlin/defaultConfiguration.kt +++ b/core/src/main/kotlin/defaultConfiguration.kt @@ -43,8 +43,8 @@ data class DokkaSourceSetImpl( data class DokkaModuleDescriptionImpl( override val name: String, - override val path: File, - override val docFile: File + override val relativePathToOutputDirectory: File, + override val includes: Set ) : DokkaConfiguration.DokkaModuleDescription data class SourceLinkDefinitionImpl( diff --git a/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt index f6cb99db4e..2d9f99b229 100644 --- a/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt +++ b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt @@ -138,7 +138,6 @@ val defaultSourceSet = DokkaSourceSetImpl( analysisPlatform = Platform.DEFAULT ) -// TODO NOW: Clean up fun sourceSet(name: String): DokkaConfiguration.DokkaSourceSet { return defaultSourceSet.copy( displayName = name, diff --git a/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/Module.md b/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/Module.md new file mode 100644 index 0000000000..0570f46749 --- /dev/null +++ b/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/Module.md @@ -0,0 +1,6 @@ +# Module !Module B! +Here is some description for Module B + +Module B: Second paragraph +# Module moduleB +§IGNORED$This documentation shall be ignored, because wrong module name§IGNORED$ diff --git a/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/README.md b/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/README.md deleted file mode 100644 index f8c52880a7..0000000000 --- a/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Module moduleB -Here is some description for module B diff --git a/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/build.gradle.kts b/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/build.gradle.kts index 9492fdc8ca..5f0b69c72d 100644 --- a/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/build.gradle.kts +++ b/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleB/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.dokka.gradle.DokkaTask + plugins { kotlin("jvm") id("org.jetbrains.dokka") @@ -6,3 +8,10 @@ plugins { dependencies { implementation(kotlin("stdlib")) } + +tasks.withType().configureEach { + moduleName.set("!Module B!") + dokkaSourceSets.configureEach { + includes.from("Module.md") + } +} diff --git a/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/README.md b/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/Module.md similarity index 100% rename from integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/README.md rename to integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/Module.md diff --git a/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/build.gradle.kts b/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/build.gradle.kts index 9492fdc8ca..e471d37504 100644 --- a/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/build.gradle.kts +++ b/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleC/build.gradle.kts @@ -1,3 +1,5 @@ +import org.jetbrains.dokka.gradle.DokkaTask + plugins { kotlin("jvm") id("org.jetbrains.dokka") @@ -6,3 +8,9 @@ plugins { dependencies { implementation(kotlin("stdlib")) } + +tasks.withType().configureEach { + dokkaSourceSets.configureEach { + includes.from("Module.md") + } +} diff --git a/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/build.gradle.kts b/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/build.gradle.kts new file mode 100644 index 0000000000..a16e038f2b --- /dev/null +++ b/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/build.gradle.kts @@ -0,0 +1,10 @@ +import org.jetbrains.dokka.gradle.DokkaTask + +plugins { + kotlin("jvm") + id("org.jetbrains.dokka") +} + +dependencies { + implementation(kotlin("stdlib")) +} diff --git a/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/src/main/kotlin/org/jetbrains/dokka/it/moduleD/ModuleC.kt b/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/src/main/kotlin/org/jetbrains/dokka/it/moduleD/ModuleC.kt new file mode 100644 index 0000000000..88174d5353 --- /dev/null +++ b/integration-tests/gradle/projects/it-multimodule-0/moduleA/moduleD/src/main/kotlin/org/jetbrains/dokka/it/moduleD/ModuleC.kt @@ -0,0 +1,6 @@ +package org.jetbrains.dokka.it.moduleD + +@Suppress("unused") +class ModuleD { + fun undocumentedPublicFunction() {} +} diff --git a/integration-tests/gradle/projects/it-multimodule-0/settings.gradle.kts b/integration-tests/gradle/projects/it-multimodule-0/settings.gradle.kts index a5c89291ae..dda6558f47 100644 --- a/integration-tests/gradle/projects/it-multimodule-0/settings.gradle.kts +++ b/integration-tests/gradle/projects/it-multimodule-0/settings.gradle.kts @@ -3,3 +3,4 @@ rootProject.name = "it-multimodule-0" include(":moduleA") include(":moduleA:moduleB") include(":moduleA:moduleC") +include(":moduleA:moduleD") diff --git a/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt b/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt index a87d4319b4..dab06343f9 100644 --- a/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt +++ b/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt @@ -1,9 +1,13 @@ package org.jetbrains.dokka.base.allModulePage -import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.DokkaConfiguration.DokkaModuleDescription import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.DokkaException import org.jetbrains.dokka.base.DokkaBase +import org.jetbrains.dokka.base.parsers.MarkdownParser +import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Module +import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentationParsingContext +import org.jetbrains.dokka.base.parsers.moduleAndPackage.parseModuleAndPackageDocumentation +import org.jetbrains.dokka.base.parsers.moduleAndPackage.parseModuleAndPackageDocumentationFragments import org.jetbrains.dokka.base.resolvers.local.MultimoduleLocationProvider.Companion.MULTIMODULE_PACKAGE_PLACEHOLDER import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder @@ -11,21 +15,19 @@ import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.model.doc.P import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.base.parsers.MarkdownParser import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.transformers.pages.PageCreator import org.jetbrains.dokka.utilities.DokkaLogger -class MultimodulePageCreator( - val context: DokkaContext +class MultimodulePageCreator ( + private val context: DokkaContext, ) : PageCreator { private val logger: DokkaLogger = context.logger override fun invoke(): RootPageNode { val parser = MarkdownParser(logger = logger) val modules = context.configuration.modules - modules.forEach(::throwOnMissingModuleDocFile) val commentsConverter = context.plugin(DokkaBase::class)?.querySingle { commentsToContentConverter } val signatureProvider = context.plugin(DokkaBase::class)?.querySingle { signatureProvider } @@ -41,20 +43,22 @@ class MultimodulePageCreator( ) { header(2, "All modules:") table(styles = setOf(MultimoduleTable)) { - modules.mapNotNull { module -> - val paragraph = module.docFile.readText().let { parser.parse(it).firstParagraph() } - paragraph?.let { - val dri = DRI(packageName = MULTIMODULE_PACKAGE_PLACEHOLDER, classNames = module.name) - val dci = DCI(setOf(dri), ContentKind.Comment) - val header = linkNode(module.name, dri) - val content = ContentGroup( - DocTagToContentConverter.buildContent(it, dci, emptySet()), - dci, - emptySet(), - emptySet() - ) - ContentGroup(listOf(header, content), dci, emptySet(), emptySet()) - } + modules.map { module -> + val displayedModuleDocumentation = getDisplayedModuleDocumentation(module) + val dri = DRI(packageName = MULTIMODULE_PACKAGE_PLACEHOLDER, classNames = module.name) + val dci = DCI(setOf(dri), ContentKind.Comment) + val header = + ContentHeader(listOf(linkNode(module.name, dri)), 2, dci, emptySet(), emptySet()) + val content = ContentGroup( + children = + if (displayedModuleDocumentation != null) + DocTagToContentConverter.buildContent(displayedModuleDocumentation, dci, emptySet()) + else emptyList(), + dci = dci, + sourceSets = emptySet(), + style = emptySet() + ) + ContentGroup(listOf(header, content), dci, emptySet(), emptySet()) } } } @@ -65,12 +69,16 @@ class MultimodulePageCreator( ) } - private fun throwOnMissingModuleDocFile(module: DokkaConfiguration.DokkaModuleDescription) { - if (!module.docFile.exists() || !module.docFile.isFile) { - throw DokkaException( - "Missing documentation file for module ${module.name}: ${module.docFile.absolutePath}" - ) - } + private fun getDisplayedModuleDocumentation(module: DokkaModuleDescription): P? { + val parsingContext = ModuleAndPackageDocumentationParsingContext(logger) + return module.includes + .flatMap { include -> parseModuleAndPackageDocumentationFragments(include) } + .map { fragment -> parseModuleAndPackageDocumentation(parsingContext, fragment) } + .firstOrNull { documentation -> documentation.classifier == Module && documentation.name == module.name } + ?.documentation?.children.orEmpty() + .flatMap { it.root.children } + .filterIsInstance

() + .firstOrNull() } private fun DocumentationNode.firstParagraph() = diff --git a/plugins/base/src/main/kotlin/resolvers/local/MultimoduleLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/local/MultimoduleLocationProvider.kt index 3e0122bf6a..b5891dbf09 100644 --- a/plugins/base/src/main/kotlin/resolvers/local/MultimoduleLocationProvider.kt +++ b/plugins/base/src/main/kotlin/resolvers/local/MultimoduleLocationProvider.kt @@ -12,7 +12,7 @@ class MultimoduleLocationProvider(private val root: RootPageNode, context: Dokka private val defaultLocationProvider = DokkaLocationProvider(root, context) val paths = context.configuration.modules.map { - it.name to it.path + it.name to it.relativePathToOutputDirectory }.toMap() override fun resolve(dri: DRI, sourceSets: Set, context: PageNode?) = diff --git a/plugins/base/src/test/kotlin/model/PackagesTest.kt b/plugins/base/src/test/kotlin/model/PackagesTest.kt index 1adf76268b..3deb95e990 100644 --- a/plugins/base/src/test/kotlin/model/PackagesTest.kt +++ b/plugins/base/src/test/kotlin/model/PackagesTest.kt @@ -117,8 +117,6 @@ class PackagesTest : AbstractModelTest("/src/main/kotlin/packages/Test.kt", "pac } } - // TODO NOW test displayName - // todo // @Test fun suppressAtPackageLevel() { // verifyModel( diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt index 82e2148f2b..92560c94e7 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTask.kt @@ -3,8 +3,6 @@ package org.jetbrains.dokka.gradle import org.gradle.api.internal.tasks.TaskDependencyInternal import org.gradle.api.provider.Property import org.gradle.api.tasks.* -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.DokkaConfigurationImpl import org.jetbrains.dokka.DokkaModuleDescriptionImpl import org.jetbrains.dokka.DokkaMultimoduleBootstrapImpl @@ -14,25 +12,14 @@ import java.io.File @Deprecated("Use 'DokkaMultimoduleTask' instead", ReplaceWith("DokkaMultimoduleTask")) typealias DokkaMultimoduleTask = DokkaMultiModuleTask +private typealias TaskPath = String abstract class DokkaMultiModuleTask : AbstractDokkaParentTask(DokkaMultimoduleBootstrapImpl::class) { - /** - * Name of the file containing all necessary module information. - * This file has to be placed inside the subproject root directory. - */ - @Internal - val documentationFileName: Property = project.objects.safeProperty() - .safeConvention("README.md") - @Internal val fileLayout: Property = project.objects.safeProperty() .safeConvention(DokkaMultiModuleFileLayout.CompactInParent) - @get:InputFiles - internal val childDocumentationFiles: Iterable - get() = childDokkaTasks.map { task -> task.project.projectDir.resolve(documentationFileName.getSafe()) } - @get:InputFiles internal val sourceChildOutputDirectories: Iterable get() = childDokkaTasks.map { task -> task.outputDirectory.getSafe() } @@ -41,6 +28,12 @@ abstract class DokkaMultiModuleTask : AbstractDokkaParentTask(DokkaMultimoduleBo internal val targetChildOutputDirectories: Iterable get() = childDokkaTasks.map { task -> targetChildOutputDirectory(task) } + @get:Input + internal val childDokkaTaskIncludes: Map> + get() = childDokkaTasks.filterIsInstance().associate { task -> + task.path to task.dokkaSourceSets.flatMap { it.includes }.toSet() + } + @Internal override fun getTaskDependencies(): TaskDependencyInternal = super.getTaskDependencies() + childDokkaTasks @@ -62,9 +55,9 @@ abstract class DokkaMultiModuleTask : AbstractDokkaParentTask(DokkaMultimoduleBo pluginsClasspath = plugins.resolve().toList(), modules = childDokkaTasks.map { dokkaTask -> DokkaModuleDescriptionImpl( - name = dokkaTask.project.name, - path = targetChildOutputDirectory(dokkaTask).relativeTo(outputDirectory.getSafe()), - docFile = dokkaTask.project.projectDir.resolve(documentationFileName.get()).absoluteFile + name = dokkaTask.moduleName.getSafe(), + relativePathToOutputDirectory = targetChildOutputDirectory(dokkaTask).relativeTo(outputDirectory.getSafe()), + includes = childDokkaTaskIncludes[dokkaTask.path].orEmpty() ) } ) diff --git a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTaskTest.kt b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTaskTest.kt index 5b9413c8c3..bea80f1efc 100644 --- a/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTaskTest.kt +++ b/runners/gradle-plugin/src/test/kotlin/org/jetbrains/dokka/gradle/DokkaMultiModuleTaskTest.kt @@ -2,8 +2,7 @@ package org.jetbrains.dokka.gradle -import org.gradle.kotlin.dsl.create -import org.gradle.kotlin.dsl.withType +import org.gradle.kotlin.dsl.* import org.gradle.testfixtures.ProjectBuilder import org.jetbrains.dokka.DokkaConfigurationImpl import org.jetbrains.dokka.DokkaException @@ -25,10 +24,14 @@ class DokkaMultiModuleTaskTest { .withProjectDir(rootProject.projectDir.resolve("child")) .withParent(rootProject).build() + private val childDokkaTask = childProject.tasks.create("childDokkaTask") + + private val multiModuleTask = rootProject.tasks.create("multiModuleTask").apply { + addChildTask(childDokkaTask) + } + init { rootProject.allprojects { project -> - project.plugins.apply("org.jetbrains.kotlin.jvm") - project.plugins.apply("org.jetbrains.dokka") project.tasks.withType().configureEach { task -> task.plugins.withDependencies { dependencies -> dependencies.clear() } } @@ -50,70 +53,66 @@ class DokkaMultiModuleTaskTest { @Test fun buildDokkaConfiguration() { - childProject.tasks.withType().configureEach { task -> - task.outputDirectory by task.project.buildDir.resolve("output") + val include1 = childDokkaTask.project.file("include1.md") + val include2 = childDokkaTask.project.file("include2.md") + + childDokkaTask.apply { + dokkaSourceSets.create("main") + dokkaSourceSets.create("test") + dokkaSourceSets.configureEach { + it.includes.from(include1, include2) + } } - val multimoduleTasks = rootProject.tasks.withType() - assertTrue(multimoduleTasks.isNotEmpty(), "Expected at least one multimodule task") - - multimoduleTasks.configureEach { task -> - task.moduleName by "custom Module Name" - task.documentationFileName by "customDocumentationFileName.md" - task.outputDirectory by task.project.buildDir.resolve("customOutputDirectory") - task.cacheRoot by File("customCacheRoot") - task.pluginsConfiguration.put("pluginA", "configA") - task.failOnWarning by true - task.offlineMode by true + multiModuleTask.apply { + moduleName by "custom Module Name" + outputDirectory by project.buildDir.resolve("customOutputDirectory") + cacheRoot by File("customCacheRoot") + pluginsConfiguration.put("pluginA", "configA") + failOnWarning by true + offlineMode by true } - multimoduleTasks.forEach { task -> - val dokkaConfiguration = task.buildDokkaConfiguration() - assertEquals( - DokkaConfigurationImpl( - moduleName = "custom Module Name", - outputDir = task.project.buildDir.resolve("customOutputDirectory"), - cacheRoot = File("customCacheRoot"), - pluginsConfiguration = mapOf("pluginA" to "configA"), - pluginsClasspath = emptyList(), - failOnWarning = true, - offlineMode = true, - modules = listOf( - DokkaModuleDescriptionImpl( - name = "child", - path = File("child"), - docFile = childProject.projectDir.resolve("customDocumentationFileName.md") - ) + val dokkaConfiguration = multiModuleTask.buildDokkaConfiguration() + assertEquals( + DokkaConfigurationImpl( + moduleName = "custom Module Name", + outputDir = multiModuleTask.project.buildDir.resolve("customOutputDirectory"), + cacheRoot = File("customCacheRoot"), + pluginsConfiguration = mapOf("pluginA" to "configA"), + pluginsClasspath = emptyList(), + failOnWarning = true, + offlineMode = true, + modules = listOf( + DokkaModuleDescriptionImpl( + name = "child", + relativePathToOutputDirectory = File("child"), + includes = setOf(include1, include2) ) - ), - dokkaConfiguration - ) - } + ) + ), + dokkaConfiguration + ) } @Test fun `setting dokkaTaskNames declares proper task dependencies`() { - val multimoduleTasks = rootProject.tasks.withType() - assertTrue(multimoduleTasks.isNotEmpty(), "Expected at least one multimodule task") + val dependenciesInitial = multiModuleTask.taskDependencies.getDependencies(multiModuleTask).toSet() + assertEquals(1, dependenciesInitial.size, "Expected one dependency") + val dependency = dependenciesInitial.single() - multimoduleTasks.toList().forEach { task -> - val dependencies = task.taskDependencies.getDependencies(task).toSet() - assertEquals(1, dependencies.size, "Expected one dependency") - val dependency = dependencies.single() + assertTrue(dependency is DokkaTask, "Expected dependency to be of Type ${DokkaTask::class.simpleName}") + assertEquals(childProject, dependency.project, "Expected dependency from child project") - assertTrue(dependency is DokkaTask, "Expected dependency to be of Type ${DokkaTask::class.simpleName}") - assertEquals(childProject, dependency.project, "Expected dependency from child project") - } val customDokkaTask = childProject.tasks.create("customDokkaTask") - multimoduleTasks.toList().forEach { task -> - task.addSubprojectChildTasks("customDokkaTask") - val dependencies = task.taskDependencies.getDependencies(task).toSet() + multiModuleTask.addSubprojectChildTasks("customDokkaTask") + val dependenciesAfter = multiModuleTask.taskDependencies.getDependencies(multiModuleTask).toSet() + + assertEquals(2, dependenciesAfter.size, "Expected two dependencies") + assertTrue(customDokkaTask in dependenciesAfter, "Expected 'customDokkaTask' in dependencies") - assertEquals(2, dependencies.size, "Expected two dependencies") - assertTrue(customDokkaTask in dependencies, "Expected 'customDokkaTask' in dependencies") - } } @Test @@ -125,19 +124,38 @@ class DokkaMultiModuleTaskTest { } @Test - fun childDocumentationFiles() { - val parent = ProjectBuilder.builder().build() - val child = ProjectBuilder.builder().withName("child").withParent(parent).build() - - val parentTask = parent.tasks.create("parent") - val childTask = child.tasks.create("child") + fun childDokkaTaskIncludes() { + val childDokkaTaskInclude1 = childProject.file("include1") + val childDokkaTaskInclude2 = childProject.file("include2") + val childDokkaTaskInclude3 = childProject.file("include3") + + childDokkaTask.apply { + dokkaSourceSets.create("main") { + it.includes.from(childDokkaTaskInclude1, childDokkaTaskInclude2) + } + dokkaSourceSets.create("main2") { + it.includes.from(childDokkaTaskInclude3) + } + } - parentTask.addChildTask(childTask) - parentTask.documentationFileName by "module.txt" + val secondChildDokkaTaskInclude = childProject.file("include4") + val secondChildDokkaTask = childProject.tasks.create("secondChildDokkaTask") { + dokkaSourceSets.create("main") { + it.includes.from(secondChildDokkaTaskInclude) + } + } + multiModuleTask.addChildTask(secondChildDokkaTask) assertEquals( - listOf(parent.file("child/module.txt")), parentTask.childDocumentationFiles, - "Expected child documentation file being present" + mapOf( + ":child:childDokkaTask" to setOf( + childDokkaTaskInclude1, + childDokkaTaskInclude2, + childDokkaTaskInclude3 + ), + ":child:secondChildDokkaTask" to setOf(secondChildDokkaTaskInclude) + ), + multiModuleTask.childDokkaTaskIncludes ) } @@ -177,6 +195,5 @@ class DokkaMultiModuleTaskTest { listOf(parent.project.buildDir.resolve("child")), parentTask.targetChildOutputDirectories, "Expected child target output directory being present" ) - } } From 0b93cfa0b4717053fc31e4b7eb204fa6563e9dc0 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Fri, 28 Aug 2020 11:52:21 +0200 Subject: [PATCH 13/19] Minor readability improvement in ModuleAndPackageDocumentationTransformer.kt --- core/src/main/kotlin/model/doc/TagWrapper.kt | 11 +++--- .../allModulePage/MultimodulePageCreator.kt | 34 +++++++++++++------ ...oduleAndPackageDocumentationTransformer.kt | 5 +-- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/core/src/main/kotlin/model/doc/TagWrapper.kt b/core/src/main/kotlin/model/doc/TagWrapper.kt index 095f3eaf60..d9b08f2c00 100644 --- a/core/src/main/kotlin/model/doc/TagWrapper.kt +++ b/core/src/main/kotlin/model/doc/TagWrapper.kt @@ -6,17 +6,18 @@ import org.jetbrains.dokka.model.WithChildren sealed class TagWrapper(val root: DocTag) : WithChildren { override val children: List - get() = root.children + get() = root.children override fun equals(other: Any?): Boolean = ( - other != null && - this::class == other::class && - this.root == (other as TagWrapper).root - ) + other != null && + this::class == other::class && + this.root == (other as TagWrapper).root + ) override fun hashCode(): Int = root.hashCode() } + sealed class NamedTagWrapper(root: DocTag, val name: String) : TagWrapper(root) { override fun equals(other: Any?): Boolean = super.equals(other) && this.name == (other as NamedTagWrapper).name override fun hashCode(): Int = super.hashCode() + name.hashCode() diff --git a/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt b/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt index dab06343f9..e8c6f02d30 100644 --- a/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt +++ b/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt @@ -12,6 +12,7 @@ import org.jetbrains.dokka.base.resolvers.local.MultimoduleLocationProvider.Comp import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.doc.DocTag import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.model.doc.P import org.jetbrains.dokka.pages.* @@ -20,7 +21,7 @@ import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.transformers.pages.PageCreator import org.jetbrains.dokka.utilities.DokkaLogger -class MultimodulePageCreator ( +class MultimodulePageCreator( private val context: DokkaContext, ) : PageCreator { private val logger: DokkaLogger = context.logger @@ -71,16 +72,29 @@ class MultimodulePageCreator ( private fun getDisplayedModuleDocumentation(module: DokkaModuleDescription): P? { val parsingContext = ModuleAndPackageDocumentationParsingContext(logger) - return module.includes + + val documentationFragment = module.includes .flatMap { include -> parseModuleAndPackageDocumentationFragments(include) } - .map { fragment -> parseModuleAndPackageDocumentation(parsingContext, fragment) } - .firstOrNull { documentation -> documentation.classifier == Module && documentation.name == module.name } - ?.documentation?.children.orEmpty() - .flatMap { it.root.children } - .filterIsInstance

() - .firstOrNull() + .firstOrNull { fragment -> fragment.classifier == Module && fragment.name == module.name } + ?: return null + + val moduleDocumentation = parseModuleAndPackageDocumentation(parsingContext, documentationFragment) + return moduleDocumentation.documentation.firstParagraph() } - private fun DocumentationNode.firstParagraph() = - this.children.flatMap { it.root.children }.filterIsInstance

().firstOrNull() + private fun DocumentationNode.firstParagraph(): P? = + this.children + .map { it.root } + .mapNotNull { it.firstParagraph() } + .firstOrNull() + + /** + * @return The very first, most inner paragraph. If any [P] is wrapped inside another [P], the inner one + * is preferred. + */ + private fun DocTag.firstParagraph(): P? { + val firstChildParagraph = children.mapNotNull { it.firstParagraph() }.firstOrNull() + return if (firstChildParagraph == null && this is P) this + else firstChildParagraph + } } diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt index bf6579af74..2b2a3f0327 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt @@ -2,6 +2,7 @@ package org.jetbrains.dokka.base.transformers.documentables import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.model.DModule +import org.jetbrains.dokka.model.SourceSetDependent import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer @@ -22,8 +23,8 @@ internal class ModuleAndPackageDocumentationTransformer( } } - private operator fun Map.plus( - other: Map + private operator fun SourceSetDependent.plus( + other: SourceSetDependent ): Map = (asSequence() + other.asSequence()) .distinct() From 7e86b026bf73f7001f885ace8292b9d37bbab8b0 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Fri, 28 Aug 2020 15:42:59 +0200 Subject: [PATCH 14/19] Remove unnecessary trailing comma in defaultConfiguration.kt --- core/src/main/kotlin/defaultConfiguration.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/kotlin/defaultConfiguration.kt b/core/src/main/kotlin/defaultConfiguration.kt index 5b32ebae1f..69df44b130 100644 --- a/core/src/main/kotlin/defaultConfiguration.kt +++ b/core/src/main/kotlin/defaultConfiguration.kt @@ -13,7 +13,7 @@ data class DokkaConfigurationImpl( override val pluginsClasspath: List = emptyList(), override val pluginsConfiguration: Map = emptyMap(), override val modules: List = emptyList(), - override val failOnWarning: Boolean = DokkaDefaults.failOnWarning, + override val failOnWarning: Boolean = DokkaDefaults.failOnWarning ) : DokkaConfiguration From bbf9bc1a86234437557b3a1b81e3e3725d7a3957 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Fri, 28 Aug 2020 15:44:34 +0200 Subject: [PATCH 15/19] Remove unnecessary blank lines --- .../parseModuleAndPackageDocumentationFragments.kt | 3 --- .../org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt | 1 - 2 files changed, 4 deletions(-) diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt index e66b76127f..7dcaccfa40 100644 --- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt +++ b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt @@ -50,6 +50,3 @@ private fun parseModuleAndPackageDocFragment( source = source ) } - - - diff --git a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt index d3a6c587ad..17e7dd1c51 100644 --- a/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt +++ b/runners/gradle-plugin/src/main/kotlin/org/jetbrains/dokka/gradle/GradleDokkaSourceSetBuilder.kt @@ -1,5 +1,4 @@ @file:Suppress("FunctionName", "UnstableApiUsage") -@file:JvmName("GradleDokkaSourceSetBuilderKt") package org.jetbrains.dokka.gradle From 50962e9e47a61147a0e95ca72aa6441ce7eef0ca Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Fri, 28 Aug 2020 15:45:22 +0200 Subject: [PATCH 16/19] Improve style of ModuleAndPackageDocumentationSource --- .../moduleAndPackage/ModuleAndPackageDocumentationSource.kt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt index 7c3f6d9795..90dc9ca886 100644 --- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt +++ b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt @@ -5,10 +5,7 @@ import java.io.File internal abstract class ModuleAndPackageDocumentationSource { abstract val sourceDescription: String abstract val documentation: String - - override fun toString(): String { - return sourceDescription - } + override fun toString(): String = sourceDescription } internal data class ModuleAndPackageDocumentationFile(private val file: File) : ModuleAndPackageDocumentationSource() { From 3538bf67be5de509d60f53210ebad9b5b5d4ffdd Mon Sep 17 00:00:00 2001 From: Sebastian Sellmair <34319766+sellmair@users.noreply.github.com> Date: Fri, 28 Aug 2020 18:06:40 +0200 Subject: [PATCH 17/19] CompositeSourceSetID: drop reduce in favour of `joinToString` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Paweł Marks --- core/src/main/kotlin/model/CompositeSourceSetID.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/kotlin/model/CompositeSourceSetID.kt b/core/src/main/kotlin/model/CompositeSourceSetID.kt index 9f38dafb39..e14b01dfab 100644 --- a/core/src/main/kotlin/model/CompositeSourceSetID.kt +++ b/core/src/main/kotlin/model/CompositeSourceSetID.kt @@ -14,8 +14,8 @@ data class CompositeSourceSetID( } val merged = DokkaSourceSetID( - scopeId = children.map { it.scopeId }.reduce { acc, s -> "$acc+$s" }, - sourceSetName = children.map { it.sourceSetName }.reduce { acc, s -> "$acc+$s" } + scopeId = children.joinToString(separator = "+") { it.scopeId }, + sourceSetName = children.joinToString(separator = "+") { it.sourceSetName } ) val all: Set = setOf(merged, *children.toTypedArray()) From 064b22b55d53cd215b1ddfb320ce23242b5e529f Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Fri, 28 Aug 2020 18:24:11 +0200 Subject: [PATCH 18/19] Implement dPackage and dModule test APIs in favour of default params in DModule and DPackage --- core/src/main/kotlin/model/Documentable.kt | 18 ++++----- .../TestDokkaConfigurationBuilder.kt | 39 +++++++++++++++++++ ...oduleAndPackageDocumentationReaderTest1.kt | 24 ++++++------ ...oduleAndPackageDocumentationReaderTest3.kt | 3 +- ...PackageDocumentationTransformerUnitTest.kt | 13 ++++--- 5 files changed, 69 insertions(+), 28 deletions(-) diff --git a/core/src/main/kotlin/model/Documentable.kt b/core/src/main/kotlin/model/Documentable.kt index 34ad6c2b0f..0ffc2f8431 100644 --- a/core/src/main/kotlin/model/Documentable.kt +++ b/core/src/main/kotlin/model/Documentable.kt @@ -87,10 +87,10 @@ sealed class DClasslike : Documentable(), WithScope, WithVisibility, WithExpectA data class DModule( override val name: String, - val packages: List = emptyList(), - override val documentation: SourceSetDependent = emptyMap(), + val packages: List, + override val documentation: SourceSetDependent, override val expectPresentInSet: DokkaSourceSet? = null, - override val sourceSets: Set = emptySet(), + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithExtraProperties { override val dri: DRI = DRI.topLevel @@ -102,13 +102,13 @@ data class DModule( data class DPackage( override val dri: DRI, - override val functions: List = emptyList(), - override val properties: List = emptyList(), - override val classlikes: List = emptyList(), - val typealiases: List = emptyList(), - override val documentation: SourceSetDependent = emptyMap(), + override val functions: List, + override val properties: List, + override val classlikes: List, + val typealiases: List, + override val documentation: SourceSetDependent, override val expectPresentInSet: DokkaSourceSet? = null, - override val sourceSets: Set = emptySet(), + override val sourceSets: Set, override val extra: PropertyContainer = PropertyContainer.empty() ) : Documentable(), WithScope, WithExtraProperties { diff --git a/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt index 2d9f99b229..d7b4f64fa7 100644 --- a/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt +++ b/core/test-api/src/main/kotlin/testApi/testRunner/TestDokkaConfigurationBuilder.kt @@ -6,6 +6,7 @@ import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.doc.Description import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.model.doc.Text +import org.jetbrains.dokka.model.properties.PropertyContainer import java.io.File fun dokkaConfiguration(block: TestDokkaConfigurationBuilder.() -> Unit): DokkaConfigurationImpl = @@ -145,6 +146,44 @@ fun sourceSet(name: String): DokkaConfiguration.DokkaSourceSet { ) } +fun dModule( + name: String, + packages: List = emptyList(), + documentation: SourceSetDependent = emptyMap(), + expectPresentInSet: DokkaConfiguration.DokkaSourceSet? = null, + sourceSets: Set = emptySet(), + extra: PropertyContainer = PropertyContainer.empty() +): DModule = DModule( + name = name, + packages = packages, + documentation = documentation, + expectPresentInSet = expectPresentInSet, + sourceSets = sourceSets, + extra = extra +) + +fun dPackage( + dri: DRI, + functions: List = emptyList(), + properties: List = emptyList(), + classlikes: List = emptyList(), + typealiases: List = emptyList(), + documentation: SourceSetDependent = emptyMap(), + expectPresentInSet: DokkaConfiguration.DokkaSourceSet? = null, + sourceSets: Set = emptySet(), + extra: PropertyContainer = PropertyContainer.empty() +): DPackage = DPackage( + dri = dri, + functions = functions, + properties = properties, + classlikes = classlikes, + typealiases = typealiases, + documentation = documentation, + expectPresentInSet = expectPresentInSet, + sourceSets = sourceSets, + extra = extra +) + fun documentationNode(vararg texts: String): DocumentationNode { return DocumentationNode(texts.toList().map { Description(Text(it)) }) } diff --git a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt index 51a5e85ab4..2aba6d67d3 100644 --- a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt +++ b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest1.kt @@ -3,8 +3,6 @@ package transformers import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.base.transformers.documentables.ModuleAndPackageDocumentationReader import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.DModule -import org.jetbrains.dokka.model.DPackage import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.testApi.logger.TestLogger @@ -13,6 +11,8 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testApi.testRunner.TestDokkaConfigurationBuilder +import testApi.testRunner.dModule +import testApi.testRunner.dPackage class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAndPackageDocumentationReaderTest() { @@ -83,7 +83,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert moduleA with sourceSetA`() { - val documentation = reader[DModule(name = "moduleA", sourceSets = setOf(sourceSetA))] + val documentation = reader[dModule(name = "moduleA", sourceSets = setOf(sourceSetA))] assertEquals( 1, documentation.keys.size, "Expected moduleA only containing documentation in a single source set" @@ -101,7 +101,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert moduleA with no source sets`() { - val documentation = reader[DModule("moduleA")] + val documentation = reader[dModule("moduleA")] assertEquals( emptyMap(), documentation, "Expected no documentation received for module not declaring a matching sourceSet" @@ -111,7 +111,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert moduleA with unknown source set`() { val documentation = reader[ - DModule("moduleA", sourceSets = setOf(configurationBuilder.unattachedSourceSet { name = "unknown" })) + dModule("moduleA", sourceSets = setOf(configurationBuilder.unattachedSourceSet { name = "unknown" })) ] assertEquals( emptyMap(), documentation, @@ -121,7 +121,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert moduleA with all sourceSets`() { - val documentation = reader[DModule("moduleA", sourceSets = setOf(sourceSetA, sourceSetB, sourceSetB2))] + val documentation = reader[dModule("moduleA", sourceSets = setOf(sourceSetA, sourceSetB, sourceSetB2))] assertEquals(1, documentation.entries.size, "Expected only one entry from sourceSetA") assertEquals(sourceSetA, documentation.keys.single(), "Expected only one entry from sourceSetA") assertEquals("This is moduleA", documentation.texts.single()) @@ -129,7 +129,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert moduleB with sourceSetB and sourceSetB2`() { - val documentation = reader[DModule("moduleB", sourceSets = setOf(sourceSetB, sourceSetB2))] + val documentation = reader[dModule("moduleB", sourceSets = setOf(sourceSetB, sourceSetB2))] assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSetB") assertEquals(sourceSetB, documentation.keys.single(), "Expected only one entry from sourceSetB") assertEquals("This is moduleB", documentation.texts.single()) @@ -137,7 +137,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert sample_A in sourceSetA`() { - val documentation = reader[DPackage(DRI("sample.a"), sourceSets = setOf(sourceSetA))] + val documentation = reader[dPackage(DRI("sample.a"), sourceSets = setOf(sourceSetA))] assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSetA") assertEquals(sourceSetA, documentation.keys.single(), "Expected only one entry from sourceSetA") assertEquals("This is package sample.a", documentation.texts.single()) @@ -145,7 +145,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert sample_a_sub in sourceSetA`() { - val documentation = reader[DPackage(DRI("sample.a.sub"), sourceSets = setOf(sourceSetA))] + val documentation = reader[dPackage(DRI("sample.a.sub"), sourceSets = setOf(sourceSetA))] assertEquals( emptyMap(), documentation, "Expected no documentation found for different package" @@ -154,7 +154,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert sample_a in sourceSetB`() { - val documentation = reader[DPackage(DRI("sample.a"), sourceSets = setOf(sourceSetB))] + val documentation = reader[dPackage(DRI("sample.a"), sourceSets = setOf(sourceSetB))] assertEquals( emptyMap(), documentation, "Expected no documentation found for different sourceSet" @@ -163,7 +163,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert sample_b in sourceSetB`() { - val documentation = reader[DPackage(DRI("sample.b"), sourceSets = setOf(sourceSetB))] + val documentation = reader[dPackage(DRI("sample.b"), sourceSets = setOf(sourceSetB))] assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSetB") assertEquals(sourceSetB, documentation.keys.single(), "Expected only one entry from sourceSetB") assertEquals("This is package sample.b", documentation.texts.single()) @@ -171,7 +171,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd @Test fun `assert sample_b in sourceSetB and sourceSetB2`() { - val documentation = reader[DPackage(DRI("sample.b"), sourceSets = setOf(sourceSetB, sourceSetB2))] + val documentation = reader[dPackage(DRI("sample.b"), sourceSets = setOf(sourceSetB, sourceSetB2))] assertEquals(1, documentation.keys.size, "Expected only one entry from sourceSetB") assertEquals(sourceSetB, documentation.keys.single(), "Expected only one entry from sourceSetB") assertEquals("This is package sample.b", documentation.texts.single()) diff --git a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt index a557379bfa..9319f5af51 100644 --- a/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt +++ b/plugins/base/src/test/kotlin/transformers/ContextModuleAndPackageDocumentationReaderTest3.kt @@ -8,6 +8,7 @@ import org.jetbrains.dokka.utilities.DokkaConsoleLogger import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testApi.testRunner.TestDokkaConfigurationBuilder +import testApi.testRunner.dPackage import testApi.testRunner.dokkaConfiguration import testApi.testRunner.sourceSet import kotlin.test.assertEquals @@ -48,7 +49,7 @@ class ContextModuleAndPackageDocumentationReaderTest3 : AbstractContextModuleAnd @Test fun `root package is matched by empty string and the root keyword`() { - val documentation = reader[DPackage(DRI(""), sourceSets = setOf(sourceSet))] + val documentation = reader[dPackage(DRI(""), sourceSets = setOf(sourceSet))] assertEquals( listOf("This is the root package", "This is also the root package"), documentation.texts ) diff --git a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerUnitTest.kt b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerUnitTest.kt index b75f8e5b51..9f934f3f18 100644 --- a/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerUnitTest.kt +++ b/plugins/base/src/test/kotlin/transformers/ModuleAndPackageDocumentationTransformerUnitTest.kt @@ -9,6 +9,7 @@ import org.jetbrains.dokka.model.SourceSetDependent import org.jetbrains.dokka.model.doc.DocumentationNode import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test +import testApi.testRunner.dPackage import testApi.testRunner.documentationNode import testApi.testRunner.sourceSet @@ -139,21 +140,21 @@ class ModuleAndPackageDocumentationTransformerUnitTest { documentation = emptyMap(), sourceSets = emptySet(), packages = listOf( - DPackage( + dPackage( dri = DRI("com.sample"), documentation = mapOf( sourceSet("A") to documentationNode("pre-existing:A:com.sample") ), sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")), ), - DPackage( + dPackage( dri = DRI("com.attach"), documentation = mapOf( sourceSet("A") to documentationNode("pre-existing:A:com.attach") ), sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")) ), - DPackage( + dPackage( dri = DRI("com.attach.sub"), documentation = mapOf( sourceSet("A") to documentationNode("pre-existing:A:com.attach.sub"), @@ -197,7 +198,7 @@ class ModuleAndPackageDocumentationTransformerUnitTest { documentation = emptyMap(), sourceSets = emptySet(), packages = listOf( - DPackage( + dPackage( dri = DRI("com.sample"), documentation = mapOf( /* No documentation added, since in wrong package */ @@ -206,7 +207,7 @@ class ModuleAndPackageDocumentationTransformerUnitTest { sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")), ), - DPackage( + dPackage( dri = DRI("com.attach"), documentation = mapOf( /* Documentation added */ @@ -215,7 +216,7 @@ class ModuleAndPackageDocumentationTransformerUnitTest { ), sourceSets = setOf(sourceSet("A"), sourceSet("B"), sourceSet("C")), ), - DPackage( + dPackage( dri = DRI("com.attach.sub"), documentation = mapOf( /* Documentation added */ From c2dd9620df304669b6bd22fcb7ed237f85be62c1 Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Mon, 31 Aug 2020 11:58:05 +0200 Subject: [PATCH 19/19] Remove old `defaultSourceSet` in favour of new package --- .../src/main/kotlin/renderers/defaultSourceSet.kt | 3 --- .../test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt | 2 +- .../test/kotlin/renderers/html/SourceSetDependentHintTest.kt | 3 +-- plugins/gfm/src/test/kotlin/renderers/gfm/DivergentTest.kt | 2 +- .../test/kotlin/renderers/gfm/SourceSetDependentHintTest.kt | 2 +- 5 files changed, 4 insertions(+), 8 deletions(-) delete mode 100644 plugins/base/base-test-utils/src/main/kotlin/renderers/defaultSourceSet.kt diff --git a/plugins/base/base-test-utils/src/main/kotlin/renderers/defaultSourceSet.kt b/plugins/base/base-test-utils/src/main/kotlin/renderers/defaultSourceSet.kt deleted file mode 100644 index 41ca714695..0000000000 --- a/plugins/base/base-test-utils/src/main/kotlin/renderers/defaultSourceSet.kt +++ /dev/null @@ -1,3 +0,0 @@ -package renderers - -val defaultSourceSet = testApi.testRunner.defaultSourceSet diff --git a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt index 8426923dff..0d3763eeb6 100644 --- a/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt +++ b/plugins/base/src/test/kotlin/renderers/html/HtmlRenderingOnlyTestBase.kt @@ -15,7 +15,7 @@ import org.jsoup.nodes.Node import org.jsoup.nodes.TextNode import renderers.RenderingOnlyTestBase import utils.TestOutputWriter -import renderers.defaultSourceSet +import testApi.testRunner.defaultSourceSet import java.io.File abstract class HtmlRenderingOnlyTestBase : RenderingOnlyTestBase() { diff --git a/plugins/base/src/test/kotlin/renderers/html/SourceSetDependentHintTest.kt b/plugins/base/src/test/kotlin/renderers/html/SourceSetDependentHintTest.kt index 4fd349e454..6be3839df8 100644 --- a/plugins/base/src/test/kotlin/renderers/html/SourceSetDependentHintTest.kt +++ b/plugins/base/src/test/kotlin/renderers/html/SourceSetDependentHintTest.kt @@ -5,8 +5,7 @@ import org.jetbrains.dokka.base.renderers.html.HtmlRenderer import org.jetbrains.dokka.pages.TextStyle import org.junit.jupiter.api.Test import renderers.TestPage -import renderers.defaultSourceSet -import renderers.RenderingOnlyTestBase +import testApi.testRunner.defaultSourceSet import utils.Div import utils.match import java.io.File diff --git a/plugins/gfm/src/test/kotlin/renderers/gfm/DivergentTest.kt b/plugins/gfm/src/test/kotlin/renderers/gfm/DivergentTest.kt index dee43b1def..ab1378d5d3 100644 --- a/plugins/gfm/src/test/kotlin/renderers/gfm/DivergentTest.kt +++ b/plugins/gfm/src/test/kotlin/renderers/gfm/DivergentTest.kt @@ -6,8 +6,8 @@ import org.jetbrains.dokka.gfm.CommonmarkRenderer import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.pages.ContentDivergentGroup import org.junit.jupiter.api.Test -import renderers.defaultSourceSet import renderers.TestPage +import testApi.testRunner.defaultSourceSet import java.io.File class DivergentTest : GfmRenderingOnlyTestBase() { diff --git a/plugins/gfm/src/test/kotlin/renderers/gfm/SourceSetDependentHintTest.kt b/plugins/gfm/src/test/kotlin/renderers/gfm/SourceSetDependentHintTest.kt index 93edd00119..999d7954a1 100644 --- a/plugins/gfm/src/test/kotlin/renderers/gfm/SourceSetDependentHintTest.kt +++ b/plugins/gfm/src/test/kotlin/renderers/gfm/SourceSetDependentHintTest.kt @@ -6,7 +6,7 @@ import org.jetbrains.dokka.gfm.CommonmarkRenderer import org.jetbrains.dokka.pages.TextStyle import org.junit.jupiter.api.Test import renderers.TestPage -import renderers.defaultSourceSet +import testApi.testRunner.defaultSourceSet import java.io.File class SourceSetDependentHintTest : GfmRenderingOnlyTestBase() {