path-to-regexp 2.4.0 → 3.0.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/History.md CHANGED
@@ -1,3 +1,8 @@
1
+ 2.4.0 / 2018-08-26
2
+ ==================
3
+
4
+ * Support `start` option to disable anchoring from beginning of the string
5
+
1
6
  2.3.0 / 2018-08-20
2
7
  ==================
3
8
 
package/Readme.md CHANGED
@@ -18,7 +18,7 @@ npm install path-to-regexp --save
18
18
  ## Usage
19
19
 
20
20
  ```javascript
21
- var pathToRegexp = require('path-to-regexp')
21
+ const pathToRegexp = require('path-to-regexp')
22
22
 
23
23
  // pathToRegexp(path, keys?, options?)
24
24
  // pathToRegexp.parse(path)
@@ -26,25 +26,24 @@ var pathToRegexp = require('path-to-regexp')
26
26
  ```
27
27
 
28
28
  - **path** A string, array of strings, or a regular expression.
29
- - **keys** An array to be populated with keys found in the path.
29
+ - **keys** An array to populate with keys found in the path.
30
30
  - **options**
31
31
  - **sensitive** When `true` the regexp will be case sensitive. (default: `false`)
32
32
  - **strict** When `true` the regexp allows an optional trailing delimiter to match. (default: `false`)
33
33
  - **end** When `true` the regexp will match to the end of the string. (default: `true`)
34
34
  - **start** When `true` the regexp will match from the beginning of the string. (default: `true`)
35
- - Advanced options (use for non-pathname strings, e.g. host names):
36
- - **delimiter** The default delimiter for segments. (default: `'/'`)
37
- - **endsWith** Optional character, or list of characters, to treat as "end" characters.
38
- - **delimiters** List of characters to consider delimiters when parsing. (default: `'./'`)
35
+ - **delimiter** The default delimiter for segments. (default: `'/'`)
36
+ - **endsWith** Optional character, or list of characters, to treat as "end" characters.
37
+ - **whitelist** List of characters to consider delimiters when parsing. (default: `undefined`, any character)
39
38
 
40
39
  ```javascript
41
- var keys = []
42
- var re = pathToRegexp('/foo/:bar', keys)
43
- // re = /^\/foo\/([^\/]+?)\/?$/i
40
+ const keys = []
41
+ const regexp = pathToRegexp('/foo/:bar', keys)
42
+ // regexp = /^\/foo\/([^\/]+?)\/?$/i
44
43
  // keys = [{ name: 'bar', prefix: '/', delimiter: '/', optional: false, repeat: false, pattern: '[^\\/]+?' }]
45
44
  ```
46
45
 
47
- **Please note:** The `RegExp` returned by `path-to-regexp` is intended for ordered data (e.g. pathnames, hostnames). It does not handle arbitrary data (e.g. query strings, URL fragments, JSON, etc).
46
+ **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
47
 
49
48
  ### Parameters
50
49
 
@@ -52,17 +51,17 @@ The path argument is used to define parameters and populate the list of keys.
52
51
 
53
52
  #### Named Parameters
54
53
 
55
- Named parameters are defined by prefixing a colon to the parameter name (`:foo`). By default, the parameter will match until the following path segment.
54
+ 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
55
 
57
56
  ```js
58
- var re = pathToRegexp('/:foo/:bar')
57
+ const regexp = pathToRegexp('/:foo/:bar')
59
58
  // keys = [{ name: 'foo', prefix: '/', ... }, { name: 'bar', prefix: '/', ... }]
60
59
 
61
60
  re.exec('/test/route')
62
61
  //=> ['/test/route', 'test', 'route']
63
62
  ```
64
63
 
65
- **Please note:** Parameter names must be made up of "word characters" (`[A-Za-z0-9_]`).
64
+ **Please note:** Parameter names must use "word characters" (`[A-Za-z0-9_]`).
66
65
 
67
66
  #### Parameter Modifiers
68
67
 
@@ -71,7 +70,7 @@ re.exec('/test/route')
71
70
  Parameters can be suffixed with a question mark (`?`) to make the parameter optional.
72
71
 
