diff options
author | Paweł Marks <pmarks@virtuslab.com> | 2020-09-16 16:36:54 +0200 |
---|---|---|
committer | Błażej Kardyś <bkardys@virtuslab.com> | 2020-11-27 03:15:02 +0100 |
commit | c8a83153a88fe6f5b50b6f459295421f90a21583 (patch) | |
tree | 4ce52c287dde3a8303549287ce67e58174d9f9fc /core/src | |
parent | 585178984228a9c2e5bd2af9b675094ac6e3fa46 (diff) | |
download | dokka-c8a83153a88fe6f5b50b6f459295421f90a21583.tar.gz dokka-c8a83153a88fe6f5b50b6f459295421f90a21583.tar.bz2 dokka-c8a83153a88fe6f5b50b6f459295421f90a21583.zip |
Extracting dokka generation to the dedicated extension point
Diffstat (limited to 'core/src')
-rw-r--r-- | core/src/main/kotlin/CoreExtensions.kt | 44 | ||||
-rw-r--r-- | core/src/main/kotlin/DokkaGenerator.kt | 143 | ||||
-rw-r--r-- | core/src/main/kotlin/DokkaMultimoduleBootstrapImpl.kt | 29 | ||||
-rw-r--r-- | core/src/main/kotlin/generation/Generation.kt | 15 | ||||
-rw-r--r-- | core/src/main/kotlin/generation/SingleModule.kt | 0 | ||||
-rw-r--r-- | core/src/main/kotlin/generation/SingleModuleGeneration.kt | 124 | ||||
-rw-r--r-- | core/src/main/kotlin/plugability/DokkaContext.kt | 2 | ||||
-rw-r--r-- | core/src/main/kotlin/plugability/extensions.kt | 2 |
8 files changed, 182 insertions, 177 deletions
diff --git a/core/src/main/kotlin/CoreExtensions.kt b/core/src/main/kotlin/CoreExtensions.kt index f5fb7604..0eea416a 100644 --- a/core/src/main/kotlin/CoreExtensions.kt +++ b/core/src/main/kotlin/CoreExtensions.kt @@ -1,6 +1,9 @@ package org.jetbrains.dokka -import org.jetbrains.dokka.plugability.ExtensionPoint +import org.jetbrains.dokka.generation.Generation +import org.jetbrains.dokka.generation.SingleModuleGeneration +import org.jetbrains.dokka.plugability.* +import org.jetbrains.dokka.plugability.LazyEvaluated import org.jetbrains.dokka.renderers.Renderer import org.jetbrains.dokka.transformers.documentation.DocumentableMerger import org.jetbrains.dokka.transformers.documentation.DocumentableToPageTranslator @@ -13,19 +16,36 @@ import org.jetbrains.dokka.validity.PreGenerationChecker import kotlin.reflect.KProperty object CoreExtensions { - val preGenerationCheck by coreExtension<PreGenerationChecker>() - val sourceToDocumentableTranslator by coreExtension<SourceToDocumentableTranslator>() - val preMergeDocumentableTransformer by coreExtension<PreMergeDocumentableTransformer>() - val documentableMerger by coreExtension<DocumentableMerger>() - val documentableTransformer by coreExtension<DocumentableTransformer>() - val documentableToPageTranslator by coreExtension<DocumentableToPageTranslator>() - val allModulePageCreator by coreExtension<PageCreator>() - val pageTransformer by coreExtension<PageTransformer>() - val allModulePageTransformer by coreExtension<PageTransformer>() - val renderer by coreExtension<Renderer>() + private val extensionDelegates = mutableListOf<Lazy<Extension<*, *, *>>>() - private fun <T : Any> coreExtension() = object { + val preGenerationCheck by coreExtensionPoint<PreGenerationChecker>() + val generation by coreExtensionPoint<Generation>() + val sourceToDocumentableTranslator by coreExtensionPoint<SourceToDocumentableTranslator>() + val preMergeDocumentableTransformer by coreExtensionPoint<PreMergeDocumentableTransformer>() + val documentableMerger by coreExtensionPoint<DocumentableMerger>() + val documentableTransformer by coreExtensionPoint<DocumentableTransformer>() + val documentableToPageTranslator by coreExtensionPoint<DocumentableToPageTranslator>() + val allModulePageCreator by coreExtensionPoint<PageCreator>() + val pageTransformer by coreExtensionPoint<PageTransformer>() + val allModulePageTransformer by coreExtensionPoint<PageTransformer>() + val renderer by coreExtensionPoint<Renderer>() + + val singleGeneration by generation extendWith LazyEvaluated.fromRecipe(::SingleModuleGeneration) + + private fun <T : Any> coreExtensionPoint() = object { operator fun provideDelegate(thisRef: CoreExtensions, property: KProperty<*>): Lazy<ExtensionPoint<T>> = lazy { ExtensionPoint<T>(thisRef::class.qualifiedName!!, property.name) } } + + private infix fun <T: Any> ExtensionPoint<T>.extendWith(action: LazyEvaluated<T>) = object { + operator fun provideDelegate(thisRef: CoreExtensions, property: KProperty<*>): Lazy<Extension<T, OrderingKind.None, OverrideKind.None>> = + lazy { Extension(this@extendWith, thisRef::class.qualifiedName!!, property.name, action) } + .also { extensionDelegates += it } + } + + internal fun installTo(context: DokkaContextConfiguration) { + extensionDelegates.forEach { + context.installExtension(it.value) + } + } }
\ No newline at end of file diff --git a/core/src/main/kotlin/DokkaGenerator.kt b/core/src/main/kotlin/DokkaGenerator.kt index b3d58439..947fa737 100644 --- a/core/src/main/kotlin/DokkaGenerator.kt +++ b/core/src/main/kotlin/DokkaGenerator.kt @@ -2,17 +2,10 @@ package org.jetbrains.dokka -import org.jetbrains.dokka.model.DModule -import org.jetbrains.dokka.DokkaConfiguration.* -import org.jetbrains.dokka.pages.RootPageNode +import org.jetbrains.dokka.generation.GracefulGenerationExit import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.utilities.DokkaLogger -import org.jetbrains.dokka.utilities.report -import kotlinx.coroutines.* -import org.jetbrains.dokka.transformers.sources.AsyncSourceToDocumentableTranslator -import org.jetbrains.dokka.utilities.parallelMap - /** * DokkaGenerator is the main entry point for generating documentation @@ -29,136 +22,21 @@ class DokkaGenerator( report("Initializing plugins") val context = initializePlugins(configuration, logger) - report("Validity check") - validityCheck(context) - - report("Creating documentation models") - val modulesFromPlatforms = createDocumentationModels(context) - - report("Transforming documentation model before merging") - val transformedDocumentationBeforeMerge = transformDocumentationModelBeforeMerge(modulesFromPlatforms, context) - - report("Merging documentation models") - val documentationModel = mergeDocumentationModels(transformedDocumentationBeforeMerge, context) - - report("Transforming documentation model after merging") - val transformedDocumentation = transformDocumentationModelAfterMerge(documentationModel, context) - - report("Creating pages") - val pages = createPages(transformedDocumentation, context) - - report("Transforming pages") - val transformedPages = transformPages(pages, context) - - report("Rendering") - render(transformedPages, context) - - reportAfterRendering(context) - }.dump("\n\n === TIME MEASUREMENT ===\n") - - fun generateAllModulesPage() = timed { - report("Initializing plugins") - val context = initializePlugins(configuration, logger) - - report("Creating all modules page") - val pages = createAllModulePage(context) - - report("Transforming pages") - val transformedPages = transformAllModulesPage(pages, context) + context.single(CoreExtensions.generation).run { + logger.progress("Dokka is performing: $generationName") + generate() + } - report("Rendering") - render(transformedPages, context) }.dump("\n\n === TIME MEASUREMENT ===\n") - fun initializePlugins( configuration: DokkaConfiguration, logger: DokkaLogger, additionalPlugins: List<DokkaPlugin> = emptyList() ) = DokkaContext.create(configuration, logger, additionalPlugins) - - fun createDocumentationModels( - context: DokkaContext - ) = runBlocking(Dispatchers.Default) { - context.configuration.sourceSets.parallelMap { sourceSet -> translateSources(sourceSet, context) }.flatten() - .also { modules -> if (modules.isEmpty()) exitGenerationGracefully("Nothing to document") } - } - - fun transformDocumentationModelBeforeMerge( - modulesFromPlatforms: List<DModule>, - context: DokkaContext - ) = context[CoreExtensions.preMergeDocumentableTransformer].fold(modulesFromPlatforms) { acc, t -> t(acc) } - - fun mergeDocumentationModels( - modulesFromPlatforms: List<DModule>, - context: DokkaContext - ) = context.single(CoreExtensions.documentableMerger).invoke(modulesFromPlatforms) - - fun transformDocumentationModelAfterMerge( - documentationModel: DModule, - context: DokkaContext - ) = context[CoreExtensions.documentableTransformer].fold(documentationModel) { acc, t -> t(acc, context) } - - fun createPages( - transformedDocumentation: DModule, - context: DokkaContext - ) = context.single(CoreExtensions.documentableToPageTranslator).invoke(transformedDocumentation) - - fun createAllModulePage( - context: DokkaContext - ) = context.single(CoreExtensions.allModulePageCreator).invoke() - - fun transformPages( - pages: RootPageNode, - context: DokkaContext - ) = context[CoreExtensions.pageTransformer].fold(pages) { acc, t -> t(acc) } - - fun transformAllModulesPage( - pages: RootPageNode, - context: DokkaContext - ) = context[CoreExtensions.allModulePageTransformer].fold(pages) { acc, t -> t(acc) } - - fun render( - transformedPages: RootPageNode, - context: DokkaContext - ) { - val renderer = context.single(CoreExtensions.renderer) - renderer.render(transformedPages) - } - - fun reportAfterRendering(context: DokkaContext) { - context.unusedPoints.takeIf { it.isNotEmpty() }?.also { - logger.info("Unused extension points found: ${it.joinToString(", ")}") - } - - logger.report() - - if (context.configuration.failOnWarning && (logger.warningsCount > 0 || logger.errorsCount > 0)) { - throw DokkaException( - "Failed with warningCount=${logger.warningsCount} and errorCount=${logger.errorsCount}" - ) - } - } - - fun validityCheck(context: DokkaContext) { - val (preGenerationCheckResult, checkMessages) = context[CoreExtensions.preGenerationCheck].fold( - Pair(true, emptyList<String>()) - ) { acc, checker -> checker() + acc } - if (!preGenerationCheckResult) throw DokkaException( - "Pre-generation validity check failed: ${checkMessages.joinToString(",")}" - ) - } - - private suspend fun translateSources(sourceSet: DokkaSourceSet, context: DokkaContext) = - context[CoreExtensions.sourceToDocumentableTranslator].parallelMap { translator -> - when(translator){ - is AsyncSourceToDocumentableTranslator -> translator.invokeSuspending(sourceSet, context) - else -> translator.invoke(sourceSet, context) - } - } } -private class Timer(startTime: Long, private val logger: DokkaLogger?) { +class Timer internal constructor(startTime: Long, private val logger: DokkaLogger?) { private val steps = mutableListOf("" to startTime) fun report(name: String) { @@ -168,8 +46,8 @@ private class Timer(startTime: Long, private val logger: DokkaLogger?) { fun dump(prefix: String = "") { logger?.info(prefix) - val namePad = steps.map { it.first.length }.max() ?: 0 - val timePad = steps.windowed(2).map { (p1, p2) -> p2.second - p1.second }.max()?.toString()?.length ?: 0 + val namePad = steps.map { it.first.length }.maxOrNull() ?: 0 + val timePad = steps.windowed(2).map { (p1, p2) -> p2.second - p1.second }.maxOrNull()?.toString()?.length ?: 0 steps.windowed(2).forEach { (p1, p2) -> if (p1.first.isNotBlank()) { logger?.info("${p1.first.padStart(namePad)}: ${(p2.second - p1.second).toString().padStart(timePad)}") @@ -189,8 +67,3 @@ private fun timed(logger: DokkaLogger? = null, block: Timer.() -> Unit): Timer = } } -private fun exitGenerationGracefully(reason: String): Nothing { - throw GracefulGenerationExit(reason) -} - -private class GracefulGenerationExit(val reason: String) : Throwable() diff --git a/core/src/main/kotlin/DokkaMultimoduleBootstrapImpl.kt b/core/src/main/kotlin/DokkaMultimoduleBootstrapImpl.kt deleted file mode 100644 index c0726584..00000000 --- a/core/src/main/kotlin/DokkaMultimoduleBootstrapImpl.kt +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Accessed with reflection - */ -@file:Suppress("unused") - -package org.jetbrains.dokka - -import org.jetbrains.dokka.DokkaBootstrapImpl.DokkaProxyLogger -import org.jetbrains.dokka.utilities.DokkaLogger -import java.util.function.BiConsumer - -class DokkaMultimoduleBootstrapImpl : DokkaBootstrap { - - private lateinit var generator: DokkaGenerator - - fun configure(logger: DokkaLogger, configuration: DokkaConfiguration) { - generator = DokkaGenerator(configuration, logger) - } - - override fun configure(serializedConfigurationJSON: String, logger: BiConsumer<String, String>) = configure( - DokkaProxyLogger(logger), - DokkaConfigurationImpl(serializedConfigurationJSON) - ) - - override fun generate() { - generator.generateAllModulesPage() - } - -} diff --git a/core/src/main/kotlin/generation/Generation.kt b/core/src/main/kotlin/generation/Generation.kt new file mode 100644 index 00000000..230cdae1 --- /dev/null +++ b/core/src/main/kotlin/generation/Generation.kt @@ -0,0 +1,15 @@ +package org.jetbrains.dokka.generation + +import org.jetbrains.dokka.Timer + +interface Generation { + fun Timer.generate() + val generationName: String +} + +// This needs to be public for now but in the future it should be replaced with system of checks provided by EP +fun exitGenerationGracefully(reason: String): Nothing { + throw GracefulGenerationExit(reason) +} + +class GracefulGenerationExit(val reason: String) : Throwable()
\ No newline at end of file diff --git a/core/src/main/kotlin/generation/SingleModule.kt b/core/src/main/kotlin/generation/SingleModule.kt new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/core/src/main/kotlin/generation/SingleModule.kt diff --git a/core/src/main/kotlin/generation/SingleModuleGeneration.kt b/core/src/main/kotlin/generation/SingleModuleGeneration.kt new file mode 100644 index 00000000..59514632 --- /dev/null +++ b/core/src/main/kotlin/generation/SingleModuleGeneration.kt @@ -0,0 +1,124 @@ +package org.jetbrains.dokka.generation + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking +import org.jetbrains.dokka.* +import org.jetbrains.dokka.model.DModule +import org.jetbrains.dokka.pages.RootPageNode +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.transformers.sources.AsyncSourceToDocumentableTranslator +import org.jetbrains.dokka.utilities.parallelMap +import org.jetbrains.dokka.utilities.report + +class SingleModuleGeneration(private val context: DokkaContext): Generation { + override fun Timer.generate() { + report("Validity check") + validityCheck(context) + + report("Creating documentation models") + val modulesFromPlatforms = createDocumentationModels(context) + + report("Transforming documentation model before merging") + val transformedDocumentationBeforeMerge = transformDocumentationModelBeforeMerge(modulesFromPlatforms, context) + + report("Merging documentation models") + val documentationModel = mergeDocumentationModels(transformedDocumentationBeforeMerge, context) + + report("Transforming documentation model after merging") + val transformedDocumentation = transformDocumentationModelAfterMerge(documentationModel, context) + + report("Creating pages") + val pages = createPages(transformedDocumentation, context) + + report("Transforming pages") + val transformedPages = transformPages(pages, context) + + report("Rendering") + render(transformedPages, context) + + reportAfterRendering(context) + } + + override val generationName: String + get() = TODO("Not yet implemented") + + fun createDocumentationModels( + context: DokkaContext + ) = runBlocking(Dispatchers.Default) { + context.configuration.sourceSets.parallelMap { sourceSet -> translateSources(sourceSet, context) }.flatten() + .also { modules -> if (modules.isEmpty()) exitGenerationGracefully("Nothing to document") } + } + + fun transformDocumentationModelBeforeMerge( + modulesFromPlatforms: List<DModule>, + context: DokkaContext + ) = context[CoreExtensions.preMergeDocumentableTransformer].fold(modulesFromPlatforms) { acc, t -> t(acc) } + + fun mergeDocumentationModels( + modulesFromPlatforms: List<DModule>, + context: DokkaContext + ) = context.single(CoreExtensions.documentableMerger).invoke(modulesFromPlatforms) + + fun transformDocumentationModelAfterMerge( + documentationModel: DModule, + context: DokkaContext + ) = context[CoreExtensions.documentableTransformer].fold(documentationModel) { acc, t -> t(acc, context) } + + fun createPages( + transformedDocumentation: DModule, + context: DokkaContext + ) = context.single(CoreExtensions.documentableToPageTranslator).invoke(transformedDocumentation) + + fun createAllModulePage( + context: DokkaContext + ) = context.single(CoreExtensions.allModulePageCreator).invoke() + + fun transformPages( + pages: RootPageNode, + context: DokkaContext + ) = context[CoreExtensions.pageTransformer].fold(pages) { acc, t -> t(acc) } + + fun transformAllModulesPage( + pages: RootPageNode, + context: DokkaContext + ) = context[CoreExtensions.allModulePageTransformer].fold(pages) { acc, t -> t(acc) } + + fun render( + transformedPages: RootPageNode, + context: DokkaContext + ) { + val renderer = context.single(CoreExtensions.renderer) + renderer.render(transformedPages) + } + + fun validityCheck(context: DokkaContext) { + val (preGenerationCheckResult, checkMessages) = context[CoreExtensions.preGenerationCheck].fold( + Pair(true, emptyList<String>()) + ) { acc, checker -> checker() + acc } + if (!preGenerationCheckResult) throw DokkaException( + "Pre-generation validity check failed: ${checkMessages.joinToString(",")}" + ) + } + + fun reportAfterRendering(context: DokkaContext) { + context.unusedPoints.takeIf { it.isNotEmpty() }?.also { + context.logger.info("Unused extension points found: ${it.joinToString(", ")}") + } + + context.logger.report() + + if (context.configuration.failOnWarning && (context.logger.warningsCount > 0 || context.logger.errorsCount > 0)) { + throw DokkaException( + "Failed with warningCount=${context.logger.warningsCount} and errorCount=${context.logger.errorsCount}" + ) + } + } + + private suspend fun translateSources(sourceSet: DokkaConfiguration.DokkaSourceSet, context: DokkaContext) = + context[CoreExtensions.sourceToDocumentableTranslator].parallelMap { translator -> + when(translator){ + is AsyncSourceToDocumentableTranslator -> translator.invokeSuspending(sourceSet, context) + else -> translator.invoke(sourceSet, context) + } + } +}
\ No newline at end of file diff --git a/core/src/main/kotlin/plugability/DokkaContext.kt b/core/src/main/kotlin/plugability/DokkaContext.kt index 323039e9..1f5f6018 100644 --- a/core/src/main/kotlin/plugability/DokkaContext.kt +++ b/core/src/main/kotlin/plugability/DokkaContext.kt @@ -1,5 +1,6 @@ package org.jetbrains.dokka.plugability +import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.utilities.DokkaLogger import java.io.File @@ -29,6 +30,7 @@ interface DokkaContext { pluginOverrides: List<DokkaPlugin> ): DokkaContext = DokkaContextConfigurationImpl(logger, configuration).apply { + CoreExtensions.installTo(this) // File(it.path) is a workaround for an incorrect filesystem in a File instance returned by Gradle. configuration.pluginsClasspath.map { File(it.path).toURI().toURL() } .toTypedArray() diff --git a/core/src/main/kotlin/plugability/extensions.kt b/core/src/main/kotlin/plugability/extensions.kt index be45c237..46739951 100644 --- a/core/src/main/kotlin/plugability/extensions.kt +++ b/core/src/main/kotlin/plugability/extensions.kt @@ -40,7 +40,7 @@ class Extension<T : Any, Ordering : OrderingKind, Override : OverrideKind> inter get() = { conditions.all { it(this) } } } -private fun <T : Any> Extension( +internal fun <T : Any> Extension( extensionPoint: ExtensionPoint<T>, pluginClass: String, extensionName: String, |