diff options
Diffstat (limited to 'plugins/base/src/main/kotlin')
4 files changed, 405 insertions, 2 deletions
diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index b18e2ad5..34c0ffae 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -3,14 +3,19 @@ package org.jetbrains.dokka.base import org.jetbrains.dokka.CoreExtensions import org.jetbrains.dokka.base.transformers.descriptors.DefaultDescriptorToDocumentationTranslator import org.jetbrains.dokka.base.transformers.documentables.DefaultDocumentableMerger +import org.jetbrains.dokka.base.transformers.documentables.DefaultDocumentablesToPageTranslator import org.jetbrains.dokka.plugability.DokkaPlugin class DokkaBase: DokkaPlugin() { - val defaultDescriptorToDocumentationTranslator by extending(isFallback = true) { + val descriptorToDocumentationTranslator by extending(isFallback = true) { CoreExtensions.descriptorToDocumentationTranslator providing ::DefaultDescriptorToDocumentationTranslator } - val defaultDocumentableMerger by extending(isFallback = true) { + val documentableMerger by extending(isFallback = true) { CoreExtensions.documentableMerger with DefaultDocumentableMerger } + + val documentablesToPageTranslator by extending(isFallback = true) { + CoreExtensions.documentablesToPageTranslator with DefaultDocumentablesToPageTranslator + } }
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentablesToPageTranslator.kt b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentablesToPageTranslator.kt new file mode 100644 index 00000000..90f8e2d7 --- /dev/null +++ b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentablesToPageTranslator.kt @@ -0,0 +1,22 @@ +package org.jetbrains.dokka.base.transformers.documentables + +import org.jetbrains.dokka.CoreExtensions +import org.jetbrains.dokka.model.Module +import org.jetbrains.dokka.pages.ModulePageNode +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.transformers.documentation.DocumentablesToPageTranslator + + +object DefaultDocumentablesToPageTranslator : DocumentablesToPageTranslator { + override fun invoke(module: Module, context: DokkaContext): ModulePageNode = + DefaultPageBuilder { node, kind, operation -> + DefaultPageContentBuilder.group( + setOf(node.dri), + node.platformData, + kind, + context.single(CoreExtensions.commentsToContentConverter), + context.logger, + operation + ) + }.pageForModule(module) +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/documentables/PageBuilder.kt b/plugins/base/src/main/kotlin/transformers/documentables/PageBuilder.kt new file mode 100644 index 00000000..29f39c73 --- /dev/null +++ b/plugins/base/src/main/kotlin/transformers/documentables/PageBuilder.kt @@ -0,0 +1,159 @@ +package org.jetbrains.dokka.base.transformers.documentables + +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.Enum +import org.jetbrains.dokka.model.Function +import org.jetbrains.dokka.model.doc.TagWrapper +import org.jetbrains.dokka.pages.* + +open class DefaultPageBuilder( + override val rootContentGroup: RootContentBuilder +) : PageBuilder { + + override fun pageForModule(m: Module): ModulePageNode = + ModulePageNode(m.name.ifEmpty { "root" }, contentForModule(m), m, m.packages.map { pageForPackage(it) }) + + override fun pageForPackage(p: Package) = + PackagePageNode(p.name, contentForPackage(p), setOf(p.dri), p, + p.classlikes.map { pageForClasslike(it) } + + p.functions.map { pageForMember(it) }) + + override fun pageForClasslike(c: Classlike): ClasslikePageNode { + val constructors = when (c) { + is Class -> c.constructors + is Enum -> c.constructors + else -> emptyList() + } + + return ClasslikePageNode(c.name, contentForClasslike(c), setOf(c.dri), c, + constructors.map { pageForMember(it) } + + c.classlikes.map { pageForClasslike(it) } + + c.functions.map { pageForMember(it) }) + } + + override fun pageForMember(m: CallableNode): MemberPageNode = + when (m) { + is Function -> + MemberPageNode(m.name, contentForFunction(m), setOf(m.dri), m) + else -> throw IllegalStateException("$m should not be present here") + } + + protected open fun group(node: Documentable, content: PageContentBuilderFunction) = + rootContentGroup(node, ContentKind.Main, content) + + protected open fun contentForModule(m: Module) = group(m) { + header(1) { text("root") } + block("Packages", 2, ContentKind.Packages, m.packages, m.platformData) { + link(it.name, it.dri) + } + text("Index\n") + text("Link to allpage here") + } + + protected open fun contentForPackage(p: Package) = group(p) { + header(1) { text("Package ${p.name}") } + block("Types", 2, ContentKind.Properties, p.classlikes, p.platformData) { + link(it.name, it.dri) + text(it.briefDocTagString) + } + block("Functions", 2, ContentKind.Functions, p.functions, p.platformData) { + link(it.name, it.dri) + signature(it) + text(it.briefDocTagString) + } + } + + open fun contentForClasslike(c: Classlike): ContentGroup = when (c) { + is Class -> contentForClass(c) + is Enum -> contentForEnum(c) + else -> throw IllegalStateException("$c should not be present here") + } + + protected fun contentForClass(c: Class) = group(c) { + header(1) { text(c.name) } + + c.inherited.takeIf { it.isNotEmpty() }?.let { + header(2) { text("SuperInterfaces") } + linkTable(it) + } + contentForComments(c) + block("Constructors", 2, ContentKind.Functions, c.constructors, c.platformData) { + link(it.name, it.dri) + signature(it) + text(it.briefDocTagString) + } + block("Functions", 2, ContentKind.Functions, c.functions, c.platformData) { + link(it.name, it.dri) + signature(it) + text(it.briefDocTagString) + } + block("Properties", 2, ContentKind.Properties, c.properties, c.platformData) { + link(it.name, it.dri) + text(it.briefDocTagString) + + } + } + + fun contentForEnum(c: Enum): ContentGroup = group(c) { + header(1) { text("enum ${c.name}") } + + block("Entries", 2, ContentKind.Properties, c.entries, c.platformData) { entry -> + link(entry.name, entry.dri) + contentForComments(entry) + } + + c.inherited.takeIf { it.isNotEmpty() }?.let { + header(2) { text("SuperInterfaces") } + linkTable(it) + } + contentForComments(c) + block("Constructors", 2, ContentKind.Functions, c.constructors, c.platformData) { + link(it.name, it.dri) + signature(it) + text(it.briefDocTagString) + } + block("Functions", 2, ContentKind.Functions, c.functions, c.platformData) { + link(it.name, it.dri) + signature(it) + text(it.briefDocTagString) + } + block("Properties", 2, ContentKind.Properties, c.properties, c.platformData) { + link(it.name, it.dri) + text(it.briefDocTagString) + } + } + + private fun PageContentBuilder.contentForComments(d: Documentable) = + d.platformInfo.forEach { platformInfo -> + platformInfo.documentationNode.children.forEach { + header(3) { + text(it.toHeaderString()) + text(" [${platformInfo.platformData.joinToString(", ") { it.platformType.name }}]") + } + comment(it.root) + text("\n") + } + } + + private fun contentForFunction(f: Function) = group(f) { + header(1) { text(f.name) } + signature(f) + contentForComments(f) + block("Parameters", 2, ContentKind.Parameters, f.children, f.platformData) { + text(it.name ?: "<receiver>") + it.platformInfo.forEach { it.documentationNode.children.forEach { comment(it.root) } } + } + } + + private fun TagWrapper.toHeaderString() = this.javaClass.toGenericString().split('.').last() +} + +typealias RootContentBuilder = (Documentable, Kind, PageContentBuilderFunction) -> ContentGroup + +interface PageBuilder { + val rootContentGroup: RootContentBuilder + fun pageForModule(m: Module): ModulePageNode + fun pageForPackage(p: Package): PackagePageNode + fun pageForMember(m: CallableNode): MemberPageNode + fun pageForClasslike(c: Classlike): ClasslikePageNode +}
\ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/documentables/PageContentBuilder.kt b/plugins/base/src/main/kotlin/transformers/documentables/PageContentBuilder.kt new file mode 100644 index 00000000..809b97a0 --- /dev/null +++ b/plugins/base/src/main/kotlin/transformers/documentables/PageContentBuilder.kt @@ -0,0 +1,217 @@ +package org.jetbrains.dokka.base.transformers.documentables + +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.model.Documentable +import org.jetbrains.dokka.model.Function +import org.jetbrains.dokka.model.TypeWrapper +import org.jetbrains.dokka.model.doc.DocTag +import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.utilities.DokkaLogger + +open class DefaultPageContentBuilder( + protected val dri: Set<DRI>, + protected val platformData: Set<PlatformData>, + protected val kind: Kind, + protected val commentsConverter: CommentsToContentConverter, + val logger: DokkaLogger, + protected val styles: Set<Style> = emptySet(), + protected val extras: Set<Extra> = emptySet() +) : PageContentBuilder { + protected val contents = mutableListOf<ContentNode>() + + protected fun createText(text: String, kind: Kind = ContentKind.Symbol) = + ContentText(text, DCI(dri, kind), platformData, styles, extras) + + protected fun build() = ContentGroup( + contents.toList(), + DCI(dri, kind), + platformData, + styles, + extras + ) + + override fun header(level: Int, block: PageContentBuilderFunction) { + contents += ContentHeader(level, group(ContentKind.Symbol, block)) + } + + override fun text(text: String, kind: Kind) { + contents += createText(text, kind) + } + + protected fun signature(f: Function, block: PageContentBuilderFunction) { + contents += group(setOf(f.dri), f.platformData, ContentKind.Symbol, block) + } + + override fun signature(f: Function) = signature(f) { + text("fun ") + f.receiver?.also { + type(it.type) + text(".") + } + link(f.name, f.dri) + text("(") + list(f.parameters) { + link(it.name!!, it.dri) + text(": ") + type(it.type) + } + text(")") + val returnType = f.returnType + if (!f.isConstructor && returnType != null && + returnType.constructorFqName != Unit::class.qualifiedName + ) { + text(": ") + type(returnType) + } + } + + override fun linkTable(elements: List<DRI>) { + contents += ContentTable( + emptyList(), + elements.map { group(dri, platformData, ContentKind.Classes) { link(it.classNames ?: "", it) } }, + DCI(dri, kind), + platformData, styles, extras + ) + } + + override fun <T : Documentable> block( + name: String, + level: Int, + kind: Kind, + elements: Iterable<T>, + platformData: Set<PlatformData>, + operation: PageContentBuilder.(T) -> Unit + ) { + header(level) { text(name) } + + contents += ContentTable( + emptyList(), + elements.map { group(setOf(it.dri), it.platformData, kind) { operation(it) } }, + DCI(dri, kind), + platformData, styles, extras + ) + } + + override fun <T> list( + elements: List<T>, + prefix: String, + suffix: String, + separator: String, + operation: PageContentBuilder.(T) -> Unit + ) { + if (elements.isNotEmpty()) { + if (prefix.isNotEmpty()) text(prefix) + elements.dropLast(1).forEach { + operation(it) + text(separator) + } + operation(elements.last()) + if (suffix.isNotEmpty()) text(suffix) + } + } + + override fun link(text: String, address: DRI, kind: Kind) { + contents += ContentDRILink( + listOf(createText(text)), + address, + DCI(dri, kind), + platformData + ) + } + + override fun link(address: DRI, kind: Kind, block: PageContentBuilderFunction) { + contents += ContentDRILink( + group(ContentKind.Main, block).children, + address, + DCI(dri, kind), + platformData + ) + } + + override fun comment(docTag: DocTag) { + contents += group(ContentKind.Comment) { + with(this as DefaultPageContentBuilder) { + contents += commentsConverter.buildContent( + docTag, + DCI(dri, ContentKind.Comment), + platformData + ) + } + } + } + + fun group(kind: Kind, block: PageContentBuilderFunction): ContentGroup = + group(dri, platformData, kind, block) + + override fun group( + dri: Set<DRI>, + platformData: Set<PlatformData>, + kind: Kind, + block: PageContentBuilderFunction + ): ContentGroup = group(dri, platformData, kind, commentsConverter, logger, block) + + companion object { + fun group( + dri: Set<DRI>, + platformData: Set<PlatformData>, + kind: Kind, + commentsConverter: CommentsToContentConverter, + logger: DokkaLogger, + block: PageContentBuilderFunction + ): ContentGroup = + DefaultPageContentBuilder(dri, platformData, kind, commentsConverter, logger).apply(block).build() + } +} + + +fun PageContentBuilder.type(t: TypeWrapper) { + if (t.constructorNamePathSegments.isNotEmpty() && t.dri != null) + link(t.constructorNamePathSegments.last(), t.dri!!) + else if (t.constructorNamePathSegments.isNotEmpty() && t.dri == null) + text(t.toString()) + else (this as? DefaultPageContentBuilder)?.let { + logger.error("type $t cannot be resolved") + text("???") + } + list(t.arguments, prefix = "<", suffix = ">") { + type(it) + } +} + +typealias PageContentBuilderFunction = PageContentBuilder.() -> Unit + +@DslMarker +annotation class ContentMarker + +@ContentMarker +interface PageContentBuilder { + fun group( + dri: Set<DRI>, + platformData: Set<PlatformData>, + kind: Kind, block: PageContentBuilderFunction + ): ContentGroup + + fun text(text: String, kind: Kind = ContentKind.Symbol) + fun signature(f: Function) + fun link(text: String, address: DRI, kind: Kind = ContentKind.Symbol) + fun link(address: DRI, kind: Kind = ContentKind.Symbol, block: PageContentBuilderFunction) + fun linkTable(elements: List<DRI>) + fun comment(docTag: DocTag) + fun header(level: Int, block: PageContentBuilderFunction) + fun <T> list( + elements: List<T>, + prefix: String = "", + suffix: String = "", + separator: String = ",", + operation: PageContentBuilder.(T) -> Unit + ) + + fun <T : Documentable> block( + name: String, + level: Int, + kind: Kind, + elements: Iterable<T>, + platformData: Set<PlatformData>, + operation: PageContentBuilder.(T) -> Unit + ) +}
\ No newline at end of file |