use std::path::Path;
use crate::rules::Issue;
pub fn report_text(issues: &[Issue]) -> usize {
if issues.is_empty() {
println!("✓ No performance issues found.");
return 0;
}
let mut sorted = issues.to_vec();
sorted.sort_by(|a, b| {
a.file
.cmp(&b.file)
.then(a.line.cmp(&b.line))
.then(a.column.cmp(&b.column))
});
let mut current_file: Option<&Path> = None;
for issue in &sorted {
if current_file != Some(&issue.file) {
if current_file.is_some() {
println!(); }
current_file = Some(&issue.file);
}
println!(
"{file}:{line}:{col} {severity} {rule:<22} {message}",
file = issue.file.display(),
line = issue.line,
col = issue.column,
severity = issue.severity,
rule = issue.rule,
message = issue.message,
);
}
println!();
let count = sorted.len();
let label = if count == 1 { "issue" } else { "issues" };
println!("✖ {count} {label} found");
count
}
pub fn report_json(issues: &[Issue]) -> usize {
#[derive(serde::Serialize)]
struct JsonIssue<'a> {
rule: &'a str,
message: &'a str,
file: String,
line: u32,
column: u32,
severity: &'a crate::rules::Severity,
}
let json_issues: Vec<JsonIssue<'_>> = issues
.iter()
.map(|i| JsonIssue {
rule: &i.rule,
message: &i.message,
file: i.file.display().to_string(),
line: i.line,
column: i.column,
severity: &i.severity,
})
.collect();
match serde_json::to_string_pretty(&json_issues) {
Ok(json) => println!("{json}"),
Err(err) => eprintln!("Error serializing JSON output: {err}"),
}
issues.len()
}
pub fn print_summary(issues: &[Issue]) {
use std::collections::HashMap;
if issues.is_empty() {
return;
}
let mut counts: HashMap<&str, usize> = HashMap::new();
for issue in issues {
*counts.entry(issue.rule.as_str()).or_insert(0) += 1;
}
let mut pairs: Vec<(&&str, &usize)> = counts.iter().collect();
pairs.sort_by_key(|(rule, _)| **rule);
eprintln!("\nSummary:");
for (rule, count) in pairs {
eprintln!(" {rule:<24} {count} issue(s)");
}
}