@openrewrite/rewrite 8.91.1 → 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.
Files changed (96) hide show
  1. package/dist/javascript/add-import.d.ts +68 -34
  2. package/dist/javascript/add-import.d.ts.map +1 -1
  3. package/dist/javascript/add-import.js +322 -160
  4. package/dist/javascript/add-import.js.map +1 -1
  5. package/dist/javascript/amd.d.ts +138 -0
  6. package/dist/javascript/amd.d.ts.map +1 -0
  7. package/dist/javascript/amd.js +768 -0
  8. package/dist/javascript/amd.js.map +1 -0
  9. package/dist/javascript/binding.d.ts +94 -0
  10. package/dist/javascript/binding.d.ts.map +1 -0
  11. package/dist/javascript/binding.js +335 -0
  12. package/dist/javascript/binding.js.map +1 -0
  13. package/dist/javascript/index.d.ts +8 -1
  14. package/dist/javascript/index.d.ts.map +1 -1
  15. package/dist/javascript/index.js +26 -1
  16. package/dist/javascript/index.js.map +1 -1
  17. package/dist/javascript/parser-utils.d.ts.map +1 -1
  18. package/dist/javascript/parser-utils.js +2 -0
  19. package/dist/javascript/parser-utils.js.map +1 -1
  20. package/dist/javascript/parser.d.ts +7 -1
  21. package/dist/javascript/parser.d.ts.map +1 -1
  22. package/dist/javascript/parser.js +7 -1
  23. package/dist/javascript/parser.js.map +1 -1
  24. package/dist/javascript/recipes/change-import.d.ts +2 -4
  25. package/dist/javascript/recipes/change-import.d.ts.map +1 -1
  26. package/dist/javascript/recipes/change-import.js +8 -240
  27. package/dist/javascript/recipes/change-import.js.map +1 -1
  28. package/dist/javascript/remove-import.d.ts +2 -28
  29. package/dist/javascript/remove-import.d.ts.map +1 -1
  30. package/dist/javascript/remove-import.js +19 -57
  31. package/dist/javascript/remove-import.js.map +1 -1
  32. package/dist/javascript/scope.d.ts +49 -0
  33. package/dist/javascript/scope.d.ts.map +1 -0
  34. package/dist/javascript/scope.js +324 -0
  35. package/dist/javascript/scope.js.map +1 -0
  36. package/dist/javascript/templating/bindings.d.ts +0 -11
  37. package/dist/javascript/templating/bindings.d.ts.map +1 -1
  38. package/dist/javascript/templating/bindings.js +0 -29
  39. package/dist/javascript/templating/bindings.js.map +1 -1
  40. package/dist/javascript/templating/comparator.d.ts +10 -0
  41. package/dist/javascript/templating/comparator.d.ts.map +1 -1
  42. package/dist/javascript/templating/comparator.js +43 -14
  43. package/dist/javascript/templating/comparator.js.map +1 -1
  44. package/dist/javascript/templating/engine.d.ts +17 -4
  45. package/dist/javascript/templating/engine.d.ts.map +1 -1
  46. package/dist/javascript/templating/engine.js +43 -17
  47. package/dist/javascript/templating/engine.js.map +1 -1
  48. package/dist/javascript/templating/index.d.ts +1 -1
  49. package/dist/javascript/templating/index.d.ts.map +1 -1
  50. package/dist/javascript/templating/index.js.map +1 -1
  51. package/dist/javascript/templating/pattern.d.ts.map +1 -1
  52. package/dist/javascript/templating/pattern.js +2 -2
  53. package/dist/javascript/templating/pattern.js.map +1 -1
  54. package/dist/javascript/templating/placeholder-replacement.d.ts +2 -0
  55. package/dist/javascript/templating/placeholder-replacement.d.ts.map +1 -1
  56. package/dist/javascript/templating/placeholder-replacement.js +10 -5
  57. package/dist/javascript/templating/placeholder-replacement.js.map +1 -1
  58. package/dist/javascript/templating/precedence.d.ts +12 -4
  59. package/dist/javascript/templating/precedence.d.ts.map +1 -1
  60. package/dist/javascript/templating/precedence.js +18 -11
  61. package/dist/javascript/templating/precedence.js.map +1 -1
  62. package/dist/javascript/templating/rewrite.d.ts.map +1 -1
  63. package/dist/javascript/templating/rewrite.js +7 -1
  64. package/dist/javascript/templating/rewrite.js.map +1 -1
  65. package/dist/javascript/templating/template.d.ts +7 -1
  66. package/dist/javascript/templating/template.d.ts.map +1 -1
  67. package/dist/javascript/templating/template.js +48 -28
  68. package/dist/javascript/templating/template.js.map +1 -1
  69. package/dist/javascript/templating/types.d.ts +10 -18
  70. package/dist/javascript/templating/types.d.ts.map +1 -1
  71. package/dist/javascript/templating/utils.d.ts +1 -1
  72. package/dist/javascript/templating/utils.d.ts.map +1 -1
  73. package/dist/javascript/templating/utils.js +3 -2
  74. package/dist/javascript/templating/utils.js.map +1 -1
  75. package/dist/rewrite-javascript-version.txt +1 -1
  76. package/package.json +2 -2
  77. package/src/javascript/add-import.ts +342 -198
  78. package/src/javascript/amd.ts +915 -0
  79. package/src/javascript/binding.ts +449 -0
  80. package/src/javascript/index.ts +12 -1
  81. package/src/javascript/parser-utils.ts +2 -0
  82. package/src/javascript/parser.ts +13 -0
  83. package/src/javascript/recipes/change-import.ts +10 -260
  84. package/src/javascript/remove-import.ts +20 -56
  85. package/src/javascript/scope.ts +338 -0
  86. package/src/javascript/templating/bindings.ts +0 -30
  87. package/src/javascript/templating/comparator.ts +52 -14
  88. package/src/javascript/templating/engine.ts +70 -28
  89. package/src/javascript/templating/index.ts +0 -1
  90. package/src/javascript/templating/pattern.ts +4 -2
  91. package/src/javascript/templating/placeholder-replacement.ts +16 -6
  92. package/src/javascript/templating/precedence.ts +21 -13
  93. package/src/javascript/templating/rewrite.ts +9 -1
  94. package/src/javascript/templating/template.ts +62 -29
  95. package/src/javascript/templating/types.ts +11 -18
  96. package/src/javascript/templating/utils.ts +4 -2
