diff --git a/crates/oxc_cli/fixtures/typescript_eslint/eslintrc.json b/crates/oxc_cli/fixtures/typescript_eslint/eslintrc.json new file mode 100644 index 000000000..35ed3856d --- /dev/null +++ b/crates/oxc_cli/fixtures/typescript_eslint/eslintrc.json @@ -0,0 +1,6 @@ +{ + "rules": { + "no-loss-of-precision": "off", + "@typescript-eslint/no-loss-of-precision": "error" + } +} diff --git a/crates/oxc_cli/fixtures/typescript_eslint/test.js b/crates/oxc_cli/fixtures/typescript_eslint/test.js new file mode 100644 index 000000000..ddf89a754 --- /dev/null +++ b/crates/oxc_cli/fixtures/typescript_eslint/test.js @@ -0,0 +1 @@ +9007199254740993 // no-loss-of-precision diff --git a/crates/oxc_cli/src/lint/mod.rs b/crates/oxc_cli/src/lint/mod.rs index fd5a2acb1..98cdc74d2 100644 --- a/crates/oxc_cli/src/lint/mod.rs +++ b/crates/oxc_cli/src/lint/mod.rs @@ -363,6 +363,19 @@ mod test { assert_eq!(result.number_of_errors, 0); } + #[test] + fn typescript_eslint() { + let args = &[ + "-c", + "fixtures/typescript_eslint/eslintrc.json", + "fixtures/typescript_eslint/test.js", + ]; + let result = test(args); + assert_eq!(result.number_of_files, 1); + assert_eq!(result.number_of_warnings, 1); + assert_eq!(result.number_of_errors, 0); + } + #[test] fn lint_vue_file() { let args = &["fixtures/vue/debugger.vue"]; diff --git a/crates/oxc_linter/src/config/mod.rs b/crates/oxc_linter/src/config/mod.rs index e347d183f..192267da8 100644 --- a/crates/oxc_linter/src/config/mod.rs +++ b/crates/oxc_linter/src/config/mod.rs @@ -68,41 +68,66 @@ impl ESLintConfig { }) } + #[allow(clippy::option_if_let_else)] pub fn override_rules( &self, - rules_to_override: &mut FxHashSet, + rules_for_override: &mut FxHashSet, all_rules: &[RuleEnum], ) { + use itertools::Itertools; let mut rules_to_replace = vec![]; let mut rules_to_remove = vec![]; - for rule_to_configure in &self.rules { - let (plugin_name, rule_name) = - (&rule_to_configure.plugin_name, &rule_to_configure.rule_name); - if let Some(rule) = rules_to_override - .iter() - .find(|r| r.plugin_name() == plugin_name && r.name() == rule_name) - { - match rule_to_configure.severity { - AllowWarnDeny::Warn | AllowWarnDeny::Deny => { - rules_to_replace.push(rule.read_json(rule_to_configure.config.clone())); - } - AllowWarnDeny::Allow => { - rules_to_remove.push(rule.clone()); + // Rules can have the same name but different plugin names + let lookup = self.rules.iter().into_group_map_by(|r| r.rule_name.as_str()); + + for (name, rule_configs) in &lookup { + match rule_configs.len() { + 0 => unreachable!(), + 1 => { + let rule_config = &rule_configs[0]; + let rule_name = &rule_config.rule_name; + let plugin_name = &rule_config.plugin_name; + if let Some(rule) = rules_for_override.iter().find(|r| r.name() == rule_name) { + match rule_config.severity { + AllowWarnDeny::Warn | AllowWarnDeny::Deny => { + rules_to_replace.push(rule.read_json(rule_config.config.clone())); + } + AllowWarnDeny::Allow => { + rules_to_remove.push(rule.clone()); + } + } + } else if let Some(rule) = all_rules + .iter() + .find(|r| r.plugin_name() == plugin_name && r.name() == rule_name) + { + rules_to_replace.push(rule.read_json(rule_config.config.clone())); + } + } + _ => { + // For overlapping rule names, use the "error" one + // "no-loss-of-precision": "off", + // "@typescript-eslint/no-loss-of-precision": "error" + if let Some(rule_config) = + rule_configs.iter().find(|r| r.severity.is_warn_deny()) + { + if let Some(rule) = rules_for_override.iter().find(|r| r.name() == *name) { + rules_to_replace.push(rule.read_json(rule_config.config.clone())); + } + } else if rule_configs.iter().all(|r| r.severity.is_allow()) { + if let Some(rule) = rules_for_override.iter().find(|r| r.name() == *name) { + rules_to_remove.push(rule.clone()); + } } } - } else if let Some(rule) = - all_rules.iter().find(|r| r.plugin_name() == plugin_name && r.name() == rule_name) - { - rules_to_replace.push(rule.read_json(rule_to_configure.config.clone())); } } for rule in rules_to_remove { - rules_to_override.remove(&rule); + rules_for_override.remove(&rule); } for rule in rules_to_replace { - rules_to_override.replace(rule); + rules_for_override.replace(rule); } } } diff --git a/crates/oxc_linter/src/options.rs b/crates/oxc_linter/src/options.rs index 53465459c..921bc4ac6 100644 --- a/crates/oxc_linter/src/options.rs +++ b/crates/oxc_linter/src/options.rs @@ -104,9 +104,13 @@ pub enum AllowWarnDeny { } impl AllowWarnDeny { - pub fn is_enabled(self) -> bool { + pub fn is_warn_deny(self) -> bool { self != Self::Allow } + + pub fn is_allow(self) -> bool { + self == Self::Allow + } } impl TryFrom<&str> for AllowWarnDeny {