commit
fbcfc5072d
20
README.md
20
README.md
|
@ -2,6 +2,8 @@
|
|||
|
||||
Yet another JSON Schema validator implementation. It compiles schema into a validation tree to have validation as fast as possible.
|
||||
|
||||
To validate documents against some schema and get validation errors (if any):
|
||||
|
||||
```rust
|
||||
use jsonschema::{JSONSchema, Draft};
|
||||
use serde_json::json;
|
||||
|
@ -11,7 +13,25 @@ fn main() {
|
|||
let instance = json!("foo");
|
||||
let compiled = JSONSchema::compile(&schema, Some(Draft::Draft7));
|
||||
let result = compiled.validate(&instance);
|
||||
if let Err(errors) = result {
|
||||
for error in errors {
|
||||
println!("Validation error: {}", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you only need to know whether document is valid or not:
|
||||
|
||||
```rust
|
||||
use jsonschema::is_valid;
|
||||
use serde_json::json;
|
||||
|
||||
fn main() {
|
||||
let schema = json!({"maxLength": 5});
|
||||
let instance = json!("foo");
|
||||
assert!(is_valid(&schema, &instance));
|
||||
}
|
||||
```
|
||||
|
||||
**NOTE**. This library is in early development.
|
|
@ -85,20 +85,6 @@ fn fastjsonschema_invalid_benchmark(c: &mut Criterion) {
|
|||
});
|
||||
}
|
||||
|
||||
fn format_time_benchmark(c: &mut Criterion) {
|
||||
let schema = black_box(json!({"type": "string", "format": "time"}));
|
||||
let validator = JSONSchema::compile(&schema, None).unwrap();
|
||||
let data = black_box(json!("10:00:00Z"));
|
||||
c.bench_function("format time", |b| b.iter(|| validator.validate(&data)));
|
||||
}
|
||||
|
||||
fn max_length_benchmark(c: &mut Criterion) {
|
||||
let schema = json!({"maxLength": 5});
|
||||
let validator = JSONSchema::compile(&schema, None).unwrap();
|
||||
let data = black_box(json!("abc"));
|
||||
c.bench_function("max length", |b| b.iter(|| validator.validate(&data)));
|
||||
}
|
||||
|
||||
bench_validate!(
|
||||
additional_items_valid,
|
||||
"additional items valid",
|
||||
|
@ -287,12 +273,12 @@ bench_compile!(c_aproperties6, "compile additional properties 6", {"properties":
|
|||
|
||||
criterion_group!(
|
||||
benches,
|
||||
// canada_benchmark,
|
||||
canada_benchmark,
|
||||
// canada_benchmark_alternative,
|
||||
// canada_compile_benchmark,
|
||||
// fastjsonschema_compile,
|
||||
// fastjsonschema_valid_benchmark,
|
||||
// fastjsonschema_invalid_benchmark,
|
||||
canada_compile_benchmark,
|
||||
fastjsonschema_compile,
|
||||
fastjsonschema_valid_benchmark,
|
||||
fastjsonschema_invalid_benchmark,
|
||||
// type_string_valid,
|
||||
// type_string_invalid,
|
||||
// false_schema,
|
||||
|
@ -349,10 +335,10 @@ criterion_group!(
|
|||
// additional_properties_invalid6,
|
||||
// type_integer_valid1,
|
||||
// type_integer_invalid1,
|
||||
type_integer_valid2,
|
||||
type_integer_invalid2,
|
||||
type_multiple_valid3,
|
||||
type_multiple_invalid3,
|
||||
// type_integer_valid2,
|
||||
// type_integer_invalid2,
|
||||
// type_multiple_valid3,
|
||||
// type_multiple_invalid3,
|
||||
// unique_items_valid,
|
||||
// unique_items_invalid,
|
||||
// multiple_of_integer_valid,
|
||||
|
@ -370,9 +356,9 @@ criterion_group!(
|
|||
// format_time_benchmark,
|
||||
// max_length_benchmark,
|
||||
// ref_valid,
|
||||
// c_required,
|
||||
// properties_valid,
|
||||
// properties_invalid,
|
||||
// c_required,
|
||||
// c_properties,
|
||||
// c_dependencies,
|
||||
// c_enum,
|
||||
|
|
|
@ -89,36 +89,20 @@ fn make_fn_body(schema: &Value, data: &Value, description: &str, valid: bool) ->
|
|||
if valid {
|
||||
output.push_str(
|
||||
r#"
|
||||
match result.err() {
|
||||
Some(err) => {
|
||||
let message = format!(
|
||||
"Schema: {}\nInstance: {}\nError: {}",
|
||||
schema, data, err
|
||||
);
|
||||
assert!(false, message)
|
||||
}
|
||||
None => {}
|
||||
let err = result.err();
|
||||
let errors = err.iter().collect::<Vec<_>>();
|
||||
if !errors.is_empty() {
|
||||
let message = format!(
|
||||
"Schema: {}\nInstance: {}\nError: {:?}",
|
||||
schema, data, 1
|
||||
);
|
||||
assert!(false, message)
|
||||
}
|
||||
"#,
|
||||
)
|
||||
} else {
|
||||
output.push_str(
|
||||
r#"assert!(result.is_err(), "It should be INVALID!");
|
||||
"#,
|
||||
)
|
||||
output.push_str(r#"assert!(result.is_err(), "It should be INVALID!");"#)
|
||||
}
|
||||
output.push_str("}");
|
||||
output
|
||||
}
|
||||
// id: "json-schema://86de4a79-34d7-45d4-8821-a9a99dc2d7a6",
|
||||
// children: [
|
||||
// <additional properties: {
|
||||
// id: "json-schema://355c236a-4057-47e8-8325-4d1c6050b861",
|
||||
// children: [<false>],
|
||||
// }
|
||||
// <properties: {
|
||||
// "foo": {
|
||||
// id: "json-schema://0dff1dfb-a85e-4b26-9abe-a8e1adbf7c8e",
|
||||
// children: [<ref: #>]
|
||||
// }
|
||||
// ]
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::error::ValidationError;
|
||||
use crate::keywords::ValidationResult;
|
||||
use crate::error::{error, no_error, ErrorIterator, ValidationError};
|
||||
use chrono::{DateTime, NaiveDate};
|
||||
use regex::Regex;
|
||||
use std::net::IpAddr;
|
||||
|
@ -24,28 +23,28 @@ lazy_static! {
|
|||
.unwrap();
|
||||
}
|
||||
|
||||
pub(crate) fn date(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn date(instance: &str) -> ErrorIterator {
|
||||
if NaiveDate::parse_from_str(instance, "%Y-%m-%d").is_err() {
|
||||
return Err(ValidationError::format(instance.to_owned(), "date"));
|
||||
return error(ValidationError::format(instance.to_owned(), "date"));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn datetime(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn datetime(instance: &str) -> ErrorIterator {
|
||||
if DateTime::parse_from_rfc3339(instance).is_err() {
|
||||
return Err(ValidationError::format(instance.to_owned(), "date-time"));
|
||||
return error(ValidationError::format(instance.to_owned(), "date-time"));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn email(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn email(instance: &str) -> ErrorIterator {
|
||||
if !instance.contains('@') {
|
||||
return Err(ValidationError::format(instance.to_owned(), "email"));
|
||||
return error(ValidationError::format(instance.to_owned(), "email"));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn hostname(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn hostname(instance: &str) -> ErrorIterator {
|
||||
if instance.ends_with('-')
|
||||
|| instance.starts_with('-')
|
||||
|| instance.is_empty()
|
||||
|
@ -55,12 +54,12 @@ pub(crate) fn hostname(instance: &str) -> ValidationResult {
|
|||
.any(|c| !(c.is_alphanumeric() || c == '-' || c == '.'))
|
||||
|| instance.split('.').any(|part| part.chars().count() > 63)
|
||||
{
|
||||
return Err(ValidationError::format(instance.to_owned(), "hostname"));
|
||||
return error(ValidationError::format(instance.to_owned(), "hostname"));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn ipv4(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn ipv4(instance: &str) -> ErrorIterator {
|
||||
if !match IpAddr::from_str(instance) {
|
||||
Ok(i) => match i {
|
||||
IpAddr::V4(_) => true,
|
||||
|
@ -68,12 +67,12 @@ pub(crate) fn ipv4(instance: &str) -> ValidationResult {
|
|||
},
|
||||
Err(_) => false,
|
||||
} {
|
||||
return Err(ValidationError::format(instance.to_owned(), "ipv4"));
|
||||
return error(ValidationError::format(instance.to_owned(), "ipv4"));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn ipv6(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn ipv6(instance: &str) -> ErrorIterator {
|
||||
if !match IpAddr::from_str(instance) {
|
||||
Ok(i) => match i {
|
||||
IpAddr::V4(_) => false,
|
||||
|
@ -81,72 +80,72 @@ pub(crate) fn ipv6(instance: &str) -> ValidationResult {
|
|||
},
|
||||
Err(_) => false,
|
||||
} {
|
||||
return Err(ValidationError::format(instance.to_owned(), "ipv6"));
|
||||
return error(ValidationError::format(instance.to_owned(), "ipv6"));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn iri(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn iri(instance: &str) -> ErrorIterator {
|
||||
if Url::from_str(instance).is_err() {
|
||||
return Err(ValidationError::format(instance.to_owned(), "iri"));
|
||||
return error(ValidationError::format(instance.to_owned(), "iri"));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn iri_reference(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn iri_reference(instance: &str) -> ErrorIterator {
|
||||
if !IRI_REFERENCE_RE.is_match(instance) {
|
||||
return Err(ValidationError::format(
|
||||
return error(ValidationError::format(
|
||||
instance.to_owned(),
|
||||
"iri-reference",
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn json_pointer(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn json_pointer(instance: &str) -> ErrorIterator {
|
||||
if !JSON_POINTER_RE.is_match(instance) {
|
||||
return Err(ValidationError::format(instance.to_owned(), "json-pointer"));
|
||||
return error(ValidationError::format(instance.to_owned(), "json-pointer"));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn regex(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn regex(instance: &str) -> ErrorIterator {
|
||||
if Regex::new(instance).is_err() {
|
||||
return Err(ValidationError::format(instance.to_owned(), "regex"));
|
||||
return error(ValidationError::format(instance.to_owned(), "regex"));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn relative_json_pointer(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn relative_json_pointer(instance: &str) -> ErrorIterator {
|
||||
if !RELATIVE_JSON_POINTER_RE.is_match(instance) {
|
||||
return Err(ValidationError::format(
|
||||
return error(ValidationError::format(
|
||||
instance.to_owned(),
|
||||
"relative-json-pointer",
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn time(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn time(instance: &str) -> ErrorIterator {
|
||||
if !TIME_RE.is_match(instance) {
|
||||
return Err(ValidationError::format(instance.to_owned(), "time"));
|
||||
return error(ValidationError::format(instance.to_owned(), "time"));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn uri_reference(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn uri_reference(instance: &str) -> ErrorIterator {
|
||||
if !URI_REFERENCE_RE.is_match(instance) {
|
||||
return Err(ValidationError::format(
|
||||
return error(ValidationError::format(
|
||||
instance.to_owned(),
|
||||
"uri-reference",
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn uri_template(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn uri_template(instance: &str) -> ErrorIterator {
|
||||
if !URI_TEMPLATE_RE.is_match(instance) {
|
||||
return Err(ValidationError::format(instance.to_owned(), "uri-template"));
|
||||
return error(ValidationError::format(instance.to_owned(), "uri-template"));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
|
171
src/error.rs
171
src/error.rs
|
@ -1,5 +1,6 @@
|
|||
use serde_json::Value;
|
||||
use std::fmt::{Error, Formatter};
|
||||
use std::iter::{empty, once};
|
||||
use std::string::FromUtf8Error;
|
||||
use std::{error, fmt, io};
|
||||
|
||||
|
@ -25,6 +26,17 @@ pub struct ValidationError {
|
|||
kind: ValidationErrorKind,
|
||||
}
|
||||
|
||||
pub type ErrorIterator<'a> = Box<dyn Iterator<Item = ValidationError> + 'a>;
|
||||
|
||||
// Empty iterator means no error happened
|
||||
pub(crate) fn no_error<'a>() -> ErrorIterator<'a> {
|
||||
Box::new(empty())
|
||||
}
|
||||
// A wrapper for one error
|
||||
pub(crate) fn error<'a>(instance: ValidationError) -> ErrorIterator<'a> {
|
||||
Box::new(once(instance))
|
||||
}
|
||||
|
||||
/// Kinds of errors that may happen during validation
|
||||
#[derive(Debug)]
|
||||
pub enum ValidationErrorKind {
|
||||
|
@ -129,46 +141,46 @@ pub enum TypeKind {
|
|||
}
|
||||
|
||||
/// Shortcuts for creation of specific error kinds.
|
||||
impl ValidationError {
|
||||
pub(crate) fn additional_items(items: Vec<Value>, limit: usize) -> ValidationError {
|
||||
ValidationError {
|
||||
impl<'a> ValidationError {
|
||||
pub(crate) fn additional_items(items: Vec<Value>, limit: usize) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::AdditionalItems { items, limit },
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn any_of(instance: Value) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn any_of(instance: Value) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::AnyOf(instance),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn constant(message: String) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn constant(message: String) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::Constant(message),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn contains(instance: Value) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn contains(instance: Value) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::Contains(instance),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn enumeration(instance: Value, options: Value) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn enumeration(instance: Value, options: Value) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::Enum { instance, options },
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn exclusive_maximum(instance: f64, limit: f64) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn exclusive_maximum(instance: f64, limit: f64) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::ExclusiveMaximum { instance, limit },
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn exclusive_minimum(instance: f64, limit: f64) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn exclusive_minimum(instance: f64, limit: f64) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::ExclusiveMinimum { instance, limit },
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn false_schema(instance: Value) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn false_schema(instance: Value) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::FalseSchema(instance),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn file_not_found(err: io::Error) -> ValidationError {
|
||||
ValidationError {
|
||||
|
@ -195,107 +207,110 @@ impl ValidationError {
|
|||
kind: ValidationErrorKind::InvalidReference(reference),
|
||||
}
|
||||
}
|
||||
pub(crate) fn max_items(instance: Value) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn max_items(instance: Value) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::MaxItems(instance),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn maximum(instance: f64, limit: f64) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn maximum(instance: f64, limit: f64) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::Maximum { instance, limit },
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn max_length(instance: String) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn max_length(instance: String) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::MaxLength(instance),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn max_properties(instance: Value) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn max_properties(instance: Value) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::MaxProperties(instance),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn min_items(instance: Value) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn min_items(instance: Value) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::MinItems(instance),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn minimum(instance: f64, limit: f64) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn minimum(instance: f64, limit: f64) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::Minimum { instance, limit },
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn min_length(instance: String) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn min_length(instance: String) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::MinLength(instance),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn min_properties(instance: Value) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn min_properties(instance: Value) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::MinProperties(instance),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn multiple_of(instance: f64, multiple_of: f64) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn multiple_of(instance: f64, multiple_of: f64) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::MultipleOf {
|
||||
instance,
|
||||
multiple_of,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn not(instance: Value, schema: Value) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn not(instance: Value, schema: Value) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::Not { instance, schema },
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn one_of_multiple_valid(instance: Value) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn one_of_multiple_valid(instance: Value) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::OneOfMultipleValid(instance),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn one_of_not_valid(instance: Value) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn one_of_not_valid(instance: Value) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::OneOfNotValid(instance),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn pattern(instance: String, pattern: String) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn pattern(instance: String, pattern: String) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::Pattern { instance, pattern },
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn required(property: String) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn required(property: String) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::Required(property),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn schema() -> ValidationError {
|
||||
ValidationError {
|
||||
kind: ValidationErrorKind::Schema,
|
||||
}
|
||||
}
|
||||
pub(crate) fn single_type_error(instance: Value, type_name: PrimitiveType) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn single_type_error(
|
||||
instance: Value,
|
||||
type_name: PrimitiveType,
|
||||
) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::Type {
|
||||
instance,
|
||||
kind: TypeKind::Single(type_name),
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn multiple_type_error(
|
||||
instance: Value,
|
||||
types: Vec<PrimitiveType>,
|
||||
) -> ValidationError {
|
||||
ValidationError {
|
||||
) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::Type {
|
||||
instance,
|
||||
kind: TypeKind::Multiple(types),
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn unique_items(instance: Value) -> ValidationError {
|
||||
ValidationError {
|
||||
pub(crate) fn unique_items(instance: Value) -> ErrorIterator<'a> {
|
||||
error(ValidationError {
|
||||
kind: ValidationErrorKind::UniqueItems(instance),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub(crate) fn unknown_reference_scheme(scheme: String) -> ValidationError {
|
||||
ValidationError {
|
||||
|
@ -468,7 +483,9 @@ mod tests {
|
|||
#[test]
|
||||
fn type_error() {
|
||||
let instance = json!(42);
|
||||
let err = ValidationError::single_type_error(instance, PrimitiveType::String);
|
||||
let err = ValidationError::single_type_error(instance, PrimitiveType::String)
|
||||
.next()
|
||||
.unwrap();
|
||||
let repr = format!("{}", err);
|
||||
assert_eq!(repr, "'42' is not of type 'string'")
|
||||
}
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
use super::{CompilationResult, ValidationResult};
|
||||
use super::CompilationResult;
|
||||
use super::{Validate, Validators};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::keywords::boolean::TrueValidator;
|
||||
use crate::validator::compile_validators;
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct AdditionalItemsObjectValidator<'a> {
|
||||
validators: Validators<'a>,
|
||||
pub struct AdditionalItemsObjectValidator {
|
||||
validators: Validators,
|
||||
items_count: usize,
|
||||
}
|
||||
pub struct AdditionalItemsBooleanValidator {
|
||||
items_count: usize,
|
||||
}
|
||||
|
||||
impl<'a> AdditionalItemsObjectValidator<'a> {
|
||||
impl AdditionalItemsObjectValidator {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
schema: &Value,
|
||||
items_count: usize,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
) -> CompilationResult {
|
||||
let validators = compile_validators(schema, context)?;
|
||||
Ok(Box::new(AdditionalItemsObjectValidator {
|
||||
validators,
|
||||
|
@ -30,21 +30,26 @@ impl<'a> AdditionalItemsObjectValidator<'a> {
|
|||
}
|
||||
|
||||
impl<'a> AdditionalItemsBooleanValidator {
|
||||
pub(crate) fn compile(items_count: usize) -> CompilationResult<'a> {
|
||||
pub(crate) fn compile(items_count: usize) -> CompilationResult {
|
||||
Ok(Box::new(AdditionalItemsBooleanValidator { items_count }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for AdditionalItemsObjectValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for AdditionalItemsObjectValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Array(items) = instance {
|
||||
for item in items.iter().skip(self.items_count) {
|
||||
for validator in self.validators.iter() {
|
||||
validator.validate(schema, item)?
|
||||
}
|
||||
}
|
||||
let errors: Vec<_> = items
|
||||
.iter()
|
||||
.skip(self.items_count)
|
||||
.flat_map(|item| {
|
||||
self.validators
|
||||
.iter()
|
||||
.flat_map(move |validator| validator.validate(schema, item))
|
||||
})
|
||||
.collect();
|
||||
return Box::new(errors.into_iter());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!(
|
||||
|
@ -54,28 +59,25 @@ impl<'a> Validate<'a> for AdditionalItemsObjectValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for AdditionalItemsBooleanValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for AdditionalItemsBooleanValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Array(items) = instance {
|
||||
if items.len() > self.items_count {
|
||||
return Err(ValidationError::additional_items(
|
||||
items.clone(),
|
||||
self.items_count,
|
||||
));
|
||||
return ValidationError::additional_items(items.clone(), self.items_count);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<additional items: {}>", self.items_count)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
parent: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
parent: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
if let Some(items) = parent.get("items") {
|
||||
match items {
|
||||
Value::Object(_) => Some(TrueValidator::compile()),
|
||||
|
|
|
@ -1,37 +1,38 @@
|
|||
use super::{CompilationResult, ValidationResult};
|
||||
use super::CompilationResult;
|
||||
use super::{Validate, Validators};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::CompilationError;
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator};
|
||||
use crate::validator::compile_validators;
|
||||
use crate::{JSONSchema, ValidationError};
|
||||
use regex::Regex;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct AdditionalPropertiesValidator<'a> {
|
||||
validators: Validators<'a>,
|
||||
pub struct AdditionalPropertiesValidator {
|
||||
validators: Validators,
|
||||
}
|
||||
|
||||
impl<'a> AdditionalPropertiesValidator<'a> {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
impl AdditionalPropertiesValidator {
|
||||
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
|
||||
Ok(Box::new(AdditionalPropertiesValidator {
|
||||
validators: compile_validators(schema, context)?,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for AdditionalPropertiesValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for AdditionalPropertiesValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance {
|
||||
for value in item.values() {
|
||||
for validator in self.validators.iter() {
|
||||
validator.validate(schema, value)?
|
||||
}
|
||||
}
|
||||
let errors: Vec<_> = self
|
||||
.validators
|
||||
.iter()
|
||||
.flat_map(move |validator| {
|
||||
item.values()
|
||||
.flat_map(move |value| validator.validate(schema, value))
|
||||
})
|
||||
.collect();
|
||||
return Box::new(errors.into_iter());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<additional properties: {:?}>", self.validators)
|
||||
|
@ -40,73 +41,71 @@ impl<'a> Validate<'a> for AdditionalPropertiesValidator<'a> {
|
|||
pub struct AdditionalPropertiesFalseValidator {}
|
||||
|
||||
impl<'a> AdditionalPropertiesFalseValidator {
|
||||
pub(crate) fn compile() -> CompilationResult<'a> {
|
||||
pub(crate) fn compile() -> CompilationResult {
|
||||
Ok(Box::new(AdditionalPropertiesFalseValidator {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for AdditionalPropertiesFalseValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for AdditionalPropertiesFalseValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance {
|
||||
if let Some((_, value)) = item.iter().next() {
|
||||
return Err(ValidationError::false_schema(value.clone()));
|
||||
return ValidationError::false_schema(value.clone());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
"<additional properties: false>".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AdditionalPropertiesNotEmptyFalseValidator<'a> {
|
||||
properties: &'a Map<String, Value>,
|
||||
pub struct AdditionalPropertiesNotEmptyFalseValidator {
|
||||
properties: Map<String, Value>,
|
||||
}
|
||||
|
||||
impl<'a> AdditionalPropertiesNotEmptyFalseValidator<'a> {
|
||||
pub(crate) fn compile(properties: &'a Value) -> CompilationResult<'a> {
|
||||
impl AdditionalPropertiesNotEmptyFalseValidator {
|
||||
pub(crate) fn compile(properties: &Value) -> CompilationResult {
|
||||
if let Value::Object(properties) = properties {
|
||||
return Ok(Box::new(AdditionalPropertiesNotEmptyFalseValidator {
|
||||
properties,
|
||||
properties: properties.clone(),
|
||||
}));
|
||||
}
|
||||
Err(CompilationError::SchemaError)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for AdditionalPropertiesNotEmptyFalseValidator<'a> {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for AdditionalPropertiesNotEmptyFalseValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance {
|
||||
for property in item.keys() {
|
||||
if !self.properties.contains_key(property) {
|
||||
// No extra properties are allowed
|
||||
return Err(ValidationError::false_schema(Value::String(
|
||||
property.to_string(),
|
||||
)));
|
||||
return ValidationError::false_schema(Value::String(property.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
"<additional properties: false>".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AdditionalPropertiesNotEmptyValidator<'a> {
|
||||
validators: Validators<'a>,
|
||||
properties: &'a Map<String, Value>,
|
||||
pub struct AdditionalPropertiesNotEmptyValidator {
|
||||
validators: Validators,
|
||||
properties: Map<String, Value>,
|
||||
}
|
||||
|
||||
impl<'a> AdditionalPropertiesNotEmptyValidator<'a> {
|
||||
impl AdditionalPropertiesNotEmptyValidator {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
properties: &'a Value,
|
||||
schema: &Value,
|
||||
properties: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
) -> CompilationResult {
|
||||
if let Value::Object(properties) = properties {
|
||||
return Ok(Box::new(AdditionalPropertiesNotEmptyValidator {
|
||||
properties,
|
||||
properties: properties.clone(),
|
||||
validators: compile_validators(schema, context)?,
|
||||
}));
|
||||
}
|
||||
|
@ -114,35 +113,38 @@ impl<'a> AdditionalPropertiesNotEmptyValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for AdditionalPropertiesNotEmptyValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
if let Value::Object(item) = instance {
|
||||
for (property, value) in item {
|
||||
if !self.properties.contains_key(property) {
|
||||
for validator in self.validators.iter() {
|
||||
validator.validate(schema, value)?
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Validate for AdditionalPropertiesNotEmptyValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(ref item) = instance {
|
||||
let errors: Vec<_> = self
|
||||
.validators
|
||||
.iter()
|
||||
.flat_map(move |validator| {
|
||||
item.iter()
|
||||
.filter(move |(property, _)| !self.properties.contains_key(*property))
|
||||
.flat_map(move |(_, value)| validator.validate(schema, value))
|
||||
})
|
||||
.collect();
|
||||
return Box::new(errors.into_iter());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<additional properties: {:?}>", self.validators)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AdditionalPropertiesWithPatternsValidator<'a> {
|
||||
validators: Validators<'a>,
|
||||
pub struct AdditionalPropertiesWithPatternsValidator {
|
||||
validators: Validators,
|
||||
pattern: Regex,
|
||||
}
|
||||
|
||||
impl<'a> AdditionalPropertiesWithPatternsValidator<'a> {
|
||||
impl AdditionalPropertiesWithPatternsValidator {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
schema: &Value,
|
||||
pattern: Regex,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
) -> CompilationResult {
|
||||
Ok(Box::new(AdditionalPropertiesWithPatternsValidator {
|
||||
validators: compile_validators(schema, context)?,
|
||||
pattern,
|
||||
|
@ -150,18 +152,21 @@ impl<'a> AdditionalPropertiesWithPatternsValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for AdditionalPropertiesWithPatternsValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for AdditionalPropertiesWithPatternsValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance {
|
||||
for (property, value) in item {
|
||||
if !self.pattern.is_match(property) {
|
||||
for validator in self.validators.iter() {
|
||||
validator.validate(schema, value)?
|
||||
}
|
||||
}
|
||||
}
|
||||
let errors: Vec<_> = self
|
||||
.validators
|
||||
.iter()
|
||||
.flat_map(move |validator| {
|
||||
item.iter()
|
||||
.filter(move |(property, _)| !self.pattern.is_match(property))
|
||||
.flat_map(move |(_, value)| validator.validate(schema, value))
|
||||
})
|
||||
.collect();
|
||||
return Box::new(errors.into_iter());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<additional properties: {:?}>", self.validators)
|
||||
|
@ -173,49 +178,47 @@ pub struct AdditionalPropertiesWithPatternsFalseValidator {
|
|||
}
|
||||
|
||||
impl<'a> AdditionalPropertiesWithPatternsFalseValidator {
|
||||
pub(crate) fn compile(pattern: Regex) -> CompilationResult<'a> {
|
||||
pub(crate) fn compile(pattern: Regex) -> CompilationResult {
|
||||
Ok(Box::new(AdditionalPropertiesWithPatternsFalseValidator {
|
||||
pattern,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for AdditionalPropertiesWithPatternsFalseValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for AdditionalPropertiesWithPatternsFalseValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance {
|
||||
for (property, _) in item {
|
||||
if !self.pattern.is_match(property) {
|
||||
return Err(ValidationError::false_schema(Value::String(
|
||||
property.to_string(),
|
||||
)));
|
||||
return ValidationError::false_schema(Value::String(property.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
"<additional properties: false>".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AdditionalPropertiesWithPatternsNotEmptyValidator<'a> {
|
||||
validators: Validators<'a>,
|
||||
properties: &'a Map<String, Value>,
|
||||
pub struct AdditionalPropertiesWithPatternsNotEmptyValidator {
|
||||
validators: Validators,
|
||||
properties: Map<String, Value>,
|
||||
pattern: Regex,
|
||||
}
|
||||
|
||||
impl<'a> AdditionalPropertiesWithPatternsNotEmptyValidator<'a> {
|
||||
impl AdditionalPropertiesWithPatternsNotEmptyValidator {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
properties: &'a Value,
|
||||
schema: &Value,
|
||||
properties: &Value,
|
||||
pattern: Regex,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
) -> CompilationResult {
|
||||
if let Value::Object(properties) = properties {
|
||||
return Ok(Box::new(
|
||||
AdditionalPropertiesWithPatternsNotEmptyValidator {
|
||||
validators: compile_validators(schema, context)?,
|
||||
properties,
|
||||
properties: properties.clone(),
|
||||
pattern,
|
||||
},
|
||||
));
|
||||
|
@ -224,35 +227,41 @@ impl<'a> AdditionalPropertiesWithPatternsNotEmptyValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for AdditionalPropertiesWithPatternsNotEmptyValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for AdditionalPropertiesWithPatternsNotEmptyValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance {
|
||||
for (property, value) in item {
|
||||
if !self.properties.contains_key(property) && !self.pattern.is_match(property) {
|
||||
for validator in self.validators.iter() {
|
||||
validator.validate(schema, value)?
|
||||
}
|
||||
}
|
||||
}
|
||||
let errors: Vec<_> = self
|
||||
.validators
|
||||
.iter()
|
||||
.flat_map(move |validator| {
|
||||
item.iter()
|
||||
.filter(move |(property, _)| {
|
||||
!self.properties.contains_key(*property)
|
||||
&& !self.pattern.is_match(property)
|
||||
})
|
||||
.flat_map(move |(_, value)| validator.validate(schema, value))
|
||||
})
|
||||
.collect();
|
||||
return Box::new(errors.into_iter());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<additional properties: {:?}>", self.validators)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AdditionalPropertiesWithPatternsNotEmptyFalseValidator<'a> {
|
||||
properties: &'a Map<String, Value>,
|
||||
pub struct AdditionalPropertiesWithPatternsNotEmptyFalseValidator {
|
||||
properties: Map<String, Value>,
|
||||
pattern: Regex,
|
||||
}
|
||||
|
||||
impl<'a> AdditionalPropertiesWithPatternsNotEmptyFalseValidator<'a> {
|
||||
pub(crate) fn compile(properties: &'a Value, pattern: Regex) -> CompilationResult<'a> {
|
||||
impl AdditionalPropertiesWithPatternsNotEmptyFalseValidator {
|
||||
pub(crate) fn compile(properties: &Value, pattern: Regex) -> CompilationResult {
|
||||
if let Value::Object(properties) = properties {
|
||||
return Ok(Box::new(
|
||||
AdditionalPropertiesWithPatternsNotEmptyFalseValidator {
|
||||
properties,
|
||||
properties: properties.clone(),
|
||||
pattern,
|
||||
},
|
||||
));
|
||||
|
@ -261,29 +270,27 @@ impl<'a> AdditionalPropertiesWithPatternsNotEmptyFalseValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for AdditionalPropertiesWithPatternsNotEmptyFalseValidator<'a> {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for AdditionalPropertiesWithPatternsNotEmptyFalseValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance {
|
||||
for property in item.keys() {
|
||||
if !self.properties.contains_key(property) && !self.pattern.is_match(property) {
|
||||
return Err(ValidationError::false_schema(Value::String(
|
||||
property.to_string(),
|
||||
)));
|
||||
return ValidationError::false_schema(Value::String(property.to_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
"<additional properties: false>".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
parent: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
parent: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
let properties = parent.get("properties");
|
||||
if let Some(patterns) = parent.get("patternProperties") {
|
||||
if let Value::Object(obj) = patterns {
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
use super::{CompilationResult, ValidationResult};
|
||||
use super::CompilationResult;
|
||||
use super::{Validate, Validators};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::CompilationError;
|
||||
use crate::error::{CompilationError, ErrorIterator};
|
||||
use crate::validator::compile_validators;
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct AllOfValidator<'a> {
|
||||
schemas: Vec<Validators<'a>>,
|
||||
pub struct AllOfValidator {
|
||||
schemas: Vec<Validators>,
|
||||
}
|
||||
|
||||
impl<'a> AllOfValidator<'a> {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
impl AllOfValidator {
|
||||
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
|
||||
match schema.as_array() {
|
||||
Some(items) => {
|
||||
let mut schemas = Vec::with_capacity(items.len());
|
||||
|
@ -29,23 +26,27 @@ impl<'a> AllOfValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for AllOfValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
for validators in self.schemas.iter() {
|
||||
for validator in validators {
|
||||
validator.validate(schema, instance)?
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
impl Validate for AllOfValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
let errors: Vec<_> = self
|
||||
.schemas
|
||||
.iter()
|
||||
.flat_map(move |validators| {
|
||||
validators
|
||||
.iter()
|
||||
.flat_map(move |validator| validator.validate(schema, instance))
|
||||
})
|
||||
.collect();
|
||||
Box::new(errors.into_iter())
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<all of: {:?}>", self.schemas)
|
||||
}
|
||||
}
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(AllOfValidator::compile(schema, context))
|
||||
}
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
use super::{CompilationResult, ValidationResult};
|
||||
use super::CompilationResult;
|
||||
use super::{Validate, Validators};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::validator::compile_validators;
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct AnyOfValidator<'a> {
|
||||
schemas: Vec<Validators<'a>>,
|
||||
pub struct AnyOfValidator {
|
||||
schemas: Vec<Validators>,
|
||||
}
|
||||
|
||||
impl<'a> AnyOfValidator<'a> {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
impl AnyOfValidator {
|
||||
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
|
||||
match schema.as_array() {
|
||||
Some(items) => {
|
||||
let mut schemas = Vec::with_capacity(items.len());
|
||||
|
@ -29,27 +26,27 @@ impl<'a> AnyOfValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for AnyOfValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for AnyOfValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
for validators in self.schemas.iter() {
|
||||
if validators
|
||||
.iter()
|
||||
.all(|validator| validator.is_valid(schema, instance))
|
||||
{
|
||||
return Ok(());
|
||||
return no_error();
|
||||
}
|
||||
}
|
||||
Err(ValidationError::any_of(instance.clone()))
|
||||
ValidationError::any_of(instance.clone())
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<any of: {:?}>", self.schemas)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(AnyOfValidator::compile(schema, context))
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::error::ValidationError;
|
||||
use crate::error::{no_error, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::Value;
|
||||
|
||||
pub struct TrueValidator {}
|
||||
|
||||
impl TrueValidator {
|
||||
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
|
||||
pub(crate) fn compile() -> CompilationResult {
|
||||
Ok(Box::new(TrueValidator {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for TrueValidator {
|
||||
fn validate(&self, _: &JSONSchema, _: &Value) -> ValidationResult {
|
||||
Ok(())
|
||||
impl Validate for TrueValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, _: &'a Value) -> ErrorIterator<'a> {
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
"<true>".to_string()
|
||||
|
@ -24,21 +24,21 @@ impl<'a> Validate<'a> for TrueValidator {
|
|||
pub struct FalseValidator {}
|
||||
|
||||
impl FalseValidator {
|
||||
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
|
||||
pub(crate) fn compile() -> CompilationResult {
|
||||
Ok(Box::new(FalseValidator {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for FalseValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
Err(ValidationError::false_schema(instance.clone()))
|
||||
impl Validate for FalseValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
ValidationError::false_schema(instance.clone())
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
"<false>".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(value: bool) -> Option<CompilationResult<'a>> {
|
||||
pub(crate) fn compile(value: bool) -> Option<CompilationResult> {
|
||||
if value {
|
||||
Some(TrueValidator::compile())
|
||||
} else {
|
||||
|
|
|
@ -1,39 +1,39 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::ValidationError;
|
||||
use crate::error::{no_error, ErrorIterator, ValidationError};
|
||||
use crate::{helpers, JSONSchema};
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct ConstValidator<'a> {
|
||||
pub struct ConstValidator {
|
||||
error_message: String,
|
||||
value: &'a Value,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
impl<'a> ConstValidator<'a> {
|
||||
pub(crate) fn compile(value: &'a Value) -> CompilationResult<'a> {
|
||||
impl ConstValidator {
|
||||
pub(crate) fn compile(value: &Value) -> CompilationResult {
|
||||
Ok(Box::new(ConstValidator {
|
||||
error_message: format!("'{}' was expected", value),
|
||||
value,
|
||||
value: value.clone(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for ConstValidator<'a> {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for ConstValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if !helpers::equal(instance, &self.value) {
|
||||
return Err(ValidationError::constant(self.error_message.clone()));
|
||||
return ValidationError::constant(self.error_message.clone());
|
||||
};
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<const: {}>", self.value)
|
||||
}
|
||||
}
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(ConstValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -1,51 +1,48 @@
|
|||
use super::{CompilationResult, ValidationResult};
|
||||
use super::CompilationResult;
|
||||
use super::{Validate, Validators};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::ValidationError;
|
||||
use crate::error::{no_error, ErrorIterator, ValidationError};
|
||||
use crate::validator::compile_validators;
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct ContainsValidator<'a> {
|
||||
validators: Validators<'a>,
|
||||
pub struct ContainsValidator {
|
||||
validators: Validators,
|
||||
}
|
||||
|
||||
impl<'a> ContainsValidator<'a> {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
impl ContainsValidator {
|
||||
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
|
||||
Ok(Box::new(ContainsValidator {
|
||||
validators: compile_validators(schema, context)?,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for ContainsValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for ContainsValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Array(items) = instance {
|
||||
for item in items {
|
||||
if self
|
||||
.validators
|
||||
.iter()
|
||||
.all(|validator| validator.validate(schema, item).is_ok())
|
||||
.all(|validator| validator.is_valid(schema, item))
|
||||
{
|
||||
return Ok(());
|
||||
return no_error();
|
||||
}
|
||||
}
|
||||
return Err(ValidationError::contains(instance.clone()));
|
||||
return ValidationError::contains(instance.clone());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<contains: {:?}>", self.validators)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(ContainsValidator::compile(schema, context))
|
||||
}
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use super::{CompilationResult, ErrorIterator};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{error, no_error, CompilationError, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{from_str, Map, Value};
|
||||
|
||||
pub struct ContentMediaTypeValidator {
|
||||
func: fn(&str) -> ValidationResult,
|
||||
func: fn(&str) -> ErrorIterator,
|
||||
}
|
||||
|
||||
impl<'a> ContentMediaTypeValidator {
|
||||
pub(crate) fn compile(func: fn(&str) -> ValidationResult) -> CompilationResult<'a> {
|
||||
impl ContentMediaTypeValidator {
|
||||
pub(crate) fn compile(func: fn(&str) -> ErrorIterator) -> CompilationResult {
|
||||
Ok(Box::new(ContentMediaTypeValidator { func }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for ContentMediaTypeValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for ContentMediaTypeValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::String(item) = instance {
|
||||
return (self.func)(item);
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
// TODO. store media type
|
||||
|
@ -29,21 +29,21 @@ impl<'a> Validate<'a> for ContentMediaTypeValidator {
|
|||
}
|
||||
|
||||
pub struct ContentEncodingValidator {
|
||||
func: fn(&str) -> ValidationResult,
|
||||
func: fn(&str) -> ErrorIterator,
|
||||
}
|
||||
|
||||
impl<'a> ContentEncodingValidator {
|
||||
pub(crate) fn compile(func: fn(&str) -> ValidationResult) -> CompilationResult<'a> {
|
||||
impl ContentEncodingValidator {
|
||||
pub(crate) fn compile(func: fn(&str) -> ErrorIterator) -> CompilationResult {
|
||||
Ok(Box::new(ContentEncodingValidator { func }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for ContentEncodingValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for ContentEncodingValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::String(item) = instance {
|
||||
return (self.func)(item);
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
// TODO. store encoding
|
||||
|
@ -52,15 +52,15 @@ impl<'a> Validate<'a> for ContentEncodingValidator {
|
|||
}
|
||||
|
||||
pub struct ContentMediaTypeAndEncodingValidator {
|
||||
func: fn(&str) -> ValidationResult,
|
||||
func: fn(&str) -> ErrorIterator,
|
||||
converter: fn(&str) -> Result<String, ValidationError>,
|
||||
}
|
||||
|
||||
impl<'a> ContentMediaTypeAndEncodingValidator {
|
||||
pub(crate) fn compile(
|
||||
func: fn(&str) -> ValidationResult,
|
||||
func: fn(&str) -> ErrorIterator,
|
||||
converter: fn(&str) -> Result<String, ValidationError>,
|
||||
) -> CompilationResult<'a> {
|
||||
) -> CompilationResult {
|
||||
Ok(Box::new(ContentMediaTypeAndEncodingValidator {
|
||||
func,
|
||||
converter,
|
||||
|
@ -68,13 +68,18 @@ impl<'a> ContentMediaTypeAndEncodingValidator {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for ContentMediaTypeAndEncodingValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for ContentMediaTypeAndEncodingValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::String(item) = instance {
|
||||
let converted = (self.converter)(item)?;
|
||||
return (self.func)(&converted);
|
||||
return match (self.converter)(item) {
|
||||
Ok(converted) => {
|
||||
let errors: Vec<_> = (self.func)(&converted).collect();
|
||||
Box::new(errors.into_iter())
|
||||
}
|
||||
Err(e) => error(e),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
// TODO. store encoding
|
||||
|
@ -82,21 +87,21 @@ impl<'a> Validate<'a> for ContentMediaTypeAndEncodingValidator {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_json(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn is_json(instance: &str) -> ErrorIterator {
|
||||
if from_str::<Value>(instance).is_err() {
|
||||
return Err(ValidationError::format(
|
||||
return error(ValidationError::format(
|
||||
instance.to_owned(),
|
||||
"application/json",
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn is_base64(instance: &str) -> ValidationResult {
|
||||
pub(crate) fn is_base64(instance: &str) -> ErrorIterator {
|
||||
if base64::decode(instance).is_err() {
|
||||
return Err(ValidationError::format(instance.to_owned(), "base64"));
|
||||
return error(ValidationError::format(instance.to_owned(), "base64"));
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
pub(crate) fn from_base64(instance: &str) -> Result<String, ValidationError> {
|
||||
|
@ -106,11 +111,11 @@ pub(crate) fn from_base64(instance: &str) -> Result<String, ValidationError> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile_media_type<'a>(
|
||||
schema: &'a Map<String, Value>,
|
||||
subschema: &'a Value,
|
||||
pub(crate) fn compile_media_type(
|
||||
schema: &Map<String, Value>,
|
||||
subschema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
match subschema {
|
||||
Value::String(content_type) => {
|
||||
let func = match content_type.as_str() {
|
||||
|
@ -138,11 +143,11 @@ pub(crate) fn compile_media_type<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile_content_encoding<'a>(
|
||||
schema: &'a Map<String, Value>,
|
||||
subschema: &'a Value,
|
||||
pub(crate) fn compile_content_encoding(
|
||||
schema: &Map<String, Value>,
|
||||
subschema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
// Performed during media type validation
|
||||
if schema.get("contentMediaType").is_some() {
|
||||
// TODO. what if media type is not supported?
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
use super::{CompilationResult, ValidationResult};
|
||||
use super::CompilationResult;
|
||||
use super::{Validate, Validators};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::CompilationError;
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator};
|
||||
use crate::keywords::required::RequiredValidator;
|
||||
use crate::validator::compile_validators;
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct DependenciesValidator<'a> {
|
||||
dependencies: Vec<(&'a String, Validators<'a>)>,
|
||||
pub struct DependenciesValidator {
|
||||
dependencies: Vec<(String, Validators)>,
|
||||
}
|
||||
|
||||
impl<'a> DependenciesValidator<'a> {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
impl DependenciesValidator {
|
||||
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
|
||||
match schema.as_object() {
|
||||
Some(map) => {
|
||||
let mut dependencies = Vec::with_capacity(map.len());
|
||||
|
@ -24,7 +21,7 @@ impl<'a> DependenciesValidator<'a> {
|
|||
Value::Array(_) => vec![RequiredValidator::compile(subschema)?],
|
||||
_ => compile_validators(subschema, context)?,
|
||||
};
|
||||
dependencies.push((key, s))
|
||||
dependencies.push((key.clone(), s))
|
||||
}
|
||||
Ok(Box::new(DependenciesValidator { dependencies }))
|
||||
}
|
||||
|
@ -33,20 +30,23 @@ impl<'a> DependenciesValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for DependenciesValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for DependenciesValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance {
|
||||
for (property, validators) in self.dependencies.iter() {
|
||||
if !item.contains_key(*property) {
|
||||
continue;
|
||||
}
|
||||
// TODO. custom error message for "required" case
|
||||
for validator in validators.iter() {
|
||||
validator.validate(schema, instance)?
|
||||
}
|
||||
}
|
||||
let errors: Vec<_> = self
|
||||
.dependencies
|
||||
.iter()
|
||||
.filter(|(property, _)| item.contains_key(property))
|
||||
.flat_map(move |(_, validators)| {
|
||||
validators
|
||||
.iter()
|
||||
.flat_map(move |validator| validator.validate(schema, instance))
|
||||
})
|
||||
.collect();
|
||||
// TODO. custom error message for "required" case
|
||||
return Box::new(errors.into_iter());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
|
@ -54,10 +54,10 @@ impl<'a> Validate<'a> for DependenciesValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(DependenciesValidator::compile(schema, context))
|
||||
}
|
||||
|
|
|
@ -1,46 +1,43 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::{helpers, JSONSchema};
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct EnumValidator<'a> {
|
||||
options: &'a Value,
|
||||
items: &'a Vec<Value>,
|
||||
pub struct EnumValidator {
|
||||
options: Value,
|
||||
items: Vec<Value>,
|
||||
}
|
||||
|
||||
impl<'a> EnumValidator<'a> {
|
||||
pub(crate) fn compile(schema: &'a Value) -> CompilationResult<'a> {
|
||||
impl EnumValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult {
|
||||
if let Value::Array(items) = schema {
|
||||
return Ok(Box::new(EnumValidator {
|
||||
options: schema,
|
||||
items,
|
||||
options: schema.clone(),
|
||||
items: items.clone(),
|
||||
}));
|
||||
}
|
||||
Err(CompilationError::SchemaError)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for EnumValidator<'a> {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for EnumValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if !self.items.iter().any(|item| helpers::equal(instance, item)) {
|
||||
return Err(ValidationError::enumeration(
|
||||
instance.clone(),
|
||||
self.options.clone(),
|
||||
));
|
||||
return ValidationError::enumeration(instance.clone(), self.options.clone());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<enum: {:?}>", self.items)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(EnumValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
|
@ -10,7 +10,7 @@ pub struct ExclusiveMaximumValidator {
|
|||
}
|
||||
|
||||
impl<'a> ExclusiveMaximumValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult<'a> {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult {
|
||||
if let Value::Number(limit) = schema {
|
||||
return Ok(Box::new(ExclusiveMaximumValidator {
|
||||
limit: limit.as_f64().unwrap(),
|
||||
|
@ -20,25 +20,25 @@ impl<'a> ExclusiveMaximumValidator {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for ExclusiveMaximumValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for ExclusiveMaximumValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Number(item) = instance {
|
||||
let item = item.as_f64().unwrap();
|
||||
if item >= self.limit {
|
||||
return Err(ValidationError::exclusive_maximum(item, self.limit));
|
||||
return ValidationError::exclusive_maximum(item, self.limit);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<exclusive maximum: {}>", self.limit)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(ExclusiveMaximumValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
|
@ -10,7 +10,7 @@ pub struct ExclusiveMinimumValidator {
|
|||
}
|
||||
|
||||
impl<'a> ExclusiveMinimumValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult<'a> {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult {
|
||||
if let Value::Number(limit) = schema {
|
||||
let limit = limit.as_f64().unwrap();
|
||||
return Ok(Box::new(ExclusiveMinimumValidator { limit }));
|
||||
|
@ -19,24 +19,24 @@ impl<'a> ExclusiveMinimumValidator {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for ExclusiveMinimumValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for ExclusiveMinimumValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Number(item) = instance {
|
||||
let item = item.as_f64().unwrap();
|
||||
if item <= self.limit {
|
||||
return Err(ValidationError::exclusive_minimum(item, self.limit));
|
||||
return ValidationError::exclusive_minimum(item, self.limit);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<exclusive minimum: {}>", self.limit)
|
||||
}
|
||||
}
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(ExclusiveMinimumValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::CompilationError;
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator};
|
||||
use crate::{checks, JSONSchema};
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct FormatValidator {
|
||||
check: fn(&str) -> ValidationResult,
|
||||
check: fn(&str) -> ErrorIterator,
|
||||
}
|
||||
|
||||
impl<'a> FormatValidator {
|
||||
pub(crate) fn compile(check: fn(&str) -> ValidationResult) -> CompilationResult<'a> {
|
||||
pub(crate) fn compile(check: fn(&str) -> ErrorIterator) -> CompilationResult {
|
||||
Ok(Box::new(FormatValidator { check }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for FormatValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for FormatValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::String(item) = instance {
|
||||
return (self.check)(item);
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
// TODO. store name
|
||||
|
@ -28,11 +28,11 @@ impl<'a> Validate<'a> for FormatValidator {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
match schema.as_str() {
|
||||
Some(format) => {
|
||||
let func = match format {
|
||||
|
|
|
@ -1,21 +1,22 @@
|
|||
use super::{CompilationResult, ValidationResult};
|
||||
use super::CompilationResult;
|
||||
use super::{Validate, Validators};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{no_error, ErrorIterator};
|
||||
use crate::validator::compile_validators;
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct IfThenValidator<'a> {
|
||||
schema: Validators<'a>,
|
||||
then_schema: Validators<'a>,
|
||||
pub struct IfThenValidator {
|
||||
schema: Validators,
|
||||
then_schema: Validators,
|
||||
}
|
||||
|
||||
impl<'a> IfThenValidator<'a> {
|
||||
impl IfThenValidator {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
then_schema: &'a Value,
|
||||
schema: &Value,
|
||||
then_schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
) -> CompilationResult {
|
||||
Ok(Box::new(IfThenValidator {
|
||||
schema: compile_validators(schema, context)?,
|
||||
then_schema: compile_validators(then_schema, context)?,
|
||||
|
@ -23,35 +24,38 @@ impl<'a> IfThenValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for IfThenValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for IfThenValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if self
|
||||
.schema
|
||||
.iter()
|
||||
.all(|validator| validator.is_valid(schema, instance))
|
||||
{
|
||||
for validator in self.then_schema.iter() {
|
||||
validator.validate(schema, instance)?
|
||||
}
|
||||
let errors: Vec<_> = self
|
||||
.then_schema
|
||||
.iter()
|
||||
.flat_map(move |validator| validator.validate(schema, instance))
|
||||
.collect();
|
||||
return Box::new(errors.into_iter());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<if-then: {:?} {:?}>", self.schema, self.then_schema)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IfElseValidator<'a> {
|
||||
schema: Validators<'a>,
|
||||
else_schema: Validators<'a>,
|
||||
pub struct IfElseValidator {
|
||||
schema: Validators,
|
||||
else_schema: Validators,
|
||||
}
|
||||
|
||||
impl<'a> IfElseValidator<'a> {
|
||||
impl<'a> IfElseValidator {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
else_schema: &'a Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
) -> CompilationResult {
|
||||
Ok(Box::new(IfElseValidator {
|
||||
schema: compile_validators(schema, context)?,
|
||||
else_schema: compile_validators(else_schema, context)?,
|
||||
|
@ -59,37 +63,40 @@ impl<'a> IfElseValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for IfElseValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for IfElseValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if self
|
||||
.schema
|
||||
.iter()
|
||||
.any(|validator| !validator.is_valid(schema, instance))
|
||||
{
|
||||
for validator in self.else_schema.iter() {
|
||||
validator.validate(schema, instance)?
|
||||
}
|
||||
let errors: Vec<_> = self
|
||||
.else_schema
|
||||
.iter()
|
||||
.flat_map(move |validator| validator.validate(schema, instance))
|
||||
.collect();
|
||||
return Box::new(errors.into_iter());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<if-else: {:?} {:?}>", self.schema, self.else_schema)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct IfThenElseValidator<'a> {
|
||||
schema: Validators<'a>,
|
||||
then_schema: Validators<'a>,
|
||||
else_schema: Validators<'a>,
|
||||
pub struct IfThenElseValidator {
|
||||
schema: Validators,
|
||||
then_schema: Validators,
|
||||
else_schema: Validators,
|
||||
}
|
||||
|
||||
impl<'a> IfThenElseValidator<'a> {
|
||||
impl IfThenElseValidator {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
then_schema: &'a Value,
|
||||
else_schema: &'a Value,
|
||||
schema: &Value,
|
||||
then_schema: &Value,
|
||||
else_schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
) -> CompilationResult {
|
||||
Ok(Box::new(IfThenElseValidator {
|
||||
schema: compile_validators(schema, context)?,
|
||||
then_schema: compile_validators(then_schema, context)?,
|
||||
|
@ -98,22 +105,27 @@ impl<'a> IfThenElseValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for IfThenElseValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for IfThenElseValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if self
|
||||
.schema
|
||||
.iter()
|
||||
.all(|validator| validator.is_valid(schema, instance))
|
||||
{
|
||||
for validator in self.then_schema.iter() {
|
||||
validator.validate(schema, instance)?
|
||||
}
|
||||
let errors: Vec<_> = self
|
||||
.then_schema
|
||||
.iter()
|
||||
.flat_map(move |validator| validator.validate(schema, instance))
|
||||
.collect();
|
||||
Box::new(errors.into_iter())
|
||||
} else {
|
||||
for validator in self.else_schema.iter() {
|
||||
validator.validate(schema, instance)?
|
||||
}
|
||||
let errors: Vec<_> = self
|
||||
.else_schema
|
||||
.iter()
|
||||
.flat_map(move |validator| validator.validate(schema, instance))
|
||||
.collect();
|
||||
Box::new(errors.into_iter())
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!(
|
||||
|
@ -123,11 +135,11 @@ impl<'a> Validate<'a> for IfThenElseValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
parent: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
parent: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
let then = parent.get("then");
|
||||
let else_ = parent.get("else");
|
||||
match (then, else_) {
|
||||
|
|
|
@ -1,24 +1,18 @@
|
|||
use super::{CompilationResult, ValidationResult};
|
||||
use super::CompilationResult;
|
||||
use super::{Validate, Validators};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::ValidationError;
|
||||
use crate::error::{no_error, ErrorIterator};
|
||||
use crate::keywords::boolean::TrueValidator;
|
||||
use crate::validator::compile_validators;
|
||||
use crate::JSONSchema;
|
||||
use rayon::prelude::*;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
static PARALLEL_ITEMS_THRESHOLD: usize = 8;
|
||||
|
||||
pub struct ItemsArrayValidator<'a> {
|
||||
items: Vec<Validators<'a>>,
|
||||
pub struct ItemsArrayValidator {
|
||||
items: Vec<Validators>,
|
||||
}
|
||||
|
||||
impl<'a> ItemsArrayValidator<'a> {
|
||||
pub(crate) fn compile(
|
||||
schemas: &'a [Value],
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
impl ItemsArrayValidator {
|
||||
pub(crate) fn compile(schemas: &[Value], context: &CompilationContext) -> CompilationResult {
|
||||
let mut items = Vec::with_capacity(schemas.len());
|
||||
for item in schemas {
|
||||
let validators = compile_validators(item, context)?;
|
||||
|
@ -28,62 +22,54 @@ impl<'a> ItemsArrayValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for ItemsArrayValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for ItemsArrayValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Array(items) = instance {
|
||||
for (item, validators) in items.iter().zip(self.items.iter()) {
|
||||
for validator in validators {
|
||||
validator.validate(schema, item)?
|
||||
}
|
||||
}
|
||||
let errors: Vec<_> = items
|
||||
.iter()
|
||||
.zip(self.items.iter())
|
||||
.flat_map(move |(item, validators)| {
|
||||
validators
|
||||
.iter()
|
||||
.flat_map(move |validator| validator.validate(schema, item))
|
||||
})
|
||||
.collect();
|
||||
return Box::new(errors.into_iter());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<items: {:?}>", self.items)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ItemsObjectValidator<'a> {
|
||||
validators: Validators<'a>,
|
||||
pub struct ItemsObjectValidator {
|
||||
validators: Validators,
|
||||
}
|
||||
|
||||
impl<'a> ItemsObjectValidator<'a> {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
impl ItemsObjectValidator {
|
||||
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
|
||||
let validators = compile_validators(schema, context)?;
|
||||
Ok(Box::new(ItemsObjectValidator { validators }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for ItemsObjectValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for ItemsObjectValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Array(items) = instance {
|
||||
if items.len() > PARALLEL_ITEMS_THRESHOLD {
|
||||
let validate = |item| {
|
||||
for validator in self.validators.iter() {
|
||||
match validator.validate(schema, item) {
|
||||
Ok(_) => continue,
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
if items.par_iter().map(validate).any(|res| res.is_err()) {
|
||||
// TODO. it should be propagated! not necessarily "schema" error
|
||||
return Err(ValidationError::schema());
|
||||
}
|
||||
} else {
|
||||
for item in items {
|
||||
for validator in self.validators.iter() {
|
||||
validator.validate(schema, item)?
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO. make parallel
|
||||
let errors: Vec<_> = self
|
||||
.validators
|
||||
.iter()
|
||||
.flat_map(move |validator| {
|
||||
items
|
||||
.iter()
|
||||
.flat_map(move |item| validator.validate(schema, item))
|
||||
})
|
||||
.collect();
|
||||
return Box::new(errors.into_iter());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
|
@ -91,11 +77,11 @@ impl<'a> Validate<'a> for ItemsObjectValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
match schema {
|
||||
Value::Array(items) => Some(ItemsArrayValidator::compile(&items, &context)),
|
||||
Value::Object(_) => Some(ItemsObjectValidator::compile(schema, &context)),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
|
@ -10,7 +10,7 @@ pub struct MaxItemsValidator {
|
|||
}
|
||||
|
||||
impl<'a> MaxItemsValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult<'a> {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult {
|
||||
if let Value::Number(limit) = schema {
|
||||
let limit = limit.as_u64().unwrap() as usize;
|
||||
return Ok(Box::new(MaxItemsValidator { limit }));
|
||||
|
@ -19,14 +19,14 @@ impl<'a> MaxItemsValidator {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for MaxItemsValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for MaxItemsValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Array(items) = instance {
|
||||
if items.len() > self.limit {
|
||||
return Err(ValidationError::max_items(instance.clone()));
|
||||
return ValidationError::max_items(instance.clone());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
|
@ -34,10 +34,10 @@ impl<'a> Validate<'a> for MaxItemsValidator {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(MaxItemsValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
|
@ -9,8 +9,8 @@ pub struct MaxLengthValidator {
|
|||
limit: usize,
|
||||
}
|
||||
|
||||
impl<'a> MaxLengthValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult<'a> {
|
||||
impl MaxLengthValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult {
|
||||
if let Value::Number(limit) = schema {
|
||||
let limit = limit.as_u64().unwrap() as usize;
|
||||
return Ok(Box::new(MaxLengthValidator { limit }));
|
||||
|
@ -19,23 +19,23 @@ impl<'a> MaxLengthValidator {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for MaxLengthValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for MaxLengthValidator {
|
||||
fn validate<'a>(&self, _schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::String(item) = instance {
|
||||
if item.chars().count() > self.limit {
|
||||
return Err(ValidationError::max_length(item.clone()));
|
||||
return ValidationError::max_length(item.clone());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<max length: {}>", self.limit)
|
||||
}
|
||||
}
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(MaxLengthValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
|
@ -10,7 +10,7 @@ pub struct MaxPropertiesValidator {
|
|||
}
|
||||
|
||||
impl<'a> MaxPropertiesValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult<'a> {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult {
|
||||
if let Value::Number(limit) = schema {
|
||||
let limit = limit.as_u64().unwrap() as usize;
|
||||
return Ok(Box::new(MaxPropertiesValidator { limit }));
|
||||
|
@ -19,23 +19,23 @@ impl<'a> MaxPropertiesValidator {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for MaxPropertiesValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for MaxPropertiesValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance {
|
||||
if item.len() > self.limit {
|
||||
return Err(ValidationError::max_properties(instance.clone()));
|
||||
return ValidationError::max_properties(instance.clone());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<max properties: {}>", self.limit)
|
||||
}
|
||||
}
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(MaxPropertiesValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
|
@ -9,8 +9,8 @@ pub struct MaximumValidator {
|
|||
limit: f64,
|
||||
}
|
||||
|
||||
impl<'a> MaximumValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult<'a> {
|
||||
impl MaximumValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult {
|
||||
if let Value::Number(limit) = schema {
|
||||
let limit = limit.as_f64().unwrap();
|
||||
return Ok(Box::new(MaximumValidator { limit }));
|
||||
|
@ -19,25 +19,25 @@ impl<'a> MaximumValidator {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for MaximumValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for MaximumValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Number(item) = instance {
|
||||
let item = item.as_f64().unwrap();
|
||||
if item > self.limit {
|
||||
return Err(ValidationError::maximum(item, self.limit));
|
||||
return ValidationError::maximum(item, self.limit);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<maximum: {}>", self.limit)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(MaximumValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
|
@ -9,8 +9,8 @@ pub struct MinItemsValidator {
|
|||
limit: usize,
|
||||
}
|
||||
|
||||
impl<'a> MinItemsValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult<'a> {
|
||||
impl MinItemsValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult {
|
||||
if let Value::Number(limit) = schema {
|
||||
let limit = limit.as_u64().unwrap() as usize;
|
||||
return Ok(Box::new(MinItemsValidator { limit }));
|
||||
|
@ -19,23 +19,23 @@ impl<'a> MinItemsValidator {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for MinItemsValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for MinItemsValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Array(items) = instance {
|
||||
if items.len() < self.limit {
|
||||
return Err(ValidationError::min_items(instance.clone()));
|
||||
return ValidationError::min_items(instance.clone());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<min items: {}>", self.limit)
|
||||
}
|
||||
}
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(MinItemsValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
|
@ -10,7 +10,7 @@ pub struct MinLengthValidator {
|
|||
}
|
||||
|
||||
impl<'a> MinLengthValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult<'a> {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult {
|
||||
if let Value::Number(limit) = schema {
|
||||
let limit = limit.as_u64().unwrap() as usize;
|
||||
return Ok(Box::new(MinLengthValidator { limit }));
|
||||
|
@ -19,24 +19,24 @@ impl<'a> MinLengthValidator {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for MinLengthValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for MinLengthValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::String(item) = instance {
|
||||
if item.chars().count() < self.limit {
|
||||
return Err(ValidationError::min_length(item.clone()));
|
||||
return ValidationError::min_length(item.clone());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
format!("<min length: {}>", self.limit)
|
||||
}
|
||||
}
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(MinLengthValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
|
@ -10,7 +10,7 @@ pub struct MinPropertiesValidator {
|
|||
}
|
||||
|
||||
impl<'a> MinPropertiesValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult<'a> {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult {
|
||||
if let Value::Number(limit) = schema {
|
||||
let limit = limit.as_u64().unwrap() as usize;
|
||||
return Ok(Box::new(MinPropertiesValidator { limit }));
|
||||
|
@ -19,24 +19,24 @@ impl<'a> MinPropertiesValidator {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for MinPropertiesValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for MinPropertiesValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance {
|
||||
if item.len() < self.limit {
|
||||
return Err(ValidationError::min_properties(instance.clone()));
|
||||
return ValidationError::min_properties(instance.clone());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<min properties: {}>", self.limit)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(MinPropertiesValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
|
@ -19,25 +19,25 @@ impl MinimumValidator {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for MinimumValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for MinimumValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Number(item) = instance {
|
||||
let item = item.as_f64().unwrap();
|
||||
if item < self.limit {
|
||||
return Err(ValidationError::minimum(item, self.limit));
|
||||
return ValidationError::minimum(item, self.limit);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<minimum: {}>", self.limit)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(MinimumValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -33,30 +33,30 @@ pub(crate) mod required;
|
|||
pub(crate) mod type_;
|
||||
pub(crate) mod unique_items;
|
||||
use crate::error;
|
||||
use crate::error::ErrorIterator;
|
||||
use crate::validator::JSONSchema;
|
||||
use serde_json::Value;
|
||||
use std::fmt::{Debug, Error, Formatter};
|
||||
|
||||
pub trait Validate<'a>: Send + Sync + 'a {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult;
|
||||
// The same as above, but does not construct Result.
|
||||
pub trait Validate: Send + Sync {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a>;
|
||||
// The same as above, but does not construct ErrorIterator.
|
||||
// It is faster for cases when the result is not needed (like anyOf), since errors are
|
||||
// not constructed
|
||||
fn is_valid(&self, schema: &JSONSchema, instance: &Value) -> bool {
|
||||
self.validate(schema, instance).is_ok() // TODO. remove it and implement everywhere
|
||||
self.validate(schema, instance).next().is_none()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
"<validator>".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Debug for dyn Validate<'a> + Send + Sync + 'a {
|
||||
impl Debug for dyn Validate + Send + Sync {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
|
||||
f.write_str(&self.name())
|
||||
}
|
||||
}
|
||||
|
||||
pub type ValidationResult = Result<(), error::ValidationError>;
|
||||
pub type CompilationResult<'a> = Result<BoxedValidator<'a>, error::CompilationError>;
|
||||
pub type BoxedValidator<'a> = Box<dyn Validate<'a> + Send + Sync + 'a>;
|
||||
pub type Validators<'a> = Vec<BoxedValidator<'a>>;
|
||||
pub type CompilationResult = Result<BoxedValidator, error::CompilationError>;
|
||||
pub type BoxedValidator = Box<dyn Validate + Send + Sync>;
|
||||
pub type Validators = Vec<BoxedValidator>;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
use std::f64::EPSILON;
|
||||
|
@ -11,21 +11,21 @@ pub struct MultipleOfFloatValidator {
|
|||
}
|
||||
|
||||
impl<'a> MultipleOfFloatValidator {
|
||||
pub(crate) fn compile(multiple_of: f64) -> CompilationResult<'a> {
|
||||
pub(crate) fn compile(multiple_of: f64) -> CompilationResult {
|
||||
Ok(Box::new(MultipleOfFloatValidator { multiple_of }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for MultipleOfFloatValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for MultipleOfFloatValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Number(item) = instance {
|
||||
let item = item.as_f64().unwrap();
|
||||
let remainder = (item / self.multiple_of) % 1.;
|
||||
if !(remainder < EPSILON && remainder < (1. - EPSILON)) {
|
||||
return Err(ValidationError::multiple_of(item, self.multiple_of));
|
||||
return ValidationError::multiple_of(item, self.multiple_of);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<multiple of: {}>", self.multiple_of)
|
||||
|
@ -37,13 +37,13 @@ pub struct MultipleOfIntegerValidator {
|
|||
}
|
||||
|
||||
impl<'a> MultipleOfIntegerValidator {
|
||||
pub(crate) fn compile(multiple_of: f64) -> CompilationResult<'a> {
|
||||
pub(crate) fn compile(multiple_of: f64) -> CompilationResult {
|
||||
Ok(Box::new(MultipleOfIntegerValidator { multiple_of }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for MultipleOfIntegerValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for MultipleOfIntegerValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Number(item) = instance {
|
||||
let item = item.as_f64().unwrap();
|
||||
let is_multiple = if item.fract() == 0. {
|
||||
|
@ -53,21 +53,21 @@ impl<'a> Validate<'a> for MultipleOfIntegerValidator {
|
|||
remainder < EPSILON && remainder < (1. - EPSILON)
|
||||
};
|
||||
if !is_multiple {
|
||||
return Err(ValidationError::multiple_of(item, self.multiple_of));
|
||||
return ValidationError::multiple_of(item, self.multiple_of);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<multiple of: {}>", self.multiple_of)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
if let Value::Number(multiple_of) = schema {
|
||||
let multiple_of = multiple_of.as_f64().unwrap();
|
||||
return if multiple_of.fract() == 0. {
|
||||
|
|
|
@ -1,42 +1,36 @@
|
|||
use super::{CompilationResult, ValidationResult};
|
||||
use super::CompilationResult;
|
||||
use super::{Validate, Validators};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::ValidationError;
|
||||
use crate::error::{no_error, ErrorIterator, ValidationError};
|
||||
use crate::validator::compile_validators;
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct NotValidator<'a> {
|
||||
pub struct NotValidator {
|
||||
// needed only for error representation
|
||||
original: &'a Value,
|
||||
validators: Validators<'a>,
|
||||
original: Value,
|
||||
validators: Validators,
|
||||
}
|
||||
|
||||
impl<'a> NotValidator<'a> {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
impl NotValidator {
|
||||
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
|
||||
Ok(Box::new(NotValidator {
|
||||
original: schema,
|
||||
original: schema.clone(),
|
||||
validators: compile_validators(schema, context)?,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for NotValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for NotValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if self
|
||||
.validators
|
||||
.iter()
|
||||
.all(|validator| validator.is_valid(schema, instance))
|
||||
{
|
||||
Err(ValidationError::not(
|
||||
instance.clone(),
|
||||
self.original.clone(),
|
||||
))
|
||||
ValidationError::not(instance.clone(), self.original.clone())
|
||||
} else {
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
|
@ -44,10 +38,10 @@ impl<'a> Validate<'a> for NotValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(NotValidator::compile(schema, context))
|
||||
}
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
use super::{CompilationResult, ValidationResult};
|
||||
use super::CompilationResult;
|
||||
use super::{Validate, Validators};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::validator::compile_validators;
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct OneOfValidator<'a> {
|
||||
schemas: Vec<Validators<'a>>,
|
||||
pub struct OneOfValidator {
|
||||
schemas: Vec<Validators>,
|
||||
}
|
||||
|
||||
impl<'a> OneOfValidator<'a> {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
impl OneOfValidator {
|
||||
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
|
||||
match schema.as_array() {
|
||||
Some(items) => {
|
||||
let mut schemas = Vec::with_capacity(items.len());
|
||||
|
@ -31,7 +28,7 @@ impl<'a> OneOfValidator<'a> {
|
|||
&self,
|
||||
schema: &JSONSchema,
|
||||
instance: &Value,
|
||||
) -> (Option<&Validators<'a>>, Option<usize>) {
|
||||
) -> (Option<&Validators>, Option<usize>) {
|
||||
let mut first_valid = None;
|
||||
let mut first_valid_idx = None;
|
||||
for (idx, validators) in self.schemas.iter().enumerate() {
|
||||
|
@ -60,16 +57,16 @@ impl<'a> OneOfValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for OneOfValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for OneOfValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
let (first_valid, first_valid_idx) = self.get_first_valid(schema, instance);
|
||||
if first_valid.is_none() {
|
||||
return Err(ValidationError::one_of_not_valid(instance.clone()));
|
||||
return ValidationError::one_of_not_valid(instance.clone());
|
||||
}
|
||||
if self.are_others_valid(schema, instance, first_valid_idx) {
|
||||
return Err(ValidationError::one_of_multiple_valid(instance.clone()));
|
||||
return ValidationError::one_of_multiple_valid(instance.clone());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn is_valid(&self, schema: &JSONSchema, instance: &Value) -> bool {
|
||||
let (first_valid, first_valid_idx) = self.get_first_valid(schema, instance);
|
||||
|
@ -83,10 +80,10 @@ impl<'a> Validate<'a> for OneOfValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(OneOfValidator::compile(schema, context))
|
||||
}
|
||||
|
|
|
@ -1,28 +1,29 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use regex::{Captures, Regex};
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
use std::ops::Index;
|
||||
|
||||
lazy_static! {
|
||||
static ref CONTROL_GROUPS_RE: Regex = Regex::new(r"\\c[A-Za-z]").unwrap();
|
||||
}
|
||||
|
||||
pub struct PatternValidator<'a> {
|
||||
original: &'a String,
|
||||
pub struct PatternValidator {
|
||||
original: String,
|
||||
pattern: Regex,
|
||||
}
|
||||
|
||||
impl<'a> PatternValidator<'a> {
|
||||
pub(crate) fn compile(pattern: &'a Value) -> CompilationResult<'a> {
|
||||
impl PatternValidator {
|
||||
pub(crate) fn compile(pattern: &Value) -> CompilationResult {
|
||||
match pattern {
|
||||
Value::String(item) => {
|
||||
let pattern = convert_regex(item)?;
|
||||
Ok(Box::new(PatternValidator {
|
||||
original: item,
|
||||
original: item.clone(),
|
||||
pattern,
|
||||
}))
|
||||
}
|
||||
|
@ -31,17 +32,14 @@ impl<'a> PatternValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for PatternValidator<'a> {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for PatternValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::String(item) = instance {
|
||||
if !self.pattern.is_match(item) {
|
||||
return Err(ValidationError::pattern(
|
||||
item.clone(),
|
||||
self.original.clone(),
|
||||
));
|
||||
return ValidationError::pattern(item.clone(), self.original.clone());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<pattern: {}>", self.pattern)
|
||||
|
@ -74,10 +72,10 @@ fn replace_control_group(captures: &Captures) -> String {
|
|||
- 64) as char)
|
||||
.to_string()
|
||||
}
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(PatternValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -1,21 +1,18 @@
|
|||
use super::{CompilationResult, ValidationResult};
|
||||
use super::CompilationResult;
|
||||
use super::{Validate, Validators};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::CompilationError;
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator};
|
||||
use crate::validator::compile_validators;
|
||||
use crate::JSONSchema;
|
||||
use regex::Regex;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct PatternPropertiesValidator<'a> {
|
||||
patterns: Vec<(Regex, Validators<'a>)>,
|
||||
pub struct PatternPropertiesValidator {
|
||||
patterns: Vec<(Regex, Validators)>,
|
||||
}
|
||||
|
||||
impl<'a> PatternPropertiesValidator<'a> {
|
||||
pub(crate) fn compile(
|
||||
properties: &'a Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
impl PatternPropertiesValidator {
|
||||
pub(crate) fn compile(properties: &Value, context: &CompilationContext) -> CompilationResult {
|
||||
match properties.as_object() {
|
||||
Some(map) => {
|
||||
let mut patterns = Vec::with_capacity(map.len());
|
||||
|
@ -32,30 +29,35 @@ impl<'a> PatternPropertiesValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for PatternPropertiesValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for PatternPropertiesValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance {
|
||||
for (re, validators) in self.patterns.iter() {
|
||||
for (key, value) in item {
|
||||
if re.is_match(key) {
|
||||
for validator in validators.iter() {
|
||||
validator.validate(schema, value)?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let errors: Vec<_> = self
|
||||
.patterns
|
||||
.iter()
|
||||
.flat_map(move |(re, validators)| {
|
||||
item.iter()
|
||||
.filter(move |(key, _)| re.is_match(key))
|
||||
.flat_map(move |(_key, value)| {
|
||||
validators
|
||||
.iter()
|
||||
.flat_map(move |validator| validator.validate(schema, value))
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
return Box::new(errors.into_iter());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn name(&self) -> String {
|
||||
format!("<pattern properties: {:?}>", self.patterns)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(PatternPropertiesValidator::compile(schema, context))
|
||||
}
|
||||
|
|
|
@ -1,24 +1,21 @@
|
|||
use super::{CompilationResult, ValidationResult};
|
||||
use super::CompilationResult;
|
||||
use super::{Validate, Validators};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::CompilationError;
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator};
|
||||
use crate::validator::{compile_validators, JSONSchema};
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct PropertiesValidator<'a> {
|
||||
properties: Vec<(&'a String, Validators<'a>)>,
|
||||
pub struct PropertiesValidator {
|
||||
properties: Vec<(String, Validators)>,
|
||||
}
|
||||
|
||||
impl<'a> PropertiesValidator<'a> {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
impl PropertiesValidator {
|
||||
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
|
||||
match schema {
|
||||
Value::Object(map) => {
|
||||
let mut properties = Vec::with_capacity(map.len());
|
||||
for (key, subschema) in map {
|
||||
properties.push((key, compile_validators(subschema, context)?));
|
||||
properties.push((key.clone(), compile_validators(subschema, context)?));
|
||||
}
|
||||
Ok(Box::new(PropertiesValidator { properties }))
|
||||
}
|
||||
|
@ -27,29 +24,34 @@ impl<'a> PropertiesValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for PropertiesValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for PropertiesValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance {
|
||||
for (name, validators) in self.properties.iter() {
|
||||
if let Some(item) = item.get(*name) {
|
||||
for validator in validators {
|
||||
validator.validate(schema, item)?
|
||||
}
|
||||
}
|
||||
}
|
||||
let errors: Vec<_> = self
|
||||
.properties
|
||||
.iter()
|
||||
.flat_map(move |(name, validators)| {
|
||||
let option = item.get(name);
|
||||
option.into_iter().flat_map(move |item| {
|
||||
validators
|
||||
.iter()
|
||||
.flat_map(move |validator| validator.validate(schema, item))
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
return Box::new(errors.into_iter());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
// "".to_string()
|
||||
format!("<properties: {:?}>", self.properties)
|
||||
}
|
||||
}
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(PropertiesValidator::compile(schema, context))
|
||||
}
|
||||
|
|
|
@ -1,37 +1,41 @@
|
|||
use super::{CompilationResult, ValidationResult};
|
||||
use super::CompilationResult;
|
||||
use super::{Validate, Validators};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::ValidationError;
|
||||
use crate::error::{no_error, ErrorIterator, ValidationError};
|
||||
use crate::validator::compile_validators;
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
use std::borrow::Borrow;
|
||||
|
||||
pub struct PropertyNamesObjectValidator<'a> {
|
||||
validators: Validators<'a>,
|
||||
pub struct PropertyNamesObjectValidator {
|
||||
validators: Validators,
|
||||
}
|
||||
|
||||
impl<'a> PropertyNamesObjectValidator<'a> {
|
||||
pub(crate) fn compile(
|
||||
schema: &'a Value,
|
||||
context: &CompilationContext,
|
||||
) -> CompilationResult<'a> {
|
||||
impl PropertyNamesObjectValidator {
|
||||
pub(crate) fn compile(schema: &Value, context: &CompilationContext) -> CompilationResult {
|
||||
Ok(Box::new(PropertyNamesObjectValidator {
|
||||
validators: compile_validators(schema, context)?,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for PropertyNamesObjectValidator<'a> {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
if let Value::Object(item) = instance {
|
||||
for name in item.keys() {
|
||||
let wrapper = Value::String(name.to_string());
|
||||
for validator in self.validators.iter() {
|
||||
validator.validate(schema, &wrapper)?
|
||||
}
|
||||
}
|
||||
impl Validate for PropertyNamesObjectValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = &instance.borrow() {
|
||||
let errors: Vec<_> = self
|
||||
.validators
|
||||
.iter()
|
||||
.flat_map(move |validator| {
|
||||
item.keys().flat_map(move |key| {
|
||||
let wrapper = Value::String(key.to_string());
|
||||
let errors: Vec<_> = validator.validate(schema, &wrapper).collect();
|
||||
errors.into_iter()
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
return Box::new(errors.into_iter());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
|
@ -41,20 +45,20 @@ impl<'a> Validate<'a> for PropertyNamesObjectValidator<'a> {
|
|||
|
||||
pub struct PropertyNamesBooleanValidator {}
|
||||
|
||||
impl<'a> PropertyNamesBooleanValidator {
|
||||
pub(crate) fn compile() -> CompilationResult<'a> {
|
||||
impl PropertyNamesBooleanValidator {
|
||||
pub(crate) fn compile() -> CompilationResult {
|
||||
Ok(Box::new(PropertyNamesBooleanValidator {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for PropertyNamesBooleanValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
if let Value::Object(item) = instance {
|
||||
impl Validate for PropertyNamesBooleanValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance.borrow() {
|
||||
if !item.is_empty() {
|
||||
return Err(ValidationError::false_schema(instance.clone()));
|
||||
return ValidationError::false_schema(instance.clone());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
|
@ -62,11 +66,11 @@ impl<'a> Validate<'a> for PropertyNamesBooleanValidator {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
match schema {
|
||||
Value::Object(_) => Some(PropertyNamesObjectValidator::compile(schema, context)),
|
||||
Value::Bool(false) => Some(PropertyNamesBooleanValidator::compile()),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{error, ErrorIterator};
|
||||
use crate::validator::{compile_validators, JSONSchema};
|
||||
use serde_json::Value;
|
||||
use url::Url;
|
||||
|
@ -9,28 +10,31 @@ pub struct RefValidator {
|
|||
reference: Url,
|
||||
}
|
||||
|
||||
impl<'a> RefValidator {
|
||||
pub(crate) fn compile(reference: &str, context: &CompilationContext) -> CompilationResult<'a> {
|
||||
impl RefValidator {
|
||||
pub(crate) fn compile(reference: &str, context: &CompilationContext) -> CompilationResult {
|
||||
let reference = context.build_url(reference)?;
|
||||
Ok(Box::new(RefValidator { reference }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for RefValidator {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for RefValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
match schema
|
||||
.resolver
|
||||
.resolve_fragment(schema.draft, &self.reference, schema.schema)
|
||||
{
|
||||
Ok((scope, resolved)) => {
|
||||
let context = CompilationContext::new(scope, schema.draft);
|
||||
let validators = compile_validators(&resolved, &context)?;
|
||||
for v in validators.iter() {
|
||||
v.validate(schema, instance)?
|
||||
match compile_validators(&resolved, &context) {
|
||||
Ok(validators) => Box::new(
|
||||
validators
|
||||
.into_iter()
|
||||
.flat_map(move |validator| validator.validate(schema, instance)),
|
||||
),
|
||||
Err(e) => error(e.into()),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
Err(e) => error(e),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,10 +42,10 @@ impl<'a> Validate<'a> for RefValidator {
|
|||
format!("<ref: {}>", self.reference)
|
||||
}
|
||||
}
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Value,
|
||||
reference: &str,
|
||||
context: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(RefValidator::compile(reference, &context))
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, ValidationError};
|
||||
use crate::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
pub struct RequiredValidator<'a> {
|
||||
required: Vec<&'a String>,
|
||||
pub struct RequiredValidator {
|
||||
required: Vec<String>,
|
||||
}
|
||||
|
||||
impl<'a> RequiredValidator<'a> {
|
||||
pub(crate) fn compile(schema: &'a Value) -> CompilationResult<'a> {
|
||||
impl RequiredValidator {
|
||||
pub(crate) fn compile(schema: &Value) -> CompilationResult {
|
||||
match schema {
|
||||
Value::Array(items) => {
|
||||
let mut required = Vec::with_capacity(items.len());
|
||||
for item in items {
|
||||
match item {
|
||||
Value::String(string) => required.push(string),
|
||||
Value::String(string) => required.push(string.clone()),
|
||||
_ => return Err(CompilationError::SchemaError),
|
||||
}
|
||||
}
|
||||
|
@ -27,17 +27,16 @@ impl<'a> RequiredValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for RequiredValidator<'a> {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for RequiredValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if let Value::Object(item) = instance {
|
||||
for property_name in self.required.iter() {
|
||||
let name = *property_name;
|
||||
if !item.contains_key(name) {
|
||||
return Err(ValidationError::required(name.clone()));
|
||||
if !item.contains_key(property_name) {
|
||||
return ValidationError::required(property_name.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
fn name(&self) -> String {
|
||||
|
@ -45,10 +44,10 @@ impl<'a> Validate<'a> for RequiredValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
Some(RequiredValidator::compile(schema))
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::{CompilationError, PrimitiveType, ValidationError};
|
||||
use crate::error::{no_error, CompilationError, ErrorIterator, PrimitiveType, ValidationError};
|
||||
use crate::validator::JSONSchema;
|
||||
use serde_json::{Map, Number, Value};
|
||||
|
||||
|
@ -10,7 +10,7 @@ pub struct MultipleTypesValidator {
|
|||
}
|
||||
|
||||
impl MultipleTypesValidator {
|
||||
pub(crate) fn compile<'a>(items: &[Value]) -> CompilationResult<'a> {
|
||||
pub(crate) fn compile(items: &[Value]) -> CompilationResult {
|
||||
let mut types = Vec::with_capacity(items.len());
|
||||
for item in items {
|
||||
match item {
|
||||
|
@ -31,15 +31,12 @@ impl MultipleTypesValidator {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for MultipleTypesValidator {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for MultipleTypesValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if !self.is_valid(schema, instance) {
|
||||
return Err(ValidationError::multiple_type_error(
|
||||
instance.clone(),
|
||||
self.types.clone(),
|
||||
));
|
||||
return ValidationError::multiple_type_error(instance.clone(), self.types.clone());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
|
||||
for type_ in self.types.iter() {
|
||||
|
@ -65,20 +62,17 @@ impl<'a> Validate<'a> for MultipleTypesValidator {
|
|||
pub struct NullTypeValidator {}
|
||||
|
||||
impl NullTypeValidator {
|
||||
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
|
||||
pub(crate) fn compile() -> CompilationResult {
|
||||
Ok(Box::new(NullTypeValidator {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for NullTypeValidator {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for NullTypeValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if !self.is_valid(schema, instance) {
|
||||
return Err(ValidationError::single_type_error(
|
||||
instance.clone(),
|
||||
PrimitiveType::Null,
|
||||
));
|
||||
return ValidationError::single_type_error(instance.clone(), PrimitiveType::Null);
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
|
||||
instance.is_null()
|
||||
|
@ -92,20 +86,17 @@ impl<'a> Validate<'a> for NullTypeValidator {
|
|||
pub struct BooleanTypeValidator {}
|
||||
|
||||
impl BooleanTypeValidator {
|
||||
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
|
||||
pub(crate) fn compile() -> CompilationResult {
|
||||
Ok(Box::new(BooleanTypeValidator {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for BooleanTypeValidator {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for BooleanTypeValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if !self.is_valid(schema, instance) {
|
||||
return Err(ValidationError::single_type_error(
|
||||
instance.clone(),
|
||||
PrimitiveType::Boolean,
|
||||
));
|
||||
return ValidationError::single_type_error(instance.clone(), PrimitiveType::Boolean);
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
|
||||
instance.is_boolean()
|
||||
|
@ -119,20 +110,17 @@ impl<'a> Validate<'a> for BooleanTypeValidator {
|
|||
pub struct StringTypeValidator {}
|
||||
|
||||
impl StringTypeValidator {
|
||||
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
|
||||
pub(crate) fn compile() -> CompilationResult {
|
||||
Ok(Box::new(StringTypeValidator {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for StringTypeValidator {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for StringTypeValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if !self.is_valid(schema, instance) {
|
||||
return Err(ValidationError::single_type_error(
|
||||
instance.clone(),
|
||||
PrimitiveType::String,
|
||||
));
|
||||
return ValidationError::single_type_error(instance.clone(), PrimitiveType::String);
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
|
||||
|
@ -147,20 +135,17 @@ impl<'a> Validate<'a> for StringTypeValidator {
|
|||
pub struct ArrayTypeValidator {}
|
||||
|
||||
impl ArrayTypeValidator {
|
||||
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
|
||||
pub(crate) fn compile() -> CompilationResult {
|
||||
Ok(Box::new(ArrayTypeValidator {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for ArrayTypeValidator {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for ArrayTypeValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if !self.is_valid(schema, instance) {
|
||||
return Err(ValidationError::single_type_error(
|
||||
instance.clone(),
|
||||
PrimitiveType::Array,
|
||||
));
|
||||
return ValidationError::single_type_error(instance.clone(), PrimitiveType::Array);
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
|
||||
|
@ -175,20 +160,17 @@ impl<'a> Validate<'a> for ArrayTypeValidator {
|
|||
pub struct ObjectTypeValidator {}
|
||||
|
||||
impl ObjectTypeValidator {
|
||||
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
|
||||
pub(crate) fn compile() -> CompilationResult {
|
||||
Ok(Box::new(ObjectTypeValidator {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for ObjectTypeValidator {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for ObjectTypeValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if !self.is_valid(schema, instance) {
|
||||
return Err(ValidationError::single_type_error(
|
||||
instance.clone(),
|
||||
PrimitiveType::Object,
|
||||
));
|
||||
return ValidationError::single_type_error(instance.clone(), PrimitiveType::Object);
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
|
||||
instance.is_object()
|
||||
|
@ -202,20 +184,17 @@ impl<'a> Validate<'a> for ObjectTypeValidator {
|
|||
pub struct NumberTypeValidator {}
|
||||
|
||||
impl NumberTypeValidator {
|
||||
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
|
||||
pub(crate) fn compile() -> CompilationResult {
|
||||
Ok(Box::new(NumberTypeValidator {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for NumberTypeValidator {
|
||||
fn validate(&self, _: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for NumberTypeValidator {
|
||||
fn validate<'a>(&self, _: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if !instance.is_number() {
|
||||
return Err(ValidationError::single_type_error(
|
||||
instance.clone(),
|
||||
PrimitiveType::Number,
|
||||
));
|
||||
return ValidationError::single_type_error(instance.clone(), PrimitiveType::Number);
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
|
||||
instance.is_number()
|
||||
|
@ -229,20 +208,17 @@ impl<'a> Validate<'a> for NumberTypeValidator {
|
|||
pub struct IntegerTypeValidator {}
|
||||
|
||||
impl IntegerTypeValidator {
|
||||
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
|
||||
pub(crate) fn compile() -> CompilationResult {
|
||||
Ok(Box::new(IntegerTypeValidator {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for IntegerTypeValidator {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for IntegerTypeValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if !self.is_valid(schema, instance) {
|
||||
return Err(ValidationError::single_type_error(
|
||||
instance.clone(),
|
||||
PrimitiveType::Integer,
|
||||
));
|
||||
return ValidationError::single_type_error(instance.clone(), PrimitiveType::Integer);
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
|
||||
|
@ -261,11 +237,11 @@ fn is_integer(num: &Number) -> bool {
|
|||
num.is_u64() || num.is_i64() || num.as_f64().unwrap().fract() == 0.
|
||||
}
|
||||
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
match schema {
|
||||
Value::String(item) => compile_single_type(item.as_str()),
|
||||
Value::Array(items) => {
|
||||
|
@ -283,7 +259,7 @@ pub(crate) fn compile<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn compile_single_type<'a>(item: &str) -> Option<CompilationResult<'a>> {
|
||||
fn compile_single_type(item: &str) -> Option<CompilationResult> {
|
||||
match item {
|
||||
"integer" => Some(IntegerTypeValidator::compile()),
|
||||
"null" => Some(NullTypeValidator::compile()),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use super::CompilationResult;
|
||||
use super::Validate;
|
||||
use super::{CompilationResult, ValidationResult};
|
||||
use crate::context::CompilationContext;
|
||||
use crate::error::ValidationError;
|
||||
use crate::error::{no_error, ErrorIterator, ValidationError};
|
||||
use crate::validator::JSONSchema;
|
||||
use serde_json::{Map, Value};
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
|
@ -59,17 +59,17 @@ pub fn is_unique(items: &[Value]) -> bool {
|
|||
pub struct UniqueItemsValidator {}
|
||||
|
||||
impl UniqueItemsValidator {
|
||||
pub(crate) fn compile<'a>() -> CompilationResult<'a> {
|
||||
pub(crate) fn compile() -> CompilationResult {
|
||||
Ok(Box::new(UniqueItemsValidator {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Validate<'a> for UniqueItemsValidator {
|
||||
fn validate(&self, schema: &JSONSchema, instance: &Value) -> ValidationResult {
|
||||
impl Validate for UniqueItemsValidator {
|
||||
fn validate<'a>(&self, schema: &'a JSONSchema, instance: &'a Value) -> ErrorIterator<'a> {
|
||||
if !self.is_valid(schema, instance) {
|
||||
return Err(ValidationError::unique_items(instance.clone()));
|
||||
return ValidationError::unique_items(instance.clone());
|
||||
}
|
||||
Ok(())
|
||||
no_error()
|
||||
}
|
||||
|
||||
fn is_valid(&self, _: &JSONSchema, instance: &Value) -> bool {
|
||||
|
@ -85,11 +85,11 @@ impl<'a> Validate<'a> for UniqueItemsValidator {
|
|||
"<unique items>".to_string()
|
||||
}
|
||||
}
|
||||
pub(crate) fn compile<'a>(
|
||||
_: &'a Map<String, Value>,
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile(
|
||||
_: &Map<String, Value>,
|
||||
schema: &Value,
|
||||
_: &CompilationContext,
|
||||
) -> Option<CompilationResult<'a>> {
|
||||
) -> Option<CompilationResult> {
|
||||
if let Value::Bool(value) = schema {
|
||||
if *value {
|
||||
Some(UniqueItemsValidator::compile())
|
||||
|
|
24
src/lib.rs
24
src/lib.rs
|
@ -6,9 +6,31 @@ mod keywords;
|
|||
mod resolver;
|
||||
mod schemas;
|
||||
mod validator;
|
||||
pub use error::ValidationError;
|
||||
pub use error::{ErrorIterator, ValidationError};
|
||||
pub use schemas::Draft;
|
||||
use serde_json::Value;
|
||||
pub use validator::JSONSchema;
|
||||
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
/// Validates `instance` against `schema`. Draft version is detected automatically.
|
||||
pub fn is_valid(schema: &Value, instance: &Value) -> bool {
|
||||
let compiled = JSONSchema::compile(schema, None).expect("Invalid schema");
|
||||
compiled.is_valid(instance)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn test_is_valid() {
|
||||
let schema = json!({"minLength": 5});
|
||||
let valid = json!("foobar");
|
||||
let invalid = json!("foo");
|
||||
assert!(is_valid(&schema, &valid));
|
||||
assert!(!is_valid(&schema, &invalid));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,14 +10,11 @@ pub enum Draft {
|
|||
Draft7,
|
||||
}
|
||||
|
||||
type CompileFunc<'a> = fn(
|
||||
&'a Map<String, Value>,
|
||||
&'a Value,
|
||||
&CompilationContext,
|
||||
) -> Option<keywords::CompilationResult<'a>>;
|
||||
type CompileFunc =
|
||||
fn(&Map<String, Value>, &Value, &CompilationContext) -> Option<keywords::CompilationResult>;
|
||||
|
||||
impl Draft {
|
||||
pub(crate) fn get_validator<'a>(self, keyword: &str) -> Option<CompileFunc<'a>> {
|
||||
pub(crate) fn get_validator(self, keyword: &str) -> Option<CompileFunc> {
|
||||
match self {
|
||||
Draft::Draft7 => match keyword {
|
||||
"additionalItems" => Some(keywords::additional_items::compile),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::context::CompilationContext;
|
||||
use crate::error::CompilationError;
|
||||
use crate::keywords::{ValidationResult, Validators};
|
||||
use crate::error::{CompilationError, ErrorIterator};
|
||||
use crate::keywords::Validators;
|
||||
use crate::resolver::Resolver;
|
||||
use crate::schemas::{id_of, Draft};
|
||||
use crate::{keywords, schemas};
|
||||
|
@ -11,7 +11,7 @@ pub(crate) const DOCUMENT_PROTOCOL: &str = "json-schema:///";
|
|||
pub struct JSONSchema<'a> {
|
||||
pub(crate) draft: Draft,
|
||||
pub(crate) schema: &'a Value,
|
||||
pub(crate) validators: Validators<'a>,
|
||||
pub(crate) validators: Validators,
|
||||
pub(crate) resolver: Resolver<'a>,
|
||||
}
|
||||
|
||||
|
@ -39,11 +39,17 @@ impl<'a> JSONSchema<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn validate(&self, instance: &Value) -> ValidationResult {
|
||||
for v in self.validators.iter() {
|
||||
v.validate(self, instance)?
|
||||
pub fn validate(&'a self, instance: &'a Value) -> Result<(), ErrorIterator<'a>> {
|
||||
let mut errors = self
|
||||
.validators
|
||||
.iter()
|
||||
.flat_map(move |validator| validator.validate(self, instance))
|
||||
.peekable();
|
||||
if errors.peek().is_none() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Box::new(errors))
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn is_valid(&self, instance: &Value) -> bool {
|
||||
|
@ -53,10 +59,10 @@ impl<'a> JSONSchema<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compile_validators<'a>(
|
||||
schema: &'a Value,
|
||||
pub(crate) fn compile_validators(
|
||||
schema: &Value,
|
||||
context: &CompilationContext,
|
||||
) -> Result<Validators<'a>, CompilationError> {
|
||||
) -> Result<Validators, CompilationError> {
|
||||
let context = context.push(schema);
|
||||
match schema {
|
||||
Value::Bool(value) => {
|
||||
|
@ -96,6 +102,7 @@ pub(crate) fn compile_validators<'a>(
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ValidationError;
|
||||
use serde_json::*;
|
||||
use std::borrow::Cow;
|
||||
use std::fs::File;
|
||||
|
@ -117,9 +124,9 @@ mod tests {
|
|||
fn only_keyword() {
|
||||
// When only one keyword is specified
|
||||
let schema = json!({"type": "string"});
|
||||
let compiled = JSONSchema::compile(&schema, None).unwrap();
|
||||
let value1 = json!("AB");
|
||||
let value2 = json!(1);
|
||||
let compiled = JSONSchema::compile(&schema, None).unwrap();
|
||||
// And only this validator
|
||||
assert_eq!(compiled.validators.len(), 1);
|
||||
assert!(compiled.validate(&value1).is_ok());
|
||||
|
@ -150,4 +157,19 @@ mod tests {
|
|||
let value = json!({"bar": true});
|
||||
assert!(compiled.validate(&value).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn multiple_errors() {
|
||||
let schema = json!({"minProperties": 2, "propertyNames": {"minLength": 3}});
|
||||
let value = json!({"a": 3});
|
||||
let compiled = JSONSchema::compile(&schema, None).unwrap();
|
||||
let result = compiled.validate(&value);
|
||||
let errors: Vec<ValidationError> = result.unwrap_err().collect();
|
||||
assert_eq!(errors.len(), 2);
|
||||
assert_eq!(
|
||||
format!("{}", errors[0]),
|
||||
r#"'{"a":3}' does not have enough properties"#
|
||||
);
|
||||
assert_eq!(format!("{}", errors[1]), r#"'a' is too short"#);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue