Skip to content

Conversation

@LuggaPugga
Copy link

@LuggaPugga LuggaPugga commented Nov 10, 2025

This fix corrects the route matching logic to ensure that static suffixes are matched
before dynamic segments (e.g., /user/settings is prioritized over /user/:id).
Closes #5799

Summary by CodeRabbit

  • Improvements
    • Route matching now collects exact matches and prefers routes that end with static segments before falling back to fuzzy matching, improving selection predictability.
  • Tests
    • Added parameterized tests validating static-suffix vs. dynamic-parameter route selection across multiple scenarios.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 10, 2025

Walkthrough

Collects exact-match route candidates during matching, marks candidates whose last segment is a static pathname segment, prefers exact matches that end with a static segment when selecting a route, and falls back to the prior fuzzy-match candidate if no prioritized exact match exists. Adds pathname parsing/segment imports.

Changes

Cohort / File(s) Summary
Router exact-match logic
packages/router-core/src/router.ts
Add collection of exact-match candidates, compute endsWithStatic by parsing last route/path segments (uses parsePathname, SEGMENT_TYPE_PATHNAME, Segment), prefer exact matches with endsWithStatic === true; fallback to existing fuzzy-match selection; update type/imports (ParsePathnameCache, Segment, parsePathname, SEGMENT_TYPE_PATHNAME).
Tests: static-suffix priority
packages/router-core/tests/processRouteTree.test.ts
Add parameterized tests asserting that routes with a static suffix are chosen over dynamic-parameter routes in various matching scenarios.

Sequence Diagram(s)

sequenceDiagram
    participant C as Client
    participant R as Router.match
    participant P as parsePathname
    participant E as ExactCollector
    participant S as Selector
    participant F as FuzzyCandidate

    C->>R: request(pathname)
    R->>P: parse pathname & route pattern segments
    R->>E: collect exact-match candidates (compute endsWithStatic)
    E-->>S: candidates + endsWithStatic flags
    alt exact matches exist
        S-->>R: select best exact (prefer endsWithStatic = true)
        R-->>C: return exact match + params
    else
        F-->>R: use prior fuzzy-match candidate
        R-->>C: return fuzzy match + params
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to last-segment extraction and endsWithStatic computation (trailing slashes, empty/optional segments, case sensitivity).
  • Verify imports/types: Segment, parsePathname, SEGMENT_TYPE_PATHNAME, and ParsePathnameCache.
  • Confirm tests correctly exercise prioritized selection and edge cases.

Possibly related PRs

Suggested reviewers

  • Sheraff
  • schiller-manuel
  • nlynzaad

Poem

🐇 I hopped through segments, sniffed the end,
Static footprints meant I needn't bend.
Exact wins out where suffixes gleam,
I chose the route like a quiet dream. 🥕

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main change: prioritizing static suffixes over dynamic segments in route matching, which is the core fix described in the PR.
Linked Issues check ✅ Passed The PR implements the exact-match routing logic with static suffix prioritization to fix issue #5799, ensuring routes with static suffixes are matched before dynamic parameters.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the route matching priority issue: exact-match logic, static suffix detection, and comprehensive test coverage for the fix.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8010064 and 13142ff.

📒 Files selected for processing (1)
  • packages/router-core/tests/processRouteTree.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/router-core/tests/processRouteTree.test.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/router-core/src/router.ts (1)

2691-2702: Well-structured setup for enhanced matching.

The exactMatches array and getLastNonSlashSegment helper are cleanly implemented. The helper correctly skips slash delimiters to find the last meaningful segment for comparison.

Consider adding a brief inline comment above line 2697 explaining the purpose:

