aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/base/src')
-rw-r--r--plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt4
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt19
-rw-r--r--plugins/base/src/main/kotlin/transformers/pages/merger/SameMethodNamePageMergerStrategy.kt8
-rw-r--r--plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt14
-rw-r--r--plugins/base/src/main/kotlin/transformers/pages/sourcelinks/SourceLinksTransformer.kt48
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt519
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt39
-rw-r--r--plugins/base/src/test/kotlin/content/functions/ContentForBriefTest.kt10
-rw-r--r--plugins/base/src/test/kotlin/content/functions/ContentForConstructors.kt2
-rw-r--r--plugins/base/src/test/kotlin/locationProvider/DokkaLocationProviderTest.kt5
-rw-r--r--plugins/base/src/test/kotlin/transformers/MergeImplicitExpectActualDeclarationsTest.kt352
11 files changed, 784 insertions, 236 deletions
diff --git a/plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt b/plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt
index 21757d70..8ea8818d 100644
--- a/plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt
+++ b/plugins/base/src/main/kotlin/DokkaBaseConfiguration.kt
@@ -8,12 +8,14 @@ data class DokkaBaseConfiguration(
var customStyleSheets: List<File> = defaultCustomStyleSheets,
var customAssets: List<File> = defaultCustomAssets,
var separateInheritedMembers: Boolean = separateInheritedMembersDefault,
- var footerMessage: String = defaultFooterMessage
+ var footerMessage: String = defaultFooterMessage,
+ var mergeImplicitExpectActualDeclarations: Boolean = mergeImplicitExpectActualDeclarationsDefault
) : ConfigurableBlock {
companion object {
val defaultFooterMessage = "© ${Year.now().value} Copyright"
val defaultCustomStyleSheets: List<File> = emptyList()
val defaultCustomAssets: List<File> = emptyList()
const val separateInheritedMembersDefault: Boolean = false
+ const val mergeImplicitExpectActualDeclarationsDefault: Boolean = false
}
} \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
index 43526dc3..3297d09f 100644
--- a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
@@ -1,14 +1,14 @@
package org.jetbrains.dokka.base.renderers.html
-import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.DokkaBaseConfiguration
import org.jetbrains.dokka.base.renderers.sourceSets
-import org.jetbrains.dokka.base.templating.AddToSearch
import org.jetbrains.dokka.base.templating.AddToSourcesetDependencies
import org.jetbrains.dokka.base.templating.toJsonString
-import org.jetbrains.dokka.links.DRI
-import org.jetbrains.dokka.model.*
+import org.jetbrains.dokka.model.DEnum
+import org.jetbrains.dokka.model.DEnumEntry
+import org.jetbrains.dokka.model.DFunction
+import org.jetbrains.dokka.model.withDescendants
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.configuration
@@ -30,19 +30,18 @@ abstract class NavigationDataProvider {
when {
this !is ClasslikePageNode ->
children.filterIsInstance<ContentPage>().map { visit(it) }
- documentable is DEnum ->
- children.filter { it is ContentPage && it.documentable is DEnumEntry }.map { visit(it as ContentPage) }
+ documentables.any { it is DEnum } ->
+ children.filter { it is WithDocumentables && it.documentables.any { it is DEnumEntry } }
+ .map { visit(it as ContentPage) }
else -> emptyList()
}.sortedBy { it.name.toLowerCase() }
/**
- * Parenthesis is applied in 2 cases:
+ * Parenthesis is applied in 1 case:
* - page only contains functions (therefore documentable from this page is [DFunction])
- * - page merges only functions (documentable is null because [SameMethodNamePageMergerStrategy][org.jetbrains.dokka.base.transformers.pages.merger.SameMethodNamePageMergerStrategy]
- * removes it from page)
*/
private val ContentPage.displayableName: String
- get() = if (documentable is DFunction || (documentable == null && dri.all { it.callable != null })) {
+ get() = if (this is WithDocumentables && documentables.all { it is DFunction }) {
"$name()"
} else {
name
diff --git a/plugins/base/src/main/kotlin/transformers/pages/merger/SameMethodNamePageMergerStrategy.kt b/plugins/base/src/main/kotlin/transformers/pages/merger/SameMethodNamePageMergerStrategy.kt
index 2fb70fc8..6c12c719 100644
--- a/plugins/base/src/main/kotlin/transformers/pages/merger/SameMethodNamePageMergerStrategy.kt
+++ b/plugins/base/src/main/kotlin/transformers/pages/merger/SameMethodNamePageMergerStrategy.kt
@@ -23,7 +23,7 @@ class SameMethodNamePageMergerStrategy(val logger: DokkaLogger) : PageMergerStra
children = members.flatMap { it.children }.distinct(),
content = squashDivergentInstances(members).withSourceSets(members.allSourceSets()),
embeddedResources = members.flatMap { it.embeddedResources }.distinct(),
- documentable = null
+ documentables = members.flatMap { it.documentables }
)
return (pages - members) + listOf(merged)
@@ -37,9 +37,9 @@ class SameMethodNamePageMergerStrategy(val logger: DokkaLogger) : PageMergerStra
.reduce { acc, node ->
acc.mapTransform<ContentDivergentGroup, ContentNode> { g ->
g.copy(children = (g.children +
- (node.dfs { it is ContentDivergentGroup && it.groupID == g.groupID } as? ContentDivergentGroup)
- ?.children?.single()
- ).filterNotNull()
+ ((node.dfs { it is ContentDivergentGroup && it.groupID == g.groupID } as? ContentDivergentGroup)
+ ?.children ?: emptyList())
+ )
)
}
}
diff --git a/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt b/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt
index 3ff7a77d..db133bb8 100644
--- a/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt
+++ b/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt
@@ -35,14 +35,18 @@ abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer {
"<script src=\"https://unpkg.com/kotlin-playground@1\"></script>"
return input.transformContentPagesTree { page ->
- page.documentable?.documentation?.entries?.fold(page) { acc, entry ->
- entry.value.children.filterIsInstance<Sample>().fold(acc) { acc, sample ->
+ val samples = (page as? WithDocumentables)?.documentables?.flatMap {
+ it.documentation.entries.flatMap { entry ->
+ entry.value.children.filterIsInstance<Sample>().map { entry.key to it }
+ }
+ }
+
+ samples?.fold(page as ContentPage) { acc, (sampleSourceSet, sample) ->
acc.modified(
- content = acc.content.addSample(page, entry.key, sample.name, analysis),
+ content = acc.content.addSample(page, sampleSourceSet, sample.name, analysis),
embeddedResources = acc.embeddedResources + kotlinPlaygroundScript
)
- }
- } ?: page
+ } ?: page
}
}
diff --git a/plugins/base/src/main/kotlin/transformers/pages/sourcelinks/SourceLinksTransformer.kt b/plugins/base/src/main/kotlin/transformers/pages/sourcelinks/SourceLinksTransformer.kt
index f66ff222..93305055 100644
--- a/plugins/base/src/main/kotlin/transformers/pages/sourcelinks/SourceLinksTransformer.kt
+++ b/plugins/base/src/main/kotlin/transformers/pages/sourcelinks/SourceLinksTransformer.kt
@@ -1,15 +1,15 @@
package org.jetbrains.dokka.base.transformers.pages.sourcelinks
-import com.intellij.psi.PsiElement
import com.intellij.psi.PsiDocumentManager
+import com.intellij.psi.PsiElement
import org.jetbrains.dokka.DokkaConfiguration
-import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder
-import org.jetbrains.dokka.model.DocumentableSource
import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
import org.jetbrains.dokka.analysis.DescriptorDocumentableSource
import org.jetbrains.dokka.analysis.PsiDocumentableSource
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint
+import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder
+import org.jetbrains.dokka.model.DocumentableSource
import org.jetbrains.dokka.model.WithSources
import org.jetbrains.dokka.model.toDisplaySourceSets
import org.jetbrains.dokka.pages.*
@@ -32,8 +32,9 @@ class SourceLinksTransformer(val context: DokkaContext) : PageTransformer {
override fun invoke(input: RootPageNode) =
input.transformContentPagesTree { node ->
- when (val documentable = node.documentable) {
- is WithSources -> resolveSources(documentable)
+ when (node) {
+ is WithDocumentables ->
+ node.documentables.filterIsInstance<WithSources>().flatMap { resolveSources(it) }
.takeIf { it.isNotEmpty() }
?.let { node.addSourcesContent(it) }
?: node
@@ -65,23 +66,26 @@ class SourceLinksTransformer(val context: DokkaContext) : PageTransformer {
private fun PageContentBuilder.buildSourcesContent(
node: ContentPage,
sources: List<Pair<DokkaSourceSet, String>>
- ) = contentFor(
- node.dri.first(),
- node.documentable!!.sourceSets.toSet()
- ) {
- header(2, "Sources", kind = ContentKind.Source)
- +ContentTable(
- header = emptyList(),
- children = sources.map {
- buildGroup(node.dri, setOf(it.first), kind = ContentKind.Source, extra = mainExtra + SymbolAnchorHint(it.second, ContentKind.Source)) {
- link("${it.first.displayName} source", it.second)
- }
- },
- dci = DCI(node.dri, ContentKind.Source),
- sourceSets = node.documentable!!.sourceSets.toDisplaySourceSets(),
- style = emptySet(),
- extra = mainExtra + SimpleAttr.header("Sources")
- )
+ ): ContentGroup {
+ val documentables = (node as? WithDocumentables)?.documentables.orEmpty()
+ return contentFor(
+ node.dri,
+ documentables.flatMap { it.sourceSets }.toSet()
+ ) {
+ header(2, "Sources", kind = ContentKind.Source)
+ +ContentTable(
+ header = emptyList(),
+ children = sources.map {
+ buildGroup(node.dri, setOf(it.first), kind = ContentKind.Source, extra = mainExtra + SymbolAnchorHint(it.second, ContentKind.Source)) {
+ link("${it.first.displayName} source", it.second)
+ }
+ },
+ dci = DCI(node.dri, ContentKind.Source),
+ sourceSets = documentables.flatMap { it.sourceSets }.toDisplaySourceSets(),
+ style = emptySet(),
+ extra = mainExtra + SimpleAttr.header("Sources")
+ )
+ }
}
private fun DocumentableSource.toLink(sourceLink: SourceLink): String {
diff --git a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
index e2aca6f9..c5136c27 100644
--- a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
+++ b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
@@ -1,9 +1,14 @@
package org.jetbrains.dokka.base.translators.documentables
+import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
+import org.jetbrains.dokka.base.DokkaBaseConfiguration
+import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint
import org.jetbrains.dokka.base.signatures.SignatureProvider
import org.jetbrains.dokka.base.transformers.documentables.CallableExtensions
+import org.jetbrains.dokka.base.transformers.documentables.ClashingDriIdentifier
import org.jetbrains.dokka.base.transformers.documentables.InheritorsInfo
import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter
+import org.jetbrains.dokka.base.transformers.pages.tags.CustomTagContentProvider
import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder.DocumentableContentBuilder
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.model.*
@@ -15,11 +20,6 @@ import org.jetbrains.dokka.utilities.DokkaLogger
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import kotlin.reflect.KClass
import kotlin.reflect.full.isSubclassOf
-import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet
-import org.jetbrains.dokka.base.DokkaBaseConfiguration
-import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint
-import org.jetbrains.dokka.base.transformers.documentables.ClashingDriIdentifier
-import org.jetbrains.dokka.base.transformers.pages.tags.CustomTagContentProvider
private typealias GroupedTags = Map<KClass<out TagWrapper>, List<Pair<DokkaSourceSet?, TagWrapper>>>
@@ -35,66 +35,139 @@ open class DefaultPageCreator(
) {
protected open val contentBuilder = PageContentBuilder(commentsToContentConverter, signatureProvider, logger)
+ protected val mergeImplicitExpectActualDeclarations =
+ configuration?.mergeImplicitExpectActualDeclarations
+ ?: DokkaBaseConfiguration.mergeImplicitExpectActualDeclarationsDefault
+
protected val separateInheritedMembers =
configuration?.separateInheritedMembers ?: DokkaBaseConfiguration.separateInheritedMembersDefault
- open fun pageForModule(m: DModule) =
- ModulePageNode(m.name.ifEmpty { "<root>" }, contentForModule(m), m, m.packages.map(::pageForPackage))
+ open fun pageForModule(m: DModule): ModulePageNode =
+ ModulePageNode(m.name.ifEmpty { "<root>" }, contentForModule(m), listOf(m), m.packages.map(::pageForPackage))
open fun pageForPackage(p: DPackage): PackagePageNode = PackagePageNode(
- p.name, contentForPackage(p), setOf(p.dri), p,
- p.classlikes.renameClashingDocumentable().map(::pageForClasslike) +
- p.functions.renameClashingDocumentable()
- .map(::pageForFunction) + p.properties.mapNotNull(::pageForProperty)
+ p.name, contentForPackage(p), setOf(p.dri), listOf(p),
+ if (mergeImplicitExpectActualDeclarations)
+ p.classlikes.mergeClashingDocumentable().map(::pageForClasslikes) +
+ p.functions.mergeClashingDocumentable().map(::pageForFunctions) +
+ p.properties.mergeClashingDocumentable().map(::pageForProperties)
+ else
+ p.classlikes.renameClashingDocumentable().map(::pageForClasslike) +
+ p.functions.renameClashingDocumentable().map(::pageForFunction) +
+ p.properties.mapNotNull(::pageForProperty)
)
- open fun pageForEnumEntry(e: DEnumEntry): ClasslikePageNode =
- ClasslikePageNode(
- e.nameAfterClash(), contentForEnumEntry(e), setOf(e.dri), e,
- e.classlikes.renameClashingDocumentable().map(::pageForClasslike) +
- e.filteredFunctions.renameClashingDocumentable().map(::pageForFunction) +
- e.filteredProperties.renameClashingDocumentable().mapNotNull(::pageForProperty)
- )
+ open fun pageForEnumEntry(e: DEnumEntry): ClasslikePageNode = pageForEnumEntries(listOf(e))
- open fun pageForClasslike(c: DClasslike): ClasslikePageNode {
- val constructors = if (c is WithConstructors) c.constructors else emptyList()
+ open fun pageForClasslike(c: DClasslike): ClasslikePageNode = pageForClasslikes(listOf(c))
+
+ open fun pageForEnumEntries(documentables: List<DEnumEntry>): ClasslikePageNode {
+ val dri = documentables.dri.also {
+ if (it.size != 1) {
+ logger.error("Documentable dri should have the same one ${it.first()} inside the one page!")
+ }
+ }
+
+ val classlikes = documentables.flatMap { it.classlikes }
+ val functions = documentables.flatMap { it.filteredFunctions }
+ val props = documentables.flatMap { it.filteredProperties }
+
+ val childrenPages = if (mergeImplicitExpectActualDeclarations)
+ functions.mergeClashingDocumentable().map(::pageForFunctions) +
+ props.mergeClashingDocumentable().map(::pageForProperties)
+ else
+ classlikes.renameClashingDocumentable().map(::pageForClasslike) +
+ functions.renameClashingDocumentable().map(::pageForFunction) +
+ props.renameClashingDocumentable().mapNotNull(::pageForProperty)
return ClasslikePageNode(
- c.nameAfterClash(), contentForClasslike(c), setOf(c.dri), c,
- constructors.map(::pageForFunction) +
- c.classlikes.renameClashingDocumentable().map(::pageForClasslike) +
- c.filteredFunctions.renameClashingDocumentable().map(::pageForFunction) +
- c.filteredProperties.renameClashingDocumentable().mapNotNull(::pageForProperty) +
- if (c is DEnum) c.entries.map(::pageForEnumEntry) else emptyList()
+ documentables.first().nameAfterClash(), contentForClasslikesAndEntries(documentables), dri, documentables,
+ childrenPages
+ )
+ }
+
+ open fun pageForClasslikes(documentables: List<DClasslike>): ClasslikePageNode {
+ val dri = documentables.dri.also {
+ if (it.size != 1) {
+ logger.error("Documentable dri should have the same one ${it.first()} inside the one page!")
+ }
+ }
+
+ val constructors = documentables.flatMap { if (it is WithConstructors) it.constructors else emptyList() }
+
+ val classlikes = documentables.flatMap { it.classlikes }
+ val functions = documentables.flatMap { it.filteredFunctions }
+ val props = documentables.flatMap { it.filteredProperties }
+ val entries = documentables.flatMap { if (it is DEnum) it.entries else emptyList() }
+
+ val childrenPages = constructors.map(::pageForFunction) +
+ if (mergeImplicitExpectActualDeclarations)
+ classlikes.mergeClashingDocumentable().map(::pageForClasslikes) +
+ functions.mergeClashingDocumentable().map(::pageForFunctions) +
+ props.mergeClashingDocumentable().map(::pageForProperties) +
+ entries.mergeClashingDocumentable().map(::pageForEnumEntries)
+ else
+ classlikes.renameClashingDocumentable().map(::pageForClasslike) +
+ functions.renameClashingDocumentable().map(::pageForFunction) +
+ props.renameClashingDocumentable().mapNotNull(::pageForProperty) +
+ entries.renameClashingDocumentable().map(::pageForEnumEntry)
+
+ return ClasslikePageNode(
+ documentables.first().nameAfterClash(), contentForClasslikesAndEntries(documentables), dri, documentables,
+ childrenPages
)
}
private fun <T> T.toClashedName() where T : Documentable, T : WithExtraProperties<T> =
(extra[ClashingDriIdentifier]?.value?.joinToString(", ", "[", "]") { it.displayName } ?: "") + name.orEmpty()
- @Suppress("UNCHECKED_CAST")
private fun <T : Documentable> List<T>.renameClashingDocumentable(): List<T> =
groupBy { it.dri }.values.flatMap { elements ->
if (elements.size == 1) elements else elements.mapNotNull { element ->
- when (element) {
- is DClass -> element.copy(extra = element.extra + DriClashAwareName(element.toClashedName()))
- is DObject -> element.copy(extra = element.extra + DriClashAwareName(element.toClashedName()))
- is DAnnotation -> element.copy(extra = element.extra + DriClashAwareName(element.toClashedName()))
- is DInterface -> element.copy(extra = element.extra + DriClashAwareName(element.toClashedName()))
- is DEnum -> element.copy(extra = element.extra + DriClashAwareName(element.toClashedName()))
- is DFunction -> element.copy(extra = element.extra + DriClashAwareName(element.toClashedName()))
- is DProperty -> element.copy(extra = element.extra + DriClashAwareName(element.toClashedName()))
- is DTypeAlias -> element.copy(extra = element.extra + DriClashAwareName(element.toClashedName()))
- else -> null
- } as? T?
+ element.renameClashingDocumentable()
}
}
- open fun pageForFunction(f: DFunction) = MemberPageNode(f.nameAfterClash(), contentForFunction(f), setOf(f.dri), f)
+ @Suppress("UNCHECKED_CAST")
+ private fun <T : Documentable> T.renameClashingDocumentable(): T? = when (this) {
+ is DClass -> copy(extra = this.extra + DriClashAwareName(this.toClashedName()))
+ is DObject -> copy(extra = this.extra + DriClashAwareName(this.toClashedName()))
+ is DAnnotation -> copy(extra = this.extra + DriClashAwareName(this.toClashedName()))
+ is DInterface -> copy(extra = this.extra + DriClashAwareName(this.toClashedName()))
+ is DEnum -> copy(extra = this.extra + DriClashAwareName(this.toClashedName()))
+ is DFunction -> copy(extra = this.extra + DriClashAwareName(this.toClashedName()))
+ is DProperty -> copy(extra = this.extra + DriClashAwareName(this.toClashedName()))
+ is DTypeAlias -> copy(extra = this.extra + DriClashAwareName(this.toClashedName()))
+ else -> null
+ } as? T?
+
+ private fun <T : Documentable> List<T>.mergeClashingDocumentable(): List<List<T>> =
+ groupBy { it.dri }.values.toList()
+
+ open fun pageForFunction(f: DFunction) =
+ MemberPageNode(f.nameAfterClash(), contentForFunction(f), setOf(f.dri), listOf(f))
+
+ open fun pageForFunctions(fs: List<DFunction>): MemberPageNode {
+ val dri = fs.dri.also {
+ if (it.size != 1) {
+ logger.error("Function dri should have the same one ${it.first()} inside the one page!")
+ }
+ }
+ return MemberPageNode(fs.first().nameAfterClash(), contentForMembers(fs), dri, fs)
+ }
open fun pageForProperty(p: DProperty): MemberPageNode? =
- MemberPageNode(p.nameAfterClash(), contentForProperty(p), setOf(p.dri), p)
+ MemberPageNode(p.nameAfterClash(), contentForProperty(p), setOf(p.dri), listOf(p))
+
+ open fun pageForProperties(ps: List<DProperty>): MemberPageNode {
+ val dri = ps.dri.also {
+ if (it.size != 1) {
+ logger.error("Property dri should have the same one ${it.first()} inside the one page!")
+ }
+ }
+ return MemberPageNode(ps.first().nameAfterClash(), contentForMembers(ps), dri, ps)
+ }
private fun <T> T.isInherited(): Boolean where T : Documentable, T : WithExtraProperties<T> =
sourceSets.all { sourceSet -> extra[InheritedMember]?.isInherited(sourceSet) == true }
@@ -168,148 +241,193 @@ open class DefaultPageCreator(
}
}
+ protected open fun contentForScopes(
+ scopes: List<WithScope>,
+ sourceSets: Set<DokkaSourceSet>
+ ): ContentGroup {
+ val types = scopes.flatMap { it.classlikes } + scopes.filterIsInstance<DPackage>().flatMap { it.typealiases }
+ val inheritors = scopes.fold(mutableMapOf<DokkaSourceSet, List<DRI>>()) { acc, scope ->
+ val inheritorsForScope =
+ scope.safeAs<WithExtraProperties<Documentable>>()?.let { it.extra[InheritorsInfo] }?.let { inheritors ->
+ inheritors.value.filter { it.value.isNotEmpty() }
+ }.orEmpty()
+ inheritorsForScope.forEach { (k, v) ->
+ acc.compute(k) { _, value -> value?.plus(v) ?: v }
+ }
+ acc
+ }
+
+ return contentForScope(
+ @Suppress("UNCHECKED_CAST")
+ (scopes as List<Documentable>).dri,
+ sourceSets,
+ types,
+ scopes.flatMap { it.functions },
+ scopes.flatMap { it.properties },
+ inheritors
+ )
+ }
+
protected open fun contentForScope(
s: WithScope,
dri: DRI,
sourceSets: Set<DokkaSourceSet>
- ) = contentBuilder.contentFor(s as Documentable) {
+ ): ContentGroup {
val types = listOf(
s.classlikes,
(s as? DPackage)?.typealiases ?: emptyList()
).flatten()
+ val inheritors =
+ s.safeAs<WithExtraProperties<Documentable>>()?.let { it.extra[InheritorsInfo] }?.let { inheritors ->
+ inheritors.value.filter { it.value.isNotEmpty() }
+ }.orEmpty()
+
+ return contentForScope(setOf(dri), sourceSets, types, s.functions, s.properties, inheritors)
+ }
+
+ protected open fun contentForScope(
+ dri: Set<DRI>,
+ sourceSets: Set<DokkaSourceSet>,
+ types: List<Documentable>,
+ functions: List<DFunction>,
+ properties: List<DProperty>,
+ inheritors: SourceSetDependent<List<DRI>>
+ ) = contentBuilder.contentFor(dri, sourceSets) {
divergentBlock("Types", types, ContentKind.Classlikes, extra = mainExtra + SimpleAttr.header("Types"))
if (separateInheritedMembers) {
- val (inheritedFunctions, memberFunctions) = s.functions.splitInherited()
- val (inheritedProperties, memberProperties) = s.properties.splitInherited()
+ val (inheritedFunctions, memberFunctions) = functions.splitInherited()
+ val (inheritedProperties, memberProperties) = properties.splitInherited()
propertiesBlock("Properties", memberProperties, sourceSets)
propertiesBlock("Inherited properties", inheritedProperties, sourceSets)
functionsBlock("Functions", memberFunctions)
functionsBlock("Inherited functions", inheritedFunctions)
} else {
- functionsBlock("Functions", s.functions)
- propertiesBlock("Properties", s.properties, sourceSets)
+ functionsBlock("Functions", functions)
+ propertiesBlock("Properties", properties, sourceSets)
}
- s.safeAs<WithExtraProperties<Documentable>>()?.let { it.extra[InheritorsInfo] }?.let { inheritors ->
- val map = inheritors.value.filter { it.value.isNotEmpty() }
- if (map.values.any()) {
- header(2, "Inheritors") { }
- +ContentTable(
- header = listOf(contentBuilder.contentFor(mainDRI, mainSourcesetData) {
- text("Name")
- }),
- children = map.entries.flatMap { entry -> entry.value.map { Pair(entry.key, it) } }
- .groupBy({ it.second }, { it.first }).map { (classlike, platforms) ->
- val label = classlike.classNames?.substringAfterLast(".") ?: classlike.toString()
- .also { logger.warn("No class name found for DRI $classlike") }
- buildGroup(
- setOf(classlike),
- platforms.toSet(),
- ContentKind.Inheritors,
- extra = mainExtra + SymbolAnchorHint(label, ContentKind.Inheritors)
- ) {
- link(label, classlike)
- }
- },
- dci = DCI(setOf(dri), ContentKind.Inheritors),
- sourceSets = sourceSets.toDisplaySourceSets(),
- style = emptySet(),
- extra = mainExtra + SimpleAttr.header("Inheritors")
- )
- }
+ if (inheritors.values.any()) {
+ header(2, "Inheritors") { }
+ +ContentTable(
+ header = listOf(contentBuilder.contentFor(mainDRI, mainSourcesetData) {
+ text("Name")
+ }),
+ children = inheritors.entries.flatMap { entry -> entry.value.map { Pair(entry.key, it) } }
+ .groupBy({ it.second }, { it.first }).map { (classlike, platforms) ->
+ val label = classlike.classNames?.substringAfterLast(".") ?: classlike.toString()
+ .also { logger.warn("No class name found for DRI $classlike") }
+ buildGroup(
+ setOf(classlike),
+ platforms.toSet(),
+ ContentKind.Inheritors,
+ extra = mainExtra + SymbolAnchorHint(label, ContentKind.Inheritors)
+ ) {
+ link(label, classlike)
+ }
+ },
+ dci = DCI(dri, ContentKind.Inheritors),
+ sourceSets = sourceSets.toDisplaySourceSets(),
+ style = emptySet(),
+ extra = mainExtra + SimpleAttr.header("Inheritors")
+ )
}
}
private fun Iterable<DFunction>.sorted() =
sortedWith(compareBy({ it.name }, { it.parameters.size }, { it.dri.toString() }))
- protected open fun contentForEnumEntry(e: DEnumEntry) = contentBuilder.contentFor(e) {
- group(kind = ContentKind.Cover) {
- cover(e.name)
- sourceSetDependentHint(e.dri, e.sourceSets.toSet()) {
- +buildSignature(e)
- +contentForDescription(e)
- }
- }
- group(styles = setOf(ContentStyle.TabbedContent)) {
- +contentForComments(e)
- +contentForScope(e, e.dri, e.sourceSets)
- }
- }
-
- protected open fun contentForClasslike(c: DClasslike) = contentBuilder.contentFor(c) {
- @Suppress("UNCHECKED_CAST")
- val extensions = (c as WithExtraProperties<DClasslike>)
- .extra[CallableExtensions]?.extensions
- ?.filterIsInstance<Documentable>().orEmpty()
- // Extensions are added to sourceSets since they can be placed outside the sourceSets from classlike
- // Example would be an Interface in common and extension function in jvm
- group(kind = ContentKind.Cover, sourceSets = mainSourcesetData + extensions.sourceSets) {
- cover(c.name.orEmpty())
- sourceSetDependentHint(c.dri, c.sourceSets) {
- +buildSignature(c)
- +contentForDescription(c)
+ /**
+ * @param documentables a list of [DClasslike] and [DEnumEntry] with the same dri in different sourceSets
+ */
+ protected open fun contentForClasslikesAndEntries(documentables: List<Documentable>): ContentGroup =
+ contentBuilder.contentFor(documentables.dri, documentables.sourceSets) {
+ val classlikes = documentables.filterIsInstance<DClasslike>()
+
+ @Suppress("UNCHECKED_CAST")
+ val extensions = (classlikes as List<WithExtraProperties<DClasslike>>).flatMap {
+ it.extra[CallableExtensions]?.extensions
+ ?.filterIsInstance<Documentable>().orEmpty()
}
- }
- group(styles = setOf(ContentStyle.TabbedContent), sourceSets = mainSourcesetData + extensions.sourceSets) {
- +contentForComments(c)
- if (c is WithConstructors) {
- block(
- "Constructors",
- 2,
- ContentKind.Constructors,
- c.constructors,
- c.sourceSets,
- needsAnchors = true,
- extra = PropertyContainer.empty<ContentNode>() + SimpleAttr.header("Constructors")
- ) {
- link(it.name, it.dri, kind = ContentKind.Main, styles = setOf(ContentStyle.RowTitle))
- sourceSetDependentHint(
- it.dri,
- it.sourceSets.toSet(),
- kind = ContentKind.SourceSetDependentHint,
- styles = emptySet(),
- extra = PropertyContainer.empty()
- ) {
+ // Extensions are added to sourceSets since they can be placed outside the sourceSets from classlike
+ // Example would be an Interface in common and extension function in jvm
+ group(kind = ContentKind.Cover, sourceSets = mainSourcesetData + extensions.sourceSets) {
+ cover(documentables.first().name.orEmpty())
+ sourceSetDependentHint(documentables.dri, documentables.sourceSets) {
+ documentables.forEach {
+buildSignature(it)
- contentForBrief(it)
+ +contentForDescription(it)
}
}
}
- if (c is DEnum) {
- block(
- "Entries",
- 2,
- ContentKind.Classlikes,
- c.entries,
- c.sourceSets.toSet(),
- needsSorting = false,
- needsAnchors = true,
- extra = mainExtra + SimpleAttr.header("Entries"),
- styles = emptySet()
- ) {
- link(it.name, it.dri)
- sourceSetDependentHint(
- it.dri,
- it.sourceSets.toSet(),
- kind = ContentKind.SourceSetDependentHint,
- extra = PropertyContainer.empty()
- ) {
- +buildSignature(it)
- contentForBrief(it)
+
+ group(styles = setOf(ContentStyle.TabbedContent), sourceSets = mainSourcesetData + extensions.sourceSets) {
+ +contentForComments(documentables)
+ val csWithConstructor = classlikes.filterIsInstance<WithConstructors>()
+ if (csWithConstructor.isNotEmpty()) {
+ val constructorsToDocumented = csWithConstructor.flatMap { it.constructors }
+ multiBlock(
+ "Constructors",
+ 2,
+ ContentKind.Constructors,
+ constructorsToDocumented.groupBy { it.parameters.map { it.dri } }
+ .map { (_, v) -> v.first().name to v },
+ @Suppress("UNCHECKED_CAST")
+ (csWithConstructor as List<Documentable>).sourceSets,
+ needsAnchors = true,
+ extra = PropertyContainer.empty<ContentNode>() + SimpleAttr.header("Constructors")
+ ) { key, ds ->
+ link(key, ds.first().dri, kind = ContentKind.Main, styles = setOf(ContentStyle.RowTitle))
+ sourceSetDependentHint(
+ ds.dri,
+ ds.sourceSets,
+ kind = ContentKind.SourceSetDependentHint,
+ styles = emptySet(),
+ extra = PropertyContainer.empty<ContentNode>()
+ ) {
+ ds.forEach {
+ +buildSignature(it)
+ contentForBrief(it)
+ }
+ }
}
}
- }
- +contentForScope(c, c.dri, c.sourceSets)
+ val csEnum = classlikes.filterIsInstance<DEnum>()
+ if (csEnum.isNotEmpty()) {
+ multiBlock(
+ "Entries",
+ 2,
+ ContentKind.Classlikes,
+ csEnum.flatMap { it.entries }.groupBy { it.name }.toList(),
+ csEnum.sourceSets,
+ needsSorting = false,
+ needsAnchors = true,
+ extra = mainExtra + SimpleAttr.header("Entries"),
+ styles = emptySet()
+ ) { key, ds ->
+ link(key, ds.first().dri)
+ sourceSetDependentHint(
+ ds.dri,
+ ds.sourceSets,
+ kind = ContentKind.SourceSetDependentHint,
+ extra = PropertyContainer.empty<ContentNode>()
+ ) {
+ ds.forEach {
+ +buildSignature(it)
+ contentForBrief(it)
+ }
+ }
+ }
+ }
+ +contentForScopes(documentables.filterIsInstance<WithScope>(), documentables.sourceSets)
- divergentBlock(
- "Extensions",
- extensions,
- ContentKind.Extensions,
- extra = mainExtra + SimpleAttr.header("Extensions")
- )
+ divergentBlock(
+ "Extensions",
+ extensions,
+