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

Add example to demonstrate how to configure a custom Dokka plugin #3871

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions examples/gradle-v2/custom-dokka-plugin-example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Custom Dokka Plugin example

This project demonstrates how to create and configure a custom Dokka plugin.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
plugins {
base
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import kotlinx.serialization.json.add
import kotlinx.serialization.json.buildJsonArray
import kotlinx.serialization.json.buildJsonObject
import org.jetbrains.dokka.gradle.engine.plugins.DokkaPluginParametersBaseSpec
import org.jetbrains.dokka.gradle.internal.DokkaInternalApi

plugins {
kotlin("jvm") version "2.0.21"
id("org.jetbrains.dokka") version "2.0.20-SNAPSHOT"
}

dependencies {
dokkaPlugin(project(":dokka-plugin-hide-internal-api"))
}

dokka {
moduleName.set("Demo Library")

pluginsConfiguration {
registerBinding(HideInternalApiParameters::class, HideInternalApiParameters::class)
register<HideInternalApiParameters>("HideInternalApiPlugin") {
annotatedWith.add("demo.HideFromDokka")
}
}
}

/**
* Define custom parameters for the HideInternalApi Dokka Plugin.
*
* Using a custom class for defining parameters means Gradle can accurately check for task up-to-date checks.
*
* If you find you need to re-use the plugin parameters configuration class in multiple buildscripts,
* move the class into a shared location, like `buildSrc` (or another included-build for build conventions).
* See [Sharing Build Logic between Subprojects](https://docs.gradle.org/8.10/userguide/sharing_build_logic_between_subprojects.html).
*/
@OptIn(DokkaInternalApi::class)
abstract class HideInternalApiParameters @Inject constructor(
name: String
) : DokkaPluginParametersBaseSpec(name, "demo.dokka.plugin.HideInternalApiPlugin") {

@get:Input
@get:Optional
abstract val annotatedWith: ListProperty<String>

override fun jsonEncode(): String {
// Convert annotatedWith to a JSON list.
val annotatedWithJson = buildJsonArray {
annotatedWith.orNull.orEmpty().forEach {
add(it)
}
}

return buildJsonObject {
put("annotatedWith", annotatedWithJson)
}.toString()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package demo

/**
* This class supports greeting people by name.
*
* @property name The name of the person to be greeted.
*/
class Greeter(
val name: String
) {

/**
* Prints the greeting to the standard output.
*/
fun greet() {
println("Hello $name!")
}
}

/**
* The entry point for [Greeter].
*/
@EntryPoint
fun main(args: Array<String>) {
Greeter(args[0]).greet()
}

/**
* Marks the entry point of the program.
*
* The `HideInternalApi` Dokka Plugin is configured to exclude code
* with this annotation from the generated docs.
*/
annotation class EntryPoint
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
plugins {
`embedded-kotlin`
kotlin("plugin.serialization") version embeddedKotlinVersion
}


dependencies {
val dokkaVersion = "2.0.20-SNAPSHOT"
compileOnly("org.jetbrains.dokka:dokka-core:$dokkaVersion")
implementation("org.jetbrains.dokka:dokka-base:$dokkaVersion")

implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

package demo.dokka.plugin

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import org.jetbrains.dokka.DokkaConfiguration
import org.jetbrains.dokka.base.DokkaBase
import org.jetbrains.dokka.base.transformers.documentables.SuppressedByConditionDocumentableFilterTransformer
import org.jetbrains.dokka.model.Annotations
import org.jetbrains.dokka.model.Documentable
import org.jetbrains.dokka.model.properties.WithExtraProperties
import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.DokkaPlugin
import org.jetbrains.dokka.plugability.DokkaPluginApiPreview
import org.jetbrains.dokka.plugability.PluginApiPreviewAcknowledgement

@Suppress("unused")
class HideInternalApiPlugin : DokkaPlugin() {
val myFilterExtension by extending {
plugin<DokkaBase>().preMergeDocumentableTransformer providing ::HideInternalApiTransformer
}

@DokkaPluginApiPreview
override fun pluginApiPreviewAcknowledgement() = PluginApiPreviewAcknowledgement

companion object {
const val FQN = "demo.dokka.plugin.HideInternalApiPlugin"
}
}

/**
* Configuration for [HideInternalApiPlugin].
*/
@Serializable
data class HideInternalApiConfig(
val annotatedWith: List<String>
)

class HideInternalApiTransformer(context: DokkaContext) : SuppressedByConditionDocumentableFilterTransformer(context) {

/**
* Decode [HideInternalApiPlugin] from the [DokkaContext].
*/
private val configuration: HideInternalApiPlugin by lazy {
val pluginConfig = context.configuration.pluginsConfiguration
.firstOrNull { it.fqPluginName == HideInternalApiPlugin.FQN }

if (pluginConfig != null) {
require(pluginConfig.serializationFormat == DokkaConfiguration.SerializationFormat.JSON) {
"HideInternalApiPlugin configuration must be encoded as JSON"
}

Json.decodeFromString(HideInternalApiConfig.serializer(), pluginConfig.values)
} else {
HideInternalApiConfig(
annotatedWith = emptyList()
)
}
}

override fun shouldBeSuppressed(d: Documentable): Boolean {
val annotations: List<Annotations.Annotation> =
(d as? WithExtraProperties<*>)
?.extra
?.allOfType<Annotations>()
?.flatMap { it.directAnnotations.values.flatten() }
?: emptyList()

return annotations.any { isInternalAnnotation(it) }
}

private fun isInternalAnnotation(annotation: Annotations.Annotation): Boolean {
val annotationFqn = "${annotation.dri.packageName}.${annotation.dri.classNames}"
return configuration.annotatedWith.any { it == annotationFqn }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
demo.dokka.plugin.HideInternalApiPlugin
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
org.gradle.jvmargs=-Dfile.encoding=UTF-8
org.gradle.caching=true
org.gradle.configuration-cache=true
org.gradle.parallel=true

org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
org.jetbrains.dokka.experimental.gradle.pluginMode.noWarn=true
18 changes: 18 additions & 0 deletions examples/gradle-v2/custom-dokka-plugin-example/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
rootProject.name = "custom-dokka-plugin-example"

pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
}
}

@Suppress("UnstableApiUsage")
dependencyResolutionManagement {
repositories {
mavenCentral()
}
}

include(":dokka-plugin-hide-internal-api")
include(":demo-library")
Loading