systemprompt_traits/
validation_report.rs1use std::path::PathBuf;
7
8#[derive(Debug, Clone)]
9pub struct ValidationError {
10 pub field: String,
11 pub message: String,
12 pub path: Option<PathBuf>,
13 pub suggestion: Option<String>,
14}
15
16impl ValidationError {
17 #[must_use]
18 pub fn new(field: impl Into<String>, message: impl Into<String>) -> Self {
19 Self {
20 field: field.into(),
21 message: message.into(),
22 path: None,
23 suggestion: None,
24 }
25 }
26
27 #[must_use]
28 pub fn with_path(mut self, path: impl Into<PathBuf>) -> Self {
29 self.path = Some(path.into());
30 self
31 }
32
33 #[must_use]
34 pub fn with_suggestion(mut self, suggestion: impl Into<String>) -> Self {
35 self.suggestion = Some(suggestion.into());
36 self
37 }
38}
39
40impl std::fmt::Display for ValidationError {
41 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42 write!(f, "{}\n {}", self.field, self.message)?;
43 if let Some(ref path) = self.path {
44 write!(f, "\n Path: {}", path.display())?;
45 }
46 if let Some(ref suggestion) = self.suggestion {
47 write!(f, "\n To fix: {}", suggestion)?;
48 }
49 Ok(())
50 }
51}
52
53#[derive(Debug, Clone)]
54pub struct ValidationWarning {
55 pub field: String,
56 pub message: String,
57 pub suggestion: Option<String>,
58}
59
60impl ValidationWarning {
61 #[must_use]
62 pub fn new(field: impl Into<String>, message: impl Into<String>) -> Self {
63 Self {
64 field: field.into(),
65 message: message.into(),
66 suggestion: None,
67 }
68 }
69
70 #[must_use]
71 pub fn with_suggestion(mut self, suggestion: impl Into<String>) -> Self {
72 self.suggestion = Some(suggestion.into());
73 self
74 }
75}
76
77#[derive(Debug, Clone, Default)]
78pub struct ValidationReport {
79 pub domain: String,
80 pub errors: Vec<ValidationError>,
81 pub warnings: Vec<ValidationWarning>,
82}
83
84impl ValidationReport {
85 #[must_use]
86 pub fn new(domain: impl Into<String>) -> Self {
87 Self {
88 domain: domain.into(),
89 errors: Vec::new(),
90 warnings: Vec::new(),
91 }
92 }
93
94 pub fn add_error(&mut self, error: ValidationError) {
95 self.errors.push(error);
96 }
97
98 pub fn add_warning(&mut self, warning: ValidationWarning) {
99 self.warnings.push(warning);
100 }
101
102 pub const fn has_errors(&self) -> bool {
103 !self.errors.is_empty()
104 }
105
106 pub const fn has_warnings(&self) -> bool {
107 !self.warnings.is_empty()
108 }
109
110 pub const fn is_clean(&self) -> bool {
111 self.errors.is_empty() && self.warnings.is_empty()
112 }
113
114 pub fn merge(&mut self, other: Self) {
115 self.errors.extend(other.errors);
116 self.warnings.extend(other.warnings);
117 }
118}
119
120#[derive(Debug, Clone, Default)]
121pub struct StartupValidationReport {
122 pub profile_path: Option<PathBuf>,
123 pub domains: Vec<ValidationReport>,
124 pub extensions: Vec<ValidationReport>,
125}
126
127impl StartupValidationReport {
128 #[must_use]
129 pub fn new() -> Self {
130 Self::default()
131 }
132
133 #[must_use]
134 pub fn with_profile_path(mut self, path: impl Into<PathBuf>) -> Self {
135 self.profile_path = Some(path.into());
136 self
137 }
138
139 pub fn add_domain(&mut self, report: ValidationReport) {
140 self.domains.push(report);
141 }
142
143 pub fn add_extension(&mut self, report: ValidationReport) {
144 self.extensions.push(report);
145 }
146
147 pub fn has_errors(&self) -> bool {
148 self.domains.iter().any(ValidationReport::has_errors)
149 || self.extensions.iter().any(ValidationReport::has_errors)
150 }
151
152 pub fn has_warnings(&self) -> bool {
153 self.domains.iter().any(ValidationReport::has_warnings)
154 || self.extensions.iter().any(ValidationReport::has_warnings)
155 }
156
157 pub fn error_count(&self) -> usize {
158 self.domains.iter().map(|r| r.errors.len()).sum::<usize>()
159 + self
160 .extensions
161 .iter()
162 .map(|r| r.errors.len())
163 .sum::<usize>()
164 }
165
166 pub fn warning_count(&self) -> usize {
167 self.domains.iter().map(|r| r.warnings.len()).sum::<usize>()
168 + self
169 .extensions
170 .iter()
171 .map(|r| r.warnings.len())
172 .sum::<usize>()
173 }
174}
175
176impl std::fmt::Display for StartupValidationReport {
177 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178 write!(
179 f,
180 "{} error(s), {} warning(s)",
181 self.error_count(),
182 self.warning_count()
183 )
184 }
185}
186
187#[derive(Debug, thiserror::Error)]
188#[error("Startup validation failed with {0}")]
189pub struct StartupValidationError(pub StartupValidationReport);
190
191impl From<StartupValidationReport> for StartupValidationError {
192 fn from(report: StartupValidationReport) -> Self {
193 Self(report)
194 }
195}