conversion.js 16 KB

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