index.js 19 KB

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