304 lines
7.9 KiB
JavaScript
304 lines
7.9 KiB
JavaScript
//@flow
|
|
|
|
import semver from "semver";
|
|
import builtInsList from "../data/built-ins.json";
|
|
import { logPlugin } from "./debug";
|
|
import {
|
|
getPlatformSpecificDefaultFor,
|
|
getOptionSpecificExcludesFor,
|
|
} from "./defaults";
|
|
import moduleTransformations from "./module-transformations";
|
|
import normalizeOptions from "./normalize-options.js";
|
|
import pluginList from "../data/plugins.json";
|
|
import {
|
|
builtIns as proposalBuiltIns,
|
|
features as proposalPlugins,
|
|
pluginSyntaxMap,
|
|
} from "../data/shipped-proposals.js";
|
|
import useBuiltInsEntryPlugin from "./use-built-ins-entry-plugin";
|
|
import addUsedBuiltInsPlugin from "./use-built-ins-plugin";
|
|
import getTargets from "./targets-parser";
|
|
import availablePlugins from "./available-plugins";
|
|
import {
|
|
filterStageFromList,
|
|
prettifyTargets,
|
|
semverify,
|
|
isUnreleasedVersion,
|
|
} from "./utils";
|
|
import type { Targets } from "./types";
|
|
import { declare } from "@babel/helper-plugin-utils";
|
|
|
|
const getPlugin = (pluginName: string) => {
|
|
const plugin = availablePlugins[pluginName];
|
|
|
|
if (!plugin) {
|
|
throw new Error(
|
|
`Could not find plugin "${pluginName}". Ensure there is an entry in ./available-plugins.js for it.`,
|
|
);
|
|
}
|
|
|
|
return plugin;
|
|
};
|
|
|
|
const builtInsListWithoutProposals = filterStageFromList(
|
|
builtInsList,
|
|
proposalBuiltIns,
|
|
);
|
|
|
|
const pluginListWithoutProposals = filterStageFromList(
|
|
pluginList,
|
|
proposalPlugins,
|
|
);
|
|
|
|
export const isPluginRequired = (
|
|
supportedEnvironments: Targets,
|
|
plugin: Targets,
|
|
): boolean => {
|
|
const targetEnvironments: Array<string> = Object.keys(supportedEnvironments);
|
|
|
|
if (targetEnvironments.length === 0) {
|
|
return true;
|
|
}
|
|
|
|
const isRequiredForEnvironments: Array<string> = targetEnvironments.filter(
|
|
environment => {
|
|
// Feature is not implemented in that environment
|
|
if (!plugin[environment]) {
|
|
return true;
|
|
}
|
|
|
|
const lowestImplementedVersion: string = plugin[environment];
|
|
const lowestTargetedVersion: string = supportedEnvironments[environment];
|
|
// If targets has unreleased value as a lowest version, then don't require a plugin.
|
|
if (isUnreleasedVersion(lowestTargetedVersion, environment)) {
|
|
return false;
|
|
// Include plugin if it is supported in the unreleased environment, which wasn't specified in targets
|
|
} else if (isUnreleasedVersion(lowestImplementedVersion, environment)) {
|
|
return true;
|
|
}
|
|
|
|
if (!semver.valid(lowestTargetedVersion)) {
|
|
throw new Error(
|
|
`Invalid version passed for target "${environment}": "${lowestTargetedVersion}". ` +
|
|
"Versions must be in semver format (major.minor.patch)",
|
|
);
|
|
}
|
|
|
|
return semver.gt(
|
|
semverify(lowestImplementedVersion),
|
|
lowestTargetedVersion,
|
|
);
|
|
},
|
|
);
|
|
|
|
return isRequiredForEnvironments.length > 0;
|
|
};
|
|
|
|
const getBuiltInTargets = targets => {
|
|
const builtInTargets = {
|
|
...targets,
|
|
};
|
|
if (builtInTargets.uglify != null) {
|
|
delete builtInTargets.uglify;
|
|
}
|
|
return builtInTargets;
|
|
};
|
|
|
|
export const transformIncludesAndExcludes = (opts: Array<string>): Object => {
|
|
return opts.reduce(
|
|
(result, opt) => {
|
|
const target = opt.match(/^(es\d+|web)\./) ? "builtIns" : "plugins";
|
|
result[target].add(opt);
|
|
return result;
|
|
},
|
|
{
|
|
all: opts,
|
|
plugins: new Set(),
|
|
builtIns: new Set(),
|
|
},
|
|
);
|
|
};
|
|
|
|
const filterItems = (
|
|
list,
|
|
includes,
|
|
excludes,
|
|
targets,
|
|
defaultIncludes,
|
|
defaultExcludes,
|
|
): Set<string> => {
|
|
const result = new Set();
|
|
|
|
for (const item in list) {
|
|
if (
|
|
!excludes.has(item) &&
|
|
(isPluginRequired(targets, list[item]) || includes.has(item))
|
|
) {
|
|
result.add(item);
|
|
} else {
|
|
const shippedProposalsSyntax = pluginSyntaxMap.get(item);
|
|
|
|
if (shippedProposalsSyntax) {
|
|
result.add(shippedProposalsSyntax);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (defaultIncludes) {
|
|
defaultIncludes.forEach(item => !excludes.has(item) && result.add(item));
|
|
}
|
|
|
|
if (defaultExcludes) {
|
|
defaultExcludes.forEach(item => !includes.has(item) && result.delete(item));
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
function supportsStaticESM(caller) {
|
|
return !!(caller && caller.supportsStaticESM);
|
|
}
|
|
|
|
export default declare((api, opts) => {
|
|
api.assertVersion(7);
|
|
|
|
const {
|
|
configPath,
|
|
debug,
|
|
exclude: optionsExclude,
|
|
forceAllTransforms,
|
|
ignoreBrowserslistConfig,
|
|
include: optionsInclude,
|
|
loose,
|
|
modules,
|
|
shippedProposals,
|
|
spec,
|
|
targets: optionsTargets,
|
|
useBuiltIns,
|
|
} = normalizeOptions(opts);
|
|
// TODO: remove this in next major
|
|
let hasUglifyTarget = false;
|
|
|
|
if (optionsTargets && optionsTargets.uglify) {
|
|
hasUglifyTarget = true;
|
|
delete optionsTargets.uglify;
|
|
|
|
console.log("");
|
|
console.log("The uglify target has been deprecated. Set the top level");
|
|
console.log("option `forceAllTransforms: true` instead.");
|
|
console.log("");
|
|
}
|
|
|
|
if (optionsTargets && optionsTargets.esmodules && optionsTargets.browsers) {
|
|
console.log("");
|
|
console.log(
|
|
"@babel/preset-env: esmodules and browsers targets have been specified together.",
|
|
);
|
|
console.log(
|
|
`\`browsers\` target, \`${optionsTargets.browsers}\` will be ignored.`,
|
|
);
|
|
console.log("");
|
|
}
|
|
|
|
const targets = getTargets(optionsTargets, {
|
|
ignoreBrowserslistConfig,
|
|
configPath,
|
|
});
|
|
const include = transformIncludesAndExcludes(optionsInclude);
|
|
const exclude = transformIncludesAndExcludes(optionsExclude);
|
|
|
|
const transformTargets = forceAllTransforms || hasUglifyTarget ? {} : targets;
|
|
|
|
const transformations = filterItems(
|
|
shippedProposals ? pluginList : pluginListWithoutProposals,
|
|
include.plugins,
|
|
exclude.plugins,
|
|
transformTargets,
|
|
null,
|
|
getOptionSpecificExcludesFor({ loose }),
|
|
);
|
|
|
|
let polyfills;
|
|
let polyfillTargets;
|
|
|
|
if (useBuiltIns) {
|
|
polyfillTargets = getBuiltInTargets(targets);
|
|
|
|
polyfills = filterItems(
|
|
shippedProposals ? builtInsList : builtInsListWithoutProposals,
|
|
include.builtIns,
|
|
exclude.builtIns,
|
|
polyfillTargets,
|
|
getPlatformSpecificDefaultFor(polyfillTargets),
|
|
);
|
|
}
|
|
|
|
const plugins = [];
|
|
const pluginUseBuiltIns = useBuiltIns !== false;
|
|
|
|
if (
|
|
modules !== false &&
|
|
moduleTransformations[modules] &&
|
|
// TODO: Remove the 'api.caller' check eventually. Just here to prevent
|
|
// unnecessary breakage in the short term for users on older betas/RCs.
|
|
(modules !== "auto" || !api.caller || !api.caller(supportsStaticESM))
|
|
) {
|
|
// NOTE: not giving spec here yet to avoid compatibility issues when
|
|
// transform-modules-commonjs gets its spec mode
|
|
plugins.push([getPlugin(moduleTransformations[modules]), { loose }]);
|
|
}
|
|
|
|
transformations.forEach(pluginName =>
|
|
plugins.push([
|
|
getPlugin(pluginName),
|
|
{ spec, loose, useBuiltIns: pluginUseBuiltIns },
|
|
]),
|
|
);
|
|
|
|
const regenerator = transformations.has("transform-regenerator");
|
|
|
|
if (debug) {
|
|
console.log("@babel/preset-env: `DEBUG` option");
|
|
console.log("\nUsing targets:");
|
|
console.log(JSON.stringify(prettifyTargets(targets), null, 2));
|
|
console.log(`\nUsing modules transform: ${modules.toString()}`);
|
|
console.log("\nUsing plugins:");
|
|
transformations.forEach(transform => {
|
|
logPlugin(transform, targets, pluginList);
|
|
});
|
|
|
|
if (!useBuiltIns) {
|
|
console.log(
|
|
"\nUsing polyfills: No polyfills were added, since the `useBuiltIns` option was not set.",
|
|
);
|
|
} else {
|
|
console.log(
|
|
`
|
|
Using polyfills with \`${useBuiltIns}\` option:`,
|
|
);
|
|
}
|
|
}
|
|
|
|
if (useBuiltIns === "usage" || useBuiltIns === "entry") {
|
|
const pluginOptions = {
|
|
debug,
|
|
polyfills,
|
|
regenerator,
|
|
onDebug: (polyfills, context) => {
|
|
polyfills.forEach(polyfill =>
|
|
logPlugin(polyfill, polyfillTargets, builtInsList, context),
|
|
);
|
|
},
|
|
};
|
|
|
|
plugins.push([
|
|
useBuiltIns === "usage" ? addUsedBuiltInsPlugin : useBuiltInsEntryPlugin,
|
|
pluginOptions,
|
|
]);
|
|
}
|
|
|
|
return {
|
|
plugins,
|
|
};
|
|
});
|