path-to-regexp 6.2.2 → 7.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Readme.md CHANGED
@@ -16,59 +16,55 @@ npm install path-to-regexp --save
16
16
 
17
17
  ## Usage
18
18
 
19
- ```javascript
19
+ ```js
20
20
  const { pathToRegexp, match, parse, compile } = require("path-to-regexp");
21
21
 
22
- // pathToRegexp(path, keys?, options?)
23
- // match(path)
24
- // parse(path)
25
- // compile(path)
22
+ // pathToRegexp(path, options?)
23
+ // match(path, options?)
24
+ // parse(path, options?)
25
+ // compile(path, options?)
26
26
  ```
27
27
 
28
28
  ### Path to regexp
29
29
 
30
- The `pathToRegexp` function will return a regular expression object based on the provided `path` argument. It accepts the following arguments:
30
+ The `pathToRegexp` function returns a regular expression with `keys` as a property. It accepts the following arguments:
31
31
 
32
- - **path** A string, array of strings, or a regular expression.
33
- - **keys** _(optional)_ An array to populate with keys found in the path.
32
+ - **path** A string.
34
33
  - **options** _(optional)_
35
- - **sensitive** When `true` the regexp will be case sensitive. (default: `false`)
36
- - **strict** When `true` the regexp won't allow an optional trailing delimiter to match. (default: `false`)
37
- - **end** When `true` the regexp will match to the end of the string. (default: `true`)
38
- - **start** When `true` the regexp will match from the beginning of the string. (default: `true`)
39
- - **delimiter** The default delimiter for segments, e.g. `[^/#?]` for `:named` patterns. (default: `'/#?'`)
40
- - **endsWith** Optional character, or list of characters, to treat as "end" characters.
41
- - **encode** A function to encode strings before inserting into `RegExp`. (default: `x => x`)
42
- - **prefixes** List of characters to automatically consider prefixes when parsing. (default: `./`)
43
-
44
- ```javascript
45
- const keys = [];
46
- const regexp = pathToRegexp("/foo/:bar", keys);
47
- // regexp = /^\/foo(?:\/([^\/#\?]+?))[\/#\?]?$/i
48
- // keys = [{ name: 'bar', prefix: '/', suffix: '', pattern: '[^\\/#\\?]+?', modifier: '' }]
34
+ - **sensitive** Regexp will be case sensitive. (default: `false`)
35
+ - **trailing** Allows optional trailing delimiter to match. (default: `true`)
36
+ - **strict** Verify patterns are valid and safe to use. (default: `false`, recommended: `true`)
37
+ - **end** Match to the end of the string. (default: `true`)
38
+ - **start** Match from the beginning of the string. (default: `true`)
39
+ - **loose** Allow the delimiter to be arbitrarily repeated, e.g. `/` or `///`. (default: `true`)
40
+ - **delimiter** The default delimiter for segments, e.g. `[^/]` for `:named` parameters. (default: `'/'`)
41
+ - **encodePath** A function for encoding input strings. (default: `x => x`, recommended: [`encodeurl`](https://github.com/pillarjs/encodeurl) for unicode encoding)
42
+
43
+ ```js
44
+ const regexp = pathToRegexp("/foo/:bar");
45
+ // regexp = /^\/+foo(?:\/+([^\/]+?))(?:\/+)?$/i
46
+ // keys = [{ name: 'bar', prefix: '', suffix: '', pattern: '', modifier: '' }]
49
47
  ```
50
48
 
51
- **Please note:** The `RegExp` returned by `path-to-regexp` is intended for ordered data (e.g. pathnames, hostnames). It can not handle arbitrarily ordered data (e.g. query strings, URL fragments, JSON, etc). When using paths that contain query strings, you need to escape the question mark (`?`) to ensure it does not flag the parameter as [optional](#optional).
49
+ **Please note:** The `RegExp` returned by `path-to-regexp` is intended for ordered data (e.g. pathnames, hostnames). It can not handle arbitrarily ordered data (e.g. query strings, URL fragments, JSON, etc).
52
50
 
53
51
  ### Parameters
54
52
 
55
53
  The path argument is used to define parameters and populate keys.
56
54
 
57
- #### Named Parameters
55
+ #### Named parameters
58
56
 
59
- Named parameters are defined by prefixing a colon to the parameter name (`:foo`).
57
+ Named parameters are defined by prefixing a colon to the parameter name (`:foo`). Parameter names can use any valid unicode identifier characters (similar to JavaScript).
60
58
 
61
59
  ```js
62
60
  const regexp = pathToRegexp("/:foo/:bar");
63
- // keys = [{ name: 'foo', prefix: '/', ... }, { name: 'bar', prefix: '/', ... }]
61
+ // keys = [{ name: 'foo', ... }, { name: 'bar', ... }]
64
62
 
65
63
  regexp.exec("/test/route");
66
- //=> [ '/test/route', 'test', 'route', index: 0, input: '/test/route', groups: undefined ]
64
+ //=> [ '/test/route', 'test', 'route', index: 0 ]
67
65
  ```
68
66
 
69
- **Please note:** Parameter names must use "word characters" (`[A-Za-z0-9_]`).
70
-
71
- ##### Custom Matching Parameters
67
+ ##### Custom matching parameters
72
68
 
73
69
  Parameters can have a custom regexp, which overrides the default match (`[^/]+`). For example, you can match digits or names in a path:
74
70
 
@@ -94,64 +90,49 @@ regexpWord.exec("/users");
94
90
 
95
91
  **Tip:** Backslashes need to be escaped with another backslash in JavaScript strings.
96
92
 
97
- ##### Custom Prefix and Suffix
93
+ #### Unnamed parameters
98
94
 
99
- Parameters can be wrapped in `{}` to create custom prefixes or suffixes for your segment:
95
+ It is possible to define a parameter without a name. The name will be numerically indexed:
100
96
 
101
97
  ```js
102
- const regexp = pathToRegexp("/:attr1?{-:attr2}?{-:attr3}?");
103
-
104
- regexp.exec("/test");
105
- // => ['/test', 'test', undefined, undefined]
98
+ const regexp = pathToRegexp("/:foo/(.*)");
99
+ // keys = [{ name: 'foo', ... }, { name: '0', ... }]
106
100
 
107
- regexp.exec("/test-test");
108
- // => ['/test', 'test', 'test', undefined]
101
+ regexp.exec("/test/route");
102
+ //=> [ '/test/route', 'test', 'route', index: 0 ]
109
103
  ```
110
104
 
111
- #### Unnamed Parameters
105
+ ##### Custom prefix and suffix
112
106
 
113
- It is possible to write an unnamed parameter that only consists of a regexp. It works the same the named parameter, except it will be numerically indexed:
107
+ Parameters can be wrapped in `{}` to create custom prefixes or suffixes for your segment:
114
108
 
115
109
  ```js
116
- const regexp = pathToRegexp("/:foo/(.*)");
117
- // keys = [{ name: 'foo', ... }, { name: 0, ... }]
110
+ const regexp = pathToRegexp("{/:attr1}?{-:attr2}?{-:attr3}?");
118
111
 
119
- regexp.exec("/test/route");
120
- //=> [ '/test/route', 'test', 'route', index: 0, input: '/test/route', groups: undefined ]
112
+ regexp.exec("/test");
113
+ // => ['/test', 'test', undefined, undefined]
114
+
115
+ regexp.exec("/test-test");
116
+ // => ['/test', 'test', 'test', undefined]
121
117
  ```
122
118
 
123
119
  #### Modifiers
124
120
 
125
- Modifiers must be placed after the parameter (e.g. `/:foo?`, `/(test)?`, `/:foo(test)?`, or `{-:foo(test)}?`).
121
+ Modifiers are used after parameters with custom prefixes and suffixes (`{}`).
126
122
 
127
123
  ##### Optional
128
124
 
129
125
  Parameters can be suffixed with a question mark (`?`) to make the parameter optional.
130
126
 
131
127
  ```js
132
- const regexp = pathToRegexp("/:foo/:bar?");
128
+ const regexp = pathToRegexp("/:foo{/:bar}?");
133
129
  // keys = [{ name: 'foo', ... }, { name: 'bar', prefix: '/', modifier: '?' }]
134
130
 
135
131
  regexp.exec("/test");
136
- //=> [ '/test', 'test', undefined, index: 0, input: '/test', groups: undefined ]
132
+ //=> [ '/test', 'test', undefined, index: 0 ]
137
133
 
138
134
  regexp.exec("/test/route");
139
- //=> [ '/test/route', 'test', 'route', index: 0, input: '/test/route', groups: undefined ]
140
- ```
141
-
142
- **Tip:** The prefix is also optional, escape the prefix `\/` to make it required.
143
-
144
- When dealing with query strings, escape the question mark (`?`) so it doesn't mark the parameter as optional. Handling unordered data is outside the scope of this library.
145
-
146
- ```js
147
- const regexp = pathToRegexp("/search/:tableName\\?useIndex=true&term=amazing");
148
-
149
- regexp.exec("/search/people?useIndex=true&term=amazing");
150
- //=> [ '/search/people?useIndex=true&term=amazing', 'people', index: 0, input: '/search/people?useIndex=true&term=amazing', groups: undefined ]
151
-
152
- // This library does not handle query strings in different orders
153
- regexp.exec("/search/people?term=amazing&useIndex=true");
154
- //=> null
135
+ //=> [ '/test/route', 'test', 'route', index: 0 ]
155
136
  ```
156
137
 
157
138
  ##### Zero or more
@@ -159,14 +140,14 @@ regexp.exec("/search/people?term=amazing&useIndex=true");
159
140
  Parameters can be suffixed with an asterisk (`*`) to denote a zero or more parameter matches.
160
141
 
161
142
  ```js
162
- const regexp = pathToRegexp("/:foo*");
143
+ const regexp = pathToRegexp("{/:foo}*");
163
144
  // keys = [{ name: 'foo', prefix: '/', modifier: '*' }]
164
145
 
165
- regexp.exec("/");
166
- //=> [ '/', undefined, index: 0, input: '/', groups: undefined ]
146
+ regexp.exec("/foo");
147
+ //=> [ '/foo', "foo", index: 0 ]
167
148
 
168
149
  regexp.exec("/bar/baz");
169
- //=> [ '/bar/baz', 'bar/baz', index: 0, input: '/bar/baz', groups: undefined ]
150
+ //=> [ '/bar/baz', 'bar/baz', index: 0 ]
170
151
  ```
171
152
 
172
153
  ##### One or more
@@ -174,165 +155,159 @@ regexp.exec("/bar/baz");
174
155
  Parameters can be suffixed with a plus sign (`+`) to denote a one or more parameter matches.
175
156
 
176
157
  ```js
177
- const regexp = pathToRegexp("/:foo+");
158
+ const regexp = pathToRegexp("{/:foo}+");
178
159
  // keys = [{ name: 'foo', prefix: '/', modifier: '+' }]
179
160
 
180
161
  regexp.exec("/");
181
162
  //=> null
182
163
 
183
164
  regexp.exec("/bar/baz");
184
- //=> [ '/bar/baz','bar/baz', index: 0, input: '/bar/baz', groups: undefined ]
165
+ //=> [ '/bar/baz', 'bar/baz', index: 0 ]
185
166
  ```
186
167
 
187
- ### Match
168
+ ##### Custom separator
188
169
 
189
- The `match` function will return a function for transforming paths into parameters:
170
+ By default, parameters set the separator as the `prefix + suffix` of the token. Using `;` you can modify this:
190
171
 
191
172
  ```js
192
- // Make sure you consistently `decode` segments.
193
- const fn = match("/user/:id", { decode: decodeURIComponent });
173
+ const regexp = pathToRegexp("/name{/:parts;-}+");
194
174
 
195
- fn("/user/123"); //=> { path: '/user/123', index: 0, params: { id: '123' } }
196
- fn("/invalid"); //=> false
197
- fn("/user/caf%C3%A9"); //=> { path: '/user/caf%C3%A9', index: 0, params: { id: 'café' } }
175
+ regexp.exec("/name");
176
+ //=> null
177
+
178
+ regexp.exec("/bar/1-2-3");
179
+ //=> [ '/name/1-2-3', '1-2-3', index: 0 ]
198
180
  ```
199
181
 
200
- The `match` function can be used to custom match named parameters. For example, this can be used to whitelist a small number of valid paths:
182
+ #### Wildcard
201
183
 
202
- ```js
203
- const urlMatch = match("/users/:id/:tab(home|photos|bio)", {
204
- decode: decodeURIComponent,
205
- });
184
+ A wildcard can also be used. It is roughly equivalent to `(.*)`.
206
185
 
207
- urlMatch("/users/1234/photos");
208
- //=> { path: '/users/1234/photos', index: 0, params: { id: '1234', tab: 'photos' } }
186
+ ```js
187
+ const regexp = pathToRegexp("/*");
188
+ // keys = [{ name: '0', pattern: '[^\\/]*', separator: '/', modifier: '*' }]
209
189
 
210
- urlMatch("/users/1234/bio");
211
- //=> { path: '/users/1234/bio', index: 0, params: { id: '1234', tab: 'bio' } }
190
+ regexp.exec("/");
191
+ //=> [ '/', '', index: 0 ]
212
192
 
213
- urlMatch("/users/1234/otherstuff");
214
- //=> false
193
+ regexp.exec("/bar/baz");
194
+ //=> [ '/bar/baz', 'bar/baz', index: 0 ]
215
195
  ```
216
196
 
217
- #### Process Pathname
197
+ ### Match
198
+
199
+ The `match` function returns a function for transforming paths into parameters:
218
200
 
219
- You should make sure variations of the same path match the expected `path`. Here's one possible solution using `encode`:
201
+ - **path** A string.
202
+ - **options** _(optional)_ The same options as `pathToRegexp`, plus:
203
+ - **decode** Function for decoding strings for params, or `false` to disable entirely. (default: `decodeURIComponent`)
220
204
 
221
205
  ```js
222
- const fn = match("/café", { encode: encodeURI });
206
+ const fn = match("/user/:id");
223
207
 
224
- fn("/caf%C3%A9"); //=> { path: '/caf%C3%A9', index: 0, params: {} }
208
+ fn("/user/123"); //=> { path: '/user/123', index: 0, params: { id: '123' } }
209
+ fn("/invalid"); //=> false
210
+ fn("/user/caf%C3%A9"); //=> { path: '/user/caf%C3%A9', index: 0, params: { id: 'café' } }
225
211
  ```
226
212
 
227
- **Note:** [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) encodes paths, so `/café` would be normalized to `/caf%C3%A9` and match in the above example.
213
+ **Note:** Setting `decode: false` disables the "splitting" behavior of repeated parameters, which is useful if you need the exactly matched parameter back.
214
+
215
+ ### Compile ("Reverse" Path-To-RegExp)
228
216
 
229
- ##### Alternative Using Normalize
217
+ The `compile` function will return a function for transforming parameters into a valid path:
230
218
 
231
- Sometimes you won't have already normalized paths to use, so you could normalize it yourself before matching:
219
+ - **path** A string.
220
+ - **options** _(optional)_ Similar to `pathToRegexp` (`delimiter`, `encodePath`, `sensitive`, and `loose`), plus:
221
+ - **validate** When `false` the function can produce an invalid (unmatched) path. (default: `true`)
222
+ - **encode** Function for encoding input strings for output into the path, or `false` to disable entirely. (default: `encodeURIComponent`)
232
223
 
233
224
  ```js
234
- /**
235
- * Normalize a pathname for matching, replaces multiple slashes with a single
236
- * slash and normalizes unicode characters to "NFC". When using this method,
237
- * `decode` should be an identity function so you don't decode strings twice.
238
- */
239
- function normalizePathname(pathname: string) {
240
- return (
241
- decodeURI(pathname)
242
- // Replaces repeated slashes in the URL.
243
- .replace(/\/+/g, "/")
244
- // Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
245
- // Note: Missing native IE support, may want to skip this step.
246
- .normalize()
247
- );
248
- }
249
-
250
- // Two possible ways of writing `/café`:
251
- const re = pathToRegexp("/caf\u00E9");
252
- const input = encodeURI("/cafe\u0301");
253
-
254
- re.test(input); //=> false
255
- re.test(normalizePathname(input)); //=> true
256
- ```
225
+ const toPath = compile("/user/:id");
257
226
 
258
- ### Parse
227
+ toPath({ id: "name" }); //=> "/user/name"
228
+ toPath({ id: "café" }); //=> "/user/caf%C3%A9"
259
229
 
260
- The `parse` function will return a list of strings and keys from a path string:
230
+ // When disabling `encode`, you need to make sure inputs are encoded correctly. No arrays are accepted.
231
+ const toPathRaw = compile("/user/:id", { encode: false });
261
232
 
262
- ```js
263
- const tokens = parse("/route/:foo/(.*)");
233
+ toPathRaw({ id: "%3A%2F" }); //=> "/user/%3A%2F"
234
+ toPathRaw({ id: ":/" }); //=> Throws, "/user/:/" when `validate` is `false`.
264
235
 
265
- console.log(tokens[0]);
266
- //=> "/route"
236
+ const toPathRepeated = compile("{/:segment}+");
267
237
 
268
- console.log(tokens[1]);
269
- //=> { name: 'foo', prefix: '/', suffix: '', pattern: '[^\\/#\\?]+?', modifier: '' }
238
+ toPathRepeated({ segment: ["foo"] }); //=> "/foo"
239
+ toPathRepeated({ segment: ["a", "b", "c"] }); //=> "/a/b/c"
270
240
 
271
- console.log(tokens[2]);
272
- //=> { name: 0, prefix: '/', suffix: '', pattern: '.*', modifier: '' }
241
+ const toPathRegexp = compile("/user/:id(\\d+)");
242
+
243
+ toPathRegexp({ id: "123" }); //=> "/user/123"
273
244
  ```
274
245
 
275
- **Note:** This method only works with strings.
246
+ ## Developers
276
247
 
277
- ### Compile ("Reverse" Path-To-RegExp)
248
+ - If you are rewriting paths with match and compiler, consider using `encode: false` and `decode: false` to keep raw paths passed around.
249
+ - To ensure matches work on paths containing characters usually encoded, consider using [encodeurl](https://github.com/pillarjs/encodeurl) for `encodePath`.
250
+ - If matches are intended to be exact, you need to set `loose: false`, `trailing: false`, and `sensitive: true`.
251
+ - Enable `strict: true` to detect ReDOS issues.
278
252
 
279
- The `compile` function will return a function for transforming parameters into a valid path:
253
+ ### Parse
280
254
 
281
- ```js
282
- // Make sure you encode your path segments consistently.
283
- const toPath = compile("/user/:id", { encode: encodeURIComponent });
255
+ A `parse` function is available and returns `TokenData`, the set of tokens and other metadata parsed from the input string. `TokenData` is can passed directly into `pathToRegexp`, `match`, and `compile`. It accepts only two options, `delimiter` and `encodePath`, which makes those options redundant in the above methods.
284
256
 
285
- toPath({ id: 123 }); //=> "/user/123"
286
- toPath({ id: "café" }); //=> "/user/caf%C3%A9"
287
- toPath({ id: ":/" }); //=> "/user/%3A%2F"
257
+ ### Tokens
288
258
 
289
- // Without `encode`, you need to make sure inputs are encoded correctly.
290
- // (Note: You can use `validate: false` to create an invalid paths.)
291
- const toPathRaw = compile("/user/:id", { validate: false });
259
+ The `tokens` returned by `TokenData` is an array of strings or keys, represented as objects, with the following properties:
292
260
 
293
- toPathRaw({ id: "%3A%2F" }); //=> "/user/%3A%2F"
294
- toPathRaw({ id: ":/" }); //=> "/user/:/"
261
+ - `name` The name of the token
262
+ - `prefix` _(optional)_ The prefix string for the segment (e.g. `"/"`)
263
+ - `suffix` _(optional)_ The suffix string for the segment (e.g. `""`)
264
+ - `pattern` _(optional)_ The pattern defined to match this token
265
+ - `modifier` _(optional)_ The modifier character used for the segment (e.g. `?`)
266
+ - `separator` _(optional)_ The string used to separate repeated parameters
295
267
 
296
- const toPathRepeated = compile("/:segment+");
268
+ ### Custom path
297
269
 
298
- toPathRepeated({ segment: "foo" }); //=> "/foo"
299
- toPathRepeated({ segment: ["a", "b", "c"] }); //=> "/a/b/c"
270
+ In some applications, you may not be able to use the `path-to-regexp` syntax (e.g. file-based routing), but you can still use this library for `match`, `compile`, and `pathToRegexp` by building your own `TokenData` instance. For example:
300
271
 
301
- const toPathRegexp = compile("/user/:id(\\d+)");
272
+ ```js
273
+ import { TokenData, match } from "path-to-regexp";
302
274
 
303
- toPathRegexp({ id: 123 }); //=> "/user/123"
304
- toPathRegexp({ id: "123" }); //=> "/user/123"
275
+ const tokens = ["/", { name: "foo" }];
276
+ const path = new TokenData(tokens, "/");
277
+ const fn = match(path);
278
+
279
+ fn("/test"); //=> { path: '/test', index: 0, params: { foo: 'test' } }
305
280
  ```
306
281
 
307
- **Note:** The generated function will throw on invalid input.
282
+ ## Errors
283
+
284
+ An effort has been made to ensure ambiguous paths from previous releases throw an error. This means you might be seeing an error when things worked before.
308
285
 
309
- ### Working with Tokens
286
+ ### Unexpected `?`, `*`, or `+`
310
287
 
311
- Path-To-RegExp exposes the two functions used internally that accept an array of tokens:
288
+ In previous major versions `/` and `.` were used as implicit prefixes of parameters. So `/:key?` was implicitly `{/:key}?`. For example:
312
289
 
313
- - `tokensToRegexp(tokens, keys?, options?)` Transform an array of tokens into a matching regular expression.
314
- - `tokensToFunction(tokens)` Transform an array of tokens into a path generator function.
290
+ - `/:key?` `{/:key}?` or `/:key*` `{/:key}*` or `/:key+` `{/:key}+`
291
+ - `.:key?` `{.:key}?` or `.:key*` `{.:key}*` or `.:key+` `{.:key}+`
292
+ - `:key?` → `{:key}?` or `:key*` → `{:key}*` or `:key+` → `{:key}+`
315
293
 
316
- #### Token Information
294
+ ### Unexpected `;`
317
295
 
318
- - `name` The name of the token (`string` for named or `number` for unnamed index)
319
- - `prefix` The prefix string for the segment (e.g. `"/"`)
320
- - `suffix` The suffix string for the segment (e.g. `""`)
321
- - `pattern` The RegExp used to match this token (`string`)
322
- - `modifier` The modifier character used for the segment (e.g. `?`)
296
+ Used as a [custom separator](#custom-separator) for repeated parameters.
323
297
 
324
- ## Compatibility with Express <= 4.x
298
+ ### Unexpected `!`, `@`, or `,`
325
299
 
326
- Path-To-RegExp breaks compatibility with Express <= `4.x`:
300
+ These characters have been reserved for future use.
327
301
 
328
- - RegExp special characters can only be used in a parameter
329
- - Express.js 4.x supported `RegExp` special characters regardless of position - this is considered a bug
330
- - Parameters have suffixes that augment meaning - `*`, `+` and `?`. E.g. `/:user*`
331
- - No wildcard asterisk (`*`) - use parameters instead (`(.*)` or `:splat*`)
302
+ ### Express <= 4.x
332
303
 
333
- ## Live Demo
304
+ Path-To-RegExp breaks compatibility with Express <= `4.x` in the following ways:
334
305
 
335
- You can see a live demo of this library in use at [express-route-tester](http://forbeslindesay.github.io/express-route-tester/).
306
+ - The only part of the string that is a regex is within `()`.
307
+ - In Express.js 4.x, everything was passed as-is after a simple replacement, so you could write `/[a-z]+` to match `/test`.
308
+ - The `?` optional character must be used after `{}`.
309
+ - Some characters have new meaning or have been reserved (`{}?*+@!;`).
310
+ - The parameter name now supports all unicode identifier characters, previously it was only `[a-z0-9]`.
336
311
 
337
312
  ## License
338
313