Skip to content

Commit f2ccddf

Browse files
authored
refactor(router-generator): reduce use of boolean to identify file-system routes (#3626)
1 parent d8878af commit f2ccddf

File tree

4 files changed

+174
-81
lines changed

4 files changed

+174
-81
lines changed

packages/router-generator/src/filesystem/physical/getRouteNodes.ts

Lines changed: 89 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import type {
1515
VirtualRootRoute,
1616
VirtualRouteSubtreeConfig,
1717
} from '@tanstack/virtual-file-routes'
18-
import type { GetRouteNodesResult, RouteNode } from '../../types'
18+
import type { FsRouteType, GetRouteNodesResult, RouteNode } from '../../types'
1919
import type { Config } from '../../config'
2020

2121
const disallowedRouteGroupConfiguration = /\(([^)]+)\).(ts|js|tsx|jsx)/
@@ -119,33 +119,29 @@ export async function getRouteNodes(
119119
throw new Error(errorMessage)
120120
}
121121

122-
const variableName = routePathToVariable(routePath)
122+
const meta = getRouteMeta(routePath, config)
123+
const variableName = meta.variableName
124+
let routeType: FsRouteType = meta.fsRouteType
123125

124-
const isLazy = routePath.endsWith('/lazy')
125-
126-
if (isLazy) {
126+
if (routeType === 'lazy') {
127127
routePath = routePath.replace(/\/lazy$/, '')
128128
}
129129

130-
const isRoute = routePath.endsWith(`/${config.routeToken}`)
131-
const isComponent = routePath.endsWith('/component')
132-
const isErrorComponent = routePath.endsWith('/errorComponent')
133-
const isPendingComponent = routePath.endsWith('/pendingComponent')
134-
const isLoader = routePath.endsWith('/loader')
135-
const isAPIRoute = routePath.startsWith(
136-
`${removeTrailingSlash(config.apiBase)}/`,
137-
)
138-
const isLayout = determineRouteIsLayout(routePath, config)
130+
// this check needs to happen after the lazy route has been cleaned up
131+
// since the routePath is used to determine if a route is pathless
132+
if (isValidPathlessLayoutRoute(routePath, routeType, config)) {
133+
routeType = 'pathless_layout'
134+
}
139135

140136
;(
141137
[
142-
[isComponent, 'component'],
143-
[isErrorComponent, 'errorComponent'],
144-
[isPendingComponent, 'pendingComponent'],
145-
[isLoader, 'loader'],
146-
] as const
147-
).forEach(([isType, type]) => {
148-
if (isType) {
138+
['component', 'component'],
139+
['errorComponent', 'errorComponent'],
140+
['pendingComponent', 'pendingComponent'],
141+
['loader', 'loader'],
142+
] satisfies Array<[FsRouteType, string]>
143+
).forEach(([matcher, type]) => {
144+
if (routeType === matcher) {
149145
logger.warn(
150146
`WARNING: The \`.${type}.tsx\` suffix used for the ${filePath} file is deprecated. Use the new \`.lazy.tsx\` suffix instead.`,
151147
)
@@ -171,14 +167,7 @@ export async function getRouteNodes(
171167
fullPath,
172168
routePath,
173169
variableName,
174-
isRoute,
175-
isComponent,
176-
isErrorComponent,
177-
isPendingComponent,
178-
isLoader,
179-
isLazy,
180-
isLayout,
181-
isAPIRoute,
170+
_fsRouteType: routeType,
182171
})
183172
}
184173
}),
@@ -190,16 +179,84 @@ export async function getRouteNodes(
190179
await recurse('./')
191180

192181
const rootRouteNode = routeNodes.find((d) => d.routePath === `/${rootPathId}`)
182+
if (rootRouteNode) {
183+
rootRouteNode._fsRouteType = '__root'
184+
}
185+
193186
return { rootRouteNode, routeNodes }
194187
}
195188

196189
/**
197-
* Used to determine if a route is a layout route
190+
* Determines the metadata for a given route path based on the provided configuration.
191+
*
192+
* @param routePath - The determined initial routePath.
193+
* @param config - The user configuration object.
194+
* @returns An object containing the type of the route and the variable name derived from the route path.
195+
*/
196+
export function getRouteMeta(
197+
routePath: string,
198+
config: Config,
199+
): {
200+
// `__root` is can be more easily determined by filtering down to routePath === /${rootPathId}
201+
// `pathless` is needs to determined after `lazy` has been cleaned up from the routePath
202+
fsRouteType: Extract<
203+
FsRouteType,
204+
| 'static'
205+
| 'layout'
206+
| 'api'
207+
| 'lazy'
208+
| 'loader'
209+
| 'component'
210+
| 'pendingComponent'
211+
| 'errorComponent'
212+
>
213+
variableName: string
214+
} {
215+
let fsRouteType: FsRouteType = 'static'
216+
217+
if (routePath.endsWith(`/${config.routeToken}`)) {
218+
// layout routes, i.e `/foo/route.tsx` or `/foo/_layout/route.tsx`
219+
fsRouteType = 'layout'
220+
} else if (routePath.startsWith(`${removeTrailingSlash(config.apiBase)}/`)) {
221+
// api routes, i.e. `/api/foo.ts`
222+
fsRouteType = 'api'
223+
} else if (routePath.endsWith('/lazy')) {
224+
// lazy routes, i.e. `/foo.lazy.tsx`
225+
fsRouteType = 'lazy'
226+
} else if (routePath.endsWith('/loader')) {
227+
// loader routes, i.e. `/foo.loader.tsx`
228+
fsRouteType = 'loader'
229+
} else if (routePath.endsWith('/component')) {
230+
// component routes, i.e. `/foo.component.tsx`
231+
fsRouteType = 'component'
232+
} else if (routePath.endsWith('/pendingComponent')) {
233+
// pending component routes, i.e. `/foo.pendingComponent.tsx`
234+
fsRouteType = 'pendingComponent'
235+
} else if (routePath.endsWith('/errorComponent')) {
236+
// error component routes, i.e. `/foo.errorComponent.tsx`
237+
fsRouteType = 'errorComponent'
238+
}
239+
240+
const variableName = routePathToVariable(routePath)
241+
242+
return { fsRouteType, variableName }
243+
}
244+
245+
/**
246+
* Used to validate if a route is a pathless layout route
198247
* @param normalizedRoutePath Normalized route path, i.e `/foo/_layout/route.tsx` and `/foo._layout.route.tsx` to `/foo/_layout/route`
199248
* @param config The `router-generator` configuration object
200-
* @returns Boolean indicating if the route is a layout route
249+
* @returns Boolean indicating if the route is a pathless layout route
201250
*/
202-
function determineRouteIsLayout(normalizedRoutePath: string, config: Config) {
251+
function isValidPathlessLayoutRoute(
252+
normalizedRoutePath: string,
253+
routeType: FsRouteType,
254+
config: Config,
255+
): boolean {
256+
if (routeType === 'lazy') {
257+
return false
258+
}
259+
203260
const segments = normalizedRoutePath.split('/').filter(Boolean)
204261

205262
if (segments.length === 0) {

packages/router-generator/src/filesystem/virtual/getRouteNodes.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
routePathToVariable,
77
} from '../../utils'
88
import { getRouteNodes as getRouteNodesPhysical } from '../physical/getRouteNodes'
9+
import { rootPathId } from '../physical/rootPathId'
910
import { virtualRootRouteSchema } from './config'
1011
import { loadConfigFile } from './loadConfigFile'
1112
import type {
@@ -64,8 +65,8 @@ export async function getRouteNodes(
6465
filePath: virtualRouteConfig.file,
6566
fullPath: join(fullDir, virtualRouteConfig.file),
6667
variableName: 'rootRoute',
67-
routePath: '/',
68-
isRoot: true,
68+
routePath: `/${rootPathId}`,
69+
_fsRouteType: '__root',
6970
})
7071

7172
const rootRouteNode = allNodes[0]
@@ -150,7 +151,7 @@ export async function getRouteNodesRecursive(
150151
return { filePath, variableName, fullPath }
151152
}
152153
const parentRoutePath = removeTrailingSlash(parent?.routePath ?? '/')
153-
const isLayout = node.type === 'layout'
154+
154155
switch (node.type) {
155156
case 'index': {
156157
const { filePath, variableName, fullPath } = getFile(node.file)
@@ -160,7 +161,7 @@ export async function getRouteNodesRecursive(
160161
fullPath,
161162
variableName,
162163
routePath,
163-
isLayout,
164+
_fsRouteType: 'static',
164165
} satisfies RouteNode
165166
}
166167

@@ -176,16 +177,16 @@ export async function getRouteNodesRecursive(
176177
fullPath,
177178
variableName,
178179
routePath,
179-
isLayout,
180+
_fsRouteType: 'static',
180181
}
181182
} else {
182183
routeNode = {
183184
filePath: '',
184185
fullPath: '',
185186
variableName: routePathToVariable(routePath),
186187
routePath,
187-
isLayout,
188188
isVirtual: true,
189+
_fsRouteType: 'static',
189190
}
190191
}
191192

@@ -198,6 +199,9 @@ export async function getRouteNodesRecursive(
198199
routeNode,
199200
)
200201
routeNode.children = children
202+
203+
// If the route has children, it should be a layout
204+
routeNode._fsRouteType = 'layout'
201205
}
202206
return routeNode
203207
}
@@ -216,10 +220,10 @@ export async function getRouteNodesRecursive(
216220

217221
const routeNode: RouteNode = {
218222
fullPath,
219-
isLayout,
220223
filePath,
221224
variableName,
222225
routePath,
226+
_fsRouteType: 'pathless_layout',
223227
}
224228

225229
if (node.children !== undefined) {

0 commit comments

Comments
 (0)