pushkin-compiler 0.1.0

Schema compiler for pushkin: canonical JSON Schema emission and generated bindings
Documentation
//! TS/Zod emission: `.strict()` objects, `z.infer` types (spec ยง5.2 table).

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, "//"),
    )
}