@openrewrite/rewrite 8.91.2 → 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.
- package/dist/execution.d.ts +8 -0
- package/dist/execution.d.ts.map +1 -1
- package/dist/execution.js +31 -0
- package/dist/execution.js.map +1 -1
- package/dist/javascript/add-import.d.ts +64 -9
- package/dist/javascript/add-import.d.ts.map +1 -1
- package/dist/javascript/add-import.js +398 -71
- package/dist/javascript/add-import.js.map +1 -1
- package/dist/javascript/amd.d.ts +11 -1
- package/dist/javascript/amd.d.ts.map +1 -1
- package/dist/javascript/amd.js +43 -9
- package/dist/javascript/amd.js.map +1 -1
- package/dist/javascript/binding.d.ts +10 -2
- package/dist/javascript/binding.d.ts.map +1 -1
- package/dist/javascript/binding.js +44 -71
- package/dist/javascript/binding.js.map +1 -1
- package/dist/javascript/comparator.d.ts +2 -0
- package/dist/javascript/comparator.d.ts.map +1 -1
- package/dist/javascript/comparator.js +5 -1
- package/dist/javascript/comparator.js.map +1 -1
- package/dist/javascript/format/format.d.ts +5 -2
- package/dist/javascript/format/format.d.ts.map +1 -1
- package/dist/javascript/format/format.js +51 -11
- package/dist/javascript/format/format.js.map +1 -1
- package/dist/javascript/format/minimum-viable-spacing-visitor.d.ts +19 -0
- package/dist/javascript/format/minimum-viable-spacing-visitor.d.ts.map +1 -1
- package/dist/javascript/format/minimum-viable-spacing-visitor.js +180 -7
- package/dist/javascript/format/minimum-viable-spacing-visitor.js.map +1 -1
- package/dist/javascript/format/prettier-format.d.ts +2 -1
- package/dist/javascript/format/prettier-format.d.ts.map +1 -1
- package/dist/javascript/format/prettier-format.js +33 -23
- package/dist/javascript/format/prettier-format.js.map +1 -1
- package/dist/javascript/index.d.ts +3 -3
- package/dist/javascript/index.d.ts.map +1 -1
- package/dist/javascript/index.js +21 -1
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/parser-utils.d.ts.map +1 -1
- package/dist/javascript/parser-utils.js +5 -9
- package/dist/javascript/parser-utils.js.map +1 -1
- package/dist/javascript/parser.d.ts.map +1 -1
- package/dist/javascript/parser.js +48 -3
- package/dist/javascript/parser.js.map +1 -1
- package/dist/javascript/print.d.ts +1 -0
- package/dist/javascript/print.d.ts.map +1 -1
- package/dist/javascript/print.js +9 -0
- package/dist/javascript/print.js.map +1 -1
- package/dist/javascript/recipes/change-import.d.ts +6 -3
- package/dist/javascript/recipes/change-import.d.ts.map +1 -1
- package/dist/javascript/recipes/change-import.js +17 -277
- package/dist/javascript/recipes/change-import.js.map +1 -1
- package/dist/javascript/rpc.js +2 -0
- package/dist/javascript/rpc.js.map +1 -1
- package/dist/javascript/scope.d.ts +40 -7
- package/dist/javascript/scope.d.ts.map +1 -1
- package/dist/javascript/scope.js +182 -30
- package/dist/javascript/scope.js.map +1 -1
- package/dist/javascript/templating/bindings.js +2 -20
- package/dist/javascript/templating/bindings.js.map +1 -1
- package/dist/javascript/templating/comparator.d.ts +2 -0
- package/dist/javascript/templating/comparator.d.ts.map +1 -1
- package/dist/javascript/templating/comparator.js +25 -0
- package/dist/javascript/templating/comparator.js.map +1 -1
- package/dist/javascript/templating/engine.d.ts +5 -0
- package/dist/javascript/templating/engine.d.ts.map +1 -1
- package/dist/javascript/templating/engine.js +30 -12
- package/dist/javascript/templating/engine.js.map +1 -1
- package/dist/javascript/templating/template.d.ts.map +1 -1
- package/dist/javascript/templating/template.js +6 -0
- package/dist/javascript/templating/template.js.map +1 -1
- package/dist/javascript/templating/types.d.ts +5 -0
- package/dist/javascript/templating/types.d.ts.map +1 -1
- package/dist/javascript/tree.d.ts +1 -0
- package/dist/javascript/tree.d.ts.map +1 -1
- package/dist/javascript/tree.js.map +1 -1
- package/dist/javascript/type-mapping.d.ts.map +1 -1
- package/dist/javascript/type-mapping.js +14 -0
- package/dist/javascript/type-mapping.js.map +1 -1
- package/dist/javascript/visitor.d.ts.map +1 -1
- package/dist/javascript/visitor.js +1 -0
- package/dist/javascript/visitor.js.map +1 -1
- package/dist/parser.d.ts +6 -0
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +23 -1
- package/dist/parser.js.map +1 -1
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +5 -2
- package/dist/print.js.map +1 -1
- package/dist/rewrite-javascript-version.txt +1 -1
- package/dist/rpc/request/parse-project.d.ts +11 -1
- package/dist/rpc/request/parse-project.d.ts.map +1 -1
- package/dist/rpc/request/parse-project.js +7 -2
- package/dist/rpc/request/parse-project.js.map +1 -1
- package/dist/rpc/request/parse.d.ts +13 -1
- package/dist/rpc/request/parse.d.ts.map +1 -1
- package/dist/rpc/request/parse.js +8 -2
- package/dist/rpc/request/parse.js.map +1 -1
- package/package.json +1 -1
- package/src/execution.ts +23 -0
- package/src/javascript/add-import.ts +449 -78
- package/src/javascript/amd.ts +49 -10
- package/src/javascript/binding.ts +60 -74
- package/src/javascript/comparator.ts +6 -1
- package/src/javascript/format/format.ts +56 -12
- package/src/javascript/format/minimum-viable-spacing-visitor.ts +196 -7
- package/src/javascript/format/prettier-format.ts +35 -25
- package/src/javascript/index.ts +10 -3
- package/src/javascript/parser-utils.ts +5 -11
- package/src/javascript/parser.ts +65 -6
- package/src/javascript/print.ts +10 -0
- package/src/javascript/recipes/change-import.ts +19 -349
- package/src/javascript/rpc.ts +2 -0
- package/src/javascript/scope.ts +210 -31
- package/src/javascript/templating/bindings.ts +2 -25
- package/src/javascript/templating/comparator.ts +29 -2
- package/src/javascript/templating/engine.ts +41 -14
- package/src/javascript/templating/template.ts +6 -0
- package/src/javascript/templating/types.ts +6 -0
- package/src/javascript/tree.ts +1 -0
- package/src/javascript/type-mapping.ts +15 -0
- package/src/javascript/visitor.ts +1 -0
- package/src/parser.ts +24 -1
- package/src/print.ts +5 -2
- package/src/rpc/request/parse-project.ts +6 -2
- package/src/rpc/request/parse.ts +7 -2
|
@@ -4,7 +4,12 @@ exports.RebindImport = exports.AddImport = exports.ImportStyle = void 0;
|
|
|
4
4
|
exports.bindImport = bindImport;
|
|
5
5
|
exports.memberName = memberName;
|
|
6
6
|
exports.moduleScopeBindings = moduleScopeBindings;
|
|
7
|
+
exports.hasEsmSyntax = hasEsmSyntax;
|
|
8
|
+
exports.isCommonJs = isCommonJs;
|
|
9
|
+
exports.requiredModuleOfDeclaration = requiredModuleOfDeclaration;
|
|
7
10
|
exports.requiredModuleOf = requiredModuleOf;
|
|
11
|
+
exports.takenNames = takenNames;
|
|
12
|
+
exports.nameTaken = nameTaken;
|
|
8
13
|
exports.moduleNameOf = moduleNameOf;
|
|
9
14
|
exports.existingImportBinding = existingImportBinding;
|
|
10
15
|
const visitor_1 = require("./visitor");
|
|
@@ -15,6 +20,9 @@ const markers_1 = require("../markers");
|
|
|
15
20
|
const style_1 = require("./style");
|
|
16
21
|
const scope_1 = require("./scope");
|
|
17
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");
|
|
18
26
|
var ImportStyle;
|
|
19
27
|
(function (ImportStyle) {
|
|
20
28
|
ImportStyle[ImportStyle["ES6Named"] = 0] = "ES6Named";
|
|
@@ -75,15 +83,13 @@ function bindImport(visitor, options, refuseCreate) {
|
|
|
75
83
|
visitor.afterVisit.push(new AddImport(options, derived));
|
|
76
84
|
return derived;
|
|
77
85
|
}
|
|
78
|
-
// An import already serving this request answers it
|
|
79
|
-
//
|
|
80
|
-
//
|
|
81
|
-
|
|
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);
|
|
82
90
|
for (const binding of moduleScopeBindings(cu)) {
|
|
83
91
|
if (binding.module === module && binding.member === memberName(options.member) &&
|
|
84
|
-
binding.typeOnly === typeOnly &&
|
|
85
|
-
(options.preferredName !== undefined || anyNameAnswers(options) ||
|
|
86
|
-
binding.name === derived)) {
|
|
92
|
+
binding.typeOnly === typeOnly && scope.declaringScope(binding.name) === cu) {
|
|
87
93
|
return binding.name;
|
|
88
94
|
}
|
|
89
95
|
}
|
|
@@ -168,6 +174,62 @@ function moduleScopeBindings(cu) {
|
|
|
168
174
|
}
|
|
169
175
|
return bindings;
|
|
170
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
|
+
}
|
|
171
233
|
/** The module a `require('...')` initializer names, `undefined` for an initializer that is anything else. */
|
|
172
234
|
function requiredModule(initializer) {
|
|
173
235
|
return (initializer === null || initializer === void 0 ? void 0 : initializer.kind) === java_1.J.Kind.MethodInvocation
|
|
@@ -257,12 +319,12 @@ function importBindings(jsImport) {
|
|
|
257
319
|
return bindings;
|
|
258
320
|
}
|
|
259
321
|
/**
|
|
260
|
-
*
|
|
322
|
+
* `names`, plus those pending `AddImport`s on the `afterVisit` queue have claimed. A queued
|
|
261
323
|
* `RemoveImport` does not free one: it removes only what the file leaves unused, and binding a name
|
|
262
324
|
* it keeps is an error, where an unnecessary suffix merely reads oddly.
|
|
263
325
|
*/
|
|
264
|
-
function takenNames(
|
|
265
|
-
const taken = new Set(
|
|
326
|
+
function takenNames(names, visitor) {
|
|
327
|
+
const taken = new Set(names);
|
|
266
328
|
for (const v of visitor.afterVisit || []) {
|
|
267
329
|
if (v instanceof AddImport && v.bindingName) {
|
|
268
330
|
taken.add(v.bindingName);
|
|
@@ -270,6 +332,11 @@ function takenNames(inScope, visitor) {
|
|
|
270
332
|
}
|
|
271
333
|
return taken;
|
|
272
334
|
}
|
|
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);
|
|
339
|
+
}
|
|
273
340
|
/**
|
|
274
341
|
* The parser lifts surrogate pairs out of `valueSource` into `unicodeEscapes` and, when it does,
|
|
275
342
|
* sets `value` to the quoted source (`parser.ts` `mapLiteral`), so neither field alone is the
|
|
@@ -371,8 +438,8 @@ async function detectQuote(cu) {
|
|
|
371
438
|
if (specifierQuote) {
|
|
372
439
|
return specifierQuote;
|
|
373
440
|
}
|
|
374
|
-
const prettier = (0,
|
|
375
|
-
if (
|
|
441
|
+
const prettier = (0, prettier_format_1.getPrettierStyle)(cu);
|
|
442
|
+
if (prettier && !prettier.ignored) {
|
|
376
443
|
const singleQuote = prettier.config.singleQuote;
|
|
377
444
|
if (typeof singleQuote === 'boolean') {
|
|
378
445
|
return singleQuote ? "'" : '"';
|
|
@@ -380,6 +447,32 @@ async function detectQuote(cu) {
|
|
|
380
447
|
}
|
|
381
448
|
return double > single ? '"' : "'";
|
|
382
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
|
+
*/
|
|
383
476
|
class AddImport extends visitor_1.JavaScriptVisitor {
|
|
384
477
|
constructor(options, bindingName) {
|
|
385
478
|
var _a, _b, _c;
|
|
@@ -581,17 +674,18 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
581
674
|
return mergedCu;
|
|
582
675
|
}
|
|
583
676
|
}
|
|
584
|
-
//
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
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;
|
|
589
683
|
}
|
|
590
684
|
// Add ES6 import (handles ES6Named, ES6Namespace, ES6Default)
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
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) => {
|
|
595
689
|
// Insert the import at the appropriate position
|
|
596
690
|
// Create semicolon marker for the import statement
|
|
597
691
|
const semicolonMarkers = (0, markers_1.markers)({
|
|
@@ -638,6 +732,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
638
732
|
}
|
|
639
733
|
}
|
|
640
734
|
});
|
|
735
|
+
return formatImport(withImport, newImport.id, p);
|
|
641
736
|
}
|
|
642
737
|
/**
|
|
643
738
|
* Try to merge the new member into an existing import from the same module
|
|
@@ -673,7 +768,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
673
768
|
continue;
|
|
674
769
|
}
|
|
675
770
|
// We found a matching import with named bindings - merge into it
|
|
676
|
-
return this.produceJavaScript(compilationUnit, p, async (draft) => {
|
|
771
|
+
return formatMergedImport(await this.produceJavaScript(compilationUnit, p, async (draft) => {
|
|
677
772
|
var _a, _b, _c;
|
|
678
773
|
const namedImports = importClause.namedBindings;
|
|
679
774
|
const existingElements = namedImports.elements.elements;
|
|
@@ -733,12 +828,12 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
733
828
|
});
|
|
734
829
|
// Replace the statement in the compilation unit
|
|
735
830
|
draft.statements = compilationUnit.statements.map((s, idx) => idx === i ? Object.assign(Object.assign({}, s), { element: updatedImport }) : s);
|
|
736
|
-
});
|
|
831
|
+
}), jsImport.id, p);
|
|
737
832
|
}
|
|
738
833
|
// Case 2: Default import without named bindings - add named bindings
|
|
739
834
|
// Transform: import React from 'react' -> import React, { useState } from 'react'
|
|
740
835
|
if (importClause.name && !importClause.namedBindings) {
|
|
741
|
-
return this.produceJavaScript(compilationUnit, p, async (draft) => {
|
|
836
|
+
return formatMergedImport(await this.produceJavaScript(compilationUnit, p, async (draft) => {
|
|
742
837
|
const newSpecifier = this.createImportSpecifier();
|
|
743
838
|
// Get the spaces style for brace spacing
|
|
744
839
|
const spacesStyle = (0, style_1.getStyle)(style_1.StyleKind.SpacesStyle, compilationUnit);
|
|
@@ -774,7 +869,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
774
869
|
});
|
|
775
870
|
// Replace the statement in the compilation unit
|
|
776
871
|
draft.statements = compilationUnit.statements.map((s, idx) => idx === i ? Object.assign(Object.assign({}, s), { element: updatedImport }) : s);
|
|
777
|
-
});
|
|
872
|
+
}), jsImport.id, p);
|
|
778
873
|
}
|
|
779
874
|
}
|
|
780
875
|
}
|
|
@@ -1076,10 +1171,8 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
1076
1171
|
var _a;
|
|
1077
1172
|
// Determine the appropriate prefix (spacing before the import)
|
|
1078
1173
|
const prefix = this.determineImportPrefix(compilationUnit, insertionIndex);
|
|
1079
|
-
//
|
|
1080
|
-
//
|
|
1081
|
-
// For regular imports with import clause, use emptySpace since space comes from LeftPadded.before
|
|
1082
|
-
// 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.
|
|
1083
1176
|
// Note: value is the unquoted module name; valueSource and unicodeEscapes are its printed form
|
|
1084
1177
|
let valueSource = this.moduleValueSource;
|
|
1085
1178
|
if (valueSource === undefined) {
|
|
@@ -1089,7 +1182,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
1089
1182
|
const moduleSpecifier = {
|
|
1090
1183
|
id: (0, uuid_1.randomId)(),
|
|
1091
1184
|
kind: java_1.J.Kind.Literal,
|
|
1092
|
-
prefix:
|
|
1185
|
+
prefix: java_1.singleSpace,
|
|
1093
1186
|
markers: markers_1.emptyMarkers,
|
|
1094
1187
|
value: this.module,
|
|
1095
1188
|
valueSource,
|
|
@@ -1126,7 +1219,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
1126
1219
|
const namespaceBinding = {
|
|
1127
1220
|
id: (0, uuid_1.randomId)(),
|
|
1128
1221
|
kind: tree_1.JS.Kind.Alias,
|
|
1129
|
-
prefix: java_1.singleSpace,
|
|
1222
|
+
prefix: this.typeOnly ? java_1.singleSpace : java_1.emptySpace,
|
|
1130
1223
|
markers: markers_1.emptyMarkers,
|
|
1131
1224
|
propertyName: (0, java_1.rightPadded)(propertyName, java_1.singleSpace),
|
|
1132
1225
|
alias: aliasIdentifier
|
|
@@ -1134,7 +1227,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
1134
1227
|
importClause = {
|
|
1135
1228
|
id: (0, uuid_1.randomId)(),
|
|
1136
1229
|
kind: tree_1.JS.Kind.ImportClause,
|
|
1137
|
-
prefix:
|
|
1230
|
+
prefix: java_1.singleSpace,
|
|
1138
1231
|
markers: markers_1.emptyMarkers,
|
|
1139
1232
|
typeOnly: this.typeOnly,
|
|
1140
1233
|
name: undefined,
|
|
@@ -1147,7 +1240,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
1147
1240
|
const defaultName = {
|
|
1148
1241
|
id: (0, uuid_1.randomId)(),
|
|
1149
1242
|
kind: java_1.J.Kind.Identifier,
|
|
1150
|
-
prefix: java_1.singleSpace,
|
|
1243
|
+
prefix: this.typeOnly ? java_1.singleSpace : java_1.emptySpace,
|
|
1151
1244
|
markers: markers_1.emptyMarkers,
|
|
1152
1245
|
annotations: [],
|
|
1153
1246
|
simpleName: this.bindingName,
|
|
@@ -1157,10 +1250,10 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
1157
1250
|
importClause = {
|
|
1158
1251
|
id: (0, uuid_1.randomId)(),
|
|
1159
1252
|
kind: tree_1.JS.Kind.ImportClause,
|
|
1160
|
-
prefix:
|
|
1253
|
+
prefix: java_1.singleSpace,
|
|
1161
1254
|
markers: markers_1.emptyMarkers,
|
|
1162
1255
|
typeOnly: this.typeOnly,
|
|
1163
|
-
name: (0, java_1.rightPadded)(defaultName, java_1.
|
|
1256
|
+
name: (0, java_1.rightPadded)(defaultName, java_1.singleSpace),
|
|
1164
1257
|
namedBindings: undefined
|
|
1165
1258
|
};
|
|
1166
1259
|
}
|
|
@@ -1176,11 +1269,11 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
1176
1269
|
const namedImports = {
|
|
1177
1270
|
id: (0, uuid_1.randomId)(),
|
|
1178
1271
|
kind: tree_1.JS.Kind.NamedImports,
|
|
1179
|
-
prefix: java_1.
|
|
1272
|
+
prefix: java_1.emptySpace,
|
|
1180
1273
|
markers: markers_1.emptyMarkers,
|
|
1181
1274
|
elements: {
|
|
1182
1275
|
kind: java_1.J.Kind.Container,
|
|
1183
|
-
before: java_1.emptySpace,
|
|
1276
|
+
before: this.typeOnly ? java_1.singleSpace : java_1.emptySpace,
|
|
1184
1277
|
elements: [(0, java_1.rightPadded)(importSpecWithSpacing, braceSpace)],
|
|
1185
1278
|
markers: markers_1.emptyMarkers
|
|
1186
1279
|
}
|
|
@@ -1188,7 +1281,7 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
1188
1281
|
importClause = {
|
|
1189
1282
|
id: (0, uuid_1.randomId)(),
|
|
1190
1283
|
kind: tree_1.JS.Kind.ImportClause,
|
|
1191
|
-
prefix:
|
|
1284
|
+
prefix: java_1.singleSpace,
|
|
1192
1285
|
markers: markers_1.emptyMarkers,
|
|
1193
1286
|
typeOnly: this.typeOnly,
|
|
1194
1287
|
name: undefined,
|
|
@@ -1204,7 +1297,9 @@ class AddImport extends visitor_1.JavaScriptVisitor {
|
|
|
1204
1297
|
importClause,
|
|
1205
1298
|
moduleSpecifier: {
|
|
1206
1299
|
kind: java_1.J.Kind.LeftPadded,
|
|
1207
|
-
before
|
|
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,
|
|
1208
1303
|
element: moduleSpecifier,
|
|
1209
1304
|
markers: markers_1.emptyMarkers
|
|
1210
1305
|
},
|
|
@@ -1426,15 +1521,20 @@ function existingImportBinding(cu, module, member) {
|
|
|
1426
1521
|
}
|
|
1427
1522
|
const localName = importBinds(element, module, member);
|
|
1428
1523
|
if (localName !== undefined) {
|
|
1429
|
-
return {
|
|
1524
|
+
return {
|
|
1525
|
+
localName,
|
|
1526
|
+
onlyMemberOfStatement: isOnlyMember(element),
|
|
1527
|
+
aliased: localName !== memberName(member)
|
|
1528
|
+
};
|
|
1430
1529
|
}
|
|
1431
1530
|
}
|
|
1432
1531
|
return undefined;
|
|
1433
1532
|
}
|
|
1434
1533
|
/**
|
|
1435
|
-
*
|
|
1436
|
-
*
|
|
1437
|
-
* takes its prefix: that whitespace separates the specifier
|
|
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.
|
|
1438
1538
|
*/
|
|
1439
1539
|
function aliasing(local, member) {
|
|
1440
1540
|
const propertyName = {
|
|
@@ -1514,22 +1614,29 @@ function removeBinding(jsImport, member) {
|
|
|
1514
1614
|
return Object.assign(Object.assign({}, jsImport), { importClause: Object.assign(Object.assign({}, importClause), { namedBindings: updatedNamedImports }) });
|
|
1515
1615
|
}
|
|
1516
1616
|
/**
|
|
1517
|
-
* Moves the binding `from` names to `to`,
|
|
1518
|
-
*
|
|
1519
|
-
* directly; otherwise the old specifier drops and {@link bindImport} queues the replacement
|
|
1520
|
-
*
|
|
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.
|
|
1521
1621
|
*
|
|
1522
1622
|
* Not built on `RemoveImport`/`maybeUnbind`: those only drop a binding once nothing references
|
|
1523
1623
|
* it, but a rebind moves one that is still in use — removal here has to be unconditional.
|
|
1524
1624
|
*/
|
|
1525
1625
|
class RebindImport extends visitor_1.JavaScriptVisitor {
|
|
1526
|
-
constructor(from, to, localName) {
|
|
1626
|
+
constructor(from, to, localName, boundName) {
|
|
1527
1627
|
super();
|
|
1528
1628
|
this.from = from;
|
|
1529
1629
|
this.to = to;
|
|
1530
1630
|
this.localName = localName;
|
|
1631
|
+
this.boundName = boundName;
|
|
1531
1632
|
this.transformedInPlace = false;
|
|
1532
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;
|
|
1533
1640
|
}
|
|
1534
1641
|
async visitJsCompilationUnit(cu, p) {
|
|
1535
1642
|
const visited = await super.visitJsCompilationUnit(cu, p);
|
|
@@ -1537,7 +1644,7 @@ class RebindImport extends visitor_1.JavaScriptVisitor {
|
|
|
1537
1644
|
bindImport(this, {
|
|
1538
1645
|
module: this.to.module,
|
|
1539
1646
|
member: this.to.member,
|
|
1540
|
-
alias: this.
|
|
1647
|
+
alias: this.boundName,
|
|
1541
1648
|
typeOnly: this.typeOnly,
|
|
1542
1649
|
onlyIfReferenced: false
|
|
1543
1650
|
});
|
|
@@ -1548,7 +1655,9 @@ class RebindImport extends visitor_1.JavaScriptVisitor {
|
|
|
1548
1655
|
var _a, _b;
|
|
1549
1656
|
const imp = await super.visitImportDeclaration(jsImport, p);
|
|
1550
1657
|
const key = memberName(this.from.member);
|
|
1551
|
-
|
|
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) {
|
|
1552
1661
|
return imp;
|
|
1553
1662
|
}
|
|
1554
1663
|
// A moved named specifier's own inline `type` marks it type-only even where the clause
|
|
@@ -1566,31 +1675,249 @@ class RebindImport extends visitor_1.JavaScriptVisitor {
|
|
|
1566
1675
|
const originalSource = literal.valueSource || `"${this.from.module}"`;
|
|
1567
1676
|
const quoteChar = originalSource.startsWith("'") ? "'" : '"';
|
|
1568
1677
|
literal.valueSource = `${quoteChar}${this.to.module}${quoteChar}`;
|
|
1569
|
-
// A
|
|
1570
|
-
//
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
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
|
-
}
|
|
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);
|
|
1590
1683
|
}
|
|
1684
|
+
return;
|
|
1591
1685
|
}
|
|
1686
|
+
rewriteNamedSpecifier(draft.importClause, key, (_a = memberName(this.to.member)) !== null && _a !== void 0 ? _a : key, this.boundName);
|
|
1592
1687
|
});
|
|
1593
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
|
+
}
|
|
1594
1796
|
}
|
|
1595
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
|
+
}
|
|
1596
1923
|
//# sourceMappingURL=add-import.js.map
|