path-to-regexp 4.0.4 → 6.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
@@ -18,19 +18,12 @@ npm install path-to-regexp --save
18
18
  ## Usage
19
19
 
20
20
  ```javascript
21
- const {
22
- pathToRegexp,
23
- match,
24
- parse,
25
- compile,
26
- normalizePathname
27
- } = require("path-to-regexp");
21
+ const { pathToRegexp, match, parse, compile } = require("path-to-regexp");
28
22
 
29
23
  // pathToRegexp(path, keys?, options?)
30
24
  // match(path)
31
25
  // parse(path)
32
26
  // compile(path)
33
- // normalizePathname(path)
34
27
  ```
35
28
 
36
29
  - **path** A string, array of strings, or a regular expression.
@@ -40,26 +33,27 @@ const {
40
33
  - **strict** When `true` the regexp allows an optional trailing delimiter to match. (default: `false`)
41
34
  - **end** When `true` the regexp will match to the end of the string. (default: `true`)
42
35
  - **start** When `true` the regexp will match from the beginning of the string. (default: `true`)
43
- - **delimiter** The default delimiter for segments. (default: `'/'`)
36
+ - **delimiter** The default delimiter for segments, e.g. `[^/#?]` for `:named` patterns. (default: `'/#?'`)
44
37
  - **endsWith** Optional character, or list of characters, to treat as "end" characters.
45
- - **whitelist** List of characters to consider delimiters when parsing. (default: `undefined`, any character)
38
+ - **encode** A function to encode strings before inserting into `RegExp`. (default: `x => x`)
39
+ - **prefixes** List of characters to automatically consider prefixes when parsing. (default: `./`)
46
40
 
47
41
  ```javascript
48
42
  const keys = [];
49
43
  const regexp = pathToRegexp("/foo/:bar", keys);
50
44
  // regexp = /^\/foo\/([^\/]+?)\/?$/i
51
- // keys = [{ name: 'bar', prefix: '/', delimiter: '/', optional: false, repeat: false, pattern: '[^\\/]+?' }]
45
+ // keys = [{ name: 'bar', prefix: '/', suffix: '', pattern: '[^\\/#\\?]+?', modifier: '' }]
52
46
  ```
53
47
 
54
- **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).
48
+ **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).
55
49
 
56
50
  ### Parameters
57
51
 
58
- The path argument is used to define parameters and populate the list of keys.
52
+ The path argument is used to define parameters and populate keys.
59
53
 
60
54
  #### Named Parameters
61
55
 
62
- Named parameters are defined by prefixing a colon to the parameter name (`:foo`). By default, the parameter will match until the next prefix (e.g. `[^/]+`).
56
+ Named parameters are defined by prefixing a colon to the parameter name (`:foo`).
63
57
 
