aboutsummaryrefslogtreecommitdiff
path: root/core/src
diff options
context:
space:
mode:
Diffstat (limited to 'core/src')
-rw-r--r--core/src/main/kotlin/model/Documentable.kt (renamed from core/src/main/kotlin/model/DocumentationNode.kt)50
-rw-r--r--core/src/main/kotlin/model/doc/DocNode.kt74
-rw-r--r--core/src/main/kotlin/model/doc/DocType.kt18
-rw-r--r--core/src/main/kotlin/model/doc/DocumentationNode.kt3
-rw-r--r--core/src/main/kotlin/pages/DefaultMarkdownToContentConverter.kt229
-rw-r--r--core/src/main/kotlin/pages/DocNodeToContentConverter.kt82
-rw-r--r--core/src/main/kotlin/pages/MarkdownToContentConverter.kt4
-rw-r--r--core/src/main/kotlin/pages/PageBuilder.kt23
-rw-r--r--core/src/main/kotlin/pages/PageContentBuilder.kt26
-rw-r--r--core/src/main/kotlin/pages/PageNodes.kt22
-rw-r--r--core/src/main/kotlin/parsers/HtmlParser.kt89
-rw-r--r--core/src/main/kotlin/parsers/MarkdownParser.kt206
-rw-r--r--core/src/main/kotlin/parsers/Parser.kt44
-rw-r--r--core/src/main/kotlin/parsers/factories/DocNodesFromIElementFactory.kt36
-rw-r--r--core/src/main/kotlin/parsers/factories/DocNodesFromStringFactory.kt76
-rw-r--r--core/src/main/kotlin/plugability/DefaultExtensions.kt4
-rw-r--r--core/src/main/kotlin/renderers/HtmlRenderer.kt9
-rw-r--r--core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt38
-rw-r--r--core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt9
-rw-r--r--core/src/main/kotlin/utilities/nodeDebug.kt4
-rw-r--r--core/src/test/kotlin/markdown/ParserTest.kt8
21 files changed, 720 insertions, 334 deletions
diff --git a/core/src/main/kotlin/model/DocumentationNode.kt b/core/src/main/kotlin/model/Documentable.kt
index 77225eca..9f676a1e 100644
--- a/core/src/main/kotlin/model/DocumentationNode.kt
+++ b/core/src/main/kotlin/model/Documentable.kt
@@ -1,11 +1,11 @@
package org.jetbrains.dokka.model
+import model.doc.*
import org.jetbrains.dokka.transformers.descriptors.KotlinTypeWrapper
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.pages.PlatformData
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
-class Module(val packages: List<Package>) : DocumentationNode() {
+class Module(val packages: List<Package>) : Documentable() {
override val dri: DRI = DRI.topLevel
override val children: List<Package> = packages
override val extra: MutableSet<Extra> = mutableSetOf()
@@ -70,73 +70,77 @@ class Parameter(
val type: TypeWrapper,
override val actual: List<PlatformInfo>,
override val extra: MutableSet<Extra> = mutableSetOf()
-) : DocumentationNode() {
- override val children: List<DocumentationNode>
+) : Documentable() {
+ override val children: List<Documentable>
get() = emptyList()
}
interface PlatformInfo {
- val docTag: KDocTag?
- val links: Map<String, DRI>
+ val documentationNode: DocumentationNode
val platformData: List<PlatformData>
}
class BasePlatformInfo(
- override val docTag: KDocTag?,
- override val links: Map<String, DRI>,
+ override val documentationNode: DocumentationNode,
override val platformData: List<PlatformData>) : PlatformInfo {
override fun equals(other: Any?): Boolean =
- other is PlatformInfo && (
- docTag?.text == other.docTag?.text &&
- links == other.links)
+ other is PlatformInfo && documentationNode == other.documentationNode
override fun hashCode(): Int =
- listOf(docTag?.text, links).hashCode()
+ documentationNode.hashCode()
}
class ClassPlatformInfo(
val info: PlatformInfo,
val inherited: List<DRI>) : PlatformInfo by info
-abstract class DocumentationNode {
+abstract class Documentable {
open val expected: PlatformInfo? = null
open val actual: List<PlatformInfo> = emptyList()
open val name: String? = null
val platformInfo by lazy { listOfNotNull(expected) + actual }
val platformData by lazy { platformInfo.flatMap { it.platformData }.toSet() }
-
abstract val dri: DRI
- abstract val children: List<DocumentationNode>
+ abstract val children: List<Documentable>
override fun toString(): String {
return "${javaClass.simpleName}($dri)" + briefDocstring.takeIf { it.isNotBlank() }?.let { " [$it]" }.orEmpty()
}
- override fun equals(other: Any?) = other is DocumentationNode && this.dri == other.dri
+ override fun equals(other: Any?) = other is Documentable && this.dri == other.dri
override fun hashCode() = dri.hashCode()
- val commentsData: List<Pair<String, Map<String, DRI>>>
- get() = platformInfo.mapNotNull { it.docTag?.let { tag -> Pair(tag.getContent(), it.links) } }
+
+
+ val commentsData: List<DocumentationNode>
+ get() = platformInfo.map { it.documentationNode }
val briefDocstring: String
- get() = platformInfo.firstOrNull()?.docTag?.getContent().orEmpty().shorten(40)
+ get() = docNodeSummary(platformInfo.firstOrNull()?.documentationNode?.children?.firstOrNull()?.root ?: Text(body = "")).shorten(40)
+
+ private fun docNodeSummary(docNode: DocNode): String {
+ if(docNode.children.isEmpty() && docNode is Text)
+ return docNode.body
+
+ return docNode.children.joinToString(" ") { docNodeSummary(it) }
+ }
open val extra: MutableSet<Extra> = mutableSetOf()
}
-abstract class ScopeNode : DocumentationNode() {
+abstract class ScopeNode : Documentable() {
abstract val functions: List<Function>
abstract val properties: List<Property>
abstract val classes: List<Class>
- override val children: List<DocumentationNode>
+ override val children: List<Documentable>
get() = functions + properties + classes
}
-abstract class CallableNode : DocumentationNode() {
+abstract class CallableNode : Documentable() {
abstract val receiver: Parameter?
}
@@ -152,7 +156,7 @@ interface TypeWrapper {
}
interface ClassKind
-fun DocumentationNode.dfs(predicate: (DocumentationNode) -> Boolean): DocumentationNode? =
+fun Documentable.dfs(predicate: (Documentable) -> Boolean): Documentable? =
if (predicate(this)) {
this
} else {
diff --git a/core/src/main/kotlin/model/doc/DocNode.kt b/core/src/main/kotlin/model/doc/DocNode.kt
new file mode 100644
index 00000000..0c643551
--- /dev/null
+++ b/core/src/main/kotlin/model/doc/DocNode.kt
@@ -0,0 +1,74 @@
+package model.doc
+
+import org.jetbrains.dokka.links.DRI
+
+sealed class DocNode(
+ val children: List<DocNode>,
+ val params: Map<String, String>
+)
+
+class A(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Big(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class B(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class BlockQuote(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Cite(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Code(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Dd(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Dfn(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Dir(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Div(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Dl(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Dt(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Em(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Font(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Footer(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Frame(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class FrameSet(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class H1(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class H2(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class H3(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class H4(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class H5(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class H6(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Head(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Header(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Html(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class I(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class IFrame(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Img(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Input(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Li(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Link(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Listing(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Main(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Menu(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Meta(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Nav(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class NoFrames(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class NoScript(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Ol(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class P(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Pre(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Script(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Section(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Small(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Span(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Strong(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Sub(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Sup(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Table(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Text(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap(), val body: String = "") : DocNode(children, params)
+class TBody(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Td(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class TFoot(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Th(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class THead(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Title(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Tr(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Tt(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class U(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Ul(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class Var(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params)
+class DocumentationLink(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap(), val dri: DRI) : DocNode(children, params)
+class HorizontalRule() : DocNode(emptyList(), emptyMap())
+class CustomNode(children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap()) : DocNode(children, params) \ No newline at end of file
diff --git a/core/src/main/kotlin/model/doc/DocType.kt b/core/src/main/kotlin/model/doc/DocType.kt
new file mode 100644
index 00000000..0888876e
--- /dev/null
+++ b/core/src/main/kotlin/model/doc/DocType.kt
@@ -0,0 +1,18 @@
+package model.doc
+
+sealed class DocType(val root: DocNode)
+class Description(root: DocNode) : DocType(root)
+class Author(root: DocNode) : DocType(root)
+class Version(root: DocNode) : DocType(root)
+class Since(root: DocNode) : DocType(root)
+class See(root: DocNode, val name: String) : DocType(root)
+class Param(root: DocNode, val name: String) : DocType(root)
+class Return(root: DocNode) : DocType(root)
+class Receiver(root: DocNode) : DocType(root)
+class Constructor(root: DocNode) : DocType(root)
+class Throws(root: DocNode, val name: String) : DocType(root)
+class Sample(root: DocNode, val name: String) : DocType(root)
+class Deprecated(root: DocNode) : DocType(root)
+class Property(root: DocNode, val name: String) : DocType(root)
+class Suppress(root: DocNode) : DocType(root)
+class CustomTag(root: DocNode, val name: String) : DocType(root)
diff --git a/core/src/main/kotlin/model/doc/DocumentationNode.kt b/core/src/main/kotlin/model/doc/DocumentationNode.kt
new file mode 100644
index 00000000..73424616
--- /dev/null
+++ b/core/src/main/kotlin/model/doc/DocumentationNode.kt
@@ -0,0 +1,3 @@
+package model.doc
+
+data class DocumentationNode(val children: List<DocType>) \ No newline at end of file
diff --git a/core/src/main/kotlin/pages/DefaultMarkdownToContentConverter.kt b/core/src/main/kotlin/pages/DefaultMarkdownToContentConverter.kt
deleted file mode 100644
index bb8a826d..00000000
--- a/core/src/main/kotlin/pages/DefaultMarkdownToContentConverter.kt
+++ /dev/null
@@ -1,229 +0,0 @@
-package org.jetbrains.dokka.pages
-
-import org.intellij.markdown.MarkdownElementTypes
-import org.intellij.markdown.MarkdownTokenTypes
-import org.jetbrains.dokka.markdown.MarkdownNode
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.plugability.DokkaContext
-
-class DefaultMarkdownToContentConverter(
- private val context: DokkaContext
-) : MarkdownToContentConverter {
- override fun buildContent(
- node: MarkdownNode,
- dci: DCI,
- platforms: Set<PlatformData>,
- links: Map<String, DRI>,
- styles: Set<Style>,
- extras: Set<Extra>
-
- ): List<ContentNode> {
-// println(tree.toTestString())
-
- fun buildChildren(node: MarkdownNode, newStyles: Set<Style> = emptySet(), newExtras: Set<Extra> = emptySet()) =
- node.children.flatMap {
- buildContent(it, dci, platforms, links, styles + newStyles, extras + newExtras)
- }.coalesceText(platforms, styles + newStyles, extras + newExtras)
-
- fun buildHeader(level: Int) =
- ContentHeader(buildChildren(node), level, dci, platforms, styles)
-
- return when (node.type) {
- MarkdownElementTypes.ATX_1 -> listOf(buildHeader(1))
- MarkdownElementTypes.ATX_2 -> listOf(buildHeader(2))
- MarkdownElementTypes.ATX_3 -> listOf(buildHeader(3))
- MarkdownElementTypes.ATX_4 -> listOf(buildHeader(4))
- MarkdownElementTypes.ATX_5 -> listOf(buildHeader(5))
- MarkdownElementTypes.ATX_6 -> listOf(buildHeader(6))
- MarkdownElementTypes.UNORDERED_LIST -> listOf(
- ContentList(
- buildChildren(node),
- false,
- dci,
- platforms,
- styles,
- extras
- )
- )
- MarkdownElementTypes.ORDERED_LIST -> listOf(
- ContentList(
- buildChildren(node),
- true,
- dci,
- platforms,
- styles,
- extras
- )
- )
- MarkdownElementTypes.LIST_ITEM -> TODO()
- MarkdownElementTypes.STRONG,
- MarkdownTokenTypes.EMPH,
- MarkdownElementTypes.EMPH ->
- buildChildren(node, setOf(TextStyle.Strong))
- // TODO
- MarkdownElementTypes.CODE_SPAN -> TODO()
-// val startDelimiter = node.child(MarkdownTokenTypes.BACKTICK)?.text
-// if (startDelimiter != null) {
-// val text = node.text.substring(startDelimiter.length).removeSuffix(startDelimiter)
-// val codeSpan = ContentCode().apply { append(ContentText(text)) }
-// parent.append(codeSpan)
-// }
-
- MarkdownElementTypes.CODE_BLOCK,
- MarkdownElementTypes.CODE_FENCE -> {
- val language = node.child(MarkdownTokenTypes.FENCE_LANG)?.text?.trim() ?: ""
- listOf(ContentCode(buildChildren(node), language, dci, platforms, styles, extras)) // TODO
- }
- MarkdownElementTypes.PARAGRAPH -> buildChildren(node, newStyles = setOf(TextStyle.Paragraph))
-
- MarkdownElementTypes.INLINE_LINK -> {
-// val linkTextNode = node.child(MarkdownElementTypes.LINK_TEXT)
-// val destination = node.child(MarkdownElementTypes.LINK_DESTINATION)
-// if (linkTextNode != null) {
-// if (destination != null) {
-// val link = ContentExternalLink(destination.text)
-// renderLinkTextTo(linkTextNode, link, linkResolver)
-// parent.append(link)
-// } else {
-// val link = ContentExternalLink(linkTextNode.getLabelText())
-// renderLinkTextTo(linkTextNode, link, linkResolver)
-// parent.append(link)
-// }
-// }
- //TODO: Linking!!!
-// ContentLink()
- TODO()
- }
- MarkdownElementTypes.SHORT_REFERENCE_LINK,
- MarkdownElementTypes.FULL_REFERENCE_LINK -> {
- val destinationNode = node.children.find { it.type == MarkdownElementTypes.LINK_DESTINATION }
- ?: node.children.first { it.type == MarkdownElementTypes.LINK_LABEL }
- val destination = destinationNode.children.find { it.type == MarkdownTokenTypes.TEXT }?.text
- ?: destinationNode.text
- links[destination]?.let { dri ->
- listOf(
- ContentDRILink( // TODO: differentiate between KDoc link and some external link (http://...)
- buildChildren(node),
- dri,
- DCI(dri, ContentKind.Symbol),
- platforms,
- styles,
- extras
- )
- )
- } ?: let {
- context.logger.error("Apparently there is no link resolved for $destination")
- emptyList<ContentNode>()
- }
- }
- MarkdownTokenTypes.WHITE_SPACE -> {
- // Don't append first space if start of header (it is added during formatting later)
- // v
- // #### Some Heading
-// if (nodeStack.peek() !is ContentHeading || node.parent?.children?.first() != node) {
-// parent.append(ContentText(node.text))
-// }
- listOf(ContentText(" ", dci, platforms, styles, extras))
- }
- MarkdownTokenTypes.EOL -> {
-// if ((keepEol(nodeStack.peek()) && node.parent?.children?.last() != node) ||
-// // Keep extra blank lines when processing lists (affects Markdown formatting)
-// (processingList(nodeStack.peek()) && node.previous?.type == MarkdownTokenTypes.EOL)) {
-// parent.append(ContentText(node.text))
-// }
- listOf(ContentText(" ", dci, platforms, styles, extras))
- }
-
- MarkdownTokenTypes.CODE_LINE -> {
- listOf(ContentText(node.text, dci, platforms, styles, extras)) // TODO check
-// if (parent is ContentBlockCode) {
-// parent.append(content)
-// } else {
-// parent.append(ContentBlockCode().apply { append(content) })
-// }
- }
-
- MarkdownTokenTypes.TEXT ->
-// fun createEntityOrText(text: String): ContentNode {
-// if (text == "&amp;" || text == "&quot;" || text == "&lt;" || text == "&gt;") {
-// return ContentEntity(text)
-// }
-// if (text == "&") {
-// return ContentEntity("&amp;")
-// }
-// val decodedText = EntityConverter.replaceEntities(text, true, true)
-// if (decodedText != text) {
-// return ContentEntity(text)
-// }
-// return ContentText(text)
-// }
-//
-// parent.append(createEntityOrText(node.text))
- listOf(ContentText(node.text, dci, platforms, styles, extras)) // TODO
-
- MarkdownTokenTypes.COLON,
- MarkdownTokenTypes.SINGLE_QUOTE,
- MarkdownTokenTypes.DOUBLE_QUOTE,
- MarkdownTokenTypes.LT,
- MarkdownTokenTypes.GT,
- MarkdownTokenTypes.LPAREN,
- MarkdownTokenTypes.RPAREN,
- MarkdownTokenTypes.LBRACKET,
- MarkdownTokenTypes.RBRACKET,
- MarkdownTokenTypes.EXCLAMATION_MARK,
- MarkdownTokenTypes.BACKTICK,
- MarkdownTokenTypes.CODE_FENCE_CONTENT -> {
- listOf(ContentText(node.text, dci, platforms, styles, extras))
- }
-
- MarkdownElementTypes.LINK_DEFINITION -> TODO()
-
- MarkdownTokenTypes.EMAIL_AUTOLINK ->
- listOf(
- ContentResolvedLink(
- listOf(ContentText(node.text, dci, platforms, styles, extras)),
- "mailto:${node.text}",
- dci, platforms, styles, extras
- )
- )
-
- else -> buildChildren(node)
- }
- }
-
- private fun Collection<ContentNode>.coalesceText(
- platforms: Set<PlatformData>,
- styles: Set<Style>,
- extras: Set<Extra>
- ) =
- this
- .sliceWhen { prev, next -> prev::class != next::class }
- .flatMap { nodes ->
- when (nodes.first()) {
- is ContentText -> listOf(
- ContentText(
- nodes.joinToString("") { (it as ContentText).text },
- nodes.first().dci, platforms, styles, extras
- )
- )
- else -> nodes
- }
- }
-}
-
-fun <T> Collection<T>.sliceWhen(predicate: (before: T, after: T) -> Boolean): Collection<Collection<T>> {
- val newCollection = mutableListOf<Collection<T>>()
- var currentSlice = mutableListOf<T>()
- for ((prev, next) in this.windowed(2, 1, false)) {
- currentSlice.add(prev)
- if (predicate(prev, next)) {
- newCollection.add(currentSlice)
- currentSlice = mutableListOf<T>()
- }
- }
- if (this.isNotEmpty()) {
- currentSlice.add(this.last())
- newCollection.add(currentSlice)
- }
- return newCollection
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/pages/DocNodeToContentConverter.kt b/core/src/main/kotlin/pages/DocNodeToContentConverter.kt
new file mode 100644
index 00000000..dce69114
--- /dev/null
+++ b/core/src/main/kotlin/pages/DocNodeToContentConverter.kt
@@ -0,0 +1,82 @@
+package org.jetbrains.dokka.pages
+
+import model.doc.*
+import org.intellij.markdown.MarkdownElementTypes
+import org.intellij.markdown.MarkdownTokenTypes
+import org.jetbrains.dokka.markdown.MarkdownNode
+import org.jetbrains.dokka.plugability.DokkaContext
+
+class DocNodeToContentConverter(
+ private val context: DokkaContext
+) : MarkdownToContentConverter {
+ override fun buildContent(
+ docNode: DocNode,
+ dci: DCI,
+ platforms: Set<PlatformData>,
+ styles: Set<Style>,
+ extras: Set<Extra>
+
+ ): List<ContentNode> {
+
+ fun buildChildren(docNode: DocNode, newStyles: Set<Style> = emptySet(), newExtras: Set<Extra> = emptySet()) =
+ docNode.children.flatMap {
+ buildContent(it, dci, platforms, styles + newStyles, extras + newExtras)
+ }
+
+ fun buildHeader(level: Int) =
+ listOf(ContentHeader(buildChildren(docNode), level, dci, platforms, styles, extras))
+
+ fun buildList(ordered: Boolean) =
+ listOf(ContentList(buildChildren(docNode), ordered, dci, platforms, styles, extras))
+
+ return when (docNode) {
+ is H1 -> buildHeader(1)
+ is H2 -> buildHeader(2)
+ is H3 -> buildHeader(3)
+ is H4 -> buildHeader(4)
+ is H5 -> buildHeader(5)
+ is H6 -> buildHeader(6)
+ is Ul -> buildList(false)
+ is Ol -> buildList(true)
+ is Li -> buildChildren(docNode)
+ is B -> buildChildren(docNode, setOf(TextStyle.Strong))
+ is I -> buildChildren(docNode, setOf(TextStyle.Italic))
+ is P -> buildChildren(docNode, newStyles = setOf(TextStyle.Paragraph))
+ is A -> listOf(
+ ContentResolvedLink(
+ buildChildren(docNode),
+ docNode.params.get("href")!!,
+ dci,
+ platforms,
+ styles,
+ extras
+ )
+ )
+ is DocumentationLink -> listOf(
+ ContentDRILink(
+ buildChildren(docNode),
+ docNode.dri,
+ DCI(docNode.dri, ContentKind.Symbol),
+ platforms,
+ styles,
+ extras
+ )
+ )
+ is BlockQuote -> throw NotImplementedError("Implement DocNotToContent BlockQuote!")
+ is Code -> listOf(
+ ContentCode(
+ buildChildren(docNode),
+ "",
+ dci,
+ platforms,
+ styles,
+ extras
+ )
+ )
+ is Img -> throw NotImplementedError("Implement DocNotToContent Img!")
+ is HorizontalRule -> listOf(ContentText("", dci, platforms, setOf()))
+ is Text -> listOf(ContentText(docNode.body, dci, platforms, styles, extras))
+ else -> buildChildren(docNode)
+ }
+ }
+}
diff --git a/core/src/main/kotlin/pages/MarkdownToContentConverter.kt b/core/src/main/kotlin/pages/MarkdownToContentConverter.kt
index cd96ff79..321a3f02 100644
--- a/core/src/main/kotlin/pages/MarkdownToContentConverter.kt
+++ b/core/src/main/kotlin/pages/MarkdownToContentConverter.kt
@@ -1,14 +1,14 @@
package org.jetbrains.dokka.pages
+import model.doc.DocNode
import org.jetbrains.dokka.markdown.MarkdownNode
import org.jetbrains.dokka.links.DRI
interface MarkdownToContentConverter {
fun buildContent(
- node: MarkdownNode,
+ docNode: DocNode,
dci: DCI,
platforms: Set<PlatformData>,
- links: Map<String, DRI> = emptyMap(),
styles: Set<Style> = emptySet(),
extras: Set<Extra> = emptySet()
): List<ContentNode>
diff --git a/core/src/main/kotlin/pages/PageBuilder.kt b/core/src/main/kotlin/pages/PageBuilder.kt
index 92e2c5fe..8951219a 100644
--- a/core/src/main/kotlin/pages/PageBuilder.kt
+++ b/core/src/main/kotlin/pages/PageBuilder.kt
@@ -1,5 +1,6 @@
package org.jetbrains.dokka.pages
+import model.doc.DocType
import org.jetbrains.dokka.model.*
import org.jetbrains.dokka.model.Function
@@ -29,7 +30,7 @@ class DefaultPageBuilder(
else -> throw IllegalStateException("$m should not be present here")
}
- private fun group(node: DocumentationNode, content: PageContentBuilderFunction) =
+ private fun group(node: Documentable, content: PageContentBuilderFunction) =
rootContentGroup(node, ContentKind.Main, content)
private fun contentForModule(m: Module) = group(m) {
@@ -60,7 +61,13 @@ class DefaultPageBuilder(
header(2) { text("SuperInterfaces") }
linkTable(it)
}
- c.commentsData.forEach { (doc, links) -> comment(doc, links) }
+ c.commentsData.forEach {
+ it.children.forEach {
+ header(3) { text(it.toHeaderString()) }
+ comment(it.root)
+ text("\n")
+ }
+ }
block("Constructors", 2, ContentKind.Functions, c.constructors, c.platformData) {
link(it.name, it.dri)
signature(it)
@@ -71,20 +78,26 @@ class DefaultPageBuilder(
signature(it)
text(it.briefDocstring)
}
+ block("Properties", 2, ContentKind.Properties, c.properties, c.platformData) {
+ link(it.name, it.dri)
+ text(it.briefDocstring)
+ }
}
private fun contentForFunction(f: Function) = group(f) {
header(1) { text(f.name) }
signature(f)
- f.commentsData.forEach { (doc, links) -> markdown(doc, links) }
+ f.commentsData.forEach { it.children.forEach { comment(it.root) } }
block("Parameters", 2, ContentKind.Parameters, f.children, f.platformData) {
text(it.name ?: "<receiver>")
- it.commentsData.forEach { (doc, links) -> markdown(doc, links) }
+ it.commentsData.forEach { it.children.forEach { comment(it.root) } }
}
}
+
+ private fun DocType.toHeaderString() = this.javaClass.toGenericString().split('.').last()
}
-typealias RootContentBuilder = (DocumentationNode, Kind, PageContentBuilderFunction) -> ContentGroup
+typealias RootContentBuilder = (Documentable, Kind, PageContentBuilderFunction) -> ContentGroup
interface PageBuilder {
val rootContentGroup: RootContentBuilder
diff --git a/core/src/main/kotlin/pages/PageContentBuilder.kt b/core/src/main/kotlin/pages/PageContentBuilder.kt
index 3e852306..e3c924d1 100644
--- a/core/src/main/kotlin/pages/PageContentBuilder.kt
+++ b/core/src/main/kotlin/pages/PageContentBuilder.kt
@@ -1,12 +1,12 @@
package org.jetbrains.dokka.pages
+import model.doc.DocNode
import org.jetbrains.dokka.utilities.DokkaLogger
-import org.jetbrains.dokka.model.DocumentationNode
+import org.jetbrains.dokka.model.Documentable
import org.jetbrains.dokka.model.Function
import org.jetbrains.dokka.model.Parameter
import org.jetbrains.dokka.model.TypeWrapper
import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.markdown.parseMarkdown
class DefaultPageContentBuilder(
private val dri: DRI,
@@ -73,7 +73,7 @@ class DefaultPageContentBuilder(
)
}
- override fun <T : DocumentationNode> block(
+ override fun <T : Documentable> block(
name: String,
level: Int,
kind: Kind,
@@ -127,27 +127,18 @@ class DefaultPageContentBuilder(
)
}
- override fun comment(raw: String, links: Map<String, DRI>) {
+ override fun comment(docNode: DocNode) {
contents += group(ContentKind.Comment) {
with(this as DefaultPageContentBuilder) {
contents += markdownConverter.buildContent(
- parseMarkdown(raw),
+ docNode,
DCI(dri, ContentKind.Comment),
- platformData,
- links
+ platformData
)
}
}
}
- override fun markdown(raw: String, links: Map<String, DRI>) {
- contents += markdownConverter.buildContent(
- parseMarkdown(raw), DCI(dri, ContentKind.Sample),
- platformData,
- links
- )
- }
-
fun group(kind: Kind, block: PageContentBuilderFunction): ContentGroup =
group(dri, platformData, kind, block)
@@ -200,8 +191,7 @@ interface PageContentBuilder {
fun link(text: String, address: DRI, kind: Kind = ContentKind.Symbol)
fun link(address: DRI, kind: Kind = ContentKind.Symbol, block: PageContentBuilderFunction)
fun linkTable(elements: List<DRI>)
- fun comment(raw: String, links: Map<String, DRI>)
- fun markdown(raw: String, links: Map<String, DRI>)
+ fun comment(docNode: DocNode)
fun header(level: Int, block: PageContentBuilderFunction)
fun <T> list(
elements: List<T>,
@@ -211,7 +201,7 @@ interface PageContentBuilder {
operation: PageContentBuilder.(T) -> Unit
)
- fun <T : DocumentationNode> block(
+ fun <T : Documentable> block(
name: String,
level: Int,
kind: Kind,
diff --git a/core/src/main/kotlin/pages/PageNodes.kt b/core/src/main/kotlin/pages/PageNodes.kt
index f1ad430f..0aa439de 100644
--- a/core/src/main/kotlin/pages/PageNodes.kt
+++ b/core/src/main/kotlin/pages/PageNodes.kt
@@ -1,6 +1,6 @@
package org.jetbrains.dokka.pages
-import org.jetbrains.dokka.model.DocumentationNode
+import org.jetbrains.dokka.model.Documentable
import org.jetbrains.dokka.Platform
import org.jetbrains.dokka.links.DRI
import java.util.*
@@ -9,7 +9,7 @@ interface PageNode {
val name: String
val content: ContentNode
val dri: DRI
- val documentationNode: DocumentationNode?
+ val documentable: Documentable?
val embeddedResources: List<String>
val children: List<PageNode>
@@ -24,7 +24,8 @@ interface PageNode {
class ModulePageNode(
override val name: String,
override val content: ContentNode,
- override val documentationNode: DocumentationNode?,
+
+ override val documentable: Documentable?,
override val children: List<PageNode>,
override val embeddedResources: List<String> = listOf()
) : PageNode {
@@ -37,7 +38,7 @@ class ModulePageNode(
children: List<PageNode>
): ModulePageNode =
if (name == this.name && content === this.content && embeddedResources === this.embeddedResources && children shallowEq this.children) this
- else ModulePageNode(name, content, documentationNode, children, embeddedResources)
+ else ModulePageNode(name, content, documentable, children, embeddedResources)
private fun PageNode.transformNode(operation: (PageNode) -> PageNode): PageNode =
operation(this).let { newNode ->
@@ -64,7 +65,8 @@ class PackagePageNode(
override val name: String,
override val content: ContentNode,
override val dri: DRI,
- override val documentationNode: DocumentationNode?,
+
+ override val documentable: Documentable?,
override val children: List<PageNode>,
override val embeddedResources: List<String> = listOf()
) : PageNode {
@@ -76,14 +78,14 @@ class PackagePageNode(
children: List<PageNode>
): PackagePageNode =
if (name == this.name && content === this.content && embeddedResources === this.embeddedResources && children shallowEq this.children) this
- else PackagePageNode(name, content, dri, documentationNode, children, embeddedResources)
+ else PackagePageNode(name, content, dri, documentable, children, embeddedResources)
}
class ClassPageNode(
override val name: String,
override val content: ContentNode,
override val dri: DRI,
- override val documentationNode: DocumentationNode?,
+ override val documentable: Documentable?,
override val children: List<PageNode>,
override val embeddedResources: List<String> = listOf()
) : PageNode {
@@ -95,14 +97,14 @@ class ClassPageNode(
children: List<PageNode>
): ClassPageNode =
if (name == this.name && content === this.content && embeddedResources === this.embeddedResources && children shallowEq this.children) this
- else ClassPageNode(name, content, dri, documentationNode, children, embeddedResources)
+ else ClassPageNode(name, content, dri, documentable, children, embeddedResources)
}
class MemberPageNode(
override val name: String,
override val content: ContentNode,
override val dri: DRI,
- override val documentationNode: DocumentationNode?,
+ override val documentable: Documentable?,
override val children: List<PageNode> = emptyList(),
override val embeddedResources: List<String> = listOf()
) : PageNode {
@@ -114,7 +116,7 @@ class MemberPageNode(
children: List<PageNode>
): MemberPageNode =
if (name == this.name && content === this.content && embeddedResources === this.embeddedResources && children shallowEq this.children) this
- else MemberPageNode(name, content, dri, documentationNode, children, embeddedResources)
+ else MemberPageNode(name, content, dri, documentable, children, embeddedResources)
}
data class PlatformData(val platformType: Platform, val targets: List<String>) {
diff --git a/core/src/main/kotlin/parsers/HtmlParser.kt b/core/src/main/kotlin/parsers/HtmlParser.kt
new file mode 100644
index 00000000..30f882b1
--- /dev/null
+++ b/core/src/main/kotlin/parsers/HtmlParser.kt
@@ -0,0 +1,89 @@
+package parsers
+
+import model.doc.*
+import org.jetbrains.dokka.parsers.factories.DocNodesFromStringFactory
+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<DocNode>> = mutableMapOf()
+ private var currentDepth = 0
+
+ fun collect(): DocNode = 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) {
+ DocNodesFromStringFactory.getInstance(nodeName, nodesCache.getOrDefault(currentDepth, mutableListOf()).toList(), params, body).also {
+ nodesCache[currentDepth] = mutableListOf()
+ currentDepth = depth
+ }
+ } else {
+ DocNodesFromStringFactory.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): DocNode {
+ 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/core/src/main/kotlin/parsers/MarkdownParser.kt b/core/src/main/kotlin/parsers/MarkdownParser.kt
new file mode 100644
index 00000000..44c917e3
--- /dev/null
+++ b/core/src/main/kotlin/parsers/MarkdownParser.kt
@@ -0,0 +1,206 @@
+package parsers
+
+import model.doc.*
+import org.intellij.markdown.MarkdownElementTypes
+import org.intellij.markdown.MarkdownTokenTypes
+import org.intellij.markdown.ast.ASTNode
+import org.intellij.markdown.ast.impl.ListItemCompositeNode
+import org.intellij.markdown.flavours.commonmark.CommonMarkFlavourDescriptor
+import org.jetbrains.dokka.analysis.DokkaResolutionFacade
+import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.parsers.factories.DocNodesFromIElementFactory
+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.KDocTag
+import org.intellij.markdown.parser.MarkdownParser as IntellijMarkdownParser
+
+class MarkdownParser (
+ private val resolutionFacade: DokkaResolutionFacade,
+ private val declarationDescriptor: DeclarationDescriptor
+ ) : Parser() {
+
+ inner class MarkdownVisitor(val text: String) {
+
+ private fun headersHandler(node: ASTNode): DocNode =
+ DocNodesFromIElementFactory.getInstance(node.type, visitNode(node.children.find { it.type == MarkdownTokenTypes.ATX_CONTENT }!!).children.drop(1))
+
+ private fun horizontalRulesHandler(node: ASTNode): DocNode =
+ DocNodesFromIElementFactory.getInstance(MarkdownTokenTypes.HORIZONTAL_RULE)
+
+ private fun emphasisHandler(node: ASTNode): DocNode =
+ DocNodesFromIElementFactory.getInstance(node.type, children = listOf(visitNode(node.children[node.children.size/2])))
+
+ private fun blockquotesHandler(node: ASTNode): DocNode =
+ DocNodesFromIElementFactory.getInstance(node.type, children = node.children.drop(1).map { visitNode(it) })
+
+ private fun listsHandler(node: ASTNode): DocNode {
+
+ 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 DocNodesFromIElementFactory.getInstance(
+ node.type,
+ children =
+ children
+ .map {
+ if(it.type == MarkdownElementTypes.LIST_ITEM)
+ DocNodesFromIElementFactory.getInstance(
+ it.type,
+ children = it
+ .children
+ .drop(1)
+ .filter { it.type !in listOf(MarkdownTokenTypes.WHITE_SPACE, MarkdownTokenTypes.EOL) }
+ .map { visitNode(it) }
+ )
+ 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).dropLast(2))
+ } else
+ emptyMap()
+ )
+ }
+
+ private fun linksHandler(node: ASTNode): DocNode {
+ val linkNode = node.children.find { it.type == MarkdownElementTypes.LINK_LABEL }!!
+ val link = text.substring(linkNode.startOffset+1, linkNode.endOffset-1)
+
+ val dri: DRI? = if (link.startsWith("http") || link.startsWith("www")) {
+ null
+ } else {
+ DRI.from(
+ resolveKDocLink(
+ resolutionFacade.resolveSession.bindingContext,
+ resolutionFacade,
+ declarationDescriptor,
+ null,
+ link.split('.')
+ ).single()
+ )
+ }
+ val href = mapOf("href" to link)
+ return when (node.type) {
+ MarkdownElementTypes.FULL_REFERENCE_LINK -> DocNodesFromIElementFactory.getInstance(node.type, params = href, children = node.children.find { it.type == MarkdownElementTypes.LINK_TEXT }!!.children.drop(1).dropLast(1).map { visitNode(it) }, dri = dri)
+ else -> DocNodesFromIElementFactory.getInstance(node.type, params = href, children = listOf(visitNode(linkNode)), dri = dri)
+ }
+ }
+
+ private fun imagesHandler(node: ASTNode): DocNode {
+ 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 DocNodesFromIElementFactory.getInstance(node.type, params = src, children = listOf(visitNode(node.children.last().children.find { it.type == MarkdownElementTypes.LINK_TEXT }!!)))
+ }
+
+ private fun codeSpansHandler(node: ASTNode): DocNode =
+ DocNodesFromIElementFactory.getInstance(
+ node.type,
+ children = listOf(
+ DocNodesFromIElementFactory.getInstance(
+ MarkdownTokenTypes.TEXT,
+ body = text.substring(node.startOffset+1, node.endOffset-1).replace('\n', ' ').trimIndent()
+ )
+
+ )
+ )
+
+ private fun codeFencesHandler(node: ASTNode): DocNode =
+ DocNodesFromIElementFactory.getInstance(
+ node.type,
+ children = node
+ .children
+ .filter { it.type == MarkdownTokenTypes.CODE_FENCE_CONTENT }
+ .map { visitNode(it) },
+ 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): DocNode =
+ DocNodesFromIElementFactory.getInstance(node.type, children = node.children.map { visitNode(it) })
+
+ private fun defaultHandler(node: ASTNode): DocNode =
+ DocNodesFromIElementFactory.getInstance(MarkdownElementTypes.PARAGRAPH, children = node.children.map { visitNode(it) })
+
+ fun visitNode(node: ASTNode): DocNode =
+ 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 -> linksHandler(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.EOL -> DocNodesFromIElementFactory.getInstance(MarkdownTokenTypes.TEXT, body = "\n")
+ MarkdownTokenTypes.WHITE_SPACE -> DocNodesFromIElementFactory.getInstance(MarkdownTokenTypes.TEXT, body = " ")
+ MarkdownTokenTypes.CODE_FENCE_CONTENT,
+ MarkdownTokenTypes.CODE_LINE,
+ MarkdownTokenTypes.TEXT -> DocNodesFromIElementFactory.getInstance(MarkdownTokenTypes.TEXT, body = text.substring(node.startOffset, node.endOffset))
+ else -> defaultHandler(node)
+ }
+ }
+
+ private fun markdownToDocNode(text: String): DocNode {
+
+ val flavourDescriptor = CommonMarkFlavourDescriptor()
+ val markdownAstRoot: ASTNode = IntellijMarkdownParser(flavourDescriptor).buildMarkdownTreeFromString(text)
+
+ return MarkdownVisitor(text).visitNode(markdownAstRoot)
+ }
+
+ override fun parseStringToDocNode(extractedString: String) = markdownToDocNode(extractedString)
+ override fun preparse(text: String) = text
+
+ fun parseFromKDocTag(kDocTag: KDocTag?): DocumentationNode {
+ return if(kDocTag == null)
+ DocumentationNode(emptyList())
+ else
+ DocumentationNode(
+ (listOf(kDocTag) + kDocTag.children).filterIsInstance<KDocTag>().map {
+ when( it.knownTag ) {
+ null -> Description(parseStringToDocNode(it.getContent()))
+ KDocKnownTag.AUTHOR -> Author(parseStringToDocNode(it.getContent()))
+ KDocKnownTag.THROWS -> Throws(parseStringToDocNode(it.getContent()), it.getSubjectName()!!)
+ KDocKnownTag.EXCEPTION -> Throws(parseStringToDocNode(it.getContent()), it.getSubjectName()!!)
+ KDocKnownTag.PARAM -> Param(parseStringToDocNode(it.getContent()), it.getSubjectName()!!)
+ KDocKnownTag.RECEIVER -> Receiver(parseStringToDocNode(it.getContent()))
+ KDocKnownTag.RETURN -> Return(parseStringToDocNode(it.getContent()))
+ KDocKnownTag.SEE -> See(parseStringToDocNode(it.getContent()), it.getSubjectName()!!)
+ KDocKnownTag.SINCE -> Since(parseStringToDocNode(it.getContent()))
+ KDocKnownTag.CONSTRUCTOR -> Constructor(parseStringToDocNode(it.getContent()))
+ KDocKnownTag.PROPERTY -> Property(parseStringToDocNode(it.getContent()), it.getSubjectName()!!)
+ KDocKnownTag.SAMPLE -> Sample(parseStringToDocNode(it.getContent()), it.getSubjectName()!!)
+ KDocKnownTag.SUPPRESS -> Suppress(parseStringToDocNode(it.getContent()))
+ }
+ }
+ )
+ }
+
+
+
+
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/parsers/Parser.kt b/core/src/main/kotlin/parsers/Parser.kt
new file mode 100644
index 00000000..a2a90dcd
--- /dev/null
+++ b/core/src/main/kotlin/parsers/Parser.kt
@@ -0,0 +1,44 @@
+package parsers
+
+import model.doc.*
+import model.doc.Deprecated
+
+
+abstract class Parser {
+
+ abstract fun parseStringToDocNode(extractedString: String): DocNode
+ abstract fun preparse(text: String): String
+
+ fun parse(text: String): DocumentationNode {
+
+ val list = jkdocToListOfPairs(preparse(text))
+
+ val mappedList: List<DocType> = 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(' '))
+ "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 -> CustomTag(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/core/src/main/kotlin/parsers/factories/DocNodesFromIElementFactory.kt b/core/src/main/kotlin/parsers/factories/DocNodesFromIElementFactory.kt
new file mode 100644
index 00000000..a93be0d3
--- /dev/null
+++ b/core/src/main/kotlin/parsers/factories/DocNodesFromIElementFactory.kt
@@ -0,0 +1,36 @@
+package org.jetbrains.dokka.parsers.factories
+
+import model.doc.*
+import org.intellij.markdown.IElementType
+import org.intellij.markdown.MarkdownElementTypes
+import org.intellij.markdown.MarkdownTokenTypes
+import org.jetbrains.dokka.links.DRI
+import java.lang.NullPointerException
+
+object DocNodesFromIElementFactory {
+ fun getInstance(type: IElementType, children: List<DocNode> = emptyList(), params: Map<String, String> = emptyMap(), body: String? = null, dri: DRI? = null) =
+ when(type) {
+ MarkdownElementTypes.SHORT_REFERENCE_LINK,
+ MarkdownElementTypes.FULL_REFERENCE_LINK -> if(dri == null) A(children, params) else DocumentationLink(children, params, dri)
+ 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(children, params, body ?: throw NullPointerException("Text body should be at least empty string passed to DocNodes factory!"))
+ MarkdownTokenTypes.HORIZONTAL_RULE -> HorizontalRule()
+ else -> CustomNode(children, params)
+ }
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/parsers/factories/DocNodesFromStringFactory.kt b/core/src/main/kotlin/parsers/factories/DocNodesFromStringFactory.kt
new file mode 100644
index 00000000..49102ed0
--- /dev/null
+++ b/core/src/main/kotlin/parsers/factories/DocNodesFromStringFactory.kt
@@ -0,0 +1,76 @@
+package org.jetbrains.dokka.parsers.factories
+
+import model.doc.*
+import org.jetbrains.dokka.links.DRI
+import java.lang.NullPointerException
+
+object DocNodesFromStringFactory {
+ fun getInstance(name: String, children: List<DocNode> = 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)
+ "bite" -> Cite(children, params)
+ "bode" -> 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(children, params, body ?: throw NullPointerException("Text body should be at least empty string passed to DocNodes factory!"))
+ "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(children, params, dri ?: throw NullPointerException("DRI cannot be passed null while constructing documentation link!"))
+ "hr" -> HorizontalRule()
+ else -> CustomNode(children, params)
+ }
+} \ No newline at end of file
diff --git a/core/src/main/kotlin/plugability/DefaultExtensions.kt b/core/src/main/kotlin/plugability/DefaultExtensions.kt
index d89fc031..e46ade01 100644
--- a/core/src/main/kotlin/plugability/DefaultExtensions.kt
+++ b/core/src/main/kotlin/plugability/DefaultExtensions.kt
@@ -1,7 +1,7 @@
package org.jetbrains.dokka.plugability
import org.jetbrains.dokka.CoreExtensions
-import org.jetbrains.dokka.pages.DefaultMarkdownToContentConverter
+import org.jetbrains.dokka.pages.DocNodeToContentConverter
import org.jetbrains.dokka.renderers.HtmlRenderer
import org.jetbrains.dokka.resolvers.DefaultLocationProvider
import org.jetbrains.dokka.transformers.descriptors.DefaultDescriptorToDocumentationTranslator
@@ -14,7 +14,7 @@ object DefaultExtensions : DokkaExtensionHandler {
when (point) {
CoreExtensions.descriptorToDocumentationTranslator -> DefaultDescriptorToDocumentationTranslator
CoreExtensions.documentationMerger -> DefaultDocumentationNodeMerger
- CoreExtensions.markdownToContentConverterFactory -> ::DefaultMarkdownToContentConverter
+ CoreExtensions.markdownToContentConverterFactory -> ::DocNodeToContentConverter
CoreExtensions.documentationToPageTranslator -> DefaultDocumentationToPageTranslator
CoreExtensions.rendererFactory -> ::HtmlRenderer
CoreExtensions.locationProviderFactory -> ::DefaultLocationProvider
diff --git a/core/src/main/kotlin/renderers/HtmlRenderer.kt b/core/src/main/kotlin/renderers/HtmlRenderer.kt
index c04a18b4..e9f2801e 100644
--- a/core/src/main/kotlin/renderers/HtmlRenderer.kt
+++ b/core/src/main/kotlin/renderers/HtmlRenderer.kt
@@ -20,7 +20,12 @@ open class HtmlRenderer(
}
protected open fun buildListItems(items: List<ContentNode>, pageContext: PageNode) =
- "<li>\n${items.joinToString("\n</li>\n<li>\n") { it.build(pageContext) }}\n</li>"
+ items.joinToString("") {
+ if (it is ContentText) "<li>\n${it.build(pageContext)}\n</li>\n" else buildList(
+ it as ContentList,
+ pageContext
+ )
+ }
override fun buildResource(node: ContentEmbeddedResource, pageContext: PageNode): String { // TODO: extension point there
val imageExtensions = setOf("png", "jpg", "jpeg", "gif", "bmp", "tif", "webp", "svg")
@@ -59,7 +64,7 @@ open class HtmlRenderer(
override fun buildLink(text: String, address: String): String = "<a href=\"$address\">$text</a>"
- override fun buildCode(code: List<ContentNode>, language: String, pageContext: PageNode): String = "<code>$code</code>"
+ override fun buildCode(code: List<ContentNode>, language: String, pageContext: PageNode): String = buildNewLine() + "<code>${code.joinToString("") { (it as ContentText).text + buildNewLine() }}</code>"
override fun buildText(textNode: ContentText): String = super.buildText(textNode).htmlEscape()
diff --git a/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt b/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt
index 4ffa4295..bdd345f1 100644
--- a/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt
+++ b/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt
@@ -12,15 +12,13 @@ import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies
import org.jetbrains.kotlin.idea.kdoc.findKDoc
-import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink
-import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.MemberScope
import org.jetbrains.kotlin.types.KotlinType
+import parsers.MarkdownParser
object DefaultDescriptorToDocumentationTranslator: DescriptorToDocumentationTranslator {
override fun invoke(
@@ -36,7 +34,7 @@ object DefaultDescriptorToDocumentationTranslator: DescriptorToDocumentationTran
class DokkaDescriptorVisitor(
private val platformData: PlatformData,
private val resolutionFacade: DokkaResolutionFacade
-) : DeclarationDescriptorVisitorEmptyBodies<DocumentationNode, DRI>() {
+) : DeclarationDescriptorVisitorEmptyBodies<Documentable, DRI>() {
override fun visitDeclarationDescriptor(descriptor: DeclarationDescriptor, parent: DRI): Nothing {
throw IllegalStateException("${javaClass.simpleName} should never enter ${descriptor.javaClass.simpleName}")
}
@@ -69,7 +67,7 @@ class DokkaDescriptorVisitor(
scope.classes(dri),
descriptor.takeIf { it.isExpect }?.resolveClassDescriptionData(),
listOfNotNull(descriptorData),
- getXMLDRIs(descriptor, descriptorData).toMutableSet()
+ mutableSetOf() // TODO Implement following method to return proper results getXMLDRIs(descriptor, descriptorData).toMutableSet()
)
}
@@ -147,39 +145,15 @@ class DokkaDescriptorVisitor(
private fun DeclarationDescriptor.resolveDescriptorData(): PlatformInfo {
val doc = findKDoc()
- val links = doc?.children?.filter { it is KDocLink }?.flatMap { link ->
- val destination = link.children.first { it is KDocName }.text
- resolveKDocLink(
- resolutionFacade.resolveSession.bindingContext,
- resolutionFacade,
- this,
- null,
- destination.split('.')
- ).map { Pair(destination, DRI.from(it)) }
- }?.toMap() ?: emptyMap()
- return BasePlatformInfo(doc, links, listOf(platformData))
+ val parser: MarkdownParser = MarkdownParser(resolutionFacade, this)
+ val docHeader = parser.parseFromKDocTag(doc)
+ return BasePlatformInfo(docHeader, listOf(platformData))
}
private fun ClassDescriptor.resolveClassDescriptionData(): ClassPlatformInfo {
return ClassPlatformInfo(resolveDescriptorData(),
(getSuperInterfaces() + getAllSuperclassesWithoutAny()).map { DRI.from(it) })
}
-
- private fun getXMLDRIs(descriptor: DeclarationDescriptor, platformInfo: PlatformInfo?) =
- platformInfo?.docTag?.children
- ?.filter {
- it.text.contains("@attr")
- }?.flatMap { ref ->
- val matchResult = "@attr\\s+ref\\s+(.+)".toRegex().matchEntire(ref.text)
- val toFind = matchResult?.groups?.last()?.value.orEmpty()
- resolveKDocLink(
- resolutionFacade.resolveSession.bindingContext,
- resolutionFacade,
- descriptor,
- null,
- toFind.split('.')
- ).map { XMLMega("@attr ref", DRI.from(it)) }
- }.orEmpty()
}
data class XMLMega(val key: String, val dri: DRI) : Extra
diff --git a/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt b/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt
index 2b00c582..ef0f48d6 100644
--- a/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt
+++ b/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt
@@ -14,14 +14,13 @@ internal object DefaultDocumentationNodeMerger : DocumentationNodeMerger {
)
}
-private fun <T: DocumentationNode> merge(elements: List<T>, reducer: (T, T) -> T): List<T> =
+private fun <T: Documentable> merge(elements: List<T>, reducer: (T, T) -> T): List<T> =
elements.groupingBy { it.dri }
.reduce { _, left, right -> reducer(left, right)}
.values.toList()
fun PlatformInfo.mergeWith(other: PlatformInfo?) = BasePlatformInfo(
- docTag,
- links,
+ documentationNode,
(platformData + (other?.platformData ?: emptyList())).distinct()
)
@@ -31,12 +30,12 @@ fun ClassPlatformInfo.mergeWith(other: ClassPlatformInfo?) = ClassPlatformInfo(
)
fun List<ClassPlatformInfo>.mergeClassPlatformInfo() : List<ClassPlatformInfo> =
- groupingBy { it.docTag.toString() + it.links + it.inherited}.reduce {
+ groupingBy { it.documentationNode.children + it.inherited}.reduce {
_, left, right -> left.mergeWith(right)
}.values.toList()
fun List<PlatformInfo>.merge() : List<PlatformInfo> =
- groupingBy { it.docTag.toString() + it.links }.reduce {
+ groupingBy { it.documentationNode }.reduce {
_, left, right -> left.mergeWith(right)
}.values.toList()
diff --git a/core/src/main/kotlin/utilities/nodeDebug.kt b/core/src/main/kotlin/utilities/nodeDebug.kt
index 3290202e..984f13ed 100644
--- a/core/src/main/kotlin/utilities/nodeDebug.kt
+++ b/core/src/main/kotlin/utilities/nodeDebug.kt
@@ -1,13 +1,13 @@
package org.jetbrains.dokka.utilities
-import org.jetbrains.dokka.model.DocumentationNode
+import org.jetbrains.dokka.model.Documentable
import org.jetbrains.dokka.pages.*
const val DOWN = '\u2503'
const val BRANCH = '\u2523'
const val LAST = '\u2517'
-fun DocumentationNode.pretty(prefix: String = "", isLast: Boolean = true): String {
+fun Documentable.pretty(prefix: String = "", isLast: Boolean = true): String {
val nextPrefix = prefix + (if (isLast) ' ' else DOWN) + ' '
return prefix + (if (isLast) LAST else BRANCH) + this.toString() +
diff --git a/core/src/test/kotlin/markdown/ParserTest.kt b/core/src/test/kotlin/markdown/ParserTest.kt
index b0ec68ff..e5944e17 100644
--- a/core/src/test/kotlin/markdown/ParserTest.kt
+++ b/core/src/test/kotlin/markdown/ParserTest.kt
@@ -1,17 +1,17 @@
package org.jetbrains.dokka.tests
import org.junit.Test
-import org.jetbrains.dokka.toTestString
-import org.jetbrains.dokka.parseMarkdown
+//import org.jetbrains.dokkatoTestString
+//import org.jetbrains.dokka.parseMarkdown
import org.junit.Ignore
@Ignore public class ParserTest {
fun runTestFor(text : String) {
println("MD: ---")
println(text)
- val markdownTree = parseMarkdown(text)
+// val markdownTree = parseMarkdown(text)
println("AST: ---")
- println(markdownTree.toTestString())
+// println(markdownTree.toTestString())
println()
}