use std::collections::HashMap;
use std::io::Write;
use mago_database::DatabaseReader;
use mago_database::ReadDatabase;
use mago_database::file::HasFileId;
use crate::IssueCollection;
use crate::Level;
use crate::error::ReportingError;
use crate::formatter::Formatter;
use crate::formatter::FormatterConfig;
use crate::formatter::utils::long_message;
use crate::formatter::utils::xml_encode;
pub(crate) struct CheckstyleFormatter;
impl Formatter for CheckstyleFormatter {
fn format(
&self,
writer: &mut dyn Write,
issues: &IssueCollection,
database: &ReadDatabase,
config: &FormatterConfig,
) -> Result<(), ReportingError> {
let mut issues_by_file: HashMap<String, Vec<String>> = HashMap::new();
for issue in crate::formatter::utils::filter_issues(issues, config, false) {
let (filename, line, column) = match issue.primary_annotation() {
Some(annotation) => {
let file = database.get(&annotation.span.file_id())?;
let line = file.line_number(annotation.span.start.offset) + 1;
let column = file.column_number(annotation.span.start.offset) + 1;
(file.name.to_string(), line, column)
}
None => ("<unknown>".to_string(), 0, 0),
};
let severity = match issue.level {
Level::Error => "error",
Level::Warning => "warning",
Level::Help | Level::Note => "info",
};
let message = xml_encode(long_message(issue, true));
let error_tag = format!(
" <error line=\"{line}\" column=\"{column}\" severity=\"{severity}\" message=\"{message}\" />"
);
issues_by_file.entry(filename).or_default().push(error_tag);
}
writeln!(writer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>")?;
writeln!(writer, "<checkstyle>")?;
for (filename, errors) in issues_by_file {
writeln!(writer, " <file name=\"{}\">", xml_encode(&filename))?;
for error in errors {
writeln!(writer, "{error}")?;
}
writeln!(writer, " </file>")?;
}
writeln!(writer, "</checkstyle>")?;
Ok(())
}
}