From 8c218ff4dd5f970233c43845c19299fc74256389 Mon Sep 17 00:00:00 2001 From: Ignat Beresnev Date: Fri, 29 Apr 2022 15:03:08 +0300 Subject: Enable warnings as errors and fix all warnings (#2451) * Enable warnings as errors and fix all warnings * Enable skip-metadata-version-check compiler setting --- .../DefaultPreviousDocumentationCopyPostAction.kt | 54 ++++++++++++++ .../versioning/ReplaceVersionCommandConsumer.kt | 50 +++++++++++++ .../dokka/versioning/ReplaceVersionsCommand.kt | 25 +++++++ .../dokka/versioning/VersioningConfiguration.kt | 34 +++++++++ .../jetbrains/dokka/versioning/VersioningPlugin.kt | 52 +++++++++++++ .../dokka/versioning/VersioningStorage.kt | 65 ++++++++++++++++ .../dokka/versioning/VersionsNavigationCreator.kt | 86 ++++++++++++++++++++++ .../jetbrains/dokka/versioning/VersionsOrdering.kt | 23 ++++++ .../dokka/versioning/htmlPreprocessors.kt | 38 ++++++++++ .../DefaultPreviousDocumentationCopyPostAction.kt | 54 -------------- .../versioning/ReplaceVersionCommandConsumer.kt | 50 ------------- .../kotlin/versioning/ReplaceVersionsCommand.kt | 25 ------- .../kotlin/versioning/VersioningConfiguration.kt | 34 --------- .../src/main/kotlin/versioning/VersioningPlugin.kt | 52 ------------- .../main/kotlin/versioning/VersioningStorage.kt | 65 ---------------- .../kotlin/versioning/VersionsNavigationCreator.kt | 86 ---------------------- .../src/main/kotlin/versioning/VersionsOrdering.kt | 23 ------ .../main/kotlin/versioning/htmlPreprocessors.kt | 38 ---------- 18 files changed, 427 insertions(+), 427 deletions(-) create mode 100644 plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt create mode 100644 plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionCommandConsumer.kt create mode 100644 plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionsCommand.kt create mode 100644 plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningConfiguration.kt create mode 100644 plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningPlugin.kt create mode 100644 plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningStorage.kt create mode 100644 plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsNavigationCreator.kt create mode 100644 plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsOrdering.kt create mode 100644 plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/htmlPreprocessors.kt delete mode 100644 plugins/versioning/src/main/kotlin/versioning/DefaultPreviousDocumentationCopyPostAction.kt delete mode 100644 plugins/versioning/src/main/kotlin/versioning/ReplaceVersionCommandConsumer.kt delete mode 100644 plugins/versioning/src/main/kotlin/versioning/ReplaceVersionsCommand.kt delete mode 100644 plugins/versioning/src/main/kotlin/versioning/VersioningConfiguration.kt delete mode 100644 plugins/versioning/src/main/kotlin/versioning/VersioningPlugin.kt delete mode 100644 plugins/versioning/src/main/kotlin/versioning/VersioningStorage.kt delete mode 100644 plugins/versioning/src/main/kotlin/versioning/VersionsNavigationCreator.kt delete mode 100644 plugins/versioning/src/main/kotlin/versioning/VersionsOrdering.kt delete mode 100644 plugins/versioning/src/main/kotlin/versioning/htmlPreprocessors.kt (limited to 'plugins/versioning/src') diff --git a/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/DefaultPreviousDocumentationCopyPostAction.kt new file mode 100644 index 00000000..6ab81d31 --- /dev/null +++ b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/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().querySingle { versioningStorage } } + private val processingStrategies: List = + context.plugin().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/org/jetbrains/dokka/versioning/ReplaceVersionCommandConsumer.kt b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionCommandConsumer.kt new file mode 100644 index 00000000..ea524c52 --- /dev/null +++ b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionCommandConsumer.kt @@ -0,0 +1,50 @@ +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 + +class ReplaceVersionCommandConsumer(context: DokkaContext) : ImmediateHtmlCommandConsumer { + + private val versionsNavigationCreator = + context.plugin().querySingle { versionsNavigationCreator } + private val versioningStorage = + context.plugin().querySingle { versioningStorage } + + override fun canProcess(command: Command) = command is ReplaceVersionsCommand + + override fun processCommand( + command: Command, + block: TemplateBlock, + tagConsumer: ImmediateResolutionTagConsumer + ) { + command as ReplaceVersionsCommand + templateCommandFor(command, tagConsumer).visit { + unsafe { + +versionsNavigationCreator(versioningStorage.currentVersion.dir.resolve(command.location)) + } + } + } + + override fun processCommandAndFinalize( + command: Command, + block: TemplateBlock, + tagConsumer: ImmediateResolutionTagConsumer + ): R { + command as ReplaceVersionsCommand + return templateCommandFor(command, tagConsumer).visitAndFinalize(tagConsumer) { + unsafe { + +versionsNavigationCreator(versioningStorage.currentVersion.dir.resolve(command.location)) + } + } + } +} \ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionsCommand.kt b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionsCommand.kt new file mode 100644 index 00000000..66dd9860 --- /dev/null +++ b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/ReplaceVersionsCommand.kt @@ -0,0 +1,25 @@ +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 + +class ReplaceVersionCommandHandler(context: DokkaContext) : CommandHandler { + + val versionsNavigationCreator by lazy { + context.plugin().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)) + } +} \ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningConfiguration.kt b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningConfiguration.kt new file mode 100644 index 00000000..56c72257 --- /dev/null +++ b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningConfiguration.kt @@ -0,0 +1,34 @@ +package org.jetbrains.dokka.versioning + +import org.jetbrains.dokka.plugability.ConfigurableBlock +import org.jetbrains.dokka.plugability.DokkaContext +import java.io.File + +data class VersioningConfiguration( + var olderVersionsDir: File? = defaultOlderVersionsDir, + var olderVersions: List? = defaultOlderVersions, + var versionsOrdering: List? = 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 { + if (olderVersionsDir != null) + assert(olderVersionsDir!!.isDirectory) { "Supplied previous version $olderVersionsDir is not a directory!" } + + return olderVersionsDir?.listFiles()?.toList().orEmpty() + olderVersions.orEmpty() + } + + companion object { + val defaultOlderVersionsDir: File? = null + val defaultOlderVersions: List? = null + val defaultVersionsOrdering: List? = 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/org/jetbrains/dokka/versioning/VersioningPlugin.kt b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningPlugin.kt new file mode 100644 index 00000000..e4e8bbae --- /dev/null +++ b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningPlugin.kt @@ -0,0 +1,52 @@ +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 +import org.jetbrains.dokka.templates.TemplatingPlugin + +class VersioningPlugin : DokkaPlugin() { + + val versioningStorage by extensionPoint() + val versionsNavigationCreator by extensionPoint() + val versionsOrdering by extensionPoint() + + private val dokkaBase by lazy { plugin() } + private val templatingPlugin by lazy { plugin() } + + val defaultVersioningStorage by extending { + versioningStorage providing ::DefaultVersioningStorage + } + val defaultVersioningNavigationCreator by extending { + versionsNavigationCreator providing ::HtmlVersionsNavigationCreator + } + val replaceVersionCommandHandler by extending { + templatingPlugin.directiveBasedCommandHandlers providing ::ReplaceVersionCommandHandler override templatingPlugin.replaceVersionCommandHandler + } + val resolveLinkConsumer by extending { + dokkaBase.immediateHtmlCommandConsumer providing ::ReplaceVersionCommandConsumer override dokkaBase.replaceVersionConsumer + } + val cssStyleInstaller by extending { + 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 -> + configuration(ctx)?.versionsOrdering?.let { + ByConfigurationVersionOrdering(ctx) + } ?: SemVerVersionOrdering() + } + } + val previousDocumentationCopyPostAction by extending { + postActions providing ::DefaultPreviousDocumentationCopyPostAction applyIf { !delayTemplateSubstitution } + } +} \ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningStorage.kt b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersioningStorage.kt new file mode 100644 index 00000000..6e1dd7ca --- /dev/null +++ b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/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 + val currentVersion: CurrentVersion + fun createVersionFile() +} + +typealias VersionId = String + +class DefaultVersioningStorage(val context: DokkaContext) : VersioningStorage { + + private val mapper = ObjectMapper() + private val configuration = configuration(context) + + override val previousVersions: Map 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, output: File): Map = + versionsFrom(olderVersions).associate { (key, srcDir) -> + key to VersionDirs(srcDir, output.resolve(VersioningConfiguration.OLDER_VERSIONS_DIR).resolve(key)) + } + + private fun versionsFrom(olderVersions: List) = + olderVersions.mapNotNull { versionDir -> + versionDir.listFiles { _, name -> name == VersioningConfiguration.VERSIONS_FILE }?.firstOrNull() + ?.let { file -> + val versionsContent = mapper.readValue(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/org/jetbrains/dokka/versioning/VersionsNavigationCreator.kt b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsNavigationCreator.kt new file mode 100644 index 00000000..719d2cf9 --- /dev/null +++ b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsNavigationCreator.kt @@ -0,0 +1,86 @@ +package org.jetbrains.dokka.versioning + +import kotlinx.html.a +import kotlinx.html.div +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 + +fun interface VersionsNavigationCreator { + operator fun invoke(output: File): String +} + +class HtmlVersionsNavigationCreator(private val context: DokkaContext) : VersionsNavigationCreator { + + private val versioningStorage by lazy { context.plugin().querySingle { versioningStorage } } + + private val versionsOrdering by lazy { context.plugin().querySingle { versionsOrdering } } + + private val isOnlyOnRootPage = + configuration(context)?.renderVersionsNavigationOnAllPages == false + + private val versions: Map 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 + 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 { orderedVersions -> + StringBuilder().appendHTML().div(classes = "versions-dropdown") { + 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") { + 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/org/jetbrains/dokka/versioning/VersionsOrdering.kt b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsOrdering.kt new file mode 100644 index 00000000..f72e2df6 --- /dev/null +++ b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/VersionsOrdering.kt @@ -0,0 +1,23 @@ +package org.jetbrains.dokka.versioning + +import org.apache.maven.artifact.versioning.ComparableVersion +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.configuration +import org.jetbrains.dokka.versioning.VersionId +import org.jetbrains.dokka.versioning.VersioningConfiguration +import org.jetbrains.dokka.versioning.VersioningPlugin + +fun interface VersionsOrdering { + fun order(records: List): List +} + +class ByConfigurationVersionOrdering(val dokkaContext: DokkaContext) : VersionsOrdering { + override fun order(records: List): List = + configuration(dokkaContext)?.versionsOrdering + ?: throw IllegalStateException("Attempted to use a configuration ordering without providing configuration") +} + +class SemVerVersionOrdering : VersionsOrdering { + override fun order(records: List): List = + records.map { it to ComparableVersion(it) }.sortedByDescending { it.second }.map { it.first } +} \ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/htmlPreprocessors.kt b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/htmlPreprocessors.kt new file mode 100644 index 00000000..94400898 --- /dev/null +++ b/plugins/versioning/src/main/kotlin/org/jetbrains/dokka/versioning/htmlPreprocessors.kt @@ -0,0 +1,38 @@ +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 + +class MultiModuleStylesInstaller(private val dokkaContext: DokkaContext) : PageTransformer { + private val stylesPages = listOf( + "styles/multimodule.css", + ) + + override fun invoke(input: RootPageNode): RootPageNode = + 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.toRenderSpecificResourcePage(): List = + map { RendererSpecificResourcePage(it, emptyList(), RenderingStrategy.Copy("/dokka/$it")) } diff --git a/plugins/versioning/src/main/kotlin/versioning/DefaultPreviousDocumentationCopyPostAction.kt b/plugins/versioning/src/main/kotlin/versioning/DefaultPreviousDocumentationCopyPostAction.kt deleted file mode 100644 index 6ab81d31..00000000 --- a/plugins/versioning/src/main/kotlin/versioning/DefaultPreviousDocumentationCopyPostAction.kt +++ /dev/null @@ -1,54 +0,0 @@ -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().querySingle { versioningStorage } } - private val processingStrategies: List = - context.plugin().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 deleted file mode 100644 index ea524c52..00000000 --- a/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionCommandConsumer.kt +++ /dev/null @@ -1,50 +0,0 @@ -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 - -class ReplaceVersionCommandConsumer(context: DokkaContext) : ImmediateHtmlCommandConsumer { - - private val versionsNavigationCreator = - context.plugin().querySingle { versionsNavigationCreator } - private val versioningStorage = - context.plugin().querySingle { versioningStorage } - - override fun canProcess(command: Command) = command is ReplaceVersionsCommand - - override fun processCommand( - command: Command, - block: TemplateBlock, - tagConsumer: ImmediateResolutionTagConsumer - ) { - command as ReplaceVersionsCommand - templateCommandFor(command, tagConsumer).visit { - unsafe { - +versionsNavigationCreator(versioningStorage.currentVersion.dir.resolve(command.location)) - } - } - } - - override fun processCommandAndFinalize( - command: Command, - block: TemplateBlock, - tagConsumer: ImmediateResolutionTagConsumer - ): R { - command as ReplaceVersionsCommand - return templateCommandFor(command, tagConsumer).visitAndFinalize(tagConsumer) { - unsafe { - +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 deleted file mode 100644 index ad1edd2b..00000000 --- a/plugins/versioning/src/main/kotlin/versioning/ReplaceVersionsCommand.kt +++ /dev/null @@ -1,25 +0,0 @@ -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 - -class ReplaceVersionCommandHandler(context: DokkaContext) : CommandHandler { - - val versionsNavigationCreator by lazy { - context.plugin().querySingle { versionsNavigationCreator } - } - - override fun canHandle(command: Command): Boolean = command is ReplaceVersionsCommand - - override fun handleCommandAsTag(command: Command, element: Element, input: File, output: File) { - element.empty() - element.append(versionsNavigationCreator(output)) - } -} \ No newline at end of file diff --git a/plugins/versioning/src/main/kotlin/versioning/VersioningConfiguration.kt b/plugins/versioning/src/main/kotlin/versioning/VersioningConfiguration.kt deleted file mode 100644 index 56c72257..00000000 --- a/plugins/versioning/src/main/kotlin/versioning/VersioningConfiguration.kt +++ /dev/null @@ -1,34 +0,0 @@ -package org.jetbrains.dokka.versioning - -import org.jetbrains.dokka.plugability.ConfigurableBlock -import org.jetbrains.dokka.plugability.DokkaContext -import java.io.File - -data class VersioningConfiguration( - var olderVersionsDir: File? = defaultOlderVersionsDir, - var olderVersions: List? = defaultOlderVersions, - var versionsOrdering: List? = 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 { - if (olderVersionsDir != null) - assert(olderVersionsDir!!.isDirectory) { "Supplied previous version $olderVersionsDir is not a directory!" } - - return olderVersionsDir?.listFiles()?.toList().orEmpty() + olderVersions.orEmpty() - } - - companion object { - val defaultOlderVersionsDir: File? = null - val defaultOlderVersions: List? = null - val defaultVersionsOrdering: List? = 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/VersioningPlugin.kt b/plugins/versioning/src/main/kotlin/versioning/VersioningPlugin.kt deleted file mode 100644 index e4e8bbae..00000000 --- a/plugins/versioning/src/main/kotlin/versioning/VersioningPlugin.kt +++ /dev/null @@ -1,52 +0,0 @@ -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 -import org.jetbrains.dokka.templates.TemplatingPlugin - -class VersioningPlugin : DokkaPlugin() { - - val versioningStorage by extensionPoint() - val versionsNavigationCreator by extensionPoint() - val versionsOrdering by extensionPoint() - - private val dokkaBase by lazy { plugin() } - private val templatingPlugin by lazy { plugin() } - - val defaultVersioningStorage by extending { - versioningStorage providing ::DefaultVersioningStorage - } - val defaultVersioningNavigationCreator by extending { - versionsNavigationCreator providing ::HtmlVersionsNavigationCreator - } - val replaceVersionCommandHandler by extending { - templatingPlugin.directiveBasedCommandHandlers providing ::ReplaceVersionCommandHandler override templatingPlugin.replaceVersionCommandHandler - } - val resolveLinkConsumer by extending { - dokkaBase.immediateHtmlCommandConsumer providing ::ReplaceVersionCommandConsumer override dokkaBase.replaceVersionConsumer - } - val cssStyleInstaller by extending { - 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 -> - configuration(ctx)?.versionsOrdering?.let { - ByConfigurationVersionOrdering(ctx) - } ?: 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 deleted file mode 100644 index 6e1dd7ca..00000000 --- a/plugins/versioning/src/main/kotlin/versioning/VersioningStorage.kt +++ /dev/null @@ -1,65 +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 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 - val currentVersion: CurrentVersion - fun createVersionFile() -} - -typealias VersionId = String - -class DefaultVersioningStorage(val context: DokkaContext) : VersioningStorage { - - private val mapper = ObjectMapper() - private val configuration = configuration(context) - - override val previousVersions: Map 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, output: File): Map = - versionsFrom(olderVersions).associate { (key, srcDir) -> - key to VersionDirs(srcDir, output.resolve(VersioningConfiguration.OLDER_VERSIONS_DIR).resolve(key)) - } - - private fun versionsFrom(olderVersions: List) = - olderVersions.mapNotNull { versionDir -> - versionDir.listFiles { _, name -> name == VersioningConfiguration.VERSIONS_FILE }?.firstOrNull() - ?.let { file -> - val versionsContent = mapper.readValue(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 deleted file mode 100644 index 719d2cf9..00000000 --- a/plugins/versioning/src/main/kotlin/versioning/VersionsNavigationCreator.kt +++ /dev/null @@ -1,86 +0,0 @@ -package org.jetbrains.dokka.versioning - -import kotlinx.html.a -import kotlinx.html.div -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 - -fun interface VersionsNavigationCreator { - operator fun invoke(output: File): String -} - -class HtmlVersionsNavigationCreator(private val context: DokkaContext) : VersionsNavigationCreator { - - private val versioningStorage by lazy { context.plugin().querySingle { versioningStorage } } - - private val versionsOrdering by lazy { context.plugin().querySingle { versionsOrdering } } - - private val isOnlyOnRootPage = - configuration(context)?.renderVersionsNavigationOnAllPages == false - - private val versions: Map 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 - 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 { orderedVersions -> - StringBuilder().appendHTML().div(classes = "versions-dropdown") { - 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") { - 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/VersionsOrdering.kt b/plugins/versioning/src/main/kotlin/versioning/VersionsOrdering.kt deleted file mode 100644 index f72e2df6..00000000 --- a/plugins/versioning/src/main/kotlin/versioning/VersionsOrdering.kt +++ /dev/null @@ -1,23 +0,0 @@ -package org.jetbrains.dokka.versioning - -import org.apache.maven.artifact.versioning.ComparableVersion -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.configuration -import org.jetbrains.dokka.versioning.VersionId -import org.jetbrains.dokka.versioning.VersioningConfiguration -import org.jetbrains.dokka.versioning.VersioningPlugin - -fun interface VersionsOrdering { - fun order(records: List): List -} - -class ByConfigurationVersionOrdering(val dokkaContext: DokkaContext) : VersionsOrdering { - override fun order(records: List): List = - configuration(dokkaContext)?.versionsOrdering - ?: throw IllegalStateException("Attempted to use a configuration ordering without providing configuration") -} - -class SemVerVersionOrdering : VersionsOrdering { - override fun order(records: List): List = - records.map { it to ComparableVersion(it) }.sortedByDescending { it.second }.map { it.first } -} \ 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 deleted file mode 100644 index 94400898..00000000 --- a/plugins/versioning/src/main/kotlin/versioning/htmlPreprocessors.kt +++ /dev/null @@ -1,38 +0,0 @@ -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 - -class MultiModuleStylesInstaller(private val dokkaContext: DokkaContext) : PageTransformer { - private val stylesPages = listOf( - "styles/multimodule.css", - ) - - override fun invoke(input: RootPageNode): RootPageNode = - 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.toRenderSpecificResourcePage(): List = - map { RendererSpecificResourcePage(it, emptyList(), RenderingStrategy.Copy("/dokka/$it")) } -- cgit