Merge pull request #125 from babel/feature/extract-option-validation
Extract option normalization into independant file
This commit is contained in:
commit
80f93f3d87
@ -45,7 +45,8 @@
|
||||
"babel-plugin-transform-es2015-unicode-regex": "^6.3.13",
|
||||
"babel-plugin-transform-exponentiation-operator": "^6.8.0",
|
||||
"babel-plugin-transform-regenerator": "^6.6.0",
|
||||
"browserslist": "^1.4.0"
|
||||
"browserslist": "^1.4.0",
|
||||
"invariant": "^2.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "^6.11.4",
|
||||
|
||||
5
experimental/babel-preset-env/src/default-includes.js
Normal file
5
experimental/babel-preset-env/src/default-includes.js
Normal file
@ -0,0 +1,5 @@
|
||||
export default [
|
||||
"web.timers",
|
||||
"web.immediate",
|
||||
"web.dom.iterable"
|
||||
];
|
||||
@ -1,29 +1,12 @@
|
||||
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";
|
||||
|
||||
import builtInsList from "../data/built-ins.json";
|
||||
import defaultInclude from "./default-includes";
|
||||
import electronToChromium from "../data/electron-to-chromium";
|
||||
|
||||
export const MODULE_TRANSFORMATIONS = {
|
||||
"amd": "transform-es2015-modules-amd",
|
||||
"commonjs": "transform-es2015-modules-commonjs",
|
||||
"systemjs": "transform-es2015-modules-systemjs",
|
||||
"umd": "transform-es2015-modules-umd"
|
||||
};
|
||||
|
||||
const defaultInclude = [
|
||||
"web.timers",
|
||||
"web.immediate",
|
||||
"web.dom.iterable"
|
||||
];
|
||||
|
||||
export const validIncludesAndExcludes = [
|
||||
...Object.keys(pluginFeatures),
|
||||
...Object.keys(MODULE_TRANSFORMATIONS).map((m) => MODULE_TRANSFORMATIONS[m]),
|
||||
...Object.keys(builtInsList),
|
||||
...defaultInclude
|
||||
];
|
||||
import moduleTransformations from "./module-transformations";
|
||||
import normalizeOptions from "./normalize-options.js";
|
||||
import pluginList from "../data/plugins.json";
|
||||
import transformPolyfillRequirePlugin from "./transform-polyfill-require-plugin";
|
||||
|
||||
/**
|
||||
* Determine if a transformation is required
|
||||
@ -51,7 +34,7 @@ export const isPluginRequired = (supportedEnvironments, plugin) => {
|
||||
const lowestTargetedVersion = supportedEnvironments[environment];
|
||||
|
||||
if (typeof lowestTargetedVersion === "string") {
|
||||
throw new Error(`Target version must be a number,
|
||||
throw new Error(`Target version must be a number,
|
||||
'${lowestTargetedVersion}' was given for '${environment}'`);
|
||||
}
|
||||
|
||||
@ -153,69 +136,7 @@ export const getTargets = (targets = {}) => {
|
||||
return targetOps;
|
||||
};
|
||||
|
||||
// TODO: Allow specifying plugins as either shortened or full name
|
||||
// babel-plugin-transform-es2015-classes
|
||||
// transform-es2015-classes
|
||||
export const validateLooseOption = (looseOpt = false) => {
|
||||
if (typeof looseOpt !== "boolean") {
|
||||
throw new Error("Preset env: 'loose' option must be a boolean.");
|
||||
}
|
||||
|
||||
return looseOpt;
|
||||
};
|
||||
|
||||
export const validateModulesOption = (modulesOpt = "commonjs") => {
|
||||
if (modulesOpt !== false && Object.keys(MODULE_TRANSFORMATIONS).indexOf(modulesOpt) === -1) {
|
||||
throw new Error("The 'modules' option must be 'false' to indicate no modules\n" +
|
||||
"or a module type which be be one of: 'commonjs' (default), 'amd', 'umd', 'systemjs'");
|
||||
}
|
||||
|
||||
return modulesOpt;
|
||||
};
|
||||
|
||||
export function validatePluginsOption(opts = [], type) {
|
||||
if (!Array.isArray(opts)) {
|
||||
throw new Error(`The '${type}' option must be an Array<string> of plugins/built-ins`);
|
||||
}
|
||||
|
||||
const 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 {
|
||||
all: opts,
|
||||
plugins: opts.filter((opt) => !opt.match(/^(es\d+|web)\./)),
|
||||
builtIns: opts.filter((opt) => opt.match(/^(es\d+|web)\./))
|
||||
};
|
||||
}
|
||||
|
||||
const validateIncludeOption = (opts) => validatePluginsOption(opts, "include");
|
||||
const validateExcludeOption = (opts) => validatePluginsOption(opts, "exclude");
|
||||
|
||||
export function checkDuplicateIncludeExcludes(include, exclude) {
|
||||
const 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] || {};
|
||||
@ -237,21 +158,19 @@ const filterItem = (targets, exclusions, list, item) => {
|
||||
return isRequired && notExcluded;
|
||||
};
|
||||
|
||||
export const transformIncludesAndExculdes = (opts) => ({
|
||||
all: opts,
|
||||
plugins: opts.filter((opt) => !opt.match(/^(es\d+|web)\./)),
|
||||
builtIns: opts.filter((opt) => opt.match(/^(es\d+|web)\./))
|
||||
});
|
||||
|
||||
export default function buildPreset(context, opts = {}) {
|
||||
const loose = validateLooseOption(opts.loose);
|
||||
const moduleType = validateModulesOption(opts.modules);
|
||||
// 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.all, exclude.all);
|
||||
const targets = getTargets(opts.targets);
|
||||
const debug = opts.debug;
|
||||
const useBuiltIns = opts.useBuiltIns;
|
||||
const validatedOptions = normalizeOptions(opts);
|
||||
const {debug, loose, moduleType, useBuiltIns} = validatedOptions;
|
||||
|
||||
const targets = getTargets(validatedOptions.targets);
|
||||
const include = transformIncludesAndExculdes(validatedOptions.include);
|
||||
const exclude = transformIncludesAndExculdes(validatedOptions.exclude);
|
||||
|
||||
const filterPlugins = filterItem.bind(null, targets, exclude.plugins, pluginList);
|
||||
const transformations = Object.keys(pluginList)
|
||||
@ -287,7 +206,7 @@ export default function buildPreset(context, opts = {}) {
|
||||
}
|
||||
|
||||
const regenerator = transformations.indexOf("transform-regenerator") >= 0;
|
||||
const modulePlugin = moduleType !== false && MODULE_TRANSFORMATIONS[moduleType];
|
||||
const modulePlugin = moduleType !== false && moduleTransformations[moduleType];
|
||||
const plugins = [];
|
||||
|
||||
modulePlugin &&
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
export default {
|
||||
"amd": "transform-es2015-modules-amd",
|
||||
"commonjs": "transform-es2015-modules-commonjs",
|
||||
"systemjs": "transform-es2015-modules-systemjs",
|
||||
"umd": "transform-es2015-modules-umd"
|
||||
};
|
||||
93
experimental/babel-preset-env/src/normalize-options.js
Normal file
93
experimental/babel-preset-env/src/normalize-options.js
Normal file
@ -0,0 +1,93 @@
|
||||
import intersection from "lodash/intersection";
|
||||
import invariant from "invariant";
|
||||
|
||||
import builtInsList from "../data/built-ins.json";
|
||||
import defaultInclude from "./default-includes";
|
||||
import moduleTransformations from "./module-transformations";
|
||||
import pluginFeatures from "../data/plugin-features";
|
||||
|
||||
const hasBeenWarned = false;
|
||||
|
||||
const validIncludesAndExcludes = [
|
||||
...Object.keys(pluginFeatures),
|
||||
...Object.keys(moduleTransformations).map((m) => moduleTransformations[m]),
|
||||
...Object.keys(builtInsList),
|
||||
...defaultInclude
|
||||
];
|
||||
|
||||
export const validateIncludesAndExcludes = (opts = [], type) => {
|
||||
invariant(
|
||||
Array.isArray(opts),
|
||||
`Invalid Option: The '${type}' option must be an Array<String> of plugins/built-ins`
|
||||
);
|
||||
|
||||
const unknownOpts = opts.filter((opt) => !validIncludesAndExcludes.includes(opt));
|
||||
|
||||
invariant(
|
||||
unknownOpts.length === 0,
|
||||
`Invalid Option: The plugins/built-ins '${unknownOpts}' passed to the '${type}' option are not
|
||||
valid. Please check data/[plugin-features|built-in-features].js in babel-preset-env`
|
||||
);
|
||||
|
||||
return opts;
|
||||
};
|
||||
|
||||
export const checkDuplicateIncludeExcludes = (include = [], exclude = []) => {
|
||||
const duplicates = intersection(include, exclude);
|
||||
|
||||
invariant(
|
||||
duplicates.length === 0,
|
||||
`Invalid Option: The plugins/built-ins '${duplicates}' were found in both the "include" and
|
||||
"exclude" options.`
|
||||
);
|
||||
};
|
||||
|
||||
// TODO: Allow specifying plugins as either shortened or full name
|
||||
// babel-plugin-transform-es2015-classes
|
||||
// transform-es2015-classes
|
||||
export const validateLooseOption = (looseOpt = false) => {
|
||||
invariant(
|
||||
typeof looseOpt === "boolean",
|
||||
"Invalid Option: The 'loose' option must be a boolean."
|
||||
);
|
||||
|
||||
return looseOpt;
|
||||
};
|
||||
|
||||
export const validateModulesOption = (modulesOpt = "commonjs") => {
|
||||
invariant(
|
||||
modulesOpt === false || Object.keys(moduleTransformations).includes(modulesOpt),
|
||||
`Invalid Option: The 'modules' option must be either 'false' to indicate no modules, or a
|
||||
module type which can be be one of: 'commonjs' (default), 'amd', 'umd', 'systemjs'.`
|
||||
);
|
||||
|
||||
return modulesOpt;
|
||||
};
|
||||
|
||||
export default function normalizeOptions(opts) {
|
||||
// TODO: remove whitelist in favor of include in next major
|
||||
if (opts.whitelist && !hasBeenWarned) {
|
||||
console.warn(
|
||||
`Deprecation Warning: The "whitelist" option has been deprecated in favor of "include" to
|
||||
match the newly added "exclude" option (instead of "blacklist").`
|
||||
);
|
||||
}
|
||||
|
||||
invariant(
|
||||
!(opts.whitelist && opts.include),
|
||||
`Invalid Option: The "whitelist" and the "include" option are the same and one can be used at
|
||||
a time`
|
||||
);
|
||||
|
||||
checkDuplicateIncludeExcludes(opts.whitelist || opts.include, opts.exclude);
|
||||
|
||||
return {
|
||||
debug: opts.debug,
|
||||
exclude: validateIncludesAndExcludes(opts.exclude, "exclude"),
|
||||
include: validateIncludesAndExcludes(opts.whitelist || opts.include, "include"),
|
||||
loose: validateLooseOption(opts.loose),
|
||||
moduleType: validateModulesOption(opts.modules),
|
||||
targets: opts.targets,
|
||||
useBuiltIns: opts.useBuiltIns
|
||||
};
|
||||
}
|
||||
@ -4,13 +4,6 @@ const babelPresetEnv = require("../lib/index.js");
|
||||
const assert = require("assert");
|
||||
const electronToChromiumData = require("../data/electron-to-chromium");
|
||||
|
||||
const {
|
||||
validateModulesOption,
|
||||
validateLooseOption,
|
||||
validatePluginsOption,
|
||||
checkDuplicateIncludeExcludes
|
||||
} = babelPresetEnv;
|
||||
|
||||
describe("babel-preset-env", () => {
|
||||
describe("getTargets", () => {
|
||||
it("should return the current node version with option 'current'", function() {
|
||||
@ -173,115 +166,27 @@ describe("babel-preset-env", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("validateLooseOption", () => {
|
||||
it("`undefined` option returns false", () => {
|
||||
assert(validateLooseOption() === false);
|
||||
describe("transformIncludesAndExculdes", function() {
|
||||
it("should return in transforms array", function() {
|
||||
assert.deepEqual(
|
||||
babelPresetEnv.transformIncludesAndExculdes(["transform-es2015-arrow-functions"]),
|
||||
{
|
||||
all: ["transform-es2015-arrow-functions"],
|
||||
plugins: ["transform-es2015-arrow-functions"],
|
||||
builtIns: []
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it("`false` option returns false", () => {
|
||||
assert(validateLooseOption(false) === false);
|
||||
});
|
||||
|
||||
it("`true` option returns true", () => {
|
||||
assert(validateLooseOption(true) === true);
|
||||
});
|
||||
|
||||
it("array option is invalid", () => {
|
||||
assert.throws(() => {
|
||||
validateModulesOption([]);
|
||||
}, Error);
|
||||
});
|
||||
});
|
||||
|
||||
describe("validateModulesOption", () => {
|
||||
it("`undefined` option returns commonjs", () => {
|
||||
assert(validateModulesOption() === "commonjs");
|
||||
});
|
||||
|
||||
it("`false` option returns commonjs", () => {
|
||||
assert(validateModulesOption(false) === false);
|
||||
});
|
||||
|
||||
it("commonjs option is valid", () => {
|
||||
assert(validateModulesOption("commonjs") === "commonjs");
|
||||
});
|
||||
|
||||
it("systemjs option is valid", () => {
|
||||
assert(validateModulesOption("systemjs") === "systemjs");
|
||||
});
|
||||
|
||||
it("amd option is valid", () => {
|
||||
assert(validateModulesOption("amd") === "amd");
|
||||
});
|
||||
|
||||
it("umd option is valid", () => {
|
||||
assert(validateModulesOption("umd") === "umd");
|
||||
});
|
||||
|
||||
it("`true` option is invalid", () => {
|
||||
assert.throws(() => {
|
||||
validateModulesOption(true);
|
||||
}, Error);
|
||||
});
|
||||
|
||||
it("array option is invalid", () => {
|
||||
assert.throws(() => {
|
||||
assert(validateModulesOption([]));
|
||||
}, Error);
|
||||
});
|
||||
|
||||
describe("validatePluginsOption", function() {
|
||||
it("should return empty arrays if undefined", function() {
|
||||
assert.deepEqual(validatePluginsOption(), { all: [], plugins: [], builtIns: [] });
|
||||
});
|
||||
|
||||
it("should return in transforms array", function() {
|
||||
assert.deepEqual(
|
||||
validatePluginsOption(["transform-es2015-arrow-functions"]),
|
||||
{
|
||||
all: ["transform-es2015-arrow-functions"],
|
||||
plugins: ["transform-es2015-arrow-functions"],
|
||||
builtIns: []
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it("should return in built-ins array", function() {
|
||||
assert.deepEqual(
|
||||
validatePluginsOption(["es6.map"]),
|
||||
{
|
||||
all: ["es6.map"],
|
||||
plugins: [],
|
||||
builtIns: ["es6.map"]
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
it("should return in built-ins array", function() {
|
||||
assert.deepEqual(
|
||||
babelPresetEnv.transformIncludesAndExculdes(["es6.map"]),
|
||||
{
|
||||
all: ["es6.map"],
|
||||
plugins: [],
|
||||
builtIns: ["es6.map"]
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
101
experimental/babel-preset-env/test/normalize-options.spec.js
Normal file
101
experimental/babel-preset-env/test/normalize-options.spec.js
Normal file
@ -0,0 +1,101 @@
|
||||
"use strict";
|
||||
|
||||
const normalizeOptions = require("../lib/normalize-options.js");
|
||||
const assert = require("assert");
|
||||
|
||||
const {
|
||||
checkDuplicateIncludeExcludes,
|
||||
validateIncludesAndExcludes,
|
||||
validateLooseOption,
|
||||
validateModulesOption
|
||||
} = normalizeOptions;
|
||||
|
||||
describe("normalize-options", () => {
|
||||
describe("validateLooseOption", () => {
|
||||
it("`undefined` option returns false", () => {
|
||||
assert(validateLooseOption() === false);
|
||||
});
|
||||
|
||||
it("`false` option returns false", () => {
|
||||
assert(validateLooseOption(false) === false);
|
||||
});
|
||||
|
||||
it("`true` option returns true", () => {
|
||||
assert(validateLooseOption(true) === true);
|
||||
});
|
||||
|
||||
it("array option is invalid", () => {
|
||||
assert.throws(() => {
|
||||
validateLooseOption([]);
|
||||
}, 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);
|
||||
});
|
||||
});
|
||||
|
||||
describe("validateModulesOption", () => {
|
||||
it("`undefined` option returns commonjs", () => {
|
||||
assert(validateModulesOption() === "commonjs");
|
||||
});
|
||||
|
||||
it("`false` option returns commonjs", () => {
|
||||
assert(validateModulesOption(false) === false);
|
||||
});
|
||||
|
||||
it("commonjs option is valid", () => {
|
||||
assert(validateModulesOption("commonjs") === "commonjs");
|
||||
});
|
||||
|
||||
it("systemjs option is valid", () => {
|
||||
assert(validateModulesOption("systemjs") === "systemjs");
|
||||
});
|
||||
|
||||
it("amd option is valid", () => {
|
||||
assert(validateModulesOption("amd") === "amd");
|
||||
});
|
||||
|
||||
it("umd option is valid", () => {
|
||||
assert(validateModulesOption("umd") === "umd");
|
||||
});
|
||||
|
||||
it("`true` option is invalid", () => {
|
||||
assert.throws(() => {
|
||||
validateModulesOption(true);
|
||||
}, Error);
|
||||
});
|
||||
|
||||
it("array option is invalid", () => {
|
||||
assert.throws(() => {
|
||||
assert(validateModulesOption([]));
|
||||
}, Error);
|
||||
});
|
||||
});
|
||||
describe("validateIncludesAndExcludes", function() {
|
||||
it("should return empty arrays if undefined", function() {
|
||||
assert.deepEqual(validateIncludesAndExcludes(), []);
|
||||
});
|
||||
it("should throw if not in features", function() {
|
||||
assert.throws(() => {
|
||||
validateIncludesAndExcludes(["asdf"]);
|
||||
}, Error);
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user