use-built-ins-plugin.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = _default;
  6. var _builtInDefinitions = require("./built-in-definitions");
  7. var _debug = require("./debug");
  8. var _utils = require("./utils");
  9. function has(obj, key) {
  10. return Object.prototype.hasOwnProperty.call(obj, key);
  11. }
  12. function getType(target) {
  13. if (Array.isArray(target)) return "array";
  14. return typeof target;
  15. }
  16. function _default({
  17. types: t
  18. }) {
  19. function addImport(path, builtIn, builtIns) {
  20. if (builtIn && !builtIns.has(builtIn)) {
  21. builtIns.add(builtIn);
  22. (0, _utils.createImport)(path, builtIn);
  23. }
  24. }
  25. function addUnsupported(path, polyfills, builtIn, builtIns) {
  26. if (Array.isArray(builtIn)) {
  27. for (const i of builtIn) {
  28. if (polyfills.has(i)) {
  29. addImport(path, i, builtIns);
  30. }
  31. }
  32. } else {
  33. if (polyfills.has(builtIn)) {
  34. addImport(path, builtIn, builtIns);
  35. }
  36. }
  37. }
  38. const addAndRemovePolyfillImports = {
  39. ImportDeclaration(path) {
  40. if (path.node.specifiers.length === 0 && (0, _utils.isPolyfillSource)(path.node.source.value)) {
  41. console.warn(`
  42. When setting \`useBuiltIns: 'usage'\`, polyfills are automatically imported when needed.
  43. Please remove the \`import '@babel/polyfill'\` call or use \`useBuiltIns: 'entry'\` instead.`);
  44. path.remove();
  45. }
  46. },
  47. Program: {
  48. enter(path) {
  49. path.get("body").forEach(bodyPath => {
  50. if ((0, _utils.isRequire)(t, bodyPath)) {
  51. console.warn(`
  52. When setting \`useBuiltIns: 'usage'\`, polyfills are automatically imported when needed.
  53. Please remove the \`require('@babel/polyfill')\` call or use \`useBuiltIns: 'entry'\` instead.`);
  54. bodyPath.remove();
  55. }
  56. });
  57. }
  58. },
  59. ReferencedIdentifier(path, state) {
  60. const {
  61. node,
  62. parent,
  63. scope
  64. } = path;
  65. if (t.isMemberExpression(parent)) return;
  66. if (!has(_builtInDefinitions.definitions.builtins, node.name)) return;
  67. if (scope.getBindingIdentifier(node.name)) return;
  68. const builtIn = _builtInDefinitions.definitions.builtins[node.name];
  69. addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns);
  70. },
  71. CallExpression(path) {
  72. if (path.node.arguments.length) return;
  73. const callee = path.node.callee;
  74. if (!t.isMemberExpression(callee)) return;
  75. if (!callee.computed) return;
  76. if (!path.get("callee.property").matchesPattern("Symbol.iterator")) {
  77. return;
  78. }
  79. addImport(path, "web.dom.iterable", this.builtIns);
  80. },
  81. BinaryExpression(path) {
  82. if (path.node.operator !== "in") return;
  83. if (!path.get("left").matchesPattern("Symbol.iterator")) return;
  84. addImport(path, "web.dom.iterable", this.builtIns);
  85. },
  86. YieldExpression(path) {
  87. if (!path.node.delegate) return;
  88. addImport(path, "web.dom.iterable", this.builtIns);
  89. },
  90. MemberExpression: {
  91. enter(path, state) {
  92. if (!path.isReferenced()) return;
  93. const {
  94. node
  95. } = path;
  96. const obj = node.object;
  97. const prop = node.property;
  98. if (!t.isReferenced(obj, node)) return;
  99. let instanceType;
  100. let evaluatedPropType = obj.name;
  101. let propName = prop.name;
  102. if (node.computed) {
  103. if (t.isStringLiteral(prop)) {
  104. propName = prop.value;
  105. } else {
  106. const res = path.get("property").evaluate();
  107. if (res.confident && res.value) {
  108. propName = res.value;
  109. }
  110. }
  111. }
  112. if (path.scope.getBindingIdentifier(obj.name)) {
  113. const result = path.get("object").evaluate();
  114. if (result.value) {
  115. instanceType = getType(result.value);
  116. } else if (result.deopt && result.deopt.isIdentifier()) {
  117. evaluatedPropType = result.deopt.node.name;
  118. }
  119. }
  120. if (has(_builtInDefinitions.definitions.staticMethods, evaluatedPropType)) {
  121. const staticMethods = _builtInDefinitions.definitions.staticMethods[evaluatedPropType];
  122. if (has(staticMethods, propName)) {
  123. const builtIn = staticMethods[propName];
  124. addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns);
  125. }
  126. }
  127. if (has(_builtInDefinitions.definitions.instanceMethods, propName)) {
  128. let builtIn = _builtInDefinitions.definitions.instanceMethods[propName];
  129. if (instanceType) {
  130. builtIn = builtIn.filter(item => item.includes(instanceType));
  131. }
  132. addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns);
  133. }
  134. },
  135. exit(path, state) {
  136. if (!path.isReferenced()) return;
  137. const {
  138. node
  139. } = path;
  140. const obj = node.object;
  141. if (!has(_builtInDefinitions.definitions.builtins, obj.name)) return;
  142. if (path.scope.getBindingIdentifier(obj.name)) return;
  143. const builtIn = _builtInDefinitions.definitions.builtins[obj.name];
  144. addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns);
  145. }
  146. },
  147. VariableDeclarator(path, state) {
  148. if (!path.isReferenced()) return;
  149. const {
  150. node
  151. } = path;
  152. const obj = node.init;
  153. if (!t.isObjectPattern(node.id)) return;
  154. if (!t.isReferenced(obj, node)) return;
  155. if (obj && path.scope.getBindingIdentifier(obj.name)) return;
  156. for (let prop of node.id.properties) {
  157. prop = prop.key;
  158. if (!node.computed && t.isIdentifier(prop) && has(_builtInDefinitions.definitions.instanceMethods, prop.name)) {
  159. const builtIn = _builtInDefinitions.definitions.instanceMethods[prop.name];
  160. addUnsupported(path, state.opts.polyfills, builtIn, this.builtIns);
  161. }
  162. }
  163. },
  164. Function(path, state) {
  165. if (!this.usesRegenerator && (path.node.generator || path.node.async)) {
  166. this.usesRegenerator = true;
  167. if (state.opts.regenerator) {
  168. addImport(path, "regenerator-runtime", this.builtIns);
  169. }
  170. }
  171. }
  172. };
  173. return {
  174. name: "use-built-ins",
  175. pre() {
  176. this.builtIns = new Set();
  177. this.usesRegenerator = false;
  178. },
  179. post() {
  180. const {
  181. debug,
  182. onDebug
  183. } = this.opts;
  184. if (debug) {
  185. (0, _debug.logUsagePolyfills)(this.builtIns, this.file.opts.filename, onDebug);
  186. }
  187. },
  188. visitor: addAndRemovePolyfillImports
  189. };
  190. }