aboutsummaryrefslogtreecommitdiff
path: root/dokka-subprojects/plugin-versioning
diff options
context:
space:
mode:
authorIgnat Beresnev <ignat.beresnev@jetbrains.com>2023-11-10 11:46:54 +0100
committerGitHub <noreply@github.com>2023-11-10 11:46:54 +0100
commit8e5c63d035ef44a269b8c43430f43f5c8eebfb63 (patch)
tree1b915207b2b9f61951ddbf0ff2e687efd053d555 /dokka-subprojects/plugin-versioning
parenta44efd4ba0c2e4ab921ff75e0f53fc9335aa79db (diff)
downloaddokka-8e5c63d035ef44a269b8c43430f43f5c8eebfb63.tar.gz
dokka-8e5c63d035ef44a269b8c43430f43f5c8eebfb63.tar.bz2
dokka-8e5c63d035ef44a269b8c43430f43f5c8eebfb63.zip
Restructure the project to utilize included builds (#3174)
* Refactor and simplify artifact publishing * Update Gradle to 8.4 * Refactor and simplify convention plugins and build scripts Fixes #3132 --------- Co-authored-by: Adam <897017+aSemy@users.noreply.github.com> Co-authored-by: Oleg Yukhnevich <whyoleg@gmail.com>
Diffstat (limited to 'dokka-subprojects/plugin-versioning')
-rw-r--r--dokka-subprojects/plugin-versioning/README.md332
-rw-r--r--dokka-subprojects/plugin-versioning/api/plugin-versioning.api149
-rw-r--r--dokka-subprojects/plugin-versioning/build.gradle.kts33
-rw-r--r--dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt60
-rw-r--r--dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionCommandConsumer.kt54
-rw-r--r--dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionsCommand.kt29
-rw-r--r--dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningConfiguration.kt38
-rw-r--r--dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningPlugin.kt70
-rw-r--r--dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningStorage.kt72
-rw-r--r--dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsNavigationCreator.kt91
-rw-r--r--dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsOrdering.kt26
-rw-r--r--dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/htmlPreprocessors.kt46
-rw-r--r--dokka-subprojects/plugin-versioning/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin5
-rw-r--r--dokka-subprojects/plugin-versioning/src/main/resources/dokka/not-found-version.html193
-rw-r--r--dokka-subprojects/plugin-versioning/src/main/resources/dokka/styles/multimodule.css55
-rw-r--r--dokka-subprojects/plugin-versioning/versioning-plugin-example.pngbin0 -> 43684 bytes
16 files changed, 1253 insertions, 0 deletions
diff --git a/dokka-subprojects/plugin-versioning/README.md b/dokka-subprojects/plugin-versioning/README.md
new file mode 100644
index 00000000..d501a58f
--- /dev/null
+++ b/dokka-subprojects/plugin-versioning/README.md
@@ -0,0 +1,332 @@
+# Versioning plugin
+
+The versioning plugin provides the ability to host documentation for multiple versions of your library/application
+with seamless switching between them. This, in turn, provides a better experience for your users.
+
+![Screenshot of documentation version dropdown](versioning-plugin-example.png)
+
+**Note:** The versioning plugin only works with Dokka's HTML format.
+
+Visit the [versioning plugin example project](../../examples/gradle/dokka-versioning-multimodule-example)
+to see an example of it in action and how it can be configured.
+
+## Applying the plugin
+
+You can apply the versioning plugin the same way as other Dokka plugins:
+
+<details open>
+<summary>Kotlin</summary>
+
+```kotlin
+dependencies {
+ dokkaHtmlPlugin("org.jetbrains.dokka:versioning-plugin:1.9.10")
+}
+```
+
+**Note:** When documenting multi-project builds, you need to apply the versioning
+plugin within subprojects as well as in their parent project.
+
+</details>
+
+<details>
+<summary>Groovy</summary>
+
+```groovy
+dependencies {
+ dokkaHtmlPlugin 'org.jetbrains.dokka:versioning-plugin:1.9.10'
+}
+```
+
+**Note:** When documenting multi-project builds, you need to apply the versioning
+plugin within subprojects as well as in their parent project.
+
+</details>
+
+<details>
+<summary>Maven</summary>
+
+```xml
+<plugin>
+ <groupId>org.jetbrains.dokka</groupId>
+ <artifactId>dokka-maven-plugin</artifactId>
+ ...
+ <configuration>
+ <dokkaPlugins>
+ <plugin>
+ <groupId>org.jetbrains.dokka</groupId>
+ <artifactId>versioning-plugin</artifactId>
+ <version>1.9.10</version>
+ </plugin>
+ </dokkaPlugins>
+ </configuration>
+</plugin>
+```
+
+</details>
+
+<details>
+<summary>CLI</summary>
+
+You can find the versioning plugin's artifact on
+[mvnrepository](https://mvnrepository.com/artifact/org.jetbrains.dokka/versioning-plugin/1.9.10) or by browsing
+[maven central repository](https://repo1.maven.org/maven2/org/jetbrains/dokka/versioning-plugin/1.9.10)
+directly, and pass it to `pluginsClasspath`.
+
+Via command line arguments:
+
+```Bash
+java -jar dokka-cli-1.9.10.jar \
+ -pluginsClasspath "./dokka-base-1.9.10.jar;...;./versioning-plugin-1.9.10.jar" \
+ ...
+```
+
+Via JSON configuration:
+
+```json
+{
+ ...
+ "pluginsClasspath": [
+ "./dokka-base-1.9.10.jar",
+ "...",
+ "./versioning-plugin-1.9.10.jar"
+ ],
+ ...
+}
+```
+
+</details>
+
+## Configuration
+
+### Configuration options
+
+The table below contains all the possible configuration options for the versioning plugin and their purpose.
+
+| **Option** | **Description** |
+|--------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `version` | The version of your application/library that documentation is going to be generated for. This will be the version shown in the dropdown menu. |
+| `versionsOrdering` | An optional list of strings that represents the order that versions should appear in the dropdown menu. Must match `version` string exactly. The first item in the list is at the top of the dropdown. |
+| `olderVersionsDir` | An optional path to a parent folder that contains other documentation versions. It requires a specific directory structure. For more information, see [Directory structure](#directory-structure). |
+| `olderVersions` | An optional list of paths to other documentation versions. It must point to Dokka's outputs directly. This is useful if different versions can't all be in the same directory. |
+| `renderVersionsNavigationOnAllPages` | An optional boolean value indicating whether to render the navigation dropdown on all pages. Set to true by default. |
+
+#### Directory structure
+
+Note that the directory passed to `olderVersionsDir` needs to follow a specific structure:
+
+```text
+.
+└── olderVersionsDir
+ └── 1.7.10
+ ├── <dokka output>
+ └── 1.7.20
+ ├── <dokka output>
+...
+```
+
+### Configuration example
+
+<details open>
+<summary>Kotlin</summary>
+
+```kotlin
+import org.jetbrains.dokka.versioning.VersioningPlugin
+import org.jetbrains.dokka.versioning.VersioningConfiguration
+
+buildscript {
+ dependencies {
+ classpath("org.jetbrains.dokka:versioning-plugin:1.9.10")
+ }
+}
+
+tasks.dokkaHtml {
+ pluginConfiguration<VersioningPlugin, VersioningConfiguration> {
+ version = "1.5"
+ versionsOrdering = listOf("1.5", "1.4", "1.3", "1.2", "1.1", "alpha-2", "alpha-1")
+ olderVersionsDir = file("documentation/version")
+ olderVersions = listOf(file("documentation/alpha/alpha-2"), file("documentation/alpha/alpha-1"))
+ renderVersionsNavigationOnAllPages = true
+ }
+}
+```
+
+Alternatively, you can configure it via JSON:
+
+```kotlin
+ val versioningConfiguration = """
+ {
+ "version": "1.5",
+ "versionsOrdering": ["1.5", "1.4", "1.3", "1.2", "1.1", "alpha-2", "alpha-1"],
+ "olderVersionsDir": "documentation/version",
+ "olderVersions": ["documentation/alpha/alpha-2", "documentation/alpha/alpha-1"],
+ "renderVersionsNavigationOnAllPages": true
+ }
+ """
+ pluginsMapConfiguration.set(
+ mapOf(
+ "org.jetbrains.dokka.versioning.VersioningPlugin" to versioningConfiguration
+ )
+ )
+```
+
+</details>
+
+<details>
+<summary>Groovy</summary>
+
+```groovy
+dokkaHtml {
+ String versioningConfiguration = """
+ {
+ "version": "1.5",
+ "versionsOrdering": ["1.5", "1.4", "1.3", "1.2", "1.1", "alpha-2", "alpha-1"],
+ "olderVersionsDir": "documentation/version",
+ "olderVersions": ["documentation/alpha/alpha-2", "documentation/alpha/alpha-1"],
+ "renderVersionsNavigationOnAllPages": true
+ }
+ """
+ pluginsMapConfiguration.set(
+ ["org.jetbrains.dokka.versioning.VersioningPlugin": versioningConfiguration]
+ )
+}
+```
+
+</details>
+
+<details>
+<summary>Maven</summary>
+
+```xml
+<plugin>
+ <groupId>org.jetbrains.dokka</groupId>
+ <artifactId>dokka-maven-plugin</artifactId>
+ ...
+ <configuration>
+ <pluginsConfiguration>
+ <org.jetbrains.dokka.versioning.VersioningPlugin>
+ <version>1.5</version>
+ <versionsOrdering>
+ <version>1.5</version>
+ <version>1.4</version>
+ <version>1.3</version>
+ <version>1.2</version>
+ <version>1.1</version>
+ <version>alpha-2</version>
+ <version>alpha-1</version>
+ </versionsOrdering>
+ <olderVersionsDir>${project.basedir}/documentation/version</olderVersionsDir>
+ <olderVersions>
+ <version>${project.basedir}/documentation/alpha/alpha-2</version>
+ <version>${project.basedir}/documentation/alpha/alpha-1</version>
+ </olderVersions>
+ <renderVersionsNavigationOnAllPages>true</renderVersionsNavigationOnAllPages>
+ </org.jetbrains.dokka.versioning.VersioningPlugin>
+ </pluginsConfiguration>
+ </configuration>
+</plugin>
+```
+
+</details>
+
+<details>
+<summary>CLI</summary>
+
+```Bash
+java -jar dokka-cli-1.9.10.jar \
+ ...
+ -pluginsConfiguration "org.jetbrains.dokka.versioning.VersioningPlugin={\"version\": \"1.5\", \"versionsOrdering\": [\"1.5\", \"1.4\", \"1.3\", \"1.2\", \"1.1\", \"alpha-2\", \"alpha-1\"], \"olderVersionsDir\": \"documentation/version\", \"olderVersions\": [\"documentation/alpha/alpha-2\", \"documentation/alpha/alpha-1\"], \"renderVersionsNavigationOnAllPages\": true}"
+
+```
+
+Alternatively, via JSON configuration:
+```json
+{
+ "moduleName": "Dokka Example",
+ ...
+ "pluginsConfiguration": [
+ {
+ "fqPluginName": "org.jetbrains.dokka.versioning.VersioningPlugin",
+ "serializationFormat": "JSON",
+ "values": "{\"version\": \"1.5\", \"versionsOrdering\": [\"1.5\", \"1.4\", \"1.3\", \"1.2\", \"1.1\", \"alpha-2\", \"alpha-1\"], \"olderVersionsDir\": \"documentation/version\", \"olderVersions\": [\"documentation/alpha/alpha-2\", \"documentation/alpha/alpha-1\"], \"renderVersionsNavigationOnAllPages\": true}"
+ }
+ ]
+}
+```
+
+</details>
+
+## Generating versioned documentation
+
+With the versioning plugin applied and configured, no other steps are needed. Documentation can be built in the usual way.
+
+Among other things, the versioning plugin adds a `version.json` file to the output folder. This file is used by the
+plugin to match versions and generate version navigation. If your previously generated documentation does not have that
+file, you will need to re-generate documentation for such versions. Just adding the file will not work.
+
+The versioning plugin also bundles all other documentation versions that have been passed through `olderVersionsDir`
+and `olderVersions` configuration options by putting them inside the `older` directory.
+
+## Usage example
+
+There is no single correct way to configure the plugin, it can be tailored to your needs. However,
+it can be a bit overwhelming when starting out. Below you will find one of the ways it can be configured so that you
+can begin publishing versioned documentation straight away.
+
+The main idea behind it is the following:
+
+1. One directory contains all versions of your documentation. For example, `documentation/version/{doc_version}`.
+ This is your archive which is needed for future builds.
+2. The output directory of all new builds is set to that directory as well, under `documentation/version/{new_version}`.
+3. When new builds are executed, the plugin looks for previous versions of documentation in the archive directory.
+4. Once new documentation has been generated, it needs to be **copied** to somewhere accessible by the user.
+ For example, GitHub pages or nginx static directories. It needs to be **copied**, not moved because Dokka will still
+ need this version for future builds, otherwise there will be a gap in the archive.
+5. Once it has been safely copied, you can remove the `older` directory from the newly generated and archived version.
+ This helps reduce the overhead of each version bundling all previous versions, as these files are effectively duplicates.
+
+```kotlin
+import org.jetbrains.dokka.versioning.VersioningPlugin
+import org.jetbrains.dokka.versioning.VersioningConfiguration
+
+buildscript {
+ dependencies {
+ classpath("org.jetbrains.dokka:versioning-plugin:1.9.10")
+ }
+}
+
+dependencies {
+ dokkaPlugin("org.jetbrains.dokka:versioning-plugin:1.9.10")
+}
+
+tasks.dokkaHtml {
+ // This can be any persistent folder where
+ // you store documentation by version
+ val docVersionsDir = projectDir.resolve("documentation/version")
+
+ // The version for which you are currently generating docs
+ val currentVersion = "1.3"
+
+ // Set the output to a folder with all other versions
+ // as you'll need the current version for future builds
+ val currentDocsDir = docVersionsDir.resolve(currentVersion)
+ outputDirectory.set(currentDocsDir)
+
+ pluginConfiguration<VersioningPlugin, VersioningConfiguration> {
+ olderVersionsDir = docVersionsDir
+ version = currentVersion
+ }
+
+ doLast {
+ // This folder contains the latest documentation with all
+ // previous versions included, so it's ready to be published.
+ // Make sure it's copied and not moved - you'll still need this
+ // version for future builds
+ currentDocsDir.copyTo(file("/my/hosting"))
+
+ // Only once current documentation has been safely moved,
+ // remove previous versions bundled in it. They will not
+ // be needed in future builds, it's just overhead.
+ currentDocsDir.resolve("older").deleteRecursively()
+ }
+}
+```
diff --git a/dokka-subprojects/plugin-versioning/api/plugin-versioning.api b/dokka-subprojects/plugin-versioning/api/plugin-versioning.api
new file mode 100644
index 00000000..6ba2c822
--- /dev/null
+++ b/dokka-subprojects/plugin-versioning/api/plugin-versioning.api
@@ -0,0 +1,149 @@
+public final class org/jetbrains/dokka/versioning/ByConfigurationVersionOrdering : org/jetbrains/dokka/versioning/VersionsOrdering {
+ public fun <init> (Lorg/jetbrains/dokka/plugability/DokkaContext;)V
+ public final fun getDokkaContext ()Lorg/jetbrains/dokka/plugability/DokkaContext;
+ public fun order (Ljava/util/List;)Ljava/util/List;
+}
+
+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 synthetic fun invoke ()Ljava/lang/Object;
+ public fun invoke ()V
+}
+
+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 fun invoke (Ljava/io/File;)Ljava/lang/String;
+}
+
+public final class org/jetbrains/dokka/versioning/MultiModuleStylesInstaller : 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;
+}
+
+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;
+}
+
+public final class org/jetbrains/dokka/versioning/ReplaceVersionCommandConsumer : 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/versioning/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 final fun getVersionsNavigationCreator ()Lorg/jetbrains/dokka/versioning/VersionsNavigationCreator;
+ public fun handleCommand (Lorg/jsoup/nodes/Element;Lorg/jetbrains/dokka/base/templating/Command;Ljava/io/File;Ljava/io/File;)V
+ public fun handleCommandAsComment (Lorg/jetbrains/dokka/base/templating/Command;Ljava/util/List;Ljava/io/File;Ljava/io/File;)V
+ public fun handleCommandAsTag (Lorg/jetbrains/dokka/base/templating/Command;Lorg/jsoup/nodes/Element;Ljava/io/File;Ljava/io/File;)V
+}
+
+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;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 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;
+}
+
+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/String;
+ public final fun getDefaultVersionsOrdering ()Ljava/util/List;
+}
+
+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 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 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/io/File;)Ljava/lang/String;
+}
+
+public abstract interface class org/jetbrains/dokka/versioning/VersionsOrdering {
+ public abstract fun order (Ljava/util/List;)Ljava/util/List;
+}
+
diff --git a/dokka-subprojects/plugin-versioning/build.gradle.kts b/dokka-subprojects/plugin-versioning/build.gradle.kts
new file mode 100644
index 00000000..941661bd
--- /dev/null
+++ b/dokka-subprojects/plugin-versioning/build.gradle.kts
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+import dokkabuild.overridePublicationArtifactId
+
+plugins {
+ id("dokkabuild.kotlin-jvm")
+ id("dokkabuild.publish-jvm")
+}
+
+overridePublicationArtifactId("versioning-plugin")
+
+dependencies {
+ compileOnly(projects.dokkaSubprojects.dokkaCore)
+
+ implementation(projects.dokkaSubprojects.pluginBase)
+ implementation(projects.dokkaSubprojects.pluginTemplating)
+
+ implementation(kotlin("reflect"))
+ implementation(libs.kotlinx.coroutines.core)
+ implementation(libs.kotlinx.html)
+ implementation(libs.apacheMaven.artifact)
+ implementation(libs.jackson.kotlin)
+ constraints {
+ implementation(libs.jackson.databind) {
+ because("CVE-2022-42003")
+ }
+ }
+
+ testImplementation(kotlin("test"))
+ testImplementation(projects.dokkaSubprojects.coreTestApi)
+}
diff --git a/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt
new file mode 100644
index 00000000..7e03f59c
--- /dev/null
+++ b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+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.plugability.DokkaContext
+import org.jetbrains.dokka.plugability.plugin
+import org.jetbrains.dokka.plugability.query
+import org.jetbrains.dokka.plugability.querySingle
+import org.jetbrains.dokka.renderers.PostAction
+import org.jetbrains.dokka.templates.TemplateProcessingStrategy
+import org.jetbrains.dokka.templates.TemplatingPlugin
+import java.io.File
+
+public 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)
+ }
+ }
+}
diff --git a/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionCommandConsumer.kt b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionCommandConsumer.kt
new file mode 100644
index 00000000..b31afb9a
--- /dev/null
+++ b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionCommandConsumer.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.versioning
+
+import kotlinx.html.unsafe
+import kotlinx.html.visit
+import kotlinx.html.visitAndFinalize
+import org.jetbrains.dokka.base.renderers.html.TemplateBlock
+import org.jetbrains.dokka.base.renderers.html.command.consumers.ImmediateResolutionTagConsumer
+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
+
+public class ReplaceVersionCommandConsumer(context: DokkaContext) : ImmediateHtmlCommandConsumer {
+
+ private val versionsNavigationCreator =
+ context.plugin<VersioningPlugin>().querySingle { versionsNavigationCreator }
+ private val versioningStorage =
+ context.plugin<VersioningPlugin>().querySingle { versioningStorage }
+
+ override fun canProcess(command: Command): Boolean = command is ReplaceVersionsCommand
+
+ override fun <R> processCommand(
+ command: Command,
+ block: TemplateBlock,
+ tagConsumer: ImmediateResolutionTagConsumer<R>
+ ) {
+ command as ReplaceVersionsCommand
+ templateCommandFor(command, tagConsumer).visit {
+ unsafe {
+ +versionsNavigationCreator(versioningStorage.currentVersion.dir.resolve(command.location))
+ }
+ }
+ }
+
+ override fun <R> processCommandAndFinalize(
+ command: Command,
+ block: TemplateBlock,
+ tagConsumer: ImmediateResolutionTagConsumer<R>
+ ): R {
+ command as ReplaceVersionsCommand
+ return templateCommandFor(command, tagConsumer).visitAndFinalize(tagConsumer) {
+ unsafe {
+ +versionsNavigationCreator(versioningStorage.currentVersion.dir.resolve(command.location))
+ }
+ }
+ }
+}
diff --git a/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionsCommand.kt b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionsCommand.kt
new file mode 100644
index 00000000..c9bc57b2
--- /dev/null
+++ b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionsCommand.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+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
+import org.jetbrains.dokka.templates.CommandHandler
+import org.jsoup.nodes.Element
+import java.io.File
+
+public class ReplaceVersionCommandHandler(context: DokkaContext) : CommandHandler {
+
+ public val versionsNavigationCreator: VersionsNavigationCreator by lazy {
+ context.plugin<VersioningPlugin>().querySingle { versionsNavigationCreator }
+ }
+
+ override fun canHandle(command: Command): Boolean = command is ReplaceVersionsCommand
+
+ override fun handleCommandAsTag(command: Command, body: Element, input: File, output: File) {
+ body.empty()
+ body.append(versionsNavigationCreator(output))
+ }
+}
diff --git a/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningConfiguration.kt b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningConfiguration.kt
new file mode 100644
index 00000000..91b1117d
--- /dev/null
+++ b/dokka-subprojects/plugin-versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningConfiguration.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package org.jetbrains.dokka.versioning
+
+import org.jetbrains.dokka.plugability.ConfigurableBlock
+import org.jetbrains.dokka.plugability.DokkaContext
+import java.io.File
+
+public data class VersioningConfiguration(
+ var olderVersionsDir: File? = defaultOlderVersionsDir,
+ 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"
+
+ internal fun allOlderVersions(): List<File> {
+ if (olderVersionsDir != null)
+ assert(olderVersionsDir!!.isDirectory) { "Supplied previous version $olderVersionsDir is not a directory!" }