use crate::config::E2eConfig;
use alef_core::backend::GeneratedFile;
use std::collections::HashSet;
use std::path::Path;
use tracing::warn;
fn default_formatter(lang: &str) -> Option<&'static str> {
match lang {
"rust" => Some("(cd {dir} && cargo fmt --all)"),
"python" => Some("ruff format {dir}"),
_ => None,
}
}
pub fn run_formatters(files: &[GeneratedFile], e2e_config: &E2eConfig) {
let output_prefix = Path::new(e2e_config.effective_output());
let languages: HashSet<String> = files
.iter()
.filter_map(|f| {
let remainder = f.path.strip_prefix(output_prefix).ok()?;
let first = remainder.components().next()?;
Some(first.as_os_str().to_string_lossy().into_owned())
})
.collect();
for lang in &languages {
let cmd_template: &str = if let Some(custom) = e2e_config.format.get(lang.as_str()) {
custom.as_str()
} else if let Some(builtin) = default_formatter(lang.as_str()) {
builtin
} else {
continue;
};
let dir = format!("{}/{}", e2e_config.effective_output(), lang);
let cmd = cmd_template.replace("{dir}", &dir);
eprintln!(" Formatting {lang}: {cmd}");
let status = std::process::Command::new("sh").args(["-c", &cmd]).status();
match status {
Ok(s) if s.success() => {}
Ok(s) => {
warn!("Formatter for {lang} exited with {s}: {cmd}");
}
Err(e) => {
warn!("Failed to run formatter for {lang}: {e}");
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_formatter_rust_uses_cd_into_dir() {
let cmd = default_formatter("rust").expect("rust must have a default formatter");
assert!(
cmd.contains("cd {dir}") && cmd.contains("cargo fmt"),
"rust formatter must cd into {{dir}} before invoking cargo fmt so it works on \
standalone (non-workspace-member) e2e crates: {cmd}"
);
assert!(
!cmd.contains("--manifest-path"),
"rust formatter must not use --manifest-path; cargo-fmt does not accept it as a \
global flag: {cmd}"
);
assert!(
cmd.contains("{dir}"),
"rust formatter must include {{dir}} placeholder: {cmd}"
);
}
#[test]
fn test_default_formatter_python_uses_ruff_format() {
let cmd = default_formatter("python").expect("python must have a default formatter");
assert!(cmd.contains("ruff"), "python formatter must use ruff: {cmd}");
assert!(cmd.contains("format"), "python formatter must run ruff format: {cmd}");
assert!(
cmd.contains("{dir}"),
"python formatter must include {{dir}} placeholder: {cmd}"
);
}
#[test]
fn test_default_formatter_unknown_lang_returns_none() {
assert!(default_formatter("gleam").is_none());
assert!(default_formatter("zig").is_none());
assert!(default_formatter("java").is_none());
}
}