aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin/parsers
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/base/src/main/kotlin/parsers')
-rw-r--r--plugins/base/src/main/kotlin/parsers/MarkdownParser.kt604
-rw-r--r--plugins/base/src/main/kotlin/parsers/Parser.kt131
-rw-r--r--plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt67
-rw-r--r--plugins/base/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt77
-rw-r--r--plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt7
-rw-r--r--plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentation.kt11
-rw-r--r--plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment.kt10
-rw-r--r--plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext.kt64
-rw-r--r--plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt14
-rw-r--r--plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentation.kt12
-rw-r--r--plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt55
11 files changed, 0 insertions, 1052 deletions
diff --git a/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt b/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt
deleted file mode 100644
index d49e7c7a..00000000
--- a/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt
+++ /dev/null
@@ -1,604 +0,0 @@
-package org.jetbrains.dokka.base.parsers
-
-import com.intellij.psi.PsiElement
-import org.intellij.markdown.MarkdownElementTypes
-import org.intellij.markdown.MarkdownTokenTypes
-import org.intellij.markdown.ast.ASTNode
-import org.intellij.markdown.ast.CompositeASTNode
-import org.intellij.markdown.ast.LeafASTNode
-import org.intellij.markdown.ast.impl.ListItemCompositeNode
-import org.intellij.markdown.flavours.gfm.GFMElementTypes
-import org.intellij.markdown.flavours.gfm.GFMFlavourDescriptor
-import org.intellij.markdown.flavours.gfm.GFMTokenTypes
-import org.intellij.markdown.html.HtmlGenerator
-import org.jetbrains.dokka.base.parsers.factories.DocTagsFromIElementFactory
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.links.PointingToDeclaration
-import org.jetbrains.dokka.model.doc.*
-import org.jetbrains.dokka.model.doc.Suppress
-import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
-import java.net.MalformedURLException
-import java.net.URL
-import org.intellij.markdown.parser.MarkdownParser as IntellijMarkdownParser
-
-open class MarkdownParser(
- private val externalDri: (String) -> DRI?,
- private val kdocLocation: String?,
-) : Parser() {
-
- private lateinit var destinationLinksMap: Map<String, String>
- private lateinit var text: String
-
- override fun parseStringToDocNode(extractedString: String): DocTag {
- val gfmFlavourDescriptor = GFMFlavourDescriptor()
- val markdownAstRoot = IntellijMarkdownParser(gfmFlavourDescriptor).buildMarkdownTreeFromString(extractedString)
- destinationLinksMap = getAllDestinationLinks(extractedString, markdownAstRoot).toMap()
- text = extractedString
-
- val parsed = visitNode(markdownAstRoot)
- if (parsed.size == 1) {
- return parsed.first()
- }
- return CustomDocTag(children = parsed, params = emptyMap(), name = "")
- }
-
- override fun preparse(text: String) = text.replace("\r\n", "\n").replace("\r", "\n")
-
- override fun parseTagWithBody(tagName: String, content: String): TagWrapper =
- when (tagName) {
- "see" -> {
- val referencedName = content.substringBefore(' ')
- val dri = externalDri(referencedName)
- See(
- parseStringToDocNode(content.substringAfter(' ')),
- dri?.fqDeclarationName() ?: referencedName,
- dri
- )
- }
- "throws", "exception" -> {
- val dri = externalDri(content.substringBefore(' '))
- Throws(
- parseStringToDocNode(content.substringAfter(' ')),
- dri?.fqDeclarationName() ?: content.substringBefore(' '),
- dri
- )
- }
- else -> super.parseTagWithBody(tagName, content)
- }
-
- private fun headersHandler(node: ASTNode) =
- DocTagsFromIElementFactory.getInstance(
- node.type,
- visitNode(node.children.find { it.type == MarkdownTokenTypes.ATX_CONTENT }
- ?: throw detailedException("Wrong AST Tree. Header does not contain expected content", node)
- ).flatMap { it.children }
- )
-
- private fun horizontalRulesHandler() =
- DocTagsFromIElementFactory.getInstance(MarkdownTokenTypes.HORIZONTAL_RULE)
-
- private fun emphasisHandler(node: ASTNode) =
- DocTagsFromIElementFactory.getInstance(
- node.type,
- children = node.children.evaluateChildrenWithDroppedEnclosingTokens(1)
- )
-
- private fun strongHandler(node: ASTNode) =
- DocTagsFromIElementFactory.getInstance(
- node.type,
- children = node.children.evaluateChildrenWithDroppedEnclosingTokens(2)
- )
-
- private fun List<ASTNode>.evaluateChildrenWithDroppedEnclosingTokens(count: Int) =
- drop(count).dropLast(count).evaluateChildren()
-
- private fun blockquotesHandler(node: ASTNode) =
- DocTagsFromIElementFactory.getInstance(
- node.type, children = node.children
- .filterIsInstance<CompositeASTNode>()
- .evaluateChildren()
- )
-
- private fun listsHandler(node: ASTNode): List<DocTag> {
-
- val children = node.children.filterIsInstance<ListItemCompositeNode>().flatMap {
- if (it.children.last().type in listOf(
- MarkdownElementTypes.ORDERED_LIST,
- MarkdownElementTypes.UNORDERED_LIST
- )
- ) {
- val nestedList = it.children.last()
- (it.children as MutableList).removeAt(it.children.lastIndex)
- listOf(it, nestedList)
- } else
- listOf(it)
- }
-
- return DocTagsFromIElementFactory.getInstance(
- node.type,
- children =
- children
- .flatMap {
- if (it.type == MarkdownElementTypes.LIST_ITEM)
- DocTagsFromIElementFactory.getInstance(
- it.type,
- children = it
- .children
- .filterIsInstance<CompositeASTNode>()
- .evaluateChildren()
- )
- else
- visitNode(it)
- },
- params =
- if (node.type == MarkdownElementTypes.ORDERED_LIST) {
- val listNumberNode = node.children.first().children.first()
- mapOf(
- "start" to text.substring(
- listNumberNode.startOffset,
- listNumberNode.endOffset
- ).trim().dropLast(1)
- )
- } else
- emptyMap()
- )
- }
-
- private fun resolveDRI(mdLink: String): DRI? =
- mdLink
- .removePrefix("[")
- .removeSuffix("]")
- .let { link ->
- try {
- URL(link)
- null
- } catch (e: MalformedURLException) {
- externalDri(link)
- }
- }
-
- private fun getAllDestinationLinks(text: String, node: ASTNode): List<Pair<String, String>> =
- node.children
- .filter { it.type == MarkdownElementTypes.LINK_DEFINITION }
- .map {
- text.substring(it.children[0].startOffset, it.children[0].endOffset).toLowerCase() to
- text.substring(it.children[2].startOffset, it.children[2].endOffset)
- } +
- node.children.filterIsInstance<CompositeASTNode>().flatMap { getAllDestinationLinks(text, it) }
-
-
- private fun referenceLinksHandler(node: ASTNode): List<DocTag> {
- val linkLabel = node.children.find { it.type == MarkdownElementTypes.LINK_LABEL }
- ?: throw detailedException("Wrong AST Tree. Reference link does not contain link label", node)
- val linkText = node.children.findLast { it.type == MarkdownElementTypes.LINK_TEXT } ?: linkLabel
-
- val linkKey = text.substring(linkLabel.startOffset, linkLabel.endOffset)
-
- val link = destinationLinksMap[linkKey.toLowerCase()] ?: linkKey
-
- return linksHandler(linkText, link)
- }
-
- private fun inlineLinksHandler(node: ASTNode): List<DocTag> {
- val linkText = node.children.find { it.type == MarkdownElementTypes.LINK_TEXT }
- ?: throw detailedException("Wrong AST Tree. Inline link does not contain link text", node)
- val linkDestination = node.children.find { it.type == MarkdownElementTypes.LINK_DESTINATION }
- val linkTitle = node.children.find { it.type == MarkdownElementTypes.LINK_TITLE }
-
- // Link destination may be ommited: https://github.github.com/gfm/#example-495
- val link = linkDestination?.let { text.substring(it.startOffset, it.endOffset) }
-
- return linksHandler(linkText, link, linkTitle)
- }
-
- private fun markdownFileHandler(node: ASTNode) =
- DocTagsFromIElementFactory.getInstance(
- node.type,
- children = node.children
- .filterSpacesAndEOL()
- .evaluateChildren()
- )
-
- private fun autoLinksHandler(node: ASTNode): List<DocTag> {
- val link = text.substring(node.startOffset + 1, node.endOffset - 1)
-
- return linksHandler(node, link)
- }
-
- private fun linksHandler(linkText: ASTNode, link: String?, linkTitle: ASTNode? = null): List<DocTag> {
- val dri: DRI? = link?.let { resolveDRI(it) }
- val linkOrEmpty = link ?: ""
- val linkTextString =
- if (linkTitle == null) linkOrEmpty else text.substring(linkTitle.startOffset + 1, linkTitle.endOffset - 1)
-
- val params = if (linkTitle == null)
- mapOf("href" to linkOrEmpty)
- else
- mapOf("href" to linkOrEmpty, "title" to linkTextString)
-
- return if (link != null && dri == null && !linkOrEmpty.isRemoteLink()) {
- DocTagsFromIElementFactory.getInstance(
- MarkdownTokenTypes.TEXT,
- params = params,
- children = linkText.children.drop(1).dropLast(1).evaluateChildren(),
- body = linkTextString.removeSurrounding("[", "]")
- )
- } else {
- DocTagsFromIElementFactory.getInstance(
- MarkdownElementTypes.INLINE_LINK,
- params = params,
- children = linkText.children.drop(1).dropLast(1).evaluateChildren(),
- dri = dri
- )
- }
- }
-
- private fun codeLineHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance(
- MarkdownElementTypes.CODE_BLOCK,
- body = text.substring(node.startOffset, node.endOffset)
- )
-
- private fun textHandler(node: ASTNode, keepAllFormatting: Boolean) = DocTagsFromIElementFactory.getInstance(
- MarkdownTokenTypes.TEXT,
- body = text.substring(node.startOffset, node.endOffset).transform(),
- keepFormatting = keepAllFormatting
- )
-
- private fun strikeThroughHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance(
- node.type,
- children = node.children.evaluateChildrenWithDroppedEnclosingTokens(2)
- )
-
- private fun tableHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance(
- GFMElementTypes.TABLE,
- children = node.children
- .filter { it.type == GFMElementTypes.ROW || it.type == GFMElementTypes.HEADER }
- .evaluateChildren()
- )
-
- private fun headerHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance(
- GFMElementTypes.HEADER,
- children = node.children
- .filter { it.type == GFMTokenTypes.CELL }
- .evaluateChildren()
- )
-
- private fun rowHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance(
- GFMElementTypes.ROW,
- children = node.children
- .filter { it.type == GFMTokenTypes.CELL }
- .evaluateChildren()
- )
-
- private fun cellHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance(
- GFMTokenTypes.CELL,
- children = node.children.filterTabSeparators().evaluateChildren().trimSurroundingTokensIfText()
- )
-
- private fun String.isRemoteLink() = try {
- URL(this)
- true
- } catch (e: MalformedURLException) {
- false
- }
-
- private fun imagesHandler(node: ASTNode): List<DocTag> =
- with(node.children.last().children) {
- val destination = find { it.type == MarkdownElementTypes.LINK_DESTINATION }
- val description = find { it.type == MarkdownElementTypes.LINK_TEXT }
-
- val src = destination?.let {
- mapOf("href" to text.substring(it.startOffset, it.endOffset))
- } ?: emptyMap()
-
- val alt = description?.let {
- mapOf("alt" to text.substring(it.startOffset + 1, it.endOffset - 1))
- } ?: emptyMap()
-
- return DocTagsFromIElementFactory.getInstance(
- node.type,
- params = src + alt
- )
- }
-
-
- private fun rawHtmlHandler(node: ASTNode): List<DocTag> =
- DocTagsFromIElementFactory.getInstance(
- node.type,
- body = text.substring(node.startOffset, node.endOffset)
- )
-
- private fun codeSpansHandler(node: ASTNode) =
- DocTagsFromIElementFactory.getInstance(
- node.type,
- children = DocTagsFromIElementFactory.getInstance(
- MarkdownTokenTypes.TEXT,
- body = text.substring(node.startOffset + 1, node.endOffset - 1).replace('\n', ' ').trimIndent(),
- keepFormatting = true
- )
- )
-
- private fun codeFencesHandler(node: ASTNode) =
- DocTagsFromIElementFactory.getInstance(
- node.type,
- children = node
- .children
- .dropWhile { it.type != MarkdownTokenTypes.CODE_FENCE_CONTENT }
- .dropLastWhile { it.type != MarkdownTokenTypes.CODE_FENCE_CONTENT }
- .filter { it.type != MarkdownTokenTypes.WHITE_SPACE }
- .map {
- if (it.type == MarkdownTokenTypes.EOL)
- LeafASTNode(MarkdownTokenTypes.HARD_LINE_BREAK, 0, 0)
- else
- it
- }.evaluateChildren(keepAllFormatting = true),
- params = node
- .children
- .find { it.type == MarkdownTokenTypes.FENCE_LANG }
- ?.let { mapOf("lang" to text.substring(it.startOffset, it.endOffset)) }
- ?: emptyMap()
- )
-
- private fun codeBlocksHandler(node: ASTNode) =
- DocTagsFromIElementFactory.getInstance(node.type, children = node.children.mergeLeafASTNodes().flatMap {
- DocTagsFromIElementFactory.getInstance(
- MarkdownTokenTypes.TEXT,
- body = HtmlGenerator.trimIndents(text.substring(it.startOffset, it.endOffset), 4).toString()
- )
- })
-
- private fun defaultHandler(node: ASTNode) =
- DocTagsFromIElementFactory.getInstance(
- MarkdownElementTypes.PARAGRAPH,
- children = node.children.evaluateChildren()
- )
-
- private fun visitNode(node: ASTNode, keepAllFormatting: Boolean = false): List<DocTag> =
- when (node.type) {
- MarkdownElementTypes.ATX_1,
- MarkdownElementTypes.ATX_2,
- MarkdownElementTypes.ATX_3,
- MarkdownElementTypes.ATX_4,
- MarkdownElementTypes.ATX_5,
- MarkdownElementTypes.ATX_6,
- -> headersHandler(node)
- MarkdownTokenTypes.HORIZONTAL_RULE -> horizontalRulesHandler()
- MarkdownElementTypes.STRONG -> strongHandler(node)
- MarkdownElementTypes.EMPH -> emphasisHandler(node)
- MarkdownElementTypes.FULL_REFERENCE_LINK,
- MarkdownElementTypes.SHORT_REFERENCE_LINK,
- -> referenceLinksHandler(node)
- MarkdownElementTypes.INLINE_LINK -> inlineLinksHandler(node)
- MarkdownElementTypes.AUTOLINK -> autoLinksHandler(node)
- MarkdownElementTypes.BLOCK_QUOTE -> blockquotesHandler(node)
- MarkdownElementTypes.UNORDERED_LIST,
- MarkdownElementTypes.ORDERED_LIST,
- -> listsHandler(node)
- MarkdownElementTypes.CODE_BLOCK -> codeBlocksHandler(node)
- MarkdownElementTypes.CODE_FENCE -> codeFencesHandler(node)
- MarkdownElementTypes.CODE_SPAN -> codeSpansHandler(node)
- MarkdownElementTypes.IMAGE -> imagesHandler(node)
- MarkdownElementTypes.HTML_BLOCK,
- MarkdownTokenTypes.HTML_TAG,
- MarkdownTokenTypes.HTML_BLOCK_CONTENT,
- -> rawHtmlHandler(node)
- MarkdownTokenTypes.HARD_LINE_BREAK -> DocTagsFromIElementFactory.getInstance(node.type)
- MarkdownTokenTypes.CODE_FENCE_CONTENT,
- MarkdownTokenTypes.CODE_LINE,
- -> codeLineHandler(node)
- MarkdownTokenTypes.TEXT -> textHandler(node, keepAllFormatting)
- MarkdownElementTypes.MARKDOWN_FILE -> markdownFileHandler(node)
- GFMElementTypes.STRIKETHROUGH -> strikeThroughHandler(node)
- GFMElementTypes.TABLE -> tableHandler(node)
- GFMElementTypes.HEADER -> headerHandler(node)
- GFMElementTypes.ROW -> rowHandler(node)
- GFMTokenTypes.CELL -> cellHandler(node)
- else -> defaultHandler(node)
- }
-
- private fun List<ASTNode>.filterTabSeparators() =
- this.filterNot { it.type == GFMTokenTypes.TABLE_SEPARATOR }
-
- private fun List<ASTNode>.filterSpacesAndEOL() =
- this.filterNot { it.type == MarkdownTokenTypes.WHITE_SPACE || it.type == MarkdownTokenTypes.EOL }
-
- private fun List<ASTNode>.evaluateChildren(keepAllFormatting: Boolean = false): List<DocTag> =
- this.removeUselessTokens().swapImagesThatShouldBeLinks(keepAllFormatting).mergeLeafASTNodes().flatMap { visitNode(it, keepAllFormatting) }
-
- private fun List<ASTNode>.swapImagesThatShouldBeLinks(keepAllFormatting: Boolean): List<ASTNode> =
- if (keepAllFormatting) {
- this
- } else {
- flatMap { node ->
- if (node.type == MarkdownElementTypes.IMAGE
- && node.children.firstOrNull()?.let { it is LeafASTNode && it.type.name == "!" } == true
- && node.children.lastOrNull()?.type == MarkdownElementTypes.SHORT_REFERENCE_LINK
- ) {
- node.children
- } else {
- listOf(node)
- }
- }
- }
-
- private fun List<ASTNode>.removeUselessTokens(): List<ASTNode> =
- this.filterIndexed { index, node ->
- !(node.type == MarkdownElementTypes.LINK_DEFINITION || (
- node.type == MarkdownTokenTypes.EOL &&
- this.getOrNull(index - 1)?.type == MarkdownTokenTypes.HARD_LINE_BREAK
- ))
- }
-
- private fun List<DocTag>.trimSurroundingTokensIfText() = mapIndexed { index, elem ->
- val elemTransformed = if (index == 0 && elem is Text) elem.copy(elem.body.trimStart()) else elem
- if (index == lastIndex && elemTransformed is Text) elemTransformed.copy(elemTransformed.body.trimEnd()) else elemTransformed
- }
-
- private val notLeafNodes = listOf(
- MarkdownTokenTypes.HORIZONTAL_RULE,
- MarkdownTokenTypes.HARD_LINE_BREAK,
- MarkdownTokenTypes.HTML_TAG,
- MarkdownTokenTypes.HTML_BLOCK_CONTENT
- )
-
- private fun ASTNode.isNotLeaf() = this is CompositeASTNode || this.type in notLeafNodes
-
- private fun List<ASTNode>.isNotLeaf(index: Int): Boolean =
- if (index in 0..this.lastIndex)
- this[index].isNotLeaf()
- else
- false
-
- private fun List<ASTNode>.mergeLeafASTNodes(): List<ASTNode> {
- val children: MutableList<ASTNode> = mutableListOf()
- var index = 0
- while (index <= this.lastIndex) {
- if (this.isNotLeaf(index)) {
- children += this[index]
- } else {
- val startOffset = this[index].startOffset
- val sIndex = index
- while (index < this.lastIndex) {
- if (this.isNotLeaf(index + 1) || this[index + 1].startOffset != this[index].endOffset) {
- children += mergedLeafNode(this, index, startOffset, sIndex)
- break
- }
- index++
- }
- if (index == this.lastIndex) {
- children += mergedLeafNode(this, index, startOffset, sIndex)
- }
- }
- index++
- }
- return children
- }
-
- private fun mergedLeafNode(nodes: List<ASTNode>, index: Int, startOffset: Int, sIndex: Int): LeafASTNode {
- val endOffset = nodes[index].endOffset
- val type = if (nodes.subList(sIndex, index)
- .any { it.type == MarkdownTokenTypes.CODE_LINE }
- ) MarkdownTokenTypes.CODE_LINE else MarkdownTokenTypes.TEXT
- return LeafASTNode(type, startOffset, endOffset)
- }
-
- private fun String.transform() = this
- .replace(Regex("\n\n+"), "") // Squashing new lines between paragraphs
- .replace(Regex("\n"), " ")
- .replace(Regex(" >+ +"), " ") // Replacement used in blockquotes, get rid of garbage
-
- private fun detailedException(baseMessage: String, node: ASTNode) =
- IllegalStateException(
- baseMessage + " in ${kdocLocation ?: "unspecified location"}, element starts from offset ${node.startOffset} and ends ${node.endOffset}: ${
- text.substring(
- node.startOffset,
- node.endOffset
- )
- }"
- )
-
-
- companion object {
- fun parseFromKDocTag(
- kDocTag: KDocTag?,
- externalDri: (String) -> DRI?,
- kdocLocation: String?,
- parseWithChildren: Boolean = true
- ): DocumentationNode {
- return if (kDocTag == null) {
- DocumentationNode(emptyList())
- } else {
- fun parseStringToDocNode(text: String) =
- MarkdownParser(externalDri, kdocLocation).parseStringToDocNode(text)
-
- fun pointedLink(tag: KDocTag): DRI? = (parseStringToDocNode("[${tag.getSubjectName()}]")).let {
- val link = it.children[0].children[0]
- if (link is DocumentationLink) link.dri else null
- }
-
- val allTags =
- listOf(kDocTag) + if (kDocTag.canHaveParent() && parseWithChildren) getAllKDocTags(findParent(kDocTag)) else emptyList()
- DocumentationNode(
- allTags.map {
- when (it.knownTag) {
- null -> if (it.name == null) Description(parseStringToDocNode(it.getContent())) else CustomTagWrapper(
- parseStringToDocNode(it.getContent()),
- it.name!!
- )
- KDocKnownTag.AUTHOR -> Author(parseStringToDocNode(it.getContent()))
- KDocKnownTag.THROWS -> {
- val dri = pointedLink(it)
- Throws(
- parseStringToDocNode(it.getContent()),
- dri?.fqDeclarationName() ?: it.getSubjectName().orEmpty(),
- dri,
- )
- }
- KDocKnownTag.EXCEPTION -> {
- val dri = pointedLink(it)
- Throws(
- parseStringToDocNode(it.getContent()),
- dri?.fqDeclarationName() ?: it.getSubjectName().orEmpty(),
- dri
- )
- }
- KDocKnownTag.PARAM -> Param(
- parseStringToDocNode(it.getContent()),
- it.getSubjectName().orEmpty()
- )
- KDocKnownTag.RECEIVER -> Receiver(parseStringToDocNode(it.getContent()))
- KDocKnownTag.RETURN -> Return(parseStringToDocNode(it.getContent()))
- KDocKnownTag.SEE -> {
- val dri = pointedLink(it)
- See(
- parseStringToDocNode(it.getContent()),
- dri?.fqDeclarationName() ?: it.getSubjectName().orEmpty(),
- dri,
- )
- }
- KDocKnownTag.SINCE -> Since(parseStringToDocNode(it.getContent()))
- KDocKnownTag.CONSTRUCTOR -> Constructor(parseStringToDocNode(it.getContent()))
- KDocKnownTag.PROPERTY -> Property(
- parseStringToDocNode(it.getContent()),
- it.getSubjectName().orEmpty()
- )
- KDocKnownTag.SAMPLE -> Sample(
- parseStringToDocNode(it.getContent()),
- it.getSubjectName().orEmpty()
- )
- KDocKnownTag.SUPPRESS -> Suppress(parseStringToDocNode(it.getContent()))
- }
- }
- )
- }
- }
-
- //Horrible hack but since link resolution is passed as a function i am not able to resolve them otherwise
- @kotlin.Suppress("DeprecatedCallableAddReplaceWith")
- @Deprecated("This function makes wrong assumptions and is missing a lot of corner cases related to generics, " +
- "parameters and static members. This is not supposed to be public API and will not be supported in the future")
- fun DRI.fqName(): String? = "$packageName.$classNames".takeIf { packageName != null && classNames != null }
-
- private fun DRI.fqDeclarationName(): String? {
- if (this.target !is PointingToDeclaration) {
- return null
- }
- return listOfNotNull(this.packageName, this.classNames, this.callable?.name)
- .joinToString(separator = ".")
- .takeIf { it.isNotBlank() }
- }
-
- private fun findParent(kDoc: PsiElement): PsiElement =
- if (kDoc.canHaveParent()) findParent(kDoc.parent) else kDoc
-
- private fun PsiElement.canHaveParent(): Boolean = this is KDocSection && knownTag != KDocKnownTag.PROPERTY
-
- private fun getAllKDocTags(kDocImpl: PsiElement): List<KDocTag> =
- kDocImpl.children.filterIsInstance<KDocTag>().filterNot { it is KDocSection } + kDocImpl.children.flatMap {
- getAllKDocTags(it)
- }
- }
-}
-
diff --git a/plugins/base/src/main/kotlin/parsers/Parser.kt b/plugins/base/src/main/kotlin/parsers/Parser.kt
deleted file mode 100644
index af07ec53..00000000
--- a/plugins/base/src/main/kotlin/parsers/Parser.kt
+++ /dev/null
@@ -1,131 +0,0 @@
-package org.jetbrains.dokka.base.parsers
-
-import org.jetbrains.dokka.model.doc.*
-import org.jetbrains.dokka.model.doc.Deprecated
-import org.jetbrains.dokka.model.doc.Suppress
-
-abstract class Parser {
-
- abstract fun parseStringToDocNode(extractedString: String): DocTag
-
- abstract fun preparse(text: String): String
-
- open fun parse(text: String): DocumentationNode =
- DocumentationNode(extractTagsToListOfPairs(preparse(text)).map { (tag, content) -> parseTagWithBody(tag, content) })
-
- open fun parseTagWithBody(tagName: String, content: String): TagWrapper =
- when (tagName) {
- "description" -> Description(parseStringToDocNode(content))
- "author" -> Author(parseStringToDocNode(content))
- "version" -> Version(parseStringToDocNode(content))
- "since" -> Since(parseStringToDocNode(content))
- "see" -> See(
- parseStringToDocNode(content.substringAfter(' ')),
- content.substringBefore(' '),
- null
- )
- "param" -> Param(
- parseStringToDocNode(content.substringAfter(' ')),
- content.substringBefore(' ')
- )
- "property" -> Property(
- parseStringToDocNode(content.substringAfter(' ')),
- content.substringBefore(' ')
- )
- "return" -> Return(parseStringToDocNode(content))
- "constructor" -> Constructor(parseStringToDocNode(content))
- "receiver" -> Receiver(parseStringToDocNode(content))
- "throws", "exception" -> Throws(
- parseStringToDocNode(content.substringAfter(' ')),
- content.substringBefore(' '),
- null
- )
- "deprecated" -> Deprecated(parseStringToDocNode(content))
- "sample" -> Sample(
- parseStringToDocNode(content.substringAfter(' ')),
- content.substringBefore(' ')
- )
- "suppress" -> Suppress(parseStringToDocNode(content))
- else -> CustomTagWrapper(parseStringToDocNode(content), tagName)
- }
-
- /**
- * KDoc parser from Kotlin compiler relies on a comment asterisk
- * So there is a mini parser here
- * TODO: at least to adapt [org.jetbrains.kotlin.kdoc.lexer.KDocLexer] to analyze KDoc without the asterisks and use it here
- */
- private fun extractTagsToListOfPairs(text: String): List<Pair<String, String>> =
- "description $text"
- .extractKDocSections()
- .map { content ->
- val contentWithEscapedAts = content.replace("\\@", "@")
- val (tag, body) = contentWithEscapedAts.split(" ", limit = 2)
- tag to body
- }
-
- /**
- * Ignore a doc tag inside code spans and blocks
- * @see org.jetbrains.kotlin.kdoc.psi.impl.KDocSection
- */
- private fun CharSequence.extractKDocSections(delimiter: String = "\n@"): List<String> {
- var countOfBackticks = 0
- var countOfTildes = 0
- var countOfBackticksInOpeningFence = 0
- var countOfTildesInOpeningFence = 0
-
- var isInCode = false
- val result = mutableListOf<String>()
- var rangeStart = 0
- var rangeEnd = 0
- var currentOffset = 0
- while (currentOffset < length) {
-
- when (get(currentOffset)) {
- '`' -> {
- countOfBackticks++
- countOfTildes = 0
- }
- '~' -> {
- countOfTildes++
- countOfBackticks = 0
- }
- else -> {
- if (isInCode) {
- // The closing code fence must be at least as long as the opening fence
- if(countOfBackticks >= countOfBackticksInOpeningFence
- || countOfTildes >= countOfTildesInOpeningFence)
- isInCode = false
- } else {
- // as per CommonMark spec, there can be any number of backticks for a code span, not only one or three
- if (countOfBackticks > 0) {
- isInCode = true
- countOfBackticksInOpeningFence = countOfBackticks
- countOfTildesInOpeningFence = Int.MAX_VALUE
- }
- // tildes are only for a code block, not code span
- if (countOfTildes >= 3) {
- isInCode = true
- countOfTildesInOpeningFence = countOfTildes
- countOfBackticksInOpeningFence = Int.MAX_VALUE
- }
- }
- countOfTildes = 0
- countOfBackticks = 0
- }
- }
- if (!isInCode && startsWith(delimiter, currentOffset)) {
- result.add(substring(rangeStart, rangeEnd))
- currentOffset += delimiter.length
- rangeStart = currentOffset
- rangeEnd = currentOffset
- continue
- }
-
- ++rangeEnd
- ++currentOffset
- }
- result.add(substring(rangeStart, rangeEnd))
- return result
- }
-
-}
diff --git a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt b/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt
deleted file mode 100644
index fed3f7eb..00000000
--- a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-package org.jetbrains.dokka.base.parsers.factories
-
-import org.jetbrains.dokka.model.doc.*
-import org.intellij.markdown.IElementType
-import org.intellij.markdown.MarkdownElementTypes
-import org.intellij.markdown.MarkdownTokenTypes
-import org.intellij.markdown.flavours.gfm.GFMElementTypes
-import org.intellij.markdown.flavours.gfm.GFMTokenTypes
-import org.jetbrains.dokka.base.translators.parseWithNormalisedSpaces
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.model.doc.DocTag.Companion.contentTypeParam
-
-object DocTagsFromIElementFactory {
-
- @Suppress("IMPLICIT_CAST_TO_ANY")
- fun getInstance(type: IElementType, children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap(), body: String? = null, dri: DRI? = null, keepFormatting: Boolean = false) =
- when(type) {
- MarkdownElementTypes.SHORT_REFERENCE_LINK,
- MarkdownElementTypes.FULL_REFERENCE_LINK,
- MarkdownElementTypes.INLINE_LINK -> if(dri == null) A(children, params) else DocumentationLink(dri, children, params)
- MarkdownElementTypes.STRONG -> B(children, params)
- MarkdownElementTypes.BLOCK_QUOTE -> BlockQuote(children, params)
- MarkdownElementTypes.CODE_SPAN -> CodeInline(children, params)
- MarkdownElementTypes.CODE_BLOCK,
- MarkdownElementTypes.CODE_FENCE -> CodeBlock(children, params)
- MarkdownElementTypes.ATX_1 -> H1(children, params)
- MarkdownElementTypes.ATX_2 -> H2(children, params)
- MarkdownElementTypes.ATX_3 -> H3(children, params)
- MarkdownElementTypes.ATX_4 -> H4(children, params)
- MarkdownElementTypes.ATX_5 -> H5(children, params)
- MarkdownElementTypes.ATX_6 -> H6(children, params)
- MarkdownElementTypes.EMPH -> I(children, params)
- MarkdownElementTypes.IMAGE -> Img(children, params)
- MarkdownElementTypes.LIST_ITEM -> Li(children, params)
- MarkdownElementTypes.ORDERED_LIST -> Ol(children, params)
- MarkdownElementTypes.UNORDERED_LIST -> Ul(children, params)
- MarkdownElementTypes.PARAGRAPH -> P(children, params)
- MarkdownTokenTypes.TEXT -> if (keepFormatting) Text(
- body.orEmpty(),
- children,
- params
- ) else {
- // corner case: there are only spaces between two Markdown nodes
- val containsOnlySpaces = body?.isNotEmpty() == true && body.all { it.isWhitespace() }
- if (containsOnlySpaces) Text(" ", children, params)
- else body?.parseWithNormalisedSpaces(renderWhiteCharactersAsSpaces = false).orEmpty()
- }
- MarkdownTokenTypes.HORIZONTAL_RULE -> HorizontalRule
- MarkdownTokenTypes.HARD_LINE_BREAK -> Br
- GFMElementTypes.STRIKETHROUGH -> Strikethrough(children, params)
- GFMElementTypes.TABLE -> Table(children, params)
- GFMElementTypes.HEADER -> Th(children, params)
- GFMElementTypes.ROW -> Tr(children, params)
- GFMTokenTypes.CELL -> Td(children, params)
- MarkdownElementTypes.MARKDOWN_FILE -> CustomDocTag(children, params, MarkdownElementTypes.MARKDOWN_FILE.name)
- MarkdownElementTypes.HTML_BLOCK,
- MarkdownTokenTypes.HTML_TAG,
- MarkdownTokenTypes.HTML_BLOCK_CONTENT -> Text(body.orEmpty(), params = params + contentTypeParam("html"))
- else -> CustomDocTag(children, params, type.name)
- }.let {
- @Suppress("UNCHECKED_CAST")
- when (it) {
- is List<*> -> it as List<DocTag>
- else -> listOf(it as DocTag)
- }
- }
-}
diff --git a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt b/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt
deleted file mode 100644
index 1af4e719..00000000
--- a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-package org.jetbrains.dokka.base.parsers.factories
-
-import org.jetbrains.dokka.model.doc.*
-import org.jetbrains.dokka.links.DRI
-import java.lang.NullPointerException
-
-object DocTagsFromStringFactory {
- fun getInstance(name: String, children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap(), body: String? = null, dri: DRI? = null) =
- when(name) {
- "a" -> A(children, params)
- "big" -> Big(children, params)
- "b" -> B(children, params)
- "blockquote" -> BlockQuote(children, params)
- "br" -> Br
- "cite" -> Cite(children, params)
- "code" -> if(params.isEmpty()) CodeInline(children, params) else CodeBlock(children, params)
- "dd" -> Dd(children, params)
- "dfn" -> Dfn(children, params)
- "dir" -> Dir(children, params)
- "div" -> Div(children, params)
- "dl" -> Dl(children, params)
- "dt" -> Dt(children, params)
- "Em" -> Em(children, params)
- "font" -> Font(children, params)
- "footer" -> Footer(children, params)
- "frame" -> Frame(children, params)
- "frameset" -> FrameSet(children, params)
- "h1" -> H1(children, params)
- "h2" -> H2(children, params)
- "h3" -> H3(children, params)
- "h4" -> H4(children, params)
- "h5" -> H5(children, params)
- "h6" -> H6(children, params)
- "head" -> Head(children, params)
- "header" -> Header(children, params)
- "html" -> Html(children, params)
- "i" -> I(children, params)
- "iframe" -> IFrame(children, params)
- "img" -> Img(children, params)
- "input" -> Input(children, params)
- "li" -> Li(children, params)
- "link" -> Link(children, params)
- "listing" -> Listing(children, params)
- "main" -> Main(children, params)
- "menu" -> Menu(children, params)
- "meta" -> Meta(children, params)
- "nav" -> Nav(children, params)
- "noframes" -> NoFrames(children, params)
- "noscript" -> NoScript(children, params)
- "ol" -> Ol(children, params)
- "p" -> P(children, params)
- "pre" -> Pre(children, params)
- "script" -> Script(children, params)
- "section" -> Section(children, params)
- "small" -> Small(children, params)
- "span" -> Span(children, params)
- "strong" -> Strong(children, params)
- "sub" -> Sub(children, params)
- "sup" -> Sup(children, params)
- "table" -> Table(children, params)
- "#text" -> Text(body ?: throw NullPointerException("Text body should be at least empty string passed to DocNodes factory!"), children, params)
- "tBody" -> TBody(children, params)
- "td" -> Td(children, params)
- "tFoot" -> TFoot(children, params)
- "th" -> Th(children, params)
- "tHead" -> THead(children, params)
- "title" -> Title(children, params)
- "tr" -> Tr(children, params)
- "tt" -> Tt(children, params)
- "u" -> U(children, params)
- "ul" -> Ul(children, params)
- "var" -> Var(children, params)
- "documentationlink" -> DocumentationLink(dri ?: throw NullPointerException("DRI cannot be passed null while constructing documentation link!"), children, params)
- "hr" -> HorizontalRule
- else -> CustomDocTag(children, params, name)
- }
-}
diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt
deleted file mode 100644
index f642c374..00000000
--- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-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
deleted file mode 100644
index ee67fad1..00000000
--- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentation.kt
+++ /dev/null
@@ -1,11 +0,0 @@
-package org.jetbrains.dokka.base.parsers.moduleAndPackage
-
-import org.jetbrains.dokka.model.doc.DocumentationNode
-
-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
deleted file mode 100644
index 06fef72c..00000000
--- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment.kt
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.jetbrains.dokka.base.parsers.moduleAndPackage
-
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.*
-
-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
deleted file mode 100644
index fa6c653e..00000000
--- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-package org.jetbrains.dokka.base.parsers.moduleAndPackage
-
-import org.jetbrains.dokka.analysis.DokkaResolutionFacade
-import org.jetbrains.dokka.analysis.from
-import org.jetbrains.dokka.base.parsers.MarkdownParser
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Module
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Package
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.model.doc.DocumentationNode
-import org.jetbrains.dokka.utilities.DokkaLogger
-import org.jetbrains.kotlin.descriptors.ClassDescriptor
-import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
-import org.jetbrains.kotlin.descriptors.FunctionDescriptor
-import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
-import org.jetbrains.kotlin.name.FqName
-import org.jetbrains.kotlin.name.Name
-
-fun interface ModuleAndPackageDocumentationParsingContext {
- fun markdownParserFor(fragment: ModuleAndPackageDocumentationFragment, location: String): MarkdownParser
-}
-
-internal fun ModuleAndPackageDocumentationParsingContext.parse(
- fragment: ModuleAndPackageDocumentationFragment
-): DocumentationNode {
- return markdownParserFor(fragment, fragment.source.sourceDescription).parse(fragment.documentation)
-}
-
-fun ModuleAndPackageDocumentationParsingContext(
- logger: DokkaLogger,
- facade: DokkaResolutionFacade? = null
-) = ModuleAndPackageDocumentationParsingContext { fragment, sourceLocation ->
- val descriptor = when (fragment.classifier) {
- Module -> facade?.moduleDescriptor?.getPackage(FqName.topLevel(Name.identifier("")))
- Package -> facade?.moduleDescriptor?.getPackage(FqName(fragment.name))
- }
-
- val externalDri = { link: String ->
- try {
- if (facade != null && descriptor != null) {
- resolveKDocLink(
- facade.resolveSession.bindingContext,
- facade,
- descriptor,
- null,
- link.split('.')
- ).sorted().firstOrNull()?.let { DRI.from(it) }
- } else null
- } catch (e1: IllegalArgumentException) {
- logger.warn("Couldn't resolve link for $link")
- null
- }
- }
-
- MarkdownParser(externalDri = externalDri, sourceLocation)
-}
-
-private fun Collection<DeclarationDescriptor>.sorted() = sortedWith(
- compareBy(
- { it is ClassDescriptor },
- { (it as? FunctionDescriptor)?.name },
- { (it as? FunctionDescriptor)?.valueParameters?.size },
- { (it as? FunctionDescriptor)?.valueParameters?.joinToString { it.type.toString() } }
- )
-)
diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt
deleted file mode 100644
index 9514adb4..00000000
--- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package org.jetbrains.dokka.base.parsers.moduleAndPackage
-
-import java.io.File
-
-abstract class ModuleAndPackageDocumentationSource {
- abstract val sourceDescription: String
- abstract val documentation: String
- override fun toString(): String = 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
deleted file mode 100644
index db342042..00000000
--- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentation.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.jetbrains.dokka.base.parsers.moduleAndPackage
-
-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
deleted file mode 100644
index d3381901..00000000
--- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.jetbrains.dokka.base.parsers.moduleAndPackage
-
-import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.*
-import java.io.File
-
-
-fun parseModuleAndPackageDocumentationFragments(source: File): List<ModuleAndPackageDocumentationFragment> {
- return parseModuleAndPackageDocumentationFragments(ModuleAndPackageDocumentationFile(source))
-}
-
-fun parseModuleAndPackageDocumentationFragments(
- source: ModuleAndPackageDocumentationSource
-): List<ModuleAndPackageDocumentationFragment> {
- 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)
-
- val classifier = when (classifierAndName[0].trim()) {
- "Module" -> Module
- "Package" -> Package
- else -> throw IllegalStateException(
- """Unexpected classifier: "${classifierAndName[0]}", expected either "Module" or "Package".
- |For more information consult the specification: https://kotlinlang.org/docs/dokka-module-and-package-docs.html""".trimMargin()
- )
- }
-
- if (classifierAndName.size != 2 && classifier == Module) {
- throw IllegalModuleAndPackageDocumentation(source, "Missing Module name")
- }
-
- val name = classifierAndName.getOrNull(1)?.trim().orEmpty()
- if (classifier == Package && name.contains(Regex("\\s"))) {
- throw IllegalModuleAndPackageDocumentation(
- source, "Package name cannot contain whitespace in '$firstLine'"
- )
- }
-
- return ModuleAndPackageDocumentationFragment(
- name = name,
- classifier = classifier,
- documentation = firstLineAndDocumentation.getOrNull(1)?.trim().orEmpty(),
- source = source
- )
-}