Skip to content

Commit 669f62a

Browse files
ghallebartlomiejuclaude
authored
fix: prevent 404 for routes consisting solely of an optional parameter (#2798)
Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent be813e0 commit 669f62a

3 files changed

Lines changed: 23 additions & 1 deletion

File tree

docs/latest/concepts/file-routing.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ they might match:
7878
| `blog/[slug]/comments.ts` | `/blog/:slug/comments` | `/blog/foo/comments` |
7979
| `old/[...path].ts` | `/old/:path*` | `/old/foo`, `/old/bar/baz` |
8080
| `docs/[[version]]/index.ts` | `/docs{/:version}?` | `/docs`, `/docs/latest`, `/docs/canary` |
81+
| `[[name]].ts` | `/{:name}?` | `/`, `/foo`, `/bar` |
8182

8283
Advanced use-cases can require that a more complex pattern be used for matching.
8384
A custom [URL pattern][urlpattern] can be specified in the route configuration.

packages/fresh/src/router.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ export function pathToPattern(
196196

197197
let route = "";
198198

199+
let nonOptionalSegments = 0;
199200
for (let i = 0; i < parts.length; i++) {
200201
const part = parts[i];
201202

@@ -268,14 +269,29 @@ export function pathToPattern(
268269
}
269270
}
270271

271-
route += (optional ? "" : "/") + pattern;
272+
if (optional) {
273+
route += pattern;
274+
} else {
275+
nonOptionalSegments++;
276+
route += "/" + pattern;
277+
}
272278
}
273279

274280
// Case: /(group)/index.tsx
275281
if (route === "") {
276282
route = "/";
277283
}
278284

285+
// Handles all cases where a route starts with
286+
// an optional parameter and does not contain
287+
// any non-group and non-optional segments after
288+
// Case: /[[id]].tsx
289+
// Case: /(group)/[[id]].tsx
290+
// Case: /(group)/[[name]]/(group2)/index.tsx
291+
if (route.startsWith(`{/`) && nonOptionalSegments === 0) {
292+
route = route.replace("{/", "/{");
293+
}
294+
279295
return route;
280296
}
281297

packages/fresh/src/router_test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,11 @@ Deno.test("pathToPattern", async (t) => {
193193
).toEqual(
194194
"/foo{/:name}?/bar{/:bob}?",
195195
);
196+
expect(
197+
pathToPattern("(group)/[[name]]/(group2)/index"),
198+
).toEqual(
199+
"/{:name}?",
200+
);
196201
});
197202

198203
await t.step("throws on invalid patterns", () => {

0 commit comments

Comments
 (0)