use super::traits::CodeGenerator;
use crate::infer::types::{TypeInferenceContext, InferredType};
use crate::config::GeneratorConfig;
use anyhow::Result;
pub struct ConfigBasedGenerator;
impl CodeGenerator for ConfigBasedGenerator {
fn generate(
&self,
context: &TypeInferenceContext,
_root_name: &str,
config: &GeneratorConfig,
) -> Result<String> {
let mut output = String::new();
if let Some(header) = &config.file_header {
output.push_str(header);
}
for (name, def) in &context.struct_defs {
output.push_str(&render_struct(name, def, config));
}
if let Some(footer) = &config.file_footer {
output.push_str(footer);
}
Ok(output)
}
}
fn render_struct(name: &str, def: &crate::infer::structs::StructDef, config: &GeneratorConfig) -> String {
let indent = config.indent.as_deref().unwrap_or("");
let field_sep = config.field_separator.as_deref().unwrap_or("\n");
let mut parts = Vec::new();
if let Some(before_struct) = &config.before_struct {
parts.push(before_struct.to_string());
}
if let Some(before_name) = &config.before_struct_name {
parts.push(before_name.to_string());
}
parts.push(name.to_string());
if let Some(after_name) = &config.after_struct_name {
parts.push(after_name.to_string());
}
let mut fields = Vec::new();
for (field_name, field_type) in &def.fields {
let field_type_str = map_field_type(field_type, config);
fields.push(config.render_field(field_name, &field_type_str, indent));
}
parts.push(fields.join(field_sep));
if let Some(after_struct) = &config.after_struct {
parts.push(after_struct.to_string());
}
parts.join("")
}
fn map_field_type(field_type: &InferredType, config: &GeneratorConfig) -> String {
match field_type {
InferredType::Array(inner) => {
let inner_type = map_field_type(inner, config);
config.map_type("array", false).replace("$T", &inner_type)
}
InferredType::Object(name) => {
config.map_type("object", false).replace("$T", name)
}
_ => {
let base_type = field_type.base_type_name();
config.map_type(base_type, field_type.is_nullable())
}
}
}