diff --git a/lib/cli-engine/file-enumerator.js b/lib/cli-engine/file-enumerator.js index 2840d9fe2da..1427a51f4a1 100644 --- a/lib/cli-engine/file-enumerator.js +++ b/lib/cli-engine/file-enumerator.js @@ -289,31 +289,32 @@ class FileEnumerator { * @param {string} pattern The glob pattern to iterate files. * @returns {IterableIterator} The found files. */ - _iterateFiles(pattern) { + *_iterateFiles(pattern) { const { cwd, globInputPaths } = internalSlotsMap.get(this); const absolutePath = path.resolve(cwd, pattern); + const isDot = dotfilesPattern.test(pattern); if (globInputPaths && isGlobPattern(pattern)) { - return this._iterateFilesWithGlob( - absolutePath, - dotfilesPattern.test(pattern) - ); + let found = false; + + for (const entry of this._iterateFilesWithGlob(absolutePath, isDot)) { + found = true; + yield entry; + } + + // If the glob didn't match any files, fall it through as a filename. + if (found) { + return; + } } const stat = statSafeSync(absolutePath); if (stat && stat.isDirectory()) { - return this._iterateFilesWithDirectory( - absolutePath, - dotfilesPattern.test(pattern) - ); - } - - if (stat && stat.isFile()) { - return this._iterateFilesWithFile(absolutePath); + yield* this._iterateFilesWithDirectory(absolutePath, isDot); + } else if (stat && stat.isFile()) { + yield* this._iterateFilesWithFile(absolutePath); } - - return []; } /** diff --git a/tests/lib/cli-engine/cli-engine.js b/tests/lib/cli-engine/cli-engine.js index de152f3bae8..a19e3c28a80 100644 --- a/tests/lib/cli-engine/cli-engine.js +++ b/tests/lib/cli-engine/cli-engine.js @@ -3454,6 +3454,46 @@ describe("CLIEngine", () => { assert.strictEqual(report.results[0].messages[0].message, "ok"); }); }); + + describe("glob pattern '[ab].js'", () => { + const root = getFixturePath("cli-engine/unmatched-glob"); + + it("should match 'a.js' and 'b.js', but not '[ab].js'.", () => { + CLIEngine = defineCLIEngineWithInMemoryFileSystem({ + cwd: () => root, + files: { + "a.js": "", + "b.js": "", + "ab.js": "", + "[ab].js": "", + ".eslintrc.yml": "root: true" + } + }).CLIEngine; + engine = new CLIEngine(); + + const { results } = engine.executeOnFiles(["[ab].js"]); + const filenames = results.map(r => path.basename(r.filePath)); + + assert.deepStrictEqual(filenames, ["a.js", "b.js"]); + }); + + it("should match '[ab].js' if both 'a.js' and 'b.js' didn't exist.", () => { + CLIEngine = defineCLIEngineWithInMemoryFileSystem({ + cwd: () => root, + files: { + "ab.js": "", + "[ab].js": "", + ".eslintrc.yml": "root: true" + } + }).CLIEngine; + engine = new CLIEngine(); + + const { results } = engine.executeOnFiles(["[ab].js"]); + const filenames = results.map(r => path.basename(r.filePath)); + + assert.deepStrictEqual(filenames, ["[ab].js"]); + }); + }); }); describe("getConfigForFile", () => {