fix: support URLPattern modifiers (?, +, *) in non-exact parent routes#222
Merged
Conversation
Non-exact (parent) routes computed the consumed pathname prefix by
counting pattern segments, assuming one pathname segment per pattern
segment. URLPattern syntax where the number of matched segments can
differ from the number of pattern segments (optional/repeated params,
regex groups, wildcards) produced a wrong consumed prefix, so child
matching received the wrong remaining pathname and the whole tree
failed to match.
matchPath now returns match candidates. Simple patterns (literal
segments and plain :params) keep the segment-counting fast path. For
patterns with variable-length syntax, the bare pattern (without the
{/*}? suffix) is matched against every pathname prefix, longest first,
and route matching backtracks to a shorter consumed prefix when no
child matches the remainder.
Also fix ExtractParams to strip modifiers, regex groups, and group
delimiters from param names, so path "/docs/:section?" types params as
{ section: string } instead of { "section?": string }.
Closes #205
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016HWo3h7xx3i3yB7AjoBTpP
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #205
Problem
Non-exact (parent) routes computed the consumed pathname prefix by counting pattern segments, assuming one pathname segment per pattern segment. Any URLPattern syntax where the number of matched segments can differ from the number of pattern segments (
?,+,*modifiers, regex groups, wildcards) produced a wrong consumed prefix, so children received the wrong remaining pathname and the whole route tree failed to match:Fix
Runtime (
matchRoutes.ts):matchPathnow returns match candidates instead of a single result.:params) keep the original segment-counting fast path, so the common case does no extra work.{/*}?suffix) against every pathname prefix, longest first.matchRoutebacktracks to a shorter consumed prefix when no child matches the remainder, so/docs/:section?matches/docs/page/5withsectionabsent.SKIPPEDsemantics are preserved: once a candidate's child is skipped, shorter prefixes aren't tried, so the server can't render a different tree than the client would hydrate.Types (
route.ts):ExtractParamsnow strips modifiers, regex groups, and group delimiters from param names, sopath: "/docs/:section?"types params as{ section: string }instead of{ "section?": string }(also handles:id(\d+)and{/:section}?).Docs: extended the README Path Patterns table with optional/repeated/regex parameter rows and a note that patterns work as prefixes on parent routes.
Tests
13 new cases: 11 runtime tests pinning
?/+/*/regex-group/brace-group behavior in parent routes (including greedy preference, backtracking,:path+minimum-segment enforcement, andrequireChildren: falsefallback) and 2 type-level tests for modifier stripping. All 299 tests pass; typecheck, lint, and format are clean.Note:
pnpm buildfails for the docs and example-rsc packages in the dev container withReferenceError: URLPattern is not defined— this is pre-existing on the base commit (Node 22 has no global URLPattern) and unrelated to this change. The router package builds cleanly.🤖 Generated with Claude Code
https://claude.ai/code/session_016HWo3h7xx3i3yB7AjoBTpP
Generated by Claude Code