aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.idea/compiler.xml2
-rw-r--r--core/src/main/kotlin/CoreExtensions.kt35
-rw-r--r--core/src/main/kotlin/DokkaGenerator.kt183
-rw-r--r--core/src/main/kotlin/Model/DocumentationNode.kt2
-rw-r--r--core/src/main/kotlin/Model/transformers/DocumentationNodeTransformer.kt8
-rw-r--r--core/src/main/kotlin/pages/DefaultMarkdownToContentConverter.kt229
-rw-r--r--core/src/main/kotlin/pages/MarkdownToContentConverter.kt219
-rw-r--r--core/src/main/kotlin/pages/transformers/PageNodeTransformer.kt7
-rw-r--r--core/src/main/kotlin/plugability/DefaultExtensions.kt25
-rw-r--r--core/src/main/kotlin/plugability/DokkaContext.kt61
-rw-r--r--core/src/main/kotlin/plugability/extensions.kt2
-rw-r--r--core/src/main/kotlin/renderers/DefaultRenderer.kt7
-rw-r--r--core/src/main/kotlin/renderers/HtmlRenderer.kt7
-rw-r--r--core/src/main/kotlin/renderers/Renderer.kt1
-rw-r--r--core/src/main/kotlin/resolvers/DefaultLocationProvider.kt11
-rw-r--r--core/src/main/kotlin/transformers/DefaultDocumentationToPageTransformer.kt20
-rw-r--r--core/src/main/kotlin/transformers/PageNodeTransformer.kt8
-rw-r--r--core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt (renamed from core/src/main/kotlin/DokkaDescriptorVisitor.kt)21
-rw-r--r--core/src/main/kotlin/transformers/descriptors/DescriptorToDocumentationTranslator.kt15
-rw-r--r--core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt (renamed from core/src/main/kotlin/Model/transformers/DocumentationNodesMerger.kt)24
-rw-r--r--core/src/main/kotlin/transformers/documentation/DefaultDocumentationToPageTranslator.kt24
-rw-r--r--core/src/main/kotlin/transformers/documentation/DocumentationNodeMerger.kt8
-rw-r--r--core/src/main/kotlin/transformers/documentation/DocumentationNodeTransformer.kt8
-rw-r--r--core/src/main/kotlin/transformers/documentation/DocumentationToPageTranslator.kt (renamed from core/src/main/kotlin/transformers/DocumentationToPageTransformer.kt)7
-rw-r--r--core/src/main/kotlin/transformers/pages/PageNodeTransformer.kt8
-rw-r--r--plugins/mathjax/src/main/kotlin/MathjaxPlugin.kt3
-rw-r--r--plugins/xml/src/main/kotlin/XmlPlugin.kt10
27 files changed, 588 insertions, 367 deletions
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 34ea6446..e78fe4d3 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -50,6 +50,8 @@
<module name="dokka.plugins.mathjax.main" target="1.8" />
<module name="dokka.plugins.mathjax.test" target="1.8" />
<module name="dokka.plugins.test" target="1.8" />
+ <module name="dokka.plugins.xml.main" target="1.8" />
+ <module name="dokka.plugins.xml.test" target="1.8" />
<module name="dokka.runners.android-gradle-plugin.main" target="1.8" />
<module name="dokka.runners.android-gradle-plugin.test" target="1.8" />
<module name="dokka.runners.ant.main" target="1.8" />
diff --git a/core/src/main/kotlin/CoreExtensions.kt b/core/src/main/kotlin/CoreExtensions.kt
index 6579cab2..f56cd854 100644
--- a/core/src/main/kotlin/CoreExtensions.kt
+++ b/core/src/main/kotlin/CoreExtensions.kt
@@ -1,14 +1,37 @@
package org.jetbrains.dokka
-import org.jetbrains.dokka.Model.transformers.DocumentationNodeTransformer
+import org.jetbrains.dokka.pages.MarkdownToContentConverter
+import org.jetbrains.dokka.pages.PageNode
+import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.ExtensionPoint
+import org.jetbrains.dokka.renderers.FileWriter
import org.jetbrains.dokka.renderers.Renderer
import org.jetbrains.dokka.resolvers.LocationProvider
-import org.jetbrains.dokka.transformers.PageNodeTransformer
+import org.jetbrains.dokka.transformers.descriptors.DescriptorToDocumentationTranslator
+import org.jetbrains.dokka.transformers.documentation.DocumentationNodeMerger
+import org.jetbrains.dokka.transformers.documentation.DocumentationNodeTransformer
+import org.jetbrains.dokka.transformers.documentation.DocumentationToPageTranslator
+import org.jetbrains.dokka.transformers.pages.PageNodeTransformer
+import kotlin.reflect.KProperty
+
+/**
+ * Extension points declared by dokka core.
+ * Default values are stored in [org.jetbrains.dokka.plugability.DefaultExtensions]
+ */
object CoreExtensions {
- val nodeTransformer = ExtensionPoint<DocumentationNodeTransformer>(this::class.qualifiedName!!, "nodeTransformer")
- val pageTransformer = ExtensionPoint<PageNodeTransformer>(this::class.qualifiedName!!, "pageTransformer")
- val renderer = ExtensionPoint<Renderer>(this::class.qualifiedName!!, "renderer")
- val locationProvider = ExtensionPoint<LocationProvider>(this::class.qualifiedName!!, "locationProvider")
+ val descriptorToDocumentationTranslator by coreExtension<DescriptorToDocumentationTranslator>()
+ val documentationMerger by coreExtension<DocumentationNodeMerger>()
+ val documentationTransformer by coreExtension<DocumentationNodeTransformer>()
+ val markdownToContentConverterFactory by coreExtension<(DokkaContext) -> MarkdownToContentConverter>()
+ val documentationToPageTranslator by coreExtension<DocumentationToPageTranslator>()
+ val pageTransformer by coreExtension<PageNodeTransformer>()
+ val renderer by coreExtension<(FileWriter, LocationProvider, DokkaContext) -> Renderer>()
+ val locationProvider by coreExtension<(root: PageNode, DokkaConfiguration, DokkaContext) -> LocationProvider>()
+ val fileExtension by coreExtension<String>()
+
+ private fun <T: Any> coreExtension() = object {
+ operator fun provideDelegate(thisRef: CoreExtensions, property: KProperty<*>): Lazy<ExtensionPoint<T>> =
+ lazy { ExtensionPoint<T>(thisRef::class.qualifiedName!!, property.name) }
+ }
} \ No newline at end of file
diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt
index 05eb3054..b6bf7a73 100644
--- a/core/src/main/kotlin/DokkaGenerator.kt
+++ b/core/src/main/kotlin/DokkaGenerator.kt
@@ -1,20 +1,24 @@
package org.jetbrains.dokka
import org.jetbrains.dokka.Model.Module
-import org.jetbrains.dokka.Model.transformers.DocumentationNodesMerger
import org.jetbrains.dokka.Utilities.pretty
import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.pages.MarkdownToContentConverter
+import org.jetbrains.dokka.pages.DefaultMarkdownToContentConverter
import org.jetbrains.dokka.pages.PlatformData
import org.jetbrains.dokka.plugability.DokkaContext
+import org.jetbrains.dokka.plugability.single
import org.jetbrains.dokka.renderers.FileWriter
import org.jetbrains.dokka.renderers.HtmlRenderer
import org.jetbrains.dokka.resolvers.DefaultLocationProvider
-import org.jetbrains.dokka.transformers.DefaultDocumentationToPageTransformer
+import org.jetbrains.dokka.resolvers.LocationProvider
+import org.jetbrains.dokka.transformers.documentation.DefaultDocumentationToPageTranslator
+import org.jetbrains.dokka.transformers.descriptors.DokkaDescriptorVisitor
+import org.jetbrains.dokka.transformers.documentation.DefaultDocumentationNodeMerger
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
+import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
@@ -22,56 +26,131 @@ class DokkaGenerator(
private val configuration: DokkaConfiguration,
private val logger: DokkaLogger
) {
- fun generate(): Unit {
+
+ fun generate() {
+ logger.debug("Setting up analysis environments")
+ val platforms: Map<PlatformData, EnvironmentAndFacade> = configuration.passesConfigurations.map {
+ PlatformData(it.analysisPlatform, it.targets) to createEnvironmentAndFacade(it)
+ }.toMap()
logger.debug("Initializing plugins")
- val context = DokkaContext.create(configuration.pluginsClasspath, logger)
-
- configuration.passesConfigurations.map { pass ->
- AnalysisEnvironment(DokkaMessageCollector(logger), pass.analysisPlatform).run {
- if (analysisPlatform == Platform.jvm) {
- addClasspath(PathUtil.getJdkClassesRootsFromCurrentJre())
- }
- for (element in pass.classpath) {
- addClasspath(File(element))
- }
-
- addSources(pass.sourceRoots.map { it.path })
-
- loadLanguageVersionSettings(pass.languageVersion, pass.apiVersion)
-
- val environment = createCoreEnvironment()
- val (facade, _) = createResolutionFacade(environment)
-
- environment.getSourceFiles().asSequence()
- .map { it.packageFqName }
- .distinct()
- .mapNotNull { facade.resolveSession.getPackageFragment(it) }
- .map {
- DokkaDescriptorVisitor(
- PlatformData(pass.analysisPlatform, pass.targets),
- facade
- ).visitPackageFragmentDescriptor(
- it,
- DRI.topLevel
- )
- }
- .toList()
- .let { Module(it) }
- .let { DocumentationNodesMerger(it) }
- .also { println("${pass.analysisPlatform}:\n${it.pretty()}\n\n") }
+ val context = DokkaContext.create(configuration.pluginsClasspath, logger, platforms)
+
+ logger.debug("Creating documentation models")
+ val modulesFromPlatforms = platforms.map { (pdata, _) -> translateDescriptors(pdata, context) }
+
+ logger.debug("Merging documentation models")
+ val documentationModel = context.single(CoreExtensions.documentationMerger)
+ .invoke(modulesFromPlatforms, context)
+
+ logger.debug("Transforming documentation model")
+ val transformedDocumentation = context[CoreExtensions.documentationTransformer]
+ .fold(documentationModel) { acc, t -> t(acc, context) }
+
+ logger.debug("Creating pages")
+ val pages = context.single(CoreExtensions.documentationToPageTranslator)
+ .invoke(transformedDocumentation, context)
+
+ logger.debug("Transforming pages")
+ val transformedPages = context[CoreExtensions.pageTransformer]
+ .fold(pages) { acc, t -> t(acc, context) }
+
+ logger.debug("Rendering")
+ val fileWriter = FileWriter(configuration.outputDir, "")
+ val locationProvider = context.single(CoreExtensions.locationProvider)
+ .invoke(transformedPages, configuration, context)
+ val renderer = context.single(CoreExtensions.renderer)
+ .invoke(fileWriter, locationProvider, context)
+
+ renderer.render(transformedPages)
+ }
+
+// fun generate(int: Int) {
+//
+// logger.debug("Initializing plugins")
+// val context = DokkaContext.create(configuration.pluginsClasspath, logger, platforms)
+//
+// configuration.passesConfigurations.map { pass ->
+// AnalysisEnvironment(DokkaMessageCollector(logger), pass.analysisPlatform).run {
+// if (analysisPlatform == Platform.jvm) {
+// addClasspath(PathUtil.getJdkClassesRootsFromCurrentJre())
+// }
+// for (element in pass.classpath) {
+// addClasspath(File(element))
+// }
+//
+// addSources(pass.sourceRoots.map { it.path })
+//
+// loadLanguageVersionSettings(pass.languageVersion, pass.apiVersion)
+//
+// val environment = createCoreEnvironment()
+// val (facade, _) = createResolutionFacade(environment)
+//
+// environment.getSourceFiles().asSequence()
+// .map { it.packageFqName }
+// .distinct()
+// .mapNotNull { facade.resolveSession.getPackageFragment(it) }
+// .map {
+// DokkaDescriptorVisitor(
+// PlatformData(
+// pass.analysisPlatform,
+// pass.targets
+// ), facade
+// )
+// .visitPackageFragmentDescriptor(it, DRI.topLevel)
+// }
+// .toList()
+// .let { Module(it) }
+// .let { DefaultDocumentationNodeMerger(it) }
+// .also { println("${pass.analysisPlatform}:\n${it.pretty()}\n\n") }
+// }
+// }.let {
+// val markdownConverter = DefaultMarkdownToContentConverter(logger)
+// DefaultDocumentationToPageTranslator(
+// markdownConverter,
+// logger
+// ).transform(
+// DefaultDocumentationNodeMerger(
+// it
+// )
+// )
+// }.let {
+// context[CoreExtensions.pageTransformer].fold(it) { pn, t -> t(pn, context) }
+// }.also {
+// HtmlRenderer(
+// FileWriter(configuration.outputDir, ""),
+// DefaultLocationProvider(it, configuration, ".${configuration.format}")
+// ).render(it)
+// }
+// }
+
+ private fun createEnvironmentAndFacade(pass: DokkaConfiguration.PassConfiguration): EnvironmentAndFacade =
+ AnalysisEnvironment(DokkaMessageCollector(logger), pass.analysisPlatform).run {
+ if (analysisPlatform == Platform.jvm) {
+ addClasspath(PathUtil.getJdkClassesRootsFromCurrentJre())
}
- }.let {
- val markdownConverter = MarkdownToContentConverter(logger)
- DefaultDocumentationToPageTransformer(markdownConverter, logger).transform(DocumentationNodesMerger(it))
- }.let {
- context[CoreExtensions.pageTransformer].fold(it) { pn, t -> t.action.invoke(pn, context) }
- }.also {
- HtmlRenderer(
- FileWriter(configuration.outputDir, ""),
- DefaultLocationProvider(it, configuration, ".${configuration.format}")
- ).render(it)
+ pass.classpath.forEach { addClasspath(File(it)) }
+
+ addSources(pass.sourceRoots.map { it.path })
+
+ loadLanguageVersionSettings(pass.languageVersion, pass.apiVersion)
+
+ val environment = createCoreEnvironment()
+ val (facade, _) = createResolutionFacade(environment)
+ EnvironmentAndFacade(environment, facade)
}
+
+ private fun translateDescriptors(platformData: PlatformData, context: DokkaContext): Module {
+ val (environment, facade) = context.platforms.getValue(platformData)
+
+ val packageFragments = environment.getSourceFiles().asSequence()
+ .map { it.packageFqName }
+ .distinct()
+ .mapNotNull { facade.resolveSession.getPackageFragment(it) }
+ .toList()
+
+ return context.single(CoreExtensions.descriptorToDocumentationTranslator)
+ .invoke(packageFragments, platformData, context)
}
private class DokkaMessageCollector(private val logger: DokkaLogger) : MessageCollector {
@@ -90,4 +169,10 @@ class DokkaGenerator(
override fun hasErrors() = seenErrors
}
+}
+
+// It is not data class due to ill-defined equals
+class EnvironmentAndFacade(val environment: KotlinCoreEnvironment, val facade: DokkaResolutionFacade) {
+ operator fun component1() = environment
+ operator fun component2() = facade
} \ No newline at end of file
diff --git a/core/src/main/kotlin/Model/DocumentationNode.kt b/core/src/main/kotlin/Model/DocumentationNode.kt
index 0adb37b5..b1d4be55 100644
--- a/core/src/main/kotlin/Model/DocumentationNode.kt
+++ b/core/src/main/kotlin/Model/DocumentationNode.kt
@@ -1,6 +1,6 @@
package org.jetbrains.dokka.Model
-import org.jetbrains.dokka.KotlinTypeWrapper
+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
diff --git a/core/src/main/kotlin/Model/transformers/DocumentationNodeTransformer.kt b/core/src/main/kotlin/Model/transformers/DocumentationNodeTransformer.kt
deleted file mode 100644
index 318d20b3..00000000
--- a/core/src/main/kotlin/Model/transformers/DocumentationNodeTransformer.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package org.jetbrains.dokka.Model.transformers
-
-import org.jetbrains.dokka.Model.Module
-
-interface DocumentationNodeTransformer {
- operator fun invoke(original: Module): Module
- operator fun invoke(modules: Collection<Module>): Module
-} \ No newline at end of file
diff --git a/core/src/main/kotlin/pages/DefaultMarkdownToContentConverter.kt b/core/src/main/kotlin/pages/DefaultMarkdownToContentConverter.kt
new file mode 100644
index 00000000..72b5ead2
--- /dev/null
+++ b/core/src/main/kotlin/pages/DefaultMarkdownToContentConverter.kt
@@ -0,0 +1,229 @@
+package org.jetbrains.dokka.pages
+
+import org.intellij.markdown.MarkdownElementTypes
+import org.intellij.markdown.MarkdownTokenTypes
+import org.jetbrains.dokka.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(
+ ContentResolvedLink(
+ buildChildren(node),
+ destination,
+ 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/MarkdownToContentConverter.kt b/core/src/main/kotlin/pages/MarkdownToContentConverter.kt
index 8caddeb0..fe4736b7 100644
--- a/core/src/main/kotlin/pages/MarkdownToContentConverter.kt
+++ b/core/src/main/kotlin/pages/MarkdownToContentConverter.kt
@@ -1,14 +1,10 @@
package org.jetbrains.dokka.pages
-import org.intellij.markdown.MarkdownElementTypes
-import org.intellij.markdown.MarkdownTokenTypes
-import org.jetbrains.dokka.DokkaLogger
import org.jetbrains.dokka.MarkdownNode
import org.jetbrains.dokka.links.DRI
+import org.jetbrains.dokka.plugability.DokkaContext
-class MarkdownToContentConverter(
- private val logger: DokkaLogger
-) {
+interface MarkdownToContentConverter {
fun buildContent(
node: MarkdownNode,
dci: DCI,
@@ -16,214 +12,5 @@ class MarkdownToContentConverter(
links: Map<String, DRI> = emptyMap(),
styles: Set<Style> = emptySet(),
extras: Set<Extra> = emptySet()
-
- ): 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(
- ContentResolvedLink(
- buildChildren(node),
- destination,
- DCI(dri, ContentKind.Symbol),
- platforms,
- styles,
- extras
- )
- )
- } ?: let {
- 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(nodeSt