64
58
  ```js
65
59
  const regexp = pathToRegexp("/:foo/:bar");
@@ -71,7 +65,61 @@ regexp.exec("/test/route");
71
65
 
72
66
  **Please note:** Parameter names must use "word characters" (`[A-Za-z0-9_]`).
73
67
 
74
- #### Parameter Modifiers
68
+ ##### Custom Matching Parameters
69
+
70
+ Parameters can have a custom regexp, which overrides the default match (`[^/]+`). For example, you can match digits or names in a path:
71
+
72
+ ```js
73
+ const regexpNumbers = pathToRegexp("/icon-:foo(\\d+).png");
74
+ // keys = [{ name: 'foo', ... }]
75
+
76
+ regexpNumbers.exec("/icon-123.png");
77
+ //=> ['/icon-123.png', '123']
78
+
79
+ regexpNumbers.exec("/icon-abc.png");
80
+ //=> null
81
+
82
+ const regexpWord = pathToRegexp("/(user|u)");
83
+ // keys = [{ name: 0, ... }]
84
+
85
+ regexpWord.exec("/u");
86
+ //=> ['/u', 'u']
87
+
88
+ regexpWord.exec("/users");
89
+ //=> null
90
+ ```
91
+
92
+ **Tip:** Backslashes need to be escaped with another backslash in JavaScript strings.
93
+
94
+ ##### Custom Prefix and Suffix
95
+
96
+ Parameters can be wrapped in `{}` to create custom prefixes or suffixes for your segment:
97
+
98
+ ```js
99
+ const regexp = pathToRegexp("/:attr1?{-:attr2}?{-:attr3}?");
100
+
101
+ regexp.exec("/test");
102
+ // => ['/test', 'test', undefined, undefined]
103
+
104
+ regexp.exec("/test-test");
105
+ // => ['/test', 'test', 'test', undefined]
106
+ ```
107
+
108
+ #### Unnamed Parameters
109
+
110
+ 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:
111
+
112
+ ```js
113
+ const regexp = pathToRegexp("/:foo/(.*)");
114
+ // keys = [{ name: 'foo', ... }, { name: 0, ... }]
115
+
116
+ regexp.exec("/test/route");
117
+ //=> [ '/test/route', 'test', 'route', index: 0, input: '/test/route', groups: undefined ]
118
+ ```
119
+
120
+ #### Modifiers
121
+
122
+ Modifiers must be placed after the parameter (e.g. `/:foo?`, `/(test)?`, or `/:foo(test)?`).
75
123
 
76
124
  ##### Optional
77
125
 
@@ -79,7 +127,7 @@ Parameters can be suffixed with a question mark (`?`) to make the parameter opti
79
127
 
80
128
  ```js
81
129
  const regexp = pathToRegexp("/:foo/:bar?");
82
- // keys = [{ name: 'foo', ... }, { name: 'bar', delimiter: '/', optional: true, repeat: false }]
130
+ // keys = [{ name: 'foo', ... }, { name: 'bar', prefix: '/', modifier: '?' }]
83
131
 
84
132
  regexp.exec("/test");
85
133
  //=> [ '/test', 'test', undefined, index: 0, input: '/test', groups: undefined ]
@@ -90,13 +138,26 @@ regexp.exec("/test/route");
90
138
 
91
139
  **Tip:** The prefix is also optional, escape the prefix `\/` to make it required.
92
140
 
141
+ 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.
142
+
143
+ ```js
144
+ const regexp = pathToRegexp("/search/:tableName\\?useIndex=true&term=amazing");
145
+
146
+ regexp.exec("/search/people?useIndex=true&term=amazing");
147
+ //=> [ '/search/people?useIndex=true&term=amazing', 'people', index: 0, input: '/search/people?useIndex=true&term=amazing', groups: undefined ]
148
+
149
+ // This library does not handle query strings in different orders
150
+ regexp.exec("/search/people?term=amazing&useIndex=true");
151
+ //=> null
152
+ ```
153
+
93
154
  ##### Zero or more
94
155
 
95
- Parameters can be suffixed with an asterisk (`*`) to denote a zero or more parameter matches. The prefix is used for each match.
156
+ Parameters can be suffixed with an asterisk (`*`) to denote a zero or more parameter matches.
96
157
 
97
158
  ```js
98
159
  const regexp = pathToRegexp("/:foo*");
99
- // keys = [{ name: 'foo', delimiter: '/', optional: true, repeat: true }]
160
+ // keys = [{ name: 'foo', prefix: '/', modifier: '*' }]
100
161
 
101
162
  regexp.exec("/");
102
163
  //=> [ '/', undefined, index: 0, input: '/', groups: undefined ]
@@ -107,11 +168,11 @@ regexp.exec("/bar/baz");
107
168
 
108
169
  ##### One or more
109
170
 
110
- Parameters can be suffixed with a plus sign (`+`) to denote a one or more parameter matches. The prefix is used for each match.
171
+ Parameters can be suffixed with a plus sign (`+`) to denote a one or more parameter matches.
111
172
 
112
173
  ```js
113
174
  const regexp = pathToRegexp("/:foo+");
114
- // keys = [{ name: 'foo', delimiter: '/', optional: false, repeat: true }]
175
+ // keys = [{ name: 'foo', prefix: '/', modifier: '+' }]
115
176
 
