Skip to content

Commit

Permalink
Path parameter support
Browse files Browse the repository at this point in the history
  • Loading branch information
programadorthi committed Nov 12, 2024
1 parent fa79aa4 commit 4fa57fa
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
package dev.programadorthi.routing.ksp

import com.google.devtools.ksp.getVisibility
import com.google.devtools.ksp.isLocal
import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.Dependencies
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
import com.google.devtools.ksp.symbol.FunctionKind
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSAnnotation
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.google.devtools.ksp.symbol.KSTypeReference
import com.google.devtools.ksp.symbol.Visibility
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.MemberName
import com.squareup.kotlinpoet.ksp.writeTo
import dev.programadorthi.routing.annotation.Route

Expand All @@ -37,6 +43,9 @@ private class RoutingProcessor(
}
invoked = true

val call = MemberName("dev.programadorthi.routing.core.application", "call")
val handle = MemberName("dev.programadorthi.routing.core", "handle")

val configureSpec = FunSpec
.builder("configure")
.addModifiers(KModifier.INTERNAL)
Expand All @@ -46,21 +55,56 @@ private class RoutingProcessor(
.getSymbolsWithAnnotation(Route::class.java.name)
.filterIsInstance<KSFunctionDeclaration>()
.forEach { func ->
val qualifiedName = func.qualifiedName?.asString()

check(func.functionKind == FunctionKind.TOP_LEVEL) {
"$qualifiedName fun must be a top level fun"
}

check(func.getVisibility() != Visibility.PRIVATE) {
"$qualifiedName fun must not be private"
}

check(func.packageName.asString().isNotBlank()) {
"Local functions are not supported. " +
"Please provide a package to fun '${func.qualifiedName?.asString()}'"
"Top level fun '$qualifiedName' must have a package"
}

val annotation = func.getAnnotationByName("Route")
val path = annotation?.getArgumentValueByName<String>("value")

configureSpec.addCode(
"""
|handle(path = "$path") {
| ${func.qualifiedName?.asString()}()
|}
|""".trimMargin()
)
val path = checkNotNull(annotation?.getArgumentValueByName<String>("value")) {
"No path provided to @Route annotation at '$qualifiedName'"
}

val parameters = mutableListOf<String>()

for (param in func.parameters) {
val paramName = param.name?.asString()
check(path.contains("{$paramName}")) {
"'$qualifiedName' has parameter '$paramName' that is not declared as path parameter {$paramName}"
}

val parsed = """$paramName = %M.parameters["$paramName"]!!"""
parameters += when (param.type.resolve()) {
resolver.builtIns.booleanType -> "$parsed.toBoolean()"
resolver.builtIns.byteType -> "$parsed.toByte()"
resolver.builtIns.charType -> "$parsed[0]"
resolver.builtIns.doubleType -> "$parsed.toDouble()"
resolver.builtIns.floatType -> "$parsed.toFloat()"
resolver.builtIns.intType -> "$parsed.toInt()"
resolver.builtIns.longType -> "$parsed.toInt()"
resolver.builtIns.shortType -> "$parsed.toInt()"
resolver.builtIns.stringType -> parsed
else -> error("Path parameters must be primitive type only")
}
}

val calls = Array(size = parameters.size) { call }
val params = parameters
.joinToString(prefix = "(", postfix = ")") { "\n$it" }

configureSpec
.beginControlFlow("""%M(path = "$path")""", handle)
.addStatement("""$qualifiedName$params""", *calls)
.endControlFlow()
}

FileSpec
Expand All @@ -69,7 +113,6 @@ private class RoutingProcessor(
fileName = "ModuleRoutes"
)
.addFileComment("Generated by Kotlin Routing")
.addImport("dev.programadorthi.routing.core", "handle")
.addFunction(configureSpec.build())
.build()
.writeTo(
Expand Down
4 changes: 3 additions & 1 deletion samples/ksp-sample/src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ suspend fun main() {
configure()
}
router.call(uri = "/path")
delay(1_000)
delay(500)
router.call(uri = "/path/1.2/routing")
delay(500)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,15 @@ import dev.programadorthi.routing.annotation.Route
fun execute() {
println(">>>> I'm routing")
}

@Route("/path/{id}/{name}")
fun execute(id: Double, name: String) {
println(">>>> ID: $id, name: $name")
}

class Routes {
//@Route("/path")
fun run() {
println(">>>> I'm routing")
}
}

0 comments on commit 4fa57fa

Please sign in to comment.