path-to-regexp 1.7.0 → 2.2.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 +28 -0
- package/Readme.md +32 -49
- package/index.d.ts +14 -11
- package/index.js +101 -156
- package/package.json +10 -12
package/History.md
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
2.1.0 / 2018-03-06
|
2
|
+
==================
|
3
|
+
|
4
|
+
* Pass `token` as second argument to `encode` option (e.g. `encode(value, token)`)
|
5
|
+
|
6
|
+
2.1.0 / 2017-10-20
|
7
|
+
==================
|
8
|
+
|
9
|
+
* Handle non-ending paths where the final character is a delimiter
|
10
|
+
* E.g. `/foo/` before required either `/foo/` or `/foo//` to match in non-ending mode
|
11
|
+
|
12
|
+
2.0.0 / 2017-08-23
|
13
|
+
==================
|
14
|
+
|
15
|
+
* New option! Ability to set `endsWith` to match paths like `/test?query=string` up to the query string
|
16
|
+
* New option! Set `delimiters` for specific characters to be treated as parameter prefixes (e.g. `/:test`)
|
17
|
+
* Remove `isarray` dependency
|
18
|
+
* Explicitly handle trailing delimiters instead of trimming them (e.g. `/test/` is now treated as `/test/` instead of `/test` when matching)
|
19
|
+
* Remove overloaded `keys` argument that accepted `options`
|
20
|
+
* Remove `keys` list attached to the `RegExp` output
|
21
|
+
* Remove asterisk functionality (it's a real pain to properly encode)
|
22
|
+
* Change `tokensToFunction` (e.g. `compile`) to accept an `encode` function for pretty encoding (e.g. pass your own implementation)
|
23
|
+
|
24
|
+
1.7.0 / 2016-11-08
|
25
|
+
==================
|
26
|
+
|
27
|
+
* Allow a `delimiter` option to be passed in with `tokensToRegExp` which will be used for "non-ending" token match situations
|
28
|
+
|
1
29
|
1.6.0 / 2016-10-03
|
2
30
|
==================
|
3
31
|
|
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,42 +43,34 @@ 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')
|
58
61
|
//=> ['/test/route', 'test', 'route']
|
59
62
|
```
|
60
63
|
|
61
|
-
**Please note:**
|
64
|
+
**Please note:** Parameter names must be made up of "word characters" (`[A-Za-z0-9_]`).
|
62
65
|
|
63
|
-
|
64
|
-
var re = pathToRegexp('/(apple-)?icon-:res(\\d+).png', keys)
|
65
|
-
// keys = [{ name: 0, prefix: '/', ... }, { name: 'res', prefix: '', ... }]
|
66
|
-
|
67
|
-
re.exec('/icon-76.png')
|
68
|
-
//=> ['/icon-76.png', undefined, '76']
|
69
|
-
```
|
70
|
-
|
71
|
-
#### Modified Parameters
|
66
|
+
#### Parameter Modifiers
|
72
67
|
|
73
68
|
##### Optional
|
74
69
|
|
75
|
-
Parameters can be suffixed with a question mark (`?`) to make the parameter optional.
|
70
|
+
Parameters can be suffixed with a question mark (`?`) to make the parameter optional.
|
76
71
|
|
77
72
|
```js
|
78
|
-
var re = pathToRegexp('/:foo/:bar?'
|
73
|
+
var re = pathToRegexp('/:foo/:bar?')
|
79
74
|
// keys = [{ name: 'foo', ... }, { name: 'bar', delimiter: '/', optional: true, repeat: false }]
|
80
75
|
|
81
76
|
re.exec('/test')
|
@@ -85,12 +80,14 @@ re.exec('/test/route')
|
|
85
80
|
//=> ['/test', 'test', 'route']
|
86
81
|
```
|
87
82
|
|
83
|
+
**Tip:** If the parameter is the _only_ value in the segment, the prefix is also optional.
|
84
|
+
|
88
85
|
##### Zero or more
|
89
86
|
|
90
87
|
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
88
|
|
92
89
|
```js
|
93
|
-
var re = pathToRegexp('/:foo*'
|
90
|
+
var re = pathToRegexp('/:foo*')
|
94
91
|
// keys = [{ name: 'foo', delimiter: '/', optional: true, repeat: true }]
|
95
92
|
|
96
93
|
re.exec('/')
|
@@ -105,7 +102,7 @@ re.exec('/bar/baz')
|
|
105
102
|
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
103
|
|
107
104
|
```js
|
108
|
-
var re = pathToRegexp('/:foo+'
|
105
|
+
var re = pathToRegexp('/:foo+')
|
109
106
|
// keys = [{ name: 'foo', delimiter: '/', optional: false, repeat: true }]
|
110
107
|
|
111
108
|
re.exec('/')
|
@@ -115,18 +112,18 @@ re.exec('/bar/baz')
|
|
115
112
|
//=> ['/bar/baz', 'bar/baz']
|
116
113
|
```
|
117
114
|
|
118
|
-
#### Custom
|
115
|
+
#### Custom Matching Parameters
|
119
116
|
|
120
|
-
All parameters can be provided a custom regexp, which overrides the default (`[^\/]+`).
|
117
|
+
All parameters can be provided a custom regexp, which overrides the default match (`[^\/]+`). For example, you can match digits in the path:
|
121
118
|
|
122
119
|
```js
|
123
|
-
var re = pathToRegexp('
|
120
|
+
var re = pathToRegexp('/icon-:foo(\\d+).png')
|
124
121
|
// keys = [{ name: 'foo', ... }]
|
125
122
|
|
126
|
-
re.exec('/123')
|
127
|
-
//=> ['/123', '123']
|
123
|
+
re.exec('/icon-123.png')
|
124
|
+
//=> ['/icon-123.png', '123']
|
128
125
|
|
129
|
-
re.exec('/abc')
|
126
|
+
re.exec('/icon-abc.png')
|
130
127
|
//=> null
|
131
128
|
```
|
132
129
|
|
@@ -137,25 +134,13 @@ re.exec('/abc')
|
|
137
134
|
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
135
|
|
139
136
|
```js
|
140
|
-
var re = pathToRegexp('/:foo/(.*)'
|
137
|
+
var re = pathToRegexp('/:foo/(.*)')
|
141
138
|
// keys = [{ name: 'foo', ... }, { name: 0, ... }]
|
142
139
|
|
143
140
|
re.exec('/test/route')
|
144
141
|
//=> ['/test/route', 'test', 'route']
|
145
142
|
```
|
146
143
|
|
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
144
|
### Parse
|
160
145
|
|
161
146
|
The parse function is exposed via `pathToRegexp.parse`. This will return an array of strings and keys.
|
@@ -173,11 +158,11 @@ console.log(tokens[2])
|
|
173
158
|
//=> { name: 0, prefix: '/', delimiter: '/', optional: false, repeat: false, pattern: '.*' }
|
174
159
|
```
|
175
160
|
|
176
|
-
**Note:** This method only works with
|
161
|
+
**Note:** This method only works with strings.
|
177
162
|
|
178
163
|
### Compile ("Reverse" Path-To-RegExp)
|
179
164
|
|
180
|
-
Path-To-RegExp exposes a compile function for transforming
|
165
|
+
Path-To-RegExp exposes a compile function for transforming a string into a valid path.
|
181
166
|
|
182
167
|
```js
|
183
168
|
var toPath = pathToRegexp.compile('/user/:id')
|
@@ -186,8 +171,8 @@ toPath({ id: 123 }) //=> "/user/123"
|
|
186
171
|
toPath({ id: 'café' }) //=> "/user/caf%C3%A9"
|
187
172
|
toPath({ id: '/' }) //=> "/user/%2F"
|
188
173
|
|
189
|
-
toPath({ id: '
|
190
|
-
toPath({ id: '
|
174
|
+
toPath({ id: ':/' }) //=> "/user/%3A%2F"
|
175
|
+
toPath({ id: ':/' }, { encode: (value, token) => value }) //=> "/user/:/"
|
191
176
|
|
192
177
|
var toPathRepeated = pathToRegexp.compile('/:segment+')
|
193
178
|
|
@@ -219,17 +204,15 @@ Path-To-RegExp exposes the two functions used internally that accept an array of
|
|
219
204
|
* `repeat` Indicates the token is repeated (`boolean`)
|
220
205
|
* `partial` Indicates this token is a partial path segment (`boolean`)
|
221
206
|
* `pattern` The RegExp used to match this token (`string`)
|
222
|
-
* `asterisk` Indicates the token is an `*` match (`boolean`)
|
223
207
|
|
224
208
|
## Compatibility with Express <= 4.x
|
225
209
|
|
226
210
|
Path-To-RegExp breaks compatibility with Express <= `4.x`:
|
227
211
|
|
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
|
212
|
+
* RegExp special characters can only be used in a parameter
|
213
|
+
* Express.js 4.x used all `RegExp` special characters regardless of position - this considered a bug
|
232
214
|
* Parameters have suffixes that augment meaning - `*`, `+` and `?`. E.g. `/:user*`
|
215
|
+
* No wildcard asterisk (`*`) - use parameters instead (`(.*)`)
|
233
216
|
|
234
217
|
## TypeScript
|
235
218
|
|
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`)
|
@@ -24,6 +18,10 @@ declare namespace pathToRegexp {
|
|
24
18
|
* Sets the final character for non-ending optimistic matches. (default: `/`)
|
25
19
|
*/
|
26
20
|
delimiter?: string;
|
21
|
+
/**
|
22
|
+
* List of characters that can also be "end" characters.
|
23
|
+
*/
|
24
|
+
endsWith?: string | string[];
|
27
25
|
}
|
28
26
|
|
29
27
|
export interface ParseOptions {
|
@@ -31,6 +29,10 @@ declare namespace pathToRegexp {
|
|
31
29
|
* Set the default delimiter for repeat parameters. (default: `'/'`)
|
32
30
|
*/
|
33
31
|
delimiter?: string;
|
32
|
+
/**
|
33
|
+
* List of valid delimiter characters. (default: `'./'`)
|
34
|
+
*/
|
35
|
+
delimiters?: string | string[];
|
34
36
|
}
|
35
37
|
|
36
38
|
/**
|
@@ -51,8 +53,7 @@ declare namespace pathToRegexp {
|
|
51
53
|
/**
|
52
54
|
* Transform an array of tokens into a matching regular expression.
|
53
55
|
*/
|
54
|
-
export function tokensToRegExp (tokens: Token[], options?: RegExpOptions):
|
55
|
-
export function tokensToRegExp (tokens: Token[], keys?: Key[], options?: RegExpOptions): PathRegExp;
|
56
|
+
export function tokensToRegExp (tokens: Token[], keys?: Key[], options?: RegExpOptions): RegExp;
|
56
57
|
|
57
58
|
export interface Key {
|
58
59
|
name: string | number;
|
@@ -62,11 +63,13 @@ declare namespace pathToRegexp {
|
|
62
63
|
repeat: boolean;
|
63
64
|
pattern: string;
|
64
65
|
partial: boolean;
|
65
|
-
asterisk: boolean;
|
66
66
|
}
|
67
67
|
|
68
68
|
interface PathFunctionOptions {
|
69
|
-
|
69
|
+
/**
|
70
|
+
* Function for encoding input strings for output.
|
71
|
+
*/
|
72
|
+
encode?: (value: string, token: Key) => string;
|
70
73
|
}
|
71
74
|
|
72
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
|
-
segment = encode(value[j])
|
164
|
+
segment = encode(value[j], token)
|
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), token)
|
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,22 +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 = ''
|
308
|
+
var isEndDelimited = false
|
344
309
|
|
345
310
|
// Iterate over the tokens and create our regexp string.
|
346
311
|
for (var i = 0; i < tokens.length; i++) {
|
@@ -348,50 +313,37 @@ function tokensToRegExp (tokens, keys, options) {
|
|
348
313
|
|
349
314
|
if (typeof token === 'string') {
|
350
315
|
route += escapeString(token)
|
316
|
+
isEndDelimited = i === tokens.length - 1 && delimiters.indexOf(token[token.length - 1]) > -1
|
351
317
|
} else {
|
352
318
|
var prefix = escapeString(token.prefix)
|
353
|
-
var capture =
|
319
|
+
var capture = token.repeat
|
320
|
+
? '(?:' + token.pattern + ')(?:' + prefix + '(?:' + token.pattern + '))*'
|
321
|
+
: token.pattern
|
354
322
|
|
355
|
-
keys.push(token)
|
356
|
-
|
357
|
-
if (token.repeat) {
|
358
|
-
capture += '(?:' + prefix + capture + ')*'
|
359
|
-
}
|
323
|
+
if (keys) keys.push(token)
|
360
324
|
|
361
325
|
if (token.optional) {
|
362
|
-
if (
|
363
|
-
|
326
|
+
if (token.partial) {
|
327
|
+
route += prefix + '(' + capture + ')?'
|
364
328
|
} else {
|
365
|
-
|
329
|
+
route += '(?:' + prefix + '(' + capture + '))?'
|
366
330
|
}
|
367
331
|
} else {
|
368
|
-
|
332
|
+
route += prefix + '(' + capture + ')'
|
369
333
|
}
|
370
|
-
|
371
|
-
route += capture
|
372
334
|
}
|
373
335
|
}
|
374
336
|
|
375
|
-
var delimiter = escapeString(options.delimiter || '/')
|
376
|
-
var endsWithDelimiter = route.slice(-delimiter.length) === delimiter
|
377
|
-
|
378
|
-
// In non-strict mode we allow a slash at the end of match. If the path to
|
379
|
-
// match already ends with a slash, we remove it for consistency. The slash
|
380
|
-
// is valid at the end of a path match, not in the middle. This is important
|
381
|
-
// in non-ending mode, where "/test/" shouldn't match "/test//route".
|
382
|
-
if (!strict) {
|
383
|
-
route = (endsWithDelimiter ? route.slice(0, -delimiter.length) : route) + '(?:' + delimiter + '(?=$))?'
|
384
|
-
}
|
385
|
-
|
386
337
|
if (end) {
|
387
|
-
route += '
|
338
|
+
if (!strict) route += '(?:' + delimiter + ')?'
|
339
|
+
|
340
|
+
route += endsWith === '$' ? '$' : '(?=' + endsWith + ')'
|
388
341
|
} else {
|
389
|
-
|
390
|
-
|
391
|
-
route += strict && endsWithDelimiter ? '' : '(?=' + delimiter + '|$)'
|
342
|
+
if (!strict) route += '(?:' + delimiter + '(?=' + endsWith + '))?'
|
343
|
+
if (!isEndDelimited) route += '(?=' + delimiter + '|' + endsWith + ')'
|
392
344
|
}
|
393
345
|
|
394
|
-
return
|
346
|
+
return new RegExp('^' + route, flags(options))
|
395
347
|
}
|
396
348
|
|
397
349
|
/**
|
@@ -402,25 +354,18 @@ function tokensToRegExp (tokens, keys, options) {
|
|
402
354
|
* contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
|
403
355
|
*
|
404
356
|
* @param {(string|RegExp|Array)} path
|
405
|
-
* @param {
|
357
|
+
* @param {Array=} keys
|
406
358
|
* @param {Object=} options
|
407
359
|
* @return {!RegExp}
|
408
360
|
*/
|
409
361
|
function pathToRegexp (path, keys, options) {
|
410
|
-
if (!isarray(keys)) {
|
411
|
-
options = /** @type {!Object} */ (keys || options)
|
412
|
-
keys = []
|
413
|
-
}
|
414
|
-
|
415
|
-
options = options || {}
|
416
|
-
|
417
362
|
if (path instanceof RegExp) {
|
418
|
-
return regexpToRegexp(path,
|
363
|
+
return regexpToRegexp(path, keys)
|
419
364
|
}
|
420
365
|
|
421
|
-
if (
|
422
|
-
return arrayToRegexp(/** @type {!Array} */ (path),
|
366
|
+
if (Array.isArray(path)) {
|
367
|
+
return arrayToRegexp(/** @type {!Array} */ (path), keys, options)
|
423
368
|
}
|
424
369
|
|
425
|
-
return stringToRegexp(/** @type {string} */ (path),
|
370
|
+
return stringToRegexp(/** @type {string} */ (path), keys, options)
|
426
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": "
|
4
|
+
"version": "2.2.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
|
}
|