@@ -217,7 +217,7 @@ type _PathParam<Path extends string> =
217
217
*/
218
218
type PathParam < Path extends string > =
219
219
// check if path is just a wildcard
220
- Path extends "*"
220
+ Path extends "*" | "/*"
221
221
? "*"
222
222
: // look for wildcard at the end of the path
223
223
Path extends `${infer Rest } /*`
@@ -621,7 +621,7 @@ export function generatePath<Path extends string>(
621
621
[ key in PathParam < Path > ] : string | null ;
622
622
} = { } as any
623
623
) : string {
624
- let path = originalPath ;
624
+ let path : string = originalPath ;
625
625
if ( path . endsWith ( "*" ) && path !== "*" && ! path . endsWith ( "/*" ) ) {
626
626
warning (
627
627
false ,
@@ -633,49 +633,46 @@ export function generatePath<Path extends string>(
633
633
path = path . replace ( / \* $ / , "/*" ) as Path ;
634
634
}
635
635
636
- return (
637
- path
638
- . replace (
639
- / ^ : ( \w + ) ( \? ? ) / g,
640
- ( _ , key : PathParam < Path > , optional : string | undefined ) => {
641
- let param = params [ key ] ;
642
- if ( optional === "?" ) {
643
- return param == null ? "" : param ;
644
- }
645
- if ( param == null ) {
646
- invariant ( false , `Missing ":${ key } " param` ) ;
647
- }
648
- return param ;
649
- }
650
- )
651
- . replace (
652
- / \/ : ( \w + ) ( \? ? ) / g,
653
- ( _ , key : PathParam < Path > , optional : string | undefined ) => {
654
- let param = params [ key ] ;
655
- if ( optional === "?" ) {
656
- return param == null ? "" : `/${ param } ` ;
657
- }
658
- if ( param == null ) {
659
- invariant ( false , `Missing ":${ key } " param` ) ;
660
- }
661
- return `/${ param } ` ;
662
- }
663
- )
664
- // Remove any optional markers from optional static segments
665
- . replace ( / \? / g, "" )
666
- . replace ( / ( \/ ? ) \* / , ( _ , prefix , __ , str ) => {
636
+ // ensure `/` is added at the beginning if the path is absolute
637
+ const prefix = path . startsWith ( "/" ) ? "/" : "" ;
638
+
639
+ const segments = path
640
+ . split ( / \/ + / )
641
+ . map ( ( segment , index , array ) => {
642
+ const isLastSegment = index === array . length - 1 ;
643
+
644
+ // only apply the splat if it's the last segment
645
+ if ( isLastSegment && segment === "*" ) {
667
646
const star = "*" as PathParam < Path > ;
647
+ const starParam = params [ star ] ;
668
648
669
- if ( params [ star ] == null ) {
670
- // If no splat was provided, trim the trailing slash _unless_ it's
671
- // the entire path
672
- return str === "/*" ? "/" : "" ;
649
+ // Apply the splat
650
+ return starParam ;
651
+ }
652
+
653
+ const keyMatch = segment . match ( / ^ : ( \w + ) ( \? ? ) $ / ) ;
654
+ if ( keyMatch ) {
655
+ const [ , key , optional ] = keyMatch ;
656
+ let param = params [ key as PathParam < Path > ] ;
657
+
658
+ if ( optional === "?" ) {
659
+ return param == null ? "" : param ;
673
660
}
674
661
675
- // Apply the splat
676
- return `${ prefix } ${ params [ star ] } ` ;
677
- } )
678
- ) ;
662
+ if ( param == null ) {
663
+ invariant ( false , `Missing ":${ key } " param` ) ;
664
+ }
665
+
666
+ return param ;
667
+ }
668
+
669
+ // Remove any optional markers from optional static segments
670
+ return segment . replace ( / \? $ / g, "" ) ;
671
+ } )
672
+ // Remove empty segments
673
+ . filter ( ( segment ) => ! ! segment ) ;
674
+
675
+ return prefix + segments . join ( "/" ) ;
679
676
}
680
677
681
678
/**
0 commit comments