Skip to content

Commit 767c38f

Browse files
committed
feat(alterschema): [linter] create rule to remove additional items when items is an objects
Signed-off-by: karan-palan <karanpalan007@gmail.com>
1 parent 0839c19 commit 767c38f

File tree

6 files changed

+253
-2
lines changed

6 files changed

+253
-2
lines changed

src/extension/alterschema/alterschema.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ static auto every_item_is_boolean(const T &container) -> bool {
5252
#include "linter/content_media_type_without_encoding.h"
5353
#include "linter/content_schema_default.h"
5454
#include "linter/content_schema_without_media_type.h"
55+
#include "linter/dangling_additional_items.h"
5556
#include "linter/dependencies_default.h"
5657
#include "linter/dependencies_property_tautology.h"
5758
#include "linter/dependent_required_default.h"
@@ -112,6 +113,7 @@ auto add(SchemaTransformer &bundle, const AlterSchemaMode mode)
112113
bundle.add<DuplicateEnumValues>();
113114
bundle.add<DuplicateRequiredValues>();
114115
bundle.add<ConstWithType>();
116+
bundle.add<DanglingAdditionalItems>();
115117
bundle.add<ExclusiveMaximumNumberAndMaximum>();
116118
bundle.add<ExclusiveMinimumNumberAndMinimum>();
117119

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
class DanglingAdditionalItems final : public SchemaTransformRule {
2+
public:
3+
DanglingAdditionalItems()
4+
: SchemaTransformRule{
5+
"dangling_additional_items",
6+
"`additionalItems` is ignored when `items` is an object"} {};
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+
schema.is_object() && schema.defines("items") &&
24+
schema.defines("additionalItems") && schema.at("items").is_object();
25+
}
26+
27+
auto transform(JSON &schema) const -> void override {
28+
schema.erase("additionalItems");
29+
}
30+
};

test/alterschema/alterschema_lint_2019_09_test.cc

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,8 +1661,7 @@ TEST(AlterSchema_lint_2019_09, unnecessary_allof_ref_wrapper_5) {
16611661
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
16621662
"$schema": "https://json-schema.org/draft/2019-09/schema",
16631663
"allOf": [
1664-
{
1665-
"type": "integer",
1664+
{ "type": "integer",
16661665
"$ref": "https://example.com"
16671666
}
16681667
]
@@ -1680,3 +1679,47 @@ TEST(AlterSchema_lint_2019_09, unnecessary_allof_ref_wrapper_5) {
16801679

16811680
EXPECT_EQ(document, expected);
16821681
}
1682+
1683+
TEST(AlterSchema_lint_2019_09, dangling_additional_items_1) {
1684+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
1685+
"$schema": "https://json-schema.org/draft/2019-09/schema",
1686+
"items": {
1687+
"type": "number"
1688+
},
1689+
"additionalItems": false
1690+
})JSON");
1691+
1692+
LINT_AND_FIX_FOR_READABILITY(document);
1693+
1694+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
1695+
"$schema": "https://json-schema.org/draft/2019-09/schema",
1696+
"items": {
1697+
"type": "number"
1698+
}
1699+
})JSON");
1700+
1701+
EXPECT_EQ(document, expected);
1702+
}
1703+
1704+
TEST(AlterSchema_lint_2019_09, dangling_additional_items_2) {
1705+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
1706+
"$schema": "https://json-schema.org/draft/2019-09/schema",
1707+
"items": {
1708+
"unevaluatedProperties": false
1709+
},
1710+
"additionalItems": {
1711+
"type": "string"
1712+
}
1713+
})JSON");
1714+
1715+
LINT_AND_FIX_FOR_READABILITY(document);
1716+
1717+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
1718+
"$schema": "https://json-schema.org/draft/2019-09/schema",
1719+
"items": {
1720+
"unevaluatedProperties": false
1721+
}
1722+
})JSON");
1723+
1724+
EXPECT_EQ(document, expected);
1725+
}

