diff --git a/lib/linter/linter.js b/lib/linter/linter.js
index 4b28e196a76f..aa5426e0f916 100644
--- a/lib/linter/linter.js
+++ b/lib/linter/linter.js
@@ -961,7 +961,8 @@ function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parser
selector,
timing.enabled
? timing.time(ruleId, ruleListeners[selector])
- : ruleListeners[selector]
+ : ruleListeners[selector],
+ ruleId
);
});
});
@@ -1223,6 +1224,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 f4837c1ddcf5..f3cd642605fc 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 d277ce1ea92b..8eedeabd6c21 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", () => {
@@ -5300,7 +5300,7 @@ var a = "test2";
assert.throws(() => {
linter.verify("0", { rules: { "test-rule": "error" } });
- }, /Fixable rules must set the `meta\.fixable` property to "code" or "whitespace".\nOccurred while linting :1$/u);
+ }, /Fixable rules must set the `meta\.fixable` property to "code" or "whitespace".\nOccurred while linting :1\nRule: "test-rule"$/u);
});
it("should throw an error if fix is passed and there is no metadata", () => {