diff options
Diffstat (limited to 'plugins/base/src/main/kotlin/parsers')
-rw-r--r-- | plugins/base/src/main/kotlin/parsers/MarkdownParser.kt | 91 | ||||
-rw-r--r-- | plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt | 16 |
2 files changed, 55 insertions, 52 deletions
diff --git a/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt b/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt index 34dceeea..4787c091 100644 --- a/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt +++ b/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt @@ -12,24 +12,8 @@ import org.intellij.markdown.flavours.gfm.GFMFlavourDescriptor import org.intellij.markdown.flavours.gfm.GFMTokenTypes import org.jetbrains.dokka.base.parsers.factories.DocTagsFromIElementFactory import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.doc.Author -import org.jetbrains.dokka.model.doc.Constructor -import org.jetbrains.dokka.model.doc.CustomTagWrapper -import org.jetbrains.dokka.model.doc.Description -import org.jetbrains.dokka.model.doc.DocTag -import org.jetbrains.dokka.model.doc.DocumentationLink -import org.jetbrains.dokka.model.doc.DocumentationNode -import org.jetbrains.dokka.model.doc.Param -import org.jetbrains.dokka.model.doc.Property -import org.jetbrains.dokka.model.doc.Receiver -import org.jetbrains.dokka.model.doc.Return -import org.jetbrains.dokka.model.doc.Sample -import org.jetbrains.dokka.model.doc.See -import org.jetbrains.dokka.model.doc.Since +import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.model.doc.Suppress -import org.jetbrains.dokka.model.doc.TagWrapper -import org.jetbrains.dokka.model.doc.Text -import org.jetbrains.dokka.model.doc.Throws import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag @@ -50,7 +34,12 @@ open class MarkdownParser( val markdownAstRoot = IntellijMarkdownParser(gfmFlavourDescriptor).buildMarkdownTreeFromString(extractedString) destinationLinksMap = getAllDestinationLinks(extractedString, markdownAstRoot).toMap() text = extractedString - return visitNode(markdownAstRoot) + + 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") @@ -82,7 +71,7 @@ open class MarkdownParser( node.type, visitNode(node.children.find { it.type == MarkdownTokenTypes.ATX_CONTENT } ?: throw detailedException("Wrong AST Tree. Header does not contain expected content", node) - ).children + ).flatMap { it.children } ) private fun horizontalRulesHandler(node: ASTNode) = @@ -110,7 +99,7 @@ open class MarkdownParser( .evaluateChildren() ) - private fun listsHandler(node: ASTNode): DocTag { + private fun listsHandler(node: ASTNode): List<DocTag> { val children = node.children.filterIsInstance<ListItemCompositeNode>().flatMap { if (it.children.last().type in listOf( @@ -129,7 +118,7 @@ open class MarkdownParser( node.type, children = children - .map { + .flatMap { if (it.type == MarkdownElementTypes.LIST_ITEM) DocTagsFromIElementFactory.getInstance( it.type, @@ -178,7 +167,7 @@ open class MarkdownParser( node.children.filterIsInstance<CompositeASTNode>().flatMap { getAllDestinationLinks(text, it) } - private fun referenceLinksHandler(node: ASTNode): DocTag { + 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 @@ -190,7 +179,7 @@ open class MarkdownParser( return linksHandler(linkText, link) } - private fun inlineLinksHandler(node: ASTNode): DocTag { + 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 } @@ -208,13 +197,13 @@ open class MarkdownParser( children = node.children.evaluateChildren() ) - private fun autoLinksHandler(node: ASTNode): DocTag { + 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): DocTag { + private fun linksHandler(linkText: ASTNode, link: String?, linkTitle: ASTNode? = null): List<DocTag> { val dri: DRI? = link?.let { resolveDRI(it) } val linkOrEmpty = link ?: "" val linkTextString = @@ -247,9 +236,10 @@ open class MarkdownParser( body = text.substring(node.startOffset, node.endOffset) ) - private fun textHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( + private fun textHandler(node: ASTNode, keepAllFormatting: Boolean) = DocTagsFromIElementFactory.getInstance( MarkdownTokenTypes.TEXT, - body = text.substring(node.startOffset, node.endOffset).transform() + body = text.substring(node.startOffset, node.endOffset).transform(), + keepFormatting = keepAllFormatting ) private fun strikeThroughHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( @@ -284,7 +274,7 @@ open class MarkdownParser( false } - private fun imagesHandler(node: ASTNode): DocTag = + 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 } @@ -304,7 +294,7 @@ open class MarkdownParser( } - private fun rawHtmlHandler(node: ASTNode): DocTag = + private fun rawHtmlHandler(node: ASTNode): List<DocTag> = DocTagsFromIElementFactory.getInstance( node.type, body = text.substring(node.startOffset, node.endOffset) @@ -313,12 +303,9 @@ open class MarkdownParser( private fun codeSpansHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( node.type, - children = listOf( - DocTagsFromIElementFactory.getInstance( - MarkdownTokenTypes.TEXT, - body = text.substring(node.startOffset + 1, node.endOffset - 1).replace('\n', ' ').trimIndent() - ) - + children = DocTagsFromIElementFactory.getInstance( + MarkdownTokenTypes.TEXT, + body = text.substring(node.startOffset + 1, node.endOffset - 1).replace('\n', ' ').trimIndent() ) ) @@ -334,7 +321,7 @@ open class MarkdownParser( LeafASTNode(MarkdownTokenTypes.HARD_LINE_BREAK, 0, 0) else it - }.evaluateChildren(), + }.evaluateChildren(keepAllFormatting = true), params = node .children .find { it.type == MarkdownTokenTypes.FENCE_LANG } @@ -343,7 +330,7 @@ open class MarkdownParser( ) private fun codeBlocksHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance(node.type, children = node.children.mergeLeafASTNodes().map { + DocTagsFromIElementFactory.getInstance(node.type, children = node.children.mergeLeafASTNodes().flatMap { DocTagsFromIElementFactory.getInstance( MarkdownTokenTypes.TEXT, body = text.substring(it.startOffset, it.endOffset) @@ -356,7 +343,7 @@ open class MarkdownParser( children = node.children.evaluateChildren() ) - private fun visitNode(node: ASTNode): DocTag = + private fun visitNode(node: ASTNode, keepAllFormatting: Boolean = false): List<DocTag> = when (node.type) { MarkdownElementTypes.ATX_1, MarkdownElementTypes.ATX_2, @@ -389,7 +376,7 @@ open class MarkdownParser( MarkdownTokenTypes.CODE_FENCE_CONTENT, MarkdownTokenTypes.CODE_LINE, -> codeLineHandler(node) - MarkdownTokenTypes.TEXT -> textHandler(node) + MarkdownTokenTypes.TEXT -> textHandler(node, keepAllFormatting) MarkdownElementTypes.MARKDOWN_FILE -> markdownFileHandler(node) GFMElementTypes.STRIKETHROUGH -> strikeThroughHandler(node) GFMElementTypes.TABLE -> tableHandler(node) @@ -402,18 +389,22 @@ open class MarkdownParser( private fun List<ASTNode>.filterTabSeparators() = this.filterNot { it.type == GFMTokenTypes.TABLE_SEPARATOR } - private fun List<ASTNode>.evaluateChildren(): List<DocTag> = - this.removeUselessTokens().swapImagesThatShouldBeLinks().mergeLeafASTNodes().map { visitNode(it) } + private fun List<ASTNode>.evaluateChildren(keepAllFormatting: Boolean = false): List<DocTag> = + this.removeUselessTokens().swapImagesThatShouldBeLinks(keepAllFormatting).mergeLeafASTNodes().flatMap { visitNode(it, keepAllFormatting) } - private fun List<ASTNode>.swapImagesThatShouldBeLinks(): List<ASTNode> = - 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>.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) + } } } diff --git a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt b/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt index 9ee11732..a3cbcc2e 100644 --- a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt +++ b/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt @@ -6,12 +6,15 @@ 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 import java.lang.NullPointerException object DocTagsFromIElementFactory { - fun getInstance(type: IElementType, children: List<DocTag> = emptyList(), params: Map<String, String> = emptyMap(), body: String? = null, dri: DRI? = null) = + + @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, @@ -33,7 +36,11 @@ object DocTagsFromIElementFactory { MarkdownElementTypes.ORDERED_LIST -> Ol(children, params) MarkdownElementTypes.UNORDERED_LIST -> Ul(children, params) MarkdownElementTypes.PARAGRAPH -> P(children, params) - MarkdownTokenTypes.TEXT -> Text(body ?: throw NullPointerException("Text body should be at least empty string passed to DocNodes factory!"), children, params ) + MarkdownTokenTypes.TEXT -> if (keepFormatting) Text( + body.orEmpty(), + children, + params + ) else body?.parseWithNormalisedSpaces(renderWhiteCharactersAsSpaces = false).orEmpty() MarkdownTokenTypes.HORIZONTAL_RULE -> HorizontalRule MarkdownTokenTypes.HARD_LINE_BREAK -> Br GFMElementTypes.STRIKETHROUGH -> Strikethrough(children, params) @@ -46,5 +53,10 @@ object DocTagsFromIElementFactory { MarkdownTokenTypes.HTML_TAG, MarkdownTokenTypes.HTML_BLOCK_CONTENT -> Text(body.orEmpty(), params = params + contentTypeParam("html")) else -> CustomDocTag(children, params, type.name) + }.let { + when (it) { + is List<*> -> it as List<DocTag> + else -> listOf(it as DocTag) + } } } |