diff --git a/config.cmake.in b/config.cmake.in index 68b732085..b65964553 100644 --- a/config.cmake.in +++ b/config.cmake.in @@ -75,9 +75,6 @@ foreach(component ${BLAZE_COMPONENTS}) elseif(component STREQUAL "canonicalizer") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_blaze_foundation.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_blaze_frame.cmake") - include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_blaze_evaluator.cmake") - include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_blaze_compiler.cmake") - include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_blaze_output.cmake") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_blaze_canonicalizer.cmake") elseif(component STREQUAL "editor") include("${CMAKE_CURRENT_LIST_DIR}/sourcemeta_blaze_foundation.cmake") diff --git a/src/canonicalizer/CMakeLists.txt b/src/canonicalizer/CMakeLists.txt index d2c6c79ae..7eb309db5 100644 --- a/src/canonicalizer/CMakeLists.txt +++ b/src/canonicalizer/CMakeLists.txt @@ -1,8 +1,8 @@ sourcemeta_library(NAMESPACE sourcemeta PROJECT blaze NAME canonicalizer FOLDER "Blaze/Canonicalizer" - SOURCES canonicalize.cc transformer.cc - canonicalizer_transformer.h - canonicalizer_error.h + SOURCES canonicalize.cc + rule.h + helpers.h # Rules rules/additional_items_implicit.h @@ -140,13 +140,5 @@ target_link_libraries(sourcemeta_blaze_canonicalizer PUBLIC sourcemeta::blaze::foundation) target_link_libraries(sourcemeta_blaze_canonicalizer PUBLIC sourcemeta::blaze::frame) -target_link_libraries(sourcemeta_blaze_canonicalizer PUBLIC - sourcemeta::blaze::compiler) -target_link_libraries(sourcemeta_blaze_canonicalizer PRIVATE - sourcemeta::blaze::evaluator) -target_link_libraries(sourcemeta_blaze_canonicalizer PRIVATE - sourcemeta::blaze::output) -target_link_libraries(sourcemeta_blaze_canonicalizer PRIVATE - sourcemeta::core::regex) target_link_libraries(sourcemeta_blaze_canonicalizer PRIVATE sourcemeta::core::uri) diff --git a/src/canonicalizer/canonicalize.cc b/src/canonicalizer/canonicalize.cc index 21aef13c8..95b425c48 100644 --- a/src/canonicalizer/canonicalize.cc +++ b/src/canonicalizer/canonicalize.cc @@ -1,103 +1,251 @@ #include - -#include -#include +#include #include -#include -#include -#include -#include "canonicalizer_transformer.h" +#include +#include +#include -// For built-in rules #include // std::sort, std::unique, std::ranges::none_of #include // std::array #include // std::popcount #include // assert #include // std::floor, std::ceil, std::isfinite +#include // std::derived_from #include // std::size_t -#include // std::ref -#include // std::back_inserter +#include // std::uint64_t +#include // std::hash, std::ref #include // std::numeric_limits -#include // std::unique_ptr, std::make_unique -#include // std::ostringstream +#include // std::make_unique, std::unique_ptr +#include // std::optional, std::nullopt +#include // std::string #include // std::string_view +#include // std::tuple +#include // std::is_same_v, std::true_type #include // std::unordered_map #include // std::unordered_set #include // std::move, std::to_underlying +#include // std::vector + +namespace sourcemeta::blaze { + +namespace { + +#include "rule.h" -namespace sourcemeta::blaze::canonicalizer { +using Rule = std::tuple, bool>; -using namespace sourcemeta::core; +/// Construct a rule entry for the given rule type +template T> +[[nodiscard]] auto make_rule() -> Rule { + return {std::make_unique(), + std::is_same_v}; +} -// TODO: Move upstream -inline auto IS_IN_PLACE_APPLICATOR(const SchemaKeywordType type) -> bool { - return type == SchemaKeywordType::ApplicatorValueOrElementsInPlace || - type == SchemaKeywordType::ApplicatorMembersInPlaceSome || - type == SchemaKeywordType::ApplicatorElementsInPlace || - type == SchemaKeywordType::ApplicatorElementsInPlaceSome || - type == SchemaKeywordType::ApplicatorElementsInPlaceSomeNegate || - type == SchemaKeywordType::ApplicatorValueInPlaceMaybe || - type == SchemaKeywordType::ApplicatorValueInPlaceOther || - type == SchemaKeywordType::ApplicatorValueInPlaceNegate; +/// Re-analyse the frame, honouring any identifier already present in the schema +auto analyse_frame(sourcemeta::blaze::SchemaFrame &target, + sourcemeta::core::JSON &schema, + const sourcemeta::blaze::SchemaWalker &walker, + const sourcemeta::blaze::SchemaResolver &resolver, + const std::string_view default_dialect, + const std::string_view default_id) -> void { + if (!blaze::identify(schema, resolver, default_dialect).empty()) { + target.analyse(schema, walker, resolver, default_dialect); + } else { + target.analyse(schema, walker, resolver, default_dialect, default_id); + } } -// Walk up from a schema location, continuing as long as the traversal -// predicate returns true for each keyword type encountered. Returns a -// reference to the pointer of the ancestor where the match callback returned -// true, or nullopt if no match was found or the traversal predicate stopped -// the walk. -template -auto WALK_UP(const JSON &root, const SchemaFrame &frame, - const SchemaFrame::Location &location, const SchemaWalker &walker, - const SchemaResolver &resolver, - const TraversePredicate &should_continue, - const MatchCallback &matches) - -> std::optional> { - auto current_pointer{location.pointer}; - auto current_parent{location.parent}; - - while (current_parent.has_value()) { - const auto &parent_pointer{current_parent.value()}; - const auto relative_pointer{current_pointer.resolve_from(parent_pointer)}; - assert(!relative_pointer.empty() && relative_pointer.at(0).is_property()); - const auto parent{frame.traverse(frame.uri(parent_pointer).value().get())}; - assert(parent.has_value()); - const auto parent_vocabularies{ - frame.vocabularies(parent.value().get(), resolver)}; - const auto keyword_type{ - walker(relative_pointer.at(0).to_property(), parent_vocabularies).type}; - - if (!should_continue(keyword_type)) { - return std::nullopt; +/// Apply the given rules top-down to every subschema until none of them applies +auto apply(const std::vector &rules, sourcemeta::core::JSON &schema, + const sourcemeta::blaze::SchemaWalker &walker, + const sourcemeta::blaze::SchemaResolver &resolver, + const std::string_view default_dialect = "", + const std::string_view default_id = "") -> void { + assert(!rules.empty()); + + struct ProcessedRuleHasher { + auto operator()(const std::tuple &value) const noexcept + -> std::size_t { + return core::Pointer::Hasher{}(std::get<0>(value)) ^ + (std::hash{}(std::get<1>(value)) << 1) ^ + (std::hash{}(std::get<2>(value).fast_hash()) << 2); } + }; + + std::unordered_set, + ProcessedRuleHasher> + processed_rules; - if (matches(get(root, parent_pointer), parent_vocabularies)) { - return std::cref(parent.value().get().pointer); + blaze::SchemaFrame frame{blaze::SchemaFrame::Mode::References}; + + struct PotentiallyBrokenReference { + core::Pointer origin; + core::JSON::String original; + core::JSON::String destination; + core::JSON::String fragment; + core::Pointer target_pointer; + std::size_t target_relative_pointer; + }; + + std::vector potentially_broken_references; + + while (true) { + if (frame.empty()) { + if (schema.is_boolean()) { + break; + } + + analyse_frame(frame, schema, walker, resolver, default_dialect, + default_id); } - current_pointer = parent_pointer; - current_parent = parent.value().get().parent; - } + std::unordered_set visited; + bool applied{false}; - return std::nullopt; -} + for (const auto &entry : frame.locations()) { + if (entry.second.type != blaze::SchemaFrame::LocationType::Resource && + entry.second.type != blaze::SchemaFrame::LocationType::Subschema) { + continue; + } -template -auto WALK_UP_IN_PLACE_APPLICATORS(const JSON &root, const SchemaFrame &frame, - const SchemaFrame::Location &location, - const SchemaWalker &walker, - const SchemaResolver &resolver, - const MatchCallback &matches) - -> std::optional> { - return WALK_UP(root, frame, location, walker, resolver, - IS_IN_PLACE_APPLICATOR, matches); -} + const auto [visited_iterator, inserted] = + visited.insert(core::to_pointer(entry.second.pointer)); + if (!inserted) { + continue; + } + const auto &entry_pointer{*visited_iterator}; + auto ¤t{core::get(schema, entry_pointer)}; + const auto current_vocabularies{ + frame.vocabularies(entry.second, resolver)}; + + for (const auto &[rule, reframe_after_transform] : rules) { + const auto outcome{rule->condition(current, schema, + current_vocabularies, frame, + entry.second, walker, resolver)}; + + if (!outcome) { + continue; + } + + potentially_broken_references.clear(); + for (const auto &reference : frame.references()) { + const auto destination{frame.traverse(reference.second.destination)}; + if (!destination.has_value() || + !reference.second.fragment.has_value() || + !reference.second.fragment.value().starts_with('/')) { + continue; + } + + const auto &target{destination.value().get()}; + potentially_broken_references.push_back( + {.origin = core::to_pointer(reference.first.second), + .original = core::JSON::String{reference.second.original}, + .destination = reference.second.destination, + .fragment = + core::JSON::String{reference.second.fragment.value()}, + .target_pointer = core::to_pointer(target.pointer), + .target_relative_pointer = target.relative_pointer}); + } + + rule->transform(current); -#define ONLY_CONTINUE_IF(condition) \ - if (!(condition)) { \ - return false; \ + applied = true; + + if (reframe_after_transform) { + analyse_frame(frame, schema, walker, resolver, default_dialect, + default_id); + } else if (current.is_boolean()) { + std::tuple mark{ + entry_pointer, rule->name(), current}; + assert(!processed_rules.contains(mark)); + processed_rules.emplace(std::move(mark)); + frame.reset(); + goto blaze_transformer_start_again; + } + + const auto new_location{ + frame.traverse(core::to_weak_pointer(entry_pointer))}; + assert(new_location.has_value()); + + // Fix broken references before re-checking the condition, + // as the re-check may mutate rule state that rereference needs + bool references_fixed{false}; + const auto resource_offset{new_location.value().get().relative_pointer}; + const auto current_slice{entry_pointer.slice(resource_offset)}; + for (const auto &saved_reference : potentially_broken_references) { + if (core::try_get(schema, saved_reference.target_pointer)) { + continue; + } + + // If the origin was also relocated, resolve its new location + auto effective_origin{saved_reference.origin}; + if (!core::try_get(schema, saved_reference.origin.initial())) { + const auto new_origin{rule->rereference( + saved_reference.destination, saved_reference.origin, + saved_reference.origin.slice(resource_offset), current_slice)}; + if (!new_origin.has_value()) { + continue; + } + effective_origin = saved_reference.origin.slice(0, resource_offset) + .concat(new_origin.value()); + if (!core::try_get(schema, effective_origin.initial())) { + continue; + } + } + + const auto new_relative{rule->rereference( + saved_reference.destination, saved_reference.origin, + saved_reference.target_pointer.slice( + saved_reference.target_relative_pointer), + current_slice)}; + if (!new_relative.has_value()) { + continue; + } + const auto new_fragment{ + saved_reference.fragment == + core::to_string(saved_reference.target_pointer) + ? saved_reference.target_pointer + .slice(0, saved_reference.target_relative_pointer) + .concat(new_relative.value()) + : new_relative.value()}; + + core::URI original{saved_reference.original}; + original.fragment(core::to_string(new_fragment)); + core::set(schema, effective_origin, core::JSON{original.recompose()}); + references_fixed = true; + } + + const auto new_vocabularies{ + frame.vocabularies(new_location.value().get(), resolver)}; + + assert(!rule->condition(current, schema, new_vocabularies, frame, + new_location.value().get(), walker, resolver)); + + std::tuple mark{ + entry_pointer, rule->name(), current}; + assert(!processed_rules.contains(mark)); + processed_rules.emplace(std::move(mark)); + + if (references_fixed) { + frame.reset(); + } + + if (references_fixed || reframe_after_transform) { + goto blaze_transformer_start_again; + } + } + } + + blaze_transformer_start_again: + if (!applied) { + break; + } } +} + +#include "helpers.h" #include "rules/additional_items_implicit.h" #include "rules/allof_false_simplify.h" @@ -227,155 +375,141 @@ auto WALK_UP_IN_PLACE_APPLICATORS(const JSON &root, const SchemaFrame &frame, #undef ONLY_CONTINUE_IF -namespace { - -auto add_canonicalizer_rules( - sourcemeta::blaze::canonicalizer::SchemaTransformer &bundle) -> void { - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); - bundle.add(); -} - } // namespace -} // namespace sourcemeta::blaze::canonicalizer - -namespace sourcemeta::blaze { - auto canonicalize(sourcemeta::core::JSON &schema, const sourcemeta::blaze::SchemaWalker &walker, const sourcemeta::blaze::SchemaResolver &resolver, const std::string_view default_dialect, const std::string_view default_id) -> void { - sourcemeta::blaze::canonicalizer::SchemaTransformer bundle; - sourcemeta::blaze::canonicalizer::add_canonicalizer_rules(bundle); - bundle.apply( - schema, walker, resolver, - [](const auto &, const auto &, const auto &, const auto &, - const auto &) -> void {}, - default_dialect, default_id); + std::vector rules; + rules.reserve(125); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + rules.push_back(make_rule()); + apply(rules, schema, walker, resolver, default_dialect, default_id); } } // namespace sourcemeta::blaze diff --git a/src/canonicalizer/canonicalizer_error.h b/src/canonicalizer/canonicalizer_error.h deleted file mode 100644 index 7172a413e..000000000 --- a/src/canonicalizer/canonicalizer_error.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef SOURCEMETA_BLAZE_CANONICALIZER_ERROR_H_ -#define SOURCEMETA_BLAZE_CANONICALIZER_ERROR_H_ - -#ifndef SOURCEMETA_BLAZE_CANONICALIZER_EXPORT -#include -#endif - -#include - -#include // std::exception -#include // std::string -#include // std::string_view -#include // std::move - -namespace sourcemeta::blaze::canonicalizer { - -// Exporting symbols that depends on the standard C++ library is considered -// safe. -// https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4275?view=msvc-170&redirectedfrom=MSDN -#if defined(_MSC_VER) -#pragma warning(disable : 4251 4275) -#endif - -/// @ingroup canonicalizer -/// An error that represents a broken schema reference after transformation -class SOURCEMETA_BLAZE_CANONICALIZER_EXPORT SchemaBrokenReferenceError - : public std::exception { -public: - SchemaBrokenReferenceError(const std::string_view identifier, - sourcemeta::core::Pointer schema_location, - const char *message) - : identifier_{identifier}, schema_location_{std::move(schema_location)}, - message_{message} {} - - [[nodiscard]] auto what() const noexcept -> const char * override { - return this->message_; - } - - [[nodiscard]] auto identifier() const noexcept -> std::string_view { - return this->identifier_; - } - - [[nodiscard]] auto location() const noexcept - -> const sourcemeta::core::Pointer & { - return this->schema_location_; - } - -private: - std::string identifier_; - sourcemeta::core::Pointer schema_location_; - const char *message_; -}; - -/// @ingroup canonicalizer -/// An error that signifies that a transform rule was applied more than once -class SOURCEMETA_BLAZE_CANONICALIZER_EXPORT - SchemaTransformRuleProcessedTwiceError : public std::exception { -public: - SchemaTransformRuleProcessedTwiceError(const std::string_view name, - sourcemeta::core::Pointer location) - : name_{name}, location_{std::move(location)} {} - - [[nodiscard]] auto what() const noexcept -> const char * override { - return "Transformation rules must only be processed once"; - } - - [[nodiscard]] auto name() const noexcept -> std::string_view { - return this->name_; - } - - [[nodiscard]] auto location() const noexcept - -> const sourcemeta::core::Pointer & { - return this->location_; - } - -private: - std::string name_; - sourcemeta::core::Pointer location_; -}; - -#if defined(_MSC_VER) -#pragma warning(default : 4251 4275) -#endif - -} // namespace sourcemeta::blaze::canonicalizer - -#endif diff --git a/src/canonicalizer/canonicalizer_transformer.h b/src/canonicalizer/canonicalizer_transformer.h deleted file mode 100644 index 2dd898760..000000000 --- a/src/canonicalizer/canonicalizer_transformer.h +++ /dev/null @@ -1,164 +0,0 @@ -#ifndef SOURCEMETA_BLAZE_CANONICALIZER_TRANSFORMER_H_ -#define SOURCEMETA_BLAZE_CANONICALIZER_TRANSFORMER_H_ - -#ifndef SOURCEMETA_BLAZE_CANONICALIZER_EXPORT -#include -#endif - -#include -#include -#include -#include - -#include // std::derived_from -#include // std::function -#include // std::make_unique, std::unique_ptr -#include // std::string -#include // std::string_view -#include // std::tuple -#include // std::is_same_v, std::true_type -#include // std::move, std::forward -#include // std::vector - -namespace sourcemeta::blaze::canonicalizer { - -/// @ingroup canonicalizer -/// -/// A class that represents a transformation rule. Clients of this class -/// are expected to subclass and implement their own condition and -/// transformation methods. -class SOURCEMETA_BLAZE_CANONICALIZER_EXPORT SchemaTransformRule { -public: - SchemaTransformRule(const std::string_view name, - const std::string_view message); - - virtual ~SchemaTransformRule() = default; - - SchemaTransformRule(const SchemaTransformRule &) = delete; - SchemaTransformRule(SchemaTransformRule &&) = delete; - auto operator=(const SchemaTransformRule &) -> SchemaTransformRule & = delete; - auto operator=(SchemaTransformRule &&) -> SchemaTransformRule & = delete; - - /// Compare a rule against another rule - auto operator==(const SchemaTransformRule &other) const -> bool; - - /// Fetch the name of a rule - [[nodiscard]] auto name() const noexcept -> std::string_view; - - /// Fetch the message of a rule - [[nodiscard]] auto message() const noexcept -> std::string_view; - - /// The result of evaluating a rule - using Result = bool; - - /// Check if the rule applies to a schema - [[nodiscard]] auto - check(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &root, - const sourcemeta::blaze::Vocabularies &vocabularies, - const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &resolver, - const sourcemeta::blaze::SchemaFrame &frame, - const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::core::JSON::String &exclude_keyword, - const bool is_metaschema) const -> Result; - - /// A method to optionally fix any reference location that was affected by the - /// transformation - [[nodiscard]] virtual auto - rereference(const std::string_view reference, - const sourcemeta::core::Pointer &origin, - const sourcemeta::core::Pointer &target, - const sourcemeta::core::Pointer ¤t) const - -> sourcemeta::core::Pointer; - - /// The rule condition - [[nodiscard]] virtual auto - condition(const sourcemeta::core::JSON &schema, - const sourcemeta::core::JSON &root, - const sourcemeta::blaze::Vocabularies &vocabularies, - const sourcemeta::blaze::SchemaFrame &frame, - const sourcemeta::blaze::SchemaFrame::Location &location, - const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &resolver, - const bool is_metaschema) const -> Result = 0; - - /// The rule transformation. If this virtual method is not overriden, - /// then the rule is considered to not mutate the schema - virtual auto transform(sourcemeta::core::JSON &schema, - const Result &result) const -> void = 0; - -private: -// Exporting symbols that depends on the standard C++ library is considered -// safe. -// https://learn.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-2-c4275?view=msvc-170&redirectedfrom=MSDN -#if defined(_MSC_VER) -#pragma warning(disable : 4251) -#endif - const std::string name_{}; - const std::string message_{}; -#if defined(_MSC_VER) -#pragma warning(default : 4251) -#endif -}; - -/// @ingroup canonicalizer -/// -/// You can use this class to perform top-down transformations on subschemas -/// given a set of rules. Every registered rule is applied to every subschema -/// of the passed schema until no longer of them applies. -class SOURCEMETA_BLAZE_CANONICALIZER_EXPORT SchemaTransformer { -public: - SchemaTransformer() = default; - -#if !defined(DOXYGEN) - SchemaTransformer(const SchemaTransformer &) = delete; - auto operator=(const SchemaTransformer &) -> SchemaTransformer & = delete; - SchemaTransformer(SchemaTransformer &&) = default; - auto operator=(SchemaTransformer &&) -> SchemaTransformer & = default; -#endif - - /// Add a rule to the bundle. Rules are evaluated in the order they are added. - /// It is the caller's responsibility to not add duplicate rules. - template T, typename... Args> - auto add(Args &&...args) -> std::string_view { - static_assert(requires { typename T::mutates; }); - static_assert(requires { typename T::reframe_after_transform; }); - static_assert( - std::is_same_v || - std::is_same_v); - auto &entry{this->rules.emplace_back( - std::make_unique(std::forward(args)...), - std::is_same_v, - std::is_same_v)}; - return std::get<0>(entry)->name(); - } - - /// The callback that is called whenever the condition of a rule holds true - using Callback = std::function; - - /// Apply the bundle of rules to a schema - auto apply(sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &resolver, - const Callback &callback, std::string_view default_dialect = "", - std::string_view default_id = "", - const sourcemeta::core::JSON::String &exclude_keyword = "", - const bool is_metaschema = false) const -> void; - -private: -#if defined(_MSC_VER) -#pragma warning(disable : 4251) -#endif - std::vector, bool, bool>> - rules; -#if defined(_MSC_VER) -#pragma warning(default : 4251) -#endif -}; - -} // namespace sourcemeta::blaze::canonicalizer - -#endif diff --git a/src/canonicalizer/helpers.h b/src/canonicalizer/helpers.h new file mode 100644 index 000000000..d31752a95 --- /dev/null +++ b/src/canonicalizer/helpers.h @@ -0,0 +1,77 @@ +#ifndef SOURCEMETA_BLAZE_CANONICALIZER_HELPERS_H_ +#define SOURCEMETA_BLAZE_CANONICALIZER_HELPERS_H_ + +// TODO: Move upstream +inline auto IS_IN_PLACE_APPLICATOR(const SchemaKeywordType type) -> bool { + return type == SchemaKeywordType::ApplicatorValueOrElementsInPlace || + type == SchemaKeywordType::ApplicatorMembersInPlaceSome || + type == SchemaKeywordType::ApplicatorElementsInPlace || + type == SchemaKeywordType::ApplicatorElementsInPlaceSome || + type == SchemaKeywordType::ApplicatorElementsInPlaceSomeNegate || + type == SchemaKeywordType::ApplicatorValueInPlaceMaybe || + type == SchemaKeywordType::ApplicatorValueInPlaceOther || + type == SchemaKeywordType::ApplicatorValueInPlaceNegate; +} + +// Walk up from a schema location, continuing as long as the traversal +// predicate returns true for each keyword type encountered. Returns a +// reference to the pointer of the ancestor where the match callback returned +// true, or nullopt if no match was found or the traversal predicate stopped +// the walk. +template +auto WALK_UP(const sourcemeta::core::JSON &root, const SchemaFrame &frame, + const SchemaFrame::Location &location, const SchemaWalker &walker, + const SchemaResolver &resolver, + const TraversePredicate &should_continue, + const MatchCallback &matches) + -> std::optional< + std::reference_wrapper> { + auto current_pointer{location.pointer}; + auto current_parent{location.parent}; + + while (current_parent.has_value()) { + const auto &parent_pointer{current_parent.value()}; + const auto relative_pointer{current_pointer.resolve_from(parent_pointer)}; + assert(!relative_pointer.empty() && relative_pointer.at(0).is_property()); + const auto parent{frame.traverse(frame.uri(parent_pointer).value().get())}; + assert(parent.has_value()); + const auto parent_vocabularies{ + frame.vocabularies(parent.value().get(), resolver)}; + const auto keyword_type{ + walker(relative_pointer.at(0).to_property(), parent_vocabularies).type}; + + if (!should_continue(keyword_type)) { + return std::nullopt; + } + + if (matches(sourcemeta::core::get(root, parent_pointer), + parent_vocabularies)) { + return std::cref(parent.value().get().pointer); + } + + current_pointer = parent_pointer; + current_parent = parent.value().get().parent; + } + + return std::nullopt; +} + +template +auto WALK_UP_IN_PLACE_APPLICATORS(const sourcemeta::core::JSON &root, + const SchemaFrame &frame, + const SchemaFrame::Location &location, + const SchemaWalker &walker, + const SchemaResolver &resolver, + const MatchCallback &matches) + -> std::optional< + std::reference_wrapper> { + return WALK_UP(root, frame, location, walker, resolver, + IS_IN_PLACE_APPLICATOR, matches); +} + +#define ONLY_CONTINUE_IF(condition) \ + if (!(condition)) { \ + return false; \ + } + +#endif diff --git a/src/canonicalizer/rule.h b/src/canonicalizer/rule.h new file mode 100644 index 000000000..ba9edc34d --- /dev/null +++ b/src/canonicalizer/rule.h @@ -0,0 +1,43 @@ +#ifndef SOURCEMETA_BLAZE_CANONICALIZER_RULE_H_ +#define SOURCEMETA_BLAZE_CANONICALIZER_RULE_H_ + +class SchemaTransformRule { +public: + SchemaTransformRule(const std::string_view name) : name_{name} {} + + virtual ~SchemaTransformRule() = default; + + SchemaTransformRule(const SchemaTransformRule &) = delete; + SchemaTransformRule(SchemaTransformRule &&) = delete; + auto operator=(const SchemaTransformRule &) -> SchemaTransformRule & = delete; + auto operator=(SchemaTransformRule &&) -> SchemaTransformRule & = delete; + + [[nodiscard]] auto name() const noexcept -> std::string_view { + return this->name_; + } + + /// A method to optionally fix any reference location that was affected by the + /// transformation + [[nodiscard]] virtual auto + rereference(const std::string_view, const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &) const + -> std::optional { + return std::nullopt; + } + + [[nodiscard]] virtual auto condition( + const sourcemeta::core::JSON &schema, const sourcemeta::core::JSON &root, + const sourcemeta::blaze::Vocabularies &vocabularies, + const sourcemeta::blaze::SchemaFrame &frame, + const sourcemeta::blaze::SchemaFrame::Location &location, + const sourcemeta::blaze::SchemaWalker &walker, + const sourcemeta::blaze::SchemaResolver &resolver) const -> bool = 0; + + virtual auto transform(sourcemeta::core::JSON &schema) const -> void = 0; + +private: + const std::string name_{}; +}; + +#endif diff --git a/src/canonicalizer/rules/additional_items_implicit.h b/src/canonicalizer/rules/additional_items_implicit.h index 9badd20a7..824ab36eb 100644 --- a/src/canonicalizer/rules/additional_items_implicit.h +++ b/src/canonicalizer/rules/additional_items_implicit.h @@ -1,9 +1,8 @@ class AdditionalItemsImplicit final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; AdditionalItemsImplicit() - : SchemaTransformRule{"additional_items_implicit", ""} {}; + : SchemaTransformRule{"additional_items_implicit"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class AdditionalItemsImplicit final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_4, @@ -31,7 +29,7 @@ class AdditionalItemsImplicit final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.assign("additionalItems", this->is_draft3_ ? sourcemeta::core::JSON::make_object() : sourcemeta::core::JSON{true}); diff --git a/src/canonicalizer/rules/allof_false_simplify.h b/src/canonicalizer/rules/allof_false_simplify.h index 2fd3830e2..6ee154c8e 100644 --- a/src/canonicalizer/rules/allof_false_simplify.h +++ b/src/canonicalizer/rules/allof_false_simplify.h @@ -1,11 +1,7 @@ class AllOfFalseSimplify final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - AllOfFalseSimplify() - : SchemaTransformRule{"allof_false_simplify", - "When `allOf` contains a `false` branch, the " - "schema is unsatisfiable"} {}; + AllOfFalseSimplify() : SchemaTransformRule{"allof_false_simplify"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,9 +10,8 @@ class AllOfFalseSimplify final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"allOf"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"allOf"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -31,7 +26,8 @@ class AllOfFalseSimplify final : public SchemaTransformRule { const auto &entry{all_of->at(index)}; if (entry.is_boolean() && !entry.to_boolean()) { ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); return true; } } @@ -39,8 +35,8 @@ class AllOfFalseSimplify final : public SchemaTransformRule { return false; } - auto transform(JSON &schema, const Result &) const -> void override { - schema.at("allOf").into(JSON{true}); + auto transform(sourcemeta::core::JSON &schema) const -> void override { + schema.at("allOf").into(sourcemeta::core::JSON{true}); schema.rename("allOf", "not"); } }; diff --git a/src/canonicalizer/rules/allof_merge_compatible_branches.h b/src/canonicalizer/rules/allof_merge_compatible_branches.h index 2912f1e86..fd7fc1d59 100644 --- a/src/canonicalizer/rules/allof_merge_compatible_branches.h +++ b/src/canonicalizer/rules/allof_merge_compatible_branches.h @@ -1,9 +1,8 @@ class AllOfMergeCompatibleBranches final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; AllOfMergeCompatibleBranches() - : SchemaTransformRule{"allof_merge_compatible_branches", ""} {}; + : SchemaTransformRule{"allof_merge_compatible_branches"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,9 +11,8 @@ class AllOfMergeCompatibleBranches final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"allOf"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"allOf"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -27,7 +25,8 @@ class AllOfMergeCompatibleBranches final : public SchemaTransformRule { ONLY_CONTINUE_IF(all_of && all_of->is_array() && all_of->size() >= 2); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); const auto &branches{*all_of}; @@ -72,8 +71,8 @@ class AllOfMergeCompatibleBranches final : public SchemaTransformRule { return false; } - auto transform(JSON &schema, const Result &) const -> void override { - static const JSON::String KEYWORD{"allOf"}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + static const sourcemeta::core::JSON::String KEYWORD{"allOf"}; auto &target{schema.at(KEYWORD).at(this->merge_into_)}; const auto &source{schema.at(KEYWORD).at(this->merge_from_)}; target.merge(source.as_object()); @@ -82,11 +81,12 @@ class AllOfMergeCompatibleBranches final : public SchemaTransformRule { static_cast(this->merge_from_))); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { - static const JSON::String KEYWORD{"allOf"}; + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { + static const sourcemeta::core::JSON::String KEYWORD{"allOf"}; const auto relative{target.resolve_from(current)}; if (relative.size() < 2 || !relative.at(0).is_property() || relative.at(0).to_property() != KEYWORD || !relative.at(1).is_index()) { @@ -95,16 +95,18 @@ class AllOfMergeCompatibleBranches final : public SchemaTransformRule { const auto index{relative.at(1).to_index()}; if (index == this->merge_from_) { - const Pointer old_prefix{ - current.concat(Pointer{KEYWORD, this->merge_from_})}; - const Pointer new_prefix{ - current.concat(Pointer{KEYWORD, this->merge_into_})}; + const sourcemeta::core::Pointer old_prefix{current.concat( + sourcemeta::core::Pointer{KEYWORD, this->merge_from_})}; + const sourcemeta::core::Pointer new_prefix{current.concat( + sourcemeta::core::Pointer{KEYWORD, this->merge_into_})}; return target.rebase(old_prefix, new_prefix); } if (index > this->merge_from_) { - const Pointer old_prefix{current.concat(Pointer{KEYWORD, index})}; - const Pointer new_prefix{current.concat(Pointer{KEYWORD, index - 1})}; + const sourcemeta::core::Pointer old_prefix{ + current.concat(sourcemeta::core::Pointer{KEYWORD, index})}; + const sourcemeta::core::Pointer new_prefix{ + current.concat(sourcemeta::core::Pointer{KEYWORD, index - 1})}; return target.rebase(old_prefix, new_prefix); } @@ -112,17 +114,20 @@ class AllOfMergeCompatibleBranches final : public SchemaTransformRule { } private: - static auto is_type_only_branch(const JSON &branch) -> bool { + static auto is_type_only_branch(const sourcemeta::core::JSON &branch) + -> bool { return branch.size() == 1 && branch.defines("type"); } - static auto has_in_place_applicators(const JSON &branch) -> bool { + static auto has_in_place_applicators(const sourcemeta::core::JSON &branch) + -> bool { return branch.defines("anyOf") || branch.defines("oneOf") || branch.defines("allOf") || branch.defines("not") || branch.defines("if"); } - static auto is_mergeable_branch(const JSON &branch) -> bool { + static auto is_mergeable_branch(const sourcemeta::core::JSON &branch) + -> bool { if (!branch.is_object()) { return false; } @@ -133,8 +138,9 @@ class AllOfMergeCompatibleBranches final : public SchemaTransformRule { !branch.defines("$recursiveAnchor"); } - static auto has_overlapping_keywords(const JSON &branch_a, - const JSON &branch_b) -> bool { + static auto has_overlapping_keywords(const sourcemeta::core::JSON &branch_a, + const sourcemeta::core::JSON &branch_b) + -> bool { for (const auto &entry : branch_a.as_object()) { if (branch_b.defines(entry.first)) { return true; @@ -144,14 +150,15 @@ class AllOfMergeCompatibleBranches final : public SchemaTransformRule { } static auto - has_cross_dependencies(const JSON &branch_a, const JSON &branch_b, + has_cross_dependencies(const sourcemeta::core::JSON &branch_a, + const sourcemeta::core::JSON &branch_b, const sourcemeta::blaze::SchemaWalker &walker, const sourcemeta::blaze::Vocabularies &vocabularies) -> bool { for (const auto &entry_a : branch_a.as_object()) { const auto &metadata{walker(entry_a.first, vocabularies)}; for (const auto &dependency : metadata.dependencies) { - if (branch_b.defines(JSON::String{dependency})) { + if (branch_b.defines(sourcemeta::core::JSON::String{dependency})) { return true; } } @@ -160,7 +167,7 @@ class AllOfMergeCompatibleBranches final : public SchemaTransformRule { for (const auto &entry_b : branch_b.as_object()) { const auto &metadata{walker(entry_b.first, vocabularies)}; for (const auto &dependency : metadata.dependencies) { - if (branch_a.defines(JSON::String{dependency})) { + if (branch_a.defines(sourcemeta::core::JSON::String{dependency})) { return true; } } diff --git a/src/canonicalizer/rules/anyof_false_simplify.h b/src/canonicalizer/rules/anyof_false_simplify.h index 1ce5bd6cf..c7c117a3f 100644 --- a/src/canonicalizer/rules/anyof_false_simplify.h +++ b/src/canonicalizer/rules/anyof_false_simplify.h @@ -1,11 +1,7 @@ class AnyOfFalseSimplify final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - AnyOfFalseSimplify() - : SchemaTransformRule{"anyof_false_simplify", - "An `anyOf` of a single `false` branch is " - "unsatisfiable"} {}; + AnyOfFalseSimplify() : SchemaTransformRule{"anyof_false_simplify"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,9 +10,8 @@ class AnyOfFalseSimplify final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"anyOf"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"anyOf"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -30,12 +25,13 @@ class AnyOfFalseSimplify final : public SchemaTransformRule { const auto &entry{any_of->front()}; ONLY_CONTINUE_IF(entry.is_boolean() && !entry.to_boolean()); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); return true; } - auto transform(JSON &schema, const Result &) const -> void override { - schema.at("anyOf").into(JSON{true}); + auto transform(sourcemeta::core::JSON &schema) const -> void override { + schema.at("anyOf").into(sourcemeta::core::JSON{true}); schema.rename("anyOf", "not"); } }; diff --git a/src/canonicalizer/rules/anyof_remove_false_schemas.h b/src/canonicalizer/rules/anyof_remove_false_schemas.h index 4b98140a8..129df3577 100644 --- a/src/canonicalizer/rules/anyof_remove_false_schemas.h +++ b/src/canonicalizer/rules/anyof_remove_false_schemas.h @@ -1,12 +1,8 @@ class AnyOfRemoveFalseSchemas final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; AnyOfRemoveFalseSchemas() - : SchemaTransformRule{ - "anyof_remove_false_schemas", - "The boolean schema `false` is guaranteed to never match in " - "`anyOf`, as it is sufficient for any other branch to match"} {}; + : SchemaTransformRule{"anyof_remove_false_schemas"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,27 +11,28 @@ class AnyOfRemoveFalseSchemas final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"anyOf"}; - ONLY_CONTINUE_IF(vocabularies.contains_any( - {Vocabularies::Known::JSON_Schema_2020_12_Applicator, - Vocabularies::Known::JSON_Schema_2019_09_Applicator, - Vocabularies::Known::JSON_Schema_Draft_7, - Vocabularies::Known::JSON_Schema_Draft_6}) && - schema.is_object() && schema.defines(KEYWORD) && - schema.at(KEYWORD).is_array() && - schema.at(KEYWORD).contains(JSON{false})); + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"anyOf"}; + ONLY_CONTINUE_IF( + vocabularies.contains_any( + {Vocabularies::Known::JSON_Schema_2020_12_Applicator, + Vocabularies::Known::JSON_Schema_2019_09_Applicator, + Vocabularies::Known::JSON_Schema_Draft_7, + Vocabularies::Known::JSON_Schema_Draft_6}) && + schema.is_object() && schema.defines(KEYWORD) && + schema.at(KEYWORD).is_array() && + schema.at(KEYWORD).contains(sourcemeta::core::JSON{false})); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); - std::vector false_locations; + std::vector false_locations; bool has_non_false{false}; const auto &anyof{schema.at(KEYWORD)}; for (std::size_t index = 0; index < anyof.size(); ++index) { const auto &entry{anyof.at(index)}; if (entry.is_boolean() && !entry.to_boolean()) { - false_locations.push_back(Pointer{KEYWORD, index}); + false_locations.push_back(sourcemeta::core::Pointer{KEYWORD, index}); } else { has_non_false = true; } @@ -46,15 +43,15 @@ class AnyOfRemoveFalseSchemas final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - static const JSON::String KEYWORD{"anyOf"}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + static const sourcemeta::core::JSON::String KEYWORD{"anyOf"}; std::unordered_set indices_to_remove; for (const auto &location : this->locations_) { indices_to_remove.insert(location.at(1).to_index()); } - auto new_anyof{JSON::make_array()}; + auto new_anyof{sourcemeta::core::JSON::make_array()}; const auto &anyof{schema.at(KEYWORD)}; for (std::size_t index = 0; index < anyof.size(); ++index) { if (!indices_to_remove.contains(index)) { diff --git a/src/canonicalizer/rules/anyof_true_simplify.h b/src/canonicalizer/rules/anyof_true_simplify.h index 910f26488..ee92e734c 100644 --- a/src/canonicalizer/rules/anyof_true_simplify.h +++ b/src/canonicalizer/rules/anyof_true_simplify.h @@ -1,11 +1,7 @@ class AnyOfTrueSimplify final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - AnyOfTrueSimplify() - : SchemaTransformRule{ - "anyof_true_simplify", - "An `anyOf` with a `true` or `{}` branch always succeeds"} {}; + AnyOfTrueSimplify() : SchemaTransformRule{"anyof_true_simplify"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,9 +10,8 @@ class AnyOfTrueSimplify final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"anyOf"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"anyOf"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -58,7 +53,8 @@ class AnyOfTrueSimplify final : public SchemaTransformRule { if ((entry.is_boolean() && entry.to_boolean()) || (entry.is_object() && entry.empty())) { ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); return true; } } @@ -66,7 +62,7 @@ class AnyOfTrueSimplify final : public SchemaTransformRule { return false; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("anyOf"); } }; diff --git a/src/canonicalizer/rules/comment_drop.h b/src/canonicalizer/rules/comment_drop.h index 713eca547..bfe3c2d10 100644 --- a/src/canonicalizer/rules/comment_drop.h +++ b/src/canonicalizer/rules/comment_drop.h @@ -1,8 +1,7 @@ class CommentDrop final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - CommentDrop() : SchemaTransformRule{"comment_drop", ""} {}; + CommentDrop() : SchemaTransformRule{"comment_drop"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class CommentDrop final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_7, Vocabularies::Known::JSON_Schema_2019_09_Core, @@ -21,7 +19,7 @@ class CommentDrop final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("$comment"); } }; diff --git a/src/canonicalizer/rules/const_as_enum.h b/src/canonicalizer/rules/const_as_enum.h index 7fab593d4..d1fea3c82 100644 --- a/src/canonicalizer/rules/const_as_enum.h +++ b/src/canonicalizer/rules/const_as_enum.h @@ -1,11 +1,7 @@ class ConstAsEnum final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - ConstAsEnum() - : SchemaTransformRule{"const_as_enum", - "Setting `const` is syntax sugar for an " - "enumeration of a single value"} {}; + ConstAsEnum() : SchemaTransformRule{"const_as_enum"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,8 +10,7 @@ class ConstAsEnum final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -26,7 +21,7 @@ class ConstAsEnum final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto values = sourcemeta::core::JSON::make_array(); values.push_back(schema.at("const")); schema.at("const").into(std::move(values)); diff --git a/src/canonicalizer/rules/const_in_enum.h b/src/canonicalizer/rules/const_in_enum.h index 8e9bc5deb..eaffe08f6 100644 --- a/src/canonicalizer/rules/const_in_enum.h +++ b/src/canonicalizer/rules/const_in_enum.h @@ -1,12 +1,7 @@ class ConstInEnum final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - ConstInEnum() - : SchemaTransformRule{ - "const_in_enum", - "If the `const` and `enum` keyword overlap, then `enum` is " - "redundant and can be removed"} {}; + ConstInEnum() : SchemaTransformRule{"const_in_enum"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +10,7 @@ class ConstInEnum final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -32,7 +26,7 @@ class ConstInEnum final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("enum"); } }; diff --git a/src/canonicalizer/rules/const_with_type.h b/src/canonicalizer/rules/const_with_type.h index 37afdc7b7..5428247dd 100644 --- a/src/canonicalizer/rules/const_with_type.h +++ b/src/canonicalizer/rules/const_with_type.h @@ -1,12 +1,7 @@ class ConstWithType final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - ConstWithType() - : SchemaTransformRule{ - "const_with_type", - "Setting `type` alongside `const` is considered an anti-pattern, " - "as the constant already implies its respective type"} {}; + ConstWithType() : SchemaTransformRule{"const_with_type"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +10,7 @@ class ConstWithType final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -36,7 +30,7 @@ class ConstWithType final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("type"); } }; diff --git a/src/canonicalizer/rules/content_media_type_without_encoding.h b/src/canonicalizer/rules/content_media_type_without_encoding.h index 52d7f3751..53974f89b 100644 --- a/src/canonicalizer/rules/content_media_type_without_encoding.h +++ b/src/canonicalizer/rules/content_media_type_without_encoding.h @@ -1,12 +1,8 @@ class ContentMediaTypeWithoutEncoding final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; ContentMediaTypeWithoutEncoding() - : SchemaTransformRule{ - "content_media_type_without_encoding", - "The `contentMediaType` keyword is meaningless " - "without the presence of the `contentEncoding` keyword"} {}; + : SchemaTransformRule{"content_media_type_without_encoding"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class ContentMediaTypeWithoutEncoding final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Content, Vocabularies::Known::JSON_Schema_2019_09_Content, @@ -26,7 +21,7 @@ class ContentMediaTypeWithoutEncoding final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("contentMediaType"); } }; diff --git a/src/canonicalizer/rules/content_schema_without_media_type.h b/src/canonicalizer/rules/content_schema_without_media_type.h index da32947e6..cc3f88756 100644 --- a/src/canonicalizer/rules/content_schema_without_media_type.h +++ b/src/canonicalizer/rules/content_schema_without_media_type.h @@ -4,13 +4,9 @@ class ContentSchemaWithoutMediaType final : public SchemaTransformRule { static inline const std::string KEYWORD{"contentSchema"}; public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; ContentSchemaWithoutMediaType() - : SchemaTransformRule{ - "content_schema_without_media_type", - "The `contentSchema` keyword is meaningless without the presence " - "of the `contentMediaType` keyword"} {}; + : SchemaTransformRule{"content_schema_without_media_type"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -19,19 +15,19 @@ class ContentSchemaWithoutMediaType final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Content, Vocabularies::Known::JSON_Schema_2019_09_Content}) && schema.is_object() && schema.defines(KEYWORD) && !schema.defines("contentMediaType")); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase(KEYWORD); } }; diff --git a/src/canonicalizer/rules/definitions_to_defs.h b/src/canonicalizer/rules/definitions_to_defs.h index 0a9d418d7..d5ca0914b 100644 --- a/src/canonicalizer/rules/definitions_to_defs.h +++ b/src/canonicalizer/rules/definitions_to_defs.h @@ -1,11 +1,7 @@ class DefinitionsToDefs final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - DefinitionsToDefs() - : SchemaTransformRule{"definitions_to_defs", - "`definitions` was superseded by `$defs` in " - "2019-09 and later versions"} {}; + DefinitionsToDefs() : SchemaTransformRule{"definitions_to_defs"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,8 +10,7 @@ class DefinitionsToDefs final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Core, Vocabularies::Known::JSON_Schema_2019_09_Core}) && @@ -24,14 +19,15 @@ class DefinitionsToDefs final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.rename("definitions", "$defs"); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { return target.rebase(current.concat("definitions"), current.concat("$defs")); } diff --git a/src/canonicalizer/rules/dependencies_property_tautology.h b/src/canonicalizer/rules/dependencies_property_tautology.h index ea0bcba39..efc4478a0 100644 --- a/src/canonicalizer/rules/dependencies_property_tautology.h +++ b/src/canonicalizer/rules/dependencies_property_tautology.h @@ -1,13 +1,8 @@ class DependenciesPropertyTautology final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; DependenciesPropertyTautology() - : SchemaTransformRule{ - "dependencies_property_tautology", - "Defining requirements for a property using `dependencies` " - "that is already marked as required is an unnecessarily complex " - "use of `dependencies`"} {}; + : SchemaTransformRule{"dependencies_property_tautology"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -16,8 +11,7 @@ class DependenciesPropertyTautology final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_7, Vocabularies::Known::JSON_Schema_Draft_6, @@ -51,7 +45,8 @@ class DependenciesPropertyTautology final : public SchemaTransformRule { return dependent && (dependent->is_array() || dependent->is_string()); })); - this->locations_ = {Pointer{"dependencies"}, Pointer{"properties"}}; + this->locations_ = {sourcemeta::core::Pointer{"dependencies"}, + sourcemeta::core::Pointer{"properties"}}; return true; } @@ -66,11 +61,12 @@ class DependenciesPropertyTautology final : public SchemaTransformRule { const auto *dependent{dependencies->try_at(element.to_string())}; return dependent && (dependent->is_array() || dependent->is_string()); })); - this->locations_ = {Pointer{"dependencies"}, Pointer{"required"}}; + this->locations_ = {sourcemeta::core::Pointer{"dependencies"}, + sourcemeta::core::Pointer{"required"}}; return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { const bool is_draft_3_path{ std::ranges::any_of(this->locations_, [](const auto &pointer) -> auto { return pointer.size() == 1 && pointer.at(0).is_property() && @@ -84,7 +80,7 @@ class DependenciesPropertyTautology final : public SchemaTransformRule { } private: - static auto transform_array(JSON &schema) -> void { + static auto transform_array(sourcemeta::core::JSON &schema) -> void { auto requirements{schema.at("required")}; while (true) { bool match{false}; @@ -121,11 +117,11 @@ class DependenciesPropertyTautology final : public SchemaTransformRule { schema.assign("required", requirements); } - static auto transform_boolean(JSON &schema) -> void { + static auto transform_boolean(sourcemeta::core::JSON &schema) -> void { while (true) { bool match{false}; - std::vector snapshot; + std::vector snapshot; for (const auto &entry : schema.at("properties").as_object()) { if (!entry.second.is_object()) { continue; @@ -142,7 +138,7 @@ class DependenciesPropertyTautology final : public SchemaTransformRule { } const auto dependents_copy{schema.at("dependencies").at(name)}; - std::vector new_required; + std::vector new_required; if (dependents_copy.is_string()) { new_required.push_back(dependents_copy.to_string()); } else if (dependents_copy.is_array()) { @@ -157,8 +153,8 @@ class DependenciesPropertyTautology final : public SchemaTransformRule { for (const auto &dependency_name : new_required) { if (!schema.at("properties").defines(dependency_name)) { - auto new_property{JSON::make_object()}; - new_property.assign("required", JSON{true}); + auto new_property{sourcemeta::core::JSON::make_object()}; + new_property.assign("required", sourcemeta::core::JSON{true}); schema.at("properties") .assign(dependency_name, std::move(new_property)); match = true; @@ -167,7 +163,7 @@ class DependenciesPropertyTautology final : public SchemaTransformRule { const auto *current_required{existing.try_at("required")}; if (!current_required || !current_required->is_boolean() || !current_required->to_boolean()) { - existing.assign("required", JSON{true}); + existing.assign("required", sourcemeta::core::JSON{true}); match = true; } } diff --git a/src/canonicalizer/rules/dependencies_to_any_of.h b/src/canonicalizer/rules/dependencies_to_any_of.h index 9ab137c0b..e950ad97a 100644 --- a/src/canonicalizer/rules/dependencies_to_any_of.h +++ b/src/canonicalizer/rules/dependencies_to_any_of.h @@ -1,8 +1,7 @@ class DependenciesToAnyOf final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - DependenciesToAnyOf() : SchemaTransformRule{"dependencies_to_any_of", ""} {}; + DependenciesToAnyOf() : SchemaTransformRule{"dependencies_to_any_of"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class DependenciesToAnyOf final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_4, Vocabularies::Known::JSON_Schema_Draft_6, @@ -29,61 +27,64 @@ class DependenciesToAnyOf final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - auto result_branches{JSON::make_array()}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + auto result_branches{sourcemeta::core::JSON::make_array()}; - std::vector processed; + std::vector processed; for (const auto &entry : schema.at("dependencies").as_object()) { if (is_schema(entry.second)) { - auto not_required{JSON::make_object()}; - not_required.assign("type", JSON{"object"}); - not_required.assign("required", JSON::make_array()); - not_required.at("required").push_back(JSON{entry.first}); - auto not_branch{JSON::make_object()}; + auto not_required{sourcemeta::core::JSON::make_object()}; + not_required.assign("type", sourcemeta::core::JSON{"object"}); + not_required.assign("required", sourcemeta::core::JSON::make_array()); + not_required.at("required") + .push_back(sourcemeta::core::JSON{entry.first}); + auto not_branch{sourcemeta::core::JSON::make_object()}; not_branch.assign("not", std::move(not_required)); - auto required_obj{JSON::make_object()}; - required_obj.assign("type", JSON{"object"}); - required_obj.assign("required", JSON::make_array()); - required_obj.at("required").push_back(JSON{entry.first}); + auto required_obj{sourcemeta::core::JSON::make_object()}; + required_obj.assign("type", sourcemeta::core::JSON{"object"}); + required_obj.assign("required", sourcemeta::core::JSON::make_array()); + required_obj.at("required") + .push_back(sourcemeta::core::JSON{entry.first}); - auto all_of{JSON::make_array()}; + auto all_of{sourcemeta::core::JSON::make_array()}; all_of.push_back(std::move(required_obj)); all_of.push_back(entry.second); - auto allof_branch{JSON::make_object()}; + auto allof_branch{sourcemeta::core::JSON::make_object()}; allof_branch.assign("allOf", std::move(all_of)); - auto pair{JSON::make_array()}; + auto pair{sourcemeta::core::JSON::make_array()}; pair.push_back(std::move(not_branch)); pair.push_back(std::move(allof_branch)); - auto wrapper{JSON::make_object()}; + auto wrapper{sourcemeta::core::JSON::make_object()}; wrapper.assign("anyOf", std::move(pair)); result_branches.push_back(std::move(wrapper)); } else if (entry.second.is_array()) { - auto required_all{JSON::make_array()}; - required_all.push_back(JSON{entry.first}); + auto required_all{sourcemeta::core::JSON::make_array()}; + required_all.push_back(sourcemeta::core::JSON{entry.first}); for (const auto &dependent : entry.second.as_array()) { required_all.push_back(dependent); } - auto not_required{JSON::make_object()}; - not_required.assign("type", JSON{"object"}); - not_required.assign("required", JSON::make_array()); - not_required.at("required").push_back(JSON{entry.first}); - auto not_branch{JSON::make_object()}; + auto not_required{sourcemeta::core::JSON::make_object()}; + not_required.assign("type", sourcemeta::core::JSON{"object"}); + not_required.assign("required", sourcemeta::core::JSON::make_array()); + not_required.at("required") + .push_back(sourcemeta::core::JSON{entry.first}); + auto not_branch{sourcemeta::core::JSON::make_object()}; not_branch.assign("not", std::move(not_required)); - auto required_branch{JSON::make_object()}; - required_branch.assign("type", JSON{"object"}); + auto required_branch{sourcemeta::core::JSON::make_object()}; + required_branch.assign("type", sourcemeta::core::JSON{"object"}); required_branch.assign("required", std::move(required_all)); - auto pair{JSON::make_array()}; + auto pair{sourcemeta::core::JSON::make_array()}; pair.push_back(std::move(not_branch)); pair.push_back(std::move(required_branch)); - auto wrapper{JSON::make_object()}; + auto wrapper{sourcemeta::core::JSON::make_object()}; wrapper.assign("anyOf", std::move(pair)); result_branches.push_back(std::move(wrapper)); } else { diff --git a/src/canonicalizer/rules/dependencies_to_extends_disallow.h b/src/canonicalizer/rules/dependencies_to_extends_disallow.h index 5db582376..49a462b34 100644 --- a/src/canonicalizer/rules/dependencies_to_extends_disallow.h +++ b/src/canonicalizer/rules/dependencies_to_extends_disallow.h @@ -1,9 +1,8 @@ class DependenciesToExtendsDisallow final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; DependenciesToExtendsDisallow() - : SchemaTransformRule{"dependencies_to_extends_disallow", ""} {}; + : SchemaTransformRule{"dependencies_to_extends_disallow"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class DependenciesToExtendsDisallow final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains(Vocabularies::Known::JSON_Schema_Draft_3) && schema.is_object()); @@ -29,48 +27,52 @@ class DependenciesToExtendsDisallow final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - auto result_branches{JSON::make_array()}; - std::vector processed; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + auto result_branches{sourcemeta::core::JSON::make_array()}; + std::vector processed; for (const auto &entry : schema.at("dependencies").as_object()) { - auto required_property{JSON::make_object()}; - required_property.assign("type", JSON{"object"}); - auto required_props{JSON::make_object()}; - auto required_prop_schema{JSON::make_object()}; - required_prop_schema.assign("required", JSON{true}); + auto required_property{sourcemeta::core::JSON::make_object()}; + required_property.assign("type", sourcemeta::core::JSON{"object"}); + auto required_props{sourcemeta::core::JSON::make_object()}; + auto required_prop_schema{sourcemeta::core::JSON::make_object()}; + required_prop_schema.assign("required", sourcemeta::core::JSON{true}); required_props.assign(entry.first, std::move(required_prop_schema)); required_property.assign("properties", std::move(required_props)); - required_property.assign("patternProperties", JSON::make_object()); - required_property.assign("additionalProperties", JSON::make_object()); + required_property.assign("patternProperties", + sourcemeta::core::JSON::make_object()); + required_property.assign("additionalProperties", + sourcemeta::core::JSON::make_object()); - auto not_required{JSON::make_object()}; - auto disallow_array{JSON::make_array()}; + auto not_required{sourcemeta::core::JSON::make_object()}; + auto disallow_array{sourcemeta::core::JSON::make_array()}; disallow_array.push_back(required_property); not_required.assign("disallow", std::move(disallow_array)); if (is_schema(entry.second)) { - auto extends_array{JSON::make_array()}; - auto required_copy{JSON::make_object()}; - required_copy.assign("type", JSON{"object"}); - auto req_props_copy{JSON::make_object()}; - auto req_prop_schema_copy{JSON::make_object()}; - req_prop_schema_copy.assign("required", JSON{true}); + auto extends_array{sourcemeta::core::JSON::make_array()}; + auto required_copy{sourcemeta::core::JSON::make_object()}; + required_copy.assign("type", sourcemeta::core::JSON{"object"}); + auto req_props_copy{sourcemeta::core::JSON::make_object()}; + auto req_prop_schema_copy{sourcemeta::core::JSON::make_object()}; + req_prop_schema_copy.assign("required", sourcemeta::core::JSON{true}); req_props_copy.assign(entry.first, std::move(req_prop_schema_copy)); required_copy.assign("properties", std::move(req_props_copy)); - required_copy.assign("patternProperties", JSON::make_object()); - required_copy.assign("additionalProperties", JSON::make_object()); + required_copy.assign("patternProperties", + sourcemeta::core::JSON::make_object()); + required_copy.assign("additionalProperties", + sourcemeta::core::JSON::make_object()); extends_array.push_back(std::move(required_copy)); extends_array.push_back(entry.second); - auto extends_branch{JSON::make_object()}; + auto extends_branch{sourcemeta::core::JSON::make_object()}; extends_branch.assign("extends", std::move(extends_array)); - auto type_array{JSON::make_array()}; + auto type_array{sourcemeta::core::JSON::make_array()}; type_array.push_back(std::move(not_required)); type_array.push_back(std::move(extends_branch)); - auto wrapper{JSON::make_object()}; + auto wrapper{sourcemeta::core::JSON::make_object()}; wrapper.assign("type", std::move(type_array)); result_branches.push_back(std::move(wrapper)); } else if (entry.second.is_string() || entry.second.is_array()) { @@ -85,26 +87,28 @@ class DependenciesToExtendsDisallow final : public SchemaTransformRule { } } - auto required_all{JSON::make_object()}; - required_all.assign("type", JSON{"object"}); - auto all_props{JSON::make_object()}; - auto trigger_schema{JSON::make_object()}; - trigger_schema.assign("required", JSON{true}); + auto required_all{sourcemeta::core::JSON::make_object()}; + required_all.assign("type", sourcemeta::core::JSON{"object"}); + auto all_props{sourcemeta::core::JSON::make_object()}; + auto trigger_schema{sourcemeta::core::JSON::make_object()}; + trigger_schema.assign("required", sourcemeta::core::JSON{true}); all_props.assign(entry.first, std::move(trigger_schema)); for (const auto &dependent_prop : dependent_props) { - auto dep_schema{JSON::make_object()}; - dep_schema.assign("required", JSON{true}); + auto dep_schema{sourcemeta::core::JSON::make_object()}; + dep_schema.assign("required", sourcemeta::core::JSON{true}); all_props.assign(dependent_prop, std::move(dep_schema)); } required_all.assign("properties", std::move(all_props)); - required_all.assign("patternProperties", JSON::make_object()); - required_all.assign("additionalProperties", JSON::make_object()); + required_all.assign("patternProperties", + sourcemeta::core::JSON::make_object()); + required_all.assign("additionalProperties", + sourcemeta::core::JSON::make_object()); - auto type_array{JSON::make_array()}; + auto type_array{sourcemeta::core::JSON::make_array()}; type_array.push_back(std::move(not_required)); type_array.push_back(std::move(required_all)); - auto wrapper{JSON::make_object()}; + auto wrapper{sourcemeta::core::JSON::make_object()}; wrapper.assign("type", std::move(type_array)); result_branches.push_back(std::move(wrapper)); } else { diff --git a/src/canonicalizer/rules/dependent_required_tautology.h b/src/canonicalizer/rules/dependent_required_tautology.h index 7ad8901f0..6fe8ef300 100644 --- a/src/canonicalizer/rules/dependent_required_tautology.h +++ b/src/canonicalizer/rules/dependent_required_tautology.h @@ -1,13 +1,8 @@ class DependentRequiredTautology final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::false_type; DependentRequiredTautology() - : SchemaTransformRule{ - "dependent_required_tautology", - "Defining requirements for a property using `dependentRequired` " - "that is already marked as required is an unnecessarily complex " - "use of `dependentRequired`"} {}; + : SchemaTransformRule{"dependent_required_tautology"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -16,8 +11,7 @@ class DependentRequiredTautology final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, @@ -38,7 +32,7 @@ class DependentRequiredTautology final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto requirements{schema.at("required")}; while (true) { bool match{false}; diff --git a/src/canonicalizer/rules/dependent_required_to_any_of.h b/src/canonicalizer/rules/dependent_required_to_any_of.h index 525859e92..4f21155aa 100644 --- a/src/canonicalizer/rules/dependent_required_to_any_of.h +++ b/src/canonicalizer/rules/dependent_required_to_any_of.h @@ -1,9 +1,8 @@ class DependentRequiredToAnyOf final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; DependentRequiredToAnyOf() - : SchemaTransformRule{"dependent_required_to_any_of", ""} {}; + : SchemaTransformRule{"dependent_required_to_any_of"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class DependentRequiredToAnyOf final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -39,34 +37,36 @@ class DependentRequiredToAnyOf final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - auto result_branches{JSON::make_array()}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + auto result_branches{sourcemeta::core::JSON::make_array()}; - std::vector processed; + std::vector processed; for (const auto &entry : schema.at("dependentRequired").as_object()) { if (!entry.second.is_array()) { continue; } - auto required_all{JSON::make_array()}; - required_all.push_back(JSON{entry.first}); + auto required_all{sourcemeta::core::JSON::make_array()}; + required_all.push_back(sourcemeta::core::JSON{entry.first}); for (const auto &dependent : entry.second.as_array()) { required_all.push_back(dependent); } - auto absence_branch{JSON::make_object()}; - absence_branch.assign("properties", JSON::make_object()); - absence_branch.at("properties").assign(entry.first, JSON{false}); + auto absence_branch{sourcemeta::core::JSON::make_object()}; + absence_branch.assign("properties", + sourcemeta::core::JSON::make_object()); + absence_branch.at("properties") + .assign(entry.first, sourcemeta::core::JSON{false}); - auto required_branch{JSON::make_object()}; - required_branch.assign("type", JSON{"object"}); + auto required_branch{sourcemeta::core::JSON::make_object()}; + required_branch.assign("type", sourcemeta::core::JSON{"object"}); required_branch.assign("required", std::move(required_all)); - auto pair{JSON::make_array()}; + auto pair{sourcemeta::core::JSON::make_array()}; pair.push_back(std::move(absence_branch)); pair.push_back(std::move(required_branch)); - auto wrapper{JSON::make_object()}; + auto wrapper{sourcemeta::core::JSON::make_object()}; wrapper.assign("anyOf", std::move(pair)); result_branches.push_back(std::move(wrapper)); diff --git a/src/canonicalizer/rules/dependent_schemas_to_any_of.h b/src/canonicalizer/rules/dependent_schemas_to_any_of.h index 989ecb2ca..e57b9d2ed 100644 --- a/src/canonicalizer/rules/dependent_schemas_to_any_of.h +++ b/src/canonicalizer/rules/dependent_schemas_to_any_of.h @@ -1,9 +1,8 @@ class DependentSchemasToAnyOf final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; DependentSchemasToAnyOf() - : SchemaTransformRule{"dependent_schemas_to_any_of", ""} {}; + : SchemaTransformRule{"dependent_schemas_to_any_of"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class DependentSchemasToAnyOf final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -35,31 +33,34 @@ class DependentSchemasToAnyOf final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - auto result_branches{JSON::make_array()}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + auto result_branches{sourcemeta::core::JSON::make_array()}; for (const auto &entry : schema.at("dependentSchemas").as_object()) { - auto absence_branch{JSON::make_object()}; - absence_branch.assign("properties", JSON::make_object()); - absence_branch.at("properties").assign(entry.first, JSON{false}); + auto absence_branch{sourcemeta::core::JSON::make_object()}; + absence_branch.assign("properties", + sourcemeta::core::JSON::make_object()); + absence_branch.at("properties") + .assign(entry.first, sourcemeta::core::JSON{false}); - auto required_obj{JSON::make_object()}; - required_obj.assign("type", JSON{"object"}); - required_obj.assign("required", JSON::make_array()); - required_obj.at("required").push_back(JSON{entry.first}); + auto required_obj{sourcemeta::core::JSON::make_object()}; + required_obj.assign("type", sourcemeta::core::JSON{"object"}); + required_obj.assign("required", sourcemeta::core::JSON::make_array()); + required_obj.at("required") + .push_back(sourcemeta::core::JSON{entry.first}); - auto all_of{JSON::make_array()}; + auto all_of{sourcemeta::core::JSON::make_array()}; all_of.push_back(std::move(required_obj)); all_of.push_back(entry.second); - auto allof_branch{JSON::make_object()}; + auto allof_branch{sourcemeta::core::JSON::make_object()}; allof_branch.assign("allOf", std::move(all_of)); - auto pair{JSON::make_array()}; + auto pair{sourcemeta::core::JSON::make_array()}; pair.push_back(std::move(absence_branch)); pair.push_back(std::move(allof_branch)); - auto wrapper{JSON::make_object()}; + auto wrapper{sourcemeta::core::JSON::make_object()}; wrapper.assign("anyOf", std::move(pair)); result_branches.push_back(std::move(wrapper)); } diff --git a/src/canonicalizer/rules/deprecated_false_drop.h b/src/canonicalizer/rules/deprecated_false_drop.h index d9218527b..6de3c1dee 100644 --- a/src/canonicalizer/rules/deprecated_false_drop.h +++ b/src/canonicalizer/rules/deprecated_false_drop.h @@ -1,8 +1,7 @@ class DeprecatedFalseDrop final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - DeprecatedFalseDrop() : SchemaTransformRule{"deprecated_false_drop", ""} {}; + DeprecatedFalseDrop() : SchemaTransformRule{"deprecated_false_drop"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class DeprecatedFalseDrop final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2019_09_Meta_Data, @@ -25,7 +23,7 @@ class DeprecatedFalseDrop final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("deprecated"); } }; diff --git a/src/canonicalizer/rules/disallow_array_to_extends.h b/src/canonicalizer/rules/disallow_array_to_extends.h index 89be86db8..b15c6d937 100644 --- a/src/canonicalizer/rules/disallow_array_to_extends.h +++ b/src/canonicalizer/rules/disallow_array_to_extends.h @@ -1,13 +1,8 @@ class DisallowArrayToExtends final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; DisallowArrayToExtends() - : SchemaTransformRule{ - "disallow_array_to_extends", - "A multi-way `disallow` is the conjunction of single negations: " - "each element becomes its own single-element `disallow` in an " - "`extends` branch"} {}; + : SchemaTransformRule{"disallow_array_to_extends"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -16,8 +11,7 @@ class DisallowArrayToExtends final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper}) && @@ -28,12 +22,12 @@ class DisallowArrayToExtends final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - auto branches{JSON::make_array()}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + auto branches{sourcemeta::core::JSON::make_array()}; for (const auto &element : schema.at("disallow").as_array()) { - auto negation{JSON::make_array()}; + auto negation{sourcemeta::core::JSON::make_array()}; negation.push_back(element); - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign("disallow", std::move(negation)); branches.push_back(std::move(branch)); } @@ -46,7 +40,7 @@ class DisallowArrayToExtends final : public SchemaTransformRule { schema.at("extends").push_back(std::move(branch)); } } else if (schema.defines("extends")) { - auto extends{JSON::make_array()}; + auto extends{sourcemeta::core::JSON::make_array()}; extends.push_back(schema.at("extends")); this->extends_start_ = extends.size(); for (auto &branch : branches.as_array()) { @@ -59,10 +53,11 @@ class DisallowArrayToExtends final : public SchemaTransformRule { } } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { const auto disallow_prefix{current.concat("disallow")}; if (!target.starts_with(disallow_prefix)) { return target; @@ -75,7 +70,7 @@ class DisallowArrayToExtends final : public SchemaTransformRule { const auto index{relative.at(0).to_index()}; return target.rebase( - current.concat(Pointer{"disallow", index}), + current.concat(sourcemeta::core::Pointer{"disallow", index}), current.concat( {"extends", this->extends_start_ + index, "disallow", 0})); } diff --git a/src/canonicalizer/rules/disallow_double_negation.h b/src/canonicalizer/rules/disallow_double_negation.h index 4a6ffa816..2a3fb1531 100644 --- a/src/canonicalizer/rules/disallow_double_negation.h +++ b/src/canonicalizer/rules/disallow_double_negation.h @@ -1,14 +1,7 @@ class DisallowDoubleNegation final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - DisallowDoubleNegation() - : SchemaTransformRule{ - "disallow_double_negation", - "A `disallow` whose single negated schema is itself a `disallow` " - "of " - "a single schema is a double negation equivalent to the inner " - "schema"} {}; + DisallowDoubleNegation() : SchemaTransformRule{"disallow_double_negation"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -17,9 +10,8 @@ class DisallowDoubleNegation final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"disallow"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"disallow"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper}) && @@ -54,7 +46,7 @@ class DisallowDoubleNegation final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto inner{schema.at("disallow").at(0).at("disallow").at(0)}; schema.erase("disallow"); @@ -69,10 +61,11 @@ class DisallowDoubleNegation final : public SchemaTransformRule { } } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { auto old_prefix{current.concat({"disallow", 0, "disallow", 0})}; while ( target.starts_with(old_prefix.concat({"disallow", 0, "disallow", 0}))) { diff --git a/src/canonicalizer/rules/disallow_extends_to_type.h b/src/canonicalizer/rules/disallow_extends_to_type.h index 2f0791623..92f595245 100644 --- a/src/canonicalizer/rules/disallow_extends_to_type.h +++ b/src/canonicalizer/rules/disallow_extends_to_type.h @@ -1,13 +1,7 @@ class DisallowExtendsToType final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - DisallowExtendsToType() - : SchemaTransformRule{ - "disallow_extends_to_type", - "Negating a conjunction is the disjunction of the negations: an " - "`extends` under `disallow` becomes a `type` union where each " - "branch is its own single negation"} {}; + DisallowExtendsToType() : SchemaTransformRule{"disallow_extends_to_type"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -16,8 +10,7 @@ class DisallowExtendsToType final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper}) && @@ -42,7 +35,7 @@ class DisallowExtendsToType final : public SchemaTransformRule { // The conjuncts relocate to distinct `type` branches (handled by // `rereference`), but the wrapper schema itself is dissolved rather than // moved, so a reference straight at it has no new home: bail in that case - static const JSON::String DISALLOW{"disallow"}; + static const sourcemeta::core::JSON::String DISALLOW{"disallow"}; auto wrapper_pointer{location.pointer}; wrapper_pointer.push_back(std::cref(DISALLOW)); wrapper_pointer.push_back(static_cast(0)); @@ -51,12 +44,12 @@ class DisallowExtendsToType final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - auto branches{JSON::make_array()}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + auto branches{sourcemeta::core::JSON::make_array()}; for (auto &branch : schema.at("disallow").at(0).at("extends").as_array()) { - auto negation{JSON::make_array()}; + auto negation{sourcemeta::core::JSON::make_array()}; negation.push_back(std::move(branch)); - auto element{JSON::make_object()}; + auto element{sourcemeta::core::JSON::make_object()}; element.assign("disallow", std::move(negation)); branches.push_back(std::move(element)); } @@ -65,10 +58,11 @@ class DisallowExtendsToType final : public SchemaTransformRule { schema.assign("type", std::move(branches)); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { const auto extends_prefix{current.concat({"disallow", 0, "extends"})}; if (!target.starts_with(extends_prefix)) { return target; diff --git a/src/canonicalizer/rules/disallow_narrows_type.h b/src/canonicalizer/rules/disallow_narrows_type.h index 5eba348fd..20fb047f3 100644 --- a/src/canonicalizer/rules/disallow_narrows_type.h +++ b/src/canonicalizer/rules/disallow_narrows_type.h @@ -1,13 +1,7 @@ class DisallowNarrowsType final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - DisallowNarrowsType() - : SchemaTransformRule{ - "disallow_narrows_type", - "When `disallow` excludes types that are also in the parent " - "`type`, those types can be removed from `type` and the " - "corresponding `disallow` entries dropped"} {}; + DisallowNarrowsType() : SchemaTransformRule{"disallow_narrows_type"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -16,9 +10,8 @@ class DisallowNarrowsType final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"disallow"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"disallow"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper}) && @@ -31,14 +24,14 @@ class DisallowNarrowsType final : public SchemaTransformRule { ONLY_CONTINUE_IF(parent_type && parent_type->is_array() && parent_type->size() > 1); - std::unordered_set parent_type_names; + std::unordered_set parent_type_names; for (const auto &entry : parent_type->as_array()) { ONLY_CONTINUE_IF(entry.is_string() && entry.to_string() != "any"); parent_type_names.insert(entry.to_string()); } - std::vector locations; - std::unordered_set narrowed_types; + std::vector locations; + std::unordered_set narrowed_types; for (std::size_t index = 0; index < disallow->size(); ++index) { const auto entry_types{extract_type_names(disallow->at(index))}; if (entry_types.empty()) { @@ -53,7 +46,7 @@ class DisallowNarrowsType final : public SchemaTransformRule { continue; } - locations.push_back(Pointer{KEYWORD, index}); + locations.push_back(sourcemeta::core::Pointer{KEYWORD, index}); narrowed_types.insert(entry_types.cbegin(), entry_types.cend()); } @@ -68,8 +61,8 @@ class DisallowNarrowsType final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - std::unordered_set narrowed_types; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + std::unordered_set narrowed_types; std::vector dead_indices; dead_indices.reserve(this->locations_.size()); const auto &disallow{schema.at("disallow")}; @@ -81,7 +74,7 @@ class DisallowNarrowsType final : public SchemaTransformRule { narrowed_types.insert(entry_types.cbegin(), entry_types.cend()); } - auto new_type{JSON::make_array()}; + auto new_type{sourcemeta::core::JSON::make_array()}; for (const auto &entry : schema.at("type").as_array()) { if (entry.is_string() && !narrowed_types.contains(entry.to_string())) { new_type.push_back(entry); @@ -89,7 +82,7 @@ class DisallowNarrowsType final : public SchemaTransformRule { } schema.assign("type", std::move(new_type)); - auto new_disallow{JSON::make_array()}; + auto new_disallow{sourcemeta::core::JSON::make_array()}; for (std::size_t index = 0; index < disallow.size(); ++index) { if (std::ranges::find(dead_indices, index) == dead_indices.end()) { new_disallow.push_back(disallow.at(index)); @@ -104,8 +97,8 @@ class DisallowNarrowsType final : public SchemaTransformRule { private: static auto extract_type_names(const sourcemeta::core::JSON &entry) - -> std::unordered_set { - std::unordered_set result; + -> std::unordered_set { + std::unordered_set result; if (entry.is_string()) { if (entry.to_string() != "any") { result.insert(entry.to_string()); @@ -130,7 +123,7 @@ class DisallowNarrowsType final : public SchemaTransformRule { } for (const auto &type_entry : entry_type->as_array()) { if (!type_entry.is_string() || type_entry.to_string() == "any") { - return std::unordered_set{}; + return std::unordered_set{}; } result.insert(type_entry.to_string()); } diff --git a/src/canonicalizer/rules/disallow_to_array_of_schemas.h b/src/canonicalizer/rules/disallow_to_array_of_schemas.h index c50b213bb..5889c05fb 100644 --- a/src/canonicalizer/rules/disallow_to_array_of_schemas.h +++ b/src/canonicalizer/rules/disallow_to_array_of_schemas.h @@ -1,9 +1,8 @@ class DisallowToArrayOfSchemas final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; DisallowToArrayOfSchemas() - : SchemaTransformRule{"disallow_to_array_of_schemas", ""} {}; + : SchemaTransformRule{"disallow_to_array_of_schemas"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class DisallowToArrayOfSchemas final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_0, Vocabularies::Known::JSON_Schema_Draft_1, @@ -41,11 +39,11 @@ class DisallowToArrayOfSchemas final : public SchemaTransformRule { return false; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { const auto &disallow{schema.at("disallow")}; if (disallow.is_string()) { - auto array{JSON::make_array()}; + auto array{sourcemeta::core::JSON::make_array()}; if (this->convert_to_schemas_) { array.push_back(type_string_to_schema(disallow.to_string())); } else { @@ -55,7 +53,7 @@ class DisallowToArrayOfSchemas final : public SchemaTransformRule { return; } - auto new_array{JSON::make_array()}; + auto new_array{sourcemeta::core::JSON::make_array()}; for (const auto &element : disallow.as_array()) { if (element.is_string() && this->convert_to_schemas_) { new_array.push_back(type_string_to_schema(element.to_string())); @@ -66,39 +64,42 @@ class DisallowToArrayOfSchemas final : public SchemaTransformRule { schema.assign("disallow", std::move(new_array)); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { - return target.rebase(current.concat("disallow"), - current.concat(Pointer{"disallow", 0})); + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { + return target.rebase( + current.concat("disallow"), + current.concat(sourcemeta::core::Pointer{"disallow", 0})); } private: - static auto type_string_to_schema(const std::string &type_name) -> JSON { + static auto type_string_to_schema(const std::string &type_name) + -> sourcemeta::core::JSON { if (type_name == "null") { - auto result{JSON::make_object()}; - auto values{JSON::make_array()}; - values.push_back(JSON{nullptr}); + auto result{sourcemeta::core::JSON::make_object()}; + auto values{sourcemeta::core::JSON::make_array()}; + values.push_back(sourcemeta::core::JSON{nullptr}); result.assign("enum", std::move(values)); return result; } if (type_name == "boolean") { - auto result{JSON::make_object()}; - auto values{JSON::make_array()}; - values.push_back(JSON{false}); - values.push_back(JSON{true}); + auto result{sourcemeta::core::JSON::make_object()}; + auto values{sourcemeta::core::JSON::make_array()}; + values.push_back(sourcemeta::core::JSON{false}); + values.push_back(sourcemeta::core::JSON{true}); result.assign("enum", std::move(values)); return result; } if (type_name == "any") { - return JSON::make_object(); + return sourcemeta::core::JSON::make_object(); } - auto result{JSON::make_object()}; - result.assign("type", JSON{type_name}); + auto result{sourcemeta::core::JSON::make_object()}; + result.assign("type", sourcemeta::core::JSON{type_name}); return result; } diff --git a/src/canonicalizer/rules/disallow_type_union_to_extends.h b/src/canonicalizer/rules/disallow_type_union_to_extends.h index 518e40fdb..ef86637d1 100644 --- a/src/canonicalizer/rules/disallow_type_union_to_extends.h +++ b/src/canonicalizer/rules/disallow_type_union_to_extends.h @@ -1,13 +1,8 @@ class DisallowTypeUnionToExtends final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; DisallowTypeUnionToExtends() - : SchemaTransformRule{ - "disallow_type_union_to_extends", - "Negating a disjunction is the conjunction of the negations: a " - "`type` union under `disallow` becomes an `extends` where each " - "branch is its own single negation"} {}; + : SchemaTransformRule{"disallow_type_union_to_extends"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -16,8 +11,7 @@ class DisallowTypeUnionToExtends final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper}) && @@ -42,7 +36,7 @@ class DisallowTypeUnionToExtends final : public SchemaTransformRule { // The union members relocate to distinct `extends` branches (handled by // `rereference`), but the wrapper schema itself is dissolved rather than // moved, so a reference straight at it has no new home: bail in that case - static const JSON::String DISALLOW{"disallow"}; + static const sourcemeta::core::JSON::String DISALLOW{"disallow"}; auto wrapper_pointer{location.pointer}; wrapper_pointer.push_back(std::cref(DISALLOW)); wrapper_pointer.push_back(static_cast(0)); @@ -51,12 +45,12 @@ class DisallowTypeUnionToExtends final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - auto branches{JSON::make_array()}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + auto branches{sourcemeta::core::JSON::make_array()}; for (auto &member : schema.at("disallow").at(0).at("type").as_array()) { - auto negation{JSON::make_array()}; + auto negation{sourcemeta::core::JSON::make_array()}; negation.push_back(std::move(member)); - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign("disallow", std::move(negation)); branches.push_back(std::move(branch)); } @@ -65,10 +59,11 @@ class DisallowTypeUnionToExtends final : public SchemaTransformRule { schema.assign("extends", std::move(branches)); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { const auto type_prefix{current.concat({"disallow", 0, "type"})}; if (!target.starts_with(type_prefix)) { return target; diff --git a/src/canonicalizer/rules/divisible_by_implicit.h b/src/canonicalizer/rules/divisible_by_implicit.h index e6a0fdcd1..3c99b51ce 100644 --- a/src/canonicalizer/rules/divisible_by_implicit.h +++ b/src/canonicalizer/rules/divisible_by_implicit.h @@ -1,8 +1,7 @@ class DivisibleByImplicit final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - DivisibleByImplicit() : SchemaTransformRule{"divisible_by_implicit", ""} {}; + DivisibleByImplicit() : SchemaTransformRule{"divisible_by_implicit"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class DivisibleByImplicit final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_2, Vocabularies::Known::JSON_Schema_Draft_3}) && @@ -24,7 +22,7 @@ class DivisibleByImplicit final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.assign("divisibleBy", sourcemeta::core::JSON{1}); } }; diff --git a/src/canonicalizer/rules/double_negation_elimination.h b/src/canonicalizer/rules/double_negation_elimination.h index f7acc7a1c..a60b15280 100644 --- a/src/canonicalizer/rules/double_negation_elimination.h +++ b/src/canonicalizer/rules/double_negation_elimination.h @@ -1,12 +1,8 @@ class DoubleNegationElimination final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; DoubleNegationElimination() - : SchemaTransformRule{ - "double_negation_elimination", - "A `not` whose value is a schema containing only another " - "`not` is equivalent to the inner value"} {}; + : SchemaTransformRule{"double_negation_elimination"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,9 +11,8 @@ class DoubleNegationElimination final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"not"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"not"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -39,11 +34,12 @@ class DoubleNegationElimination final : public SchemaTransformRule { (schema.defines("unevaluatedProperties") || schema.defines("unevaluatedItems")))); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto inner{schema.at("not").at("not")}; schema.erase("not"); @@ -61,13 +57,15 @@ class DoubleNegationElimination final : public SchemaTransformRule { } } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { - auto old_prefix{current.concat(Pointer{"not", "not"})}; - while (target.starts_with(old_prefix.concat(Pointer{"not", "not"}))) { - old_prefix = old_prefix.concat(Pointer{"not", "not"}); + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { + auto old_prefix{current.concat(sourcemeta::core::Pointer{"not", "not"})}; + while (target.starts_with( + old_prefix.concat(sourcemeta::core::Pointer{"not", "not"}))) { + old_prefix = old_prefix.concat(sourcemeta::core::Pointer{"not", "not"}); } if (!target.starts_with(old_prefix)) { return target; diff --git a/src/canonicalizer/rules/draft3_type_any.h b/src/canonicalizer/rules/draft3_type_any.h index d16c1b73b..84438b74d 100644 --- a/src/canonicalizer/rules/draft3_type_any.h +++ b/src/canonicalizer/rules/draft3_type_any.h @@ -1,8 +1,7 @@ class Draft3TypeAny final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - Draft3TypeAny() : SchemaTransformRule{"draft3_type_any", ""} {}; + Draft3TypeAny() : SchemaTransformRule{"draft3_type_any"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class Draft3TypeAny final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains(Vocabularies::Known::JSON_Schema_Draft_3) && schema.is_object()); @@ -47,7 +45,7 @@ class Draft3TypeAny final : public SchemaTransformRule { return false; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("type"); } }; diff --git a/src/canonicalizer/rules/draft_official_dialect_with_https.h b/src/canonicalizer/rules/draft_official_dialect_with_https.h index 929f088c1..c50fd1312 100644 --- a/src/canonicalizer/rules/draft_official_dialect_with_https.h +++ b/src/canonicalizer/rules/draft_official_dialect_with_https.h @@ -1,12 +1,8 @@ class DraftOfficialDialectWithHttps final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; DraftOfficialDialectWithHttps() - : SchemaTransformRule{ - "draft_official_dialect_with_https", - "The official dialect URI of Draft 7 and older must use " - "\"http://\" instead of \"https://\""} {}; + : SchemaTransformRule{"draft_official_dialect_with_https"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class DraftOfficialDialectWithHttps final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { using sourcemeta::blaze::SchemaBaseDialect; ONLY_CONTINUE_IF( location.base_dialect == SchemaBaseDialect::JSON_Schema_Draft_7 || @@ -67,8 +62,7 @@ class DraftOfficialDialectWithHttps final : public SchemaTransformRule { return true; } - auto transform(sourcemeta::core::JSON &schema, const Result &) const - -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { const auto &old_dialect{schema.at("$schema").to_string()}; std::string new_dialect{"http://"}; new_dialect += old_dialect.substr(8); diff --git a/src/canonicalizer/rules/draft_official_dialect_without_empty_fragment.h b/src/canonicalizer/rules/draft_official_dialect_without_empty_fragment.h index f9622df8e..c36f2dd4e 100644 --- a/src/canonicalizer/rules/draft_official_dialect_without_empty_fragment.h +++ b/src/canonicalizer/rules/draft_official_dialect_without_empty_fragment.h @@ -1,12 +1,9 @@ class DraftOfficialDialectWithoutEmptyFragment final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; DraftOfficialDialectWithoutEmptyFragment() - : SchemaTransformRule{"draft_official_dialect_without_empty_fragment", - "The official dialect URI of Draft 7 and older " - "versions must contain the empty fragment"} {}; + : SchemaTransformRule{"draft_official_dialect_without_empty_fragment"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, const sourcemeta::core::JSON &, @@ -14,9 +11,8 @@ class DraftOfficialDialectWithoutEmptyFragment final const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, - const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const + -> bool override { ONLY_CONTINUE_IF(schema.is_object()); const auto *schema_keyword{schema.try_at("$schema")}; ONLY_CONTINUE_IF(schema_keyword && schema_keyword->is_string()); @@ -39,8 +35,7 @@ class DraftOfficialDialectWithoutEmptyFragment final return true; } - auto transform(sourcemeta::core::JSON &schema, const Result &) const - -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto dialect{std::move(schema.at("$schema")).to_string()}; dialect += "#"; schema.at("$schema").into(sourcemeta::core::JSON{dialect}); diff --git a/src/canonicalizer/rules/draft_ref_siblings.h b/src/canonicalizer/rules/draft_ref_siblings.h index 8d173350c..a63bf2941 100644 --- a/src/canonicalizer/rules/draft_ref_siblings.h +++ b/src/canonicalizer/rules/draft_ref_siblings.h @@ -1,11 +1,7 @@ class DraftRefSiblings final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - DraftRefSiblings() - : SchemaTransformRule{"draft_ref_siblings", - "In Draft 7 and older dialects, keywords sibling " - "to `$ref` are never evaluated"} {} + DraftRefSiblings() : SchemaTransformRule{"draft_ref_siblings"} {} [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,8 +10,7 @@ class DraftRefSiblings final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_7, Vocabularies::Known::JSON_Schema_Draft_6, @@ -27,7 +22,7 @@ class DraftRefSiblings final : public SchemaTransformRule { Vocabularies::Known::JSON_Schema_Draft_0})); ONLY_CONTINUE_IF(schema.is_object() && schema.defines("$ref")); - std::vector locations; + std::vector locations; for (const auto &entry : schema.as_object()) { const auto &metadata{walker(entry.first, vocabularies)}; if (metadata.type == sourcemeta::blaze::SchemaKeywordType::Reference || @@ -37,7 +32,7 @@ class DraftRefSiblings final : public SchemaTransformRule { entry.first == "$schema") { continue; } else { - locations.push_back(Pointer{entry.first}); + locations.push_back(sourcemeta::core::Pointer{entry.first}); } } @@ -46,7 +41,7 @@ class DraftRefSiblings final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { for (const auto &location : this->locations_) { schema.erase(location.at(0).to_property()); } diff --git a/src/canonicalizer/rules/drop_allof_empty_schemas.h b/src/canonicalizer/rules/drop_allof_empty_schemas.h index a1d6b5ce3..cfe3f468d 100644 --- a/src/canonicalizer/rules/drop_allof_empty_schemas.h +++ b/src/canonicalizer/rules/drop_allof_empty_schemas.h @@ -1,17 +1,14 @@ class DropAllOfEmptySchemas final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - DropAllOfEmptySchemas() - : SchemaTransformRule{"drop_allof_empty_schemas", - "Empty schemas in `allOf` are redundant and can be " - "removed"} {}; + DropAllOfEmptySchemas() : SchemaTransformRule{"drop_allof_empty_schemas"} {}; [[nodiscard]] auto - condition(const JSON &schema, const JSON &, const Vocabularies &vocabularies, + condition(const sourcemeta::core::JSON &schema, + const sourcemeta::core::JSON &, const Vocabularies &vocabularies, const SchemaFrame &, const SchemaFrame::Location &, - const SchemaWalker &, const SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const SchemaWalker &, const SchemaResolver &) const + -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -25,8 +22,8 @@ class DropAllOfEmptySchemas final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - auto new_allof{JSON::make_array()}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + auto new_allof{sourcemeta::core::JSON::make_array()}; for (const auto &entry : schema.at("allOf").as_array()) { if (!is_empty_schema(entry)) { new_allof.push_back(entry); diff --git a/src/canonicalizer/rules/drop_extends_empty_schemas.h b/src/canonicalizer/rules/drop_extends_empty_schemas.h index 6f41e03de..3fa45a2bb 100644 --- a/src/canonicalizer/rules/drop_extends_empty_schemas.h +++ b/src/canonicalizer/rules/drop_extends_empty_schemas.h @@ -1,11 +1,8 @@ class DropExtendsEmptySchemas final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; DropExtendsEmptySchemas() - : SchemaTransformRule{ - "drop_extends_empty_schemas", - "Empty schemas in `extends` are redundant and can be removed"} {}; + : SchemaTransformRule{"drop_extends_empty_schemas"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,9 +11,8 @@ class DropExtendsEmptySchemas final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"extends"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"extends"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper}) && @@ -30,15 +26,15 @@ class DropExtendsEmptySchemas final : public SchemaTransformRule { ONLY_CONTINUE_IF(!frame.has_references_through(keyword_pointer)); if (sourcemeta::blaze::is_empty_schema(*extends)) { - this->locations_ = {Pointer{KEYWORD}}; + this->locations_ = {sourcemeta::core::Pointer{KEYWORD}}; return true; } if (extends->is_array() && !extends->empty()) { - std::vector locations; + std::vector locations; for (std::size_t index = 0; index < extends->size(); ++index) { if (sourcemeta::blaze::is_empty_schema(extends->at(index))) { - locations.push_back(Pointer{KEYWORD, index}); + locations.push_back(sourcemeta::core::Pointer{KEYWORD, index}); } } ONLY_CONTINUE_IF(!locations.empty()); @@ -49,13 +45,13 @@ class DropExtendsEmptySchemas final : public SchemaTransformRule { return false; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { if (this->locations_.size() == 1 && this->locations_.at(0).size() == 1) { schema.erase("extends"); return; } - auto new_extends{JSON::make_array()}; + auto new_extends{sourcemeta::core::JSON::make_array()}; for (const auto &entry : schema.at("extends").as_array()) { if (!sourcemeta::blaze::is_empty_schema(entry)) { new_extends.push_back(entry); diff --git a/src/canonicalizer/rules/duplicate_allof_branches.h b/src/canonicalizer/rules/duplicate_allof_branches.h index 6231c7a63..64a6ee478 100644 --- a/src/canonicalizer/rules/duplicate_allof_branches.h +++ b/src/canonicalizer/rules/duplicate_allof_branches.h @@ -1,14 +1,7 @@ class DuplicateAllOfBranches final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - DuplicateAllOfBranches() - : SchemaTransformRule{ - "duplicate_allof_branches", - "Setting duplicate subschemas in `allOf` is redundant, as it " - "produces " - "unnecessary additional validation that is guaranteed to not " - "affect the validation result"} {}; + DuplicateAllOfBranches() : SchemaTransformRule{"duplicate_allof_branches"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -17,8 +10,7 @@ class DuplicateAllOfBranches final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -33,15 +25,18 @@ class DuplicateAllOfBranches final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { this->index_mapping_.clear(); const auto &original{schema.at("allOf")}; - std::unordered_map, std::size_t, - HashJSON>, - EqualJSON>> + std::unordered_map< + std::reference_wrapper, std::size_t, + sourcemeta::core::HashJSON< + std::reference_wrapper>, + sourcemeta::core::EqualJSON< + std::reference_wrapper>> seen; - auto result{JSON::make_array()}; + auto result{sourcemeta::core::JSON::make_array()}; for (std::size_t index = 0; index < original.size(); ++index) { const auto &value{original.at(index)}; @@ -59,16 +54,17 @@ class DuplicateAllOfBranches final : public SchemaTransformRule { schema.assign("allOf", std::move(result)); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { const auto allof_prefix{current.concat("allOf")}; const auto relative{target.resolve_from(allof_prefix)}; const auto old_index{relative.at(0).to_index()}; const auto new_index{this->index_mapping_.at(old_index)}; - const Pointer old_prefix{allof_prefix.concat(old_index)}; - const Pointer new_prefix{allof_prefix.concat(new_index)}; + const sourcemeta::core::Pointer old_prefix{allof_prefix.concat(old_index)}; + const sourcemeta::core::Pointer new_prefix{allof_prefix.concat(new_index)}; return target.rebase(old_prefix, new_prefix); } diff --git a/src/canonicalizer/rules/duplicate_anyof_branches.h b/src/canonicalizer/rules/duplicate_anyof_branches.h index 624484f37..a967bbbfe 100644 --- a/src/canonicalizer/rules/duplicate_anyof_branches.h +++ b/src/canonicalizer/rules/duplicate_anyof_branches.h @@ -1,14 +1,7 @@ class DuplicateAnyOfBranches final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - DuplicateAnyOfBranches() - : SchemaTransformRule{ - "duplicate_anyof_branches", - "Setting duplicate subschemas in `anyOf` is redundant, as it " - "produces " - "unnecessary additional validation that is guaranteed to not " - "affect the validation result"} {}; + DuplicateAnyOfBranches() : SchemaTransformRule{"duplicate_anyof_branches"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -17,8 +10,7 @@ class DuplicateAnyOfBranches final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -33,15 +25,18 @@ class DuplicateAnyOfBranches final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { this->index_mapping_.clear(); const auto &original{schema.at("anyOf")}; - std::unordered_map, std::size_t, - HashJSON>, - EqualJSON>> + std::unordered_map< + std::reference_wrapper, std::size_t, + sourcemeta::core::HashJSON< + std::reference_wrapper>, + sourcemeta::core::EqualJSON< + std::reference_wrapper>> seen; - auto result{JSON::make_array()}; + auto result{sourcemeta::core::JSON::make_array()}; for (std::size_t index = 0; index < original.size(); ++index) { const auto &value{original.at(index)}; @@ -59,16 +54,17 @@ class DuplicateAnyOfBranches final : public SchemaTransformRule { schema.assign("anyOf", std::move(result)); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { const auto anyof_prefix{current.concat("anyOf")}; const auto relative{target.resolve_from(anyof_prefix)}; const auto old_index{relative.at(0).to_index()}; const auto new_index{this->index_mapping_.at(old_index)}; - const Pointer old_prefix{anyof_prefix.concat(old_index)}; - const Pointer new_prefix{anyof_prefix.concat(new_index)}; + const sourcemeta::core::Pointer old_prefix{anyof_prefix.concat(old_index)}; + const sourcemeta::core::Pointer new_prefix{anyof_prefix.concat(new_index)}; return target.rebase(old_prefix, new_prefix); } diff --git a/src/canonicalizer/rules/duplicate_disallow_entries.h b/src/canonicalizer/rules/duplicate_disallow_entries.h index aecdcda26..594b67940 100644 --- a/src/canonicalizer/rules/duplicate_disallow_entries.h +++ b/src/canonicalizer/rules/duplicate_disallow_entries.h @@ -1,13 +1,8 @@ class DuplicateDisallowEntries final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; DuplicateDisallowEntries() - : SchemaTransformRule{ - "duplicate_disallow_entries", - "Setting duplicate subschemas in `disallow` is redundant, as " - "negating the same subschema more than once is guaranteed to not " - "affect the validation result"} {}; + : SchemaTransformRule{"duplicate_disallow_entries"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -16,8 +11,7 @@ class DuplicateDisallowEntries final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper}) && @@ -33,19 +27,23 @@ class DuplicateDisallowEntries final : public SchemaTransformRule { // as its own `extends` branch const std::string keyword{"disallow"}; ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(keyword)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(keyword)})); return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { const auto &original{schema.at("disallow")}; - std::unordered_set, - HashJSON>, - EqualJSON>> + std::unordered_set< + std::reference_wrapper, + sourcemeta::core::HashJSON< + std::reference_wrapper>, + sourcemeta::core::EqualJSON< + std::reference_wrapper>> seen; - auto result{JSON::make_array()}; + auto result{sourcemeta::core::JSON::make_array()}; for (const auto &element : original.as_array()) { if (seen.emplace(std::cref(element)).second) { diff --git a/src/canonicalizer/rules/duplicate_enum_values.h b/src/canonicalizer/rules/duplicate_enum_values.h index a72392d75..6e73964a0 100644 --- a/src/canonicalizer/rules/duplicate_enum_values.h +++ b/src/canonicalizer/rules/duplicate_enum_values.h @@ -1,11 +1,7 @@ class DuplicateEnumValues final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::false_type; - DuplicateEnumValues() - : SchemaTransformRule{"duplicate_enum_values", - "Setting duplicate values in `enum` is " - "considered an anti-pattern"} {}; + DuplicateEnumValues() : SchemaTransformRule{"duplicate_enum_values"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,8 +10,7 @@ class DuplicateEnumValues final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -35,11 +30,13 @@ class DuplicateEnumValues final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { // We want to be super careful to maintain the current ordering // as we delete the duplicates auto &enumeration{schema.at("enum")}; - std::unordered_set> cache; + std::unordered_set> + cache; for (auto iterator = enumeration.as_array().cbegin(); iterator != enumeration.as_array().cend();) { if (cache.contains(*iterator)) { diff --git a/src/canonicalizer/rules/duplicate_required_values.h b/src/canonicalizer/rules/duplicate_required_values.h index 3d7692d40..3bcbbbe35 100644 --- a/src/canonicalizer/rules/duplicate_required_values.h +++ b/src/canonicalizer/rules/duplicate_required_values.h @@ -1,12 +1,8 @@ class DuplicateRequiredValues final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::false_type; DuplicateRequiredValues() - : SchemaTransformRule{ - "duplicate_required_values", - "Setting duplicate values in `required` is considered an " - "anti-pattern"} {}; + : SchemaTransformRule{"duplicate_required_values"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class DuplicateRequiredValues final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -31,7 +26,7 @@ class DuplicateRequiredValues final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto collection = schema.at("required"); std::sort(collection.as_array().begin(), collection.as_array().end()); auto last = diff --git a/src/canonicalizer/rules/dynamic_ref_to_static_ref.h b/src/canonicalizer/rules/dynamic_ref_to_static_ref.h index 8adf1d236..5ef592990 100644 --- a/src/canonicalizer/rules/dynamic_ref_to_static_ref.h +++ b/src/canonicalizer/rules/dynamic_ref_to_static_ref.h @@ -6,13 +6,8 @@ class DynamicRefToStaticRef final : public SchemaTransformRule { static inline const std::string KEYWORD_RECURSIVE_REF{"$recursiveRef"}; public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - DynamicRefToStaticRef() - : SchemaTransformRule{ - "dynamic_ref_to_static_ref", - "A dynamic reference whose destination is unambiguous can be " - "expressed as a static reference"} {}; + DynamicRefToStaticRef() : SchemaTransformRule{"dynamic_ref_to_static_ref"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -21,8 +16,7 @@ class DynamicRefToStaticRef final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(schema.is_object() && !schema.defines("$ref")); if (vocabularies.contains(Vocabularies::Known::JSON_Schema_2020_12_Core) && @@ -110,8 +104,7 @@ class DynamicRefToStaticRef final : public SchemaTransformRule { return false; } - auto transform(sourcemeta::core::JSON &schema, const Result &) const - -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { assert(this->keyword_ != nullptr); schema.rename(*this->keyword_, "$ref"); } diff --git a/src/canonicalizer/rules/else_without_if.h b/src/canonicalizer/rules/else_without_if.h index 68452514b..6e2a913a2 100644 --- a/src/canonicalizer/rules/else_without_if.h +++ b/src/canonicalizer/rules/else_without_if.h @@ -4,12 +4,8 @@ class ElseWithoutIf final : public SchemaTransformRule { static inline const std::string KEYWORD{"else"}; public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - ElseWithoutIf() - : SchemaTransformRule{"else_without_if", - "The `else` keyword is meaningless " - "without the presence of the `if` keyword"} {}; + ElseWithoutIf() : SchemaTransformRule{"else_without_if"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -18,8 +14,7 @@ class ElseWithoutIf final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -27,11 +22,12 @@ class ElseWithoutIf final : public SchemaTransformRule { schema.is_object() && schema.defines(KEYWORD) && !schema.defines("if")); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase(KEYWORD); } }; diff --git a/src/canonicalizer/rules/empty_definitions_drop.h b/src/canonicalizer/rules/empty_definitions_drop.h index a2fff0e0b..efb8fbfea 100644 --- a/src/canonicalizer/rules/empty_definitions_drop.h +++ b/src/canonicalizer/rules/empty_definitions_drop.h @@ -1,8 +1,7 @@ class EmptyDefinitionsDrop final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - EmptyDefinitionsDrop() : SchemaTransformRule{"empty_definitions_drop", ""} {}; + EmptyDefinitionsDrop() : SchemaTransformRule{"empty_definitions_drop"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class EmptyDefinitionsDrop final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_4, Vocabularies::Known::JSON_Schema_Draft_6, @@ -25,7 +23,7 @@ class EmptyDefinitionsDrop final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("definitions"); } }; diff --git a/src/canonicalizer/rules/empty_defs_drop.h b/src/canonicalizer/rules/empty_defs_drop.h index ad0e80eb0..f6da47a11 100644 --- a/src/canonicalizer/rules/empty_defs_drop.h +++ b/src/canonicalizer/rules/empty_defs_drop.h @@ -1,8 +1,7 @@ class EmptyDefsDrop final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - EmptyDefsDrop() : SchemaTransformRule{"empty_defs_drop", ""} {}; + EmptyDefsDrop() : SchemaTransformRule{"empty_defs_drop"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class EmptyDefsDrop final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2019_09_Core, Vocabularies::Known::JSON_Schema_2020_12_Core}) && @@ -23,7 +21,7 @@ class EmptyDefsDrop final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("$defs"); } }; diff --git a/src/canonicalizer/rules/empty_dependencies_drop.h b/src/canonicalizer/rules/empty_dependencies_drop.h index 249bdb7b5..0cbe43085 100644 --- a/src/canonicalizer/rules/empty_dependencies_drop.h +++ b/src/canonicalizer/rules/empty_dependencies_drop.h @@ -1,9 +1,7 @@ class EmptyDependenciesDrop final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - EmptyDependenciesDrop() - : SchemaTransformRule{"empty_dependencies_drop", ""} {}; + EmptyDependenciesDrop() : SchemaTransformRule{"empty_dependencies_drop"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +10,7 @@ class EmptyDependenciesDrop final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_4, @@ -27,7 +24,7 @@ class EmptyDependenciesDrop final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("dependencies"); } }; diff --git a/src/canonicalizer/rules/empty_dependent_required_drop.h b/src/canonicalizer/rules/empty_dependent_required_drop.h index 6e04d1fa8..55671c60a 100644 --- a/src/canonicalizer/rules/empty_dependent_required_drop.h +++ b/src/canonicalizer/rules/empty_dependent_required_drop.h @@ -1,9 +1,8 @@ class EmptyDependentRequiredDrop final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; EmptyDependentRequiredDrop() - : SchemaTransformRule{"empty_dependent_required_drop", ""} {}; + : SchemaTransformRule{"empty_dependent_required_drop"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class EmptyDependentRequiredDrop final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -26,7 +24,7 @@ class EmptyDependentRequiredDrop final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("dependentRequired"); } }; diff --git a/src/canonicalizer/rules/empty_dependent_schemas_drop.h b/src/canonicalizer/rules/empty_dependent_schemas_drop.h index 794fb530b..302bac234 100644 --- a/src/canonicalizer/rules/empty_dependent_schemas_drop.h +++ b/src/canonicalizer/rules/empty_dependent_schemas_drop.h @@ -1,9 +1,8 @@ class EmptyDependentSchemasDrop final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; EmptyDependentSchemasDrop() - : SchemaTransformRule{"empty_dependent_schemas_drop", ""} {}; + : SchemaTransformRule{"empty_dependent_schemas_drop"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class EmptyDependentSchemasDrop final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -26,7 +24,7 @@ class EmptyDependentSchemasDrop final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("dependentSchemas"); } }; diff --git a/src/canonicalizer/rules/empty_disallow_drop.h b/src/canonicalizer/rules/empty_disallow_drop.h index 429e85c7f..6aad634ad 100644 --- a/src/canonicalizer/rules/empty_disallow_drop.h +++ b/src/canonicalizer/rules/empty_disallow_drop.h @@ -1,8 +1,7 @@ class EmptyDisallowDrop final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - EmptyDisallowDrop() : SchemaTransformRule{"empty_disallow_drop", ""} {}; + EmptyDisallowDrop() : SchemaTransformRule{"empty_disallow_drop"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class EmptyDisallowDrop final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper}) && @@ -23,7 +21,7 @@ class EmptyDisallowDrop final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("disallow"); } }; diff --git a/src/canonicalizer/rules/empty_object_as_true.h b/src/canonicalizer/rules/empty_object_as_true.h index 30b12ca7f..d3e929cfb 100644 --- a/src/canonicalizer/rules/empty_object_as_true.h +++ b/src/canonicalizer/rules/empty_object_as_true.h @@ -1,12 +1,7 @@ class EmptyObjectAsTrue final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::false_type; - EmptyObjectAsTrue() - : SchemaTransformRule{ - "empty_object_as_true", - "The empty schema `{}` accepts all values and is equivalent to the " - "boolean schema `true`"} {}; + EmptyObjectAsTrue() : SchemaTransformRule{"empty_object_as_true"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +10,7 @@ class EmptyObjectAsTrue final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Core, Vocabularies::Known::JSON_Schema_2019_09_Core, @@ -27,7 +21,7 @@ class EmptyObjectAsTrue final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - schema.into(JSON{true}); + auto transform(sourcemeta::core::JSON &schema) const -> void override { + schema.into(sourcemeta::core::JSON{true}); } }; diff --git a/src/canonicalizer/rules/enum_drop_redundant_validation.h b/src/canonicalizer/rules/enum_drop_redundant_validation.h index b92335042..b2a40ac51 100644 --- a/src/canonicalizer/rules/enum_drop_redundant_validation.h +++ b/src/canonicalizer/rules/enum_drop_redundant_validation.h @@ -1,9 +1,8 @@ class EnumDropRedundantValidation final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; EnumDropRedundantValidation() - : SchemaTransformRule{"enum_drop_redundant_validation", ""} {}; + : SchemaTransformRule{"enum_drop_redundant_validation"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class EnumDropRedundantValidation final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_0, @@ -86,7 +84,8 @@ class EnumDropRedundantValidation final : public SchemaTransformRule { if (entry.second.is_boolean() && entry.second.to_boolean()) { if (!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(entry.first)})) { + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(entry.first)})) { this->keywords_.emplace_back(entry.first); } continue; @@ -98,7 +97,8 @@ class EnumDropRedundantValidation final : public SchemaTransformRule { } if (!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(entry.first)})) { + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(entry.first)})) { this->wrap_keywords_.emplace_back(entry.first); } } @@ -107,7 +107,7 @@ class EnumDropRedundantValidation final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { for (const auto &keyword : this->keywords_) { schema.erase(keyword); } @@ -116,9 +116,9 @@ class EnumDropRedundantValidation final : public SchemaTransformRule { return; } - auto new_allof{JSON::make_array()}; + auto new_allof{sourcemeta::core::JSON::make_array()}; for (const auto &keyword : this->wrap_keywords_) { - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign(keyword, schema.at(keyword)); if (keyword == "if" && this->has_if_group_) { if (schema.defines("then")) { @@ -140,7 +140,7 @@ class EnumDropRedundantValidation final : public SchemaTransformRule { } } - auto enum_branch{JSON::make_object()}; + auto enum_branch{sourcemeta::core::JSON::make_object()}; enum_branch.assign("enum", schema.at("enum")); schema.erase("enum"); new_allof.push_back(std::move(enum_branch)); @@ -150,8 +150,8 @@ class EnumDropRedundantValidation final : public SchemaTransformRule { } private: - mutable std::vector keywords_; - mutable std::vector wrap_keywords_; + mutable std::vector keywords_; + mutable std::vector wrap_keywords_; mutable bool has_if_group_{false}; mutable bool is_pre_draft4_{false}; }; diff --git a/src/canonicalizer/rules/enum_filter_by_type.h b/src/canonicalizer/rules/enum_filter_by_type.h index 685ccc1ad..1ed2326ec 100644 --- a/src/canonicalizer/rules/enum_filter_by_type.h +++ b/src/canonicalizer/rules/enum_filter_by_type.h @@ -1,8 +1,7 @@ class EnumFilterByType final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - EnumFilterByType() : SchemaTransformRule{"enum_filter_by_type", ""} {}; + EnumFilterByType() : SchemaTransformRule{"enum_filter_by_type"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class EnumFilterByType final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_0, @@ -40,7 +38,8 @@ class EnumFilterByType final : public SchemaTransformRule { Vocabularies::Known::JSON_Schema_Draft_7, Vocabularies::Known::JSON_Schema_2019_09_Validation, Vocabularies::Known::JSON_Schema_2020_12_Validation}) && - declared_types.test(std::to_underlying(JSON::Type::Integer))}; + declared_types.test( + std::to_underlying(sourcemeta::core::JSON::Type::Integer))}; this->matching_indices_.clear(); bool has_mismatch{false}; @@ -61,8 +60,8 @@ class EnumFilterByType final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - auto filtered{JSON::make_array()}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + auto filtered{sourcemeta::core::JSON::make_array()}; for (const auto &index : this->matching_indices_) { filtered.push_back(schema.at("enum").at(index)); } diff --git a/src/canonicalizer/rules/enum_split_by_type.h b/src/canonicalizer/rules/enum_split_by_type.h index 67c3213aa..997872c42 100644 --- a/src/canonicalizer/rules/enum_split_by_type.h +++ b/src/canonicalizer/rules/enum_split_by_type.h @@ -1,13 +1,7 @@ class EnumSplitByType final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - EnumSplitByType() - : SchemaTransformRule{ - "enum_split_by_type", - "An `enum` whose values span more than one type is the disjunction " - "of its single-type subsets, so it splits into a union of " - "single-type enums"} {}; + EnumSplitByType() : SchemaTransformRule{"enum_split_by_type"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -16,8 +10,7 @@ class EnumSplitByType final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { const bool any_of_dialect{ vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_4, Vocabularies::Known::JSON_Schema_Draft_6, @@ -42,7 +35,7 @@ class EnumSplitByType final : public SchemaTransformRule { ONLY_CONTINUE_IF(enumeration && enumeration->is_array() && !enumeration->empty()); - JSON::TypeSet kinds; + sourcemeta::core::JSON::TypeSet kinds; for (const auto &value : enumeration->as_array()) { kinds.set(static_cast(kind_of(value))); } @@ -60,8 +53,8 @@ class EnumSplitByType final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - auto branches{JSON::make_array()}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + auto branches{sourcemeta::core::JSON::make_array()}; for (const auto &value : schema.at("enum").as_array()) { const auto kind{kind_of(value)}; bool merged{false}; @@ -74,9 +67,9 @@ class EnumSplitByType final : public SchemaTransformRule { } if (!merged) { - auto values{JSON::make_array()}; + auto values{sourcemeta::core::JSON::make_array()}; values.push_back(value); - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign("enum", std::move(values)); branches.push_back(std::move(branch)); } diff --git a/src/canonicalizer/rules/enum_with_type.h b/src/canonicalizer/rules/enum_with_type.h index 23ff79458..09d2b3556 100644 --- a/src/canonicalizer/rules/enum_with_type.h +++ b/src/canonicalizer/rules/enum_with_type.h @@ -1,12 +1,7 @@ class EnumWithType final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - EnumWithType() - : SchemaTransformRule{ - "enum_with_type", - "Setting `type` alongside `enum` is considered an anti-pattern, as " - "the enumeration choices already imply their respective types"} {}; + EnumWithType() : SchemaTransformRule{"enum_with_type"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +10,7 @@ class EnumWithType final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -72,7 +66,8 @@ class EnumWithType final : public SchemaTransformRule { const bool integer_matches_integral{ vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_6, Vocabularies::Known::JSON_Schema_Draft_7}) && - current_types.test(std::to_underlying(JSON::Type::Integer))}; + current_types.test( + std::to_underlying(sourcemeta::core::JSON::Type::Integer))}; ONLY_CONTINUE_IF(std::ranges::all_of( enum_value->as_array(), [¤t_types, integer_matches_integral](const auto &item) -> auto { @@ -83,7 +78,7 @@ class EnumWithType final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("type"); } }; diff --git a/src/canonicalizer/rules/equal_numeric_bounds_to_const.h b/src/canonicalizer/rules/equal_numeric_bounds_to_const.h index b39286cc3..3de7bcfcc 100644 --- a/src/canonicalizer/rules/equal_numeric_bounds_to_const.h +++ b/src/canonicalizer/rules/equal_numeric_bounds_to_const.h @@ -1,12 +1,8 @@ class EqualNumericBoundsToConst final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; EqualNumericBoundsToConst() - : SchemaTransformRule{ - "equal_numeric_bounds_to_const", - "Setting `minimum` and `maximum` to the same number only leaves " - "one possible value"} {}; + : SchemaTransformRule{"equal_numeric_bounds_to_const"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class EqualNumericBoundsToConst final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any({ Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -44,7 +39,7 @@ class EqualNumericBoundsToConst final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.rename("minimum", "const"); schema.erase("type"); schema.erase("maximum"); diff --git a/src/canonicalizer/rules/equal_numeric_bounds_to_enum.h b/src/canonicalizer/rules/equal_numeric_bounds_to_enum.h index 1fbe72219..245aacbfd 100644 --- a/src/canonicalizer/rules/equal_numeric_bounds_to_enum.h +++ b/src/canonicalizer/rules/equal_numeric_bounds_to_enum.h @@ -1,12 +1,8 @@ class EqualNumericBoundsToEnum final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; EqualNumericBoundsToEnum() - : SchemaTransformRule{ - "equal_numeric_bounds_to_enum", - "Setting `minimum` and `maximum` to the same number only leaves " - "one possible value"} {}; + : SchemaTransformRule{"equal_numeric_bounds_to_enum"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class EqualNumericBoundsToEnum final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_4, Vocabularies::Known::JSON_Schema_Draft_3, @@ -50,7 +45,7 @@ class EqualNumericBoundsToEnum final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { sourcemeta::core::JSON values = sourcemeta::core::JSON::make_array(); values.push_back(schema.at("minimum")); schema.assign("enum", std::move(values)); diff --git a/src/canonicalizer/rules/exclusive_bounds_false_drop.h b/src/canonicalizer/rules/exclusive_bounds_false_drop.h index 6658bc36e..1309b4cf8 100644 --- a/src/canonicalizer/rules/exclusive_bounds_false_drop.h +++ b/src/canonicalizer/rules/exclusive_bounds_false_drop.h @@ -1,12 +1,8 @@ class ExclusiveBoundsFalseDrop final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; ExclusiveBoundsFalseDrop() - : SchemaTransformRule{ - "exclusive_bounds_false_drop", - "Setting `exclusiveMinimum` or `exclusiveMaximum` to `false` " - "adds no constraint"} {}; + : SchemaTransformRule{"exclusive_bounds_false_drop"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class ExclusiveBoundsFalseDrop final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper, @@ -28,16 +23,16 @@ class ExclusiveBoundsFalseDrop final : public SchemaTransformRule { type && type->is_string() && (type->to_string() == "integer" || type->to_string() == "number")); - std::vector locations; + std::vector locations; const auto *exclusive_min{schema.try_at("exclusiveMinimum")}; if (exclusive_min && exclusive_min->is_boolean() && !exclusive_min->to_boolean()) { - locations.push_back(Pointer{"exclusiveMinimum"}); + locations.push_back(sourcemeta::core::Pointer{"exclusiveMinimum"}); } const auto *exclusive_max{schema.try_at("exclusiveMaximum")}; if (exclusive_max && exclusive_max->is_boolean() && !exclusive_max->to_boolean()) { - locations.push_back(Pointer{"exclusiveMaximum"}); + locations.push_back(sourcemeta::core::Pointer{"exclusiveMaximum"}); } ONLY_CONTINUE_IF(!locations.empty()); @@ -45,7 +40,7 @@ class ExclusiveBoundsFalseDrop final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { for (const auto &location : this->locations_) { schema.erase(location.at(0).to_property()); } diff --git a/src/canonicalizer/rules/exclusive_maximum_boolean_integer_fold.h b/src/canonicalizer/rules/exclusive_maximum_boolean_integer_fold.h index 585e8dd28..fdf36990d 100644 --- a/src/canonicalizer/rules/exclusive_maximum_boolean_integer_fold.h +++ b/src/canonicalizer/rules/exclusive_maximum_boolean_integer_fold.h @@ -1,9 +1,8 @@ class ExclusiveMaximumBooleanIntegerFold final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; ExclusiveMaximumBooleanIntegerFold() - : SchemaTransformRule{"exclusive_maximum_boolean_integer_fold", ""} {}; + : SchemaTransformRule{"exclusive_maximum_boolean_integer_fold"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class ExclusiveMaximumBooleanIntegerFold final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_4}) && @@ -30,7 +28,7 @@ class ExclusiveMaximumBooleanIntegerFold final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { const auto &maximum{schema.at("maximum")}; if (maximum.is_integer()) { if (maximum.to_integer() > std::numeric_limits::min()) { diff --git a/src/canonicalizer/rules/exclusive_maximum_integer_to_maximum.h b/src/canonicalizer/rules/exclusive_maximum_integer_to_maximum.h index 54b3c28ca..1092beb08 100644 --- a/src/canonicalizer/rules/exclusive_maximum_integer_to_maximum.h +++ b/src/canonicalizer/rules/exclusive_maximum_integer_to_maximum.h @@ -1,12 +1,8 @@ class ExclusiveMaximumIntegerToMaximum final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; ExclusiveMaximumIntegerToMaximum() - : SchemaTransformRule{ - "exclusive_maximum_integer_to_maximum", - "Setting `exclusiveMaximum` when `type` is `integer` is syntax " - "sugar for `maximum`"} {}; + : SchemaTransformRule{"exclusive_maximum_integer_to_maximum"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class ExclusiveMaximumIntegerToMaximum final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -32,7 +27,7 @@ class ExclusiveMaximumIntegerToMaximum final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { if (schema.at("exclusiveMaximum").is_integer()) { if (schema.at("exclusiveMaximum").to_integer() > std::numeric_limits::min()) { diff --git a/src/canonicalizer/rules/exclusive_maximum_number_and_maximum.h b/src/canonicalizer/rules/exclusive_maximum_number_and_maximum.h index 547b4cd28..d288427d9 100644 --- a/src/canonicalizer/rules/exclusive_maximum_number_and_maximum.h +++ b/src/canonicalizer/rules/exclusive_maximum_number_and_maximum.h @@ -1,12 +1,8 @@ class ExclusiveMaximumNumberAndMaximum final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; ExclusiveMaximumNumberAndMaximum() - : SchemaTransformRule{ - "exclusive_maximum_number_and_maximum", - "Setting both `exclusiveMaximum` and `maximum` at the same time " - "is considered an anti-pattern. You should choose one"} {}; + : SchemaTransformRule{"exclusive_maximum_number_and_maximum"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class ExclusiveMaximumNumberAndMaximum final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -31,7 +26,7 @@ class ExclusiveMaximumNumberAndMaximum final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { if (schema.at("maximum") < schema.at("exclusiveMaximum")) { schema.erase("exclusiveMaximum"); } else { diff --git a/src/canonicalizer/rules/exclusive_minimum_boolean_integer_fold.h b/src/canonicalizer/rules/exclusive_minimum_boolean_integer_fold.h index b16a78d93..af96a4f9b 100644 --- a/src/canonicalizer/rules/exclusive_minimum_boolean_integer_fold.h +++ b/src/canonicalizer/rules/exclusive_minimum_boolean_integer_fold.h @@ -1,9 +1,8 @@ class ExclusiveMinimumBooleanIntegerFold final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; ExclusiveMinimumBooleanIntegerFold() - : SchemaTransformRule{"exclusive_minimum_boolean_integer_fold", ""} {}; + : SchemaTransformRule{"exclusive_minimum_boolean_integer_fold"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class ExclusiveMinimumBooleanIntegerFold final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_4}) && @@ -30,7 +28,7 @@ class ExclusiveMinimumBooleanIntegerFold final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { const auto &minimum{schema.at("minimum")}; if (minimum.is_integer()) { if (minimum.to_integer() < std::numeric_limits::max()) { diff --git a/src/canonicalizer/rules/exclusive_minimum_integer_to_minimum.h b/src/canonicalizer/rules/exclusive_minimum_integer_to_minimum.h index 0807f0e41..9c5aa8220 100644 --- a/src/canonicalizer/rules/exclusive_minimum_integer_to_minimum.h +++ b/src/canonicalizer/rules/exclusive_minimum_integer_to_minimum.h @@ -1,12 +1,8 @@ class ExclusiveMinimumIntegerToMinimum final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; ExclusiveMinimumIntegerToMinimum() - : SchemaTransformRule{ - "exclusive_minimum_integer_to_minimum", - "Setting `exclusiveMinimum` when `type` is `integer` is syntax " - "sugar for `minimum`"} {}; + : SchemaTransformRule{"exclusive_minimum_integer_to_minimum"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class ExclusiveMinimumIntegerToMinimum final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -32,7 +27,7 @@ class ExclusiveMinimumIntegerToMinimum final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { if (schema.at("exclusiveMinimum").is_integer()) { if (schema.at("exclusiveMinimum").to_integer() < std::numeric_limits::max()) { diff --git a/src/canonicalizer/rules/exclusive_minimum_number_and_minimum.h b/src/canonicalizer/rules/exclusive_minimum_number_and_minimum.h index 51229ad03..b8c47952f 100644 --- a/src/canonicalizer/rules/exclusive_minimum_number_and_minimum.h +++ b/src/canonicalizer/rules/exclusive_minimum_number_and_minimum.h @@ -1,12 +1,8 @@ class ExclusiveMinimumNumberAndMinimum final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; ExclusiveMinimumNumberAndMinimum() - : SchemaTransformRule{ - "exclusive_minimum_number_and_minimum", - "Setting both `exclusiveMinimum` and `minimum` at the same time " - "is considered an anti-pattern. You should choose one"} {}; + : SchemaTransformRule{"exclusive_minimum_number_and_minimum"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class ExclusiveMinimumNumberAndMinimum final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -31,7 +26,7 @@ class ExclusiveMinimumNumberAndMinimum final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { if (schema.at("exclusiveMinimum") < schema.at("minimum")) { schema.erase("exclusiveMinimum"); } else { diff --git a/src/canonicalizer/rules/extends_to_array.h b/src/canonicalizer/rules/extends_to_array.h index a6b2b951e..ff5a26b40 100644 --- a/src/canonicalizer/rules/extends_to_array.h +++ b/src/canonicalizer/rules/extends_to_array.h @@ -1,8 +1,7 @@ class ExtendsToArray final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - ExtendsToArray() : SchemaTransformRule{"extends_to_array", ""} {}; + ExtendsToArray() : SchemaTransformRule{"extends_to_array"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class ExtendsToArray final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_0, Vocabularies::Known::JSON_Schema_Draft_1, @@ -25,17 +23,19 @@ class ExtendsToArray final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto array{sourcemeta::core::JSON::make_array()}; array.push_back(schema.at("extends")); schema.assign("extends", std::move(array)); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { - return target.rebase(current.concat("extends"), - current.concat(Pointer{"extends", 0})); + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { + return target.rebase( + current.concat("extends"), + current.concat(sourcemeta::core::Pointer{"extends", 0})); } }; diff --git a/src/canonicalizer/rules/flatten_nested_allof.h b/src/canonicalizer/rules/flatten_nested_allof.h index a331e4bce..74f0c2bbe 100644 --- a/src/canonicalizer/rules/flatten_nested_allof.h +++ b/src/canonicalizer/rules/flatten_nested_allof.h @@ -1,12 +1,7 @@ class FlattenNestedAllOf final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - FlattenNestedAllOf() - : SchemaTransformRule{ - "flatten_nested_allof", - "An `allOf` branch that only contains another `allOf` can " - "be flattened into the parent `allOf`"} {}; + FlattenNestedAllOf() : SchemaTransformRule{"flatten_nested_allof"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,9 +10,8 @@ class FlattenNestedAllOf final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"allOf"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"allOf"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -39,15 +33,16 @@ class FlattenNestedAllOf final : public SchemaTransformRule { ONLY_CONTINUE_IF(!this->flatten_indices_.empty()); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); return true; } - auto transform(JSON &schema, const Result &) const -> void override { - static const JSON::String KEYWORD{"allOf"}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + static const sourcemeta::core::JSON::String KEYWORD{"allOf"}; this->index_mapping_.clear(); const auto &original{schema.at(KEYWORD)}; - auto result{JSON::make_array()}; + auto result{sourcemeta::core::JSON::make_array()}; std::size_t new_index{0}; std::size_t flatten_cursor{0}; @@ -67,11 +62,12 @@ class FlattenNestedAllOf final : public SchemaTransformRule { schema.assign(KEYWORD, std::move(result)); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { - static const JSON::String KEYWORD{"allOf"}; + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { + static const sourcemeta::core::JSON::String KEYWORD{"allOf"}; const auto prefix{current.concat(KEYWORD)}; if (!target.starts_with(prefix)) { return target; @@ -83,15 +79,15 @@ class FlattenNestedAllOf final : public SchemaTransformRule { const auto old_index{relative.at(0).to_index()}; for (const auto &[outer, inner, mapped] : this->index_mapping_) { if (outer == old_index && inner.has_value()) { - const Pointer old_prefix{ + const sourcemeta::core::Pointer old_prefix{ prefix.concat({old_index, KEYWORD, inner.value()})}; if (target.starts_with(old_prefix)) { - const Pointer new_prefix{prefix.concat(mapped)}; + const sourcemeta::core::Pointer new_prefix{prefix.concat(mapped)}; return target.rebase(old_prefix, new_prefix); } } else if (outer == old_index) { - const Pointer old_prefix{prefix.concat(old_index)}; - const Pointer new_prefix{prefix.concat(mapped)}; + const sourcemeta::core::Pointer old_prefix{prefix.concat(old_index)}; + const sourcemeta::core::Pointer new_prefix{prefix.concat(mapped)}; return target.rebase(old_prefix, new_prefix); } } @@ -99,8 +95,9 @@ class FlattenNestedAllOf final : public SchemaTransformRule { } private: - auto collect_leaves_(const JSON &node, const JSON::String &keyword, - std::size_t outer_index, JSON &result, + auto collect_leaves_(const sourcemeta::core::JSON &node, + const sourcemeta::core::JSON::String &keyword, + std::size_t outer_index, sourcemeta::core::JSON &result, std::size_t &new_index) const -> void { const auto &inner{node.at(keyword)}; for (std::size_t inner_index = 0; inner_index < inner.size(); diff --git a/src/canonicalizer/rules/flatten_nested_anyof.h b/src/canonicalizer/rules/flatten_nested_anyof.h index f358290ce..207ba1054 100644 --- a/src/canonicalizer/rules/flatten_nested_anyof.h +++ b/src/canonicalizer/rules/flatten_nested_anyof.h @@ -1,12 +1,7 @@ class FlattenNestedAnyOf final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - FlattenNestedAnyOf() - : SchemaTransformRule{ - "flatten_nested_anyof", - "An `anyOf` branch that only contains another `anyOf` can " - "be flattened into the parent `anyOf`"} {}; + FlattenNestedAnyOf() : SchemaTransformRule{"flatten_nested_anyof"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,9 +10,8 @@ class FlattenNestedAnyOf final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"anyOf"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"anyOf"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -39,15 +33,16 @@ class FlattenNestedAnyOf final : public SchemaTransformRule { ONLY_CONTINUE_IF(!this->flatten_indices_.empty()); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); return true; } - auto transform(JSON &schema, const Result &) const -> void override { - static const JSON::String KEYWORD{"anyOf"}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + static const sourcemeta::core::JSON::String KEYWORD{"anyOf"}; this->index_mapping_.clear(); const auto &original{schema.at(KEYWORD)}; - auto result{JSON::make_array()}; + auto result{sourcemeta::core::JSON::make_array()}; std::size_t new_index{0}; std::size_t flatten_cursor{0}; @@ -67,11 +62,12 @@ class FlattenNestedAnyOf final : public SchemaTransformRule { schema.assign(KEYWORD, std::move(result)); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { - static const JSON::String KEYWORD{"anyOf"}; + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { + static const sourcemeta::core::JSON::String KEYWORD{"anyOf"}; const auto prefix{current.concat(KEYWORD)}; if (!target.starts_with(prefix)) { return target; @@ -83,15 +79,15 @@ class FlattenNestedAnyOf final : public SchemaTransformRule { const auto old_index{relative.at(0).to_index()}; for (const auto &[outer, inner, mapped] : this->index_mapping_) { if (outer == old_index && inner.has_value()) { - const Pointer old_prefix{ + const sourcemeta::core::Pointer old_prefix{ prefix.concat({old_index, KEYWORD, inner.value()})}; if (target.starts_with(old_prefix)) { - const Pointer new_prefix{prefix.concat(mapped)}; + const sourcemeta::core::Pointer new_prefix{prefix.concat(mapped)}; return target.rebase(old_prefix, new_prefix); } } else if (outer == old_index) { - const Pointer old_prefix{prefix.concat(old_index)}; - const Pointer new_prefix{prefix.concat(mapped)}; + const sourcemeta::core::Pointer old_prefix{prefix.concat(old_index)}; + const sourcemeta::core::Pointer new_prefix{prefix.concat(mapped)}; return target.rebase(old_prefix, new_prefix); } } @@ -99,8 +95,9 @@ class FlattenNestedAnyOf final : public SchemaTransformRule { } private: - auto collect_leaves_(const JSON &node, const JSON::String &keyword, - std::size_t outer_index, JSON &result, + auto collect_leaves_(const sourcemeta::core::JSON &node, + const sourcemeta::core::JSON::String &keyword, + std::size_t outer_index, sourcemeta::core::JSON &result, std::size_t &new_index) const -> void { const auto &inner{node.at(keyword)}; for (std::size_t inner_index = 0; inner_index < inner.size(); diff --git a/src/canonicalizer/rules/flatten_nested_extends.h b/src/canonicalizer/rules/flatten_nested_extends.h index 7ac67a6bf..f71d314c3 100644 --- a/src/canonicalizer/rules/flatten_nested_extends.h +++ b/src/canonicalizer/rules/flatten_nested_extends.h @@ -1,12 +1,7 @@ class FlattenNestedExtends final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - FlattenNestedExtends() - : SchemaTransformRule{ - "flatten_nested_extends", - "An `extends` branch that only contains another `extends` can " - "be flattened into the parent `extends`"} {}; + FlattenNestedExtends() : SchemaTransformRule{"flatten_nested_extends"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,9 +10,8 @@ class FlattenNestedExtends final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"extends"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"extends"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper}) && @@ -36,15 +30,16 @@ class FlattenNestedExtends final : public SchemaTransformRule { ONLY_CONTINUE_IF(!this->flatten_indices_.empty()); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); return true; } - auto transform(JSON &schema, const Result &) const -> void override { - static const JSON::String KEYWORD{"extends"}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + static const sourcemeta::core::JSON::String KEYWORD{"extends"}; this->index_mapping_.clear(); const auto &original{schema.at(KEYWORD)}; - auto result{JSON::make_array()}; + auto result{sourcemeta::core::JSON::make_array()}; std::size_t new_index{0}; std::size_t flatten_cursor{0}; @@ -64,11 +59,12 @@ class FlattenNestedExtends final : public SchemaTransformRule { schema.assign(KEYWORD, std::move(result)); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { - static const JSON::String KEYWORD{"extends"}; + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { + static const sourcemeta::core::JSON::String KEYWORD{"extends"}; const auto prefix{current.concat(KEYWORD)}; if (!target.starts_with(prefix)) { return target; @@ -80,15 +76,15 @@ class FlattenNestedExtends final : public SchemaTransformRule { const auto old_index{relative.at(0).to_index()}; for (const auto &[outer, inner, mapped] : this->index_mapping_) { if (outer == old_index && inner.has_value()) { - const Pointer old_prefix{ + const sourcemeta::core::Pointer old_prefix{ prefix.concat({old_index, KEYWORD, inner.value()})}; if (target.starts_with(old_prefix)) { - const Pointer new_prefix{prefix.concat(mapped)}; + const sourcemeta::core::Pointer new_prefix{prefix.concat(mapped)}; return target.rebase(old_prefix, new_prefix); } } else if (outer == old_index) { - const Pointer old_prefix{prefix.concat(old_index)}; - const Pointer new_prefix{prefix.concat(mapped)}; + const sourcemeta::core::Pointer old_prefix{prefix.concat(old_index)}; + const sourcemeta::core::Pointer new_prefix{prefix.concat(mapped)}; return target.rebase(old_prefix, new_prefix); } } @@ -96,8 +92,9 @@ class FlattenNestedExtends final : public SchemaTransformRule { } private: - auto collect_leaves_(const JSON &node, const JSON::String &keyword, - std::size_t outer_index, JSON &result, + auto collect_leaves_(const sourcemeta::core::JSON &node, + const sourcemeta::core::JSON::String &keyword, + std::size_t outer_index, sourcemeta::core::JSON &result, std::size_t &new_index) const -> void { const auto &inner{node.at(keyword)}; for (std::size_t inner_index = 0; inner_index < inner.size(); diff --git a/src/canonicalizer/rules/if_then_else_implicit.h b/src/canonicalizer/rules/if_then_else_implicit.h index 0a2658adc..8398c42d0 100644 --- a/src/canonicalizer/rules/if_then_else_implicit.h +++ b/src/canonicalizer/rules/if_then_else_implicit.h @@ -1,8 +1,7 @@ class IfThenElseImplicit final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - IfThenElseImplicit() : SchemaTransformRule{"if_then_else_implicit", ""} {}; + IfThenElseImplicit() : SchemaTransformRule{"if_then_else_implicit"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class IfThenElseImplicit final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_7, @@ -24,12 +22,12 @@ class IfThenElseImplicit final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { if (!schema.defines("then")) { - schema.assign("then", JSON{true}); + schema.assign("then", sourcemeta::core::JSON{true}); } if (!schema.defines("else")) { - schema.assign("else", JSON{true}); + schema.assign("else", sourcemeta::core::JSON{true}); } } }; diff --git a/src/canonicalizer/rules/if_without_then_else.h b/src/canonicalizer/rules/if_without_then_else.h index e5bccf506..7c273fc1f 100644 --- a/src/canonicalizer/rules/if_without_then_else.h +++ b/src/canonicalizer/rules/if_without_then_else.h @@ -4,13 +4,8 @@ class IfWithoutThenElse final : public SchemaTransformRule { static inline const std::string KEYWORD{"if"}; public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - IfWithoutThenElse() - : SchemaTransformRule{ - "if_without_then_else", - "The `if` keyword is meaningless " - "without the presence of the `then` or `else` keywords"} {}; + IfWithoutThenElse() : SchemaTransformRule{"if_without_then_else"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -19,8 +14,7 @@ class IfWithoutThenElse final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -28,11 +22,12 @@ class IfWithoutThenElse final : public SchemaTransformRule { schema.is_object() && schema.defines(KEYWORD) && !schema.defines("then") && !schema.defines("else")); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase(KEYWORD); } }; diff --git a/src/canonicalizer/rules/ignored_metaschema.h b/src/canonicalizer/rules/ignored_metaschema.h index 9ff8488b4..6b84c8fa2 100644 --- a/src/canonicalizer/rules/ignored_metaschema.h +++ b/src/canonicalizer/rules/ignored_metaschema.h @@ -1,12 +1,7 @@ class IgnoredMetaschema final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - IgnoredMetaschema() - : SchemaTransformRule{ - "ignored_metaschema", - "A `$schema` declaration without a sibling identifier (or with a " - "sibling `$ref` in Draft 7 and older dialects), is ignored"} {}; + IgnoredMetaschema() : SchemaTransformRule{"ignored_metaschema"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +10,7 @@ class IgnoredMetaschema final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(schema.is_object()); const auto *schema_keyword{schema.try_at("$schema")}; ONLY_CONTINUE_IF(schema_keyword && schema_keyword->is_string()); @@ -26,7 +20,7 @@ class IgnoredMetaschema final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("$schema"); } }; diff --git a/src/canonicalizer/rules/implicit_contains_keywords.h b/src/canonicalizer/rules/implicit_contains_keywords.h index 5c633cedc..5078c4a5b 100644 --- a/src/canonicalizer/rules/implicit_contains_keywords.h +++ b/src/canonicalizer/rules/implicit_contains_keywords.h @@ -1,9 +1,8 @@ class ImplicitContainsKeywords final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; ImplicitContainsKeywords() - : SchemaTransformRule{"implicit_contains_keywords", ""} {}; + : SchemaTransformRule{"implicit_contains_keywords"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,8 @@ class ImplicitContainsKeywords final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &resolver, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &resolver) const + -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -31,7 +30,7 @@ class ImplicitContainsKeywords final : public SchemaTransformRule { ONLY_CONTINUE_IF( !WALK_UP_IN_PLACE_APPLICATORS( root, frame, location, walker, resolver, - [](const JSON &ancestor, + [](const sourcemeta::core::JSON &ancestor, const Vocabularies &ancestor_vocabularies) -> bool { return ancestor.defines("unevaluatedItems") && ancestor_vocabularies.contains( @@ -44,7 +43,7 @@ class ImplicitContainsKeywords final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { if (!schema.defines("contains")) { schema.assign("contains", sourcemeta::core::JSON{true}); schema.assign("minContains", sourcemeta::core::JSON{0}); diff --git a/src/canonicalizer/rules/implicit_object_keywords.h b/src/canonicalizer/rules/implicit_object_keywords.h index b0bf42d83..d34f0aba2 100644 --- a/src/canonicalizer/rules/implicit_object_keywords.h +++ b/src/canonicalizer/rules/implicit_object_keywords.h @@ -1,9 +1,7 @@ class ImplicitObjectKeywords final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - ImplicitObjectKeywords() - : SchemaTransformRule{"implicit_object_keywords", ""} {}; + ImplicitObjectKeywords() : SchemaTransformRule{"implicit_object_keywords"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +10,7 @@ class ImplicitObjectKeywords final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(schema.is_object()); const auto *type{schema.try_at("type")}; @@ -32,7 +29,7 @@ class ImplicitObjectKeywords final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { // Object keywords if (this->add_pattern_properties_) { schema.assign("patternProperties", sourcemeta::core::JSON::make_object()); diff --git a/src/canonicalizer/rules/inline_single_use_ref.h b/src/canonicalizer/rules/inline_single_use_ref.h index 2ea6bf44b..b4de771ff 100644 --- a/src/canonicalizer/rules/inline_single_use_ref.h +++ b/src/canonicalizer/rules/inline_single_use_ref.h @@ -1,8 +1,7 @@ class InlineSingleUseRef final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - InlineSingleUseRef() : SchemaTransformRule{"inline_single_use_ref", ""} {}; + InlineSingleUseRef() : SchemaTransformRule{"inline_single_use_ref"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class InlineSingleUseRef final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(schema.is_object() && schema.size() == 1); const auto *ref{schema.try_at("$ref")}; @@ -94,14 +92,15 @@ class InlineSingleUseRef final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.into(std::move(this->target_copy_)); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { if (target.starts_with(this->target_pointer_)) { const auto relative{target.resolve_from(this->target_pointer_)}; return current.concat(relative); @@ -110,6 +109,6 @@ class InlineSingleUseRef final : public SchemaTransformRule { } private: - mutable Pointer target_pointer_; + mutable sourcemeta::core::Pointer target_pointer_; mutable sourcemeta::core::JSON target_copy_{sourcemeta::core::JSON{nullptr}}; }; diff --git a/src/canonicalizer/rules/items_implicit.h b/src/canonicalizer/rules/items_implicit.h index d4e88e279..c574c40d7 100644 --- a/src/canonicalizer/rules/items_implicit.h +++ b/src/canonicalizer/rules/items_implicit.h @@ -1,11 +1,7 @@ class ItemsImplicit final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - ItemsImplicit() - : SchemaTransformRule{"items_implicit", - "Every array has an implicit `items` " - "that consists of the boolean schema `true`"} {}; + ItemsImplicit() : SchemaTransformRule{"items_implicit"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,8 +10,8 @@ class ItemsImplicit final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &resolver, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &resolver) const + -> bool override { ONLY_CONTINUE_IF( ((vocabularies.contains( Vocabularies::Known::JSON_Schema_2020_12_Validation) && @@ -40,7 +36,7 @@ class ItemsImplicit final : public SchemaTransformRule { ONLY_CONTINUE_IF( !WALK_UP_IN_PLACE_APPLICATORS( root, frame, location, walker, resolver, - [](const JSON &ancestor, + [](const sourcemeta::core::JSON &ancestor, const Vocabularies &ancestor_vocabularies) -> bool { return ancestor.defines("unevaluatedItems") && ancestor_vocabularies.contains_any( @@ -52,7 +48,7 @@ class ItemsImplicit final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - schema.assign("items", JSON{true}); + auto transform(sourcemeta::core::JSON &schema) const -> void override { + schema.assign("items", sourcemeta::core::JSON{true}); } }; diff --git a/src/canonicalizer/rules/max_contains_covered_by_max_items.h b/src/canonicalizer/rules/max_contains_covered_by_max_items.h index a9cd3666d..20c773c2d 100644 --- a/src/canonicalizer/rules/max_contains_covered_by_max_items.h +++ b/src/canonicalizer/rules/max_contains_covered_by_max_items.h @@ -1,13 +1,8 @@ class MaxContainsCoveredByMaxItems final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::false_type; MaxContainsCoveredByMaxItems() - : SchemaTransformRule{ - "max_contains_covered_by_max_items", - "Setting the `maxContains` keyword to a number greater than or " - "equal to the array upper bound does not add any further " - "constraint"} {}; + : SchemaTransformRule{"max_contains_covered_by_max_items"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -16,8 +11,7 @@ class MaxContainsCoveredByMaxItems final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, @@ -32,7 +26,7 @@ class MaxContainsCoveredByMaxItems final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.assign("maxContains", schema.at("maxItems")); } }; diff --git a/src/canonicalizer/rules/max_contains_without_contains.h b/src/canonicalizer/rules/max_contains_without_contains.h index 4a5295a9e..8516b11ee 100644 --- a/src/canonicalizer/rules/max_contains_without_contains.h +++ b/src/canonicalizer/rules/max_contains_without_contains.h @@ -1,12 +1,8 @@ class MaxContainsWithoutContains final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; MaxContainsWithoutContains() - : SchemaTransformRule{"max_contains_without_contains", - "The `maxContains` keyword is meaningless " - "without the presence of the `contains` keyword"} { - }; + : SchemaTransformRule{"max_contains_without_contains"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class MaxContainsWithoutContains final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, @@ -26,7 +21,7 @@ class MaxContainsWithoutContains final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("maxContains"); } }; diff --git a/src/canonicalizer/rules/max_decimal_implicit.h b/src/canonicalizer/rules/max_decimal_implicit.h index d90985420..d56c1d2fd 100644 --- a/src/canonicalizer/rules/max_decimal_implicit.h +++ b/src/canonicalizer/rules/max_decimal_implicit.h @@ -1,8 +1,7 @@ class MaxDecimalImplicit final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - MaxDecimalImplicit() : SchemaTransformRule{"max_decimal_implicit", ""} {}; + MaxDecimalImplicit() : SchemaTransformRule{"max_decimal_implicit"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class MaxDecimalImplicit final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_0, Vocabularies::Known::JSON_Schema_Draft_1}) && @@ -24,7 +22,7 @@ class MaxDecimalImplicit final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.assign("maxDecimal", sourcemeta::core::JSON{0}); } }; diff --git a/src/canonicalizer/rules/maximum_can_equal_integer_fold.h b/src/canonicalizer/rules/maximum_can_equal_integer_fold.h index c98f20f15..936e620db 100644 --- a/src/canonicalizer/rules/maximum_can_equal_integer_fold.h +++ b/src/canonicalizer/rules/maximum_can_equal_integer_fold.h @@ -1,9 +1,8 @@ class MaximumCanEqualIntegerFold final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; MaximumCanEqualIntegerFold() - : SchemaTransformRule{"maximum_can_equal_integer_fold", ""} {}; + : SchemaTransformRule{"maximum_can_equal_integer_fold"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class MaximumCanEqualIntegerFold final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_0, Vocabularies::Known::JSON_Schema_Draft_1, @@ -31,7 +29,7 @@ class MaximumCanEqualIntegerFold final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { const auto &maximum{schema.at("maximum")}; if (maximum.is_integer()) { if (maximum.to_integer() > std::numeric_limits::min()) { diff --git a/src/canonicalizer/rules/maximum_can_equal_true_drop.h b/src/canonicalizer/rules/maximum_can_equal_true_drop.h index ee2faaa90..932c6a99e 100644 --- a/src/canonicalizer/rules/maximum_can_equal_true_drop.h +++ b/src/canonicalizer/rules/maximum_can_equal_true_drop.h @@ -1,9 +1,8 @@ class MaximumCanEqualTrueDrop final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; MaximumCanEqualTrueDrop() - : SchemaTransformRule{"maximum_can_equal_true_drop", ""} {}; + : SchemaTransformRule{"maximum_can_equal_true_drop"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class MaximumCanEqualTrueDrop final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_0, Vocabularies::Known::JSON_Schema_Draft_1, @@ -30,7 +28,7 @@ class MaximumCanEqualTrueDrop final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("maximumCanEqual"); } }; diff --git a/src/canonicalizer/rules/maximum_real_for_integer.h b/src/canonicalizer/rules/maximum_real_for_integer.h index 1167614bf..cbc3fc76d 100644 --- a/src/canonicalizer/rules/maximum_real_for_integer.h +++ b/src/canonicalizer/rules/maximum_real_for_integer.h @@ -1,12 +1,7 @@ class MaximumRealForInteger final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::false_type; - MaximumRealForInteger() - : SchemaTransformRule{ - "maximum_real_for_integer", - "If an instance is guaranteed to be an integer, setting a real " - "number upper bound is the same as a floor of that upper bound"} {}; + MaximumRealForInteger() : SchemaTransformRule{"maximum_real_for_integer"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +10,7 @@ class MaximumRealForInteger final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -38,7 +32,7 @@ class MaximumRealForInteger final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { if (schema.at("maximum").is_decimal()) { auto current{schema.at("maximum").to_decimal()}; auto new_value{current.to_integral()}; diff --git a/src/canonicalizer/rules/min_contains_without_contains.h b/src/canonicalizer/rules/min_contains_without_contains.h index 514f1fd8f..6594f2b1d 100644 --- a/src/canonicalizer/rules/min_contains_without_contains.h +++ b/src/canonicalizer/rules/min_contains_without_contains.h @@ -1,12 +1,8 @@ class MinContainsWithoutContains final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; MinContainsWithoutContains() - : SchemaTransformRule{"min_contains_without_contains", - "The `minContains` keyword is meaningless " - "without the presence of the `contains` keyword"} { - }; + : SchemaTransformRule{"min_contains_without_contains"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class MinContainsWithoutContains final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, @@ -26,7 +21,7 @@ class MinContainsWithoutContains final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("minContains"); } }; diff --git a/src/canonicalizer/rules/min_items_given_min_contains.h b/src/canonicalizer/rules/min_items_given_min_contains.h index 26bcb141b..3dc24be82 100644 --- a/src/canonicalizer/rules/min_items_given_min_contains.h +++ b/src/canonicalizer/rules/min_items_given_min_contains.h @@ -1,12 +1,8 @@ class MinItemsGivenMinContains final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; MinItemsGivenMinContains() - : SchemaTransformRule{ - "min_items_given_min_contains", - "Every array has a minimum size of zero items but may be affected " - "by `minContains`"} {}; + : SchemaTransformRule{"min_items_given_min_contains"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class MinItemsGivenMinContains final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, @@ -28,7 +23,7 @@ class MinItemsGivenMinContains final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { if (schema.defines("contains") && schema.defines("minContains") && schema.at("minContains").is_integer()) { schema.assign("minItems", sourcemeta::core::JSON{ diff --git a/src/canonicalizer/rules/min_length_implicit.h b/src/canonicalizer/rules/min_length_implicit.h index 931671832..b48921edb 100644 --- a/src/canonicalizer/rules/min_length_implicit.h +++ b/src/canonicalizer/rules/min_length_implicit.h @@ -1,11 +1,7 @@ class MinLengthImplicit final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - MinLengthImplicit() - : SchemaTransformRule{ - "min_length_implicit", - "Every string has a minimum length of zero characters"} {}; + MinLengthImplicit() : SchemaTransformRule{"min_length_implicit"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,8 +10,7 @@ class MinLengthImplicit final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -34,7 +29,7 @@ class MinLengthImplicit final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.assign("minLength", sourcemeta::core::JSON{0}); } }; diff --git a/src/canonicalizer/rules/min_properties_covered_by_required.h b/src/canonicalizer/rules/min_properties_covered_by_required.h index 0e645a8f5..a80bca96d 100644 --- a/src/canonicalizer/rules/min_properties_covered_by_required.h +++ b/src/canonicalizer/rules/min_properties_covered_by_required.h @@ -1,12 +1,8 @@ class MinPropertiesCoveredByRequired final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::false_type; MinPropertiesCoveredByRequired() - : SchemaTransformRule{ - "min_properties_covered_by_required", - "Setting `minProperties` to a number less than `required` does " - "not add any further constraint"} {}; + : SchemaTransformRule{"min_properties_covered_by_required"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class MinPropertiesCoveredByRequired final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -35,7 +30,7 @@ class MinPropertiesCoveredByRequired final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.assign("minProperties", sourcemeta::core::JSON{schema.at("required").size()}); } diff --git a/src/canonicalizer/rules/minimum_can_equal_integer_fold.h b/src/canonicalizer/rules/minimum_can_equal_integer_fold.h index 48460e63e..de89dd461 100644 --- a/src/canonicalizer/rules/minimum_can_equal_integer_fold.h +++ b/src/canonicalizer/rules/minimum_can_equal_integer_fold.h @@ -1,9 +1,8 @@ class MinimumCanEqualIntegerFold final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; MinimumCanEqualIntegerFold() - : SchemaTransformRule{"minimum_can_equal_integer_fold", ""} {}; + : SchemaTransformRule{"minimum_can_equal_integer_fold"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class MinimumCanEqualIntegerFold final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_0, Vocabularies::Known::JSON_Schema_Draft_1, @@ -31,7 +29,7 @@ class MinimumCanEqualIntegerFold final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { const auto &minimum{schema.at("minimum")}; if (minimum.is_integer()) { if (minimum.to_integer() < std::numeric_limits::max()) { diff --git a/src/canonicalizer/rules/minimum_can_equal_true_drop.h b/src/canonicalizer/rules/minimum_can_equal_true_drop.h index 4085eb0db..c1e98e736 100644 --- a/src/canonicalizer/rules/minimum_can_equal_true_drop.h +++ b/src/canonicalizer/rules/minimum_can_equal_true_drop.h @@ -1,9 +1,8 @@ class MinimumCanEqualTrueDrop final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; MinimumCanEqualTrueDrop() - : SchemaTransformRule{"minimum_can_equal_true_drop", ""} {}; + : SchemaTransformRule{"minimum_can_equal_true_drop"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class MinimumCanEqualTrueDrop final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_0, Vocabularies::Known::JSON_Schema_Draft_1, @@ -30,7 +28,7 @@ class MinimumCanEqualTrueDrop final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("minimumCanEqual"); } }; diff --git a/src/canonicalizer/rules/minimum_real_for_integer.h b/src/canonicalizer/rules/minimum_real_for_integer.h index 51be6c94b..566d0b9b2 100644 --- a/src/canonicalizer/rules/minimum_real_for_integer.h +++ b/src/canonicalizer/rules/minimum_real_for_integer.h @@ -1,12 +1,7 @@ class MinimumRealForInteger final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::false_type; - MinimumRealForInteger() - : SchemaTransformRule{ - "minimum_real_for_integer", - "If an instance is guaranteed to be an integer, setting a real " - "number lower bound is the same as a ceil of that lower bound"} {}; + MinimumRealForInteger() : SchemaTransformRule{"minimum_real_for_integer"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +10,7 @@ class MinimumRealForInteger final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -38,7 +32,7 @@ class MinimumRealForInteger final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { if (schema.at("minimum").is_decimal()) { const auto current{schema.at("minimum").to_decimal()}; auto new_value{current.to_integral()}; diff --git a/src/canonicalizer/rules/modern_official_dialect_with_empty_fragment.h b/src/canonicalizer/rules/modern_official_dialect_with_empty_fragment.h index 7201e27fb..3226034a0 100644 --- a/src/canonicalizer/rules/modern_official_dialect_with_empty_fragment.h +++ b/src/canonicalizer/rules/modern_official_dialect_with_empty_fragment.h @@ -1,13 +1,9 @@ class ModernOfficialDialectWithEmptyFragment final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; ModernOfficialDialectWithEmptyFragment() - : SchemaTransformRule{ - "modern_official_dialect_with_empty_fragment", - "The official dialect URI of 2019-09 and newer versions must " - "not contain the empty fragment"} {}; + : SchemaTransformRule{"modern_official_dialect_with_empty_fragment"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, const sourcemeta::core::JSON &, @@ -15,9 +11,8 @@ class ModernOfficialDialectWithEmptyFragment final const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, - const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const + -> bool override { ONLY_CONTINUE_IF(schema.is_object()); const auto *schema_keyword{schema.try_at("$schema")}; ONLY_CONTINUE_IF(schema_keyword && schema_keyword->is_string()); @@ -30,8 +25,7 @@ class ModernOfficialDialectWithEmptyFragment final return true; } - auto transform(sourcemeta::core::JSON &schema, const Result &) const - -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto dialect{std::move(schema.at("$schema")).to_string()}; dialect.pop_back(); schema.at("$schema").into(sourcemeta::core::JSON{dialect}); diff --git a/src/canonicalizer/rules/modern_official_dialect_with_http.h b/src/canonicalizer/rules/modern_official_dialect_with_http.h index ef6405f8a..4176a4baf 100644 --- a/src/canonicalizer/rules/modern_official_dialect_with_http.h +++ b/src/canonicalizer/rules/modern_official_dialect_with_http.h @@ -1,12 +1,8 @@ class ModernOfficialDialectWithHttp final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; ModernOfficialDialectWithHttp() - : SchemaTransformRule{ - "modern_official_dialect_with_http", - "The official dialect URI of 2019-09 and later must use " - "\"https://\" instead of \"http://\""} {}; + : SchemaTransformRule{"modern_official_dialect_with_http"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class ModernOfficialDialectWithHttp final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { using sourcemeta::blaze::SchemaBaseDialect; ONLY_CONTINUE_IF( location.base_dialect == SchemaBaseDialect::JSON_Schema_2020_12 || @@ -40,8 +35,7 @@ class ModernOfficialDialectWithHttp final : public SchemaTransformRule { return true; } - auto transform(sourcemeta::core::JSON &schema, const Result &) const - -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { const auto &old_dialect{schema.at("$schema").to_string()}; std::string new_dialect{"https://"}; new_dialect += old_dialect.substr(7); diff --git a/src/canonicalizer/rules/multiple_of_implicit.h b/src/canonicalizer/rules/multiple_of_implicit.h index aa59e3401..72f04c0ff 100644 --- a/src/canonicalizer/rules/multiple_of_implicit.h +++ b/src/canonicalizer/rules/multiple_of_implicit.h @@ -1,10 +1,7 @@ class MultipleOfImplicit final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - MultipleOfImplicit() - : SchemaTransformRule{"multiple_of_implicit", - "The unit of `multipleOf` is the integer 1"} {}; + MultipleOfImplicit() : SchemaTransformRule{"multiple_of_implicit"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -13,8 +10,7 @@ class MultipleOfImplicit final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -30,7 +26,7 @@ class MultipleOfImplicit final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.assign("multipleOf", sourcemeta::core::JSON{1}); } }; diff --git a/src/canonicalizer/rules/non_applicable_additional_items.h b/src/canonicalizer/rules/non_applicable_additional_items.h index a7deb28db..eb7c983cb 100644 --- a/src/canonicalizer/rules/non_applicable_additional_items.h +++ b/src/canonicalizer/rules/non_applicable_additional_items.h @@ -4,13 +4,9 @@ class NonApplicableAdditionalItems final : public SchemaTransformRule { static inline const std::string KEYWORD{"additionalItems"}; public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; NonApplicableAdditionalItems() - : SchemaTransformRule{ - "non_applicable_additional_items", - "The `additionalItems` keyword is ignored when the " - "`items` keyword is either not present or set to a schema"} {}; + : SchemaTransformRule{"non_applicable_additional_items"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -19,8 +15,7 @@ class NonApplicableAdditionalItems final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2019_09_Applicator, Vocabularies::Known::JSON_Schema_Draft_7, @@ -30,13 +25,14 @@ class NonApplicableAdditionalItems final : public SchemaTransformRule { Vocabularies::Known::JSON_Schema_Draft_3_Hyper}) && schema.is_object() && schema.defines(KEYWORD)); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); const auto *items{schema.try_at("items")}; return (items && is_schema(*items)) || !items; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase(KEYWORD); } }; diff --git a/src/canonicalizer/rules/non_applicable_disallow_types.h b/src/canonicalizer/rules/non_applicable_disallow_types.h index 19e64a71a..2554c065f 100644 --- a/src/canonicalizer/rules/non_applicable_disallow_types.h +++ b/src/canonicalizer/rules/non_applicable_disallow_types.h @@ -1,12 +1,8 @@ class NonApplicableDisallowTypes final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; NonApplicableDisallowTypes() - : SchemaTransformRule{ - "non_applicable_disallow_types", - "`disallow` entries whose type cannot overlap with the parent " - "`type` can never match and can be dropped"} {}; + : SchemaTransformRule{"non_applicable_disallow_types"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,9 +11,8 @@ class NonApplicableDisallowTypes final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"disallow"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"disallow"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper}) && @@ -33,10 +28,10 @@ class NonApplicableDisallowTypes final : public SchemaTransformRule { const auto parent_types{parse_schema_type(*parent_type_value)}; ONLY_CONTINUE_IF(parent_types.any()); - std::vector locations; + std::vector locations; for (std::size_t index = 0; index < disallow->size(); ++index) { const auto &entry{disallow->at(index)}; - JSON::TypeSet entry_types; + sourcemeta::core::JSON::TypeSet entry_types; if (entry.is_string() && entry.to_string() != "any") { entry_types = parse_schema_type(entry); } else if (entry.is_object()) { @@ -47,7 +42,7 @@ class NonApplicableDisallowTypes final : public SchemaTransformRule { } if (entry_types.any() && (parent_types & entry_types).none()) { - locations.push_back(Pointer{KEYWORD, index}); + locations.push_back(sourcemeta::core::Pointer{KEYWORD, index}); } } @@ -61,7 +56,7 @@ class NonApplicableDisallowTypes final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { std::vector dead_indices; dead_indices.reserve(this->locations_.size()); for (const auto &location : this->locations_) { @@ -69,7 +64,7 @@ class NonApplicableDisallowTypes final : public SchemaTransformRule { dead_indices.push_back(location.at(1).to_index()); } - auto new_disallow{JSON::make_array()}; + auto new_disallow{sourcemeta::core::JSON::make_array()}; const auto &disallow{schema.at("disallow")}; for (std::size_t index = 0; index < disallow.size(); ++index) { if (std::ranges::find(dead_indices, index) == dead_indices.end()) { diff --git a/src/canonicalizer/rules/non_applicable_enum_validation_keywords.h b/src/canonicalizer/rules/non_applicable_enum_validation_keywords.h index 742bce192..0b9ef9c61 100644 --- a/src/canonicalizer/rules/non_applicable_enum_validation_keywords.h +++ b/src/canonicalizer/rules/non_applicable_enum_validation_keywords.h @@ -1,12 +1,8 @@ class NonApplicableEnumValidationKeywords final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; NonApplicableEnumValidationKeywords() - : SchemaTransformRule{ - "non_applicable_enum_validation_keywords", - "Setting validation keywords that do not apply to any item in " - "`enum` is considered an anti-pattern"} {}; + : SchemaTransformRule{"non_applicable_enum_validation_keywords"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class NonApplicableEnumValidationKeywords final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -44,7 +39,7 @@ class NonApplicableEnumValidationKeywords final : public SchemaTransformRule { {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper})}; - std::vector positions; + std::vector positions; for (const auto &entry : schema.as_object()) { const auto &metadata = walker(entry.first, vocabularies); @@ -60,7 +55,7 @@ class NonApplicableEnumValidationKeywords final : public SchemaTransformRule { // Check if there's any overlap between keyword's applicable types and // enum types if ((metadata.instances & enum_types).none()) { - positions.push_back(Pointer{entry.first}); + positions.push_back(sourcemeta::core::Pointer{entry.first}); } } @@ -70,7 +65,7 @@ class NonApplicableEnumValidationKeywords final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { for (const auto &location : this->locations_) { schema.erase(location.at(0).to_property()); } diff --git a/src/canonicalizer/rules/non_applicable_type_specific_keywords.h b/src/canonicalizer/rules/non_applicable_type_specific_keywords.h index 0355d2b2e..182ec587f 100644 --- a/src/canonicalizer/rules/non_applicable_type_specific_keywords.h +++ b/src/canonicalizer/rules/non_applicable_type_specific_keywords.h @@ -1,11 +1,8 @@ class NonApplicableTypeSpecificKeywords final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; NonApplicableTypeSpecificKeywords() - : SchemaTransformRule{"non_applicable_type_specific_keywords", - "Avoid keywords that don't apply to the type or " - "types that the current subschema expects"} {}; + : SchemaTransformRule{"non_applicable_type_specific_keywords"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,8 +11,7 @@ class NonApplicableTypeSpecificKeywords final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(schema.is_object()); const auto *type_value{schema.try_at("type")}; @@ -68,7 +64,7 @@ class NonApplicableTypeSpecificKeywords final : public SchemaTransformRule { // so we cannot remove anything from it. ONLY_CONTINUE_IF(current_types.any()); - std::vector positions; + std::vector positions; for (const auto &entry : schema.as_object()) { const auto &metadata{walker(entry.first, vocabularies)}; @@ -109,11 +105,12 @@ class NonApplicableTypeSpecificKeywords final : public SchemaTransformRule { if ((metadata.instances & current_types).none()) { // Skip keywords that have references pointing to them if (frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(entry.first)})) { + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(entry.first)})) { continue; } - positions.push_back(Pointer{entry.first}); + positions.push_back(sourcemeta::core::Pointer{entry.first}); } } @@ -122,7 +119,7 @@ class NonApplicableTypeSpecificKeywords final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { for (const auto &location : this->locations_) { schema.erase(location.at(0).to_property()); } diff --git a/src/canonicalizer/rules/not_false.h b/src/canonicalizer/rules/not_false.h index 7fa105cfd..4d085f087 100644 --- a/src/canonicalizer/rules/not_false.h +++ b/src/canonicalizer/rules/not_false.h @@ -4,19 +4,15 @@ class NotFalse final : public SchemaTransformRule { static inline const std::string KEYWORD{"not"}; public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - NotFalse() - : SchemaTransformRule{"not_false", - "Setting the `not` keyword to `false` imposes no " - "constraints. Negating `false` yields the " - "always-true schema"} {}; + NotFalse() : SchemaTransformRule{"not_false"} {}; [[nodiscard]] auto - condition(const JSON &schema, const JSON &, const Vocabularies &vocabularies, + condition(const sourcemeta::core::JSON &schema, + const sourcemeta::core::JSON &, const Vocabularies &vocabularies, const SchemaFrame &frame, const SchemaFrame::Location &location, - const SchemaWalker &, const SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const SchemaWalker &, const SchemaResolver &) const + -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -27,11 +23,12 @@ class NotFalse final : public SchemaTransformRule { schema.at(KEYWORD).is_boolean() && !schema.at(KEYWORD).to_boolean()); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase(KEYWORD); } }; diff --git a/src/canonicalizer/rules/oneof_false_simplify.h b/src/canonicalizer/rules/oneof_false_simplify.h index a22fa78ca..48b587246 100644 --- a/src/canonicalizer/rules/oneof_false_simplify.h +++ b/src/canonicalizer/rules/oneof_false_simplify.h @@ -1,11 +1,7 @@ class OneOfFalseSimplify final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - OneOfFalseSimplify() - : SchemaTransformRule{"oneof_false_simplify", - "A `oneOf` of a single `false` branch is " - "unsatisfiable"} {}; + OneOfFalseSimplify() : SchemaTransformRule{"oneof_false_simplify"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,9 +10,8 @@ class OneOfFalseSimplify final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"oneOf"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"oneOf"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -30,12 +25,13 @@ class OneOfFalseSimplify final : public SchemaTransformRule { const auto &entry{one_of->front()}; ONLY_CONTINUE_IF(entry.is_boolean() && !entry.to_boolean()); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); return true; } - auto transform(JSON &schema, const Result &) const -> void override { - schema.at("oneOf").into(JSON{true}); + auto transform(sourcemeta::core::JSON &schema) const -> void override { + schema.at("oneOf").into(sourcemeta::core::JSON{true}); schema.rename("oneOf", "not"); } }; diff --git a/src/canonicalizer/rules/oneof_to_anyof_disjoint_types.h b/src/canonicalizer/rules/oneof_to_anyof_disjoint_types.h index 93c60bae8..abcd97439 100644 --- a/src/canonicalizer/rules/oneof_to_anyof_disjoint_types.h +++ b/src/canonicalizer/rules/oneof_to_anyof_disjoint_types.h @@ -1,12 +1,8 @@ class OneOfToAnyOfDisjointTypes final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; OneOfToAnyOfDisjointTypes() - : SchemaTransformRule{ - "oneof_to_anyof_disjoint_types", - "A `oneOf` where all branches have disjoint types can be safely " - "converted to `anyOf`"} {}; + : SchemaTransformRule{"oneof_to_anyof_disjoint_types"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,9 +11,8 @@ class OneOfToAnyOfDisjointTypes final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"oneOf"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"oneOf"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -45,7 +40,7 @@ class OneOfToAnyOfDisjointTypes final : public SchemaTransformRule { Vocabularies::Known::JSON_Schema_Draft_7, Vocabularies::Known::JSON_Schema_Draft_6})}; - std::vector type_sets; + std::vector type_sets; type_sets.reserve(oneof_value->size()); for (const auto &branch : oneof_value->as_array()) { @@ -63,11 +58,11 @@ class OneOfToAnyOfDisjointTypes final : public SchemaTransformRule { ONLY_CONTINUE_IF(branch_types.any()); type_sets.push_back(branch_types); } else if (const_value && !has_enum) { - JSON::TypeSet branch_types; + sourcemeta::core::JSON::TypeSet branch_types; branch_types.set(std::to_underlying(const_value->type())); type_sets.push_back(branch_types); } else if (has_enum && !const_value) { - JSON::TypeSet branch_types; + sourcemeta::core::JSON::TypeSet branch_types; for (const auto &item : enum_value->as_array()) { branch_types.set(std::to_underlying(item.type())); } @@ -86,16 +81,18 @@ class OneOfToAnyOfDisjointTypes final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.rename("oneOf", "anyOf"); } - [[nodiscard]] auto - rereference(const std::string_view, const Pointer &origin [[maybe_unused]], - const Pointer &target, const Pointer ¤t) const - -> Pointer override { - const Pointer oneof_prefix{current.concat("oneOf")}; - const Pointer anyof_prefix{current.concat("anyOf")}; + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &origin + [[maybe_unused]], + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { + const sourcemeta::core::Pointer oneof_prefix{current.concat("oneOf")}; + const sourcemeta::core::Pointer anyof_prefix{current.concat("anyOf")}; return target.rebase(oneof_prefix, anyof_prefix); } }; diff --git a/src/canonicalizer/rules/optional_property_implicit.h b/src/canonicalizer/rules/optional_property_implicit.h index bf9efb626..2d5a5a679 100644 --- a/src/canonicalizer/rules/optional_property_implicit.h +++ b/src/canonicalizer/rules/optional_property_implicit.h @@ -1,9 +1,8 @@ class OptionalPropertyImplicit final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; OptionalPropertyImplicit() - : SchemaTransformRule{"optional_property_implicit", ""} {}; + : SchemaTransformRule{"optional_property_implicit"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class OptionalPropertyImplicit final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_0, Vocabularies::Known::JSON_Schema_Draft_1, @@ -36,8 +34,8 @@ class OptionalPropertyImplicit final : public SchemaTransformRule { return false; } - auto transform(JSON &schema, const Result &) const -> void override { - std::vector keys; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + std::vector keys; for (const auto &entry : schema.at("properties").as_object()) { if (entry.second.is_object() && !entry.second.empty() && !entry.second.defines("optional")) { diff --git a/src/canonicalizer/rules/orphan_definitions.h b/src/canonicalizer/rules/orphan_definitions.h index 54eff4cd6..21d830fe8 100644 --- a/src/canonicalizer/rules/orphan_definitions.h +++ b/src/canonicalizer/rules/orphan_definitions.h @@ -1,12 +1,7 @@ class OrphanDefinitions final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - OrphanDefinitions() - : SchemaTransformRule{ - "orphan_definitions", - "Schema definitions in `$defs` or `definitions` that " - "are never internally referenced can be removed"} {}; + OrphanDefinitions() : SchemaTransformRule{"orphan_definitions"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +10,8 @@ class OrphanDefinitions final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &resolver, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &resolver) const + -> bool override { ONLY_CONTINUE_IF(schema.is_object()); const bool has_modern_core{ vocabularies.contains(Vocabularies::Known::JSON_Schema_2020_12_Core) || @@ -33,7 +28,7 @@ class OrphanDefinitions final : public SchemaTransformRule { const auto base{frame.traverse(frame.root())}; ONLY_CONTINUE_IF(base.has_value()); - std::vector orphans; + std::vector orphans; collect_orphans(frame, base->get(), walker, resolver, location.pointer, schema, "$defs", has_defs, orphans); collect_orphans(frame, base->get(), walker, resolver, location.pointer, @@ -44,7 +39,7 @@ class OrphanDefinitions final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { for (const auto &pointer : this->locations_) { assert(pointer.size() == 2); assert(pointer.at(0).is_property()); @@ -67,7 +62,8 @@ class OrphanDefinitions final : public SchemaTransformRule { private: static auto subtree_has_dynamic_anchor(const sourcemeta::blaze::SchemaFrame &frame, - const WeakPointer &entry_pointer) -> bool { + const sourcemeta::core::WeakPointer &entry_pointer) + -> bool { for (const auto &[key, location] : frame.locations()) { if (key.first != sourcemeta::blaze::SchemaReferenceType::Dynamic) { continue; @@ -88,7 +84,7 @@ class OrphanDefinitions final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame::Location &base, const sourcemeta::blaze::SchemaWalker &walker, const sourcemeta::blaze::SchemaResolver &resolver, - const WeakPointer &pointer) -> bool { + const sourcemeta::core::WeakPointer &pointer) -> bool { for (const auto &reference : frame.references()) { const auto destination{frame.traverse(reference.second.destination)}; if (!destination.has_value()) { @@ -121,16 +117,18 @@ class OrphanDefinitions final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame::Location &base, const sourcemeta::blaze::SchemaWalker &walker, const sourcemeta::blaze::SchemaResolver &resolver, - const WeakPointer &prefix, const JSON &schema, - const JSON::String &container, const bool has_container, - std::vector &orphans) -> void { + const sourcemeta::core::WeakPointer &prefix, + const sourcemeta::core::JSON &schema, + const sourcemeta::core::JSON::String &container, + const bool has_container, + std::vector &orphans) -> void { if (!has_container || !schema.at(container).is_object()) { return; } for (const auto &entry : schema.at(container).as_object()) { - const WeakPointer entry_pointer{std::cref(container), - std::cref(entry.first)}; + const sourcemeta::core::WeakPointer entry_pointer{std::cref(container), + std::cref(entry.first)}; const auto absolute_entry_pointer{prefix.concat(entry_pointer)}; const auto entry_location{frame.traverse( absolute_entry_pointer, @@ -141,7 +139,7 @@ class OrphanDefinitions final : public SchemaTransformRule { absolute_entry_pointer) && !(!frame.standalone() && subtree_has_dynamic_anchor(frame, absolute_entry_pointer))) { - orphans.push_back(Pointer{container, entry.first}); + orphans.push_back(sourcemeta::core::Pointer{container, entry.first}); } } } diff --git a/src/canonicalizer/rules/recursive_anchor_false_drop.h b/src/canonicalizer/rules/recursive_anchor_false_drop.h index d9b9310ba..faa505dab 100644 --- a/src/canonicalizer/rules/recursive_anchor_false_drop.h +++ b/src/canonicalizer/rules/recursive_anchor_false_drop.h @@ -1,9 +1,8 @@ class RecursiveAnchorFalseDrop final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; RecursiveAnchorFalseDrop() - : SchemaTransformRule{"recursive_anchor_false_drop", ""} {}; + : SchemaTransformRule{"recursive_anchor_false_drop"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class RecursiveAnchorFalseDrop final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains(Vocabularies::Known::JSON_Schema_2019_09_Core) && schema.is_object()); @@ -24,7 +22,7 @@ class RecursiveAnchorFalseDrop final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase("$recursiveAnchor"); } }; diff --git a/src/canonicalizer/rules/required_properties_in_properties.h b/src/canonicalizer/rules/required_properties_in_properties.h index d669bc729..ea3e240c2 100644 --- a/src/canonicalizer/rules/required_properties_in_properties.h +++ b/src/canonicalizer/rules/required_properties_in_properties.h @@ -1,12 +1,8 @@ class RequiredPropertiesInProperties final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; RequiredPropertiesInProperties() - : SchemaTransformRule{ - "required_properties_in_properties", - "Every property listed in the `required` keyword must be " - "explicitly defined using the `properties` keyword"} {}; + : SchemaTransformRule{"required_properties_in_properties"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,8 @@ class RequiredPropertiesInProperties final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &resolver, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &resolver) const + -> bool override { ONLY_CONTINUE_IF( ((vocabularies.contains( Vocabularies::Known::JSON_Schema_2020_12_Validation) && @@ -40,19 +36,20 @@ class RequiredPropertiesInProperties final : public SchemaTransformRule { (additional_properties->is_boolean() && additional_properties->to_boolean())); - std::vector locations; + std::vector locations; std::size_t index{0}; for (const auto &property : required->as_array()) { if (property.is_string() && !this->defined_in_properties_sibling(schema, property.to_string()) && !WALK_UP_IN_PLACE_APPLICATORS( root, frame, location, walker, resolver, - [&](const JSON &ancestor, const Vocabularies &) -> bool { + [&](const sourcemeta::core::JSON &ancestor, + const Vocabularies &) -> bool { return this->defined_in_properties_sibling( ancestor, property.to_string()); }) .has_value()) { - locations.push_back(Pointer{"required", index}); + locations.push_back(sourcemeta::core::Pointer{"required", index}); } index += 1; @@ -63,7 +60,7 @@ class RequiredPropertiesInProperties final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.assign_if_missing("properties", sourcemeta::core::JSON::make_object()); for (const auto &location : this->locations_) { @@ -74,9 +71,9 @@ class RequiredPropertiesInProperties final : public SchemaTransformRule { } private: - [[nodiscard]] auto - defined_in_properties_sibling(const JSON &schema, - const JSON::String &property) const -> bool { + [[nodiscard]] auto defined_in_properties_sibling( + const sourcemeta::core::JSON &schema, + const sourcemeta::core::JSON::String &property) const -> bool { assert(schema.is_object()); const auto *properties{schema.try_at("properties")}; return properties && properties->is_object() && diff --git a/src/canonicalizer/rules/required_property_implicit.h b/src/canonicalizer/rules/required_property_implicit.h index ffc862da1..a823588c8 100644 --- a/src/canonicalizer/rules/required_property_implicit.h +++ b/src/canonicalizer/rules/required_property_implicit.h @@ -1,9 +1,8 @@ class RequiredPropertyImplicit final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; RequiredPropertyImplicit() - : SchemaTransformRule{"required_property_implicit", ""} {}; + : SchemaTransformRule{"required_property_implicit"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class RequiredPropertyImplicit final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains(Vocabularies::Known::JSON_Schema_Draft_3) && schema.is_object()); @@ -34,8 +32,8 @@ class RequiredPropertyImplicit final : public SchemaTransformRule { return false; } - auto transform(JSON &schema, const Result &) const -> void override { - std::vector keys; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + std::vector keys; for (const auto &entry : schema.at("properties").as_object()) { if (entry.second.is_object() && !entry.second.empty() && !entry.second.defines("$ref") && !entry.second.defines("required")) { diff --git a/src/canonicalizer/rules/required_to_extends.h b/src/canonicalizer/rules/required_to_extends.h index 86c7f109c..d33b0bd73 100644 --- a/src/canonicalizer/rules/required_to_extends.h +++ b/src/canonicalizer/rules/required_to_extends.h @@ -1,13 +1,7 @@ class RequiredToExtends final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - RequiredToExtends() - : SchemaTransformRule{ - "required_to_extends", - "In Draft 3 canonical form, `required` is only ever a sibling of " - "`extends`; its other siblings are wrapped into an `extends` " - "branch"} {}; + RequiredToExtends() : SchemaTransformRule{"required_to_extends"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -16,8 +10,7 @@ class RequiredToExtends final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper}) && @@ -35,7 +28,7 @@ class RequiredToExtends final : public SchemaTransformRule { return false; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { this->wrapped_keywords_.clear(); for (const auto &entry : schema.as_object()) { if (!stays_at_top(entry.first)) { @@ -43,7 +36,7 @@ class RequiredToExtends final : public SchemaTransformRule { } } - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; for (const auto &keyword : this->wrapped_keywords_) { branch.assign(keyword, schema.at(keyword)); } @@ -58,23 +51,24 @@ class RequiredToExtends final : public SchemaTransformRule { } else if (schema.defines("extends")) { // Draft 3 allows `extends` to be a single schema; preserve it as the // first branch of the new array - auto extends{JSON::make_array()}; + auto extends{sourcemeta::core::JSON::make_array()}; extends.push_back(schema.at("extends")); this->branch_index_ = extends.size(); extends.push_back(std::move(branch)); schema.assign("extends", std::move(extends)); } else { this->branch_index_ = 0; - auto extends{JSON::make_array()}; + auto extends{sourcemeta::core::JSON::make_array()}; extends.push_back(std::move(branch)); schema.assign("extends", std::move(extends)); } } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { for (const auto &keyword : this->wrapped_keywords_) { const auto keyword_prefix{current.concat(keyword)}; if (target.starts_with(keyword_prefix)) { diff --git a/src/canonicalizer/rules/single_branch_allof.h b/src/canonicalizer/rules/single_branch_allof.h index 38b4b475d..27dfb7a70 100644 --- a/src/canonicalizer/rules/single_branch_allof.h +++ b/src/canonicalizer/rules/single_branch_allof.h @@ -1,8 +1,7 @@ class SingleBranchAllOf final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - SingleBranchAllOf() : SchemaTransformRule{"single_branch_allof", ""} {}; + SingleBranchAllOf() : SchemaTransformRule{"single_branch_allof"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,9 +10,8 @@ class SingleBranchAllOf final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"allOf"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"allOf"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -31,7 +29,8 @@ class SingleBranchAllOf final : public SchemaTransformRule { (schema.defines("unevaluatedProperties") || schema.defines("unevaluatedItems")))); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); const auto &branch{all_of->at(0)}; if (branch.is_object()) { ONLY_CONTINUE_IF(!branch.defines("$ref") && @@ -41,13 +40,13 @@ class SingleBranchAllOf final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto &branch{schema.at("allOf").at(0)}; if (branch.is_boolean()) { if (branch.to_boolean()) { schema.erase("allOf"); } else { - schema.into(JSON{false}); + schema.into(sourcemeta::core::JSON{false}); } return; } @@ -56,12 +55,13 @@ class SingleBranchAllOf final : public SchemaTransformRule { schema.erase("allOf"); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { - static const JSON::String KEYWORD{"allOf"}; - const auto prefix{current.concat(Pointer{KEYWORD, 0})}; + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { + static const sourcemeta::core::JSON::String KEYWORD{"allOf"}; + const auto prefix{current.concat(sourcemeta::core::Pointer{KEYWORD, 0})}; if (!target.starts_with(prefix)) { return target; } @@ -69,7 +69,8 @@ class SingleBranchAllOf final : public SchemaTransformRule { if (relative.empty()) { return target; } - const Pointer new_prefix{current.concat({relative.at(0)})}; + const sourcemeta::core::Pointer new_prefix{ + current.concat({relative.at(0)})}; return target.rebase(prefix.concat({relative.at(0)}), new_prefix); } }; diff --git a/src/canonicalizer/rules/single_branch_anyof.h b/src/canonicalizer/rules/single_branch_anyof.h index e43abf563..50cd0a528 100644 --- a/src/canonicalizer/rules/single_branch_anyof.h +++ b/src/canonicalizer/rules/single_branch_anyof.h @@ -1,8 +1,7 @@ class SingleBranchAnyOf final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - SingleBranchAnyOf() : SchemaTransformRule{"single_branch_anyof", ""} {}; + SingleBranchAnyOf() : SchemaTransformRule{"single_branch_anyof"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,9 +10,8 @@ class SingleBranchAnyOf final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"anyOf"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"anyOf"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -25,7 +23,8 @@ class SingleBranchAnyOf final : public SchemaTransformRule { const auto *any_of{schema.try_at(KEYWORD)}; ONLY_CONTINUE_IF(any_of && any_of->is_array() && any_of->size() == 1); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); this->has_unevaluated_ = vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Unevaluated, @@ -35,7 +34,7 @@ class SingleBranchAnyOf final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { if (this->has_unevaluated_) { schema.rename("anyOf", "allOf"); return; @@ -46,7 +45,7 @@ class SingleBranchAnyOf final : public SchemaTransformRule { if (branch.to_boolean()) { schema.erase("anyOf"); } else { - schema.into(JSON{false}); + schema.into(sourcemeta::core::JSON{false}); } return; } @@ -55,17 +54,18 @@ class SingleBranchAnyOf final : public SchemaTransformRule { schema.erase("anyOf"); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { - static const JSON::String KEYWORD{"anyOf"}; + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { + static const sourcemeta::core::JSON::String KEYWORD{"anyOf"}; if (this->has_unevaluated_) { const auto old_prefix{current.concat(KEYWORD)}; - const Pointer new_prefix{current.concat("allOf")}; + const sourcemeta::core::Pointer new_prefix{current.concat("allOf")}; return target.rebase(old_prefix, new_prefix); } - const auto prefix{current.concat(Pointer{KEYWORD, 0})}; + const auto prefix{current.concat(sourcemeta::core::Pointer{KEYWORD, 0})}; if (!target.starts_with(prefix)) { return target; } @@ -73,7 +73,8 @@ class SingleBranchAnyOf final : public SchemaTransformRule { if (relative.empty()) { return target; } - const Pointer new_prefix{current.concat({relative.at(0)})}; + const sourcemeta::core::Pointer new_prefix{ + current.concat({relative.at(0)})}; return target.rebase(prefix.concat({relative.at(0)}), new_prefix); } diff --git a/src/canonicalizer/rules/single_branch_oneof.h b/src/canonicalizer/rules/single_branch_oneof.h index d7b21e9cf..858bab4c5 100644 --- a/src/canonicalizer/rules/single_branch_oneof.h +++ b/src/canonicalizer/rules/single_branch_oneof.h @@ -1,8 +1,7 @@ class SingleBranchOneOf final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - SingleBranchOneOf() : SchemaTransformRule{"single_branch_oneof", ""} {}; + SingleBranchOneOf() : SchemaTransformRule{"single_branch_oneof"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,9 +10,8 @@ class SingleBranchOneOf final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { - static const JSON::String KEYWORD{"oneOf"}; + const sourcemeta::blaze::SchemaResolver &) const -> bool override { + static const sourcemeta::core::JSON::String KEYWORD{"oneOf"}; ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -25,7 +23,8 @@ class SingleBranchOneOf final : public SchemaTransformRule { const auto *one_of{schema.try_at(KEYWORD)}; ONLY_CONTINUE_IF(one_of && one_of->is_array() && one_of->size() == 1); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); this->has_unevaluated_ = vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Unevaluated, @@ -35,7 +34,7 @@ class SingleBranchOneOf final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { if (this->has_unevaluated_) { schema.rename("oneOf", "allOf"); return; @@ -46,7 +45,7 @@ class SingleBranchOneOf final : public SchemaTransformRule { if (branch.to_boolean()) { schema.erase("oneOf"); } else { - schema.into(JSON{false}); + schema.into(sourcemeta::core::JSON{false}); } return; } @@ -55,17 +54,18 @@ class SingleBranchOneOf final : public SchemaTransformRule { schema.erase("oneOf"); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { - static const JSON::String KEYWORD{"oneOf"}; + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { + static const sourcemeta::core::JSON::String KEYWORD{"oneOf"}; if (this->has_unevaluated_) { const auto old_prefix{current.concat(KEYWORD)}; - const Pointer new_prefix{current.concat("allOf")}; + const sourcemeta::core::Pointer new_prefix{current.concat("allOf")}; return target.rebase(old_prefix, new_prefix); } - const auto prefix{current.concat(Pointer{KEYWORD, 0})}; + const auto prefix{current.concat(sourcemeta::core::Pointer{KEYWORD, 0})}; if (!target.starts_with(prefix)) { return target; } @@ -73,7 +73,8 @@ class SingleBranchOneOf final : public SchemaTransformRule { if (relative.empty()) { return target; } - const Pointer new_prefix{current.concat({relative.at(0)})}; + const sourcemeta::core::Pointer new_prefix{ + current.concat({relative.at(0)})}; return target.rebase(prefix.concat({relative.at(0)}), new_prefix); } diff --git a/src/canonicalizer/rules/single_type_array.h b/src/canonicalizer/rules/single_type_array.h index 17fdc37aa..5a81f03f2 100644 --- a/src/canonicalizer/rules/single_type_array.h +++ b/src/canonicalizer/rules/single_type_array.h @@ -1,11 +1,7 @@ class SingleTypeArray final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::false_type; - SingleTypeArray() - : SchemaTransformRule{"single_type_array", - "Setting `type` to an array of a single type is " - "the same as directly declaring such type"} {}; + SingleTypeArray() : SchemaTransformRule{"single_type_array"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,8 +10,7 @@ class SingleTypeArray final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -35,7 +30,7 @@ class SingleTypeArray final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto type{schema.at("type").front()}; schema.at("type").into(std::move(type)); } diff --git a/src/canonicalizer/rules/then_without_if.h b/src/canonicalizer/rules/then_without_if.h index 34f9e74c7..f69d95166 100644 --- a/src/canonicalizer/rules/then_without_if.h +++ b/src/canonicalizer/rules/then_without_if.h @@ -4,12 +4,8 @@ class ThenWithoutIf final : public SchemaTransformRule { static inline const std::string KEYWORD{"then"}; public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - ThenWithoutIf() - : SchemaTransformRule{"then_without_if", - "The `then` keyword is meaningless " - "without the presence of the `if` keyword"} {}; + ThenWithoutIf() : SchemaTransformRule{"then_without_if"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -18,8 +14,7 @@ class ThenWithoutIf final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -27,11 +22,12 @@ class ThenWithoutIf final : public SchemaTransformRule { schema.is_object() && schema.defines(KEYWORD) && !schema.defines("if")); ONLY_CONTINUE_IF(!frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(KEYWORD)})); + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(KEYWORD)})); return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase(KEYWORD); } }; diff --git a/src/canonicalizer/rules/type_array_to_any_of.h b/src/canonicalizer/rules/type_array_to_any_of.h index a40c740f9..95edeeb62 100644 --- a/src/canonicalizer/rules/type_array_to_any_of.h +++ b/src/canonicalizer/rules/type_array_to_any_of.h @@ -1,12 +1,7 @@ class TypeArrayToAnyOf final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - TypeArrayToAnyOf() - : SchemaTransformRule{ - "type_array_to_any_of", - "Setting `type` to more than one choice is syntax sugar to " - "`anyOf` over the corresponding types"} {}; + TypeArrayToAnyOf() : SchemaTransformRule{"type_array_to_any_of"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +10,7 @@ class TypeArrayToAnyOf final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( ((vocabularies.contains( @@ -57,7 +51,7 @@ class TypeArrayToAnyOf final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { this->keyword_branch_index_.clear(); auto disjunctors{sourcemeta::core::JSON::make_array()}; std::size_t branch_index{0}; @@ -113,9 +107,10 @@ class TypeArrayToAnyOf final : public SchemaTransformRule { } [[nodiscard]] auto rereference(const std::string_view reference, - const Pointer &origin, const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + const sourcemeta::core::Pointer &origin, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { const auto relative{target.resolve_from(current)}; assert(!relative.empty() && relative.at(0).is_property()); const auto &keyword{relative.at(0).to_property()}; @@ -125,9 +120,10 @@ class TypeArrayToAnyOf final : public SchemaTransformRule { current); } - const Pointer old_prefix{current.concat(keyword)}; - const Pointer new_prefix{current.concat(this->disjunctors_prefix_) - .concat(Pointer{match->second, keyword})}; + const sourcemeta::core::Pointer old_prefix{current.concat(keyword)}; + const sourcemeta::core::Pointer new_prefix{ + current.concat(this->disjunctors_prefix_) + .concat(sourcemeta::core::Pointer{match->second, keyword})}; return target.rebase(old_prefix, new_prefix); } @@ -135,5 +131,5 @@ class TypeArrayToAnyOf final : public SchemaTransformRule { mutable std::unordered_map keyword_instances_; mutable std::unordered_map keyword_branch_index_; - mutable Pointer disjunctors_prefix_; + mutable sourcemeta::core::Pointer disjunctors_prefix_; }; diff --git a/src/canonicalizer/rules/type_boolean_as_enum.h b/src/canonicalizer/rules/type_boolean_as_enum.h index f728b4e7d..b78b4ad33 100644 --- a/src/canonicalizer/rules/type_boolean_as_enum.h +++ b/src/canonicalizer/rules/type_boolean_as_enum.h @@ -1,12 +1,7 @@ class TypeBooleanAsEnum final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - TypeBooleanAsEnum() - : SchemaTransformRule{ - "type_boolean_as_enum", - "Setting `type` to `boolean` is syntax sugar for an enumeration " - "of two values: `false` and `true`"} {}; + TypeBooleanAsEnum() : SchemaTransformRule{"type_boolean_as_enum"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +10,7 @@ class TypeBooleanAsEnum final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -36,7 +30,7 @@ class TypeBooleanAsEnum final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto choices = sourcemeta::core::JSON::make_array(); choices.push_back(sourcemeta::core::JSON{false}); choices.push_back(sourcemeta::core::JSON{true}); diff --git a/src/canonicalizer/rules/type_inherit_in_place.h b/src/canonicalizer/rules/type_inherit_in_place.h index 033425e78..aa060824a 100644 --- a/src/canonicalizer/rules/type_inherit_in_place.h +++ b/src/canonicalizer/rules/type_inherit_in_place.h @@ -1,12 +1,7 @@ class TypeInheritInPlace final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - TypeInheritInPlace() - : SchemaTransformRule{ - "type_inherit_in_place", - "An untyped schema inside an in-place applicator inherits " - "the type from its nearest typed ancestor"} {}; + TypeInheritInPlace() : SchemaTransformRule{"type_inherit_in_place"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,9 +10,8 @@ class TypeInheritInPlace final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &resolver, const bool) const - -> SchemaTransformRule::Result override { - using namespace sourcemeta::core; + const sourcemeta::blaze::SchemaResolver &resolver) const + -> bool override { ONLY_CONTINUE_IF(schema.is_object()); ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, @@ -55,12 +49,12 @@ class TypeInheritInPlace final : public SchemaTransformRule { return IS_IN_PLACE_APPLICATOR(keyword_type) && keyword_type != SchemaKeywordType::ApplicatorElementsInPlace; }, - [](const JSON &ancestor_schema, const Vocabularies &) -> bool { - return ancestor_schema.defines("type"); - })}; + [](const sourcemeta::core::JSON &ancestor_schema, const Vocabularies &) + -> bool { return ancestor_schema.defines("type"); })}; if (ancestor.has_value()) { - const auto &ancestor_type{get(root, ancestor.value().get()).at("type")}; + const auto &ancestor_type{ + sourcemeta::core::get(root, ancestor.value().get()).at("type")}; if (ancestor_type.is_array()) { for (const auto &element : ancestor_type.as_array()) { if (!element.is_string()) { @@ -96,7 +90,7 @@ class TypeInheritInPlace final : public SchemaTransformRule { if (walk_keyword_type == SchemaKeywordType::ApplicatorElementsInPlace && walk_relative.size() >= 2 && walk_relative.at(1).is_index()) { const auto branch_index{walk_relative.at(1).to_index()}; - const auto &allof_parent{get(root, wp)}; + const auto &allof_parent{sourcemeta::core::get(root, wp)}; const auto &keyword_name{walk_relative.at(0).to_property()}; const auto *branches{allof_parent.is_object() ? allof_parent.try_at(keyword_name) @@ -120,7 +114,7 @@ class TypeInheritInPlace final : public SchemaTransformRule { !sibling_enum->empty()) { const auto inferred{infer_type_from_enum(*sibling_enum)}; if (!inferred.empty()) { - this->inherited_type_ = JSON{inferred}; + this->inherited_type_ = sourcemeta::core::JSON{inferred}; return true; } } @@ -128,8 +122,8 @@ class TypeInheritInPlace final : public SchemaTransformRule { if (sibling_ref && sibling_ref->is_string()) { const auto ref_target{frame.traverse(sibling_ref->to_string())}; if (ref_target.has_value()) { - const auto &ref_schema{ - get(root, ref_target.value().get().pointer)}; + const auto &ref_schema{sourcemeta::core::get( + root, ref_target.value().get().pointer)}; const auto *ref_type{ref_schema.is_object() ? ref_schema.try_at("type") : nullptr}; @@ -150,7 +144,7 @@ class TypeInheritInPlace final : public SchemaTransformRule { return false; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.assign("type", this->inherited_type_); } diff --git a/src/canonicalizer/rules/type_null_as_enum.h b/src/canonicalizer/rules/type_null_as_enum.h index bd29690ba..0d14bd9ef 100644 --- a/src/canonicalizer/rules/type_null_as_enum.h +++ b/src/canonicalizer/rules/type_null_as_enum.h @@ -1,12 +1,7 @@ class TypeNullAsEnum final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - TypeNullAsEnum() - : SchemaTransformRule{ - "type_null_as_enum", - "Setting `type` to `null` is syntax sugar for an enumeration " - "of a single value: `null`"} {}; + TypeNullAsEnum() : SchemaTransformRule{"type_null_as_enum"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +10,7 @@ class TypeNullAsEnum final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, Vocabularies::Known::JSON_Schema_2019_09_Validation, @@ -35,7 +29,7 @@ class TypeNullAsEnum final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto choices = sourcemeta::core::JSON::make_array(); choices.push_back(sourcemeta::core::JSON{nullptr}); schema.at("type").into(std::move(choices)); diff --git a/src/canonicalizer/rules/type_union_distribute_keywords.h b/src/canonicalizer/rules/type_union_distribute_keywords.h index 70076b94b..487a5c2cf 100644 --- a/src/canonicalizer/rules/type_union_distribute_keywords.h +++ b/src/canonicalizer/rules/type_union_distribute_keywords.h @@ -1,12 +1,8 @@ class TypeUnionDistributeKeywords final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; TypeUnionDistributeKeywords() - : SchemaTransformRule{ - "type_union_distribute_keywords", - "A type-specific keyword sibling to a `type` union belongs inside " - "the branch of the type that it applies to"} {}; + : SchemaTransformRule{"type_union_distribute_keywords"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class TypeUnionDistributeKeywords final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper}) && @@ -31,7 +26,7 @@ class TypeUnionDistributeKeywords final : public SchemaTransformRule { this->moves_.clear(); this->wrap_keywords_.clear(); this->wrap_ = false; - std::vector movable; + std::vector movable; for (const auto &entry : schema.as_object()) { // `required` is a property-presence flag, not a value assertion, so it // is never pushed into a branch @@ -89,11 +84,11 @@ class TypeUnionDistributeKeywords final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { if (this->wrap_) { - auto union_branch{JSON::make_object()}; + auto union_branch{sourcemeta::core::JSON::make_object()}; union_branch.assign("type", schema.at("type")); - auto sibling_branch{JSON::make_object()}; + auto sibling_branch{sourcemeta::core::JSON::make_object()}; for (const auto &keyword : this->wrap_keywords_) { sibling_branch.assign(keyword, schema.at(keyword)); } @@ -109,7 +104,7 @@ class TypeUnionDistributeKeywords final : public SchemaTransformRule { this->sibling_index_ = schema.at("extends").size(); schema.at("extends").push_back(std::move(sibling_branch)); } else { - auto extends{JSON::make_array()}; + auto extends{sourcemeta::core::JSON::make_array()}; this->type_index_ = 0; extends.push_back(std::move(union_branch)); this->sibling_index_ = 1; @@ -133,10 +128,11 @@ class TypeUnionDistributeKeywords final : public SchemaTransformRule { } } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { if (this->wrap_) { const auto type_prefix{current.concat("type")}; if (target.starts_with(type_prefix)) { diff --git a/src/canonicalizer/rules/type_union_implicit.h b/src/canonicalizer/rules/type_union_implicit.h index 4d40c9b2c..54bdf98c0 100644 --- a/src/canonicalizer/rules/type_union_implicit.h +++ b/src/canonicalizer/rules/type_union_implicit.h @@ -1,11 +1,7 @@ class TypeUnionImplicit final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - TypeUnionImplicit() - : SchemaTransformRule{ - "type_union_implicit", - "Not setting `type` is equivalent to accepting any type"} {}; + TypeUnionImplicit() : SchemaTransformRule{"type_union_implicit"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,9 +10,8 @@ class TypeUnionImplicit final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &resolver, const bool) const - -> SchemaTransformRule::Result override { - using namespace sourcemeta::core; + const sourcemeta::blaze::SchemaResolver &resolver) const + -> bool override { ONLY_CONTINUE_IF(schema.is_object() && !schema.empty()); ONLY_CONTINUE_IF(!vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_0, @@ -60,7 +55,7 @@ class TypeUnionImplicit final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto types{sourcemeta::core::JSON::make_array()}; types.push_back(sourcemeta::core::JSON{"null"}); @@ -82,7 +77,6 @@ class TypeUnionImplicit final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, const sourcemeta::blaze::SchemaResolver &resolver) -> bool { - using namespace sourcemeta::core; auto walk_pointer{location.pointer}; auto walk_parent{location.parent}; while (walk_parent.has_value()) { @@ -107,7 +101,7 @@ class TypeUnionImplicit final : public SchemaTransformRule { if (walk_keyword_type == SchemaKeywordType::ApplicatorElementsInPlace && walk_relative.size() >= 2 && walk_relative.at(1).is_index()) { const auto branch_index{walk_relative.at(1).to_index()}; - const auto &allof_parent{get(root, wp)}; + const auto &allof_parent{sourcemeta::core::get(root, wp)}; const auto &keyword_name{walk_relative.at(0).to_property()}; const auto *branches{allof_parent.is_object() ? allof_parent.try_at(keyword_name) diff --git a/src/canonicalizer/rules/type_union_to_schemas.h b/src/canonicalizer/rules/type_union_to_schemas.h index dd914cbc9..c0e836445 100644 --- a/src/canonicalizer/rules/type_union_to_schemas.h +++ b/src/canonicalizer/rules/type_union_to_schemas.h @@ -1,8 +1,7 @@ class TypeUnionToSchemas final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - TypeUnionToSchemas() : SchemaTransformRule{"type_union_to_schemas", ""} {}; + TypeUnionToSchemas() : SchemaTransformRule{"type_union_to_schemas"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -11,8 +10,7 @@ class TypeUnionToSchemas final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_0, Vocabularies::Known::JSON_Schema_Draft_1, @@ -32,8 +30,8 @@ class TypeUnionToSchemas final : public SchemaTransformRule { return false; } - auto transform(JSON &schema, const Result &) const -> void override { - auto new_array{JSON::make_array()}; + auto transform(sourcemeta::core::JSON &schema) const -> void override { + auto new_array{sourcemeta::core::JSON::make_array()}; for (const auto &element : schema.at("type").as_array()) { if (element.is_string()) { new_array.push_back(type_string_to_schema(element.to_string())); @@ -45,30 +43,31 @@ class TypeUnionToSchemas final : public SchemaTransformRule { } private: - static auto type_string_to_schema(const std::string &type_name) -> JSON { + static auto type_string_to_schema(const std::string &type_name) + -> sourcemeta::core::JSON { if (type_name == "null") { - auto result{JSON::make_object()}; - auto values{JSON::make_array()}; - values.push_back(JSON{nullptr}); + auto result{sourcemeta::core::JSON::make_object()}; + auto values{sourcemeta::core::JSON::make_array()}; + values.push_back(sourcemeta::core::JSON{nullptr}); result.assign("enum", std::move(values)); return result; } if (type_name == "boolean") { - auto result{JSON::make_object()}; - auto values{JSON::make_array()}; - values.push_back(JSON{false}); - values.push_back(JSON{true}); + auto result{sourcemeta::core::JSON::make_object()}; + auto values{sourcemeta::core::JSON::make_array()}; + values.push_back(sourcemeta::core::JSON{false}); + values.push_back(sourcemeta::core::JSON{true}); result.assign("enum", std::move(values)); return result; } if (type_name == "any") { - return JSON::make_object(); + return sourcemeta::core::JSON::make_object(); } - auto result{JSON::make_object()}; - result.assign("type", JSON{type_name}); + auto result{sourcemeta::core::JSON::make_object()}; + result.assign("type", sourcemeta::core::JSON{type_name}); return result; } }; diff --git a/src/canonicalizer/rules/type_with_applicator_to_allof.h b/src/canonicalizer/rules/type_with_applicator_to_allof.h index 006e23cb1..276ae2b7d 100644 --- a/src/canonicalizer/rules/type_with_applicator_to_allof.h +++ b/src/canonicalizer/rules/type_with_applicator_to_allof.h @@ -1,9 +1,8 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; TypeWithApplicatorToAllOf() - : SchemaTransformRule{"type_with_applicator_to_allof", ""} {}; + : SchemaTransformRule{"type_with_applicator_to_allof"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_4, @@ -192,7 +190,7 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { this->typed_keywords_.clear(); if (this->strategy_ == Strategy::MergeIntoAllOf) { @@ -200,7 +198,7 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { if (!schema.defines(applicator)) { continue; } - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign(applicator, schema.at(applicator)); if (std::string_view{applicator} == "if" && this->has_if_then_else_) { if (schema.defines("then")) { @@ -224,7 +222,7 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { return; } - auto typed_branch{JSON::make_object()}; + auto typed_branch{sourcemeta::core::JSON::make_object()}; for (const auto &entry : schema.as_object()) { if (entry.first == "not" || entry.first == "anyOf" || entry.first == "allOf" || entry.first == "oneOf" || @@ -258,25 +256,25 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { schema.at("allOf").push_back(std::move(typed_branch)); } else { this->typed_branch_index_ = 0; - auto new_allof{JSON::make_array()}; + auto new_allof{sourcemeta::core::JSON::make_array()}; new_allof.push_back(std::move(typed_branch)); schema.assign("allOf", std::move(new_allof)); } if (this->has_modern_ref_ && schema.defines("$ref")) { - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign("$ref", schema.at("$ref")); schema.at("allOf").push_back(std::move(branch)); schema.erase("$ref"); } if (this->has_dynamic_ref_ && schema.defines("$dynamicRef")) { - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign("$dynamicRef", schema.at("$dynamicRef")); schema.at("allOf").push_back(std::move(branch)); schema.erase("$dynamicRef"); } if (this->has_recursive_ref_ && schema.defines("$recursiveRef")) { - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign("$recursiveRef", schema.at("$recursiveRef")); schema.at("allOf").push_back(std::move(branch)); schema.erase("$recursiveRef"); @@ -289,7 +287,7 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { if (this->applicators_with_refs_ & applicator_bit(applicator)) { continue; } - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign(applicator, schema.at(applicator)); if (std::string_view{applicator} == "if" && this->has_if_then_else_) { if (schema.defines("then")) { @@ -314,11 +312,11 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { return; } - auto new_allof{JSON::make_array()}; + auto new_allof{sourcemeta::core::JSON::make_array()}; this->applicator_indices_ = 0; if (this->has_modern_ref_ && schema.defines("$ref")) { - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign("$ref", schema.at("$ref")); if (this->ref_annotations_only_ && !this->typed_keywords_.empty()) { for (const auto &entry : typed_branch.as_object()) { @@ -329,7 +327,7 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { new_allof.push_back(std::move(branch)); } if (this->has_dynamic_ref_ && schema.defines("$dynamicRef")) { - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign("$dynamicRef", schema.at("$dynamicRef")); if (this->ref_annotations_only_ && !this->typed_keywords_.empty()) { for (const auto &entry : typed_branch.as_object()) { @@ -340,7 +338,7 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { new_allof.push_back(std::move(branch)); } if (this->has_recursive_ref_ && schema.defines("$recursiveRef")) { - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign("$recursiveRef", schema.at("$recursiveRef")); if (this->ref_annotations_only_ && !this->typed_keywords_.empty()) { for (const auto &entry : typed_branch.as_object()) { @@ -355,7 +353,7 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { if (!schema.defines(applicator)) { continue; } - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign(applicator, schema.at(applicator)); if (std::string_view{applicator} == "if" && this->has_if_then_else_) { if (schema.defines("then")) { @@ -373,7 +371,7 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { new_allof.push_back(std::move(typed_branch)); } - auto new_schema{JSON::make_object()}; + auto new_schema{sourcemeta::core::JSON::make_object()}; if (schema.defines("$schema")) { new_schema.assign("$schema", schema.at("$schema")); } @@ -420,23 +418,24 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { schema.into(std::move(new_schema)); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { const auto relative{target.resolve_from(current)}; if (relative.empty() || !relative.at(0).is_property()) { return target; } const auto &keyword{relative.at(0).to_property()}; - static const JSON::String allof_keyword{"allOf"}; + static const sourcemeta::core::JSON::String allof_keyword{"allOf"}; for (const auto &typed_kw : this->typed_keywords_) { if (typed_kw == keyword) { - const Pointer old_prefix{current.concat(keyword)}; + const sourcemeta::core::Pointer old_prefix{current.concat(keyword)}; if (this->strategy_ == Strategy::SafeExtract) { - const Pointer new_prefix{current.concat( + const sourcemeta::core::Pointer new_prefix{current.concat( {allof_keyword, this->typed_branch_index_, keyword})}; return target.rebase(old_prefix, new_prefix); } else { @@ -445,7 +444,7 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { (this->has_recursive_ref_ ? 1U : 0U) + static_cast(std::popcount( this->applicator_indices_))}; - const Pointer new_prefix{ + const sourcemeta::core::Pointer new_prefix{ current.concat({allof_keyword, typed_index, keyword})}; return target.rebase(old_prefix, new_prefix); } @@ -468,8 +467,8 @@ class TypeWithApplicatorToAllOf final : public SchemaTransformRule { if (keyword == applicator || (this->has_if_then_else_ && std::string_view{applicator} == "if" && (keyword == "then" || keyword == "else"))) { - const Pointer old_prefix{current.concat(keyword)}; - const Pointer new_prefix{ + const sourcemeta::core::Pointer old_prefix{current.concat(keyword)}; + const sourcemeta::core::Pointer new_prefix{ current.concat({allof_keyword, index, keyword})}; return target.rebase(old_prefix, new_prefix); } diff --git a/src/canonicalizer/rules/type_with_applicator_to_extends.h b/src/canonicalizer/rules/type_with_applicator_to_extends.h index 65e59b447..e48100fe7 100644 --- a/src/canonicalizer/rules/type_with_applicator_to_extends.h +++ b/src/canonicalizer/rules/type_with_applicator_to_extends.h @@ -1,9 +1,8 @@ class TypeWithApplicatorToExtends final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; TypeWithApplicatorToExtends() - : SchemaTransformRule{"type_with_applicator_to_extends", ""} {}; + : SchemaTransformRule{"type_with_applicator_to_extends"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class TypeWithApplicatorToExtends final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_0, Vocabularies::Known::JSON_Schema_Draft_1, @@ -39,10 +37,10 @@ class TypeWithApplicatorToExtends final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { this->typed_keywords_.clear(); - auto typed_branch{JSON::make_object()}; + auto typed_branch{sourcemeta::core::JSON::make_object()}; for (const auto &entry : schema.as_object()) { if (entry.first == "extends" || entry.first == "disallow" || entry.first == "$schema" || entry.first == "id" || @@ -57,7 +55,7 @@ class TypeWithApplicatorToExtends final : public SchemaTransformRule { schema.erase(key); } - auto new_extends{JSON::make_array()}; + auto new_extends{sourcemeta::core::JSON::make_array()}; this->applicator_indices_ = 0; for (const auto &applicator : APPLICATORS) { @@ -68,7 +66,7 @@ class TypeWithApplicatorToExtends final : public SchemaTransformRule { if (std::string_view{applicator} == "type" && !value.is_array()) { continue; } - auto branch{JSON::make_object()}; + auto branch{sourcemeta::core::JSON::make_object()}; branch.assign(applicator, value); new_extends.push_back(std::move(branch)); this->applicator_indices_ |= applicator_bit(applicator); @@ -78,7 +76,7 @@ class TypeWithApplicatorToExtends final : public SchemaTransformRule { new_extends.push_back(std::move(typed_branch)); } - auto new_schema{JSON::make_object()}; + auto new_schema{sourcemeta::core::JSON::make_object()}; if (schema.defines("$schema")) { new_schema.assign("$schema", schema.at("$schema")); } @@ -89,24 +87,25 @@ class TypeWithApplicatorToExtends final : public SchemaTransformRule { schema.into(std::move(new_schema)); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { const auto relative{target.resolve_from(current)}; if (relative.empty() || !relative.at(0).is_property()) { return target; } const auto &keyword{relative.at(0).to_property()}; - static const JSON::String extends_keyword{"extends"}; + static const sourcemeta::core::JSON::String extends_keyword{"extends"}; for (const auto &typed_keyword : this->typed_keywords_) { if (typed_keyword == keyword) { - const Pointer old_prefix{current.concat(keyword)}; + const sourcemeta::core::Pointer old_prefix{current.concat(keyword)}; const std::size_t typed_index{ static_cast(std::popcount(this->applicator_indices_))}; - const Pointer new_prefix{ + const sourcemeta::core::Pointer new_prefix{ current.concat({extends_keyword, typed_index, keyword})}; return target.rebase(old_prefix, new_prefix); } @@ -115,8 +114,8 @@ class TypeWithApplicatorToExtends final : public SchemaTransformRule { std::size_t index{0}; for (const auto &applicator : APPLICATORS) { if (keyword == applicator) { - const Pointer old_prefix{current.concat(keyword)}; - const Pointer new_prefix{ + const sourcemeta::core::Pointer old_prefix{current.concat(keyword)}; + const sourcemeta::core::Pointer new_prefix{ current.concat({extends_keyword, index, keyword})}; return target.rebase(old_prefix, new_prefix); } diff --git a/src/canonicalizer/rules/unevaluated_items_to_items.h b/src/canonicalizer/rules/unevaluated_items_to_items.h index 35d7cb2f7..ae8f3abcf 100644 --- a/src/canonicalizer/rules/unevaluated_items_to_items.h +++ b/src/canonicalizer/rules/unevaluated_items_to_items.h @@ -1,9 +1,8 @@ class UnevaluatedItemsToItems final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; UnevaluatedItemsToItems() - : SchemaTransformRule{"unevaluated_items_to_items", ""} {}; + : SchemaTransformRule{"unevaluated_items_to_items"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class UnevaluatedItemsToItems final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Unevaluated, @@ -40,14 +38,15 @@ class UnevaluatedItemsToItems final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.rename("unevaluatedItems", "items"); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { return target.rebase(current.concat("unevaluatedItems"), current.concat("items")); } diff --git a/src/canonicalizer/rules/unevaluated_properties_to_additional_properties.h b/src/canonicalizer/rules/unevaluated_properties_to_additional_properties.h index 628c14c7a..3564b701c 100644 --- a/src/canonicalizer/rules/unevaluated_properties_to_additional_properties.h +++ b/src/canonicalizer/rules/unevaluated_properties_to_additional_properties.h @@ -1,11 +1,10 @@ class UnevaluatedPropertiesToAdditionalProperties final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; UnevaluatedPropertiesToAdditionalProperties() - : SchemaTransformRule{"unevaluated_properties_to_additional_properties", - ""} {}; + : SchemaTransformRule{"unevaluated_properties_to_additional_properties"} { + }; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,8 +13,7 @@ class UnevaluatedPropertiesToAdditionalProperties final const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Unevaluated, @@ -42,14 +40,15 @@ class UnevaluatedPropertiesToAdditionalProperties final return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.rename("unevaluatedProperties", "additionalProperties"); } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { return target.rebase(current.concat("unevaluatedProperties"), current.concat("additionalProperties")); } diff --git a/src/canonicalizer/rules/unknown_keywords_prefix.h b/src/canonicalizer/rules/unknown_keywords_prefix.h index 488f1bff2..ceabef270 100644 --- a/src/canonicalizer/rules/unknown_keywords_prefix.h +++ b/src/canonicalizer/rules/unknown_keywords_prefix.h @@ -1,21 +1,16 @@ class UnknownKeywordsPrefix final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - UnknownKeywordsPrefix() - : SchemaTransformRule{ - "unknown_keywords_prefix", - "Future versions of JSON Schema will refuse to evaluate unknown " - "keywords or custom keywords from optional vocabularies that don't " - "have an x- prefix"} {}; + UnknownKeywordsPrefix() : SchemaTransformRule{"unknown_keywords_prefix"} {}; [[nodiscard]] auto - condition(const JSON &schema, const JSON &, const Vocabularies &vocabularies, + condition(const sourcemeta::core::JSON &schema, + const sourcemeta::core::JSON &, const Vocabularies &vocabularies, const SchemaFrame &, const SchemaFrame::Location &, - const SchemaWalker &walker, const SchemaResolver &, - const bool) const -> SchemaTransformRule::Result override { + const SchemaWalker &walker, const SchemaResolver &) const + -> bool override { ONLY_CONTINUE_IF(schema.is_object()); - std::vector locations; + std::vector locations; for (const auto &entry : schema.as_object()) { if (entry.first.starts_with("x-")) { continue; @@ -27,7 +22,7 @@ class UnknownKeywordsPrefix final : public SchemaTransformRule { // this seemingly unknown keyword might belong to one of those, and // thus it might not be safe to flag it !vocabularies.has_unknown()) { - locations.push_back(Pointer{entry.first}); + locations.push_back(sourcemeta::core::Pointer{entry.first}); } } @@ -36,7 +31,7 @@ class UnknownKeywordsPrefix final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { this->renames_.clear(); for (const auto &location : this->locations_) { const auto &keyword{location.at(0).to_property()}; @@ -51,13 +46,15 @@ class UnknownKeywordsPrefix final : public SchemaTransformRule { } } - [[nodiscard]] auto rereference(const std::string_view, const Pointer &, - const Pointer &target, - const Pointer ¤t) const - -> Pointer override { + [[nodiscard]] auto rereference(const std::string_view, + const sourcemeta::core::Pointer &, + const sourcemeta::core::Pointer &target, + const sourcemeta::core::Pointer ¤t) const + -> std::optional override { for (const auto &[old_name, new_name] : this->renames_) { - const auto result{target.rebase(current.concat(Pointer{old_name}), - current.concat(Pointer{new_name}))}; + auto result{ + target.rebase(current.concat(sourcemeta::core::Pointer{old_name}), + current.concat(sourcemeta::core::Pointer{new_name}))}; if (result != target) { return result; } diff --git a/src/canonicalizer/rules/unknown_local_ref.h b/src/canonicalizer/rules/unknown_local_ref.h index d3386711b..f7bda5d4e 100644 --- a/src/canonicalizer/rules/unknown_local_ref.h +++ b/src/canonicalizer/rules/unknown_local_ref.h @@ -4,24 +4,21 @@ class UnknownLocalRef final : public SchemaTransformRule { static inline const std::string KEYWORD{"$ref"}; public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; - UnknownLocalRef() - : SchemaTransformRule{ - "unknown_local_ref", - "Local references that point to unknown locations are invalid and " - "will result in evaluation failures"} {}; + UnknownLocalRef() : SchemaTransformRule{"unknown_local_ref"} {}; [[nodiscard]] auto - condition(const JSON &schema, const JSON &, const Vocabularies &vocabularies, + condition(const sourcemeta::core::JSON &schema, + const sourcemeta::core::JSON &, const Vocabularies &vocabularies, const SchemaFrame &frame, const SchemaFrame::Location &location, - const SchemaWalker &, const SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const SchemaWalker &, const SchemaResolver &) const + -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Core, Vocabularies::Known::JSON_Schema_2019_09_Core, - // In JSON Schema Draft 7 and older, `$ref` overrides siblings. - // However, we do not need to worry about this case here, as if the + // In sourcemeta::core::JSON Schema Draft 7 and older, `$ref` overrides + // siblings. However, we do not need to worry about this case here, as + // if the // `$ref` points to an unknown local location, the entire schema is // invalid anyway. We just help at least making the schema valid Vocabularies::Known::JSON_Schema_Draft_7, @@ -57,7 +54,7 @@ class UnknownLocalRef final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { schema.erase(KEYWORD); } }; diff --git a/src/canonicalizer/rules/unnecessary_allof_ref_wrapper_draft.h b/src/canonicalizer/rules/unnecessary_allof_ref_wrapper_draft.h index a17b9717b..ff3b61270 100644 --- a/src/canonicalizer/rules/unnecessary_allof_ref_wrapper_draft.h +++ b/src/canonicalizer/rules/unnecessary_allof_ref_wrapper_draft.h @@ -1,11 +1,8 @@ class UnnecessaryAllOfRefWrapperDraft final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; UnnecessaryAllOfRefWrapperDraft() - : SchemaTransformRule{"unnecessary_allof_ref_wrapper_draft", - "Wrapping `$ref` in `allOf` is only necessary if " - "there are other sibling keywords"} {}; + : SchemaTransformRule{"unnecessary_allof_ref_wrapper_draft"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,8 +11,7 @@ class UnnecessaryAllOfRefWrapperDraft final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_7, Vocabularies::Known::JSON_Schema_Draft_6, @@ -35,7 +31,7 @@ class UnnecessaryAllOfRefWrapperDraft final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { auto value{schema.at("allOf").at(0).at("$ref")}; schema.at("allOf").into(std::move(value)); schema.rename("allOf", "$ref"); diff --git a/src/canonicalizer/rules/unnecessary_extends_ref_wrapper.h b/src/canonicalizer/rules/unnecessary_extends_ref_wrapper.h index f689f8bd3..64f1a5fe1 100644 --- a/src/canonicalizer/rules/unnecessary_extends_ref_wrapper.h +++ b/src/canonicalizer/rules/unnecessary_extends_ref_wrapper.h @@ -1,11 +1,8 @@ class UnnecessaryExtendsRefWrapper final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; UnnecessaryExtendsRefWrapper() - : SchemaTransformRule{"unnecessary_extends_ref_wrapper", - "Wrapping `$ref` in `extends` is only necessary if " - "there are other sibling keywords"} {}; + : SchemaTransformRule{"unnecessary_extends_ref_wrapper"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,8 +11,7 @@ class UnnecessaryExtendsRefWrapper final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_3_Hyper})); @@ -44,7 +40,7 @@ class UnnecessaryExtendsRefWrapper final : public SchemaTransformRule { return false; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { const auto &location{this->locations_.at(0)}; if (location.size() == 3) { auto value{schema.at("extends").at(0).at("$ref")}; diff --git a/src/canonicalizer/rules/unsatisfiable_drop_validation.h b/src/canonicalizer/rules/unsatisfiable_drop_validation.h index 512258722..3f946a883 100644 --- a/src/canonicalizer/rules/unsatisfiable_drop_validation.h +++ b/src/canonicalizer/rules/unsatisfiable_drop_validation.h @@ -1,11 +1,8 @@ class UnsatisfiableDropValidation final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; UnsatisfiableDropValidation() - : SchemaTransformRule{"unsatisfiable_drop_validation", - "Do not place assertions or applicators next to an " - "unsatisfiable negation"} {}; + : SchemaTransformRule{"unsatisfiable_drop_validation"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -14,8 +11,7 @@ class UnsatisfiableDropValidation final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &frame, const sourcemeta::blaze::SchemaFrame::Location &location, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Applicator, Vocabularies::Known::JSON_Schema_2019_09_Applicator, @@ -44,7 +40,7 @@ class UnsatisfiableDropValidation final : public SchemaTransformRule { ONLY_CONTINUE_IF(!trigger_keyword.empty()); - std::vector positions; + std::vector positions; for (const auto &entry : schema.as_object()) { if (entry.first == trigger_keyword) { continue; @@ -56,11 +52,12 @@ class UnsatisfiableDropValidation final : public SchemaTransformRule { } if (frame.has_references_through( - location.pointer, WeakPointer::Token{std::cref(entry.first)})) { + location.pointer, + sourcemeta::core::WeakPointer::Token{std::cref(entry.first)})) { continue; } - positions.push_back(Pointer{entry.first}); + positions.push_back(sourcemeta::core::Pointer{entry.first}); } ONLY_CONTINUE_IF(!positions.empty()); @@ -68,7 +65,7 @@ class UnsatisfiableDropValidation final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { for (const auto &location : this->locations_) { schema.erase(location.at(0).to_property()); } diff --git a/src/canonicalizer/rules/unsatisfiable_exclusive_equal_bounds.h b/src/canonicalizer/rules/unsatisfiable_exclusive_equal_bounds.h index 5f694ac29..dc70d1e8e 100644 --- a/src/canonicalizer/rules/unsatisfiable_exclusive_equal_bounds.h +++ b/src/canonicalizer/rules/unsatisfiable_exclusive_equal_bounds.h @@ -1,9 +1,8 @@ class UnsatisfiableExclusiveEqualBounds final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::false_type; UnsatisfiableExclusiveEqualBounds() - : SchemaTransformRule{"unsatisfiable_exclusive_equal_bounds", ""} {}; + : SchemaTransformRule{"unsatisfiable_exclusive_equal_bounds"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class UnsatisfiableExclusiveEqualBounds final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any({Vocabularies::Known::JSON_Schema_Draft_3, Vocabularies::Known::JSON_Schema_Draft_4}) && @@ -40,7 +38,7 @@ class UnsatisfiableExclusiveEqualBounds final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - schema.into(JSON{false}); + auto transform(sourcemeta::core::JSON &schema) const -> void override { + schema.into(sourcemeta::core::JSON{false}); } }; diff --git a/src/canonicalizer/rules/unsatisfiable_in_place_applicator_type.h b/src/canonicalizer/rules/unsatisfiable_in_place_applicator_type.h index d31f275f1..9494ca73e 100644 --- a/src/canonicalizer/rules/unsatisfiable_in_place_applicator_type.h +++ b/src/canonicalizer/rules/unsatisfiable_in_place_applicator_type.h @@ -1,12 +1,8 @@ class UnsatisfiableInPlaceApplicatorType final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::true_type; UnsatisfiableInPlaceApplicatorType() - : SchemaTransformRule{ - "unsatisfiable_in_place_applicator_type", - "An in-place applicator branch that defines a `type` with no " - "overlap with the parent `type` can never be satisfied"} {}; + : SchemaTransformRule{"unsatisfiable_in_place_applicator_type"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -15,8 +11,7 @@ class UnsatisfiableInPlaceApplicatorType final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF(schema.is_object() && schema.defines("type")); ONLY_CONTINUE_IF(vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_2020_12_Validation, @@ -32,7 +27,7 @@ class UnsatisfiableInPlaceApplicatorType final : public SchemaTransformRule { const auto parent_types{parse_schema_type(schema.at("type"))}; ONLY_CONTINUE_IF(parent_types.any()); - std::vector locations; + std::vector locations; for (const auto &entry : schema.as_object()) { const auto &keyword{entry.first}; @@ -57,7 +52,7 @@ class UnsatisfiableInPlaceApplicatorType final : public SchemaTransformRule { const auto branch_types{parse_schema_type(*branch_type)}; if (branch_types.any() && (parent_types & branch_types).none()) { - locations.push_back(Pointer{keyword, index}); + locations.push_back(sourcemeta::core::Pointer{keyword, index}); } } } else if (keyword_type == @@ -74,7 +69,7 @@ class UnsatisfiableInPlaceApplicatorType final : public SchemaTransformRule { const auto branch_types{parse_schema_type(*branch_type)}; if (branch_types.any() && (parent_types & branch_types).none()) { - locations.push_back(Pointer{keyword}); + locations.push_back(sourcemeta::core::Pointer{keyword}); } } } @@ -84,16 +79,16 @@ class UnsatisfiableInPlaceApplicatorType final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { + auto transform(sourcemeta::core::JSON &schema) const -> void override { for (const auto &location : this->locations_) { if (location.size() == 2) { const auto &keyword{location.at(0).to_property()}; const auto index{location.at(1).to_index()}; - schema.at(keyword).at(index).into(JSON{false}); + schema.at(keyword).at(index).into(sourcemeta::core::JSON{false}); } else { assert(location.size() == 1); const auto &keyword{location.at(0).to_property()}; - schema.at(keyword).into(JSON{false}); + schema.at(keyword).into(sourcemeta::core::JSON{false}); } } } diff --git a/src/canonicalizer/rules/unsatisfiable_type_and_enum.h b/src/canonicalizer/rules/unsatisfiable_type_and_enum.h index ba0a4e242..1537316e3 100644 --- a/src/canonicalizer/rules/unsatisfiable_type_and_enum.h +++ b/src/canonicalizer/rules/unsatisfiable_type_and_enum.h @@ -1,9 +1,8 @@ class UnsatisfiableTypeAndEnum final : public SchemaTransformRule { public: - using mutates = std::true_type; using reframe_after_transform = std::false_type; UnsatisfiableTypeAndEnum() - : SchemaTransformRule{"unsatisfiable_type_and_enum", ""} {}; + : SchemaTransformRule{"unsatisfiable_type_and_enum"} {}; [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, @@ -12,8 +11,7 @@ class UnsatisfiableTypeAndEnum final : public SchemaTransformRule { const sourcemeta::blaze::SchemaFrame &, const sourcemeta::blaze::SchemaFrame::Location &, const sourcemeta::blaze::SchemaWalker &, - const sourcemeta::blaze::SchemaResolver &, const bool) const - -> SchemaTransformRule::Result override { + const sourcemeta::blaze::SchemaResolver &) const -> bool override { ONLY_CONTINUE_IF( vocabularies.contains_any( {Vocabularies::Known::JSON_Schema_Draft_0, @@ -41,7 +39,8 @@ class UnsatisfiableTypeAndEnum final : public SchemaTransformRule { Vocabularies::Known::JSON_Schema_Draft_7, Vocabularies::Known::JSON_Schema_2019_09_Validation, Vocabularies::Known::JSON_Schema_2020_12_Validation}) && - declared_types.test(std::to_underlying(JSON::Type::Integer))}; + declared_types.test( + std::to_underlying(sourcemeta::core::JSON::Type::Integer))}; ONLY_CONTINUE_IF(std::ranges::none_of( enum_value->as_array(), [&declared_types, integer_matches_integral](const auto &value) -> auto { @@ -51,7 +50,7 @@ class UnsatisfiableTypeAndEnum final : public SchemaTransformRule { return true; } - auto transform(JSON &schema, const Result &) const -> void override { - schema.into(JSON{false}); + auto transform(sourcemeta::core::JSON &schema) const -> void override { + schema.into(sourcemeta::core::JSON{false}); } }; diff --git a/src/canonicalizer/transformer.cc b/src/canonicalizer/transformer.cc deleted file mode 100644 index 6af49cca6..000000000 --- a/src/canonicalizer/transformer.cc +++ /dev/null @@ -1,293 +0,0 @@ -#include "canonicalizer_error.h" -#include "canonicalizer_transformer.h" -#include -#include -#include - -#include // assert -#include // std::hash -#include // std::ostringstream -#include // std::tuple -#include // std::unordered_set -#include // std::move -#include // std::vector - -namespace { - -struct ProcessedRuleHasher { - auto - operator()(const std::tuple &value) const noexcept - -> std::size_t { - return sourcemeta::core::Pointer::Hasher{}(std::get<0>(value)) ^ - (std::hash{}(std::get<1>(value)) << 1) ^ - (std::hash{}(std::get<2>(value).fast_hash()) << 2); - } -}; - -auto analyse_frame(sourcemeta::blaze::SchemaFrame &frame, - const sourcemeta::core::JSON &schema, - const sourcemeta::blaze::SchemaWalker &walker, - const sourcemeta::blaze::SchemaResolver &resolver, - const std::string_view default_dialect, - const std::string_view default_id) -> void { - if (!sourcemeta::blaze::identify(schema, resolver, default_dialect).empty()) { - frame.analyse(schema, walker, resolver, default_dialect); - } else { - frame.analyse(schema, walker, resolver, default_dialect, default_id); - } -} - -} // namespace - -namespace sourcemeta::blaze::canonicalizer { - -SchemaTransformRule::SchemaTransformRule(const std::string_view name, - const std::string_view message) - : name_{name}, message_{message} {} - -auto SchemaTransformRule::operator==(const SchemaTransformRule &other) const - -> bool { - return this->name() == other.name(); -} - -auto SchemaTransformRule::name() const noexcept -> std::string_view { - return this->name_; -} - -auto SchemaTransformRule::message() const noexcept -> std::string_view { - return this->message_; -} - -auto SchemaTransformRule::rereference(const std::string_view reference, - const core::Pointer &origin, - const core::Pointer &, - const core::Pointer &) const - -> core::Pointer { - throw SchemaBrokenReferenceError(reference, origin, - "The reference broke after transformation"); -} - -auto SchemaTransformRule::check( - const core::JSON &schema, const core::JSON &root, - const blaze::Vocabularies &vocabularies, const blaze::SchemaWalker &walker, - const blaze::SchemaResolver &resolver, const blaze::SchemaFrame &frame, - const blaze::SchemaFrame::Location &location, - const core::JSON::String &exclude_keyword, const bool is_metaschema) const - -> SchemaTransformRule::Result { - auto result{this->condition(schema, root, vocabularies, frame, location, - walker, resolver, is_metaschema)}; - - if (result && !exclude_keyword.empty() && schema.is_object()) { - const auto *exclude_value{schema.try_at(exclude_keyword)}; - if (exclude_value != nullptr && - ((exclude_value->is_string() && - exclude_value->to_string() == this->name()) || - (exclude_value->is_array() && - exclude_value->contains(this->name())))) { - return false; - } - } - - return result; -} - -auto SchemaTransformer::apply(core::JSON &schema, - const blaze::SchemaWalker &walker, - const blaze::SchemaResolver &resolver, - const SchemaTransformer::Callback &callback, - std::string_view default_dialect, - std::string_view default_id, - const core::JSON::String &exclude_keyword, - const bool is_metaschema) const -> void { - assert(!this->rules.empty()); - std::unordered_set, - ProcessedRuleHasher> - processed_rules; - - blaze::SchemaFrame frame{blaze::SchemaFrame::Mode::References}; - - struct PotentiallyBrokenReference { - core::Pointer origin; - core::JSON::String original; - core::JSON::String destination; - core::JSON::String fragment; - core::Pointer target_pointer; - std::size_t target_relative_pointer; - }; - - std::vector potentially_broken_references; - - while (true) { - if (frame.empty()) { - if (schema.is_boolean()) { - break; - } - - analyse_frame(frame, schema, walker, resolver, default_dialect, - default_id); - } - - std::unordered_set visited; - bool applied{false}; - - for (const auto &entry : frame.locations()) { - if (entry.second.type != blaze::SchemaFrame::LocationType::Resource && - entry.second.type != blaze::SchemaFrame::LocationType::Subschema) { - continue; - } - - const auto [visited_iterator, inserted] = - visited.insert(core::to_pointer(entry.second.pointer)); - if (!inserted) { - continue; - } - const auto &entry_pointer{*visited_iterator}; - auto ¤t{core::get(schema, entry_pointer)}; - const auto current_vocabularies{ - frame.vocabularies(entry.second, resolver)}; - - for (const auto &[rule, mutates, reframe_after_transform] : this->rules) { - if (!mutates) { - continue; - } - - auto outcome{rule->check(current, schema, current_vocabularies, walker, - resolver, frame, entry.second, exclude_keyword, - is_metaschema)}; - - if (!outcome) { - continue; - } - - potentially_broken_references.clear(); - for (const auto &reference : frame.references()) { - const auto destination{frame.traverse(reference.second.destination)}; - if (!destination.has_value() || - !reference.second.fragment.has_value() || - !reference.second.fragment.value().starts_with('/')) { - continue; - } - - const auto &target{destination.value().get()}; - potentially_broken_references.push_back( - {.origin = core::to_pointer(reference.first.second), - .original = core::JSON::String{reference.second.original}, - .destination = reference.second.destination, - .fragment = - core::JSON::String{reference.second.fragment.value()}, - .target_pointer = core::to_pointer(target.pointer), - .target_relative_pointer = target.relative_pointer}); - } - - rule->transform(current, outcome); - callback(entry_pointer, rule->name(), rule->message(), outcome, true); - - applied = true; - - if (reframe_after_transform) { - analyse_frame(frame, schema, walker, resolver, default_dialect, - default_id); - } else if (current.is_boolean()) { - std::tuple mark{ - entry_pointer, rule->name(), current}; - if (processed_rules.contains(mark)) { - throw SchemaTransformRuleProcessedTwiceError(rule->name(), - entry_pointer); - } - - processed_rules.emplace(std::move(mark)); - frame.reset(); - goto blaze_transformer_start_again; - } - - const auto new_location{ - frame.traverse(core::to_weak_pointer(entry_pointer))}; - assert(new_location.has_value()); - - // Fix broken references before re-checking the condition, - // as the re-check may mutate rule state that rereference needs - bool references_fixed{false}; - const auto resource_offset{new_location.value().get().relative_pointer}; - const auto current_slice{entry_pointer.slice(resource_offset)}; - for (const auto &saved_reference : potentially_broken_references) { - if (core::try_get(schema, saved_reference.target_pointer)) { - continue; - } - - // If the origin was also relocated, resolve its new location - auto effective_origin{saved_reference.origin}; - if (!core::try_get(schema, saved_reference.origin.initial())) { - try { - const auto new_origin{rule->rereference( - saved_reference.destination, saved_reference.origin, - saved_reference.origin.slice(resource_offset), - current_slice)}; - effective_origin = - saved_reference.origin.slice(0, resource_offset) - .concat(new_origin); - } catch (...) { - continue; - } - if (!core::try_get(schema, effective_origin.initial())) { - continue; - } - } - - const auto new_relative{rule->rereference( - saved_reference.destination, saved_reference.origin, - saved_reference.target_pointer.slice( - saved_reference.target_relative_pointer), - current_slice)}; - const auto new_fragment{ - saved_reference.fragment == - core::to_string(saved_reference.target_pointer) - ? saved_reference.target_pointer - .slice(0, saved_reference.target_relative_pointer) - .concat(new_relative) - : new_relative}; - - core::URI original{saved_reference.original}; - original.fragment(core::to_string(new_fragment)); - core::set(schema, effective_origin, core::JSON{original.recompose()}); - references_fixed = true; - } - - const auto new_vocabularies{ - frame.vocabularies(new_location.value().get(), resolver)}; - - if (rule->check(current, schema, new_vocabularies, walker, resolver, - frame, new_location.value().get(), exclude_keyword, - is_metaschema)) { - std::ostringstream error; - error << "Rule condition holds after application: " << rule->name(); - throw std::runtime_error(error.str()); - } - - std::tuple mark{ - entry_pointer, rule->name(), current}; - if (processed_rules.contains(mark)) { - throw SchemaTransformRuleProcessedTwiceError(rule->name(), - entry_pointer); - } - - processed_rules.emplace(std::move(mark)); - - if (references_fixed) { - frame.reset(); - } - - if (references_fixed || reframe_after_transform) { - goto blaze_transformer_start_again; - } - } - } - - blaze_transformer_start_again: - if (!applied) { - break; - } - } -} - -} // namespace sourcemeta::blaze::canonicalizer