1use std::fmt;
4
5#[derive(Default, Debug)]
7pub struct Diagnostics(Vec<Diagnostic>);
8
9impl Diagnostics {
10 pub fn any_fatal(&self) -> bool {
12 self.0.iter().any(|diagnostic| diagnostic.severity.is_error())
13 }
14
15 pub fn is_empty(&self) -> bool {
17 self.0.is_empty()
18 }
19
20 pub fn iter(&self) -> impl Iterator<Item = &Diagnostic> {
22 self.0.iter()
23 }
24
25 pub fn iter_warnings(&self) -> impl Iterator<Item = &str> {
27 self.0
28 .iter()
29 .filter(|diagnostic| diagnostic.severity.is_warning())
30 .map(|diagnostic| diagnostic.message.as_str())
31 }
32
33 pub fn iter_errors(&self) -> impl Iterator<Item = &str> {
35 self.0
36 .iter()
37 .filter(|diagnostic| diagnostic.severity.is_error())
38 .map(|diagnostic| diagnostic.message.as_str())
39 }
40
41 pub(crate) fn clone_all_from(&mut self, other: &Diagnostics) {
42 self.0.extend(other.0.iter().cloned())
43 }
44
45 pub fn iter_messages(&self) -> impl Iterator<Item = &str> {
47 self.0.iter().map(|diagnostic| diagnostic.message.as_str())
48 }
49
50 pub(crate) fn push_composite_schemas_source_schema_validation_error(
51 &mut self,
52 source_schema_name: &str,
53 message: impl fmt::Display,
54 error_code: CompositeSchemasSourceSchemaValidationErrorCode,
55 ) {
56 self.0.push(Diagnostic {
57 message: format!("[{source_schema_name}] {message}"),
58 severity: error_code.severity(),
59 error_code: Some(error_code.into()),
60 });
61 }
62
63 pub(crate) fn push_composite_schemas_pre_merge_validation_error(
64 &mut self,
65 message: String,
66 error_code: CompositeSchemasPreMergeValidationErrorCode,
67 ) {
68 self.0.push(Diagnostic {
69 message,
70 severity: error_code.severity(),
71 error_code: Some(error_code.into()),
72 });
73 }
74
75 pub(crate) fn push_composite_schemas_post_merge_validation_error(
76 &mut self,
77 message: String,
78 error_code: CompositeSchemasPostMergeValidationErrorCode,
79 ) {
80 self.0.push(Diagnostic {
81 message,
82 severity: error_code.severity(),
83 error_code: Some(error_code.into()),
84 });
85 }
86
87 pub(crate) fn push_fatal(&mut self, message: String) {
88 self.0.push(Diagnostic {
89 message,
90 severity: Severity::Error,
91 error_code: None,
92 });
93 }
94
95 pub(crate) fn push_warning(&mut self, message: String) {
96 self.0.push(Diagnostic {
97 message,
98 severity: Severity::Warning,
99 error_code: None,
100 });
101 }
102}
103
104#[derive(Debug, Clone)]
106pub struct Diagnostic {
107 message: String,
108 severity: Severity,
109 error_code: Option<CompositeSchemasErrorCode>,
110}
111
112impl Diagnostic {
113 pub fn message(&self) -> &str {
115 &self.message
116 }
117
118 pub fn severity(&self) -> Severity {
120 self.severity
121 }
122
123 pub fn composite_schemas_error_code(&self) -> Option<CompositeSchemasErrorCode> {
125 self.error_code
126 }
127}
128
129#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
131pub enum Severity {
132 Error,
134 Warning,
136}
137
138impl Severity {
139 #[must_use]
143 pub fn is_error(&self) -> bool {
144 matches!(self, Self::Error)
145 }
146
147 #[must_use]
151 pub fn is_warning(&self) -> bool {
152 matches!(self, Self::Warning)
153 }
154}
155
156#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
158#[non_exhaustive]
159pub enum CompositeSchemasErrorCode {
160 SourceSchema(CompositeSchemasSourceSchemaValidationErrorCode),
162 PreMerge(CompositeSchemasPreMergeValidationErrorCode),
164 PostMerge(CompositeSchemasPostMergeValidationErrorCode),
166}
167
168impl From<CompositeSchemasPostMergeValidationErrorCode> for CompositeSchemasErrorCode {
169 fn from(v: CompositeSchemasPostMergeValidationErrorCode) -> Self {
170 Self::PostMerge(v)
171 }
172}
173
174impl From<CompositeSchemasSourceSchemaValidationErrorCode> for CompositeSchemasErrorCode {
175 fn from(v: CompositeSchemasSourceSchemaValidationErrorCode) -> Self {
176 Self::SourceSchema(v)
177 }
178}
179
180impl From<CompositeSchemasPreMergeValidationErrorCode> for CompositeSchemasErrorCode {
181 fn from(v: CompositeSchemasPreMergeValidationErrorCode) -> Self {
182 Self::PreMerge(v)
183 }
184}
185
186#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
188#[non_exhaustive]
189pub enum CompositeSchemasSourceSchemaValidationErrorCode {
190 QueryRootTypeInaccessible,
192 LookupReturnsNonNullableType,
194 OverrideFromSelf,
196 ProvidesDirectiveInFieldsArgument,
198}
199
200impl CompositeSchemasSourceSchemaValidationErrorCode {
201 fn severity(&self) -> Severity {
202 use CompositeSchemasSourceSchemaValidationErrorCode::*;
203
204 match self {
205 QueryRootTypeInaccessible | OverrideFromSelf | ProvidesDirectiveInFieldsArgument => Severity::Error,
206
207 LookupReturnsNonNullableType => Severity::Warning,
208 }
209 }
210}
211
212#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
214pub enum CompositeSchemasPreMergeValidationErrorCode {
215 TypeKindMismatch,
217 OverrideSourceHasOverride,
219}
220
221impl CompositeSchemasPreMergeValidationErrorCode {
222 fn severity(&self) -> Severity {
223 use CompositeSchemasPreMergeValidationErrorCode::*;
224
225 match self {
226 TypeKindMismatch | OverrideSourceHasOverride => Severity::Error,
227 }
228 }
229}
230
231#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
233pub enum CompositeSchemasPostMergeValidationErrorCode {
234 InvalidFieldSharing,
236}
237
238impl CompositeSchemasPostMergeValidationErrorCode {
239 fn severity(&self) -> Severity {
240 use CompositeSchemasPostMergeValidationErrorCode::*;
241
242 match self {
243 InvalidFieldSharing => Severity::Error,
244 }
245 }
246}