jspg progress
This commit is contained in:
129
src/compiler.rs
129
src/compiler.rs
@ -1,7 +1,7 @@
|
||||
use crate::schema::Schema;
|
||||
use regex::Regex;
|
||||
use serde_json::Value;
|
||||
use std::collections::HashMap;
|
||||
// use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -14,14 +14,6 @@ pub enum CompiledFormat {
|
||||
Regex(Regex),
|
||||
}
|
||||
|
||||
/// A fully compiled schema with a root node and a pre-calculated index map.
|
||||
/// This allows O(1) lookup of any anchor or $id within the schema tree.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CompiledSchema {
|
||||
pub root: Arc<Schema>,
|
||||
pub index: HashMap<String, Arc<Schema>>,
|
||||
}
|
||||
|
||||
/// A wrapper for compiled regex patterns
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CompiledRegex(pub Regex);
|
||||
@ -169,10 +161,10 @@ impl Compiler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Recursively traverses the schema tree to build a map of all internal Anchors ($id) and JSON Pointers.
|
||||
/// Recursively traverses the schema tree to build the local registry index.
|
||||
fn compile_index(
|
||||
schema: &Arc<Schema>,
|
||||
index: &mut HashMap<String, Arc<Schema>>,
|
||||
registry: &mut crate::registry::Registry,
|
||||
parent_base: Option<String>,
|
||||
pointer: json_pointer::JsonPointer<String, Vec<String>>,
|
||||
) {
|
||||
@ -186,15 +178,14 @@ impl Compiler {
|
||||
} else {
|
||||
format!("{}#{}", base, fragment)
|
||||
};
|
||||
index.insert(ptr_uri, schema.clone());
|
||||
registry.insert(ptr_uri, schema.clone());
|
||||
}
|
||||
|
||||
// 2. Determine Current Scope... (unchanged logic, just use pointer)
|
||||
// 2. Determine Current Scope... (unchanged logic)
|
||||
let mut current_base = parent_base.clone();
|
||||
let mut child_pointer = pointer.clone();
|
||||
|
||||
if let Some(id) = &schema.obj.id {
|
||||
// ... resolve ID logic ...
|
||||
let mut new_base = None;
|
||||
if let Ok(_) = url::Url::parse(id) {
|
||||
new_base = Some(id.clone());
|
||||
@ -209,40 +200,29 @@ impl Compiler {
|
||||
}
|
||||
|
||||
if let Some(base) = new_base {
|
||||
index.insert(base.clone(), schema.clone());
|
||||
// println!("DEBUG: Compiling index for path: {}", base); // Added println
|
||||
registry.insert(base.clone(), schema.clone());
|
||||
current_base = Some(base);
|
||||
child_pointer = json_pointer::JsonPointer::new(vec![]); // Reset
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Index by Anchor (unchanged)
|
||||
if let Some(anchor) = &schema.obj.anchor {
|
||||
if let Some(base) = ¤t_base {
|
||||
let anchor_uri = format!("{}#{}", base, anchor);
|
||||
index.insert(anchor_uri, schema.clone());
|
||||
}
|
||||
}
|
||||
// Index by Dynamic Anchor
|
||||
if let Some(d_anchor) = &schema.obj.dynamic_anchor {
|
||||
if let Some(base) = ¤t_base {
|
||||
let anchor_uri = format!("{}#{}", base, d_anchor);
|
||||
index.insert(anchor_uri.clone(), schema.clone());
|
||||
println!("Indexed Dynamic Anchor: {}", anchor_uri);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Index by Anchor
|
||||
if let Some(anchor) = &schema.obj.anchor {
|
||||
if let Some(base) = ¤t_base {
|
||||
let anchor_uri = format!("{}#{}", base, anchor);
|
||||
index.insert(anchor_uri.clone(), schema.clone());
|
||||
println!("Indexed Anchor: {}", anchor_uri);
|
||||
registry.insert(anchor_uri, schema.clone());
|
||||
}
|
||||
}
|
||||
// Index by Dynamic Anchor
|
||||
if let Some(d_anchor) = &schema.obj.dynamic_anchor {
|
||||
if let Some(base) = ¤t_base {
|
||||
let anchor_uri = format!("{}#{}", base, d_anchor);
|
||||
registry.insert(anchor_uri, schema.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// ... (Const/Enum indexing skipped for brevity, relies on string)
|
||||
|
||||
// 4. Recurse
|
||||
// 4. Recurse (unchanged logic structure, just passing registry)
|
||||
if let Some(defs) = schema.defs.as_ref().or(schema.definitions.as_ref()) {
|
||||
let segment = if schema.defs.is_some() {
|
||||
"$defs"
|
||||
@ -252,10 +232,9 @@ impl Compiler {
|
||||
for (key, sub_schema) in defs {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push(segment.to_string());
|
||||
// Decode key to avoid double encoding by JsonPointer
|
||||
let decoded_key = percent_encoding::percent_decode_str(key).decode_utf8_lossy();
|
||||
sub.push(decoded_key.to_string());
|
||||
Self::compile_index(sub_schema, index, current_base.clone(), sub);
|
||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
||||
}
|
||||
}
|
||||
|
||||
@ -264,14 +243,14 @@ impl Compiler {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("properties".to_string());
|
||||
sub.push(key.to_string());
|
||||
Self::compile_index(sub_schema, index, current_base.clone(), sub);
|
||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(items) = &schema.items {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("items".to_string());
|
||||
Self::compile_index(items, index, current_base.clone(), sub);
|
||||
Self::compile_index(items, registry, current_base.clone(), sub);
|
||||
}
|
||||
|
||||
if let Some(prefix_items) = &schema.prefix_items {
|
||||
@ -279,7 +258,7 @@ impl Compiler {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("prefixItems".to_string());
|
||||
sub.push(i.to_string());
|
||||
Self::compile_index(sub_schema, index, current_base.clone(), sub);
|
||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,7 +267,7 @@ impl Compiler {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("allOf".to_string());
|
||||
sub.push(i.to_string());
|
||||
Self::compile_index(sub_schema, index, current_base.clone(), sub);
|
||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
||||
}
|
||||
}
|
||||
if let Some(any_of) = &schema.any_of {
|
||||
@ -296,7 +275,7 @@ impl Compiler {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("anyOf".to_string());
|
||||
sub.push(i.to_string());
|
||||
Self::compile_index(sub_schema, index, current_base.clone(), sub);
|
||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
||||
}
|
||||
}
|
||||
if let Some(one_of) = &schema.one_of {
|
||||
@ -304,36 +283,36 @@ impl Compiler {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("oneOf".to_string());
|
||||
sub.push(i.to_string());
|
||||
Self::compile_index(sub_schema, index, current_base.clone(), sub);
|
||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(not) = &schema.not {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("not".to_string());
|
||||
Self::compile_index(not, index, current_base.clone(), sub);
|
||||
Self::compile_index(not, registry, current_base.clone(), sub);
|
||||
}
|
||||
if let Some(if_) = &schema.if_ {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("if".to_string());
|
||||
Self::compile_index(if_, index, current_base.clone(), sub);
|
||||
Self::compile_index(if_, registry, current_base.clone(), sub);
|
||||
}
|
||||
if let Some(then_) = &schema.then_ {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("then".to_string());
|
||||
Self::compile_index(then_, index, current_base.clone(), sub);
|
||||
Self::compile_index(then_, registry, current_base.clone(), sub);
|
||||
}
|
||||
if let Some(else_) = &schema.else_ {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("else".to_string());
|
||||
Self::compile_index(else_, index, current_base.clone(), sub);
|
||||
Self::compile_index(else_, registry, current_base.clone(), sub);
|
||||
}
|
||||
if let Some(deps) = &schema.dependent_schemas {
|
||||
for (key, sub_schema) in deps {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("dependentSchemas".to_string());
|
||||
sub.push(key.to_string());
|
||||
Self::compile_index(sub_schema, index, current_base.clone(), sub);
|
||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
||||
}
|
||||
}
|
||||
if let Some(pp) = &schema.pattern_properties {
|
||||
@ -341,55 +320,67 @@ impl Compiler {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("patternProperties".to_string());
|
||||
sub.push(key.to_string());
|
||||
Self::compile_index(sub_schema, index, current_base.clone(), sub);
|
||||
Self::compile_index(sub_schema, registry, current_base.clone(), sub);
|
||||
}
|
||||
}
|
||||
if let Some(contains) = &schema.contains {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("contains".to_string());
|
||||
Self::compile_index(contains, index, current_base.clone(), sub);
|
||||
Self::compile_index(contains, registry, current_base.clone(), sub);
|
||||
}
|
||||
if let Some(property_names) = &schema.property_names {
|
||||
let mut sub = child_pointer.clone();
|
||||
sub.push("propertyNames".to_string());
|
||||
Self::compile_index(property_names, index, current_base.clone(), sub);
|
||||
Self::compile_index(property_names, registry, current_base.clone(), sub);
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolves a format string to a CompiledFormat (future optimization)
|
||||
pub fn compile_format(_format: &str) -> Option<CompiledFormat> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn compile(mut root_schema: Schema, root_id: Option<String>) -> CompiledSchema {
|
||||
// 1. Compile in-place (formats/regexes)
|
||||
pub fn compile(mut root_schema: Schema, root_id: Option<String>) -> Arc<Schema> {
|
||||
// 1. Compile in-place (formats/regexes/normalization)
|
||||
Self::compile_formats_and_regexes(&mut root_schema);
|
||||
|
||||
// Apply root_id override if schema ID is missing
|
||||
if let Some(ref rid) = root_id {
|
||||
if let Some(rid) = &root_id {
|
||||
if root_schema.obj.id.is_none() {
|
||||
root_schema.obj.id = Some(rid.clone());
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Wrap in Arc
|
||||
let root = Arc::new(root_schema);
|
||||
let mut index = HashMap::new();
|
||||
// 2. Build ID/Pointer Index
|
||||
let mut registry = crate::registry::Registry::new();
|
||||
|
||||
// We need a temporary Arc to satisfy compile_index recursion
|
||||
// But we are modifying root_schema.
|
||||
// This is tricky. compile_index takes &Arc<Schema>.
|
||||
// We should build the index first, THEN attach it.
|
||||
|
||||
let root = Arc::new(root_schema);
|
||||
|
||||
// Default base_uri to ""
|
||||
let base_uri = root_id
|
||||
.clone()
|
||||
.or_else(|| root.obj.id.clone())
|
||||
.or(Some("".to_string()));
|
||||
|
||||
// 3. Build ID/Pointer Index
|
||||
// Default base_uri to "" so that pointers like "#/foo" are indexed even if no root ID exists
|
||||
Self::compile_index(
|
||||
&root,
|
||||
&mut index,
|
||||
root_id.clone().or(Some("".to_string())),
|
||||
&mut registry,
|
||||
base_uri,
|
||||
json_pointer::JsonPointer::new(vec![]),
|
||||
);
|
||||
|
||||
// Also ensure root id is indexed if present
|
||||
if let Some(rid) = root_id {
|
||||
index.insert(rid, root.clone());
|
||||
registry.insert(rid, root.clone());
|
||||
}
|
||||
|
||||
CompiledSchema { root, index }
|
||||
// Now we need to attach this registry to the root schema.
|
||||
// Since root is an Arc, we might need to recreate it if we can't mutate.
|
||||
// Schema struct modifications require &mut.
|
||||
|
||||
let mut final_schema = Arc::try_unwrap(root).unwrap_or_else(|arc| (*arc).clone());
|
||||
final_schema.obj.compiled_schemas = Some(Arc::new(registry));
|
||||
|
||||
Arc::new(final_schema)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user