Allow config objects to use test/include/exclude to limit application to specific files.
This commit is contained in:
@@ -7,6 +7,7 @@ import {
|
||||
validate,
|
||||
type ValidatedOptions,
|
||||
type IgnoreList,
|
||||
type ConfigApplicableTest,
|
||||
} from "./validation/options";
|
||||
|
||||
const debug = buildDebug("babel:config:config-chain");
|
||||
@@ -204,11 +205,13 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Process 'ignore' and 'only' before 'extends' items are processed so
|
||||
@@ -355,6 +358,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.
|
||||
*/
|
||||
@@ -403,6 +442,7 @@ function matchesPatterns(
|
||||
context: ConfigContextNamed,
|
||||
patterns: IgnoreList,
|
||||
dirname: string,
|
||||
allowNegation?: boolean = true,
|
||||
): boolean {
|
||||
const res = [];
|
||||
const strings = [];
|
||||
@@ -424,13 +464,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;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import type {
|
||||
PluginList,
|
||||
PluginItem,
|
||||
PluginTarget,
|
||||
ConfigApplicableTest,
|
||||
SourceMapsOption,
|
||||
SourceTypeOption,
|
||||
CompactOption,
|
||||
@@ -122,12 +123,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) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
assertInputSourceMap,
|
||||
assertIgnoreList,
|
||||
assertPluginList,
|
||||
assertConfigApplicableTest,
|
||||
assertFunction,
|
||||
assertSourceMaps,
|
||||
assertCompact,
|
||||
@@ -44,6 +45,19 @@ const NONPRESET_VALIDATORS: ValidatorSet = {
|
||||
$PropertyType<ValidatedOptions, "ignore">,
|
||||
>),
|
||||
only: (assertIgnoreList: Validator<$PropertyType<ValidatedOptions, "only">>),
|
||||
|
||||
// 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 = {
|
||||
@@ -143,6 +157,11 @@ export type ValidatedOptions = {
|
||||
ignore?: IgnoreList,
|
||||
only?: IgnoreList,
|
||||
|
||||
// Generally verify if a given config object should be applied to the given file.
|
||||
test?: ConfigApplicableTest,
|
||||
include?: ConfigApplicableTest,
|
||||
exclude?: ConfigApplicableTest,
|
||||
|
||||
presets?: PluginList,
|
||||
plugins?: PluginList,
|
||||
passPerPreset?: boolean,
|
||||
@@ -196,6 +215,8 @@ export type PluginItem =
|
||||
| [PluginTarget, PluginOptions, string];
|
||||
export type PluginList = $ReadOnlyArray<PluginItem>;
|
||||
|
||||
export type ConfigApplicableTest = IgnoreItem | Array<IgnoreItem>;
|
||||
|
||||
export type SourceMapsOption = boolean | "inline" | "both";
|
||||
export type SourceTypeOption = "module" | "script" | "unambiguous";
|
||||
export type CompactOption = boolean | "auto";
|
||||
|
||||
Reference in New Issue
Block a user