Skip to content

Commit 7504c08

Browse files
committed
fix: segment parsing
1 parent 32c50bb commit 7504c08

2 files changed

Lines changed: 40 additions & 29 deletions

File tree

‎packages/routes-gen/src/route.test.ts‎

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
import { route } from "./route";
22

33
it("supports optional params (issue 31)", () => {
4-
expect(route("/reports/:type?/:id/", { id: "123" })).toEqual("/reports/123/");
5-
6-
expect(route("/reports/:type?/:id/", { id: "123", type: "annual" })).toEqual(
7-
"/reports/annual/123/"
4+
expect(route("/reports/:type?/:id", { id: "123" })).toEqual("/reports/123");
5+
expect(route("/reports/:type?/:id?", { id: "123", type: "annual" })).toEqual(
6+
"/reports/annual/123"
87
);
98

10-
expect(route("/reports/:id/:type?/", { id: "123" })).toEqual("/reports/123/");
119

12-
expect(route("/reports/:id/:type?/", { id: "123", type: "annual" })).toEqual(
13-
"/reports/123/annual/"
10+
expect(route("/reports/:id/:type?", { id: "123" })).toEqual("/reports/123");
11+
expect(route("/reports/:id/:type?", { id: "123", type: "annual" })).toEqual(
12+
"/reports/123/annual"
13+
);
14+
15+
expect(route("/categories?/:category?/products", {})).toEqual(
16+
"/products"
17+
);
18+
expect(route("/categories?/:category?/products", { category: 'tees'})).toEqual(
19+
"/categories/tees/products"
1420
);
1521
});
1622

‎packages/routes-gen/src/route.ts‎

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,33 @@
1-
export function route<T extends string>(
2-
path: T,
3-
params?: Record<string, any>
4-
): T {
5-
if (params) {
6-
const segments = path.split(/\/+/).map((segment) => {
7-
if (segment.startsWith(":")) {
8-
const key = segment.replace(":", "").replace("?", "");
9-
10-
if (key in params) {
11-
return params[key];
12-
}
1+
export function route<T extends string>(path: T, params: Record<string, any> = {}): T {
2+
if (!path.includes('?') && !path.includes(':')) {
3+
return path;
4+
}
135

14-
// If the segment is optional and it doesn't exist in params, return null to omit it from the resulting path
15-
if (segment.endsWith("?")) {
16-
return null;
17-
}
18-
}
6+
let realPath = "";
7+
let currentIndex = path.length;
8+
let lastSegmentHadParam = false;
199

20-
return segment;
21-
});
10+
while (currentIndex > 0) {
11+
const startSegmentIndex = path.lastIndexOf('/', currentIndex);
12+
const segment = path.slice(startSegmentIndex, currentIndex + 1);
13+
currentIndex = startSegmentIndex - 1;
2214

23-
// Filter out any null/undefined segments and join remaining segments
24-
return segments.filter((value) => value != null).join("/") as T;
15+
if (segment.startsWith('/:')) {
16+
const paramName = segment.endsWith('?') ? segment.slice(2, -1) : segment.slice(2);
17+
const paramValue = params[paramName];
18+
if (paramValue !== undefined) {
19+
lastSegmentHadParam = true;
20+
realPath = '/' + paramValue + realPath;
21+
}
22+
} else if (segment.endsWith('?')) {
23+
if (lastSegmentHadParam) {
24+
realPath = segment.slice(0, -1) + realPath;
25+
}
26+
} else {
27+
lastSegmentHadParam = false;
28+
realPath = segment + realPath;
29+
}
2530
}
2631

27-
return path;
32+
return realPath as T;
2833
}

0 commit comments

Comments
 (0)