diff --git a/src/extension/alterschema/CMakeLists.txt b/src/extension/alterschema/CMakeLists.txt index 74d69b07e..86b093911 100644 --- a/src/extension/alterschema/CMakeLists.txt +++ b/src/extension/alterschema/CMakeLists.txt @@ -29,6 +29,7 @@ sourcemeta_library(NAMESPACE sourcemeta PROJECT core NAME alterschema linter/dependent_required_tautology.h linter/equal_numeric_bounds_to_enum.h linter/maximum_real_for_integer.h + linter/draft_official_dialect_without_empty_fragment.h linter/minimum_real_for_integer.h linter/single_type_array.h linter/enum_to_const.h diff --git a/src/extension/alterschema/alterschema.cc b/src/extension/alterschema/alterschema.cc index 8869201c6..9c7833ca5 100644 --- a/src/extension/alterschema/alterschema.cc +++ b/src/extension/alterschema/alterschema.cc @@ -44,6 +44,7 @@ contains_any(const Vocabularies &container, #include "linter/dependencies_property_tautology.h" #include "linter/dependent_required_default.h" #include "linter/dependent_required_tautology.h" +#include "linter/draft_official_dialect_without_empty_fragment.h" #include "linter/duplicate_allof_branches.h" #include "linter/duplicate_anyof_branches.h" #include "linter/duplicate_enum_values.h" @@ -84,6 +85,7 @@ auto add(SchemaTransformer &bundle, const AlterSchemaMode mode) // Common rules that apply to all modes bundle.add(); bundle.add(); + bundle.add(); bundle.add(); bundle.add(); bundle.add(); diff --git a/src/extension/alterschema/linter/draft_official_dialect_without_empty_fragment.h b/src/extension/alterschema/linter/draft_official_dialect_without_empty_fragment.h new file mode 100644 index 000000000..8bf46af7a --- /dev/null +++ b/src/extension/alterschema/linter/draft_official_dialect_without_empty_fragment.h @@ -0,0 +1,44 @@ +class DraftOfficialDialectWithoutEmptyFragment final + : public SchemaTransformRule { +public: + DraftOfficialDialectWithoutEmptyFragment() + : SchemaTransformRule{"draft_official_dialect_without_empty_fragment", + "The official dialect URI of Draft 7 and older " + "versions must contain the empty fragment"} {}; + + [[nodiscard]] auto condition(const sourcemeta::core::JSON &schema, + const sourcemeta::core::JSON &, + const sourcemeta::core::Vocabularies &, + const sourcemeta::core::SchemaFrame &, + const sourcemeta::core::SchemaFrame::Location &, + const sourcemeta::core::SchemaWalker &, + const sourcemeta::core::SchemaResolver &) const + -> sourcemeta::core::SchemaTransformRule::Result override { + if (!schema.is_object() || !schema.defines("$schema") || + !schema.at("$schema").is_string()) { + return false; + } + + const auto &schema_value = schema.at("$schema").to_string(); + return (schema_value == "http://json-schema.org/draft-07/schema" || + schema_value == "http://json-schema.org/draft-07/hyper-schema" || + schema_value == "http://json-schema.org/draft-06/schema" || + schema_value == "http://json-schema.org/draft-06/hyper-schema" || + schema_value == "http://json-schema.org/draft-04/schema" || + schema_value == "http://json-schema.org/draft-04/hyper-schema" || + schema_value == "http://json-schema.org/draft-03/schema" || + schema_value == "http://json-schema.org/draft-03/hyper-schema" || + schema_value == "http://json-schema.org/draft-02/schema" || + schema_value == "http://json-schema.org/draft-02/hyper-schema" || + schema_value == "http://json-schema.org/draft-01/schema" || + schema_value == "http://json-schema.org/draft-01/hyper-schema" || + schema_value == "http://json-schema.org/draft-00/schema" || + schema_value == "http://json-schema.org/draft-00/hyper-schema"); + } + + auto transform(sourcemeta::core::JSON &schema) const -> void override { + auto schema_value = schema.at("$schema").to_string(); + schema_value += "#"; + schema.at("$schema").into(sourcemeta::core::JSON{std::move(schema_value)}); + } +}; diff --git a/test/alterschema/alterschema_lint_draft0_test.cc b/test/alterschema/alterschema_lint_draft0_test.cc index 623a634ad..956eac3db 100644 --- a/test/alterschema/alterschema_lint_draft0_test.cc +++ b/test/alterschema/alterschema_lint_draft0_test.cc @@ -192,3 +192,19 @@ TEST(AlterSchema_lint_draft0, boolean_true_1) { EXPECT_EQ(document, expected); } + +TEST(AlterSchema_lint_draft0, draft_official_dialect_without_empty_fragment_1) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema", + "type": "string" + })JSON"); + + LINT_AND_FIX_FOR_READABILITY(document); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-00/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/alterschema/alterschema_lint_draft1_test.cc b/test/alterschema/alterschema_lint_draft1_test.cc index 1f20ffdc4..350207549 100644 --- a/test/alterschema/alterschema_lint_draft1_test.cc +++ b/test/alterschema/alterschema_lint_draft1_test.cc @@ -522,3 +522,19 @@ TEST(AlterSchema_lint_draft1, equal_numeric_bounds_to_enum_2) { EXPECT_EQ(document, expected); } + +TEST(AlterSchema_lint_draft1, draft_official_dialect_without_empty_fragment_1) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema", + "type": "string" + })JSON"); + + LINT_AND_FIX_FOR_READABILITY(document); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-01/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/alterschema/alterschema_lint_draft2_test.cc b/test/alterschema/alterschema_lint_draft2_test.cc index 11ad031bc..955815d09 100644 --- a/test/alterschema/alterschema_lint_draft2_test.cc +++ b/test/alterschema/alterschema_lint_draft2_test.cc @@ -522,3 +522,19 @@ TEST(AlterSchema_lint_draft2, equal_numeric_bounds_to_enum_2) { EXPECT_EQ(document, expected); } + +TEST(AlterSchema_lint_draft2, draft_official_dialect_without_empty_fragment_1) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema", + "type": "string" + })JSON"); + + LINT_AND_FIX_FOR_READABILITY(document); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/alterschema/alterschema_lint_draft3_test.cc b/test/alterschema/alterschema_lint_draft3_test.cc index 210d322da..11fca2505 100644 --- a/test/alterschema/alterschema_lint_draft3_test.cc +++ b/test/alterschema/alterschema_lint_draft3_test.cc @@ -579,3 +579,19 @@ TEST(AlterSchema_lint_draft3, equal_numeric_bounds_to_enum_2) { EXPECT_EQ(document, expected); } + +TEST(AlterSchema_lint_draft3, draft_official_dialect_without_empty_fragment_1) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema", + "type": "string" + })JSON"); + + LINT_AND_FIX_FOR_READABILITY(document); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/alterschema/alterschema_lint_draft4_test.cc b/test/alterschema/alterschema_lint_draft4_test.cc index 121cd4d30..0f92f2fdc 100644 --- a/test/alterschema/alterschema_lint_draft4_test.cc +++ b/test/alterschema/alterschema_lint_draft4_test.cc @@ -921,3 +921,19 @@ TEST(AlterSchema_lint_draft4, unnecessary_allof_wrapper_properties_1) { EXPECT_EQ(document, expected); } + +TEST(AlterSchema_lint_draft4, draft_official_dialect_without_empty_fragment_1) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema", + "type": "string" + })JSON"); + + LINT_AND_FIX_FOR_READABILITY(document); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/alterschema/alterschema_lint_draft6_test.cc b/test/alterschema/alterschema_lint_draft6_test.cc index 0a85afd5d..0a1413822 100644 --- a/test/alterschema/alterschema_lint_draft6_test.cc +++ b/test/alterschema/alterschema_lint_draft6_test.cc @@ -1183,3 +1183,19 @@ TEST(AlterSchema_lint_draft6, unnecessary_allof_wrapper_properties_1) { EXPECT_EQ(document, expected); } + +TEST(AlterSchema_lint_draft6, draft_official_dialect_without_empty_fragment_1) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema", + "type": "string" + })JSON"); + + LINT_AND_FIX_FOR_READABILITY(document); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} diff --git a/test/alterschema/alterschema_lint_draft7_test.cc b/test/alterschema/alterschema_lint_draft7_test.cc index c4912b494..cabdb9ea4 100644 --- a/test/alterschema/alterschema_lint_draft7_test.cc +++ b/test/alterschema/alterschema_lint_draft7_test.cc @@ -1283,3 +1283,53 @@ TEST(AlterSchema_lint_draft7, unnecessary_allof_wrapper_properties_1) { EXPECT_EQ(document, expected); } + +TEST(AlterSchema_lint_draft7, draft_official_dialect_without_empty_fragment_1) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema", + "type": "string" + })JSON"); + + LINT_AND_FIX_FOR_READABILITY(document); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(AlterSchema_lint_draft7, + draft_official_dialect_without_empty_fragment_hyper) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-07/hyper-schema", + "type": "string" + })JSON"); + + LINT_AND_FIX_FOR_READABILITY(document); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-07/hyper-schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(AlterSchema_lint_draft7, + draft_official_dialect_without_empty_fragment_already_has_hash) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "string" + })JSON"); + + LINT_AND_FIX_FOR_READABILITY(document); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "string" + })JSON"); + + EXPECT_EQ(document, expected); +}