@@ -487,7 +487,7 @@ export function pathToRegexp(
487487 for ( const input of pathsToArray ( path , [ ] ) ) {
488488 const data = typeof input === "object" ? input : parse ( input , options ) ;
489489 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 ) ) ;
491491 }
492492 }
493493
@@ -544,12 +544,12 @@ function* flatten(
544544/**
545545 * Transform a flat sequence of tokens into a regular expression.
546546 */
547- function toRegExp (
547+ function toRegExpSource (
548548 tokens : FlatToken [ ] ,
549549 delimiter : string ,
550550 keys : Keys ,
551551 originalPath : string | undefined ,
552- ) {
552+ ) : string {
553553 let result = "" ;
554554 let backtrack = "" ;
555555 let isSafeSegmentParam = true ;
@@ -588,7 +588,7 @@ function toRegExp(
588588/**
589589 * Block backtracking on previous text and ignore delimiter string.
590590 */
591- function negate ( delimiter : string , backtrack : string ) {
591+ function negate ( delimiter : string , backtrack : string ) : string {
592592 if ( backtrack . length < 2 ) {
593593 if ( delimiter . length < 2 ) return `[^${ escape ( delimiter + backtrack ) } ]` ;
594594 return `(?:(?!${ escape ( delimiter ) } )[^${ escape ( backtrack ) } ])` ;
@@ -600,40 +600,65 @@ function negate(delimiter: string, backtrack: string) {
600600}
601601
602602/**
603- * Stringify token data into a path string.
603+ * Stringify an array of tokens into a path string.
604604 */
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 ;
612608
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+ }
616613
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 ) ;
622648}
623649
624650/**
625651 * Validate the parameter name contains valid ID characters.
626652 */
627- function isNameSafe ( name : string ) {
653+ function isNameSafe ( name : string ) : boolean {
628654 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 ) ) ;
631656}
632657
633658/**
634659 * Validate the next token does not interfere with the current param name.
635660 */
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 ;
639664}
0 commit comments