1use crate::config::E2eConfig;
8use alef_core::backend::GeneratedFile;
9use std::collections::HashSet;
10use std::path::Path;
11use tracing::warn;
12
13fn default_formatter(lang: &str) -> Option<&'static str> {
24 match lang {
25 "rust" => Some("cargo fmt --manifest-path {dir}/Cargo.toml"),
26 "python" => Some("ruff format {dir}"),
27 _ => None,
28 }
29}
30
31pub fn run_formatters(files: &[GeneratedFile], e2e_config: &E2eConfig) {
39 let output_prefix = Path::new(e2e_config.effective_output());
43 let languages: HashSet<String> = files
44 .iter()
45 .filter_map(|f| {
46 let remainder = f.path.strip_prefix(output_prefix).ok()?;
47 let first = remainder.components().next()?;
48 Some(first.as_os_str().to_string_lossy().into_owned())
49 })
50 .collect();
51
52 for lang in &languages {
53 let cmd_template: &str = if let Some(custom) = e2e_config.format.get(lang.as_str()) {
55 custom.as_str()
56 } else if let Some(builtin) = default_formatter(lang.as_str()) {
57 builtin
58 } else {
59 continue;
60 };
61
62 let dir = format!("{}/{}", e2e_config.effective_output(), lang);
63 let cmd = cmd_template.replace("{dir}", &dir);
64
65 eprintln!(" Formatting {lang}: {cmd}");
66 let status = std::process::Command::new("sh").args(["-c", &cmd]).status();
67
68 match status {
69 Ok(s) if s.success() => {}
70 Ok(s) => {
71 warn!("Formatter for {lang} exited with {s}: {cmd}");
72 }
73 Err(e) => {
74 warn!("Failed to run formatter for {lang}: {e}");
75 }
76 }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn test_default_formatter_rust_uses_manifest_path() {
86 let cmd = default_formatter("rust").expect("rust must have a default formatter");
87 assert!(
88 cmd.contains("--manifest-path"),
89 "rust formatter must use --manifest-path so it works on standalone e2e crates: {cmd}"
90 );
91 assert!(
92 cmd.contains("{dir}"),
93 "rust formatter must include {{dir}} placeholder: {cmd}"
94 );
95 }
96
97 #[test]
98 fn test_default_formatter_python_uses_ruff_format() {
99 let cmd = default_formatter("python").expect("python must have a default formatter");
100 assert!(cmd.contains("ruff"), "python formatter must use ruff: {cmd}");
101 assert!(cmd.contains("format"), "python formatter must run ruff format: {cmd}");
102 assert!(
103 cmd.contains("{dir}"),
104 "python formatter must include {{dir}} placeholder: {cmd}"
105 );
106 }
107
108 #[test]
109 fn test_default_formatter_unknown_lang_returns_none() {
110 assert!(default_formatter("gleam").is_none());
111 assert!(default_formatter("zig").is_none());
112 assert!(default_formatter("java").is_none());
113 }
114}