aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/build.gradle.kts1
-rw-r--r--core/src/main/kotlin/Java/JavadocParser.kt369
-rw-r--r--core/src/main/kotlin/links/DRI.kt26
-rw-r--r--plugins/base/build.gradle.kts4
-rw-r--r--plugins/base/src/main/kotlin/DokkaBase.kt2
-rw-r--r--plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt (renamed from plugins/base/src/main/kotlin/transformers/psi/DefaultPsiToDocumentableTranslator.kt)5
-rw-r--r--plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt149
7 files changed, 180 insertions, 376 deletions
diff --git a/core/build.gradle.kts b/core/build.gradle.kts
index 365cf7e8..080e1fe6 100644
--- a/core/build.gradle.kts
+++ b/core/build.gradle.kts
@@ -12,7 +12,6 @@ dependencies {
api("org.jetbrains.kotlin:kotlin-compiler:$kotlin_version")
implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version")
implementation("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version")
- implementation("org.jsoup:jsoup:1.12.1")
implementation("com.google.code.gson:gson:2.8.5")
testImplementation(project(":testApi"))
diff --git a/core/src/main/kotlin/Java/JavadocParser.kt b/core/src/main/kotlin/Java/JavadocParser.kt
deleted file mode 100644
index 856cfa04..00000000
--- a/core/src/main/kotlin/Java/JavadocParser.kt
+++ /dev/null
@@ -1,369 +0,0 @@
-package org.jetbrains.dokka
-
-import com.intellij.psi.*
-import com.intellij.psi.impl.source.tree.JavaDocElementType
-import com.intellij.psi.javadoc.*
-import com.intellij.psi.util.PsiTreeUtil
-import org.jetbrains.dokka.model.doc.*
-import org.jetbrains.dokka.utilities.DokkaLogger
-import org.jsoup.Jsoup
-import org.jsoup.nodes.Element
-import org.jsoup.nodes.Node
-import org.jsoup.nodes.TextNode
-
-interface JavaDocumentationParser {
- fun parseDocumentation(element: PsiNamedElement): DocumentationNode
-}
-
-class JavadocParser(
- private val logger: DokkaLogger
-) : JavaDocumentationParser {
-
- override fun parseDocumentation(element: PsiNamedElement): DocumentationNode {
- val docComment = (element as? PsiDocCommentOwner)?.docComment ?: return DocumentationNode(emptyList())
- val nodes =
- convertJavadocElements(docComment.descriptionElements.dropWhile { it.text.trim().isEmpty() }, element)
- return DocumentationNode(nodes.map { Description(it) })
- /*val firstParagraphContents = nodes.takeWhile { it !is ContentParagraph }
- val firstParagraph = ContentParagraph()
- if (firstParagraphContents.isNotEmpty()) {
- firstParagraphContents.forEach { firstParagraph.append(it) }
- result.add(firstParagraph)
- }
-
- result.appendAll(nodes.drop(firstParagraphContents.size))
-
- if (element is PsiMethod) {
- val tagsByName = element.searchInheritedTags()
- for ((tagName, tags) in tagsByName) {
- for ((tag, context) in tags) {
- val section = result.addSection(javadocSectionDisplayName(tagName), tag.getSubjectName())
- val signature = signatureProvider.signature(element)
- when (tagName) {
- "param" -> {
- section.appendTypeElement(signature) {
- it.details
- .find { node -> node.kind == NodeKind.Parameter && node.name == tag.getSubjectName() }
- ?.detailOrNull(NodeKind.Type)
- }
- }
- "return" -> {
- section.appendTypeElement(signature) { it.detailOrNull(NodeKind.Type) }
- }
- }
- section.appendAll(convertJavadocElements(tag.contentElements(), context))
- }
- }
- }
-
- docComment.tags.forEach { tag ->
- when (tag.name) {
- "see" -> result.convertSeeTag(tag)
- "deprecated" -> {
- deprecatedContent = Content().apply {
- appendAll(convertJavadocElements(tag.contentElements(), element))
- }
- }
- in tagsToInherit -> {}
- else -> {
- val subjectName = tag.getSubjectName()
- val section = result.addSection(javadocSectionDisplayName(tag.name), subjectName)
-
- section.appendAll(convertJavadocElements(tag.contentElements(), element))
- }
- }
- }
- return JavadocParseResult(result, deprecatedContent)*/
- }
-
- private val tagsToInherit = setOf("param", "return", "throws")
-
- private data class TagWithContext(val tag: PsiDocTag, val context: PsiNamedElement)
-/*
- private fun PsiMethod.searchInheritedTags(): Map<String, Collection<TagWithContext>> {
-
- val output = tagsToInherit.keysToMap { mutableMapOf<String?, TagWithContext>() }
-
- fun recursiveSearch(methods: Array<PsiMethod>) {
- for (method in methods) {
- recursiveSearch(method.findSuperMethods())
- }
- for (method in methods) {
- for (tag in method.docComment?.tags.orEmpty()) {
- if (tag.name in tagsToInherit) {
- output[tag.name]!![tag.getSubjectName()] = TagWithContext(tag, method)
- }
- }
- }
- }
-
- recursiveSearch(arrayOf(this))
- return output.mapValues { it.value.values }
- }
-*/
-
- private fun PsiDocTag.contentElements(): Iterable<PsiElement> {
- val tagValueElements = children
- .dropWhile { it.node?.elementType == JavaDocTokenType.DOC_TAG_NAME }
- .dropWhile { it is PsiWhiteSpace }
- .filterNot { it.node?.elementType == JavaDocTokenType.DOC_COMMENT_LEADING_ASTERISKS }
- return if (getSubjectName() != null) tagValueElements.dropWhile { it is PsiDocTagValue } else tagValueElements
- }
-
- private fun convertJavadocElements(elements: Iterable<PsiElement>, element: PsiNamedElement): List<DocTag> {
- val doc = Jsoup.parse(expandAllForElements(elements, element))
- return doc.body().childNodes().mapNotNull { convertHtmlNode(it) }
- }
-
- private fun expandAllForElements(elements: Iterable<PsiElement>, element: PsiNamedElement): String {
- val htmlBuilder = StringBuilder()
- elements.forEach {
- if (it is PsiInlineDocTag) {
- htmlBuilder.append(convertInlineDocTag(it, element))
- } else {
- htmlBuilder.append(it.text)
- }
- }
- return htmlBuilder.toString().trim()
- }
-
- private fun convertHtmlNode(node: Node, insidePre: Boolean = false): DocTag? = when (node) {
- is TextNode -> Text(body = if (insidePre) node.wholeText else node.text())
- is Element -> createBlock(node)
- else -> null
- }
-
- private fun createBlock(element: Element): DocTag {
- val children = element.childNodes().mapNotNull { convertHtmlNode(it) }
- return when (element.tagName()) {
- "p" -> P(children)
- "b" -> B(children)
- "strong" -> Strong(children)
- "i" -> I(children)
- "em" -> Em(children)
-// "s", "del" -> ContentStrikethrough()
- "code" -> Code(children)
- "pre" -> Pre(children)
- "ul" -> Ul(children)
- "ol" -> Ol(children)
- "li" -> Li(children)
-// "a" -> createLink(element)
-// "br" -> ContentBlock().apply { hardLineBreak() }
- else -> Text(body = element.ownText())
- }
- }
-/*
-
- private fun createLink(element: Element): DocTag {
- return when {
- element.hasAttr("docref") -> {
- val docref = element.attr("docref")
- ContentNodeLazyLink(docref) { refGraph.lookupOrWarn(docref, logger) }
- }
- element.hasAttr("href") -> {
- val href = element.attr("href")
-
- val uri = try {
- URI(href)
- } catch (_: Exception) {
- null
- }
-
- if (uri?.isAbsolute == false) {
- ContentLocalLink(href)
- } else {
- ContentExternalLink(href)
- }
- }
- element.hasAttr("name") -> {
- ContentBookmark(element.attr("name"))
- }
- else -> ContentBlock()
- }
- }
-
-
- private fun convertSeeTag(tag: PsiDocTag) {
- val linkElement = tag.linkElement() ?: return
- val seeSection = findSectionByTag(ContentTags.SeeAlso) ?: addSection(ContentTags.SeeAlso, null)
-
- val valueElement = tag.referenceElement()
- val externalLink = resolveExternalLink(valueElement)
- val text = ContentText(linkElement.text)
-
- val linkSignature by lazy { resolveInternalLink(valueElement) }
- val node = when {
- externalLink != null -> {
- val linkNode = ContentExternalLink(externalLink)
- linkNode.append(text)
- linkNode
- }
- linkSignature != null -> {
- val linkNode =
- ContentNodeLazyLink(
- (tag.valueElement ?: linkElement).text
- ) { refGraph.lookupOrWarn(linkSignature!!, logger) }
- linkNode.append(text)
- linkNode
- }
- else -> text
- }
- seeSection.append(node)
- }
-*/
- private fun convertInlineDocTag(tag: PsiInlineDocTag, element: PsiNamedElement) = when (tag.name) {
- "link", "linkplain" -> {
- val valueElement = tag.referenceElement()
- val externalLink = resolveExternalLink(valueElement)
- val linkSignature by lazy { resolveInternalLink(valueElement) }
- if (externalLink != null || linkSignature != null) {
- val labelText = tag.dataElements.firstOrNull { it is PsiDocToken }?.text ?: valueElement!!.text
- val linkTarget = if (externalLink != null) "href=\"$externalLink\"" else "docref=\"$linkSignature\""
- val link = "<a $linkTarget>$labelText</a>"
- if (tag.name == "link") "<code>$link</code>" else link
- } else if (valueElement != null) {
- valueElement.text
- } else {
- ""
- }
- }
- "code", "literal" -> {
- val text = StringBuilder()
- tag.dataElements.forEach { text.append(it.text) }
- val escaped = text.toString().trimStart()
- if (tag.name == "code") "<code>$escaped</code>" else escaped
- }
- "inheritDoc" -> {
- val result = (element as? PsiMethod)?.let {
- // @{inheritDoc} is only allowed on functions
- val parent = tag.parent
- when (parent) {
- is PsiDocComment -> element.findSuperDocCommentOrWarn()
- is PsiDocTag -> element.findSuperDocTagOrWarn(parent)
- else -> null
- }
- }
- result ?: tag.text
- }
- else -> tag.text
- }
-
- private fun PsiDocTag.referenceElement(): PsiElement? =
- linkElement()?.let {
- if (it.node.elementType == JavaDocElementType.DOC_REFERENCE_HOLDER) {
- PsiTreeUtil.findChildOfType(it, PsiJavaCodeReferenceElement::class.java)
- } else {
- it
- }
- }
-
- private fun PsiDocTag.linkElement(): PsiElement? =
- valueElement ?: dataElements.firstOrNull { it !is PsiWhiteSpace }
-
- private fun resolveExternalLink(valueElement: PsiElement?): String? {
- /*val target = valueElement?.reference?.resolve()
- if (target != null) {
- return externalDocumentationLinkResolver.buildExternalDocumentationLink(target)
- }*/
- return null
- }
-
- private fun resolveInternalLink(valueElement: PsiElement?): String? {
- /*val target = valueElement?.reference?.resolve()
- if (target != null) {
- return signatureProvider.signature(target)
- }*/
- return null
- }
-
- fun PsiDocTag.getSubjectName(): String? {
- if (name == "param" || name == "throws" || name == "exception") {
- return valueElement?.text
- }
- return null
- }
-
- private fun PsiMethod.findSuperDocCommentOrWarn(): String {
- val method = findFirstSuperMethodWithDocumentation(this)
- if (method != null) {
- val descriptionElements = method.docComment?.descriptionElements?.dropWhile {
- it.text.trim().isEmpty()
- } ?: return ""
-
- return expandAllForElements(descriptionElements, method)
- }
- logger.warn("No docs found on supertype with {@inheritDoc} method ${this.name} in ${this.containingFile.name}}")
- return ""
- }
-
-
- private fun PsiMethod.findSuperDocTagOrWarn(elementToExpand: PsiDocTag): String {
- val result = findFirstSuperMethodWithDocumentationforTag(elementToExpand, this)
-
- if (result != null) {
- val (method, tag) = result
-
- val contentElements = tag.contentElements().dropWhile { it.text.trim().isEmpty() }
-
- val expandedString = expandAllForElements(contentElements, method)
-
- return expandedString
- }
- logger.warn("No docs found on supertype for @${elementToExpand.name} ${elementToExpand.getSubjectName()} with {@inheritDoc} method ${this.name} in ${this.containingFile.name}}")
- return ""
- }
-
- private fun findFirstSuperMethodWithDocumentation(current: PsiMethod): PsiMethod? {
- val superMethods = current.findSuperMethods()
- for (method in superMethods) {
- val docs = method.docComment?.descriptionElements?.dropWhile { it.text.trim().isEmpty() }
- if (!docs.isNullOrEmpty()) {
- return method
- }
- }
- for (method in superMethods) {
- val result = findFirstSuperMethodWithDocumentation(method)
- if (result != null) {
- return result
- }
- }
-
- return null
- }
-
- private fun findFirstSuperMethodWithDocumentationforTag(elementToExpand: PsiDocTag, current: PsiMethod): Pair<PsiMethod, PsiDocTag>? {
- val superMethods = current.findSuperMethods()
- val mappedFilteredTags = superMethods.map {
- it to it.docComment?.tags?.filter { it.name == elementToExpand.name }
- }
-
- for ((method, tags) in mappedFilteredTags) {
- tags ?: continue
- for (tag in tags) {
- val (tagSubject, elementSubject) = when (tag.name) {
- "throws" -> {
- // match class names only for throws, ignore possibly fully qualified path
- // TODO: Always match exactly here
- tag.getSubjectName()?.split(".")?.last() to elementToExpand.getSubjectName()?.split(".")?.last()
- }
- else -> {
- tag.getSubjectName() to elementToExpand.getSubjectName()
- }
- }
-
- if (tagSubject == elementSubject) {
- return method to tag
- }
- }
- }
-
- for (method in superMethods) {
- val result = findFirstSuperMethodWithDocumentationforTag(elementToExpand, method)
- if (result != null) {
- return result
- }
- }
- return null
- }
-
-}
diff --git a/core/src/main/kotlin/links/DRI.kt b/core/src/main/kotlin/links/DRI.kt
index aefaf8f6..791d2b5e 100644
--- a/core/src/main/kotlin/links/DRI.kt
+++ b/core/src/main/kotlin/links/DRI.kt
@@ -1,6 +1,11 @@
package org.jetbrains.dokka.links
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiElement
+import com.intellij.psi.PsiMethod
+import com.intellij.psi.PsiParameter
import org.jetbrains.kotlin.descriptors.*
+import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.parentsWithSelf
import org.jetbrains.kotlin.resolve.scopes.receivers.ExtensionReceiver
@@ -36,6 +41,17 @@ data class DRI(
)
}
+ fun from(psi: PsiElement) = psi.parentsWithSelf.run {
+ val callable = firstIsInstanceOrNull<PsiMethod>()
+ val params = (callable?.parameterList?.parameters).orEmpty()
+ val classes = filterIsInstance<PsiClass>().toList()
+ DRI(
+ classes.lastOrNull()?.qualifiedName?.substringBeforeLast('.', ""),
+ classes.toList().takeIf { it.isNotEmpty() }?.asReversed()?.mapNotNull { it.name }?.joinToString("."),
+ callable?.let { Callable.from(it) },
+ firstIsInstanceOrNull<PsiParameter>()?.let { params.indexOf(it) }
+ )
+ }
val topLevel = DRI()
}
}
@@ -67,6 +83,12 @@ data class Callable(
valueParameters.mapNotNull { TypeReference.from(it) }
)
}
+ fun from(psi: PsiMethod) = with(psi) {
+ Callable(
+ name,
+ null,
+ parameterList.parameters.map { param -> JavaClassReference(param.type.canonicalText) })
+ }
}
}
@@ -110,7 +132,7 @@ sealed class TypeReference {
}
}
-data class JavaClassReference(val name: String): TypeReference() {
+data class JavaClassReference(val name: String) : TypeReference() {
override fun toString(): String = name
}
@@ -132,7 +154,7 @@ data class Nullable(val wrapped: TypeReference) : TypeReference() {
override fun toString() = "$wrapped?"
}
-object StarProjection: TypeReference() {
+object StarProjection : TypeReference() {
override fun toString() = "*"
}
diff --git a/plugins/base/build.gradle.kts b/plugins/base/build.gradle.kts
index fd7ae978..08f8601e 100644
--- a/plugins/base/build.gradle.kts
+++ b/plugins/base/build.gradle.kts
@@ -4,6 +4,10 @@ plugins {
id("com.jfrog.bintray")
}
+dependencies {
+ implementation("org.jsoup:jsoup:1.12.1")
+}
+
publishing {
publications {
register<MavenPublication>("basePlugin") {
diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt
index 489da3ef..03875320 100644
--- a/plugins/base/src/main/kotlin/DokkaBase.kt
+++ b/plugins/base/src/main/kotlin/DokkaBase.kt
@@ -13,7 +13,7 @@ import org.jetbrains.dokka.base.transformers.pages.merger.FallbackPageMergerStra
import org.jetbrains.dokka.base.transformers.pages.merger.PageMerger
import org.jetbrains.dokka.base.transformers.pages.merger.PageMergerStrategy
import org.jetbrains.dokka.base.transformers.pages.merger.SameMethodNamePageMergerStrategy
-import org.jetbrains.dokka.base.transformers.psi.DefaultPsiToDocumentableTranslator
+import org.jetbrains.dokka.base.translators.psi.DefaultPsiToDocumentableTranslator
import org.jetbrains.dokka.base.translators.descriptors.DefaultDescriptorToDocumentableTranslator
import org.jetbrains.dokka.base.translators.documentables.DefaultDocumentableToPageTranslator
import org.jetbrains.dokka.plugability.DokkaPlugin
diff --git a/plugins/base/src/main/kotlin/transformers/psi/DefaultPsiToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
index 4aea45e3..3e95865e 100644
--- a/plugins/base/src/main/kotlin/transformers/psi/DefaultPsiToDocumentableTranslator.kt
+++ b/plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt
@@ -1,9 +1,8 @@
-package org.jetbrains.dokka.base.transformers.psi
+package org.jetbrains.dokka.base.translators.psi
import com.intellij.lang.jvm.JvmModifier
import com.intellij.lang.jvm.types.JvmReferenceType
import com.intellij.psi.*
-import org.jetbrains.dokka.JavadocParser
import org.jetbrains.dokka.links.Callable
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.links.JavaClassReference
@@ -61,7 +60,7 @@ object DefaultPsiToDocumentableTranslator : PsiToDocumentableTranslator {
logger: DokkaLogger
) {
- private val javadocParser: JavadocParser = JavadocParser(logger)
+ private val javadocParser: JavaDocumentationParser = JavadocParser(logger)
private fun PsiModifierListOwner.getVisibility() = modifierList?.children?.toList()?.let { ml ->
when {
diff --git a/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt b/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt
new file mode 100644
index 00000000..5b9af028
--- /dev/null
+++ b/plugins/base/src/main/kotlin/translators/psi/JavadocParser.kt
@@ -0,0 +1,149 @@
+package org.jetbrains.dokka.base.translators.psi
+
+import com.intellij.psi.*
+import com.intellij.psi.impl.source.javadoc.PsiDocParamRef
+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.links.DRI
+import org.jetbrains.dokka.model.doc.*
+import org.jetbrains.dokka.model.doc.Deprecated
+import org.jetbrains.dokka.utilities.DokkaLogger
+import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
+import org.jsoup.Jsoup
+import org.jsoup.nodes.Element
+import org.jsoup.nodes.Node
+import org.jsoup.nodes.TextNode
+
+interface JavaDocumentationParser {
+ fun parseDocumentation(element: PsiNamedElement): DocumentationNode
+}
+
+class JavadocParser(
+ private val logger: DokkaLogger // TODO: Add logging
+) : JavaDocumentationParser {
+
+ override fun parseDocumentation(element: PsiNamedElement): DocumentationNode {
+ val docComment = (element as? PsiDocCommentOwner)?.docComment ?: return DocumentationNode(emptyList())
+ val nodes = mutableListOf<TagWrapper>()
+ docComment.getDescription()?.let { nodes.add(it) }
+ nodes.addAll(docComment.tags.mapNotNull { tag ->
+ when (tag.name) {
+ "param" -> Param(P(convertJavadocElements(tag.dataElements.toList())), tag.text)
+ "throws" -> Throws(P(convertJavadocElements(tag.dataElements.toList())), tag.text)
+ "return" -> Return(P(convertJavadocElements(tag.dataElements.toList())))
+ "author" -> Author(P(convertJavadocElements(tag.dataElements.toList())))
+ "see" -> See(P(getSeeTagElementContent(tag)), tag.referenceElement()?.text.orEmpty())
+ "deprecated" -> Deprecated(P(convertJavadocElements(tag.dataElements.toList())))
+ else -> null
+ }
+ })
+ return DocumentationNode(nodes)
+ }
+
+ private fun getSeeTagElementContent(tag: PsiDocTag): List<DocTag> =
+ listOfNotNull(tag.referenceElement()?.toDocumentationLink())
+
+ private fun PsiDocComment.getDescription(): Description? =
+ convertJavadocElements(descriptionElements.dropWhile {
+ it.text.trim().isEmpty()
+ }).takeIf { it.isNotEmpty() }?.let { list ->
+ Description(P(list))
+ }
+
+ private fun convertJavadocElements(elements: Iterable<PsiElement>): List<DocTag> =
+ elements.mapNotNull {
+ when (it) {
+ is PsiReference -> convertJavadocElements(it.children.toList())
+ is PsiInlineDocTag -> listOfNotNull(convertInlineDocTag(it))
+ is PsiDocParamRef -> listOfNotNull(it.toDocumentationLink())
+ is PsiDocTagValue,
+ is PsiWhiteSpace -> listOfNotNull(Text(it.text))
+ is LeafPsiElement -> Jsoup.parse(it.text).body().childNodes().mapNotNull { convertHtmlNode(it) }
+ else -> null
+ }
+ }.flatten()
+
+ private fun convertHtmlNode(node: Node, insidePre: Boolean = false): DocTag? = when (node) {
+ is TextNode -> Text(body = if (insidePre) node.wholeText else node.text())
+ is Element -> createBlock(node)
+ else -> null
+ }
+
+ private fun createBlock(element: Element): DocTag {
+ val children = element.childNodes().mapNotNull { convertHtmlNode(it) }
+ return when (element.tagName()) {
+ "p" -> P(children)
+ "b" -> B(children)
+ "strong" -> Strong(children)
+ "i" -> I(children)
+ "em" -> Em(children)
+ "code" -> Code(children)
+ "pre" -> Pre(children)
+ "ul" -> Ul(children)
+ "ol" -> Ol(children)
+ "li" -> Li(children)
+ //"a" -> createLink(element, children) // TODO: add proper inline link handling
+ "br" -> Br
+ else -> Text(body = element.ownText())
+ }
+ }
+/*
+
+ private fun createLink(element: Element, children: List<DocTag>): DocTag {
+ return when {
+ element.hasAttr("docref") -> {
+ A(children, params = mapOf("docref" to element.attr("docref")))
+ }
+ element.hasAttr("href") -> {
+ val href = element.attr("href")
+
+ val uri = try {
+ A(children, params = mapOf("href" to href))
+ } catch (_: Exception) {
+ null
+ }
+
+ if (uri?.isAbsolute == false) {
+ ContentLocalLink(href)
+ } else {
+ ContentExternalLink(href)
+ }
+ }
+ element.hasAttr("name") -> {
+ ContentBookmark(element.attr("name"))
+ }
+ else -> Text()
+ }
+ }*/
+
+ private fun PsiElement.toDocumentationLink(labelElement: PsiElement? = null) =
+ reference?.resolve()?.let {
+ val dri = DRI.from(it)
+ val label = labelElement ?: children.firstOrNull { it is PsiDocToken && it.text.isNotBlank() } ?: this
+ DocumentationLink(dri, convertJavadocElements(listOfNotNull(label)))
+ }
+
+ private fun convertInlineDocTag(tag: PsiInlineDocTag) = when (tag.name) {
+ "link", "linkplain" -> {
+ tag.referenceElement()?.toDocumentationLink(tag.dataElements.firstIsInstanceOrNull<PsiDocToken>())
+ }
+ "code", "literal" -> {
+ Code(listOf(Text(tag.text)))
+ }
+ else -> Text(tag.text)
+ }
+
+ private fun PsiDocTag.referenceElement(): PsiElement? =
+ linkElement()?.let {
+ if (it.node.elementType == JavaDocElementType.DOC_REFERENCE_HOLDER) {
+ PsiTreeUtil.findChildOfType(it, PsiJavaCodeReferenceElement::class.java)
+ } else {
+ it
+ }
+ }
+
+ private fun PsiDocTag.linkElement(): PsiElement? =
+ valueElement ?: dataElements.firstOrNull { it !is PsiWhiteSpace }
+}