diff options
author | Paweł Marks <pmarks@virtuslab.com> | 2019-11-26 13:44:27 +0100 |
---|---|---|
committer | Paweł Marks <pmarks@virtuslab.com> | 2019-11-26 21:02:20 +0100 |
commit | 49439594f86217d8a25e8df2580b8ef29d836230 (patch) | |
tree | 50dc1b0793c4804b382c6b75fd7a3a0d27cb869a /core/src | |
parent | c185e420971950747535e98f96a12e480159dd83 (diff) | |
download | dokka-49439594f86217d8a25e8df2580b8ef29d836230.tar.gz dokka-49439594f86217d8a25e8df2580b8ef29d836230.tar.bz2 dokka-49439594f86217d8a25e8df2580b8ef29d836230.zip |
Introduction of all important extension points and restructuring of DokkaGenerator
Diffstat (limited to 'core/src')
24 files changed, 580 insertions, 360 deletions
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 == "&" || text == """ || text == "<" || text == ">") { +// return ContentEntity(text) +// } +// if (text == "&") { +// return ContentEntity("&") +// } +// 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(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 == "&" || text == """ || text == "<" || text == ">") { -// return ContentEntity(text) -// } -// if (text == "&") { -// return ContentEntity("&") -// } -// 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 - } - } + ): List<ContentNode> } - -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/transformers/PageNodeTransformer.kt b/core/src/main/kotlin/pages/transformers/PageNodeTransformer.kt deleted file mode 100644 index 0d0f8057..00000000 --- a/core/src/main/kotlin/pages/transformers/PageNodeTransformer.kt +++ /dev/null @@ -1,7 +0,0 @@ -package org.jetbrains.dokka.pages.transformers - -import org.jetbrains.dokka.pages.ModulePageNode - -interface PageNodeTransformer { - operator fun invoke(original: ModulePageNode): ModulePageNode -}
\ No newline at end of file diff --git a/core/src/main/kotlin/plugability/DefaultExtensions.kt b/core/src/main/kotlin/plugability/DefaultExtensions.kt new file mode 100644 index 00000000..dd656386 --- /dev/null +++ b/core/src/main/kotlin/plugability/DefaultExtensions.kt @@ -0,0 +1,25 @@ +package org.jetbrains.dokka.plugability + +import org.jetbrains.dokka.CoreExtensions +import org.jetbrains.dokka.pages.DefaultMarkdownToContentConverter +import org.jetbrains.dokka.renderers.DefaultRenderer +import org.jetbrains.dokka.renderers.HtmlRenderer +import org.jetbrains.dokka.resolvers.DefaultLocationProvider +import org.jetbrains.dokka.transformers.descriptors.DefaultDescriptorToDocumentationTranslator +import org.jetbrains.dokka.transformers.documentation.DefaultDocumentationNodeMerger +import org.jetbrains.dokka.transformers.documentation.DefaultDocumentationToPageTranslator + +object DefaultExtensions : DokkaExtensionHandler { + @Suppress("IMPLICIT_CAST_TO_ANY", "UNCHECKED_CAST") + override fun <T : Any, E : ExtensionPoint<T>> get(point: E, askDefault: AskDefault): List<T> = + when (point) { + CoreExtensions.descriptorToDocumentationTranslator -> DefaultDescriptorToDocumentationTranslator + CoreExtensions.documentationMerger -> DefaultDocumentationNodeMerger + CoreExtensions.markdownToContentConverterFactory -> ::DefaultMarkdownToContentConverter + CoreExtensions.documentationToPageTranslator -> DefaultDocumentationToPageTranslator + CoreExtensions.renderer -> ::HtmlRenderer + CoreExtensions.locationProvider -> ::DefaultLocationProvider + CoreExtensions.fileExtension -> ".html" + else -> null + }.let { listOfNotNull(it) as List<T> } +}
\ No newline at end of file diff --git a/core/src/main/kotlin/plugability/DokkaContext.kt b/core/src/main/kotlin/plugability/DokkaContext.kt index b917ff99..31c56728 100644 --- a/core/src/main/kotlin/plugability/DokkaContext.kt +++ b/core/src/main/kotlin/plugability/DokkaContext.kt @@ -1,23 +1,35 @@ package org.jetbrains.dokka.plugability import org.jetbrains.dokka.DokkaLogger +import org.jetbrains.dokka.EnvironmentAndFacade +import org.jetbrains.dokka.pages.PlatformData import java.io.File import java.net.URLClassLoader import java.util.* import kotlin.reflect.KClass import kotlin.reflect.full.createInstance -interface DokkaContext { - operator fun <T, E> get(point: E, askDefault: AskDefault = AskDefault.WhenEmpty): List<Extension<T>> + +interface DokkaExtensionHandler { + operator fun <T, E> get(point: E, askDefault: AskDefault = AskDefault.WhenEmpty): List<T> where T : Any, E : ExtensionPoint<T> +} + +interface DokkaContext : DokkaExtensionHandler { fun <T : DokkaPlugin> plugin(kclass: KClass<T>): T? val logger: DokkaLogger + val platforms: Map<PlatformData, EnvironmentAndFacade> + companion object { - fun create(pluginsClasspath: Iterable<File>, logger: DokkaLogger): DokkaContext = - DokkaContextConfigurationImpl(logger, DefaultContext(logger)).apply { + fun create( + pluginsClasspath: Iterable<File>, + logger: DokkaLogger, + platforms: Map<PlatformData, EnvironmentAndFacade> + ): DokkaContext = + DokkaContextConfigurationImpl(logger, DefaultExtensions, platforms).apply { pluginsClasspath.map { it.relativeTo(File(".").absoluteFile).toURI().toURL() } .toTypedArray() .let { URLClassLoader(it, this.javaClass.classLoader) } @@ -28,13 +40,27 @@ interface DokkaContext { } } +fun <T, E> DokkaContext.single(point: E): T where T : Any, E : ExtensionPoint<T> { + fun throwBadArity(substitution: String): Nothing = throw IllegalStateException( + "$point was expected to have exactly one extension registered, but $substitution found." + ) + + val extensions = get(point, AskDefault.WhenEmpty) + return when (extensions.size) { + 0 -> throwBadArity("none was") + 1 -> extensions.first() + else -> throwBadArity("multiple were") + } +} + interface DokkaContextConfiguration { fun addExtension(extension: Extension<*>) } private class DokkaContextConfigurationImpl( override val logger: DokkaLogger, - private val defaultContext: DokkaContext? + private val defaultHandler: DokkaExtensionHandler?, + override val platforms: Map<PlatformData, EnvironmentAndFacade> ) : DokkaContext, DokkaContextConfiguration { private val plugins = mutableMapOf<KClass<*>, DokkaPlugin>() @@ -45,15 +71,16 @@ private class DokkaContextConfigurationImpl( @Suppress("UNCHECKED_CAST") override operator fun <T, E> get(point: E, askDefault: AskDefault) where T : Any, E : ExtensionPoint<T> = when (askDefault) { - AskDefault.Never -> extensions[point].orEmpty() - AskDefault.Always -> extensions[point].orEmpty() + defaultContext?.get(point, askDefault).orEmpty() + AskDefault.Never -> actions(point).orEmpty() + AskDefault.Always -> actions(point).orEmpty() + defaultHandler?.get(point, askDefault).orEmpty() AskDefault.WhenEmpty -> - extensions[point]?.takeIf { it.isNotEmpty() } ?: defaultContext?.get(point, askDefault).orEmpty() - } as List<Extension<T>> + actions(point)?.takeIf { it.isNotEmpty() } ?: defaultHandler?.get(point, askDefault).orEmpty() + } as List<T> + + private fun <E : ExtensionPoint<*>> actions(point: E) = extensions[point]?.map { it.action } @Suppress("UNCHECKED_CAST") - override fun <T : DokkaPlugin> plugin(kclass: KClass<T>) = - (plugins[kclass] ?: defaultContext?.plugin(kclass) ?: pluginStubFor(kclass)) as T + override fun <T : DokkaPlugin> plugin(kclass: KClass<T>) = (plugins[kclass] ?: pluginStubFor(kclass)) as T private fun <T : DokkaPlugin> pluginStubFor(kclass: KClass<T>): DokkaPlugin = pluginStubs.getOrPut(kclass) { kclass.createInstance().also { it.context = this } } @@ -69,7 +96,7 @@ private class DokkaContextConfigurationImpl( } fun logInitialisationInfo() { - val pluginNames: List<String> = plugins.values.map { it::class.qualifiedName.toString() } + val pluginNames = plugins.values.map { it::class.qualifiedName.toString() } val loadedListForDebug = extensions.run { keys + values.flatten() }.toList() .joinToString(prefix = "[\n", separator = ",\n", postfix = "\n]") { "\t$it" } @@ -89,16 +116,6 @@ private fun checkClasspath(classLoader: URLClassLoader) { } } -class DefaultContext(override val logger: DokkaLogger) : DokkaContext { - override fun <T : Any, E : ExtensionPoint<T>> get(point: E, askDefault: AskDefault): List<Extension<T>> = - when (point) { - - else -> emptyList() - } - - override fun <T : DokkaPlugin> plugin(kclass: KClass<T>): Nothing? = null -} - enum class AskDefault { Always, Never, WhenEmpty }
\ No newline at end of file diff --git a/core/src/main/kotlin/plugability/extensions.kt b/core/src/main/kotlin/plugability/extensions.kt index c1573e1a..3039cb5a 100644 --- a/core/src/main/kotlin/plugability/extensions.kt +++ b/core/src/main/kotlin/plugability/extensions.kt @@ -11,7 +11,7 @@ class Extension<T : Any> internal constructor( internal val extensionPoint: ExtensionPoint<T>, internal val pluginClass: String, internal val extensionName: String, - internal val action: T, + val action: T, internal val ordering: (OrderDsl.() -> Unit)? = null ) { override fun toString() = "Extension: $pluginClass/$extensionName" diff --git a/core/src/main/kotlin/renderers/DefaultRenderer.kt b/core/src/main/kotlin/renderers/DefaultRenderer.kt index 3b16c093..3f851849 100644 --- a/core/src/main/kotlin/renderers/DefaultRenderer.kt +++ b/core/src/main/kotlin/renderers/DefaultRenderer.kt @@ -1,9 +1,14 @@ package org.jetbrains.dokka.renderers import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.resolvers.LocationProvider -abstract class DefaultRenderer(val fileWriter: FileWriter, val locationProvider: LocationProvider) : Renderer { +abstract class DefaultRenderer( + protected val fileWriter: FileWriter, + protected val locationProvider: LocationProvider, + protected val context: DokkaContext +) : Renderer { protected abstract fun buildHeader(level: Int, text: String): String protected abstract fun buildLink(text: String, address: String): String diff --git a/core/src/main/kotlin/renderers/HtmlRenderer.kt b/core/src/main/kotlin/renderers/HtmlRenderer.kt index 3b778671..46548699 100644 --- a/core/src/main/kotlin/renderers/HtmlRenderer.kt +++ b/core/src/main/kotlin/renderers/HtmlRenderer.kt @@ -2,13 +2,18 @@ package org.jetbrains.dokka.renderers import org.jetbrains.dokka.htmlEscape import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.resolvers.LocationProvider import java.io.File import java.net.URL import java.nio.file.Path import java.nio.file.Paths -open class HtmlRenderer(fileWriter: FileWriter, locationProvider: LocationProvider) : DefaultRenderer(fileWriter, locationProvider) { +open class HtmlRenderer( + fileWriter: FileWriter, + locationProvider: LocationProvider, + context: DokkaContext +) : DefaultRenderer(fileWriter, locationProvider, context) { override fun buildList(node: ContentList, pageContext: PageNode): String = if (node.ordered) { "<ol>${buildListItems(node.children, pageContext)}</ol>" diff --git a/core/src/main/kotlin/renderers/Renderer.kt b/core/src/main/kotlin/renderers/Renderer.kt index 24e01cdb..91483a46 100644 --- a/core/src/main/kotlin/renderers/Renderer.kt +++ b/core/src/main/kotlin/renderers/Renderer.kt @@ -1,6 +1,7 @@ package org.jetbrains.dokka.renderers import org.jetbrains.dokka.pages.PageNode +import org.jetbrains.dokka.plugability.DokkaContext interface Renderer { fun render(root: PageNode) diff --git a/core/src/main/kotlin/resolvers/DefaultLocationProvider.kt b/core/src/main/kotlin/resolvers/DefaultLocationProvider.kt index 208410fe..ec5aa29a 100644 --- a/core/src/main/kotlin/resolvers/DefaultLocationProvider.kt +++ b/core/src/main/kotlin/resolvers/DefaultLocationProvider.kt @@ -1,11 +1,20 @@ package org.jetbrains.dokka.resolvers +import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.htmlEscape import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.single + +open class DefaultLocationProvider( + private val pageGraphRoot: PageNode, + private val configuration: DokkaConfiguration, + context: DokkaContext +): LocationProvider { // TODO: cache + private val extension = context.single(CoreExtensions.fileExtension) -open class DefaultLocationProvider(private val pageGraphRoot: PageNode, val configuration: DokkaConfiguration, val extension: String): LocationProvider { // TODO: cache override fun resolve(node: PageNode, context: PageNode?): String = pathTo(node, context) + extension override fun resolve(dri: DRI, platforms: List<PlatformData>, context: PageNode?): String = diff --git a/core/src/main/kotlin/transformers/DefaultDocumentationToPageTransformer.kt b/core/src/main/kotlin/transformers/DefaultDocumentationToPageTransformer.kt deleted file mode 100644 index b0877527..00000000 --- a/core/src/main/kotlin/transformers/DefaultDocumentationToPageTransformer.kt +++ /dev/null @@ -1,20 +0,0 @@ -package org.jetbrains.dokka.transformers - -import org.jetbrains.dokka.DokkaLogger -import org.jetbrains.dokka.Model.Module -import org.jetbrains.dokka.pages.DefaultPageBuilder -import org.jetbrains.dokka.pages.DefaultPageContentBuilder -import org.jetbrains.dokka.pages.MarkdownToContentConverter -import org.jetbrains.dokka.pages.ModulePageNode - - -class DefaultDocumentationToPageTransformer( - private val markdownConverter: MarkdownToContentConverter, - private val logger: DokkaLogger -) : DocumentationToPageTransformer { - override fun transform(module: Module): ModulePageNode = - DefaultPageBuilder { node, kind, operation -> - DefaultPageContentBuilder.group(node.dri, node.platformData, kind, markdownConverter, logger, operation) - }.pageForModule(module) - -}
\ No newline at end of file diff --git a/core/src/main/kotlin/transformers/PageNodeTransformer.kt b/core/src/main/kotlin/transformers/PageNodeTransformer.kt deleted file mode 100644 index b86e0b34..00000000 --- a/core/src/main/kotlin/transformers/PageNodeTransformer.kt +++ /dev/null @@ -1,8 +0,0 @@ -package org.jetbrains.dokka.transformers - -import org.jetbrains.dokka.pages.ModulePageNode -import org.jetbrains.dokka.plugability.DokkaContext - -interface PageNodeTransformer { - fun invoke(input: ModulePageNode, dokkaContext: DokkaContext): ModulePageNode -}
\ No newline at end of file diff --git a/core/src/main/kotlin/DokkaDescriptorVisitor.kt b/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt index 6c82f2c3..19aeef92 100644 --- a/core/src/main/kotlin/DokkaDescriptorVisitor.kt +++ b/core/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt @@ -1,5 +1,6 @@ -package org.jetbrains.dokka +package org.jetbrains.dokka.transformers.descriptors +import org.jetbrains.dokka.DokkaResolutionFacade import org.jetbrains.dokka.Model.* import org.jetbrains.dokka.Model.ClassKind import org.jetbrains.dokka.Model.Function @@ -7,6 +8,7 @@ import org.jetbrains.dokka.links.Callable import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.withClass import org.jetbrains.dokka.pages.PlatformData +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 @@ -20,6 +22,17 @@ import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter import org.jetbrains.kotlin.resolve.scopes.MemberScope import org.jetbrains.kotlin.types.KotlinType +object DefaultDescriptorToDocumentationTranslator: DescriptorToDocumentationTranslator { + override fun invoke( + packageFragments: Iterable<PackageFragmentDescriptor>, + platformData: PlatformData, + context: DokkaContext + ) = DokkaDescriptorVisitor(platformData, context.platforms[platformData]?.facade!!).run { + packageFragments.map { visitPackageFragmentDescriptor(it, DRI.topLevel) } + }.let { Module(it) } + +} + class DokkaDescriptorVisitor( private val platformData: PlatformData, private val resolutionFacade: DokkaResolutionFacade @@ -186,6 +199,10 @@ class KotlinTypeWrapper(private val kotlinType: KotlinType) : TypeWrapper { override val constructorFqName = fqNameSafe?.asString() override val constructorNamePathSegments: List<String> = fqNameSafe?.pathSegments()?.map { it.asString() } ?: emptyList() - override val arguments: List<KotlinTypeWrapper> by lazy { kotlinType.arguments.map { KotlinTypeWrapper(it.type) } } + override val arguments: List<KotlinTypeWrapper> by lazy { kotlinType.arguments.map { + KotlinTypeWrapper( + it.type + ) + } } override val dri: DRI? by lazy { declarationDescriptor?.let { DRI.from(it) } } }
\ No newline at end of file diff --git a/core/src/main/kotlin/transformers/descriptors/DescriptorToDocumentationTranslator.kt b/core/src/main/kotlin/transformers/descriptors/DescriptorToDocumentationTranslator.kt new file mode 100644 index 00000000..d08aba21 --- /dev/null +++ b/core/src/main/kotlin/transformers/descriptors/DescriptorToDocumentationTranslator.kt @@ -0,0 +1,15 @@ +package org.jetbrains.dokka.transformers.descriptors + +import org.jetbrains.dokka.Model.Module +import org.jetbrains.dokka.Model.Package +import org.jetbrains.dokka.pages.PlatformData +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor + +interface DescriptorToDocumentationTranslator { + fun invoke( + packageFragments: Iterable<PackageFragmentDescriptor>, + platformData: PlatformData, + context: DokkaContext + ): Module +}
\ No newline at end of file diff --git a/core/src/main/kotlin/Model/transformers/DocumentationNodesMerger.kt b/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt index ae4f8d99..46ba2816 100644 --- a/core/src/main/kotlin/Model/transformers/DocumentationNodesMerger.kt +++ b/core/src/main/kotlin/transformers/documentation/DefaultDocumentationNodeMerger.kt @@ -1,23 +1,19 @@ -package org.jetbrains.dokka.Model.transformers +package org.jetbrains.dokka.transformers.documentation import org.jetbrains.dokka.Model.* import org.jetbrains.dokka.Model.Function +import org.jetbrains.dokka.plugability.DokkaContext -internal object DocumentationNodesMerger : DocumentationNodeTransformer { - override fun invoke(original: Module) = Module( - original.packages.map { mergePackageContent(it) } - ) - override fun invoke(modules: Collection<Module>): Module = - Module(merge(modules.flatMap { it.packages }, Package::mergeWith)) +internal object DefaultDocumentationNodeMerger : DocumentationNodeMerger { + override fun invoke(modules: Collection<Module>, context: DokkaContext): Module = + Module( + merge( + modules.flatMap { it.packages }, + Package::mergeWith + ) + ) } -private fun mergePackageContent(original: Package) = Package( - original.dri, - merge(original.functions, Function::mergeWith), - merge(original.properties, Property::mergeWith), - merge(original.classes, Class::mergeWith) -) - private fun <T: DocumentationNode> merge(elements: List<T>, reducer: (T, T) -> T): List<T> = elements.groupingBy { it.dri } .reduce { _, left, right -> reducer(left, right)} diff --git a/core/src/main/kotlin/transformers/documentation/DefaultDocumentationToPageTranslator.kt b/core/src/main/kotlin/transformers/documentation/DefaultDocumentationToPageTranslator.kt new file mode 100644 index 00000000..236d0864 --- /dev/null +++ b/core/src/main/kotlin/transformers/documentation/DefaultDocumentationToPageTranslator.kt @@ -0,0 +1,24 @@ +package org.jetbrains.dokka.transformers.documentation + +import org.jetbrains.dokka.CoreExtensions +import org.jetbrains.dokka.Model.Module +import org.jetbrains.dokka.pages.DefaultPageBuilder +import org.jetbrains.dokka.pages.DefaultPageContentBuilder +import org.jetbrains.dokka.pages.ModulePageNode +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.single + + +object DefaultDocumentationToPageTranslator : DocumentationToPageTranslator { + override fun invoke(module: Module, context: DokkaContext): ModulePageNode = + DefaultPageBuilder { node, kind, operation -> + DefaultPageContentBuilder.group( + node.dri, + node.platformData, + kind, + context.single(CoreExtensions.markdownToContentConverterFactory).invoke(context), + context.logger, + operation + ) + }.pageForModule(module) +}
\ No newline at end of file diff --git a/core/src/main/kotlin/transformers/documentation/DocumentationNodeMerger.kt b/core/src/main/kotlin/transformers/documentation/DocumentationNodeMerger.kt new file mode 100644 index 00000000..0423f47c --- /dev/null +++ b/core/src/main/kotlin/transformers/documentation/DocumentationNodeMerger.kt @@ -0,0 +1,8 @@ +package org.jetbrains.dokka.transformers.documentation + +import org.jetbrains.dokka.Model.Module +import org.jetbrains.dokka.plugability.DokkaContext + +interface DocumentationNodeMerger { + operator fun invoke(modules: Collection<Module>, context: DokkaContext): Module +}
\ No newline at end of file diff --git a/core/src/main/kotlin/transformers/documentation/DocumentationNodeTransformer.kt b/core/src/main/kotlin/transformers/documentation/DocumentationNodeTransformer.kt new file mode 100644 index 00000000..8ac4a7c2 --- /dev/null +++ b/core/src/main/kotlin/transformers/documentation/DocumentationNodeTransformer.kt @@ -0,0 +1,8 @@ +package org.jetbrains.dokka.transformers.documentation + +import org.jetbrains.dokka.Model.Module +import org.jetbrains.dokka.plugability.DokkaContext + +interface DocumentationNodeTransformer { + operator fun invoke(original: Module, context: DokkaContext): Module +}
\ No newline at end of file diff --git a/core/src/main/kotlin/transformers/DocumentationToPageTransformer.kt b/core/src/main/kotlin/transformers/documentation/DocumentationToPageTranslator.kt index 19703025..ffe34226 100644 --- a/core/src/main/kotlin/transformers/DocumentationToPageTransformer.kt +++ b/core/src/main/kotlin/transformers/documentation/DocumentationToPageTranslator.kt @@ -1,11 +1,12 @@ -package org.jetbrains.dokka.transformers +package org.jetbrains.dokka.transformers.documentation import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.Model.DocumentationNode import org.jetbrains.dokka.Model.Module import org.jetbrains.dokka.pages.ModulePageNode import org.jetbrains.dokka.pages.PageNode +import org.jetbrains.dokka.plugability.DokkaContext -interface DocumentationToPageTransformer { - fun transform(module: Module): ModulePageNode // TODO refactor this... some more? +interface DocumentationToPageTranslator { + operator fun invoke(module: Module, context: DokkaContext): ModulePageNode }
\ No newline at end of file diff --git a/core/src/main/kotlin/transformers/pages/PageNodeTransformer.kt b/core/src/main/kotlin/transformers/pages/PageNodeTransformer.kt new file mode 100644 index 00000000..286835f9 --- /dev/null +++ b/core/src/main/kotlin/transformers/pages/PageNodeTransformer.kt @@ -0,0 +1,8 @@ +package org.jetbrains.dokka.transformers.pages + +import org.jetbrains.dokka.pages.ModulePageNode +import org.jetbrains.dokka.plugability.DokkaContext + +interface PageNodeTransformer { + operator fun invoke(input: ModulePageNode, dokkaContext: DokkaContext): ModulePageNode +}
\ No newline at end of file |