diff options
-rw-r--r-- | core/build.gradle | 1 | ||||
-rw-r--r-- | core/src/main/kotlin/Kotlin/ContentBuilder.kt | 26 | ||||
-rw-r--r-- | core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt | 6 | ||||
-rw-r--r-- | core/src/main/kotlin/Model/PackageDocs.kt | 10 | ||||
-rw-r--r-- | core/src/test/kotlin/TestAPI.kt | 1 | ||||
-rw-r--r-- | core/src/test/kotlin/format/PackageDocsTest.kt | 47 | ||||
-rw-r--r-- | core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker | 1 | ||||
-rw-r--r-- | core/testdata/packagedocs/referenceLinks.kotlin.md | 7 | ||||
-rw-r--r-- | core/testdata/packagedocs/referenceLinks.md | 17 | ||||
-rw-r--r-- | core/testdata/packagedocs/referenceLinks.module.md | 9 |
10 files changed, 103 insertions, 22 deletions
diff --git a/core/build.gradle b/core/build.gradle index 08be76c0..274ea466 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -51,5 +51,6 @@ dependencies { testCompile group: 'junit', name: 'junit', version: '4.12' testCompile group: 'org.jetbrains.kotlin', name: 'kotlin-test-junit', version: kotlin_version + testCompile "com.nhaarman:mockito-kotlin-kt1.1:1.5.0" } diff --git a/core/src/main/kotlin/Kotlin/ContentBuilder.kt b/core/src/main/kotlin/Kotlin/ContentBuilder.kt index b7b7a044..771bc44b 100644 --- a/core/src/main/kotlin/Kotlin/ContentBuilder.kt +++ b/core/src/main/kotlin/Kotlin/ContentBuilder.kt @@ -6,25 +6,27 @@ import org.intellij.markdown.html.entities.EntityConverter import org.intellij.markdown.parser.LinkMap import java.util.* -fun buildContent(tree: MarkdownNode, linkResolver: (String) -> ContentBlock, inline: Boolean = false): MutableContent { +class LinkResolver(private val linkMap: LinkMap, private val contentFactory: (String) -> ContentBlock) { + fun getLinkInfo(refLabel: String) = linkMap.getLinkInfo(refLabel) + fun resolve(href: String): ContentBlock = contentFactory(href) +} + +fun buildContent(tree: MarkdownNode, linkResolver: LinkResolver, inline: Boolean = false): MutableContent { val result = MutableContent() if (inline) { buildInlineContentTo(tree, result, linkResolver) - } - else { + } else { buildContentTo(tree, result, linkResolver) } return result } -fun buildContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (String) -> ContentBlock) { +fun buildContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: LinkResolver) { // println(tree.toTestString()) val nodeStack = ArrayDeque<ContentBlock>() nodeStack.push(target) - val linkMap = LinkMap.buildLinkMap(tree.node, tree.text) - - tree.visit {node, processChildren -> + tree.visit { node, processChildren -> val parent = nodeStack.peek() fun appendNodeWithChildren(content: ContentBlock) { @@ -42,7 +44,7 @@ fun buildContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (Stri MarkdownElementTypes.ATX_6 -> appendNodeWithChildren(ContentHeading(6)) MarkdownElementTypes.UNORDERED_LIST -> appendNodeWithChildren(ContentUnorderedList()) MarkdownElementTypes.ORDERED_LIST -> appendNodeWithChildren(ContentOrderedList()) - MarkdownElementTypes.LIST_ITEM -> appendNodeWithChildren(ContentListItem()) + MarkdownElementTypes.LIST_ITEM -> appendNodeWithChildren(ContentListItem()) MarkdownElementTypes.EMPH -> appendNodeWithChildren(ContentEmphasis()) MarkdownElementTypes.STRONG -> appendNodeWithChildren(ContentStrong()) MarkdownElementTypes.CODE_SPAN -> { @@ -79,9 +81,9 @@ fun buildContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (Stri MarkdownElementTypes.FULL_REFERENCE_LINK -> { val labelElement = node.child(MarkdownElementTypes.LINK_LABEL) if (labelElement != null) { - val linkInfo = linkMap.getLinkInfo(labelElement.text) + val linkInfo = linkResolver.getLinkInfo(labelElement.text) val labelText = labelElement.getLabelText() - val link = linkInfo?.let { linkResolver(it.destination.toString()) } ?: linkResolver(labelText) + val link = linkInfo?.let { linkResolver.resolve(it.destination.toString()) } ?: linkResolver.resolve(labelText) val linkText = node.child(MarkdownElementTypes.LINK_TEXT) if (linkText != null) { renderLinkTextTo(linkText, link, linkResolver) @@ -168,14 +170,14 @@ private fun MarkdownNode.getLabelText() = children.filter { it.type == MarkdownT private fun keepEol(node: ContentNode) = node is ContentParagraph || node is ContentSection || node is ContentBlockCode private fun processingList(node: ContentNode) = node is ContentOrderedList || node is ContentUnorderedList -fun buildInlineContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (String) -> ContentBlock) { +fun buildInlineContentTo(tree: MarkdownNode, target: ContentBlock, linkResolver: LinkResolver) { val inlineContent = tree.children.singleOrNull { it.type == MarkdownElementTypes.PARAGRAPH }?.children ?: listOf(tree) inlineContent.forEach { buildContentTo(it, target, linkResolver) } } -fun renderLinkTextTo(tree: MarkdownNode, target: ContentBlock, linkResolver: (String) -> ContentBlock) { +fun renderLinkTextTo(tree: MarkdownNode, target: ContentBlock, linkResolver: LinkResolver) { val linkTextNodes = tree.children.drop(1).dropLast(1) linkTextNodes.forEach { buildContentTo(it, target, linkResolver) diff --git a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt index dd96bafa..eb8c12d0 100644 --- a/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt +++ b/core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt @@ -4,6 +4,7 @@ import com.google.inject.Inject import com.intellij.psi.PsiDocCommentOwner import com.intellij.psi.PsiNamedElement import com.intellij.psi.util.PsiTreeUtil +import org.intellij.markdown.parser.LinkMap import org.jetbrains.dokka.* import org.jetbrains.dokka.Samples.SampleProcessingService import org.jetbrains.kotlin.descriptors.* @@ -54,7 +55,8 @@ class DescriptorDocumentationParser kdocText += "\n" } val tree = parseMarkdown(kdocText) - val content = buildContent(tree, { href -> linkResolver.resolveContentLink(descriptor, href) }, inline) + val linkMap = LinkMap.buildLinkMap(tree.node, kdocText) + val content = buildContent(tree, LinkResolver(linkMap, { href -> linkResolver.resolveContentLink(descriptor, href) }), inline) if (kdoc is KDocSection) { val tags = kdoc.getTags() tags.forEach { @@ -67,7 +69,7 @@ class DescriptorDocumentationParser val section = content.addSection(javadocSectionDisplayName(it.name), it.getSubjectName()) val sectionContent = it.getContent() val markdownNode = parseMarkdown(sectionContent) - buildInlineContentTo(markdownNode, section, { href -> linkResolver.resolveContentLink(descriptor, href) }) + buildInlineContentTo(markdownNode, section, LinkResolver(linkMap, { href -> linkResolver.resolveContentLink(descriptor, href) })) } } } diff --git a/core/src/main/kotlin/Model/PackageDocs.kt b/core/src/main/kotlin/Model/PackageDocs.kt index d057d4d0..3b03324c 100644 --- a/core/src/main/kotlin/Model/PackageDocs.kt +++ b/core/src/main/kotlin/Model/PackageDocs.kt @@ -4,7 +4,8 @@ import com.google.inject.Inject import com.google.inject.Singleton import org.intellij.markdown.MarkdownElementTypes import org.intellij.markdown.MarkdownTokenTypes -import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyPackageDescriptor +import org.intellij.markdown.parser.LinkMap +import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import java.io.File @Singleton @@ -17,11 +18,12 @@ class PackageDocs val packageContent: Map<String, Content> get() = _packageContent - fun parse(fileName: String, linkResolveContext: List<LazyPackageDescriptor>) { + fun parse(fileName: String, linkResolveContext: List<PackageFragmentDescriptor>) { val file = File(fileName) if (file.exists()) { val text = file.readText() val tree = parseMarkdown(text) + val linkMap = LinkMap.buildLinkMap(tree.node, text) var targetContent: MutableContent = moduleContent tree.children.forEach { if (it.type == MarkdownElementTypes.ATX_1) { @@ -30,7 +32,7 @@ class PackageDocs targetContent = findTargetContent(headingText.trimStart()) } } else { - buildContentTo(it, targetContent, { resolveContentLink(it, linkResolveContext) }) + buildContentTo(it, targetContent, LinkResolver(linkMap, { resolveContentLink(it, linkResolveContext) })) } } } else { @@ -51,7 +53,7 @@ class PackageDocs private fun findOrCreatePackageContent(packageName: String) = _packageContent.getOrPut(packageName) { -> MutableContent() } - private fun resolveContentLink(href: String, linkResolveContext: List<LazyPackageDescriptor>): ContentBlock { + private fun resolveContentLink(href: String, linkResolveContext: List<PackageFragmentDescriptor>): ContentBlock { if (linkResolver != null) { linkResolveContext .asSequence() diff --git a/core/src/test/kotlin/TestAPI.kt b/core/src/test/kotlin/TestAPI.kt index e11274ea..4799cd93 100644 --- a/core/src/test/kotlin/TestAPI.kt +++ b/core/src/test/kotlin/TestAPI.kt @@ -189,6 +189,7 @@ fun verifyJavaOutput(path: String, } fun assertEqualsIgnoringSeparators(expectedFile: File, output: String) { + if (!expectedFile.exists()) expectedFile.createNewFile() val expectedText = expectedFile.readText().replace("\r\n", "\n") val actualText = output.replace("\r\n", "\n") diff --git a/core/src/test/kotlin/format/PackageDocsTest.kt b/core/src/test/kotlin/format/PackageDocsTest.kt index 2ff6e85f..a5547025 100644 --- a/core/src/test/kotlin/format/PackageDocsTest.kt +++ b/core/src/test/kotlin/format/PackageDocsTest.kt @@ -1,11 +1,16 @@ package org.jetbrains.dokka.tests.format -import org.jetbrains.dokka.ContentBlock -import org.jetbrains.dokka.ContentText -import org.jetbrains.dokka.DokkaConsoleLogger -import org.jetbrains.dokka.PackageDocs +import com.nhaarman.mockito_kotlin.any +import com.nhaarman.mockito_kotlin.doAnswer +import com.nhaarman.mockito_kotlin.eq +import com.nhaarman.mockito_kotlin.mock +import org.jetbrains.dokka.* +import org.jetbrains.dokka.tests.InMemoryLocationService +import org.jetbrains.dokka.tests.assertEqualsIgnoringSeparators +import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.junit.Assert.assertEquals import org.junit.Test +import java.io.File public class PackageDocsTest { @Test fun verifyParse() { @@ -15,4 +20,38 @@ public class PackageDocsTest { val block = (packageContent.children.single() as ContentBlock).children.first() as ContentText assertEquals("Core functions and types", block.text) } + + @Test fun testReferenceLinksInPackageDocs() { + val mockLinkResolver = mock<DeclarationLinkResolver> { + val exampleCom = "http://example.com" + on { tryResolveContentLink(any(), eq(exampleCom)) } doAnswer { ContentExternalLink(exampleCom) } + } + + val mockPackageDescriptor = mock<PackageFragmentDescriptor> {} + + val docs = PackageDocs(mockLinkResolver, DokkaConsoleLogger) + docs.parse("testdata/packagedocs/referenceLinks.md", listOf(mockPackageDescriptor)) + + checkMarkdownOutput(docs, "testdata/packagedocs/referenceLinks") + } + + fun checkMarkdownOutput(docs: PackageDocs, expectedFilePrefix: String) { + + val out = StringBuilder() + val outputBuilder = MarkdownOutputBuilder(out, InMemoryLocationService.root, InMemoryLocationService, KotlinLanguageService(), ".md", emptyList()) + fun checkOutput(content: Content, filePostfix: String) { + outputBuilder.appendContent(content) + val expectedFile = File(expectedFilePrefix + filePostfix) + assertEqualsIgnoringSeparators(expectedFile, out.toString()) + out.setLength(0) + } + + checkOutput(docs.moduleContent, ".module.md") + + docs.packageContent.forEach { + (name, content) -> + checkOutput(content, ".$name.md") + } + + } } diff --git a/core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 00000000..ca6ee9ce --- /dev/null +++ b/core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline
\ No newline at end of file diff --git a/core/testdata/packagedocs/referenceLinks.kotlin.md b/core/testdata/packagedocs/referenceLinks.kotlin.md new file mode 100644 index 00000000..ac7e4b48 --- /dev/null +++ b/core/testdata/packagedocs/referenceLinks.kotlin.md @@ -0,0 +1,7 @@ + + +Core functions and types +See [ref](http://example.com) +Also, [example](http://example.com) + +
\ No newline at end of file diff --git a/core/testdata/packagedocs/referenceLinks.md b/core/testdata/packagedocs/referenceLinks.md new file mode 100644 index 00000000..7583ee9d --- /dev/null +++ b/core/testdata/packagedocs/referenceLinks.md @@ -0,0 +1,17 @@ +# Module refLinks + +## Kotlin Standard Library + +The Kotlin standard library is a set of functions and types implementing idiomatic patterns when working with collections, +text and files. +See [ref] +Also, [example][ref] + +# Package kotlin + +Core functions and types +See [ref] +Also, [example][ref] + +<!-- Refs --> +[ref]: http://example.com diff --git a/core/testdata/packagedocs/referenceLinks.module.md b/core/testdata/packagedocs/referenceLinks.module.md new file mode 100644 index 00000000..ddbdbe2f --- /dev/null +++ b/core/testdata/packagedocs/referenceLinks.module.md @@ -0,0 +1,9 @@ + + +## Kotlin Standard Library + +The Kotlin standard library is a set of functions and types implementing idiomatic patterns when working with collections, +text and files. +See [ref](http://example.com) +Also, [example](http://example.com) + |