@tanstack/router-cli 0.0.1-beta.69 → 1.0.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.
- 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 -1
- 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/watch.ts
CHANGED
|
@@ -5,41 +5,44 @@ import { generator } from './generator'
|
|
|
5
5
|
|
|
6
6
|
export async function watch() {
|
|
7
7
|
const configWatcher = chokidar.watch(
|
|
8
|
-
path.resolve(process.cwd(), 'tsr.config.
|
|
8
|
+
path.resolve(process.cwd(), 'tsr.config.json'),
|
|
9
9
|
)
|
|
10
10
|
|
|
11
|
-
let watcher = new chokidar.FSWatcher()
|
|
11
|
+
let watcher = new chokidar.FSWatcher({})
|
|
12
12
|
|
|
13
13
|
const generatorWatcher = async () => {
|
|
14
14
|
const config = await getConfig()
|
|
15
15
|
|
|
16
16
|
watcher.close()
|
|
17
17
|
|
|
18
|
-
console.
|
|
18
|
+
console.info(`TSR: Watching routes (${config.routesDirectory})...`)
|
|
19
19
|
watcher = chokidar.watch(config.routesDirectory)
|
|
20
20
|
|
|
21
21
|
watcher.on('ready', async () => {
|
|
22
|
-
try {
|
|
23
|
-
await generator(config)
|
|
24
|
-
} catch (err) {
|
|
25
|
-
console.error(err)
|
|
26
|
-
console.log()
|
|
27
|
-
}
|
|
28
|
-
|
|
29
22
|
const handle = async () => {
|
|
30
23
|
try {
|
|
31
24
|
await generator(config)
|
|
32
25
|
} catch (err) {
|
|
33
26
|
console.error(err)
|
|
34
|
-
console.
|
|
27
|
+
console.info()
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
await handle()
|
|
32
|
+
|
|
33
|
+
let timeout: ReturnType<typeof setTimeout>
|
|
34
|
+
|
|
35
|
+
const deduped = (file: string) => {
|
|
36
|
+
if (timeout) {
|
|
37
|
+
clearTimeout(timeout)
|
|
35
38
|
}
|
|
39
|
+
|
|
40
|
+
timeout = setTimeout(handle, 10)
|
|
36
41
|
}
|
|
37
42
|
|
|
38
|
-
watcher.on('change',
|
|
39
|
-
watcher.on('add',
|
|
40
|
-
watcher.on('
|
|
41
|
-
watcher.on('unlink', handle)
|
|
42
|
-
watcher.on('unlinkDir', handle)
|
|
43
|
+
watcher.on('change', deduped)
|
|
44
|
+
watcher.on('add', deduped)
|
|
45
|
+
watcher.on('unlink', deduped)
|
|
43
46
|
})
|
|
44
47
|
}
|
|
45
48
|
|
|
@@ -1,584 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* router-cli
|
|
3
|
-
*
|
|
4
|
-
* Copyright (c) TanStack
|
|
5
|
-
*
|
|
6
|
-
* This source code is licensed under the MIT license found in the
|
|
7
|
-
* LICENSE.md file in the root directory of this source tree.
|
|
8
|
-
*
|
|
9
|
-
* @license MIT
|
|
10
|
-
*/
|
|
11
|
-
'use strict';
|
|
12
|
-
|
|
13
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
14
|
-
|
|
15
|
-
var babel = require('@babel/core');
|
|
16
|
-
var t = require('@babel/types');
|
|
17
|
-
var syntaxTS = require('@babel/plugin-syntax-typescript');
|
|
18
|
-
var generator = require('./generator.js');
|
|
19
|
-
var path = require('path');
|
|
20
|
-
|
|
21
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
22
|
-
|
|
23
|
-
function _interopNamespace(e) {
|
|
24
|
-
if (e && e.__esModule) return e;
|
|
25
|
-
var n = Object.create(null);
|
|
26
|
-
if (e) {
|
|
27
|
-
Object.keys(e).forEach(function (k) {
|
|
28
|
-
if (k !== 'default') {
|
|
29
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
30
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
31
|
-
enumerable: true,
|
|
32
|
-
get: function () { return e[k]; }
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
n["default"] = e;
|
|
38
|
-
return Object.freeze(n);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
var babel__namespace = /*#__PURE__*/_interopNamespace(babel);
|
|
42
|
-
var t__namespace = /*#__PURE__*/_interopNamespace(t);
|
|
43
|
-
var syntaxTS__default = /*#__PURE__*/_interopDefaultLegacy(syntaxTS);
|
|
44
|
-
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
45
|
-
|
|
46
|
-
const isolatedProperties = ['component', 'errorComponent', 'pendingComponent'];
|
|
47
|
-
const getBasePlugins = () => [[syntaxTS__default["default"], {
|
|
48
|
-
isTSX: true
|
|
49
|
-
}]];
|
|
50
|
-
async function ensureBoilerplate(node, code) {
|
|
51
|
-
const relativeImportPath = path__default["default"].relative(node.fullDir, node.genPathNoExt);
|
|
52
|
-
const originalFile = await babel__namespace.transformAsync(code, {
|
|
53
|
-
configFile: false,
|
|
54
|
-
babelrc: false,
|
|
55
|
-
plugins: [...getBasePlugins()]
|
|
56
|
-
});
|
|
57
|
-
const file = await babel__namespace.transformAsync(code, {
|
|
58
|
-
configFile: false,
|
|
59
|
-
babelrc: false,
|
|
60
|
-
plugins: [...getBasePlugins(), {
|
|
61
|
-
visitor: {
|
|
62
|
-
Program: {
|
|
63
|
-
enter(programPath) {
|
|
64
|
-
// Remove all properties except for our isolated one
|
|
65
|
-
if (node.isRoot) {
|
|
66
|
-
let foundImport = false;
|
|
67
|
-
programPath.traverse({
|
|
68
|
-
ImportSpecifier(importPath) {
|
|
69
|
-
if (t__namespace.isIdentifier(importPath.node.imported) && importPath.node.imported.name === 'Route') {
|
|
70
|
-
foundImport = true;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
if (!foundImport) {
|
|
75
|
-
programPath.node.body.unshift(babel__namespace.template.statement(`import { Route } from '@tanstack/react-router'`)());
|
|
76
|
-
}
|
|
77
|
-
} else {
|
|
78
|
-
let foundImport = false;
|
|
79
|
-
programPath.traverse({
|
|
80
|
-
ImportSpecifier(importPath) {
|
|
81
|
-
if (t__namespace.isIdentifier(importPath.node.imported) && importPath.node.imported.name === 'route') {
|
|
82
|
-
foundImport = true;
|
|
83
|
-
if (t__namespace.isImportDeclaration(importPath.parentPath.node)) {
|
|
84
|
-
if (importPath.parentPath.node.source.value !== relativeImportPath) {
|
|
85
|
-
importPath.parentPath.node.source.value = relativeImportPath;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
if (!foundImport) {
|
|
92
|
-
programPath.node.body.unshift(babel__namespace.template.statement(`import { Route } from '${relativeImportPath.replace(/\\/gi, '/')}'`)());
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}]
|
|
99
|
-
});
|
|
100
|
-
const separator = 'new Route(';
|
|
101
|
-
if (!originalFile?.code) {
|
|
102
|
-
return `${file?.code}\n\n${separator}{\n\n})`;
|
|
103
|
-
}
|
|
104
|
-
const originalHead = originalFile?.code?.substring(0, originalFile?.code?.indexOf(separator));
|
|
105
|
-
const generatedHead = file?.code?.substring(0, file?.code?.indexOf(separator));
|
|
106
|
-
if (originalHead !== generatedHead) {
|
|
107
|
-
return `${generatedHead}\n\n${originalFile?.code?.substring(originalFile?.code?.indexOf(separator))}`;
|
|
108
|
-
}
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
async function isolateOptionToExport(node, code, opts) {
|
|
112
|
-
return (await babel__namespace.transformAsync(code, {
|
|
113
|
-
configFile: false,
|
|
114
|
-
babelrc: false,
|
|
115
|
-
plugins: [...getBasePlugins(), plugin()],
|
|
116
|
-
ast: true
|
|
117
|
-
}))?.code;
|
|
118
|
-
function plugin() {
|
|
119
|
-
return {
|
|
120
|
-
visitor: {
|
|
121
|
-
Program: {
|
|
122
|
-
enter(programPath, state) {
|
|
123
|
-
// If we're the root, handle things a bit differently
|
|
124
|
-
if (node.isRoot) {
|
|
125
|
-
programPath.traverse({
|
|
126
|
-
Identifier(path) {
|
|
127
|
-
if (path.node.name === 'Route' && t__namespace.isCallExpression(path.parentPath.node)) {
|
|
128
|
-
const options = getRouteOptions(path);
|
|
129
|
-
if (options) {
|
|
130
|
-
const property = options.properties.find(property => {
|
|
131
|
-
return t__namespace.isObjectProperty(property) && t__namespace.isIdentifier(property.key) && property.key.name === opts.isolate;
|
|
132
|
-
});
|
|
133
|
-
if (t__namespace.isObjectProperty(property)) {
|
|
134
|
-
const program = path.findParent(d => d.isProgram());
|
|
135
|
-
if (program?.isProgram()) {
|
|
136
|
-
program.node.body.push(babel__namespace.template.statement(`export const ${opts.isolate} = $VAR`)({
|
|
137
|
-
$VAR: property.value
|
|
138
|
-
}));
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
path.findParent(d => d.isExpressionStatement())?.remove();
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// We're not in the root, handle things normally
|
|
149
|
-
if (!node.isRoot) {
|
|
150
|
-
// Remove all properties except for our isolated one
|
|
151
|
-
programPath.traverse({
|
|
152
|
-
Identifier(path) {
|
|
153
|
-
if (path.node.name === 'generate') {
|
|
154
|
-
const options = getRouteConfigGenerateOptions(path);
|
|
155
|
-
if (options) {
|
|
156
|
-
const property = options.properties.find(property => {
|
|
157
|
-
return t__namespace.isObjectProperty(property) && t__namespace.isIdentifier(property.key) && property.key.name === opts.isolate;
|
|
158
|
-
});
|
|
159
|
-
if (t__namespace.isObjectProperty(property) && t__namespace.isIdentifier(property.key)) {
|
|
160
|
-
if (property.key.name === opts.isolate) {
|
|
161
|
-
const program = path.findParent(d => d.isProgram());
|
|
162
|
-
if (program?.isProgram()) {
|
|
163
|
-
program.node.body.push(babel__namespace.template.statement(`export const ${opts.isolate} = $VAR`)({
|
|
164
|
-
$VAR: property.value
|
|
165
|
-
}));
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
path.findParent(d => d.isExpressionStatement())?.remove();
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
});
|
|
174
|
-
}
|
|
175
|
-
cleanUnusedCode(programPath, state, [opts.isolate]);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
async function detectExports(code) {
|
|
183
|
-
let exported = [];
|
|
184
|
-
|
|
185
|
-
// try {
|
|
186
|
-
await babel__namespace.transformAsync(code, {
|
|
187
|
-
configFile: false,
|
|
188
|
-
babelrc: false,
|
|
189
|
-
plugins: [...getBasePlugins(), {
|
|
190
|
-
visitor: {
|
|
191
|
-
ExportNamedDeclaration(path) {
|
|
192
|
-
if (t__namespace.isVariableDeclaration(path.node.declaration)) {
|
|
193
|
-
if (t__namespace.isVariableDeclarator(path.node.declaration.declarations?.[0])) {
|
|
194
|
-
if (t__namespace.isIdentifier(path.node.declaration.declarations[0].id)) {
|
|
195
|
-
exported.push(path.node.declaration.declarations[0].id.name);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}],
|
|
202
|
-
ast: true
|
|
203
|
-
});
|
|
204
|
-
return exported;
|
|
205
|
-
}
|
|
206
|
-
async function generateRouteConfig(node, routeCode, imports, clientOnly) {
|
|
207
|
-
const relativeParentRoutePath = clientOnly ? node.parent ? generator.removeExt(path__default["default"].relative(node.genDir, path__default["default"].resolve(node.parent?.genDir, node.parent?.clientFilename))) : `./${generator.rootRouteClientName}` : node.parent ? generator.removeExt(path__default["default"].relative(node.genDir, path__default["default"].resolve(node.parent?.genDir, node.parent?.filename))) : `./${generator.rootRouteName}`;
|
|
208
|
-
const pathName = node.isRoot ? undefined : node.fileNameNoExt.startsWith('__') ? undefined : node.fileNameNoExt === 'index' ? '/' : node.fileNameNoExt;
|
|
209
|
-
const routeId = node.isRoot ? undefined : node.fileNameNoExt;
|
|
210
|
-
function plugin() {
|
|
211
|
-
return {
|
|
212
|
-
visitor: {
|
|
213
|
-
Program: {
|
|
214
|
-
enter(programPath, state) {
|
|
215
|
-
// Remove all of the isolated import properties from the config
|
|
216
|
-
programPath.traverse({
|
|
217
|
-
ImportSpecifier(path) {
|
|
218
|
-
if (t__namespace.isIdentifier(path.node.imported)) {
|
|
219
|
-
if (!node.isRoot) {
|
|
220
|
-
if (path.node.imported.name === 'route') {
|
|
221
|
-
path.parentPath.remove();
|
|
222
|
-
const program = path.findParent(d => d.isProgram());
|
|
223
|
-
if (program?.isProgram()) {
|
|
224
|
-
program.node.body.unshift(babel__namespace.template.statement(`import { route as parentRoute } from '$IMPORT'`)({
|
|
225
|
-
$IMPORT: relativeParentRoutePath
|
|
226
|
-
}));
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
},
|
|
232
|
-
Identifier(iPath) {
|
|
233
|
-
let options;
|
|
234
|
-
if (node.isRoot) {
|
|
235
|
-
if (iPath.node.name === 'Route') {
|
|
236
|
-
if (t__namespace.isCallExpression(iPath.parentPath.node)) {
|
|
237
|
-
if (t__namespace.isExpressionStatement(iPath.parentPath.parentPath?.node)) {
|
|
238
|
-
iPath.parentPath.parentPath?.replaceWith(t__namespace.variableDeclaration('const', [t__namespace.variableDeclarator(t__namespace.identifier('route'), iPath.parentPath.node)]));
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
} else {
|
|
243
|
-
if (iPath.node.name === 'generate') {
|
|
244
|
-
if (t__namespace.isMemberExpression(iPath.parentPath.node)) {
|
|
245
|
-
if (t__namespace.isIdentifier(iPath.parentPath.node.object)) {
|
|
246
|
-
iPath.node.name = 'Route';
|
|
247
|
-
iPath.parentPath.node.object.name = 'parentRoute';
|
|
248
|
-
options = getRouteConfigGenerateOptions(iPath);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
if (options) {
|
|
254
|
-
options.properties = [...(pathName ? [t__namespace.objectProperty(t__namespace.identifier('path'), t__namespace.stringLiteral(pathName))] : routeId ? [t__namespace.objectProperty(t__namespace.identifier('id'), t__namespace.stringLiteral(routeId))] : []), ...options.properties.map(property => {
|
|
255
|
-
if (t__namespace.isObjectProperty(property) && t__namespace.isIdentifier(property.key) && isolatedProperties.includes(property.key.name)) {
|
|
256
|
-
const key = property.key.name;
|
|
257
|
-
if (key === 'loader') {
|
|
258
|
-
if (clientOnly) {
|
|
259
|
-
return t__namespace.objectProperty(t__namespace.identifier('loader'), t__namespace.tSAsExpression(t__namespace.booleanLiteral(true), t__namespace.tsAnyKeyword()));
|
|
260
|
-
}
|
|
261
|
-
return t__namespace.objectProperty(t__namespace.identifier(key), babel__namespace.template.expression(`(...args) => import('./${path__default["default"].relative(node.genDir, node.genPathNoExt)}-${key}').then(d => d.${key}.apply(d.${key}, (args as any)))`, {
|
|
262
|
-
plugins: ['typescript']
|
|
263
|
-
})({}));
|
|
264
|
-
}
|
|
265
|
-
if (key === 'action') {
|
|
266
|
-
if (clientOnly) {
|
|
267
|
-
return t__namespace.objectProperty(t__namespace.identifier('action'), t__namespace.tSAsExpression(t__namespace.booleanLiteral(true), t__namespace.tSAnyKeyword()));
|
|
268
|
-
}
|
|
269
|
-
return t__namespace.objectProperty(t__namespace.identifier(key), babel__namespace.template.expression(`(...payload: Parameters<typeof import('./${path__default["default"].relative(node.genDir, node.genPathNoExt)}-${key}').action>) => import('./${path__default["default"].relative(node.genDir, node.genPathNoExt)}-${key}').then(d => d.${key}.apply(d.${key}, (payload as any)))`, {
|
|
270
|
-
plugins: ['typescript']
|
|
271
|
-
})({}));
|
|
272
|
-
}
|
|
273
|
-
if (clientOnly) {
|
|
274
|
-
return t__namespace.objectProperty(t__namespace.identifier(key), babel__namespace.template.expression(`
|
|
275
|
-
lazy(() => import('./${path__default["default"].relative(node.genDir, node.genPathNoExt)}-${key}').then(d => ({ default: d.${key} }) ))`)());
|
|
276
|
-
}
|
|
277
|
-
return t__namespace.objectProperty(t__namespace.identifier(key), property.value);
|
|
278
|
-
}
|
|
279
|
-
return property;
|
|
280
|
-
})];
|
|
281
|
-
const program = iPath.findParent(d => d.isProgram());
|
|
282
|
-
if (program?.isProgram() && options) {
|
|
283
|
-
const index = program.node.body.findIndex(d => d.start === iPath.parentPath.parentPath?.node.start);
|
|
284
|
-
if (node.isRoot) {
|
|
285
|
-
program.node.body[index] = babel__namespace.template.statement(`const route = new Route(
|
|
286
|
-
$OPTIONS
|
|
287
|
-
)`)({
|
|
288
|
-
$OPTIONS: options
|
|
289
|
-
});
|
|
290
|
-
} else {
|
|
291
|
-
program.node.body[index] = babel__namespace.template.statement(`const route = new Route(
|
|
292
|
-
$OPTIONS
|
|
293
|
-
)`)({
|
|
294
|
-
$OPTIONS: options
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
});
|
|
301
|
-
programPath.node.body.unshift(babel__namespace.template.statement(`import { lazy } from '@tanstack/react-router'`)());
|
|
302
|
-
|
|
303
|
-
// Add the route exports
|
|
304
|
-
programPath.node.body.push(babel__namespace.template.statement(clientOnly ? `export { route, route as ${node.variable}Route }` : `export { route }`)());
|
|
305
|
-
cleanUnusedCode(programPath, state, ['route', `${node.variable}Route`]);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
const code = (await babel__namespace.transformAsync(routeCode, {
|
|
312
|
-
configFile: false,
|
|
313
|
-
babelrc: false,
|
|
314
|
-
plugins: [...getBasePlugins(), plugin()],
|
|
315
|
-
ast: true
|
|
316
|
-
}))?.code;
|
|
317
|
-
if (!code) {
|
|
318
|
-
throw new Error('Error while generating a route file!');
|
|
319
|
-
}
|
|
320
|
-
return code;
|
|
321
|
-
}
|
|
322
|
-
function getIdentifier(path) {
|
|
323
|
-
const parentPath = path.parentPath;
|
|
324
|
-
if (parentPath.type === 'VariableDeclarator') {
|
|
325
|
-
const pp = parentPath;
|
|
326
|
-
const name = pp.get('id');
|
|
327
|
-
return name.node.type === 'Identifier' ? name : null;
|
|
328
|
-
}
|
|
329
|
-
if (parentPath.type === 'AssignmentExpression') {
|
|
330
|
-
const pp = parentPath;
|
|
331
|
-
const name = pp.get('left');
|
|
332
|
-
return name.node.type === 'Identifier' ? name : null;
|
|
333
|
-
}
|
|
334
|
-
if (path.node.type === 'ArrowFunctionExpression') {
|
|
335
|
-
return null;
|
|
336
|
-
}
|
|
337
|
-
return path.node.id && path.node.id.type === 'Identifier' ? path.get('id') : null;
|
|
338
|
-
}
|
|
339
|
-
function isIdentifierReferenced(ident) {
|
|
340
|
-
const b = ident.scope.getBinding(ident.node.name);
|
|
341
|
-
if (b && b.referenced) {
|
|
342
|
-
if (b.path.type === 'FunctionDeclaration') {
|
|
343
|
-
return !b.constantViolations.concat(b.referencePaths).every(ref => ref.findParent(p => p === b.path));
|
|
344
|
-
}
|
|
345
|
-
return true;
|
|
346
|
-
}
|
|
347
|
-
return false;
|
|
348
|
-
}
|
|
349
|
-
function markFunction(path, state) {
|
|
350
|
-
const ident = getIdentifier(path);
|
|
351
|
-
if (ident && ident.node && isIdentifierReferenced(ident)) {
|
|
352
|
-
state.refs.add(ident);
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
function markImport(path, state) {
|
|
356
|
-
const local = path.get('local');
|
|
357
|
-
if (isIdentifierReferenced(local)) {
|
|
358
|
-
state.refs.add(local);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
function getRouteConfigGenerateOptions(path) {
|
|
362
|
-
const tryOptions = node => {
|
|
363
|
-
if (t__namespace.isIdentifier(node)) {
|
|
364
|
-
const initNode = path.scope.getBinding(node.name)?.path.node;
|
|
365
|
-
if (t__namespace.isVariableDeclarator(initNode)) {
|
|
366
|
-
return tryOptions(initNode.init);
|
|
367
|
-
}
|
|
368
|
-
} else if (t__namespace.isObjectExpression(node)) {
|
|
369
|
-
return node;
|
|
370
|
-
}
|
|
371
|
-
return;
|
|
372
|
-
};
|
|
373
|
-
if (t__namespace.isMemberExpression(path.parentPath.node) && t__namespace.isCallExpression(path.parentPath.parentPath?.node)) {
|
|
374
|
-
const options = path.parentPath.parentPath?.node.arguments[0];
|
|
375
|
-
return tryOptions(options);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
function getRouteOptions(path) {
|
|
379
|
-
const tryOptions = node => {
|
|
380
|
-
if (t__namespace.isIdentifier(node)) {
|
|
381
|
-
const initNode = path.scope.getBinding(node.name)?.path.node;
|
|
382
|
-
if (t__namespace.isVariableDeclarator(initNode)) {
|
|
383
|
-
return tryOptions(initNode.init);
|
|
384
|
-
}
|
|
385
|
-
} else if (t__namespace.isObjectExpression(node)) {
|
|
386
|
-
return node;
|
|
387
|
-
}
|
|
388
|
-
return;
|
|
389
|
-
};
|
|
390
|
-
if (t__namespace.isCallExpression(path.parentPath?.node)) {
|
|
391
|
-
const options = path.parentPath?.node.arguments[0];
|
|
392
|
-
return tryOptions(options);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// All credit for this amazing function goes to the Next.js team
|
|
397
|
-
// (and the Solid.js team for their derivative work).
|
|
398
|
-
// https://github.com/vercel/next.js/blob/canary/packages/next/build/babel/plugins/next-ssg-transform.ts
|
|
399
|
-
// https://github.com/solidjs/solid-start/blob/main/packages/start/server/routeData.js
|
|
400
|
-
|
|
401
|
-
function cleanUnusedCode(programPath, state, keepExports = []) {
|
|
402
|
-
state.refs = new Set();
|
|
403
|
-
state.done = false;
|
|
404
|
-
function markVariable(variablePath, variableState) {
|
|
405
|
-
if (variablePath.node.id.type === 'Identifier') {
|
|
406
|
-
const local = variablePath.get('id');
|
|
407
|
-
if (isIdentifierReferenced(local)) {
|
|
408
|
-
variableState.refs.add(local);
|
|
409
|
-
}
|
|
410
|
-
} else if (variablePath.node.id.type === 'ObjectPattern') {
|
|
411
|
-
const pattern = variablePath.get('id');
|
|
412
|
-
const properties = pattern.get('properties');
|
|
413
|
-
properties.forEach(p => {
|
|
414
|
-
const local = p.get(p.node.type === 'ObjectProperty' ? 'value' : p.node.type === 'RestElement' ? 'argument' : function () {
|
|
415
|
-
throw new Error('invariant');
|
|
416
|
-
}());
|
|
417
|
-
if (isIdentifierReferenced(local)) {
|
|
418
|
-
variableState.refs.add(local);
|
|
419
|
-
}
|
|
420
|
-
});
|
|
421
|
-
} else if (variablePath.node.id.type === 'ArrayPattern') {
|
|
422
|
-
const pattern = variablePath.get('id');
|
|
423
|
-
const elements = pattern.get('elements');
|
|
424
|
-
elements.forEach(e => {
|
|
425
|
-
let local;
|
|
426
|
-
if (e.node && e.node.type === 'Identifier') {
|
|
427
|
-
local = e;
|
|
428
|
-
} else if (e.node && e.node.type === 'RestElement') {
|
|
429
|
-
local = e.get('argument');
|
|
430
|
-
} else {
|
|
431
|
-
return;
|
|
432
|
-
}
|
|
433
|
-
if (isIdentifierReferenced(local)) {
|
|
434
|
-
variableState.refs.add(local);
|
|
435
|
-
}
|
|
436
|
-
});
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// Mark all variables and functions if used
|
|
441
|
-
programPath.traverse({
|
|
442
|
-
VariableDeclarator: markVariable,
|
|
443
|
-
FunctionDeclaration: markFunction,
|
|
444
|
-
FunctionExpression: markFunction,
|
|
445
|
-
ArrowFunctionExpression: markFunction,
|
|
446
|
-
ImportSpecifier: markImport,
|
|
447
|
-
ImportDefaultSpecifier: markImport,
|
|
448
|
-
ImportNamespaceSpecifier: markImport,
|
|
449
|
-
ExportDefaultDeclaration: markImport,
|
|
450
|
-
// ExportNamedDeclaration(path, state) {
|
|
451
|
-
// if (t.isVariableDeclaration(path.node.declaration)) {
|
|
452
|
-
// if (t.isVariableDeclarator(path.node.declaration.declarations?.[0])) {
|
|
453
|
-
// if (t.isIdentifier(path.node.declaration.declarations[0].id)) {
|
|
454
|
-
// if (
|
|
455
|
-
// keepExports.includes(
|
|
456
|
-
// path.node.declaration.declarations[0].id.name,
|
|
457
|
-
// )
|
|
458
|
-
// ) {
|
|
459
|
-
// return
|
|
460
|
-
// }
|
|
461
|
-
// }
|
|
462
|
-
// path.replaceWith(path.node.declaration.declarations[0])
|
|
463
|
-
// return
|
|
464
|
-
// }
|
|
465
|
-
// }
|
|
466
|
-
// path.remove()
|
|
467
|
-
// },
|
|
468
|
-
ImportDeclaration: path => {
|
|
469
|
-
if (path.node.source.value.endsWith('.css')) {
|
|
470
|
-
path.remove();
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}, state);
|
|
474
|
-
|
|
475
|
-
// Sweet all of the remaining references and remove unused ones
|
|
476
|
-
const refs = state.refs;
|
|
477
|
-
let count;
|
|
478
|
-
function sweepFunction(sweepPath) {
|
|
479
|
-
const ident = getIdentifier(sweepPath);
|
|
480
|
-
if (ident && ident.node && refs.has(ident) && !isIdentifierReferenced(ident)) {
|
|
481
|
-
++count;
|
|
482
|
-
if (t__namespace.isAssignmentExpression(sweepPath.parentPath) || t__namespace.isVariableDeclarator(sweepPath.parentPath)) {
|
|
483
|
-
sweepPath.parentPath.remove();
|
|
484
|
-
} else {
|
|
485
|
-
sweepPath.remove();
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
function sweepImport(sweepPath) {
|
|
490
|
-
const local = sweepPath.get('local');
|
|
491
|
-
if (refs.has(local) && !isIdentifierReferenced(local)) {
|
|
492
|
-
++count;
|
|
493
|
-
sweepPath.remove();
|
|
494
|
-
if (sweepPath.parent.specifiers.length === 0) {
|
|
495
|
-
sweepPath.parentPath.remove();
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
do {
|
|
500
|
-
programPath.scope.crawl();
|
|
501
|
-
count = 0;
|
|
502
|
-
programPath.traverse({
|
|
503
|
-
VariableDeclarator(variablePath) {
|
|
504
|
-
if (variablePath.node.id.type === 'Identifier') {
|
|
505
|
-
const local = variablePath.get('id');
|
|
506
|
-
if (refs.has(local) && !isIdentifierReferenced(local)) {
|
|
507
|
-
++count;
|
|
508
|
-
variablePath.remove();
|
|
509
|
-
}
|
|
510
|
-
} else if (variablePath.node.id.type === 'ObjectPattern') {
|
|
511
|
-
const pattern = variablePath.get('id');
|
|
512
|
-
const beforeCount = count;
|
|
513
|
-
const properties = pattern.get('properties');
|
|
514
|
-
properties.forEach(p => {
|
|
515
|
-
const local = p.get(p.node.type === 'ObjectProperty' ? 'value' : p.node.type === 'RestElement' ? 'argument' : function () {
|
|
516
|
-
throw new Error('invariant');
|
|
517
|
-
}());
|
|
518
|
-
if (refs.has(local) && !isIdentifierReferenced(local)) {
|
|
519
|
-
++count;
|
|
520
|
-
p.remove();
|
|
521
|
-
}
|
|
522
|
-
});
|
|
523
|
-
if (beforeCount !== count && pattern.get('properties').length < 1) {
|
|
524
|
-
variablePath.remove();
|
|
525
|
-
}
|
|
526
|
-
} else if (variablePath.node.id.type === 'ArrayPattern') {
|
|
527
|
-
const pattern = variablePath.get('id');
|
|
528
|
-
const beforeCount = count;
|
|
529
|
-
const elements = pattern.get('elements');
|
|
530
|
-
elements.forEach(e => {
|
|
531
|
-
let local;
|
|
532
|
-
if (e.node && e.node.type === 'Identifier') {
|
|
533
|
-
local = e;
|
|
534
|
-
} else if (e.node && e.node.type === 'RestElement') {
|
|
535
|
-
local = e.get('argument');
|
|
536
|
-
} else {
|
|
537
|
-
return;
|
|
538
|
-
}
|
|
539
|
-
if (refs.has(local) && !isIdentifierReferenced(local)) {
|
|
540
|
-
++count;
|
|
541
|
-
e.remove();
|
|
542
|
-
}
|
|
543
|
-
});
|
|
544
|
-
if (beforeCount !== count && pattern.get('elements').length < 1) {
|
|
545
|
-
variablePath.remove();
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
},
|
|
549
|
-
FunctionDeclaration: sweepFunction,
|
|
550
|
-
FunctionExpression: sweepFunction,
|
|
551
|
-
ArrowFunctionExpression: sweepFunction,
|
|
552
|
-
ImportSpecifier: sweepImport,
|
|
553
|
-
ImportDefaultSpecifier: sweepImport,
|
|
554
|
-
ImportNamespaceSpecifier: sweepImport
|
|
555
|
-
});
|
|
556
|
-
} while (count);
|
|
557
|
-
|
|
558
|
-
// Do we need the * import for react?
|
|
559
|
-
let hasReact = false;
|
|
560
|
-
|
|
561
|
-
// Mark react elements as having react
|
|
562
|
-
programPath.traverse({
|
|
563
|
-
JSXElement(path) {
|
|
564
|
-
hasReact = true;
|
|
565
|
-
}
|
|
566
|
-
});
|
|
567
|
-
if (!hasReact) {
|
|
568
|
-
// Mark all variables and functions if used
|
|
569
|
-
programPath.traverse({
|
|
570
|
-
ImportDeclaration(path) {
|
|
571
|
-
if (t__namespace.isStringLiteral(path.node.source) && path.node.source.value === 'react' && t__namespace.isImportNamespaceSpecifier(path.node.specifiers[0])) {
|
|
572
|
-
path.remove();
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
});
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
exports.detectExports = detectExports;
|
|
580
|
-
exports.ensureBoilerplate = ensureBoilerplate;
|
|
581
|
-
exports.generateRouteConfig = generateRouteConfig;
|
|
582
|
-
exports.isolateOptionToExport = isolateOptionToExport;
|
|
583
|
-
exports.isolatedProperties = isolatedProperties;
|
|
584
|
-
//# sourceMappingURL=transformCode.js.map
|