diff --git a/e2e/react-router/basic-file-based/src/routeTree.gen.ts b/e2e/react-router/basic-file-based/src/routeTree.gen.ts
index c1503cfdaa0..ad5f737ec76 100644
--- a/e2e/react-router/basic-file-based/src/routeTree.gen.ts
+++ b/e2e/react-router/basic-file-based/src/routeTree.gen.ts
@@ -23,6 +23,7 @@ import { Route as Char45824Char54620Char48124Char44397RouteRouteImport } from '.
import { Route as SearchParamsRouteRouteImport } from './routes/search-params/route'
import { Route as PathlessLayoutRouteRouteImport } from './routes/pathless-layout/route'
import { Route as NonNestedRouteRouteImport } from './routes/non-nested/route'
+import { Route as FullpathTestRouteRouteImport } from './routes/fullpath-test/route'
import { Route as IndexRouteImport } from './routes/index'
import { Route as SearchParamsIndexRouteImport } from './routes/search-params/index'
import { Route as RelativeIndexRouteImport } from './routes/relative/index'
@@ -47,10 +48,12 @@ import { Route as NonNestedPrefixRouteRouteImport } from './routes/non-nested/pr
import { Route as NonNestedPathRouteRouteImport } from './routes/non-nested/path/route'
import { Route as NonNestedNamedRouteRouteImport } from './routes/non-nested/named/route'
import { Route as NonNestedDeepRouteRouteImport } from './routes/non-nested/deep/route'
+import { Route as FullpathTestLayoutRouteRouteImport } from './routes/fullpath-test/_layout/route'
import { Route as RedirectTargetIndexRouteImport } from './routes/redirect/$target/index'
import { Route as PathlessLayoutLayoutIndexRouteImport } from './routes/pathless-layout/_layout/index'
import { Route as ParamsPsWildcardIndexRouteImport } from './routes/params-ps/wildcard/index'
import { Route as ParamsPsNamedIndexRouteImport } from './routes/params-ps/named/index'
+import { Route as FullpathTestLayoutIndexRouteImport } from './routes/fullpath-test/_layout/index'
import { Route as Char45824Char54620Char48124Char44397Char55357Char56960IdRouteImport } from './routes/λνλ―Όκ΅/π.$id'
import { Route as Char45824Char54620Char48124Char44397WildcardSplatRouteImport } from './routes/λνλ―Όκ΅/wildcard.$'
import { Route as RelativeUseNavigateRelativeUseNavigateBRouteImport } from './routes/relative/useNavigate/relative-useNavigate-b'
@@ -79,6 +82,7 @@ import { Route as ParamsPsNamedChar123fooChar125suffixRouteImport } from './rout
import { Route as ParamsPsNamedPrefixChar123fooChar125RouteImport } from './routes/params-ps/named/prefix{$foo}'
import { Route as MasksPublicUsernameRouteImport } from './routes/masks.public.$username'
import { Route as MasksAdminUserIdRouteImport } from './routes/masks.admin.$userId'
+import { Route as FullpathTestLayoutIdRouteImport } from './routes/fullpath-test/_layout/$id'
import { Route as LayoutLayout2LayoutBRouteImport } from './routes/_layout/_layout-2/layout-b'
import { Route as LayoutLayout2LayoutARouteImport } from './routes/_layout/_layout-2/layout-a'
import { Route as groupSubfolderInsideRouteImport } from './routes/(group)/subfolder/inside'
@@ -193,6 +197,11 @@ const NonNestedRouteRoute = NonNestedRouteRouteImport.update({
path: '/non-nested',
getParentRoute: () => rootRouteImport,
} as any)
+const FullpathTestRouteRoute = FullpathTestRouteRouteImport.update({
+ id: '/fullpath-test',
+ path: '/fullpath-test',
+ getParentRoute: () => rootRouteImport,
+} as any)
const IndexRoute = IndexRouteImport.update({
id: '/',
path: '/',
@@ -316,6 +325,10 @@ const NonNestedDeepRouteRoute = NonNestedDeepRouteRouteImport.update({
path: '/deep',
getParentRoute: () => NonNestedRouteRoute,
} as any)
+const FullpathTestLayoutRouteRoute = FullpathTestLayoutRouteRouteImport.update({
+ id: '/_layout',
+ getParentRoute: () => FullpathTestRouteRoute,
+} as any)
const RedirectTargetIndexRoute = RedirectTargetIndexRouteImport.update({
id: '/',
path: '/',
@@ -337,6 +350,11 @@ const ParamsPsNamedIndexRoute = ParamsPsNamedIndexRouteImport.update({
path: '/params-ps/named/',
getParentRoute: () => rootRouteImport,
} as any)
+const FullpathTestLayoutIndexRoute = FullpathTestLayoutIndexRouteImport.update({
+ id: '/',
+ path: '/',
+ getParentRoute: () => FullpathTestLayoutRouteRoute,
+} as any)
const Char45824Char54620Char48124Char44397Char55357Char56960IdRoute =
Char45824Char54620Char48124Char44397Char55357Char56960IdRouteImport.update({
id: '/π/$id',
@@ -496,6 +514,11 @@ const MasksAdminUserIdRoute = MasksAdminUserIdRouteImport.update({
path: '/admin/$userId',
getParentRoute: () => MasksRoute,
} as any)
+const FullpathTestLayoutIdRoute = FullpathTestLayoutIdRouteImport.update({
+ id: '/$id',
+ path: '/$id',
+ getParentRoute: () => FullpathTestLayoutRouteRoute,
+} as any)
const LayoutLayout2LayoutBRoute = LayoutLayout2LayoutBRouteImport.update({
id: '/layout-b',
path: '/layout-b',
@@ -737,6 +760,7 @@ const NonNestedDeepBazBarFooQuxRoute =
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
+ '/fullpath-test': typeof FullpathTestLayoutRouteRouteWithChildren
'/non-nested': typeof NonNestedRouteRouteWithChildren
'/pathless-layout': typeof PathlessLayoutLayoutRouteRouteWithChildren
'/search-params': typeof SearchParamsRouteRouteWithChildren
@@ -765,10 +789,10 @@ export interface FileRoutesByFullPath {
'/redirect/$target': typeof RedirectTargetRouteWithChildren
'/search-params/default': typeof SearchParamsDefaultRoute
'/structural-sharing/$enabled': typeof StructuralSharingEnabledRoute
- '/params-ps': typeof ParamsPsIndexRoute
+ '/params-ps/': typeof ParamsPsIndexRoute
'/posts/': typeof PostsIndexRoute
- '/redirect': typeof RedirectIndexRoute
- '/relative': typeof RelativeIndexRoute
+ '/redirect/': typeof RedirectIndexRoute
+ '/relative/': typeof RelativeIndexRoute
'/search-params/': typeof SearchParamsIndexRoute
'/non-nested/deep/$baz': typeof NonNestedDeepBazRouteRouteWithChildren
'/non-nested/named/$baz': typeof NonNestedNamedBazRouteRouteWithChildren
@@ -781,6 +805,7 @@ export interface FileRoutesByFullPath {
'/subfolder/inside': typeof groupSubfolderInsideRoute
'/layout-a': typeof LayoutLayout2LayoutARoute
'/layout-b': typeof LayoutLayout2LayoutBRoute
+ '/fullpath-test/$id': typeof FullpathTestLayoutIdRoute
'/masks/admin/$userId': typeof MasksAdminUserIdRoute
'/masks/public/$username': typeof MasksPublicUsernameRoute
'/params-ps/named/prefix{$foo}': typeof ParamsPsNamedPrefixChar123fooChar125Route
@@ -809,8 +834,9 @@ export interface FileRoutesByFullPath {
'/relative/useNavigate/relative-useNavigate-b': typeof RelativeUseNavigateRelativeUseNavigateBRoute
'/λνλ―Όκ΅/wildcard/$': typeof Char45824Char54620Char48124Char44397WildcardSplatRoute
'/λνλ―Όκ΅/π/$id': typeof Char45824Char54620Char48124Char44397Char55357Char56960IdRoute
- '/params-ps/named': typeof ParamsPsNamedIndexRoute
- '/params-ps/wildcard': typeof ParamsPsWildcardIndexRoute
+ '/fullpath-test/': typeof FullpathTestLayoutIndexRoute
+ '/params-ps/named/': typeof ParamsPsNamedIndexRoute
+ '/params-ps/wildcard/': typeof ParamsPsWildcardIndexRoute
'/pathless-layout/': typeof PathlessLayoutLayoutIndexRoute
'/redirect/$target/': typeof RedirectTargetIndexRoute
'/non-nested/deep/$baz/bar': typeof NonNestedDeepBazBarRouteRouteWithChildren
@@ -829,25 +855,26 @@ export interface FileRoutesByFullPath {
'/non-nested/path/baz/': typeof NonNestedPathBazIndexRoute
'/non-nested/prefix/prefix{$baz}/': typeof NonNestedPrefixPrefixChar123bazChar125IndexRoute
'/non-nested/suffix/{$baz}suffix/': typeof NonNestedSuffixChar123bazChar125suffixIndexRoute
- '/relative/link/nested': typeof RelativeLinkNestedIndexRoute
- '/relative/link/path': typeof RelativeLinkPathIndexRoute
- '/relative/link/with-search': typeof RelativeLinkWithSearchIndexRoute
- '/relative/useNavigate/nested': typeof RelativeUseNavigateNestedIndexRoute
- '/relative/useNavigate/path': typeof RelativeUseNavigatePathIndexRoute
- '/relative/useNavigate/with-search': typeof RelativeUseNavigateWithSearchIndexRoute
+ '/relative/link/nested/': typeof RelativeLinkNestedIndexRoute
+ '/relative/link/path/': typeof RelativeLinkPathIndexRoute
+ '/relative/link/with-search/': typeof RelativeLinkWithSearchIndexRoute
+ '/relative/useNavigate/nested/': typeof RelativeUseNavigateNestedIndexRoute
+ '/relative/useNavigate/path/': typeof RelativeUseNavigatePathIndexRoute
+ '/relative/useNavigate/with-search/': typeof RelativeUseNavigateWithSearchIndexRoute
'/non-nested/deep/$baz/bar/$foo': typeof NonNestedDeepBazBarFooRouteRouteWithChildren
'/non-nested/deep/$baz/bar/qux': typeof NonNestedDeepBazBarQuxRoute
'/params-ps/named/$foo/$bar/$baz': typeof ParamsPsNamedFooBarBazRoute
'/non-nested/deep/$baz/bar/': typeof NonNestedDeepBazBarIndexRoute
- '/relative/link/nested/deep': typeof RelativeLinkNestedDeepIndexRoute
- '/relative/link/path/$path': typeof RelativeLinkPathPathIndexRoute
- '/relative/useNavigate/nested/deep': typeof RelativeUseNavigateNestedDeepIndexRoute
- '/relative/useNavigate/path/$path': typeof RelativeUseNavigatePathPathIndexRoute
+ '/relative/link/nested/deep/': typeof RelativeLinkNestedDeepIndexRoute
+ '/relative/link/path/$path/': typeof RelativeLinkPathPathIndexRoute
+ '/relative/useNavigate/nested/deep/': typeof RelativeUseNavigateNestedDeepIndexRoute
+ '/relative/useNavigate/path/$path/': typeof RelativeUseNavigatePathPathIndexRoute
'/non-nested/deep/$baz/bar/$foo/qux': typeof NonNestedDeepBazBarFooQuxRoute
'/non-nested/deep/$baz/bar/$foo/': typeof NonNestedDeepBazBarFooIndexRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
+ '/fullpath-test': typeof FullpathTestLayoutIndexRoute
'/non-nested': typeof NonNestedRouteRouteWithChildren
'/pathless-layout': typeof PathlessLayoutLayoutIndexRoute
'/λνλ―Όκ΅': typeof Char45824Char54620Char48124Char44397RouteRouteWithChildren
@@ -884,6 +911,7 @@ export interface FileRoutesByTo {
'/subfolder/inside': typeof groupSubfolderInsideRoute
'/layout-a': typeof LayoutLayout2LayoutARoute
'/layout-b': typeof LayoutLayout2LayoutBRoute
+ '/fullpath-test/$id': typeof FullpathTestLayoutIdRoute
'/masks/admin/$userId': typeof MasksAdminUserIdRoute
'/masks/public/$username': typeof MasksPublicUsernameRoute
'/params-ps/named/prefix{$foo}': typeof ParamsPsNamedPrefixChar123fooChar125Route
@@ -949,6 +977,7 @@ export interface FileRoutesByTo {
export interface FileRoutesById {
__root__: typeof rootRouteImport
'/': typeof IndexRoute
+ '/fullpath-test': typeof FullpathTestRouteRouteWithChildren
'/non-nested': typeof NonNestedRouteRouteWithChildren
'/pathless-layout': typeof PathlessLayoutRouteRouteWithChildren
'/search-params': typeof SearchParamsRouteRouteWithChildren
@@ -963,6 +992,7 @@ export interface FileRoutesById {
'/notRemountDeps': typeof NotRemountDepsRoute
'/posts': typeof PostsRouteWithChildren
'/remountDeps': typeof RemountDepsRoute
+ '/fullpath-test/_layout': typeof FullpathTestLayoutRouteRouteWithChildren
'/non-nested/deep': typeof NonNestedDeepRouteRouteWithChildren
'/non-nested/named': typeof NonNestedNamedRouteRouteWithChildren
'/non-nested/path': typeof NonNestedPathRouteRouteWithChildren
@@ -997,6 +1027,7 @@ export interface FileRoutesById {
'/(group)/subfolder/inside': typeof groupSubfolderInsideRoute
'/_layout/_layout-2/layout-a': typeof LayoutLayout2LayoutARoute
'/_layout/_layout-2/layout-b': typeof LayoutLayout2LayoutBRoute
+ '/fullpath-test/_layout/$id': typeof FullpathTestLayoutIdRoute
'/masks/admin/$userId': typeof MasksAdminUserIdRoute
'/masks/public/$username': typeof MasksPublicUsernameRoute
'/params-ps/named/prefix{$foo}': typeof ParamsPsNamedPrefixChar123fooChar125Route
@@ -1025,6 +1056,7 @@ export interface FileRoutesById {
'/relative/useNavigate/relative-useNavigate-b': typeof RelativeUseNavigateRelativeUseNavigateBRoute
'/λνλ―Όκ΅/wildcard/$': typeof Char45824Char54620Char48124Char44397WildcardSplatRoute
'/λνλ―Όκ΅/π/$id': typeof Char45824Char54620Char48124Char44397Char55357Char56960IdRoute
+ '/fullpath-test/_layout/': typeof FullpathTestLayoutIndexRoute
'/params-ps/named/': typeof ParamsPsNamedIndexRoute
'/params-ps/wildcard/': typeof ParamsPsWildcardIndexRoute
'/pathless-layout/_layout/': typeof PathlessLayoutLayoutIndexRoute
@@ -1066,6 +1098,7 @@ export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
| '/'
+ | '/fullpath-test'
| '/non-nested'
| '/pathless-layout'
| '/search-params'
@@ -1094,10 +1127,10 @@ export interface FileRouteTypes {
| '/redirect/$target'
| '/search-params/default'
| '/structural-sharing/$enabled'
- | '/params-ps'
+ | '/params-ps/'
| '/posts/'
- | '/redirect'
- | '/relative'
+ | '/redirect/'
+ | '/relative/'
| '/search-params/'
| '/non-nested/deep/$baz'
| '/non-nested/named/$baz'
@@ -1110,6 +1143,7 @@ export interface FileRouteTypes {
| '/subfolder/inside'
| '/layout-a'
| '/layout-b'
+ | '/fullpath-test/$id'
| '/masks/admin/$userId'
| '/masks/public/$username'
| '/params-ps/named/prefix{$foo}'
@@ -1138,8 +1172,9 @@ export interface FileRouteTypes {
| '/relative/useNavigate/relative-useNavigate-b'
| '/λνλ―Όκ΅/wildcard/$'
| '/λνλ―Όκ΅/π/$id'
- | '/params-ps/named'
- | '/params-ps/wildcard'
+ | '/fullpath-test/'
+ | '/params-ps/named/'
+ | '/params-ps/wildcard/'
| '/pathless-layout/'
| '/redirect/$target/'
| '/non-nested/deep/$baz/bar'
@@ -1158,25 +1193,26 @@ export interface FileRouteTypes {
| '/non-nested/path/baz/'
| '/non-nested/prefix/prefix{$baz}/'
| '/non-nested/suffix/{$baz}suffix/'
- | '/relative/link/nested'
- | '/relative/link/path'
- | '/relative/link/with-search'
- | '/relative/useNavigate/nested'
- | '/relative/useNavigate/path'
- | '/relative/useNavigate/with-search'
+ | '/relative/link/nested/'
+ | '/relative/link/path/'
+ | '/relative/link/with-search/'
+ | '/relative/useNavigate/nested/'
+ | '/relative/useNavigate/path/'
+ | '/relative/useNavigate/with-search/'
| '/non-nested/deep/$baz/bar/$foo'
| '/non-nested/deep/$baz/bar/qux'
| '/params-ps/named/$foo/$bar/$baz'
| '/non-nested/deep/$baz/bar/'
- | '/relative/link/nested/deep'
- | '/relative/link/path/$path'
- | '/relative/useNavigate/nested/deep'
- | '/relative/useNavigate/path/$path'
+ | '/relative/link/nested/deep/'
+ | '/relative/link/path/$path/'
+ | '/relative/useNavigate/nested/deep/'
+ | '/relative/useNavigate/path/$path/'
| '/non-nested/deep/$baz/bar/$foo/qux'
| '/non-nested/deep/$baz/bar/$foo/'
fileRoutesByTo: FileRoutesByTo
to:
| '/'
+ | '/fullpath-test'
| '/non-nested'
| '/pathless-layout'
| '/λνλ―Όκ΅'
@@ -1213,6 +1249,7 @@ export interface FileRouteTypes {
| '/subfolder/inside'
| '/layout-a'
| '/layout-b'
+ | '/fullpath-test/$id'
| '/masks/admin/$userId'
| '/masks/public/$username'
| '/params-ps/named/prefix{$foo}'
@@ -1277,6 +1314,7 @@ export interface FileRouteTypes {
id:
| '__root__'
| '/'
+ | '/fullpath-test'
| '/non-nested'
| '/pathless-layout'
| '/search-params'
@@ -1291,6 +1329,7 @@ export interface FileRouteTypes {
| '/notRemountDeps'
| '/posts'
| '/remountDeps'
+ | '/fullpath-test/_layout'
| '/non-nested/deep'
| '/non-nested/named'
| '/non-nested/path'
@@ -1325,6 +1364,7 @@ export interface FileRouteTypes {
| '/(group)/subfolder/inside'
| '/_layout/_layout-2/layout-a'
| '/_layout/_layout-2/layout-b'
+ | '/fullpath-test/_layout/$id'
| '/masks/admin/$userId'
| '/masks/public/$username'
| '/params-ps/named/prefix{$foo}'
@@ -1353,6 +1393,7 @@ export interface FileRouteTypes {
| '/relative/useNavigate/relative-useNavigate-b'
| '/λνλ―Όκ΅/wildcard/$'
| '/λνλ―Όκ΅/π/$id'
+ | '/fullpath-test/_layout/'
| '/params-ps/named/'
| '/params-ps/wildcard/'
| '/pathless-layout/_layout/'
@@ -1393,6 +1434,7 @@ export interface FileRouteTypes {
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
+ FullpathTestRouteRoute: typeof FullpathTestRouteRouteWithChildren
NonNestedRouteRoute: typeof NonNestedRouteRouteWithChildren
PathlessLayoutRouteRoute: typeof PathlessLayoutRouteRouteWithChildren
SearchParamsRouteRoute: typeof SearchParamsRouteRouteWithChildren
@@ -1505,7 +1547,7 @@ declare module '@tanstack/react-router' {
'/_layout': {
id: '/_layout'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof LayoutRouteImport
parentRoute: typeof rootRouteImport
}
@@ -1537,6 +1579,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof NonNestedRouteRouteImport
parentRoute: typeof rootRouteImport
}
+ '/fullpath-test': {
+ id: '/fullpath-test'
+ path: '/fullpath-test'
+ fullPath: '/fullpath-test'
+ preLoaderRoute: typeof FullpathTestRouteRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/': {
id: '/'
path: '/'
@@ -1554,14 +1603,14 @@ declare module '@tanstack/react-router' {
'/relative/': {
id: '/relative/'
path: '/relative'
- fullPath: '/relative'
+ fullPath: '/relative/'
preLoaderRoute: typeof RelativeIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/redirect/': {
id: '/redirect/'
path: '/redirect'
- fullPath: '/redirect'
+ fullPath: '/redirect/'
preLoaderRoute: typeof RedirectIndexRouteImport
parentRoute: typeof rootRouteImport
}
@@ -1575,7 +1624,7 @@ declare module '@tanstack/react-router' {
'/params-ps/': {
id: '/params-ps/'
path: '/params-ps'
- fullPath: '/params-ps'
+ fullPath: '/params-ps/'
preLoaderRoute: typeof ParamsPsIndexRouteImport
parentRoute: typeof rootRouteImport
}
@@ -1610,7 +1659,7 @@ declare module '@tanstack/react-router' {
'/_layout/_layout-2': {
id: '/_layout/_layout-2'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof LayoutLayout2RouteImport
parentRoute: typeof LayoutRoute
}
@@ -1705,6 +1754,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof NonNestedDeepRouteRouteImport
parentRoute: typeof NonNestedRouteRoute
}
+ '/fullpath-test/_layout': {
+ id: '/fullpath-test/_layout'
+ path: ''
+ fullPath: '/fullpath-test'
+ preLoaderRoute: typeof FullpathTestLayoutRouteRouteImport
+ parentRoute: typeof FullpathTestRouteRoute
+ }
'/redirect/$target/': {
id: '/redirect/$target/'
path: '/'
@@ -1722,17 +1778,24 @@ declare module '@tanstack/react-router' {
'/params-ps/wildcard/': {
id: '/params-ps/wildcard/'
path: '/params-ps/wildcard'
- fullPath: '/params-ps/wildcard'
+ fullPath: '/params-ps/wildcard/'
preLoaderRoute: typeof ParamsPsWildcardIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/params-ps/named/': {
id: '/params-ps/named/'
path: '/params-ps/named'
- fullPath: '/params-ps/named'
+ fullPath: '/params-ps/named/'
preLoaderRoute: typeof ParamsPsNamedIndexRouteImport
parentRoute: typeof rootRouteImport
}
+ '/fullpath-test/_layout/': {
+ id: '/fullpath-test/_layout/'
+ path: '/'
+ fullPath: '/fullpath-test/'
+ preLoaderRoute: typeof FullpathTestLayoutIndexRouteImport
+ parentRoute: typeof FullpathTestLayoutRouteRoute
+ }
'/λνλ―Όκ΅/π/$id': {
id: '/λνλ―Όκ΅/π/$id'
path: '/π/$id'
@@ -1929,6 +1992,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof MasksAdminUserIdRouteImport
parentRoute: typeof MasksRoute
}
+ '/fullpath-test/_layout/$id': {
+ id: '/fullpath-test/_layout/$id'
+ path: '/$id'
+ fullPath: '/fullpath-test/$id'
+ preLoaderRoute: typeof FullpathTestLayoutIdRouteImport
+ parentRoute: typeof FullpathTestLayoutRouteRoute
+ }
'/_layout/_layout-2/layout-b': {
id: '/_layout/_layout-2/layout-b'
path: '/layout-b'
@@ -2009,42 +2079,42 @@ declare module '@tanstack/react-router' {
'/relative/useNavigate/with-search/': {
id: '/relative/useNavigate/with-search/'
path: '/with-search'
- fullPath: '/relative/useNavigate/with-search'
+ fullPath: '/relative/useNavigate/with-search/'
preLoaderRoute: typeof RelativeUseNavigateWithSearchIndexRouteImport
parentRoute: typeof RelativeUseNavigateRouteRoute
}
'/relative/useNavigate/path/': {
id: '/relative/useNavigate/path/'
path: '/path'
- fullPath: '/relative/useNavigate/path'
+ fullPath: '/relative/useNavigate/path/'
preLoaderRoute: typeof RelativeUseNavigatePathIndexRouteImport
parentRoute: typeof RelativeUseNavigateRouteRoute
}
'/relative/useNavigate/nested/': {
id: '/relative/useNavigate/nested/'
path: '/nested'
- fullPath: '/relative/useNavigate/nested'
+ fullPath: '/relative/useNavigate/nested/'
preLoaderRoute: typeof RelativeUseNavigateNestedIndexRouteImport
parentRoute: typeof RelativeUseNavigateRouteRoute
}
'/relative/link/with-search/': {
id: '/relative/link/with-search/'
path: '/with-search'
- fullPath: '/relative/link/with-search'
+ fullPath: '/relative/link/with-search/'
preLoaderRoute: typeof RelativeLinkWithSearchIndexRouteImport
parentRoute: typeof RelativeLinkRouteRoute
}
'/relative/link/path/': {
id: '/relative/link/path/'
path: '/path'
- fullPath: '/relative/link/path'
+ fullPath: '/relative/link/path/'
preLoaderRoute: typeof RelativeLinkPathIndexRouteImport
parentRoute: typeof RelativeLinkRouteRoute
}
'/relative/link/nested/': {
id: '/relative/link/nested/'
path: '/nested'
- fullPath: '/relative/link/nested'
+ fullPath: '/relative/link/nested/'
preLoaderRoute: typeof RelativeLinkNestedIndexRouteImport
parentRoute: typeof RelativeLinkRouteRoute
}
@@ -2163,28 +2233,28 @@ declare module '@tanstack/react-router' {
'/relative/useNavigate/path/$path/': {
id: '/relative/useNavigate/path/$path/'
path: '/path/$path'
- fullPath: '/relative/useNavigate/path/$path'
+ fullPath: '/relative/useNavigate/path/$path/'
preLoaderRoute: typeof RelativeUseNavigatePathPathIndexRouteImport
parentRoute: typeof RelativeUseNavigateRouteRoute
}
'/relative/useNavigate/nested/deep/': {
id: '/relative/useNavigate/nested/deep/'
path: '/nested/deep'
- fullPath: '/relative/useNavigate/nested/deep'
+ fullPath: '/relative/useNavigate/nested/deep/'
preLoaderRoute: typeof RelativeUseNavigateNestedDeepIndexRouteImport
parentRoute: typeof RelativeUseNavigateRouteRoute
}
'/relative/link/path/$path/': {
id: '/relative/link/path/$path/'
path: '/path/$path'
- fullPath: '/relative/link/path/$path'
+ fullPath: '/relative/link/path/$path/'
preLoaderRoute: typeof RelativeLinkPathPathIndexRouteImport
parentRoute: typeof RelativeLinkRouteRoute
}
'/relative/link/nested/deep/': {
id: '/relative/link/nested/deep/'
path: '/nested/deep'
- fullPath: '/relative/link/nested/deep'
+ fullPath: '/relative/link/nested/deep/'
preLoaderRoute: typeof RelativeLinkNestedDeepIndexRouteImport
parentRoute: typeof RelativeLinkRouteRoute
}
@@ -2233,6 +2303,33 @@ declare module '@tanstack/react-router' {
}
}
+interface FullpathTestLayoutRouteRouteChildren {
+ FullpathTestLayoutIdRoute: typeof FullpathTestLayoutIdRoute
+ FullpathTestLayoutIndexRoute: typeof FullpathTestLayoutIndexRoute
+}
+
+const FullpathTestLayoutRouteRouteChildren: FullpathTestLayoutRouteRouteChildren =
+ {
+ FullpathTestLayoutIdRoute: FullpathTestLayoutIdRoute,
+ FullpathTestLayoutIndexRoute: FullpathTestLayoutIndexRoute,
+ }
+
+const FullpathTestLayoutRouteRouteWithChildren =
+ FullpathTestLayoutRouteRoute._addFileChildren(
+ FullpathTestLayoutRouteRouteChildren,
+ )
+
+interface FullpathTestRouteRouteChildren {
+ FullpathTestLayoutRouteRoute: typeof FullpathTestLayoutRouteRouteWithChildren
+}
+
+const FullpathTestRouteRouteChildren: FullpathTestRouteRouteChildren = {
+ FullpathTestLayoutRouteRoute: FullpathTestLayoutRouteRouteWithChildren,
+}
+
+const FullpathTestRouteRouteWithChildren =
+ FullpathTestRouteRoute._addFileChildren(FullpathTestRouteRouteChildren)
+
interface NonNestedDeepBazRouteRouteChildren {
NonNestedDeepBazIndexRoute: typeof NonNestedDeepBazIndexRoute
}
@@ -2697,6 +2794,7 @@ const ParamsPsNamedFooRouteRouteWithChildren =
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
+ FullpathTestRouteRoute: FullpathTestRouteRouteWithChildren,
NonNestedRouteRoute: NonNestedRouteRouteWithChildren,
PathlessLayoutRouteRoute: PathlessLayoutRouteRouteWithChildren,
SearchParamsRouteRoute: SearchParamsRouteRouteWithChildren,
diff --git a/e2e/react-router/basic-file-based/src/routes/__root.tsx b/e2e/react-router/basic-file-based/src/routes/__root.tsx
index dde8139a6e2..298f97c1bae 100644
--- a/e2e/react-router/basic-file-based/src/routes/__root.tsx
+++ b/e2e/react-router/basic-file-based/src/routes/__root.tsx
@@ -164,6 +164,15 @@ function RootComponent() {
}}
>
Pathless Layout
+ {' '}
+
+ FullPath Test
diff --git a/e2e/react-router/basic-file-based/src/routes/fullpath-test/_layout/$id.tsx b/e2e/react-router/basic-file-based/src/routes/fullpath-test/_layout/$id.tsx
new file mode 100644
index 00000000000..44b1f077ff8
--- /dev/null
+++ b/e2e/react-router/basic-file-based/src/routes/fullpath-test/_layout/$id.tsx
@@ -0,0 +1,23 @@
+import { createFileRoute, useMatches } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/fullpath-test/_layout/$id')({
+ component: IdComponent,
+})
+
+function IdComponent() {
+ const matches = useMatches()
+ const { id } = Route.useParams()
+ // Find this route's match by routeId
+ const idMatch = matches.find(
+ (m) => m.routeId === '/fullpath-test/_layout/$id',
+ )
+
+ return (
+
+
+ {idMatch?.fullPath ?? 'undefined'}
+
+
Param: {id}
+
+ )
+}
diff --git a/e2e/react-router/basic-file-based/src/routes/fullpath-test/_layout/index.tsx b/e2e/react-router/basic-file-based/src/routes/fullpath-test/_layout/index.tsx
new file mode 100644
index 00000000000..e84b81047aa
--- /dev/null
+++ b/e2e/react-router/basic-file-based/src/routes/fullpath-test/_layout/index.tsx
@@ -0,0 +1,23 @@
+import { createFileRoute, useMatches } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/fullpath-test/_layout/')({
+ component: IndexComponent,
+})
+
+function IndexComponent() {
+ const matches = useMatches()
+ // Find this index route's match by routeId
+ const indexMatch = matches.find(
+ (m) => m.routeId === '/fullpath-test/_layout/',
+ )
+
+ return (
+
+
+ {indexMatch?.fullPath ?? 'undefined'}
+
+
{Route.to}
+
FullPath Test Index
+
+ )
+}
diff --git a/e2e/react-router/basic-file-based/src/routes/fullpath-test/_layout/route.tsx b/e2e/react-router/basic-file-based/src/routes/fullpath-test/_layout/route.tsx
new file mode 100644
index 00000000000..770888e62a2
--- /dev/null
+++ b/e2e/react-router/basic-file-based/src/routes/fullpath-test/_layout/route.tsx
@@ -0,0 +1,22 @@
+import { Outlet, createFileRoute, useMatches } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/fullpath-test/_layout')({
+ component: LayoutComponent,
+})
+
+function LayoutComponent() {
+ const matches = useMatches()
+ // Find this layout's match by routeId
+ const layoutMatch = matches.find(
+ (m) => m.routeId === '/fullpath-test/_layout',
+ )
+
+ return (
+
+
+ {layoutMatch?.fullPath ?? 'undefined'}
+
+
+
+ )
+}
diff --git a/e2e/react-router/basic-file-based/src/routes/fullpath-test/route.tsx b/e2e/react-router/basic-file-based/src/routes/fullpath-test/route.tsx
new file mode 100644
index 00000000000..e876f36cbca
--- /dev/null
+++ b/e2e/react-router/basic-file-based/src/routes/fullpath-test/route.tsx
@@ -0,0 +1,10 @@
+import { Outlet, createFileRoute } from '@tanstack/react-router'
+
+export const Route = createFileRoute('/fullpath-test')({
+ component: () => (
+
+
FullPath Test Section
+
+
+ ),
+})
diff --git a/e2e/react-router/basic-file-based/src/routes/relative/link/path/$path/index.tsx b/e2e/react-router/basic-file-based/src/routes/relative/link/path/$path/index.tsx
index 30b13cb09d2..36e95665bce 100644
--- a/e2e/react-router/basic-file-based/src/routes/relative/link/path/$path/index.tsx
+++ b/e2e/react-router/basic-file-based/src/routes/relative/link/path/$path/index.tsx
@@ -17,7 +17,7 @@ function RouteComponent() {
navigate({
- from: '/relative/useNavigate/path',
+ from: '/relative/useNavigate/path/',
to: './$path',
params: { path: path === 'a' ? 'b' : 'a' },
})
diff --git a/e2e/react-router/basic-file-based/tests/fullpath-types.spec.ts b/e2e/react-router/basic-file-based/tests/fullpath-types.spec.ts
new file mode 100644
index 00000000000..d1bd9c1c413
--- /dev/null
+++ b/e2e/react-router/basic-file-based/tests/fullpath-types.spec.ts
@@ -0,0 +1,81 @@
+import { expect, test } from '@playwright/test'
+
+test.describe('FullPath type/runtime match (Issues #4892, #2675, #6403)', () => {
+ test.describe('Pathless layout routes should have parent fullPath, not empty string', () => {
+ test('direct navigation to pathless layout shows correct fullPath', async ({
+ page,
+ }) => {
+ await page.goto('/fullpath-test')
+ // The pathless layout's fullPath should be '/fullpath-test' (same as parent), not ''
+ await expect(page.getByTestId('pathless-layout-fullpath')).toHaveText(
+ '/fullpath-test',
+ )
+ })
+
+ test('client-side navigation to pathless layout shows correct fullPath', async ({
+ page,
+ }) => {
+ await page.goto('/')
+ await page.getByTestId('link-to-fullpath-test').click()
+ await expect(page.getByTestId('pathless-layout-fullpath')).toHaveText(
+ '/fullpath-test',
+ )
+ })
+ })
+
+ test.describe('Index routes should have trailing slash in fullPath', () => {
+ test('direct navigation to index route shows fullPath with trailing slash', async ({
+ page,
+ }) => {
+ await page.goto('/fullpath-test')
+ // The index route's fullPath should be '/fullpath-test/' (with trailing slash)
+ await expect(page.getByTestId('index-route-fullpath')).toHaveText(
+ '/fullpath-test/',
+ )
+ })
+
+ test('param route under pathless layout shows correct fullPath', async ({
+ page,
+ }) => {
+ await page.goto('/fullpath-test/123')
+ // The param route's fullPath should be '/fullpath-test/$id'
+ await expect(page.getByTestId('param-route-fullpath')).toHaveText(
+ '/fullpath-test/$id',
+ )
+ await expect(page.getByTestId('fullpath-test-param')).toHaveText(
+ 'Param: 123',
+ )
+ })
+ })
+
+ test.describe('Route.to should NOT have trailing slash (Issue #3005)', () => {
+ test('index route Route.to should not have trailing slash', async ({
+ page,
+ }) => {
+ await page.goto('/fullpath-test')
+ // Route.to should be '/fullpath-test' (without trailing slash)
+ // while Route.fullPath is '/fullpath-test/' (with trailing slash)
+ await expect(page.getByTestId('index-route-to')).toHaveText(
+ '/fullpath-test',
+ )
+ })
+ })
+
+ test.describe('Existing pathless layout routes', () => {
+ test('existing pathless layout index shows correct fullPath at runtime', async ({
+ page,
+ }) => {
+ // This tests the existing /pathless-layout route which has a pathless _layout
+ await page.goto('/pathless-layout')
+ await expect(page.getByTestId('pathless-layout-header')).toContainText(
+ 'Pathless Layout Section',
+ )
+ await expect(page.getByTestId('pathless-layout-wrapper')).toContainText(
+ 'Pathless Layout Wrapper',
+ )
+ await expect(page.getByTestId('pathless-layout-index')).toContainText(
+ 'Pathless Layout Index',
+ )
+ })
+ })
+})
diff --git a/e2e/react-router/basic-virtual-file-based/src/routeTree.gen.ts b/e2e/react-router/basic-virtual-file-based/src/routeTree.gen.ts
index ab3e216c966..d7f30c2cd15 100644
--- a/e2e/react-router/basic-virtual-file-based/src/routeTree.gen.ts
+++ b/e2e/react-router/basic-virtual-file-based/src/routeTree.gen.ts
@@ -178,7 +178,7 @@ declare module '@tanstack/react-router' {
'/_first': {
id: '/_first'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof layoutFirstLayoutRouteImport
parentRoute: typeof rootRouteImport
}
@@ -199,7 +199,7 @@ declare module '@tanstack/react-router' {
'/_first/_second': {
id: '/_first/_second'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof layoutSecondLayoutRouteImport
parentRoute: typeof layoutFirstLayoutRoute
}
diff --git a/e2e/react-start/basic/src/routeTree.gen.ts b/e2e/react-start/basic/src/routeTree.gen.ts
index 27d5e911452..21841bff704 100644
--- a/e2e/react-start/basic/src/routeTree.gen.ts
+++ b/e2e/react-start/basic/src/routeTree.gen.ts
@@ -354,11 +354,11 @@ export interface FileRoutesByFullPath {
'/search-params/default': typeof SearchParamsDefaultRoute
'/search-params/loader-throws-redirect': typeof SearchParamsLoaderThrowsRedirectRoute
'/users/$userId': typeof UsersUserIdRoute
- '/multi-cookie-redirect': typeof MultiCookieRedirectIndexRoute
+ '/multi-cookie-redirect/': typeof MultiCookieRedirectIndexRoute
'/not-found/': typeof NotFoundIndexRoute
'/posts/': typeof PostsIndexRoute
'/raw-stream/': typeof RawStreamIndexRoute
- '/redirect': typeof RedirectIndexRoute
+ '/redirect/': typeof RedirectIndexRoute
'/search-params/': typeof SearchParamsIndexRoute
'/users/': typeof UsersIndexRoute
'/layout-a': typeof LayoutLayout2LayoutARoute
@@ -372,7 +372,7 @@ export interface FileRoutesByFullPath {
'/redirect/$target/serverFn/via-beforeLoad': typeof RedirectTargetServerFnViaBeforeLoadRoute
'/redirect/$target/serverFn/via-loader': typeof RedirectTargetServerFnViaLoaderRoute
'/redirect/$target/serverFn/via-useServerFn': typeof RedirectTargetServerFnViaUseServerFnRoute
- '/redirect/$target/serverFn': typeof RedirectTargetServerFnIndexRoute
+ '/redirect/$target/serverFn/': typeof RedirectTargetServerFnIndexRoute
'/foo/$bar/$qux/': typeof FooBarQuxHereIndexRoute
}
export interface FileRoutesByTo {
@@ -505,11 +505,11 @@ export interface FileRouteTypes {
| '/search-params/default'
| '/search-params/loader-throws-redirect'
| '/users/$userId'
- | '/multi-cookie-redirect'
+ | '/multi-cookie-redirect/'
| '/not-found/'
| '/posts/'
| '/raw-stream/'
- | '/redirect'
+ | '/redirect/'
| '/search-params/'
| '/users/'
| '/layout-a'
@@ -523,7 +523,7 @@ export interface FileRouteTypes {
| '/redirect/$target/serverFn/via-beforeLoad'
| '/redirect/$target/serverFn/via-loader'
| '/redirect/$target/serverFn/via-useServerFn'
- | '/redirect/$target/serverFn'
+ | '/redirect/$target/serverFn/'
| '/foo/$bar/$qux/'
fileRoutesByTo: FileRoutesByTo
to:
@@ -731,7 +731,7 @@ declare module '@tanstack/react-router' {
'/_layout': {
id: '/_layout'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof LayoutRouteImport
parentRoute: typeof rootRouteImport
}
@@ -773,7 +773,7 @@ declare module '@tanstack/react-router' {
'/redirect/': {
id: '/redirect/'
path: '/redirect'
- fullPath: '/redirect'
+ fullPath: '/redirect/'
preLoaderRoute: typeof RedirectIndexRouteImport
parentRoute: typeof rootRouteImport
}
@@ -801,7 +801,7 @@ declare module '@tanstack/react-router' {
'/multi-cookie-redirect/': {
id: '/multi-cookie-redirect/'
path: '/multi-cookie-redirect'
- fullPath: '/multi-cookie-redirect'
+ fullPath: '/multi-cookie-redirect/'
preLoaderRoute: typeof MultiCookieRedirectIndexRouteImport
parentRoute: typeof rootRouteImport
}
@@ -913,7 +913,7 @@ declare module '@tanstack/react-router' {
'/_layout/_layout-2': {
id: '/_layout/_layout-2'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof LayoutLayout2RouteImport
parentRoute: typeof LayoutRoute
}
@@ -969,7 +969,7 @@ declare module '@tanstack/react-router' {
'/redirect/$target/serverFn/': {
id: '/redirect/$target/serverFn/'
path: '/serverFn'
- fullPath: '/redirect/$target/serverFn'
+ fullPath: '/redirect/$target/serverFn/'
preLoaderRoute: typeof RedirectTargetServerFnIndexRouteImport
parentRoute: typeof RedirectTargetRoute
}
diff --git a/e2e/react-start/server-functions/src/routeTree.gen.ts b/e2e/react-start/server-functions/src/routeTree.gen.ts
index e71028621c7..f4c74f657b7 100644
--- a/e2e/react-start/server-functions/src/routeTree.gen.ts
+++ b/e2e/react-start/server-functions/src/routeTree.gen.ts
@@ -288,19 +288,19 @@ export interface FileRoutesByFullPath {
'/middleware/unhandled-exception': typeof MiddlewareUnhandledExceptionRoute
'/redirect-test-ssr/target': typeof RedirectTestSsrTargetRoute
'/redirect-test/target': typeof RedirectTestTargetRoute
- '/abort-signal': typeof AbortSignalIndexRoute
- '/cookies': typeof CookiesIndexRoute
- '/factory': typeof FactoryIndexRoute
- '/formdata-redirect': typeof FormdataRedirectIndexRoute
- '/function-metadata': typeof FunctionMetadataIndexRoute
- '/function-method': typeof FunctionMethodIndexRoute
- '/middleware': typeof MiddlewareIndexRoute
- '/primitives': typeof PrimitivesIndexRoute
- '/redirect-test-ssr': typeof RedirectTestSsrIndexRoute
- '/redirect-test': typeof RedirectTestIndexRoute
+ '/abort-signal/': typeof AbortSignalIndexRoute
+ '/cookies/': typeof CookiesIndexRoute
+ '/factory/': typeof FactoryIndexRoute
+ '/formdata-redirect/': typeof FormdataRedirectIndexRoute
+ '/function-metadata/': typeof FunctionMetadataIndexRoute
+ '/function-method/': typeof FunctionMethodIndexRoute
+ '/middleware/': typeof MiddlewareIndexRoute
+ '/primitives/': typeof PrimitivesIndexRoute
+ '/redirect-test-ssr/': typeof RedirectTestSsrIndexRoute
+ '/redirect-test/': typeof RedirectTestIndexRoute
'/formdata-redirect/target/$name': typeof FormdataRedirectTargetNameRoute
'/middleware/redirect-with-middleware/target': typeof MiddlewareRedirectWithMiddlewareTargetRoute
- '/middleware/redirect-with-middleware': typeof MiddlewareRedirectWithMiddlewareIndexRoute
+ '/middleware/redirect-with-middleware/': typeof MiddlewareRedirectWithMiddlewareIndexRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
@@ -417,19 +417,19 @@ export interface FileRouteTypes {
| '/middleware/unhandled-exception'
| '/redirect-test-ssr/target'
| '/redirect-test/target'
- | '/abort-signal'
- | '/cookies'
- | '/factory'
- | '/formdata-redirect'
- | '/function-metadata'
- | '/function-method'
- | '/middleware'
- | '/primitives'
- | '/redirect-test-ssr'
- | '/redirect-test'
+ | '/abort-signal/'
+ | '/cookies/'
+ | '/factory/'
+ | '/formdata-redirect/'
+ | '/function-metadata/'
+ | '/function-method/'
+ | '/middleware/'
+ | '/primitives/'
+ | '/redirect-test-ssr/'
+ | '/redirect-test/'
| '/formdata-redirect/target/$name'
| '/middleware/redirect-with-middleware/target'
- | '/middleware/redirect-with-middleware'
+ | '/middleware/redirect-with-middleware/'
fileRoutesByTo: FileRoutesByTo
to:
| '/'
@@ -676,70 +676,70 @@ declare module '@tanstack/react-router' {
'/redirect-test/': {
id: '/redirect-test/'
path: '/redirect-test'
- fullPath: '/redirect-test'
+ fullPath: '/redirect-test/'
preLoaderRoute: typeof RedirectTestIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/redirect-test-ssr/': {
id: '/redirect-test-ssr/'
path: '/redirect-test-ssr'
- fullPath: '/redirect-test-ssr'
+ fullPath: '/redirect-test-ssr/'
preLoaderRoute: typeof RedirectTestSsrIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/primitives/': {
id: '/primitives/'
path: '/primitives'
- fullPath: '/primitives'
+ fullPath: '/primitives/'
preLoaderRoute: typeof PrimitivesIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/middleware/': {
id: '/middleware/'
path: '/middleware'
- fullPath: '/middleware'
+ fullPath: '/middleware/'
preLoaderRoute: typeof MiddlewareIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/function-method/': {
id: '/function-method/'
path: '/function-method'
- fullPath: '/function-method'
+ fullPath: '/function-method/'
preLoaderRoute: typeof FunctionMethodIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/function-metadata/': {
id: '/function-metadata/'
path: '/function-metadata'
- fullPath: '/function-metadata'
+ fullPath: '/function-metadata/'
preLoaderRoute: typeof FunctionMetadataIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/formdata-redirect/': {
id: '/formdata-redirect/'
path: '/formdata-redirect'
- fullPath: '/formdata-redirect'
+ fullPath: '/formdata-redirect/'
preLoaderRoute: typeof FormdataRedirectIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/factory/': {
id: '/factory/'
path: '/factory'
- fullPath: '/factory'
+ fullPath: '/factory/'
preLoaderRoute: typeof FactoryIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/cookies/': {
id: '/cookies/'
path: '/cookies'
- fullPath: '/cookies'
+ fullPath: '/cookies/'
preLoaderRoute: typeof CookiesIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/abort-signal/': {
id: '/abort-signal/'
path: '/abort-signal'
- fullPath: '/abort-signal'
+ fullPath: '/abort-signal/'
preLoaderRoute: typeof AbortSignalIndexRouteImport
parentRoute: typeof rootRouteImport
}
@@ -823,7 +823,7 @@ declare module '@tanstack/react-router' {
'/middleware/redirect-with-middleware/': {
id: '/middleware/redirect-with-middleware/'
path: '/middleware/redirect-with-middleware'
- fullPath: '/middleware/redirect-with-middleware'
+ fullPath: '/middleware/redirect-with-middleware/'
preLoaderRoute: typeof MiddlewareRedirectWithMiddlewareIndexRouteImport
parentRoute: typeof rootRouteImport
}
diff --git a/e2e/react-start/server-functions/src/routes/cookies/index.tsx b/e2e/react-start/server-functions/src/routes/cookies/index.tsx
index ae42043959c..005be0d9fa4 100644
--- a/e2e/react-start/server-functions/src/routes/cookies/index.tsx
+++ b/e2e/react-start/server-functions/src/routes/cookies/index.tsx
@@ -12,7 +12,7 @@ export const Route = createFileRoute('/cookies/')({
function RouteComponent() {
const search = Route.useSearch()
return (
-
+
got to route that sets the cookies with {JSON.stringify(search)}
)
diff --git a/e2e/react-start/website/src/routeTree.gen.ts b/e2e/react-start/website/src/routeTree.gen.ts
index 33b0aa6c4b3..e26402107fe 100644
--- a/e2e/react-start/website/src/routeTree.gen.ts
+++ b/e2e/react-start/website/src/routeTree.gen.ts
@@ -83,10 +83,11 @@ const ProjectVersionDocsFrameworkFrameworkExamplesSplatRoute =
} as any)
export interface FileRoutesByFullPath {
- '/$project': typeof ProjectIndexRoute
'/': typeof LibraryIndexRoute
- '/$project/$version/docs': typeof ProjectVersionDocsIndexRoute
- '/$project/$version': typeof LibraryProjectVersionIndexRoute
+ '/$project': typeof LibraryProjectRouteWithChildren
+ '/$project/': typeof ProjectIndexRoute
+ '/$project/$version/docs/': typeof ProjectVersionDocsIndexRoute
+ '/$project/$version/': typeof LibraryProjectVersionIndexRoute
'/$project/$version/docs/framework/$framework': typeof ProjectVersionDocsFrameworkFrameworkRouteWithChildren
'/$project/$version/docs/framework/$framework/$': typeof ProjectVersionDocsFrameworkFrameworkSplatRoute
'/$project/$version/docs/framework/$framework/{$}.md': typeof ProjectVersionDocsFrameworkFrameworkChar123Char125DotmdRoute
@@ -120,10 +121,11 @@ export interface FileRoutesById {
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
- | '/$project'
| '/'
- | '/$project/$version/docs'
- | '/$project/$version'
+ | '/$project'
+ | '/$project/'
+ | '/$project/$version/docs/'
+ | '/$project/$version/'
| '/$project/$version/docs/framework/$framework'
| '/$project/$version/docs/framework/$framework/$'
| '/$project/$version/docs/framework/$framework/{$}.md'
@@ -166,7 +168,7 @@ declare module '@tanstack/react-router' {
'/_library': {
id: '/_library'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof LibraryRouteImport
parentRoute: typeof rootRouteImport
}
@@ -180,7 +182,7 @@ declare module '@tanstack/react-router' {
'/$project/': {
id: '/$project/'
path: '/$project'
- fullPath: '/$project'
+ fullPath: '/$project/'
preLoaderRoute: typeof ProjectIndexRouteImport
parentRoute: typeof rootRouteImport
}
@@ -194,14 +196,14 @@ declare module '@tanstack/react-router' {
'/_library/$project/$version/': {
id: '/_library/$project/$version/'
path: '/$version'
- fullPath: '/$project/$version'
+ fullPath: '/$project/$version/'
preLoaderRoute: typeof LibraryProjectVersionIndexRouteImport
parentRoute: typeof LibraryProjectRoute
}
'/$project/$version/docs/': {
id: '/$project/$version/docs/'
path: '/$project/$version/docs'
- fullPath: '/$project/$version/docs'
+ fullPath: '/$project/$version/docs/'
preLoaderRoute: typeof ProjectVersionDocsIndexRouteImport
parentRoute: typeof rootRouteImport
}
diff --git a/e2e/react-start/website/src/routes/$project.$version.docs.index.tsx b/e2e/react-start/website/src/routes/$project.$version.docs.index.tsx
index 518a2bf4665..d6e3abbbf64 100644
--- a/e2e/react-start/website/src/routes/$project.$version.docs.index.tsx
+++ b/e2e/react-start/website/src/routes/$project.$version.docs.index.tsx
@@ -3,7 +3,7 @@ import { redirect, createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/$project/$version/docs/')({
beforeLoad: () => {
throw redirect({
- from: '/$project/$version/docs',
+ from: '/$project/$version/docs/',
to: '/$project/$version/docs/framework/$framework/$',
params: {
framework: 'react',
diff --git a/e2e/react-start/website/src/routes/_library.$project.$version.index.tsx b/e2e/react-start/website/src/routes/_library.$project.$version.index.tsx
index a45a2775ace..31248b72a02 100644
--- a/e2e/react-start/website/src/routes/_library.$project.$version.index.tsx
+++ b/e2e/react-start/website/src/routes/_library.$project.$version.index.tsx
@@ -16,7 +16,7 @@ function Page() {
Get started with our documentation.
diff --git a/e2e/solid-router/basic-file-based/src/routeTree.gen.ts b/e2e/solid-router/basic-file-based/src/routeTree.gen.ts
index 0b0315d3498..04fe5873747 100644
--- a/e2e/solid-router/basic-file-based/src/routeTree.gen.ts
+++ b/e2e/solid-router/basic-file-based/src/routeTree.gen.ts
@@ -709,10 +709,10 @@ export interface FileRoutesByFullPath {
'/posts/$postId': typeof PostsPostIdRoute
'/redirect/$target': typeof RedirectTargetRouteWithChildren
'/search-params/default': typeof SearchParamsDefaultRoute
- '/params-ps': typeof ParamsPsIndexRoute
+ '/params-ps/': typeof ParamsPsIndexRoute
'/posts/': typeof PostsIndexRoute
- '/redirect': typeof RedirectIndexRoute
- '/relative': typeof RelativeIndexRoute
+ '/redirect/': typeof RedirectIndexRoute
+ '/relative/': typeof RelativeIndexRoute
'/search-params/': typeof SearchParamsIndexRoute
'/non-nested/deep/$baz': typeof NonNestedDeepBazRouteRouteWithChildren
'/non-nested/named/$baz': typeof NonNestedNamedBazRouteRouteWithChildren
@@ -749,8 +749,8 @@ export interface FileRoutesByFullPath {
'/transition/typing/create-resource': typeof TransitionTypingCreateResourceRoute
'/λνλ―Όκ΅/wildcard/$': typeof Char45824Char54620Char48124Char44397WildcardSplatRoute
'/λνλ―Όκ΅/π/$id': typeof Char45824Char54620Char48124Char44397Char55357Char56960IdRoute
- '/params-ps/named': typeof ParamsPsNamedIndexRoute
- '/params-ps/wildcard': typeof ParamsPsWildcardIndexRoute
+ '/params-ps/named/': typeof ParamsPsNamedIndexRoute
+ '/params-ps/wildcard/': typeof ParamsPsWildcardIndexRoute
'/redirect/$target/': typeof RedirectTargetIndexRoute
'/non-nested/deep/$baz/bar': typeof NonNestedDeepBazBarRouteRouteWithChildren
'/params-ps/named/$foo/$bar': typeof ParamsPsNamedFooBarRouteRouteWithChildren
@@ -768,20 +768,20 @@ export interface FileRoutesByFullPath {
'/non-nested/path/baz/': typeof NonNestedPathBazIndexRoute
'/non-nested/prefix/prefix{$baz}/': typeof NonNestedPrefixPrefixChar123bazChar125IndexRoute
'/non-nested/suffix/{$baz}suffix/': typeof NonNestedSuffixChar123bazChar125suffixIndexRoute
- '/relative/link/nested': typeof RelativeLinkNestedIndexRoute
- '/relative/link/path': typeof RelativeLinkPathIndexRoute
- '/relative/link/with-search': typeof RelativeLinkWithSearchIndexRoute
- '/relative/useNavigate/nested': typeof RelativeUseNavigateNestedIndexRoute
- '/relative/useNavigate/path': typeof RelativeUseNavigatePathIndexRoute
- '/relative/useNavigate/with-search': typeof RelativeUseNavigateWithSearchIndexRoute
+ '/relative/link/nested/': typeof RelativeLinkNestedIndexRoute
+ '/relative/link/path/': typeof RelativeLinkPathIndexRoute
+ '/relative/link/with-search/': typeof RelativeLinkWithSearchIndexRoute
+ '/relative/useNavigate/nested/': typeof RelativeUseNavigateNestedIndexRoute
+ '/relative/useNavigate/path/': typeof RelativeUseNavigatePathIndexRoute
+ '/relative/useNavigate/with-search/': typeof RelativeUseNavigateWithSearchIndexRoute
'/non-nested/deep/$baz/bar/$foo': typeof NonNestedDeepBazBarFooRouteRouteWithChildren
'/non-nested/deep/$baz/bar/qux': typeof NonNestedDeepBazBarQuxRoute
'/params-ps/named/$foo/$bar/$baz': typeof ParamsPsNamedFooBarBazRoute
'/non-nested/deep/$baz/bar/': typeof NonNestedDeepBazBarIndexRoute
- '/relative/link/nested/deep': typeof RelativeLinkNestedDeepIndexRoute
- '/relative/link/path/$path': typeof RelativeLinkPathPathIndexRoute
- '/relative/useNavigate/nested/deep': typeof RelativeUseNavigateNestedDeepIndexRoute
- '/relative/useNavigate/path/$path': typeof RelativeUseNavigatePathPathIndexRoute
+ '/relative/link/nested/deep/': typeof RelativeLinkNestedDeepIndexRoute
+ '/relative/link/path/$path/': typeof RelativeLinkPathPathIndexRoute
+ '/relative/useNavigate/nested/deep/': typeof RelativeUseNavigateNestedDeepIndexRoute
+ '/relative/useNavigate/path/$path/': typeof RelativeUseNavigatePathPathIndexRoute
'/non-nested/deep/$baz/bar/$foo/qux': typeof NonNestedDeepBazBarFooQuxRoute
'/non-nested/deep/$baz/bar/$foo/': typeof NonNestedDeepBazBarFooIndexRoute
}
@@ -1017,10 +1017,10 @@ export interface FileRouteTypes {
| '/posts/$postId'
| '/redirect/$target'
| '/search-params/default'
- | '/params-ps'
+ | '/params-ps/'
| '/posts/'
- | '/redirect'
- | '/relative'
+ | '/redirect/'
+ | '/relative/'
| '/search-params/'
| '/non-nested/deep/$baz'
| '/non-nested/named/$baz'
@@ -1057,8 +1057,8 @@ export interface FileRouteTypes {
| '/transition/typing/create-resource'
| '/λνλ―Όκ΅/wildcard/$'
| '/λνλ―Όκ΅/π/$id'
- | '/params-ps/named'
- | '/params-ps/wildcard'
+ | '/params-ps/named/'
+ | '/params-ps/wildcard/'
| '/redirect/$target/'
| '/non-nested/deep/$baz/bar'
| '/params-ps/named/$foo/$bar'
@@ -1076,20 +1076,20 @@ export interface FileRouteTypes {
| '/non-nested/path/baz/'
| '/non-nested/prefix/prefix{$baz}/'
| '/non-nested/suffix/{$baz}suffix/'
- | '/relative/link/nested'
- | '/relative/link/path'
- | '/relative/link/with-search'
- | '/relative/useNavigate/nested'
- | '/relative/useNavigate/path'
- | '/relative/useNavigate/with-search'
+ | '/relative/link/nested/'
+ | '/relative/link/path/'
+ | '/relative/link/with-search/'
+ | '/relative/useNavigate/nested/'
+ | '/relative/useNavigate/path/'
+ | '/relative/useNavigate/with-search/'
| '/non-nested/deep/$baz/bar/$foo'
| '/non-nested/deep/$baz/bar/qux'
| '/params-ps/named/$foo/$bar/$baz'
| '/non-nested/deep/$baz/bar/'
- | '/relative/link/nested/deep'
- | '/relative/link/path/$path'
- | '/relative/useNavigate/nested/deep'
- | '/relative/useNavigate/path/$path'
+ | '/relative/link/nested/deep/'
+ | '/relative/link/path/$path/'
+ | '/relative/useNavigate/nested/deep/'
+ | '/relative/useNavigate/path/$path/'
| '/non-nested/deep/$baz/bar/$foo/qux'
| '/non-nested/deep/$baz/bar/$foo/'
fileRoutesByTo: FileRoutesByTo
@@ -1409,7 +1409,7 @@ declare module '@tanstack/solid-router' {
'/_layout': {
id: '/_layout'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof LayoutRouteImport
parentRoute: typeof rootRouteImport
}
@@ -1451,14 +1451,14 @@ declare module '@tanstack/solid-router' {
'/relative/': {
id: '/relative/'
path: '/relative'
- fullPath: '/relative'
+ fullPath: '/relative/'
preLoaderRoute: typeof RelativeIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/redirect/': {
id: '/redirect/'
path: '/redirect'
- fullPath: '/redirect'
+ fullPath: '/redirect/'
preLoaderRoute: typeof RedirectIndexRouteImport
parentRoute: typeof rootRouteImport
}
@@ -1472,7 +1472,7 @@ declare module '@tanstack/solid-router' {
'/params-ps/': {
id: '/params-ps/'
path: '/params-ps'
- fullPath: '/params-ps'
+ fullPath: '/params-ps/'
preLoaderRoute: typeof ParamsPsIndexRouteImport
parentRoute: typeof rootRouteImport
}
@@ -1500,7 +1500,7 @@ declare module '@tanstack/solid-router' {
'/_layout/_layout-2': {
id: '/_layout/_layout-2'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof LayoutLayout2RouteImport
parentRoute: typeof LayoutRoute
}
@@ -1598,14 +1598,14 @@ declare module '@tanstack/solid-router' {
'/params-ps/wildcard/': {
id: '/params-ps/wildcard/'
path: '/params-ps/wildcard'
- fullPath: '/params-ps/wildcard'
+ fullPath: '/params-ps/wildcard/'
preLoaderRoute: typeof ParamsPsWildcardIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/params-ps/named/': {
id: '/params-ps/named/'
path: '/params-ps/named'
- fullPath: '/params-ps/named'
+ fullPath: '/params-ps/named/'
preLoaderRoute: typeof ParamsPsNamedIndexRouteImport
parentRoute: typeof rootRouteImport
}
@@ -1857,42 +1857,42 @@ declare module '@tanstack/solid-router' {
'/relative/useNavigate/with-search/': {
id: '/relative/useNavigate/with-search/'
path: '/with-search'
- fullPath: '/relative/useNavigate/with-search'
+ fullPath: '/relative/useNavigate/with-search/'
preLoaderRoute: typeof RelativeUseNavigateWithSearchIndexRouteImport
parentRoute: typeof RelativeUseNavigateRouteRoute
}
'/relative/useNavigate/path/': {
id: '/relative/useNavigate/path/'
path: '/path'
- fullPath: '/relative/useNavigate/path'
+ fullPath: '/relative/useNavigate/path/'
preLoaderRoute: typeof RelativeUseNavigatePathIndexRouteImport
parentRoute: typeof RelativeUseNavigateRouteRoute
}
'/relative/useNavigate/nested/': {
id: '/relative/useNavigate/nested/'
path: '/nested'
- fullPath: '/relative/useNavigate/nested'
+ fullPath: '/relative/useNavigate/nested/'
preLoaderRoute: typeof RelativeUseNavigateNestedIndexRouteImport
parentRoute: typeof RelativeUseNavigateRouteRoute
}
'/relative/link/with-search/': {
id: '/relative/link/with-search/'
path: '/with-search'
- fullPath: '/relative/link/with-search'
+ fullPath: '/relative/link/with-search/'
preLoaderRoute: typeof RelativeLinkWithSearchIndexRouteImport
parentRoute: typeof RelativeLinkRouteRoute
}
'/relative/link/path/': {
id: '/relative/link/path/'
path: '/path'
- fullPath: '/relative/link/path'
+ fullPath: '/relative/link/path/'
preLoaderRoute: typeof RelativeLinkPathIndexRouteImport
parentRoute: typeof RelativeLinkRouteRoute
}
'/relative/link/nested/': {
id: '/relative/link/nested/'
path: '/nested'
- fullPath: '/relative/link/nested'
+ fullPath: '/relative/link/nested/'
preLoaderRoute: typeof RelativeLinkNestedIndexRouteImport
parentRoute: typeof RelativeLinkRouteRoute
}
@@ -2011,28 +2011,28 @@ declare module '@tanstack/solid-router' {
'/relative/useNavigate/path/$path/': {
id: '/relative/useNavigate/path/$path/'
path: '/path/$path'
- fullPath: '/relative/useNavigate/path/$path'
+ fullPath: '/relative/useNavigate/path/$path/'
preLoaderRoute: typeof RelativeUseNavigatePathPathIndexRouteImport
parentRoute: typeof RelativeUseNavigateRouteRoute
}
'/relative/useNavigate/nested/deep/': {
id: '/relative/useNavigate/nested/deep/'
path: '/nested/deep'
- fullPath: '/relative/useNavigate/nested/deep'
+ fullPath: '/relative/useNavigate/nested/deep/'
preLoaderRoute: typeof RelativeUseNavigateNestedDeepIndexRouteImport
parentRoute: typeof RelativeUseNavigateRouteRoute
}
'/relative/link/path/$path/': {
id: '/relative/link/path/$path/'
path: '/path/$path'
- fullPath: '/relative/link/path/$path'
+ fullPath: '/relative/link/path/$path/'
preLoaderRoute: typeof RelativeLinkPathPathIndexRouteImport
parentRoute: typeof RelativeLinkRouteRoute
}
'/relative/link/nested/deep/': {
id: '/relative/link/nested/deep/'
path: '/nested/deep'
- fullPath: '/relative/link/nested/deep'
+ fullPath: '/relative/link/nested/deep/'
preLoaderRoute: typeof RelativeLinkNestedDeepIndexRouteImport
parentRoute: typeof RelativeLinkRouteRoute
}
diff --git a/e2e/solid-router/basic-file-based/src/routes/relative/link/path/$path/index.tsx b/e2e/solid-router/basic-file-based/src/routes/relative/link/path/$path/index.tsx
index 1cf079d4b82..bdfcafee622 100644
--- a/e2e/solid-router/basic-file-based/src/routes/relative/link/path/$path/index.tsx
+++ b/e2e/solid-router/basic-file-based/src/routes/relative/link/path/$path/index.tsx
@@ -17,7 +17,7 @@ function RouteComponent() {
navigate({
- from: '/relative/useNavigate/path',
+ from: '/relative/useNavigate/path/',
to: './$path',
params: { path: params().path === 'a' ? 'b' : 'a' },
})
diff --git a/e2e/solid-start/server-functions/src/routeTree.gen.ts b/e2e/solid-start/server-functions/src/routeTree.gen.ts
index 0dcd95b34a9..329a70726e5 100644
--- a/e2e/solid-start/server-functions/src/routeTree.gen.ts
+++ b/e2e/solid-start/server-functions/src/routeTree.gen.ts
@@ -214,16 +214,16 @@ export interface FileRoutesByFullPath {
'/middleware/send-serverFn': typeof MiddlewareSendServerFnRoute
'/redirect-test-ssr/target': typeof RedirectTestSsrTargetRoute
'/redirect-test/target': typeof RedirectTestTargetRoute
- '/abort-signal': typeof AbortSignalIndexRoute
- '/cookies': typeof CookiesIndexRoute
- '/factory': typeof FactoryIndexRoute
- '/formdata-redirect': typeof FormdataRedirectIndexRoute
- '/function-metadata': typeof FunctionMetadataIndexRoute
- '/function-method': typeof FunctionMethodIndexRoute
- '/middleware': typeof MiddlewareIndexRoute
- '/primitives': typeof PrimitivesIndexRoute
- '/redirect-test-ssr': typeof RedirectTestSsrIndexRoute
- '/redirect-test': typeof RedirectTestIndexRoute
+ '/abort-signal/': typeof AbortSignalIndexRoute
+ '/cookies/': typeof CookiesIndexRoute
+ '/factory/': typeof FactoryIndexRoute
+ '/formdata-redirect/': typeof FormdataRedirectIndexRoute
+ '/function-metadata/': typeof FunctionMetadataIndexRoute
+ '/function-method/': typeof FunctionMethodIndexRoute
+ '/middleware/': typeof MiddlewareIndexRoute
+ '/primitives/': typeof PrimitivesIndexRoute
+ '/redirect-test-ssr/': typeof RedirectTestSsrIndexRoute
+ '/redirect-test/': typeof RedirectTestIndexRoute
'/formdata-redirect/target/$name': typeof FormdataRedirectTargetNameRoute
}
export interface FileRoutesByTo {
@@ -313,16 +313,16 @@ export interface FileRouteTypes {
| '/middleware/send-serverFn'
| '/redirect-test-ssr/target'
| '/redirect-test/target'
- | '/abort-signal'
- | '/cookies'
- | '/factory'
- | '/formdata-redirect'
- | '/function-metadata'
- | '/function-method'
- | '/middleware'
- | '/primitives'
- | '/redirect-test-ssr'
- | '/redirect-test'
+ | '/abort-signal/'
+ | '/cookies/'
+ | '/factory/'
+ | '/formdata-redirect/'
+ | '/function-metadata/'
+ | '/function-method/'
+ | '/middleware/'
+ | '/primitives/'
+ | '/redirect-test-ssr/'
+ | '/redirect-test/'
| '/formdata-redirect/target/$name'
fileRoutesByTo: FileRoutesByTo
to:
@@ -512,70 +512,70 @@ declare module '@tanstack/solid-router' {
'/redirect-test/': {
id: '/redirect-test/'
path: '/redirect-test'
- fullPath: '/redirect-test'
+ fullPath: '/redirect-test/'
preLoaderRoute: typeof RedirectTestIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/redirect-test-ssr/': {
id: '/redirect-test-ssr/'
path: '/redirect-test-ssr'
- fullPath: '/redirect-test-ssr'
+ fullPath: '/redirect-test-ssr/'
preLoaderRoute: typeof RedirectTestSsrIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/primitives/': {
id: '/primitives/'
path: '/primitives'
- fullPath: '/primitives'
+ fullPath: '/primitives/'
preLoaderRoute: typeof PrimitivesIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/middleware/': {
id: '/middleware/'
path: '/middleware'
- fullPath: '/middleware'
+ fullPath: '/middleware/'
preLoaderRoute: typeof MiddlewareIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/function-method/': {
id: '/function-method/'
path: '/function-method'
- fullPath: '/function-method'
+ fullPath: '/function-method/'
preLoaderRoute: typeof FunctionMethodIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/function-metadata/': {
id: '/function-metadata/'
path: '/function-metadata'
- fullPath: '/function-metadata'
+ fullPath: '/function-metadata/'
preLoaderRoute: typeof FunctionMetadataIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/formdata-redirect/': {
id: '/formdata-redirect/'
path: '/formdata-redirect'
- fullPath: '/formdata-redirect'
+ fullPath: '/formdata-redirect/'
preLoaderRoute: typeof FormdataRedirectIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/factory/': {
id: '/factory/'
path: '/factory'
- fullPath: '/factory'
+ fullPath: '/factory/'
preLoaderRoute: typeof FactoryIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/cookies/': {
id: '/cookies/'
path: '/cookies'
- fullPath: '/cookies'
+ fullPath: '/cookies/'
preLoaderRoute: typeof CookiesIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/abort-signal/': {
id: '/abort-signal/'
path: '/abort-signal'
- fullPath: '/abort-signal'
+ fullPath: '/abort-signal/'
preLoaderRoute: typeof AbortSignalIndexRouteImport
parentRoute: typeof rootRouteImport
}
diff --git a/e2e/solid-start/server-functions/src/routes/cookies/index.tsx b/e2e/solid-start/server-functions/src/routes/cookies/index.tsx
index 5cccd18057c..9abb86d0f79 100644
--- a/e2e/solid-start/server-functions/src/routes/cookies/index.tsx
+++ b/e2e/solid-start/server-functions/src/routes/cookies/index.tsx
@@ -14,7 +14,7 @@ function RouteComponent() {
return (
diff --git a/e2e/solid-start/website/src/routeTree.gen.ts b/e2e/solid-start/website/src/routeTree.gen.ts
index 0b9ca527e54..c37e78d2f18 100644
--- a/e2e/solid-start/website/src/routeTree.gen.ts
+++ b/e2e/solid-start/website/src/routeTree.gen.ts
@@ -76,10 +76,11 @@ const ProjectVersionDocsFrameworkFrameworkExamplesSplatRoute =
} as any)
export interface FileRoutesByFullPath {
- '/$project': typeof ProjectIndexRoute
'/': typeof LibraryIndexRoute
- '/$project/$version/docs': typeof ProjectVersionDocsIndexRoute
- '/$project/$version': typeof LibraryProjectVersionIndexRoute
+ '/$project': typeof LibraryProjectRouteWithChildren
+ '/$project/': typeof ProjectIndexRoute
+ '/$project/$version/docs/': typeof ProjectVersionDocsIndexRoute
+ '/$project/$version/': typeof LibraryProjectVersionIndexRoute
'/$project/$version/docs/framework/$framework': typeof ProjectVersionDocsFrameworkFrameworkRouteWithChildren
'/$project/$version/docs/framework/$framework/$': typeof ProjectVersionDocsFrameworkFrameworkSplatRoute
'/$project/$version/docs/framework/$framework/': typeof ProjectVersionDocsFrameworkFrameworkIndexRoute
@@ -110,10 +111,11 @@ export interface FileRoutesById {
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
- | '/$project'
| '/'
- | '/$project/$version/docs'
- | '/$project/$version'
+ | '/$project'
+ | '/$project/'
+ | '/$project/$version/docs/'
+ | '/$project/$version/'
| '/$project/$version/docs/framework/$framework'
| '/$project/$version/docs/framework/$framework/$'
| '/$project/$version/docs/framework/$framework/'
@@ -153,7 +155,7 @@ declare module '@tanstack/solid-router' {
'/_library': {
id: '/_library'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof LibraryRouteImport
parentRoute: typeof rootRouteImport
}
@@ -167,7 +169,7 @@ declare module '@tanstack/solid-router' {
'/$project/': {
id: '/$project/'
path: '/$project'
- fullPath: '/$project'
+ fullPath: '/$project/'
preLoaderRoute: typeof ProjectIndexRouteImport
parentRoute: typeof rootRouteImport
}
@@ -181,14 +183,14 @@ declare module '@tanstack/solid-router' {
'/_library/$project/$version/': {
id: '/_library/$project/$version/'
path: '/$version'
- fullPath: '/$project/$version'
+ fullPath: '/$project/$version/'
preLoaderRoute: typeof LibraryProjectVersionIndexRouteImport
parentRoute: typeof LibraryProjectRoute
}
'/$project/$version/docs/': {
id: '/$project/$version/docs/'
path: '/$project/$version/docs'
- fullPath: '/$project/$version/docs'
+ fullPath: '/$project/$version/docs/'
preLoaderRoute: typeof ProjectVersionDocsIndexRouteImport
parentRoute: typeof rootRouteImport
}
diff --git a/e2e/solid-start/website/src/routes/$project.$version.docs.index.tsx b/e2e/solid-start/website/src/routes/$project.$version.docs.index.tsx
index a80b132e2ef..c5005f8ec71 100644
--- a/e2e/solid-start/website/src/routes/$project.$version.docs.index.tsx
+++ b/e2e/solid-start/website/src/routes/$project.$version.docs.index.tsx
@@ -3,7 +3,7 @@ import { redirect, createFileRoute } from '@tanstack/solid-router'
export const Route = createFileRoute('/$project/$version/docs/')({
beforeLoad: () => {
throw redirect({
- from: '/$project/$version/docs',
+ from: '/$project/$version/docs/',
to: '/$project/$version/docs/framework/$framework/$',
params: {
framework: 'solid',
diff --git a/e2e/solid-start/website/src/routes/_library.$project.$version.index.tsx b/e2e/solid-start/website/src/routes/_library.$project.$version.index.tsx
index 191c6bf1654..61187e80cdf 100644
--- a/e2e/solid-start/website/src/routes/_library.$project.$version.index.tsx
+++ b/e2e/solid-start/website/src/routes/_library.$project.$version.index.tsx
@@ -14,7 +14,7 @@ function Page() {
version: {params().version}
-
+
Get started with our documentation.
diff --git a/e2e/vue-start/server-functions/src/routeTree.gen.ts b/e2e/vue-start/server-functions/src/routeTree.gen.ts
index 25a71dff282..43a6eb4ae6a 100644
--- a/e2e/vue-start/server-functions/src/routeTree.gen.ts
+++ b/e2e/vue-start/server-functions/src/routeTree.gen.ts
@@ -208,15 +208,15 @@ export interface FileRoutesByFullPath {
'/middleware/send-serverFn': typeof MiddlewareSendServerFnRoute
'/redirect-test-ssr/target': typeof RedirectTestSsrTargetRoute
'/redirect-test/target': typeof RedirectTestTargetRoute
- '/cookies': typeof CookiesIndexRoute
- '/factory': typeof FactoryIndexRoute
- '/formdata-redirect': typeof FormdataRedirectIndexRoute
- '/function-metadata': typeof FunctionMetadataIndexRoute
- '/function-method': typeof FunctionMethodIndexRoute
- '/middleware': typeof MiddlewareIndexRoute
- '/primitives': typeof PrimitivesIndexRoute
- '/redirect-test-ssr': typeof RedirectTestSsrIndexRoute
- '/redirect-test': typeof RedirectTestIndexRoute
+ '/cookies/': typeof CookiesIndexRoute
+ '/factory/': typeof FactoryIndexRoute
+ '/formdata-redirect/': typeof FormdataRedirectIndexRoute
+ '/function-metadata/': typeof FunctionMetadataIndexRoute
+ '/function-method/': typeof FunctionMethodIndexRoute
+ '/middleware/': typeof MiddlewareIndexRoute
+ '/primitives/': typeof PrimitivesIndexRoute
+ '/redirect-test-ssr/': typeof RedirectTestSsrIndexRoute
+ '/redirect-test/': typeof RedirectTestIndexRoute
'/formdata-redirect/target/$name': typeof FormdataRedirectTargetNameRoute
}
export interface FileRoutesByTo {
@@ -304,15 +304,15 @@ export interface FileRouteTypes {
| '/middleware/send-serverFn'
| '/redirect-test-ssr/target'
| '/redirect-test/target'
- | '/cookies'
- | '/factory'
- | '/formdata-redirect'
- | '/function-metadata'
- | '/function-method'
- | '/middleware'
- | '/primitives'
- | '/redirect-test-ssr'
- | '/redirect-test'
+ | '/cookies/'
+ | '/factory/'
+ | '/formdata-redirect/'
+ | '/function-metadata/'
+ | '/function-method/'
+ | '/middleware/'
+ | '/primitives/'
+ | '/redirect-test-ssr/'
+ | '/redirect-test/'
| '/formdata-redirect/target/$name'
fileRoutesByTo: FileRoutesByTo
to:
@@ -506,63 +506,63 @@ declare module '@tanstack/vue-router' {
'/redirect-test/': {
id: '/redirect-test/'
path: '/redirect-test'
- fullPath: '/redirect-test'
+ fullPath: '/redirect-test/'
preLoaderRoute: typeof RedirectTestIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/redirect-test-ssr/': {
id: '/redirect-test-ssr/'
path: '/redirect-test-ssr'
- fullPath: '/redirect-test-ssr'
+ fullPath: '/redirect-test-ssr/'
preLoaderRoute: typeof RedirectTestSsrIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/primitives/': {
id: '/primitives/'
path: '/primitives'
- fullPath: '/primitives'
+ fullPath: '/primitives/'
preLoaderRoute: typeof PrimitivesIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/middleware/': {
id: '/middleware/'
path: '/middleware'
- fullPath: '/middleware'
+ fullPath: '/middleware/'
preLoaderRoute: typeof MiddlewareIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/function-method/': {
id: '/function-method/'
path: '/function-method'
- fullPath: '/function-method'
+ fullPath: '/function-method/'
preLoaderRoute: typeof FunctionMethodIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/function-metadata/': {
id: '/function-metadata/'
path: '/function-metadata'
- fullPath: '/function-metadata'
+ fullPath: '/function-metadata/'
preLoaderRoute: typeof FunctionMetadataIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/formdata-redirect/': {
id: '/formdata-redirect/'
path: '/formdata-redirect'
- fullPath: '/formdata-redirect'
+ fullPath: '/formdata-redirect/'
preLoaderRoute: typeof FormdataRedirectIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/factory/': {
id: '/factory/'
path: '/factory'
- fullPath: '/factory'
+ fullPath: '/factory/'
preLoaderRoute: typeof FactoryIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/cookies/': {
id: '/cookies/'
path: '/cookies'
- fullPath: '/cookies'
+ fullPath: '/cookies/'
preLoaderRoute: typeof CookiesIndexRouteImport
parentRoute: typeof rootRouteImport
}
diff --git a/e2e/vue-start/server-functions/src/routes/cookies/index.tsx b/e2e/vue-start/server-functions/src/routes/cookies/index.tsx
index c47897c1096..5da8860ac6e 100644
--- a/e2e/vue-start/server-functions/src/routes/cookies/index.tsx
+++ b/e2e/vue-start/server-functions/src/routes/cookies/index.tsx
@@ -14,7 +14,7 @@ function RouteComponent() {
return (
diff --git a/e2e/vue-start/website/src/routeTree.gen.ts b/e2e/vue-start/website/src/routeTree.gen.ts
index 6b390c0fcf7..e7b58aae2a6 100644
--- a/e2e/vue-start/website/src/routeTree.gen.ts
+++ b/e2e/vue-start/website/src/routeTree.gen.ts
@@ -76,10 +76,11 @@ const ProjectVersionDocsFrameworkFrameworkExamplesSplatRoute =
} as any)
export interface FileRoutesByFullPath {
- '/$project': typeof ProjectIndexRoute
'/': typeof LibraryIndexRoute
- '/$project/$version/docs': typeof ProjectVersionDocsIndexRoute
- '/$project/$version': typeof LibraryProjectVersionIndexRoute
+ '/$project': typeof LibraryProjectRouteWithChildren
+ '/$project/': typeof ProjectIndexRoute
+ '/$project/$version/docs/': typeof ProjectVersionDocsIndexRoute
+ '/$project/$version/': typeof LibraryProjectVersionIndexRoute
'/$project/$version/docs/framework/$framework': typeof ProjectVersionDocsFrameworkFrameworkRouteWithChildren
'/$project/$version/docs/framework/$framework/$': typeof ProjectVersionDocsFrameworkFrameworkSplatRoute
'/$project/$version/docs/framework/$framework/': typeof ProjectVersionDocsFrameworkFrameworkIndexRoute
@@ -110,10 +111,11 @@ export interface FileRoutesById {
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
- | '/$project'
| '/'
- | '/$project/$version/docs'
- | '/$project/$version'
+ | '/$project'
+ | '/$project/'
+ | '/$project/$version/docs/'
+ | '/$project/$version/'
| '/$project/$version/docs/framework/$framework'
| '/$project/$version/docs/framework/$framework/$'
| '/$project/$version/docs/framework/$framework/'
@@ -153,7 +155,7 @@ declare module '@tanstack/vue-router' {
'/_library': {
id: '/_library'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof LibraryRouteImport
parentRoute: typeof rootRouteImport
}
@@ -167,7 +169,7 @@ declare module '@tanstack/vue-router' {
'/$project/': {
id: '/$project/'
path: '/$project'
- fullPath: '/$project'
+ fullPath: '/$project/'
preLoaderRoute: typeof ProjectIndexRouteImport
parentRoute: typeof rootRouteImport
}
@@ -181,14 +183,14 @@ declare module '@tanstack/vue-router' {
'/_library/$project/$version/': {
id: '/_library/$project/$version/'
path: '/$version'
- fullPath: '/$project/$version'
+ fullPath: '/$project/$version/'
preLoaderRoute: typeof LibraryProjectVersionIndexRouteImport
parentRoute: typeof LibraryProjectRoute
}
'/$project/$version/docs/': {
id: '/$project/$version/docs/'
path: '/$project/$version/docs'
- fullPath: '/$project/$version/docs'
+ fullPath: '/$project/$version/docs/'
preLoaderRoute: typeof ProjectVersionDocsIndexRouteImport
parentRoute: typeof rootRouteImport
}
diff --git a/e2e/vue-start/website/src/routes/$project.$version.docs.index.tsx b/e2e/vue-start/website/src/routes/$project.$version.docs.index.tsx
index b033d538656..8c067c8c867 100644
--- a/e2e/vue-start/website/src/routes/$project.$version.docs.index.tsx
+++ b/e2e/vue-start/website/src/routes/$project.$version.docs.index.tsx
@@ -3,7 +3,7 @@ import { redirect, createFileRoute } from '@tanstack/vue-router'
export const Route = createFileRoute('/$project/$version/docs/')({
beforeLoad: () => {
throw redirect({
- from: '/$project/$version/docs',
+ from: '/$project/$version/docs/',
to: '/$project/$version/docs/framework/$framework/$',
params: {
framework: 'vue',
diff --git a/e2e/vue-start/website/src/routes/_library.$project.$version.index.tsx b/e2e/vue-start/website/src/routes/_library.$project.$version.index.tsx
index 67986b09c6f..ed8e4d0bb4e 100644
--- a/e2e/vue-start/website/src/routes/_library.$project.$version.index.tsx
+++ b/e2e/vue-start/website/src/routes/_library.$project.$version.index.tsx
@@ -14,7 +14,7 @@ function Page() {
version: {params.value.version}
-
+
Get started with our documentation.
diff --git a/examples/react/search-validator-adapters/src/routeTree.gen.ts b/examples/react/search-validator-adapters/src/routeTree.gen.ts
index 3312abe25e8..c3d792c4118 100644
--- a/examples/react/search-validator-adapters/src/routeTree.gen.ts
+++ b/examples/react/search-validator-adapters/src/routeTree.gen.ts
@@ -39,9 +39,9 @@ const UsersArktypeIndexRoute = UsersArktypeIndexRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
- '/users/arktype': typeof UsersArktypeIndexRoute
- '/users/valibot': typeof UsersValibotIndexRoute
- '/users/zod': typeof UsersZodIndexRoute
+ '/users/arktype/': typeof UsersArktypeIndexRoute
+ '/users/valibot/': typeof UsersValibotIndexRoute
+ '/users/zod/': typeof UsersZodIndexRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
@@ -58,7 +58,7 @@ export interface FileRoutesById {
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
- fullPaths: '/' | '/users/arktype' | '/users/valibot' | '/users/zod'
+ fullPaths: '/' | '/users/arktype/' | '/users/valibot/' | '/users/zod/'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/users/arktype' | '/users/valibot' | '/users/zod'
id: '__root__' | '/' | '/users/arktype/' | '/users/valibot/' | '/users/zod/'
@@ -83,21 +83,21 @@ declare module '@tanstack/react-router' {
'/users/zod/': {
id: '/users/zod/'
path: '/users/zod'
- fullPath: '/users/zod'
+ fullPath: '/users/zod/'
preLoaderRoute: typeof UsersZodIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/users/valibot/': {
id: '/users/valibot/'
path: '/users/valibot'
- fullPath: '/users/valibot'
+ fullPath: '/users/valibot/'
preLoaderRoute: typeof UsersValibotIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/users/arktype/': {
id: '/users/arktype/'
path: '/users/arktype'
- fullPath: '/users/arktype'
+ fullPath: '/users/arktype/'
preLoaderRoute: typeof UsersArktypeIndexRouteImport
parentRoute: typeof rootRouteImport
}
diff --git a/examples/react/search-validator-adapters/tests/arktype.test.tsx b/examples/react/search-validator-adapters/tests/arktype.test.tsx
index da700851149..1c3a1baf764 100644
--- a/examples/react/search-validator-adapters/tests/arktype.test.tsx
+++ b/examples/react/search-validator-adapters/tests/arktype.test.tsx
@@ -26,7 +26,7 @@ test('can navigate to the route', async () => {
return (
diff --git a/examples/react/search-validator-adapters/tests/valibot.test.tsx b/examples/react/search-validator-adapters/tests/valibot.test.tsx
index 30dc6da7518..3680d2302c8 100644
--- a/examples/react/search-validator-adapters/tests/valibot.test.tsx
+++ b/examples/react/search-validator-adapters/tests/valibot.test.tsx
@@ -25,7 +25,7 @@ test('can navigate to the route', async () => {
return (
diff --git a/examples/solid/search-validator-adapters/src/routeTree.gen.ts b/examples/solid/search-validator-adapters/src/routeTree.gen.ts
index 3226feeab26..d7aab613247 100644
--- a/examples/solid/search-validator-adapters/src/routeTree.gen.ts
+++ b/examples/solid/search-validator-adapters/src/routeTree.gen.ts
@@ -39,9 +39,9 @@ const UsersArktypeIndexRoute = UsersArktypeIndexRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
- '/users/arktype': typeof UsersArktypeIndexRoute
- '/users/valibot': typeof UsersValibotIndexRoute
- '/users/zod': typeof UsersZodIndexRoute
+ '/users/arktype/': typeof UsersArktypeIndexRoute
+ '/users/valibot/': typeof UsersValibotIndexRoute
+ '/users/zod/': typeof UsersZodIndexRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
@@ -58,7 +58,7 @@ export interface FileRoutesById {
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
- fullPaths: '/' | '/users/arktype' | '/users/valibot' | '/users/zod'
+ fullPaths: '/' | '/users/arktype/' | '/users/valibot/' | '/users/zod/'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/users/arktype' | '/users/valibot' | '/users/zod'
id: '__root__' | '/' | '/users/arktype/' | '/users/valibot/' | '/users/zod/'
@@ -83,21 +83,21 @@ declare module '@tanstack/solid-router' {
'/users/zod/': {
id: '/users/zod/'
path: '/users/zod'
- fullPath: '/users/zod'
+ fullPath: '/users/zod/'
preLoaderRoute: typeof UsersZodIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/users/valibot/': {
id: '/users/valibot/'
path: '/users/valibot'
- fullPath: '/users/valibot'
+ fullPath: '/users/valibot/'
preLoaderRoute: typeof UsersValibotIndexRouteImport
parentRoute: typeof rootRouteImport
}
'/users/arktype/': {
id: '/users/arktype/'
path: '/users/arktype'
- fullPath: '/users/arktype'
+ fullPath: '/users/arktype/'
preLoaderRoute: typeof UsersArktypeIndexRouteImport
parentRoute: typeof rootRouteImport
}
diff --git a/examples/solid/search-validator-adapters/tests/arktype.test.tsx b/examples/solid/search-validator-adapters/tests/arktype.test.tsx
index 7e130132bd1..4ec555fc7bf 100644
--- a/examples/solid/search-validator-adapters/tests/arktype.test.tsx
+++ b/examples/solid/search-validator-adapters/tests/arktype.test.tsx
@@ -26,7 +26,7 @@ test('can navigate to the route', async () => {
return (
{search().search}
-
+
Update
diff --git a/examples/solid/search-validator-adapters/tests/valibot.test.tsx b/examples/solid/search-validator-adapters/tests/valibot.test.tsx
index 882a73d574f..cd4545397ce 100644
--- a/examples/solid/search-validator-adapters/tests/valibot.test.tsx
+++ b/examples/solid/search-validator-adapters/tests/valibot.test.tsx
@@ -25,7 +25,7 @@ test('can navigate to the route', async () => {
return (
{search().search}
-
+
Update
diff --git a/packages/react-router/tests/routeApi.test-d.tsx b/packages/react-router/tests/routeApi.test-d.tsx
index a51a50b10ff..587c189fb03 100644
--- a/packages/react-router/tests/routeApi.test-d.tsx
+++ b/packages/react-router/tests/routeApi.test-d.tsx
@@ -106,3 +106,35 @@ describe('createRoute', () => {
})
})
})
+
+describe('fullPath type correctness', () => {
+ // Create a layout route (pathless route)
+ const layoutRoute = createRoute({
+ getParentRoute: () => rootRoute,
+ id: '_layout',
+ })
+
+ const layoutChildRoute = createRoute({
+ getParentRoute: () => layoutRoute,
+ path: 'dashboard',
+ })
+
+ const routeTreeWithLayout = rootRoute.addChildren([
+ layoutRoute.addChildren([layoutChildRoute]),
+ indexRoute,
+ ])
+
+ test('index route fullPath should have trailing slash to match runtime', () => {
+ // At runtime, Route.fullPath returns '/invoices/' for an index route
+ // The type should match this behavior
+ const fullPath = invoicesIndexRoute.fullPath
+ expectTypeOf(fullPath).toEqualTypeOf<'/invoices/'>()
+ })
+
+ test('layout route fullPath should be "/" not empty string', () => {
+ // At runtime, a pathless layout route has fullPath of '/'
+ // The type should be '/' not ''
+ const fullPath = layoutRoute.fullPath
+ expectTypeOf(fullPath).toEqualTypeOf<'/'>()
+ })
+})
diff --git a/packages/router-core/src/route.ts b/packages/router-core/src/route.ts
index c06ee9fcc5e..faadfd2c79e 100644
--- a/packages/router-core/src/route.ts
+++ b/packages/router-core/src/route.ts
@@ -1,5 +1,5 @@
import invariant from 'tiny-invariant'
-import { joinPaths, trimPathLeft } from './path'
+import { joinPaths, trimPathLeft, trimPathRight } from './path'
import { notFound } from './not-found'
import { redirect } from './redirect'
import { rootRouteId } from './root'
@@ -1755,7 +1755,7 @@ export class BaseRoute<
this._path = path as TPath
this._id = id as TId
this._fullPath = fullPath as TFullPath
- this._to = fullPath as TrimPathRight
+ this._to = trimPathRight(fullPath) as TrimPathRight
}
addChildren: RouteAddChildrenFn<
diff --git a/packages/router-generator/src/utils.ts b/packages/router-generator/src/utils.ts
index 366a4e84f6f..094a50924a8 100644
--- a/packages/router-generator/src/utils.ts
+++ b/packages/router-generator/src/utils.ts
@@ -700,9 +700,10 @@ export function isRouteNodeValidForAugmentation(
* Infers the path for use by TS
*/
export const inferPath = (routeNode: RouteNode): string => {
- return routeNode.cleanedPath === '/'
- ? routeNode.cleanedPath
- : (routeNode.cleanedPath?.replace(/\/$/, '') ?? '')
+ if (routeNode.cleanedPath === '/') {
+ return routeNode.cleanedPath ?? ''
+ }
+ return routeNode.cleanedPath?.replace(/\/$/, '') ?? ''
}
/**
@@ -719,7 +720,25 @@ export const inferFullPath = (routeNode: RouteNode): string => {
),
)
- return routeNode.cleanedPath === '/' ? fullPath : fullPath.replace(/\/$/, '')
+ if (fullPath === '') {
+ return '/'
+ }
+
+ // Preserve trailing slash for index routes (routePath ends with '/')
+ // This ensures types match runtime behavior
+ const isIndexRoute = routeNode.routePath?.endsWith('/')
+ if (isIndexRoute) {
+ return fullPath
+ }
+
+ return fullPath.replace(/\/$/, '')
+}
+
+const shouldPreferIndexRoute = (
+ current: RouteNode,
+ existing: RouteNode,
+): boolean => {
+ return existing.cleanedPath === '/' && current.cleanedPath !== '/'
}
/**
@@ -728,9 +747,22 @@ export const inferFullPath = (routeNode: RouteNode): string => {
export const createRouteNodesByFullPath = (
routeNodes: Array,
): Map => {
- return new Map(
- routeNodes.map((routeNode) => [inferFullPath(routeNode), routeNode]),
- )
+ const map = new Map()
+
+ for (const routeNode of routeNodes) {
+ const fullPath = inferFullPath(routeNode)
+
+ if (fullPath === '/' && map.has('/')) {
+ const existing = map.get('/')!
+ if (shouldPreferIndexRoute(routeNode, existing)) {
+ continue
+ }
+ }
+
+ map.set(fullPath, routeNode)
+ }
+
+ return map
}
/**
@@ -739,12 +771,22 @@ export const createRouteNodesByFullPath = (
export const createRouteNodesByTo = (
routeNodes: Array,
): Map => {
- return new Map(
- dedupeBranchesAndIndexRoutes(routeNodes).map((routeNode) => [
- inferTo(routeNode),
- routeNode,
- ]),
- )
+ const map = new Map()
+
+ for (const routeNode of dedupeBranchesAndIndexRoutes(routeNodes)) {
+ const to = inferTo(routeNode)
+
+ if (to === '/' && map.has('/')) {
+ const existing = map.get('/')!
+ if (shouldPreferIndexRoute(routeNode, existing)) {
+ continue
+ }
+ }
+
+ map.set(to, routeNode)
+ }
+
+ return map
}
/**
@@ -803,6 +845,15 @@ export function checkRouteFullPathUniqueness(
_routes: Array,
config: Config,
) {
+ const emptyPathRoutes = _routes.filter((d) => d.routePath === '')
+ if (emptyPathRoutes.length) {
+ const errorMessage = `Invalid route path "" was found. Root routes must be defined via __root.tsx (createRootRoute), not createFileRoute('') or a route file that resolves to an empty path.
+Conflicting files: \n ${emptyPathRoutes
+ .map((d) => path.resolve(config.routesDirectory, d.filePath))
+ .join('\n ')}\n`
+ throw new Error(errorMessage)
+ }
+
const routes = _routes.map((d) => {
const inferredFullPath = inferFullPath(d)
return { ...d, inferredFullPath }
diff --git a/packages/router-generator/tests/generator.test.ts b/packages/router-generator/tests/generator.test.ts
index 1fd787cda1e..485767e51aa 100644
--- a/packages/router-generator/tests/generator.test.ts
+++ b/packages/router-generator/tests/generator.test.ts
@@ -252,7 +252,7 @@ function shouldThrow(folderName: string) {
return `Conflicting configuration paths were found for the following routes: "/", "/".`
}
if (folderName === 'virtual-physical-empty-path-conflict-root') {
- return `Conflicting configuration paths were found for the following routes: "/__root", "/__root".`
+ return 'Invalid route path "" was found.'
}
if (folderName === 'virtual-physical-empty-path-conflict-virtual') {
return `Conflicting configuration paths were found for the following routes: "/about", "/about".`
diff --git a/packages/router-generator/tests/generator/custom-tokens/routeTree.snapshot.ts b/packages/router-generator/tests/generator/custom-tokens/routeTree.snapshot.ts
index c82afab07df..f49d059f202 100644
--- a/packages/router-generator/tests/generator/custom-tokens/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/custom-tokens/routeTree.snapshot.ts
@@ -67,7 +67,7 @@ export interface FileRoutesByFullPath {
'/blog/': typeof Blog1nd3xRoute
'/posts/': typeof Posts1nd3xRoute
'/posts/$postId/deep': typeof PostsPostIdDeepRoute
- '/posts/$postId': typeof PostsPostId1nd3xRoute
+ '/posts/$postId/': typeof PostsPostId1nd3xRoute
}
export interface FileRoutesByTo {
'/': typeof R1nd3xRoute
@@ -98,7 +98,7 @@ export interface FileRouteTypes {
| '/blog/'
| '/posts/'
| '/posts/$postId/deep'
- | '/posts/$postId'
+ | '/posts/$postId/'
fileRoutesByTo: FileRoutesByTo
to:
| '/'
@@ -172,7 +172,7 @@ declare module '@tanstack/react-router' {
'/posts/$postId/': {
id: '/posts/$postId/'
path: '/$postId'
- fullPath: '/posts/$postId'
+ fullPath: '/posts/$postId/'
preLoaderRoute: typeof PostsPostId1nd3xRouteImport
parentRoute: typeof PostsR0ut3Route
}
diff --git a/packages/router-generator/tests/generator/flat/routeTree.snapshot.ts b/packages/router-generator/tests/generator/flat/routeTree.snapshot.ts
index abfa5604c96..b1bf6587fcb 100644
--- a/packages/router-generator/tests/generator/flat/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/flat/routeTree.snapshot.ts
@@ -100,8 +100,8 @@ export interface FileRoutesByFullPath {
'/blog/$blogId/$slug': typeof BlogBlogIdSlugRouteRoute
'/blog/$blogId/edit': typeof BlogBlogIdEditRoute
'/posts/$postId/deep': typeof PostsPostIdDeepRoute
- '/blog/$slug': typeof BlogSlugIndexRoute
- '/posts/$postId': typeof PostsPostIdIndexRoute
+ '/blog/$slug/': typeof BlogSlugIndexRoute
+ '/posts/$postId/': typeof PostsPostIdIndexRoute
'/blog/$blogId/$slug/bar': typeof BlogBlogIdSlugBarRoute
}
export interface FileRoutesByTo {
@@ -146,8 +146,8 @@ export interface FileRouteTypes {
| '/blog/$blogId/$slug'
| '/blog/$blogId/edit'
| '/posts/$postId/deep'
- | '/blog/$slug'
- | '/posts/$postId'
+ | '/blog/$slug/'
+ | '/posts/$postId/'
| '/blog/$blogId/$slug/bar'
fileRoutesByTo: FileRoutesByTo
to:
@@ -242,14 +242,14 @@ declare module '@tanstack/react-router' {
'/posts/$postId/': {
id: '/posts/$postId/'
path: '/$postId'
- fullPath: '/posts/$postId'
+ fullPath: '/posts/$postId/'
preLoaderRoute: typeof PostsPostIdIndexRouteImport
parentRoute: typeof PostsRouteRoute
}
'/blog/$slug/': {
id: '/blog/$slug/'
path: '/$slug'
- fullPath: '/blog/$slug'
+ fullPath: '/blog/$slug/'
preLoaderRoute: typeof BlogSlugIndexRouteImport
parentRoute: typeof BlogRouteRoute
}
diff --git a/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts b/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts
index 6501b213ecc..c38345a64bf 100644
--- a/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/nested-layouts/routeTree.snapshot.ts
@@ -278,14 +278,14 @@ declare module '@tanstack/react-router' {
'/_layout-a2': {
id: '/_layout-a2'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof LayoutA2RouteImport
parentRoute: typeof rootRouteImport
}
'/_layout-a1': {
id: '/_layout-a1'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof LayoutA1RouteImport
parentRoute: typeof rootRouteImport
}
diff --git a/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routeTree.snapshot.ts b/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routeTree.snapshot.ts
index b7094626b90..ce5d831534c 100644
--- a/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routeTree.snapshot.ts
@@ -11,6 +11,7 @@
import type { CreateFileRoute, FileRoutesByPath } from '@tanstack/react-router'
import { Route as rootRouteImport } from './routes/__root'
+import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout'
import { Route as PostsRouteRouteImport } from './routes/posts/route'
import { Route as BlogRouteRouteImport } from './routes/blog/route'
import { Route as IndexRouteImport } from './routes/index'
@@ -18,6 +19,7 @@ import { Route as PostsIndexRouteImport } from './routes/posts/index'
import { Route as BlogIndexRouteImport } from './routes/blog/index'
import { Route as BlogStatsRouteImport } from './routes/blog_/stats'
import { Route as BlogSlugRouteImport } from './routes/blog/$slug'
+import { Route as PathlessLayoutSettingsRouteImport } from './routes/_pathlessLayout/settings'
import { Route as BlogBlogIdRouteRouteImport } from './routes/blog_/$blogId/route'
import { Route as PostsPostIdIndexRouteImport } from './routes/posts/$postId/index'
import { Route as PostsPostIdDeepRouteImport } from './routes/posts/$postId/deep'
@@ -25,6 +27,10 @@ import { Route as BlogBlogIdEditRouteImport } from './routes/blog_/$blogId_/edit
import { Route as BlogBlogIdSlugRouteRouteImport } from './routes/blog_/$blogId/$slug/route'
import { Route as BlogBlogIdSlugBarRouteImport } from './routes/blog_/$blogId/$slug_/bar'
+const PathlessLayoutRoute = PathlessLayoutRouteImport.update({
+ id: '/_pathlessLayout',
+ getParentRoute: () => rootRouteImport,
+} as any)
const PostsRouteRoute = PostsRouteRouteImport.update({
id: '/posts',
path: '/posts',
@@ -60,6 +66,11 @@ const BlogSlugRoute = BlogSlugRouteImport.update({
path: '/$slug',
getParentRoute: () => BlogRouteRoute,
} as any)
+const PathlessLayoutSettingsRoute = PathlessLayoutSettingsRouteImport.update({
+ id: '/settings',
+ path: '/settings',
+ getParentRoute: () => PathlessLayoutRoute,
+} as any)
const BlogBlogIdRouteRoute = BlogBlogIdRouteRouteImport.update({
id: '/blog_/$blogId',
path: '/blog/$blogId',
@@ -96,6 +107,7 @@ export interface FileRoutesByFullPath {
'/blog': typeof BlogRouteRouteWithChildren
'/posts': typeof PostsRouteRouteWithChildren
'/blog/$blogId': typeof BlogBlogIdRouteRouteWithChildren
+ '/settings': typeof PathlessLayoutSettingsRoute
'/blog/$slug': typeof BlogSlugRoute
'/blog/stats': typeof BlogStatsRoute
'/blog/': typeof BlogIndexRoute
@@ -103,12 +115,13 @@ export interface FileRoutesByFullPath {
'/blog/$blogId/$slug': typeof BlogBlogIdSlugRouteRoute
'/blog/$blogId/edit': typeof BlogBlogIdEditRoute
'/posts/$postId/deep': typeof PostsPostIdDeepRoute
- '/posts/$postId': typeof PostsPostIdIndexRoute
+ '/posts/$postId/': typeof PostsPostIdIndexRoute
'/blog/$blogId/$slug/bar': typeof BlogBlogIdSlugBarRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/blog/$blogId': typeof BlogBlogIdRouteRouteWithChildren
+ '/settings': typeof PathlessLayoutSettingsRoute
'/blog/$slug': typeof BlogSlugRoute
'/blog/stats': typeof BlogStatsRoute
'/blog': typeof BlogIndexRoute
@@ -124,7 +137,9 @@ export interface FileRoutesById {
'/': typeof IndexRoute
'/blog': typeof BlogRouteRouteWithChildren
'/posts': typeof PostsRouteRouteWithChildren
+ '/_pathlessLayout': typeof PathlessLayoutRouteWithChildren
'/blog_/$blogId': typeof BlogBlogIdRouteRouteWithChildren
+ '/_pathlessLayout/settings': typeof PathlessLayoutSettingsRoute
'/blog/$slug': typeof BlogSlugRoute
'/blog_/stats': typeof BlogStatsRoute
'/blog/': typeof BlogIndexRoute
@@ -142,6 +157,7 @@ export interface FileRouteTypes {
| '/blog'
| '/posts'
| '/blog/$blogId'
+ | '/settings'
| '/blog/$slug'
| '/blog/stats'
| '/blog/'
@@ -149,12 +165,13 @@ export interface FileRouteTypes {
| '/blog/$blogId/$slug'
| '/blog/$blogId/edit'
| '/posts/$postId/deep'
- | '/posts/$postId'
+ | '/posts/$postId/'
| '/blog/$blogId/$slug/bar'
fileRoutesByTo: FileRoutesByTo
to:
| '/'
| '/blog/$blogId'
+ | '/settings'
| '/blog/$slug'
| '/blog/stats'
| '/blog'
@@ -169,7 +186,9 @@ export interface FileRouteTypes {
| '/'
| '/blog'
| '/posts'
+ | '/_pathlessLayout'
| '/blog_/$blogId'
+ | '/_pathlessLayout/settings'
| '/blog/$slug'
| '/blog_/stats'
| '/blog/'
@@ -185,6 +204,7 @@ export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
BlogRouteRoute: typeof BlogRouteRouteWithChildren
PostsRouteRoute: typeof PostsRouteRouteWithChildren
+ PathlessLayoutRoute: typeof PathlessLayoutRouteWithChildren
BlogBlogIdRouteRoute: typeof BlogBlogIdRouteRouteWithChildren
BlogStatsRoute: typeof BlogStatsRoute
BlogBlogIdEditRoute: typeof BlogBlogIdEditRoute
@@ -192,6 +212,13 @@ export interface RootRouteChildren {
declare module '@tanstack/react-router' {
interface FileRoutesByPath {
+ '/_pathlessLayout': {
+ id: '/_pathlessLayout'
+ path: ''
+ fullPath: '/'
+ preLoaderRoute: typeof PathlessLayoutRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/posts': {
id: '/posts'
path: '/posts'
@@ -241,6 +268,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof BlogSlugRouteImport
parentRoute: typeof BlogRouteRoute
}
+ '/_pathlessLayout/settings': {
+ id: '/_pathlessLayout/settings'
+ path: '/settings'
+ fullPath: '/settings'
+ preLoaderRoute: typeof PathlessLayoutSettingsRouteImport
+ parentRoute: typeof PathlessLayoutRoute
+ }
'/blog_/$blogId': {
id: '/blog_/$blogId'
path: '/blog/$blogId'
@@ -251,7 +285,7 @@ declare module '@tanstack/react-router' {
'/posts/$postId/': {
id: '/posts/$postId/'
path: '/$postId'
- fullPath: '/posts/$postId'
+ fullPath: '/posts/$postId/'
preLoaderRoute: typeof PostsPostIdIndexRouteImport
parentRoute: typeof PostsRouteRoute
}
@@ -313,6 +347,15 @@ declare module './routes/posts/route' {
FileRoutesByPath['/posts']['fullPath']
>
}
+declare module './routes/_pathlessLayout' {
+ const createFileRoute: CreateFileRoute<
+ '/_pathlessLayout',
+ FileRoutesByPath['/_pathlessLayout']['parentRoute'],
+ FileRoutesByPath['/_pathlessLayout']['id'],
+ FileRoutesByPath['/_pathlessLayout']['path'],
+ FileRoutesByPath['/_pathlessLayout']['fullPath']
+ >
+}
declare module './routes/blog_/$blogId/route' {
const createFileRoute: CreateFileRoute<
'/blog_/$blogId',
@@ -322,6 +365,15 @@ declare module './routes/blog_/$blogId/route' {
FileRoutesByPath['/blog_/$blogId']['fullPath']
>
}
+declare module './routes/_pathlessLayout/settings' {
+ const createFileRoute: CreateFileRoute<
+ '/_pathlessLayout/settings',
+ FileRoutesByPath['/_pathlessLayout/settings']['parentRoute'],
+ FileRoutesByPath['/_pathlessLayout/settings']['id'],
+ FileRoutesByPath['/_pathlessLayout/settings']['path'],
+ FileRoutesByPath['/_pathlessLayout/settings']['fullPath']
+ >
+}
declare module './routes/blog/$slug' {
const createFileRoute: CreateFileRoute<
'/blog/$slug',
@@ -434,6 +486,18 @@ const PostsRouteRouteWithChildren = PostsRouteRoute._addFileChildren(
PostsRouteRouteChildren,
)
+interface PathlessLayoutRouteChildren {
+ PathlessLayoutSettingsRoute: typeof PathlessLayoutSettingsRoute
+}
+
+const PathlessLayoutRouteChildren: PathlessLayoutRouteChildren = {
+ PathlessLayoutSettingsRoute: PathlessLayoutSettingsRoute,
+}
+
+const PathlessLayoutRouteWithChildren = PathlessLayoutRoute._addFileChildren(
+ PathlessLayoutRouteChildren,
+)
+
interface BlogBlogIdRouteRouteChildren {
BlogBlogIdSlugRouteRoute: typeof BlogBlogIdSlugRouteRoute
BlogBlogIdSlugBarRoute: typeof BlogBlogIdSlugBarRoute
@@ -452,6 +516,7 @@ const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
BlogRouteRoute: BlogRouteRouteWithChildren,
PostsRouteRoute: PostsRouteRouteWithChildren,
+ PathlessLayoutRoute: PathlessLayoutRouteWithChildren,
BlogBlogIdRouteRoute: BlogBlogIdRouteRouteWithChildren,
BlogStatsRoute: BlogStatsRoute,
BlogBlogIdEditRoute: BlogBlogIdEditRoute,
diff --git a/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routes/_pathlessLayout.tsx b/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routes/_pathlessLayout.tsx
new file mode 100644
index 00000000000..ae38370b806
--- /dev/null
+++ b/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routes/_pathlessLayout.tsx
@@ -0,0 +1,4 @@
+import { Outlet } from '@tanstack/react-router'
+export const Route = createFileRoute({
+ component: () => ,
+})
diff --git a/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routes/_pathlessLayout/settings.tsx b/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routes/_pathlessLayout/settings.tsx
new file mode 100644
index 00000000000..b2a1f1a950d
--- /dev/null
+++ b/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/routes/_pathlessLayout/settings.tsx
@@ -0,0 +1,3 @@
+export const Route = createFileRoute({
+ component: () => Settings
,
+})
diff --git a/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/tests.test-d.ts b/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/tests.test-d.ts
index adfb3ae535e..47dcc0f5b1e 100644
--- a/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/tests.test-d.ts
+++ b/packages/router-generator/tests/generator/nested-verboseFileRoutes-false/tests.test-d.ts
@@ -10,9 +10,10 @@ import {
useRouteContext,
useSearch,
} from '@tanstack/react-router'
+import type { FileRoutesByPath, MakeRouteMatch } from '@tanstack/react-router'
import { expectTypeOf, test } from 'vitest'
import { routeTree } from './routeTree.gen'
-import type { MakeRouteMatch } from '@tanstack/react-router'
+import type { FileRouteTypes } from './routeTree.gen'
const defaultRouter = createRouter({
routeTree,
@@ -36,6 +37,29 @@ const preserveTrailingSlashRouter = createRouter({
})
test('when navigating to the root', () => {
+ // Issue #4892: Pathless layout routes should have fullPath: '/' not ''
+ expectTypeOf().toEqualTypeOf<'/'>()
+ expectTypeOf<
+ FileRoutesByPath['/posts/']['fullPath']
+ >().toEqualTypeOf<'/posts/'>()
+ // Issue #6403: Index routes should have trailing slash in fullPath to match runtime
+ expectTypeOf<
+ FileRoutesByPath['/posts/$postId/']['fullPath']
+ >().toEqualTypeOf<'/posts/$postId/'>()
+ expectTypeOf<
+ FileRoutesByPath['/blog/']['fullPath']
+ >().toEqualTypeOf<'/blog/'>()
+ // Verify empty string is not in fullPaths union
+ expectTypeOf<''>().not.toMatchTypeOf()
+ // Verify pathless layout's fullPath is '/' (not '')
+ expectTypeOf<
+ FileRoutesByPath['/_pathlessLayout']['fullPath']
+ >().toEqualTypeOf<'/'>()
+ // Child of pathless layout should have correct fullPath
+ expectTypeOf<
+ FileRoutesByPath['/_pathlessLayout/settings']['fullPath']
+ >().toEqualTypeOf<'/settings'>()
+
expectTypeOf(Link)
.parameter(0)
.toHaveProperty('to')
@@ -51,6 +75,7 @@ test('when navigating to the root', () => {
| '/blog/stats'
| '/posts/$postId/deep'
| '/posts/$postId'
+ | '/settings'
| undefined
>()
@@ -69,6 +94,7 @@ test('when navigating to the root', () => {
| '/blog/stats/'
| '/posts/$postId/deep/'
| '/posts/$postId/'
+ | '/settings/'
| undefined
>()
@@ -87,6 +113,7 @@ test('when navigating to the root', () => {
| '/blog/stats'
| '/posts/$postId/deep'
| '/posts/$postId'
+ | '/settings'
| undefined
>()
@@ -115,6 +142,8 @@ test('when navigating to the root', () => {
| '/blog/stats/'
| '/posts/$postId/deep/'
| '/posts/$postId/'
+ | '/settings/'
+ | '/settings'
| undefined
>()
@@ -134,7 +163,8 @@ test('when navigating to the root', () => {
| '/blog/'
| '/posts/'
| '/posts/$postId/deep'
- | '/posts/$postId'
+ | '/posts/$postId/'
+ | '/settings'
| undefined
>()
@@ -181,6 +211,7 @@ test('when navigating a index route with search and params', () => {
| '/blog/stats'
| '/posts/$postId/deep'
| '/posts/$postId'
+ | '/settings'
>()
expectTypeOf(
@@ -202,6 +233,7 @@ test('when navigating a index route with search and params', () => {
| '/blog/stats/'
| '/posts/$postId/deep/'
| '/posts/$postId/'
+ | '/settings/'
>()
expectTypeOf(Link)
@@ -219,6 +251,7 @@ test('when navigating a index route with search and params', () => {
| '/blog/stats'
| '/posts/$postId/deep'
| '/posts/$postId'
+ | '/settings'
| '.'
| '..'
>()
@@ -254,6 +287,8 @@ test('when navigating a index route with search and params', () => {
| '/blog/stats/'
| '/posts/$postId/deep/'
| '/posts/$postId/'
+ | '/settings'
+ | '/settings/'
>()
expectTypeOf(Link)
@@ -261,7 +296,7 @@ test('when navigating a index route with search and params', () => {
.toHaveProperty('from')
.toEqualTypeOf<
| '/'
- | '/posts/$postId'
+ | '/posts/$postId/'
| '/blog'
| '/posts'
| '/blog/$blogId'
@@ -273,6 +308,7 @@ test('when navigating a index route with search and params', () => {
| '/blog/'
| '/posts/'
| '/posts/$postId/deep'
+ | '/settings'
| undefined
>()
@@ -366,12 +402,12 @@ test('when navigating a index route with search and params', () => {
})
test('when navigating from a index route with search and params', () => {
- expectTypeOf(Link)
+ expectTypeOf(Link)
.parameter(0)
.toHaveProperty('from')
.toEqualTypeOf<
| '/'
- | '/posts/$postId'
+ | '/posts/$postId/'
| '/blog'
| '/posts'
| '/blog/$blogId'
@@ -383,10 +419,11 @@ test('when navigating from a index route with search and params', () => {
| '/blog/'
| '/posts/'
| '/posts/$postId/deep'
+ | '/settings'
| undefined
>()
- expectTypeOf(Link)
+ expectTypeOf(Link)
.parameter(0)
.toHaveProperty('search')
.parameter(0)
@@ -413,6 +450,7 @@ test('when using useNavigate', () => {
| '/blog/stats'
| '/posts/$postId/deep'
| '/posts/$postId'
+ | '/settings'
>()
})
@@ -432,6 +470,7 @@ test('when using redirect', () => {
| '/blog/$slug'
| '/blog/stats'
| '/posts/$postId/deep'
+ | '/settings'
| undefined
>()
})
@@ -444,7 +483,6 @@ test('when using useSearch from a route with no search', () => {
| '__root__'
| '/'
| '/blog'
- | '/blog/'
| '/posts'
| '/blog/$slug'
| '/blog_/$blogId'
@@ -452,9 +490,12 @@ test('when using useSearch from a route with no search', () => {
| '/blog_/$blogId/$slug'
| '/blog_/$blogId/$slug_/bar'
| '/blog_/stats'
+ | '/blog/'
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(useSearch).returns.toEqualTypeOf<{}>()
@@ -468,7 +509,6 @@ test('when using useSearch from a route with search', () => {
| '__root__'
| '/'
| '/blog'
- | '/blog/'
| '/posts'
| '/blog/$slug'
| '/blog_/$blogId'
@@ -476,9 +516,12 @@ test('when using useSearch from a route with search', () => {
| '/blog_/$blogId/$slug'
| '/blog_/$blogId/$slug_/bar'
| '/blog_/stats'
+ | '/blog/'
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(
@@ -494,17 +537,19 @@ test('when using useLoaderData from a route with loaderData', () => {
| '__root__'
| '/'
| '/blog'
- | '/blog/'
| '/posts'
+ | '/blog/$slug'
| '/blog_/$blogId'
| '/blog_/$blogId_/edit'
| '/blog_/$blogId/$slug'
| '/blog_/$blogId/$slug_/bar'
- | '/blog/$slug'
| '/blog_/stats'
+ | '/blog/'
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(
@@ -520,7 +565,6 @@ test('when using useLoaderDeps from a route with loaderDeps', () => {
| '__root__'
| '/'
| '/blog'
- | '/blog/'
| '/posts'
| '/blog/$slug'
| '/blog_/$blogId'
@@ -528,9 +572,12 @@ test('when using useLoaderDeps from a route with loaderDeps', () => {
| '/blog_/$blogId/$slug'
| '/blog_/$blogId/$slug_/bar'
| '/blog_/stats'
+ | '/blog/'
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(
@@ -546,7 +593,6 @@ test('when using useMatch from a route', () => {
| '__root__'
| '/'
| '/blog'
- | '/blog/'
| '/posts'
| '/blog/$slug'
| '/blog_/$blogId'
@@ -554,9 +600,12 @@ test('when using useMatch from a route', () => {
| '/blog_/$blogId/$slug'
| '/blog_/$blogId/$slug_/bar'
| '/blog_/stats'
+ | '/blog/'
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(
@@ -574,7 +623,6 @@ test('when using useParams from a route', () => {
| '__root__'
| '/'
| '/blog'
- | '/blog/'
| '/posts'
| '/blog/$slug'
| '/blog_/$blogId'
@@ -582,9 +630,12 @@ test('when using useParams from a route', () => {
| '/blog_/$blogId/$slug'
| '/blog_/$blogId/$slug_/bar'
| '/blog_/stats'
+ | '/blog/'
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(
@@ -600,7 +651,6 @@ test('when using useRouteContext from a route', () => {
| '__root__'
| '/'
| '/blog'
- | '/blog/'
| '/posts'
| '/blog/$slug'
| '/blog_/$blogId'
@@ -608,9 +658,12 @@ test('when using useRouteContext from a route', () => {
| '/blog_/$blogId/$slug'
| '/blog_/$blogId/$slug_/bar'
| '/blog_/stats'
+ | '/blog/'
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(
diff --git a/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routeTree.snapshot.ts b/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routeTree.snapshot.ts
index 3cb8036f7c3..9a87dd69538 100644
--- a/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routeTree.snapshot.ts
@@ -9,6 +9,7 @@
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
import { Route as rootRouteImport } from './routes/__root'
+import { Route as PathlessLayoutRouteImport } from './routes/_pathlessLayout'
import { Route as PostsRouteRouteImport } from './routes/posts/route'
import { Route as BlogRouteRouteImport } from './routes/blog/route'
import { Route as IndexRouteImport } from './routes/index'
@@ -16,6 +17,7 @@ import { Route as PostsIndexRouteImport } from './routes/posts/index'
import { Route as BlogIndexRouteImport } from './routes/blog/index'
import { Route as BlogStatsRouteImport } from './routes/blog_/stats'
import { Route as BlogSlugRouteImport } from './routes/blog/$slug'
+import { Route as PathlessLayoutSettingsRouteImport } from './routes/_pathlessLayout/settings'
import { Route as BlogBlogIdRouteRouteImport } from './routes/blog_/$blogId/route'
import { Route as PostsPostIdIndexRouteImport } from './routes/posts/$postId/index'
import { Route as PostsPostIdDeepRouteImport } from './routes/posts/$postId/deep'
@@ -23,6 +25,10 @@ import { Route as BlogBlogIdEditRouteImport } from './routes/blog_/$blogId_/edit
import { Route as BlogBlogIdSlugRouteRouteImport } from './routes/blog_/$blogId/$slug/route'
import { Route as BlogBlogIdSlugBarRouteImport } from './routes/blog_/$blogId/$slug_/bar'
+const PathlessLayoutRoute = PathlessLayoutRouteImport.update({
+ id: '/_pathlessLayout',
+ getParentRoute: () => rootRouteImport,
+} as any)
const PostsRouteRoute = PostsRouteRouteImport.update({
id: '/posts',
path: '/posts',
@@ -58,6 +64,11 @@ const BlogSlugRoute = BlogSlugRouteImport.update({
path: '/$slug',
getParentRoute: () => BlogRouteRoute,
} as any)
+const PathlessLayoutSettingsRoute = PathlessLayoutSettingsRouteImport.update({
+ id: '/settings',
+ path: '/settings',
+ getParentRoute: () => PathlessLayoutRoute,
+} as any)
const BlogBlogIdRouteRoute = BlogBlogIdRouteRouteImport.update({
id: '/blog_/$blogId',
path: '/blog/$blogId',
@@ -94,6 +105,7 @@ export interface FileRoutesByFullPath {
'/blog': typeof BlogRouteRouteWithChildren
'/posts': typeof PostsRouteRouteWithChildren
'/blog/$blogId': typeof BlogBlogIdRouteRouteWithChildren
+ '/settings': typeof PathlessLayoutSettingsRoute
'/blog/$slug': typeof BlogSlugRoute
'/blog/stats': typeof BlogStatsRoute
'/blog/': typeof BlogIndexRoute
@@ -101,12 +113,13 @@ export interface FileRoutesByFullPath {
'/blog/$blogId/$slug': typeof BlogBlogIdSlugRouteRoute
'/blog/$blogId/edit': typeof BlogBlogIdEditRoute
'/posts/$postId/deep': typeof PostsPostIdDeepRoute
- '/posts/$postId': typeof PostsPostIdIndexRoute
+ '/posts/$postId/': typeof PostsPostIdIndexRoute
'/blog/$blogId/$slug/bar': typeof BlogBlogIdSlugBarRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/blog/$blogId': typeof BlogBlogIdRouteRouteWithChildren
+ '/settings': typeof PathlessLayoutSettingsRoute
'/blog/$slug': typeof BlogSlugRoute
'/blog/stats': typeof BlogStatsRoute
'/blog': typeof BlogIndexRoute
@@ -122,7 +135,9 @@ export interface FileRoutesById {
'/': typeof IndexRoute
'/blog': typeof BlogRouteRouteWithChildren
'/posts': typeof PostsRouteRouteWithChildren
+ '/_pathlessLayout': typeof PathlessLayoutRouteWithChildren
'/blog_/$blogId': typeof BlogBlogIdRouteRouteWithChildren
+ '/_pathlessLayout/settings': typeof PathlessLayoutSettingsRoute
'/blog/$slug': typeof BlogSlugRoute
'/blog_/stats': typeof BlogStatsRoute
'/blog/': typeof BlogIndexRoute
@@ -140,6 +155,7 @@ export interface FileRouteTypes {
| '/blog'
| '/posts'
| '/blog/$blogId'
+ | '/settings'
| '/blog/$slug'
| '/blog/stats'
| '/blog/'
@@ -147,12 +163,13 @@ export interface FileRouteTypes {
| '/blog/$blogId/$slug'
| '/blog/$blogId/edit'
| '/posts/$postId/deep'
- | '/posts/$postId'
+ | '/posts/$postId/'
| '/blog/$blogId/$slug/bar'
fileRoutesByTo: FileRoutesByTo
to:
| '/'
| '/blog/$blogId'
+ | '/settings'
| '/blog/$slug'
| '/blog/stats'
| '/blog'
@@ -167,7 +184,9 @@ export interface FileRouteTypes {
| '/'
| '/blog'
| '/posts'
+ | '/_pathlessLayout'
| '/blog_/$blogId'
+ | '/_pathlessLayout/settings'
| '/blog/$slug'
| '/blog_/stats'
| '/blog/'
@@ -183,6 +202,7 @@ export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
BlogRouteRoute: typeof BlogRouteRouteWithChildren
PostsRouteRoute: typeof PostsRouteRouteWithChildren
+ PathlessLayoutRoute: typeof PathlessLayoutRouteWithChildren
BlogBlogIdRouteRoute: typeof BlogBlogIdRouteRouteWithChildren
BlogStatsRoute: typeof BlogStatsRoute
BlogBlogIdEditRoute: typeof BlogBlogIdEditRoute
@@ -190,6 +210,13 @@ export interface RootRouteChildren {
declare module '@tanstack/react-router' {
interface FileRoutesByPath {
+ '/_pathlessLayout': {
+ id: '/_pathlessLayout'
+ path: ''
+ fullPath: '/'
+ preLoaderRoute: typeof PathlessLayoutRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/posts': {
id: '/posts'
path: '/posts'
@@ -239,6 +266,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof BlogSlugRouteImport
parentRoute: typeof BlogRouteRoute
}
+ '/_pathlessLayout/settings': {
+ id: '/_pathlessLayout/settings'
+ path: '/settings'
+ fullPath: '/settings'
+ preLoaderRoute: typeof PathlessLayoutSettingsRouteImport
+ parentRoute: typeof PathlessLayoutRoute
+ }
'/blog_/$blogId': {
id: '/blog_/$blogId'
path: '/blog/$blogId'
@@ -249,7 +283,7 @@ declare module '@tanstack/react-router' {
'/posts/$postId/': {
id: '/posts/$postId/'
path: '/$postId'
- fullPath: '/posts/$postId'
+ fullPath: '/posts/$postId/'
preLoaderRoute: typeof PostsPostIdIndexRouteImport
parentRoute: typeof PostsRouteRoute
}
@@ -314,6 +348,18 @@ const PostsRouteRouteWithChildren = PostsRouteRoute._addFileChildren(
PostsRouteRouteChildren,
)
+interface PathlessLayoutRouteChildren {
+ PathlessLayoutSettingsRoute: typeof PathlessLayoutSettingsRoute
+}
+
+const PathlessLayoutRouteChildren: PathlessLayoutRouteChildren = {
+ PathlessLayoutSettingsRoute: PathlessLayoutSettingsRoute,
+}
+
+const PathlessLayoutRouteWithChildren = PathlessLayoutRoute._addFileChildren(
+ PathlessLayoutRouteChildren,
+)
+
interface BlogBlogIdRouteRouteChildren {
BlogBlogIdSlugRouteRoute: typeof BlogBlogIdSlugRouteRoute
BlogBlogIdSlugBarRoute: typeof BlogBlogIdSlugBarRoute
@@ -332,6 +378,7 @@ const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
BlogRouteRoute: BlogRouteRouteWithChildren,
PostsRouteRoute: PostsRouteRouteWithChildren,
+ PathlessLayoutRoute: PathlessLayoutRouteWithChildren,
BlogBlogIdRouteRoute: BlogBlogIdRouteRouteWithChildren,
BlogStatsRoute: BlogStatsRoute,
BlogBlogIdEditRoute: BlogBlogIdEditRoute,
diff --git a/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routes/_pathlessLayout.tsx b/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routes/_pathlessLayout.tsx
new file mode 100644
index 00000000000..714f9def3e6
--- /dev/null
+++ b/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routes/_pathlessLayout.tsx
@@ -0,0 +1,4 @@
+import { createFileRoute, Outlet } from '@tanstack/react-router'
+export const Route = createFileRoute('/_pathlessLayout')({
+ component: () => ,
+})
diff --git a/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routes/_pathlessLayout/settings.tsx b/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routes/_pathlessLayout/settings.tsx
new file mode 100644
index 00000000000..b687c8c8c9b
--- /dev/null
+++ b/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/routes/_pathlessLayout/settings.tsx
@@ -0,0 +1,4 @@
+import { createFileRoute } from '@tanstack/react-router'
+export const Route = createFileRoute('/_pathlessLayout/settings')({
+ component: () => Settings
,
+})
diff --git a/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/tests.test-d.ts b/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/tests.test-d.ts
index 2e991843d59..47dcc0f5b1e 100644
--- a/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/tests.test-d.ts
+++ b/packages/router-generator/tests/generator/nested-verboseFileRoutes-true/tests.test-d.ts
@@ -10,9 +10,10 @@ import {
useRouteContext,
useSearch,
} from '@tanstack/react-router'
+import type { FileRoutesByPath, MakeRouteMatch } from '@tanstack/react-router'
import { expectTypeOf, test } from 'vitest'
import { routeTree } from './routeTree.gen'
-import type { MakeRouteMatch } from '@tanstack/react-router'
+import type { FileRouteTypes } from './routeTree.gen'
const defaultRouter = createRouter({
routeTree,
@@ -36,6 +37,29 @@ const preserveTrailingSlashRouter = createRouter({
})
test('when navigating to the root', () => {
+ // Issue #4892: Pathless layout routes should have fullPath: '/' not ''
+ expectTypeOf().toEqualTypeOf<'/'>()
+ expectTypeOf<
+ FileRoutesByPath['/posts/']['fullPath']
+ >().toEqualTypeOf<'/posts/'>()
+ // Issue #6403: Index routes should have trailing slash in fullPath to match runtime
+ expectTypeOf<
+ FileRoutesByPath['/posts/$postId/']['fullPath']
+ >().toEqualTypeOf<'/posts/$postId/'>()
+ expectTypeOf<
+ FileRoutesByPath['/blog/']['fullPath']
+ >().toEqualTypeOf<'/blog/'>()
+ // Verify empty string is not in fullPaths union
+ expectTypeOf<''>().not.toMatchTypeOf()
+ // Verify pathless layout's fullPath is '/' (not '')
+ expectTypeOf<
+ FileRoutesByPath['/_pathlessLayout']['fullPath']
+ >().toEqualTypeOf<'/'>()
+ // Child of pathless layout should have correct fullPath
+ expectTypeOf<
+ FileRoutesByPath['/_pathlessLayout/settings']['fullPath']
+ >().toEqualTypeOf<'/settings'>()
+
expectTypeOf(Link)
.parameter(0)
.toHaveProperty('to')
@@ -51,6 +75,7 @@ test('when navigating to the root', () => {
| '/blog/stats'
| '/posts/$postId/deep'
| '/posts/$postId'
+ | '/settings'
| undefined
>()
@@ -69,6 +94,7 @@ test('when navigating to the root', () => {
| '/blog/stats/'
| '/posts/$postId/deep/'
| '/posts/$postId/'
+ | '/settings/'
| undefined
>()
@@ -87,6 +113,7 @@ test('when navigating to the root', () => {
| '/blog/stats'
| '/posts/$postId/deep'
| '/posts/$postId'
+ | '/settings'
| undefined
>()
@@ -115,6 +142,8 @@ test('when navigating to the root', () => {
| '/blog/stats/'
| '/posts/$postId/deep/'
| '/posts/$postId/'
+ | '/settings/'
+ | '/settings'
| undefined
>()
@@ -134,7 +163,8 @@ test('when navigating to the root', () => {
| '/blog/'
| '/posts/'
| '/posts/$postId/deep'
- | '/posts/$postId'
+ | '/posts/$postId/'
+ | '/settings'
| undefined
>()
@@ -181,6 +211,7 @@ test('when navigating a index route with search and params', () => {
| '/blog/stats'
| '/posts/$postId/deep'
| '/posts/$postId'
+ | '/settings'
>()
expectTypeOf(
@@ -202,6 +233,7 @@ test('when navigating a index route with search and params', () => {
| '/blog/stats/'
| '/posts/$postId/deep/'
| '/posts/$postId/'
+ | '/settings/'
>()
expectTypeOf(Link)
@@ -219,6 +251,7 @@ test('when navigating a index route with search and params', () => {
| '/blog/stats'
| '/posts/$postId/deep'
| '/posts/$postId'
+ | '/settings'
| '.'
| '..'
>()
@@ -254,6 +287,8 @@ test('when navigating a index route with search and params', () => {
| '/blog/stats/'
| '/posts/$postId/deep/'
| '/posts/$postId/'
+ | '/settings'
+ | '/settings/'
>()
expectTypeOf(Link)
@@ -261,7 +296,7 @@ test('when navigating a index route with search and params', () => {
.toHaveProperty('from')
.toEqualTypeOf<
| '/'
- | '/posts/$postId'
+ | '/posts/$postId/'
| '/blog'
| '/posts'
| '/blog/$blogId'
@@ -273,6 +308,7 @@ test('when navigating a index route with search and params', () => {
| '/blog/'
| '/posts/'
| '/posts/$postId/deep'
+ | '/settings'
| undefined
>()
@@ -366,12 +402,12 @@ test('when navigating a index route with search and params', () => {
})
test('when navigating from a index route with search and params', () => {
- expectTypeOf(Link)
+ expectTypeOf(Link)
.parameter(0)
.toHaveProperty('from')
.toEqualTypeOf<
| '/'
- | '/posts/$postId'
+ | '/posts/$postId/'
| '/blog'
| '/posts'
| '/blog/$blogId'
@@ -383,10 +419,11 @@ test('when navigating from a index route with search and params', () => {
| '/blog/'
| '/posts/'
| '/posts/$postId/deep'
+ | '/settings'
| undefined
>()
- expectTypeOf(Link)
+ expectTypeOf(Link)
.parameter(0)
.toHaveProperty('search')
.parameter(0)
@@ -413,6 +450,7 @@ test('when using useNavigate', () => {
| '/blog/stats'
| '/posts/$postId/deep'
| '/posts/$postId'
+ | '/settings'
>()
})
@@ -432,6 +470,7 @@ test('when using redirect', () => {
| '/blog/$slug'
| '/blog/stats'
| '/posts/$postId/deep'
+ | '/settings'
| undefined
>()
})
@@ -455,6 +494,8 @@ test('when using useSearch from a route with no search', () => {
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(useSearch).returns.toEqualTypeOf<{}>()
@@ -479,6 +520,8 @@ test('when using useSearch from a route with search', () => {
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(
@@ -505,6 +548,8 @@ test('when using useLoaderData from a route with loaderData', () => {
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(
@@ -531,6 +576,8 @@ test('when using useLoaderDeps from a route with loaderDeps', () => {
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(
@@ -557,6 +604,8 @@ test('when using useMatch from a route', () => {
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(
@@ -585,6 +634,8 @@ test('when using useParams from a route', () => {
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(
@@ -611,6 +662,8 @@ test('when using useRouteContext from a route', () => {
| '/posts/'
| '/posts/$postId/deep'
| '/posts/$postId/'
+ | '/_pathlessLayout'
+ | '/_pathlessLayout/settings'
>()
expectTypeOf(
diff --git a/packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.snapshot.ts b/packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.snapshot.ts
index e4f872ce3a9..b2ff9737650 100644
--- a/packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/no-formatted-route-tree/routeTree.snapshot.ts
@@ -24,7 +24,7 @@ const NestedChildRoute = NestedChildRouteImport.update({
}as any)
export interface FileRoutesByFullPath {
-'/': typeof IndexRoute,'/nested/child': typeof NestedChildRoute,'/nested': typeof NestedIndexRoute
+'/': typeof IndexRoute,'/nested/child': typeof NestedChildRoute,'/nested/': typeof NestedIndexRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute,'/nested/child': typeof NestedChildRoute,'/nested': typeof NestedIndexRoute
@@ -35,7 +35,7 @@ export interface FileRoutesById {
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
-fullPaths: '/'|'/nested/child'|'/nested'
+fullPaths: '/'|'/nested/child'|'/nested/'
fileRoutesByTo: FileRoutesByTo
to: '/'|'/nested/child'|'/nested'
id: '__root__'|'/'|'/nested/child'|'/nested/'
@@ -57,7 +57,7 @@ declare module '@tanstack/react-router' {
'/nested/': {
id: '/nested/'
path: '/nested'
- fullPath: '/nested'
+ fullPath: '/nested/'
preLoaderRoute: typeof NestedIndexRouteImport
parentRoute: typeof rootRouteImport
}
diff --git a/packages/router-generator/tests/generator/numbers-in-path/routeTree.snapshot.ts b/packages/router-generator/tests/generator/numbers-in-path/routeTree.snapshot.ts
index 754b730b7ae..76af9354014 100644
--- a/packages/router-generator/tests/generator/numbers-in-path/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/numbers-in-path/routeTree.snapshot.ts
@@ -45,8 +45,8 @@ export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/03': typeof R03Route
'/about': typeof AboutRoute
- '/01-example': typeof R01ExampleIndexRoute
- '/02': typeof R02IndexRoute
+ '/01-example/': typeof R01ExampleIndexRoute
+ '/02/': typeof R02IndexRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
@@ -65,7 +65,7 @@ export interface FileRoutesById {
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
- fullPaths: '/' | '/03' | '/about' | '/01-example' | '/02'
+ fullPaths: '/' | '/03' | '/about' | '/01-example/' | '/02/'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/03' | '/about' | '/01-example' | '/02'
id: '__root__' | '/' | '/03' | '/about' | '/01-example/' | '/02/'
@@ -105,14 +105,14 @@ declare module '@tanstack/react-router' {
'/02/': {
id: '/02/'
path: '/02'
- fullPath: '/02'
+ fullPath: '/02/'
preLoaderRoute: typeof R02IndexRouteImport
parentRoute: typeof rootRouteImport
}
'/01-example/': {
id: '/01-example/'
path: '/01-example'
- fullPath: '/01-example'
+ fullPath: '/01-example/'
preLoaderRoute: typeof R01ExampleIndexRouteImport
parentRoute: typeof rootRouteImport
}
diff --git a/packages/router-generator/tests/generator/path-above-route-in-group/routeTree.snapshot.ts b/packages/router-generator/tests/generator/path-above-route-in-group/routeTree.snapshot.ts
index c937f95ba87..1a8ad18a103 100644
--- a/packages/router-generator/tests/generator/path-above-route-in-group/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/path-above-route-in-group/routeTree.snapshot.ts
@@ -32,7 +32,7 @@ const ABcDEIndexRoute = ABcDEIndexRouteImport.update({
export interface FileRoutesByFullPath {
'/a/$b': typeof ABcRouteRouteWithChildren
'/a/$b/': typeof ABcIndexRoute
- '/a/$b/d/e': typeof ABcDEIndexRoute
+ '/a/$b/d/e/': typeof ABcDEIndexRoute
}
export interface FileRoutesByTo {
'/a/$b': typeof ABcIndexRoute
@@ -46,7 +46,7 @@ export interface FileRoutesById {
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
- fullPaths: '/a/$b' | '/a/$b/' | '/a/$b/d/e'
+ fullPaths: '/a/$b' | '/a/$b/' | '/a/$b/d/e/'
fileRoutesByTo: FileRoutesByTo
to: '/a/$b' | '/a/$b/d/e'
id: '__root__' | '/a/$b/(c)' | '/a/$b/(c)/' | '/a/$b/(c)/d/e/'
@@ -75,7 +75,7 @@ declare module '@tanstack/react-router' {
'/a/$b/(c)/d/e/': {
id: '/a/$b/(c)/d/e/'
path: '/d/e'
- fullPath: '/a/$b/d/e'
+ fullPath: '/a/$b/d/e/'
preLoaderRoute: typeof ABcDEIndexRouteImport
parentRoute: typeof ABcRouteRoute
}
diff --git a/packages/router-generator/tests/generator/virtual-config-file-default-export/routeTree.snapshot.ts b/packages/router-generator/tests/generator/virtual-config-file-default-export/routeTree.snapshot.ts
index ab31f63e997..3d3c2de9d5f 100644
--- a/packages/router-generator/tests/generator/virtual-config-file-default-export/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/virtual-config-file-default-export/routeTree.snapshot.ts
@@ -78,15 +78,15 @@ const dbInvoicesIndexRoute = dbInvoicesIndexRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof indexRoute
- '/$lang': typeof pagesRoute
+ '/$lang/': typeof pagesRoute
'/dashboard': typeof dbDashboardRouteWithChildren
'/dashboard/': typeof dbDashboardIndexRoute
'/dashboard/invoices': typeof dbDashboardInvoicesRouteWithChildren
- '/hello': typeof HelloIndexRoute
+ '/hello/': typeof HelloIndexRoute
'/dashboard/invoices/': typeof dbInvoicesIndexRoute
'/dashboard/invoices/$id': typeof dbInvoiceDetailRoute
'/hello/foo/$id': typeof HelloFooIdRoute
- '/hello/foo': typeof HelloFooIndexRoute
+ '/hello/foo/': typeof HelloFooIndexRoute
}
export interface FileRoutesByTo {
'/': typeof indexRoute
@@ -116,15 +116,15 @@ export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
| '/'
- | '/$lang'
+ | '/$lang/'
| '/dashboard'
| '/dashboard/'
| '/dashboard/invoices'
- | '/hello'
+ | '/hello/'
| '/dashboard/invoices/'
| '/dashboard/invoices/$id'
| '/hello/foo/$id'
- | '/hello/foo'
+ | '/hello/foo/'
fileRoutesByTo: FileRoutesByTo
to:
| '/'
@@ -161,7 +161,7 @@ declare module '@tanstack/react-router' {
'/_layout': {
id: '/_layout'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof layoutRouteImport
parentRoute: typeof rootRouteImport
}
@@ -182,14 +182,14 @@ declare module '@tanstack/react-router' {
'/$lang/': {
id: '/$lang/'
path: '/$lang'
- fullPath: '/$lang'
+ fullPath: '/$lang/'
preLoaderRoute: typeof pagesRouteImport
parentRoute: typeof rootRouteImport
}
'/_layout/hello/': {
id: '/_layout/hello/'
path: '/hello'
- fullPath: '/hello'
+ fullPath: '/hello/'
preLoaderRoute: typeof HelloIndexRouteImport
parentRoute: typeof layoutRoute
}
@@ -210,7 +210,7 @@ declare module '@tanstack/react-router' {
'/_layout/hello/foo/': {
id: '/_layout/hello/foo/'
path: '/hello/foo'
- fullPath: '/hello/foo'
+ fullPath: '/hello/foo/'
preLoaderRoute: typeof HelloFooIndexRouteImport
parentRoute: typeof layoutRoute
}
diff --git a/packages/router-generator/tests/generator/virtual-config-file-named-export/routeTree.snapshot.ts b/packages/router-generator/tests/generator/virtual-config-file-named-export/routeTree.snapshot.ts
index ab31f63e997..3d3c2de9d5f 100644
--- a/packages/router-generator/tests/generator/virtual-config-file-named-export/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/virtual-config-file-named-export/routeTree.snapshot.ts
@@ -78,15 +78,15 @@ const dbInvoicesIndexRoute = dbInvoicesIndexRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof indexRoute
- '/$lang': typeof pagesRoute
+ '/$lang/': typeof pagesRoute
'/dashboard': typeof dbDashboardRouteWithChildren
'/dashboard/': typeof dbDashboardIndexRoute
'/dashboard/invoices': typeof dbDashboardInvoicesRouteWithChildren
- '/hello': typeof HelloIndexRoute
+ '/hello/': typeof HelloIndexRoute
'/dashboard/invoices/': typeof dbInvoicesIndexRoute
'/dashboard/invoices/$id': typeof dbInvoiceDetailRoute
'/hello/foo/$id': typeof HelloFooIdRoute
- '/hello/foo': typeof HelloFooIndexRoute
+ '/hello/foo/': typeof HelloFooIndexRoute
}
export interface FileRoutesByTo {
'/': typeof indexRoute
@@ -116,15 +116,15 @@ export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
| '/'
- | '/$lang'
+ | '/$lang/'
| '/dashboard'
| '/dashboard/'
| '/dashboard/invoices'
- | '/hello'
+ | '/hello/'
| '/dashboard/invoices/'
| '/dashboard/invoices/$id'
| '/hello/foo/$id'
- | '/hello/foo'
+ | '/hello/foo/'
fileRoutesByTo: FileRoutesByTo
to:
| '/'
@@ -161,7 +161,7 @@ declare module '@tanstack/react-router' {
'/_layout': {
id: '/_layout'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof layoutRouteImport
parentRoute: typeof rootRouteImport
}
@@ -182,14 +182,14 @@ declare module '@tanstack/react-router' {
'/$lang/': {
id: '/$lang/'
path: '/$lang'
- fullPath: '/$lang'
+ fullPath: '/$lang/'
preLoaderRoute: typeof pagesRouteImport
parentRoute: typeof rootRouteImport
}
'/_layout/hello/': {
id: '/_layout/hello/'
path: '/hello'
- fullPath: '/hello'
+ fullPath: '/hello/'
preLoaderRoute: typeof HelloIndexRouteImport
parentRoute: typeof layoutRoute
}
@@ -210,7 +210,7 @@ declare module '@tanstack/react-router' {
'/_layout/hello/foo/': {
id: '/_layout/hello/foo/'
path: '/hello/foo'
- fullPath: '/hello/foo'
+ fullPath: '/hello/foo/'
preLoaderRoute: typeof HelloFooIndexRouteImport
parentRoute: typeof layoutRoute
}
diff --git a/packages/router-generator/tests/generator/virtual-inside-with-escaped-underscore/routeTree.snapshot.ts b/packages/router-generator/tests/generator/virtual-inside-with-escaped-underscore/routeTree.snapshot.ts
index 53ba374b1ac..28aebc0aad0 100644
--- a/packages/router-generator/tests/generator/virtual-inside-with-escaped-underscore/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/virtual-inside-with-escaped-underscore/routeTree.snapshot.ts
@@ -37,7 +37,7 @@ const nestedHomeRoute = nestedHomeRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
- '/nested': typeof nestedHomeRoute
+ '/nested/': typeof nestedHomeRoute
'/nested/_auth': typeof nestedAuthRoute
'/nested/_callback': typeof nestedCallbackRoute
}
@@ -56,7 +56,7 @@ export interface FileRoutesById {
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
- fullPaths: '/' | '/nested' | '/nested/_auth' | '/nested/_callback'
+ fullPaths: '/' | '/nested/' | '/nested/_auth' | '/nested/_callback'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/nested' | '/nested/_auth' | '/nested/_callback'
id: '__root__' | '/' | '/nested/' | '/nested/_auth' | '/nested/_callback'
@@ -95,7 +95,7 @@ declare module '@tanstack/react-router' {
'/nested/': {
id: '/nested/'
path: '/nested'
- fullPath: '/nested'
+ fullPath: '/nested/'
preLoaderRoute: typeof nestedHomeRouteImport
parentRoute: typeof rootRouteImport
}
diff --git a/packages/router-generator/tests/generator/virtual-with-escaped-underscore/routeTree.snapshot.ts b/packages/router-generator/tests/generator/virtual-with-escaped-underscore/routeTree.snapshot.ts
index 5726099cc75..8eed55a7fef 100644
--- a/packages/router-generator/tests/generator/virtual-with-escaped-underscore/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/virtual-with-escaped-underscore/routeTree.snapshot.ts
@@ -40,7 +40,7 @@ export interface FileRoutesByFullPath {
'/': typeof indexRoute
'/api/_auth': typeof ApiChar91_Char93authDotrouteRoute
'/api/_hello': typeof ApiChar91_Char93helloRoute
- '/api': typeof ApiIndexRoute
+ '/api/': typeof ApiIndexRoute
}
export interface FileRoutesByTo {
'/': typeof indexRoute
@@ -57,7 +57,7 @@ export interface FileRoutesById {
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
- fullPaths: '/' | '/api/_auth' | '/api/_hello' | '/api'
+ fullPaths: '/' | '/api/_auth' | '/api/_hello' | '/api/'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/api/_auth' | '/api/_hello' | '/api'
id: '__root__' | '/' | '/api/_auth' | '/api/_hello' | '/api/'
@@ -82,7 +82,7 @@ declare module '@tanstack/react-router' {
'/api/': {
id: '/api/'
path: '/api'
- fullPath: '/api'
+ fullPath: '/api/'
preLoaderRoute: typeof ApiIndexRouteImport
parentRoute: typeof rootRouteImport
}
diff --git a/packages/router-generator/tests/generator/virtual/routeTree.snapshot.ts b/packages/router-generator/tests/generator/virtual/routeTree.snapshot.ts
index ab31f63e997..3d3c2de9d5f 100644
--- a/packages/router-generator/tests/generator/virtual/routeTree.snapshot.ts
+++ b/packages/router-generator/tests/generator/virtual/routeTree.snapshot.ts
@@ -78,15 +78,15 @@ const dbInvoicesIndexRoute = dbInvoicesIndexRouteImport.update({
export interface FileRoutesByFullPath {
'/': typeof indexRoute
- '/$lang': typeof pagesRoute
+ '/$lang/': typeof pagesRoute
'/dashboard': typeof dbDashboardRouteWithChildren
'/dashboard/': typeof dbDashboardIndexRoute
'/dashboard/invoices': typeof dbDashboardInvoicesRouteWithChildren
- '/hello': typeof HelloIndexRoute
+ '/hello/': typeof HelloIndexRoute
'/dashboard/invoices/': typeof dbInvoicesIndexRoute
'/dashboard/invoices/$id': typeof dbInvoiceDetailRoute
'/hello/foo/$id': typeof HelloFooIdRoute
- '/hello/foo': typeof HelloFooIndexRoute
+ '/hello/foo/': typeof HelloFooIndexRoute
}
export interface FileRoutesByTo {
'/': typeof indexRoute
@@ -116,15 +116,15 @@ export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths:
| '/'
- | '/$lang'
+ | '/$lang/'
| '/dashboard'
| '/dashboard/'
| '/dashboard/invoices'
- | '/hello'
+ | '/hello/'
| '/dashboard/invoices/'
| '/dashboard/invoices/$id'
| '/hello/foo/$id'
- | '/hello/foo'
+ | '/hello/foo/'
fileRoutesByTo: FileRoutesByTo
to:
| '/'
@@ -161,7 +161,7 @@ declare module '@tanstack/react-router' {
'/_layout': {
id: '/_layout'
path: ''
- fullPath: ''
+ fullPath: '/'
preLoaderRoute: typeof layoutRouteImport
parentRoute: typeof rootRouteImport
}
@@ -182,14 +182,14 @@ declare module '@tanstack/react-router' {
'/$lang/': {
id: '/$lang/'
path: '/$lang'
- fullPath: '/$lang'
+ fullPath: '/$lang/'
preLoaderRoute: typeof pagesRouteImport
parentRoute: typeof rootRouteImport
}
'/_layout/hello/': {
id: '/_layout/hello/'
path: '/hello'
- fullPath: '/hello'
+ fullPath: '/hello/'
preLoaderRoute: typeof HelloIndexRouteImport
parentRoute: typeof layoutRoute
}
@@ -210,7 +210,7 @@ declare module '@tanstack/react-router' {
'/_layout/hello/foo/': {
id: '/_layout/hello/foo/'
path: '/hello/foo'
- fullPath: '/hello/foo'
+ fullPath: '/hello/foo/'
preLoaderRoute: typeof HelloFooIndexRouteImport
parentRoute: typeof layoutRoute
}
diff --git a/packages/router-generator/tests/utils.test.ts b/packages/router-generator/tests/utils.test.ts
index 8d1d1be3723..0d9f2478bf7 100644
--- a/packages/router-generator/tests/utils.test.ts
+++ b/packages/router-generator/tests/utils.test.ts
@@ -5,6 +5,7 @@ import {
determineInitialRoutePath,
hasEscapedLeadingUnderscore,
hasEscapedTrailingUnderscore,
+ inferFullPath,
isSegmentPathless,
mergeImportDeclarations,
multiSortBy,
@@ -24,6 +25,20 @@ describe('cleanPath', () => {
})
})
+describe('inferFullPath', () => {
+ it('returns "/" for pathless layouts under root', () => {
+ const node = {
+ routePath: '/_layout-a1',
+ originalRoutePath: '/_layout-a1',
+ cleanedPath: '',
+ _fsRouteType: 'pathless_layout',
+ } as unknown as RouteNode
+
+ // This avoids inferred fullPath "" which breaks match.fullPath unions
+ expect(inferFullPath(node)).toBe('/')
+ })
+})
+
describe('determineInitialRoutePath', () => {
it('removes dots and adds slashes', () => {
expect(determineInitialRoutePath('test.test')).toStrictEqual({