93 lines
2.8 KiB
Rust
93 lines
2.8 KiB
Rust
use crate::validator::context::ValidationContext;
|
|
use crate::validator::error::ValidationError;
|
|
use crate::validator::result::ValidationResult;
|
|
|
|
impl<'a> ValidationContext<'a> {
|
|
pub(crate) fn validate_combinators(
|
|
&self,
|
|
result: &mut ValidationResult,
|
|
) -> Result<bool, ValidationError> {
|
|
if let Some(ref all_of) = self.schema.all_of {
|
|
for sub in all_of {
|
|
let derived = self.derive_for_schema(sub, true);
|
|
let res = derived.validate()?;
|
|
result.merge(res);
|
|
}
|
|
}
|
|
|
|
if let Some(ref one_of) = self.schema.one_of {
|
|
let mut passed_candidates: Vec<(Option<String>, usize, ValidationResult)> = Vec::new();
|
|
|
|
for sub in one_of {
|
|
let derived = self.derive_for_schema(sub, true);
|
|
let sub_res = derived.validate()?;
|
|
if sub_res.is_valid() {
|
|
let child_id = sub.id.clone();
|
|
let depth = child_id
|
|
.as_ref()
|
|
.and_then(|id| self.db.depths.get(id).copied())
|
|
.unwrap_or(0);
|
|
passed_candidates.push((child_id, depth, sub_res));
|
|
}
|
|
}
|
|
|
|
if passed_candidates.len() == 1 {
|
|
result.merge(passed_candidates.pop().unwrap().2);
|
|
} else if passed_candidates.is_empty() {
|
|
result.errors.push(ValidationError {
|
|
code: "NO_ONEOF_MATCH".to_string(),
|
|
message: "Matches none of oneOf schemas".to_string(),
|
|
path: self.path.to_string(),
|
|
});
|
|
} else {
|
|
// Apply depth heuristic tie-breaker
|
|
let mut best_depth: Option<usize> = None;
|
|
let mut ambiguous = false;
|
|
let mut best_res = None;
|
|
|
|
for (_, depth, res) in passed_candidates.into_iter() {
|
|
if let Some(current_best) = best_depth {
|
|
if depth > current_best {
|
|
best_depth = Some(depth);
|
|
best_res = Some(res);
|
|
ambiguous = false;
|
|
} else if depth == current_best {
|
|
ambiguous = true;
|
|
}
|
|
} else {
|
|
best_depth = Some(depth);
|
|
best_res = Some(res);
|
|
}
|
|
}
|
|
|
|
if !ambiguous {
|
|
if let Some(res) = best_res {
|
|
result.merge(res);
|
|
return Ok(true);
|
|
}
|
|
}
|
|
|
|
result.errors.push(ValidationError {
|
|
code: "AMBIGUOUS_ONEOF_MATCH".to_string(),
|
|
message: "Matches multiple oneOf schemas without a clear depth winner".to_string(),
|
|
path: self.path.to_string(),
|
|
});
|
|
}
|
|
}
|
|
|
|
if let Some(ref not_schema) = self.schema.not {
|
|
let derived = self.derive_for_schema(not_schema, true);
|
|
let sub_res = derived.validate()?;
|
|
if sub_res.is_valid() {
|
|
result.errors.push(ValidationError {
|
|
code: "NOT_VIOLATED".to_string(),
|
|
message: "Matched 'not' schema".to_string(),
|
|
path: self.path.to_string(),
|
|
});
|
|
}
|
|
}
|
|
|
|
Ok(true)
|
|
}
|
|
}
|