From a9897845a09a97f41a15e9d5ab3dc9b8b0f50cf3 Mon Sep 17 00:00:00 2001 From: Dmitry Dygalo Date: Sat, 26 Oct 2024 07:21:30 +0200 Subject: [PATCH] chore!: Remove deprecated ValidationErrorKind variants Signed-off-by: Dmitry Dygalo --- CHANGELOG.md | 4 + crates/jsonschema/src/error.rs | 70 ----------------- .../src/keywords/additional_properties.rs | 78 ++++++++++--------- crates/jsonschema/src/keywords/custom.rs | 7 -- .../src/keywords/legacy/type_draft_4.rs | 33 +++++--- crates/jsonschema/src/keywords/type_.rs | 33 +++++--- crates/jsonschema/src/properties.rs | 7 +- 7 files changed, 94 insertions(+), 138 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae91b213..5987fce3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Changed + +- **BREAKING**: Remove unused `ValidationErrorKind::JSONParse`, `ValidationErrorKind::InvalidReference`, `ValidationErrorKind::Schema`, `ValidationErrorKind::FileNotFound` and `ValidationErrorKind::Utf8`. + ### Performance - Optimize error formatting in some cases. diff --git a/crates/jsonschema/src/error.rs b/crates/jsonschema/src/error.rs index d472774a..8dacbbee 100644 --- a/crates/jsonschema/src/error.rs +++ b/crates/jsonschema/src/error.rs @@ -8,9 +8,7 @@ use std::{ borrow::Cow, error, fmt::{self, Formatter, Write}, - io, iter::{empty, once}, - str::Utf8Error, string::FromUtf8Error, }; @@ -87,18 +85,10 @@ pub enum ValidationErrorKind { ExclusiveMinimum { limit: Value }, /// Everything is invalid for `false` schema. FalseSchema, - /// If the referenced file is not found during ref resolution. - FileNotFound { error: io::Error }, /// When the input doesn't match to the specified format. Format { format: String }, /// May happen in `contentEncoding` validation if `base64` encoded data is invalid. FromUtf8 { error: FromUtf8Error }, - /// Invalid UTF-8 string during percent encoding when resolving happens - Utf8 { error: Utf8Error }, - /// May happen during ref resolution when remote document is not a valid JSON. - JSONParse { error: serde_json::Error }, - /// `ref` value is not valid. - InvalidReference { reference: String }, /// Too many items in an array. MaxItems { limit: u64 }, /// Value is too large. @@ -131,8 +121,6 @@ pub enum ValidationErrorKind { }, /// When a required property is missing. Required { property: Value }, - /// Resolved schema failed to compile. - Schema, /// When the input value doesn't match one or multiple required types. Type { kind: TypeKind }, /// Unexpected items. @@ -398,14 +386,6 @@ impl<'a> ValidationError<'a> { schema_path: location, } } - pub(crate) fn file_not_found(error: io::Error) -> ValidationError<'a> { - ValidationError { - instance_path: Location::new(), - instance: Cow::Owned(Value::Null), - kind: ValidationErrorKind::FileNotFound { error }, - schema_path: Location::new(), - } - } pub(crate) fn format( location: Location, instance_path: Location, @@ -429,14 +409,6 @@ impl<'a> ValidationError<'a> { schema_path: Location::new(), } } - pub(crate) fn json_parse(error: serde_json::Error) -> ValidationError<'a> { - ValidationError { - instance_path: Location::new(), - instance: Cow::Owned(Value::Null), - kind: ValidationErrorKind::JSONParse { error }, - schema_path: Location::new(), - } - } pub(crate) const fn max_items( location: Location, instance_path: Location, @@ -633,15 +605,6 @@ impl<'a> ValidationError<'a> { } } - pub(crate) fn null_schema() -> ValidationError<'a> { - ValidationError { - instance_path: Location::new(), - instance: Cow::Owned(Value::Null), - kind: ValidationErrorKind::Schema, - schema_path: Location::new(), - } - } - pub(crate) const fn single_type_error( location: Location, instance_path: Location, @@ -710,14 +673,6 @@ impl<'a> ValidationError<'a> { schema_path: location, } } - pub(crate) fn utf8(error: Utf8Error) -> ValidationError<'a> { - ValidationError { - instance_path: Location::new(), - instance: Cow::Owned(Value::Null), - kind: ValidationErrorKind::Utf8 { error }, - schema_path: Location::new(), - } - } /// Create a new custom validation error. pub fn custom( location: Location, @@ -737,12 +692,6 @@ impl<'a> ValidationError<'a> { } impl error::Error for ValidationError<'_> {} -impl From for ValidationError<'_> { - #[inline] - fn from(err: serde_json::Error) -> Self { - ValidationError::json_parse(err) - } -} impl From for ValidationError<'_> { #[inline] fn from(err: referencing::Error) -> Self { @@ -754,34 +703,19 @@ impl From for ValidationError<'_> { } } } -impl From for ValidationError<'_> { - #[inline] - fn from(err: io::Error) -> Self { - ValidationError::file_not_found(err) - } -} impl From for ValidationError<'_> { #[inline] fn from(err: FromUtf8Error) -> Self { ValidationError::from_utf8(err) } } -impl From for ValidationError<'_> { - #[inline] - fn from(err: Utf8Error) -> Self { - ValidationError::utf8(err) - } -} /// Textual representation of various validation errors. impl fmt::Display for ValidationError<'_> { #[allow(clippy::too_many_lines)] // The function is long but it does formatting only fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match &self.kind { - ValidationErrorKind::Schema => f.write_str("Schema error"), - ValidationErrorKind::JSONParse { error } => error.fmt(f), ValidationErrorKind::Referencing(error) => error.fmt(f), - ValidationErrorKind::FileNotFound { error } => error.fmt(f), ValidationErrorKind::BacktrackLimitExceeded { error } => error.fmt(f), ValidationErrorKind::Format { format } => { write!(f, r#"{} is not a "{}""#, self.instance, format) @@ -859,7 +793,6 @@ impl fmt::Display for ValidationError<'_> { ) } ValidationErrorKind::FromUtf8 { error } => error.fmt(f), - ValidationErrorKind::Utf8 { error } => error.fmt(f), ValidationErrorKind::Enum { options } => { write!(f, "{} is not one of {}", self.instance, options) } @@ -876,9 +809,6 @@ impl fmt::Display for ValidationError<'_> { ValidationErrorKind::FalseSchema => { write!(f, "False schema does not allow {}", self.instance) } - ValidationErrorKind::InvalidReference { reference } => { - write!(f, "Invalid reference: {}", reference) - } ValidationErrorKind::Maximum { limit } => write!( f, "{} is greater than the maximum of {}", diff --git a/crates/jsonschema/src/keywords/additional_properties.rs b/crates/jsonschema/src/keywords/additional_properties.rs index 6146bf51..c11bc288 100644 --- a/crates/jsonschema/src/keywords/additional_properties.rs +++ b/crates/jsonschema/src/keywords/additional_properties.rs @@ -13,6 +13,7 @@ use crate::{ node::SchemaNode, output::{Annotations, BasicOutput, OutputUnit}, paths::{LazyLocation, Location}, + primitive_type::PrimitiveType, properties::*, validator::{PartialApplication, Validate}, }; @@ -1035,47 +1036,52 @@ pub(crate) fn compile<'a>( if let Some(patterns) = parent.get("patternProperties") { if let Value::Object(obj) = patterns { // Compile all patterns & their validators to avoid doing work in the `patternProperties` validator - if let Ok(compiled_patterns) = compile_patterns(ctx, obj) { - match schema { - Value::Bool(true) => None, // "additionalProperties" are "true" by default - Value::Bool(false) => { - if let Some(properties) = properties { - compile_dynamic_prop_map_validator!( - AdditionalPropertiesWithPatternsNotEmptyFalseValidator, - properties, - ctx, - compiled_patterns, - ) - } else { - Some(AdditionalPropertiesWithPatternsFalseValidator::compile( - ctx, - compiled_patterns, - )) - } + let compiled_patterns = match compile_patterns(ctx, obj) { + Ok(patterns) => patterns, + Err(error) => return Some(Err(error)), + }; + match schema { + Value::Bool(true) => None, // "additionalProperties" are "true" by default + Value::Bool(false) => { + if let Some(properties) = properties { + compile_dynamic_prop_map_validator!( + AdditionalPropertiesWithPatternsNotEmptyFalseValidator, + properties, + ctx, + compiled_patterns, + ) + } else { + Some(AdditionalPropertiesWithPatternsFalseValidator::compile( + ctx, + compiled_patterns, + )) } - _ => { - if let Some(properties) = properties { - compile_dynamic_prop_map_validator!( - AdditionalPropertiesWithPatternsNotEmptyValidator, - properties, - ctx, - schema, - compiled_patterns, - ) - } else { - Some(AdditionalPropertiesWithPatternsValidator::compile( - ctx, - schema, - compiled_patterns, - )) - } + } + _ => { + if let Some(properties) = properties { + compile_dynamic_prop_map_validator!( + AdditionalPropertiesWithPatternsNotEmptyValidator, + properties, + ctx, + schema, + compiled_patterns, + ) + } else { + Some(AdditionalPropertiesWithPatternsValidator::compile( + ctx, + schema, + compiled_patterns, + )) } } - } else { - Some(Err(ValidationError::null_schema())) } } else { - Some(Err(ValidationError::null_schema())) + Some(Err(ValidationError::single_type_error( + Location::new(), + ctx.location().clone(), + schema, + PrimitiveType::Object, + ))) } } else { match schema { diff --git a/crates/jsonschema/src/keywords/custom.rs b/crates/jsonschema/src/keywords/custom.rs index f38ee1f4..dbb404f1 100644 --- a/crates/jsonschema/src/keywords/custom.rs +++ b/crates/jsonschema/src/keywords/custom.rs @@ -4,7 +4,6 @@ use crate::{ ErrorIterator, ValidationError, }; use serde_json::{Map, Value}; -use std::fmt::{Display, Formatter}; pub(crate) struct CustomKeyword { inner: Box, @@ -16,12 +15,6 @@ impl CustomKeyword { } } -impl Display for CustomKeyword { - fn fmt(&self, _: &mut Formatter<'_>) -> std::fmt::Result { - Ok(()) - } -} - impl Validate for CustomKeyword { fn validate<'i>(&self, instance: &'i Value, location: &LazyLocation) -> ErrorIterator<'i> { self.inner.validate(instance, location) diff --git a/crates/jsonschema/src/keywords/legacy/type_draft_4.rs b/crates/jsonschema/src/keywords/legacy/type_draft_4.rs index 65c5e5aa..9cd7d2cf 100644 --- a/crates/jsonschema/src/keywords/legacy/type_draft_4.rs +++ b/crates/jsonschema/src/keywords/legacy/type_draft_4.rs @@ -122,12 +122,12 @@ pub(crate) fn compile<'a>( ) -> Option> { let location = ctx.location().join("type"); match schema { - Value::String(item) => compile_single_type(item.as_str(), location), + Value::String(item) => Some(compile_single_type(item.as_str(), location, schema)), Value::Array(items) => { if items.len() == 1 { let item = &items[0]; - if let Value::String(item) = item { - compile_single_type(item.as_str(), location) + if let Value::String(ty) = item { + Some(compile_single_type(ty.as_str(), location, item)) } else { Some(Err(ValidationError::single_type_error( Location::new(), @@ -151,15 +151,24 @@ pub(crate) fn compile<'a>( } } -fn compile_single_type<'a>(item: &str, location: Location) -> Option> { +fn compile_single_type<'a>( + item: &str, + location: Location, + instance: &'a Value, +) -> CompilationResult<'a> { match PrimitiveType::try_from(item) { - Ok(PrimitiveType::Array) => Some(type_::ArrayTypeValidator::compile(location)), - Ok(PrimitiveType::Boolean) => Some(type_::BooleanTypeValidator::compile(location)), - Ok(PrimitiveType::Integer) => Some(IntegerTypeValidator::compile(location)), - Ok(PrimitiveType::Null) => Some(type_::NullTypeValidator::compile(location)), - Ok(PrimitiveType::Number) => Some(type_::NumberTypeValidator::compile(location)), - Ok(PrimitiveType::Object) => Some(type_::ObjectTypeValidator::compile(location)), - Ok(PrimitiveType::String) => Some(type_::StringTypeValidator::compile(location)), - Err(()) => Some(Err(ValidationError::null_schema())), + Ok(PrimitiveType::Array) => type_::ArrayTypeValidator::compile(location), + Ok(PrimitiveType::Boolean) => type_::BooleanTypeValidator::compile(location), + Ok(PrimitiveType::Integer) => IntegerTypeValidator::compile(location), + Ok(PrimitiveType::Null) => type_::NullTypeValidator::compile(location), + Ok(PrimitiveType::Number) => type_::NumberTypeValidator::compile(location), + Ok(PrimitiveType::Object) => type_::ObjectTypeValidator::compile(location), + Ok(PrimitiveType::String) => type_::StringTypeValidator::compile(location), + Err(()) => Err(ValidationError::custom( + Location::new(), + location, + instance, + "Unexpected type", + )), } } diff --git a/crates/jsonschema/src/keywords/type_.rs b/crates/jsonschema/src/keywords/type_.rs index 56865ef0..b5d2b3f4 100644 --- a/crates/jsonschema/src/keywords/type_.rs +++ b/crates/jsonschema/src/keywords/type_.rs @@ -299,12 +299,12 @@ pub(crate) fn compile<'a>( ) -> Option> { let location = ctx.location().join("type"); match schema { - Value::String(item) => compile_single_type(item.as_str(), location), + Value::String(item) => Some(compile_single_type(item.as_str(), location, schema)), Value::Array(items) => { if items.len() == 1 { let item = &items[0]; - if let Value::String(item) = item { - compile_single_type(item.as_str(), location) + if let Value::String(ty) = item { + Some(compile_single_type(ty.as_str(), location, item)) } else { Some(Err(ValidationError::single_type_error( Location::new(), @@ -328,16 +328,25 @@ pub(crate) fn compile<'a>( } } -fn compile_single_type(item: &str, location: Location) -> Option { +fn compile_single_type<'a>( + item: &str, + location: Location, + instance: &'a Value, +) -> CompilationResult<'a> { match PrimitiveType::try_from(item) { - Ok(PrimitiveType::Array) => Some(ArrayTypeValidator::compile(location)), - Ok(PrimitiveType::Boolean) => Some(BooleanTypeValidator::compile(location)), - Ok(PrimitiveType::Integer) => Some(IntegerTypeValidator::compile(location)), - Ok(PrimitiveType::Null) => Some(NullTypeValidator::compile(location)), - Ok(PrimitiveType::Number) => Some(NumberTypeValidator::compile(location)), - Ok(PrimitiveType::Object) => Some(ObjectTypeValidator::compile(location)), - Ok(PrimitiveType::String) => Some(StringTypeValidator::compile(location)), - Err(()) => Some(Err(ValidationError::null_schema())), + Ok(PrimitiveType::Array) => ArrayTypeValidator::compile(location), + Ok(PrimitiveType::Boolean) => BooleanTypeValidator::compile(location), + Ok(PrimitiveType::Integer) => IntegerTypeValidator::compile(location), + Ok(PrimitiveType::Null) => NullTypeValidator::compile(location), + Ok(PrimitiveType::Number) => NumberTypeValidator::compile(location), + Ok(PrimitiveType::Object) => ObjectTypeValidator::compile(location), + Ok(PrimitiveType::String) => StringTypeValidator::compile(location), + Err(()) => Err(ValidationError::custom( + Location::new(), + location, + instance, + "Unexpected type", + )), } } diff --git a/crates/jsonschema/src/properties.rs b/crates/jsonschema/src/properties.rs index 41438cd4..ecff1a42 100644 --- a/crates/jsonschema/src/properties.rs +++ b/crates/jsonschema/src/properties.rs @@ -142,7 +142,12 @@ macro_rules! compile_dynamic_prop_map_validator { )) } } else { - Some(Err(ValidationError::null_schema())) + Some(Err(ValidationError::custom( + Location::new(), + Location::new(), + $properties, + "Unexpected type", + ))) } }}; }