typhoon-instruction-builder 0.2.2

Code generation for instruction clients and CPI builders
Documentation
use {
    crate::{mod_path::ModContext, read_and_parse_file},
    std::path::Path,
    syn::{visit::Visit, Item, ItemMod, Visibility},
};

pub struct Resolver<'a> {
    path: &'a Path,
    root: bool,
    mod_context: ModContext,
    pub items: Vec<Item>,
}

impl<'a> Resolver<'a> {
    pub fn new(path: &'a Path, root: bool) -> Self {
        Self {
            path,
            root,
            mod_context: Default::default(),
            items: Vec::new(),
        }
    }
}

impl Visit<'_> for Resolver<'_> {
    fn visit_file(&mut self, i: &'_ syn::File) {
        for item in &i.items {
            let is_public = match &item {
                Item::Fn(f) => matches!(f.vis, Visibility::Public(_)),
                Item::Struct(s) => matches!(s.vis, Visibility::Public(_)),
                Item::Enum(e) => matches!(e.vis, Visibility::Public(_)),
                _ => false,
            };

            if is_public {
                self.items.push(item.clone());
            }
            self.visit_item(item);
        }
    }

    fn visit_item_mod(&mut self, i: &ItemMod) {
        self.mod_context.push(i.into());

        if let Some((_, items)) = &i.content {
            for item in items {
                self.visit_item(item);
            }
        } else {
            let candidates = self.mod_context.relative_to(self.path, self.root);
            let first_candidate = candidates.iter().find(|p| p.exists());

            if let Some(file) = first_candidate.and_then(|p| read_and_parse_file(p).ok()) {
                self.visit_file(&file);
            };
        }

        self.mod_context.pop();
    }
}