Skip to main content

driven/templates/
standards.rs

1//! Coding standards templates
2
3use super::{Template, TemplateCategory};
4use crate::{Result, format::RuleCategory, parser::UnifiedRule};
5
6/// Standards template definition
7#[derive(Debug, Clone)]
8pub struct StandardsTemplate {
9    name: String,
10    description: String,
11    rules: Vec<(RuleCategory, u8, String)>,
12    tags: Vec<String>,
13}
14
15impl StandardsTemplate {
16    /// Rust idiomatic patterns
17    pub fn rust_idioms() -> Self {
18        Self {
19            name: "rust-idioms".to_string(),
20            description: "Idiomatic Rust coding patterns".to_string(),
21            rules: vec![
22                (
23                    RuleCategory::Naming,
24                    0,
25                    "Use snake_case for functions and variables".to_string(),
26                ),
27                (
28                    RuleCategory::Naming,
29                    1,
30                    "Use PascalCase for types and traits".to_string(),
31                ),
32                (
33                    RuleCategory::Naming,
34                    2,
35                    "Use SCREAMING_SNAKE_CASE for constants".to_string(),
36                ),
37                (
38                    RuleCategory::Style,
39                    0,
40                    "Prefer &str over String for function parameters".to_string(),
41                ),
42                (
43                    RuleCategory::Style,
44                    1,
45                    "Use iterators instead of manual loops when possible".to_string(),
46                ),
47                (
48                    RuleCategory::Style,
49                    2,
50                    "Prefer Option and Result over nulls and exceptions".to_string(),
51                ),
52                (
53                    RuleCategory::ErrorHandling,
54                    0,
55                    "Use ? operator for error propagation".to_string(),
56                ),
57                (
58                    RuleCategory::ErrorHandling,
59                    1,
60                    "Create custom error types for libraries".to_string(),
61                ),
62                (
63                    RuleCategory::Performance,
64                    0,
65                    "Prefer references over cloning when possible".to_string(),
66                ),
67                (
68                    RuleCategory::Performance,
69                    1,
70                    "Use Cow<str> for potentially owned strings".to_string(),
71                ),
72            ],
73            tags: vec![
74                "rust".to_string(),
75                "idioms".to_string(),
76                "patterns".to_string(),
77            ],
78        }
79    }
80
81    /// Error handling standards
82    pub fn error_handling() -> Self {
83        Self {
84            name: "error-handling".to_string(),
85            description: "Error handling best practices".to_string(),
86            rules: vec![
87                (
88                    RuleCategory::ErrorHandling,
89                    0,
90                    "Never silently swallow errors".to_string(),
91                ),
92                (
93                    RuleCategory::ErrorHandling,
94                    1,
95                    "Provide context with error messages".to_string(),
96                ),
97                (
98                    RuleCategory::ErrorHandling,
99                    2,
100                    "Use structured error types, not strings".to_string(),
101                ),
102                (
103                    RuleCategory::ErrorHandling,
104                    3,
105                    "Handle errors at the appropriate level".to_string(),
106                ),
107                (
108                    RuleCategory::ErrorHandling,
109                    4,
110                    "Log errors with sufficient context for debugging".to_string(),
111                ),
112                (
113                    RuleCategory::ErrorHandling,
114                    5,
115                    "Consider user experience when displaying errors".to_string(),
116                ),
117            ],
118            tags: vec![
119                "errors".to_string(),
120                "handling".to_string(),
121                "exceptions".to_string(),
122            ],
123        }
124    }
125
126    /// Testing standards
127    pub fn testing() -> Self {
128        Self {
129            name: "testing".to_string(),
130            description: "Testing best practices".to_string(),
131            rules: vec![
132                (
133                    RuleCategory::Testing,
134                    0,
135                    "Write tests for all public functions".to_string(),
136                ),
137                (
138                    RuleCategory::Testing,
139                    1,
140                    "Use descriptive test names that explain the scenario".to_string(),
141                ),
142                (
143                    RuleCategory::Testing,
144                    2,
145                    "Follow Arrange-Act-Assert pattern".to_string(),
146                ),
147                (
148                    RuleCategory::Testing,
149                    3,
150                    "Test edge cases and error conditions".to_string(),
151                ),
152                (
153                    RuleCategory::Testing,
154                    4,
155                    "Keep tests independent and isolated".to_string(),
156                ),
157                (
158                    RuleCategory::Testing,
159                    5,
160                    "Prefer integration tests for complex workflows".to_string(),
161                ),
162                (
163                    RuleCategory::Testing,
164                    6,
165                    "Mock external dependencies".to_string(),
166                ),
167            ],
168            tags: vec![
169                "testing".to_string(),
170                "tests".to_string(),
171                "quality".to_string(),
172            ],
173        }
174    }
175
176    /// Documentation standards
177    pub fn documentation() -> Self {
178        Self {
179            name: "documentation".to_string(),
180            description: "Documentation best practices".to_string(),
181            rules: vec![
182                (
183                    RuleCategory::Documentation,
184                    0,
185                    "Document all public APIs".to_string(),
186                ),
187                (
188                    RuleCategory::Documentation,
189                    1,
190                    "Include examples in documentation".to_string(),
191                ),
192                (
193                    RuleCategory::Documentation,
194                    2,
195                    "Document error conditions and panics".to_string(),
196                ),
197                (
198                    RuleCategory::Documentation,
199                    3,
200                    "Keep documentation up to date with code".to_string(),
201                ),
202                (
203                    RuleCategory::Documentation,
204                    4,
205                    "Use proper markdown formatting".to_string(),
206                ),
207                (
208                    RuleCategory::Documentation,
209                    5,
210                    "Link to related documentation".to_string(),
211                ),
212            ],
213            tags: vec![
214                "documentation".to_string(),
215                "docs".to_string(),
216                "comments".to_string(),
217            ],
218        }
219    }
220
221    /// Git conventions
222    pub fn git_conventions() -> Self {
223        Self {
224            name: "git-conventions".to_string(),
225            description: "Git commit and branching conventions".to_string(),
226            rules: vec![
227                (
228                    RuleCategory::Git,
229                    0,
230                    "Use conventional commit messages (feat:, fix:, docs:, etc.)".to_string(),
231                ),
232                (
233                    RuleCategory::Git,
234                    1,
235                    "Keep commits atomic and focused".to_string(),
236                ),
237                (
238                    RuleCategory::Git,
239                    2,
240                    "Write meaningful commit messages".to_string(),
241                ),
242                (
243                    RuleCategory::Git,
244                    3,
245                    "Reference issues in commits when applicable".to_string(),
246                ),
247                (
248                    RuleCategory::Git,
249                    4,
250                    "Use feature branches for development".to_string(),
251                ),
252                (
253                    RuleCategory::Git,
254                    5,
255                    "Rebase to keep history clean".to_string(),
256                ),
257            ],
258            tags: vec![
259                "git".to_string(),
260                "commits".to_string(),
261                "branching".to_string(),
262            ],
263        }
264    }
265}
266
267impl Template for StandardsTemplate {
268    fn name(&self) -> &str {
269        &self.name
270    }
271
272    fn description(&self) -> &str {
273        &self.description
274    }
275
276    fn category(&self) -> TemplateCategory {
277        TemplateCategory::Standards
278    }
279
280    fn expand(&self) -> Result<Vec<UnifiedRule>> {
281        Ok(self
282            .rules
283            .iter()
284            .map(|(category, priority, description)| UnifiedRule::Standard {
285                category: *category,
286                priority: *priority,
287                description: description.clone(),
288                pattern: None,
289            })
290            .collect())
291    }
292
293    fn tags(&self) -> Vec<&str> {
294        self.tags.iter().map(|s| s.as_str()).collect()
295    }
296}
297
298#[cfg(test)]
299mod tests {
300    use super::*;
301
302    #[test]
303    fn test_rust_idioms() {
304        let template = StandardsTemplate::rust_idioms();
305        assert_eq!(template.name(), "rust-idioms");
306        assert_eq!(template.category(), TemplateCategory::Standards);
307
308        let rules = template.expand().unwrap();
309        assert!(!rules.is_empty());
310    }
311
312    #[test]
313    fn test_all_standards() {
314        let standards = vec![
315            StandardsTemplate::rust_idioms(),
316            StandardsTemplate::error_handling(),
317            StandardsTemplate::testing(),
318            StandardsTemplate::documentation(),
319            StandardsTemplate::git_conventions(),
320        ];
321
322        for standard in standards {
323            let rules = standard.expand().unwrap();
324            assert!(
325                !rules.is_empty(),
326                "Standard {} should have rules",
327                standard.name()
328            );
329        }
330    }
331}