use regex::Regex;
use serde_json::Value;
use std::collections::HashMap;
pub fn extract_vars(s: &str) -> Vec<String> {
let re = Regex::new(r"\$([A-Z][A-Z0-9_]*)").unwrap();
re.captures_iter(s).map(|cap| cap[1].to_string()).collect()
}
pub fn extract_vars_from_value(value: &Value) -> Vec<String> {
let mut vars = Vec::new();
collect_vars_from_value(value, &mut vars);
vars.sort();
vars.dedup();
vars
}
fn collect_vars_from_value(value: &Value, vars: &mut Vec<String>) {
match value {
Value::String(s) => {
vars.extend(extract_vars(s));
}
Value::Array(arr) => {
for item in arr {
collect_vars_from_value(item, vars);
}
}
Value::Object(map) => {
for v in map.values() {
collect_vars_from_value(v, vars);
}
}
_ => {}
}
}
pub fn substitute_string(s: &str, resolved: &HashMap<String, String>) -> String {
let re = Regex::new(r"\$([A-Z][A-Z0-9_]*)").unwrap();
re.replace_all(s, |caps: ®ex::Captures| {
let var_name = &caps[1];
resolved
.get(var_name)
.cloned()
.unwrap_or_else(|| caps[0].to_string())
})
.to_string()
}
pub fn substitute_value(value: &Value, resolved: &HashMap<String, String>) -> Value {
match value {
Value::String(s) => Value::String(substitute_string(s, resolved)),
Value::Array(arr) => {
Value::Array(arr.iter().map(|v| substitute_value(v, resolved)).collect())
}
Value::Object(map) => {
let new_map = map
.iter()
.map(|(k, v)| (k.clone(), substitute_value(v, resolved)))
.collect();
Value::Object(new_map)
}
other => other.clone(),
}
}