diff options
Diffstat (limited to 'plugins/base/src/main/kotlin')
14 files changed, 754 insertions, 42 deletions
diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index cf4ad88f..f1b0d969 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -1,6 +1,9 @@ +@file:Suppress("unused") + package org.jetbrains.dokka.base import org.jetbrains.dokka.CoreExtensions +import org.jetbrains.dokka.analysis.KotlinAnalysis import org.jetbrains.dokka.base.allModulePage.MultimodulePageCreator import org.jetbrains.dokka.base.renderers.* import org.jetbrains.dokka.base.renderers.html.* @@ -37,13 +40,19 @@ class DokkaBase : DokkaPlugin() { val externalLocationProviderFactory by extensionPoint<ExternalLocationProviderFactory>() val outputWriter by extensionPoint<OutputWriter>() val htmlPreprocessors by extensionPoint<PageTransformer>() + val kotlinAnalysis by extensionPoint<KotlinAnalysis>() + val descriptorToDocumentableTranslator by extending { - CoreExtensions.sourceToDocumentableTranslator with DefaultDescriptorToDocumentableTranslator + CoreExtensions.sourceToDocumentableTranslator providing { ctx -> + DefaultDescriptorToDocumentableTranslator(ctx.single(kotlinAnalysis)) + } } val psiToDocumentableTranslator by extending { - CoreExtensions.sourceToDocumentableTranslator with DefaultPsiToDocumentableTranslator + CoreExtensions.sourceToDocumentableTranslator providing { ctx -> + DefaultPsiToDocumentableTranslator(ctx.single(kotlinAnalysis)) + } } val documentableMerger by extending(isFallback = true) { @@ -69,7 +78,9 @@ class DokkaBase : DokkaPlugin() { } val modulesAndPackagesDocumentation by extending(isFallback = true) { - CoreExtensions.preMergeDocumentableTransformer providing ::ModuleAndPackageDocumentationTransformer + CoreExtensions.preMergeDocumentableTransformer providing { ctx -> + ModuleAndPackageDocumentationTransformer(ctx, ctx.single(kotlinAnalysis)) + } } val kotlinSignatureProvider by extending(isFallback = true) { @@ -124,6 +135,10 @@ class DokkaBase : DokkaPlugin() { CoreExtensions.renderer providing ::HtmlRenderer applyIf { format == "html" } } + val defaultKotlinAnalysis by extending(isFallback = true) { + kotlinAnalysis providing { ctx -> KotlinAnalysis(ctx) } + } + val locationProvider by extending(isFallback = true) { locationProviderFactory providing ::DefaultLocationProviderFactory } diff --git a/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt b/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt index ea1d8510..cdaa0274 100644 --- a/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt +++ b/plugins/base/src/main/kotlin/allModulePage/MultimodulePageCreator.kt @@ -9,7 +9,7 @@ import org.jetbrains.dokka.model.SourceSetData import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.model.doc.P import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.parsers.MarkdownParser +import org.jetbrains.dokka.base.parsers.MarkdownParser import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.transformers.pages.PageCreator diff --git a/plugins/base/src/main/kotlin/parsers/HtmlParser.kt b/plugins/base/src/main/kotlin/parsers/HtmlParser.kt new file mode 100644 index 00000000..ece3cf24 --- /dev/null +++ b/plugins/base/src/main/kotlin/parsers/HtmlParser.kt @@ -0,0 +1,89 @@ +package org.jetbrains.dokka.base.parsers + +import org.jetbrains.dokka.model.doc.* +import org.jetbrains.dokka.base.parsers.factories.DocTagsFromStringFactory +import org.jsoup.Jsoup +import org.jsoup.nodes.Node +import org.jsoup.select.NodeFilter +import org.jsoup.select.NodeTraversor + +class HtmlParser : Parser() { + + inner class NodeFilterImpl : NodeFilter { + + private val nodesCache: MutableMap<Int, MutableList<DocTag>> = mutableMapOf() + private var currentDepth = 0 + + fun collect(): DocTag = nodesCache[currentDepth]!![0] + + override fun tail(node: Node?, depth: Int): NodeFilter.FilterResult { + val nodeName = node!!.nodeName() + val nodeAttributes = node.attributes() + + if(nodeName in listOf("#document", "html", "head")) + return NodeFilter.FilterResult.CONTINUE + + val body: String + val params: Map<String, String> + + + if(nodeName != "#text") { + body = "" + params = nodeAttributes.map { it.key to it.value }.toMap() + } else { + body = nodeAttributes["#text"] + params = emptyMap() + } + + val docNode = if(depth < currentDepth) { + DocTagsFromStringFactory.getInstance(nodeName, nodesCache.getOrDefault(currentDepth, mutableListOf()).toList(), params, body).also { + nodesCache[currentDepth] = mutableListOf() + currentDepth = depth + } + } else { + DocTagsFromStringFactory.getInstance(nodeName, emptyList(), params, body) + } + + nodesCache.getOrDefault(depth, mutableListOf()) += docNode + return NodeFilter.FilterResult.CONTINUE + } + + override fun head(node: Node?, depth: Int): NodeFilter.FilterResult { + + val nodeName = node!!.nodeName() + + if(currentDepth < depth) { + currentDepth = depth + nodesCache[currentDepth] = mutableListOf() + } + + if(nodeName in listOf("#document", "html", "head")) + return NodeFilter.FilterResult.CONTINUE + + return NodeFilter.FilterResult.CONTINUE + } + } + + + private fun htmlToDocNode(string: String): DocTag { + val document = Jsoup.parse(string) + val nodeFilterImpl = NodeFilterImpl() + NodeTraversor.filter(nodeFilterImpl, document.root()) + return nodeFilterImpl.collect() + } + + private fun replaceLinksWithHrefs(javadoc: String): String = Regex("\\{@link .*?}").replace(javadoc) { + val split = it.value.dropLast(1).split(" ") + if(split.size !in listOf(2, 3)) + return@replace it.value + if(split.size == 3) + return@replace "<documentationlink href=\"${split[1]}\">${split[2]}</documentationlink>" + else + return@replace "<documentationlink href=\"${split[1]}\">${split[1]}</documentationlink>" + } + + override fun parseStringToDocNode(extractedString: String) = htmlToDocNode(extractedString) + override fun preparse(text: String) = replaceLinksWithHrefs(text) +} + + diff --git a/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt b/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt new file mode 100644 index 00000000..6075ef73 --- /dev/null +++ b/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt @@ -0,0 +1,419 @@ +package org.jetbrains.dokka.base.parsers + +import com.intellij.psi.PsiElement +import org.jetbrains.dokka.model.doc.* +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.jetbrains.dokka.analysis.DokkaResolutionFacade +import org.jetbrains.dokka.analysis.from +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.base.parsers.factories.DocTagsFromIElementFactory +import org.jetbrains.dokka.utilities.DokkaLogger +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink +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 org.intellij.markdown.parser.MarkdownParser as IntellijMarkdownParser + +class MarkdownParser( + private val resolutionFacade: DokkaResolutionFacade? = null, + private val declarationDescriptor: DeclarationDescriptor? = null, + private val logger: DokkaLogger +) : Parser() { + + inner class MarkdownVisitor(val text: String, val destinationLinksMap: Map<String, String>) { + + private fun headersHandler(node: ASTNode): DocTag = + DocTagsFromIElementFactory.getInstance( + node.type, + visitNode(node.children.find { it.type == MarkdownTokenTypes.ATX_CONTENT } + ?: throw IllegalStateException("Wrong AST Tree. ATX Header does not contain expected content")).children + ) + + private fun horizontalRulesHandler(node: ASTNode): DocTag = + DocTagsFromIElementFactory.getInstance(MarkdownTokenTypes.HORIZONTAL_RULE) + + private fun emphasisHandler(node: ASTNode): DocTag = + DocTagsFromIElementFactory.getInstance( + node.type, + children = listOf(visitNode(node.children[node.children.size / 2])) + ) + + private fun blockquotesHandler(node: ASTNode): DocTag = + DocTagsFromIElementFactory.getInstance( + node.type, children = node.children + .filterIsInstance<CompositeASTNode>() + .evaluateChildren() + ) + + private fun listsHandler(node: ASTNode): 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 + .map { + 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 { + java.net.URL(link) + null + } catch (e: MalformedURLException) { + try { + if (resolutionFacade != null && declarationDescriptor != null) { + resolveKDocLink( + resolutionFacade.resolveSession.bindingContext, + resolutionFacade, + declarationDescriptor, + null, + link.split('.') + ).minBy { it is ClassDescriptor }?.let { DRI.from(it) } + } else null + } catch (e1: IllegalArgumentException) { + null + } + } + } + + private fun referenceLinksHandler(node: ASTNode): DocTag { + val linkLabel = node.children.find { it.type == MarkdownElementTypes.LINK_LABEL } + ?: throw IllegalStateException("Wrong AST Tree. Reference link does not contain expected content") + 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): DocTag { + val linkText = node.children.find { it.type == MarkdownElementTypes.LINK_TEXT } + ?: throw IllegalStateException("Wrong AST Tree. Inline link does not contain expected content") + val linkDestination = node.children.find { it.type == MarkdownElementTypes.LINK_DESTINATION } + ?: throw IllegalStateException("Wrong AST Tree. Inline link does not contain expected content") + val linkTitle = node.children.find { it.type == MarkdownElementTypes.LINK_TITLE } + + val link = text.substring(linkDestination.startOffset, linkDestination.endOffset) + + return linksHandler(linkText, link, linkTitle) + } + + private fun autoLinksHandler(node: ASTNode): 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 { + val dri: DRI? = resolveDRI(link) + val params = if (linkTitle == null) + mapOf("href" to link) + else + mapOf("href" to link, "title" to text.substring(linkTitle.startOffset + 1, linkTitle.endOffset - 1)) + + return DocTagsFromIElementFactory.getInstance( + MarkdownElementTypes.INLINE_LINK, + params = params, + children = linkText.children.drop(1).dropLast(1).evaluateChildren(), + dri = dri + ) + } + + private fun imagesHandler(node: ASTNode): DocTag { + val linkNode = + node.children.last().children.find { it.type == MarkdownElementTypes.LINK_LABEL }!!.children[1] + val link = text.substring(linkNode.startOffset, linkNode.endOffset) + val src = mapOf("src" to link) + return DocTagsFromIElementFactory.getInstance( + node.type, + params = src, + children = listOf(visitNode(node.children.last().children.find { it.type == MarkdownElementTypes.LINK_TEXT }!!)) + ) + } + + private fun codeSpansHandler(node: ASTNode): DocTag = + DocTagsFromIElementFactory.getInstance( + node.type, + children = listOf( + DocTagsFromIElementFactory.getInstance( + MarkdownTokenTypes.TEXT, + body = text.substring(node.startOffset + 1, node.endOffset - 1).replace('\n', ' ').trimIndent() + ) + + ) + ) + + private fun codeFencesHandler(node: ASTNode): DocTag = + DocTagsFromIElementFactory.getInstance( + node.type, + children = node + .children + .dropWhile { it.type != MarkdownTokenTypes.CODE_FENCE_CONTENT } + .dropLastWhile { it.type != MarkdownTokenTypes.CODE_FENCE_CONTENT } + .map { + if (it.type == MarkdownTokenTypes.EOL) + LeafASTNode(MarkdownTokenTypes.HARD_LINE_BREAK, 0, 0) + else + it + }.evaluateChildren(), + 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): DocTag = + DocTagsFromIElementFactory.getInstance(node.type, children = node.children.evaluateChildren()) + + private fun defaultHandler(node: ASTNode): DocTag = + DocTagsFromIElementFactory.getInstance( + MarkdownElementTypes.PARAGRAPH, + children = node.children.evaluateChildren() + ) + + fun visitNode(node: ASTNode): 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(node) + MarkdownElementTypes.STRONG, + 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) + MarkdownTokenTypes.HARD_LINE_BREAK -> DocTagsFromIElementFactory.getInstance(node.type) + MarkdownTokenTypes.CODE_FENCE_CONTENT, + MarkdownTokenTypes.CODE_LINE, + 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() + ) + else -> defaultHandler(node) + } + + private fun List<ASTNode>.filterTabSeparators() = + this.filterNot { it.type == GFMTokenTypes.TABLE_SEPARATOR } + + private fun List<ASTNode>.evaluateChildren(): List<DocTag> = + this.removeUselessTokens().mergeLeafASTNodes().map { visitNode(it) } + + 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 val notLeafNodes = listOf(MarkdownTokenTypes.HORIZONTAL_RULE, MarkdownTokenTypes.HARD_LINE_BREAK) + + private fun List<ASTNode>.isNotLeaf(index: Int): Boolean = + if (index in 0..this.lastIndex) + (this[index] is CompositeASTNode) || this[index].type in notLeafNodes + 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 + while (index < this.lastIndex) { + if (this.isNotLeaf(index + 1) || this[index + 1].startOffset != this[index].endOffset) { + val endOffset = this[index].endOffset + if (text.substring(startOffset, endOffset).transform().trim().isNotEmpty()) + children += LeafASTNode(MarkdownTokenTypes.TEXT, startOffset, endOffset) + break + } + index++ + } + if (index == this.lastIndex) { + val endOffset = this[index].endOffset + if (text.substring(startOffset, endOffset).transform().trim().isNotEmpty()) + children += LeafASTNode(MarkdownTokenTypes.TEXT, startOffset, endOffset) + } + } + index++ + } + return children + } + + 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 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 markdownToDocNode(text: String): DocTag { + + val flavourDescriptor = GFMFlavourDescriptor() + val markdownAstRoot: ASTNode = IntellijMarkdownParser(flavourDescriptor).buildMarkdownTreeFromString(text) + + return MarkdownVisitor(text, getAllDestinationLinks(text, markdownAstRoot).toMap()).visitNode(markdownAstRoot) + } + + override fun parseStringToDocNode(extractedString: String) = markdownToDocNode(extractedString) + override fun preparse(text: String) = text + + private fun findParent(kDoc: PsiElement): PsiElement = + if (kDoc is KDocSection) findParent(kDoc.parent) else kDoc + + private fun getAllKDocTags(kDocImpl: PsiElement): List<KDocTag> = + kDocImpl.children.filterIsInstance<KDocTag>().filterNot { it is KDocSection } + kDocImpl.children.flatMap { + getAllKDocTags( + it + ) + } + + fun parseFromKDocTag(kDocTag: KDocTag?): DocumentationNode { + return if (kDocTag == null) + DocumentationNode(emptyList()) + else + DocumentationNode( + (listOf(kDocTag) + getAllKDocTags(findParent(kDocTag))).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 -> Throws( + parseStringToDocNode(it.getContent()), + it.getSubjectName().orEmpty() + ) + KDocKnownTag.EXCEPTION -> Throws( + parseStringToDocNode(it.getContent()), + it.getSubjectName().orEmpty() + ) + KDocKnownTag.PARAM -> Param( + parseStringToDocNode(it.getContent()), + it.getSubjectName().orEmpty() + ) + KDocKnownTag.RECEIVER -> Receiver(parseStringToDocNode(it.getContent())) + KDocKnownTag.RETURN -> Return(parseStringToDocNode(it.getContent())) + KDocKnownTag.SEE -> See( + parseStringToDocNode(it.getContent()), + it.getSubjectName().orEmpty(), + parseStringToDocNode("[${it.getSubjectName()}]") + .let { + val link = it.children[0] + if (link is DocumentationLink) link.dri + else null + } + ) + 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())) + } + } + ) + } +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/parsers/Parser.kt b/plugins/base/src/main/kotlin/parsers/Parser.kt new file mode 100644 index 00000000..1dd0c34a --- /dev/null +++ b/plugins/base/src/main/kotlin/parsers/Parser.kt @@ -0,0 +1,42 @@ +package org.jetbrains.dokka.base.parsers + +import org.jetbrains.dokka.model.doc.* + +abstract class Parser { + + abstract fun parseStringToDocNode(extractedString: String): DocTag + abstract fun preparse(text: String): String + + fun parse(text: String): DocumentationNode { + + val list = jkdocToListOfPairs(preparse(text)) + + val mappedList: List<TagWrapper> = list.map { + when(it.first) { + "description" -> Description(parseStringToDocNode(it.second)) + "author" -> Author(parseStringToDocNode(it.second)) + "version" -> Version(parseStringToDocNode(it.second)) + "since" -> Since(parseStringToDocNode(it.second)) + "see" -> See(parseStringToDocNode(it.second.substringAfter(' ')), it.second.substringBefore(' '), null) + "param" -> Param(parseStringToDocNode(it.second.substringAfter(' ')), it.second.substringBefore(' ')) + "property" -> Property(parseStringToDocNode(it.second.substringAfter(' ')), it.second.substringBefore(' ')) + "return" -> Return(parseStringToDocNode(it.second)) + "constructor" -> Constructor(parseStringToDocNode(it.second)) + "receiver" -> Receiver(parseStringToDocNode(it.second)) + "throws", "exception" -> Throws(parseStringToDocNode(it.second.substringAfter(' ')), it.second.substringBefore(' ')) + "deprecated" -> Deprecated(parseStringToDocNode(it.second)) + "sample" -> Sample(parseStringToDocNode(it.second.substringAfter(' ')), it.second.substringBefore(' ')) + "suppress" -> Suppress(parseStringToDocNode(it.second)) + else -> CustomTagWrapper(parseStringToDocNode(it.second), it.first) + } + } + return DocumentationNode(mappedList) + } + + private fun jkdocToListOfPairs(javadoc: String): List<Pair<String, String>> = + "description $javadoc" + .split("\n@") + .map { + it.substringBefore(' ') to it.substringAfter(' ') + } +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt b/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt new file mode 100644 index 00000000..e81eb513 --- /dev/null +++ b/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt @@ -0,0 +1,43 @@ +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.jetbrains.dokka.links.DRI +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) = + 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, + MarkdownElementTypes.CODE_BLOCK, + MarkdownElementTypes.CODE_FENCE -> Code(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 -> Text(body ?: throw NullPointerException("Text body should be at least empty string passed to DocNodes factory!"), children, params ) + 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) + else -> CustomDocTag(children, params) + } +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt b/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt new file mode 100644 index 00000000..de7c3cad --- /dev/null +++ b/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt @@ -0,0 +1,77 @@ +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" -> Code(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) + } +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt index 2aab6018..63232793 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt @@ -1,10 +1,13 @@ package org.jetbrains.dokka.base.transformers.documentables +import org.jetbrains.dokka.analysis.EnvironmentAndFacade +import org.jetbrains.dokka.analysis.KotlinAnalysis import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.model.SourceSetData import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.model.sourceSet -import org.jetbrains.dokka.parsers.MarkdownParser +import org.jetbrains.dokka.base.parsers.MarkdownParser +import org.jetbrains.dokka.model.SourceSetDependent import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer import org.jetbrains.kotlin.name.FqName @@ -12,9 +15,12 @@ import java.nio.file.Files import java.nio.file.Paths -internal class ModuleAndPackageDocumentationTransformer(val context: DokkaContext) : PreMergeDocumentableTransformer { +internal class ModuleAndPackageDocumentationTransformer( + private val context: DokkaContext, + private val kotlinAnalysis: KotlinAnalysis +) : PreMergeDocumentableTransformer { - override fun invoke(original: List<DModule>): List<DModule> { + override fun invoke(modules: List<DModule>): List<DModule> { val modulesAndPackagesDocumentation = context.configuration.passesConfigurations @@ -47,13 +53,12 @@ internal class ModuleAndPackageDocumentationTransformer(val context: DokkaContex } }.toMap() - return original.map { module -> + return modules.map { module -> val moduleDocumentation = module.sourceSets.mapNotNull { pd -> val doc = modulesAndPackagesDocumentation[Pair(module.name, pd)] - val facade = context.platforms[pd]?.facade - ?: return@mapNotNull null.also { context.logger.warn("Could not find platform data for ${pd.moduleName}/${pd.sourceSetID}") } + val facade = kotlinAnalysis[pd].facade try { doc?.get("Module")?.get(module.name)?.run { pd to MarkdownParser( @@ -71,8 +76,7 @@ internal class ModuleAndPackageDocumentationTransformer(val context: DokkaContex val packagesDocumentation = module.packages.map { it.name to it.sourceSets.mapNotNull { pd -> val doc = modulesAndPackagesDocumentation[Pair(module.name, pd)] - val facade = context.platforms[pd]?.facade - ?: return@mapNotNull null.also { context.logger.warn("Could not find platform data for ${pd.moduleName}/${pd.sourceSetID}") } + val facade = kotlinAnalysis[pd].facade val descriptor = facade.moduleDescriptor.getPackage(FqName(it.name.let { if(it == "[JS root]") "" else it })) doc?.get("Package")?.get(it.name)?.run { pd to MarkdownParser( diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ReportUndocumentedTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/ReportUndocumentedTransformer.kt index 7d475571..0b47345d 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ReportUndocumentedTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ReportUndocumentedTransformer.kt @@ -2,6 +2,7 @@ package org.jetbrains.dokka.base.transformers.documentables import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.DokkaConfiguration.PassConfiguration +import org.jetbrains.dokka.analysis.DescriptorDocumentableSource import org.jetbrains.dokka.model.* import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.documentation.DocumentableTransformer diff --git a/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt b/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt index 57655a9d..0d133a65 100644 --- a/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt @@ -1,11 +1,11 @@ package org.jetbrains.dokka.base.transformers.pages.samples import com.intellij.psi.PsiElement -import org.jetbrains.dokka.DokkaGenerator -import org.jetbrains.dokka.EnvironmentAndFacade import org.jetbrains.dokka.Platform import org.jetbrains.dokka.analysis.AnalysisEnvironment +import org.jetbrains.dokka.analysis.DokkaMessageCollector import org.jetbrains.dokka.analysis.DokkaResolutionFacade +import org.jetbrains.dokka.analysis.EnvironmentAndFacade import org.jetbrains.dokka.base.renderers.platforms import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.SourceSetData @@ -41,7 +41,7 @@ abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer { } private fun setUpAnalysis(context: DokkaContext) = context.configuration.passesConfigurations.map { - context.sourceSet(it) to AnalysisEnvironment(DokkaGenerator.DokkaMessageCollector(context.logger), it.analysisPlatform).run { + context.sourceSet(it) to AnalysisEnvironment(DokkaMessageCollector(context.logger), it.analysisPlatform).run { if (analysisPlatform == Platform.jvm) { addClasspath(PathUtil.getJdkClassesRootsFromCurrentJre()) } @@ -57,11 +57,16 @@ abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer { } }.toMap() - private fun ContentNode.addSample(contentPage: ContentPage, platform: SourceSetData, fqName: String, analysis: Map<SourceSetData, EnvironmentAndFacade>): ContentNode { - val facade = analysis[platform]?.facade ?: - return this.also { context.logger.warn("Cannot resolve facade for platform ${platform.moduleName}")} - val psiElement = fqNameToPsiElement(facade, fqName) ?: - return this.also { context.logger.warn("Cannot find PsiElement corresponding to $fqName") } + private fun ContentNode.addSample( + contentPage: ContentPage, + platform: SourceSetData, + fqName: String, + analysis: Map<SourceSetData, EnvironmentAndFacade> + ): ContentNode { + val facade = analysis[platform]?.facade + ?: return this.also { context.logger.warn("Cannot resolve facade for platform ${platform.moduleName}") } + val psiElement = fqNameToPsiElement(facade, fqName) + ?: return this.also { context.logger.warn("Cannot find PsiElement corresponding to $fqName") } val imports = processImports(psiElement) // TODO: Process somehow imports. Maybe just attach them at the top of each body val body = processBody(psiElement) val node = contentCode(contentPage.platforms(), contentPage.dri, body, "kotlin") @@ -70,10 +75,14 @@ abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer { } private fun ContentNode.dfs(fqName: String, node: ContentCode): ContentNode { - return when(this) { + return when (this) { is ContentHeader -> copy(children.map { it.dfs(fqName, node) }) is ContentDivergentGroup -> copy(children.map { it.dfs(fqName, node) } as List<ContentDivergentInstance>) - is ContentDivergentInstance -> copy(before.let { it?.dfs(fqName, node) }, divergent.let { it.dfs(fqName, node) }, after.let { it?.dfs(fqName, node) }) + is ContentDivergentInstance -> copy( + before.let { it?.dfs(fqName, node) }, + divergent.dfs(fqName, node), + after.let { it?.dfs(fqName, node) } + ) is ContentCode -> copy(children.map { it.dfs(fqName, node) }) is ContentDRILink -> copy(children.map { it.dfs(fqName, node) }) is ContentResolvedLink -> copy(children.map { it.dfs(fqName, node) }) @@ -90,10 +99,14 @@ abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer { private fun fqNameToPsiElement(resolutionFacade: DokkaResolutionFacade, functionName: String): PsiElement? { val packageName = functionName.takeWhile { it != '.' } - val descriptor = resolutionFacade.resolveSession.getPackageFragment(FqName(packageName)) ?: - return null.also { context.logger.warn("Cannot find descriptor for package $packageName") } - val symbol = resolveKDocSampleLink(BindingContext.EMPTY, resolutionFacade, descriptor, functionName.split(".")).firstOrNull() ?: - return null.also { context.logger.warn("Unresolved function $functionName in @sample") } + val descriptor = resolutionFacade.resolveSession.getPackageFragment(FqName(packageName)) + ?: return null.also { context.logger.warn("Cannot find descriptor for package $packageName") } + val symbol = resolveKDocSampleLink( + BindingContext.EMPTY, + resolutionFacade, + descriptor, + functionName.split(".") + ).firstOrNull() ?: return null.also { context.logger.warn("Unresolved function $functionName in @sample") } return DescriptorToSourceUtils.descriptorToDeclaration(symbol) } diff --git a/plugins/base/src/main/kotlin/transformers/pages/sourcelinks/SourceLinksTransformer.kt b/plugins/base/src/main/kotlin/transformers/pages/sourcelinks/SourceLinksTransformer.kt index 8113d277..7603c80b 100644 --- a/plugins/base/src/main/kotlin/transformers/pages/sourcelinks/SourceLinksTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/pages/sourcelinks/SourceLinksTransformer.kt @@ -3,11 +3,11 @@ package org.jetbrains.dokka.base.transformers.pages.sourcelinks import com.intellij.psi.PsiElement import com.intellij.psi.PsiDocumentManager import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.analysis.DescriptorDocumentableSource +import org.jetbrains.dokka.analysis.PsiDocumentableSource import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder -import org.jetbrains.dokka.model.DescriptorDocumentableSource import org.jetbrains.dokka.model.SourceSetData import org.jetbrains.dokka.model.DocumentableSource -import org.jetbrains.dokka.model.PsiDocumentableSource import org.jetbrains.dokka.model.WithExpectActual import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index 49d8ae0f..cefea4ec 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -1,6 +1,6 @@ package org.jetbrains.dokka.base.translators.descriptors -import org.jetbrains.dokka.analysis.DokkaResolutionFacade +import org.jetbrains.dokka.analysis.* import org.jetbrains.dokka.links.* import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.model.* @@ -8,7 +8,7 @@ import org.jetbrains.dokka.model.Nullable import org.jetbrains.dokka.model.TypeConstructor import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.model.properties.PropertyContainer -import org.jetbrains.dokka.parsers.MarkdownParser +import org.jetbrains.dokka.base.parsers.MarkdownParser import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator import org.jetbrains.dokka.utilities.DokkaLogger @@ -52,18 +52,19 @@ import org.jetbrains.kotlin.resolve.constants.EnumValue as ConstantsEnumValue import org.jetbrains.kotlin.resolve.constants.KClassValue as ConstantsKtClassValue import kotlin.IllegalArgumentException -object DefaultDescriptorToDocumentableTranslator : SourceToDocumentableTranslator { +class DefaultDescriptorToDocumentableTranslator( + private val kotlinAnalysis: KotlinAnalysis +) : SourceToDocumentableTranslator { override fun invoke(sourceSet: SourceSetData, context: DokkaContext): DModule { - - val (environment, facade) = context.platforms.getValue(sourceSet) + val (environment, facade) = kotlinAnalysis[sourceSet] val packageFragments = environment.getSourceFiles().asSequence() .map { it.packageFqName } .distinct() .mapNotNull { facade.resolveSession.getPackageFragment(it) } .toList() - return DokkaDescriptorVisitor(sourceSet, context.platforms.getValue(sourceSet).facade, context.logger).run { + return DokkaDescriptorVisitor(sourceSet, kotlinAnalysis[sourceSet].facade, context.logger).run { packageFragments.mapNotNull { it.safeAs<PackageFragmentDescriptor>() }.map { visitPackageFragmentDescriptor( it, diff --git a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt index a5117b09..e71d936a 100644 --- a/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt @@ -7,6 +7,10 @@ import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.* import com.intellij.psi.impl.source.PsiClassReferenceType import com.intellij.psi.impl.source.PsiImmediateClassType +import org.jetbrains.dokka.analysis.KotlinAnalysis +import org.jetbrains.dokka.analysis.PsiDocumentableSource +import org.jetbrains.dokka.analysis.from +import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.nextTarget import org.jetbrains.dokka.links.withClass @@ -17,6 +21,7 @@ import org.jetbrains.dokka.model.doc.Param import org.jetbrains.dokka.model.doc.Text import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.transformers.sources.SourceToDocumentableTranslator import org.jetbrains.dokka.utilities.DokkaLogger import org.jetbrains.kotlin.asJava.elements.KtLightAbstractAnnotation @@ -33,15 +38,17 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.io.File -object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { +class DefaultPsiToDocumentableTranslator( + private val kotlinAnalysis: KotlinAnalysis +) : SourceToDocumentableTranslator { - override fun invoke(sourceSetData: SourceSetData, context: DokkaContext): DModule { + override fun invoke(sourceSet: SourceSetData, context: DokkaContext): DModule { fun isFileInSourceRoots(file: File): Boolean { - return sourceSetData.sourceRoots.any { root -> file.path.startsWith(File(root.path).absolutePath) } + return sourceSet.sourceRoots.any { root -> file.path.startsWith(File(root.path).absolutePath) } } - val (environment, _) = context.platforms.getValue(sourceSetData) + val (environment, _) = kotlinAnalysis[sourceSet] val sourceRoots = environment.configuration.get(CLIConfigurationKeys.CONTENT_ROOTS) ?.filterIsInstance<JavaSourceRoot>() @@ -59,11 +66,11 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { val docParser = DokkaPsiParser( - sourceSetData, + sourceSet, context.logger ) return DModule( - sourceSetData.moduleName, + sourceSet.moduleName, psiFiles.mapNotNull { it.safeAs<PsiJavaFile>() }.groupBy { it.packageName }.map { (packageName, psiFiles) -> val dri = DRI(packageName = packageName) DPackage( @@ -76,12 +83,12 @@ object DefaultPsiToDocumentableTranslator : SourceToDocumentableTranslator { emptyList(), emptyMap(), null, - setOf(sourceSetData) + setOf(sourceSet) ) }, emptyMap(), null, - setOf(sourceSetData) + setOf(sourceSet) ) } diff --git a/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt b/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt index d8130974..7119ba68 100644 --- a/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt +++ b/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt @@ -6,6 +6,7 @@ import com.intellij.psi.impl.source.tree.JavaDocElementType import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.javadoc.* import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.dokka.analysis.from import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.model.doc.Deprecated |