Skip to content

Commit bc3a4e6

Browse files
authored
Linter: add rule to remove empty then else (#1819)
Signed-off-by: karan-palan <[email protected]>
1 parent 5ddb95c commit bc3a4e6

File tree

7 files changed

+478
-0
lines changed

7 files changed

+478
-0
lines changed

src/extension/alterschema/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ sourcemeta_library(NAMESPACE sourcemeta PROJECT core NAME alterschema
6060
linter/max_contains_without_contains.h
6161
linter/min_contains_without_contains.h
6262
linter/modern_official_dialect_with_empty_fragment.h
63+
linter/then_empty.h
64+
linter/else_empty.h
6365
linter/then_without_if.h)
6466

6567
if(SOURCEMETA_CORE_INSTALL)

src/extension/alterschema/alterschema.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ contains_any(const Vocabularies &container,
5050
#include "linter/duplicate_anyof_branches.h"
5151
#include "linter/duplicate_enum_values.h"
5252
#include "linter/duplicate_required_values.h"
53+
#include "linter/else_empty.h"
5354
#include "linter/else_without_if.h"
5455
#include "linter/enum_to_const.h"
5556
#include "linter/enum_with_type.h"
@@ -69,6 +70,7 @@ contains_any(const Vocabularies &container,
6970
#include "linter/pattern_properties_default.h"
7071
#include "linter/properties_default.h"
7172
#include "linter/single_type_array.h"
73+
#include "linter/then_empty.h"
7274
#include "linter/then_without_if.h"
7375
#include "linter/unevaluated_items_default.h"
7476
#include "linter/unevaluated_properties_default.h"
@@ -98,6 +100,8 @@ auto add(SchemaTransformer &bundle, const AlterSchemaMode mode)
98100
bundle.add<IfWithoutThenElse>();
99101
bundle.add<MaxContainsWithoutContains>();
100102
bundle.add<MinContainsWithoutContains>();
103+
bundle.add<ThenEmpty>();
104+
bundle.add<ElseEmpty>();
101105
bundle.add<ThenWithoutIf>();
102106
bundle.add<DependenciesPropertyTautology>();
103107
bundle.add<DependentRequiredTautology>();
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
class ElseEmpty final : public SchemaTransformRule {
2+
public:
3+
ElseEmpty()
4+
: SchemaTransformRule{"else_empty",
5+
"Setting the `else` keyword to the empty schema "
6+
"does not add any further constraint"} {};
7+
8+
[[nodiscard]] auto
9+
condition(const JSON &schema, const JSON &, const Vocabularies &vocabularies,
10+
const SchemaFrame &, const SchemaFrame::Location &,
11+
const SchemaWalker &, const SchemaResolver &) const
12+
-> SchemaTransformRule::Result override {
13+
return contains_any(
14+
vocabularies,
15+
{"https://json-schema.org/draft/2020-12/vocab/applicator",
16+
"https://json-schema.org/draft/2019-09/vocab/applicator",
17+
"http://json-schema.org/draft-07/schema#"}) &&
18+
schema.is_object() && schema.defines("else") &&
19+
is_schema(schema.at("else")) && is_empty_schema(schema.at("else")) &&
20+
(schema.at("else").is_object() ||
21+
(!schema.defines("if") ||
22+
!(schema.at("if").is_boolean() && schema.at("if").to_boolean())));
23+
}
24+
25+
auto transform(JSON &schema) const -> void override { schema.erase("else"); }
26+
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
class ThenEmpty final : public SchemaTransformRule {
2+
public:
3+
ThenEmpty()
4+
: SchemaTransformRule{"then_empty",
5+
"Setting the `then` keyword to the empty schema "
6+
"does not add any further constraint"} {};
7+
8+
[[nodiscard]] auto
9+
condition(const JSON &schema, const JSON &, const Vocabularies &vocabularies,
10+
const SchemaFrame &, const SchemaFrame::Location &,
11+
const SchemaWalker &, const SchemaResolver &) const
12+
-> SchemaTransformRule::Result override {
13+
return contains_any(
14+
vocabularies,
15+
{"https://json-schema.org/draft/2020-12/vocab/applicator",
16+
"https://json-schema.org/draft/2019-09/vocab/applicator",
17+
"http://json-schema.org/draft-07/schema#"}) &&
18+
schema.is_object() && schema.defines("then") &&
19+
is_schema(schema.at("then")) && is_empty_schema(schema.at("then")) &&
20+
(schema.at("then").is_object() ||
21+
(!schema.defines("if") ||
22+
!(schema.at("if").is_boolean() && schema.at("if").to_boolean())));
23+
}
24+
25+
auto transform(JSON &schema) const -> void override { schema.erase("then"); }
26+
};

test/alterschema/alterschema_lint_2019_09_test.cc

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2032,3 +2032,105 @@ TEST(AlterSchema_lint_2019_09, modern_official_dialect_with_empty_fragment_3) {
20322032

20332033
EXPECT_EQ(document, expected);
20342034
}
2035+
2036+
TEST(AlterSchema_lint_2019_09, then_empty_1) {
2037+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
2038+
"$schema": "https://json-schema.org/draft/2019-09/schema",
2039+
"if": {
2040+
"properties": {
2041+
"flag": {
2042+
"const": true
2043+
}
2044+
}
2045+
},
2046+
"then": {}
2047+
})JSON");
2048+
2049+
LINT_AND_FIX_FOR_READABILITY(document);
2050+
2051+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
2052+
"$schema": "https://json-schema.org/draft/2019-09/schema"
2053+
})JSON");
2054+
2055+
EXPECT_EQ(document, expected);
2056+
}
2057+
2058+
TEST(AlterSchema_lint_2019_09, else_empty_1) {
2059+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
2060+
"$schema": "https://json-schema.org/draft/2019-09/schema",
2061+
"if": {
2062+
"properties": {
2063+
"flag": {
2064+
"const": true
2065+
}
2066+
}
2067+
},
2068+
"else": {}
2069+
})JSON");
2070+
2071+
LINT_AND_FIX_FOR_READABILITY(document);
2072+
2073+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
2074+
"$schema": "https://json-schema.org/draft/2019-09/schema"
2075+
})JSON");
2076+
2077+
EXPECT_EQ(document, expected);
2078+
}
2079+
2080+
TEST(AlterSchema_lint_2019_09, then_empty_2) {
2081+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
2082+
"$schema": "https://json-schema.org/draft/2019-09/schema",
2083+
"if": {
2084+
"properties": {
2085+
"flag": {
2086+
"const": true
2087+
}
2088+
}
2089+
},
2090+
"then": {},
2091+
"else": {}
2092+
})JSON");
2093+
2094+
LINT_AND_FIX_FOR_READABILITY(document);
2095+
2096+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
2097+
"$schema": "https://json-schema.org/draft/2019-09/schema"
2098+
})JSON");
2099+
2100+
EXPECT_EQ(document, expected);
2101+
}
2102+
2103+
TEST(AlterSchema_lint_2019_09, else_empty_2) {
2104+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
2105+
"$schema": "https://json-schema.org/draft/2019-09/schema",
2106+
"if": {
2107+
"properties": {
2108+
"flag": {
2109+
"const": true
2110+
}
2111+
}
2112+
},
2113+
"then": {
2114+
"type": "string"
2115+
},
2116+
"else": {}
2117+
})JSON");
2118+
2119+
LINT_AND_FIX_FOR_READABILITY(document);
2120+
2121+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
2122+
"$schema": "https://json-schema.org/draft/2019-09/schema",
2123+
"if": {
2124+
"properties": {
2125+
"flag": {
2126+
"const": true
2127+
}
2128+
}
2129+
},
2130+
"then": {
2131+
"type": "string"
2132+
}
2133+
})JSON");
2134+
2135+
EXPECT_EQ(document, expected);
2136+
}