+    // Helper to find the last meaningful (non-slash) segment for static suffix comparison
     const getLastNonSlashSegment = (segments: ReadonlyArray<Segment>) => {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1b75808 and 4a850d1.

📒 Files selected for processing (1)
  • packages/router-core/src/router.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/router-core/src/router.ts
packages/router-core/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep framework-agnostic core router logic in packages/router-core/

Files:

  • packages/router-core/src/router.ts
🧠 Learnings (8)
📓 Common learnings
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts:167-172
Timestamp: 2025-09-22T00:56:53.426Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments during path parsing, but preserved in base path segments. This is the expected behavior implemented in PR #5182.
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5284
File: e2e/react-start/basic/server.js:50-0
Timestamp: 2025-09-28T21:41:45.233Z
Learning: In Express v5, catch-all routes must use named wildcards. Use `/*splat` to match everything except root path, or `/{*splat}` (with braces) to match including root path. The old `*` syntax is not allowed and will cause "Missing parameter name" errors. This breaking change requires explicit naming of wildcard parameters.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5732
File: packages/start-client-core/src/client/hydrateStart.ts:6-9
Timestamp: 2025-11-02T16:16:24.898Z
Learning: In packages/start-client-core/src/client/hydrateStart.ts, the `import/no-duplicates` ESLint disable is necessary for imports from `#tanstack-router-entry` and `#tanstack-start-entry` because both aliases resolve to the same placeholder file (`fake-start-entry.js`) in package.json during static analysis, even though they resolve to different files at runtime.
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{router-cli,router-generator,router-plugin,virtual-file-routes}/** : Keep CLI, generators, bundler plugins, and virtual file routing utilities in their dedicated tooling package directories

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{router-devtools,*-router-devtools}/** : Keep router devtools packages in packages/router-devtools/ and packages/*-router-devtools/

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Applied to files:

  • packages/router-core/src/router.ts
🧬 Code graph analysis (1)
packages/router-core/src/router.ts (1)
packages/router-core/src/path.ts (3)
  • Segment (11-22)
  • parsePathname (235-245)
  • SEGMENT_TYPE_PATHNAME (6-6)
🔇 Additional comments (3)
packages/router-core/src/router.ts (3)

14-14: LGTM: Import additions support enhanced matching logic.

The new imports (SEGMENT_TYPE_PATHNAME, parsePathname, Segment) are properly sourced from the ./path module and necessary for the segment-based route matching enhancements.

Also applies to: 18-18, 36-36


2704-2730: Correct implementation of static suffix prioritization.

The refactored logic properly distinguishes fuzzy matches (with ** wildcard capture) from exact matches, then evaluates whether exact matches end with matching static segments. The segment type check (SEGMENT_TYPE_PATHNAME) correctly identifies static path components versus dynamic parameters.

For example, given path /posts/settings:

  • Route /posts/settings: Both segments are static PATHNAME type with value "settings"endsWithStatic: true
  • Route /posts/:id: Route segment is PARAM type, path segment is PATHNAME type → endsWithStatic: false

The cache parameter on parsePathname calls mitigates any performance concerns from repeated parsing.


2732-2741: Code prioritization logic is correct; no actionable issues found.

The route matching method correctly prioritizes exact matches ending with static path segments over other exact matches, with fallback to fuzzy matching. The sort by endsWithStatic (descending) ensures specific routes like /posts/settings are matched before dynamic routes like /posts/:id. When multiple routes have the same endsWithStatic value, stable sort preserves the original flatRoutes order—an acceptable tie-breaker since conflicting matches at the same specificity level are rare in practice.

Integration and e2e tests exercise this logic indirectly through route navigation workflows. No regressions detected.

@nx-cloud
Copy link

nx-cloud bot commented Nov 11, 2025

View your CI Pipeline Execution ↗ for commit 13142ff

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 9m 14s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1m 27s View ↗

☁️ Nx Cloud last updated this comment at 2025-11-11 18:11:59 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 11, 2025

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@5805

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@5805

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@5805

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@5805

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@5805

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@5805

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@5805

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@5805

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@5805

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@5805

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@5805

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@5805

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@5805

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@5805

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@5805

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@5805

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@5805

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@5805

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@5805

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@5805

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@5805

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@5805

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@5805

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@5805

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@5805

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@5805

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@5805

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@5805

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@5805

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@5805

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@5805

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@5805

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@5805

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@5805

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@5805

commit: 13142ff

@birkskyum
Copy link
Member

@LuggaPugga can you add a test for this?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
packages/router-core/src/router.ts (1)

730-739: Consider documenting tie-breaking behavior for multiple static suffix matches.

The sorting correctly prioritizes routes ending with static segments. However, when multiple routes have endsWithStatic: true, the selection depends on flatRoutes iteration order (line 702).

While this is likely acceptable for most cases, consider:

  1. Documenting this tie-breaking behavior to set expectations for route registration order
  2. Optionally adding secondary criteria (e.g., route specificity, path length, or param count) if deterministic ordering independent of registration order is desired
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a850d1 and 8f46add.

📒 Files selected for processing (1)
  • packages/router-core/src/router.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/router-core/src/router.ts
packages/router-core/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep framework-agnostic core router logic in packages/router-core/

Files:

  • packages/router-core/src/router.ts
🧠 Learnings (5)
📓 Common learnings
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts:167-172
Timestamp: 2025-09-22T00:56:53.426Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments during path parsing, but preserved in base path segments. This is the expected behavior implemented in PR #5182.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{router-devtools,*-router-devtools}/** : Keep router devtools packages in packages/router-devtools/ and packages/*-router-devtools/
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{router-cli,router-generator,router-plugin,virtual-file-routes}/** : Keep CLI, generators, bundler plugins, and virtual file routing utilities in their dedicated tooling package directories
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/
Learnt from: nlynzaad
Repo: TanStack/router PR: 5284
File: e2e/react-start/basic/server.js:50-0
Timestamp: 2025-09-28T21:41:45.233Z
Learning: In Express v5, catch-all routes must use named wildcards. Use `/*splat` to match everything except root path, or `/{*splat}` (with braces) to match including root path. The old `*` syntax is not allowed and will cause "Missing parameter name" errors. This breaking change requires explicit naming of wildcard parameters.
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-28T21:41:45.233Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5284
File: e2e/react-start/basic/server.js:50-0
Timestamp: 2025-09-28T21:41:45.233Z
Learning: In Express v5, catch-all routes must use named wildcards. Use `/*splat` to match everything except root path, or `/{*splat}` (with braces) to match including root path. The old `*` syntax is not allowed and will cause "Missing parameter name" errors. This breaking change requires explicit naming of wildcard parameters.

Applied to files:

  • packages/router-core/src/router.ts
🧬 Code graph analysis (1)
packages/router-core/src/router.ts (1)
packages/router-core/src/path.ts (3)
  • Segment (11-22)
  • parsePathname (235-245)
  • SEGMENT_TYPE_PATHNAME (6-6)
🔇 Additional comments (3)
packages/router-core/src/router.ts (3)

14-14: LGTM: Imports correctly added for static suffix detection.

The new imports (SEGMENT_TYPE_PATHNAME, parsePathname, and Segment type) are properly typed and necessary for the enhanced route matching logic.

Also applies to: 18-18, 36-36


695-700: LGTM: Helper function correctly finds last non-slash segment.

The backward iteration and optional chaining ensure safe extraction of the last meaningful segment.


689-728: The review comment references incorrect line numbers and code snippet — disregard it.

The code snippet shown (lines 689-728) displays TypeScript type definitions (ParseLocationFn, GetMatchRoutesFn, etc.). The actual matching logic exists at lines 2680-2740 in the same file. This systematic error suggests the wrong code section was reviewed.

While the implementation itself at the correct lines does include the exactMatches array and endsWithStatic prioritization logic as described, the review comment's reference points are wrong and should not be used as guidance for code changes.

Additionally: Test coverage for the endsWithStatic prioritization during actual path matching is minimal. The test suite includes comprehensive route ranking tests, but only one call to getMatchedRoutes exists (testing /foo against optional param routes). There are no tests verifying that paths like /foo/bar correctly prioritize routes ending with static segments over dynamic segments using the endsWithStatic flag.

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a850d1 and 8f46add.

📒 Files selected for processing (1)
  • packages/router-core/src/router.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/router-core/src/router.ts
packages/router-core/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep framework-agnostic core router logic in packages/router-core/

Files:

  • packages/router-core/src/router.ts
🧠 Learnings (9)
📓 Common learnings
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts:167-172
Timestamp: 2025-09-22T00:56:53.426Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments during path parsing, but preserved in base path segments. This is the expected behavior implemented in PR #5182.
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5284
File: e2e/react-start/basic/server.js:50-0
Timestamp: 2025-09-28T21:41:45.233Z
Learning: In Express v5, catch-all routes must use named wildcards. Use `/*splat` to match everything except root path, or `/{*splat}` (with braces) to match including root path. The old `*` syntax is not allowed and will cause "Missing parameter name" errors. This breaking change requires explicit naming of wildcard parameters.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{router-cli,router-generator,router-plugin,virtual-file-routes}/** : Keep CLI, generators, bundler plugins, and virtual file routing utilities in their dedicated tooling package directories

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{router-devtools,*-router-devtools}/** : Keep router devtools packages in packages/router-devtools/ and packages/*-router-devtools/

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-22T00:56:49.237Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Applied to files:

  • packages/router-core/src/router.ts
🧬 Code graph analysis (1)
packages/router-core/src/router.ts (1)
packages/router-core/src/path.ts (3)
  • Segment (11-22)
  • parsePathname (235-245)
  • SEGMENT_TYPE_PATHNAME (6-6)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Preview
  • GitHub Check: Test

@LuggaPugga
Copy link
Author

@LuggaPugga can you add a test for this?

Just did and applied the coderabbit suggestion as well :)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/router-core/src/router.ts (1)

2712-2713: Performance consideration: parsing overhead is acceptable.

The implementation calls parsePathname for both the route and request path for each exact match candidate. While this adds parsing overhead, the impact is mitigated by:

  • The parseCache (LRU cache) avoiding redundant parses
  • Parsing only happens for exact matches, not fuzzy matches
  • Correctness in route selection is more critical than micro-optimizations

The trade-off is reasonable for core routing logic.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f46add and b73f4a7.

📒 Files selected for processing (2)
  • packages/router-core/src/router.ts (3 hunks)
  • packages/router-core/tests/processRouteTree.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use TypeScript in strict mode with extensive type safety across the codebase

Files:

  • packages/router-core/src/router.ts
  • packages/router-core/tests/processRouteTree.test.ts
packages/router-core/**

📄 CodeRabbit inference engine (AGENTS.md)

Keep framework-agnostic core router logic in packages/router-core/

Files:

  • packages/router-core/src/router.ts
  • packages/router-core/tests/processRouteTree.test.ts
🧠 Learnings (12)
📓 Common learnings
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts:167-172
Timestamp: 2025-09-22T00:56:53.426Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments during path parsing, but preserved in base path segments. This is the expected behavior implemented in PR #5182.
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/router-core/** : Keep framework-agnostic core router logic in packages/router-core/

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-10-08T08:11:47.088Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5402
File: packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.nonnested.snapshot.ts:19-21
Timestamp: 2025-10-08T08:11:47.088Z
Learning: Test snapshot files in the router-generator tests directory (e.g., files matching the pattern `packages/router-generator/tests/generator/**/routeTree*.snapshot.ts` or `routeTree*.snapshot.js`) should not be modified or have issues flagged, as they are fixtures used to verify the generator's output and are intentionally preserved as-is.

Applied to files:

  • packages/router-core/src/router.ts
  • packages/router-core/tests/processRouteTree.test.ts
📚 Learning: 2025-10-01T18:30:26.591Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: packages/router-core/src/router.ts:2231-2245
Timestamp: 2025-10-01T18:30:26.591Z
Learning: In `packages/router-core/src/router.ts`, the `resolveRedirect` method intentionally strips the router's origin from redirect URLs when they match (e.g., `https://foo.com/bar` → `/bar` for same-origin redirects) while preserving the full URL for cross-origin redirects. This logic should not be removed or simplified to use `location.publicHref` directly.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-28T21:41:45.233Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5284
File: e2e/react-start/basic/server.js:50-0
Timestamp: 2025-09-28T21:41:45.233Z
Learning: In Express v5, catch-all routes must use named wildcards. Use `/*splat` to match everything except root path, or `/{*splat}` (with braces) to match including root path. The old `*` syntax is not allowed and will cause "Missing parameter name" errors. This breaking change requires explicit naming of wildcard parameters.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{router-cli,router-generator,router-plugin,virtual-file-routes}/** : Keep CLI, generators, bundler plugins, and virtual file routing utilities in their dedicated tooling package directories

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{react-router,solid-router}/** : Implement React and Solid bindings/components only in packages/react-router/ and packages/solid-router/

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-23T17:36:12.598Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-23T17:36:12.598Z
Learning: Applies to packages/{router-devtools,*-router-devtools}/** : Keep router devtools packages in packages/router-devtools/ and packages/*-router-devtools/

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-22T00:56:49.237Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/src/routes/non-nested/named/$baz_.bar.tsx:3-5
Timestamp: 2025-09-22T00:56:49.237Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments (e.g., `$baz_` becomes `baz` in generated types) but should be preserved in base path segments. This is the correct behavior as of the fix in PR #5182.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-09-22T00:56:53.426Z
Learnt from: nlynzaad
Repo: TanStack/router PR: 5182
File: e2e/react-router/basic-file-based/tests/non-nested-paths.spec.ts:167-172
Timestamp: 2025-09-22T00:56:53.426Z
Learning: In TanStack Router, underscores are intentionally stripped from route segments during path parsing, but preserved in base path segments. This is the expected behavior implemented in PR #5182.

Applied to files:

  • packages/router-core/src/router.ts
📚 Learning: 2025-10-14T18:59:33.990Z
Learnt from: FatahChan
Repo: TanStack/router PR: 5475
File: e2e/react-start/basic-prerendering/src/routes/redirect/$target/via-beforeLoad.tsx:8-0
Timestamp: 2025-10-14T18:59:33.990Z
Learning: In TanStack Router e2e test files, when a route parameter is validated at the route level (e.g., using zod in validateSearch or param validation), switch statements on that parameter do not require a default case, as the validation ensures only expected values will reach the switch.

Applied to files:

  • packages/router-core/tests/processRouteTree.test.ts
📚 Learning: 2025-10-01T18:31:35.420Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 5330
File: e2e/react-start/custom-basepath/src/routeTree.gen.ts:58-61
Timestamp: 2025-10-01T18:31:35.420Z
Learning: Do not review files named `routeTree.gen.ts` in TanStack Router repositories, as these are autogenerated files that should not be manually modified.

Applied to files:

  • packages/router-core/tests/processRouteTree.test.ts
🧬 Code graph analysis (2)
packages/router-core/src/router.ts (1)
packages/router-core/src/path.ts (3)
  • Segment (11-22)
  • parsePathname (235-245)
  • SEGMENT_TYPE_PATHNAME (6-6)
packages/router-core/tests/processRouteTree.test.ts (2)
packages/router-core/src/process-route-tree.ts (1)
  • processRouteTree (195-241)
packages/router-core/src/router.ts (1)
  • getMatchedRoutes (2646-2764)
🔇 Additional comments (4)
packages/router-core/src/router.ts (4)

14-18: LGTM! Clean import additions.

The new imports (SEGMENT_TYPE_PATHNAME, parsePathname, Segment) are properly scoped from ./path and necessary for the static suffix detection logic.

Also applies to: 36-36


2689-2700: LGTM! Well-structured helper logic.

The exactMatches array and getLastNonSlashSegment helper are cleanly implemented:

  • The array structure properly tracks the endsWithStatic flag alongside route and params
  • The helper correctly iterates backwards to find the last meaningful segment
  • Edge case handled: returns undefined when all segments are slashes

2706-2737: Excellent! Static suffix detection properly implemented.

The logic correctly distinguishes between fuzzy and exact matches, and properly detects when an exact match ends with a static segment:

  1. Fuzzy matches (** wildcard) are collected separately to allow exact matches to take precedence
  2. Exact matches are parsed to extract the last non-slash segments
  3. Case-insensitive handling is correctly implemented (lines 2716-2730) by normalizing segment values based on route.options.caseSensitive ?? caseSensitive, addressing the previous review concern
  4. Static suffix detection compares normalized pathname segments, ignoring dynamic/optional params

This ensures routes like /{-$owner}/posts/new match /posts/new instead of /posts/$id.


2741-2750: LGTM! Clean prioritization logic.

The selection strategy correctly implements the desired behavior:

  1. Exact matches ending with static segments are sorted first (endsWithStatic: true)
  2. When multiple routes have the same endsWithStatic value, the stable sort preserves the original flatRoutes ranking (which already considers specificity)
  3. Falls back to fuzzy match when no exact matches exist, maintaining backward compatibility

The sort using Number(b.endsWithStatic) - Number(a.endsWithStatic) is idiomatic and correct.

@nlynzaad
Copy link
Contributor

@Sheraff I'm assuming the work you are doing with the matching and others will be intersecting with this. maybe just hold this till you have completed your refactor/rewrite?

@Sheraff
Copy link
Contributor

Sheraff commented Nov 11, 2025

@Sheraff I'm assuming the work you are doing with the matching and others will be intersecting with this. maybe just hold this till you have completed your refactor/rewrite?

Yes, what I'm doing fixes this issue. I don't know when I'll be finished though, it's a pretty major rewrite

@birkskyum
Copy link
Member

@Sheraff
Copy link
Contributor

Sheraff commented Nov 12, 2025

@Sheraff , and it's this PR that's conflicting, right?

Yes, that's the one.

routeParams = matchedParams
break
const routeSegments = parsePathname(route.fullPath, parseCache)
const pathSegments = parsePathname(trimmedPath, parseCache)
Copy link
Contributor

@nlynzaad nlynzaad Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we only need to parse this once right? since this is the trimmedPath we can move this above the for loop?

const routeSegments = parsePathname(route.fullPath, parseCache)
const pathSegments = parsePathname(trimmedPath, parseCache)
const lastRouteSegment = getLastNonSlashSegment(routeSegments)
const lastPathSegment = getLastNonSlashSegment(pathSegments)
Copy link
Contributor

@nlynzaad nlynzaad Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we only need to parse this once right? since this is the trimmedPath we can move this above the for loop?

const lastPathSegment = getLastNonSlashSegment(pathSegments)
const routeCaseSensitive =
route.options?.caseSensitive ?? caseSensitive ?? false
const normalizeSegmentValue = (segment?: Segment) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bit of a nitpick but can we move this above the for loop and just add the routeCaseSensitive as a paramater. This way its only declared once and not with every iteration that has matching params

Comment on lines +2732 to 2750
exactMatches.push({
route,
routeParams: matchedParams,
endsWithStatic: !!endsWithStatic,
})
}
}
}
// did not find a perfect fit, so take the fuzzy matching route if it exists
if (!foundRoute && fuzzyMatch) {

if (exactMatches.length > 0) {
exactMatches.sort(
(a, b) => Number(b.endsWithStatic) - Number(a.endsWithStatic),
)
foundRoute = exactMatches[0]!.route
routeParams = exactMatches[0]!.routeParams
} else if (fuzzyMatch) {
foundRoute = fuzzyMatch.foundRoute
routeParams = fuzzyMatch.routeParams
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should still break out as early possible and if no route is ending with a matched static the original case of first route being matched can still apply.

Suggested change
exactMatches.push({
route,
routeParams: matchedParams,
endsWithStatic: !!endsWithStatic,
})
}
}
}
// did not find a perfect fit, so take the fuzzy matching route if it exists
if (!foundRoute && fuzzyMatch) {
if (exactMatches.length > 0) {
exactMatches.sort(
(a, b) => Number(b.endsWithStatic) - Number(a.endsWithStatic),
)
foundRoute = exactMatches[0]!.route
routeParams = exactMatches[0]!.routeParams
} else if (fuzzyMatch) {
foundRoute = fuzzyMatch.foundRoute
routeParams = fuzzyMatch.routeParams
}
if (endsWithStatic) {
foundRoute = route
routeParams = matchedParams
break
}
if (!foundRoute) {
foundRoute = route
routeParams = matchedParams
}
}
}
}
if (!foundRoute && fuzzyMatch) {
foundRoute = fuzzyMatch.foundRoute
routeParams = fuzzyMatch.routeParams
}
}

@nlynzaad
Copy link
Contributor

@LuggaPugga thanks a lot for this.

We are a bit concerned about the performance impact this might have and given that #5722 solves this issue, as well as a host of performance enhancements, it's probably best to put this on hold for a bit and see how #5722 progresses

@LuggaPugga
Copy link
Author

@LuggaPugga thanks a lot for this.

We are a bit concerned about the performance impact this might have and given that #5722 solves this issue, as well as a host of performance enhancements, it's probably best to put this on hold for a bit and see how #5722 progresses

Should I go ahead and address the suggested changes, or is it better to wait for #5722 before updating this?

@Sheraff
Copy link
Contributor

Sheraff commented Nov 14, 2025

Should I go ahead and address the suggested changes, or is it better to wait for #5722 before updating this?

If all goes well 🤞, we're shipping #5722 this week end, and I incorporated your unit tests to make sure this case was handled. So maybe wait and see.

@nlynzaad
Copy link
Contributor

@LuggaPugga #5722 has been merged. I will close this PR now.

Thanks again for making this PR and the accompanying tests.

It definitely helped to ensure the rewrite addressed this issue.

@nlynzaad nlynzaad closed this Nov 15, 2025
@LuggaPugga LuggaPugga deleted the fix-route-matching branch November 15, 2025 15:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Route matching prioritizes dynamic segment over static suffix

4 participants