@tanstack/router-cli 0.0.1-beta.69 → 1.0.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.
- package/LICENSE +1 -1
- package/bin/tsr.js +1 -1
- package/build/cjs/config.js +14 -10
- package/build/cjs/config.js.map +1 -1
- package/build/cjs/generate.js +1 -3
- package/build/cjs/generate.js.map +1 -1
- package/build/cjs/generator.js +203 -237
- package/build/cjs/generator.js.map +1 -1
- package/build/cjs/index.js +4 -7
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/watch.js +17 -24
- package/build/cjs/watch.js.map +1 -1
- package/build/types/config.d.ts +20 -0
- package/build/types/generate.d.ts +2 -0
- package/build/types/generator.d.ts +20 -0
- package/build/types/index.d.ts +1 -13
- package/build/types/watch.d.ts +1 -0
- package/package.json +8 -2
- package/src/config.ts +13 -8
- package/src/generator.ts +290 -394
- package/src/watch.ts +19 -16
- package/build/cjs/transformCode.js +0 -584
- package/build/cjs/transformCode.js.map +0 -1
- package/build/esm/index.js +0 -903
- package/build/esm/index.js.map +0 -1
- package/src/transformCode.ts +0 -860
package/src/transformCode.ts
DELETED
|
@@ -1,860 +0,0 @@
|
|
|
1
|
-
import * as babel from '@babel/core'
|
|
2
|
-
import * as t from '@babel/types'
|
|
3
|
-
// @ts-ignore
|
|
4
|
-
import syntaxTS from '@babel/plugin-syntax-typescript'
|
|
5
|
-
import {
|
|
6
|
-
IsolatedExport,
|
|
7
|
-
removeExt,
|
|
8
|
-
rootRouteName,
|
|
9
|
-
rootRouteClientName,
|
|
10
|
-
RouteNode,
|
|
11
|
-
} from './generator'
|
|
12
|
-
import path from 'path'
|
|
13
|
-
|
|
14
|
-
export const isolatedProperties = [
|
|
15
|
-
'component',
|
|
16
|
-
'errorComponent',
|
|
17
|
-
'pendingComponent',
|
|
18
|
-
] as const
|
|
19
|
-
|
|
20
|
-
export type IsolatedProperty = typeof isolatedProperties[number]
|
|
21
|
-
|
|
22
|
-
type Opts = {
|
|
23
|
-
isolate: IsolatedProperty
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const getBasePlugins = () => [
|
|
27
|
-
[
|
|
28
|
-
syntaxTS,
|
|
29
|
-
{
|
|
30
|
-
isTSX: true,
|
|
31
|
-
},
|
|
32
|
-
],
|
|
33
|
-
]
|
|
34
|
-
|
|
35
|
-
export async function ensureBoilerplate(node: RouteNode, code: string) {
|
|
36
|
-
const relativeImportPath = path.relative(node.fullDir, node.genPathNoExt)
|
|
37
|
-
|
|
38
|
-
const originalFile = await babel.transformAsync(code, {
|
|
39
|
-
configFile: false,
|
|
40
|
-
babelrc: false,
|
|
41
|
-
plugins: [...getBasePlugins()],
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
const file = await babel.transformAsync(code, {
|
|
45
|
-
configFile: false,
|
|
46
|
-
babelrc: false,
|
|
47
|
-
plugins: [
|
|
48
|
-
...getBasePlugins(),
|
|
49
|
-
{
|
|
50
|
-
visitor: {
|
|
51
|
-
Program: {
|
|
52
|
-
enter(programPath) {
|
|
53
|
-
// Remove all properties except for our isolated one
|
|
54
|
-
if (node.isRoot) {
|
|
55
|
-
let foundImport = false
|
|
56
|
-
|
|
57
|
-
programPath.traverse({
|
|
58
|
-
ImportSpecifier(importPath) {
|
|
59
|
-
if (
|
|
60
|
-
t.isIdentifier(importPath.node.imported) &&
|
|
61
|
-
importPath.node.imported.name === 'Route'
|
|
62
|
-
) {
|
|
63
|
-
foundImport = true
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
if (!foundImport) {
|
|
69
|
-
programPath.node.body.unshift(
|
|
70
|
-
babel.template.statement(
|
|
71
|
-
`import { Route } from '@tanstack/react-router'`,
|
|
72
|
-
)(),
|
|
73
|
-
)
|
|
74
|
-
}
|
|
75
|
-
} else {
|
|
76
|
-
let foundImport = false
|
|
77
|
-
programPath.traverse({
|
|
78
|
-
ImportSpecifier(importPath) {
|
|
79
|
-
if (
|
|
80
|
-
t.isIdentifier(importPath.node.imported) &&
|
|
81
|
-
importPath.node.imported.name === 'route'
|
|
82
|
-
) {
|
|
83
|
-
foundImport = true
|
|
84
|
-
if (t.isImportDeclaration(importPath.parentPath.node)) {
|
|
85
|
-
if (
|
|
86
|
-
importPath.parentPath.node.source.value !==
|
|
87
|
-
relativeImportPath
|
|
88
|
-
) {
|
|
89
|
-
importPath.parentPath.node.source.value =
|
|
90
|
-
relativeImportPath
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
})
|
|
96
|
-
if (!foundImport) {
|
|
97
|
-
programPath.node.body.unshift(
|
|
98
|
-
babel.template.statement(
|
|
99
|
-
`import { Route } from '${relativeImportPath.replace(
|
|
100
|
-
/\\/gi,
|
|
101
|
-
'/',
|
|
102
|
-
)}'`,
|
|
103
|
-
)(),
|
|
104
|
-
)
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
],
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
const separator = 'new Route('
|
|
115
|
-
|
|
116
|
-
if (!originalFile?.code) {
|
|
117
|
-
return `${file?.code}\n\n${separator}{\n\n})`
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const originalHead = originalFile?.code?.substring(
|
|
121
|
-
0,
|
|
122
|
-
originalFile?.code?.indexOf(separator),
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
const generatedHead = file?.code?.substring(0, file?.code?.indexOf(separator))
|
|
126
|
-
|
|
127
|
-
if (originalHead !== generatedHead) {
|
|
128
|
-
return `${generatedHead}\n\n${originalFile?.code?.substring(
|
|
129
|
-
originalFile?.code?.indexOf(separator),
|
|
130
|
-
)}`
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
return
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export async function isolateOptionToExport(
|
|
137
|
-
node: RouteNode,
|
|
138
|
-
code: string,
|
|
139
|
-
opts: Opts,
|
|
140
|
-
) {
|
|
141
|
-
return (
|
|
142
|
-
await babel.transformAsync(code, {
|
|
143
|
-
configFile: false,
|
|
144
|
-
babelrc: false,
|
|
145
|
-
plugins: [...getBasePlugins(), plugin()],
|
|
146
|
-
ast: true,
|
|
147
|
-
})
|
|
148
|
-
)?.code
|
|
149
|
-
|
|
150
|
-
function plugin(): babel.PluginItem {
|
|
151
|
-
return {
|
|
152
|
-
visitor: {
|
|
153
|
-
Program: {
|
|
154
|
-
enter(programPath, state) {
|
|
155
|
-
// If we're the root, handle things a bit differently
|
|
156
|
-
if (node.isRoot) {
|
|
157
|
-
programPath.traverse({
|
|
158
|
-
Identifier(path) {
|
|
159
|
-
if (
|
|
160
|
-
path.node.name === 'Route' &&
|
|
161
|
-
t.isCallExpression(path.parentPath.node)
|
|
162
|
-
) {
|
|
163
|
-
const options = getRouteOptions(path)
|
|
164
|
-
|
|
165
|
-
if (options) {
|
|
166
|
-
const property = options.properties.find((property) => {
|
|
167
|
-
return (
|
|
168
|
-
t.isObjectProperty(property) &&
|
|
169
|
-
t.isIdentifier(property.key) &&
|
|
170
|
-
property.key.name === opts.isolate
|
|
171
|
-
)
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
if (t.isObjectProperty(property)) {
|
|
175
|
-
const program = path.findParent((d) => d.isProgram())
|
|
176
|
-
|
|
177
|
-
if (program?.isProgram()) {
|
|
178
|
-
program.node.body.push(
|
|
179
|
-
babel.template.statement(
|
|
180
|
-
`export const ${opts.isolate} = $VAR`,
|
|
181
|
-
)({
|
|
182
|
-
$VAR: property.value,
|
|
183
|
-
}),
|
|
184
|
-
)
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
path
|
|
189
|
-
.findParent((d) => d.isExpressionStatement())
|
|
190
|
-
?.remove()
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
|
-
})
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// We're not in the root, handle things normally
|
|
198
|
-
if (!node.isRoot) {
|
|
199
|
-
// Remove all properties except for our isolated one
|
|
200
|
-
programPath.traverse({
|
|
201
|
-
Identifier(path) {
|
|
202
|
-
if (path.node.name === 'generate') {
|
|
203
|
-
const options = getRouteConfigGenerateOptions(path)
|
|
204
|
-
|
|
205
|
-
if (options) {
|
|
206
|
-
const property = options.properties.find((property) => {
|
|
207
|
-
return (
|
|
208
|
-
t.isObjectProperty(property) &&
|
|
209
|
-
t.isIdentifier(property.key) &&
|
|
210
|
-
property.key.name === opts.isolate
|
|
211
|
-
)
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
if (
|
|
215
|
-
t.isObjectProperty(property) &&
|
|
216
|
-
t.isIdentifier(property.key)
|
|
217
|
-
) {
|
|
218
|
-
if (property.key.name === opts.isolate) {
|
|
219
|
-
const program = path.findParent((d) => d.isProgram())
|
|
220
|
-
|
|
221
|
-
if (program?.isProgram()) {
|
|
222
|
-
program.node.body.push(
|
|
223
|
-
babel.template.statement(
|
|
224
|
-
`export const ${opts.isolate} = $VAR`,
|
|
225
|
-
)({
|
|
226
|
-
$VAR: property.value,
|
|
227
|
-
}),
|
|
228
|
-
)
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
path
|
|
234
|
-
.findParent((d) => d.isExpressionStatement())
|
|
235
|
-
?.remove()
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
},
|
|
239
|
-
})
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
cleanUnusedCode(programPath, state, [opts.isolate])
|
|
243
|
-
},
|
|
244
|
-
},
|
|
245
|
-
},
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
export async function detectExports(code: string) {
|
|
251
|
-
let exported: string[] = []
|
|
252
|
-
|
|
253
|
-
// try {
|
|
254
|
-
await babel.transformAsync(code, {
|
|
255
|
-
configFile: false,
|
|
256
|
-
babelrc: false,
|
|
257
|
-
plugins: [
|
|
258
|
-
...getBasePlugins(),
|
|
259
|
-
{
|
|
260
|
-
visitor: {
|
|
261
|
-
ExportNamedDeclaration(path) {
|
|
262
|
-
if (t.isVariableDeclaration(path.node.declaration)) {
|
|
263
|
-
if (
|
|
264
|
-
t.isVariableDeclarator(path.node.declaration.declarations?.[0])
|
|
265
|
-
) {
|
|
266
|
-
if (t.isIdentifier(path.node.declaration.declarations[0].id)) {
|
|
267
|
-
exported.push(path.node.declaration.declarations[0].id.name)
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
},
|
|
272
|
-
},
|
|
273
|
-
},
|
|
274
|
-
],
|
|
275
|
-
ast: true,
|
|
276
|
-
})
|
|
277
|
-
|
|
278
|
-
return exported
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
export async function generateRouteConfig(
|
|
282
|
-
node: RouteNode,
|
|
283
|
-
routeCode: string,
|
|
284
|
-
imports: IsolatedExport[],
|
|
285
|
-
clientOnly: boolean,
|
|
286
|
-
) {
|
|
287
|
-
const relativeParentRoutePath = clientOnly
|
|
288
|
-
? node.parent
|
|
289
|
-
? removeExt(
|
|
290
|
-
path.relative(
|
|
291
|
-
node.genDir,
|
|
292
|
-
path.resolve(node.parent?.genDir, node.parent?.clientFilename),
|
|
293
|
-
),
|
|
294
|
-
)
|
|
295
|
-
: `./${rootRouteClientName}`
|
|
296
|
-
: node.parent
|
|
297
|
-
? removeExt(
|
|
298
|
-
path.relative(
|
|
299
|
-
node.genDir,
|
|
300
|
-
path.resolve(node.parent?.genDir, node.parent?.filename),
|
|
301
|
-
),
|
|
302
|
-
)
|
|
303
|
-
: `./${rootRouteName}`
|
|
304
|
-
|
|
305
|
-
const pathName = node.isRoot
|
|
306
|
-
? undefined
|
|
307
|
-
: node.fileNameNoExt.startsWith('__')
|
|
308
|
-
? undefined
|
|
309
|
-
: node.fileNameNoExt === 'index'
|
|
310
|
-
? '/'
|
|
311
|
-
: node.fileNameNoExt
|
|
312
|
-
|
|
313
|
-
const routeId = node.isRoot ? undefined : node.fileNameNoExt
|
|
314
|
-
|
|
315
|
-
function plugin(): babel.PluginItem {
|
|
316
|
-
return {
|
|
317
|
-
visitor: {
|
|
318
|
-
Program: {
|
|
319
|
-
enter(programPath, state) {
|
|
320
|
-
// Remove all of the isolated import properties from the config
|
|
321
|
-
programPath.traverse({
|
|
322
|
-
ImportSpecifier(path) {
|
|
323
|
-
if (t.isIdentifier(path.node.imported)) {
|
|
324
|
-
if (!node.isRoot) {
|
|
325
|
-
if (path.node.imported.name === 'route') {
|
|
326
|
-
path.parentPath.remove()
|
|
327
|
-
|
|
328
|
-
const program = path.findParent((d) => d.isProgram())
|
|
329
|
-
|
|
330
|
-
if (program?.isProgram()) {
|
|
331
|
-
program.node.body.unshift(
|
|
332
|
-
babel.template.statement(
|
|
333
|
-
`import { route as parentRoute } from '$IMPORT'`,
|
|
334
|
-
)({
|
|
335
|
-
$IMPORT: relativeParentRoutePath,
|
|
336
|
-
}),
|
|
337
|
-
)
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
},
|
|
343
|
-
Identifier(iPath) {
|
|
344
|
-
let options
|
|
345
|
-
|
|
346
|
-
if (node.isRoot) {
|
|
347
|
-
if (iPath.node.name === 'Route') {
|
|
348
|
-
if (t.isCallExpression(iPath.parentPath.node)) {
|
|
349
|
-
if (
|
|
350
|
-
t.isExpressionStatement(
|
|
351
|
-
iPath.parentPath.parentPath?.node,
|
|
352
|
-
)
|
|
353
|
-
) {
|
|
354
|
-
iPath.parentPath.parentPath?.replaceWith(
|
|
355
|
-
t.variableDeclaration('const', [
|
|
356
|
-
t.variableDeclarator(
|
|
357
|
-
t.identifier('route'),
|
|
358
|
-
iPath.parentPath.node,
|
|
359
|
-
),
|
|
360
|
-
]) as any,
|
|
361
|
-
)
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
} else {
|
|
366
|
-
if (iPath.node.name === 'generate') {
|
|
367
|
-
if (t.isMemberExpression(iPath.parentPath.node)) {
|
|
368
|
-
if (t.isIdentifier(iPath.parentPath.node.object)) {
|
|
369
|
-
iPath.node.name = 'Route'
|
|
370
|
-
iPath.parentPath.node.object.name = 'parentRoute'
|
|
371
|
-
|
|
372
|
-
options = getRouteConfigGenerateOptions(iPath)
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
if (options) {
|
|
379
|
-
options.properties = [
|
|
380
|
-
...(pathName
|
|
381
|
-
? [
|
|
382
|
-
t.objectProperty(
|
|
383
|
-
t.identifier('path'),
|
|
384
|
-
t.stringLiteral(pathName),
|
|
385
|
-
),
|
|
386
|
-
]
|
|
387
|
-
: routeId
|
|
388
|
-
? [
|
|
389
|
-
t.objectProperty(
|
|
390
|
-
t.identifier('id'),
|
|
391
|
-
t.stringLiteral(routeId),
|
|
392
|
-
),
|
|
393
|
-
]
|
|
394
|
-
: []),
|
|
395
|
-
...options.properties.map((property) => {
|
|
396
|
-
if (
|
|
397
|
-
t.isObjectProperty(property) &&
|
|
398
|
-
t.isIdentifier(property.key) &&
|
|
399
|
-
isolatedProperties.includes(
|
|
400
|
-
property.key.name as IsolatedProperty,
|
|
401
|
-
)
|
|
402
|
-
) {
|
|
403
|
-
const key = property.key.name
|
|
404
|
-
|
|
405
|
-
if (key === 'loader') {
|
|
406
|
-
if (clientOnly) {
|
|
407
|
-
return t.objectProperty(
|
|
408
|
-
t.identifier('loader'),
|
|
409
|
-
t.tSAsExpression(
|
|
410
|
-
t.booleanLiteral(true),
|
|
411
|
-
t.tsAnyKeyword(),
|
|
412
|
-
),
|
|
413
|
-
)
|
|
414
|
-
}
|
|
415
|
-
return t.objectProperty(
|
|
416
|
-
t.identifier(key),
|
|
417
|
-
babel.template.expression(
|
|
418
|
-
`(...args) => import('./${path.relative(
|
|
419
|
-
node.genDir,
|
|
420
|
-
node.genPathNoExt,
|
|
421
|
-
)}-${key}').then(d => d.${key}.apply(d.${key}, (args as any)))`,
|
|
422
|
-
{
|
|
423
|
-
plugins: ['typescript'],
|
|
424
|
-
},
|
|
425
|
-
)({}),
|
|
426
|
-
)
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
if (key === 'action') {
|
|
430
|
-
if (clientOnly) {
|
|
431
|
-
return t.objectProperty(
|
|
432
|
-
t.identifier('action'),
|
|
433
|
-
t.tSAsExpression(
|
|
434
|
-
t.booleanLiteral(true),
|
|
435
|
-
t.tSAnyKeyword(),
|
|
436
|
-
),
|
|
437
|
-
)
|
|
438
|
-
}
|
|
439
|
-
return t.objectProperty(
|
|
440
|
-
t.identifier(key),
|
|
441
|
-
babel.template.expression(
|
|
442
|
-
`(...payload: Parameters<typeof import('./${path.relative(
|
|
443
|
-
node.genDir,
|
|
444
|
-
node.genPathNoExt,
|
|
445
|
-
)}-${key}').action>) => import('./${path.relative(
|
|
446
|
-
node.genDir,
|
|
447
|
-
node.genPathNoExt,
|
|
448
|
-
)}-${key}').then(d => d.${key}.apply(d.${key}, (payload as any)))`,
|
|
449
|
-
{
|
|
450
|
-
plugins: ['typescript'],
|
|
451
|
-
},
|
|
452
|
-
)({}),
|
|
453
|
-
)
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
if (clientOnly) {
|
|
457
|
-
return t.objectProperty(
|
|
458
|
-
t.identifier(key),
|
|
459
|
-
babel.template.expression(`
|
|
460
|
-
lazy(() => import('./${path.relative(
|
|
461
|
-
node.genDir,
|
|
462
|
-
node.genPathNoExt,
|
|
463
|
-
)}-${key}').then(d => ({ default: d.${key} }) ))`)(),
|
|
464
|
-
)
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
return t.objectProperty(
|
|
468
|
-
t.identifier(key),
|
|
469
|
-
property.value as any,
|
|
470
|
-
)
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
return property
|
|
474
|
-
}),
|
|
475
|
-
]
|
|
476
|
-
|
|
477
|
-
const program = iPath.findParent((d) => d.isProgram())
|
|
478
|
-
|
|
479
|
-
if (program?.isProgram() && options) {
|
|
480
|
-
const index = program.node.body.findIndex(
|
|
481
|
-
(d) =>
|
|
482
|
-
d.start === iPath.parentPath.parentPath?.node.start,
|
|
483
|
-
)
|
|
484
|
-
|
|
485
|
-
if (node.isRoot) {
|
|
486
|
-
program.node.body[index] = babel.template.statement(
|
|
487
|
-
`const route = new Route(
|
|
488
|
-
$OPTIONS
|
|
489
|
-
)`,
|
|
490
|
-
)({
|
|
491
|
-
$OPTIONS: options,
|
|
492
|
-
})
|
|
493
|
-
} else {
|
|
494
|
-
program.node.body[index] = babel.template.statement(
|
|
495
|
-
`const route = new Route(
|
|
496
|
-
$OPTIONS
|
|
497
|
-
)`,
|
|
498
|
-
)({
|
|
499
|
-
$OPTIONS: options,
|
|
500
|
-
})
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
},
|
|
505
|
-
})
|
|
506
|
-
|
|
507
|
-
programPath.node.body.unshift(
|
|
508
|
-
babel.template.statement(
|
|
509
|
-
`import { lazy } from '@tanstack/react-router'`,
|
|
510
|
-
)(),
|
|
511
|
-
)
|
|
512
|
-
|
|
513
|
-
// Add the route exports
|
|
514
|
-
programPath.node.body.push(
|
|
515
|
-
babel.template.statement(
|
|
516
|
-
clientOnly
|
|
517
|
-
? `export { route, route as ${node.variable}Route }`
|
|
518
|
-
: `export { route }`,
|
|
519
|
-
)(),
|
|
520
|
-
)
|
|
521
|
-
|
|
522
|
-
cleanUnusedCode(programPath, state, [
|
|
523
|
-
'route',
|
|
524
|
-
`${node.variable}Route`,
|
|
525
|
-
])
|
|
526
|
-
},
|
|
527
|
-
},
|
|
528
|
-
},
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
const code = (
|
|
533
|
-
await babel.transformAsync(routeCode, {
|
|
534
|
-
configFile: false,
|
|
535
|
-
babelrc: false,
|
|
536
|
-
plugins: [...getBasePlugins(), plugin()],
|
|
537
|
-
ast: true,
|
|
538
|
-
})
|
|
539
|
-
)?.code
|
|
540
|
-
|
|
541
|
-
if (!code) {
|
|
542
|
-
throw new Error('Error while generating a route file!')
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
return code
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
function getIdentifier(path: any) {
|
|
549
|
-
const parentPath = path.parentPath
|
|
550
|
-
if (parentPath.type === 'VariableDeclarator') {
|
|
551
|
-
const pp = parentPath
|
|
552
|
-
const name = pp.get('id')
|
|
553
|
-
return name.node.type === 'Identifier' ? name : null
|
|
554
|
-
}
|
|
555
|
-
if (parentPath.type === 'AssignmentExpression') {
|
|
556
|
-
const pp = parentPath
|
|
557
|
-
const name = pp.get('left')
|
|
558
|
-
return name.node.type === 'Identifier' ? name : null
|
|
559
|
-
}
|
|
560
|
-
if (path.node.type === 'ArrowFunctionExpression') {
|
|
561
|
-
return null
|
|
562
|
-
}
|
|
563
|
-
return path.node.id && path.node.id.type === 'Identifier'
|
|
564
|
-
? path.get('id')
|
|
565
|
-
: null
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
function isIdentifierReferenced(ident: any) {
|
|
569
|
-
const b = ident.scope.getBinding(ident.node.name)
|
|
570
|
-
if (b && b.referenced) {
|
|
571
|
-
if (b.path.type === 'FunctionDeclaration') {
|
|
572
|
-
return !b.constantViolations
|
|
573
|
-
.concat(b.referencePaths)
|
|
574
|
-
.every((ref: any) => ref.findParent((p: any) => p === b.path))
|
|
575
|
-
}
|
|
576
|
-
return true
|
|
577
|
-
}
|
|
578
|
-
return false
|
|
579
|
-
}
|
|
580
|
-
function markFunction(path: any, state: any) {
|
|
581
|
-
const ident = getIdentifier(path)
|
|
582
|
-
if (ident && ident.node && isIdentifierReferenced(ident)) {
|
|
583
|
-
state.refs.add(ident)
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
function markImport(path: any, state: any) {
|
|
587
|
-
const local = path.get('local')
|
|
588
|
-
if (isIdentifierReferenced(local)) {
|
|
589
|
-
state.refs.add(local)
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
function getRouteConfigGenerateOptions(path: any): t.ObjectExpression | void {
|
|
594
|
-
const tryOptions = (node: any): t.ObjectExpression | void => {
|
|
595
|
-
if (t.isIdentifier(node)) {
|
|
596
|
-
const initNode = path.scope.getBinding(node.name)?.path.node
|
|
597
|
-
if (t.isVariableDeclarator(initNode)) {
|
|
598
|
-
return tryOptions(initNode.init)
|
|
599
|
-
}
|
|
600
|
-
} else if (t.isObjectExpression(node)) {
|
|
601
|
-
return node
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
return
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
if (
|
|
608
|
-
t.isMemberExpression(path.parentPath.node) &&
|
|
609
|
-
t.isCallExpression(path.parentPath.parentPath?.node)
|
|
610
|
-
) {
|
|
611
|
-
const options = path.parentPath.parentPath?.node.arguments[0]
|
|
612
|
-
|
|
613
|
-
return tryOptions(options)
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
function getRouteOptions(path: any): t.ObjectExpression | void {
|
|
618
|
-
const tryOptions = (node: any): t.ObjectExpression | void => {
|
|
619
|
-
if (t.isIdentifier(node)) {
|
|
620
|
-
const initNode = path.scope.getBinding(node.name)?.path.node
|
|
621
|
-
if (t.isVariableDeclarator(initNode)) {
|
|
622
|
-
return tryOptions(initNode.init)
|
|
623
|
-
}
|
|
624
|
-
} else if (t.isObjectExpression(node)) {
|
|
625
|
-
return node
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
return
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
if (t.isCallExpression(path.parentPath?.node)) {
|
|
632
|
-
const options = path.parentPath?.node.arguments[0]
|
|
633
|
-
|
|
634
|
-
return tryOptions(options)
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
// All credit for this amazing function goes to the Next.js team
|
|
639
|
-
// (and the Solid.js team for their derivative work).
|
|
640
|
-
// https://github.com/vercel/next.js/blob/canary/packages/next/build/babel/plugins/next-ssg-transform.ts
|
|
641
|
-
// https://github.com/solidjs/solid-start/blob/main/packages/start/server/routeData.js
|
|
642
|
-
|
|
643
|
-
function cleanUnusedCode(
|
|
644
|
-
programPath: babel.NodePath<babel.types.Program>,
|
|
645
|
-
state: any,
|
|
646
|
-
keepExports: string[] = [],
|
|
647
|
-
) {
|
|
648
|
-
state.refs = new Set()
|
|
649
|
-
state.done = false
|
|
650
|
-
|
|
651
|
-
function markVariable(variablePath: any, variableState: any) {
|
|
652
|
-
if (variablePath.node.id.type === 'Identifier') {
|
|
653
|
-
const local = variablePath.get('id')
|
|
654
|
-
if (isIdentifierReferenced(local)) {
|
|
655
|
-
variableState.refs.add(local)
|
|
656
|
-
}
|
|
657
|
-
} else if (variablePath.node.id.type === 'ObjectPattern') {
|
|
658
|
-
const pattern = variablePath.get('id')
|
|
659
|
-
const properties: any = pattern.get('properties')
|
|
660
|
-
properties.forEach((p: any) => {
|
|
661
|
-
const local = p.get(
|
|
662
|
-
p.node.type === 'ObjectProperty'
|
|
663
|
-
? 'value'
|
|
664
|
-
: p.node.type === 'RestElement'
|
|
665
|
-
? 'argument'
|
|
666
|
-
: (function () {
|
|
667
|
-
throw new Error('invariant')
|
|
668
|
-
})(),
|
|
669
|
-
)
|
|
670
|
-
if (isIdentifierReferenced(local)) {
|
|
671
|
-
variableState.refs.add(local)
|
|
672
|
-
}
|
|
673
|
-
})
|
|
674
|
-
} else if (variablePath.node.id.type === 'ArrayPattern') {
|
|
675
|
-
const pattern = variablePath.get('id')
|
|
676
|
-
const elements: any = pattern.get('elements')
|
|
677
|
-
elements.forEach((e: any) => {
|
|
678
|
-
let local
|
|
679
|
-
if (e.node && e.node.type === 'Identifier') {
|
|
680
|
-
local = e
|
|
681
|
-
} else if (e.node && e.node.type === 'RestElement') {
|
|
682
|
-
local = e.get('argument')
|
|
683
|
-
} else {
|
|
684
|
-
return
|
|
685
|
-
}
|
|
686
|
-
if (isIdentifierReferenced(local)) {
|
|
687
|
-
variableState.refs.add(local)
|
|
688
|
-
}
|
|
689
|
-
})
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
// Mark all variables and functions if used
|
|
694
|
-
programPath.traverse(
|
|
695
|
-
{
|
|
696
|
-
VariableDeclarator: markVariable,
|
|
697
|
-
FunctionDeclaration: markFunction,
|
|
698
|
-
FunctionExpression: markFunction,
|
|
699
|
-
ArrowFunctionExpression: markFunction,
|
|
700
|
-
ImportSpecifier: markImport,
|
|
701
|
-
ImportDefaultSpecifier: markImport,
|
|
702
|
-
ImportNamespaceSpecifier: markImport,
|
|
703
|
-
ExportDefaultDeclaration: markImport,
|
|
704
|
-
// ExportNamedDeclaration(path, state) {
|
|
705
|
-
// if (t.isVariableDeclaration(path.node.declaration)) {
|
|
706
|
-
// if (t.isVariableDeclarator(path.node.declaration.declarations?.[0])) {
|
|
707
|
-
// if (t.isIdentifier(path.node.declaration.declarations[0].id)) {
|
|
708
|
-
// if (
|
|
709
|
-
// keepExports.includes(
|
|
710
|
-
// path.node.declaration.declarations[0].id.name,
|
|
711
|
-
// )
|
|
712
|
-
// ) {
|
|
713
|
-
// return
|
|
714
|
-
// }
|
|
715
|
-
// }
|
|
716
|
-
// path.replaceWith(path.node.declaration.declarations[0])
|
|
717
|
-
// return
|
|
718
|
-
// }
|
|
719
|
-
// }
|
|
720
|
-
// path.remove()
|
|
721
|
-
// },
|
|
722
|
-
ImportDeclaration: (path) => {
|
|
723
|
-
if (path.node.source.value.endsWith('.css')) {
|
|
724
|
-
path.remove()
|
|
725
|
-
}
|
|
726
|
-
},
|
|
727
|
-
},
|
|
728
|
-
state,
|
|
729
|
-
)
|
|
730
|
-
|
|
731
|
-
// Sweet all of the remaining references and remove unused ones
|
|
732
|
-
const refs: any = state.refs
|
|
733
|
-
let count: number
|
|
734
|
-
function sweepFunction(sweepPath: any) {
|
|
735
|
-
const ident = getIdentifier(sweepPath)
|
|
736
|
-
if (
|
|
737
|
-
ident &&
|
|
738
|
-
ident.node &&
|
|
739
|
-
refs.has(ident) &&
|
|
740
|
-
!isIdentifierReferenced(ident)
|
|
741
|
-
) {
|
|
742
|
-
++count
|
|
743
|
-
if (
|
|
744
|
-
t.isAssignmentExpression(sweepPath.parentPath) ||
|
|
745
|
-
t.isVariableDeclarator(sweepPath.parentPath)
|
|
746
|
-
) {
|
|
747
|
-
sweepPath.parentPath.remove()
|
|
748
|
-
} else {
|
|
749
|
-
sweepPath.remove()
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
function sweepImport(sweepPath: any) {
|
|
754
|
-
const local = sweepPath.get('local')
|
|
755
|
-
if (refs.has(local) && !isIdentifierReferenced(local)) {
|
|
756
|
-
++count
|
|
757
|
-
sweepPath.remove()
|
|
758
|
-
if (sweepPath.parent.specifiers.length === 0) {
|
|
759
|
-
sweepPath.parentPath.remove()
|
|
760
|
-
}
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
do {
|
|
764
|
-
programPath.scope.crawl()
|
|
765
|
-
count = 0
|
|
766
|
-
programPath.traverse({
|
|
767
|
-
VariableDeclarator(variablePath) {
|
|
768
|
-
if (variablePath.node.id.type === 'Identifier') {
|
|
769
|
-
const local = variablePath.get('id')
|
|
770
|
-
if (refs.has(local) && !isIdentifierReferenced(local)) {
|
|
771
|
-
++count
|
|
772
|
-
|
|
773
|
-
variablePath.remove()
|
|
774
|
-
}
|
|
775
|
-
} else if (variablePath.node.id.type === 'ObjectPattern') {
|
|
776
|
-
const pattern = variablePath.get('id')
|
|
777
|
-
const beforeCount = count
|
|
778
|
-
const properties: any = pattern.get('properties')
|
|
779
|
-
properties.forEach((p: any) => {
|
|
780
|
-
const local = p.get(
|
|
781
|
-
p.node.type === 'ObjectProperty'
|
|
782
|
-
? 'value'
|
|
783
|
-
: p.node.type === 'RestElement'
|
|
784
|
-
? 'argument'
|
|
785
|
-
: (function () {
|
|
786
|
-
throw new Error('invariant')
|
|
787
|
-
})(),
|
|
788
|
-
)
|
|
789
|
-
if (refs.has(local) && !isIdentifierReferenced(local)) {
|
|
790
|
-
++count
|
|
791
|
-
p.remove()
|
|
792
|
-
}
|
|
793
|
-
})
|
|
794
|
-
if (
|
|
795
|
-
beforeCount !== count &&
|
|
796
|
-
(pattern.get('properties') as any).length < 1
|
|
797
|
-
) {
|
|
798
|
-
variablePath.remove()
|
|
799
|
-
}
|
|
800
|
-
} else if (variablePath.node.id.type === 'ArrayPattern') {
|
|
801
|
-
const pattern = variablePath.get('id')
|
|
802
|
-
const beforeCount = count
|
|
803
|
-
const elements: any = pattern.get('elements')
|
|
804
|
-
elements.forEach((e: any) => {
|
|
805
|
-
let local
|
|
806
|
-
if (e.node && e.node.type === 'Identifier') {
|
|
807
|
-
local = e
|
|
808
|
-
} else if (e.node && e.node.type === 'RestElement') {
|
|
809
|
-
local = e.get('argument')
|
|
810
|
-
} else {
|
|
811
|
-
return
|
|
812
|
-
}
|
|
813
|
-
if (refs.has(local) && !isIdentifierReferenced(local)) {
|
|
814
|
-
++count
|
|
815
|
-
|
|
816
|
-
e.remove()
|
|
817
|
-
}
|
|
818
|
-
})
|
|
819
|
-
if (
|
|
820
|
-
beforeCount !== count &&
|
|
821
|
-
(pattern.get('elements') as any).length < 1
|
|
822
|
-
) {
|
|
823
|
-
variablePath.remove()
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
},
|
|
827
|
-
FunctionDeclaration: sweepFunction,
|
|
828
|
-
FunctionExpression: sweepFunction,
|
|
829
|
-
ArrowFunctionExpression: sweepFunction,
|
|
830
|
-
ImportSpecifier: sweepImport,
|
|
831
|
-
ImportDefaultSpecifier: sweepImport,
|
|
832
|
-
ImportNamespaceSpecifier: sweepImport,
|
|
833
|
-
})
|
|
834
|
-
} while (count)
|
|
835
|
-
|
|
836
|
-
// Do we need the * import for react?
|
|
837
|
-
let hasReact = false
|
|
838
|
-
|
|
839
|
-
// Mark react elements as having react
|
|
840
|
-
programPath.traverse({
|
|
841
|
-
JSXElement(path) {
|
|
842
|
-
hasReact = true
|
|
843
|
-
},
|
|
844
|
-
})
|
|
845
|
-
|
|
846
|
-
if (!hasReact) {
|
|
847
|
-
// Mark all variables and functions if used
|
|
848
|
-
programPath.traverse({
|
|
849
|
-
ImportDeclaration(path) {
|
|
850
|
-
if (
|
|
851
|
-
t.isStringLiteral(path.node.source) &&
|
|
852
|
-
path.node.source.value === 'react' &&
|
|
853
|
-
t.isImportNamespaceSpecifier(path.node.specifiers[0])
|
|
854
|
-
) {
|
|
855
|
-
path.remove()
|
|
856
|
-
}
|
|
857
|
-
},
|
|
858
|
-
})
|
|
859
|
-
}
|
|
860
|
-
}
|