forked from pillarjs/path-to-regexp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
132 lines (110 loc) · 4.11 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/**
* Expose `pathtoRegexp`.
*/
module.exports = pathtoRegexp;
var PATH_REGEXP = new RegExp([
// Match already escaped characters that would otherwise incorrectly appear
// in future matches. This allows the user to escape special characters that
// shouldn't be transformed.
'(\\\\.)',
// Match Express-style parameters and un-named parameters with a prefix
// and optional suffixes. Matches appear as:
//
// "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?"]
// "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined]
'([\\/.])?(?:\\:(\\w+)(?:\\((.+)\\))?|\\((.+)\\))([+*?])?',
// Match regexp special characters that should always be escaped.
'([.+*?=^!:${}()[\\]|\\/])'
].join('|'), 'g');
/**
* Escape the capturing group by escaping special characters and meaning.
*
* @param {String} group
* @return {String}
*/
function escapeGroup (group) {
return group.replace(/([=!:$\/()])/g, '\\$1');
}
/**
* Normalize the given path string, returning a regular expression.
*
* An empty array should be passed in, which will contain the placeholder key
* names. For example `/user/:id` will then contain `["id"]`.
*
* @param {(String|RegExp|Array)} path
* @param {Array} keys
* @param {Object} options
* @return {RegExp}
*/
function pathtoRegexp (path, keys, options) {
keys = keys || [];
options = options || {};
var strict = options.strict;
var end = options.end !== false;
var flags = options.sensitive ? '' : 'i';
var index = 0;
if (path instanceof RegExp) {
// Match all capturing groups of a regexp.
var groups = path.source.match(/\((?!\?)/g) || [];
// Map all the matches to their numeric keys and push into the keys.
keys.push.apply(keys, groups.map(function (m, i) { return i; }));
// Return the source back to the user.
return path;
}
if (Array.isArray(path)) {
// Map array parts into regexps and return their source. We also pass
// the same keys and options instance into every generation to get
// consistent matching groups before we join the sources together.
path = path.map(function (value) {
return pathtoRegexp(value, keys, options).source;
});
// Generate a new regexp instance by joining all the parts together.
return new RegExp('(?:' + path.join('|') + ')', flags);
}
// Alter the path string into a usable regexp.
path = path.replace(PATH_REGEXP, function (match, escaped, prefix, key, capture, group, suffix, escape) {
// Avoiding re-escaping escaped characters.
if (escaped) {
return escaped;
}
// Escape regexp special characters.
if (escape) {
return '\\' + escape;
}
keys.push(key || index++);
// Special behaviour for format params.
var format = prefix === '.' ? '\\.' : '';
// Escape the prefix character.
prefix = prefix ? '\\' + prefix : '';
// Match using the custom capturing group, or fallback to capturing
// everything up to the next slash (or next period if the param was
// prefixed with a period).
capture = escapeGroup(capture || group || '[^\\/' + format + ']+?');
// More complex regexp is required for suffix support.
if (suffix) {
if (suffix === '+') {
return prefix + '(' + capture + '(?:' + prefix + capture + ')*)'
}
if (suffix === '*') {
return '(?:' + prefix + '(' + capture + '(?:' + prefix + capture + ')*|' + capture + '))?';
}
return '(?:' + prefix + '(' + capture + '))?';
}
// Basic parameter support.
return prefix + '(' + capture + ')';
});
if (path[path.length - 1] !== '/') {
// If we are doing a non-ending match, we need to prompt the matching groups
// to match as much as possible. To do this, we add a positive lookahead for
// the next path fragment or the end. However, if the regexp already ends
// in a path fragment, we'll run into problems.
if (!end) {
path += '(?=\\/|$)';
}
// Allow trailing slashes to be matched in non-strict, ending mode.
if (end && !strict) {
path += '\\/?';
}
}
return new RegExp('^' + path + (end ? '$' : ''), flags);
};