use std::ffi::OsString;
pub(crate) fn extract_config_overrides(args: &mut Vec<OsString>) -> Vec<(String, String)> {
let mut out = Vec::new();
let mut i = 1;
while i < args.len() {
let Some(s) = args[i].to_str() else {
i += 1;
continue;
};
if s == "--" {
break;
}
if let Some(rest) = s.strip_prefix("--config.") {
let (key, value) = match rest.split_once('=') {
Some((k, v)) => (k.to_string(), v.to_string()),
None => (rest.to_string(), "true".to_string()),
};
if !key.is_empty() {
out.push((key, value));
args.remove(i);
continue;
}
}
i += 1;
}
out
}
pub(crate) fn rewrite_multicall_argv(mut args: Vec<OsString>) -> Vec<OsString> {
normalize_npm_interpreter_shim_argv(&mut args);
let Some(argv0) = args.first() else {
return args;
};
let stem = std::path::Path::new(argv0)
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or("aube")
.to_ascii_lowercase();
let subcommand = match stem.as_str() {
"aubr" => "run",
"aubx" => "dlx",
_ => return args,
};
args[0] = OsString::from("aube");
if matches!(
args.get(1).and_then(|s| s.to_str()),
Some("--version") | Some("-V")
) {
return args;
}
args.insert(1, OsString::from(subcommand));
args
}
fn normalize_npm_interpreter_shim_argv(args: &mut Vec<OsString>) {
let Some(shim) = args.get(1).cloned() else {
return;
};
let shim_path = std::path::Path::new(&shim);
let Some(stem) = shim_path.file_stem().and_then(|s| s.to_str()) else {
return;
};
if !matches!(stem, "aube" | "aubr" | "aubx") {
return;
}
let Ok(bytes) = std::fs::read(shim_path) else {
return;
};
if !bytes.starts_with(b"#!") {
return;
}
args[0] = shim;
args.remove(1);
}
pub(crate) fn lift_per_subcommand_flags(mut args: Vec<OsString>) -> Vec<OsString> {
const LIFTED_LONGS: &[(&str, bool)] = &[
("frozen-lockfile", false),
("no-frozen-lockfile", false),
("prefer-frozen-lockfile", false),
("registry", true),
("fetch-retries", true),
("fetch-retry-factor", true),
("fetch-retry-maxtimeout", true),
("fetch-retry-mintimeout", true),
("fetch-timeout", true),
("disable-global-virtual-store", false),
("disable-gvs", false),
("enable-global-virtual-store", false),
("enable-gvs", false),
];
const KEPT_LONGS_WITH_VALUE: &[&str] = &[
"dir",
"cd",
"prefix",
"loglevel",
"reporter",
"filter",
"filter-prod",
];
const KEPT_SHORTS_WITH_VALUE: &[&str] = &["-C", "-F"];
let token_looks_like_flag = |args: &[OsString], idx: usize| -> bool {
args.get(idx)
.and_then(|t| t.to_str())
.is_some_and(|s| s.starts_with('-') && s != "-")
};
let mut lifted: Vec<OsString> = Vec::new();
let mut subcommand_idx: Option<usize> = None;
let mut i = 1;
while i < args.len() {
let Some(s) = args[i].to_str() else { break };
if s == "--" {
break;
}
if let Some(rest) = s.strip_prefix("--") {
let (bare, has_inline_value) = match rest.split_once('=') {
Some((bare, _)) => (bare, true),
None => (rest, false),
};
if let Some((_, takes_value)) =
LIFTED_LONGS.iter().copied().find(|(name, _)| *name == bare)
{
lifted.push(args.remove(i));
if takes_value
&& !has_inline_value
&& i < args.len()
&& !token_looks_like_flag(&args, i)
{
lifted.push(args.remove(i));
}
continue;
}
if KEPT_LONGS_WITH_VALUE.contains(&bare) {
i += 1;
if !has_inline_value && i < args.len() && !token_looks_like_flag(&args, i) {
i += 1;
}
continue;
}
i += 1;
continue;
}
if s == "-" {
subcommand_idx = Some(i);
break;
}
if s.strip_prefix('-').is_some() {
if s == "-F" {
i += 1;
if i < args.len() && !token_looks_like_flag(&args, i) {
i += 1;
}
continue;
}
if let Some(rest) = s.strip_prefix("-F")
&& !rest.is_empty()
{
i += 1;
continue;
}
if KEPT_SHORTS_WITH_VALUE.contains(&s) {
i += 1;
if i < args.len() && !token_looks_like_flag(&args, i) {
i += 1;
}
continue;
}
i += 1;
continue;
}
subcommand_idx = Some(i);
break;
}
if let Some(idx) = subcommand_idx {
let insert_at = idx + 1;
for (j, tok) in lifted.into_iter().enumerate() {
args.insert(insert_at + j, tok);
}
} else {
for tok in lifted.into_iter().rev() {
args.insert(1, tok);
}
}
args
}