@tanstack/router-generator 1.132.0-alpha.9 → 1.132.0

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.
Files changed (58) hide show
  1. package/dist/cjs/config.cjs +6 -2
  2. package/dist/cjs/config.cjs.map +1 -1
  3. package/dist/cjs/config.d.cts +12 -9
  4. package/dist/cjs/generator.cjs +264 -316
  5. package/dist/cjs/generator.cjs.map +1 -1
  6. package/dist/cjs/generator.d.cts +20 -7
  7. package/dist/cjs/index.cjs +0 -1
  8. package/dist/cjs/index.cjs.map +1 -1
  9. package/dist/cjs/index.d.cts +4 -4
  10. package/dist/cjs/plugin/types.d.cts +10 -38
  11. package/dist/cjs/transform/transform.cjs +108 -40
  12. package/dist/cjs/transform/transform.cjs.map +1 -1
  13. package/dist/cjs/transform/transform.d.cts +1 -1
  14. package/dist/cjs/transform/types.d.cts +4 -18
  15. package/dist/cjs/types.d.cts +1 -1
  16. package/dist/cjs/utils.cjs +55 -39
  17. package/dist/cjs/utils.cjs.map +1 -1
  18. package/dist/cjs/utils.d.cts +5 -5
  19. package/dist/esm/config.d.ts +12 -9
  20. package/dist/esm/config.js +6 -2
  21. package/dist/esm/config.js.map +1 -1
  22. package/dist/esm/generator.d.ts +20 -7
  23. package/dist/esm/generator.js +266 -318
  24. package/dist/esm/generator.js.map +1 -1
  25. package/dist/esm/index.d.ts +4 -4
  26. package/dist/esm/index.js +1 -2
  27. package/dist/esm/plugin/types.d.ts +10 -38
  28. package/dist/esm/transform/transform.d.ts +1 -1
  29. package/dist/esm/transform/transform.js +106 -38
  30. package/dist/esm/transform/transform.js.map +1 -1
  31. package/dist/esm/transform/types.d.ts +4 -18
  32. package/dist/esm/types.d.ts +1 -1
  33. package/dist/esm/utils.d.ts +5 -5
  34. package/dist/esm/utils.js +55 -39
  35. package/dist/esm/utils.js.map +1 -1
  36. package/package.json +5 -5
  37. package/src/config.ts +7 -1
  38. package/src/generator.ts +306 -366
  39. package/src/index.ts +2 -7
  40. package/src/plugin/types.ts +11 -44
  41. package/src/transform/transform.ts +118 -53
  42. package/src/transform/types.ts +5 -18
  43. package/src/types.ts +1 -1
  44. package/src/utils.ts +85 -70
  45. package/dist/cjs/plugin/default-generator-plugin.cjs +0 -94
  46. package/dist/cjs/plugin/default-generator-plugin.cjs.map +0 -1
  47. package/dist/cjs/plugin/default-generator-plugin.d.cts +0 -2
  48. package/dist/cjs/transform/default-transform-plugin.cjs +0 -97
  49. package/dist/cjs/transform/default-transform-plugin.cjs.map +0 -1
  50. package/dist/cjs/transform/default-transform-plugin.d.cts +0 -2
  51. package/dist/esm/plugin/default-generator-plugin.d.ts +0 -2
  52. package/dist/esm/plugin/default-generator-plugin.js +0 -94
  53. package/dist/esm/plugin/default-generator-plugin.js.map +0 -1
  54. package/dist/esm/transform/default-transform-plugin.d.ts +0 -2
  55. package/dist/esm/transform/default-transform-plugin.js +0 -97
  56. package/dist/esm/transform/default-transform-plugin.js.map +0 -1
  57. package/src/plugin/default-generator-plugin.ts +0 -109
  58. package/src/transform/default-transform-plugin.ts +0 -106
@@ -12,7 +12,6 @@ const rootPathId = require("./filesystem/physical/rootPathId.cjs");
12
12
  const utils = require("./utils.cjs");
13
13
  const template = require("./template.cjs");
14
14
  const transform = require("./transform/transform.cjs");
