1#![warn(missing_docs)]
3use super::types::ErrorCategory;
15use std::collections::HashMap;
16
17#[derive(Debug, Clone)]
19pub struct FixTemplate {
20 pub name: String,
22 pub description: String,
24 pub template: String,
26 pub applicable_categories: Vec<ErrorCategory>,
28 pub target_error_codes: Vec<String>,
30}
31
32impl FixTemplate {
33 pub fn new(
40 name: impl Into<String>,
41 description: impl Into<String>,
42 template: impl Into<String>,
43 ) -> Self {
44 Self {
45 name: name.into(),
46 description: description.into(),
47 template: template.into(),
48 applicable_categories: Vec::new(),
49 target_error_codes: Vec::new(),
50 }
51 }
52
53 pub fn add_category(mut self, category: ErrorCategory) -> Self {
58 self.applicable_categories.push(category);
59 self
60 }
61
62 pub fn add_error_code(mut self, code: impl Into<String>) -> Self {
67 self.target_error_codes.push(code.into());
68 self
69 }
70
71 pub fn apply(&self, params: &HashMap<String, String>) -> String {
79 let mut result = self.template.clone();
80 for (key, value) in params {
81 result = result.replace(&format!("{{{}}}", key), value);
82 }
83 result
84 }
85}
86
87#[derive(Debug, Default)]
89pub struct SyntaxGenerator;
90
91impl SyntaxGenerator {
92 pub fn new() -> Self {
94 Self
95 }
96
97 pub fn generate_trait_impl(
107 &self,
108 trait_name: &str,
109 type_name: &str,
110 methods: HashMap<String, String>,
111 ) -> String {
112 let mut impl_body = String::new();
113 for (method_name, method_body) in methods {
114 impl_body.push_str(&format!(
115 " fn {}() {{\n {}\n }}\n\n",
116 method_name, method_body
117 ));
118 }
119
120 format!(
121 "impl {} for {} {{\n{}}}\n",
122 trait_name, type_name, impl_body
123 )
124 }
125
126 pub fn generate_import(&self, path: &str, items: &[&str]) -> String {
135 if items.is_empty() {
136 format!("use {};", path)
137 } else if items.len() == 1 {
138 format!("use {}::{};", path, items[0])
139 } else {
140 let items_str = items.join(", ");
141 format!("use {}::{{{}}};", path, items_str)
142 }
143 }
144
145 pub fn generate_struct(
155 &self,
156 struct_name: &str,
157 fields: HashMap<String, String>,
158 derive_traits: Option<Vec<&str>>,
159 ) -> String {
160 let mut struct_def = String::new();
161
162 if let Some(traits) = derive_traits {
164 if !traits.is_empty() {
165 struct_def.push_str(&format!("#[derive({})]\n", traits.join(", ")));
166 }
167 }
168
169 struct_def.push_str(&format!("pub struct {} {{\n", struct_name));
170
171 for (field_name, field_type) in fields {
173 struct_def.push_str(&format!(" pub {}: {},\n", field_name, field_type));
174 }
175
176 struct_def.push_str("}\n");
177 struct_def
178 }
179
180 pub fn generate_enum(
190 &self,
191 enum_name: &str,
192 variants: HashMap<String, Option<String>>,
193 derive_traits: Option<Vec<&str>>,
194 ) -> String {
195 let mut enum_def = String::new();
196
197 if let Some(traits) = derive_traits {
199 if !traits.is_empty() {
200 enum_def.push_str(&format!("#[derive({})]\n", traits.join(", ")));
201 }
202 }
203
204 enum_def.push_str(&format!("pub enum {} {{\n", enum_name));
205
206 for (variant_name, variant_type) in variants {
208 if let Some(type_str) = variant_type {
209 enum_def.push_str(&format!(" {}({}),\n", variant_name, type_str));
210 } else {
211 enum_def.push_str(&format!(" {},\n", variant_name));
212 }
213 }
214
215 enum_def.push_str("}\n");
216 enum_def
217 }
218
219 pub fn generate_function(
230 &self,
231 fn_name: &str,
232 params: HashMap<String, String>,
233 return_type: Option<&str>,
234 body: &str,
235 ) -> String {
236 let mut param_str = String::new();
237 for (param_name, param_type) in params {
238 if !param_str.is_empty() {
239 param_str.push_str(", ");
240 }
241 param_str.push_str(&format!("{}: {}", param_name, param_type));
242 }
243
244 let return_type_str = if let Some(rt) = return_type {
245 format!(" -> {}", rt)
246 } else {
247 String::new()
248 };
249
250 format!(
251 "fn {}({}){} {{\n {}\n}}\n",
252 fn_name, param_str, return_type_str, body
253 )
254 }
255
256 pub fn generate_method_call(&self, object: &str, method_name: &str, args: &[&str]) -> String {
266 let args_str = args.join(", ");
267 format!("{}.{}({})", object, method_name, args_str)
268 }
269}
270
271#[derive(Debug, Default)]
273pub struct TemplateRegistry {
274 templates: HashMap<String, FixTemplate>,
276}
277
278impl TemplateRegistry {
279 pub fn new() -> Self {
281 Self {
282 templates: HashMap::new(),
283 }
284 }
285
286 pub fn register_template(&mut self, template: FixTemplate) {
291 self.templates.insert(template.name.clone(), template);
292 }
293
294 pub fn get_template(&self, name: &str) -> Option<&FixTemplate> {
302 self.templates.get(name)
303 }
304
305 pub fn get_templates_for_category(&self, category: ErrorCategory) -> Vec<&FixTemplate> {
313 self.templates
314 .values()
315 .filter(|t| t.applicable_categories.contains(&category))
316 .collect()
317 }
318
319 pub fn get_templates_for_error_code(&self, error_code: &str) -> Vec<&FixTemplate> {
327 self.templates
328 .values()
329 .filter(|t| t.target_error_codes.iter().any(|c| c == error_code))
330 .collect()
331 }
332}
333
334#[cfg(test)]
335mod tests {
336 use super::*;
337 use std::collections::HashMap;
338
339 #[test]
340 fn test_fix_template_creation_and_application() {
341 let template = FixTemplate::new(
343 "test_template",
344 "A test template for fixing errors",
345 "fn {function_name}({param_name}: {param_type}) -> {return_type} {\n // Implementation\n {body}\n}"
346 )
347 .add_category(ErrorCategory::Validation)
348 .add_error_code("E0001");
349
350 assert_eq!(template.name, "test_template");
352 assert_eq!(template.description, "A test template for fixing errors");
353 assert_eq!(template.applicable_categories.len(), 1);
354 assert_eq!(template.applicable_categories[0], ErrorCategory::Validation);
355 assert_eq!(template.target_error_codes.len(), 1);
356 assert_eq!(template.target_error_codes[0], "E0001");
357
358 let mut params = HashMap::new();
360 params.insert("function_name".to_string(), "process_data".to_string());
361 params.insert("param_name".to_string(), "data".to_string());
362 params.insert("param_type".to_string(), "String".to_string());
363 params.insert("return_type".to_string(), "Result<(), Error>".to_string());
364 params.insert("body".to_string(), "Ok(())".to_string());
365
366 let result = template.apply(¶ms);
368
369 let expected = "fn process_data(data: String) -> Result<(), Error> {\n // Implementation\n Ok(())\n}";
371 assert_eq!(result, expected);
372 }
373
374 #[test]
375 fn test_syntax_generator_code_generation() {
376 let generator = SyntaxGenerator::new();
377
378 let import_single = generator.generate_import("std::collections", &["HashMap"]);
380 assert_eq!(import_single, "use std::collections::HashMap;");
381
382 let import_multiple =
383 generator.generate_import("std::collections", &["HashMap", "HashSet", "BTreeMap"]);
384 assert_eq!(
385 import_multiple,
386 "use std::collections::{HashMap, HashSet, BTreeMap};"
387 );
388
389 let import_empty = generator.generate_import("std::collections", &[]);
390 assert_eq!(import_empty, "use std::collections;");
391
392 let mut fields = HashMap::new();
394 fields.insert("name".to_string(), "String".to_string());
395 fields.insert("age".to_string(), "u32".to_string());
396 fields.insert("active".to_string(), "bool".to_string());
397
398 let struct_def = generator.generate_struct("User", fields, Some(vec!["Debug", "Clone"]));
399
400 assert!(struct_def.contains("#[derive(Debug, Clone)]"));
402 assert!(struct_def.contains("pub struct User {"));
403 assert!(struct_def.contains("pub name: String,"));
404 assert!(struct_def.contains("pub age: u32,"));
405 assert!(struct_def.contains("pub active: bool,"));
406 }
407
408 #[test]
409 fn test_template_registry_operations() {
410 let mut registry = TemplateRegistry::new();
411
412 let template1 = FixTemplate::new(
414 "validation_fix",
415 "Fix for validation errors",
416 "// Validation fix for {field_name}",
417 )
418 .add_category(ErrorCategory::Validation)
419 .add_error_code("E0001");
420
421 let template2 = FixTemplate::new("io_fix", "Fix for IO errors", "// IO fix for {path}")
422 .add_category(ErrorCategory::Io)
423 .add_error_code("E0002");
424
425 registry.register_template(template1);
427 registry.register_template(template2);
428
429 let validation_template = registry.get_template("validation_fix");
431 assert!(validation_template.is_some());
432 assert_eq!(
433 validation_template.unwrap().description,
434 "Fix for validation errors"
435 );
436
437 let io_templates = registry.get_templates_for_category(ErrorCategory::Io);
439 assert_eq!(io_templates.len(), 1);
440 assert_eq!(io_templates[0].name, "io_fix");
441
442 let e0001_templates = registry.get_templates_for_error_code("E0001");
444 assert_eq!(e0001_templates.len(), 1);
445 assert_eq!(e0001_templates[0].name, "validation_fix");
446 }
447
448 #[test]
449 fn test_syntax_integration() {
450 let mut registry = TemplateRegistry::new();
452
453 let generator = SyntaxGenerator::new();
455
456 let mut fields = HashMap::new();
458 fields.insert("id".to_string(), "u64".to_string());
459 fields.insert("name".to_string(), "String".to_string());
460
461 let struct_def = generator.generate_struct("User", fields, Some(vec!["Debug", "Clone"]));
462
463 let template = FixTemplate::new(
465 "user_struct_template",
466 "Template for User struct",
467 struct_def,
468 )
469 .add_category(ErrorCategory::Validation);
470
471 registry.register_template(template);
473
474 let retrieved_template = registry.get_template("user_struct_template").unwrap();
476
477 assert!(retrieved_template.template.contains("pub struct User {"));
479 assert!(retrieved_template.template.contains("pub id: u64,"));
480 assert!(retrieved_template.template.contains("pub name: String,"));
481 }
482}