Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Stabilize Sample analysis API #3195

Merged
merged 12 commits into from
Nov 21, 2023
25 changes: 14 additions & 11 deletions dokka-subprojects/analysis-kotlin-api/api/analysis-kotlin-api.api
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
public final class org/jetbrains/dokka/analysis/kotlin/KotlinAnalysisPlugin : org/jetbrains/dokka/plugability/DokkaPlugin {
public fun <init> ()V
public final fun getSampleAnalysisEnvironmentCreator ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
}

public final class org/jetbrains/dokka/analysis/kotlin/internal/DocumentableLanguage : java/lang/Enum {
Expand Down Expand Up @@ -51,7 +52,6 @@ public final class org/jetbrains/dokka/analysis/kotlin/internal/InternalKotlinAn
public final fun getInheritanceBuilder ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
public final fun getKotlinToJavaService ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
public final fun getModuleAndPackageDocumentationReader ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
public final fun getSampleProviderFactory ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
public final fun getSyntheticDocumentableDetector ()Lorg/jetbrains/dokka/plugability/ExtensionPoint;
}

Expand All @@ -65,21 +65,24 @@ public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/Mod
public abstract fun read (Lorg/jetbrains/dokka/model/DPackage;)Ljava/util/Map;
}

public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/SampleProvider : java/lang/AutoCloseable {
public abstract fun getSample (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Ljava/lang/String;)Lorg/jetbrains/dokka/analysis/kotlin/internal/SampleProvider$SampleSnippet;
public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/SyntheticDocumentableDetector {
public abstract fun isSynthetic (Lorg/jetbrains/dokka/model/Documentable;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Z
}

public final class org/jetbrains/dokka/analysis/kotlin/internal/SampleProvider$SampleSnippet {
public fun <init> (Ljava/lang/String;Ljava/lang/String;)V
public final fun getBody ()Ljava/lang/String;
public final fun getImports ()Ljava/lang/String;
public abstract interface class org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironment {
public abstract fun resolveSample (Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;Ljava/lang/String;)Lorg/jetbrains/dokka/analysis/kotlin/sample/SampleSnippet;
}

public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/SampleProviderFactory {
public abstract fun build ()Lorg/jetbrains/dokka/analysis/kotlin/internal/SampleProvider;
public abstract interface class org/jetbrains/dokka/analysis/kotlin/sample/SampleAnalysisEnvironmentCreator {
public abstract fun use (Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
}

public abstract interface class org/jetbrains/dokka/analysis/kotlin/internal/SyntheticDocumentableDetector {
public abstract fun isSynthetic (Lorg/jetbrains/dokka/model/Documentable;Lorg/jetbrains/dokka/DokkaConfiguration$DokkaSourceSet;)Z
public final class org/jetbrains/dokka/analysis/kotlin/sample/SampleSnippet {
public fun <init> (Ljava/util/List;Ljava/lang/String;)V
public fun equals (Ljava/lang/Object;)Z
public final fun getBody ()Ljava/lang/String;
public final fun getImports ()Ljava/util/List;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}

Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@

package org.jetbrains.dokka.analysis.kotlin

import org.jetbrains.dokka.analysis.kotlin.sample.SampleAnalysisEnvironmentCreator
import org.jetbrains.dokka.analysis.kotlin.sample.SampleAnalysisEnvironment
import org.jetbrains.dokka.plugability.DokkaPlugin
import org.jetbrains.dokka.plugability.DokkaPluginApiPreview
import org.jetbrains.dokka.plugability.ExtensionPoint
import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement

public class KotlinAnalysisPlugin : DokkaPlugin() {

/*
* This is where stable public API will go.
/**
* An extension for analyzing Kotlin sample functions used in the `@sample` KDoc tag.
*
* No stable public API for now.
* @see SampleAnalysisEnvironment for more details
*/
public val sampleAnalysisEnvironmentCreator: ExtensionPoint<SampleAnalysisEnvironmentCreator> by extensionPoint()

@OptIn(DokkaPluginApiPreview::class)
override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ public class InternalKotlinAnalysisPlugin : DokkaPlugin() {

public val documentableSourceLanguageParser: ExtensionPoint<DocumentableSourceLanguageParser> by extensionPoint()

public val sampleProviderFactory: ExtensionPoint<SampleProviderFactory> by extensionPoint()

@OptIn(DokkaPluginApiPreview::class)
override fun pluginApiPreviewAcknowledgement(): PluginApiPreviewAcknowledgement = PluginApiPreviewAcknowledgement
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package org.jetbrains.dokka.analysis.kotlin.sample

import org.jetbrains.dokka.DokkaConfiguration

/**
* Fully-configured and ready-to-use sample analysis environment.
*
* It's best to limit the scope of use and lifetime of this environment as it takes up
* additional resources which could be freed once the samples have been analyzed.
* Therefore, it's best to use it through the [SampleAnalysisEnvironmentCreator.use] lambda.
*
* For example, if you need to process all samples in an arbitrary project, it's best to do it
* in one iteration and at the same time, so that the environment is created once and lives for
* as little is possible, as opposed to creating it again and again for every individual sample.
*/
public interface SampleAnalysisEnvironment {

/**
* Resolves a Kotlin sample function by its fully qualified name, and returns its import statements and body.
*
* @param sourceSet must be either the source set in which this sample function resides, or the source set
* for which [DokkaConfiguration#samples] or [DokkaConfiguration#sourceRoots]
* have been configured with the sample's sources.
* @param fullyQualifiedLink fully qualified path to the sample function, including all middle packages
* and the name of the function. Only links to Kotlin functions are valid,
* which can reside within a class. The package must be the same as the package
* declared in the sample file. The function must be resolvable by Dokka,
* meaning it must reside either in the main sources of the project or its
* sources must be included in [DokkaConfiguration#samples] or
* [DokkaConfiguration#sourceRoots]. Example: `com.example.pckg.topLevelKotlinFunction`
*
* @return a sample code snippet which includes import statements and the function body,
* or null if the link could not be resolved (examine the logs to find out the reason).
*/
public fun resolveSample(
sourceSet: DokkaConfiguration.DokkaSourceSet,
fullyQualifiedLink: String
): SampleSnippet?
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package org.jetbrains.dokka.analysis.kotlin.sample

import org.jetbrains.dokka.analysis.kotlin.KotlinAnalysisPlugin

/**
* Entry point to analyzing Kotlin samples.
*
* Can be acquired via [KotlinAnalysisPlugin.sampleAnalysisEnvironmentCreator].
*/
public interface SampleAnalysisEnvironmentCreator {

/**
* Creates and configures the sample analysis environment for a limited-time use.
*
* Configuring sample analysis environment is a rather expensive operation that takes up additional
* resources since Dokka needs to configure and analyze source roots additional to the main ones.
* It's best to limit the scope of use and the lifetime of the created environment
* so that the resources could be freed as soon as possible.
*
* No specific cleanup is required by the caller - everything is taken care of automatically
* as soon as you exit the [block] block.
*
* Usage example:
* ```kotlin
* // create a short-lived environment and resolve all the needed samples
* val sample = sampleAnalysisEnvironmentCreator.use {
* resolveSample(sampleSourceSet, "org.jetbrains.dokka.sample.functionName")
* }
* // process the samples
* // ...
* ```
*/
public fun <T> use(block: SampleAnalysisEnvironment.() -> T): T
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package org.jetbrains.dokka.analysis.kotlin.sample

/**
* Represents a sample code snippet of a Kotlin function. The snippet includes both file
* import directives (all, even unused) and the sample function body.
*
* @property imports list of import statement values, without the `import` prefix.
* Contains no blank lines. Example of a single value: `com.example.pckg.MyClass.function`.
* @property body body of the sample function, without the function name or curly braces, only the inner body.
* Common minimal indent of all lines is trimmed. Leading and trailing line breaks are removed.
* Trailing whitespaces are removed. Example: given the sample function `fun foo() { println("foo") }`,
* the sample body will be `println("foo")`.
*
* @see SampleAnalysisEnvironment for how to acquire it
*/
public class SampleSnippet(
public val imports: List<String>,
public val body: String
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as SampleSnippet

if (imports != other.imports) return false
if (body != other.body) return false

return true
}

override fun hashCode(): Int {
var result = imports.hashCode()
result = 31 * result + body.hashCode()
return result
}

override fun toString(): String {
return "SampleSnippet(imports=$imports, body='$body')"
}
}
Loading