116
177
  regexp.exec("/");
117
178
  //=> null
@@ -120,60 +181,53 @@ regexp.exec("/bar/baz");
120
181
  //=> [ '/bar/baz','bar/baz', index: 0, input: '/bar/baz', groups: undefined ]
121
182
  ```
122
183
 
123
- #### Unnamed Parameters
184
+ ### Match
124
185
 
125
- It is possible to write an unnamed parameter that only consists of a matching group. It works the same as a named parameter, except it will be numerically indexed.
186
+ The `match` function will return a function for transforming paths into parameters:
126
187
 
127
188
  ```js
128
- const regexp = pathToRegexp("/:foo/(.*)");
129
- // keys = [{ name: 'foo', ... }, { name: 0, ... }]
189
+ // Make sure you consistently `decode` segments.
190
+ const match = match("/user/:id", { decode: decodeURIComponent });
130
191
 
131
- regexp.exec("/test/route");
132
- //=> [ '/test/route', 'test', 'route', index: 0, input: '/test/route', groups: undefined ]
192
+ match("/user/123"); //=> { path: '/user/123', index: 0, params: { id: '123' } }
193
+ match("/invalid"); //=> false
194
+ match("/user/caf%C3%A9"); //=> { path: '/user/caf%C3%A9', index: 0, params: { id: 'café' } }
133
195
  ```
134
196
 
135
- #### Custom Matching Parameters
197
+ #### Process Pathname
136
198
 
137
- All parameters can have a custom regexp, which overrides the default match (`[^/]+`). For example, you can match digits or names in a path:
199
+ You should make sure variations of the same path match the expected `path`. Here's one possible solution using `encode`:
138
200
 
139
201
  ```js
140
- const regexpNumbers = pathToRegexp("/icon-:foo(\\d+).png");
141
- // keys = [{ name: 'foo', ... }]
142
-
143
- regexpNumbers.exec("/icon-123.png");
144
- //=> ['/icon-123.png', '123']
145
-
146
- regexpNumbers.exec("/icon-abc.png");
147
- //=> null
148
-
149
- const regexpWord = pathToRegexp("/(user|u)");
150
- // keys = [{ name: 0, ... }]
202
+ const match = match("/café", { encode: encodeURI, decode: decodeURIComponent });
151
203
 
152
- regexpWord.exec("/u");
153
- //=> ['/u', 'u']
154
-
155
- regexpWord.exec("/users");
156
- //=> null
204
+ match("/user/caf%C3%A9"); //=> { path: '/user/caf%C3%A9', index: 0, params: { id: 'café' } }
157
205
  ```
158
206
 
159
- **Tip:** Backslashes need to be escaped with another backslash in JavaScript strings.
160
-
161
- ### Match
207
+ **Note:** [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL) automatically encodes pathnames for you.
162
208
 
163
- The `match` function will return a function for transforming paths into parameters:
209
+ ##### Alternative Using Normalize
164
210
 
165
- ```js
166
- const match = match("/user/:id");
167
-
168
- match("/user/123"); //=> { path: '/user/123', index: 0, params: { id: '123' } }
169
- match("/invalid"); //=> false
170
- ```
171
-
172
- ### Normalize Pathname
173
-
174
- The `normalizePathname` function will return a normalized string for matching with `pathToRegexp`.
211
+ Sometimes you won't have an already normalized pathname. You can normalize it yourself before processing:
175
212
 
176
213
  ```js
214
+ /**
215
+ * Normalize a pathname for matching, replaces multiple slashes with a single
216
+ * slash and normalizes unicode characters to "NFC". When using this method,
217
+ * `decode` should be an identity function so you don't decode strings twice.
218
+ */
219
+ function normalizePathname(pathname: string) {
220
+ return (
221
+ decodeURI(pathname)
222
+ // Replaces repeated slashes in the URL.
223
+ .replace(/\/+/g, "/")
224
+ // Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
225
+ // Note: Missing native IE support, may want to skip this step.
226
+ .normalize()
227
+ );
228
+ }
229
+
230
+ // Two possible ways of writing `/café`:
177
231
  const re = pathToRegexp("/caf\u00E9");
