From afb10e60409328e56aa428b7e58baee992f3e2d0 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Fri, 30 Sep 2022 13:40:42 -0700 Subject: [PATCH 01/15] feat: Swap out Globby for custom globbing solution. Removes globby due to numerous issues with ignoring files and returning the correct files. Fixes #16354 Fixes #16340 Fixes #16300 --- lib/eslint/eslint-helpers.js | 130 +++++++++++++++++++++++++++++--- package.json | 4 +- tests/lib/eslint/flat-eslint.js | 3 +- 3 files changed, 123 insertions(+), 14 deletions(-) diff --git a/lib/eslint/eslint-helpers.js b/lib/eslint/eslint-helpers.js index e257310f6e9..c2eb1f3c5c7 100644 --- a/lib/eslint/eslint-helpers.js +++ b/lib/eslint/eslint-helpers.js @@ -13,9 +13,16 @@ const path = require("path"); const fs = require("fs"); const fsp = fs.promises; const isGlob = require("is-glob"); -const globby = require("globby"); const hash = require("../cli-engine/hash"); const minimatch = require("minimatch"); +const util = require("util"); +const fswalk = require("@nodelib/fs.walk"); + +//----------------------------------------------------------------------------- +// Fix fswalk +//----------------------------------------------------------------------------- + +const doFsWalk = util.promisify(fswalk.walk); //----------------------------------------------------------------------------- // Errors @@ -97,6 +104,105 @@ function isGlobPattern(pattern) { return isGlob(path.sep === "\\" ? normalizeToPosix(pattern) : pattern); } +/** + * Searches a directory looking for matching glob patterns. This uses + * the config array's logic to determine if a directory or file should + * be ignored, so it is consistent with how ignoring works throughout + * ESLint. + * @param {Object} options The options for this function. + * @param {string} options.cwd The directory to search. + * @param {Array} options.patterns An array of glob patterns + * to match. + * @param {FlatConfigArray} options.configs The config array to use for + * determining what to ignore. + * @returns {Promise>} An array of matching file paths + * or an empty array if there are no matches. + */ +async function globSearch({ cwd, patterns, configs }) { + + if (patterns.length === 0) { + return []; + } + + const matchers = patterns.map(pattern => new minimatch.Minimatch(pattern)); + + return (await doFsWalk(cwd, { + + deepFilter(entry) { + return !configs.isDirectoryIgnored(entry.path); + }, + + entryFilter(entry) { + + // entries may be directories or files so filter out directories + if (entry.dirent.isDirectory()) { + return false; + } + + const posixName = normalizeToPosix(path.relative(cwd, entry.path)); + const matchesPattern = matchers.some(matcher => { + + /* + * Patterns can either be relative, like `foo/bar` or + * absolute like `c:/foo/bar/**` and so we need to apply + * the match either against the relative or absolute filename, + * respectively. + */ + if (path.isAbsolute(matcher.pattern)) { + return matcher.match(entry.path); + } + + return matcher.match(posixName); + }); + + return matchesPattern && !configs.isFileIgnored(entry.path); + } + })).map(entry => entry.path); + +} + +/** + * Determines if a given glob pattern will return any results. + * Used primarily to help with useful error messages. + * @param {Object} options The options for the function. + * @param {string} options.cwd The directory to search. + * @param {string} options.pattern A glob pattern to match. + * @returns {Promise} True if there is a glob match, false if not. + */ +async function globMatch({ cwd, pattern }) { + + let found = false; + + const fsWalkSettings = { + + deepFilter() { + return !found; + }, + + entryFilter(entry) { + if (found) { + return false; + } + + const posixName = normalizeToPosix(path.relative(cwd, entry.path)); + + if (minimatch(path.isAbsolute(pattern) ? entry.path : posixName, pattern)) { + found = true; + return true; + } + + return false; + } + }; + + /* eslint-disable-next-line no-unreachable-loop -- Don't need the value */ + for await (const entry of fswalk.walkStream(cwd, fsWalkSettings)) { + return true; + } + + return false; +} + /** * Finds all files matching the options specified. * @param {Object} args The arguments objects. @@ -226,32 +332,34 @@ async function findFiles({ }); // note: globbyPatterns can be an empty array - const globbyResults = (await globby(globbyPatterns, { + const globbyResults = await globSearch({ cwd, - absolute: true, - ignore: configs.ignores.filter(matcher => typeof matcher === "string") - })); + patterns: globbyPatterns, + configs, + shouldIgnore: true + }); // if there are no results, tell the user why if (!results.length && !globbyResults.length) { // try globby without ignoring anything - /* eslint-disable no-unreachable-loop -- We want to exit early. */ for (const globbyPattern of globbyPatterns) { - /* eslint-disable-next-line no-unused-vars -- Want to exit early. */ - for await (const filePath of globby.stream(globbyPattern, { cwd, absolute: true })) { + // check if there are any matches at all + const patternHasMatch = await globMatch({ + cwd, + pattern: globbyPattern + }); - // files were found but ignored + if (patternHasMatch) { throw new AllFilesIgnoredError(globbyPattern); } - // no files were found + // otherwise no files were found if (errorOnUnmatchedPattern) { throw new NoFilesFoundError(globbyPattern, globInputPaths); } } - /* eslint-enable no-unreachable-loop -- Go back to normal. */ } diff --git a/package.json b/package.json index 9a0665d1ad2..28ef51c0fa4 100644 --- a/package.json +++ b/package.json @@ -56,8 +56,9 @@ "bugs": "https://github.com/eslint/eslint/issues/", "dependencies": { "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.10.5", + "@humanwhocodes/config-array": "^0.11.1", "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -75,7 +76,6 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.1", "globals": "^13.15.0", - "globby": "^11.1.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", diff --git a/tests/lib/eslint/flat-eslint.js b/tests/lib/eslint/flat-eslint.js index f3f8b06dc01..54ebfd33b93 100644 --- a/tests/lib/eslint/flat-eslint.js +++ b/tests/lib/eslint/flat-eslint.js @@ -980,7 +980,8 @@ describe("FlatESLint", () => { it("should throw an error when given a directory with all eslint excluded files in the directory", async () => { eslint = new FlatESLint({ - overrideConfigFile: getFixturePath("eslint.config_with_ignores.js") + cwd: getFixturePath(), + ignorePath: getFixturePath(".eslintignore") }); await assert.rejects(async () => { From e595cc8a529074e855133a490326c5ef98fc46ee Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Mon, 3 Oct 2022 11:17:44 -0700 Subject: [PATCH 02/15] Fix failing test --- lib/config/default-config.js | 2 +- tests/lib/cli.js | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/config/default-config.js b/lib/config/default-config.js index c48551a4f2a..a99923185bf 100644 --- a/lib/config/default-config.js +++ b/lib/config/default-config.js @@ -52,7 +52,7 @@ exports.defaultConfig = [ { ignores: [ "**/node_modules/**", - ".git/**" + "**/.git" ] }, diff --git a/tests/lib/cli.js b/tests/lib/cli.js index 475a522187a..af43c737aa3 100644 --- a/tests/lib/cli.js +++ b/tests/lib/cli.js @@ -160,17 +160,6 @@ describe("cli", () => { }); }); - describe("when given a config file and a directory of files", () => { - it(`should load and execute without error with configType:${configType}`, async () => { - const configPath = getFixturePath("configurations", "semi-error.js"); - const filePath = getFixturePath("formatters"); - const code = `--config ${configPath} ${filePath}`; - const exitStatus = await cli.execute(code, null, useFlatConfig); - - assert.strictEqual(exitStatus, 0); - }); - }); - describe("when there is a local config file", () => { it(`should load the local config file with configType:${configType}`, async () => { @@ -460,6 +449,17 @@ describe("cli", () => { process.cwd = originalCwd; }); + describe("when given a config file and a directory of files", () => { + it(`should load and execute without error with configType:${configType}`, async () => { + const configPath = getFixturePath("configurations", "semi-error.js"); + const filePath = getFixturePath("formatters"); + const code = `--no-ignore --config ${configPath} ${filePath}`; + const exitStatus = await cli.execute(code, null, useFlatConfig); + + assert.strictEqual(exitStatus, 0); + }); + }); + describe("when executing with global flag", () => { it(`should default defined variables to read-only with configType:${configType}`, async () => { From 0ef41f0139e2feaa54d44448e652edec07958008 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Mon, 3 Oct 2022 11:35:48 -0700 Subject: [PATCH 03/15] Add test for 16300 --- tests/fixtures/ignores-relative/a.js | 0 tests/fixtures/ignores-relative/eslint.config.js | 5 +++++ tests/fixtures/ignores-relative/subdir/a.js | 0 tests/lib/eslint/flat-eslint.js | 13 +++++++++++++ 4 files changed, 18 insertions(+) create mode 100644 tests/fixtures/ignores-relative/a.js create mode 100644 tests/fixtures/ignores-relative/eslint.config.js create mode 100644 tests/fixtures/ignores-relative/subdir/a.js diff --git a/tests/fixtures/ignores-relative/a.js b/tests/fixtures/ignores-relative/a.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/fixtures/ignores-relative/eslint.config.js b/tests/fixtures/ignores-relative/eslint.config.js new file mode 100644 index 00000000000..41032a96ad1 --- /dev/null +++ b/tests/fixtures/ignores-relative/eslint.config.js @@ -0,0 +1,5 @@ +module.exports = [ + { + ignores: ["a.js"] + } +]; diff --git a/tests/fixtures/ignores-relative/subdir/a.js b/tests/fixtures/ignores-relative/subdir/a.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/lib/eslint/flat-eslint.js b/tests/lib/eslint/flat-eslint.js index 54ebfd33b93..2a3bd783974 100644 --- a/tests/lib/eslint/flat-eslint.js +++ b/tests/lib/eslint/flat-eslint.js @@ -1100,6 +1100,19 @@ describe("FlatESLint", () => { assert.strictEqual(results[0].messages[1].severity, 2); assert.strictEqual(results[0].suppressedMessages.length, 0); }); + + // https://github.com/eslint/eslint/issues/16300 + it("should process ignore patterns relative to basePath not cwd", async () => { + eslint = new FlatESLint({ + cwd: getFixturePath("ignores-relative/subdir") + }); + const results = await eslint.lintFiles(["**/*.js"]); + + assert.strictEqual(results.length, 1); + assert.strictEqual(results[0].filePath, getFixturePath("ignores-relative/subdir/a.js")); + }); + + }); From 324fc0a2057a7c89fee5a97f8deee2bdb459e1bf Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Mon, 3 Oct 2022 14:42:04 -0700 Subject: [PATCH 04/15] Make more tests pass --- lib/config/default-config.js | 2 +- lib/eslint/eslint-helpers.js | 2 +- package.json | 2 +- .../ignores-directory/eslint.config.js | 3 +++ .../ignores-directory/subdir/subsubdir/a.js | 0 tests/lib/eslint/flat-eslint.js | 20 +++++++++++++++++++ 6 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 tests/fixtures/ignores-directory/eslint.config.js create mode 100644 tests/fixtures/ignores-directory/subdir/subsubdir/a.js diff --git a/lib/config/default-config.js b/lib/config/default-config.js index a99923185bf..44dc48bc9ce 100644 --- a/lib/config/default-config.js +++ b/lib/config/default-config.js @@ -52,7 +52,7 @@ exports.defaultConfig = [ { ignores: [ "**/node_modules/**", - "**/.git" + ".git/" ] }, diff --git a/lib/eslint/eslint-helpers.js b/lib/eslint/eslint-helpers.js index c2eb1f3c5c7..6384c2bd7d4 100644 --- a/lib/eslint/eslint-helpers.js +++ b/lib/eslint/eslint-helpers.js @@ -248,7 +248,7 @@ async function findFiles({ if (stat.isFile()) { results.push({ filePath, - ignored: configs.isIgnored(filePath) + ignored: configs.isFileIgnored(filePath) }); } diff --git a/package.json b/package.json index 28ef51c0fa4..fa25f6f0e53 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "bugs": "https://github.com/eslint/eslint/issues/", "dependencies": { "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.1", + "@humanwhocodes/config-array": "^0.11.2", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", diff --git a/tests/fixtures/ignores-directory/eslint.config.js b/tests/fixtures/ignores-directory/eslint.config.js new file mode 100644 index 00000000000..25d0cef4bcb --- /dev/null +++ b/tests/fixtures/ignores-directory/eslint.config.js @@ -0,0 +1,3 @@ +module.exports = { + ignores: ["subdir/subsubdir"] +}; diff --git a/tests/fixtures/ignores-directory/subdir/subsubdir/a.js b/tests/fixtures/ignores-directory/subdir/subsubdir/a.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/lib/eslint/flat-eslint.js b/tests/lib/eslint/flat-eslint.js index 2a3bd783974..0c16bc5cc99 100644 --- a/tests/lib/eslint/flat-eslint.js +++ b/tests/lib/eslint/flat-eslint.js @@ -1113,6 +1113,26 @@ describe("FlatESLint", () => { }); + // https://github.com/eslint/eslint/issues/16354 + it.only("should skip subdirectory files when ignore pattern matches subdirectory", async () => { + eslint = new FlatESLint({ + cwd: getFixturePath("ignores-directory") + }); + + await assert.rejects(async () => { + await eslint.lintFiles(["subdir/**"]); + }, /All files matched by 'subdir\/\*\*' are ignored\./u); + + await assert.rejects(async () => { + await eslint.lintFiles(["subdir/subsubdir/**"]); + }, /All files matched by 'subdir\/subsubdir\/\*\*' are ignored\./u); + + await assert.rejects(async () => { + await eslint.lintFiles(["subdir/subsubdir/a.js"]); + }, /All files matched by 'subdir\/subsubdir\/a.js' are ignored\./u); + }); + + }); From 15fc4b6a4e5fbeb13182d3e4af25a37872c5fb83 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 4 Oct 2022 10:34:17 -0700 Subject: [PATCH 05/15] Fix another test --- tests/lib/eslint/flat-eslint.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/lib/eslint/flat-eslint.js b/tests/lib/eslint/flat-eslint.js index 0c16bc5cc99..583a7c4b974 100644 --- a/tests/lib/eslint/flat-eslint.js +++ b/tests/lib/eslint/flat-eslint.js @@ -1114,7 +1114,7 @@ describe("FlatESLint", () => { // https://github.com/eslint/eslint/issues/16354 - it.only("should skip subdirectory files when ignore pattern matches subdirectory", async () => { + it("should skip subdirectory files when ignore pattern matches subdirectory", async () => { eslint = new FlatESLint({ cwd: getFixturePath("ignores-directory") }); @@ -1127,9 +1127,13 @@ describe("FlatESLint", () => { await eslint.lintFiles(["subdir/subsubdir/**"]); }, /All files matched by 'subdir\/subsubdir\/\*\*' are ignored\./u); - await assert.rejects(async () => { - await eslint.lintFiles(["subdir/subsubdir/a.js"]); - }, /All files matched by 'subdir\/subsubdir\/a.js' are ignored\./u); + const results = await eslint.lintFiles(["subdir/subsubdir/a.js"]); + + assert.strictEqual(results.length, 1); + assert.strictEqual(results[0].filePath, getFixturePath("ignores-directory/subdir/subsubdir/a.js")); + assert.strictEqual(results[0].warningCount, 1); + assert(results[0].messages[0].message.startsWith("File ignored"), "Should contain file ignored warning"); + }); From c447b9fa3b6a19c755234610b4b183143da95193 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 4 Oct 2022 10:43:47 -0700 Subject: [PATCH 06/15] Add another test --- tests/fixtures/ignores-self/eslint.config.js | 3 +++ tests/lib/eslint/flat-eslint.js | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/fixtures/ignores-self/eslint.config.js diff --git a/tests/fixtures/ignores-self/eslint.config.js b/tests/fixtures/ignores-self/eslint.config.js new file mode 100644 index 00000000000..35f93ee5df3 --- /dev/null +++ b/tests/fixtures/ignores-self/eslint.config.js @@ -0,0 +1,3 @@ +module.exports = { + ignores: ["**/ignores-self/**"] +}; diff --git a/tests/lib/eslint/flat-eslint.js b/tests/lib/eslint/flat-eslint.js index 583a7c4b974..3d895f5ec13 100644 --- a/tests/lib/eslint/flat-eslint.js +++ b/tests/lib/eslint/flat-eslint.js @@ -1136,6 +1136,21 @@ describe("FlatESLint", () => { }); + // https://github.com/eslint/eslint/issues/16340 + it("should lint files even when cwd directory name matches ignores pattern", async () => { + eslint = new FlatESLint({ + cwd: getFixturePath("ignores-self") + }); + + const results = await eslint.lintFiles(["*.js"]); + + assert.strictEqual(results.length, 1); + assert.strictEqual(results[0].filePath, getFixturePath("ignores-self/eslint.config.js")); + assert.strictEqual(results[0].errorCount, 0); + assert.strictEqual(results[0].warningCount, 0); + + }); + }); From 15e0f79de9722f6219c632bca9771965cd7f60a9 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 4 Oct 2022 10:57:17 -0700 Subject: [PATCH 07/15] Remove old test --- tests/lib/eslint/flat-eslint.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/lib/eslint/flat-eslint.js b/tests/lib/eslint/flat-eslint.js index 3d895f5ec13..721710ade1b 100644 --- a/tests/lib/eslint/flat-eslint.js +++ b/tests/lib/eslint/flat-eslint.js @@ -978,17 +978,6 @@ describe("FlatESLint", () => { }, /All files matched by 'node_modules\/\*\*\/\*\.js' are ignored\./u); }); - it("should throw an error when given a directory with all eslint excluded files in the directory", async () => { - eslint = new FlatESLint({ - cwd: getFixturePath(), - ignorePath: getFixturePath(".eslintignore") - }); - - await assert.rejects(async () => { - await eslint.lintFiles([getFixturePath("./cli-engine/")]); - }, /All files matched by '.*?cli-engine[\\/]\*\*[\\/]\*\.js' are ignored/u); - }); - it("should throw an error when all given files are ignored", async () => { eslint = new FlatESLint({ overrideConfigFile: getFixturePath("eslint.config_with_ignores.js") From 2e937a2d0fb45270009086d0c31e4e26b8877737 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 4 Oct 2022 10:59:55 -0700 Subject: [PATCH 08/15] Fix cli tests --- tests/lib/cli.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/lib/cli.js b/tests/lib/cli.js index af43c737aa3..e9d6c8efb2d 100644 --- a/tests/lib/cli.js +++ b/tests/lib/cli.js @@ -755,22 +755,22 @@ describe("cli", () => { }); if (useFlatConfig) { - it("should not ignore files if the pattern is a path to a directory (with trailing slash)", async () => { + it("should ignore files if the pattern is a path to a directory (with trailing slash)", async () => { const filePath = getFixturePath("cli/syntax-error.js"); const exit = await cli.execute(`--ignore-pattern cli/ ${filePath}`, null, true); // parsing error causes exit code 1 assert.isTrue(log.info.called); - assert.strictEqual(exit, 1); + assert.strictEqual(exit, 0); }); - it("should not ignore files if the pattern is a path to a directory (without trailing slash)", async () => { + it("should ignore files if the pattern is a path to a directory (without trailing slash)", async () => { const filePath = getFixturePath("cli/syntax-error.js"); const exit = await cli.execute(`--ignore-pattern cli ${filePath}`, null, true); // parsing error causes exit code 1 assert.isTrue(log.info.called); - assert.strictEqual(exit, 1); + assert.strictEqual(exit, 0); }); } }); From 24a9cef242b0c85bcdb39bd56d7171ed7f86a04c Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 4 Oct 2022 11:35:30 -0700 Subject: [PATCH 09/15] Bump up Mocha timeout for Node 18 --- Makefile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.js b/Makefile.js index 64b52457943..df8a207b86d 100644 --- a/Makefile.js +++ b/Makefile.js @@ -86,7 +86,7 @@ const NODE = "node ", // intentional extra space PERF_MULTIFILES_TARGETS = `"${TEMP_DIR}eslint/performance/eslint/{lib,tests/lib}/**/*.js"`, // Settings - MOCHA_TIMEOUT = parseInt(process.env.ESLINT_MOCHA_TIMEOUT, 10) || 10000; + MOCHA_TIMEOUT = parseInt(process.env.ESLINT_MOCHA_TIMEOUT, 10) || 15000; //------------------------------------------------------------------------------ // Helpers From 371b4ebadefaa4beb9416c78c4fe03e03c166f6a Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 4 Oct 2022 11:41:07 -0700 Subject: [PATCH 10/15] Revert timeout bump --- Makefile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.js b/Makefile.js index df8a207b86d..64b52457943 100644 --- a/Makefile.js +++ b/Makefile.js @@ -86,7 +86,7 @@ const NODE = "node ", // intentional extra space PERF_MULTIFILES_TARGETS = `"${TEMP_DIR}eslint/performance/eslint/{lib,tests/lib}/**/*.js"`, // Settings - MOCHA_TIMEOUT = parseInt(process.env.ESLINT_MOCHA_TIMEOUT, 10) || 15000; + MOCHA_TIMEOUT = parseInt(process.env.ESLINT_MOCHA_TIMEOUT, 10) || 10000; //------------------------------------------------------------------------------ // Helpers From 6814258a9f88ba8cd1171473f93a3f29a646ba6e Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 4 Oct 2022 16:50:39 -0700 Subject: [PATCH 11/15] Manually use stream --- lib/eslint/eslint-helpers.js | 75 +++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/lib/eslint/eslint-helpers.js b/lib/eslint/eslint-helpers.js index 6384c2bd7d4..f89177bfe9f 100644 --- a/lib/eslint/eslint-helpers.js +++ b/lib/eslint/eslint-helpers.js @@ -24,6 +24,23 @@ const fswalk = require("@nodelib/fs.walk"); const doFsWalk = util.promisify(fswalk.walk); +/* + * function doFsWalk(a, b) { + * return new Promise((resolve, reject) => { + * fswalk.walk(a, b, (err, entries) => { + * if (err) { + * reject(err); + * return; + * } + */ + +/* + * resolve(entries); + * }); + * }); + * } + */ + //----------------------------------------------------------------------------- // Errors //----------------------------------------------------------------------------- @@ -128,32 +145,22 @@ async function globSearch({ cwd, patterns, configs }) { return (await doFsWalk(cwd, { + concurrency: 1, deepFilter(entry) { - return !configs.isDirectoryIgnored(entry.path); - }, + const relativePath = normalizeToPosix(path.relative(cwd, entry.path)); + const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true)); + return matchesPattern && !configs.isDirectoryIgnored(entry.path); + }, entryFilter(entry) { + const relativePath = normalizeToPosix(path.relative(cwd, entry.path)); // entries may be directories or files so filter out directories if (entry.dirent.isDirectory()) { return false; } - const posixName = normalizeToPosix(path.relative(cwd, entry.path)); - const matchesPattern = matchers.some(matcher => { - - /* - * Patterns can either be relative, like `foo/bar` or - * absolute like `c:/foo/bar/**` and so we need to apply - * the match either against the relative or absolute filename, - * respectively. - */ - if (path.isAbsolute(matcher.pattern)) { - return matcher.match(entry.path); - } - - return matcher.match(posixName); - }); + const matchesPattern = matchers.some(matcher => matcher.match(relativePath)); return matchesPattern && !configs.isFileIgnored(entry.path); } @@ -169,7 +176,7 @@ async function globSearch({ cwd, patterns, configs }) { * @param {string} options.pattern A glob pattern to match. * @returns {Promise} True if there is a glob match, false if not. */ -async function globMatch({ cwd, pattern }) { +function globMatch({ cwd, pattern }) { let found = false; @@ -180,13 +187,13 @@ async function globMatch({ cwd, pattern }) { }, entryFilter(entry) { - if (found) { + if (found || entry.dirent.isDirectory()) { return false; } - const posixName = normalizeToPosix(path.relative(cwd, entry.path)); + const relativePath = normalizeToPosix(path.relative(cwd, entry.path)); - if (minimatch(path.isAbsolute(pattern) ? entry.path : posixName, pattern)) { + if (minimatch(relativePath, pattern)) { found = true; return true; } @@ -195,12 +202,25 @@ async function globMatch({ cwd, pattern }) { } }; - /* eslint-disable-next-line no-unreachable-loop -- Don't need the value */ - for await (const entry of fswalk.walkStream(cwd, fsWalkSettings)) { - return true; - } + return new Promise(resolve => { + + // using a stream so we can exit early because we just need one match + const globStream = fswalk.walkStream(cwd, fsWalkSettings); + + globStream.on("data", () => { + globStream.destroy(); + resolve(true); + }); + + // swallow errors as they're not important here + globStream.on("error", () => {}); + + globStream.on("end", () => { + resolve(false); + }); + globStream.read(); + }); - return false; } /** @@ -231,6 +251,7 @@ async function findFiles({ // check to see if we have explicit files and directories const filePaths = patterns.map(filePath => path.resolve(cwd, filePath)); + const relativePatterns = filePaths.map(filePath => path.relative(cwd, filePath)); const stats = await Promise.all( filePaths.map( filePath => fsp.stat(filePath).catch(() => { }) @@ -240,7 +261,7 @@ async function findFiles({ stats.forEach((stat, index) => { const filePath = filePaths[index]; - const pattern = normalizeToPosix(patterns[index]); + const pattern = normalizeToPosix(relativePatterns[index]); if (stat) { From 39c5ecde18bb19d02d550ef6d39b171dfd181137 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 4 Oct 2022 16:51:34 -0700 Subject: [PATCH 12/15] clean up comment --- lib/eslint/eslint-helpers.js | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/lib/eslint/eslint-helpers.js b/lib/eslint/eslint-helpers.js index f89177bfe9f..59c57e26d5c 100644 --- a/lib/eslint/eslint-helpers.js +++ b/lib/eslint/eslint-helpers.js @@ -24,23 +24,6 @@ const fswalk = require("@nodelib/fs.walk"); const doFsWalk = util.promisify(fswalk.walk); -/* - * function doFsWalk(a, b) { - * return new Promise((resolve, reject) => { - * fswalk.walk(a, b, (err, entries) => { - * if (err) { - * reject(err); - * return; - * } - */ - -/* - * resolve(entries); - * }); - * }); - * } - */ - //----------------------------------------------------------------------------- // Errors //----------------------------------------------------------------------------- From 054670fd48df5c6e35bf8c7b3e81db6957b8c3cf Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Tue, 4 Oct 2022 16:52:11 -0700 Subject: [PATCH 13/15] Set concurrency back to default --- lib/eslint/eslint-helpers.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/eslint/eslint-helpers.js b/lib/eslint/eslint-helpers.js index 59c57e26d5c..b288a780819 100644 --- a/lib/eslint/eslint-helpers.js +++ b/lib/eslint/eslint-helpers.js @@ -128,7 +128,6 @@ async function globSearch({ cwd, patterns, configs }) { return (await doFsWalk(cwd, { - concurrency: 1, deepFilter(entry) { const relativePath = normalizeToPosix(path.relative(cwd, entry.path)); const matchesPattern = matchers.some(matcher => matcher.match(relativePath, true)); From e5813fb0e98fe1ca234a1e7b54eb73d337d085cf Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Thu, 6 Oct 2022 14:24:31 -0700 Subject: [PATCH 14/15] Fix remaining tests --- lib/eslint/eslint-helpers.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/eslint/eslint-helpers.js b/lib/eslint/eslint-helpers.js index b288a780819..4f8e1578de9 100644 --- a/lib/eslint/eslint-helpers.js +++ b/lib/eslint/eslint-helpers.js @@ -17,6 +17,7 @@ const hash = require("../cli-engine/hash"); const minimatch = require("minimatch"); const util = require("util"); const fswalk = require("@nodelib/fs.walk"); +const { Minimatch } = require("minimatch"); //----------------------------------------------------------------------------- // Fix fswalk @@ -124,7 +125,13 @@ async function globSearch({ cwd, patterns, configs }) { return []; } - const matchers = patterns.map(pattern => new minimatch.Minimatch(pattern)); + const matchers = patterns.map(pattern => { + const patternToUse = path.isAbsolute(pattern) + ? normalizeToPosix(path.relative(cwd, pattern)) + : pattern; + + return new minimatch.Minimatch(patternToUse); + }); return (await doFsWalk(cwd, { @@ -161,11 +168,18 @@ async function globSearch({ cwd, patterns, configs }) { function globMatch({ cwd, pattern }) { let found = false; + const patternToUse = path.isAbsolute(pattern) + ? normalizeToPosix(path.relative(cwd, pattern)) + : pattern; + + const matcher = new Minimatch(patternToUse); const fsWalkSettings = { - deepFilter() { - return !found; + deepFilter(entry) { + const relativePath = normalizeToPosix(path.relative(cwd, entry.path)); + + return !found && matcher.match(relativePath, true); }, entryFilter(entry) { @@ -175,7 +189,7 @@ function globMatch({ cwd, pattern }) { const relativePath = normalizeToPosix(path.relative(cwd, entry.path)); - if (minimatch(relativePath, pattern)) { + if (matcher.match(relativePath)) { found = true; return true; } @@ -233,7 +247,6 @@ async function findFiles({ // check to see if we have explicit files and directories const filePaths = patterns.map(filePath => path.resolve(cwd, filePath)); - const relativePatterns = filePaths.map(filePath => path.relative(cwd, filePath)); const stats = await Promise.all( filePaths.map( filePath => fsp.stat(filePath).catch(() => { }) @@ -243,7 +256,7 @@ async function findFiles({ stats.forEach((stat, index) => { const filePath = filePaths[index]; - const pattern = normalizeToPosix(relativePatterns[index]); + const pattern = normalizeToPosix(patterns[index]); if (stat) { From 5e699df8d6db53315155cfdd7eabc9b9b77ad3db Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Thu, 6 Oct 2022 14:28:40 -0700 Subject: [PATCH 15/15] Cleanup requires --- lib/eslint/eslint-helpers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/eslint/eslint-helpers.js b/lib/eslint/eslint-helpers.js index 4f8e1578de9..80e37f92310 100644 --- a/lib/eslint/eslint-helpers.js +++ b/lib/eslint/eslint-helpers.js @@ -17,13 +17,13 @@ const hash = require("../cli-engine/hash"); const minimatch = require("minimatch"); const util = require("util"); const fswalk = require("@nodelib/fs.walk"); -const { Minimatch } = require("minimatch"); //----------------------------------------------------------------------------- -// Fix fswalk +// Fixup references //----------------------------------------------------------------------------- const doFsWalk = util.promisify(fswalk.walk); +const Minimatch = minimatch.Minimatch; //----------------------------------------------------------------------------- // Errors