aboutsummaryrefslogtreecommitdiff
path: root/plugins/base/src/main/kotlin/transformers/pages/samples
diff options
context:
space:
mode:
authorIgnat Beresnev <ignat.beresnev@jetbrains.com>2023-07-05 10:04:55 +0200
committerGitHub <noreply@github.com>2023-07-05 10:04:55 +0200
commit9559158bfeeb274e9ccf1b4563f1b23b42afc493 (patch)
tree3ece0887623cfe2b7148af23001867a1dd5e6597 /plugins/base/src/main/kotlin/transformers/pages/samples
parentcbd9733d3dd2f52992e98e7cebd072091a572529 (diff)
downloaddokka-9559158bfeeb274e9ccf1b4563f1b23b42afc493.tar.gz
dokka-9559158bfeeb274e9ccf1b4563f1b23b42afc493.tar.bz2
dokka-9559158bfeeb274e9ccf1b4563f1b23b42afc493.zip
Decompose Kotlin/Java analysis (#3034)
* Extract analysis into separate modules
Diffstat (limited to 'plugins/base/src/main/kotlin/transformers/pages/samples')
-rw-r--r--plugins/base/src/main/kotlin/transformers/pages/samples/DefaultSamplesTransformer.kt36
-rw-r--r--plugins/base/src/main/kotlin/transformers/pages/samples/SamplesTransformer.kt148
2 files changed, 0 insertions, 184 deletions
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<KtFile>()?.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 = "<script src=\"https://unpkg.com/kotlin-playground@1\"></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<DokkaBase>().querySingle { kotlinAnalysis }
- )
- analysis.use {
- input.transformContentPagesTree { page ->
- val samples = (page as? WithDocumentables)?.documentables?.flatMap {
- it.documentation.entries.flatMap { entry ->
- entry.value.children.filterIsInstance<Sample>().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<ContentDivergentInstance>)
- 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<DisplaySourceSet>,
- dri: Set<DRI>,
- content: String,
- language: String,
- styles: Set<Style> = emptySet(),
- extra: PropertyContainer<ContentNode> = PropertyContainer.empty()
- ) =
- ContentCodeBlock(
- children = listOf(
- ContentText(
- text = content,
- dci = DCI(dri, ContentKind.Sample),
- sourceSets = sourceSets,
- style = emptySet(),
- extra = PropertyContainer.empty()
- )
- ),
- language = language,
- dci = DCI(dri, ContentKind.Sample),
- sourceSets = sourceSets,
- style = styles + ContentStyle.RunnableSample + TextStyle.Monospace,
- extra = extra
- )
-}