path-to-regexp 1.6.0 → 2.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/History.md +24 -0
- package/Readme.md +27 -36
- package/index.d.ts +18 -11
- package/index.js +100 -154
- package/package.json +10 -12
package/History.md
CHANGED
@@ -1,3 +1,27 @@
|
|
1
|
+
2.0.0 / 2017-08-23
|
2
|
+
==================
|
3
|
+
|
4
|
+
* New option! Ability to set `endsWith` to match paths like `/test?query=string` up to the query string
|
5
|
+
* New option! Set `delimiters` for specific characters to be treated as parameter prefixes (e.g. `/:test`)
|
6
|
+
* Remove `isarray` dependency
|
7
|
+
* Explicitly handle trailing delimiters instead of trimming them (e.g. `/test/` is now treated as `/test/` instead of `/test` when matching)
|
8
|
+
* Remove overloaded `keys` argument that accepted `options`
|
9
|
+
* Remove `keys` list attached to the `RegExp` output
|
10
|
+
* Remove asterisk functionality (it's a real pain to properly encode)
|
11
|
+
* Change `tokensToFunction` (e.g. `compile`) to accept an `encode` function for pretty encoding (e.g. pass your own implementation)
|
12
|
+
|
13
|
+
1.7.0 / 2016-11-08
|
14
|
+
==================
|
15
|
+
|
16
|
+
* Allow a `delimiter` option to be passed in with `tokensToRegExp` which will be used for "non-ending" token match situations
|
17
|
+
|
18
|
+
1.6.0 / 2016-10-03
|
19
|
+
==================
|
20
|
+
|
21
|
+
* Populate `RegExp.keys` when using the `tokensToRegExp` method (making it consistent with the main export)
|
22
|
+
* Allow a `delimiter` option to be passed in with `parse`
|
23
|
+
* Updated TypeScript definition with `Keys` and `Options` updated
|
24
|
+
|
1
25
|
1.5.3 / 2016-06-15
|
2
26
|
==================
|
3
27
|
|
package/Readme.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Path-to-RegExp
|
2
2
|
|
3
|
-
> Turn
|
3
|
+
> Turn a path string such as `/user/:name` into a regular expression.
|
4
4
|
|
5
5
|
[![NPM version][npm-image]][npm-url]
|
6
6
|
[![Build status][travis-image]][travis-url]
|
@@ -20,18 +20,21 @@ npm install path-to-regexp --save
|
|
20
20
|
```javascript
|
21
21
|
var pathToRegexp = require('path-to-regexp')
|
22
22
|
|
23
|
-
// pathToRegexp(path, keys
|
23
|
+
// pathToRegexp(path, keys?, options?)
|
24
24
|
// pathToRegexp.parse(path)
|
25
25
|
// pathToRegexp.compile(path)
|
26
26
|
```
|
27
27
|
|
28
|
-
- **path**
|
28
|
+
- **path** A string, array of strings, or a regular expression.
|
29
29
|
- **keys** An array to be populated with the keys found in the path.
|
30
30
|
- **options**
|
31
31
|
- **sensitive** When `true` the route will be case sensitive. (default: `false`)
|
32
32
|
- **strict** When `false` the trailing slash is optional. (default: `false`)
|
33
33
|
- **end** When `false` the path will match at the beginning. (default: `true`)
|
34
|
-
-
|
34
|
+
- Advanced options (use for non-pathname strings, e.g. host names):
|
35
|
+
- **delimiter** The default delimiter for segments. (default: `'/'`)
|
36
|
+
- **endsWith** Optional character, or list of characters, to treat as "end" characters.
|
37
|
+
- **delimiters** List of characters to consider delimiters when parsing. (default: `'./'`)
|
35
38
|
|
36
39
|
```javascript
|
37
40
|
var keys = []
|
@@ -40,18 +43,18 @@ var re = pathToRegexp('/foo/:bar', keys)
|
|
40
43
|
// keys = [{ name: 'bar', prefix: '/', delimiter: '/', optional: false, repeat: false, pattern: '[^\\/]+?' }]
|
41
44
|
```
|
42
45
|
|
43
|
-
**Please note:** The `RegExp` returned by `path-to-regexp` is intended for
|
46
|
+
**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).
|
44
47
|
|
45
48
|
### Parameters
|
46
49
|
|
47
|
-
The path
|
50
|
+
The path argument is used to define parameters and populate the list of keys.
|
48
51
|
|
49
52
|
#### Named Parameters
|
50
53
|
|
51
54
|
Named parameters are defined by prefixing a colon to the parameter name (`:foo`). By default, the parameter will match until the following path segment.
|
52
55
|
|
53
56
|
```js
|
54
|
-
var re = pathToRegexp('/:foo/:bar'
|
57
|
+
var re = pathToRegexp('/:foo/:bar')
|
55
58
|
// keys = [{ name: 'foo', prefix: '/', ... }, { name: 'bar', prefix: '/', ... }]
|
56
59
|
|
57
60
|
re.exec('/test/route')
|
@@ -61,21 +64,21 @@ re.exec('/test/route')
|
|
61
64
|
**Please note:** Named parameters must be made up of "word characters" (`[A-Za-z0-9_]`).
|
62
65
|
|
63
66
|
```js
|
64
|
-
var re = pathToRegexp('/(apple-)?icon-:res(\\d+).png'
|
67
|
+
var re = pathToRegexp('/(apple-)?icon-:res(\\d+).png')
|
65
68
|
// keys = [{ name: 0, prefix: '/', ... }, { name: 'res', prefix: '', ... }]
|
66
69
|
|
67
70
|
re.exec('/icon-76.png')
|
68
71
|
//=> ['/icon-76.png', undefined, '76']
|
69
72
|
```
|
70
73
|
|
71
|
-
####
|
74
|
+
#### Parameter Modifiers
|
72
75
|
|
73
76
|
##### Optional
|
74
77
|
|
75
|
-
Parameters can be suffixed with a question mark (`?`) to make the parameter optional.
|
78
|
+
Parameters can be suffixed with a question mark (`?`) to make the parameter optional.
|
76
79
|
|
77
80
|
```js
|
78
|
-
var re = pathToRegexp('/:foo/:bar?'
|
81
|
+
var re = pathToRegexp('/:foo/:bar?')
|
79
82
|
// keys = [{ name: 'foo', ... }, { name: 'bar', delimiter: '/', optional: true, repeat: false }]
|
80
83
|
|
81
84
|
re.exec('/test')
|
@@ -85,12 +88,14 @@ re.exec('/test/route')
|
|
85
88
|
//=> ['/test', 'test', 'route']
|
86
89
|
```
|
87
90
|
|
91
|
+
**Tip:** If the parameter is the _only_ value in the segment, the prefix is also optional.
|
92
|
+
|
88
93
|
##### Zero or more
|
89
94
|
|
90
95
|
Parameters can be suffixed with an asterisk (`*`) to denote a zero or more parameter matches. The prefix is taken into account for each match.
|
91
96
|
|
92
97
|
```js
|
93
|
-
var re = pathToRegexp('/:foo*'
|
98
|
+
var re = pathToRegexp('/:foo*')
|
94
99
|
// keys = [{ name: 'foo', delimiter: '/', optional: true, repeat: true }]
|
95
100
|
|
96
101
|
re.exec('/')
|
@@ -105,7 +110,7 @@ re.exec('/bar/baz')
|
|
105
110
|
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.
|
106
111
|
|
107
112
|
```js
|
108
|
-
var re = pathToRegexp('/:foo+'
|
113
|
+
var re = pathToRegexp('/:foo+')
|
109
114
|
// keys = [{ name: 'foo', delimiter: '/', optional: false, repeat: true }]
|
110
115
|
|
111
116
|
re.exec('/')
|
@@ -120,7 +125,7 @@ re.exec('/bar/baz')
|
|
120
125
|
All parameters can be provided a custom regexp, which overrides the default (`[^\/]+`).
|
121
126
|
|
122
127
|
```js
|
123
|
-
var re = pathToRegexp('/:foo(\\d+)'
|
128
|
+
var re = pathToRegexp('/:foo(\\d+)')
|
124
129
|
// keys = [{ name: 'foo', ... }]
|
125
130
|
|
126
131
|
re.exec('/123')
|
@@ -137,25 +142,13 @@ re.exec('/abc')
|
|
137
142
|
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.
|
138
143
|
|
139
144
|
```js
|
140
|
-
var re = pathToRegexp('/:foo/(.*)'
|
145
|
+
var re = pathToRegexp('/:foo/(.*)')
|
141
146
|
// keys = [{ name: 'foo', ... }, { name: 0, ... }]
|
142
147
|
|
143
148
|
re.exec('/test/route')
|
144
149
|
//=> ['/test/route', 'test', 'route']
|
145
150
|
```
|
146
151
|
|
147
|
-
#### Asterisk
|
148
|
-
|
149
|
-
An asterisk can be used for matching everything. It is equivalent to an unnamed matching group of `(.*)`.
|
150
|
-
|
151
|
-
```js
|
152
|
-
var re = pathToRegexp('/foo/*', keys)
|
153
|
-
// keys = [{ name: '0', ... }]
|
154
|
-
|
155
|
-
re.exec('/foo/bar/baz')
|
156
|
-
//=> ['/foo/bar/baz', 'bar/baz']
|
157
|
-
```
|
158
|
-
|
159
152
|
### Parse
|
160
153
|
|
161
154
|
The parse function is exposed via `pathToRegexp.parse`. This will return an array of strings and keys.
|
@@ -173,11 +166,11 @@ console.log(tokens[2])
|
|
173
166
|
//=> { name: 0, prefix: '/', delimiter: '/', optional: false, repeat: false, pattern: '.*' }
|
174
167
|
```
|
175
168
|
|
176
|
-
**Note:** This method only works with
|
169
|
+
**Note:** This method only works with strings.
|
177
170
|
|
178
171
|
### Compile ("Reverse" Path-To-RegExp)
|
179
172
|
|
180
|
-
Path-To-RegExp exposes a compile function for transforming
|
173
|
+
Path-To-RegExp exposes a compile function for transforming a string into a valid path.
|
181
174
|
|
182
175
|
```js
|
183
176
|
var toPath = pathToRegexp.compile('/user/:id')
|
@@ -186,8 +179,8 @@ toPath({ id: 123 }) //=> "/user/123"
|
|
186
179
|
toPath({ id: 'café' }) //=> "/user/caf%C3%A9"
|
187
180
|
toPath({ id: '/' }) //=> "/user/%2F"
|
188
181
|
|
189
|
-
toPath({ id: '
|
190
|
-
toPath({ id: '
|
182
|
+
toPath({ id: ':/' }) //=> "/user/%3A%2F"
|
183
|
+
toPath({ id: ':/' }, { encode: (x) => x }) //=> "/user/:/"
|
191
184
|
|
192
185
|
var toPathRepeated = pathToRegexp.compile('/:segment+')
|
193
186
|
|
@@ -219,17 +212,15 @@ Path-To-RegExp exposes the two functions used internally that accept an array of
|
|
219
212
|
* `repeat` Indicates the token is repeated (`boolean`)
|
220
213
|
* `partial` Indicates this token is a partial path segment (`boolean`)
|
221
214
|
* `pattern` The RegExp used to match this token (`string`)
|
222
|
-
* `asterisk` Indicates the token is an `*` match (`boolean`)
|
223
215
|
|
224
216
|
## Compatibility with Express <= 4.x
|
225
217
|
|
226
218
|
Path-To-RegExp breaks compatibility with Express <= `4.x`:
|
227
219
|
|
228
|
-
*
|
229
|
-
*
|
230
|
-
* All matching RegExp special characters can be used in a matching group. E.g. `/:user(.*)`
|
231
|
-
* Other RegExp features are not support - no nested matching groups, non-capturing groups or look aheads
|
220
|
+
* RegExp special characters can only be used in a parameter
|
221
|
+
* Express.js 4.x used all `RegExp` special characters regardless of position - this considered a bug
|
232
222
|
* Parameters have suffixes that augment meaning - `*`, `+` and `?`. E.g. `/:user*`
|
223
|
+
* No wildcard asterisk (`*`) - use parameters instead (`(.*)`)
|
233
224
|
|
234
225
|
## TypeScript
|
235
226
|
|
package/index.d.ts
CHANGED
@@ -1,12 +1,6 @@
|
|
1
|
-
declare function pathToRegexp (path: pathToRegexp.Path, options?: pathToRegexp.RegExpOptions & pathToRegexp.ParseOptions):
|
2
|
-
declare function pathToRegexp (path: pathToRegexp.Path, keys?: pathToRegexp.Key[], options?: pathToRegexp.RegExpOptions & pathToRegexp.ParseOptions): pathToRegexp.PathRegExp;
|
1
|
+
declare function pathToRegexp (path: pathToRegexp.Path, keys?: pathToRegexp.Key[], options?: pathToRegexp.RegExpOptions & pathToRegexp.ParseOptions): RegExp;
|
3
2
|
|
4
3
|
declare namespace pathToRegexp {
|
5
|
-
export interface PathRegExp extends RegExp {
|
6
|
-
// An array to be populated with the keys found in the path.
|
7
|
-
keys: Key[];
|
8
|
-
}
|
9
|
-
|
10
4
|
export interface RegExpOptions {
|
11
5
|
/**
|
12
6
|
* When `true` the route will be case sensitive. (default: `false`)
|
@@ -20,6 +14,14 @@ declare namespace pathToRegexp {
|
|
20
14
|
* When `false` the path will match at the beginning. (default: `true`)
|
21
15
|
*/
|
22
16
|
end?: boolean;
|
17
|
+
/**
|
18
|
+
* Sets the final character for non-ending optimistic matches. (default: `/`)
|
19
|
+
*/
|
20
|
+
delimiter?: string;
|
21
|
+
/**
|
22
|
+
* List of characters that can also be "end" characters.
|
23
|
+
*/
|
24
|
+
endsWith?: string | string[];
|
23
25
|
}
|
24
26
|
|
25
27
|
export interface ParseOptions {
|
@@ -27,6 +29,10 @@ declare namespace pathToRegexp {
|
|
27
29
|
* Set the default delimiter for repeat parameters. (default: `'/'`)
|
28
30
|
*/
|
29
31
|
delimiter?: string;
|
32
|
+
/**
|
33
|
+
* List of valid delimiter characters. (default: `'./'`)
|
34
|
+
*/
|
35
|
+
delimiters?: string | string[];
|
30
36
|
}
|
31
37
|
|
32
38
|
/**
|
@@ -47,8 +53,7 @@ declare namespace pathToRegexp {
|
|
47
53
|
/**
|
48
54
|
* Transform an array of tokens into a matching regular expression.
|
49
55
|
*/
|
50
|
-
export function tokensToRegExp (tokens: Token[], options?: RegExpOptions):
|
51
|
-
export function tokensToRegExp (tokens: Token[], keys?: Key[], options?: RegExpOptions): PathRegExp;
|
56
|
+
export function tokensToRegExp (tokens: Token[], keys?: Key[], options?: RegExpOptions): RegExp;
|
52
57
|
|
53
58
|
export interface Key {
|
54
59
|
name: string | number;
|
@@ -58,11 +63,13 @@ declare namespace pathToRegexp {
|
|
58
63
|
repeat: boolean;
|
59
64
|
pattern: string;
|
60
65
|
partial: boolean;
|
61
|
-
asterisk: boolean;
|
62
66
|
}
|
63
67
|
|
64
68
|
interface PathFunctionOptions {
|
65
|
-
|
69
|
+
/**
|
70
|
+
* Function for encoding input strings for output.
|
71
|
+
*/
|
72
|
+
encode?: (value: string) => string;
|
66
73
|
}
|
67
74
|
|
68
75
|
export type Token = string | Key;
|
package/index.js
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
var isarray = require('isarray')
|
2
|
-
|
3
1
|
/**
|
4
2
|
* Expose `pathToRegexp`.
|
5
3
|
*/
|
@@ -9,6 +7,12 @@ module.exports.compile = compile
|
|
9
7
|
module.exports.tokensToFunction = tokensToFunction
|
10
8
|
module.exports.tokensToRegExp = tokensToRegExp
|
11
9
|
|
10
|
+
/**
|
11
|
+
* Default configs.
|
12
|
+
*/
|
13
|
+
var DEFAULT_DELIMITER = '/'
|
14
|
+
var DEFAULT_DELIMITERS = './'
|
15
|
+
|
12
16
|
/**
|
13
17
|
* The main path matching regexp utility.
|
14
18
|
*
|
@@ -21,10 +25,9 @@ var PATH_REGEXP = new RegExp([
|
|
21
25
|
// Match Express-style parameters and un-named parameters with a prefix
|
22
26
|
// and optional suffixes. Matches appear as:
|
23
27
|
//
|
24
|
-
// "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?"
|
25
|
-
// "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined
|
26
|
-
|
27
|
-
'([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
|
28
|
+
// "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?"]
|
29
|
+
// "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined]
|
30
|
+
'(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?'
|
28
31
|
].join('|'), 'g')
|
29
32
|
|
30
33
|
/**
|
@@ -39,10 +42,12 @@ function parse (str, options) {
|
|
39
42
|
var key = 0
|
40
43
|
var index = 0
|
41
44
|
var path = ''
|
42
|
-
var defaultDelimiter = options && options.delimiter ||
|
45
|
+
var defaultDelimiter = (options && options.delimiter) || DEFAULT_DELIMITER
|
46
|
+
var delimiters = (options && options.delimiters) || DEFAULT_DELIMITERS
|
47
|
+
var pathEscaped = false
|
43
48
|
var res
|
44
49
|
|
45
|
-
while ((res = PATH_REGEXP.exec(str))
|
50
|
+
while ((res = PATH_REGEXP.exec(str)) !== null) {
|
46
51
|
var m = res[0]
|
47
52
|
var escaped = res[1]
|
48
53
|
var offset = res.index
|
@@ -52,49 +57,53 @@ function parse (str, options) {
|
|
52
57
|
// Ignore already escaped sequences.
|
53
58
|
if (escaped) {
|
54
59
|
path += escaped[1]
|
60
|
+
pathEscaped = true
|
55
61
|
continue
|
56
62
|
}
|
57
63
|
|
64
|
+
var prev = ''
|
58
65
|
var next = str[index]
|
59
|
-
var
|
60
|
-
var
|
61
|
-
var
|
62
|
-
var
|
63
|
-
|
64
|
-
|
66
|
+
var name = res[2]
|
67
|
+
var capture = res[3]
|
68
|
+
var group = res[4]
|
69
|
+
var modifier = res[5]
|
70
|
+
|
71
|
+
if (!pathEscaped && path.length) {
|
72
|
+
var k = path.length - 1
|
73
|
+
|
74
|
+
if (delimiters.indexOf(path[k]) > -1) {
|
75
|
+
prev = path[k]
|
76
|
+
path = path.slice(0, k)
|
77
|
+
}
|
78
|
+
}
|
65
79
|
|
66
80
|
// Push the current path onto the tokens.
|
67
81
|
if (path) {
|
68
82
|
tokens.push(path)
|
69
83
|
path = ''
|
84
|
+
pathEscaped = false
|
70
85
|
}
|
71
86
|
|
72
|
-
var partial =
|
87
|
+
var partial = prev !== '' && next !== undefined && next !== prev
|
73
88
|
var repeat = modifier === '+' || modifier === '*'
|
74
89
|
var optional = modifier === '?' || modifier === '*'
|
75
|
-
var delimiter =
|
90
|
+
var delimiter = prev || defaultDelimiter
|
76
91
|
var pattern = capture || group
|
77
92
|
|
78
93
|
tokens.push({
|
79
94
|
name: name || key++,
|
80
|
-
prefix:
|
95
|
+
prefix: prev,
|
81
96
|
delimiter: delimiter,
|
82
97
|
optional: optional,
|
83
98
|
repeat: repeat,
|
84
99
|
partial: partial,
|
85
|
-
|
86
|
-
pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
|
100
|
+
pattern: pattern ? escapeGroup(pattern) : '[^' + escapeString(delimiter) + ']+?'
|
87
101
|
})
|
88
102
|
}
|
89
103
|
|
90
|
-
//
|
91
|
-
if (index < str.length) {
|
92
|
-
path
|
93
|
-
}
|
94
|
-
|
95
|
-
// If the path exists, push it onto the end.
|
96
|
-
if (path) {
|
97
|
-
tokens.push(path)
|
104
|
+
// Push any remaining characters.
|
105
|
+
if (path || index < str.length) {
|
106
|
+
tokens.push(path + str.substr(index))
|
98
107
|
}
|
99
108
|
|
100
109
|
return tokens
|
@@ -111,30 +120,6 @@ function compile (str, options) {
|
|
111
120
|
return tokensToFunction(parse(str, options))
|
112
121
|
}
|
113
122
|
|
114
|
-
/**
|
115
|
-
* Prettier encoding of URI path segments.
|
116
|
-
*
|
117
|
-
* @param {string}
|
118
|
-
* @return {string}
|
119
|
-
*/
|
120
|
-
function encodeURIComponentPretty (str) {
|
121
|
-
return encodeURI(str).replace(/[\/?#]/g, function (c) {
|
122
|
-
return '%' + c.charCodeAt(0).toString(16).toUpperCase()
|
123
|
-
})
|
124
|
-
}
|
125
|
-
|
126
|
-
/**
|
127
|
-
* Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
|
128
|
-
*
|
129
|
-
* @param {string}
|
130
|
-
* @return {string}
|
131
|
-
*/
|
132
|
-
function encodeAsterisk (str) {
|
133
|
-
return encodeURI(str).replace(/[?#]/g, function (c) {
|
134
|
-
return '%' + c.charCodeAt(0).toString(16).toUpperCase()
|
135
|
-
})
|
136
|
-
}
|
137
|
-
|
138
123
|
/**
|
139
124
|
* Expose a method for transforming tokens into the path function.
|
140
125
|
*/
|
@@ -149,55 +134,37 @@ function tokensToFunction (tokens) {
|
|
149
134
|
}
|
150
135
|
}
|
151
136
|
|
152
|
-
return function (
|
137
|
+
return function (data, options) {
|
153
138
|
var path = ''
|
154
|
-
var
|
155
|
-
var options = opts || {}
|
156
|
-
var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent
|
139
|
+
var encode = (options && options.encode) || encodeURIComponent
|
157
140
|
|
158
141
|
for (var i = 0; i < tokens.length; i++) {
|
159
142
|
var token = tokens[i]
|
160
143
|
|
161
144
|
if (typeof token === 'string') {
|
162
145
|
path += token
|
163
|
-
|
164
146
|
continue
|
165
147
|
}
|
166
148
|
|
167
|
-
var value = data[token.name]
|
149
|
+
var value = data ? data[token.name] : undefined
|
168
150
|
var segment
|
169
151
|
|
170
|
-
if (value
|
171
|
-
if (token.optional) {
|
172
|
-
// Prepend partial segment prefixes.
|
173
|
-
if (token.partial) {
|
174
|
-
path += token.prefix
|
175
|
-
}
|
176
|
-
|
177
|
-
continue
|
178
|
-
} else {
|
179
|
-
throw new TypeError('Expected "' + token.name + '" to be defined')
|
180
|
-
}
|
181
|
-
}
|
182
|
-
|
183
|
-
if (isarray(value)) {
|
152
|
+
if (Array.isArray(value)) {
|
184
153
|
if (!token.repeat) {
|
185
|
-
throw new TypeError('Expected "' + token.name + '" to not repeat, but
|
154
|
+
throw new TypeError('Expected "' + token.name + '" to not repeat, but got array')
|
186
155
|
}
|
187
156
|
|
188
157
|
if (value.length === 0) {
|
189
|
-
if (token.optional)
|
190
|
-
|
191
|
-
|
192
|
-
throw new TypeError('Expected "' + token.name + '" to not be empty')
|
193
|
-
}
|
158
|
+
if (token.optional) continue
|
159
|
+
|
160
|
+
throw new TypeError('Expected "' + token.name + '" to not be empty')
|
194
161
|
}
|
195
162
|
|
196
163
|
for (var j = 0; j < value.length; j++) {
|
197
164
|
segment = encode(value[j])
|
198
165
|
|
199
166
|
if (!matches[i].test(segment)) {
|
200
|
-
throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '"
|
167
|
+
throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '"')
|
201
168
|
}
|
202
169
|
|
203
170
|
path += (j === 0 ? token.prefix : token.delimiter) + segment
|
@@ -206,13 +173,25 @@ function tokensToFunction (tokens) {
|
|
206
173
|
continue
|
207
174
|
}
|
208
175
|
|
209
|
-
|
176
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
|
177
|
+
segment = encode(String(value))
|
210
178
|
|
211
|
-
|
212
|
-
|
179
|
+
if (!matches[i].test(segment)) {
|
180
|
+
throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but got "' + segment + '"')
|
181
|
+
}
|
182
|
+
|
183
|
+
path += token.prefix + segment
|
184
|
+
continue
|
185
|
+
}
|
186
|
+
|
187
|
+
if (token.optional) {
|
188
|
+
// Prepend partial segment prefixes.
|
189
|
+
if (token.partial) path += token.prefix
|
190
|
+
|
191
|
+
continue
|
213
192
|
}
|
214
193
|
|
215
|
-
|
194
|
+
throw new TypeError('Expected "' + token.name + '" to be ' + (token.repeat ? 'an array' : 'a string'))
|
216
195
|
}
|
217
196
|
|
218
197
|
return path
|
@@ -226,7 +205,7 @@ function tokensToFunction (tokens) {
|
|
226
205
|
* @return {string}
|
227
206
|
*/
|
228
207
|
function escapeString (str) {
|
229
|
-
return str.replace(/([.+*?=^!:${}()[\]
|
208
|
+
return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1')
|
230
209
|
}
|
231
210
|
|
232
211
|
/**
|
@@ -236,19 +215,7 @@ function escapeString (str) {
|
|
236
215
|
* @return {string}
|
237
216
|
*/
|
238
217
|
function escapeGroup (group) {
|
239
|
-
return group.replace(/([
|
240
|
-
}
|
241
|
-
|
242
|
-
/**
|
243
|
-
* Attach the keys as a property of the regexp.
|
244
|
-
*
|
245
|
-
* @param {!RegExp} re
|
246
|
-
* @param {Array} keys
|
247
|
-
* @return {!RegExp}
|
248
|
-
*/
|
249
|
-
function attachKeys (re, keys) {
|
250
|
-
re.keys = keys
|
251
|
-
return re
|
218
|
+
return group.replace(/([=!:$/()])/g, '\\$1')
|
252
219
|
}
|
253
220
|
|
254
221
|
/**
|
@@ -258,17 +225,19 @@ function attachKeys (re, keys) {
|
|
258
225
|
* @return {string}
|
259
226
|
*/
|
260
227
|
function flags (options) {
|
261
|
-
return options.sensitive ? '' : 'i'
|
228
|
+
return options && options.sensitive ? '' : 'i'
|
262
229
|
}
|
263
230
|
|
264
231
|
/**
|
265
232
|
* Pull out keys from a regexp.
|
266
233
|
*
|
267
234
|
* @param {!RegExp} path
|
268
|
-
* @param {
|
235
|
+
* @param {Array=} keys
|
269
236
|
* @return {!RegExp}
|
270
237
|
*/
|
271
238
|
function regexpToRegexp (path, keys) {
|
239
|
+
if (!keys) return path
|
240
|
+
|
272
241
|
// Use a negative lookahead to match only capturing groups.
|
273
242
|
var groups = path.source.match(/\((?!\?)/g)
|
274
243
|
|
@@ -281,21 +250,20 @@ function regexpToRegexp (path, keys) {
|
|
281
250
|
optional: false,
|
282
251
|
repeat: false,
|
283
252
|
partial: false,
|
284
|
-
asterisk: false,
|
285
253
|
pattern: null
|
286
254
|
})
|
287
255
|
}
|
288
256
|
}
|
289
257
|
|
290
|
-
return
|
258
|
+
return path
|
291
259
|
}
|
292
260
|
|
293
261
|
/**
|
294
262
|
* Transform an array into a regexp.
|
295
263
|
*
|
296
264
|
* @param {!Array} path
|
297
|
-
* @param {Array}
|
298
|
-
* @param {
|
265
|
+
* @param {Array=} keys
|
266
|
+
* @param {Object=} options
|
299
267
|
* @return {!RegExp}
|
300
268
|
*/
|
301
269
|
function arrayToRegexp (path, keys, options) {
|
@@ -305,17 +273,15 @@ function arrayToRegexp (path, keys, options) {
|
|
305
273
|
parts.push(pathToRegexp(path[i], keys, options).source)
|
306
274
|
}
|
307
275
|
|
308
|
-
|
309
|
-
|
310
|
-
return attachKeys(regexp, keys)
|
276
|
+
return new RegExp('(?:' + parts.join('|') + ')', flags(options))
|
311
277
|
}
|
312
278
|
|
313
279
|
/**
|
314
280
|
* Create a path regexp from string input.
|
315
281
|
*
|
316
282
|
* @param {string} path
|
317
|
-
* @param {
|
318
|
-
* @param {
|
283
|
+
* @param {Array=} keys
|
284
|
+
* @param {Object=} options
|
319
285
|
* @return {!RegExp}
|
320
286
|
*/
|
321
287
|
function stringToRegexp (path, keys, options) {
|
@@ -325,24 +291,21 @@ function stringToRegexp (path, keys, options) {
|
|
325
291
|
/**
|
326
292
|
* Expose a function for taking tokens and returning a RegExp.
|
327
293
|
*
|
328
|
-
* @param {!Array}
|
329
|
-
* @param {
|
330
|
-
* @param {Object=}
|
294
|
+
* @param {!Array} tokens
|
295
|
+
* @param {Array=} keys
|
296
|
+
* @param {Object=} options
|
331
297
|
* @return {!RegExp}
|
332
298
|
*/
|
333
299
|
function tokensToRegExp (tokens, keys, options) {
|
334
|
-
if (!isarray(keys)) {
|
335
|
-
options = /** @type {!Object} */ (keys || options)
|
336
|
-
keys = []
|
337
|
-
}
|
338
|
-
|
339
300
|
options = options || {}
|
340
301
|
|
341
302
|
var strict = options.strict
|
342
303
|
var end = options.end !== false
|
304
|
+
var delimiter = escapeString(options.delimiter || DEFAULT_DELIMITER)
|
305
|
+
var delimiters = options.delimiters || DEFAULT_DELIMITERS
|
306
|
+
var endsWith = [].concat(options.endsWith || []).map(escapeString).concat('$').join('|')
|
343
307
|
var route = ''
|
344
|
-
var
|
345
|
-
var endsWithSlash = typeof lastToken === 'string' && /\/$/.test(lastToken)
|
308
|
+
var isEndDelimited = false
|
346
309
|
|
347
310
|
// Iterate over the tokens and create our regexp string.
|
348
311
|
for (var i = 0; i < tokens.length; i++) {
|
@@ -350,47 +313,37 @@ function tokensToRegExp (tokens, keys, options) {
|
|
350
313
|
|
351
314
|
if (typeof token === 'string') {
|
352
315
|
route += escapeString(token)
|
316
|
+
isEndDelimited = i === tokens.length - 1 && delimiters.indexOf(token[token.length - 1]) > -1
|
353
317
|
} else {
|
354
318
|
var prefix = escapeString(token.prefix)
|
355
|
-
var capture =
|
356
|
-
|
357
|
-
|
319
|
+
var capture = token.repeat
|
320
|
+
? '(?:' + token.pattern + ')(?:' + prefix + '(?:' + token.pattern + '))*'
|
321
|
+
: token.pattern
|
358
322
|
|
359
|
-
if (token
|
360
|
-
capture += '(?:' + prefix + capture + ')*'
|
361
|
-
}
|
323
|
+
if (keys) keys.push(token)
|
362
324
|
|
363
325
|
if (token.optional) {
|
364
|
-
if (
|
365
|
-
|
326
|
+
if (token.partial) {
|
327
|
+
route += prefix + '(' + capture + ')?'
|
366
328
|
} else {
|
367
|
-
|
329
|
+
route += '(?:' + prefix + '(' + capture + '))?'
|
368
330
|
}
|
369
331
|
} else {
|
370
|
-
|
332
|
+
route += prefix + '(' + capture + ')'
|
371
333
|
}
|
372
|
-
|
373
|
-
route += capture
|
374
334
|
}
|
375
335
|
}
|
376
336
|
|
377
|
-
// In non-strict mode we allow a slash at the end of match. If the path to
|
378
|
-
// match already ends with a slash, we remove it for consistency. The slash
|
379
|
-
// is valid at the end of a path match, not in the middle. This is important
|
380
|
-
// in non-ending mode, where "/test/" shouldn't match "/test//route".
|
381
|
-
if (!strict) {
|
382
|
-
route = (endsWithSlash ? route.slice(0, -2) : route) + '(?:\\/(?=$))?'
|
383
|
-
}
|
384
|
-
|
385
337
|
if (end) {
|
386
|
-
route += '
|
338
|
+
if (!strict) route += '(?:' + delimiter + ')?'
|
339
|
+
|
340
|
+
route += endsWith === '$' ? '$' : '(?=' + endsWith + ')'
|
387
341
|
} else {
|
388
|
-
|
389
|
-
|
390
|
-
route += strict && endsWithSlash ? '' : '(?=\\/|$)'
|
342
|
+
if (!strict) route += '(?:' + delimiter + '(?=' + endsWith + '))?'
|
343
|
+
if (!isEndDelimited) route += '(?=' + delimiter + '|' + endsWith + ')'
|
391
344
|
}
|
392
345
|
|
393
|
-
return
|
346
|
+
return new RegExp('^' + route, flags(options))
|
394
347
|
}
|
395
348
|
|
396
349
|
/**
|
@@ -401,25 +354,18 @@ function tokensToRegExp (tokens, keys, options) {
|
|
401
354
|
* contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
|
402
355
|
*
|
403
356
|
* @param {(string|RegExp|Array)} path
|
404
|
-
* @param {
|
357
|
+
* @param {Array=} keys
|
405
358
|
* @param {Object=} options
|
406
359
|
* @return {!RegExp}
|
407
360
|
*/
|
408
361
|
function pathToRegexp (path, keys, options) {
|
409
|
-
if (!isarray(keys)) {
|
410
|
-
options = /** @type {!Object} */ (keys || options)
|
411
|
-
keys = []
|
412
|
-
}
|
413
|
-
|
414
|
-
options = options || {}
|
415
|
-
|
416
362
|
if (path instanceof RegExp) {
|
417
|
-
return regexpToRegexp(path,
|
363
|
+
return regexpToRegexp(path, keys)
|
418
364
|
}
|
419
365
|
|
420
|
-
if (
|
421
|
-
return arrayToRegexp(/** @type {!Array} */ (path),
|
366
|
+
if (Array.isArray(path)) {
|
367
|
+
return arrayToRegexp(/** @type {!Array} */ (path), keys, options)
|
422
368
|
}
|
423
369
|
|
424
|
-
return stringToRegexp(/** @type {string} */ (path),
|
370
|
+
return stringToRegexp(/** @type {string} */ (path), keys, options)
|
425
371
|
}
|
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": "1.
|
4
|
+
"version": "2.1.0",
|
5
5
|
"main": "index.js",
|
6
6
|
"typings": "index.d.ts",
|
7
7
|
"files": [
|
@@ -13,7 +13,6 @@
|
|
13
13
|
"lint": "standard",
|
14
14
|
"test-spec": "mocha --require ts-node/register -R spec --bail test.ts",
|
15
15
|
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --require ts-node/register -R spec test.ts",
|
16
|
-
"prepublish": "typings install",
|
17
16
|
"test": "npm run lint && npm run test-cov"
|
18
17
|
},
|
19
18
|
"keywords": [
|
@@ -33,15 +32,14 @@
|
|
33
32
|
"url": "https://github.com/pillarjs/path-to-regexp.git"
|
34
33
|
},
|
35
34
|
"devDependencies": {
|
36
|
-
"chai": "^
|
37
|
-
"
|
38
|
-
"
|
39
|
-
"
|
40
|
-
"
|
41
|
-
"
|
42
|
-
"
|
43
|
-
|
44
|
-
|
45
|
-
"isarray": "0.0.1"
|
35
|
+
"@types/chai": "^4.0.4",
|
36
|
+
"@types/mocha": "^2.2.42",
|
37
|
+
"@types/node": "^8.0.24",
|
38
|
+
"chai": "^4.1.1",
|
39
|
+
"istanbul": "^0.4.5",
|
40
|
+
"mocha": "^3.5.0",
|
41
|
+
"standard": "^10.0.3",
|
42
|
+
"ts-node": "^3.3.0",
|
43
|
+
"typescript": "^2.4.2"
|
46
44
|
}
|
47
45
|
}
|