Skip to main content

pgevolve_core/lint/
finding.rs

1//! [`Finding`] and [`Severity`] — the unit of lint output.
2
3use crate::parse::SourceLocation;
4
5/// Severity of a single [`Finding`]. Affects exit codes only — both severities
6/// are printed.
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub enum Severity {
9    /// A rule violation that should fail the lint.
10    Error,
11    /// A best-practice violation; does not fail the lint.
12    Warning,
13    /// Drift / divergence detected at plan time that pgevolve declines
14    /// to act on without explicit user instruction. By default, plan
15    /// fails when any `LintAtPlan` finding is present without a matching
16    /// `[[lint_waiver]]` row in `intent.toml`. See arch spec Decisions
17    /// 13–14.
18    LintAtPlan,
19}
20
21impl std::fmt::Display for Severity {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        f.write_str(match self {
24            Self::Error => "error",
25            Self::Warning => "warning",
26            Self::LintAtPlan => "lint-at-plan",
27        })
28    }
29}
30
31/// One lint finding.
32#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct Finding {
34    /// Severity classification.
35    pub severity: Severity,
36    /// Stable rule identifier (used for filter / deny / explain).
37    pub rule: &'static str,
38    /// Human-readable message.
39    pub message: String,
40    /// Optional source location.
41    pub location: Option<SourceLocation>,
42}
43
44impl Finding {
45    /// Build an error-severity finding.
46    pub fn error(rule: &'static str, message: impl Into<String>) -> Self {
47        Self {
48            severity: Severity::Error,
49            rule,
50            message: message.into(),
51            location: None,
52        }
53    }
54
55    /// Build a warning-severity finding.
56    pub fn warning(rule: &'static str, message: impl Into<String>) -> Self {
57        Self {
58            severity: Severity::Warning,
59            rule,
60            message: message.into(),
61            location: None,
62        }
63    }
64
65    /// Build a lint-at-plan-severity finding.
66    pub fn lint_at_plan(rule: &'static str, message: impl Into<String>) -> Self {
67        Self {
68            severity: Severity::LintAtPlan,
69            rule,
70            message: message.into(),
71            location: None,
72        }
73    }
74
75    /// Attach a source location.
76    #[must_use]
77    pub fn at(mut self, loc: SourceLocation) -> Self {
78        self.location = Some(loc);
79        self
80    }
81}