diff --git a/crates/biome_analyze/src/lib.rs b/crates/biome_analyze/src/lib.rs index 5f3d5c36eb31..ed5e3e2ad914 100644 --- a/crates/biome_analyze/src/lib.rs +++ b/crates/biome_analyze/src/lib.rs @@ -806,7 +806,7 @@ impl<'a> RuleFilter<'a> { } } /// Return `true` if the group `G` matches this filter - fn match_group(self) -> bool { + pub fn match_group(self) -> bool { match self { RuleFilter::Group(group) => group == G::NAME, RuleFilter::Rule(group, _) => group == G::NAME, @@ -814,7 +814,7 @@ impl<'a> RuleFilter<'a> { } /// Return `true` if the rule `R` matches this filter - fn match_rule(self) -> bool + pub fn match_rule(self) -> bool where R: Rule, { diff --git a/crates/biome_configuration/src/linter/mod.rs b/crates/biome_configuration/src/linter/mod.rs index 9dba813c1a36..8982747ab345 100644 --- a/crates/biome_configuration/src/linter/mod.rs +++ b/crates/biome_configuration/src/linter/mod.rs @@ -311,6 +311,15 @@ impl From for RuleFilter<'static> { } } +impl<'a> From<&'a RuleSelector> for RuleFilter<'static> { + fn from(value: &'a RuleSelector) -> Self { + match value { + RuleSelector::Group(group) => RuleFilter::Group(group.as_str()), + RuleSelector::Rule(group, name) => RuleFilter::Rule(group.as_str(), name), + } + } +} + impl FromStr for RuleSelector { type Err = &'static str; fn from_str(selector: &str) -> Result { diff --git a/crates/biome_service/src/file_handlers/css.rs b/crates/biome_service/src/file_handlers/css.rs index a7a469047a0d..018e4f401b4c 100644 --- a/crates/biome_service/src/file_handlers/css.rs +++ b/crates/biome_service/src/file_handlers/css.rs @@ -1,6 +1,6 @@ use super::{ - is_diagnostic_error, CodeActionsParams, ExtensionHandler, FixAllParams, LintParams, - LintResults, ParseResult, SearchCapabilities, SyntaxVisitor, + is_diagnostic_error, ActionVisitor, CodeActionsParams, ExtensionHandler, FixAllParams, + LintParams, LintResults, LintVisitor, ParseResult, SearchCapabilities, SyntaxVisitor, }; use crate::configuration::to_analyzer_rules; use crate::file_handlers::DebugCapabilities; @@ -21,7 +21,7 @@ use biome_analyze::{ AnalysisFilter, AnalyzerConfiguration, AnalyzerOptions, ControlFlow, Never, RuleCategoriesBuilder, RuleCategory, RuleError, }; -use biome_css_analyze::analyze; +use biome_css_analyze::{analyze, visit_registry}; use biome_css_formatter::context::CssFormatOptions; use biome_css_formatter::format_node; use biome_css_parser::CssParserOptions; @@ -31,7 +31,6 @@ use biome_formatter::{ FormatError, IndentStyle, IndentWidth, LineEnding, LineWidth, Printed, QuoteStyle, }; use biome_fs::BiomePath; -use biome_js_analyze::visit_registry; use biome_parser::AnyParse; use biome_rowan::{AstNode, NodeCache}; use biome_rowan::{TextRange, TextSize, TokenAtOffset}; @@ -338,42 +337,34 @@ fn lint(params: LintParams) -> LintResults { let analyzer_options = workspace_settings.analyzer_options::(params.path, ¶ms.language); let tree = params.parse.tree(); - let mut diagnostics = params.parse.into_diagnostics(); let has_only_filter = !params.only.is_empty(); - let mut rules = None; - - let mut enabled_rules = if let Some(settings) = params.workspace.settings() { - // Compute final rules (taking `overrides` into account) - rules = settings.as_rules(params.path.as_path()); - - if has_only_filter { - params - .only - .into_iter() - .map(|selector| selector.into()) - .collect::>() - } else { - rules - .as_ref() - .map(|rules| rules.as_enabled_rules()) - .unwrap_or_default() - .into_iter() - .collect::>() - } - } else { - Vec::new() - }; + let rules = params + .workspace + .settings() + .as_ref() + .and_then(|settings| settings.as_rules(params.path.as_path())); + let mut enabled_rules = vec![]; + let mut disabled_rules = vec![]; let mut syntax_visitor = SyntaxVisitor::default(); + let mut lint_visitor = LintVisitor::new( + ¶ms.only, + ¶ms.skip, + params.workspace.settings(), + params.path.as_path(), + ); + let mut action_visitor = + ActionVisitor::new(params.workspace.settings(), ¶ms.categories); visit_registry(&mut syntax_visitor); + visit_registry(&mut lint_visitor); + visit_registry(&mut action_visitor); enabled_rules.extend(syntax_visitor.enabled_rules); - - let disabled_rules = params - .skip - .into_iter() - .map(|selector| selector.into()) - .collect::>(); + let (lint_enabled_rules, lint_disabled_rules) = lint_visitor.finish(); + enabled_rules.extend(lint_enabled_rules); + disabled_rules.extend(lint_disabled_rules); + enabled_rules.extend(action_visitor.enabled_rules); + let mut diagnostics = params.parse.into_diagnostics(); let filter = AnalysisFilter { categories: params.categories, @@ -540,32 +531,18 @@ pub(crate) fn fix_all(params: FixAllParams) -> Result>() - } else { - rules - .as_ref() - .map(|rules| rules.as_enabled_rules()) - .unwrap_or_default() - .into_iter() - .collect::>() - }; - + let mut lint_visitor = LintVisitor::new( + ¶ms.only, + ¶ms.skip, + params.workspace.settings(), + params.biome_path.as_path(), + ); let mut syntax_visitor = SyntaxVisitor::default(); + visit_registry(&mut lint_visitor); visit_registry(&mut syntax_visitor); + let (mut enabled_rules, disabled_rules) = lint_visitor.finish(); enabled_rules.extend(syntax_visitor.enabled_rules); - let disabled_rules = params - .skip - .into_iter() - .map(|selector| selector.into()) - .collect::>(); - let filter = AnalysisFilter { categories: RuleCategoriesBuilder::default() .with_syntax() diff --git a/crates/biome_service/src/file_handlers/graphql.rs b/crates/biome_service/src/file_handlers/graphql.rs index 630fa04c9e58..c3c3c5ae1041 100644 --- a/crates/biome_service/src/file_handlers/graphql.rs +++ b/crates/biome_service/src/file_handlers/graphql.rs @@ -1,6 +1,7 @@ use super::{ - is_diagnostic_error, CodeActionsParams, DocumentFileSource, ExtensionHandler, FixAllParams, - LintParams, LintResults, ParseResult, SearchCapabilities, SyntaxVisitor, + is_diagnostic_error, ActionVisitor, CodeActionsParams, DocumentFileSource, ExtensionHandler, + FixAllParams, LintParams, LintResults, LintVisitor, ParseResult, SearchCapabilities, + SyntaxVisitor, }; use crate::file_handlers::DebugCapabilities; use crate::file_handlers::{ @@ -24,12 +25,11 @@ use biome_formatter::{ QuoteStyle, }; use biome_fs::BiomePath; -use biome_graphql_analyze::analyze; +use biome_graphql_analyze::{analyze, visit_registry}; use biome_graphql_formatter::context::GraphqlFormatOptions; use biome_graphql_formatter::format_node; use biome_graphql_parser::parse_graphql_with_cache; use biome_graphql_syntax::{GraphqlLanguage, GraphqlRoot, GraphqlSyntaxNode, TextRange, TextSize}; -use biome_js_analyze::visit_registry; use biome_parser::AnyParse; use biome_rowan::{AstNode, NodeCache, TokenAtOffset}; use std::borrow::Cow; @@ -296,42 +296,34 @@ fn lint(params: LintParams) -> LintResults { let analyzer_options = workspace_settings .analyzer_options::(params.path, ¶ms.language); let tree = params.parse.tree(); - let mut diagnostics = params.parse.into_diagnostics(); let has_only_filter = !params.only.is_empty(); - let mut rules = None; - - let mut enabled_rules = if let Some(settings) = params.workspace.settings() { - // Compute final rules (taking `overrides` into account) - rules = settings.as_rules(params.path.as_path()); - - if has_only_filter { - params - .only - .into_iter() - .map(|selector| selector.into()) - .collect::>() - } else { - rules - .as_ref() - .map(|rules| rules.as_enabled_rules()) - .unwrap_or_default() - .into_iter() - .collect::>() - } - } else { - Vec::new() - }; + let rules = params + .workspace + .settings() + .as_ref() + .and_then(|settings| settings.as_rules(params.path.as_path())); + let mut enabled_rules = vec![]; + let mut disabled_rules = vec![]; let mut syntax_visitor = SyntaxVisitor::default(); + let mut lint_visitor = LintVisitor::new( + ¶ms.only, + ¶ms.skip, + params.workspace.settings(), + params.path.as_path(), + ); + let mut action_visitor = + ActionVisitor::new(params.workspace.settings(), ¶ms.categories); visit_registry(&mut syntax_visitor); + visit_registry(&mut lint_visitor); + visit_registry(&mut action_visitor); enabled_rules.extend(syntax_visitor.enabled_rules); - - let disabled_rules = params - .skip - .into_iter() - .map(|selector| selector.into()) - .collect::>(); + let (lint_enabled_rules, lint_disabled_rules) = lint_visitor.finish(); + enabled_rules.extend(lint_enabled_rules); + disabled_rules.extend(lint_disabled_rules); + enabled_rules.extend(action_visitor.enabled_rules); + let mut diagnostics = params.parse.into_diagnostics(); let filter = AnalysisFilter { categories: params.categories, @@ -492,31 +484,19 @@ pub(crate) fn fix_all(params: FixAllParams) -> Result>() - } else { - rules - .as_ref() - .map(|rules| rules.as_enabled_rules()) - .unwrap_or_default() - .into_iter() - .collect::>() - }; + let mut lint_visitor = LintVisitor::new( + ¶ms.only, + ¶ms.skip, + params.workspace.settings(), + params.biome_path.as_path(), + ); let mut syntax_visitor = SyntaxVisitor::default(); + visit_registry(&mut lint_visitor); visit_registry(&mut syntax_visitor); + let (mut enabled_rules, disabled_rules) = lint_visitor.finish(); enabled_rules.extend(syntax_visitor.enabled_rules); - let disabled_rules = params - .skip - .into_iter() - .map(|selector| selector.into()) - .collect::>(); - let filter = AnalysisFilter { categories: RuleCategoriesBuilder::default() .with_syntax() diff --git a/crates/biome_service/src/file_handlers/javascript.rs b/crates/biome_service/src/file_handlers/javascript.rs index f66648634a6a..b7dc321b5cb4 100644 --- a/crates/biome_service/src/file_handlers/javascript.rs +++ b/crates/biome_service/src/file_handlers/javascript.rs @@ -1,7 +1,7 @@ use super::{ - search, AnalyzerCapabilities, CodeActionsParams, DebugCapabilities, ExtensionHandler, - FormatterCapabilities, LintParams, LintResults, ParseResult, ParserCapabilities, - SearchCapabilities, SyntaxVisitor, + search, ActionVisitor, AnalyzerCapabilities, CodeActionsParams, DebugCapabilities, + ExtensionHandler, FormatterCapabilities, LintParams, LintResults, LintVisitor, ParseResult, + ParserCapabilities, SearchCapabilities, SyntaxVisitor, }; use crate::configuration::to_analyzer_rules; use crate::diagnostics::extension_error; @@ -416,48 +416,35 @@ pub(crate) fn lint(params: LintParams) -> LintResults { }; }; let tree = params.parse.tree(); - let mut diagnostics = params.parse.into_diagnostics(); let analyzer_options = ¶ms .workspace .analyzer_options::(params.path, ¶ms.language); - let mut rules = None; - let mut organize_imports_enabled = true; - if let Some(settings) = params.workspace.settings() { - // Compute final rules (taking `overrides` into account) - rules = settings.as_rules(params.path.as_path()); - organize_imports_enabled = settings.organize_imports.enabled; - } - - let has_only_filter = !params.only.is_empty(); - let mut enabled_rules = if has_only_filter { - params - .only - .into_iter() - .map(|selector| selector.into()) - .collect::>() - } else { - let mut enabled_rules = rules - .as_ref() - .map(|rules| rules.as_enabled_rules()) - .unwrap_or_default() - .into_iter() - .collect::>(); - if organize_imports_enabled && !params.categories.is_syntax() { - enabled_rules.push(RuleFilter::Rule("correctness", "organizeImports")); - } - enabled_rules - }; + let rules = params + .workspace + .settings() + .as_ref() + .and_then(|settings| settings.as_rules(params.path.as_path())); + let mut enabled_rules = vec![]; + let mut disabled_rules = vec![]; let mut syntax_visitor = SyntaxVisitor::default(); + let mut lint_visitor = LintVisitor::new( + ¶ms.only, + ¶ms.skip, + params.workspace.settings(), + params.path.as_path(), + ); + let mut action_visitor = + ActionVisitor::new(params.workspace.settings(), ¶ms.categories); visit_registry(&mut syntax_visitor); + visit_registry(&mut lint_visitor); + visit_registry(&mut action_visitor); enabled_rules.extend(syntax_visitor.enabled_rules); - - let disabled_rules = params - .skip - .into_iter() - .map(|selector| selector.into()) - .collect::>(); + let (lint_enabled_rules, lint_disabled_rules) = lint_visitor.finish(); + enabled_rules.extend(lint_enabled_rules); + disabled_rules.extend(lint_disabled_rules); + enabled_rules.extend(action_visitor.enabled_rules); let filter = AnalysisFilter { categories: params.categories, @@ -466,12 +453,10 @@ pub(crate) fn lint(params: LintParams) -> LintResults { range: None, }; - // Do not report unused suppression comment diagnostics if: - // - it is a syntax-only analyzer pass, or - // - if a single rule is run. let ignores_suppression_comment = - !filter.categories.contains(RuleCategory::Lint) || has_only_filter; + !filter.categories.contains(RuleCategory::Lint) || !params.only.is_empty(); + let mut diagnostics = params.parse.into_diagnostics(); let mut diagnostic_count = diagnostics.len() as u32; let mut errors = diagnostics .iter() @@ -669,25 +654,19 @@ pub(crate) fn fix_all(params: FixAllParams) -> Result>() - } else { - rules - .as_ref() - .map(|rules| rules.as_enabled_rules()) - .unwrap_or_default() - .into_iter() - .collect::>() - }; - let disabled_rules = params - .skip - .into_iter() - .map(|selector| selector.into()) - .collect::>(); + + let mut lint_visitor = LintVisitor::new( + ¶ms.only, + ¶ms.skip, + params.workspace.settings(), + params.biome_path.as_path(), + ); + let mut syntax_visitor = SyntaxVisitor::default(); + visit_registry(&mut lint_visitor); + visit_registry(&mut syntax_visitor); + let (mut enabled_rules, disabled_rules) = lint_visitor.finish(); + enabled_rules.extend(syntax_visitor.enabled_rules); + let filter = AnalysisFilter { categories: RuleCategoriesBuilder::default() .with_syntax() diff --git a/crates/biome_service/src/file_handlers/json.rs b/crates/biome_service/src/file_handlers/json.rs index 07bf6afa860e..8dab8659fc4e 100644 --- a/crates/biome_service/src/file_handlers/json.rs +++ b/crates/biome_service/src/file_handlers/json.rs @@ -2,8 +2,8 @@ use std::borrow::Cow; use std::ffi::OsStr; use super::{ - CodeActionsParams, DocumentFileSource, ExtensionHandler, ParseResult, SearchCapabilities, - SyntaxVisitor, + ActionVisitor, CodeActionsParams, DocumentFileSource, ExtensionHandler, LintVisitor, + ParseResult, SearchCapabilities, SyntaxVisitor, }; use crate::configuration::to_analyzer_rules; use crate::file_handlers::DebugCapabilities; @@ -29,8 +29,7 @@ use biome_deserialize::json::deserialize_from_json_ast; use biome_diagnostics::{category, Diagnostic, DiagnosticExt, Severity}; use biome_formatter::{FormatError, IndentStyle, IndentWidth, LineEnding, LineWidth, Printed}; use biome_fs::{BiomePath, ConfigName, ROME_JSON}; -use biome_json_analyze::analyze; -use biome_json_analyze::visit_registry; +use biome_json_analyze::{analyze, visit_registry}; use biome_json_formatter::context::{JsonFormatOptions, TrailingCommas}; use biome_json_formatter::format_node; use biome_json_parser::JsonParserOptions; @@ -318,8 +317,38 @@ fn lint(params: LintParams) -> LintResults { }; }; let root: JsonRoot = params.parse.tree(); - let mut diagnostics = params.parse.into_diagnostics(); + let analyzer_options = ¶ms + .workspace + .analyzer_options::(params.path, ¶ms.language); + + let has_only_filter = !params.only.is_empty(); + let rules = params + .workspace + .settings() + .as_ref() + .and_then(|settings| settings.as_rules(params.path.as_path())); + + let mut enabled_rules = vec![]; + let mut disabled_rules = vec![]; + let mut syntax_visitor = SyntaxVisitor::default(); + let mut lint_visitor = LintVisitor::new( + ¶ms.only, + ¶ms.skip, + params.workspace.settings(), + params.path.as_path(), + ); + let mut action_visitor = + ActionVisitor::new(params.workspace.settings(), ¶ms.categories); + visit_registry(&mut syntax_visitor); + visit_registry(&mut lint_visitor); + visit_registry(&mut action_visitor); + enabled_rules.extend(syntax_visitor.enabled_rules); + let (lint_enabled_rules, lint_disabled_rules) = lint_visitor.finish(); + enabled_rules.extend(lint_enabled_rules); + disabled_rules.extend(lint_disabled_rules); + enabled_rules.extend(action_visitor.enabled_rules); + let mut diagnostics = params.parse.into_diagnostics(); // if we're parsing the `biome.json` file, we deserialize it, so we can emit diagnostics for // malformed configuration if params.path.ends_with(ROME_JSON) @@ -335,39 +364,6 @@ fn lint(params: LintParams) -> LintResults { .collect::>(), ); } - - let analyzer_options = ¶ms - .workspace - .analyzer_options::(params.path, ¶ms.language); - - let mut rules = None; - if let Some(settings) = params.workspace.settings() { - rules = settings.as_rules(params.path.as_path()); - } - - let has_only_filter = !params.only.is_empty(); - let mut enabled_rules = if has_only_filter { - params - .only - .into_iter() - .map(|selector| selector.into()) - .collect::>() - } else { - rules - .as_ref() - .map(|rules| rules.as_enabled_rules()) - .unwrap_or_default() - .into_iter() - .collect::>() - }; - let mut syntax_visitor = SyntaxVisitor::default(); - biome_js_analyze::visit_registry(&mut syntax_visitor); - enabled_rules.extend(syntax_visitor.enabled_rules); - let disabled_rules = params - .skip - .into_iter() - .map(|selector| selector.into()) - .collect::>(); let filter = AnalysisFilter { categories: params.categories, enabled_rules: Some(enabled_rules.as_slice()), diff --git a/crates/biome_service/src/file_handlers/mod.rs b/crates/biome_service/src/file_handlers/mod.rs index 7e9b76fb13ba..9733a2574c2e 100644 --- a/crates/biome_service/src/file_handlers/mod.rs +++ b/crates/biome_service/src/file_handlers/mod.rs @@ -393,6 +393,7 @@ pub struct DebugCapabilities { pub(crate) debug_formatter_ir: Option, } +#[derive(Debug)] pub(crate) struct LintParams<'a> { pub(crate) parse: AnyParse, pub(crate) workspace: &'a WorkspaceSettingsHandle<'a>, @@ -733,6 +734,286 @@ impl<'a> RegistryVisitor for SyntaxVisitor<'a> { } } +/// Type meant to register all the lint rules for each language supported by Biome +/// +#[derive(Debug)] +pub(crate) struct LintVisitor<'a, 'b> { + pub(crate) enabled_rules: Vec>, + pub(crate) disabled_rules: Vec>, + // lint_params: &'b LintParams<'a>, + only: &'b Vec, + skip: &'b Vec, + settings: Option<&'b Settings>, + path: &'b Path, +} + +impl<'a, 'b> LintVisitor<'a, 'b> { + pub(crate) fn new( + only: &'b Vec, + skip: &'b Vec, + settings: Option<&'b Settings>, + path: &'b Path, + ) -> Self { + Self { + enabled_rules: vec![], + disabled_rules: vec![], + only, + skip, + settings, + path, + } + } + + fn finish(mut self) -> (Vec>, Vec>) { + let has_only_filter = !self.only.is_empty(); + let enabled_rules = if !has_only_filter { + self.settings + .and_then(|settings| settings.as_rules(self.path)) + .as_ref() + .map(|rules| rules.as_enabled_rules()) + .unwrap_or_default() + .into_iter() + .collect::>() + } else { + vec![] + }; + self.enabled_rules.extend(enabled_rules); + (self.enabled_rules, self.disabled_rules) + } + + fn push_rule(&mut self) + where + R: Rule> + 'static, + { + // Do not report unused suppression comment diagnostics if: + // - it is a syntax-only analyzer pass, or + // - if a single rule is run. + for selector in self.only { + let filter = RuleFilter::from(selector); + if filter.match_rule::() { + self.enabled_rules.push(filter) + } + } + for selector in self.skip { + let filter = RuleFilter::from(selector); + if filter.match_rule::() { + self.disabled_rules.push(filter) + } + } + } +} + +impl<'a, 'b> RegistryVisitor for LintVisitor<'a, 'b> { + fn record_category>(&mut self) { + if C::CATEGORY == RuleCategory::Lint { + C::record_groups(self) + } + } + + fn record_group>(&mut self) { + for selector in self.only { + if RuleFilter::from(selector).match_group::() { + G::record_rules(self) + } + } + + for selector in self.skip { + if RuleFilter::from(selector).match_group::() { + G::record_rules(self) + } + } + } + + fn record_rule(&mut self) + where + R: Rule> + 'static, + { + self.push_rule::::Language>() + } +} +impl<'a, 'b> RegistryVisitor for LintVisitor<'a, 'b> { + fn record_category>(&mut self) { + if C::CATEGORY == RuleCategory::Lint { + C::record_groups(self) + } + } + + fn record_group>(&mut self) { + for selector in self.only { + if RuleFilter::from(selector).match_group::() { + G::record_rules(self) + } + } + + for selector in self.skip { + if RuleFilter::from(selector).match_group::() { + G::record_rules(self) + } + } + } + + fn record_rule(&mut self) + where + R: Rule> + + 'static, + { + self.push_rule::::Language>() + } +} + +impl<'a, 'b> RegistryVisitor for LintVisitor<'a, 'b> { + fn record_category>(&mut self) { + if C::CATEGORY == RuleCategory::Lint { + C::record_groups(self) + } + } + + fn record_group>(&mut self) { + for selector in self.only { + if RuleFilter::from(selector).match_group::() { + G::record_rules(self) + } + } + + for selector in self.skip { + if RuleFilter::from(selector).match_group::() { + G::record_rules(self) + } + } + } + + fn record_rule(&mut self) + where + R: Rule> + + 'static, + { + self.push_rule::::Language>() + } +} + +impl<'a, 'b> RegistryVisitor for LintVisitor<'a, 'b> { + fn record_category>(&mut self) { + if C::CATEGORY == RuleCategory::Lint { + C::record_groups(self) + } + } + + fn record_group>(&mut self) { + for selector in self.only { + if RuleFilter::from(selector).match_group::() { + G::record_rules(self) + } + } + + for selector in self.skip { + if RuleFilter::from(selector).match_group::() { + G::record_rules(self) + } + } + } + + fn record_rule(&mut self) + where + R: Rule> + + 'static, + { + self.push_rule::::Language>() + } +} + +struct ActionVisitor<'a, 'b> { + settings: Option<&'b Settings>, + rule_categories: &'b RuleCategories, + pub(crate) enabled_rules: Vec>, + import_sorting: RuleFilter<'a>, +} + +impl<'a, 'b> ActionVisitor<'a, 'b> { + pub(crate) fn new(settings: Option<&'b Settings>, rule_categories: &'b RuleCategories) -> Self { + Self { + enabled_rules: vec![], + settings, + rule_categories, + import_sorting: RuleFilter::Rule("correctness", "organizeImports"), + } + } +} + +impl<'a, 'b> RegistryVisitor for ActionVisitor<'a, 'b> { + fn record_category>(&mut self) { + if C::CATEGORY == RuleCategory::Action { + C::record_groups(self) + } + } + + fn record_rule(&mut self) + where + R: Rule> + 'static, + { + let organize_imports_enabled = self + .settings + .map(|settings| settings.organize_imports.enabled) + .unwrap_or_default(); + if organize_imports_enabled + && !self.rule_categories.is_syntax() + && self.import_sorting.match_rule::() + { + self.enabled_rules.push(self.import_sorting); + } + } +} + +impl<'a, 'b> RegistryVisitor for ActionVisitor<'a, 'b> { + fn record_category>(&mut self) { + if C::CATEGORY == RuleCategory::Action { + C::record_groups(self) + } + } + + fn record_rule(&mut self) + where + R: Rule> + + 'static, + { + self.enabled_rules + .push(RuleFilter::Rule(R::Group::NAME, R::METADATA.name)) + } +} + +impl<'a, 'b> RegistryVisitor for ActionVisitor<'a, 'b> { + fn record_category>(&mut self) { + if C::CATEGORY == RuleCategory::Action { + C::record_groups(self) + } + } + + fn record_rule(&mut self) + where + R: Rule> + + 'static, + { + self.enabled_rules + .push(RuleFilter::Rule(R::Group::NAME, R::METADATA.name)) + } +} + +impl<'a, 'b> RegistryVisitor for ActionVisitor<'a, 'b> { + fn record_category>(&mut self) { + if C::CATEGORY == RuleCategory::Action { + C::record_groups(self) + } + } + + fn record_rule(&mut self) + where + R: Rule> + + 'static, + { + self.enabled_rules + .push(RuleFilter::Rule(R::Group::NAME, R::METADATA.name)) + } +} + #[test] fn test_vue_script_lang() { const VUE_JS_SCRIPT_OPENING_TAG: &str = r#"