diff --git a/lib/linter/linter.js b/lib/linter/linter.js index 4e80926a895..310db3a9ebb 100644 --- a/lib/linter/linter.js +++ b/lib/linter/linter.js @@ -942,7 +942,8 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parser selector, timing.enabled ? timing.time(ruleId, ruleListeners[selector]) - : ruleListeners[selector] + : ruleListeners[selector], + ruleId ); }); }); @@ -1203,6 +1204,11 @@ class Linter { debug("Parser Options:", parserOptions); debug("Parser Path:", parserName); debug("Settings:", settings); + + if (err.ruleId) { + err.message += `\nRule: "${err.ruleId}"`; + } + throw err; } diff --git a/lib/linter/safe-emitter.js b/lib/linter/safe-emitter.js index ab212230d39..703347aad72 100644 --- a/lib/linter/safe-emitter.js +++ b/lib/linter/safe-emitter.js @@ -31,18 +31,29 @@ */ module.exports = () => { const listeners = Object.create(null); + const listenersToRuleId = Object.create(null); return Object.freeze({ - on(eventName, listener) { + on(eventName, listener, ruleId) { if (eventName in listeners) { listeners[eventName].push(listener); } else { listeners[eventName] = [listener]; } + listenersToRuleId[listener] = ruleId; }, emit(eventName, ...args) { if (eventName in listeners) { - listeners[eventName].forEach(listener => listener(...args)); + listeners[eventName].forEach(listener => { + try { + listener(...args); + } catch (e) { + const ruleId = listenersToRuleId[listener]; + + e.ruleId = ruleId; + throw e; + } + }); } }, eventNames() { diff --git a/tests/lib/linter/linter.js b/tests/lib/linter/linter.js index 522f9b19726..ae7f759a17b 100644 --- a/tests/lib/linter/linter.js +++ b/tests/lib/linter/linter.js @@ -87,7 +87,7 @@ describe("Linter", () => { assert.throws(() => { linter.verify(code, config, filename); - }, `Intentional error.\nOccurred while linting ${filename}:1`); + }, `Intentional error.\nOccurred while linting ${filename}:1\nRule: "checker"`); }); it("does not call rule listeners with a `this` value", () => { @@ -5193,7 +5193,7 @@ var a = "test2"; assert.throws(() => { linter.verify("0", { rules: { "test-rule": "error" } }); - }, /Fixable rules should export a `meta\.fixable` property.\nOccurred while linting :1$/u); + }, /Fixable rules should export a `meta\.fixable` property.\nOccurred while linting :1\nRule: "test-rule"$/u); }); it("should not throw an error if fix is passed and there is no metadata", () => {