diff --git a/GEMINI.md b/GEMINI.md index a964871..f33022c 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -71,7 +71,7 @@ JSPG implements specific extensions to the Draft 2020-12 standard to support the ### 1. Polymorphism & Referencing (`$ref`, `$family`, and Native Types) -JSPG replaces the complex, dynamic reference resolution logic of standard JSON Schema (e.g., `$defs`, relative URIs, `$dynamicRef`, `$dynamicAnchor`, `if/then/else`) with a strict, explicitly structured global `$id` system. This powers predictable code generation and blazing-fast runtime validation. +JSPG replaces the complex, dynamic reference resolution logic of standard JSON Schema (e.g., `$defs`, relative URIs, `$dynamicRef`, `$dynamicAnchor`, `anyOf`) with a strict, explicitly structured global `$id` system. This powers predictable code generation and blazing-fast runtime validation. #### A. Global `$id` Conventions & Schema Buckets Every schema is part of a flat, globally addressable namespace. However, where a schema is defined in the database determines its physical boundaries: diff --git a/agreego.sql b/agreego.sql new file mode 100644 index 0000000..e69de29 diff --git a/src/database/mod.rs b/src/database/mod.rs index de1e008..fa48320 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -121,7 +121,7 @@ impl Database { if !visited.insert(current_id.clone()) { break; // Cycle detected } - if let Some(ref_str) = &schema.obj.ref_string { + if let Some(ref_str) = &schema.obj.r#ref { current_id = ref_str.clone(); depth += 1; } else { @@ -136,7 +136,7 @@ impl Database { fn collect_descendants(&mut self) { let mut direct_refs: HashMap> = HashMap::new(); for (id, schema) in &self.schemas { - if let Some(ref_str) = &schema.obj.ref_string { + if let Some(ref_str) = &schema.obj.r#ref { direct_refs .entry(ref_str.clone()) .or_default() diff --git a/src/database/schema.rs b/src/database/schema.rs index 38c93c0..2878f91 100644 --- a/src/database/schema.rs +++ b/src/database/schema.rs @@ -11,7 +11,7 @@ pub struct SchemaObject { #[serde(rename = "$id")] pub id: Option, #[serde(rename = "$ref")] - pub ref_string: Option, + pub r#ref: Option, /* Note: The `Ref` field in the Go struct is a pointer populated by the linker. In Rust, we might handle this differently (e.g., separate lookup or Rc/Arc), @@ -306,7 +306,7 @@ impl<'de> Deserialize<'de> for Schema { && obj.if_.is_none() && obj.then_.is_none() && obj.else_.is_none() - && obj.ref_string.is_none() + && obj.r#ref.is_none() && obj.family.is_none(); if is_empty && obj.extensible.is_none() { diff --git a/src/validator/rules/object.rs b/src/validator/rules/object.rs index 32058b1..4975fe4 100644 --- a/src/validator/rules/object.rs +++ b/src/validator/rules/object.rs @@ -14,7 +14,7 @@ impl<'a> ValidationContext<'a> { let current = self.instance; if let Some(obj) = current.as_object() { // Entity Bound Implicit Type Validation - if let Some(lookup_key) = self.schema.id.as_ref().or(self.schema.ref_string.as_ref()) { + if let Some(lookup_key) = self.schema.id.as_ref().or(self.schema.r#ref.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") @@ -99,7 +99,7 @@ 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(); + let is_ref = sub_schema.r#ref.is_some(); let next_extensible = if is_ref { false } else { self.extensible }; let derived = self.derive( @@ -114,7 +114,7 @@ impl<'a> ValidationContext<'a> { // Entity Bound Implicit Type Interception if key == "type" - && let Some(lookup_key) = sub_schema.id.as_ref().or(sub_schema.ref_string.as_ref()) + && let Some(lookup_key) = sub_schema.id.as_ref().or(sub_schema.r#ref.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) @@ -138,7 +138,7 @@ 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(); + let is_ref = sub_schema.r#ref.is_some(); let next_extensible = if is_ref { false } else { self.extensible }; let derived = self.derive( @@ -177,7 +177,7 @@ impl<'a> ValidationContext<'a> { if !locally_matched { let new_path = format!("{}/{}", self.path, key); - let is_ref = additional_schema.ref_string.is_some(); + let is_ref = additional_schema.r#ref.is_some(); let next_extensible = if is_ref { false } else { self.extensible }; let derived = self.derive( diff --git a/src/validator/rules/polymorphism.rs b/src/validator/rules/polymorphism.rs index 6ce7bfd..1121081 100644 --- a/src/validator/rules/polymorphism.rs +++ b/src/validator/rules/polymorphism.rs @@ -13,7 +13,7 @@ impl<'a> ValidationContext<'a> { || self.schema.required.is_some() || self.schema.additional_properties.is_some() || self.schema.items.is_some() - || self.schema.ref_string.is_some() + || self.schema.r#ref.is_some() || self.schema.one_of.is_some() || self.schema.all_of.is_some() || self.schema.enum_.is_some() @@ -122,7 +122,7 @@ impl<'a> ValidationContext<'a> { result: &mut ValidationResult, ) -> Result { // 1. Core $ref logic relies on the fast O(1) map to allow cycles and proper nesting - if let Some(ref_str) = &self.schema.ref_string { + if let Some(ref_str) = &self.schema.r#ref { if let Some(global_schema) = self.db.schemas.get(ref_str) { let mut new_overrides = self.overrides.clone(); if let Some(props) = &self.schema.properties {