From eca6fdbffe99ac7424119bfe8f6743897f49bb0e Mon Sep 17 00:00:00 2001 From: DonIsaac <22823424+DonIsaac@users.noreply.github.com> Date: Fri, 23 Aug 2024 00:01:21 +0000 Subject: [PATCH] refactor(linter): move plugin options into separate struct (#5100) Part of #5046 --- crates/oxc_linter/src/lib.rs | 8 +- crates/oxc_linter/src/options.rs | 151 +++++++++++++++++++++---------- crates/oxc_linter/src/service.rs | 8 +- crates/oxc_linter/src/tester.rs | 52 +++++------ 4 files changed, 133 insertions(+), 86 deletions(-) diff --git a/crates/oxc_linter/src/lib.rs b/crates/oxc_linter/src/lib.rs index 808071e71a8c9..1f842cc77158e 100644 --- a/crates/oxc_linter/src/lib.rs +++ b/crates/oxc_linter/src/lib.rs @@ -157,12 +157,12 @@ impl Linter { .with_frameworks(self.options.framework_hints); // set file-specific jest/vitest flags - if self.options.jest_plugin || self.options.vitest_plugin { + if self.options.plugins.jest || self.options.plugins.vitest { let mut test_flags = FrameworkFlags::empty(); if frameworks::is_jestlike_file(path) { - test_flags.set(FrameworkFlags::Jest, self.options.jest_plugin); - test_flags.set(FrameworkFlags::Vitest, self.options.vitest_plugin); + test_flags.set(FrameworkFlags::Jest, self.options.plugins.jest); + test_flags.set(FrameworkFlags::Vitest, self.options.plugins.vitest); } else if frameworks::has_vitest_imports(ctx.module_record()) { test_flags.set(FrameworkFlags::Vitest, true); } @@ -186,7 +186,7 @@ impl Linter { } fn map_jest(&self, plugin_name: &'static str, rule_name: &str) -> &'static str { - if self.options.vitest_plugin + if self.options.plugins.vitest && plugin_name == "jest" && utils::is_jest_rule_adapted_to_vitest(rule_name) { diff --git a/crates/oxc_linter/src/options.rs b/crates/oxc_linter/src/options.rs index bd2b6860b5bc0..2b8d5490add1a 100644 --- a/crates/oxc_linter/src/options.rs +++ b/crates/oxc_linter/src/options.rs @@ -21,18 +21,7 @@ pub struct LintOptions { /// The kind represents the riskiest fix that the linter can apply. pub fix: FixKind, - pub react_plugin: bool, - pub unicorn_plugin: bool, - pub typescript_plugin: bool, - pub oxc_plugin: bool, - pub import_plugin: bool, - pub jsdoc_plugin: bool, - pub jest_plugin: bool, - pub vitest_plugin: bool, - pub jsx_a11y_plugin: bool, - pub nextjs_plugin: bool, - pub react_perf_plugin: bool, - pub promise_plugin: bool, + pub plugins: LintPluginOptions, pub framework_hints: FrameworkFlags, } @@ -43,19 +32,7 @@ impl Default for LintOptions { filter: vec![(AllowWarnDeny::Warn, String::from("correctness"))], config_path: None, fix: FixKind::None, - react_plugin: true, - unicorn_plugin: true, - typescript_plugin: true, - oxc_plugin: true, - import_plugin: false, - jsdoc_plugin: false, - jest_plugin: false, - vitest_plugin: false, - jsx_a11y_plugin: false, - nextjs_plugin: false, - react_perf_plugin: false, - promise_plugin: false, - + plugins: LintPluginOptions::default(), framework_hints: FrameworkFlags::default(), } } @@ -94,77 +71,151 @@ impl LintOptions { #[must_use] pub fn with_react_plugin(mut self, yes: bool) -> Self { - self.react_plugin = yes; + self.plugins.react = yes; self } #[must_use] pub fn with_unicorn_plugin(mut self, yes: bool) -> Self { - self.unicorn_plugin = yes; + self.plugins.unicorn = yes; self } #[must_use] pub fn with_typescript_plugin(mut self, yes: bool) -> Self { - self.typescript_plugin = yes; + self.plugins.typescript = yes; self } #[must_use] pub fn with_oxc_plugin(mut self, yes: bool) -> Self { - self.oxc_plugin = yes; + self.plugins.oxc = yes; self } #[must_use] pub fn with_import_plugin(mut self, yes: bool) -> Self { - self.import_plugin = yes; + self.plugins.import = yes; self } #[must_use] pub fn with_jsdoc_plugin(mut self, yes: bool) -> Self { - self.jsdoc_plugin = yes; + self.plugins.jsdoc = yes; self } #[must_use] pub fn with_jest_plugin(mut self, yes: bool) -> Self { - self.jest_plugin = yes; + self.plugins.jest = yes; self } #[must_use] pub fn with_vitest_plugin(mut self, yes: bool) -> Self { - self.vitest_plugin = yes; + self.plugins.vitest = yes; self } #[must_use] pub fn with_jsx_a11y_plugin(mut self, yes: bool) -> Self { - self.jsx_a11y_plugin = yes; + self.plugins.jsx_a11y = yes; self } #[must_use] pub fn with_nextjs_plugin(mut self, yes: bool) -> Self { - self.nextjs_plugin = yes; + self.plugins.nextjs = yes; self } #[must_use] pub fn with_react_perf_plugin(mut self, yes: bool) -> Self { - self.react_perf_plugin = yes; + self.plugins.react_perf = yes; self } #[must_use] pub fn with_promise_plugin(mut self, yes: bool) -> Self { - self.promise_plugin = yes; + self.plugins.promise = yes; self } } +#[derive(Debug)] +#[non_exhaustive] +pub struct LintPluginOptions { + pub react: bool, + pub unicorn: bool, + pub typescript: bool, + pub oxc: bool, + pub import: bool, + pub jsdoc: bool, + pub jest: bool, + pub vitest: bool, + pub jsx_a11y: bool, + pub nextjs: bool, + pub react_perf: bool, + pub promise: bool, +} + +impl Default for LintPluginOptions { + fn default() -> Self { + Self { + react: true, + unicorn: true, + typescript: true, + oxc: true, + import: false, + jsdoc: false, + jest: false, + vitest: false, + jsx_a11y: false, + nextjs: false, + react_perf: false, + promise: false, + } + } +} + +impl LintPluginOptions { + /// Create a new instance with all plugins disabled. + pub fn none() -> Self { + Self { + react: false, + unicorn: false, + typescript: false, + oxc: false, + import: false, + jsdoc: false, + jest: false, + vitest: false, + jsx_a11y: false, + nextjs: false, + react_perf: false, + promise: false, + } + } + + /// Create a new instance with all plugins enabled. + pub fn all() -> Self { + Self { + react: true, + unicorn: true, + typescript: true, + oxc: true, + import: true, + jsdoc: true, + jest: true, + vitest: true, + jsx_a11y: true, + nextjs: true, + react_perf: true, + promise: true, + } + } +} + #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub enum AllowWarnDeny { Allow, // Off @@ -348,27 +399,27 @@ impl LintOptions { RULES .iter() .filter(|rule| match rule.plugin_name() { - "react" => self.react_plugin, - "unicorn" => self.unicorn_plugin, - "typescript" => self.typescript_plugin, - "import" => self.import_plugin, - "jsdoc" => self.jsdoc_plugin, + "react" => self.plugins.react, + "unicorn" => self.plugins.unicorn, + "typescript" => self.plugins.typescript, + "import" => self.plugins.import, + "jsdoc" => self.plugins.jsdoc, "jest" => { - if self.jest_plugin { + if self.plugins.jest { return true; } - if self.vitest_plugin && is_jest_rule_adapted_to_vitest(rule.name()) { + if self.plugins.vitest && is_jest_rule_adapted_to_vitest(rule.name()) { return true; } false } - "vitest" => self.vitest_plugin, - "jsx_a11y" => self.jsx_a11y_plugin, - "nextjs" => self.nextjs_plugin, - "react_perf" => self.react_perf_plugin, - "oxc" => self.oxc_plugin, + "vitest" => self.plugins.vitest, + "jsx_a11y" => self.plugins.jsx_a11y, + "nextjs" => self.plugins.nextjs, + "react_perf" => self.plugins.react_perf, + "oxc" => self.plugins.oxc, "eslint" | "tree_shaking" => true, - "promise" => self.promise_plugin, + "promise" => self.plugins.promise, name => panic!("Unhandled plugin: {name}"), }) .cloned() diff --git a/crates/oxc_linter/src/service.rs b/crates/oxc_linter/src/service.rs index 14ea3c1b09ba0..fbc9041dc3a22 100644 --- a/crates/oxc_linter/src/service.rs +++ b/crates/oxc_linter/src/service.rs @@ -134,7 +134,7 @@ pub struct Runtime { impl Runtime { fn new(linter: Linter, options: LintServiceOptions) -> Self { - let resolver = linter.options().import_plugin.then(|| { + let resolver = linter.options().plugins.import.then(|| { Self::get_resolver(options.tsconfig.or_else(|| Some(options.cwd.join("tsconfig.json")))) }); Self { @@ -278,7 +278,7 @@ impl Runtime { .build_module_record(path.to_path_buf(), program); let module_record = semantic_builder.module_record(); - if self.linter.options().import_plugin { + if self.linter.options().plugins.import { self.module_map.insert( path.to_path_buf().into_boxed_path(), ModuleState::Resolved(Arc::clone(&module_record)), @@ -360,7 +360,7 @@ impl Runtime { } fn init_cache_state(&self, path: &Path) -> bool { - if !self.linter.options().import_plugin { + if !self.linter.options().plugins.import { return false; } @@ -415,7 +415,7 @@ impl Runtime { } fn ignore_path(&self, path: &Path) { - if self.linter.options().import_plugin { + if self.linter.options().plugins.import { self.module_map.insert(path.to_path_buf().into_boxed_path(), ModuleState::Ignored); self.update_cache_state(path); } diff --git a/crates/oxc_linter/src/tester.rs b/crates/oxc_linter/src/tester.rs index c599a84205642..e58d50685fdc0 100644 --- a/crates/oxc_linter/src/tester.rs +++ b/crates/oxc_linter/src/tester.rs @@ -9,8 +9,8 @@ use serde::Deserialize; use serde_json::Value; use crate::{ - fixer::FixKind, rules::RULES, AllowWarnDeny, Fixer, LintOptions, LintService, - LintServiceOptions, Linter, OxlintConfig, RuleEnum, RuleWithSeverity, + fixer::FixKind, options::LintPluginOptions, rules::RULES, AllowWarnDeny, Fixer, LintOptions, + LintService, LintServiceOptions, Linter, OxlintConfig, RuleEnum, RuleWithSeverity, }; #[derive(Eq, PartialEq)] @@ -170,12 +170,13 @@ pub struct Tester { /// See: [insta::Settings::set_snapshot_suffix] snapshot_suffix: Option<&'static str>, current_working_directory: Box, - import_plugin: bool, - jest_plugin: bool, - vitest_plugin: bool, - jsx_a11y_plugin: bool, - nextjs_plugin: bool, - react_perf_plugin: bool, + // import_plugin: bool, + // jest_plugin: bool, + // vitest_plugin: bool, + // jsx_a11y_plugin: bool, + // nextjs_plugin: bool, + // react_perf_plugin: bool, + plugins: LintPluginOptions, } impl Tester { @@ -198,12 +199,7 @@ impl Tester { snapshot: String::new(), snapshot_suffix: None, current_working_directory, - import_plugin: false, - jest_plugin: false, - jsx_a11y_plugin: false, - nextjs_plugin: false, - react_perf_plugin: false, - vitest_plugin: false, + plugins: LintPluginOptions::none(), } } @@ -225,32 +221,32 @@ impl Tester { } pub fn with_import_plugin(mut self, yes: bool) -> Self { - self.import_plugin = yes; + self.plugins.import = yes; self } pub fn with_jest_plugin(mut self, yes: bool) -> Self { - self.jest_plugin = yes; + self.plugins.jest = yes; self } pub fn with_vitest_plugin(mut self, yes: bool) -> Self { - self.vitest_plugin = yes; + self.plugins.vitest = yes; self } pub fn with_jsx_a11y_plugin(mut self, yes: bool) -> Self { - self.jsx_a11y_plugin = yes; + self.plugins.jsx_a11y = yes; self } pub fn with_nextjs_plugin(mut self, yes: bool) -> Self { - self.nextjs_plugin = yes; + self.plugins.nextjs = yes; self } pub fn with_react_perf_plugin(mut self, yes: bool) -> Self { - self.react_perf_plugin = yes; + self.plugins.react_perf = yes; self } @@ -350,12 +346,12 @@ impl Tester { let rule = self.find_rule().read_json(rule_config.unwrap_or_default()); let options = LintOptions::default() .with_fix(fix.into()) - .with_import_plugin(self.import_plugin) - .with_jest_plugin(self.jest_plugin) - .with_vitest_plugin(self.vitest_plugin) - .with_jsx_a11y_plugin(self.jsx_a11y_plugin) - .with_nextjs_plugin(self.nextjs_plugin) - .with_react_perf_plugin(self.react_perf_plugin); + .with_import_plugin(self.plugins.import) + .with_jest_plugin(self.plugins.jest) + .with_vitest_plugin(self.plugins.vitest) + .with_jsx_a11y_plugin(self.plugins.jsx_a11y) + .with_nextjs_plugin(self.plugins.nextjs) + .with_react_perf_plugin(self.plugins.react_perf); let eslint_config = eslint_config .as_ref() .map_or_else(OxlintConfig::default, |v| OxlintConfig::deserialize(v).unwrap()); @@ -363,7 +359,7 @@ impl Tester { .unwrap() .with_rules(vec![RuleWithSeverity::new(rule, AllowWarnDeny::Warn)]) .with_eslint_config(eslint_config); - let path_to_lint = if self.import_plugin { + let path_to_lint = if self.plugins.import { assert!(path.is_none(), "import plugin does not support path"); self.current_working_directory.join(&self.rule_path) } else if let Some(path) = path { @@ -389,7 +385,7 @@ impl Tester { return TestResult::Fixed(fix_result.fixed_code.to_string()); } - let diagnostic_path = if self.import_plugin { + let diagnostic_path = if self.plugins.import { self.rule_path.strip_prefix(&self.current_working_directory).unwrap() } else { &self.rule_path