add exclude option, rename whitelist to include (#89)

This commit is contained in:
Henry Zhu 2016-12-13 16:16:54 -05:00 committed by GitHub
parent 0ad9b7a177
commit 45370e3553
13 changed files with 237 additions and 37 deletions

View File

@ -113,15 +113,29 @@ Can be `false` to not transform modules.
Defaults to `false`
`console.log` out the targets and plugins being used as well as the version specified in `/data/plugins.json`.
### `whitelist`: `Array<string>`
### `include`: `Array<string>`
> `whitelist` is deprecated and will be removed in the next major in favor of this.
Defaults to `[]`
Enable a whitelist of plugins to always include.
An array of plugins to always include.
Valid options include any of the [babel plugins](/data/plugin-features.js) or [built-ins](/data/built-in-features.js) such as `transform-es2015-arrow-functions` or `map`, `set`, `object.assign`.
> For the built-ins like `es6.typed.data-view` just put `typed.data-view`.
Useful if there is a bug in a native implementation, or a combination of a non-supported feature + a supported one doesn't work.
Ex: Node 4 supports native classes but not spread.
### `exclude`: `Array<string>`
Defaults to `[]`
An array of plugins to always exclude/remove.
The possible options are the same as the `include` option.
Useful for "blacklisting" a transform like `transform-regenerator` if you don't use generators and don't want to include `regeneratorRuntime` (when using `useBuiltIns`) or for using another plugin like [fast-async](https://github.com/MatAtBread/fast-async) instead of `async-to-gen`(http://babeljs.io/docs/plugins/transform-async-generator-functions/).
### `useBuiltIns`: `boolean`
Defaults to `false`.
@ -262,27 +276,22 @@ transform-async-to-generator {}
syntax-trailing-function-commas {}
```
### Example with `whitelist`
### Example with `include`/`exclude`
> always include arrow functions, explicitly blacklist generators
```js
// target chrome 52 with whitelist on arrow functions
{
"presets": [
["env", {
"targets": {
"chrome": 52
"browsers": ["last 2 versions", "safari >= 7"]
},
"whitelist": ["transform-es2015-arrow-functions"]
"include": ["transform-es2015-arrow-functions"],
"exclude": ["transform-regenerator"]
}]
]
}
Using plugins:
transform-exponentiation-operator {}
transform-async-to-generator {}
syntax-trailing-function-commas {}
transform-es2015-arrow-functions {}
```
## Caveats

View File

@ -1,4 +1,5 @@
import pluginList from "../data/plugins.json";
import pluginFeatures from "../data/plugin-features";
import builtInsList from "../data/built-ins.json";
import browserslist from "browserslist";
import transformPolyfillRequirePlugin from "./transform-polyfill-require-plugin";
@ -11,6 +12,12 @@ export const MODULE_TRANSFORMATIONS = {
"umd": "transform-es2015-modules-umd"
};
export const validIncludesAndExcludes = [
...Object.keys(pluginFeatures),
...Object.values(MODULE_TRANSFORMATIONS),
...Object.keys(builtInsList).slice(4) // remove the `es6.`
];
/**
* Determine if a transformation is required
* @param {Object} supportedEnvironments An Object containing environment keys and the lowest
@ -156,27 +163,45 @@ export const validateModulesOption = (modulesOpt = "commonjs") => {
return modulesOpt;
};
export const validateWhitelistOption = (whitelistOpt = []) => {
if (!Array.isArray(whitelistOpt)) {
throw new Error(`The 'whitelist' option must be an Array<string> of plugins
{
"presets": [
["env", {
"targets": {
"chrome": 50
},
"whitelist": ["transform-es2015-arrow-functions"]
}]
]
}
was passed "${whitelistOpt}" instead
`);
export function validatePluginsOption(opts = [], type) {
if (!Array.isArray(opts)) {
throw new Error(`The '${type}' option must be an Array<string> of plugins/built-ins`);
}
return whitelistOpt;
};
let unknownOpts = [];
opts.forEach((opt) => {
if (validIncludesAndExcludes.indexOf(opt) === -1) {
unknownOpts.push(opt);
}
});
if (unknownOpts.length > 0) {
throw new Error(`Invalid plugins/built-ins '${unknownOpts}' passed to '${type}' option.
Check data/[plugin-features|built-in-features].js in babel-preset-env`);
}
return opts;
}
const validateIncludeOption = (opts) => validatePluginsOption(opts, "include");
const validateExcludeOption = (opts) => validatePluginsOption(opts, "exclude");
export function checkDuplicateIncludeExcludes(include, exclude) {
let duplicates = [];
include.forEach((opt) => {
if (exclude.indexOf(opt) >= 0) {
duplicates.push(opt);
}
});
if (duplicates.length > 0) {
throw new Error(`Duplicate plugins/built-ins: '${duplicates}' found
in both the "include" and "exclude" options.`);
}
}
let hasBeenLogged = false;
let hasBeenWarned = false;
const logPlugin = (plugin, targets, list) => {
const envList = list[plugin];
@ -192,7 +217,15 @@ const logPlugin = (plugin, targets, list) => {
export default function buildPreset(context, opts = {}) {
const loose = validateLooseOption(opts.loose);
const moduleType = validateModulesOption(opts.modules);
const whitelist = validateWhitelistOption(opts.whitelist);
// TODO: remove whitelist in favor of include in next major
if (opts.whitelist && !hasBeenWarned) {
hasBeenWarned = true;
console.warn(`The "whitelist" option has been deprecated
in favor of "include" to match the newly added "exclude" option (instead of "blacklist").`);
}
const include = validateIncludeOption(opts.whitelist || opts.include);
const exclude = validateExcludeOption(opts.exclude);
checkDuplicateIncludeExcludes(include, exclude);
const targets = getTargets(opts.targets);
const debug = opts.debug;
const useBuiltIns = opts.useBuiltIns;
@ -226,7 +259,10 @@ export default function buildPreset(context, opts = {}) {
}
}
const allTransformations = [...transformations, ...whitelist];
const allTransformations = transformations
.filter((plugin) => exclude.indexOf(plugin) === -1)
.concat(include);
const regenerator = allTransformations.indexOf("transform-regenerator") >= 0;
const modulePlugin = moduleType !== false && MODULE_TRANSFORMATIONS[moduleType];
const plugins = [];

View File

@ -2,7 +2,7 @@ function isPolyfillSource(value) {
return value === "babel-polyfill" || value === "core-js";
}
const whitelist = [
const alwaysInclude = [
"web.timers",
"web.immediate",
"web.dom.iterable"
@ -70,7 +70,7 @@ export default function ({ types: t }) {
}
path.replaceWithMultiple(
createImports([...state.opts.polyfills, ...whitelist], "import", state.opts.regenerator)
createImports([...state.opts.polyfills, ...alwaysInclude], "import", state.opts.regenerator)
);
}
},
@ -91,7 +91,7 @@ to the "transform-polyfill-require" plugin
}
bodyPath.replaceWithMultiple(
createImports([...state.opts.polyfills, ...whitelist], "require", state.opts.regenerator)
createImports([...state.opts.polyfills, ...alwaysInclude], "require", state.opts.regenerator)
);
}
});

View File

@ -0,0 +1 @@
import "babel-polyfill";

View File

@ -0,0 +1,85 @@
import "core-js/modules/es6.typed.data-view";
import "core-js/modules/es6.typed.int8-array";
import "core-js/modules/es6.typed.uint8-array";
import "core-js/modules/es6.typed.uint8-clamped-array";
import "core-js/modules/es6.typed.int16-array";
import "core-js/modules/es6.typed.uint16-array";
import "core-js/modules/es6.typed.int32-array";
import "core-js/modules/es6.typed.uint32-array";
import "core-js/modules/es6.typed.float32-array";
import "core-js/modules/es6.typed.float64-array";
import "core-js/modules/es6.map";
import "core-js/modules/es6.set";
import "core-js/modules/es6.weak-map";
import "core-js/modules/es6.weak-set";
import "core-js/modules/es6.reflect.apply";
import "core-js/modules/es6.reflect.construct";
import "core-js/modules/es6.reflect.define-property";
import "core-js/modules/es6.reflect.delete-property";
import "core-js/modules/es6.reflect.get";
import "core-js/modules/es6.reflect.get-own-property-descriptor";
import "core-js/modules/es6.reflect.get-prototype-of";
import "core-js/modules/es6.reflect.has";
import "core-js/modules/es6.reflect.is-extensible";
import "core-js/modules/es6.reflect.own-keys";
import "core-js/modules/es6.reflect.prevent-extensions";
import "core-js/modules/es6.reflect.set";
import "core-js/modules/es6.reflect.set-prototype-of";
import "core-js/modules/es6.promise";
import "core-js/modules/es6.symbol";
import "core-js/modules/es6.object.assign";
import "core-js/modules/es6.object.is";
import "core-js/modules/es6.object.set-prototype-of";
import "core-js/modules/es6.function.name";
import "core-js/modules/es6.string.raw";
import "core-js/modules/es6.string.from-code-point";
import "core-js/modules/es6.string.code-point-at";
import "core-js/modules/es6.string.repeat";
import "core-js/modules/es6.string.starts-with";
import "core-js/modules/es6.string.ends-with";
import "core-js/modules/es6.string.includes";
import "core-js/modules/es6.regexp.flags";
import "core-js/modules/es6.regexp.match";
import "core-js/modules/es6.regexp.replace";
import "core-js/modules/es6.regexp.split";
import "core-js/modules/es6.regexp.search";
import "core-js/modules/es6.array.from";
import "core-js/modules/es6.array.of";
import "core-js/modules/es6.array.copy-within";
import "core-js/modules/es6.array.find";
import "core-js/modules/es6.array.find-index";
import "core-js/modules/es6.array.fill";
import "core-js/modules/es6.array.iterator";
import "core-js/modules/es6.number.is-finite";
import "core-js/modules/es6.number.is-integer";
import "core-js/modules/es6.number.is-safe-integer";
import "core-js/modules/es6.number.is-nan";
import "core-js/modules/es6.number.epsilon";
import "core-js/modules/es6.number.min-safe-integer";
import "core-js/modules/es6.number.max-safe-integer";
import "core-js/modules/es6.math.acosh";
import "core-js/modules/es6.math.asinh";
import "core-js/modules/es6.math.atanh";
import "core-js/modules/es6.math.cbrt";
import "core-js/modules/es6.math.clz32";
import "core-js/modules/es6.math.cosh";
import "core-js/modules/es6.math.expm1";
import "core-js/modules/es6.math.fround";
import "core-js/modules/es6.math.hypot";
import "core-js/modules/es6.math.imul";
import "core-js/modules/es6.math.log1p";
import "core-js/modules/es6.math.log10";
import "core-js/modules/es6.math.log2";
import "core-js/modules/es6.math.sign";
import "core-js/modules/es6.math.sinh";
import "core-js/modules/es6.math.tanh";
import "core-js/modules/es6.math.trunc";
import "core-js/modules/es7.array.includes.js";
import "core-js/modules/es7.object.values";
import "core-js/modules/es7.object.entries";
import "core-js/modules/es7.object.get-own-property-descriptors";
import "core-js/modules/es7.string.pad-start";
import "core-js/modules/es7.string.pad-end";
import "core-js/modules/web.timers";
import "core-js/modules/web.immediate";
import "core-js/modules/web.dom.iterable";

View File

@ -0,0 +1,9 @@
{
"presets": [
["../../../../lib", {
"modules": false,
"useBuiltIns": true,
"exclude": ["transform-regenerator"]
}]
]
}

View File

@ -0,0 +1,3 @@
async function a() {
await 1;
}

View File

@ -0,0 +1,3 @@
async function a() {
await 1;
}

View File

@ -0,0 +1,12 @@
{
"presets": [
["../../../../lib", {
"modules": false,
"useBuiltIns": true,
"exclude": [
"transform-async-to-generator",
"transform-regenerator"
]
}]
]
}

View File

@ -2,7 +2,7 @@
"presets": [
["../../../../lib", {
"targets": {},
"whitelist": ["transform-es2015-modules-commonjs"],
"include": ["transform-es2015-modules-commonjs"],
"modules": false
}]
]

View File

@ -6,7 +6,10 @@ const electronToChromiumData = require("../data/electron-to-chromium");
const {
validateModulesOption,
validateLooseOption
validateLooseOption,
validatePluginsOption,
validIncludesAndExcludes,
checkDuplicateIncludeExcludes
} = babelPresetEnv;
describe("babel-preset-env", () => {
@ -214,5 +217,44 @@ describe("babel-preset-env", () => {
assert(validateModulesOption([]));
}, Error);
});
describe("validatePluginsOption", function() {
it("should return an empty array if undefined", function() {
assert.deepEqual(validatePluginsOption(), []);
});
it("should return itself if in features", function() {
assert.deepEqual(
validatePluginsOption(validIncludesAndExcludes),
validIncludesAndExcludes
);
});
it("should throw if not in features", function() {
assert.throws(() => {
validatePluginsOption(["asdf"]);
}, Error);
});
});
describe("checkDuplicateIncludeExcludes", function() {
it("should throw if duplicate names in both", function() {
assert.throws(() => {
checkDuplicateIncludeExcludes(
["transform-regenerator", "map"],
["transform-regenerator", "map"]
);
}, Error);
});
it("should not throw if no duplicate names in both", function() {
assert.doesNotThrow(() => {
checkDuplicateIncludeExcludes(
["transform-regenerator"],
["map"]
);
}, Error);
});
});
});
});