pub mod javascript;
use crate::core::error::NeatifyError;
use crate::core::formatter::{Formatter, FormattingStats};
use anyhow::Result;
use std::path::Path;
pub fn format_file<P: AsRef<Path>>(file_path: P, write: bool) -> Result<bool> {
let file_path = file_path.as_ref();
let formatter = get_formatter_for_file(file_path);
match formatter {
Some(formatter) => formatter.format_file(file_path, write),
None => Err(NeatifyError::UnsupportedFile(file_path.display().to_string()).into()),
}
}
pub fn format_directory<P: AsRef<Path>>(dir_path: P, write: bool) -> Result<FormattingStats> {
let dir_path = dir_path.as_ref();
if !dir_path.exists() || !dir_path.is_dir() {
return Err(NeatifyError::IoError(std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("Directory does not exist: {}", dir_path.display()),
))
.into());
}
let mut stats = FormattingStats::new();
format_directory_recursive(dir_path, write, &mut stats)?;
Ok(stats)
}
fn format_directory_recursive(
dir_path: &Path,
write: bool,
stats: &mut FormattingStats,
) -> Result<()> {
for entry in std::fs::read_dir(dir_path)? {
let entry = entry?;
let path = entry.path();
if path.is_dir() {
if path
.file_name()
.map_or(false, |name| name == "node_modules")
{
continue;
}
format_directory_recursive(&path, write, stats)?;
} else if path.is_file() {
if let Some(formatter) = get_formatter_for_file(&path) {
stats.total_files += 1;
match formatter.format_file(&path, write) {
Ok(true) => {
if write {
stats.formatted_files += 1;
} else {
stats.files_needing_formatting += 1;
}
}
Ok(false) => {
}
Err(e) => {
return Err(NeatifyError::FormattingError(format!(
"Error formatting {}: {}",
path.display(),
e
))
.into());
}
}
}
}
}
Ok(())
}
fn get_formatter_for_file(file_path: &Path) -> Option<Box<dyn Formatter>> {
let formatters: Vec<Box<dyn Formatter>> =
vec![Box::new(javascript::JavaScriptFormatter::new())];
for formatter in formatters {
if formatter.is_supported(file_path) {
return Some(formatter);
}
}
None
}