Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@ describe("path-to-regexp", () => {
describe("ParseError", () => {
it("should contain original path and debug url", () => {
const error = new PathError(
"Unexpected END at index 7, expected }",
"Unexpected end at index 7, expected }",
"/{:foo,",
);

expect(error).toBeInstanceOf(TypeError);
expect(error.message).toBe(
"Unexpected END at index 7, expected }: /{:foo,; visit https://git.new/pathToRegexpError for info",
"Unexpected end at index 7, expected }: /{:foo,; visit https://git.new/pathToRegexpError for info",
);
expect(error.originalPath).toBe("/{:foo,");
});

it("should omit original url when undefined", () => {
const error = new PathError(
"Unexpected END at index 7, expected }",
"Unexpected end at index 7, expected }",
undefined,
);

expect(error).toBeInstanceOf(TypeError);
expect(error.message).toBe(
"Unexpected END at index 7, expected }; visit https://git.new/pathToRegexpError for info",
"Unexpected end at index 7, expected }; visit https://git.new/pathToRegexpError for info",
);
expect(error.originalPath).toBeUndefined();
});
Expand All @@ -50,13 +50,13 @@ describe("path-to-regexp", () => {
describe("parse errors", () => {
it("should throw on unbalanced group", () => {
expect(() => parse("/{:foo,")).toThrow(
new PathError("Unexpected END at index 7, expected }", "/{:foo,"),
new PathError("Unexpected end at index 7, expected }", "/{:foo,"),
);
});

it("should throw on nested unbalanced group", () => {
expect(() => parse("/{:foo/{x,y}")).toThrow(
new PathError("Unexpected END at index 12, expected }", "/{:foo/{x,y}"),
new PathError("Unexpected end at index 12, expected }", "/{:foo/{x,y}"),
);
});

Expand Down
88 changes: 41 additions & 47 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ export interface CompileOptions {
type TokenType =
| "{"
| "}"
| "WILDCARD"
| "PARAM"
| "CHAR"
| "ESCAPED"
| "END"
| "wildcard"
| "param"
| "char"
| "escape"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"ESCAPED" -> "escape" arguably reads better in an error (Unexpected escape at index 12). That said, I don't think type would ever show in an error anyway, the only unexpected token is "end".

| "end"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All these types are also internal only, never exposed, so renaming them is safe (only the error changes for "Unexpected END").

// Reserved for use or ambiguous due to past use.
| "("
| ")"
Expand Down Expand Up @@ -197,29 +197,27 @@ export function parse(str: string, options: ParseOptions = {}): TokenData {
let value = "";

if (ID_START.test(chars[index])) {
value += chars[index];
while (ID_CONTINUE.test(chars[++index])) {
value += chars[index];
}
do {
value += chars[index++];
} while (ID_CONTINUE.test(chars[index]));
} else if (chars[index] === '"') {
let pos = index;
let quoteStart = index;

while (index < chars.length) {
if (chars[++index] === '"') {
while (index++ < chars.length) {
if (chars[index] === '"') {
index++;
pos = 0;
quoteStart = 0;
break;
}

if (chars[index] === "\\") {
value += chars[++index];
} else {
value += chars[index];
}
// Increment over escape characters.
if (chars[index] === "\\") index++;

value += chars[index];
}

if (pos) {
throw new PathError(`Unterminated quote at index ${pos}`, str);
if (quoteStart) {
throw new PathError(`Unterminated quote at index ${quoteStart}`, str);
}
}

Expand All @@ -237,54 +235,50 @@ export function parse(str: string, options: ParseOptions = {}): TokenData {
if (type) {
tokens.push({ type, index: index++, value });
} else if (value === "\\") {
tokens.push({ type: "ESCAPED", index: index++, value: chars[index++] });
tokens.push({ type: "escape", index: index++, value: chars[index++] });
} else if (value === ":") {
tokens.push({ type: "PARAM", index: index++, value: name() });
tokens.push({ type: "param", index: index++, value: name() });
} else if (value === "*") {
tokens.push({ type: "WILDCARD", index: index++, value: name() });
tokens.push({ type: "wildcard", index: index++, value: name() });
} else {
tokens.push({ type: "CHAR", index: index++, value });
tokens.push({ type: "char", index: index++, value });
}
}

tokens.push({ type: "END", index, value: "" });
tokens.push({ type: "end", index, value: "" });

function consumeUntil(endType: TokenType): Token[] {
const output: Token[] = [];

while (true) {
const { type, value, index } = tokens[pos++];
if (type === endType) break;

if (type === "CHAR" || type === "ESCAPED") {
let path = value;
while (true) {
const next = tokens[pos];
if (next.type !== "CHAR" && next.type !== "ESCAPED") break;
pos++;
path += next.value;
const token = tokens[pos++];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Surprised me, but removing destructuring helped.

if (token.type === endType) break;

if (token.type === "char" || token.type === "escape") {
let path = token.value;
let cur = tokens[pos];

while (cur.type === "char" || cur.type === "escape") {
path += cur.value;
cur = tokens[++pos];
}
output.push({ type: "text", value: encodePath(path) });
continue;
}

if (type === "PARAM") {
output.push({
type: "param",
name: value,
type: "text",
value: encodePath(path),
});
continue;
}

if (type === "WILDCARD") {
if (token.type === "param" || token.type === "wildcard") {
output.push({
type: "wildcard",
name: value,
type: token.type,
name: token.value,
});
continue;
}

if (type === "{") {
if (token.type === "{") {
output.push({
type: "group",
tokens: consumeUntil("}"),
Expand All @@ -293,15 +287,15 @@ export function parse(str: string, options: ParseOptions = {}): TokenData {
}

throw new PathError(
`Unexpected ${type} at index ${index}, expected ${endType}`,
`Unexpected ${token.type} at index ${token.index}, expected ${endType}`,
str,
);
}

return output;
}

return new TokenData(consumeUntil("END"), str);
return new TokenData(consumeUntil("end"), str);
}

/**
Expand Down