aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src
diff options
context:
space:
mode:
authorVadim Mishenev <vad-mishenev@yandex.ru>2023-06-30 16:44:20 +0300
committerGitHub <noreply@github.com>2023-06-30 16:44:20 +0300
commit12a386bb7185f862a1cbd831e6856c4235953833 (patch)
tree9fcfaba5bf87587e008fb9feb52264618e4180a2 /plugins/base/src
parent26112637ba3511afc218fbe0ead6f72421ac7c77 (diff)
downloaddokka-12a386bb7185f862a1cbd831e6856c4235953833.tar.gz
dokka-12a386bb7185f862a1cbd831e6856c4235953833.tar.bz2
dokka-12a386bb7185f862a1cbd831e6856c4235953833.zip
Generate dedicated pages for typealiases (#3051)
Diffstat (limited to 'plugins/base/src')
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt1
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt1
-rw-r--r--plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt1
-rw-r--r--plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt51
-rw-r--r--plugins/base/src/main/resources/dokka/images/nav-icons/typealias-kotlin.svg9
-rw-r--r--plugins/base/src/main/resources/dokka/styles/style.css4
-rw-r--r--plugins/base/src/test/kotlin/content/functions/ContentForBriefTest.kt37
-rw-r--r--plugins/base/src/test/kotlin/content/typealiases/TypealiasTest.kt78
-rw-r--r--plugins/base/src/test/kotlin/renderers/html/NavigationIconTest.kt12
-rw-r--r--plugins/base/src/test/kotlin/signatures/SignatureTest.kt6
-rw-r--r--plugins/base/src/test/kotlin/transformers/MergeImplicitExpectActualDeclarationsTest.kt32
11 files changed, 210 insertions, 22 deletions
diff --git a/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt b/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt
index 4dae21c8..be1b0fcf 100644
--- a/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt
@@ -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() -> {
diff --git a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt
index fc17983d..9543c388 100644
--- a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt
@@ -109,6 +109,7 @@ enum class NavigationNodeIcon(
FUNCTION("function"),
EXCEPTION("exception-class"),
OBJECT("object"),
+ TYPEALIAS_KT("typealias-kt"),
VAL("val"),
VAR("var");
diff --git a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
index 7ffcd9e3..a213bce9 100644
--- a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
+++ b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt
@@ -120,6 +120,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(
diff --git a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
index 1abd3441..ffc7fd85 100644
--- a/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
+++ b/plugins/base/src/main/kotlin/translators/documentables/DefaultPageCreator.kt
@@ -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 {
@@ -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)
@@ -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 =
contentBuilder.contentFor(documentables.dri, documentables.sourceSets) {
@@ -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)
}
}
}
@@ -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()
@@ -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
*/
diff --git a/plugins/base/src/main/resources/dokka/images/nav-icons/typealias-kotlin.svg b/plugins/base/src/main/resources/dokka/images/nav-icons/typealias-kotlin.svg
new file mode 100644
index 00000000..4795069b
--- /dev/null
+++ b/plugins/base/src/main/resources/dokka/images/nav-icons/typealias-kotlin.svg
@@ -0,0 +1,9 @@
+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g id="typeAlias">
+<path id="Vector" fill-rule="evenodd" clip-rule="evenodd" d="M8 15C4.134 15 1 11.866 1 8C1 4.134 4.134 1 8 1C11.866 1 15 4.134 15 8H8V15Z" fill="#B99BF8" fill-opacity="0.6"/>
+<path id="Vector_2" fill-rule="evenodd" clip-rule="evenodd" d="M8.5 8H8V11H7.5V6H5.5V5H10.5V6H8.5V8Z" fill="#231F20" fill-opacity="0.7"/>
+<g id="&#226;&#140;&#152;/modifier/kotlin">
+<path id="&#226;&#140;&#152;/modifier/kotlin_2" d="M16 16H9V9H16L12.4 12.4L16 16Z" fill="#B99BF8"/>
+</g>
+</g>
+</svg>
diff --git a/plugins/base/src/main/resources/dokka/styles/style.css b/plugins/base/src/main/resources/dokka/styles/style.css
index 30f3b176..ab48a7db 100644
--- a/plugins/base/src/main/resources/dokka/styles/style.css
+++ b/plugins/base/src/main/resources/dokka/styles/style.css
@@ -913,6 +913,10 @@ code:not(.block) {
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");
}
diff --git a/plugins/base/src/test/kotlin/content/functions/ContentForBriefTest.kt b/plugins/base/src/test/kotlin/content/functions/ContentForBriefTest.kt
index f86506af..c09a0e4d 100644
--- a/plugins/base/src/test/kotlin/content/functions/ContentForBriefTest.kt
+++ b/plugins/base/src/test/kotlin/content/functions/ContentForBriefTest.kt
@@ -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
@@ -132,6 +133,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(
"""
@@ -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
+ }
} \ No newline at end of file
diff --git a/plugins/base/src/test/kotlin/content/typealiases/TypealiasTest.kt b/plugins/base/src/test/kotlin/content/typealiases/TypealiasTest.kt
new file mode 100644
index 00000000..c2f58cb9
--- /dev/null
+++ b/plugins/base/src/test/kotlin/content/typealiases/TypealiasTest.kt
@@ -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" } } }
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/base/src/test/kotlin/renderers/html/NavigationIconTest.kt b/plugins/base/src/test/kotlin/renderers/html/NavigationIconTest.kt
index a7a7bacf..e83f70d5 100644
--- a/plugins/base/src/test/kotlin/renderers/html/NavigationIconTest.kt
+++ b/plugins/base/src/test/kotlin/renderers/html/NavigationIconTest.kt
@@ -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])
@@ -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])
}
}
}
@@ -100,6 +101,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(
source = kotlinSource("enum class KotlinEnum {}"),
diff --git a/plugins/base/src/test/kotlin/signatures/SignatureTest.kt b/plugins/base/src/test/kotlin/signatures/SignatureTest.kt
index 3a263fd0..d271be2e 100644
--- a/plugins/base/src/test/kotlin/signatures/SignatureTest.kt
+++ b/plugins/base/src/test/kotlin/signatures/SignatureTest.kt
@@ -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
)
@@ -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
@@ -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
diff --git a/plugins/base/src/test/kotlin/transformers/MergeImplicitExpectActualDeclarationsTest.kt b/plugins/base/src/test/kotlin/transformers/MergeImplicitExpectActualDeclarationsTest.kt
index 5e335209..241fb481 100644
--- a/plugins/base/src/test/kotlin/transformers/MergeImplicitExpectActualDeclarationsTest.kt
+++ b/plugins/base/src/test/kotlin/transformers/MergeImplicitExpectActualDeclarationsTest.kt
@@ -114,6 +114,38 @@ class MergeImplicitExpectActualDeclarationsTest : BaseAbstractTest() {
}
@Test
+ fun `should merge class and typealias`() {
+ testInline(
+ """
+ |/src/jvmMain/kotlin/pageMerger/Test.kt
+ |package pageMerger
+ |
+ |class A {
+ | fun method1(): String
+ |}
+ |
+ |/src/jsMain/kotlin/pageMerger/Test.kt
+ |package pageMerger
+ |
+ |typealias A = String
+ |
+ """.trimMargin(),
+ configuration(true),
+ cleanupOutput = true
+ ) {
+ pagesTransformationStage = { root ->
+ val classPage = root.dfs { it.name == "A" } as? ClasslikePageNode
+ assertNotNull(classPage, "Tested class not found!")
+
+ val platformHintedContent = classPage.content.dfs { it is PlatformHintedContent }.assertNotNull("platformHintedContent")
+ assertEquals(2, platformHintedContent.sourceSets.size)
+
+ platformHintedContent.dfs { it is ContentText && it.text == "class " }.assertNotNull("class keyword")
+ platformHintedContent.dfs { it is ContentText && it.text == "typealias " }.assertNotNull("typealias keyword")
+ }
+ }
+ }
+ @Test
fun `should merge method and prop`() {
testInline(
"""