#![warn(missing_docs)]
use super::types::ErrorCategory;
use std::collections::HashMap;
#[derive(Debug, Clone)]
pub struct FixTemplate {
pub name: String,
pub description: String,
pub template: String,
pub applicable_categories: Vec<ErrorCategory>,
pub target_error_codes: Vec<String>,
}
impl FixTemplate {
pub fn new(
name: impl Into<String>,
description: impl Into<String>,
template: impl Into<String>,
) -> Self {
Self {
name: name.into(),
description: description.into(),
template: template.into(),
applicable_categories: Vec::new(),
target_error_codes: Vec::new(),
}
}
pub fn add_category(mut self, category: ErrorCategory) -> Self {
self.applicable_categories.push(category);
self
}
pub fn add_error_code(mut self, code: impl Into<String>) -> Self {
self.target_error_codes.push(code.into());
self
}
pub fn apply(&self, params: &HashMap<String, String>) -> String {
let mut result = self.template.clone();
for (key, value) in params {
result = result.replace(&format!("{{{}}}", key), value);
}
result
}
}
#[derive(Debug, Default)]
pub struct SyntaxGenerator;
impl SyntaxGenerator {
pub fn new() -> Self {
Self
}
pub fn generate_trait_impl(
&self,
trait_name: &str,
type_name: &str,
methods: HashMap<String, String>,
) -> String {
let mut impl_body = String::new();
for (method_name, method_body) in methods {
impl_body.push_str(&format!(
" fn {}() {{\n {}\n }}\n\n",
method_name, method_body
));
}
format!(
"impl {} for {} {{\n{}}}\n",
trait_name, type_name, impl_body
)
}
pub fn generate_import(&self, path: &str, items: &[&str]) -> String {
if items.is_empty() {
format!("use {};", path)
} else if items.len() == 1 {
format!("use {}::{};", path, items[0])
} else {
let items_str = items.join(", ");
format!("use {}::{{{}}};", path, items_str)
}
}
pub fn generate_struct(
&self,
struct_name: &str,
fields: HashMap<String, String>,
derive_traits: Option<Vec<&str>>,
) -> String {
let mut struct_def = String::new();
if let Some(traits) = derive_traits {
if !traits.is_empty() {
struct_def.push_str(&format!("#[derive({})]\n", traits.join(", ")));
}
}
struct_def.push_str(&format!("pub struct {} {{\n", struct_name));
for (field_name, field_type) in fields {
struct_def.push_str(&format!(" pub {}: {},\n", field_name, field_type));
}
struct_def.push_str("}\n");
struct_def
}
pub fn generate_enum(
&self,
enum_name: &str,
variants: HashMap<String, Option<String>>,
derive_traits: Option<Vec<&str>>,
) -> String {
let mut enum_def = String::new();
if let Some(traits) = derive_traits {
if !traits.is_empty() {
enum_def.push_str(&format!("#[derive({})]\n", traits.join(", ")));
}
}
enum_def.push_str(&format!("pub enum {} {{\n", enum_name));
for (variant_name, variant_type) in variants {
if let Some(type_str) = variant_type {
enum_def.push_str(&format!(" {}({}),\n", variant_name, type_str));
} else {
enum_def.push_str(&format!(" {},\n", variant_name));
}
}
enum_def.push_str("}\n");
enum_def
}
pub fn generate_function(
&self,
fn_name: &str,
params: HashMap<String, String>,
return_type: Option<&str>,
body: &str,
) -> String {
let mut param_str = String::new();
for (param_name, param_type) in params {
if !param_str.is_empty() {
param_str.push_str(", ");
}
param_str.push_str(&format!("{}: {}", param_name, param_type));
}
let return_type_str = if let Some(rt) = return_type {
format!(" -> {}", rt)
} else {
String::new()
};
format!(
"fn {}({}){} {{\n {}\n}}\n",
fn_name, param_str, return_type_str, body
)
}
pub fn generate_method_call(&self, object: &str, method_name: &str, args: &[&str]) -> String {
let args_str = args.join(", ");
format!("{}.{}({})", object, method_name, args_str)
}
}
#[derive(Debug, Default)]
pub struct TemplateRegistry {
templates: HashMap<String, FixTemplate>,
}
impl TemplateRegistry {
pub fn new() -> Self {
Self {
templates: HashMap::new(),
}
}
pub fn register_template(&mut self, template: FixTemplate) {
self.templates.insert(template.name.clone(), template);
}
pub fn get_template(&self, name: &str) -> Option<&FixTemplate> {
self.templates.get(name)
}
pub fn get_templates_for_category(&self, category: ErrorCategory) -> Vec<&FixTemplate> {
self.templates
.values()
.filter(|t| t.applicable_categories.contains(&category))
.collect()
}
pub fn get_templates_for_error_code(&self, error_code: &str) -> Vec<&FixTemplate> {
self.templates
.values()
.filter(|t| t.target_error_codes.iter().any(|c| c == error_code))
.collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn test_fix_template_creation_and_application() {
let template = FixTemplate::new(
"test_template",
"A test template for fixing errors",
"fn {function_name}({param_name}: {param_type}) -> {return_type} {\n // Implementation\n {body}\n}"
)
.add_category(ErrorCategory::Validation)
.add_error_code("E0001");
assert_eq!(template.name, "test_template");
assert_eq!(template.description, "A test template for fixing errors");
assert_eq!(template.applicable_categories.len(), 1);
assert_eq!(template.applicable_categories[0], ErrorCategory::Validation);
assert_eq!(template.target_error_codes.len(), 1);
assert_eq!(template.target_error_codes[0], "E0001");
let mut params = HashMap::new();
params.insert("function_name".to_string(), "process_data".to_string());
params.insert("param_name".to_string(), "data".to_string());
params.insert("param_type".to_string(), "String".to_string());
params.insert("return_type".to_string(), "Result<(), Error>".to_string());
params.insert("body".to_string(), "Ok(())".to_string());
let result = template.apply(¶ms);
let expected = "fn process_data(data: String) -> Result<(), Error> {\n // Implementation\n Ok(())\n}";
assert_eq!(result, expected);
}
#[test]
fn test_syntax_generator_code_generation() {
let generator = SyntaxGenerator::new();
let import_single = generator.generate_import("std::collections", &["HashMap"]);
assert_eq!(import_single, "use std::collections::HashMap;");
let import_multiple =
generator.generate_import("std::collections", &["HashMap", "HashSet", "BTreeMap"]);
assert_eq!(
import_multiple,
"use std::collections::{HashMap, HashSet, BTreeMap};"
);
let import_empty = generator.generate_import("std::collections", &[]);
assert_eq!(import_empty, "use std::collections;");
let mut fields = HashMap::new();
fields.insert("name".to_string(), "String".to_string());
fields.insert("age".to_string(), "u32".to_string());
fields.insert("active".to_string(), "bool".to_string());
let struct_def = generator.generate_struct("User", fields, Some(vec!["Debug", "Clone"]));
assert!(struct_def.contains("#[derive(Debug, Clone)]"));
assert!(struct_def.contains("pub struct User {"));
assert!(struct_def.contains("pub name: String,"));
assert!(struct_def.contains("pub age: u32,"));
assert!(struct_def.contains("pub active: bool,"));
}
#[test]
fn test_template_registry_operations() {
let mut registry = TemplateRegistry::new();
let template1 = FixTemplate::new(
"validation_fix",
"Fix for validation errors",
"// Validation fix for {field_name}",
)
.add_category(ErrorCategory::Validation)
.add_error_code("E0001");
let template2 = FixTemplate::new("io_fix", "Fix for IO errors", "// IO fix for {path}")
.add_category(ErrorCategory::Io)
.add_error_code("E0002");
registry.register_template(template1);
registry.register_template(template2);
let validation_template = registry.get_template("validation_fix");
assert!(validation_template.is_some());
assert_eq!(
validation_template.unwrap().description,
"Fix for validation errors"
);
let io_templates = registry.get_templates_for_category(ErrorCategory::Io);
assert_eq!(io_templates.len(), 1);
assert_eq!(io_templates[0].name, "io_fix");
let e0001_templates = registry.get_templates_for_error_code("E0001");
assert_eq!(e0001_templates.len(), 1);
assert_eq!(e0001_templates[0].name, "validation_fix");
}
#[test]
fn test_syntax_integration() {
let mut registry = TemplateRegistry::new();
let generator = SyntaxGenerator::new();
let mut fields = HashMap::new();
fields.insert("id".to_string(), "u64".to_string());
fields.insert("name".to_string(), "String".to_string());
let struct_def = generator.generate_struct("User", fields, Some(vec!["Debug", "Clone"]));
let template = FixTemplate::new(
"user_struct_template",
"Template for User struct",
struct_def,
)
.add_category(ErrorCategory::Validation);
registry.register_template(template);
let retrieved_template = registry.get_template("user_struct_template").unwrap();
assert!(retrieved_template.template.contains("pub struct User {"));
assert!(retrieved_template.template.contains("pub id: u64,"));
assert!(retrieved_template.template.contains("pub name: String,"));
}
}