weggli_ruleset/
reporting.rs1use std::borrow::Cow;
2use std::fmt::Debug;
3use std::sync::Arc;
4
5use rustc_hash::FxHashSet;
6use serde::{Deserialize, Serialize};
7use weggli::result::QueryResult;
8
9use crate::matcher::RuleMatch;
10use crate::rule::Severity;
11
12#[derive(Deserialize, Serialize)]
13pub struct RuleMatchReport<'a> {
14 rule: Cow<'a, str>,
15 checker: Cow<'a, str>,
16 #[serde(skip_serializing_if = "str::is_empty")]
17 description: Cow<'a, str>,
18 #[serde(skip_serializing_if = "FxHashSet::<String>::is_empty")]
19 tags: Cow<'a, FxHashSet<String>>,
20 severity: Severity,
21 source: Arc<str>,
22 #[serde(rename = "match")]
23 match_result: Cow<'a, QueryResult>,
24}
25
26impl<'a> Debug for RuleMatchReport<'a> {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 let mut m = f.debug_struct("RuleMatchReport");
29
30 m.field("rule", &self.rule as _);
31 m.field("checker", &self.checker as _);
32
33 if let Some(ref description) = self.description() {
34 m.field("description", description as _);
35 }
36
37 m.field("tags", self.tags());
38 m.field("severity", &self.severity as _);
39 m.field("matches", &self.match_result as _);
40
41 m.finish_non_exhaustive()
42 }
43}
44
45impl<'a> RuleMatchReport<'a> {
46 pub fn new(m: &'a RuleMatch) -> Self {
47 Self {
48 rule: Cow::Borrowed(m.rule().id()),
49 description: Cow::Borrowed(m.rule().description().unwrap_or_default()),
50 checker: Cow::Borrowed(m.checker().name()),
51 tags: Cow::Borrowed(m.rule().tags()),
52 severity: m.rule().severity(),
53 source: m.source(),
54 match_result: Cow::Borrowed(m.result()),
55 }
56 }
57
58 pub fn rule(&self) -> &str {
59 &self.rule
60 }
61
62 pub fn checker(&self) -> &str {
63 &self.checker
64 }
65
66 pub fn description(&self) -> Option<&str> {
67 if self.description.is_empty() {
68 None
69 } else {
70 Some(&self.description)
71 }
72 }
73
74 pub fn severity(&self) -> Severity {
75 self.severity
76 }
77
78 pub fn tags(&self) -> &FxHashSet<String> {
79 &self.tags
80 }
81
82 pub fn source(&self) -> &str {
83 &self.source
84 }
85
86 pub fn result(&self) -> &QueryResult {
87 &self.match_result
88 }
89
90 pub fn display(&self, before: usize, after: usize, line_numbers: bool) -> String {
91 self.match_result
92 .display(&self.source, before, after, line_numbers)
93 }
94
95 pub fn into_owned(self) -> RuleMatchReport<'static> {
96 RuleMatchReport {
97 rule: self.rule.into_owned().into(),
98 description: self.description.into_owned().into(),
99 checker: self.checker.into_owned().into(),
100 tags: Cow::Owned(self.tags.into_owned()),
101 severity: self.severity,
102 source: self.source,
103 match_result: Cow::Owned(self.match_result.into_owned()),
104 }
105 }
106}