zorath-env 0.1.2

A tiny CLI to validate .env using a schema, generate docs, and keep config sane.
use std::path::Path;

use crate::envfile;
use crate::schema::{self, Schema, VarSpec, VarType};

pub fn run(example_path: &str, schema_path: &str) -> Result<(), String> {
    if !Path::new(example_path).exists() {
        return Err(format!("example file not found: {example_path}"));
    }

    if Path::new(schema_path).exists() {
        eprintln!("warning: overwriting existing {schema_path}");
    }

    let env = envfile::parse_env_file(example_path).map_err(|e| e.to_string())?;

    let mut schema_map: Schema = Schema::new();

    for (k, v) in env {
        let inferred = infer_type(&v);

        schema_map.insert(k, VarSpec {
            var_type: inferred,
            required: true,
            description: Some("TODO: describe this variable".into()),
            values: None,
            default: None,
        });
    }

    schema::save_schema(schema_path, &schema_map).map_err(|e| e.to_string())?;
    println!("zenv: wrote schema to {schema_path}");
    Ok(())
}

fn infer_type(v: &str) -> VarType {
    let lv = v.trim().to_lowercase();

    if lv == "true" || lv == "false" || lv == "1" || lv == "0" || lv == "yes" || lv == "no" {
        return VarType::Bool;
    }
    if v.parse::<i64>().is_ok() {
        return VarType::Int;
    }
    if v.parse::<f64>().is_ok() {
        return VarType::Float;
    }
    if url::Url::parse(v).is_ok() {
        return VarType::Url;
    }
    VarType::String
}