@@ -58,33 +58,6 @@ export interface CompileOptions {
5858 delimiter ?: string ;
5959}
6060
61- type TokenType =
62- | "{"
63- | "}"
64- | "wildcard"
65- | "param"
66- | "char"
67- | "end"
68- // Reserved for use or ambiguous due to past use.
69- | "("
70- | ")"
71- | "["
72- | "]"
73- | "+"
74- | "?"
75- | "!" ;
76-
77- /**
78- * Tokenizer results.
79- */
80- interface LexToken {
81- type : TokenType ;
82- index : number ;
83- value : string ;
84- }
85-
86- const SIMPLE_TOKENS = "{}()[]+?!" ;
87-
8861/**
8962 * Escape text for stringify to path.
9063 */
@@ -177,116 +150,116 @@ export class PathError extends TypeError {
177150export function parse ( str : string , options : ParseOptions = { } ) : TokenData {
178151 const { encodePath = NOOP_VALUE } = options ;
179152 const chars = [ ...str ] ;
180- const tokens : Array < LexToken > = [ ] ;
181153 let index = 0 ;
182- let pos = 0 ;
183-
184- function name ( ) {
185- let value = "" ;
186-
187- if ( ID_START . test ( chars [ index ] ) ) {
188- do {
189- value += chars [ index ++ ] ;
190- } while ( ID_CONTINUE . test ( chars [ index ] ) ) ;
191- } else if ( chars [ index ] === '"' ) {
192- let quoteStart = index ;
193-
194- while ( index < chars . length ) {
195- if ( chars [ ++ index ] === '"' ) {
196- index ++ ;
197- quoteStart = 0 ;
198- break ;
199- }
200-
201- // Increment over escape characters.
202- if ( chars [ index ] === "\\" ) index ++ ;
203154
204- value += chars [ index ] ;
205- }
206-
207- if ( quoteStart ) {
208- throw new PathError ( `Unterminated quote at index ${ quoteStart } ` , str ) ;
209- }
210- }
211-
212- if ( ! value ) {
213- throw new PathError ( `Missing parameter name at index ${ index } ` , str ) ;
155+ function consumeUntil ( end : string ) : Token [ ] {
156+ const output : Token [ ] = [ ] ;
157+ let path = "" ;
158+
159+ function writePath ( ) {
160+ if ( ! path ) return ;
161+ output . push ( {
162+ type : "text" ,
163+ value : encodePath ( path ) ,
164+ } ) ;
165+ path = "" ;
214166 }
215167
216- return value ;
217- }
218-
219- while ( index < chars . length ) {
220- const value = chars [ index ++ ] ;
168+ while ( index < chars . length ) {
169+ const value = chars [ index ++ ] ;
221170
222- if ( value === "\\" ) {
223- if ( index === chars . length ) {
224- throw new PathError ( `Unexpected end after \\ at index ${ index } ` , str ) ;
171+ if ( value === end ) {
172+ writePath ( ) ;
173+ return output ;
225174 }
226175
227- tokens . push ( { type : "char" , index, value : chars [ index ++ ] } ) ;
228- } else if ( SIMPLE_TOKENS . includes ( value ) ) {
229- tokens . push ( { type : value as TokenType , index, value } ) ;
230- } else if ( value === ":" ) {
231- tokens . push ( { type : "param" , index, value : name ( ) } ) ;
232- } else if ( value === "*" ) {
233- tokens . push ( { type : "wildcard" , index, value : name ( ) } ) ;
234- } else {
235- tokens . push ( { type : "char" , index, value } ) ;
236- }
237- }
176+ if ( value === "\\" ) {
177+ if ( index === chars . length ) {
178+ throw new PathError ( `Unexpected end after \\ at index ${ index } ` , str ) ;
179+ }
238180
239- tokens . push ( { type : "end" , index, value : "" } ) ;
181+ path += chars [ index ++ ] ;
182+ continue ;
183+ }
240184
241- function consumeUntil ( endType : TokenType ) : Token [ ] {
242- const output : Token [ ] = [ ] ;
185+ if ( value === ":" || value === "*" ) {
186+ const type = value === ":" ? "param" : "wildcard" ;
187+ let name = "" ;
188+
189+ if ( ID_START . test ( chars [ index ] ) ) {
190+ do {
191+ name += chars [ index ++ ] ;
192+ } while ( ID_CONTINUE . test ( chars [ index ] ) ) ;
193+ } else if ( chars [ index ] === '"' ) {
194+ let quoteStart = index ;
195+
196+ while ( index < chars . length ) {
197+ if ( chars [ ++ index ] === '"' ) {
198+ index ++ ;
199+ quoteStart = 0 ;
200+ break ;
201+ }
243202
244- while ( true ) {
245- const token = tokens [ pos ++ ] ;
246- if ( token . type === endType ) break ;
203+ // Increment over escape characters.
204+ if ( chars [ index ] === "\\" ) index ++ ;
247205
248- if ( token . type === "char" ) {
249- let path = token . value ;
250- let cur = tokens [ pos ] ;
206+ name += chars [ index ] ;
207+ }
251208
252- while ( cur . type === "char" ) {
253- path += cur . value ;
254- cur = tokens [ ++ pos ] ;
209+ if ( quoteStart ) {
210+ throw new PathError (
211+ `Unterminated quote at index ${ quoteStart } ` ,
212+ str ,
213+ ) ;
214+ }
255215 }
256216
257- output . push ( {
258- type : "text" ,
259- value : encodePath ( path ) ,
260- } ) ;
261- continue ;
262- }
217+ if ( ! name ) {
218+ throw new PathError ( `Missing parameter name at index ${ index } ` , str ) ;
219+ }
263220
264- if ( token . type === "param" || token . type === "wildcard" ) {
265- output . push ( {
266- type : token . type ,
267- name : token . value ,
268- } ) ;
221+ writePath ( ) ;
222+ output . push ( { type, name } ) ;
269223 continue ;
270224 }
271225
272- if ( token . type === "{" ) {
226+ if ( value === "{" ) {
227+ writePath ( ) ;
273228 output . push ( {
274229 type : "group" ,
275230 tokens : consumeUntil ( "}" ) ,
276231 } ) ;
277232 continue ;
278233 }
279234
235+ if (
236+ value === "}" ||
237+ value === "(" ||
238+ value === ")" ||
239+ value === "[" ||
240+ value === "]" ||
241+ value === "+" ||
242+ value === "?" ||
243+ value === "!"
244+ ) {
245+ throw new PathError ( `Unexpected ${ value } at index ${ index - 1 } ` , str ) ;
246+ }
247+
248+ path += value ;
249+ }
250+
251+ if ( end ) {
280252 throw new PathError (
281- `Unexpected ${ token . type } at index ${ token . index } , expected ${ endType } ` ,
253+ `Unexpected end at index ${ index } , expected ${ end } ` ,
282254 str ,
283255 ) ;
284256 }
285257
258+ writePath ( ) ;
286259 return output ;
287260 }
288261
289- return new TokenData ( consumeUntil ( "end " ) , str ) ;
262+ return new TokenData ( consumeUntil ( "" ) , str ) ;
290263}
291264
292265/**
@@ -537,7 +510,7 @@ function toRegExpSource(
537510 let hasSegmentCapture = 0 ;
538511 let index = 0 ;
539512
540- function hasInSegment ( index : number , type : TokenType ) {
513+ function hasInSegment ( index : number , type : Token [ "type" ] ) {
541514 while ( index < tokens . length ) {
542515 const token = tokens [ index ++ ] ;
543516 if ( token . type === type ) return true ;
0 commit comments