knowledge_base_validation/
additional_validator.rs1use crate::{Diagnostic, ValidationLayer, diagnostic, validator};
2use knowledge_base_snapshot::RepositorySnapshot;
3use std::path::{Path, PathBuf};
4
5#[derive(Clone, Copy, Debug)]
10pub struct ValidationContext<'a> {
11 repository_root: &'a Path,
12 snapshot: &'a RepositorySnapshot,
13}
14
15impl<'a> ValidationContext<'a> {
16 fn new(repository_root: &'a Path, snapshot: &'a RepositorySnapshot) -> Self {
17 Self { repository_root, snapshot }
18 }
19
20 pub fn repository_root(&self) -> &'a Path {
22 self.repository_root
23 }
24
25 pub fn snapshot(&self) -> &'a RepositorySnapshot {
27 self.snapshot
28 }
29}
30
31pub trait KnowledgeBaseValidator: Send + Sync {
36 fn validate(&self, context: &ValidationContext<'_>) -> Vec<Diagnostic>;
37}
38
39impl<F> KnowledgeBaseValidator for F
40where
41 F: for<'a> Fn(&ValidationContext<'a>) -> Vec<Diagnostic> + Send + Sync,
42{
43 fn validate(&self, context: &ValidationContext<'_>) -> Vec<Diagnostic> {
44 self(context)
45 }
46}
47
48pub fn validate_repository_with<'a>(root: impl AsRef<Path>, validators: impl IntoIterator<Item = &'a dyn KnowledgeBaseValidator>) -> Vec<Diagnostic> {
53 let root = root.as_ref();
54 let mut diagnostics = validator::validate_repository(root);
55 let validators = validators.into_iter().collect::<Vec<_>>();
56 if !validators.is_empty() {
57 match RepositorySnapshot::load(root) {
58 Ok(snapshot) => {
59 let context = ValidationContext::new(root, &snapshot);
60 for validator in validators {
61 diagnostics.extend(validator.validate(&context));
62 }
63 }
64 Err(error) if diagnostics.is_empty() => {
65 let path = error.path().strip_prefix(root).map(PathBuf::from).unwrap_or_else(|_| error.path().to_path_buf());
66 diagnostics.push(Diagnostic {
67 layer: ValidationLayer::Schema,
68 path,
69 line: None,
70 identifier: None,
71 message: format!("cannot load shared repository snapshot: {error}"),
72 });
73 }
74 Err(_) => {}
75 }
76 }
77 diagnostic::sort_diagnostics(&mut diagnostics);
78 diagnostics
79}