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