1use super::{Template, TemplateCategory};
4use crate::{Result, format::RuleCategory, parser::UnifiedRule};
5
6#[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 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 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 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 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 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}