Skip to content

Conversation

@nlynzaad
Copy link
Contributor

@nlynzaad nlynzaad commented Nov 12, 2025

During the matching process, when building the location, we interpolate the next path while leaving the params in place, i.e. returning the route back in its original route form. This is unnecessary and can be avoided by just using the original next.to path.

This also simplifies interpolatePath in that leaveParams is no longer necessary which in turn resolves #5674 since the logic in interpolatePath when leaveParams=true was not returning the segments in the correct form.

This PR applies the above changes and adds tests to verify that the params are still matched correctly and that matchRoutes now also succeeds where it was previously failing

Summary by CodeRabbit

  • New Features

    • Added a new runtime capability to inspect detailed route matching information.
  • Improvements

    • Simplified and standardized path parameter interpolation and encoding for more consistent route results.
  • Tests

    • Expanded test coverage for parameter-matching scenarios, including wildcards, optional params, and varied param forms.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 12, 2025

Walkthrough

Adds and exports a new useMatchRoute hook, expands React and Solid tests for many param patterns, removes the leaveParams branch from interpolatePath (always encodes params), and adjusts buildLocation to return the original template when leaveParams is requested.

Changes

Cohort / File(s) Summary
React tests
packages/react-router/tests/Matches.test.tsx
Added comprehensive "matching on different param types" tests, imports test helpers, uses memory history, renders RouterProvider, and cleans up after each test. Tests use useMatchRoute() to assert param extraction and match results.
Solid tests
packages/solid-router/tests/Matches.test.tsx
Added equivalent expanded test suite for Solid; per-test cleanup and assertions via useMatchRoute().
Path interpolation
packages/router-core/src/path.ts
Removed leaveParams from InterpolatePathOptions and eliminated branches that preserved placeholders; interpolatePath now always encodes/interpolates parameters (minor formatting tweak for splat handling).
Router location building
packages/router-core/src/router.ts
buildLocation now sets nextPathname to the raw nextTo when opts.leaveParams is true; otherwise it interpolates/decodes as before.
Devtools tweak
packages/router-devtools-core/src/BaseTanStackRouterDevtoolsPanel.tsx
Removed explicit leaveParams: false option from an interpolatePath call.
Public API exports
packages/react-router/..., packages/solid-router/...
Exported useMatchRoute in public router APIs and updated tests to import and use it.

Sequence Diagram(s)

sequenceDiagram
    participant App as App (component)
    participant useMatchRoute as useMatchRoute
    participant buildLocation as buildLocation
    participant interpolatePath as interpolatePath
    participant matcher as pathMatcher

    App->>useMatchRoute: call matchRoute({ to: '/page-{$page}' })
    activate useMatchRoute

    useMatchRoute->>buildLocation: build candidate location (opts.leaveParams = true/false)
    activate buildLocation

    alt opts.leaveParams == true
        buildLocation-->>useMatchRoute: return candidate = '/page-{$page}'
    else
        buildLocation->>interpolatePath: interpolatePath(template, params)
        interpolatePath-->>buildLocation: return '/page-a' (encoded)
        buildLocation-->>useMatchRoute: return candidate = '/page-a'
    end
    deactivate buildLocation

    useMatchRoute->>matcher: compare candidate vs current '/page-a'
    activate matcher
    matcher-->>useMatchRoute: match result (params or false)
    deactivate matcher

    useMatchRoute-->>App: return match result
    deactivate useMatchRoute
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Files warranting extra attention:
    • packages/router-core/src/path.ts — verify all param forms (prefix/suffix, optional, splat) still interpolate and encode correctly without leaveParams.
    • packages/router-core/src/router.ts — confirm buildLocation behavior when opts.leaveParams is true and ensure navigation URLs remain correct.
    • New tests in React and Solid — confirm test assumptions and stability.

Possibly related PRs

Suggested reviewers

  • Sheraff
  • schiller-manuel

Poem

