Skip to main content

knowledge_base_validation/
diagnostic.rs

1use 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}