mod compiler;
mod dialect;
mod document;
mod eval;
mod formats;
mod instance;
mod loader;
#[rustfmt::skip]
mod metaschemas;
mod node;
mod numbers;
mod options;
mod pattern;
mod results;
mod uri;
use std::sync::Arc;
use serde_json::Value;
pub use dialect::Dialect;
pub use document::{JsonDocument, JsonDocumentArray, JsonDocumentObject, JsonDocumentValue, JsonParseError};
pub use instance::{ArrayView, Instance, Kind, ObjectView, View};
pub use options::{
CompileOptions, DocumentResolver, FormatValidator, SchemaCompilationError, SchemaEvaluationDepthError,
};
pub use results::{
Annotation, JsonSchemaResultsCollector, ResultsLevel, SchemaResult, collect_annotations, encode_pointer_segment,
enumerate_annotations, schema_location_fragment,
};
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum JsonValidationError {
InvalidJson(JsonParseError),
DepthExceeded(SchemaEvaluationDepthError),
}
impl std::fmt::Display for JsonValidationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
JsonValidationError::InvalidJson(e) => write!(f, "invalid JSON: {e}"),
JsonValidationError::DepthExceeded(e) => e.fmt(f),
}
}
}
impl std::error::Error for JsonValidationError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
JsonValidationError::InvalidJson(e) => Some(e),
JsonValidationError::DepthExceeded(e) => Some(e),
}
}
}
#[derive(Clone)]
pub struct Validator {
program: Arc<eval::Program>,
}
impl std::fmt::Debug for Validator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Validator").field("nodes", &self.program.nodes.len()).finish()
}
}
pub fn compile(schema: &Value) -> Result<Validator, SchemaCompilationError> {
compile_with(schema, &CompileOptions::default())
}
pub fn compile_with(schema: &Value, options: &CompileOptions) -> Result<Validator, SchemaCompilationError> {
let compiled = compiler::SchemaCompiler::compile(schema.clone(), options)?;
Ok(Validator::from_compiled(compiled, options))
}
pub fn compile_from_uri(uri: &str, options: &CompileOptions) -> Result<Validator, SchemaCompilationError> {
let compiled = compiler::SchemaCompiler::compile_from_uri(uri, options)?;
Ok(Validator::from_compiled(compiled, options))
}
impl Validator {
fn from_compiled(c: compiler::CompiledSchema, options: &CompileOptions) -> Validator {
let program = eval::Program::new(
c.nodes,
c.root,
c.uses_dynamic_scope,
options.max_depth,
options.formats.clone(),
c.documents,
c.annotation_sources,
options.assert_format.is_some(),
);
Validator { program: Arc::new(program) }
}
#[inline]
pub fn is_valid(&self, instance: &Value) -> bool {
eval::Evaluator::new(&self.program, None).validate(instance)
}
pub fn validate(&self, instance: &Value) -> Result<bool, SchemaEvaluationDepthError> {
let mut e = eval::Evaluator::new(&self.program, None);
let ok = e.validate(instance);
if e.depth_exceeded { Err(SchemaEvaluationDepthError) } else { Ok(ok) }
}
pub fn evaluate(
&self,
instance: &Value,
collector: &mut JsonSchemaResultsCollector,
) -> Result<bool, SchemaEvaluationDepthError> {
self.evaluate_instance(instance, collector)
}
pub fn validate_instance<'a, I: Instance<'a>>(&self, instance: I) -> Result<bool, SchemaEvaluationDepthError> {
let mut e = eval::Evaluator::new(&self.program, None);
let ok = e.validate(instance);
if e.depth_exceeded { Err(SchemaEvaluationDepthError) } else { Ok(ok) }
}
pub fn validate_json(&self, json: &str) -> Result<bool, JsonValidationError> {
JsonDocument::with_document(json, |d| self.validate_instance(d.root()))
.map_err(JsonValidationError::InvalidJson)?
.map_err(JsonValidationError::DepthExceeded)
}
pub fn evaluate_json(
&self,
json: &str,
collector: &mut JsonSchemaResultsCollector,
) -> Result<bool, JsonValidationError> {
JsonDocument::with_document(json, |d| self.evaluate_instance(d.root(), collector))
.map_err(JsonValidationError::InvalidJson)?
.map_err(JsonValidationError::DepthExceeded)
}
pub fn evaluate_instance<'a, I: Instance<'a>>(
&self,
instance: I,
collector: &mut JsonSchemaResultsCollector,
) -> Result<bool, SchemaEvaluationDepthError> {
let mut e = eval::Evaluator::new(&self.program, Some(collector));
let ok = e.evaluate(instance);
if e.depth_exceeded { Err(SchemaEvaluationDepthError) } else { Ok(ok) }
}
}