use serde_json::{Map, Value};
pub(crate) fn raw_problems(raw: &Map<String, Value>) -> Vec<String> {
let mut problems = crate::script::raw_script_problems(raw);
let Some(command) = raw.get("command").and_then(Value::as_str) else {
return problems;
};
if bnto_core::placeholders::mentions_data(command) {
problems.push(format!(
"'command' must be written literally, but '{command}' lets data choose \
the program. Name the tool and pass values as arguments"
));
}
problems.extend(crate::interpreter_code::code_problems(
command,
raw.get("args"),
));
problems.extend(crate::wrappers::wrapper_problems(command, raw.get("args")));
problems
}
#[cfg(test)]
mod tests {
use super::*;
fn params(json: Value) -> Map<String, Value> {
json.as_object().unwrap().clone()
}
#[test]
fn a_literal_command_passes() {
assert!(raw_problems(¶ms(serde_json::json!({ "command": "ffmpeg" }))).is_empty());
}
#[test]
fn a_command_from_data_is_refused() {
for command in ["{{fields.tool}}", "{{item.bin}}", "yt-{{env.X}}", "{{url}}"] {
let problems = raw_problems(¶ms(serde_json::json!({ "command": command })));
assert_eq!(problems.len(), 1, "{command}");
assert!(problems[0].contains("literal"), "{}", problems[0]);
}
}
#[test]
fn a_command_from_run_vars_is_allowed() {
let raw = params(serde_json::json!({ "command": "{{vars.Tool}}" }));
assert!(raw_problems(&raw).is_empty());
}
}