diff options
author | vmishenev <vad-mishenev@yandex.ru> | 2021-09-01 00:03:13 +0300 |
---|---|---|
committer | vmishenev <vad-mishenev@yandex.ru> | 2021-09-20 19:01:44 +0300 |
commit | fc5496fb8bb888c3a50717260dc05d8fe2d54306 (patch) | |
tree | 2b61c01babe696065c4b8bafad61cce7479561ad /plugins | |
parent | 8efe04e127e3bf0aef395b31f3f3d9f49a0afe26 (diff) | |
download | dokka-fc5496fb8bb888c3a50717260dc05d8fe2d54306.tar.gz dokka-fc5496fb8bb888c3a50717260dc05d8fe2d54306.tar.bz2 dokka-fc5496fb8bb888c3a50717260dc05d8fe2d54306.zip |
Improve versioning plugin (#2104)
- support for single module projects
- version navigator is on all pages
- dropdown arrow for version navigator
Diffstat (limited to 'plugins')
27 files changed, 609 insertions, 200 deletions
diff --git a/plugins/all-modules-page/api/all-modules-page.api b/plugins/all-modules-page/api/all-modules-page.api index 1849c6d9..9d8bca9b 100644 --- a/plugins/all-modules-page/api/all-modules-page.api +++ b/plugins/all-modules-page/api/all-modules-page.api @@ -4,10 +4,10 @@ public final class org/jetbrains/dokka/allModulesPage/AllModulesPageGeneration : public final fun finishProcessingSubmodules ()V public fun generate (Lorg/jetbrains/dokka/Timer;)V public fun getGenerationName ()Ljava/lang/String; - public final fun handlePreviousDocs ()V public final fun processMultiModule (Lorg/jetbrains/dokka/pages/RootPageNode;)V public final fun processSubmodules ()Lorg/jetbrains/dokka/allModulesPage/AllModulesPageGeneration$DefaultAllModulesContext; public final fun render (Lorg/jetbrains/dokka/pages/RootPageNode;)V + public final fun runPostActions ()V public final fun transformAllModulesPage (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RootPageNode; } @@ -51,8 +51,10 @@ public abstract interface class org/jetbrains/dokka/allModulesPage/ExternalModul } public class org/jetbrains/dokka/allModulesPage/MultimoduleLocationProvider : org/jetbrains/dokka/base/resolvers/local/DokkaBaseLocationProvider { - public fun <init> (Lorg/jetbrains/dokka/pages/RootPageNode;Lorg/jetbrains/dokka/plugability/DokkaContext;)V + public fun <init> (Lorg/jetbrains/dokka/pages/RootPageNode;Lorg/jetbrains/dokka/plugability/DokkaContext;Ljava/lang/String;)V + public synthetic fun <init> (Lorg/jetbrains/dokka/pages/RootPageNode;Lorg/jetbrains/dokka/plugability/DokkaContext;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun ancestors (Lorg/jetbrains/dokka/pages/PageNode;)Ljava/util/List; + public final fun getExtension ()Ljava/lang/String; public fun pathToRoot (Lorg/jetbrains/dokka/pages/PageNode;)Ljava/lang/String; public fun resolve (Lorg/jetbrains/dokka/links/DRI;Ljava/util/Set;Lorg/jetbrains/dokka/pages/PageNode;)Ljava/lang/String; public fun resolve (Lorg/jetbrains/dokka/pages/PageNode;Lorg/jetbrains/dokka/pages/PageNode;Z)Ljava/lang/String; diff --git a/plugins/all-modules-page/build.gradle.kts b/plugins/all-modules-page/build.gradle.kts index 9ab299f6..ff9fcbd8 100644 --- a/plugins/all-modules-page/build.gradle.kts +++ b/plugins/all-modules-page/build.gradle.kts @@ -7,7 +7,6 @@ registerDokkaArtifactPublication("dokkaAllModulesPage") { dependencies { implementation(project(":plugins:base")) implementation(project(":plugins:templating")) - implementation(project(":plugins:versioning")) testImplementation(project(":plugins:base")) testImplementation(project(":plugins:base:base-test-utils")) testImplementation(project(":plugins:gfm")) diff --git a/plugins/all-modules-page/src/main/kotlin/AllModulesPageGeneration.kt b/plugins/all-modules-page/src/main/kotlin/AllModulesPageGeneration.kt index 21c624ef..8558750e 100644 --- a/plugins/all-modules-page/src/main/kotlin/AllModulesPageGeneration.kt +++ b/plugins/all-modules-page/src/main/kotlin/AllModulesPageGeneration.kt @@ -11,13 +11,11 @@ import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.templates.TemplatingPlugin import org.jetbrains.dokka.templates.TemplatingResult import org.jetbrains.dokka.transformers.pages.CreationContext -import org.jetbrains.dokka.versioning.VersioningPlugin class AllModulesPageGeneration(private val context: DokkaContext) : Generation { private val allModulesPagePlugin by lazy { context.plugin<AllModulesPagePlugin>() } private val templatingPlugin by lazy { context.plugin<TemplatingPlugin>() } - private val versioningPlugin by lazy { context.plugin<VersioningPlugin>() } override fun Timer.generate() { report("Processing submodules") @@ -26,9 +24,6 @@ class AllModulesPageGeneration(private val context: DokkaContext) : Generation { report("Creating all modules page") val pages = createAllModulesPage(generationContext) - report("Copy previous documentation") - handlePreviousDocs() - report("Transforming pages") val transformedPages = transformAllModulesPage(pages) @@ -40,12 +35,13 @@ class AllModulesPageGeneration(private val context: DokkaContext) : Generation { report("Finish submodule processing") finishProcessingSubmodules() + + report("Running post-actions") + runPostActions() } override val generationName = "index page for project" - fun handlePreviousDocs() = versioningPlugin.querySingle { versioningHandler }.invoke() - fun createAllModulesPage(allModulesContext: DefaultAllModulesContext) = allModulesPagePlugin.querySingle { allModulesPageCreator }.invoke(allModulesContext) @@ -56,6 +52,10 @@ class AllModulesPageGeneration(private val context: DokkaContext) : Generation { context.single(CoreExtensions.renderer).render(transformedPages) } + fun runPostActions() { + context[CoreExtensions.postActions].forEach { it() } + } + fun processSubmodules() = templatingPlugin.querySingle { submoduleTemplateProcessor } .process(context.configuration.modules) diff --git a/plugins/all-modules-page/src/main/kotlin/MultimoduleLocationProvider.kt b/plugins/all-modules-page/src/main/kotlin/MultimoduleLocationProvider.kt index 1a323f63..dab5be09 100644 --- a/plugins/all-modules-page/src/main/kotlin/MultimoduleLocationProvider.kt +++ b/plugins/all-modules-page/src/main/kotlin/MultimoduleLocationProvider.kt @@ -12,7 +12,8 @@ import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle -open class MultimoduleLocationProvider(private val root: RootPageNode, dokkaContext: DokkaContext) : +open class MultimoduleLocationProvider(private val root: RootPageNode, dokkaContext: DokkaContext, + val extension: String = ".html") : DokkaBaseLocationProvider(root, dokkaContext) { private val defaultLocationProvider = @@ -27,7 +28,7 @@ open class MultimoduleLocationProvider(private val root: RootPageNode, dokkaCont ?.let(externalModuleLinkResolver::resolveLinkToModuleIndex) override fun resolve(node: PageNode, context: PageNode?, skipExtension: Boolean) = - if (node is ContentPage && MultimodulePageCreator.MULTIMODULE_ROOT_DRI in node.dri) pathToRoot(root) + "index" + if (node is ContentPage && MultimodulePageCreator.MULTIMODULE_ROOT_DRI in node.dri) pathToRoot(root) + "index" + if (!skipExtension) extension else "" else defaultLocationProvider.resolve(node, context, skipExtension) override fun pathToRoot(from: PageNode): String = defaultLocationProvider.pathToRoot(from) diff --git a/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt b/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt index 4285046a..f522fd4c 100644 --- a/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt +++ b/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt @@ -19,14 +19,10 @@ import org.jetbrains.dokka.model.doc.P import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.configuration import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.transformers.pages.PageCreator import org.jetbrains.dokka.utilities.DokkaLogger -import org.jetbrains.dokka.versioning.ReplaceVersionsCommand -import org.jetbrains.dokka.versioning.VersioningConfiguration -import org.jetbrains.dokka.versioning.VersioningPlugin import java.io.File class MultimodulePageCreator( @@ -46,11 +42,6 @@ class MultimodulePageCreator( kind = ContentKind.Cover, sourceSets = sourceSetData ) { - /* The line below checks if there is a provided configuration for versioning. - If not, we are skipping the template for inserting versions navigation */ - configuration<VersioningPlugin, VersioningConfiguration>(context)?.let { - group(extra = PropertyContainer.withAll(InsertTemplateExtra(ReplaceVersionsCommand))) { } - } getMultiModuleDocumentation(context.configuration.includes).takeIf { it.isNotEmpty() }?.let { nodes -> group(kind = ContentKind.Cover) { nodes.forEach { node -> diff --git a/plugins/base/api/base.api b/plugins/base/api/base.api index 10d2c564..2ab821d4 100644 --- a/plugins/base/api/base.api +++ b/plugins/base/api/base.api @@ -42,6 +42,7 @@ public final class org/jetbrains/dokka/base/DokkaBase : org/jetbrains/dokka/plug public final fun getPathToRootConsumer ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getPreMergeDocumentableTransformer ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; public final fun getPsiToDocumentableTranslator ()Lorg/jetbrains/dokka/plugability/Extension; + public final fun getReplaceVersionConsumer ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getResolveLinkConsumer ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getRootCreator ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getSameMethodNameMerger ()Lorg/jetbrains/dokka/plugability/Extension; @@ -99,6 +100,7 @@ public final class org/jetbrains/dokka/base/generation/SingleModuleGeneration : public final fun mergeDocumentationModels (Ljava/util/List;)Lorg/jetbrains/dokka/model/DModule; public final fun render (Lorg/jetbrains/dokka/pages/RootPageNode;)V public final fun reportAfterRendering ()V + public final fun runPostActions ()V public final fun transformDocumentationModelAfterMerge (Lorg/jetbrains/dokka/model/DModule;)Lorg/jetbrains/dokka/model/DModule; public final fun transformDocumentationModelBeforeMerge (Ljava/util/List;)Ljava/util/List; public final fun transformPages (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RootPageNode; @@ -534,6 +536,13 @@ public final class org/jetbrains/dokka/base/renderers/html/command/consumers/Pat public fun processCommandAndFinalize (Lorg/jetbrains/dokka/base/templating/Command;Lkotlin/jvm/functions/Function1;Lorg/jetbrains/dokka/base/renderers/html/command/consumers/ImmediateResolutionTagConsumer;)Ljava/lang/Object; } +public final class org/jetbrains/dokka/base/renderers/html/command/consumers/ReplaceVersionsConsumer : org/jetbrains/dokka/base/templating/ImmediateHtmlCommandConsumer { + public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V + public fun canProcess (Lorg/jetbrains/dokka/base/templating/Command;)Z + public fun processCommand (Lorg/jetbrains/dokka/base/templating/Command;Lkotlin/jvm/functions/Function1;Lorg/jetbrains/dokka/base/renderers/html/command/consumers/ImmediateResolutionTagConsumer;)V + public fun processCommandAndFinalize (Lorg/jetbrains/dokka/base/templating/Command;Lkotlin/jvm/functions/Function1;Lorg/jetbrains/dokka/base/renderers/html/command/consumers/ImmediateResolutionTagConsumer;)Ljava/lang/Object; +} + public final class org/jetbrains/dokka/base/renderers/html/command/consumers/ResolveLinkConsumer : org/jetbrains/dokka/base/templating/ImmediateHtmlCommandConsumer { public static final field INSTANCE Lorg/jetbrains/dokka/base/renderers/html/command/consumers/ResolveLinkConsumer; public fun canProcess (Lorg/jetbrains/dokka/base/templating/Command;)Z @@ -955,6 +964,19 @@ public final class org/jetbrains/dokka/base/templating/ProjectNameSubstitutionCo public fun toString ()Ljava/lang/String; } +public final class org/jetbrains/dokka/base/templating/ReplaceVersionsCommand : org/jetbrains/dokka/base/templating/Command { + public fun <init> ()V + public fun <init> (Ljava/lang/String;)V + public synthetic fun <init> (Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lorg/jetbrains/dokka/base/templating/ReplaceVersionsCommand; + public static synthetic fun copy$default (Lorg/jetbrains/dokka/base/templating/ReplaceVersionsCommand;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/dokka/base/templating/ReplaceVersionsCommand; + public fun equals (Ljava/lang/Object;)Z + public final fun getLocation ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class org/jetbrains/dokka/base/templating/ResolveLinkCommand : org/jetbrains/dokka/base/templating/Command { public fun <init> (Lorg/jetbrains/dokka/links/DRI;)V public final fun getDri ()Lorg/jetbrains/dokka/links/DRI; diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index 7e88d08f..fc138461 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -28,6 +28,7 @@ import org.jetbrains.dokka.base.translators.descriptors.DefaultDescriptorToDocum import org.jetbrains.dokka.base.translators.documentables.DefaultDocumentableToPageTranslator import org.jetbrains.dokka.base.translators.psi.DefaultPsiToDocumentableTranslator import org.jetbrains.dokka.base.generation.SingleModuleGeneration +import org.jetbrains.dokka.base.renderers.html.command.consumers.ReplaceVersionsConsumer import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer import org.jetbrains.dokka.transformers.pages.PageTransformer @@ -242,7 +243,9 @@ class DokkaBase : DokkaPlugin() { val resolveLinkConsumer by extending { immediateHtmlCommandConsumer with ResolveLinkConsumer } - + val replaceVersionConsumer by extending { + immediateHtmlCommandConsumer providing ::ReplaceVersionsConsumer + } val pathToRootConsumer by extending { immediateHtmlCommandConsumer with PathToRootConsumer } diff --git a/plugins/base/src/main/kotlin/generation/SingleModuleGeneration.kt b/plugins/base/src/main/kotlin/generation/SingleModuleGeneration.kt index e0deef17..5cdeeb40 100644 --- a/plugins/base/src/main/kotlin/generation/SingleModuleGeneration.kt +++ b/plugins/base/src/main/kotlin/generation/SingleModuleGeneration.kt @@ -46,6 +46,9 @@ class SingleModuleGeneration(private val context: DokkaContext) : Generation { report("Rendering") render(transformedPages) + report("Running post-actions") + runPostActions() + reportAfterRendering() } @@ -76,6 +79,10 @@ class SingleModuleGeneration(private val context: DokkaContext) : Generation { context.single(CoreExtensions.renderer).render(transformedPages) } + fun runPostActions() { + context[CoreExtensions.postActions].forEach { it() } + } + fun validityCheck(context: DokkaContext) { val (preGenerationCheckResult, checkMessages) = context[CoreExtensions.preGenerationCheck].fold( Pair(true, emptyList<String>()) diff --git a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt index 5eaf9fc7..2a21337f 100644 --- a/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/DefaultRenderer.kt @@ -12,6 +12,7 @@ import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.dokka.renderers.PostAction import org.jetbrains.dokka.renderers.Renderer import org.jetbrains.dokka.transformers.pages.PageTransformer diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt index 951f0973..9a88de86 100644 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt @@ -13,10 +13,7 @@ import org.jetbrains.dokka.base.renderers.isImage import org.jetbrains.dokka.base.renderers.pageId import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint import org.jetbrains.dokka.base.resolvers.local.DokkaBaseLocationProvider -import org.jetbrains.dokka.base.templating.InsertTemplateExtra -import org.jetbrains.dokka.base.templating.PathToRootSubstitutionCommand -import org.jetbrains.dokka.base.templating.ProjectNameSubstitutionCommand -import org.jetbrains.dokka.base.templating.ResolveLinkCommand +import org.jetbrains.dokka.base.templating.* import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.DisplaySourceSet import org.jetbrains.dokka.model.properties.PropertyContainer @@ -757,6 +754,7 @@ open class HtmlRenderer( get() = URI(this).isAbsolute open fun buildHtml(page: PageNode, resources: List<String>, content: FlowContent.() -> Unit): String { + val path = locationProvider.resolve(page) val pathToRoot = locationProvider.pathToRoot(page) return createHTML().prepareForTemplates().html { head { @@ -821,9 +819,7 @@ open class HtmlRenderer( div("library-name") { clickableLogo(page, pathToRoot) } - context.configuration.moduleVersion?.let { moduleVersion -> - div { text(moduleVersion) } - } + div { templateCommand(ReplaceVersionsCommand(path.orEmpty())) } div("pull-right d-flex") { filterButtons(page) button { diff --git a/plugins/base/src/main/kotlin/renderers/html/command/consumers/ReplaceVersionsConsumer.kt b/plugins/base/src/main/kotlin/renderers/html/command/consumers/ReplaceVersionsConsumer.kt new file mode 100644 index 00000000..ea8cde0f --- /dev/null +++ b/plugins/base/src/main/kotlin/renderers/html/command/consumers/ReplaceVersionsConsumer.kt @@ -0,0 +1,25 @@ +package org.jetbrains.dokka.base.renderers.html.command.consumers + +import org.jetbrains.dokka.base.renderers.html.TemplateBlock +import org.jetbrains.dokka.base.templating.Command +import org.jetbrains.dokka.base.templating.ImmediateHtmlCommandConsumer +import org.jetbrains.dokka.base.templating.ReplaceVersionsCommand +import org.jetbrains.dokka.plugability.DokkaContext + +class ReplaceVersionsConsumer(private val context: DokkaContext) : ImmediateHtmlCommandConsumer { + override fun canProcess(command: Command) = command is ReplaceVersionsCommand + + override fun <R> processCommand( + command: Command, + block: TemplateBlock, + tagConsumer: ImmediateResolutionTagConsumer<R> + ) { + command as ReplaceVersionsCommand + tagConsumer.onTagContentUnsafe { +context.configuration.moduleVersion.orEmpty() } + } + + override fun <R> processCommandAndFinalize(command: Command, block: TemplateBlock, tagConsumer: ImmediateResolutionTagConsumer<R>): R { + PathToRootConsumer.processCommand(command, block, tagConsumer) + return tagConsumer.finalize() + } +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/templating/ReplaceVersionsCommand.kt b/plugins/base/src/main/kotlin/templating/ReplaceVersionsCommand.kt new file mode 100644 index 00000000..89f267b3 --- /dev/null +++ b/plugins/base/src/main/kotlin/templating/ReplaceVersionsCommand.kt @@ -0,0 +1,3 @@ +package org.jetbrains.dokka.base.templating + +data class ReplaceVersionsCommand(val location: String = ""): Command
\ No newline at end of file diff --git a/plugins/templating/api/templating.api b/plugins/templating/api/templating.api index 0965020b..a0fb5122 100644 --- a/plugins/templating/api/templating.api +++ b/plugins/templating/api/templating.api @@ -130,6 +130,7 @@ public final class org/jetbrains/dokka/templates/TemplatingPlugin : org/jetbrain public final fun getPagesSearchTemplateStrategy ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getPathToRootSubstitutor ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getProjectNameSubstitutor ()Lorg/jetbrains/dokka/plugability/Extension; + public final fun getReplaceVersionCommandHandler ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getSourcesetDependencyProcessingStrategy ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getSubmoduleTemplateProcessor ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; public final fun getSubstitutionCommandHandler ()Lorg/jetbrains/dokka/plugability/Extension; @@ -156,6 +157,13 @@ public final class templates/ProjectNameSubstitutor : org/jetbrains/dokka/templa public fun trySubstitute (Lorg/jetbrains/dokka/templates/TemplatingContext;Lkotlin/text/MatchResult;)Ljava/lang/String; } +public final class templates/ReplaceVersionCommandHandler : org/jetbrains/dokka/templates/CommandHandler { + public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V + public fun canHandle (Lorg/jetbrains/dokka/base/templating/Command;)Z + public fun finish (Ljava/io/File;)V + public fun handleCommand (Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;Ljava/io/File;Ljava/io/File;)V +} + public final class templates/SourcesetDependencyProcessingStrategy : org/jetbrains/dokka/templates/TemplateProcessingStrategy { public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V public fun finish (Ljava/io/File;)V diff --git a/plugins/templating/src/main/kotlin/templates/ReplaceVersionCommandHandler.kt b/plugins/templating/src/main/kotlin/templates/ReplaceVersionCommandHandler.kt new file mode 100644 index 00000000..8035fc83 --- /dev/null +++ b/plugins/templating/src/main/kotlin/templates/ReplaceVersionCommandHandler.kt @@ -0,0 +1,22 @@ +package templates + +import org.jetbrains.dokka.base.templating.Command +import org.jetbrains.dokka.base.templating.ReplaceVersionsCommand +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.templates.CommandHandler +import org.jsoup.nodes.Element +import org.jsoup.nodes.TextNode +import java.io.File + +class ReplaceVersionCommandHandler(private val context: DokkaContext) : CommandHandler { + + override fun canHandle(command: Command): Boolean = command is ReplaceVersionsCommand + + override fun handleCommand(element: Element, command: Command, input: File, output: File) { + val position = element.elementSiblingIndex() + val parent = element.parent() + element.remove() + context.configuration.moduleVersion?.takeIf { it.isNotEmpty() } + ?.let { parent.insertChildren(position, TextNode(it)) } + } +}
\ No newline at end of file diff --git a/plugins/templating/src/main/kotlin/templates/TemplatingPlugin.kt b/plugins/templating/src/main/kotlin/templates/TemplatingPlugin.kt index 1a02d41f..7001b1ba 100644 --- a/plugins/templating/src/main/kotlin/templates/TemplatingPlugin.kt +++ b/plugins/templating/src/main/kotlin/templates/TemplatingPlugin.kt @@ -4,6 +4,7 @@ import org.jetbrains.dokka.allModulesPage.templates.PackageListProcessingStrateg import org.jetbrains.dokka.allModulesPage.templates.PagesSearchTemplateStrategy import org.jetbrains.dokka.plugability.DokkaPlugin import templates.ProjectNameSubstitutor +import templates.ReplaceVersionCommandHandler import templates.SourcesetDependencyProcessingStrategy class TemplatingPlugin : DokkaPlugin() { @@ -65,4 +66,7 @@ class TemplatingPlugin : DokkaPlugin() { val substitutionCommandHandler by extending { directiveBasedCommandHandlers providing ::SubstitutionCommandHandler } + val replaceVersionCommandHandler by extending { + directiveBasedCommandHandlers providing ::ReplaceVersionCommandHandler + } } diff --git a/plugins/versioning/api/versioning.api b/plugins/versioning/api/versioning.api index 8223579b..15ebe7be 100644 --- a/plugins/versioning/api/versioning.api +++ b/plugins/versioning/api/versioning.api @@ -4,28 +4,45 @@ public final class org/jetbrains/dokka/versioning/ByConfigurationVersionOrdering public fun order (Ljava/util/List;)Ljava/util/List; } -public final class org/jetbrains/dokka/versioning/DefaultVersioningHandler : org/jetbrains/dokka/versioning/VersioningHandler { - public static final field Companion Lorg/jetbrains/dokka/versioning/DefaultVersioningHandler$Companion; +public final class org/jetbrains/dokka/versioning/CurrentVersion { + public fun <init> (Ljava/lang/String;Ljava/io/File;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/io/File; + public final fun copy (Ljava/lang/String;Ljava/io/File;)Lorg/jetbrains/dokka/versioning/CurrentVersion; + public static synthetic fun copy$default (Lorg/jetbrains/dokka/versioning/CurrentVersion;Ljava/lang/String;Ljava/io/File;ILjava/lang/Object;)Lorg/jetbrains/dokka/versioning/CurrentVersion; + public fun equals (Ljava/lang/Object;)Z + public final fun getDir ()Ljava/io/File; + public final fun getName ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction : org/jetbrains/dokka/renderers/PostAction { public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V - public fun currentVersion ()Ljava/io/File; - public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext; - public fun getVersions ()Ljava/util/Map; public synthetic fun invoke ()Ljava/lang/Object; public fun invoke ()V } -public final class org/jetbrains/dokka/versioning/DefaultVersioningHandler$Companion { +public final class org/jetbrains/dokka/versioning/DefaultVersioningStorage : org/jetbrains/dokka/versioning/VersioningStorage { + public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V + public fun createVersionFile ()V + public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext; + public fun getCurrentVersion ()Lorg/jetbrains/dokka/versioning/CurrentVersion; + public fun getPreviousVersions ()Ljava/util/Map; } public final class org/jetbrains/dokka/versioning/HtmlVersionsNavigationCreator : org/jetbrains/dokka/versioning/VersionsNavigationCreator { public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V - public final fun getContext ()Lorg/jetbrains/dokka/plugability/DokkaContext; - public fun invoke ()Ljava/lang/String; public fun invoke (Ljava/io/File;)Ljava/lang/String; } public final class org/jetbrains/dokka/versioning/MultiModuleStylesInstaller : org/jetbrains/dokka/transformers/pages/PageTransformer { - public static final field INSTANCE Lorg/jetbrains/dokka/versioning/MultiModuleStylesInstaller; + public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V + public fun invoke (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RootPageNode; +} + +public final class org/jetbrains/dokka/versioning/NotFoundPageInstaller : org/jetbrains/dokka/transformers/pages/PageTransformer { + public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V public fun invoke (Lorg/jetbrains/dokka/pages/RootPageNode;)Lorg/jetbrains/dokka/pages/RootPageNode; } @@ -44,34 +61,48 @@ public final class org/jetbrains/dokka/versioning/ReplaceVersionCommandHandler : public fun handleCommand (Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;Ljava/io/File;Ljava/io/File;)V } -public final class org/jetbrains/dokka/versioning/ReplaceVersionsCommand : org/jetbrains/dokka/base/templating/Command { - public static final field INSTANCE Lorg/jetbrains/dokka/versioning/ReplaceVersionsCommand; -} - public final class org/jetbrains/dokka/versioning/SemVerVersionOrdering : org/jetbrains/dokka/versioning/VersionsOrdering { public fun <init> ()V public fun order (Ljava/util/List;)Ljava/util/List; } +public final class org/jetbrains/dokka/versioning/VersionDirs { + public fun <init> (Ljava/io/File;Ljava/io/File;)V + public final fun component1 ()Ljava/io/File; + public final fun component2 ()Ljava/io/File; + public final fun copy (Ljava/io/File;Ljava/io/File;)Lorg/jetbrains/dokka/versioning/VersionDirs; + public static synthetic fun copy$default (Lorg/jetbrains/dokka/versioning/VersionDirs;Ljava/io/File;Ljava/io/File;ILjava/lang/Object;)Lorg/jetbrains/dokka/versioning/VersionDirs; + public fun equals (Ljava/lang/Object;)Z + public final fun getDst ()Ljava/io/File; + public final fun getSrc ()Ljava/io/File; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class org/jetbrains/dokka/versioning/VersioningConfiguration : org/jetbrains/dokka/plugability/ConfigurableBlock { public static final field Companion Lorg/jetbrains/dokka/versioning/VersioningConfiguration$Companion; + public static final field OLDER_VERSIONS_DIR Ljava/lang/String; + public static final field VERSIONS_FILE Ljava/lang/String; public fun <init> ()V - public fun <init> (Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;)V - public synthetic fun <init> (Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun <init> (Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;)V + public synthetic fun <init> (Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/io/File; public final fun component2 ()Ljava/util/List; public final fun component3 ()Ljava/util/List; public final fun component4 ()Ljava/lang/String; - public final fun copy (Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;)Lorg/jetbrains/dokka/versioning/VersioningConfiguration; - public static synthetic fun copy$default (Lorg/jetbrains/dokka/versioning/VersioningConfiguration;Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;ILjava/lang/Object;)Lorg/jetbrains/dokka/versioning/VersioningConfiguration; + public final fun component5 ()Ljava/lang/Boolean; + public final fun copy (Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;)Lorg/jetbrains/dokka/versioning/VersioningConfiguration; + public static synthetic fun copy$default (Lorg/jetbrains/dokka/versioning/VersioningConfiguration;Ljava/io/File;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Boolean;ILjava/lang/Object;)Lorg/jetbrains/dokka/versioning/VersioningConfiguration; public fun equals (Ljava/lang/Object;)Z public final fun getOlderVersions ()Ljava/util/List; public final fun getOlderVersionsDir ()Ljava/io/File; + public final fun getRenderVersionsNavigationOnAllPages ()Ljava/lang/Boolean; public final fun getVersion ()Ljava/lang/String; public final fun getVersionsOrdering ()Ljava/util/List; public fun hashCode ()I public final fun setOlderVersions (Ljava/util/List;)V public final fun setOlderVersionsDir (Ljava/io/File;)V + public final fun setRenderVersionsNavigationOnAllPages (Ljava/lang/Boolean;)V public final fun setVersion (Ljava/lang/String;)V public final fun setVersionsOrdering (Ljava/util/List;)V public fun toString ()Ljava/lang/String; @@ -80,30 +111,33 @@ public final class org/jetbrains/dokka/versioning/VersioningConfiguration : org/ public final class org/jetbrains/dokka/versioning/VersioningConfiguration$Companion { public final fun getDefaultOlderVersions ()Ljava/util/List; public final fun getDefaultOlderVersionsDir ()Ljava/io/File; + public final fun getDefaultRenderVersionsNavigationOnAllPages ()Z public final fun getDefaultVersion ()Ljava/lang/Void; public final fun getDefaultVersionsOrdering ()Ljava/util/List; } -public abstract interface class org/jetbrains/dokka/versioning/VersioningHandler : kotlin/jvm/functions/Function0 { - public abstract fun currentVersion ()Ljava/io/File; - public abstract fun getVersions ()Ljava/util/Map; -} - public final class org/jetbrains/dokka/versioning/VersioningPlugin : org/jetbrains/dokka/plugability/DokkaPlugin { public fun <init> ()V public final fun getCssStyleInstaller ()Lorg/jetbrains/dokka/plugability/Extension; - public final fun getDefaultVersioningHandler ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getDefaultVersioningNavigationCreator ()Lorg/jetbrains/dokka/plugability/Extension; + public final fun getDefaultVersioningStorage ()Lorg/jetbrains/dokka/plugability/Extension; + public final fun getNotFoundPageInstaller ()Lorg/jetbrains/dokka/plugability/Extension; + public final fun getPreviousDocumentationCopyPostAction ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getReplaceVersionCommandHandler ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getResolveLinkConsumer ()Lorg/jetbrains/dokka/plugability/Extension; - public final fun getVersioningHandler ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; + public final fun getVersioningStorage ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; public final fun getVersionsDefaultOrdering ()Lorg/jetbrains/dokka/plugability/Extension; public final fun getVersionsNavigationCreator ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; public final fun getVersionsOrdering ()Lorg/jetbrains/dokka/plugability/ExtensionPoint; } +public abstract interface class org/jetbrains/dokka/versioning/VersioningStorage { + public abstract fun createVersionFile ()V + public abstract fun getCurrentVersion ()Lorg/jetbrains/dokka/versioning/CurrentVersion; + public abstract fun getPreviousVersions ()Ljava/util/Map; +} + public abstract interface class org/jetbrains/dokka/versioning/VersionsNavigationCreator { - public abstract fun invoke ()Ljava/lang/String; public abstract fun invoke (Ljava/io/File;)Ljava/lang/String; } diff --git a/plugins/versioning/src/main/kotlin/versioning/DefaultPreviousDocumentationCopyPostAction.kt b/plugins/versioning/src/main/kotlin/versioning/DefaultPreviousDocumentationCopyPostAction.kt new file mode 100644 index 00000000..6ab81d31 --- /dev/null +++ b/plugins/versioning/src/main/kotlin/versioning/DefaultPreviousDocumentationCopyPostAction.kt @@ -0,0 +1,54 @@ +package org.jetbrains.dokka.versioning + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import org.jetbrains.dokka.renderers.PostAction +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.query +import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.dokka.templates.TemplateProcessingStrategy +import org.jetbrains.dokka.templates.TemplatingPlugin +import java.io.File + +class DefaultPreviousDocumentationCopyPostAction(private val context: DokkaContext) : PostAction { + private val versioningStorage by lazy { context.plugin<VersioningPlugin>().querySingle { versioningStorage } } + private val processingStrategies: List<TemplateProcessingStrategy> = + context.plugin<TemplatingPlugin>().query { templateProcessingStrategy } + + override fun invoke() { + versioningStorage.createVersionFile() + versioningStorage.previousVersions.forEach { (_, dirs) -> copyVersion(dirs.src, dirs.dst) } + } + + private fun copyVersion(versionRoot: File, targetParent: File) { + targetParent.apply { mkdirs() } + val ignoreDir = versionRoot.resolve(VersioningConfiguration.OLDER_VERSIONS_DIR) + runBlocking(Dispatchers.Default) { + coroutineScope { + versionRoot.listFiles().orEmpty() + .filter { it.absolutePath != ignoreDir.absolutePath } + .forEach { versionRootContent -> + launch { + processRecursively(versionRootContent, targetParent) + } + } + } + } + } + + private fun processRecursively(versionRootContent: File, targetParent: File) { + if (versionRootContent.isDirectory) { + val target = targetParent.resolve(versionRootContent.name).also { it.mkdir() } + versionRootContent.listFiles()?.forEach { + processRecursively(it, target) + } + } else if (versionRootContent.extension == "html") processingStrategies.first { + it.process(versionRootContent, targetParent.resolve(versionRootContent.name), null) + } else { + versionRootContent.copyTo(targetParent.resolve(versionRootContent.name), overwrite = true) + } + } +}
\ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionCommandConsumer.kt b/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionCommandConsumer.kt index 2577b2da..ea524c52 100644 --- a/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionCommandConsumer.kt +++ b/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionCommandConsumer.kt @@ -8,6 +8,7 @@ import org.jetbrains.dokka.base.renderers.html.command.consumers.ImmediateResolu import org.jetbrains.dokka.base.renderers.html.templateCommandFor import org.jetbrains.dokka.base.templating.Command import org.jetbrains.dokka.base.templating.ImmediateHtmlCommandConsumer +import org.jetbrains.dokka.base.templating.ReplaceVersionsCommand import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle @@ -16,6 +17,8 @@ class ReplaceVersionCommandConsumer(context: DokkaContext) : ImmediateHtmlComman private val versionsNavigationCreator = context.plugin<VersioningPlugin>().querySingle { versionsNavigationCreator } + private val versioningStorage = + context.plugin<VersioningPlugin>().querySingle { versioningStorage } override fun canProcess(command: Command) = command is ReplaceVersionsCommand @@ -27,7 +30,7 @@ class ReplaceVersionCommandConsumer(context: DokkaContext) : ImmediateHtmlComman command as ReplaceVersionsCommand templateCommandFor(command, tagConsumer).visit { unsafe { - +versionsNavigationCreator() + +versionsNavigationCreator(versioningStorage.currentVersion.dir.resolve(command.location)) } } } @@ -36,10 +39,12 @@ class ReplaceVersionCommandConsumer(context: DokkaContext) : ImmediateHtmlComman command: Command, block: TemplateBlock, tagConsumer: ImmediateResolutionTagConsumer<R> - ): R = - templateCommandFor(command, tagConsumer).visitAndFinalize(tagConsumer) { + ): R { + command as ReplaceVersionsCommand + return templateCommandFor(command, tagConsumer).visitAndFinalize(tagConsumer) { unsafe { - +versionsNavigationCreator() + +versionsNavigationCreator(versioningStorage.currentVersion.dir.resolve(command.location)) } } + } }
\ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionsCommand.kt b/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionsCommand.kt index 2d2c8e36..728eac09 100644 --- a/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionsCommand.kt +++ b/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionsCommand.kt @@ -2,6 +2,7 @@ package org.jetbrains.dokka.versioning import org.jetbrains.dokka.base.templating.Command +import org.jetbrains.dokka.base.templating.ReplaceVersionsCommand import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle @@ -9,8 +10,6 @@ import org.jetbrains.dokka.templates.CommandHandler import org.jsoup.nodes.Element import java.io.File -object ReplaceVersionsCommand : Command - class ReplaceVersionCommandHandler(context: DokkaContext) : CommandHandler { val versionsNavigationCreator by lazy { diff --git a/plugins/versioning/src/main/kotlin/versioning/VersioningConfiguration.kt b/plugins/versioning/src/main/kotlin/versioning/VersioningConfiguration.kt index f5c69cf4..56c72257 100644 --- a/plugins/versioning/src/main/kotlin/versioning/VersioningConfiguration.kt +++ b/plugins/versioning/src/main/kotlin/versioning/VersioningConfiguration.kt @@ -9,6 +9,7 @@ data class VersioningConfiguration( var olderVersions: List<File>? = defaultOlderVersions, var versionsOrdering: List<String>? = defaultVersionsOrdering, var version: String? = defaultVersion, + var renderVersionsNavigationOnAllPages: Boolean? = defaultRenderVersionsNavigationOnAllPages ) : ConfigurableBlock { internal fun versionFromConfigurationOrModule(dokkaContext: DokkaContext): String = version ?: dokkaContext.configuration.moduleVersion ?: "1.0" @@ -25,5 +26,9 @@ data class VersioningConfiguration( val defaultOlderVersions: List<File>? = null val defaultVersionsOrdering: List<String>? = null val defaultVersion = null + val defaultRenderVersionsNavigationOnAllPages = true + + const val OLDER_VERSIONS_DIR = "older" + const val VERSIONS_FILE = "version.json" } }
\ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/versioning/VersioningHandler.kt b/plugins/versioning/src/main/kotlin/versioning/VersioningHandler.kt deleted file mode 100644 index 1cc584b7..00000000 --- a/plugins/versioning/src/main/kotlin/versioning/VersioningHandler.kt +++ /dev/null @@ -1,104 +0,0 @@ -package org.jetbrains.dokka.versioning - -import com.fasterxml.jackson.annotation.JsonProperty -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.module.kotlin.readValue -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.configuration -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.query -import org.jetbrains.dokka.templates.TemplateProcessingStrategy -import org.jetbrains.dokka.templates.TemplatingPlugin -import java.io.File - -interface VersioningHandler : () -> Unit { - fun getVersions(): Map<VersionId, File> - fun currentVersion(): File? -} - -typealias VersionId = String - -class DefaultVersioningHandler(val context: DokkaContext) : VersioningHandler { - - private val mapper = ObjectMapper() - - private lateinit var versions: Map<VersionId, File> - - private val processingStrategies: List<TemplateProcessingStrategy> = - context.plugin<TemplatingPlugin>().query { templateProcessingStrategy } - - private val configuration = configuration<VersioningPlugin, VersioningConfiguration>(context) - - override fun getVersions() = versions - - override fun currentVersion() = configuration?.let { versionsConfiguration -> - versions[versionsConfiguration.versionFromConfigurationOrModule(context)] - } - - override fun invoke() { - configuration?.let { versionsConfiguration -> - versions = - mapOf(versionsConfiguration.versionFromConfigurationOrModule(context) to context.configuration.outputDir) - handlePreviousVersions(versionsConfiguration.allOlderVersions(), context.configuration.outputDir) - mapper.writeValue( - context.configuration.outputDir.resolve(VERSIONS_FILE), - Version(versionsConfiguration.versionFromConfigurationOrModule(context)) - ) - } - } - - private fun handlePreviousVersions(olderVersions: List<File>, output: File): Map<String, File> { - return versionsFrom(olderVersions) - .also { fetched -> - versions = versions + fetched.map { (key, _) -> - key to output.resolve(OLDER_VERSIONS_DIR).resolve(key) - }.toMap() - } - .onEach { (version, path) -> copyVersion(version, path, output) }.toMap() - } - - private fun versionsFrom(olderVersions: List<File>) = - olderVersions.mapNotNull { versionDir -> - versionDir.listFiles { _, name -> name == VERSIONS_FILE }?.firstOrNull()?.let { file -> - val versionsContent = mapper.readValue<Version>(file) - Pair(versionsContent.version, versionDir) - }.also { - if (it == null) context.logger.warn("Failed to find versions file named $VERSIONS_FILE in $versionDir") - } - } - - private fun copyVersion(version: VersionId, versionRoot: File, output: File) { - val targetParent = output.resolve(OLDER_VERSIONS_DIR).resolve(version).apply { mkdirs() } - val olderDirs = versionRoot.resolve(OLDER_VERSIONS_DIR) - runBlocking(Dispatchers.Default) { - coroutineScope { - versionRoot.listFiles().orEmpty() - .filter { it.absolutePath != olderDirs.absolutePath } - .forEach { versionRootContent -> - launch { - if (versionRootContent.isDirectory) versionRootContent.copyRecursively( - targetParent.resolve(versionRootContent.name), - overwrite = true - ) - else processingStrategies.first { - it.process(versionRootContent, targetParent.resolve(versionRootContent.name), null) - } - } - } - } - } - } - - private data class Version( - @JsonProperty("version") val version: String, - ) - - companion object { - private const val OLDER_VERSIONS_DIR = "older" - private const val VERSIONS_FILE = "version.json" - } -} diff --git a/plugins/versioning/src/main/kotlin/versioning/VersioningPlugin.kt b/plugins/versioning/src/main/kotlin/versioning/VersioningPlugin.kt index 9c20a128..e4e8bbae 100644 --- a/plugins/versioning/src/main/kotlin/versioning/VersioningPlugin.kt +++ b/plugins/versioning/src/main/kotlin/versioning/VersioningPlugin.kt @@ -1,5 +1,6 @@ package org.jetbrains.dokka.versioning +import org.jetbrains.dokka.CoreExtensions.postActions import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.plugability.configuration @@ -7,27 +8,36 @@ import org.jetbrains.dokka.templates.TemplatingPlugin class VersioningPlugin : DokkaPlugin() { - val versioningHandler by extensionPoint<VersioningHandler>() + val versioningStorage by extensionPoint<VersioningStorage>() val versionsNavigationCreator by extensionPoint<VersionsNavigationCreator>() val versionsOrdering by extensionPoint<VersionsOrdering>() private val dokkaBase by lazy { plugin<DokkaBase>() } private val templatingPlugin by lazy { plugin<TemplatingPlugin>() } - val defaultVersioningHandler by extending { - versioningHandler providing ::DefaultVersioningHandler + val defaultVersioningStorage by extending { + versioningStorage providing ::DefaultVersioningStorage } val defaultVersioningNavigationCreator by extending { versionsNavigationCreator providing ::HtmlVersionsNavigationCreator } val replaceVersionCommandHandler by extending { - templatingPlugin.directiveBasedCommandHandlers providing ::ReplaceVersionCommandHandler + templatingPlugin.directiveBasedCommandHandlers providing ::ReplaceVersionCommandHandler override templatingPlugin.replaceVersionCommandHandler } val resolveLinkConsumer by extending { - dokkaBase.immediateHtmlCommandConsumer providing ::ReplaceVersionCommandConsumer + dokkaBase.immediateHtmlCommandConsumer providing ::ReplaceVersionCommandConsumer override dokkaBase.replaceVersionConsumer } val cssStyleInstaller by extending { - dokkaBase.htmlPreprocessors with MultiModuleStylesInstaller order { after(dokkaBase.assetsInstaller) } + dokkaBase.htmlPreprocessors providing ::MultiModuleStylesInstaller order { + after(dokkaBase.assetsInstaller) + before(dokkaBase.customResourceInstaller) + } + } + val notFoundPageInstaller by extending { + dokkaBase.htmlPreprocessors providing ::NotFoundPageInstaller order { + after(dokkaBase.assetsInstaller) + before(dokkaBase.customResourceInstaller) + } applyIf { !delayTemplateSubstitution } } val versionsDefaultOrdering by extending { versionsOrdering providing { ctx -> @@ -36,4 +46,7 @@ class VersioningPlugin : DokkaPlugin() { } ?: SemVerVersionOrdering() } } + val previousDocumentationCopyPostAction by extending { + postActions providing ::DefaultPreviousDocumentationCopyPostAction applyIf { !delayTemplateSubstitution } + } }
\ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/versioning/VersioningStorage.kt b/plugins/versioning/src/main/kotlin/versioning/VersioningStorage.kt new file mode 100644 index 00000000..6e1dd7ca --- /dev/null +++ b/plugins/versioning/src/main/kotlin/versioning/VersioningStorage.kt @@ -0,0 +1,65 @@ +package org.jetbrains.dokka.versioning + +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.configuration +import java.io.File + +data class VersionDirs(val src: File, val dst: File) +data class CurrentVersion(val name: String, val dir: File) + +interface VersioningStorage { + val previousVersions: Map<VersionId, VersionDirs> + val currentVersion: CurrentVersion + fun createVersionFile() +} + +typealias VersionId = String + +class DefaultVersioningStorage(val context: DokkaContext) : VersioningStorage { + + private val mapper = ObjectMapper() + private val configuration = configuration<VersioningPlugin, VersioningConfiguration>(context) + + override val previousVersions: Map<VersionId, VersionDirs> by lazy { + configuration?.let { versionsConfiguration -> + getPreviousVersions(versionsConfiguration.allOlderVersions(), context.configuration.outputDir) + } ?: emptyMap() + } + + override val currentVersion: CurrentVersion by lazy { + configuration?.let { versionsConfiguration -> + CurrentVersion(versionsConfiguration.versionFromConfigurationOrModule(context), + context.configuration.outputDir) + }?: CurrentVersion(context.configuration.moduleVersion.orEmpty(), context.configuration.outputDir) + } + + override fun createVersionFile() { + mapper.writeValue( + currentVersion.dir.resolve(VersioningConfiguration.VERSIONS_FILE), + Version(currentVersion.name) + ) + } + + private fun getPreviousVersions(olderVersions: List<File>, output: File): Map<String, VersionDirs> = + versionsFrom(olderVersions).associate { (key, srcDir) -> + key to VersionDirs(srcDir, output.resolve(VersioningConfiguration.OLDER_VERSIONS_DIR).resolve(key)) + } + + private fun versionsFrom(olderVersions: List<File>) = + olderVersions.mapNotNull { versionDir -> + versionDir.listFiles { _, name -> name == VersioningConfiguration.VERSIONS_FILE }?.firstOrNull() + ?.let { file -> + val versionsContent = mapper.readValue<Version>(file) + Pair(versionsContent.version, versionDir) + }.also { + if (it == null) context.logger.warn("Failed to find versions file named ${VersioningConfiguration.VERSIONS_FILE} in $versionDir") + } + } + + private data class Version( + @JsonProperty("version") val version: String, + ) +} diff --git a/plugins/versioning/src/main/kotlin/versioning/VersionsNavigationCreator.kt b/plugins/versioning/src/main/kotlin/versioning/VersionsNavigationCreator.kt index 76653d47..876b3ccf 100644 --- a/plugins/versioning/src/main/kotlin/versioning/VersionsNavigationCreator.kt +++ b/plugins/versioning/src/main/kotlin/versioning/VersionsNavigationCreator.kt @@ -1,53 +1,86 @@ package org.jetbrains.dokka.versioning import kotlinx.html.a -import kotlinx.html.button import kotlinx.html.div -import kotlinx.html.i import kotlinx.html.stream.appendHTML +import org.jetbrains.dokka.base.renderers.html.strike import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.configuration import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.dokka.utilities.urlEncoded import java.io.File -import java.nio.file.Files.isDirectory -import java.nio.file.Path interface VersionsNavigationCreator { - operator fun invoke(): String operator fun invoke(output: File): String } -class HtmlVersionsNavigationCreator(val context: DokkaContext) : VersionsNavigationCreator { +class HtmlVersionsNavigationCreator(private val context: DokkaContext) : VersionsNavigationCreator { - private val versioningHandler by lazy { context.plugin<VersioningPlugin>().querySingle { versioningHandler } } + private val versioningStorage by lazy { context.plugin<VersioningPlugin>().querySingle { versioningStorage } } private val versionsOrdering by lazy { context.plugin<VersioningPlugin>().querySingle { versionsOrdering } } - override fun invoke(): String = - versioningHandler.currentVersion()?.let { invoke(it) }.orEmpty() + private val isOnlyOnRootPage = + configuration<VersioningPlugin, VersioningConfiguration>(context)?.renderVersionsNavigationOnAllPages == false + + private val versions: Map<VersionId, File> by lazy { + versioningStorage.previousVersions.map { (k, v) -> k to v.dst }.toMap() + + (versioningStorage.currentVersion.name to versioningStorage.currentVersion.dir) + } override fun invoke(output: File): String { + if (versions.size == 1) { + return versioningStorage.currentVersion.name + } val position = output.takeIf { it.isDirectory } ?: output.parentFile - return versioningHandler.getVersions() + if (isOnlyOnRootPage) { + getActiveVersion(position)?.takeIf { + it.value == versioningStorage.currentVersion.dir + && it.value != position + }?.also { return@invoke it.key } + } + return versions .let { versions -> versionsOrdering.order(versions.keys.toList()).map { it to versions[it] } } .takeIf { it.isNotEmpty() } - ?.let { versions -> + ?.let { orderedVersions -> StringBuilder().appendHTML().div(classes = "versions-dropdown") { - button(classes = "versions-dropdown-button") { - versions.first { (_, versionLocation) -> versionLocation?.absolutePath == position.absolutePath } - .let { (version, _) -> - text(version) - } - i(classes = "fa fa-caret-down") + val activeVersion = getActiveVersion(position) + val relativePosition: String = activeVersion?.value?.let { output.toRelativeString(it) } ?: "index.html" + div(classes = "versions-dropdown-button") { + activeVersion?.key?.let { text(it) } } div(classes = "versions-dropdown-data") { - versions.forEach { (version, path) -> - a(href = path?.resolve("index.html")?.toRelativeString(position)) { - text(version) + orderedVersions.forEach { (version, path) -> + if (version == activeVersion?.key) { + a(href = output.name) { text(version) } + } else { + val isExistsFile = + if (version == versioningStorage.currentVersion.name) + path?.resolve(relativePosition)?.exists() == true + else + versioningStorage.previousVersions[version]?.src?.resolve(relativePosition) + ?.exists() == true + + val absolutePath = + if (isExistsFile) + path?.resolve(relativePosition) + else + versioningStorage.currentVersion.dir.resolve("not-found-version.html") + + a(href = absolutePath?.toRelativeString(position) + + if (!isExistsFile) "?v=" + version.urlEncoded() else "") { + text(version) + } } } } }.toString() }.orEmpty() } + + private fun getActiveVersion(position: File) = + versions.minByOrNull { (_, versionLocation) -> + versionLocation.let { position.toRelativeString(it).length } + } }
\ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/versioning/htmlPreprocessors.kt b/plugins/versioning/src/main/kotlin/versioning/htmlPreprocessors.kt index 5852ba9e..94400898 100644 --- a/plugins/versioning/src/main/kotlin/versioning/htmlPreprocessors.kt +++ b/plugins/versioning/src/main/kotlin/versioning/htmlPreprocessors.kt @@ -3,22 +3,36 @@ package org.jetbrains.dokka.versioning import org.jetbrains.dokka.pages.RendererSpecificResourcePage import org.jetbrains.dokka.pages.RenderingStrategy import org.jetbrains.dokka.pages.RootPageNode +import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.pages.PageTransformer -object MultiModuleStylesInstaller : PageTransformer { +class MultiModuleStylesInstaller(private val dokkaContext: DokkaContext) : PageTransformer { private val stylesPages = listOf( "styles/multimodule.css", ) override fun invoke(input: RootPageNode): RootPageNode = - input.modified( - children = input.children + stylesPages.toRenderSpecificResourcePage() - ).transformContentPagesTree { + input.let { root -> + if (dokkaContext.configuration.delayTemplateSubstitution) root + else root.modified(children = input.children + stylesPages.toRenderSpecificResourcePage()) + }.transformContentPagesTree { it.modified( embeddedResources = it.embeddedResources + stylesPages ) } } +class NotFoundPageInstaller(private val dokkaContext: DokkaContext) : PageTransformer { + private val notFoundPage = listOf( + "not-found-version.html", + ) + + override fun invoke(input: RootPageNode): RootPageNode = + input.let { root -> + if (dokkaContext.configuration.delayTemplateSubstitution) root + else root.modified(children = input.children + notFoundPage.toRenderSpecificResourcePage()) + } +} + private fun List<String>.toRenderSpecificResourcePage(): List<RendererSpecificResourcePage> = map { RendererSpecificResourcePage(it, emptyList(), RenderingStrategy.Copy("/dokka/$it")) } diff --git a/plugins/versioning/src/main/resources/dokka/not-found-version.html b/plugins/versioning/src/main/resources/dokka/not-found-version.html new file mode 100644 index 00000000..259a4893 --- /dev/null +++ b/plugins/versioning/src/main/resources/dokka/not-found-version.html @@ -0,0 +1,189 @@ +<!DOCTYPE html> +<html> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <title>Unavailable page</title> + <style> +.article-content h1._big { + text-transform: uppercase; + color: #161616; + font-size: 54px; + font-weight: 800; + line-height: 45px; +} +.sub-title { + margin-bottom: 40px; + font-size: 20px; + font-weight: 400; + line-height: 30px; +} +.margin-top-vertical-unit-half { + margin-top: 25px; +} +.wt-row_size_m { + --wt-horizontal-layout-gutter: 16px; +} +.article-content { + color: #343434; + font-family: system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Droid Sans, Helvetica Neue, Arial, sans-serif; + font-size: 14px; + font-weight: 400; + line-height: 25px; +} +.wt-container { + width: 100%; + margin-left: auto; + margin-right: auto; + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding-left: 22px; + padding-right: 22px; + max-width: 1276px; +} +.wt-col-5 { + --wt-col-count: 5; +} +.wt-col-3 { + --wt-col-count: 3; +} +.page-404__logo { + position: relative; + display: flex; +} +.wt-row, .wt-row_wide { + display: -webkit-box; + display: -ms-flexbox; + display: flex; +} +[class*="wt-col"] { + -ms-flex-preferred-size: calc(8.33333%*var(--wt-col-count) - var(--wt-horizontal-layout-gutter)*2); + flex-basis: calc(8.33333%*var(--wt-col-count) - var(--wt-horizontal-layout-gutter)*2); + max-width: calc(8.33333%*var(--wt-col-count) - var(--wt-horizontal-layout-gutter)*2); + -webkit-box-sizing: border-box; + box-sizing: border-box; +} +.wt-row_size_m { + --wt-horizontal-layout-gutter: 16px; +} +[class*="wt-col"], [class*="wt-col"].wt-row { + margin-right: var(--wt-horizontal-layout-gutter); + margin-left: var(--wt-horizontal-layout-gutter); +} +.wt-row_justify_center { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; +} +.page-404__logo .sprite-img._404 { + position: absolute; + width: 100%; + height: 100%; +} +.page-404__logo::before { + float: left; + padding-bottom: 100%; + content: ""; +} +.page-404__beam { + position: absolute; + left: -50%; + top: -50%; + width: 587px; + height: 636px; + z-index: -1; +} +.heavy { + font-size: 14px; + font-weight: bold; +} + </style> +</head> +<body> +<script type="text/javascript"> +function getUrlParams(url) { + + var queryString = url ? url.split('?')[1] : window.location.search.slice(1); + var obj = {}; + + if (queryString) { + queryString = queryString.split('#')[0]; + + var arr = queryString.split('&'); + + for (var i = 0; i < arr.length; i++) { + var a = arr[i].split('='); + + var paramName = a[0]; + var paramValue = typeof (a[1]) === 'undefined' ? true : a[1]; + + paramName = paramName.toLowerCase(); + if (typeof paramValue === 'string') paramValue = paramValue.toLowerCase(); + + if (!obj[paramName]) { + obj[paramName] = paramValue; + } + } + } + return obj; +} +window.onload = function() { + document.getElementById("version").textContent = getUrlParams()['v'] +} +</script> + +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" + style="position: absolute; width: 0; height: 0" id="__SVG_SPRITE_NODE__"> + <symbol xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 64 64" id="404"> + <g> + <rect y="0" width="64" height="64"></rect> + <rect x="5.9" y="52" fill="#fff" width="24" height="4"></rect> + <text x="5" y="20" fill="#fff" class="heavy">NOT</text> + <text x="5" y="35" fill="#fff" class="heavy">FOUND</text> + </g> + </symbol> + <symbol xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="183 -134 978 1061" + id="page-404-beam"> + <g style="opacity:0.49;"> + <path style="fill-opacity:0;stroke:#D9D9D9;stroke-dasharray:10,3;" + d="M1117.5,424.5l-535-476l87,449L1117.5,424.5z"></path> + <path style="fill-opacity:0;stroke:#E1E1E1;stroke-dasharray:10,3;" + d="M1118.3,465.9c-23.3,0-42.2-18.9-42.2-42.2 s18.9-42.2,42.2-42.2c23.3,0,42.2,18.9,42.2,42.2S1141.6,465.9,1118.3,465.9z M583.6,34.4c-46.3,0-83.9-37.6-83.9-83.9 s37.6-83.9,83.9-83.9s83.9,37.6,83.9,83.9S630,34.4,583.6,34.4z M536.2,841.7c0,46.8-37.9,84.8-84.7,84.8s-84.7-37.9-84.7-84.8 s37.9-84.8,84.7-84.8S536.2,794.9,536.2,841.7z M273.9,263.1c-49.9,0-90.4-40.5-90.4-90.4s40.5-90.4,90.4-90.4s90.4,40.5,90.4,90.4 S323.8,263.1,273.9,263.1z"></path> + <path style="fill:#FFFFFF;fill-opacity:0;stroke:#CCCCCC;stroke-linejoin:round;" + d="M1138.3,460.8L494,916l-0.4-0.7 c-12.4,7.1-26.8,11.2-42.2,11.2c-46.8,0-84.8-37.9-84.8-84.8c0-34.5,20.6-64.1,50.2-77.4l638.2-348l-470.3-382L417,173.1 l222.9,172.2c13.4,5.4,22.8,18.5,22.8,33.8c0,20.2-16.3,36.5-36.5,36.5c-9.8,0-18.6-3.8-25.2-10.1L242.9,257.6 c-2.2-0.8-4.3-1.7-6.3-2.6l-2-0.8l0-0.1c-30.2-14.6-51.1-45.6-51.1-81.4c0-28.6,13.3-54.1,34.1-70.7l0-0.3l321.1-222.2l0.2,0 c13-8.2,28.3-13,44.8-13c25.1,0,47.7,11.1,63,28.6l497.7,495.4c9.8,7.7,16.2,19.7,16.2,33.2 C1160.5,439.7,1151.5,453.7,1138.3,460.8z"></path> + <path style="fill-opacity:0;stroke:#D9D9D9;stroke-dasharray:10,3;" + d="M451.5,849.5l219-452l-398-223L451.5,849.5z"></path> + <g> + <path style="fill:#CDCDCD;" + d="M608.5,58.4l-5.7-5.1l-3.1,6.9l-0.7-0.6l3.1-6.9l-0.1-0.1l0.4-0.8l6.5,5.8L608.5,58.4z"></path> + <path style="fill:#CDCDCD;" + d="M353.8,220.4l3.1,6.9l-0.9,0.1l-3.1-6.9l-0.2,0l-0.4-0.8l8.6-1l0.4,0.8L353.8,220.4z"></path> + <path style="fill:#CDCDCD;" + d="M1041.4,418.5l-7.2,4.9l-0.7-0.5l6.3-4.3l-6-4.7l0.8-0.5l6,4.7l0.1-0.1L1041.4,418.5z"></path> + <path style="fill:#CDCDCD;" + d="M528.6,699.3l-6.9,3.1l0,0.2l-0.8,0.4l-1-8.6l0.8-0.4l0.8,7.6l6.9-3.1L528.6,699.3z"></path> + </g> + </g> + </symbol> +</svg> +<div class="wt-container article-content"> + <div class="wt-row wt-row_size_m wt-row_justify_center"> + <div class="wt-col-3"> + <div class="page-404__logo"> + <svg class="sprite-img _404"> + <use xlink:href="#404"></use> + </svg> + <svg class="page-404__beam"> + <use xlink:href="#page-404-beam"></use> + </svg> + </div> + </div> + <div class="wt-col-5"> + <h1 class="_big">uh-oh!</h1> + <div class="sub-title margin-top-vertical-unit-half">You are requesting a page that not + available in documentation version <span id="version"></span> + </div> + </div> + </div> +</div> +</body> +</html>
\ No newline at end of file diff --git a/plugins/versioning/src/main/resources/dokka/styles/multimodule.css b/plugins/versioning/src/main/resources/dokka/styles/multimodule.css index 4334d759..541e2eb9 100644 --- a/plugins/versioning/src/main/resources/dokka/styles/multimodule.css +++ b/plugins/versioning/src/main/resources/dokka/styles/multimodule.css @@ -8,28 +8,46 @@ padding: 5px; } -.versions-dropdown-button:hover, -.versions-dropdown-button:focus { - background-color: #f1f1f1; +.versions-dropdown-button::after { + content: ''; + -webkit-mask: url("../images/arrow_down.svg") no-repeat 50% 50%; + mask: url("../images/arrow_down.svg") no-repeat 50% 50%; + mask-size: auto; + -webkit-mask-size: cover; + mask-size: cover; + background-color: #fff; + display: inline-block; + position: relative; + top: 2px; + transform: rotate(90deg); + width: 24px; + height: 16px; } .versions-dropdown-data { display: none; position: absolute; - background-color: #f1f1f1; + background-color: #27282c; + border-style: solid; + border-width: 1px; + border-color: hsla(0,0%,100%,.6); box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); z-index: 1; + overflow-y: auto; + max-height: 200px; + min-width: 50px; + } .versions-dropdown-data a { padding: 5px; + padding-right: 18px; text-decoration: none; display: block; - color: black; } .versions-dropdown-data a:hover { - background-color: #ddd + background-color: hsla(0,0%,100%,.1) } .versions-dropdown:hover .versions-dropdown-data { |