envl 0.4.0

load .envl and .envlconf
Documentation
use envl_config::{
    generate_ast as gen_config_ast,
    misc::{
        config::Config,
        variable::{Type, Value},
    },
};
use envl_utils::types::Position;
use envl_vars::{
    generate_ast as gen_vars_ast,
    misc::variable::{Variable, VariableValue},
};
use std::{collections::HashMap, env::current_dir, path::PathBuf};

use crate::{
    generator::{generate_file, rust::value::gen_value},
    misc::{
        error::{
            convert_envl_config_error, convert_envl_lib_error, convert_envl_vars_error,
            convert_io_error, EnvlError, EnvlLibError,
        },
        filesystem::{read_file, write_file},
        vars::vars_to_hashmap,
    },
    var::parse_var,
};

pub mod generator;
pub mod misc;
pub mod var;

#[derive(Debug, Clone)]
pub struct VarData {
    pub value: Value,
    pub v_type: Type,
    pub default_value: Value,
    pub actions_value: Value,
    pub basic_value: Option<VariableValue>,
    pub position: Position,
}

pub type VariableHashMap = HashMap<String, VarData>;

pub fn load_envl(output: String) -> Result<(), EnvlError> {
    match current_dir() {
        Ok(current_dir_path) => {
            let config_file_path = current_dir_path.join(".envlconf").display().to_string();
            match read_file(config_file_path.to_owned()) {
                Ok(code) => {
                    match load_envl_core(
                        current_dir_path.to_owned(),
                        config_file_path.to_owned(),
                        code,
                    ) {
                        Ok(hm) => match generate_file(hm, output.to_owned()) {
                            Ok(result) => {
                                if let Err(err) = write_file(output, result) {
                                    Err(convert_io_error(err))
                                } else {
                                    Ok(())
                                }
                            }
                            Err(err) => Err(convert_io_error(err)),
                        },
                        Err(err) => Err(err),
                    }
                }
                Err(err) => Err(err),
            }
        }
        Err(err) => Err(convert_io_error(err)),
    }
}

pub fn load_envl_core(
    current_dir: PathBuf,
    config_file_path: String,
    code: String,
) -> Result<VariableHashMap, EnvlError> {
    match load_files(current_dir, config_file_path, code) {
        Ok((vars, config)) => {
            let vars_hm = vars_to_hashmap(vars);
            let mut result = HashMap::new();

            for (name, value) in config.vars {
                if let Some(v) = vars_hm.get(&name) {
                    match parse_var(value.v_type.clone(), v.value.clone()) {
                        Ok(var) => {
                            result.insert(
                                name,
                                VarData {
                                    value: var,
                                    v_type: value.v_type.clone(),
                                    default_value: value.default_value,
                                    actions_value: value.actions_value,
                                    basic_value: Some(v.value.clone()),
                                    position: v.position.clone(),
                                },
                            );
                        }
                        Err(err) => {
                            return Err(err);
                        }
                    }
                } else {
                    result.insert(
                        name,
                        VarData {
                            value: Value::Null,
                            v_type: value.v_type,
                            default_value: value.default_value,
                            actions_value: value.actions_value,
                            basic_value: None,
                            position: value.position,
                        },
                    );
                }
            }

            if let Err(err) = check_envl_vars(result.to_owned()) {
                Err(convert_envl_lib_error(err))
            } else {
                Ok(result)
            }
        }
        Err(err) => Err(err),
    }
}

pub fn check_envl_vars(hm: HashMap<String, VarData>) -> Result<(), EnvlLibError> {
    for (name, value) in hm {
        if value.value == Value::Null {
            match &value.default_value {
                Value::Null => match &value.v_type {
                    Type::Option(_) => {}
                    _ => {
                        return Err(EnvlLibError {
                            message: "Invalid Type".to_string(),
                        });
                    }
                },
                v => {
                    if gen_value(name, value.v_type.to_owned(), v.to_owned(), &mut Vec::new())
                        .is_err()
                    {
                        return Err(EnvlLibError {
                            message: "Invalid Type".to_string(),
                        });
                    }
                }
            }
        }
    }

    Ok(())
}

pub fn load_files(
    current_dir: PathBuf,
    config_file_path: String,
    code: String,
) -> Result<(Vec<Variable>, Config), EnvlError> {
    match gen_config_ast(config_file_path.clone(), code.clone()) {
        Ok(config) => {
            let file_path = if let Some(ref file_path) = config.settings.envl_file_path {
                file_path.value.clone()
            } else {
                current_dir.join(".envl").display().to_string()
            };
            match read_file(file_path.to_owned()) {
                Ok(code) => match gen_vars_ast(file_path, code) {
                    Ok(vars) => Ok((vars, config)),
                    Err(err) => Err(convert_envl_vars_error(err)),
                },
                Err(err) => Err(err),
            }
        }
        Err(err) => Err(convert_envl_config_error(err)),
    }
}