aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin/translators
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/base/src/main/kotlin/translators')
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt405
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/DescriptionSections.kt2
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt52
3 files changed, 273 insertions, 186 deletions
diff --git a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
index 6006af5b..a9c6dcca 100644
--- a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
+++ b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
@@ -18,6 +18,7 @@ import org.jetbrains.dokka.model.properties.PropertyContainer
import org.jetbrains.dokka.model.properties.WithExtraProperties
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.utilities.DokkaLogger
+import java.util.Comparator
import kotlin.reflect.KClass
internal typealias GroupedTags = Map<KClass<out TagWrapper>, List<Pair<DokkaSourceSet?, TagWrapper>>>
@@ -90,7 +91,7 @@ open class DefaultPageCreator(
}
val constructors =
- if (documentables.shouldRenderConstructors()) {
+ if (documentables.shouldDocumentConstructors()) {
documentables.flatMap { (it as? WithConstructors)?.constructors ?: emptyList() }
} else {
emptyList()
@@ -179,6 +180,22 @@ open class DefaultPageCreator(
private val WithScope.filteredProperties: List<DProperty>
get() = properties.filterNot { it.isInherited() }
+ private fun Collection<Documentable>.splitPropsAndFuns(): Pair<List<DProperty>, List<DFunction>> {
+ val first = ArrayList<DProperty>()
+ val second = ArrayList<DFunction>()
+ for (element in this) {
+ when (element) {
+ is DProperty -> first.add(element)
+ is DFunction -> second.add(element)
+ else -> throw IllegalStateException("Expected only properties or functions")
+ }
+ }
+ return Pair(first, second)
+ }
+
+ private fun <T> Collection<T>.splitInheritedExtension(dri: Set<DRI>): Pair<List<T>, List<T>> where T : org.jetbrains.dokka.model.Callable =
+ partition { it.receiver?.dri !in dri }
+
private fun <T> Collection<T>.splitInherited(): Pair<List<T>, List<T>> where T : Documentable, T : WithExtraProperties<T> =
partition { it.isInherited() }
@@ -235,14 +252,15 @@ open class DefaultPageCreator(
}
}
}
- group(styles = setOf(ContentStyle.TabbedContent)) {
+ group(styles = setOf(ContentStyle.TabbedContent), extra = mainExtra) {
+contentForScope(p, p.dri, p.sourceSets)
}
}
protected open fun contentForScopes(
scopes: List<WithScope>,
- sourceSets: Set<DokkaSourceSet>
+ sourceSets: Set<DokkaSourceSet>,
+ extensions: List<Documentable> = emptyList()
): ContentGroup {
val types = scopes.flatMap { it.classlikes } + scopes.filterIsInstance<DPackage>().flatMap { it.typealiases }
return contentForScope(
@@ -251,40 +269,59 @@ open class DefaultPageCreator(
sourceSets,
types,
scopes.flatMap { it.functions },
- scopes.flatMap { it.properties }
+ scopes.flatMap { it.properties },
+ extensions
)
}
protected open fun contentForScope(
s: WithScope,
dri: DRI,
- sourceSets: Set<DokkaSourceSet>
+ sourceSets: Set<DokkaSourceSet>,
+ extensions: List<Documentable> = emptyList()
): ContentGroup {
val types = listOf(
s.classlikes,
(s as? DPackage)?.typealiases ?: emptyList()
).flatten()
- return contentForScope(setOf(dri), sourceSets, types, s.functions, s.properties)
+ return contentForScope(setOf(dri), sourceSets, types, s.functions, s.properties, extensions)
}
- protected open fun contentForScope(
+ private fun contentForScope(
dri: Set<DRI>,
sourceSets: Set<DokkaSourceSet>,
types: List<Documentable>,
functions: List<DFunction>,
- properties: List<DProperty>
+ properties: List<DProperty>,
+ extensions: List<Documentable>
) = contentBuilder.contentFor(dri, sourceSets) {
- divergentBlock("Types", types, ContentKind.Classlikes, extra = mainExtra + SimpleAttr.header("Types"))
+ divergentBlock(
+ "Types",
+ types,
+ ContentKind.Classlikes
+ )
+ val (extensionProps, extensionFuns) = extensions.splitPropsAndFuns()
if (separateInheritedMembers) {
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)
+
+ val (inheritedExtensionFunctions, extensionFunctions) = extensionFuns.splitInheritedExtension(dri)
+ val (inheritedExtensionProperties, extensionProperties) = extensionProps.splitInheritedExtension(dri)
+ propertiesBlock(
+ "Properties", memberProperties + extensionProperties
+ )
+ propertiesBlock(
+ "Inherited properties", inheritedProperties + inheritedExtensionProperties
+ )
+ functionsBlock("Functions", memberFunctions + extensionFunctions)
+ functionsBlock(
+ "Inherited functions", inheritedFunctions + inheritedExtensionFunctions
+ )
} else {
- functionsBlock("Functions", functions)
- propertiesBlock("Properties", properties, sourceSets)
+ functionsBlock("Functions", functions + extensionFuns)
+ propertiesBlock(
+ "Properties", properties + extensionProps
+ )
}
}
@@ -302,7 +339,8 @@ open class DefaultPageCreator(
val extensions = (classlikes as List<WithExtraProperties<DClasslike>>).flatMap {
it.extra[CallableExtensions]?.extensions
?.filterIsInstance<Documentable>().orEmpty()
- }.distinctBy{ it.sourceSets to it.dri} // [Documentable] has expensive equals/hashCode at the moment, see #2620
+ }
+ .distinctBy { it.sourceSets to it.dri } // [Documentable] has expensive equals/hashCode at the moment, see #2620
// 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
@@ -315,78 +353,91 @@ open class DefaultPageCreator(
}
}
}
- group(styles = setOf(ContentStyle.TabbedContent), sourceSets = mainSourcesetData + extensions.sourceSets) {
- val csWithConstructor = classlikes.filterIsInstance<WithConstructors>()
- if (csWithConstructor.isNotEmpty() && documentables.shouldRenderConstructors()) {
- val constructorsToDocumented = csWithConstructor.flatMap { it.constructors }
- multiBlock(
- "Constructors",
- 2,
- ContentKind.Constructors,
- constructorsToDocumented.groupBy { it.name }
- .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)
- }
- }
- }
+ val csEnum = classlikes.filterIsInstance<DEnum>()
+ val csWithConstructor = classlikes.filterIsInstance<WithConstructors>()
+ val scopes = documentables.filterIsInstance<WithScope>()
+ val constructorsToDocumented = csWithConstructor.flatMap { it.constructors }
+
+ group(
+ styles = setOf(ContentStyle.TabbedContent),
+ sourceSets = mainSourcesetData + extensions.sourceSets,
+ extra = mainExtra
+ ) {
+ if (constructorsToDocumented.isNotEmpty() && documentables.shouldDocumentConstructors()) {
+ +contentForConstructors(constructorsToDocumented, classlikes.dri, classlikes.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)
- }
- }
- }
+ +contentForEntries(csEnum.flatMap { it.entries }, csEnum.dri, csEnum.sourceSets)
}
- +contentForScopes(documentables.filterIsInstance<WithScope>(), documentables.sourceSets)
+ +contentForScopes(scopes, documentables.sourceSets, extensions)
+ }
+ }
+ protected open fun contentForConstructors(
+ constructorsToDocumented: List<DFunction>,
+ dri: Set<DRI>,
+ sourceSets: Set<DokkaSourceSet>
+ ) = contentBuilder.contentFor(dri, sourceSets) {
+ multiBlock(
+ "Constructors",
+ 2,
+ ContentKind.Constructors,
+ constructorsToDocumented.groupBy { it.name }
+ .map { (_, v) -> v.first().name to v },
+ @Suppress("UNCHECKED_CAST")
+ (constructorsToDocumented as List<Documentable>).sourceSets,
+ needsAnchors = true,
+ extra = PropertyContainer.empty<ContentNode>() + TabbedContentTypeExtra(
+ BasicTabbedContentType.CONSTRUCTOR
+ ),
+ ) { 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)
+ }
+ }
+ }
+ }
- divergentBlock(
- "Extensions",
- extensions,
- ContentKind.Extensions,
- extra = mainExtra + SimpleAttr.header("Extensions")
- )
+ protected open fun contentForEntries(
+ entries: List<DEnumEntry>,
+ dri: Set<DRI>,
+ sourceSets: Set<DokkaSourceSet>
+ ) = contentBuilder.contentFor(dri, sourceSets) {
+ multiBlock(
+ "Entries",
+ 2,
+ ContentKind.Classlikes,
+ entries.groupBy { it.name }.toList(),
+ entries.sourceSets,
+ needsSorting = false,
+ needsAnchors = true,
+ extra = mainExtra + TabbedContentTypeExtra(BasicTabbedContentType.ENTRY),
+ 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)
+ }
}
}
+ }
+
- // Annotations might have constructors to substitute reflection invocations
- // and for internal/compiler purposes, but they are not expected to be documented
- // and instantiated directly under normal circumstances, so constructors should not be rendered.
- private fun List<Documentable>.shouldRenderConstructors() = !this.any { it is DAnnotation }
protected open fun contentForDescription(
d: Documentable
@@ -410,7 +461,9 @@ open class DefaultPageCreator(
}.children
}
- protected open fun DocumentableContentBuilder.contentForBrief(documentable: Documentable) {
+ protected open fun DocumentableContentBuilder.contentForBrief(
+ documentable: Documentable
+ ) {
documentable.sourceSets.forEach { sourceSet ->
documentable.documentation[sourceSet]?.let {
/*
@@ -469,48 +522,50 @@ open class DefaultPageCreator(
}
}
- private fun DocumentableContentBuilder.functionsBlock(name: String, list: Collection<DFunction>) = divergentBlock(
- name,
- list.sorted(),
- ContentKind.Functions,
- extra = mainExtra + SimpleAttr.header(name)
- )
+ private fun DocumentableContentBuilder.functionsBlock(
+ name: String,
+ list: Collection<DFunction>
+ ) {
+ divergentBlock(
+ name,
+ list.sorted(),
+ ContentKind.Functions,
+ extra = mainExtra
+ )
+ }
private fun DocumentableContentBuilder.propertiesBlock(
name: String,
- list: Collection<DProperty>,
- sourceSets: Set<DokkaSourceSet>
+ list: Collection<DProperty>
) {
- multiBlock(
+ divergentBlock(
name,
- 2,
+ list,
ContentKind.Properties,
- list.groupBy { it.name }.toList(),
- sourceSets,
- needsAnchors = true,
- extra = mainExtra + SimpleAttr.header(name),
- headers = listOf(
- headers("Name", "Summary")
- )
- ) { key, props ->
- link(
- text = key,
- address = props.first().dri,
- kind = ContentKind.Main,
- styles = setOf(ContentStyle.RowTitle)
- )
- sourceSetDependentHint(props.dri, props.sourceSets, kind = ContentKind.SourceSetDependentHint) {
- props.forEach {
- +buildSignature(it)
- contentForBrief(it)
- contentForCustomTagsBrief(it)
- }
- }
- }
- }
+ extra = mainExtra
+ )
- private val groupKeyComparator: Comparator<Map.Entry<String?, *>> =
- compareBy(nullsFirst(canonicalAlphabeticalOrder)) { it.key }
+ }
+ private data class NameAndIsExtension(val name:String?, val isExtension: Boolean)
+
+ private fun groupAndSortDivergentCollection(collection: Collection<Documentable>): List<Map.Entry<NameAndIsExtension, List<Documentable>>> {
+ val groupKeyComparator: Comparator<Map.Entry<NameAndIsExtension, List<Documentable>>> =
+ compareBy<Map.Entry<NameAndIsExtension, List<Documentable>>, String?>(
+ nullsFirst(canonicalAlphabeticalOrder)
+ ) { it.key.name }
+ .thenBy { it.key.isExtension }
+
+ return collection
+ .groupBy {
+ NameAndIsExtension(
+ it.name,
+ it.isExtension()
+ )
+ } // This groupBy should probably use LocationProvider
+ // This hacks displaying actual typealias signatures along classlike ones
+ .mapValues { if (it.value.any { it is DClasslike }) it.value.filter { it !is DTypeAlias } else it.value }
+ .entries.sortedWith(groupKeyComparator)
+ }
protected open fun DocumentableContentBuilder.divergentBlock(
name: String,
@@ -519,60 +574,77 @@ open class DefaultPageCreator(
extra: PropertyContainer<ContentNode> = mainExtra
) {
if (collection.any()) {
- header(2, name, kind = kind)
- table(kind, extra = extra, styles = emptySet()) {
- header {
- group { text("Name") }
- group { text("Summary") }
- }
- collection
- .groupBy { it.name } // This groupBy should probably use LocationProvider
- // This hacks displaying actual typealias signatures along classlike ones
- .mapValues { if (it.value.any { it is DClasslike }) it.value.filter { it !is DTypeAlias } else it.value }
- .entries.sortedWith(groupKeyComparator)
- .forEach { (elementName, elements) -> // This groupBy should probably use LocationProvider
- val sortedElements = sortDivergentElementsDeterministically(elements)
- row(
- dri = sortedElements.map { it.dri }.toSet(),
- sourceSets = sortedElements.flatMap { it.sourceSets }.toSet(),
- kind = kind,
- styles = emptySet(),
- extra = elementName?.let { name -> extra + SymbolAnchorHint(name, kind) } ?: extra
- ) {
- link(
- text = elementName.orEmpty(),
- address = sortedElements.first().dri,
- kind = kind,
- styles = setOf(ContentStyle.RowTitle),
- sourceSets = sortedElements.sourceSets.toSet(),
- extra = extra
- )
- divergentGroup(
- ContentDivergentGroup.GroupID(name),
- sortedElements.map { it.dri }.toSet(),
- kind = kind,
- extra = extra
+ val onlyExtensions = collection.all { it.isExtension() }
+ val groupExtra = when(kind) {
+ ContentKind.Functions -> extra + TabbedContentTypeExtra(if (onlyExtensions) BasicTabbedContentType.EXTENSION_FUNCTION else BasicTabbedContentType.FUNCTION)
+ ContentKind.Properties -> extra + TabbedContentTypeExtra(if (onlyExtensions) BasicTabbedContentType.EXTENSION_PROPERTY else BasicTabbedContentType.PROPERTY)
+ ContentKind.Classlikes -> extra + TabbedContentTypeExtra(BasicTabbedContentType.TYPE)
+ else -> extra
+ }
+
+ group(extra = groupExtra) {
+ // be careful: groupExtra will be applied for children by default
+ header(2, name, kind = kind, extra = extra) { }
+ val isFunctions = collection.any { it is DFunction }
+ table(kind, extra = extra, styles = emptySet()) {
+ header {
+ group { text("Name") }
+ group { text("Summary") }
+ }
+ groupAndSortDivergentCollection(collection)
+ .forEach { (elementNameAndIsExtension, elements) -> // This groupBy should probably use LocationProvider
+ val elementName = elementNameAndIsExtension.name
+ val isExtension = elementNameAndIsExtension.isExtension
+ val rowExtra =
+ if (isExtension) extra + TabbedContentTypeExtra(if(isFunctions) BasicTabbedContentType.EXTENSION_FUNCTION else BasicTabbedContentType.EXTENSION_PROPERTY) else extra
+ val rowKind = if (isExtension) ContentKind.Extensions else kind
+ val sortedElements = sortDivergentElementsDeterministically(elements)
+ row(
+ dri = sortedElements.map { it.dri }.toSet(),
+ sourceSets = sortedElements.flatMap { it.sourceSets }.toSet(),
+ kind = rowKind,
+ styles = emptySet(),
+ extra = elementName?.let { name -> rowExtra + SymbolAnchorHint(name, kind) } ?: rowExtra
) {
- sortedElements.map {
- instance(
- setOf(it.dri),
- it.sourceSets.toSet(),
- extra = PropertyContainer.withAll(SymbolAnchorHint(it.name ?: "", kind))
- ) {
- divergent(extra = PropertyContainer.empty()) {
- group {
- +buildSignature(it)
+ link(
+ text = elementName.orEmpty(),
+ address = sortedElements.first().dri,
+ kind = rowKind,
+ styles = setOf(ContentStyle.RowTitle),
+ sourceSets = sortedElements.sourceSets.toSet(),
+ extra = extra
+ )
+ divergentGroup(
+ ContentDivergentGroup.GroupID(name),
+ sortedElements.map { it.dri }.toSet(),
+ kind = rowKind,
+ extra = extra
+ ) {
+ sortedElements.map { element ->
+ instance(
+ setOf(element.dri),
+ element.sourceSets.toSet(),
+ extra = PropertyContainer.withAll(
+ SymbolAnchorHint(element.name ?: "", rowKind)
+ )
+ ) {
+ divergent(extra = PropertyContainer.empty()) {
+ group {
+ +buildSignature(element)
+ }
+ }
+ after(
+ extra = PropertyContainer.empty()
+ ) {
+ contentForBrief(element)
+ contentForCustomTagsBrief(element)
}
- }
- after(extra = PropertyContainer.empty()) {
- contentForBrief(it)
- contentForCustomTagsBrief(it)
}
}
}
}
}
- }
+ }
}
}
}
@@ -664,3 +736,8 @@ internal inline fun <reified T : NamedTagWrapper> GroupedTags.withTypeNamed(): M
?.groupByTo(linkedMapOf()) { it.second.name }
?.mapValues { (_, v) -> v.toMap() }
.orEmpty()
+
+// Annotations might have constructors to substitute reflection invocations
+// and for internal/compiler purposes, but they are not expected to be documented
+// and instantiated directly under normal circumstances, so constructors should not be rendered.
+internal fun List<Documentable>.shouldDocumentConstructors() = !this.any { it is DAnnotation } \ No newline at end of file
diff --git a/plugins/base/src/main/kotlin/translators/documentables/DescriptionSections.kt b/plugins/base/src/main/kotlin/translators/documentables/DescriptionSections.kt
index 1720b1d0..8cd53525 100644
--- a/plugins/base/src/main/kotlin/translators/documentables/DescriptionSections.kt
+++ b/plugins/base/src/main/kotlin/translators/documentables/DescriptionSections.kt
@@ -229,7 +229,6 @@ internal fun PageContentBuilder.DocumentableContentBuilder.samplesSectionContent
sourceSets = setOf(sourceSet),
kind = ContentKind.Sample,
styles = setOf(TextStyle.Monospace, ContentStyle.RunnableSample),
- extra = mainExtra + SimpleAttr.header("Samples")
) {
samples.filter { it.value.isEmpty() || sourceSet in it.value }
.forEach { text(text = it.key, sourceSets = setOf(sourceSet)) }
@@ -333,7 +332,6 @@ private fun PageContentBuilder.DocumentableContentBuilder.tableSectionContentBlo
table(
kind = kind,
sourceSets = sourceSets,
- extra = mainExtra + SimpleAttr.header(blockName)
) {
body()
}
diff --git a/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt b/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt
index 000c955f..4eb1f06b 100644
--- a/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt
+++ b/plugins/base/src/main/kotlin/translators/documentables/PageContentBuilder.kt
@@ -245,28 +245,40 @@ open class PageContentBuilder(
needsAnchors: Boolean = false,
operation: DocumentableContentBuilder.(String, List<Documentable>) -> Unit
) {
+
if (renderWhenEmpty || groupedElements.any()) {
- header(level, name, kind = kind) { }
- contents += ContentTable(
- header = headers,
- children = groupedElements
- .let {
- if (needsSorting)
- it.sortedWith(compareBy(nullsLast(String.CASE_INSENSITIVE_ORDER)) { it.first })
- else it
- }
- .map {
- val newExtra = if (needsAnchors) extra + SymbolAnchorHint(it.first, kind) else extra
- val documentables = it.second
- buildGroup(documentables.map { it.dri }.toSet(), documentables.flatMap { it.sourceSets }.toSet(), kind, styles, newExtra) {
- operation(it.first, documentables)
+ group(extra = extra) {
+ header(level, name, kind = kind) { }
+ contents += ContentTable(
+ header = headers,
+ children = groupedElements
+ .let {
+ if (needsSorting)
+ it.sortedWith(compareBy(nullsLast(String.CASE_INSENSITIVE_ORDER)) { it.first })
+ else it
}
- },
- dci = DCI(mainDRI, kind),
- sourceSets = sourceSets.toDisplaySourceSets(),
- style = styles,
- extra = extra
- )
+ .map {
+ val documentables = it.second
+ val newExtra = if (needsAnchors) extra + SymbolAnchorHint(
+ it.first,
+ kind
+ ) else extra
+ buildGroup(
+ documentables.map { it.dri }.toSet(),
+ documentables.flatMap { it.sourceSets }.toSet(),
+ kind,
+ styles,
+ newExtra
+ ) {
+ operation(it.first, documentables)
+ }
+ },
+ dci = DCI(mainDRI, kind),
+ sourceSets = sourceSets.toDisplaySourceSets(),
+ style = styles,
+ extra = extra
+ )
+ }
}
}