@tanstack/router-generator 1.121.0-alpha.5 → 1.121.1

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 (90) hide show
  1. package/dist/cjs/config.cjs +23 -5
  2. package/dist/cjs/config.cjs.map +1 -1
  3. package/dist/cjs/config.d.cts +7 -3
  4. package/dist/cjs/filesystem/physical/getRouteNodes.cjs +5 -3
  5. package/dist/cjs/filesystem/physical/getRouteNodes.cjs.map +1 -1
  6. package/dist/cjs/filesystem/virtual/getRouteNodes.cjs +1 -1
  7. package/dist/cjs/filesystem/virtual/getRouteNodes.cjs.map +1 -1
  8. package/dist/cjs/generator.cjs +836 -668
  9. package/dist/cjs/generator.cjs.map +1 -1
  10. package/dist/cjs/generator.d.cts +71 -1
  11. package/dist/cjs/index.cjs +5 -2
  12. package/dist/cjs/index.cjs.map +1 -1
  13. package/dist/cjs/index.d.cts +7 -3
  14. package/dist/cjs/logger.cjs +37 -0
  15. package/dist/cjs/logger.cjs.map +1 -0
  16. package/dist/cjs/logger.d.cts +10 -0
  17. package/dist/cjs/plugin/default-generator-plugin.cjs +88 -0
  18. package/dist/cjs/plugin/default-generator-plugin.cjs.map +1 -0
  19. package/dist/cjs/plugin/default-generator-plugin.d.cts +2 -0
  20. package/dist/cjs/plugin/types.d.cts +46 -0
  21. package/dist/cjs/template.cjs +10 -10
  22. package/dist/cjs/template.cjs.map +1 -1
  23. package/dist/cjs/template.d.cts +2 -2
  24. package/dist/cjs/transform/default-transform-plugin.cjs +95 -0
  25. package/dist/cjs/transform/default-transform-plugin.cjs.map +1 -0
  26. package/dist/cjs/transform/default-transform-plugin.d.cts +2 -0
  27. package/dist/cjs/transform/transform.cjs +351 -0
  28. package/dist/cjs/transform/transform.cjs.map +1 -0
  29. package/dist/cjs/transform/transform.d.cts +4 -0
  30. package/dist/cjs/transform/types.d.cts +43 -0
  31. package/dist/cjs/transform/utils.cjs +36 -0
  32. package/dist/cjs/transform/utils.cjs.map +1 -0
  33. package/dist/cjs/transform/utils.d.cts +2 -0
  34. package/dist/cjs/types.d.cts +22 -0
  35. package/dist/cjs/utils.cjs +262 -40
  36. package/dist/cjs/utils.cjs.map +1 -1
  37. package/dist/cjs/utils.d.cts +82 -9
  38. package/dist/esm/config.d.ts +7 -3
  39. package/dist/esm/config.js +21 -3
  40. package/dist/esm/config.js.map +1 -1
  41. package/dist/esm/filesystem/physical/getRouteNodes.js +3 -1
  42. package/dist/esm/filesystem/physical/getRouteNodes.js.map +1 -1
  43. package/dist/esm/filesystem/virtual/getRouteNodes.js +1 -1
  44. package/dist/esm/filesystem/virtual/getRouteNodes.js.map +1 -1
  45. package/dist/esm/generator.d.ts +71 -1
  46. package/dist/esm/generator.js +827 -658
  47. package/dist/esm/generator.js.map +1 -1
  48. package/dist/esm/index.d.ts +7 -3
  49. package/dist/esm/index.js +7 -4
  50. package/dist/esm/index.js.map +1 -1
  51. package/dist/esm/logger.d.ts +10 -0
  52. package/dist/esm/logger.js +37 -0
  53. package/dist/esm/logger.js.map +1 -0
  54. package/dist/esm/plugin/default-generator-plugin.d.ts +2 -0
  55. package/dist/esm/plugin/default-generator-plugin.js +88 -0
  56. package/dist/esm/plugin/default-generator-plugin.js.map +1 -0
  57. package/dist/esm/plugin/types.d.ts +46 -0
  58. package/dist/esm/template.d.ts +2 -2
  59. package/dist/esm/template.js +10 -10
  60. package/dist/esm/template.js.map +1 -1
  61. package/dist/esm/transform/default-transform-plugin.d.ts +2 -0
  62. package/dist/esm/transform/default-transform-plugin.js +95 -0
  63. package/dist/esm/transform/default-transform-plugin.js.map +1 -0
  64. package/dist/esm/transform/transform.d.ts +4 -0
  65. package/dist/esm/transform/transform.js +351 -0
  66. package/dist/esm/transform/transform.js.map +1 -0
  67. package/dist/esm/transform/types.d.ts +43 -0
  68. package/dist/esm/transform/utils.d.ts +2 -0
  69. package/dist/esm/transform/utils.js +36 -0
  70. package/dist/esm/transform/utils.js.map +1 -0
  71. package/dist/esm/types.d.ts +22 -0
  72. package/dist/esm/utils.d.ts +82 -9
  73. package/dist/esm/utils.js +262 -40
  74. package/dist/esm/utils.js.map +1 -1
  75. package/package.json +9 -10
  76. package/src/config.ts +23 -2
  77. package/src/filesystem/physical/getRouteNodes.ts +2 -1
  78. package/src/filesystem/virtual/getRouteNodes.ts +1 -1
  79. package/src/generator.ts +1123 -945
  80. package/src/index.ts +25 -3
  81. package/src/logger.ts +43 -0
  82. package/src/plugin/default-generator-plugin.ts +96 -0
  83. package/src/plugin/types.ts +51 -0
  84. package/src/template.ts +33 -12
  85. package/src/transform/default-transform-plugin.ts +103 -0
  86. package/src/transform/transform.ts +430 -0
  87. package/src/transform/types.ts +50 -0
  88. package/src/transform/utils.ts +42 -0
  89. package/src/types.ts +25 -0
  90. package/src/utils.ts +385 -36
