react_auditor/formatters/
stylish.rs1use std::io::Write;
2
3use termcolor::{Buffer, Color, ColorSpec, WriteColor};
4
5use crate::formatters::Formatter;
6use crate::rules::Severity;
7use crate::scanner::ScanResult;
8
9pub struct StylishFormatter;
10
11impl Formatter for StylishFormatter {
12 fn format(&self, results: &[ScanResult], quiet: bool) -> String {
13 let mut buf = Buffer::ansi();
14 let mut error_count = 0u32;
15 let mut warning_count = 0u32;
16
17 for result in results {
18 let violations: Vec<_> = result
19 .violations
20 .iter()
21 .filter(|v| {
22 if quiet {
23 v.severity == Severity::Error
24 } else {
25 true
26 }
27 })
28 .collect();
29
30 if violations.is_empty() {
31 continue;
32 }
33
34 let _ = writeln!(buf, "\n{}:", result.file_path);
35
36 for v in &violations {
37 let (severity_str, color) = match v.severity {
38 Severity::Error => {
39 error_count += 1;
40 ("error", Color::Red)
41 }
42 Severity::Warning => {
43 warning_count += 1;
44 ("warning", Color::Yellow)
45 }
46 Severity::Off => continue,
47 };
48
49 let _ = buf.set_color(ColorSpec::new().set_fg(Some(Color::Cyan)));
50 let _ = write!(buf, " {severity_str} {}:{} ", v.line, v.column);
51 let _ = buf.set_color(ColorSpec::new().set_fg(Some(Color::Blue)));
52 let _ = write!(buf, "[{}/{}]", v.category, v.rule_id);
53 let _ = buf.set_color(ColorSpec::new().set_fg(Some(color)));
54 let _ = write!(buf, " {}", v.message);
55 let _ = buf.reset();
56 let _ = writeln!(buf);
57 }
58 }
59
60 let total = error_count + warning_count;
61 if total > 0 {
62 let _ = writeln!(buf);
63 if error_count > 0 {
64 let _ = buf.set_color(ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true));
65 let _ = writeln!(buf, " {error_count} error(s)");
66 }
67 if warning_count > 0 {
68 let _ = buf.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)).set_bold(true));
69 let _ = writeln!(buf, " {warning_count} warning(s)");
70 }
71 let _ = buf.reset();
72 }
73
74 String::from_utf8(buf.into_inner()).unwrap_or_default()
75 }
76}