@@ -333,8 +333,8 @@ export function compile<P extends ParamData = ParamData>(
333
333
const data = path instanceof TokenData ? path : parse ( path , options ) ;
334
334
const fn = tokensToFunction ( data . tokens , delimiter , encode ) ;
335
335
336
- return function path ( data : P = { } as P ) {
337
- const [ path , ...missing ] = fn ( data ) ;
336
+ return function path ( params : P = { } as P ) {
337
+ const [ path , ...missing ] = fn ( params ) ;
338
338
if ( missing . length ) {
339
339
throw new TypeError ( `Missing parameters: ${ missing . join ( ", " ) } ` ) ;
340
340
}
@@ -498,16 +498,9 @@ export function pathToRegexp(
498
498
const keys : Keys = [ ] ;
499
499
const sources : string [ ] = [ ] ;
500
500
const flags = sensitive ? "" : "i" ;
501
- const paths = Array . isArray ( path ) ? path : [ path ] ;
502
- const items = paths . map ( ( path ) =>
503
- path instanceof TokenData ? path : parse ( path , options ) ,
504
- ) ;
505
501
506
- for ( const { tokens } of items ) {
507
- for ( const seq of flatten ( tokens , 0 , [ ] ) ) {
508
- const regexp = sequenceToRegExp ( seq , delimiter , keys ) ;
509
- sources . push ( regexp ) ;
510
- }
502
+ for ( const seq of flat ( path , options ) ) {
503
+ sources . push ( toRegExp ( seq , delimiter , keys ) ) ;
511
504
}
512
505
513
506
let pattern = `^(?:${ sources . join ( "|" ) } )` ;
@@ -523,6 +516,22 @@ export function pathToRegexp(
523
516
*/
524
517
type Flattened = Text | Parameter | Wildcard ;
525
518
519
+ /**
520
+ * Path or array of paths to normalize.
521
+ */
522
+ function * flat (
523
+ path : Path | Path [ ] ,
524
+ options : ParseOptions ,
525
+ ) : Generator < Flattened [ ] > {
526
+ if ( Array . isArray ( path ) ) {
527
+ for ( const p of path ) yield * flat ( p , options ) ;
528
+ return ;
529
+ }
530
+
531
+ const data = path instanceof TokenData ? path : parse ( path , options ) ;
532
+ yield * flatten ( data . tokens , 0 , [ ] ) ;
533
+ }
534
+
526
535
/**
527
536
* Generate a flat list of sequence tokens from the given tokens.
528
537
*/
@@ -538,8 +547,7 @@ function* flatten(
538
547
const token = tokens [ index ] ;
539
548
540
549
if ( token . type === "group" ) {
541
- const fork = init . slice ( ) ;
542
- for ( const seq of flatten ( token . tokens , 0 , fork ) ) {
550
+ for ( const seq of flatten ( token . tokens , 0 , init . slice ( ) ) ) {
543
551
yield * flatten ( tokens , index + 1 , seq ) ;
544
552
}
545
553
} else {
@@ -552,14 +560,12 @@ function* flatten(
552
560
/**
553
561
* Transform a flat sequence of tokens into a regular expression.
554
562
*/
555
- function sequenceToRegExp ( tokens : Flattened [ ] , delimiter : string , keys : Keys ) {
563
+ function toRegExp ( tokens : Flattened [ ] , delimiter : string , keys : Keys ) {
556
564
let result = "" ;
557
565
let backtrack = "" ;
558
566
let isSafeSegmentParam = true ;
559
567
560
- for ( let i = 0 ; i < tokens . length ; i ++ ) {
561
- const token = tokens [ i ] ;
562
-
568
+ for ( const token of tokens ) {
563
569
if ( token . type === "text" ) {
564
570
result += escape ( token . value ) ;
565
571
backtrack += token . value ;
@@ -588,6 +594,9 @@ function sequenceToRegExp(tokens: Flattened[], delimiter: string, keys: Keys) {
588
594
return result ;
589
595
}
590
596
597
+ /**
598
+ * Block backtracking on previous text and ignore delimiter string.
599
+ */
591
600
function negate ( delimiter : string , backtrack : string ) {
592
601
if ( backtrack . length < 2 ) {
593
602
if ( delimiter . length < 2 ) return `[^${ escape ( delimiter + backtrack ) } ]` ;
@@ -621,12 +630,18 @@ export function stringify(data: TokenData) {
621
630
. join ( "" ) ;
622
631
}
623
632
633
+ /**
634
+ * Validate the parameter name contains valid ID characters.
635
+ */
624
636
function isNameSafe ( name : string ) {
625
637
const [ first , ...rest ] = name ;
626
638
if ( ! ID_START . test ( first ) ) return false ;
627
639
return rest . every ( ( char ) => ID_CONTINUE . test ( char ) ) ;
628
640
}
629
641
642
+ /**
643
+ * Validate the next token does not interfere with the current param name.
644
+ */
630
645
function isNextNameSafe ( token : Token | undefined ) {
631
646
if ( ! token || token . type !== "text" ) return true ;
632
647
return ! ID_CONTINUE . test ( token . value [ 0 ] ) ;
0 commit comments