Skip to content

Commit 060bb26

Browse files
committed
Support returning pointers as part of SchemaTransformRule::Result
Signed-off-by: Juan Cruz Viotti <[email protected]>
1 parent 85b02e0 commit 060bb26

12 files changed

+229
-101
lines changed

src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
#include <sourcemeta/core/jsonschema_resolver.h>
1212

1313
#include <cassert> // assert
14-
#include <concepts> // std::derived_from
14+
#include <concepts> // std::derived_from, std::same_as
1515
#include <functional> // std::function
16+
#include <iterator> // std::make_move_iterator, std::begin, std::end
1617
#include <map> // std::map
1718
#include <memory> // std::make_unique, std::unique_ptr
1819
#include <optional> // std::optional, std::nullopt
@@ -88,8 +89,26 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaTransformRule {
8889
: applies{true}, description{std::move(description_)} {}
8990
Result(const char *description_)
9091
: applies{true}, description{description_} {}
92+
Result(Pointer pointer)
93+
: applies{true}, description{""}, locations{std::move(pointer)} {
94+
assert(this->locations.size() == 1);
95+
}
96+
97+
template <typename T>
98+
requires std::same_as<typename T::value_type, Pointer>
99+
Result(T &&container) : applies{true}, description{""} {
100+
auto &&input = std::forward<T>(container);
101+
if constexpr (requires { input.size(); }) {
102+
locations.reserve(input.size());
103+
}
104+
105+
locations.assign(std::make_move_iterator(std::begin(input)),
106+
std::make_move_iterator(std::end(input)));
107+
}
108+
91109
bool applies;
92110
std::string description{""};
111+
std::vector<Pointer> locations;
93112
};
94113

95114
/// Apply the rule to a schema

src/extension/alterschema/alterschema.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include <sourcemeta/core/alterschema.h>
22

3+
#include <initializer_list> // std::initializer_list
4+
35
// For built-in rules
46
#include <algorithm>
57
#include <cmath>
@@ -14,6 +16,29 @@ contains_any(const Vocabularies &container,
1416
});
1517
}
1618

19+
static auto keyword(const Pointer::Token::Property &keyword,
20+
const bool condition) -> SchemaTransformRule::Result {
21+
if (condition) {
22+
return Pointer{keyword};
23+
} else {
24+
return false;
25+
}
26+
}
27+
28+
static auto keywords(std::initializer_list<Pointer::Token::Property> keywords,
29+
const bool condition) -> SchemaTransformRule::Result {
30+
if (condition) {
31+
std::vector<Pointer> result;
32+
result.reserve(keywords.size());
33+
for (auto &&keyword : keywords) {
34+
result.push_back(Pointer{keyword});
35+
}
36+
return result;
37+
} else {
38+
return false;
39+
}
40+
}
41+
1742
// Canonicalizer
1843
#include "canonicalizer/boolean_true.h"
1944
#include "canonicalizer/const_as_enum.h"

src/extension/alterschema/canonicalizer/const_as_enum.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@ class ConstAsEnum final : public SchemaTransformRule {
1414
const sourcemeta::core::SchemaWalker &,
1515
const sourcemeta::core::SchemaResolver &) const
1616
-> sourcemeta::core::SchemaTransformRule::Result override {
17-
return contains_any(
18-
vocabularies,
19-
{"https://json-schema.org/draft/2020-12/vocab/validation",
20-
"https://json-schema.org/draft/2019-09/vocab/validation",
21-
"http://json-schema.org/draft-07/schema#",
22-
"http://json-schema.org/draft-06/schema#"}) &&
23-
schema.is_object() && schema.defines("const") &&
24-
!schema.defines("enum");
17+
return keyword(
18+
"const",
19+
contains_any(vocabularies,
20+
{"https://json-schema.org/draft/2020-12/vocab/validation",
21+
"https://json-schema.org/draft/2019-09/vocab/validation",
22+
"http://json-schema.org/draft-07/schema#",
23+
"http://json-schema.org/draft-06/schema#"}) &&
24+
schema.is_object() && schema.defines("const") &&
25+
!schema.defines("enum"));
2526
}
2627

