robinpath 0.2.0

RobinPath - A lightweight, fast scripting language interpreter for automation and data processing
Documentation
use crate::executor::Environment;
use crate::value::Value;
use indexmap::IndexMap;

pub fn register(env: &mut Environment) {
    env.register_builtin("object.keys", |args, _| {
        if let Some(Value::Object(obj)) = args.first() {
            Ok(Value::Array(
                obj.keys().map(|k| Value::String(k.clone())).collect(),
            ))
        } else {
            Ok(Value::Array(Vec::new()))
        }
    });

    env.register_builtin("object.values", |args, _| {
        if let Some(Value::Object(obj)) = args.first() {
            Ok(Value::Array(obj.values().cloned().collect()))
        } else {
            Ok(Value::Array(Vec::new()))
        }
    });

    env.register_builtin("object.entries", |args, _| {
        if let Some(Value::Object(obj)) = args.first() {
            Ok(Value::Array(
                obj.iter()
                    .map(|(k, v)| {
                        Value::Array(vec![Value::String(k.clone()), v.clone()])
                    })
                    .collect(),
            ))
        } else {
            Ok(Value::Array(Vec::new()))
        }
    });

    env.register_builtin("object.merge", |args, _| {
        let mut result = IndexMap::new();
        for arg in args {
            if let Value::Object(obj) = arg {
                for (k, v) in obj {
                    result.insert(k.clone(), v.clone());
                }
            }
        }
        Ok(Value::Object(result))
    });

    env.register_builtin("object.clone", |args, _| {
        // Deep clone via serialization
        args.first().cloned().ok_or_else(|| "object.clone: missing argument".to_string())
    });

    env.register_builtin("object.hasProperty", |args, _| {
        match (args.first(), args.get(1)) {
            (Some(Value::Object(obj)), Some(Value::String(key))) => {
                Ok(Value::Bool(obj.contains_key(key)))
            }
            _ => Ok(Value::Bool(false)),
        }
    });

    env.register_builtin("object.getProperty", |args, _| {
        match (args.first(), args.get(1)) {
            (Some(Value::Object(obj)), Some(Value::String(key))) => {
                Ok(obj.get(key).cloned().unwrap_or(Value::Null))
            }
            _ => Ok(Value::Null),
        }
    });

    // Global shorthands
    env.register_builtin("keys", |args, _| {
        if let Some(Value::Object(obj)) = args.first() {
            Ok(Value::Array(
                obj.keys().map(|k| Value::String(k.clone())).collect(),
            ))
        } else {
            Ok(Value::Array(Vec::new()))
        }
    });

    env.register_builtin("values", |args, _| {
        if let Some(Value::Object(obj)) = args.first() {
            Ok(Value::Array(obj.values().cloned().collect()))
        } else {
            Ok(Value::Array(Vec::new()))
        }
    });

    env.register_builtin("entries", |args, _| {
        if let Some(Value::Object(obj)) = args.first() {
            Ok(Value::Array(
                obj.iter()
                    .map(|(k, v)| Value::Array(vec![Value::String(k.clone()), v.clone()]))
                    .collect(),
            ))
        } else {
            Ok(Value::Array(Vec::new()))
        }
    });

    env.register_builtin("merge", |args, _| {
        let mut result = IndexMap::new();
        for arg in args {
            if let Value::Object(obj) = arg {
                for (k, v) in obj {
                    result.insert(k.clone(), v.clone());
                }
            }
        }
        Ok(Value::Object(result))
    });

    env.register_builtin("clone", |args, _| {
        args.first().cloned().ok_or_else(|| "clone: missing argument".to_string())
    });

    env.register_builtin("object.setProperty", |args, _| {
        if let Some(Value::Object(obj)) = args.first() {
            let mut new_obj = obj.clone();
            if let (Some(Value::String(key)), Some(val)) = (args.get(1), args.get(2)) {
                new_obj.insert(key.clone(), val.clone());
            }
            Ok(Value::Object(new_obj))
        } else {
            Ok(Value::Null)
        }
    });
}