Skip to content

Commit

Permalink
feat: Initial handling of if keyword
Browse files Browse the repository at this point in the history
  • Loading branch information
macisamuele committed Jun 25, 2020
1 parent 591821a commit 460baf2
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 2 deletions.
74 changes: 74 additions & 0 deletions src/keywords/if_.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use crate::helpers::is;
use jsonschema_equivalent_rule_processor_logger::log_processing;
use serde_json::Value;

/// Simplify `if` keyword group by embedding the content of `then` or `else` schema
/// into `allOf` in case of deterministic validation or removing it if `then` or `else` are missing.
#[log_processing(cfg(feature = "logging"))]
pub(crate) fn simplify_if(schema: &mut Value) -> bool {
let schema_object = if let Some(value) = schema.as_object_mut() {
value
} else {
return false;
};

if let Some(if_schema) = schema_object.get("if") {
if is::false_schema(if_schema) {
// In case of a `false` schema we know that the `then` schema will never be considered
// so we can simplify the schema by ensuring that the `else` schema has to be verified
let _ = schema_object.remove("if");
let _ = schema_object.remove("then");
if let Some(else_schema) = schema_object.remove("else") {
if let Value::Array(mut all_of_items) = schema_object
.remove("allOf")
.unwrap_or_else(|| Value::Array(Vec::with_capacity(1)))
{
all_of_items.push(else_schema);
let _ = schema_object.insert("allOf".to_string(), Value::Array(all_of_items));
}
}
true
} else if is::true_schema(if_schema) {
// In case of a `true` schema we know that the `then` schema will never be considered
// so we can simplify the schema by ensuring that the `then` schema has to be verified
let _ = schema_object.remove("if");
let _ = schema_object.remove("else");
if let Some(else_schema) = schema_object.remove("then") {
if let Value::Array(mut all_of_items) = schema_object
.remove("allOf")
.unwrap_or_else(|| Value::Array(Vec::with_capacity(1)))
{
all_of_items.push(else_schema);
let _ = schema_object.insert("allOf".to_string(), Value::Array(all_of_items));
}
}
true
} else if !schema_object.contains_key("else") && !schema_object.contains_key("then") {
let _ = schema_object.remove("if");
true
} else {
false
}
} else {
false
}
}

#[cfg(test)]
mod tests {
use super::simplify_if;
use serde_json::{json, Value};
use test_case::test_case;

#[test_case(json!({}) => json!({}))]
#[test_case(json!({"if": false, "then": {"minLength": 0}, "else": {"maxLength": 0}}) => json!({"allOf": [{"maxLength": 0}]}))]
#[test_case(json!({"if": true, "then": {"minLength": 0}, "else": {"maxLength": 0}}) => json!({"allOf": [{"minLength": 0}]}))]
#[test_case(json!({"if": {"type": "string"}, "then": {"minLength": 0}, "else": {"maxLength": 0}}) => json!({"if": {"type": "string"}, "then": {"minLength": 0}, "else": {"maxLength": 0}}))]
#[test_case(json!({"if": false}) => json!({}))]
#[test_case(json!({"if": true}) => json!({}))]
#[test_case(json!({"if": {"type": "string"}}) => json!({}))]
fn test_simplify_if(mut value: Value) -> Value {
let _ = simplify_if(&mut value);
value
}
}
3 changes: 2 additions & 1 deletion src/keywords/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
mod additional_properties;
mod const_;
mod enum_;
mod if_;
mod macro_;
mod property_names;
mod required;
Expand All @@ -28,11 +29,11 @@ static UPDATE_SCHEMA_METHODS: &[fn(&mut Value) -> bool] = &[
additional_properties::remove_empty_additional_properties,
const_::simple_const_cleanup,
enum_::simple_enum_cleanup,
if_::simplify_if,
macro_::maximum_minimum_related_keywords::update_max_min_related_keywords,
property_names::optimise_property_names,
required::remove_empty_required,
type_::optimise_keyword_type,
type_::remove_extraneous_keys_keyword_type,
];

/// Perform the schema optimisaton without descending the schema
Expand Down
2 changes: 1 addition & 1 deletion tests/all_rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::str::FromStr;

/// This method does expose the one-liner pretty-print value of a given JSON value
/// Respect the default `Value::to_string` method this ensures that the separators (`:` and `,`) have a space after
/// NOTE: The code is far from being good looking or performing, but this is mostly used to esure that all_rules.md has
/// NOTE: The code is far from being good looking or performing, but this is mostly used to esure that `all_rules.md` has
/// considently formatted JSON fields
fn pretty_format_json_value(value: &Value) -> String {
value.to_string().replace(":", ": ").replace(",", ", ")
Expand Down

0 comments on commit 460baf2

Please sign in to comment.