@tanstack/router-generator 1.121.2 → 1.121.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs +14 -3
- package/dist/cjs/filesystem/physical/getRouteNodes.cjs.map +1 -1
- package/dist/cjs/filesystem/physical/getRouteNodes.d.cts +1 -0
- package/dist/cjs/filesystem/virtual/getRouteNodes.cjs +14 -8
- package/dist/cjs/filesystem/virtual/getRouteNodes.cjs.map +1 -1
- package/dist/cjs/filesystem/virtual/getRouteNodes.d.cts +4 -1
- package/dist/cjs/generator.cjs +34 -5
- package/dist/cjs/generator.cjs.map +1 -1
- package/dist/cjs/generator.d.cts +3 -0
- package/dist/cjs/transform/transform.cjs +38 -15
- package/dist/cjs/transform/transform.cjs.map +1 -1
- package/dist/cjs/types.d.cts +1 -0
- package/dist/esm/filesystem/physical/getRouteNodes.d.ts +1 -0
- package/dist/esm/filesystem/physical/getRouteNodes.js +15 -4
- package/dist/esm/filesystem/physical/getRouteNodes.js.map +1 -1
- package/dist/esm/filesystem/virtual/getRouteNodes.d.ts +4 -1
- package/dist/esm/filesystem/virtual/getRouteNodes.js +14 -8
- package/dist/esm/filesystem/virtual/getRouteNodes.js.map +1 -1
- package/dist/esm/generator.d.ts +3 -0
- package/dist/esm/generator.js +35 -6
- package/dist/esm/generator.js.map +1 -1
- package/dist/esm/transform/transform.js +38 -15
- package/dist/esm/transform/transform.js.map +1 -1
- package/dist/esm/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/filesystem/physical/getRouteNodes.ts +22 -10
- package/src/filesystem/virtual/getRouteNodes.ts +29 -21
- package/src/generator.ts +60 -13
- package/src/transform/transform.ts +59 -25
- package/src/types.ts +1 -0
|
@@ -53,7 +53,6 @@ export async function getRouteNodes(
|
|
|
53
53
|
throw new Error(`virtualRouteConfig is undefined`)
|
|
54
54
|
}
|
|
55
55
|
let virtualRouteConfig: VirtualRootRoute
|
|
56
|
-
let children: Array<RouteNode> = []
|
|
57
56
|
if (typeof tsrConfig.virtualRouteConfig === 'string') {
|
|
58
57
|
virtualRouteConfig = await getVirtualRouteConfigFromFileExport(
|
|
59
58
|
tsrConfig,
|
|
@@ -62,7 +61,7 @@ export async function getRouteNodes(
|
|
|
62
61
|
} else {
|
|
63
62
|
virtualRouteConfig = tsrConfig.virtualRouteConfig
|
|
64
63
|
}
|
|
65
|
-
children = await getRouteNodesRecursive(
|
|
64
|
+
const { children, physicalDirectories } = await getRouteNodesRecursive(
|
|
66
65
|
tsrConfig,
|
|
67
66
|
root,
|
|
68
67
|
fullDir,
|
|
@@ -80,7 +79,7 @@ export async function getRouteNodes(
|
|
|
80
79
|
const rootRouteNode = allNodes[0]
|
|
81
80
|
const routeNodes = allNodes.slice(1)
|
|
82
81
|
|
|
83
|
-
return { rootRouteNode, routeNodes }
|
|
82
|
+
return { rootRouteNode, routeNodes, physicalDirectories }
|
|
84
83
|
}
|
|
85
84
|
|
|
86
85
|
/**
|
|
@@ -135,20 +134,22 @@ export async function getRouteNodesRecursive(
|
|
|
135
134
|
fullDir: string,
|
|
136
135
|
nodes?: Array<VirtualRouteNode>,
|
|
137
136
|
parent?: RouteNode,
|
|
138
|
-
): Promise<Array<RouteNode
|
|
137
|
+
): Promise<{ children: Array<RouteNode>; physicalDirectories: Array<string> }> {
|
|
139
138
|
if (nodes === undefined) {
|
|
140
|
-
return []
|
|
139
|
+
return { children: [], physicalDirectories: [] }
|
|
141
140
|
}
|
|
141
|
+
const allPhysicalDirectories: Array<string> = []
|
|
142
142
|
const children = await Promise.all(
|
|
143
143
|
nodes.map(async (node) => {
|
|
144
144
|
if (node.type === 'physical') {
|
|
145
|
-
const { routeNodes } = await getRouteNodesPhysical(
|
|
145
|
+
const { routeNodes, physicalDirectories } = await getRouteNodesPhysical(
|
|
146
146
|
{
|
|
147
147
|
...tsrConfig,
|
|
148
148
|
routesDirectory: resolve(fullDir, node.directory),
|
|
149
149
|
},
|
|
150
150
|
root,
|
|
151
151
|
)
|
|
152
|
+
allPhysicalDirectories.push(node.directory)
|
|
152
153
|
routeNodes.forEach((subtreeNode) => {
|
|
153
154
|
subtreeNode.variableName = routePathToVariable(
|
|
154
155
|
`${node.pathPrefix}/${removeExt(subtreeNode.filePath)}`,
|
|
@@ -206,14 +207,16 @@ export async function getRouteNodesRecursive(
|
|
|
206
207
|
}
|
|
207
208
|
|
|
208
209
|
if (node.children !== undefined) {
|
|
209
|
-
const children
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
210
|
+
const { children, physicalDirectories } =
|
|
211
|
+
await getRouteNodesRecursive(
|
|
212
|
+
tsrConfig,
|
|
213
|
+
root,
|
|
214
|
+
fullDir,
|
|
215
|
+
node.children,
|
|
216
|
+
routeNode,
|
|
217
|
+
)
|
|
216
218
|
routeNode.children = children
|
|
219
|
+
allPhysicalDirectories.push(...physicalDirectories)
|
|
217
220
|
|
|
218
221
|
// If the route has children, it should be a layout
|
|
219
222
|
routeNode._fsRouteType = 'layout'
|
|
@@ -242,19 +245,24 @@ export async function getRouteNodesRecursive(
|
|
|
242
245
|
}
|
|
243
246
|
|
|
244
247
|
if (node.children !== undefined) {
|
|
245
|
-
const children
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
248
|
+
const { children, physicalDirectories } =
|
|
249
|
+
await getRouteNodesRecursive(
|
|
250
|
+
tsrConfig,
|
|
251
|
+
root,
|
|
252
|
+
fullDir,
|
|
253
|
+
node.children,
|
|
254
|
+
routeNode,
|
|
255
|
+
)
|
|
252
256
|
routeNode.children = children
|
|
257
|
+
allPhysicalDirectories.push(...physicalDirectories)
|
|
253
258
|
}
|
|
254
259
|
return routeNode
|
|
255
260
|
}
|
|
256
261
|
}
|
|
257
262
|
}),
|
|
258
263
|
)
|
|
259
|
-
return
|
|
264
|
+
return {
|
|
265
|
+
children: children.flat(),
|
|
266
|
+
physicalDirectories: allPhysicalDirectories,
|
|
267
|
+
}
|
|
260
268
|
}
|
package/src/generator.ts
CHANGED
|
@@ -4,7 +4,10 @@ import { mkdtempSync } from 'node:fs'
|
|
|
4
4
|
import crypto from 'node:crypto'
|
|
5
5
|
import { deepEqual, rootRouteId } from '@tanstack/router-core'
|
|
6
6
|
import { logging } from './logger'
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
isVirtualConfigFile,
|
|
9
|
+
getRouteNodes as physicalGetRouteNodes,
|
|
10
|
+
} from './filesystem/physical/getRouteNodes'
|
|
8
11
|
import { getRouteNodes as virtualGetRouteNodes } from './filesystem/virtual/getRouteNodes'
|
|
9
12
|
import { rootPathId } from './filesystem/physical/rootPathId'
|
|
10
13
|
import {
|
|
@@ -170,6 +173,7 @@ export class Generator {
|
|
|
170
173
|
// this is just a cache for the transform plugins since we need them for each route file that is to be processed
|
|
171
174
|
private transformPlugins: Array<TransformPlugin> = []
|
|
172
175
|
private routeGroupPatternRegex = /\(.+\)/g
|
|
176
|
+
private physicalDirectories: Array<string> = []
|
|
173
177
|
|
|
174
178
|
constructor(opts: { config: Config; root: string; fs?: fs }) {
|
|
175
179
|
this.config = opts.config
|
|
@@ -203,17 +207,17 @@ export class Generator {
|
|
|
203
207
|
: path.resolve(this.root, this.config.routesDirectory)
|
|
204
208
|
}
|
|
205
209
|
|
|
210
|
+
public getRouteFileList(): Set<string> {
|
|
211
|
+
return new Set(this.routeNodeCache.keys())
|
|
212
|
+
}
|
|
213
|
+
|
|
206
214
|
public async run(event?: GeneratorEvent): Promise<void> {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
)
|
|
214
|
-
) {
|
|
215
|
-
return
|
|
216
|
-
}
|
|
215
|
+
if (
|
|
216
|
+
event &&
|
|
217
|
+
event.type !== 'rerun' &&
|
|
218
|
+
!this.isFileRelevantForRouteTreeGeneration(event.path)
|
|
219
|
+
) {
|
|
220
|
+
return
|
|
217
221
|
}
|
|
218
222
|
this.fileEventQueue.push(event ?? { type: 'rerun' })
|
|
219
223
|
// only allow a single run at a time
|
|
@@ -233,7 +237,7 @@ export class Generator {
|
|
|
233
237
|
await Promise.all(
|
|
234
238
|
tempQueue.map(async (e) => {
|
|
235
239
|
if (e.type === 'update') {
|
|
236
|
-
let cacheEntry
|
|
240
|
+
let cacheEntry: GeneratorCacheEntry | undefined
|
|
237
241
|
if (e.path === this.generatedRouteTreePath) {
|
|
238
242
|
cacheEntry = this.routeTreeFileCache
|
|
239
243
|
} else {
|
|
@@ -301,7 +305,11 @@ export class Generator {
|
|
|
301
305
|
getRouteNodesResult = await physicalGetRouteNodes(this.config, this.root)
|
|
302
306
|
}
|
|
303
307
|
|
|
304
|
-
const {
|
|
308
|
+
const {
|
|
309
|
+
rootRouteNode,
|
|
310
|
+
routeNodes: beforeRouteNodes,
|
|
311
|
+
physicalDirectories,
|
|
312
|
+
} = getRouteNodesResult
|
|
305
313
|
if (rootRouteNode === undefined) {
|
|
306
314
|
let errorMessage = `rootRouteNode must not be undefined. Make sure you've added your root route into the route-tree.`
|
|
307
315
|
if (!this.config.virtualRouteConfig) {
|
|
@@ -309,6 +317,7 @@ export class Generator {
|
|
|
309
317
|
}
|
|
310
318
|
throw new Error(errorMessage)
|
|
311
319
|
}
|
|
320
|
+
this.physicalDirectories = physicalDirectories
|
|
312
321
|
|
|
313
322
|
writeRouteTreeFile = await this.handleRootNode(rootRouteNode)
|
|
314
323
|
|
|
@@ -1292,4 +1301,42 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${get
|
|
|
1292
1301
|
|
|
1293
1302
|
acc.routeNodes.push(node)
|
|
1294
1303
|
}
|
|
1304
|
+
|
|
1305
|
+
// only process files that are relevant for the route tree generation
|
|
1306
|
+
private isFileRelevantForRouteTreeGeneration(filePath: string): boolean {
|
|
1307
|
+
// the generated route tree file
|
|
1308
|
+
if (filePath === this.generatedRouteTreePath) {
|
|
1309
|
+
return true
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
// files inside the routes folder
|
|
1313
|
+
if (filePath.startsWith(this.routesDirectoryPath)) {
|
|
1314
|
+
return true
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
// the virtual route config file passed into `virtualRouteConfig`
|
|
1318
|
+
if (
|
|
1319
|
+
typeof this.config.virtualRouteConfig === 'string' &&
|
|
1320
|
+
filePath === this.config.virtualRouteConfig
|
|
1321
|
+
) {
|
|
1322
|
+
return true
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
// this covers all files that are mounted via `virtualRouteConfig` or any `__virtual.ts` files
|
|
1326
|
+
if (this.routeNodeCache.has(filePath)) {
|
|
1327
|
+
return true
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
// virtual config files such as`__virtual.ts`
|
|
1331
|
+
if (isVirtualConfigFile(path.basename(filePath))) {
|
|
1332
|
+
return true
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
// route files inside directories mounted via `physical()` inside a virtual route config
|
|
1336
|
+
if (this.physicalDirectories.some((dir) => filePath.startsWith(dir))) {
|
|
1337
|
+
return true
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
return false
|
|
1341
|
+
}
|
|
1295
1342
|
}
|
|
@@ -56,35 +56,69 @@ export async function transform({
|
|
|
56
56
|
registeredExports.set(exportName, plugin)
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
function onExportFound(
|
|
60
|
+
decl: types.namedTypes.VariableDeclarator,
|
|
61
|
+
exportName: string,
|
|
62
|
+
plugin: TransformPlugin,
|
|
63
|
+
) {
|
|
64
|
+
const pluginAppliedChanges = plugin.onExportFound({
|
|
65
|
+
decl,
|
|
66
|
+
ctx: { ...ctx, preferredQuote },
|
|
67
|
+
})
|
|
68
|
+
if (pluginAppliedChanges) {
|
|
69
|
+
appliedChanges = true
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// export is handled, remove it from the registered exports
|
|
73
|
+
registeredExports.delete(exportName)
|
|
74
|
+
// store the export so we can later return it once the file is transformed
|
|
75
|
+
foundExports.push(exportName)
|
|
76
|
+
}
|
|
77
|
+
|
|
59
78
|
const program: types.namedTypes.Program = ast.program
|
|
60
79
|
// first pass: find registered exports
|
|
61
80
|
for (const n of program.body) {
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
n.type === '
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
if (
|
|
81
|
-
|
|
81
|
+
if (registeredExports.size > 0 && n.type === 'ExportNamedDeclaration') {
|
|
82
|
+
// direct export of a variable declaration, e.g. `export const Route = createFileRoute('/path')`
|
|
83
|
+
if (n.declaration?.type === 'VariableDeclaration') {
|
|
84
|
+
const decl = n.declaration.declarations[0]
|
|
85
|
+
if (
|
|
86
|
+
decl &&
|
|
87
|
+
decl.type === 'VariableDeclarator' &&
|
|
88
|
+
decl.id.type === 'Identifier'
|
|
89
|
+
) {
|
|
90
|
+
const plugin = registeredExports.get(decl.id.name)
|
|
91
|
+
if (plugin) {
|
|
92
|
+
onExportFound(decl, decl.id.name, plugin)
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// this is an export without a declaration, e.g. `export { Route }`
|
|
97
|
+
else if (n.declaration === null && n.specifiers) {
|
|
98
|
+
for (const spec of n.specifiers) {
|
|
99
|
+
if (typeof spec.exported.name === 'string') {
|
|
100
|
+
const plugin = registeredExports.get(spec.exported.name)
|
|
101
|
+
if (plugin) {
|
|
102
|
+
const variableName = spec.local?.name || spec.exported.name
|
|
103
|
+
// find the matching variable declaration by iterating over the top-level declarations
|
|
104
|
+
for (const decl of program.body) {
|
|
105
|
+
if (
|
|
106
|
+
decl.type === 'VariableDeclaration' &&
|
|
107
|
+
decl.declarations[0]
|
|
108
|
+
) {
|
|
109
|
+
const variable = decl.declarations[0]
|
|
110
|
+
if (
|
|
111
|
+
variable.type === 'VariableDeclarator' &&
|
|
112
|
+
variable.id.type === 'Identifier' &&
|
|
113
|
+
variable.id.name === variableName
|
|
114
|
+
) {
|
|
115
|
+
onExportFound(variable, spec.exported.name, plugin)
|
|
116
|
+
break
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
82
121
|
}
|
|
83
|
-
|
|
84
|
-
// export is handled, remove it from the registered exports
|
|
85
|
-
registeredExports.delete(decl.id.name)
|
|
86
|
-
// store the export so we can later return it once the file is transformed
|
|
87
|
-
foundExports.push(decl.id.name)
|
|
88
122
|
}
|
|
89
123
|
}
|
|
90
124
|
}
|