🐰 I hopped through braces, prefixes, and dots,
I sniffed every splat in my little hopslots,
No placeholders lingering near,
Params now surface clear,
I twitched my nose — the matches connect! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: refactoring to use the original nextTo path instead of interpolating with leaveParams when building locations.
Linked Issues check ✅ Passed The PR successfully addresses issue #5674 by removing leaveParams logic and using the original nextTo path, fixing useMatchRoute to correctly match routes with prefixed parameters.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the leaveParams issue: removing the leaveParams option from interpolatePath, updating router.ts logic, removing leaveParams from devtools, and adding tests.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 5674

📜 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 2b6cc8e and c8ce2b2.

📒 Files selected for processing (2)
  • packages/router-core/src/path.ts (2 hunks)
  • packages/router-devtools-core/src/BaseTanStackRouterDevtoolsPanel.tsx (0 hunks)
💤 Files with no reviewable changes (1)
  • packages/router-devtools-core/src/BaseTanStackRouterDevtoolsPanel.tsx
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
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: 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: 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.
📚 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/path.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/path.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/path.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/path.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/path.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/path.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/src/path.ts
⏰ 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: Test
  • GitHub Check: Preview
🔇 Additional comments (1)
packages/router-core/src/path.ts (1)

400-494: LGTM! Simplification improves maintainability.

The removal of leaveParams conditional logic streamlines interpolatePath to always encode parameters, eliminating the confusing dual-behavior pattern. The blank lines added at lines 452 and 465 improve readability by visually separating variable setup from return statements. This refactoring aligns with the PR objective to simplify the function and move the responsibility of preserving original route forms to the caller.


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

@nx-cloud
Copy link

nx-cloud bot commented Nov 12, 2025

View your CI Pipeline Execution ↗ for commit c8ce2b2

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

☁️ Nx Cloud last updated this comment at 2025-11-13 23:54:52 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 12, 2025

More templates

@tanstack/arktype-adapter

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

@tanstack/directive-functions-plugin

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

@tanstack/eslint-plugin-router

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

@tanstack/history

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

@tanstack/nitro-v2-vite-plugin

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

@tanstack/react-router

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

@tanstack/react-router-devtools

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

@tanstack/react-router-ssr-query

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

@tanstack/react-start

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

@tanstack/react-start-client

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

@tanstack/react-start-server

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

@tanstack/router-cli

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

@tanstack/router-core

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

@tanstack/router-devtools

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

@tanstack/router-devtools-core

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

@tanstack/router-generator

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

@tanstack/router-plugin

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

@tanstack/router-ssr-query-core

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

@tanstack/router-utils

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

@tanstack/router-vite-plugin

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

@tanstack/server-functions-plugin

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

@tanstack/solid-router

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

@tanstack/solid-router-devtools

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

@tanstack/solid-router-ssr-query

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

@tanstack/solid-start

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

@tanstack/solid-start-client

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

@tanstack/solid-start-server

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

@tanstack/start-client-core

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

@tanstack/start-plugin-core

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

@tanstack/start-server-core

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

@tanstack/start-static-server-functions

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

@tanstack/start-storage-context

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

@tanstack/valibot-adapter

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

@tanstack/virtual-file-routes

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

@tanstack/zod-adapter

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

commit: c8ce2b2

@nlynzaad
Copy link
Contributor Author

@Sheraff This probably overlaps with #5722 as well. if the tests in the matches.test.tsx files for react and solid passes in #5722 then we can probably close this one.

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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fb88ffb and 9efbeca.

📒 Files selected for processing (2)
  • packages/router-core/src/path.ts (6 hunks)
  • packages/router-core/tests/path.test.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/router-core/tests/path.test.ts