178
232
  const input = encodeURI("/cafe\u0301");
179
233
 
@@ -192,10 +246,10 @@ console.log(tokens[0]);
192
246
  //=> "/route"
193
247
 
194
248
  console.log(tokens[1]);
195
- //=> { name: 'foo', prefix: '/', delimiter: '/', optional: false, repeat: false, pattern: '[^\\/]+?' }
249
+ //=> { name: 'foo', prefix: '/', suffix: '', pattern: '[^\\/#\\?]+?', modifier: '' }
196
250
 
197
251
  console.log(tokens[2]);
198
- //=> { name: 0, prefix: '/', delimiter: '/', optional: false, repeat: false, pattern: '.*' }
252
+ //=> { name: 0, prefix: '/', suffix: '', pattern: '.*', modifier: '' }
199
253
  ```
200
254
 
201
255
  **Note:** This method only works with strings.
@@ -205,14 +259,20 @@ console.log(tokens[2]);
205
259
  The `compile` function will return a function for transforming parameters into a valid path:
206
260
 
207
261
  ```js
208
- const toPath = compile("/user/:id");
262
+ // Make sure you encode your path segments consistently.
263
+ const toPath = compile("/user/:id", { encode: encodeURIComponent });
209
264
 
210
265
  toPath({ id: 123 }); //=> "/user/123"
211
266
  toPath({ id: "café" }); //=> "/user/caf%C3%A9"
212
267
  toPath({ id: "/" }); //=> "/user/%2F"
213
268
 
214
269
  toPath({ id: ":/" }); //=> "/user/%3A%2F"
215
- toPath({ id: ":/" }, { encode: (value, token) => value, validate: false }); //=> "/user/:/"
270
+
271
+ // Without `encode`, you need to make sure inputs are encoded correctly.
272
+ const toPathRaw = compile("/user/:id");
273
+
274
+ toPathRaw({ id: "%3A%2F" }); //=> "/user/%3A%2F"
275
+ toPathRaw({ id: ":/" }, { validate: false }); //=> "/user/:/"
216
276
 
217
277
  const toPathRepeated = compile("/:segment+");
218
278
 
@@ -227,11 +287,11 @@ toPathRegexp({ id: "abc" }); //=> Throws `TypeError`.
227
287
  toPathRegexp({ id: "abc" }, { validate: false }); //=> "/user/abc"
