@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
@@ -1,13 +1,28 @@
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.hasEsmSyntax = hasEsmSyntax;
8
+ exports.isCommonJs = isCommonJs;
9
+ exports.requiredModuleOfDeclaration = requiredModuleOfDeclaration;
10
+ exports.requiredModuleOf = requiredModuleOf;
11
+ exports.takenNames = takenNames;
12
+ exports.nameTaken = nameTaken;
13
+ exports.moduleNameOf = moduleNameOf;
14
+ exports.existingImportBinding = existingImportBinding;
5
15
  const visitor_1 = require("./visitor");
6
16
  const java_1 = require("../java");
7
17
  const tree_1 = require("./tree");
8
18
  const uuid_1 = require("../uuid");
9
19
  const markers_1 = require("../markers");
10
20
  const style_1 = require("./style");
21
+ const scope_1 = require("./scope");
22
+ const mutative_1 = require("mutative");
23
+ const type_visitor_1 = require("../java/type-visitor");
24
+ const format_1 = require("./format");
25
+ const prettier_format_1 = require("./format/prettier-format");
11
26
  var ImportStyle;
12
27
  (function (ImportStyle) {
13
28
  ImportStyle[ImportStyle["ES6Named"] = 0] = "ES6Named";
@@ -15,7 +30,13 @@ var ImportStyle;
15
30
  ImportStyle[ImportStyle["ES6Default"] = 2] = "ES6Default";
16
31
  ImportStyle[ImportStyle["CommonJS"] = 3] = "CommonJS"; // const x = require('module')
17
32
  })(ImportStyle || (exports.ImportStyle = ImportStyle = {}));
