nu_protocol/config/
error.rs

1use super::ConfigPath;
2use crate::{Config, ConfigError, ConfigWarning, ShellError, ShellWarning, Span, Type, Value};
3
4#[derive(Debug)]
5#[must_use]
6pub(super) struct ConfigErrors<'a> {
7    config: &'a Config,
8    errors: Vec<ConfigError>,
9    warnings: Vec<ConfigWarning>,
10}
11
12impl<'a> ConfigErrors<'a> {
13    pub fn new(config: &'a Config) -> Self {
14        Self {
15            config,
16            errors: Vec::new(),
17            warnings: Vec::new(),
18        }
19    }
20
21    pub fn has_errors(&self) -> bool {
22        !self.errors.is_empty()
23    }
24
25    pub fn has_warnings(&self) -> bool {
26        !self.warnings.is_empty()
27    }
28
29    pub fn error(&mut self, error: ConfigError) {
30        self.errors.push(error);
31    }
32
33    pub fn warn(&mut self, warning: ConfigWarning) {
34        self.warnings.push(warning);
35    }
36
37    pub fn type_mismatch(&mut self, path: &ConfigPath, expected: Type, actual: &Value) {
38        self.error(ConfigError::TypeMismatch {
39            path: path.to_string(),
40            expected,
41            actual: actual.get_type(),
42            span: actual.span(),
43        });
44    }
45
46    pub fn invalid_value(
47        &mut self,
48        path: &ConfigPath,
49        expected: impl Into<String>,
50        actual: &Value,
51    ) {
52        self.error(ConfigError::InvalidValue {
53            path: path.to_string(),
54            valid: expected.into(),
55            actual: if let Ok(str) = actual.as_str() {
56                format!("'{str}'")
57            } else {
58                actual.to_abbreviated_string(self.config)
59            },
60            span: actual.span(),
61        });
62    }
63
64    pub fn missing_column(&mut self, path: &ConfigPath, column: &'static str, span: Span) {
65        self.error(ConfigError::MissingRequiredColumn {
66            path: path.to_string(),
67            column,
68            span,
69        })
70    }
71
72    pub fn unknown_option(&mut self, path: &ConfigPath, value: &Value) {
73        self.error(ConfigError::UnknownOption {
74            path: path.to_string(),
75            span: value.span(),
76        });
77    }
78
79    // We'll probably need this again in the future so allow dead code for now
80    #[allow(dead_code)]
81    pub fn deprecated_option(&mut self, path: &ConfigPath, suggestion: &'static str, span: Span) {
82        self.error(ConfigError::Deprecated {
83            path: path.to_string(),
84            suggestion,
85            span,
86        });
87    }
88
89    pub fn check(self) -> Result<Option<ShellWarning>, ShellError> {
90        match (self.has_errors(), self.has_warnings()) {
91            (true, _) => Err(ShellError::InvalidConfig {
92                errors: self.errors,
93            }),
94            (false, true) => Ok(Some(ShellWarning::InvalidConfig {
95                warnings: self.warnings,
96            })),
97            (false, false) => Ok(None),
98        }
99    }
100}