🧰 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/path.ts
packages/router-core/**

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • packages/router-core/src/path.ts
🧠 Learnings (4)
📓 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: 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.
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: 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.
📚 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/path.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/path.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/path.ts
⏰ 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: Test
  • GitHub Check: Preview
🔇 Additional comments (4)
packages/router-core/src/path.ts (4)

447-454: LGTM - Correctly preserves placeholder for missing splat parameters.

When leaveParams is true and the splat parameter is missing, this correctly returns the placeholder format (e.g., prefix{$}suffix) instead of omitting the segment. This enables proper route matching with curly-brace syntax.


508-511: LGTM - Correctly preserves placeholder for missing optional parameters.

When leaveParams is true and the optional parameter is missing, this correctly returns only the placeholder format (e.g., prefix{-$param}suffix). This is the right pattern that the wildcard and regular param cases should also follow.


523-526: LGTM - Correctly preserves placeholder for existing optional parameters.

When leaveParams is true, this correctly returns only the placeholder format, regardless of whether the parameter has a value. This consistent approach enables proper route matching.


838-840: Verify: Should empty optional parameter values be excluded from the result?

This code prevents adding optional parameters with empty string values to the extracted params. For example, if a route is /prefix{-$param}suffix and the actual path is /prefixsuffix, the extracted _paramValue would be '', which is not added to params.

This creates an asymmetry with the interpolation logic (line 507), which treats empty strings as valid values distinct from null/undefined. Consider:

  • Is it intentional that users cannot distinguish between "optional param present but empty" vs "optional param not present"?
  • Could any use cases legitimately need to match empty parameter values?

For most scenarios, omitting empty optional params seems reasonable, but please confirm this is the intended behavior.

@nlynzaad nlynzaad marked this pull request as draft November 12, 2025 23:47
@nlynzaad nlynzaad changed the title fix(router-core): resolve problems with matching paths using curly brackets around params refactor(router-core): use original nextTo path when building location in its route form Nov 13, 2025
@nlynzaad nlynzaad marked this pull request as ready for review November 13, 2025 23:02
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/react-router/tests/Matches.test.tsx (1)

148-356: Thorough param‑matching coverage; tighten textContent handling and double‑check optional param expectations

The new matching on different param types table‑driven suite is a solid addition and clearly targets the regression around prefix/suffix and brace syntax; overall structure and use of createMemoryHistory + useMatchRoute look good.

Two minor points to consider:

  1. Guard textContent to satisfy TS and avoid latent null issues

screen.findByTestId guarantees the element exists, but HTMLElement['textContent'] is typed as string | null. To keep TypeScript happy (and be explicit about the assumption), it would be better to assert non‑null or provide a fallback before JSON.parse:

-      expect(JSON.parse(paramsToCheck.textContent)).toEqual(params)
-      expect(JSON.parse(matchesToCheck.textContent)).toEqual(matchParams)
+      expect(JSON.parse(paramsToCheck.textContent!)).toEqual(params)
+      expect(JSON.parse(matchesToCheck.textContent!)).toEqual(matchParams)

(or use a null‑coalescing fallback if you prefer a safer runtime behavior).

  1. Verify the intentional difference between params and matchParams for some optional cases

For the “optional param with prefix/suffix and no value” cases you expect params to be {} while matchParams includes { id: '' }, whereas in the complex case "optional param with required param, prefix, suffix, wildcard and no value" both params and matchParams include id: ''. If this asymmetry reflects existing, intentional behavior between Route.useParams() and matchRoute, great—might be worth a short inline comment on one of those cases to document it. If not intentional, this is a good place to harmonize the expectations while you’re formalizing this behavior in tests.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9efbeca and 9e545ef.

📒 Files selected for processing (4)
  • packages/react-router/tests/Matches.test.tsx (4 hunks)
  • packages/router-core/src/path.ts (2 hunks)
  • packages/router-core/src/router.ts (1 hunks)
  • packages/solid-router/tests/Matches.test.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/router-core/src/path.ts
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
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: 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: 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/react-router/tests/Matches.test.tsx
  • packages/router-core/src/router.ts
  • packages/solid-router/tests/Matches.test.tsx
📚 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/react-router/tests/Matches.test.tsx
  • packages/solid-router/tests/Matches.test.tsx
📚 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/solid-router/tests/Matches.test.tsx
🧬 Code graph analysis (3)
packages/react-router/tests/Matches.test.tsx (1)
packages/react-router/src/Matches.tsx (1)
  • useMatchRoute (142-172)
packages/router-core/src/router.ts (2)
packages/router-core/src/utils.ts (1)
  • decodePath (499-559)
packages/router-core/src/path.ts (1)
  • interpolatePath (402-497)
packages/solid-router/tests/Matches.test.tsx (2)
packages/solid-router/src/Matches.tsx (1)
  • useMatchRoute (123-154)
packages/solid-router/src/RouterProvider.tsx (1)
  • RouterProvider (44-53)
🔇 Additional comments (5)
packages/solid-router/tests/Matches.test.tsx (3)

1-20: LGTM! Well-organized imports for comprehensive testing.

The new imports properly support the expanded test suite:

  • afterEach, describe, and waitFor enable robust test structure and async assertions
  • createMemoryHistory provides isolated routing history for each test
  • useMatchRoute is the newly exposed public API hook being tested

153-310: Excellent test coverage for parameter matching edge cases.

The parameterized test suite comprehensively covers the issue described in #5674 and beyond:

  • Standard and curly-brace parameter syntax (/$id vs /{$id})
  • Parameters with prefixes and/or suffixes (e.g., /prefix-{$id}-suffix)
  • Wildcard parameters with various prefix/suffix combinations
  • Optional parameters in isolation and combination with other param types
  • Complex scenarios mixing multiple parameter types

This thorough coverage should prevent regressions in parameter matching behavior.


311-363: LGTM! Well-structured test implementation following Solid.js patterns.

The test implementation correctly:

  • Isolates each test with fresh router and memory history instances
  • Uses router.history.push() to trigger navigation programmatically
  • Employs waitFor to handle async DOM updates from Solid.js reactivity
  • Calls accessor functions (signals) with () syntax per Solid.js conventions
  • Tests both Route.useParams() and the new useMatchRoute() hook
  • Validates extracted parameters match expected values for each scenario

The per-test isolation and comprehensive assertions ensure reliable verification of the parameter matching fixes.

packages/react-router/tests/Matches.test.tsx (2)

1-14: Imports and new useMatchRoute usage look consistent

The added imports (afterEach, act, cleanup, createMemoryHistory, useMatchRoute) are all used below and keep the test file cohesive; no issues from my side here.


127-147: Pending component test remains valid after surrounding changes

The should show pendingComponent of root route test still accurately exercises pendingComponent vs defaultPendingComponent; the minor structural/whitespace changes around the router creation do not affect behavior.

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/path.ts (1)

390-400: Remove duplicate JSDoc comment.

There are two JSDoc blocks before the interpolatePath function. The first block (lines 390-396) contains outdated information stating "Optionally leaves placeholders or wildcards in place," which is no longer accurate after the removal of leaveParams. The second block (lines 397-400) reflects the current behavior.

Apply this diff to remove the outdated comment:

-/**
- * Interpolate params and wildcards into a route path template.
- *
- * - Encodes params safely (configurable allowed characters)
- * - Supports `{-$optional}` segments, `{prefix{$id}suffix}` and `{$}` wildcards
- * - Optionally leaves placeholders or wildcards in place
- */
 /**
  * Interpolate params and wildcards into a route path template.
  * Encodes safely and supports optional params and custom decode char maps.
  */
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9e545ef and 2b6cc8e.

📒 Files selected for processing (2)
  • packages/router-core/src/path.ts (2 hunks)
  • packages/router-core/src/router.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/router-core/src/router.ts
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
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: 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: 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: 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.
📚 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/path.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/path.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/path.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/path.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/path.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/path.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/src/path.ts
⏰ 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: Test
  • GitHub Check: Preview

Copy link
Contributor

@Sheraff Sheraff left a comment

Choose a reason for hiding this comment

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

🎉

@nlynzaad nlynzaad merged commit f1bd5c5 into main Nov 13, 2025
6 checks passed
@nlynzaad nlynzaad deleted the 5674 branch November 13, 2025 23:55
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.

useMatchRoute does not match routes with prefix.

3 participants