]> git.proxmox.com Git - pve-eslint.git/blame - eslint/tests/lib/eslint/eslint.js
import 8.23.1 source
[pve-eslint.git] / eslint / tests / lib / eslint / eslint.js
CommitLineData
56c4a2cb
DC
1/**
2 * @fileoverview Tests for the ESLint class.
3 * @author Kai Cataldo
4 * @author Toru Nagashima
5 */
6
7"use strict";
8
9//------------------------------------------------------------------------------
10// Requirements
11//------------------------------------------------------------------------------
12
13const assert = require("assert");
14const fs = require("fs");
15const os = require("os");
16const path = require("path");
17const escapeStringRegExp = require("escape-string-regexp");
18const fCache = require("file-entry-cache");
56c4a2cb
DC
19const sinon = require("sinon");
20const proxyquire = require("proxyquire").noCallThru().noPreserveCache();
21const shell = require("shelljs");
609c276f
TL
22const {
23 Legacy: {
24 CascadingConfigArrayFactory
25 }
26} = require("@eslint/eslintrc");
56c4a2cb 27const hash = require("../../../lib/cli-engine/hash");
6f036462 28const { unIndent, createCustomTeardown } = require("../../_utils");
609c276f 29const coreRules = require("../../../lib/rules");
8f9d1d4d 30const childProcess = require("child_process");
56c4a2cb
DC
31
32//------------------------------------------------------------------------------
33// Tests
34//------------------------------------------------------------------------------
35
36describe("ESLint", () => {
37 const examplePluginName = "eslint-plugin-example";
38 const examplePluginNameWithNamespace = "@eslint/eslint-plugin-example";
39 const examplePlugin = {
40 rules: {
41 "example-rule": require("../../fixtures/rules/custom-rule"),
42 "make-syntax-error": require("../../fixtures/rules/make-syntax-error-rule")
43 }
44 };
45 const examplePreprocessorName = "eslint-plugin-processor";
46 const originalDir = process.cwd();
47 const fixtureDir = path.resolve(fs.realpathSync(os.tmpdir()), "eslint/fixtures");
48
609c276f 49 /** @type {import("../../../lib/eslint").ESLint} */
56c4a2cb
DC
50 let ESLint;
51
52 /**
53 * Returns the path inside of the fixture directory.
54 * @param {...string} args file path segments.
55 * @returns {string} The path inside the fixture directory.
56 * @private
57 */
58 function getFixturePath(...args) {
59 const filepath = path.join(fixtureDir, ...args);
60
61 try {
62 return fs.realpathSync(filepath);
d3726936 63 } catch {
56c4a2cb
DC
64 return filepath;
65 }
66 }
67
68 /**
69 * Create the ESLint object by mocking some of the plugins
70 * @param {Object} options options for ESLint
71 * @returns {ESLint} engine object
72 * @private
73 */
74 function eslintWithPlugins(options) {
75 return new ESLint({
76 ...options,
77 plugins: {
78 [examplePluginName]: examplePlugin,
79 [examplePluginNameWithNamespace]: examplePlugin,
80 [examplePreprocessorName]: require("../../fixtures/processors/custom-processor")
81 }
82 });
83 }
84
85 /**
86 * Call the last argument.
87 * @param {any[]} args Arguments
88 * @returns {void}
89 */
90 function callLastArgument(...args) {
91 process.nextTick(args[args.length - 1], null);
92 }
93
94 // copy into clean area so as not to get "infected" by this project's .eslintrc files
6f036462
TL
95 before(function() {
96
97 /*
98 * GitHub Actions Windows and macOS runners occasionally exhibit
99 * extremely slow filesystem operations, during which copying fixtures
100 * exceeds the default test timeout, so raise it just for this hook.
101 * Mocha uses `this` to set timeouts on an individual hook level.
102 */
609c276f 103 this.timeout(60 * 1000); // eslint-disable-line no-invalid-this -- Mocha API
56c4a2cb
DC
104 shell.mkdir("-p", fixtureDir);
105 shell.cp("-r", "./tests/fixtures/.", fixtureDir);
106 });
107
108 beforeEach(() => {
109 ({ ESLint } = require("../../../lib/eslint/eslint"));
110 });
111
112 after(() => {
113 shell.rm("-r", fixtureDir);
114 });
115
116 describe("ESLint constructor function", () => {
117 it("the default value of 'options.cwd' should be the current working directory.", async () => {
118 process.chdir(__dirname);
119 try {
120 const engine = new ESLint();
121 const results = await engine.lintFiles("eslint.js");
122
123 assert.strictEqual(path.dirname(results[0].filePath), __dirname);
124 } finally {
125 process.chdir(originalDir);
126 }
127 });
128
129 it("should report one fatal message when given a path by --ignore-path that is not a file when ignore is true.", () => {
130 assert.throws(() => {
609c276f 131 // eslint-disable-next-line no-new -- Check for throwing
56c4a2cb
DC
132 new ESLint({ ignorePath: fixtureDir });
133 }, new RegExp(escapeStringRegExp(`Cannot read .eslintignore file: ${fixtureDir}\nError: EISDIR: illegal operation on a directory, read`), "u"));
134 });
135
136 // https://github.com/eslint/eslint/issues/2380
137 it("should not modify baseConfig when format is specified", () => {
138 const customBaseConfig = { root: true };
139
609c276f 140 new ESLint({ baseConfig: customBaseConfig }); // eslint-disable-line no-new -- Check for argument side effects
56c4a2cb
DC
141
142 assert.deepStrictEqual(customBaseConfig, { root: true });
143 });
144
145 it("should throw readable messages if removed options are present", () => {
146 assert.throws(
147 () => new ESLint({
148 cacheFile: "",
149 configFile: "",
150 envs: [],
151 globals: [],
152 ignorePattern: [],
153 parser: "",
154 parserOptions: {},
155 rules: {},
156 plugins: []
157 }),
158 new RegExp(escapeStringRegExp([
159 "Invalid Options:",
160 "- Unknown options: cacheFile, configFile, envs, globals, ignorePattern, parser, parserOptions, rules",
161 "- 'cacheFile' has been removed. Please use the 'cacheLocation' option instead.",
162 "- 'configFile' has been removed. Please use the 'overrideConfigFile' option instead.",
163 "- 'envs' has been removed. Please use the 'overrideConfig.env' option instead.",
164 "- 'globals' has been removed. Please use the 'overrideConfig.globals' option instead.",
165 "- 'ignorePattern' has been removed. Please use the 'overrideConfig.ignorePatterns' option instead.",
166 "- 'parser' has been removed. Please use the 'overrideConfig.parser' option instead.",
167 "- 'parserOptions' has been removed. Please use the 'overrideConfig.parserOptions' option instead.",
168 "- 'rules' has been removed. Please use the 'overrideConfig.rules' option instead.",
169 "- 'plugins' doesn't add plugins to configuration to load. Please use the 'overrideConfig.plugins' option instead."
170 ].join("\n")), "u")
171 );
172 });
173
174 it("should throw readable messages if wrong type values are given to options", () => {
175 assert.throws(
176 () => new ESLint({
177 allowInlineConfig: "",
178 baseConfig: "",
179 cache: "",
180 cacheLocation: "",
181 cwd: "foo",
182 errorOnUnmatchedPattern: "",
183 extensions: "",
184 fix: "",
185 fixTypes: ["xyz"],
186 globInputPaths: "",
187 ignore: "",
188 ignorePath: "",
189 overrideConfig: "",
190 overrideConfigFile: "",
191 plugins: "",
192 reportUnusedDisableDirectives: "",
193 resolvePluginsRelativeTo: "",
194 rulePaths: "",
195 useEslintrc: ""
196 }),
197 new RegExp(escapeStringRegExp([
198 "Invalid Options:",
199 "- 'allowInlineConfig' must be a boolean.",
200 "- 'baseConfig' must be an object or null.",
201 "- 'cache' must be a boolean.",
202 "- 'cacheLocation' must be a non-empty string.",
203 "- 'cwd' must be an absolute path.",
204 "- 'errorOnUnmatchedPattern' must be a boolean.",
205 "- 'extensions' must be an array of non-empty strings or null.",
206 "- 'fix' must be a boolean or a function.",
609c276f 207 "- 'fixTypes' must be an array of any of \"directive\", \"problem\", \"suggestion\", and \"layout\".",
56c4a2cb
DC
208 "- 'globInputPaths' must be a boolean.",
209 "- 'ignore' must be a boolean.",
210 "- 'ignorePath' must be a non-empty string or null.",
211 "- 'overrideConfig' must be an object or null.",
212 "- 'overrideConfigFile' must be a non-empty string or null.",
213 "- 'plugins' must be an object or null.",
214 "- 'reportUnusedDisableDirectives' must be any of \"error\", \"warn\", \"off\", and null.",
215 "- 'resolvePluginsRelativeTo' must be a non-empty string or null.",
216 "- 'rulePaths' must be an array of non-empty strings.",
456be15e 217 "- 'useEslintrc' must be a boolean."
56c4a2cb
DC
218 ].join("\n")), "u")
219 );
220 });
221
222 it("should throw readable messages if 'plugins' option contains empty key", () => {
223 assert.throws(
224 () => new ESLint({
225 plugins: {
226 "eslint-plugin-foo": {},
227 "eslint-plugin-bar": {},
228 "": {}
229 }
230 }),
231 new RegExp(escapeStringRegExp([
232 "Invalid Options:",
233 "- 'plugins' must not include an empty string."
234 ].join("\n")), "u")
235 );
236 });
237 });
238
239 describe("lintText()", () => {
240 let eslint;
241
242 it("should report the total and per file errors when using local cwd .eslintrc", async () => {
243 eslint = new ESLint();
244 const results = await eslint.lintText("var foo = 'bar';");
245
246 assert.strictEqual(results.length, 1);
247 assert.strictEqual(results[0].messages.length, 5);
248 assert.strictEqual(results[0].messages[0].ruleId, "strict");
249 assert.strictEqual(results[0].messages[1].ruleId, "no-var");
250 assert.strictEqual(results[0].messages[2].ruleId, "no-unused-vars");
251 assert.strictEqual(results[0].messages[3].ruleId, "quotes");
252 assert.strictEqual(results[0].messages[4].ruleId, "eol-last");
253 assert.strictEqual(results[0].fixableErrorCount, 3);
254 assert.strictEqual(results[0].fixableWarningCount, 0);
255 assert.strictEqual(results[0].usedDeprecatedRules.length, 0);
256 });
257
258 it("should report the total and per file warnings when using local cwd .eslintrc", async () => {
259 eslint = new ESLint({
260 overrideConfig: {
261 rules: {
262 quotes: 1,
263 "no-var": 1,
264 "eol-last": 1,
265 strict: 1,
266 "no-unused-vars": 1
267 }
268 }
269 });
270 const results = await eslint.lintText("var foo = 'bar';");
271
272 assert.strictEqual(results.length, 1);
273 assert.strictEqual(results[0].messages.length, 5);
274 assert.strictEqual(results[0].messages[0].ruleId, "strict");
275 assert.strictEqual(results[0].messages[1].ruleId, "no-var");
276 assert.strictEqual(results[0].messages[2].ruleId, "no-unused-vars");
277 assert.strictEqual(results[0].messages[3].ruleId, "quotes");
278 assert.strictEqual(results[0].messages[4].ruleId, "eol-last");
279 assert.strictEqual(results[0].fixableErrorCount, 0);
280 assert.strictEqual(results[0].fixableWarningCount, 3);
281 assert.strictEqual(results[0].usedDeprecatedRules.length, 0);
282 });
283
284 it("should report one message when using specific config file", async () => {
285 eslint = new ESLint({
286 overrideConfigFile: "fixtures/configurations/quotes-error.json",
287 useEslintrc: false,
288 cwd: getFixturePath("..")
289 });
290 const results = await eslint.lintText("var foo = 'bar';");
291
292 assert.strictEqual(results.length, 1);
293 assert.strictEqual(results[0].messages.length, 1);
294 assert.strictEqual(results[0].messages[0].ruleId, "quotes");
295 assert.strictEqual(results[0].messages[0].output, void 0);
296 assert.strictEqual(results[0].errorCount, 1);
297 assert.strictEqual(results[0].fixableErrorCount, 1);
298 assert.strictEqual(results[0].warningCount, 0);
299 assert.strictEqual(results[0].usedDeprecatedRules.length, 0);
300 });
301
302 it("should report the filename when passed in", async () => {
303 eslint = new ESLint({
304 ignore: false,
305 cwd: getFixturePath()
306 });
307 const options = { filePath: "test.js" };
308 const results = await eslint.lintText("var foo = 'bar';", options);
309
310 assert.strictEqual(results[0].filePath, getFixturePath("test.js"));
311 });
312
313 it("should return a warning when given a filename by --stdin-filename in excluded files list if warnIgnored is true", async () => {
314 eslint = new ESLint({
315 ignorePath: getFixturePath(".eslintignore"),
316 cwd: getFixturePath("..")
317 });
318 const options = { filePath: "fixtures/passing.js", warnIgnored: true };
319 const results = await eslint.lintText("var bar = foo;", options);
320
321 assert.strictEqual(results.length, 1);
322 assert.strictEqual(results[0].filePath, getFixturePath("passing.js"));
323 assert.strictEqual(results[0].messages[0].severity, 1);
324 assert.strictEqual(results[0].messages[0].message, "File ignored because of a matching ignore pattern. Use \"--no-ignore\" to override.");
325 assert.strictEqual(results[0].messages[0].output, void 0);
326 assert.strictEqual(results[0].errorCount, 0);
327 assert.strictEqual(results[0].warningCount, 1);
8f9d1d4d 328 assert.strictEqual(results[0].fatalErrorCount, 0);
56c4a2cb
DC
329 assert.strictEqual(results[0].fixableErrorCount, 0);
330 assert.strictEqual(results[0].fixableWarningCount, 0);
331 assert.strictEqual(results[0].usedDeprecatedRules.length, 0);
332 });
333
334 it("should not return a warning when given a filename by --stdin-filename in excluded files list if warnIgnored is false", async () => {
335 eslint = new ESLint({
336 ignorePath: getFixturePath(".eslintignore"),
337 cwd: getFixturePath("..")
338 });
339 const options = {
340 filePath: "fixtures/passing.js",
341 warnIgnored: false
342 };
343
344 // intentional parsing error
345 const results = await eslint.lintText("va r bar = foo;", options);
346
347 // should not report anything because the file is ignored
348 assert.strictEqual(results.length, 0);
349 });
350
351 it("should suppress excluded file warnings by default", async () => {
352 eslint = new ESLint({
353 ignorePath: getFixturePath(".eslintignore"),
354 cwd: getFixturePath("..")
355 });
356 const options = { filePath: "fixtures/passing.js" };
357 const results = await eslint.lintText("var bar = foo;", options);
358
359 // should not report anything because there are no errors
360 assert.strictEqual(results.length, 0);
361 });
362
363 it("should return a message when given a filename by --stdin-filename in excluded files list and ignore is off", async () => {
364 eslint = new ESLint({
365 ignorePath: "fixtures/.eslintignore",
366 cwd: getFixturePath(".."),
367 ignore: false,
368 useEslintrc: false,
369 overrideConfig: {
370 rules: {
371 "no-undef": 2
372 }
373 }
374 });
375 const options = { filePath: "fixtures/passing.js" };
376 const results = await eslint.lintText("var bar = foo;", options);
377
378 assert.strictEqual(results.length, 1);
379 assert.strictEqual(results[0].filePath, getFixturePath("passing.js"));
380 assert.strictEqual(results[0].messages[0].ruleId, "no-undef");
381 assert.strictEqual(results[0].messages[0].severity, 2);
382 assert.strictEqual(results[0].messages[0].output, void 0);
383 });
384
385 it("should return a message and fixed text when in fix mode", async () => {
386 eslint = new ESLint({
387 useEslintrc: false,
388 fix: true,
389 overrideConfig: {
390 rules: {
391 semi: 2
392 }
393 },
394 ignore: false,
395 cwd: getFixturePath()
396 });
397 const options = { filePath: "passing.js" };
398 const results = await eslint.lintText("var bar = foo", options);
399
400 assert.deepStrictEqual(results, [
401 {
402 filePath: getFixturePath("passing.js"),
403 messages: [],
8f9d1d4d 404 suppressedMessages: [],
56c4a2cb
DC
405 errorCount: 0,
406 warningCount: 0,
609c276f 407 fatalErrorCount: 0,
56c4a2cb
DC
408 fixableErrorCount: 0,
409 fixableWarningCount: 0,
410 output: "var bar = foo;",
411 usedDeprecatedRules: []
412 }
413 ]);
414 });
415
8f9d1d4d
DC
416 it("should use eslint:recommended rules when eslint:recommended configuration is specified", async () => {
417 eslint = new ESLint({
418 useEslintrc: false,
419 overrideConfig: {
420 extends: ["eslint:recommended"]
421 },
422 ignore: false,
423 cwd: getFixturePath()
424 });
425 const options = { filePath: "file.js" };
426 const results = await eslint.lintText("foo ()", options);
427
428 assert.strictEqual(results.length, 1);
429 assert.strictEqual(results[0].messages.length, 1);
430 assert.strictEqual(results[0].messages[0].ruleId, "no-undef");
431 assert.strictEqual(results[0].messages[0].severity, 2);
432 });
433
434 it("should use eslint:all rules when eslint:all configuration is specified", async () => {
435 eslint = new ESLint({
436 useEslintrc: false,
437 overrideConfig: {
438 extends: ["eslint:all"]
439 },
440 ignore: false,
441 cwd: getFixturePath()
442 });
443 const options = { filePath: "file.js" };
444 const results = await eslint.lintText("foo ()", options);
445
446 assert.strictEqual(results.length, 1);
447
448 const { messages } = results[0];
449
450 // Some rules that should report errors in the given code. Not all, as we don't want to update this test when we add new rules.
451 const expectedRules = ["no-undef", "semi", "func-call-spacing"];
452
453 expectedRules.forEach(ruleId => {
454 const messageFromRule = messages.find(message => message.ruleId === ruleId);
455
456 assert.ok(
457 typeof messageFromRule === "object" && messageFromRule !== null, // LintMessage object
458 `Expected a message from rule '${ruleId}'`
459 );
460 assert.strictEqual(messageFromRule.severity, 2);
461 });
462
463 });
464
56c4a2cb
DC
465 it("correctly autofixes semicolon-conflicting-fixes", async () => {
466 eslint = new ESLint({
467 cwd: path.join(fixtureDir, ".."),
468 useEslintrc: false,
469 fix: true
470 });
471 const inputPath = getFixturePath("autofix/semicolon-conflicting-fixes.js");
472 const outputPath = getFixturePath("autofix/semicolon-conflicting-fixes.expected.js");
473 const results = await eslint.lintFiles([inputPath]);
474 const expectedOutput = fs.readFileSync(outputPath, "utf8");
475
476 assert.strictEqual(results[0].output, expectedOutput);
477 });
478
479 it("correctly autofixes return-conflicting-fixes", async () => {
480 eslint = new ESLint({
481 cwd: path.join(fixtureDir, ".."),
482 useEslintrc: false,
483 fix: true
484 });
485 const inputPath = getFixturePath("autofix/return-conflicting-fixes.js");
486 const outputPath = getFixturePath("autofix/return-conflicting-fixes.expected.js");
487 const results = await eslint.lintFiles([inputPath]);
488 const expectedOutput = fs.readFileSync(outputPath, "utf8");
489
490 assert.strictEqual(results[0].output, expectedOutput);
491 });
492
493 describe("Fix Types", () => {
494 it("should throw an error when an invalid fix type is specified", () => {
495 assert.throws(() => {
496 eslint = new ESLint({
497 cwd: path.join(fixtureDir, ".."),
498 useEslintrc: false,
499 fix: true,
500 fixTypes: ["layou"]
501 });
609c276f 502 }, /'fixTypes' must be an array of any of "directive", "problem", "suggestion", and "layout"\./iu);
56c4a2cb
DC
503 });
504
505 it("should not fix any rules when fixTypes is used without fix", async () => {
506 eslint = new ESLint({
507 cwd: path.join(fixtureDir, ".."),
508 useEslintrc: false,
509 fix: false,
510 fixTypes: ["layout"]
511 });
512 const inputPath = getFixturePath("fix-types/fix-only-semi.js");
513 const results = await eslint.lintFiles([inputPath]);
514
515 assert.strictEqual(results[0].output, void 0);
516 });
517
518 it("should not fix non-style rules when fixTypes has only 'layout'", async () => {
519 eslint = new ESLint({
520 cwd: path.join(fixtureDir, ".."),
521 useEslintrc: false,
522 fix: true,
523 fixTypes: ["layout"]
524 });
525 const inputPath = getFixturePath("fix-types/fix-only-semi.js");
526 const outputPath = getFixturePath("fix-types/fix-only-semi.expected.js");
527 const results = await eslint.lintFiles([inputPath]);
528 const expectedOutput = fs.readFileSync(outputPath, "utf8");
529
530 assert.strictEqual(results[0].output, expectedOutput);
531 });
532
533 it("should not fix style or problem rules when fixTypes has only 'suggestion'", async () => {
534 eslint = new ESLint({
535 cwd: path.join(fixtureDir, ".."),
536 useEslintrc: false,
537 fix: true,
538 fixTypes: ["suggestion"]
539 });
540 const inputPath = getFixturePath("fix-types/fix-only-prefer-arrow-callback.js");
541 const outputPath = getFixturePath("fix-types/fix-only-prefer-arrow-callback.expected.js");
542 const results = await eslint.lintFiles([inputPath]);
543 const expectedOutput = fs.readFileSync(outputPath, "utf8");
544
545 assert.strictEqual(results[0].output, expectedOutput);
546 });
547
548 it("should fix both style and problem rules when fixTypes has 'suggestion' and 'layout'", async () => {
549 eslint = new ESLint({
550 cwd: path.join(fixtureDir, ".."),
551 useEslintrc: false,
552 fix: true,
553 fixTypes: ["suggestion", "layout"]
554 });
555 const inputPath = getFixturePath("fix-types/fix-both-semi-and-prefer-arrow-callback.js");
556 const outputPath = getFixturePath("fix-types/fix-both-semi-and-prefer-arrow-callback.expected.js");
557 const results = await eslint.lintFiles([inputPath]);
558 const expectedOutput = fs.readFileSync(outputPath, "utf8");
559
560 assert.strictEqual(results[0].output, expectedOutput);
561 });
562
563 it("should not throw an error when a rule doesn't have a 'meta' property", async () => {
564 eslint = new ESLint({
565 cwd: path.join(fixtureDir, ".."),
566 useEslintrc: false,
567 fix: true,
568 fixTypes: ["layout"],
569 rulePaths: [getFixturePath("rules", "fix-types-test")]
570 });
571 const inputPath = getFixturePath("fix-types/ignore-missing-meta.js");
572 const outputPath = getFixturePath("fix-types/ignore-missing-meta.expected.js");
573 const results = await eslint.lintFiles([inputPath]);
574 const expectedOutput = fs.readFileSync(outputPath, "utf8");
575
576 assert.strictEqual(results[0].output, expectedOutput);
577 });
578
579 it("should not throw an error when a rule is loaded after initialization with lintFiles()", async () => {
580 eslint = new ESLint({
581 cwd: path.join(fixtureDir, ".."),
582 useEslintrc: false,
583 fix: true,
584 fixTypes: ["layout"],
585 plugins: {
586 test: {
587 rules: {
588 "no-program": require(getFixturePath("rules", "fix-types-test", "no-program.js"))
589 }
590 }
591 }
592 });
593 const inputPath = getFixturePath("fix-types/ignore-missing-meta.js");
594 const outputPath = getFixturePath("fix-types/ignore-missing-meta.expected.js");
595 const results = await eslint.lintFiles([inputPath]);
596 const expectedOutput = fs.readFileSync(outputPath, "utf8");
597
598 assert.strictEqual(results[0].output, expectedOutput);
599 });
600
601 it("should not throw an error when a rule is loaded after initialization with lintText()", async () => {
602 eslint = new ESLint({
603 cwd: path.join(fixtureDir, ".."),
604 useEslintrc: false,
605 fix: true,
606 fixTypes: ["layout"],
607 plugins: {
608 test: {
609 rules: {
610 "no-program": require(getFixturePath("rules", "fix-types-test", "no-program.js"))
611 }
612 }
613 }
614 });
615 const inputPath = getFixturePath("fix-types/ignore-missing-meta.js");
616 const outputPath = getFixturePath("fix-types/ignore-missing-meta.expected.js");
617 const results = await eslint.lintText(fs.readFileSync(inputPath, { encoding: "utf8" }), { filePath: inputPath });
618 const expectedOutput = fs.readFileSync(outputPath, "utf8");
619
620 assert.strictEqual(results[0].output, expectedOutput);
621 });
622 });
623
624 it("should return a message and omit fixed text when in fix mode and fixes aren't done", async () => {
625 eslint = new ESLint({
626 useEslintrc: false,
627 fix: true,
628 overrideConfig: {
629 rules: {
630 "no-undef": 2
631 }
632 },
633 ignore: false,
634 cwd: getFixturePath()
635 });
636 const options = { filePath: "passing.js" };
637 const results = await eslint.lintText("var bar = foo", options);
638
639 assert.deepStrictEqual(results, [
640 {
641 filePath: getFixturePath("passing.js"),
642 messages: [
643 {
644 ruleId: "no-undef",
645 severity: 2,
646 messageId: "undef",
647 message: "'foo' is not defined.",
648 line: 1,
649 column: 11,
650 endLine: 1,
651 endColumn: 14,
652 nodeType: "Identifier"
653 }
654 ],
8f9d1d4d 655 suppressedMessages: [],
56c4a2cb
DC
656 errorCount: 1,
657 warningCount: 0,
609c276f 658 fatalErrorCount: 0,
56c4a2cb
DC
659 fixableErrorCount: 0,
660 fixableWarningCount: 0,
661 source: "var bar = foo",
662 usedDeprecatedRules: []
663 }
664 ]);
665 });
666
667 it("should not delete code if there is a syntax error after trying to autofix.", async () => {
668 eslint = eslintWithPlugins({
669 useEslintrc: false,
670 fix: true,
671 overrideConfig: {
672 plugins: ["example"],
673 rules: {
674 "example/make-syntax-error": "error"
675 }
676 },
677 ignore: false,
678 cwd: getFixturePath()
679 });
680 const options = { filePath: "test.js" };
681 const results = await eslint.lintText("var bar = foo", options);
682
683 assert.deepStrictEqual(results, [
684 {
685 filePath: getFixturePath("test.js"),
686 messages: [
687 {
688 ruleId: null,
689 fatal: true,
690 severity: 2,
691 message: "Parsing error: Unexpected token is",
692 line: 1,
693 column: 19
694 }
695 ],
8f9d1d4d 696 suppressedMessages: [],
56c4a2cb
DC
697 errorCount: 1,
698 warningCount: 0,
609c276f 699 fatalErrorCount: 1,
56c4a2cb
DC
700 fixableErrorCount: 0,
701 fixableWarningCount: 0,
702 output: "var bar = foothis is a syntax error.",
703 usedDeprecatedRules: []
704 }
705 ]);
706 });
707
708 it("should not crash even if there are any syntax error since the first time.", async () => {
709 eslint = new ESLint({
710 useEslintrc: false,
711 fix: true,
712 overrideConfig: {
713 rules: {
714 "example/make-syntax-error": "error"
715 }
716 },
717 ignore: false,
718 cwd: getFixturePath()
719 });
720 const options = { filePath: "test.js" };
721 const results = await eslint.lintText("var bar =", options);
722
723 assert.deepStrictEqual(results, [
724 {
725 filePath: getFixturePath("test.js"),
726 messages: [
727 {
728 ruleId: null,
729 fatal: true,
730 severity: 2,
731 message: "Parsing error: Unexpected token",
732 line: 1,
733 column: 10
734 }
735 ],
8f9d1d4d 736 suppressedMessages: [],
56c4a2cb
DC
737 errorCount: 1,
738 warningCount: 0,
609c276f 739 fatalErrorCount: 1,
56c4a2cb
DC
740 fixableErrorCount: 0,
741 fixableWarningCount: 0,
742 source: "var bar =",
743 usedDeprecatedRules: []
744 }
745 ]);
746 });
747
748 it("should return source code of file in `source` property when errors are present", async () => {
749 eslint = new ESLint({
750 useEslintrc: false,
751 overrideConfig: {
752 rules: { semi: 2 }
753 }
754 });
755 const results = await eslint.lintText("var foo = 'bar'");
756
757 assert.strictEqual(results[0].source, "var foo = 'bar'");
758 });
759
760 it("should return source code of file in `source` property when warnings are present", async () => {
761 eslint = new ESLint({
762 useEslintrc: false,
763 overrideConfig: {
764 rules: { semi: 1 }
765 }
766 });
767 const results = await eslint.lintText("var foo = 'bar'");
768
769 assert.strictEqual(results[0].source, "var foo = 'bar'");
770 });
771
772
773 it("should not return a `source` property when no errors or warnings are present", async () => {
774 eslint = new ESLint({
775 useEslintrc: false,
776 overrideConfig: {
777 rules: { semi: 2 }
778 }
779 });
780 const results = await eslint.lintText("var foo = 'bar';");
781
782 assert.strictEqual(results[0].messages.length, 0);
783 assert.strictEqual(results[0].source, void 0);
784 });
785
786 it("should not return a `source` property when fixes are applied", async () => {
787 eslint = new ESLint({
788 useEslintrc: false,
789 fix: true,
790 overrideConfig: {
791 rules: {
792 semi: 2,
793 "no-unused-vars": 2
794 }
795 }
796 });
797 const results = await eslint.lintText("var msg = 'hi' + foo\n");
798
799 assert.strictEqual(results[0].source, void 0);
800 assert.strictEqual(results[0].output, "var msg = 'hi' + foo;\n");
801 });
802
803 it("should return a `source` property when a parsing error has occurred", async () => {
804 eslint = new ESLint({
805 useEslintrc: false,
806 overrideConfig: {
807 rules: { semi: 2 }
808 }
809 });
810 const results = await eslint.lintText("var bar = foothis is a syntax error.\n return bar;");
811
812 assert.deepStrictEqual(results, [
813 {
814 filePath: "<text>",
815 messages: [
816 {
817 ruleId: null,
818 fatal: true,
819 severity: 2,
820 message: "Parsing error: Unexpected token is",
821 line: 1,
822 column: 19
823 }
824 ],
8f9d1d4d 825 suppressedMessages: [],
56c4a2cb
DC
826 errorCount: 1,
827 warningCount: 0,
609c276f 828 fatalErrorCount: 1,
56c4a2cb
DC
829 fixableErrorCount: 0,
830 fixableWarningCount: 0,
831 source: "var bar = foothis is a syntax error.\n return bar;",
832 usedDeprecatedRules: []
833 }
834 ]);
835 });
836
837 // https://github.com/eslint/eslint/issues/5547
838 it("should respect default ignore rules, even with --no-ignore", async () => {
839 eslint = new ESLint({
840 cwd: getFixturePath(),
841 ignore: false
842 });
843 const results = await eslint.lintText("var bar = foo;", { filePath: "node_modules/passing.js", warnIgnored: true });
844 const expectedMsg = "File ignored by default. Use \"--ignore-pattern '!node_modules/*'\" to override.";
845
846 assert.strictEqual(results.length, 1);
847 assert.strictEqual(results[0].filePath, getFixturePath("node_modules/passing.js"));
848 assert.strictEqual(results[0].messages[0].message, expectedMsg);
849 });
850
851 describe('plugin shorthand notation ("@scope" for "@scope/eslint-plugin")', () => {
852 const Module = require("module");
853 let originalFindPath = null;
854
609c276f 855 /* eslint-disable no-underscore-dangle -- Override Node API */
56c4a2cb
DC
856 before(() => {
857 originalFindPath = Module._findPath;
858 Module._findPath = function(id, ...otherArgs) {
859 if (id === "@scope/eslint-plugin") {
860 return path.resolve(__dirname, "../../fixtures/plugin-shorthand/basic/node_modules/@scope/eslint-plugin/index.js");
861 }
862 return originalFindPath.call(this, id, ...otherArgs);
863 };
864 });
865 after(() => {
866 Module._findPath = originalFindPath;
867 });
609c276f 868 /* eslint-enable no-underscore-dangle -- Override Node API */
56c4a2cb
DC
869
870 it("should resolve 'plugins:[\"@scope\"]' to 'node_modules/@scope/eslint-plugin'.", async () => {
871 eslint = new ESLint({ cwd: getFixturePath("plugin-shorthand/basic") });
872 const [result] = await eslint.lintText("var x = 0", { filePath: "index.js" });
873
874 assert.strictEqual(result.filePath, getFixturePath("plugin-shorthand/basic/index.js"));
875 assert.strictEqual(result.messages[0].ruleId, "@scope/rule");
876 assert.strictEqual(result.messages[0].message, "OK");
877 });
878
879 it("should resolve 'extends:[\"plugin:@scope/recommended\"]' to 'node_modules/@scope/eslint-plugin'.", async () => {
880 eslint = new ESLint({ cwd: getFixturePath("plugin-shorthand/extends") });
881 const [result] = await eslint.lintText("var x = 0", { filePath: "index.js" });
882
883 assert.strictEqual(result.filePath, getFixturePath("plugin-shorthand/extends/index.js"));
884 assert.strictEqual(result.messages[0].ruleId, "@scope/rule");
885 assert.strictEqual(result.messages[0].message, "OK");
886 });
887 });
888
889 it("should warn when deprecated rules are found in a config", async () => {
890 eslint = new ESLint({
891 cwd: originalDir,
892 useEslintrc: false,
893 overrideConfigFile: "tests/fixtures/cli-engine/deprecated-rule-config/.eslintrc.yml"
894 });
895 const [result] = await eslint.lintText("foo");
896
897 assert.deepStrictEqual(
898 result.usedDeprecatedRules,
899 [{ ruleId: "indent-legacy", replacedBy: ["indent"] }]
900 );
901 });
902
903 it("should throw if non-string value is given to 'code' parameter", async () => {
904 eslint = new ESLint();
905 await assert.rejects(() => eslint.lintText(100), /'code' must be a string/u);
906 });
907
908 it("should throw if non-object value is given to 'options' parameter", async () => {
909 eslint = new ESLint();
910 await assert.rejects(() => eslint.lintText("var a = 0", "foo.js"), /'options' must be an object, null, or undefined/u);
911 });
912
913 it("should throw if 'options' argument contains unknown key", async () => {
914 eslint = new ESLint();
609c276f 915 await assert.rejects(() => eslint.lintText("var a = 0", { filename: "foo.js" }), /'options' must not include the unknown option\(s\): filename/u);
56c4a2cb
DC
916 });
917
918 it("should throw if non-string value is given to 'options.filePath' option", async () => {
919 eslint = new ESLint();
920 await assert.rejects(() => eslint.lintText("var a = 0", { filePath: "" }), /'options.filePath' must be a non-empty string or undefined/u);
921 });
922
923 it("should throw if non-boolean value is given to 'options.warnIgnored' option", async () => {
924 eslint = new ESLint();
925 await assert.rejects(() => eslint.lintText("var a = 0", { warnIgnored: "" }), /'options.warnIgnored' must be a boolean or undefined/u);
926 });
927 });
928
929 describe("lintFiles()", () => {
930
609c276f 931 /** @type {InstanceType<import("../../../lib/eslint").ESLint>} */
56c4a2cb
DC
932 let eslint;
933
934 it("should use correct parser when custom parser is specified", async () => {
935 eslint = new ESLint({
936 cwd: originalDir,
937 ignore: false
938 });
939 const filePath = path.resolve(__dirname, "../../fixtures/configurations/parser/custom.js");
940 const results = await eslint.lintFiles([filePath]);
941
942 assert.strictEqual(results.length, 1);
943 assert.strictEqual(results[0].messages.length, 1);
944 assert.strictEqual(results[0].messages[0].message, "Parsing error: Boom!");
945 });
946
947 it("should report zero messages when given a config file and a valid file", async () => {
948 eslint = new ESLint({
949 cwd: originalDir,
950 overrideConfigFile: ".eslintrc.js"
951 });
952 const results = await eslint.lintFiles(["lib/**/cli*.js"]);
953
954 assert.strictEqual(results.length, 2);
955 assert.strictEqual(results[0].messages.length, 0);
956 assert.strictEqual(results[1].messages.length, 0);
957 });
958
959 it("should handle multiple patterns with overlapping files", async () => {
960 eslint = new ESLint({
961 cwd: originalDir,
962 overrideConfigFile: ".eslintrc.js"
963 });
964 const results = await eslint.lintFiles(["lib/**/cli*.js", "lib/cli.?s", "lib/{cli,cli-engine/cli-engine}.js"]);
965
966 assert.strictEqual(results.length, 2);
967 assert.strictEqual(results[0].messages.length, 0);
968 assert.strictEqual(results[1].messages.length, 0);
969 });
970
971 it("should report zero messages when given a config file and a valid file and espree as parser", async () => {
972 eslint = new ESLint({
973 overrideConfig: {
974 parser: "espree",
975 parserOptions: {
6f036462 976 ecmaVersion: 2021
56c4a2cb
DC
977 }
978 },
979 useEslintrc: false
980 });
981 const results = await eslint.lintFiles(["lib/cli.js"]);
982
983 assert.strictEqual(results.length, 1);
984 assert.strictEqual(results[0].messages.length, 0);
985 });
986
987 it("should report zero messages when given a config file and a valid file and esprima as parser", async () => {
988 eslint = new ESLint({
989 overrideConfig: {
990 parser: "esprima"
991 },
992 useEslintrc: false,
993 ignore: false
994 });
995 const results = await eslint.lintFiles(["tests/fixtures/passing.js"]);
996
997 assert.strictEqual(results.length, 1);
998 assert.strictEqual(results[0].messages.length, 0);
999 });
1000
1001 it("should throw an error when given a config file and a valid file and invalid parser", async () => {
1002 eslint = new ESLint({
1003 overrideConfig: {
1004 parser: "test11"
1005 },
1006 useEslintrc: false
1007 });
1008
1009 await assert.rejects(async () => await eslint.lintFiles(["lib/cli.js"]), /Cannot find module 'test11'/u);
1010 });
1011
1012 it("should report zero messages when given a directory with a .js2 file", async () => {
1013 eslint = new ESLint({
1014 cwd: path.join(fixtureDir, ".."),
1015 extensions: [".js2"]
1016 });
1017 const results = await eslint.lintFiles([getFixturePath("files/foo.js2")]);
1018
1019 assert.strictEqual(results.length, 1);
1020 assert.strictEqual(results[0].messages.length, 0);
1021 });
1022
1023 it("should fall back to defaults when extensions is set to an empty array", async () => {
1024 eslint = new ESLint({
1025 cwd: getFixturePath("configurations"),
1026 overrideConfigFile: getFixturePath("configurations", "quotes-error.json"),
1027 extensions: []
1028 });
1029 const results = await eslint.lintFiles([getFixturePath("single-quoted.js")]);
1030
1031 assert.strictEqual(results.length, 1);
1032 assert.strictEqual(results[0].messages.length, 1);
1033 assert.strictEqual(results[0].messages[0].ruleId, "quotes");
1034 assert.strictEqual(results[0].messages[0].severity, 2);
1035 assert.strictEqual(results[0].errorCount, 1);
1036 assert.strictEqual(results[0].warningCount, 0);
1037 assert.strictEqual(results[0].fixableErrorCount, 1);
1038 assert.strictEqual(results[0].fixableWarningCount, 0);
1039 });
1040
1041 it("should report zero messages when given a directory with a .js and a .js2 file", async () => {
1042 eslint = new ESLint({
1043 extensions: [".js", ".js2"],
1044 ignore: false,
1045 cwd: getFixturePath("..")
1046 });
1047 const results = await eslint.lintFiles(["fixtures/files/"]);
1048
1049 assert.strictEqual(results.length, 2);
1050 assert.strictEqual(results[0].messages.length, 0);
1051 assert.strictEqual(results[1].messages.length, 0);
1052 });
1053
1054 it("should report zero messages when given a '**' pattern with a .js and a .js2 file", async () => {
1055 eslint = new ESLint({
1056 extensions: [".js", ".js2"],
1057 ignore: false,
1058 cwd: path.join(fixtureDir, "..")
1059 });
1060 const results = await eslint.lintFiles(["fixtures/files/*"]);
1061
1062 assert.strictEqual(results.length, 2);
1063 assert.strictEqual(results[0].messages.length, 0);
1064 assert.strictEqual(results[1].messages.length, 0);
1065 });
1066
1067 it("should resolve globs when 'globInputPaths' option is true", async () => {
1068 eslint = new ESLint({
1069 extensions: [".js", ".js2"],
1070 ignore: false,
1071 cwd: getFixturePath("..")
1072 });
1073 const results = await eslint.lintFiles(["fixtures/files/*"]);
1074
1075 assert.strictEqual(results.length, 2);
1076 assert.strictEqual(results[0].messages.length, 0);
1077 assert.strictEqual(results[1].messages.length, 0);
1078 });
1079
1080 it("should not resolve globs when 'globInputPaths' option is false", async () => {
1081 eslint = new ESLint({
1082 extensions: [".js", ".js2"],
1083 ignore: false,
1084 cwd: getFixturePath(".."),
1085 globInputPaths: false
1086 });
1087
1088 await assert.rejects(async () => {
1089 await eslint.lintFiles(["fixtures/files/*"]);
1090 }, /No files matching 'fixtures\/files\/\*' were found \(glob was disabled\)\./u);
1091 });
1092
1093 it("should report on all files passed explicitly, even if ignored by default", async () => {
1094 eslint = new ESLint({
1095 cwd: getFixturePath("cli-engine")
1096 });
1097 const results = await eslint.lintFiles(["node_modules/foo.js"]);
1098 const expectedMsg = "File ignored by default. Use \"--ignore-pattern '!node_modules/*'\" to override.";
1099
1100 assert.strictEqual(results.length, 1);
1101 assert.strictEqual(results[0].errorCount, 0);
1102 assert.strictEqual(results[0].warningCount, 1);
8f9d1d4d 1103 assert.strictEqual(results[0].fatalErrorCount, 0);
56c4a2cb
DC
1104 assert.strictEqual(results[0].fixableErrorCount, 0);
1105 assert.strictEqual(results[0].fixableWarningCount, 0);
1106 assert.strictEqual(results[0].messages[0].message, expectedMsg);
1107 });
1108
1109 it("should report on globs with explicit inclusion of dotfiles, even though ignored by default", async () => {
1110 eslint = new ESLint({
1111 cwd: getFixturePath("cli-engine"),
1112 overrideConfig: {
1113 rules: {
1114 quotes: [2, "single"]
1115 }
1116 }
1117 });
1118 const results = await eslint.lintFiles(["hidden/.hiddenfolder/*.js"]);
1119
1120 assert.strictEqual(results.length, 1);
1121 assert.strictEqual(results[0].errorCount, 1);
1122 assert.strictEqual(results[0].warningCount, 0);
1123 assert.strictEqual(results[0].fixableErrorCount, 1);
1124 assert.strictEqual(results[0].fixableWarningCount, 0);
1125 });
1126
1127 it("should not check default ignored files without --no-ignore flag", async () => {
1128 eslint = new ESLint({
1129 cwd: getFixturePath("cli-engine")
1130 });
1131
1132 await assert.rejects(async () => {
1133 await eslint.lintFiles(["node_modules"]);
1134 }, /All files matched by 'node_modules' are ignored\./u);
1135 });
1136
1137 // https://github.com/eslint/eslint/issues/5547
1138 it("should not check node_modules files even with --no-ignore flag", async () => {
1139 eslint = new ESLint({
1140 cwd: getFixturePath("cli-engine"),
1141 ignore: false
1142 });
1143
1144 await assert.rejects(async () => {
1145 await eslint.lintFiles(["node_modules"]);
1146 }, /All files matched by 'node_modules' are ignored\./u);
1147 });
1148
1149 it("should not check .hidden files if they are passed explicitly without --no-ignore flag", async () => {
1150 eslint = new ESLint({
1151 cwd: getFixturePath(".."),
1152 useEslintrc: false,
1153 overrideConfig: {
1154 rules: {
1155 quotes: [2, "single"]
1156 }
1157 }
1158 });
1159 const results = await eslint.lintFiles(["fixtures/files/.bar.js"]);
1160 const expectedMsg = "File ignored by default. Use a negated ignore pattern (like \"--ignore-pattern '!<relative/path/to/filename>'\") to override.";
1161
1162 assert.strictEqual(results.length, 1);
1163 assert.strictEqual(results[0].errorCount, 0);
1164 assert.strictEqual(results[0].warningCount, 1);
8f9d1d4d 1165 assert.strictEqual(results[0].fatalErrorCount, 0);
56c4a2cb
DC
1166 assert.strictEqual(results[0].fixableErrorCount, 0);
1167 assert.strictEqual(results[0].fixableWarningCount, 0);
1168 assert.strictEqual(results[0].messages[0].message, expectedMsg);
1169 });
1170
1171 // https://github.com/eslint/eslint/issues/12873
1172 it("should not check files within a .hidden folder if they are passed explicitly without the --no-ignore flag", async () => {
1173 eslint = new ESLint({
1174 cwd: getFixturePath("cli-engine"),
1175 useEslintrc: false,
1176 overrideConfig: {
1177 rules: {
1178 quotes: [2, "single"]
1179 }
1180 }
1181 });
1182 const results = await eslint.lintFiles(["hidden/.hiddenfolder/double-quotes.js"]);
1183 const expectedMsg = "File ignored by default. Use a negated ignore pattern (like \"--ignore-pattern '!<relative/path/to/filename>'\") to override.";
1184
1185 assert.strictEqual(results.length, 1);
1186 assert.strictEqual(results[0].errorCount, 0);
1187 assert.strictEqual(results[0].warningCount, 1);
8f9d1d4d 1188 assert.strictEqual(results[0].fatalErrorCount, 0);
56c4a2cb
DC
1189 assert.strictEqual(results[0].fixableErrorCount, 0);
1190 assert.strictEqual(results[0].fixableWarningCount, 0);
1191 assert.strictEqual(results[0].messages[0].message, expectedMsg);
1192 });
1193
1194 it("should check .hidden files if they are passed explicitly with --no-ignore flag", async () => {
1195 eslint = new ESLint({
1196 cwd: getFixturePath(".."),
1197 ignore: false,
1198 useEslintrc: false,
1199 overrideConfig: {
1200 rules: {
1201 quotes: [2, "single"]
1202 }
1203 }
1204 });
1205 const results = await eslint.lintFiles(["fixtures/files/.bar.js"]);
1206
1207 assert.strictEqual(results.length, 1);
1208 assert.strictEqual(results[0].warningCount, 0);
1209 assert.strictEqual(results[0].errorCount, 1);
1210 assert.strictEqual(results[0].fixableErrorCount, 1);
1211 assert.strictEqual(results[0].fixableWarningCount, 0);
1212 assert.strictEqual(results[0].messages[0].ruleId, "quotes");
1213 });
1214
1215 it("should check .hidden files if they are unignored with an --ignore-pattern", async () => {
1216 eslint = new ESLint({
1217 cwd: getFixturePath("cli-engine"),
1218 ignore: true,
1219 useEslintrc: false,
1220 overrideConfig: {
1221 ignorePatterns: "!.hidden*",
1222 rules: {
1223 quotes: [2, "single"]
1224 }
1225 }
1226 });
1227 const results = await eslint.lintFiles(["hidden/"]);
1228
1229 assert.strictEqual(results.length, 1);
1230 assert.strictEqual(results[0].warningCount, 0);
1231 assert.strictEqual(results[0].errorCount, 1);
1232 assert.strictEqual(results[0].fixableErrorCount, 1);
1233 assert.strictEqual(results[0].fixableWarningCount, 0);
1234 assert.strictEqual(results[0].messages[0].ruleId, "quotes");
1235 });
1236
1237 it("should report zero messages when given a pattern with a .js and a .js2 file", async () => {
1238 eslint = new ESLint({
1239 extensions: [".js", ".js2"],
1240 ignore: false,
1241 cwd: path.join(fixtureDir, "..")
1242 });
1243 const results = await eslint.lintFiles(["fixtures/files/*.?s*"]);
1244
1245 assert.strictEqual(results.length, 2);
1246 assert.strictEqual(results[0].messages.length, 0);
1247 assert.strictEqual(results[1].messages.length, 0);
1248 });
1249
1250 it("should return one error message when given a config with rules with options and severity level set to error", async () => {
1251 eslint = new ESLint({
1252 cwd: getFixturePath("configurations"),
1253 overrideConfigFile: getFixturePath("configurations", "quotes-error.json")
1254 });
1255 const results = await eslint.lintFiles([getFixturePath("single-quoted.js")]);
1256
1257 assert.strictEqual(results.length, 1);
1258 assert.strictEqual(results[0].messages.length, 1);
1259 assert.strictEqual(results[0].messages[0].ruleId, "quotes");
1260 assert.strictEqual(results[0].messages[0].severity, 2);
1261 assert.strictEqual(results[0].errorCount, 1);
1262 assert.strictEqual(results[0].warningCount, 0);
1263 assert.strictEqual(results[0].fixableErrorCount, 1);
1264 assert.strictEqual(results[0].fixableWarningCount, 0);
1265 });
1266
1267 it("should return 3 messages when given a config file and a directory of 3 valid files", async () => {
1268 eslint = new ESLint({
1269 cwd: path.join(fixtureDir, ".."),
1270 overrideConfigFile: getFixturePath("configurations", "semi-error.json")
1271 });
34eeec05
TL
1272 const fixturePath = getFixturePath("formatters");
1273 const results = await eslint.lintFiles([fixturePath]);
56c4a2cb 1274
34eeec05
TL
1275 assert.strictEqual(results.length, 5);
1276 assert.strictEqual(path.relative(fixturePath, results[0].filePath), "async.js");
56c4a2cb
DC
1277 assert.strictEqual(results[0].errorCount, 0);
1278 assert.strictEqual(results[0].warningCount, 0);
1279 assert.strictEqual(results[0].fixableErrorCount, 0);
1280 assert.strictEqual(results[0].fixableWarningCount, 0);
34eeec05
TL
1281 assert.strictEqual(results[0].messages.length, 0);
1282 assert.strictEqual(path.relative(fixturePath, results[1].filePath), "broken.js");
56c4a2cb
DC
1283 assert.strictEqual(results[1].errorCount, 0);
1284 assert.strictEqual(results[1].warningCount, 0);
1285 assert.strictEqual(results[1].fixableErrorCount, 0);
1286 assert.strictEqual(results[1].fixableWarningCount, 0);
34eeec05
TL
1287 assert.strictEqual(results[1].messages.length, 0);
1288 assert.strictEqual(path.relative(fixturePath, results[2].filePath), "cwd.js");
56c4a2cb
DC
1289 assert.strictEqual(results[2].errorCount, 0);
1290 assert.strictEqual(results[2].warningCount, 0);
1291 assert.strictEqual(results[2].fixableErrorCount, 0);
1292 assert.strictEqual(results[2].fixableWarningCount, 0);
34eeec05
TL
1293 assert.strictEqual(results[2].messages.length, 0);
1294 assert.strictEqual(path.relative(fixturePath, results[3].filePath), "simple.js");
1295 assert.strictEqual(results[3].errorCount, 0);
1296 assert.strictEqual(results[3].warningCount, 0);
1297 assert.strictEqual(results[3].fixableErrorCount, 0);
1298 assert.strictEqual(results[3].fixableWarningCount, 0);
1299 assert.strictEqual(results[3].messages.length, 0);
1300 assert.strictEqual(path.relative(fixturePath, results[4].filePath), path.join("test", "simple.js"));
1301 assert.strictEqual(results[4].errorCount, 0);
1302 assert.strictEqual(results[4].warningCount, 0);
1303 assert.strictEqual(results[4].fixableErrorCount, 0);
1304 assert.strictEqual(results[4].fixableWarningCount, 0);
1305 assert.strictEqual(results[4].messages.length, 0);
56c4a2cb
DC
1306 });
1307
1308 it("should process when file is given by not specifying extensions", async () => {
1309 eslint = new ESLint({
1310 ignore: false,
1311 cwd: path.join(fixtureDir, "..")
1312 });
1313 const results = await eslint.lintFiles(["fixtures/files/foo.js2"]);
1314
1315 assert.strictEqual(results.length, 1);
1316 assert.strictEqual(results[0].messages.length, 0);
1317 });
1318
1319 it("should return zero messages when given a config with environment set to browser", async () => {
1320 eslint = new ESLint({
1321 cwd: path.join(fixtureDir, ".."),
1322 overrideConfigFile: getFixturePath("configurations", "env-browser.json")
1323 });
1324 const results = await eslint.lintFiles([fs.realpathSync(getFixturePath("globals-browser.js"))]);
1325
1326 assert.strictEqual(results.length, 1);
1327 assert.strictEqual(results[0].messages.length, 0);
1328 });
1329
1330 it("should return zero messages when given an option to set environment to browser", async () => {
1331 eslint = new ESLint({
1332 cwd: path.join(fixtureDir, ".."),
1333 overrideConfig: {
1334 env: { browser: true },
1335 rules: {
1336 "no-alert": 0,
1337 "no-undef": 2
1338 }
1339 }
1340 });
1341 const results = await eslint.lintFiles([fs.realpathSync(getFixturePath("globals-browser.js"))]);
1342
1343 assert.strictEqual(results.length, 1);
1344 assert.strictEqual(results[0].messages.length, 0);
1345 });
1346
1347 it("should return zero messages when given a config with environment set to Node.js", async () => {
1348 eslint = new ESLint({
1349 cwd: path.join(fixtureDir, ".."),
1350 overrideConfigFile: getFixturePath("configurations", "env-node.json")
1351 });
1352 const results = await eslint.lintFiles([fs.realpathSync(getFixturePath("globals-node.js"))]);
1353
1354 assert.strictEqual(results.length, 1);
1355 assert.strictEqual(results[0].messages.length, 0);
1356 });
1357
1358 it("should not return results from previous call when calling more than once", async () => {
1359 eslint = new ESLint({
1360 cwd: path.join(fixtureDir, ".."),
1361 ignore: false,
1362 overrideConfig: {
1363 rules: {
1364 semi: 2
1365 }
1366 }
1367 });
1368 const failFilePath = fs.realpathSync(getFixturePath("missing-semicolon.js"));
1369 const passFilePath = fs.realpathSync(getFixturePath("passing.js"));
1370
1371 let results = await eslint.lintFiles([failFilePath]);
1372
1373 assert.strictEqual(results.length, 1);
1374 assert.strictEqual(results[0].filePath, failFilePath);
1375 assert.strictEqual(results[0].messages.length, 1);
1376 assert.strictEqual(results[0].messages[0].ruleId, "semi");
1377 assert.strictEqual(results[0].messages[0].severity, 2);
1378
1379 results = await eslint.lintFiles([passFilePath]);
1380 assert.strictEqual(results.length, 1);
1381 assert.strictEqual(results[0].filePath, passFilePath);
1382 assert.strictEqual(results[0].messages.length, 0);
1383 });
1384
1385 it("should throw an error when given a directory with all eslint excluded files in the directory", async () => {
1386 eslint = new ESLint({
1387 ignorePath: getFixturePath(".eslintignore")
1388 });
1389
1390 await assert.rejects(async () => {
1391 await eslint.lintFiles([getFixturePath("./cli-engine/")]);
1392 }, new RegExp(escapeStringRegExp(`All files matched by '${getFixturePath("./cli-engine/")}' are ignored.`), "u"));
1393 });
1394
1395 it("should throw an error when all given files are ignored", async () => {
1396 await assert.rejects(async () => {
1397 await eslint.lintFiles(["tests/fixtures/cli-engine/"]);
1398 }, /All files matched by 'tests\/fixtures\/cli-engine\/' are ignored\./u);
1399 });
1400
1401 it("should throw an error when all given files are ignored even with a `./` prefix", async () => {
1402 eslint = new ESLint({
1403 ignorePath: getFixturePath(".eslintignore")
1404 });
1405
1406 await assert.rejects(async () => {
1407 await eslint.lintFiles(["./tests/fixtures/cli-engine/"]);
1408 }, /All files matched by '\.\/tests\/fixtures\/cli-engine\/' are ignored\./u);
1409 });
1410
1411 // https://github.com/eslint/eslint/issues/3788
1412 it("should ignore one-level down node_modules when ignore file has 'node_modules/' in it", async () => {
1413 eslint = new ESLint({
1414 ignorePath: getFixturePath("cli-engine", "nested_node_modules", ".eslintignore"),
1415 useEslintrc: false,
1416 overrideConfig: {
1417 rules: {
1418 quotes: [2, "double"]
1419 }
1420 },
1421 cwd: getFixturePath("cli-engine", "nested_node_modules")
1422 });
1423 const results = await eslint.lintFiles(["."]);
1424
1425 assert.strictEqual(results.length, 1);
1426 assert.strictEqual(results[0].errorCount, 0);
1427 assert.strictEqual(results[0].warningCount, 0);
1428 assert.strictEqual(results[0].fixableErrorCount, 0);
1429 assert.strictEqual(results[0].fixableWarningCount, 0);
1430 });
1431
1432 // https://github.com/eslint/eslint/issues/3812
1433 it("should ignore all files and throw an error when tests/fixtures/ is in ignore file", async () => {
1434 eslint = new ESLint({
1435 ignorePath: getFixturePath("cli-engine/.eslintignore2"),
1436 useEslintrc: false,
1437 overrideConfig: {
1438 rules: {
1439 quotes: [2, "double"]
1440 }
1441 }
1442 });
1443
1444 await assert.rejects(async () => {
1445 await eslint.lintFiles(["./tests/fixtures/cli-engine/"]);
1446 }, /All files matched by '\.\/tests\/fixtures\/cli-engine\/' are ignored\./u);
1447 });
1448
8f9d1d4d
DC
1449 // https://github.com/eslint/eslint/issues/15642
1450 it("should ignore files that are ignored by patterns with escaped brackets", async () => {
1451 eslint = new ESLint({
1452 ignorePath: getFixturePath("ignored-paths", ".eslintignoreWithEscapedBrackets"),
1453 useEslintrc: false,
1454 cwd: getFixturePath("ignored-paths")
1455 });
1456
1457 // Only `brackets/index.js` should be linted. Other files in `brackets/` should be ignored.
1458 const results = await eslint.lintFiles(["brackets/*.js"]);
1459
1460 assert.strictEqual(results.length, 1);
1461 assert.strictEqual(results[0].filePath, getFixturePath("ignored-paths", "brackets", "index.js"));
1462 });
1463
56c4a2cb
DC
1464 it("should throw an error when all given files are ignored via ignore-pattern", async () => {
1465 eslint = new ESLint({
1466 overrideConfig: {
1467 ignorePatterns: "tests/fixtures/single-quoted.js"
1468 }
1469 });
1470
1471 await assert.rejects(async () => {
1472 await eslint.lintFiles(["tests/fixtures/*-quoted.js"]);
1473 }, /All files matched by 'tests\/fixtures\/\*-quoted\.js' are ignored\./u);
1474 });
1475
1476 it("should return a warning when an explicitly given file is ignored", async () => {
1477 eslint = new ESLint({
1478 ignorePath: getFixturePath(".eslintignore"),
1479 cwd: getFixturePath()
1480 });
1481 const filePath = getFixturePath("passing.js");
1482 const results = await eslint.lintFiles([filePath]);
1483
1484 assert.strictEqual(results.length, 1);
1485 assert.strictEqual(results[0].filePath, filePath);
1486 assert.strictEqual(results[0].messages[0].severity, 1);
1487 assert.strictEqual(results[0].messages[0].message, "File ignored because of a matching ignore pattern. Use \"--no-ignore\" to override.");
1488 assert.strictEqual(results[0].errorCount, 0);
1489 assert.strictEqual(results[0].warningCount, 1);
8f9d1d4d 1490 assert.strictEqual(results[0].fatalErrorCount, 0);
56c4a2cb
DC
1491 assert.strictEqual(results[0].fixableErrorCount, 0);
1492 assert.strictEqual(results[0].fixableWarningCount, 0);
1493 });
1494
1495 it("should return two messages when given a file in excluded files list while ignore is off", async () => {
1496 eslint = new ESLint({
1497 ignorePath: getFixturePath(".eslintignore"),
1498 ignore: false,
1499 overrideConfig: {
1500 rules: {
1501 "no-undef": 2
1502 }
1503 }
1504 });
1505 const filePath = fs.realpathSync(getFixturePath("undef.js"));
1506 const results = await eslint.lintFiles([filePath]);
1507
1508 assert.strictEqual(results.length, 1);
1509 assert.strictEqual(results[0].filePath, filePath);
1510 assert.strictEqual(results[0].messages[0].ruleId, "no-undef");
1511 assert.strictEqual(results[0].messages[0].severity, 2);
1512 assert.strictEqual(results[0].messages[1].ruleId, "no-undef");
1513 assert.strictEqual(results[0].messages[1].severity, 2);
1514 });
1515
1516 it("should return zero messages when executing a file with a shebang", async () => {
1517 eslint = new ESLint({
1518 ignore: false
1519 });
1520 const results = await eslint.lintFiles([getFixturePath("shebang.js")]);
1521
1522 assert.strictEqual(results.length, 1);
1523 assert.strictEqual(results[0].messages.length, 0);
1524 });
1525
1526 it("should give a warning when loading a custom rule that doesn't exist", async () => {
1527 eslint = new ESLint({
1528 ignore: false,
1529 rulePaths: [getFixturePath("rules", "dir1")],
1530 overrideConfigFile: getFixturePath("rules", "missing-rule.json")
1531 });
1532 const results = await eslint.lintFiles([getFixturePath("rules", "test", "test-custom-rule.js")]);
1533
1534 assert.strictEqual(results.length, 1);
1535 assert.strictEqual(results[0].messages.length, 1);
1536 assert.strictEqual(results[0].messages[0].ruleId, "missing-rule");
1537 assert.strictEqual(results[0].messages[0].severity, 2);
1538 assert.strictEqual(results[0].messages[0].message, "Definition for rule 'missing-rule' was not found.");
1539 });
1540
1541 it("should throw an error when loading a bad custom rule", async () => {
1542 eslint = new ESLint({
1543 ignore: false,
1544 rulePaths: [getFixturePath("rules", "wrong")],
1545 overrideConfigFile: getFixturePath("rules", "eslint.json")
1546 });
1547
1548
1549 await assert.rejects(async () => {
1550 await eslint.lintFiles([getFixturePath("rules", "test", "test-custom-rule.js")]);
1551 }, /Error while loading rule 'custom-rule'/u);
1552 });
1553
1554 it("should return one message when a custom rule matches a file", async () => {
1555 eslint = new ESLint({
1556 ignore: false,
1557 useEslintrc: false,
1558 rulePaths: [getFixturePath("rules/")],
1559 overrideConfigFile: getFixturePath("rules", "eslint.json")
1560 });
1561 const filePath = fs.realpathSync(getFixturePath("rules", "test", "test-custom-rule.js"));
1562 const results = await eslint.lintFiles([filePath]);
1563
1564 assert.strictEqual(results.length, 1);
1565 assert.strictEqual(results[0].filePath, filePath);
1566 assert.strictEqual(results[0].messages.length, 2);
1567 assert.strictEqual(results[0].messages[0].ruleId, "custom-rule");
1568 assert.strictEqual(results[0].messages[0].severity, 1);
1569 });
1570
1571 it("should load custom rule from the provided cwd", async () => {
1572 const cwd = path.resolve(getFixturePath("rules"));
1573
1574 eslint = new ESLint({
1575 ignore: false,
1576 cwd,
1577 rulePaths: ["./"],
1578 overrideConfigFile: "eslint.json"
1579 });
1580 const filePath = fs.realpathSync(getFixturePath("rules", "test", "test-custom-rule.js"));
1581 const results = await eslint.lintFiles([filePath]);
1582
1583 assert.strictEqual(results.length, 1);
1584 assert.strictEqual(results[0].filePath, filePath);
1585 assert.strictEqual(results[0].messages.length, 2);
1586 assert.strictEqual(results[0].messages[0].ruleId, "custom-rule");
1587 assert.strictEqual(results[0].messages[0].severity, 1);
1588 });
1589
1590 it("should return messages when multiple custom rules match a file", async () => {
1591 eslint = new ESLint({
1592 ignore: false,
1593 rulePaths: [
1594 getFixturePath("rules", "dir1"),
1595 getFixturePath("rules", "dir2")
1596 ],
1597 overrideConfigFile: getFixturePath("rules", "multi-rulesdirs.json")
1598 });
1599 const filePath = fs.realpathSync(getFixturePath("rules", "test-multi-rulesdirs.js"));
1600 const results = await eslint.lintFiles([filePath]);
1601
1602 assert.strictEqual(results.length, 1);
1603 assert.strictEqual(results[0].filePath, filePath);
1604 assert.strictEqual(results[0].messages.length, 2);
1605 assert.strictEqual(results[0].messages[0].ruleId, "no-literals");
1606 assert.strictEqual(results[0].messages[0].severity, 2);
1607 assert.strictEqual(results[0].messages[1].ruleId, "no-strings");
1608 assert.strictEqual(results[0].messages[1].severity, 2);
1609 });
1610
1611 it("should return zero messages when executing without useEslintrc flag", async () => {
1612 eslint = new ESLint({
1613 ignore: false,
1614 useEslintrc: false
1615 });
1616 const filePath = fs.realpathSync(getFixturePath("missing-semicolon.js"));
1617 const results = await eslint.lintFiles([filePath]);
1618
1619 assert.strictEqual(results.length, 1);
1620 assert.strictEqual(results[0].filePath, filePath);
1621 assert.strictEqual(results[0].messages.length, 0);
1622 });
1623
1624 it("should return zero messages when executing without useEslintrc flag in Node.js environment", async () => {
1625 eslint = new ESLint({
1626 ignore: false,
1627 useEslintrc: false,
1628 overrideConfig: {
1629 env: { node: true }
1630 }
1631 });
1632 const filePath = fs.realpathSync(getFixturePath("process-exit.js"));
1633 const results = await eslint.lintFiles([filePath]);
1634
1635 assert.strictEqual(results.length, 1);
1636 assert.strictEqual(results[0].filePath, filePath);
1637 assert.strictEqual(results[0].messages.length, 0);
1638 });
1639
1640 it("should return zero messages and ignore .eslintrc files when executing with no-eslintrc flag", async () => {
1641 eslint = new ESLint({
1642 ignore: false,
1643 useEslintrc: false,
1644 overrideConfig: {
1645 env: { node: true }
1646 }
1647 });
1648 const filePath = fs.realpathSync(getFixturePath("eslintrc", "quotes.js"));
1649 const results = await eslint.lintFiles([filePath]);
1650
1651 assert.strictEqual(results.length, 1);
1652 assert.strictEqual(results[0].filePath, filePath);
1653 assert.strictEqual(results[0].messages.length, 0);
1654 });
1655
1656 it("should return zero messages and ignore package.json files when executing with no-eslintrc flag", async () => {
1657 eslint = new ESLint({
1658 ignore: false,
1659 useEslintrc: false,
1660 overrideConfig: {
1661 env: { node: true }
1662 }
1663 });
1664 const filePath = fs.realpathSync(getFixturePath("packagejson", "quotes.js"));
1665 const results = await eslint.lintFiles([filePath]);
1666
1667 assert.strictEqual(results.length, 1);
1668 assert.strictEqual(results[0].filePath, filePath);
1669 assert.strictEqual(results[0].messages.length, 0);
1670 });
1671
1672 it("should warn when deprecated rules are configured", async () => {
1673 eslint = new ESLint({
1674 cwd: originalDir,
1675 overrideConfigFile: ".eslintrc.js",
1676 overrideConfig: {
1677 rules: {
1678 "indent-legacy": 1,
1679 "require-jsdoc": 1,
1680 "valid-jsdoc": 1
1681 }
1682 }
1683 });
1684 const results = await eslint.lintFiles(["lib/cli*.js"]);
1685
1686 assert.deepStrictEqual(
1687 results[0].usedDeprecatedRules,
1688 [
1689 { ruleId: "indent-legacy", replacedBy: ["indent"] },
1690 { ruleId: "require-jsdoc", replacedBy: [] },
1691 { ruleId: "valid-jsdoc", replacedBy: [] }
1692 ]
1693 );
1694 });
1695
1696 it("should not warn when deprecated rules are not configured", async () => {
1697 eslint = new ESLint({
1698 cwd: originalDir,
1699 overrideConfigFile: ".eslintrc.js",
1700 overrideConfig: {
1701 rules: { indent: 1, "valid-jsdoc": 0, "require-jsdoc": 0 }
1702 }
1703 });
1704 const results = await eslint.lintFiles(["lib/cli*.js"]);
1705
1706 assert.deepStrictEqual(results[0].usedDeprecatedRules, []);
1707 });
1708
1709 it("should warn when deprecated rules are found in a config", async () => {
1710 eslint = new ESLint({
1711 cwd: originalDir,
1712 overrideConfigFile: "tests/fixtures/cli-engine/deprecated-rule-config/.eslintrc.yml",
1713 useEslintrc: false
1714 });
1715 const results = await eslint.lintFiles(["lib/cli*.js"]);
1716
1717 assert.deepStrictEqual(
1718 results[0].usedDeprecatedRules,
1719 [{ ruleId: "indent-legacy", replacedBy: ["indent"] }]
1720 );
1721 });
1722
1723 describe("Fix Mode", () => {
1724 it("should return fixed text on multiple files when in fix mode", async () => {
1725
1726 /**
1727 * Converts CRLF to LF in output.
1728 * This is a workaround for git's autocrlf option on Windows.
1729 * @param {Object} result A result object to convert.
1730 * @returns {void}
1731 */
1732 function convertCRLF(result) {
1733 if (result && result.output) {
1734 result.output = result.output.replace(/\r\n/gu, "\n");
1735 }
1736 }
1737
1738 eslint = new ESLint({
1739 cwd: path.join(fixtureDir, ".."),
1740 useEslintrc: false,
1741 fix: true,
1742 overrideConfig: {
1743 rules: {
1744 semi: 2,
1745 quotes: [2, "double"],
1746 eqeqeq: 2,
1747 "no-undef": 2,
1748 "space-infix-ops": 2
1749 }
1750 }
1751 });
1752 const results = await eslint.lintFiles([path.resolve(fixtureDir, `${fixtureDir}/fixmode`)]);
1753
1754 results.forEach(convertCRLF);
1755 assert.deepStrictEqual(results, [
1756 {
1757 filePath: fs.realpathSync(path.resolve(fixtureDir, "fixmode/multipass.js")),
1758 messages: [],
8f9d1d4d 1759 suppressedMessages: [],
56c4a2cb
DC
1760 errorCount: 0,
1761 warningCount: 0,
609c276f 1762 fatalErrorCount: 0,
56c4a2cb
DC
1763 fixableErrorCount: 0,
1764 fixableWarningCount: 0,
1765 output: "true ? \"yes\" : \"no\";\n",
1766 usedDeprecatedRules: []
1767 },
1768 {
1769 filePath: fs.realpathSync(path.resolve(fixtureDir, "fixmode/ok.js")),
1770 messages: [],
8f9d1d4d 1771 suppressedMessages: [],
56c4a2cb
DC
1772 errorCount: 0,
1773 warningCount: 0,
609c276f 1774 fatalErrorCount: 0,
56c4a2cb
DC
1775 fixableErrorCount: 0,
1776 fixableWarningCount: 0,
1777 usedDeprecatedRules: []
1778 },
1779 {
1780 filePath: fs.realpathSync(path.resolve(fixtureDir, "fixmode/quotes-semi-eqeqeq.js")),
1781 messages: [
1782 {
1783 column: 9,
1784 line: 2,
1785 endColumn: 11,
1786 endLine: 2,
1787 message: "Expected '===' and instead saw '=='.",
1788 messageId: "unexpected",
1789 nodeType: "BinaryExpression",
1790 ruleId: "eqeqeq",
1791 severity: 2
1792 }
1793 ],
8f9d1d4d 1794 suppressedMessages: [],
56c4a2cb
DC
1795 errorCount: 1,
1796 warningCount: 0,
609c276f 1797 fatalErrorCount: 0,
56c4a2cb
DC
1798 fixableErrorCount: 0,
1799 fixableWarningCount: 0,
1800 output: "var msg = \"hi\";\nif (msg == \"hi\") {\n\n}\n",
1801 usedDeprecatedRules: []
1802 },
1803 {
1804 filePath: fs.realpathSync(path.resolve(fixtureDir, "fixmode/quotes.js")),
1805 messages: [
1806 {
1807 column: 18,
1808 line: 1,
1809 endColumn: 21,
1810 endLine: 1,
1811 messageId: "undef",
1812 message: "'foo' is not defined.",
1813 nodeType: "Identifier",
1814 ruleId: "no-undef",
1815 severity: 2
1816 }
1817 ],
8f9d1d4d 1818 suppressedMessages: [],
56c4a2cb
DC
1819 errorCount: 1,
1820 warningCount: 0,
609c276f 1821 fatalErrorCount: 0,
56c4a2cb
DC
1822 fixableErrorCount: 0,
1823 fixableWarningCount: 0,
1824 output: "var msg = \"hi\" + foo;\n",
1825 usedDeprecatedRules: []
1826 }
1827 ]);
1828 });
1829
1830 it("should run autofix even if files are cached without autofix results", async () => {
1831 const baseOptions = {
1832 cwd: path.join(fixtureDir, ".."),
1833 useEslintrc: false,
1834 overrideConfig: {
1835 rules: {
1836 semi: 2,
1837 quotes: [2, "double"],
1838 eqeqeq: 2,
1839 "no-undef": 2,
1840 "space-infix-ops": 2
1841 }
1842 }
1843 };
1844
1845 eslint = new ESLint(Object.assign({}, baseOptions, { cache: true, fix: false }));
1846
1847 // Do initial lint run and populate the cache file
1848 await eslint.lintFiles([path.resolve(fixtureDir, `${fixtureDir}/fixmode`)]);
1849
1850 eslint = new ESLint(Object.assign({}, baseOptions, { cache: true, fix: true }));
1851 const results = await eslint.lintFiles([path.resolve(fixtureDir, `${fixtureDir}/fixmode`)]);
1852
1853 assert(results.some(result => result.output));
1854 });
1855 });
1856
1857 // These tests have to do with https://github.com/eslint/eslint/issues/963
1858
1859 describe("configuration hierarchy", () => {
1860
1861 // Default configuration - blank
1862 it("should return zero messages when executing with no .eslintrc", async () => {
1863 eslint = new ESLint({
1864 cwd: path.join(fixtureDir, ".."),
1865 useEslintrc: false
1866 });
1867 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/broken/console-wrong-quotes.js`)]);
1868
1869 assert.strictEqual(results.length, 1);
1870 assert.strictEqual(results[0].messages.length, 0);
1871 });
1872
1873 // No default configuration rules - conf/environments.js (/*eslint-env node*/)
1874 it("should return zero messages when executing with no .eslintrc in the Node.js environment", async () => {
1875 eslint = new ESLint({
1876 cwd: path.join(fixtureDir, ".."),
1877 useEslintrc: false
1878 });
1879 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/broken/console-wrong-quotes-node.js`)]);
1880
1881 assert.strictEqual(results.length, 1);
1882 assert.strictEqual(results[0].messages.length, 0);
1883 });
1884
1885 // Project configuration - first level .eslintrc
1886 it("should return zero messages when executing with .eslintrc in the Node.js environment", async () => {
1887 eslint = new ESLint({
1888 cwd: path.join(fixtureDir, "..")
1889 });
1890 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/broken/process-exit.js`)]);
1891
1892 assert.strictEqual(results.length, 1);
1893 assert.strictEqual(results[0].messages.length, 0);
1894 });
1895
1896 // Project configuration - first level .eslintrc
1897 it("should return zero messages when executing with .eslintrc in the Node.js environment", async () => {
1898 eslint = new ESLint({
1899 cwd: path.join(fixtureDir, "..")
1900 });
1901 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/broken/process-exit.js`)]);
1902
1903 assert.strictEqual(results.length, 1);
1904 assert.strictEqual(results[0].messages.length, 0);
1905 });
1906
1907 // Project configuration - first level .eslintrc
1908 it("should return one message when executing with .eslintrc", async () => {
1909 eslint = new ESLint({
1910 cwd: path.join(fixtureDir, "..")
1911 });
1912 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/broken/console-wrong-quotes.js`)]);
1913
1914 assert.strictEqual(results.length, 1);
1915 assert.strictEqual(results[0].messages.length, 1);
1916 assert.strictEqual(results[0].messages[0].ruleId, "quotes");
1917 assert.strictEqual(results[0].messages[0].severity, 2);
1918 });
1919
1920 // Project configuration - second level .eslintrc
1921 it("should return one message when executing with local .eslintrc that overrides parent .eslintrc", async () => {
1922 eslint = new ESLint({
1923 cwd: path.join(fixtureDir, "..")
1924 });
1925 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/broken/subbroken/console-wrong-quotes.js`)]);
1926
1927 assert.strictEqual(results.length, 1);
1928 assert.strictEqual(results[0].messages.length, 1);
1929 assert.strictEqual(results[0].messages[0].ruleId, "no-console");
1930 assert.strictEqual(results[0].messages[0].severity, 1);
1931 });
1932
1933 // Project configuration - third level .eslintrc
1934 it("should return one message when executing with local .eslintrc that overrides parent and grandparent .eslintrc", async () => {
1935 eslint = new ESLint({
1936 cwd: path.join(fixtureDir, "..")
1937 });
1938 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/broken/subbroken/subsubbroken/console-wrong-quotes.js`)]);
1939
1940 assert.strictEqual(results.length, 1);
1941 assert.strictEqual(results[0].messages.length, 1);
1942 assert.strictEqual(results[0].messages[0].ruleId, "quotes");
1943 assert.strictEqual(results[0].messages[0].severity, 1);
1944 });
1945
1946 // Project configuration - first level package.json
1947 it("should return one message when executing with package.json", async () => {
1948 eslint = new ESLint({
1949 cwd: path.join(fixtureDir, "..")
1950 });
1951 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/packagejson/subdir/wrong-quotes.js`)]);
1952
1953 assert.strictEqual(results.length, 1);
1954 assert.strictEqual(results[0].messages.length, 1);
1955 assert.strictEqual(results[0].messages[0].ruleId, "quotes");
1956 assert.strictEqual(results[0].messages[0].severity, 1);
1957 });
1958
1959 // Project configuration - second level package.json
1960 it("should return zero messages when executing with local package.json that overrides parent package.json", async () => {
1961 eslint = new ESLint({
1962 cwd: path.join(fixtureDir, "..")
1963 });
1964 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/packagejson/subdir/subsubdir/wrong-quotes.js`)]);
1965
1966 assert.strictEqual(results.length, 1);
1967 assert.strictEqual(results[0].messages.length, 0);
1968 });
1969
1970 // Project configuration - third level package.json
1971 it("should return one message when executing with local package.json that overrides parent and grandparent package.json", async () => {
1972 eslint = new ESLint({
1973 cwd: path.join(fixtureDir, "..")
1974 });
1975 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/packagejson/subdir/subsubdir/subsubsubdir/wrong-quotes.js`)]);
1976
1977 assert.strictEqual(results.length, 1);
1978 assert.strictEqual(results[0].messages.length, 1);
1979 assert.strictEqual(results[0].messages[0].ruleId, "quotes");
1980 assert.strictEqual(results[0].messages[0].severity, 2);
1981 });
1982
1983 // Project configuration - .eslintrc overrides package.json in same directory
1984 it("should return one message when executing with .eslintrc that overrides a package.json in the same directory", async () => {
1985 eslint = new ESLint({
1986 cwd: path.join(fixtureDir, "..")
1987 });
1988 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/packagejson/wrong-quotes.js`)]);
1989
1990 assert.strictEqual(results.length, 1);
1991 assert.strictEqual(results[0].messages.length, 1);
1992 assert.strictEqual(results[0].messages[0].ruleId, "quotes");
1993 assert.strictEqual(results[0].messages[0].severity, 2);
1994 });
1995
1996 // Command line configuration - --config with first level .eslintrc
1997 it("should return two messages when executing with config file that adds to local .eslintrc", async () => {
1998 eslint = new ESLint({
1999 cwd: path.join(fixtureDir, ".."),
2000 overrideConfigFile: `${fixtureDir}/config-hierarchy/broken/add-conf.yaml`
2001 });
2002 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/broken/console-wrong-quotes.js`)]);
2003
2004 assert.strictEqual(results.length, 1);
2005 assert.strictEqual(results[0].messages.length, 2);
2006 assert.strictEqual(results[0].messages[0].ruleId, "quotes");
2007 assert.strictEqual(results[0].messages[0].severity, 2);
2008 assert.strictEqual(results[0].messages[1].ruleId, "semi");
2009 assert.strictEqual(results[0].messages[1].severity, 1);
2010 });
2011
2012 // Command line configuration - --config with first level .eslintrc
2013 it("should return no messages when executing with config file that overrides local .eslintrc", async () => {
2014 eslint = new ESLint({
2015 cwd: path.join(fixtureDir, ".."),
2016 overrideConfigFile: `${fixtureDir}/config-hierarchy/broken/override-conf.yaml`
2017 });
2018 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/broken/console-wrong-quotes.js`)]);
2019
2020 assert.strictEqual(results.length, 1);
2021 assert.strictEqual(results[0].messages.length, 0);
2022 });
2023
2024 // Command line configuration - --config with second level .eslintrc
2025 it("should return two messages when executing with config file that adds to local and parent .eslintrc", async () => {
2026 eslint = new ESLint({
2027 cwd: path.join(fixtureDir, ".."),
2028 overrideConfigFile: `${fixtureDir}/config-hierarchy/broken/add-conf.yaml`
2029 });
2030 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/broken/subbroken/console-wrong-quotes.js`)]);
2031
2032 assert.strictEqual(results.length, 1);
2033 assert.strictEqual(results[0].messages.length, 2);
2034 assert.strictEqual(results[0].messages[0].ruleId, "no-console");
2035 assert.strictEqual(results[0].messages[0].severity, 1);
2036 assert.strictEqual(results[0].messages[1].ruleId, "semi");
2037 assert.strictEqual(results[0].messages[1].severity, 1);
2038 });
2039
2040 // Command line configuration - --config with second level .eslintrc
2041 it("should return one message when executing with config file that overrides local and parent .eslintrc", async () => {
2042 eslint = new ESLint({
2043 cwd: path.join(fixtureDir, ".."),
2044 overrideConfigFile: getFixturePath("config-hierarchy/broken/override-conf.yaml")
2045 });
2046 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/broken/subbroken/console-wrong-quotes.js`)]);
2047
2048 assert.strictEqual(results.length, 1);
2049 assert.strictEqual(results[0].messages.length, 1);
2050 assert.strictEqual(results[0].messages[0].ruleId, "no-console");
2051 assert.strictEqual(results[0].messages[0].severity, 1);
2052 });
2053
2054 // Command line configuration - --config with first level .eslintrc
2055 it("should return no messages when executing with config file that overrides local .eslintrc", async () => {
2056 eslint = new ESLint({
2057 cwd: path.join(fixtureDir, ".."),
2058 overrideConfigFile: `${fixtureDir}/config-hierarchy/broken/override-conf.yaml`
2059 });
2060 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/broken/console-wrong-quotes.js`)]);
2061
2062 assert.strictEqual(results.length, 1);
2063 assert.strictEqual(results[0].messages.length, 0);
2064 });
2065
2066 // Command line configuration - --rule with --config and first level .eslintrc
2067 it("should return one message when executing with command line rule and config file that overrides local .eslintrc", async () => {
2068 eslint = new ESLint({
2069 cwd: path.join(fixtureDir, ".."),
2070 overrideConfigFile: getFixturePath("config-hierarchy/broken/override-conf.yaml"),
2071 overrideConfig: {
2072 rules: {
2073 quotes: [1, "double"]
2074 }
2075 }
2076 });
2077 const results = await eslint.lintFiles([fs.realpathSync(`${fixtureDir}/config-hierarchy/broken/console-wrong-quotes.js`)]);
2078
2079 assert.strictEqual(results.length, 1);
2080 assert.strictEqual(results[0].messages.length, 1);
2081 assert.strictEqual(results[0].messages[0].ruleId, "quotes");
2082 assert.strictEqual(results[0].messages[0].severity, 1);
2083 });
2084
2085 // Command line configuration - --rule with --config and first level .eslintrc
2086 it("should return one message when executing with command line rule and config file that overrides local .eslintrc", async () => {
2087 eslint = new ESLint({
2088 cwd: path.join(fixtureDir, ".."),
2089 overrideConfigFile: getFixturePath("/config-hierarchy/broken/override-conf.yaml"),
2090 overrideConfig: {
2091 rules: {
2092 quotes: [1, "double"]
2093 }
2094 }
2095 });
2096 const results = await eslint.lintFiles([getFixturePath("config-hierarchy/broken/console-wrong-quotes.js")]);
2097
2098 assert.strictEqual(results.length, 1);
2099 assert.strictEqual(results[0].messages.length, 1);
2100 assert.strictEqual(results[0].messages[0].ruleId, "quotes");
2101 assert.strictEqual(results[0].messages[0].severity, 1);
2102 });
2103 });
2104
2105 describe("plugins", () => {
2106 it("should return two messages when executing with config file that specifies a plugin", async () => {
2107 eslint = eslintWithPlugins({
2108 cwd: path.join(fixtureDir, ".."),
2109 overrideConfigFile: getFixturePath("configurations", "plugins-with-prefix.json"),
2110 useEslintrc: false
2111 });
2112 const results = await eslint.lintFiles([fs.realpathSync(getFixturePath("rules", "test/test-custom-rule.js"))]);
2113
2114 assert.strictEqual(results.length, 1);
2115 assert.strictEqual(results[0].messages.length, 2);
2116 assert.strictEqual(results[0].messages[0].ruleId, "example/example-rule");
2117 });
2118
2119 it("should return two messages when executing with config file that specifies a plugin with namespace", async () => {
2120 eslint = eslintWithPlugins({
2121 cwd: path.join(fixtureDir, ".."),
2122 overrideConfigFile: getFixturePath("configurations", "plugins-with-prefix-and-namespace.json"),
2123 useEslintrc: false
2124 });
2125 const results = await eslint.lintFiles([fs.realpathSync(getFixturePath("rules", "test", "test-custom-rule.js"))]);
2126
2127 assert.strictEqual(results.length, 1);
2128 assert.strictEqual(results[0].messages.length, 2);
2129 assert.strictEqual(results[0].messages[0].ruleId, "@eslint/example/example-rule");
2130 });
2131
2132 it("should return two messages when executing with config file that specifies a plugin without prefix", async () => {
2133 eslint = eslintWithPlugins({
2134 cwd: path.join(fixtureDir, ".."),
2135 overrideConfigFile: getFixturePath("configurations", "plugins-without-prefix.json"),
2136 useEslintrc: false
2137 });
2138 const results = await eslint.lintFiles([fs.realpathSync(getFixturePath("rules", "test", "test-custom-rule.js"))]);
2139
2140 assert.strictEqual(results.length, 1);
2141 assert.strictEqual(results[0].messages.length, 2);
2142 assert.strictEqual(results[0].messages[0].ruleId, "example/example-rule");
2143 });
2144
2145 it("should return two messages when executing with config file that specifies a plugin without prefix and with namespace", async () => {
2146 eslint = eslintWithPlugins({
2147 cwd: path.join(fixtureDir, ".."),
2148 overrideConfigFile: getFixturePath("configurations", "plugins-without-prefix-with-namespace.json"),
2149 useEslintrc: false
2150 });
2151 const results = await eslint.lintFiles([fs.realpathSync(getFixturePath("rules", "test", "test-custom-rule.js"))]);
2152
2153 assert.strictEqual(results.length, 1);
2154 assert.strictEqual(results[0].messages.length, 2);
2155 assert.strictEqual(results[0].messages[0].ruleId, "@eslint/example/example-rule");
2156 });
2157
2158 it("should return two messages when executing with cli option that specifies a plugin", async () => {
2159 eslint = eslintWithPlugins({
2160 cwd: path.join(fixtureDir, ".."),
2161 useEslintrc: false,
2162 overrideConfig: {
2163 plugins: ["example"],
2164 rules: { "example/example-rule": 1 }
2165 }
2166 });
2167 const results = await eslint.lintFiles([fs.realpathSync(getFixturePath("rules", "test", "test-custom-rule.js"))]);
2168
2169 assert.strictEqual(results.length, 1);
2170 assert.strictEqual(results[0].messages.length, 2);
2171 assert.strictEqual(results[0].messages[0].ruleId, "example/example-rule");
2172 });
2173
2174 it("should return two messages when executing with cli option that specifies preloaded plugin", async () => {
2175 eslint = new ESLint({
2176 cwd: path.join(fixtureDir, ".."),
2177 useEslintrc: false,
2178 overrideConfig: {
2179 plugins: ["test"],
2180 rules: { "test/example-rule": 1 }
2181 },
2182 plugins: {
2183 "eslint-plugin-test": { rules: { "example-rule": require("../../fixtures/rules/custom-rule") } }
2184 }
2185 });
2186 const results = await eslint.lintFiles([fs.realpathSync(getFixturePath("rules", "test", "test-custom-rule.js"))]);
2187
2188 assert.strictEqual(results.length, 1);
2189 assert.strictEqual(results[0].messages.length, 2);
2190 assert.strictEqual(results[0].messages[0].ruleId, "test/example-rule");
2191 });
2192
609c276f
TL
2193 it("should return two messages when executing with `baseConfig` that extends preloaded plugin config", async () => {
2194 eslint = new ESLint({
2195 cwd: path.join(fixtureDir, ".."),
2196 useEslintrc: false,
2197 baseConfig: {
2198 extends: ["plugin:test/preset"]
2199 },
2200 plugins: {
2201 test: {
2202 rules: {
2203 "example-rule": require("../../fixtures/rules/custom-rule")
2204 },
2205 configs: {
2206 preset: {
2207 rules: {
2208 "test/example-rule": 1
2209 },
2210 plugins: ["test"]
2211 }
2212 }
2213 }
2214 }
2215 });
2216 const results = await eslint.lintFiles([fs.realpathSync(getFixturePath("rules", "test", "test-custom-rule.js"))]);
2217
2218 assert.strictEqual(results.length, 1);
2219 assert.strictEqual(results[0].messages.length, 2);
2220 assert.strictEqual(results[0].messages[0].ruleId, "test/example-rule");
2221 });
2222
56c4a2cb
DC
2223 it("should load plugins from the `loadPluginsRelativeTo` directory, if specified", async () => {
2224 eslint = new ESLint({
2225 resolvePluginsRelativeTo: getFixturePath("plugins"),
2226 baseConfig: {
2227 plugins: ["with-rules"],
2228 rules: { "with-rules/rule1": "error" }
2229 },
2230 useEslintrc: false
2231 });
2232 const results = await eslint.lintText("foo");
2233
2234 assert.strictEqual(results.length, 1);
2235 assert.strictEqual(results[0].messages.length, 1);
2236 assert.strictEqual(results[0].messages[0].ruleId, "with-rules/rule1");
2237 assert.strictEqual(results[0].messages[0].message, "Rule report from plugin");
2238 });
2239 });
2240
2241 describe("cache", () => {
2242
2243 /**
2244 * helper method to delete a file without caring about exceptions
2245 * @param {string} filePath The file path
2246 * @returns {void}
2247 */
2248 function doDelete(filePath) {
2249 try {
2250 fs.unlinkSync(filePath);
d3726936 2251 } catch {
56c4a2cb
DC
2252
2253 /*
2254 * we don't care if the file didn't exist, since our
2255 * intention was to remove the file
2256 */
2257 }
2258 }
2259
2260 /**
2261 * helper method to delete the cache files created during testing
2262 * @returns {void}
2263 */
2264 function deleteCache() {
2265 doDelete(path.resolve(".eslintcache"));
2266 doDelete(path.resolve(".cache/custom-cache"));
2267 }
2268
2269 beforeEach(() => {
2270 deleteCache();
2271 });
2272
2273 afterEach(() => {
2274 sinon.restore();
2275 deleteCache();
2276 });
2277
2278 describe("when the cacheFile is a directory or looks like a directory", () => {
2279
2280 /**
2281 * helper method to delete the cache files created during testing
2282 * @returns {void}
2283 */
2284 function deleteCacheDir() {
2285 try {
2286 fs.unlinkSync("./tmp/.cacheFileDir/.cache_hashOfCurrentWorkingDirectory");
d3726936 2287 } catch {
56c4a2cb
DC
2288
2289 /*
2290 * we don't care if the file didn't exist, since our
2291 * intention was to remove the file
2292 */
2293 }
2294 }
2295 beforeEach(() => {
2296 deleteCacheDir();
2297 });
2298
2299 afterEach(() => {
2300 deleteCacheDir();
2301 });
2302
2303 it("should create the cache file inside the provided directory", async () => {
2304 assert(!shell.test("-d", path.resolve("./tmp/.cacheFileDir/.cache_hashOfCurrentWorkingDirectory")), "the cache for eslint does not exist");
2305
2306 eslint = new ESLint({
2307 useEslintrc: false,
2308
2309 // specifying cache true the cache will be created
2310 cache: true,
2311 cacheLocation: "./tmp/.cacheFileDir/",
2312 overrideConfig: {
2313 rules: {
2314 "no-console": 0,
2315 "no-unused-vars": 2
2316 }
2317 },
2318 extensions: ["js"],
2319 ignore: false
2320 });
2321 const file = getFixturePath("cache/src", "test-file.js");
2322
2323 await eslint.lintFiles([file]);
2324
2325 assert(shell.test("-f", path.resolve(`./tmp/.cacheFileDir/.cache_${hash(process.cwd())}`)), "the cache for eslint was created");
2326
2327 sinon.restore();
2328 });
2329 });
2330
2331 it("should create the cache file inside the provided directory using the cacheLocation option", async () => {
2332 assert(!shell.test("-d", path.resolve("./tmp/.cacheFileDir/.cache_hashOfCurrentWorkingDirectory")), "the cache for eslint does not exist");
2333
2334 eslint = new ESLint({
2335 useEslintrc: false,
2336
2337 // specifying cache true the cache will be created
2338 cache: true,
2339 cacheLocation: "./tmp/.cacheFileDir/",
2340 overrideConfig: {
2341 rules: {
2342 "no-console": 0,
2343 "no-unused-vars": 2
2344 }
2345 },
2346 extensions: ["js"],
2347 ignore: false
2348 });
2349 const file = getFixturePath("cache/src", "test-file.js");
2350
2351 await eslint.lintFiles([file]);
2352
2353 assert(shell.test("-f", path.resolve(`./tmp/.cacheFileDir/.cache_${hash(process.cwd())}`)), "the cache for eslint was created");
2354
2355 sinon.restore();
2356 });
2357
2358 it("should create the cache file inside cwd when no cacheLocation provided", async () => {
2359 const cwd = path.resolve(getFixturePath("cli-engine"));
2360
2361 eslint = new ESLint({
2362 useEslintrc: false,
2363 cache: true,
2364 cwd,
2365 overrideConfig: {
2366 rules: {
2367 "no-console": 0
2368 }
2369 },
2370 extensions: ["js"],
2371 ignore: false
2372 });
2373 const file = getFixturePath("cli-engine", "console.js");
2374
2375 await eslint.lintFiles([file]);
2376
2377 assert(shell.test("-f", path.resolve(cwd, ".eslintcache")), "the cache for eslint was created at provided cwd");
2378 });
2379
2380 it("should invalidate the cache if the configuration changed between executions", async () => {
2381 assert(!shell.test("-f", path.resolve(".eslintcache")), "the cache for eslint does not exist");
2382
2383 eslint = new ESLint({
2384 useEslintrc: false,
2385
2386 // specifying cache true the cache will be created
2387 cache: true,
2388 overrideConfig: {
2389 rules: {
2390 "no-console": 0,
2391 "no-unused-vars": 2
2392 }
2393 },
2394 extensions: ["js"],
2395 ignore: false
2396 });
2397
2398 let spy = sinon.spy(fs, "readFileSync");
2399
2400 let file = getFixturePath("cache/src", "test-file.js");
2401
2402 file = fs.realpathSync(file);
2403 const results = await eslint.lintFiles([file]);
2404
2405 for (const { errorCount, warningCount } of results) {
2406 assert.strictEqual(errorCount + warningCount, 0, "the file passed without errors or warnings");
2407 }
2408 assert.strictEqual(spy.getCall(0).args[0], file, "the module read the file because is considered changed");
2409 assert(shell.test("-f", path.resolve(".eslintcache")), "the cache for eslint was created");
2410
2411 // destroy the spy
2412 sinon.restore();
2413
2414 eslint = new ESLint({
2415 useEslintrc: false,
2416
2417 // specifying cache true the cache will be created
2418 cache: true,
2419 overrideConfig: {
2420 rules: {
2421 "no-console": 2,
2422 "no-unused-vars": 2
2423 }
2424 },
2425 extensions: ["js"],
2426 ignore: false
2427 });
2428
2429 // create a new spy
2430 spy = sinon.spy(fs, "readFileSync");
2431
2432 const [cachedResult] = await eslint.lintFiles([file]);
2433
2434 assert.strictEqual(spy.getCall(0).args[0], file, "the module read the file because is considered changed because the config changed");
2435 assert.strictEqual(cachedResult.errorCount, 1, "since configuration changed the cache was not used an one error was reported");
2436 assert(shell.test("-f", path.resolve(".eslintcache")), "the cache for eslint was created");
2437 });
2438
2439 it("should remember the files from a previous run and do not operate on them if not changed", async () => {
2440 assert(!shell.test("-f", path.resolve(".eslintcache")), "the cache for eslint does not exist");
2441
2442 eslint = new ESLint({
2443 useEslintrc: false,
2444
2445 // specifying cache true the cache will be created
2446 cache: true,
2447 overrideConfig: {
2448 rules: {
2449 "no-console": 0,
2450 "no-unused-vars": 2
2451 }
2452 },
2453 extensions: ["js"],
2454 ignore: false
2455 });
2456
2457 let spy = sinon.spy(fs, "readFileSync");
2458
2459 let file = getFixturePath("cache/src", "test-file.js");
2460
2461 file = fs.realpathSync(file);
2462
2463 const result = await eslint.lintFiles([file]);
2464
2465 assert.strictEqual(spy.getCall(0).args[0], file, "the module read the file because is considered changed");
2466 assert(shell.test("-f", path.resolve(".eslintcache")), "the cache for eslint was created");
2467
2468 // destroy the spy
2469 sinon.restore();
2470
2471 eslint = new ESLint({
2472 useEslintrc: false,
2473
2474 // specifying cache true the cache will be created
2475 cache: true,
2476 overrideConfig: {
2477 rules: {
2478 "no-console": 0,
2479 "no-unused-vars": 2
2480 }
2481 },
2482 extensions: ["js"],
2483 ignore: false
2484 });
2485
2486 // create a new spy
2487 spy = sinon.spy(fs, "readFileSync");
2488
2489 const cachedResult = await eslint.lintFiles([file]);
2490
2491 assert.deepStrictEqual(result, cachedResult, "the result is the same regardless of using cache or not");
2492
2493 // assert the file was not processed because the cache was used
2494 assert(!spy.calledWith(file), "the file was not loaded because it used the cache");
2495 });
2496
2497 it("should remember the files from a previous run and do not operate on then if not changed", async () => {
2498 const cacheLocation = getFixturePath(".eslintcache");
2499 const eslintOptions = {
2500 useEslintrc: false,
2501
2502 // specifying cache true the cache will be created
2503 cache: true,
2504 cacheLocation,
2505 overrideConfig: {
2506 rules: {
2507 "no-console": 0,
2508 "no-unused-vars": 2
2509 }
2510 },
2511 extensions: ["js"],
2512 cwd: path.join(fixtureDir, "..")
2513 };
2514
2515 assert(!shell.test("-f", cacheLocation), "the cache for eslint does not exist");
2516
2517 eslint = new ESLint(eslintOptions);
2518
2519 let file = getFixturePath("cache/src", "test-file.js");
2520
2521 file = fs.realpathSync(file);
2522
2523 await eslint.lintFiles([file]);
2524
2525 assert(shell.test("-f", cacheLocation), "the cache for eslint was created");
2526
2527 eslintOptions.cache = false;
2528 eslint = new ESLint(eslintOptions);
2529
2530 await eslint.lintFiles([file]);
2531
2532 assert(!shell.test("-f", cacheLocation), "the cache for eslint was deleted since last run did not used the cache");
2533 });
2534
2535 it("should store in the cache a file that failed the test", async () => {
2536 const cacheLocation = getFixturePath(".eslintcache");
2537
2538 assert(!shell.test("-f", cacheLocation), "the cache for eslint does not exist");
2539
2540 eslint = new ESLint({
2541 cwd: path.join(fixtureDir, ".."),
2542 useEslintrc: false,
2543
2544 // specifying cache true the cache will be created
2545 cache: true,
2546 cacheLocation,
2547 overrideConfig: {
2548 rules: {
2549 "no-console": 0,
2550 "no-unused-vars": 2
2551 }
2552 },
2553 extensions: ["js"]
2554 });
2555 const badFile = fs.realpathSync(getFixturePath("cache/src", "fail-file.js"));
2556 const goodFile = fs.realpathSync(getFixturePath("cache/src", "test-file.js"));
2557 const result = await eslint.lintFiles([badFile, goodFile]);
2558
2559 assert(shell.test("-f", cacheLocation), "the cache for eslint was created");
2560 const fileCache = fCache.createFromFile(cacheLocation);
2561 const { cache } = fileCache;
2562
2563 assert.strictEqual(typeof cache.getKey(goodFile), "object", "the entry for the good file is in the cache");
2564 assert.strictEqual(typeof cache.getKey(badFile), "object", "the entry for the bad file is in the cache");
2565 const cachedResult = await eslint.lintFiles([badFile, goodFile]);
2566
2567 assert.deepStrictEqual(result, cachedResult, "result is the same with or without cache");
2568 });
2569
2570 it("should not contain in the cache a file that was deleted", async () => {
2571 const cacheLocation = getFixturePath(".eslintcache");
2572
2573 doDelete(cacheLocation);
2574
2575 eslint = new ESLint({
2576 cwd: path.join(fixtureDir, ".."),
2577 useEslintrc: false,
2578
2579 // specifying cache true the cache will be created
2580 cache: true,
2581 cacheLocation,
2582 overrideConfig: {
2583 rules: {
2584 "no-console": 0,
2585 "no-unused-vars": 2
2586 }
2587 },
2588 extensions: ["js"]
2589 });
2590 const badFile = fs.realpathSync(getFixturePath("cache/src", "fail-file.js"));
2591 const goodFile = fs.realpathSync(getFixturePath("cache/src", "test-file.js"));
2592 const toBeDeletedFile = fs.realpathSync(getFixturePath("cache/src", "file-to-delete.js"));
2593
2594 await eslint.lintFiles([badFile, goodFile, toBeDeletedFile]);
2595 const fileCache = fCache.createFromFile(cacheLocation);
2596 let { cache } = fileCache;
2597
2598 assert.strictEqual(typeof cache.getKey(toBeDeletedFile), "object", "the entry for the file to be deleted is in the cache");
2599
2600 // delete the file from the file system
2601 fs.unlinkSync(toBeDeletedFile);
2602
2603 /*
2604 * file-entry-cache@2.0.0 will remove from the cache deleted files
2605 * even when they were not part of the array of files to be analyzed
2606 */
2607 await eslint.lintFiles([badFile, goodFile]);
2608
2609 cache = JSON.parse(fs.readFileSync(cacheLocation));
2610
2611 assert.strictEqual(typeof cache[toBeDeletedFile], "undefined", "the entry for the file to be deleted is not in the cache");
2612 });
2613
2614 it("should contain files that were not visited in the cache provided they still exist", async () => {
2615 const cacheLocation = getFixturePath(".eslintcache");
2616
2617 doDelete(cacheLocation);
2618
2619 eslint = new ESLint({
2620 cwd: path.join(fixtureDir, ".."),
2621 useEslintrc: false,
2622
2623 // specifying cache true the cache will be created
2624 cache: true,
2625 cacheLocation,
2626 overrideConfig: {
2627 rules: {
2628 "no-console": 0,
2629 "no-unused-vars": 2
2630 }
2631 },
2632 extensions: ["js"]
2633 });
2634 const badFile = fs.realpathSync(getFixturePath("cache/src", "fail-file.js"));
2635 const goodFile = fs.realpathSync(getFixturePath("cache/src", "test-file.js"));
2636 const testFile2 = fs.realpathSync(getFixturePath("cache/src", "test-file2.js"));
2637
2638 await eslint.lintFiles([badFile, goodFile, testFile2]);
2639
2640 let fileCache = fCache.createFromFile(cacheLocation);
2641 let { cache } = fileCache;
2642
2643 assert.strictEqual(typeof cache.getKey(testFile2), "object", "the entry for the test-file2 is in the cache");
2644
2645 /*
2646 * we pass a different set of files minus test-file2
2647 * previous version of file-entry-cache would remove the non visited
2648 * entries. 2.0.0 version will keep them unless they don't exist
2649 */
2650 await eslint.lintFiles([badFile, goodFile]);
2651
2652 fileCache = fCache.createFromFile(cacheLocation);
2653 cache = fileCache.cache;
2654
2655 assert.strictEqual(typeof cache.getKey(testFile2), "object", "the entry for the test-file2 is in the cache");
2656 });
2657
2658 it("should not delete cache when executing on text", async () => {
2659 const cacheLocation = getFixturePath(".eslintcache");
2660
2661 eslint = new ESLint({
2662 cwd: path.join(fixtureDir, ".."),
2663 useEslintrc: false,
2664 cacheLocation,
2665 overrideConfig: {
2666 rules: {
2667 "no-console": 0,
2668 "no-unused-vars": 2
2669 }
2670 },
2671 extensions: ["js"]
2672 });
2673
2674 assert(shell.test("-f", cacheLocation), "the cache for eslint exists");
2675
2676 await eslint.lintText("var foo = 'bar';");
2677
2678 assert(shell.test("-f", cacheLocation), "the cache for eslint still exists");
2679 });
2680
2681 it("should not delete cache when executing on text with a provided filename", async () => {
2682 const cacheLocation = getFixturePath(".eslintcache");
2683
2684 eslint = new ESLint({
2685 cwd: path.join(fixtureDir, ".."),
2686 useEslintrc: false,
2687 cacheLocation,
2688 overrideConfig: {
2689 rules: {
2690 "no-console": 0,
2691 "no-unused-vars": 2
2692 }
2693 },
2694 extensions: ["js"]
2695 });
2696
2697 assert(shell.test("-f", cacheLocation), "the cache for eslint exists");
2698
2699 await eslint.lintText("var bar = foo;", { filePath: "fixtures/passing.js" });
2700
2701 assert(shell.test("-f", cacheLocation), "the cache for eslint still exists");
2702 });
2703
2704 it("should not delete cache when executing on files with --cache flag", async () => {
2705 const cacheLocation = getFixturePath(".eslintcache");
2706
2707 eslint = new ESLint({
2708 cwd: path.join(fixtureDir, ".."),
2709 useEslintrc: false,
2710 cache: true,
2711 cacheLocation,
2712 overrideConfig: {
2713 rules: {
2714 "no-console": 0,
2715 "no-unused-vars": 2
2716 }
2717 },
2718 extensions: ["js"]
2719 });
2720 const file = getFixturePath("cli-engine", "console.js");
2721
2722 assert(shell.test("-f", cacheLocation), "the cache for eslint exists");
2723
2724 await eslint.lintFiles([file]);
2725
2726 assert(shell.test("-f", cacheLocation), "the cache for eslint still exists");
2727 });
2728
2729 it("should delete cache when executing on files without --cache flag", async () => {
2730 const cacheLocation = getFixturePath(".eslintcache");
2731
2732 eslint = new ESLint({
2733 cwd: path.join(fixtureDir, ".."),
2734 useEslintrc: false,
2735 cacheLocation,
2736 overrideConfig: {
2737 rules: {
2738 "no-console": 0,
2739 "no-unused-vars": 2
2740 }
2741 },
2742 extensions: ["js"]
2743 });
2744 const file = getFixturePath("cli-engine", "console.js");
2745
2746 assert(shell.test("-f", cacheLocation), "the cache for eslint exists");
2747
2748 await eslint.lintFiles([file]);
2749
2750 assert(!shell.test("-f", cacheLocation), "the cache for eslint has been deleted");
2751 });
2752
2753 describe("cacheFile", () => {
2754 it("should use the specified cache file", async () => {
2755 const customCacheFile = path.resolve(".cache/custom-cache");
2756
2757 assert(!shell.test("-f", customCacheFile), "the cache for eslint does not exist");
2758
2759 eslint = new ESLint({
2760 useEslintrc: false,
2761
2762 // specify a custom cache file
2763 cacheLocation: customCacheFile,
2764
2765 // specifying cache true the cache will be created
2766 cache: true,
2767 overrideConfig: {
2768 rules: {
2769 "no-console": 0,
2770 "no-unused-vars": 2
2771 }
2772 },
2773 extensions: ["js"],
2774 cwd: path.join(fixtureDir, "..")
2775 });
2776 const badFile = fs.realpathSync(getFixturePath("cache/src", "fail-file.js"));
2777 const goodFile = fs.realpathSync(getFixturePath("cache/src", "test-file.js"));
2778 const result = await eslint.lintFiles([badFile, goodFile]);
2779
2780 assert(shell.test("-f", customCacheFile), "the cache for eslint was created");
2781 const fileCache = fCache.createFromFile(customCacheFile);
2782 const { cache } = fileCache;
2783
2784 assert(typeof cache.getKey(goodFile) === "object", "the entry for the good file is in the cache");
2785
2786 assert(typeof cache.getKey(badFile) === "object", "the entry for the bad file is in the cache");
2787 const cachedResult = await eslint.lintFiles([badFile, goodFile]);
2788
2789 assert.deepStrictEqual(result, cachedResult, "result is the same with or without cache");
2790 });
2791 });
5422a9cc
TL
2792
2793 describe("cacheStrategy", () => {
2794 it("should detect changes using a file's modification time when set to 'metadata'", async () => {
2795 const cacheLocation = getFixturePath(".eslintcache");
2796
2797 doDelete(cacheLocation);
2798
2799 eslint = new ESLint({
2800 cwd: path.join(fixtureDir, ".."),
2801 useEslintrc: false,
2802
2803 // specifying cache true the cache will be created
2804 cache: true,
2805 cacheLocation,
2806 cacheStrategy: "metadata",
2807 overrideConfig: {
2808 rules: {
2809 "no-console": 0,
2810 "no-unused-vars": 2
2811 }
2812 },
2813 extensions: ["js"]
2814 });
2815 const badFile = fs.realpathSync(getFixturePath("cache/src", "fail-file.js"));
2816 const goodFile = fs.realpathSync(getFixturePath("cache/src", "test-file.js"));
2817
2818 await eslint.lintFiles([badFile, goodFile]);
2819 let fileCache = fCache.createFromFile(cacheLocation);
2820 const entries = fileCache.normalizeEntries([badFile, goodFile]);
2821
2822 entries.forEach(entry => {
2823 assert(entry.changed === false, `the entry for ${entry.key} is initially unchanged`);
2824 });
2825
2826 // this should result in a changed entry
2827 shell.touch(goodFile);
2828 fileCache = fCache.createFromFile(cacheLocation);
2829 assert(fileCache.getFileDescriptor(badFile).changed === false, `the entry for ${badFile} is unchanged`);
2830 assert(fileCache.getFileDescriptor(goodFile).changed === true, `the entry for ${goodFile} is changed`);
2831 });
2832
2833 it("should not detect changes using a file's modification time when set to 'content'", async () => {
2834 const cacheLocation = getFixturePath(".eslintcache");
2835
2836 doDelete(cacheLocation);
2837
2838 eslint = new ESLint({
2839 cwd: path.join(fixtureDir, ".."),
2840 useEslintrc: false,
2841
2842 // specifying cache true the cache will be created
2843 cache: true,
2844 cacheLocation,
2845 cacheStrategy: "content",
2846 overrideConfig: {
2847 rules: {
2848 "no-console": 0,
2849 "no-unused-vars": 2
2850 }
2851 },
2852 extensions: ["js"]
2853 });
2854 const badFile = fs.realpathSync(getFixturePath("cache/src", "fail-file.js"));
2855 const goodFile = fs.realpathSync(getFixturePath("cache/src", "test-file.js"));
2856
2857 await eslint.lintFiles([badFile, goodFile]);
2858 let fileCache = fCache.createFromFile(cacheLocation, true);
2859 let entries = fileCache.normalizeEntries([badFile, goodFile]);
2860
2861 entries.forEach(entry => {
2862 assert(entry.changed === false, `the entry for ${entry.key} is initially unchanged`);
2863 });
2864
2865 // this should NOT result in a changed entry
2866 shell.touch(goodFile);
2867 fileCache = fCache.createFromFile(cacheLocation, true);
2868 entries = fileCache.normalizeEntries([badFile, goodFile]);
2869 entries.forEach(entry => {
2870 assert(entry.changed === false, `the entry for ${entry.key} remains unchanged`);
2871 });
2872 });
2873
2874 it("should detect changes using a file's contents when set to 'content'", async () => {
2875 const cacheLocation = getFixturePath(".eslintcache");
2876
2877 doDelete(cacheLocation);
2878
2879 eslint = new ESLint({
2880 cwd: path.join(fixtureDir, ".."),
2881 useEslintrc: false,
2882
2883 // specifying cache true the cache will be created
2884 cache: true,
2885 cacheLocation,
2886 cacheStrategy: "content",
2887 overrideConfig: {
2888 rules: {
2889 "no-console": 0,
2890 "no-unused-vars": 2
2891 }
2892 },
2893 extensions: ["js"]
2894 });
2895 const badFile = fs.realpathSync(getFixturePath("cache/src", "fail-file.js"));
2896 const goodFile = fs.realpathSync(getFixturePath("cache/src", "test-file.js"));
2897 const goodFileCopy = path.resolve(`${path.dirname(goodFile)}`, "test-file-copy.js");
2898
2899 shell.cp(goodFile, goodFileCopy);
2900
2901 await eslint.lintFiles([badFile, goodFileCopy]);
2902 let fileCache = fCache.createFromFile(cacheLocation, true);
2903 const entries = fileCache.normalizeEntries([badFile, goodFileCopy]);
2904
2905 entries.forEach(entry => {
2906 assert(entry.changed === false, `the entry for ${entry.key} is initially unchanged`);
2907 });
2908
2909 // this should result in a changed entry
2910 shell.sed("-i", "abc", "xzy", goodFileCopy);
2911 fileCache = fCache.createFromFile(cacheLocation, true);
2912 assert(fileCache.getFileDescriptor(badFile).changed === false, `the entry for ${badFile} is unchanged`);
2913 assert(fileCache.getFileDescriptor(goodFileCopy).changed === true, `the entry for ${goodFileCopy} is changed`);
2914 });
2915 });
56c4a2cb
DC
2916 });
2917
2918 describe("processors", () => {
2919 it("should return two messages when executing with config file that specifies a processor", async () => {
2920 eslint = eslintWithPlugins({
2921 overrideConfigFile: getFixturePath("configurations", "processors.json"),
2922 useEslintrc: false,
2923 extensions: ["js", "txt"],
2924 cwd: path.join(fixtureDir, "..")
2925 });
2926 const results = await eslint.lintFiles([fs.realpathSync(getFixturePath("processors", "test", "test-processor.txt"))]);
2927
2928 assert.strictEqual(results.length, 1);
2929 assert.strictEqual(results[0].messages.length, 2);
2930 });
2931
2932 it("should return two messages when executing with config file that specifies preloaded processor", async () => {
2933 eslint = new ESLint({
2934 useEslintrc: false,
2935 overrideConfig: {
2936 plugins: ["test-processor"],
2937 rules: {
2938 "no-console": 2,
2939 "no-unused-vars": 2
2940 }
2941 },
2942 extensions: ["js", "txt"],
2943 cwd: path.join(fixtureDir, ".."),
2944 plugins: {
2945 "test-processor": {
2946 processors: {
2947 ".txt": {
2948 preprocess(text) {
2949 return [text];
2950 },
2951 postprocess(messages) {
2952 return messages[0];
2953 }
2954 }
2955 }
2956 }
2957 }
2958 });
2959 const results = await eslint.lintFiles([fs.realpathSync(getFixturePath("processors", "test", "test-processor.txt"))]);
2960
2961 assert.strictEqual(results.length, 1);
2962 assert.strictEqual(results[0].messages.length, 2);
2963 });
2964
2965 it("should run processors when calling lintFiles with config file that specifies a processor", async () => {
2966 eslint = eslintWithPlugins({
2967 overrideConfigFile: getFixturePath("configurations", "processors.json"),
2968 useEslintrc: false,
2969 extensions: ["js", "txt"],
2970 cwd: path.join(fixtureDir, "..")
2971 });
2972 const results = await eslint.lintFiles([getFixturePath("processors", "test", "test-processor.txt")]);
2973
2974 assert.strictEqual(results[0].messages[0].message, "'b' is defined but never used.");
2975 assert.strictEqual(results[0].messages[0].ruleId, "post-processed");
2976 });
2977
2978 it("should run processors when calling lintFiles with config file that specifies preloaded processor", async () => {
2979 eslint = new ESLint({
2980 useEslintrc: false,
2981 overrideConfig: {
2982 plugins: ["test-processor"],
2983 rules: {
2984 "no-console": 2,
2985 "no-unused-vars": 2
2986 }
2987 },
2988 extensions: ["js", "txt"],
2989 cwd: path.join(fixtureDir, ".."),
2990 plugins: {
2991 "test-processor": {
2992 processors: {
2993 ".txt": {
2994 preprocess(text) {
2995 return [text.replace("a()", "b()")];
2996 },
2997 postprocess(messages) {
2998 messages[0][0].ruleId = "post-processed";
2999 return messages[0];
3000 }
3001 }
3002 }
3003 }
3004 }
3005 });
3006 const results = await eslint.lintFiles([getFixturePath("processors", "test", "test-processor.txt")]);
3007
3008 assert.strictEqual(results[0].messages[0].message, "'b' is defined but never used.");
3009 assert.strictEqual(results[0].messages[0].ruleId, "post-processed");
3010 });
3011
3012 it("should run processors when calling lintText with config file that specifies a processor", async () => {
3013 eslint = eslintWithPlugins({
3014 overrideConfigFile: getFixturePath("configurations", "processors.json"),
3015 useEslintrc: false,
3016 extensions: ["js", "txt"],
3017 ignore: false
3018 });
3019 const results = await eslint.lintText("function a() {console.log(\"Test\");}", { filePath: "tests/fixtures/processors/test/test-processor.txt" });
3020
3021 assert.strictEqual(results[0].messages[0].message, "'b' is defined but never used.");
3022 assert.strictEqual(results[0].messages[0].ruleId, "post-processed");
3023 });
3024
3025 it("should run processors when calling lintText with config file that specifies preloaded processor", async () => {
3026 eslint = new ESLint({
3027 useEslintrc: false,
3028 overrideConfig: {
3029 plugins: ["test-processor"],
3030 rules: {
3031 "no-console": 2,
3032 "no-unused-vars": 2
3033 }
3034 },
3035 extensions: ["js", "txt"],
3036 ignore: false,
3037 plugins: {
3038 "test-processor": {
3039 processors: {
3040 ".txt": {
3041 preprocess(text) {
3042 return [text.replace("a()", "b()")];
3043 },
3044 postprocess(messages) {
3045 messages[0][0].ruleId = "post-processed";
3046 return messages[0];
3047 }
3048 }
3049 }
3050 }
3051 }
3052 });
3053 const results = await eslint.lintText("function a() {console.log(\"Test\");}", { filePath: "tests/fixtures/processors/test/test-processor.txt" });
3054
3055 assert.strictEqual(results[0].messages[0].message, "'b' is defined but never used.");
3056 assert.strictEqual(results[0].messages[0].ruleId, "post-processed");
3057 });
3058
5422a9cc
TL
3059 it("should run processors when calling lintText with processor resolves same extension but different content correctly", async () => {
3060 let count = 0;
3061
3062 eslint = new ESLint({
3063 useEslintrc: false,
3064 overrideConfig: {
3065 plugins: ["test-processor"],
3066 overrides: [{
3067 files: ["**/*.txt/*.txt"],
3068 rules: {
3069 "no-console": 2,
3070 "no-unused-vars": 2
3071 }
3072 }]
3073 },
3074 extensions: ["txt"],
3075 ignore: false,
3076 plugins: {
3077 "test-processor": {
3078 processors: {
3079 ".txt": {
3080 preprocess(text) {
3081 count++;
3082 return [
3083 {
3084
3085 // it will be run twice, and text will be as-is at the second time, then it will not run third time
3086 text: text.replace("a()", "b()"),
3087 filename: ".txt"
3088 }
3089 ];
3090 },
3091 postprocess(messages) {
3092 messages[0][0].ruleId = "post-processed";
3093 return messages[0];
3094 }
3095 }
3096 }
3097 }
3098 }
3099 });
3100 const results = await eslint.lintText("function a() {console.log(\"Test\");}", { filePath: "tests/fixtures/processors/test/test-processor.txt" });
3101
3102 assert.strictEqual(count, 2);
3103 assert.strictEqual(results[0].messages[0].message, "'b' is defined but never used.");
3104 assert.strictEqual(results[0].messages[0].ruleId, "post-processed");
3105 });
3106
56c4a2cb
DC
3107 describe("autofixing with processors", () => {
3108 const HTML_PROCESSOR = Object.freeze({
3109 preprocess(text) {
3110 return [text.replace(/^<script>/u, "").replace(/<\/script>$/u, "")];
3111 },
3112 postprocess(problemLists) {
3113 return problemLists[0].map(problem => {
3114 if (problem.fix) {
3115 const updatedFix = Object.assign({}, problem.fix, {
3116 range: problem.fix.range.map(index => index + "<script>".length)
3117 });
3118
3119 return Object.assign({}, problem, { fix: updatedFix });
3120 }
3121 return problem;
3122 });
3123 }
3124 });
3125
3126
3127 it("should run in autofix mode when using a processor that supports autofixing", async () => {
3128 eslint = new ESLint({
3129 useEslintrc: false,
3130 overrideConfig: {
3131 plugins: ["test-processor"],
3132 rules: {
3133 semi: 2
3134 }
3135 },
3136 extensions: ["js", "txt"],
3137 ignore: false,
3138 fix: true,
3139 plugins: {
3140 "test-processor": {
3141 processors: {
3142 ".html": Object.assign({ supportsAutofix: true }, HTML_PROCESSOR)
3143 }
3144 }
3145 }
3146 });
3147 const results = await eslint.lintText("<script>foo</script>", { filePath: "foo.html" });
3148
3149 assert.strictEqual(results[0].messages.length, 0);
3150 assert.strictEqual(results[0].output, "<script>foo;</script>");
3151 });
3152
3153 it("should not run in autofix mode when using a processor that does not support autofixing", async () => {
3154 eslint = new ESLint({
3155 useEslintrc: false,
3156 overrideConfig: {
3157 plugins: ["test-processor"],
3158 rules: {
3159 semi: 2
3160 }
3161 },
3162 extensions: ["js", "txt"],
3163 ignore: false,
3164 fix: true,
3165 plugins: {
3166 "test-processor": { processors: { ".html": HTML_PROCESSOR } }
3167 }
3168 });
3169 const results = await eslint.lintText("<script>foo</script>", { filePath: "foo.html" });
3170
3171 assert.strictEqual(results[0].messages.length, 1);
3172 assert(!Object.prototype.hasOwnProperty.call(results[0], "output"));
3173 });
3174
3175 it("should not run in autofix mode when `fix: true` is not provided, even if the processor supports autofixing", async () => {
3176 eslint = new ESLint({
3177 useEslintrc: false,
3178 overrideConfig: {
3179 plugins: ["test-processor"],
3180 rules: {
3181 semi: 2
3182 }
3183 },
3184 extensions: ["js", "txt"],
3185 ignore: false,
3186 plugins: {
3187 "test-processor": {
3188 processors: {
3189 ".html": Object.assign({ supportsAutofix: true }, HTML_PROCESSOR)
3190 }
3191 }
3192 }
3193 });
3194 const results = await eslint.lintText("<script>foo</script>", { filePath: "foo.html" });
3195
3196 assert.strictEqual(results[0].messages.length, 1);
3197 assert(!Object.prototype.hasOwnProperty.call(results[0], "output"));
3198 });
3199 });
3200 });
3201
3202 describe("Patterns which match no file should throw errors.", () => {
3203 beforeEach(() => {
3204 eslint = new ESLint({
3205 cwd: getFixturePath("cli-engine"),
3206 useEslintrc: false
3207 });
3208 });
3209
3210 it("one file", async () => {
3211 await assert.rejects(async () => {
3212 await eslint.lintFiles(["non-exist.js"]);
3213 }, /No files matching 'non-exist\.js' were found\./u);
3214 });
3215
3216 it("should throw if the directory exists and is empty", async () => {
3217 await assert.rejects(async () => {
3218 await eslint.lintFiles(["empty"]);
3219 }, /No files matching 'empty' were found\./u);
3220 });
3221
3222 it("one glob pattern", async () => {
3223 await assert.rejects(async () => {
3224 await eslint.lintFiles(["non-exist/**/*.js"]);
3225 }, /No files matching 'non-exist\/\*\*\/\*\.js' were found\./u);
3226 });
3227
3228 it("two files", async () => {
3229 await assert.rejects(async () => {
3230 await eslint.lintFiles(["aaa.js", "bbb.js"]);
3231 }, /No files matching 'aaa\.js' were found\./u);
3232 });
3233
3234 it("a mix of an existing file and a non-existing file", async () => {
3235 await assert.rejects(async () => {
3236 await eslint.lintFiles(["console.js", "non-exist.js"]);
3237 }, /No files matching 'non-exist\.js' were found\./u);
3238 });
3239 });
3240
3241 describe("overrides", () => {
3242 beforeEach(() => {
3243 eslint = new ESLint({
3244 cwd: getFixturePath("cli-engine/overrides-with-dot"),
3245 ignore: false
3246 });
3247 });
3248
3249 it("should recognize dotfiles", async () => {
3250 const ret = await eslint.lintFiles([".test-target.js"]);
3251
3252 assert.strictEqual(ret.length, 1);
3253 assert.strictEqual(ret[0].messages.length, 1);
3254 assert.strictEqual(ret[0].messages[0].ruleId, "no-unused-vars");
3255 });
3256 });
3257
3258 describe("a config file setting should have higher priority than a shareable config file's settings always; https://github.com/eslint/eslint/issues/11510", () => {
6f036462
TL
3259
3260 const { prepare, cleanup, getPath } = createCustomTeardown({
3261 cwd: path.join(os.tmpdir(), "eslint/11510"),
3262 files: {
3263 "no-console-error-in-overrides.json": JSON.stringify({
3264 overrides: [{
3265 files: ["*.js"],
3266 rules: { "no-console": "error" }
3267 }]
3268 }),
3269 ".eslintrc.json": JSON.stringify({
3270 extends: "./no-console-error-in-overrides.json",
3271 rules: { "no-console": "off" }
3272 }),
3273 "a.js": "console.log();"
3274 }
3275 });
3276
56c4a2cb 3277 beforeEach(() => {
6f036462
TL
3278 eslint = new ESLint({ cwd: getPath() });
3279 return prepare();
56c4a2cb
DC
3280 });
3281
6f036462
TL
3282 afterEach(cleanup);
3283
56c4a2cb
DC
3284 it("should not report 'no-console' error.", async () => {
3285 const results = await eslint.lintFiles("a.js");
3286
3287 assert.strictEqual(results.length, 1);
3288 assert.deepStrictEqual(results[0].messages, []);
3289 });
3290 });
3291
3292 describe("configs of plugin rules should be validated even if 'plugins' key doesn't exist; https://github.com/eslint/eslint/issues/11559", () => {
6f036462
TL
3293
3294 const { prepare, cleanup, getPath } = createCustomTeardown({
3295 cwd: path.join(os.tmpdir(), "eslint/11559"),
3296 files: {
3297 "node_modules/eslint-plugin-test/index.js": `
56c4a2cb
DC
3298 exports.configs = {
3299 recommended: { plugins: ["test"] }
3300 };
3301 exports.rules = {
3302 foo: {
3303 meta: { schema: [{ type: "number" }] },
3304 create() { return {}; }
3305 }
3306 };
3307 `,
6f036462 3308 ".eslintrc.json": JSON.stringify({
56c4a2cb 3309
6f036462
TL
3310 // Import via the recommended config.
3311 extends: "plugin:test/recommended",
56c4a2cb 3312
6f036462
TL
3313 // Has invalid option.
3314 rules: { "test/foo": ["error", "invalid-option"] }
3315 }),
3316 "a.js": "console.log();"
3317 }
56c4a2cb
DC
3318 });
3319
6f036462
TL
3320 beforeEach(() => {
3321 eslint = new ESLint({ cwd: getPath() });
3322 return prepare();
3323 });
3324
3325 afterEach(cleanup);
3326
3327
56c4a2cb
DC
3328 it("should throw fatal error.", async () => {
3329 await assert.rejects(async () => {
3330 await eslint.lintFiles("a.js");
3331 }, /invalid-option/u);
3332 });
3333 });
3334
3335 describe("'--fix-type' should not crash even if plugin rules exist; https://github.com/eslint/eslint/issues/11586", () => {
6f036462
TL
3336 const { prepare, cleanup, getPath } = createCustomTeardown({
3337 cwd: path.join(os.tmpdir(), "cli-engine/11586"),
3338 files: {
3339 "node_modules/eslint-plugin-test/index.js": `
56c4a2cb
DC
3340 exports.rules = {
3341 "no-example": {
3342 meta: { type: "problem", fixable: "code" },
3343 create(context) {
3344 return {
3345 Identifier(node) {
3346 if (node.name === "example") {
3347 context.report({
3348 node,
3349 message: "fix",
3350 fix: fixer => fixer.replaceText(node, "fixed")
3351 })
3352 }
3353 }
3354 };
3355 }
3356 }
3357 };
3358 `,
6f036462
TL
3359 ".eslintrc.json": {
3360 plugins: ["test"],
3361 rules: { "test/no-example": "error" }
3362 },
3363 "a.js": "example;"
3364 }
56c4a2cb
DC
3365 });
3366
6f036462
TL
3367 beforeEach(() => {
3368 eslint = new ESLint({
3369 cwd: getPath(),
3370 fix: true,
3371 fixTypes: ["problem"]
3372 });
3373
3374 return prepare();
3375 });
3376
3377 afterEach(cleanup);
3378
56c4a2cb
DC
3379 it("should not crash.", async () => {
3380 const results = await eslint.lintFiles("a.js");
3381
3382 assert.strictEqual(results.length, 1);
3383 assert.deepStrictEqual(results[0].messages, []);
3384 assert.deepStrictEqual(results[0].output, "fixed;");
3385 });
3386 });
3387
3388 describe("multiple processors", () => {
3389 const root = path.join(os.tmpdir(), "eslint/eslint/multiple-processors");
3390 const commonFiles = {
3391 "node_modules/pattern-processor/index.js": fs.readFileSync(
3392 require.resolve("../../fixtures/processors/pattern-processor"),
3393 "utf8"
3394 ),
3395 "node_modules/eslint-plugin-markdown/index.js": `
3396 const { defineProcessor } = require("pattern-processor");
3397 const processor = defineProcessor(${/```(\w+)\n([\s\S]+?)\n```/gu});
3398 exports.processors = {
3399 ".md": { ...processor, supportsAutofix: true },
3400 "non-fixable": processor
3401 };
3402 `,
3403 "node_modules/eslint-plugin-html/index.js": `
3404 const { defineProcessor } = require("pattern-processor");
3405 const processor = defineProcessor(${/<script lang="(\w*)">\n([\s\S]+?)\n<\/script>/gu});
3406 const legacyProcessor = defineProcessor(${/<script lang="(\w*)">\n([\s\S]+?)\n<\/script>/gu}, true);
3407 exports.processors = {
3408 ".html": { ...processor, supportsAutofix: true },
3409 "non-fixable": processor,
3410 "legacy": legacyProcessor
3411 };
3412 `,
3413 "test.md": unIndent`
3414 \`\`\`js
3415 console.log("hello")
3416 \`\`\`
3417 \`\`\`html
3418 <div>Hello</div>
3419 <script lang="js">
3420 console.log("hello")
3421 </script>
3422 <script lang="ts">
3423 console.log("hello")
3424 </script>
3425 \`\`\`
3426 `
3427 };
3428
6f036462
TL
3429 let cleanup;
3430
3431 beforeEach(() => {
3432 cleanup = () => { };
3433 });
3434
3435 afterEach(() => cleanup());
3436
56c4a2cb 3437 it("should lint only JavaScript blocks if '--ext' was not given.", async () => {
6f036462
TL
3438 const teardown = createCustomTeardown({
3439 cwd: root,
56c4a2cb
DC
3440 files: {
3441 ...commonFiles,
6f036462 3442 ".eslintrc.json": {
56c4a2cb
DC
3443 plugins: ["markdown", "html"],
3444 rules: { semi: "error" }
6f036462 3445 }
56c4a2cb 3446 }
6f036462
TL
3447 });
3448
3449 cleanup = teardown.cleanup;
3450 await teardown.prepare();
3451 eslint = new ESLint({ cwd: teardown.getPath() });
56c4a2cb
DC
3452 const results = await eslint.lintFiles(["test.md"]);
3453
3454 assert.strictEqual(results.length, 1);
3455 assert.strictEqual(results[0].messages.length, 1);
3456 assert.strictEqual(results[0].messages[0].ruleId, "semi");
3457 assert.strictEqual(results[0].messages[0].line, 2);
3458 });
3459
3460 it("should fix only JavaScript blocks if '--ext' was not given.", async () => {
6f036462
TL
3461 const teardown = createCustomTeardown({
3462 cwd: root,
56c4a2cb
DC
3463 files: {
3464 ...commonFiles,
6f036462 3465 ".eslintrc.json": {
56c4a2cb
DC
3466 plugins: ["markdown", "html"],
3467 rules: { semi: "error" }
6f036462 3468 }
56c4a2cb 3469 }
6f036462
TL
3470 });
3471
3472 await teardown.prepare();
3473 cleanup = teardown.cleanup;
3474 eslint = new ESLint({ cwd: teardown.getPath(), fix: true });
56c4a2cb
DC
3475 const results = await eslint.lintFiles(["test.md"]);
3476
3477 assert.strictEqual(results.length, 1);
3478 assert.strictEqual(results[0].messages.length, 0);
3479 assert.strictEqual(results[0].output, unIndent`
3480 \`\`\`js
3481 console.log("hello");${/* ← fixed */""}
3482 \`\`\`
3483 \`\`\`html
3484 <div>Hello</div>
3485 <script lang="js">
3486 console.log("hello")${/* ← ignored */""}
3487 </script>
3488 <script lang="ts">
3489 console.log("hello")${/* ← ignored */""}
3490 </script>
3491 \`\`\`
3492 `);
3493 });
3494
3495 it("should lint HTML blocks as well with multiple processors if '--ext' option was given.", async () => {
6f036462
TL
3496 const teardown = createCustomTeardown({
3497 cwd: root,
56c4a2cb
DC
3498 files: {
3499 ...commonFiles,
6f036462 3500 ".eslintrc.json": {
56c4a2cb
DC
3501 plugins: ["markdown", "html"],
3502 rules: { semi: "error" }
6f036462 3503 }
56c4a2cb 3504 }
6f036462
TL
3505 });
3506
3507 await teardown.prepare();
3508 cleanup = teardown.cleanup;
3509 eslint = new ESLint({ cwd: teardown.getPath(), extensions: ["js", "html"] });
56c4a2cb
DC
3510 const results = await eslint.lintFiles(["test.md"]);
3511
3512 assert.strictEqual(results.length, 1);
3513 assert.strictEqual(results[0].messages.length, 2);
3514 assert.strictEqual(results[0].messages[0].ruleId, "semi"); // JS block
3515 assert.strictEqual(results[0].messages[0].line, 2);
3516 assert.strictEqual(results[0].messages[1].ruleId, "semi"); // JS block in HTML block
3517 assert.strictEqual(results[0].messages[1].line, 7);
3518 });
3519
3520 it("should fix HTML blocks as well with multiple processors if '--ext' option was given.", async () => {
6f036462
TL
3521 const teardown = createCustomTeardown({
3522 cwd: root,
56c4a2cb
DC
3523 files: {
3524 ...commonFiles,
6f036462 3525 ".eslintrc.json": {
56c4a2cb
DC
3526 plugins: ["markdown", "html"],
3527 rules: { semi: "error" }
6f036462 3528 }
56c4a2cb 3529 }
6f036462
TL
3530 });
3531
3532 await teardown.prepare();
3533 cleanup = teardown.cleanup;
3534 eslint = new ESLint({ cwd: teardown.getPath(), extensions: ["js", "html"], fix: true });
56c4a2cb
DC
3535 const results = await eslint.lintFiles(["test.md"]);
3536
3537 assert.strictEqual(results.length, 1);
3538 assert.strictEqual(results[0].messages.length, 0);
3539 assert.strictEqual(results[0].output, unIndent`
3540 \`\`\`js
3541 console.log("hello");${/* ← fixed */""}
3542 \`\`\`
3543 \`\`\`html
3544 <div>Hello</div>
3545 <script lang="js">
3546 console.log("hello");${/* ← fixed */""}
3547 </script>
3548 <script lang="ts">
3549 console.log("hello")${/* ← ignored */""}
3550 </script>
3551 \`\`\`
3552 `);
3553 });
3554
6f036462
TL
3555 it("should use overridden processor; should report HTML blocks but not fix HTML blocks if the processor for '*.html' didn't support autofix.", async () => {
3556 const teardown = createCustomTeardown({
3557 cwd: root,
56c4a2cb
DC
3558 files: {
3559 ...commonFiles,
6f036462 3560 ".eslintrc.json": {
56c4a2cb
DC
3561 plugins: ["markdown", "html"],
3562 rules: { semi: "error" },
3563 overrides: [
3564 {
3565 files: "*.html",
3566 processor: "html/non-fixable" // supportsAutofix: false
3567 }
3568 ]
6f036462 3569 }
56c4a2cb 3570 }
6f036462
TL
3571 });
3572
3573 await teardown.prepare();
3574 cleanup = teardown.cleanup;
3575 eslint = new ESLint({ cwd: teardown.getPath(), extensions: ["js", "html"], fix: true });
56c4a2cb
DC
3576 const results = await eslint.lintFiles(["test.md"]);
3577
3578 assert.strictEqual(results.length, 1);
3579 assert.strictEqual(results[0].messages.length, 1);
3580 assert.strictEqual(results[0].messages[0].ruleId, "semi"); // JS Block in HTML Block
3581 assert.strictEqual(results[0].messages[0].line, 7);
3582 assert.strictEqual(results[0].messages[0].fix, void 0);
3583 assert.strictEqual(results[0].output, unIndent`
3584 \`\`\`js
3585 console.log("hello");${/* ← fixed */""}
3586 \`\`\`
3587 \`\`\`html
3588 <div>Hello</div>
3589 <script lang="js">
3590 console.log("hello")${/* ← reported but not fixed */""}
3591 </script>
3592 <script lang="ts">
3593 console.log("hello")
3594 </script>
3595 \`\`\`
3596 `);
3597 });
3598
3599 it("should use the config '**/*.html/*.js' to lint JavaScript blocks in HTML.", async () => {
6f036462
TL
3600 const teardown = createCustomTeardown({
3601 cwd: root,
56c4a2cb
DC
3602 files: {
3603 ...commonFiles,
6f036462 3604 ".eslintrc.json": {
56c4a2cb
DC
3605 plugins: ["markdown", "html"],
3606 rules: { semi: "error" },
3607 overrides: [
3608 {
3609 files: "*.html",
3610
3611 // this rules are not used because ESLint re-resolve configs if a code block had a different file extension.
3612 rules: {
3613 semi: "error",
3614 "no-console": "off"
3615 }
3616 },
3617 {
3618 files: "**/*.html/*.js",
3619 rules: {
3620 semi: "off",
3621 "no-console": "error"
3622 }
3623 }
3624 ]
6f036462 3625 }
56c4a2cb 3626 }
6f036462
TL
3627 });
3628
3629 await teardown.prepare();
3630 cleanup = teardown.cleanup;
3631 eslint = new ESLint({ cwd: teardown.getPath(), extensions: ["js", "html"] });
56c4a2cb
DC
3632 const results = await eslint.lintFiles(["test.md"]);
3633
3634 assert.strictEqual(results.length, 1);
3635 assert.strictEqual(results[0].messages.length, 2);
3636 assert.strictEqual(results[0].messages[0].ruleId, "semi");
3637 assert.strictEqual(results[0].messages[0].line, 2);
3638 assert.strictEqual(results[0].messages[1].ruleId, "no-console");
3639 assert.strictEqual(results[0].messages[1].line, 7);
3640 });
3641
3642 it("should use the same config as one which has 'processor' property in order to lint blocks in HTML if the processor was legacy style.", async () => {
6f036462
TL
3643 const teardown = createCustomTeardown({
3644 cwd: root,
56c4a2cb
DC
3645 files: {
3646 ...commonFiles,
6f036462 3647 ".eslintrc.json": {
56c4a2cb
DC
3648 plugins: ["markdown", "html"],
3649 rules: { semi: "error" },
3650 overrides: [
3651 {
3652 files: "*.html",
3653 processor: "html/legacy", // this processor returns strings rather than `{text, filename}`
3654 rules: {
3655 semi: "off",
3656 "no-console": "error"
3657 }
3658 },
3659 {
3660 files: "**/*.html/*.js",
3661 rules: {
3662 semi: "error",
3663 "no-console": "off"
3664 }
3665 }
3666 ]
6f036462 3667 }
56c4a2cb 3668 }
6f036462
TL
3669 });
3670
3671 await teardown.prepare();
3672 cleanup = teardown.cleanup;
3673 eslint = new ESLint({ cwd: teardown.getPath(), extensions: ["js", "html"] });
56c4a2cb
DC
3674 const results = await eslint.lintFiles(["test.md"]);
3675
3676 assert.strictEqual(results.length, 1);
3677 assert.strictEqual(results[0].messages.length, 3);
3678 assert.strictEqual(results[0].messages[0].ruleId, "semi");
3679 assert.strictEqual(results[0].messages[0].line, 2);
3680 assert.strictEqual(results[0].messages[1].ruleId, "no-console");
3681 assert.strictEqual(results[0].messages[1].line, 7);
3682 assert.strictEqual(results[0].messages[2].ruleId, "no-console");
3683 assert.strictEqual(results[0].messages[2].line, 10);
3684 });
3685
3686 it("should throw an error if invalid processor was specified.", async () => {
6f036462
TL
3687 const teardown = createCustomTeardown({
3688 cwd: root,
56c4a2cb
DC
3689 files: {
3690 ...commonFiles,
6f036462 3691 ".eslintrc.json": {
56c4a2cb
DC
3692 plugins: ["markdown", "html"],
3693 processor: "markdown/unknown"
6f036462 3694 }
56c4a2cb 3695 }
6f036462
TL
3696 });
3697
3698 await teardown.prepare();
3699 cleanup = teardown.cleanup;
3700 eslint = new ESLint({ cwd: teardown.getPath() });
56c4a2cb
DC
3701
3702 await assert.rejects(async () => {
3703 await eslint.lintFiles(["test.md"]);
3704 }, /ESLint configuration of processor in '\.eslintrc\.json' is invalid: 'markdown\/unknown' was not found\./u);
3705 });
3706
3707 it("should lint HTML blocks as well with multiple processors if 'overrides[].files' is present.", async () => {
6f036462
TL
3708 const teardown = createCustomTeardown({
3709 cwd: root,
56c4a2cb
DC
3710 files: {
3711 ...commonFiles,
6f036462 3712 ".eslintrc.json": {
56c4a2cb
DC
3713 plugins: ["markdown", "html"],
3714 rules: { semi: "error" },
3715 overrides: [
3716 {
3717 files: "*.html",
3718 processor: "html/.html"
3719 },
3720 {
3721 files: "*.md",
3722 processor: "markdown/.md"
3723 }
3724 ]
6f036462 3725 }
56c4a2cb 3726 }
6f036462
TL
3727 });
3728
3729 await teardown.prepare();
3730 cleanup = teardown.cleanup;
3731 eslint = new ESLint({ cwd: teardown.getPath() });
56c4a2cb
DC
3732 const results = await eslint.lintFiles(["test.md"]);
3733
3734 assert.strictEqual(results.length, 1);
3735 assert.strictEqual(results[0].messages.length, 2);
3736 assert.strictEqual(results[0].messages[0].ruleId, "semi"); // JS block
3737 assert.strictEqual(results[0].messages[0].line, 2);
3738 assert.strictEqual(results[0].messages[1].ruleId, "semi"); // JS block in HTML block
3739 assert.strictEqual(results[0].messages[1].line, 7);
3740 });
3741 });
3742
3743 describe("MODULE_NOT_FOUND error handling", () => {
3744 const cwd = getFixturePath("module-not-found");
3745
3746 beforeEach(() => {
3747 eslint = new ESLint({ cwd });
3748 });
3749
3750 it("should throw an error with a message template when 'extends' property has a non-existence JavaScript config.", async () => {
3751 try {
3752 await eslint.lintText("test", { filePath: "extends-js/test.js" });
3753 } catch (err) {
3754 assert.strictEqual(err.messageTemplate, "extend-config-missing");
3755 assert.deepStrictEqual(err.messageData, {
3756 configName: "nonexistent-config",
3757 importerName: getFixturePath("module-not-found", "extends-js", ".eslintrc.yml")
3758 });
3759 return;
3760 }
3761 assert.fail("Expected to throw an error");
3762 });
3763
3764 it("should throw an error with a message template when 'extends' property has a non-existence plugin config.", async () => {
3765 try {
3766 await eslint.lintText("test", { filePath: "extends-plugin/test.js" });
3767 } catch (err) {
3768 assert.strictEqual(err.code, "MODULE_NOT_FOUND");
3769 assert.strictEqual(err.messageTemplate, "plugin-missing");
3770 assert.deepStrictEqual(err.messageData, {
3771 importerName: `extends-plugin${path.sep}.eslintrc.yml`,
3772 pluginName: "eslint-plugin-nonexistent-plugin",
3773 resolvePluginsRelativeTo: path.join(cwd, "extends-plugin") // the directory of the config file.
3774 });
3775 return;
3776 }
3777 assert.fail("Expected to throw an error");
3778 });
3779
3780 it("should throw an error with a message template when 'plugins' property has a non-existence plugin.", async () => {
3781 try {
3782 await eslint.lintText("test", { filePath: "plugins/test.js" });
3783 } catch (err) {
3784 assert.strictEqual(err.code, "MODULE_NOT_FOUND");
3785 assert.strictEqual(err.messageTemplate, "plugin-missing");
3786 assert.deepStrictEqual(err.messageData, {
3787 importerName: `plugins${path.sep}.eslintrc.yml`,
3788 pluginName: "eslint-plugin-nonexistent-plugin",
3789 resolvePluginsRelativeTo: path.join(cwd, "plugins") // the directory of the config file.
3790 });
3791 return;
3792 }
3793 assert.fail("Expected to throw an error");
3794 });
3795
3796 it("should throw an error with no message template when a JavaScript config threw a 'MODULE_NOT_FOUND' error.", async () => {
3797 try {
3798 await eslint.lintText("test", { filePath: "throw-in-config-itself/test.js" });
3799 } catch (err) {
3800 assert.strictEqual(err.code, "MODULE_NOT_FOUND");
3801 assert.strictEqual(err.messageTemplate, void 0);
3802 return;
3803 }
3804 assert.fail("Expected to throw an error");
3805 });
3806
3807 it("should throw an error with no message template when 'extends' property has a JavaScript config that throws a 'MODULE_NOT_FOUND' error.", async () => {
3808 try {
3809 await eslint.lintText("test", { filePath: "throw-in-extends-js/test.js" });
3810 } catch (err) {
3811 assert.strictEqual(err.code, "MODULE_NOT_FOUND");
3812 assert.strictEqual(err.messageTemplate, void 0);
3813 return;
3814 }
3815 assert.fail("Expected to throw an error");
3816 });
3817
3818 it("should throw an error with no message template when 'extends' property has a plugin config that throws a 'MODULE_NOT_FOUND' error.", async () => {
3819 try {
3820 await eslint.lintText("test", { filePath: "throw-in-extends-plugin/test.js" });
3821 } catch (err) {
3822 assert.strictEqual(err.code, "MODULE_NOT_FOUND");
3823 assert.strictEqual(err.messageTemplate, void 0);
3824 return;
3825 }
3826 assert.fail("Expected to throw an error");
3827 });
3828
3829 it("should throw an error with no message template when 'plugins' property has a plugin config that throws a 'MODULE_NOT_FOUND' error.", async () => {
3830 try {
3831 await eslint.lintText("test", { filePath: "throw-in-plugins/test.js" });
3832 } catch (err) {
3833 assert.strictEqual(err.code, "MODULE_NOT_FOUND");
3834 assert.strictEqual(err.messageTemplate, void 0);
3835 return;
3836 }
3837 assert.fail("Expected to throw an error");
3838 });
3839 });
3840
3841 describe("with '--rulesdir' option", () => {
6f036462
TL
3842
3843 const rootPath = getFixturePath("cli-engine/with-rulesdir");
3844 const { prepare, cleanup, getPath } = createCustomTeardown({
3845 cwd: rootPath,
3846 files: {
3847 "internal-rules/test.js": `
56c4a2cb
DC
3848 module.exports = context => ({
3849 ExpressionStatement(node) {
3850 context.report({ node, message: "ok" })
3851 }
3852 })
3853 `,
6f036462
TL
3854 ".eslintrc.json": {
3855 root: true,
3856 rules: { test: "error" }
3857 },
3858 "test.js": "console.log('hello')"
3859 }
3860 });
56c4a2cb 3861
6f036462
TL
3862 beforeEach(prepare);
3863 afterEach(cleanup);
3864
3865
3866 it("should use the configured rules which are defined by '--rulesdir' option.", async () => {
3867 eslint = new ESLint({
3868 cwd: getPath(),
56c4a2cb
DC
3869 rulePaths: ["internal-rules"]
3870 });
3871 const results = await eslint.lintFiles(["test.js"]);
3872
3873 assert.strictEqual(results.length, 1);
3874 assert.strictEqual(results[0].messages.length, 1);
3875 assert.strictEqual(results[0].messages[0].message, "ok");
3876 });
3877 });
3878
3879 describe("glob pattern '[ab].js'", () => {
3880 const root = getFixturePath("cli-engine/unmatched-glob");
3881
6f036462
TL
3882 let cleanup;
3883
3884 beforeEach(() => {
3885 cleanup = () => { };
3886 });
3887
3888 afterEach(() => cleanup());
3889
56c4a2cb 3890 it("should match '[ab].js' if existed.", async () => {
6f036462
TL
3891
3892 const teardown = createCustomTeardown({
3893 cwd: root,
56c4a2cb
DC
3894 files: {
3895 "a.js": "",
3896 "b.js": "",
3897 "ab.js": "",
3898 "[ab].js": "",
3899 ".eslintrc.yml": "root: true"
3900 }
6f036462
TL
3901 });
3902
3903 await teardown.prepare();
3904 cleanup = teardown.cleanup;
3905
3906 eslint = new ESLint({ cwd: teardown.getPath() });
56c4a2cb
DC
3907 const results = await eslint.lintFiles(["[ab].js"]);
3908 const filenames = results.map(r => path.basename(r.filePath));
3909
3910 assert.deepStrictEqual(filenames, ["[ab].js"]);
3911 });
3912
3913 it("should match 'a.js' and 'b.js' if '[ab].js' didn't existed.", async () => {
6f036462
TL
3914 const teardown = createCustomTeardown({
3915 cwd: root,
56c4a2cb
DC
3916 files: {
3917 "a.js": "",
3918 "b.js": "",
3919 "ab.js": "",
3920 ".eslintrc.yml": "root: true"
3921 }
6f036462
TL
3922 });
3923
3924 await teardown.prepare();
3925 cleanup = teardown.cleanup;
3926 eslint = new ESLint({ cwd: teardown.getPath() });
56c4a2cb
DC
3927 const results = await eslint.lintFiles(["[ab].js"]);
3928 const filenames = results.map(r => path.basename(r.filePath));
3929
3930 assert.deepStrictEqual(filenames, ["a.js", "b.js"]);
3931 });
3932 });
3933
3934 describe("with 'noInlineConfig' setting", () => {
3935 const root = getFixturePath("cli-engine/noInlineConfig");
3936
6f036462
TL
3937 let cleanup;
3938
3939 beforeEach(() => {
3940 cleanup = () => { };
3941 });
3942
3943 afterEach(() => cleanup());
3944
56c4a2cb 3945 it("should warn directive comments if 'noInlineConfig' was given.", async () => {
6f036462
TL
3946 const teardown = createCustomTeardown({
3947 cwd: root,
56c4a2cb
DC
3948 files: {
3949 "test.js": "/* globals foo */",
3950 ".eslintrc.yml": "noInlineConfig: true"
3951 }
6f036462
TL
3952 });
3953
3954 await teardown.prepare();
3955 cleanup = teardown.cleanup;
3956 eslint = new ESLint({ cwd: teardown.getPath() });
3957
56c4a2cb
DC
3958 const results = await eslint.lintFiles(["test.js"]);
3959 const messages = results[0].messages;
3960
3961 assert.strictEqual(messages.length, 1);
3962 assert.strictEqual(messages[0].message, "'/*globals*/' has no effect because you have 'noInlineConfig' setting in your config (.eslintrc.yml).");
3963 });
3964
3965 it("should show the config file what the 'noInlineConfig' came from.", async () => {
6f036462
TL
3966 const teardown = createCustomTeardown({
3967 cwd: root,
56c4a2cb
DC
3968 files: {
3969 "node_modules/eslint-config-foo/index.js": "module.exports = {noInlineConfig: true}",
3970 "test.js": "/* globals foo */",
3971 ".eslintrc.yml": "extends: foo"
3972 }
6f036462
TL
3973 });
3974
3975 await teardown.prepare();
3976 cleanup = teardown.cleanup;
3977 eslint = new ESLint({ cwd: teardown.getPath() });
3978
56c4a2cb
DC
3979 const results = await eslint.lintFiles(["test.js"]);
3980 const messages = results[0].messages;
3981
3982 assert.strictEqual(messages.length, 1);
3983 assert.strictEqual(messages[0].message, "'/*globals*/' has no effect because you have 'noInlineConfig' setting in your config (.eslintrc.yml » eslint-config-foo).");
3984 });
3985 });
3986
3987 describe("with 'reportUnusedDisableDirectives' setting", () => {
3988 const root = getFixturePath("cli-engine/reportUnusedDisableDirectives");
3989
6f036462
TL
3990 let cleanup;
3991
3992 beforeEach(() => {
3993 cleanup = () => { };
3994 });
3995
3996 afterEach(() => cleanup());
3997
56c4a2cb 3998 it("should warn unused 'eslint-disable' comments if 'reportUnusedDisableDirectives' was given.", async () => {
6f036462
TL
3999 const teardown = createCustomTeardown({
4000 cwd: root,
56c4a2cb
DC
4001 files: {
4002 "test.js": "/* eslint-disable eqeqeq */",
4003 ".eslintrc.yml": "reportUnusedDisableDirectives: true"
4004 }
6f036462
TL
4005 });
4006
4007
4008 await teardown.prepare();
4009 cleanup = teardown.cleanup;
4010 eslint = new ESLint({ cwd: teardown.getPath() });
4011
56c4a2cb
DC
4012 const results = await eslint.lintFiles(["test.js"]);
4013 const messages = results[0].messages;
4014
4015 assert.strictEqual(messages.length, 1);
4016 assert.strictEqual(messages[0].severity, 1);
4017 assert.strictEqual(messages[0].message, "Unused eslint-disable directive (no problems were reported from 'eqeqeq').");
4018 });
4019
4020 describe("the runtime option overrides config files.", () => {
4021 it("should not warn unused 'eslint-disable' comments if 'reportUnusedDisableDirectives=off' was given in runtime.", async () => {
6f036462
TL
4022 const teardown = createCustomTeardown({
4023 cwd: root,
56c4a2cb
DC
4024 files: {
4025 "test.js": "/* eslint-disable eqeqeq */",
4026 ".eslintrc.yml": "reportUnusedDisableDirectives: true"
4027 }
6f036462
TL
4028 });
4029
4030 await teardown.prepare();
4031 cleanup = teardown.cleanup;
4032
4033 eslint = new ESLint({
4034 cwd: teardown.getPath(),
4035 reportUnusedDisableDirectives: "off"
4036 });
4037
56c4a2cb
DC
4038 const results = await eslint.lintFiles(["test.js"]);
4039 const messages = results[0].messages;
4040
4041 assert.strictEqual(messages.length, 0);
4042 });
4043
4044 it("should warn unused 'eslint-disable' comments as error if 'reportUnusedDisableDirectives=error' was given in runtime.", async () => {
6f036462
TL
4045 const teardown = createCustomTeardown({
4046 cwd: root,
56c4a2cb
DC
4047 files: {
4048 "test.js": "/* eslint-disable eqeqeq */",
4049 ".eslintrc.yml": "reportUnusedDisableDirectives: true"
4050 }
6f036462
TL
4051 });
4052
4053 await teardown.prepare();
4054 cleanup = teardown.cleanup;
4055
4056 eslint = new ESLint({
4057 cwd: teardown.getPath(),
4058 reportUnusedDisableDirectives: "error"
4059 });
4060
56c4a2cb
DC
4061 const results = await eslint.lintFiles(["test.js"]);
4062 const messages = results[0].messages;
4063
4064 assert.strictEqual(messages.length, 1);
4065 assert.strictEqual(messages[0].severity, 2);
4066 assert.strictEqual(messages[0].message, "Unused eslint-disable directive (no problems were reported from 'eqeqeq').");
4067 });
4068 });
4069 });
4070
4071 describe("with 'overrides[*].extends' setting on deep locations", () => {
4072 const root = getFixturePath("cli-engine/deeply-overrides-i-extends");
6f036462
TL
4073 const { prepare, cleanup, getPath } = createCustomTeardown({
4074 cwd: root,
4075 files: {
4076 "node_modules/eslint-config-one/index.js": `module.exports = ${JSON.stringify({
4077 overrides: [{ files: ["*test*"], extends: "two" }]
4078 })}`,
4079 "node_modules/eslint-config-two/index.js": `module.exports = ${JSON.stringify({
4080 overrides: [{ files: ["*.js"], extends: "three" }]
4081 })}`,
4082 "node_modules/eslint-config-three/index.js": `module.exports = ${JSON.stringify({
4083 rules: { "no-console": "error" }
4084 })}`,
4085 "test.js": "console.log('hello')",
4086 ".eslintrc.yml": "extends: one"
4087 }
4088 });
4089
4090 beforeEach(prepare);
4091 afterEach(cleanup);
56c4a2cb
DC
4092
4093 it("should not throw.", async () => {
6f036462 4094 eslint = new ESLint({ cwd: getPath() });
56c4a2cb
DC
4095 const results = await eslint.lintFiles(["test.js"]);
4096 const messages = results[0].messages;
4097
4098 assert.strictEqual(messages.length, 1);
4099 assert.strictEqual(messages[0].ruleId, "no-console");
4100 });
4101 });
4102
4103 describe("don't ignore the entry directory.", () => {
4104 const root = getFixturePath("cli-engine/dont-ignore-entry-dir");
4105
6f036462
TL
4106 let cleanup;
4107
4108 beforeEach(() => {
4109 cleanup = () => { };
4110 });
4111
4112 afterEach(async () => {
4113 await cleanup();
4114
4115 const configFilePath = path.resolve(root, "../.eslintrc.json");
4116
4117 if (shell.test("-e", configFilePath)) {
4118 shell.rm(configFilePath);
4119 }
4120 });
4121
56c4a2cb 4122 it("'lintFiles(\".\")' should not load config files from outside of \".\".", async () => {
6f036462
TL
4123 const teardown = createCustomTeardown({
4124 cwd: root,
56c4a2cb
DC
4125 files: {
4126 "../.eslintrc.json": "BROKEN FILE",
4127 ".eslintrc.json": JSON.stringify({ root: true }),
4128 "index.js": "console.log(\"hello\")"
4129 }
6f036462
TL
4130 });
4131
4132 await teardown.prepare();
4133 cleanup = teardown.cleanup;
4134 eslint = new ESLint({ cwd: teardown.getPath() });
56c4a2cb
DC
4135
4136 // Don't throw "failed to load config file" error.
4137 await eslint.lintFiles(".");
4138 });
4139
4140 it("'lintFiles(\".\")' should not ignore '.' even if 'ignorePatterns' contains it.", async () => {
6f036462
TL
4141 const teardown = createCustomTeardown({
4142 cwd: root,
56c4a2cb 4143 files: {
6f036462
TL
4144 "../.eslintrc.json": { ignorePatterns: ["/dont-ignore-entry-dir"] },
4145 ".eslintrc.json": { root: true },
56c4a2cb
DC
4146 "index.js": "console.log(\"hello\")"
4147 }
6f036462
TL
4148 });
4149
4150 await teardown.prepare();
4151 cleanup = teardown.cleanup;
4152 eslint = new ESLint({ cwd: teardown.getPath() });
56c4a2cb
DC
4153
4154 // Don't throw "file not found" error.
4155 await eslint.lintFiles(".");
4156 });
4157
4158 it("'lintFiles(\"subdir\")' should not ignore './subdir' even if 'ignorePatterns' contains it.", async () => {
6f036462
TL
4159 const teardown = createCustomTeardown({
4160 cwd: root,
56c4a2cb 4161 files: {
6f036462
TL
4162 ".eslintrc.json": { ignorePatterns: ["/subdir"] },
4163 "subdir/.eslintrc.json": { root: true },
56c4a2cb
DC
4164 "subdir/index.js": "console.log(\"hello\")"
4165 }
6f036462
TL
4166 });
4167
4168 await teardown.prepare();
4169 cleanup = teardown.cleanup;
4170 eslint = new ESLint({ cwd: teardown.getPath() });
56c4a2cb
DC
4171
4172 // Don't throw "file not found" error.
4173 await eslint.lintFiles("subdir");
4174 });
4175 });
4176
4177 it("should throw if non-boolean value is given to 'options.warnIgnored' option", async () => {
4178 eslint = new ESLint();
4179 await assert.rejects(() => eslint.lintFiles(777), /'patterns' must be a non-empty string or an array of non-empty strings/u);
4180 await assert.rejects(() => eslint.lintFiles([null]), /'patterns' must be a non-empty string or an array of non-empty strings/u);
4181 });
4182 });
4183
4184 describe("calculateConfigForFile", () => {
4185 it("should return the info from Config#getConfig when called", async () => {
4186 const options = {
4187 overrideConfigFile: getFixturePath("configurations", "quotes-error.json")
4188 };
4189 const engine = new ESLint(options);
4190 const filePath = getFixturePath("single-quoted.js");
4191 const actualConfig = await engine.calculateConfigForFile(filePath);
4192 const expectedConfig = new CascadingConfigArrayFactory({ specificConfigPath: options.overrideConfigFile })
4193 .getConfigArrayForFile(filePath)
4194 .extractConfig(filePath)
4195 .toCompatibleObjectAsConfigFileContent();
4196
4197 assert.deepStrictEqual(actualConfig, expectedConfig);
4198 });
4199
5422a9cc
TL
4200 it("should return the config for a file that doesn't exist", async () => {
4201 const engine = new ESLint();
4202 const filePath = getFixturePath("does_not_exist.js");
4203 const existingSiblingFilePath = getFixturePath("single-quoted.js");
4204 const actualConfig = await engine.calculateConfigForFile(filePath);
4205 const expectedConfig = await engine.calculateConfigForFile(existingSiblingFilePath);
4206
4207 assert.deepStrictEqual(actualConfig, expectedConfig);
4208 });
4209
4210 it("should return the config for a virtual file that is a child of an existing file", async () => {
4211 const engine = new ESLint();
4212 const parentFileName = "single-quoted.js";
4213 const filePath = getFixturePath(parentFileName, "virtual.js"); // single-quoted.js/virtual.js
4214 const parentFilePath = getFixturePath(parentFileName);
4215 const actualConfig = await engine.calculateConfigForFile(filePath);
4216 const expectedConfig = await engine.calculateConfigForFile(parentFilePath);
4217
4218 assert.deepStrictEqual(actualConfig, expectedConfig);
4219 });
56c4a2cb
DC
4220
4221 it("should return the config when run from within a subdir", async () => {
4222 const options = {
4223 cwd: getFixturePath("config-hierarchy", "root-true", "parent", "root", "subdir")
4224 };
4225 const engine = new ESLint(options);
4226 const filePath = getFixturePath("config-hierarchy", "root-true", "parent", "root", ".eslintrc");
4227 const actualConfig = await engine.calculateConfigForFile("./.eslintrc");
4228 const expectedConfig = new CascadingConfigArrayFactory(options)
4229 .getConfigArrayForFile(filePath)
4230 .extractConfig(filePath)
4231 .toCompatibleObjectAsConfigFileContent();
4232
4233 assert.deepStrictEqual(actualConfig, expectedConfig);
4234 });
4235
4236 it("should throw an error if a directory path was given.", async () => {
4237 const engine = new ESLint();
4238
4239 try {
4240 await engine.calculateConfigForFile(".");
4241 } catch (error) {
4242 assert.strictEqual(error.messageTemplate, "print-config-with-directory-path");
4243 return;
4244 }
4245 assert.fail("should throw an error");
4246 });
4247
4248 it("should throw if non-string value is given to 'filePath' parameter", async () => {
4249 const eslint = new ESLint();
4250
4251 await assert.rejects(() => eslint.calculateConfigForFile(null), /'filePath' must be a non-empty string/u);
4252 });
6f036462
TL
4253
4254 // https://github.com/eslint/eslint/issues/13793
4255 it("should throw with an invalid built-in rule config", async () => {
4256 const options = {
4257 baseConfig: {
4258 rules: {
4259 "no-alert": ["error", {
4260 thisDoesNotExist: true
4261 }]
4262 }
4263 }
4264 };
4265 const engine = new ESLint(options);
4266 const filePath = getFixturePath("single-quoted.js");
4267
4268 await assert.rejects(
4269 () => engine.calculateConfigForFile(filePath),
4270 /Configuration for rule "no-alert" is invalid:/u
4271 );
4272 });
56c4a2cb
DC
4273 });
4274
4275 describe("isPathIgnored", () => {
4276 it("should check if the given path is ignored", async () => {
4277 const engine = new ESLint({
4278 ignorePath: getFixturePath(".eslintignore2"),
4279 cwd: getFixturePath()
4280 });
4281
4282 assert(await engine.isPathIgnored("undef.js"));
4283 assert(!await engine.isPathIgnored("passing.js"));
4284 });
4285
4286 it("should return false if ignoring is disabled", async () => {
4287 const engine = new ESLint({
4288 ignore: false,
4289 ignorePath: getFixturePath(".eslintignore2"),
4290 cwd: getFixturePath()
4291 });
4292
4293 assert(!await engine.isPathIgnored("undef.js"));
4294 });
4295
4296 // https://github.com/eslint/eslint/issues/5547
4297 it("should return true for default ignores even if ignoring is disabled", async () => {
4298 const engine = new ESLint({
4299 ignore: false,
4300 cwd: getFixturePath("cli-engine")
4301 });
4302
4303 assert(await engine.isPathIgnored("node_modules/foo.js"));
4304 });
4305
4306 describe("about the default ignore patterns", () => {
4307 it("should always apply defaultPatterns if ignore option is true", async () => {
4308 const cwd = getFixturePath("ignored-paths");
4309 const engine = new ESLint({ cwd });
4310
4311 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "node_modules/package/file.js")));
4312 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "subdir/node_modules/package/file.js")));
4313 });
4314
4315 it("should still apply defaultPatterns if ignore option is is false", async () => {
4316 const cwd = getFixturePath("ignored-paths");
4317 const engine = new ESLint({ ignore: false, cwd });
4318
4319 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "node_modules/package/file.js")));
4320 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "subdir/node_modules/package/file.js")));
4321 });
4322
4323 it("should allow subfolders of defaultPatterns to be unignored by ignorePattern", async () => {
4324 const cwd = getFixturePath("ignored-paths");
4325 const engine = new ESLint({
4326 cwd,
4327 overrideConfig: {
4328 ignorePatterns: "!/node_modules/package"
4329 }
4330 });
4331
4332 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "node_modules", "package", "file.js")));
4333 });
4334
4335 it("should allow subfolders of defaultPatterns to be unignored by ignorePath", async () => {
4336 const cwd = getFixturePath("ignored-paths");
4337 const engine = new ESLint({ cwd, ignorePath: getFixturePath("ignored-paths", ".eslintignoreWithUnignoredDefaults") });
4338
4339 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "node_modules", "package", "file.js")));
4340 });
4341
4342 it("should ignore dotfiles", async () => {
4343 const cwd = getFixturePath("ignored-paths");
4344 const engine = new ESLint({ cwd });
4345
4346 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", ".foo")));
4347 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "foo/.bar")));
4348 });
4349
4350 it("should ignore directories beginning with a dot", async () => {
4351 const cwd = getFixturePath("ignored-paths");
4352 const engine = new ESLint({ cwd });
4353
4354 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", ".foo/bar")));
4355 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "foo/.bar/baz")));
4356 });
4357
4358 it("should still ignore dotfiles when ignore option disabled", async () => {
4359 const cwd = getFixturePath("ignored-paths");
4360 const engine = new ESLint({ ignore: false, cwd });
4361
4362 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", ".foo")));
4363 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "foo/.bar")));
4364 });
4365
4366 it("should still ignore directories beginning with a dot when ignore option disabled", async () => {
4367 const cwd = getFixturePath("ignored-paths");
4368 const engine = new ESLint({ ignore: false, cwd });
4369
4370 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", ".foo/bar")));
4371 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "foo/.bar/baz")));
4372 });
4373
4374 it("should not ignore absolute paths containing '..'", async () => {
4375 const cwd = getFixturePath("ignored-paths");
4376 const engine = new ESLint({ cwd });
4377
4378 assert(!await engine.isPathIgnored(`${getFixturePath("ignored-paths", "foo")}/../unignored.js`));
4379 });
4380
4381 it("should ignore /node_modules/ relative to .eslintignore when loaded", async () => {
4382 const cwd = getFixturePath("ignored-paths");
4383 const engine = new ESLint({ ignorePath: getFixturePath("ignored-paths", ".eslintignore"), cwd });
4384
4385 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "node_modules", "existing.js")));
4386 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "foo", "node_modules", "existing.js")));
4387 });
4388
4389 it("should ignore /node_modules/ relative to cwd without an .eslintignore", async () => {
4390 const cwd = getFixturePath("ignored-paths", "no-ignore-file");
4391 const engine = new ESLint({ cwd });
4392
4393 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "no-ignore-file", "node_modules", "existing.js")));
4394 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "no-ignore-file", "foo", "node_modules", "existing.js")));
4395 });
4396 });
4397
4398 describe("with no .eslintignore file", () => {
4399 it("should not travel to parent directories to find .eslintignore when it's missing and cwd is provided", async () => {
4400 const cwd = getFixturePath("ignored-paths", "configurations");
4401 const engine = new ESLint({ cwd });
4402
4403 // a .eslintignore in parent directories includes `*.js`, but don't load it.
4404 assert(!await engine.isPathIgnored("foo.js"));
4405 assert(await engine.isPathIgnored("node_modules/foo.js"));
4406 });
4407
4408 it("should return false for files outside of the cwd (with no ignore file provided)", async () => {
4409
4410 // Default ignore patterns should not inadvertently ignore files in parent directories
4411 const engine = new ESLint({ cwd: getFixturePath("ignored-paths", "no-ignore-file") });
4412
4413 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "undef.js")));
4414 });
4415 });
4416
4417 describe("with .eslintignore file or package.json file", () => {
4418 it("should load .eslintignore from cwd when explicitly passed", async () => {
4419 const cwd = getFixturePath("ignored-paths");
4420 const engine = new ESLint({ cwd });
4421
4422 // `${cwd}/.eslintignore` includes `sampleignorepattern`.
4423 assert(await engine.isPathIgnored("sampleignorepattern"));
4424 });
4425
4426 it("should use package.json's eslintIgnore files if no specified .eslintignore file", async () => {
4427 const cwd = getFixturePath("ignored-paths", "package-json-ignore");
4428 const engine = new ESLint({ cwd });
4429
4430 assert(await engine.isPathIgnored("hello.js"));
4431 assert(await engine.isPathIgnored("world.js"));
4432 });
4433
4434 it("should use correct message template if failed to parse package.json", () => {
4435 const cwd = getFixturePath("ignored-paths", "broken-package-json");
4436
4437 assert.throws(() => {
4438 try {
609c276f 4439 // eslint-disable-next-line no-new -- Check for error
56c4a2cb
DC
4440 new ESLint({ cwd });
4441 } catch (error) {
4442 assert.strictEqual(error.messageTemplate, "failed-to-read-json");
4443 throw error;
4444 }
4445 });
4446 });
4447
4448 it("should not use package.json's eslintIgnore files if specified .eslintignore file", async () => {
4449 const cwd = getFixturePath("ignored-paths");
4450 const engine = new ESLint({ cwd });
4451
4452 /*
4453 * package.json includes `hello.js` and `world.js`.
4454 * .eslintignore includes `sampleignorepattern`.
4455 */
4456 assert(!await engine.isPathIgnored("hello.js"));
4457 assert(!await engine.isPathIgnored("world.js"));
4458 assert(await engine.isPathIgnored("sampleignorepattern"));
4459 });
4460
4461 it("should error if package.json's eslintIgnore is not an array of file paths", () => {
4462 const cwd = getFixturePath("ignored-paths", "bad-package-json-ignore");
4463
4464 assert.throws(() => {
609c276f 4465 // eslint-disable-next-line no-new -- Check for throwing
56c4a2cb
DC
4466 new ESLint({ cwd });
4467 }, /Package\.json eslintIgnore property requires an array of paths/u);
4468 });
4469 });
4470
4471 describe("with --ignore-pattern option", () => {
4472 it("should accept a string for options.ignorePattern", async () => {
4473 const cwd = getFixturePath("ignored-paths", "ignore-pattern");
4474 const engine = new ESLint({
4475 overrideConfig: {
4476 ignorePatterns: "ignore-me.txt"
4477 },
4478 cwd
4479 });
4480
4481 assert(await engine.isPathIgnored("ignore-me.txt"));
4482 });
4483
4484 it("should accept an array for options.ignorePattern", async () => {
4485 const engine = new ESLint({
4486 overrideConfig: {
4487 ignorePatterns: ["a", "b"]
4488 },
4489 useEslintrc: false
4490 });
4491
4492 assert(await engine.isPathIgnored("a"));
4493 assert(await engine.isPathIgnored("b"));
4494 assert(!await engine.isPathIgnored("c"));
4495 });
4496
4497 it("should return true for files which match an ignorePattern even if they do not exist on the filesystem", async () => {
4498 const cwd = getFixturePath("ignored-paths");
4499 const engine = new ESLint({
4500 overrideConfig: {
4501 ignorePatterns: "not-a-file"
4502 },
4503 cwd
4504 });
4505
4506 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "not-a-file")));
4507 });
4508
4509 it("should return true for file matching an ignore pattern exactly", async () => {
4510 const cwd = getFixturePath("ignored-paths");
4511 const engine = new ESLint({ overrideConfig: { ignorePatterns: "undef.js" }, cwd });
4512
4513 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "undef.js")));
4514 });
4515
4516 it("should return false for file matching an invalid ignore pattern with leading './'", async () => {
4517 const cwd = getFixturePath("ignored-paths");
4518 const engine = new ESLint({ overrideConfig: { ignorePatterns: "./undef.js" }, cwd });
4519
4520 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "undef.js")));
4521 });
4522
4523 it("should return false for file in subfolder of cwd matching an ignore pattern with leading '/'", async () => {
4524 const cwd = getFixturePath("ignored-paths");
4525 const engine = new ESLint({ overrideConfig: { ignorePatterns: "/undef.js" }, cwd });
4526
4527 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "subdir", "undef.js")));
4528 });
4529
4530 it("should return true for file matching a child of an ignore pattern", async () => {
4531 const cwd = getFixturePath("ignored-paths");
4532 const engine = new ESLint({ overrideConfig: { ignorePatterns: "ignore-pattern" }, cwd });
4533
4534 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "ignore-pattern", "ignore-me.txt")));
4535 });
4536
4537 it("should return true for file matching a grandchild of an ignore pattern", async () => {
4538 const cwd = getFixturePath("ignored-paths");
4539 const engine = new ESLint({ overrideConfig: { ignorePatterns: "ignore-pattern" }, cwd });
4540
4541 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "ignore-pattern", "subdir", "ignore-me.txt")));
4542 });
4543
4544 it("should return false for file not matching any ignore pattern", async () => {
4545 const cwd = getFixturePath("ignored-paths");
4546 const engine = new ESLint({ overrideConfig: { ignorePatterns: "failing.js" }, cwd });
4547
4548 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "unignored.js")));
4549 });
4550
4551 it("two globstar '**' ignore pattern should ignore files in nested directories", async () => {
4552 const cwd = getFixturePath("ignored-paths");
4553 const engine = new ESLint({ overrideConfig: { ignorePatterns: "**/*.js" }, cwd });
4554
4555 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "foo.js")));
4556 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "foo/bar.js")));
4557 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "foo/bar/baz.js")));
4558 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "foo.j2")));
4559 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "foo/bar.j2")));
4560 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "foo/bar/baz.j2")));
4561 });
4562 });
4563
4564 describe("with --ignore-path option", () => {
4565 it("initialization with ignorePath should work when cwd is a parent directory", async () => {
4566 const cwd = getFixturePath("ignored-paths");
4567 const ignorePath = getFixturePath("ignored-paths", "custom-name", "ignore-file");
4568 const engine = new ESLint({ ignorePath, cwd });
4569
4570 assert(await engine.isPathIgnored("custom-name/foo.js"));
4571 });
4572
4573 it("initialization with ignorePath should work when the file is in the cwd", async () => {
4574 const cwd = getFixturePath("ignored-paths", "custom-name");
4575 const ignorePath = getFixturePath("ignored-paths", "custom-name", "ignore-file");
4576 const engine = new ESLint({ ignorePath, cwd });
4577
4578 assert(await engine.isPathIgnored("foo.js"));
4579 });
4580
4581 it("initialization with ignorePath should work when cwd is a subdirectory", async () => {
4582 const cwd = getFixturePath("ignored-paths", "custom-name", "subdirectory");
4583 const ignorePath = getFixturePath("ignored-paths", "custom-name", "ignore-file");
4584 const engine = new ESLint({ ignorePath, cwd });
4585
4586 assert(await engine.isPathIgnored("../custom-name/foo.js"));
4587 });
4588
4589 it("initialization with invalid file should throw error", () => {
4590 const cwd = getFixturePath("ignored-paths");
4591 const ignorePath = getFixturePath("ignored-paths", "not-a-directory", ".foobaz");
4592
4593 assert.throws(() => {
609c276f 4594 // eslint-disable-next-line no-new -- Check for throwing
56c4a2cb
DC
4595 new ESLint({ ignorePath, cwd });
4596 }, /Cannot read \.eslintignore file/u);
4597 });
4598
4599 it("should return false for files outside of ignorePath's directory", async () => {
4600 const cwd = getFixturePath("ignored-paths");
4601 const ignorePath = getFixturePath("ignored-paths", "custom-name", "ignore-file");
4602 const engine = new ESLint({ ignorePath, cwd });
4603
4604 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "undef.js")));
4605 });
4606
4607 it("should resolve relative paths from CWD", async () => {
4608 const cwd = getFixturePath("ignored-paths", "subdir");
4609 const ignorePath = getFixturePath("ignored-paths", ".eslintignoreForDifferentCwd");
4610 const engine = new ESLint({ ignorePath, cwd });
4611
4612 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "subdir/undef.js")));
4613 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "undef.js")));
4614 });
4615
4616 it("should resolve relative paths from CWD when it's in a child directory", async () => {
4617 const cwd = getFixturePath("ignored-paths");
4618 const ignorePath = getFixturePath("ignored-paths", "subdir/.eslintignoreInChildDir");
4619 const engine = new ESLint({ ignorePath, cwd });
4620
4621 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "subdir/undef.js")));
4622 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "undef.js")));
4623 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "foo.js")));
4624 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "subdir/foo.js")));
4625
4626 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "node_modules/bar.js")));
4627 });
4628
4629 it("should resolve relative paths from CWD when it contains negated globs", async () => {
4630 const cwd = getFixturePath("ignored-paths");
4631 const ignorePath = getFixturePath("ignored-paths", "subdir/.eslintignoreInChildDir");
4632 const engine = new ESLint({ ignorePath, cwd });
4633
4634 assert(await engine.isPathIgnored("subdir/blah.txt"));
4635 assert(await engine.isPathIgnored("blah.txt"));
4636 assert(await engine.isPathIgnored("subdir/bar.txt"));
4637 assert(!await engine.isPathIgnored("bar.txt"));
4638 assert(!await engine.isPathIgnored("subdir/baz.txt"));
4639 assert(!await engine.isPathIgnored("baz.txt"));
4640 });
4641
4642 it("should resolve default ignore patterns from the CWD even when the ignorePath is in a subdirectory", async () => {
4643 const cwd = getFixturePath("ignored-paths");
4644 const ignorePath = getFixturePath("ignored-paths", "subdir/.eslintignoreInChildDir");
4645 const engine = new ESLint({ ignorePath, cwd });
4646
4647 assert(await engine.isPathIgnored("node_modules/blah.js"));
4648 });
4649
4650 it("should resolve default ignore patterns from the CWD even when the ignorePath is in a parent directory", async () => {
4651 const cwd = getFixturePath("ignored-paths", "subdir");
4652 const ignorePath = getFixturePath("ignored-paths", ".eslintignoreForDifferentCwd");
4653 const engine = new ESLint({ ignorePath, cwd });
4654
4655 assert(await engine.isPathIgnored("node_modules/blah.js"));
4656 });
4657
4658 it("should handle .eslintignore which contains CRLF correctly.", async () => {
4659 const ignoreFileContent = fs.readFileSync(getFixturePath("ignored-paths", "crlf/.eslintignore"), "utf8");
4660
4661 assert(ignoreFileContent.includes("\r"), "crlf/.eslintignore should contains CR.");
4662 const cwd = getFixturePath("ignored-paths");
4663 const ignorePath = getFixturePath("ignored-paths", "crlf/.eslintignore");
4664 const engine = new ESLint({ ignorePath, cwd });
4665
4666 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "crlf/hide1/a.js")));
4667 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "crlf/hide2/a.js")));
4668 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "crlf/hide3/a.js")));
4669 });
4670
4671 it("should not include comments in ignore rules", async () => {
4672 const cwd = getFixturePath("ignored-paths");
4673 const ignorePath = getFixturePath("ignored-paths", ".eslintignoreWithComments");
4674 const engine = new ESLint({ ignorePath, cwd });
4675
4676 assert(!await engine.isPathIgnored("# should be ignored"));
4677 assert(await engine.isPathIgnored("this_one_not"));
4678 });
4679
4680 it("should ignore a non-negated pattern", async () => {
4681 const cwd = getFixturePath("ignored-paths");
4682 const ignorePath = getFixturePath("ignored-paths", ".eslintignoreWithNegation");
4683 const engine = new ESLint({ ignorePath, cwd });
4684
4685 assert(await engine.isPathIgnored(getFixturePath("ignored-paths", "negation", "ignore.js")));
4686 });
4687
4688 it("should not ignore a negated pattern", async () => {
4689 const cwd = getFixturePath("ignored-paths");
4690 const ignorePath = getFixturePath("ignored-paths", ".eslintignoreWithNegation");
4691 const engine = new ESLint({ ignorePath, cwd });
4692
4693 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "negation", "unignore.js")));
4694 });
8f9d1d4d
DC
4695
4696 // https://github.com/eslint/eslint/issues/15642
4697 it("should correctly handle patterns with escaped brackets", async () => {
4698 const cwd = getFixturePath("ignored-paths");
4699 const ignorePath = getFixturePath("ignored-paths", ".eslintignoreWithEscapedBrackets");
4700 const engine = new ESLint({ ignorePath, cwd });
4701
4702 const subdir = "brackets";
4703
4704 assert(
4705 !await engine.isPathIgnored(getFixturePath("ignored-paths", subdir, "index.js")),
4706 `'${subdir}/index.js' should not be ignored`
4707 );
4708
4709 for (const filename of ["[index.js", "index].js", "[index].js"]) {
4710 assert(
4711 await engine.isPathIgnored(getFixturePath("ignored-paths", subdir, filename)),
4712 `'${subdir}/${filename}' should be ignored`
4713 );
4714 }
4715
4716 });
56c4a2cb
DC
4717 });
4718
4719 describe("with --ignore-path option and --ignore-pattern option", () => {
4720 it("should return false for ignored file when unignored with ignore pattern", async () => {
4721 const cwd = getFixturePath("ignored-paths");
4722 const engine = new ESLint({
4723 ignorePath: getFixturePath("ignored-paths", ".eslintignore"),
4724 overrideConfig: {
4725 ignorePatterns: "!sampleignorepattern"
4726 },
4727 cwd
4728 });
4729
4730 assert(!await engine.isPathIgnored(getFixturePath("ignored-paths", "sampleignorepattern")));
4731 });
4732 });
4733
4734 it("should throw if non-string value is given to 'filePath' parameter", async () => {
4735 const eslint = new ESLint();
4736
4737 await assert.rejects(() => eslint.isPathIgnored(null), /'filePath' must be a non-empty string/u);
4738 });
4739 });
4740
4741 describe("loadFormatter()", () => {
4742 it("should return a formatter object when a bundled formatter is requested", async () => {
4743 const engine = new ESLint();
4744 const formatter = await engine.loadFormatter("compact");
4745
4746 assert.strictEqual(typeof formatter, "object");
4747 assert.strictEqual(typeof formatter.format, "function");
4748 });
4749
4750 it("should return a formatter object when no argument is passed", async () => {
4751 const engine = new ESLint();
4752 const formatter = await engine.loadFormatter();
4753
4754 assert.strictEqual(typeof formatter, "object");
4755 assert.strictEqual(typeof formatter.format, "function");
4756 });
4757
4758 it("should return a formatter object when a custom formatter is requested", async () => {
4759 const engine = new ESLint();
4760 const formatter = await engine.loadFormatter(getFixturePath("formatters", "simple.js"));
4761
4762 assert.strictEqual(typeof formatter, "object");
4763 assert.strictEqual(typeof formatter.format, "function");
4764 });
4765
4766 it("should return a formatter object when a custom formatter is requested, also if the path has backslashes", async () => {
4767 const engine = new ESLint({
4768 cwd: path.join(fixtureDir, "..")
4769 });
4770 const formatter = await engine.loadFormatter(".\\fixtures\\formatters\\simple.js");
4771
4772 assert.strictEqual(typeof formatter, "object");
4773 assert.strictEqual(typeof formatter.format, "function");
4774 });
4775
4776 it("should return a formatter object when a formatter prefixed with eslint-formatter is requested", async () => {
4777 const engine = new ESLint({
4778 cwd: getFixturePath("cli-engine")
4779 });
4780 const formatter = await engine.loadFormatter("bar");
4781
4782 assert.strictEqual(typeof formatter, "object");
4783 assert.strictEqual(typeof formatter.format, "function");
4784 });
4785
4786 it("should return a formatter object when a formatter is requested, also when the eslint-formatter prefix is included in the format argument", async () => {
4787 const engine = new ESLint({
4788 cwd: getFixturePath("cli-engine")
4789 });
4790 const formatter = await engine.loadFormatter("eslint-formatter-bar");
4791
4792 assert.strictEqual(typeof formatter, "object");
4793 assert.strictEqual(typeof formatter.format, "function");
4794 });
4795
4796 it("should return a formatter object when a formatter is requested within a scoped npm package", async () => {
4797 const engine = new ESLint({
4798 cwd: getFixturePath("cli-engine")
4799 });
4800 const formatter = await engine.loadFormatter("@somenamespace/foo");
4801
4802 assert.strictEqual(typeof formatter, "object");
4803 assert.strictEqual(typeof formatter.format, "function");
4804 });
4805
4806 it("should return a formatter object when a formatter is requested within a scoped npm package, also when the eslint-formatter prefix is included in the format argument", async () => {
4807 const engine = new ESLint({
4808 cwd: getFixturePath("cli-engine")
4809 });
4810 const formatter = await engine.loadFormatter("@somenamespace/eslint-formatter-foo");
4811
4812 assert.strictEqual(typeof formatter, "object");
4813 assert.strictEqual(typeof formatter.format, "function");
4814 });
4815
609c276f 4816 it("should throw if a custom formatter doesn't exist", async () => {
56c4a2cb
DC
4817 const engine = new ESLint();
4818 const formatterPath = getFixturePath("formatters", "doesntexist.js");
4819 const fullFormatterPath = path.resolve(formatterPath);
4820
4821 await assert.rejects(async () => {
4822 await engine.loadFormatter(formatterPath);
4823 }, new RegExp(escapeStringRegExp(`There was a problem loading formatter: ${fullFormatterPath}\nError: Cannot find module '${fullFormatterPath}'`), "u"));
4824 });
4825
4826 it("should throw if a built-in formatter doesn't exist", async () => {
4827 const engine = new ESLint();
4828 const fullFormatterPath = path.resolve(__dirname, "../../../lib/cli-engine/formatters/special");
4829
4830 await assert.rejects(async () => {
4831 await engine.loadFormatter("special");
4832 }, new RegExp(escapeStringRegExp(`There was a problem loading formatter: ${fullFormatterPath}\nError: Cannot find module '${fullFormatterPath}'`), "u"));
4833 });
4834
4835 it("should throw if the required formatter exists but has an error", async () => {
4836 const engine = new ESLint();
4837 const formatterPath = getFixturePath("formatters", "broken.js");
4838
4839 await assert.rejects(async () => {
4840 await engine.loadFormatter(formatterPath);
4841 }, new RegExp(escapeStringRegExp(`There was a problem loading formatter: ${formatterPath}\nError: Cannot find module 'this-module-does-not-exist'`), "u"));
4842 });
4843
4844 it("should throw if a non-string formatter name is passed", async () => {
4845 const engine = new ESLint();
4846
4847 await assert.rejects(async () => {
4848 await engine.loadFormatter(5);
4849 }, /'name' must be a string/u);
4850 });
34eeec05
TL
4851
4852 it("should pass cwd to the `cwd` property of the second argument.", async () => {
4853 const cwd = getFixturePath();
4854 const engine = new ESLint({ cwd });
4855 const formatterPath = getFixturePath("formatters", "cwd.js");
4856 const formatter = await engine.loadFormatter(formatterPath);
4857
4858 assert.strictEqual(formatter.format([]), cwd);
4859 });
56c4a2cb
DC
4860 });
4861
4862 describe("getErrorResults()", () => {
4863 it("should report 5 error messages when looking for errors only", async () => {
4864 process.chdir(originalDir);
4865 const engine = new ESLint();
4866 const results = await engine.lintText("var foo = 'bar';");
4867 const errorResults = ESLint.getErrorResults(results);
4868
4869 assert.strictEqual(errorResults[0].messages.length, 5);
4870 assert.strictEqual(errorResults[0].errorCount, 5);
4871 assert.strictEqual(errorResults[0].fixableErrorCount, 3);
4872 assert.strictEqual(errorResults[0].fixableWarningCount, 0);
4873 assert.strictEqual(errorResults[0].messages[0].ruleId, "strict");
4874 assert.strictEqual(errorResults[0].messages[0].severity, 2);
4875 assert.strictEqual(errorResults[0].messages[1].ruleId, "no-var");
4876 assert.strictEqual(errorResults[0].messages[1].severity, 2);
4877 assert.strictEqual(errorResults[0].messages[2].ruleId, "no-unused-vars");
4878 assert.strictEqual(errorResults[0].messages[2].severity, 2);
4879 assert.strictEqual(errorResults[0].messages[3].ruleId, "quotes");
4880 assert.strictEqual(errorResults[0].messages[3].severity, 2);
4881 assert.strictEqual(errorResults[0].messages[4].ruleId, "eol-last");
4882 assert.strictEqual(errorResults[0].messages[4].severity, 2);
4883 });
4884
4885 it("should not mutate passed report parameter", async () => {
4886 process.chdir(originalDir);
4887 const engine = new ESLint({
4888 overrideConfig: {
4889 rules: { quotes: [1, "double"] }
4890 }
4891 });
4892 const results = await engine.lintText("var foo = 'bar';");
4893 const reportResultsLength = results[0].messages.length;
4894
4895 ESLint.getErrorResults(results);
4896
4897 assert.strictEqual(results[0].messages.length, reportResultsLength);
4898 });
4899
4900 it("should report a warningCount of 0 when looking for errors only", async () => {
4901 process.chdir(originalDir);
4902 const engine = new ESLint();
4903 const results = await engine.lintText("var foo = 'bar';");
4904 const errorResults = ESLint.getErrorResults(results);
4905
4906 assert.strictEqual(errorResults[0].warningCount, 0);
4907 assert.strictEqual(errorResults[0].fixableWarningCount, 0);
4908 });
4909
4910 it("should return 0 error or warning messages even when the file has warnings", async () => {
4911 const engine = new ESLint({
4912 ignorePath: path.join(fixtureDir, ".eslintignore"),
4913 cwd: path.join(fixtureDir, "..")
4914 });
4915 const options = {
4916 filePath: "fixtures/passing.js",
4917 warnIgnored: true
4918 };
4919 const results = await engine.lintText("var bar = foo;", options);
4920 const errorReport = ESLint.getErrorResults(results);
4921
4922 assert.strictEqual(errorReport.length, 0);
4923 assert.strictEqual(results.length, 1);
4924 assert.strictEqual(results[0].errorCount, 0);
4925 assert.strictEqual(results[0].warningCount, 1);
8f9d1d4d
DC
4926 assert.strictEqual(results[0].fatalErrorCount, 0);
4927 assert.strictEqual(results[0].fixableErrorCount, 0);
4928 assert.strictEqual(results[0].fixableWarningCount, 0);
56c4a2cb
DC
4929 });
4930
4931 it("should return source code of file in the `source` property", async () => {
4932 process.chdir(originalDir);
4933 const engine = new ESLint({
4934 useEslintrc: false,
4935 overrideConfig: {
4936 rules: { quotes: [2, "double"] }
4937 }
4938 });
4939 const results = await engine.lintText("var foo = 'bar';");
4940 const errorResults = ESLint.getErrorResults(results);
4941
4942 assert.strictEqual(errorResults[0].messages.length, 1);
4943 assert.strictEqual(errorResults[0].source, "var foo = 'bar';");
4944 });
4945
4946 it("should contain `output` property after fixes", async () => {
4947 process.chdir(originalDir);
4948 const engine = new ESLint({
4949 useEslintrc: false,
4950 fix: true,
4951 overrideConfig: {
4952 rules: {
4953 semi: 2,
4954 "no-console": 2
4955 }
4956 }
4957 });
4958 const results = await engine.lintText("console.log('foo')");
4959 const errorResults = ESLint.getErrorResults(results);
4960
4961 assert.strictEqual(errorResults[0].messages.length, 1);
4962 assert.strictEqual(errorResults[0].output, "console.log('foo');");
4963 });
4964 });
4965
609c276f
TL
4966 describe("getRulesMetaForResults()", () => {
4967 it("should return empty object when there are no linting errors", async () => {
4968 const engine = new ESLint({
4969 useEslintrc: false
4970 });
4971
4972 const rulesMeta = engine.getRulesMetaForResults([]);
4973
4974 assert.strictEqual(Object.keys(rulesMeta).length, 0);
4975 });
4976
4977 it("should return one rule meta when there is a linting error", async () => {
4978 const engine = new ESLint({
4979 useEslintrc: false,
4980 overrideConfig: {
4981 rules: {
4982 semi: 2
4983 }
4984 }
4985 });
4986
4987 const results = await engine.lintText("a");
4988 const rulesMeta = engine.getRulesMetaForResults(results);
4989
4990 assert.strictEqual(rulesMeta.semi, coreRules.get("semi").meta);
4991 });
4992
8f9d1d4d
DC
4993 it("should return one rule meta when there is a suppressed linting error", async () => {
4994 const engine = new ESLint({
4995 useEslintrc: false,
4996 overrideConfig: {
4997 rules: {
4998 semi: 2
4999 }
5000 }
5001 });
5002
5003 const results = await engine.lintText("a // eslint-disable-line semi");
5004 const rulesMeta = engine.getRulesMetaForResults(results);
5005
5006 assert.strictEqual(rulesMeta.semi, coreRules.get("semi").meta);
5007 });
5008
609c276f
TL
5009 it("should return multiple rule meta when there are multiple linting errors", async () => {
5010 const engine = new ESLint({
5011 useEslintrc: false,
5012 overrideConfig: {
5013 rules: {
5014 semi: 2,
5015 quotes: [2, "double"]
5016 }
5017 }
5018 });
5019
5020 const results = await engine.lintText("'a'");
5021 const rulesMeta = engine.getRulesMetaForResults(results);
5022
5023 assert.strictEqual(rulesMeta.semi, coreRules.get("semi").meta);
5024 assert.strictEqual(rulesMeta.quotes, coreRules.get("quotes").meta);
5025 });
5026
5027 it("should return multiple rule meta when there are multiple linting errors from a plugin", async () => {
8f9d1d4d 5028 const nodePlugin = require("eslint-plugin-n");
609c276f
TL
5029 const engine = new ESLint({
5030 useEslintrc: false,
5031 plugins: {
5032 node: nodePlugin
5033 },
5034 overrideConfig: {
8f9d1d4d 5035 plugins: ["n"],
609c276f 5036 rules: {
8f9d1d4d 5037 "n/no-new-require": 2,
609c276f
TL
5038 semi: 2,
5039 quotes: [2, "double"]
5040 }
5041 }
5042 });
5043
5044 const results = await engine.lintText("new require('hi')");
5045 const rulesMeta = engine.getRulesMetaForResults(results);
5046
5047 assert.strictEqual(rulesMeta.semi, coreRules.get("semi").meta);
5048 assert.strictEqual(rulesMeta.quotes, coreRules.get("quotes").meta);
5049 assert.strictEqual(
8f9d1d4d 5050 rulesMeta["n/no-new-require"],
609c276f
TL
5051 nodePlugin.rules["no-new-require"].meta
5052 );
5053 });
5054 });
5055
56c4a2cb
DC
5056 describe("outputFixes()", () => {
5057 afterEach(() => {
5058 sinon.verifyAndRestore();
5059 });
5060
5061 it("should call fs.writeFile() for each result with output", async () => {
6f036462
TL
5062 const fakeFS = {
5063 writeFile: sinon.spy(callLastArgument)
5064 };
5065 const spy = fakeFS.writeFile;
5066 const { ESLint: localESLint } = proxyquire("../../../lib/eslint/eslint", {
56c4a2cb 5067 fs: fakeFS
6f036462
TL
5068 });
5069
56c4a2cb
DC
5070 const results = [
5071 {
5072 filePath: path.resolve("foo.js"),
5073 output: "bar"
5074 },
5075 {
5076 filePath: path.resolve("bar.js"),
5077 output: "baz"
5078 }
5079 ];
5080
5081 await localESLint.outputFixes(results);
5082
5083 assert.strictEqual(spy.callCount, 2);
5084 assert(spy.firstCall.calledWithExactly(path.resolve("foo.js"), "bar", sinon.match.func), "First call was incorrect.");
5085 assert(spy.secondCall.calledWithExactly(path.resolve("bar.js"), "baz", sinon.match.func), "Second call was incorrect.");
5086 });
5087
5088 it("should call fs.writeFile() for each result with output and not at all for a result without output", async () => {
6f036462
TL
5089 const fakeFS = {
5090 writeFile: sinon.spy(callLastArgument)
5091 };
5092 const spy = fakeFS.writeFile;
5093 const { ESLint: localESLint } = proxyquire("../../../lib/eslint/eslint", {
56c4a2cb 5094 fs: fakeFS
6f036462 5095 });
56c4a2cb
DC
5096 const results = [
5097 {
5098 filePath: path.resolve("foo.js"),
5099 output: "bar"
5100 },
5101 {
5102 filePath: path.resolve("abc.js")
5103 },
5104 {
5105 filePath: path.resolve("bar.js"),
5106 output: "baz"
5107 }
5108 ];
5109
5110 await localESLint.outputFixes(results);
5111
5112 assert.strictEqual(spy.callCount, 2);
5113 assert(spy.firstCall.calledWithExactly(path.resolve("foo.js"), "bar", sinon.match.func), "First call was incorrect.");
5114 assert(spy.secondCall.calledWithExactly(path.resolve("bar.js"), "baz", sinon.match.func), "Second call was incorrect.");
5115 });
5116
5117 it("should throw if non object array is given to 'results' parameter", async () => {
5118 await assert.rejects(() => ESLint.outputFixes(null), /'results' must be an array/u);
5119 await assert.rejects(() => ESLint.outputFixes([null]), /'results' must include only objects/u);
5120 });
5121 });
5122
5123 describe("when evaluating code with comments to change config when allowInlineConfig is disabled", () => {
5124 it("should report a violation for disabling rules", async () => {
5125 const code = [
5126 "alert('test'); // eslint-disable-line no-alert"
5127 ].join("\n");
5128 const config = {
5129 ignore: true,
609c276f 5130 useEslintrc: false,
56c4a2cb
DC
5131 allowInlineConfig: false,
5132 overrideConfig: {
5133 env: { browser: true },
5134 rules: {
5135 "eol-last": 0,
5136 "no-alert": 1,
5137 "no-trailing-spaces": 0,
5138 strict: 0,
5139 quotes: 0
5140 }
5141 }
5142 };
5143 const eslintCLI = new ESLint(config);
5144 const results = await eslintCLI.lintText(code);
5145 const messages = results[0].messages;
5146
5147 assert.strictEqual(messages.length, 1);
5148 assert.strictEqual(messages[0].ruleId, "no-alert");
5149 });
5150
5151 it("should not report a violation by default", async () => {
5152 const code = [
5153 "alert('test'); // eslint-disable-line no-alert"
5154 ].join("\n");
5155 const config = {
5156 ignore: true,
609c276f 5157 useEslintrc: false,
56c4a2cb
DC
5158 allowInlineConfig: true,
5159 overrideConfig: {
5160 env: { browser: true },
5161 rules: {
5162 "eol-last": 0,
5163 "no-alert": 1,
5164 "no-trailing-spaces": 0,
5165 strict: 0,
5166 quotes: 0
5167 }
5168 }
5169 };
5170 const eslintCLI = new ESLint(config);
5171 const results = await eslintCLI.lintText(code);
5172 const messages = results[0].messages;
5173
5174 assert.strictEqual(messages.length, 0);
5175 });
5176 });
5177
5178 describe("when evaluating code when reportUnusedDisableDirectives is enabled", () => {
5179 it("should report problems for unused eslint-disable directives", async () => {
5180 const eslint = new ESLint({ useEslintrc: false, reportUnusedDisableDirectives: "error" });
5181
5182 assert.deepStrictEqual(
5183 await eslint.lintText("/* eslint-disable */"),
5184 [
5185 {
5186 filePath: "<text>",
5187 messages: [
5188 {
5189 ruleId: null,
5190 message: "Unused eslint-disable directive (no problems were reported).",
5191 line: 1,
5192 column: 1,
609c276f
TL
5193 fix: {
5194 range: [0, 20],
5195 text: " "
5196 },
56c4a2cb
DC
5197 severity: 2,
5198 nodeType: null
5199 }
5200 ],
8f9d1d4d 5201 suppressedMessages: [],
56c4a2cb
DC
5202 errorCount: 1,
5203 warningCount: 0,
609c276f
TL
5204 fatalErrorCount: 0,
5205 fixableErrorCount: 1,
56c4a2cb
DC
5206 fixableWarningCount: 0,
5207 source: "/* eslint-disable */",
5208 usedDeprecatedRules: []
5209 }
5210 ]
5211 );
5212 });
5213 });
5214
8f9d1d4d 5215 describe("when retrieving version number", () => {
56c4a2cb
DC
5216 it("should return current version number", () => {
5217 const eslintCLI = require("../../../lib/eslint").ESLint;
5218 const version = eslintCLI.version;
5219
5220 assert.strictEqual(typeof version, "string");
5221 assert(parseInt(version[0], 10) >= 3);
5222 });
5223 });
5224
5225 describe("mutability", () => {
5226 describe("plugins", () => {
5227 it("Loading plugin in one instance doesn't mutate to another instance", async () => {
5228 const filePath = getFixturePath("single-quoted.js");
5229 const engine1 = eslintWithPlugins({
5230 cwd: path.join(fixtureDir, ".."),
5231 useEslintrc: false,
5232 overrideConfig: {
5233 plugins: ["example"],
5234 rules: { "example/example-rule": 1 }
5235 }
5236 });
5237 const engine2 = new ESLint({
5238 cwd: path.join(fixtureDir, ".."),
5239 useEslintrc: false
5240 });
5241 const fileConfig1 = await engine1.calculateConfigForFile(filePath);
5242 const fileConfig2 = await engine2.calculateConfigForFile(filePath);
5243
5244 // plugin
5245 assert.deepStrictEqual(fileConfig1.plugins, ["example"], "Plugin is present for engine 1");
5246 assert.deepStrictEqual(fileConfig2.plugins, [], "Plugin is not present for engine 2");
5247 });
5248 });
5249
5250 describe("rules", () => {
5251 it("Loading rules in one instance doesn't mutate to another instance", async () => {
5252 const filePath = getFixturePath("single-quoted.js");
5253 const engine1 = new ESLint({
5254 cwd: path.join(fixtureDir, ".."),
5255 useEslintrc: false,
5256 overrideConfig: { rules: { "example/example-rule": 1 } }
5257 });
5258 const engine2 = new ESLint({
5259 cwd: path.join(fixtureDir, ".."),
5260 useEslintrc: false
5261 });
5262 const fileConfig1 = await engine1.calculateConfigForFile(filePath);
5263 const fileConfig2 = await engine2.calculateConfigForFile(filePath);
5264
5265 // plugin
5266 assert.deepStrictEqual(fileConfig1.rules["example/example-rule"], [1], "example is present for engine 1");
5267 assert.strictEqual(fileConfig2.rules["example/example-rule"], void 0, "example is not present for engine 2");
5268 });
5269 });
5270 });
5271
5272 describe("with ignorePatterns config", () => {
5273 const root = getFixturePath("cli-engine/ignore-patterns");
5274
56c4a2cb 5275 describe("ignorePatterns can add an ignore pattern ('foo.js').", () => {
6f036462
TL
5276 const { prepare, cleanup, getPath } = createCustomTeardown({
5277 cwd: root,
5278 files: {
5279 ".eslintrc.json": {
5280 ignorePatterns: "foo.js"
5281 },
5282 "foo.js": "",
5283 "bar.js": "",
5284 "subdir/foo.js": "",
5285 "subdir/bar.js": ""
5286 }
56c4a2cb
DC
5287 });
5288
6f036462
TL
5289 beforeEach(prepare);
5290 afterEach(cleanup);
5291
56c4a2cb 5292 it("'isPathIgnored()' should return 'true' for 'foo.js'.", async () => {
6f036462 5293 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5294
5295 assert.strictEqual(await engine.isPathIgnored("foo.js"), true);
5296 assert.strictEqual(await engine.isPathIgnored("subdir/foo.js"), true);
5297 });
5298
5299 it("'isPathIgnored()' should return 'false' for 'bar.js'.", async () => {
6f036462 5300 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5301
5302 assert.strictEqual(await engine.isPathIgnored("bar.js"), false);
5303 assert.strictEqual(await engine.isPathIgnored("subdir/bar.js"), false);
5304 });
5305
5306 it("'lintFiles()' should not verify 'foo.js'.", async () => {
6f036462 5307 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5308 const filePaths = (await engine.lintFiles("**/*.js"))
5309 .map(r => r.filePath)
5310 .sort();
5311
5312 assert.deepStrictEqual(filePaths, [
5313 path.join(root, "bar.js"),
5314 path.join(root, "subdir/bar.js")
5315 ]);
5316 });
5317 });
5318
5319 describe("ignorePatterns can add ignore patterns ('foo.js', '/bar.js').", () => {
6f036462
TL
5320 const { prepare, cleanup, getPath } = createCustomTeardown({
5321 cwd: root,
5322 files: {
5323 ".eslintrc.json": {
5324 ignorePatterns: ["foo.js", "/bar.js"]
5325 },
5326 "foo.js": "",
5327 "bar.js": "",
5328 "baz.js": "",
5329 "subdir/foo.js": "",
5330 "subdir/bar.js": "",
5331 "subdir/baz.js": ""
5332 }
56c4a2cb
DC
5333 });
5334
6f036462
TL
5335 beforeEach(prepare);
5336 afterEach(cleanup);
5337
56c4a2cb 5338 it("'isPathIgnored()' should return 'true' for 'foo.js'.", async () => {
6f036462 5339 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5340
5341 assert.strictEqual(await engine.isPathIgnored("foo.js"), true);
5342 assert.strictEqual(await engine.isPathIgnored("subdir/foo.js"), true);
5343 });
5344
5345 it("'isPathIgnored()' should return 'true' for '/bar.js'.", async () => {
6f036462 5346 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5347
5348 assert.strictEqual(await engine.isPathIgnored("bar.js"), true);
5349 assert.strictEqual(await engine.isPathIgnored("subdir/bar.js"), false);
5350 });
5351
5352 it("'lintFiles()' should not verify 'foo.js' and '/bar.js'.", async () => {
6f036462 5353 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5354 const filePaths = (await engine.lintFiles("**/*.js"))
5355 .map(r => r.filePath)
5356 .sort();
5357
5358 assert.deepStrictEqual(filePaths, [
5359 path.join(root, "baz.js"),
5360 path.join(root, "subdir/bar.js"),
5361 path.join(root, "subdir/baz.js")
5362 ]);
5363 });
5364 });
5365
5366 describe("ignorePatterns can unignore '/node_modules/foo'.", () => {
6f036462
TL
5367
5368 const { prepare, cleanup, getPath } = createCustomTeardown({
5369 cwd: root,
5370 files: {
5371 ".eslintrc.json": {
5372 ignorePatterns: "!/node_modules/foo"
5373 },
5374 "node_modules/foo/index.js": "",
5375 "node_modules/foo/.dot.js": "",
5376 "node_modules/bar/index.js": "",
5377 "foo.js": ""
5378 }
56c4a2cb
DC
5379 });
5380
6f036462
TL
5381 beforeEach(prepare);
5382 afterEach(cleanup);
5383
56c4a2cb 5384 it("'isPathIgnored()' should return 'false' for 'node_modules/foo/index.js'.", async () => {
6f036462 5385 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5386
5387 assert.strictEqual(await engine.isPathIgnored("node_modules/foo/index.js"), false);
5388 });
5389
5390 it("'isPathIgnored()' should return 'true' for 'node_modules/foo/.dot.js'.", async () => {
6f036462 5391 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5392
5393 assert.strictEqual(await engine.isPathIgnored("node_modules/foo/.dot.js"), true);
5394 });
5395
5396 it("'isPathIgnored()' should return 'true' for 'node_modules/bar/index.js'.", async () => {
6f036462 5397 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5398
5399 assert.strictEqual(await engine.isPathIgnored("node_modules/bar/index.js"), true);
5400 });
5401
5402 it("'lintFiles()' should verify 'node_modules/foo/index.js'.", async () => {
6f036462 5403 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5404 const filePaths = (await engine.lintFiles("**/*.js"))
5405 .map(r => r.filePath)
5406 .sort();
5407
5408 assert.deepStrictEqual(filePaths, [
5409 path.join(root, "foo.js"),
5410 path.join(root, "node_modules/foo/index.js")
5411 ]);
5412 });
5413 });
5414
5415 describe("ignorePatterns can unignore '.eslintrc.js'.", () => {
6f036462
TL
5416
5417 const { prepare, cleanup, getPath } = createCustomTeardown({
5418 cwd: root,
5419 files: {
5420 ".eslintrc.js": `module.exports = ${JSON.stringify({
5421 ignorePatterns: "!.eslintrc.js"
5422 })}`,
5423 "foo.js": ""
5424 }
56c4a2cb
DC
5425 });
5426
6f036462
TL
5427 beforeEach(prepare);
5428 afterEach(cleanup);
5429
56c4a2cb 5430 it("'isPathIgnored()' should return 'false' for '.eslintrc.js'.", async () => {
6f036462 5431 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5432
5433 assert.strictEqual(await engine.isPathIgnored(".eslintrc.js"), false);
5434 });
5435
5436 it("'lintFiles()' should verify '.eslintrc.js'.", async () => {
6f036462 5437 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5438 const filePaths = (await engine.lintFiles("**/*.js"))
5439 .map(r => r.filePath)
5440 .sort();
5441
5442 assert.deepStrictEqual(filePaths, [
5443 path.join(root, ".eslintrc.js"),
5444 path.join(root, "foo.js")
5445 ]);
5446 });
5447 });
5448
5449 describe(".eslintignore can re-ignore files that are unignored by ignorePatterns.", () => {
6f036462
TL
5450 const { prepare, cleanup, getPath } = createCustomTeardown({
5451 cwd: root,
5452 files: {
5453 ".eslintrc.js": `module.exports = ${JSON.stringify({
5454 ignorePatterns: "!.*"
5455 })}`,
5456 ".eslintignore": ".foo*",
5457 ".foo.js": "",
5458 ".bar.js": ""
5459 }
56c4a2cb
DC
5460 });
5461
6f036462
TL
5462 beforeEach(prepare);
5463 afterEach(cleanup);
5464
56c4a2cb 5465 it("'isPathIgnored()' should return 'true' for re-ignored '.foo.js'.", async () => {
6f036462 5466 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5467
5468 assert.strictEqual(await engine.isPathIgnored(".foo.js"), true);
5469 });
5470
5471 it("'isPathIgnored()' should return 'false' for unignored '.bar.js'.", async () => {
6f036462 5472 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5473
5474 assert.strictEqual(await engine.isPathIgnored(".bar.js"), false);
5475 });
5476
5477 it("'lintFiles()' should not verify re-ignored '.foo.js'.", async () => {
6f036462 5478 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5479 const filePaths = (await engine.lintFiles("**/*.js"))
5480 .map(r => r.filePath)
5481 .sort();
5482
5483 assert.deepStrictEqual(filePaths, [
5484 path.join(root, ".bar.js"),
5485 path.join(root, ".eslintrc.js")
5486 ]);
5487 });
5488 });
5489
5490 describe(".eslintignore can unignore files that are ignored by ignorePatterns.", () => {
6f036462
TL
5491 const { prepare, cleanup, getPath } = createCustomTeardown({
5492 cwd: root,
5493 files: {
5494 ".eslintrc.js": `module.exports = ${JSON.stringify({
5495 ignorePatterns: "*.js"
5496 })}`,
5497 ".eslintignore": "!foo.js",
5498 "foo.js": "",
5499 "bar.js": ""
5500 }
56c4a2cb
DC
5501 });
5502
6f036462
TL
5503 beforeEach(prepare);
5504 afterEach(cleanup);
5505
56c4a2cb 5506 it("'isPathIgnored()' should return 'false' for unignored 'foo.js'.", async () => {
6f036462 5507 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5508
5509 assert.strictEqual(await engine.isPathIgnored("foo.js"), false);
5510 });
5511
5512 it("'isPathIgnored()' should return 'true' for ignored 'bar.js'.", async () => {
6f036462 5513 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5514
5515 assert.strictEqual(await engine.isPathIgnored("bar.js"), true);
5516 });
5517
5518 it("'lintFiles()' should verify unignored 'foo.js'.", async () => {
6f036462 5519 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5520 const filePaths = (await engine.lintFiles("**/*.js"))
5521 .map(r => r.filePath)
5522 .sort();
5523
5524 assert.deepStrictEqual(filePaths, [
5525 path.join(root, "foo.js")
5526 ]);
5527 });
5528 });
5529
5530 describe("ignorePatterns in the config file in a child directory affects to only in the directory.", () => {
6f036462
TL
5531 const { prepare, cleanup, getPath } = createCustomTeardown({
5532 cwd: root,
5533 files: {
5534 ".eslintrc.json": JSON.stringify({
5535 ignorePatterns: "foo.js"
5536 }),
5537 "subdir/.eslintrc.json": JSON.stringify({
5538 ignorePatterns: "bar.js"
5539 }),
5540 "foo.js": "",
5541 "bar.js": "",
5542 "subdir/foo.js": "",
5543 "subdir/bar.js": "",
5544 "subdir/subsubdir/foo.js": "",
5545 "subdir/subsubdir/bar.js": ""
5546 }
56c4a2cb
DC
5547 });
5548
6f036462
TL
5549
5550 beforeEach(prepare);
5551 afterEach(cleanup);
5552
56c4a2cb 5553 it("'isPathIgnored()' should return 'true' for 'foo.js'.", async () => {
6f036462 5554 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5555
5556 assert.strictEqual(await engine.isPathIgnored("foo.js"), true);
5557 assert.strictEqual(await engine.isPathIgnored("subdir/foo.js"), true);
5558 assert.strictEqual(await engine.isPathIgnored("subdir/subsubdir/foo.js"), true);
5559 });
5560
5561 it("'isPathIgnored()' should return 'true' for 'bar.js' in 'subdir'.", async () => {
6f036462 5562 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5563
5564 assert.strictEqual(await engine.isPathIgnored("subdir/bar.js"), true);
5565 assert.strictEqual(await engine.isPathIgnored("subdir/subsubdir/bar.js"), true);
5566 });
5567
5568 it("'isPathIgnored()' should return 'false' for 'bar.js' in the outside of 'subdir'.", async () => {
6f036462 5569 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5570
5571 assert.strictEqual(await engine.isPathIgnored("bar.js"), false);
5572 });
5573
5574 it("'lintFiles()' should verify 'bar.js' in the outside of 'subdir'.", async () => {
6f036462 5575 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5576 const filePaths = (await engine.lintFiles("**/*.js"))
5577 .map(r => r.filePath)
5578 .sort();
5579
5580 assert.deepStrictEqual(filePaths, [
5581 path.join(root, "bar.js")
5582 ]);
5583 });
5584 });
5585
5586 describe("ignorePatterns in the config file in a child directory can unignore the ignored files in the parent directory's config.", () => {
6f036462
TL
5587 const { prepare, cleanup, getPath } = createCustomTeardown({
5588 cwd: root,
5589 files: {
5590 ".eslintrc.json": JSON.stringify({
5591 ignorePatterns: "foo.js"
5592 }),
5593 "subdir/.eslintrc.json": JSON.stringify({
5594 ignorePatterns: "!foo.js"
5595 }),
5596 "foo.js": "",
5597 "subdir/foo.js": ""
5598 }
56c4a2cb
DC
5599 });
5600
6f036462
TL
5601 beforeEach(prepare);
5602 afterEach(cleanup);
5603
56c4a2cb 5604 it("'isPathIgnored()' should return 'true' for 'foo.js' in the root directory.", async () => {
6f036462 5605 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5606
5607 assert.strictEqual(await engine.isPathIgnored("foo.js"), true);
5608 });
5609
5610 it("'isPathIgnored()' should return 'false' for 'foo.js' in the child directory.", async () => {
6f036462 5611 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5612
5613 assert.strictEqual(await engine.isPathIgnored("subdir/foo.js"), false);
5614 });
5615
5616 it("'lintFiles()' should verify 'foo.js' in the child directory.", async () => {
6f036462 5617 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5618 const filePaths = (await engine.lintFiles("**/*.js"))
5619 .map(r => r.filePath)
5620 .sort();
5621
5622 assert.deepStrictEqual(filePaths, [
5623 path.join(root, "subdir/foo.js")
5624 ]);
5625 });
5626 });
5627
5628 describe(".eslintignore can unignore files that are ignored by ignorePatterns in the config file in the child directory.", () => {
6f036462
TL
5629 const { prepare, cleanup, getPath } = createCustomTeardown({
5630 cwd: root,
5631 files: {
5632 ".eslintrc.json": JSON.stringify({}),
5633 "subdir/.eslintrc.json": JSON.stringify({
5634 ignorePatterns: "*.js"
5635 }),
5636 ".eslintignore": "!foo.js",
5637 "foo.js": "",
5638 "subdir/foo.js": "",
5639 "subdir/bar.js": ""
5640 }
56c4a2cb
DC
5641 });
5642
6f036462
TL
5643 beforeEach(prepare);
5644 afterEach(cleanup);
5645
56c4a2cb 5646 it("'isPathIgnored()' should return 'false' for unignored 'foo.js'.", async () => {
6f036462 5647 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5648
5649 assert.strictEqual(await engine.isPathIgnored("foo.js"), false);
5650 assert.strictEqual(await engine.isPathIgnored("subdir/foo.js"), false);
5651 });
5652
5653 it("'isPathIgnored()' should return 'true' for ignored 'bar.js'.", async () => {
6f036462 5654 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5655
5656 assert.strictEqual(await engine.isPathIgnored("subdir/bar.js"), true);
5657 });
5658
5659 it("'lintFiles()' should verify unignored 'foo.js'.", async () => {
6f036462 5660 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5661 const filePaths = (await engine.lintFiles("**/*.js"))
5662 .map(r => r.filePath)
5663 .sort();
5664
5665 assert.deepStrictEqual(filePaths, [
5666 path.join(root, "foo.js"),
5667 path.join(root, "subdir/foo.js")
5668 ]);
5669 });
5670 });
5671
5672 describe("if the config in a child directory has 'root:true', ignorePatterns in the config file in the parent directory should not be used.", () => {
6f036462
TL
5673 const { prepare, cleanup, getPath } = createCustomTeardown({
5674 cwd: root,
5675 files: {
5676 ".eslintrc.json": JSON.stringify({
5677 ignorePatterns: "foo.js"
5678 }),
5679 "subdir/.eslintrc.json": JSON.stringify({
5680 root: true,
5681 ignorePatterns: "bar.js"
5682 }),
5683 "foo.js": "",
5684 "bar.js": "",
5685 "subdir/foo.js": "",
5686 "subdir/bar.js": ""
5687 }
56c4a2cb
DC
5688 });
5689
6f036462
TL
5690 beforeEach(prepare);
5691 afterEach(cleanup);
5692
56c4a2cb 5693 it("'isPathIgnored()' should return 'true' for 'foo.js' in the root directory.", async () => {
6f036462 5694 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5695
5696 assert.strictEqual(await engine.isPathIgnored("foo.js"), true);
5697 });
5698
5699 it("'isPathIgnored()' should return 'false' for 'bar.js' in the root directory.", async () => {
6f036462 5700 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5701
5702 assert.strictEqual(await engine.isPathIgnored("bar.js"), false);
5703 });
5704
5705 it("'isPathIgnored()' should return 'false' for 'foo.js' in the child directory.", async () => {
6f036462 5706 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5707
5708 assert.strictEqual(await engine.isPathIgnored("subdir/foo.js"), false);
5709 });
5710
5711 it("'isPathIgnored()' should return 'true' for 'bar.js' in the child directory.", async () => {
6f036462 5712 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5713
5714 assert.strictEqual(await engine.isPathIgnored("subdir/bar.js"), true);
5715 });
5716
5717 it("'lintFiles()' should verify 'bar.js' in the root directory and 'foo.js' in the child directory.", async () => {
6f036462 5718 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5719 const filePaths = (await engine.lintFiles("**/*.js"))
5720 .map(r => r.filePath)
5721 .sort();
5722
5723 assert.deepStrictEqual(filePaths, [
5724 path.join(root, "bar.js"),
5725 path.join(root, "subdir/foo.js")
5726 ]);
5727 });
5728 });
5729
5730 describe("even if the config in a child directory has 'root:true', .eslintignore should be used.", () => {
6f036462
TL
5731 const { prepare, cleanup, getPath } = createCustomTeardown({
5732 cwd: root,
5733 files: {
5734 ".eslintrc.json": JSON.stringify({}),
5735 "subdir/.eslintrc.json": JSON.stringify({
5736 root: true,
5737 ignorePatterns: "bar.js"
5738 }),
5739 ".eslintignore": "foo.js",
5740 "foo.js": "",
5741 "bar.js": "",
5742 "subdir/foo.js": "",
5743 "subdir/bar.js": ""
5744 }
56c4a2cb
DC
5745 });
5746
6f036462
TL
5747 beforeEach(prepare);
5748 afterEach(cleanup);
5749
56c4a2cb 5750 it("'isPathIgnored()' should return 'true' for 'foo.js'.", async () => {
6f036462 5751 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5752
5753 assert.strictEqual(await engine.isPathIgnored("foo.js"), true);
5754 assert.strictEqual(await engine.isPathIgnored("subdir/foo.js"), true);
5755 });
5756
5757 it("'isPathIgnored()' should return 'false' for 'bar.js' in the root directory.", async () => {
6f036462 5758 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5759
5760 assert.strictEqual(await engine.isPathIgnored("bar.js"), false);
5761 });
5762
5763 it("'isPathIgnored()' should return 'true' for 'bar.js' in the child directory.", async () => {
6f036462 5764 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5765
5766 assert.strictEqual(await engine.isPathIgnored("subdir/bar.js"), true);
5767 });
5768
5769 it("'lintFiles()' should verify 'bar.js' in the root directory.", async () => {
6f036462 5770 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5771 const filePaths = (await engine.lintFiles("**/*.js"))
5772 .map(r => r.filePath)
5773 .sort();
5774
5775 assert.deepStrictEqual(filePaths, [
5776 path.join(root, "bar.js")
5777 ]);
5778 });
5779 });
5780
5781 describe("ignorePatterns in the shareable config should be used.", () => {
6f036462
TL
5782 const { prepare, cleanup, getPath } = createCustomTeardown({
5783 cwd: root,
5784 files: {
5785 "node_modules/eslint-config-one/index.js": `module.exports = ${JSON.stringify({
5786 ignorePatterns: "foo.js"
5787 })}`,
5788 ".eslintrc.json": JSON.stringify({
5789 extends: "one"
5790 }),
5791 "foo.js": "",
5792 "bar.js": ""
5793 }
56c4a2cb
DC
5794 });
5795
6f036462
TL
5796 beforeEach(prepare);
5797 afterEach(cleanup);
5798
56c4a2cb 5799 it("'isPathIgnored()' should return 'true' for 'foo.js'.", async () => {
6f036462 5800 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5801
5802 assert.strictEqual(await engine.isPathIgnored("foo.js"), true);
5803 });
5804
5805 it("'isPathIgnored()' should return 'false' for 'bar.js'.", async () => {
6f036462 5806 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5807
5808 assert.strictEqual(await engine.isPathIgnored("bar.js"), false);
5809 });
5810
5811 it("'lintFiles()' should verify 'bar.js'.", async () => {
6f036462 5812 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5813 const filePaths = (await engine.lintFiles("**/*.js"))
5814 .map(r => r.filePath)
5815 .sort();
5816
5817 assert.deepStrictEqual(filePaths, [
5818 path.join(root, "bar.js")
5819 ]);
5820 });
5821 });
5822
5823 describe("ignorePatterns in the shareable config should be relative to the entry config file.", () => {
6f036462
TL
5824
5825 const { prepare, cleanup, getPath } = createCustomTeardown({
5826 cwd: root,
5827 files: {
5828 "node_modules/eslint-config-one/index.js": `module.exports = ${JSON.stringify({
5829 ignorePatterns: "/foo.js"
5830 })}`,
5831 ".eslintrc.json": JSON.stringify({
5832 extends: "one"
5833 }),
5834 "foo.js": "",
5835 "subdir/foo.js": ""
5836 }
56c4a2cb
DC
5837 });
5838
6f036462
TL
5839 beforeEach(prepare);
5840 afterEach(cleanup);
5841
56c4a2cb 5842 it("'isPathIgnored()' should return 'true' for 'foo.js'.", async () => {
6f036462 5843 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5844
5845 assert.strictEqual(await engine.isPathIgnored("foo.js"), true);
5846 });
5847
5848 it("'isPathIgnored()' should return 'false' for 'subdir/foo.js'.", async () => {
6f036462 5849 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5850
5851 assert.strictEqual(await engine.isPathIgnored("subdir/foo.js"), false);
5852 });
5853
5854 it("'lintFiles()' should verify 'subdir/foo.js'.", async () => {
6f036462 5855 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5856 const filePaths = (await engine.lintFiles("**/*.js"))
5857 .map(r => r.filePath)
5858 .sort();
5859
5860 assert.deepStrictEqual(filePaths, [
5861 path.join(root, "subdir/foo.js")
5862 ]);
5863 });
5864 });
5865
5866 describe("ignorePatterns in a config file can unignore the files which are ignored by ignorePatterns in the shareable config.", () => {
6f036462
TL
5867 const { prepare, cleanup, getPath } = createCustomTeardown({
5868 cwd: root,
5869 files: {
5870 "node_modules/eslint-config-one/index.js": `module.exports = ${JSON.stringify({
5871 ignorePatterns: "*.js"
5872 })}`,
5873 ".eslintrc.json": JSON.stringify({
5874 extends: "one",
5875 ignorePatterns: "!bar.js"
5876 }),
5877 "foo.js": "",
5878 "bar.js": ""
5879 }
56c4a2cb
DC
5880 });
5881
6f036462
TL
5882 beforeEach(prepare);
5883 afterEach(cleanup);
5884
56c4a2cb 5885 it("'isPathIgnored()' should return 'true' for 'foo.js'.", async () => {
6f036462 5886 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5887
5888 assert.strictEqual(await engine.isPathIgnored("foo.js"), true);
5889 });
5890
5891 it("'isPathIgnored()' should return 'false' for 'bar.js'.", async () => {
6f036462 5892 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5893
5894 assert.strictEqual(await engine.isPathIgnored("bar.js"), false);
5895 });
5896
5897 it("'lintFiles()' should verify 'bar.js'.", async () => {
6f036462 5898 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5899 const filePaths = (await engine.lintFiles("**/*.js"))
5900 .map(r => r.filePath)
5901 .sort();
5902
5903 assert.deepStrictEqual(filePaths, [
5904 path.join(root, "bar.js")
5905 ]);
5906 });
5907 });
5908
5909 describe("ignorePatterns in a config file should not be used if --no-ignore option was given.", () => {
6f036462
TL
5910
5911 const { prepare, cleanup, getPath } = createCustomTeardown({
5912 cwd: root,
5913 files: {
5914 ".eslintrc.json": JSON.stringify({
5915 ignorePatterns: "*.js"
5916 }),
5917 "foo.js": ""
5918 }
56c4a2cb
DC
5919 });
5920
6f036462
TL
5921 beforeEach(prepare);
5922 afterEach(cleanup);
5923
56c4a2cb 5924 it("'isPathIgnored()' should return 'false' for 'foo.js'.", async () => {
6f036462 5925 const engine = new ESLint({ cwd: getPath(), ignore: false });
56c4a2cb
DC
5926
5927 assert.strictEqual(await engine.isPathIgnored("foo.js"), false);
5928 });
5929
5930 it("'lintFiles()' should verify 'foo.js'.", async () => {
6f036462 5931 const engine = new ESLint({ cwd: getPath(), ignore: false });
56c4a2cb
DC
5932 const filePaths = (await engine.lintFiles("**/*.js"))
5933 .map(r => r.filePath)
5934 .sort();
5935
5936 assert.deepStrictEqual(filePaths, [
5937 path.join(root, "foo.js")
5938 ]);
5939 });
5940 });
5941
5942 describe("ignorePatterns in overrides section is not allowed.", () => {
6f036462
TL
5943
5944 const { prepare, cleanup, getPath } = createCustomTeardown({
5945 cwd: root,
5946 files: {
5947 ".eslintrc.js": `module.exports = ${JSON.stringify({
5948 overrides: [
5949 {
5950 files: "*.js",
5951 ignorePatterns: "foo.js"
5952 }
5953 ]
5954 })}`,
5955 "foo.js": ""
5956 }
56c4a2cb
DC
5957 });
5958
6f036462
TL
5959 beforeEach(prepare);
5960 afterEach(cleanup);
5961
56c4a2cb
DC
5962 it("should throw a configuration error.", async () => {
5963 await assert.rejects(async () => {
6f036462 5964 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
5965
5966 await engine.lintFiles("*.js");
5967 }, /Unexpected top-level property "overrides\[0\]\.ignorePatterns"/u);
5968 });
5969 });
5970 });
5971
5972 describe("'overrides[].files' adds lint targets", () => {
5973 const root = getFixturePath("cli-engine/additional-lint-targets");
6f036462 5974
56c4a2cb
DC
5975
5976 describe("if { files: 'foo/*.txt', excludedFiles: '**/ignore.txt' } is present,", () => {
6f036462
TL
5977 const { prepare, cleanup, getPath } = createCustomTeardown({
5978 cwd: root,
5979 files: {
5980 ".eslintrc.json": JSON.stringify({
5981 overrides: [
5982 {
5983 files: "foo/*.txt",
5984 excludedFiles: "**/ignore.txt"
5985 }
5986 ]
5987 }),
5988 "foo/nested/test.txt": "",
5989 "foo/test.js": "",
5990 "foo/test.txt": "",
5991 "foo/ignore.txt": "",
5992 "bar/test.js": "",
5993 "bar/test.txt": "",
5994 "bar/ignore.txt": "",
5995 "test.js": "",
5996 "test.txt": "",
5997 "ignore.txt": ""
5998 }
56c4a2cb
DC
5999 });
6000
6f036462
TL
6001 beforeEach(prepare);
6002 afterEach(cleanup);
6003
56c4a2cb 6004 it("'lintFiles()' with a directory path should contain 'foo/test.txt'.", async () => {
6f036462 6005 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
6006 const filePaths = (await engine.lintFiles("."))
6007 .map(r => r.filePath)
6008 .sort();
6009
6010 assert.deepStrictEqual(filePaths, [
6011 path.join(root, "bar/test.js"),
6012 path.join(root, "foo/test.js"),
6013 path.join(root, "foo/test.txt"),
6014 path.join(root, "test.js")
6015 ]);
6016 });
6017
6018 it("'lintFiles()' with a glob pattern '*.js' should not contain 'foo/test.txt'.", async () => {
6f036462 6019 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
6020 const filePaths = (await engine.lintFiles("**/*.js"))
6021 .map(r => r.filePath)
6022 .sort();
6023
6024 assert.deepStrictEqual(filePaths, [
6025 path.join(root, "bar/test.js"),
6026 path.join(root, "foo/test.js"),
6027 path.join(root, "test.js")
6028 ]);
6029 });
6030 });
6031
6032 describe("if { files: 'foo/**/*.txt' } is present,", () => {
6f036462
TL
6033
6034 const { prepare, cleanup, getPath } = createCustomTeardown({
6035 cwd: root,
6036 files: {
6037 ".eslintrc.json": JSON.stringify({
6038 overrides: [
6039 {
6040 files: "foo/**/*.txt"
6041 }
6042 ]
6043 }),
6044 "foo/nested/test.txt": "",
6045 "foo/test.js": "",
6046 "foo/test.txt": "",
6047 "bar/test.js": "",
6048 "bar/test.txt": "",
6049 "test.js": "",
6050 "test.txt": ""
6051 }
56c4a2cb
DC
6052 });
6053
6f036462
TL
6054 beforeEach(prepare);
6055 afterEach(cleanup);
6056
56c4a2cb 6057 it("'lintFiles()' with a directory path should contain 'foo/test.txt' and 'foo/nested/test.txt'.", async () => {
6f036462 6058 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
6059 const filePaths = (await engine.lintFiles("."))
6060 .map(r => r.filePath)
6061 .sort();
6062
6063 assert.deepStrictEqual(filePaths, [
6064 path.join(root, "bar/test.js"),
6065 path.join(root, "foo/nested/test.txt"),
6066 path.join(root, "foo/test.js"),
6067 path.join(root, "foo/test.txt"),
6068 path.join(root, "test.js")
6069 ]);
6070 });
6071 });
6072
6073 describe("if { files: 'foo/**/*' } is present,", () => {
6f036462
TL
6074
6075 const { prepare, cleanup, getPath } = createCustomTeardown({
6076 cwd: root,
6077 files: {
6078 ".eslintrc.json": JSON.stringify({
6079 overrides: [
6080 {
6081 files: "foo/**/*"
6082 }
6083 ]
6084 }),
6085 "foo/nested/test.txt": "",
6086 "foo/test.js": "",
6087 "foo/test.txt": "",
6088 "bar/test.js": "",
6089 "bar/test.txt": "",
6090 "test.js": "",
6091 "test.txt": ""
6092 }
56c4a2cb
DC
6093 });
6094
6f036462
TL
6095 beforeEach(prepare);
6096 afterEach(cleanup);
6097
56c4a2cb 6098 it("'lintFiles()' with a directory path should NOT contain 'foo/test.txt' and 'foo/nested/test.txt'.", async () => {
6f036462 6099 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
6100 const filePaths = (await engine.lintFiles("."))
6101 .map(r => r.filePath)
6102 .sort();
6103
6104 assert.deepStrictEqual(filePaths, [
6105 path.join(root, "bar/test.js"),
6106 path.join(root, "foo/test.js"),
6107 path.join(root, "test.js")
6108 ]);
6109 });
6110 });
6111
6112 describe("if { files: 'foo/**/*.txt' } is present in a shareable config,", () => {
6f036462
TL
6113
6114 const { prepare, cleanup, getPath } = createCustomTeardown({
6115 cwd: root,
6116 files: {
6117 "node_modules/eslint-config-foo/index.js": `module.exports = ${JSON.stringify({
6118 overrides: [
6119 {
6120 files: "foo/**/*.txt"
6121 }
6122 ]
6123 })}`,
6124 ".eslintrc.json": JSON.stringify({
6125 extends: "foo"
6126 }),
6127 "foo/nested/test.txt": "",
6128 "foo/test.js": "",
6129 "foo/test.txt": "",
6130 "bar/test.js": "",
6131 "bar/test.txt": "",
6132 "test.js": "",
6133 "test.txt": ""
6134 }
56c4a2cb
DC
6135 });
6136
6f036462
TL
6137 beforeEach(prepare);
6138 afterEach(cleanup);
6139
56c4a2cb 6140 it("'lintFiles()' with a directory path should contain 'foo/test.txt' and 'foo/nested/test.txt'.", async () => {
6f036462 6141 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
6142 const filePaths = (await engine.lintFiles("."))
6143 .map(r => r.filePath)
6144 .sort();
6145
6146 assert.deepStrictEqual(filePaths, [
6147 path.join(root, "bar/test.js"),
6148 path.join(root, "foo/nested/test.txt"),
6149 path.join(root, "foo/test.js"),
6150 path.join(root, "foo/test.txt"),
6151 path.join(root, "test.js")
6152 ]);
6153 });
6154 });
6155
6156 describe("if { files: 'foo/**/*.txt' } is present in a plugin config,", () => {
6f036462
TL
6157
6158 const { prepare, cleanup, getPath } = createCustomTeardown({
6159 cwd: root,
6160 files: {
6161 "node_modules/eslint-plugin-foo/index.js": `exports.configs = ${JSON.stringify({
6162 bar: {
6163 overrides: [
6164 {
6165 files: "foo/**/*.txt"
6166 }
6167 ]
6168 }
6169 })}`,
6170 ".eslintrc.json": JSON.stringify({
6171 extends: "plugin:foo/bar"
6172 }),
6173 "foo/nested/test.txt": "",
6174 "foo/test.js": "",
6175 "foo/test.txt": "",
6176 "bar/test.js": "",
6177 "bar/test.txt": "",
6178 "test.js": "",
6179 "test.txt": ""
6180 }
56c4a2cb
DC
6181 });
6182
6f036462
TL
6183 beforeEach(prepare);
6184 afterEach(cleanup);
6185
56c4a2cb 6186 it("'lintFiles()' with a directory path should contain 'foo/test.txt' and 'foo/nested/test.txt'.", async () => {
6f036462 6187 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
6188 const filePaths = (await engine.lintFiles("."))
6189 .map(r => r.filePath)
6190 .sort();
6191
6192 assert.deepStrictEqual(filePaths, [
6193 path.join(root, "bar/test.js"),
6194 path.join(root, "foo/nested/test.txt"),
6195 path.join(root, "foo/test.js"),
6196 path.join(root, "foo/test.txt"),
6197 path.join(root, "test.js")
6198 ]);
6199 });
6200 });
6201 });
6202
6203 describe("'ignorePatterns', 'overrides[].files', and 'overrides[].excludedFiles' of the configuration that the '--config' option provided should be resolved from CWD.", () => {
6204 const root = getFixturePath("cli-engine/config-and-overrides-files");
6205
56c4a2cb 6206 describe("if { files: 'foo/*.txt', ... } is present by '--config node_modules/myconf/.eslintrc.json',", () => {
6f036462
TL
6207 const { prepare, cleanup, getPath } = createCustomTeardown({
6208 cwd: root,
6209 files: {
6210 "node_modules/myconf/.eslintrc.json": {
6211 overrides: [
6212 {
6213 files: "foo/*.js",
6214 rules: {
6215 eqeqeq: "error"
56c4a2cb 6216 }
6f036462
TL
6217 }
6218 ]
6219 },
6220 "node_modules/myconf/foo/test.js": "a == b",
6221 "foo/test.js": "a == b"
6222 }
56c4a2cb
DC
6223 });
6224
6f036462
TL
6225 beforeEach(prepare);
6226 afterEach(cleanup);
6227
56c4a2cb 6228 it("'lintFiles()' with 'foo/test.js' should use the override entry.", async () => {
6f036462 6229 const engine = new ESLint({
56c4a2cb 6230 overrideConfigFile: "node_modules/myconf/.eslintrc.json",
6f036462 6231 cwd: getPath(),
56c4a2cb
DC
6232 ignore: false,
6233 useEslintrc: false
6234 });
6235 const results = await engine.lintFiles("foo/test.js");
6236
6237 // Expected to be an 'eqeqeq' error because the file matches to `$CWD/foo/*.js`.
6238 assert.deepStrictEqual(results, [
6239 {
6240 errorCount: 1,
6f036462 6241 filePath: path.join(getPath(), "foo/test.js"),
56c4a2cb
DC
6242 fixableErrorCount: 0,
6243 fixableWarningCount: 0,
6244 messages: [
6245 {
6246 column: 3,
6247 endColumn: 5,
6248 endLine: 1,
6249 line: 1,
6250 message: "Expected '===' and instead saw '=='.",
6251 messageId: "unexpected",
6252 nodeType: "BinaryExpression",
6253 ruleId: "eqeqeq",
6254 severity: 2
6255 }
6256 ],
8f9d1d4d 6257 suppressedMessages: [],
56c4a2cb
DC
6258 source: "a == b",
6259 usedDeprecatedRules: [],
609c276f
TL
6260 warningCount: 0,
6261 fatalErrorCount: 0
56c4a2cb
DC
6262 }
6263 ]);
6264 });
6265
6266 it("'lintFiles()' with 'node_modules/myconf/foo/test.js' should NOT use the override entry.", async () => {
6f036462 6267 const engine = new ESLint({
56c4a2cb
DC
6268 overrideConfigFile: "node_modules/myconf/.eslintrc.json",
6269 cwd: root,
6270 ignore: false,
6271 useEslintrc: false
6272 });
6273 const results = await engine.lintFiles("node_modules/myconf/foo/test.js");
6274
6275 // Expected to be no errors because the file doesn't match to `$CWD/foo/*.js`.
6276 assert.deepStrictEqual(results, [
6277 {
6278 errorCount: 0,
6f036462 6279 filePath: path.join(getPath(), "node_modules/myconf/foo/test.js"),
56c4a2cb
DC
6280 fixableErrorCount: 0,
6281 fixableWarningCount: 0,
6282 messages: [],
8f9d1d4d 6283 suppressedMessages: [],
56c4a2cb 6284 usedDeprecatedRules: [],
609c276f
TL
6285 warningCount: 0,
6286 fatalErrorCount: 0
56c4a2cb
DC
6287 }
6288 ]);
6289 });
6290 });
6291
6292 describe("if { files: '*', excludedFiles: 'foo/*.txt', ... } is present by '--config node_modules/myconf/.eslintrc.json',", () => {
6f036462
TL
6293 const { prepare, cleanup, getPath } = createCustomTeardown({
6294 cwd: root,
6295 files: {
6296 "node_modules/myconf/.eslintrc.json": JSON.stringify({
6297 overrides: [
6298 {
6299 files: "*",
6300 excludedFiles: "foo/*.js",
6301 rules: {
6302 eqeqeq: "error"
56c4a2cb 6303 }
6f036462
TL
6304 }
6305 ]
6306 }),
6307 "node_modules/myconf/foo/test.js": "a == b",
6308 "foo/test.js": "a == b"
6309 }
56c4a2cb
DC
6310 });
6311
6f036462
TL
6312 beforeEach(prepare);
6313 afterEach(cleanup);
6314
56c4a2cb 6315 it("'lintFiles()' with 'foo/test.js' should NOT use the override entry.", async () => {
6f036462 6316 const engine = new ESLint({
56c4a2cb
DC
6317 overrideConfigFile: "node_modules/myconf/.eslintrc.json",
6318 cwd: root,
6319 ignore: false,
6320 useEslintrc: false
6321 });
6322 const results = await engine.lintFiles("foo/test.js");
6323
6324 // Expected to be no errors because the file matches to `$CWD/foo/*.js`.
6325 assert.deepStrictEqual(results, [
6326 {
6327 errorCount: 0,
6f036462 6328 filePath: path.join(getPath(), "foo/test.js"),
56c4a2cb
DC
6329 fixableErrorCount: 0,
6330 fixableWarningCount: 0,
6331 messages: [],
8f9d1d4d 6332 suppressedMessages: [],
56c4a2cb 6333 usedDeprecatedRules: [],
609c276f
TL
6334 warningCount: 0,
6335 fatalErrorCount: 0
56c4a2cb
DC
6336 }
6337 ]);
6338 });
6339
6340 it("'lintFiles()' with 'node_modules/myconf/foo/test.js' should use the override entry.", async () => {
6f036462 6341 const engine = new ESLint({
56c4a2cb
DC
6342 overrideConfigFile: "node_modules/myconf/.eslintrc.json",
6343 cwd: root,
6344 ignore: false,
6345 useEslintrc: false
6346 });
6347 const results = await engine.lintFiles("node_modules/myconf/foo/test.js");
6348
6349 // Expected to be an 'eqeqeq' error because the file doesn't match to `$CWD/foo/*.js`.
6350 assert.deepStrictEqual(results, [
6351 {
6352 errorCount: 1,
6f036462 6353 filePath: path.join(getPath(), "node_modules/myconf/foo/test.js"),
56c4a2cb
DC
6354 fixableErrorCount: 0,
6355 fixableWarningCount: 0,
6356 messages: [
6357 {
6358 column: 3,
6359 endColumn: 5,
6360 endLine: 1,
6361 line: 1,
6362 message: "Expected '===' and instead saw '=='.",
6363 messageId: "unexpected",
6364 nodeType: "BinaryExpression",
6365 ruleId: "eqeqeq",
6366 severity: 2
6367 }
6368 ],
8f9d1d4d 6369 suppressedMessages: [],
56c4a2cb
DC
6370 source: "a == b",
6371 usedDeprecatedRules: [],
609c276f
TL
6372 warningCount: 0,
6373 fatalErrorCount: 0
56c4a2cb
DC
6374 }
6375 ]);
6376 });
6377 });
6378
6379 describe("if { ignorePatterns: 'foo/*.txt', ... } is present by '--config node_modules/myconf/.eslintrc.json',", () => {
6f036462
TL
6380 const { prepare, cleanup, getPath } = createCustomTeardown({
6381 cwd: root,
6382 files: {
6383 "node_modules/myconf/.eslintrc.json": JSON.stringify({
6384 ignorePatterns: ["!/node_modules/myconf", "foo/*.js"],
6385 rules: {
6386 eqeqeq: "error"
6387 }
6388 }),
6389 "node_modules/myconf/foo/test.js": "a == b",
6390 "foo/test.js": "a == b"
6391 }
56c4a2cb
DC
6392 });
6393
6f036462
TL
6394 beforeEach(prepare);
6395 afterEach(cleanup);
6396
56c4a2cb 6397 it("'lintFiles()' with '**/*.js' should iterate 'node_modules/myconf/foo/test.js' but not 'foo/test.js'.", async () => {
6f036462 6398 const engine = new ESLint({
56c4a2cb 6399 overrideConfigFile: "node_modules/myconf/.eslintrc.json",
6f036462 6400 cwd: getPath(),
56c4a2cb
DC
6401 useEslintrc: false
6402 });
6403 const files = (await engine.lintFiles("**/*.js"))
6404 .map(r => r.filePath)
6405 .sort();
6406
6407 assert.deepStrictEqual(files, [
6408 path.join(root, "node_modules/myconf/foo/test.js")
6409 ]);
6410 });
6411 });
6412 });
6413
6414 describe("plugin conflicts", () => {
6415 let uid = 0;
6f036462 6416 const root = getFixturePath("cli-engine/plugin-conflicts-");
56c4a2cb
DC
6417
6418 /**
6419 * Verify thrown errors.
6420 * @param {() => Promise<any>} f The function to run and throw.
6421 * @param {Record<string, any>} props The properties to verify.
6422 * @returns {Promise<void>} void
6423 */
6424 async function assertThrows(f, props) {
6425 try {
6426 await f();
6427 } catch (error) {
6428 for (const [key, value] of Object.entries(props)) {
6429 assert.deepStrictEqual(error[key], value, key);
6430 }
6431 return;
6432 }
6433
6434 assert.fail("Function should throw an error, but not.");
6435 }
6436
6437 describe("between a config file and linear extendees.", () => {
6f036462
TL
6438
6439 const { prepare, cleanup, getPath } = createCustomTeardown({
6440 cwd: `${root}${++uid}`,
6441 files: {
6442 "node_modules/eslint-plugin-foo/index.js": "",
6443 "node_modules/eslint-config-one/node_modules/eslint-plugin-foo/index.js": "",
6444 "node_modules/eslint-config-one/index.js": `module.exports = ${JSON.stringify({
6445 extends: ["two"],
6446 plugins: ["foo"]
6447 })}`,
6448 "node_modules/eslint-config-two/node_modules/eslint-plugin-foo/index.js": "",
6449 "node_modules/eslint-config-two/index.js": `module.exports = ${JSON.stringify({
6450 plugins: ["foo"]
6451 })}`,
6452 ".eslintrc.json": JSON.stringify({
6453 extends: ["one"],
6454 plugins: ["foo"]
6455 }),
6456 "test.js": ""
6457 }
56c4a2cb
DC
6458 });
6459
6f036462
TL
6460 beforeEach(prepare);
6461 afterEach(cleanup);
6462
56c4a2cb 6463 it("'lintFiles()' should NOT throw plugin-conflict error. (Load the plugin from the base directory of the entry config file.)", async () => {
6f036462 6464 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
6465
6466 await engine.lintFiles("test.js");
6467 });
6468 });
6469
6470 describe("between a config file and same-depth extendees.", () => {
6f036462
TL
6471
6472 const { prepare, cleanup, getPath } = createCustomTeardown({
6473 cwd: `${root}${++uid}`,
6474 files: {
6475 "node_modules/eslint-plugin-foo/index.js": "",
6476 "node_modules/eslint-config-one/node_modules/eslint-plugin-foo/index.js": "",
6477 "node_modules/eslint-config-one/index.js": `module.exports = ${JSON.stringify({
6478 plugins: ["foo"]
6479 })}`,
6480 "node_modules/eslint-config-two/node_modules/eslint-plugin-foo/index.js": "",
6481 "node_modules/eslint-config-two/index.js": `module.exports = ${JSON.stringify({
6482 plugins: ["foo"]
6483 })}`,
6484 ".eslintrc.json": JSON.stringify({
6485 extends: ["one", "two"],
6486 plugins: ["foo"]
6487 }),
6488 "test.js": ""
6489 }
56c4a2cb
DC
6490 });
6491
6f036462
TL
6492 beforeEach(prepare);
6493 afterEach(cleanup);
6494
56c4a2cb 6495 it("'lintFiles()' should NOT throw plugin-conflict error. (Load the plugin from the base directory of the entry config file.)", async () => {
6f036462 6496 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
6497
6498 await engine.lintFiles("test.js");
6499 });
6500 });
6501
6502 describe("between two config files in different directories, with single node_modules.", () => {
6f036462
TL
6503
6504 const { prepare, cleanup, getPath } = createCustomTeardown({
6505 cwd: `${root}${++uid}`,
6506 files: {
6507 "node_modules/eslint-plugin-foo/index.js": "",
6508 ".eslintrc.json": JSON.stringify({
6509 plugins: ["foo"]
6510 }),
6511 "subdir/.eslintrc.json": JSON.stringify({
6512 plugins: ["foo"]
6513 }),
6514 "subdir/test.js": ""
6515 }
56c4a2cb
DC
6516 });
6517
6f036462
TL
6518 beforeEach(prepare);
6519 afterEach(cleanup);
6520
56c4a2cb 6521 it("'lintFiles()' should NOT throw plugin-conflict error. (Load the plugin from the base directory of the entry config file, but there are two entry config files, but node_modules directory is unique.)", async () => {
6f036462 6522 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
6523
6524 await engine.lintFiles("subdir/test.js");
6525 });
6526 });
6527
6528 describe("between two config files in different directories, with multiple node_modules.", () => {
6f036462
TL
6529
6530 const { prepare, cleanup, getPath } = createCustomTeardown({
6531 cwd: `${root}${++uid}`,
6532 files: {
6533 "node_modules/eslint-plugin-foo/index.js": "",
6534 ".eslintrc.json": JSON.stringify({
6535 plugins: ["foo"]
6536 }),
6537 "subdir/node_modules/eslint-plugin-foo/index.js": "",
6538 "subdir/.eslintrc.json": JSON.stringify({
6539 plugins: ["foo"]
6540 }),
6541 "subdir/test.js": ""
6542 }
56c4a2cb
DC
6543 });
6544
6f036462
TL
6545 beforeEach(prepare);
6546 afterEach(cleanup);
6547
56c4a2cb 6548 it("'lintFiles()' should throw plugin-conflict error. (Load the plugin from the base directory of the entry config file, but there are two entry config files.)", async () => {
6f036462 6549 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
6550
6551 await assertThrows(
6552 () => engine.lintFiles("subdir/test.js"),
6553 {
6554 message: `Plugin "foo" was conflicted between "subdir${path.sep}.eslintrc.json" and ".eslintrc.json".`,
6555 messageTemplate: "plugin-conflict",
6556 messageData: {
6557 pluginId: "foo",
6558 plugins: [
6559 {
6f036462 6560 filePath: path.join(getPath(), "subdir/node_modules/eslint-plugin-foo/index.js"),
56c4a2cb
DC
6561 importerName: `subdir${path.sep}.eslintrc.json`
6562 },
6563 {
6f036462 6564 filePath: path.join(getPath(), "node_modules/eslint-plugin-foo/index.js"),
56c4a2cb
DC
6565 importerName: ".eslintrc.json"
6566 }
6567 ]
6568 }
6569 }
6570 );
6571 });
6572 });
6573
6574 describe("between '--config' option and a regular config file, with single node_modules.", () => {
6f036462
TL
6575
6576 const { prepare, cleanup, getPath } = createCustomTeardown({
6577 cwd: `${root}${++uid}`,
6578 files: {
6579 "node_modules/eslint-plugin-foo/index.js": "",
6580 "node_modules/mine/.eslintrc.json": JSON.stringify({
6581 plugins: ["foo"]
6582 }),
6583 ".eslintrc.json": JSON.stringify({
6584 plugins: ["foo"]
6585 }),
6586 "test.js": ""
6587 }
56c4a2cb
DC
6588 });
6589
6f036462
TL
6590 beforeEach(prepare);
6591 afterEach(cleanup);
6592
56c4a2cb 6593 it("'lintFiles()' should NOT throw plugin-conflict error. (Load the plugin from the base directory of the entry config file, but there are two entry config files, but node_modules directory is unique.)", async () => {
6f036462
TL
6594 const engine = new ESLint({
6595 cwd: getPath(),
56c4a2cb
DC
6596 overrideConfigFile: "node_modules/mine/.eslintrc.json"
6597 });
6598
6599 await engine.lintFiles("test.js");
6600 });
6601 });
6602
6603 describe("between '--config' option and a regular config file, with multiple node_modules.", () => {
6f036462
TL
6604
6605 const { prepare, cleanup, getPath } = createCustomTeardown({
6606 cwd: `${root}${++uid}`,
6607 files: {
6608 "node_modules/eslint-plugin-foo/index.js": "",
6609 "node_modules/mine/node_modules/eslint-plugin-foo/index.js": "",
6610 "node_modules/mine/.eslintrc.json": JSON.stringify({
6611 plugins: ["foo"]
6612 }),
6613 ".eslintrc.json": JSON.stringify({
6614 plugins: ["foo"]
6615 }),
6616 "test.js": ""
6617 }
56c4a2cb
DC
6618 });
6619
6f036462
TL
6620 beforeEach(prepare);
6621 afterEach(cleanup);
6622
56c4a2cb 6623 it("'lintFiles()' should throw plugin-conflict error. (Load the plugin from the base directory of the entry config file, but there are two entry config files.)", async () => {
6f036462
TL
6624 const engine = new ESLint({
6625 cwd: getPath(),
56c4a2cb
DC
6626 overrideConfigFile: "node_modules/mine/.eslintrc.json"
6627 });
6628
6629 await assertThrows(
6630 () => engine.lintFiles("test.js"),
6631 {
6632 message: "Plugin \"foo\" was conflicted between \"--config\" and \".eslintrc.json\".",
6633 messageTemplate: "plugin-conflict",
6634 messageData: {
6635 pluginId: "foo",
6636 plugins: [
6637 {
6f036462 6638 filePath: path.join(getPath(), "node_modules/mine/node_modules/eslint-plugin-foo/index.js"),
56c4a2cb
DC
6639 importerName: "--config"
6640 },
6641 {
6f036462 6642 filePath: path.join(getPath(), "node_modules/eslint-plugin-foo/index.js"),
56c4a2cb
DC
6643 importerName: ".eslintrc.json"
6644 }
6645 ]
6646 }
6647 }
6648 );
6649 });
6650 });
6651
6652 describe("between '--plugin' option and a regular config file, with single node_modules.", () => {
6f036462
TL
6653
6654 const { prepare, cleanup, getPath } = createCustomTeardown({
6655 cwd: `${root}${++uid}`,
6656 files: {
6657 "node_modules/eslint-plugin-foo/index.js": "",
6658 "subdir/.eslintrc.json": JSON.stringify({
6659 plugins: ["foo"]
6660 }),
6661 "subdir/test.js": ""
6662 }
56c4a2cb
DC
6663 });
6664
6f036462
TL
6665
6666 beforeEach(prepare);
6667 afterEach(cleanup);
6668
56c4a2cb 6669 it("'lintFiles()' should NOT throw plugin-conflict error. (Load the plugin from both CWD and the base directory of the entry config file, but node_modules directory is unique.)", async () => {
6f036462
TL
6670 const engine = new ESLint({
6671 cwd: getPath(),
56c4a2cb
DC
6672 overrideConfig: { plugins: ["foo"] }
6673 });
6674
6675 await engine.lintFiles("subdir/test.js");
6676 });
6677 });
6678
6679 describe("between '--plugin' option and a regular config file, with multiple node_modules.", () => {
6f036462
TL
6680
6681 const { prepare, cleanup, getPath } = createCustomTeardown({
6682 cwd: `${root}${++uid}`,
6683 files: {
6684 "node_modules/eslint-plugin-foo/index.js": "",
6685 "subdir/node_modules/eslint-plugin-foo/index.js": "",
6686 "subdir/.eslintrc.json": JSON.stringify({
6687 plugins: ["foo"]
6688 }),
6689 "subdir/test.js": ""
6690 }
56c4a2cb
DC
6691 });
6692
6f036462
TL
6693 beforeEach(prepare);
6694 afterEach(cleanup);
6695
56c4a2cb 6696 it("'lintFiles()' should throw plugin-conflict error. (Load the plugin from both CWD and the base directory of the entry config file.)", async () => {
6f036462
TL
6697 const engine = new ESLint({
6698 cwd: getPath(),
56c4a2cb
DC
6699 overrideConfig: { plugins: ["foo"] }
6700 });
6701
6702 await assertThrows(
6703 () => engine.lintFiles("subdir/test.js"),
6704 {
6705 message: `Plugin "foo" was conflicted between "CLIOptions" and "subdir${path.sep}.eslintrc.json".`,
6706 messageTemplate: "plugin-conflict",
6707 messageData: {
6708 pluginId: "foo",
6709 plugins: [
6710 {
6f036462 6711 filePath: path.join(getPath(), "node_modules/eslint-plugin-foo/index.js"),
56c4a2cb
DC
6712 importerName: "CLIOptions"
6713 },
6714 {
6f036462 6715 filePath: path.join(getPath(), "subdir/node_modules/eslint-plugin-foo/index.js"),
56c4a2cb
DC
6716 importerName: `subdir${path.sep}.eslintrc.json`
6717 }
6718 ]
6719 }
6720 }
6721 );
6722 });
6723 });
6724
6725 describe("'--resolve-plugins-relative-to' option overrides the location that ESLint load plugins from.", () => {
6f036462
TL
6726
6727 const { prepare, cleanup, getPath } = createCustomTeardown({
6728 cwd: `${root}${++uid}`,
6729 files: {
6730 "node_modules/eslint-plugin-foo/index.js": "",
6731 ".eslintrc.json": JSON.stringify({
6732 plugins: ["foo"]
6733 }),
6734 "subdir/node_modules/eslint-plugin-foo/index.js": "",
6735 "subdir/.eslintrc.json": JSON.stringify({
6736 plugins: ["foo"]
6737 }),
6738 "subdir/test.js": ""
6739 }
56c4a2cb
DC
6740 });
6741
6f036462
TL
6742 beforeEach(prepare);
6743 afterEach(cleanup);
6744
56c4a2cb 6745 it("'lintFiles()' should NOT throw plugin-conflict error. (Load the plugin from '--resolve-plugins-relative-to'.)", async () => {
6f036462
TL
6746 const engine = new ESLint({
6747 cwd: getPath(),
6748 resolvePluginsRelativeTo: getPath()
56c4a2cb
DC
6749 });
6750
6751 await engine.lintFiles("subdir/test.js");
6752 });
6753 });
6754
6755 describe("between two config files with different target files.", () => {
6f036462
TL
6756
6757 const { prepare, cleanup, getPath } = createCustomTeardown({
6758 cwd: `${root}${++uid}`,
6759 files: {
6760 "one/node_modules/eslint-plugin-foo/index.js": "",
6761 "one/.eslintrc.json": JSON.stringify({
6762 plugins: ["foo"]
6763 }),
6764 "one/test.js": "",
6765 "two/node_modules/eslint-plugin-foo/index.js": "",
6766 "two/.eslintrc.json": JSON.stringify({
6767 plugins: ["foo"]
6768 }),
6769 "two/test.js": ""
6770 }
56c4a2cb
DC
6771 });
6772
6f036462
TL
6773 beforeEach(prepare);
6774 afterEach(cleanup);
6775
56c4a2cb 6776 it("'lintFiles()' should NOT throw plugin-conflict error. (Load the plugin from the base directory of the entry config file for each target file. Not related to each other.)", async () => {
6f036462 6777 const engine = new ESLint({ cwd: getPath() });
56c4a2cb
DC
6778 const results = await engine.lintFiles("*/test.js");
6779
6780 assert.strictEqual(results.length, 2);
6781 });
6782 });
6783 });
8f9d1d4d
DC
6784
6785 describe("loading rules", () => {
6786 it("should not load unused core rules", done => {
6787 let calledDone = false;
6788
6789 const cwd = getFixturePath("lazy-loading-rules");
6790 const pattern = "foo.js";
6791 const usedRules = ["semi"];
6792
6793 const forkedProcess = childProcess.fork(
6794 path.join(__dirname, "../../_utils/test-lazy-loading-rules.js"),
6795 [cwd, pattern, String(usedRules)]
6796 );
6797
6798 // this is an error message
6799 forkedProcess.on("message", ({ message, stack }) => {
6800 if (calledDone) {
6801 return;
6802 }
6803 calledDone = true;
6804
6805 const error = new Error(message);
6806
6807 error.stack = stack;
6808 done(error);
6809 });
6810
6811 forkedProcess.on("exit", exitCode => {
6812 if (calledDone) {
6813 return;
6814 }
6815 calledDone = true;
6816
6817 if (exitCode === 0) {
6818 done();
6819 } else {
6820 done(new Error("Forked process exited with a non-zero exit code"));
6821 }
6822 });
6823 });
6824 });
56c4a2cb 6825});