test/alterschema/alterschema_lint_2020_12_test.cc

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,3 +2207,164 @@ TEST(AlterSchema_lint_2020_12, modern_official_dialect_with_empty_fragment_3) {
22072207

22082208
EXPECT_EQ(document, expected);
22092209
}
2210+
2211+
TEST(AlterSchema_lint_2020_12, then_empty_1) {
2212+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
2213+
"$schema": "https://json-schema.org/draft/2020-12/schema",
2214+
"if": {
2215+
"properties": {
2216+
"flag": {
2217+
"const": true
2218+
}
2219+
}
2220+
},
2221+
"then": {}
2222+
})JSON");
2223+
2224+
LINT_AND_FIX_FOR_READABILITY(document);
2225+
2226+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
2227+
"$schema": "https://json-schema.org/draft/2020-12/schema"
2228+
})JSON");
2229+
2230+
EXPECT_EQ(document, expected);
2231+
}
2232+
2233+
TEST(AlterSchema_lint_2020_12, else_empty_1) {
2234+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
2235+
"$schema": "https://json-schema.org/draft/2020-12/schema",
2236+
"if": {
2237+
"properties": {
2238+
"flag": {
2239+
"const": true
2240+
}
2241+
}
2242+
},
2243+
"else": {}
2244+
})JSON");
2245+
2246+
LINT_AND_FIX_FOR_READABILITY(document);
2247+
2248+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
2249+
"$schema": "https://json-schema.org/draft/2020-12/schema"
2250+
})JSON");
2251+
2252+
EXPECT_EQ(document, expected);
2253+
}
2254+
2255+
TEST(AlterSchema_lint_2020_12, then_empty_2) {
2256+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
2257+
"$schema": "https://json-schema.org/draft/2020-12/schema",
2258+
"if": {
2259+
"properties": {
2260+
"flag": {
2261+
"const": true
2262+
}
2263+
}
2264+
},
2265+
"then": {},
2266+
"else": {}
2267+
})JSON");
2268+
2269+
LINT_AND_FIX_FOR_READABILITY(document);
2270+
2271+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
2272+
"$schema": "https://json-schema.org/draft/2020-12/schema"
2273+
})JSON");
2274+
2275+
EXPECT_EQ(document, expected);
2276+
}
2277+
2278+
TEST(AlterSchema_lint_2020_12, else_empty_2) {
2279+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
2280+
"$schema": "https://json-schema.org/draft/2020-12/schema",
2281+
"if": {
2282+
"properties": {
2283+
"flag": {
2284+
"const": true
2285+
}
2286+
}
2287+
},
2288+
"then": {
2289+
"type": "string"
2290+
},
2291+
"else": {}
2292+
})JSON");
2293+
2294+
LINT_AND_FIX_FOR_READABILITY(document);
2295+
2296+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
2297+
"$schema": "https://json-schema.org/draft/2020-12/schema",
2298+
"if": {
2299+
"properties": {
2300+
"flag": {
2301+
"const": true
2302+
}
2303+
}
2304+
},
2305+
"then": {
2306+
"type": "string"
2307+
}
2308+
})JSON");
2309+
2310+
EXPECT_EQ(document, expected);
2311+
}
2312+
2313+
TEST(AlterSchema_lint_2020_12, else_empty_3) {
2314+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
2315+
"$schema": "https://json-schema.org/draft/2020-12/schema",
2316+
"if": {
2317+
"properties": {
2318+
"flag": {
2319+
"const": true
2320+
}
2321+
}
2322+
},
2323+
"else": true
2324+
})JSON");
2325+
2326+
LINT_AND_FIX_FOR_READABILITY(document);
2327+
2328+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
2329+
"$schema": "https://json-schema.org/draft/2020-12/schema"
2330+
})JSON");
2331+
2332+
EXPECT_EQ(document, expected);
2333+
}
2334+
2335+
TEST(AlterSchema_lint_2020_12, then_empty_3) {
2336+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
2337+
"$schema": "https://json-schema.org/draft/2020-12/schema",
2338+
"if": {
2339+
"properties": {
2340+
"flag": {
2341+
"const": true
2342+
}
2343+
}
2344+
},
2345+
"then": true
2346+
})JSON");
2347+
2348+
LINT_AND_FIX_FOR_READABILITY(document);
2349+
2350+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
2351+
"$schema": "https://json-schema.org/draft/2020-12/schema"
2352+
})JSON");
2353+
2354+
EXPECT_EQ(document, expected);
2355+
}
2356+
2357+
TEST(AlterSchema_lint_2020_12, then_empty_4) {
2358+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
2359+
"$schema": "https://json-schema.org/draft/2020-12/schema",
2360+
"then": {}
2361+
})JSON");
2362+
2363+
LINT_AND_FIX_FOR_READABILITY(document);
2364+
2365+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
2366+
"$schema": "https://json-schema.org/draft/2020-12/schema"
2367+
})JSON");
2368+
2369+
EXPECT_EQ(document, expected);
2370+
}

0 commit comments

Comments
 (0)