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