#[allow(clippy::too_many_arguments)]
async fn analyze_single_file(
calculator: &crate::services::tdg_calculator::TDGCalculator,
project_path: &Path,
file: PathBuf,
threshold: f64,
format: TdgOutputFormat,
include_components: bool,
critical_only: bool,
verbose: bool,
) -> Result<String> {
eprintln!("📄 Analyzing TDG for file: {}", file.display());
let full_path = if file.is_absolute() {
file
} else {
project_path.join(&file)
};
if !full_path.exists() {
anyhow::bail!("File not found: {}", full_path.display());
}
let score = calculator.calculate_file(&full_path).await?;
if critical_only && score.value <= 2.5 {
return Ok(format_empty_results(format));
}
if score.value < threshold {
return Ok(format_empty_results(format));
}
format_tdg_single_file_output(&score, &full_path, format, include_components, verbose)
}
#[allow(clippy::too_many_arguments)]
async fn analyze_multiple_files(
calculator: &crate::services::tdg_calculator::TDGCalculator,
project_path: &Path,
files: Vec<PathBuf>,
threshold: f64,
top_files: usize,
format: TdgOutputFormat,
include_components: bool,
critical_only: bool,
verbose: bool,
) -> Result<String> {
eprintln!("📄 Analyzing TDG for {} files...", files.len());
let results =
process_files_for_tdg(calculator, project_path, files, threshold, critical_only).await;
let filtered_results = apply_results_filtering(results, top_files);
let summary = create_summary_from_file_results(&filtered_results);
format_output_from_summary(&summary, format, include_components, verbose)
}
async fn process_files_for_tdg(
calculator: &crate::services::tdg_calculator::TDGCalculator,
project_path: &Path,
files: Vec<PathBuf>,
threshold: f64,
critical_only: bool,
) -> Vec<(crate::models::tdg::TDGScore, PathBuf)> {
let mut results = Vec::new();
for file_path in files {
let full_path = resolve_file_path(project_path, file_path);
if !full_path.exists() {
eprintln!("⚠️ Skipping missing file: {}", full_path.display());
continue;
}
if let Some(score) =
calculate_and_filter_file(calculator, &full_path, threshold, critical_only).await
{
results.push((score, full_path));
}
}
results
}
async fn calculate_and_filter_file(
calculator: &crate::services::tdg_calculator::TDGCalculator,
full_path: &Path,
threshold: f64,
critical_only: bool,
) -> Option<crate::models::tdg::TDGScore> {
match calculator.calculate_file(full_path).await {
Ok(score) => {
if should_include_score(&score, threshold, critical_only) {
Some(score)
} else {
None
}
}
Err(e) => {
eprintln!("⚠️ Error analyzing {}: {}", full_path.display(), e);
None
}
}
}
#[allow(clippy::too_many_arguments)]
async fn analyze_project(
calculator: &crate::services::tdg_calculator::TDGCalculator,
project_path: &Path,
_include: Vec<String>,
threshold: f64,
top_files: usize,
format: TdgOutputFormat,
include_components: bool,
critical_only: bool,
verbose: bool,
) -> Result<String> {
eprintln!("📁 Project path: {}", project_path.display());
let mut summary = calculator.analyze_directory(project_path).await?;
summary.hotspots = summary
.hotspots
.into_iter()
.filter(|h| {
if critical_only {
h.tdg_score > 2.5
} else {
h.tdg_score >= threshold
}
})
.take(if top_files > 0 { top_files } else { usize::MAX })
.collect();
format_output_from_summary(&summary, format, include_components, verbose)
}