package/src/index.ts CHANGED
@@ -6,10 +6,16 @@ export {
6
6
  } from './config'
7
7
  export type { Config, BaseConfig } from './config'
8
8
 
9
- export { generator } from './generator'
9
+ export { Generator } from './generator'
10
+ export type { FileEventType, FileEvent, GeneratorEvent } from './generator'
11
+
12
+ export type {
13
+ GeneratorPluginBase,
14
+ GeneratorPlugin,
15
+ GeneratorPluginWithTransform,
16
+ } from './plugin/types'
10
17
 
11
18
  export {
12
- logging,
13
19
  capitalize,
14
20
  cleanPath,
15
21
  trimPathLeft,
@@ -24,11 +30,27 @@ export {
24
30
  writeIfDifferent,
25
31
  format,
26
32
  removeExt,
33
+ checkRouteFullPathUniqueness,
34
+ hasChildWithExport,
27
35
  } from './utils'
28
36
 
29
- export type { RouteNode, GetRouteNodesResult } from './types'
37
+ export type {
38
+ RouteNode,
39
+ GetRouteNodesResult,
40
+ ImportDeclaration,
41
+ ImportSpecifier,
42
+ } from './types'
30
43
 
31
44
  export { getRouteNodes as physicalGetRouteNodes } from './filesystem/physical/getRouteNodes'
32
45
  export { getRouteNodes as virtualGetRouteNodes } from './filesystem/virtual/getRouteNodes'
33
46
 
34
47
  export { rootPathId } from './filesystem/physical/rootPathId'
48
+
49
+ export { ensureStringArgument } from './transform/utils'
50
+
51
+ export type {
52
+ TransformImportsConfig,
53
+ TransformContext,
54
+ TransformOptions,
55
+ TransformPlugin,
56
+ } from './transform/types'
package/src/logger.ts ADDED
@@ -0,0 +1,43 @@
1
+ export interface Logger {
2
+ log: (...args: Array<any>) => void
3
+ debug: (...args: Array<any>) => void
4
+ info: (...args: Array<any>) => void
5
+ warn: (...args: Array<any>) => void
6
+ error: (...args: Array<any>) => void
7
+ }
8
+
9
+ export function logging(config: { disabled: boolean }): Logger {
10
+ function stripEmojis(str: string) {
11
+ return str.replace(
12
+ /[\p{Emoji_Presentation}\p{Extended_Pictographic}]/gu,
13
+ '',
14
+ )
15
+ }
16
+
17
+ function formatLogArgs(args: Array<any>): Array<any> {
18
+ if (process.env.CI) {
19
+ return args.map((arg) =>
20
+ typeof arg === 'string' ? stripEmojis(arg) : arg,
21
+ )
22
+ }
23
+ return args
24
+ }
25
+
26
+ return {
27
+ log: (...args: Array<any>) => {
28
+ if (!config.disabled) console.log(...formatLogArgs(args))
29
+ },
30
+ debug: (...args: Array<any>) => {
31
+ if (!config.disabled) console.debug(...formatLogArgs(args))
32
+ },
33
+ info: (...args: Array<any>) => {
34
+ if (!config.disabled) console.info(...formatLogArgs(args))
35
+ },
36
+ warn: (...args: Array<any>) => {
37
+ if (!config.disabled) console.warn(...formatLogArgs(args))
38
+ },
39
+ error: (...args: Array<any>) => {
40
+ if (!config.disabled) console.error(...formatLogArgs(args))
41
+ },
42
+ }
43
+ }
@@ -0,0 +1,96 @@
1
+ import { defaultTransformPlugin } from '../transform/default-transform-plugin'
2
+ import {
3
+ checkRouteFullPathUniqueness,
4
+ isRouteNodeValidForAugmentation,
5
+ } from '../utils'
6
+ import type { ImportDeclaration } from '../types'
7
+ import type { GeneratorPluginWithTransform } from './types'
8
+
9
+ export function defaultGeneratorPlugin(): GeneratorPluginWithTransform {
10
+ return {
11
+ name: 'default',
12
+ transformPlugin: defaultTransformPlugin,
13
+ imports: (opts) => {
14
+ const imports: Array<ImportDeclaration> = []
15
+ if (opts.acc.routeNodes.some((n) => n.isVirtual)) {
16
+ imports.push({
17
+ specifiers: [{ imported: 'createFileRoute' }],
18
+ source: opts.generator.targetTemplate.fullPkg,
19
+ })
20
+ }
21
+ if (opts.generator.config.verboseFileRoutes === false) {
22
+ const typeImport: ImportDeclaration = {
23
+ specifiers: [],
24
+ source: opts.generator.targetTemplate.fullPkg,
25
+ importKind: 'type',
26
+ }
27
+ if (
28
+ opts.sortedRouteNodes.some(
29
+ (d) =>
30
+ isRouteNodeValidForAugmentation(d) && d._fsRouteType !== 'lazy',
31
+ )
32
+ ) {
33
+ typeImport.specifiers.push({ imported: 'CreateFileRoute' })
34
+ }
35
+ if (
36
+ opts.sortedRouteNodes.some(
37
+ (node) =>
38
+ opts.acc.routePiecesByPath[node.routePath!]?.lazy &&
39
+ isRouteNodeValidForAugmentation(node),
40
+ )
41
+ ) {
42
+ typeImport.specifiers.push({ imported: 'CreateLazyFileRoute' })
43
+ }
44
+
45
+ if (typeImport.specifiers.length > 0) {
46
+ typeImport.specifiers.push({ imported: 'FileRoutesByPath' })
47
+ imports.push(typeImport)
48
+ }
49
+ }
50
+ return imports
51
+ },
52
+ moduleAugmentation: ({ generator }) => ({
53
+ module: generator.targetTemplate.fullPkg,
54
+ interfaceName: 'FileRoutesByPath',
55
+ }),
56
+ onRouteTreesChanged: ({ routeTrees, generator }) => {
57
+ const routeTree = routeTrees.find((tree) => tree.exportName === 'Route')
58
+ if (!routeTree) {
59
+ throw new Error(
60
+ 'No route tree found with export name "Route". Please ensure your routes are correctly defined.',
61
+ )
62
+ }
63
+ checkRouteFullPathUniqueness(
64
+ routeTree.sortedRouteNodes.filter(
65
+ (d) =>
66
+ d.children === undefined &&
67
+ 'lazy' !== d._fsRouteType &&
68
+ d.exports?.includes('Route'),
69
+ ),
70
+ generator.config,
71
+ )
72
+ },
73
+ routeModuleAugmentation: ({ routeNode }) => {
74
+ if (routeNode._fsRouteType === 'lazy') {
75
+ return `const createLazyFileRoute: CreateLazyFileRoute<FileRoutesByPath['${routeNode.routePath}']['preLoaderRoute']>`
76
+ } else {
77
+ return `const createFileRoute: CreateFileRoute<'${routeNode.routePath}',
78
+ FileRoutesByPath['${routeNode.routePath}']['parentRoute'],
79
+ FileRoutesByPath['${routeNode.routePath}']['id'],
80
+ FileRoutesByPath['${routeNode.routePath}']['path'],
81
+ FileRoutesByPath['${routeNode.routePath}']['fullPath']
82
+ >
83
+ `
84
+ }
85
+ },
86
+ createRootRouteCode: () => `createRooRoute()`,
87
+ createVirtualRouteCode: ({ node }) =>
88
+ `createFileRoute('${node.routePath}')()`,
89
+ config: ({ sortedRouteNodes }) => {
90
+ const hasMatchingRouteFiles = sortedRouteNodes.length > 0
91
+ return {
92
+ virtualRootRoute: hasMatchingRouteFiles,
93
+ }
94
+ },
95
+ }
96
+ }
@@ -0,0 +1,51 @@
1
+ import type { TransformPlugin } from '../transform/types'
2
+ import type {
3
+ HandleNodeAccumulator,
4
+ ImportDeclaration,
5
+ RouteNode,
6
+ } from '../types'
7
+
8
+ import type { Generator } from '../generator'
9
+
10
+ export type GeneratorPlugin = GeneratorPluginBase | GeneratorPluginWithTransform
11
+
12
+ export interface GeneratorPluginBase {
13
+ name: string
14
+ onRouteTreesChanged?: (opts: {
15
+ routeTrees: Array<{
16
+ sortedRouteNodes: Array<RouteNode>
17
+ acc: HandleNodeAccumulator
18
+ exportName: string
19
+ }>
20
+ rootRouteNode: RouteNode
21
+ generator: Generator
22
+ }) => void
23
+ }
24
+
25
+ export interface GeneratorPluginWithTransform extends GeneratorPluginBase {
26
+ transformPlugin: TransformPlugin
27
+ moduleAugmentation: (opts: { generator: Generator }) => {
28
+ module: string
29
+ interfaceName: string
30
+ }
31
+ imports: (opts: {
32
+ rootRouteNode: RouteNode
33
+ sortedRouteNodes: Array<RouteNode>
34
+ acc: HandleNodeAccumulator
35
+ generator: Generator
36
+ }) => Array<ImportDeclaration>
37
+ routeModuleAugmentation: (opts: {
38
+ routeNode: RouteNode
39
+ }) => string | undefined
40
+ createRootRouteCode: () => string
41
+ createVirtualRouteCode: (opts: { node: RouteNode }) => string
42
+ config: (opts: {
43
+ generator: Generator
44
+ rootRouteNode: RouteNode
45
+ sortedRouteNodes: Array<RouteNode>
46
+ }) => {
47
+ virtualRootRoute?: boolean
48
+ }
49
+ }
50
+
51
+ export {}
package/src/template.ts CHANGED
@@ -15,7 +15,7 @@ export function fillTemplate(
15
15
  return format(replaced, config)
16
16
  }
17
17
 
18
- type TargetTemplate = {
18
+ export type TargetTemplate = {
19
19
  fullPkg: string
20
20
  subPkg: string
21
21
  rootRoute: {
@@ -44,10 +44,9 @@ type TargetTemplate = {
44
44
  }
45
45
  }
46
46
 
47
- export function getTargetTemplate(target: Config['target']): TargetTemplate {
47
+ export function getTargetTemplate(config: Config): TargetTemplate {
48
+ const target = config.target
48
49
  switch (target) {
49
- // TODO: Remove this disabled eslint rule when more target types are added.
50
-
51
50
  case 'react':
52
51
  return {
53
52
  fullPkg: '@tanstack/react-router',
@@ -77,8 +76,14 @@ export function getTargetTemplate(target: Config['target']): TargetTemplate {
77
76
  'function RouteComponent() { return <div>Hello "%%tsrPath%%"!</div> };\n',
78
77
  ].join(''),
79
78
  imports: {
80
- tsrImports: () => '',
81
- tsrExportStart: () => `export const Route = createFileRoute(`,
79
+ tsrImports: () =>
80
+ config.verboseFileRoutes === false
81
+ ? ''
82
+ : "import { createFileRoute } from '@tanstack/react-router';",
83
+ tsrExportStart: (routePath) =>
84
+ config.verboseFileRoutes === false
85
+ ? 'export const Route = createFileRoute('
86
+ : `export const Route = createFileRoute('${routePath}')(`,
82
87
  tsrExportEnd: () => ');',
83
88
  },
84
89
  },
@@ -92,9 +97,13 @@ export function getTargetTemplate(target: Config['target']): TargetTemplate {
92
97
  ].join(''),
93
98
  imports: {
94
99
  tsrImports: () =>
95
- "import { createLazyFileRoute } from '@tanstack/react-router';",
100
+ config.verboseFileRoutes === false
101
+ ? ''
102
+ : "import { createLazyFileRoute } from '@tanstack/react-router';",
96
103
  tsrExportStart: (routePath) =>
97
- `export const Route = createLazyFileRoute('${routePath}')(`,
104
+ config.verboseFileRoutes === false
105
+ ? 'export const Route = createLazyFileRoute('
106
+ : `export const Route = createLazyFileRoute('${routePath}')(`,
98
107
  tsrExportEnd: () => ');',
99
108
  },
100
109
  },
@@ -128,8 +137,14 @@ export function getTargetTemplate(target: Config['target']): TargetTemplate {
128
137
  'function RouteComponent() { return <div>Hello "%%tsrPath%%"!</div> };\n',
129
138
  ].join(''),
130
139
  imports: {
131
- tsrImports: () => '',
132
- tsrExportStart: () => `export const Route = createFileRoute(`,
140
+ tsrImports: () =>
141
+ config.verboseFileRoutes === false
142
+ ? ''
143
+ : "import { createFileRoute } from '@tanstack/solid-router';",
144
+ tsrExportStart: (routePath) =>
145
+ config.verboseFileRoutes === false
146
+ ? 'export const Route = createFileRoute('
147
+ : `export const Route = createFileRoute('${routePath}')(`,
133
148
  tsrExportEnd: () => ');',
134
149
  },
135
150
  },
@@ -143,9 +158,15 @@ export function getTargetTemplate(target: Config['target']): TargetTemplate {
143
158
  ].join(''),
144
159
  imports: {
145
160
  tsrImports: () =>
146
- "import { createLazyFileRoute } from '@tanstack/solid-router';",
161
+ config.verboseFileRoutes === false
162
+ ? ''
163
+ : "import { createLazyFileRoute } from '@tanstack/solid-router';",
164
+
147
165
  tsrExportStart: (routePath) =>
148
- `export const Route = createLazyFileRoute('${routePath}')(`,
166
+ config.verboseFileRoutes === false
167
+ ? 'export const Route = createLazyFileRoute('
168
+ : `export const Route = createLazyFileRoute('${routePath}')(`,
169
+
149
170
  tsrExportEnd: () => ');',
150
171
  },
151
172
  },
@@ -0,0 +1,103 @@
1
+ import { types } from 'recast'
2
+ import { ensureStringArgument } from './utils'
3
+ import type { TransformImportsConfig, TransformPlugin } from './types'
4
+
5
+ const b = types.builders
6
+
7
+ export const defaultTransformPlugin: TransformPlugin = {
8
+ name: 'default-transform',
9
+ exportName: 'Route',
10
+ imports: (ctx) => {
11
+ const imports: TransformImportsConfig = {}
12
+ const targetModule = `@tanstack/${ctx.target}-router`
13
+ if (ctx.verboseFileRoutes === false) {
14
+ imports.banned = [
15
+ {
16
+ source: targetModule,
17
+ specifiers: [
18
+ { imported: 'createLazyFileRoute' },
19
+ { imported: 'createFileRoute' },
20
+ ],
21
+ },
22
+ ]
23
+ } else {
24
+ if (ctx.lazy) {
25
+ imports.required = [
26
+ {
27
+ source: targetModule,
28
+ specifiers: [{ imported: 'createLazyFileRoute' }],
29
+ },
30
+ ]
31
+ imports.banned = [
32
+ {
33
+ source: targetModule,
34
+ specifiers: [{ imported: 'createFileRoute' }],
35
+ },
36
+ ]
37
+ } else {
38
+ imports.required = [
39
+ {
40
+ source: targetModule,
41
+ specifiers: [{ imported: 'createFileRoute' }],
42
+ },
43
+ ]
44
+ imports.banned = [
45
+ {
46
+ source: targetModule,
47
+ specifiers: [{ imported: 'createLazyFileRoute' }],
48
+ },
49
+ ]
50
+ }
51
+ }
52
+ return imports
53
+ },
54
+ onExportFound: ({ decl, ctx }) => {
55
+ let appliedChanges = false
56
+ if (decl.init?.type === 'CallExpression') {
57
+ const callExpression = decl.init
58
+ let identifier: types.namedTypes.Identifier | undefined
59
+ // `const Route = createFileRoute({ ... })`
60
+ if (callExpression.callee.type === 'Identifier') {
61
+ identifier = callExpression.callee
62
+ if (ctx.verboseFileRoutes) {
63
+ // we need to add the string literal via another CallExpression
64
+ callExpression.callee = b.callExpression(identifier, [
65
+ b.stringLiteral(ctx.routeId),
66
+ ])
67
+ appliedChanges = true
68
+ }
69
+ }
70
+ // `const Route = createFileRoute('/path')({ ... })`
71
+ else if (
72
+ callExpression.callee.type === 'CallExpression' &&
73
+ callExpression.callee.callee.type === 'Identifier'
74
+ ) {
75
+ identifier = callExpression.callee.callee
76
+ if (!ctx.verboseFileRoutes) {
77
+ // we need to remove the route id
78
+ callExpression.callee = identifier
79
+ appliedChanges = true
80
+ } else {
81
+ // check if the route id is correct
82
+ appliedChanges = ensureStringArgument(
83
+ callExpression.callee,
84
+ ctx.routeId,
85
+ ctx.preferredQuote,
86
+ )
87
+ }
88
+ }
89
+ if (identifier === undefined) {
90
+ throw new Error(`expected identifier to be present`)
91
+ }
92
+ if (identifier.name === 'createFileRoute' && ctx.lazy) {
93
+ identifier.name = 'createLazyFileRoute'
94
+ appliedChanges = true
95
+ } else if (identifier.name === 'createLazyFileRoute' && !ctx.lazy) {
96
+ identifier.name = 'createFileRoute'
97
+ appliedChanges = true
98
+ }
99
+ }
100
+
101
+ return appliedChanges
102
+ },
103
+ }