Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/extension/alterschema/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ sourcemeta_library(NAMESPACE sourcemeta PROJECT core NAME alterschema
linter/property_names_type_default.h
linter/property_names_default.h
linter/draft_ref_siblings.h
linter/definitions_to_defs.h)
linter/definitions_to_defs.h
linter/then_false.h)

if(SOURCEMETA_CORE_INSTALL)
sourcemeta_library_install(NAMESPACE sourcemeta PROJECT core NAME alterschema)
Expand Down
2 changes: 2 additions & 0 deletions src/extension/alterschema/alterschema.cc
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ contains_any(const Vocabularies &container,
#include "linter/property_names_type_default.h"
#include "linter/single_type_array.h"
#include "linter/then_empty.h"
#include "linter/then_false.h"
#include "linter/then_without_if.h"
#include "linter/unevaluated_items_default.h"
#include "linter/unevaluated_properties_default.h"
Expand Down Expand Up @@ -107,6 +108,7 @@ auto add(SchemaTransformer &bundle, const AlterSchemaMode mode)
bundle.add<MinContainsWithoutContains>();
bundle.add<ThenEmpty>();
bundle.add<ElseEmpty>();
bundle.add<ThenFalse>();
bundle.add<ThenWithoutIf>();
bundle.add<DependenciesPropertyTautology>();
bundle.add<DependentRequiredTautology>();
Expand Down
52 changes: 52 additions & 0 deletions src/extension/alterschema/linter/then_false.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
class ThenFalse final : public SchemaTransformRule {
public:
ThenFalse()
: SchemaTransformRule{
"then_false",
"`if: S, then: false` is logically equivalent to `not: S`"} {};

[[nodiscard]] auto
condition(const JSON &schema, const JSON &, const Vocabularies &vocabularies,
const SchemaFrame &, const SchemaFrame::Location &,
const SchemaWalker &, const SchemaResolver &) const
-> SchemaTransformRule::Result override {
if (!contains_any(vocabularies,
{"https://json-schema.org/draft/2020-12/vocab/applicator",
"https://json-schema.org/draft/2019-09/vocab/applicator",
"http://json-schema.org/draft-07/schema#"})) {
return false;
}

if (!schema.is_object() || !schema.defines("if") ||
!schema.defines("then") || !is_schema(schema.at("then")) ||
!schema.at("then").is_boolean() || schema.at("then").to_boolean() ||
!is_schema(schema.at("if"))) {
return false;
}

if (schema.defines("else") &&
(!schema.at("else").is_boolean() || !schema.at("else").to_boolean())) {
return false;
}

if (schema.at("if").is_object()) {
for (const auto &entry : schema.at("if").as_object()) {
if (schema.defines(entry.first)) {
return false;
}
}
}

return true;
}

auto transform(JSON &schema) const -> void override {
auto if_schema = schema.at("if");
schema.erase("if");
schema.erase("then");
if (schema.defines("else")) {
schema.erase("else");
}
schema.assign("not", std::move(if_schema));
}
};
176 changes: 176 additions & 0 deletions test/alterschema/alterschema_lint_2019_09_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2636,3 +2636,179 @@ TEST(AlterSchema_lint_2019_09, non_applicable_type_specific_keywords_3) {

EXPECT_EQ(document, expected);
}

TEST(AlterSchema_lint_2019_09, then_false_1) {
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"if": {
"properties": {
"flag": {
"const": true
}
}
},
"then": false
})JSON");

LINT_AND_FIX_FOR_READABILITY(document);

const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"not": {
"properties": {
"flag": {
"const": true
}
}
}
})JSON");

EXPECT_EQ(document, expected);
}

TEST(AlterSchema_lint_2019_09, then_false_2) {
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"if": {
"properties": {
"flag": {
"const": true
}
}
},
"then": false,
"else": true
})JSON");

LINT_AND_FIX_FOR_READABILITY(document);

const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"not": {
"properties": {
"flag": {
"const": true
}
}
}
})JSON");

EXPECT_EQ(document, expected);
}

TEST(AlterSchema_lint_2019_09, then_false_3) {
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"if": true,
"then": false
})JSON");

LINT_AND_FIX_FOR_READABILITY(document);

const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"not": true
})JSON");

EXPECT_EQ(document, expected);
}

TEST(AlterSchema_lint_2019_09, then_false_4) {
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"if": false,
"then": false
})JSON");

LINT_AND_FIX_FOR_READABILITY(document);

const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"not": false
})JSON");

EXPECT_EQ(document, expected);
}

TEST(AlterSchema_lint_2019_09, then_false_5) {
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"type": "object",
"properties": {
"name": { "type": "string" }
},
"if": {
"properties": {
"name": { "type": "number" }
}
},
"then": false
})JSON");

LINT_AND_FIX_FOR_READABILITY(document);

const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"type": "object",
"properties": {
"name": { "type": "string" }
},
"if": {
"properties": {
"name": { "type": "number" }
}
},
"then": false
})JSON");

EXPECT_EQ(document, expected);
}

TEST(AlterSchema_lint_2019_09, then_false_6) {
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"if": {
"properties": {
"flag": { "const": true }
}
},
"then": false
})JSON");

LINT_AND_FIX_FOR_READABILITY(document);

const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"not": {
"properties": {
"flag": { "const": true }
}
}
})JSON");

EXPECT_EQ(document, expected);
}

TEST(AlterSchema_lint_2019_09, then_false_7) {
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"if": {
"type": "object"
},
"then": false,
"else": false
})JSON");

LINT_AND_FIX_FOR_READABILITY(document);

const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
"$schema": "https://json-schema.org/draft/2019-09/schema",
"if": {
"type": "object"
},
"then": false,
"else": false
})JSON");

EXPECT_EQ(document, expected);
}
Loading
Loading