Skip to content

Commit

Permalink
Avoid generating documentation for symbols annotated with @InternalRe…
Browse files Browse the repository at this point in the history
…venueCatAPI (#1958)
  • Loading branch information
JayShortway authored Dec 4, 2024
1 parent 3e74d49 commit d8b3f23
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 0 deletions.
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ plugins {
alias libs.plugins.android.application apply false
alias libs.plugins.android.library apply false
alias libs.plugins.kotlin.android apply false
alias libs.plugins.kotlin.jvm apply false
alias libs.plugins.dokka
alias libs.plugins.kover apply false
alias libs.plugins.detekt
Expand Down
12 changes: 12 additions & 0 deletions dokka-hide-internal/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
plugins {
alias(libs.plugins.kotlin.jvm)
}

dependencies {
compileOnly(libs.dokka.core)
implementation(libs.dokka.base)

testImplementation(libs.kotlin.test)
testImplementation(libs.dokka.testApi)
testImplementation(libs.dokka.baseTestUtils)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.revenuecat.dokka.plugin.hideinternal

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

class HideInternalRevenueCatAPIPlugin : DokkaPlugin() {

val filterExtension by extending {
plugin<DokkaBase>().preMergeDocumentableTransformer providing ::HideInternalRevenueCatAPITransformer
}

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

class HideInternalRevenueCatAPITransformer(
context: DokkaContext,
) : SuppressedByConditionDocumentableFilterTransformer(context) {

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 =
annotation.dri.packageName == "com.revenuecat.purchases" && annotation.dri.classNames == "InternalRevenueCatAPI"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
com.revenuecat.dokka.plugin.hideinternal.HideInternalRevenueCatAPIPlugin
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package com.revenuecat.dokka.plugin.hideinternal

import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
import org.jetbrains.dokka.model.DClass
import org.jetbrains.dokka.model.DObject
import kotlin.test.Test
import kotlin.test.assertEquals

class HideInternalRevenueCatAPIPluginTest: BaseAbstractTest() {

@Test
fun `Should hide annotated functions`() {
val configuration = dokkaConfiguration {
sourceSets {
sourceSet {
sourceRoots = listOf("src/main/kotlin/basic/Test.kt")
}
}
}
val hideInternalPlugin = HideInternalRevenueCatAPIPlugin()

testInline(
"""
|/src/main/kotlin/basic/Test.kt
|package com.revenuecat.purchases
|
|annotation class InternalRevenueCatAPI
|
|fun shouldBeVisible() {}
|
|@InternalRevenueCatAPI
|fun shouldBeExcludedFromDocumentation() {}
""".trimMargin(),
configuration = configuration,
pluginOverrides = listOf(hideInternalPlugin)
) {
preMergeDocumentablesTransformationStage = { modules ->
val testModule = modules.single { it.name == "root" }
val testPackage = testModule.packages.single { it.name == "com.revenuecat.purchases" }

val packageFunctions = testPackage.functions
assertEquals(expected = 1, actual = packageFunctions.size)
assertEquals(expected = "shouldBeVisible", actual = packageFunctions[0].name)
}
}
}

@Test
fun `Should hide annotated classes`() {
val configuration = dokkaConfiguration {
sourceSets {
sourceSet {
sourceRoots = listOf("src/main/kotlin/basic/Test.kt")
}
}
}
val hideInternalPlugin = HideInternalRevenueCatAPIPlugin()

testInline(
"""
|/src/main/kotlin/basic/Test.kt
|package com.revenuecat.purchases
|
|annotation class InternalRevenueCatAPI
|
|class ShouldBeVisible
|
|@InternalRevenueCatAPI
|class ShouldBeExcludedFromDocumentation
""".trimMargin(),
configuration = configuration,
pluginOverrides = listOf(hideInternalPlugin)
) {
preMergeDocumentablesTransformationStage = { modules ->
val testModule = modules.single { it.name == "root" }
val testPackage = testModule.packages.single { it.name == "com.revenuecat.purchases" }

val packageClasses = testPackage.classlikes.filterIsInstance<DClass>()
assertEquals(expected = 1, actual = packageClasses.size)
assertEquals(expected = "ShouldBeVisible", actual = packageClasses[0].name)
}
}
}

@Test
fun `Should hide annotated objects`() {
val configuration = dokkaConfiguration {
sourceSets {
sourceSet {
sourceRoots = listOf("src/main/kotlin/basic/Test.kt")
}
}
}
val hideInternalPlugin = HideInternalRevenueCatAPIPlugin()

testInline(
"""
|/src/main/kotlin/basic/Test.kt
|package com.revenuecat.purchases
|
|annotation class InternalRevenueCatAPI
|
|object ShouldBeVisible
|
|@InternalRevenueCatAPI
|object ShouldBeExcludedFromDocumentation
""".trimMargin(),
configuration = configuration,
pluginOverrides = listOf(hideInternalPlugin)
) {
preMergeDocumentablesTransformationStage = { modules ->
val testModule = modules.single { it.name == "root" }
val testPackage = testModule.packages.single { it.name == "com.revenuecat.purchases" }

val packageObjects = testPackage.classlikes.filterIsInstance<DObject>()
assertEquals(expected = 1, actual = packageObjects.size)
assertEquals(expected = "ShouldBeVisible", actual = packageObjects[0].name)
}
}
}

}
7 changes: 7 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
dokka = { id ="org.jetbrains.dokka", version.ref = "dokka"}
emerge = { id = "com.emergetools.android", version.ref = "emergeGradlePlugin" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlin-parcelize = { id = "org.jetbrains.kotlin.plugin.parcelize", version.ref = "kotlin" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover"}
Expand Down Expand Up @@ -122,6 +123,7 @@ tink = { module = "com.google.crypto.tink:tink-android", version.ref = "tink" }
coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "coroutines" }

kotlin-bom = "org.jetbrains.kotlin:kotlin-bom:1.8.0"
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
compose-bom = "androidx.compose:compose-bom:2024.08.00"
compose-ui = { module = "androidx.compose.ui:ui" }
compose-ui-util = { module = "androidx.compose.ui:ui-util" }
Expand All @@ -145,5 +147,10 @@ commonmark-strikethrough = { module = "org.commonmark:commonmark-ext-gfm-striket
navigation-compose = "androidx.navigation:navigation-compose:2.5.3"
activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" }

dokka-base = { module ="org.jetbrains.dokka:dokka-base", version.ref = "dokka" }
dokka-core = { module ="org.jetbrains.dokka:dokka-core", version.ref = "dokka" }
dokka-testApi = { module = "org.jetbrains.dokka:dokka-test-api", version.ref = "dokka"}
dokka-baseTestUtils = { module = "org.jetbrains.dokka:dokka-base-test-utils", version.ref = "dokka" }

[bundles]
test = ["androidx-test-core", "androidx-core-testing", "androidx-test-runner", "androidx-test-rules", "androidx-test-junit", "robolectric", "mockk", "assertJ"]
9 changes: 9 additions & 0 deletions purchases/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ dependencies {
compileOnly libs.amazon.appstore.sdk
compileOnly libs.coil.compose

dokkaPlugin(project(":dokka-hide-internal"))

testImplementation libs.bundles.test
testImplementation libs.billing
testImplementation libs.coroutines.test
Expand Down Expand Up @@ -147,6 +149,13 @@ tasks.dokkaHtmlPartial.configure {
includeNonPublic.set(false)
skipDeprecated.set(true)

// This package exclusively contains symbols annotated with @InternalRevenueCatAPI, for which no
// documentation is generated due to our dokka-hide-internal plugin. However, by default Dokka still
// generates an empty page for the package. This avoids that.
perPackageOption {
matchingRegex.set("com\\.revenuecat\\.purchases\\.paywalls\\.components.*")
suppress.set(true)
}
externalDocumentationLink {
url.set(uri("https://developer.android.com/reference/package-list").toURL())
}
Expand Down
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ include ':examples:paywall-tester'
include ':test-apps:testpurchasesandroidcompatibility'
include ':test-apps:testpurchasesuiandroidcompatibility'
include ':examples:web-purchase-redemption-sample'
include ':dokka-hide-internal'

0 comments on commit d8b3f23

Please sign in to comment.