Skip to content

Commit 0b3aba6

Browse files
committed
Reuse iter class > fns, less regex paths
1 parent b893429 commit 0b3aba6

File tree

2 files changed

+66
-62
lines changed

2 files changed

+66
-62
lines changed

src/index.spec.ts

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,7 +1215,7 @@ const TESTS: Test[] = [
12151215
[
12161216
["route", ["route", "route"]],
12171217
["/route", null],
1218-
["", ["", ""]],
1218+
["", ["", undefined]],
12191219
["route/foobar", null],
12201220
],
12211221
[
@@ -1888,9 +1888,9 @@ const TESTS: Test[] = [
18881888
],
18891889
[
18901890
["/test", null],
1891-
["/test/", ["/test/", "", ""]],
1892-
["/test/u123", ["/test/u123", "u123", ""]],
1893-
["/test/c123", ["/test/c123", "", "c123"]],
1891+
["/test/", ["/test/", undefined, undefined]],
1892+
["/test/u123", ["/test/u123", "u123", undefined]],
1893+
["/test/c123", ["/test/c123", undefined, "c123"]],
18941894
],
18951895
[
18961896
[{ uid: "u123" }, "/test/u123"],
@@ -2060,7 +2060,7 @@ const TESTS: Test[] = [
20602060
],
20612061
[
20622062
["/foobaz", ["/foobaz", "foo"]],
2063-
["/baz", ["/baz", ""]],
2063+
["/baz", ["/baz", undefined]],
20642064
],
20652065
[
20662066
[{}, "/baz"],
@@ -2090,7 +2090,7 @@ const TESTS: Test[] = [
20902090
],
20912091
[
20922092
["/hello(world)", ["/hello(world)", "hello", "world"]],
2093-
["/hello()", ["/hello()", "hello", ""]],
2093+
["/hello()", ["/hello()", "hello", undefined]],
20942094
],
20952095
[
20962096
[{ foo: "hello", bar: "world" }, "/hello(world)"],
@@ -2117,7 +2117,7 @@ const TESTS: Test[] = [
21172117
},
21182118
],
21192119
[
2120-
["/video", ["/video", "video", ""]],
2120+
["/video", ["/video", "video", undefined]],
21212121
["/video+test", ["/video+test", "video", "+test"]],
21222122
["/video+", null],
21232123
],
@@ -2545,7 +2545,7 @@ const TESTS: Test[] = [
25452545
},
25462546
],
25472547
[
2548-
["/user/123", ["/user/123", "", "123"]],
2548+
["/user/123", ["/user/123", undefined, "123"]],
25492549
["/users/123", ["/users/123", "s", "123"]],
25502550
],
25512551
[[{ user: "123" }, "/user/123"]],
@@ -2793,12 +2793,6 @@ describe("path-to-regexp", () => {
27932793
pathToRegexp.pathToRegexp("/{a{b:foo}}");
27942794
}).toThrow(new TypeError("Unexpected OPEN at 3, expected CLOSE"));
27952795
});
2796-
2797-
it("should throw on misplaced modifier", () => {
2798-
expect(() => {
2799-
pathToRegexp.pathToRegexp("/foo?");
2800-
}).toThrow(new TypeError("Unexpected MODIFIER at 4, expected END"));
2801-
});
28022796
});
28032797

