Skip to content

Commit 9e7adc0

Browse files
bartlomiejuclaude
andauthored
fix: middleware not matching routes with optional parameters in fs routing (#3726)
Closes #3545 Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent ad8ec0f commit 9e7adc0

2 files changed

Lines changed: 19 additions & 5 deletions

File tree

packages/fresh/src/router.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -288,21 +288,27 @@ export function patternToSegments(
288288

289289
if (path === "/" || path === "*" || path === "/*") return out;
290290

291+
// Strip optional groups like {/:param}? before segmenting, so that
292+
// /api{/:opt}?/endpoint produces the same segments as /api/endpoint.
293+
// This ensures middleware registered at /api applies to routes with
294+
// optional parameters under /api.
295+
const cleaned = path.replace(/\{[^}]*\}\??/g, "");
296+
291297
let start = -1;
292-
for (let i = 0; i < path.length; i++) {
293-
const ch = path[i];
298+
for (let i = 0; i < cleaned.length; i++) {
299+
const ch = cleaned[i];
294300

295301
if (ch === "/") {
296302
if (i > 0) {
297-
const raw = path.slice(start + 1, i);
303+
const raw = cleaned.slice(start + 1, i);
298304
out.push(raw);
299305
}
300306
start = i;
301307
}
302308
}
303309

304-
if (includeLast && start < path.length - 1) {
305-
out.push(path.slice(start + 1));
310+
if (includeLast && start < cleaned.length - 1) {
311+
out.push(cleaned.slice(start + 1));
306312
}
307313

308314
return out;

packages/fresh/src/router_test.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,14 @@ Deno.test("patternToSegments", () => {
224224
expect(patternToSegments("/foo/", "")).toEqual(["", "foo"]);
225225

226226
expect(patternToSegments("/foo/bar", "", true)).toEqual(["", "foo", "bar"]);
227+
228+
// Optional params with {/...}? syntax should not split on / inside braces
229+
expect(patternToSegments("/api{/:opt}?/endpoint", "")).toEqual(["", "api"]);
230+
expect(patternToSegments("/api{/:opt}?/endpoint", "", true)).toEqual([
231+
"",
232+
"api",
233+
"endpoint",
234+
]);
227235
});
228236

229237
Deno.test("mergePath", () => {

0 commit comments

Comments
 (0)