2728
auto transform(JSON &schema) const -> void override {

src/extension/alterschema/canonicalizer/exclusive_maximum_integer_to_maximum.h

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,19 @@ class ExclusiveMaximumIntegerToMaximum final : public SchemaTransformRule {
1515
const sourcemeta::core::SchemaWalker &,
1616
const sourcemeta::core::SchemaResolver &) const
1717
-> sourcemeta::core::SchemaTransformRule::Result override {
18-
return contains_any(
19-
vocabularies,
20-
{"https://json-schema.org/draft/2020-12/vocab/validation",
21-
"https://json-schema.org/draft/2019-09/vocab/validation",
22-
"http://json-schema.org/draft-07/schema#",
23-
"http://json-schema.org/draft-06/schema#"}) &&
24-
schema.is_object() && schema.defines("type") &&
25-
schema.at("type").is_string() &&
26-
schema.at("type").to_string() == "integer" &&
27-
schema.defines("exclusiveMaximum") &&
28-
schema.at("exclusiveMaximum").is_number() &&
29-
!schema.defines("maximum");
18+
return keywords(
19+
{"exclusiveMaximum", "type"},
20+
contains_any(vocabularies,
21+
{"https://json-schema.org/draft/2020-12/vocab/validation",
22+
"https://json-schema.org/draft/2019-09/vocab/validation",
23+
"http://json-schema.org/draft-07/schema#",
24+
"http://json-schema.org/draft-06/schema#"}) &&
25+
schema.is_object() && schema.defines("type") &&
26+
schema.at("type").is_string() &&
27+
schema.at("type").to_string() == "integer" &&
28+
schema.defines("exclusiveMaximum") &&
29+
schema.at("exclusiveMaximum").is_number() &&
30+
!schema.defines("maximum"));
3031
}
3132

3233
auto transform(JSON &schema) const -> void override {

src/extension/alterschema/canonicalizer/exclusive_minimum_integer_to_minimum.h

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,19 @@ class ExclusiveMinimumIntegerToMinimum final : public SchemaTransformRule {
1515
const sourcemeta::core::SchemaWalker &,
1616
const sourcemeta::core::SchemaResolver &) const
1717
-> sourcemeta::core::SchemaTransformRule::Result override {
18-
return contains_any(
19-
vocabularies,
20-
{"https://json-schema.org/draft/2020-12/vocab/validation",
21-
"https://json-schema.org/draft/2019-09/vocab/validation",
22-
"http://json-schema.org/draft-07/schema#",
23-
"http://json-schema.org/draft-06/schema#"}) &&
24-
schema.is_object() && schema.defines("type") &&
25-
schema.at("type").is_string() &&
26-
schema.at("type").to_string() == "integer" &&
27-
schema.defines("exclusiveMinimum") &&
28-
schema.at("exclusiveMinimum").is_number() &&
29-
!schema.defines("minimum");
18+
return keywords(
19+
{"exclusiveMinimum", "type"},
20+
contains_any(vocabularies,
21+
{"https://json-schema.org/draft/2020-12/vocab/validation",
22+
"https://json-schema.org/draft/2019-09/vocab/validation",
23+
"http://json-schema.org/draft-07/schema#",
24+
"http://json-schema.org/draft-06/schema#"}) &&
25+
schema.is_object() && schema.defines("type") &&
26+
schema.at("type").is_string() &&
27+
schema.at("type").to_string() == "integer" &&
28+
schema.defines("exclusiveMinimum") &&
29+
schema.at("exclusiveMinimum").is_number() &&
30+
!schema.defines("minimum"));
3031
}
3132

3233
auto transform(JSON &schema) const -> void override {

src/extension/alterschema/canonicalizer/max_contains_covered_by_max_items.h

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,17 @@ class MaxContainsCoveredByMaxItems final : public SchemaTransformRule {
1616
const sourcemeta::core::SchemaWalker &,
1717
const sourcemeta::core::SchemaResolver &) const
1818
-> sourcemeta::core::SchemaTransformRule::Result override {
19-
return contains_any(
20-
vocabularies,
21-
{"https://json-schema.org/draft/2020-12/vocab/validation",
22-
"https://json-schema.org/draft/2019-09/vocab/validation"}) &&
23-
schema.is_object() && schema.defines("maxContains") &&
24-
schema.at("maxContains").is_integer() &&
25-
schema.defines("maxItems") && schema.at("maxItems").is_integer() &&
26-
schema.at("maxContains").to_integer() >
27-
schema.at("maxItems").to_integer();
19+
return keywords(
20+
{"maxContains", "maxItems"},
21+
contains_any(
22+
vocabularies,
23+
{"https://json-schema.org/draft/2020-12/vocab/validation",
24+
"https://json-schema.org/draft/2019-09/vocab/validation"}) &&
25+
schema.is_object() && schema.defines("maxContains") &&
26+
schema.at("maxContains").is_integer() &&
27+
schema.defines("maxItems") && schema.at("maxItems").is_integer() &&
28+
schema.at("maxContains").to_integer() >
29+
schema.at("maxItems").to_integer());
2830
}
2931

3032
auto transform(JSON &schema) const -> void override {

src/extension/alterschema/canonicalizer/min_properties_covered_by_required.h

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,21 @@ class MinPropertiesCoveredByRequired final : public SchemaTransformRule {
1515
const sourcemeta::core::SchemaWalker &,
1616
const sourcemeta::core::SchemaResolver &) const
1717
-> sourcemeta::core::SchemaTransformRule::Result override {
18-
return contains_any(
19-
vocabularies,
20-
{"https://json-schema.org/draft/2020-12/vocab/validation",
21-
"https://json-schema.org/draft/2019-09/vocab/validation",
22-
"http://json-schema.org/draft-07/schema#",
23-
"http://json-schema.org/draft-06/schema#",
24-
"http://json-schema.org/draft-04/schema#"}) &&
25-
schema.is_object() && schema.defines("minProperties") &&
26-
schema.at("minProperties").is_integer() &&
27-
schema.defines("required") && schema.at("required").is_array() &&
28-
schema.at("required").unique() &&
29-
std::cmp_greater(schema.at("required").size(),
30-
static_cast<std::uint64_t>(
31-
schema.at("minProperties").to_integer()));
18+
return keywords(
19+
{"minProperties", "required"},
20+
contains_any(vocabularies,
21+
{"https://json-schema.org/draft/2020-12/vocab/validation",
22+
"https://json-schema.org/draft/2019-09/vocab/validation",
23+
"http://json-schema.org/draft-07/schema#",
24+
"http://json-schema.org/draft-06/schema#",
25+
"http://json-schema.org/draft-04/schema#"}) &&
26+
schema.is_object() && schema.defines("minProperties") &&
27+
schema.at("minProperties").is_integer() &&
28+
schema.defines("required") && schema.at("required").is_array() &&
29+
schema.at("required").unique() &&
30+
std::cmp_greater(schema.at("required").size(),
31+
static_cast<std::uint64_t>(
32+
schema.at("minProperties").to_integer())));
3233
}
3334

3435
auto transform(JSON &schema) const -> void override {

src/extension/alterschema/canonicalizer/type_array_to_any_of_2020_12.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,19 @@ class TypeArrayToAnyOf_2020_12 final : public SchemaTransformRule {
3131
sourcemeta::core::SchemaFrame::LocationType::Anchor;
3232
})};
3333

34-
return contains_any(
35-
vocabularies,
36-
{"https://json-schema.org/draft/2020-12/vocab/validation",
37-
"https://json-schema.org/draft/2020-12/vocab/applicator"}) &&
38-
!has_identifiers && schema.is_object() && schema.defines("type") &&
39-
schema.at("type").is_array() &&
40-
// Non type-specific applicators can leads to invalid schemas
41-
!schema.defines("$defs") && !schema.defines("$ref") &&
42-
!schema.defines("if") && !schema.defines("then") &&
43-
!schema.defines("else") && !schema.defines("allOf") &&
44-
!schema.defines("oneOf") && !schema.defines("anyOf");
34+
return keyword(
35+
"type",
36+
contains_any(
37+
vocabularies,
38+
{"https://json-schema.org/draft/2020-12/vocab/validation",
39+
"https://json-schema.org/draft/2020-12/vocab/applicator"}) &&
40+
!has_identifiers && schema.is_object() && schema.defines("type") &&
41+
schema.at("type").is_array() &&
42+
// Non type-specific applicators can leads to invalid schemas
43+
!schema.defines("$defs") && !schema.defines("$ref") &&
44+
!schema.defines("if") && !schema.defines("then") &&
45+
!schema.defines("else") && !schema.defines("allOf") &&
46+
!schema.defines("oneOf") && !schema.defines("anyOf"));
4547
}
4648

4749
auto transform(JSON &schema) const -> void override {

src/extension/alterschema/canonicalizer/type_boolean_as_enum.h

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,21 @@ class TypeBooleanAsEnum final : public SchemaTransformRule {
1515
const sourcemeta::core::SchemaWalker &,
1616
const sourcemeta::core::SchemaResolver &) const
1717
-> sourcemeta::core::SchemaTransformRule::Result override {
18-
return contains_any(
19-
vocabularies,
20-
{"https://json-schema.org/draft/2020-12/vocab/validation",
21-
"https://json-schema.org/draft/2019-09/vocab/validation",
22-
"http://json-schema.org/draft-07/schema#",
23-
"http://json-schema.org/draft-06/schema#",
24-
"http://json-schema.org/draft-04/schema#",
25-
"http://json-schema.org/draft-03/schema#",
26-
"http://json-schema.org/draft-02/schema#",
27-
"http://json-schema.org/draft-01/schema#"}) &&
28-
schema.is_object() && schema.defines("type") &&
29-
schema.at("type").is_string() &&
30-
schema.at("type").to_string() == "boolean" &&
31-
!schema.defines("enum") && !schema.defines("const");
18+
return keyword(
19+
"type",
20+
contains_any(vocabularies,
21+
{"https://json-schema.org/draft/2020-12/vocab/validation",
22+
"https://json-schema.org/draft/2019-09/vocab/validation",
23+
"http://json-schema.org/draft-07/schema#",
24+
"http://json-schema.org/draft-06/schema#",
25+
"http://json-schema.org/draft-04/schema#",
26+
"http://json-schema.org/draft-03/schema#",
27+
"http://json-schema.org/draft-02/schema#",
28+
"http://json-schema.org/draft-01/schema#"}) &&
29+
schema.is_object() && schema.defines("type") &&
30+
schema.at("type").is_string() &&
31+
schema.at("type").to_string() == "boolean" &&
32+
!schema.defines("enum") && !schema.defines("const"));
3233
}
3334

3435
auto transform(JSON &schema) const -> void override {

src/extension/alterschema/canonicalizer/type_null_as_enum.h

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,21 @@ class TypeNullAsEnum final : public SchemaTransformRule {
1515
const sourcemeta::core::SchemaWalker &,
1616
const sourcemeta::core::SchemaResolver &) const
1717
-> sourcemeta::core::SchemaTransformRule::Result override {
18-
return contains_any(
19-
vocabularies,
20-
{"https://json-schema.org/draft/2020-12/vocab/validation",
21-
"https://json-schema.org/draft/2019-09/vocab/validation",
22-
"http://json-schema.org/draft-07/schema#",
23-
"http://json-schema.org/draft-06/schema#",
24-
"http://json-schema.org/draft-04/schema#",
25-
"http://json-schema.org/draft-03/schema#",
26-
"http://json-schema.org/draft-02/schema#",
27-
"http://json-schema.org/draft-01/schema#"}) &&
28-
schema.is_object() && schema.defines("type") &&
29-
schema.at("type").is_string() &&
30-
schema.at("type").to_string() == "null" && !schema.defines("enum") &&
31-
!schema.defines("const");
18+
return keyword(
19+
"type",
20+
contains_any(vocabularies,
21+
{"https://json-schema.org/draft/2020-12/vocab/validation",
22+
"https://json-schema.org/draft/2019-09/vocab/validation",
23+
"http://json-schema.org/draft-07/schema#",
24+
"http://json-schema.org/draft-06/schema#",
25+
"http://json-schema.org/draft-04/schema#",
26+
"http://json-schema.org/draft-03/schema#",
27+
"http://json-schema.org/draft-02/schema#",
28+
"http://json-schema.org/draft-01/schema#"}) &&
29+
schema.is_object() && schema.defines("type") &&
30+
schema.at("type").is_string() &&
31+
schema.at("type").to_string() == "null" &&
32+
!schema.defines("enum") && !schema.defines("const"));
3233
}
3334

3435
auto transform(JSON &schema) const -> void override {

0 commit comments

Comments
 (0)