Skip to main content

specfold_core/check/
finding.rs

1//! What a check reports: one problem, where it is, and how to fix it.
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
6#[serde(rename_all = "lowercase")]
7pub enum Severity {
8    Error,
9    Warn,
10}
11
12/// A fix an agent can apply without judgement: a command to run, or an exact replacement.
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
14#[serde(rename_all = "lowercase")]
15pub enum Fix {
16    Cmd(String),
17    Replace { path: String, line: usize, from: String, to: String },
18}
19
20#[derive(Debug, Clone, Serialize)]
21pub struct Finding {
22    pub rule: String,
23    pub severity: Severity,
24    pub path: String,
25    pub line: usize,
26    pub message: String,
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub fix: Option<Fix>,
29    #[serde(skip_serializing_if = "Vec::is_empty")]
30    pub candidates: Vec<String>,
31}
32
33impl Finding {
34    pub fn new(
35        rule: impl Into<String>,
36        severity: Severity,
37        path: impl Into<String>,
38        line: usize,
39        message: impl Into<String>,
40    ) -> Self {
41        Finding {
42            rule: rule.into(),
43            severity,
44            path: path.into(),
45            line,
46            message: message.into(),
47            fix: None,
48            candidates: vec![],
49        }
50    }
51
52    pub fn error(rule: impl Into<String>, path: impl Into<String>, line: usize, message: impl Into<String>) -> Self {
53        Self::new(rule, Severity::Error, path, line, message)
54    }
55
56    pub fn warn(rule: impl Into<String>, path: impl Into<String>, line: usize, message: impl Into<String>) -> Self {
57        Self::new(rule, Severity::Warn, path, line, message)
58    }
59
60    pub fn fix_cmd(mut self, cmd: impl Into<String>) -> Self {
61        self.fix = Some(Fix::Cmd(cmd.into()));
62        self
63    }
64
65    pub fn fix_replace(mut self, from: impl Into<String>, to: impl Into<String>) -> Self {
66        self.fix = Some(Fix::Replace { path: self.path.clone(), line: self.line, from: from.into(), to: to.into() });
67        self
68    }
69
70    pub fn with_candidates(mut self, c: Vec<String>) -> Self {
71        self.candidates = c;
72        self
73    }
74}