rsbuild-plugin-react-router 0.2.0 → 0.3.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/README.md +213 -201
- package/dist/451.js +1103 -0
- package/dist/bounded-cache.d.ts +1 -0
- package/dist/build-manifest.d.ts +7 -4
- package/dist/build-output-transforms.d.ts +30 -0
- package/dist/concurrency.d.ts +3 -0
- package/dist/config-imports.d.ts +10 -0
- package/dist/constants.d.ts +3 -0
- package/dist/dev-background-resources.d.ts +38 -0
- package/dist/dev-generation.d.ts +25 -0
- package/dist/dev-runtime-artifacts.d.ts +47 -0
- package/dist/dev-runtime-compilation.d.ts +47 -0
- package/dist/dev-runtime-controller.d.ts +14 -0
- package/dist/dev-runtime-session.d.ts +34 -0
- package/dist/dev-server.d.ts +16 -2
- package/dist/effect-runtime.d.ts +18 -0
- package/dist/export-utils.d.ts +15 -7
- package/dist/index.cjs +13775 -1412
- package/dist/index.d.ts +8 -1
- package/dist/index.js +9429 -1501
- package/dist/lazy-compilation-prewarm.d.ts +25 -0
- package/dist/lazy-compilation.d.ts +6 -0
- package/dist/manifest.d.ts +48 -10
- package/dist/modify-browser-manifest.d.ts +30 -13
- package/dist/parallel-route-transform-protocol.d.ts +25 -0
- package/dist/parallel-route-transform-worker.d.ts +1 -0
- package/dist/parallel-route-transform-worker.js +38 -0
- package/dist/parallel-route-transforms.d.ts +29 -0
- package/dist/performance.d.ts +26 -0
- package/dist/plugin-utils.d.ts +2 -12
- package/dist/prerender-build.d.ts +36 -0
- package/dist/prerender.d.ts +27 -2
- package/dist/react-router-config.d.ts +15 -5
- package/dist/route-artifacts.d.ts +33 -0
- package/dist/route-ast.d.ts +21 -0
- package/dist/route-chunks.d.ts +9 -1
- package/dist/route-component-transform.d.ts +5 -0
- package/dist/route-export-pruning.d.ts +6 -0
- package/dist/route-export-resolution.d.ts +5 -0
- package/dist/route-transform-tasks.d.ts +47 -0
- package/dist/route-watch.d.ts +27 -0
- package/dist/server-build-plan.d.ts +22 -0
- package/dist/server-build-resolution.d.ts +3 -0
- package/dist/server-utils.d.ts +3 -2
- package/dist/ssr-externals.d.ts +1 -0
- package/dist/templates/entry.server.cjs +3 -3
- package/dist/templates/entry.server.js +3 -3
- package/dist/typegen.d.ts +15 -0
- package/dist/types.d.ts +41 -14
- package/dist/virtual-modules.d.ts +2 -0
- package/dist/warnings/warn-on-client-source-maps.d.ts +1 -0
- package/dist/yuku.d.ts +15 -0
- package/package.json +24 -19
- package/src/bounded-cache.ts +18 -0
- package/src/build-manifest.ts +205 -0
- package/src/build-output-transforms.ts +273 -0
- package/src/concurrency.ts +15 -0
- package/src/config-imports.ts +83 -0
- package/src/constants.ts +91 -0
- package/src/dev-background-resources.ts +255 -0
- package/src/dev-generation.ts +690 -0
- package/src/dev-runtime-artifacts.ts +239 -0
- package/src/dev-runtime-compilation.ts +171 -0
- package/src/dev-runtime-controller.ts +542 -0
- package/src/dev-runtime-session.ts +191 -0
- package/src/dev-server.ts +88 -0
- package/src/effect-runtime.ts +130 -0
- package/src/export-utils.ts +278 -0
- package/src/index.ts +990 -0
- package/src/lazy-compilation-prewarm.ts +279 -0
- package/src/lazy-compilation.ts +101 -0
- package/src/manifest.ts +591 -0
- package/src/modify-browser-manifest.ts +246 -0
- package/src/parallel-route-transform-protocol.ts +35 -0
- package/src/parallel-route-transform-worker.ts +82 -0
- package/src/parallel-route-transforms.ts +458 -0
- package/src/performance.ts +254 -0
- package/src/plugin-utils.ts +82 -0
- package/src/prerender-build.ts +687 -0
- package/src/prerender.ts +349 -0
- package/src/react-router-config.ts +245 -0
- package/src/route-artifacts.ts +155 -0
- package/src/route-ast.ts +163 -0
- package/src/route-chunks.ts +857 -0
- package/src/route-component-transform.ts +314 -0
- package/src/route-config.ts +106 -0
- package/src/route-export-pruning.ts +668 -0
- package/src/route-export-resolution.ts +329 -0
- package/src/route-transform-tasks.ts +249 -0
- package/src/route-watch.ts +357 -0
- package/src/server-build-plan.ts +91 -0
- package/src/server-build-resolution.ts +131 -0
- package/src/server-utils.ts +111 -0
- package/src/ssr-externals.ts +59 -0
- package/src/templates/context.ts +12 -0
- package/src/templates/entry.client.tsx +12 -0
- package/src/templates/entry.server.tsx +76 -0
- package/src/typegen.ts +178 -0
- package/src/types.ts +92 -0
- package/src/validation/validate-plugin-order.ts +76 -0
- package/src/virtual-modules.ts +30 -0
- package/src/warnings/warn-on-client-source-maps.ts +96 -0
- package/src/yuku.ts +67 -0
- package/dist/0~rslib-runtime.js +0 -16
- package/dist/babel.d.ts +0 -8
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
import { walk, type ParseResult } from 'yuku-parser';
|
|
2
|
+
import {
|
|
3
|
+
getExportedName,
|
|
4
|
+
getPatternIdentifierNames,
|
|
5
|
+
getProgram,
|
|
6
|
+
removeFromArray,
|
|
7
|
+
type AnyNode,
|
|
8
|
+
type ProgramNode,
|
|
9
|
+
} from './route-ast.js';
|
|
10
|
+
|
|
11
|
+
export function validateDestructuredExports(
|
|
12
|
+
id: AnyNode,
|
|
13
|
+
exportsToRemove: readonly string[]
|
|
14
|
+
): void {
|
|
15
|
+
validateBindingTarget(id, new Set(exportsToRemove));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function invalidDestructureError(name: string): Error {
|
|
19
|
+
return new Error(`Cannot remove destructured export "${name}"`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const assertAllowedBindingName = (
|
|
23
|
+
name: string,
|
|
24
|
+
exportsToRemove: ReadonlySet<string>
|
|
25
|
+
): void => {
|
|
26
|
+
if (exportsToRemove.has(name)) {
|
|
27
|
+
throw invalidDestructureError(name);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const validateRestElement = (
|
|
32
|
+
element: AnyNode,
|
|
33
|
+
exportsToRemove: ReadonlySet<string>
|
|
34
|
+
): void => {
|
|
35
|
+
if (element.argument?.type === 'Identifier' && element.argument.name) {
|
|
36
|
+
assertAllowedBindingName(element.argument.name, exportsToRemove);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const validateObjectProperty = (
|
|
41
|
+
property: AnyNode,
|
|
42
|
+
exportsToRemove: ReadonlySet<string>
|
|
43
|
+
): void => {
|
|
44
|
+
if (property.type === 'RestElement') {
|
|
45
|
+
validateRestElement(property, exportsToRemove);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (property.type === 'Property') {
|
|
49
|
+
validateBindingTarget(
|
|
50
|
+
property.value as AnyNode | null | undefined,
|
|
51
|
+
exportsToRemove
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const validateBindingTarget = (
|
|
57
|
+
node: AnyNode | null | undefined,
|
|
58
|
+
exportsToRemove: ReadonlySet<string>
|
|
59
|
+
): void => {
|
|
60
|
+
if (!node) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
switch (node.type) {
|
|
65
|
+
case 'Identifier':
|
|
66
|
+
if (node.name) {
|
|
67
|
+
assertAllowedBindingName(node.name, exportsToRemove);
|
|
68
|
+
}
|
|
69
|
+
return;
|
|
70
|
+
case 'AssignmentPattern':
|
|
71
|
+
validateBindingTarget(node.left, exportsToRemove);
|
|
72
|
+
return;
|
|
73
|
+
case 'ArrayPattern':
|
|
74
|
+
for (const element of node.elements ?? []) {
|
|
75
|
+
if (element?.type === 'RestElement') {
|
|
76
|
+
validateRestElement(element, exportsToRemove);
|
|
77
|
+
} else {
|
|
78
|
+
validateBindingTarget(element, exportsToRemove);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return;
|
|
82
|
+
case 'ObjectPattern':
|
|
83
|
+
for (const property of node.properties ?? []) {
|
|
84
|
+
validateObjectProperty(property, exportsToRemove);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const getDeclaredNames = (node: AnyNode): Set<string> => {
|
|
90
|
+
const names = new Set<string>();
|
|
91
|
+
if (node.type === 'VariableDeclaration') {
|
|
92
|
+
for (const declarator of node.declarations ?? []) {
|
|
93
|
+
getPatternIdentifierNames(declarator.id, names);
|
|
94
|
+
}
|
|
95
|
+
} else if (
|
|
96
|
+
(node.type === 'FunctionDeclaration' || node.type === 'ClassDeclaration') &&
|
|
97
|
+
node.id?.name
|
|
98
|
+
) {
|
|
99
|
+
names.add(node.id.name);
|
|
100
|
+
} else if (node.type === 'ImportDeclaration') {
|
|
101
|
+
for (const specifier of node.specifiers ?? []) {
|
|
102
|
+
if (specifier.local?.name) {
|
|
103
|
+
names.add(specifier.local.name);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return names;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const isIdentifierDeclaration = (node: AnyNode, parent: AnyNode | null) => {
|
|
111
|
+
if (!parent || node.type !== 'Identifier') {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
if (
|
|
115
|
+
(parent.type === 'FunctionDeclaration' ||
|
|
116
|
+
parent.type === 'FunctionExpression' ||
|
|
117
|
+
parent.type === 'ClassDeclaration' ||
|
|
118
|
+
parent.type === 'ClassExpression') &&
|
|
119
|
+
parent.id === node
|
|
120
|
+
) {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
if (parent.type === 'VariableDeclarator') {
|
|
124
|
+
return Boolean(
|
|
125
|
+
node.name && getPatternIdentifierNames(parent.id).has(node.name)
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
if (
|
|
129
|
+
(parent.type === 'ImportSpecifier' ||
|
|
130
|
+
parent.type === 'ImportDefaultSpecifier' ||
|
|
131
|
+
parent.type === 'ImportNamespaceSpecifier') &&
|
|
132
|
+
parent.local === node
|
|
133
|
+
) {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
if (
|
|
137
|
+
(parent.type === 'FunctionDeclaration' ||
|
|
138
|
+
parent.type === 'FunctionExpression' ||
|
|
139
|
+
parent.type === 'ArrowFunctionExpression') &&
|
|
140
|
+
node.name
|
|
141
|
+
) {
|
|
142
|
+
const name = node.name;
|
|
143
|
+
return (parent.params ?? []).some((param: AnyNode) =>
|
|
144
|
+
getPatternIdentifierNames(param).has(name)
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
const isNonReferenceIdentifier = (node: AnyNode, parent: AnyNode | null) => {
|
|
151
|
+
if (!parent || node.type !== 'Identifier') {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
if (isIdentifierDeclaration(node, parent)) {
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
if (
|
|
158
|
+
parent.type === 'MemberExpression' &&
|
|
159
|
+
parent.property === node &&
|
|
160
|
+
!parent.computed
|
|
161
|
+
) {
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
if (
|
|
165
|
+
parent.type === 'Property' &&
|
|
166
|
+
parent.key === node &&
|
|
167
|
+
!parent.computed &&
|
|
168
|
+
!parent.shorthand
|
|
169
|
+
) {
|
|
170
|
+
return true;
|
|
171
|
+
}
|
|
172
|
+
if (
|
|
173
|
+
parent.type === 'MethodDefinition' &&
|
|
174
|
+
parent.key === node &&
|
|
175
|
+
!parent.computed
|
|
176
|
+
) {
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
if (
|
|
180
|
+
parent.type === 'ExportSpecifier' ||
|
|
181
|
+
parent.type === 'ExportDefaultSpecifier' ||
|
|
182
|
+
parent.type === 'ExportNamespaceSpecifier'
|
|
183
|
+
) {
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
if (parent.type === 'ImportSpecifier' && parent.imported === node) {
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
if (
|
|
190
|
+
parent.type === 'LabeledStatement' ||
|
|
191
|
+
parent.type === 'BreakStatement' ||
|
|
192
|
+
parent.type === 'ContinueStatement'
|
|
193
|
+
) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
return false;
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const isUppercaseName = (name: string): boolean => /^[A-Z]/.test(name);
|
|
200
|
+
|
|
201
|
+
const collectReferencedNames = (node: AnyNode): Set<string> => {
|
|
202
|
+
const referenced = new Set<string>();
|
|
203
|
+
walk(node as never, {
|
|
204
|
+
Identifier(node, ctx) {
|
|
205
|
+
const current = node as unknown as AnyNode;
|
|
206
|
+
const parent = (ctx as { parent?: unknown }).parent as AnyNode | null;
|
|
207
|
+
if (!isNonReferenceIdentifier(current, parent) && current.name) {
|
|
208
|
+
referenced.add(current.name);
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
JSXIdentifier(node, ctx) {
|
|
212
|
+
const current = node as unknown as AnyNode;
|
|
213
|
+
const parent = (ctx as { parent?: unknown }).parent as AnyNode | null;
|
|
214
|
+
if (!parent) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
if (parent.type === 'JSXMemberExpression' && parent.object === current) {
|
|
218
|
+
if (current.name) {
|
|
219
|
+
referenced.add(current.name);
|
|
220
|
+
}
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (!current.name || !isUppercaseName(current.name)) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (
|
|
227
|
+
(parent.type === 'JSXOpeningElement' ||
|
|
228
|
+
parent.type === 'JSXClosingElement') &&
|
|
229
|
+
parent.name === current
|
|
230
|
+
) {
|
|
231
|
+
referenced.add(current.name);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
ExportSpecifier(node, ctx) {
|
|
236
|
+
const current = node as unknown as AnyNode;
|
|
237
|
+
const declaration = (ctx as { parent?: unknown })
|
|
238
|
+
.parent as AnyNode | null;
|
|
239
|
+
if (
|
|
240
|
+
!declaration?.source &&
|
|
241
|
+
declaration?.exportKind !== 'type' &&
|
|
242
|
+
current.local?.name &&
|
|
243
|
+
current.exportKind !== 'type'
|
|
244
|
+
) {
|
|
245
|
+
referenced.add(current.local.name);
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
});
|
|
249
|
+
return referenced;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
type TopLevelDeclaration = {
|
|
253
|
+
referencedNames: Set<string>;
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
type TopLevelDeclarationGraph = {
|
|
257
|
+
declarationsByNode: Map<AnyNode, TopLevelDeclaration>;
|
|
258
|
+
declarationsByName: Map<string, Set<TopLevelDeclaration>>;
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const createTopLevelDeclarationGraph = (
|
|
262
|
+
program: ProgramNode
|
|
263
|
+
): TopLevelDeclarationGraph => {
|
|
264
|
+
const declarationsByNode = new Map<AnyNode, TopLevelDeclaration>();
|
|
265
|
+
const declarationsByName = new Map<string, Set<TopLevelDeclaration>>();
|
|
266
|
+
|
|
267
|
+
const registerDeclaration = (
|
|
268
|
+
node: AnyNode,
|
|
269
|
+
declarationNode: AnyNode,
|
|
270
|
+
declaredNames: Set<string>
|
|
271
|
+
) => {
|
|
272
|
+
const declaration: TopLevelDeclaration = {
|
|
273
|
+
referencedNames: collectReferencedNames(declarationNode),
|
|
274
|
+
};
|
|
275
|
+
declarationsByNode.set(node, declaration);
|
|
276
|
+
for (const name of declaredNames) {
|
|
277
|
+
const namedDeclarations = declarationsByName.get(name) ?? new Set();
|
|
278
|
+
namedDeclarations.add(declaration);
|
|
279
|
+
declarationsByName.set(name, namedDeclarations);
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
for (const statement of [...(program.body ?? [])]) {
|
|
284
|
+
if (statement.type === 'VariableDeclaration') {
|
|
285
|
+
for (const declarator of statement.declarations ?? []) {
|
|
286
|
+
registerDeclaration(
|
|
287
|
+
declarator,
|
|
288
|
+
declarator,
|
|
289
|
+
getPatternIdentifierNames(declarator.id)
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (
|
|
295
|
+
statement.type === 'FunctionDeclaration' ||
|
|
296
|
+
statement.type === 'ClassDeclaration'
|
|
297
|
+
) {
|
|
298
|
+
registerDeclaration(statement, statement, getDeclaredNames(statement));
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
return { declarationsByNode, declarationsByName };
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
const collectLiveTopLevelDeclarations = (
|
|
306
|
+
program: ProgramNode,
|
|
307
|
+
graph: TopLevelDeclarationGraph
|
|
308
|
+
): Set<TopLevelDeclaration> => {
|
|
309
|
+
const pendingNames: string[] = [];
|
|
310
|
+
|
|
311
|
+
for (const statement of program.body ?? []) {
|
|
312
|
+
if (statement.type === 'VariableDeclaration') {
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
if (graph.declarationsByNode.has(statement)) {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
for (const name of collectReferencedNames(statement)) {
|
|
319
|
+
pendingNames.push(name);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// This is intentionally name-based and conservative: shadowing may retain a
|
|
324
|
+
// declaration, but it must never make a live declaration removable.
|
|
325
|
+
const visitedNames = new Set<string>();
|
|
326
|
+
const liveDeclarations = new Set<TopLevelDeclaration>();
|
|
327
|
+
while (pendingNames.length > 0) {
|
|
328
|
+
const name = pendingNames.pop();
|
|
329
|
+
if (!name || visitedNames.has(name)) {
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
visitedNames.add(name);
|
|
333
|
+
for (const declaration of graph.declarationsByName.get(name) ?? []) {
|
|
334
|
+
if (!liveDeclarations.has(declaration)) {
|
|
335
|
+
liveDeclarations.add(declaration);
|
|
336
|
+
for (const referencedName of declaration.referencedNames) {
|
|
337
|
+
pendingNames.push(referencedName);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
return liveDeclarations;
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
const declarationReferencesName = (
|
|
347
|
+
declaration: TopLevelDeclaration,
|
|
348
|
+
names: ReadonlySet<string>,
|
|
349
|
+
graph: TopLevelDeclarationGraph,
|
|
350
|
+
cache: Map<TopLevelDeclaration, boolean>,
|
|
351
|
+
visitedNames = new Set<string>()
|
|
352
|
+
): boolean => {
|
|
353
|
+
const cached = cache.get(declaration);
|
|
354
|
+
if (cached !== undefined) {
|
|
355
|
+
return cached;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
for (const referencedName of declaration.referencedNames) {
|
|
359
|
+
if (names.has(referencedName)) {
|
|
360
|
+
cache.set(declaration, true);
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
if (visitedNames.has(referencedName)) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
visitedNames.add(referencedName);
|
|
367
|
+
for (const referencedDeclaration of graph.declarationsByName.get(
|
|
368
|
+
referencedName
|
|
369
|
+
) ?? []) {
|
|
370
|
+
if (
|
|
371
|
+
declarationReferencesName(
|
|
372
|
+
referencedDeclaration,
|
|
373
|
+
names,
|
|
374
|
+
graph,
|
|
375
|
+
cache,
|
|
376
|
+
visitedNames
|
|
377
|
+
)
|
|
378
|
+
) {
|
|
379
|
+
cache.set(declaration, true);
|
|
380
|
+
return true;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
cache.set(declaration, false);
|
|
385
|
+
return false;
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
const removeNewlyDeadTopLevelDeclarations = (
|
|
389
|
+
program: ProgramNode,
|
|
390
|
+
graph: TopLevelDeclarationGraph,
|
|
391
|
+
previouslyLive: ReadonlySet<TopLevelDeclaration>,
|
|
392
|
+
removedExportReferencedNames: ReadonlySet<string>
|
|
393
|
+
): void => {
|
|
394
|
+
const currentlyLive = collectLiveTopLevelDeclarations(program, graph);
|
|
395
|
+
const removedReferenceCache = new Map<TopLevelDeclaration, boolean>();
|
|
396
|
+
const isRemovableDeadDeclaration = (node: AnyNode) => {
|
|
397
|
+
const declaration = graph.declarationsByNode.get(node);
|
|
398
|
+
if (!declaration || currentlyLive.has(declaration)) {
|
|
399
|
+
return false;
|
|
400
|
+
}
|
|
401
|
+
return (
|
|
402
|
+
previouslyLive.has(declaration) ||
|
|
403
|
+
declarationReferencesName(
|
|
404
|
+
declaration,
|
|
405
|
+
removedExportReferencedNames,
|
|
406
|
+
graph,
|
|
407
|
+
removedReferenceCache
|
|
408
|
+
)
|
|
409
|
+
);
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
program.body = program.body.filter((statement: AnyNode) => {
|
|
413
|
+
if (statement.type === 'VariableDeclaration') {
|
|
414
|
+
statement.declarations = (statement.declarations ?? []).filter(
|
|
415
|
+
(declarator: AnyNode) => !isRemovableDeadDeclaration(declarator)
|
|
416
|
+
);
|
|
417
|
+
return statement.declarations.length > 0;
|
|
418
|
+
}
|
|
419
|
+
return !isRemovableDeadDeclaration(statement);
|
|
420
|
+
});
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
const hasRemovableExport = (
|
|
424
|
+
program: ProgramNode,
|
|
425
|
+
exportsToRemove: ReadonlySet<string>
|
|
426
|
+
): boolean => {
|
|
427
|
+
const removesNamedExports = [...exportsToRemove].some(
|
|
428
|
+
name => name !== 'default'
|
|
429
|
+
);
|
|
430
|
+
for (const statement of program.body ?? []) {
|
|
431
|
+
if (statement.type === 'ExportAllDeclaration') {
|
|
432
|
+
const exportedName = statement.exported
|
|
433
|
+
? getExportedName({ exported: statement.exported })
|
|
434
|
+
: null;
|
|
435
|
+
if (exportedName && exportsToRemove.has(exportedName)) {
|
|
436
|
+
return true;
|
|
437
|
+
}
|
|
438
|
+
if (!exportedName && removesNamedExports) {
|
|
439
|
+
return true;
|
|
440
|
+
}
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
if (statement.type === 'ExportDefaultDeclaration') {
|
|
445
|
+
if (exportsToRemove.has('default')) {
|
|
446
|
+
return true;
|
|
447
|
+
}
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
if (statement.type !== 'ExportNamedDeclaration') {
|
|
452
|
+
continue;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
for (const specifier of statement.specifiers ?? []) {
|
|
456
|
+
if (specifier.type !== 'ExportSpecifier') {
|
|
457
|
+
continue;
|
|
458
|
+
}
|
|
459
|
+
const exportedName = getExportedName(specifier);
|
|
460
|
+
if (exportedName && exportsToRemove.has(exportedName)) {
|
|
461
|
+
return true;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
const declaration = statement.declaration;
|
|
466
|
+
if (declaration?.type === 'VariableDeclaration') {
|
|
467
|
+
for (const declarator of declaration.declarations ?? []) {
|
|
468
|
+
for (const name of getPatternIdentifierNames(declarator.id)) {
|
|
469
|
+
if (exportsToRemove.has(name)) {
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (
|
|
478
|
+
(declaration?.type === 'FunctionDeclaration' ||
|
|
479
|
+
declaration?.type === 'ClassDeclaration') &&
|
|
480
|
+
declaration.id?.name &&
|
|
481
|
+
exportsToRemove.has(declaration.id.name)
|
|
482
|
+
) {
|
|
483
|
+
return true;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
return false;
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
export const removeExports = (
|
|
490
|
+
ast: ParseResult | AnyNode,
|
|
491
|
+
exportsToRemove: readonly string[],
|
|
492
|
+
exportsToRemoveSet: ReadonlySet<string> = new Set(exportsToRemove)
|
|
493
|
+
): boolean => {
|
|
494
|
+
const program = getProgram(ast);
|
|
495
|
+
if (!hasRemovableExport(program, exportsToRemoveSet)) {
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const declarationGraph = createTopLevelDeclarationGraph(program);
|
|
500
|
+
const previouslyLive = collectLiveTopLevelDeclarations(
|
|
501
|
+
program,
|
|
502
|
+
declarationGraph
|
|
503
|
+
);
|
|
504
|
+
let exportsChanged = false;
|
|
505
|
+
const removedExportLocalNames = new Set<string>();
|
|
506
|
+
const removedExportReferencedNames = new Set<string>();
|
|
507
|
+
const removesNamedExports = exportsToRemove.some(name => name !== 'default');
|
|
508
|
+
const trackRemovedExportReferences = (node: AnyNode | null | undefined) => {
|
|
509
|
+
if (!node) {
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
const declaration = declarationGraph.declarationsByNode.get(node);
|
|
513
|
+
for (const name of declaration?.referencedNames ??
|
|
514
|
+
collectReferencedNames(node)) {
|
|
515
|
+
removedExportReferencedNames.add(name);
|
|
516
|
+
}
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
for (const statement of [...program.body]) {
|
|
520
|
+
if (statement.type === 'ExportAllDeclaration') {
|
|
521
|
+
const exportedName = statement.exported
|
|
522
|
+
? getExportedName({ exported: statement.exported })
|
|
523
|
+
: null;
|
|
524
|
+
if (exportedName && exportsToRemoveSet.has(exportedName)) {
|
|
525
|
+
exportsChanged = true;
|
|
526
|
+
removeFromArray(program.body, statement);
|
|
527
|
+
}
|
|
528
|
+
if (!exportedName && removesNamedExports) {
|
|
529
|
+
throw new Error(
|
|
530
|
+
'Cannot remove named exports from `export *`; use explicit named re-exports.'
|
|
531
|
+
);
|
|
532
|
+
}
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
if (statement.type === 'ExportNamedDeclaration') {
|
|
537
|
+
if (statement.specifiers?.length) {
|
|
538
|
+
statement.specifiers = statement.specifiers.filter(
|
|
539
|
+
(specifier: AnyNode) => {
|
|
540
|
+
if (specifier.type !== 'ExportSpecifier') {
|
|
541
|
+
return true;
|
|
542
|
+
}
|
|
543
|
+
const exportedName = getExportedName(specifier);
|
|
544
|
+
if (exportedName && exportsToRemoveSet.has(exportedName)) {
|
|
545
|
+
exportsChanged = true;
|
|
546
|
+
if (specifier.local?.name) {
|
|
547
|
+
removedExportLocalNames.add(specifier.local.name);
|
|
548
|
+
removedExportReferencedNames.add(specifier.local.name);
|
|
549
|
+
}
|
|
550
|
+
return false;
|
|
551
|
+
}
|
|
552
|
+
return true;
|
|
553
|
+
}
|
|
554
|
+
);
|
|
555
|
+
if (statement.specifiers.length === 0 && !statement.declaration) {
|
|
556
|
+
removeFromArray(program.body, statement);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const declaration = statement.declaration;
|
|
561
|
+
if (declaration?.type === 'VariableDeclaration') {
|
|
562
|
+
declaration.declarations = (declaration.declarations ?? []).filter(
|
|
563
|
+
(declarator: AnyNode) => {
|
|
564
|
+
const id = declarator.id;
|
|
565
|
+
if (id?.type === 'Identifier') {
|
|
566
|
+
if (id.name && exportsToRemoveSet.has(id.name)) {
|
|
567
|
+
exportsChanged = true;
|
|
568
|
+
removedExportLocalNames.add(id.name);
|
|
569
|
+
removedExportReferencedNames.add(id.name);
|
|
570
|
+
trackRemovedExportReferences(declarator);
|
|
571
|
+
return false;
|
|
572
|
+
}
|
|
573
|
+
return true;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
if (id) {
|
|
577
|
+
validateDestructuredExports(id, exportsToRemove);
|
|
578
|
+
}
|
|
579
|
+
return true;
|
|
580
|
+
}
|
|
581
|
+
);
|
|
582
|
+
if (declaration.declarations.length === 0) {
|
|
583
|
+
removeFromArray(program.body, statement);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (
|
|
588
|
+
(declaration?.type === 'FunctionDeclaration' ||
|
|
589
|
+
declaration?.type === 'ClassDeclaration') &&
|
|
590
|
+
declaration.id?.name &&
|
|
591
|
+
exportsToRemoveSet.has(declaration.id.name)
|
|
592
|
+
) {
|
|
593
|
+
exportsChanged = true;
|
|
594
|
+
removedExportLocalNames.add(declaration.id.name);
|
|
595
|
+
removedExportReferencedNames.add(declaration.id.name);
|
|
596
|
+
trackRemovedExportReferences(statement);
|
|
597
|
+
removeFromArray(program.body, statement);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
if (
|
|
602
|
+
statement.type === 'ExportDefaultDeclaration' &&
|
|
603
|
+
exportsToRemoveSet.has('default')
|
|
604
|
+
) {
|
|
605
|
+
exportsChanged = true;
|
|
606
|
+
const declaration = statement.declaration;
|
|
607
|
+
if (declaration?.type === 'Identifier' && declaration.name) {
|
|
608
|
+
removedExportLocalNames.add(declaration.name);
|
|
609
|
+
removedExportReferencedNames.add(declaration.name);
|
|
610
|
+
} else if (declaration?.id?.name) {
|
|
611
|
+
removedExportLocalNames.add(declaration.id.name);
|
|
612
|
+
removedExportReferencedNames.add(declaration.id.name);
|
|
613
|
+
}
|
|
614
|
+
trackRemovedExportReferences(statement);
|
|
615
|
+
removeFromArray(program.body, statement);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
for (const statement of [...program.body]) {
|
|
620
|
+
const expression =
|
|
621
|
+
statement.type === 'ExpressionStatement' ? statement.expression : null;
|
|
622
|
+
const left =
|
|
623
|
+
expression?.type === 'AssignmentExpression' ? expression.left : null;
|
|
624
|
+
if (
|
|
625
|
+
left?.type === 'MemberExpression' &&
|
|
626
|
+
left.object?.type === 'Identifier' &&
|
|
627
|
+
left.object.name &&
|
|
628
|
+
removedExportLocalNames.has(left.object.name)
|
|
629
|
+
) {
|
|
630
|
+
removeFromArray(program.body, statement);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
if (exportsChanged) {
|
|
635
|
+
removeNewlyDeadTopLevelDeclarations(
|
|
636
|
+
program,
|
|
637
|
+
declarationGraph,
|
|
638
|
+
previouslyLive,
|
|
639
|
+
removedExportReferencedNames
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
return exportsChanged;
|
|
644
|
+
};
|
|
645
|
+
|
|
646
|
+
export const removeUnusedImports = (ast: ParseResult | AnyNode): void => {
|
|
647
|
+
const program = getProgram(ast);
|
|
648
|
+
const referenced = collectReferencedNames(program);
|
|
649
|
+
for (const statement of [...program.body]) {
|
|
650
|
+
if (statement.type !== 'ImportDeclaration') {
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
if ((statement.specifiers ?? []).length === 0) {
|
|
654
|
+
continue;
|
|
655
|
+
}
|
|
656
|
+
statement.specifiers = (statement.specifiers ?? []).filter(
|
|
657
|
+
(specifier: AnyNode) => {
|
|
658
|
+
if (specifier.importKind === 'type') {
|
|
659
|
+
return false;
|
|
660
|
+
}
|
|
661
|
+
return !specifier.local?.name || referenced.has(specifier.local.name);
|
|
662
|
+
}
|
|
663
|
+
);
|
|
664
|
+
if (statement.specifiers.length === 0) {
|
|
665
|
+
removeFromArray(program.body, statement);
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
};
|