diff options
6 files changed, 394 insertions, 100 deletions
diff --git a/core/src/main/kotlin/DokkaException.kt b/core/src/main/kotlin/DokkaException.kt index 0010249c..9a5e3d04 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 dc2cd2be..0d3b0612 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<DocTag> { 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<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Big(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class B(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class BlockQuote(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -object Br : DocTag(emptyList(), emptyMap()) -class Cite(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -sealed class Code(children: List<DocTag>, params: Map<String, String>) : DocTag(children, params) -class CodeInline(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : Code(children, params) -class CodeBlock(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : Code(children, params) -class Dd(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Dfn(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Dir(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Div(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Dl(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Dt(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Em(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Font(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Footer(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Frame(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class FrameSet(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class H1(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class H2(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class H3(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class H4(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class H5(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class H6(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Head(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Header(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Html(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class I(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class IFrame(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Img(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Input(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Li(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Link(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Listing(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Main(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Menu(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Meta(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Nav(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class NoFrames(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class NoScript(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Ol(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class P(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Pre(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Script(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Section(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Small(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Span(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Strikethrough(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Strong(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Sub(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Sup(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Table(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Text(val body: String = "", children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) { +class A(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Big(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class B(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class BlockQuote(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : + DocTag(children, params) + +object Br : DocTag(emptyList(), emptyMap()) +class Cite(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +sealed class Code(children: List<DocTag>, params: Map<String, String>) : DocTag(children, params) +class CodeInline(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : + Code(children, params) + +class CodeBlock(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : Code(children, params) +class Dd(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Dfn(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Dir(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Div(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Dl(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Dt(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Em(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Font(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Footer(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Frame(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class FrameSet(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : + DocTag(children, params) + +class H1(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class H2(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class H3(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class H4(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class H5(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class H6(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Head(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Header(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Html(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class I(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class IFrame(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Img(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Input(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Li(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Link(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Listing(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Main(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Menu(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Meta(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Nav(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class NoFrames(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : + DocTag(children, params) + +class NoScript(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : + DocTag(children, params) + +class Ol(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class P(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Pre(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Script(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Section(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Small(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Span(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Strikethrough(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : + DocTag(children, params) + +class Strong(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Sub(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Sup(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Table(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Text(val body: String = "", children: List<DocTag> = emptyList(), params: Map<String, String> = 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<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Td(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class TFoot(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Th(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class THead(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Title(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Tr(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Tt(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class U(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Ul(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class Var(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class DocumentationLink(val dri: DRI, children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) { + +class TBody(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Td(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class TFoot(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Th(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class THead(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Title(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Tr(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Tt(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class U(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Ul(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class Var(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class DocumentationLink(val dri: DRI, children: List<DocTag> = emptyList(), params: Map<String, String> = 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<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) -class CustomDocTag(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) + +object HorizontalRule : DocTag(emptyList(), emptyMap()) +class Index(children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap()) : DocTag(children, params) +class CustomDocTag(children: List<DocTag> = emptyList(), params: Map<String, String> = 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 00000000..4b46537b --- /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<ModuleAndPackageDocFragment> { + return parseModuleAndPackageDocFragments(ModuleAndPackageDocumentationFile(source)) +} + +internal fun parseModuleAndPackageDocFragments(source: ModuleAndPackageDocumentationSource): List<ModuleAndPackageDocFragment> { + 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 1dd0c34a..706f093b 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<TagWrapper> = 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 71824922..5f1a540d 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<DokkaSourceSet, DocumentationNode>, new: Map<DokkaSourceSet, DocumentationNode>) = + private fun mergeDocumentation(origin: Map<DokkaSourceSet, DocumentationNode>, new: Map<DokkaSourceSet, DocumentationNode>): Map<DokkaSourceSet, DocumentationNode> = (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 00000000..49eddaea --- /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<IllegalModuleAndPackageDocumentation> { + 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<IllegalModuleAndPackageDocumentation> { + 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<IllegalModuleAndPackageDocumentation> { + 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<IllegalModuleAndPackageDocumentation> { + 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 + } +} |