Replace repeated plugins/preset in top-level config instead of running both.
This commit is contained in:
parent
8be488652f
commit
189c56628a
@ -30,13 +30,9 @@ export default function manageOptions(opts: {}): {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class OptionManager {
|
class OptionManager {
|
||||||
constructor() {
|
optionDefaults: ValidatedOptions = {};
|
||||||
this.options = {};
|
options: ValidatedOptions = {};
|
||||||
this.passes = [[]];
|
passes: Array<Array<Plugin>> = [[]];
|
||||||
}
|
|
||||||
|
|
||||||
options: ValidatedOptions;
|
|
||||||
passes: Array<Array<Plugin>>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is called when we want to merge the input `opts` into the
|
* This is called when we want to merge the input `opts` into the
|
||||||
@ -46,16 +42,23 @@ class OptionManager {
|
|||||||
* - `loc` is used to point to the original config.
|
* - `loc` is used to point to the original config.
|
||||||
* - `dirname` is used to resolve plugins relative to it.
|
* - `dirname` is used to resolve plugins relative to it.
|
||||||
*/
|
*/
|
||||||
mergeOptions(config: MergeOptions, pass: Array<Plugin>, envName: string) {
|
mergeOptions(
|
||||||
const result = loadConfig(config);
|
config: {
|
||||||
|
plugins: Array<BasicDescriptor>,
|
||||||
const plugins = result.plugins.map(descriptor =>
|
presets: Array<BasicDescriptor>,
|
||||||
|
},
|
||||||
|
pass: Array<Plugin>,
|
||||||
|
envName: string,
|
||||||
|
) {
|
||||||
|
const plugins = config.plugins.map(descriptor =>
|
||||||
loadPluginDescriptor(descriptor, envName),
|
loadPluginDescriptor(descriptor, envName),
|
||||||
);
|
);
|
||||||
const presets = result.presets.map(descriptor => ({
|
const presets = config.presets.map(descriptor => {
|
||||||
pass: descriptor.ownPass ? [] : pass,
|
return {
|
||||||
preset: loadPresetDescriptor(descriptor, envName),
|
preset: loadPresetDescriptor(descriptor, envName),
|
||||||
}));
|
pass: descriptor.ownPass ? [] : pass,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// resolve presets
|
// resolve presets
|
||||||
if (presets.length > 0) {
|
if (presets.length > 0) {
|
||||||
@ -68,7 +71,18 @@ class OptionManager {
|
|||||||
);
|
);
|
||||||
|
|
||||||
presets.forEach(({ preset, pass }) => {
|
presets.forEach(({ preset, pass }) => {
|
||||||
this.mergeOptions(preset, pass, envName);
|
const loadedConfig = loadConfig(preset);
|
||||||
|
this.mergeOptions(
|
||||||
|
{
|
||||||
|
// Call dedupDescriptors() to remove 'false' descriptors.
|
||||||
|
plugins: dedupDescriptors(loadedConfig.plugins),
|
||||||
|
presets: dedupDescriptors(loadedConfig.presets),
|
||||||
|
},
|
||||||
|
pass,
|
||||||
|
envName,
|
||||||
|
);
|
||||||
|
|
||||||
|
merge(this.optionDefaults, normalizeOptions(loadedConfig.options));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,24 +90,23 @@ class OptionManager {
|
|||||||
if (plugins.length > 0) {
|
if (plugins.length > 0) {
|
||||||
pass.unshift(...plugins);
|
pass.unshift(...plugins);
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = Object.assign({}, result.options);
|
|
||||||
delete options.extends;
|
|
||||||
delete options.env;
|
|
||||||
delete options.plugins;
|
|
||||||
delete options.presets;
|
|
||||||
delete options.passPerPreset;
|
|
||||||
delete options.ignore;
|
|
||||||
delete options.only;
|
|
||||||
|
|
||||||
// "sourceMap" is just aliased to sourceMap, so copy it over as
|
|
||||||
// we merge the options together.
|
|
||||||
if (options.sourceMap) {
|
|
||||||
options.sourceMaps = options.sourceMap;
|
|
||||||
delete options.sourceMap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
merge(this.options, options);
|
mergeConfigChain(chain: $ReadOnlyArray<MergeOptions>, envName: string) {
|
||||||
|
const config = dedupLoadedConfigs(chain.map(config => loadConfig(config)));
|
||||||
|
|
||||||
|
this.mergeOptions(
|
||||||
|
{
|
||||||
|
plugins: config.plugins,
|
||||||
|
presets: config.presets,
|
||||||
|
},
|
||||||
|
this.passes[0],
|
||||||
|
envName,
|
||||||
|
);
|
||||||
|
|
||||||
|
config.options.forEach(opts => {
|
||||||
|
merge(this.options, normalizeOptions(opts));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
init(inputOpts: {}) {
|
init(inputOpts: {}) {
|
||||||
@ -106,9 +119,7 @@ class OptionManager {
|
|||||||
if (!configChain) return null;
|
if (!configChain) return null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (const config of configChain) {
|
this.mergeConfigChain(configChain, envName);
|
||||||
this.mergeOptions(config, this.passes[0], envName);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// There are a few case where thrown errors will try to annotate themselves multiple times, so
|
// There are a few case where thrown errors will try to annotate themselves multiple times, so
|
||||||
// to keep things simple we just bail out if re-wrapping the message.
|
// to keep things simple we just bail out if re-wrapping the message.
|
||||||
@ -119,7 +130,7 @@ class OptionManager {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
const opts: Object = this.options;
|
const opts: Object = merge(this.optionDefaults, this.options);
|
||||||
|
|
||||||
// Tack the passes onto the object itself so that, if this object is passed back to Babel a second time,
|
// Tack the passes onto the object itself so that, if this object is passed back to Babel a second time,
|
||||||
// it will be in the right structure to not change behavior.
|
// it will be in the right structure to not change behavior.
|
||||||
@ -140,10 +151,29 @@ class OptionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeOptions(opts: ValidatedOptions): ValidatedOptions {
|
||||||
|
const options = Object.assign({}, opts);
|
||||||
|
delete options.extends;
|
||||||
|
delete options.env;
|
||||||
|
delete options.plugins;
|
||||||
|
delete options.presets;
|
||||||
|
delete options.passPerPreset;
|
||||||
|
delete options.ignore;
|
||||||
|
delete options.only;
|
||||||
|
|
||||||
|
// "sourceMap" is just aliased to sourceMap, so copy it over as
|
||||||
|
// we merge the options together.
|
||||||
|
if (options.sourceMap) {
|
||||||
|
options.sourceMaps = options.sourceMap;
|
||||||
|
delete options.sourceMap;
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
type BasicDescriptor = {
|
type BasicDescriptor = {
|
||||||
name: string | void,
|
name: string | void,
|
||||||
value: {} | Function,
|
value: {} | Function,
|
||||||
options: {} | void,
|
options: {} | void | false,
|
||||||
dirname: string,
|
dirname: string,
|
||||||
alias: string,
|
alias: string,
|
||||||
ownPass?: boolean,
|
ownPass?: boolean,
|
||||||
@ -156,14 +186,16 @@ type LoadedDescriptor = {
|
|||||||
alias: string,
|
alias: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type LoadedConfig = {
|
||||||
|
options: ValidatedOptions,
|
||||||
|
plugins: Array<BasicDescriptor>,
|
||||||
|
presets: Array<BasicDescriptor>,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load and validate the given config into a set of options, plugins, and presets.
|
* Load and validate the given config into a set of options, plugins, and presets.
|
||||||
*/
|
*/
|
||||||
const loadConfig = makeWeakCache((config: MergeOptions): {
|
const loadConfig = makeWeakCache((config: MergeOptions): LoadedConfig => {
|
||||||
options: {},
|
|
||||||
plugins: Array<BasicDescriptor>,
|
|
||||||
presets: Array<BasicDescriptor>,
|
|
||||||
} => {
|
|
||||||
const options = config.options;
|
const options = config.options;
|
||||||
|
|
||||||
const plugins = (config.options.plugins || []).map((plugin, index) =>
|
const plugins = (config.options.plugins || []).map((plugin, index) =>
|
||||||
@ -173,25 +205,133 @@ const loadConfig = makeWeakCache((config: MergeOptions): {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assertNoDuplicates(plugins);
|
||||||
|
|
||||||
const presets = (config.options.presets || []).map((preset, index) =>
|
const presets = (config.options.presets || []).map((preset, index) =>
|
||||||
createDescriptor(preset, loadPreset, config.dirname, {
|
createDescriptor(preset, loadPreset, config.dirname, {
|
||||||
index,
|
index,
|
||||||
alias: config.alias,
|
alias: config.alias,
|
||||||
ownPass: config.options.passPerPreset,
|
ownPass: options.passPerPreset,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
assertNoDuplicates(presets);
|
||||||
|
|
||||||
return { options, plugins, presets };
|
return { options, plugins, presets };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function assertNoDuplicates(items: Array<BasicDescriptor>): void {
|
||||||
|
const map = new Map();
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
if (typeof item.value !== "function") continue;
|
||||||
|
|
||||||
|
let nameMap = map.get(item.value);
|
||||||
|
if (!nameMap) {
|
||||||
|
nameMap = new Set();
|
||||||
|
map.set(item.value, nameMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nameMap.has(item.name)) {
|
||||||
|
throw new Error(
|
||||||
|
[
|
||||||
|
`Duplicate plugin/preset detected.`,
|
||||||
|
`If you'd like to use two separate instances of a plugin,`,
|
||||||
|
`they neen separate names, e.g.`,
|
||||||
|
``,
|
||||||
|
` plugins: [`,
|
||||||
|
` ['some-plugin', {}],`,
|
||||||
|
` ['some-plugin', {}, 'some unique name'],`,
|
||||||
|
` ]`,
|
||||||
|
].join("\n"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
nameMap.add(item.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function dedupLoadedConfigs(
|
||||||
|
items: Array<LoadedConfig>,
|
||||||
|
): {
|
||||||
|
plugins: Array<BasicDescriptor>,
|
||||||
|
presets: Array<BasicDescriptor>,
|
||||||
|
options: Array<ValidatedOptions>,
|
||||||
|
} {
|
||||||
|
const options = [];
|
||||||
|
const plugins = [];
|
||||||
|
const presets = [];
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
plugins.push(...item.plugins);
|
||||||
|
presets.push(...item.presets);
|
||||||
|
options.push(item.options);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
options,
|
||||||
|
plugins: dedupDescriptors(plugins),
|
||||||
|
presets: dedupDescriptors(presets),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function dedupDescriptors(
|
||||||
|
items: Array<BasicDescriptor>,
|
||||||
|
): Array<BasicDescriptor> {
|
||||||
|
const map: Map<
|
||||||
|
Function,
|
||||||
|
Map<string | void, { value: BasicDescriptor | null }>,
|
||||||
|
> = new Map();
|
||||||
|
|
||||||
|
const descriptors = [];
|
||||||
|
|
||||||
|
for (const item of items) {
|
||||||
|
if (typeof item.value === "function") {
|
||||||
|
const fnKey = item.value;
|
||||||
|
let nameMap = map.get(fnKey);
|
||||||
|
if (!nameMap) {
|
||||||
|
nameMap = new Map();
|
||||||
|
map.set(fnKey, nameMap);
|
||||||
|
}
|
||||||
|
let desc = nameMap.get(item.name);
|
||||||
|
if (!desc) {
|
||||||
|
desc = { value: null };
|
||||||
|
descriptors.push(desc);
|
||||||
|
|
||||||
|
// Treat passPerPreset presets as unique, skipping them
|
||||||
|
// in the merge processing steps.
|
||||||
|
if (!item.ownPass) nameMap.set(item.name, desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.options === false) {
|
||||||
|
desc.value = null;
|
||||||
|
} else {
|
||||||
|
desc.value = item;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
descriptors.push({ value: item });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return descriptors.reduce((acc, desc) => {
|
||||||
|
if (desc.value) acc.push(desc.value);
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a generic plugin/preset from the given descriptor loaded from the config object.
|
* Load a generic plugin/preset from the given descriptor loaded from the config object.
|
||||||
*/
|
*/
|
||||||
const loadDescriptor = makeWeakCache(
|
const loadDescriptor = makeWeakCache(
|
||||||
(
|
(
|
||||||
{ value, options = {}, dirname, alias }: BasicDescriptor,
|
{ value, options, dirname, alias }: BasicDescriptor,
|
||||||
cache: CacheConfigurator<{ envName: string }>,
|
cache: CacheConfigurator<{ envName: string }>,
|
||||||
): LoadedDescriptor => {
|
): LoadedDescriptor => {
|
||||||
|
// Disabled presets should already have been filtered out
|
||||||
|
if (options === false) throw new Error("Assertion failure");
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
let item = value;
|
let item = value;
|
||||||
if (typeof value === "function") {
|
if (typeof value === "function") {
|
||||||
const api = Object.assign(Object.create(context), {
|
const api = Object.assign(Object.create(context), {
|
||||||
|
|||||||
@ -187,7 +187,7 @@ export type EnvSet<T> = {
|
|||||||
export type IgnoreItem = string | Function | RegExp;
|
export type IgnoreItem = string | Function | RegExp;
|
||||||
export type IgnoreList = $ReadOnlyArray<IgnoreItem>;
|
export type IgnoreList = $ReadOnlyArray<IgnoreItem>;
|
||||||
|
|
||||||
export type PluginOptions = {} | void;
|
export type PluginOptions = {} | void | false;
|
||||||
export type PluginTarget = string | {} | Function;
|
export type PluginTarget = string | {} | Function;
|
||||||
export type PluginItem =
|
export type PluginItem =
|
||||||
| Plugin
|
| Plugin
|
||||||
|
|||||||
@ -310,30 +310,30 @@ describe("api", function() {
|
|||||||
assert.equal(
|
assert.equal(
|
||||||
result.code,
|
result.code,
|
||||||
[
|
[
|
||||||
"argtwo;",
|
"thirteen;",
|
||||||
"argone;",
|
"fourteen;",
|
||||||
"eleven;",
|
"seventeen;",
|
||||||
"twelve;",
|
"eighteen;",
|
||||||
"one;",
|
"one;",
|
||||||
"two;",
|
"two;",
|
||||||
|
"eleven;",
|
||||||
|
"twelve;",
|
||||||
|
"argtwo;",
|
||||||
|
"argone;",
|
||||||
"five;",
|
"five;",
|
||||||
"six;",
|
"six;",
|
||||||
"three;",
|
"three;",
|
||||||
"four;",
|
"four;",
|
||||||
"seventeen;",
|
|
||||||
"eighteen;",
|
|
||||||
"nineteen;",
|
"nineteen;",
|
||||||
"twenty;",
|
"twenty;",
|
||||||
"thirteen;",
|
|
||||||
"fourteen;",
|
|
||||||
"fifteen;",
|
"fifteen;",
|
||||||
"sixteen;",
|
"sixteen;",
|
||||||
"argthree;",
|
|
||||||
"argfour;",
|
|
||||||
"seven;",
|
"seven;",
|
||||||
"eight;",
|
"eight;",
|
||||||
"nine;",
|
"nine;",
|
||||||
"ten;",
|
"ten;",
|
||||||
|
"argthree;",
|
||||||
|
"argfour;",
|
||||||
].join("\n"),
|
].join("\n"),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -42,10 +42,10 @@ describe("@babel/core config loading", () => {
|
|||||||
|
|
||||||
const options1 = loadConfig(opts).options;
|
const options1 = loadConfig(opts).options;
|
||||||
expect(options1.plugins.map(p => p.key)).to.eql([
|
expect(options1.plugins.map(p => p.key)).to.eql([
|
||||||
"plugin6",
|
|
||||||
"plugin5",
|
|
||||||
"plugin1",
|
"plugin1",
|
||||||
"plugin2",
|
"plugin2",
|
||||||
|
"plugin6",
|
||||||
|
"plugin5",
|
||||||
"plugin4",
|
"plugin4",
|
||||||
"plugin3",
|
"plugin3",
|
||||||
]);
|
]);
|
||||||
@ -86,7 +86,7 @@ describe("@babel/core config loading", () => {
|
|||||||
expect(options2.plugins.length).to.equal(options1.plugins.length);
|
expect(options2.plugins.length).to.equal(options1.plugins.length);
|
||||||
|
|
||||||
for (let i = 0; i < options1.plugins.length; i++) {
|
for (let i = 0; i < options1.plugins.length; i++) {
|
||||||
if (i === 2) {
|
if (i === 0) {
|
||||||
expect(options2.plugins[i]).not.to.equal(options1.plugins[i]);
|
expect(options2.plugins[i]).not.to.equal(options1.plugins[i]);
|
||||||
} else {
|
} else {
|
||||||
expect(options2.plugins[i]).to.equal(options1.plugins[i]);
|
expect(options2.plugins[i]).to.equal(options1.plugins[i]);
|
||||||
@ -99,7 +99,7 @@ describe("@babel/core config loading", () => {
|
|||||||
expect(options3.plugins.length).to.equal(options1.plugins.length);
|
expect(options3.plugins.length).to.equal(options1.plugins.length);
|
||||||
|
|
||||||
for (let i = 0; i < options1.plugins.length; i++) {
|
for (let i = 0; i < options1.plugins.length; i++) {
|
||||||
if (i === 2 || i === 5) {
|
if (i === 0 || i === 5) {
|
||||||
expect(options3.plugins[i]).not.to.equal(options1.plugins[i]);
|
expect(options3.plugins[i]).not.to.equal(options1.plugins[i]);
|
||||||
} else {
|
} else {
|
||||||
expect(options3.plugins[i]).to.equal(options1.plugins[i]);
|
expect(options3.plugins[i]).to.equal(options1.plugins[i]);
|
||||||
@ -150,7 +150,7 @@ describe("@babel/core config loading", () => {
|
|||||||
expect(options2.plugins.length).to.equal(options1.plugins.length);
|
expect(options2.plugins.length).to.equal(options1.plugins.length);
|
||||||
|
|
||||||
for (let i = 0; i < options1.plugins.length; i++) {
|
for (let i = 0; i < options1.plugins.length; i++) {
|
||||||
if (i === 2 || i === 3 || i === 4 || i === 5 || i === 6) {
|
if (i === 0 || i === 1 || i === 4 || i === 5 || i === 6) {
|
||||||
expect(options2.plugins[i]).not.to.equal(options1.plugins[i]);
|
expect(options2.plugins[i]).not.to.equal(options1.plugins[i]);
|
||||||
} else {
|
} else {
|
||||||
expect(options2.plugins[i]).to.equal(options1.plugins[i]);
|
expect(options2.plugins[i]).to.equal(options1.plugins[i]);
|
||||||
@ -185,7 +185,7 @@ describe("@babel/core config loading", () => {
|
|||||||
expect(options2.plugins.length).to.equal(options1.plugins.length);
|
expect(options2.plugins.length).to.equal(options1.plugins.length);
|
||||||
|
|
||||||
for (let i = 0; i < options2.plugins.length; i++) {
|
for (let i = 0; i < options2.plugins.length; i++) {
|
||||||
if (i === 0) {
|
if (i === 2) {
|
||||||
expect(options2.plugins[i]).not.to.equal(options1.plugins[i]);
|
expect(options2.plugins[i]).not.to.equal(options1.plugins[i]);
|
||||||
} else {
|
} else {
|
||||||
expect(options2.plugins[i]).to.equal(options1.plugins[i]);
|
expect(options2.plugins[i]).to.equal(options1.plugins[i]);
|
||||||
@ -205,7 +205,7 @@ describe("@babel/core config loading", () => {
|
|||||||
expect(options2.plugins.length).to.equal(options1.plugins.length);
|
expect(options2.plugins.length).to.equal(options1.plugins.length);
|
||||||
|
|
||||||
for (let i = 0; i < options2.plugins.length; i++) {
|
for (let i = 0; i < options2.plugins.length; i++) {
|
||||||
if (i === 1) {
|
if (i === 3) {
|
||||||
expect(options2.plugins[i]).not.to.equal(options1.plugins[i]);
|
expect(options2.plugins[i]).not.to.equal(options1.plugins[i]);
|
||||||
} else {
|
} else {
|
||||||
expect(options2.plugins[i]).to.equal(options1.plugins[i]);
|
expect(options2.plugins[i]).to.equal(options1.plugins[i]);
|
||||||
@ -224,7 +224,7 @@ describe("@babel/core config loading", () => {
|
|||||||
expect(options2.plugins.length).to.equal(options1.plugins.length);
|
expect(options2.plugins.length).to.equal(options1.plugins.length);
|
||||||
|
|
||||||
for (let i = 0; i < options1.plugins.length; i++) {
|
for (let i = 0; i < options1.plugins.length; i++) {
|
||||||
if (i === 0) {
|
if (i === 2) {
|
||||||
expect(options2.plugins[i]).not.to.equal(options1.plugins[i]);
|
expect(options2.plugins[i]).not.to.equal(options1.plugins[i]);
|
||||||
} else {
|
} else {
|
||||||
expect(options2.plugins[i]).to.equal(options1.plugins[i]);
|
expect(options2.plugins[i]).to.equal(options1.plugins[i]);
|
||||||
@ -243,7 +243,7 @@ describe("@babel/core config loading", () => {
|
|||||||
expect(options2.plugins.length).to.equal(options1.plugins.length);
|
expect(options2.plugins.length).to.equal(options1.plugins.length);
|
||||||
|
|
||||||
for (let i = 0; i < options1.plugins.length; i++) {
|
for (let i = 0; i < options1.plugins.length; i++) {
|
||||||
if (i === 1) {
|
if (i === 3) {
|
||||||
expect(options2.plugins[i]).not.to.equal(options1.plugins[i]);
|
expect(options2.plugins[i]).not.to.equal(options1.plugins[i]);
|
||||||
} else {
|
} else {
|
||||||
expect(options2.plugins[i]).to.equal(options1.plugins[i]);
|
expect(options2.plugins[i]).to.equal(options1.plugins[i]);
|
||||||
|
|||||||
@ -11,6 +11,113 @@ describe("option-manager", () => {
|
|||||||
}, /Babel 5 plugin is being run with an unsupported Babel/);
|
}, /Babel 5 plugin is being run with an unsupported Babel/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("config plugin/preset flattening and overriding", () => {
|
||||||
|
function makePlugin() {
|
||||||
|
const calls = [];
|
||||||
|
const plugin = (api, opts) => {
|
||||||
|
calls.push(opts);
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
return { plugin, calls };
|
||||||
|
}
|
||||||
|
|
||||||
|
it("should throw if a plugin is repeated", () => {
|
||||||
|
const { calls, plugin } = makePlugin();
|
||||||
|
|
||||||
|
assert.throws(() => {
|
||||||
|
manageOptions({
|
||||||
|
plugins: [plugin, plugin],
|
||||||
|
});
|
||||||
|
}, /Duplicate plugin\/preset detected/);
|
||||||
|
assert.deepEqual(calls, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not throw if a repeated plugin has a different name", () => {
|
||||||
|
const { calls: calls1, plugin: plugin1 } = makePlugin();
|
||||||
|
const { calls: calls2, plugin: plugin2 } = makePlugin();
|
||||||
|
|
||||||
|
manageOptions({
|
||||||
|
plugins: [[plugin1, { arg: 1 }], [plugin2, { arg: 2 }, "some-name"]],
|
||||||
|
});
|
||||||
|
assert.deepEqual(calls1, [{ arg: 1 }]);
|
||||||
|
assert.deepEqual(calls2, [{ arg: 2 }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should merge .env[] plugins with parent presets", () => {
|
||||||
|
const { calls: calls1, plugin: plugin1 } = makePlugin();
|
||||||
|
const { calls: calls2, plugin: plugin2 } = makePlugin();
|
||||||
|
|
||||||
|
manageOptions({
|
||||||
|
envName: "test",
|
||||||
|
plugins: [[plugin1, { arg: 1 }]],
|
||||||
|
env: {
|
||||||
|
test: {
|
||||||
|
plugins: [[plugin1, { arg: 3 }], [plugin2, { arg: 2 }]],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assert.deepEqual(calls1, [{ arg: 3 }]);
|
||||||
|
assert.deepEqual(calls2, [{ arg: 2 }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should throw if a preset is repeated", () => {
|
||||||
|
const { calls, plugin: preset } = makePlugin();
|
||||||
|
|
||||||
|
assert.throws(() => {
|
||||||
|
manageOptions({
|
||||||
|
presets: [preset, preset],
|
||||||
|
});
|
||||||
|
}, /Duplicate plugin\/preset detected/);
|
||||||
|
assert.deepEqual(calls, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not throw if a repeated preset has a different name", () => {
|
||||||
|
const { calls: calls1, plugin: preset1 } = makePlugin();
|
||||||
|
const { calls: calls2, plugin: preset2 } = makePlugin();
|
||||||
|
|
||||||
|
manageOptions({
|
||||||
|
presets: [[preset1, { arg: 1 }], [preset2, { arg: 2 }, "some-name"]],
|
||||||
|
});
|
||||||
|
assert.deepEqual(calls1, [{ arg: 1 }]);
|
||||||
|
assert.deepEqual(calls2, [{ arg: 2 }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should merge .env[] presets with parent presets", () => {
|
||||||
|
const { calls: calls1, plugin: preset1 } = makePlugin();
|
||||||
|
const { calls: calls2, plugin: preset2 } = makePlugin();
|
||||||
|
|
||||||
|
manageOptions({
|
||||||
|
envName: "test",
|
||||||
|
presets: [[preset1, { arg: 1 }]],
|
||||||
|
env: {
|
||||||
|
test: {
|
||||||
|
presets: [[preset1, { arg: 3 }], [preset2, { arg: 2 }]],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assert.deepEqual(calls1, [{ arg: 3 }]);
|
||||||
|
assert.deepEqual(calls2, [{ arg: 2 }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not merge .env[] presets with parent presets when passPerPreset", () => {
|
||||||
|
const { calls: calls1, plugin: preset1 } = makePlugin();
|
||||||
|
const { calls: calls2, plugin: preset2 } = makePlugin();
|
||||||
|
|
||||||
|
manageOptions({
|
||||||
|
envName: "test",
|
||||||
|
passPerPreset: true,
|
||||||
|
presets: [[preset1, { arg: 1 }]],
|
||||||
|
env: {
|
||||||
|
test: {
|
||||||
|
presets: [[preset1, { arg: 3 }], [preset2, { arg: 2 }]],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
assert.deepEqual(calls1, [{ arg: 1 }, { arg: 3 }]);
|
||||||
|
assert.deepEqual(calls2, [{ arg: 2 }]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("mergeOptions", () => {
|
describe("mergeOptions", () => {
|
||||||
it("throws for removed babel 5 options", () => {
|
it("throws for removed babel 5 options", () => {
|
||||||
return assert.throws(() => {
|
return assert.throws(() => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user