toni 0.1.0

Fast and modular web framework for scalable applications
Documentation
use std::{cell::RefCell, rc::Rc};

use anyhow::{Result, anyhow};

use crate::{
    injector::ToniContainer, module_helpers::module_enum::ModuleDefinition,
    traits_helpers::ModuleMetadata,
};

pub struct ToniDependenciesScanner {
    container: Rc<RefCell<ToniContainer>>,
}

impl ToniDependenciesScanner {
    pub fn new(container: Rc<RefCell<ToniContainer>>) -> Self {
        Self { container }
    }
    pub fn scan(&mut self, module: ModuleDefinition) -> Result<()> {
        self.scan_for_modules_with_imports(module)?;
        self.scan_modules_for_dependencies()?;
        Ok(())
    }
    fn scan_for_modules_with_imports(&mut self, module: ModuleDefinition) -> Result<()> {
        let mut ctx_registry: Vec<String> = vec![];

        let mut stack: Vec<ModuleDefinition> = vec![module];

        while let Some(current_module_definition) = stack.pop() {
            let ModuleDefinition::DefaultModule(default_module) = current_module_definition;

            ctx_registry.push(default_module.get_name());

            let modules_imported = default_module.imports().unwrap_or_default();

            let mut modules_imported_tokens = vec![];

            for module_imported in modules_imported {
                modules_imported_tokens.push(module_imported.get_id());

                if ctx_registry
                    .iter()
                    .any(|module_imported_id| module_imported_id == &module_imported.get_name())
                {
                    continue;
                }

                stack.push(ModuleDefinition::DefaultModule(module_imported));
            }
            let default_module_id = default_module.get_id();
            self.insert_module(default_module);
            self.insert_imports(default_module_id, modules_imported_tokens)?;
        }
        Ok(())
    }

    pub fn scan_modules_for_dependencies(&mut self) -> Result<()> {
        let modules_token = self.container.borrow().get_modules_token();
        for module_token in modules_token {
            self.insert_providers(module_token.clone())?;
            self.insert_controllers(module_token.clone())?;
            self.insert_exports(module_token.clone())?;
        }
        Ok(())
    }

    fn insert_module(&mut self, module: Box<dyn ModuleMetadata>) {
        let mut container = self.container.borrow_mut();
        container.add_module(module);
    }

    pub fn insert_imports(&mut self, module_token: String, imports: Vec<String>) -> Result<()> {
        let mut container = self.container.borrow_mut();

        for import in imports {
            container.add_import(&module_token, import)?;
        }

        Ok(())
    }

    pub fn insert_controllers(&mut self, module_token: String) -> Result<()> {
        let mut container = self.container.borrow_mut();
        let module_ref = container.get_module_by_token(&module_token);
        let resolved_module_ref = match module_ref {
            Some(module_ref) => module_ref,
            None => return Err(anyhow!("Module not found")),
        };

        let controllers = resolved_module_ref.get_metadata().controllers();

        if let Some(controllers) = controllers {
            for controller in controllers {
                container.add_controller(&module_token, controller)?;
            }
        };

        Ok(())
    }

    pub fn insert_providers(&mut self, module_token: String) -> Result<()> {
        let mut container = self.container.borrow_mut();
        let module_ref = container.get_module_by_token(&module_token);
        let resolved_module_ref = match module_ref {
            Some(module_ref) => module_ref,
            None => return Err(anyhow!("Module not found")),
        };

        let providers = resolved_module_ref.get_metadata().providers();

        if let Some(providers) = providers {
            for provider in providers {
                container.add_provider(&module_token, provider)?;
            }
        };

        Ok(())
    }

    pub fn insert_exports(&mut self, module_token: String) -> Result<()> {
        let mut container = self.container.borrow_mut();
        let module_ref = container.get_module_by_token(&module_token);
        let resolved_module_ref = match module_ref {
            Some(module_ref) => module_ref,
            None => return Err(anyhow!("Module not found")),
        };

        let exports = resolved_module_ref.get_metadata().exports();
        if let Some(exports) = exports {
            for export in exports {
                container.add_export(&module_token, export)?;
            }
        };

        Ok(())
    }
}