@@ -1,13 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AddImport = exports.ImportStyle = void 0;
4
- exports.maybeAddImport = maybeAddImport;
3
+ exports.RebindImport = exports.AddImport = exports.ImportStyle = void 0;
4
+ exports.bindImport = bindImport;
5
+ exports.memberName = memberName;
6
+ exports.moduleScopeBindings = moduleScopeBindings;
7
+ exports.requiredModuleOf = requiredModuleOf;
8
+ exports.moduleNameOf = moduleNameOf;
9
+ exports.existingImportBinding = existingImportBinding;
5
10
  const visitor_1 = require("./visitor");
6
11
  const java_1 = require("../java");
7
12
  const tree_1 = require("./tree");
8
13
  const uuid_1 = require("../uuid");
9
14
  const markers_1 = require("../markers");
10
15
  const style_1 = require("./style");
16
+ const scope_1 = require("./scope");
17
+ const mutative_1 = require("mutative");
11
18
  var ImportStyle;
12
19
  (function (ImportStyle) {
13
20
  ImportStyle[ImportStyle["ES6Named"] = 0] = "ES6Named";
@@ -15,7 +22,13 @@ var ImportStyle;
15
22
  ImportStyle[ImportStyle["ES6Default"] = 2] = "ES6Default";
16
23
  ImportStyle[ImportStyle["CommonJS"] = 3] = "CommonJS"; // const x = require('module')
17
24
  })(ImportStyle || (exports.ImportStyle = ImportStyle = {}));
