From 17ad866ff2c85cdebc87fbca648432dd758b1ee1 Mon Sep 17 00:00:00 2001 From: Oleg Yukhnevich Date: Fri, 24 Nov 2023 11:52:22 +0200 Subject: [PATCH] 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 --- dokka-subprojects/core/api/dokka-core.api | 1 + .../org/jetbrains/dokka/pages/ContentNodes.kt | 3 +- .../org/jetbrains/dokka/base/DokkaBase.kt | 4 +- .../base/DokkaBaseInternalConfiguration.kt | 30 ++ .../dokka/base/pages/AllTypesPageNode.kt | 46 ++ .../dokka/base/renderers/html/HtmlRenderer.kt | 13 +- .../renderers/html/NavigationDataProvider.kt | 38 +- .../resolvers/local/DokkaLocationProvider.kt | 11 +- .../annotations/SinceKotlinTransformer.kt | 84 ++-- .../tags/SinceKotlinTagContentProvider.kt | 6 +- .../documentables/DefaultPageCreator.kt | 111 ++++- .../test/kotlin/content/AllTypesPageTest.kt | 426 ++++++++++++++++++ .../src/test/kotlin/content/ModulePageTest.kt | 115 +++++ .../content/annotations/SinceKotlinTest.kt | 19 +- .../content/params/ContentForParamsTest.kt | 1 - .../content/seealso/ContentForSeeAlsoTest.kt | 4 - .../kotlin/pageMerger/PageNodeMergerTest.kt | 1 - .../kotlin/renderers/html/NavigationTest.kt | 45 ++ .../kotlin/renderers/html/TextStylesTest.kt | 2 - .../src/test/kotlin/utils/systemProperties.kt | 34 ++ 20 files changed, 927 insertions(+), 67 deletions(-) create mode 100644 dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/DokkaBaseInternalConfiguration.kt create mode 100644 dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/pages/AllTypesPageNode.kt create mode 100644 dokka-subprojects/plugin-base/src/test/kotlin/content/AllTypesPageTest.kt create mode 100644 dokka-subprojects/plugin-base/src/test/kotlin/content/ModulePageTest.kt create mode 100644 dokka-subprojects/plugin-base/src/test/kotlin/utils/systemProperties.kt diff --git a/dokka-subprojects/core/api/dokka-core.api b/dokka-subprojects/core/api/dokka-core.api index fffcb87769..c04d3f2f53 100644 --- a/dokka-subprojects/core/api/dokka-core.api +++ b/dokka-subprojects/core/api/dokka-core.api @@ -3807,6 +3807,7 @@ public final class org/jetbrains/dokka/pages/ContentHeader : org/jetbrains/dokka } public final class org/jetbrains/dokka/pages/ContentKind : java/lang/Enum, org/jetbrains/dokka/pages/Kind { + public static final field AllTypes Lorg/jetbrains/dokka/pages/ContentKind; public static final field Annotations Lorg/jetbrains/dokka/pages/ContentKind; public static final field BriefComment Lorg/jetbrains/dokka/pages/ContentKind; public static final field Classlikes Lorg/jetbrains/dokka/pages/ContentKind; diff --git a/dokka-subprojects/core/src/main/kotlin/org/jetbrains/dokka/pages/ContentNodes.kt b/dokka-subprojects/core/src/main/kotlin/org/jetbrains/dokka/pages/ContentNodes.kt index 96f43205e8..586ac9cd1b 100644 --- a/dokka-subprojects/core/src/main/kotlin/org/jetbrains/dokka/pages/ContentNodes.kt +++ b/dokka-subprojects/core/src/main/kotlin/org/jetbrains/dokka/pages/ContentNodes.kt @@ -336,7 +336,7 @@ public enum class ContentKind : Kind { */ Symbol, - Comment, Constructors, Functions, Parameters, Properties, Classlikes, Packages, Sample, Main, BriefComment, + Comment, Constructors, Functions, Parameters, Properties, Classlikes, Packages, AllTypes, Sample, Main, BriefComment, Empty, Source, TypeAliases, Cover, Inheritors, SourceSetDependentHint, Extensions, Annotations, /** @@ -352,6 +352,7 @@ public enum class ContentKind : Kind { Properties, Classlikes, Packages, + AllTypes, Source, TypeAliases, Inheritors, diff --git a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/DokkaBase.kt b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/DokkaBase.kt index 6fa4270b9a..94c0dfe33d 100644 --- a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/DokkaBase.kt +++ b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/DokkaBase.kt @@ -131,7 +131,7 @@ public class DokkaBase : DokkaPlugin() { public val sinceKotlinTransformer: Extension by extending { CoreExtensions.documentableTransformer providing ::SinceKotlinTransformer applyIf { - SinceKotlinTransformer.shouldDisplaySinceKotlin() + DokkaBaseInternalConfiguration.sinceKotlinRenderingEnabled } order { before(extensionsExtractor) } @@ -159,7 +159,7 @@ public class DokkaBase : DokkaPlugin() { public val sinceKotlinTagContentProvider: Extension by extending { customTagContentProvider with SinceKotlinTagContentProvider applyIf { - SinceKotlinTransformer.shouldDisplaySinceKotlin() + DokkaBaseInternalConfiguration.sinceKotlinRenderingEnabled } } diff --git a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/DokkaBaseInternalConfiguration.kt b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/DokkaBaseInternalConfiguration.kt new file mode 100644 index 0000000000..7dcd1667fa --- /dev/null +++ b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/DokkaBaseInternalConfiguration.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.base + +// revisit in scope of https://github.com/Kotlin/dokka/issues/2776 +internal object DokkaBaseInternalConfiguration { + const val SHOULD_DISPLAY_ALL_TYPES_PAGE_SYS_PROP = "dokka.shouldDisplayAllTypesPage" + const val SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP = "dokka.shouldDisplaySinceKotlin" + + var allTypesPageEnabled: Boolean = false + private set + var sinceKotlinRenderingEnabled: Boolean = false + private set + + init { + reinitialize() + } + + // should be private, internal is only for usage in tests + internal fun reinitialize() { + allTypesPageEnabled = getBooleanProperty(SHOULD_DISPLAY_ALL_TYPES_PAGE_SYS_PROP) + sinceKotlinRenderingEnabled = getBooleanProperty(SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP) + } + + private fun getBooleanProperty(propertyName: String): Boolean { + return System.getProperty(propertyName) in setOf("1", "true") + } +} diff --git a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/pages/AllTypesPageNode.kt b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/pages/AllTypesPageNode.kt new file mode 100644 index 0000000000..00fd342853 --- /dev/null +++ b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/pages/AllTypesPageNode.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package org.jetbrains.dokka.base.pages + +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.pages.ContentNode +import org.jetbrains.dokka.pages.ContentPage +import org.jetbrains.dokka.pages.PageNode + +/** + * This page is internal because it's an stdlib-specific feature, + * which is not intended for public use or customization. + * + * For more details, see https://github.com/Kotlin/dokka/issues/2887 + */ +internal class AllTypesPageNode( + override val content: ContentNode, + override val embeddedResources: List = listOf() +) : ContentPage { + override val dri: Set = setOf(DRI) + override val name: String = "All Types" + override val children: List get() = emptyList() + + override fun modified(name: String, children: List): AllTypesPageNode = + modified(name = name, content = this.content, dri = dri, children = children) + + override fun modified( + name: String, + content: ContentNode, + dri: Set, + embeddedResources: List, + children: List + ): AllTypesPageNode = + if (name == this.name && content === this.content && embeddedResources === this.embeddedResources && children shallowEq this.children) this + else AllTypesPageNode(content, embeddedResources) + + companion object { + val DRI: DRI = DRI(packageName = ".alltypes") + } +} + +// copy-pasted from dokka-core, not sure why it was needed in the first place +private infix fun List.shallowEq(other: List) = + this === other || (this.size == other.size && (this zip other).all { (a, b) -> a === b }) diff --git a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/HtmlRenderer.kt b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/HtmlRenderer.kt index e7b77383d9..d86f645c1a 100644 --- a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/HtmlRenderer.kt +++ b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/HtmlRenderer.kt @@ -19,6 +19,7 @@ import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint import org.jetbrains.dokka.base.resolvers.local.DokkaBaseLocationProvider import org.jetbrains.dokka.base.templating.* import org.jetbrains.dokka.base.transformers.documentables.CallableExtensions +import org.jetbrains.dokka.base.pages.AllTypesPageNode import org.jetbrains.dokka.base.translators.documentables.shouldDocumentConstructors import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.* @@ -474,7 +475,10 @@ public open class HtmlRenderer( ?.let { when (pageContext) { is MultimoduleRootPage -> buildRowForMultiModule(node, it, pageContext, sourceSetRestriction) - is ModulePage -> buildRowForModule(node, it, pageContext, sourceSetRestriction) + + is ModulePage, + is AllTypesPageNode -> buildRowForPlatformTaggedBrief(node, it, pageContext, sourceSetRestriction) + else -> buildRowForContent(node, it, pageContext, sourceSetRestriction) } } @@ -497,7 +501,12 @@ public open class HtmlRenderer( } } - private fun FlowContent.buildRowForModule( + /** + * Builds a row with support for filtering and showing platform bubble and brief content. + * + * Used for rendering packages in [ModulePage] and types in [AllTypesPageNode] + */ + private fun FlowContent.buildRowForPlatformTaggedBrief( contextNode: ContentGroup, toRender: List, pageContext: ContentPage, diff --git a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/NavigationDataProvider.kt b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/NavigationDataProvider.kt index fccfd14514..7b778ec529 100644 --- a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/NavigationDataProvider.kt +++ b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/renderers/html/NavigationDataProvider.kt @@ -16,6 +16,8 @@ import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.analysis.kotlin.internal.DocumentableLanguage import org.jetbrains.dokka.analysis.kotlin.internal.InternalKotlinAnalysisPlugin +import org.jetbrains.dokka.base.DokkaBaseInternalConfiguration +import org.jetbrains.dokka.base.pages.AllTypesPageNode public abstract class NavigationDataProvider( dokkaContext: DokkaContext @@ -105,23 +107,47 @@ public abstract class NavigationDataProvider( } private val navigationNodeOrder: Comparator = - compareBy(canonicalAlphabeticalOrder) { it.name } + compareBy(canonicalAlphabeticalOrder, NavigationNode::name) + + private val navigationModuleNodeOrder: Comparator = + when (DokkaBaseInternalConfiguration.allTypesPageEnabled) { + false -> navigationNodeOrder + // put `All Types` page at the bottom of the navigation page + true -> Comparator { a, b -> + when { + a === b -> 0 + a.dri == AllTypesPageNode.DRI -> 1 + b.dri == AllTypesPageNode.DRI -> -1 + else -> navigationNodeOrder.compare(a, b) + } + } + } - private fun ContentPage.navigableChildren() = - if (this is ClasslikePage) { + private fun ContentPage.navigableChildren() = when (this) { + is ClasslikePage -> { this.navigableChildren() - } else { + } + + is ModulePage -> { children .filterIsInstance() - .map { visit(it) } + .map(::visit) + .sortedWith(navigationModuleNodeOrder) + } + + else -> { + children + .filterIsInstance() + .map(::visit) .sortedWith(navigationNodeOrder) } + } private fun ClasslikePage.navigableChildren(): List { // Classlikes should only have other classlikes as navigable children val navigableChildren = children .filterIsInstance() - .map { visit(it) } + .map(::visit) val isEnumPage = documentables.any { it is DEnum } return if (isEnumPage) { diff --git a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/resolvers/local/DokkaLocationProvider.kt b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/resolvers/local/DokkaLocationProvider.kt index aedbfb88ee..8a17dd1922 100644 --- a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/resolvers/local/DokkaLocationProvider.kt +++ b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/resolvers/local/DokkaLocationProvider.kt @@ -6,6 +6,7 @@ package org.jetbrains.dokka.base.resolvers.local import org.jetbrains.dokka.base.renderers.sourceSets import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint +import org.jetbrains.dokka.base.pages.AllTypesPageNode import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.PointingToDeclaration import org.jetbrains.dokka.model.* @@ -25,6 +26,9 @@ public open class DokkaLocationProvider( if (page is RootPageNode && page.forceTopLevelName) { put(page, prefix + PAGE_WITH_CHILDREN_SUFFIX) page.children.forEach { registerPath(it, prefix) } + } else if (page is AllTypesPageNode) { + put(page, prefix + ALL_TYPES_PAGE_PATH) + page.children.forEach { registerPath(it, prefix) } } else { val newPrefix = prefix + page.pathName put(page, if (page is ModulePageNode) prefix else newPrefix) @@ -159,7 +163,12 @@ public open class DokkaLocationProvider( protected data class PageWithKind(val page: ContentPage, val kind: Kind) public companion object { - public val reservedFilenames: Set = setOf("index", "con", "aux", "lst", "prn", "nul", "eof", "inp", "out") + private const val ALL_TYPES_PAGE_PATH: String = "all-types" + + public val reservedFilenames: Set = setOf( + "index", "con", "aux", "lst", "prn", "nul", "eof", "inp", "out", + ALL_TYPES_PAGE_PATH + ) //Taken from: https://stackoverflow.com/questions/1976007/what-characters-are-forbidden-in-windows-and-linux-directory-names internal val reservedCharacters = setOf('|', '>', '<', '*', ':', '"', '?', '%') diff --git a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/pages/annotations/SinceKotlinTransformer.kt b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/pages/annotations/SinceKotlinTransformer.kt index 9ff5960d7c..df07a6a051 100644 --- a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/pages/annotations/SinceKotlinTransformer.kt +++ b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/pages/annotations/SinceKotlinTransformer.kt @@ -37,20 +37,60 @@ public class SinceKotlinVersion(str: String) : Comparable { } override fun toString(): String = parts.joinToString(".") + + internal companion object { + internal const val SINCE_KOTLIN_TAG_NAME = "Since Kotlin" + + private val minVersionOfPlatform = mapOf( + Platform.common to SinceKotlinVersion("1.0"), + Platform.jvm to SinceKotlinVersion("1.0"), + Platform.js to SinceKotlinVersion("1.1"), + Platform.native to SinceKotlinVersion("1.3"), + Platform.wasm to SinceKotlinVersion("1.8"), + ) + + fun minVersionOfPlatform(platform: Platform): SinceKotlinVersion { + return minVersionOfPlatform[platform] + ?: throw IllegalStateException("No value for platform: $platform") + } + + /** + * Should be in sync with [extractSinceKotlinVersionFromCustomTag] + */ + fun createCustomTagFromSinceKotlinVersion( + version: SinceKotlinVersion?, + platform: Platform + ): CustomTagWrapper { + val sinceKotlinVersion = version?: minVersionOfPlatform(platform) + return CustomTagWrapper( + CustomDocTag( + children = listOf(Text(sinceKotlinVersion.toString())), + name = MARKDOWN_ELEMENT_FILE_NAME + ), + SINCE_KOTLIN_TAG_NAME + ) + } + + /** + * Should be in sync with [createCustomTagFromSinceKotlinVersion] + */ + fun extractSinceKotlinVersionFromCustomTag( + tagWrapper: CustomTagWrapper, + platform: Platform + ): SinceKotlinVersion { + val customTag = tagWrapper.root as? CustomDocTag + val sinceKotlinVersionText = customTag?.children?.firstOrNull() as? Text + val sinceKotlinVersion = sinceKotlinVersionText?.body?.let(::SinceKotlinVersion) + return sinceKotlinVersion ?: minVersionOfPlatform(platform) + } + + } } public class SinceKotlinTransformer( public val context: DokkaContext ) : DocumentableTransformer { - private val minSinceKotlinVersionOfPlatform = mapOf( - Platform.common to SinceKotlinVersion("1.0"), - Platform.jvm to SinceKotlinVersion("1.0"), - Platform.js to SinceKotlinVersion("1.1"), - Platform.native to SinceKotlinVersion("1.3"), - Platform.wasm to SinceKotlinVersion("1.8"), - ) - override fun invoke(original: DModule, context: DokkaContext): DModule = original.transform() as DModule private fun T.transform(parent: SourceSetDependent? = null): Documentable { @@ -132,8 +172,7 @@ public class SinceKotlinTransformer( ?.params?.let { it["version"] as? StringValue }?.value ?.let { SinceKotlinVersion(it) } - val minSinceKotlin = minSinceKotlinVersionOfPlatform[sourceSet.analysisPlatform] - ?: throw IllegalStateException("No value for platform: ${sourceSet.analysisPlatform}") + val minSinceKotlin = SinceKotlinVersion.minVersionOfPlatform(sourceSet.analysisPlatform) return annotatedVersion?.takeIf { version -> version >= minSinceKotlin } ?: minSinceKotlin } @@ -153,34 +192,17 @@ public class SinceKotlinTransformer( private fun Documentable.appendSinceKotlin(versions: SourceSetDependent) = sourceSets.fold(documentation) { acc, sourceSet -> - val version = versions[sourceSet] - - val sinceKotlinCustomTag = CustomTagWrapper( - CustomDocTag( - listOf( - Text( - version.toString() - ) - ), - name = MARKDOWN_ELEMENT_FILE_NAME - ), - "Since Kotlin" + val sinceKotlinCustomTag = SinceKotlinVersion.createCustomTagFromSinceKotlinVersion( + version = versions[sourceSet], + platform = sourceSet.analysisPlatform ) if (acc[sourceSet] == null) acc + (sourceSet to DocumentationNode(listOf(sinceKotlinCustomTag))) else acc.mapValues { if (it.key == sourceSet) it.value.copy( - it.value.children + listOf( - sinceKotlinCustomTag - ) + it.value.children + listOf(sinceKotlinCustomTag) ) else it.value } } - - internal companion object { - internal const val SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP = "dokka.shouldDisplaySinceKotlin" - internal fun shouldDisplaySinceKotlin() = - System.getProperty(SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP) in listOf("true", "1") - } } diff --git a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/pages/tags/SinceKotlinTagContentProvider.kt b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/pages/tags/SinceKotlinTagContentProvider.kt index 7c35f71910..0299fd9b63 100644 --- a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/pages/tags/SinceKotlinTagContentProvider.kt +++ b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/transformers/pages/tags/SinceKotlinTagContentProvider.kt @@ -5,6 +5,7 @@ package org.jetbrains.dokka.base.transformers.pages.tags import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.base.transformers.pages.annotations.SinceKotlinVersion import org.jetbrains.dokka.base.translators.documentables.KDOC_TAG_HEADER_LEVEL import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder.DocumentableContentBuilder import org.jetbrains.dokka.model.doc.CustomTagWrapper @@ -12,9 +13,8 @@ import org.jetbrains.dokka.pages.TextStyle public object SinceKotlinTagContentProvider : CustomTagContentProvider { - private const val SINCE_KOTLIN_TAG_NAME = "Since Kotlin" - - override fun isApplicable(customTag: CustomTagWrapper): Boolean = customTag.name == SINCE_KOTLIN_TAG_NAME + override fun isApplicable(customTag: CustomTagWrapper): Boolean = + customTag.name == SinceKotlinVersion.SINCE_KOTLIN_TAG_NAME override fun DocumentableContentBuilder.contentForDescription( sourceSet: DokkaConfiguration.DokkaSourceSet, diff --git a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/translators/documentables/DefaultPageCreator.kt b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/translators/documentables/DefaultPageCreator.kt index 5c8ac51219..dac5144d8c 100644 --- a/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/translators/documentables/DefaultPageCreator.kt +++ b/dokka-subprojects/plugin-base/src/main/kotlin/org/jetbrains/dokka/base/translators/documentables/DefaultPageCreator.kt @@ -5,6 +5,7 @@ package org.jetbrains.dokka.base.translators.documentables import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet +import org.jetbrains.dokka.Platform import org.jetbrains.dokka.base.DokkaBaseConfiguration import org.jetbrains.dokka.base.resolvers.anchors.SymbolAnchorHint import org.jetbrains.dokka.base.signatures.SignatureProvider @@ -24,6 +25,9 @@ import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.utilities.DokkaLogger import org.jetbrains.dokka.analysis.kotlin.internal.DocumentableSourceLanguageParser import org.jetbrains.dokka.analysis.kotlin.internal.DocumentableLanguage +import org.jetbrains.dokka.base.DokkaBaseInternalConfiguration +import org.jetbrains.dokka.base.pages.AllTypesPageNode +import org.jetbrains.dokka.base.transformers.pages.annotations.SinceKotlinVersion import kotlin.reflect.KClass internal typealias GroupedTags = Map, List>> @@ -47,8 +51,18 @@ public open class DefaultPageCreator( protected val separateInheritedMembers: Boolean = configuration?.separateInheritedMembers ?: DokkaBaseConfiguration.separateInheritedMembersDefault - public open fun pageForModule(m: DModule): ModulePageNode = - ModulePageNode(m.name.ifEmpty { "" }, contentForModule(m), listOf(m), m.packages.map(::pageForPackage)) + public open fun pageForModule(m: DModule): ModulePageNode { + val packagePages = m.packages.map(::pageForPackage) + return ModulePageNode( + name = m.name.ifEmpty { "" }, + content = contentForModule(m), + documentables = listOf(m), + children = when { + m.needAllTypesPage() -> packagePages + AllTypesPageNode(content = contentForAllTypes(m)) + else -> packagePages + } + ) + } /** * We want to generate separated pages for no-actual typealias. @@ -270,9 +284,77 @@ public open class DefaultPageCreator( documentations.first()?.let { firstParagraphComment(kind = ContentKind.Comment, content = it.root) } } } + + if (m.needAllTypesPage()) { + header(2, "Index", kind = ContentKind.Cover) + link("All Types", AllTypesPageNode.DRI) + } + } + } + + private fun contentForAllTypes(m: DModule): ContentGroup = contentBuilder.contentFor(m) { + group(kind = ContentKind.Cover) { + cover(m.name) + } + + block( + name = "All Types", + level = 2, + kind = ContentKind.AllTypes, + elements = m.packages.flatMap { it.classlikes + it.typealiases }.filterOutActualTypeAlias(), + sourceSets = m.sourceSets.toSet(), + needsAnchors = true, + headers = listOf( + headers("Name") + ) + ) { typelike -> + + val comment = typelike.sourceSets.mapNotNull { sourceSet -> + typelike.descriptions[sourceSet]?.let { sourceSet to it } + }.selectBestVariant { firstParagraphBrief(it.root) } + + val sinceKotlinTag = typelike.customTags[SinceKotlinVersion.SINCE_KOTLIN_TAG_NAME]?.let { sourceSetTag -> + typelike.sourceSets.mapNotNull { sourceSet -> + sourceSetTag[sourceSet]?.let { sourceSet to it } + }.minByOrNull { (sourceSet, tagWrapper) -> + SinceKotlinVersion.extractSinceKotlinVersionFromCustomTag( + tagWrapper = tagWrapper, + platform = sourceSet.analysisPlatform + ) + } + } + + // qualified name will never be 'null' for classlike and typealias + link(typelike.qualifiedName()!!, typelike.dri) + comment?.let { (sourceSet, description) -> + createBriefComment(typelike, sourceSet, description) + } + sinceKotlinTag?.let { (sourceSet, tag) -> + createBriefCustomTags(sourceSet, tag) + } } } + // the idea is to have at least some description, so we do: + // 1. if all data per source sets are the same - take it + // 2. if not, try to take common data + // 3. if not, try to take JVM data (as this is most likely to be the best variant) + // 4. if not, just take any data + private fun List>.selectBestVariant(selector: (T) -> K): Pair? { + if (isEmpty()) return null + val uniqueElements = distinctBy { selector(it.second) } + return uniqueElements.singleOrNull() + ?: uniqueElements.firstOrNull { it.first.analysisPlatform == Platform.common } + ?: uniqueElements.firstOrNull { it.first.analysisPlatform == Platform.jvm } + ?: uniqueElements.firstOrNull() + } + + private fun Documentable.qualifiedName(): String? { + val className = dri.classNames?.takeIf(String::isNotBlank) ?: name + val packageName = dri.packageName?.takeIf(String::isNotBlank) ?: return className + return "$packageName.${className}" + } + protected open fun contentForPackage(p: DPackage): ContentGroup { return contentBuilder.contentFor(p) { group(kind = ContentKind.Cover) { @@ -482,7 +564,7 @@ public open class DefaultPageCreator( protected open fun contentForDescription( d: Documentable ): List { - val sourceSets = d.sourceSets.toSet() + val sourceSets = d.sourceSets val tags = d.groupedTags return contentBuilder.contentFor(d) { @@ -715,17 +797,30 @@ public open class DefaultPageCreator( documentable.sourceSets.forEach { sourceSet -> customTags.forEach { (_, sourceSetTag) -> sourceSetTag[sourceSet]?.let { tag -> - customTagContentProviders.filter { it.isApplicable(tag) }.forEach { provider -> - with(provider) { - contentForBrief(sourceSet, tag) - } - } + createBriefCustomTags(sourceSet, tag) } } } } + private fun DocumentableContentBuilder.createBriefCustomTags( + sourceSet: DokkaSourceSet, + customTag: CustomTagWrapper + ) { + customTagContentProviders.filter { it.isApplicable(customTag) }.forEach { provider -> + with(provider) { + contentForBrief(sourceSet, customTag) + } + } + } + protected open fun TagWrapper.toHeaderString(): String = this.javaClass.toGenericString().split('.').last() + + private fun DModule.needAllTypesPage(): Boolean { + return DokkaBaseInternalConfiguration.allTypesPageEnabled && packages.any { + it.classlikes.isNotEmpty() || it.typealiases.isNotEmpty() + } + } } internal val List.sourceSets: Set diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/content/AllTypesPageTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/content/AllTypesPageTest.kt new file mode 100644 index 0000000000..4670dfa77e --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/content/AllTypesPageTest.kt @@ -0,0 +1,426 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package content + +import matchers.content.* +import org.jetbrains.dokka.base.pages.AllTypesPageNode +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.pages.RootPageNode +import utils.withAllTypesPage +import utils.withSinceKotlin +import kotlin.test.Test +import kotlin.test.assertNotNull +import kotlin.test.assertNull + +class AllTypesPageTest : BaseAbstractTest() { + private val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + private val multiplatformConfiguration = dokkaConfiguration { + sourceSets { + val commonId = sourceSet { + sourceRoots = listOf("src/common/") + analysisPlatform = "common" + name = "common" + }.value.sourceSetID + sourceSet { + sourceRoots = listOf("src/jvm/") + analysisPlatform = "jvm" + name = "jvm" + dependentSourceSets = setOf(commonId) + } + sourceSet { + sourceRoots = listOf("src/native/") + analysisPlatform = "native" + name = "native" + dependentSourceSets = setOf(commonId) + } + } + } + + private fun RootPageNode.allTypesPageNode(): AllTypesPageNode? = + children.singleOrNull { it is AllTypesPageNode } as? AllTypesPageNode + + @Test + fun `all types page generated when there are types`() = withAllTypesPage { + testInline( + """ + |/src/Test.kt + |package sample + |/** + | * Hello World! + | * + | * Some other comment which should not be on All Types page + | */ + |public class Test + | + |/** + | * Hello type + | */ + |public typealias Alias = Int + """.trimIndent(), + configuration + ) { + pagesTransformationStage = { rootPage -> + assertNotNull(rootPage.allTypesPageNode()).content.assertNode { + group { + header { +"root" } + } + header { +"All Types" } + table { + group { + link { +"sample.Alias" } + group { + group { + +"Hello type" + } + } + } + group { + link { +"sample.Test" } + group { + group { + +"Hello World!" + } + } + } + } + } + } + } + } + + @Test + fun `all types isn't generated when not enabled by property`() { + testInline( + """ + |/src/Test.kt + |package sample + |/** + | * Hello World! + | * + | * Some other comment which should not be on All Types page + | */ + |public class Test + | + |/** + | * Hello type + | */ + |public typealias Alias = Int + """.trimIndent(), + configuration + ) { + pagesTransformationStage = { rootPage -> + assertNull(rootPage.allTypesPageNode()) + } + } + } + + @Test + fun `all types page isn't generated when there are NO types`() = withAllTypesPage { + testInline( + """ + |/src/Test.kt + |package sample + |/** + | * Hello World! + | */ + |public fun test() {} + """.trimIndent(), + configuration + ) { + pagesTransformationStage = { rootPage -> + assertNull(rootPage.allTypesPageNode()) + } + } + } + + @Test + fun `all types sorting depends only on simple name`() = withAllTypesPage { + testInline( + """ + |/src/A.kt + |package bbb + |public class A + |/src/B.kt + |package xxx + |public class B + |/src/C.kt + |package aaa + |public class C + """.trimIndent(), + configuration + ) { + pagesTransformationStage = { rootPage -> + assertNotNull(rootPage.allTypesPageNode()).content.assertNode { + group { + header { +"root" } + } + header { +"All Types" } + table { + group { + link { +"bbb.A" } + } + group { + link { +"xxx.B" } + } + group { + link { +"aaa.C" } + } + } + } + } + } + } + + @Test + fun `all types description is the same for all sourceSets`() = withAllTypesPage { + testInline( + """ + |/src/common/test.kt + |package test + |/** + | * Common + | */ + |expect class ExpectActual + |/src/jvm/test.kt + |package test + |/** + | * Common + | */ + |actual class ExpectActual + |/src/native/test.kt + |package test + |/** + | * Common + | */ + |actual class ExpectActual + """.trimIndent(), + multiplatformConfiguration + ) { + pagesTransformationStage = { rootPage -> + assertNotNull(rootPage.allTypesPageNode()).content.assertNode { + group { + header { +"root" } + } + header { +"All Types" } + table { + group { + link { +"test.ExpectActual" } + group { group { +"Common" } } + } + } + } + } + } + } + + @Test + fun `all types description should should be taken from common if others different has different description`() = + withAllTypesPage { + testInline( + """ + |/src/common/test.kt + |package test + |/** + | * Common + | */ + |expect class ExpectActual + |/src/jvm/test.kt + |package test + |/** + | * JVM + | */ + |actual class ExpectActual + |/src/native/test.kt + |package test + |/** + | * Native + | */ + |actual class ExpectActual + """.trimIndent(), + multiplatformConfiguration + ) { + pagesTransformationStage = { rootPage -> + assertNotNull(rootPage.allTypesPageNode()).content.assertNode { + group { + header { +"root" } // module name + } + header { +"All Types" } + table { + group { + link { +"test.ExpectActual" } + group { group { +"Common" } } + } + } + } + } + } + } + + @Test + fun `all types description should should be taken from jvm if common description is missing`() = withAllTypesPage { + testInline( + """ + |/src/common/test.kt + |package test + |expect class ExpectActual + |/src/jvm/test.kt + |package test + |/** + | * JVM + | */ + |actual class ExpectActual + |/src/native/test.kt + |package test + |/** + | * Native + | */ + |actual class ExpectActual + """.trimIndent(), + multiplatformConfiguration + ) { + pagesTransformationStage = { rootPage -> + assertNotNull(rootPage.allTypesPageNode()).content.assertNode { + group { + header { +"root" } // module name + } + header { +"All Types" } + table { + group { + link { +"test.ExpectActual" } + group { group { +"JVM" } } + } + } + } + } + } + } + + @Test + fun `all types description should should be taken from any source set if common and jvm descriptions are missing`() = + withAllTypesPage { + testInline( + """ + |/src/common/test.kt + |package test + |expect class ExpectActual + |/src/jvm/test.kt + |package test + |actual class ExpectActual + |/src/native/test.kt + |package test + |/** + | * Native + | */ + |actual class ExpectActual + """.trimIndent(), + multiplatformConfiguration + ) { + pagesTransformationStage = { rootPage -> + assertNotNull(rootPage.allTypesPageNode()).content.assertNode { + group { + header { +"root" } // module name + } + header { +"All Types" } + table { + group { + link { +"test.ExpectActual" } + group { group { +"Native" } } + } + } + } + } + } + } + + + @Test + fun `since kotlin is the same for all sourceSets`() = withAllTypesPage { + withSinceKotlin { + testInline( + """ + |/src/common/test.kt + |package test + |@SinceKotlin("1.3") + |expect class ExpectActual + |/src/jvm/test.kt + |package test + |@SinceKotlin("1.3") + |actual class ExpectActual + |/src/native/test.kt + |package test + |@SinceKotlin("1.3") + |actual class ExpectActual + """.trimIndent(), + multiplatformConfiguration + ) { + pagesTransformationStage = { rootPage -> + assertNotNull(rootPage.allTypesPageNode()).content.assertNode { + group { + header { +"root" } + } + header { +"All Types" } + table { + group { + link { +"test.ExpectActual" } + group { + +"Since Kotlin " + group { +"1.3" } + } + } + } + } + } + } + } + } + + @Test + fun `minimal since kotlin is used if it's different between sourceSets`() = withAllTypesPage { + withSinceKotlin { + testInline( + """ + |/src/common/test.kt + |package test + |@SinceKotlin("1.4") + |expect class ExpectActual + |/src/jvm/test.kt + |package test + |@SinceKotlin("1.2") + |actual class ExpectActual + |/src/native/test.kt + |package test + |@SinceKotlin("1.5") + |actual class ExpectActual + """.trimIndent(), + multiplatformConfiguration + ) { + pagesTransformationStage = { rootPage -> + assertNotNull(rootPage.allTypesPageNode()).content.assertNode { + group { + header { +"root" } + } + header { +"All Types" } + table { + group { + link { +"test.ExpectActual" } + group { + +"Since Kotlin " + group { +"1.2" } + } + } + } + } + } + } + } + } +} diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/content/ModulePageTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/content/ModulePageTest.kt new file mode 100644 index 0000000000..81f6ffd993 --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/content/ModulePageTest.kt @@ -0,0 +1,115 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package content + +import matchers.content.* +import org.jetbrains.dokka.base.pages.AllTypesPageNode +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.pages.ContentDRILink +import org.jetbrains.dokka.pages.ModulePageNode +import utils.withAllTypesPage +import kotlin.test.Test +import kotlin.test.assertEquals + +class ModulePageTest : BaseAbstractTest() { + private val configuration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + } + } + } + + @Test + fun `show packages content`() = withAllTypesPage { + testInline( + """ + |/src/A.kt + |package bbb + |public class A + |/src/B.kt + |package xxx + |public class B + |/src/C.kt + |package aaa + |public class C + """.trimIndent(), + configuration + ) { + pagesTransformationStage = { rootPage -> + (rootPage as ModulePageNode).content.assertNode { + group { + header { +"root" } // module name + } + header { +"Packages" } + table { + group { + link { +"aaa" } + } + group { + link { +"bbb" } + } + group { + link { +"xxx" } + } + } + header { +"Index" } + link { +"All Types" } + } + } + } + } + + @Test + fun `show link to all types page when there are types`() = withAllTypesPage { + testInline( + """ + |/src/Test.kt + |package sample + |public class Test + """.trimIndent(), + configuration + ) { + pagesTransformationStage = { rootPage -> + (rootPage as ModulePageNode).content.assertNode { + group { + header { +"root" } // module name + } + header { +"Packages" } + table { skipAllNotMatching() } + header { +"Index" } + link { + +"All Types" + check { + assertEquals(AllTypesPageNode.DRI, (this as ContentDRILink).address) + } + } + } + } + } + } + + @Test + fun `no link to all types page when there are no types`() { + testInline( + """ + |/src/Test.kt + |package sample + |public fun test() {} + """.trimIndent(), + configuration + ) { + pagesTransformationStage = { rootPage -> + (rootPage as ModulePageNode).content.assertNode { + group { + header { +"root" } // module name + } + header { +"Packages" } + table { skipAllNotMatching() } + } + } + } + } +} diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/content/annotations/SinceKotlinTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/content/annotations/SinceKotlinTest.kt index 6ee95bbd0d..4cf6573a88 100644 --- a/dokka-subprojects/plugin-base/src/test/kotlin/content/annotations/SinceKotlinTest.kt +++ b/dokka-subprojects/plugin-base/src/test/kotlin/content/annotations/SinceKotlinTest.kt @@ -6,7 +6,8 @@ package content.annotations import matchers.content.* import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.base.transformers.pages.annotations.SinceKotlinTransformer +import org.jetbrains.dokka.base.DokkaBaseInternalConfiguration +import org.jetbrains.dokka.base.DokkaBaseInternalConfiguration.SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP import org.jetbrains.dokka.base.transformers.pages.annotations.SinceKotlinVersion import org.jetbrains.dokka.model.DFunction import org.jetbrains.dokka.model.dfs @@ -32,11 +33,12 @@ class SinceKotlinTest : AbstractRenderingTest() { @BeforeTest fun setSystemProperty() { - System.setProperty(SinceKotlinTransformer.SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP, "true") + DokkaBaseInternalConfiguration.setProperty(SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP, "true") } + @AfterTest fun clearSystemProperty() { - System.clearProperty(SinceKotlinTransformer.SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP) + DokkaBaseInternalConfiguration.clearProperty(SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP) } @Test @@ -50,7 +52,7 @@ class SinceKotlinTest : AbstractRenderingTest() { } @Test - fun `rendered SinceKotlin custom tag for typealias, extensions, functions, properties`() { + fun `rendered SinceKotlin custom tag for typealias, extensions, functions, properties`() = withAllTypesPage { val writerPlugin = TestOutputWriterPlugin() testInline( @@ -70,13 +72,20 @@ class SinceKotlinTest : AbstractRenderingTest() { |typealias Str = String |@SinceKotlin("1.5") |val str = "str" + |@SinceKotlin("1.5") + |class A """.trimIndent(), testConfiguration, pluginOverrides = listOf(writerPlugin) ) { renderingStage = { _, _ -> + // 5 = 2 functions, 1 typealias, 1 property, 1 class val content = writerPlugin.renderedContent("root/test/index.html") - assertEquals(4, content.getElementsContainingOwnText("Since Kotlin").count()) + assertEquals(5, content.getElementsContainingOwnText("Since Kotlin").count()) + + // 2 = 1 typealias, 1 class + val allTypesContent = writerPlugin.renderedContent("root/all-types.html") + assertEquals(2, allTypesContent.getElementsContainingOwnText("Since Kotlin").count()) } } } diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/content/params/ContentForParamsTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/content/params/ContentForParamsTest.kt index 6656dc44dd..b4f283727a 100644 --- a/dokka-subprojects/plugin-base/src/test/kotlin/content/params/ContentForParamsTest.kt +++ b/dokka-subprojects/plugin-base/src/test/kotlin/content/params/ContentForParamsTest.kt @@ -1090,7 +1090,6 @@ class ContentForParamsTest : BaseAbstractTest() { ) { pagesTransformationStage = { module -> val page = module.findTestType("test", "Foo") - println(page.content) page.content.assertNode { group { header(1) { +"Foo" } diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/content/seealso/ContentForSeeAlsoTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/content/seealso/ContentForSeeAlsoTest.kt index fb72178b2e..9ff300cc59 100644 --- a/dokka-subprojects/plugin-base/src/test/kotlin/content/seealso/ContentForSeeAlsoTest.kt +++ b/dokka-subprojects/plugin-base/src/test/kotlin/content/seealso/ContentForSeeAlsoTest.kt @@ -150,7 +150,6 @@ class ContentForSeeAlsoTest : BaseAbstractTest() { ) { pagesTransformationStage = { module -> val page = module.findTestType("test", "Foo") - println(page.content) page.content.assertNode { group { header(1) { +"Foo" } @@ -191,7 +190,6 @@ class ContentForSeeAlsoTest : BaseAbstractTest() { ) { pagesTransformationStage = { module -> val page = module.findTestType("test", "Foo") - println(page.content) page.content.assertNode { group { header(1) { +"Foo" } @@ -233,7 +231,6 @@ class ContentForSeeAlsoTest : BaseAbstractTest() { ) { pagesTransformationStage = { module -> val page = module.findTestType("test", "Foo") - println(page.content) page.content.assertNode { group { header(1) { +"Foo" } @@ -327,7 +324,6 @@ class ContentForSeeAlsoTest : BaseAbstractTest() { ) { pagesTransformationStage = { module -> val page = module.findTestType("test", "Foo") - println(page.content) page.content.assertNode { group { header(1) { +"Foo" } diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt index 983f73ffe6..57e285d2a6 100644 --- a/dokka-subprojects/plugin-base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt +++ b/dokka-subprojects/plugin-base/src/test/kotlin/pageMerger/PageNodeMergerTest.kt @@ -141,7 +141,6 @@ class PageNodeMergerTest : BaseAbstractTest() { configuration ) { pagesTransformationStage = { - println(it) val allChildren = it.childrenRec().filterIsInstance() val jvmClass = allChildren.filter { it.name == "[jvm]DoNotMerge" } val jsClass = allChildren.filter { it.name == "[js]DoNotMerge" } diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/renderers/html/NavigationTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/renderers/html/NavigationTest.kt index 020748107e..093179dc03 100644 --- a/dokka-subprojects/plugin-base/src/test/kotlin/renderers/html/NavigationTest.kt +++ b/dokka-subprojects/plugin-base/src/test/kotlin/renderers/html/NavigationTest.kt @@ -9,6 +9,7 @@ import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest import org.jsoup.nodes.Element import utils.TestOutputWriterPlugin import utils.navigationHtml +import utils.withAllTypesPage import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNotNull @@ -98,6 +99,50 @@ class NavigationTest : BaseAbstractTest() { } } + @Test + fun `all types page should be in the end`() = withAllTypesPage{ + val writerPlugin = TestOutputWriterPlugin() + testInline( + """ + |/src/main/kotlin/com/example/Sequences.kt + |package com.example + |interface Sequence + """.trimMargin(), + configuration, + pluginOverrides = listOf(writerPlugin) + ) { + renderingStage = { _, _ -> + val content = writerPlugin.writer.navigationHtml().select("div.sideMenuPart") + assertEquals(4, content.size) + + content[0].assertNavigationLink( + id = "root-nav-submenu", + text = "root", + address = "index.html", + ) + + content[1].assertNavigationLink( + id = "root-nav-submenu-0", + text = "com.example", + address = "root/com.example/index.html", + ) + + content[2].assertNavigationLink( + id = "root-nav-submenu-0-0", + text = "Sequence", + address = "root/com.example/-sequence/index.html", + icon = NavigationNodeIcon.INTERFACE_KT + ) + + content[3].assertNavigationLink( + id = "root-nav-submenu-1", + text = "All Types", + address = "root/all-types.html", + ) + } + } + } + @Test fun `should strike deprecated class link`() { val writerPlugin = TestOutputWriterPlugin() diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/renderers/html/TextStylesTest.kt b/dokka-subprojects/plugin-base/src/test/kotlin/renderers/html/TextStylesTest.kt index 0ca4e24598..4d591d5405 100644 --- a/dokka-subprojects/plugin-base/src/test/kotlin/renderers/html/TextStylesTest.kt +++ b/dokka-subprojects/plugin-base/src/test/kotlin/renderers/html/TextStylesTest.kt @@ -92,7 +92,6 @@ class TextStylesTest : HtmlRenderingOnlyTestBase() { } } HtmlRenderer(context).render(page) - println(renderedContent) renderedContent.match(Var("variable")) } @@ -104,7 +103,6 @@ class TextStylesTest : HtmlRenderingOnlyTestBase() { } } HtmlRenderer(context).render(page) - println(renderedContent) renderedContent.match(U("underlined text")) } diff --git a/dokka-subprojects/plugin-base/src/test/kotlin/utils/systemProperties.kt b/dokka-subprojects/plugin-base/src/test/kotlin/utils/systemProperties.kt new file mode 100644 index 0000000000..4f15c5665b --- /dev/null +++ b/dokka-subprojects/plugin-base/src/test/kotlin/utils/systemProperties.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license. + */ + +package utils + +import org.jetbrains.dokka.base.DokkaBaseInternalConfiguration +import org.jetbrains.dokka.base.DokkaBaseInternalConfiguration.SHOULD_DISPLAY_ALL_TYPES_PAGE_SYS_PROP +import org.jetbrains.dokka.base.DokkaBaseInternalConfiguration.SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP + +internal fun withAllTypesPage(block: () -> Unit): Unit = + DokkaBaseInternalConfiguration.withProperty(SHOULD_DISPLAY_ALL_TYPES_PAGE_SYS_PROP, "true", block) + +internal fun withSinceKotlin(block: () -> Unit): Unit = + DokkaBaseInternalConfiguration.withProperty(SHOULD_DISPLAY_SINCE_KOTLIN_SYS_PROP, "true", block) + +internal fun DokkaBaseInternalConfiguration.withProperty(propertyName: String, value: String, block: () -> Unit) { + setProperty(propertyName, value) + try { + block() + } finally { + clearProperty(propertyName) + } +} + +internal fun DokkaBaseInternalConfiguration.setProperty(propertyName: String, value: String) { + System.setProperty(propertyName, value) + reinitialize() +} + +internal fun DokkaBaseInternalConfiguration.clearProperty(propertyName: String) { + System.clearProperty(propertyName) + reinitialize() +}