diff --git a/crates/oxc_linter/src/config/config_builder.rs b/crates/oxc_linter/src/config/config_builder.rs index f2723b8cd772d..7e99e449c85e0 100644 --- a/crates/oxc_linter/src/config/config_builder.rs +++ b/crates/oxc_linter/src/config/config_builder.rs @@ -305,6 +305,7 @@ impl ConfigStoreBuilder { self.upsert_where(severity, |r| r.category() == *category); } LintFilterKind::Rule(plugin, rule) => { + let (plugin, rule) = super::rules::unalias_plugin_name(plugin, rule); self.upsert_where(severity, |r| r.plugin_name() == plugin && r.name() == rule); } LintFilterKind::Generic(name) => self.upsert_where(severity, |r| r.name() == name), @@ -317,6 +318,7 @@ impl ConfigStoreBuilder { self.rules.retain(|rule, _| rule.category() != *category); } LintFilterKind::Rule(plugin, rule) => { + let (plugin, rule) = super::rules::unalias_plugin_name(plugin, rule); self.rules.retain(|r, _| r.plugin_name() != plugin || r.name() != rule); } LintFilterKind::Generic(name) => self.rules.retain(|rule, _| rule.name() != name), @@ -857,6 +859,47 @@ mod test { assert_eq!(expected_plugins, builder.plugins()); } + #[test] + fn test_cli_rule_aliases() { + let builder = ConfigStoreBuilder::default().and_builtin_plugins(LintPlugins::REACT, true); + + // Assert rule doesn't exist by default + assert_eq!( + builder + .rules + .iter() + .find(|(r, _)| r.plugin_name() == "react" && r.name() == "exhaustive-deps"), + None + ); + + let builder = builder.with_filter( + &LintFilter::new(AllowWarnDeny::Deny, "react-hooks/exhaustive-deps").unwrap(), + ); + + let (rule, sev) = builder + .rules + .iter() + .find(|(r, _)| r.plugin_name() == "react" && r.name() == "exhaustive-deps") + .expect("react/exhaustive-deps should be configured to Deny"); + + assert_eq!(rule.plugin_name(), "react"); + assert_eq!(rule.name(), "exhaustive-deps"); + assert_eq!(sev, &AllowWarnDeny::Deny); + + let builder = builder.with_filter( + &LintFilter::new(AllowWarnDeny::Allow, "react-hooks/exhaustive-deps").unwrap(), + ); + + // Allowing the rule removes it from rules "overlay" + assert_eq!( + builder + .rules + .iter() + .find(|(r, _)| r.plugin_name() == "react" && r.name() == "exhaustive-deps"), + None + ); + } + #[test] fn test_categories() { let oxlintrc: Oxlintrc = serde_json::from_str( diff --git a/crates/oxc_linter/src/config/rules.rs b/crates/oxc_linter/src/config/rules.rs index af2434125e48b..388faac70d15b 100644 --- a/crates/oxc_linter/src/config/rules.rs +++ b/crates/oxc_linter/src/config/rules.rs @@ -240,7 +240,10 @@ fn parse_rule_key(name: &str) -> (String, String) { name.to_string(), ); }; + unalias_plugin_name(plugin_name, rule_name) +} +pub(super) fn unalias_plugin_name(plugin_name: &str, rule_name: &str) -> (String, String) { let (oxlint_plugin_name, rule_name) = match plugin_name { "@typescript-eslint" => ("typescript", rule_name), // import-x has the same rules but better performance