@@ -137,6 +137,10 @@ export interface ParseOptions {
137
137
* List of characters to automatically consider prefixes when parsing.
138
138
*/
139
139
prefixes ?: string ;
140
+ /**
141
+ * Function for encoding input strings for output into path.
142
+ */
143
+ encode ?: Encode ;
140
144
}
141
145
142
146
class Iter {
@@ -178,11 +182,15 @@ class Iter {
178
182
* Parse a string for the raw tokens.
179
183
*/
180
184
export function parse ( str : string , options : ParseOptions = { } ) : Token [ ] {
181
- const { prefixes = DEFAULT_PREFIXES , delimiter = DEFAULT_DELIMITER } =
182
- options ;
183
- const defaultPattern = `[^${ escapeString ( delimiter ) } ]+?` ;
185
+ const {
186
+ prefixes = DEFAULT_PREFIXES ,
187
+ delimiter = DEFAULT_DELIMITER ,
188
+ encode = DEFAULT_ENCODE ,
189
+ } = options ;
190
+ const defaultPattern = `[^${ escape ( delimiter ) } ]+?` ;
184
191
const result : Token [ ] = [ ] ;
185
192
const tokens = lexer ( str ) ;
193
+ const stringify = encoder ( delimiter , encode ) ;
186
194
let key = 0 ;
187
195
let path = "" ;
188
196
@@ -207,7 +215,7 @@ export function parse(str: string, options: ParseOptions = {}): Token[] {
207
215
208
216
result . push ( {
209
217
name : name || key ++ ,
210
- prefix,
218
+ prefix : stringify ( prefix ) ,
211
219
suffix : "" ,
212
220
pattern : pattern || defaultPattern ,
213
221
modifier : modifier || "" ,
@@ -222,7 +230,7 @@ export function parse(str: string, options: ParseOptions = {}): Token[] {
222
230
}
223
231
224
232
if ( path ) {
225
- result . push ( path ) ;
233
+ result . push ( stringify ( path ) ) ;
226
234
path = "" ;
227
235
}
228
236
@@ -238,8 +246,8 @@ export function parse(str: string, options: ParseOptions = {}): Token[] {
238
246
result . push ( {
239
247
name : name || ( pattern ? key ++ : "" ) ,
240
248
pattern : name && ! pattern ? defaultPattern : pattern ,
241
- prefix,
242
- suffix,
249
+ prefix : stringify ( prefix ) ,
250
+ suffix : stringify ( suffix ) ,
243
251
modifier : tokens . tryConsume ( "MODIFIER" ) || "" ,
244
252
} ) ;
245
253
continue ;
@@ -252,19 +260,21 @@ export function parse(str: string, options: ParseOptions = {}): Token[] {
252
260
return result ;
253
261
}
254
262
263
+ export type Encode = ( value : string ) => string ;
264
+
255
265
export interface TokensToFunctionOptions {
256
266
/**
257
267
* When `true` the regexp will be case sensitive. (default: `false`)
258
268
*/
259
269
sensitive ?: boolean ;
260
- /**
261
- * Function for encoding input strings for output.
262
- */
263
- encode ?: ( value : string , token : Key ) => string ;
264
270
/**
265
271
* When `false` the function can produce an invalid (unmatched) path. (default: `true`)
266
272
*/
267
273
validate ?: boolean ;
274
+ /**
275
+ * Function for encoding input strings for output.
276
+ */
277
+ encode ?: Encode ;
268
278
}
269
279
270
280
/**
@@ -325,7 +335,7 @@ export function tokensToFunction<P extends object = object>(
325
335
}
326
336
327
337
for ( let j = 0 ; j < value . length ; j ++ ) {
328
- const segment = encode ( value [ j ] , token ) ;
338
+ const segment = encode ( value [ j ] ) ;
329
339
330
340
if ( validate && ! ( matches [ i ] as RegExp ) . test ( segment ) ) {
331
341
throw new TypeError (
@@ -340,7 +350,7 @@ export function tokensToFunction<P extends object = object>(
340
350
}
341
351
342
352
if ( typeof value === "string" || typeof value === "number" ) {
343
- const segment = encode ( String ( value ) , token ) ;
353
+ const segment = encode ( String ( value ) ) ;
344
354
345
355
if ( validate && ! ( matches [ i ] as RegExp ) . test ( segment ) ) {
346
356
throw new TypeError (
@@ -440,10 +450,18 @@ export function regexpToFunction<P extends object = object>(
440
450
/**
441
451
* Escape a regular expression string.
442
452
*/
443
- function escapeString ( str : string ) {
453
+ function escape ( str : string ) {
444
454
return str . replace ( / ( [ . + * ? = ^ ! : $ { } ( ) [ \] | / \\ ] ) / g, "\\$1" ) ;
445
455
}
446
456
457
+ /**
458
+ * Encode all non-delimiter characters using the encode function.
459
+ */
460
+ function encoder ( delimiter : string , encode : Encode ) {
461
+ const re = new RegExp ( `[^${ escape ( delimiter ) } ]+` , "g" ) ;
462
+ return ( value : string ) => value . replace ( re , encode ) ;
463
+ }
464
+
447
465
/**
448
466
* Get the flags for a regexp from the options.
449
467
*/
@@ -538,10 +556,6 @@ export interface TokensToRegexpOptions {
538
556
* List of characters that can also be "end" characters.
539
557
*/
540
558
endsWith ?: string ;
541
- /**
542
- * Encode path tokens for use in the `RegExp`.
543
- */
544
- encode ?: ( value : string ) => string ;
545
559
}
546
560
547
561
/**
@@ -556,21 +570,20 @@ export function tokensToRegexp(
556
570
strict = false ,
557
571
start = true ,
558
572
end = true ,
559
- encode = DEFAULT_ENCODE ,
560
573
delimiter = DEFAULT_DELIMITER ,
561
574
endsWith = "" ,
562
575
} = options ;
563
- const endsWithRe = `[${ escapeString ( endsWith ) } ]|$` ;
564
- const delimiterRe = `[${ escapeString ( delimiter ) } ]` ;
576
+ const endsWithRe = `[${ escape ( endsWith ) } ]|$` ;
577
+ const delimiterRe = `[${ escape ( delimiter ) } ]` ;
565
578
let route = start ? "^" : "" ;
566
579
567
580
// Iterate over the tokens and create our regexp string.
568
581
for ( const token of tokens ) {
569
582
if ( typeof token === "string" ) {
570
- route += escapeString ( encode ( token ) ) ;
583
+ route += escape ( token ) ;
571
584
} else {
572
- const prefix = escapeString ( encode ( token . prefix ) ) ;
573
- const suffix = escapeString ( encode ( token . suffix ) ) ;
585
+ const prefix = escape ( token . prefix ) ;
586
+ const suffix = escape ( token . suffix ) ;
574
587
575
588
if ( token . pattern ) {
576
589
if ( keys ) keys . push ( token ) ;
0 commit comments