Skip to content

Commit

Permalink
Allow negation of ignore and only patterns. (#5625)
Browse files Browse the repository at this point in the history
  • Loading branch information
loganfsmyth committed Apr 12, 2017
1 parent 2ea3338 commit d1c954b
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 43 deletions.
86 changes: 43 additions & 43 deletions packages/babel-core/src/config/build-config-chain.js
Expand Up @@ -46,63 +46,63 @@ class ConfigChainBuilder {
): boolean {
if (!this.filename) return false;

if (ignore) {
if (!Array.isArray(ignore)) {
throw new Error(`.ignore should be an array, was ${JSON.stringify(ignore)}`);
}

for (const pattern of ignore) {
if (this.matchesPattern(pattern, dirname)) return true;
}
if (ignore && !Array.isArray(ignore)) {
throw new Error(`.ignore should be an array, ${JSON.stringify(ignore)} given`);
}

if (only) {
if (!Array.isArray(only)) {
throw new Error(`.only should be an array, was ${JSON.stringify(only)}`);
}

for (const pattern of only) {
if (this.matchesPattern(pattern, dirname)) return false;
}
return true;
if (only && !Array.isArray(only)) {
throw new Error(`.only should be an array, ${JSON.stringify(only)} given`);
}

return false;
return (ignore && this.matchesPatterns(ignore, dirname)) ||
(only && !this.matchesPatterns(only, dirname));
}

/**
* Returns result of calling function with filename if pattern is a function.
* Otherwise returns result of matching pattern Regex with filename.
*/
matchesPattern(pattern: string | Function | RegExp, dirname: string) {
if (typeof pattern === "string") {
// Lazy-init so we don't initialize this for files that have no glob patterns.
if (!this.possibleDirs) {
this.possibleDirs = [];

if (this.filename) {
this.possibleDirs.push(this.filename);

let current = this.filename;
while (true) {
const previous = current;
current = path.dirname(current);
if (previous === current) break;

this.possibleDirs.push(current);
}
matchesPatterns(patterns: Array<string | Function | RegExp>, dirname: string) {
const res = [];
const strings = [];
const fns = [];

patterns.forEach((pattern) => {
const type = typeof pattern;
if (type === "string") strings.push(pattern);
else if (type === "function") fns.push(pattern);
else res.push(pattern);
});

// Lazy-init so we don't initialize this for files that have no glob patterns.
if (strings.length > 0 && !this.possibleDirs) {
this.possibleDirs = [];

if (this.filename) {
this.possibleDirs.push(this.filename);

let current = this.filename;
while (true) {
const previous = current;
current = path.dirname(current);
if (previous === current) break;

this.possibleDirs.push(current);
}
}
}

return res.some((re) => re.test(this.filename)) ||
fns.some((fn) => fn(this.filename)) ||
this.possibleDirs.some(micromatch.filter(strings.map((pattern) => {
// Preserve the "!" prefix so that micromatch can use it for negation.
const negate = pattern[0] === "!";
if (negate) pattern = pattern.slice(1);

return this.possibleDirs.some(micromatch.filter(path.resolve(dirname, pattern), {
return (negate ? "!" : "") + path.resolve(dirname, pattern);
}, {
nocase: true,
nonegate: true,
}));
} else if (typeof pattern === "function") {
return pattern(this.filename);
} else {
return pattern.test(this.filename);
}
})));
}

findConfigs(loc: string) {
Expand Down
98 changes: 98 additions & 0 deletions packages/babel-core/test/config-chain.js
Expand Up @@ -557,6 +557,104 @@ describe("buildConfigChain", function () {
assert.deepEqual(chain, expected);
});

it("should not ignore file matching negated file pattern", function () {
const chain = buildConfigChain({
filename: fixture("ignore-negate", "src.js"),
});

const expected = [
{
type: "options",
options: {
ignore: [
"root-ignore",
],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
dirname: fixture(),
},
{
type: "options",
options: {
ignore: [
"*",
"!src.js",
],
},
alias: fixture("ignore-negate", ".babelrc"),
loc: fixture("ignore-negate", ".babelrc"),
dirname: fixture("ignore-negate"),
},
{
type: "arguments",
options: {
filename: fixture("ignore-negate", "src.js"),
},
alias: "base",
loc: "base",
dirname: base(),
},
];

assert.deepEqual(chain, expected);

const chain2 = buildConfigChain({
filename: fixture("ignore-negate", "src2.js"),
});

assert.equal(chain2, null);
});

it("should not ignore file matching negated folder pattern", function () {
const chain = buildConfigChain({
filename: fixture("ignore-negate-folder", "folder", "src.js"),
});

const expected = [
{
type: "options",
options: {
ignore: [
"root-ignore",
],
},
alias: fixture(".babelignore"),
loc: fixture(".babelignore"),
dirname: fixture(),
},
{
type: "options",
options: {
ignore: [
"*",
"!folder",
],
},
alias: fixture("ignore-negate-folder", ".babelrc"),
loc: fixture("ignore-negate-folder", ".babelrc"),
dirname: fixture("ignore-negate-folder"),
},
{
type: "arguments",
options: {
filename: fixture("ignore-negate-folder", "folder", "src.js"),
},
alias: "base",
loc: "base",
dirname: base(),
},
];

assert.deepEqual(chain, expected);

const chain2 = buildConfigChain({
filename: fixture("ignore-negate-folder", "src2.js"),
});

assert.equal(chain2, null);
});

it("js-json-config - should throw an error if both a .babelrc" +
" and a .babelrc.js are present", function () {
assert.throws(
Expand Down
@@ -0,0 +1,6 @@
{
ignore: [
"*",
"!folder",
],
}
@@ -0,0 +1,2 @@
# Blank .gitignore to ensure this directory exists.
!.gitignore
@@ -0,0 +1,6 @@
{
ignore: [
"*",
"!src.js",
],
}

0 comments on commit d1c954b

Please sign in to comment.