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",
|
"debug": "^3.1.0",
|
||||||
"json5": "^0.5.0",
|
"json5": "^0.5.0",
|
||||||
"lodash": "^4.17.5",
|
"lodash": "^4.17.5",
|
||||||
"micromatch": "^2.3.11",
|
|
||||||
"resolve": "^1.3.2",
|
"resolve": "^1.3.2",
|
||||||
"semver": "^5.4.1",
|
"semver": "^5.4.1",
|
||||||
"source-map": "^0.5.0"
|
"source-map": "^0.5.0"
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import micromatch from "micromatch";
|
|
||||||
import buildDebug from "debug";
|
import buildDebug from "debug";
|
||||||
import {
|
import {
|
||||||
validate,
|
validate,
|
||||||
@ -10,6 +9,7 @@ import {
|
|||||||
type ConfigApplicableTest,
|
type ConfigApplicableTest,
|
||||||
type BabelrcSearch,
|
type BabelrcSearch,
|
||||||
} from "./validation/options";
|
} from "./validation/options";
|
||||||
|
import pathPatternToRegex from "./pattern-to-regex";
|
||||||
|
|
||||||
const debug = buildDebug("babel:config:config-chain");
|
const debug = buildDebug("babel:config:config-chain");
|
||||||
|
|
||||||
@ -52,11 +52,6 @@ export type ConfigContext = {
|
|||||||
envName: string,
|
envName: string,
|
||||||
};
|
};
|
||||||
|
|
||||||
type ConfigContextNamed = {
|
|
||||||
...ConfigContext,
|
|
||||||
filename: string,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a config chain for a given preset.
|
* Build a config chain for a given preset.
|
||||||
*/
|
*/
|
||||||
@ -217,7 +212,7 @@ function babelrcLoadEnabled(
|
|||||||
|
|
||||||
const absoluteRoot = context.root;
|
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.
|
// loading in the standard root directory.
|
||||||
if (babelrcRoots === undefined) {
|
if (babelrcRoots === undefined) {
|
||||||
return pkgData.directories.indexOf(absoluteRoot) !== -1;
|
return pkgData.directories.indexOf(absoluteRoot) !== -1;
|
||||||
@ -225,15 +220,23 @@ function babelrcLoadEnabled(
|
|||||||
|
|
||||||
let babelrcPatterns = babelrcRoots;
|
let babelrcPatterns = babelrcRoots;
|
||||||
if (!Array.isArray(babelrcPatterns)) babelrcPatterns = [babelrcPatterns];
|
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.
|
// loading in the standard root directory.
|
||||||
if (babelrcPatterns.length === 1 && babelrcPatterns[0] === absoluteRoot) {
|
if (babelrcPatterns.length === 1 && babelrcPatterns[0] === absoluteRoot) {
|
||||||
return pkgData.directories.indexOf(absoluteRoot) !== -1;
|
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(
|
const validateConfigFile = makeWeakCache(
|
||||||
@ -583,20 +586,9 @@ function configFieldIsApplicable(
|
|||||||
test: ConfigApplicableTest,
|
test: ConfigApplicableTest,
|
||||||
dirname: string,
|
dirname: string,
|
||||||
): boolean {
|
): 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];
|
const patterns = Array.isArray(test) ? test : [test];
|
||||||
|
|
||||||
// Disabling negation here because it's a bit buggy from
|
return matchesPatterns(context, patterns, dirname);
|
||||||
// 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 */);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -608,43 +600,24 @@ function shouldIgnore(
|
|||||||
only: ?IgnoreList,
|
only: ?IgnoreList,
|
||||||
dirname: string,
|
dirname: string,
|
||||||
): boolean {
|
): boolean {
|
||||||
if (ignore) {
|
if (ignore && matchesPatterns(context, ignore, dirname)) {
|
||||||
if (typeof context.filename !== "string") {
|
debug(
|
||||||
throw new Error(
|
"Ignored %o because it matched one of %O from %o",
|
||||||
`Configuration contains ignore checks, but no filename was passed to Babel`,
|
context.filename,
|
||||||
);
|
ignore,
|
||||||
}
|
dirname,
|
||||||
// $FlowIgnore - Flow refinements aren't quite smart enough for this :(
|
);
|
||||||
const ctx: ConfigContextNamed = context;
|
return true;
|
||||||
if (matchesPatterns(ctx, ignore, dirname)) {
|
|
||||||
debug(
|
|
||||||
"Ignored %o because it matched one of %O from %o",
|
|
||||||
context.filename,
|
|
||||||
ignore,
|
|
||||||
dirname,
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (only) {
|
if (only && !matchesPatterns(context, only, dirname)) {
|
||||||
if (typeof context.filename !== "string") {
|
debug(
|
||||||
throw new Error(
|
"Ignored %o because it failed to match one of %O from %o",
|
||||||
`Configuration contains ignore checks, but no filename was passed to Babel`,
|
context.filename,
|
||||||
);
|
only,
|
||||||
}
|
dirname,
|
||||||
// $FlowIgnore - Flow refinements aren't quite smart enough for this :(
|
);
|
||||||
const ctx: ConfigContextNamed = context;
|
return true;
|
||||||
|
|
||||||
if (!matchesPatterns(ctx, only, dirname)) {
|
|
||||||
debug(
|
|
||||||
"Ignored %o because it failed to match one of %O from %o",
|
|
||||||
context.filename,
|
|
||||||
only,
|
|
||||||
dirname,
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -655,64 +628,26 @@ function shouldIgnore(
|
|||||||
* Otherwise returns result of matching pattern Regex with filename.
|
* Otherwise returns result of matching pattern Regex with filename.
|
||||||
*/
|
*/
|
||||||
function matchesPatterns(
|
function matchesPatterns(
|
||||||
context: ConfigContextNamed,
|
context: ConfigContext,
|
||||||
patterns: IgnoreList,
|
patterns: IgnoreList,
|
||||||
dirname: string,
|
dirname: string,
|
||||||
allowNegation?: boolean = true,
|
|
||||||
): boolean {
|
): boolean {
|
||||||
const res = [];
|
return patterns.some(pattern =>
|
||||||
const strings = [];
|
matchPattern(pattern, dirname, context.filename),
|
||||||
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 false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getPossibleDirs = makeWeakCache((context: ConfigContextNamed) => {
|
function matchPattern(pattern, dirname, pathToTest): boolean {
|
||||||
let current = context.filename;
|
if (typeof pattern === "function") return !!pattern(pathToTest);
|
||||||
if (typeof current !== "string") return [];
|
|
||||||
|
|
||||||
const possibleDirs = [current];
|
if (typeof pathToTest !== "string") {
|
||||||
while (true) {
|
throw new Error(
|
||||||
const previous = current;
|
`Configuration contains string/RegExp pattern, but no filename was passed to Babel`,
|
||||||
current = path.dirname(current);
|
);
|
||||||
if (previous === current) break;
|
|
||||||
|
|
||||||
possibleDirs.push(current);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return possibleDirs;
|
if (typeof pattern === "string") {
|
||||||
});
|
pattern = pathPatternToRegex(pattern, dirname);
|
||||||
|
}
|
||||||
|
return pattern.test(pathToTest);
|
||||||
|
}
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import {
|
|||||||
} from "../caching";
|
} from "../caching";
|
||||||
import makeAPI from "../helpers/config-api";
|
import makeAPI from "../helpers/config-api";
|
||||||
import { makeStaticFileCache } from "./utils";
|
import { makeStaticFileCache } from "./utils";
|
||||||
|
import pathPatternToRegex from "../pattern-to-regex";
|
||||||
import type { FilePackageData, RelativeConfig, ConfigFile } from "./types";
|
import type { FilePackageData, RelativeConfig, ConfigFile } from "./types";
|
||||||
|
|
||||||
const debug = buildDebug("babel:config:loading:files:configuration");
|
const debug = buildDebug("babel:config:loading:files:configuration");
|
||||||
@ -240,15 +241,24 @@ const readConfigJSON5 = makeStaticFileCache((filepath, content) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const readIgnoreConfig = makeStaticFileCache((filepath, content) => {
|
const readIgnoreConfig = makeStaticFileCache((filepath, content) => {
|
||||||
const ignore = content
|
const ignoreDir = path.dirname(filepath);
|
||||||
|
const ignorePatterns = content
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.map(line => line.replace(/#(.*?)$/, "").trim())
|
.map(line => line.replace(/#(.*?)$/, "").trim())
|
||||||
.filter(line => !!line);
|
.filter(line => !!line);
|
||||||
|
|
||||||
|
for (const pattern of ignorePatterns) {
|
||||||
|
if (pattern[0] === "!") {
|
||||||
|
throw new Error(`Negation of file paths is not supported.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
filepath,
|
filepath,
|
||||||
dirname: path.dirname(filepath),
|
dirname: path.dirname(filepath),
|
||||||
ignore,
|
ignore: ignorePatterns.map(pattern =>
|
||||||
|
pathPatternToRegex(pattern, ignoreDir),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export type ConfigFile = {
|
|||||||
export type IgnoreFile = {
|
export type IgnoreFile = {
|
||||||
filepath: string,
|
filepath: string,
|
||||||
dirname: string,
|
dirname: string,
|
||||||
ignore: Array<string>,
|
ignore: Array<RegExp>,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RelativeConfig = {
|
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)) {
|
if (Array.isArray(value)) {
|
||||||
value.forEach((item, i) => {
|
value.forEach((item, i) => {
|
||||||
if (typeof item !== "string") {
|
if (!checkValidTest(value)) {
|
||||||
throw new Error(`.${key}[${i}] must be a string.`);
|
throw new Error(`.${key}[${i}] must be a string/Function/RegExp.`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else if (typeof value !== "string") {
|
} else if (!checkValidTest(value)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`.${key} must be a undefined, a boolean, a string, ` +
|
`.${key} must be a undefined, a boolean, a string/Function/RegExp ` +
|
||||||
`or an array of strings, got ${JSON.stringify(value)}`,
|
`or an array of those, got ${JSON.stringify(value)}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (value: any);
|
return (value: any);
|
||||||
|
|||||||
@ -242,7 +242,7 @@ export type OverridesList = Array<ValidatedOptions>;
|
|||||||
export type ConfigApplicableTest = IgnoreItem | Array<IgnoreItem>;
|
export type ConfigApplicableTest = IgnoreItem | Array<IgnoreItem>;
|
||||||
|
|
||||||
export type ConfigFileSearch = string | boolean;
|
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 SourceMapsOption = boolean | "inline" | "both";
|
||||||
export type SourceTypeOption = "module" | "script" | "unambiguous";
|
export type SourceTypeOption = "module" | "script" | "unambiguous";
|
||||||
export type CompactOption = boolean | "auto";
|
export type CompactOption = boolean | "auto";
|
||||||
|
|||||||
@ -5,11 +5,11 @@ import Plugin from "../lib/config/plugin";
|
|||||||
import generator from "@babel/generator";
|
import generator from "@babel/generator";
|
||||||
|
|
||||||
function assertIgnored(result) {
|
function assertIgnored(result) {
|
||||||
expect(result).toBeFalsy();
|
expect(result).toBeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
function assertNotIgnored(result) {
|
function assertNotIgnored(result) {
|
||||||
expect(result.ignored).toBeFalsy();
|
expect(result).not.toBeNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
function transform(code, opts) {
|
function transform(code, opts) {
|
||||||
@ -36,13 +36,11 @@ function transformFileSync(filename, opts) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// shim
|
|
||||||
function transformAsync(code, opts) {
|
function transformAsync(code, opts) {
|
||||||
return {
|
return babel.transformAsync(code, {
|
||||||
then: function(resolve) {
|
cwd: __dirname,
|
||||||
resolve(transform(code, opts));
|
...opts,
|
||||||
},
|
});
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe("parser and generator options", function() {
|
describe("parser and generator options", function() {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user