aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaweł Marks <pmarks@virtuslab.com>2020-07-01 16:57:58 +0200
committerPaweł Marks <Kordyjan@users.noreply.github.com>2020-07-07 10:07:21 +0200
commit177ede83228515f03436a4ac0ce1ce573fc3d74b (patch)
treef42f9b98f2c6e78a36e65ab1f00fe1a231be9219
parent9b7e163ae69272c7e56088d6f256d6b19f9a01d4 (diff)
downloaddokka-177ede83228515f03436a4ac0ce1ce573fc3d74b.tar.gz
dokka-177ede83228515f03436a4ac0ce1ce573fc3d74b.tar.bz2
dokka-177ede83228515f03436a4ac0ce1ce573fc3d74b.zip
Add functionality to plugin overrides
-rw-r--r--core/src/main/kotlin/DokkaGenerator.kt5
-rw-r--r--core/src/main/kotlin/plugability/DokkaContext.kt85
-rw-r--r--core/src/main/kotlin/plugability/DokkaPlugin.kt2
-rw-r--r--testApi/src/main/kotlin/testApi/testRunner/DokkaTestGenerator.kt4
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)