28042798
describe("tokens", () => {

src/index.ts

Lines changed: 58 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ interface LexToken {
2323
/**
2424
* Tokenize input string.
2525
*/
26-
function lexer(str: string): LexToken[] {
26+
function lexer(str: string) {
2727
const tokens: LexToken[] = [];
2828
let i = 0;
2929

@@ -125,7 +125,7 @@ function lexer(str: string): LexToken[] {
125125

126126
tokens.push({ type: "END", index: i, value: "" });
127127

128-
return tokens;
128+
return new Iter(tokens);
129129
}
130130

131131
export interface ParseOptions {
@@ -139,6 +139,41 @@ export interface ParseOptions {
139139
prefixes?: string;
140140
}
141141

142+
class Iter {
143+
index = 0;
144+
145+
constructor(private tokens: LexToken[]) {}
146+
147+
peek(): LexToken {
148+
return this.tokens[this.index];
149+
}
150+
151+
tryConsume(type: LexToken["type"]): string | undefined {
152+
const token = this.peek();
153+
if (token.type !== type) return;
154+
this.index++;
155+
return token.value;
156+
}
157+
158+
consume(type: LexToken["type"]): string {
159+
const value = this.tryConsume(type);
160+
if (value !== undefined) return value;
161+
const { type: nextType, index } = this.peek();
162+
throw new TypeError(`Unexpected ${nextType} at ${index}, expected ${type}`);
163+
}
164+
165+
text(): string {
166+
let result = "";
167+
let value: string | undefined;
168+
while (
169+
(value = this.tryConsume("CHAR") || this.tryConsume("ESCAPED_CHAR"))
170+
) {
171+
result += value;
172+
}
173+
return result;
174+
}
175+
}
176+
142177
/**
143178
* Parse a string for the raw tokens.
144179
*/
@@ -149,33 +184,12 @@ export function parse(str: string, options: ParseOptions = {}): Token[] {
149184
const result: Token[] = [];
150185
const tokens = lexer(str);
151186
let key = 0;
152-
let i = 0;
153187
let path = "";
154188

155-
const tryConsume = (type: LexToken["type"]): string | undefined => {
156-
if (i < tokens.length && tokens[i].type === type) return tokens[i++].value;
157-
};
158-
159-
const mustConsume = (type: LexToken["type"]): string => {
160-
const value = tryConsume(type);
161-
if (value !== undefined) return value;
162-
const { type: nextType, index } = tokens[i];
163-
throw new TypeError(`Unexpected ${nextType} at ${index}, expected ${type}`);
164-
};
165-
166-
const consumeText = (): string => {
167-
let result = "";
168-
let value: string | undefined;
169-
while ((value = tryConsume("CHAR") || tryConsume("ESCAPED_CHAR"))) {
170-
result += value;
171-
}
172-
return result;
173-
};
174-
175-
while (i < tokens.length) {
176-
const char = tryConsume("CHAR");
177-
const name = tryConsume("NAME");
178-
const pattern = tryConsume("PATTERN");
189+
do {
190+
const char = tokens.tryConsume("CHAR");
191+
const name = tokens.tryConsume("NAME");
192+
const pattern = tokens.tryConsume("PATTERN");
179193

180194
if (name || pattern) {
181195
let prefix = char || "";
@@ -195,12 +209,12 @@ export function parse(str: string, options: ParseOptions = {}): Token[] {
195209
prefix,
196210
suffix: "",
197211
pattern: pattern || defaultPattern,
198-
modifier: tryConsume("MODIFIER") || "",
212+
modifier: tokens.tryConsume("MODIFIER") || "",
199213
});
200214
continue;
201215
}
202216

203-
const value = char || tryConsume("ESCAPED_CHAR");
217+
const value = char || tokens.tryConsume("ESCAPED_CHAR");
204218
if (value) {
205219
path += value;
206220
continue;
@@ -211,27 +225,28 @@ export function parse(str: string, options: ParseOptions = {}): Token[] {
211225
path = "";
212226
}
213227

214-
const open = tryConsume("OPEN");
228+
const open = tokens.tryConsume("OPEN");
215229
if (open) {
216-
const prefix = consumeText();
217-
const name = tryConsume("NAME") || "";
218-
const pattern = tryConsume("PATTERN") || "";
219-
const suffix = consumeText();
230+
const prefix = tokens.text();
231+
const name = tokens.tryConsume("NAME") || "";
232+
const pattern = tokens.tryConsume("PATTERN") || "";
233+
const suffix = tokens.text();
220234

221-
mustConsume("CLOSE");
235+
tokens.consume("CLOSE");
222236

223237
result.push({
224238
name: name || (pattern ? key++ : ""),
225239
pattern: name && !pattern ? defaultPattern : pattern,
226240
prefix,
227241
suffix,
228-
modifier: tryConsume("MODIFIER") || "",
242+
modifier: tokens.tryConsume("MODIFIER") || "",
229243
});
230244
continue;
231245
}
232246

233-
mustConsume("END");
234-
}
247+
tokens.consume("END");
248+
break;
249+
} while (true);
235250

236251
return result;
237252
}
@@ -559,15 +574,11 @@ export function tokensToRegexp(
559574
if (token.pattern) {
560575
if (keys) keys.push(token);
561576

562-
if (prefix || suffix) {
563-
if (token.modifier === "+" || token.modifier === "*") {
564-
const mod = token.modifier === "*" ? "?" : "";
565-
route += `(?:${prefix}((?:${token.pattern})(?:${suffix}${prefix}(?:${token.pattern}))*)${suffix})${mod}`;
566-
} else {
567-
route += `(?:${prefix}(${token.pattern})${suffix})${token.modifier}`;
568-
}
577+
if (token.modifier === "+" || token.modifier === "*") {
578+
const mod = token.modifier === "*" ? "?" : "";
579+
route += `(?:${prefix}((?:${token.pattern})(?:${suffix}${prefix}(?:${token.pattern}))*)${suffix})${mod}`;
569580
} else {
570-
route += `((?:${token.pattern})${token.modifier})`;
581+
route += `(?:${prefix}(${token.pattern})${suffix})${token.modifier}`;
571582
}
572583
} else {
573584
route += `(?:${prefix}${suffix})${token.modifier}`;
@@ -577,8 +588,7 @@ export function tokensToRegexp(
577588

578589
if (end) {
579590
if (!strict) route += `${delimiterRe}?`;
580-
581-
route += options.endsWith ? `(?=${endsWithRe})` : "$";
591+
route += endsWith ? `(?=${endsWithRe})` : "$";
582592
} else {
583593
const endToken = tokens[tokens.length - 1];
584594
const isEndDelimited =

0 commit comments

Comments
 (0)