218 lines
6.1 KiB
Rust
218 lines
6.1 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use serde_json::Value;
|
|
use std::collections::BTreeMap;
|
|
use std::sync::Arc;
|
|
|
|
// Schema mirrors the Go Punc Generator's schema struct for consistency.
|
|
// It is an order-preserving representation of a JSON Schema.
|
|
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
|
pub struct SchemaObject {
|
|
// Core Schema Keywords
|
|
#[serde(rename = "$id")]
|
|
pub id: Option<String>,
|
|
#[serde(rename = "$ref")]
|
|
pub ref_string: Option<String>,
|
|
#[serde(rename = "$anchor")]
|
|
pub anchor: Option<String>,
|
|
#[serde(rename = "$dynamicAnchor")]
|
|
pub dynamic_anchor: Option<String>,
|
|
#[serde(rename = "$dynamicRef")]
|
|
pub dynamic_ref: Option<String>,
|
|
/*
|
|
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),
|
|
so we omit the direct recursive `Ref` field for now and rely on `ref_string`.
|
|
*/
|
|
pub description: Option<String>,
|
|
pub title: Option<String>,
|
|
#[serde(default)] // Allow missing type
|
|
#[serde(rename = "type")]
|
|
pub type_: Option<SchemaTypeOrArray>, // Handles string or array of strings
|
|
|
|
// Object Keywords
|
|
pub properties: Option<BTreeMap<String, Arc<Schema>>>,
|
|
#[serde(rename = "patternProperties")]
|
|
pub pattern_properties: Option<BTreeMap<String, Arc<Schema>>>,
|
|
pub required: Option<Vec<String>>,
|
|
|
|
// dependencies can be schema dependencies or property dependencies
|
|
pub dependencies: Option<BTreeMap<String, Dependency>>,
|
|
|
|
// Definitions (for $ref resolution)
|
|
#[serde(rename = "$defs")]
|
|
pub defs: Option<BTreeMap<String, Arc<Schema>>>,
|
|
#[serde(rename = "definitions")]
|
|
pub definitions: Option<BTreeMap<String, Arc<Schema>>>,
|
|
|
|
// Array Keywords
|
|
#[serde(rename = "items")]
|
|
pub items: Option<Arc<Schema>>,
|
|
#[serde(rename = "prefixItems")]
|
|
pub prefix_items: Option<Vec<Arc<Schema>>>,
|
|
|
|
// String Validation
|
|
#[serde(rename = "minLength")]
|
|
pub min_length: Option<f64>,
|
|
#[serde(rename = "maxLength")]
|
|
pub max_length: Option<f64>,
|
|
pub pattern: Option<String>,
|
|
|
|
// Array Validation
|
|
#[serde(rename = "minItems")]
|
|
pub min_items: Option<f64>,
|
|
#[serde(rename = "maxItems")]
|
|
pub max_items: Option<f64>,
|
|
#[serde(rename = "uniqueItems")]
|
|
pub unique_items: Option<bool>,
|
|
#[serde(rename = "contains")]
|
|
pub contains: Option<Arc<Schema>>,
|
|
#[serde(rename = "minContains")]
|
|
pub min_contains: Option<f64>,
|
|
#[serde(rename = "maxContains")]
|
|
pub max_contains: Option<f64>,
|
|
|
|
// Object Validation
|
|
#[serde(rename = "minProperties")]
|
|
pub min_properties: Option<f64>,
|
|
#[serde(rename = "maxProperties")]
|
|
pub max_properties: Option<f64>,
|
|
#[serde(rename = "propertyNames")]
|
|
pub property_names: Option<Arc<Schema>>,
|
|
#[serde(rename = "dependentRequired")]
|
|
pub dependent_required: Option<BTreeMap<String, Vec<String>>>,
|
|
#[serde(rename = "dependentSchemas")]
|
|
pub dependent_schemas: Option<BTreeMap<String, Arc<Schema>>>,
|
|
|
|
// Numeric Validation
|
|
pub format: Option<String>,
|
|
#[serde(rename = "enum")]
|
|
pub enum_: Option<Vec<Value>>, // `enum` is a reserved keyword in Rust
|
|
#[serde(
|
|
default,
|
|
rename = "const",
|
|
deserialize_with = "crate::util::deserialize_some"
|
|
)]
|
|
pub const_: Option<Value>,
|
|
|
|
// Numeric Validation
|
|
#[serde(rename = "multipleOf")]
|
|
pub multiple_of: Option<f64>,
|
|
pub minimum: Option<f64>,
|
|
pub maximum: Option<f64>,
|
|
#[serde(rename = "exclusiveMinimum")]
|
|
pub exclusive_minimum: Option<f64>,
|
|
#[serde(rename = "exclusiveMaximum")]
|
|
pub exclusive_maximum: Option<f64>,
|
|
|
|
// Combining Keywords
|
|
#[serde(rename = "allOf")]
|
|
pub all_of: Option<Vec<Arc<Schema>>>,
|
|
#[serde(rename = "anyOf")]
|
|
pub any_of: Option<Vec<Arc<Schema>>>,
|
|
#[serde(rename = "oneOf")]
|
|
pub one_of: Option<Vec<Arc<Schema>>>,
|
|
#[serde(rename = "not")]
|
|
pub not: Option<Arc<Schema>>,
|
|
#[serde(rename = "if")]
|
|
pub if_: Option<Arc<Schema>>,
|
|
#[serde(rename = "then")]
|
|
pub then_: Option<Arc<Schema>>,
|
|
#[serde(rename = "else")]
|
|
pub else_: Option<Arc<Schema>>,
|
|
|
|
// Custom Vocabularies
|
|
pub form: Option<Vec<String>>,
|
|
pub display: Option<Vec<String>>,
|
|
#[serde(rename = "enumNames")]
|
|
pub enum_names: Option<Vec<String>>,
|
|
pub control: Option<String>,
|
|
pub actions: Option<BTreeMap<String, Action>>,
|
|
pub computer: Option<String>,
|
|
#[serde(default)]
|
|
pub extensible: Option<bool>,
|
|
|
|
// Compiled Fields (Hidden from JSON/Serde)
|
|
#[serde(skip)]
|
|
pub compiled_format: Option<crate::compiler::CompiledFormat>,
|
|
#[serde(skip)]
|
|
pub compiled_pattern: Option<crate::compiler::CompiledRegex>,
|
|
#[serde(skip)]
|
|
pub compiled_pattern_properties: Option<Vec<(crate::compiler::CompiledRegex, Arc<Schema>)>>,
|
|
#[serde(skip)]
|
|
pub compiled_registry: Option<Arc<crate::registry::Registry>>,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize)]
|
|
pub struct Schema {
|
|
#[serde(flatten)]
|
|
pub obj: SchemaObject,
|
|
#[serde(skip)]
|
|
pub always_fail: bool,
|
|
}
|
|
|
|
impl Default for Schema {
|
|
fn default() -> Self {
|
|
Schema {
|
|
obj: SchemaObject::default(),
|
|
always_fail: false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::ops::Deref for Schema {
|
|
type Target = SchemaObject;
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.obj
|
|
}
|
|
}
|
|
impl std::ops::DerefMut for Schema {
|
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
&mut self.obj
|
|
}
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for Schema {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
let v: Value = Deserialize::deserialize(deserializer)?;
|
|
|
|
if let Some(b) = v.as_bool() {
|
|
let mut obj = SchemaObject::default();
|
|
if b {
|
|
obj.extensible = Some(true);
|
|
}
|
|
return Ok(Schema {
|
|
obj,
|
|
always_fail: !b,
|
|
});
|
|
}
|
|
let obj: SchemaObject = serde_json::from_value(v.clone()).map_err(serde::de::Error::custom)?;
|
|
|
|
Ok(Schema {
|
|
obj,
|
|
always_fail: false,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(untagged)]
|
|
pub enum SchemaTypeOrArray {
|
|
Single(String),
|
|
Multiple(Vec<String>),
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct Action {
|
|
pub navigate: Option<String>,
|
|
pub punc: Option<String>,
|
|
}
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(untagged)]
|
|
pub enum Dependency {
|
|
Props(Vec<String>),
|
|
Schema(Arc<Schema>),
|
|
}
|