1
1
import type { GenericLogger } from '@aws-lambda-powertools/commons/types' ;
2
+ import { isRegExp } from '@aws-lambda-powertools/commons/typeutils' ;
2
3
import type {
3
4
DynamicRoute ,
4
5
HttpMethod ,
@@ -11,11 +12,13 @@ import { ParameterValidationError } from './errors.js';
11
12
import { Route } from './Route.js' ;
12
13
import {
13
14
compilePath ,
15
+ getPathString ,
14
16
resolvePrefixedPath ,
15
17
validatePathPattern ,
16
18
} from './utils.js' ;
17
19
18
20
class RouteHandlerRegistry {
21
+ readonly #regexRoutes: Map < string , DynamicRoute > = new Map ( ) ;
19
22
readonly #staticRoutes: Map < string , Route > = new Map ( ) ;
20
23
readonly #dynamicRoutesSet: Set < string > = new Set ( ) ;
21
24
readonly #dynamicRoutes: DynamicRoute [ ] = [ ] ;
@@ -44,8 +47,8 @@ class RouteHandlerRegistry {
44
47
}
45
48
46
49
// Routes with more path segments are more specific
47
- const aSegments = a . path . split ( '/' ) . length ;
48
- const bSegments = b . path . split ( '/' ) . length ;
50
+ const aSegments = getPathString ( a . path ) . split ( '/' ) . length ;
51
+ const bSegments = getPathString ( b . path ) . split ( '/' ) . length ;
49
52
50
53
return bSegments - aSegments ;
51
54
}
@@ -103,6 +106,18 @@ class RouteHandlerRegistry {
103
106
104
107
const compiled = compilePath ( route . path ) ;
105
108
109
+ if ( isRegExp ( route . path ) ) {
110
+ if ( this . #regexRoutes. has ( route . id ) ) {
111
+ this . #logger. warn (
112
+ `Handler for method: ${ route . method } and path: ${ route . path } already exists. The previous handler will be replaced.`
113
+ ) ;
114
+ }
115
+ this . #regexRoutes. set ( route . id , {
116
+ ...route ,
117
+ ...compiled ,
118
+ } ) ;
119
+ return ;
120
+ }
106
121
if ( compiled . isDynamic ) {
107
122
const dynamicRoute = {
108
123
...route ,
@@ -171,28 +186,10 @@ class RouteHandlerRegistry {
171
186
} ;
172
187
}
173
188
174
- for ( const route of this . #dynamicRoutes) {
175
- if ( route . method !== method ) continue ;
176
-
177
- const match = route . regex . exec ( path ) ;
178
- if ( match ?. groups ) {
179
- const params = match . groups ;
180
-
181
- const processedParams = this . #processParams( params ) ;
182
-
183
- const validation = this . #validateParams( processedParams ) ;
184
-
185
- if ( ! validation . isValid ) {
186
- throw new ParameterValidationError ( validation . issues ) ;
187
- }
188
-
189
- return {
190
- handler : route . handler ,
191
- params : processedParams ,
192
- rawParams : params ,
193
- middleware : route . middleware ,
194
- } ;
195
- }
189
+ const routes = [ ...this . #dynamicRoutes, ...this . #regexRoutes. values ( ) ] ;
190
+ for ( const route of routes ) {
191
+ const result = this . #processRoute( route , method , path ) ;
192
+ if ( result ) return result ;
196
193
}
197
194
198
195
return null ;
@@ -215,6 +212,7 @@ class RouteHandlerRegistry {
215
212
const routes = [
216
213
...routeHandlerRegistry . #staticRoutes. values ( ) ,
217
214
...routeHandlerRegistry . #dynamicRoutes,
215
+ ...routeHandlerRegistry . #regexRoutes. values ( ) ,
218
216
] ;
219
217
for ( const route of routes ) {
220
218
this . register (
@@ -227,6 +225,28 @@ class RouteHandlerRegistry {
227
225
) ;
228
226
}
229
227
}
228
+
229
+ #processRoute( route : DynamicRoute , method : HttpMethod , path : Path ) {
230
+ if ( route . method !== method ) return ;
231
+
232
+ const match = route . regex . exec ( getPathString ( path ) ) ;
233
+ if ( ! match ) return ;
234
+
235
+ const params = match . groups || { } ;
236
+ const processedParams = this . #processParams( params ) ;
237
+ const validation = this . #validateParams( processedParams ) ;
238
+
239
+ if ( ! validation . isValid ) {
240
+ throw new ParameterValidationError ( validation . issues ) ;
241
+ }
242
+
243
+ return {
244
+ handler : route . handler ,
245
+ params : processedParams ,
246
+ rawParams : params ,
247
+ middleware : route . middleware ,
248
+ } ;
249
+ }
230
250
}
231
251
232
252
export { RouteHandlerRegistry } ;
0 commit comments