73
72
  ```js
74
- var re = pathToRegexp('/:foo/:bar?')
73
+ const regexp = pathToRegexp('/:foo/:bar?')
75
74
  // keys = [{ name: 'foo', ... }, { name: 'bar', delimiter: '/', optional: true, repeat: false }]
76
75
 
77
76
  re.exec('/test')
@@ -81,14 +80,14 @@ re.exec('/test/route')
81
80
  //=> ['/test', 'test', 'route']
82
81
  ```
83
82
 
84
- **Tip:** If the parameter is the _only_ value in the segment, the prefix is also optional.
83
+ **Tip:** The prefix is also optional, escape the prefix `\/` to make it required.
85
84
 
86
85
  ##### Zero or more
87
86
 
88
- Parameters can be suffixed with an asterisk (`*`) to denote a zero or more parameter matches. The prefix is taken into account for each match.
87
+ Parameters can be suffixed with an asterisk (`*`) to denote a zero or more parameter matches. The prefix is used for each match.
89
88
 
90
89
  ```js
91
- var re = pathToRegexp('/:foo*')
90
+ const regexp = pathToRegexp('/:foo*')
92
91
  // keys = [{ name: 'foo', delimiter: '/', optional: true, repeat: true }]
93
92
 
94
93
  re.exec('/')
@@ -100,10 +99,10 @@ re.exec('/bar/baz')
100
99
 
101
100
  ##### One or more
102
101
 
103
- Parameters can be suffixed with a plus sign (`+`) to denote a one or more parameter matches. The prefix is taken into account for each match.
102
+ Parameters can be suffixed with a plus sign (`+`) to denote a one or more parameter matches. The prefix is used for each match.
104
103
 
105
104
  ```js
106
- var re = pathToRegexp('/:foo+')
105
+ const regexp = pathToRegexp('/:foo+')
107
106
  // keys = [{ name: 'foo', delimiter: '/', optional: false, repeat: true }]
108
107
 
109
108
  re.exec('/')
@@ -113,41 +112,50 @@ re.exec('/bar/baz')
113
112
  //=> ['/bar/baz', 'bar/baz']
114
113
  ```
115
114
 
115
+ #### Unnamed Parameters
116
+
117
+ 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.
118
+
119
+ ```js
120
+ const regexp = pathToRegexp('/:foo/(.*)')
121
+ // keys = [{ name: 'foo', ... }, { name: 0, ... }]
122
+
123
+ regexp.exec('/test/route')
124
+ //=> ['/test/route', 'test', 'route']
125
+ ```
126
+
116
127
  #### Custom Matching Parameters
117
128
 
118
- All parameters can be provided a custom regexp, which overrides the default match (`[^\/]+`). For example, you can match digits in the path:
129
+ All parameters can have a custom regexp, which overrides the default match (`[^/]+`). For example, you can match digits or names in a path:
119
130
 
120
131
  ```js
121
- var re = pathToRegexp('/icon-:foo(\\d+).png')
132
+ const regexpNumbers = pathToRegexp('/icon-:foo(\\d+).png')
122
133
  // keys = [{ name: 'foo', ... }]
123
134
 
124
- re.exec('/icon-123.png')
135
+ regexpNumbers.exec('/icon-123.png')
125
136
  //=> ['/icon-123.png', '123']
126
137
 
127
- re.exec('/icon-abc.png')
138
+ regexpNumbers.exec('/icon-abc.png')
128
139
  //=> null
129
- ```
130
140
 
131
- **Please note:** Backslashes need to be escaped with another backslash in strings.
141
+ const regexpWord = pathToRegexp('/(user|u)')
142
+ // keys = [{ name: 0, ... }]
132
143
 
133
- #### Unnamed Parameters
134
-
135
- 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.
136
-
137
- ```js
138
- var re = pathToRegexp('/:foo/(.*)')
139
- // keys = [{ name: 'foo', ... }, { name: 0, ... }]
144
+ regexpWord.exec('/u')
145
+ //=> ['/u', 'u']
140
146
 
