Skip to content

Commit f25000b

Browse files
committed
100% test coverage
1 parent 85e5e2c commit f25000b

File tree

2 files changed

+61
-20
lines changed

2 files changed

+61
-20
lines changed

src/cases.spec.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,35 @@ export const MATCH_TESTS: MatchTestSet[] = [
16451645
},
16461646
],
16471647
},
1648+
{
1649+
path: "%25:foo..:bar",
1650+
options: {
1651+
delimiter: "%25",
1652+
},
1653+
tests: [
1654+
{
1655+
input: "%25hello..world",
1656+
expected: {
1657+
path: "%25hello..world",
1658+
params: { foo: "hello", bar: "world" },
1659+
},
1660+
},
1661+
{
1662+
input: "%25555..222",
1663+
expected: {
1664+
path: "%25555..222",
1665+
params: { foo: "555", bar: "222" },
1666+
},
1667+
},
1668+
{
1669+
input: "%25555....222%25",
1670+
expected: {
1671+
path: "%25555....222%25",
1672+
params: { foo: "555..", bar: "222" },
1673+
},
1674+
},
1675+
],
1676+
},
16481677

16491678
/**
16501679
* Array input is normalized.

src/index.ts

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -619,40 +619,52 @@ function negate(delimiter: string, backtrack: string) {
619619
}
620620

621621
/**
622-
* Stringify token data into a path string.
622+
* Stringify an array of tokens into a path string.
623623
*/
624-
export function stringify(data: TokenData) {
625-
return data.tokens
626-
.map(function stringifyToken(token, index, tokens): string {
627-
if (token.type === "text") return escapeText(token.value);
628-
if (token.type === "group") {
629-
return `{${token.tokens.map(stringifyToken).join("")}}`;
630-
}
624+
function stringifyTokens(tokens: Token[]): string {
625+
let value = "";
626+
let i = 0;
627+
628+
while (i < tokens.length) {
629+
const token = tokens[i++];
631630

632-
const isSafe =
633-
isNameSafe(token.name) && isNextNameSafe(tokens[index + 1]);
634-
const key = isSafe ? token.name : JSON.stringify(token.name);
631+
if (token.type === "text") {
632+
value += escapeText(token.value);
633+
continue;
634+
}
635635

636-
if (token.type === "param") return `:${key}`;
637-
if (token.type === "wildcard") return `*${key}`;
638-
throw new TypeError(`Unexpected token: ${token}`);
639-
})
640-
.join("");
636+
if (token.type === "group") {
637+
value += `{${stringifyTokens(token.tokens)}}`;
638+
continue;
639+
}
640+
641+
const isSafe = isNameSafe(token.name) && isNextNameSafe(tokens[i]);
642+
const name = isSafe ? token.name : JSON.stringify(token.name);
643+
value += token.type === "param" ? `:${name}` : `*${name}`;
644+
}
645+
646+
return value;
647+
}
648+
649+
/**
650+
* Stringify token data into a path string.
651+
*/
652+
export function stringify(data: TokenData) {
653+
return stringifyTokens(data.tokens);
641654
}
642655

643656
/**
644657
* Validate the parameter name contains valid ID characters.
645658
*/
646659
function isNameSafe(name: string) {
647660
const [first, ...rest] = name;
648-
if (!ID_START.test(first)) return false;
649-
return rest.every((char) => ID_CONTINUE.test(char));
661+
return ID_START.test(first) && rest.every((char) => ID_CONTINUE.test(char));
650662
}
651663

652664
/**
653665
* Validate the next token does not interfere with the current param name.
654666
*/
655667
function isNextNameSafe(token: Token | undefined) {
656-
if (!token || token.type !== "text") return true;
657-
return !ID_CONTINUE.test(token.value[0]);
668+
if (token && token.type === "text") return !ID_CONTINUE.test(token.value[0]);
669+
return true;
658670
}

0 commit comments

Comments
 (0)