const URL_PLACEHOLDER: &str = "{{url}}";
const INPUT_PLACEHOLDER: &str = "{{input}}";
const OUTPUT_DIR_TOKEN: &str = "{{output_dir}}";
#[expect(clippy::too_many_lines)]
pub(crate) fn resolve_input_placeholders(
args: &mut Vec<String>,
params: &serde_json::Map<String, serde_json::Value>,
) -> Result<(), String> {
let url = params
.get("url")
.and_then(serde_json::Value::as_str)
.unwrap_or("");
let text = params
.get("text")
.and_then(serde_json::Value::as_str)
.unwrap_or("");
let input_val = if !url.is_empty() { url } else { text };
if input_val.contains(OUTPUT_DIR_TOKEN) {
return Err(format!(
"the input carries '{OUTPUT_DIR_TOKEN}', which shell-run fills itself"
));
}
let has_url_placeholder = args.iter().any(|a| a.contains(URL_PLACEHOLDER));
let has_input_placeholder = args.iter().any(|a| a.contains(INPUT_PLACEHOLDER));
for arg in args.iter_mut() {
if arg.contains(URL_PLACEHOLDER) && !url.is_empty() {
*arg = arg.replace(URL_PLACEHOLDER, url);
}
if arg.contains(INPUT_PLACEHOLDER) && !input_val.is_empty() {
*arg = arg.replace(INPUT_PLACEHOLDER, input_val);
}
}
if !has_url_placeholder && !has_input_placeholder && !url.is_empty() {
args.push(url.to_string());
}
Ok(())
}
pub fn flatten_conditional_args(args: &[serde_json::Value]) -> Vec<String> {
let mut result = Vec::new();
for item in args {
match item {
serde_json::Value::String(s) if !s.is_empty() => {
result.push(s.clone());
}
serde_json::Value::Array(group) => {
let strings: Vec<&str> =
group.iter().filter_map(serde_json::Value::as_str).collect();
let all_non_empty =
strings.len() == group.len() && strings.iter().all(|s| !s.is_empty());
if all_non_empty {
result.extend(strings.into_iter().map(String::from));
}
}
_ => {}
}
}
result
}