diff --git a/src/linter/CMakeLists.txt b/src/linter/CMakeLists.txt index 0770afe..7a038c2 100644 --- a/src/linter/CMakeLists.txt +++ b/src/linter/CMakeLists.txt @@ -24,6 +24,98 @@ noa_library(NAMESPACE sourcemeta PROJECT alterschema NAME linter redundant/content_media_type_without_encoding.h redundant/content_schema_default.h redundant/content_schema_without_media_type.h + redundant/drop_non_array_keywords_applicator_2019_09.h + redundant/drop_non_array_keywords_applicator_2020_12.h + redundant/drop_non_array_keywords_content_2019_09.h + redundant/drop_non_array_keywords_content_2020_12.h + redundant/drop_non_array_keywords_draft0.h + redundant/drop_non_array_keywords_draft1.h + redundant/drop_non_array_keywords_draft2.h + redundant/drop_non_array_keywords_draft3.h + redundant/drop_non_array_keywords_draft4.h + redundant/drop_non_array_keywords_draft6.h + redundant/drop_non_array_keywords_draft7.h + redundant/drop_non_array_keywords_format_2019_09.h + redundant/drop_non_array_keywords_format_2020_12.h + redundant/drop_non_array_keywords_unevaluated_2020_12.h + redundant/drop_non_array_keywords_validation_2019_09.h + redundant/drop_non_array_keywords_validation_2020_12.h + redundant/drop_non_boolean_keywords_applicator_2019_09.h + redundant/drop_non_boolean_keywords_applicator_2020_12.h + redundant/drop_non_boolean_keywords_content_2019_09.h + redundant/drop_non_boolean_keywords_content_2020_12.h + redundant/drop_non_boolean_keywords_draft0.h + redundant/drop_non_boolean_keywords_draft1.h + redundant/drop_non_boolean_keywords_draft2.h + redundant/drop_non_boolean_keywords_draft3.h + redundant/drop_non_boolean_keywords_draft4.h + redundant/drop_non_boolean_keywords_draft6.h + redundant/drop_non_boolean_keywords_draft7.h + redundant/drop_non_boolean_keywords_format_2019_09.h + redundant/drop_non_boolean_keywords_format_2020_12.h + redundant/drop_non_boolean_keywords_unevaluated_2020_12.h + redundant/drop_non_boolean_keywords_validation_2019_09.h + redundant/drop_non_boolean_keywords_validation_2020_12.h + redundant/drop_non_null_keywords_applicator_2019_09.h + redundant/drop_non_null_keywords_applicator_2020_12.h + redundant/drop_non_null_keywords_content_2019_09.h + redundant/drop_non_null_keywords_content_2020_12.h + redundant/drop_non_null_keywords_draft0.h + redundant/drop_non_null_keywords_draft1.h + redundant/drop_non_null_keywords_draft2.h + redundant/drop_non_null_keywords_draft3.h + redundant/drop_non_null_keywords_draft4.h + redundant/drop_non_null_keywords_draft6.h + redundant/drop_non_null_keywords_draft7.h + redundant/drop_non_null_keywords_format_2019_09.h + redundant/drop_non_null_keywords_format_2020_12.h + redundant/drop_non_null_keywords_unevaluated_2020_12.h + redundant/drop_non_null_keywords_validation_2019_09.h + redundant/drop_non_null_keywords_validation_2020_12.h + redundant/drop_non_numeric_keywords_applicator_2019_09.h + redundant/drop_non_numeric_keywords_applicator_2020_12.h + redundant/drop_non_numeric_keywords_content_2019_09.h + redundant/drop_non_numeric_keywords_content_2020_12.h + redundant/drop_non_numeric_keywords_draft0.h + redundant/drop_non_numeric_keywords_draft1.h + redundant/drop_non_numeric_keywords_draft2.h + redundant/drop_non_numeric_keywords_draft3.h + redundant/drop_non_numeric_keywords_draft4.h + redundant/drop_non_numeric_keywords_draft6.h + redundant/drop_non_numeric_keywords_draft7.h + redundant/drop_non_numeric_keywords_format_2019_09.h + redundant/drop_non_numeric_keywords_format_2020_12.h + redundant/drop_non_numeric_keywords_unevaluated_2020_12.h + redundant/drop_non_numeric_keywords_validation_2019_09.h + redundant/drop_non_numeric_keywords_validation_2020_12.h + redundant/drop_non_object_keywords_applicator_2019_09.h + redundant/drop_non_object_keywords_applicator_2020_12.h + redundant/drop_non_object_keywords_content_2019_09.h + redundant/drop_non_object_keywords_content_2020_12.h + redundant/drop_non_object_keywords_draft0.h + redundant/drop_non_object_keywords_draft1.h + redundant/drop_non_object_keywords_draft2.h + redundant/drop_non_object_keywords_draft3.h + redundant/drop_non_object_keywords_draft4.h + redundant/drop_non_object_keywords_draft6.h + redundant/drop_non_object_keywords_draft7.h + redundant/drop_non_object_keywords_format_2019_09.h + redundant/drop_non_object_keywords_format_2020_12.h + redundant/drop_non_object_keywords_unevaluated_2020_12.h + redundant/drop_non_object_keywords_validation_2019_09.h + redundant/drop_non_object_keywords_validation_2020_12.h + redundant/drop_non_string_keywords_applicator_2019_09.h + redundant/drop_non_string_keywords_applicator_2020_12.h + redundant/drop_non_string_keywords_draft0.h + redundant/drop_non_string_keywords_draft1.h + redundant/drop_non_string_keywords_draft2.h + redundant/drop_non_string_keywords_draft3.h + redundant/drop_non_string_keywords_draft4.h + redundant/drop_non_string_keywords_draft6.h + redundant/drop_non_string_keywords_draft7.h + redundant/drop_non_string_keywords_unevaluated_2020_12.h + redundant/drop_non_string_keywords_validation_2019_09.h + redundant/drop_non_string_keywords_validation_2020_12.h redundant/duplicate_allof_branches.h redundant/duplicate_anyof_branches.h redundant/else_without_if.h diff --git a/src/linter/linter.cc b/src/linter/linter.cc index 6ff2e4a..e4e185e 100644 --- a/src/linter/linter.cc +++ b/src/linter/linter.cc @@ -14,6 +14,16 @@ auto contains_any(const T &container, const T &values) -> bool { [&values](const auto &element) { return values.contains(element); }); } +template auto every_item_is_null(const T &container) -> bool { + return std::all_of(std::cbegin(container), std::cend(container), + [](const auto &element) { return element.is_null(); }); +} + +template auto every_item_is_boolean(const T &container) -> bool { + return std::all_of(std::cbegin(container), std::cend(container), + [](const auto &element) { return element.is_boolean(); }); +} + // Modernize #include "modernize/enum_to_const.h" // AntiPattern @@ -34,6 +44,98 @@ auto contains_any(const T &container, const T &values) -> bool { #include "redundant/content_media_type_without_encoding.h" #include "redundant/content_schema_default.h" #include "redundant/content_schema_without_media_type.h" +#include "redundant/drop_non_array_keywords_applicator_2019_09.h" +#include "redundant/drop_non_array_keywords_applicator_2020_12.h" +#include "redundant/drop_non_array_keywords_content_2019_09.h" +#include "redundant/drop_non_array_keywords_content_2020_12.h" +#include "redundant/drop_non_array_keywords_draft0.h" +#include "redundant/drop_non_array_keywords_draft1.h" +#include "redundant/drop_non_array_keywords_draft2.h" +#include "redundant/drop_non_array_keywords_draft3.h" +#include "redundant/drop_non_array_keywords_draft4.h" +#include "redundant/drop_non_array_keywords_draft6.h" +#include "redundant/drop_non_array_keywords_draft7.h" +#include "redundant/drop_non_array_keywords_format_2019_09.h" +#include "redundant/drop_non_array_keywords_format_2020_12.h" +#include "redundant/drop_non_array_keywords_unevaluated_2020_12.h" +#include "redundant/drop_non_array_keywords_validation_2019_09.h" +#include "redundant/drop_non_array_keywords_validation_2020_12.h" +#include "redundant/drop_non_boolean_keywords_applicator_2019_09.h" +#include "redundant/drop_non_boolean_keywords_applicator_2020_12.h" +#include "redundant/drop_non_boolean_keywords_content_2019_09.h" +#include "redundant/drop_non_boolean_keywords_content_2020_12.h" +#include "redundant/drop_non_boolean_keywords_draft0.h" +#include "redundant/drop_non_boolean_keywords_draft1.h" +#include "redundant/drop_non_boolean_keywords_draft2.h" +#include "redundant/drop_non_boolean_keywords_draft3.h" +#include "redundant/drop_non_boolean_keywords_draft4.h" +#include "redundant/drop_non_boolean_keywords_draft6.h" +#include "redundant/drop_non_boolean_keywords_draft7.h" +#include "redundant/drop_non_boolean_keywords_format_2019_09.h" +#include "redundant/drop_non_boolean_keywords_format_2020_12.h" +#include "redundant/drop_non_boolean_keywords_unevaluated_2020_12.h" +#include "redundant/drop_non_boolean_keywords_validation_2019_09.h" +#include "redundant/drop_non_boolean_keywords_validation_2020_12.h" +#include "redundant/drop_non_null_keywords_applicator_2019_09.h" +#include "redundant/drop_non_null_keywords_applicator_2020_12.h" +#include "redundant/drop_non_null_keywords_content_2019_09.h" +#include "redundant/drop_non_null_keywords_content_2020_12.h" +#include "redundant/drop_non_null_keywords_draft0.h" +#include "redundant/drop_non_null_keywords_draft1.h" +#include "redundant/drop_non_null_keywords_draft2.h" +#include "redundant/drop_non_null_keywords_draft3.h" +#include "redundant/drop_non_null_keywords_draft4.h" +#include "redundant/drop_non_null_keywords_draft6.h" +#include "redundant/drop_non_null_keywords_draft7.h" +#include "redundant/drop_non_null_keywords_format_2019_09.h" +#include "redundant/drop_non_null_keywords_format_2020_12.h" +#include "redundant/drop_non_null_keywords_unevaluated_2020_12.h" +#include "redundant/drop_non_null_keywords_validation_2019_09.h" +#include "redundant/drop_non_null_keywords_validation_2020_12.h" +#include "redundant/drop_non_numeric_keywords_applicator_2019_09.h" +#include "redundant/drop_non_numeric_keywords_applicator_2020_12.h" +#include "redundant/drop_non_numeric_keywords_content_2019_09.h" +#include "redundant/drop_non_numeric_keywords_content_2020_12.h" +#include "redundant/drop_non_numeric_keywords_draft0.h" +#include "redundant/drop_non_numeric_keywords_draft1.h" +#include "redundant/drop_non_numeric_keywords_draft2.h" +#include "redundant/drop_non_numeric_keywords_draft3.h" +#include "redundant/drop_non_numeric_keywords_draft4.h" +#include "redundant/drop_non_numeric_keywords_draft6.h" +#include "redundant/drop_non_numeric_keywords_draft7.h" +#include "redundant/drop_non_numeric_keywords_format_2019_09.h" +#include "redundant/drop_non_numeric_keywords_format_2020_12.h" +#include "redundant/drop_non_numeric_keywords_unevaluated_2020_12.h" +#include "redundant/drop_non_numeric_keywords_validation_2019_09.h" +#include "redundant/drop_non_numeric_keywords_validation_2020_12.h" +#include "redundant/drop_non_object_keywords_applicator_2019_09.h" +#include "redundant/drop_non_object_keywords_applicator_2020_12.h" +#include "redundant/drop_non_object_keywords_content_2019_09.h" +#include "redundant/drop_non_object_keywords_content_2020_12.h" +#include "redundant/drop_non_object_keywords_draft0.h" +#include "redundant/drop_non_object_keywords_draft1.h" +#include "redundant/drop_non_object_keywords_draft2.h" +#include "redundant/drop_non_object_keywords_draft3.h" +#include "redundant/drop_non_object_keywords_draft4.h" +#include "redundant/drop_non_object_keywords_draft6.h" +#include "redundant/drop_non_object_keywords_draft7.h" +#include "redundant/drop_non_object_keywords_format_2019_09.h" +#include "redundant/drop_non_object_keywords_format_2020_12.h" +#include "redundant/drop_non_object_keywords_unevaluated_2020_12.h" +#include "redundant/drop_non_object_keywords_validation_2019_09.h" +#include "redundant/drop_non_object_keywords_validation_2020_12.h" +#include "redundant/drop_non_string_keywords_applicator_2019_09.h" +#include "redundant/drop_non_string_keywords_applicator_2020_12.h" +#include "redundant/drop_non_string_keywords_draft0.h" +#include "redundant/drop_non_string_keywords_draft1.h" +#include "redundant/drop_non_string_keywords_draft2.h" +#include "redundant/drop_non_string_keywords_draft3.h" +#include "redundant/drop_non_string_keywords_draft4.h" +#include "redundant/drop_non_string_keywords_draft6.h" +#include "redundant/drop_non_string_keywords_draft7.h" +#include "redundant/drop_non_string_keywords_unevaluated_2020_12.h" +#include "redundant/drop_non_string_keywords_validation_2019_09.h" +#include "redundant/drop_non_string_keywords_validation_2020_12.h" #include "redundant/duplicate_allof_branches.h" #include "redundant/duplicate_anyof_branches.h" #include "redundant/else_without_if.h" @@ -79,6 +181,98 @@ auto add(Bundle &bundle, const LinterCategory category) -> 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(); diff --git a/src/linter/redundant/drop_non_array_keywords_applicator_2019_09.h b/src/linter/redundant/drop_non_array_keywords_applicator_2019_09.h new file mode 100644 index 0000000..b243195 --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_applicator_2019_09.h @@ -0,0 +1,30 @@ +class DropNonArrayKeywordsApplicator_2019_09 final : public Rule { +public: + DropNonArrayKeywordsApplicator_2019_09() + : Rule{"drop_non_array_keywords_applicator_2019_09", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/applicator") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "patternProperties", "additionalProperties", + "dependentSchemas", "propertyNames", "unevaluatedProperties"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_applicator_2020_12.h b/src/linter/redundant/drop_non_array_keywords_applicator_2020_12.h new file mode 100644 index 0000000..05b0802 --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_applicator_2020_12.h @@ -0,0 +1,30 @@ +class DropNonArrayKeywordsApplicator_2020_12 final : public Rule { +public: + DropNonArrayKeywordsApplicator_2020_12() + : Rule{"drop_non_array_keywords_applicator_2020_12", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/applicator") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"properties", "patternProperties", + "additionalProperties", + "dependentSchemas", "propertyNames"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_content_2019_09.h b/src/linter/redundant/drop_non_array_keywords_content_2019_09.h new file mode 100644 index 0000000..75fc7a2 --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_content_2019_09.h @@ -0,0 +1,29 @@ +class DropNonArrayKeywordsContent_2019_09 final : public Rule { +public: + DropNonArrayKeywordsContent_2019_09() + : Rule{"drop_non_array_keywords_content_2019_09", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/content") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"contentEncoding", "contentMediaType", + "contentSchema"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_content_2020_12.h b/src/linter/redundant/drop_non_array_keywords_content_2020_12.h new file mode 100644 index 0000000..a2f8263 --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_content_2020_12.h @@ -0,0 +1,29 @@ +class DropNonArrayKeywordsContent_2020_12 final : public Rule { +public: + DropNonArrayKeywordsContent_2020_12() + : Rule{"drop_non_array_keywords_content_2020_12", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/content") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"contentEncoding", "contentMediaType", + "contentSchema"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_draft0.h b/src/linter/redundant/drop_non_array_keywords_draft0.h new file mode 100644 index 0000000..98c7460 --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_draft0.h @@ -0,0 +1,30 @@ +class DropNonArrayKeywords_Draft0 final : public Rule { +public: + DropNonArrayKeywords_Draft0() + : Rule{"drop_non_array_keywords_draft0", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-00/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "maxDecimal", "maximum", "maximumCanEqual", "minimum", + "minimumCanEqual", "maxLength", "minLength", "pattern", + "requires", "optional", "properties", "additionalProperties", + "contentEncoding", "format"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_draft1.h b/src/linter/redundant/drop_non_array_keywords_draft1.h new file mode 100644 index 0000000..a44e710 --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_draft1.h @@ -0,0 +1,30 @@ +class DropNonArrayKeywords_Draft1 final : public Rule { +public: + DropNonArrayKeywords_Draft1() + : Rule{"drop_non_array_keywords_draft1", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-01/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "maxDecimal", "maximum", "maximumCanEqual", "minimum", + "minimumCanEqual", "maxLength", "minLength", "pattern", + "requires", "optional", "properties", "additionalProperties", + "contentEncoding", "format"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_draft2.h b/src/linter/redundant/drop_non_array_keywords_draft2.h new file mode 100644 index 0000000..425b9f0 --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_draft2.h @@ -0,0 +1,31 @@ +class DropNonArrayKeywords_Draft2 final : public Rule { +public: + DropNonArrayKeywords_Draft2() + : Rule{"drop_non_array_keywords_draft2", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-02/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "optional", "additionalProperties", + "requires", "minimum", "maximum", + "minimumCanEqual", "maximumCanEqual", "pattern", + "maxLength", "minLength", "format", + "contentEncoding", "divisibleBy"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_draft3.h b/src/linter/redundant/drop_non_array_keywords_draft3.h new file mode 100644 index 0000000..7599fe8 --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_draft3.h @@ -0,0 +1,30 @@ +class DropNonArrayKeywords_Draft3 final : public Rule { +public: + DropNonArrayKeywords_Draft3() + : Rule{"drop_non_array_keywords_draft3", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-03/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "patternProperties", "additionalProperties", + "required", "dependencies", "minimum", + "maximum", "exclusiveMinimum", "exclusiveMaximum", + "pattern", "minLength", "maxLength", + "format", "divisibleBy"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_draft4.h b/src/linter/redundant/drop_non_array_keywords_draft4.h new file mode 100644 index 0000000..913a945 --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_draft4.h @@ -0,0 +1,33 @@ +class DropNonArrayKeywords_Draft4 final : public Rule { +public: + DropNonArrayKeywords_Draft4() + : Rule{"drop_non_array_keywords_draft4", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-04/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "multipleOf", "maximum", + "exclusiveMaximum", "minimum", + "exclusiveMinimum", "maxLength", + "minLength", "pattern", + "maxProperties", "minProperties", + "required", "properties", + "patternProperties", "additionalProperties", + "dependencies", "format"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_draft6.h b/src/linter/redundant/drop_non_array_keywords_draft6.h new file mode 100644 index 0000000..5fc0ae4 --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_draft6.h @@ -0,0 +1,41 @@ +class DropNonArrayKeywords_Draft6 final : public Rule { +public: + DropNonArrayKeywords_Draft6() + : Rule{"drop_non_array_keywords_draft6", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-06/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"multipleOf", + "maximum", + "exclusiveMaximum", + "minimum", + "exclusiveMinimum", + "maxLength", + "minLength", + "pattern", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "propertyNames", + "dependencies", + "format"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_draft7.h b/src/linter/redundant/drop_non_array_keywords_draft7.h new file mode 100644 index 0000000..58c9dbd --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_draft7.h @@ -0,0 +1,43 @@ +class DropNonArrayKeywords_Draft7 final : public Rule { +public: + DropNonArrayKeywords_Draft7() + : Rule{"drop_non_array_keywords_draft7", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-07/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"multipleOf", + "maximum", + "exclusiveMaximum", + "minimum", + "exclusiveMinimum", + "maxLength", + "minLength", + "pattern", + "contentEncoding", + "contentMediaType", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "propertyNames", + "dependencies", + "format"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_format_2019_09.h b/src/linter/redundant/drop_non_array_keywords_format_2019_09.h new file mode 100644 index 0000000..92d34bb --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_format_2019_09.h @@ -0,0 +1,28 @@ +class DropNonArrayKeywordsFormat_2019_09 final : public Rule { +public: + DropNonArrayKeywordsFormat_2019_09() + : Rule{"drop_non_array_keywords_format_2019_09", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/format") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"format"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_format_2020_12.h b/src/linter/redundant/drop_non_array_keywords_format_2020_12.h new file mode 100644 index 0000000..4aea095 --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_format_2020_12.h @@ -0,0 +1,30 @@ +class DropNonArrayKeywordsFormat_2020_12 final : public Rule { +public: + DropNonArrayKeywordsFormat_2020_12() + : Rule{"drop_non_array_keywords_format_2020_12", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + (vocabularies.contains("https://json-schema.org/draft/2020-12/vocab/" + "format-annotation") || + vocabularies.contains("https://json-schema.org/draft/2020-12/vocab/" + "format-assertion")) && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"format"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_unevaluated_2020_12.h b/src/linter/redundant/drop_non_array_keywords_unevaluated_2020_12.h new file mode 100644 index 0000000..e3ae17a --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_unevaluated_2020_12.h @@ -0,0 +1,28 @@ +class DropNonArrayKeywordsUnevaluated_2020_12 final : public Rule { +public: + DropNonArrayKeywordsUnevaluated_2020_12() + : Rule{"drop_non_array_keywords_unevaluated_2020_12", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/unevaluated") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"unevaluatedProperties"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_validation_2019_09.h b/src/linter/redundant/drop_non_array_keywords_validation_2019_09.h new file mode 100644 index 0000000..dcdcab1 --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_validation_2019_09.h @@ -0,0 +1,29 @@ +class DropNonArrayKeywordsValidation_2019_09 final : public Rule { +public: + DropNonArrayKeywordsValidation_2019_09() + : Rule{"drop_non_array_keywords_validation_2019_09", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "minLength", "maxLength", "pattern", "maximum", + "exclusiveMinimum", "multipleOf", "exclusiveMaximum", "minimum", + "dependentRequired", "minProperties", "maxProperties", "required"}; +}; diff --git a/src/linter/redundant/drop_non_array_keywords_validation_2020_12.h b/src/linter/redundant/drop_non_array_keywords_validation_2020_12.h new file mode 100644 index 0000000..58ecce5 --- /dev/null +++ b/src/linter/redundant/drop_non_array_keywords_validation_2020_12.h @@ -0,0 +1,29 @@ +class DropNonArrayKeywordsValidation_2020_12 final : public Rule { +public: + DropNonArrayKeywordsValidation_2020_12() + : Rule{"drop_non_array_keywords_validation_2020_12", + "Keywords that don't apply to arrays will never match if the " + "instance is guaranteed to be an array"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "array" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "minLength", "maxLength", "pattern", "maximum", + "exclusiveMinimum", "multipleOf", "exclusiveMaximum", "minimum", + "dependentRequired", "minProperties", "maxProperties", "required"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_applicator_2019_09.h b/src/linter/redundant/drop_non_boolean_keywords_applicator_2019_09.h new file mode 100644 index 0000000..d26cb0f --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_applicator_2019_09.h @@ -0,0 +1,39 @@ +class DropNonBooleanKeywordsApplicator_2019_09 final : public Rule { +public: + DropNonBooleanKeywordsApplicator_2019_09() + : Rule{"drop_non_boolean_keywords_applicator_2019_09", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "boolean") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_boolean(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/applicator") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"properties", + "patternProperties", + "additionalProperties", + "dependentSchemas", + "propertyNames", + "additionalItems", + "contains", + "items", + "unevaluatedProperties", + "unevaluatedItems"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_applicator_2020_12.h b/src/linter/redundant/drop_non_boolean_keywords_applicator_2020_12.h new file mode 100644 index 0000000..ae03d39 --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_applicator_2020_12.h @@ -0,0 +1,37 @@ +class DropNonBooleanKeywordsApplicator_2020_12 final : public Rule { +public: + DropNonBooleanKeywordsApplicator_2020_12() + : Rule{"drop_non_boolean_keywords_applicator_2020_12", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "boolean") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_boolean(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/applicator") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"properties", + "patternProperties", + "additionalProperties", + "dependentSchemas", + "propertyNames", + "prefixItems", + "contains", + "items"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_content_2019_09.h b/src/linter/redundant/drop_non_boolean_keywords_content_2019_09.h new file mode 100644 index 0000000..33fe367 --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_content_2019_09.h @@ -0,0 +1,31 @@ +class DropNonBooleanKeywordsContent_2019_09 final : public Rule { +public: + DropNonBooleanKeywordsContent_2019_09() + : Rule{"drop_non_boolean_keywords_content_2019_09", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "boolean") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_boolean(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/content") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"contentEncoding", "contentMediaType", + "contentSchema"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_content_2020_12.h b/src/linter/redundant/drop_non_boolean_keywords_content_2020_12.h new file mode 100644 index 0000000..bf1b98f --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_content_2020_12.h @@ -0,0 +1,31 @@ +class DropNonBooleanKeywordsContent_2020_12 final : public Rule { +public: + DropNonBooleanKeywordsContent_2020_12() + : Rule{"drop_non_boolean_keywords_content_2020_12", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "boolean") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_boolean(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/content") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"contentEncoding", "contentMediaType", + "contentSchema"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_draft0.h b/src/linter/redundant/drop_non_boolean_keywords_draft0.h new file mode 100644 index 0000000..91323dd --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_draft0.h @@ -0,0 +1,30 @@ +class DropNonBooleanKeywords_Draft0 final : public Rule { +public: + DropNonBooleanKeywords_Draft0() + : Rule{"drop_non_boolean_keywords_draft0", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-00/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "boolean" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "items", "optional", "additionalProperties", + "requires", "minimum", "maximum", "minimumCanEqual", + "maximumCanEqual", "minItems", "maxItems", "maxLength", + "minLength", "format", "contentEncoding", "maxDecimal"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_draft1.h b/src/linter/redundant/drop_non_boolean_keywords_draft1.h new file mode 100644 index 0000000..e9a8848 --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_draft1.h @@ -0,0 +1,30 @@ +class DropNonBooleanKeywords_Draft1 final : public Rule { +public: + DropNonBooleanKeywords_Draft1() + : Rule{"drop_non_boolean_keywords_draft1", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-01/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "boolean" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "items", "optional", "additionalProperties", + "requires", "minimum", "maximum", "minimumCanEqual", + "maximumCanEqual", "minItems", "maxItems", "maxLength", + "minLength", "format", "contentEncoding", "maxDecimal"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_draft2.h b/src/linter/redundant/drop_non_boolean_keywords_draft2.h new file mode 100644 index 0000000..09f1a27 --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_draft2.h @@ -0,0 +1,31 @@ +class DropNonBooleanKeywords_Draft2 final : public Rule { +public: + DropNonBooleanKeywords_Draft2() + : Rule{"drop_non_boolean_keywords_draft2", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-02/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "boolean" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "items", "optional", "additionalProperties", + "requires", "minimum", "maximum", "minimumCanEqual", + "maximumCanEqual", "minItems", "maxItems", "uniqueItems", + "pattern", "maxLength", "minLength", "format", + "contentEncoding", "divisibleBy"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_draft3.h b/src/linter/redundant/drop_non_boolean_keywords_draft3.h new file mode 100644 index 0000000..97a7877 --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_draft3.h @@ -0,0 +1,43 @@ +class DropNonBooleanKeywords_Draft3 final : public Rule { +public: + DropNonBooleanKeywords_Draft3() + : Rule{"drop_non_boolean_keywords_draft3", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-03/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "boolean" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"properties", + "patternProperties", + "additionalProperties", + "items", + "additionalItems", + "required", + "dependencies", + "minimum", + "maximum", + "exclusiveMinimum", + "exclusiveMaximum", + "minItems", + "maxItems", + "uniqueItems", + "pattern", + "minLength", + "maxLength", + "format", + "divisibleBy"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_draft4.h b/src/linter/redundant/drop_non_boolean_keywords_draft4.h new file mode 100644 index 0000000..6840ec5 --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_draft4.h @@ -0,0 +1,45 @@ +class DropNonBooleanKeywords_Draft4 final : public Rule { +public: + DropNonBooleanKeywords_Draft4() + : Rule{"drop_non_boolean_keywords_draft4", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-04/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "boolean" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"multipleOf", + "maximum", + "exclusiveMaximum", + "minimum", + "exclusiveMinimum", + "maxLength", + "minLength", + "pattern", + "additionalItems", + "items", + "maxItems", + "minItems", + "uniqueItems", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "dependencies", + "format"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_draft6.h b/src/linter/redundant/drop_non_boolean_keywords_draft6.h new file mode 100644 index 0000000..94de111 --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_draft6.h @@ -0,0 +1,47 @@ +class DropNonBooleanKeywords_Draft6 final : public Rule { +public: + DropNonBooleanKeywords_Draft6() + : Rule{"drop_non_boolean_keywords_draft6", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-06/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "boolean" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"multipleOf", + "maximum", + "exclusiveMaximum", + "minimum", + "exclusiveMinimum", + "maxLength", + "minLength", + "pattern", + "additionalItems", + "items", + "contains", + "maxItems", + "minItems", + "uniqueItems", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "propertyNames", + "dependencies", + "format"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_draft7.h b/src/linter/redundant/drop_non_boolean_keywords_draft7.h new file mode 100644 index 0000000..c66f550 --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_draft7.h @@ -0,0 +1,49 @@ +class DropNonBooleanKeywords_Draft7 final : public Rule { +public: + DropNonBooleanKeywords_Draft7() + : Rule{"drop_non_boolean_keywords_draft7", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-07/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "boolean" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"multipleOf", + "maximum", + "exclusiveMaximum", + "minimum", + "exclusiveMinimum", + "maxLength", + "minLength", + "pattern", + "contentEncoding", + "contentMediaType", + "additionalItems", + "items", + "contains", + "maxItems", + "minItems", + "uniqueItems", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "propertyNames", + "dependencies", + "format"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_format_2019_09.h b/src/linter/redundant/drop_non_boolean_keywords_format_2019_09.h new file mode 100644 index 0000000..3e1d681 --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_format_2019_09.h @@ -0,0 +1,30 @@ +class DropNonBooleanKeywordsFormat_2019_09 final : public Rule { +public: + DropNonBooleanKeywordsFormat_2019_09() + : Rule{"drop_non_boolean_keywords_format_2019_09", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "boolean") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_boolean(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/format") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"format"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_format_2020_12.h b/src/linter/redundant/drop_non_boolean_keywords_format_2020_12.h new file mode 100644 index 0000000..fc93814 --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_format_2020_12.h @@ -0,0 +1,32 @@ +class DropNonBooleanKeywordsFormat_2020_12 final : public Rule { +public: + DropNonBooleanKeywordsFormat_2020_12() + : Rule{"drop_non_boolean_keywords_format_2020_12", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "boolean") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_boolean(schema.at("enum").as_array()))) && + (vocabularies.contains("https://json-schema.org/draft/2020-12/vocab/" + "format-annotation") || + vocabularies.contains("https://json-schema.org/draft/2020-12/vocab/" + "format-assertion")) && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"format"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_unevaluated_2020_12.h b/src/linter/redundant/drop_non_boolean_keywords_unevaluated_2020_12.h new file mode 100644 index 0000000..a2e2b3a --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_unevaluated_2020_12.h @@ -0,0 +1,31 @@ +class DropNonBooleanKeywordsUnevaluated_2020_12 final : public Rule { +public: + DropNonBooleanKeywordsUnevaluated_2020_12() + : Rule{"drop_non_boolean_keywords_unevaluated_2020_12", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "boolean") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_boolean(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/unevaluated") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"unevaluatedItems", + "unevaluatedProperties"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_validation_2019_09.h b/src/linter/redundant/drop_non_boolean_keywords_validation_2019_09.h new file mode 100644 index 0000000..072b8e8 --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_validation_2019_09.h @@ -0,0 +1,35 @@ +class DropNonBooleanKeywordsValidation_2019_09 final : public Rule { +public: + DropNonBooleanKeywordsValidation_2019_09() + : Rule{"drop_non_boolean_keywords_validation_2019_09", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "boolean") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_boolean(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "minLength", "maxLength", "pattern", "maximum", + "exclusiveMinimum", "multipleOf", "exclusiveMaximum", "minimum", + "dependentRequired", "minProperties", "maxProperties", "required", + "minItems", "maxItems", "minContains", "maxContains", + "uniqueItems"}; +}; diff --git a/src/linter/redundant/drop_non_boolean_keywords_validation_2020_12.h b/src/linter/redundant/drop_non_boolean_keywords_validation_2020_12.h new file mode 100644 index 0000000..e3d5b81 --- /dev/null +++ b/src/linter/redundant/drop_non_boolean_keywords_validation_2020_12.h @@ -0,0 +1,35 @@ +class DropNonBooleanKeywordsValidation_2020_12 final : public Rule { +public: + DropNonBooleanKeywordsValidation_2020_12() + : Rule{"drop_non_boolean_keywords_validation_2020_12", + "Keywords that don't apply to booleans will never match if the " + "instance is guaranteed to be a boolean"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "boolean") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_boolean(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "minLength", "maxLength", "pattern", "maximum", + "exclusiveMinimum", "multipleOf", "exclusiveMaximum", "minimum", + "dependentRequired", "minProperties", "maxProperties", "required", + "minItems", "maxItems", "minContains", "maxContains", + "uniqueItems"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_applicator_2019_09.h b/src/linter/redundant/drop_non_null_keywords_applicator_2019_09.h new file mode 100644 index 0000000..b6279f4 --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_applicator_2019_09.h @@ -0,0 +1,39 @@ +class DropNonNullKeywordsApplicator_2019_09 final : public Rule { +public: + DropNonNullKeywordsApplicator_2019_09() + : Rule{"drop_non_null_keywords_applicator_2019_09", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "null") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_null(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/applicator") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"properties", + "patternProperties", + "additionalProperties", + "dependentSchemas", + "propertyNames", + "additionalItems", + "contains", + "items", + "unevaluatedProperties", + "unevaluatedItems"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_applicator_2020_12.h b/src/linter/redundant/drop_non_null_keywords_applicator_2020_12.h new file mode 100644 index 0000000..f6958e0 --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_applicator_2020_12.h @@ -0,0 +1,37 @@ +class DropNonNullKeywordsApplicator_2020_12 final : public Rule { +public: + DropNonNullKeywordsApplicator_2020_12() + : Rule{"drop_non_null_keywords_applicator_2020_12", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "null") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_null(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/applicator") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"properties", + "patternProperties", + "additionalProperties", + "dependentSchemas", + "propertyNames", + "prefixItems", + "contains", + "items"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_content_2019_09.h b/src/linter/redundant/drop_non_null_keywords_content_2019_09.h new file mode 100644 index 0000000..9343c03 --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_content_2019_09.h @@ -0,0 +1,31 @@ +class DropNonNullKeywordsContent_2019_09 final : public Rule { +public: + DropNonNullKeywordsContent_2019_09() + : Rule{"drop_non_null_keywords_content_2019_09", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "null") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_null(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/content") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"contentEncoding", "contentMediaType", + "contentSchema"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_content_2020_12.h b/src/linter/redundant/drop_non_null_keywords_content_2020_12.h new file mode 100644 index 0000000..61538b1 --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_content_2020_12.h @@ -0,0 +1,31 @@ +class DropNonNullKeywordsContent_2020_12 final : public Rule { +public: + DropNonNullKeywordsContent_2020_12() + : Rule{"drop_non_null_keywords_content_2020_12", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "null") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_null(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/content") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"contentEncoding", "contentMediaType", + "contentSchema"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_draft0.h b/src/linter/redundant/drop_non_null_keywords_draft0.h new file mode 100644 index 0000000..366d193 --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_draft0.h @@ -0,0 +1,30 @@ +class DropNonNullKeywords_Draft0 final : public Rule { +public: + DropNonNullKeywords_Draft0() + : Rule{"drop_non_null_keywords_draft0", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-00/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "null" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "items", "optional", "additionalProperties", + "requires", "minimum", "maximum", "minimumCanEqual", + "maximumCanEqual", "minItems", "maxItems", "maxLength", + "minLength", "format", "contentEncoding", "maxDecimal"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_draft1.h b/src/linter/redundant/drop_non_null_keywords_draft1.h new file mode 100644 index 0000000..8b2a85d --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_draft1.h @@ -0,0 +1,30 @@ +class DropNonNullKeywords_Draft1 final : public Rule { +public: + DropNonNullKeywords_Draft1() + : Rule{"drop_non_null_keywords_draft1", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-01/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "null" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "items", "optional", "additionalProperties", + "requires", "minimum", "maximum", "minimumCanEqual", + "maximumCanEqual", "minItems", "maxItems", "maxLength", + "minLength", "format", "contentEncoding", "maxDecimal"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_draft2.h b/src/linter/redundant/drop_non_null_keywords_draft2.h new file mode 100644 index 0000000..f06acf8 --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_draft2.h @@ -0,0 +1,31 @@ +class DropNonNullKeywords_Draft2 final : public Rule { +public: + DropNonNullKeywords_Draft2() + : Rule{"drop_non_null_keywords_draft2", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-02/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "null" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "items", "optional", "additionalProperties", + "requires", "minimum", "maximum", "minimumCanEqual", + "maximumCanEqual", "minItems", "maxItems", "uniqueItems", + "pattern", "maxLength", "minLength", "format", + "contentEncoding", "divisibleBy"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_draft3.h b/src/linter/redundant/drop_non_null_keywords_draft3.h new file mode 100644 index 0000000..ffb36cf --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_draft3.h @@ -0,0 +1,43 @@ +class DropNonNullKeywords_Draft3 final : public Rule { +public: + DropNonNullKeywords_Draft3() + : Rule{"drop_non_null_keywords_draft3", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-03/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "null" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"properties", + "patternProperties", + "additionalProperties", + "items", + "additionalItems", + "required", + "dependencies", + "minimum", + "maximum", + "exclusiveMinimum", + "exclusiveMaximum", + "minItems", + "maxItems", + "uniqueItems", + "pattern", + "minLength", + "maxLength", + "format", + "divisibleBy"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_draft4.h b/src/linter/redundant/drop_non_null_keywords_draft4.h new file mode 100644 index 0000000..8aed21e --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_draft4.h @@ -0,0 +1,45 @@ +class DropNonNullKeywords_Draft4 final : public Rule { +public: + DropNonNullKeywords_Draft4() + : Rule{"drop_non_null_keywords_draft4", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-04/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "null" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"multipleOf", + "maximum", + "exclusiveMaximum", + "minimum", + "exclusiveMinimum", + "maxLength", + "minLength", + "pattern", + "additionalItems", + "items", + "maxItems", + "minItems", + "uniqueItems", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "dependencies", + "format"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_draft6.h b/src/linter/redundant/drop_non_null_keywords_draft6.h new file mode 100644 index 0000000..2be83a8 --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_draft6.h @@ -0,0 +1,47 @@ +class DropNonNullKeywords_Draft6 final : public Rule { +public: + DropNonNullKeywords_Draft6() + : Rule{"drop_non_null_keywords_draft6", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-06/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "null" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"multipleOf", + "maximum", + "exclusiveMaximum", + "minimum", + "exclusiveMinimum", + "maxLength", + "minLength", + "pattern", + "additionalItems", + "items", + "contains", + "maxItems", + "minItems", + "uniqueItems", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "propertyNames", + "dependencies", + "format"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_draft7.h b/src/linter/redundant/drop_non_null_keywords_draft7.h new file mode 100644 index 0000000..a025d45 --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_draft7.h @@ -0,0 +1,49 @@ +class DropNonNullKeywords_Draft7 final : public Rule { +public: + DropNonNullKeywords_Draft7() + : Rule{"drop_non_null_keywords_draft7", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-07/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "null" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"multipleOf", + "maximum", + "exclusiveMaximum", + "minimum", + "exclusiveMinimum", + "maxLength", + "minLength", + "pattern", + "contentEncoding", + "contentMediaType", + "additionalItems", + "items", + "contains", + "maxItems", + "minItems", + "uniqueItems", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "propertyNames", + "dependencies", + "format"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_format_2019_09.h b/src/linter/redundant/drop_non_null_keywords_format_2019_09.h new file mode 100644 index 0000000..28592fc --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_format_2019_09.h @@ -0,0 +1,30 @@ +class DropNonNullKeywordsFormat_2019_09 final : public Rule { +public: + DropNonNullKeywordsFormat_2019_09() + : Rule{"drop_non_null_keywords_format_2019_09", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "null") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_null(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/format") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"format"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_format_2020_12.h b/src/linter/redundant/drop_non_null_keywords_format_2020_12.h new file mode 100644 index 0000000..de26f8d --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_format_2020_12.h @@ -0,0 +1,32 @@ +class DropNonNullKeywordsFormat_2020_12 final : public Rule { +public: + DropNonNullKeywordsFormat_2020_12() + : Rule{"drop_non_null_keywords_format_2020_12", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "null") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_null(schema.at("enum").as_array()))) && + (vocabularies.contains("https://json-schema.org/draft/2020-12/vocab/" + "format-annotation") || + vocabularies.contains("https://json-schema.org/draft/2020-12/vocab/" + "format-assertion")) && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"format"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_unevaluated_2020_12.h b/src/linter/redundant/drop_non_null_keywords_unevaluated_2020_12.h new file mode 100644 index 0000000..de42538 --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_unevaluated_2020_12.h @@ -0,0 +1,31 @@ +class DropNonNullKeywordsUnevaluated_2020_12 final : public Rule { +public: + DropNonNullKeywordsUnevaluated_2020_12() + : Rule{"drop_non_null_keywords_unevaluated_2020_12", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "null") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_null(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/unevaluated") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"unevaluatedItems", + "unevaluatedProperties"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_validation_2019_09.h b/src/linter/redundant/drop_non_null_keywords_validation_2019_09.h new file mode 100644 index 0000000..b35331f --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_validation_2019_09.h @@ -0,0 +1,35 @@ +class DropNonNullKeywordsValidation_2019_09 final : public Rule { +public: + DropNonNullKeywordsValidation_2019_09() + : Rule{"drop_non_null_keywords_validation_2019_09", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "null") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_null(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "minLength", "maxLength", "pattern", "maximum", + "exclusiveMinimum", "multipleOf", "exclusiveMaximum", "minimum", + "dependentRequired", "minProperties", "maxProperties", "required", + "minItems", "maxItems", "minContains", "maxContains", + "uniqueItems"}; +}; diff --git a/src/linter/redundant/drop_non_null_keywords_validation_2020_12.h b/src/linter/redundant/drop_non_null_keywords_validation_2020_12.h new file mode 100644 index 0000000..be528a4 --- /dev/null +++ b/src/linter/redundant/drop_non_null_keywords_validation_2020_12.h @@ -0,0 +1,35 @@ +class DropNonNullKeywordsValidation_2020_12 final : public Rule { +public: + DropNonNullKeywordsValidation_2020_12() + : Rule{"drop_non_null_keywords_validation_2020_12", + "Keywords that don't apply to null values will never match if the " + "instance is guaranteed to be null"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && + ((schema.defines("type") && schema.at("type").is_string() && + schema.at("type").to_string() == "null") || + (schema.defines("enum") && schema.at("enum").is_array() && + every_item_is_null(schema.at("enum").as_array()))) && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "minLength", "maxLength", "pattern", "maximum", + "exclusiveMinimum", "multipleOf", "exclusiveMaximum", "minimum", + "dependentRequired", "minProperties", "maxProperties", "required", + "minItems", "maxItems", "minContains", "maxContains", + "uniqueItems"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_applicator_2019_09.h b/src/linter/redundant/drop_non_numeric_keywords_applicator_2019_09.h new file mode 100644 index 0000000..6827d61 --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_applicator_2019_09.h @@ -0,0 +1,38 @@ +class DropNonNumericKeywordsApplicator_2019_09 final : public Rule { +public: + DropNonNumericKeywordsApplicator_2019_09() + : Rule{"drop_non_numeric_keywords_applicator_2019_09", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "integer" || + schema.at("type").to_string() == "number") && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/applicator") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"properties", + "patternProperties", + "additionalProperties", + "dependentSchemas", + "propertyNames", + "additionalItems", + "contains", + "items", + "unevaluatedProperties", + "unevaluatedItems"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_applicator_2020_12.h b/src/linter/redundant/drop_non_numeric_keywords_applicator_2020_12.h new file mode 100644 index 0000000..e475d11 --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_applicator_2020_12.h @@ -0,0 +1,36 @@ +class DropNonNumericKeywordsApplicator_2020_12 final : public Rule { +public: + DropNonNumericKeywordsApplicator_2020_12() + : Rule{"drop_non_numeric_keywords_applicator_2020_12", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "integer" || + schema.at("type").to_string() == "number") && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/applicator") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"properties", + "patternProperties", + "additionalProperties", + "dependentSchemas", + "propertyNames", + "prefixItems", + "contains", + "items"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_content_2019_09.h b/src/linter/redundant/drop_non_numeric_keywords_content_2019_09.h new file mode 100644 index 0000000..db6bac2 --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_content_2019_09.h @@ -0,0 +1,30 @@ +class DropNonNumericKeywordsContent_2019_09 final : public Rule { +public: + DropNonNumericKeywordsContent_2019_09() + : Rule{"drop_non_numeric_keywords_content_2019_09", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "integer" || + schema.at("type").to_string() == "number") && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/content") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"contentEncoding", "contentMediaType", + "contentSchema"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_content_2020_12.h b/src/linter/redundant/drop_non_numeric_keywords_content_2020_12.h new file mode 100644 index 0000000..40f0194 --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_content_2020_12.h @@ -0,0 +1,30 @@ +class DropNonNumericKeywordsContent_2020_12 final : public Rule { +public: + DropNonNumericKeywordsContent_2020_12() + : Rule{"drop_non_numeric_keywords_content_2020_12", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "integer" || + schema.at("type").to_string() == "number") && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/content") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"contentEncoding", "contentMediaType", + "contentSchema"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_draft0.h b/src/linter/redundant/drop_non_numeric_keywords_draft0.h new file mode 100644 index 0000000..b8ac546 --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_draft0.h @@ -0,0 +1,30 @@ +class DropNonNumericKeywords_Draft0 final : public Rule { +public: + DropNonNumericKeywords_Draft0() + : Rule{"drop_non_numeric_keywords_draft0", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-00/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "number" || + schema.at("type").to_string() == "integer") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "items", "optional", "additionalProperties", + "requires", "minItems", "maxItems", "maxLength", + "minLength", "format", "contentEncoding"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_draft1.h b/src/linter/redundant/drop_non_numeric_keywords_draft1.h new file mode 100644 index 0000000..f27f584 --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_draft1.h @@ -0,0 +1,30 @@ +class DropNonNumericKeywords_Draft1 final : public Rule { +public: + DropNonNumericKeywords_Draft1() + : Rule{"drop_non_numeric_keywords_draft1", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-01/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "number" || + schema.at("type").to_string() == "integer") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "items", "optional", "additionalProperties", + "requires", "minItems", "maxItems", "maxLength", + "minLength", "format", "contentEncoding"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_draft2.h b/src/linter/redundant/drop_non_numeric_keywords_draft2.h new file mode 100644 index 0000000..4b14b7b --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_draft2.h @@ -0,0 +1,31 @@ +class DropNonNumericKeywords_Draft2 final : public Rule { +public: + DropNonNumericKeywords_Draft2() + : Rule{"drop_non_numeric_keywords_draft2", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-02/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "number" || + schema.at("type").to_string() == "integer") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "items", "optional", "additionalProperties", + "requires", "minItems", "maxItems", "uniqueItems", + "pattern", "maxLength", "minLength", "format", + "contentEncoding"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_draft3.h b/src/linter/redundant/drop_non_numeric_keywords_draft3.h new file mode 100644 index 0000000..82e02ca --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_draft3.h @@ -0,0 +1,39 @@ +class DropNonNumericKeywords_Draft3 final : public Rule { +public: + DropNonNumericKeywords_Draft3() + : Rule{"drop_non_numeric_keywords_draft3", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-03/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "number" || + schema.at("type").to_string() == "integer") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"properties", + "patternProperties", + "additionalProperties", + "items", + "additionalItems", + "required", + "dependencies", + "minItems", + "maxItems", + "uniqueItems", + "pattern", + "minLength", + "maxLength", + "format"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_draft4.h b/src/linter/redundant/drop_non_numeric_keywords_draft4.h new file mode 100644 index 0000000..10b0bfd --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_draft4.h @@ -0,0 +1,41 @@ +class DropNonNumericKeywords_Draft4 final : public Rule { +public: + DropNonNumericKeywords_Draft4() + : Rule{"drop_non_numeric_keywords_draft4", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-04/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "number" || + schema.at("type").to_string() == "integer") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"maxLength", + "minLength", + "pattern", + "additionalItems", + "items", + "maxItems", + "minItems", + "uniqueItems", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "dependencies", + "format"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_draft6.h b/src/linter/redundant/drop_non_numeric_keywords_draft6.h new file mode 100644 index 0000000..6fc5029 --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_draft6.h @@ -0,0 +1,43 @@ +class DropNonNumericKeywords_Draft6 final : public Rule { +public: + DropNonNumericKeywords_Draft6() + : Rule{"drop_non_numeric_keywords_draft6", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-06/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "number" || + schema.at("type").to_string() == "integer") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"maxLength", + "minLength", + "pattern", + "additionalItems", + "items", + "contains", + "maxItems", + "minItems", + "uniqueItems", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "propertyNames", + "dependencies", + "format"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_draft7.h b/src/linter/redundant/drop_non_numeric_keywords_draft7.h new file mode 100644 index 0000000..befe174 --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_draft7.h @@ -0,0 +1,45 @@ +class DropNonNumericKeywords_Draft7 final : public Rule { +public: + DropNonNumericKeywords_Draft7() + : Rule{"drop_non_numeric_keywords_draft7", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-07/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "number" || + schema.at("type").to_string() == "integer") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"maxLength", + "minLength", + "pattern", + "contentEncoding", + "contentMediaType", + "additionalItems", + "items", + "contains", + "maxItems", + "minItems", + "uniqueItems", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "propertyNames", + "dependencies", + "format"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_format_2019_09.h b/src/linter/redundant/drop_non_numeric_keywords_format_2019_09.h new file mode 100644 index 0000000..1dc8145 --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_format_2019_09.h @@ -0,0 +1,29 @@ +class DropNonNumericKeywordsFormat_2019_09 final : public Rule { +public: + DropNonNumericKeywordsFormat_2019_09() + : Rule{"drop_non_numeric_keywords_format_2019_09", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "integer" || + schema.at("type").to_string() == "number") && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/format") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"format"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_format_2020_12.h b/src/linter/redundant/drop_non_numeric_keywords_format_2020_12.h new file mode 100644 index 0000000..1fbe343 --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_format_2020_12.h @@ -0,0 +1,31 @@ +class DropNonNumericKeywordsFormat_2020_12 final : public Rule { +public: + DropNonNumericKeywordsFormat_2020_12() + : Rule{"drop_non_numeric_keywords_format_2020_12", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "integer" || + schema.at("type").to_string() == "number") && + (vocabularies.contains("https://json-schema.org/draft/2020-12/vocab/" + "format-annotation") || + vocabularies.contains("https://json-schema.org/draft/2020-12/vocab/" + "format-assertion")) && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"format"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_unevaluated_2020_12.h b/src/linter/redundant/drop_non_numeric_keywords_unevaluated_2020_12.h new file mode 100644 index 0000000..919ff86 --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_unevaluated_2020_12.h @@ -0,0 +1,30 @@ +class DropNonNumericKeywordsUnevaluated_2020_12 final : public Rule { +public: + DropNonNumericKeywordsUnevaluated_2020_12() + : Rule{"drop_non_numeric_keywords_unevaluated_2020_12", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "integer" || + schema.at("type").to_string() == "number") && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/unevaluated") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"unevaluatedItems", + "unevaluatedProperties"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_validation_2019_09.h b/src/linter/redundant/drop_non_numeric_keywords_validation_2019_09.h new file mode 100644 index 0000000..7d6f186 --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_validation_2019_09.h @@ -0,0 +1,30 @@ +class DropNonNumericKeywordsValidation_2019_09 final : public Rule { +public: + DropNonNumericKeywordsValidation_2019_09() + : Rule{"drop_non_numeric_keywords_validation_2019_09", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "integer" || + schema.at("type").to_string() == "number") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "minLength", "maxLength", "pattern", "dependentRequired", + "minProperties", "maxProperties", "required", "minItems", + "maxItems", "minContains", "maxContains", "uniqueItems"}; +}; diff --git a/src/linter/redundant/drop_non_numeric_keywords_validation_2020_12.h b/src/linter/redundant/drop_non_numeric_keywords_validation_2020_12.h new file mode 100644 index 0000000..c74e72b --- /dev/null +++ b/src/linter/redundant/drop_non_numeric_keywords_validation_2020_12.h @@ -0,0 +1,30 @@ +class DropNonNumericKeywordsValidation_2020_12 final : public Rule { +public: + DropNonNumericKeywordsValidation_2020_12() + : Rule{"drop_non_numeric_keywords_validation_2020_12", + "Keywords that don't apply to numbers will never match if the " + "instance is guaranteed to be a number"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + (schema.at("type").to_string() == "integer" || + schema.at("type").to_string() == "number") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "minLength", "maxLength", "pattern", "dependentRequired", + "minProperties", "maxProperties", "required", "minItems", + "maxItems", "minContains", "maxContains", "uniqueItems"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_applicator_2019_09.h b/src/linter/redundant/drop_non_object_keywords_applicator_2019_09.h new file mode 100644 index 0000000..59e255e --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_applicator_2019_09.h @@ -0,0 +1,29 @@ +class DropNonObjectKeywordsApplicator_2019_09 final : public Rule { +public: + DropNonObjectKeywordsApplicator_2019_09() + : Rule{"drop_non_object_keywords_applicator_2019_09", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/applicator") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"additionalItems", "contains", "items", + "unevaluatedItems"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_applicator_2020_12.h b/src/linter/redundant/drop_non_object_keywords_applicator_2020_12.h new file mode 100644 index 0000000..212d009 --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_applicator_2020_12.h @@ -0,0 +1,28 @@ +class DropNonObjectKeywordsApplicator_2020_12 final : public Rule { +public: + DropNonObjectKeywordsApplicator_2020_12() + : Rule{"drop_non_object_keywords_applicator_2020_12", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/applicator") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"prefixItems", "contains", "items"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_content_2019_09.h b/src/linter/redundant/drop_non_object_keywords_content_2019_09.h new file mode 100644 index 0000000..eb73b34 --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_content_2019_09.h @@ -0,0 +1,29 @@ +class DropNonObjectKeywordsContent_2019_09 final : public Rule { +public: + DropNonObjectKeywordsContent_2019_09() + : Rule{"drop_non_object_keywords_content_2019_09", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/content") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"contentEncoding", "contentMediaType", + "contentSchema"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_content_2020_12.h b/src/linter/redundant/drop_non_object_keywords_content_2020_12.h new file mode 100644 index 0000000..70d2485 --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_content_2020_12.h @@ -0,0 +1,29 @@ +class DropNonObjectKeywordsContent_2020_12 final : public Rule { +public: + DropNonObjectKeywordsContent_2020_12() + : Rule{"drop_non_object_keywords_content_2020_12", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/content") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"contentEncoding", "contentMediaType", + "contentSchema"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_draft0.h b/src/linter/redundant/drop_non_object_keywords_draft0.h new file mode 100644 index 0000000..67f4e46 --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_draft0.h @@ -0,0 +1,29 @@ +class DropNonObjectKeywords_Draft0 final : public Rule { +public: + DropNonObjectKeywords_Draft0() + : Rule{"drop_non_object_keywords_draft0", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-00/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "items", "minimum", "maximum", "minimumCanEqual", + "maximumCanEqual", "minItems", "maxItems", "maxLength", + "minLength", "format", "contentEncoding", "maxDecimal"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_draft1.h b/src/linter/redundant/drop_non_object_keywords_draft1.h new file mode 100644 index 0000000..56e84ca --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_draft1.h @@ -0,0 +1,29 @@ +class DropNonObjectKeywords_Draft1 final : public Rule { +public: + DropNonObjectKeywords_Draft1() + : Rule{"drop_non_object_keywords_draft1", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-01/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "items", "minimum", "maximum", "minimumCanEqual", + "maximumCanEqual", "minItems", "maxItems", "maxLength", + "minLength", "format", "contentEncoding", "maxDecimal"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_draft2.h b/src/linter/redundant/drop_non_object_keywords_draft2.h new file mode 100644 index 0000000..0c21be2 --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_draft2.h @@ -0,0 +1,29 @@ +class DropNonObjectKeywords_Draft2 final : public Rule { +public: + DropNonObjectKeywords_Draft2() + : Rule{"drop_non_object_keywords_draft2", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-02/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "items", "minimum", "maximum", "minimumCanEqual", + "maximumCanEqual", "minItems", "maxItems", "maxLength", + "minLength", "format", "contentEncoding", "maxDecimal"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_draft3.h b/src/linter/redundant/drop_non_object_keywords_draft3.h new file mode 100644 index 0000000..d33ecb3 --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_draft3.h @@ -0,0 +1,29 @@ +class DropNonObjectKeywords_Draft3 final : public Rule { +public: + DropNonObjectKeywords_Draft3() + : Rule{"drop_non_object_keywords_draft3", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-03/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "items", "additionalItems", "required", "minimum", + "maximum", "exclusiveMinimum", "exclusiveMaximum", "minItems", + "maxItems", "uniqueItems", "pattern", "minLength", + "maxLength", "format", "divisibleBy"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_draft4.h b/src/linter/redundant/drop_non_object_keywords_draft4.h new file mode 100644 index 0000000..55ecaea --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_draft4.h @@ -0,0 +1,29 @@ +class DropNonObjectKeywords_Draft4 final : public Rule { +public: + DropNonObjectKeywords_Draft4() + : Rule{"drop_non_object_keywords_draft4", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-04/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "multipleOf", "maximum", "exclusiveMaximum", "minimum", + "exclusiveMinimum", "maxLength", "minLength", "pattern", + "additionalItems", "items", "maxItems", "minItems", + "uniqueItems", "format"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_draft6.h b/src/linter/redundant/drop_non_object_keywords_draft6.h new file mode 100644 index 0000000..22942ef --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_draft6.h @@ -0,0 +1,30 @@ +class DropNonObjectKeywords_Draft6 final : public Rule { +public: + DropNonObjectKeywords_Draft6() + : Rule{"drop_non_object_keywords_draft6", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-06/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "multipleOf", "maximum", "exclusiveMaximum", + "minimum", "exclusiveMinimum", "maxLength", + "minLength", "pattern", "additionalItems", + "items", "contains", "maxItems", + "minItems", "uniqueItems", "format"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_draft7.h b/src/linter/redundant/drop_non_object_keywords_draft7.h new file mode 100644 index 0000000..3e0db71 --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_draft7.h @@ -0,0 +1,41 @@ +class DropNonObjectKeywords_Draft7 final : public Rule { +public: + DropNonObjectKeywords_Draft7() + : Rule{"drop_non_object_keywords_draft7", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-07/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"multipleOf", + "maximum", + "exclusiveMaximum", + "minimum", + "exclusiveMinimum", + "maxLength", + "minLength", + "pattern", + "contentEncoding", + "contentMediaType", + "additionalItems", + "items", + "contains", + "maxItems", + "minItems", + "uniqueItems", + "format"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_format_2019_09.h b/src/linter/redundant/drop_non_object_keywords_format_2019_09.h new file mode 100644 index 0000000..3ac6973 --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_format_2019_09.h @@ -0,0 +1,28 @@ +class DropNonObjectKeywordsFormat_2019_09 final : public Rule { +public: + DropNonObjectKeywordsFormat_2019_09() + : Rule{"drop_non_object_keywords_format_2019_09", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/format") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"format"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_format_2020_12.h b/src/linter/redundant/drop_non_object_keywords_format_2020_12.h new file mode 100644 index 0000000..8ab84ed --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_format_2020_12.h @@ -0,0 +1,30 @@ +class DropNonObjectKeywordsFormat_2020_12 final : public Rule { +public: + DropNonObjectKeywordsFormat_2020_12() + : Rule{"drop_non_object_keywords_format_2020_12", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + (vocabularies.contains("https://json-schema.org/draft/2020-12/vocab/" + "format-annotation") || + vocabularies.contains("https://json-schema.org/draft/2020-12/vocab/" + "format-assertion")) && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"format"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_unevaluated_2020_12.h b/src/linter/redundant/drop_non_object_keywords_unevaluated_2020_12.h new file mode 100644 index 0000000..a486125 --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_unevaluated_2020_12.h @@ -0,0 +1,28 @@ +class DropNonObjectKeywordsUnevaluated_2020_12 final : public Rule { +public: + DropNonObjectKeywordsUnevaluated_2020_12() + : Rule{"drop_non_object_keywords_unevaluated_2020_12", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/unevaluated") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"unevaluatedItems"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_validation_2019_09.h b/src/linter/redundant/drop_non_object_keywords_validation_2019_09.h new file mode 100644 index 0000000..d41cff0 --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_validation_2019_09.h @@ -0,0 +1,30 @@ +class DropNonObjectKeywordsValidation_2019_09 final : public Rule { +public: + DropNonObjectKeywordsValidation_2019_09() + : Rule{"drop_non_object_keywords_validation_2019_09", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "minLength", "maxLength", "pattern", "maximum", + "exclusiveMinimum", "multipleOf", "exclusiveMaximum", "minimum", + "minItems", "maxItems", "minContains", "maxContains", + "uniqueItems"}; +}; diff --git a/src/linter/redundant/drop_non_object_keywords_validation_2020_12.h b/src/linter/redundant/drop_non_object_keywords_validation_2020_12.h new file mode 100644 index 0000000..90dc496 --- /dev/null +++ b/src/linter/redundant/drop_non_object_keywords_validation_2020_12.h @@ -0,0 +1,30 @@ +class DropNonObjectKeywordsValidation_2020_12 final : public Rule { +public: + DropNonObjectKeywordsValidation_2020_12() + : Rule{"drop_non_object_keywords_validation_2020_12", + "Keywords that don't apply to objects will never match if the " + "instance is guaranteed to be an object"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "object" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "minLength", "maxLength", "pattern", "maximum", + "exclusiveMinimum", "multipleOf", "exclusiveMaximum", "minimum", + "minItems", "maxItems", "minContains", "maxContains", + "uniqueItems"}; +}; diff --git a/src/linter/redundant/drop_non_string_keywords_applicator_2019_09.h b/src/linter/redundant/drop_non_string_keywords_applicator_2019_09.h new file mode 100644 index 0000000..7133783 --- /dev/null +++ b/src/linter/redundant/drop_non_string_keywords_applicator_2019_09.h @@ -0,0 +1,37 @@ +class DropNonStringKeywordsApplicator_2019_09 final : public Rule { +public: + DropNonStringKeywordsApplicator_2019_09() + : Rule{"drop_non_string_keywords_applicator_2019_09", + "Keywords that don't apply to strings will never match if the " + "instance is guaranteed to be a string"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "string" && + vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/applicator") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"properties", + "patternProperties", + "additionalProperties", + "dependentSchemas", + "propertyNames", + "additionalItems", + "contains", + "items", + "unevaluatedProperties", + "unevaluatedItems"}; +}; diff --git a/src/linter/redundant/drop_non_string_keywords_applicator_2020_12.h b/src/linter/redundant/drop_non_string_keywords_applicator_2020_12.h new file mode 100644 index 0000000..0f6c4e7 --- /dev/null +++ b/src/linter/redundant/drop_non_string_keywords_applicator_2020_12.h @@ -0,0 +1,35 @@ +class DropNonStringKeywordsApplicator_2020_12 final : public Rule { +public: + DropNonStringKeywordsApplicator_2020_12() + : Rule{"drop_non_string_keywords_applicator_2020_12", + "Keywords that don't apply to strings will never match if the " + "instance is guaranteed to be a string"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "string" && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/applicator") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"properties", + "patternProperties", + "additionalProperties", + "dependentSchemas", + "propertyNames", + "prefixItems", + "contains", + "items"}; +}; diff --git a/src/linter/redundant/drop_non_string_keywords_draft0.h b/src/linter/redundant/drop_non_string_keywords_draft0.h new file mode 100644 index 0000000..db7309e --- /dev/null +++ b/src/linter/redundant/drop_non_string_keywords_draft0.h @@ -0,0 +1,29 @@ +class DropNonStringKeywords_Draft0 final : public Rule { +public: + DropNonStringKeywords_Draft0() + : Rule{"drop_non_string_keywords_draft0", + "Keywords that don't apply to strings will never match if the " + "instance is guaranteed to be a string"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-00/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "string" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "items", "optional", "additionalProperties", + "requires", "minimum", "maximum", "minimumCanEqual", + "maximumCanEqual", "minItems", "maxItems", "maxDecimal"}; +}; diff --git a/src/linter/redundant/drop_non_string_keywords_draft1.h b/src/linter/redundant/drop_non_string_keywords_draft1.h new file mode 100644 index 0000000..d8099ee --- /dev/null +++ b/src/linter/redundant/drop_non_string_keywords_draft1.h @@ -0,0 +1,29 @@ +class DropNonStringKeywords_Draft1 final : public Rule { +public: + DropNonStringKeywords_Draft1() + : Rule{"drop_non_string_keywords_draft1", + "Keywords that don't apply to strings will never match if the " + "instance is guaranteed to be a string"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-01/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "string" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "items", "optional", "additionalProperties", + "requires", "minimum", "maximum", "minimumCanEqual", + "maximumCanEqual", "minItems", "maxItems", "maxDecimal"}; +}; diff --git a/src/linter/redundant/drop_non_string_keywords_draft2.h b/src/linter/redundant/drop_non_string_keywords_draft2.h new file mode 100644 index 0000000..7b85ec2 --- /dev/null +++ b/src/linter/redundant/drop_non_string_keywords_draft2.h @@ -0,0 +1,30 @@ +class DropNonStringKeywords_Draft2 final : public Rule { +public: + DropNonStringKeywords_Draft2() + : Rule{"drop_non_string_keywords_draft2", + "Keywords that don't apply to strings will never match if the " + "instance is guaranteed to be a string"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "http://json-schema.org/draft-02/hyper-schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "string" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "properties", "items", "optional", "additionalProperties", + "requires", "minimum", "maximum", "minimumCanEqual", + "maximumCanEqual", "minItems", "maxItems", "uniqueItems", + "divisibleBy"}; +}; diff --git a/src/linter/redundant/drop_non_string_keywords_draft3.h b/src/linter/redundant/drop_non_string_keywords_draft3.h new file mode 100644 index 0000000..16b3376 --- /dev/null +++ b/src/linter/redundant/drop_non_string_keywords_draft3.h @@ -0,0 +1,39 @@ +class DropNonStringKeywords_Draft3 final : public Rule { +public: + DropNonStringKeywords_Draft3() + : Rule{"drop_non_string_keywords_draft3", + "Keywords that don't apply to strings will never match if the " + "instance is guaranteed to be a string"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-03/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "string" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"properties", + "patternProperties", + "additionalProperties", + "items", + "additionalItems", + "required", + "dependencies", + "minimum", + "maximum", + "exclusiveMinimum", + "exclusiveMaximum", + "minItems", + "maxItems", + "uniqueItems", + "divisibleBy"}; +}; diff --git a/src/linter/redundant/drop_non_string_keywords_draft4.h b/src/linter/redundant/drop_non_string_keywords_draft4.h new file mode 100644 index 0000000..aacd47b --- /dev/null +++ b/src/linter/redundant/drop_non_string_keywords_draft4.h @@ -0,0 +1,41 @@ +class DropNonStringKeywords_Draft4 final : public Rule { +public: + DropNonStringKeywords_Draft4() + : Rule{"drop_non_string_keywords_draft4", + "Keywords that don't apply to strings will never match if the " + "instance is guaranteed to be a string"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-04/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "string" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"multipleOf", + "maximum", + "exclusiveMaximum", + "minimum", + "exclusiveMinimum", + "additionalItems", + "items", + "maxItems", + "minItems", + "uniqueItems", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "dependencies"}; +}; diff --git a/src/linter/redundant/drop_non_string_keywords_draft6.h b/src/linter/redundant/drop_non_string_keywords_draft6.h new file mode 100644 index 0000000..e3e9f03 --- /dev/null +++ b/src/linter/redundant/drop_non_string_keywords_draft6.h @@ -0,0 +1,43 @@ +class DropNonStringKeywords_Draft6 final : public Rule { +public: + DropNonStringKeywords_Draft6() + : Rule{"drop_non_string_keywords_draft6", + "Keywords that don't apply to strings will never match if the " + "instance is guaranteed to be a string"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-06/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "string" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"multipleOf", + "maximum", + "exclusiveMaximum", + "minimum", + "exclusiveMinimum", + "additionalItems", + "items", + "contains", + "maxItems", + "minItems", + "uniqueItems", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "propertyNames", + "dependencies"}; +}; diff --git a/src/linter/redundant/drop_non_string_keywords_draft7.h b/src/linter/redundant/drop_non_string_keywords_draft7.h new file mode 100644 index 0000000..5eff1fc --- /dev/null +++ b/src/linter/redundant/drop_non_string_keywords_draft7.h @@ -0,0 +1,43 @@ +class DropNonStringKeywords_Draft7 final : public Rule { +public: + DropNonStringKeywords_Draft7() + : Rule{"drop_non_string_keywords_draft7", + "Keywords that don't apply to strings will never match if the " + "instance is guaranteed to be a string"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains("http://json-schema.org/draft-07/schema#") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "string" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"multipleOf", + "maximum", + "exclusiveMaximum", + "minimum", + "exclusiveMinimum", + "additionalItems", + "items", + "contains", + "maxItems", + "minItems", + "uniqueItems", + "maxProperties", + "minProperties", + "required", + "properties", + "patternProperties", + "additionalProperties", + "propertyNames", + "dependencies"}; +}; diff --git a/src/linter/redundant/drop_non_string_keywords_unevaluated_2020_12.h b/src/linter/redundant/drop_non_string_keywords_unevaluated_2020_12.h new file mode 100644 index 0000000..2d7495f --- /dev/null +++ b/src/linter/redundant/drop_non_string_keywords_unevaluated_2020_12.h @@ -0,0 +1,29 @@ +class DropNonStringKeywordsUnevaluated_2020_12 final : public Rule { +public: + DropNonStringKeywordsUnevaluated_2020_12() + : Rule{"drop_non_string_keywords_unevaluated_2020_12", + "Keywords that don't apply to strings will never match if the " + "instance is guaranteed to be a string"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "string" && + vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/unevaluated") && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{"unevaluatedItems", + "unevaluatedProperties"}; +}; diff --git a/src/linter/redundant/drop_non_string_keywords_validation_2019_09.h b/src/linter/redundant/drop_non_string_keywords_validation_2019_09.h new file mode 100644 index 0000000..0d69e75 --- /dev/null +++ b/src/linter/redundant/drop_non_string_keywords_validation_2019_09.h @@ -0,0 +1,30 @@ +class DropNonStringKeywordsValidation_2019_09 final : public Rule { +public: + DropNonStringKeywordsValidation_2019_09() + : Rule{"drop_non_string_keywords_validation_2019_09", + "Keywords that don't apply to strings will never match if the " + "instance is guaranteed to be a string"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "string" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "maximum", "exclusiveMinimum", "multipleOf", "exclusiveMaximum", + "minimum", "dependentRequired", "minProperties", "maxProperties", + "required", "minItems", "maxItems", "minContains", + "maxContains", "uniqueItems"}; +}; diff --git a/src/linter/redundant/drop_non_string_keywords_validation_2020_12.h b/src/linter/redundant/drop_non_string_keywords_validation_2020_12.h new file mode 100644 index 0000000..1caa459 --- /dev/null +++ b/src/linter/redundant/drop_non_string_keywords_validation_2020_12.h @@ -0,0 +1,30 @@ +class DropNonStringKeywordsValidation_2020_12 final : public Rule { +public: + DropNonStringKeywordsValidation_2020_12() + : Rule{"drop_non_string_keywords_validation_2020_12", + "Keywords that don't apply to strings will never match if the " + "instance is guaranteed to be a string"} {}; + + [[nodiscard]] auto + condition(const sourcemeta::jsontoolkit::JSON &schema, const std::string &, + const std::set &vocabularies, + const sourcemeta::jsontoolkit::Pointer &) const -> bool override { + return vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/validation") && + schema.is_object() && schema.defines("type") && + schema.at("type").is_string() && + schema.at("type").to_string() == "string" && + schema.defines_any(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + + auto transform(Transformer &transformer) const -> void override { + transformer.erase_keys(this->BLACKLIST.cbegin(), this->BLACKLIST.cend()); + } + +private: + const std::set BLACKLIST{ + "maximum", "exclusiveMinimum", "multipleOf", "exclusiveMaximum", + "minimum", "dependentRequired", "minProperties", "maxProperties", + "required", "minItems", "maxItems", "minContains", + "maxContains", "uniqueItems"}; +}; diff --git a/test/linter/2019_09_test.cc b/test/linter/2019_09_test.cc index 0e47a19..e04ecf1 100644 --- a/test/linter/2019_09_test.cc +++ b/test/linter/2019_09_test.cc @@ -932,3 +932,189 @@ TEST(Lint_2019_09, min_properties_covered_by_required_3) { EXPECT_EQ(document, expected); } + +TEST(Lint_2019_09, drop_non_array_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "array", + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "array", + "minItems": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, drop_non_boolean_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "boolean", + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "boolean" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, drop_non_null_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "null", + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "null" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, drop_non_numeric_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "number", + "multipleOf": 2, + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "number", + "multipleOf": 2 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, drop_non_numeric_keywords_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "integer", + "multipleOf": 2, + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "integer", + "multipleOf": 2 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, drop_non_object_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "object", + "multipleOf": 2, + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "object", + "unevaluatedProperties": false, + "maxProperties": 3 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2019_09, drop_non_string_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "string", + "multipleOf": 2, + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "title": "Test", + "type": "string", + "contentEncoding": "base64", + "format": "uri" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/2020_12_test.cc b/test/linter/2020_12_test.cc index 1023018..b6e3590 100644 --- a/test/linter/2020_12_test.cc +++ b/test/linter/2020_12_test.cc @@ -915,3 +915,189 @@ TEST(Lint_2020_12, min_properties_covered_by_required_3) { EXPECT_EQ(document, expected); } + +TEST(Lint_2020_12, drop_non_array_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "array", + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "array", + "minItems": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, drop_non_boolean_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "boolean", + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "boolean" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, drop_non_null_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "null", + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "null" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, drop_non_numeric_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "number", + "multipleOf": 2, + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "number", + "multipleOf": 2 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, drop_non_numeric_keywords_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "integer", + "multipleOf": 2, + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "integer", + "multipleOf": 2 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, drop_non_object_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "object", + "multipleOf": 2, + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "object", + "unevaluatedProperties": false, + "maxProperties": 3 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_2020_12, drop_non_string_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "string", + "multipleOf": 2, + "unevaluatedProperties": false, + "contentEncoding": "base64", + "maxProperties": 3, + "format": "uri", + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Test", + "type": "string", + "contentEncoding": "base64", + "format": "uri" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/draft0_test.cc b/test/linter/draft0_test.cc index a789294..1ae4124 100644 --- a/test/linter/draft0_test.cc +++ b/test/linter/draft0_test.cc @@ -21,3 +21,167 @@ TEST(Lint_draft0, single_type_array_1) { EXPECT_EQ(document, expected); } + +TEST(Lint_draft0, drop_non_array_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "array", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "array", + "minItems": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft0, drop_non_boolean_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "boolean", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "boolean" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft0, drop_non_null_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "null", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "null" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft0, drop_non_numeric_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "number", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "number" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft0, drop_non_numeric_keywords_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "integer", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "integer" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft0, drop_non_object_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft0, drop_non_string_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "string", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "title": "Test", + "type": "string", + "minLength": 2 + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/draft1_test.cc b/test/linter/draft1_test.cc index f998732..5c00e75 100644 --- a/test/linter/draft1_test.cc +++ b/test/linter/draft1_test.cc @@ -236,3 +236,167 @@ TEST(Lint_draft1, properties_default_1) { EXPECT_EQ(document, expected); } + +TEST(Lint_draft1, drop_non_array_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "array", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "array", + "minItems": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, drop_non_boolean_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "boolean", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "boolean" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, drop_non_null_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "null", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "null" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, drop_non_numeric_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "number", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "number" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, drop_non_numeric_keywords_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "integer", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "integer" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, drop_non_object_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft1, drop_non_string_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "string", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "title": "Test", + "type": "string", + "minLength": 2 + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/draft2_test.cc b/test/linter/draft2_test.cc index bcd989d..75b48e9 100644 --- a/test/linter/draft2_test.cc +++ b/test/linter/draft2_test.cc @@ -236,3 +236,167 @@ TEST(Lint_draft2, properties_default_1) { EXPECT_EQ(document, expected); } + +TEST(Lint_draft2, drop_non_array_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "array", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "array", + "minItems": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, drop_non_boolean_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "boolean", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "boolean" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, drop_non_null_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "null", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "null" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, drop_non_numeric_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "number", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "number" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, drop_non_numeric_keywords_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "integer", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "integer" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, drop_non_object_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft2, drop_non_string_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "string", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "title": "Test", + "type": "string", + "minLength": 2 + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/draft3_test.cc b/test/linter/draft3_test.cc index 5f6676d..a600546 100644 --- a/test/linter/draft3_test.cc +++ b/test/linter/draft3_test.cc @@ -302,3 +302,167 @@ TEST(Lint_draft3, pattern_properties_default_1) { EXPECT_EQ(document, expected); } + +TEST(Lint_draft3, drop_non_array_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "array", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "array", + "minItems": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, drop_non_boolean_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "boolean", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "boolean" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, drop_non_null_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "null", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "null" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, drop_non_numeric_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "number", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "number" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, drop_non_numeric_keywords_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "integer", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "integer" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, drop_non_object_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft3, drop_non_string_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "string", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "title": "Test", + "type": "string", + "minLength": 2 + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/draft4_test.cc b/test/linter/draft4_test.cc index 49021f0..24a0d4a 100644 --- a/test/linter/draft4_test.cc +++ b/test/linter/draft4_test.cc @@ -414,3 +414,167 @@ TEST(Lint_draft4, min_properties_covered_by_required_3) { EXPECT_EQ(document, expected); } + +TEST(Lint_draft4, drop_non_array_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "array", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "array", + "minItems": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, drop_non_boolean_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "boolean", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "boolean" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, drop_non_null_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "null", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "null" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, drop_non_numeric_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "number", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "number" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, drop_non_numeric_keywords_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "integer", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "integer" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, drop_non_object_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft4, drop_non_string_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "string", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Test", + "type": "string", + "minLength": 2 + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/draft6_test.cc b/test/linter/draft6_test.cc index 81adda5..99151b8 100644 --- a/test/linter/draft6_test.cc +++ b/test/linter/draft6_test.cc @@ -565,3 +565,167 @@ TEST(Lint_draft6, min_properties_covered_by_required_3) { EXPECT_EQ(document, expected); } + +TEST(Lint_draft6, drop_non_array_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "array", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "array", + "minItems": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, drop_non_boolean_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "boolean", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "boolean" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, drop_non_null_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "null", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "null" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, drop_non_numeric_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "number", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "number" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, drop_non_numeric_keywords_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "integer", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "integer" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, drop_non_object_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft6, drop_non_string_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "string", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "title": "Test", + "type": "string", + "minLength": 2 + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/linter/draft7_test.cc b/test/linter/draft7_test.cc index d73dfa4..d935041 100644 --- a/test/linter/draft7_test.cc +++ b/test/linter/draft7_test.cc @@ -673,3 +673,167 @@ TEST(Lint_draft7, min_properties_covered_by_required_3) { EXPECT_EQ(document, expected); } + +TEST(Lint_draft7, drop_non_array_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "array", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "array", + "minItems": 1 + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, drop_non_boolean_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "boolean", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "boolean" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, drop_non_null_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "null", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "null" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, drop_non_numeric_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "number", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "number" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, drop_non_numeric_keywords_2) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "integer", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "integer" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, drop_non_object_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "object", + "additionalProperties": false + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(Lint_draft7, drop_non_string_keywords_1) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "string", + "additionalProperties": false, + "minLength": 2, + "minItems": 1 + })JSON"); + + LINT_AND_FIX(document); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Test", + "type": "string", + "minLength": 2 + })JSON"); + + EXPECT_EQ(document, expected); +}