From d1c954b36f3a1d59aa579e1e5a1ba4960625a54d Mon Sep 17 00:00:00 2001 From: Logan Smyth Date: Wed, 12 Apr 2017 11:10:33 -0700 Subject: [PATCH] Allow negation of ignore and only patterns. (#5625) --- .../src/config/build-config-chain.js | 82 ++++++++-------- packages/babel-core/test/config-chain.js | 98 +++++++++++++++++++ .../config/ignore-negate-folder/.babelrc | 6 ++ .../ignore-negate-folder/folder/.gitignore | 2 + .../fixtures/config/ignore-negate/.babelrc | 6 ++ 5 files changed, 153 insertions(+), 41 deletions(-) create mode 100644 packages/babel-core/test/fixtures/config/ignore-negate-folder/.babelrc create mode 100644 packages/babel-core/test/fixtures/config/ignore-negate-folder/folder/.gitignore create mode 100644 packages/babel-core/test/fixtures/config/ignore-negate/.babelrc diff --git a/packages/babel-core/src/config/build-config-chain.js b/packages/babel-core/src/config/build-config-chain.js index e560eeedfd..6b92b9086e 100644 --- a/packages/babel-core/src/config/build-config-chain.js +++ b/packages/babel-core/src/config/build-config-chain.js @@ -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 = []; + matchesPatterns(patterns: Array, dirname: string) { + const res = []; + const strings = []; + const fns = []; - if (this.filename) { - this.possibleDirs.push(this.filename); + patterns.forEach((pattern) => { + const type = typeof pattern; + if (type === "string") strings.push(pattern); + else if (type === "function") fns.push(pattern); + else res.push(pattern); + }); - let current = this.filename; - while (true) { - const previous = current; - current = path.dirname(current); - if (previous === current) break; + // Lazy-init so we don't initialize this for files that have no glob patterns. + if (strings.length > 0 && !this.possibleDirs) { + this.possibleDirs = []; - this.possibleDirs.push(current); - } + 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 this.possibleDirs.some(micromatch.filter(path.resolve(dirname, pattern), { - nocase: true, - nonegate: true, - })); - } else if (typeof pattern === "function") { - return pattern(this.filename); - } else { - return pattern.test(this.filename); } + + 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 (negate ? "!" : "") + path.resolve(dirname, pattern); + }, { + nocase: true, + }))); } findConfigs(loc: string) { diff --git a/packages/babel-core/test/config-chain.js b/packages/babel-core/test/config-chain.js index 6f3461cf1e..1aeed5f4d0 100644 --- a/packages/babel-core/test/config-chain.js +++ b/packages/babel-core/test/config-chain.js @@ -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( diff --git a/packages/babel-core/test/fixtures/config/ignore-negate-folder/.babelrc b/packages/babel-core/test/fixtures/config/ignore-negate-folder/.babelrc new file mode 100644 index 0000000000..dfee3683a4 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/ignore-negate-folder/.babelrc @@ -0,0 +1,6 @@ +{ + ignore: [ + "*", + "!folder", + ], +} diff --git a/packages/babel-core/test/fixtures/config/ignore-negate-folder/folder/.gitignore b/packages/babel-core/test/fixtures/config/ignore-negate-folder/folder/.gitignore new file mode 100644 index 0000000000..b65b769d49 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/ignore-negate-folder/folder/.gitignore @@ -0,0 +1,2 @@ +# Blank .gitignore to ensure this directory exists. +!.gitignore diff --git a/packages/babel-core/test/fixtures/config/ignore-negate/.babelrc b/packages/babel-core/test/fixtures/config/ignore-negate/.babelrc new file mode 100644 index 0000000000..301a5ac2b1 --- /dev/null +++ b/packages/babel-core/test/fixtures/config/ignore-negate/.babelrc @@ -0,0 +1,6 @@ +{ + ignore: [ + "*", + "!src.js", + ], +}