diff options
Diffstat (limited to 'plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt')
-rw-r--r-- | plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt b/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt new file mode 100644 index 00000000..7f441aa1 --- /dev/null +++ b/plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt @@ -0,0 +1,101 @@ +package org.jetbrains.dokka.allModulesPage + +import org.jetbrains.dokka.DokkaConfiguration.DokkaModuleDescription +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet +import org.jetbrains.dokka.base.DokkaBase +import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Module +import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentationParsingContext +import org.jetbrains.dokka.base.parsers.moduleAndPackage.parseModuleAndPackageDocumentation +import org.jetbrains.dokka.base.parsers.moduleAndPackage.parseModuleAndPackageDocumentationFragments +import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint +import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter +import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.doc.DocTag +import org.jetbrains.dokka.model.doc.DocumentationNode +import org.jetbrains.dokka.model.doc.P +import org.jetbrains.dokka.model.properties.PropertyContainer +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.dokka.transformers.pages.PageCreator +import org.jetbrains.dokka.utilities.DokkaLogger + +class MultimodulePageCreator( + private val context: DokkaContext, +) : PageCreator { + private val logger: DokkaLogger = context.logger + + private val commentsConverter by lazy { context.plugin<DokkaBase>().querySingle { commentsToContentConverter } } + private val signatureProvider by lazy { context.plugin<DokkaBase>().querySingle { signatureProvider } } + + override fun invoke(): RootPageNode { + val modules = context.configuration.modules + val sourceSetData = emptySet<DokkaSourceSet>() + val builder = PageContentBuilder(commentsConverter, signatureProvider, context.logger) + val contentNode = builder.contentFor( + dri = DRI(MULTIMODULE_PACKAGE_PLACEHOLDER), + kind = ContentKind.Cover, + sourceSets = sourceSetData + ) { + header(2, "All modules:") + table(styles = setOf(MultimoduleTable)) { + modules.map { module -> + val displayedModuleDocumentation = getDisplayedModuleDocumentation(module) + val dri = DRI(packageName = MULTIMODULE_PACKAGE_PLACEHOLDER, classNames = module.name) + val dci = DCI(setOf(dri), ContentKind.Comment) + val extraWithAnchor = PropertyContainer.withAll(SymbolAnchorHint(module.name, ContentKind.Main)) + val header = linkNode(module.name, dri, DCI(setOf(dri), ContentKind.Main), extra = extraWithAnchor) + val content = ContentGroup( + children = + if (displayedModuleDocumentation != null) + DocTagToContentConverter().buildContent(displayedModuleDocumentation, dci, emptySet()) + else emptyList(), + dci = dci, + sourceSets = emptySet(), + style = emptySet() + ) + ContentGroup(listOf(header, content), dci, emptySet(), emptySet(), extraWithAnchor) + } + } + } + return MultimoduleRootPageNode( + setOf(MULTIMODULE_ROOT_DRI), + contentNode + ) + } + + private fun getDisplayedModuleDocumentation(module: DokkaModuleDescription): P? { + val parsingContext = ModuleAndPackageDocumentationParsingContext(logger) + + val documentationFragment = module.includes + .flatMap { include -> parseModuleAndPackageDocumentationFragments(include) } + .firstOrNull { fragment -> fragment.classifier == Module && fragment.name == module.name } + ?: return null + + val moduleDocumentation = parseModuleAndPackageDocumentation(parsingContext, documentationFragment) + return moduleDocumentation.documentation.firstParagraph() + } + + private fun DocumentationNode.firstParagraph(): P? = + this.children + .map { it.root } + .mapNotNull { it.firstParagraph() } + .firstOrNull() + + /** + * @return The very first, most inner paragraph. If any [P] is wrapped inside another [P], the inner one + * is preferred. + */ + private fun DocTag.firstParagraph(): P? { + val firstChildParagraph = children.mapNotNull { it.firstParagraph() }.firstOrNull() + return if (firstChildParagraph == null && this is P) this + else firstChildParagraph + } + + companion object { + const val MULTIMODULE_PACKAGE_PLACEHOLDER = ".ext" + val MULTIMODULE_ROOT_DRI = DRI(packageName = MULTIMODULE_PACKAGE_PLACEHOLDER, classNames = "allModules") + } +} |