yamllint_rs/rules/
base.rs

1use crate::{LintIssue, Severity};
2use regex::Regex;
3use std::collections::HashMap;
4
5#[derive(Debug, Clone)]
6pub struct BaseRule<T> {
7    pub config: T,
8    pub severity_override: Option<Severity>,
9}
10
11impl<T> BaseRule<T> {
12    pub fn new(config: T) -> Self {
13        Self {
14            config,
15            severity_override: None,
16        }
17    }
18
19    pub fn with_config(config: T) -> Self {
20        Self {
21            config,
22            severity_override: None,
23        }
24    }
25
26    pub fn config(&self) -> &T {
27        &self.config
28    }
29
30    pub fn set_config(&mut self, config: T) {
31        self.config = config;
32    }
33
34    pub fn get_severity(&self, default_severity: Severity) -> Severity {
35        self.severity_override.unwrap_or(default_severity)
36    }
37
38    pub fn set_severity(&mut self, severity: Severity) {
39        self.severity_override = Some(severity);
40    }
41
42    pub fn has_severity_override(&self) -> bool {
43        self.severity_override.is_some()
44    }
45}
46
47#[derive(Debug, Clone)]
48pub struct BaseRuleWithRegex<T> {
49    pub config: T,
50    pub severity_override: Option<Severity>,
51    pub compiled_patterns: HashMap<String, Regex>,
52}
53
54impl<T> BaseRuleWithRegex<T> {
55    pub fn new(config: T) -> Self {
56        Self {
57            config,
58            severity_override: None,
59            compiled_patterns: HashMap::new(),
60        }
61    }
62
63    pub fn with_config(config: T) -> Self {
64        Self {
65            config,
66            severity_override: None,
67            compiled_patterns: HashMap::new(),
68        }
69    }
70
71    pub fn config(&self) -> &T {
72        &self.config
73    }
74
75    pub fn set_config(&mut self, config: T) {
76        self.config = config;
77    }
78
79    pub fn get_severity(&self, default_severity: Severity) -> Severity {
80        self.severity_override.unwrap_or(default_severity)
81    }
82
83    pub fn set_severity(&mut self, severity: Severity) {
84        self.severity_override = Some(severity);
85    }
86
87    pub fn has_severity_override(&self) -> bool {
88        self.severity_override.is_some()
89    }
90
91    pub fn get_or_compile_pattern(&mut self, pattern: &str) -> Result<&Regex, regex::Error> {
92        if !self.compiled_patterns.contains_key(pattern) {
93            let regex = Regex::new(pattern)?;
94            self.compiled_patterns.insert(pattern.to_string(), regex);
95        }
96        Ok(self.compiled_patterns.get(pattern).unwrap())
97    }
98
99    pub fn get_cached_pattern(&self, pattern: &str) -> &Regex {
100        self.compiled_patterns
101            .get(pattern)
102            .expect("Pattern should be cached")
103    }
104}
105
106pub trait LintIssueBuilder {
107    fn create_issue(line: usize, column: usize, message: String, severity: Severity) -> LintIssue {
108        LintIssue {
109            line,
110            column,
111            message,
112            severity,
113        }
114    }
115
116    fn create_line_issue(
117        line: usize,
118        column: usize,
119        message: String,
120        severity: Severity,
121    ) -> LintIssue {
122        Self::create_issue(line, column, message, severity)
123    }
124}
125
126impl<T> LintIssueBuilder for T {}
127
128pub mod utils {
129    pub fn is_empty_or_comment(line: &str) -> bool {
130        let trimmed = line.trim();
131        trimmed.is_empty() || trimmed.starts_with('#')
132    }
133
134    pub fn calculate_indentation(line: &str) -> usize {
135        line.len() - line.trim_start().len()
136    }
137
138    pub fn has_trailing_whitespace(line: &str) -> bool {
139        line.ends_with(' ') || line.ends_with('\t')
140    }
141
142    pub fn count_trailing_whitespace(line: &str) -> usize {
143        line.len() - line.trim_end().len()
144    }
145
146    pub fn join_lines_preserving_newlines(
147        lines: Vec<String>,
148        original_ends_with_newline: bool,
149    ) -> String {
150        if original_ends_with_newline {
151            lines.join("\n") + "\n"
152        } else {
153            lines.join("\n")
154        }
155    }
156}