228
288
  ```
229
289
 
230
- **Note:** The generated function will throw on invalid input. It will do all necessary checks to ensure the generated path is valid. This method only works with strings.
290
+ **Note:** The generated function will throw on invalid input.
231
291
 
232
292
  ### Working with Tokens
233
293
 
234
- Path-To-RegExp exposes the two functions used internally that accept an array of tokens.
294
+ Path-To-RegExp exposes the two functions used internally that accept an array of tokens:
235
295
 
236
296
  - `tokensToRegexp(tokens, keys?, options?)` Transform an array of tokens into a matching regular expression.
237
297
  - `tokensToFunction(tokens)` Transform an array of tokens into a path generator function.
@@ -239,11 +299,10 @@ Path-To-RegExp exposes the two functions used internally that accept an array of
239
299
  #### Token Information
240
300
 
241
301
  - `name` The name of the token (`string` for named or `number` for unnamed index)
242
- - `prefix` The prefix character for the segment (e.g. `/`)
243
- - `delimiter` The delimiter for the segment (same as prefix or default delimiter)
244
- - `optional` Indicates the token is optional (`boolean`)
245
- - `repeat` Indicates the token is repeated (`boolean`)
302
+ - `prefix` The prefix string for the segment (e.g. `"/"`)
303
+ - `suffix` The suffix string for the segment (e.g. `""`)
246
304
  - `pattern` The RegExp used to match this token (`string`)
305
+ - `modifier` The modifier character used for the segment (e.g. `?`)
247
306
 
248
307
  ## Compatibility with Express <= 4.x
249
308
 
package/dist/index.d.ts CHANGED
@@ -4,16 +4,10 @@ export interface ParseOptions {
4
4
  */
5
5
  delimiter?: string;
6
6
  /**
7
- * List of characters to consider delimiters when parsing. (default: `undefined`, any character)
7
+ * List of characters to automatically consider prefixes when parsing.
8
8
  */
9
- whitelist?: string | string[];
9
+ prefixes?: string;
10
10
  }
11
- /**
12
- * Normalize a pathname for matching, replaces multiple slashes with a single
13
- * slash and normalizes unicode characters to "NFC". When using this method,
14
- * `decode` should be an identity function so you don't decode strings twice.
15
- */
16
- export declare function normalizePathname(pathname: string, whitelist?: string | string[]): string;
17
11
  /**
18
12
  * Parse a string for the raw tokens.
19
13
  */
@@ -66,7 +60,7 @@ export declare type MatchFunction<P extends object = object> = (path: string) =>
66
60
  /**
67
61
  * Create path match function from `path-to-regexp` spec.
68
62
  */
69
- export declare function match<P extends object = object>(str: Path, options?: ParseOptions & RegexpOptions & RegexpToFunctionOptions): MatchFunction<P>;
63
+ export declare function match<P extends object = object>(str: Path, options?: ParseOptions & TokensToRegexpOptions & RegexpToFunctionOptions): MatchFunction<P>;
70
64
  /**
71
65
  * Create a path match function from `path-to-regexp` output.
72
66
  */
@@ -77,20 +71,15 @@ export declare function regexpToFunction<P extends object = object>(re: RegExp,
77
71
  export interface Key {
78
72
  name: string | number;
79
73
  prefix: string;
80
- delimiter: string;
81
- optional: boolean;
82
- repeat: boolean;
74
+ suffix: string;
83
75
  pattern: string;
76
+ modifier: string;
84
77
  }
85
78
  /**
86
79
  * A token is a string (nothing special) or key metadata (capture group).
87
80
  */
88
81
  export declare type Token = string | Key;
89
- /**
90
- * Expose a function for taking tokens and returning a RegExp.
91
- */
92
- export declare function tokensToRegexp(tokens: Token[], keys?: Key[], options?: RegexpOptions): RegExp;
93
- export interface RegexpOptions {
82
+ export interface TokensToRegexpOptions {
94
83
  /**
95
84
  * When `true` the regexp will be case sensitive. (default: `false`)
96
85
  */
@@ -114,14 +103,16 @@ export interface RegexpOptions {
114
103
  /**
115
104
  * List of characters that can also be "end" characters.
116
105
  */
117
- endsWith?: string | string[];
118
- }
119
- export interface ParseOptions {
106
+ endsWith?: string;
120
107
  /**
121
- * Set the default delimiter for repeat parameters. (default: `'/'`)
108
+ * Encode path tokens for use in the `RegExp`.
122
109
  */
123
- delimiter?: string;
110
+ encode?: (value: string) => string;
124
111
  }
112
+ /**
113
+ * Expose a function for taking tokens and returning a RegExp.
114
+ */
115
+ export declare function tokensToRegexp(tokens: Token[], keys?: Key[], options?: TokensToRegexpOptions): RegExp;
125
116
  /**
126
117
  * Supported `path-to-regexp` input types.
127
118
  */
@@ -133,4 +124,4 @@ export declare type Path = string | RegExp | Array<string | RegExp>;
133
124
  * placeholder key descriptions. For example, using `/user/:id`, `keys` will
134
125
  * contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
135
126
  */
136
- export declare function pathToRegexp(path: Path, keys?: Key[], options?: RegexpOptions & ParseOptions): RegExp;
127
+ export declare function pathToRegexp(path: Path, keys?: Key[], options?: TokensToRegexpOptions & ParseOptions): RegExp;