Skip to content

Commit

Permalink
Refactor ContentTable builder and fix GFM table rendering (#1682)
Browse files Browse the repository at this point in the history
  • Loading branch information
kamildoleglo committed Jan 4, 2021
1 parent 6b0cdf3 commit d3f0e03
Show file tree
Hide file tree
Showing 5 changed files with 265 additions and 113 deletions.
25 changes: 13 additions & 12 deletions plugins/all-modules-page/src/main/kotlin/MultimodulePageCreator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,23 @@ class MultimodulePageCreator(
) {
header(2, "All modules:")
table(styles = setOf(MultimoduleTable)) {
modules.map { module ->
modules.forEach { module ->
val displayedModuleDocumentation = getDisplayedModuleDocumentation(module)
val dri = DRI(packageName = MULTIMODULE_PACKAGE_PLACEHOLDER, classNames = module.name)
val dci = DCI(setOf(dri), ContentKind.Comment)
val extraWithAnchor = PropertyContainer.withAll(SymbolAnchorHint(module.name, ContentKind.Main))
val header = linkNode(module.name, dri, DCI(setOf(dri), ContentKind.Main), extra = extraWithAnchor)
val content = ContentGroup(
children =
if (displayedModuleDocumentation != null)
DocTagToContentConverter().buildContent(displayedModuleDocumentation, dci, emptySet())
else emptyList(),
dci = dci,
sourceSets = emptySet(),
style = emptySet()
)
ContentGroup(listOf(header, content), dci, emptySet(), emptySet(), extraWithAnchor)
row(setOf(dri), emptySet(), styles = emptySet(), extra = extraWithAnchor) {
linkNode(module.name, dri, DCI(setOf(dri), ContentKind.Main), extra = extraWithAnchor)
+ContentGroup(
children =
if (displayedModuleDocumentation != null)
DocTagToContentConverter().buildContent(displayedModuleDocumentation, dci, emptySet())
else emptyList(),
dci = dci,
sourceSets = emptySet(),
style = emptySet()
)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,17 @@ open class DefaultPageCreator(
) {
protected open val contentBuilder = PageContentBuilder(commentsToContentConverter, signatureProvider, logger)

protected val separateInheritedMembers = configuration?.separateInheritedMembers ?: DokkaBaseConfiguration.separateInheritedMembersDefault
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 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.functions.renameClashingDocumentable()
.map(::pageForFunction) + p.properties.mapNotNull(::pageForProperty)
)

open fun pageForEnumEntry(e: DEnumEntry): ClasslikePageNode =
Expand All @@ -66,31 +68,32 @@ open class DefaultPageCreator(
)
}

private fun <T> T.toClashedName() where T: Documentable, T: WithExtraProperties<T> =
private fun <T> T.toClashedName() where T : Documentable, T : WithExtraProperties<T> =
(extra[ClashingDriIdentifier]?.value?.joinToString(", ", "[", "]") { it.displayName } ?: "") + name.orEmpty()

private fun <T> List<T>.renameClashingDocumentable(): List<T> where T: Documentable =
private fun <T> List<T>.renameClashingDocumentable(): List<T> where T : Documentable =
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?
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?
}
}
}

open fun pageForFunction(f: DFunction) = MemberPageNode(f.nameAfterClash(), contentForFunction(f), setOf(f.dri), f)

open fun pageForProperty(p: DProperty): MemberPageNode? = MemberPageNode(p.nameAfterClash(), contentForProperty(p), setOf(p.dri), p)
open fun pageForProperty(p: DProperty): MemberPageNode? =
MemberPageNode(p.nameAfterClash(), contentForProperty(p), setOf(p.dri), p)

private fun <T> T.isInherited(): Boolean where T: Documentable, T: WithExtraProperties<T> =
private fun <T> T.isInherited(): Boolean where T : Documentable, T : WithExtraProperties<T> =
sourceSets.all { sourceSet -> extra[InheritedMember]?.isInherited(sourceSet) == true }

private val WithScope.filteredFunctions: List<DFunction>
Expand All @@ -99,7 +102,7 @@ open class DefaultPageCreator(
private val WithScope.filteredProperties: List<DProperty>
get() = properties.filterNot { it.isInherited() }

private fun <T> Collection<T>.splitInherited(): Pair<List<T>, List<T>> where T: Documentable, T: WithExtraProperties<T> =
private fun <T> Collection<T>.splitInherited(): Pair<List<T>, List<T>> where T : Documentable, T : WithExtraProperties<T> =
partition { it.isInherited() }

protected open fun contentForModule(m: DModule) = contentBuilder.contentFor(m) {
Expand Down Expand Up @@ -185,7 +188,12 @@ open class DefaultPageCreator(
.groupBy({ it.second }, { it.first }).map { (classlike, platforms) ->
val label = classlike.classNames?.substringBeforeLast(".") ?: 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)) {
buildGroup(
setOf(classlike),
platforms.toSet(),
ContentKind.Inheritors,
extra = mainExtra + SymbolAnchorHint(label, ContentKind.Inheritors)
) {
link(label, classlike)
}
},
Expand Down Expand Up @@ -268,7 +276,12 @@ open class DefaultPageCreator(
styles = emptySet()
) {
link(it.name, it.dri)
sourceSetDependentHint(it.dri, it.sourceSets.toSet(), kind = ContentKind.SourceSetDependentHint, extra = PropertyContainer.empty<ContentNode>()) {
sourceSetDependentHint(
it.dri,
it.sourceSets.toSet(),
kind = ContentKind.SourceSetDependentHint,
extra = PropertyContainer.empty<ContentNode>()
) {
+buildSignature(it)
contentForBrief(it)
}
Expand Down Expand Up @@ -322,13 +335,12 @@ open class DefaultPageCreator(
if (unnamedTags.isNotEmpty()) {
platforms.forEach { platform ->
unnamedTags[platform]?.let { tags ->
if(tags.isNotEmpty()){
tags.groupBy { it::class }.forEach {
(_, sameCategoryTags) ->
group(sourceSets = setOf(platform), styles = emptySet()) {
header(4, sameCategoryTags.first().toHeaderString())
sameCategoryTags.forEach { comment(it.root) }
}
if (tags.isNotEmpty()) {
tags.groupBy { it::class }.forEach { (_, sameCategoryTags) ->
group(sourceSets = setOf(platform), styles = emptySet()) {
header(4, sameCategoryTags.first().toHeaderString())
sameCategoryTags.forEach { comment(it.root) }
}
}
}
}
Expand Down Expand Up @@ -362,18 +374,18 @@ open class DefaultPageCreator(
val receiver = tags.withTypeUnnamed<Receiver>()
val params = tags.withTypeNamed<Param>()
table(kind = ContentKind.Parameters) {
platforms.flatMap { platform ->
platforms.forEach { platform ->
val possibleFallbacks = d.getPossibleFallbackSourcesets(platform)
val receiverRow = (receiver[platform] ?: receiver.fallback(possibleFallbacks))?.let {
buildGroup(sourceSets = setOf(platform), kind = ContentKind.Parameters) {
(receiver[platform] ?: receiver.fallback(possibleFallbacks))?.let {
row(sourceSets = setOf(platform), kind = ContentKind.Parameters) {
text("<receiver>", styles = mainStyles + ContentStyle.RowTitle)
comment(it.root)
}
}

val paramRows = params.mapNotNull { (_, param) ->
params.mapNotNull { (_, param) ->
(param[platform] ?: param.fallback(possibleFallbacks))?.let {
buildGroup(sourceSets = setOf(platform), kind = ContentKind.Parameters) {
row(sourceSets = setOf(platform), kind = ContentKind.Parameters) {
text(
it.name,
kind = ContentKind.Parameters,
Expand All @@ -383,8 +395,6 @@ open class DefaultPageCreator(
}
}
}

listOfNotNull(receiverRow) + paramRows
}
}
}
Expand All @@ -402,14 +412,14 @@ open class DefaultPageCreator(
sourceSetDependentHint(sourceSets = platforms.toSet(), kind = ContentKind.SourceSetDependentHint) {
val seeAlsoTags = tags.withTypeNamed<See>()
table(kind = ContentKind.Sample) {
platforms.flatMap { platform ->
platforms.forEach { platform ->
val possibleFallbacks = d.getPossibleFallbackSourcesets(platform)
seeAlsoTags.mapNotNull { (_, see) ->
seeAlsoTags.forEach { (_, see) ->
(see[platform] ?: see.fallback(possibleFallbacks))?.let {
buildGroup(
row(
sourceSets = setOf(platform),
kind = ContentKind.Comment,
styles = mainStyles + ContentStyle.RowTitle,
styles = this@sourceSetDependentHint.mainStyles + ContentStyle.RowTitle,
) {
if (it.address != null) link(
it.name,
Expand All @@ -427,16 +437,17 @@ open class DefaultPageCreator(
}
}
}

fun DocumentableContentBuilder.contentForThrows() {
val throws = tags.withTypeNamed<Throws>()
if (throws.isNotEmpty()) {
header(4, "Throws")
sourceSetDependentHint(sourceSets = platforms.toSet(), kind = ContentKind.SourceSetDependentHint) {
platforms.forEach { sourceset ->
table(kind = ContentKind.Main, sourceSets = setOf(sourceset)) {
throws.entries.mapNotNull { entry ->
throws.entries.forEach { entry ->
entry.value[sourceset]?.let { throws ->
buildGroup(sourceSets = setOf(sourceset)) {
row(sourceSets = setOf(sourceset)) {
group(styles = mainStyles + ContentStyle.RowTitle) {
throws.exceptionAddress?.let {
link(text = entry.key, address = it)
Expand Down Expand Up @@ -492,7 +503,7 @@ open class DefaultPageCreator(
documentable.sourceSets.forEach { sourceSet ->
documentable.documentation[sourceSet]?.children?.firstOrNull()?.root?.let {
group(sourceSets = setOf(sourceSet), kind = ContentKind.BriefComment) {
if(documentable.hasSeparatePage) firstSentenceComment(it)
if (documentable.hasSeparatePage) firstSentenceComment(it)
else comment(it)
}
}
Expand Down Expand Up @@ -541,7 +552,12 @@ open class DefaultPageCreator(
ContentKind.Functions,
extra = mainExtra + SimpleAttr.header(name)
)
private fun DocumentableContentBuilder.propertiesBlock(name: String, list: Collection<DProperty>, sourceSets: Set<DokkaSourceSet>) {

private fun DocumentableContentBuilder.propertiesBlock(
name: String,
list: Collection<DProperty>,
sourceSets: Set<DokkaSourceSet>
) {
block(
name,
2,
Expand Down Expand Up @@ -573,23 +589,27 @@ open class DefaultPageCreator(
// 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 }
.toSortedMap(compareBy(nullsLast(String.CASE_INSENSITIVE_ORDER)) { it })
.map { (elementName, elements) -> // This groupBy should probably use LocationProvider
buildGroup(
.forEach { (elementName, elements) -> // This groupBy should probably use LocationProvider
row(
dri = elements.map { it.dri }.toSet(),
sourceSets = elements.flatMap { it.sourceSets }.toSet(),
kind = kind,
styles = emptySet(),
extra = elementName?.let { name -> extra + SymbolAnchorHint(name, kind) } ?: extra
) {
link(elementName.orEmpty(), elements.first().dri, kind = kind)
divergentGroup(
ContentDivergentGroup.GroupID(name),
elements.map { it.dri }.toSet(),
kind = kind,
extra = extra
) {
link(elementName.orEmpty(), elements.first().dri, kind = kind)
divergentGroup(
ContentDivergentGroup.GroupID(name),
elements.map { it.dri }.toSet(),
kind = kind,
extra = extra
) {
elements.map {
instance(setOf(it.dri), it.sourceSets.toSet(), extra = PropertyContainer.withAll(SymbolAnchorHint(it.name ?: "", kind))) {
instance(
setOf(it.dri),
it.sourceSets.toSet(),
extra = PropertyContainer.withAll(SymbolAnchorHint(it.name ?: "", kind))
) {
divergent(extra = PropertyContainer.empty()) {
group {
+buildSignature(it)
Expand Down Expand Up @@ -625,6 +645,6 @@ open class DefaultPageCreator(
private val Documentable.hasSeparatePage: Boolean
get() = this !is DTypeAlias

private fun <T: Documentable> T.nameAfterClash(): String =
private fun <T : Documentable> T.nameAfterClash(): String =
((this as? WithExtraProperties<out Documentable>)?.extra?.get(DriClashAwareName)?.value ?: name).orEmpty()
}
Loading

0 comments on commit d3f0e03

Please sign in to comment.