use crate::circular;
use crate::deadcode;
use crate::duplicates;
use crate::health;
use crate::index;
use crate::watcher;
use colored::*;
use serde_json;
use std::path::Path;
use std::sync::Arc;
pub fn handle_duplicates_command(
path: &Path,
extensions: Option<Vec<String>>,
exclude: Option<Vec<String>>,
min_lines: usize,
similarity: f64,
) -> Result<(), Box<dyn std::error::Error>> {
duplicates::detect_duplicates(
path,
extensions.as_deref(),
exclude.as_deref(),
min_lines,
similarity,
)?;
Ok(())
}
pub fn handle_deadcode_command(
path: &Path,
extensions: Option<Vec<String>>,
exclude: Option<Vec<String>>,
) -> Result<(), Box<dyn std::error::Error>> {
deadcode::detect_dead_code(path, extensions.as_deref(), exclude.as_deref())?;
Ok(())
}
pub fn handle_circular_command(
path: &Path,
extensions: Option<Vec<String>>,
exclude: Option<Vec<String>>,
) -> Result<(), Box<dyn std::error::Error>> {
circular::detect_circular_calls(path, extensions.as_deref(), exclude.as_deref())?;
Ok(())
}
pub fn handle_health_command(
path: &Path,
extensions: Option<Vec<String>>,
exclude: Option<Vec<String>>,
format: &str,
fail_under: Option<u8>,
) -> Result<(), Box<dyn std::error::Error>> {
let report = health::scan_health(path, extensions.as_deref(), exclude.as_deref())?;
if format == "json" {
println!("{}", serde_json::to_string_pretty(&report)?);
} else {
health::print_health_report(&report);
}
if let Some(threshold) = fail_under {
if report.score < threshold {
std::process::exit(1);
}
}
Ok(())
}
pub fn handle_index_command(
path: &Path,
extensions: Option<Vec<String>>,
exclude: Option<Vec<String>>,
index_file: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
println!("{}", "Building code index...".cyan().bold());
let index = Arc::new(index::CodeIndex::new(index_file.to_path_buf()));
index.index_directory(path, extensions.as_deref(), exclude.as_deref())?;
index.save()?;
let stats = index.get_stats();
println!("\n{}", "Index Statistics:".green().bold());
println!(" Total files: {}", stats.total_files);
println!(" Total lines: {}", stats.total_lines);
println!(" Total functions: {}", stats.total_functions);
println!(" Total classes: {}", stats.total_classes);
println!(
"\n{}",
format!("Index saved to: {}", index_file.display()).green()
);
Ok(())
}
pub fn handle_watch_command(
path: &Path,
extensions: Option<Vec<String>>,
index_file: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
println!("{}", "Starting file watcher...".cyan().bold());
let index = Arc::new(index::CodeIndex::new(index_file.to_path_buf()));
watcher::start_watching(path.to_path_buf(), index, extensions)?;
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tempfile::tempdir;
#[test]
fn test_handle_duplicates_command() {
let dir = tempdir().unwrap();
fs::write(dir.path().join("test.rs"), "fn test() {}").unwrap();
let result =
handle_duplicates_command(dir.path(), Some(vec!["rs".to_string()]), None, 5, 0.8);
assert!(result.is_ok());
}
#[test]
fn test_handle_deadcode_command() {
let dir = tempdir().unwrap();
fs::write(dir.path().join("test.rs"), "fn test() {}").unwrap();
let result = handle_deadcode_command(dir.path(), Some(vec!["rs".to_string()]), None);
assert!(result.is_ok());
}
#[test]
fn test_handle_circular_command() {
let dir = tempdir().unwrap();
fs::write(dir.path().join("test.rs"), "fn test() {}").unwrap();
let result = handle_circular_command(dir.path(), Some(vec!["rs".to_string()]), None);
assert!(result.is_ok());
}
#[test]
fn test_handle_health_command() {
let dir = tempdir().unwrap();
fs::write(dir.path().join("test.rs"), "fn test() {}").unwrap();
let result =
handle_health_command(dir.path(), Some(vec!["rs".to_string()]), None, "text", None);
assert!(result.is_ok());
}
}