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