Skip to content

Commit

Permalink
Make key prefix/suffix/modifier/separator optional
Browse files Browse the repository at this point in the history
  • Loading branch information
blakeembrey committed Jun 20, 2024
1 parent 8b74404 commit 17ce0be
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 50 deletions.
21 changes: 11 additions & 10 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,25 +242,26 @@ A `parse` function is available and returns `TokenData`, the set of tokens and o

### Token Information

- `name` The name of the token (`string` for named or `number` for unnamed index)
- `prefix` The prefix string for the segment (e.g. `"/"`)
- `suffix` The suffix string for the segment (e.g. `""`)
- `pattern` The RegExp used to match this token (`string`)
- `modifier` The modifier character used for the segment (e.g. `?`)
- `separator` _(optional)_ The string used to separate repeated parameters (modifier is `+` or `*`)
- `optional` _(optional)_ A boolean used to indicate whether the parameter is optional (modifier is `?` or `*`)
- `name` The name of the token
- `prefix` _(optional)_ The prefix string for the segment (e.g. `"/"`)
- `suffix` _(optional)_ The suffix string for the segment (e.g. `""`)
- `pattern` _(optional)_ The pattern defined to match this token
- `modifier` _(optional)_ The modifier character used for the segment (e.g. `?`)
- `separator` _(optional)_ The string used to separate repeated parameters

## Errors

An effort has been made to ensure ambiguous paths from previous releases throw an error. This means you might be seeing an error when things worked before.

### Unexpected `?`, `*`, or `+`

In previous major versions, `/` or `.` were used as implicit prefixes of parameters. So `/:key?` was implicitly `{/:key}?`.
In previous major versions `/` and `.` were used as implicit prefixes of parameters. So `/:key?` was implicitly `{/:key}?`. For example:

This has been made explicit. Assuming `?` as the modifier, if you have a `/` or `.` before the parameter, you want `{.:ext}?` or `{/:ext}?`. If not, you want `{:ext}?`.
- `/:key?``{/:key}?` or `/:key*``{/:key}*` or `/:key+``{/:key}+`
- `.:key?``{.:key}?` or `.:key*``{.:key}*` or `.:key+``{.:key}+`
- `:key?``{:key}?` or `:key*``{:key}*` or `:key+``{:key}+`

### Unexpected `!`, `@`, or `;`
### Unexpected `!`, `@`, `,`, or `;`

These characters have been reserved for future use.

Expand Down
25 changes: 5 additions & 20 deletions src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,31 +36,19 @@ const PARSER_TESTS: ParserTestSet[] = [
},
{
path: "/:test",
expected: [
"/",
{ name: "test", prefix: "", suffix: "", pattern: "", modifier: "" },
],
expected: ["/", { name: "test" }],
},
{
path: "/:0",
expected: [
"/",
{ name: "0", prefix: "", suffix: "", pattern: "", modifier: "" },
],
expected: ["/", { name: "0" }],
},
{
path: "/:_",
expected: [
"/",
{ name: "_", prefix: "", suffix: "", pattern: "", modifier: "" },
],
expected: ["/", { name: "_" }],
},
{
path: "/:café",
expected: [
"/",
{ name: "café", prefix: "", suffix: "", pattern: "", modifier: "" },
],
expected: ["/", { name: "café" }],
},
];

Expand Down Expand Up @@ -2913,10 +2901,7 @@ describe("path-to-regexp", () => {
const expectedKeys = [
{
name: "id",
prefix: "",
suffix: "",
modifier: "",
pattern: "",
pattern: undefined,
},
];

Expand Down
35 changes: 15 additions & 20 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,15 +258,12 @@ export function parse(str: string, options: ParseOptions = {}): TokenData {
if (path) tokens.push(encodePath(path));

const name = it.tryConsume("NAME");
const pattern = it.tryConsume("PATTERN") || "";
const pattern = it.tryConsume("PATTERN");

if (name || pattern) {
tokens.push({
name: name || String(key++),
prefix: "",
suffix: "",
pattern,
modifier: "",
});

const next = it.peek();
Expand All @@ -283,8 +280,6 @@ export function parse(str: string, options: ParseOptions = {}): TokenData {
if (asterisk) {
tokens.push({
name: String(key++),
prefix: "",
suffix: "",
pattern: `[^${escape(delimiter)}]*`,
modifier: "*",
separator: delimiter,
Expand All @@ -296,7 +291,7 @@ export function parse(str: string, options: ParseOptions = {}): TokenData {
if (open) {
const prefix = it.text();
const name = it.tryConsume("NAME");
const pattern = it.tryConsume("PATTERN") || "";
const pattern = it.tryConsume("PATTERN");
const suffix = it.text();
const separator = it.tryConsume(";") ? it.text() : prefix + suffix;

Expand Down Expand Up @@ -350,6 +345,7 @@ function tokenToFunction(
const encodeValue = encode || NOOP_VALUE;
const repeated = token.modifier === "+" || token.modifier === "*";
const optional = token.modifier === "?" || token.modifier === "*";
const { prefix = "", suffix = "", separator = "" } = token;

if (encode && repeated) {
const stringify = (value: string, index: number) => {
Expand All @@ -366,9 +362,7 @@ function tokenToFunction(

if (value.length === 0) return "";

return (
token.prefix + value.map(stringify).join(token.separator) + token.suffix
);
return prefix + value.map(stringify).join(separator) + suffix;
};

if (optional) {
Expand All @@ -389,7 +383,7 @@ function tokenToFunction(
if (typeof value !== "string") {
throw new TypeError(`Expected "${token.name}" to be a string`);
}
return token.prefix + encodeValue(value) + token.suffix;
return prefix + encodeValue(value) + suffix;
};

if (optional) {
Expand Down Expand Up @@ -546,10 +540,10 @@ function flags(options: { sensitive?: boolean }) {
*/
export interface Key {
name: string;
prefix: string;
suffix: string;
pattern: string;
modifier: string;
prefix?: string;
suffix?: string;
pattern?: string;
modifier?: string;
separator?: string;
}

Expand Down Expand Up @@ -593,20 +587,21 @@ function toKeyRegexp(stringify: Encode, delimiter: string) {
const segmentPattern = `[^${escape(delimiter)}]+?`;

return (key: Key) => {
const prefix = stringify(key.prefix);
const suffix = stringify(key.suffix);
const prefix = key.prefix ? stringify(key.prefix) : "";
const suffix = key.suffix ? stringify(key.suffix) : "";
const modifier = key.modifier || "";

if (key.name) {
const pattern = key.pattern || segmentPattern;
if (key.modifier === "+" || key.modifier === "*") {
const mod = key.modifier === "*" ? "?" : "";
const split = stringify(key.separator || "");
const split = key.separator ? stringify(key.separator) : "";
return `(?:${prefix}((?:${pattern})(?:${split}(?:${pattern}))*)${suffix})${mod}`;
}
return `(?:${prefix}(${pattern})${suffix})${key.modifier}`;
return `(?:${prefix}(${pattern})${suffix})${modifier}`;
}

return `(?:${prefix}${suffix})${key.modifier}`;
return `(?:${prefix}${suffix})${modifier}`;
};
}

Expand Down

0 comments on commit 17ce0be

Please sign in to comment.