diff --git a/DEPENDENCIES b/DEPENDENCIES index e6fcc6b1..2d7138b3 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -1,4 +1,4 @@ vendorpull https://github.com/sourcemeta/vendorpull dea311b5bfb53b6926a4140267959ae334d3ecf4 noa https://github.com/sourcemeta/noa 5ff4024902642afc9cc2f9a9e02ae9dff9d15d4f -jsontoolkit https://github.com/sourcemeta/jsontoolkit d6587f01cc6d31bdf3169690bbd18937dd5cfd65 +jsontoolkit https://github.com/sourcemeta/jsontoolkit 0f31b9576a2eb442c64b4005c9ae4b03dbbc7834 hydra https://github.com/sourcemeta/hydra 3c53d3fdef79e9ba603d48470a508cc45472a0dc diff --git a/vendor/jsontoolkit/src/jsonschema/bundle.cc b/vendor/jsontoolkit/src/jsonschema/bundle.cc index a910ecda..c67d5b13 100644 --- a/vendor/jsontoolkit/src/jsonschema/bundle.cc +++ b/vendor/jsontoolkit/src/jsonschema/bundle.cc @@ -75,7 +75,7 @@ auto upsert_id(sourcemeta::jsontoolkit::JSON &target, auto embed_schema(sourcemeta::jsontoolkit::JSON &definitions, const std::string &identifier, - sourcemeta::jsontoolkit::JSON &&target) -> void { + const sourcemeta::jsontoolkit::JSON &target) -> void { std::ostringstream key; key << identifier; // Ensure we get a definitions entry that does not exist @@ -83,7 +83,7 @@ auto embed_schema(sourcemeta::jsontoolkit::JSON &definitions, key << "/x"; } - definitions.assign(key.str(), std::move(target)); + definitions.assign(key.str(), target); } auto bundle_schema(sourcemeta::jsontoolkit::JSON &root, @@ -110,21 +110,20 @@ auto bundle_schema(sourcemeta::jsontoolkit::JSON &root, sourcemeta::jsontoolkit::JSON::make_object()); assert(reference.base.has_value()); - const auto remote{resolver(reference.base.value()).get()}; + const auto identifier{reference.base.value()}; + const auto remote{resolver(identifier).get()}; if (!remote.has_value()) { throw sourcemeta::jsontoolkit::SchemaResolutionError( reference.base.value(), "Could not resolve schema"); } - const auto identifier{reference.base.value()}; - // Otherwise, if the target schema does not declare an inline identifier, // references to that identifier from the outer schema won't resolve. sourcemeta::jsontoolkit::JSON copy{remote.value()}; upsert_id(copy, identifier, resolver, default_dialect); - embed_schema(root.at(container), identifier, std::move(copy)); - bundle_schema(root, container, remote.value(), frame, walker, resolver, + embed_schema(root.at(container), identifier, copy); + bundle_schema(root, container, copy, frame, walker, resolver, default_dialect); } } diff --git a/vendor/jsontoolkit/src/jsonschema/compile_describe.cc b/vendor/jsontoolkit/src/jsonschema/compile_describe.cc index d9170e9d..569ec733 100644 --- a/vendor/jsontoolkit/src/jsonschema/compile_describe.cc +++ b/vendor/jsontoolkit/src/jsonschema/compile_describe.cc @@ -70,6 +70,12 @@ struct DescribeVisitor { return "The target object is expected to define all of the given " "properties"; } + auto operator()(const SchemaCompilerAssertionType &) const -> std::string { + return "The target document is expected to be of the given type"; + } + auto operator()(const SchemaCompilerAssertionTypeAny &) const -> std::string { + return "The target document is expected to be of one of the given types"; + } auto operator()(const SchemaCompilerAssertionTypeStrict &) const -> std::string { return "The target document is expected to be of the given type"; diff --git a/vendor/jsontoolkit/src/jsonschema/compile_evaluate.cc b/vendor/jsontoolkit/src/jsonschema/compile_evaluate.cc index 87701eba..72fbf453 100644 --- a/vendor/jsontoolkit/src/jsonschema/compile_evaluate.cc +++ b/vendor/jsontoolkit/src/jsonschema/compile_evaluate.cc @@ -228,6 +228,28 @@ auto evaluate_step( break; } } + } else if (std::holds_alternative(step)) { + const auto &assertion{std::get(step)}; + context.push(assertion); + EVALUATE_CONDITION_GUARD(assertion.condition, instance); + const auto &value{context.resolve_value(assertion.value, instance)}; + const auto &target{ + context.resolve_target(assertion.target, instance)}; + // In non-strict mode, we consider a real number that represents an + // integer to be an integer + result = target.type() == value || + (value == JSON::Type::Integer && target.is_integer_real()); + } else if (std::holds_alternative(step)) { + const auto &assertion{std::get(step)}; + context.push(assertion); + EVALUATE_CONDITION_GUARD(assertion.condition, instance); + const auto &value{context.resolve_value(assertion.value, instance)}; + const auto &target{ + context.resolve_target(assertion.target, instance)}; + // In non-strict mode, we consider a real number that represents an + // integer to be an integer + result = value.contains(target.type()) || + (value.contains(JSON::Type::Integer) && target.is_integer_real()); } else if (std::holds_alternative(step)) { const auto &assertion{std::get(step)}; context.push(assertion); diff --git a/vendor/jsontoolkit/src/jsonschema/compile_json.cc b/vendor/jsontoolkit/src/jsonschema/compile_json.cc index 18fb032e..7afbe02e 100644 --- a/vendor/jsontoolkit/src/jsonschema/compile_json.cc +++ b/vendor/jsontoolkit/src/jsonschema/compile_json.cc @@ -178,6 +178,8 @@ struct StepVisitor { HANDLE_STEP("assertion", "fail", SchemaCompilerAssertionFail) HANDLE_STEP("assertion", "defines", SchemaCompilerAssertionDefines) HANDLE_STEP("assertion", "defines-all", SchemaCompilerAssertionDefinesAll) + HANDLE_STEP("assertion", "type", SchemaCompilerAssertionType) + HANDLE_STEP("assertion", "type-any", SchemaCompilerAssertionTypeAny) HANDLE_STEP("assertion", "type-strict", SchemaCompilerAssertionTypeStrict) HANDLE_STEP("assertion", "type-strict-any", SchemaCompilerAssertionTypeStrictAny) diff --git a/vendor/jsontoolkit/src/jsonschema/default_compiler.cc b/vendor/jsontoolkit/src/jsonschema/default_compiler.cc index c767da89..d86b7c6f 100644 --- a/vendor/jsontoolkit/src/jsonschema/default_compiler.cc +++ b/vendor/jsontoolkit/src/jsonschema/default_compiler.cc @@ -50,6 +50,8 @@ auto sourcemeta::jsontoolkit::default_schema_compiler( STOP_IF_SIBLING_KEYWORD("http://json-schema.org/draft-06/schema#", "$ref"); // Any + COMPILE("http://json-schema.org/draft-06/schema#", "type", + compiler_draft6_validation_type); COMPILE("http://json-schema.org/draft-06/schema#", "const", compiler_draft6_validation_const); @@ -69,8 +71,6 @@ auto sourcemeta::jsontoolkit::default_schema_compiler( // Same as Draft 4 - COMPILE("http://json-schema.org/draft-06/schema#", "type", - compiler_draft4_validation_type); COMPILE("http://json-schema.org/draft-06/schema#", "allOf", compiler_draft4_applicator_allof); COMPILE("http://json-schema.org/draft-06/schema#", "anyOf", diff --git a/vendor/jsontoolkit/src/jsonschema/default_compiler_draft6.h b/vendor/jsontoolkit/src/jsonschema/default_compiler_draft6.h index 3dfc5600..5f8e2cee 100644 --- a/vendor/jsontoolkit/src/jsonschema/default_compiler_draft6.h +++ b/vendor/jsontoolkit/src/jsonschema/default_compiler_draft6.h @@ -9,6 +9,98 @@ namespace internal { using namespace sourcemeta::jsontoolkit; +auto compiler_draft6_validation_type(const SchemaCompilerContext &context) + -> SchemaCompilerTemplate { + if (context.value.is_string()) { + const auto &type{context.value.to_string()}; + if (type == "null") { + return {make( + context, JSON::Type::Null, {}, SchemaCompilerTargetType::Instance)}; + } else if (type == "boolean") { + return {make( + context, JSON::Type::Boolean, {}, + SchemaCompilerTargetType::Instance)}; + } else if (type == "object") { + return {make( + context, JSON::Type::Object, {}, SchemaCompilerTargetType::Instance)}; + } else if (type == "array") { + return {make( + context, JSON::Type::Array, {}, SchemaCompilerTargetType::Instance)}; + } else if (type == "number") { + return {make( + context, std::set{JSON::Type::Real, JSON::Type::Integer}, + {}, SchemaCompilerTargetType::Instance)}; + } else if (type == "integer") { + return {make( + context, JSON::Type::Integer, {}, + SchemaCompilerTargetType::Instance)}; + } else if (type == "string") { + return {make( + context, JSON::Type::String, {}, SchemaCompilerTargetType::Instance)}; + } else { + return {}; + } + } else if (context.value.is_array() && context.value.size() == 1 && + context.value.front().is_string()) { + const auto &type{context.value.front().to_string()}; + if (type == "null") { + return {make( + context, JSON::Type::Null, {}, SchemaCompilerTargetType::Instance)}; + } else if (type == "boolean") { + return {make( + context, JSON::Type::Boolean, {}, + SchemaCompilerTargetType::Instance)}; + } else if (type == "object") { + return {make( + context, JSON::Type::Object, {}, SchemaCompilerTargetType::Instance)}; + } else if (type == "array") { + return {make( + context, JSON::Type::Array, {}, SchemaCompilerTargetType::Instance)}; + } else if (type == "number") { + return {make( + context, std::set{JSON::Type::Real, JSON::Type::Integer}, + {}, SchemaCompilerTargetType::Instance)}; + } else if (type == "integer") { + return {make( + context, JSON::Type::Integer, {}, + SchemaCompilerTargetType::Instance)}; + } else if (type == "string") { + return {make( + context, JSON::Type::String, {}, SchemaCompilerTargetType::Instance)}; + } else { + return {}; + } + } else if (context.value.is_array()) { + std::set types; + for (const auto &type : context.value.as_array()) { + assert(type.is_string()); + const auto &type_string{type.to_string()}; + if (type_string == "null") { + types.emplace(JSON::Type::Null); + } else if (type_string == "boolean") { + types.emplace(JSON::Type::Boolean); + } else if (type_string == "object") { + types.emplace(JSON::Type::Object); + } else if (type_string == "array") { + types.emplace(JSON::Type::Array); + } else if (type_string == "number") { + types.emplace(JSON::Type::Integer); + types.emplace(JSON::Type::Real); + } else if (type_string == "integer") { + types.emplace(JSON::Type::Integer); + } else if (type_string == "string") { + types.emplace(JSON::Type::String); + } + } + + assert(types.size() >= context.value.size()); + return {make( + context, std::move(types), {}, SchemaCompilerTargetType::Instance)}; + } + + return {}; +} + auto compiler_draft6_validation_const(const SchemaCompilerContext &context) -> SchemaCompilerTemplate { return {make( diff --git a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_compile.h b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_compile.h index 4837f91f..4dc6f25b 100644 --- a/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_compile.h +++ b/vendor/jsontoolkit/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_compile.h @@ -117,11 +117,21 @@ struct SchemaCompilerAssertionDefinesAll; /// @ingroup jsonschema /// Represents a compiler assertion step that checks if a document is of the /// given type -struct SchemaCompilerAssertionTypeStrict; +struct SchemaCompilerAssertionType; /// @ingroup jsonschema /// Represents a compiler assertion step that checks if a document is of any of /// the given types +struct SchemaCompilerAssertionTypeAny; + +/// @ingroup jsonschema +/// Represents a compiler assertion step that checks if a document is of the +/// given type (strict version) +struct SchemaCompilerAssertionTypeStrict; + +/// @ingroup jsonschema +/// Represents a compiler assertion step that checks if a document is of any of +/// the given types (strict version) struct SchemaCompilerAssertionTypeStrictAny; /// @ingroup jsonschema @@ -254,7 +264,8 @@ struct SchemaCompilerControlJump; /// Represents a schema compilation step that can be evaluated using SchemaCompilerTemplate = std::vector