@@ -112,6 +112,16 @@ function escape(str: string) {
112112 return str . replace ( / [ . + * ? ^ $ { } ( ) [ \] | / \\ ] / g, "\\$&" ) ;
113113}
114114
115+ /**
116+ * Format error so it's easier to debug.
117+ */
118+ function errorMessage ( message : string , originalPath : string | undefined ) {
119+ if ( originalPath ) {
120+ return `${ message } : ${ originalPath } ; visit ${ DEBUG_URL } for more info` ;
121+ }
122+ return `${ message } ; visit ${ DEBUG_URL } for more info` ;
123+ }
124+
115125/**
116126 * Tokenize input string.
117127 */
@@ -145,12 +155,16 @@ function* lexer(str: string): Generator<LexToken, LexToken> {
145155 }
146156
147157 if ( pos ) {
148- throw new TypeError ( `Unterminated quote at ${ pos } : ${ DEBUG_URL } ` ) ;
158+ throw new TypeError (
159+ errorMessage ( `Unterminated quote at index ${ pos } ` , str ) ,
160+ ) ;
149161 }
150162 }
151163
152164 if ( ! value ) {
153- throw new TypeError ( `Missing parameter name at ${ i } : ${ DEBUG_URL } ` ) ;
165+ throw new TypeError (
166+ errorMessage ( `Missing parameter name at index ${ i } ` , str ) ,
167+ ) ;
154168 }
155169
156170 return value ;
@@ -180,12 +194,15 @@ function* lexer(str: string): Generator<LexToken, LexToken> {
180194
181195class Iter {
182196 private _peek ?: LexToken ;
197+ private _tokens : Generator < LexToken , LexToken > ;
183198
184- constructor ( private tokens : Generator < LexToken , LexToken > ) { }
199+ constructor ( private originalPath : string ) {
200+ this . _tokens = lexer ( originalPath ) ;
201+ }
185202
186203 peek ( ) : LexToken {
187204 if ( ! this . _peek ) {
188- const next = this . tokens . next ( ) ;
205+ const next = this . _tokens . next ( ) ;
189206 this . _peek = next . value ;
190207 }
191208 return this . _peek ;
@@ -203,7 +220,10 @@ class Iter {
203220 if ( value !== undefined ) return value ;
204221 const { type : nextType , index } = this . peek ( ) ;
205222 throw new TypeError (
206- `Unexpected ${ nextType } at ${ index } , expected ${ type } : ${ DEBUG_URL } ` ,
223+ errorMessage (
224+ `Unexpected ${ nextType } at index ${ index } , expected ${ type } ` ,
225+ this . originalPath ,
226+ ) ,
207227 ) ;
208228 }
209229
@@ -268,15 +288,18 @@ export type Token = Text | Parameter | Wildcard | Group;
268288 * Tokenized path instance.
269289 */
270290export class TokenData {
271- constructor ( public readonly tokens : Token [ ] ) { }
291+ constructor (
292+ public readonly tokens : Token [ ] ,
293+ public readonly originalPath ?: string ,
294+ ) { }
272295}
273296
274297/**
275298 * Parse a string for the raw tokens.
276299 */
277300export function parse ( str : string , options : ParseOptions = { } ) : TokenData {
278301 const { encodePath = NOOP_VALUE } = options ;
279- const it = new Iter ( lexer ( str ) ) ;
302+ const it = new Iter ( str ) ;
280303
281304 function consume ( endType : TokenType ) : Token [ ] {
282305 const tokens : Token [ ] = [ ] ;
@@ -318,7 +341,7 @@ export function parse(str: string, options: ParseOptions = {}): TokenData {
318341 }
319342
320343 const tokens = consume ( "END" ) ;
321- return new TokenData ( tokens ) ;
344+ return new TokenData ( tokens , str ) ;
322345}
323346
324347/**
@@ -496,12 +519,8 @@ export function pathToRegexp(
496519 trailing = true ,
497520 } = options ;
498521 const keys : Keys = [ ] ;
499- const sources : string [ ] = [ ] ;
500522 const flags = sensitive ? "" : "i" ;
501-
502- for ( const seq of flat ( path , options ) ) {
503- sources . push ( toRegExp ( seq , delimiter , keys ) ) ;
504- }
523+ const sources = Array . from ( toRegExps ( path , delimiter , keys , options ) ) ;
505524
506525 let pattern = `^(?:${ sources . join ( "|" ) } )` ;
507526 if ( trailing ) pattern += `(?:${ escape ( delimiter ) } $)?` ;
@@ -511,35 +530,39 @@ export function pathToRegexp(
511530 return { regexp, keys } ;
512531}
513532
514- /**
515- * Flattened token set.
516- */
517- type Flattened = Text | Parameter | Wildcard ;
518-
519533/**
520534 * Path or array of paths to normalize.
521535 */
522- function * flat (
536+ function * toRegExps (
523537 path : Path | Path [ ] ,
538+ delimiter : string ,
539+ keys : Keys ,
524540 options : ParseOptions ,
525- ) : Generator < Flattened [ ] > {
541+ ) : Generator < string > {
526542 if ( Array . isArray ( path ) ) {
527- for ( const p of path ) yield * flat ( p , options ) ;
543+ for ( const p of path ) yield * toRegExps ( p , delimiter , keys , options ) ;
528544 return ;
529545 }
530546
531547 const data = path instanceof TokenData ? path : parse ( path , options ) ;
532- yield * flatten ( data . tokens , 0 , [ ] ) ;
548+ for ( const tokens of flatten ( data . tokens , 0 , [ ] ) ) {
549+ yield toRegExp ( tokens , delimiter , keys , data . originalPath ) ;
550+ }
533551}
534552
553+ /**
554+ * Flattened token set.
555+ */
556+ type FlatToken = Text | Parameter | Wildcard ;
557+
535558/**
536559 * Generate a flat list of sequence tokens from the given tokens.
537560 */
538561function * flatten (
539562 tokens : Token [ ] ,
540563 index : number ,
541- init : Flattened [ ] ,
542- ) : Generator < Flattened [ ] > {
564+ init : FlatToken [ ] ,
565+ ) : Generator < FlatToken [ ] > {
543566 if ( index === tokens . length ) {
544567 return yield init ;
545568 }
@@ -560,7 +583,12 @@ function* flatten(
560583/**
561584 * Transform a flat sequence of tokens into a regular expression.
562585 */
563- function toRegExp ( tokens : Flattened [ ] , delimiter : string , keys : Keys ) {
586+ function toRegExp (
587+ tokens : FlatToken [ ] ,
588+ delimiter : string ,
589+ keys : Keys ,
590+ originalPath : string | undefined ,
591+ ) {
564592 let result = "" ;
565593 let backtrack = "" ;
566594 let isSafeSegmentParam = true ;
@@ -575,7 +603,9 @@ function toRegExp(tokens: Flattened[], delimiter: string, keys: Keys) {
575603
576604 if ( token . type === "param" || token . type === "wildcard" ) {
577605 if ( ! isSafeSegmentParam && ! backtrack ) {
578- throw new TypeError ( `Missing text after "${ token . name } ": ${ DEBUG_URL } ` ) ;
606+ throw new TypeError (
607+ errorMessage ( `Missing text after "${ token . name } "` , originalPath ) ,
608+ ) ;
579609 }
580610
581611 if ( token . type === "param" ) {
0 commit comments