18
- function maybeAddImport(visitor, options) {
33
+ /**
34
+ * Ensures an import for `options.module` exists, queuing an `AddImport` edit where none already
35
+ * serves the request. `maybeBind`'s ESM/CommonJS lane is this function; its own JSDoc carries the
36
+ * return-value contract. `refuseCreate` answers `undefined` instead of queuing a new import,
37
+ * without affecting whether an existing binding answers the request first.
38
+ */
39
+ function bindImport(visitor, options, refuseCreate) {
19
40
  var _a, _b;
20
41
  validate(options);
21
42
  const module = moduleNameOf(options.module);
@@ -38,34 +59,48 @@ function maybeAddImport(visitor, options) {
38
59
  }
39
60
  }
40
61
  if (sideEffectOnly) {
62
+ if (refuseCreate) {
63
+ return undefined;
64
+ }
41
65
  visitor.afterVisit.push(new AddImport(options));
42
66
  return undefined;
43
67
  }
44
68
  // A pinned alias is the whole answer, so the file has no say and nothing below needs to read it.
45
69
  if (options.alias) {
70
+ if (refuseCreate) {
71
+ return undefined;
72
+ }
46
73
  visitor.afterVisit.push(new AddImport(options, options.alias));
47
74
  return options.alias;
48
75
  }
49
76
  const derived = derivedName(options);
50
- const cu = compilationUnitOf(visitor);
77
+ const cursor = (0, scope_1.cursorOf)(visitor);
78
+ const cu = cursor && (0, scope_1.compilationUnitOf)(cursor);
51
79
  if (!cu) {
80
+ if (refuseCreate) {
81
+ return undefined;
82
+ }
52
83
  visitor.afterVisit.push(new AddImport(options, derived));
53
84
  return derived;
54
85
  }
55
- const bindings = bindingsInScope(cu, cursorOf(visitor));
56
- // An import already serving this request answers it; queuing one would, on the next cycle,
57
- // derive a suffixed name from the binding this call just added. A caller that named a preference
58
- // takes whatever comes back; one that did not assumes the name it derived, so a binding under
59
- // any other name would leave the references it emits unbound.
60
- for (const binding of bindings) {
86
+ // An import already serving this request answers it, under whatever name the file gave it —
87
+ // only a pinned alias, returned above, asks for a binding of its own. Queuing a second import
88
+ // would, on the next cycle, derive a suffixed name from the binding this call just added.
89
+ const scope = (0, scope_1.scopeOf)(cursor);
90
+ for (const binding of moduleScopeBindings(cu)) {
61
91
  if (binding.module === module && binding.member === memberName(options.member) &&
62
- binding.typeOnly === typeOnly &&
63
- (options.preferredName !== undefined || anyNameAnswers(options) ||
64
- binding.name === derived)) {
92
+ binding.typeOnly === typeOnly && scope.declaringScope(binding.name) === cu) {
65
93
  return binding.name;
66
94
  }
67
95
  }
68
- const name = deconflict(derived, takenNames(bindings, visitor));
96
+ if (refuseCreate) {
97
+ return undefined;
98
+ }
99
+ // Only the module scope answers for a name, but any scope in the file occupies one. The queue
100
+ // gives every later request for this module the name chosen here, so it has to clear the scopes
101
+ // those references will sit in, which are not known yet.
102
+ const taken = takenNames((0, scope_1.namesDeclaredIn)(cu), visitor);
103
+ const name = (0, scope_1.deconflict)(derived, candidate => taken.has(candidate));
69
104
  visitor.afterVisit.push(new AddImport(options, name));
70
105
  return name;
71
106
  }
@@ -115,108 +150,86 @@ function derivedName(options) {
115
150
  function memberName(member) {
116
151
  return member === 'default' ? undefined : member;
117
152
  }
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;
153
+ /** What the file's imports and `require`s bind at module scope, and the module each name comes from. */
154
+ function moduleScopeBindings(cu) {
170
155
  const bindings = [];
171
- const declaredBy = (name) => {
172
- for (const bound of patternNames(name)) {
173
- bindings.push({ name: bound.name });
174
- }
175
- };
176
156
  const declaredByVariables = (varDecl) => {
177
- var _a, _b, _c, _d;
157
+ var _a, _b, _c;
178
158
  for (const variable of varDecl.variables) {
179
159
  const required = requiredModule((_b = (_a = variable.element) === null || _a === void 0 ? void 0 : _a.initializer) === null || _b === void 0 ? void 0 : _b.element);
180
160
  if (required !== undefined) {
181
161
  bindings.push(...requireBindings((_c = variable.element) === null || _c === void 0 ? void 0 : _c.name, required));
182
162
  }
183
- else {
184
- declaredBy((_d = variable.element) === null || _d === void 0 ? void 0 : _d.name);
185
- }
186
163
  }
187
164
  };
188
- for (const stmt of statements) {
165
+ for (const stmt of cu.statements) {
189
166
  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;
167
+ if ((statement === null || statement === void 0 ? void 0 : statement.kind) === tree_1.JS.Kind.Import) {
168
+ bindings.push(...importBindings(statement));
169
+ continue;
170
+ }
171
+ for (const declaration of (0, scope_1.declarationsOf)(statement)) {
172
+ declaredByVariables(declaration);
216
173
  }
217
174
  }
218
175
  return bindings;
219
176
  }
177
+ /** Whether a top-level statement already marks the file as a module: an import or any export form. */
178
+ function hasEsmSyntax(cu) {
179
+ return cu.statements.some(stmt => {
180
+ var _a;
181
+ const element = stmt.element;
182
+ // `export {a, b}`, `export * from` and `export default` are their own statement kinds;
183
+ // `export class`/`function`/`const` instead carry `export` as a modifier on the
184
+ // declaration itself, the same way TypeScript's own AST models it.
185
+ const modifiers = element === null || element === void 0 ? void 0 : element.modifiers;
186
+ return (element === null || element === void 0 ? void 0 : element.kind) === tree_1.JS.Kind.Import ||
187
+ (element === null || element === void 0 ? void 0 : element.kind) === tree_1.JS.Kind.ExportDeclaration ||
188
+ (element === null || element === void 0 ? void 0 : element.kind) === tree_1.JS.Kind.ExportAssignment ||
189
+ ((_a = modifiers === null || modifiers === void 0 ? void 0 : modifiers.some(m => m.keyword === "export")) !== null && _a !== void 0 ? _a : false);
190
+ }) || hasTopLevelAwait(cu);
191
+ }
192
+ /**
193
+ * Whether a statement holds an `await` outside any function of its own — legal only at module
194
+ * top level, unlike an `await` inside an `async function`, which says nothing about the file.
195
+ */
196
+ function hasTopLevelAwait(cu) {
197
+ let found = false;
198
+ (0, scope_1.walk)(cu.statements, node => {
199
+ if (found) {
200
+ return false;
201
+ }
202
+ if (node.kind === tree_1.JS.Kind.Await) {
203
+ found = true;
204
+ return false;
205
+ }
206
+ return node.kind !== java_1.J.Kind.MethodDeclaration && node.kind !== java_1.J.Kind.Lambda;
207
+ });
208
+ return found;
209
+ }
210
+ /** Whether the file binds its modules with `require`, which decides whether a create is possible. */
211
+ function isCommonJs(cu) {
212
+ if (cu.sourcePath.endsWith(".cjs") || cu.sourcePath.endsWith(".cts")) {
213
+ return true;
214
+ }
215
+ // Node treats these as ES modules regardless of what they contain, the same way
216
+ // `determineImportStyle` reads them as ES6-preferring; `.js`/`.ts`/`.tsx` stay ambiguous and
217
+ // fall through to the statements below.
218
+ if (cu.sourcePath.endsWith(".mjs") || cu.sourcePath.endsWith(".mts")) {
219
+ return false;
220
+ }
221
+ if (hasEsmSyntax(cu)) {
222
+ return false;
223
+ }
224
+ return cu.statements.some(stmt => (0, scope_1.declarationsOf)(stmt.element).some(d => requiredModuleOfDeclaration(d) !== undefined));
225
+ }
226
+ /** The module a `const X = require('m')` declaration names, for the one variable it declares. */
227
+ function requiredModuleOfDeclaration(declaration) {
228
+ var _a, _b;
229
+ return declaration.variables.length === 1
230
+ ? requiredModule((_b = (_a = declaration.variables[0].element) === null || _a === void 0 ? void 0 : _a.initializer) === null || _b === void 0 ? void 0 : _b.element)
231
+ : undefined;
232
+ }
220
233
  /** The module a `require('...')` initializer names, `undefined` for an initializer that is anything else. */
221
234
  function requiredModule(initializer) {
222
235
  return (initializer === null || initializer === void 0 ? void 0 : initializer.kind) === java_1.J.Kind.MethodInvocation
@@ -243,59 +256,13 @@ function requiredModuleOf(methodInv) {
243
256
  ? moduleNameOf(argument)
244
257
  : undefined;
245
258
  }
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
259
  /** A `require` binds a module the way an import does, so the pool records it the same way. */
293
260
  function requireBindings(pattern, module) {
294
261
  // A whole-module require binds no member, exactly as a default import does.
295
262
  if ((pattern === null || pattern === void 0 ? void 0 : pattern.kind) === java_1.J.Kind.Identifier) {
296
263
  return [{ name: pattern.simpleName, module, member: undefined, typeOnly: false }];
297
264
  }
298
- return patternNames(pattern).map(bound => bound.member === undefined
265
+ return (0, scope_1.bindingNames)(pattern).map(bound => bound.member === undefined
299
266
  ? { name: bound.name }
300
267
  : { name: bound.name, module, member: bound.member, typeOnly: false });
301
268
  }
@@ -352,31 +319,23 @@ function importBindings(jsImport) {
352
319
  return bindings;
353
320
  }
354
321
  /**
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.
322
+ * `names`, plus those pending `AddImport`s on the `afterVisit` queue have claimed. A queued
323
+ * `RemoveImport` does not free one: it removes only what the file leaves unused, and binding a name
324
+ * it keeps is an error, where an unnecessary suffix merely reads oddly.
358
325
  */
359
- function takenNames(bindings, visitor) {
360
- const taken = new Set();
326
+ function takenNames(names, visitor) {
327
+ const taken = new Set(names);
361
328
  for (const v of visitor.afterVisit || []) {
362
329
  if (v instanceof AddImport && v.bindingName) {
363
330
  taken.add(v.bindingName);
364
331
  }
365
332
  }
366
- for (const binding of bindings) {
367
- taken.add(binding.name);
368
- }
369
333
  return taken;
370
334
  }
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}`;
335
+ /** As {@link takenNames}, for a caller asking about one name rather than probing repeatedly. */
336
+ function nameTaken(name, names, visitor) {
337
+ return names.has(name) ||
338
+ (visitor.afterVisit || []).some(v => v instanceof AddImport && v.bindingName === name);
380
339
  }
381
340
  /**
382
341
  * The parser lifts surrogate pairs out of `valueSource` into `unicodeEscapes` and, when it does,
@@ -479,8 +438,8 @@ async function detectQuote(cu) {
479
438
  if (specifierQuote) {
480
439
  return specifierQuote;
481
440
  }
482
- const prettier = (0, style_1.getStyle)(style_1.StyleKind.PrettierStyle, cu);
483
- if ((prettier === null || prettier === void 0 ? void 0 : prettier.kind) === style_1.StyleKind.PrettierStyle && !prettier.ignored) {
441
+ const prettier = (0, prettier_format_1.getPrettierStyle)(cu);
442
+ if (prettier && !prettier.ignored) {
484
443
  const singleQuote = prettier.config.singleQuote;
485
444
  if (typeof singleQuote === 'boolean') {
486
445
  return singleQuote ? "'" : '"';
@@ -488,6 +447,32 @@ async function detectQuote(cu) {
488
447
  }
489
448
  return double > single ? '"' : "'";
490
449
  }
450
+ /**
451
+ * Lays out the import statement `AddImport` wrote, so that the file's own style — a Prettier
452
+ * configuration's brace spacing and print width, say — reaches it.
453
+ */
454
+ async function formatImport(cu, id, p) {
455
+ return await new class extends visitor_1.JavaScriptVisitor {
456
+ async visitImportDeclaration(jsImport, p) {
457
+ return jsImport.id === id ? await (0, format_1.autoFormat)(jsImport, p, undefined, this.cursor.parent) : jsImport;
458
+ }
459
+ }().visit(cu, p);
460
+ }
461
+ /**
462
+ * As {@link formatImport}, for an import that gained specifiers. Short of a Prettier configuration
463
+ * deciding the whole line, the statement's own text says more about its spacing than a
464
+ * repository-wide style does, and the merge reads it directly.
465
+ */
466
+ async function formatMergedImport(cu, id, p) {
467
+ var _a;
468
+ return ((_a = (0, prettier_format_1.getPrettierStyle)(cu)) === null || _a === void 0 ? void 0 : _a.ignored) === false ? formatImport(cu, id, p) : cu;
469
+ }
470
+ /**
471
+ * Adds the import {@link AddImportOptions} describes, under the name derived there. An import
472
+ * already in the file answers where it binds that same name, or where the request expressed no
473
+ * preference at all. Reuse under some other name belongs to {@link bindImport}, whose caller
474
+ * learns which name came back; a recipe driving this visitor is stuck with the one it derived.
475
+ */
491
476
  class AddImport extends visitor_1.JavaScriptVisitor {
492
477
  constructor(options, bindingName) {
493
478
  var _a, _b, _c;
@@ -689,17 +674,18 @@ class AddImport extends visitor_1.JavaScriptVisitor {
689
674
  return mergedCu;
690
675
  }
691
676
  }
692
- // Add the import using the appropriate style
693
- if (importStyle === ImportStyle.CommonJS) {
694
- // TODO: Implement CommonJS require creation
695
- // For now, fall back to ES6 imports
696
- // return this.addCommonJSRequire(compilationUnit, p);
677
+ // TODO: create a `require` here. Until then the request goes unserved, since `import` would
678
+ // make a file that binds its modules with `require` an ES module and change how everything
679
+ // in it loads — `maybeBind` refuses it for the same reason. An explicit ES6 `style`
680
+ // overrides, which is how a caller converting the file to ESM asks for one.
681
+ if (importStyle === ImportStyle.CommonJS && isCommonJs(compilationUnit)) {
682
+ return compilationUnit;
697
683
  }
698
684
  // Add ES6 import (handles ES6Named, ES6Namespace, ES6Default)
699
- return this.produceJavaScript(compilationUnit, p, async (draft) => {
700
- // Find the position to insert the import
701
- const insertionIndex = this.findImportInsertionIndex(compilationUnit);
702
- const newImport = await this.createImportStatement(compilationUnit, insertionIndex, p);
685
+ // Find the position to insert the import
686
+ const insertionIndex = this.findImportInsertionIndex(compilationUnit);
687
+ const newImport = await this.createImportStatement(compilationUnit, insertionIndex, p);
688
+ const withImport = await this.produceJavaScript(compilationUnit, p, async (draft) => {
703
689
  // Insert the import at the appropriate position
704
690
  // Create semicolon marker for the import statement
705
691
  const semicolonMarkers = (0, markers_1.markers)({
@@ -746,6 +732,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
746
732
  }
747
733
  }
748
734
  });
735
+ return formatImport(withImport, newImport.id, p);
749
736
  }
750
737
  /**
751
738
  * Try to merge the new member into an existing import from the same module
@@ -781,7 +768,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
781
768
  continue;
782
769
  }
783
770
  // We found a matching import with named bindings - merge into it
784
- return this.produceJavaScript(compilationUnit, p, async (draft) => {
771
+ return formatMergedImport(await this.produceJavaScript(compilationUnit, p, async (draft) => {
785
772
  var _a, _b, _c;
786
773
  const namedImports = importClause.namedBindings;
787
774
  const existingElements = namedImports.elements.elements;
@@ -841,12 +828,12 @@ class AddImport extends visitor_1.JavaScriptVisitor {
841
828
  });
842
829
  // Replace the statement in the compilation unit
843
830
  draft.statements = compilationUnit.statements.map((s, idx) => idx === i ? Object.assign(Object.assign({}, s), { element: updatedImport }) : s);
844
- });
831
+ }), jsImport.id, p);
845
832
  }
846
833
  // Case 2: Default import without named bindings - add named bindings
847
834
  // Transform: import React from 'react' -> import React, { useState } from 'react'
848
835
  if (importClause.name && !importClause.namedBindings) {
849
- return this.produceJavaScript(compilationUnit, p, async (draft) => {
836
+ return formatMergedImport(await this.produceJavaScript(compilationUnit, p, async (draft) => {
850
837
  const newSpecifier = this.createImportSpecifier();
851
838
  // Get the spaces style for brace spacing
852
839
  const spacesStyle = (0, style_1.getStyle)(style_1.StyleKind.SpacesStyle, compilationUnit);
@@ -882,7 +869,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
882
869
  });
883
870
  // Replace the statement in the compilation unit
884
871
  draft.statements = compilationUnit.statements.map((s, idx) => idx === i ? Object.assign(Object.assign({}, s), { element: updatedImport }) : s);
885
- });
872
+ }), jsImport.id, p);
886
873
  }
887
874
  }
888
875
  }
@@ -1184,10 +1171,8 @@ class AddImport extends visitor_1.JavaScriptVisitor {
1184
1171
  var _a;
1185
1172
  // Determine the appropriate prefix (spacing before the import)
1186
1173
  const prefix = this.determineImportPrefix(compilationUnit, insertionIndex);
1187
- // Create the module specifier
1188
- // For side-effect imports, use emptySpace since space comes from LeftPadded.before
1189
- // For regular imports with import clause, use emptySpace since space comes from LeftPadded.before
1190
- // However, the printer expects the space after 'from' in the literal's prefix
1174
+ // Whitespace throughout follows the parser's placement, so that formatting the result is a
1175
+ // no-op where the file's style already agrees with it.
1191
1176
  // Note: value is the unquoted module name; valueSource and unicodeEscapes are its printed form
1192
1177
  let valueSource = this.moduleValueSource;
1193
1178
  if (valueSource === undefined) {
@@ -1197,7 +1182,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
1197
1182
  const moduleSpecifier = {
1198
1183
  id: (0, uuid_1.randomId)(),
1199
1184
  kind: java_1.J.Kind.Literal,
1200
- prefix: this.sideEffectOnly ? java_1.emptySpace : java_1.singleSpace,
1185
+ prefix: java_1.singleSpace,
1201
1186
  markers: markers_1.emptyMarkers,
1202
1187
  value: this.module,
1203
1188
  valueSource,
@@ -1234,7 +1219,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
1234
1219
  const namespaceBinding = {
1235
1220
  id: (0, uuid_1.randomId)(),
1236
1221
  kind: tree_1.JS.Kind.Alias,
1237
- prefix: java_1.singleSpace,
1222
+ prefix: this.typeOnly ? java_1.singleSpace : java_1.emptySpace,
1238
1223
  markers: markers_1.emptyMarkers,
1239
1224
  propertyName: (0, java_1.rightPadded)(propertyName, java_1.singleSpace),
1240
1225
  alias: aliasIdentifier
@@ -1242,7 +1227,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
1242
1227
  importClause = {
1243
1228
  id: (0, uuid_1.randomId)(),
1244
1229
  kind: tree_1.JS.Kind.ImportClause,
1245
- prefix: this.typeOnly ? java_1.singleSpace : java_1.emptySpace,
1230
+ prefix: java_1.singleSpace,
1246
1231
  markers: markers_1.emptyMarkers,
1247
1232
  typeOnly: this.typeOnly,
1248
1233
  name: undefined,
@@ -1255,7 +1240,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
1255
1240
  const defaultName = {
1256
1241
  id: (0, uuid_1.randomId)(),
1257
1242
  kind: java_1.J.Kind.Identifier,
1258
- prefix: java_1.singleSpace,
1243
+ prefix: this.typeOnly ? java_1.singleSpace : java_1.emptySpace,
1259
1244
  markers: markers_1.emptyMarkers,
1260
1245
  annotations: [],
1261
1246
  simpleName: this.bindingName,
@@ -1265,10 +1250,10 @@ class AddImport extends visitor_1.JavaScriptVisitor {
1265
1250
  importClause = {
1266
1251
  id: (0, uuid_1.randomId)(),
1267
1252
  kind: tree_1.JS.Kind.ImportClause,
1268
- prefix: this.typeOnly ? java_1.singleSpace : java_1.emptySpace,
1253
+ prefix: java_1.singleSpace,
1269
1254
  markers: markers_1.emptyMarkers,
1270
1255
  typeOnly: this.typeOnly,
1271
- name: (0, java_1.rightPadded)(defaultName, java_1.emptySpace),
1256
+ name: (0, java_1.rightPadded)(defaultName, java_1.singleSpace),
1272
1257
  namedBindings: undefined
1273
1258
  };
1274
1259
  }
@@ -1284,11 +1269,11 @@ class AddImport extends visitor_1.JavaScriptVisitor {
1284
1269
  const namedImports = {
1285
1270
  id: (0, uuid_1.randomId)(),
1286
1271
  kind: tree_1.JS.Kind.NamedImports,
1287
- prefix: java_1.singleSpace,
1272
+ prefix: java_1.emptySpace,
1288
1273
  markers: markers_1.emptyMarkers,
1289
1274
  elements: {
1290
1275
  kind: java_1.J.Kind.Container,
1291
- before: java_1.emptySpace,
1276
+ before: this.typeOnly ? java_1.singleSpace : java_1.emptySpace,
1292
1277
  elements: [(0, java_1.rightPadded)(importSpecWithSpacing, braceSpace)],
1293
1278
  markers: markers_1.emptyMarkers
1294
1279
  }
@@ -1296,7 +1281,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
1296
1281
  importClause = {
1297
1282
  id: (0, uuid_1.randomId)(),
1298
1283
  kind: tree_1.JS.Kind.ImportClause,
1299
- prefix: this.typeOnly ? java_1.singleSpace : java_1.emptySpace,
1284
+ prefix: java_1.singleSpace,
1300
1285
  markers: markers_1.emptyMarkers,
1301
1286
  typeOnly: this.typeOnly,
1302
1287
  name: undefined,
@@ -1312,7 +1297,9 @@ class AddImport extends visitor_1.JavaScriptVisitor {
1312
1297
  importClause,
1313
1298
  moduleSpecifier: {
1314
1299
  kind: java_1.J.Kind.LeftPadded,
1315
- before: java_1.singleSpace,
1300
+ // Bindings end at `}`, so the space before `from` sits here; a default import's name
1301
+ // and a side-effect import's literal carry their own
1302
+ before: (importClause === null || importClause === void 0 ? void 0 : importClause.namedBindings) ? java_1.singleSpace : java_1.emptySpace,
1316
1303
  element: moduleSpecifier,
1317
1304
  markers: markers_1.emptyMarkers
1318
1305
  },
@@ -1431,4 +1418,506 @@ class AddImport extends visitor_1.JavaScriptVisitor {
1431
1418
  }
1432
1419
  }
1433
1420
  exports.AddImport = AddImport;
1421
+ /**
1422
+ * The local name `jsImport` binds `member` of `module` to, or `undefined` where it binds
1423
+ * something else. `'default'` and an absent `member` both mean the default import, matching
1424
+ * {@link memberName}.
1425
+ */
1426
+ function importBinds(jsImport, module, member) {
1427
+ var _a, _b;
1428
+ const specifier = (_a = jsImport.moduleSpecifier) === null || _a === void 0 ? void 0 : _a.element;
1429
+ if ((specifier === null || specifier === void 0 ? void 0 : specifier.kind) !== java_1.J.Kind.Literal || specifier.value !== module) {
1430
+ return undefined;
1431
+ }
1432
+ const importClause = jsImport.importClause;
1433
+ if (!importClause) {
1434
+ return undefined;
1435
+ }
1436
+ const key = memberName(member);
1437
+ if (key === undefined) {
1438
+ const nameElem = (_b = importClause.name) === null || _b === void 0 ? void 0 : _b.element;
1439
+ return nameElem && (0, java_1.isIdentifier)(nameElem) ? nameElem.simpleName : undefined;
1440
+ }
1441
+ if (key === '*') {
1442
+ const namedBindings = importClause.namedBindings;
1443
+ return (namedBindings === null || namedBindings === void 0 ? void 0 : namedBindings.kind) === tree_1.JS.Kind.Alias && (0, java_1.isIdentifier)(namedBindings.alias)
1444
+ ? namedBindings.alias.simpleName
1445
+ : undefined;
1446
+ }
1447
+ const namedBindings = importClause.namedBindings;
1448
+ if ((namedBindings === null || namedBindings === void 0 ? void 0 : namedBindings.kind) !== tree_1.JS.Kind.NamedImports) {
1449
+ return undefined;
1450
+ }
1451
+ for (const elem of namedBindings.elements.elements) {
1452
+ const specifierNode = elem.element.specifier;
1453
+ if (!namedSpecifierImports(specifierNode, key)) {
1454
+ continue;
1455
+ }
1456
+ if ((0, java_1.isIdentifier)(specifierNode)) {
1457
+ return specifierNode.simpleName;
1458
+ }
1459
+ const alias = specifierNode.alias;
1460
+ if ((0, java_1.isIdentifier)(alias)) {
1461
+ return alias.simpleName;
1462
+ }
1463
+ }
1464
+ return undefined;
1465
+ }
1466
+ /** Whether `specifier` imports the member `key`, under whatever local name it binds it to. */
1467
+ function namedSpecifierImports(specifier, key) {
1468
+ if ((0, java_1.isIdentifier)(specifier)) {
1469
+ return specifier.simpleName === key;
1470
+ }
1471
+ if (specifier.kind === tree_1.JS.Kind.Alias) {
1472
+ const propertyName = specifier.propertyName.element;
1473
+ return (0, java_1.isIdentifier)(propertyName) && propertyName.simpleName === key;
1474
+ }
1475
+ return false;
1476
+ }
1477
+ /** Whether the named specifier binding `key` carries its own inline `type`, as in `{type a, b}`. */
1478
+ function namedSpecifierIsTypeOnly(imp, key) {
1479
+ var _a;
1480
+ const namedBindings = (_a = imp.importClause) === null || _a === void 0 ? void 0 : _a.namedBindings;
1481
+ if ((namedBindings === null || namedBindings === void 0 ? void 0 : namedBindings.kind) !== tree_1.JS.Kind.NamedImports) {
1482
+ return false;
1483
+ }
1484
+ for (const elem of namedBindings.elements.elements) {
1485
+ if (namedSpecifierImports(elem.element.specifier, key)) {
1486
+ return elem.element.importType.element;
1487
+ }
1488
+ }
1489
+ return false;
1490
+ }
1491
+ /** How many named specifiers `jsImport` carries, `0` for a default, namespace or side-effect import. */
1492
+ function namedImportCount(jsImport) {
1493
+ var _a;
1494
+ const namedBindings = (_a = jsImport.importClause) === null || _a === void 0 ? void 0 : _a.namedBindings;
1495
+ return (namedBindings === null || namedBindings === void 0 ? void 0 : namedBindings.kind) === tree_1.JS.Kind.NamedImports ? namedBindings.elements.elements.length : 0;
1496
+ }
1497
+ /**
1498
+ * Whether `jsImport`'s clause binds exactly one thing — a default, a namespace, or one named
1499
+ * specifier. That is the only shape a module-only move can rewrite in place: whichever binding
1500
+ * `importBinds` already matched is this one, so nothing else the clause carries goes along with it.
1501
+ */
1502
+ function isOnlyMember(jsImport) {
1503
+ var _a;
1504
+ const importClause = jsImport.importClause;
1505
+ if (!importClause) {
1506
+ return false;
1507
+ }
1508
+ const hasDefault = importClause.name !== undefined;
1509
+ const hasNamespace = ((_a = importClause.namedBindings) === null || _a === void 0 ? void 0 : _a.kind) === tree_1.JS.Kind.Alias;
1510
+ return (hasDefault ? 1 : 0) + (hasNamespace ? 1 : 0) + namedImportCount(jsImport) === 1;
1511
+ }
1512
+ /**
1513
+ * The existing binding for `member` of `module`, read from `cu`'s own import statements — what
1514
+ * `maybeRebind` reads before committing to a `RebindImport` edit.
1515
+ */
1516
+ function existingImportBinding(cu, module, member) {
1517
+ for (const stmt of cu.statements) {
1518
+ const element = stmt.element;
1519
+ if ((element === null || element === void 0 ? void 0 : element.kind) !== tree_1.JS.Kind.Import) {
1520
+ continue;
1521
+ }
1522
+ const localName = importBinds(element, module, member);
1523
+ if (localName !== undefined) {
1524
+ return {
1525
+ localName,
1526
+ onlyMemberOfStatement: isOnlyMember(element),
1527
+ aliased: localName !== memberName(member)
1528
+ };
1529
+ }
1530
+ }
1531
+ return undefined;
1532
+ }
1533
+ /**
1534
+ * The `member as local` specifier, for an import binding `member` under `local` or an export
1535
+ * publishing `local`'s binding under that name. `local` itself becomes the alias, keeping the type
1536
+ * attribution it holds, and the alias takes its prefix: that whitespace separates the specifier
1537
+ * from a `type` keyword before it.
1538
+ */
1539
+ function aliasing(local, member) {
1540
+ const propertyName = {
1541
+ id: (0, uuid_1.randomId)(),
1542
+ kind: java_1.J.Kind.Identifier,
1543
+ prefix: java_1.emptySpace,
1544
+ markers: markers_1.emptyMarkers,
1545
+ annotations: [],
1546
+ simpleName: member,
1547
+ type: undefined,
1548
+ fieldType: undefined
1549
+ };
1550
+ return {
1551
+ id: (0, uuid_1.randomId)(),
1552
+ kind: tree_1.JS.Kind.Alias,
1553
+ prefix: local.prefix,
1554
+ markers: markers_1.emptyMarkers,
1555
+ propertyName: (0, java_1.rightPadded)(propertyName, java_1.singleSpace),
1556
+ alias: Object.assign(Object.assign({}, local), { prefix: java_1.singleSpace })
1557
+ };
1558
+ }
1559
+ /**
1560
+ * Drops the binding for `member` from `jsImport`'s clause — the default, the namespace alias, or
1561
+ * one entry of the named list, whichever `member` names — keeping everything else the clause
1562
+ * binds. `ElementRemovalFormatter` carries the dropped binding's prefix onto whatever prints
1563
+ * next, the same way `RemoveImport` keeps formatting sane when trimming a list.
1564
+ */
1565
+ function removeBinding(jsImport, member) {
1566
+ var _a;
1567
+ const importClause = jsImport.importClause;
1568
+ if (!importClause) {
1569
+ return jsImport;
1570
+ }
1571
+ const key = memberName(member);
1572
+ if (key === undefined) {
1573
+ if (!importClause.name) {
1574
+ return jsImport;
1575
+ }
1576
+ const namedBindings = importClause.namedBindings;
1577
+ if ((namedBindings === null || namedBindings === void 0 ? void 0 : namedBindings.kind) === tree_1.JS.Kind.NamedImports) {
1578
+ // `NamedImports` keeps the space before its own `{` on the container's `before`,
1579
+ // not on its own prefix, so the removed default's prefix has to land there instead.
1580
+ const namedImports = namedBindings;
1581
+ const updated = Object.assign(Object.assign({}, namedImports), { elements: Object.assign(Object.assign({}, namedImports.elements), { before: importClause.name.element.prefix }) });
1582
+ return Object.assign(Object.assign({}, jsImport), { importClause: Object.assign(Object.assign({}, importClause), { name: undefined, namedBindings: updated }) });
1583
+ }
1584
+ if (namedBindings) {
1585
+ const formatter = new java_1.ElementRemovalFormatter();
1586
+ formatter.markRemoved(importClause.name.element);
1587
+ return Object.assign(Object.assign({}, jsImport), { importClause: Object.assign(Object.assign({}, importClause), { name: undefined, namedBindings: formatter.processKept(namedBindings) }) });
1588
+ }
1589
+ return Object.assign(Object.assign({}, jsImport), { importClause: Object.assign(Object.assign({}, importClause), { name: undefined }) });
1590
+ }
1591
+ if (key === '*') {
1592
+ return Object.assign(Object.assign({}, jsImport), { importClause: Object.assign(Object.assign({}, importClause), { namedBindings: undefined }) });
1593
+ }
1594
+ if (((_a = importClause.namedBindings) === null || _a === void 0 ? void 0 : _a.kind) !== tree_1.JS.Kind.NamedImports) {
1595
+ return jsImport;
1596
+ }
1597
+ const namedImports = importClause.namedBindings;
1598
+ const formatter = new java_1.ElementRemovalFormatter();
1599
+ const kept = [];
1600
+ for (const entry of namedImports.elements.elements) {
1601
+ if (namedSpecifierImports(entry.element.specifier, key)) {
1602
+ formatter.markRemoved(entry.element);
1603
+ }
1604
+ else {
1605
+ kept.push(Object.assign(Object.assign({}, entry), { element: formatter.processKept(entry.element) }));
1606
+ }
1607
+ }
1608
+ if (kept.length === 0) {
1609
+ // An emptied brace list still prints, as `import D, {} from "m"`, so it goes with its
1610
+ // last member; the caller drops the whole statement when no default remains either.
1611
+ return Object.assign(Object.assign({}, jsImport), { importClause: Object.assign(Object.assign({}, importClause), { namedBindings: undefined }) });
1612
+ }
1613
+ const updatedNamedImports = Object.assign(Object.assign({}, namedImports), { elements: Object.assign(Object.assign({}, namedImports.elements), { elements: kept }) });
1614
+ return Object.assign(Object.assign({}, jsImport), { importClause: Object.assign(Object.assign({}, importClause), { namedBindings: updatedNamedImports }) });
1615
+ }
1616
+ /**
1617
+ * Moves the binding `from` names to `to`, binding it under `boundName`. In place when the
1618
+ * statement that carries it binds nothing else — module and member specifier rewritten there
1619
+ * directly; otherwise the old specifier drops and {@link bindImport} queues the replacement.
1620
+ * A `boundName` of its own renames the binding, and the file's references to it follow.
1621
+ *
1622
+ * Not built on `RemoveImport`/`maybeUnbind`: those only drop a binding once nothing references
1623
+ * it, but a rebind moves one that is still in use — removal here has to be unconditional.
1624
+ */
1625
+ class RebindImport extends visitor_1.JavaScriptVisitor {
1626
+ constructor(from, to, localName, boundName) {
1627
+ super();
1628
+ this.from = from;
1629
+ this.to = to;
1630
+ this.localName = localName;
1631
+ this.boundName = boundName;
1632
+ this.transformedInPlace = false;
1633
+ this.typeOnly = false;
1634
+ this.movedTypes = new MovedTypes(this.from, this.to);
1635
+ /** Identifiers settled as references to the binding, so a parent need not settle it again. */
1636
+ this.references = new Set();
1637
+ }
1638
+ get renaming() {
1639
+ return this.boundName !== this.localName;
1640
+ }
1641
+ async visitJsCompilationUnit(cu, p) {
1642
+ const visited = await super.visitJsCompilationUnit(cu, p);
1643
+ if (!this.transformedInPlace) {
1644
+ bindImport(this, {
1645
+ module: this.to.module,
1646
+ member: this.to.member,
1647
+ alias: this.boundName,
1648
+ typeOnly: this.typeOnly,
1649
+ onlyIfReferenced: false
1650
+ });
1651
+ }
1652
+ return visited;
1653
+ }
1654
+ async visitImportDeclaration(jsImport, p) {
1655
+ var _a, _b;
1656
+ const imp = await super.visitImportDeclaration(jsImport, p);
1657
+ const key = memberName(this.from.member);
1658
+ // One call moves one binding, and no two imports bind the same local name, so the name
1659
+ // read from the matched statement is what picks it back out of the file.
1660
+ if (importBinds(imp, this.from.module, this.from.member) !== this.localName) {
1661
+ return imp;
1662
+ }
1663
+ // A moved named specifier's own inline `type` marks it type-only even where the clause
1664
+ // it's leaving is not — the replacement needs the same answer to stay type-safe.
1665
+ this.typeOnly = ((_b = (_a = imp.importClause) === null || _a === void 0 ? void 0 : _a.typeOnly) !== null && _b !== void 0 ? _b : false) ||
1666
+ (key !== undefined && key !== '*' && namedSpecifierIsTypeOnly(imp, key));
1667
+ if (!isOnlyMember(imp)) {
1668
+ return removeBinding(imp, this.from.member);
1669
+ }
1670
+ this.transformedInPlace = true;
1671
+ return (0, mutative_1.create)(imp, draft => {
1672
+ var _a;
1673
+ const literal = draft.moduleSpecifier.element;
1674
+ literal.value = this.to.module;
1675
+ const originalSource = literal.valueSource || `"${this.from.module}"`;
1676
+ const quoteChar = originalSource.startsWith("'") ? "'" : '"';
1677
+ literal.valueSource = `${quoteChar}${this.to.module}${quoteChar}`;
1678
+ // A default or namespace import carries its local name on the clause itself; a named
1679
+ // one states the member alongside it, in the specifier.
1680
+ if (key === undefined || key === '*') {
1681
+ if (this.boundName !== this.localName) {
1682
+ renameClauseBinding(draft.importClause, key, this.boundName);
1683
+ }
1684
+ return;
1685
+ }
1686
+ rewriteNamedSpecifier(draft.importClause, key, (_a = memberName(this.to.member)) !== null && _a !== void 0 ? _a : key, this.boundName);
1687
+ });
1688
+ }
1689
+ async visitIdentifier(identifier, p) {
1690
+ if (!this.referencesBinding(identifier)) {
1691
+ return super.visitIdentifier(identifier, p);
1692
+ }
1693
+ this.references.add(identifier.id);
1694
+ // The name follows the binding, and so does what the name is attributed to; an aliased
1695
+ // binding keeps its name and still resolves somewhere new.
1696
+ const type = await this.movedTypes.visit(identifier.type, undefined);
1697
+ const fieldType = await this.movedTypes.visit(identifier.fieldType, undefined);
1698
+ return !this.renaming && type === identifier.type && fieldType === identifier.fieldType
1699
+ ? identifier
1700
+ : Object.assign(Object.assign({}, identifier), { simpleName: this.boundName, type, fieldType });
1701
+ }
1702
+ async visitMethodInvocation(method, p) {
1703
+ const m = await super.visitMethodInvocation(method, p);
1704
+ if (!this.referencesMovedBinding(m.name)) {
1705
+ return m;
1706
+ }
1707
+ const methodType = await this.movedTypes.visit(m.methodType, undefined);
1708
+ return methodType === m.methodType ? m : Object.assign(Object.assign({}, m), { methodType });
1709
+ }
1710
+ async visitNewClass(newClass, p) {
1711
+ const nc = await super.visitNewClass(newClass, p);
1712
+ if (!this.referencesMovedBinding(nc.class)) {
1713
+ return nc;
1714
+ }
1715
+ const type = await this.movedTypes.visit(nc.type, undefined);
1716
+ const methodType = await this.movedTypes.visit(nc.methodType, undefined);
1717
+ const constructorType = await this.movedTypes.visit(nc.constructorType, undefined);
1718
+ return type === nc.type && methodType === nc.methodType && constructorType === nc.constructorType
1719
+ ? nc
1720
+ : Object.assign(Object.assign({}, nc), { type, methodType, constructorType });
1721
+ }
1722
+ async visitFunctionCall(functionCall, p) {
1723
+ var _a;
1724
+ const fc = await super.visitFunctionCall(functionCall, p);
1725
+ if (!this.referencesMovedBinding((_a = fc.function) === null || _a === void 0 ? void 0 : _a.element)) {
1726
+ return fc;
1727
+ }
1728
+ const methodType = await this.movedTypes.visit(fc.methodType, undefined);
1729
+ return methodType === fc.methodType ? fc : Object.assign(Object.assign({}, fc), { methodType });
1730
+ }
1731
+ /**
1732
+ * Whether `callee` is the identifier `visitIdentifier` settled as a reference to the binding.
1733
+ * A rewrite keeps the identifier's id, so the one it settled is the one still standing here.
1734
+ */
1735
+ referencesMovedBinding(callee) {
1736
+ return (callee === null || callee === void 0 ? void 0 : callee.kind) === java_1.J.Kind.Identifier && this.references.has(callee.id);
1737
+ }
1738
+ /**
1739
+ * A decorator and the other type-name positions reach the tree through this hook, which the
1740
+ * base visitor holds closed; a reference in one of them is a reference like any other.
1741
+ */
1742
+ async visitTypeName(nameTree, p) {
1743
+ return await this.visit(nameTree, p);
1744
+ }
1745
+ /**
1746
+ * An export specifier's own name is the module's public surface, which its consumers read and
1747
+ * the rename leaves alone. See CLAUDE.md: Which name a rebind binds.
1748
+ */
1749
+ async visitExportSpecifier(exportSpecifier, p) {
1750
+ if (!this.renaming) {
1751
+ return super.visitExportSpecifier(exportSpecifier, p);
1752
+ }
1753
+ // `export {a} from "m"` names `m`'s member rather than anything this file binds.
1754
+ const from = this.cursor.firstEnclosing((v) => (v === null || v === void 0 ? void 0 : v.kind) === tree_1.JS.Kind.ExportDeclaration);
1755
+ if ((from === null || from === void 0 ? void 0 : from.moduleSpecifier) !== undefined) {
1756
+ return exportSpecifier;
1757
+ }
1758
+ const specifier = exportSpecifier.specifier;
1759
+ if (specifier.kind === java_1.J.Kind.Identifier && specifier.simpleName === this.localName) {
1760
+ return Object.assign(Object.assign({}, exportSpecifier), { specifier: aliasing(specifier, this.boundName) });
1761
+ }
1762
+ if (specifier.kind === tree_1.JS.Kind.Alias) {
1763
+ const alias = specifier;
1764
+ const propertyName = alias.propertyName.element;
1765
+ return propertyName.kind === java_1.J.Kind.Identifier && propertyName.simpleName === this.localName
1766
+ ? Object.assign(Object.assign({}, exportSpecifier), { specifier: Object.assign(Object.assign({}, alias), { propertyName: Object.assign(Object.assign({}, alias.propertyName), { element: Object.assign(Object.assign({}, propertyName), { simpleName: this.boundName }) }) }) })
1767
+ : exportSpecifier;
1768
+ }
1769
+ return super.visitExportSpecifier(exportSpecifier, p);
1770
+ }
1771
+ /**
1772
+ * Whether the identifier at the cursor stands for the moved binding: the right name, in a
1773
+ * position that references rather than declares, reaching the module scope that binds it.
1774
+ */
1775
+ referencesBinding(identifier) {
1776
+ var _a;
1777
+ return identifier.simpleName === this.localName &&
1778
+ // The specifier binding the name is the one edit that is not a reference to it.
1779
+ !this.cursor.firstEnclosing((v) => (v === null || v === void 0 ? void 0 : v.kind) === tree_1.JS.Kind.Import) &&
1780
+ (0, scope_1.isValueReference)(this.cursor, identifier) &&
1781
+ ((_a = (0, scope_1.scopeOf)(this.cursor).declaringScope(this.localName)) === null || _a === void 0 ? void 0 : _a.kind) === tree_1.JS.Kind.CompilationUnit;
1782
+ }
1783
+ /** A shorthand property's name slot is also the reference to the binding. */
1784
+ async visitPropertyAssignment(propertyAssignment, p) {
1785
+ var _a;
1786
+ const name = propertyAssignment.name.element;
1787
+ if (this.renaming && propertyAssignment.initializer === undefined &&
1788
+ name.kind === java_1.J.Kind.Identifier && name.simpleName === this.localName &&
1789
+ ((_a = (0, scope_1.scopeOf)(this.cursor).declaringScope(this.localName)) === null || _a === void 0 ? void 0 : _a.kind) === tree_1.JS.Kind.CompilationUnit) {
1790
+ // The key names a property rather than the binding, so it carries no attribution,
1791
+ // the same way `aliasing` builds a property name that stands for nothing.
1792
+ return Object.assign(Object.assign({}, propertyAssignment), { name: Object.assign(Object.assign({}, propertyAssignment.name), { element: Object.assign(Object.assign({}, name), { type: undefined, fieldType: undefined }) }), assigmentToken: tree_1.JS.PropertyAssignment.Token.Colon, initializer: Object.assign(Object.assign({}, name), { prefix: java_1.singleSpace, simpleName: this.boundName }) });
1793
+ }
1794
+ return super.visitPropertyAssignment(propertyAssignment, p);
1795
+ }
1796
+ }
1797
+ exports.RebindImport = RebindImport;
1798
+ /**
1799
+ * Rewrites the attribution a move invalidates, onto the module and member it moved to. Applied at
1800
+ * a reference to the moved binding. See CLAUDE.md: What a rebind's attribution follows.
1801
+ */
1802
+ class MovedTypes extends type_visitor_1.TypeVisitor {
1803
+ constructor(from, to) {
1804
+ super();
1805
+ this.onPath = new Set();
1806
+ this.answered = new Map();
1807
+ // Where no member is named the two keys coincide, and both name the module.
1808
+ this.renamed = new Map([[from.module, to.module], [qualifiedName(from), qualifiedName(to)]]);
1809
+ this.fromMember = declaredMember(from);
1810
+ this.toMember = declaredMember(to);
1811
+ this.toModule = to.module;
1812
+ }
1813
+ /**
1814
+ * A type reached while it is still being visited is a cycle — a class holds a method whose
1815
+ * declaring type is that class — and answers with itself, which is what ends the walk. Every
1816
+ * reference to a binding shares one type, so a completed walk is remembered for the next.
1817
+ */
1818
+ async visit(type, p) {
1819
+ if (type === undefined || this.onPath.has(type)) {
1820
+ return type;
1821
+ }
1822
+ if (this.answered.has(type)) {
1823
+ return this.answered.get(type);
1824
+ }
1825
+ this.onPath.add(type);
1826
+ try {
1827
+ const answer = await super.visit(type, p);
1828
+ // Only the type a walk entered at is remembered: one reached inside it may have met
1829
+ // a back edge, which answers with the type itself and so stands for the path it was on.
1830
+ if (this.onPath.size === 1) {
1831
+ this.answered.set(type, answer);
1832
+ }
1833
+ return answer;
1834
+ }
1835
+ finally {
1836
+ this.onPath.delete(type);
1837
+ }
1838
+ }
1839
+ async visitClass(aClass, p) {
1840
+ const visited = await super.visitClass(aClass, p);
1841
+ const moved = this.renamed.get(visited.fullyQualifiedName);
1842
+ return moved === undefined || moved === visited.fullyQualifiedName
1843
+ ? visited
1844
+ : Object.assign(Object.assign({}, visited), { fullyQualifiedName: moved });
1845
+ }
1846
+ async visitMethod(method, p) {
1847
+ const visited = await super.visitMethod(method, p);
1848
+ return this.declaresMovedMember(visited.name, visited.declaringType)
1849
+ ? Object.assign(Object.assign({}, visited), { name: this.toMember })
1850
+ : visited;
1851
+ }
1852
+ async visitVariable(variable, p) {
1853
+ const visited = await super.visitVariable(variable, p);
1854
+ return this.declaresMovedMember(visited.name, visited.owner)
1855
+ ? Object.assign(Object.assign({}, visited), { name: this.toMember })
1856
+ : visited;
1857
+ }
1858
+ /**
1859
+ * Whether `name`, declared on `owner`, is the member that moved. `owner` has already followed
1860
+ * the move by the time this runs, so it is the module moved *to* that it has to name. A
1861
+ * default or namespace binding declares no member, so there is no name for one to take.
1862
+ */
1863
+ declaresMovedMember(name, owner) {
1864
+ return this.toMember !== undefined && name === this.fromMember && this.toMember !== this.fromMember &&
1865
+ owner !== undefined && java_1.Type.isFullyQualified(owner) &&
1866
+ java_1.Type.FullyQualified.getFullyQualifiedName(owner) === this.toModule;
1867
+ }
1868
+ }
1869
+ /** A member's qualified name, or the module's own where no member is named. */
1870
+ function qualifiedName(binding) {
1871
+ const key = memberName(binding.member);
1872
+ return key === undefined || key === '*' ? binding.module : `${binding.module}.${key}`;
1873
+ }
1874
+ /** The member the module declares, where the binding names one: a whole module declares none. */
1875
+ function declaredMember(binding) {
1876
+ const key = memberName(binding.member);
1877
+ return key === undefined || key === '*' ? undefined : key;
1878
+ }
1879
+ /** Renames the identifier a default (`key` undefined) or namespace clause binds its module under. */
1880
+ function renameClauseBinding(importClause, key, boundName) {
1881
+ var _a, _b;
1882
+ const bound = key === undefined
1883
+ ? (_a = importClause === null || importClause === void 0 ? void 0 : importClause.name) === null || _a === void 0 ? void 0 : _a.element
1884
+ : (_b = importClause === null || importClause === void 0 ? void 0 : importClause.namedBindings) === null || _b === void 0 ? void 0 : _b.alias;
1885
+ if ((bound === null || bound === void 0 ? void 0 : bound.kind) === java_1.J.Kind.Identifier) {
1886
+ bound.simpleName = boundName;
1887
+ }
1888
+ }
1889
+ /**
1890
+ * Rewrites the specifier importing `key` to import `member` under `boundName` — a bare `{member}`
1891
+ * where the two agree, since an alias saying the same thing is noise the source never had.
1892
+ */
1893
+ function rewriteNamedSpecifier(importClause, key, member, boundName) {
1894
+ var _a, _b;
1895
+ if (((_a = importClause === null || importClause === void 0 ? void 0 : importClause.namedBindings) === null || _a === void 0 ? void 0 : _a.kind) !== tree_1.JS.Kind.NamedImports) {
1896
+ return;
1897
+ }
1898
+ for (const elem of importClause.namedBindings.elements.elements) {
1899
+ const specifier = elem.element;
1900
+ const node = specifier.specifier;
1901
+ if (!namedSpecifierImports(node, key)) {
1902
+ continue;
1903
+ }
1904
+ const alias = node.kind === tree_1.JS.Kind.Alias ? node : undefined;
1905
+ const local = ((_b = alias === null || alias === void 0 ? void 0 : alias.alias) !== null && _b !== void 0 ? _b : node);
1906
+ if (local.kind !== java_1.J.Kind.Identifier) {
1907
+ continue;
1908
+ }
1909
+ if (boundName === member) {
1910
+ // An alias node holds the specifier's leading whitespace, so the bare identifier
1911
+ // standing in for it takes that prefix.
1912
+ specifier.specifier = Object.assign(Object.assign({}, local), { prefix: (alias !== null && alias !== void 0 ? alias : local).prefix, simpleName: member });
1913
+ }
1914
+ else if (alias) {
1915
+ alias.propertyName.element.simpleName = member;
1916
+ local.simpleName = boundName;
1917
+ }
1918
+ else {
1919
+ specifier.specifier = aliasing(Object.assign(Object.assign({}, local), { simpleName: boundName }), member);
1920
+ }
1921
+ }
1922
+ }
1434
1923
  //# sourceMappingURL=add-import.js.map