Remove micromatch and use a simple pattern matching utility.
This commit is contained in:
parent
c4f67bfa57
commit
6d177ba4c5
@ -41,7 +41,6 @@
|
||||
"debug": "^3.1.0",
|
||||
"json5": "^0.5.0",
|
||||
"lodash": "^4.17.5",
|
||||
"micromatch": "^2.3.11",
|
||||
"resolve": "^1.3.2",
|
||||
"semver": "^5.4.1",
|
||||
"source-map": "^0.5.0"
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import path from "path";
|
||||
import micromatch from "micromatch";
|
||||
import buildDebug from "debug";
|
||||
import {
|
||||
validate,
|
||||
@ -10,6 +9,7 @@ import {
|
||||
type ConfigApplicableTest,
|
||||
type BabelrcSearch,
|
||||
} from "./validation/options";
|
||||
import pathPatternToRegex from "./pattern-to-regex";
|
||||
|
||||
const debug = buildDebug("babel:config:config-chain");
|
||||
|
||||
@ -52,11 +52,6 @@ export type ConfigContext = {
|
||||
envName: string,
|
||||
};
|
||||
|
||||
type ConfigContextNamed = {
|
||||
...ConfigContext,
|
||||
filename: string,
|
||||
};
|
||||
|
||||
/**
|
||||
* Build a config chain for a given preset.
|
||||
*/
|
||||
@ -217,7 +212,7 @@ function babelrcLoadEnabled(
|
||||
|
||||
const absoluteRoot = context.root;
|
||||
|
||||
// Fast path to avoid having to load micromatch if the babelrc is just
|
||||
// Fast path to avoid having to match patterns if the babelrc is just
|
||||
// loading in the standard root directory.
|
||||
if (babelrcRoots === undefined) {
|
||||
return pkgData.directories.indexOf(absoluteRoot) !== -1;
|
||||
@ -225,15 +220,23 @@ function babelrcLoadEnabled(
|
||||
|
||||
let babelrcPatterns = babelrcRoots;
|
||||
if (!Array.isArray(babelrcPatterns)) babelrcPatterns = [babelrcPatterns];
|
||||
babelrcPatterns = babelrcPatterns.map(pat => path.resolve(context.cwd, pat));
|
||||
babelrcPatterns = babelrcPatterns.map(pat => {
|
||||
return typeof pat === "string" ? path.resolve(context.cwd, pat) : pat;
|
||||
});
|
||||
|
||||
// Fast path to avoid having to load micromatch if the babelrc is just
|
||||
// Fast path to avoid having to match patterns if the babelrc is just
|
||||
// loading in the standard root directory.
|
||||
if (babelrcPatterns.length === 1 && babelrcPatterns[0] === absoluteRoot) {
|
||||
return pkgData.directories.indexOf(absoluteRoot) !== -1;
|
||||
}
|
||||
|
||||
return micromatch(pkgData.directories, babelrcPatterns).length > 0;
|
||||
return babelrcPatterns.some(pat => {
|
||||
if (typeof pat === "string") pat = pathPatternToRegex(pat, context.cwd);
|
||||
|
||||
return pkgData.directories.some(directory => {
|
||||
return matchPattern(pat, context.cwd, directory);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const validateConfigFile = makeWeakCache(
|
||||
@ -583,20 +586,9 @@ function configFieldIsApplicable(
|
||||
test: ConfigApplicableTest,
|
||||
dirname: string,
|
||||
): boolean {
|
||||
if (typeof context.filename !== "string") {
|
||||
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 */);
|
||||
return matchesPatterns(context, patterns, dirname);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -608,15 +600,7 @@ function shouldIgnore(
|
||||
only: ?IgnoreList,
|
||||
dirname: string,
|
||||
): boolean {
|
||||
if (ignore) {
|
||||
if (typeof context.filename !== "string") {
|
||||
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)) {
|
||||
if (ignore && matchesPatterns(context, ignore, dirname)) {
|
||||
debug(
|
||||
"Ignored %o because it matched one of %O from %o",
|
||||
context.filename,
|
||||
@ -625,18 +609,8 @@ function shouldIgnore(
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (only) {
|
||||
if (typeof context.filename !== "string") {
|
||||
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)) {
|
||||
if (only && !matchesPatterns(context, only, dirname)) {
|
||||
debug(
|
||||
"Ignored %o because it failed to match one of %O from %o",
|
||||
context.filename,
|
||||
@ -645,7 +619,6 @@ function shouldIgnore(
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -655,64 +628,26 @@ function shouldIgnore(
|
||||
* Otherwise returns result of matching pattern Regex with filename.
|
||||
*/
|
||||
function matchesPatterns(
|
||||
context: ConfigContextNamed,
|
||||
context: ConfigContext,
|
||||
patterns: IgnoreList,
|
||||
dirname: string,
|
||||
allowNegation?: boolean = true,
|
||||
): boolean {
|
||||
const res = [];
|
||||
const strings = [];
|
||||
const fns = [];
|
||||
|
||||
patterns.forEach(pattern => {
|
||||
if (typeof pattern === "string") strings.push(pattern);
|
||||
else if (typeof pattern === "function") fns.push(pattern);
|
||||
else res.push(pattern);
|
||||
});
|
||||
|
||||
const filename = context.filename;
|
||||
if (res.some(re => re.test(context.filename))) return true;
|
||||
if (fns.some(fn => fn(filename))) return true;
|
||||
|
||||
if (strings.length > 0) {
|
||||
const possibleDirs = getPossibleDirs(context);
|
||||
|
||||
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,
|
||||
nonegate: !allowNegation,
|
||||
}).length > 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return patterns.some(pattern =>
|
||||
matchPattern(pattern, dirname, context.filename),
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
function matchPattern(pattern, dirname, pathToTest): boolean {
|
||||
if (typeof pattern === "function") return !!pattern(pathToTest);
|
||||
|
||||
if (typeof pathToTest !== "string") {
|
||||
throw new Error(
|
||||
`Configuration contains string/RegExp pattern, but no filename was passed to Babel`,
|
||||
);
|
||||
}
|
||||
|
||||
const getPossibleDirs = makeWeakCache((context: ConfigContextNamed) => {
|
||||
let current = context.filename;
|
||||
if (typeof current !== "string") return [];
|
||||
|
||||
const possibleDirs = [current];
|
||||
while (true) {
|
||||
const previous = current;
|
||||
current = path.dirname(current);
|
||||
if (previous === current) break;
|
||||
|
||||
possibleDirs.push(current);
|
||||
if (typeof pattern === "string") {
|
||||
pattern = pathPatternToRegex(pattern, dirname);
|
||||
}
|
||||
return pattern.test(pathToTest);
|
||||
}
|
||||
|
||||
return possibleDirs;
|
||||
});
|
||||
|
||||
@ -12,6 +12,7 @@ import {
|
||||
} from "../caching";
|
||||
import makeAPI from "../helpers/config-api";
|
||||
import { makeStaticFileCache } from "./utils";
|
||||
import pathPatternToRegex from "../pattern-to-regex";
|
||||
import type { FilePackageData, RelativeConfig, ConfigFile } from "./types";
|
||||
|
||||
const debug = buildDebug("babel:config:loading:files:configuration");
|
||||
@ -240,15 +241,24 @@ const readConfigJSON5 = makeStaticFileCache((filepath, content) => {
|
||||
});
|
||||
|
||||
const readIgnoreConfig = makeStaticFileCache((filepath, content) => {
|
||||
const ignore = content
|
||||
const ignoreDir = path.dirname(filepath);
|
||||
const ignorePatterns = content
|
||||
.split("\n")
|
||||
.map(line => line.replace(/#(.*?)$/, "").trim())
|
||||
.filter(line => !!line);
|
||||
|
||||
for (const pattern of ignorePatterns) {
|
||||
if (pattern[0] === "!") {
|
||||
throw new Error(`Negation of file paths is not supported.`);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
filepath,
|
||||
dirname: path.dirname(filepath),
|
||||
ignore,
|
||||
ignore: ignorePatterns.map(pattern =>
|
||||
pathPatternToRegex(pattern, ignoreDir),
|
||||
),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ export type ConfigFile = {
|
||||
export type IgnoreFile = {
|
||||
filepath: string,
|
||||
dirname: string,
|
||||
ignore: Array<string>,
|
||||
ignore: Array<RegExp>,
|
||||
};
|
||||
|
||||
export type RelativeConfig = {
|
||||
|
||||
51
packages/babel-core/src/config/pattern-to-regex.js
Normal file
51
packages/babel-core/src/config/pattern-to-regex.js
Normal file
@ -0,0 +1,51 @@
|
||||
// @flow
|
||||
import path from "path";
|
||||
import escapeRegExp from "lodash/escapeRegExp";
|
||||
|
||||
const sep = `\\${path.sep}`;
|
||||
const endSep = `(?:${sep}|$)`;
|
||||
|
||||
const substitution = `[^${sep}]+`;
|
||||
|
||||
const starPat = `(?:${substitution}${sep})`;
|
||||
const starPatLast = `(?:${substitution}${endSep})`;
|
||||
|
||||
const starStarPat = `${starPat}*?`;
|
||||
const starStarPatLast = `${starPat}*?${starPatLast}?`;
|
||||
|
||||
/**
|
||||
* Implement basic pattern matching that will allow users to do the simple
|
||||
* tests with * and **. If users want full complex pattern matching, then can
|
||||
* always use regex matching, or function validation.
|
||||
*/
|
||||
export default function pathToPattern(
|
||||
pattern: string,
|
||||
dirname: string,
|
||||
): RegExp {
|
||||
const parts = path.resolve(dirname, pattern).split(path.sep);
|
||||
|
||||
return new RegExp(
|
||||
[
|
||||
"^",
|
||||
...parts.map((part, i) => {
|
||||
const last = i === parts.length - 1;
|
||||
|
||||
// ** matches 0 or more path parts.
|
||||
if (part === "**") return last ? starStarPatLast : starStarPat;
|
||||
|
||||
// * matches 1 path part.
|
||||
if (part === "*") return last ? starPatLast : starPat;
|
||||
|
||||
// *.ext matches a wildcard with an extension.
|
||||
if (part.indexOf("*.") === 0) {
|
||||
return (
|
||||
substitution + escapeRegExp(part.slice(1)) + (last ? endSep : sep)
|
||||
);
|
||||
}
|
||||
|
||||
// Otherwise match the pattern text.
|
||||
return escapeRegExp(part) + (last ? endSep : sep);
|
||||
}),
|
||||
].join(""),
|
||||
);
|
||||
}
|
||||
@ -192,14 +192,14 @@ export function assertBabelrcSearch(
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((item, i) => {
|
||||
if (typeof item !== "string") {
|
||||
throw new Error(`.${key}[${i}] must be a string.`);
|
||||
if (!checkValidTest(value)) {
|
||||
throw new Error(`.${key}[${i}] must be a string/Function/RegExp.`);
|
||||
}
|
||||
});
|
||||
} else if (typeof value !== "string") {
|
||||
} else if (!checkValidTest(value)) {
|
||||
throw new Error(
|
||||
`.${key} must be a undefined, a boolean, a string, ` +
|
||||
`or an array of strings, got ${JSON.stringify(value)}`,
|
||||
`.${key} must be a undefined, a boolean, a string/Function/RegExp ` +
|
||||
`or an array of those, got ${JSON.stringify(value)}`,
|
||||
);
|
||||
}
|
||||
return (value: any);
|
||||
|
||||
@ -242,7 +242,7 @@ export type OverridesList = Array<ValidatedOptions>;
|
||||
export type ConfigApplicableTest = IgnoreItem | Array<IgnoreItem>;
|
||||
|
||||
export type ConfigFileSearch = string | boolean;
|
||||
export type BabelrcSearch = boolean | string | Array<string>;
|
||||
export type BabelrcSearch = boolean | IgnoreItem | IgnoreList;
|
||||
export type SourceMapsOption = boolean | "inline" | "both";
|
||||
export type SourceTypeOption = "module" | "script" | "unambiguous";
|
||||
export type CompactOption = boolean | "auto";
|
||||
|
||||
@ -5,11 +5,11 @@ import Plugin from "../lib/config/plugin";
|
||||
import generator from "@babel/generator";
|
||||
|
||||
function assertIgnored(result) {
|
||||
expect(result).toBeFalsy();
|
||||
expect(result).toBeNull();
|
||||
}
|
||||
|
||||
function assertNotIgnored(result) {
|
||||
expect(result.ignored).toBeFalsy();
|
||||
expect(result).not.toBeNull();
|
||||
}
|
||||
|
||||
function transform(code, opts) {
|
||||
@ -36,13 +36,11 @@ function transformFileSync(filename, opts) {
|
||||
});
|
||||
}
|
||||
|
||||
// shim
|
||||
function transformAsync(code, opts) {
|
||||
return {
|
||||
then: function(resolve) {
|
||||
resolve(transform(code, opts));
|
||||
},
|
||||
};
|
||||
return babel.transformAsync(code, {
|
||||
cwd: __dirname,
|
||||
...opts,
|
||||
});
|
||||
}
|
||||
|
||||
describe("parser and generator options", function() {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user