-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Expose fullPath and to on RouteApi from getRouteApi #6370
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Adds fullPath and to getters to RouteApi, enabling type-safe navigation
patterns like <Link from={routeApi.fullPath} to="./relative">.
Uses the global router reference (window.__TSR_ROUTER__) to resolve the
correct fullPath at runtime, correctly handling pathless/layout routes
where id differs from fullPath.
📝 WalkthroughWalkthroughThis PR adds two new public properties ( Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~15 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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. Comment |
There was a problem hiding this 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
🤖 Fix all issues with AI agents
In @packages/router-core/src/route.ts:
- Around line 1915-1927: Update the JSDoc for the fullPath getter to document
its SSR/runtime fallback: note that fullPath (getter fullPath on the route API)
returns the computed route.fullPath when window.__TSR_ROUTER__ and
routesById[this.id] are available at runtime, but during SSR or before
createRouter completes (i.e., when window.__TSR_ROUTER__ is absent) layout
routes without a path will return this.id (e.g., "__root_/posts") instead of a
resolved path (e.g., "/posts"); mention when this limitation occurs and suggest
checking for a router instance or using client-side code if the resolved path is
required.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
packages/react-router/tests/route.test.tsxpackages/react-router/tests/routeApi.test-d.tsxpackages/router-core/src/route.tspackages/solid-router/tests/route.test.tsxpackages/solid-router/tests/routeApi.test-d.tsxpackages/vue-router/tests/route.test.tsxpackages/vue-router/tests/routeApi.test-d.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use TypeScript strict mode with extensive type safety for all code
Files:
packages/react-router/tests/routeApi.test-d.tsxpackages/router-core/src/route.tspackages/solid-router/tests/route.test.tsxpackages/vue-router/tests/routeApi.test-d.tsxpackages/solid-router/tests/routeApi.test-d.tsxpackages/vue-router/tests/route.test.tsxpackages/react-router/tests/route.test.tsx
**/*.{js,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Implement ESLint rules for router best practices using the ESLint plugin router
Files:
packages/react-router/tests/routeApi.test-d.tsxpackages/router-core/src/route.tspackages/solid-router/tests/route.test.tsxpackages/vue-router/tests/routeApi.test-d.tsxpackages/solid-router/tests/routeApi.test-d.tsxpackages/vue-router/tests/route.test.tsxpackages/react-router/tests/route.test.tsx
🧠 Learnings (7)
📓 Common learnings
Learnt from: schiller-manuel
Repo: TanStack/router PR: 6120
File: packages/router-generator/src/generator.ts:654-657
Timestamp: 2025-12-17T02:17:55.086Z
Learning: In `packages/router-generator/src/generator.ts`, pathless_layout routes must receive a `path` property when they have a `cleanedPath`, even though they are non-path routes. This is necessary because child routes inherit the path from their parent, and without this property, child routes would not have the correct full path at runtime.
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.
📚 Learning: 2025-12-17T02:17:55.086Z
Learnt from: schiller-manuel
Repo: TanStack/router PR: 6120
File: packages/router-generator/src/generator.ts:654-657
Timestamp: 2025-12-17T02:17:55.086Z
Learning: In `packages/router-generator/src/generator.ts`, pathless_layout routes must receive a `path` property when they have a `cleanedPath`, even though they are non-path routes. This is necessary because child routes inherit the path from their parent, and without this property, child routes would not have the correct full path at runtime.
Applied to files:
packages/react-router/tests/routeApi.test-d.tsxpackages/router-core/src/route.tspackages/solid-router/tests/route.test.tsxpackages/vue-router/tests/routeApi.test-d.tsxpackages/solid-router/tests/routeApi.test-d.tsxpackages/vue-router/tests/route.test.tsxpackages/react-router/tests/route.test.tsx
📚 Learning: 2025-12-21T12:52:35.231Z
Learnt from: Sheraff
Repo: TanStack/router PR: 6171
File: packages/router-core/src/new-process-route-tree.ts:898-898
Timestamp: 2025-12-21T12:52:35.231Z
Learning: In `packages/router-core/src/new-process-route-tree.ts`, the matching logic intentionally allows paths without trailing slashes to match index routes with trailing slashes (e.g., `/a` can match `/a/` route), but not vice-versa (e.g., `/a/` cannot match `/a` layout route). This is implemented via the condition `!pathIsIndex || node.kind === SEGMENT_TYPE_INDEX` and is a deliberate design decision to provide better UX by being permissive with missing trailing slashes.
Applied to files:
packages/react-router/tests/routeApi.test-d.tsxpackages/router-core/src/route.tspackages/solid-router/tests/route.test.tsxpackages/vue-router/tests/routeApi.test-d.tsxpackages/solid-router/tests/routeApi.test-d.tsxpackages/vue-router/tests/route.test.tsxpackages/react-router/tests/route.test.tsx
📚 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/routeApi.test-d.tsxpackages/solid-router/tests/route.test.tsxpackages/vue-router/tests/routeApi.test-d.tsxpackages/solid-router/tests/routeApi.test-d.tsxpackages/vue-router/tests/route.test.tsxpackages/react-router/tests/route.test.tsx
📚 Learning: 2025-12-06T15:03:07.223Z
Learnt from: CR
Repo: TanStack/router PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-06T15:03:07.223Z
Learning: Applies to **/*.{js,ts,tsx} : Implement ESLint rules for router best practices using the ESLint plugin router
Applied to files:
packages/react-router/tests/routeApi.test-d.tsxpackages/solid-router/tests/route.test.tsxpackages/vue-router/tests/routeApi.test-d.tsxpackages/solid-router/tests/routeApi.test-d.tsxpackages/vue-router/tests/route.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/solid-router/tests/route.test.tsxpackages/solid-router/tests/routeApi.test-d.tsx
📚 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/vue-router/tests/routeApi.test-d.tsxpackages/solid-router/tests/routeApi.test-d.tsx
🧬 Code graph analysis (5)
packages/react-router/tests/routeApi.test-d.tsx (1)
packages/virtual-file-routes/src/api.ts (1)
rootRoute(10-19)
packages/router-core/src/route.ts (1)
packages/virtual-file-routes/src/api.ts (1)
route(66-84)
packages/solid-router/tests/route.test.tsx (1)
packages/virtual-file-routes/src/api.ts (1)
rootRoute(10-19)
packages/solid-router/tests/routeApi.test-d.tsx (1)
packages/virtual-file-routes/src/api.ts (1)
rootRoute(10-19)
packages/react-router/tests/route.test.tsx (1)
packages/virtual-file-routes/src/api.ts (1)
rootRoute(10-19)
🔇 Additional comments (15)
packages/router-core/src/route.ts (1)
1929-1935: LGTM!toas an alias forfullPathmaintains API parity withRoute.to.This provides a consistent API surface where both
RouteandRouteApiexposetofor navigation purposes.packages/solid-router/tests/routeApi.test-d.tsx (2)
33-45: LGTM! Good test setup for pathless layout route scenario.The route definitions correctly set up the layout route with
id: '_layout'(no path) and a childpostsRoutewithpath: 'posts', which creates the expectedid = '/_layout/posts'andfullPath = '/posts'relationship.
119-145: LGTM! Comprehensive type tests for the newfullPathandtoproperties.The tests correctly verify:
- Standard routes:
fullPath,to, andidall resolve to the same type ('/invoices/$invoiceId')- Pathless layout routes:
idincludes the layout segment ('/_layout/posts') whilefullPathandtoexclude it ('/posts')This ensures type-safe navigation patterns like
<Link from={routeApi.fullPath}>will work correctly.packages/solid-router/tests/route.test.tsx (2)
64-79: LGTM! Good runtime validation for standard route behavior.These tests verify that
fullPathandtoare accessible and return expected values. For standard routes without a pathless layout prefix, the fallback behavior (returningid) produces the correct result.
82-99: LGTM! Critical test for pathless layout route resolution.This test correctly:
- Sets up a router with a pathless layout route (
id: '_layout') and child route- Calls
createRouterwhich populateswindow.__TSR_ROUTER__- Verifies that
api.idremains'/_layout/posts'whileapi.fullPathandapi.toresolve to'/posts'This validates the core functionality of the PR - resolving the actual navigable path for routes nested under pathless layouts.
packages/vue-router/tests/routeApi.test-d.tsx (2)
32-44: LGTM! Consistent test setup across frameworks.The pathless layout route setup mirrors the Solid and React router tests, ensuring consistent behavior validation across all supported frameworks.
110-136: LGTM! Type tests maintain cross-framework consistency.The Vue router type tests correctly verify the same type relationships as the other frameworks:
- Standard routes:
fullPath === to === id- Pathless layout routes:
idincludes layout segment,fullPathandtoexclude itpackages/react-router/tests/routeApi.test-d.tsx (2)
32-44: LGTM! Consistent pathless layout route setup.The route definitions follow the same pattern as the other framework tests, ensuring uniform behavior across React, Solid, and Vue routers.
108-140: LGTM! Comprehensive type tests with practicalRoutePathsvalidation.The React tests include an additional valuable test at lines 136-140 that verifies
fullPathis assignable toRoutePaths, confirming it can be used in<Link from={routeApi.fullPath}>. This demonstrates the practical use case that motivated the feature.packages/vue-router/tests/route.test.tsx (3)
65-73: LGTM!These tests correctly verify that the
fullPathandtoproperties are exposed on the route API object. The tests run without a router initialized, which appropriately validates the fallback behavior where these properties equal the route ID.
75-80: LGTM!Good coverage for standard routes where
fullPathshould equalid. The additional assertionexpect(api.fullPath).toBe(api.id)explicitly documents this invariant.
82-99: LGTM - properly tests pathless layout route handling.This test correctly validates the key feature: for pathless layout routes where
id = '/_layout/posts', thefullPathresolves to/postsby stripping the layout segment. The router is properly created before callinggetRouteApi, enabling the global router lookup. Based on learnings, pathless layout routes need special handling because child routes inherit paths from their parent.packages/react-router/tests/route.test.tsx (3)
66-74: LGTM!Property existence tests are correctly implemented and consistent with the Vue router tests.
76-81: LGTM!Standard route test correctly verifies that
fullPath === idfor routes without pathless layout ancestors.
83-100: LGTM - pathless layout route test is well-structured.The test properly sets up a layout route hierarchy and validates that
getRouteApi('/_layout/posts')returnsfullPath: '/posts'while preservingid: '/_layout/posts'. This is consistent with the Vue router test and correctly exercises the global router lookup mechanism.
| /** | ||
| * The full path of the route, which can be used as the `from` parameter | ||
| * in navigation APIs like `<Link from={routeApi.fullPath}>` or `navigate({ from: routeApi.fullPath })`. | ||
| */ | ||
| get fullPath(): RouteTypesById<TRouter, TId>['fullPath'] { | ||
| if (typeof window !== 'undefined' && window.__TSR_ROUTER__) { | ||
| const route = window.__TSR_ROUTER__.routesById[this.id as string] | ||
| if (route) { | ||
| return route.fullPath as RouteTypesById<TRouter, TId>['fullPath'] | ||
| } | ||
| } | ||
| return this.id as RouteTypesById<TRouter, TId>['fullPath'] | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# Search for __TSR_ROUTER__ type declaration and definition
rg -n "__TSR_ROUTER__" --type=ts -B2 -A2 | head -100Repository: TanStack/router
Length of output: 4492
🏁 Script executed:
# Look at the actual file to understand the context better
head -n 1940 packages/router-core/src/route.ts | tail -n 50Repository: TanStack/router
Length of output: 1403
🏁 Script executed:
# Search for fullPath property definition and assignments
rg -n "fullPath" packages/router-core/src/ --type=ts -B1 -A1 | head -150Repository: TanStack/router
Length of output: 9142
🏁 Script executed:
# Search for documentation about BaseRouteApi.fullPath or routeApi behavior
rg -n "routeApi\.fullPath|BaseRouteApi" --type=ts packages/router-core/src/ -B3 -A3 | head -80Repository: TanStack/router
Length of output: 1529
🏁 Script executed:
# Check if there are any test cases that document this behavior
rg -n "fullPath" packages/router-core/tests/ --type=ts -B2 -A2 | head -100Repository: TanStack/router
Length of output: 7889
🏁 Script executed:
# Search for tests involving routeApi or BaseRouteApi
rg -n "routeApi|BaseRouteApi" packages/router-core/tests/ --type=ts -B2 -A2 | head -100Repository: TanStack/router
Length of output: 41
🏁 Script executed:
# Look for tests that verify fullPath getter specifically
rg -n "\.fullPath" packages/router-core/tests/ --type=ts -B1 -A1 | head -50Repository: TanStack/router
Length of output: 41
🏁 Script executed:
# Search for usage of routeApi.fullPath or routeApi.to in the codebase
rg -n "routeApi\.(fullPath|to)" --type=ts --type=tsx | head -50Repository: TanStack/router
Length of output: 86
🏁 Script executed:
# Look for any examples or tests that use BaseRouteApi
find packages -name "*.test.ts" -o -name "*.test.tsx" -o -name "*.spec.ts" | xargs grep -l "fullPath" | head -5Repository: TanStack/router
Length of output: 289
🏁 Script executed:
# Check if there's SSR-specific documentation or comments about BaseRouteApi
rg -n "SSR|server.*render|isomorphic" packages/router-core/src/route.ts -B2 -A2 | head -50Repository: TanStack/router
Length of output: 1425
🏁 Script executed:
# Look at the broader context of how fullPath is used in actual route implementation vs API
rg -n "class Route|class BaseRouteApi" packages/router-core/src/route.ts -A15 | grep -A15 "get fullPath"Repository: TanStack/router
Length of output: 375
🏁 Script executed:
# Check if there's any documentation about BaseRouteApi in comments or README
rg -n "BaseRouteApi" packages/ -B3 -A3 --type=ts | head -80Repository: TanStack/router
Length of output: 3463
🏁 Script executed:
# Search for any JSDoc updates or issues related to fullPath fallback behavior
rg -n "id.*fallback|fallback.*id" packages/router-core/src/ --type=ts -B2 -A2Repository: TanStack/router
Length of output: 1464
Update JSDoc to document SSR fallback behavior.
The implementation correctly guards against SSR and falls back to id when the router isn't available. However, the JSDoc comment (lines 1915-1917) only describes the intended purpose and doesn't document the runtime limitation. For SSR or before createRouter completes, pathless layout routes will return their id (e.g., __root_/posts) instead of their computed fullPath (e.g., /posts). Add a note to the JSDoc explaining this behavior and when it occurs, so developers understand the constraint when using routeApi.fullPath in SSR contexts.
🤖 Prompt for AI Agents
In @packages/router-core/src/route.ts around lines 1915 - 1927, Update the JSDoc
for the fullPath getter to document its SSR/runtime fallback: note that fullPath
(getter fullPath on the route API) returns the computed route.fullPath when
window.__TSR_ROUTER__ and routesById[this.id] are available at runtime, but
during SSR or before createRouter completes (i.e., when window.__TSR_ROUTER__ is
absent) layout routes without a path will return this.id (e.g., "__root_/posts")
instead of a resolved path (e.g., "/posts"); mention when this limitation occurs
and suggest checking for a router instance or using client-side code if the
resolved path is required.
| * in navigation APIs like `<Link from={routeApi.fullPath}>` or `navigate({ from: routeApi.fullPath })`. | ||
| */ | ||
| get fullPath(): RouteTypesById<TRouter, TId>['fullPath'] { | ||
| if (typeof window !== 'undefined' && window.__TSR_ROUTER__) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this doesnt work during SSR correctly, so we cant use this
Summary
fullPathandtogetters toRouteApi(returned bygetRouteApi)Routeobjects which already exposefullPathandto<Link from={routeApi.fullPath} to="./relative">fullPathat runtimeiddiffers fromfullPathTest plan
id === fullPath)id = '/_layout/posts',fullPath = '/posts')