1 | "use strict";
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 | exports.toComputedKey = toComputedKey;
|
7 | exports.ensureBlock = ensureBlock;
|
8 | exports.arrowFunctionToShadowed = arrowFunctionToShadowed;
|
9 | exports.unwrapFunctionEnvironment = unwrapFunctionEnvironment;
|
10 | exports.arrowFunctionToExpression = arrowFunctionToExpression;
|
11 |
|
12 | var t = _interopRequireWildcard(require("@babel/types"));
|
13 |
|
14 | var _helperFunctionName = _interopRequireDefault(require("@babel/helper-function-name"));
|
15 |
|
16 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
17 |
|
18 | function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; }
|
19 |
|
20 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
21 |
|
22 | function toComputedKey() {
|
23 | const node = this.node;
|
24 | let key;
|
25 |
|
26 | if (this.isMemberExpression()) {
|
27 | key = node.property;
|
28 | } else if (this.isProperty() || this.isMethod()) {
|
29 | key = node.key;
|
30 | } else {
|
31 | throw new ReferenceError("todo");
|
32 | }
|
33 |
|
34 | if (!node.computed) {
|
35 | if (t.isIdentifier(key)) key = t.stringLiteral(key.name);
|
36 | }
|
37 |
|
38 | return key;
|
39 | }
|
40 |
|
41 | function ensureBlock() {
|
42 | const body = this.get("body");
|
43 | const bodyNode = body.node;
|
44 |
|
45 | if (Array.isArray(body)) {
|
46 | throw new Error("Can't convert array path to a block statement");
|
47 | }
|
48 |
|
49 | if (!bodyNode) {
|
50 | throw new Error("Can't convert node without a body");
|
51 | }
|
52 |
|
53 | if (body.isBlockStatement()) {
|
54 | return bodyNode;
|
55 | }
|
56 |
|
57 | const statements = [];
|
58 | let stringPath = "body";
|
59 | let key;
|
60 | let listKey;
|
61 |
|
62 | if (body.isStatement()) {
|
63 | listKey = "body";
|
64 | key = 0;
|
65 | statements.push(body.node);
|
66 | } else {
|
67 | stringPath += ".body.0";
|
68 |
|
69 | if (this.isFunction()) {
|
70 | key = "argument";
|
71 | statements.push(t.returnStatement(body.node));
|
72 | } else {
|
73 | key = "expression";
|
74 | statements.push(t.expressionStatement(body.node));
|
75 | }
|
76 | }
|
77 |
|
78 | this.node.body = t.blockStatement(statements);
|
79 | const parentPath = this.get(stringPath);
|
80 | body.setup(parentPath, listKey ? parentPath.node[listKey] : parentPath.node, listKey, key);
|
81 | return this.node;
|
82 | }
|
83 |
|
84 | function arrowFunctionToShadowed() {
|
85 | if (!this.isArrowFunctionExpression()) return;
|
86 | this.arrowFunctionToExpression();
|
87 | }
|
88 |
|
89 | function unwrapFunctionEnvironment() {
|
90 | if (!this.isArrowFunctionExpression() && !this.isFunctionExpression() && !this.isFunctionDeclaration()) {
|
91 | throw this.buildCodeFrameError("Can only unwrap the environment of a function.");
|
92 | }
|
93 |
|
94 | hoistFunctionEnvironment(this);
|
95 | }
|
96 |
|
97 | function arrowFunctionToExpression({
|
98 | allowInsertArrow = true,
|
99 | specCompliant = false
|
100 | } = {}) {
|
101 | if (!this.isArrowFunctionExpression()) {
|
102 | throw this.buildCodeFrameError("Cannot convert non-arrow function to a function expression.");
|
103 | }
|
104 |
|
105 | const thisBinding = hoistFunctionEnvironment(this, specCompliant, allowInsertArrow);
|
106 | this.ensureBlock();
|
107 | this.node.type = "FunctionExpression";
|
108 |
|
109 | if (specCompliant) {
|
110 | const checkBinding = thisBinding ? null : this.parentPath.scope.generateUidIdentifier("arrowCheckId");
|
111 |
|
112 | if (checkBinding) {
|
113 | this.parentPath.scope.push({
|
114 | id: checkBinding,
|
115 | init: t.objectExpression([])
|
116 | });
|
117 | }
|
118 |
|
119 | this.get("body").unshiftContainer("body", t.expressionStatement(t.callExpression(this.hub.addHelper("newArrowCheck"), [t.thisExpression(), checkBinding ? t.identifier(checkBinding.name) : t.identifier(thisBinding)])));
|
120 | this.replaceWith(t.callExpression(t.memberExpression((0, _helperFunctionName.default)(this, true) || this.node, t.identifier("bind")), [checkBinding ? t.identifier(checkBinding.name) : t.thisExpression()]));
|
121 | }
|
122 | }
|
123 |
|
124 | function hoistFunctionEnvironment(fnPath, specCompliant = false, allowInsertArrow = true) {
|
125 | const thisEnvFn = fnPath.findParent(p => {
|
126 | return p.isFunction() && !p.isArrowFunctionExpression() || p.isProgram() || p.isClassProperty({
|
127 | static: false
|
128 | });
|
129 | });
|
130 | const inConstructor = thisEnvFn && thisEnvFn.node.kind === "constructor";
|
131 |
|
132 | if (thisEnvFn.isClassProperty()) {
|
133 | throw fnPath.buildCodeFrameError("Unable to transform arrow inside class property");
|
134 | }
|
135 |
|
136 | const {
|
137 | thisPaths,
|
138 | argumentsPaths,
|
139 | newTargetPaths,
|
140 | superProps,
|
141 | superCalls
|
142 | } = getScopeInformation(fnPath);
|
143 |
|
144 | if (inConstructor && superCalls.length > 0) {
|
145 | if (!allowInsertArrow) {
|
146 | throw superCalls[0].buildCodeFrameError("Unable to handle nested super() usage in arrow");
|
147 | }
|
148 |
|
149 | const allSuperCalls = [];
|
150 | thisEnvFn.traverse({
|
151 | Function(child) {
|
152 | if (child.isArrowFunctionExpression()) return;
|
153 | child.skip();
|
154 | },
|
155 |
|
156 | ClassProperty(child) {
|
157 | child.skip();
|
158 | },
|
159 |
|
160 | CallExpression(child) {
|
161 | if (!child.get("callee").isSuper()) return;
|
162 | allSuperCalls.push(child);
|
163 | }
|
164 |
|
165 | });
|
166 | const superBinding = getSuperBinding(thisEnvFn);
|
167 | allSuperCalls.forEach(superCall => {
|
168 | const callee = t.identifier(superBinding);
|
169 | callee.loc = superCall.node.callee.loc;
|
170 | superCall.get("callee").replaceWith(callee);
|
171 | });
|
172 | }
|
173 |
|
174 | if (argumentsPaths.length > 0) {
|
175 | const argumentsBinding = getBinding(thisEnvFn, "arguments", () => t.identifier("arguments"));
|
176 | argumentsPaths.forEach(argumentsChild => {
|
177 | const argsRef = t.identifier(argumentsBinding);
|
178 | argsRef.loc = argumentsChild.node.loc;
|
179 | argumentsChild.replaceWith(argsRef);
|
180 | });
|
181 | }
|
182 |
|
183 | if (newTargetPaths.length > 0) {
|
184 | const newTargetBinding = getBinding(thisEnvFn, "newtarget", () => t.metaProperty(t.identifier("new"), t.identifier("target")));
|
185 | newTargetPaths.forEach(targetChild => {
|
186 | const targetRef = t.identifier(newTargetBinding);
|
187 | targetRef.loc = targetChild.node.loc;
|
188 | targetChild.replaceWith(targetRef);
|
189 | });
|
190 | }
|
191 |
|
192 | if (superProps.length > 0) {
|
193 | if (!allowInsertArrow) {
|
194 | throw superProps[0].buildCodeFrameError("Unable to handle nested super.prop usage");
|
195 | }
|
196 |
|
197 | const flatSuperProps = superProps.reduce((acc, superProp) => acc.concat(standardizeSuperProperty(superProp)), []);
|
198 | flatSuperProps.forEach(superProp => {
|
199 | const key = superProp.node.computed ? "" : superProp.get("property").node.name;
|
200 | const isAssignment = superProp.parentPath.isAssignmentExpression({
|
201 | left: superProp.node
|
202 | });
|
203 | const isCall = superProp.parentPath.isCallExpression({
|
204 | callee: superProp.node
|
205 | });
|
206 | const superBinding = getSuperPropBinding(thisEnvFn, isAssignment, key);
|
207 | const args = [];
|
208 |
|
209 | if (superProp.node.computed) {
|
210 | args.push(superProp.get("property").node);
|
211 | }
|
212 |
|
213 | if (isAssignment) {
|
214 | const value = superProp.parentPath.node.right;
|
215 | args.push(value);
|
216 | }
|
217 |
|
218 | const call = t.callExpression(t.identifier(superBinding), args);
|
219 |
|
220 | if (isCall) {
|
221 | superProp.parentPath.unshiftContainer("arguments", t.thisExpression());
|
222 | superProp.replaceWith(t.memberExpression(call, t.identifier("call")));
|
223 | thisPaths.push(superProp.parentPath.get("arguments.0"));
|
224 | } else if (isAssignment) {
|
225 | superProp.parentPath.replaceWith(call);
|
226 | } else {
|
227 | superProp.replaceWith(call);
|
228 | }
|
229 | });
|
230 | }
|
231 |
|
232 | let thisBinding;
|
233 |
|
234 | if (thisPaths.length > 0 || specCompliant) {
|
235 | thisBinding = getThisBinding(thisEnvFn, inConstructor);
|
236 |
|
237 | if (!specCompliant || inConstructor && hasSuperClass(thisEnvFn)) {
|
238 | thisPaths.forEach(thisChild => {
|
239 | const thisRef = thisChild.isJSX() ? t.jsxIdentifier(thisBinding) : t.identifier(thisBinding);
|
240 | thisRef.loc = thisChild.node.loc;
|
241 | thisChild.replaceWith(thisRef);
|
242 | });
|
243 | if (specCompliant) thisBinding = null;
|
244 | }
|
245 | }
|
246 |
|
247 | return thisBinding;
|
248 | }
|
249 |
|
250 | function standardizeSuperProperty(superProp) {
|
251 | if (superProp.parentPath.isAssignmentExpression() && superProp.parentPath.node.operator !== "=") {
|
252 | const assignmentPath = superProp.parentPath;
|
253 | const op = assignmentPath.node.operator.slice(0, -1);
|
254 | const value = assignmentPath.node.right;
|
255 | assignmentPath.node.operator = "=";
|
256 |
|
257 | if (superProp.node.computed) {
|
258 | const tmp = superProp.scope.generateDeclaredUidIdentifier("tmp");
|
259 | assignmentPath.get("left").replaceWith(t.memberExpression(superProp.node.object, t.assignmentExpression("=", tmp, superProp.node.property), true));
|
260 | assignmentPath.get("right").replaceWith(t.binaryExpression(op, t.memberExpression(superProp.node.object, t.identifier(tmp.name), true), value));
|
261 | } else {
|
262 | assignmentPath.get("left").replaceWith(t.memberExpression(superProp.node.object, superProp.node.property));
|
263 | assignmentPath.get("right").replaceWith(t.binaryExpression(op, t.memberExpression(superProp.node.object, t.identifier(superProp.node.property.name)), value));
|
264 | }
|
265 |
|
266 | return [assignmentPath.get("left"), assignmentPath.get("right").get("left")];
|
267 | } else if (superProp.parentPath.isUpdateExpression()) {
|
268 | const updateExpr = superProp.parentPath;
|
269 | const tmp = superProp.scope.generateDeclaredUidIdentifier("tmp");
|
270 | const computedKey = superProp.node.computed ? superProp.scope.generateDeclaredUidIdentifier("prop") : null;
|
271 | const parts = [t.assignmentExpression("=", tmp, t.memberExpression(superProp.node.object, computedKey ? t.assignmentExpression("=", computedKey, superProp.node.property) : superProp.node.property, superProp.node.computed)), t.assignmentExpression("=", t.memberExpression(superProp.node.object, computedKey ? t.identifier(computedKey.name) : superProp.node.property, superProp.node.computed), t.binaryExpression("+", t.identifier(tmp.name), t.numericLiteral(1)))];
|
272 |
|
273 | if (!superProp.parentPath.node.prefix) {
|
274 | parts.push(t.identifier(tmp.name));
|
275 | }
|
276 |
|
277 | updateExpr.replaceWith(t.sequenceExpression(parts));
|
278 | const left = updateExpr.get("expressions.0.right");
|
279 | const right = updateExpr.get("expressions.1.left");
|
280 | return [left, right];
|
281 | }
|
282 |
|
283 | return [superProp];
|
284 | }
|
285 |
|
286 | function hasSuperClass(thisEnvFn) {
|
287 | return thisEnvFn.isClassMethod() && !!thisEnvFn.parentPath.parentPath.node.superClass;
|
288 | }
|
289 |
|
290 | function getThisBinding(thisEnvFn, inConstructor) {
|
291 | return getBinding(thisEnvFn, "this", thisBinding => {
|
292 | if (!inConstructor || !hasSuperClass(thisEnvFn)) return t.thisExpression();
|
293 | const supers = new WeakSet();
|
294 | thisEnvFn.traverse({
|
295 | Function(child) {
|
296 | if (child.isArrowFunctionExpression()) return;
|
297 | child.skip();
|
298 | },
|
299 |
|
300 | ClassProperty(child) {
|
301 | child.skip();
|
302 | },
|
303 |
|
304 | CallExpression(child) {
|
305 | if (!child.get("callee").isSuper()) return;
|
306 | if (supers.has(child.node)) return;
|
307 | supers.add(child.node);
|
308 | child.replaceWithMultiple([child.node, t.assignmentExpression("=", t.identifier(thisBinding), t.identifier("this"))]);
|
309 | }
|
310 |
|
311 | });
|
312 | });
|
313 | }
|
314 |
|
315 | function getSuperBinding(thisEnvFn) {
|
316 | return getBinding(thisEnvFn, "supercall", () => {
|
317 | const argsBinding = thisEnvFn.scope.generateUidIdentifier("args");
|
318 | return t.arrowFunctionExpression([t.restElement(argsBinding)], t.callExpression(t.super(), [t.spreadElement(t.identifier(argsBinding.name))]));
|
319 | });
|
320 | }
|
321 |
|
322 | function getSuperPropBinding(thisEnvFn, isAssignment, propName) {
|
323 | const op = isAssignment ? "set" : "get";
|
324 | return getBinding(thisEnvFn, `superprop_${op}:${propName || ""}`, () => {
|
325 | const argsList = [];
|
326 | let fnBody;
|
327 |
|
328 | if (propName) {
|
329 | fnBody = t.memberExpression(t.super(), t.identifier(propName));
|
330 | } else {
|
331 | const method = thisEnvFn.scope.generateUidIdentifier("prop");
|
332 | argsList.unshift(method);
|
333 | fnBody = t.memberExpression(t.super(), t.identifier(method.name), true);
|
334 | }
|
335 |
|
336 | if (isAssignment) {
|
337 | const valueIdent = thisEnvFn.scope.generateUidIdentifier("value");
|
338 | argsList.push(valueIdent);
|
339 | fnBody = t.assignmentExpression("=", fnBody, t.identifier(valueIdent.name));
|
340 | }
|
341 |
|
342 | return t.arrowFunctionExpression(argsList, fnBody);
|
343 | });
|
344 | }
|
345 |
|
346 | function getBinding(thisEnvFn, key, init) {
|
347 | const cacheKey = "binding:" + key;
|
348 | let data = thisEnvFn.getData(cacheKey);
|
349 |
|
350 | if (!data) {
|
351 | const id = thisEnvFn.scope.generateUidIdentifier(key);
|
352 | data = id.name;
|
353 | thisEnvFn.setData(cacheKey, data);
|
354 | thisEnvFn.scope.push({
|
355 | id: id,
|
356 | init: init(data)
|
357 | });
|
358 | }
|
359 |
|
360 | return data;
|
361 | }
|
362 |
|
363 | function getScopeInformation(fnPath) {
|
364 | const thisPaths = [];
|
365 | const argumentsPaths = [];
|
366 | const newTargetPaths = [];
|
367 | const superProps = [];
|
368 | const superCalls = [];
|
369 | fnPath.traverse({
|
370 | ClassProperty(child) {
|
371 | child.skip();
|
372 | },
|
373 |
|
374 | Function(child) {
|
375 | if (child.isArrowFunctionExpression()) return;
|
376 | child.skip();
|
377 | },
|
378 |
|
379 | ThisExpression(child) {
|
380 | thisPaths.push(child);
|
381 | },
|
382 |
|
383 | JSXIdentifier(child) {
|
384 | if (child.node.name !== "this") return;
|
385 |
|
386 | if (!child.parentPath.isJSXMemberExpression({
|
387 | object: child.node
|
388 | }) && !child.parentPath.isJSXOpeningElement({
|
389 | name: child.node
|
390 | })) {
|
391 | return;
|
392 | }
|
393 |
|
394 | thisPaths.push(child);
|
395 | },
|
396 |
|
397 | CallExpression(child) {
|
398 | if (child.get("callee").isSuper()) superCalls.push(child);
|
399 | },
|
400 |
|
401 | MemberExpression(child) {
|
402 | if (child.get("object").isSuper()) superProps.push(child);
|
403 | },
|
404 |
|
405 | ReferencedIdentifier(child) {
|
406 | if (child.node.name !== "arguments") return;
|
407 | argumentsPaths.push(child);
|
408 | },
|
409 |
|
410 | MetaProperty(child) {
|
411 | if (!child.get("meta").isIdentifier({
|
412 | name: "new"
|
413 | })) return;
|
414 | if (!child.get("property").isIdentifier({
|
415 | name: "target"
|
416 | })) return;
|
417 | newTargetPaths.push(child);
|
418 | }
|
419 |
|
420 | });
|
421 | return {
|
422 | thisPaths,
|
423 | argumentsPaths,
|
424 | newTargetPaths,
|
425 | superProps,
|
426 | superCalls
|
427 | };
|
428 | } |
\ | No newline at end of file |