typhoon-context-macro 0.1.0-alpha.13

TODO
Documentation
use {crate::context::Context, syn::spanned::Spanned, typhoon_syn::constraints::Constraint};

fn check_program_prerequisite(context: &Context, program: &str) -> Result<(), syn::Error> {
    let has_system_program = context.accounts.iter().any(|acc| {
        (acc.ty.ident == "Program" || acc.ty.ident == "Interface") && acc.inner_ty == program
    });

    if !has_system_program {
        return Err(syn::Error::new(
            context.item_struct.span(),
            format!("One constraint requires including the `Program<{program}>` account."),
        ));
    }

    Ok(())
}

pub fn cross_checks(context: &Context) -> Result<(), syn::Error> {
    for acc in &context.accounts {
        if acc
            .constraints
            .0
            .iter()
            .any(|c| matches!(c, Constraint::Init(_) | Constraint::InitIfNeeded(_)))
        {
            check_program_prerequisite(context, "System")?;

            if acc.inner_ty == "Mint" || acc.inner_ty == "TokenAccount" {
                check_program_prerequisite(context, "TokenProgram")?;

                if acc
                    .constraints
                    .0
                    .iter()
                    .any(|c| matches!(c, Constraint::AssociatedToken(_)))
                {
                    check_program_prerequisite(context, "AtaTokenProgram")?;
                }
            }
        }
    }

    Ok(())
}