use crate::formatting::FormattingConfig;
use crate::priority::{UnifiedAnalysis, UnifiedAnalysisQueries};
use std::fmt::Write;
mod categorical;
mod details;
mod priority_item;
mod tiered;
mod utilities;
use categorical::{
format_categorical_summary, format_category_section, format_cross_category_dependencies,
};
use priority_item::format_mixed_priority_item_markdown;
use tiered::format_tier_section;
pub fn format_priorities_markdown(
analysis: &UnifiedAnalysis,
limit: usize,
verbosity: u8,
config: FormattingConfig,
) -> String {
let mut output = String::new();
let version = env!("CARGO_PKG_VERSION");
writeln!(output, "# Debtmap v{}\n", version).unwrap();
let top_items = analysis.get_top_mixed_priorities(limit);
let count = top_items.len().min(limit);
writeln!(output, "## Top {} Recommendations\n", count).unwrap();
for (idx, item) in top_items.iter().enumerate() {
format_mixed_priority_item_markdown(&mut output, idx + 1, item, verbosity, &config);
writeln!(output).unwrap();
}
writeln!(output, "---\n").unwrap();
writeln!(
output,
"**Total Debt Score:** {:.0}",
analysis.total_debt_score
)
.unwrap();
writeln!(
output,
"**Debt Density:** {:.1} per 1K LOC ({} total LOC)",
analysis.debt_density, analysis.total_lines_of_code
)
.unwrap();
if let Some(coverage) = analysis.overall_coverage {
writeln!(output, "**Overall Coverage:** {:.2}%", coverage).unwrap();
}
output
}
pub fn format_priorities_categorical_markdown(
analysis: &UnifiedAnalysis,
limit: usize,
verbosity: u8,
) -> String {
let mut output = String::new();
let version = env!("CARGO_PKG_VERSION");
writeln!(output, "# Debtmap v{}\n", version).unwrap();
let categorized = analysis.get_categorized_debt(limit);
writeln!(output, "## Technical Debt Analysis - By Category\n").unwrap();
let mut sorted_categories: Vec<_> = categorized.categories.iter().collect();
sorted_categories.sort_by(|a, b| {
b.1.total_score
.partial_cmp(&a.1.total_score)
.unwrap_or(std::cmp::Ordering::Equal)
});
for (category, summary) in sorted_categories {
format_category_section(&mut output, category, summary, verbosity);
}
if !categorized.cross_category_dependencies.is_empty() {
format_cross_category_dependencies(&mut output, &categorized.cross_category_dependencies);
}
format_categorical_summary(&mut output, &categorized);
writeln!(output).unwrap();
writeln!(
output,
"**Total Debt Score:** {:.0}",
analysis.total_debt_score
)
.unwrap();
writeln!(
output,
"**Debt Density:** {:.1} per 1K LOC ({} total LOC)",
analysis.debt_density, analysis.total_lines_of_code
)
.unwrap();
if let Some(coverage) = analysis.overall_coverage {
writeln!(output, "**Overall Coverage:** {:.2}%", coverage).unwrap();
}
output
}
pub fn format_priorities_tiered_markdown(
analysis: &UnifiedAnalysis,
limit: usize,
verbosity: u8,
) -> String {
let mut output = String::new();
let version = env!("CARGO_PKG_VERSION");
writeln!(output, "# Debtmap v{}\n", version).unwrap();
let tiered_display = analysis.get_tiered_display(limit);
writeln!(output, "## Technical Debt Analysis - Priority Tiers\n").unwrap();
use crate::priority::Tier;
format_tier_section(
&mut output,
&tiered_display.critical,
Tier::Critical,
verbosity,
);
format_tier_section(&mut output, &tiered_display.high, Tier::High, verbosity);
format_tier_section(
&mut output,
&tiered_display.moderate,
Tier::Moderate,
verbosity,
);
format_tier_section(&mut output, &tiered_display.low, Tier::Low, verbosity);
writeln!(output, "---\n").unwrap();
writeln!(output, "## Summary\n").unwrap();
let critical_count: usize = tiered_display.critical.iter().map(|g| g.items.len()).sum();
let high_count: usize = tiered_display.high.iter().map(|g| g.items.len()).sum();
let moderate_count: usize = tiered_display.moderate.iter().map(|g| g.items.len()).sum();
let low_count: usize = tiered_display.low.iter().map(|g| g.items.len()).sum();
writeln!(
output,
"**Total Debt Items:** {}",
critical_count + high_count + moderate_count + low_count
)
.unwrap();
writeln!(output, "- [CRITICAL] Critical: {} items", critical_count).unwrap();
writeln!(output, "- [WARN] High: {} items", high_count).unwrap();
writeln!(output, "- Moderate: {} items", moderate_count).unwrap();
writeln!(output, "- [INFO] Low: {} items", low_count).unwrap();
writeln!(output).unwrap();
writeln!(
output,
"**Total Debt Score:** {:.0}",
analysis.total_debt_score
)
.unwrap();
writeln!(
output,
"**Debt Density:** {:.1} per 1K LOC ({} total LOC)",
analysis.debt_density, analysis.total_lines_of_code
)
.unwrap();
if let Some(coverage) = analysis.overall_coverage {
writeln!(output, "**Overall Coverage:** {:.2}%", coverage).unwrap();
}
output
}
pub fn format_filter_metrics(metrics: &crate::priority::FilterMetrics) -> String {
let mut output = String::new();
writeln!(output, "## Filtering Summary\n").unwrap();
writeln!(
output,
"- **Total items analyzed**: {}",
metrics.total_items
)
.unwrap();
writeln!(
output,
"- **Items included**: {} ({:.1}%)",
metrics.included,
metrics.inclusion_rate()
)
.unwrap();
writeln!(
output,
"- **Items filtered**: {}\n",
metrics.total_filtered()
)
.unwrap();
if metrics.total_filtered() > 0 {
writeln!(output, "### Filtering Breakdown\n").unwrap();
if metrics.filtered_t4_maintenance > 0 {
writeln!(
output,
"- **Low-priority (T4)**: {} items (use `--min-score 0` to see)",
metrics.filtered_t4_maintenance
)
.unwrap();
}
if metrics.filtered_below_score > 0 {
writeln!(
output,
"- **Below score threshold**: {} items (threshold: {:.1})",
metrics.filtered_below_score, metrics.min_score_threshold
)
.unwrap();
}
if metrics.filtered_by_debt_type > 0 {
writeln!(
output,
"- **Disabled debt types**: {} items",
metrics.filtered_by_debt_type
)
.unwrap();
}
}
writeln!(output).unwrap();
output
}