@tanstack/router-generator 1.121.6 → 1.121.9
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/config.d.cts +3 -3
- 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 +43 -7
- package/dist/cjs/generator.cjs.map +1 -1
- package/dist/cjs/generator.d.cts +4 -0
- package/dist/cjs/index.d.cts +1 -1
- package/dist/cjs/types.d.cts +5 -0
- package/dist/esm/config.d.ts +3 -3
- 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 +4 -0
- package/dist/esm/generator.js +44 -8
- package/dist/esm/generator.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/types.d.ts +5 -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 +69 -13
- package/src/index.ts +2 -0
- package/src/types.ts +7 -0
package/dist/esm/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { Generator } from './generator.js';
|
|
|
4
4
|
export type { FileEventType, FileEvent, GeneratorEvent } from './generator.js';
|
|
5
5
|
export type { GeneratorPluginBase, GeneratorPlugin, GeneratorPluginWithTransform, } from './plugin/types.js';
|
|
6
6
|
export { capitalize, cleanPath, trimPathLeft, removeLeadingSlash, removeTrailingSlash, determineInitialRoutePath, replaceBackslash, routePathToVariable, removeUnderscores, resetRegex, multiSortBy, writeIfDifferent, format, removeExt, checkRouteFullPathUniqueness, hasChildWithExport, } from './utils.js';
|
|
7
|
-
export type { RouteNode, GetRouteNodesResult, ImportDeclaration, ImportSpecifier, } from './types.js';
|
|
7
|
+
export type { RouteNode, GetRouteNodesResult, GetRoutesByFileMapResult, GetRoutesByFileMapResultValue, ImportDeclaration, ImportSpecifier, } from './types.js';
|
|
8
8
|
export { getRouteNodes as physicalGetRouteNodes } from './filesystem/physical/getRouteNodes.js';
|
|
9
9
|
export { getRouteNodes as virtualGetRouteNodes } from './filesystem/virtual/getRouteNodes.js';
|
|
10
10
|
export { rootPathId } from './filesystem/physical/rootPathId.js';
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export type RouteNode = {
|
|
|
17
17
|
export interface GetRouteNodesResult {
|
|
18
18
|
rootRouteNode?: RouteNode;
|
|
19
19
|
routeNodes: Array<RouteNode>;
|
|
20
|
+
physicalDirectories: Array<string>;
|
|
20
21
|
}
|
|
21
22
|
export type FsRouteType = '__root' | 'static' | 'layout' | 'pathless_layout' | 'lazy' | 'loader' | 'component' | 'pendingComponent' | 'errorComponent';
|
|
22
23
|
export type RouteSubNode = {
|
|
@@ -40,3 +41,7 @@ export type HandleNodeAccumulator = {
|
|
|
40
41
|
routePiecesByPath: Record<string, RouteSubNode>;
|
|
41
42
|
routeNodes: Array<RouteNode>;
|
|
42
43
|
};
|
|
44
|
+
export type GetRoutesByFileMapResultValue = {
|
|
45
|
+
routePath: string;
|
|
46
|
+
};
|
|
47
|
+
export type GetRoutesByFileMapResult = Map<string, GetRoutesByFileMapResultValue>;
|
package/package.json
CHANGED
|
@@ -19,6 +19,11 @@ import type { Config } from '../../config'
|
|
|
19
19
|
|
|
20
20
|
const disallowedRouteGroupConfiguration = /\(([^)]+)\).(ts|js|tsx|jsx)/
|
|
21
21
|
|
|
22
|
+
const virtualConfigFileRegExp = /__virtual\.[mc]?[jt]s$/
|
|
23
|
+
export function isVirtualConfigFile(fileName: string): boolean {
|
|
24
|
+
return virtualConfigFileRegExp.test(fileName)
|
|
25
|
+
}
|
|
26
|
+
|
|
22
27
|
export async function getRouteNodes(
|
|
23
28
|
config: Pick<
|
|
24
29
|
Config,
|
|
@@ -38,6 +43,7 @@ export async function getRouteNodes(
|
|
|
38
43
|
const routeFileIgnoreRegExp = new RegExp(routeFileIgnorePattern ?? '', 'g')
|
|
39
44
|
|
|
40
45
|
const routeNodes: Array<RouteNode> = []
|
|
46
|
+
const allPhysicalDirectories: Array<string> = []
|
|
41
47
|
|
|
42
48
|
async function recurse(dir: string) {
|
|
43
49
|
const fullDir = path.resolve(config.routesDirectory, dir)
|
|
@@ -63,7 +69,7 @@ export async function getRouteNodes(
|
|
|
63
69
|
})
|
|
64
70
|
|
|
65
71
|
const virtualConfigFile = dirList.find((dirent) => {
|
|
66
|
-
return dirent.isFile() && dirent.name
|
|
72
|
+
return dirent.isFile() && isVirtualConfigFile(dirent.name)
|
|
67
73
|
})
|
|
68
74
|
|
|
69
75
|
if (virtualConfigFile !== undefined) {
|
|
@@ -81,14 +87,16 @@ export async function getRouteNodes(
|
|
|
81
87
|
file: '',
|
|
82
88
|
children: virtualRouteSubtreeConfig,
|
|
83
89
|
}
|
|
84
|
-
const { routeNodes: virtualRouteNodes } =
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
const { routeNodes: virtualRouteNodes, physicalDirectories } =
|
|
91
|
+
await getRouteNodesVirtual(
|
|
92
|
+
{
|
|
93
|
+
...config,
|
|
94
|
+
routesDirectory: fullDir,
|
|
95
|
+
virtualRouteConfig: dummyRoot,
|
|
96
|
+
},
|
|
97
|
+
root,
|
|
98
|
+
)
|
|
99
|
+
allPhysicalDirectories.push(...physicalDirectories)
|
|
92
100
|
virtualRouteNodes.forEach((node) => {
|
|
93
101
|
const filePath = replaceBackslash(path.join(dir, node.filePath))
|
|
94
102
|
const routePath = `/${dir}${node.routePath}`
|
|
@@ -192,7 +200,11 @@ export async function getRouteNodes(
|
|
|
192
200
|
rootRouteNode.variableName = 'root'
|
|
193
201
|
}
|
|
194
202
|
|
|
195
|
-
return {
|
|
203
|
+
return {
|
|
204
|
+
rootRouteNode,
|
|
205
|
+
routeNodes,
|
|
206
|
+
physicalDirectories: allPhysicalDirectories,
|
|
207
|
+
}
|
|
196
208
|
}
|
|
197
209
|
|
|
198
210
|
/**
|
|
@@ -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 {
|
|
@@ -45,6 +48,7 @@ import type { TargetTemplate } from './template'
|
|
|
45
48
|
import type {
|
|
46
49
|
FsRouteType,
|
|
47
50
|
GetRouteNodesResult,
|
|
51
|
+
GetRoutesByFileMapResult,
|
|
48
52
|
HandleNodeAccumulator,
|
|
49
53
|
ImportDeclaration,
|
|
50
54
|
RouteNode,
|
|
@@ -134,6 +138,7 @@ interface GeneratorCacheEntry {
|
|
|
134
138
|
|
|
135
139
|
interface RouteNodeCacheEntry extends GeneratorCacheEntry {
|
|
136
140
|
exports: Array<string>
|
|
141
|
+
routeId: string
|
|
137
142
|
}
|
|
138
143
|
|
|
139
144
|
type GeneratorRouteNodeCache = Map</** filePath **/ string, RouteNodeCacheEntry>
|
|
@@ -170,6 +175,7 @@ export class Generator {
|
|
|
170
175
|
// this is just a cache for the transform plugins since we need them for each route file that is to be processed
|
|
171
176
|
private transformPlugins: Array<TransformPlugin> = []
|
|
172
177
|
private routeGroupPatternRegex = /\(.+\)/g
|
|
178
|
+
private physicalDirectories: Array<string> = []
|
|
173
179
|
|
|
174
180
|
constructor(opts: { config: Config; root: string; fs?: fs }) {
|
|
175
181
|
this.config = opts.config
|
|
@@ -203,17 +209,22 @@ export class Generator {
|
|
|
203
209
|
: path.resolve(this.root, this.config.routesDirectory)
|
|
204
210
|
}
|
|
205
211
|
|
|
212
|
+
public getRoutesByFileMap(): GetRoutesByFileMapResult {
|
|
213
|
+
return new Map(
|
|
214
|
+
[...this.routeNodeCache.entries()].map(([filePath, cacheEntry]) => [
|
|
215
|
+
filePath,
|
|
216
|
+
{ routePath: cacheEntry.routeId },
|
|
217
|
+
]),
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
206
221
|
public async run(event?: GeneratorEvent): Promise<void> {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
)
|
|
214
|
-
) {
|
|
215
|
-
return
|
|
216
|
-
}
|
|
222
|
+
if (
|
|
223
|
+
event &&
|
|
224
|
+
event.type !== 'rerun' &&
|
|
225
|
+
!this.isFileRelevantForRouteTreeGeneration(event.path)
|
|
226
|
+
) {
|
|
227
|
+
return
|
|
217
228
|
}
|
|
218
229
|
this.fileEventQueue.push(event ?? { type: 'rerun' })
|
|
219
230
|
// only allow a single run at a time
|
|
@@ -233,7 +244,7 @@ export class Generator {
|
|
|
233
244
|
await Promise.all(
|
|
234
245
|
tempQueue.map(async (e) => {
|
|
235
246
|
if (e.type === 'update') {
|
|
236
|
-
let cacheEntry
|
|
247
|
+
let cacheEntry: GeneratorCacheEntry | undefined
|
|
237
248
|
if (e.path === this.generatedRouteTreePath) {
|
|
238
249
|
cacheEntry = this.routeTreeFileCache
|
|
239
250
|
} else {
|
|
@@ -301,7 +312,11 @@ export class Generator {
|
|
|
301
312
|
getRouteNodesResult = await physicalGetRouteNodes(this.config, this.root)
|
|
302
313
|
}
|
|
303
314
|
|
|
304
|
-
const {
|
|
315
|
+
const {
|
|
316
|
+
rootRouteNode,
|
|
317
|
+
routeNodes: beforeRouteNodes,
|
|
318
|
+
physicalDirectories,
|
|
319
|
+
} = getRouteNodesResult
|
|
305
320
|
if (rootRouteNode === undefined) {
|
|
306
321
|
let errorMessage = `rootRouteNode must not be undefined. Make sure you've added your root route into the route-tree.`
|
|
307
322
|
if (!this.config.virtualRouteConfig) {
|
|
@@ -309,6 +324,7 @@ export class Generator {
|
|
|
309
324
|
}
|
|
310
325
|
throw new Error(errorMessage)
|
|
311
326
|
}
|
|
327
|
+
this.physicalDirectories = physicalDirectories
|
|
312
328
|
|
|
313
329
|
writeRouteTreeFile = await this.handleRootNode(rootRouteNode)
|
|
314
330
|
|
|
@@ -822,6 +838,7 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${get
|
|
|
822
838
|
fileContent: existingRouteFile.fileContent,
|
|
823
839
|
mtimeMs: existingRouteFile.stat.mtimeMs,
|
|
824
840
|
exports: [],
|
|
841
|
+
routeId: node.routePath ?? '$$TSR_NO_ROUTE_PATH_ASSIGNED$$',
|
|
825
842
|
}
|
|
826
843
|
|
|
827
844
|
const escapedRoutePath = node.routePath?.replaceAll('$', '$$') ?? ''
|
|
@@ -1101,6 +1118,7 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${get
|
|
|
1101
1118
|
fileContent: rootNodeFile.fileContent,
|
|
1102
1119
|
mtimeMs: rootNodeFile.stat.mtimeMs,
|
|
1103
1120
|
exports: [],
|
|
1121
|
+
routeId: node.routePath ?? '$$TSR_NO_ROOT_ROUTE_PATH_ASSIGNED$$',
|
|
1104
1122
|
}
|
|
1105
1123
|
|
|
1106
1124
|
// scaffold the root route
|
|
@@ -1292,4 +1310,42 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${get
|
|
|
1292
1310
|
|
|
1293
1311
|
acc.routeNodes.push(node)
|
|
1294
1312
|
}
|
|
1313
|
+
|
|
1314
|
+
// only process files that are relevant for the route tree generation
|
|
1315
|
+
private isFileRelevantForRouteTreeGeneration(filePath: string): boolean {
|
|
1316
|
+
// the generated route tree file
|
|
1317
|
+
if (filePath === this.generatedRouteTreePath) {
|
|
1318
|
+
return true
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
// files inside the routes folder
|
|
1322
|
+
if (filePath.startsWith(this.routesDirectoryPath)) {
|
|
1323
|
+
return true
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
// the virtual route config file passed into `virtualRouteConfig`
|
|
1327
|
+
if (
|
|
1328
|
+
typeof this.config.virtualRouteConfig === 'string' &&
|
|
1329
|
+
filePath === this.config.virtualRouteConfig
|
|
1330
|
+
) {
|
|
1331
|
+
return true
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// this covers all files that are mounted via `virtualRouteConfig` or any `__virtual.ts` files
|
|
1335
|
+
if (this.routeNodeCache.has(filePath)) {
|
|
1336
|
+
return true
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
// virtual config files such as`__virtual.ts`
|
|
1340
|
+
if (isVirtualConfigFile(path.basename(filePath))) {
|
|
1341
|
+
return true
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
// route files inside directories mounted via `physical()` inside a virtual route config
|
|
1345
|
+
if (this.physicalDirectories.some((dir) => filePath.startsWith(dir))) {
|
|
1346
|
+
return true
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
return false
|
|
1350
|
+
}
|
|
1295
1351
|
}
|
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -18,6 +18,7 @@ export type RouteNode = {
|
|
|
18
18
|
export interface GetRouteNodesResult {
|
|
19
19
|
rootRouteNode?: RouteNode
|
|
20
20
|
routeNodes: Array<RouteNode>
|
|
21
|
+
physicalDirectories: Array<string>
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
export type FsRouteType =
|
|
@@ -54,3 +55,9 @@ export type HandleNodeAccumulator = {
|
|
|
54
55
|
routePiecesByPath: Record<string, RouteSubNode>
|
|
55
56
|
routeNodes: Array<RouteNode>
|
|
56
57
|
}
|
|
58
|
+
|
|
59
|
+
export type GetRoutesByFileMapResultValue = { routePath: string }
|
|
60
|
+
export type GetRoutesByFileMapResult = Map<
|
|
61
|
+
string,
|
|
62
|
+
GetRoutesByFileMapResultValue
|
|
63
|
+
>
|