use blvm_node::module::ipc::protocol::CliArgSpec;
use blvm_node::module::traits::ModuleError;
use std::collections::HashMap;
pub fn parse_args(
args: &[String],
arg_specs: &[CliArgSpec],
) -> Result<HashMap<String, String>, ModuleError> {
let mut map = HashMap::new();
let has_named = args.iter().any(|a| {
a.starts_with("--")
|| (a.starts_with('-')
&& a.len() > 1
&& !a
.chars()
.nth(1)
.map(|c| c.is_ascii_digit())
.unwrap_or(false))
});
if has_named {
let mut i = 0;
while i < args.len() {
let arg = &args[i];
if arg.starts_with("--") {
let key = arg.trim_start_matches('-');
if key.is_empty() {
i += 1;
continue;
}
let param_name = find_param_by_long(arg_specs, key);
i += 1;
if i < args.len() && !args[i].starts_with('-') {
let value = args[i].clone();
i += 1;
map.insert(param_name.to_string(), value);
} else {
map.insert(param_name.to_string(), "true".to_string());
}
} else if arg.starts_with('-') && arg.len() > 1 {
let short = &arg[1..];
let param_name = find_param_by_short(arg_specs, short);
i += 1;
if i < args.len() && !args[i].starts_with('-') {
let value = args[i].clone();
i += 1;
map.insert(param_name.to_string(), value);
} else {
map.insert(param_name.to_string(), "true".to_string());
}
} else {
i += 1;
}
}
} else {
for (i, spec) in arg_specs.iter().enumerate() {
if let Some(v) = args.get(i) {
map.insert(spec.name.clone(), v.clone());
}
}
}
Ok(map)
}
fn find_param_by_long<'a>(specs: &'a [CliArgSpec], long: &'a str) -> &'a str {
for spec in specs {
let long_form = spec.long_name.as_deref().unwrap_or(&spec.name);
if long_form == long {
return &spec.name;
}
}
long
}
fn find_param_by_short<'a>(specs: &'a [CliArgSpec], short: &'a str) -> &'a str {
for spec in specs {
if let Some(s) = &spec.short_name {
if s == short {
return &spec.name;
}
}
if let Some(c) = short.chars().next() {
if spec.name.starts_with(c) {
return &spec.name;
}
}
}
short
}
pub fn coerce_bool(s: &str) -> Result<bool, ModuleError> {
let s = s.to_lowercase();
if s == "true" || s == "1" || s == "yes" || s == "on" {
Ok(true)
} else if s == "false" || s == "0" || s == "no" || s == "off" {
Ok(false)
} else {
Err(ModuleError::Other(format!("invalid bool: {s}")))
}
}