diff options
3 files changed, 275 insertions, 4 deletions
diff --git a/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt b/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt index 0b9a5c23..a27734cc 100644 --- a/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt +++ b/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt @@ -452,8 +452,9 @@ open class MarkdownParser( if (link is DocumentationLink) link.dri else null } + val allTags = listOf(kDocTag) + if(kDocTag.canHaveParent()) getAllKDocTags(findParent(kDocTag)) else emptyList() DocumentationNode( - (listOf(kDocTag) + getAllKDocTags(findParent(kDocTag))).map { + allTags.map { when (it.knownTag) { null -> if (it.name == null) Description(parseStringToDocNode(it.getContent())) else CustomTagWrapper( parseStringToDocNode(it.getContent()), @@ -511,7 +512,9 @@ open class MarkdownParser( fun DRI.fqName(): String? = "$packageName.$classNames".takeIf { packageName != null && classNames != null } private fun findParent(kDoc: PsiElement): PsiElement = - if (kDoc is KDocSection) findParent(kDoc.parent) else kDoc + if (kDoc.canHaveParent()) findParent(kDoc.parent) else kDoc + + private fun PsiElement.canHaveParent(): Boolean = this is KDocSection && knownTag != KDocKnownTag.PROPERTY private fun getAllKDocTags(kDocImpl: PsiElement): List<KDocTag> = kDocImpl.children.filterIsInstance<KDocTag>().filterNot { it is KDocSection } + kDocImpl.children.flatMap { diff --git a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt index 642f991f..5185dc3e 100644 --- a/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt +++ b/plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt @@ -719,7 +719,7 @@ private class DokkaDescriptorVisitor( private suspend fun List<ClassDescriptor>.visitEnumEntries(parent: DRIWithPlatformInfo): List<DEnumEntry> = coroutineScope { parallelMap { visitEnumEntryDescriptor(it, parent) } } - private suspend fun DeclarationDescriptor.resolveDescriptorData(): SourceSetDependent<DocumentationNode> = + private fun DeclarationDescriptor.resolveDescriptorData(): SourceSetDependent<DocumentationNode> = getDocumentation()?.toSourceSetDependent() ?: emptyMap() @@ -831,7 +831,7 @@ private class DokkaDescriptorVisitor( org.jetbrains.kotlin.types.Variance.OUT_VARIANCE -> Covariance(this) } - private suspend fun DeclarationDescriptor.getDocumentation() = findKDoc().let { + private fun DeclarationDescriptor.getDocumentation() = findKDoc().let { MarkdownParser.parseFromKDocTag( kDocTag = it, externalDri = { link: String -> diff --git a/plugins/base/src/test/kotlin/content/properties/ContentForClassWithParamsAndPropertiesTest.kt b/plugins/base/src/test/kotlin/content/properties/ContentForClassWithParamsAndPropertiesTest.kt new file mode 100644 index 00000000..5bd152dc --- /dev/null +++ b/plugins/base/src/test/kotlin/content/properties/ContentForClassWithParamsAndPropertiesTest.kt @@ -0,0 +1,268 @@ +package content.properties + +import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest +import org.jetbrains.dokka.model.DClass +import org.jetbrains.dokka.model.dfs +import org.jetbrains.dokka.model.doc.* +import org.jetbrains.dokka.pages.ClasslikePageNode +import org.jetbrains.dokka.pages.RootPageNode +import org.junit.jupiter.api.Test +import kotlin.test.assertEquals + +class ContentForClassWithParamsAndPropertiesTest : BaseAbstractTest() { + private val testConfiguration = dokkaConfiguration { + sourceSets { + sourceSet { + sourceRoots = listOf("src/") + analysisPlatform = "jvm" + } + } + } + + @Test + fun `should work for a simple property`() { + propertyTest { rootPage -> + val node = rootPage.dfs { it.name == "LoadInitialParams" } as ClasslikePageNode + val actualDocsForPlaceholdersEnabled = + (node.documentable as DClass).constructors.first().parameters.find { it.name == "placeholdersEnabled" } + ?.documentation?.entries?.first()?.value + assertEquals(DocumentationNode(listOf(docsForPlaceholdersEnabled)), actualDocsForPlaceholdersEnabled) + } + } + + @Test + fun `should work for a simple with linebreak`() { + propertyTest { rootPage -> + val node = rootPage.dfs { it.name == "LoadInitialParams" } as ClasslikePageNode + val actualDocsForRequestedLoadSize = + (node.documentable as DClass).constructors.first().parameters.find { it.name == "requestedLoadSize" } + ?.documentation?.entries?.first()?.value + assertEquals(DocumentationNode(listOf(docsForRequestedLoadSize)), actualDocsForRequestedLoadSize) + } + } + + @Test + fun `should work with multiline property inline code`() { + propertyTest { rootPage -> + val node = rootPage.dfs { it.name == "LoadInitialParams" } as ClasslikePageNode + + val actualDocsForRequestedInitialKey = + (node.documentable as DClass).constructors.first().parameters.find { it.name == "requestedInitialKey" } + ?.documentation?.entries?.first()?.value + assertEquals(DocumentationNode(listOf(docsForRequestedInitialKey)), actualDocsForRequestedInitialKey) + } + } + + @Test + fun `constructor should only the param and constructor tags`() { + propertyTest { rootPage -> + val constructorDocs = Description( + root = CustomDocTag( + children = listOf( + P( + children = listOf( + Text("Creates an empty group.") + ) + ) + ), + emptyMap(), "MARKDOWN_FILE" + ) + ) + val node = rootPage.dfs { it.name == "LoadInitialParams" } as ClasslikePageNode + + val actualDocs = + (node.documentable as DClass).constructors.first().documentation.entries.first().value + assertEquals(DocumentationNode(listOf(constructorDocs, docsForParam)), actualDocs) + } + } + + @Test + fun `class should have all tags`() { + propertyTest { rootPage -> + val ownDescription = Description( + root = CustomDocTag( + children = listOf( + P( + children = listOf( + Text("Holder object for inputs to loadInitial.") + ) + ) + ), + emptyMap(), "MARKDOWN_FILE" + ) + ) + val node = rootPage.dfs { it.name == "LoadInitialParams" } as ClasslikePageNode + + val actualDocs = + (node.documentable as DClass).documentation.entries.first().value + assertEquals( + DocumentationNode( + listOf( + ownDescription, + docsForParam, + docsForRequestedInitialKey, + docsForRequestedLoadSize, + docsForPlaceholdersEnabled, + docsForConstructor + ) + ), + actualDocs + ) + } + } + + @Test + fun `property should also work with own docs that override the param tag`() { + propertyTest { rootPage -> + val ownDescription = Description( + root = CustomDocTag( + children = listOf( + P( + children = listOf( + Text("Own docs") + ) + ) + ), + emptyMap(), "MARKDOWN_FILE" + ) + ) + val node = rootPage.dfs { it.name == "ItemKeyedDataSource" } as ClasslikePageNode + + val actualDocs = + (node.documentable as DClass).properties.first().documentation.entries.first().value + assertEquals( + DocumentationNode(listOf(ownDescription)), + actualDocs + ) + } + } + + + private fun propertyTest(block: (RootPageNode) -> Unit) { + testInline( + """ |/src/main/kotlin/test/source.kt + |package test + |/** + | * @property tested Docs from class + | */ + |abstract class ItemKeyedDataSource<Key : Any, Value : Any> : DataSource<Key, Value>(ITEM_KEYED) { + | /** + | * Own docs + | */ + | val tested = "" + | + | /** + | * Holder object for inputs to loadInitial. + | * + | * @param Key Type of data used to query Value types out of the DataSource. + | * @property requestedInitialKey Load items around this key, or at the beginning of the data set + | * if `null` is passed. + | * + | * Note that this key is generally a hint, and may be ignored if you want to always load from + | * the beginning. + | * @property requestedLoadSize Requested number of items to load. + | * + | * Note that this may be larger than available data. + | * @property placeholdersEnabled Defines whether placeholders are enabled, and whether the + | * loaded total count will be ignored. + | * + | * @constructor Creates an empty group. + | */ + | open class LoadInitialParams<Key : Any>( + | @JvmField + | val requestedInitialKey: Key?, + | @JvmField + | val requestedLoadSize: Int, + | @JvmField + | val placeholdersEnabled: Boolean + | ) + |}""".trimIndent(), testConfiguration + ) { + pagesGenerationStage = block + } + } + + private val docsForPlaceholdersEnabled = Property( + root = CustomDocTag( + listOf( + P( + children = listOf( + Text("Defines whether placeholders are enabled, and whether the loaded total count will be ignored.") + ) + ) + ), emptyMap(), "MARKDOWN_FILE" + ), + name = "placeholdersEnabled" + ) + + private val docsForRequestedInitialKey = Property( + root = CustomDocTag( + listOf( + P( + children = listOf( + Text("Load items around this key, or at the beginning of the data set if "), + CodeInline( + listOf( + Text("null") + ) + ), + Text(" is passed.") + ), + params = emptyMap() + ), + P( + children = listOf( + Text("Note that this key is generally a hint, and may be ignored if you want to always load from the beginning.") + ) + ) + ), emptyMap(), "MARKDOWN_FILE" + ), + name = "requestedInitialKey" + ) + + private val docsForRequestedLoadSize = Property( + root = CustomDocTag( + listOf( + P( + children = listOf( + Text("Requested number of items to load.") + ) + ), + P( + children = listOf( + Text("Note that this may be larger than available data.") + ) + ) + ), emptyMap(), "MARKDOWN_FILE" + ), + name = "requestedLoadSize" + ) + + private val docsForConstructor = Constructor( + root = CustomDocTag( + children = listOf( + P( + children = listOf( + Text("Creates an empty group.") + ) + ) + ), + emptyMap(), "MARKDOWN_FILE" + ) + ) + + private val docsForParam = Param( + root = CustomDocTag( + children = listOf( + P( + children = listOf( + Text("Type of data used to query Value types out of the DataSource.") + ) + ) + ), + emptyMap(), "MARKDOWN_FILE" + ), + name = "Key" + ) +} + |