@@ -132,6 +132,7 @@ export abstract class CoreRouter {
132132 routes : [ ] as Array < Route < any , any , any > > ,
133133 routesByPathMethod : { } as Record < string , Route < any , any , any > > ,
134134 routesByMethod : { } as { [ method in Uppercase < HttpMethod > ] ?: Array < Route < any , any , any > > } ,
135+ routesByName : { } as Record < string , Route < any , any , any > > ,
135136 prefix : '' ,
136137 groupMiddlewares : [ ] as any [ ] ,
137138 globalMiddlewares : [ ] as any [ ] ,
@@ -156,6 +157,7 @@ export abstract class CoreRouter {
156157 'routes' ,
157158 'routesByPathMethod' ,
158159 'routesByMethod' ,
160+ 'routesByName' ,
159161 'prefix' ,
160162 'groupMiddlewares' ,
161163 'globalMiddlewares' ,
@@ -341,6 +343,7 @@ export abstract class CoreRouter {
341343 static routes : Array < Route < any , any , any > > = [ ]
342344 static routesByPathMethod : Record < string , Route < any , any , any > > = { }
343345 static routesByMethod : { [ method in Uppercase < HttpMethod > ] ?: Array < Route < any , any , any > > } = { }
346+ static routesByName : Record < string , Route < any , any , any > > = { }
344347
345348 static prefix = ''
346349 static groupMiddlewares : any [ ] = [ ]
@@ -432,6 +435,10 @@ export abstract class CoreRouter {
432435 this . routesByMethod = { }
433436 }
434437
438+ if ( ! this . routesByName || typeof this . routesByName !== 'object' ) {
439+ this . routesByName = { }
440+ }
441+
435442 if ( typeof this . prefix !== 'string' ) {
436443 this . prefix = ''
437444 }
@@ -459,6 +466,68 @@ export abstract class CoreRouter {
459466 . join ( '/' )
460467 }
461468
469+ protected static parseRouteParameters ( path : string ) : Array < {
470+ name : string
471+ field ?: string
472+ optional : boolean
473+ } > {
474+ const parameters : Array < { name : string ; field ?: string ; optional : boolean } > = [ ]
475+ const seen = new Set < string > ( )
476+ const pattern = / \{ ( [ ^ { } ] + ) \} / g
477+ let match : RegExpExecArray | null
478+
479+ while ( ( match = pattern . exec ( path ) ) !== null ) {
480+ const raw = match [ 1 ] . trim ( )
481+ const optional = raw . endsWith ( '?' )
482+ const withoutOptional = optional ? raw . slice ( 0 , - 1 ) : raw
483+ const [ name , field ] = withoutOptional . split ( ':' , 2 ) . map ( part => part . trim ( ) )
484+
485+ if ( ! name || seen . has ( name ) ) continue
486+
487+ seen . add ( name )
488+ parameters . push ( {
489+ name,
490+ field : field || undefined ,
491+ optional,
492+ } )
493+ }
494+
495+ return parameters
496+ }
497+
498+ protected static expandRoutePath ( path : string ) : string [ ] {
499+ let paths = [ '' ]
500+ const segments = this . normalizePath ( path ) . split ( '/' ) . filter ( Boolean )
501+
502+ for ( const segment of segments ) {
503+ const match = segment . match ( / ^ \{ ( [ ^ { } ] + ) \} $ / )
504+
505+ if ( ! match ) {
506+ paths = paths . map ( current => `${ current } /${ segment } ` )
507+ continue
508+ }
509+
510+ const raw = match [ 1 ] . trim ( )
511+ const optional = raw . endsWith ( '?' )
512+ const withoutOptional = optional ? raw . slice ( 0 , - 1 ) : raw
513+ const [ rawName ] = withoutOptional . split ( ':' , 2 )
514+ const name = rawName . trim ( )
515+
516+ if ( ! name ) continue
517+
518+ const parameterSegment = `/:${ name } `
519+ paths = optional
520+ ? paths . flatMap ( current => [ current , `${ current } ${ parameterSegment } ` ] )
521+ : paths . map ( current => `${ current } ${ parameterSegment } ` )
522+ }
523+
524+ return paths . map ( path => path || '/' )
525+ }
526+
527+ protected static routeRegistrationPaths ( path : string ) : string [ ] {
528+ return this . expandRoutePath ( path )
529+ }
530+
462531 /**
463532 * Configures the router with the given options, such as method override settings.
464533 *
@@ -573,7 +642,7 @@ export abstract class CoreRouter {
573642 path : string ,
574643 handler : any ,
575644 middlewares ?: any [ ] | any
576- ) : void {
645+ ) : Route < any , any , any > {
577646 this . ensureState ( )
578647
579648 const context = this . groupContext . getStore ( )
@@ -586,12 +655,25 @@ export abstract class CoreRouter {
586655 : undefined
587656
588657 const fullPath = this . normalizePath ( `${ activePrefix } /${ path } ` )
658+ const registrationPaths = this . routeRegistrationPaths ( fullPath )
659+ const parameters = this . parseRouteParameters ( fullPath )
589660
590661 const route = new Route (
591662 methods . includes ( 'options' ) ? methods : methods . concat ( 'options' ) ,
592663 fullPath ,
593664 handler ,
594- [ ...this . globalMiddlewares , ...activeGroupMiddlewares , ...( middlewares || [ ] ) ]
665+ [ ...this . globalMiddlewares , ...activeGroupMiddlewares , ...( middlewares || [ ] ) ] ,
666+ {
667+ registrationPaths,
668+ parameters,
669+ onName : ( name , route , previousName ) => {
670+ if ( previousName && this . routesByName [ previousName ] === route ) {
671+ delete this . routesByName [ previousName ]
672+ }
673+
674+ this . routesByName [ name ] = route
675+ } ,
676+ }
595677 )
596678
597679 if (
@@ -610,6 +692,8 @@ export abstract class CoreRouter {
610692 }
611693 this . routesByMethod [ method ] . push ( route )
612694 }
695+
696+ return route
613697 }
614698
615699 /**
@@ -670,8 +754,8 @@ export abstract class CoreRouter {
670754 * @param handler The handler function for the GET route.
671755 * @param middlewares Optional middlewares to apply to the GET route.
672756 */
673- static get ( path : string , handler : any , middlewares ?: any [ ] | any ) : void {
674- this . add ( 'get' , path , handler , middlewares )
757+ static get ( path : string , handler : any , middlewares ?: any [ ] | any ) : Route < any , any , any > {
758+ return this . add ( 'get' , path , handler , middlewares )
675759 }
676760
677761 /**
@@ -682,8 +766,8 @@ export abstract class CoreRouter {
682766 * @param handler
683767 * @param middlewares
684768 */
685- static post ( path : string , handler : any , middlewares ?: any [ ] | any ) : void {
686- this . add ( 'post' , path , handler , middlewares )
769+ static post ( path : string , handler : any , middlewares ?: any [ ] | any ) : Route < any , any , any > {
770+ return this . add ( 'post' , path , handler , middlewares )
687771 }
688772
689773 /**
@@ -694,8 +778,8 @@ export abstract class CoreRouter {
694778 * @param handler
695779 * @param middlewares
696780 */
697- static put ( path : string , handler : any , middlewares ?: any [ ] | any ) : void {
698- this . add ( 'put' , path , handler , middlewares )
781+ static put ( path : string , handler : any , middlewares ?: any [ ] | any ) : Route < any , any , any > {
782+ return this . add ( 'put' , path , handler , middlewares )
699783 }
700784
701785 /**
@@ -706,8 +790,8 @@ export abstract class CoreRouter {
706790 * @param handler
707791 * @param middlewares
708792 */
709- static delete ( path : string , handler : any , middlewares ?: any [ ] | any ) : void {
710- this . add ( 'delete' , path , handler , middlewares )
793+ static delete ( path : string , handler : any , middlewares ?: any [ ] | any ) : Route < any , any , any > {
794+ return this . add ( 'delete' , path , handler , middlewares )
711795 }
712796
713797 /**
@@ -718,8 +802,8 @@ export abstract class CoreRouter {
718802 * @param handler
719803 * @param middlewares
720804 */
721- static patch ( path : string , handler : any , middlewares ?: any [ ] | any ) : void {
722- this . add ( 'patch' , path , handler , middlewares )
805+ static patch ( path : string , handler : any , middlewares ?: any [ ] | any ) : Route < any , any , any > {
806+ return this . add ( 'patch' , path , handler , middlewares )
723807 }
724808
725809 /**
@@ -730,8 +814,8 @@ export abstract class CoreRouter {
730814 * @param handler
731815 * @param middlewares
732816 */
733- static options ( path : string , handler : any , middlewares ?: any [ ] | any ) : void {
734- this . add ( 'options' , path , handler , middlewares )
817+ static options ( path : string , handler : any , middlewares ?: any [ ] | any ) : Route < any , any , any > {
818+ return this . add ( 'options' , path , handler , middlewares )
735819 }
736820
737821 /**
@@ -742,8 +826,8 @@ export abstract class CoreRouter {
742826 * @param handler
743827 * @param middlewares
744828 */
745- static head ( path : string , handler : any , middlewares ?: any [ ] | any ) : void {
746- this . add ( 'head' , path , handler , middlewares )
829+ static head ( path : string , handler : any , middlewares ?: any [ ] | any ) : Route < any , any , any > {
830+ return this . add ( 'head' , path , handler , middlewares )
747831 }
748832
749833 /**
@@ -814,7 +898,8 @@ export abstract class CoreRouter {
814898 * @param type - 'method' to get routes organized by method
815899 */
816900 static allRoutes ( type : 'method' ) : { [ method in Uppercase < HttpMethod > ] ?: Array < Route < any , any , any > > }
817- static allRoutes ( type ?: 'method' | 'path' ) :
901+ static allRoutes ( type : 'name' ) : Record < string , Route < any , any , any > >
902+ static allRoutes ( type ?: 'method' | 'path' | 'name' ) :
818903 Array < Route < any , any , any > > |
819904 Record < string , Route < any , any , any > > |
820905 Record < string , Array < Route < any , any , any > > > {
@@ -828,9 +913,23 @@ export abstract class CoreRouter {
828913 return this . routesByPathMethod
829914 }
830915
916+ if ( type === 'name' ) {
917+ return this . routesByName
918+ }
919+
831920 return this . routes . filter ( ( e : Route < any , any , any > ) => e . methods . length > 1 || e . methods [ 0 ] !== 'options' )
832921 }
833922
923+ static route ( name : string ) : Route < any , any , any > | undefined {
924+ this . ensureState ( )
925+
926+ return this . routesByName [ name ]
927+ }
928+
929+ static url ( name : string , params ?: Record < string , any > ) : string | undefined {
930+ return this . route ( name ) ?. toPath ( params )
931+ }
932+
834933 protected static resolveHandler ( route : Route < any , any , any > ) : {
835934 handlerFunction : ( ( ctx : any , req : CoreRequest ) => any | Promise < any > ) | null
836935 instance : Controller < any > | null
0 commit comments