Skip to content

Commit 75e08fc

Browse files
committed
Disable standalone modifiers
1 parent cb27d37 commit 75e08fc

File tree

2 files changed

+64
-126
lines changed

2 files changed

+64
-126
lines changed

Diff for: src/index.spec.ts

+16-79
Original file line numberDiff line numberDiff line change
@@ -1961,78 +1961,6 @@ const MATCH_TESTS: MatchTestSet[] = [
19611961
],
19621962
},
19631963

1964-
/**
1965-
* Standalone modifiers.
1966-
*/
1967-
{
1968-
path: "/?",
1969-
tests: [
1970-
{
1971-
input: "/",
1972-
matches: ["/", undefined],
1973-
expected: { path: "/", index: 0, params: {} },
1974-
},
1975-
{
1976-
input: "/route",
1977-
matches: ["/route", "route"],
1978-
expected: { path: "/route", index: 0, params: { "0": "route" } },
1979-
},
1980-
],
1981-
},
1982-
{
1983-
path: "/+",
1984-
tests: [
1985-
{
1986-
input: "/",
1987-
matches: null,
1988-
expected: false,
1989-
},
1990-
{
1991-
input: "/route",
1992-
matches: ["/route", "route"],
1993-
expected: { path: "/route", index: 0, params: { "0": ["route"] } },
1994-
},
1995-
{
1996-
input: "/route/",
1997-
matches: ["/route/", "route"],
1998-
expected: { path: "/route/", index: 0, params: { "0": ["route"] } },
1999-
},
2000-
{
2001-
input: "/route/route",
2002-
matches: ["/route/route", "route/route"],
2003-
expected: {
2004-
path: "/route/route",
2005-
index: 0,
2006-
params: { "0": ["route", "route"] },
2007-
},
2008-
},
2009-
],
2010-
},
2011-
{
2012-
path: "/*",
2013-
tests: [
2014-
{
2015-
input: "/",
2016-
matches: ["/", undefined],
2017-
expected: { path: "/", index: 0, params: { "0": undefined } },
2018-
},
2019-
{
2020-
input: "/route",
2021-
matches: ["/route", "route"],
2022-
expected: { path: "/route", index: 0, params: { "0": ["route"] } },
2023-
},
2024-
{
2025-
input: "/route/nested",
2026-
matches: ["/route/nested", "route/nested"],
2027-
expected: {
2028-
path: "/route/nested",
2029-
index: 0,
2030-
params: { "0": ["route", "nested"] },
2031-
},
2032-
},
2033-
],
2034-
},
2035-
20361964
/**
20371965
* Regexps.
20381966
*/
@@ -2951,6 +2879,9 @@ const MATCH_TESTS: MatchTestSet[] = [
29512879
},
29522880
{
29532881
path: "#/*",
2882+
testOptions: {
2883+
skip: true,
2884+
},
29542885
tests: [
29552886
{
29562887
input: "#/",
@@ -2975,6 +2906,9 @@ const MATCH_TESTS: MatchTestSet[] = [
29752906
},
29762907
{
29772908
path: "/entity/:id/*",
2909+
testOptions: {
2910+
skip: true,
2911+
},
29782912
tests: [
29792913
{
29802914
input: "/entity/foo",
@@ -2990,6 +2924,9 @@ const MATCH_TESTS: MatchTestSet[] = [
29902924
},
29912925
{
29922926
path: "/test/*",
2927+
testOptions: {
2928+
skip: true,
2929+
},
29932930
tests: [
29942931
{
29952932
input: "/test",
@@ -3086,7 +3023,7 @@ describe("path-to-regexp", () => {
30863023
it("should throw on nested groups", () => {
30873024
expect(() => {
30883025
pathToRegexp.pathToRegexp("/{a{b:foo}}");
3089-
}).toThrow(new TypeError("Unexpected OPEN at 3, expected CLOSE"));
3026+
}).toThrow(new TypeError("Unexpected { at 3, expected }"));
30903027
});
30913028
});
30923029

@@ -3103,12 +3040,12 @@ describe("path-to-regexp", () => {
31033040
describe.each(COMPILE_TESTS)(
31043041
"compile $path with $options",
31053042
({ path, options, tests, testOptions = {} }) => {
3106-
const toPath = pathToRegexp.compile(path, options);
3107-
31083043
it.each(tests)(
31093044
"should compile $input",
31103045
testOptions,
31113046
({ input, expected }) => {
3047+
const toPath = pathToRegexp.compile(path, options);
3048+
31123049
if (expected === null) {
31133050
expect(() => toPath(input)).toThrow();
31143051
} else {
@@ -3122,14 +3059,14 @@ describe("path-to-regexp", () => {
31223059
describe.each(MATCH_TESTS)(
31233060
"match $path with $options",
31243061
({ path, options, tests, testOptions = {} }) => {
3125-
const keys: pathToRegexp.Key[] = [];
3126-
const re = pathToRegexp.pathToRegexp(path, keys, options);
3127-
const match = pathToRegexp.match(path, options);
3128-
31293062
it.each(tests)(
31303063
"should match $input",
31313064
testOptions,
31323065
({ input, matches, expected }) => {
3066+
const keys: pathToRegexp.Key[] = [];
3067+
const re = pathToRegexp.pathToRegexp(path, keys, options);
3068+
const match = pathToRegexp.match(path, options);
3069+
31333070
expect(exec(re, input)).toEqual(matches);
31343071
expect(match(input)).toEqual(expected);
31353072
},

Diff for: src/index.ts

+48-47
Original file line numberDiff line numberDiff line change
@@ -79,24 +79,40 @@ export interface CompileOptions extends ParseOptions {
7979
encode?: Encode;
8080
}
8181

82+
type TokenType =
83+
| "{"
84+
| "}"
85+
| "*"
86+
| "+"
87+
| "?"
88+
| "NAME"
89+
| "PATTERN"
90+
| "CHAR"
91+
| "ESCAPED"
92+
| "END"
93+
// Reserved for use.
94+
| "!"
95+
| ";";
96+
8297
/**
8398
* Tokenizer results.
8499
*/
85100
interface LexToken {
86-
type:
87-
| "OPEN"
88-
| "CLOSE"
89-
| "PATTERN"
90-
| "NAME"
91-
| "CHAR"
92-
| "ESCAPED_CHAR"
93-
| "MODIFIER"
94-
| "RESERVED"
95-
| "END";
101+
type: TokenType;
96102
index: number;
97103
value: string;
98104
}
99105

106+
const SIMPLE_TOKENS: Record<string, TokenType> = {
107+
"!": "!",
108+
";": ";",
109+
"*": "*",
110+
"+": "+",
111+
"?": "?",
112+
"{": "{",
113+
"}": "}",
114+
};
115+
100116
/**
101117
* Tokenize input string.
102118
*/
@@ -107,29 +123,15 @@ function lexer(str: string) {
107123

108124
while (i < chars.length) {
109125
const char = chars[i];
126+
const type = SIMPLE_TOKENS[char];
110127

111-
if (char === "!" || char === ";" || char === "|") {
112-
tokens.push({ type: "RESERVED", index: i, value: chars[i++] });
113-
continue;
114-
}
115-
116-
if (char === "*" || char === "+" || char === "?") {
117-
tokens.push({ type: "MODIFIER", index: i, value: chars[i++] });
128+
if (type) {
129+
tokens.push({ type, index: i++, value: char });
118130
continue;
119131
}
120132

121133
if (char === "\\") {
122-
tokens.push({ type: "ESCAPED_CHAR", index: i++, value: chars[i++] });
123-
continue;
124-
}
125-
126-
if (char === "{") {
127-
tokens.push({ type: "OPEN", index: i, value: chars[i++] });
128-
continue;
129-
}
130-
131-
if (char === "}") {
132-
tokens.push({ type: "CLOSE", index: i, value: chars[i++] });
134+
tokens.push({ type: "ESCAPED", index: i++, value: chars[i++] });
133135
continue;
134136
}
135137

@@ -220,13 +222,15 @@ class Iter {
220222
text(): string {
221223
let result = "";
222224
let value: string | undefined;
223-
while (
224-
(value = this.tryConsume("CHAR") || this.tryConsume("ESCAPED_CHAR"))
225-
) {
225+
while ((value = this.tryConsume("CHAR") || this.tryConsume("ESCAPED"))) {
226226
result += value;
227227
}
228228
return result;
229229
}
230+
231+
modifier(): string | undefined {
232+
return this.tryConsume("?") || this.tryConsume("*") || this.tryConsume("+");
233+
}
230234
}
231235

232236
/**
@@ -258,9 +262,8 @@ export function parse(str: string, options: ParseOptions = {}): TokenData {
258262
const char = it.tryConsume("CHAR");
259263
const name = it.tryConsume("NAME");
260264
const pattern = it.tryConsume("PATTERN");
261-
const modifier = it.tryConsume("MODIFIER");
262265

263-
if (name || pattern || modifier) {
266+
if (name || pattern) {
264267
let prefix = char || "";
265268

266269
if (!prefixes.includes(prefix)) {
@@ -277,17 +280,17 @@ export function parse(str: string, options: ParseOptions = {}): TokenData {
277280
toKey(
278281
encodePath,
279282
delimiter,
280-
name || key++,
283+
name || String(key++),
281284
pattern || defaultPattern,
282285
prefix,
283286
"",
284-
modifier,
287+
it.modifier(),
285288
),
286289
);
287290
continue;
288291
}
289292

290-
const value = char || it.tryConsume("ESCAPED_CHAR");
293+
const value = char || it.tryConsume("ESCAPED");
291294
if (value) {
292295
path += value;
293296
continue;
@@ -298,26 +301,24 @@ export function parse(str: string, options: ParseOptions = {}): TokenData {
298301
path = "";
299302
}
300303

301-
const open = it.tryConsume("OPEN");
304+
const open = it.tryConsume("{");
302305
if (open) {
303306
const prefix = it.text();
304307
const name = it.tryConsume("NAME");
305308
const pattern = it.tryConsume("PATTERN");
306309
const suffix = it.text();
307310

308-
it.consume("CLOSE");
309-
310-
const modifier = it.tryConsume("MODIFIER");
311+
it.consume("}");
311312

312313
tokens.push(
313314
toKey(
314315
encodePath,
315316
delimiter,
316-
name || (pattern ? key++ : ""),
317+
name || (pattern ? String(key++) : ""),
317318
name && !pattern ? defaultPattern : pattern || "",
318319
prefix,
319320
suffix,
320-
modifier,
321+
it.modifier(),
321322
),
322323
);
323324
continue;
@@ -333,7 +334,7 @@ export function parse(str: string, options: ParseOptions = {}): TokenData {
333334
function toKey(
334335
encode: Encode,
335336
delimiter: string,
336-
name: string | number,
337+
name: string,
337338
pattern = "",
338339
inputPrefix = "",
339340
inputSuffix = "",
@@ -586,7 +587,7 @@ function flags(options: { sensitive?: boolean }) {
586587
* A key is a capture group in the regex.
587588
*/
588589
export interface Key {
589-
name: string | number;
590+
name: string;
590591
prefix: string;
591592
suffix: string;
592593
pattern: string;
@@ -609,7 +610,7 @@ function regexpToRegexp(path: RegExp, keys: Key[]): RegExp {
609610
for (const execResult of path.source.matchAll(GROUPS_RE)) {
610611
keys.push({
611612
// Use parenthesized substring match if available, index otherwise.
612-
name: execResult[1] || index++,
613+
name: execResult[1] || String(index++),
613614
prefix: "",
614615
suffix: "",
615616
modifier: "",
@@ -664,7 +665,7 @@ function tokensToRegexp(
664665
if (typeof token === "string") {
665666
pattern += stringify(token);
666667
} else {
667-
if (token.pattern) keys.push(token);
668+
if (token.name) keys.push(token);
668669
pattern += keyToRegexp(token, stringify);
669670
}
670671
}
@@ -685,7 +686,7 @@ function keyToRegexp(key: Key, stringify: Encode): string {
685686
const prefix = stringify(key.prefix);
686687
const suffix = stringify(key.suffix);
687688

688-
if (key.pattern) {
689+
if (key.name) {
689690
if (key.separator) {
690691
const mod = key.modifier === "*" ? "?" : "";
691692
const split = stringify(key.separator);

0 commit comments

Comments
 (0)