@openrewrite/rewrite 8.91.1 → 8.91.3

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.
Files changed (160) hide show
  1. package/dist/execution.d.ts +8 -0
  2. package/dist/execution.d.ts.map +1 -1
  3. package/dist/execution.js +31 -0
  4. package/dist/execution.js.map +1 -1
  5. package/dist/javascript/add-import.d.ts +127 -38
  6. package/dist/javascript/add-import.d.ts.map +1 -1
  7. package/dist/javascript/add-import.js +684 -195
  8. package/dist/javascript/add-import.js.map +1 -1
  9. package/dist/javascript/amd.d.ts +148 -0
  10. package/dist/javascript/amd.d.ts.map +1 -0
  11. package/dist/javascript/amd.js +802 -0
  12. package/dist/javascript/amd.js.map +1 -0
  13. package/dist/javascript/binding.d.ts +102 -0
  14. package/dist/javascript/binding.d.ts.map +1 -0
  15. package/dist/javascript/binding.js +308 -0
  16. package/dist/javascript/binding.js.map +1 -0
  17. package/dist/javascript/comparator.d.ts +2 -0
  18. package/dist/javascript/comparator.d.ts.map +1 -1
  19. package/dist/javascript/comparator.js +5 -1
  20. package/dist/javascript/comparator.js.map +1 -1
  21. package/dist/javascript/format/format.d.ts +5 -2
  22. package/dist/javascript/format/format.d.ts.map +1 -1
  23. package/dist/javascript/format/format.js +51 -11
  24. package/dist/javascript/format/format.js.map +1 -1
  25. package/dist/javascript/format/minimum-viable-spacing-visitor.d.ts +19 -0
  26. package/dist/javascript/format/minimum-viable-spacing-visitor.d.ts.map +1 -1
  27. package/dist/javascript/format/minimum-viable-spacing-visitor.js +180 -7
  28. package/dist/javascript/format/minimum-viable-spacing-visitor.js.map +1 -1
  29. package/dist/javascript/format/prettier-format.d.ts +2 -1
  30. package/dist/javascript/format/prettier-format.d.ts.map +1 -1
  31. package/dist/javascript/format/prettier-format.js +33 -23
  32. package/dist/javascript/format/prettier-format.js.map +1 -1
  33. package/dist/javascript/index.d.ts +8 -1
  34. package/dist/javascript/index.d.ts.map +1 -1
  35. package/dist/javascript/index.js +46 -1
  36. package/dist/javascript/index.js.map +1 -1
  37. package/dist/javascript/parser-utils.d.ts.map +1 -1
  38. package/dist/javascript/parser-utils.js +7 -9
  39. package/dist/javascript/parser-utils.js.map +1 -1
  40. package/dist/javascript/parser.d.ts +7 -1
  41. package/dist/javascript/parser.d.ts.map +1 -1
  42. package/dist/javascript/parser.js +55 -4
  43. package/dist/javascript/parser.js.map +1 -1
  44. package/dist/javascript/print.d.ts +1 -0
  45. package/dist/javascript/print.d.ts.map +1 -1
  46. package/dist/javascript/print.js +9 -0
  47. package/dist/javascript/print.js.map +1 -1
  48. package/dist/javascript/recipes/change-import.d.ts +4 -3
  49. package/dist/javascript/recipes/change-import.d.ts.map +1 -1
  50. package/dist/javascript/recipes/change-import.js +12 -504
  51. package/dist/javascript/recipes/change-import.js.map +1 -1
  52. package/dist/javascript/remove-import.d.ts +2 -28
  53. package/dist/javascript/remove-import.d.ts.map +1 -1
  54. package/dist/javascript/remove-import.js +19 -57
  55. package/dist/javascript/remove-import.js.map +1 -1
  56. package/dist/javascript/rpc.js +2 -0
  57. package/dist/javascript/rpc.js.map +1 -1
  58. package/dist/javascript/scope.d.ts +82 -0
  59. package/dist/javascript/scope.d.ts.map +1 -0
  60. package/dist/javascript/scope.js +476 -0
  61. package/dist/javascript/scope.js.map +1 -0
  62. package/dist/javascript/templating/bindings.d.ts +0 -11
  63. package/dist/javascript/templating/bindings.d.ts.map +1 -1
  64. package/dist/javascript/templating/bindings.js +2 -49
  65. package/dist/javascript/templating/bindings.js.map +1 -1
  66. package/dist/javascript/templating/comparator.d.ts +12 -0
  67. package/dist/javascript/templating/comparator.d.ts.map +1 -1
  68. package/dist/javascript/templating/comparator.js +68 -14
  69. package/dist/javascript/templating/comparator.js.map +1 -1
  70. package/dist/javascript/templating/engine.d.ts +22 -4
  71. package/dist/javascript/templating/engine.d.ts.map +1 -1
  72. package/dist/javascript/templating/engine.js +68 -24
  73. package/dist/javascript/templating/engine.js.map +1 -1
  74. package/dist/javascript/templating/index.d.ts +1 -1
  75. package/dist/javascript/templating/index.d.ts.map +1 -1
  76. package/dist/javascript/templating/index.js.map +1 -1
  77. package/dist/javascript/templating/pattern.d.ts.map +1 -1
  78. package/dist/javascript/templating/pattern.js +2 -2
  79. package/dist/javascript/templating/pattern.js.map +1 -1
  80. package/dist/javascript/templating/placeholder-replacement.d.ts +2 -0
  81. package/dist/javascript/templating/placeholder-replacement.d.ts.map +1 -1
  82. package/dist/javascript/templating/placeholder-replacement.js +10 -5
  83. package/dist/javascript/templating/placeholder-replacement.js.map +1 -1
  84. package/dist/javascript/templating/precedence.d.ts +12 -4
  85. package/dist/javascript/templating/precedence.d.ts.map +1 -1
  86. package/dist/javascript/templating/precedence.js +18 -11
  87. package/dist/javascript/templating/precedence.js.map +1 -1
  88. package/dist/javascript/templating/rewrite.d.ts.map +1 -1
  89. package/dist/javascript/templating/rewrite.js +7 -1
  90. package/dist/javascript/templating/rewrite.js.map +1 -1
  91. package/dist/javascript/templating/template.d.ts +7 -1
  92. package/dist/javascript/templating/template.d.ts.map +1 -1
  93. package/dist/javascript/templating/template.js +54 -28
  94. package/dist/javascript/templating/template.js.map +1 -1
  95. package/dist/javascript/templating/types.d.ts +15 -18
  96. package/dist/javascript/templating/types.d.ts.map +1 -1
  97. package/dist/javascript/templating/utils.d.ts +1 -1
  98. package/dist/javascript/templating/utils.d.ts.map +1 -1
  99. package/dist/javascript/templating/utils.js +3 -2
  100. package/dist/javascript/templating/utils.js.map +1 -1
  101. package/dist/javascript/tree.d.ts +1 -0
  102. package/dist/javascript/tree.d.ts.map +1 -1
  103. package/dist/javascript/tree.js.map +1 -1
  104. package/dist/javascript/type-mapping.d.ts.map +1 -1
  105. package/dist/javascript/type-mapping.js +14 -0
  106. package/dist/javascript/type-mapping.js.map +1 -1
  107. package/dist/javascript/visitor.d.ts.map +1 -1
  108. package/dist/javascript/visitor.js +1 -0
  109. package/dist/javascript/visitor.js.map +1 -1
  110. package/dist/parser.d.ts +6 -0
  111. package/dist/parser.d.ts.map +1 -1
  112. package/dist/parser.js +23 -1
  113. package/dist/parser.js.map +1 -1
  114. package/dist/print.d.ts.map +1 -1
  115. package/dist/print.js +5 -2
  116. package/dist/print.js.map +1 -1
  117. package/dist/rewrite-javascript-version.txt +1 -1
  118. package/dist/rpc/request/parse-project.d.ts +11 -1
  119. package/dist/rpc/request/parse-project.d.ts.map +1 -1
  120. package/dist/rpc/request/parse-project.js +7 -2
  121. package/dist/rpc/request/parse-project.js.map +1 -1
  122. package/dist/rpc/request/parse.d.ts +13 -1
  123. package/dist/rpc/request/parse.d.ts.map +1 -1
  124. package/dist/rpc/request/parse.js +8 -2
  125. package/dist/rpc/request/parse.js.map +1 -1
  126. package/package.json +2 -2
  127. package/src/execution.ts +23 -0
  128. package/src/javascript/add-import.ts +753 -238
  129. package/src/javascript/amd.ts +954 -0
  130. package/src/javascript/binding.ts +435 -0
  131. package/src/javascript/comparator.ts +6 -1
  132. package/src/javascript/format/format.ts +56 -12
  133. package/src/javascript/format/minimum-viable-spacing-visitor.ts +196 -7
  134. package/src/javascript/format/prettier-format.ts +35 -25
  135. package/src/javascript/index.ts +19 -1
  136. package/src/javascript/parser-utils.ts +7 -11
  137. package/src/javascript/parser.ts +78 -6
  138. package/src/javascript/print.ts +10 -0
  139. package/src/javascript/recipes/change-import.ts +13 -593
  140. package/src/javascript/remove-import.ts +20 -56
  141. package/src/javascript/rpc.ts +2 -0
  142. package/src/javascript/scope.ts +517 -0
  143. package/src/javascript/templating/bindings.ts +2 -55
  144. package/src/javascript/templating/comparator.ts +81 -16
  145. package/src/javascript/templating/engine.ts +107 -38
  146. package/src/javascript/templating/index.ts +0 -1
  147. package/src/javascript/templating/pattern.ts +4 -2
  148. package/src/javascript/templating/placeholder-replacement.ts +16 -6
  149. package/src/javascript/templating/precedence.ts +21 -13
  150. package/src/javascript/templating/rewrite.ts +9 -1
  151. package/src/javascript/templating/template.ts +68 -29
  152. package/src/javascript/templating/types.ts +17 -18
  153. package/src/javascript/templating/utils.ts +4 -2
  154. package/src/javascript/tree.ts +1 -0
  155. package/src/javascript/type-mapping.ts +15 -0
  156. package/src/javascript/visitor.ts +1 -0
  157. package/src/parser.ts +24 -1
  158. package/src/print.ts +5 -2
  159. package/src/rpc/request/parse-project.ts +6 -2
  160. package/src/rpc/request/parse.ts +7 -2
