11import type { GenericLogger } from '@aws-lambda-powertools/commons/types' ;
2+ import { isRegExp } from '@aws-lambda-powertools/commons/typeutils' ;
23import type {
34 DynamicRoute ,
45 HttpMethod ,
@@ -11,11 +12,13 @@ import { ParameterValidationError } from './errors.js';
1112import { Route } from './Route.js' ;
1213import {
1314 compilePath ,
15+ getPathString ,
1416 resolvePrefixedPath ,
1517 validatePathPattern ,
1618} from './utils.js' ;
1719
1820class RouteHandlerRegistry {
21+ readonly #regexRoutes: Map < string , DynamicRoute > = new Map ( ) ;
1922 readonly #staticRoutes: Map < string , Route > = new Map ( ) ;
2023 readonly #dynamicRoutesSet: Set < string > = new Set ( ) ;
2124 readonly #dynamicRoutes: DynamicRoute [ ] = [ ] ;
@@ -44,8 +47,8 @@ class RouteHandlerRegistry {
4447 }
4548
4649 // 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 ;
4952
5053 return bSegments - aSegments ;
5154 }
@@ -103,6 +106,18 @@ class RouteHandlerRegistry {
103106
104107 const compiled = compilePath ( route . path ) ;
105108
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+ }
106121 if ( compiled . isDynamic ) {
107122 const dynamicRoute = {
108123 ...route ,
@@ -171,28 +186,10 @@ class RouteHandlerRegistry {
171186 } ;
172187 }
173188
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 ;
196193 }
197194
198195 return null ;
@@ -215,6 +212,7 @@ class RouteHandlerRegistry {
215212 const routes = [
216213 ...routeHandlerRegistry . #staticRoutes. values ( ) ,
217214 ...routeHandlerRegistry . #dynamicRoutes,
215+ ...routeHandlerRegistry . #regexRoutes. values ( ) ,
218216 ] ;
219217 for ( const route of routes ) {
220218 this . register (
@@ -227,6 +225,28 @@ class RouteHandlerRegistry {
227225 ) ;
228226 }
229227 }
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+ }
230250}
231251
232252export { RouteHandlerRegistry } ;
0 commit comments