mod compiler;
mod dialect;
mod document;
mod ecmaregex;
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, DEFAULT_PATTERN_MATCH_LIMIT, DocumentResolver, FormatValidator, PatternMatchLimitError,
PatternTooLargeError, SchemaCompilationError, SchemaCompilationErrorKind, SchemaEvaluationDepthError,
SchemaEvaluationError,
};
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),
}
}
}
fn without_the_limit(e: SchemaEvaluationError) -> SchemaEvaluationDepthError {
match e {
SchemaEvaluationError::DepthExceeded(e) => e,
_ => SchemaEvaluationDepthError,
}
}
fn json_error(e: SchemaEvaluationError) -> JsonValidationError {
match e {
SchemaEvaluationError::InvalidJson(e) => JsonValidationError::InvalidJson(e),
other => JsonValidationError::DepthExceeded(without_the_limit(other)),
}
}
#[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)?;
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)?;
Validator::from_compiled(compiled, options)
}
impl Validator {
fn from_compiled(
c: compiler::CompiledSchema,
options: &CompileOptions,
) -> Result<Validator, SchemaCompilationError> {
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(),
pattern::PatternLimit::new(options.pattern_match_limit),
);
let failure = program.compile_budget.lock().unwrap_or_else(|e| e.into_inner()).take_failure();
if let Some(e) = failure {
return Err(SchemaCompilationError::of_kind(
e.to_string(),
SchemaCompilationErrorKind::PatternMatchLimit(e),
));
}
Ok(Validator { program: Arc::new(program) })
}
#[inline]
pub fn is_valid(&self, instance: &Value) -> bool {
eval::Evaluator::new(&self.program, None).validate(instance)
}
pub fn try_validate(&self, instance: &Value) -> Result<bool, SchemaEvaluationError> {
self.try_validate_instance(instance)
}
pub fn try_validate_instance<'a, I: Instance<'a>>(&self, instance: I) -> Result<bool, SchemaEvaluationError> {
let mut e = eval::Evaluator::new(&self.program, None);
let ok = e.validate(instance);
e.outcome(ok)
}
pub fn try_validate_json(&self, json: &str) -> Result<bool, SchemaEvaluationError> {
JsonDocument::with_document(json, |d| self.try_validate_instance(d.root()))
.map_err(SchemaEvaluationError::InvalidJson)?
}
pub fn try_evaluate(
&self,
instance: &Value,
collector: &mut JsonSchemaResultsCollector,
) -> Result<bool, SchemaEvaluationError> {
self.try_evaluate_instance(instance, collector)
}
pub fn try_evaluate_instance<'a, I: Instance<'a>>(
&self,
instance: I,
collector: &mut JsonSchemaResultsCollector,
) -> Result<bool, SchemaEvaluationError> {
let mut e = eval::Evaluator::new(&self.program, Some(collector));
let ok = e.evaluate(instance);
e.outcome(ok)
}
pub fn try_evaluate_json(
&self,
json: &str,
collector: &mut JsonSchemaResultsCollector,
) -> Result<bool, SchemaEvaluationError> {
JsonDocument::with_document(json, |d| self.try_evaluate_instance(d.root(), collector))
.map_err(SchemaEvaluationError::InvalidJson)?
}
pub fn validate(&self, instance: &Value) -> Result<bool, SchemaEvaluationDepthError> {
self.try_validate(instance).map_err(without_the_limit)
}
pub fn evaluate(
&self,
instance: &Value,
collector: &mut JsonSchemaResultsCollector,
) -> Result<bool, SchemaEvaluationDepthError> {
self.try_evaluate(instance, collector).map_err(without_the_limit)
}
pub fn validate_instance<'a, I: Instance<'a>>(&self, instance: I) -> Result<bool, SchemaEvaluationDepthError> {
self.try_validate_instance(instance).map_err(without_the_limit)
}
pub fn validate_json(&self, json: &str) -> Result<bool, JsonValidationError> {
self.try_validate_json(json).map_err(json_error)
}
pub fn evaluate_json(
&self,
json: &str,
collector: &mut JsonSchemaResultsCollector,
) -> Result<bool, JsonValidationError> {
self.try_evaluate_json(json, collector).map_err(json_error)
}
pub fn evaluate_instance<'a, I: Instance<'a>>(
&self,
instance: I,
collector: &mut JsonSchemaResultsCollector,
) -> Result<bool, SchemaEvaluationDepthError> {
self.try_evaluate_instance(instance, collector).map_err(without_the_limit)
}
}