18
- function maybeAddImport(visitor, options) {
25
+ /**
26
+ * Ensures an import for `options.module` exists, queuing an `AddImport` edit where none already
27
+ * serves the request. `maybeBind`'s ESM/CommonJS lane is this function; its own JSDoc carries the
28
+ * return-value contract. `refuseCreate` answers `undefined` instead of queuing a new import,
29
+ * without affecting whether an existing binding answers the request first.
30
+ */
31
+ function bindImport(visitor, options, refuseCreate) {
19
32
  var _a, _b;
20
33
  validate(options);
21
34
  const module = moduleNameOf(options.module);
@@ -38,26 +51,35 @@ function maybeAddImport(visitor, options) {
38
51
  }
39
52
  }
40
53
  if (sideEffectOnly) {
54
+ if (refuseCreate) {
55
+ return undefined;
56
+ }
41
57
  visitor.afterVisit.push(new AddImport(options));
42
58
  return undefined;
43
59
  }
44
60
  // A pinned alias is the whole answer, so the file has no say and nothing below needs to read it.
45
61
  if (options.alias) {
62
+ if (refuseCreate) {
63
+ return undefined;
64
+ }
46
65
  visitor.afterVisit.push(new AddImport(options, options.alias));
47
66
  return options.alias;
48
67
  }
49
68
  const derived = derivedName(options);
50
- const cu = compilationUnitOf(visitor);
69
+ const cursor = (0, scope_1.cursorOf)(visitor);
70
+ const cu = cursor && (0, scope_1.compilationUnitOf)(cursor);
51
71
  if (!cu) {
72
+ if (refuseCreate) {
73
+ return undefined;
74
+ }
52
75
  visitor.afterVisit.push(new AddImport(options, derived));
53
76
  return derived;
54
77
  }
55
- const bindings = bindingsInScope(cu, cursorOf(visitor));
56
78
  // An import already serving this request answers it; queuing one would, on the next cycle,
57
79
  // derive a suffixed name from the binding this call just added. A caller that named a preference
58
80
  // takes whatever comes back; one that did not assumes the name it derived, so a binding under
59
81
  // any other name would leave the references it emits unbound.
60
- for (const binding of bindings) {
82
+ for (const binding of moduleScopeBindings(cu)) {
61
83
  if (binding.module === module && binding.member === memberName(options.member) &&
62
84
  binding.typeOnly === typeOnly &&
63
85
  (options.preferredName !== undefined || anyNameAnswers(options) ||
@@ -65,7 +87,14 @@ function maybeAddImport(visitor, options) {
65
87
  return binding.name;
66
88
  }
67
89
  }
68
- const name = deconflict(derived, takenNames(bindings, visitor));
90
+ if (refuseCreate) {
91
+ return undefined;
92
+ }
93
+ // Only the module scope answers for a name, but any scope in the file occupies one. The queue
94
+ // gives every later request for this module the name chosen here, so it has to clear the scopes
95
+ // those references will sit in, which are not known yet.
96
+ const taken = takenNames((0, scope_1.namesDeclaredIn)(cu), visitor);
97
+ const name = (0, scope_1.deconflict)(derived, candidate => taken.has(candidate));
69
98
  visitor.afterVisit.push(new AddImport(options, name));
70
99
  return name;
71
100
  }
@@ -115,104 +144,26 @@ function derivedName(options) {
115
144
  function memberName(member) {
116
145
  return member === 'default' ? undefined : member;
117
146
  }
118
- function cursorOf(visitor) {
119
- return visitor.cursor;
120
- }
121
- function compilationUnitOf(visitor) {
122
- var _a;
123
- // `cursor` is protected on `TreeVisitor`, and the `maybeAddImport`/`maybeRemoveImport`
124
- // API is free functions, so reaching it takes a cast.
125
- return (_a = cursorOf(visitor)) === null || _a === void 0 ? void 0 : _a.firstEnclosing((v) => (v === null || v === void 0 ? void 0 : v.kind) === tree_1.JS.Kind.CompilationUnit);
126
- }
127
- /** Every name in scope at `cursor`: what the file binds, and what each block enclosing it declares. */
128
- function bindingsInScope(cu, cursor) {
129
- const bindings = statementBindings(cu.statements);
130
- // A local shadows an import for the code the template lands in, so a name a block declares is
131
- // taken there even though the module never answers for it.
132
- for (let c = cursor; c && c.value !== cu; c = c.parent) {
133
- for (const name of scopeNames(c.value)) {
134
- bindings.push({ name });
135
- }
136
- }
137
- return bindings;
138
- }
139
- /** The names a scope introduces directly: a block's declarations, or a function's parameters. */
140
- function scopeNames(scope) {
141
- const node = scope;
142
- if ((node === null || node === void 0 ? void 0 : node.kind) === java_1.J.Kind.Block) {
143
- return statementBindings(node.statements).map(binding => binding.name);
144
- }
145
- if ((node === null || node === void 0 ? void 0 : node.kind) === java_1.J.Kind.MethodDeclaration) {
146
- return node.parameters.elements
147
- .flatMap(param => {
148
- var _a;
149
- return ((_a = param.element) === null || _a === void 0 ? void 0 : _a.kind) === java_1.J.Kind.VariableDeclarations
150
- ? param.element.variables.flatMap(v => { var _a; return patternNames((_a = v.element) === null || _a === void 0 ? void 0 : _a.name); })
151
- : patternNames(param.element);
152
- })
153
- .map(bound => bound.name);
154
- }
155
- if ((node === null || node === void 0 ? void 0 : node.kind) === java_1.J.Kind.Lambda) {
156
- return node.parameters.parameters
157
- .flatMap(param => {
158
- var _a;
159
- return ((_a = param.element) === null || _a === void 0 ? void 0 : _a.kind) === java_1.J.Kind.VariableDeclarations
160
- ? param.element.variables.flatMap(v => { var _a; return patternNames((_a = v.element) === null || _a === void 0 ? void 0 : _a.name); })
161
- : patternNames(param.element);
162
- })
163
- .map(bound => bound.name);
164
- }
165
- return [];
166
- }
167
- /** Imports are top-level statements and so is anything that can shadow one, so a flat scan sees every name. */
168
- function statementBindings(statements) {
169
- var _a;
147
+ /** What the file's imports and `require`s bind at module scope, and the module each name comes from. */
148
+ function moduleScopeBindings(cu) {
170
149
  const bindings = [];
171
- const declaredBy = (name) => {
172
- for (const bound of patternNames(name)) {
173
- bindings.push({ name: bound.name });
174
- }
175
- };
176
150
  const declaredByVariables = (varDecl) => {
177
- var _a, _b, _c, _d;
151
+ var _a, _b, _c;
178
152
  for (const variable of varDecl.variables) {
179
153
  const required = requiredModule((_b = (_a = variable.element) === null || _a === void 0 ? void 0 : _a.initializer) === null || _b === void 0 ? void 0 : _b.element);
180
154
  if (required !== undefined) {
181
155
  bindings.push(...requireBindings((_c = variable.element) === null || _c === void 0 ? void 0 : _c.name, required));
182
156
  }
183
- else {
184
- declaredBy((_d = variable.element) === null || _d === void 0 ? void 0 : _d.name);
185
- }
186
157
  }
187
158
  };
188
- for (const stmt of statements) {
159
+ for (const stmt of cu.statements) {
189
160
  const statement = stmt.element;
190
- switch (statement === null || statement === void 0 ? void 0 : statement.kind) {
191
- case tree_1.JS.Kind.Import:
192
- bindings.push(...importBindings(statement));
193
- break;
194
- case java_1.J.Kind.VariableDeclarations:
195
- declaredByVariables(statement);
196
- break;
197
- case tree_1.JS.Kind.ScopedVariableDeclarations:
198
- for (const variable of statement.variables) {
199
- if (((_a = variable.element) === null || _a === void 0 ? void 0 : _a.kind) === java_1.J.Kind.VariableDeclarations) {
200
- declaredByVariables(variable.element);
201
- }
202
- }
203
- break;
204
- case java_1.J.Kind.MethodDeclaration:
205
- declaredBy(statement.name);
206
- break;
207
- case java_1.J.Kind.ClassDeclaration:
208
- declaredBy(statement.name);
209
- break;
210
- case tree_1.JS.Kind.NamespaceDeclaration:
211
- declaredBy(statement.name.element);
212
- break;
213
- case tree_1.JS.Kind.TypeDeclaration:
214
- declaredBy(statement.name.element);
215
- break;
161
+ if ((statement === null || statement === void 0 ? void 0 : statement.kind) === tree_1.JS.Kind.Import) {
162
+ bindings.push(...importBindings(statement));
163
+ continue;
164
+ }
165
+ for (const declaration of (0, scope_1.declarationsOf)(statement)) {
166
+ declaredByVariables(declaration);
216
167
  }
217
168
  }
218
169
  return bindings;
@@ -243,59 +194,13 @@ function requiredModuleOf(methodInv) {
243
194
  ? moduleNameOf(argument)
244
195
  : undefined;
245
196
  }
246
- /**
247
- * Every name a binding pattern introduces. `member` is the property a name takes its value from,
248
- * and only a name bound directly by the pattern has one — anything deeper reads a property of a
249
- * property, so it occupies its name without binding a member of the module.
250
- */
251
- function patternNames(pattern) {
252
- var _a, _b, _c;
253
- if ((pattern === null || pattern === void 0 ? void 0 : pattern.kind) === java_1.J.Kind.Identifier) {
254
- return [{ name: pattern.simpleName }];
255
- }
256
- // An array pattern binds by position, so its elements name no member of what they destructure.
257
- if ((pattern === null || pattern === void 0 ? void 0 : pattern.kind) === tree_1.JS.Kind.ArrayBindingPattern) {
258
- return pattern.elements.elements
259
- .flatMap(elem => {
260
- var _a;
261
- return ((_a = elem.element) === null || _a === void 0 ? void 0 : _a.kind) === tree_1.JS.Kind.BindingElement
262
- ? patternNames(elem.element.name)
263
- : patternNames(elem.element);
264
- })
265
- .map(bound => ({ name: bound.name }));
266
- }
267
- if ((pattern === null || pattern === void 0 ? void 0 : pattern.kind) !== tree_1.JS.Kind.ObjectBindingPattern) {
268
- return [];
269
- }
270
- const names = [];
271
- for (const elem of pattern.bindings.elements) {
272
- if (((_a = elem.element) === null || _a === void 0 ? void 0 : _a.kind) !== tree_1.JS.Kind.BindingElement) {
273
- continue;
274
- }
275
- const bindingElem = elem.element;
276
- if (((_b = bindingElem.name) === null || _b === void 0 ? void 0 : _b.kind) === java_1.J.Kind.Identifier) {
277
- const name = bindingElem.name.simpleName;
278
- const propertyName = (_c = bindingElem.propertyName) === null || _c === void 0 ? void 0 : _c.element;
279
- names.push({
280
- name,
281
- member: (propertyName === null || propertyName === void 0 ? void 0 : propertyName.kind) === java_1.J.Kind.Identifier
282
- ? propertyName.simpleName
283
- : name
284
- });
285
- }
286
- else {
287
- names.push(...patternNames(bindingElem.name).map(bound => ({ name: bound.name })));
288
- }
289
- }
290
- return names;
291
- }
292
197
  /** A `require` binds a module the way an import does, so the pool records it the same way. */
293
198
  function requireBindings(pattern, module) {
294
199
  // A whole-module require binds no member, exactly as a default import does.
295
200
  if ((pattern === null || pattern === void 0 ? void 0 : pattern.kind) === java_1.J.Kind.Identifier) {
296
201
  return [{ name: pattern.simpleName, module, member: undefined, typeOnly: false }];
297
202
  }
298
- return patternNames(pattern).map(bound => bound.member === undefined
203
+ return (0, scope_1.bindingNames)(pattern).map(bound => bound.member === undefined
299
204
  ? { name: bound.name }
300
205
  : { name: bound.name, module, member: bound.member, typeOnly: false });
301
206
  }
@@ -352,32 +257,19 @@ function importBindings(jsImport) {
352
257
  return bindings;
353
258
  }
354
259
  /**
355
- * Names the file binds, plus those pending `AddImport`s on the `afterVisit` queue have claimed. A
356
- * queued `RemoveImport` does not free one: it removes only what the file leaves unused, and binding
357
- * a name it keeps is an error, where an unnecessary suffix merely reads oddly.
260
+ * Names in scope, plus those pending `AddImport`s on the `afterVisit` queue have claimed. A queued
261
+ * `RemoveImport` does not free one: it removes only what the file leaves unused, and binding a name
262
+ * it keeps is an error, where an unnecessary suffix merely reads oddly.
358
263
  */
359
- function takenNames(bindings, visitor) {
360
- const taken = new Set();
264
+ function takenNames(inScope, visitor) {
265
+ const taken = new Set(inScope);
361
266
  for (const v of visitor.afterVisit || []) {
362
267
  if (v instanceof AddImport && v.bindingName) {
363
268
  taken.add(v.bindingName);
364
269
  }
365
270
  }
366
- for (const binding of bindings) {
367
- taken.add(binding.name);
368
- }
369
271
  return taken;
370
272
  }
371
- function deconflict(derived, taken) {
372
- if (!taken.has(derived)) {
373
- return derived;
374
- }
375
- let suffix = 1;
376
- while (taken.has(`${derived}_${suffix}`)) {
377
- suffix++;
378
- }
379
- return `${derived}_${suffix}`;
380
- }
381
273
  /**
382
274
  * The parser lifts surrogate pairs out of `valueSource` into `unicodeEscapes` and, when it does,
383
275
  * sets `value` to the quoted source (`parser.ts` `mapLiteral`), so neither field alone is the
@@ -1431,4 +1323,274 @@ class AddImport extends visitor_1.JavaScriptVisitor {
1431
1323
  }
1432
1324
  }
1433
1325
  exports.AddImport = AddImport;
1326
+ /**
1327
+ * The local name `jsImport` binds `member` of `module` to, or `undefined` where it binds
1328
+ * something else. `'default'` and an absent `member` both mean the default import, matching
1329
+ * {@link memberName}.
1330
+ */
1331
+ function importBinds(jsImport, module, member) {
1332
+ var _a, _b;
1333
+ const specifier = (_a = jsImport.moduleSpecifier) === null || _a === void 0 ? void 0 : _a.element;
1334
+ if ((specifier === null || specifier === void 0 ? void 0 : specifier.kind) !== java_1.J.Kind.Literal || specifier.value !== module) {
1335
+ return undefined;
1336
+ }
1337
+ const importClause = jsImport.importClause;
1338
+ if (!importClause) {
1339
+ return undefined;
1340
+ }
1341
+ const key = memberName(member);
1342
+ if (key === undefined) {
1343
+ const nameElem = (_b = importClause.name) === null || _b === void 0 ? void 0 : _b.element;
1344
+ return nameElem && (0, java_1.isIdentifier)(nameElem) ? nameElem.simpleName : undefined;
1345
+ }
1346
+ if (key === '*') {
1347
+ const namedBindings = importClause.namedBindings;
1348
+ return (namedBindings === null || namedBindings === void 0 ? void 0 : namedBindings.kind) === tree_1.JS.Kind.Alias && (0, java_1.isIdentifier)(namedBindings.alias)
1349
+ ? namedBindings.alias.simpleName
1350
+ : undefined;
1351
+ }
1352
+ const namedBindings = importClause.namedBindings;
1353
+ if ((namedBindings === null || namedBindings === void 0 ? void 0 : namedBindings.kind) !== tree_1.JS.Kind.NamedImports) {
1354
+ return undefined;
1355
+ }
1356
+ for (const elem of namedBindings.elements.elements) {
1357
+ const specifierNode = elem.element.specifier;
1358
+ if (!namedSpecifierImports(specifierNode, key)) {
1359
+ continue;
1360
+ }
1361
+ if ((0, java_1.isIdentifier)(specifierNode)) {
1362
+ return specifierNode.simpleName;
1363
+ }
1364
+ const alias = specifierNode.alias;
1365
+ if ((0, java_1.isIdentifier)(alias)) {
1366
+ return alias.simpleName;
1367
+ }
1368
+ }
1369
+ return undefined;
1370
+ }
1371
+ /** Whether `specifier` imports the member `key`, under whatever local name it binds it to. */
1372
+ function namedSpecifierImports(specifier, key) {
1373
+ if ((0, java_1.isIdentifier)(specifier)) {
1374
+ return specifier.simpleName === key;
1375
+ }
1376
+ if (specifier.kind === tree_1.JS.Kind.Alias) {
1377
+ const propertyName = specifier.propertyName.element;
1378
+ return (0, java_1.isIdentifier)(propertyName) && propertyName.simpleName === key;
1379
+ }
1380
+ return false;
1381
+ }
1382
+ /** Whether the named specifier binding `key` carries its own inline `type`, as in `{type a, b}`. */
1383
+ function namedSpecifierIsTypeOnly(imp, key) {
1384
+ var _a;
1385
+ const namedBindings = (_a = imp.importClause) === null || _a === void 0 ? void 0 : _a.namedBindings;
1386
+ if ((namedBindings === null || namedBindings === void 0 ? void 0 : namedBindings.kind) !== tree_1.JS.Kind.NamedImports) {
1387
+ return false;
1388
+ }
1389
+ for (const elem of namedBindings.elements.elements) {
1390
+ if (namedSpecifierImports(elem.element.specifier, key)) {
1391
+ return elem.element.importType.element;
1392
+ }
1393
+ }
1394
+ return false;
1395
+ }
1396
+ /** How many named specifiers `jsImport` carries, `0` for a default, namespace or side-effect import. */
1397
+ function namedImportCount(jsImport) {
1398
+ var _a;
1399
+ const namedBindings = (_a = jsImport.importClause) === null || _a === void 0 ? void 0 : _a.namedBindings;
1400
+ return (namedBindings === null || namedBindings === void 0 ? void 0 : namedBindings.kind) === tree_1.JS.Kind.NamedImports ? namedBindings.elements.elements.length : 0;
1401
+ }
1402
+ /**
1403
+ * Whether `jsImport`'s clause binds exactly one thing — a default, a namespace, or one named
1404
+ * specifier. That is the only shape a module-only move can rewrite in place: whichever binding
1405
+ * `importBinds` already matched is this one, so nothing else the clause carries goes along with it.
1406
+ */
1407
+ function isOnlyMember(jsImport) {
1408
+ var _a;
1409
+ const importClause = jsImport.importClause;
1410
+ if (!importClause) {
1411
+ return false;
1412
+ }
1413
+ const hasDefault = importClause.name !== undefined;
1414
+ const hasNamespace = ((_a = importClause.namedBindings) === null || _a === void 0 ? void 0 : _a.kind) === tree_1.JS.Kind.Alias;
1415
+ return (hasDefault ? 1 : 0) + (hasNamespace ? 1 : 0) + namedImportCount(jsImport) === 1;
1416
+ }
1417
+ /**
1418
+ * The existing binding for `member` of `module`, read from `cu`'s own import statements — what
1419
+ * `maybeRebind` reads before committing to a `RebindImport` edit.
1420
+ */
1421
+ function existingImportBinding(cu, module, member) {
1422
+ for (const stmt of cu.statements) {
1423
+ const element = stmt.element;
1424
+ if ((element === null || element === void 0 ? void 0 : element.kind) !== tree_1.JS.Kind.Import) {
1425
+ continue;
1426
+ }
1427
+ const localName = importBinds(element, module, member);
1428
+ if (localName !== undefined) {
1429
+ return { localName, onlyMemberOfStatement: isOnlyMember(element) };
1430
+ }
1431
+ }
1432
+ return undefined;
1433
+ }
1434
+ /**
1435
+ * Binds `member` under the name `local` already carries, so the file's references to it still
1436
+ * resolve. `local` itself becomes the alias, keeping the type attribution it holds, and the alias
1437
+ * takes its prefix: that whitespace separates the specifier from a `type` keyword before it.
1438
+ */
1439
+ function aliasing(local, member) {
1440
+ const propertyName = {
1441
+ id: (0, uuid_1.randomId)(),
1442
+ kind: java_1.J.Kind.Identifier,
1443
+ prefix: java_1.emptySpace,
1444
+ markers: markers_1.emptyMarkers,
1445
+ annotations: [],
1446
+ simpleName: member,
1447
+ type: undefined,
1448
+ fieldType: undefined
1449
+ };
1450
+ return {
1451
+ id: (0, uuid_1.randomId)(),
1452
+ kind: tree_1.JS.Kind.Alias,
1453
+ prefix: local.prefix,
1454
+ markers: markers_1.emptyMarkers,
1455
+ propertyName: (0, java_1.rightPadded)(propertyName, java_1.singleSpace),
1456
+ alias: Object.assign(Object.assign({}, local), { prefix: java_1.singleSpace })
1457
+ };
1458
+ }
1459
+ /**
1460
+ * Drops the binding for `member` from `jsImport`'s clause — the default, the namespace alias, or
1461
+ * one entry of the named list, whichever `member` names — keeping everything else the clause
1462
+ * binds. `ElementRemovalFormatter` carries the dropped binding's prefix onto whatever prints
1463
+ * next, the same way `RemoveImport` keeps formatting sane when trimming a list.
1464
+ */
1465
+ function removeBinding(jsImport, member) {
1466
+ var _a;
1467
+ const importClause = jsImport.importClause;
1468
+ if (!importClause) {
1469
+ return jsImport;
1470
+ }
1471
+ const key = memberName(member);
1472
+ if (key === undefined) {
1473
+ if (!importClause.name) {
1474
+ return jsImport;
1475
+ }
1476
+ const namedBindings = importClause.namedBindings;
1477
+ if ((namedBindings === null || namedBindings === void 0 ? void 0 : namedBindings.kind) === tree_1.JS.Kind.NamedImports) {
1478
+ // `NamedImports` keeps the space before its own `{` on the container's `before`,
1479
+ // not on its own prefix, so the removed default's prefix has to land there instead.
1480
+ const namedImports = namedBindings;
1481
+ const updated = Object.assign(Object.assign({}, namedImports), { elements: Object.assign(Object.assign({}, namedImports.elements), { before: importClause.name.element.prefix }) });
1482
+ return Object.assign(Object.assign({}, jsImport), { importClause: Object.assign(Object.assign({}, importClause), { name: undefined, namedBindings: updated }) });
1483
+ }
1484
+ if (namedBindings) {
1485
+ const formatter = new java_1.ElementRemovalFormatter();
1486
+ formatter.markRemoved(importClause.name.element);
1487
+ return Object.assign(Object.assign({}, jsImport), { importClause: Object.assign(Object.assign({}, importClause), { name: undefined, namedBindings: formatter.processKept(namedBindings) }) });
1488
+ }
1489
+ return Object.assign(Object.assign({}, jsImport), { importClause: Object.assign(Object.assign({}, importClause), { name: undefined }) });
1490
+ }
1491
+ if (key === '*') {
1492
+ return Object.assign(Object.assign({}, jsImport), { importClause: Object.assign(Object.assign({}, importClause), { namedBindings: undefined }) });
1493
+ }
1494
+ if (((_a = importClause.namedBindings) === null || _a === void 0 ? void 0 : _a.kind) !== tree_1.JS.Kind.NamedImports) {
1495
+ return jsImport;
1496
+ }
1497
+ const namedImports = importClause.namedBindings;
1498
+ const formatter = new java_1.ElementRemovalFormatter();
1499
+ const kept = [];
1500
+ for (const entry of namedImports.elements.elements) {
1501
+ if (namedSpecifierImports(entry.element.specifier, key)) {
1502
+ formatter.markRemoved(entry.element);
1503
+ }
1504
+ else {
1505
+ kept.push(Object.assign(Object.assign({}, entry), { element: formatter.processKept(entry.element) }));
1506
+ }
1507
+ }
1508
+ if (kept.length === 0) {
1509
+ // An emptied brace list still prints, as `import D, {} from "m"`, so it goes with its
1510
+ // last member; the caller drops the whole statement when no default remains either.
1511
+ return Object.assign(Object.assign({}, jsImport), { importClause: Object.assign(Object.assign({}, importClause), { namedBindings: undefined }) });
1512
+ }
1513
+ const updatedNamedImports = Object.assign(Object.assign({}, namedImports), { elements: Object.assign(Object.assign({}, namedImports.elements), { elements: kept }) });
1514
+ return Object.assign(Object.assign({}, jsImport), { importClause: Object.assign(Object.assign({}, importClause), { namedBindings: updatedNamedImports }) });
1515
+ }
1516
+ /**
1517
+ * Moves the binding `from` names to `to`, keeping the local name it already had. In place when
1518
+ * the statement that carries it binds nothing else — module and member specifier rewritten there
1519
+ * directly; otherwise the old specifier drops and {@link bindImport} queues the replacement,
1520
+ * aliased to the preserved name.
1521
+ *
1522
+ * Not built on `RemoveImport`/`maybeUnbind`: those only drop a binding once nothing references
1523
+ * it, but a rebind moves one that is still in use — removal here has to be unconditional.
1524
+ */
1525
+ class RebindImport extends visitor_1.JavaScriptVisitor {
1526
+ constructor(from, to, localName) {
1527
+ super();
1528
+ this.from = from;
1529
+ this.to = to;
1530
+ this.localName = localName;
1531
+ this.transformedInPlace = false;
1532
+ this.typeOnly = false;
1533
+ }
1534
+ async visitJsCompilationUnit(cu, p) {
1535
+ const visited = await super.visitJsCompilationUnit(cu, p);
1536
+ if (!this.transformedInPlace) {
1537
+ bindImport(this, {
1538
+ module: this.to.module,
1539
+ member: this.to.member,
1540
+ alias: this.localName,
1541
+ typeOnly: this.typeOnly,
1542
+ onlyIfReferenced: false
1543
+ });
1544
+ }
1545
+ return visited;
1546
+ }
1547
+ async visitImportDeclaration(jsImport, p) {
1548
+ var _a, _b;
1549
+ const imp = await super.visitImportDeclaration(jsImport, p);
1550
+ const key = memberName(this.from.member);
1551
+ if (importBinds(imp, this.from.module, this.from.member) === undefined) {
1552
+ return imp;
1553
+ }
1554
+ // A moved named specifier's own inline `type` marks it type-only even where the clause
1555
+ // it's leaving is not — the replacement needs the same answer to stay type-safe.
1556
+ this.typeOnly = ((_b = (_a = imp.importClause) === null || _a === void 0 ? void 0 : _a.typeOnly) !== null && _b !== void 0 ? _b : false) ||
1557
+ (key !== undefined && key !== '*' && namedSpecifierIsTypeOnly(imp, key));
1558
+ if (!isOnlyMember(imp)) {
1559
+ return removeBinding(imp, this.from.member);
1560
+ }
1561
+ this.transformedInPlace = true;
1562
+ return (0, mutative_1.create)(imp, draft => {
1563
+ var _a;
1564
+ const literal = draft.moduleSpecifier.element;
1565
+ literal.value = this.to.module;
1566
+ const originalSource = literal.valueSource || `"${this.from.module}"`;
1567
+ const quoteChar = originalSource.startsWith("'") ? "'" : '"';
1568
+ literal.valueSource = `${quoteChar}${this.to.module}${quoteChar}`;
1569
+ // A named specifier's local name has to stay put in the source, since it is what the
1570
+ // rest of the file already reads; default and namespace imports carry that name on
1571
+ // the clause itself, which needs no edit for a module-only move.
1572
+ const toKey = memberName(this.to.member);
1573
+ if (key !== undefined && key !== '*' && toKey !== undefined && toKey !== key) {
1574
+ const importClause = draft.importClause;
1575
+ if (((_a = importClause === null || importClause === void 0 ? void 0 : importClause.namedBindings) === null || _a === void 0 ? void 0 : _a.kind) === tree_1.JS.Kind.NamedImports) {
1576
+ const namedImports = importClause.namedBindings;
1577
+ for (const elem of namedImports.elements.elements) {
1578
+ const specifier = elem.element;
1579
+ if (specifier.specifier.kind === java_1.J.Kind.Identifier && specifier.specifier.simpleName === key) {
1580
+ specifier.specifier = aliasing(specifier.specifier, toKey);
1581
+ }
1582
+ else if (specifier.specifier.kind === tree_1.JS.Kind.Alias) {
1583
+ const aliasNode = specifier.specifier;
1584
+ const propertyName = aliasNode.propertyName.element;
1585
+ if (propertyName.kind === java_1.J.Kind.Identifier && propertyName.simpleName === key) {
1586
+ propertyName.simpleName = toKey;
1587
+ }
1588
+ }
1589
+ }
1590
+ }
1591
+ }
1592
+ });
1593
+ }
1594
+ }
1595
+ exports.RebindImport = RebindImport;
1434
1596
  //# sourceMappingURL=add-import.js.map