use alloc::boxed::Box;
use alloc::collections::BTreeMap;
use alloc::string::String;
use crate::draft::Draft;
use crate::error::ValidationError;
use crate::formats::FormatChecker;
use crate::in_memory_fetcher::InMemoryFetcher;
use crate::keywords::custom::KeywordFactory;
use crate::referencing::Registry;
use crate::validator::Validator;
use serde_json::Value;
pub struct ValidationOptions {
default_draft: Draft,
resolver: InMemoryFetcher,
assert_format: bool,
custom_keywords: BTreeMap<String, Box<dyn KeywordFactory>>,
custom_formats: BTreeMap<String, Box<dyn FormatChecker>>,
pub schema: Option<Value>,
}
impl ValidationOptions {
#[must_use]
pub fn new() -> Self {
Self {
default_draft: Draft::DEFAULT,
resolver: InMemoryFetcher::builtin(),
assert_format: false,
custom_keywords: BTreeMap::new(),
custom_formats: BTreeMap::new(),
schema: None,
}
}
#[must_use]
pub fn with_schema(schema: Value) -> Self {
let mut options = Self::new();
options.schema = Some(schema);
options
}
#[must_use]
pub fn with_draft(mut self, draft: Draft) -> Self {
self.default_draft = draft;
self
}
#[must_use]
pub fn with_resolver(mut self, resolver: InMemoryFetcher) -> Self {
self.resolver = resolver;
self
}
#[must_use]
pub fn assert_format(mut self, assert: bool) -> Self {
self.assert_format = assert;
self
}
#[must_use]
pub fn with_keyword(mut self, name: &str, factory: Box<dyn KeywordFactory>) -> Self {
self.custom_keywords.insert(name.into(), factory);
self
}
#[must_use]
pub fn with_format(mut self, name: &str, checker: Box<dyn FormatChecker>) -> Self {
self.custom_formats.insert(name.into(), checker);
self
}
pub fn compile(self) -> Result<Validator, ValidationError> {
let schema = self.schema.as_ref()
.expect("schema must be set before compile() — use scheme::Builder::build() or ValidationOptions::build(schema)");
Self::_do_compile(&self, schema)
}
#[must_use]
pub fn schema(&self) -> &Value {
self.schema
.as_ref()
.expect("schema must be set — use scheme::Builder::build() first")
}
#[must_use]
pub fn into_schema(mut self) -> Value {
self.schema
.take()
.expect("schema must be set — use scheme::Builder::build() first")
}
#[must_use]
pub fn clone_schema(&self) -> Value {
self.schema
.as_ref()
.expect("schema must be set — use scheme::Builder::build() first")
.clone()
}
pub fn build(self, schema: &Value) -> Result<Validator, ValidationError> {
Self::_do_compile(&self, schema)
}
}
impl ValidationOptions {
fn _do_compile(&self, schema: &Value) -> Result<Validator, ValidationError> {
let draft = Draft::detect(schema).unwrap_or(self.default_draft);
let id_keyword = draft.id_keyword();
let base_uri = schema
.as_object()
.and_then(|o| o.get(id_keyword))
.and_then(|v| v.as_str())
.map_or("", |s| s.strip_suffix('#').unwrap_or(s));
let registry = Registry::builder()
.with_resolver(self.resolver.clone())
.with_draft(draft)
.add_resource(base_uri, schema.clone())
.build()?;
let root_node = crate::compiler::compile(
schema,
®istry,
draft,
self.assert_format,
self.custom_formats.clone(),
self.custom_keywords.clone(),
)?;
Ok(Validator::new(root_node, draft))
}
}
impl Default for ValidationOptions {
fn default() -> Self {
Self::new()
}
}