Skip to content

Commit 977dc10

Browse files
authored
Linter: create rule to remove additional items when items is an object (#1805)
Signed-off-by: karan-palan <karanpalan007@gmail.com>
1 parent b644ad6 commit 977dc10

8 files changed

+581
-0
lines changed

src/extension/alterschema/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ sourcemeta_library(NAMESPACE sourcemeta PROJECT core NAME alterschema
4848
linter/unsatisfiable_min_properties.h
4949
linter/content_media_type_without_encoding.h
5050
linter/content_schema_without_media_type.h
51+
linter/additional_items_with_schema_items.h
5152
linter/non_applicable_type_specific_keywords.h
5253
linter/unnecessary_allof_wrapper_modern.h
5354
linter/unnecessary_allof_wrapper_draft.h

src/extension/alterschema/alterschema.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ contains_any(const Vocabularies &container,
3535
#include "canonicalizer/type_union_implicit.h"
3636

3737
// Linter
38+
#include "linter/additional_items_with_schema_items.h"
3839
#include "linter/additional_properties_default.h"
3940
#include "linter/const_with_type.h"
4041
#include "linter/content_media_type_without_encoding.h"
@@ -107,6 +108,7 @@ auto add(SchemaTransformer &bundle, const AlterSchemaMode mode)
107108
bundle.add<DuplicateEnumValues>();
108109
bundle.add<DuplicateRequiredValues>();
109110
bundle.add<ConstWithType>();
111+
bundle.add<AdditionalItemsWithSchemaItems>();
110112
bundle.add<ExclusiveMaximumNumberAndMaximum>();
111113
bundle.add<ExclusiveMinimumNumberAndMinimum>();
112114

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
class AdditionalItemsWithSchemaItems final : public SchemaTransformRule {
2+
public:
3+
AdditionalItemsWithSchemaItems()
4+
: SchemaTransformRule{"additional_items_with_schema_items",
5+
"The `additionalItems` keyword is ignored when the "
6+
"`items` keyword is set to a schema"} {};
7+
8+
[[nodiscard]] auto
9+
condition(const sourcemeta::core::JSON &schema,
10+
const sourcemeta::core::JSON &,
11+
const sourcemeta::core::Vocabularies &vocabularies,
12+
const sourcemeta::core::SchemaFrame &,
13+
const sourcemeta::core::SchemaFrame::Location &,
14+
const sourcemeta::core::SchemaWalker &,
15+
const sourcemeta::core::SchemaResolver &) const
16+
-> sourcemeta::core::SchemaTransformRule::Result override {
17+
return contains_any(
18+
vocabularies,
19+
{"https://json-schema.org/draft/2019-09/vocab/applicator",
20+
"http://json-schema.org/draft-07/schema#",
21+
"http://json-schema.org/draft-06/schema#",
22+
"http://json-schema.org/draft-04/schema#",
23+
"http://json-schema.org/draft-03/schema#"}) &&
24+
schema.is_object() && schema.defines("items") &&
25+
schema.defines("additionalItems") && is_schema(schema.at("items"));
26+
}
27+
28+
auto transform(JSON &schema) const -> void override {
29+
schema.erase("additionalItems");
30+
}
31+
};

test/alterschema/alterschema_lint_2019_09_test.cc

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1879,3 +1879,108 @@ TEST(AlterSchema_lint_2019_09, unnecessary_allof_wrapper_properties_4) {
18791879

18801880
EXPECT_EQ(document, expected);
18811881
}
1882+
1883+
TEST(AlterSchema_lint_2019_09, additional_items_with_schema_items_1) {
1884+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
1885+
"$schema": "https://json-schema.org/draft/2019-09/schema",
1886+
"items": {
1887+
"type": "number"
1888+
},
1889+
"additionalItems": false
1890+
})JSON");
1891+
1892+
LINT_AND_FIX_FOR_READABILITY(document);
1893+
1894+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
1895+
"$schema": "https://json-schema.org/draft/2019-09/schema",
1896+
"items": {
1897+
"type": "number"
1898+
}
1899+
})JSON");
1900+
1901+
EXPECT_EQ(document, expected);
1902+
}
1903+
1904+
TEST(AlterSchema_lint_2019_09, additional_items_with_schema_items_2) {
1905+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
1906+
"$schema": "https://json-schema.org/draft/2019-09/schema",
1907+
"items": {
1908+
"unevaluatedProperties": false
1909+
},
1910+
"additionalItems": {
1911+
"type": "string"
1912+
}
1913+
})JSON");
1914+
1915+
LINT_AND_FIX_FOR_READABILITY(document);
1916+
1917+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
1918+
"$schema": "https://json-schema.org/draft/2019-09/schema",
1919+
"items": {
1920+
"unevaluatedProperties": false
1921+
}
1922+
})JSON");
1923+
1924+
EXPECT_EQ(document, expected);
1925+
}
1926+
1927+
TEST(AlterSchema_lint_2019_09,
1928+
additional_items_with_schema_items_boolean_items_true) {
1929+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
1930+
"$schema": "https://json-schema.org/draft/2019-09/schema",
1931+
"items": true,
1932+
"additionalItems": false
1933+
})JSON");
1934+
1935+
LINT_AND_FIX_FOR_READABILITY(document);
1936+
1937+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
1938+
"$schema": "https://json-schema.org/draft/2019-09/schema"
1939+
})JSON");
1940+
1941+
EXPECT_EQ(document, expected);
1942+
}
1943+
1944+
TEST(AlterSchema_lint_2019_09,
1945+
additional_items_with_schema_items_boolean_items_false) {
1946+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
1947+
"$schema": "https://json-schema.org/draft/2019-09/schema",
1948+
"items": false,
1949+
"additionalItems": {
1950+
"type": "string"
1951+
}
1952+
})JSON");
1953+
1954+
LINT_AND_FIX_FOR_READABILITY(document);
1955+
1956+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
1957+
"$schema": "https://json-schema.org/draft/2019-09/schema",
1958+
"items": false
1959+
})JSON");
1960+
1961+
EXPECT_EQ(document, expected);
1962+
}
1963+
1964+
TEST(AlterSchema_lint_2019_09, additional_items_with_schema_items_array_items) {
1965+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
1966+
"$schema": "https://json-schema.org/draft/2019-09/schema",
1967+
"items": [
1968+
{ "type": "string" },
1969+
{ "type": "number" }
1970+
],
1971+
"additionalItems": false
1972+
})JSON");
1973+
1974+
LINT_AND_FIX_FOR_READABILITY(document);
1975+
1976+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
1977+
"$schema": "https://json-schema.org/draft/2019-09/schema",
1978+
"items": [
1979+
{ "type": "string" },
1980+
{ "type": "number" }
1981+
],
1982+
"additionalItems": false
1983+
})JSON");
1984+
1985+
EXPECT_EQ(document, expected);
1986+
}

