Skip to content

Commit 7266d57

Browse files
whyolegvmishenev
authored andcommitted
Add All Types page generation (#3267)
* Hide All Types page under a system property * Show documentation if it exists selecting most relevant * Take the minimum SinceKotlin version if they differ * Extract internal configuration properties to one place
1 parent 66b3914 commit 7266d57

File tree

20 files changed

+927
-67
lines changed

20 files changed

+927
-67
lines changed

dokka-subprojects/core/api/dokka-core.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3807,6 +3807,7 @@ public final class org/jetbrains/dokka/pages/ContentHeader : org/jetbrains/dokka
38073807
}
38083808

38093809
public final class org/jetbrains/dokka/pages/ContentKind : java/lang/Enum, org/jetbrains/dokka/pages/Kind {
3810+
public static final field AllTypes Lorg/jetbrains/dokka/pages/ContentKind;
38103811
public static final field Annotations Lorg/jetbrains/dokka/pages/ContentKind;
38113812
public static final field BriefComment Lorg/jetbrains/dokka/pages/ContentKind;
38123813
public static final field Classlikes Lorg/jetbrains/dokka/pages/ContentKind;

dokka-subprojects/core/src/main/kotlin/org/jetbrains/dokka/pages/ContentNodes.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ public enum class ContentKind : Kind {
336336
*/
337337
Symbol,
338338

339-
Comment, Constructors, Functions, Parameters, Properties, Classlikes, Packages, Sample, Main, BriefComment,
339+
Comment, Constructors, Functions, Parameters, Properties, Classlikes, Packages, AllTypes, Sample, Main, BriefComment,
340340
Empty, Source, TypeAliases, Cover, Inheritors, SourceSetDependentHint, Extensions, Annotations,
341341

342342
/**
@@ -352,6 +352,7 @@ public enum class ContentKind : Kind {
352352
Properties,
353353
Classlikes,
354354
Packages,
355+
AllTypes,
355356
Source,
356357
TypeAliases,
357358
Inheritors,

dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/DokkaBase.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public class DokkaBase : DokkaPlugin() {
131131

132132
public val sinceKotlinTransformer: Extension<DocumentableTransformer, *, *> by extending {
133133
CoreExtensions.documentableTransformer providing ::SinceKotlinTransformer applyIf {
134-
SinceKotlinTransformer.shouldDisplaySinceKotlin()
134+
DokkaBaseInternalConfiguration.sinceKotlinRenderingEnabled
135135
} order {
136136
before(extensionsExtractor)
137137
}
@@ -159,7 +159,7 @@ public class DokkaBase : DokkaPlugin() {
159159

160160
public val sinceKotlinTagContentProvider: Extension<CustomTagContentProvider, *, *> by extending {
161161
customTagContentProvider with SinceKotlinTagContentProvider applyIf {
162-
SinceKotlinTransformer.shouldDisplaySinceKotlin()
162+
DokkaBaseInternalConfiguration.sinceKotlinRenderingEnabled
163163
}
164164
}
165165

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package org.jetbrains.dokka.base
6+
7+
// revisit in scope of https://github.com/Kotlin/dokka/issues/2776
8+
internal object DokkaBaseInternalConfiguration {
9+
const val SHOULD_DISPLAY_ALL_TYPES_PAGE_SYS_PROP = "dokka.shouldDisplayAllTypesPage"
10+
const val SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP = "dokka.shouldDisplaySinceKotlin"
11+
12+
var allTypesPageEnabled: Boolean = false
13+
private set
14+
var sinceKotlinRenderingEnabled: Boolean = false
15+
private set
16+
17+
init {
18+
reinitialize()
19+
}
20+
21+
// should be private, internal is only for usage in tests
22+
internal fun reinitialize() {
23+
allTypesPageEnabled = getBooleanProperty(SHOULD_DISPLAY_ALL_TYPES_PAGE_SYS_PROP)
24+
sinceKotlinRenderingEnabled = getBooleanProperty(SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP)
25+
}
26+
27+
private fun getBooleanProperty(propertyName: String): Boolean {
28+
return System.getProperty(propertyName) in setOf("1", "true")
29+
}
30+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package org.jetbrains.dokka.base.pages
6+
7+
import org.jetbrains.dokka.links.DRI
8+
import org.jetbrains.dokka.pages.ContentNode
9+
import org.jetbrains.dokka.pages.ContentPage
10+
import org.jetbrains.dokka.pages.PageNode
11+
12+
/**
13+
* This page is internal because it's an stdlib-specific feature,
14+
* which is not intended for public use or customization.
15+
*
16+
* For more details, see https://github.com/Kotlin/dokka/issues/2887
17+
*/
18+
internal class AllTypesPageNode(
19+
override val content: ContentNode,
20+
override val embeddedResources: List<String> = listOf()
21+
) : ContentPage {
22+
override val dri: Set<DRI> = setOf(DRI)
23+
override val name: String = "All Types"
24+
override val children: List<PageNode> get() = emptyList()
25+
26+
override fun modified(name: String, children: List<PageNode>): AllTypesPageNode =
27+
modified(name = name, content = this.content, dri = dri, children = children)
28+
29+
override fun modified(
30+
name: String,
31+
content: ContentNode,
32+
dri: Set<DRI>,
33+
embeddedResources: List<String>,
34+
children: List<PageNode>
35+
): AllTypesPageNode =
36+
if (name == this.name && content === this.content && embeddedResources === this.embeddedResources && children shallowEq this.children) this
37+
else AllTypesPageNode(content, embeddedResources)
38+
39+
companion object {
40+
val DRI: DRI = DRI(packageName = ".alltypes")
41+
}
42+
}
43+
44+
// copy-pasted from dokka-core, not sure why it was needed in the first place
45+
private infix fun <T> List<T>.shallowEq(other: List<T>) =
46+
this === other || (this.size == other.size && (this zip other).all { (a, b) -> a === b })

dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/HtmlRenderer.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint
1919
import org.jetbrains.dokka.base.resolvers.local.DokkaBaseLocationProvider
2020
import org.jetbrains.dokka.base.templating.*
2121
import org.jetbrains.dokka.base.transformers.documentables.CallableExtensions
22+
import org.jetbrains.dokka.base.pages.AllTypesPageNode
2223
import org.jetbrains.dokka.base.translators.documentables.shouldDocumentConstructors
2324
import org.jetbrains.dokka.links.DRI
2425
import org.jetbrains.dokka.model.*
@@ -474,7 +475,10 @@ public open class HtmlRenderer(
474475
?.let {
475476
when (pageContext) {
476477
is MultimoduleRootPage -> buildRowForMultiModule(node, it, pageContext, sourceSetRestriction)
477-
is ModulePage -> buildRowForModule(node, it, pageContext, sourceSetRestriction)
478+
479+
is ModulePage,
480+
is AllTypesPageNode -> buildRowForPlatformTaggedBrief(node, it, pageContext, sourceSetRestriction)
481+
478482
else -> buildRowForContent(node, it, pageContext, sourceSetRestriction)
479483
}
480484
}
@@ -497,7 +501,12 @@ public open class HtmlRenderer(
497501
}
498502
}
499503

500-
private fun FlowContent.buildRowForModule(
504+
/**
505+
* Builds a row with support for filtering and showing platform bubble and brief content.
506+
*
507+
* Used for rendering packages in [ModulePage] and types in [AllTypesPageNode]
508+
*/
509+
private fun FlowContent.buildRowForPlatformTaggedBrief(
501510
contextNode: ContentGroup,
502511
toRender: List<ContentNode>,
503512
pageContext: ContentPage,

dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/NavigationDataProvider.kt

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import org.jetbrains.dokka.plugability.plugin
1616
import org.jetbrains.dokka.plugability.querySingle
1717
import org.jetbrains.dokka.analysis.kotlin.internal.DocumentableLanguage
1818
import org.jetbrains.dokka.analysis.kotlin.internal.InternalKotlinAnalysisPlugin
19+
import org.jetbrains.dokka.base.DokkaBaseInternalConfiguration
20+
import org.jetbrains.dokka.base.pages.AllTypesPageNode
1921

2022
public abstract class NavigationDataProvider(
2123
dokkaContext: DokkaContext
@@ -105,23 +107,47 @@ public abstract class NavigationDataProvider(
105107
}
106108

107109
private val navigationNodeOrder: Comparator<NavigationNode> =
108-
compareBy(canonicalAlphabeticalOrder) { it.name }
110+
compareBy(canonicalAlphabeticalOrder, NavigationNode::name)
111+
112+
private val navigationModuleNodeOrder: Comparator<NavigationNode> =
113+
when (DokkaBaseInternalConfiguration.allTypesPageEnabled) {
114+
false -> navigationNodeOrder
115+
// put `All Types` page at the bottom of the navigation page
116+
true -> Comparator { a, b ->
117+
when {
118+
a === b -> 0
119+
a.dri == AllTypesPageNode.DRI -> 1
120+
b.dri == AllTypesPageNode.DRI -> -1
121+
else -> navigationNodeOrder.compare(a, b)
122+
}
123+
}
124+
}
109125

110-
private fun ContentPage.navigableChildren() =
111-
if (this is ClasslikePage) {
126+
private fun ContentPage.navigableChildren() = when (this) {
127+
is ClasslikePage -> {
112128
this.navigableChildren()
113-
} else {
129+
}
130+
131+
is ModulePage -> {
114132
children
115133
.filterIsInstance<ContentPage>()
116-
.map { visit(it) }
134+
.map(::visit)
135+
.sortedWith(navigationModuleNodeOrder)
136+
}
137+
138+
else -> {
139+
children
140+
.filterIsInstance<ContentPage>()
141+
.map(::visit)
117142
.sortedWith(navigationNodeOrder)
118143
}
144+
}
119145

120146
private fun ClasslikePage.navigableChildren(): List<NavigationNode> {
121147
// Classlikes should only have other classlikes as navigable children
122148
val navigableChildren = children
123149
.filterIsInstance<ClasslikePage>()
124-
.map { visit(it) }
150+
.map(::visit)
125151

126152
val isEnumPage = documentables.any { it is DEnum }
127153
return if (isEnumPage) {

dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/resolvers/local/DokkaLocationProvider.kt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package org.jetbrains.dokka.base.resolvers.local
66

77
import org.jetbrains.dokka.base.renderers.sourceSets
88
import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint
9+
import org.jetbrains.dokka.base.pages.AllTypesPageNode
910
import org.jetbrains.dokka.links.DRI
1011
import org.jetbrains.dokka.links.PointingToDeclaration
1112
import org.jetbrains.dokka.model.*
@@ -25,6 +26,9 @@ public open class DokkaLocationProvider(
2526
if (page is RootPageNode && page.forceTopLevelName) {
2627
put(page, prefix + PAGE_WITH_CHILDREN_SUFFIX)
2728
page.children.forEach { registerPath(it, prefix) }
29+
} else if (page is AllTypesPageNode) {
30+
put(page, prefix + ALL_TYPES_PAGE_PATH)
31+
page.children.forEach { registerPath(it, prefix) }
2832
} else {
2933
val newPrefix = prefix + page.pathName
3034
put(page, if (page is ModulePageNode) prefix else newPrefix)
@@ -159,7 +163,12 @@ public open class DokkaLocationProvider(
159163
protected data class PageWithKind(val page: ContentPage, val kind: Kind)
160164

161165
public companion object {
162-
public val reservedFilenames: Set<String> = setOf("index", "con", "aux", "lst", "prn", "nul", "eof", "inp", "out")
166+
private const val ALL_TYPES_PAGE_PATH: String = "all-types"
167+
168+
public val reservedFilenames: Set<String> = setOf(
169+
"index", "con", "aux", "lst", "prn", "nul", "eof", "inp", "out",
170+
ALL_TYPES_PAGE_PATH
171+
)
163172

164173
//Taken from: https://stackoverflow.com/questions/1976007/what-characters-are-forbidden-in-windows-and-linux-directory-names
165174
internal val reservedCharacters = setOf('|', '>', '<', '*', ':', '"', '?', '%')

dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/pages/annotations/SinceKotlinTransformer.kt

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,60 @@ public class SinceKotlinVersion(str: String) : Comparable<SinceKotlinVersion> {
3737
}
3838

3939
override fun toString(): String = parts.joinToString(".")
40+
41+
internal companion object {
42+
internal const val SINCE_KOTLIN_TAG_NAME = "Since Kotlin"
43+
44+
private val minVersionOfPlatform = mapOf(
45+
Platform.common to SinceKotlinVersion("1.0"),
46+
Platform.jvm to SinceKotlinVersion("1.0"),
47+
Platform.js to SinceKotlinVersion("1.1"),
48+
Platform.native to SinceKotlinVersion("1.3"),
49+
Platform.wasm to SinceKotlinVersion("1.8"),
50+
)
51+
52+
fun minVersionOfPlatform(platform: Platform): SinceKotlinVersion {
53+
return minVersionOfPlatform[platform]
54+
?: throw IllegalStateException("No value for platform: $platform")
55+
}
56+
57+
/**
58+
* Should be in sync with [extractSinceKotlinVersionFromCustomTag]
59+
*/
60+
fun createCustomTagFromSinceKotlinVersion(
61+
version: SinceKotlinVersion?,
62+
platform: Platform
63+
): CustomTagWrapper {
64+
val sinceKotlinVersion = version?: minVersionOfPlatform(platform)
65+
return CustomTagWrapper(
66+
CustomDocTag(
67+
children = listOf(Text(sinceKotlinVersion.toString())),
68+
name = MARKDOWN_ELEMENT_FILE_NAME
69+
),
70+
SINCE_KOTLIN_TAG_NAME
71+
)
72+
}
73+
74+
/**
75+
* Should be in sync with [createCustomTagFromSinceKotlinVersion]
76+
*/
77+
fun extractSinceKotlinVersionFromCustomTag(
78+
tagWrapper: CustomTagWrapper,
79+
platform: Platform
80+
): SinceKotlinVersion {
81+
val customTag = tagWrapper.root as? CustomDocTag
82+
val sinceKotlinVersionText = customTag?.children?.firstOrNull() as? Text
83+
val sinceKotlinVersion = sinceKotlinVersionText?.body?.let(::SinceKotlinVersion)
84+
return sinceKotlinVersion ?: minVersionOfPlatform(platform)
85+
}
86+
87+
}
4088
}
4189

4290
public class SinceKotlinTransformer(
4391
public val context: DokkaContext
4492
) : DocumentableTransformer {
4593

46-
private val minSinceKotlinVersionOfPlatform = mapOf(
47-
Platform.common to SinceKotlinVersion("1.0"),
48-
Platform.jvm to SinceKotlinVersion("1.0"),
49-
Platform.js to SinceKotlinVersion("1.1"),
50-
Platform.native to SinceKotlinVersion("1.3"),
51-
Platform.wasm to SinceKotlinVersion("1.8"),
52-
)
53-
5494
override fun invoke(original: DModule, context: DokkaContext): DModule = original.transform() as DModule
5595

5696
private fun <T : Documentable> T.transform(parent: SourceSetDependent<SinceKotlinVersion>? = null): Documentable {
@@ -132,8 +172,7 @@ public class SinceKotlinTransformer(
132172
?.params?.let { it["version"] as? StringValue }?.value
133173
?.let { SinceKotlinVersion(it) }
134174

135-
val minSinceKotlin = minSinceKotlinVersionOfPlatform[sourceSet.analysisPlatform]
136-
?: throw IllegalStateException("No value for platform: ${sourceSet.analysisPlatform}")
175+
val minSinceKotlin = SinceKotlinVersion.minVersionOfPlatform(sourceSet.analysisPlatform)
137176

138177
return annotatedVersion?.takeIf { version -> version >= minSinceKotlin } ?: minSinceKotlin
139178
}
@@ -153,34 +192,17 @@ public class SinceKotlinTransformer(
153192
private fun Documentable.appendSinceKotlin(versions: SourceSetDependent<SinceKotlinVersion>) =
154193
sourceSets.fold(documentation) { acc, sourceSet ->
155194

156-
val version = versions[sourceSet]
157-
158-
val sinceKotlinCustomTag = CustomTagWrapper(
159-
CustomDocTag(
160-
listOf(
161-
Text(
162-
version.toString()
163-
)
164-
),
165-
name = MARKDOWN_ELEMENT_FILE_NAME
166-
),
167-
"Since Kotlin"
195+
val sinceKotlinCustomTag = SinceKotlinVersion.createCustomTagFromSinceKotlinVersion(
196+
version = versions[sourceSet],
197+
platform = sourceSet.analysisPlatform
168198
)
169199
if (acc[sourceSet] == null)
170200
acc + (sourceSet to DocumentationNode(listOf(sinceKotlinCustomTag)))
171201
else
172202
acc.mapValues {
173203
if (it.key == sourceSet) it.value.copy(
174-
it.value.children + listOf(
175-
sinceKotlinCustomTag
176-
)
204+
it.value.children + listOf(sinceKotlinCustomTag)
177205
) else it.value
178206
}
179207
}
180-
181-
internal companion object {
182-
internal const val SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP = "dokka.shouldDisplaySinceKotlin"
183-
internal fun shouldDisplaySinceKotlin() =
184-
System.getProperty(SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP) in listOf("true", "1")
185-
}
186208
}

dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/pages/tags/SinceKotlinTagContentProvider.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@
55
package org.jetbrains.dokka.base.transformers.pages.tags
66

77
import org.jetbrains.dokka.DokkaConfiguration
8+
import org.jetbrains.dokka.base.transformers.pages.annotations.SinceKotlinVersion
89
import org.jetbrains.dokka.base.translators.documentables.KDOC_TAG_HEADER_LEVEL
910
import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder.DocumentableContentBuilder
1011
import org.jetbrains.dokka.model.doc.CustomTagWrapper
1112
import org.jetbrains.dokka.pages.TextStyle
1213

1314
public object SinceKotlinTagContentProvider : CustomTagContentProvider {
1415

15-
private const val SINCE_KOTLIN_TAG_NAME = "Since Kotlin"
16-
17-
override fun isApplicable(customTag: CustomTagWrapper): Boolean = customTag.name == SINCE_KOTLIN_TAG_NAME
16+
override fun isApplicable(customTag: CustomTagWrapper): Boolean =
17+
customTag.name == SinceKotlinVersion.SINCE_KOTLIN_TAG_NAME
1818

1919
override fun DocumentableContentBuilder.contentForDescription(
2020
sourceSet: DokkaConfiguration.DokkaSourceSet,

0 commit comments

Comments
 (0)