From c4c6a165d968fefbf8caa52b9c9763b58fc39803 Mon Sep 17 00:00:00 2001 From: Paweł Marks Date: Tue, 11 Feb 2020 14:16:11 +0100 Subject: Creates dokka base --- plugins/base/src/main/kotlin/DokkaBase.kt | 4 ++++ .../META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin | 1 + 2 files changed, 5 insertions(+) create mode 100644 plugins/base/src/main/kotlin/DokkaBase.kt create mode 100644 plugins/base/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin (limited to 'plugins/base/src/main') diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt new file mode 100644 index 00000000..e82a59bf --- /dev/null +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -0,0 +1,4 @@ +import org.jetbrains.dokka.plugability.DokkaPlugin + +class DokkaBase: DokkaPlugin() { +} \ No newline at end of file diff --git a/plugins/base/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin b/plugins/base/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin new file mode 100644 index 00000000..bc8de448 --- /dev/null +++ b/plugins/base/src/main/resources/META-INF/services/org.jetbrains.dokka.plugability.DokkaPlugin @@ -0,0 +1 @@ +org.jetbrains.dokka.base.DokkaBase -- cgit From 848f2e0656e80604cb54932db5b250303aaccca8 Mon Sep 17 00:00:00 2001 From: Paweł Marks Date: Wed, 12 Feb 2020 16:01:38 +0100 Subject: Moves DescriptorToDocumentableTransformer to base plugin --- plugins/base/src/main/kotlin/DokkaBase.kt | 7 + .../DefaultDescriptorToDocumentationTranslator.kt | 338 +++++++++++++++++++++ 2 files changed, 345 insertions(+) create mode 100644 plugins/base/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt (limited to 'plugins/base/src/main') diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index e82a59bf..5c579e54 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -1,4 +1,11 @@ +package org.jetbrains.dokka.base + +import org.jetbrains.dokka.CoreExtensions +import org.jetbrains.dokka.base.transformers.descriptors.DefaultDescriptorToDocumentationTranslator import org.jetbrains.dokka.plugability.DokkaPlugin class DokkaBase: DokkaPlugin() { + val defaultDescriptorToDocumentationTranslator by extending { + CoreExtensions.descriptorToDocumentationTranslator providing ::DefaultDescriptorToDocumentationTranslator + } } \ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt b/plugins/base/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt new file mode 100644 index 00000000..1358cef1 --- /dev/null +++ b/plugins/base/src/main/kotlin/transformers/descriptors/DefaultDescriptorToDocumentationTranslator.kt @@ -0,0 +1,338 @@ +package org.jetbrains.dokka.base.transformers.descriptors + +import org.jetbrains.dokka.analysis.DokkaResolutionFacade +import org.jetbrains.dokka.links.Callable +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.withClass +import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.ClassKind +import org.jetbrains.dokka.model.Enum +import org.jetbrains.dokka.model.Function +import org.jetbrains.dokka.model.Property +import org.jetbrains.dokka.model.doc.* +import org.jetbrains.dokka.pages.PlatformData +import org.jetbrains.dokka.parsers.MarkdownParser +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.transformers.descriptors.DescriptorToDocumentationTranslator +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.impl.DeclarationDescriptorVisitorEmptyBodies +import org.jetbrains.kotlin.idea.kdoc.findKDoc +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.resolve.descriptorUtil.getAllSuperclassesWithoutAny +import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperInterfaces +import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import org.jetbrains.kotlin.resolve.scopes.MemberScope +import org.jetbrains.kotlin.types.KotlinType +import kotlin.reflect.KClass + +class DefaultDescriptorToDocumentationTranslator( + private val context: DokkaContext +) : DescriptorToDocumentationTranslator { + override fun invoke( + moduleName: String, + packageFragments: Iterable, + platformData: PlatformData + ) = DokkaDescriptorVisitor(platformData, context.platforms[platformData]?.facade!!).run { + packageFragments.map { + visitPackageFragmentDescriptor( + it, + DRIWithPlatformInfo(DRI.topLevel, null, emptyList()) + ) + } + }.let { Module(moduleName, it) } + +} + + +data class DRIWithPlatformInfo( + val dri: DRI, + val expected: PlatformInfo?, + val actual: List +) + +fun DRI.withEmptyInfo() = DRIWithPlatformInfo(this, null, emptyList()) + +open class DokkaDescriptorVisitor( // TODO: close this class and make it private together with DRIWithPlatformInfo + private val platformData: PlatformData, + private val resolutionFacade: DokkaResolutionFacade +) : DeclarationDescriptorVisitorEmptyBodies() { + override fun visitDeclarationDescriptor(descriptor: DeclarationDescriptor, parent: DRIWithPlatformInfo): Nothing { + throw IllegalStateException("${javaClass.simpleName} should never enter ${descriptor.javaClass.simpleName}") + } + + override fun visitPackageFragmentDescriptor( + descriptor: PackageFragmentDescriptor, + parent: DRIWithPlatformInfo + ): Package { + val driWithPlatform = DRI(packageName = descriptor.fqName.asString()).withEmptyInfo() + val scope = descriptor.getMemberScope() + + return Package( + dri = driWithPlatform.dri, + functions = scope.functions(driWithPlatform), + properties = scope.properties(driWithPlatform), + classlikes = scope.classlikes(driWithPlatform) + ) + } + + override fun visitClassDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Classlike = + when (descriptor.kind) { + org.jetbrains.kotlin.descriptors.ClassKind.ENUM_CLASS -> enumDescriptor(descriptor, parent) + else -> classDescriptor(descriptor, parent) + } + + fun enumDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Enum { + val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() + val scope = descriptor.unsubstitutedMemberScope + val descriptorData = descriptor.takeUnless { it.isExpect }?.resolveClassDescriptionData() + + return Enum( + dri = driWithPlatform.dri, + name = descriptor.name.asString(), + entries = scope.classlikes(driWithPlatform).filter { it.kind == KotlinClassKindTypes.ENUM_ENTRY }.map { + EnumEntry( + it + ) + }, + constructors = descriptor.constructors.map { visitConstructorDescriptor(it, driWithPlatform) }, + functions = scope.functions(driWithPlatform), + properties = scope.properties(driWithPlatform), + classlikes = scope.classlikes(driWithPlatform), + expected = descriptor.takeIf { it.isExpect }?.resolveClassDescriptionData(), + actual = listOfNotNull(descriptorData), + extra = mutableSetOf(), // TODO Implement following method to return proper results getXMLDRIs(descriptor, descriptorData).toMutableSet() + visibility = mapOf(platformData to descriptor.visibility) + ) + } + + fun classDescriptor(descriptor: ClassDescriptor, parent: DRIWithPlatformInfo): Class { + val driWithPlatform = parent.dri.withClass(descriptor.name.asString()).withEmptyInfo() + val scope = descriptor.unsubstitutedMemberScope + val descriptorData = descriptor.takeUnless { it.isExpect }?.resolveClassDescriptionData() + val expected = descriptor.takeIf { it.isExpect }?.resolveClassDescriptionData() + val actual = listOfNotNull(descriptorData) + return Class( + dri = driWithPlatform.dri, + name = descriptor.name.asString(), + kind = KotlinClassKindTypes.valueOf(descriptor.kind.toString()), + constructors = descriptor.constructors.map { + visitConstructorDescriptor( + it, + if (it.isPrimary) + DRIWithPlatformInfo( + driWithPlatform.dri, + expected?.info.filterTagWrappers(listOf(Constructor::class)), + actual.filterTagWrappers(listOf(Constructor::class)) + ) + else + DRIWithPlatformInfo(driWithPlatform.dri, null, emptyList()) + ) + }, + functions = scope.functions(driWithPlatform), + properties = scope.properties(driWithPlatform), + classlikes = scope.classlikes(driWithPlatform), + expected = expected, + actual = actual, + extra = mutableSetOf(), // TODO Implement following method to return proper results getXMLDRIs(descriptor, descriptorData).toMutableSet() + visibility = mapOf(platformData to descriptor.visibility) + ) + } + + override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, parent: DRIWithPlatformInfo): Property { + val expected = descriptor.takeIf { it.isExpect }?.resolveDescriptorData() + val actual = listOfNotNull(descriptor.takeUnless { it.isExpect }?.resolveDescriptorData()) + val dri = parent.dri.copy(callable = Callable.from(descriptor)) + + return Property( + dri = dri, + name = descriptor.name.asString(), + receiver = descriptor.extensionReceiverParameter?.let { + visitReceiverParameterDescriptor( + it, + DRIWithPlatformInfo( + dri, + expected?.filterTagWrappers(listOf(Receiver::class)), + actual.filterTagWrappers(listOf(Receiver::class)) + ) + ) + }, + expected = expected, + actual = actual, + accessors = descriptor.accessors.map { visitPropertyAccessorDescriptor(it, descriptor, dri) }, + visibility = mapOf(platformData to descriptor.visibility) + ) + } + + override fun visitFunctionDescriptor(descriptor: FunctionDescriptor, parent: DRIWithPlatformInfo): Function { + val expected = descriptor.takeIf { it.isExpect }?.resolveDescriptorData() + val actual = listOfNotNull(descriptor.takeUnless { it.isExpect }?.resolveDescriptorData()) + val dri = parent.dri.copy(callable = Callable.from(descriptor)) + + return Function( + dri = dri, + name = descriptor.name.asString(), + returnType = descriptor.returnType?.let { KotlinTypeWrapper(it) }, + isConstructor = false, + receiver = descriptor.extensionReceiverParameter?.let { + visitReceiverParameterDescriptor( + it, + DRIWithPlatformInfo( + dri, + expected?.filterTagWrappers(listOf(Receiver::class)), + actual.filterTagWrappers(listOf(Receiver::class)) + ) + ) + }, + parameters = descriptor.valueParameters.mapIndexed { index, desc -> + parameter( + index, desc, + DRIWithPlatformInfo( + dri, + expected.filterTagWrappers(listOf(Param::class), desc.name.asString()), + actual.filterTagWrappers(listOf(Param::class), desc.name.asString()) + ) + ) + }, + expected = expected, + actual = actual, + visibility = mapOf(platformData to descriptor.visibility) + ) + } + + override fun visitConstructorDescriptor(descriptor: ConstructorDescriptor, parent: DRIWithPlatformInfo): Function { + val dri = parent.dri.copy(callable = Callable.from(descriptor)) + return Function( + dri = dri, + name = "", + returnType = KotlinTypeWrapper(descriptor.returnType), + isConstructor = true, + receiver = null, + parameters = descriptor.valueParameters.mapIndexed { index, desc -> + parameter( + index, desc, + DRIWithPlatformInfo( + dri, + parent.expected.filterTagWrappers(listOf(Param::class)), + parent.actual.filterTagWrappers(listOf(Param::class)) + ) + ) + }, + expected = parent.expected ?: descriptor.takeIf { it.isExpect }?.resolveDescriptorData(), + actual = parent.actual, + visibility = mapOf(platformData to descriptor.visibility) + ) + } + + override fun visitReceiverParameterDescriptor( + descriptor: ReceiverParameterDescriptor, + parent: DRIWithPlatformInfo + ) = Parameter( + dri = parent.dri.copy(target = 0), + name = null, + type = KotlinTypeWrapper(descriptor.type), + expected = parent.expected, + actual = parent.actual + ) + + open fun visitPropertyAccessorDescriptor( + descriptor: PropertyAccessorDescriptor, + propertyDescriptor: PropertyDescriptor, + parent: DRI + ): Function { + val dri = parent.copy(callable = Callable.from(descriptor)) + val isGetter = descriptor is PropertyGetterDescriptor + + fun PropertyDescriptor.asParameter(parent: DRI) = + Parameter( + parent.copy(target = 1), + this.name.asString(), + KotlinTypeWrapper(this.type), + descriptor.takeIf { it.isExpect }?.resolveDescriptorData(), + listOfNotNull(descriptor.takeUnless { it.isExpect }?.resolveDescriptorData()) + ) + + val name = run { + val modifier = if (isGetter) "get" else "set" + val rawName = propertyDescriptor.name.asString() + "$modifier${rawName[0].toUpperCase()}${rawName.drop(1)}" + } + + descriptor.visibility + val parameters = + if (isGetter) { + emptyList() + } else { + listOf(propertyDescriptor.asParameter(dri)) + } + + return Function( + dri, + name, + descriptor.returnType?.let { KotlinTypeWrapper(it) }, + false, + null, + parameters, + descriptor.takeIf { it.isExpect }?.resolveDescriptorData(), + listOfNotNull(descriptor.takeUnless { it.isExpect }?.resolveDescriptorData()), + visibility = mapOf(platformData to descriptor.visibility) + ) + } + + private fun parameter(index: Int, descriptor: ValueParameterDescriptor, parent: DRIWithPlatformInfo) = + Parameter( + dri = parent.dri.copy(target = index + 1), + name = descriptor.name.asString(), + type = KotlinTypeWrapper(descriptor.type), + expected = parent.expected, + actual = parent.actual + ) + + private fun MemberScope.functions(parent: DRIWithPlatformInfo): List = + getContributedDescriptors(DescriptorKindFilter.FUNCTIONS) { true } + .filterIsInstance() + .map { visitFunctionDescriptor(it, parent) } + + private fun MemberScope.properties(parent: DRIWithPlatformInfo): List = + getContributedDescriptors(DescriptorKindFilter.VALUES) { true } + .filterIsInstance() + .map { visitPropertyDescriptor(it, parent) } + + private fun MemberScope.classlikes(parent: DRIWithPlatformInfo): List = + getContributedDescriptors(DescriptorKindFilter.CLASSIFIERS) { true } + .filterIsInstance() + .map { visitClassDescriptor(it, parent) } + + private fun DeclarationDescriptor.resolveDescriptorData(): PlatformInfo { + val doc = findKDoc() + val parser = MarkdownParser(resolutionFacade, this) + val docHeader = parser.parseFromKDocTag(doc) + + return BasePlatformInfo(docHeader, listOf(platformData)) + } + + private fun ClassDescriptor.resolveClassDescriptionData(): ClassPlatformInfo { + return ClassPlatformInfo(resolveDescriptorData(), + (getSuperInterfaces() + getAllSuperclassesWithoutAny()).map { DRI.from(it) }) + } + + private fun PlatformInfo?.filterTagWrappers( + types: List>, + name: String? = null + ): PlatformInfo? { + if (this == null) + return null + return BasePlatformInfo( + DocumentationNode( + this.documentationNode.children.filter { it::class in types && (it as? NamedTagWrapper)?.name == name } + ), + this.platformData + ) + } + + private fun List.filterTagWrappers( + types: List>, + name: String? = null + ): List = + this.map { it.filterTagWrappers(types, name)!! } +} + -- cgit From e82beddda7b51f285f0422c6a7078a0a80d54d14 Mon Sep 17 00:00:00 2001 From: Paweł Marks Date: Thu, 13 Feb 2020 16:05:04 +0100 Subject: Adds option to mark extension as fallback --- plugins/base/src/main/kotlin/DokkaBase.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugins/base/src/main') diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index 5c579e54..648acfbb 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -5,7 +5,7 @@ import org.jetbrains.dokka.base.transformers.descriptors.DefaultDescriptorToDocu import org.jetbrains.dokka.plugability.DokkaPlugin class DokkaBase: DokkaPlugin() { - val defaultDescriptorToDocumentationTranslator by extending { + val defaultDescriptorToDocumentationTranslator by extending(isFallback = true) { CoreExtensions.descriptorToDocumentationTranslator providing ::DefaultDescriptorToDocumentationTranslator } } \ No newline at end of file -- cgit From 705c6d45f95408633c71bc0bcd6bc93c9d79a381 Mon Sep 17 00:00:00 2001 From: Paweł Marks Date: Sun, 16 Feb 2020 23:02:30 +0100 Subject: Renames DocumentationMerger and moves it to base plugin --- plugins/base/src/main/kotlin/DokkaBase.kt | 5 + .../documentables/DefaultDocumentableMerger.kt | 116 +++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt (limited to 'plugins/base/src/main') diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index 648acfbb..b18e2ad5 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -2,10 +2,15 @@ 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.plugability.DokkaPlugin class DokkaBase: DokkaPlugin() { val defaultDescriptorToDocumentationTranslator by extending(isFallback = true) { CoreExtensions.descriptorToDocumentationTranslator providing ::DefaultDescriptorToDocumentationTranslator } + + val defaultDocumentableMerger by extending(isFallback = true) { + CoreExtensions.documentableMerger with DefaultDocumentableMerger + } } \ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt new file mode 100644 index 00000000..f2e6f177 --- /dev/null +++ b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt @@ -0,0 +1,116 @@ +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.plugability.DokkaContext +import org.jetbrains.dokka.transformers.documentation.DocumentableMerger +import org.jetbrains.dokka.utilities.pullOutNull + +internal object DefaultDocumentableMerger : DocumentableMerger { + override fun invoke(modules: Collection, context: DokkaContext): Module { + if (!modules.all { it.name == modules.first().name }) + context.logger.error("All module names need to be the same") + return Module( + modules.first().name, + merge( + modules.flatMap { it.packages }, + Package::mergeWith + ) + ) + } +} + +private fun merge(elements: List, reducer: (T, T) -> T): List = + elements.groupingBy { it.dri } + .reduce { _, left, right -> reducer(left, right) } + .values.toList() + +fun PlatformInfo.mergeWith(other: PlatformInfo?) = BasePlatformInfo( + documentationNode, + (platformData + (other?.platformData ?: emptyList())).distinct() +) + +fun ClassPlatformInfo.mergeWith(other: ClassPlatformInfo?) = ClassPlatformInfo( + info.mergeWith(other?.info), + (inherited + (other?.inherited ?: emptyList())).distinct() +) + +fun List.mergeClassPlatformInfo(): List = + groupingBy { it.documentationNode.children + it.inherited }.reduce { _, left, right -> + left.mergeWith(right) + }.values.toList() + +fun List.merge(): List = + groupingBy { it.documentationNode }.reduce { _, left, right -> + left.mergeWith(right) + }.values.toList() + +fun Function.mergeWith(other: Function): Function = Function( + dri, + name, + returnType, + isConstructor, + (receiver to other.receiver).pullOutNull()?.let { (f, s) -> f.mergeWith(s) }, + merge(parameters + other.parameters, Parameter::mergeWith), + expected?.mergeWith(other.expected), + (actual + other.actual).merge(), + visibility = (visibility + other.visibility) +) + +fun Property.mergeWith(other: Property) = Property( + dri, + name, + (receiver to other.receiver).pullOutNull()?.let { (f, s) -> f.mergeWith(s) }, + expected?.mergeWith(other.expected), + (actual + other.actual).merge(), + accessors = (this.accessors + other.accessors).distinct(), + visibility = (visibility + other.visibility) +) + +fun Classlike.mergeWith(other: Classlike): Classlike = when { + this is Class && other is Class -> mergeWith(other) + this is Enum && other is Enum -> mergeWith(other) + else -> throw IllegalStateException("${this::class.qualifiedName} ${this.name} cannot be merged with ${other::class.qualifiedName} ${other.name}") +} + +fun Class.mergeWith(other: Class) = Class( + dri = dri, + name = name, + kind = kind, + constructors = merge(constructors + other.constructors, Function::mergeWith), + functions = merge(functions + other.functions, Function::mergeWith), + properties = merge(properties + other.properties, Property::mergeWith), + classlikes = merge(classlikes + other.classlikes, Classlike::mergeWith), + expected = expected?.mergeWith(other.expected), + actual = (actual + other.actual).mergeClassPlatformInfo(), + visibility = (visibility + other.visibility) +) + +fun Enum.mergeWith(other: Enum) = Enum( + dri = dri, + name = name, + functions = merge(functions + other.functions, Function::mergeWith), + properties = merge(properties + other.properties, Property::mergeWith), + classlikes = merge(classlikes + other.classlikes, Classlike::mergeWith), + expected = expected?.mergeWith(other.expected), + actual = (actual + other.actual).mergeClassPlatformInfo(), + entries = (this.entries + other.entries.distinctBy { it.dri }.toList()), + constructors = merge(constructors + other.constructors, Function::mergeWith), + visibility = visibility +) + +fun Parameter.mergeWith(other: Parameter) = Parameter( + dri, + name, + type, + expected?.mergeWith(other.expected), + (actual + other.actual).merge() +) + +fun Package.mergeWith(other: Package): Package = Package( + dri, + merge(functions + other.functions, Function::mergeWith), + merge(properties + other.properties, Property::mergeWith), + merge(classlikes + other.classlikes, Classlike::mergeWith) +) \ No newline at end of file -- cgit From 3b200cf10e0c50c2eee4b9da3f7039d678fa4aad Mon Sep 17 00:00:00 2001 From: Paweł Marks Date: Sun, 16 Feb 2020 23:20:17 +0100 Subject: Renames DocumentationToPagesTranslatero and moves its implementation to base plugin --- plugins/base/src/main/kotlin/DokkaBase.kt | 9 +- .../DefaultDocumentablesToPageTranslator.kt | 22 +++ .../transformers/documentables/PageBuilder.kt | 159 +++++++++++++++ .../documentables/PageContentBuilder.kt | 217 +++++++++++++++++++++ 4 files changed, 405 insertions(+), 2 deletions(-) create mode 100644 plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentablesToPageTranslator.kt create mode 100644 plugins/base/src/main/kotlin/transformers/documentables/PageBuilder.kt create mode 100644 plugins/base/src/main/kotlin/transformers/documentables/PageContentBuilder.kt (limited to 'plugins/base/src/main') 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 ?: "") + 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, + protected val platformData: Set, + protected val kind: Kind, + protected val commentsConverter: CommentsToContentConverter, + val logger: DokkaLogger, + protected val styles: Set