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