diff options
author | Paweł Marks <pmarks@virtuslab.com> | 2020-07-01 16:57:58 +0200 |
---|---|---|
committer | Paweł Marks <Kordyjan@users.noreply.github.com> | 2020-07-07 10:07:21 +0200 |
commit | 177ede83228515f03436a4ac0ce1ce573fc3d74b (patch) | |
tree | f42f9b98f2c6e78a36e65ab1f00fe1a231be9219 | |
parent | 9b7e163ae69272c7e56088d6f256d6b19f9a01d4 (diff) | |
download | dokka-177ede83228515f03436a4ac0ce1ce573fc3d74b.tar.gz dokka-177ede83228515f03436a4ac0ce1ce573fc3d74b.tar.bz2 dokka-177ede83228515f03436a4ac0ce1ce573fc3d74b.zip |
Add functionality to plugin overrides
4 files changed, 70 insertions, 26 deletions
diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt index ee1adf0b..d694cc8c 100644 --- a/core/src/main/kotlin/DokkaGenerator.kt +++ b/core/src/main/kotlin/DokkaGenerator.kt @@ -10,6 +10,7 @@ import org.jetbrains.dokka.utilities.DokkaLogger /** * DokkaGenerator is the main entry point for generating documentation + * * [generate] method has been split into submethods for test reasons */ class DokkaGenerator( @@ -62,8 +63,8 @@ class DokkaGenerator( fun initializePlugins( configuration: DokkaConfiguration, logger: DokkaLogger, - pluginOverrides: List<DokkaPlugin> = emptyList() - ) = DokkaContext.create(configuration, logger, pluginOverrides) + additionalPlugins: List<DokkaPlugin> = emptyList() + ) = DokkaContext.create(configuration, logger, additionalPlugins) fun createDocumentationModels( context: DokkaContext diff --git a/core/src/main/kotlin/plugability/DokkaContext.kt b/core/src/main/kotlin/plugability/DokkaContext.kt index 12b1557b..30566d15 100644 --- a/core/src/main/kotlin/plugability/DokkaContext.kt +++ b/core/src/main/kotlin/plugability/DokkaContext.kt @@ -37,7 +37,7 @@ interface DokkaContext { .let { ServiceLoader.load(DokkaPlugin::class.java, it) } .let { it + pluginOverrides } .forEach { install(it) } - applyExtensions() + topologicallySortAndPrune() }.also { it.logInitialisationInfo() } } } @@ -46,7 +46,7 @@ inline fun <reified T : DokkaPlugin> DokkaContext.plugin(): T = plugin(T::class) ?: throw java.lang.IllegalStateException("Plugin ${T::class.qualifiedName} is not present in context.") interface DokkaContextConfiguration { - fun addExtensionDependencies(extension: Extension<*, *, *>) + fun installExtension(extension: Extension<*, *, *>) } private class DokkaContextConfigurationImpl( @@ -67,11 +67,26 @@ private class DokkaContextConfigurationImpl( VISITED; } - val verticesWithState = mutableMapOf<Extension<*, *, *>, State>() - val adjacencyList: MutableMap<Extension<*, *, *>, MutableList<Extension<*, *, *>>> = mutableMapOf() + private sealed class Suppression { + data class ByExtension(val extension: Extension<*, *, *>) : Suppression() - private fun topologicalSort() { + data class ByPlugin(val plugin: DokkaPlugin) : Suppression() + } + + private val rawExtensions = mutableListOf<Extension<*, *, *>>() + private val rawAdjacencyList = mutableMapOf<Extension<*, *, *>, MutableList<Extension<*, *, *>>>() + private val suppressedExtensions = mutableMapOf<Extension<*, *, *>, MutableList<Suppression>>() + + fun topologicallySortAndPrune() { + pointsPopulated.clear() + extensions.clear() + + val overridesInfo = processOverrides() + val extensionsToSort = overridesInfo.keys + val adjacencyList = translateAdjacencyList(overridesInfo) + + val verticesWithState = extensionsToSort.associateWithTo(mutableMapOf()) { State.UNVISITED } val result: MutableList<Extension<*, *, *>> = mutableListOf() fun visit(n: Extension<*, *, *>) { @@ -86,14 +101,39 @@ private class DokkaContextConfigurationImpl( result += n } - for ((vertex, state) in verticesWithState) { - if (state == State.UNVISITED) - visit(vertex) - } - result.asReversed().forEach { - pointsPopulated += it.extensionPoint - extensions.getOrPut(it.extensionPoint, ::mutableListOf) += it + extensionsToSort.forEach(::visit) + + val filteredResult = result.asReversed().filterNot { it in suppressedExtensions } + + filteredResult.mapTo(pointsPopulated) { it.extensionPoint } + filteredResult.groupByTo(extensions) { it.extensionPoint } + } + + private fun processOverrides(): Map<Extension<*, *, *>, Set<Extension<*, *, *>>> { + val buckets = rawExtensions.associateWithTo(mutableMapOf()) { setOf(it) } + suppressedExtensions.forEach { (extension, suppressions) -> + val mergedBucket = suppressions.filterIsInstance<Suppression.ByExtension>() + .map { it.extension } + .plus(extension) + .flatMap { buckets[it].orEmpty() } + .toSet() + mergedBucket.forEach { buckets[it] = mergedBucket } } + return buckets.values.distinct().associateBy(::findNotOverridden) + } + + private fun findNotOverridden(bucket: Set<Extension<*, *, *>>): Extension<*, *, *> { + val filtered = bucket.filter { it !in suppressedExtensions } + return filtered.singleOrNull() ?: throw Error("Conflicting overrides: $filtered") + } + + private fun translateAdjacencyList( + overridesInfo: Map<Extension<*, *, *>, Set<Extension<*, *, *>>> + ): Map<Extension<*, *, *>, List<Extension<*, *, *>>> { + val reverseOverrideInfo = overridesInfo.flatMap { (ext, set) -> set.map { it to ext } }.toMap() + return rawAdjacencyList.map { (ext, list) -> + reverseOverrideInfo.getValue(ext) to list.map { reverseOverrideInfo.getValue(it) } + }.toMap() } @Suppress("UNCHECKED_CAST") @@ -129,14 +169,19 @@ private class DokkaContextConfigurationImpl( plugin.internalInstall(this, this.configuration) } - override fun addExtensionDependencies(extension: Extension<*, *, *>) { + override fun installExtension(extension: Extension<*, *, *>) { + rawExtensions += extension + if (extension.ordering is OrderingKind.ByDsl) { val orderDsl = OrderDsl() - extension.ordering.block.invoke(orderDsl) + orderDsl.(extension.ordering.block)() - verticesWithState += extension to State.UNVISITED - adjacencyList.getOrPut(extension, ::mutableListOf) += orderDsl.following.toList() - orderDsl.previous.forEach { adjacencyList.getOrPut(it, ::mutableListOf) += extension } + rawAdjacencyList.listFor(extension) += orderDsl.following.toList() + orderDsl.previous.forEach { rawAdjacencyList.listFor(it) += extension } + } + + if (extension.override is OverrideKind.Present) { + suppressedExtensions.listFor(extension.override.overriden) += Suppression.ByExtension(extension) } } @@ -150,10 +195,6 @@ private class DokkaContextConfigurationImpl( logger.progress("Loaded: $loadedListForDebug") } - - fun applyExtensions() { - topologicalSort() - } } private fun checkClasspath(classLoader: URLClassLoader) { @@ -164,3 +205,5 @@ private fun checkClasspath(classLoader: URLClassLoader) { ) } } + +private fun <K, V> MutableMap<K, MutableList<V>>.listFor(key: K) = getOrPut(key, ::mutableListOf)
\ No newline at end of file diff --git a/core/src/main/kotlin/plugability/DokkaPlugin.kt b/core/src/main/kotlin/plugability/DokkaPlugin.kt index bf82daa7..671cefad 100644 --- a/core/src/main/kotlin/plugability/DokkaPlugin.kt +++ b/core/src/main/kotlin/plugability/DokkaPlugin.kt @@ -40,7 +40,7 @@ abstract class DokkaPlugin { extensionDelegates.asSequence() .filterIsInstance<KProperty1<DokkaPlugin, Extension<*, *, *>>>() // should be always true .map { it.get(this) } - .forEach { if (it.condition.invoke(configuration)) ctx.addExtensionDependencies(it) } + .forEach { if (configuration.(it.condition)()) ctx.installExtension(it) } } } diff --git a/testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt b/testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt index d3127263..414919dc 100644 --- a/testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt +++ b/testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt @@ -9,14 +9,14 @@ internal class DokkaTestGenerator( private val configuration: DokkaConfiguration, private val logger: DokkaLogger, private val testMethods: TestMethods, - private val pluginOverrides: List<DokkaPlugin> = emptyList() + private val additionalPlugins: List<DokkaPlugin> = emptyList() ) { fun generate() = with(testMethods) { val dokkaGenerator = DokkaGenerator(configuration, logger) val context = - dokkaGenerator.initializePlugins(configuration, logger, pluginOverrides) + dokkaGenerator.initializePlugins(configuration, logger, additionalPlugins) pluginsSetupStage(context) val modulesFromPlatforms = dokkaGenerator.createDocumentationModels(context) |