Skip to content

Commit 286a1ba

Browse files
committed
@ContributesRenderer code generator
Add a new KSP code generator that generates the code for `@ContributesRenderer` using Metro. The implementation is almost equivalent to the kotlin-inject implementation, except for that it's using Metro APIs. The big difference is that kotlin-inject implements map-multibindings by returning a `Pair<Abc, Def>` whereas Metro uses a `@ClassKey` annotation similar to Dagger 2. Therefore, we had to introduce the `@RendererKey` annotation specifically for Metro. See #115
1 parent 1573020 commit 286a1ba

File tree

18 files changed

+1295
-8
lines changed

18 files changed

+1295
-8
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ jobs:
141141
gradle-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }}
142142

143143
- name: Test
144-
run: ./gradlew :kotlin-inject-extensions:contribute:impl-code-generators:test --stacktrace --show-version --continue -Pksp.useKSP2=${{ matrix.use-ksp2 }}
144+
run: ./gradlew :kotlin-inject-extensions:contribute:impl-code-generators:test :metro-extensions:contribute:impl-code-generators:test --stacktrace --show-version --continue -Pksp.useKSP2=${{ matrix.use-ksp2 }}
145145

146146
- name: Upload Test Results
147147
uses: actions/upload-artifact@v4

buildSrc/src/main/kotlin/software/amazon/app/platform/gradle/buildsrc/BasePlugin.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ public open class BasePlugin : Plugin<Project> {
6464
"${APP_PLATFORM_GROUP}:kotlin-inject-impl" to ":kotlin-inject:impl",
6565
"${APP_PLATFORM_GROUP}:ksp-common-public" to ":ksp-common:public",
6666
"${APP_PLATFORM_GROUP}:metro-public" to ":metro:public",
67+
"${APP_PLATFORM_GROUP}:metro-contribute-impl-code-generators" to
68+
":metro-extensions:contribute:impl-code-generators",
6769
"${APP_PLATFORM_GROUP}:presenter-public" to ":presenter:public",
6870
"${APP_PLATFORM_GROUP}:presenter-molecule-public" to ":presenter-molecule:public",
6971
"${APP_PLATFORM_GROUP}:presenter-molecule-impl" to ":presenter-molecule:impl",

buildSrc/src/main/kotlin/software/amazon/app/platform/gradle/buildsrc/SdkPlugin.kt

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,18 @@ internal object SdkPlugin {
2424
// :presenter:testing -> ${group}:presenter-testing:${version}
2525
val parent = requireNotNull(parent)
2626
val artifactId =
27-
if (parent.name == "contribute" && parent.parent?.name == "kotlin-inject-extensions") {
28-
// Change the artifact ID, because "contribute" alone is a weird name.
29-
artifactId(libraryName = "kotlin-inject-contribute")
30-
} else {
31-
artifactId()
27+
when {
28+
parent.name == "contribute" && parent.parent?.name == "kotlin-inject-extensions" -> {
29+
// Change the artifact ID, because "contribute" alone is a weird name.
30+
artifactId(libraryName = "kotlin-inject-contribute")
31+
}
32+
parent.name == "contribute" && parent.parent?.name == "metro-extensions" -> {
33+
// Change the artifact ID, because "contribute" alone is a weird name.
34+
artifactId(libraryName = "metro-contribute")
35+
}
36+
else -> {
37+
artifactId()
38+
}
3239
}
3340
mavenPublish.coordinates(artifactId = artifactId)
3441
mavenPublish.pom { pom ->

kotlin-inject-extensions/contribute/impl-code-generators/src/test/kotlin/software/amazon/app/platform/inject/processor/ContributesRendererProcessorTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ class ContributesRendererProcessorTest {
237237
}
238238

239239
@Test
240-
fun `the model type can be interred from the class hierarchy`() {
240+
fun `the model type can be inferred from the class hierarchy`() {
241241
compile(
242242
"""
243243
package software.amazon.test
@@ -261,7 +261,7 @@ class ContributesRendererProcessorTest {
261261
}
262262

263263
@Test
264-
fun `the model type can be interred from the class hierarchy with multiple levels`() {
264+
fun `the model type can be inferred from the class hierarchy with multiple levels`() {
265265
compile(
266266
"""
267267
package software.amazon.test
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
plugins {
2+
id 'software.amazon.app.platform.lib.jvm'
3+
id 'com.google.devtools.ksp'
4+
}
5+
6+
appPlatformBuildSrc {
7+
enablePublishing true
8+
}
9+
10+
test {
11+
useJUnitPlatform()
12+
13+
// Since Kotlin 2.0 we need more memory to run our tests.
14+
maxHeapSize = "2g"
15+
}
16+
17+
dependencies {
18+
implementation libs.ksp.api
19+
20+
implementation libs.kotlin.poet
21+
implementation libs.kotlin.poet.ksp
22+
23+
implementation libs.auto.service.annotations
24+
ksp libs.auto.service.ksp
25+
26+
// Gives us access to annotations.
27+
implementation project(':di-common:public')
28+
implementation project(':ksp-common:public')
29+
implementation project(':metro:public')
30+
implementation project(':scope:public')
31+
implementation libs.metro.runtime
32+
33+
testImplementation project(':ksp-common:testing')
34+
testImplementation project(':metro:public')
35+
testImplementation project(':presenter:public')
36+
testImplementation project(':renderer:public')
37+
testImplementation project(':robot:public')
38+
testImplementation libs.kotlin.compile.testing.core
39+
testImplementation libs.kotlin.compile.testing.ksp
40+
41+
// Added so that the compiler plugin is picked up in tests.
42+
testImplementation libs.metro.compiler
43+
44+
// Bump transitive dependency.
45+
testImplementation libs.kotlin.compiler.embeddable
46+
testImplementation libs.ksp
47+
testImplementation libs.ksp.embeddable
48+
}
49+
50+
// We don't need the apiCheck in this module.
51+
tasks.named('apiCheck').configure {
52+
it.enabled = false
53+
}
54+
tasks.named('apiDump').configure {
55+
it.enabled = false
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package software.amazon.app.platform.metro
2+
3+
import com.google.auto.service.AutoService
4+
import com.google.devtools.ksp.processing.SymbolProcessor
5+
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
6+
import com.google.devtools.ksp.processing.SymbolProcessorProvider
7+
import software.amazon.app.platform.ksp.CompositeSymbolProcessor
8+
import software.amazon.app.platform.metro.processor.ContributesRendererProcessor
9+
10+
/** Entry point for KSP to pick up our [SymbolProcessor]. */
11+
@AutoService(SymbolProcessorProvider::class)
12+
@Suppress("unused")
13+
public class KotlinInjectExtensionSymbolProcessorProvider : SymbolProcessorProvider {
14+
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
15+
return CompositeSymbolProcessor(
16+
ContributesRendererProcessor(
17+
codeGenerator = environment.codeGenerator,
18+
logger = environment.logger,
19+
)
20+
)
21+
}
22+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package software.amazon.app.platform.metro
2+
3+
import dev.zacsweers.metro.Inject
4+
import dev.zacsweers.metro.Scope
5+
import software.amazon.app.platform.ksp.ContextAware
6+
7+
internal interface MetroContextAware : ContextAware {
8+
val injectFqName
9+
get() = Inject::class.requireQualifiedName()
10+
11+
private val scopeFqName
12+
get() = Scope::class.requireQualifiedName()
13+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package software.amazon.app.platform.metro
2+
3+
/** The package in which the App Platform extensions generate code. */
4+
internal const val METRO_LOOKUP_PACKAGE = "app.platform.inject.metro"

0 commit comments

Comments
 (0)