Repository navigation
fix(void): register static routes before dynamic siblings - #220
Merged
Merged
Conversation
❌ Deploy Preview for staging-void-cloud failed.
|
hyfdev
marked this pull request as ready for review
June 18, 2026 12:10
The route scanner sorted overlapping routes with pattern.localeCompare, whose comment promised "static routes before dynamic" but did not deliver: ':' (0x3A) sorts before most letters, so '/users/:id' was ordered ahead of '/users/new'. The generated Hono app registers routes in this order, and Hono's default router resolves overlaps by registration order, so a request to /users/new was served by the [id] handler instead of the dedicated static route. Replace the localeCompare tiebreaker with a segment-aware specificity comparator (static segment before dynamic param before catch-all, compared depth-first) shared by both scan entry points.
hyfdev
force-pushed
the
fix/route-static-precedence
branch
from
June 18, 2026 16:08
8381649 to
f6ca1f6
Compare
Brooooooklyn
approved these changes
Jun 30, 2026
cpojer
pushed a commit
that referenced
this pull request
Sep 11, 2026
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
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.
Static routes now reliably win over dynamic siblings:
/users/newis served by its own handler instead of falling through to/users/[id].The bug
The route scanner sorted overlapping routes with
pattern.localeCompare. Its comment promised "static routes before dynamic, catch-all last" — but:(0x3A) sorts before most letters, so/users/:idwas ordered ahead of/users/new. The generated Hono app registers routes in scan order (compile.tsapp.<method>(pattern)loop), and Hono's default router resolves overlapping routes by registration order — so a request to/users/newwas wrongly served by the[id]handler (withid = "new").Expected-correct behavior
A literal segment must beat a dynamic param at the same depth (the standard file-based-routing contract, and what the scanner's own comment already intended). Verified empirically against the bundled Hono (4.12.18, default
SmartRouter): registering the static route first resolves/users/newto the correct handler; registering the dynamic one first reproduces the bug.Minimal repro
Two route files:
routes/users/[id].tsandroutes/users/new.ts. Before this change the scanner ordered them['/users/:id', '/users/new'], soGET /users/newhit the[id]handler.The fix
Replace the
localeComparetiebreaker with a segment-aware specificity comparator (static segment → dynamic:param→ catch-all, compared depth-first, then shorter-first), shared by both scan entry points (also removes the previously-duplicated inline sort).Tests
Regression tests added (
packages/void/test/unit/scan.test.ts): a direct static-vs-dynamic case and a nested same-depth case — both fail onorigin/mainand pass after. Local gate:vp test run packages/void/test/unit/scan.test.ts18/18; full--project unitzero-collateral vs a cleanorigin/mainbaseline (identical pre-existing adapter/init-migration failures, unrelated to routing);packages/voidtypecheck + lint + fmt clean.Note: the regression is guarded at the scan-order (unit) layer, which is a faithful proxy for the Hono precedence behavior; there is no playground today with colliding static+dynamic siblings to host an end-to-end dispatch test.
Prepared with AI assistance.