@openrewrite/rewrite 8.91.4 → 8.91.6
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/dist/javascript/add-import.js +4 -6
- package/dist/javascript/add-import.js.map +1 -1
- package/dist/javascript/index.d.ts +1 -1
- package/dist/javascript/index.d.ts.map +1 -1
- package/dist/javascript/index.js +2 -1
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/remove-import.d.ts +0 -18
- package/dist/javascript/remove-import.d.ts.map +1 -1
- package/dist/javascript/remove-import.js +50 -438
- package/dist/javascript/remove-import.js.map +1 -1
- package/dist/javascript/scope.d.ts +6 -0
- package/dist/javascript/scope.d.ts.map +1 -1
- package/dist/javascript/scope.js +87 -7
- package/dist/javascript/scope.js.map +1 -1
- package/dist/rewrite-javascript-version.txt +1 -1
- package/dist/rpc/index.d.ts +1 -1
- package/dist/rpc/index.d.ts.map +1 -1
- package/dist/rpc/index.js +2 -1
- package/dist/rpc/index.js.map +1 -1
- package/dist/rpc/java-recipe.d.ts +32 -22
- package/dist/rpc/java-recipe.d.ts.map +1 -1
- package/dist/rpc/java-recipe.js +91 -30
- package/dist/rpc/java-recipe.js.map +1 -1
- package/dist/rpc/request/prepare-recipe.d.ts +10 -14
- package/dist/rpc/request/prepare-recipe.d.ts.map +1 -1
- package/dist/rpc/request/prepare-recipe.js +53 -88
- package/dist/rpc/request/prepare-recipe.js.map +1 -1
- package/dist/rpc/rewrite-rpc.d.ts +5 -12
- package/dist/rpc/rewrite-rpc.d.ts.map +1 -1
- package/dist/rpc/rewrite-rpc.js +5 -12
- package/dist/rpc/rewrite-rpc.js.map +1 -1
- package/package.json +1 -1
- package/src/javascript/add-import.ts +4 -6
- package/src/javascript/index.ts +1 -1
- package/src/javascript/remove-import.ts +50 -424
- package/src/javascript/scope.ts +103 -7
- package/src/rpc/index.ts +1 -1
- package/src/rpc/java-recipe.ts +107 -33
- package/src/rpc/request/prepare-recipe.ts +55 -90
- package/src/rpc/rewrite-rpc.ts +5 -12
|
@@ -80,12 +80,7 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
async visitJsCompilationUnit(compilationUnit, p) {
|
|
83
|
-
|
|
84
|
-
const usedIdentifiers = new Set();
|
|
85
|
-
const usedTypes = new Set();
|
|
86
|
-
// Traverse the AST to collect used identifiers
|
|
87
|
-
await this.collectUsedIdentifiers(compilationUnit, usedIdentifiers, usedTypes);
|
|
88
|
-
// Now process imports with knowledge of what's used
|
|
83
|
+
const usedNames = collectUsedNames(compilationUnit);
|
|
89
84
|
return this.produceJavaScript(compilationUnit, p, async (draft) => {
|
|
90
85
|
const formatter = new java_2.ElementRemovalFormatter(true); // Preserve file headers from first import
|
|
91
86
|
const newStatements = await (0, util_1.mapAsync)(compilationUnit.statements, async (stmt) => {
|
|
@@ -93,7 +88,7 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
93
88
|
// Handle ES6 imports
|
|
94
89
|
if ((statement === null || statement === void 0 ? void 0 : statement.kind) === tree_1.JS.Kind.Import) {
|
|
95
90
|
const jsImport = statement;
|
|
96
|
-
const result = await this.processImport(jsImport,
|
|
91
|
+
const result = await this.processImport(jsImport, usedNames, p);
|
|
97
92
|
if (result === undefined) {
|
|
98
93
|
formatter.markRemoved(statement);
|
|
99
94
|
return undefined;
|
|
@@ -106,7 +101,7 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
106
101
|
// Multi-variable declarations might come as JS.ScopedVariableDeclarations
|
|
107
102
|
if ((statement === null || statement === void 0 ? void 0 : statement.kind) === java_1.J.Kind.VariableDeclarations) {
|
|
108
103
|
const varDecl = statement;
|
|
109
|
-
const result = await this.processRequireFromVarDecls(varDecl,
|
|
104
|
+
const result = await this.processRequireFromVarDecls(varDecl, usedNames, p);
|
|
110
105
|
if (result === undefined) {
|
|
111
106
|
formatter.markRemoved(statement);
|
|
112
107
|
return undefined;
|
|
@@ -124,7 +119,7 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
124
119
|
for (const v of scopedVarDecl.variables) {
|
|
125
120
|
const varDecl = v.element;
|
|
126
121
|
if ((varDecl === null || varDecl === void 0 ? void 0 : varDecl.kind) === java_1.J.Kind.VariableDeclarations) {
|
|
127
|
-
const result = await this.processRequireFromVarDecls(varDecl,
|
|
122
|
+
const result = await this.processRequireFromVarDecls(varDecl, usedNames, p);
|
|
128
123
|
if (result === undefined) {
|
|
129
124
|
hasChanges = true;
|
|
130
125
|
varFormatter.markRemoved(varDecl);
|
|
@@ -160,10 +155,10 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
160
155
|
draft.eof = await this.visitSpace(compilationUnit.eof, p);
|
|
161
156
|
});
|
|
162
157
|
}
|
|
163
|
-
async processImport(jsImport,
|
|
158
|
+
async processImport(jsImport, usedNames, p) {
|
|
164
159
|
// Handle import-equals-require syntax: import util = require("util");
|
|
165
160
|
if (jsImport.initializer) {
|
|
166
|
-
return this.processImportEqualsRequire(jsImport,
|
|
161
|
+
return this.processImportEqualsRequire(jsImport, usedNames, p);
|
|
167
162
|
}
|
|
168
163
|
// Check if this import is from the target module
|
|
169
164
|
if (!this.isTargetModule(jsImport)) {
|
|
@@ -187,11 +182,11 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
187
182
|
let shouldRemove;
|
|
188
183
|
if (this.member === 'default') {
|
|
189
184
|
// Special case: member 'default' means remove any default import from the target module if unused
|
|
190
|
-
shouldRemove = !
|
|
185
|
+
shouldRemove = !usedNames.has(name);
|
|
191
186
|
}
|
|
192
187
|
else {
|
|
193
188
|
// Regular case: check if the import name matches the removal criteria
|
|
194
|
-
shouldRemove = this.shouldRemoveImport(name,
|
|
189
|
+
shouldRemove = this.shouldRemoveImport(name, usedNames, name);
|
|
195
190
|
}
|
|
196
191
|
if (shouldRemove) {
|
|
197
192
|
// If there are no named imports, remove the entire import
|
|
@@ -230,7 +225,7 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
230
225
|
if (this.member !== undefined) {
|
|
231
226
|
// We're trying to remove a specific member from this namespace
|
|
232
227
|
// Check if the namespace itself is used
|
|
233
|
-
if (!
|
|
228
|
+
if (!usedNames.has(name)) {
|
|
234
229
|
// Namespace is not used, remove the entire import
|
|
235
230
|
if (!importClause.name) {
|
|
236
231
|
return undefined;
|
|
@@ -241,7 +236,7 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
241
236
|
}
|
|
242
237
|
// Namespace is used, we can't remove individual members from it
|
|
243
238
|
}
|
|
244
|
-
else if (this.shouldRemoveImport(name,
|
|
239
|
+
else if (this.shouldRemoveImport(name, usedNames, name)) {
|
|
245
240
|
// If there's no default import, remove the entire import
|
|
246
241
|
if (!importClause.name) {
|
|
247
242
|
return undefined;
|
|
@@ -261,7 +256,7 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
261
256
|
if (this.member !== undefined) {
|
|
262
257
|
// We're trying to remove a specific member from this namespace
|
|
263
258
|
// Check if the namespace itself is used
|
|
264
|
-
if (!
|
|
259
|
+
if (!usedNames.has(aliasName)) {
|
|
265
260
|
// Namespace is not used, remove the entire import
|
|
266
261
|
if (!importClause.name) {
|
|
267
262
|
return undefined;
|
|
@@ -272,7 +267,7 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
272
267
|
}
|
|
273
268
|
// Namespace is used, we can't remove individual members from it
|
|
274
269
|
}
|
|
275
|
-
else if (this.shouldRemoveImport(aliasName,
|
|
270
|
+
else if (this.shouldRemoveImport(aliasName, usedNames, aliasName)) {
|
|
276
271
|
// If there's no default import, remove the entire import
|
|
277
272
|
if (!importClause.name) {
|
|
278
273
|
return undefined;
|
|
@@ -286,7 +281,7 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
286
281
|
// Handle named imports: import { a, b } from 'module'
|
|
287
282
|
if (namedBindings.kind === tree_1.JS.Kind.NamedImports) {
|
|
288
283
|
const namedImports = namedBindings;
|
|
289
|
-
const updatedImports = await this.processNamedImports(namedImports,
|
|
284
|
+
const updatedImports = await this.processNamedImports(namedImports, usedNames, p);
|
|
290
285
|
if (updatedImports === undefined) {
|
|
291
286
|
// All named imports were removed
|
|
292
287
|
if (!importClause.name) {
|
|
@@ -312,10 +307,10 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
312
307
|
* Process TypeScript import-equals-require syntax: import util = require("util");
|
|
313
308
|
* This is represented as a JS.Import with an initializer containing the require() call.
|
|
314
309
|
*/
|
|
315
|
-
async processImportEqualsRequire(jsImport,
|
|
310
|
+
async processImportEqualsRequire(jsImport, usedNames, p) {
|
|
316
311
|
var _a;
|
|
317
312
|
const initializer = (_a = jsImport.initializer) === null || _a === void 0 ? void 0 : _a.element;
|
|
318
|
-
if (!initializer || !
|
|
313
|
+
if (!initializer || !isRequireCall(initializer)) {
|
|
319
314
|
return jsImport;
|
|
320
315
|
}
|
|
321
316
|
const methodInv = initializer;
|
|
@@ -332,23 +327,11 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
332
327
|
const importedName = importClause.name.element.simpleName;
|
|
333
328
|
// For import-equals-require, we can only remove the entire import since
|
|
334
329
|
// it imports the whole module as a single identifier
|
|
335
|
-
if (this.shouldRemoveIdentifier(importedName,
|
|
330
|
+
if (this.shouldRemoveIdentifier(importedName, usedNames)) {
|
|
336
331
|
return undefined;
|
|
337
332
|
}
|
|
338
333
|
return jsImport;
|
|
339
334
|
}
|
|
340
|
-
/**
|
|
341
|
-
* Check if a node is a require() method invocation
|
|
342
|
-
*/
|
|
343
|
-
isRequireCall(node) {
|
|
344
|
-
var _a;
|
|
345
|
-
if (node.kind !== java_1.J.Kind.MethodInvocation) {
|
|
346
|
-
return false;
|
|
347
|
-
}
|
|
348
|
-
const methodInv = node;
|
|
349
|
-
return ((_a = methodInv.name) === null || _a === void 0 ? void 0 : _a.kind) === java_1.J.Kind.Identifier &&
|
|
350
|
-
methodInv.name.simpleName === 'require';
|
|
351
|
-
}
|
|
352
335
|
/**
|
|
353
336
|
* Check if the module name matches the target module
|
|
354
337
|
*/
|
|
@@ -358,13 +341,13 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
358
341
|
/**
|
|
359
342
|
* Check if an identifier should be removed based on usage
|
|
360
343
|
*/
|
|
361
|
-
shouldRemoveIdentifier(name,
|
|
344
|
+
shouldRemoveIdentifier(name, usedNames) {
|
|
362
345
|
// For CommonJS and import-equals-require, we're removing the entire import
|
|
363
346
|
// if the identifier is not used (member is typically undefined for these cases,
|
|
364
347
|
// or we're checking if a specific binding is used)
|
|
365
|
-
return !
|
|
348
|
+
return !usedNames.has(name);
|
|
366
349
|
}
|
|
367
|
-
async processNamedImports(namedImports,
|
|
350
|
+
async processNamedImports(namedImports, usedNames, p) {
|
|
368
351
|
const { filtered, allRemoved } = await this.filterElementsWithPrefixPreservation(namedImports.elements.elements, (elem) => {
|
|
369
352
|
if (elem.kind === tree_1.JS.Kind.ImportSpecifier) {
|
|
370
353
|
const specifier = elem;
|
|
@@ -378,13 +361,13 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
378
361
|
// We're removing a specific member - check if this matches
|
|
379
362
|
if (this.member === importName) {
|
|
380
363
|
// This is the member we want to remove - check if it's used
|
|
381
|
-
return
|
|
364
|
+
return usedNames.has(nameToCheck);
|
|
382
365
|
}
|
|
383
366
|
return true; // Keep imports that don't match the member
|
|
384
367
|
}
|
|
385
368
|
else {
|
|
386
369
|
// We're removing based on the import name itself
|
|
387
|
-
return !this.shouldRemoveImport(importName,
|
|
370
|
+
return !this.shouldRemoveImport(importName, usedNames, importName);
|
|
388
371
|
}
|
|
389
372
|
}
|
|
390
373
|
return true; // Keep non-ImportSpecifier elements
|
|
@@ -407,7 +390,7 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
407
390
|
draft.elements = Object.assign(Object.assign({}, namedImports.elements), { elements: filtered });
|
|
408
391
|
});
|
|
409
392
|
}
|
|
410
|
-
async processRequireFromVarDecls(varDecls,
|
|
393
|
+
async processRequireFromVarDecls(varDecls, usedNames, p) {
|
|
411
394
|
var _a;
|
|
412
395
|
// Check if this is a require() call
|
|
413
396
|
if (varDecls.variables.length !== 1) {
|
|
@@ -418,7 +401,7 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
418
401
|
return varDecls;
|
|
419
402
|
}
|
|
420
403
|
const initializer = (_a = namedVar.initializer) === null || _a === void 0 ? void 0 : _a.element;
|
|
421
|
-
if (!initializer || !
|
|
404
|
+
if (!initializer || !isRequireCall(initializer)) {
|
|
422
405
|
return varDecls;
|
|
423
406
|
}
|
|
424
407
|
const methodInv = initializer;
|
|
@@ -432,14 +415,14 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
432
415
|
const varName = pattern.simpleName;
|
|
433
416
|
// For require() statements, check the module name from the require call
|
|
434
417
|
const moduleName = this.getModuleNameFromRequire(methodInv);
|
|
435
|
-
if (moduleName && this.matchesTargetModule(moduleName) && !
|
|
418
|
+
if (moduleName && this.matchesTargetModule(moduleName) && !usedNames.has(varName)) {
|
|
436
419
|
return undefined; // Remove the entire require statement
|
|
437
420
|
}
|
|
438
421
|
}
|
|
439
422
|
// Handle: const { readFile } = require('fs')
|
|
440
423
|
if (pattern.kind === tree_1.JS.Kind.ObjectBindingPattern && this.member !== undefined) {
|
|
441
424
|
const objectPattern = pattern;
|
|
442
|
-
const updatedPattern = await this.processObjectBindingPattern(objectPattern,
|
|
425
|
+
const updatedPattern = await this.processObjectBindingPattern(objectPattern, usedNames, p);
|
|
443
426
|
if (updatedPattern === undefined) {
|
|
444
427
|
return undefined; // Remove entire require
|
|
445
428
|
}
|
|
@@ -470,12 +453,12 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
470
453
|
}
|
|
471
454
|
return (_b = firstArg.value) === null || _b === void 0 ? void 0 : _b.toString();
|
|
472
455
|
}
|
|
473
|
-
async processObjectBindingPattern(pattern,
|
|
456
|
+
async processObjectBindingPattern(pattern, usedNames, p) {
|
|
474
457
|
const { filtered, allRemoved } = await this.filterElementsWithPrefixPreservation(pattern.bindings.elements, (elem) => {
|
|
475
458
|
const bound = this.boundByPatternElement(elem);
|
|
476
459
|
// An element whose names cannot be read is left alone.
|
|
477
460
|
return bound.length === 0 ||
|
|
478
|
-
bound.some(b => !this.shouldRemoveImport(b.name,
|
|
461
|
+
bound.some(b => !this.shouldRemoveImport(b.name, usedNames, b.member));
|
|
479
462
|
}, async (elem, prefix) => {
|
|
480
463
|
if (elem.kind === java_1.J.Kind.Identifier) {
|
|
481
464
|
return this.produceJava(elem, p, async (draft) => {
|
|
@@ -537,7 +520,7 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
537
520
|
? [{ name: elem.simpleName, member: elem.simpleName }]
|
|
538
521
|
: (0, scope_1.bindingNames)(elem);
|
|
539
522
|
}
|
|
540
|
-
shouldRemoveImport(name,
|
|
523
|
+
shouldRemoveImport(name, usedNames, member) {
|
|
541
524
|
// If member is specified, we're removing a specific member from the module
|
|
542
525
|
if (this.member !== undefined) {
|
|
543
526
|
// A name bound under an alias reads one member and is referenced by another, and a name
|
|
@@ -549,7 +532,7 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
549
532
|
// If no member specified, we're removing all unused imports from the module
|
|
550
533
|
// So we check if this particular import is unused
|
|
551
534
|
// Check if it's used
|
|
552
|
-
return !
|
|
535
|
+
return !usedNames.has(name);
|
|
553
536
|
}
|
|
554
537
|
isTargetModule(jsImport) {
|
|
555
538
|
var _a, _b;
|
|
@@ -563,399 +546,28 @@ class RemoveImport extends visitor_1.JavaScriptVisitor {
|
|
|
563
546
|
// Match the module name
|
|
564
547
|
return moduleName === this.module;
|
|
565
548
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
for (const p of params.elements) {
|
|
581
|
-
if (p.element) {
|
|
582
|
-
await this.collectUsedIdentifiers(p.element, usedIdentifiers, usedTypes);
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
else if (params.parameters) {
|
|
587
|
-
for (const p of params.parameters) {
|
|
588
|
-
const elem = p.element || p;
|
|
589
|
-
await this.collectUsedIdentifiers(elem, usedIdentifiers, usedTypes);
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
/**
|
|
594
|
-
* Helper to traverse statements from various node types
|
|
595
|
-
*/
|
|
596
|
-
async traverseStatements(statements, usedIdentifiers, usedTypes) {
|
|
597
|
-
if (!statements)
|
|
598
|
-
return;
|
|
599
|
-
if (Array.isArray(statements)) {
|
|
600
|
-
for (const stmt of statements) {
|
|
601
|
-
const element = stmt.element || stmt;
|
|
602
|
-
if (element) {
|
|
603
|
-
await this.collectUsedIdentifiers(element, usedIdentifiers, usedTypes);
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
/**
|
|
609
|
-
* Helper to check for type expressions and collect type usage
|
|
610
|
-
*/
|
|
611
|
-
async checkTypeExpression(node, usedTypes) {
|
|
612
|
-
if (node.typeExpression) {
|
|
613
|
-
await this.collectTypeUsage(node.typeExpression, usedTypes);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
async collectUsedIdentifiers(node, usedIdentifiers, usedTypes) {
|
|
617
|
-
// This is a simplified version - in a real implementation,
|
|
618
|
-
// we'd need to traverse the entire AST and collect all identifier usages
|
|
619
|
-
// For now, we'll implement a basic traversal
|
|
620
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _q, _r;
|
|
621
|
-
if (node.kind === java_1.J.Kind.Identifier) {
|
|
622
|
-
const identifier = node;
|
|
623
|
-
usedIdentifiers.add(identifier.simpleName);
|
|
624
|
-
}
|
|
625
|
-
else if (node.kind === java_1.J.Kind.VariableDeclarations) {
|
|
626
|
-
const varDecls = node;
|
|
627
|
-
// Check the type expression on the VariableDeclarations itself
|
|
628
|
-
await this.checkTypeExpression(varDecls, usedTypes);
|
|
629
|
-
for (const v of varDecls.variables) {
|
|
630
|
-
// Check the initializer
|
|
631
|
-
if ((_a = v.element.initializer) === null || _a === void 0 ? void 0 : _a.element) {
|
|
632
|
-
await this.collectUsedIdentifiers(v.element.initializer.element, usedIdentifiers, usedTypes);
|
|
633
|
-
}
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
else if (node.kind === java_1.J.Kind.MethodInvocation) {
|
|
637
|
-
const methodInv = node;
|
|
638
|
-
// Check if this is a member access pattern like fs.readFileSync
|
|
639
|
-
if (((_c = (_b = methodInv.select) === null || _b === void 0 ? void 0 : _b.element) === null || _c === void 0 ? void 0 : _c.kind) === java_1.J.Kind.FieldAccess) {
|
|
640
|
-
const fieldAccess = methodInv.select.element;
|
|
641
|
-
if (((_d = fieldAccess.target) === null || _d === void 0 ? void 0 : _d.kind) === java_1.J.Kind.Identifier) {
|
|
642
|
-
usedIdentifiers.add(fieldAccess.target.simpleName);
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
else if (((_f = (_e = methodInv.select) === null || _e === void 0 ? void 0 : _e.element) === null || _f === void 0 ? void 0 : _f.kind) === java_1.J.Kind.Identifier) {
|
|
646
|
-
// Direct identifier like fs in fs.method() - though this is rare
|
|
647
|
-
usedIdentifiers.add(methodInv.select.element.simpleName);
|
|
648
|
-
}
|
|
649
|
-
else if (!methodInv.select) {
|
|
650
|
-
// No select means this is a direct function call like isArray()
|
|
651
|
-
// Only in this case should we add the method name as a used identifier
|
|
652
|
-
if (methodInv.name && methodInv.name.kind === java_1.J.Kind.Identifier) {
|
|
653
|
-
usedIdentifiers.add(methodInv.name.simpleName);
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
// Note: We don't add method names for calls like Array.isArray() or obj.method()
|
|
657
|
-
// because those are methods on objects, not standalone imported functions
|
|
658
|
-
// Recursively check arguments
|
|
659
|
-
if (methodInv.arguments) {
|
|
660
|
-
for (const arg of methodInv.arguments.elements) {
|
|
661
|
-
if (arg.element) {
|
|
662
|
-
await this.collectUsedIdentifiers(arg.element, usedIdentifiers, usedTypes);
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
// Check select (object being called on)
|
|
667
|
-
if ((_g = methodInv.select) === null || _g === void 0 ? void 0 : _g.element) {
|
|
668
|
-
await this.collectUsedIdentifiers(methodInv.select.element, usedIdentifiers, usedTypes);
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
else if (node.kind === java_1.J.Kind.MemberReference) {
|
|
672
|
-
const memberRef = node;
|
|
673
|
-
if (memberRef.containing && ((_h = memberRef.containing.element) === null || _h === void 0 ? void 0 : _h.kind) === java_1.J.Kind.Identifier) {
|
|
674
|
-
usedIdentifiers.add(memberRef.containing.element.simpleName);
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
else if (node.kind === java_1.J.Kind.FieldAccess) {
|
|
678
|
-
// Handle field access like fs.readFileSync
|
|
679
|
-
const fieldAccess = node;
|
|
680
|
-
if (((_j = fieldAccess.target) === null || _j === void 0 ? void 0 : _j.kind) === java_1.J.Kind.Identifier) {
|
|
681
|
-
usedIdentifiers.add(fieldAccess.target.simpleName);
|
|
682
|
-
}
|
|
683
|
-
// Recursively check the target
|
|
684
|
-
if (fieldAccess.target) {
|
|
685
|
-
await this.collectUsedIdentifiers(fieldAccess.target, usedIdentifiers, usedTypes);
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
else if (node.kind === tree_1.JS.Kind.CompilationUnit) {
|
|
689
|
-
const cu = node;
|
|
690
|
-
for (const stmt of cu.statements) {
|
|
691
|
-
if (stmt.element && stmt.element.kind !== tree_1.JS.Kind.Import) {
|
|
692
|
-
// Skip require() statements at the top level
|
|
693
|
-
if (stmt.element.kind === java_1.J.Kind.VariableDeclarations) {
|
|
694
|
-
const varDecls = stmt.element;
|
|
695
|
-
// Check if this is a require() statement
|
|
696
|
-
let isRequire = false;
|
|
697
|
-
for (const v of varDecls.variables) {
|
|
698
|
-
const namedVar = v.element;
|
|
699
|
-
if (((_l = (_k = namedVar === null || namedVar === void 0 ? void 0 : namedVar.initializer) === null || _k === void 0 ? void 0 : _k.element) === null || _l === void 0 ? void 0 : _l.kind) === java_1.J.Kind.MethodInvocation) {
|
|
700
|
-
const methodInv = namedVar.initializer.element;
|
|
701
|
-
if (((_m = methodInv.name) === null || _m === void 0 ? void 0 : _m.kind) === java_1.J.Kind.Identifier &&
|
|
702
|
-
methodInv.name.simpleName === 'require') {
|
|
703
|
-
isRequire = true;
|
|
704
|
-
break;
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
if (!isRequire) {
|
|
709
|
-
// Not a require statement, process normally
|
|
710
|
-
await this.collectUsedIdentifiers(stmt.element, usedIdentifiers, usedTypes);
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
else if (stmt.element.kind !== tree_1.JS.Kind.ScopedVariableDeclarations) {
|
|
714
|
-
// Process other non-import, non-require statements normally
|
|
715
|
-
await this.collectUsedIdentifiers(stmt.element, usedIdentifiers, usedTypes);
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
else if (node.kind === java_1.J.Kind.Return) {
|
|
721
|
-
// Handle return statements
|
|
722
|
-
const returnStmt = node;
|
|
723
|
-
if (returnStmt.expression) {
|
|
724
|
-
await this.collectUsedIdentifiers(returnStmt.expression, usedIdentifiers, usedTypes);
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
else if (node.kind === java_1.J.Kind.Block) {
|
|
728
|
-
const block = node;
|
|
729
|
-
for (const stmt of block.statements) {
|
|
730
|
-
if (stmt.element) {
|
|
731
|
-
await this.collectUsedIdentifiers(stmt.element, usedIdentifiers, usedTypes);
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
else if (node.kind === java_1.J.Kind.MethodDeclaration) {
|
|
736
|
-
const method = node;
|
|
737
|
-
// Check parameters for type usage
|
|
738
|
-
if (method.parameters) {
|
|
739
|
-
for (const param of method.parameters.elements) {
|
|
740
|
-
// Parameters can be various types, handle them recursively
|
|
741
|
-
if (param.element) {
|
|
742
|
-
await this.collectUsedIdentifiers(param.element, usedIdentifiers, usedTypes);
|
|
743
|
-
}
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
// Check body
|
|
747
|
-
if (method.body) {
|
|
748
|
-
await this.collectUsedIdentifiers(method.body, usedIdentifiers, usedTypes);
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
else if (node.kind === tree_1.JS.Kind.TypeOf) {
|
|
752
|
-
// Handle typeof expressions like: typeof util
|
|
753
|
-
const typeOf = node;
|
|
754
|
-
if (typeOf.expression) {
|
|
755
|
-
await this.collectUsedIdentifiers(typeOf.expression, usedIdentifiers, usedTypes);
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
else if (node.kind === tree_1.JS.Kind.TypeQuery) {
|
|
759
|
-
// Handle typeof type queries like: const x: typeof util
|
|
760
|
-
const typeQuery = node;
|
|
761
|
-
if (typeQuery.typeExpression) {
|
|
762
|
-
await this.collectUsedIdentifiers(typeQuery.typeExpression, usedIdentifiers, usedTypes);
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
else if (node.typeExpression) {
|
|
766
|
-
// Handle nodes with type expressions (parameters, variables, etc.)
|
|
767
|
-
await this.checkTypeExpression(node, usedTypes);
|
|
768
|
-
// Continue traversing other parts
|
|
769
|
-
if (node.name) {
|
|
770
|
-
await this.collectUsedIdentifiers(node.name, usedIdentifiers, usedTypes);
|
|
771
|
-
}
|
|
772
|
-
if (node.initializer) {
|
|
773
|
-
await this.collectUsedIdentifiers(node.initializer, usedIdentifiers, usedTypes);
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
else if (node.kind === tree_1.JS.Kind.ArrowFunction || node.kind === java_1.J.Kind.Lambda) {
|
|
777
|
-
// Handle arrow functions and lambdas
|
|
778
|
-
const func = node;
|
|
779
|
-
if (func.parameters) {
|
|
780
|
-
await this.collectUsedIdentifiers(func.parameters, usedIdentifiers, usedTypes);
|
|
781
|
-
}
|
|
782
|
-
if (func.lambda) {
|
|
783
|
-
await this.collectUsedIdentifiers(func.lambda, usedIdentifiers, usedTypes);
|
|
784
|
-
}
|
|
785
|
-
if (func.body) {
|
|
786
|
-
await this.collectUsedIdentifiers(func.body, usedIdentifiers, usedTypes);
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
else if (node.kind === java_1.J.Kind.Lambda) {
|
|
790
|
-
const lambda = node;
|
|
791
|
-
if ((_o = lambda.parameters) === null || _o === void 0 ? void 0 : _o.parameters) {
|
|
792
|
-
for (const param of lambda.parameters.parameters) {
|
|
793
|
-
if (param.element) {
|
|
794
|
-
await this.collectUsedIdentifiers(param.element, usedIdentifiers, usedTypes);
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
if (lambda.body) {
|
|
799
|
-
await this.collectUsedIdentifiers(lambda.body, usedIdentifiers, usedTypes);
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
else if (node.kind === tree_1.JS.Kind.JsxTag) {
|
|
803
|
-
// Handle JSX tags like <div>content</div>
|
|
804
|
-
const jsxTag = node;
|
|
805
|
-
// Check attributes
|
|
806
|
-
if (jsxTag.attributes) {
|
|
807
|
-
for (const attr of jsxTag.attributes) {
|
|
808
|
-
if (attr.element) {
|
|
809
|
-
await this.collectUsedIdentifiers(attr.element, usedIdentifiers, usedTypes);
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
// Check children
|
|
814
|
-
if (jsxTag.children) {
|
|
815
|
-
for (const child of jsxTag.children) {
|
|
816
|
-
if (child) {
|
|
817
|
-
await this.collectUsedIdentifiers(child, usedIdentifiers, usedTypes);
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
else if (node.kind === tree_1.JS.Kind.JsxEmbeddedExpression) {
|
|
823
|
-
// Handle JSX embedded expressions like {React.version}
|
|
824
|
-
const embedded = node;
|
|
825
|
-
// The expression is wrapped in RightPadded, so unwrap it
|
|
826
|
-
const expr = ((_q = embedded.expression) === null || _q === void 0 ? void 0 : _q.element) || embedded.expression;
|
|
827
|
-
if (expr) {
|
|
828
|
-
await this.collectUsedIdentifiers(expr, usedIdentifiers, usedTypes);
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
else if (node.kind === tree_1.JS.Kind.JsxAttribute) {
|
|
832
|
-
// Handle JSX attributes like onClick={handler}
|
|
833
|
-
const jsxAttr = node;
|
|
834
|
-
if (jsxAttr.value) {
|
|
835
|
-
await this.collectUsedIdentifiers(jsxAttr.value, usedIdentifiers, usedTypes);
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
else if (node.kind === tree_1.JS.Kind.TypeDeclaration) {
|
|
839
|
-
// Handle type alias declarations like: type Props = { children: React.ReactNode }
|
|
840
|
-
const typeDecl = node;
|
|
841
|
-
// The initializer contains the type expression (the right side of the =)
|
|
842
|
-
if ((_r = typeDecl.initializer) === null || _r === void 0 ? void 0 : _r.element) {
|
|
843
|
-
await this.collectTypeUsage(typeDecl.initializer.element, usedTypes);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
else if (node.statements) {
|
|
847
|
-
// Generic handler for nodes with statements
|
|
848
|
-
await this.traverseStatements(node.statements, usedIdentifiers, usedTypes);
|
|
849
|
-
}
|
|
850
|
-
else if (node.body) {
|
|
851
|
-
// Generic handler for nodes with body
|
|
852
|
-
await this.collectUsedIdentifiers(node.body, usedIdentifiers, usedTypes);
|
|
853
|
-
}
|
|
854
|
-
else if (node.parameters) {
|
|
855
|
-
// Handle anything with parameters (functions, methods, etc.)
|
|
856
|
-
await this.traverseParameters(node.parameters, usedIdentifiers, usedTypes);
|
|
857
|
-
// Continue with the body if it exists
|
|
858
|
-
if (node.body) {
|
|
859
|
-
await this.collectUsedIdentifiers(node.body, usedIdentifiers, usedTypes);
|
|
860
|
-
}
|
|
861
|
-
}
|
|
549
|
+
}
|
|
550
|
+
exports.RemoveImport = RemoveImport;
|
|
551
|
+
/**
|
|
552
|
+
* The names the file references, less its own imports: a specifier names what it binds, so counting
|
|
553
|
+
* one would read an import as a use of itself.
|
|
554
|
+
*/
|
|
555
|
+
function collectUsedNames(cu) {
|
|
556
|
+
const used = new Set();
|
|
557
|
+
for (const statement of cu.statements) {
|
|
558
|
+
const element = statement.element;
|
|
559
|
+
if (!element || element.kind === tree_1.JS.Kind.Import) {
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
(0, scope_1.namesReferencedWithin)(element).forEach(name => used.add(name));
|
|
862
563
|
}
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
else if (typeExpr.kind === java_1.J.Kind.ParameterizedType) {
|
|
869
|
-
const paramType = typeExpr;
|
|
870
|
-
// First, collect usage from the base type (e.g., React.Ref from React.Ref<T>)
|
|
871
|
-
if (paramType.class) {
|
|
872
|
-
await this.collectTypeUsage(paramType.class, usedTypes);
|
|
873
|
-
}
|
|
874
|
-
// Then collect usage from type parameters (e.g., HTMLButtonElement from React.Ref<HTMLButtonElement>)
|
|
875
|
-
if (paramType.typeParameters) {
|
|
876
|
-
for (const typeParam of paramType.typeParameters.elements) {
|
|
877
|
-
if (typeParam.element) {
|
|
878
|
-
await this.collectTypeUsage(typeParam.element, usedTypes);
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
else if (typeExpr.kind === java_1.J.Kind.FieldAccess) {
|
|
884
|
-
// Handle qualified names in type positions like React.Ref
|
|
885
|
-
const fieldAccess = typeExpr;
|
|
886
|
-
if (((_a = fieldAccess.target) === null || _a === void 0 ? void 0 : _a.kind) === java_1.J.Kind.Identifier) {
|
|
887
|
-
usedTypes.add(fieldAccess.target.simpleName);
|
|
888
|
-
}
|
|
889
|
-
else if (fieldAccess.target) {
|
|
890
|
-
// Recursively handle nested field accesses
|
|
891
|
-
await this.collectTypeUsage(fieldAccess.target, usedTypes);
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
else if (typeExpr.kind === tree_1.JS.Kind.Intersection) {
|
|
895
|
-
// Handle intersection types like ButtonProps & { ref?: React.Ref<HTMLButtonElement> }
|
|
896
|
-
const intersection = typeExpr;
|
|
897
|
-
for (const typeElem of intersection.types) {
|
|
898
|
-
if (typeElem.element) {
|
|
899
|
-
await this.collectTypeUsage(typeElem.element, usedTypes);
|
|
900
|
-
}
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
else if (typeExpr.kind === tree_1.JS.Kind.TypeLiteral) {
|
|
904
|
-
// Handle type literals like { ref?: React.Ref<HTMLButtonElement> }
|
|
905
|
-
const typeLiteral = typeExpr;
|
|
906
|
-
// TypeLiteral members are in a Block, which contains statements
|
|
907
|
-
for (const stmt of typeLiteral.members.statements) {
|
|
908
|
-
if (stmt.element) {
|
|
909
|
-
// Each statement is typically a VariableDeclarations representing a property
|
|
910
|
-
await this.collectUsedIdentifiers(stmt.element, new Set(), usedTypes);
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
}
|
|
914
|
-
else if (typeExpr.kind === tree_1.JS.Kind.TypeQuery) {
|
|
915
|
-
// Handle typeof type queries like: const x: typeof util
|
|
916
|
-
const typeQuery = typeExpr;
|
|
917
|
-
if (typeQuery.typeExpression) {
|
|
918
|
-
await this.collectTypeUsage(typeQuery.typeExpression, usedTypes);
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
else if (typeExpr.kind === tree_1.JS.Kind.TypeOf) {
|
|
922
|
-
// Handle typeof expressions in types
|
|
923
|
-
const typeOf = typeExpr;
|
|
924
|
-
if (typeOf.expression) {
|
|
925
|
-
// For typeof expressions, the expression contains the identifier
|
|
926
|
-
// Add it to usedTypes since it's used in a type context
|
|
927
|
-
if (typeOf.expression.kind === java_1.J.Kind.Identifier) {
|
|
928
|
-
usedTypes.add(typeOf.expression.simpleName);
|
|
929
|
-
}
|
|
930
|
-
else {
|
|
931
|
-
await this.collectTypeUsage(typeOf.expression, usedTypes);
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
}
|
|
935
|
-
else if (typeExpr.kind === tree_1.JS.Kind.TypeTreeExpression) {
|
|
936
|
-
// Handle TypeTreeExpression which wraps type identifiers
|
|
937
|
-
const typeTree = typeExpr;
|
|
938
|
-
if (typeTree.expression) {
|
|
939
|
-
await this.collectTypeUsage(typeTree.expression, usedTypes);
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
else if (typeExpr.kind === tree_1.JS.Kind.TypeInfo) {
|
|
943
|
-
// Handle TypeInfo which contains type identifiers
|
|
944
|
-
const typeInfo = typeExpr;
|
|
945
|
-
if (typeInfo.typeIdentifier) {
|
|
946
|
-
await this.collectTypeUsage(typeInfo.typeIdentifier, usedTypes);
|
|
947
|
-
}
|
|
948
|
-
}
|
|
949
|
-
else if (typeExpr.expression) {
|
|
950
|
-
// Generic handler for nodes with expression property
|
|
951
|
-
await this.collectTypeUsage(typeExpr.expression, usedTypes);
|
|
952
|
-
}
|
|
953
|
-
else if (typeExpr.typeIdentifier) {
|
|
954
|
-
// Generic handler for nodes with typeIdentifier property
|
|
955
|
-
await this.collectTypeUsage(typeExpr.typeIdentifier, usedTypes);
|
|
956
|
-
}
|
|
957
|
-
// Add more type expression handlers as needed
|
|
564
|
+
return used;
|
|
565
|
+
}
|
|
566
|
+
function isRequireCall(node) {
|
|
567
|
+
if (node.kind !== java_1.J.Kind.MethodInvocation) {
|
|
568
|
+
return false;
|
|
958
569
|
}
|
|
570
|
+
const name = node.name;
|
|
571
|
+
return (name === null || name === void 0 ? void 0 : name.kind) === java_1.J.Kind.Identifier && name.simpleName === 'require';
|
|
959
572
|
}
|
|
960
|
-
exports.RemoveImport = RemoveImport;
|
|
961
573
|
//# sourceMappingURL=remove-import.js.map
|