Merge pull request #7091 from loganfsmyth/config-overrides

Allow configs to have an 'overrides' array
This commit is contained in:
Logan Smyth 2018-01-07 13:51:07 -08:00 committed by GitHub
commit a19349a22a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 764 additions and 54 deletions

View File

@ -7,6 +7,7 @@ import {
validate,
type ValidatedOptions,
type IgnoreList,
type ConfigApplicableTest,
} from "./validation/options";
const debug = buildDebug("babel:config:config-chain");
@ -40,7 +41,7 @@ export type PresetInstance = {
dirname: string,
};
type ConfigContext = {
export type ConfigContext = {
filename: string | null,
cwd: string,
envName: string,
@ -54,16 +55,53 @@ type ConfigContextNamed = {
/**
* Build a config chain for a given preset.
*/
export const buildPresetChain = makeWeakCache(
({ dirname, options, alias }: PresetInstance): ConfigChain => {
const result = createUncachedDescriptors(dirname, options, alias);
const { plugins, presets } = result;
return {
plugins: plugins(),
presets: presets(),
options: [normalizeOptions(result.options)],
};
},
export const buildPresetChain: (
arg: PresetInstance,
context: *,
) => * = makeChainWalker({
init: arg => arg,
root: preset => loadPresetDescriptors(preset),
env: (preset, envName) => loadPresetEnvDescriptors(preset)(envName),
overrides: (preset, index) => loadPresetOverridesDescriptors(preset)(index),
overridesEnv: (preset, index, envName) =>
loadPresetOverridesEnvDescriptors(preset)(index)(envName),
});
const loadPresetDescriptors = makeWeakCache((preset: PresetInstance) =>
buildRootDescriptors(preset, preset.alias, createUncachedDescriptors),
);
const loadPresetEnvDescriptors = makeWeakCache((preset: PresetInstance) =>
makeStrongCache((envName: string) =>
buildEnvDescriptors(
preset,
preset.alias,
createUncachedDescriptors,
envName,
),
),
);
const loadPresetOverridesDescriptors = makeWeakCache((preset: PresetInstance) =>
makeStrongCache((index: number) =>
buildOverrideDescriptors(
preset,
preset.alias,
createUncachedDescriptors,
index,
),
),
);
const loadPresetOverridesEnvDescriptors = makeWeakCache(
(preset: PresetInstance) =>
makeStrongCache((index: number) =>
makeStrongCache((envName: string) =>
buildOverrideEnvDescriptors(
preset,
preset.alias,
createUncachedDescriptors,
index,
envName,
),
),
),
);
/**
@ -72,14 +110,8 @@ export const buildPresetChain = makeWeakCache(
export function buildRootChain(
cwd: string,
opts: ValidatedOptions,
envName: string,
context: ConfigContext,
): ConfigChain | null {
const context = {
filename: opts.filename ? path.resolve(cwd, opts.filename) : null,
cwd,
envName,
};
const programmaticChain = loadProgrammaticChain(
{
options: opts,
@ -137,6 +169,16 @@ const loadProgrammaticChain = makeChainWalker({
root: input => buildRootDescriptors(input, "base", createCachedDescriptors),
env: (input, envName) =>
buildEnvDescriptors(input, "base", createCachedDescriptors, envName),
overrides: (input, index) =>
buildOverrideDescriptors(input, "base", createCachedDescriptors, index),
overridesEnv: (input, index, envName) =>
buildOverrideEnvDescriptors(
input,
"base",
createCachedDescriptors,
index,
envName,
),
});
/**
@ -146,6 +188,9 @@ const loadFileChain = makeChainWalker({
init: input => validateFile(input),
root: file => loadFileDescriptors(file),
env: (file, envName) => loadFileEnvDescriptors(file)(envName),
overrides: (file, index) => loadFileOverridesDescriptors(file)(index),
overridesEnv: (file, index, envName) =>
loadFileOverridesEnvDescriptors(file)(index)(envName),
});
const validateFile = makeWeakCache((file: ConfigFile): ValidatedFile => ({
filepath: file.filepath,
@ -165,6 +210,29 @@ const loadFileEnvDescriptors = makeWeakCache((file: ValidatedFile) =>
),
),
);
const loadFileOverridesDescriptors = makeWeakCache((file: ValidatedFile) =>
makeStrongCache((index: number) =>
buildOverrideDescriptors(
file,
file.filepath,
createUncachedDescriptors,
index,
),
),
);
const loadFileOverridesEnvDescriptors = makeWeakCache((file: ValidatedFile) =>
makeStrongCache((index: number) =>
makeStrongCache((envName: string) =>
buildOverrideEnvDescriptors(
file,
file.filepath,
createUncachedDescriptors,
index,
envName,
),
),
),
);
function buildRootDescriptors({ dirname, options }, alias, descriptors) {
return descriptors(dirname, options, alias);
@ -180,6 +248,38 @@ function buildEnvDescriptors(
return opts ? descriptors(dirname, opts, `${alias}.env["${envName}"]`) : null;
}
function buildOverrideDescriptors(
{ dirname, options },
alias,
descriptors,
index,
) {
const opts = options.overrides && options.overrides[index];
if (!opts) throw new Error("Assertion failure - missing override");
return descriptors(dirname, opts, `${alias}.overrides[${index}]`);
}
function buildOverrideEnvDescriptors(
{ dirname, options },
alias,
descriptors,
index,
envName,
) {
const override = options.overrides && options.overrides[index];
if (!override) throw new Error("Assertion failure - missing override");
const opts = override.env && override.env[envName];
return opts
? descriptors(
dirname,
opts,
`${alias}.overrides[${index}].env["${envName}"]`,
)
: null;
}
function makeChainWalker<
ArgT,
InnerT: { options: ValidatedOptions, dirname: string },
@ -187,10 +287,14 @@ function makeChainWalker<
init,
root,
env,
overrides,
overridesEnv,
}: {
init: ArgT => InnerT,
root: InnerT => OptionsAndDescriptors,
env: (InnerT, string) => OptionsAndDescriptors | null,
overrides: (InnerT, number) => OptionsAndDescriptors,
overridesEnv: (InnerT, number, string) => OptionsAndDescriptors | null,
}): (ArgT, ConfigContext, Set<ConfigFile> | void) => ConfigChain | null {
return (arg, context, files = new Set()) => {
const input = init(arg);
@ -200,11 +304,28 @@ function makeChainWalker<
const flattenedConfigs = [];
const rootOpts = root(input);
flattenedConfigs.push(rootOpts);
if (configIsApplicable(rootOpts, dirname, context)) {
flattenedConfigs.push(rootOpts);
const envOpts = env(input, context.envName);
if (envOpts) {
flattenedConfigs.push(envOpts);
const envOpts = env(input, context.envName);
if (envOpts && configIsApplicable(envOpts, dirname, context)) {
flattenedConfigs.push(envOpts);
}
(rootOpts.options.overrides || []).forEach((_, index) => {
const overrideOps = overrides(input, index);
if (configIsApplicable(overrideOps, dirname, context)) {
flattenedConfigs.push(overrideOps);
const overrideEnvOpts = overridesEnv(input, index, context.envName);
if (
overrideEnvOpts &&
configIsApplicable(overrideEnvOpts, dirname, context)
) {
flattenedConfigs.push(overrideEnvOpts);
}
}
});
}
// Process 'ignore' and 'only' before 'extends' items are processed so
@ -351,6 +472,42 @@ function dedupDescriptors(
}, []);
}
function configIsApplicable(
{ options }: OptionsAndDescriptors,
dirname: string,
context: ConfigContext,
): boolean {
return (
(options.test === undefined ||
configFieldIsApplicable(context, options.test, dirname)) &&
(options.include === undefined ||
configFieldIsApplicable(context, options.include, dirname)) &&
(options.exclude === undefined ||
!configFieldIsApplicable(context, options.exclude, dirname))
);
}
function configFieldIsApplicable(
context: ConfigContext,
test: ConfigApplicableTest,
dirname: string,
): boolean {
if (context.filename === null) {
throw new Error(
`Configuration contains explicit test/include/exclude checks, but no filename was passed to Babel`,
);
}
// $FlowIgnore - Flow refinements aren't quite smart enough for this :(
const ctx: ConfigContextNamed = context;
const patterns = Array.isArray(test) ? test : [test];
// Disabling negation here because it's a bit buggy from
// https://github.com/babel/babel/issues/6907 and it's not clear that it is
// needed since users can use 'exclude' alongside 'test'/'include'.
return matchesPatterns(ctx, patterns, dirname, false /* allowNegation */);
}
/**
* Tests if a filename should be ignored based on "ignore" and "only" options.
*/
@ -360,11 +517,14 @@ function shouldIgnore(
only: ?IgnoreList,
dirname: string,
): boolean {
if (context.filename === null) return false;
// $FlowIgnore - Flow refinements aren't quite smart enough for this :(
const ctx: ConfigContextNamed = context;
if (ignore) {
if (context.filename === null) {
throw new Error(
`Configuration contains ignore checks, but no filename was passed to Babel`,
);
}
// $FlowIgnore - Flow refinements aren't quite smart enough for this :(
const ctx: ConfigContextNamed = context;
if (matchesPatterns(ctx, ignore, dirname)) {
debug(
"Ignored %o because it matched one of %O from %o",
@ -377,6 +537,14 @@ function shouldIgnore(
}
if (only) {
if (context.filename === null) {
throw new Error(
`Configuration contains ignore checks, but no filename was passed to Babel`,
);
}
// $FlowIgnore - Flow refinements aren't quite smart enough for this :(
const ctx: ConfigContextNamed = context;
if (!matchesPatterns(ctx, only, dirname)) {
debug(
"Ignored %o because it failed to match one of %O from %o",
@ -399,6 +567,7 @@ function matchesPatterns(
context: ConfigContextNamed,
patterns: IgnoreList,
dirname: string,
allowNegation?: boolean = true,
): boolean {
const res = [];
const strings = [];
@ -420,13 +589,19 @@ function matchesPatterns(
const absolutePatterns = strings.map(pattern => {
// Preserve the "!" prefix so that micromatch can use it for negation.
const negate = pattern[0] === "!";
if (negate && !allowNegation) {
throw new Error(`Negation of file paths is not supported.`);
}
if (negate) pattern = pattern.slice(1);
return (negate ? "!" : "") + path.resolve(dirname, pattern);
});
if (
micromatch(possibleDirs, absolutePatterns, { nocase: true }).length > 0
micromatch(possibleDirs, absolutePatterns, {
nocase: true,
nonegate: !allowNegation,
}).length > 0
) {
return true;
}

View File

@ -7,6 +7,7 @@ import merge from "lodash/merge";
import {
buildRootChain,
buildPresetChain,
type ConfigContext,
type ConfigChain,
type PresetInstance,
} from "./config-chain";
@ -36,6 +37,12 @@ export type { Plugin };
export type PluginPassList = Array<Plugin>;
export type PluginPasses = Array<PluginPassList>;
// Context not including filename since it is used in places that cannot
// process 'ignore'/'only' and other filename-based logic.
type SimpleContext = {
envName: string,
};
export default function loadConfig(inputOpts: mixed): ResolvedConfig | null {
if (
inputOpts != null &&
@ -49,27 +56,32 @@ export default function loadConfig(inputOpts: mixed): ResolvedConfig | null {
const { envName = getEnv(), cwd = "." } = args;
const absoluteCwd = path.resolve(cwd);
const configChain = buildRootChain(absoluteCwd, args, envName);
const context: ConfigContext = {
filename: args.filename ? path.resolve(cwd, args.filename) : null,
cwd: absoluteCwd,
envName,
};
const configChain = buildRootChain(absoluteCwd, args, context);
if (!configChain) return null;
const optionDefaults = {};
const options = {};
const passes = [[]];
try {
(function recurseDescriptors(
const ignored = (function recurseDescriptors(
config: {
plugins: Array<UnloadedDescriptor>,
presets: Array<UnloadedDescriptor>,
},
pass: Array<Plugin>,
envName: string,
) {
const plugins = config.plugins.map(descriptor =>
loadPluginDescriptor(descriptor, envName),
loadPluginDescriptor(descriptor, context),
);
const presets = config.presets.map(descriptor => {
return {
preset: loadPresetDescriptor(descriptor, envName),
preset: loadPresetDescriptor(descriptor, context),
pass: descriptor.ownPass ? [] : pass,
};
});
@ -85,14 +97,16 @@ export default function loadConfig(inputOpts: mixed): ResolvedConfig | null {
);
for (const { preset, pass } of presets) {
recurseDescriptors(
if (!preset) return true;
const ignored = recurseDescriptors(
{
plugins: preset.plugins,
presets: preset.presets,
},
pass,
envName,
);
if (ignored) return true;
preset.options.forEach(opts => {
merge(optionDefaults, opts);
@ -110,9 +124,10 @@ export default function loadConfig(inputOpts: mixed): ResolvedConfig | null {
presets: configChain.presets,
},
passes[0],
envName,
);
if (ignored) return null;
configChain.options.forEach(opts => {
merge(options, opts);
});
@ -152,7 +167,7 @@ export default function loadConfig(inputOpts: mixed): ResolvedConfig | null {
const loadDescriptor = makeWeakCache(
(
{ value, options, dirname, alias }: UnloadedDescriptor,
cache: CacheConfigurator<{ envName: string }>,
cache: CacheConfigurator<SimpleContext>,
): LoadedDescriptor => {
// Disabled presets should already have been filtered out
if (options === false) throw new Error("Assertion failure");
@ -199,7 +214,7 @@ const loadDescriptor = makeWeakCache(
*/
function loadPluginDescriptor(
descriptor: UnloadedDescriptor,
envName: string,
context: SimpleContext,
): Plugin {
if (descriptor.value instanceof Plugin) {
if (descriptor.options) {
@ -211,15 +226,13 @@ function loadPluginDescriptor(
return descriptor.value;
}
return instantiatePlugin(loadDescriptor(descriptor, { envName }), {
envName,
});
return instantiatePlugin(loadDescriptor(descriptor, context), context);
}
const instantiatePlugin = makeWeakCache(
(
{ value, options, dirname, alias }: LoadedDescriptor,
cache: CacheConfigurator<{ envName: string }>,
cache: CacheConfigurator<SimpleContext>,
): Plugin => {
const pluginObj = validatePluginObject(value);
@ -239,7 +252,7 @@ const instantiatePlugin = makeWeakCache(
// If the inherited plugin changes, reinstantiate this plugin.
const inherits = cache.invalidate(data =>
loadPluginDescriptor(inheritsDescriptor, data.envName),
loadPluginDescriptor(inheritsDescriptor, data),
);
plugin.pre = chain(inherits.pre, plugin.pre);
@ -263,10 +276,11 @@ const instantiatePlugin = makeWeakCache(
*/
const loadPresetDescriptor = (
descriptor: UnloadedDescriptor,
envName: string,
): ConfigChain => {
context: ConfigContext,
): ConfigChain | null => {
return buildPresetChain(
instantiatePreset(loadDescriptor(descriptor, { envName })),
instantiatePreset(loadDescriptor(descriptor, context)),
context,
);
};

View File

@ -6,6 +6,7 @@ import type {
PluginList,
PluginItem,
PluginTarget,
ConfigApplicableTest,
SourceMapsOption,
SourceTypeOption,
CompactOption,
@ -104,6 +105,13 @@ export function assertObject(key: string, value: mixed): {} | void {
return value;
}
export function assertArray(key: string, value: mixed): ?$ReadOnlyArray<mixed> {
if (value != null && !Array.isArray(value)) {
throw new Error(`.${key} must be an array, or undefined`);
}
return value;
}
export function assertIgnoreList(key: string, value: mixed): IgnoreList | void {
const arr = assertArray(key, value);
if (arr) {
@ -122,12 +130,38 @@ function assertIgnoreItem(
!(value instanceof RegExp)
) {
throw new Error(
`.${key}[${index}] must be an array of string/Funtion/RegExp values, or or undefined`,
`.${key}[${index}] must be an array of string/Funtion/RegExp values, or undefined`,
);
}
return value;
}
export function assertConfigApplicableTest(
key: string,
value: mixed,
): ConfigApplicableTest | void {
if (Array.isArray(value)) {
value.forEach((item, i) => {
if (!checkValidTest(item)) {
throw new Error(`.${key}[${i}] must be a string/Function/RegExp.`);
}
});
} else if (!checkValidTest(value)) {
throw new Error(
`.${key} must be a string/Function/RegExp, or an array of those`,
);
}
return (value: any);
}
function checkValidTest(value: mixed): boolean {
return (
typeof value === "string" ||
typeof value === "function" ||
value instanceof RegExp
);
}
export function assertPluginList(key: string, value: mixed): PluginList | void {
const arr = assertArray(key, value);
if (arr) {
@ -198,10 +232,3 @@ function assertPluginTarget(
}
return value;
}
function assertArray(key: string, value: mixed): ?$ReadOnlyArray<mixed> {
if (value != null && !Array.isArray(value)) {
throw new Error(`.${key} must be an array, or undefined`);
}
return value;
}

View File

@ -5,9 +5,11 @@ import {
assertString,
assertBoolean,
assertObject,
assertArray,
assertInputSourceMap,
assertIgnoreList,
assertPluginList,
assertConfigApplicableTest,
assertFunction,
assertSourceMaps,
assertCompact,
@ -44,6 +46,22 @@ const NONPRESET_VALIDATORS: ValidatorSet = {
$PropertyType<ValidatedOptions, "ignore">,
>),
only: (assertIgnoreList: Validator<$PropertyType<ValidatedOptions, "only">>),
overrides: (assertOverridesList: Validator<
$PropertyType<ValidatedOptions, "overrides">,
>),
// We could limit these to 'overrides' blocks, but it's not clear why we'd
// bother, when the ability to limit a config to a specific set of files
// is a fairly general useful feature.
test: (assertConfigApplicableTest: Validator<
$PropertyType<ValidatedOptions, "test">,
>),
include: (assertConfigApplicableTest: Validator<
$PropertyType<ValidatedOptions, "include">,
>),
exclude: (assertConfigApplicableTest: Validator<
$PropertyType<ValidatedOptions, "exclude">,
>),
};
const COMMON_VALIDATORS: ValidatorSet = {
@ -142,6 +160,12 @@ export type ValidatedOptions = {
env?: EnvSet<ValidatedOptions>,
ignore?: IgnoreList,
only?: IgnoreList,
overrides?: OverridesList,
// Generally verify if a given config object should be applied to the given file.
test?: ConfigApplicableTest,
include?: ConfigApplicableTest,
exclude?: ConfigApplicableTest,
presets?: PluginList,
plugins?: PluginList,
@ -196,12 +220,15 @@ export type PluginItem =
| [PluginTarget, PluginOptions, string];
export type PluginList = $ReadOnlyArray<PluginItem>;
export type OverridesList = Array<ValidatedOptions>;
export type ConfigApplicableTest = IgnoreItem | Array<IgnoreItem>;
export type SourceMapsOption = boolean | "inline" | "both";
export type SourceTypeOption = "module" | "script" | "unambiguous";
export type CompactOption = boolean | "auto";
export type RootInputSourceMapOption = {} | boolean;
export type OptionsType = "arguments" | "file" | "env" | "preset";
export type OptionsType = "arguments" | "file" | "env" | "preset" | "override";
export function validate(type: OptionsType, opts: {}): ValidatedOptions {
assertNoDuplicateSourcemap(opts);
@ -216,6 +243,12 @@ export function validate(type: OptionsType, opts: {}): ValidatedOptions {
if (type === "env" && key === "env") {
throw new Error(`.${key} is not allowed inside another env block`);
}
if (type === "env" && key === "overrides") {
throw new Error(`.${key} is not allowed inside an env block`);
}
if (type === "override" && key === "overrides") {
throw new Error(`.${key} is not allowed inside an overrides block`);
}
const validator =
COMMON_VALIDATORS[key] ||
@ -266,3 +299,16 @@ function assertEnvSet(key: string, value: mixed): EnvSet<ValidatedOptions> {
}
return (obj: any);
}
function assertOverridesList(key: string, value: mixed): OverridesList {
const arr = assertArray(key, value);
if (arr) {
for (const [index, item] of arr.entries()) {
const env = assertObject(`${index}`, item);
if (!env) throw new Error(`.${key}[${index}] must be an object`);
validate("override", env);
}
}
return (arr: any);
}

View File

@ -8,6 +8,420 @@ function fixture(...args) {
}
describe("buildConfigChain", function() {
describe("test", () => {
describe("single", () => {
it("should process matching string values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
test: fixture("nonexistant-fake"),
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process matching RegExp values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
test: new RegExp(fixture("nonexistant-fake")),
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process matching function values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
test: p => p.indexOf(fixture("nonexistant-fake")) === 0,
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process non-matching string values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
test: fixture("nonexistant-fake-unknown"),
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process non-matching RegExp values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
test: new RegExp(fixture("nonexistant-unknown")),
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process non-matching function values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
test: p => p.indexOf(fixture("nonexistant-unknown")) === 0,
comments: true,
});
assert.equal(opts.comments, undefined);
});
});
describe("array", () => {
it("should process matching string values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
test: [fixture("nonexistant-fake")],
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process matching RegExp values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
test: [new RegExp(fixture("nonexistant-fake"))],
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process matching function values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
test: [p => p.indexOf(fixture("nonexistant-fake")) === 0],
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process non-matching string values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
test: [fixture("nonexistant-fake-unknown")],
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process non-matching RegExp values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
test: [new RegExp(fixture("nonexistant-unknown"))],
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process non-matching function values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
test: [p => p.indexOf(fixture("nonexistant-unknown")) === 0],
comments: true,
});
assert.equal(opts.comments, undefined);
});
});
});
describe("include", () => {
describe("single", () => {
it("should process matching string values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
include: fixture("nonexistant-fake"),
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process matching RegExp values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
include: new RegExp(fixture("nonexistant-fake")),
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process matching function values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
include: p => p.indexOf(fixture("nonexistant-fake")) === 0,
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process non-matching string values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
include: fixture("nonexistant-fake-unknown"),
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process non-matching RegExp values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
include: new RegExp(fixture("nonexistant-unknown")),
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process non-matching function values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
include: p => p.indexOf(fixture("nonexistant-unknown")) === 0,
comments: true,
});
assert.equal(opts.comments, undefined);
});
});
describe("array", () => {
it("should process matching string values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
include: [fixture("nonexistant-fake")],
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process matching RegExp values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
include: [new RegExp(fixture("nonexistant-fake"))],
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process matching function values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
include: [p => p.indexOf(fixture("nonexistant-fake")) === 0],
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process non-matching string values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
include: [fixture("nonexistant-fake-unknown")],
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process non-matching RegExp values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
include: [new RegExp(fixture("nonexistant-unknown"))],
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process non-matching function values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
include: [p => p.indexOf(fixture("nonexistant-unknown")) === 0],
comments: true,
});
assert.equal(opts.comments, undefined);
});
});
});
describe("exclude", () => {
describe("single", () => {
it("should process matching string values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
exclude: fixture("nonexistant-fake"),
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process matching RegExp values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
exclude: new RegExp(fixture("nonexistant-fake")),
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process matching function values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
exclude: p => p.indexOf(fixture("nonexistant-fake")) === 0,
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process non-matching string values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
exclude: fixture("nonexistant-fake-unknown"),
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process non-matching RegExp values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
exclude: new RegExp(fixture("nonexistant-unknown")),
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process non-matching function values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
exclude: p => p.indexOf(fixture("nonexistant-unknown")) === 0,
comments: true,
});
assert.equal(opts.comments, true);
});
});
describe("array", () => {
it("should process matching string values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
exclude: [fixture("nonexistant-fake")],
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process matching RegExp values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
exclude: [new RegExp(fixture("nonexistant-fake"))],
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process matching function values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
exclude: [p => p.indexOf(fixture("nonexistant-fake")) === 0],
comments: true,
});
assert.equal(opts.comments, undefined);
});
it("should process non-matching string values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
exclude: [fixture("nonexistant-fake-unknown")],
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process non-matching RegExp values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
exclude: [new RegExp(fixture("nonexistant-unknown"))],
comments: true,
});
assert.equal(opts.comments, true);
});
it("should process non-matching function values", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
exclude: [p => p.indexOf(fixture("nonexistant-unknown")) === 0],
comments: true,
});
assert.equal(opts.comments, true);
});
});
});
describe("ignore", () => {
it("should ignore files that match", () => {
const opts = loadOptions({
@ -387,6 +801,40 @@ describe("buildConfigChain", function() {
});
});
describe("overrides merging", () => {
it("should apply matching overrides over base configs", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
comments: true,
overrides: [
{
test: fixture("nonexistant-fake"),
comments: false,
},
],
});
assert.equal(opts.comments, false);
});
it("should not apply non-matching overrides over base configs", () => {
const opts = loadOptions({
filename: fixture("nonexistant-fake", "src.js"),
babelrc: false,
comments: true,
overrides: [
{
test: fixture("nonexistant-unknown"),
comments: false,
},
],
});
assert.equal(opts.comments, true);
});
});
describe("config files", () => {
const getDefaults = () => ({
babelrc: false,