From ba05c354a353ac3145c775e190b96b2bbe3c1227 Mon Sep 17 00:00:00 2001 From: Andrzej Ratajczak Date: Thu, 27 Aug 2020 12:47:31 +0200 Subject: Refactor DocTags and add markdown tests --- .../base/src/main/kotlin/parsers/MarkdownParser.kt | 83 ++++++++------ .../factories/DocTagsFromIElementFactory.kt | 4 +- .../base/src/test/kotlin/markdown/ParserTest.kt | 119 ++++++++++++++++++++- 3 files changed, 174 insertions(+), 32 deletions(-) (limited to 'plugins/base') diff --git a/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt b/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt index 8c7f9257..a74f2b05 100644 --- a/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt +++ b/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt @@ -1,9 +1,7 @@ package org.jetbrains.dokka.base.parsers import com.intellij.psi.PsiElement -import org.intellij.markdown.MarkdownElementType import org.intellij.markdown.MarkdownElementTypes -import org.intellij.markdown.MarkdownElementTypes.LINK_DESTINATION import org.intellij.markdown.MarkdownTokenTypes import org.intellij.markdown.ast.ASTNode import org.intellij.markdown.ast.CompositeASTNode @@ -208,6 +206,46 @@ class MarkdownParser( } } + private fun codeLineHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( + MarkdownElementTypes.CODE_BLOCK, + body = text.substring(node.startOffset, node.endOffset) + ) + + private fun textHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( + MarkdownTokenTypes.TEXT, + body = text.substring(node.startOffset, node.endOffset).transform() + ) + + private fun markdownFileHandler(node: ASTNode) = if (node.children.size == 1) + visitNode(node.children.first()) + else + defaultHandler(node) + + private fun strikeThroughHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( + GFMElementTypes.STRIKETHROUGH, + body = text.substring(node.startOffset, node.endOffset).transform() + ) + + private fun tableHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( + GFMElementTypes.TABLE, + children = node.children.filterTabSeparators().evaluateChildren() + ) + + private fun headerHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( + GFMElementTypes.HEADER, + children = node.children.filterTabSeparators().evaluateChildren() + ) + + private fun rowHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( + GFMElementTypes.ROW, + children = node.children.filterTabSeparators().evaluateChildren() + ) + + private fun cellHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( + GFMTokenTypes.CELL, + children = node.children.filterTabSeparators().evaluateChildren().trimSurroundingTokensIfText() + ) + private fun String.isRemoteLink() = try { URL(this) true @@ -304,34 +342,14 @@ class MarkdownParser( MarkdownElementTypes.IMAGE -> imagesHandler(node) MarkdownTokenTypes.HARD_LINE_BREAK -> DocTagsFromIElementFactory.getInstance(node.type) MarkdownTokenTypes.CODE_FENCE_CONTENT, - MarkdownTokenTypes.CODE_LINE -> DocTagsFromIElementFactory.getInstance( - MarkdownElementTypes.CODE_BLOCK, - body = text.substring(node.startOffset, node.endOffset) - ) - MarkdownTokenTypes.TEXT -> DocTagsFromIElementFactory.getInstance( - MarkdownTokenTypes.TEXT, - body = text.substring(node.startOffset, node.endOffset).transform() - ) - MarkdownElementTypes.MARKDOWN_FILE -> if (node.children.size == 1) visitNode(node.children.first()) else defaultHandler( - node - ) - GFMElementTypes.STRIKETHROUGH -> DocTagsFromIElementFactory.getInstance( - GFMElementTypes.STRIKETHROUGH, - body = text - .substring(node.startOffset, node.endOffset).transform() - ) - GFMElementTypes.TABLE -> DocTagsFromIElementFactory.getInstance( - GFMElementTypes.TABLE, - children = node.children.filterTabSeparators().evaluateChildren() - ) - GFMElementTypes.HEADER -> DocTagsFromIElementFactory.getInstance( - GFMElementTypes.HEADER, - children = node.children.filterTabSeparators().evaluateChildren() - ) - GFMElementTypes.ROW -> DocTagsFromIElementFactory.getInstance( - GFMElementTypes.ROW, - children = node.children.filterTabSeparators().evaluateChildren() - ) + MarkdownTokenTypes.CODE_LINE -> codeLineHandler(node) + MarkdownTokenTypes.TEXT -> textHandler(node) + 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) } @@ -349,6 +367,11 @@ class MarkdownParser( )) } + private fun List.trimSurroundingTokensIfText() = mapIndexed { index, elem -> + val elemTransformed = if (index == 0 && elem is Text) elem.copy(elem.body.trimStart()) else elem + if (index == size - 1 && elemTransformed is Text) elemTransformed.copy(elemTransformed.body.trimEnd()) else elemTransformed + } + private val notLeafNodes = listOf(MarkdownTokenTypes.HORIZONTAL_RULE, MarkdownTokenTypes.HARD_LINE_BREAK) private fun List.isNotLeaf(index: Int): Boolean = diff --git a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt b/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt index 277fd35e..58b4b223 100644 --- a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt +++ b/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt @@ -5,6 +5,7 @@ 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.links.DRI import java.lang.NullPointerException @@ -38,6 +39,7 @@ object DocTagsFromIElementFactory { GFMElementTypes.TABLE -> Table(children, params) GFMElementTypes.HEADER -> Th(children, params) GFMElementTypes.ROW -> Tr(children, params) + GFMTokenTypes.CELL -> Td(children, params) else -> CustomDocTag(children, params) } -} \ No newline at end of file +} diff --git a/plugins/base/src/test/kotlin/markdown/ParserTest.kt b/plugins/base/src/test/kotlin/markdown/ParserTest.kt index e127afc2..268af405 100644 --- a/plugins/base/src/test/kotlin/markdown/ParserTest.kt +++ b/plugins/base/src/test/kotlin/markdown/ParserTest.kt @@ -1169,7 +1169,7 @@ class ParserTest : KDocTest() { } @Test - fun image(){ + fun image() { val kdoc = "![Sample image](https://www.google.pl/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png)" val expectedDocumentationNode = DocumentationNode( listOf( @@ -1190,5 +1190,122 @@ class ParserTest : KDocTest() { ) executeTest(kdoc, expectedDocumentationNode) } + + @Test + fun `Bold + italic + link`() { + val kdoc = "It's very easy to make some words **bold** and other words *italic* with Markdown.\n" + + "You can even [link to Google!](http://google.com)" + val expectedDocumentationNode = DocumentationNode( + listOf( + Description( + P( + listOf( + Text("It's very easy to make some words "), + B(listOf(Text("bold"))), + Text(" and other words "), + I(listOf(Text("italic"))), + Text(" with Markdown. You can even "), + A(listOf(Text("link to Google!")), mapOf("href" to "http://google.com")) + ) + ) + ) + ) + ) + executeTest(kdoc, expectedDocumentationNode) + } + + @Test + fun `Codeblock from indent`() { + val kdoc = "Here is some example how to use conditional instructions:\n\n" + + " val x = 1\n" + + " val y = 2\n" + + " if (x == 1) {\n" + + " println(y)\n" + + " }" + val expectedDocumentationNode = DocumentationNode( + listOf( + Description( + P( + listOf( + P(listOf(Text("Here is some example how to use conditional instructions:"))), + CodeBlock( + listOf( + Text( + " val x = 1\n" + + " val y = 2\n" + + " if (x == 1) {\n" + + " println(y)\n" + + " }" + ) + ) + ) + ) + ) + ) + ) + ) + executeTest(kdoc, expectedDocumentationNode) + } + + @Test + fun `Table`() { + val kdoc = "First Header | Second Header\n" + + "------------ | -------------\n" + + "Content from cell 1 | Content from cell 2\n" + + "Content in the first column | Content in the second column" + val expectedDocumentationNode = DocumentationNode( + listOf( + Description( + Table( + listOf( + Th( + listOf( + Td( + listOf( + Text("First Header") + ) + ), + Td( + listOf( + Text("Second Header") + ) + ) + ) + ), + Tr( + listOf( + Td( + listOf( + Text("Content from cell 1") + ) + ), + Td( + listOf( + Text("Content from cell 2") + ) + ) + ) + ), + Tr( + listOf( + Td( + listOf( + Text("Content in the first column") + ) + ), + Td( + listOf( + Text("Content in the second column") + ) + ) + ) + ) + ) + ) + ) + ) + ) + executeTest(kdoc, expectedDocumentationNode) + } } -- cgit