all jspg tests now passing

This commit is contained in:
2026-03-04 01:02:32 -05:00
parent e7f20e2cb6
commit 566b599512
32 changed files with 531 additions and 1068 deletions

View File

@ -1,3 +1,5 @@
use std::collections::HashSet;
use serde_json::Value;
use crate::validator::context::ValidationContext;
@ -12,42 +14,44 @@ impl<'a> ValidationContext<'a> {
let current = self.instance;
if let Some(obj) = current.as_object() {
// Entity Bound Implicit Type Validation
if let Some(allowed_types) = &self.schema.obj.compiled_variations {
if let Some(type_val) = obj.get("type") {
if let Some(type_str) = type_val.as_str() {
if allowed_types.contains(type_str) {
// Ensure it passes strict mode
result.evaluated_keys.insert("type".to_string());
} else {
result.errors.push(ValidationError {
code: "CONST_VIOLATED".to_string(), // Aligning with original const override errors
message: format!(
"Type '{}' is not a valid descendant for this entity bound schema",
type_str
),
path: format!("{}/type", self.path),
});
}
if let Some(lookup_key) = self.schema.id.as_ref().or(self.schema.ref_string.as_ref()) {
let base_type_name = lookup_key.split('.').next_back().unwrap_or("").to_string();
if let Some(type_def) = self.db.types.get(&base_type_name)
&& let Some(type_val) = obj.get("type")
&& let Some(type_str) = type_val.as_str()
{
if type_def.variations.contains(type_str) {
// Ensure it passes strict mode
result.evaluated_keys.insert("type".to_string());
} else {
result.errors.push(ValidationError {
code: "CONST_VIOLATED".to_string(), // Aligning with original const override errors
message: format!(
"Type '{}' is not a valid descendant for this entity bound schema",
type_str
),
path: format!("{}/type", self.path),
});
}
}
}
if let Some(min) = self.schema.min_properties {
if (obj.len() as f64) < min {
result.errors.push(ValidationError {
code: "MIN_PROPERTIES".to_string(),
message: "Too few properties".to_string(),
path: self.path.to_string(),
});
}
if let Some(min) = self.schema.min_properties
&& (obj.len() as f64) < min
{
result.errors.push(ValidationError {
code: "MIN_PROPERTIES".to_string(),
message: "Too few properties".to_string(),
path: self.path.to_string(),
});
}
if let Some(max) = self.schema.max_properties {
if (obj.len() as f64) > max {
result.errors.push(ValidationError {
code: "MAX_PROPERTIES".to_string(),
message: "Too many properties".to_string(),
path: self.path.to_string(),
});
}
if let Some(max) = self.schema.max_properties
&& (obj.len() as f64) > max
{
result.errors.push(ValidationError {
code: "MAX_PROPERTIES".to_string(),
message: "Too many properties".to_string(),
path: self.path.to_string(),
});
}
if let Some(ref req) = self.schema.required {
for field in req {
@ -95,29 +99,31 @@ impl<'a> ValidationContext<'a> {
if let Some(child_instance) = obj.get(key) {
let new_path = format!("{}/{}", self.path, key);
let is_ref = sub_schema.ref_string.is_some() || sub_schema.obj.compiled_ref.is_some();
let is_ref = sub_schema.ref_string.is_some();
let next_extensible = if is_ref { false } else { self.extensible };
let derived = self.derive(
sub_schema,
child_instance,
&new_path,
std::collections::HashSet::new(),
HashSet::new(),
next_extensible,
false,
);
let mut item_res = derived.validate()?;
// Entity Bound Implicit Type Interception
if key == "type" {
if let Some(allowed_types) = &self.schema.obj.compiled_variations {
if let Some(instance_type) = child_instance.as_str() {
if allowed_types.contains(instance_type) {
item_res
.errors
.retain(|e| e.code != "CONST_VIOLATED" && e.code != "ENUM_VIOLATED");
}
}
if key == "type"
&& let Some(lookup_key) = sub_schema.id.as_ref().or(sub_schema.ref_string.as_ref())
{
let base_type_name = lookup_key.split('.').next_back().unwrap_or("").to_string();
if let Some(type_def) = self.db.types.get(&base_type_name)
&& let Some(instance_type) = child_instance.as_str()
&& type_def.variations.contains(instance_type)
{
item_res
.errors
.retain(|e| e.code != "CONST_VIOLATED" && e.code != "ENUM_VIOLATED");
}
}
@ -132,14 +138,14 @@ impl<'a> ValidationContext<'a> {
for (key, child_instance) in obj {
if compiled_re.0.is_match(key) {
let new_path = format!("{}/{}", self.path, key);
let is_ref = sub_schema.ref_string.is_some() || sub_schema.obj.compiled_ref.is_some();
let is_ref = sub_schema.ref_string.is_some();
let next_extensible = if is_ref { false } else { self.extensible };
let derived = self.derive(
sub_schema,
child_instance,
&new_path,
std::collections::HashSet::new(),
HashSet::new(),
next_extensible,
false,
);
@ -154,33 +160,31 @@ impl<'a> ValidationContext<'a> {
if let Some(ref additional_schema) = self.schema.additional_properties {
for (key, child_instance) in obj {
let mut locally_matched = false;
if let Some(props) = &self.schema.properties {
if props.contains_key(&key.to_string()) {
locally_matched = true;
}
if let Some(props) = &self.schema.properties
&& props.contains_key(&key.to_string())
{
locally_matched = true;
}
if !locally_matched {
if let Some(ref compiled_pp) = self.schema.compiled_pattern_properties {
for (compiled_re, _) in compiled_pp {
if compiled_re.0.is_match(key) {
locally_matched = true;
break;
}
if !locally_matched && let Some(ref compiled_pp) = self.schema.compiled_pattern_properties
{
for (compiled_re, _) in compiled_pp {
if compiled_re.0.is_match(key) {
locally_matched = true;
break;
}
}
}
if !locally_matched {
let new_path = format!("{}/{}", self.path, key);
let is_ref = additional_schema.ref_string.is_some()
|| additional_schema.obj.compiled_ref.is_some();
let is_ref = additional_schema.ref_string.is_some();
let next_extensible = if is_ref { false } else { self.extensible };
let derived = self.derive(
additional_schema,
child_instance,
&new_path,
std::collections::HashSet::new(),
HashSet::new(),
next_extensible,
false,
);
@ -197,11 +201,11 @@ impl<'a> ValidationContext<'a> {
let val_str = Value::String(key.to_string());
let ctx = ValidationContext::new(
self.schemas,
self.db,
self.root,
property_names,
&val_str,
std::collections::HashSet::new(),
HashSet::new(),
self.extensible,
self.reporter,
);