path-to-regexp 7.1.0 → 8.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/Readme.md +65 -204
- package/dist/index.d.ts +50 -77
- package/dist/index.js +258 -307
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
@@ -1,106 +1,129 @@
|
|
1
1
|
"use strict";
|
2
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
5
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
6
|
+
};
|
7
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
8
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
11
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
12
|
+
};
|
13
|
+
var _Iter_peek;
|
2
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
15
|
exports.TokenData = void 0;
|
4
16
|
exports.parse = parse;
|
5
17
|
exports.compile = compile;
|
6
18
|
exports.match = match;
|
7
|
-
exports.pathToRegexp = pathToRegexp;
|
8
19
|
const DEFAULT_DELIMITER = "/";
|
9
20
|
const NOOP_VALUE = (value) => value;
|
10
|
-
const
|
21
|
+
const ID_START = /^[$_\p{ID_Start}]$/u;
|
22
|
+
const ID_CONTINUE = /^[$\u200c\u200d\p{ID_Continue}]$/u;
|
11
23
|
const DEBUG_URL = "https://git.new/pathToRegexpError";
|
12
24
|
const SIMPLE_TOKENS = {
|
13
|
-
|
14
|
-
"@": "@",
|
15
|
-
";": ";",
|
16
|
-
",": ",",
|
17
|
-
"*": "*",
|
18
|
-
"+": "+",
|
19
|
-
"?": "?",
|
25
|
+
// Groups.
|
20
26
|
"{": "{",
|
21
27
|
"}": "}",
|
28
|
+
// Reserved.
|
29
|
+
"(": "(",
|
30
|
+
")": ")",
|
31
|
+
"[": "[",
|
32
|
+
"]": "]",
|
33
|
+
"+": "+",
|
34
|
+
"?": "?",
|
35
|
+
"!": "!",
|
22
36
|
};
|
37
|
+
/**
|
38
|
+
* Escape a regular expression string.
|
39
|
+
*/
|
40
|
+
function escape(str) {
|
41
|
+
return str.replace(/[.+*?^${}()[\]|/\\]/g, "\\$&");
|
42
|
+
}
|
43
|
+
/**
|
44
|
+
* Get the flags for a regexp from the options.
|
45
|
+
*/
|
46
|
+
function toFlags(options) {
|
47
|
+
return options.sensitive ? "s" : "is";
|
48
|
+
}
|
23
49
|
/**
|
24
50
|
* Tokenize input string.
|
25
51
|
*/
|
26
|
-
function lexer(str) {
|
52
|
+
function* lexer(str) {
|
27
53
|
const chars = [...str];
|
28
|
-
const tokens = [];
|
29
54
|
let i = 0;
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
}
|
37
|
-
if (value === "\\") {
|
38
|
-
tokens.push({ type: "ESCAPED", index: i++, value: chars[i++] });
|
39
|
-
continue;
|
40
|
-
}
|
41
|
-
if (value === ":") {
|
42
|
-
let name = "";
|
43
|
-
while (ID_CHAR.test(chars[++i])) {
|
44
|
-
name += chars[i];
|
55
|
+
function name() {
|
56
|
+
let value = "";
|
57
|
+
if (ID_START.test(chars[++i])) {
|
58
|
+
value += chars[i];
|
59
|
+
while (ID_CONTINUE.test(chars[++i])) {
|
60
|
+
value += chars[i];
|
45
61
|
}
|
46
|
-
if (!name) {
|
47
|
-
throw new TypeError(`Missing parameter name at ${i}`);
|
48
|
-
}
|
49
|
-
tokens.push({ type: "NAME", index: i, value: name });
|
50
|
-
continue;
|
51
62
|
}
|
52
|
-
if (
|
53
|
-
|
54
|
-
let count = 1;
|
55
|
-
let pattern = "";
|
56
|
-
if (chars[i] === "?") {
|
57
|
-
throw new TypeError(`Pattern cannot start with "?" at ${i}`);
|
58
|
-
}
|
63
|
+
else if (chars[i] === '"') {
|
64
|
+
let pos = i;
|
59
65
|
while (i < chars.length) {
|
60
|
-
if (chars[i] === "
|
61
|
-
|
62
|
-
|
66
|
+
if (chars[++i] === '"') {
|
67
|
+
i++;
|
68
|
+
pos = 0;
|
69
|
+
break;
|
63
70
|
}
|
64
|
-
if (chars[i] === "
|
65
|
-
|
66
|
-
if (count === 0) {
|
67
|
-
i++;
|
68
|
-
break;
|
69
|
-
}
|
71
|
+
if (chars[i] === "\\") {
|
72
|
+
value += chars[++i];
|
70
73
|
}
|
71
|
-
else
|
72
|
-
|
73
|
-
if (chars[i + 1] !== "?") {
|
74
|
-
throw new TypeError(`Capturing groups are not allowed at ${i}`);
|
75
|
-
}
|
74
|
+
else {
|
75
|
+
value += chars[i];
|
76
76
|
}
|
77
|
-
pattern += chars[i++];
|
78
77
|
}
|
79
|
-
if (
|
80
|
-
throw new TypeError(`
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
78
|
+
if (pos) {
|
79
|
+
throw new TypeError(`Unterminated quote at ${pos}: ${DEBUG_URL}`);
|
80
|
+
}
|
81
|
+
}
|
82
|
+
if (!value) {
|
83
|
+
throw new TypeError(`Missing parameter name at ${i}: ${DEBUG_URL}`);
|
84
|
+
}
|
85
|
+
return value;
|
86
|
+
}
|
87
|
+
while (i < chars.length) {
|
88
|
+
const value = chars[i];
|
89
|
+
const type = SIMPLE_TOKENS[value];
|
90
|
+
if (type) {
|
91
|
+
yield { type, index: i++, value };
|
92
|
+
}
|
93
|
+
else if (value === "\\") {
|
94
|
+
yield { type: "ESCAPED", index: i++, value: chars[i++] };
|
95
|
+
}
|
96
|
+
else if (value === ":") {
|
97
|
+
const value = name();
|
98
|
+
yield { type: "PARAM", index: i, value };
|
99
|
+
}
|
100
|
+
else if (value === "*") {
|
101
|
+
const value = name();
|
102
|
+
yield { type: "WILDCARD", index: i, value };
|
103
|
+
}
|
104
|
+
else {
|
105
|
+
yield { type: "CHAR", index: i, value: chars[i++] };
|
85
106
|
}
|
86
|
-
tokens.push({ type: "CHAR", index: i, value: chars[i++] });
|
87
107
|
}
|
88
|
-
|
89
|
-
return new Iter(tokens);
|
108
|
+
return { type: "END", index: i, value: "" };
|
90
109
|
}
|
91
110
|
class Iter {
|
92
111
|
constructor(tokens) {
|
93
112
|
this.tokens = tokens;
|
94
|
-
this
|
113
|
+
_Iter_peek.set(this, void 0);
|
95
114
|
}
|
96
115
|
peek() {
|
97
|
-
|
116
|
+
if (!__classPrivateFieldGet(this, _Iter_peek, "f")) {
|
117
|
+
const next = this.tokens.next();
|
118
|
+
__classPrivateFieldSet(this, _Iter_peek, next.value, "f");
|
119
|
+
}
|
120
|
+
return __classPrivateFieldGet(this, _Iter_peek, "f");
|
98
121
|
}
|
99
122
|
tryConsume(type) {
|
100
123
|
const token = this.peek();
|
101
124
|
if (token.type !== type)
|
102
125
|
return;
|
103
|
-
this.
|
126
|
+
__classPrivateFieldSet(this, _Iter_peek, undefined, "f"); // Reset after consumed.
|
104
127
|
return token.value;
|
105
128
|
}
|
106
129
|
consume(type) {
|
@@ -118,17 +141,14 @@ class Iter {
|
|
118
141
|
}
|
119
142
|
return result;
|
120
143
|
}
|
121
|
-
modifier() {
|
122
|
-
return this.tryConsume("?") || this.tryConsume("*") || this.tryConsume("+");
|
123
|
-
}
|
124
144
|
}
|
145
|
+
_Iter_peek = new WeakMap();
|
125
146
|
/**
|
126
|
-
* Tokenized path instance.
|
147
|
+
* Tokenized path instance.
|
127
148
|
*/
|
128
149
|
class TokenData {
|
129
|
-
constructor(tokens
|
150
|
+
constructor(tokens) {
|
130
151
|
this.tokens = tokens;
|
131
|
-
this.delimiter = delimiter;
|
132
152
|
}
|
133
153
|
}
|
134
154
|
exports.TokenData = TokenData;
|
@@ -136,177 +156,154 @@ exports.TokenData = TokenData;
|
|
136
156
|
* Parse a string for the raw tokens.
|
137
157
|
*/
|
138
158
|
function parse(str, options = {}) {
|
139
|
-
const { encodePath = NOOP_VALUE
|
140
|
-
const
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
const next = it.peek();
|
155
|
-
if (next.type === "*") {
|
156
|
-
throw new TypeError(`Unexpected * at ${next.index}, you probably want \`/*\` or \`{/:foo}*\`: ${DEBUG_URL}`);
|
159
|
+
const { encodePath = NOOP_VALUE } = options;
|
160
|
+
const it = new Iter(lexer(str));
|
161
|
+
function consume(endType) {
|
162
|
+
const tokens = [];
|
163
|
+
while (true) {
|
164
|
+
const path = it.text();
|
165
|
+
if (path)
|
166
|
+
tokens.push({ type: "text", value: encodePath(path) });
|
167
|
+
const param = it.tryConsume("PARAM");
|
168
|
+
if (param) {
|
169
|
+
tokens.push({
|
170
|
+
type: "param",
|
171
|
+
name: param,
|
172
|
+
});
|
173
|
+
continue;
|
157
174
|
}
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
175
|
+
const wildcard = it.tryConsume("WILDCARD");
|
176
|
+
if (wildcard) {
|
177
|
+
tokens.push({
|
178
|
+
type: "wildcard",
|
179
|
+
name: wildcard,
|
180
|
+
});
|
181
|
+
continue;
|
182
|
+
}
|
183
|
+
const open = it.tryConsume("{");
|
184
|
+
if (open) {
|
185
|
+
tokens.push({
|
186
|
+
type: "group",
|
187
|
+
tokens: consume("}"),
|
188
|
+
});
|
189
|
+
continue;
|
190
|
+
}
|
191
|
+
it.consume(endType);
|
192
|
+
return tokens;
|
169
193
|
}
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
modifier,
|
185
|
-
separator,
|
186
|
-
});
|
187
|
-
continue;
|
194
|
+
}
|
195
|
+
const tokens = consume("END");
|
196
|
+
return new TokenData(tokens);
|
197
|
+
}
|
198
|
+
/**
|
199
|
+
* Transform tokens into a path building function.
|
200
|
+
*/
|
201
|
+
function $compile(data, options) {
|
202
|
+
const { encode = encodeURIComponent, delimiter = DEFAULT_DELIMITER } = options;
|
203
|
+
const fn = tokensToFunction(data.tokens, delimiter, encode);
|
204
|
+
return function path(data = {}) {
|
205
|
+
const [path, ...missing] = fn(data);
|
206
|
+
if (missing.length) {
|
207
|
+
throw new TypeError(`Missing parameters: ${missing.join(", ")}`);
|
188
208
|
}
|
189
|
-
|
190
|
-
|
191
|
-
} while (true);
|
192
|
-
return new TokenData(tokens, delimiter);
|
209
|
+
return path;
|
210
|
+
};
|
193
211
|
}
|
194
212
|
/**
|
195
213
|
* Compile a string to a template function for the path.
|
196
214
|
*/
|
197
215
|
function compile(path, options = {}) {
|
198
|
-
|
199
|
-
|
216
|
+
return $compile(path instanceof TokenData ? path : parse(path, options), options);
|
217
|
+
}
|
218
|
+
function tokensToFunction(tokens, delimiter, encode) {
|
219
|
+
const encoders = tokens.map((token) => tokenToFunction(token, delimiter, encode));
|
220
|
+
return (data) => {
|
221
|
+
const result = [""];
|
222
|
+
for (const encoder of encoders) {
|
223
|
+
const [value, ...extras] = encoder(data);
|
224
|
+
result[0] += value;
|
225
|
+
result.push(...extras);
|
226
|
+
}
|
227
|
+
return result;
|
228
|
+
};
|
200
229
|
}
|
201
230
|
/**
|
202
231
|
* Convert a single token into a path building function.
|
203
232
|
*/
|
204
|
-
function tokenToFunction(token, encode) {
|
205
|
-
if (
|
206
|
-
return () => token;
|
207
|
-
|
208
|
-
|
209
|
-
const repeated = token.modifier === "+" || token.modifier === "*";
|
210
|
-
const optional = token.modifier === "?" || token.modifier === "*";
|
211
|
-
const { prefix = "", suffix = "", separator = suffix + prefix } = token;
|
212
|
-
if (encode && repeated) {
|
213
|
-
const stringify = (value, index) => {
|
214
|
-
if (typeof value !== "string") {
|
215
|
-
throw new TypeError(`Expected "${token.name}/${index}" to be a string`);
|
216
|
-
}
|
217
|
-
return encodeValue(value);
|
218
|
-
};
|
219
|
-
const compile = (value) => {
|
220
|
-
if (!Array.isArray(value)) {
|
221
|
-
throw new TypeError(`Expected "${token.name}" to be an array`);
|
222
|
-
}
|
223
|
-
if (value.length === 0)
|
224
|
-
return "";
|
225
|
-
return prefix + value.map(stringify).join(separator) + suffix;
|
226
|
-
};
|
227
|
-
if (optional) {
|
228
|
-
return (data) => {
|
229
|
-
const value = data[token.name];
|
230
|
-
if (value == null)
|
231
|
-
return "";
|
232
|
-
return value.length ? compile(value) : "";
|
233
|
-
};
|
234
|
-
}
|
233
|
+
function tokenToFunction(token, delimiter, encode) {
|
234
|
+
if (token.type === "text")
|
235
|
+
return () => [token.value];
|
236
|
+
if (token.type === "group") {
|
237
|
+
const fn = tokensToFunction(token.tokens, delimiter, encode);
|
235
238
|
return (data) => {
|
236
|
-
const value = data
|
237
|
-
|
239
|
+
const [value, ...missing] = fn(data);
|
240
|
+
if (!missing.length)
|
241
|
+
return [value];
|
242
|
+
return [""];
|
238
243
|
};
|
239
244
|
}
|
240
|
-
const
|
241
|
-
|
242
|
-
throw new TypeError(`Expected "${token.name}" to be a string`);
|
243
|
-
}
|
244
|
-
return prefix + encodeValue(value) + suffix;
|
245
|
-
};
|
246
|
-
if (optional) {
|
245
|
+
const encodeValue = encode || NOOP_VALUE;
|
246
|
+
if (token.type === "wildcard" && encode !== false) {
|
247
247
|
return (data) => {
|
248
248
|
const value = data[token.name];
|
249
249
|
if (value == null)
|
250
|
-
return "";
|
251
|
-
|
250
|
+
return ["", token.name];
|
251
|
+
if (!Array.isArray(value) || value.length === 0) {
|
252
|
+
throw new TypeError(`Expected "${token.name}" to be a non-empty array`);
|
253
|
+
}
|
254
|
+
return [
|
255
|
+
value
|
256
|
+
.map((value, index) => {
|
257
|
+
if (typeof value !== "string") {
|
258
|
+
throw new TypeError(`Expected "${token.name}/${index}" to be a string`);
|
259
|
+
}
|
260
|
+
return encodeValue(value);
|
261
|
+
})
|
262
|
+
.join(delimiter),
|
263
|
+
];
|
252
264
|
};
|
253
265
|
}
|
254
266
|
return (data) => {
|
255
267
|
const value = data[token.name];
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
function compileTokens(data, options) {
|
263
|
-
const { encode = encodeURIComponent, loose = true, validate = true, strict = false, } = options;
|
264
|
-
const flags = toFlags(options);
|
265
|
-
const stringify = toStringify(loose, data.delimiter);
|
266
|
-
const sources = toRegExpSource(data, stringify, [], flags, strict);
|
267
|
-
// Compile all the tokens into regexps.
|
268
|
-
const encoders = data.tokens.map((token, index) => {
|
269
|
-
const fn = tokenToFunction(token, encode);
|
270
|
-
if (!validate || typeof token === "string")
|
271
|
-
return fn;
|
272
|
-
const validRe = new RegExp(`^${sources[index]}$`, flags);
|
273
|
-
return (data) => {
|
274
|
-
const value = fn(data);
|
275
|
-
if (!validRe.test(value)) {
|
276
|
-
throw new TypeError(`Invalid value for "${token.name}": ${JSON.stringify(value)}`);
|
277
|
-
}
|
278
|
-
return value;
|
279
|
-
};
|
280
|
-
});
|
281
|
-
return function path(data = {}) {
|
282
|
-
let path = "";
|
283
|
-
for (const encoder of encoders)
|
284
|
-
path += encoder(data);
|
285
|
-
return path;
|
268
|
+
if (value == null)
|
269
|
+
return ["", token.name];
|
270
|
+
if (typeof value !== "string") {
|
271
|
+
throw new TypeError(`Expected "${token.name}" to be a string`);
|
272
|
+
}
|
273
|
+
return [encodeValue(value)];
|
286
274
|
};
|
287
275
|
}
|
288
276
|
/**
|
289
277
|
* Create path match function from `path-to-regexp` spec.
|
290
278
|
*/
|
291
|
-
function match(
|
292
|
-
const { decode = decodeURIComponent,
|
293
|
-
const
|
294
|
-
const
|
279
|
+
function $match(data, options = {}) {
|
280
|
+
const { decode = decodeURIComponent, delimiter = DEFAULT_DELIMITER, end = true, trailing = true, } = options;
|
281
|
+
const flags = toFlags(options);
|
282
|
+
const sources = [];
|
295
283
|
const keys = [];
|
296
|
-
const
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
const re = new RegExp(stringify(separator), "g");
|
301
|
-
return (value) => value.split(re).map(decode);
|
284
|
+
for (const { tokens } of data) {
|
285
|
+
for (const seq of flatten(tokens, 0, [])) {
|
286
|
+
const regexp = sequenceToRegExp(seq, delimiter, keys);
|
287
|
+
sources.push(regexp);
|
302
288
|
}
|
303
|
-
|
289
|
+
}
|
290
|
+
let pattern = `^(?:${sources.join("|")})`;
|
291
|
+
if (trailing)
|
292
|
+
pattern += `(?:${escape(delimiter)}$)?`;
|
293
|
+
pattern += end ? "$" : `(?=${escape(delimiter)}|$)`;
|
294
|
+
const re = new RegExp(pattern, flags);
|
295
|
+
const decoders = keys.map((key) => {
|
296
|
+
if (decode === false)
|
297
|
+
return NOOP_VALUE;
|
298
|
+
if (key.type === "param")
|
299
|
+
return decode;
|
300
|
+
return (value) => value.split(delimiter).map(decode);
|
304
301
|
});
|
305
|
-
return function match(input) {
|
302
|
+
return Object.assign(function match(input) {
|
306
303
|
const m = re.exec(input);
|
307
304
|
if (!m)
|
308
305
|
return false;
|
309
|
-
const { 0: path
|
306
|
+
const { 0: path } = m;
|
310
307
|
const params = Object.create(null);
|
311
308
|
for (let i = 1; i < m.length; i++) {
|
312
309
|
if (m[i] === undefined)
|
@@ -315,117 +312,71 @@ function match(path, options = {}) {
|
|
315
312
|
const decoder = decoders[i - 1];
|
316
313
|
params[key.name] = decoder(m[i]);
|
317
314
|
}
|
318
|
-
return { path,
|
319
|
-
};
|
315
|
+
return { path, params };
|
316
|
+
}, { re });
|
320
317
|
}
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
return str.replace(/([.+*?^${}()[\]|/\\])/g, "\\$1");
|
326
|
-
}
|
327
|
-
/**
|
328
|
-
* Escape and repeat loose characters for regular expressions.
|
329
|
-
*/
|
330
|
-
function looseReplacer(value, loose) {
|
331
|
-
const escaped = escape(value);
|
332
|
-
return loose ? `(?:${escaped})+(?!${escaped})` : escaped;
|
333
|
-
}
|
334
|
-
/**
|
335
|
-
* Encode all non-delimiter characters using the encode function.
|
336
|
-
*/
|
337
|
-
function toStringify(loose, delimiter) {
|
338
|
-
if (!loose)
|
339
|
-
return escape;
|
340
|
-
const re = new RegExp(`(?:(?!${escape(delimiter)}).)+|(.)`, "g");
|
341
|
-
return (value) => value.replace(re, looseReplacer);
|
342
|
-
}
|
343
|
-
/**
|
344
|
-
* Get the flags for a regexp from the options.
|
345
|
-
*/
|
346
|
-
function toFlags(options) {
|
347
|
-
return options.sensitive ? "" : "i";
|
318
|
+
function match(path, options = {}) {
|
319
|
+
const paths = Array.isArray(path) ? path : [path];
|
320
|
+
const items = paths.map((path) => path instanceof TokenData ? path : parse(path, options));
|
321
|
+
return $match(items, options);
|
348
322
|
}
|
349
323
|
/**
|
350
|
-
*
|
324
|
+
* Generate a flat list of sequence tokens from the given tokens.
|
351
325
|
*/
|
352
|
-
function
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
const
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
326
|
+
function* flatten(tokens, index, init) {
|
327
|
+
if (index === tokens.length) {
|
328
|
+
return yield init;
|
329
|
+
}
|
330
|
+
const token = tokens[index];
|
331
|
+
if (token.type === "group") {
|
332
|
+
const fork = init.slice();
|
333
|
+
for (const seq of flatten(token.tokens, 0, fork)) {
|
334
|
+
yield* flatten(tokens, index + 1, seq);
|
335
|
+
}
|
336
|
+
}
|
337
|
+
else {
|
338
|
+
init.push(token);
|
339
|
+
}
|
340
|
+
yield* flatten(tokens, index + 1, init);
|
363
341
|
}
|
364
342
|
/**
|
365
|
-
*
|
343
|
+
* Transform a flat sequence of tokens into a regular expression.
|
366
344
|
*/
|
367
|
-
function
|
368
|
-
|
345
|
+
function sequenceToRegExp(tokens, delimiter, keys) {
|
346
|
+
let result = "";
|
369
347
|
let backtrack = "";
|
370
|
-
let
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
348
|
+
let isSafeSegmentParam = true;
|
349
|
+
for (let i = 0; i < tokens.length; i++) {
|
350
|
+
const token = tokens[i];
|
351
|
+
if (token.type === "text") {
|
352
|
+
result += escape(token.value);
|
353
|
+
backtrack = token.value;
|
354
|
+
isSafeSegmentParam || (isSafeSegmentParam = token.value.includes(delimiter));
|
355
|
+
continue;
|
375
356
|
}
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
if (token.name) {
|
380
|
-
const pattern = token.pattern ? `(?:${token.pattern})` : defaultPattern;
|
381
|
-
const re = checkPattern(pattern, token.name, flags);
|
382
|
-
safe || (safe = safePattern(re, prefix || backtrack));
|
383
|
-
if (!safe) {
|
384
|
-
throw new TypeError(`Ambiguous pattern for "${token.name}": ${DEBUG_URL}`);
|
357
|
+
if (token.type === "param" || token.type === "wildcard") {
|
358
|
+
if (!isSafeSegmentParam && !backtrack) {
|
359
|
+
throw new TypeError(`Missing text after "${token.name}": ${DEBUG_URL}`);
|
385
360
|
}
|
386
|
-
|
387
|
-
|
388
|
-
keys.push(token);
|
389
|
-
if (modifier === "+" || modifier === "*") {
|
390
|
-
const mod = modifier === "*" ? "?" : "";
|
391
|
-
const sep = stringify(separator);
|
392
|
-
if (!sep) {
|
393
|
-
throw new TypeError(`Missing separator for "${token.name}": ${DEBUG_URL}`);
|
394
|
-
}
|
395
|
-
safe || (safe = !strict || safePattern(re, separator));
|
396
|
-
if (!safe) {
|
397
|
-
throw new TypeError(`Ambiguous pattern for "${token.name}" separator: ${DEBUG_URL}`);
|
398
|
-
}
|
399
|
-
safe = !strict;
|
400
|
-
return `(?:${pre}(${pattern}(?:${sep}${pattern})*)${post})${mod}`;
|
361
|
+
if (token.type === "param") {
|
362
|
+
result += `(${negate(delimiter, isSafeSegmentParam ? "" : backtrack)}+)`;
|
401
363
|
}
|
402
|
-
|
364
|
+
else {
|
365
|
+
result += `(.+)`;
|
366
|
+
}
|
367
|
+
keys.push(token);
|
368
|
+
backtrack = "";
|
369
|
+
isSafeSegmentParam = false;
|
370
|
+
continue;
|
403
371
|
}
|
404
|
-
return `(?:${pre}${post})${modifier}`;
|
405
|
-
});
|
406
|
-
}
|
407
|
-
function checkPattern(pattern, name, flags) {
|
408
|
-
try {
|
409
|
-
return new RegExp(`^${pattern}$`, flags);
|
410
|
-
}
|
411
|
-
catch (err) {
|
412
|
-
throw new TypeError(`Invalid pattern for "${name}": ${err.message}`);
|
413
372
|
}
|
373
|
+
return result;
|
414
374
|
}
|
415
|
-
function
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
* An empty array can be passed in for the keys, which will hold the
|
422
|
-
* placeholder key descriptions. For example, using `/user/:id`, `keys` will
|
423
|
-
* contain `[{ name: 'id', delimiter: '/', optional: false, repeat: false }]`.
|
424
|
-
*/
|
425
|
-
function pathToRegexp(path, options = {}) {
|
426
|
-
const data = path instanceof TokenData ? path : parse(path, options);
|
427
|
-
const keys = [];
|
428
|
-
const regexp = tokensToRegexp(data, keys, options);
|
429
|
-
return Object.assign(regexp, { keys });
|
375
|
+
function negate(delimiter, backtrack) {
|
376
|
+
const values = [delimiter, backtrack].filter(Boolean);
|
377
|
+
const isSimple = values.every((value) => value.length === 1);
|
378
|
+
if (isSimple)
|
379
|
+
return `[^${escape(values.join(""))}]`;
|
380
|
+
return `(?:(?!${values.map(escape).join("|")}).)`;
|
430
381
|
}
|
431
382
|
//# sourceMappingURL=index.js.map
|