221 lines
6.2 KiB
JavaScript
221 lines
6.2 KiB
JavaScript
// @flow
|
|
|
|
import corejs2Polyfills from "../../../data/corejs2-built-ins.json";
|
|
import getPlatformSpecificDefaultFor from "./get-platform-specific-default";
|
|
import filterItems from "../../filter-items";
|
|
import {
|
|
BuiltIns,
|
|
StaticProperties,
|
|
InstanceProperties,
|
|
} from "./built-in-definitions";
|
|
import {
|
|
createImport,
|
|
getType,
|
|
has,
|
|
isPolyfillSource,
|
|
getImportSource,
|
|
getRequireSource,
|
|
isNamespaced,
|
|
} from "../../utils";
|
|
import { logUsagePolyfills } from "../../debug";
|
|
|
|
import type { InternalPluginOptions } from "../../types";
|
|
import type { NodePath } from "@babel/traverse";
|
|
|
|
const NO_DIRECT_POLYFILL_IMPORT = `
|
|
When setting \`useBuiltIns: 'usage'\`, polyfills are automatically imported when needed.
|
|
Please remove the \`import '@babel/polyfill'\` call or use \`useBuiltIns: 'entry'\` instead.`;
|
|
|
|
export default function(
|
|
{ types: t }: { types: Object },
|
|
{ include, exclude, polyfillTargets, debug }: InternalPluginOptions,
|
|
) {
|
|
const polyfills = filterItems(
|
|
corejs2Polyfills,
|
|
include,
|
|
exclude,
|
|
polyfillTargets,
|
|
getPlatformSpecificDefaultFor(polyfillTargets),
|
|
);
|
|
|
|
const addAndRemovePolyfillImports = {
|
|
ImportDeclaration(path: NodePath) {
|
|
if (isPolyfillSource(getImportSource(path))) {
|
|
console.warn(NO_DIRECT_POLYFILL_IMPORT);
|
|
path.remove();
|
|
}
|
|
},
|
|
|
|
Program(path: NodePath) {
|
|
path.get("body").forEach(bodyPath => {
|
|
if (isPolyfillSource(getRequireSource(bodyPath))) {
|
|
console.warn(NO_DIRECT_POLYFILL_IMPORT);
|
|
bodyPath.remove();
|
|
}
|
|
});
|
|
},
|
|
|
|
// Symbol()
|
|
// new Promise
|
|
ReferencedIdentifier({ node: { name }, parent, scope }: NodePath) {
|
|
if (t.isMemberExpression(parent)) return;
|
|
if (!has(BuiltIns, name)) return;
|
|
if (scope.getBindingIdentifier(name)) return;
|
|
|
|
const BuiltInDependencies = BuiltIns[name];
|
|
this.addUnsupported(BuiltInDependencies);
|
|
},
|
|
|
|
// arr[Symbol.iterator]()
|
|
CallExpression(path: NodePath) {
|
|
// 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;
|
|
}
|
|
|
|
this.addImport("web.dom.iterable");
|
|
},
|
|
|
|
// Symbol.iterator in arr
|
|
BinaryExpression(path: NodePath) {
|
|
if (path.node.operator !== "in") return;
|
|
if (!path.get("left").matchesPattern("Symbol.iterator")) return;
|
|
|
|
this.addImport("web.dom.iterable");
|
|
},
|
|
|
|
// yield*
|
|
YieldExpression(path: NodePath) {
|
|
if (path.node.delegate) {
|
|
this.addImport("web.dom.iterable");
|
|
}
|
|
},
|
|
|
|
// Array.from
|
|
MemberExpression: {
|
|
enter(path: NodePath) {
|
|
const { node } = path;
|
|
const { object, property } = node;
|
|
|
|
// ignore namespace
|
|
if (isNamespaced(path.get("object"))) return;
|
|
|
|
let evaluatedPropType = object.name;
|
|
let propertyName = property.name;
|
|
let instanceType = "";
|
|
|
|
if (node.computed) {
|
|
if (t.isStringLiteral(property)) {
|
|
propertyName = property.value;
|
|
} else {
|
|
const result = path.get("property").evaluate();
|
|
if (result.confident && result.value) {
|
|
propertyName = result.value;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (path.scope.getBindingIdentifier(object.name)) {
|
|
const result = path.get("object").evaluate();
|
|
if (result.value) {
|
|
instanceType = getType(result.value);
|
|
} else if (result.deopt && result.deopt.isIdentifier()) {
|
|
evaluatedPropType = result.deopt.node.name;
|
|
}
|
|
}
|
|
|
|
if (has(StaticProperties, evaluatedPropType)) {
|
|
const BuiltInProperties = StaticProperties[evaluatedPropType];
|
|
if (has(BuiltInProperties, propertyName)) {
|
|
const StaticPropertyDependencies = BuiltInProperties[propertyName];
|
|
this.addUnsupported(StaticPropertyDependencies);
|
|
}
|
|
}
|
|
|
|
if (has(InstanceProperties, propertyName)) {
|
|
let InstancePropertyDependencies = InstanceProperties[propertyName];
|
|
if (instanceType) {
|
|
InstancePropertyDependencies = InstancePropertyDependencies.filter(
|
|
module => module.includes(instanceType),
|
|
);
|
|
}
|
|
this.addUnsupported(InstancePropertyDependencies);
|
|
}
|
|
},
|
|
|
|
// Symbol.match
|
|
exit(path: NodePath) {
|
|
const { name } = path.node.object;
|
|
|
|
if (!has(BuiltIns, name)) return;
|
|
if (path.scope.getBindingIdentifier(name)) return;
|
|
|
|
const BuiltInDependencies = BuiltIns[name];
|
|
this.addUnsupported(BuiltInDependencies);
|
|
},
|
|
},
|
|
|
|
// var { repeat, startsWith } = String
|
|
VariableDeclarator(path: NodePath) {
|
|
const { node } = path;
|
|
const { id, init } = node;
|
|
|
|
if (!t.isObjectPattern(id)) return;
|
|
|
|
// doesn't reference the global
|
|
if (init && path.scope.getBindingIdentifier(init.name)) return;
|
|
|
|
for (const { key } of id.properties) {
|
|
if (
|
|
!node.computed &&
|
|
t.isIdentifier(key) &&
|
|
has(InstanceProperties, key.name)
|
|
) {
|
|
const InstancePropertyDependencies = InstanceProperties[key.name];
|
|
this.addUnsupported(InstancePropertyDependencies);
|
|
}
|
|
}
|
|
},
|
|
};
|
|
|
|
return {
|
|
name: "corejs2-usage",
|
|
pre({ path }: { path: NodePath }) {
|
|
this.polyfillsSet = new Set();
|
|
|
|
this.addImport = function(builtIn) {
|
|
if (!this.polyfillsSet.has(builtIn)) {
|
|
this.polyfillsSet.add(builtIn);
|
|
createImport(path, builtIn);
|
|
}
|
|
};
|
|
|
|
this.addUnsupported = function(builtIn) {
|
|
const modules = Array.isArray(builtIn) ? builtIn : [builtIn];
|
|
for (const module of modules) {
|
|
if (polyfills.has(module)) {
|
|
this.addImport(module);
|
|
}
|
|
}
|
|
};
|
|
},
|
|
post() {
|
|
if (debug) {
|
|
logUsagePolyfills(
|
|
this.polyfillsSet,
|
|
this.file.opts.filename,
|
|
polyfillTargets,
|
|
corejs2Polyfills,
|
|
);
|
|
}
|
|
},
|
|
visitor: addAndRemovePolyfillImports,
|
|
};
|
|
}
|