From b4bd83acf54a8d1d24ceac3089b16f1e90f6a5ea Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Thu, 16 Sep 2021 10:34:05 -0700 Subject: [PATCH] Update: Suggest missing rule in flat config (fixes #14027) --- lib/config/rule-validator.js | 26 ++++++++++++++++------ tests/lib/config/flat-config-array.js | 32 +++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/lib/config/rule-validator.js b/lib/config/rule-validator.js index fe1aa863bfd..6f25f86b9c1 100644 --- a/lib/config/rule-validator.js +++ b/lib/config/rule-validator.js @@ -35,16 +35,28 @@ function findRuleDefinition(ruleId, config) { pluginName = ruleIdParts.join("/"); } - if (!config.plugins || !config.plugins[pluginName]) { - throw new TypeError(`Key "rules": Key "${ruleId}": Could not find plugin "${pluginName}".`); - } + if (config?.plugins) { - if (!config.plugins[pluginName].rules || !config.plugins[pluginName].rules[ruleName]) { - throw new TypeError(`Key "rules": Key "${ruleId}": Could not find "${ruleName}" in plugin "${pluginName}".`); - } + // first check for exact rule match + if (config.plugins?.[pluginName]?.rules?.[ruleName]) { + return config.plugins[pluginName].rules[ruleName]; + } - return config.plugins[pluginName].rules[ruleName]; + let errorMessage = `Key "rules": Key "${ruleId}": Could not find "${ruleName}" in plugin "${pluginName}".`; + + // otherwise, let's see if we can find the rule name elsewhere + for (const [otherPluginName, plugin] of Object.entries(config.plugins)) { + if (plugin?.rules?.[ruleName]) { + errorMessage += ` Did you mean "${otherPluginName}/${ruleName}"?`; + break; + } + } + + throw new TypeError(errorMessage); + + } + throw new TypeError(`Key "rules": Key "${ruleId}": Could not find plugin "${pluginName}".`); } /** diff --git a/tests/lib/config/flat-config-array.js b/tests/lib/config/flat-config-array.js index fd89f8d972c..e43e195ac41 100644 --- a/tests/lib/config/flat-config-array.js +++ b/tests/lib/config/flat-config-array.js @@ -56,6 +56,16 @@ const baseConfig = { } } } + }, + test1: { + rules: { + match: {} + } + }, + test2: { + rules: { + nomatch: {} + } } } }; @@ -1278,6 +1288,28 @@ describe("FlatConfigArray", () => { ], "Key \"rules\": Key \"foo\": Expected severity of \"off\", 0, \"warn\", 1, \"error\", or 2."); }); + it("should error when rule doesn't exist", async () => { + + await assertInvalidConfig([ + { + rules: { + foox: [1, "bar"] + } + } + ], /Key "rules": Key "foox": Could not find "foox" in plugin "@"./u); + }); + + it("should error and suggest alternative when rule doesn't exist", async () => { + + await assertInvalidConfig([ + { + rules: { + "test2/match": "error" + } + } + ], /Key "rules": Key "test2\/match": Could not find "match" in plugin "test2"\. Did you mean "test1\/match"\?/u); + }); + it("should error when rule options don't match schema", async () => { await assertInvalidConfig([