@openrewrite/rewrite 8.91.0 → 8.91.2
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/java/formatting-utils.d.ts +8 -5
- package/dist/java/formatting-utils.d.ts.map +1 -1
- package/dist/java/formatting-utils.js +14 -10
- package/dist/java/formatting-utils.js.map +1 -1
- package/dist/java/type.d.ts +2 -0
- package/dist/java/type.d.ts.map +1 -1
- package/dist/java/type.js +5 -0
- package/dist/java/type.js.map +1 -1
- package/dist/javascript/add-import.d.ts +96 -43
- package/dist/javascript/add-import.d.ts.map +1 -1
- package/dist/javascript/add-import.js +668 -236
- package/dist/javascript/add-import.js.map +1 -1
- package/dist/javascript/amd.d.ts +138 -0
- package/dist/javascript/amd.d.ts.map +1 -0
- package/dist/javascript/amd.js +768 -0
- package/dist/javascript/amd.js.map +1 -0
- package/dist/javascript/assertions.d.ts +7 -0
- package/dist/javascript/assertions.d.ts.map +1 -1
- package/dist/javascript/assertions.js +31 -5
- package/dist/javascript/assertions.js.map +1 -1
- package/dist/javascript/binding.d.ts +94 -0
- package/dist/javascript/binding.d.ts.map +1 -0
- package/dist/javascript/binding.js +335 -0
- package/dist/javascript/binding.js.map +1 -0
- package/dist/javascript/comparator.d.ts +5 -0
- package/dist/javascript/comparator.d.ts.map +1 -1
- package/dist/javascript/comparator.js +34 -9
- package/dist/javascript/comparator.js.map +1 -1
- package/dist/javascript/format/format.d.ts.map +1 -1
- package/dist/javascript/format/format.js +8 -9
- package/dist/javascript/format/format.js.map +1 -1
- package/dist/javascript/format/tabs-and-indents-visitor.d.ts +2 -0
- package/dist/javascript/format/tabs-and-indents-visitor.d.ts.map +1 -1
- package/dist/javascript/format/tabs-and-indents-visitor.js +17 -11
- package/dist/javascript/format/tabs-and-indents-visitor.js.map +1 -1
- package/dist/javascript/index.d.ts +8 -1
- package/dist/javascript/index.d.ts.map +1 -1
- package/dist/javascript/index.js +26 -1
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/node-resolution-result.d.ts +19 -1
- package/dist/javascript/node-resolution-result.d.ts.map +1 -1
- package/dist/javascript/node-resolution-result.js +37 -2
- package/dist/javascript/node-resolution-result.js.map +1 -1
- package/dist/javascript/package-exported-types.d.ts.map +1 -1
- package/dist/javascript/package-exported-types.js +56 -72
- package/dist/javascript/package-exported-types.js.map +1 -1
- package/dist/javascript/parser-utils.d.ts.map +1 -1
- package/dist/javascript/parser-utils.js +2 -0
- package/dist/javascript/parser-utils.js.map +1 -1
- package/dist/javascript/parser.d.ts +7 -1
- package/dist/javascript/parser.d.ts.map +1 -1
- package/dist/javascript/parser.js +17 -4
- package/dist/javascript/parser.js.map +1 -1
- package/dist/javascript/recipes/change-import.d.ts +2 -4
- package/dist/javascript/recipes/change-import.d.ts.map +1 -1
- package/dist/javascript/recipes/change-import.js +8 -244
- package/dist/javascript/recipes/change-import.js.map +1 -1
- package/dist/javascript/remove-import.d.ts +2 -28
- package/dist/javascript/remove-import.d.ts.map +1 -1
- package/dist/javascript/remove-import.js +19 -57
- package/dist/javascript/remove-import.js.map +1 -1
- package/dist/javascript/scope.d.ts +49 -0
- package/dist/javascript/scope.d.ts.map +1 -0
- package/dist/javascript/scope.js +324 -0
- package/dist/javascript/scope.js.map +1 -0
- package/dist/javascript/style.d.ts.map +1 -1
- package/dist/javascript/style.js +3 -10
- package/dist/javascript/style.js.map +1 -1
- package/dist/javascript/templating/bindings.d.ts +8 -0
- package/dist/javascript/templating/bindings.d.ts.map +1 -0
- package/dist/javascript/templating/bindings.js +92 -0
- package/dist/javascript/templating/bindings.js.map +1 -0
- package/dist/javascript/templating/comparator.d.ts +10 -0
- package/dist/javascript/templating/comparator.d.ts.map +1 -1
- package/dist/javascript/templating/comparator.js +48 -20
- package/dist/javascript/templating/comparator.js.map +1 -1
- package/dist/javascript/templating/engine.d.ts +34 -10
- package/dist/javascript/templating/engine.d.ts.map +1 -1
- package/dist/javascript/templating/engine.js +109 -55
- package/dist/javascript/templating/engine.js.map +1 -1
- package/dist/javascript/templating/index.d.ts +1 -1
- package/dist/javascript/templating/index.d.ts.map +1 -1
- package/dist/javascript/templating/index.js.map +1 -1
- package/dist/javascript/templating/pattern.d.ts.map +1 -1
- package/dist/javascript/templating/pattern.js +13 -10
- package/dist/javascript/templating/pattern.js.map +1 -1
- package/dist/javascript/templating/placeholder-replacement.d.ts +4 -0
- package/dist/javascript/templating/placeholder-replacement.d.ts.map +1 -1
- package/dist/javascript/templating/placeholder-replacement.js +24 -10
- package/dist/javascript/templating/placeholder-replacement.js.map +1 -1
- package/dist/javascript/templating/precedence.d.ts +12 -4
- package/dist/javascript/templating/precedence.d.ts.map +1 -1
- package/dist/javascript/templating/precedence.js +18 -11
- package/dist/javascript/templating/precedence.js.map +1 -1
- package/dist/javascript/templating/rewrite.d.ts.map +1 -1
- package/dist/javascript/templating/rewrite.js +19 -17
- package/dist/javascript/templating/rewrite.js.map +1 -1
- package/dist/javascript/templating/template.d.ts +14 -0
- package/dist/javascript/templating/template.d.ts.map +1 -1
- package/dist/javascript/templating/template.js +63 -3
- package/dist/javascript/templating/template.js.map +1 -1
- package/dist/javascript/templating/types.d.ts +39 -1
- package/dist/javascript/templating/types.d.ts.map +1 -1
- package/dist/javascript/templating/utils.d.ts +6 -1
- package/dist/javascript/templating/utils.d.ts.map +1 -1
- package/dist/javascript/templating/utils.js +20 -2
- package/dist/javascript/templating/utils.js.map +1 -1
- package/dist/javascript/type-mapping.d.ts +1 -0
- package/dist/javascript/type-mapping.d.ts.map +1 -1
- package/dist/javascript/type-mapping.js +52 -2
- package/dist/javascript/type-mapping.js.map +1 -1
- package/dist/rewrite-javascript-version.txt +1 -1
- package/dist/style.d.ts +2 -0
- package/dist/style.d.ts.map +1 -1
- package/dist/style.js +5 -0
- package/dist/style.js.map +1 -1
- package/dist/test/rewrite-test.d.ts +12 -0
- package/dist/test/rewrite-test.d.ts.map +1 -1
- package/dist/test/rewrite-test.js +40 -3
- package/dist/test/rewrite-test.js.map +1 -1
- package/package.json +2 -2
- package/src/java/formatting-utils.ts +14 -10
- package/src/java/type.ts +5 -0
- package/src/javascript/add-import.ts +751 -247
- package/src/javascript/amd.ts +915 -0
- package/src/javascript/assertions.ts +33 -5
- package/src/javascript/binding.ts +449 -0
- package/src/javascript/comparator.ts +39 -10
- package/src/javascript/format/format.ts +9 -10
- package/src/javascript/format/tabs-and-indents-visitor.ts +18 -12
- package/src/javascript/index.ts +12 -1
- package/src/javascript/node-resolution-result.ts +59 -4
- package/src/javascript/package-exported-types.ts +60 -74
- package/src/javascript/parser-utils.ts +2 -0
- package/src/javascript/parser.ts +23 -3
- package/src/javascript/recipes/change-import.ts +10 -263
- package/src/javascript/remove-import.ts +20 -56
- package/src/javascript/scope.ts +338 -0
- package/src/javascript/style.ts +3 -11
- package/src/javascript/templating/bindings.ts +99 -0
- package/src/javascript/templating/comparator.ts +57 -20
- package/src/javascript/templating/engine.ts +148 -68
- package/src/javascript/templating/index.ts +1 -0
- package/src/javascript/templating/pattern.ts +19 -16
- package/src/javascript/templating/placeholder-replacement.ts +32 -11
- package/src/javascript/templating/precedence.ts +21 -13
- package/src/javascript/templating/rewrite.ts +23 -17
- package/src/javascript/templating/template.ts +84 -9
- package/src/javascript/templating/types.ts +46 -1
- package/src/javascript/templating/utils.ts +21 -2
- package/src/javascript/type-mapping.ts +54 -2
- package/src/style.ts +5 -0
- package/src/test/rewrite-test.ts +61 -3
|
@@ -18,9 +18,9 @@ import { Option, Recipe } from "../../recipe";
|
|
|
18
18
|
import { TreeVisitor } from "../../visitor";
|
|
19
19
|
import { ExecutionContext } from "../../execution";
|
|
20
20
|
import { JavaScriptVisitor, JS } from "../index";
|
|
21
|
-
import {
|
|
22
|
-
import { J,
|
|
23
|
-
import { create as produce
|
|
21
|
+
import { maybeRebind } from "../binding";
|
|
22
|
+
import { J, Type } from "../../java";
|
|
23
|
+
import { create as produce } from "mutative";
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Changes an import from one module to another, updating all type attributions.
|
|
@@ -41,7 +41,7 @@ import { create as produce, Draft } from "mutative";
|
|
|
41
41
|
* // After: import { act } from 'react';
|
|
42
42
|
*
|
|
43
43
|
* @example
|
|
44
|
-
* // Change
|
|
44
|
+
* // Change which member of the module a name is bound to
|
|
45
45
|
* const recipe = new ChangeImport({
|
|
46
46
|
* oldModule: "lodash",
|
|
47
47
|
* oldMember: "extend",
|
|
@@ -49,7 +49,7 @@ import { create as produce, Draft } from "mutative";
|
|
|
49
49
|
* newMember: "assign"
|
|
50
50
|
* });
|
|
51
51
|
* // Before: import { extend } from 'lodash';
|
|
52
|
-
* // After: import { assign } from 'lodash';
|
|
52
|
+
* // After: import { assign as extend } from 'lodash';
|
|
53
53
|
*/
|
|
54
54
|
export class ChangeImport extends Recipe {
|
|
55
55
|
readonly name = "org.openrewrite.javascript.change-import";
|
|
@@ -85,19 +85,11 @@ export class ChangeImport extends Recipe {
|
|
|
85
85
|
})
|
|
86
86
|
newMember?: string;
|
|
87
87
|
|
|
88
|
-
@Option({
|
|
89
|
-
displayName: "New alias",
|
|
90
|
-
description: "Optional alias for the new import. Required when newMember is 'default' or '*'.",
|
|
91
|
-
required: false
|
|
92
|
-
})
|
|
93
|
-
newAlias?: string;
|
|
94
|
-
|
|
95
88
|
constructor(options?: {
|
|
96
89
|
oldModule?: string;
|
|
97
90
|
oldMember?: string;
|
|
98
91
|
newModule?: string;
|
|
99
92
|
newMember?: string;
|
|
100
|
-
newAlias?: string;
|
|
101
93
|
}) {
|
|
102
94
|
super(options);
|
|
103
95
|
}
|
|
@@ -107,7 +99,6 @@ export class ChangeImport extends Recipe {
|
|
|
107
99
|
const oldMember = this.oldMember;
|
|
108
100
|
const newModule = this.newModule;
|
|
109
101
|
const newMember = this.newMember ?? oldMember;
|
|
110
|
-
const newAlias = this.newAlias;
|
|
111
102
|
|
|
112
103
|
// Build the old and new FQNs for type attribution updates
|
|
113
104
|
const oldFqn = oldMember === 'default' || oldMember === '*'
|
|
@@ -119,185 +110,14 @@ export class ChangeImport extends Recipe {
|
|
|
119
110
|
|
|
120
111
|
return new class extends JavaScriptVisitor<ExecutionContext> {
|
|
121
112
|
private hasOldImport = false;
|
|
122
|
-
private oldAlias?: string;
|
|
123
|
-
private transformedImport = false;
|
|
124
113
|
|
|
125
114
|
override async visitJsCompilationUnit(cu: JS.CompilationUnit, ctx: ExecutionContext): Promise<J | undefined> {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
// First pass: check if the old import exists and capture any alias
|
|
132
|
-
for (const statement of cu.statements) {
|
|
133
|
-
const stmt = statement.element ?? statement;
|
|
134
|
-
if (stmt.kind === JS.Kind.Import) {
|
|
135
|
-
const jsImport = stmt as JS.Import;
|
|
136
|
-
const aliasInfo = this.checkForOldImport(jsImport);
|
|
137
|
-
if (aliasInfo.found) {
|
|
138
|
-
this.hasOldImport = true;
|
|
139
|
-
this.oldAlias = aliasInfo.alias;
|
|
140
|
-
break;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Visit the compilation unit (this will transform imports via visitJsImport)
|
|
146
|
-
let result = await super.visitJsCompilationUnit(cu, ctx) as JS.CompilationUnit;
|
|
147
|
-
|
|
148
|
-
// If we transformed an import but need to add to existing import from new module,
|
|
149
|
-
// or if we only removed a member from a multi-import, use maybeAddImport
|
|
150
|
-
if (this.hasOldImport && !this.transformedImport) {
|
|
151
|
-
const aliasToUse = newAlias ?? this.oldAlias;
|
|
152
|
-
|
|
153
|
-
if (newMember === 'default') {
|
|
154
|
-
maybeAddImport(this, {
|
|
155
|
-
module: newModule,
|
|
156
|
-
member: 'default',
|
|
157
|
-
alias: aliasToUse,
|
|
158
|
-
onlyIfReferenced: false
|
|
159
|
-
});
|
|
160
|
-
} else if (newMember === '*') {
|
|
161
|
-
maybeAddImport(this, {
|
|
162
|
-
module: newModule,
|
|
163
|
-
member: '*',
|
|
164
|
-
alias: aliasToUse,
|
|
165
|
-
onlyIfReferenced: false
|
|
166
|
-
});
|
|
167
|
-
} else if (aliasToUse && aliasToUse !== newMember) {
|
|
168
|
-
maybeAddImport(this, {
|
|
169
|
-
module: newModule,
|
|
170
|
-
member: newMember,
|
|
171
|
-
alias: aliasToUse,
|
|
172
|
-
onlyIfReferenced: false
|
|
173
|
-
});
|
|
174
|
-
} else {
|
|
175
|
-
maybeAddImport(this, {
|
|
176
|
-
module: newModule,
|
|
177
|
-
member: newMember,
|
|
178
|
-
onlyIfReferenced: false
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return result;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
override async visitImportDeclaration(jsImport: JS.Import, ctx: ExecutionContext): Promise<J | undefined> {
|
|
187
|
-
let imp = await super.visitImportDeclaration(jsImport, ctx) as JS.Import;
|
|
188
|
-
|
|
189
|
-
if (!this.hasOldImport) {
|
|
190
|
-
return imp;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const aliasInfo = this.checkForOldImport(imp);
|
|
194
|
-
if (!aliasInfo.found) {
|
|
195
|
-
return imp;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Check if this is the only import from the old module
|
|
199
|
-
const namedImports = this.getNamedImports(imp);
|
|
200
|
-
const isOnlyImport = namedImports.length === 1 ||
|
|
201
|
-
(oldMember === 'default' && !imp.importClause?.namedBindings) ||
|
|
202
|
-
(oldMember === '*');
|
|
203
|
-
|
|
204
|
-
if (isOnlyImport) {
|
|
205
|
-
// Transform the module specifier in place
|
|
206
|
-
this.transformedImport = true;
|
|
207
|
-
return produce(imp, draft => {
|
|
208
|
-
if (draft.moduleSpecifier) {
|
|
209
|
-
const literal = draft.moduleSpecifier.element as Draft<J.Literal>;
|
|
210
|
-
literal.value = newModule;
|
|
211
|
-
// Update valueSource to preserve quote style
|
|
212
|
-
const originalSource = literal.valueSource || `"${oldModule}"`;
|
|
213
|
-
const quoteChar = originalSource.startsWith("'") ? "'" : '"';
|
|
214
|
-
literal.valueSource = `${quoteChar}${newModule}${quoteChar}`;
|
|
215
|
-
}
|
|
216
|
-
// If we're also renaming the member, update the import specifier
|
|
217
|
-
if (newMember !== oldMember && oldMember !== 'default' && oldMember !== '*') {
|
|
218
|
-
const importClause = draft.importClause;
|
|
219
|
-
if (importClause?.namedBindings?.kind === JS.Kind.NamedImports) {
|
|
220
|
-
const namedImports = importClause.namedBindings as Draft<JS.NamedImports>;
|
|
221
|
-
for (const elem of namedImports.elements.elements) {
|
|
222
|
-
const specifier = elem.element;
|
|
223
|
-
if (specifier.specifier.kind === J.Kind.Identifier &&
|
|
224
|
-
specifier.specifier.simpleName === oldMember) {
|
|
225
|
-
specifier.specifier.simpleName = newMember;
|
|
226
|
-
} else if (specifier.specifier.kind === JS.Kind.Alias) {
|
|
227
|
-
const aliasNode = specifier.specifier as Draft<JS.Alias>;
|
|
228
|
-
const propertyName = aliasNode.propertyName.element;
|
|
229
|
-
if (propertyName.kind === J.Kind.Identifier &&
|
|
230
|
-
propertyName.simpleName === oldMember) {
|
|
231
|
-
propertyName.simpleName = newMember;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
} else {
|
|
239
|
-
// Remove just the specific member from the import
|
|
240
|
-
// maybeAddImport will add the new import
|
|
241
|
-
return this.removeNamedImportMember(imp, oldMember, ctx);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
private async removeNamedImportMember(imp: JS.Import, memberToRemove: string, _ctx: ExecutionContext): Promise<JS.Import> {
|
|
246
|
-
return produce(imp, draft => {
|
|
247
|
-
const importClause = draft.importClause;
|
|
248
|
-
if (!importClause?.namedBindings) return;
|
|
249
|
-
if (importClause.namedBindings.kind !== JS.Kind.NamedImports) return;
|
|
250
|
-
|
|
251
|
-
const namedImports = importClause.namedBindings as Draft<JS.NamedImports>;
|
|
252
|
-
const elements = namedImports.elements.elements;
|
|
253
|
-
const filteredElements = elements.filter(elem => {
|
|
254
|
-
const specifier = elem.element;
|
|
255
|
-
const specifierNode = specifier.specifier;
|
|
256
|
-
|
|
257
|
-
if (specifierNode.kind === J.Kind.Identifier) {
|
|
258
|
-
return specifierNode.simpleName !== memberToRemove;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (specifierNode.kind === JS.Kind.Alias) {
|
|
262
|
-
const alias = specifierNode as JS.Alias;
|
|
263
|
-
const propertyName = alias.propertyName.element;
|
|
264
|
-
if (propertyName.kind === J.Kind.Identifier) {
|
|
265
|
-
return propertyName.simpleName !== memberToRemove;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return true;
|
|
270
|
-
});
|
|
115
|
+
this.hasOldImport = maybeRebind(this, {
|
|
116
|
+
from: {module: oldModule, member: oldMember},
|
|
117
|
+
to: {module: newModule, member: newMember}
|
|
118
|
+
}) !== undefined;
|
|
271
119
|
|
|
272
|
-
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
private getNamedImports(imp: JS.Import): string[] {
|
|
277
|
-
const imports: string[] = [];
|
|
278
|
-
const importClause = imp.importClause;
|
|
279
|
-
if (!importClause) return imports;
|
|
280
|
-
|
|
281
|
-
const namedBindings = importClause.namedBindings;
|
|
282
|
-
if (!namedBindings || namedBindings.kind !== JS.Kind.NamedImports) return imports;
|
|
283
|
-
|
|
284
|
-
const namedImports = namedBindings as JS.NamedImports;
|
|
285
|
-
for (const elem of namedImports.elements.elements) {
|
|
286
|
-
const specifier = elem.element;
|
|
287
|
-
const specifierNode = specifier.specifier;
|
|
288
|
-
|
|
289
|
-
if (isIdentifier(specifierNode)) {
|
|
290
|
-
imports.push(specifierNode.simpleName);
|
|
291
|
-
} else if (specifierNode.kind === JS.Kind.Alias) {
|
|
292
|
-
const alias = specifierNode as JS.Alias;
|
|
293
|
-
const propertyName = alias.propertyName.element;
|
|
294
|
-
if (isIdentifier(propertyName)) {
|
|
295
|
-
imports.push(propertyName.simpleName);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
return imports;
|
|
120
|
+
return super.visitJsCompilationUnit(cu, ctx);
|
|
301
121
|
}
|
|
302
122
|
|
|
303
123
|
override async visitIdentifier(identifier: J.Identifier, ctx: ExecutionContext): Promise<J | undefined> {
|
|
@@ -629,79 +449,6 @@ export class ChangeImport extends Recipe {
|
|
|
629
449
|
}
|
|
630
450
|
return arrayType;
|
|
631
451
|
}
|
|
632
|
-
|
|
633
|
-
private checkForOldImport(jsImport: JS.Import): { found: boolean; alias?: string } {
|
|
634
|
-
// Check if this import is from the old module
|
|
635
|
-
const moduleSpecifier = jsImport.moduleSpecifier;
|
|
636
|
-
if (!moduleSpecifier) return { found: false };
|
|
637
|
-
|
|
638
|
-
const literal = moduleSpecifier.element;
|
|
639
|
-
if (literal.kind !== J.Kind.Literal) return { found: false };
|
|
640
|
-
|
|
641
|
-
const value = (literal as J.Literal).value;
|
|
642
|
-
if (value !== oldModule) return { found: false };
|
|
643
|
-
|
|
644
|
-
const importClause = jsImport.importClause;
|
|
645
|
-
if (!importClause) {
|
|
646
|
-
// Side-effect import - not what we're looking for
|
|
647
|
-
return { found: false };
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
// Check for default import
|
|
651
|
-
if (oldMember === 'default') {
|
|
652
|
-
if (importClause.name) {
|
|
653
|
-
const nameElem = importClause.name.element;
|
|
654
|
-
if (isIdentifier(nameElem)) {
|
|
655
|
-
return { found: true, alias: nameElem.simpleName };
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
return { found: false };
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
// Check for namespace import
|
|
662
|
-
if (oldMember === '*') {
|
|
663
|
-
const namedBindings = importClause.namedBindings;
|
|
664
|
-
if (namedBindings?.kind === JS.Kind.Alias) {
|
|
665
|
-
const alias = namedBindings as JS.Alias;
|
|
666
|
-
if (isIdentifier(alias.alias)) {
|
|
667
|
-
return { found: true, alias: alias.alias.simpleName };
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
return { found: false };
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
// Check for named imports
|
|
674
|
-
const namedBindings = importClause.namedBindings;
|
|
675
|
-
if (!namedBindings) return { found: false };
|
|
676
|
-
|
|
677
|
-
if (namedBindings.kind !== JS.Kind.NamedImports) return { found: false };
|
|
678
|
-
|
|
679
|
-
const namedImports = namedBindings as JS.NamedImports;
|
|
680
|
-
const elements = namedImports.elements.elements;
|
|
681
|
-
|
|
682
|
-
for (const elem of elements) {
|
|
683
|
-
const specifier = elem.element;
|
|
684
|
-
const specifierNode = specifier.specifier;
|
|
685
|
-
|
|
686
|
-
// Handle direct import: import { act }
|
|
687
|
-
if (isIdentifier(specifierNode) && specifierNode.simpleName === oldMember) {
|
|
688
|
-
return { found: true };
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
// Handle aliased import: import { act as something }
|
|
692
|
-
if (specifierNode.kind === JS.Kind.Alias) {
|
|
693
|
-
const alias = specifierNode as JS.Alias;
|
|
694
|
-
const propertyName = alias.propertyName.element;
|
|
695
|
-
if (isIdentifier(propertyName) && propertyName.simpleName === oldMember) {
|
|
696
|
-
if (isIdentifier(alias.alias)) {
|
|
697
|
-
return { found: true, alias: alias.alias.simpleName };
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
return { found: false };
|
|
704
|
-
}
|
|
705
452
|
}();
|
|
706
453
|
}
|
|
707
454
|
}
|
|
@@ -1,44 +1,10 @@
|
|
|
1
1
|
import {JavaScriptVisitor} from "./visitor";
|
|
2
2
|
import {J} from "../java";
|
|
3
|
+
import {bindingNames} from "./scope";
|
|
3
4
|
import {JS, JSX} from "./tree";
|
|
4
5
|
import {mapAsync, updateIfChanged} from "../util";
|
|
5
6
|
import {ElementRemovalFormatter} from "../java";
|
|
6
7
|
|
|
7
|
-
/**
|
|
8
|
-
* @param visitor The visitor to add the import removal to
|
|
9
|
-
* @param module The module name (e.g., 'fs', 'react') to remove imports from
|
|
10
|
-
* @param member Optionally, the specific member to remove from the import.
|
|
11
|
-
* If not specified, removes all unused imports from the module.
|
|
12
|
-
* Special values:
|
|
13
|
-
* - 'default': Removes the default import from the module if unused,
|
|
14
|
-
* regardless of its local name (e.g., `import React from 'react'`)
|
|
15
|
-
* - '*': Removes the namespace import if unused (e.g., `import * as fs from 'fs'`)
|
|
16
|
-
*
|
|
17
|
-
* @example
|
|
18
|
-
* // Remove a specific named import if unused
|
|
19
|
-
* maybeRemoveImport(visitor, 'fs', 'readFile');
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* // Remove the default import from 'react' if unused (regardless of local name)
|
|
23
|
-
* maybeRemoveImport(visitor, 'react', 'default');
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* // Remove all unused imports from 'react' module
|
|
27
|
-
* maybeRemoveImport(visitor, 'react');
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
* // Remove namespace import if unused
|
|
31
|
-
* maybeRemoveImport(visitor, 'fs', '*');
|
|
32
|
-
*/
|
|
33
|
-
export function maybeRemoveImport(visitor: JavaScriptVisitor<any>, module: string, member?: string) {
|
|
34
|
-
for (const v of visitor.afterVisit || []) {
|
|
35
|
-
if (v instanceof RemoveImport && v.module === module && v.member === member) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
visitor.afterVisit.push(new RemoveImport(module, member));
|
|
40
|
-
}
|
|
41
|
-
|
|
42
8
|
// Type alias for RightPadded elements to simplify type signatures
|
|
43
9
|
type RightPaddedElement<T extends J> = {
|
|
44
10
|
element?: T;
|
|
@@ -268,7 +234,7 @@ export class RemoveImport<P> extends JavaScriptVisitor<P> {
|
|
|
268
234
|
shouldRemove = !usedIdentifiers.has(name) && !usedTypes.has(name);
|
|
269
235
|
} else {
|
|
270
236
|
// Regular case: check if the import name matches the removal criteria
|
|
271
|
-
shouldRemove = this.shouldRemoveImport(name, usedIdentifiers, usedTypes);
|
|
237
|
+
shouldRemove = this.shouldRemoveImport(name, usedIdentifiers, usedTypes, name);
|
|
272
238
|
}
|
|
273
239
|
|
|
274
240
|
if (shouldRemove) {
|
|
@@ -325,7 +291,7 @@ export class RemoveImport<P> extends JavaScriptVisitor<P> {
|
|
|
325
291
|
}, p);
|
|
326
292
|
}
|
|
327
293
|
// Namespace is used, we can't remove individual members from it
|
|
328
|
-
} else if (this.shouldRemoveImport(name, usedIdentifiers, usedTypes)) {
|
|
294
|
+
} else if (this.shouldRemoveImport(name, usedIdentifiers, usedTypes, name)) {
|
|
329
295
|
// If there's no default import, remove the entire import
|
|
330
296
|
if (!importClause.name) {
|
|
331
297
|
return undefined;
|
|
@@ -355,7 +321,7 @@ export class RemoveImport<P> extends JavaScriptVisitor<P> {
|
|
|
355
321
|
}, p);
|
|
356
322
|
}
|
|
357
323
|
// Namespace is used, we can't remove individual members from it
|
|
358
|
-
} else if (this.shouldRemoveImport(aliasName, usedIdentifiers, usedTypes)) {
|
|
324
|
+
} else if (this.shouldRemoveImport(aliasName, usedIdentifiers, usedTypes, aliasName)) {
|
|
359
325
|
// If there's no default import, remove the entire import
|
|
360
326
|
if (!importClause.name) {
|
|
361
327
|
return undefined;
|
|
@@ -490,7 +456,7 @@ export class RemoveImport<P> extends JavaScriptVisitor<P> {
|
|
|
490
456
|
return true; // Keep imports that don't match the member
|
|
491
457
|
} else {
|
|
492
458
|
// We're removing based on the import name itself
|
|
493
|
-
return !this.shouldRemoveImport(importName, usedIdentifiers, usedTypes);
|
|
459
|
+
return !this.shouldRemoveImport(importName, usedIdentifiers, usedTypes, importName);
|
|
494
460
|
}
|
|
495
461
|
}
|
|
496
462
|
return true; // Keep non-ImportSpecifier elements
|
|
@@ -612,14 +578,10 @@ export class RemoveImport<P> extends JavaScriptVisitor<P> {
|
|
|
612
578
|
const {filtered, allRemoved} = await this.filterElementsWithPrefixPreservation(
|
|
613
579
|
pattern.bindings.elements,
|
|
614
580
|
(elem: J) => {
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
const name = (elem as J.Identifier).simpleName;
|
|
620
|
-
return !this.shouldRemoveImport(name, usedIdentifiers, new Set());
|
|
621
|
-
}
|
|
622
|
-
return true; // Keep other element types
|
|
581
|
+
const bound = this.boundByPatternElement(elem);
|
|
582
|
+
// An element whose names cannot be read is left alone.
|
|
583
|
+
return bound.length === 0 ||
|
|
584
|
+
bound.some(b => !this.shouldRemoveImport(b.name, usedIdentifiers, new Set(), b.member));
|
|
623
585
|
},
|
|
624
586
|
async (elem: J, prefix: J.Space) => {
|
|
625
587
|
if (elem.kind === J.Kind.Identifier) {
|
|
@@ -687,23 +649,25 @@ export class RemoveImport<P> extends JavaScriptVisitor<P> {
|
|
|
687
649
|
return undefined;
|
|
688
650
|
}
|
|
689
651
|
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
652
|
+
/** The names a pattern element binds, and for each the member of the module it reads. */
|
|
653
|
+
private boundByPatternElement(elem: J): { name: string; member?: string }[] {
|
|
654
|
+
// Shorthand, so the name it binds is the member it reads.
|
|
655
|
+
return elem.kind === J.Kind.Identifier
|
|
656
|
+
? [{name: (elem as J.Identifier).simpleName, member: (elem as J.Identifier).simpleName}]
|
|
657
|
+
: bindingNames(elem);
|
|
696
658
|
}
|
|
697
659
|
|
|
698
660
|
private shouldRemoveImport(
|
|
699
661
|
name: string,
|
|
700
662
|
usedIdentifiers: Set<string>,
|
|
701
|
-
usedTypes: Set<string
|
|
663
|
+
usedTypes: Set<string>,
|
|
664
|
+
member: string | undefined
|
|
702
665
|
): boolean {
|
|
703
666
|
// If member is specified, we're removing a specific member from the module
|
|
704
667
|
if (this.member !== undefined) {
|
|
705
|
-
//
|
|
706
|
-
|
|
668
|
+
// A name bound under an alias reads one member and is referenced by another, and a name
|
|
669
|
+
// a nested pattern binds reads a property of a property, so it reads no member at all.
|
|
670
|
+
if (this.member !== member) {
|
|
707
671
|
return false;
|
|
708
672
|
}
|
|
709
673
|
}
|