UNPKG

20.8 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5var helperPluginUtils = require('@babel/helper-plugin-utils');
6var core = require('@babel/core');
7
8function isPureVoid(node) {
9 return core.types.isUnaryExpression(node) && node.operator === "void" && core.types.isPureish(node.argument);
10}
11function unshiftForXStatementBody(statementPath, newStatements) {
12 statementPath.ensureBlock();
13 const {
14 scope,
15 node
16 } = statementPath;
17 const bodyScopeBindings = statementPath.get("body").scope.bindings;
18 const hasShadowedBlockScopedBindings = Object.keys(bodyScopeBindings).some(name => scope.hasBinding(name));
19 if (hasShadowedBlockScopedBindings) {
20 node.body = core.types.blockStatement([...newStatements, node.body]);
21 } else {
22 node.body.body.unshift(...newStatements);
23 }
24}
25function hasArrayRest(pattern) {
26 return pattern.elements.some(elem => core.types.isRestElement(elem));
27}
28function hasObjectRest(pattern) {
29 return pattern.properties.some(prop => core.types.isRestElement(prop));
30}
31const STOP_TRAVERSAL = {};
32const arrayUnpackVisitor = (node, ancestors, state) => {
33 if (!ancestors.length) {
34 return;
35 }
36 if (core.types.isIdentifier(node) && core.types.isReferenced(node, ancestors[ancestors.length - 1].node) && state.bindings[node.name]) {
37 state.deopt = true;
38 throw STOP_TRAVERSAL;
39 }
40};
41class DestructuringTransformer {
42 constructor(opts) {
43 this.blockHoist = void 0;
44 this.operator = void 0;
45 this.arrayRefSet = void 0;
46 this.nodes = void 0;
47 this.scope = void 0;
48 this.kind = void 0;
49 this.iterableIsArray = void 0;
50 this.arrayLikeIsIterable = void 0;
51 this.objectRestNoSymbols = void 0;
52 this.useBuiltIns = void 0;
53 this.addHelper = void 0;
54 this.blockHoist = opts.blockHoist;
55 this.operator = opts.operator;
56 this.arrayRefSet = new Set();
57 this.nodes = opts.nodes || [];
58 this.scope = opts.scope;
59 this.kind = opts.kind;
60 this.iterableIsArray = opts.iterableIsArray;
61 this.arrayLikeIsIterable = opts.arrayLikeIsIterable;
62 this.objectRestNoSymbols = opts.objectRestNoSymbols;
63 this.useBuiltIns = opts.useBuiltIns;
64 this.addHelper = opts.addHelper;
65 }
66 getExtendsHelper() {
67 return this.useBuiltIns ? core.types.memberExpression(core.types.identifier("Object"), core.types.identifier("assign")) : this.addHelper("extends");
68 }
69 buildVariableAssignment(id, init) {
70 let op = this.operator;
71 if (core.types.isMemberExpression(id)) op = "=";
72 let node;
73 if (op) {
74 node = core.types.expressionStatement(core.types.assignmentExpression(op, id, core.types.cloneNode(init) || this.scope.buildUndefinedNode()));
75 } else {
76 let nodeInit;
77 if ((this.kind === "const" || this.kind === "using") && init === null) {
78 nodeInit = this.scope.buildUndefinedNode();
79 } else {
80 nodeInit = core.types.cloneNode(init);
81 }
82 node = core.types.variableDeclaration(this.kind, [core.types.variableDeclarator(id, nodeInit)]);
83 }
84 node._blockHoist = this.blockHoist;
85 return node;
86 }
87 buildVariableDeclaration(id, init) {
88 const declar = core.types.variableDeclaration("var", [core.types.variableDeclarator(core.types.cloneNode(id), core.types.cloneNode(init))]);
89 declar._blockHoist = this.blockHoist;
90 return declar;
91 }
92 push(id, _init) {
93 const init = core.types.cloneNode(_init);
94 if (core.types.isObjectPattern(id)) {
95 this.pushObjectPattern(id, init);
96 } else if (core.types.isArrayPattern(id)) {
97 this.pushArrayPattern(id, init);
98 } else if (core.types.isAssignmentPattern(id)) {
99 this.pushAssignmentPattern(id, init);
100 } else {
101 this.nodes.push(this.buildVariableAssignment(id, init));
102 }
103 }
104 toArray(node, count) {
105 if (this.iterableIsArray || core.types.isIdentifier(node) && this.arrayRefSet.has(node.name)) {
106 return node;
107 } else {
108 return this.scope.toArray(node, count, this.arrayLikeIsIterable);
109 }
110 }
111 pushAssignmentPattern({
112 left,
113 right
114 }, valueRef) {
115 if (isPureVoid(valueRef)) {
116 this.push(left, right);
117 return;
118 }
119 const tempId = this.scope.generateUidIdentifierBasedOnNode(valueRef);
120 this.nodes.push(this.buildVariableDeclaration(tempId, valueRef));
121 const tempConditional = core.types.conditionalExpression(core.types.binaryExpression("===", core.types.cloneNode(tempId), this.scope.buildUndefinedNode()), right, core.types.cloneNode(tempId));
122 if (core.types.isPattern(left)) {
123 let patternId;
124 let node;
125 if (this.kind === "const" || this.kind === "let" || this.kind === "using") {
126 patternId = this.scope.generateUidIdentifier(tempId.name);
127 node = this.buildVariableDeclaration(patternId, tempConditional);
128 } else {
129 patternId = tempId;
130 node = core.types.expressionStatement(core.types.assignmentExpression("=", core.types.cloneNode(tempId), tempConditional));
131 }
132 this.nodes.push(node);
133 this.push(left, patternId);
134 } else {
135 this.nodes.push(this.buildVariableAssignment(left, tempConditional));
136 }
137 }
138 pushObjectRest(pattern, objRef, spreadProp, spreadPropIndex) {
139 const value = buildObjectExcludingKeys(pattern.properties.slice(0, spreadPropIndex), objRef, this.scope, name => this.addHelper(name), this.objectRestNoSymbols, this.useBuiltIns);
140 this.nodes.push(this.buildVariableAssignment(spreadProp.argument, value));
141 }
142 pushObjectProperty(prop, propRef) {
143 if (core.types.isLiteral(prop.key)) prop.computed = true;
144 const pattern = prop.value;
145 const objRef = core.types.memberExpression(core.types.cloneNode(propRef), prop.key, prop.computed);
146 if (core.types.isPattern(pattern)) {
147 this.push(pattern, objRef);
148 } else {
149 this.nodes.push(this.buildVariableAssignment(pattern, objRef));
150 }
151 }
152 pushObjectPattern(pattern, objRef) {
153 if (!pattern.properties.length) {
154 this.nodes.push(core.types.expressionStatement(core.types.callExpression(this.addHelper("objectDestructuringEmpty"), isPureVoid(objRef) ? [] : [objRef])));
155 return;
156 }
157 if (pattern.properties.length > 1 && !this.scope.isStatic(objRef)) {
158 const temp = this.scope.generateUidIdentifierBasedOnNode(objRef);
159 this.nodes.push(this.buildVariableDeclaration(temp, objRef));
160 objRef = temp;
161 }
162 if (hasObjectRest(pattern)) {
163 let copiedPattern;
164 for (let i = 0; i < pattern.properties.length; i++) {
165 const prop = pattern.properties[i];
166 if (core.types.isRestElement(prop)) {
167 break;
168 }
169 const key = prop.key;
170 if (prop.computed && !this.scope.isPure(key)) {
171 const name = this.scope.generateUidIdentifierBasedOnNode(key);
172 this.nodes.push(this.buildVariableDeclaration(name, key));
173 if (!copiedPattern) {
174 copiedPattern = pattern = Object.assign({}, pattern, {
175 properties: pattern.properties.slice()
176 });
177 }
178 copiedPattern.properties[i] = Object.assign({}, prop, {
179 key: name
180 });
181 }
182 }
183 }
184 for (let i = 0; i < pattern.properties.length; i++) {
185 const prop = pattern.properties[i];
186 if (core.types.isRestElement(prop)) {
187 this.pushObjectRest(pattern, objRef, prop, i);
188 } else {
189 this.pushObjectProperty(prop, objRef);
190 }
191 }
192 }
193 canUnpackArrayPattern(pattern, arr) {
194 if (!core.types.isArrayExpression(arr)) return false;
195 if (pattern.elements.length > arr.elements.length) return;
196 if (pattern.elements.length < arr.elements.length && !hasArrayRest(pattern)) {
197 return false;
198 }
199 for (const elem of pattern.elements) {
200 if (!elem) return false;
201 if (core.types.isMemberExpression(elem)) return false;
202 }
203 for (const elem of arr.elements) {
204 if (core.types.isSpreadElement(elem)) return false;
205 if (core.types.isCallExpression(elem)) return false;
206 if (core.types.isMemberExpression(elem)) return false;
207 }
208 const bindings = core.types.getBindingIdentifiers(pattern);
209 const state = {
210 deopt: false,
211 bindings
212 };
213 try {
214 core.types.traverse(arr, arrayUnpackVisitor, state);
215 } catch (e) {
216 if (e !== STOP_TRAVERSAL) throw e;
217 }
218 return !state.deopt;
219 }
220 pushUnpackedArrayPattern(pattern, arr) {
221 const holeToUndefined = el => el != null ? el : this.scope.buildUndefinedNode();
222 for (let i = 0; i < pattern.elements.length; i++) {
223 const elem = pattern.elements[i];
224 if (core.types.isRestElement(elem)) {
225 this.push(elem.argument, core.types.arrayExpression(arr.elements.slice(i).map(holeToUndefined)));
226 } else {
227 this.push(elem, holeToUndefined(arr.elements[i]));
228 }
229 }
230 }
231 pushArrayPattern(pattern, arrayRef) {
232 if (arrayRef === null) {
233 this.nodes.push(core.types.expressionStatement(core.types.callExpression(this.addHelper("objectDestructuringEmpty"), [])));
234 return;
235 }
236 if (!pattern.elements) return;
237 if (this.canUnpackArrayPattern(pattern, arrayRef)) {
238 this.pushUnpackedArrayPattern(pattern, arrayRef);
239 return;
240 }
241 const count = !hasArrayRest(pattern) && pattern.elements.length;
242 const toArray = this.toArray(arrayRef, count);
243 if (core.types.isIdentifier(toArray)) {
244 arrayRef = toArray;
245 } else {
246 arrayRef = this.scope.generateUidIdentifierBasedOnNode(arrayRef);
247 this.arrayRefSet.add(arrayRef.name);
248 this.nodes.push(this.buildVariableDeclaration(arrayRef, toArray));
249 }
250 for (let i = 0; i < pattern.elements.length; i++) {
251 const elem = pattern.elements[i];
252 if (!elem) continue;
253 let elemRef;
254 if (core.types.isRestElement(elem)) {
255 elemRef = this.toArray(arrayRef);
256 elemRef = core.types.callExpression(core.types.memberExpression(elemRef, core.types.identifier("slice")), [core.types.numericLiteral(i)]);
257 this.push(elem.argument, elemRef);
258 } else {
259 elemRef = core.types.memberExpression(arrayRef, core.types.numericLiteral(i), true);
260 this.push(elem, elemRef);
261 }
262 }
263 }
264 init(pattern, ref) {
265 if (!core.types.isArrayExpression(ref) && !core.types.isMemberExpression(ref)) {
266 const memo = this.scope.maybeGenerateMemoised(ref, true);
267 if (memo) {
268 this.nodes.push(this.buildVariableDeclaration(memo, core.types.cloneNode(ref)));
269 ref = memo;
270 }
271 }
272 this.push(pattern, ref);
273 return this.nodes;
274 }
275}
276function buildObjectExcludingKeys(excludedKeys, objRef, scope, addHelper, objectRestNoSymbols, useBuiltIns) {
277 const keys = [];
278 let allLiteral = true;
279 let hasTemplateLiteral = false;
280 for (let i = 0; i < excludedKeys.length; i++) {
281 const prop = excludedKeys[i];
282 const key = prop.key;
283 if (core.types.isIdentifier(key) && !prop.computed) {
284 keys.push(core.types.stringLiteral(key.name));
285 } else if (core.types.isTemplateLiteral(key)) {
286 keys.push(core.types.cloneNode(key));
287 hasTemplateLiteral = true;
288 } else if (core.types.isLiteral(key)) {
289 keys.push(core.types.stringLiteral(String(key.value)));
290 } else if (core.types.isPrivateName(key)) ; else {
291 keys.push(core.types.cloneNode(key));
292 allLiteral = false;
293 }
294 }
295 let value;
296 if (keys.length === 0) {
297 const extendsHelper = useBuiltIns ? core.types.memberExpression(core.types.identifier("Object"), core.types.identifier("assign")) : addHelper("extends");
298 value = core.types.callExpression(extendsHelper, [core.types.objectExpression([]), core.types.sequenceExpression([core.types.callExpression(addHelper("objectDestructuringEmpty"), [core.types.cloneNode(objRef)]), core.types.cloneNode(objRef)])]);
299 } else {
300 let keyExpression = core.types.arrayExpression(keys);
301 if (!allLiteral) {
302 keyExpression = core.types.callExpression(core.types.memberExpression(keyExpression, core.types.identifier("map")), [addHelper("toPropertyKey")]);
303 } else if (!hasTemplateLiteral && !core.types.isProgram(scope.block)) {
304 const programScope = scope.getProgramParent();
305 const id = programScope.generateUidIdentifier("excluded");
306 programScope.push({
307 id,
308 init: keyExpression,
309 kind: "const"
310 });
311 keyExpression = core.types.cloneNode(id);
312 }
313 value = core.types.callExpression(addHelper(`objectWithoutProperties${objectRestNoSymbols ? "Loose" : ""}`), [core.types.cloneNode(objRef), keyExpression]);
314 }
315 return value;
316}
317function convertVariableDeclaration(path, addHelper, arrayLikeIsIterable, iterableIsArray, objectRestNoSymbols, useBuiltIns) {
318 const {
319 node,
320 scope
321 } = path;
322 const nodeKind = node.kind;
323 const nodeLoc = node.loc;
324 const nodes = [];
325 for (let i = 0; i < node.declarations.length; i++) {
326 const declar = node.declarations[i];
327 const patternId = declar.init;
328 const pattern = declar.id;
329 const destructuring = new DestructuringTransformer({
330 blockHoist: node._blockHoist,
331 nodes: nodes,
332 scope: scope,
333 kind: node.kind,
334 iterableIsArray,
335 arrayLikeIsIterable,
336 useBuiltIns,
337 objectRestNoSymbols,
338 addHelper
339 });
340 if (core.types.isPattern(pattern)) {
341 destructuring.init(pattern, patternId);
342 if (+i !== node.declarations.length - 1) {
343 core.types.inherits(nodes[nodes.length - 1], declar);
344 }
345 } else {
346 nodes.push(core.types.inherits(destructuring.buildVariableAssignment(pattern, patternId), declar));
347 }
348 }
349 let tail = null;
350 let nodesOut = [];
351 for (const node of nodes) {
352 if (core.types.isVariableDeclaration(node)) {
353 if (tail !== null) {
354 tail.declarations.push(...node.declarations);
355 continue;
356 } else {
357 node.kind = nodeKind;
358 tail = node;
359 }
360 } else {
361 tail = null;
362 }
363 if (!node.loc) {
364 node.loc = nodeLoc;
365 }
366 nodesOut.push(node);
367 }
368 if (nodesOut.length === 2 && core.types.isVariableDeclaration(nodesOut[0]) && core.types.isExpressionStatement(nodesOut[1]) && core.types.isCallExpression(nodesOut[1].expression) && nodesOut[0].declarations.length === 1) {
369 const expr = nodesOut[1].expression;
370 expr.arguments = [nodesOut[0].declarations[0].init];
371 nodesOut = [expr];
372 } else {
373 if (core.types.isForStatement(path.parent, {
374 init: node
375 }) && !nodesOut.some(v => core.types.isVariableDeclaration(v))) {
376 for (let i = 0; i < nodesOut.length; i++) {
377 const node = nodesOut[i];
378 if (core.types.isExpressionStatement(node)) {
379 nodesOut[i] = node.expression;
380 }
381 }
382 }
383 }
384 if (nodesOut.length === 1) {
385 path.replaceWith(nodesOut[0]);
386 } else {
387 path.replaceWithMultiple(nodesOut);
388 }
389 scope.crawl();
390}
391function convertAssignmentExpression(path, addHelper, arrayLikeIsIterable, iterableIsArray, objectRestNoSymbols, useBuiltIns) {
392 const {
393 node,
394 scope,
395 parentPath
396 } = path;
397 const nodes = [];
398 const destructuring = new DestructuringTransformer({
399 operator: node.operator,
400 scope: scope,
401 nodes: nodes,
402 arrayLikeIsIterable,
403 iterableIsArray,
404 objectRestNoSymbols,
405 useBuiltIns,
406 addHelper
407 });
408 let ref;
409 if (!parentPath.isExpressionStatement() && !parentPath.isSequenceExpression() || path.isCompletionRecord()) {
410 ref = scope.generateUidIdentifierBasedOnNode(node.right, "ref");
411 nodes.push(core.types.variableDeclaration("var", [core.types.variableDeclarator(ref, node.right)]));
412 if (core.types.isArrayExpression(node.right)) {
413 destructuring.arrayRefSet.add(ref.name);
414 }
415 }
416 destructuring.init(node.left, ref || node.right);
417 if (ref) {
418 if (parentPath.isArrowFunctionExpression()) {
419 path.replaceWith(core.types.blockStatement([]));
420 nodes.push(core.types.returnStatement(core.types.cloneNode(ref)));
421 } else {
422 nodes.push(core.types.expressionStatement(core.types.cloneNode(ref)));
423 }
424 }
425 path.replaceWithMultiple(nodes);
426 scope.crawl();
427}
428
429function variableDeclarationHasPattern(node) {
430 for (const declar of node.declarations) {
431 if (core.types.isPattern(declar.id)) {
432 return true;
433 }
434 }
435 return false;
436}
437var index = helperPluginUtils.declare((api, options) => {
438 var _ref, _api$assumption, _ref2, _options$allowArrayLi, _ref3, _api$assumption2;
439 api.assertVersion(7);
440 const {
441 useBuiltIns = false
442 } = options;
443 const iterableIsArray = (_ref = (_api$assumption = api.assumption("iterableIsArray")) != null ? _api$assumption : options.loose) != null ? _ref : false;
444 const arrayLikeIsIterable = (_ref2 = (_options$allowArrayLi = options.allowArrayLike) != null ? _options$allowArrayLi : api.assumption("arrayLikeIsIterable")) != null ? _ref2 : false;
445 const objectRestNoSymbols = (_ref3 = (_api$assumption2 = api.assumption("objectRestNoSymbols")) != null ? _api$assumption2 : options.loose) != null ? _ref3 : false;
446 return {
447 name: "transform-destructuring",
448 visitor: {
449 ExportNamedDeclaration(path) {
450 const declaration = path.get("declaration");
451 if (!declaration.isVariableDeclaration()) return;
452 if (!variableDeclarationHasPattern(declaration.node)) return;
453 const specifiers = [];
454 for (const name of Object.keys(path.getOuterBindingIdentifiers())) {
455 specifiers.push(core.types.exportSpecifier(core.types.identifier(name), core.types.identifier(name)));
456 }
457 path.replaceWith(declaration.node);
458 path.insertAfter(core.types.exportNamedDeclaration(null, specifiers));
459 path.scope.crawl();
460 },
461 ForXStatement(path) {
462 const {
463 node,
464 scope
465 } = path;
466 const left = node.left;
467 if (core.types.isPattern(left)) {
468 const temp = scope.generateUidIdentifier("ref");
469 node.left = core.types.variableDeclaration("var", [core.types.variableDeclarator(temp)]);
470 path.ensureBlock();
471 const statementBody = path.node.body.body;
472 const nodes = [];
473 if (statementBody.length === 0 && path.isCompletionRecord()) {
474 nodes.unshift(core.types.expressionStatement(scope.buildUndefinedNode()));
475 }
476 nodes.unshift(core.types.expressionStatement(core.types.assignmentExpression("=", left, core.types.cloneNode(temp))));
477 unshiftForXStatementBody(path, nodes);
478 scope.crawl();
479 return;
480 }
481 if (!core.types.isVariableDeclaration(left)) return;
482 const pattern = left.declarations[0].id;
483 if (!core.types.isPattern(pattern)) return;
484 const key = scope.generateUidIdentifier("ref");
485 node.left = core.types.variableDeclaration(left.kind, [core.types.variableDeclarator(key, null)]);
486 const nodes = [];
487 const destructuring = new DestructuringTransformer({
488 kind: left.kind,
489 scope: scope,
490 nodes: nodes,
491 arrayLikeIsIterable,
492 iterableIsArray,
493 objectRestNoSymbols,
494 useBuiltIns,
495 addHelper: name => this.addHelper(name)
496 });
497 destructuring.init(pattern, key);
498 unshiftForXStatementBody(path, nodes);
499 scope.crawl();
500 },
501 CatchClause({
502 node,
503 scope
504 }) {
505 const pattern = node.param;
506 if (!core.types.isPattern(pattern)) return;
507 const ref = scope.generateUidIdentifier("ref");
508 node.param = ref;
509 const nodes = [];
510 const destructuring = new DestructuringTransformer({
511 kind: "let",
512 scope: scope,
513 nodes: nodes,
514 arrayLikeIsIterable,
515 iterableIsArray,
516 objectRestNoSymbols,
517 useBuiltIns,
518 addHelper: name => this.addHelper(name)
519 });
520 destructuring.init(pattern, ref);
521 node.body.body = [...nodes, ...node.body.body];
522 scope.crawl();
523 },
524 AssignmentExpression(path, state) {
525 if (!core.types.isPattern(path.node.left)) return;
526 convertAssignmentExpression(path, name => state.addHelper(name), arrayLikeIsIterable, iterableIsArray, objectRestNoSymbols, useBuiltIns);
527 },
528 VariableDeclaration(path, state) {
529 const {
530 node,
531 parent
532 } = path;
533 if (core.types.isForXStatement(parent)) return;
534 if (!parent || !path.container) return;
535 if (!variableDeclarationHasPattern(node)) return;
536 convertVariableDeclaration(path, name => state.addHelper(name), arrayLikeIsIterable, iterableIsArray, objectRestNoSymbols, useBuiltIns);
537 }
538 }
539 };
540});
541
542exports.buildObjectExcludingKeys = buildObjectExcludingKeys;
543exports["default"] = index;
544exports.unshiftForXStatementBody = unshiftForXStatementBody;
545//# sourceMappingURL=index.js.map