diff --git a/crates/simplexpr/src/eval.rs b/crates/simplexpr/src/eval.rs index 6325782..ede42d7 100644 --- a/crates/simplexpr/src/eval.rs +++ b/crates/simplexpr/src/eval.rs @@ -457,6 +457,8 @@ fn call_expr_function(name: &str, args: Vec) -> Result match args.as_slice() { [json, code] => run_jaq_function(json.as_json_value()?, code.as_string()?) .map_err(|e| EvalError::Spanned(code.span(), Box::new(e))), + [json, code, args] => run_jaq_with_args(json.as_json_value()?, code.as_string()?, &args.as_string()?) + .map_err(|e| EvalError::Spanned(code.span(), Box::new(e))), _ => Err(EvalError::WrongArgCount(name.to_string())), }, "formattime" => match args.as_slice() { @@ -505,16 +507,29 @@ fn prepare_jaq_filter(code: String) -> Result, EvalEr Ok(Arc::new(filter)) } +/// duplication for a slight performance increase +fn run_jaq_with_args(json: serde_json::Value, code: String, args: &str) -> Result { + prepare_jaq_filter(code)? + .run((jaq_interpret::Ctx::new([], &jaq_interpret::RcIter::new(std::iter::empty())), jaq_interpret::Val::from(json))) + .map(|r| r.map(Into::::into)) + .map(|x| { + x.map(|val| match (args, val) { + ("r", serde_json::Value::String(s)) => DynVal::from_string(s), + // silently ignore invalid args + (_, v) => DynVal::from_string(serde_json::to_string(&v).unwrap()), + }) + }) + .collect::>() + .map_err(|e| EvalError::JaqError(e.to_string())) +} + fn run_jaq_function(json: serde_json::Value, code: String) -> Result { - let filter: Arc = prepare_jaq_filter(code)?; - let inputs = jaq_interpret::RcIter::new(std::iter::empty()); - let out = filter - .run((jaq_interpret::Ctx::new([], &inputs), jaq_interpret::Val::from(json))) - .map(|x| x.map(Into::::into)) + prepare_jaq_filter(code)? + .run((jaq_interpret::Ctx::new([], &jaq_interpret::RcIter::new(std::iter::empty())), jaq_interpret::Val::from(json))) + .map(|r| r.map(Into::::into)) .map(|x| x.map(|x| DynVal::from_string(serde_json::to_string(&x).unwrap()))) .collect::>() - .map_err(|e| EvalError::JaqError(e.to_string()))?; - Ok(out) + .map_err(|e| EvalError::JaqError(e.to_string())) } #[cfg(test)] @@ -573,5 +588,9 @@ mod tests { lazy_evaluation_or(r#"true || "null".test"#) => Ok(DynVal::from(true)), lazy_evaluation_elvis(r#""test"?: "null".test"#) => Ok(DynVal::from("test")), jq_basic_index(r#"jq("[7,8,9]", ".[0]")"#) => Ok(DynVal::from(7)), + jq_raw_arg(r#"jq("[ \"foo\" ]", ".[0]", "r")"#) => Ok(DynVal::from("foo")), + jq_empty_arg(r#"jq("[ \"foo\" ]", ".[0]", "")"#) => Ok(DynVal::from(r#""foo""#)), + jq_invalid_arg(r#"jq("[ \"foo\" ]", ".[0]", "hello")"#) => Ok(DynVal::from(r#""foo""#)), + jq_no_arg(r#"jq("[ \"foo\" ]", ".[0]")"#) => Ok(DynVal::from(r#""foo""#)), } }