From c203be9fb65ee221875b4e1c865bcd289a85e69c Mon Sep 17 00:00:00 2001 From: Błażej Kardyś Date: Fri, 13 Nov 2020 22:05:15 +0100 Subject: Adding multimodule all modules page creation for gfm --- .../test/kotlin/transformers/DivisionSwitchTest.kt | 4 +- .../kotlin/translators/JavadocInheritDocsTest.kt | 4 +- .../translators/JavadocInheritedDocTagsTest.kt | 4 +- plugins/gfm/gfm-all-module-page/build.gradle.kts | 11 + .../gfm/allModulesPage/GfmAllModulesPagaPlugin.kt | 20 ++ .../GfmMultimoduleLocationProvider.kt | 41 +++ .../org.jetbrains.dokka.plugability.DokkaPlugin | 1 + plugins/gfm/src/main/kotlin/GfmPlugin.kt | 370 --------------------- .../kotlin/org/jetbrains/dokka/gfm/GfmPlugin.kt | 36 ++ .../dokka/gfm/location/MarkdownLocationProvider.kt | 16 + .../dokka/gfm/renderer/CommonmarkRenderer.kt | 322 ++++++++++++++++++ .../src/test/kotlin/renderers/gfm/DivergentTest.kt | 2 +- .../renderers/gfm/GfmRenderingOnlyTestBase.kt | 2 +- .../test/kotlin/renderers/gfm/GroupWrappingTest.kt | 2 +- .../kotlin/renderers/gfm/SimpleElementsTest.kt | 2 +- .../renderers/gfm/SourceSetDependentHintTest.kt | 2 +- plugins/jekyll/src/main/kotlin/JekyllPlugin.kt | 3 +- 17 files changed, 459 insertions(+), 383 deletions(-) create mode 100644 plugins/gfm/gfm-all-module-page/build.gradle.kts create mode 100644 plugins/gfm/gfm-all-module-page/src/main/kotlin/org/jetbrains/dokka/gfm/allModulesPage/GfmAllModulesPagaPlugin.kt create mode 100644 plugins/gfm/gfm-all-module-page/src/main/kotlin/org/jetbrains/dokka/gfm/allModulesPage/GfmMultimoduleLocationProvider.kt create mode 100644 plugins/gfm/gfm-all-module-page/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin delete mode 100644 plugins/gfm/src/main/kotlin/GfmPlugin.kt create mode 100644 plugins/gfm/src/main/kotlin/org/jetbrains/dokka/gfm/GfmPlugin.kt create mode 100644 plugins/gfm/src/main/kotlin/org/jetbrains/dokka/gfm/location/MarkdownLocationProvider.kt create mode 100644 plugins/gfm/src/main/kotlin/org/jetbrains/dokka/gfm/renderer/CommonmarkRenderer.kt (limited to 'plugins') diff --git a/plugins/base/src/test/kotlin/transformers/DivisionSwitchTest.kt b/plugins/base/src/test/kotlin/transformers/DivisionSwitchTest.kt index 58413074..1a2e9fa3 100644 --- a/plugins/base/src/test/kotlin/transformers/DivisionSwitchTest.kt +++ b/plugins/base/src/test/kotlin/transformers/DivisionSwitchTest.kt @@ -8,13 +8,13 @@ import org.jetbrains.dokka.pages.ClasslikePageNode import org.jetbrains.dokka.pages.ContentHeader import org.jetbrains.dokka.pages.ContentNode import org.jetbrains.dokka.pages.ContentText -import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.kotlin.utils.addIfNotNull import org.junit.jupiter.api.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull -class DivisionSwitchTest : AbstractCoreTest() { +class DivisionSwitchTest : BaseAbstractTest() { private val query = """ |/src/source0.kt diff --git a/plugins/base/src/test/kotlin/translators/JavadocInheritDocsTest.kt b/plugins/base/src/test/kotlin/translators/JavadocInheritDocsTest.kt index 8fac13c9..4e2cf70f 100644 --- a/plugins/base/src/test/kotlin/translators/JavadocInheritDocsTest.kt +++ b/plugins/base/src/test/kotlin/translators/JavadocInheritDocsTest.kt @@ -4,13 +4,13 @@ import org.jetbrains.dokka.model.doc.CustomDocTag import org.jetbrains.dokka.model.doc.Description import org.jetbrains.dokka.model.doc.P import org.jetbrains.dokka.model.doc.Text -import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.junit.Ignore import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test -class JavadocInheritDocsTest : AbstractCoreTest() { +class JavadocInheritDocsTest : BaseAbstractTest() { val configuration = dokkaConfiguration { sourceSets { sourceSet { diff --git a/plugins/base/src/test/kotlin/translators/JavadocInheritedDocTagsTest.kt b/plugins/base/src/test/kotlin/translators/JavadocInheritedDocTagsTest.kt index a7d4f057..c29c4e96 100644 --- a/plugins/base/src/test/kotlin/translators/JavadocInheritedDocTagsTest.kt +++ b/plugins/base/src/test/kotlin/translators/JavadocInheritedDocTagsTest.kt @@ -4,14 +4,14 @@ import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.PointingToDeclaration import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.model.doc.* -import org.jetbrains.dokka.testApi.testRunner.AbstractCoreTest +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.jetbrains.dokka.model.doc.Deprecated as DokkaDeprecatedTag import org.jetbrains.dokka.model.doc.Throws as DokkaThrowsTag -class JavadocInheritedDocTagsTest : AbstractCoreTest() { +class JavadocInheritedDocTagsTest : BaseAbstractTest() { private val configuration = dokkaConfiguration { sourceSets { sourceSet { diff --git a/plugins/gfm/gfm-all-module-page/build.gradle.kts b/plugins/gfm/gfm-all-module-page/build.gradle.kts new file mode 100644 index 00000000..66deb291 --- /dev/null +++ b/plugins/gfm/gfm-all-module-page/build.gradle.kts @@ -0,0 +1,11 @@ +import org.jetbrains.registerDokkaArtifactPublication + +dependencies { + implementation(project(":plugins:base")) + implementation(project(":plugins:gfm")) + implementation(project(":plugins:all-module-page")) +} + +registerDokkaArtifactPublication("dokkaGfmAllModulePage") { + artifactId = "gfm-all-module-page-plugin" +} \ No newline at end of file diff --git a/plugins/gfm/gfm-all-module-page/src/main/kotlin/org/jetbrains/dokka/gfm/allModulesPage/GfmAllModulesPagaPlugin.kt b/plugins/gfm/gfm-all-module-page/src/main/kotlin/org/jetbrains/dokka/gfm/allModulesPage/GfmAllModulesPagaPlugin.kt new file mode 100644 index 00000000..8052a762 --- /dev/null +++ b/plugins/gfm/gfm-all-module-page/src/main/kotlin/org/jetbrains/dokka/gfm/allModulesPage/GfmAllModulesPagaPlugin.kt @@ -0,0 +1,20 @@ +package org.jetbrains.dokka.gfm.allModulesPage + +import org.jetbrains.dokka.allModulesPage.AllModulesPagePlugin +import org.jetbrains.dokka.base.DokkaBase +import org.jetbrains.dokka.gfm.GfmPlugin +import org.jetbrains.dokka.plugability.DokkaPlugin + +class GfmAllModulesPagePlugin : DokkaPlugin() { + + private val gfmPlugin by lazy { plugin() } + + private val dokkaBase by lazy { plugin() } + + private val allModulesPagePlugin by lazy { plugin() } + + val locationProvider by extending { + (dokkaBase.locationProviderFactory providing GfmMultimoduleLocationProvider::Factory + override listOf(allModulesPagePlugin.multimoduleLocationProvider, gfmPlugin.locationProvider)) + } +} \ No newline at end of file diff --git a/plugins/gfm/gfm-all-module-page/src/main/kotlin/org/jetbrains/dokka/gfm/allModulesPage/GfmMultimoduleLocationProvider.kt b/plugins/gfm/gfm-all-module-page/src/main/kotlin/org/jetbrains/dokka/gfm/allModulesPage/GfmMultimoduleLocationProvider.kt new file mode 100644 index 00000000..d49be426 --- /dev/null +++ b/plugins/gfm/gfm-all-module-page/src/main/kotlin/org/jetbrains/dokka/gfm/allModulesPage/GfmMultimoduleLocationProvider.kt @@ -0,0 +1,41 @@ +package org.jetbrains.dokka.gfm.allModulesPage + +import org.jetbrains.dokka.base.resolvers.local.DokkaBaseLocationProvider +import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProvider +import org.jetbrains.dokka.base.resolvers.local.LocationProviderFactory +import org.jetbrains.dokka.gfm.location.MarkdownLocationProvider +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.DisplaySourceSet +import org.jetbrains.dokka.pages.PageNode +import org.jetbrains.dokka.pages.RootPageNode +import org.jetbrains.dokka.plugability.DokkaContext + +class GfmMultimoduleLocationProvider(private val root: RootPageNode, context: DokkaContext) : DokkaBaseLocationProvider(root, context, ".md") { + + private val defaultLocationProvider = MarkdownLocationProvider(root, context) + + val paths = context.configuration.modules.map { + it.name to it.relativePathToOutputDirectory + }.toMap() + + override fun resolve(dri: DRI, sourceSets: Set, context: PageNode?) = + dri.takeIf { it.packageName == MULTIMODULE_PACKAGE_PLACEHOLDER }?.classNames?.let { paths[it] }?.let { + "$it/${DokkaLocationProvider.identifierToFilename(dri.classNames.orEmpty())}/index.md" + } ?: defaultLocationProvider.resolve(dri, sourceSets, context) + + override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean) = + defaultLocationProvider.resolve(node, context, skipExtension) + + override fun pathToRoot(from: PageNode): String = defaultLocationProvider.pathToRoot(from) + + override fun ancestors(node: PageNode): List = listOf(root) + + companion object { + const val MULTIMODULE_PACKAGE_PLACEHOLDER = ".ext" + } + + class Factory(private val context: DokkaContext): LocationProviderFactory { + override fun getLocationProvider(pageNode: RootPageNode) = + GfmMultimoduleLocationProvider(pageNode, context) + } +} \ No newline at end of file diff --git a/plugins/gfm/gfm-all-module-page/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/plugins/gfm/gfm-all-module-page/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin new file mode 100644 index 00000000..1a8acd51 --- /dev/null +++ b/plugins/gfm/gfm-all-module-page/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin @@ -0,0 +1 @@ +org.jetbrains.dokka.gfm.allModulesPage.GfmAllModulesPagePlugin \ No newline at end of file diff --git a/plugins/gfm/src/main/kotlin/GfmPlugin.kt b/plugins/gfm/src/main/kotlin/GfmPlugin.kt deleted file mode 100644 index 780e4cb2..00000000 --- a/plugins/gfm/src/main/kotlin/GfmPlugin.kt +++ /dev/null @@ -1,370 +0,0 @@ -package org.jetbrains.dokka.gfm - -import org.jetbrains.dokka.CoreExtensions -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.DokkaException -import org.jetbrains.dokka.base.DokkaBase -import org.jetbrains.dokka.base.renderers.DefaultRenderer -import org.jetbrains.dokka.base.renderers.PackageListCreator -import org.jetbrains.dokka.base.renderers.RootCreator -import org.jetbrains.dokka.base.renderers.isImage -import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProvider -import org.jetbrains.dokka.base.resolvers.local.LocationProviderFactory -import org.jetbrains.dokka.model.DisplaySourceSet -import org.jetbrains.dokka.base.resolvers.shared.RecognizedLinkFormat -import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.DokkaPlugin -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.query -import org.jetbrains.dokka.transformers.pages.PageTransformer - -class GfmPlugin : DokkaPlugin() { - - val gfmPreprocessors by extensionPoint() - - private val dokkaBase by lazy { plugin() } - - val renderer by extending { - (CoreExtensions.renderer - providing { CommonmarkRenderer(it) } - override dokkaBase.htmlRenderer) - } - - val locationProvider by extending { - (dokkaBase.locationProviderFactory - providing { MarkdownLocationProviderFactory(it) } - override dokkaBase.locationProvider) - } - - val rootCreator by extending { - gfmPreprocessors with RootCreator - } - - val packageListCreator by extending { - (gfmPreprocessors - providing { PackageListCreator(it, RecognizedLinkFormat.DokkaGFM) } - order { after(rootCreator) }) - } -} - -open class CommonmarkRenderer( - context: DokkaContext -) : DefaultRenderer(context) { - - override val preprocessors = context.plugin().query { gfmPreprocessors } - - override fun StringBuilder.wrapGroup( - node: ContentGroup, - pageContext: ContentPage, - childrenCallback: StringBuilder.() -> Unit - ) { - return when { - node.hasStyle(TextStyle.Block) -> { - childrenCallback() - buildNewLine() - } - node.hasStyle(TextStyle.Paragraph) -> { - buildParagraph() - childrenCallback() - buildParagraph() - } - else -> childrenCallback() - } - } - - override fun StringBuilder.buildHeader(level: Int, node: ContentHeader, content: StringBuilder.() -> Unit) { - buildParagraph() - append("#".repeat(level) + " ") - content() - buildNewLine() - } - - override fun StringBuilder.buildLink(address: String, content: StringBuilder.() -> Unit) { - append("[") - content() - append("]($address)") - } - - override fun StringBuilder.buildList( - node: ContentList, - pageContext: ContentPage, - sourceSetRestriction: Set? - ) { - buildListLevel(node, pageContext) - } - - private fun StringBuilder.buildListItem(items: List, pageContext: ContentPage) { - items.forEach { - if (it is ContentList) { - buildList(it, pageContext) - } else { - append("
  • ") - append(buildString { it.build(this, pageContext, it.sourceSets) }.trim()) - append("
  • ") - } - } - } - - private fun StringBuilder.buildListLevel(node: ContentList, pageContext: ContentPage) { - if (node.ordered) { - append("
      ") - buildListItem(node.children, pageContext) - append("
    ") - } else { - append("
      ") - buildListItem(node.children, pageContext) - append("
    ") - } - } - - override fun StringBuilder.buildNewLine() { - append(" \n") - } - - private fun StringBuilder.buildParagraph() { - append("\n\n") - } - - override fun StringBuilder.buildPlatformDependent( - content: PlatformHintedContent, - pageContext: ContentPage, - sourceSetRestriction: Set? - ) { - buildPlatformDependentItem(content.inner, content.sourceSets, pageContext) - } - - private fun StringBuilder.buildPlatformDependentItem( - content: ContentNode, - sourceSets: Set, - pageContext: ContentPage, - ) { - if (content is ContentGroup && content.children.firstOrNull { it is ContentTable } != null) { - buildContentNode(content, pageContext, sourceSets) - } else { - val distinct = sourceSets.map { - it to buildString { buildContentNode(content, pageContext, setOf(it)) } - }.groupBy(Pair::second, Pair::first) - - distinct.filter { it.key.isNotBlank() }.forEach { (text, platforms) -> - append(" ") - buildSourceSetTags(platforms.toSet()) - append(" $text ") - buildNewLine() - } - } - } - - override fun StringBuilder.buildResource(node: ContentEmbeddedResource, pageContext: ContentPage) { - if(node.isImage()){ - append("!") - } - append("[${node.altText}](${node.address})") - } - - override fun StringBuilder.buildTable( - node: ContentTable, - pageContext: ContentPage, - sourceSetRestriction: Set? - ) { - buildNewLine() - if (node.dci.kind == ContentKind.Sample || node.dci.kind == ContentKind.Parameters) { - node.sourceSets.forEach { sourcesetData -> - append(sourcesetData.name) - buildNewLine() - buildTable( - node.copy( - children = node.children.filter { it.sourceSets.contains(sourcesetData) }, - dci = node.dci.copy(kind = ContentKind.Main) - ), pageContext, sourceSetRestriction - ) - buildNewLine() - } - } else { - val size = node.header.size - - if (node.header.isNotEmpty()) { - append("| ") - node.header.forEach { - it.children.forEach { - append(" ") - it.build(this, pageContext, it.sourceSets) - } - append("| ") - } - append("\n") - } else { - append("| ".repeat(size)) - if (size > 0) append("|\n") - } - - append("|---".repeat(size)) - if (size > 0) append("|\n") - - node.children.forEach { - val builder = StringBuilder() - it.children.forEach { - builder.append("| ") - builder.append("") - builder.append( - buildString { it.build(this, pageContext) }.replace( - Regex("#+ "), - "" - ) - ) // Workaround for headers inside tables - } - append(builder.toString().withEntersAsHtml()) - append(" | ".repeat(size - it.children.size)) - append("\n") - } - } - } - - override fun StringBuilder.buildText(textNode: ContentText) { - if (textNode.text.isNotBlank()) { - val decorators = decorators(textNode.style) - append(textNode.text.takeWhile { it == ' ' }) - append(decorators) - append(textNode.text.trim()) - append(decorators.reversed()) - append(textNode.text.takeLastWhile { it == ' ' }) - } - } - - override fun StringBuilder.buildNavigation(page: PageNode) { - locationProvider.ancestors(page).asReversed().forEach { node -> - append("/") - if (node.isNavigable) buildLink(node, page) - else append(node.name) - } - buildParagraph() - } - - override fun buildPage(page: ContentPage, content: (StringBuilder, ContentPage) -> Unit): String = - buildString { - content(this, page) - } - - override fun buildError(node: ContentNode) { - context.logger.warn("Markdown renderer has encountered problem. The unmatched node is $node") - } - - override fun StringBuilder.buildDivergent(node: ContentDivergentGroup, pageContext: ContentPage) { - - val distinct = - node.groupDivergentInstances(pageContext, { instance, contentPage, sourceSet -> - instance.before?.let { before -> - buildString { buildContentNode(before, pageContext, sourceSet) } - } ?: "" - }, { instance, contentPage, sourceSet -> - instance.after?.let { after -> - buildString { buildContentNode(after, pageContext, sourceSet) } - } ?: "" - }) - - distinct.values.forEach { entry -> - val (instance, sourceSets) = entry.getInstanceAndSourceSets() - - buildSourceSetTags(sourceSets) - buildNewLine() - instance.before?.let { - append("Brief description") - buildNewLine() - buildContentNode( - it, - pageContext, - sourceSets.first() - ) // It's workaround to render content only once - buildNewLine() - } - - append("Content") - buildNewLine() - entry.groupBy { buildString { buildContentNode(it.first.divergent, pageContext, setOf(it.second)) } } - .values.forEach { innerEntry -> - val (innerInstance, innerSourceSets) = innerEntry.getInstanceAndSourceSets() - if (sourceSets.size > 1) { - buildSourceSetTags(innerSourceSets) - buildNewLine() - } - innerInstance.divergent.build( - this@buildDivergent, - pageContext, - setOf(innerSourceSets.first()) - ) // It's workaround to render content only once - buildNewLine() - } - - instance.after?.let { - append("More info") - buildNewLine() - buildContentNode( - it, - pageContext, - sourceSets.first() - ) // It's workaround to render content only once - buildNewLine() - } - - buildParagraph() - } - } - - private fun decorators(styles: Set