use std::fmt::Write as _;
use crate::schema::{ContractSchema, PropertyKind};
use crate::targets::{header, quoted_string, type_name};
pub fn emit(schema: &ContractSchema, epoch: u32) -> String {
let mut fields = String::new();
for property in &schema.properties {
let PropertyKind::String {
min_length,
max_length,
format,
enum_values,
default,
} = &property.kind;
let mut chain = match enum_values {
Some(values) => {
let list = values
.iter()
.map(|value| quoted_string(value))
.collect::<Vec<_>>()
.join(", ");
format!("z.enum([{list}])")
}
None if format.as_deref() == Some("email") => "z.email()".to_owned(),
None => "z.string()".to_owned(),
};
if enum_values.is_none() {
if let Some(min) = min_length {
let _ = write!(chain, ".min({min})");
}
if let Some(max) = max_length {
let _ = write!(chain, ".max({max})");
}
}
if let Some(value) = default {
let _ = write!(chain, ".default({})", quoted_string(value));
} else if !property.required {
chain.push_str(".optional()");
}
let _ = writeln!(fields, " {}: {chain},", property.name);
}
let name = type_name(schema);
format!(
"{header}import {{ z }} from \"zod\";\n\n\
export const {name}Schema = z\n .object({{\n{fields} }})\n .strict();\n\n\
export type {name} = z.infer<typeof {name}Schema>;\n",
header = header(schema, epoch, "//"),
)
}