1use crate::error::Result;
2use std::path::Path;
3use std::process::Command;
4
5pub enum Formatter {
6 Prettier,
7 Biome,
8}
9
10pub struct FormatterManager;
11
12impl FormatterManager {
13 pub fn detect_formatter() -> Option<Formatter> {
14 if Self::has_prettier() {
16 return Some(Formatter::Prettier);
17 }
18
19 if Self::has_biome() {
21 return Some(Formatter::Biome);
22 }
23
24 None
25 }
26
27 fn has_prettier() -> bool {
28 if Path::new("package.json").exists() {
30 if let Ok(content) = std::fs::read_to_string("package.json") {
31 if content.contains("prettier") {
32 return true;
33 }
34 }
35 }
36
37 Path::new(".prettierrc").exists()
39 || Path::new(".prettierrc.json").exists()
40 || Path::new(".prettierrc.js").exists()
41 || Path::new("prettier.config.js").exists()
42 }
43
44 fn has_biome() -> bool {
45 Path::new("biome.json").exists() || Path::new("biome.jsonc").exists()
47 }
48
49 pub fn format_files(files: &[std::path::PathBuf], formatter: Formatter) -> Result<()> {
50 match formatter {
51 Formatter::Prettier => Self::format_with_prettier(files),
52 Formatter::Biome => Self::format_with_biome(files),
53 }
54 }
55
56 fn format_with_prettier(files: &[std::path::PathBuf]) -> Result<()> {
57 let file_paths: Vec<String> = files
58 .iter()
59 .filter_map(|p| p.to_str().map(|s| s.to_string()))
60 .collect();
61
62 if file_paths.is_empty() {
63 return Ok(());
64 }
65
66 let output = Command::new("npx")
67 .arg("prettier")
68 .arg("--write")
69 .args(&file_paths)
70 .output();
71
72 match output {
73 Ok(_) => Ok(()),
74 Err(e) => {
75 eprintln!("Warning: Failed to run prettier: {}", e);
77 Ok(())
78 }
79 }
80 }
81
82 fn format_with_biome(files: &[std::path::PathBuf]) -> Result<()> {
83 let file_paths: Vec<String> = files
84 .iter()
85 .filter_map(|p| p.to_str().map(|s| s.to_string()))
86 .collect();
87
88 if file_paths.is_empty() {
89 return Ok(());
90 }
91
92 let output = Command::new("npx")
93 .arg("@biomejs/biome")
94 .arg("format")
95 .arg("--write")
96 .args(&file_paths)
97 .output();
98
99 match output {
100 Ok(_) => Ok(()),
101 Err(e) => {
102 eprintln!("Warning: Failed to run biome: {}", e);
104 Ok(())
105 }
106 }
107 }
108}