Skip to content

Commit 0edfe36

Browse files
nzakasmdjermanovic
andauthored
fix: Ensure crash error messages are not duplicated (#17584)
* fix: Ensure crash error messages are not duplicated Fixes #17560 * Add test * Fix merge conflicts * Add tests --------- Co-authored-by: Milos Djermanovic <[email protected]>
1 parent ee5be81 commit 0edfe36

File tree

4 files changed

+72
-4
lines changed

4 files changed

+72
-4
lines changed

bin/eslint.js

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ function getErrorMessage(error) {
9292
return util.format("%o", error);
9393
}
9494

95+
/**
96+
* Tracks error messages that are shown to the user so we only ever show the
97+
* same message once.
98+
* @type {Set<string>}
99+
*/
100+
101+
const displayedErrors = new Set();
102+
95103
/**
96104
* Catch and report unexpected error.
97105
* @param {any} error The thrown error object.
@@ -101,14 +109,17 @@ function onFatalError(error) {
101109
process.exitCode = 2;
102110

103111
const { version } = require("../package.json");
104-
const message = getErrorMessage(error);
105-
106-
console.error(`
112+
const message = `
107113
Oops! Something went wrong! :(
108114
109115
ESLint: ${version}
110116
111-
${message}`);
117+
${getErrorMessage(error)}`;
118+
119+
if (!displayedErrors.has(message)) {
120+
console.error(message);
121+
displayedErrors.add(message);
122+
}
112123
}
113124

114125
//------------------------------------------------------------------------------

tests/bin/eslint.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,36 @@ describe("bin/eslint.js", () => {
387387
return Promise.all([exitCodeAssertion, outputAssertion]);
388388
});
389389

390+
// https://github.com/eslint/eslint/issues/17560
391+
describe("does not print duplicate errors in the event of a crash", () => {
392+
393+
it("when there is an invalid config read from a config file", () => {
394+
const config = path.join(__dirname, "../fixtures/bin/eslint.config-invalid.js");
395+
const child = runESLint(["--config", config, "conf", "tools"]);
396+
const exitCodeAssertion = assertExitCode(child, 2);
397+
const outputAssertion = getOutput(child).then(output => {
398+
399+
// The error text should appear exactly once in stderr
400+
assert.strictEqual(output.stderr.match(/A config object is using the "globals" key/gu).length, 1);
401+
});
402+
403+
return Promise.all([exitCodeAssertion, outputAssertion]);
404+
});
405+
406+
it("when there is an error in the next tick", () => {
407+
const config = path.join(__dirname, "../fixtures/bin/eslint.config-tick-throws.js");
408+
const child = runESLint(["--config", config, "Makefile.js"]);
409+
const exitCodeAssertion = assertExitCode(child, 2);
410+
const outputAssertion = getOutput(child).then(output => {
411+
412+
// The error text should appear exactly once in stderr
413+
assert.strictEqual(output.stderr.match(/test_error_stack/gu).length, 1);
414+
});
415+
416+
return Promise.all([exitCodeAssertion, outputAssertion]);
417+
});
418+
});
419+
390420
it("prints the error message pointing to line of code", () => {
391421
const invalidConfig = path.join(__dirname, "../fixtures/bin/eslint.config.js");
392422
const child = runESLint(["--no-ignore", "-c", invalidConfig]);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = [{
2+
globals: {}
3+
}];
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
function throwError() {
2+
const error = new Error();
3+
error.stack = "test_error_stack";
4+
throw error;
5+
}
6+
7+
module.exports = [{
8+
plugins: {
9+
foo: {
10+
rules: {
11+
bar: {
12+
create() {
13+
process.nextTick(throwError);
14+
process.nextTick(throwError);
15+
return {};
16+
}
17+
}
18+
}
19+
}
20+
},
21+
rules: {
22+
"foo/bar": "error"
23+
}
24+
}];

0 commit comments

Comments
 (0)