knowledge_base_validation/
diagnostic.rs1use std::fmt;
2use std::path::Path;
3use std::path::PathBuf;
4
5use crate::input::Loaded;
6
7#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
8pub enum ValidationLayer {
9 Schema,
10 Ontology,
11 Domain,
12 Provenance,
13}
14
15impl fmt::Display for ValidationLayer {
16 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
17 let name = match self {
18 Self::Schema => "schema",
19 Self::Ontology => "ontology",
20 Self::Domain => "domain",
21 Self::Provenance => "provenance",
22 };
23 formatter.write_str(name)
24 }
25}
26
27#[derive(Clone, Debug, Eq, PartialEq)]
28pub struct Diagnostic {
29 pub layer: ValidationLayer,
30 pub path: PathBuf,
31 pub line: Option<usize>,
32 pub identifier: Option<String>,
33 pub message: String,
34}
35
36impl fmt::Display for Diagnostic {
37 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
38 write!(formatter, "{}", self.path.display())?;
39 if let Some(line) = self.line {
40 write!(formatter, ":{line}")?;
41 }
42 write!(formatter, " [{}]", self.layer)?;
43 if let Some(identifier) = &self.identifier {
44 write!(formatter, " [{identifier}]")?;
45 }
46 write!(formatter, " {}", self.message)
47 }
48}
49
50#[derive(Default)]
51pub(crate) struct Diagnostics(Vec<Diagnostic>);
52
53impl Diagnostics {
54 pub(crate) fn push(&mut self, layer: ValidationLayer, path: PathBuf, line: Option<usize>, identifier: Option<String>, message: impl Into<String>) {
55 self.0.push(Diagnostic {
56 layer,
57 path,
58 line,
59 identifier,
60 message: message.into(),
61 });
62 }
63
64 pub(crate) fn schema<T>(&mut self, item: &Loaded<T>, identifier: &str, message: impl Into<String>) {
65 self.push(ValidationLayer::Schema, item.path.clone(), None, Some(identifier.to_owned()), message);
66 }
67
68 pub(crate) fn ontology<T>(&mut self, item: &Loaded<T>, identifier: &str, message: impl Into<String>) {
69 self.push(ValidationLayer::Ontology, item.path.clone(), None, Some(identifier.to_owned()), message);
70 }
71
72 pub(crate) fn provenance(&mut self, path: &Path, line: Option<usize>, identifier: &str, message: impl Into<String>) {
73 self.push(ValidationLayer::Provenance, path.to_path_buf(), line, Some(identifier.to_owned()), message);
74 }
75
76 pub(crate) fn finish(mut self) -> Vec<Diagnostic> {
77 sort_diagnostics(&mut self.0);
78 self.0
79 }
80}
81
82pub(crate) fn sort_diagnostics(diagnostics: &mut [Diagnostic]) {
83 diagnostics.sort_by(|left, right| {
84 (&left.path, left.line.unwrap_or(usize::MAX), &left.identifier, &left.message, left.layer).cmp(&(
85 &right.path,
86 right.line.unwrap_or(usize::MAX),
87 &right.identifier,
88 &right.message,
89 right.layer,
90 ))
91 });
92}