2 * @fileoverview Tests for FileEnumerator class.
3 * @author Toru Nagashima <https://github.com/mysticatea>
7 const fs
= require("fs");
8 const path
= require("path");
9 const os
= require("os");
10 const { assert
} = require("chai");
11 const sh
= require("shelljs");
12 const { CascadingConfigArrayFactory
} =
13 require("../../../lib/cli-engine/cascading-config-array-factory");
14 const { defineFileEnumeratorWithInMemoryFileSystem
} = require("./_utils");
16 describe("FileEnumerator", () => {
17 describe("'iterateFiles(patterns)' method should iterate files and configs.", () => {
18 describe("with three directories ('lib', 'lib/nested', 'test') that contains 'one.js' and 'two.js'", () => {
19 const root
= path
.join(os
.tmpdir(), "eslint/file-enumerator");
21 /* eslint-disable quote-props */
27 ".eslintrc.yml": "parser: './parser'"
35 ".eslintrc.yml": "env: { mocha: true }"
37 ".eslintignore": "/lib/nested/parser.js",
38 ".eslintrc.json": JSON
.stringify({
41 "no-unused-vars": "error"
44 /* eslint-enable quote-props */
46 const { FileEnumerator
} = defineFileEnumeratorWithInMemoryFileSystem({ cwd
: () => root
, files
});
48 /** @type {FileEnumerator} */
52 enumerator
= new FileEnumerator();
55 it("should ignore empty strings.", () => {
56 Array
.from(enumerator
.iterateFiles(["lib/*.js", ""])); // don't throw "file not found" error.
59 describe("if 'lib/*.js' was given,", () => {
61 /** @type {Array<{config:(typeof import('../../../lib/cli-engine'))["ConfigArray"], filePath:string, ignored:boolean}>} */
65 list
= [...enumerator
.iterateFiles("lib/*.js")];
68 it("should list two files.", () => {
69 assert
.strictEqual(list
.length
, 2);
72 it("should list 'lib/one.js' and 'lib/two.js'.", () => {
73 assert
.deepStrictEqual(
74 list
.map(entry
=> entry
.filePath
),
76 path
.join(root
, "lib/one.js"),
77 path
.join(root
, "lib/two.js")
82 it("should use the config '.eslintrc.json' for both files.", () => {
83 assert
.strictEqual(list
[0].config
, list
[1].config
);
84 assert
.strictEqual(list
[0].config
.length
, 3);
85 assert
.strictEqual(list
[0].config
[0].name
, "DefaultIgnorePattern");
86 assert
.strictEqual(list
[0].config
[1].filePath
, path
.join(root
, ".eslintrc.json"));
87 assert
.strictEqual(list
[0].config
[2].filePath
, path
.join(root
, ".eslintignore"));
91 describe("if 'lib/**/*.js' was given,", () => {
93 /** @type {Array<{config:(typeof import('../../../lib/cli-engine'))["ConfigArray"], filePath:string, ignored:boolean}>} */
97 list
= [...enumerator
.iterateFiles("lib/**/*.js")];
100 it("should list four files.", () => {
101 assert
.strictEqual(list
.length
, 4);
104 it("should list 'lib/nested/one.js', 'lib/nested/two.js', 'lib/one.js', 'lib/two.js'.", () => {
105 assert
.deepStrictEqual(
106 list
.map(entry
=> entry
.filePath
),
108 path
.join(root
, "lib/nested/one.js"),
109 path
.join(root
, "lib/nested/two.js"),
110 path
.join(root
, "lib/one.js"),
111 path
.join(root
, "lib/two.js")
116 it("should use the merged config of '.eslintrc.json' and 'lib/nested/.eslintrc.yml' for 'lib/nested/one.js' and 'lib/nested/two.js'.", () => {
117 assert
.strictEqual(list
[0].config
, list
[1].config
);
118 assert
.strictEqual(list
[0].config
.length
, 4);
119 assert
.strictEqual(list
[0].config
[0].name
, "DefaultIgnorePattern");
120 assert
.strictEqual(list
[0].config
[1].filePath
, path
.join(root
, ".eslintrc.json"));
121 assert
.strictEqual(list
[0].config
[2].filePath
, path
.join(root
, "lib/nested/.eslintrc.yml"));
122 assert
.strictEqual(list
[0].config
[3].filePath
, path
.join(root
, ".eslintignore"));
125 it("should use the config '.eslintrc.json' for 'lib/one.js' and 'lib/two.js'.", () => {
126 assert
.strictEqual(list
[2].config
, list
[3].config
);
127 assert
.strictEqual(list
[2].config
.length
, 3);
128 assert
.strictEqual(list
[2].config
[0].name
, "DefaultIgnorePattern");
129 assert
.strictEqual(list
[2].config
[1].filePath
, path
.join(root
, ".eslintrc.json"));
130 assert
.strictEqual(list
[2].config
[2].filePath
, path
.join(root
, ".eslintignore"));
134 describe("if 'lib/*.js' and 'test/*.js' were given,", () => {
136 /** @type {Array<{config:(typeof import('../../../lib/cli-engine'))["ConfigArray"], filePath:string, ignored:boolean}>} */
140 list
= [...enumerator
.iterateFiles(["lib/*.js", "test/*.js"])];
143 it("should list four files.", () => {
144 assert
.strictEqual(list
.length
, 4);
147 it("should list 'lib/one.js', 'lib/two.js', 'test/one.js', 'test/two.js'.", () => {
148 assert
.deepStrictEqual(
149 list
.map(entry
=> entry
.filePath
),
151 path
.join(root
, "lib/one.js"),
152 path
.join(root
, "lib/two.js"),
153 path
.join(root
, "test/one.js"),
154 path
.join(root
, "test/two.js")
159 it("should use the config '.eslintrc.json' for 'lib/one.js' and 'lib/two.js'.", () => {
160 assert
.strictEqual(list
[0].config
, list
[1].config
);
161 assert
.strictEqual(list
[0].config
.length
, 3);
162 assert
.strictEqual(list
[0].config
[0].name
, "DefaultIgnorePattern");
163 assert
.strictEqual(list
[0].config
[1].filePath
, path
.join(root
, ".eslintrc.json"));
164 assert
.strictEqual(list
[0].config
[2].filePath
, path
.join(root
, ".eslintignore"));
167 it("should use the merged config of '.eslintrc.json' and 'test/.eslintrc.yml' for 'test/one.js' and 'test/two.js'.", () => {
168 assert
.strictEqual(list
[2].config
, list
[3].config
);
169 assert
.strictEqual(list
[2].config
.length
, 4);
170 assert
.strictEqual(list
[2].config
[0].name
, "DefaultIgnorePattern");
171 assert
.strictEqual(list
[2].config
[1].filePath
, path
.join(root
, ".eslintrc.json"));
172 assert
.strictEqual(list
[2].config
[2].filePath
, path
.join(root
, "test/.eslintrc.yml"));
173 assert
.strictEqual(list
[2].config
[3].filePath
, path
.join(root
, ".eslintignore"));
178 // This group moved from 'tests/lib/util/glob-utils.js' when refactoring to keep the cumulated test cases.
179 describe("with 'tests/fixtures/glob-utils' files", () => {
180 const { FileEnumerator
} = require("../../../lib/cli-engine/file-enumerator");
184 * Returns the path inside of the fixture directory.
185 * @param {...string} args file path segments.
186 * @returns {string} The path inside the fixture directory.
189 function getFixturePath(...args
) {
190 return path
.join(fs
.realpathSync(fixtureDir
), ...args
);
194 * List files as a compatible shape with glob-utils.
195 * @param {string|string[]} patterns The patterns to list files.
196 * @param {Object} options The option for FileEnumerator.
197 * @returns {{filename:string,ignored:boolean}[]} The listed files.
199 function listFiles(patterns
, options
) {
203 configArrayFactory
: new CascadingConfigArrayFactory({
206 // Disable "No Configuration Found" error.
209 }).iterateFiles(patterns
),
210 ({ filePath
, ignored
}) => ({ filename
: filePath
, ignored
})
215 fixtureDir
= `${os.tmpdir()}/eslint/tests/fixtures/`;
216 sh
.mkdir("-p", fixtureDir
);
217 sh
.cp("-r", "./tests/fixtures/*", fixtureDir
);
221 sh
.rm("-r", fixtureDir
);
224 describe("listFilesToProcess()", () => {
225 it("should return an array with a resolved (absolute) filename", () => {
226 const patterns
= [getFixturePath("glob-util", "one-js-file", "**/*.js")];
227 const result
= listFiles(patterns
, {
228 cwd
: getFixturePath()
231 const file1
= getFixturePath("glob-util", "one-js-file", "baz.js");
233 assert
.isArray(result
);
234 assert
.deepStrictEqual(result
, [{ filename
: file1
, ignored
: false }]);
237 it("should return all files matching a glob pattern", () => {
238 const patterns
= [getFixturePath("glob-util", "two-js-files", "**/*.js")];
239 const result
= listFiles(patterns
, {
240 cwd
: getFixturePath()
243 const file1
= getFixturePath("glob-util", "two-js-files", "bar.js");
244 const file2
= getFixturePath("glob-util", "two-js-files", "foo.js");
246 assert
.strictEqual(result
.length
, 2);
247 assert
.deepStrictEqual(result
, [
248 { filename
: file1
, ignored
: false },
249 { filename
: file2
, ignored
: false }
253 it("should return all files matching multiple glob patterns", () => {
255 getFixturePath("glob-util", "two-js-files", "**/*.js"),
256 getFixturePath("glob-util", "one-js-file", "**/*.js")
258 const result
= listFiles(patterns
, {
259 cwd
: getFixturePath()
262 const file1
= getFixturePath("glob-util", "two-js-files", "bar.js");
263 const file2
= getFixturePath("glob-util", "two-js-files", "foo.js");
264 const file3
= getFixturePath("glob-util", "one-js-file", "baz.js");
266 assert
.strictEqual(result
.length
, 3);
267 assert
.deepStrictEqual(result
, [
268 { filename
: file1
, ignored
: false },
269 { filename
: file2
, ignored
: false },
270 { filename
: file3
, ignored
: false }
274 it("should ignore hidden files for standard glob patterns", () => {
275 const patterns
= [getFixturePath("glob-util", "hidden", "**/*.js")];
277 assert
.throws(() => {
278 listFiles(patterns
, {
279 cwd
: getFixturePath()
281 }, `All files matched by '${patterns[0]}' are ignored.`);
284 it("should return hidden files if included in glob pattern", () => {
285 const patterns
= [getFixturePath("glob-util", "hidden", "**/.*.js")];
286 const result
= listFiles(patterns
, {
287 cwd
: getFixturePath()
290 const file1
= getFixturePath("glob-util", "hidden", ".foo.js");
292 assert
.strictEqual(result
.length
, 1);
293 assert
.deepStrictEqual(result
, [
294 { filename
: file1
, ignored
: false }
298 it("should ignore default ignored files if not passed explicitly", () => {
299 const directory
= getFixturePath("glob-util", "hidden");
300 const patterns
= [directory
];
302 assert
.throws(() => {
303 listFiles(patterns
, {
304 cwd
: getFixturePath()
306 }, `All files matched by '${directory}' are ignored.`);
309 it("should ignore and warn for default ignored files when passed explicitly", () => {
310 const filename
= getFixturePath("glob-util", "hidden", ".foo.js");
311 const patterns
= [filename
];
312 const result
= listFiles(patterns
, {
313 cwd
: getFixturePath()
316 assert
.strictEqual(result
.length
, 1);
317 assert
.deepStrictEqual(result
[0], { filename
, ignored
: true });
320 it("should ignore default ignored files if not passed explicitly even if ignore is false", () => {
321 const directory
= getFixturePath("glob-util", "hidden");
322 const patterns
= [directory
];
324 assert
.throws(() => {
325 listFiles(patterns
, {
326 cwd
: getFixturePath(),
329 }, `All files matched by '${directory}' are ignored.`);
332 it("should not ignore default ignored files when passed explicitly if ignore is false", () => {
333 const filename
= getFixturePath("glob-util", "hidden", ".foo.js");
334 const patterns
= [filename
];
335 const result
= listFiles(patterns
, {
336 cwd
: getFixturePath(),
340 assert
.strictEqual(result
.length
, 1);
341 assert
.deepStrictEqual(result
[0], { filename
, ignored
: false });
344 it("should throw an error for a file which does not exist", () => {
345 const filename
= getFixturePath("glob-util", "hidden", "bar.js");
346 const patterns
= [filename
];
348 assert
.throws(() => {
349 listFiles(patterns
, {
350 cwd
: getFixturePath(),
351 allowMissingGlobs
: true
353 }, `No files matching '${filename}' were found.`);
356 it("should throw if a folder that does not have any applicable files is linted", () => {
357 const filename
= getFixturePath("glob-util", "empty");
358 const patterns
= [filename
];
360 assert
.throws(() => {
361 listFiles(patterns
, {
362 cwd
: getFixturePath()
364 }, `No files matching '${filename}' were found.`);
367 it("should throw if only ignored files match a glob", () => {
368 const pattern
= getFixturePath("glob-util", "ignored");
369 const options
= { ignore
: true, ignorePath
: getFixturePath("glob-util", "ignored", ".eslintignore") };
371 assert
.throws(() => {
372 listFiles([pattern
], options
);
373 }, `All files matched by '${pattern}' are ignored.`);
376 it("should throw an error if no files match a glob", () => {
378 // Relying here on the .eslintignore from the repo root
379 const patterns
= ["tests/fixtures/glob-util/ignored/**/*.js"];
381 assert
.throws(() => {
383 }, `All files matched by '${patterns[0]}' are ignored.`);
386 it("should return an ignored file, if ignore option is turned off", () => {
387 const options
= { ignore
: false };
388 const patterns
= [getFixturePath("glob-util", "ignored", "**/*.js")];
389 const result
= listFiles(patterns
, options
);
391 assert
.strictEqual(result
.length
, 1);
394 it("should ignore a file from a glob if it matches a pattern in an ignore file", () => {
395 const options
= { ignore
: true, ignorePath
: getFixturePath("glob-util", "ignored", ".eslintignore") };
396 const patterns
= [getFixturePath("glob-util", "ignored", "**/*.js")];
398 assert
.throws(() => {
399 listFiles(patterns
, options
);
400 }, `All files matched by '${patterns[0]}' are ignored.`);
403 it("should ignore a file from a glob if matching a specified ignore pattern", () => {
404 const options
= { ignore
: true, cliConfig
: { ignorePatterns
: ["foo.js"] }, cwd
: getFixturePath() };
405 const patterns
= [getFixturePath("glob-util", "ignored", "**/*.js")];
407 assert
.throws(() => {
408 listFiles(patterns
, options
);
409 }, `All files matched by '${patterns[0]}' are ignored.`);
412 it("should return a file only once if listed in more than 1 pattern", () => {
414 getFixturePath("glob-util", "one-js-file", "**/*.js"),
415 getFixturePath("glob-util", "one-js-file", "baz.js")
417 const result
= listFiles(patterns
, {
418 cwd
: path
.join(fixtureDir
, "..")
421 const file1
= getFixturePath("glob-util", "one-js-file", "baz.js");
423 assert
.isArray(result
);
424 assert
.deepStrictEqual(result
, [
425 { filename
: file1
, ignored
: false }
429 it("should set 'ignored: true' for files that are explicitly specified but ignored", () => {
430 const options
= { ignore
: true, cliConfig
: { ignorePatterns
: ["foo.js"] }, cwd
: getFixturePath() };
431 const filename
= getFixturePath("glob-util", "ignored", "foo.js");
432 const patterns
= [filename
];
433 const result
= listFiles(patterns
, options
);
435 assert
.strictEqual(result
.length
, 1);
436 assert
.deepStrictEqual(result
, [
437 { filename
, ignored
: true }
441 it("should not return files from default ignored folders", () => {
442 const options
= { cwd
: getFixturePath("glob-util") };
443 const glob
= getFixturePath("glob-util", "**/*.js");
444 const patterns
= [glob
];
445 const result
= listFiles(patterns
, options
);
446 const resultFilenames
= result
.map(resultObj
=> resultObj
.filename
);
448 assert
.notInclude(resultFilenames
, getFixturePath("glob-util", "node_modules", "dependency.js"));
451 it("should return unignored files from default ignored folders", () => {
452 const options
= { cliConfig
: { ignorePatterns
: ["!/node_modules/dependency.js"] }, cwd
: getFixturePath("glob-util") };
453 const glob
= getFixturePath("glob-util", "**/*.js");
454 const patterns
= [glob
];
455 const result
= listFiles(patterns
, options
);
456 const unignoredFilename
= getFixturePath("glob-util", "node_modules", "dependency.js");
458 assert
.includeDeepMembers(result
, [{ filename
: unignoredFilename
, ignored
: false }]);
461 it("should return unignored files from folders unignored in .eslintignore", () => {
462 const options
= { cwd
: getFixturePath("glob-util", "unignored"), ignore
: true };
463 const glob
= getFixturePath("glob-util", "unignored", "**/*.js");
464 const patterns
= [glob
];
465 const result
= listFiles(patterns
, options
);
467 const filename
= getFixturePath("glob-util", "unignored", "dir", "foo.js");
469 assert
.strictEqual(result
.length
, 1);
470 assert
.deepStrictEqual(result
, [{ filename
, ignored
: false }]);
473 it("should return unignored files from folders unignored in .eslintignore for explicitly specified folder", () => {
474 const options
= { cwd
: getFixturePath("glob-util", "unignored"), ignore
: true };
475 const dir
= getFixturePath("glob-util", "unignored", "dir");
476 const patterns
= [dir
];
477 const result
= listFiles(patterns
, options
);
479 const filename
= getFixturePath("glob-util", "unignored", "dir", "foo.js");
481 assert
.strictEqual(result
.length
, 1);
482 assert
.deepStrictEqual(result
, [{ filename
, ignored
: false }]);