aboutsummaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
authorSimon Ogorodnik <Simon.Ogorodnik@jetbrains.com>2017-06-05 18:28:49 +0300
committerSimon Ogorodnik <Simon.Ogorodnik@jetbrains.com>2017-06-07 17:19:45 +0300
commitfff865cb03d406a07190ad15a9cbf81cb4cfa36a (patch)
tree9f345ea4e34ef4e1872f424c846f129681404cea /core/src
parent6ca62b8b7b0bbe5df26e7e66b827926f9b1417d3 (diff)
downloaddokka-fff865cb03d406a07190ad15a9cbf81cb4cfa36a.tar.gz
dokka-fff865cb03d406a07190ad15a9cbf81cb4cfa36a.tar.bz2
dokka-fff865cb03d406a07190ad15a9cbf81cb4cfa36a.zip
Fix StringOutOfBoundsException in link mapping
#167 #KT-18213 fixed
Diffstat (limited to 'core/src')
-rw-r--r--core/src/main/kotlin/Kotlin/ContentBuilder.kt26
-rw-r--r--core/src/main/kotlin/Kotlin/DescriptorDocumentationParser.kt6
-rw-r--r--core/src/main/kotlin/Model/PackageDocs.kt10
-rw-r--r--core/src/test/kotlin/TestAPI.kt1
-rw-r--r--core/src/test/kotlin/format/PackageDocsTest.kt47
-rw-r--r--core/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker1
6 files changed, 69 insertions, 22 deletions
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