15
- const defaultGeneratorPlugin = require("./plugin/default-generator-plugin.cjs");
16
15
  function _interopNamespaceDefault(e) {
17
16
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
18
17
  if (e) {
@@ -68,15 +67,12 @@ function rerun(opts) {
68
67
  function isRerun(result) {
69
68
  return typeof result === "object" && result !== null && "rerun" in result && result.rerun === true;
70
69
  }
71
- class Generator {
70
+ const _Generator = class _Generator {
72
71
  constructor(opts) {
73
72
  this.routeNodeCache = /* @__PURE__ */ new Map();
74
73
  this.routeNodeShadowCache = /* @__PURE__ */ new Map();
75
74
  this.fileEventQueue = [];
76
- this.plugins = [defaultGeneratorPlugin.defaultGeneratorPlugin()];
77
- this.pluginsWithTransform = [];
78
- this.transformPlugins = [];
79
- this.routeGroupPatternRegex = /\(.+\)/g;
75
+ this.plugins = [];
80
76
  this.physicalDirectories = [];
81
77
  this.config = opts.config;
82
78
  this.logger = logger.logging({ disabled: this.config.disableLogging });
@@ -86,17 +82,9 @@ class Generator {
86
82
  this.targetTemplate = template.getTargetTemplate(this.config);
87
83
  this.routesDirectoryPath = this.getRoutesDirectoryPath();
88
84
  this.plugins.push(...opts.config.plugins || []);
89
- this.plugins.forEach((plugin) => {
90
- if ("transformPlugin" in plugin) {
91
- if (this.pluginsWithTransform.find((p) => p.name === plugin.name)) {
92
- throw new Error(
93
- `Plugin with name "${plugin.name}" is already registered for export ${plugin.transformPlugin.exportName}!`
94
- );
95
- }
96
- this.pluginsWithTransform.push(plugin);
97
- this.transformPlugins.push(plugin.transformPlugin);
98
- }
99
- });
85
+ for (const plugin of this.plugins) {
86
+ plugin.init?.({ generator: this });
87
+ }
100
88
  }
101
89
  getGeneratedRouteTreePath() {
102
90
  const generatedRouteTreePath = path.isAbsolute(
@@ -155,12 +143,7 @@ class Generator {
155
143
  break;
156
144
  }
157
145
  try {
158
- const start = performance.now();
159
146
  await this.generatorInternal();
160
- const end = performance.now();
161
- this.logger.info(
162
- `Generated route tree in ${Math.round(end - start)}ms`
163
- );
164
147
  } catch (err) {
165
148
  const errArray = !Array.isArray(err) ? [err] : err;
166
149
  const recoverableErrors = errArray.filter((e) => isRerun(e));
@@ -207,7 +190,7 @@ Add the file in: "${this.config.routesDirectory}/${rootPathId.rootPathId}.${this
207
190
  throw new Error(errorMessage);
208
191
  }
209
192
  this.physicalDirectories = physicalDirectories;
210
- writeRouteTreeFile = await this.handleRootNode(rootRouteNode);
193
+ await this.handleRootNode(rootRouteNode);
211
194
  const preRouteNodes = utils.multiSortBy(beforeRouteNodes, [
212
195
  (d) => d.routePath === "/" ? -1 : 1,
213
196
  (d) => d.routePath?.split("/").length,
@@ -230,20 +213,23 @@ Add the file in: "${this.config.routesDirectory}/${rootPathId.rootPathId}.${this
230
213
  }
231
214
  const routeFileResult = routeFileAllResult.flatMap((result) => {
232
215
  if (result.status === "fulfilled" && result.value !== null) {
233
- return result.value;
216
+ if (result.value.shouldWriteTree) {
217
+ writeRouteTreeFile = true;
218
+ }
219
+ return result.value.node;
234
220
  }
235
221
  return [];
236
222
  });
237
- routeFileResult.forEach((result) => {
238
- if (!result.node.exports?.length) {
239
- this.logger.warn(
240
- `Route file "${result.cacheEntry.fileContent}" does not export any route piece. This is likely a mistake.`
241
- );
242
- }
243
- });
244
- if (routeFileResult.find((r) => r.shouldWriteTree)) {
245
- writeRouteTreeFile = true;
223
+ routeFileResult.forEach((r) => r.children = void 0);
224
+ const acc = {
225
+ routeTree: [],
226
+ routeNodes: [],
227
+ routePiecesByPath: {}
228
+ };
229
+ for (const node of routeFileResult) {
230
+ _Generator.handleNode(node, acc);
246
231
  }
232
+ this.crawlingResult = { rootRouteNode, routeFileResult, acc };
247
233
  if (!this.routeTreeFileCache) {
248
234
  const routeTreeFile = await this.fs.readFile(this.generatedRouteTreePath);
249
235
  if (routeTreeFile !== "file-not-existing") {
@@ -274,10 +260,14 @@ Add the file in: "${this.config.routesDirectory}/${rootPathId.rootPathId}.${this
274
260
  }
275
261
  }
276
262
  if (!writeRouteTreeFile) {
277
- for (const fullPath of this.routeNodeCache.keys()) {
278
- if (!this.routeNodeShadowCache.has(fullPath)) {
279
- writeRouteTreeFile = true;
280
- break;
263
+ if (this.routeNodeCache.size !== this.routeNodeShadowCache.size) {
264
+ writeRouteTreeFile = true;
265
+ } else {
266
+ for (const fullPath of this.routeNodeCache.keys()) {
267
+ if (!this.routeNodeShadowCache.has(fullPath)) {
268
+ writeRouteTreeFile = true;
269
+ break;
270
+ }
281
271
  }
282
272
  }
283
273
  }
@@ -285,11 +275,12 @@ Add the file in: "${this.config.routesDirectory}/${rootPathId.rootPathId}.${this
285
275
  this.swapCaches();
286
276
  return;
287
277
  }
288
- let routeTreeContent = this.buildRouteTreeFileContent(
278
+ const buildResult = this.buildRouteTree({
289
279
  rootRouteNode,
290
- preRouteNodes,
280
+ acc,
291
281
  routeFileResult
292
- );
282
+ });
283
+ let routeTreeContent = buildResult.routeTreeContent;
293
284
  routeTreeContent = this.config.enableRouteTreeFormatting ? await utils.format(routeTreeContent, this.config) : routeTreeContent;
294
285
  let newMtimeMs;
295
286
  if (this.routeTreeFileCache) {
@@ -321,281 +312,258 @@ Add the file in: "${this.config.routesDirectory}/${rootPathId.rootPathId}.${this
321
312
  mtimeMs: newMtimeMs
322
313
  };
323
314
  }
315
+ this.plugins.map((plugin) => {
316
+ return plugin.onRouteTreeChanged?.({
317
+ routeTree: buildResult.routeTree,
318
+ routeNodes: buildResult.routeNodes,
319
+ acc,
320
+ rootRouteNode
321
+ });
322
+ });
324
323
  this.swapCaches();
325
324
  }
326
325
  swapCaches() {
327
326
  this.routeNodeCache = this.routeNodeShadowCache;
328
327
  this.routeNodeShadowCache = /* @__PURE__ */ new Map();
329
328
  }
330
- buildRouteTreeFileContent(rootRouteNode, preRouteNodes, routeFileResult) {
331
- const getImportForRouteNode = (node, exportName) => {
332
- if (node.exports?.includes(exportName)) {
333
- return {
334
- source: `./${this.getImportPath(node)}`,
335
- specifiers: [
336
- {
337
- imported: exportName,
338
- local: `${node.variableName}${exportName}Import`
339
- }
340
- ]
341
- };
342
- }
343
- return void 0;
344
- };
345
- const buildRouteTreeForExport = (plugin) => {
346
- const exportName = plugin.transformPlugin.exportName;
347
- const acc = {
348
- routeTree: [],
349
- routeNodes: [],
350
- routePiecesByPath: {}
329
+ buildRouteTree(opts) {
330
+ const config = { ...this.config, ...opts.config || {} };
331
+ const { rootRouteNode, acc } = opts;
332
+ const sortedRouteNodes = utils.multiSortBy(acc.routeNodes, [
333
+ (d) => d.routePath?.includes(`/${rootPathId.rootPathId}`) ? -1 : 1,
334
+ (d) => d.routePath?.split("/").length,
335
+ (d) => d.routePath?.endsWith(config.indexToken) ? -1 : 1,
336
+ (d) => d
337
+ ]);
338
+ const routeImports = sortedRouteNodes.filter((d) => !d.isVirtual).flatMap(
339
+ (node) => utils.getImportForRouteNode(
340
+ node,
341
+ config,
342
+ this.generatedRouteTreePath,
343
+ this.root
344
+ )
345
+ );
346
+ const virtualRouteNodes = sortedRouteNodes.filter((d) => d.isVirtual).map((node) => {
347
+ return `const ${node.variableName}RouteImport = createFileRoute('${node.routePath}')()`;
348
+ });
349
+ const imports = [];
350
+ if (acc.routeNodes.some((n) => n.isVirtual)) {
351
+ imports.push({
352
+ specifiers: [{ imported: "createFileRoute" }],
353
+ source: this.targetTemplate.fullPkg
354
+ });
355
+ }
356
+ if (config.verboseFileRoutes === false) {
357
+ const typeImport = {
358
+ specifiers: [],
359
+ source: this.targetTemplate.fullPkg,
360
+ importKind: "type"
351
361
  };
352
- for (const node of preRouteNodes) {
353
- if (node.exports?.includes(plugin.transformPlugin.exportName)) {
354
- this.handleNode(node, acc);
355
- }
362
+ if (sortedRouteNodes.some(
363
+ (d) => utils.isRouteNodeValidForAugmentation(d) && d._fsRouteType !== "lazy"
364
+ )) {
365
+ typeImport.specifiers.push({ imported: "CreateFileRoute" });
356
366
  }
357
- const sortedRouteNodes = utils.multiSortBy(acc.routeNodes, [
358
- (d) => d.routePath?.includes(`/${rootPathId.rootPathId}`) ? -1 : 1,
359
- (d) => d.routePath?.split("/").length,
360
- (d) => d.routePath?.endsWith(this.config.indexToken) ? -1 : 1,
361
- (d) => d
362
- ]);
363
- const pluginConfig = plugin.config({
364
- generator: this,
365
- rootRouteNode,
366
- sortedRouteNodes
367
- });
368
- const routeImports2 = sortedRouteNodes.filter((d) => !d.isVirtual).flatMap((node) => getImportForRouteNode(node, exportName) ?? []);
369
- const hasMatchingRouteFiles = acc.routeNodes.length > 0 || rootRouteNode.exports?.includes(exportName);
370
- const virtualRouteNodes = sortedRouteNodes.filter((d) => d.isVirtual).map((node) => {
371
- return `const ${node.variableName}${exportName}Import = ${plugin.createVirtualRouteCode({ node })}`;
372
- });
373
- if (!rootRouteNode.exports?.includes(exportName) && pluginConfig.virtualRootRoute) {
374
- virtualRouteNodes.unshift(
375
- `const ${rootRouteNode.variableName}${exportName}Import = ${plugin.createRootRouteCode()}`
376
- );
367
+ if (sortedRouteNodes.some(
368
+ (node) => acc.routePiecesByPath[node.routePath]?.lazy && utils.isRouteNodeValidForAugmentation(node)
369
+ )) {
370
+ typeImport.specifiers.push({ imported: "CreateLazyFileRoute" });
377
371
  }
378
- const imports = plugin.imports({
379
- sortedRouteNodes,
380
- acc,
381
- generator: this,
382
- rootRouteNode
383
- });
384
- const routeTreeConfig = utils.buildRouteTreeConfig(
385
- acc.routeTree,
386
- exportName,
387
- this.config.disableTypes
388
- );
389
- const createUpdateRoutes = sortedRouteNodes.map((node) => {
390
- const loaderNode = acc.routePiecesByPath[node.routePath]?.loader;
391
- const componentNode = acc.routePiecesByPath[node.routePath]?.component;
392
- const errorComponentNode = acc.routePiecesByPath[node.routePath]?.errorComponent;
393
- const pendingComponentNode = acc.routePiecesByPath[node.routePath]?.pendingComponent;
394
- const lazyComponentNode = acc.routePiecesByPath[node.routePath]?.lazy;
395
- return [
396
- [
397
- `const ${node.variableName}${exportName} = ${node.variableName}${exportName}Import.update({
372
+ if (typeImport.specifiers.length > 0) {
373
+ typeImport.specifiers.push({ imported: "FileRoutesByPath" });
374
+ imports.push(typeImport);
375
+ }
376
+ }
377
+ const routeTreeConfig = utils.buildRouteTreeConfig(
378
+ acc.routeTree,
379
+ config.disableTypes
380
+ );
381
+ const createUpdateRoutes = sortedRouteNodes.map((node) => {
382
+ const loaderNode = acc.routePiecesByPath[node.routePath]?.loader;
383
+ const componentNode = acc.routePiecesByPath[node.routePath]?.component;
384
+ const errorComponentNode = acc.routePiecesByPath[node.routePath]?.errorComponent;
385
+ const pendingComponentNode = acc.routePiecesByPath[node.routePath]?.pendingComponent;
386
+ const lazyComponentNode = acc.routePiecesByPath[node.routePath]?.lazy;
387
+ return [
388
+ [
389
+ `const ${node.variableName}Route = ${node.variableName}RouteImport.update({
398
390
  ${[
399
- `id: '${node.path}'`,
400
- !node.isNonPath ? `path: '${node.cleanedPath}'` : void 0,
401
- `getParentRoute: () => ${utils.findParent(node, exportName)}`
402
- ].filter(Boolean).join(",")}
403
- }${this.config.disableTypes ? "" : "as any"})`,
404
- loaderNode ? `.updateLoader({ loader: lazyFn(() => import('./${utils.replaceBackslash(
405
- utils.removeExt(
406
- path.relative(
407
- path.dirname(this.config.generatedRouteTree),
408
- path.resolve(
409
- this.config.routesDirectory,
410
- loaderNode.filePath
411
- )
412
- ),
413
- this.config.addExtensions
414
- )
415
- )}'), 'loader') })` : "",
416
- componentNode || errorComponentNode || pendingComponentNode ? `.update({
391
+ `id: '${node.path}'`,
392
+ !node.isNonPath ? `path: '${node.cleanedPath}'` : void 0,
393
+ `getParentRoute: () => ${utils.findParent(node)}`
394
+ ].filter(Boolean).join(",")}
395
+ }${config.disableTypes ? "" : "as any"})`,
396
+ loaderNode ? `.updateLoader({ loader: lazyFn(() => import('./${utils.replaceBackslash(
397
+ utils.removeExt(
398
+ path.relative(
399
+ path.dirname(config.generatedRouteTree),
400
+ path.resolve(config.routesDirectory, loaderNode.filePath)
401
+ ),
402
+ config.addExtensions
403
+ )
404
+ )}'), 'loader') })` : "",
405
+ componentNode || errorComponentNode || pendingComponentNode ? `.update({
417
406
  ${[
418
- ["component", componentNode],
419
- ["errorComponent", errorComponentNode],
420
- ["pendingComponent", pendingComponentNode]
421
- ].filter((d) => d[1]).map((d) => {
422
- return `${d[0]}: lazyRouteComponent(() => import('./${utils.replaceBackslash(
423
- utils.removeExt(
424
- path.relative(
425
- path.dirname(this.config.generatedRouteTree),
426
- path.resolve(
427
- this.config.routesDirectory,
428
- d[1].filePath
429
- )
430
- ),
431
- this.config.addExtensions
432
- )
433
- )}'), '${d[0]}')`;
434
- }).join("\n,")}
435
- })` : "",
436
- lazyComponentNode ? `.lazy(() => import('./${utils.replaceBackslash(
407
+ ["component", componentNode],
408
+ ["errorComponent", errorComponentNode],
409
+ ["pendingComponent", pendingComponentNode]
410
+ ].filter((d) => d[1]).map((d) => {
411
+ return `${d[0]}: lazyRouteComponent(() => import('./${utils.replaceBackslash(
437
412
  utils.removeExt(
438
413
  path.relative(
439
- path.dirname(this.config.generatedRouteTree),
440
- path.resolve(
441
- this.config.routesDirectory,
442
- lazyComponentNode.filePath
443
- )
414
+ path.dirname(config.generatedRouteTree),
415
+ path.resolve(config.routesDirectory, d[1].filePath)
444
416
  ),
445
- this.config.addExtensions
417
+ config.addExtensions
446
418
  )
447
- )}').then((d) => d.${exportName}))` : ""
448
- ].join("")
449
- ].join("\n\n");
450
- });
451
- let fileRoutesByPathInterfacePerPlugin = "";
452
- let fileRoutesByFullPathPerPlugin = "";
453
- if (!this.config.disableTypes && hasMatchingRouteFiles) {
454
- fileRoutesByFullPathPerPlugin = [
455
- `export interface File${exportName}sByFullPath {
419
+ )}'), '${d[0]}')`;
420
+ }).join("\n,")}
421
+ })` : "",
422
+ lazyComponentNode ? `.lazy(() => import('./${utils.replaceBackslash(
423
+ utils.removeExt(
424
+ path.relative(
425
+ path.dirname(config.generatedRouteTree),
426
+ path.resolve(
427
+ config.routesDirectory,
428
+ lazyComponentNode.filePath
429
+ )
430
+ ),
431
+ config.addExtensions
432
+ )
433
+ )}').then((d) => d.Route))` : ""
434
+ ].join("")
435
+ ].join("\n\n");
436
+ });
437
+ let fileRoutesByPathInterface = "";
438
+ let fileRoutesByFullPath = "";
439
+ if (!config.disableTypes) {
440
+ fileRoutesByFullPath = [
441
+ `export interface FileRoutesByFullPath {
456
442
  ${[...utils.createRouteNodesByFullPath(acc.routeNodes).entries()].filter(([fullPath]) => fullPath).map(([fullPath, routeNode]) => {
457
- return `'${fullPath}': typeof ${utils.getResolvedRouteNodeVariableName(routeNode, exportName)}`;
458
- })}
443
+ return `'${fullPath}': typeof ${utils.getResolvedRouteNodeVariableName(routeNode)}`;
444
+ })}
459
445
  }`,
460
- `export interface File${exportName}sByTo {
446
+ `export interface FileRoutesByTo {
461
447
  ${[...utils.createRouteNodesByTo(acc.routeNodes).entries()].filter(([to]) => to).map(([to, routeNode]) => {
462
- return `'${to}': typeof ${utils.getResolvedRouteNodeVariableName(routeNode, exportName)}`;
463
- })}
448
+ return `'${to}': typeof ${utils.getResolvedRouteNodeVariableName(routeNode)}`;
449
+ })}
464
450
  }`,
465
- `export interface File${exportName}sById {
466
- '${routerCore.rootRouteId}': typeof root${exportName}Import,
451
+ `export interface FileRoutesById {
452
+ '${routerCore.rootRouteId}': typeof rootRouteImport,
467
453
  ${[...utils.createRouteNodesById(acc.routeNodes).entries()].map(([id, routeNode]) => {
468
- return `'${id}': typeof ${utils.getResolvedRouteNodeVariableName(routeNode, exportName)}`;
469
- })}
454
+ return `'${id}': typeof ${utils.getResolvedRouteNodeVariableName(routeNode)}`;
455
+ })}
470
456
  }`,
471
- `export interface File${exportName}Types {
472
- file${exportName}sByFullPath: File${exportName}sByFullPath
457
+ `export interface FileRouteTypes {
458
+ fileRoutesByFullPath: FileRoutesByFullPath
473
459
  fullPaths: ${acc.routeNodes.length > 0 ? [...utils.createRouteNodesByFullPath(acc.routeNodes).keys()].filter((fullPath) => fullPath).map((fullPath) => `'${fullPath}'`).join("|") : "never"}
474
- file${exportName}sByTo: File${exportName}sByTo
460
+ fileRoutesByTo: FileRoutesByTo
475
461
  to: ${acc.routeNodes.length > 0 ? [...utils.createRouteNodesByTo(acc.routeNodes).keys()].filter((to) => to).map((to) => `'${to}'`).join("|") : "never"}
476
462
  id: ${[`'${routerCore.rootRouteId}'`, ...[...utils.createRouteNodesById(acc.routeNodes).keys()].map((id) => `'${id}'`)].join("|")}
477
- file${exportName}sById: File${exportName}sById
463
+ fileRoutesById: FileRoutesById
478
464
  }`,
479
- `export interface Root${exportName}Children {
480
- ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${utils.getResolvedRouteNodeVariableName(child, exportName)}`).join(",")}
465
+ `export interface RootRouteChildren {
466
+ ${acc.routeTree.map((child) => `${child.variableName}Route: typeof ${utils.getResolvedRouteNodeVariableName(child)}`).join(",")}
481
467
  }`
482
- ].join("\n");
483
- fileRoutesByPathInterfacePerPlugin = utils.buildFileRoutesByPathInterface({
484
- ...plugin.moduleAugmentation({ generator: this }),
485
- routeNodes: this.config.verboseFileRoutes !== false ? sortedRouteNodes : [
486
- ...routeFileResult.map(({ node }) => node),
487
- ...sortedRouteNodes.filter((d) => d.isVirtual)
488
- ],
489
- exportName
490
- });
491
- }
492
- let routeTree = "";
493
- if (hasMatchingRouteFiles) {
494
- routeTree = [
495
- `const root${exportName}Children${this.config.disableTypes ? "" : `: Root${exportName}Children`} = {
468
+ ].join("\n");
469
+ fileRoutesByPathInterface = utils.buildFileRoutesByPathInterface({
470
+ module: this.targetTemplate.fullPkg,
471
+ interfaceName: "FileRoutesByPath",
472
+ routeNodes: sortedRouteNodes
473
+ });
474
+ }
475
+ const routeTree = [
476
+ `const rootRouteChildren${config.disableTypes ? "" : `: RootRouteChildren`} = {
496
477
  ${acc.routeTree.map(
497
- (child) => `${child.variableName}${exportName}: ${utils.getResolvedRouteNodeVariableName(child, exportName)}`
498
- ).join(",")}
478
+ (child) => `${child.variableName}Route: ${utils.getResolvedRouteNodeVariableName(child)}`
479
+ ).join(",")}
499
480
  }`,
500
- `export const ${utils.lowerCaseFirstChar(exportName)}Tree = root${exportName}Import._addFileChildren(root${exportName}Children)${this.config.disableTypes ? "" : `._addFileTypes<File${exportName}Types>()`}`
501
- ].join("\n");
502
- }
503
- return {
504
- routeImports: routeImports2,
505
- sortedRouteNodes,
506
- acc,
507
- virtualRouteNodes,
508
- routeTreeConfig,
509
- routeTree,
510
- imports,
511
- createUpdateRoutes,
512
- fileRoutesByFullPathPerPlugin,
513
- fileRoutesByPathInterfacePerPlugin
514
- };
515
- };
516
- const routeTrees = this.pluginsWithTransform.map((plugin) => ({
517
- exportName: plugin.transformPlugin.exportName,
518
- ...buildRouteTreeForExport(plugin)
519
- }));
520
- this.plugins.map((plugin) => {
521
- return plugin.onRouteTreesChanged?.({
522
- routeTrees,
523
- rootRouteNode,
524
- generator: this
525
- });
526
- });
527
- let mergedImports = utils.mergeImportDeclarations(
528
- routeTrees.flatMap((d) => d.imports)
481
+ `export const routeTree = rootRouteImport._addFileChildren(rootRouteChildren)${config.disableTypes ? "" : `._addFileTypes<FileRouteTypes>()`}`
482
+ ].join("\n");
483
+ utils.checkRouteFullPathUniqueness(
484
+ sortedRouteNodes.filter(
485
+ (d) => d.children === void 0 && "lazy" !== d._fsRouteType
486
+ ),
487
+ config
529
488
  );
530
- if (this.config.disableTypes) {
489
+ let mergedImports = utils.mergeImportDeclarations(imports);
490
+ if (config.disableTypes) {
531
491
  mergedImports = mergedImports.filter((d) => d.importKind !== "type");
532
492
  }
533
493
  const importStatements = mergedImports.map(utils.buildImportString);
534
494
  let moduleAugmentation = "";
535
- if (this.config.verboseFileRoutes === false && !this.config.disableTypes) {
536
- moduleAugmentation = routeFileResult.map(({ node }) => {
495
+ if (config.verboseFileRoutes === false && !config.disableTypes) {
496
+ moduleAugmentation = opts.routeFileResult.map((node) => {
537
497
  const getModuleDeclaration = (routeNode) => {
538
498
  if (!utils.isRouteNodeValidForAugmentation(routeNode)) {
539
499
  return "";
540
500
  }
541
- const moduleAugmentation2 = this.pluginsWithTransform.map((plugin) => {
542
- return plugin.routeModuleAugmentation({
543
- routeNode
544
- });
545
- }).filter(Boolean).join("\n");
546
- return `declare module './${this.getImportPath(routeNode)}' {
501
+ let moduleAugmentation2 = "";
502
+ if (routeNode._fsRouteType === "lazy") {
503
+ moduleAugmentation2 = `const createLazyFileRoute: CreateLazyFileRoute<FileRoutesByPath['${routeNode.routePath}']['preLoaderRoute']>`;
504
+ } else {
505
+ moduleAugmentation2 = `const createFileRoute: CreateFileRoute<'${routeNode.routePath}',
506
+ FileRoutesByPath['${routeNode.routePath}']['parentRoute'],
507
+ FileRoutesByPath['${routeNode.routePath}']['id'],
508
+ FileRoutesByPath['${routeNode.routePath}']['path'],
509
+ FileRoutesByPath['${routeNode.routePath}']['fullPath']
510
+ >
511
+ `;
512
+ }
513
+ return `declare module './${utils.getImportPath(routeNode, config, this.generatedRouteTreePath)}' {
547
514
  ${moduleAugmentation2}
548
515
  }`;
549
516
  };
550
517
  return getModuleDeclaration(node);
551
518
  }).join("\n");
552
519
  }
553
- const routeImports = routeTrees.flatMap((t) => t.routeImports);
554
- const rootRouteImports = this.pluginsWithTransform.flatMap(
555
- (p) => getImportForRouteNode(rootRouteNode, p.transformPlugin.exportName) ?? []
520
+ const rootRouteImport = utils.getImportForRouteNode(
521
+ rootRouteNode,
522
+ config,
523
+ this.generatedRouteTreePath,
524
+ this.root
556
525
  );
557
- if (rootRouteImports.length > 0) {
558
- routeImports.unshift(...rootRouteImports);
526
+ routeImports.unshift(rootRouteImport);
527
+ let footer = [];
528
+ if (config.routeTreeFileFooter) {
529
+ if (Array.isArray(config.routeTreeFileFooter)) {
530
+ footer = config.routeTreeFileFooter;
531
+ } else {
532
+ footer = config.routeTreeFileFooter();
533
+ }
559
534
  }
560
535
  const routeTreeContent = [
561
- ...this.config.routeTreeFileHeader,
536
+ ...config.routeTreeFileHeader,
562
537
  `// This file was automatically generated by TanStack Router.
563
538
  // You should NOT make any changes in this file as it will be overwritten.
564
539
  // Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.`,
565
540
  [...importStatements].join("\n"),
566
541
  utils.mergeImportDeclarations(routeImports).map(utils.buildImportString).join("\n"),
567
- routeTrees.flatMap((t) => t.virtualRouteNodes).join("\n"),
568
- routeTrees.flatMap((t) => t.createUpdateRoutes).join("\n"),
569
- routeTrees.map((t) => t.fileRoutesByFullPathPerPlugin).join("\n"),
570
- routeTrees.map((t) => t.fileRoutesByPathInterfacePerPlugin).join("\n"),
542
+ virtualRouteNodes.join("\n"),
543
+ createUpdateRoutes.join("\n"),
544
+ fileRoutesByFullPath,
545
+ fileRoutesByPathInterface,
571
546
  moduleAugmentation,
572
- routeTrees.flatMap((t) => t.routeTreeConfig).join("\n"),
573
- routeTrees.map((t) => t.routeTree).join("\n"),
574
- ...this.config.routeTreeFileFooter
547
+ routeTreeConfig.join("\n"),
548
+ routeTree,
549
+ ...footer
575
550
  ].filter(Boolean).join("\n\n");
576
- return routeTreeContent;
577
- }
578
- getImportPath(node) {
579
- return utils.replaceBackslash(
580
- utils.removeExt(
581
- path.relative(
582
- path.dirname(this.config.generatedRouteTree),
583
- path.resolve(this.config.routesDirectory, node.filePath)
584
- ),
585
- this.config.addExtensions
586
- )
587
- );
551
+ return {
552
+ routeTreeContent,
553
+ routeTree: acc.routeTree,
554
+ routeNodes: acc.routeNodes
555
+ };
588
556
  }
589
557
  async processRouteNodeFile(node) {
590
558
  const result = await this.isRouteFileCacheFresh(node);
591
559
  if (result.status === "fresh") {
592
- node.exports = result.cacheEntry.exports;
593
560
  return {
594
- node,
595
- shouldWriteTree: result.exportsChanged,
561
+ node: result.cacheEntry.node,
562
+ shouldWriteTree: false,
596
563
  cacheEntry: result.cacheEntry
597
564
  };
598
565
  }
566
+ const previousCacheEntry = result.cacheEntry;
599
567
  const existingRouteFile = await this.fs.readFile(node.fullPath);
600
568
  if (existingRouteFile === "file-not-existing") {
601
569
  throw new Error(`⚠️ File ${node.fullPath} does not exist`);
@@ -603,13 +571,15 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${uti
603
571
  const updatedCacheEntry = {
604
572
  fileContent: existingRouteFile.fileContent,
605
573
  mtimeMs: existingRouteFile.stat.mtimeMs,
606
- exports: [],
607
- routeId: node.routePath ?? "$$TSR_NO_ROUTE_PATH_ASSIGNED$$"
574
+ routeId: node.routePath ?? "$$TSR_NO_ROUTE_PATH_ASSIGNED$$",
575
+ node
608
576
  };
609
577
  const escapedRoutePath = node.routePath?.replaceAll("$", "$$") ?? "";
610
578
  let shouldWriteRouteFile = false;
579
+ let shouldWriteTree = false;
611
580
  if (!existingRouteFile.fileContent) {
612
581
  shouldWriteRouteFile = true;
582
+ shouldWriteTree = true;
613
583
  if (node._fsRouteType === "lazy") {
614
584
  const tLazyRouteTemplate = this.targetTemplate.lazyRoute;
615
585
  updatedCacheEntry.fileContent = await template.fillTemplate(
@@ -622,7 +592,6 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${uti
622
592
  tsrExportEnd: tLazyRouteTemplate.imports.tsrExportEnd()
623
593
  }
624
594
  );
625
- updatedCacheEntry.exports = ["Route"];
626
595
  } else if (
627
596
  // Creating a new normal route file
628
597
  ["layout", "static"].some(
@@ -645,31 +614,37 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${uti
645
614
  tsrExportEnd: tRouteTemplate.imports.tsrExportEnd()
646
615
  }
647
616
  );
648
- updatedCacheEntry.exports = ["Route"];
649
617
  } else {
650
618
  return null;
651
619
  }
652
- } else {
653
- const transformResult = await transform.transform({
654
- source: updatedCacheEntry.fileContent,
655
- ctx: {
656
- target: this.config.target,
657
- routeId: escapedRoutePath,
658
- lazy: node._fsRouteType === "lazy",
659
- verboseFileRoutes: !(this.config.verboseFileRoutes === false)
660
- },
661
- plugins: this.transformPlugins
662
- });
663
- if (transformResult.result === "error") {
664
- throw new Error(
665
- `Error transforming route file ${node.fullPath}: ${transformResult.error}`
666
- );
667
- }
668
- updatedCacheEntry.exports = transformResult.exports;
669
- if (transformResult.result === "modified") {
670
- updatedCacheEntry.fileContent = transformResult.output;
671
- shouldWriteRouteFile = true;
672
- }
620
+ }
621
+ const transformResult = await transform.transform({
622
+ source: updatedCacheEntry.fileContent,
623
+ ctx: {
624
+ target: this.config.target,
625
+ routeId: escapedRoutePath,
626
+ lazy: node._fsRouteType === "lazy",
627
+ verboseFileRoutes: !(this.config.verboseFileRoutes === false)
628
+ },
629
+ node
630
+ });
631
+ if (transformResult.result === "no-route-export") {
632
+ this.logger.warn(
633
+ `Route file "${node.fullPath}" does not contain any route piece. This is likely a mistake.`
634
+ );
635
+ return null;
636
+ }
637
+ if (transformResult.result === "error") {
638
+ throw new Error(
639
+ `Error transforming route file ${node.fullPath}: ${transformResult.error}`
640
+ );
641
+ }
642
+ if (transformResult.result === "modified") {
643
+ updatedCacheEntry.fileContent = transformResult.output;
644
+ shouldWriteRouteFile = true;
645
+ }
646
+ for (const plugin of this.plugins) {
647
+ plugin.afterTransform?.({ node, prevNode: previousCacheEntry?.node });
673
648
  }
674
649
  if (shouldWriteRouteFile) {
675
650
  const stats = await this.safeFileWrite({
@@ -683,11 +658,6 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${uti
683
658
  updatedCacheEntry.mtimeMs = stats.mtimeMs;
684
659
  }
685
660
  this.routeNodeShadowCache.set(node.fullPath, updatedCacheEntry);
686
- node.exports = updatedCacheEntry.exports;
687
- const shouldWriteTree = !routerCore.deepEqual(
688
- result.cacheEntry?.exports,
689
- updatedCacheEntry.exports
690
- );
691
661
  return {
692
662
  node,
693
663
  shouldWriteTree,
@@ -771,7 +741,6 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${uti
771
741
  this.routeNodeShadowCache.set(node.fullPath, fileChangedCache.cacheEntry);
772
742
  return {
773
743
  status: "fresh",
774
- exportsChanged: false,
775
744
  cacheEntry: fileChangedCache.cacheEntry
776
745
  };
777
746
  }
@@ -788,19 +757,8 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${uti
788
757
  }
789
758
  if (shadowCacheFileChange.result === false) {
790
759
  if (fileChangedCache.result === true) {
791
- if (routerCore.deepEqual(
792
- fileChangedCache.cacheEntry.exports,
793
- shadowCacheFileChange.cacheEntry.exports
794
- )) {
795
- return {
796
- status: "fresh",
797
- exportsChanged: false,
798
- cacheEntry: shadowCacheFileChange.cacheEntry
799
- };
800
- }
801
760
  return {
802
761
  status: "fresh",
803
- exportsChanged: true,
804
762
  cacheEntry: shadowCacheFileChange.cacheEntry
805
763
  };
806
764
  }
@@ -815,9 +773,7 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${uti
815
773
  async handleRootNode(node) {
816
774
  const result = await this.isRouteFileCacheFresh(node);
817
775
  if (result.status === "fresh") {
818
- node.exports = result.cacheEntry.exports;
819
776
  this.routeNodeShadowCache.set(node.fullPath, result.cacheEntry);
820
- return result.exportsChanged;
821
777
  }
822
778
  const rootNodeFile = await this.fs.readFile(node.fullPath);
823
779
  if (rootNodeFile === "file-not-existing") {
@@ -826,8 +782,8 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${uti
826
782
  const updatedCacheEntry = {
827
783
  fileContent: rootNodeFile.fileContent,
828
784
  mtimeMs: rootNodeFile.stat.mtimeMs,
829
- exports: [],
830
- routeId: node.routePath ?? "$$TSR_NO_ROOT_ROUTE_PATH_ASSIGNED$$"
785
+ routeId: node.routePath ?? "$$TSR_NO_ROOT_ROUTE_PATH_ASSIGNED$$",
786
+ node
831
787
  };
832
788
  if (!rootNodeFile.fileContent) {
833
789
  const rootTemplate = this.targetTemplate.rootRoute;
@@ -853,23 +809,13 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${uti
853
809
  updatedCacheEntry.fileContent = rootRouteContent;
854
810
  updatedCacheEntry.mtimeMs = stats.mtimeMs;
855
811
  }
856
- const rootRouteExports = [];
857
- for (const plugin of this.pluginsWithTransform) {
858
- const exportName = plugin.transformPlugin.exportName;
859
- if (rootNodeFile.fileContent.includes(`export const ${exportName}`)) {
860
- rootRouteExports.push(exportName);
861
- }
862
- }
863
- updatedCacheEntry.exports = rootRouteExports;
864
- node.exports = rootRouteExports;
865
812
  this.routeNodeShadowCache.set(node.fullPath, updatedCacheEntry);
866
- const shouldWriteTree = !routerCore.deepEqual(
867
- result.cacheEntry?.exports,
868
- rootRouteExports
869
- );
870
- return shouldWriteTree;
871
813
  }
872
- handleNode(node, acc) {
814
+ async getCrawlingResult() {
815
+ await this.runPromise;
816
+ return this.crawlingResult;
817
+ }
818
+ static handleNode(node, acc) {
873
819
  utils.resetRegex(this.routeGroupPatternRegex);
874
820
  let parentRoute = utils.hasParentRoute(acc.routeNodes, node, node.routePath);
875
821
  if (parentRoute?.isVirtualParentRoute && parentRoute.children?.length) {
@@ -983,6 +929,8 @@ ${acc.routeTree.map((child) => `${child.variableName}${exportName}: typeof ${uti
983
929
  }
984
930
  return false;
985
931
  }
986
- }
932
+ };
933
+ _Generator.routeGroupPatternRegex = /\(.+\)/g;
934
+ let Generator = _Generator;
987
935
  exports.Generator = Generator;
988
936
  //# sourceMappingURL=generator.cjs.map