@@ -487,7 +487,7 @@ export function pathToRegexp(
487
487
for ( const input of pathsToArray ( path , [ ] ) ) {
488
488
const data = typeof input === "object" ? input : parse ( input , options ) ;
489
489
for ( const tokens of flatten ( data . tokens , 0 , [ ] ) ) {
490
- sources . push ( toRegExp ( tokens , delimiter , keys , data . originalPath ) ) ;
490
+ sources . push ( toRegExpSource ( tokens , delimiter , keys , data . originalPath ) ) ;
491
491
}
492
492
}
493
493
@@ -544,12 +544,12 @@ function* flatten(
544
544
/**
545
545
* Transform a flat sequence of tokens into a regular expression.
546
546
*/
547
- function toRegExp (
547
+ function toRegExpSource (
548
548
tokens : FlatToken [ ] ,
549
549
delimiter : string ,
550
550
keys : Keys ,
551
551
originalPath : string | undefined ,
552
- ) {
552
+ ) : string {
553
553
let result = "" ;
554
554
let backtrack = "" ;
555
555
let isSafeSegmentParam = true ;
@@ -588,7 +588,7 @@ function toRegExp(
588
588
/**
589
589
* Block backtracking on previous text and ignore delimiter string.
590
590
*/
591
- function negate ( delimiter : string , backtrack : string ) {
591
+ function negate ( delimiter : string , backtrack : string ) : string {
592
592
if ( backtrack . length < 2 ) {
593
593
if ( delimiter . length < 2 ) return `[^${ escape ( delimiter + backtrack ) } ]` ;
594
594
return `(?:(?!${ escape ( delimiter ) } )[^${ escape ( backtrack ) } ])` ;
@@ -600,40 +600,65 @@ function negate(delimiter: string, backtrack: string) {
600
600
}
601
601
602
602
/**
603
- * Stringify token data into a path string.
603
+ * Stringify an array of tokens into a path string.
604
604
*/
605
- export function stringify ( data : TokenData ) {
606
- return data . tokens
607
- . map ( function stringifyToken ( token , index , tokens ) : string {
608
- if ( token . type === "text" ) return escapeText ( token . value ) ;
609
- if ( token . type === "group" ) {
610
- return `{${ token . tokens . map ( stringifyToken ) . join ( "" ) } }` ;
611
- }
605
+ function stringifyTokens ( tokens : Token [ ] ) : string {
606
+ let value = "" ;
607
+ let i = 0 ;
612
608
613
- const isSafe =
614
- isNameSafe ( token . name ) && isNextNameSafe ( tokens [ index + 1 ] ) ;
615
- const key = isSafe ? token . name : JSON . stringify ( token . name ) ;
609
+ function name ( value : string ) {
610
+ const isSafe = isNameSafe ( value ) && isNextNameSafe ( tokens [ i ] ) ;
611
+ return isSafe ? value : JSON . stringify ( value ) ;
612
+ }
616
613
617
- if ( token . type === "param" ) return `:${ key } ` ;
618
- if ( token . type === "wildcard" ) return `*${ key } ` ;
619
- throw new TypeError ( `Unexpected token: ${ token } ` ) ;
620
- } )
621
- . join ( "" ) ;
614
+ while ( i < tokens . length ) {
615
+ const token = tokens [ i ++ ] ;
616
+
617
+ if ( token . type === "text" ) {
618
+ value += escapeText ( token . value ) ;
619
+ continue ;
620
+ }
621
+
622
+ if ( token . type === "group" ) {
623
+ value += `{${ stringifyTokens ( token . tokens ) } }` ;
624
+ continue ;
625
+ }
626
+
627
+ if ( token . type === "param" ) {
628
+ value += `:${ name ( token . name ) } ` ;
629
+ continue ;
630
+ }
631
+
632
+ if ( token . type === "wildcard" ) {
633
+ value += `*${ name ( token . name ) } ` ;
634
+ continue ;
635
+ }
636
+
637
+ throw new TypeError ( `Unknown token type: ${ ( token as any ) . type } ` ) ;
638
+ }
639
+
640
+ return value ;
641
+ }
642
+
643
+ /**
644
+ * Stringify token data into a path string.
645
+ */
646
+ export function stringify ( data : TokenData ) : string {
647
+ return stringifyTokens ( data . tokens ) ;
622
648
}
623
649
624
650
/**
625
651
* Validate the parameter name contains valid ID characters.
626
652
*/
627
- function isNameSafe ( name : string ) {
653
+ function isNameSafe ( name : string ) : boolean {
628
654
const [ first , ...rest ] = name ;
629
- if ( ! ID_START . test ( first ) ) return false ;
630
- return rest . every ( ( char ) => ID_CONTINUE . test ( char ) ) ;
655
+ return ID_START . test ( first ) && rest . every ( ( char ) => ID_CONTINUE . test ( char ) ) ;
631
656
}
632
657
633
658
/**
634
659
* Validate the next token does not interfere with the current param name.
635
660
*/
636
- function isNextNameSafe ( token : Token | undefined ) {
637
- if ( ! token || token . type !== "text" ) return true ;
638
- return ! ID_CONTINUE . test ( token . value [ 0 ] ) ;
661
+ function isNextNameSafe ( token : Token | undefined ) : boolean {
662
+ if ( token && token . type === "text" ) return ! ID_CONTINUE . test ( token . value [ 0 ] ) ;
663
+ return true ;
639
664
}
0 commit comments