exprimo 0.7.0

Exprimo is a JavaScript expression evaluator written in Rust.
Documentation
use serde_json::Value;
use std::collections::HashMap;
use std::error::Error;

pub fn add_context(key: &str, json_str: &str, context: &mut HashMap<String, String>) {
    let json: Value = match serde_json::from_str(json_str) {
        Ok(json) => json,
        Err(_) => {
            context.insert(key.to_string(), json_str.to_string());
            return;
        }
    };
    let json_obj = json.as_object().unwrap();
    let context_obj = context.entry(key.to_string()).or_insert_with(String::new);
    let nested_obj = build_nested_object(json_obj);
    let nested_str = serde_json::to_string(&nested_obj).unwrap();
    context_obj.push_str(&format!(r#"{}"#, nested_str));
}

fn build_nested_object(json: &serde_json::Map<String, Value>) -> serde_json::Map<String, Value> {
    let mut nested_obj = serde_json::Map::new();
    for (key, value) in json.iter() {
        match value {
            Value::Null => {
                nested_obj.insert(key.clone(), Value::Null);
            }
            Value::Bool(b) => {
                nested_obj.insert(key.clone(), Value::Bool(*b));
            }
            Value::Number(n) => {
                nested_obj.insert(key.clone(), Value::Number(n.clone()));
            }
            Value::String(s) => {
                nested_obj.insert(key.clone(), Value::String(s.clone()));
            }
            Value::Array(arr) => {
                let nested_arr = arr
                    .iter()
                    .map(|v| match v {
                        Value::Null => Value::Null,
                        Value::Bool(b) => Value::Bool(*b),
                        Value::Number(n) => Value::Number(n.clone()),
                        Value::String(s) => Value::String(s.clone()),
                        Value::Array(_) => Value::Array(build_nested_array(v.as_array().unwrap())),
                        Value::Object(_) => {
                            Value::Object(build_nested_object(v.as_object().unwrap()))
                        }
                    })
                    .collect();
                nested_obj.insert(key.clone(), Value::Array(nested_arr));
            }
            Value::Object(obj) => {
                let nested_obj2 = build_nested_object(obj);
                nested_obj.insert(key.clone(), Value::Object(nested_obj2));
            }
        }
    }
    nested_obj
}

fn build_nested_array(json: &[Value]) -> Vec<Value> {
    json.iter()
        .map(|v| match v {
            Value::Null => Value::Null,
            Value::Bool(b) => Value::Bool(*b),
            Value::Number(n) => Value::Number(n.clone()),
            Value::String(s) => Value::String(s.clone()),
            Value::Array(arr) => Value::Array(build_nested_array(arr)),
            Value::Object(obj) => Value::Object(build_nested_object(obj)),
        })
        .collect()
}

pub fn to_json(context: &HashMap<String, String>) -> HashMap<String, serde_json::Value> {
    let mut json = HashMap::new();
    for (key, value) in context.iter() {
        let parsed_value =
            serde_json::from_str(value).unwrap_or_else(|_| Value::String(value.clone()));
        json.insert(key.to_string(), parsed_value);
    }
    json
}

fn main() -> Result<(), Box<dyn Error>> {
    let mut ctx = HashMap::new();

    add_context("send_email", r#"{"status": "success"}"#, &mut ctx);
    let engine = exprimo::Evaluator::new(
        to_json(&ctx),
        HashMap::new(), // custom_functions
    );

    let expr = r#"send_email.status === 'success' "#;

    let result = engine.evaluate(expr)?;

    println!("send_email.status === 'success' => {}", result);

    Ok(())
}