1use crate::level::Level;
2use crate::rule::{RuleResult, Violation};
3
4#[derive(Debug, Clone)]
5pub struct Report {
6 pub results: Vec<RuleResult>,
7}
8
9impl Report {
10 pub fn has_errors(&self) -> bool {
11 self.results
12 .iter()
13 .any(|r| r.level == Level::Error && !r.violations.is_empty())
14 }
15
16 pub fn has_warnings(&self) -> bool {
17 self.results
18 .iter()
19 .any(|r| r.level == Level::Warning && !r.violations.is_empty())
20 }
21
22 pub fn total_violations(&self) -> usize {
23 self.results.iter().map(|r| r.violations.len()).sum()
24 }
25
26 pub fn failing_rules(&self) -> usize {
27 self.results.iter().filter(|r| !r.passed()).count()
28 }
29
30 pub fn passing_rules(&self) -> usize {
31 self.results.iter().filter(|r| r.passed()).count()
32 }
33}
34
35#[derive(Debug, Clone)]
39pub struct FixReport {
40 pub results: Vec<FixRuleResult>,
41}
42
43#[derive(Debug, Clone)]
44pub struct FixRuleResult {
45 pub rule_id: String,
46 pub level: Level,
47 pub items: Vec<FixItem>,
48}
49
50#[derive(Debug, Clone)]
51pub struct FixItem {
52 pub violation: Violation,
53 pub status: FixStatus,
54}
55
56#[derive(Debug, Clone)]
57pub enum FixStatus {
58 Applied(String),
60 Skipped(String),
63 Unfixable,
65}
66
67impl FixReport {
68 pub fn applied(&self) -> usize {
69 self.items()
70 .filter(|i| matches!(i.status, FixStatus::Applied(_)))
71 .count()
72 }
73
74 pub fn skipped(&self) -> usize {
75 self.items()
76 .filter(|i| matches!(i.status, FixStatus::Skipped(_)))
77 .count()
78 }
79
80 pub fn unfixable(&self) -> usize {
81 self.items()
82 .filter(|i| matches!(i.status, FixStatus::Unfixable))
83 .count()
84 }
85
86 pub fn has_unfixable_errors(&self) -> bool {
88 self.results
89 .iter()
90 .any(|r| r.level == Level::Error && has_unresolved(&r.items))
91 }
92
93 pub fn has_unfixable_warnings(&self) -> bool {
94 self.results
95 .iter()
96 .any(|r| r.level == Level::Warning && has_unresolved(&r.items))
97 }
98
99 fn items(&self) -> impl Iterator<Item = &FixItem> {
100 self.results.iter().flat_map(|r| &r.items)
101 }
102}
103
104fn has_unresolved(items: &[FixItem]) -> bool {
105 items
106 .iter()
107 .any(|i| matches!(i.status, FixStatus::Skipped(_) | FixStatus::Unfixable))
108}