From 3865580fac5eee004007db70e28e2f5229d9cc2e Mon Sep 17 00:00:00 2001 From: Thiago Santos Date: Fri, 15 Nov 2024 16:08:26 -0300 Subject: [PATCH] Composable codegen support --- .../routing/ksp/RoutingProcessor.kt | 23 ++++- samples/ksp-sample/build.gradle.kts | 8 ++ .../routing/sample/Composables.kt | 85 +++++++++++++++++++ 3 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 samples/ksp-sample/src/commonMain/kotlin/dev/programadorthi/routing/sample/Composables.kt diff --git a/ksp/core-processor/jvm/src/dev/programadorthi/routing/ksp/RoutingProcessor.kt b/ksp/core-processor/jvm/src/dev/programadorthi/routing/ksp/RoutingProcessor.kt index 5b0d8ec..db3e1ed 100644 --- a/ksp/core-processor/jvm/src/dev/programadorthi/routing/ksp/RoutingProcessor.kt +++ b/ksp/core-processor/jvm/src/dev/programadorthi/routing/ksp/RoutingProcessor.kt @@ -46,6 +46,12 @@ private class RoutingProcessor( ) : SymbolProcessor { private var invoked = false + private val fileName: String + get() = options["Routing_Module_Name"] ?: "Module" + + private val composableEnabled: Boolean + get() = options["Routing_Compose_Enable"]?.toBooleanStrictOrNull() ?: false + override fun process(resolver: Resolver): List { if (invoked) { return emptyList() @@ -97,7 +103,13 @@ private class RoutingProcessor( "@Route with regex can't be named" } + val isComposable = annotations.any { it.shortName.asString() == "Composable" } + if (isRegexRoute) { + check(!isComposable) { + // TODO: Add regex support to composable handle + "Combining @Route(regex = ...) and @Composable are not supported for $qualifiedName" + } if (routeAnnotation.method.isBlank()) { configureSpec .beginControlFlow( @@ -123,14 +135,18 @@ private class RoutingProcessor( routeAnnotation.name.isBlank() -> "name = null" else -> """name = "${routeAnnotation.name}"""" } + var memberName = handle + if (composableEnabled && isComposable) { + memberName = composable + } if (routeAnnotation.method.isBlank()) { configureSpec - .beginControlFlow("%M(path = %S, $named)", handle, routeAnnotation.path) + .beginControlFlow("%M(path = %S, $named)", memberName, routeAnnotation.path) } else { val template = """%M(path = %S, $named, method = %M(value = "${routeAnnotation.method}"))""" configureSpec - .beginControlFlow(template, handle, routeAnnotation.path, routeMethod) + .beginControlFlow(template, memberName, routeAnnotation.path, routeMethod) } } @@ -320,7 +336,7 @@ private class RoutingProcessor( FileSpec .builder( packageName = "dev.programadorthi.routing.generated", - fileName = "${options["Routing_Module_Name"] ?: "Module"}Routes", + fileName = "${fileName}Routes", ) .addFileComment("Generated by Kotlin Routing") .addFunction(this) @@ -358,6 +374,7 @@ private class RoutingProcessor( } private companion object { + private val composable = MemberName("dev.programadorthi.routing.compose", "composable") private val handle = MemberName("dev.programadorthi.routing.core", "handle") private val routeMethod = MemberName("dev.programadorthi.routing.core", "RouteMethod") private val call = MemberName("dev.programadorthi.routing.core.application", "call") diff --git a/samples/ksp-sample/build.gradle.kts b/samples/ksp-sample/build.gradle.kts index 304396b..9bd90fe 100644 --- a/samples/ksp-sample/build.gradle.kts +++ b/samples/ksp-sample/build.gradle.kts @@ -4,6 +4,12 @@ plugins { kotlin("multiplatform") alias(libs.plugins.ksp) id("dev.programadorthi.routing") version "0.0.99" + alias(libs.plugins.jetbrains.compose) + alias(libs.plugins.compose.compiler) +} + +ksp { + arg("Routing_Compose_Enable", "true") } kotlin { @@ -18,7 +24,9 @@ kotlin { commonMain { dependencies { implementation(projects.core) + implementation(projects.integration.compose) implementation(projects.ksp.coreAnnotations) + implementation(compose.runtime) } } } diff --git a/samples/ksp-sample/src/commonMain/kotlin/dev/programadorthi/routing/sample/Composables.kt b/samples/ksp-sample/src/commonMain/kotlin/dev/programadorthi/routing/sample/Composables.kt new file mode 100644 index 0000000..c94944f --- /dev/null +++ b/samples/ksp-sample/src/commonMain/kotlin/dev/programadorthi/routing/sample/Composables.kt @@ -0,0 +1,85 @@ +package dev.programadorthi.routing.sample + +import androidx.compose.runtime.Composable +import dev.programadorthi.routing.annotation.Body +import dev.programadorthi.routing.annotation.Path +import dev.programadorthi.routing.annotation.Route +import dev.programadorthi.routing.core.application.Application +import io.ktor.http.Parameters +import io.ktor.util.Attributes + +@Route("/compose") +@Composable +fun compose() { + println(">>>> I'm routing") +} + +@Route(path = "/compose/{id}") +@Composable +fun compose(id: Double) { + println(">>>> ID: $id") +} + +@Route(path = "/composeNamed/{name}", name = "composeNamed") +@Composable +fun composeNamed(name: String) { + println(">>>> name: $name") +} + +@Route(path = "/composeCustom/{random}", name = "composeCustom") +@Composable +fun composeCustom(@Path("random") value: String) { + println(">>>> value: $value") +} + +@Route(path = "/composeOptional/{id?}") +@Composable +fun composeOptional(id: Char?) { + println(">>>> Optional ID: $id") +} + +@Route(path = "/composeTailcard/{param...}") +@Composable +fun composeTailcard(param: List?) { + println(">>>> Tailcard params: $param") +} + +@Route("/compose-with-body") +@Composable +fun composeWithBody(@Body user: User) { + println(">>>> with body $user") +} + +@Route("/compose-with-null-body") +@Composable +fun composeWithNullBody(@Body user: User?) { + println(">>>> null body $user") +} + +@Route("/compose", method = "PUSH") +@Composable +fun composeByPushMethod() { + println(">>>> I'm pushing a route") +} + +@Route("/compose/{part1}/{part2}") +@Composable +fun composeMultiParameters(part1: Int, part2: String) { + println(">>>> Parts: $part1 and $part2") +} + +@Route("/compose-call/{part1}/{part2}") +@Composable +fun composeCallParameters( + application: Application, + parameters: Parameters, + attributes: Attributes, +) { + println( + """ + >>>> application: $application + >>>> parameters: $parameters + >>>> attributes: $attributes + """.trimIndent() + ) +}