141
- re.exec('/test/route')
142
- //=> ['/test/route', 'test', 'route']
147
+ regexpWord.exec('/users')
148
+ //=> null
143
149
  ```
144
150
 
151
+ **Tip:** Backslashes need to be escaped with another backslash in JavaScript strings.
152
+
145
153
  ### Parse
146
154
 
147
155
  The parse function is exposed via `pathToRegexp.parse`. This will return an array of strings and keys.
148
156
 
149
157
  ```js
150
- var tokens = pathToRegexp.parse('/route/:foo/(.*)')
158
+ const tokens = pathToRegexp.parse('/route/:foo/(.*)')
151
159
 
152
160
  console.log(tokens[0])
153
161
  //=> "/route"
@@ -166,7 +174,7 @@ console.log(tokens[2])
166
174
  Path-To-RegExp exposes a compile function for transforming a string into a valid path.
167
175
 
168
176
  ```js
169
- var toPath = pathToRegexp.compile('/user/:id')
177
+ const toPath = pathToRegexp.compile('/user/:id')
170
178
 
171
179
  toPath({ id: 123 }) //=> "/user/123"
172
180
  toPath({ id: 'café' }) //=> "/user/caf%C3%A9"
@@ -175,12 +183,12 @@ toPath({ id: '/' }) //=> "/user/%2F"
175
183
  toPath({ id: ':/' }) //=> "/user/%3A%2F"
176
184
  toPath({ id: ':/' }, { encode: (value, token) => value }) //=> "/user/:/"
177
185
 
178
- var toPathRepeated = pathToRegexp.compile('/:segment+')
186
+ const toPathRepeated = pathToRegexp.compile('/:segment+')
179
187
 
180
188
  toPathRepeated({ segment: 'foo' }) //=> "/foo"
181
189
  toPathRepeated({ segment: ['a', 'b', 'c'] }) //=> "/a/b/c"
182
190
 
183
- var toPathRegexp = pathToRegexp.compile('/user/:id(\\d+)')
191
+ const toPathRegexp = pathToRegexp.compile('/user/:id(\\d+)')
184
192
 
185
193
  toPathRegexp({ id: 123 }) //=> "/user/123"
186
194
  toPathRegexp({ id: '123' }) //=> "/user/123"
@@ -199,11 +207,10 @@ Path-To-RegExp exposes the two functions used internally that accept an array of
199
207
  #### Token Information
200
208
 
201
209
  * `name` The name of the token (`string` for named or `number` for index)
202
- * `prefix` The prefix character for the segment (`/` or `.`)
203
- * `delimiter` The delimiter for the segment (same as prefix or `/`)
210
+ * `prefix` The prefix character for the segment (e.g. `/`)
211
+ * `delimiter` The delimiter for the segment (same as prefix or default delimiter)
204
212
  * `optional` Indicates the token is optional (`boolean`)
205
213
  * `repeat` Indicates the token is repeated (`boolean`)
206
- * `partial` Indicates this token is a partial path segment (`boolean`)
207
214
  * `pattern` The RegExp used to match this token (`string`)
208
215
 
209
216
  ## Compatibility with Express <= 4.x
package/index.d.ts CHANGED
@@ -26,6 +26,10 @@ declare namespace pathToRegexp {
26
26
  * List of characters that can also be "end" characters.
27
27
  */
28
28
  endsWith?: string | string[];
29
+ /**
30
+ * List of characters to consider delimiters when parsing. (default: `undefined`, any character)
31
+ */
32
+ whitelist?: string | string[];
29
33
  }
30
34
 
31
35
  export interface ParseOptions {
@@ -33,10 +37,6 @@ declare namespace pathToRegexp {
33
37
  * Set the default delimiter for repeat parameters. (default: `'/'`)
34
38
  */
35
39
  delimiter?: string;
36
- /**
37
- * List of valid delimiter characters. (default: `'./'`)
38
- */
39
- delimiters?: string | string[];
40
40
  }
41
41
 
42
42
  /**
@@ -47,12 +47,12 @@ declare namespace pathToRegexp {
47
47
  /**
48
48
  * Transforming an Express-style path into a valid path.
49
49
  */
50
- export function compile (path: string, options?: ParseOptions): PathFunction;
50
+ export function compile <P extends object = object> (path: string, options?: ParseOptions): PathFunction<P>;
51
51
 
52
52
  /**
53
53
  * Transform an array of tokens into a path generator function.
54
54
  */
55
- export function tokensToFunction (tokens: Token[]): PathFunction;
55
+ export function tokensToFunction <P extends object = object> (tokens: Token[]): PathFunction<P>;
56
56
 
57
57
  /**
58
58
  * Transform an array of tokens into a matching regular expression.
@@ -66,7 +66,6 @@ declare namespace pathToRegexp {
66
66
  optional: boolean;
67
67
  repeat: boolean;
68
68
  pattern: string;
69
- partial: boolean;
70
69
  }
71
70
 
72
71
  interface PathFunctionOptions {
@@ -78,7 +77,7 @@ declare namespace pathToRegexp {
78
77
 
79
78
  export type Token = string | Key;
80
79
  export type Path = string | RegExp | Array<string | RegExp>;
81
- export type PathFunction = (data?: Object, options?: PathFunctionOptions) => string;
80
+ export type PathFunction <P extends object = object> = (data?: P, options?: PathFunctionOptions) => string;
82
81
  }
83
82
 
84
83
  export = pathToRegexp;
package/index.js CHANGED
@@ -11,7 +11,6 @@ module.exports.tokensToRegExp = tokensToRegExp
11
11
  * Default configs.
12
12
  */
13
13
  var DEFAULT_DELIMITER = '/'
14
- var DEFAULT_DELIMITERS = './'
15
14
 
16
15
  /**
17
16
  * The main path matching regexp utility.
@@ -43,7 +42,7 @@ function parse (str, options) {
43
42
  var index = 0
44
43
  var path = ''
45
44
  var defaultDelimiter = (options && options.delimiter) || DEFAULT_DELIMITER
46
- var delimiters = (options && options.delimiters) || DEFAULT_DELIMITERS
45
+ var whitelist = (options && options.whitelist) || undefined
47
46
  var pathEscaped = false
48
47
  var res
49
48
 
@@ -62,7 +61,6 @@ function parse (str, options) {
62
61
  }
63
62
 
64
63
  var prev = ''
65
- var next = str[index]
66
64
  var name = res[2]
67
65
  var capture = res[3]
68
66
  var group = res[4]
@@ -70,9 +68,11 @@ function parse (str, options) {
70
68
 
71
69
  if (!pathEscaped && path.length) {
72
70
  var k = path.length - 1
71
+ var c = path[k]
72
+ var matches = whitelist ? whitelist.indexOf(c) > -1 : true
73
73
 
74
- if (delimiters.indexOf(path[k]) > -1) {
75
- prev = path[k]
74
+ if (matches) {
75
+ prev = c
76
76
  path = path.slice(0, k)
77
77
  }
78
78
  }
@@ -84,11 +84,10 @@ function parse (str, options) {
84
84
  pathEscaped = false
85
85
  }
86
86
 
87
- var partial = prev !== '' && next !== undefined && next !== prev
88
87
  var repeat = modifier === '+' || modifier === '*'
89
88
  var optional = modifier === '?' || modifier === '*'
90
- var delimiter = prev || defaultDelimiter
91
89
  var pattern = capture || group
90
+ var delimiter = prev || defaultDelimiter
92
91
 
93
92
  tokens.push({
94
93
  name: name || key++,
@@ -96,8 +95,9 @@ function parse (str, options) {
96
95
  delimiter: delimiter,
97
96
  optional: optional,
98
97
  repeat: repeat,
99
- partial: partial,
100
- pattern: pattern ? escapeGroup(pattern) : '[^' + escapeString(delimiter) + ']+?'
98
+ pattern: pattern
99
+ ? escapeGroup(pattern)
100
+ : '[^' + escapeString(delimiter === defaultDelimiter ? delimiter : (delimiter + defaultDelimiter)) + ']+?'
101
101
  })
102
102
  }
103
103
 
@@ -184,12 +184,7 @@ function tokensToFunction (tokens) {
184
184
  continue
185
185
  }
186
186
 
187
- if (token.optional) {
188
- // Prepend partial segment prefixes.
189
- if (token.partial) path += token.prefix
190
-
191
- continue
192
- }
187
+ if (token.optional) continue
193
188
 
194
189
  throw new TypeError('Expected "' + token.name + '" to be ' + (token.repeat ? 'an array' : 'a string'))
195
190
  }
@@ -249,7 +244,6 @@ function regexpToRegexp (path, keys) {
249
244
  delimiter: null,
250
245
  optional: false,
251
246
  repeat: false,
252
- partial: false,
253
247
  pattern: null
254
248
  })
255
249
  }
@@ -302,11 +296,9 @@ function tokensToRegExp (tokens, keys, options) {
302
296
  var strict = options.strict
303
297
  var start = options.start !== false
304
298
  var end = options.end !== false
305
- var delimiter = escapeString(options.delimiter || DEFAULT_DELIMITER)
306
- var delimiters = options.delimiters || DEFAULT_DELIMITERS
299
+ var delimiter = options.delimiter || DEFAULT_DELIMITER
307
300
  var endsWith = [].concat(options.endsWith || []).map(escapeString).concat('$').join('|')
308
301
  var route = start ? '^' : ''
309
- var isEndDelimited = tokens.length === 0
310
302
 
311
303
  // Iterate over the tokens and create our regexp string.
312
304
  for (var i = 0; i < tokens.length; i++) {
@@ -314,7 +306,6 @@ function tokensToRegExp (tokens, keys, options) {
314
306
 
315
307
  if (typeof token === 'string') {
316
308
  route += escapeString(token)
317
- isEndDelimited = i === tokens.length - 1 && delimiters.indexOf(token[token.length - 1]) > -1
318
309
  } else {
319
310
  var capture = token.repeat
320
311
  ? '(?:' + token.pattern + ')(?:' + escapeString(token.delimiter) + '(?:' + token.pattern + '))*'
@@ -323,8 +314,8 @@ function tokensToRegExp (tokens, keys, options) {
323
314
  if (keys) keys.push(token)
324
315
 
325
316
  if (token.optional) {
326
- if (token.partial) {
327
- route += escapeString(token.prefix) + '(' + capture + ')?'
317
+ if (!token.prefix) {
318
+ route += '(' + capture + ')?'
328
319
  } else {
329
320
  route += '(?:' + escapeString(token.prefix) + '(' + capture + '))?'
330
321
  }
@@ -335,12 +326,17 @@ function tokensToRegExp (tokens, keys, options) {
335
326
  }
336
327
 
337
328
  if (end) {
338
- if (!strict) route += '(?:' + delimiter + ')?'
329
+ if (!strict) route += '(?:' + escapeString(delimiter) + ')?'
339
330
 
340
331
  route += endsWith === '$' ? '$' : '(?=' + endsWith + ')'
341
332
  } else {
342
- if (!strict) route += '(?:' + delimiter + '(?=' + endsWith + '))?'
343
- if (!isEndDelimited) route += '(?=' + delimiter + '|' + endsWith + ')'
333
+ var endToken = tokens[tokens.length - 1]
334
+ var isEndDelimited = typeof endToken === 'string'
335
+ ? endToken[endToken.length - 1] === delimiter
336
+ : endToken === undefined
337
+
338
+ if (!strict) route += '(?:' + escapeString(delimiter) + '(?=' + endsWith + '))?'
339
+ if (!isEndDelimited) route += '(?=' + escapeString(delimiter) + '|' + endsWith + ')'
344
340
  }
345
341
 
346
342
  return new RegExp(route, flags(options))
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "path-to-regexp",
3
3
  "description": "Express style path to RegExp utility",
4
- "version": "2.4.0",
4
+ "version": "3.0.0",
5
5
  "main": "index.js",
6
6
  "typings": "index.d.ts",
7
7
  "files": [
@@ -38,7 +38,7 @@
38
38
  "chai": "^4.1.1",
39
39
  "istanbul": "^0.4.5",
40
40
  "mocha": "^5.2.0",
41
- "standard": "^11.0.1",
41
+ "standard": "^12.0.1",
42
42
  "ts-node": "^7.0.1",
43
43
  "typescript": "^3.0.1"
44
44
  }