Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate dedicated pages for typealiases #3051

Merged
merged 2 commits into from
Jun 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion plugins/base/api/base.api
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ public final class org/jetbrains/dokka/base/renderers/html/NavigationNodeIcon :
public static final field INTERFACE Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon;
public static final field INTERFACE_KT Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon;
public static final field OBJECT Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon;
public static final field TYPEALIAS_KT Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon;
public static final field VAL Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon;
public static final field VAR Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon;
public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/dokka/base/renderers/html/NavigationNodeIcon;
Expand Down Expand Up @@ -1464,7 +1465,7 @@ public class org/jetbrains/dokka/base/translators/documentables/DefaultPageCreat
public final fun getLogger ()Lorg/jetbrains/dokka/utilities/DokkaLogger;
protected final fun getMergeImplicitExpectActualDeclarations ()Z
protected final fun getSeparateInheritedMembers ()Z
public fun pageForClasslike (Lorg/jetbrains/dokka/model/DClasslike;)Lorg/jetbrains/dokka/pages/ClasslikePageNode;
public fun pageForClasslike (Lorg/jetbrains/dokka/model/Documentable;)Lorg/jetbrains/dokka/pages/ClasslikePageNode;
public fun pageForClasslikes (Ljava/util/List;)Lorg/jetbrains/dokka/pages/ClasslikePageNode;
public fun pageForEnumEntries (Ljava/util/List;)Lorg/jetbrains/dokka/pages/ClasslikePageNode;
public fun pageForEnumEntry (Lorg/jetbrains/dokka/model/DEnumEntry;)Lorg/jetbrains/dokka/pages/ClasslikePageNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ abstract class NavigationDataProvider {
val isJava = documentable?.hasAnyJavaSources() ?: false

when (documentable) {
is DTypeAlias -> NavigationNodeIcon.TYPEALIAS_KT
is DClass -> when {
documentable.isException -> NavigationNodeIcon.EXCEPTION
documentable.isAbstract() -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ enum class NavigationNodeIcon(
FUNCTION("function"),
EXCEPTION("exception-class"),
OBJECT("object"),
TYPEALIAS_KT("typealias-kt"),
VAL("val"),
VAR("var");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ object AssetsInstaller : PageTransformer {
"images/nav-icons/interface.svg",
"images/nav-icons/interface-kotlin.svg",
"images/nav-icons/object.svg",
"images/nav-icons/typealias-kotlin.svg",
)

override fun invoke(input: RootPageNode) = input.modified(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,34 @@ open class DefaultPageCreator(
open fun pageForModule(m: DModule): ModulePageNode =
ModulePageNode(m.name.ifEmpty { "<root>" }, contentForModule(m), listOf(m), m.packages.map(::pageForPackage))

/**
* We want to generate separated pages for no-actual typealias.
* Actual typealias are displayed on pages for their expect class (trough [ActualTypealias] extra).
*
* @see ActualTypealias
*/
private fun List<Documentable>.filterOutActualTypeAlias(): List<Documentable> {
fun List<Documentable>.hasExpectClass(dri: DRI) = find { it is DClasslike && it.dri == dri && it.expectPresentInSet != null } != null
return this.filterNot { it is DTypeAlias && this.hasExpectClass(it.dri) }
}

open fun pageForPackage(p: DPackage): PackagePageNode = PackagePageNode(
p.name, contentForPackage(p), setOf(p.dri), listOf(p),
if (mergeImplicitExpectActualDeclarations)
p.classlikes.mergeClashingDocumentable().map(::pageForClasslikes) +
(p.classlikes + p.typealiases).filterOutActualTypeAlias()
.mergeClashingDocumentable().map(::pageForClasslikes) +
p.functions.mergeClashingDocumentable().map(::pageForFunctions) +
p.properties.mergeClashingDocumentable().map(::pageForProperties)
else
p.classlikes.renameClashingDocumentable().map(::pageForClasslike) +
(p.classlikes + p.typealiases).filterOutActualTypeAlias()
.renameClashingDocumentable().map(::pageForClasslike) +
p.functions.renameClashingDocumentable().map(::pageForFunction) +
p.properties.mapNotNull(::pageForProperty)
)

open fun pageForEnumEntry(e: DEnumEntry): ClasslikePageNode = pageForEnumEntries(listOf(e))

open fun pageForClasslike(c: DClasslike): ClasslikePageNode = pageForClasslikes(listOf(c))
open fun pageForClasslike(c: Documentable): ClasslikePageNode = pageForClasslikes(listOf(c))

open fun pageForEnumEntries(documentables: List<DEnumEntry>): ClasslikePageNode {
val dri = documentables.dri.also {
Expand All @@ -83,33 +96,38 @@ open class DefaultPageCreator(
)
}

open fun pageForClasslikes(documentables: List<DClasslike>): ClasslikePageNode {
/**
* @param documentables a list of [DClasslike] and [DTypeAlias] with the same dri in different sourceSets
*/
open fun pageForClasslikes(documentables: List<Documentable>): ClasslikePageNode {
val dri = documentables.dri.also {
if (it.size != 1) {
logger.error("Documentable dri should have the same one ${it.first()} inside the one page!")
}
}

val classlikes = documentables.filterIsInstance<DClasslike>()

val constructors =
if (documentables.shouldDocumentConstructors()) {
documentables.flatMap { (it as? WithConstructors)?.constructors ?: emptyList() }
if (classlikes.shouldDocumentConstructors()) {
classlikes.flatMap { (it as? WithConstructors)?.constructors ?: emptyList() }
} else {
emptyList()
}

val classlikes = documentables.flatMap { it.classlikes }
val functions = documentables.flatMap { it.filteredFunctions }
val props = documentables.flatMap { it.filteredProperties }
val entries = documentables.flatMap { if (it is DEnum) it.entries else emptyList() }
val nestedClasslikes = classlikes.flatMap { it.classlikes }
val functions = classlikes.flatMap { it.filteredFunctions }
val props = classlikes.flatMap { it.filteredProperties }
val entries = classlikes.flatMap { if (it is DEnum) it.entries else emptyList() }

val childrenPages = constructors.map(::pageForFunction) +
if (mergeImplicitExpectActualDeclarations)
classlikes.mergeClashingDocumentable().map(::pageForClasslikes) +
nestedClasslikes.mergeClashingDocumentable().map(::pageForClasslikes) +
functions.mergeClashingDocumentable().map(::pageForFunctions) +
props.mergeClashingDocumentable().map(::pageForProperties) +
entries.mergeClashingDocumentable().map(::pageForEnumEntries)
else
classlikes.renameClashingDocumentable().map(::pageForClasslike) +
nestedClasslikes.renameClashingDocumentable().map(::pageForClasslike) +
functions.renameClashingDocumentable().map(::pageForFunction) +
props.renameClashingDocumentable().mapNotNull(::pageForProperty) +
entries.renameClashingDocumentable().map(::pageForEnumEntry)
Expand Down Expand Up @@ -329,7 +347,7 @@ open class DefaultPageCreator(
sortedWith(compareBy({ it.name }, { it.parameters.size }, { it.dri.toString() }))

/**
* @param documentables a list of [DClasslike] and [DEnumEntry] with the same dri in different sourceSets
* @param documentables a list of [DClasslike] and [DEnumEntry] and [DTypeAlias] with the same dri in different sourceSets
*/
protected open fun contentForClasslikesAndEntries(documentables: List<Documentable>): ContentGroup =
IgnatBeresnev marked this conversation as resolved.
Show resolved Hide resolved
contentBuilder.contentFor(documentables.dri, documentables.sourceSets) {
Expand Down Expand Up @@ -477,8 +495,7 @@ open class DefaultPageCreator(
.takeIf { documentable is DProperty }
}?.let {
group(sourceSets = setOf(sourceSet), kind = ContentKind.BriefComment) {
if (documentable.hasSeparatePage) createBriefComment(documentable, sourceSet, it)
else comment(it.root)
createBriefComment(documentable, sourceSet, it)
}
}
}
Expand Down Expand Up @@ -689,6 +706,7 @@ open class DefaultPageCreator(
protected open fun TagWrapper.toHeaderString() = this.javaClass.toGenericString().split('.').last()
}


internal val List<Documentable>.sourceSets: Set<DokkaSourceSet>
get() = flatMap { it.sourceSets }.toSet()

Expand All @@ -706,9 +724,6 @@ internal val Documentable.descriptions: SourceSetDependent<Description>
internal val Documentable.customTags: Map<String, SourceSetDependent<CustomTagWrapper>>
get() = groupedTags.withTypeNamed()

private val Documentable.hasSeparatePage: Boolean
get() = this !is DTypeAlias

/**
* @see DefaultPageCreator.sortDivergentElementsDeterministically for usage
*/
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions plugins/base/src/main/resources/dokka/styles/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,10 @@ code.paragraph {
content: url("../images/nav-icons/object.svg");
}

.nav-icon.typealias-kt::before {
content: url("../images/nav-icons/typealias-kotlin.svg");
}

.nav-icon.val::before {
content: url("../images/nav-icons/field-value.svg");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
import org.jetbrains.dokka.links.DRI
import org.jetbrains.dokka.links.TypeConstructor
import org.jetbrains.dokka.model.DClass
import org.jetbrains.dokka.model.DPackage
import org.jetbrains.dokka.model.dfs
import org.jetbrains.dokka.pages.*
import org.junit.jupiter.api.Assertions.assertEquals
Expand Down Expand Up @@ -131,6 +132,32 @@ class ContentForBriefTest : BaseAbstractTest() {
}
}

@Test
fun `brief should work for typealias`() {
testInline(
"""
|/src/main/kotlin/test/source.kt
|package test
|
|/**
|* This is an example <!-- not visible --> of html
|*
|* This is definitely not a brief
|*/
|typealias A = Int
""".trimIndent(),
testConfiguration
) {
pagesTransformationStage = { module ->
val functionBriefDocs = module.singleTypeAliasesDescription("test")

assertEquals(
"This is an example <!-- not visible --> of html",
functionBriefDocs.children.joinToString("") { (it as ContentText).text })
}
}
}

@Test
fun `brief for functions should work with html`() {
testInline(
Expand Down Expand Up @@ -344,4 +371,14 @@ class ContentForBriefTest : BaseAbstractTest() {
val function = functionsTable.children.first()
return function.dfs { it is ContentGroup && it.dci.kind == ContentKind.Comment && it.children.all { it is ContentText } } as ContentGroup
}
private fun RootPageNode.singleTypeAliasesDescription(packageName: String): ContentGroup {
val packagePage =
dfs { it.name == packageName && (it as WithDocumentables).documentables.firstOrNull() is DPackage } as ContentPage
val contentTable =
packagePage.content.dfs { it is ContentTable && it.dci.kind == ContentKind.Classlikes } as ContentTable

assertEquals(1, contentTable.children.size)
val row = contentTable.children.first()
return row.dfs { it is ContentGroup && it.dci.kind == ContentKind.Comment && it.children.all { it is ContentText } } as ContentGroup
}
}
78 changes: 78 additions & 0 deletions plugins/base/src/test/kotlin/content/typealiases/TypealiasTest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package content.typealiases

import matchers.content.*
import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
import org.jetbrains.dokka.model.dfs
import org.jetbrains.dokka.pages.*
import org.junit.jupiter.api.Test
import utils.assertNotNull


class TypealiasTest : BaseAbstractTest() {
private val configuration = dokkaConfiguration {
sourceSets {
sourceSet {
sourceRoots = listOf("src/")
classpath = listOf(commonStdlibPath!!)
externalDocumentationLinks = listOf(stdlibExternalDocumentationLink)
}
}
}

@Test
fun `typealias should have a dedicated page with full documentation`() {
testInline(
"""
|/src/main/kotlin/test/Test.kt
|package example
|
| /**
| * Brief text
| *
| * some text
| *
| * @see String
| * @throws Unit
| */
| typealias A = String
""",
configuration
) {
pagesTransformationStage = { module ->
val content = (module.dfs { it.name == "A" } as ClasslikePageNode).content
val platformHinted = content.dfs { it is PlatformHintedContent }
platformHinted.assertNotNull("platformHinted").assertNode {
group {
group {
group {
+"typealias "
group { group { link { +"A" } } }
+" = "
group { link { +"String" } }
}
}

group {
group {
group {
group { +"Brief text" }
group { +"some text" }
}
}
}

header { +"See also" }
table {
group { link { +"String" } }
}

header { +"Throws" }
table {
group { group { link { +"Unit" } } }
}
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class NavigationIconTest : BaseAbstractTest() {
.filterKeys { it.startsWith("images/nav-icons") }
.keys.sorted()

assertEquals(15, navIconAssets.size)
assertEquals(16, navIconAssets.size)
assertEquals("images/nav-icons/abstract-class-kotlin.svg", navIconAssets[0])
assertEquals("images/nav-icons/abstract-class.svg", navIconAssets[1])
assertEquals("images/nav-icons/annotation-kotlin.svg", navIconAssets[2])
Expand All @@ -53,6 +53,7 @@ class NavigationIconTest : BaseAbstractTest() {
assertEquals("images/nav-icons/interface-kotlin.svg", navIconAssets[12])
assertEquals("images/nav-icons/interface.svg", navIconAssets[13])
assertEquals("images/nav-icons/object.svg", navIconAssets[14])
assertEquals("images/nav-icons/typealias-kotlin.svg", navIconAssets[15])
}
}
}
Expand Down Expand Up @@ -99,6 +100,15 @@ class NavigationIconTest : BaseAbstractTest() {
)
}

@Test
fun `should add icon styles to kotlin typealias navigation item`() {
assertNavigationIcon(
source = kotlinSource("typealias KotlinTypealias = String"),
expectedIconClass = "typealias-kt",
expectedNavLinkText = "KotlinTypealias"
)
}

@Test
fun `should add icon styles to kotlin enum navigation item`() {
assertNavigationIcon(
Expand Down
6 changes: 3 additions & 3 deletions plugins/base/src/test/kotlin/signatures/SignatureTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ class SignatureTest : BaseAbstractTest() {
pluginOverrides = listOf(writerPlugin)
) {
renderingStage = { _, _ ->
writerPlugin.writer.renderedContent("root/example.html").firstSignature().match(
writerPlugin.writer.renderedContent("root/example/index.html").firstSignature().match(
"typealias ", A("PlainTypealias"), " = ", A("Int"),
ignoreSpanWithTokenStyle = true
)
Expand Down Expand Up @@ -663,7 +663,7 @@ class SignatureTest : BaseAbstractTest() {
pluginOverrides = listOf(writerPlugin)
) {
renderingStage = { _, _ ->
writerPlugin.writer.renderedContent("root/example.html").firstSignature().match(
writerPlugin.writer.renderedContent("root/example/index.html").firstSignature().match(
"typealias ", A("PlainTypealias"), " = ", A("Comparable"),
"<", A("Int"), ">",
ignoreSpanWithTokenStyle = true
Expand All @@ -690,7 +690,7 @@ class SignatureTest : BaseAbstractTest() {
pluginOverrides = listOf(writerPlugin)
) {
renderingStage = { _, _ ->
writerPlugin.writer.renderedContent("root/example.html").firstSignature().match(
writerPlugin.writer.renderedContent("root/example/index.html").firstSignature().match(
"typealias ", A("GenericTypealias"), "<", A("T"), "> = ", A("Comparable"),
"<", A("T"), ">",
ignoreSpanWithTokenStyle = true
Expand Down
Loading
Loading