From 333091e5c5f896769c3371dd74c87a52ffa9562a Mon Sep 17 00:00:00 2001 From: "sebastian.sellmair" Date: Fri, 21 Aug 2020 10:19:07 +0200 Subject: Implement ParseModuleAndPackageDocFragments API --- .../parsers/ModuleAndPackageDocumentationParser.kt | 76 ++++++++++++++++++++++ plugins/base/src/main/kotlin/parsers/Parser.kt | 41 +++++++----- .../ModuleAndPackageDocumentationTransformer.kt | 9 +-- 3 files changed, 102 insertions(+), 24 deletions(-) create mode 100644 plugins/base/src/main/kotlin/parsers/ModuleAndPackageDocumentationParser.kt (limited to 'plugins/base/src/main/kotlin') 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 { + 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 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 = 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, new: Map) = + private fun mergeDocumentation(origin: Map, new: Map): Map = (origin.asSequence() + new.asSequence()) .distinct() .groupBy({ it.key }, { it.value }) -- cgit