Skip to content

Commit 9de7294

Browse files
Regex parameter support
1 parent 1c4a2fd commit 9de7294

File tree

4 files changed

+41
-12
lines changed
  • ksp-annotations/common/src/dev/programadorthi/routing/annotation
  • ksp-processor/jvm/src/dev/programadorthi/routing/ksp
  • samples/ksp-sample/src/main/kotlin

4 files changed

+41
-12
lines changed

ksp-annotations/common/src/dev/programadorthi/routing/annotation/Route.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package dev.programadorthi.routing.annotation
22

33
@Target(AnnotationTarget.FUNCTION)
44
public annotation class Route(
5-
val path: String,
6-
val name: String = ""
5+
val path: String = "",
6+
val name: String = "",
7+
val regex: String = "",
78
)

ksp-processor/jvm/src/dev/programadorthi/routing/ksp/RoutingProcessor.kt

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,14 @@ private class RoutingProcessor(
7575
val routeAnnotation = checkNotNull(func.getAnnotationsByType(Route::class).firstOrNull()) {
7676
"Invalid state because a @Route was not found to '$qualifiedName'"
7777
}
78+
val isRegexRoute = routeAnnotation.regex.isNotBlank()
79+
check(isRegexRoute || routeAnnotation.path.isNotBlank()) {
80+
"Using @Route a path or a regex is required"
81+
}
82+
check(!isRegexRoute || routeAnnotation.name.isBlank()) {
83+
"@Route using regex can't be named"
84+
}
85+
7886
val parameters = mutableListOf<String>()
7987

8088
for (param in func.parameters) {
@@ -88,16 +96,17 @@ private class RoutingProcessor(
8896
?.value
8997
?: paramName
9098
val paramType = param.type.resolve()
91-
if (routeAnnotation.path.contains("{$customName...}")) {
99+
if (!isRegexRoute && routeAnnotation.path.contains("{$customName...}")) {
92100
val listDeclaration = checkNotNull(resolver.getClassDeclarationByName<List<*>>()) {
93101
"Class declaration not found to List<String>?"
94102
}
95103
check(paramType.declaration == listDeclaration) {
96104
"Tailcard parameter must be a List<String>?"
97105
}
98-
val genericArgument = checkNotNull(param.type.element?.typeArguments?.firstOrNull()?.type?.resolve()) {
99-
"No <String> type found at tailcard parameter"
100-
}
106+
val genericArgument =
107+
checkNotNull(param.type.element?.typeArguments?.firstOrNull()?.type?.resolve()) {
108+
"No <String> type found at tailcard parameter"
109+
}
101110
check(genericArgument == resolver.builtIns.stringType) {
102111
"Tailcard list items type must be non nullable String"
103112
}
@@ -108,9 +117,10 @@ private class RoutingProcessor(
108117
continue
109118
}
110119

111-
val isOptional = routeAnnotation.path.contains("{$customName?}")
112-
val isRequired = routeAnnotation.path.contains("{$customName}")
113-
check(isOptional || isRequired) {
120+
val isRegex = isRegexRoute && routeAnnotation.regex.contains("(?<$customName>")
121+
val isOptional = !isRegex && routeAnnotation.path.contains("{$customName?}")
122+
val isRequired = !isRegex && routeAnnotation.path.contains("{$customName}")
123+
check(isRegex || isOptional || isRequired) {
114124
"'$qualifiedName' has parameter '$paramName' that is not declared as path parameter {$customName}"
115125
}
116126
val parsed = """$paramName = %M.parameters["$customName"]"""
@@ -127,9 +137,13 @@ private class RoutingProcessor(
127137
else -> """name = "${routeAnnotation.name}""""
128138
}
129139

130-
configureSpec
131-
.beginControlFlow("""%M(path = "${routeAnnotation.path}", $named)""", handle)
132-
.addStatement("""$qualifiedName$params""", *calls)
140+
with(configureSpec) {
141+
if (isRegexRoute) {
142+
beginControlFlow("""%M(%T(%S))""", handle, Regex::class, routeAnnotation.regex)
143+
} else {
144+
beginControlFlow("""%M(path = %S, $named)""", handle, routeAnnotation.path)
145+
}
146+
}.addStatement("""$qualifiedName$params""", *calls)
133147
.endControlFlow()
134148
}
135149

samples/ksp-sample/src/main/kotlin/Main.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,8 @@ suspend fun main() {
2727
delay(500)
2828
router.call(uri = "/tailcard/p1/p2/p3/p4")
2929
delay(500)
30+
router.call(uri = "/foo/hello") // regex1
31+
delay(500)
32+
router.call(uri = "/456") // regex2
33+
delay(500)
3034
}

samples/ksp-sample/src/main/kotlin/dev/programadorthi/routing/sample/Routes.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,16 @@ fun tailcard(param: List<String>?) {
3333
println(">>>> Tailcard params: $param")
3434
}
3535

36+
@Route(regex = ".+/hello")
37+
fun regex1() {
38+
println(">>>> Routing with regex")
39+
}
40+
41+
@Route(regex = "/(?<number>\\d+)")
42+
fun regex2(number: Int) {
43+
println(">>>> Routing with regex to number: $number")
44+
}
45+
3646
class Routes {
3747
//@Route("/path")
3848
fun run() {

0 commit comments

Comments
 (0)