@@ -950,6 +950,13 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
950
950
  return typeDeclaration;
951
951
  }
952
952
 
953
+ override async visitUnknownSource(source: J.UnknownSource, p: PrintOutputCapture): Promise<J | undefined> {
954
+ await this.beforeSyntax(source, p);
955
+ p.append(source.text);
956
+ await this.afterSyntax(source, p);
957
+ return source;
958
+ }
959
+
953
960
  override async visitLiteralType(literalType: JS.LiteralType, p: PrintOutputCapture): Promise<J | undefined> {
954
961
  await this.beforeSyntax(literalType, p);
955
962
  await this.visit(literalType.literal, p);
@@ -1413,6 +1420,9 @@ export class JavaScriptPrinter extends JavaScriptVisitor<PrintOutputCapture> {
1413
1420
  override async visitPropertyAssignment(propertyAssignment: JS.PropertyAssignment, p: PrintOutputCapture): Promise<J | undefined> {
1414
1421
  await this.beforeSyntax(propertyAssignment, p);
1415
1422
 
1423
+ for (const m of propertyAssignment.modifiers) {
1424
+ await this.visitModifier(m, p);
1425
+ }
1416
1426
  await this.visitRightPadded(propertyAssignment.name, p);
1417
1427
 
1418
1428
  if (propertyAssignment.initializer) {
@@ -18,9 +18,8 @@ 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 { maybeAddImport } from "../add-import";
22
- import { J, isIdentifier, Type } from "../../java";
23
- import { create as produce, Draft } from "mutative";
21
+ import { maybeRebind } from "../binding";
22
+ import { J } from "../../java";
24
23
 
25
24
  /**
26
25
  * Changes an import from one module to another, updating all type attributions.
@@ -41,15 +40,16 @@ import { create as produce, Draft } from "mutative";
41
40
  * // After: import { act } from 'react';
42
41
  *
43
42
  * @example
44
- * // Change a named import to a different name
43
+ * // Rename a member, carrying the references that resolve to it
45
44
  * const recipe = new ChangeImport({
46
45
  * oldModule: "lodash",
47
46
  * oldMember: "extend",
48
47
  * newModule: "lodash",
49
48
  * newMember: "assign"
50
49
  * });
51
- * // Before: import { extend } from 'lodash';
52
- * // After: import { assign } from 'lodash';
50
+ * // Before: import { extend } from 'lodash'; extend({}, {});
51
+ * // After: import { assign } from 'lodash'; assign({}, {});
52
+ * // Adding `newAlias: "extend"` instead binds it as `import { assign as extend }`.
53
53
  */
54
54
  export class ChangeImport extends Recipe {
55
55
  readonly name = "org.openrewrite.javascript.change-import";
@@ -87,7 +87,9 @@ export class ChangeImport extends Recipe {
87
87
 
88
88
  @Option({
89
89
  displayName: "New alias",
90
- description: "Optional alias for the new import. Required when newMember is 'default' or '*'.",
90
+ description: "The local name to bind the new member under. Defaults to the alias the import " +
91
+ "already had, or to the new member name where it had none.",
92
+ example: "act",
91
93
  required: false
92
94
  })
93
95
  newAlias?: string;
@@ -109,595 +111,13 @@ export class ChangeImport extends Recipe {
109
111
  const newMember = this.newMember ?? oldMember;
110
112
  const newAlias = this.newAlias;
111
113
 
112
- // Build the old and new FQNs for type attribution updates
113
- const oldFqn = oldMember === 'default' || oldMember === '*'
114
- ? oldModule
115
- : `${oldModule}.${oldMember}`;
116
- const newFqn = newMember === 'default' || newMember === '*'
117
- ? newModule
118
- : `${newModule}.${newMember}`;
119
-
120
114
  return new class extends JavaScriptVisitor<ExecutionContext> {
121
- private hasOldImport = false;
122
- private oldAlias?: string;
123
- private transformedImport = false;
124
-
125
115
  override async visitJsCompilationUnit(cu: JS.CompilationUnit, ctx: ExecutionContext): Promise<J | undefined> {
126
- // Reset tracking for each file
127
- this.hasOldImport = false;
128
- this.oldAlias = undefined;
129
- this.transformedImport = false;
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 {
168
- maybeAddImport(this, {
169
- module: newModule,
170
- member: newMember,
171
- // A moved binding keeps the local name it had. Pinning it also tells
172
- // `maybeAddImport` not to deconflict against the import being replaced,
173
- // which is still present in the tree it reads.
174
- alias: aliasToUse ?? newMember,
175
- onlyIfReferenced: false
176
- });
177
- }
178
- }
179
-
180
- return result;
181
- }
182
-
183
- override async visitImportDeclaration(jsImport: JS.Import, ctx: ExecutionContext): Promise<J | undefined> {
184
- let imp = await super.visitImportDeclaration(jsImport, ctx) as JS.Import;
185
-
186
- if (!this.hasOldImport) {
187
- return imp;
188
- }
189
-
190
- const aliasInfo = this.checkForOldImport(imp);
191
- if (!aliasInfo.found) {
192
- return imp;
193
- }
194
-
195
- // Check if this is the only import from the old module
196
- const namedImports = this.getNamedImports(imp);
197
- const isOnlyImport = namedImports.length === 1 ||
198
- (oldMember === 'default' && !imp.importClause?.namedBindings) ||
199
- (oldMember === '*');
200
-
201
- if (isOnlyImport) {
202
- // Transform the module specifier in place
203
- this.transformedImport = true;
204
- return produce(imp, draft => {
205
- if (draft.moduleSpecifier) {
206
- const literal = draft.moduleSpecifier.element as Draft<J.Literal>;
207
- literal.value = newModule;
208
- // Update valueSource to preserve quote style
209
- const originalSource = literal.valueSource || `"${oldModule}"`;
210
- const quoteChar = originalSource.startsWith("'") ? "'" : '"';
211
- literal.valueSource = `${quoteChar}${newModule}${quoteChar}`;
212
- }
213
- // If we're also renaming the member, update the import specifier
214
- if (newMember !== oldMember && oldMember !== 'default' && oldMember !== '*') {
215
- const importClause = draft.importClause;
216
- if (importClause?.namedBindings?.kind === JS.Kind.NamedImports) {
217
- const namedImports = importClause.namedBindings as Draft<JS.NamedImports>;
218
- for (const elem of namedImports.elements.elements) {
219
- const specifier = elem.element;
220
- if (specifier.specifier.kind === J.Kind.Identifier &&
221
- specifier.specifier.simpleName === oldMember) {
222
- specifier.specifier.simpleName = newMember;
223
- } else if (specifier.specifier.kind === JS.Kind.Alias) {
224
- const aliasNode = specifier.specifier as Draft<JS.Alias>;
225
- const propertyName = aliasNode.propertyName.element;
226
- if (propertyName.kind === J.Kind.Identifier &&
227
- propertyName.simpleName === oldMember) {
228
- propertyName.simpleName = newMember;
229
- }
230
- }
231
- }
232
- }
233
- }
234
- });
235
- } else {
236
- // Remove just the specific member from the import
237
- // maybeAddImport will add the new import
238
- return this.removeNamedImportMember(imp, oldMember, ctx);
239
- }
240
- }
241
-
242
- private async removeNamedImportMember(imp: JS.Import, memberToRemove: string, _ctx: ExecutionContext): Promise<JS.Import> {
243
- return produce(imp, draft => {
244
- const importClause = draft.importClause;
245
- if (!importClause?.namedBindings) return;
246
- if (importClause.namedBindings.kind !== JS.Kind.NamedImports) return;
247
-
248
- const namedImports = importClause.namedBindings as Draft<JS.NamedImports>;
249
- const elements = namedImports.elements.elements;
250
- const filteredElements = elements.filter(elem => {
251
- const specifier = elem.element;
252
- const specifierNode = specifier.specifier;
253
-
254
- if (specifierNode.kind === J.Kind.Identifier) {
255
- return specifierNode.simpleName !== memberToRemove;
256
- }
257
-
258
- if (specifierNode.kind === JS.Kind.Alias) {
259
- const alias = specifierNode as JS.Alias;
260
- const propertyName = alias.propertyName.element;
261
- if (propertyName.kind === J.Kind.Identifier) {
262
- return propertyName.simpleName !== memberToRemove;
263
- }
264
- }
265
-
266
- return true;
267
- });
268
-
269
- namedImports.elements.elements = filteredElements;
116
+ maybeRebind(this, {
117
+ from: {module: oldModule, member: oldMember},
118
+ to: {module: newModule, member: newMember, alias: newAlias}
270
119
  });
271
- }
272
-
273
- private getNamedImports(imp: JS.Import): string[] {
274
- const imports: string[] = [];
275
- const importClause = imp.importClause;
276
- if (!importClause) return imports;
277
-
278
- const namedBindings = importClause.namedBindings;
279
- if (!namedBindings || namedBindings.kind !== JS.Kind.NamedImports) return imports;
280
-
281
- const namedImports = namedBindings as JS.NamedImports;
282
- for (const elem of namedImports.elements.elements) {
283
- const specifier = elem.element;
284
- const specifierNode = specifier.specifier;
285
-
286
- if (isIdentifier(specifierNode)) {
287
- imports.push(specifierNode.simpleName);
288
- } else if (specifierNode.kind === JS.Kind.Alias) {
289
- const alias = specifierNode as JS.Alias;
290
- const propertyName = alias.propertyName.element;
291
- if (isIdentifier(propertyName)) {
292
- imports.push(propertyName.simpleName);
293
- }
294
- }
295
- }
296
-
297
- return imports;
298
- }
299
-
300
- override async visitIdentifier(identifier: J.Identifier, ctx: ExecutionContext): Promise<J | undefined> {
301
- let ident = await super.visitIdentifier(identifier, ctx) as J.Identifier;
302
-
303
- if (!this.hasOldImport) {
304
- return ident;
305
- }
306
-
307
- // Check and update type attribution
308
- let changed = false;
309
-
310
- // Update type if it references the old module
311
- const updatedType = this.updateType(ident.type);
312
- if (updatedType !== ident.type) {
313
- changed = true;
314
- }
315
-
316
- // Update fieldType if it references the old module
317
- // fieldType is specifically Type.Variable, so we need to handle it specially
318
- let updatedFieldType: Type.Variable | undefined = ident.fieldType;
319
- if (ident.fieldType) {
320
- const updated = this.updateVariableType(ident.fieldType);
321
- if (updated !== ident.fieldType) {
322
- updatedFieldType = updated;
323
- changed = true;
324
- }
325
- }
326
-
327
- if (changed) {
328
- return produce(ident, draft => {
329
- if (updatedType !== ident.type) {
330
- draft.type = updatedType;
331
- }
332
- if (updatedFieldType !== ident.fieldType) {
333
- draft.fieldType = updatedFieldType;
334
- }
335
- });
336
- }
337
-
338
- return ident;
339
- }
340
-
341
- override async visitMethodInvocation(method: J.MethodInvocation, ctx: ExecutionContext): Promise<J | undefined> {
342
- let m = await super.visitMethodInvocation(method, ctx) as J.MethodInvocation;
343
-
344
- if (!this.hasOldImport) {
345
- return m;
346
- }
347
-
348
- // Update methodType if it references the old module
349
- const updatedMethodType = this.updateMethodType(m.methodType);
350
- if (updatedMethodType !== m.methodType) {
351
- return produce(m, draft => {
352
- draft.methodType = updatedMethodType;
353
- });
354
- }
355
-
356
- return m;
357
- }
358
-
359
- override async visitFieldAccess(fieldAccess: J.FieldAccess, ctx: ExecutionContext): Promise<J | undefined> {
360
- let fa = await super.visitFieldAccess(fieldAccess, ctx) as J.FieldAccess;
361
-
362
- if (!this.hasOldImport) {
363
- return fa;
364
- }
365
-
366
- // Update type if it references the old module
367
- const updatedType = this.updateType(fa.type);
368
- if (updatedType !== fa.type) {
369
- return produce(fa, draft => {
370
- draft.type = updatedType;
371
- });
372
- }
373
-
374
- return fa;
375
- }
376
-
377
- override async visitFunctionCall(functionCall: JS.FunctionCall, ctx: ExecutionContext): Promise<J | undefined> {
378
- let fc = await super.visitFunctionCall(functionCall, ctx) as JS.FunctionCall;
379
-
380
- if (!this.hasOldImport) {
381
- return fc;
382
- }
383
-
384
- // Update methodType if it references the old module
385
- const updatedMethodType = this.updateMethodType(fc.methodType);
386
- if (updatedMethodType !== fc.methodType) {
387
- return produce(fc, draft => {
388
- draft.methodType = updatedMethodType;
389
- });
390
- }
391
-
392
- return fc;
393
- }
394
-
395
- override async visitNewClass(newClass: J.NewClass, ctx: ExecutionContext): Promise<J | undefined> {
396
- let nc = await super.visitNewClass(newClass, ctx) as J.NewClass;
397
-
398
- if (!this.hasOldImport) {
399
- return nc;
400
- }
401
-
402
- let changed = false;
403
-
404
- // Update methodType if it references the old module
405
- const updatedMethodType = this.updateMethodType(nc.methodType);
406
- if (updatedMethodType !== nc.methodType) {
407
- changed = true;
408
- }
409
-
410
- // Update constructorType if it references the old module
411
- const updatedConstructorType = this.updateMethodType(nc.constructorType);
412
- if (updatedConstructorType !== nc.constructorType) {
413
- changed = true;
414
- }
415
-
416
- // Update type if it references the old module
417
- const updatedType = this.updateType(nc.type);
418
- if (updatedType !== nc.type) {
419
- changed = true;
420
- }
421
-
422
- if (changed) {
423
- return produce(nc, draft => {
424
- if (updatedMethodType !== nc.methodType) {
425
- draft.methodType = updatedMethodType;
426
- }
427
- if (updatedConstructorType !== nc.constructorType) {
428
- draft.constructorType = updatedConstructorType;
429
- }
430
- if (updatedType !== nc.type) {
431
- draft.type = updatedType;
432
- }
433
- });
434
- }
435
-
436
- return nc;
437
- }
438
-
439
- /**
440
- * Update a type if it references the old module
441
- */
442
- private updateType(type: Type | undefined): Type | undefined {
443
- if (!type) return type;
444
-
445
- switch (type.kind) {
446
- case Type.Kind.Class:
447
- case Type.Kind.ShallowClass:
448
- return this.updateClassType(type as Type.Class);
449
-
450
- case Type.Kind.Method:
451
- return this.updateMethodType(type as Type.Method);
452
-
453
- case Type.Kind.Variable:
454
- return this.updateVariableType(type as Type.Variable);
455
-
456
- case Type.Kind.Parameterized:
457
- return this.updateParameterizedType(type as Type.Parameterized);
458
-
459
- case Type.Kind.Array:
460
- return this.updateArrayType(type as Type.Array);
461
-
462
- default:
463
- return type;
464
- }
465
- }
466
-
467
- /**
468
- * Update a Class type if its FQN references the old module
469
- */
470
- private updateClassType(classType: Type.Class): Type.Class {
471
- let changed = false;
472
- let newFullyQualifiedName = classType.fullyQualifiedName;
473
- let newOwningClass = classType.owningClass;
474
-
475
- // Check if the FQN matches or starts with the old module
476
- if (classType.fullyQualifiedName === oldFqn) {
477
- newFullyQualifiedName = newFqn;
478
- changed = true;
479
- } else if (classType.fullyQualifiedName === oldModule) {
480
- newFullyQualifiedName = newModule;
481
- changed = true;
482
- } else if (classType.fullyQualifiedName.startsWith(oldModule + '.')) {
483
- newFullyQualifiedName = newModule + classType.fullyQualifiedName.substring(oldModule.length);
484
- changed = true;
485
- }
486
-
487
- // Recursively update owningClass
488
- if (classType.owningClass) {
489
- const updatedOwningClass = this.updateClassType(classType.owningClass);
490
- if (updatedOwningClass !== classType.owningClass) {
491
- newOwningClass = updatedOwningClass;
492
- changed = true;
493
- }
494
- }
495
-
496
- if (changed) {
497
- // Type objects are marked as non-draftable, so we manually create new objects
498
- return {
499
- ...classType,
500
- fullyQualifiedName: newFullyQualifiedName,
501
- owningClass: newOwningClass
502
- } as Type.Class;
503
- }
504
-
505
- return classType;
506
- }
507
-
508
- /**
509
- * Update a Method type if its declaringType references the old module
510
- */
511
- private updateMethodType(methodType: Type.Method | undefined): Type.Method | undefined {
512
- if (!methodType) return methodType;
513
-
514
- // Update the declaring type
515
- if (Type.isFullyQualified(methodType.declaringType)) {
516
- const declaringTypeFqn = Type.FullyQualified.getFullyQualifiedName(methodType.declaringType);
517
-
518
- if (declaringTypeFqn === oldModule ||
519
- declaringTypeFqn === oldFqn ||
520
- declaringTypeFqn.startsWith(oldModule + '.')) {
521
-
522
- // Need to update the declaring type
523
- const updatedDeclaringType = this.updateType(methodType.declaringType) as Type.FullyQualified;
524
-
525
- // Also update the method name if we're renaming the member
526
- const updatedName = (oldMember !== 'default' && oldMember !== '*' &&
527
- methodType.name === oldMember && newMember !== oldMember)
528
- ? newMember
529
- : methodType.name;
530
-
531
- // Type objects are marked as non-draftable, so we manually create new objects
532
- return {
533
- ...methodType,
534
- declaringType: updatedDeclaringType,
535
- name: updatedName
536
- } as Type.Method;
537
- }
538
- }
539
-
540
- return methodType;
541
- }
542
-
543
- /**
544
- * Update a Variable type if its owner references the old module
545
- */
546
- private updateVariableType(variableType: Type.Variable): Type.Variable {
547
- let changed = false;
548
- let newOwner = variableType.owner;
549
- let newInnerType = variableType.type;
550
-
551
- // Update owner if it references the old module
552
- if (variableType.owner) {
553
- const updatedOwner = this.updateType(variableType.owner);
554
- if (updatedOwner !== variableType.owner) {
555
- newOwner = updatedOwner;
556
- changed = true;
557
- }
558
- }
559
-
560
- // Update inner type if it references the old module
561
- const updatedInnerType = this.updateType(variableType.type);
562
- if (updatedInnerType !== variableType.type) {
563
- newInnerType = updatedInnerType!;
564
- changed = true;
565
- }
566
-
567
- if (changed) {
568
- // Type objects are marked as non-draftable, so we manually create new objects
569
- return {
570
- ...variableType,
571
- owner: newOwner,
572
- type: newInnerType
573
- } as Type.Variable;
574
- }
575
-
576
- return variableType;
577
- }
578
-
579
- /**
580
- * Update a Parameterized type if its base type references the old module
581
- */
582
- private updateParameterizedType(paramType: Type.Parameterized): Type.Parameterized {
583
- let changed = false;
584
- let newBaseType = paramType.type;
585
- let newTypeParams = paramType.typeParameters;
586
-
587
- // Update base type
588
- if (Type.isFullyQualified(paramType.type)) {
589
- const updatedType = this.updateType(paramType.type) as Type.FullyQualified;
590
- if (updatedType !== paramType.type) {
591
- newBaseType = updatedType;
592
- changed = true;
593
- }
594
- }
595
-
596
- // Update type parameters
597
- const updatedParams = paramType.typeParameters.map(tp => this.updateType(tp)!);
598
- if (updatedParams.some((p, i) => p !== paramType.typeParameters[i])) {
599
- newTypeParams = updatedParams;
600
- changed = true;
601
- }
602
-
603
- if (changed) {
604
- // Type objects are marked as non-draftable, so we manually create new objects
605
- return {
606
- ...paramType,
607
- type: newBaseType,
608
- typeParameters: newTypeParams
609
- } as Type.Parameterized;
610
- }
611
-
612
- return paramType;
613
- }
614
-
615
- /**
616
- * Update an Array type if its element type references the old module
617
- */
618
- private updateArrayType(arrayType: Type.Array): Type.Array {
619
- const updatedElemType = this.updateType(arrayType.elemType);
620
- if (updatedElemType !== arrayType.elemType) {
621
- // Type objects are marked as non-draftable, so we manually create new objects
622
- return {
623
- ...arrayType,
624
- elemType: updatedElemType!
625
- } as Type.Array;
626
- }
627
- return arrayType;
628
- }
629
-
630
- private checkForOldImport(jsImport: JS.Import): { found: boolean; alias?: string } {
631
- // Check if this import is from the old module
632
- const moduleSpecifier = jsImport.moduleSpecifier;
633
- if (!moduleSpecifier) return { found: false };
634
-
635
- const literal = moduleSpecifier.element;
636
- if (literal.kind !== J.Kind.Literal) return { found: false };
637
-
638
- const value = (literal as J.Literal).value;
639
- if (value !== oldModule) return { found: false };
640
-
641
- const importClause = jsImport.importClause;
642
- if (!importClause) {
643
- // Side-effect import - not what we're looking for
644
- return { found: false };
645
- }
646
-
647
- // Check for default import
648
- if (oldMember === 'default') {
649
- if (importClause.name) {
650
- const nameElem = importClause.name.element;
651
- if (isIdentifier(nameElem)) {
652
- return { found: true, alias: nameElem.simpleName };
653
- }
654
- }
655
- return { found: false };
656
- }
657
-
658
- // Check for namespace import
659
- if (oldMember === '*') {
660
- const namedBindings = importClause.namedBindings;
661
- if (namedBindings?.kind === JS.Kind.Alias) {
662
- const alias = namedBindings as JS.Alias;
663
- if (isIdentifier(alias.alias)) {
664
- return { found: true, alias: alias.alias.simpleName };
665
- }
666
- }
667
- return { found: false };
668
- }
669
-
670
- // Check for named imports
671
- const namedBindings = importClause.namedBindings;
672
- if (!namedBindings) return { found: false };
673
-
674
- if (namedBindings.kind !== JS.Kind.NamedImports) return { found: false };
675
-
676
- const namedImports = namedBindings as JS.NamedImports;
677
- const elements = namedImports.elements.elements;
678
-
679
- for (const elem of elements) {
680
- const specifier = elem.element;
681
- const specifierNode = specifier.specifier;
682
-
683
- // Handle direct import: import { act }
684
- if (isIdentifier(specifierNode) && specifierNode.simpleName === oldMember) {
685
- return { found: true };
686
- }
687
-
688
- // Handle aliased import: import { act as something }
689
- if (specifierNode.kind === JS.Kind.Alias) {
690
- const alias = specifierNode as JS.Alias;
691
- const propertyName = alias.propertyName.element;
692
- if (isIdentifier(propertyName) && propertyName.simpleName === oldMember) {
693
- if (isIdentifier(alias.alias)) {
694
- return { found: true, alias: alias.alias.simpleName };
695
- }
696
- }
697
- }
698
- }
699
-
700
- return { found: false };
120
+ return super.visitJsCompilationUnit(cu, ctx);
701
121
  }
702
122
  }();
703
123
  }