test/alterschema/alterschema_lint_draft4_test.cc

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,3 +761,89 @@ TEST(AlterSchema_lint_draft4, unnecessary_allof_ref_wrapper_1) {
761761

762762
EXPECT_EQ(document, expected);
763763
}
764+
765+
TEST(AlterSchema_lint_draft4, dangling_additional_items_1) {
766+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
767+
"$schema": "http://json-schema.org/draft-04/schema#",
768+
"items": {
769+
"type": "number"
770+
},
771+
"additionalItems": false
772+
})JSON");
773+
774+
LINT_AND_FIX_FOR_READABILITY(document);
775+
776+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
777+
"$schema": "http://json-schema.org/draft-04/schema#",
778+
"items": {
779+
"type": "number"
780+
}
781+
})JSON");
782+
783+
EXPECT_EQ(document, expected);
784+
}
785+
786+
TEST(AlterSchema_lint_draft4, dangling_additional_items_2) {
787+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
788+
"$schema": "http://json-schema.org/draft-04/schema#",
789+
"type": "array",
790+
"items": {
791+
"type": "string"
792+
},
793+
"additionalItems": {
794+
"type": "boolean"
795+
}
796+
})JSON");
797+
798+
LINT_AND_FIX_FOR_READABILITY(document);
799+
800+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
801+
"$schema": "http://json-schema.org/draft-04/schema#",
802+
"type": "array",
803+
"items": {
804+
"type": "string"
805+
}
806+
})JSON");
807+
808+
EXPECT_EQ(document, expected);
809+
}
810+
811+
TEST(AlterSchema_lint_draft4, dangling_additional_items_no_change_array_items) {
812+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
813+
"$schema": "http://json-schema.org/draft-04/schema#",
814+
"items": [
815+
{ "type": "string" },
816+
{ "type": "number" }
817+
],
818+
"additionalItems": false
819+
})JSON");
820+
821+
LINT_AND_FIX_FOR_READABILITY(document);
822+
823+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
824+
"$schema": "http://json-schema.org/draft-04/schema#",
825+
"items": [
826+
{ "type": "string" },
827+
{ "type": "number" }
828+
],
829+
"additionalItems": false
830+
})JSON");
831+
832+
EXPECT_EQ(document, expected);
833+
}
834+
835+
TEST(AlterSchema_lint_draft4, dangling_additional_items_no_change_no_items) {
836+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
837+
"$schema": "http://json-schema.org/draft-04/schema#",
838+
"additionalItems": false
839+
})JSON");
840+
841+
LINT_AND_FIX_FOR_READABILITY(document);
842+
843+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
844+
"$schema": "http://json-schema.org/draft-04/schema#",
845+
"additionalItems": false
846+
})JSON");
847+
848+
EXPECT_EQ(document, expected);
849+
}

test/alterschema/alterschema_lint_draft6_test.cc

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,3 +1112,45 @@ TEST(AlterSchema_lint_draft6, unnecessary_allof_ref_wrapper_1) {
11121112

11131113
EXPECT_EQ(document, expected);
11141114
}
1115+
1116+
TEST(AlterSchema_lint_draft6, dangling_additional_items_1) {
1117+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
1118+
"$schema": "http://json-schema.org/draft-06/schema#",
1119+
"items": {
1120+
"type": "number"
1121+
},
1122+
"additionalItems": false
1123+
})JSON");
1124+
1125+
LINT_AND_FIX_FOR_READABILITY(document);
1126+
1127+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
1128+
"$schema": "http://json-schema.org/draft-06/schema#",
1129+
"items": {
1130+
"type": "number"
1131+
}
1132+
})JSON");
1133+
1134+
EXPECT_EQ(document, expected);
1135+
}
1136+
1137+
TEST(AlterSchema_lint_draft6, dangling_additional_items_2) {
1138+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
1139+
"$schema": "http://json-schema.org/draft-06/schema#",
1140+
"items": {
1141+
"const": "foo"
1142+
},
1143+
"additionalItems": true
1144+
})JSON");
1145+
1146+
LINT_AND_FIX_FOR_READABILITY(document);
1147+
1148+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
1149+
"$schema": "http://json-schema.org/draft-06/schema#",
1150+
"items": {
1151+
"const": "foo"
1152+
}
1153+
})JSON");
1154+
1155+
EXPECT_EQ(document, expected);
1156+
}

test/alterschema/alterschema_lint_draft7_test.cc

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,3 +1208,51 @@ TEST(AlterSchema_lint_draft7, unnecessary_allof_ref_wrapper_1) {
12081208

12091209
EXPECT_EQ(document, expected);
12101210
}
1211+
1212+
TEST(AlterSchema_lint_draft7, dangling_additional_items_1) {
1213+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
1214+
"$schema": "http://json-schema.org/draft-07/schema#",
1215+
"items": {
1216+
"type": "number"
1217+
},
1218+
"additionalItems": false
1219+
})JSON");
1220+
1221+
LINT_AND_FIX_FOR_READABILITY(document);
1222+
1223+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
1224+
"$schema": "http://json-schema.org/draft-07/schema#",
1225+
"items": {
1226+
"type": "number"
1227+
}
1228+
})JSON");
1229+
1230+
EXPECT_EQ(document, expected);
1231+
}
1232+
1233+
TEST(AlterSchema_lint_draft7, dangling_additional_items_2) {
1234+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
1235+
"$schema": "http://json-schema.org/draft-07/schema#",
1236+
"type": "array",
1237+
"items": {
1238+
"if": { "type": "string" },
1239+
"then": { "minLength": 1 }
1240+
},
1241+
"additionalItems": {
1242+
"type": "number"
1243+
}
1244+
})JSON");
1245+
1246+
LINT_AND_FIX_FOR_READABILITY(document);
1247+
1248+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
1249+
"$schema": "http://json-schema.org/draft-07/schema#",
1250+
"type": "array",
1251+
"items": {
1252+
"if": { "type": "string" },
1253+
"then": { "minLength": 1 }
1254+
}
1255+
})JSON");
1256+
1257+
EXPECT_EQ(document, expected);
1258+
}

0 commit comments

Comments
 (0)