diff --git a/crates/oxc_cli/src/command.rs b/crates/oxc_cli/src/command.rs index f6cc09cbf..3e601814a 100644 --- a/crates/oxc_cli/src/command.rs +++ b/crates/oxc_cli/src/command.rs @@ -63,6 +63,18 @@ pub struct MiscOptions { pub threads: Option, } +/// Enable Plugins +#[derive(Debug, Clone, Bpaf)] +pub struct EnablePlugins { + /// Enable the Jest plugin and detect test problems + #[bpaf(switch, hide_usage)] + pub jest_plugin: bool, + + /// Enable the JSX-a11y plugin and detect accessibility problems + #[bpaf(switch, hide_usage)] + pub jsx_a11y_plugin: bool, +} + #[derive(Debug, Clone, Bpaf)] pub struct LintOptions { #[bpaf(external(lint_filter), map(LintFilter::into_tuple), many)] @@ -72,6 +84,9 @@ pub struct LintOptions { #[bpaf(switch, hide_usage)] pub import_plugin: bool, + #[bpaf(external)] + pub enable_plugins: EnablePlugins, + #[bpaf(external)] pub fix_options: FixOptions, diff --git a/crates/oxc_cli/src/lint/mod.rs b/crates/oxc_cli/src/lint/mod.rs index 2c19b5aaa..e8a3e2bfc 100644 --- a/crates/oxc_cli/src/lint/mod.rs +++ b/crates/oxc_cli/src/lint/mod.rs @@ -35,6 +35,7 @@ impl Runner for LintRunner { fix_options, misc_options, codeowner_options, + enable_plugins, } = self.options; if paths.is_empty() { @@ -57,7 +58,9 @@ impl Runner for LintRunner { .with_filter(filter) .with_fix(fix_options.fix) .with_timing(misc_options.timing) - .with_import_plugin(import_plugin); + .with_import_plugin(import_plugin) + .with_jest_plugin(enable_plugins.jest_plugin) + .with_jsx_a11y_plugin(enable_plugins.jsx_a11y_plugin); let lint_service = LintService::new(cwd, &paths, lint_options); let diagnostic_service = DiagnosticService::default() diff --git a/crates/oxc_linter/src/options.rs b/crates/oxc_linter/src/options.rs index 5295a9506..6d38ecdb0 100644 --- a/crates/oxc_linter/src/options.rs +++ b/crates/oxc_linter/src/options.rs @@ -9,6 +9,8 @@ pub struct LintOptions { pub fix: bool, pub timing: bool, pub import_plugin: bool, + pub jest_plugin: bool, + pub jsx_a11y_plugin: bool, } impl Default for LintOptions { @@ -18,6 +20,8 @@ impl Default for LintOptions { fix: false, timing: false, import_plugin: false, + jest_plugin: false, + jsx_a11y_plugin: false, } } } @@ -48,6 +52,18 @@ impl LintOptions { self.import_plugin = yes; self } + + #[must_use] + pub fn with_jest_plugin(mut self, yes: bool) -> Self { + self.jest_plugin = yes; + self + } + + #[must_use] + pub fn with_jsx_a11y_plugin(mut self, yes: bool) -> Self { + self.jsx_a11y_plugin = yes; + self + } } #[derive(Debug, Clone, Copy, Eq, PartialEq)] @@ -67,6 +83,9 @@ impl From<&'static str> for AllowWarnDeny { } } +const JEST_PLUGIN_NAME: &str = "jest"; +const JSX_A11Y_PLUGIN_NAME: &str = "jsx_a11y"; + impl LintOptions { pub fn derive_rules(&self) -> Vec { let mut rules: FxHashSet = FxHashSet::default(); @@ -108,9 +127,24 @@ impl LintOptions { } } + self.extends_or_exclude_plugins(&mut rules); + let mut rules = rules.into_iter().collect::>(); // for stable diagnostics output ordering rules.sort_unstable_by_key(RuleEnum::name); rules } + + fn extends_or_exclude_plugins(&self, rules: &mut FxHashSet) { + let mut extends_or_exclude = |yes: bool, name: &str| { + if yes { + rules.extend(RULES.iter().filter(|rule| rule.plugin_name() == name).cloned()); + } else { + rules.retain(|rule| rule.plugin_name() != name); + } + }; + + extends_or_exclude(self.jest_plugin, JEST_PLUGIN_NAME); + extends_or_exclude(self.jsx_a11y_plugin, JSX_A11Y_PLUGIN_NAME); + } } diff --git a/crates/oxc_linter/src/tester.rs b/crates/oxc_linter/src/tester.rs index 510f1616e..5968f7d58 100644 --- a/crates/oxc_linter/src/tester.rs +++ b/crates/oxc_linter/src/tester.rs @@ -26,6 +26,8 @@ pub struct Tester { snapshot: String, current_working_directory: Box, import_plugin: bool, + jest_plugin: bool, + jsx_a11y_plugin: bool, } impl Tester { @@ -48,6 +50,8 @@ impl Tester { snapshot: String::new(), current_working_directory, import_plugin: false, + jest_plugin: false, + jsx_a11y_plugin: false, } } @@ -136,8 +140,11 @@ impl Tester { fn run(&mut self, source_text: &str, config: Option, is_fix: bool) -> TestResult { let allocator = Allocator::default(); let rule = self.find_rule().read_json(config); - let options = - LintOptions::default().with_fix(is_fix).with_import_plugin(self.import_plugin); + let options = LintOptions::default() + .with_fix(is_fix) + .with_import_plugin(self.import_plugin) + .with_jest_plugin(self.jest_plugin) + .with_jsx_a11y_plugin(self.jsx_a11y_plugin); let linter = Linter::from_options(options).with_rules(vec![rule]); let path_to_lint = if self.import_plugin { self.current_working_directory.join(&self.rule_path)