bashrs/validation/
mod.rs

1use crate::models::error::RashResult;
2use std::fmt;
3
4pub mod pipeline;
5pub mod rules;
6
7#[cfg(test)]
8mod tests;
9
10#[cfg(test)]
11mod pipeline_tests;
12
13#[derive(
14    Debug,
15    Clone,
16    Copy,
17    PartialEq,
18    Eq,
19    PartialOrd,
20    Ord,
21    Hash,
22    serde::Serialize,
23    serde::Deserialize,
24    Default,
25)]
26pub enum ValidationLevel {
27    None,
28    #[default]
29    Minimal,
30    Strict,
31    Paranoid,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum Severity {
36    Error,
37    Warning,
38    Style,
39}
40
41impl Severity {
42    pub fn as_str(&self) -> &'static str {
43        match self {
44            Severity::Error => "error",
45            Severity::Warning => "warning",
46            Severity::Style => "style",
47        }
48    }
49}
50
51#[derive(Debug, Clone)]
52pub struct ValidationError {
53    pub rule: &'static str,
54    pub severity: Severity,
55    pub message: String,
56    pub suggestion: Option<String>,
57    pub auto_fix: Option<Fix>,
58    pub line: Option<usize>,
59    pub column: Option<usize>,
60}
61
62#[derive(Debug, Clone)]
63pub struct Fix {
64    pub description: String,
65    pub replacement: String,
66}
67
68impl fmt::Display for ValidationError {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        write!(
71            f,
72            "[{}] {}: {}",
73            self.severity.as_str(),
74            self.rule,
75            self.message
76        )?;
77        if let Some(ref suggestion) = self.suggestion {
78            write!(f, "\n  Suggestion: {suggestion}")?;
79        }
80        Ok(())
81    }
82}
83
84impl std::error::Error for ValidationError {}
85
86pub trait Validate {
87    #[allow(clippy::result_large_err)]
88    fn validate(&self) -> Result<(), ValidationError>;
89}
90
91pub trait ShellCheckValidation {
92    type Error: std::error::Error;
93
94    fn validate(&self) -> Result<(), Self::Error>;
95    fn emit_safe(&self) -> String;
96}
97
98#[repr(C)]
99pub struct ValidatedNode {
100    node_type: u16,
101    rule_mask: u16,
102    validation: u32,
103}
104
105static_assertions::const_assert_eq!(std::mem::size_of::<ValidatedNode>(), 8);
106
107pub const IMPLEMENTED_RULES: &[&str] = &[
108    "SC2086", "SC2046", "SC2035", "SC2181", "SC2006", "SC2016", "SC2034", "SC2154", "SC2129",
109    "SC2164", "SC2103", "SC2115", "SC2162", "SC2219", "SC2220", "SC2088", "SC2068", "SC2145",
110    "SC2053", "SC2010",
111];
112
113pub fn validate_shell_snippet(snippet: &str) -> RashResult<()> {
114    rules::validate_all(snippet)
115}