From 9559158bfeeb274e9ccf1b4563f1b23b42afc493 Mon Sep 17 00:00:00 2001 From: Ignat Beresnev Date: Wed, 5 Jul 2023 10:04:55 +0200 Subject: Decompose Kotlin/Java analysis (#3034) * Extract analysis into separate modules --- plugins/base/src/main/kotlin/DokkaBase.kt | 71 +- .../base/src/main/kotlin/parsers/MarkdownParser.kt | 604 ---------- plugins/base/src/main/kotlin/parsers/Parser.kt | 131 -- .../factories/DocTagsFromIElementFactory.kt | 67 -- .../parsers/factories/DocTagsFromStringFactory.kt | 77 -- .../IllegalModuleAndPackageDocumentation.kt | 7 - .../ModuleAndPackageDocumentation.kt | 11 - .../ModuleAndPackageDocumentationFragment.kt | 10 - .../ModuleAndPackageDocumentationParsingContext.kt | 64 - .../ModuleAndPackageDocumentationSource.kt | 14 - .../parseModuleAndPackageDocumentation.kt | 12 - .../parseModuleAndPackageDocumentationFragments.kt | 55 - .../main/kotlin/renderers/PackageListService.kt | 5 +- .../src/main/kotlin/renderers/html/HtmlRenderer.kt | 9 +- .../renderers/html/NavigationDataProvider.kt | 18 +- .../main/kotlin/renderers/html/NavigationPage.kt | 2 + .../kotlin/renderers/html/htmlPreprocessors.kt | 2 +- .../src/main/kotlin/renderers/preprocessors.kt | 7 +- .../javadoc/JavadocExternalLocationProvider.kt | 5 +- .../main/kotlin/signatures/JvmSignatureUtils.kt | 6 +- .../kotlin/signatures/KotlinSignatureProvider.kt | 14 +- .../main/kotlin/signatures/KotlinSignatureUtils.kt | 4 +- .../documentables/DefaultDocumentableMerger.kt | 4 +- .../DeprecatedDocumentableFilterTransformer.kt | 2 +- .../DocumentableVisibilityFilterTransformer.kt | 4 +- .../documentables/ExtensionExtractorTransformer.kt | 6 +- ...nheritedEntriesDocumentableFilterTransformer.kt | 5 +- .../InheritorsExtractorTransformer.kt | 2 +- .../ModuleAndPackageDocumentationReader.kt | 107 -- .../ModuleAndPackageDocumentationTransformer.kt | 12 +- .../documentables/ReportUndocumentedTransformer.kt | 41 +- .../documentables/SuppressTagDocumentableFilter.kt | 4 +- .../utils/FullClassHierarchyBuilder.kt | 84 -- .../pages/annotations/SinceKotlinTransformer.kt | 11 +- .../pages/comments/CommentsToContentConverter.kt | 4 +- .../pages/comments/DocTagToContentConverter.kt | 7 +- .../merger/SourceSetMergingPageTransformer.kt | 4 +- .../pages/samples/DefaultSamplesTransformer.kt | 36 - .../pages/samples/SamplesTransformer.kt | 148 --- .../pages/sourcelinks/SourceLinksTransformer.kt | 37 +- .../kotlin/translators/CollectionExtensions.kt | 12 - .../main/kotlin/translators/annotationsValue.kt | 3 - .../DefaultDescriptorToDocumentableTranslator.kt | 1250 -------------------- .../DefaultExternalDocumentablesProvider.kt | 42 - .../DescriptorAccessorConventionUtil.kt | 145 --- .../descriptors/ExternalClasslikesTranslator.kt | 12 - .../descriptors/ExternalDocumentablesProvider.kt | 22 - .../SyntheticDescriptorDocumentationProvider.kt | 47 - .../DefaultDocumentableToPageTranslator.kt | 7 +- .../documentables/DefaultPageCreator.kt | 18 +- .../documentables/DeprecationSectionCreator.kt | 2 +- .../documentables/DescriptionSections.kt | 14 +- .../documentables/briefFromContentNodes.kt | 12 +- .../documentables/documentableLanguage.kt | 15 - .../src/main/kotlin/translators/isException.kt | 18 - .../translators/parseWithNormalisedSpaces.kt | 56 - .../psi/DefaultPsiToDocumentableTranslator.kt | 863 -------------- .../translators/psi/PsiAccessorConventionUtil.kt | 94 -- .../main/kotlin/translators/psi/PsiInheritance.kt | 47 - .../psi/SynheticElementDocumentationProvider.kt | 39 - .../translators/psi/parsers/InheritDocResolver.kt | 129 -- .../translators/psi/parsers/JavadocParser.kt | 511 -------- .../kotlin/translators/psi/parsers/JavadocTag.kt | 32 - .../translators/psi/parsers/PsiCommentsUtils.kt | 146 --- .../kotlin/translators/psi/parsers/exceptionTag.kt | 14 - .../src/main/kotlin/utils/CollectionExtensions.kt | 12 + .../src/main/kotlin/utils/NoopIntellijLogger.kt | 43 - plugins/base/src/test/kotlin/basic/DRITest.kt | 2 +- .../base/src/test/kotlin/basic/DokkaBasicTests.kt | 3 +- .../src/test/kotlin/basic/FailOnWarningTest.kt | 2 +- .../annotations/ContentForAnnotationsTest.kt | 9 +- .../content/annotations/KotlinDeprecatedTest.kt | 4 +- .../kotlin/content/annotations/SinceKotlinTest.kt | 4 +- .../content/exceptions/ContentForExceptions.kt | 5 +- .../content/inheritors/ContentForInheritorsTest.kt | 5 +- .../kotlin/content/params/ContentForParamsTest.kt | 2 +- .../content/signatures/ContentForSignaturesTest.kt | 5 +- .../base/src/test/kotlin/enums/JavaEnumsTest.kt | 3 - .../base/src/test/kotlin/enums/KotlinEnumsTest.kt | 12 +- .../test/kotlin/expectActuals/ExpectActualsTest.kt | 5 +- .../src/test/kotlin/filter/JavaFileFilterTest.kt | 1 - .../filter/KotlinArrayDocumentableReplacerTest.kt | 10 +- .../kotlin/linkableContent/LinkableContentTest.kt | 42 +- .../test/kotlin/linking/EnumValuesLinkingTest.kt | 15 +- .../AndroidExternalLocationProviderTest.kt | 2 +- .../DefaultExternalLocationProviderTest.kt | 2 +- .../Dokka010ExternalLocationProviderTest.kt | 2 +- .../locationProvider/DokkaLocationProviderTest.kt | 7 +- .../JavadocExternalLocationProviderTest.kt | 7 +- .../locationProvider/MultiModuleLinkingTest.kt | 3 +- plugins/base/src/test/kotlin/markdown/KDocTest.kt | 4 +- plugins/base/src/test/kotlin/markdown/LinkTest.kt | 6 +- .../base/src/test/kotlin/markdown/ParserTest.kt | 99 +- plugins/base/src/test/kotlin/model/ClassesTest.kt | 2 +- plugins/base/src/test/kotlin/model/CommentTest.kt | 6 +- .../base/src/test/kotlin/model/ExtensionsTest.kt | 9 +- .../base/src/test/kotlin/model/InheritorsTest.kt | 435 ++++--- .../kotlin/model/MultiLanguageInheritanceTest.kt | 7 +- plugins/base/src/test/kotlin/model/PropertyTest.kt | 3 - .../kotlin/multiplatform/BasicMultiplatformTest.kt | 2 +- .../test/kotlin/pageMerger/PageNodeMergerTest.kt | 7 +- .../src/test/kotlin/parsers/JavadocParserTest.kt | 72 +- ...seModuleAndPackageDocumentationFragmentsTest.kt | 282 ----- .../kotlin/renderers/html/GroupWrappingTest.kt | 2 +- .../renderers/html/HtmlRenderingOnlyTestBase.kt | 4 +- .../kotlin/renderers/html/NavigationIconTest.kt | 2 +- .../test/kotlin/renderers/html/NavigationTest.kt | 2 +- .../FunctionalTypeConstructorsSignatureTest.kt | 3 +- .../kotlin/signatures/ObviousTypeSkippingTest.kt | 2 +- .../kotlin/signatures/VarianceSignatureTest.kt | 1 - .../PageTransformerBuilderTest.kt | 5 +- .../transformers/CommentsToContentConverterTest.kt | 3 +- ...textModuleAndPackageDocumentationReaderTest1.kt | 28 +- ...textModuleAndPackageDocumentationReaderTest3.kt | 8 +- .../test/kotlin/transformers/DivisionSwitchTest.kt | 7 +- ...ntentModuleAndPackageDocumentationReaderTest.kt | 12 +- .../MergeImplicitExpectActualDeclarationsTest.kt | 5 +- ...leAndPackageDocumentationTransformerUnitTest.kt | 36 +- .../ReportUndocumentedTransformerTest.kt | 2 +- .../transformers/SourceLinkTransformerTest.kt | 4 +- ...nfigurationDocumentableFilterTransformerTest.kt | 2 +- .../kotlin/translators/AccessorMethodNamingTest.kt | 5 +- .../base/src/test/kotlin/translators/Bug1341.kt | 2 +- .../DefaultPsiToDocumentableTranslatorTest.kt | 137 ++- .../translators/ExternalDocumentablesTest.kt | 19 +- .../kotlin/translators/JavadocInheritDocsTest.kt | 5 +- .../translators/JavadocInheritedDocTagsTest.kt | 13 +- .../test/kotlin/translators/JavadocParserTest.kt | 4 +- plugins/base/src/test/kotlin/translators/utils.kt | 1 - plugins/base/src/test/kotlin/utils/contentUtils.kt | 7 +- 130 files changed, 709 insertions(+), 6016 deletions(-) delete mode 100644 plugins/base/src/main/kotlin/parsers/MarkdownParser.kt delete mode 100644 plugins/base/src/main/kotlin/parsers/Parser.kt delete mode 100644 plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt delete mode 100644 plugins/base/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt delete mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt delete mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentation.kt delete mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment.kt delete mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext.kt delete mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt delete mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentation.kt delete mode 100644 plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt delete mode 100644 plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt delete mode 100644 plugins/base/src/main/kotlin/transformers/documentables/utils/FullClassHierarchyBuilder.kt delete mode 100644 plugins/base/src/main/kotlin/transformers/pages/samples/DefaultSamplesTransformer.kt delete mode 100644 plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt delete mode 100644 plugins/base/src/main/kotlin/translators/CollectionExtensions.kt delete mode 100644 plugins/base/src/main/kotlin/translators/annotationsValue.kt delete mode 100644 plugins/base/src/main/kotlin/translators/descriptors/DefaultDescriptorToDocumentableTranslator.kt delete mode 100644 plugins/base/src/main/kotlin/translators/descriptors/DefaultExternalDocumentablesProvider.kt delete mode 100644 plugins/base/src/main/kotlin/translators/descriptors/DescriptorAccessorConventionUtil.kt delete mode 100644 plugins/base/src/main/kotlin/translators/descriptors/ExternalClasslikesTranslator.kt delete mode 100644 plugins/base/src/main/kotlin/translators/descriptors/ExternalDocumentablesProvider.kt delete mode 100644 plugins/base/src/main/kotlin/translators/descriptors/SyntheticDescriptorDocumentationProvider.kt delete mode 100644 plugins/base/src/main/kotlin/translators/documentables/documentableLanguage.kt delete mode 100644 plugins/base/src/main/kotlin/translators/isException.kt delete mode 100644 plugins/base/src/main/kotlin/translators/parseWithNormalisedSpaces.kt delete mode 100644 plugins/base/src/main/kotlin/translators/psi/DefaultPsiToDocumentableTranslator.kt delete mode 100644 plugins/base/src/main/kotlin/translators/psi/PsiAccessorConventionUtil.kt delete mode 100644 plugins/base/src/main/kotlin/translators/psi/PsiInheritance.kt delete mode 100644 plugins/base/src/main/kotlin/translators/psi/SynheticElementDocumentationProvider.kt delete mode 100644 plugins/base/src/main/kotlin/translators/psi/parsers/PsiCommentsUtils.kt delete mode 100644 plugins/base/src/main/kotlin/translators/psi/parsers/exceptionTag.kt create mode 100644 plugins/base/src/main/kotlin/utils/CollectionExtensions.kt delete mode 100644 plugins/base/src/main/kotlin/utils/NoopIntellijLogger.kt delete mode 100644 plugins/base/src/test/kotlin/parsers/ParseModuleAndPackageDocumentationFragmentsTest.kt (limited to 'plugins/base/src') diff --git a/plugins/base/src/main/kotlin/DokkaBase.kt b/plugins/base/src/main/kotlin/DokkaBase.kt index 8fc46870..6b000ac6 100644 --- a/plugins/base/src/main/kotlin/DokkaBase.kt +++ b/plugins/base/src/main/kotlin/DokkaBase.kt @@ -3,14 +3,14 @@ package org.jetbrains.dokka.base import org.jetbrains.dokka.CoreExtensions -import org.jetbrains.dokka.analysis.KotlinAnalysis -import org.jetbrains.dokka.analysis.ProjectKotlinAnalysis +import org.jetbrains.dokka.base.generation.SingleModuleGeneration import org.jetbrains.dokka.base.renderers.* import org.jetbrains.dokka.base.renderers.html.* import org.jetbrains.dokka.base.renderers.html.command.consumers.PathToRootConsumer +import org.jetbrains.dokka.base.renderers.html.command.consumers.ReplaceVersionsConsumer import org.jetbrains.dokka.base.renderers.html.command.consumers.ResolveLinkConsumer -import org.jetbrains.dokka.base.resolvers.external.ExternalLocationProviderFactory import org.jetbrains.dokka.base.resolvers.external.DefaultExternalLocationProviderFactory +import org.jetbrains.dokka.base.resolvers.external.ExternalLocationProviderFactory import org.jetbrains.dokka.base.resolvers.external.javadoc.JavadocExternalLocationProviderFactory import org.jetbrains.dokka.base.resolvers.local.DokkaLocationProviderFactory import org.jetbrains.dokka.base.resolvers.local.LocationProviderFactory @@ -23,24 +23,13 @@ import org.jetbrains.dokka.base.transformers.pages.annotations.SinceKotlinTransf import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentConverter import org.jetbrains.dokka.base.transformers.pages.comments.DocTagToContentConverter import org.jetbrains.dokka.base.transformers.pages.merger.* -import org.jetbrains.dokka.base.transformers.pages.samples.DefaultSamplesTransformer import org.jetbrains.dokka.base.transformers.pages.sourcelinks.SourceLinksTransformer -import org.jetbrains.dokka.base.translators.descriptors.DefaultDescriptorToDocumentableTranslator -import org.jetbrains.dokka.base.translators.documentables.DefaultDocumentableToPageTranslator -import org.jetbrains.dokka.base.translators.psi.DefaultPsiToDocumentableTranslator -import org.jetbrains.dokka.base.generation.SingleModuleGeneration -import org.jetbrains.dokka.base.renderers.html.command.consumers.ReplaceVersionsConsumer import org.jetbrains.dokka.base.transformers.pages.tags.CustomTagContentProvider import org.jetbrains.dokka.base.transformers.pages.tags.SinceKotlinTagContentProvider -import org.jetbrains.dokka.base.translators.descriptors.DefaultExternalDocumentablesProvider -import org.jetbrains.dokka.base.translators.descriptors.ExternalClasslikesTranslator -import org.jetbrains.dokka.base.translators.descriptors.ExternalDocumentablesProvider -import org.jetbrains.dokka.base.utils.NoopIntellijLoggerFactory +import org.jetbrains.dokka.base.translators.documentables.DefaultDocumentableToPageTranslator import org.jetbrains.dokka.plugability.DokkaPlugin import org.jetbrains.dokka.plugability.DokkaPluginApiPreview import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement -import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.dokka.renderers.PostAction import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer import org.jetbrains.dokka.transformers.pages.PageTransformer @@ -55,25 +44,16 @@ class DokkaBase : DokkaPlugin() { val externalLocationProviderFactory by extensionPoint() val outputWriter by extensionPoint() val htmlPreprocessors by extensionPoint() - val kotlinAnalysis by extensionPoint() + @Deprecated("It is not used anymore") val tabSortingStrategy by extensionPoint() val immediateHtmlCommandConsumer by extensionPoint() - val externalDocumentablesProvider by extensionPoint() - val externalClasslikesTranslator by extensionPoint() + val singleGeneration by extending { CoreExtensions.generation providing ::SingleModuleGeneration } - val descriptorToDocumentableTranslator by extending { - CoreExtensions.sourceToDocumentableTranslator providing ::DefaultDescriptorToDocumentableTranslator - } - - val psiToDocumentableTranslator by extending { - CoreExtensions.sourceToDocumentableTranslator providing ::DefaultPsiToDocumentableTranslator - } - val documentableMerger by extending { CoreExtensions.documentableMerger providing ::DefaultDocumentableMerger } @@ -168,7 +148,9 @@ class DokkaBase : DokkaPlugin() { } val pageMerger by extending { - CoreExtensions.pageTransformer providing ::PageMerger + CoreExtensions.pageTransformer providing ::PageMerger order { + // TODO [beresnev] make last() or at least after samples transformer + } } val sourceSetMerger by extending { @@ -189,15 +171,6 @@ class DokkaBase : DokkaPlugin() { CoreExtensions.renderer providing ::HtmlRenderer } - val defaultKotlinAnalysis by extending { - kotlinAnalysis providing { ctx -> - ProjectKotlinAnalysis( - sourceSets = ctx.configuration.sourceSets, - logger = ctx.logger - ) - } - } - val locationProvider by extending { locationProviderFactory providing ::DokkaLocationProviderFactory } @@ -218,12 +191,6 @@ class DokkaBase : DokkaPlugin() { htmlPreprocessors with RootCreator applyIf { !delayTemplateSubstitution } } - val defaultSamplesTransformer by extending { - CoreExtensions.pageTransformer providing ::DefaultSamplesTransformer order { - before(pageMerger) - } - } - val sourceLinksTransformer by extending { htmlPreprocessors providing ::SourceLinksTransformer order { after(rootCreator) } } @@ -275,26 +242,6 @@ class DokkaBase : DokkaPlugin() { htmlPreprocessors providing ::SearchbarDataInstaller order { after(sourceLinksTransformer) } } - val defaultExternalDocumentablesProvider by extending { - externalDocumentablesProvider providing ::DefaultExternalDocumentablesProvider - } - - val defaultExternalClasslikesTranslator by extending { - externalClasslikesTranslator providing ::DefaultDescriptorToDocumentableTranslator - } - - internal val disposeKotlinAnalysisPostAction by extending { - CoreExtensions.postActions with PostAction { this@DokkaBase.querySingle { kotlinAnalysis }.close() } - } - - private companion object { - init { - // Suppress messages emitted by the IntelliJ logger since - // there's not much the end user can do about it - com.intellij.openapi.diagnostic.Logger.setFactory(NoopIntellijLoggerFactory()) - } - } - @OptIn(DokkaPluginApiPreview::class) override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement diff --git a/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt b/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt deleted file mode 100644 index d49e7c7a..00000000 --- a/plugins/base/src/main/kotlin/parsers/MarkdownParser.kt +++ /dev/null @@ -1,604 +0,0 @@ -package org.jetbrains.dokka.base.parsers - -import com.intellij.psi.PsiElement -import org.intellij.markdown.MarkdownElementTypes -import org.intellij.markdown.MarkdownTokenTypes -import org.intellij.markdown.ast.ASTNode -import org.intellij.markdown.ast.CompositeASTNode -import org.intellij.markdown.ast.LeafASTNode -import org.intellij.markdown.ast.impl.ListItemCompositeNode -import org.intellij.markdown.flavours.gfm.GFMElementTypes -import org.intellij.markdown.flavours.gfm.GFMFlavourDescriptor -import org.intellij.markdown.flavours.gfm.GFMTokenTypes -import org.intellij.markdown.html.HtmlGenerator -import org.jetbrains.dokka.base.parsers.factories.DocTagsFromIElementFactory -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.links.PointingToDeclaration -import org.jetbrains.dokka.model.doc.* -import org.jetbrains.dokka.model.doc.Suppress -import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag -import org.jetbrains.kotlin.kdoc.psi.impl.KDocSection -import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag -import java.net.MalformedURLException -import java.net.URL -import org.intellij.markdown.parser.MarkdownParser as IntellijMarkdownParser - -open class MarkdownParser( - private val externalDri: (String) -> DRI?, - private val kdocLocation: String?, -) : Parser() { - - private lateinit var destinationLinksMap: Map - private lateinit var text: String - - override fun parseStringToDocNode(extractedString: String): DocTag { - val gfmFlavourDescriptor = GFMFlavourDescriptor() - val markdownAstRoot = IntellijMarkdownParser(gfmFlavourDescriptor).buildMarkdownTreeFromString(extractedString) - destinationLinksMap = getAllDestinationLinks(extractedString, markdownAstRoot).toMap() - text = extractedString - - val parsed = visitNode(markdownAstRoot) - if (parsed.size == 1) { - return parsed.first() - } - return CustomDocTag(children = parsed, params = emptyMap(), name = "") - } - - override fun preparse(text: String) = text.replace("\r\n", "\n").replace("\r", "\n") - - override fun parseTagWithBody(tagName: String, content: String): TagWrapper = - when (tagName) { - "see" -> { - val referencedName = content.substringBefore(' ') - val dri = externalDri(referencedName) - See( - parseStringToDocNode(content.substringAfter(' ')), - dri?.fqDeclarationName() ?: referencedName, - dri - ) - } - "throws", "exception" -> { - val dri = externalDri(content.substringBefore(' ')) - Throws( - parseStringToDocNode(content.substringAfter(' ')), - dri?.fqDeclarationName() ?: content.substringBefore(' '), - dri - ) - } - else -> super.parseTagWithBody(tagName, content) - } - - private fun headersHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, - visitNode(node.children.find { it.type == MarkdownTokenTypes.ATX_CONTENT } - ?: throw detailedException("Wrong AST Tree. Header does not contain expected content", node) - ).flatMap { it.children } - ) - - private fun horizontalRulesHandler() = - DocTagsFromIElementFactory.getInstance(MarkdownTokenTypes.HORIZONTAL_RULE) - - private fun emphasisHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, - children = node.children.evaluateChildrenWithDroppedEnclosingTokens(1) - ) - - private fun strongHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, - children = node.children.evaluateChildrenWithDroppedEnclosingTokens(2) - ) - - private fun List.evaluateChildrenWithDroppedEnclosingTokens(count: Int) = - drop(count).dropLast(count).evaluateChildren() - - private fun blockquotesHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, children = node.children - .filterIsInstance() - .evaluateChildren() - ) - - private fun listsHandler(node: ASTNode): List { - - val children = node.children.filterIsInstance().flatMap { - if (it.children.last().type in listOf( - MarkdownElementTypes.ORDERED_LIST, - MarkdownElementTypes.UNORDERED_LIST - ) - ) { - val nestedList = it.children.last() - (it.children as MutableList).removeAt(it.children.lastIndex) - listOf(it, nestedList) - } else - listOf(it) - } - - return DocTagsFromIElementFactory.getInstance( - node.type, - children = - children - .flatMap { - if (it.type == MarkdownElementTypes.LIST_ITEM) - DocTagsFromIElementFactory.getInstance( - it.type, - children = it - .children - .filterIsInstance() - .evaluateChildren() - ) - else - visitNode(it) - }, - params = - if (node.type == MarkdownElementTypes.ORDERED_LIST) { - val listNumberNode = node.children.first().children.first() - mapOf( - "start" to text.substring( - listNumberNode.startOffset, - listNumberNode.endOffset - ).trim().dropLast(1) - ) - } else - emptyMap() - ) - } - - private fun resolveDRI(mdLink: String): DRI? = - mdLink - .removePrefix("[") - .removeSuffix("]") - .let { link -> - try { - URL(link) - null - } catch (e: MalformedURLException) { - externalDri(link) - } - } - - private fun getAllDestinationLinks(text: String, node: ASTNode): List> = - node.children - .filter { it.type == MarkdownElementTypes.LINK_DEFINITION } - .map { - text.substring(it.children[0].startOffset, it.children[0].endOffset).toLowerCase() to - text.substring(it.children[2].startOffset, it.children[2].endOffset) - } + - node.children.filterIsInstance().flatMap { getAllDestinationLinks(text, it) } - - - private fun referenceLinksHandler(node: ASTNode): List { - val linkLabel = node.children.find { it.type == MarkdownElementTypes.LINK_LABEL } - ?: throw detailedException("Wrong AST Tree. Reference link does not contain link label", node) - val linkText = node.children.findLast { it.type == MarkdownElementTypes.LINK_TEXT } ?: linkLabel - - val linkKey = text.substring(linkLabel.startOffset, linkLabel.endOffset) - - val link = destinationLinksMap[linkKey.toLowerCase()] ?: linkKey - - return linksHandler(linkText, link) - } - - private fun inlineLinksHandler(node: ASTNode): List { - val linkText = node.children.find { it.type == MarkdownElementTypes.LINK_TEXT } - ?: throw detailedException("Wrong AST Tree. Inline link does not contain link text", node) - val linkDestination = node.children.find { it.type == MarkdownElementTypes.LINK_DESTINATION } - val linkTitle = node.children.find { it.type == MarkdownElementTypes.LINK_TITLE } - - // Link destination may be ommited: https://github.github.com/gfm/#example-495 - val link = linkDestination?.let { text.substring(it.startOffset, it.endOffset) } - - return linksHandler(linkText, link, linkTitle) - } - - private fun markdownFileHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, - children = node.children - .filterSpacesAndEOL() - .evaluateChildren() - ) - - private fun autoLinksHandler(node: ASTNode): List { - val link = text.substring(node.startOffset + 1, node.endOffset - 1) - - return linksHandler(node, link) - } - - private fun linksHandler(linkText: ASTNode, link: String?, linkTitle: ASTNode? = null): List { - val dri: DRI? = link?.let { resolveDRI(it) } - val linkOrEmpty = link ?: "" - val linkTextString = - if (linkTitle == null) linkOrEmpty else text.substring(linkTitle.startOffset + 1, linkTitle.endOffset - 1) - - val params = if (linkTitle == null) - mapOf("href" to linkOrEmpty) - else - mapOf("href" to linkOrEmpty, "title" to linkTextString) - - return if (link != null && dri == null && !linkOrEmpty.isRemoteLink()) { - DocTagsFromIElementFactory.getInstance( - MarkdownTokenTypes.TEXT, - params = params, - children = linkText.children.drop(1).dropLast(1).evaluateChildren(), - body = linkTextString.removeSurrounding("[", "]") - ) - } else { - DocTagsFromIElementFactory.getInstance( - MarkdownElementTypes.INLINE_LINK, - params = params, - children = linkText.children.drop(1).dropLast(1).evaluateChildren(), - dri = dri - ) - } - } - - private fun codeLineHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( - MarkdownElementTypes.CODE_BLOCK, - body = text.substring(node.startOffset, node.endOffset) - ) - - private fun textHandler(node: ASTNode, keepAllFormatting: Boolean) = DocTagsFromIElementFactory.getInstance( - MarkdownTokenTypes.TEXT, - body = text.substring(node.startOffset, node.endOffset).transform(), - keepFormatting = keepAllFormatting - ) - - private fun strikeThroughHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( - node.type, - children = node.children.evaluateChildrenWithDroppedEnclosingTokens(2) - ) - - private fun tableHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( - GFMElementTypes.TABLE, - children = node.children - .filter { it.type == GFMElementTypes.ROW || it.type == GFMElementTypes.HEADER } - .evaluateChildren() - ) - - private fun headerHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( - GFMElementTypes.HEADER, - children = node.children - .filter { it.type == GFMTokenTypes.CELL } - .evaluateChildren() - ) - - private fun rowHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( - GFMElementTypes.ROW, - children = node.children - .filter { it.type == GFMTokenTypes.CELL } - .evaluateChildren() - ) - - private fun cellHandler(node: ASTNode) = DocTagsFromIElementFactory.getInstance( - GFMTokenTypes.CELL, - children = node.children.filterTabSeparators().evaluateChildren().trimSurroundingTokensIfText() - ) - - private fun String.isRemoteLink() = try { - URL(this) - true - } catch (e: MalformedURLException) { - false - } - - private fun imagesHandler(node: ASTNode): List = - with(node.children.last().children) { - val destination = find { it.type == MarkdownElementTypes.LINK_DESTINATION } - val description = find { it.type == MarkdownElementTypes.LINK_TEXT } - - val src = destination?.let { - mapOf("href" to text.substring(it.startOffset, it.endOffset)) - } ?: emptyMap() - - val alt = description?.let { - mapOf("alt" to text.substring(it.startOffset + 1, it.endOffset - 1)) - } ?: emptyMap() - - return DocTagsFromIElementFactory.getInstance( - node.type, - params = src + alt - ) - } - - - private fun rawHtmlHandler(node: ASTNode): List = - DocTagsFromIElementFactory.getInstance( - node.type, - body = text.substring(node.startOffset, node.endOffset) - ) - - private fun codeSpansHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, - children = DocTagsFromIElementFactory.getInstance( - MarkdownTokenTypes.TEXT, - body = text.substring(node.startOffset + 1, node.endOffset - 1).replace('\n', ' ').trimIndent(), - keepFormatting = true - ) - ) - - private fun codeFencesHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - node.type, - children = node - .children - .dropWhile { it.type != MarkdownTokenTypes.CODE_FENCE_CONTENT } - .dropLastWhile { it.type != MarkdownTokenTypes.CODE_FENCE_CONTENT } - .filter { it.type != MarkdownTokenTypes.WHITE_SPACE } - .map { - if (it.type == MarkdownTokenTypes.EOL) - LeafASTNode(MarkdownTokenTypes.HARD_LINE_BREAK, 0, 0) - else - it - }.evaluateChildren(keepAllFormatting = true), - params = node - .children - .find { it.type == MarkdownTokenTypes.FENCE_LANG } - ?.let { mapOf("lang" to text.substring(it.startOffset, it.endOffset)) } - ?: emptyMap() - ) - - private fun codeBlocksHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance(node.type, children = node.children.mergeLeafASTNodes().flatMap { - DocTagsFromIElementFactory.getInstance( - MarkdownTokenTypes.TEXT, - body = HtmlGenerator.trimIndents(text.substring(it.startOffset, it.endOffset), 4).toString() - ) - }) - - private fun defaultHandler(node: ASTNode) = - DocTagsFromIElementFactory.getInstance( - MarkdownElementTypes.PARAGRAPH, - children = node.children.evaluateChildren() - ) - - private fun visitNode(node: ASTNode, keepAllFormatting: Boolean = false): List = - when (node.type) { - MarkdownElementTypes.ATX_1, - MarkdownElementTypes.ATX_2, - MarkdownElementTypes.ATX_3, - MarkdownElementTypes.ATX_4, - MarkdownElementTypes.ATX_5, - MarkdownElementTypes.ATX_6, - -> headersHandler(node) - MarkdownTokenTypes.HORIZONTAL_RULE -> horizontalRulesHandler() - MarkdownElementTypes.STRONG -> strongHandler(node) - MarkdownElementTypes.EMPH -> emphasisHandler(node) - MarkdownElementTypes.FULL_REFERENCE_LINK, - MarkdownElementTypes.SHORT_REFERENCE_LINK, - -> referenceLinksHandler(node) - MarkdownElementTypes.INLINE_LINK -> inlineLinksHandler(node) - MarkdownElementTypes.AUTOLINK -> autoLinksHandler(node) - MarkdownElementTypes.BLOCK_QUOTE -> blockquotesHandler(node) - MarkdownElementTypes.UNORDERED_LIST, - MarkdownElementTypes.ORDERED_LIST, - -> listsHandler(node) - MarkdownElementTypes.CODE_BLOCK -> codeBlocksHandler(node) - MarkdownElementTypes.CODE_FENCE -> codeFencesHandler(node) - MarkdownElementTypes.CODE_SPAN -> codeSpansHandler(node) - MarkdownElementTypes.IMAGE -> imagesHandler(node) - MarkdownElementTypes.HTML_BLOCK, - MarkdownTokenTypes.HTML_TAG, - MarkdownTokenTypes.HTML_BLOCK_CONTENT, - -> rawHtmlHandler(node) - MarkdownTokenTypes.HARD_LINE_BREAK -> DocTagsFromIElementFactory.getInstance(node.type) - MarkdownTokenTypes.CODE_FENCE_CONTENT, - MarkdownTokenTypes.CODE_LINE, - -> codeLineHandler(node) - MarkdownTokenTypes.TEXT -> textHandler(node, keepAllFormatting) - MarkdownElementTypes.MARKDOWN_FILE -> markdownFileHandler(node) - GFMElementTypes.STRIKETHROUGH -> strikeThroughHandler(node) - GFMElementTypes.TABLE -> tableHandler(node) - GFMElementTypes.HEADER -> headerHandler(node) - GFMElementTypes.ROW -> rowHandler(node) - GFMTokenTypes.CELL -> cellHandler(node) - else -> defaultHandler(node) - } - - private fun List.filterTabSeparators() = - this.filterNot { it.type == GFMTokenTypes.TABLE_SEPARATOR } - - private fun List.filterSpacesAndEOL() = - this.filterNot { it.type == MarkdownTokenTypes.WHITE_SPACE || it.type == MarkdownTokenTypes.EOL } - - private fun List.evaluateChildren(keepAllFormatting: Boolean = false): List = - this.removeUselessTokens().swapImagesThatShouldBeLinks(keepAllFormatting).mergeLeafASTNodes().flatMap { visitNode(it, keepAllFormatting) } - - private fun List.swapImagesThatShouldBeLinks(keepAllFormatting: Boolean): List = - if (keepAllFormatting) { - this - } else { - flatMap { node -> - if (node.type == MarkdownElementTypes.IMAGE - && node.children.firstOrNull()?.let { it is LeafASTNode && it.type.name == "!" } == true - && node.children.lastOrNull()?.type == MarkdownElementTypes.SHORT_REFERENCE_LINK - ) { - node.children - } else { - listOf(node) - } - } - } - - private fun List.removeUselessTokens(): List = - this.filterIndexed { index, node -> - !(node.type == MarkdownElementTypes.LINK_DEFINITION || ( - node.type == MarkdownTokenTypes.EOL && - this.getOrNull(index - 1)?.type == MarkdownTokenTypes.HARD_LINE_BREAK - )) - } - - private fun List.trimSurroundingTokensIfText() = mapIndexed { index, elem -> - val elemTransformed = if (index == 0 && elem is Text) elem.copy(elem.body.trimStart()) else elem - if (index == lastIndex && elemTransformed is Text) elemTransformed.copy(elemTransformed.body.trimEnd()) else elemTransformed - } - - private val notLeafNodes = listOf( - MarkdownTokenTypes.HORIZONTAL_RULE, - MarkdownTokenTypes.HARD_LINE_BREAK, - MarkdownTokenTypes.HTML_TAG, - MarkdownTokenTypes.HTML_BLOCK_CONTENT - ) - - private fun ASTNode.isNotLeaf() = this is CompositeASTNode || this.type in notLeafNodes - - private fun List.isNotLeaf(index: Int): Boolean = - if (index in 0..this.lastIndex) - this[index].isNotLeaf() - else - false - - private fun List.mergeLeafASTNodes(): List { - val children: MutableList = mutableListOf() - var index = 0 - while (index <= this.lastIndex) { - if (this.isNotLeaf(index)) { - children += this[index] - } else { - val startOffset = this[index].startOffset - val sIndex = index - while (index < this.lastIndex) { - if (this.isNotLeaf(index + 1) || this[index + 1].startOffset != this[index].endOffset) { - children += mergedLeafNode(this, index, startOffset, sIndex) - break - } - index++ - } - if (index == this.lastIndex) { - children += mergedLeafNode(this, index, startOffset, sIndex) - } - } - index++ - } - return children - } - - private fun mergedLeafNode(nodes: List, index: Int, startOffset: Int, sIndex: Int): LeafASTNode { - val endOffset = nodes[index].endOffset - val type = if (nodes.subList(sIndex, index) - .any { it.type == MarkdownTokenTypes.CODE_LINE } - ) MarkdownTokenTypes.CODE_LINE else MarkdownTokenTypes.TEXT - return LeafASTNode(type, startOffset, endOffset) - } - - private fun String.transform() = this - .replace(Regex("\n\n+"), "") // Squashing new lines between paragraphs - .replace(Regex("\n"), " ") - .replace(Regex(" >+ +"), " ") // Replacement used in blockquotes, get rid of garbage - - private fun detailedException(baseMessage: String, node: ASTNode) = - IllegalStateException( - baseMessage + " in ${kdocLocation ?: "unspecified location"}, element starts from offset ${node.startOffset} and ends ${node.endOffset}: ${ - text.substring( - node.startOffset, - node.endOffset - ) - }" - ) - - - companion object { - fun parseFromKDocTag( - kDocTag: KDocTag?, - externalDri: (String) -> DRI?, - kdocLocation: String?, - parseWithChildren: Boolean = true - ): DocumentationNode { - return if (kDocTag == null) { - DocumentationNode(emptyList()) - } else { - fun parseStringToDocNode(text: String) = - MarkdownParser(externalDri, kdocLocation).parseStringToDocNode(text) - - fun pointedLink(tag: KDocTag): DRI? = (parseStringToDocNode("[${tag.getSubjectName()}]")).let { - val link = it.children[0].children[0] - if (link is DocumentationLink) link.dri else null - } - - val allTags = - listOf(kDocTag) + if (kDocTag.canHaveParent() && parseWithChildren) getAllKDocTags(findParent(kDocTag)) else emptyList() - DocumentationNode( - allTags.map { - when (it.knownTag) { - null -> if (it.name == null) Description(parseStringToDocNode(it.getContent())) else CustomTagWrapper( - parseStringToDocNode(it.getContent()), - it.name!! - ) - KDocKnownTag.AUTHOR -> Author(parseStringToDocNode(it.getContent())) - KDocKnownTag.THROWS -> { - val dri = pointedLink(it) - Throws( - parseStringToDocNode(it.getContent()), - dri?.fqDeclarationName() ?: it.getSubjectName().orEmpty(), - dri, - ) - } - KDocKnownTag.EXCEPTION -> { - val dri = pointedLink(it) - Throws( - parseStringToDocNode(it.getContent()), - dri?.fqDeclarationName() ?: it.getSubjectName().orEmpty(), - dri - ) - } - KDocKnownTag.PARAM -> Param( - parseStringToDocNode(it.getContent()), - it.getSubjectName().orEmpty() - ) - KDocKnownTag.RECEIVER -> Receiver(parseStringToDocNode(it.getContent())) - KDocKnownTag.RETURN -> Return(parseStringToDocNode(it.getContent())) - KDocKnownTag.SEE -> { - val dri = pointedLink(it) - See( - parseStringToDocNode(it.getContent()), - dri?.fqDeclarationName() ?: it.getSubjectName().orEmpty(), - dri, - ) - } - KDocKnownTag.SINCE -> Since(parseStringToDocNode(it.getContent())) - KDocKnownTag.CONSTRUCTOR -> Constructor(parseStringToDocNode(it.getContent())) - KDocKnownTag.PROPERTY -> Property( - parseStringToDocNode(it.getContent()), - it.getSubjectName().orEmpty() - ) - KDocKnownTag.SAMPLE -> Sample( - parseStringToDocNode(it.getContent()), - it.getSubjectName().orEmpty() - ) - KDocKnownTag.SUPPRESS -> Suppress(parseStringToDocNode(it.getContent())) - } - } - ) - } - } - - //Horrible hack but since link resolution is passed as a function i am not able to resolve them otherwise - @kotlin.Suppress("DeprecatedCallableAddReplaceWith") - @Deprecated("This function makes wrong assumptions and is missing a lot of corner cases related to generics, " + - "parameters and static members. This is not supposed to be public API and will not be supported in the future") - fun DRI.fqName(): String? = "$packageName.$classNames".takeIf { packageName != null && classNames != null } - - private fun DRI.fqDeclarationName(): String? { - if (this.target !is PointingToDeclaration) { - return null - } - return listOfNotNull(this.packageName, this.classNames, this.callable?.name) - .joinToString(separator = ".") - .takeIf { it.isNotBlank() } - } - - private fun findParent(kDoc: PsiElement): PsiElement = - 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 = - kDocImpl.children.filterIsInstance().filterNot { it is KDocSection } + kDocImpl.children.flatMap { - getAllKDocTags(it) - } - } -} - diff --git a/plugins/base/src/main/kotlin/parsers/Parser.kt b/plugins/base/src/main/kotlin/parsers/Parser.kt deleted file mode 100644 index af07ec53..00000000 --- a/plugins/base/src/main/kotlin/parsers/Parser.kt +++ /dev/null @@ -1,131 +0,0 @@ -package org.jetbrains.dokka.base.parsers - -import org.jetbrains.dokka.model.doc.* -import org.jetbrains.dokka.model.doc.Deprecated -import org.jetbrains.dokka.model.doc.Suppress - -abstract class Parser { - - abstract fun parseStringToDocNode(extractedString: String): DocTag - - abstract fun preparse(text: String): String - - open fun parse(text: String): DocumentationNode = - DocumentationNode(extractTagsToListOfPairs(preparse(text)).map { (tag, content) -> parseTagWithBody(tag, content) }) - - open fun parseTagWithBody(tagName: String, content: String): TagWrapper = - when (tagName) { - "description" -> Description(parseStringToDocNode(content)) - "author" -> Author(parseStringToDocNode(content)) - "version" -> Version(parseStringToDocNode(content)) - "since" -> Since(parseStringToDocNode(content)) - "see" -> See( - parseStringToDocNode(content.substringAfter(' ')), - content.substringBefore(' '), - null - ) - "param" -> Param( - parseStringToDocNode(content.substringAfter(' ')), - content.substringBefore(' ') - ) - "property" -> Property( - parseStringToDocNode(content.substringAfter(' ')), - content.substringBefore(' ') - ) - "return" -> Return(parseStringToDocNode(content)) - "constructor" -> Constructor(parseStringToDocNode(content)) - "receiver" -> Receiver(parseStringToDocNode(content)) - "throws", "exception" -> Throws( - parseStringToDocNode(content.substringAfter(' ')), - content.substringBefore(' '), - null - ) - "deprecated" -> Deprecated(parseStringToDocNode(content)) - "sample" -> Sample( - parseStringToDocNode(content.substringAfter(' ')), - content.substringBefore(' ') - ) - "suppress" -> Suppress(parseStringToDocNode(content)) - else -> CustomTagWrapper(parseStringToDocNode(content), tagName) - } - - /** - * KDoc parser from Kotlin compiler relies on a comment asterisk - * So there is a mini parser here - * TODO: at least to adapt [org.jetbrains.kotlin.kdoc.lexer.KDocLexer] to analyze KDoc without the asterisks and use it here - */ - private fun extractTagsToListOfPairs(text: String): List> = - "description $text" - .extractKDocSections() - .map { content -> - val contentWithEscapedAts = content.replace("\\@", "@") - val (tag, body) = contentWithEscapedAts.split(" ", limit = 2) - tag to body - } - - /** - * Ignore a doc tag inside code spans and blocks - * @see org.jetbrains.kotlin.kdoc.psi.impl.KDocSection - */ - private fun CharSequence.extractKDocSections(delimiter: String = "\n@"): List { - var countOfBackticks = 0 - var countOfTildes = 0 - var countOfBackticksInOpeningFence = 0 - var countOfTildesInOpeningFence = 0 - - var isInCode = false - val result = mutableListOf() - var rangeStart = 0 - var rangeEnd = 0 - var currentOffset = 0 - while (currentOffset < length) { - - when (get(currentOffset)) { - '`' -> { - countOfBackticks++ - countOfTildes = 0 - } - '~' -> { - countOfTildes++ - countOfBackticks = 0 - } - else -> { - if (isInCode) { - // The closing code fence must be at least as long as the opening fence - if(countOfBackticks >= countOfBackticksInOpeningFence - || countOfTildes >= countOfTildesInOpeningFence) - isInCode = false - } else { - // as per CommonMark spec, there can be any number of backticks for a code span, not only one or three - if (countOfBackticks > 0) { - isInCode = true - countOfBackticksInOpeningFence = countOfBackticks - countOfTildesInOpeningFence = Int.MAX_VALUE - } - // tildes are only for a code block, not code span - if (countOfTildes >= 3) { - isInCode = true - countOfTildesInOpeningFence = countOfTildes - countOfBackticksInOpeningFence = Int.MAX_VALUE - } - } - countOfTildes = 0 - countOfBackticks = 0 - } - } - if (!isInCode && startsWith(delimiter, currentOffset)) { - result.add(substring(rangeStart, rangeEnd)) - currentOffset += delimiter.length - rangeStart = currentOffset - rangeEnd = currentOffset - continue - } - - ++rangeEnd - ++currentOffset - } - result.add(substring(rangeStart, rangeEnd)) - return result - } - -} diff --git a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt b/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt deleted file mode 100644 index fed3f7eb..00000000 --- a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromIElementFactory.kt +++ /dev/null @@ -1,67 +0,0 @@ -package org.jetbrains.dokka.base.parsers.factories - -import org.jetbrains.dokka.model.doc.* -import org.intellij.markdown.IElementType -import org.intellij.markdown.MarkdownElementTypes -import org.intellij.markdown.MarkdownTokenTypes -import org.intellij.markdown.flavours.gfm.GFMElementTypes -import org.intellij.markdown.flavours.gfm.GFMTokenTypes -import org.jetbrains.dokka.base.translators.parseWithNormalisedSpaces -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.doc.DocTag.Companion.contentTypeParam - -object DocTagsFromIElementFactory { - - @Suppress("IMPLICIT_CAST_TO_ANY") - fun getInstance(type: IElementType, children: List = emptyList(), params: Map = emptyMap(), body: String? = null, dri: DRI? = null, keepFormatting: Boolean = false) = - when(type) { - MarkdownElementTypes.SHORT_REFERENCE_LINK, - MarkdownElementTypes.FULL_REFERENCE_LINK, - MarkdownElementTypes.INLINE_LINK -> if(dri == null) A(children, params) else DocumentationLink(dri, children, params) - MarkdownElementTypes.STRONG -> B(children, params) - MarkdownElementTypes.BLOCK_QUOTE -> BlockQuote(children, params) - MarkdownElementTypes.CODE_SPAN -> CodeInline(children, params) - MarkdownElementTypes.CODE_BLOCK, - MarkdownElementTypes.CODE_FENCE -> CodeBlock(children, params) - MarkdownElementTypes.ATX_1 -> H1(children, params) - MarkdownElementTypes.ATX_2 -> H2(children, params) - MarkdownElementTypes.ATX_3 -> H3(children, params) - MarkdownElementTypes.ATX_4 -> H4(children, params) - MarkdownElementTypes.ATX_5 -> H5(children, params) - MarkdownElementTypes.ATX_6 -> H6(children, params) - MarkdownElementTypes.EMPH -> I(children, params) - MarkdownElementTypes.IMAGE -> Img(children, params) - MarkdownElementTypes.LIST_ITEM -> Li(children, params) - MarkdownElementTypes.ORDERED_LIST -> Ol(children, params) - MarkdownElementTypes.UNORDERED_LIST -> Ul(children, params) - MarkdownElementTypes.PARAGRAPH -> P(children, params) - MarkdownTokenTypes.TEXT -> if (keepFormatting) Text( - body.orEmpty(), - children, - params - ) else { - // corner case: there are only spaces between two Markdown nodes - val containsOnlySpaces = body?.isNotEmpty() == true && body.all { it.isWhitespace() } - if (containsOnlySpaces) Text(" ", children, params) - else body?.parseWithNormalisedSpaces(renderWhiteCharactersAsSpaces = false).orEmpty() - } - MarkdownTokenTypes.HORIZONTAL_RULE -> HorizontalRule - MarkdownTokenTypes.HARD_LINE_BREAK -> Br - GFMElementTypes.STRIKETHROUGH -> Strikethrough(children, params) - GFMElementTypes.TABLE -> Table(children, params) - GFMElementTypes.HEADER -> Th(children, params) - GFMElementTypes.ROW -> Tr(children, params) - GFMTokenTypes.CELL -> Td(children, params) - MarkdownElementTypes.MARKDOWN_FILE -> CustomDocTag(children, params, MarkdownElementTypes.MARKDOWN_FILE.name) - MarkdownElementTypes.HTML_BLOCK, - MarkdownTokenTypes.HTML_TAG, - MarkdownTokenTypes.HTML_BLOCK_CONTENT -> Text(body.orEmpty(), params = params + contentTypeParam("html")) - else -> CustomDocTag(children, params, type.name) - }.let { - @Suppress("UNCHECKED_CAST") - when (it) { - is List<*> -> it as List - else -> listOf(it as DocTag) - } - } -} diff --git a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt b/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt deleted file mode 100644 index 1af4e719..00000000 --- a/plugins/base/src/main/kotlin/parsers/factories/DocTagsFromStringFactory.kt +++ /dev/null @@ -1,77 +0,0 @@ -package org.jetbrains.dokka.base.parsers.factories - -import org.jetbrains.dokka.model.doc.* -import org.jetbrains.dokka.links.DRI -import java.lang.NullPointerException - -object DocTagsFromStringFactory { - fun getInstance(name: String, children: List = emptyList(), params: Map = emptyMap(), body: String? = null, dri: DRI? = null) = - when(name) { - "a" -> A(children, params) - "big" -> Big(children, params) - "b" -> B(children, params) - "blockquote" -> BlockQuote(children, params) - "br" -> Br - "cite" -> Cite(children, params) - "code" -> if(params.isEmpty()) CodeInline(children, params) else CodeBlock(children, params) - "dd" -> Dd(children, params) - "dfn" -> Dfn(children, params) - "dir" -> Dir(children, params) - "div" -> Div(children, params) - "dl" -> Dl(children, params) - "dt" -> Dt(children, params) - "Em" -> Em(children, params) - "font" -> Font(children, params) - "footer" -> Footer(children, params) - "frame" -> Frame(children, params) - "frameset" -> FrameSet(children, params) - "h1" -> H1(children, params) - "h2" -> H2(children, params) - "h3" -> H3(children, params) - "h4" -> H4(children, params) - "h5" -> H5(children, params) - "h6" -> H6(children, params) - "head" -> Head(children, params) - "header" -> Header(children, params) - "html" -> Html(children, params) - "i" -> I(children, params) - "iframe" -> IFrame(children, params) - "img" -> Img(children, params) - "input" -> Input(children, params) - "li" -> Li(children, params) - "link" -> Link(children, params) - "listing" -> Listing(children, params) - "main" -> Main(children, params) - "menu" -> Menu(children, params) - "meta" -> Meta(children, params) - "nav" -> Nav(children, params) - "noframes" -> NoFrames(children, params) - "noscript" -> NoScript(children, params) - "ol" -> Ol(children, params) - "p" -> P(children, params) - "pre" -> Pre(children, params) - "script" -> Script(children, params) - "section" -> Section(children, params) - "small" -> Small(children, params) - "span" -> Span(children, params) - "strong" -> Strong(children, params) - "sub" -> Sub(children, params) - "sup" -> Sup(children, params) - "table" -> Table(children, params) - "#text" -> Text(body ?: throw NullPointerException("Text body should be at least empty string passed to DocNodes factory!"), children, params) - "tBody" -> TBody(children, params) - "td" -> Td(children, params) - "tFoot" -> TFoot(children, params) - "th" -> Th(children, params) - "tHead" -> THead(children, params) - "title" -> Title(children, params) - "tr" -> Tr(children, params) - "tt" -> Tt(children, params) - "u" -> U(children, params) - "ul" -> Ul(children, params) - "var" -> Var(children, params) - "documentationlink" -> DocumentationLink(dri ?: throw NullPointerException("DRI cannot be passed null while constructing documentation link!"), children, params) - "hr" -> HorizontalRule - else -> CustomDocTag(children, params, name) - } -} diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt deleted file mode 100644 index f642c374..00000000 --- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/IllegalModuleAndPackageDocumentation.kt +++ /dev/null @@ -1,7 +0,0 @@ -package org.jetbrains.dokka.base.parsers.moduleAndPackage - -import org.jetbrains.dokka.DokkaException - -internal class IllegalModuleAndPackageDocumentation( - source: ModuleAndPackageDocumentationSource, message: String -) : DokkaException("[$source] $message") diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentation.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentation.kt deleted file mode 100644 index ee67fad1..00000000 --- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentation.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.jetbrains.dokka.base.parsers.moduleAndPackage - -import org.jetbrains.dokka.model.doc.DocumentationNode - -data class ModuleAndPackageDocumentation( - val name: String, - val classifier: Classifier, - val documentation: DocumentationNode -) { - enum class Classifier { Module, Package } -} diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment.kt deleted file mode 100644 index 06fef72c..00000000 --- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationFragment.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.jetbrains.dokka.base.parsers.moduleAndPackage - -import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.* - -data class ModuleAndPackageDocumentationFragment( - val name: String, - val classifier: Classifier, - val documentation: String, - val source: ModuleAndPackageDocumentationSource -) diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext.kt deleted file mode 100644 index fa6c653e..00000000 --- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationParsingContext.kt +++ /dev/null @@ -1,64 +0,0 @@ -package org.jetbrains.dokka.base.parsers.moduleAndPackage - -import org.jetbrains.dokka.analysis.DokkaResolutionFacade -import org.jetbrains.dokka.analysis.from -import org.jetbrains.dokka.base.parsers.MarkdownParser -import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Module -import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.Package -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.doc.DocumentationNode -import org.jetbrains.dokka.utilities.DokkaLogger -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor -import org.jetbrains.kotlin.descriptors.FunctionDescriptor -import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.name.Name - -fun interface ModuleAndPackageDocumentationParsingContext { - fun markdownParserFor(fragment: ModuleAndPackageDocumentationFragment, location: String): MarkdownParser -} - -internal fun ModuleAndPackageDocumentationParsingContext.parse( - fragment: ModuleAndPackageDocumentationFragment -): DocumentationNode { - return markdownParserFor(fragment, fragment.source.sourceDescription).parse(fragment.documentation) -} - -fun ModuleAndPackageDocumentationParsingContext( - logger: DokkaLogger, - facade: DokkaResolutionFacade? = null -) = ModuleAndPackageDocumentationParsingContext { fragment, sourceLocation -> - val descriptor = when (fragment.classifier) { - Module -> facade?.moduleDescriptor?.getPackage(FqName.topLevel(Name.identifier(""))) - Package -> facade?.moduleDescriptor?.getPackage(FqName(fragment.name)) - } - - val externalDri = { link: String -> - try { - if (facade != null && descriptor != null) { - resolveKDocLink( - facade.resolveSession.bindingContext, - facade, - descriptor, - null, - link.split('.') - ).sorted().firstOrNull()?.let { DRI.from(it) } - } else null - } catch (e1: IllegalArgumentException) { - logger.warn("Couldn't resolve link for $link") - null - } - } - - MarkdownParser(externalDri = externalDri, sourceLocation) -} - -private fun Collection.sorted() = sortedWith( - compareBy( - { it is ClassDescriptor }, - { (it as? FunctionDescriptor)?.name }, - { (it as? FunctionDescriptor)?.valueParameters?.size }, - { (it as? FunctionDescriptor)?.valueParameters?.joinToString { it.type.toString() } } - ) -) diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt deleted file mode 100644 index 9514adb4..00000000 --- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/ModuleAndPackageDocumentationSource.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.jetbrains.dokka.base.parsers.moduleAndPackage - -import java.io.File - -abstract class ModuleAndPackageDocumentationSource { - abstract val sourceDescription: String - abstract val documentation: String - override fun toString(): String = sourceDescription -} - -internal data class ModuleAndPackageDocumentationFile(private val file: File) : ModuleAndPackageDocumentationSource() { - override val sourceDescription: String = file.path - override val documentation: String by lazy(LazyThreadSafetyMode.PUBLICATION) { file.readText() } -} diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentation.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentation.kt deleted file mode 100644 index db342042..00000000 --- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentation.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.jetbrains.dokka.base.parsers.moduleAndPackage - -fun parseModuleAndPackageDocumentation( - context: ModuleAndPackageDocumentationParsingContext, - fragment: ModuleAndPackageDocumentationFragment -): ModuleAndPackageDocumentation { - return ModuleAndPackageDocumentation( - name = fragment.name, - classifier = fragment.classifier, - documentation = context.parse(fragment) - ) -} diff --git a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt b/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt deleted file mode 100644 index d3381901..00000000 --- a/plugins/base/src/main/kotlin/parsers/moduleAndPackage/parseModuleAndPackageDocumentationFragments.kt +++ /dev/null @@ -1,55 +0,0 @@ -package org.jetbrains.dokka.base.parsers.moduleAndPackage - -import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier.* -import java.io.File - - -fun parseModuleAndPackageDocumentationFragments(source: File): List { - return parseModuleAndPackageDocumentationFragments(ModuleAndPackageDocumentationFile(source)) -} - -fun parseModuleAndPackageDocumentationFragments( - source: ModuleAndPackageDocumentationSource -): List { - val fragmentStrings = source.documentation.split(Regex("(|^)#\\s*(?=(Module|Package))")) - return fragmentStrings - .filter(String::isNotBlank) - .map { fragmentString -> parseModuleAndPackageDocFragment(source, fragmentString) } -} - -private fun parseModuleAndPackageDocFragment( - source: ModuleAndPackageDocumentationSource, - fragment: String -): ModuleAndPackageDocumentationFragment { - val firstLineAndDocumentation = fragment.split("\r\n", "\n", "\r", limit = 2) - val firstLine = firstLineAndDocumentation[0] - - val classifierAndName = firstLine.split(Regex("\\s+"), limit = 2) - - val classifier = when (classifierAndName[0].trim()) { - "Module" -> Module - "Package" -> Package - else -> throw IllegalStateException( - """Unexpected classifier: "${classifierAndName[0]}", expected either "Module" or "Package". - |For more information consult the specification: https://kotlinlang.org/docs/dokka-module-and-package-docs.html""".trimMargin() - ) - } - - if (classifierAndName.size != 2 && classifier == Module) { - throw IllegalModuleAndPackageDocumentation(source, "Missing Module name") - } - - val name = classifierAndName.getOrNull(1)?.trim().orEmpty() - if (classifier == Package && name.contains(Regex("\\s"))) { - throw IllegalModuleAndPackageDocumentation( - source, "Package name cannot contain whitespace in '$firstLine'" - ) - } - - return ModuleAndPackageDocumentationFragment( - name = name, - classifier = classifier, - documentation = firstLineAndDocumentation.getOrNull(1)?.trim().orEmpty(), - source = source - ) -} diff --git a/plugins/base/src/main/kotlin/renderers/PackageListService.kt b/plugins/base/src/main/kotlin/renderers/PackageListService.kt index 2bf66ebf..79391a1c 100644 --- a/plugins/base/src/main/kotlin/renderers/PackageListService.kt +++ b/plugins/base/src/main/kotlin/renderers/PackageListService.kt @@ -3,14 +3,13 @@ package org.jetbrains.dokka.base.renderers import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.resolvers.shared.LinkFormat import org.jetbrains.dokka.base.resolvers.shared.PackageList.Companion.DOKKA_PARAM_PREFIX -import org.jetbrains.dokka.base.resolvers.shared.PackageList.Companion.SINGLE_MODULE_NAME import org.jetbrains.dokka.base.resolvers.shared.PackageList.Companion.MODULE_DELIMITER +import org.jetbrains.dokka.base.resolvers.shared.PackageList.Companion.SINGLE_MODULE_NAME import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.kotlin.utils.addToStdlib.safeAs class PackageListService(val context: DokkaContext, val rootPage: RootPageNode) { @@ -29,7 +28,7 @@ class PackageListService(val context: DokkaContext, val rootPage: RootPageNode) ?.let { packages.add(it) } } - val contentPage = node.safeAs() + val contentPage = node as? ContentPage contentPage?.dri?.forEach { dri -> val nodeLocation = locationProvider.resolve(node, context = module, skipExtension = true) ?: run { context.logger.error("Cannot resolve path for ${node.name}!"); null } diff --git a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt index 94bd0aeb..fa343eec 100644 --- a/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt +++ b/plugins/base/src/main/kotlin/renderers/html/HtmlRenderer.kt @@ -23,7 +23,6 @@ import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.pages.HtmlContent import org.jetbrains.dokka.plugability.* import org.jetbrains.dokka.utilities.htmlEscape -import org.jetbrains.kotlin.utils.addIfNotNull internal const val TEMPLATE_REPLACEMENT: String = "###" internal const val TOGGLEABLE_CONTENT_TYPE_ATTR = "data-togglable" @@ -355,12 +354,10 @@ open class HtmlRenderer( val contentOfSourceSet = mutableListOf() distinct.onEachIndexed{ index, (_, distinctInstances) -> - contentOfSourceSet.addIfNotNull(distinctInstances.firstOrNull()?.before) + distinctInstances.firstOrNull()?.before?.let { contentOfSourceSet.add(it) } contentOfSourceSet.addAll(distinctInstances.map { it.divergent }) - contentOfSourceSet.addIfNotNull( - distinctInstances.firstOrNull()?.after - ?: if (index != distinct.size - 1) ContentBreakLine(it.key) else null - ) + (distinctInstances.firstOrNull()?.after ?: if (index != distinct.size - 1) ContentBreakLine(it.key) else null) + ?.let { contentOfSourceSet.add(it) } // content kind main is important for declarations list to avoid double line breaks if (node.dci.kind == ContentKind.Main && index != distinct.size - 1) { diff --git a/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt b/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt index be1b0fcf..c864295c 100644 --- a/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt +++ b/plugins/base/src/main/kotlin/renderers/html/NavigationDataProvider.kt @@ -4,13 +4,20 @@ import org.jetbrains.dokka.base.renderers.sourceSets import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.annotations import org.jetbrains.dokka.base.transformers.documentables.isDeprecated import org.jetbrains.dokka.base.transformers.documentables.isException -import org.jetbrains.dokka.base.translators.documentables.DocumentableLanguage -import org.jetbrains.dokka.base.translators.documentables.documentableLanguage import org.jetbrains.dokka.base.utils.canonicalAlphabeticalOrder import org.jetbrains.dokka.model.* import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle +import org.jetbrains.kotlin.analysis.kotlin.internal.DocumentableLanguage +import org.jetbrains.kotlin.analysis.kotlin.internal.InternalKotlinAnalysisPlugin + +abstract class NavigationDataProvider( + dokkaContext: DokkaContext +) { + private val documentableSourceLanguageParser = dokkaContext.plugin().querySingle { documentableSourceLanguageParser } -abstract class NavigationDataProvider { open fun navigableChildren(input: RootPageNode): NavigationNode = input.withDescendants() .first { it is ModulePage || it is MultimoduleRootPage }.let { visit(it as ContentPage) } @@ -68,8 +75,9 @@ abstract class NavigationDataProvider { } private fun Documentable.hasAnyJavaSources(): Boolean { - val withSources = this as? WithSources ?: return false - return this.sourceSets.any { withSources.documentableLanguage(it) == DocumentableLanguage.JAVA } + return this.sourceSets.any { sourceSet -> + documentableSourceLanguageParser.getLanguage(this, sourceSet) == DocumentableLanguage.JAVA + } } private fun DClass.isAbstract() = diff --git a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt index 9543c388..4def7088 100644 --- a/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt +++ b/plugins/base/src/main/kotlin/renderers/html/NavigationPage.kt @@ -2,6 +2,8 @@ package org.jetbrains.dokka.base.renderers.html import kotlinx.html.* import kotlinx.html.stream.createHTML +import org.jetbrains.dokka.base.renderers.html.NavigationNodeIcon.CLASS +import org.jetbrains.dokka.base.renderers.html.NavigationNodeIcon.CLASS_KT import org.jetbrains.dokka.base.renderers.pageId import org.jetbrains.dokka.base.templating.AddToNavigationCommand import org.jetbrains.dokka.links.DRI diff --git a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt index a213bce9..557205d7 100644 --- a/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt +++ b/plugins/base/src/main/kotlin/renderers/html/htmlPreprocessors.kt @@ -11,7 +11,7 @@ import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.configuration import org.jetbrains.dokka.transformers.pages.PageTransformer -open class NavigationPageInstaller(val context: DokkaContext) : NavigationDataProvider(), PageTransformer { +open class NavigationPageInstaller(val context: DokkaContext) : NavigationDataProvider(context), PageTransformer { override fun invoke(input: RootPageNode): RootPageNode = input.modified( children = input.children + NavigationPage( diff --git a/plugins/base/src/main/kotlin/renderers/preprocessors.kt b/plugins/base/src/main/kotlin/renderers/preprocessors.kt index 8a30bed1..2cfa2dcf 100644 --- a/plugins/base/src/main/kotlin/renderers/preprocessors.kt +++ b/plugins/base/src/main/kotlin/renderers/preprocessors.kt @@ -1,12 +1,7 @@ package org.jetbrains.dokka.base.renderers import org.jetbrains.dokka.base.resolvers.shared.LinkFormat -import org.jetbrains.dokka.pages.ModulePage -import org.jetbrains.dokka.pages.RendererSpecificPage -import org.jetbrains.dokka.pages.RendererSpecificResourcePage -import org.jetbrains.dokka.pages.RendererSpecificRootPage -import org.jetbrains.dokka.pages.RenderingStrategy -import org.jetbrains.dokka.pages.RootPageNode +import org.jetbrains.dokka.pages.* import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.pages.PageTransformer diff --git a/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProvider.kt b/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProvider.kt index a1f1542d..3ac987f6 100644 --- a/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProvider.kt +++ b/plugins/base/src/main/kotlin/resolvers/external/javadoc/JavadocExternalLocationProvider.kt @@ -2,7 +2,10 @@ package org.jetbrains.dokka.base.resolvers.external.javadoc import org.jetbrains.dokka.base.resolvers.external.DefaultExternalLocationProvider import org.jetbrains.dokka.base.resolvers.shared.ExternalDocumentation -import org.jetbrains.dokka.links.* +import org.jetbrains.dokka.links.Callable +import org.jetbrains.dokka.links.DRI +import org.jetbrains.dokka.links.DRIExtraContainer +import org.jetbrains.dokka.links.EnumEntryDRIExtra import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.utilities.htmlEscape diff --git a/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt b/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt index f6c4f0db..e589da15 100644 --- a/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt +++ b/plugins/base/src/main/kotlin/signatures/JvmSignatureUtils.kt @@ -1,13 +1,13 @@ package org.jetbrains.dokka.base.signatures +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet +import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.drisOfAllNestedBounds import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.AnnotationTarget import org.jetbrains.dokka.model.properties.WithExtraProperties import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.drisOfAllNestedBounds -import org.jetbrains.dokka.model.AnnotationTarget interface JvmSignatureUtils { diff --git a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt index dfb0d3f7..8f278545 100644 --- a/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt +++ b/plugins/base/src/main/kotlin/signatures/KotlinSignatureProvider.kt @@ -2,7 +2,6 @@ package org.jetbrains.dokka.base.signatures import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.Platform -import org.jetbrains.dokka.analysis.DescriptorDocumentableSource import org.jetbrains.dokka.base.DokkaBase import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.dri import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.driOrNull @@ -18,15 +17,14 @@ import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.plugability.plugin import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.utilities.DokkaLogger -import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi -import org.jetbrains.kotlin.psi.KtParameter import kotlin.text.Typography.nbsp class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLogger) : SignatureProvider, JvmSignatureUtils by KotlinSignatureUtils { + constructor(context: DokkaContext) : this( context.plugin().querySingle { commentsToContentConverter }, - context.logger + context.logger, ) private val contentBuilder = PageContentBuilder(ctcc, this, logger) @@ -222,8 +220,12 @@ class KotlinSignatureProvider(ctcc: CommentsToContentConverter, logger: DokkaLog * An example would be a primary constructor `class A(val s: String)`, * where `s` is both a function parameter and a property */ - private fun DProperty.isAlsoParameter(sourceSet: DokkaSourceSet) = - (this.sources[sourceSet] as? DescriptorDocumentableSource)?.descriptor?.findPsi() is KtParameter + private fun DProperty.isAlsoParameter(sourceSet: DokkaSourceSet): Boolean { + return this.extra[IsAlsoParameter] + ?.inSourceSets + ?.any { it.sourceSetID == sourceSet.sourceSetID } + ?: false + } private fun propertySignature(p: DProperty) = p.sourceSets.map { sourceSet -> diff --git a/plugins/base/src/main/kotlin/signatures/KotlinSignatureUtils.kt b/plugins/base/src/main/kotlin/signatures/KotlinSignatureUtils.kt index ae5275a5..e47c85b9 100644 --- a/plugins/base/src/main/kotlin/signatures/KotlinSignatureUtils.kt +++ b/plugins/base/src/main/kotlin/signatures/KotlinSignatureUtils.kt @@ -1,14 +1,14 @@ package org.jetbrains.dokka.base.signatures -import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder import org.jetbrains.dokka.base.transformers.pages.annotations.SinceKotlinTransformer -import org.jetbrains.dokka.pages.ContentKind +import org.jetbrains.dokka.base.translators.documentables.PageContentBuilder import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.DriOfAny import org.jetbrains.dokka.links.DriOfUnit import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.AnnotationTarget import org.jetbrains.dokka.model.properties.WithExtraProperties +import org.jetbrains.dokka.pages.ContentKind object KotlinSignatureUtils : JvmSignatureUtils { diff --git a/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt index 17e3cbcd..d9c68981 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/DefaultDocumentableMerger.kt @@ -1,13 +1,13 @@ package org.jetbrains.dokka.base.transformers.documentables import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.base.utils.firstNotNullOfOrNull import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.properties.ExtraProperty import org.jetbrains.dokka.model.properties.MergeStrategy import org.jetbrains.dokka.model.properties.mergeExtras import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.documentation.DocumentableMerger -import org.jetbrains.kotlin.util.firstNotNullResult internal class DefaultDocumentableMerger(val context: DokkaContext) : DocumentableMerger { private val dependencyInfo = context.getDependencyInfo() @@ -21,7 +21,7 @@ internal class DefaultDocumentableMerger(val context: DokkaContext) : Documentab list.flatMap { it.packages } ) { pck1, pck2 -> pck1.mergeWith(pck2) }, documentation = list.map { it.documentation }.flatMap { it.entries }.associate { (k, v) -> k to v }, - expectPresentInSet = list.firstNotNullResult { it.expectPresentInSet }, + expectPresentInSet = list.firstNotNullOfOrNull { it.expectPresentInSet }, sourceSets = list.flatMap { it.sourceSets }.toSet() ).mergeExtras(left, right) } diff --git a/plugins/base/src/main/kotlin/transformers/documentables/DeprecatedDocumentableFilterTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/DeprecatedDocumentableFilterTransformer.kt index 1112ac15..366690c7 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/DeprecatedDocumentableFilterTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/DeprecatedDocumentableFilterTransformer.kt @@ -1,7 +1,7 @@ package org.jetbrains.dokka.base.transformers.documentables -import org.jetbrains.dokka.DokkaConfiguration.PackageOptions import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.DokkaConfiguration.PackageOptions import org.jetbrains.dokka.model.Annotations import org.jetbrains.dokka.model.Documentable import org.jetbrains.dokka.model.EnumValue diff --git a/plugins/base/src/main/kotlin/transformers/documentables/DocumentableVisibilityFilterTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/DocumentableVisibilityFilterTransformer.kt index 94688799..713166bb 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/DocumentableVisibilityFilterTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/DocumentableVisibilityFilterTransformer.kt @@ -1,11 +1,11 @@ package org.jetbrains.dokka.base.transformers.documentables import org.jetbrains.dokka.DokkaConfiguration +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet +import org.jetbrains.dokka.DokkaDefaults import org.jetbrains.dokka.model.* import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.DokkaDefaults class DocumentableVisibilityFilterTransformer(val context: DokkaContext) : PreMergeDocumentableTransformer { diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ExtensionExtractorTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/ExtensionExtractorTransformer.kt index 19af0564..79df844e 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ExtensionExtractorTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ExtensionExtractorTransformer.kt @@ -2,7 +2,6 @@ package org.jetbrains.dokka.base.transformers.documentables import kotlinx.coroutines.* import kotlinx.coroutines.channels.* -import org.jetbrains.dokka.base.transformers.documentables.utils.FullClassHierarchyBuilder import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.links.DriOfAny import org.jetbrains.dokka.model.* @@ -10,16 +9,19 @@ import org.jetbrains.dokka.model.properties.ExtraProperty import org.jetbrains.dokka.model.properties.MergeStrategy import org.jetbrains.dokka.model.properties.plus import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.transformers.documentation.DocumentableTransformer import org.jetbrains.dokka.utilities.parallelForEach import org.jetbrains.dokka.utilities.parallelMap +import org.jetbrains.kotlin.analysis.kotlin.internal.InternalKotlinAnalysisPlugin class ExtensionExtractorTransformer : DocumentableTransformer { override fun invoke(original: DModule, context: DokkaContext): DModule = runBlocking(Dispatchers.Default) { val classGraph = async { if (!context.configuration.suppressInheritedMembers) - FullClassHierarchyBuilder()(original) + context.plugin().querySingle { fullClassHierarchyBuilder }.build(original) else emptyMap() } diff --git a/plugins/base/src/main/kotlin/transformers/documentables/InheritedEntriesDocumentableFilterTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/InheritedEntriesDocumentableFilterTransformer.kt index 2e4b29ff..01438432 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/InheritedEntriesDocumentableFilterTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/InheritedEntriesDocumentableFilterTransformer.kt @@ -1,6 +1,7 @@ package org.jetbrains.dokka.base.transformers.documentables -import org.jetbrains.dokka.model.* +import org.jetbrains.dokka.model.Documentable +import org.jetbrains.dokka.model.InheritedMember import org.jetbrains.dokka.model.properties.WithExtraProperties import org.jetbrains.dokka.plugability.DokkaContext @@ -14,4 +15,4 @@ class InheritedEntriesDocumentableFilterTransformer(context: DokkaContext) : return context.configuration.suppressInheritedMembers && containsInheritedFrom } -} \ No newline at end of file +} diff --git a/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt index 463ec419..6106466f 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/InheritorsExtractorTransformer.kt @@ -1,11 +1,11 @@ package org.jetbrains.dokka.base.transformers.documentables +import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.links.DRI import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.properties.ExtraProperty import org.jetbrains.dokka.model.properties.MergeStrategy import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.transformers.documentation.DocumentableTransformer class InheritorsExtractorTransformer : DocumentableTransformer { diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt deleted file mode 100644 index faf94db2..00000000 --- a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationReader.kt +++ /dev/null @@ -1,107 +0,0 @@ -package org.jetbrains.dokka.base.transformers.documentables - -import org.jetbrains.dokka.DokkaConfiguration -import org.jetbrains.dokka.analysis.KotlinAnalysis -import org.jetbrains.dokka.base.DokkaBase -import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentation.Classifier -import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentationFragment -import org.jetbrains.dokka.base.parsers.moduleAndPackage.ModuleAndPackageDocumentationParsingContext -import org.jetbrains.dokka.base.parsers.moduleAndPackage.parseModuleAndPackageDocumentation -import org.jetbrains.dokka.base.parsers.moduleAndPackage.parseModuleAndPackageDocumentationFragments -import org.jetbrains.dokka.model.DModule -import org.jetbrains.dokka.model.DPackage -import org.jetbrains.dokka.model.SourceSetDependent -import org.jetbrains.dokka.model.doc.* -import org.jetbrains.dokka.model.doc.Deprecated -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.dokka.utilities.associateWithNotNull - -internal interface ModuleAndPackageDocumentationReader { - operator fun get(module: DModule): SourceSetDependent - operator fun get(pkg: DPackage): SourceSetDependent -} - -internal fun ModuleAndPackageDocumentationReader(context: DokkaContext): ModuleAndPackageDocumentationReader = - ContextModuleAndPackageDocumentationReader(context) - -private class ContextModuleAndPackageDocumentationReader( - private val context: DokkaContext -) : ModuleAndPackageDocumentationReader { - - private val kotlinAnalysis: KotlinAnalysis = context.plugin().querySingle { kotlinAnalysis } - - private val documentationFragments: SourceSetDependent> = - context.configuration.sourceSets.associateWith { sourceSet -> - sourceSet.includes.flatMap { include -> parseModuleAndPackageDocumentationFragments(include) } - } - - private fun findDocumentationNodes( - sourceSets: Set, - predicate: (ModuleAndPackageDocumentationFragment) -> Boolean - ): SourceSetDependent { - return sourceSets.associateWithNotNull { sourceSet -> - val fragments = documentationFragments[sourceSet].orEmpty().filter(predicate) - val resolutionFacade = kotlinAnalysis[sourceSet].facade - val documentations = fragments.map { fragment -> - parseModuleAndPackageDocumentation( - context = ModuleAndPackageDocumentationParsingContext(context.logger, resolutionFacade), - fragment = fragment - ) - } - when (documentations.size) { - 0 -> null - 1 -> documentations.single().documentation - else -> DocumentationNode(documentations.flatMap { it.documentation.children } - .mergeDocumentationNodes()) - } - } - } - - private val ModuleAndPackageDocumentationFragment.canonicalPackageName: String - get() { - check(classifier == Classifier.Package) - if (name == "[root]") return "" - return name - } - - override fun get(module: DModule): SourceSetDependent { - return findDocumentationNodes(module.sourceSets) { fragment -> - fragment.classifier == Classifier.Module && (fragment.name == module.name) - } - } - - override fun get(pkg: DPackage): SourceSetDependent { - return findDocumentationNodes(pkg.sourceSets) { fragment -> - fragment.classifier == Classifier.Package && fragment.canonicalPackageName == pkg.dri.packageName - } - } - - private fun List.mergeDocumentationNodes(): List = - groupBy { it::class }.values.map { - it.reduce { acc, tagWrapper -> - val newRoot = CustomDocTag( - acc.children + tagWrapper.children, - name = (tagWrapper as? NamedTagWrapper)?.name.orEmpty() - ) - when (acc) { - is See -> acc.copy(newRoot) - is Param -> acc.copy(newRoot) - is Throws -> acc.copy(newRoot) - is Sample -> acc.copy(newRoot) - is Property -> acc.copy(newRoot) - is CustomTagWrapper -> acc.copy(newRoot) - is Description -> acc.copy(newRoot) - is Author -> acc.copy(newRoot) - is Version -> acc.copy(newRoot) - is Since -> acc.copy(newRoot) - is Return -> acc.copy(newRoot) - is Receiver -> acc.copy(newRoot) - is Constructor -> acc.copy(newRoot) - is Deprecated -> acc.copy(newRoot) - is org.jetbrains.dokka.model.doc.Suppress -> acc.copy(newRoot) - } - } - } -} diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt index 99fba9f7..9f10873b 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ModuleAndPackageDocumentationTransformer.kt @@ -5,21 +5,27 @@ import org.jetbrains.dokka.model.DModule import org.jetbrains.dokka.model.SourceSetDependent import org.jetbrains.dokka.model.doc.DocumentationNode import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.transformers.documentation.PreMergeDocumentableTransformer +import org.jetbrains.kotlin.analysis.kotlin.internal.InternalKotlinAnalysisPlugin +import org.jetbrains.kotlin.analysis.kotlin.internal.ModuleAndPackageDocumentationReader internal class ModuleAndPackageDocumentationTransformer( private val moduleAndPackageDocumentationReader: ModuleAndPackageDocumentationReader ) : PreMergeDocumentableTransformer { - constructor(context: DokkaContext) : this(ModuleAndPackageDocumentationReader(context)) + constructor(context: DokkaContext) : this( + context.plugin().querySingle { moduleAndPackageDocumentationReader } + ) override fun invoke(modules: List): List { return modules.map { module -> module.copy( - documentation = module.documentation + moduleAndPackageDocumentationReader[module], + documentation = module.documentation + moduleAndPackageDocumentationReader.read(module), packages = module.packages.map { pkg -> pkg.copy( - documentation = pkg.documentation + moduleAndPackageDocumentationReader[pkg] + documentation = pkg.documentation + moduleAndPackageDocumentationReader.read(pkg) ) } ) diff --git a/plugins/base/src/main/kotlin/transformers/documentables/ReportUndocumentedTransformer.kt b/plugins/base/src/main/kotlin/transformers/documentables/ReportUndocumentedTransformer.kt index ad9e34df..3368ded1 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/ReportUndocumentedTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/ReportUndocumentedTransformer.kt @@ -2,14 +2,12 @@ package org.jetbrains.dokka.base.transformers.documentables import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.analysis.DescriptorDocumentableSource import org.jetbrains.dokka.model.* import org.jetbrains.dokka.plugability.DokkaContext +import org.jetbrains.dokka.plugability.plugin +import org.jetbrains.dokka.plugability.querySingle import org.jetbrains.dokka.transformers.documentation.DocumentableTransformer -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.FAKE_OVERRIDE -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED -import org.jetbrains.kotlin.utils.addToStdlib.safeAs +import org.jetbrains.kotlin.analysis.kotlin.internal.InternalKotlinAnalysisPlugin internal class ReportUndocumentedTransformer : DocumentableTransformer { @@ -19,14 +17,14 @@ internal class ReportUndocumentedTransformer : DocumentableTransformer { private fun invoke(documentable: Documentable, context: DokkaContext) { documentable.sourceSets.forEach { sourceSet -> - if (shouldBeReportedIfNotDocumented(documentable, sourceSet)) { + if (shouldBeReportedIfNotDocumented(documentable, sourceSet, context)) { reportIfUndocumented(context, documentable, sourceSet) } } } private fun shouldBeReportedIfNotDocumented( - documentable: Documentable, sourceSet: DokkaSourceSet + documentable: Documentable, sourceSet: DokkaSourceSet, context: DokkaContext ): Boolean { val packageOptionsOrNull = packageOptionsOrNull(sourceSet, documentable) @@ -42,11 +40,8 @@ internal class ReportUndocumentedTransformer : DocumentableTransformer { return false } - if (isFakeOverride(documentable, sourceSet)) { - return false - } - - if (isSynthesized(documentable, sourceSet)) { + val syntheticDetector = context.plugin().querySingle { syntheticDocumentableDetector } + if (syntheticDetector.isSynthetic(documentable, sourceSet)) { return false } @@ -118,28 +113,8 @@ internal class ReportUndocumentedTransformer : DocumentableTransformer { return documentable.isConstructor } - private fun isFakeOverride(documentable: Documentable, sourceSet: DokkaSourceSet): Boolean { - return callableMemberDescriptorOrNull(documentable, sourceSet)?.kind == FAKE_OVERRIDE - } - - private fun isSynthesized(documentable: Documentable, sourceSet: DokkaSourceSet): Boolean { - return callableMemberDescriptorOrNull(documentable, sourceSet)?.kind == SYNTHESIZED - } - - private fun callableMemberDescriptorOrNull( - documentable: Documentable, sourceSet: DokkaSourceSet - ): CallableMemberDescriptor? { - if (documentable is WithSources) { - return documentable.sources[sourceSet] - .safeAs()?.descriptor - .safeAs() - } - - return null - } - private fun isPrivateOrInternalApi(documentable: Documentable, sourceSet: DokkaSourceSet): Boolean { - return when (documentable.safeAs()?.visibility?.get(sourceSet)) { + return when ((documentable as? WithVisibility)?.visibility?.get(sourceSet)) { KotlinVisibility.Public -> false KotlinVisibility.Private -> true KotlinVisibility.Protected -> true diff --git a/plugins/base/src/main/kotlin/transformers/documentables/SuppressTagDocumentableFilter.kt b/plugins/base/src/main/kotlin/transformers/documentables/SuppressTagDocumentableFilter.kt index a297908d..2d65e98b 100644 --- a/plugins/base/src/main/kotlin/transformers/documentables/SuppressTagDocumentableFilter.kt +++ b/plugins/base/src/main/kotlin/transformers/documentables/SuppressTagDocumentableFilter.kt @@ -2,11 +2,11 @@ package org.jetbrains.dokka.base.transformers.documentables import org.jetbrains.dokka.model.Documentable import org.jetbrains.dokka.model.dfs -import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.model.doc.Suppress +import org.jetbrains.dokka.plugability.DokkaContext class SuppressTagDocumentableFilter(val dokkaContext: DokkaContext) : SuppressedByConditionDocumentableFilterTransformer(dokkaContext) { override fun shouldBeSuppressed(d: Documentable): Boolean = d.documentation.any { (_, docs) -> docs.dfs { it is Suppress } != null } -} \ No newline at end of file +} diff --git a/plugins/base/src/main/kotlin/transformers/documentables/utils/FullClassHierarchyBuilder.kt b/plugins/base/src/main/kotlin/transformers/documentables/utils/FullClassHierarchyBuilder.kt deleted file mode 100644 index d657fa32..00000000 --- a/plugins/base/src/main/kotlin/transformers/documentables/utils/FullClassHierarchyBuilder.kt +++ /dev/null @@ -1,84 +0,0 @@ -package org.jetbrains.dokka.base.transformers.documentables.utils - -import com.intellij.psi.PsiClass -import kotlinx.coroutines.* -import org.jetbrains.dokka.analysis.DescriptorDocumentableSource -import org.jetbrains.dokka.analysis.PsiDocumentableSource -import org.jetbrains.dokka.analysis.from -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.* -import org.jetbrains.dokka.utilities.parallelForEach -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.types.KotlinType -import org.jetbrains.kotlin.types.typeUtil.immediateSupertypes -import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny -import java.util.concurrent.ConcurrentHashMap - -typealias Supertypes = List -typealias ClassHierarchy = SourceSetDependent> - -class FullClassHierarchyBuilder { - suspend operator fun invoke(original: DModule): ClassHierarchy = coroutineScope { - val map = original.sourceSets.associateWith { ConcurrentHashMap>() } - original.packages.parallelForEach { visitDocumentable(it, map) } - map - } - - private suspend fun collectSupertypesFromKotlinType( - driWithKType: Pair, - supersMap: MutableMap - ): Unit = coroutineScope { - val (dri, kotlinType) = driWithKType - val supertypes = kotlinType.immediateSupertypes().filterNot { it.isAnyOrNullableAny() } - val supertypesDriWithKType = supertypes.mapNotNull { supertype -> - supertype.constructor.declarationDescriptor?.let { - DRI.from(it) to supertype - } - } - - if (supersMap[dri] == null) { - // another thread can rewrite the same value, but it isn't a problem - supersMap[dri] = supertypesDriWithKType.map { it.first } - supertypesDriWithKType.parallelForEach { collectSupertypesFromKotlinType(it, supersMap) } - } - } - - private suspend fun collectSupertypesFromPsiClass( - driWithPsiClass: Pair, - supersMap: MutableMap - ): Unit = coroutineScope { - val (dri, psiClass) = driWithPsiClass - val supertypes = psiClass.superTypes.mapNotNull { it.resolve() } - .filterNot { it.qualifiedName == "java.lang.Object" } - val supertypesDriWithPsiClass = supertypes.map { DRI.from(it) to it } - - if (supersMap[dri] == null) { - // another thread can rewrite the same value, but it isn't a problem - supersMap[dri] = supertypesDriWithPsiClass.map { it.first } - supertypesDriWithPsiClass.parallelForEach { collectSupertypesFromPsiClass(it, supersMap) } - } - } - - private suspend fun visitDocumentable( - documentable: Documentable, - hierarchy: SourceSetDependent>> - ): Unit = coroutineScope { - if (documentable is WithScope) { - documentable.classlikes.parallelForEach { visitDocumentable(it, hierarchy) } - } - if (documentable is DClasslike) { - // to build a full class graph, using supertypes from Documentable - // is not enough since it keeps only one level of hierarchy - documentable.sources.forEach { (sourceSet, source) -> - if (source is DescriptorDocumentableSource) { - val descriptor = source.descriptor as ClassDescriptor - val type = descriptor.defaultType - hierarchy[sourceSet]?.let { collectSupertypesFromKotlinType(documentable.dri to type, it) } - } else if (source is PsiDocumentableSource) { - val psi = source.psi as PsiClass - hierarchy[sourceSet]?.let { collectSupertypesFromPsiClass(documentable.dri to psi, it) } - } - } - } - } -} \ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/pages/annotations/SinceKotlinTransformer.kt b/plugins/base/src/main/kotlin/transformers/pages/annotations/SinceKotlinTransformer.kt index 75f43324..23b3f625 100644 --- a/plugins/base/src/main/kotlin/transformers/pages/annotations/SinceKotlinTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/pages/annotations/SinceKotlinTransformer.kt @@ -1,9 +1,9 @@ package org.jetbrains.dokka.base.transformers.pages.annotations -import com.intellij.util.containers.ComparatorUtil.max -import org.intellij.markdown.MarkdownElementTypes + import org.jetbrains.dokka.DokkaConfiguration import org.jetbrains.dokka.Platform +import org.jetbrains.dokka.analysis.markdown.jb.MARKDOWN_ELEMENT_FILE_NAME import org.jetbrains.dokka.base.signatures.KotlinSignatureUtils.annotations import org.jetbrains.dokka.model.* import org.jetbrains.dokka.model.doc.CustomDocTag @@ -13,7 +13,6 @@ import org.jetbrains.dokka.model.doc.Text import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.documentation.DocumentableTransformer import org.jetbrains.dokka.utilities.associateWithNotNull -import org.jetbrains.kotlin.utils.addToStdlib.safeAs class SinceKotlinVersion constructor(str: String) : Comparable { private val parts: List = str.split(".").map { it.toInt() } @@ -124,7 +123,7 @@ class SinceKotlinTransformer(val context: DokkaContext) : DocumentableTransforme val annotatedVersion = annotations()[sourceSet] ?.findSinceKotlinAnnotation() - ?.params?.get("version").safeAs()?.value + ?.params?.let { it["version"] as? StringValue }?.value ?.let { SinceKotlinVersion(it) } val minSinceKotlin = minSinceKotlinVersionOfPlatform[sourceSet.analysisPlatform] @@ -139,7 +138,7 @@ class SinceKotlinTransformer(val context: DokkaContext) : DocumentableTransforme val version = getVersion(sourceSet) val parentVersion = parent?.get(sourceSet) if (parentVersion != null) - max(version, parentVersion) + maxOf(version, parentVersion) else version } @@ -157,7 +156,7 @@ class SinceKotlinTransformer(val context: DokkaContext) : DocumentableTransforme version.toString() ) ), - name = MarkdownElementTypes.MARKDOWN_FILE.name + name = MARKDOWN_ELEMENT_FILE_NAME ), "Since Kotlin" ) diff --git a/plugins/base/src/main/kotlin/transformers/pages/comments/CommentsToContentConverter.kt b/plugins/base/src/main/kotlin/transformers/pages/comments/CommentsToContentConverter.kt index fa9ce37e..58e22103 100644 --- a/plugins/base/src/main/kotlin/transformers/pages/comments/CommentsToContentConverter.kt +++ b/plugins/base/src/main/kotlin/transformers/pages/comments/CommentsToContentConverter.kt @@ -3,7 +3,9 @@ package org.jetbrains.dokka.base.transformers.pages.comments import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet import org.jetbrains.dokka.model.doc.DocTag import org.jetbrains.dokka.model.properties.PropertyContainer -import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.pages.ContentNode +import org.jetbrains.dokka.pages.DCI +import org.jetbrains.dokka.pages.Style interface CommentsToContentConverter { fun buildContent( diff --git a/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt b/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt index 2193283c..083a82cc 100644 --- a/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt +++ b/plugins/base/src/main/kotlin/transformers/pages/comments/DocTagToContentConverter.kt @@ -1,13 +1,14 @@ package org.jetbrains.dokka.base.transformers.pages.comments -import org.intellij.markdown.MarkdownElementTypes + import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet +import org.jetbrains.dokka.analysis.markdown.jb.MARKDOWN_ELEMENT_FILE_NAME import org.jetbrains.dokka.model.doc.* import org.jetbrains.dokka.model.properties.PropertyContainer import org.jetbrains.dokka.model.properties.plus import org.jetbrains.dokka.model.toDisplaySourceSets import org.jetbrains.dokka.pages.* -import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull +import org.jetbrains.dokka.utilities.firstIsInstanceOrNull open class DocTagToContentConverter : CommentsToContentConverter { override fun buildContent( @@ -261,5 +262,5 @@ open class DocTagToContentConverter : CommentsToContentConverter { } } - private fun CustomDocTag.isNonemptyFile() = name == MarkdownElementTypes.MARKDOWN_FILE.name && children.size > 1 + private fun CustomDocTag.isNonemptyFile() = name == MARKDOWN_ELEMENT_FILE_NAME && children.size > 1 } diff --git a/plugins/base/src/main/kotlin/transformers/pages/merger/SourceSetMergingPageTransformer.kt b/plugins/base/src/main/kotlin/transformers/pages/merger/SourceSetMergingPageTransformer.kt index 6cb7f603..f9da616c 100644 --- a/plugins/base/src/main/kotlin/transformers/pages/merger/SourceSetMergingPageTransformer.kt +++ b/plugins/base/src/main/kotlin/transformers/pages/merger/SourceSetMergingPageTransformer.kt @@ -3,7 +3,9 @@ package org.jetbrains.dokka.base.transformers.pages.merger import org.jetbrains.dokka.Platform import org.jetbrains.dokka.model.DisplaySourceSet import org.jetbrains.dokka.model.toDisplaySourceSets -import org.jetbrains.dokka.pages.* +import org.jetbrains.dokka.pages.ContentComposite +import org.jetbrains.dokka.pages.ContentNode +import org.jetbrains.dokka.pages.RootPageNode import org.jetbrains.dokka.plugability.DokkaContext import org.jetbrains.dokka.transformers.pages.PageTransformer diff --git a/plugins/base/src/main/kotlin/transformers/pages/samples/DefaultSamplesTransformer.kt b/plugins/base/src/main/kotlin/transformers/pages/samples/DefaultSamplesTransformer.kt deleted file mode 100644 index 49ddd0a5..00000000 --- a/plugins/base/src/main/kotlin/transformers/pages/samples/DefaultSamplesTransformer.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.jetbrains.dokka.base.transformers.pages.samples - -import com.intellij.psi.PsiElement -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.kotlin.psi.KtBlockExpression -import org.jetbrains.kotlin.psi.KtDeclarationWithBody -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.utils.addToStdlib.safeAs - -class DefaultSamplesTransformer(context: DokkaContext) : SamplesTransformer(context) { - - override fun processBody(psiElement: PsiElement): String { - val text = processSampleBody(psiElement).trim { it == '\n' || it == '\r' }.trimEnd() - val lines = text.split("\n") - val indent = lines.filter(String::isNotBlank).map { it.takeWhile(Char::isWhitespace).count() }.minOrNull() ?: 0 - return lines.joinToString("\n") { it.drop(indent) } - } - - private fun processSampleBody(psiElement: PsiElement): String = when (psiElement) { - is KtDeclarationWithBody -> { - when (val bodyExpression = psiElement.bodyExpression) { - is KtBlockExpression -> bodyExpression.text.removeSurrounding("{", "}") - else -> bodyExpression!!.text - } - } - else -> psiElement.text - } - - override fun processImports(psiElement: PsiElement): String { - val psiFile = psiElement.containingFile - return when(val text = psiFile.safeAs()?.importList?.text) { - is String -> text - else -> "" - } - } -} \ No newline at end of file diff --git a/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt b/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt deleted file mode 100644 index e72700e0..00000000 --- a/plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt +++ /dev/null @@ -1,148 +0,0 @@ -package org.jetbrains.dokka.base.transformers.pages.samples - -import com.intellij.psi.PsiElement -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.runBlocking -import org.jetbrains.dokka.DokkaConfiguration.DokkaSourceSet -import org.jetbrains.dokka.analysis.* -import org.jetbrains.dokka.base.DokkaBase -import org.jetbrains.dokka.base.renderers.sourceSets -import org.jetbrains.dokka.links.DRI -import org.jetbrains.dokka.model.DisplaySourceSet -import org.jetbrains.dokka.model.doc.Sample -import org.jetbrains.dokka.model.properties.PropertyContainer -import org.jetbrains.dokka.pages.* -import org.jetbrains.dokka.plugability.DokkaContext -import org.jetbrains.dokka.plugability.plugin -import org.jetbrains.dokka.plugability.querySingle -import org.jetbrains.dokka.transformers.pages.PageTransformer -import org.jetbrains.kotlin.idea.kdoc.resolveKDocLink -import org.jetbrains.kotlin.name.FqName -import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils - -internal const val KOTLIN_PLAYGROUND_SCRIPT = "" -abstract class SamplesTransformer(val context: DokkaContext) : PageTransformer { - - abstract fun processBody(psiElement: PsiElement): String - abstract fun processImports(psiElement: PsiElement): String - - final override fun invoke(input: RootPageNode): RootPageNode = - /** - * Run from the thread of [Dispatchers.Default]. It can help to avoid a memory leaks in `ThreadLocal`s (that keep `URLCLassLoader`) - * since we shut down Dispatchers. Default at the end of each task (see [org.jetbrains.dokka.DokkaConfiguration.finalizeCoroutines]). - * Currently, all `ThreadLocal`s are in a compiler/IDE codebase. - */ - runBlocking(Dispatchers.Default) { - val analysis = SamplesKotlinAnalysis( - sourceSets = context.configuration.sourceSets, - logger = context.logger, - projectKotlinAnalysis = context.plugin().querySingle { kotlinAnalysis } - ) - analysis.use { - input.transformContentPagesTree { page -> - val samples = (page as? WithDocumentables)?.documentables?.flatMap { - it.documentation.entries.flatMap { entry -> - entry.value.children.filterIsInstance().map { entry.key to it } - } - } - - samples?.fold(page as ContentPage) { acc, (sampleSourceSet, sample) -> - acc.modified( - content = acc.content.addSample(page, sampleSourceSet, sample.name, it), - embeddedResources = acc.embeddedResources + KOTLIN_PLAYGROUND_SCRIPT - ) - } ?: page - } - } - } - - private fun ContentNode.addSample( - contentPage: ContentPage, - sourceSet: DokkaSourceSet, - fqName: String, - analysis: KotlinAnalysis - ): ContentNode { - val facade = analysis[sourceSet].facade - val psiElement = fqNameToPsiElement(facade, fqName) - ?: return this.also { context.logger.warn("Cannot find PsiElement corresponding to $fqName") } - val imports = - processImports(psiElement) - val body = processBody(psiElement) - val node = contentCode(contentPage.sourceSets(), contentPage.dri, createSampleBody(imports, body), "kotlin") - - return dfs(fqName, node) - } - - protected open fun createSampleBody(imports: String, body: String) = - """ |$imports - |fun main() { - | //sampleStart - | $body - | //sampleEnd - |}""".trimMargin() - - private fun ContentNode.dfs(fqName: String, node: ContentCodeBlock): ContentNode { - return when (this) { - is ContentHeader -> copy(children.map { it.dfs(fqName, node) }) - is ContentDivergentGroup -> @Suppress("UNCHECKED_CAST") copy(children.map { - it.dfs(fqName, node) - } as List) - is ContentDivergentInstance -> copy( - before.let { it?.dfs(fqName, node) }, - divergent.dfs(fqName, node), - after.let { it?.dfs(fqName, node) }) - is ContentCodeBlock -> copy(children.map { it.dfs(fqName, node) }) - is ContentCodeInline -> copy(children.map { it.dfs(fqName, node) }) - is ContentDRILink -> copy(children.map { it.dfs(fqName, node) }) - is ContentResolvedLink -> copy(children.map { it.dfs(fqName, node) }) - is ContentEmbeddedResource -> copy(children.map { it.dfs(fqName, node) }) - is ContentTable -> copy(children = children.map { it.dfs(fqName, node) as ContentGroup }) - is ContentList -> copy(children.map { it.dfs(fqName, node) }) - is ContentGroup -> copy(children.map { it.dfs(fqName, node) }) - is PlatformHintedContent -> copy(inner.dfs(fqName, node)) - is ContentText -> if (text == fqName) node else this - is ContentBreakLine -> this - else -> this.also { context.logger.error("Could not recognize $this ContentNode in SamplesTransformer") } - } - } - - private fun fqNameToPsiElement(resolutionFacade: DokkaResolutionFacade, functionName: String): PsiElement? { - val packageName = functionName.takeWhile { it != '.' } - val descriptor = resolutionFacade.resolveSession.getPackageFragment(FqName(packageName)) - ?: return null.also { context.logger.warn("Cannot find descriptor for package $packageName") } - val symbol = resolveKDocLink( - BindingContext.EMPTY, - resolutionFacade, - descriptor, - null, - functionName.split(".") - ).firstOrNull() ?: return null.also { context.logger.warn("Unresolved function $functionName in @sample") } - return DescriptorToSourceUtils.descriptorToDeclaration(symbol) - } - - private fun contentCode( - sourceSets: Set, - dri: Set, - content: String, - language: String, - styles: Set