nu_lint/rules/
mod.rs

1// Individual rule modules
2pub mod avoid_mutable_accumulation;
3pub mod brace_spacing;
4pub mod completion_function_naming;
5pub mod consistent_error_handling;
6pub mod descriptive_error_messages;
7pub mod discourage_bare_ignore;
8pub mod discourage_underscore_commands;
9pub mod exported_function_docs;
10pub mod kebab_case_commands;
11pub mod max_positional_params;
12pub mod missing_command_docs;
13pub mod missing_type_annotation;
14pub mod pipe_spacing;
15pub mod prefer_builtin_commands;
16pub mod prefer_builtin_system_commands;
17pub mod prefer_builtin_text_transforms;
18pub mod prefer_compound_assignment;
19pub mod prefer_each_over_for;
20pub mod prefer_error_make;
21pub mod prefer_is_not_empty;
22pub mod prefer_lines_over_split;
23pub mod prefer_match_over_if_chain;
24pub mod prefer_parse_command;
25pub mod prefer_parse_over_each_split;
26pub mod prefer_range_iteration;
27pub mod prefer_where_over_each_if;
28pub mod screaming_snake_constants;
29pub mod snake_case_variables;
30pub mod unnecessary_mut;
31pub mod unnecessary_variable_before_return;
32
33use std::collections::HashMap;
34
35use crate::rule::{Rule, RuleMetadata};
36
37pub struct RuleRegistry {
38    rules: HashMap<String, Rule>,
39}
40
41impl RuleRegistry {
42    #[must_use]
43    pub fn new() -> Self {
44        Self {
45            rules: HashMap::new(),
46        }
47    }
48
49    pub fn register(&mut self, rule: Rule) {
50        let id = rule.id().to_string();
51        self.rules.insert(id, rule);
52    }
53
54    #[must_use]
55    pub fn get_rule(&self, id: &str) -> Option<&Rule> {
56        self.rules.get(id)
57    }
58
59    pub fn all_rules(&self) -> impl Iterator<Item = &Rule> {
60        self.rules.values()
61    }
62
63    #[must_use]
64    pub fn with_default_rules() -> Self {
65        let mut registry = Self::new();
66
67        // Style rules (Regex-based)
68        registry.register(Rule::Regex(
69            Box::<snake_case_variables::SnakeCaseVariables>::default(),
70        ));
71        registry.register(Rule::Regex(
72            Box::<kebab_case_commands::KebabCaseCommands>::default(),
73        ));
74        registry.register(Rule::Regex(Box::<
75            screaming_snake_constants::ScreamingSnakeConstants,
76        >::default()));
77        registry.register(Rule::Regex(Box::new(brace_spacing::BraceSpacing)));
78        registry.register(Rule::Regex(Box::new(
79            unnecessary_variable_before_return::UnnecessaryVariableBeforeReturn::new(),
80        )));
81        registry.register(Rule::Regex(Box::new(prefer_is_not_empty::PreferIsNotEmpty)));
82        registry.register(Rule::Regex(Box::new(
83            discourage_bare_ignore::DiscouragedBareIgnore::new(),
84        )));
85        registry.register(Rule::Regex(Box::new(
86            discourage_underscore_commands::DiscourageUnderscoreCommands::new(),
87        )));
88        registry.register(Rule::Regex(Box::new(
89            completion_function_naming::CompletionFunctionNaming::new(),
90        )));
91
92        // Style rules (AST-based)
93        registry.register(Rule::Ast(Box::<pipe_spacing::PipeSpacing>::default()));
94        registry.register(Rule::Ast(Box::<
95            prefer_compound_assignment::PreferCompoundAssignment,
96        >::default()));
97        registry.register(Rule::Ast(Box::new(unnecessary_mut::UnnecessaryMut::new())));
98
99        // Best practices rules (Regex-based)
100        registry.register(Rule::Regex(Box::new(
101            prefer_error_make::PreferErrorMake::new(),
102        )));
103        registry.register(Rule::Regex(Box::new(
104            avoid_mutable_accumulation::AvoidMutableAccumulation,
105        )));
106        registry.register(Rule::Regex(Box::new(
107            prefer_range_iteration::PreferRangeIteration::new(),
108        )));
109        registry.register(Rule::Regex(Box::new(
110            prefer_parse_command::PreferParseCommand::new(),
111        )));
112        registry.register(Rule::Regex(Box::new(
113            consistent_error_handling::ConsistentErrorHandling::new(),
114        )));
115        registry.register(Rule::Regex(Box::new(
116            prefer_match_over_if_chain::PreferMatchOverIfChain::new(),
117        )));
118        registry.register(Rule::Regex(Box::new(
119            prefer_each_over_for::PreferEachOverFor::new(),
120        )));
121        registry.register(Rule::Regex(Box::new(
122            descriptive_error_messages::DescriptiveErrorMessages::new(),
123        )));
124        registry.register(Rule::Regex(Box::new(
125            prefer_builtin_commands::PreferBuiltinForCommonCommands::new(),
126        )));
127        registry.register(Rule::Regex(Box::new(
128            prefer_builtin_text_transforms::PreferBuiltinTextTransforms::new(),
129        )));
130        registry.register(Rule::Regex(Box::new(
131            prefer_builtin_system_commands::PreferBuiltinSystemCommands::new(),
132        )));
133
134        // Performance rules (Regex-based)
135        registry.register(Rule::Regex(Box::new(
136            prefer_where_over_each_if::PreferWhereOverEachIf,
137        )));
138        registry.register(Rule::Regex(Box::new(
139            prefer_lines_over_split::PreferLinesOverSplit::new(),
140        )));
141
142        // Performance rules (AST-based)
143        registry.register(Rule::Ast(Box::new(
144            prefer_parse_over_each_split::PreferParseOverEachSplit,
145        )));
146
147        // Documentation rules (Regex-based)
148        registry.register(Rule::Regex(Box::new(
149            missing_command_docs::MissingCommandDocs::new(),
150        )));
151        registry.register(Rule::Regex(Box::new(
152            exported_function_docs::ExportedFunctionDocs,
153        )));
154
155        // Type safety rules (AST-based)
156        registry.register(Rule::Ast(Box::new(
157            missing_type_annotation::MissingTypeAnnotation::new(),
158        )));
159
160        registry
161    }
162}
163
164impl Default for RuleRegistry {
165    fn default() -> Self {
166        Self::new()
167    }
168}