test/alterschema/alterschema_lint_draft3_test.cc

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,3 +595,108 @@ TEST(AlterSchema_lint_draft3, draft_official_dialect_without_empty_fragment_1) {
595595

596596
EXPECT_EQ(document, expected);
597597
}
598+
599+
TEST(AlterSchema_lint_draft3, additional_items_with_schema_items_1) {
600+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
601+
"$schema": "http://json-schema.org/draft-03/schema#",
602+
"items": {
603+
"type": "number"
604+
},
605+
"additionalItems": false
606+
})JSON");
607+
608+
LINT_AND_FIX_FOR_READABILITY(document);
609+
610+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
611+
"$schema": "http://json-schema.org/draft-03/schema#",
612+
"items": {
613+
"type": "number"
614+
}
615+
})JSON");
616+
617+
EXPECT_EQ(document, expected);
618+
}
619+
620+
TEST(AlterSchema_lint_draft3, additional_items_with_schema_items_2) {
621+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
622+
"$schema": "http://json-schema.org/draft-03/schema#",
623+
"items": {
624+
"type": "string"
625+
},
626+
"additionalItems": {
627+
"type": "boolean"
628+
}
629+
})JSON");
630+
631+
LINT_AND_FIX_FOR_READABILITY(document);
632+
633+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
634+
"$schema": "http://json-schema.org/draft-03/schema#",
635+
"items": {
636+
"type": "string"
637+
}
638+
})JSON");
639+
640+
EXPECT_EQ(document, expected);
641+
}
642+
643+
TEST(AlterSchema_lint_draft3,
644+
additional_items_with_schema_items_boolean_items_true) {
645+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
646+
"$schema": "http://json-schema.org/draft-03/schema#",
647+
"items": true,
648+
"additionalItems": false
649+
})JSON");
650+
651+
LINT_AND_FIX_FOR_READABILITY(document);
652+
653+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
654+
"$schema": "http://json-schema.org/draft-03/schema#"
655+
})JSON");
656+
657+
EXPECT_EQ(document, expected);
658+
}
659+
660+
TEST(AlterSchema_lint_draft3,
661+
additional_items_with_schema_items_boolean_items_false) {
662+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
663+
"$schema": "http://json-schema.org/draft-03/schema#",
664+
"items": false,
665+
"additionalItems": {
666+
"type": "string"
667+
}
668+
})JSON");
669+
670+
LINT_AND_FIX_FOR_READABILITY(document);
671+
672+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
673+
"$schema": "http://json-schema.org/draft-03/schema#",
674+
"items": false
675+
})JSON");
676+
677+
EXPECT_EQ(document, expected);
678+
}
679+
680+
TEST(AlterSchema_lint_draft3, additional_items_with_schema_items_array_items) {
681+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
682+
"$schema": "http://json-schema.org/draft-03/schema#",
683+
"items": [
684+
{ "type": "string" },
685+
{ "type": "number" }
686+
],
687+
"additionalItems": false
688+
})JSON");
689+
690+
LINT_AND_FIX_FOR_READABILITY(document);
691+
692+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
693+
"$schema": "http://json-schema.org/draft-03/schema#",
694+
"items": [
695+
{ "type": "string" },
696+
{ "type": "number" }
697+
],
698+
"additionalItems": false
699+
})JSON");
700+
701+
EXPECT_EQ(document, expected);
702+
}

0 commit comments

Comments
 (0)