@@ -17,9 +17,10 @@ import {
1717
1818class RouteHandlerRegistry {
1919 readonly #staticRoutes: Map < string , Route > = new Map ( ) ;
20- readonly #dynamicRoutesIndexMap: Map < string , number > = new Map ( ) ;
20+ readonly #dynamicRoutesSet: Set < string > = new Set ( ) ;
2121 readonly #dynamicRoutes: DynamicRoute [ ] = [ ] ;
2222 readonly #routesByMethod: Map < string , Route [ ] > = new Map ( ) ;
23+ #shouldSort = true ;
2324
2425 readonly #logger: Pick < GenericLogger , 'debug' | 'warn' | 'error' > ;
2526
@@ -49,43 +50,6 @@ class RouteHandlerRegistry {
4950
5051 return bSegments - aSegments ;
5152 }
52- /**
53- * Finds the correct insertion index using binary search to maintain sorted order.
54- * @param route - The route to find insertion point for
55- * @returns The index where the route should be inserted
56- */
57- #binarySearchInsertIndex( route : DynamicRoute ) : number {
58- let left = 0 ;
59- let right = this . #dynamicRoutes. length ;
60-
61- while ( left < right ) {
62- const mid = Math . floor ( ( left + right ) / 2 ) ;
63- const comparison = this . #compareRouteSpecificity(
64- route ,
65- this . #dynamicRoutes[ mid ]
66- ) ;
67-
68- if ( comparison < 0 ) {
69- right = mid ;
70- } else {
71- left = mid + 1 ;
72- }
73- }
74-
75- return left ;
76- }
77- /**
78- * Adds a dynamic route to the registry, ensuring that the dynamic
79- * routes array says sorted in ascending order of specificity.
80- * @param route - The dynamic route to add
81- * @returns The index in the specific routes array where the route was stored
82- */
83- #addDynamicRoute( route : DynamicRoute ) : number {
84- const index = this . #binarySearchInsertIndex( route ) ;
85- this . #dynamicRoutes. splice ( index , 0 , route ) ;
86- return index ;
87- }
88-
8953 /**
9054 * Registers a route in the registry after validating its path pattern.
9155 *
@@ -96,6 +60,7 @@ class RouteHandlerRegistry {
9660 * @param route - The route to register
9761 */
9862 public register ( route : Route ) : void {
63+ this . #shouldSort = true ;
9964 const { isValid, issues } = validatePathPattern ( route . path ) ;
10065 if ( ! isValid ) {
10166 for ( const issue of issues ) {
@@ -107,23 +72,25 @@ class RouteHandlerRegistry {
10772 const compiled = compilePath ( route . path ) ;
10873
10974 if ( compiled . isDynamic ) {
110- let routeIndex = this . #dynamicRoutesIndexMap. get ( route . id ) ?? - 1 ;
111- if ( routeIndex >= 0 ) {
75+ const dynamicRoute = {
76+ ...route ,
77+ ...compiled ,
78+ } ;
79+ if ( this . #dynamicRoutesSet. has ( route . id ) ) {
11280 this . #logger. warn (
11381 `Handler for method: ${ route . method } and path: ${ route . path } already exists. The previous handler will be replaced.`
11482 ) ;
11583 // as dynamic routes are stored in an array, we can't rely on
11684 // overwriting a key in a map like with static routes so have
117- // to manually manage deleting them
118- this . #dynamicRoutes. splice ( routeIndex , 1 ) ;
85+ // to manually manage overwriting them
86+ const i = this . #dynamicRoutes. findIndex (
87+ ( oldRoute ) => oldRoute . id === route . id
88+ ) ;
89+ this . #dynamicRoutes[ i ] = dynamicRoute ;
90+ } else {
91+ this . #dynamicRoutes. push ( dynamicRoute ) ;
11992 }
120-
121- routeIndex = this . #addDynamicRoute( {
122- ...route ,
123- ...compiled ,
124- } ) ;
125-
126- this . #dynamicRoutesIndexMap. set ( route . id , routeIndex ) ;
93+ this . #dynamicRoutesSet. add ( route . id ) ;
12794 } else {
12895 if ( this . #staticRoutes. has ( route . id ) ) {
12996 this . #logger. warn (
@@ -158,6 +125,10 @@ class RouteHandlerRegistry {
158125 * @returns Route handler options or null if no match found
159126 */
160127 public resolve ( method : HttpMethod , path : Path ) : RouteHandlerOptions | null {
128+ if ( this . #shouldSort) {
129+ this . #dynamicRoutes. sort ( this . #compareRouteSpecificity) ;
130+ this . #shouldSort = false ;
131+ }
161132 const routeId = `${ method } :${ path } ` ;
162133
163134 const staticRoute = this . #staticRoutes. get ( routeId ) ;
0 commit comments