use serde::{Deserialize, Serialize};
use crate::ToolError;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SchemaStrictness {
Strict,
BestEffort,
Unspecified,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct JsonSchema {
pub schema: serde_json::Value,
pub strictness: SchemaStrictness,
}
impl JsonSchema {
#[must_use]
pub fn strict(schema: serde_json::Value) -> Self {
Self {
schema,
strictness: SchemaStrictness::Strict,
}
}
#[must_use]
pub fn best_effort(schema: serde_json::Value) -> Self {
Self {
schema,
strictness: SchemaStrictness::BestEffort,
}
}
#[must_use]
pub fn unspecified(schema: serde_json::Value) -> Self {
Self {
schema,
strictness: SchemaStrictness::Unspecified,
}
}
pub(crate) fn validate(
&self,
value: &serde_json::Value,
) -> Result<Vec<ValidationIssue>, ToolError> {
Self::validate_raw(&self.schema, value)
}
pub(crate) fn validate_raw(
schema: &serde_json::Value,
value: &serde_json::Value,
) -> Result<Vec<ValidationIssue>, ToolError> {
let validator = jsonschema::validator_for(schema).map_err(|error| ToolError::Protocol {
message: format!("invalid JSON Schema: {error}"),
})?;
Ok(validator
.iter_errors(value)
.map(|error| ValidationIssue {
path: error.instance_path().to_string(),
message: error.to_string(),
})
.collect())
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ValidationIssue {
pub path: String,
pub message: String,
}