useBuiltIns uses versions of the helpers that do not import even internal polyfills from core-js. useESModules uses versions of the helpers that do not go through transform-es2015-modules-commonjs. This allows for smaller builds in module systems like webpack, as it doesn't need to preserve commonjs semantics. This includes changes to the babel-runtime build-dist script, which will build the versions of the runtime helpers to be used by combinations of useBuiltIns and useESModules.
163 lines
5.3 KiB
JavaScript
163 lines
5.3 KiB
JavaScript
import definitions from "./definitions";
|
|
|
|
export default function ({ types: t }) {
|
|
function getRuntimeModuleName(opts) {
|
|
return opts.moduleName || "babel-runtime";
|
|
}
|
|
|
|
function has(obj, key) {
|
|
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
}
|
|
|
|
const HELPER_BLACKLIST = ["interopRequireWildcard", "interopRequireDefault"];
|
|
|
|
return {
|
|
pre(file) {
|
|
const moduleName = getRuntimeModuleName(this.opts);
|
|
|
|
if (this.opts.helpers !== false) {
|
|
const baseHelpersDir = this.opts.useBuiltIns ? "helpers/builtin" : "helpers";
|
|
const helpersDir = this.opts.useESModules ? `${baseHelpersDir}/es6` : baseHelpersDir;
|
|
file.set("helperGenerator", function (name) {
|
|
if (HELPER_BLACKLIST.indexOf(name) < 0) {
|
|
return file.addImport(`${moduleName}/${helpersDir}/${name}`, "default", name);
|
|
}
|
|
});
|
|
}
|
|
|
|
if (this.opts.polyfill && this.opts.useBuiltIns) {
|
|
throw new Error("The polyfill option conflicts with useBuiltIns; use one or the other");
|
|
}
|
|
|
|
this.setDynamic("regeneratorIdentifier", function () {
|
|
return file.addImport(`${moduleName}/regenerator`, "default", "regeneratorRuntime");
|
|
});
|
|
},
|
|
|
|
visitor: {
|
|
ReferencedIdentifier(path, state) {
|
|
const { node, parent, scope } = path;
|
|
|
|
if (node.name === "regeneratorRuntime" && state.opts.regenerator !== false) {
|
|
path.replaceWith(state.get("regeneratorIdentifier"));
|
|
return;
|
|
}
|
|
|
|
if (state.opts.polyfill === false || state.opts.useBuiltIns) return;
|
|
|
|
if (t.isMemberExpression(parent)) return;
|
|
if (!has(definitions.builtins, node.name)) return;
|
|
if (scope.getBindingIdentifier(node.name)) return;
|
|
|
|
// Symbol() -> _core.Symbol(); new Promise -> new _core.Promise
|
|
const moduleName = getRuntimeModuleName(state.opts);
|
|
path.replaceWith(state.addImport(
|
|
`${moduleName}/core-js/${definitions.builtins[node.name]}`,
|
|
"default",
|
|
node.name
|
|
));
|
|
},
|
|
|
|
// arr[Symbol.iterator]() -> _core.$for.getIterator(arr)
|
|
CallExpression(path, state) {
|
|
if (state.opts.polyfill === false || state.opts.useBuiltIns) return;
|
|
|
|
// we can't compile this
|
|
if (path.node.arguments.length) return;
|
|
|
|
const callee = path.node.callee;
|
|
if (!t.isMemberExpression(callee)) return;
|
|
if (!callee.computed) return;
|
|
if (!path.get("callee.property").matchesPattern("Symbol.iterator")) return;
|
|
|
|
const moduleName = getRuntimeModuleName(state.opts);
|
|
path.replaceWith(t.callExpression(
|
|
state.addImport(
|
|
`${moduleName}/core-js/get-iterator`,
|
|
"default",
|
|
"getIterator"
|
|
),
|
|
[callee.object]
|
|
));
|
|
},
|
|
|
|
// Symbol.iterator in arr -> core.$for.isIterable(arr)
|
|
BinaryExpression(path, state) {
|
|
if (state.opts.polyfill === false || state.opts.useBuiltIns) return;
|
|
|
|
if (path.node.operator !== "in") return;
|
|
if (!path.get("left").matchesPattern("Symbol.iterator")) return;
|
|
|
|
const moduleName = getRuntimeModuleName(state.opts);
|
|
path.replaceWith(t.callExpression(
|
|
state.addImport(
|
|
`${moduleName}/core-js/is-iterable`,
|
|
"default",
|
|
"isIterable"
|
|
),
|
|
[path.node.right]
|
|
));
|
|
},
|
|
|
|
// Array.from -> _core.Array.from
|
|
MemberExpression: {
|
|
enter(path, state) {
|
|
if (state.opts.polyfill === false || state.opts.useBuiltIns) return;
|
|
if (!path.isReferenced()) return;
|
|
|
|
const { node } = path;
|
|
const obj = node.object;
|
|
const prop = node.property;
|
|
|
|
if (!t.isReferenced(obj, node)) return;
|
|
if (node.computed) return;
|
|
if (!has(definitions.methods, obj.name)) return;
|
|
|
|
const methods = definitions.methods[obj.name];
|
|
if (!has(methods, prop.name)) return;
|
|
|
|
// doesn't reference the global
|
|
if (path.scope.getBindingIdentifier(obj.name)) return;
|
|
|
|
// special case Object.defineProperty to not use core-js when using string keys
|
|
if (obj.name === "Object" && prop.name === "defineProperty" && path.parentPath.isCallExpression()) {
|
|
const call = path.parentPath.node;
|
|
if (call.arguments.length === 3 && t.isLiteral(call.arguments[1])) return;
|
|
}
|
|
|
|
const moduleName = getRuntimeModuleName(state.opts);
|
|
path.replaceWith(state.addImport(
|
|
`${moduleName}/core-js/${methods[prop.name]}`,
|
|
"default",
|
|
`${obj.name}$${prop.name}`
|
|
));
|
|
},
|
|
|
|
exit(path, state) {
|
|
if (state.opts.polyfill === false || state.opts.useBuiltIns) return;
|
|
if (!path.isReferenced()) return;
|
|
|
|
const { node } = path;
|
|
const obj = node.object;
|
|
|
|
if (!has(definitions.builtins, obj.name)) return;
|
|
if (path.scope.getBindingIdentifier(obj.name)) return;
|
|
|
|
const moduleName = getRuntimeModuleName(state.opts);
|
|
path.replaceWith(t.memberExpression(
|
|
state.addImport(
|
|
`${moduleName}/core-js/${definitions.builtins[obj.name]}`,
|
|
"default",
|
|
obj.name
|
|
),
|
|
node.property,
|
|
node.computed
|
|
));
|
|
},
|
|
},
|
|
},
|
|
};
|
|
}
|
|
|
|
export { definitions };
|