jsoncons 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/ext/jsoncons/extconf.rb +43 -0
- data/ext/jsoncons/jsoncons.cpp +161 -0
- data/ext/jsoncons/jsoncons.h +10 -0
- data/jsoncons.gemspec +44 -0
- data/lib/jsoncons/jsoncons/examples/input/address-book.json +13 -0
- data/lib/jsoncons/jsoncons/examples/input/books.json +28 -0
- data/lib/jsoncons/jsoncons/examples/input/countries.json +7 -0
- data/lib/jsoncons/jsoncons/examples/input/employees.json +30 -0
- data/lib/jsoncons/jsoncons/examples/input/jsonschema/name.json +15 -0
- data/lib/jsoncons/jsoncons/examples/input/multiple-json-objects.json +3 -0
- data/lib/jsoncons/jsoncons/examples/input/sales.csv +6 -0
- data/lib/jsoncons/jsoncons/examples/input/store.json +28 -0
- data/lib/jsoncons/jsoncons/examples/input/tasks.csv +6 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/allocator_holder.hpp +38 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/basic_json.hpp +5905 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/bigint.hpp +1611 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/byte_string.hpp +820 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/config/binary_config.hpp +226 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/config/compiler_support.hpp +375 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/config/jsoncons_config.hpp +309 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/config/version.hpp +40 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/conv_error.hpp +218 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/decode_json.hpp +209 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/decode_traits.hpp +651 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/endian.hpp +44 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/grisu3.hpp +312 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/optional.hpp +483 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/parse_number.hpp +1133 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/span.hpp +188 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/string_view.hpp +537 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/string_wrapper.hpp +370 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/detail/write_number.hpp +567 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/encode_json.hpp +315 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/encode_traits.hpp +378 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json.hpp +18 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_array.hpp +324 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_content_handler.hpp +12 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_cursor.hpp +448 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_decoder.hpp +420 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_encoder.hpp +1587 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_error.hpp +156 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_exception.hpp +241 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_filter.hpp +653 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_fwd.hpp +23 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_object.hpp +1772 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_options.hpp +862 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_parser.hpp +2900 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_reader.hpp +731 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_traits_macros.hpp +1072 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_traits_macros_deprecated.hpp +144 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_type.hpp +206 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_type_traits.hpp +1830 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_visitor.hpp +1560 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/json_visitor2.hpp +2079 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/pretty_print.hpp +89 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/ser_context.hpp +62 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/sink.hpp +289 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/source.hpp +777 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/source_adaptor.hpp +148 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/staj2_cursor.hpp +1189 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/staj_cursor.hpp +1254 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/staj_iterator.hpp +449 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/tag_type.hpp +245 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/text_source_adaptor.hpp +144 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/traits_extension.hpp +884 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/typed_array_view.hpp +250 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/unicode_traits.hpp +1330 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/uri.hpp +635 -0
- data/lib/jsoncons/jsoncons/include/jsoncons/value_converter.hpp +340 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson.hpp +23 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_cursor.hpp +320 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_decimal128.hpp +865 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_encoder.hpp +585 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_error.hpp +103 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_oid.hpp +245 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_options.hpp +75 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_parser.hpp +645 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_reader.hpp +92 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_type.hpp +44 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/decode_bson.hpp +201 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/encode_bson.hpp +144 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor.hpp +26 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_cursor.hpp +351 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_cursor2.hpp +265 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_detail.hpp +93 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_encoder.hpp +1766 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_error.hpp +105 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_options.hpp +113 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_parser.hpp +1942 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_reader.hpp +116 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/decode_cbor.hpp +203 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/encode_cbor.hpp +151 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv.hpp +17 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_cursor.hpp +358 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_encoder.hpp +954 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_error.hpp +85 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_options.hpp +973 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_parser.hpp +2099 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_reader.hpp +348 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_serializer.hpp +12 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/decode_csv.hpp +208 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/encode_csv.hpp +122 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jmespath/jmespath.hpp +5215 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jmespath/jmespath_error.hpp +215 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpatch/jsonpatch.hpp +579 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpatch/jsonpatch_error.hpp +121 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/expression.hpp +3329 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/flatten.hpp +432 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/json_location.hpp +445 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/json_query.hpp +115 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath.hpp +13 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath_error.hpp +240 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath_expression.hpp +2612 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath_selector.hpp +1322 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpointer/jsonpointer.hpp +1577 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpointer/jsonpointer_error.hpp +119 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/format_validator.hpp +968 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/json_validator.hpp +120 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/jsonschema.hpp +13 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/jsonschema_error.hpp +105 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/jsonschema_version.hpp +18 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/keyword_validator.hpp +1745 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/keyword_validator_factory.hpp +556 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/schema_draft7.hpp +198 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/schema_location.hpp +200 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/schema_version.hpp +35 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/subschema.hpp +144 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/mergepatch/mergepatch.hpp +103 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/decode_msgpack.hpp +202 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/encode_msgpack.hpp +142 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack.hpp +24 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_cursor.hpp +343 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_cursor2.hpp +259 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_encoder.hpp +753 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_error.hpp +94 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_options.hpp +74 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_parser.hpp +748 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_reader.hpp +116 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_type.hpp +63 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/decode_ubjson.hpp +201 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/encode_ubjson.hpp +142 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson.hpp +23 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_cursor.hpp +307 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_encoder.hpp +502 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_error.hpp +100 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_options.hpp +87 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_parser.hpp +880 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_reader.hpp +92 -0
- data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_type.hpp +43 -0
- data/lib/jsoncons/version.rb +5 -0
- data/lib/jsoncons.rb +33 -0
- data/test/jsoncons_test.rb +108 -0
- data/test/test_helper.rb +7 -0
- metadata +268 -0
|
@@ -0,0 +1,1745 @@
|
|
|
1
|
+
// Copyright 2020 Daniel Parker
|
|
2
|
+
// Distributed under the Boost license, Version 1.0.
|
|
3
|
+
// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
4
|
+
|
|
5
|
+
// See https://github.com/danielaparker/jsoncons for latest version
|
|
6
|
+
|
|
7
|
+
#ifndef JSONCONS_JSONSCHEMA_KEYWORD_VALIDATOR_HPP
|
|
8
|
+
#define JSONCONS_JSONSCHEMA_KEYWORD_VALIDATOR_HPP
|
|
9
|
+
|
|
10
|
+
#include <jsoncons/config/jsoncons_config.hpp>
|
|
11
|
+
#include <jsoncons/uri.hpp>
|
|
12
|
+
#include <jsoncons/json.hpp>
|
|
13
|
+
#include <jsoncons_ext/jsonpointer/jsonpointer.hpp>
|
|
14
|
+
#include <jsoncons_ext/jsonschema/subschema.hpp>
|
|
15
|
+
#include <jsoncons_ext/jsonschema/format_validator.hpp>
|
|
16
|
+
#include <cassert>
|
|
17
|
+
#include <set>
|
|
18
|
+
#include <sstream>
|
|
19
|
+
#include <iostream>
|
|
20
|
+
#include <cassert>
|
|
21
|
+
#if defined(JSONCONS_HAS_STD_REGEX)
|
|
22
|
+
#include <regex>
|
|
23
|
+
#endif
|
|
24
|
+
|
|
25
|
+
namespace jsoncons {
|
|
26
|
+
namespace jsonschema {
|
|
27
|
+
|
|
28
|
+
template <class Json>
|
|
29
|
+
class abstract_keyword_validator_factory
|
|
30
|
+
{
|
|
31
|
+
public:
|
|
32
|
+
using validator_pointer = typename keyword_validator<Json>::self_pointer;
|
|
33
|
+
|
|
34
|
+
virtual ~abstract_keyword_validator_factory() = default;
|
|
35
|
+
|
|
36
|
+
virtual validator_pointer make_keyword_validator(const Json& schema,
|
|
37
|
+
const std::vector<schema_location>& uris,
|
|
38
|
+
const std::vector<std::string>& keys) = 0;
|
|
39
|
+
virtual validator_pointer make_required_validator(const std::vector<schema_location>& uris,
|
|
40
|
+
const std::vector<std::string>& items) = 0;
|
|
41
|
+
|
|
42
|
+
virtual validator_pointer make_null_validator(const std::vector<schema_location>& uris) = 0;
|
|
43
|
+
|
|
44
|
+
virtual validator_pointer make_true_validator(const std::vector<schema_location>& uris) = 0;
|
|
45
|
+
|
|
46
|
+
virtual validator_pointer make_false_validator(const std::vector<schema_location>& uris) = 0;
|
|
47
|
+
|
|
48
|
+
virtual validator_pointer make_object_validator(const Json& sch,
|
|
49
|
+
const std::vector<schema_location>& uris) = 0;
|
|
50
|
+
|
|
51
|
+
virtual validator_pointer make_array_validator(const Json& sch,
|
|
52
|
+
const std::vector<schema_location>& uris) = 0;
|
|
53
|
+
|
|
54
|
+
virtual validator_pointer make_string_validator(const Json& sch,
|
|
55
|
+
const std::vector<schema_location>& uris) = 0;
|
|
56
|
+
|
|
57
|
+
virtual validator_pointer make_boolean_validator(const std::vector<schema_location>& uris) = 0;
|
|
58
|
+
|
|
59
|
+
virtual validator_pointer make_integer_validator(const Json& sch,
|
|
60
|
+
const std::vector<schema_location>& uris,
|
|
61
|
+
std::set<std::string>& keywords) = 0;
|
|
62
|
+
|
|
63
|
+
virtual validator_pointer make_number_validator(const Json& sch,
|
|
64
|
+
const std::vector<schema_location>& uris,
|
|
65
|
+
std::set<std::string>& keywords) = 0;
|
|
66
|
+
|
|
67
|
+
virtual validator_pointer make_not_validator(const Json& schema,
|
|
68
|
+
const std::vector<schema_location>& uris) = 0;
|
|
69
|
+
|
|
70
|
+
virtual validator_pointer make_all_of_validator(const Json& schema,
|
|
71
|
+
const std::vector<schema_location>& uris) = 0;
|
|
72
|
+
|
|
73
|
+
virtual validator_pointer make_any_of_validator(const Json& schema,
|
|
74
|
+
const std::vector<schema_location>& uris) = 0;
|
|
75
|
+
|
|
76
|
+
virtual validator_pointer make_one_of_validator(const Json& schema,
|
|
77
|
+
const std::vector<schema_location>& uris) = 0;
|
|
78
|
+
|
|
79
|
+
virtual validator_pointer make_type_validator(const Json& schema,
|
|
80
|
+
const std::vector<schema_location>& uris) = 0;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
struct collecting_error_reporter : public error_reporter
|
|
84
|
+
{
|
|
85
|
+
std::vector<validation_output> errors;
|
|
86
|
+
|
|
87
|
+
private:
|
|
88
|
+
void do_error(const validation_output& o) override
|
|
89
|
+
{
|
|
90
|
+
errors.push_back(o);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// string keyword_validator
|
|
95
|
+
|
|
96
|
+
inline
|
|
97
|
+
std::string make_absolute_keyword_location(const std::vector<schema_location>& uris,
|
|
98
|
+
const std::string& keyword)
|
|
99
|
+
{
|
|
100
|
+
for (auto it = uris.rbegin(); it != uris.rend(); ++it)
|
|
101
|
+
{
|
|
102
|
+
if (!it->has_identifier() && it->is_absolute())
|
|
103
|
+
{
|
|
104
|
+
return it->append(keyword).string();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return "";
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
template <class Json>
|
|
111
|
+
class string_validator : public keyword_validator<Json>
|
|
112
|
+
{
|
|
113
|
+
jsoncons::optional<std::size_t> max_length_;
|
|
114
|
+
std::string max_length_location_;
|
|
115
|
+
jsoncons::optional<std::size_t> min_length_;
|
|
116
|
+
std::string min_length_location_;
|
|
117
|
+
|
|
118
|
+
#if defined(JSONCONS_HAS_STD_REGEX)
|
|
119
|
+
jsoncons::optional<std::regex> pattern_;
|
|
120
|
+
std::string pattern_string_;
|
|
121
|
+
std::string pattern_location_;
|
|
122
|
+
#endif
|
|
123
|
+
|
|
124
|
+
format_checker format_check_;
|
|
125
|
+
std::string format_location_;
|
|
126
|
+
|
|
127
|
+
jsoncons::optional<std::string> content_encoding_;
|
|
128
|
+
std::string content_encoding_location_;
|
|
129
|
+
jsoncons::optional<std::string> content_media_type_;
|
|
130
|
+
std::string content_media_type_location_;
|
|
131
|
+
|
|
132
|
+
public:
|
|
133
|
+
string_validator(const Json& sch, const std::vector<schema_location>& uris)
|
|
134
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""), max_length_(), min_length_(),
|
|
135
|
+
#if defined(JSONCONS_HAS_STD_REGEX)
|
|
136
|
+
pattern_(),
|
|
137
|
+
#endif
|
|
138
|
+
content_encoding_(), content_media_type_()
|
|
139
|
+
{
|
|
140
|
+
auto it = sch.find("maxLength");
|
|
141
|
+
if (it != sch.object_range().end())
|
|
142
|
+
{
|
|
143
|
+
max_length_ = it->value().template as<std::size_t>();
|
|
144
|
+
max_length_location_ = make_absolute_keyword_location(uris, "maxLength");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
it = sch.find("minLength");
|
|
148
|
+
if (it != sch.object_range().end())
|
|
149
|
+
{
|
|
150
|
+
min_length_ = it->value().template as<std::size_t>();
|
|
151
|
+
min_length_location_ = make_absolute_keyword_location(uris, "minLength");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
it = sch.find("contentEncoding");
|
|
155
|
+
if (it != sch.object_range().end())
|
|
156
|
+
{
|
|
157
|
+
content_encoding_ = it->value().template as<std::string>();
|
|
158
|
+
content_encoding_location_ = make_absolute_keyword_location(uris, "contentEncoding");
|
|
159
|
+
// If "contentEncoding" is set to "binary", a Json value
|
|
160
|
+
// of type json_type::byte_string_value is accepted.
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
it = sch.find("contentMediaType");
|
|
164
|
+
if (it != sch.object_range().end())
|
|
165
|
+
{
|
|
166
|
+
content_media_type_ = it->value().template as<std::string>();
|
|
167
|
+
content_media_type_location_ = make_absolute_keyword_location(uris, "contentMediaType");
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
#if defined(JSONCONS_HAS_STD_REGEX)
|
|
171
|
+
it = sch.find("pattern");
|
|
172
|
+
if (it != sch.object_range().end())
|
|
173
|
+
{
|
|
174
|
+
pattern_string_ = it->value().template as<std::string>();
|
|
175
|
+
pattern_ = std::regex(it->value().template as<std::string>(),std::regex::ECMAScript);
|
|
176
|
+
pattern_location_ = make_absolute_keyword_location(uris, "pattern");
|
|
177
|
+
}
|
|
178
|
+
#endif
|
|
179
|
+
|
|
180
|
+
it = sch.find("format");
|
|
181
|
+
if (it != sch.object_range().end())
|
|
182
|
+
{
|
|
183
|
+
format_location_ = make_absolute_keyword_location(uris, "format");
|
|
184
|
+
std::string format = it->value().template as<std::string>();
|
|
185
|
+
if (format == "date-time")
|
|
186
|
+
{
|
|
187
|
+
format_check_ = rfc3339_date_time_check;
|
|
188
|
+
}
|
|
189
|
+
else if (format == "date")
|
|
190
|
+
{
|
|
191
|
+
format_check_ = rfc3339_date_check;
|
|
192
|
+
}
|
|
193
|
+
else if (format == "time")
|
|
194
|
+
{
|
|
195
|
+
format_check_ = rfc3339_time_check;
|
|
196
|
+
}
|
|
197
|
+
else if (format == "email")
|
|
198
|
+
{
|
|
199
|
+
format_check_ = email_check;
|
|
200
|
+
}
|
|
201
|
+
else if (format == "hostname")
|
|
202
|
+
{
|
|
203
|
+
format_check_ = hostname_check;
|
|
204
|
+
}
|
|
205
|
+
else if (format == "ipv4")
|
|
206
|
+
{
|
|
207
|
+
format_check_ = ipv4_check;
|
|
208
|
+
}
|
|
209
|
+
else if (format == "ipv6")
|
|
210
|
+
{
|
|
211
|
+
format_check_ = ipv6_check;
|
|
212
|
+
}
|
|
213
|
+
else if (format == "regex")
|
|
214
|
+
{
|
|
215
|
+
format_check_ = regex_check;
|
|
216
|
+
}
|
|
217
|
+
else
|
|
218
|
+
{
|
|
219
|
+
// Not supported - ignore
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private:
|
|
225
|
+
|
|
226
|
+
void do_validate(const Json& instance,
|
|
227
|
+
const jsonpointer::json_pointer& instance_location,
|
|
228
|
+
error_reporter& reporter,
|
|
229
|
+
Json&) const override
|
|
230
|
+
{
|
|
231
|
+
std::string content;
|
|
232
|
+
if (content_encoding_)
|
|
233
|
+
{
|
|
234
|
+
if (*content_encoding_ == "base64")
|
|
235
|
+
{
|
|
236
|
+
auto s = instance.template as<jsoncons::string_view>();
|
|
237
|
+
auto retval = jsoncons::decode_base64(s.begin(), s.end(), content);
|
|
238
|
+
if (retval.ec != jsoncons::conv_errc::success)
|
|
239
|
+
{
|
|
240
|
+
reporter.error(validation_output("contentEncoding",
|
|
241
|
+
content_encoding_location_,
|
|
242
|
+
instance_location.to_uri_fragment(),
|
|
243
|
+
"Content is not a base64 string"));
|
|
244
|
+
if (reporter.fail_early())
|
|
245
|
+
{
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
else if (!content_encoding_->empty())
|
|
251
|
+
{
|
|
252
|
+
reporter.error(validation_output("contentEncoding",
|
|
253
|
+
content_encoding_location_,
|
|
254
|
+
instance_location.to_uri_fragment(),
|
|
255
|
+
"unable to check for contentEncoding '" + *content_encoding_ + "'"));
|
|
256
|
+
if (reporter.fail_early())
|
|
257
|
+
{
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
else
|
|
263
|
+
{
|
|
264
|
+
content = instance.template as<std::string>();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (content_media_type_)
|
|
268
|
+
{
|
|
269
|
+
if (content_media_type_ == "application/Json")
|
|
270
|
+
{
|
|
271
|
+
json_string_reader reader(content);
|
|
272
|
+
std::error_code ec;
|
|
273
|
+
reader.read(ec);
|
|
274
|
+
|
|
275
|
+
if (ec)
|
|
276
|
+
{
|
|
277
|
+
reporter.error(validation_output("contentMediaType",
|
|
278
|
+
content_media_type_location_,
|
|
279
|
+
instance_location.to_uri_fragment(),
|
|
280
|
+
std::string("Content is not JSON: ") + ec.message()));
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
else if (instance.type() == json_type::byte_string_value)
|
|
285
|
+
{
|
|
286
|
+
reporter.error(validation_output("contentMediaType",
|
|
287
|
+
content_media_type_location_,
|
|
288
|
+
instance_location.to_uri_fragment(),
|
|
289
|
+
"Expected string, but is byte string"));
|
|
290
|
+
if (reporter.fail_early())
|
|
291
|
+
{
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (instance.type() != json_type::string_value)
|
|
297
|
+
{
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (min_length_)
|
|
302
|
+
{
|
|
303
|
+
std::size_t length = unicode_traits::count_codepoints(content.data(), content.size());
|
|
304
|
+
if (length < *min_length_)
|
|
305
|
+
{
|
|
306
|
+
reporter.error(validation_output("minLength",
|
|
307
|
+
min_length_location_,
|
|
308
|
+
instance_location.to_uri_fragment(),
|
|
309
|
+
std::string("Expected minLength: ") + std::to_string(*min_length_)
|
|
310
|
+
+ ", actual: " + std::to_string(length)));
|
|
311
|
+
if (reporter.fail_early())
|
|
312
|
+
{
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (max_length_)
|
|
319
|
+
{
|
|
320
|
+
std::size_t length = unicode_traits::count_codepoints(content.data(), content.size());
|
|
321
|
+
if (length > *max_length_)
|
|
322
|
+
{
|
|
323
|
+
reporter.error(validation_output("maxLength",
|
|
324
|
+
max_length_location_,
|
|
325
|
+
instance_location.to_uri_fragment(),
|
|
326
|
+
std::string("Expected maxLength: ") + std::to_string(*max_length_)
|
|
327
|
+
+ ", actual: " + std::to_string(length)));
|
|
328
|
+
if (reporter.fail_early())
|
|
329
|
+
{
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
#if defined(JSONCONS_HAS_STD_REGEX)
|
|
336
|
+
if (pattern_)
|
|
337
|
+
{
|
|
338
|
+
if (!std::regex_search(content, *pattern_))
|
|
339
|
+
{
|
|
340
|
+
std::string message("String \"");
|
|
341
|
+
message.append(instance.template as<std::string>());
|
|
342
|
+
message.append("\" does not match pattern \"");
|
|
343
|
+
message.append(pattern_string_);
|
|
344
|
+
message.append("\"");
|
|
345
|
+
reporter.error(validation_output("pattern",
|
|
346
|
+
pattern_location_,
|
|
347
|
+
instance_location.to_uri_fragment(),
|
|
348
|
+
std::move(message)));
|
|
349
|
+
if (reporter.fail_early())
|
|
350
|
+
{
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
#endif
|
|
357
|
+
|
|
358
|
+
if (format_check_ != nullptr)
|
|
359
|
+
{
|
|
360
|
+
format_check_(format_location_, instance_location, content, reporter);
|
|
361
|
+
if (reporter.error_count() > 0 && reporter.fail_early())
|
|
362
|
+
{
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
// not_validator
|
|
370
|
+
|
|
371
|
+
template <class Json>
|
|
372
|
+
class not_validator : public keyword_validator<Json>
|
|
373
|
+
{
|
|
374
|
+
using validator_pointer = typename keyword_validator<Json>::self_pointer;
|
|
375
|
+
|
|
376
|
+
validator_pointer rule_;
|
|
377
|
+
|
|
378
|
+
public:
|
|
379
|
+
not_validator(abstract_keyword_validator_factory<Json>* builder,
|
|
380
|
+
const Json& sch,
|
|
381
|
+
const std::vector<schema_location>& uris)
|
|
382
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : "")
|
|
383
|
+
{
|
|
384
|
+
rule_ = builder->make_keyword_validator(sch, uris, {"not"});
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
private:
|
|
388
|
+
|
|
389
|
+
void do_validate(const Json& instance,
|
|
390
|
+
const jsonpointer::json_pointer& instance_location,
|
|
391
|
+
error_reporter& reporter,
|
|
392
|
+
Json& patch) const final
|
|
393
|
+
{
|
|
394
|
+
collecting_error_reporter local_reporter;
|
|
395
|
+
rule_->validate(instance, instance_location, local_reporter, patch);
|
|
396
|
+
|
|
397
|
+
if (local_reporter.errors.empty())
|
|
398
|
+
{
|
|
399
|
+
reporter.error(validation_output("not",
|
|
400
|
+
this->absolute_keyword_location(),
|
|
401
|
+
instance_location.to_uri_fragment(),
|
|
402
|
+
"Instance must not be valid against schema"));
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
jsoncons::optional<Json> get_default_value(const jsonpointer::json_pointer& instance_location,
|
|
407
|
+
const Json& instance,
|
|
408
|
+
error_reporter& reporter) const override
|
|
409
|
+
{
|
|
410
|
+
return rule_->get_default_value(instance_location, instance, reporter);
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
template <class Json>
|
|
415
|
+
struct all_of_criterion
|
|
416
|
+
{
|
|
417
|
+
static const std::string& key()
|
|
418
|
+
{
|
|
419
|
+
static const std::string k("allOf");
|
|
420
|
+
return k;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
static bool is_complete(const Json&,
|
|
424
|
+
const jsonpointer::json_pointer& instance_location,
|
|
425
|
+
error_reporter& reporter,
|
|
426
|
+
const collecting_error_reporter& local_reporter,
|
|
427
|
+
std::size_t)
|
|
428
|
+
{
|
|
429
|
+
if (!local_reporter.errors.empty())
|
|
430
|
+
reporter.error(validation_output("allOf",
|
|
431
|
+
"",
|
|
432
|
+
instance_location.to_uri_fragment(),
|
|
433
|
+
"At least one schema failed to match, but all are required to match. ",
|
|
434
|
+
local_reporter.errors));
|
|
435
|
+
return !local_reporter.errors.empty();
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
template <class Json>
|
|
440
|
+
struct any_of_criterion
|
|
441
|
+
{
|
|
442
|
+
static const std::string& key()
|
|
443
|
+
{
|
|
444
|
+
static const std::string k("anyOf");
|
|
445
|
+
return k;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
static bool is_complete(const Json&,
|
|
449
|
+
const jsonpointer::json_pointer&,
|
|
450
|
+
error_reporter&,
|
|
451
|
+
const collecting_error_reporter&,
|
|
452
|
+
std::size_t count)
|
|
453
|
+
{
|
|
454
|
+
return count == 1;
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
template <class Json>
|
|
459
|
+
struct one_of_criterion
|
|
460
|
+
{
|
|
461
|
+
static const std::string& key()
|
|
462
|
+
{
|
|
463
|
+
static const std::string k("oneOf");
|
|
464
|
+
return k;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
static bool is_complete(const Json&,
|
|
468
|
+
const jsonpointer::json_pointer& instance_location,
|
|
469
|
+
error_reporter& reporter,
|
|
470
|
+
const collecting_error_reporter&,
|
|
471
|
+
std::size_t count)
|
|
472
|
+
{
|
|
473
|
+
if (count > 1)
|
|
474
|
+
{
|
|
475
|
+
std::string message(std::to_string(count));
|
|
476
|
+
message.append(" subschemas matched, but exactly one is required to match");
|
|
477
|
+
reporter.error(validation_output("oneOf",
|
|
478
|
+
"",
|
|
479
|
+
instance_location.to_uri_fragment(),
|
|
480
|
+
std::move(message)));
|
|
481
|
+
}
|
|
482
|
+
return count > 1;
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
template <class Json,class Criterion>
|
|
487
|
+
class combining_validator : public keyword_validator<Json>
|
|
488
|
+
{
|
|
489
|
+
using validator_pointer = typename keyword_validator<Json>::self_pointer;
|
|
490
|
+
|
|
491
|
+
std::vector<validator_pointer> subschemas_;
|
|
492
|
+
|
|
493
|
+
public:
|
|
494
|
+
combining_validator(abstract_keyword_validator_factory<Json>* builder,
|
|
495
|
+
const Json& sch,
|
|
496
|
+
const std::vector<schema_location>& uris)
|
|
497
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : "")
|
|
498
|
+
{
|
|
499
|
+
size_t c = 0;
|
|
500
|
+
for (const auto& subsch : sch.array_range())
|
|
501
|
+
{
|
|
502
|
+
subschemas_.push_back(builder->make_keyword_validator(subsch, uris, {Criterion::key(), std::to_string(c++)}));
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Validate value of allOf, anyOf, and oneOf "MUST be a non-empty array"
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
private:
|
|
509
|
+
|
|
510
|
+
void do_validate(const Json& instance,
|
|
511
|
+
const jsonpointer::json_pointer& instance_location,
|
|
512
|
+
error_reporter& reporter,
|
|
513
|
+
Json& patch) const final
|
|
514
|
+
{
|
|
515
|
+
size_t count = 0;
|
|
516
|
+
|
|
517
|
+
collecting_error_reporter local_reporter;
|
|
518
|
+
for (auto& s : subschemas_)
|
|
519
|
+
{
|
|
520
|
+
std::size_t mark = local_reporter.errors.size();
|
|
521
|
+
s->validate(instance, instance_location, local_reporter, patch);
|
|
522
|
+
if (mark == local_reporter.errors.size())
|
|
523
|
+
count++;
|
|
524
|
+
|
|
525
|
+
if (Criterion::is_complete(instance, instance_location, reporter, local_reporter, count))
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (count == 0)
|
|
530
|
+
{
|
|
531
|
+
reporter.error(validation_output("combined",
|
|
532
|
+
this->absolute_keyword_location(),
|
|
533
|
+
instance_location.to_uri_fragment(),
|
|
534
|
+
"No schema matched, but one of them is required to match",
|
|
535
|
+
local_reporter.errors));
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
|
|
540
|
+
template <class T, class Json>
|
|
541
|
+
T get_number(const Json& val, const string_view& keyword)
|
|
542
|
+
{
|
|
543
|
+
if (!val.is_number())
|
|
544
|
+
{
|
|
545
|
+
std::string message(keyword);
|
|
546
|
+
message.append(" must be a number value");
|
|
547
|
+
JSONCONS_THROW(schema_error(message));
|
|
548
|
+
}
|
|
549
|
+
return val.template as<T>();
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
template <class Json,class T>
|
|
553
|
+
class numeric_validator_base : public keyword_validator<Json>
|
|
554
|
+
{
|
|
555
|
+
jsoncons::optional<T> maximum_;
|
|
556
|
+
std::string absolute_maximum_location_;
|
|
557
|
+
jsoncons::optional<T> minimum_;
|
|
558
|
+
std::string absolute_minimum_location_;
|
|
559
|
+
jsoncons::optional<T> exclusive_maximum_;
|
|
560
|
+
std::string absolute_exclusive_maximum_location_;
|
|
561
|
+
jsoncons::optional<T> exclusive_minimum_;
|
|
562
|
+
std::string absolute_exclusive_minimum_location_;
|
|
563
|
+
jsoncons::optional<double> multiple_of_;
|
|
564
|
+
std::string absolute_multiple_of_location_;
|
|
565
|
+
|
|
566
|
+
public:
|
|
567
|
+
numeric_validator_base(const Json& sch,
|
|
568
|
+
const std::vector<schema_location>& uris,
|
|
569
|
+
std::set<std::string>& keywords)
|
|
570
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""),
|
|
571
|
+
maximum_(), minimum_(),exclusive_maximum_(), exclusive_minimum_(), multiple_of_()
|
|
572
|
+
{
|
|
573
|
+
auto it = sch.find("maximum");
|
|
574
|
+
if (it != sch.object_range().end())
|
|
575
|
+
{
|
|
576
|
+
maximum_ = get_number<T>(it->value(), "maximum");
|
|
577
|
+
absolute_maximum_location_ = make_absolute_keyword_location(uris,"maximum");
|
|
578
|
+
keywords.insert("maximum");
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
it = sch.find("minimum");
|
|
582
|
+
if (it != sch.object_range().end())
|
|
583
|
+
{
|
|
584
|
+
minimum_ = get_number<T>(it->value(), "minimum");
|
|
585
|
+
absolute_minimum_location_ = make_absolute_keyword_location(uris,"minimum");
|
|
586
|
+
keywords.insert("minimum");
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
it = sch.find("exclusiveMaximum");
|
|
590
|
+
if (it != sch.object_range().end())
|
|
591
|
+
{
|
|
592
|
+
exclusive_maximum_ = get_number<T>(it->value(), "exclusiveMaximum");
|
|
593
|
+
absolute_exclusive_maximum_location_ = make_absolute_keyword_location(uris,"exclusiveMaximum");
|
|
594
|
+
keywords.insert("exclusiveMaximum");
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
it = sch.find("exclusiveMinimum");
|
|
598
|
+
if (it != sch.object_range().end())
|
|
599
|
+
{
|
|
600
|
+
exclusive_minimum_ = get_number<T>(it->value(), "exclusiveMinimum");
|
|
601
|
+
absolute_exclusive_minimum_location_ = make_absolute_keyword_location(uris,"exclusiveMinimum");
|
|
602
|
+
keywords.insert("exclusiveMinimum");
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
it = sch.find("multipleOf");
|
|
606
|
+
if (it != sch.object_range().end())
|
|
607
|
+
{
|
|
608
|
+
multiple_of_ = get_number<double>(it->value(), "multipleOf");
|
|
609
|
+
absolute_multiple_of_location_ = make_absolute_keyword_location(uris,"multipleOf");
|
|
610
|
+
keywords.insert("multipleOf");
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
protected:
|
|
615
|
+
|
|
616
|
+
void apply_kewords(T value,
|
|
617
|
+
const jsonpointer::json_pointer& instance_location,
|
|
618
|
+
const Json& instance,
|
|
619
|
+
error_reporter& reporter) const
|
|
620
|
+
{
|
|
621
|
+
if (multiple_of_ && value != 0) // exclude zero
|
|
622
|
+
{
|
|
623
|
+
if (!is_multiple_of(value, *multiple_of_))
|
|
624
|
+
{
|
|
625
|
+
reporter.error(validation_output("multipleOf",
|
|
626
|
+
absolute_multiple_of_location_,
|
|
627
|
+
instance_location.to_uri_fragment(),
|
|
628
|
+
instance.template as<std::string>() + " is not a multiple of " + std::to_string(*multiple_of_)));
|
|
629
|
+
if (reporter.fail_early())
|
|
630
|
+
{
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
if (maximum_)
|
|
637
|
+
{
|
|
638
|
+
if (value > *maximum_)
|
|
639
|
+
{
|
|
640
|
+
reporter.error(validation_output("maximum",
|
|
641
|
+
absolute_maximum_location_,
|
|
642
|
+
instance_location.to_uri_fragment(),
|
|
643
|
+
instance.template as<std::string>() + " exceeds maximum of " + std::to_string(*maximum_)));
|
|
644
|
+
if (reporter.fail_early())
|
|
645
|
+
{
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
if (minimum_)
|
|
652
|
+
{
|
|
653
|
+
if (value < *minimum_)
|
|
654
|
+
{
|
|
655
|
+
reporter.error(validation_output("minimum",
|
|
656
|
+
absolute_minimum_location_,
|
|
657
|
+
instance_location.to_uri_fragment(),
|
|
658
|
+
instance.template as<std::string>() + " is below minimum of " + std::to_string(*minimum_)));
|
|
659
|
+
if (reporter.fail_early())
|
|
660
|
+
{
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
if (exclusive_maximum_)
|
|
667
|
+
{
|
|
668
|
+
if (value >= *exclusive_maximum_)
|
|
669
|
+
{
|
|
670
|
+
reporter.error(validation_output("exclusiveMaximum",
|
|
671
|
+
absolute_exclusive_maximum_location_,
|
|
672
|
+
instance_location.to_uri_fragment(),
|
|
673
|
+
instance.template as<std::string>() + " exceeds maximum of " + std::to_string(*exclusive_maximum_)));
|
|
674
|
+
if (reporter.fail_early())
|
|
675
|
+
{
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
if (exclusive_minimum_)
|
|
682
|
+
{
|
|
683
|
+
if (value <= *exclusive_minimum_)
|
|
684
|
+
{
|
|
685
|
+
reporter.error(validation_output("exclusiveMinimum",
|
|
686
|
+
absolute_exclusive_minimum_location_,
|
|
687
|
+
instance_location.to_uri_fragment(),
|
|
688
|
+
instance.template as<std::string>() + " is below minimum of " + std::to_string(*exclusive_minimum_)));
|
|
689
|
+
if (reporter.fail_early())
|
|
690
|
+
{
|
|
691
|
+
return;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
private:
|
|
697
|
+
static bool is_multiple_of(T x, double multiple_of)
|
|
698
|
+
{
|
|
699
|
+
double rem = std::remainder(x, multiple_of);
|
|
700
|
+
double eps = std::nextafter(x, 0) - x;
|
|
701
|
+
return std::fabs(rem) < std::fabs(eps);
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
|
|
705
|
+
template <class Json>
|
|
706
|
+
class integer_validator : public numeric_validator_base<Json,int64_t>
|
|
707
|
+
{
|
|
708
|
+
public:
|
|
709
|
+
integer_validator(const Json& sch,
|
|
710
|
+
const std::vector<schema_location>& uris,
|
|
711
|
+
std::set<std::string>& keywords)
|
|
712
|
+
: numeric_validator_base<Json, int64_t>(sch, uris, keywords)
|
|
713
|
+
{
|
|
714
|
+
}
|
|
715
|
+
private:
|
|
716
|
+
void do_validate(const Json& instance,
|
|
717
|
+
const jsonpointer::json_pointer& instance_location,
|
|
718
|
+
error_reporter& reporter,
|
|
719
|
+
Json&) const
|
|
720
|
+
{
|
|
721
|
+
if (!(instance.template is_integer<int64_t>() || (instance.is_double() && static_cast<double>(instance.template as<int64_t>()) == instance.template as<double>())))
|
|
722
|
+
{
|
|
723
|
+
reporter.error(validation_output("integer",
|
|
724
|
+
this->absolute_keyword_location(),
|
|
725
|
+
instance_location.to_uri_fragment(),
|
|
726
|
+
"Instance is not an integer"));
|
|
727
|
+
if (reporter.fail_early())
|
|
728
|
+
{
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
int64_t value = instance.template as<int64_t>();
|
|
733
|
+
this->apply_kewords(value, instance_location, instance, reporter);
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
|
|
737
|
+
template <class Json>
|
|
738
|
+
class number_validator : public numeric_validator_base<Json,double>
|
|
739
|
+
{
|
|
740
|
+
public:
|
|
741
|
+
number_validator(const Json& sch,
|
|
742
|
+
const std::vector<schema_location>& uris,
|
|
743
|
+
std::set<std::string>& keywords)
|
|
744
|
+
: numeric_validator_base<Json, double>(sch, uris, keywords)
|
|
745
|
+
{
|
|
746
|
+
}
|
|
747
|
+
private:
|
|
748
|
+
void do_validate(const Json& instance,
|
|
749
|
+
const jsonpointer::json_pointer& instance_location,
|
|
750
|
+
error_reporter& reporter,
|
|
751
|
+
Json&) const
|
|
752
|
+
{
|
|
753
|
+
if (!(instance.template is_integer<int64_t>() || instance.is_double()))
|
|
754
|
+
{
|
|
755
|
+
reporter.error(validation_output("number",
|
|
756
|
+
this->absolute_keyword_location(),
|
|
757
|
+
instance_location.to_uri_fragment(),
|
|
758
|
+
"Instance is not a number"));
|
|
759
|
+
if (reporter.fail_early())
|
|
760
|
+
{
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
double value = instance.template as<double>();
|
|
765
|
+
this->apply_kewords(value, instance_location, instance, reporter);
|
|
766
|
+
}
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
// null_validator
|
|
770
|
+
|
|
771
|
+
template <class Json>
|
|
772
|
+
class null_validator : public keyword_validator<Json>
|
|
773
|
+
{
|
|
774
|
+
public:
|
|
775
|
+
null_validator(const std::vector<schema_location>& uris)
|
|
776
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : "")
|
|
777
|
+
{
|
|
778
|
+
}
|
|
779
|
+
private:
|
|
780
|
+
void do_validate(const Json& instance,
|
|
781
|
+
const jsonpointer::json_pointer& instance_location,
|
|
782
|
+
error_reporter& reporter,
|
|
783
|
+
Json&) const override
|
|
784
|
+
{
|
|
785
|
+
if (!instance.is_null())
|
|
786
|
+
{
|
|
787
|
+
reporter.error(validation_output("null",
|
|
788
|
+
this->absolute_keyword_location(),
|
|
789
|
+
instance_location.to_uri_fragment(),
|
|
790
|
+
"Expected to be null"));
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
};
|
|
794
|
+
|
|
795
|
+
template <class Json>
|
|
796
|
+
class boolean_validator : public keyword_validator<Json>
|
|
797
|
+
{
|
|
798
|
+
public:
|
|
799
|
+
boolean_validator(const std::vector<schema_location>& uris)
|
|
800
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : "")
|
|
801
|
+
{
|
|
802
|
+
}
|
|
803
|
+
private:
|
|
804
|
+
void do_validate(const Json&,
|
|
805
|
+
const jsonpointer::json_pointer&,
|
|
806
|
+
error_reporter&,
|
|
807
|
+
Json&) const override
|
|
808
|
+
{
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
};
|
|
812
|
+
|
|
813
|
+
template <class Json>
|
|
814
|
+
class true_validator : public keyword_validator<Json>
|
|
815
|
+
{
|
|
816
|
+
public:
|
|
817
|
+
true_validator(const std::vector<schema_location>& uris)
|
|
818
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : "")
|
|
819
|
+
{
|
|
820
|
+
}
|
|
821
|
+
private:
|
|
822
|
+
void do_validate(const Json&,
|
|
823
|
+
const jsonpointer::json_pointer&,
|
|
824
|
+
error_reporter&,
|
|
825
|
+
Json&) const override
|
|
826
|
+
{
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
template <class Json>
|
|
831
|
+
class false_validator : public keyword_validator<Json>
|
|
832
|
+
{
|
|
833
|
+
public:
|
|
834
|
+
false_validator(const std::vector<schema_location>& uris)
|
|
835
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : "")
|
|
836
|
+
{
|
|
837
|
+
}
|
|
838
|
+
private:
|
|
839
|
+
void do_validate(const Json&,
|
|
840
|
+
const jsonpointer::json_pointer& instance_location,
|
|
841
|
+
error_reporter& reporter,
|
|
842
|
+
Json&) const override
|
|
843
|
+
{
|
|
844
|
+
reporter.error(validation_output("false",
|
|
845
|
+
this->absolute_keyword_location(),
|
|
846
|
+
instance_location.to_uri_fragment(),
|
|
847
|
+
"False schema always fails"));
|
|
848
|
+
}
|
|
849
|
+
};
|
|
850
|
+
|
|
851
|
+
template <class Json>
|
|
852
|
+
class required_validator : public keyword_validator<Json>
|
|
853
|
+
{
|
|
854
|
+
using validator_pointer = typename keyword_validator<Json>::self_pointer;
|
|
855
|
+
|
|
856
|
+
std::vector<std::string> items_;
|
|
857
|
+
|
|
858
|
+
public:
|
|
859
|
+
required_validator(const std::vector<schema_location>& uris,
|
|
860
|
+
const std::vector<std::string>& items)
|
|
861
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""), items_(items) {}
|
|
862
|
+
required_validator(const std::string& absolute_keyword_location, const std::vector<std::string>& items)
|
|
863
|
+
: keyword_validator<Json>(absolute_keyword_location), items_(items) {}
|
|
864
|
+
|
|
865
|
+
required_validator(const required_validator&) = delete;
|
|
866
|
+
required_validator(required_validator&&) = default;
|
|
867
|
+
required_validator& operator=(const required_validator&) = delete;
|
|
868
|
+
required_validator& operator=(required_validator&&) = default;
|
|
869
|
+
private:
|
|
870
|
+
|
|
871
|
+
void do_validate(const Json& instance,
|
|
872
|
+
const jsonpointer::json_pointer& instance_location,
|
|
873
|
+
error_reporter& reporter,
|
|
874
|
+
Json&) const override final
|
|
875
|
+
{
|
|
876
|
+
for (const auto& key : items_)
|
|
877
|
+
{
|
|
878
|
+
if (instance.find(key) == instance.object_range().end())
|
|
879
|
+
{
|
|
880
|
+
reporter.error(validation_output("required",
|
|
881
|
+
this->absolute_keyword_location(),
|
|
882
|
+
instance_location.to_uri_fragment(),
|
|
883
|
+
"Required property \"" + key + "\" not found"));
|
|
884
|
+
if (reporter.fail_early())
|
|
885
|
+
{
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
};
|
|
892
|
+
|
|
893
|
+
template <class Json>
|
|
894
|
+
class object_validator : public keyword_validator<Json>
|
|
895
|
+
{
|
|
896
|
+
using validator_pointer = typename keyword_validator<Json>::self_pointer;
|
|
897
|
+
|
|
898
|
+
jsoncons::optional<std::size_t> max_properties_;
|
|
899
|
+
std::string absolute_max_properties_location_;
|
|
900
|
+
jsoncons::optional<std::size_t> min_properties_;
|
|
901
|
+
std::string absolute_min_properties_location_;
|
|
902
|
+
jsoncons::optional<required_validator<Json>> required_;
|
|
903
|
+
|
|
904
|
+
std::map<std::string, validator_pointer> properties_;
|
|
905
|
+
#if defined(JSONCONS_HAS_STD_REGEX)
|
|
906
|
+
std::vector<std::pair<std::regex, validator_pointer>> pattern_properties_;
|
|
907
|
+
#endif
|
|
908
|
+
validator_pointer additional_properties_;
|
|
909
|
+
|
|
910
|
+
std::map<std::string, validator_pointer> dependencies_;
|
|
911
|
+
|
|
912
|
+
validator_pointer property_name_validator_;
|
|
913
|
+
|
|
914
|
+
public:
|
|
915
|
+
object_validator(abstract_keyword_validator_factory<Json>* builder,
|
|
916
|
+
const Json& sch,
|
|
917
|
+
const std::vector<schema_location>& uris)
|
|
918
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""),
|
|
919
|
+
max_properties_(), min_properties_(),
|
|
920
|
+
additional_properties_(nullptr),
|
|
921
|
+
property_name_validator_(nullptr)
|
|
922
|
+
{
|
|
923
|
+
auto it = sch.find("maxProperties");
|
|
924
|
+
if (it != sch.object_range().end())
|
|
925
|
+
{
|
|
926
|
+
max_properties_ = it->value().template as<std::size_t>();
|
|
927
|
+
absolute_max_properties_location_ = make_absolute_keyword_location(uris, "maxProperties");
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
it = sch.find("minProperties");
|
|
931
|
+
if (it != sch.object_range().end())
|
|
932
|
+
{
|
|
933
|
+
min_properties_ = it->value().template as<std::size_t>();
|
|
934
|
+
absolute_min_properties_location_ = make_absolute_keyword_location(uris, "minProperties");
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
it = sch.find("required");
|
|
938
|
+
if (it != sch.object_range().end())
|
|
939
|
+
{
|
|
940
|
+
auto location = make_absolute_keyword_location(uris, "required");
|
|
941
|
+
required_ = required_validator<Json>(location,
|
|
942
|
+
it->value().template as<std::vector<std::string>>());
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
it = sch.find("properties");
|
|
946
|
+
if (it != sch.object_range().end())
|
|
947
|
+
{
|
|
948
|
+
for (const auto& prop : it->value().object_range())
|
|
949
|
+
properties_.emplace(
|
|
950
|
+
std::make_pair(
|
|
951
|
+
prop.key(),
|
|
952
|
+
builder->make_keyword_validator(prop.value(), uris, {"properties", prop.key()})));
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
#if defined(JSONCONS_HAS_STD_REGEX)
|
|
956
|
+
it = sch.find("patternProperties");
|
|
957
|
+
if (it != sch.object_range().end())
|
|
958
|
+
{
|
|
959
|
+
for (const auto& prop : it->value().object_range())
|
|
960
|
+
pattern_properties_.emplace_back(
|
|
961
|
+
std::make_pair(
|
|
962
|
+
std::regex(prop.key(), std::regex::ECMAScript),
|
|
963
|
+
builder->make_keyword_validator(prop.value(), uris, {prop.key()})));
|
|
964
|
+
}
|
|
965
|
+
#endif
|
|
966
|
+
|
|
967
|
+
it = sch.find("additionalProperties");
|
|
968
|
+
if (it != sch.object_range().end())
|
|
969
|
+
{
|
|
970
|
+
additional_properties_ = builder->make_keyword_validator(it->value(), uris, {"additionalProperties"});
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
it = sch.find("dependencies");
|
|
974
|
+
if (it != sch.object_range().end())
|
|
975
|
+
{
|
|
976
|
+
for (const auto& dep : it->value().object_range())
|
|
977
|
+
{
|
|
978
|
+
switch (dep.value().type())
|
|
979
|
+
{
|
|
980
|
+
case json_type::array_value:
|
|
981
|
+
{
|
|
982
|
+
auto location = make_absolute_keyword_location(uris, "dependencies");
|
|
983
|
+
dependencies_.emplace(dep.key(),
|
|
984
|
+
builder->make_required_validator({location},
|
|
985
|
+
dep.value().template as<std::vector<std::string>>()));
|
|
986
|
+
break;
|
|
987
|
+
}
|
|
988
|
+
default:
|
|
989
|
+
{
|
|
990
|
+
dependencies_.emplace(dep.key(),
|
|
991
|
+
builder->make_keyword_validator(dep.value(), uris, {"dependencies", dep.key()}));
|
|
992
|
+
break;
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
auto property_names_it = sch.find("propertyNames");
|
|
999
|
+
if (property_names_it != sch.object_range().end())
|
|
1000
|
+
{
|
|
1001
|
+
property_name_validator_ = builder->make_keyword_validator(property_names_it->value(), uris, {"propertyNames"});
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
private:
|
|
1005
|
+
|
|
1006
|
+
void do_validate(const Json& instance,
|
|
1007
|
+
const jsonpointer::json_pointer& instance_location,
|
|
1008
|
+
error_reporter& reporter,
|
|
1009
|
+
Json& patch) const override
|
|
1010
|
+
{
|
|
1011
|
+
if (max_properties_ && instance.size() > *max_properties_)
|
|
1012
|
+
{
|
|
1013
|
+
std::string message("Maximum properties: " + std::to_string(*max_properties_));
|
|
1014
|
+
message.append(", found: " + std::to_string(instance.size()));
|
|
1015
|
+
reporter.error(validation_output("maxProperties",
|
|
1016
|
+
absolute_max_properties_location_,
|
|
1017
|
+
instance_location.to_uri_fragment(),
|
|
1018
|
+
std::move(message)));
|
|
1019
|
+
if (reporter.fail_early())
|
|
1020
|
+
{
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
if (min_properties_ && instance.size() < *min_properties_)
|
|
1026
|
+
{
|
|
1027
|
+
std::string message("Minimum properties: " + std::to_string(*min_properties_));
|
|
1028
|
+
message.append(", found: " + std::to_string(instance.size()));
|
|
1029
|
+
reporter.error(validation_output("minProperties",
|
|
1030
|
+
absolute_min_properties_location_,
|
|
1031
|
+
instance_location.to_uri_fragment(),
|
|
1032
|
+
std::move(message)));
|
|
1033
|
+
if (reporter.fail_early())
|
|
1034
|
+
{
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
if (required_)
|
|
1040
|
+
required_->validate(instance, instance_location, reporter, patch);
|
|
1041
|
+
|
|
1042
|
+
for (const auto& property : instance.object_range())
|
|
1043
|
+
{
|
|
1044
|
+
if (property_name_validator_)
|
|
1045
|
+
property_name_validator_->validate(property.key(), instance_location, reporter, patch);
|
|
1046
|
+
|
|
1047
|
+
bool a_prop_or_pattern_matched = false;
|
|
1048
|
+
auto properties_it = properties_.find(property.key());
|
|
1049
|
+
|
|
1050
|
+
// check if it is in "properties"
|
|
1051
|
+
if (properties_it != properties_.end())
|
|
1052
|
+
{
|
|
1053
|
+
a_prop_or_pattern_matched = true;
|
|
1054
|
+
jsonpointer::json_pointer pointer(instance_location);
|
|
1055
|
+
pointer /= property.key();
|
|
1056
|
+
properties_it->second->validate(property.value(), pointer, reporter, patch);
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
#if defined(JSONCONS_HAS_STD_REGEX)
|
|
1060
|
+
|
|
1061
|
+
// check all matching "patternProperties"
|
|
1062
|
+
for (auto& schema_pp : pattern_properties_)
|
|
1063
|
+
if (std::regex_search(property.key(), schema_pp.first))
|
|
1064
|
+
{
|
|
1065
|
+
a_prop_or_pattern_matched = true;
|
|
1066
|
+
jsonpointer::json_pointer pointer(instance_location);
|
|
1067
|
+
pointer /= property.key();
|
|
1068
|
+
schema_pp.second->validate(property.value(), pointer, reporter, patch);
|
|
1069
|
+
}
|
|
1070
|
+
#endif
|
|
1071
|
+
|
|
1072
|
+
// finally, check "additionalProperties"
|
|
1073
|
+
if (!a_prop_or_pattern_matched && additional_properties_)
|
|
1074
|
+
{
|
|
1075
|
+
collecting_error_reporter local_reporter;
|
|
1076
|
+
|
|
1077
|
+
jsonpointer::json_pointer pointer(instance_location);
|
|
1078
|
+
pointer /= property.key();
|
|
1079
|
+
additional_properties_->validate(property.value(), pointer, local_reporter, patch);
|
|
1080
|
+
if (!local_reporter.errors.empty())
|
|
1081
|
+
{
|
|
1082
|
+
reporter.error(validation_output("additionalProperties",
|
|
1083
|
+
additional_properties_->absolute_keyword_location(),
|
|
1084
|
+
instance_location.to_uri_fragment(),
|
|
1085
|
+
"Additional property \"" + property.key() + "\" found but was invalid."));
|
|
1086
|
+
if (reporter.fail_early())
|
|
1087
|
+
{
|
|
1088
|
+
return;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
// reverse search
|
|
1095
|
+
for (auto const& prop : properties_)
|
|
1096
|
+
{
|
|
1097
|
+
const auto finding = instance.find(prop.first);
|
|
1098
|
+
if (finding == instance.object_range().end())
|
|
1099
|
+
{
|
|
1100
|
+
// If property is not in instance
|
|
1101
|
+
auto default_value = prop.second->get_default_value(instance_location, instance, reporter);
|
|
1102
|
+
if (default_value)
|
|
1103
|
+
{
|
|
1104
|
+
// If default value is available, update patch
|
|
1105
|
+
jsonpointer::json_pointer pointer(instance_location);
|
|
1106
|
+
pointer /= prop.first;
|
|
1107
|
+
|
|
1108
|
+
update_patch(patch, pointer, std::move(*default_value));
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
for (const auto& dep : dependencies_)
|
|
1114
|
+
{
|
|
1115
|
+
auto prop = instance.find(dep.first);
|
|
1116
|
+
if (prop != instance.object_range().end())
|
|
1117
|
+
{
|
|
1118
|
+
// if dependency-property is present in instance
|
|
1119
|
+
jsonpointer::json_pointer pointer(instance_location);
|
|
1120
|
+
pointer /= dep.first;
|
|
1121
|
+
dep.second->validate(instance, pointer, reporter, patch); // validate
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
void update_patch(Json& patch, const jsonpointer::json_pointer& instance_location, Json&& default_value) const
|
|
1127
|
+
{
|
|
1128
|
+
Json j;
|
|
1129
|
+
j.try_emplace("op", "add");
|
|
1130
|
+
j.try_emplace("path", instance_location.to_uri_fragment());
|
|
1131
|
+
j.try_emplace("value", std::forward<Json>(default_value));
|
|
1132
|
+
patch.push_back(std::move(j));
|
|
1133
|
+
}
|
|
1134
|
+
};
|
|
1135
|
+
|
|
1136
|
+
// array_validator
|
|
1137
|
+
|
|
1138
|
+
template <class Json>
|
|
1139
|
+
class array_validator : public keyword_validator<Json>
|
|
1140
|
+
{
|
|
1141
|
+
using validator_pointer = typename keyword_validator<Json>::self_pointer;
|
|
1142
|
+
|
|
1143
|
+
jsoncons::optional<std::size_t> max_items_;
|
|
1144
|
+
std::string absolute_max_items_location_;
|
|
1145
|
+
jsoncons::optional<std::size_t> min_items_;
|
|
1146
|
+
std::string absolute_min_items_location_;
|
|
1147
|
+
bool unique_items_ = false;
|
|
1148
|
+
validator_pointer items_validator_;
|
|
1149
|
+
std::vector<validator_pointer> item_validators_;
|
|
1150
|
+
validator_pointer additional_items_validator_;
|
|
1151
|
+
validator_pointer contains_validator_;
|
|
1152
|
+
|
|
1153
|
+
public:
|
|
1154
|
+
array_validator(abstract_keyword_validator_factory<Json>* builder,
|
|
1155
|
+
const Json& sch,
|
|
1156
|
+
const std::vector<schema_location>& uris)
|
|
1157
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""),
|
|
1158
|
+
max_items_(), min_items_(), items_validator_(nullptr), additional_items_validator_(nullptr), contains_validator_(nullptr)
|
|
1159
|
+
{
|
|
1160
|
+
{
|
|
1161
|
+
auto it = sch.find("maxItems");
|
|
1162
|
+
if (it != sch.object_range().end())
|
|
1163
|
+
{
|
|
1164
|
+
max_items_ = it->value().template as<std::size_t>();
|
|
1165
|
+
absolute_max_items_location_ = make_absolute_keyword_location(uris, "maxItems");
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
{
|
|
1170
|
+
auto it = sch.find("minItems");
|
|
1171
|
+
if (it != sch.object_range().end())
|
|
1172
|
+
{
|
|
1173
|
+
min_items_ = it->value().template as<std::size_t>();
|
|
1174
|
+
absolute_min_items_location_ = make_absolute_keyword_location(uris, "minItems");
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
{
|
|
1179
|
+
auto it = sch.find("uniqueItems");
|
|
1180
|
+
if (it != sch.object_range().end())
|
|
1181
|
+
{
|
|
1182
|
+
unique_items_ = it->value().template as<bool>();
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
{
|
|
1187
|
+
auto it = sch.find("items");
|
|
1188
|
+
if (it != sch.object_range().end())
|
|
1189
|
+
{
|
|
1190
|
+
|
|
1191
|
+
if (it->value().type() == json_type::array_value)
|
|
1192
|
+
{
|
|
1193
|
+
size_t c = 0;
|
|
1194
|
+
for (const auto& subsch : it->value().array_range())
|
|
1195
|
+
item_validators_.push_back(builder->make_keyword_validator(subsch, uris, {"items", std::to_string(c++)}));
|
|
1196
|
+
|
|
1197
|
+
auto attr_add = sch.find("additionalItems");
|
|
1198
|
+
if (attr_add != sch.object_range().end())
|
|
1199
|
+
{
|
|
1200
|
+
additional_items_validator_ = builder->make_keyword_validator(attr_add->value(), uris, {"additionalItems"});
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
}
|
|
1204
|
+
else if (it->value().type() == json_type::object_value ||
|
|
1205
|
+
it->value().type() == json_type::bool_value)
|
|
1206
|
+
{
|
|
1207
|
+
items_validator_ = builder->make_keyword_validator(it->value(), uris, {"items"});
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
{
|
|
1214
|
+
auto it = sch.find("contains");
|
|
1215
|
+
if (it != sch.object_range().end())
|
|
1216
|
+
{
|
|
1217
|
+
contains_validator_ = builder->make_keyword_validator(it->value(), uris, {"contains"});
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
private:
|
|
1222
|
+
|
|
1223
|
+
void do_validate(const Json& instance,
|
|
1224
|
+
const jsonpointer::json_pointer& instance_location,
|
|
1225
|
+
error_reporter& reporter,
|
|
1226
|
+
Json& patch) const override
|
|
1227
|
+
{
|
|
1228
|
+
if (max_items_)
|
|
1229
|
+
{
|
|
1230
|
+
if (instance.size() > *max_items_)
|
|
1231
|
+
{
|
|
1232
|
+
std::string message("Expected maximum item count: " + std::to_string(*max_items_));
|
|
1233
|
+
message.append(", found: " + std::to_string(instance.size()));
|
|
1234
|
+
reporter.error(validation_output("maxItems",
|
|
1235
|
+
absolute_max_items_location_,
|
|
1236
|
+
instance_location.to_uri_fragment(),
|
|
1237
|
+
std::move(message)));
|
|
1238
|
+
if (reporter.fail_early())
|
|
1239
|
+
{
|
|
1240
|
+
return;
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
if (min_items_)
|
|
1246
|
+
{
|
|
1247
|
+
if (instance.size() < *min_items_)
|
|
1248
|
+
{
|
|
1249
|
+
std::string message("Expected minimum item count: " + std::to_string(*min_items_));
|
|
1250
|
+
message.append(", found: " + std::to_string(instance.size()));
|
|
1251
|
+
reporter.error(validation_output("minItems",
|
|
1252
|
+
absolute_min_items_location_,
|
|
1253
|
+
instance_location.to_uri_fragment(),
|
|
1254
|
+
std::move(message)));
|
|
1255
|
+
if (reporter.fail_early())
|
|
1256
|
+
{
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
if (unique_items_)
|
|
1263
|
+
{
|
|
1264
|
+
if (!array_has_unique_items(instance))
|
|
1265
|
+
{
|
|
1266
|
+
reporter.error(validation_output("uniqueItems",
|
|
1267
|
+
this->absolute_keyword_location(),
|
|
1268
|
+
instance_location.to_uri_fragment(),
|
|
1269
|
+
"Array items are not unique"));
|
|
1270
|
+
if (reporter.fail_early())
|
|
1271
|
+
{
|
|
1272
|
+
return;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
size_t index = 0;
|
|
1278
|
+
if (items_validator_)
|
|
1279
|
+
{
|
|
1280
|
+
for (const auto& i : instance.array_range())
|
|
1281
|
+
{
|
|
1282
|
+
jsonpointer::json_pointer pointer(instance_location);
|
|
1283
|
+
pointer /= index;
|
|
1284
|
+
items_validator_->validate(i, pointer, reporter, patch);
|
|
1285
|
+
index++;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
else
|
|
1289
|
+
{
|
|
1290
|
+
auto validator_it = item_validators_.cbegin();
|
|
1291
|
+
for (const auto& item : instance.array_range())
|
|
1292
|
+
{
|
|
1293
|
+
validator_pointer item_validator = nullptr;
|
|
1294
|
+
if (validator_it != item_validators_.cend())
|
|
1295
|
+
{
|
|
1296
|
+
item_validator = *validator_it;
|
|
1297
|
+
++validator_it;
|
|
1298
|
+
}
|
|
1299
|
+
else if (additional_items_validator_ != nullptr)
|
|
1300
|
+
{
|
|
1301
|
+
item_validator = additional_items_validator_;
|
|
1302
|
+
}
|
|
1303
|
+
else
|
|
1304
|
+
break;
|
|
1305
|
+
|
|
1306
|
+
jsonpointer::json_pointer pointer(instance_location);
|
|
1307
|
+
pointer /= index;
|
|
1308
|
+
item_validator->validate(item, pointer, reporter, patch);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
if (contains_validator_)
|
|
1313
|
+
{
|
|
1314
|
+
bool contained = false;
|
|
1315
|
+
collecting_error_reporter local_reporter;
|
|
1316
|
+
for (const auto& item : instance.array_range())
|
|
1317
|
+
{
|
|
1318
|
+
std::size_t mark = local_reporter.errors.size();
|
|
1319
|
+
contains_validator_->validate(item, instance_location, local_reporter, patch);
|
|
1320
|
+
if (mark == local_reporter.errors.size())
|
|
1321
|
+
{
|
|
1322
|
+
contained = true;
|
|
1323
|
+
break;
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
if (!contained)
|
|
1327
|
+
{
|
|
1328
|
+
reporter.error(validation_output("contains",
|
|
1329
|
+
this->absolute_keyword_location(),
|
|
1330
|
+
instance_location.to_uri_fragment(),
|
|
1331
|
+
"Expected at least one array item to match \"contains\" schema",
|
|
1332
|
+
local_reporter.errors));
|
|
1333
|
+
if (reporter.fail_early())
|
|
1334
|
+
{
|
|
1335
|
+
return;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
static bool array_has_unique_items(const Json& a)
|
|
1342
|
+
{
|
|
1343
|
+
for (auto it = a.array_range().begin(); it != a.array_range().end(); ++it)
|
|
1344
|
+
{
|
|
1345
|
+
for (auto jt = it+1; jt != a.array_range().end(); ++jt)
|
|
1346
|
+
{
|
|
1347
|
+
if (*it == *jt)
|
|
1348
|
+
{
|
|
1349
|
+
return false; // contains duplicates
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
return true; // elements are unique
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
|
|
1357
|
+
template <class Json>
|
|
1358
|
+
class conditional_validator : public keyword_validator<Json>
|
|
1359
|
+
{
|
|
1360
|
+
using validator_pointer = typename keyword_validator<Json>::self_pointer;
|
|
1361
|
+
|
|
1362
|
+
validator_pointer if_validator_;
|
|
1363
|
+
validator_pointer then_validator_;
|
|
1364
|
+
validator_pointer else_validator_;
|
|
1365
|
+
|
|
1366
|
+
public:
|
|
1367
|
+
conditional_validator(abstract_keyword_validator_factory<Json>* builder,
|
|
1368
|
+
const Json& sch_if,
|
|
1369
|
+
const Json& sch,
|
|
1370
|
+
const std::vector<schema_location>& uris)
|
|
1371
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""), if_validator_(nullptr), then_validator_(nullptr), else_validator_(nullptr)
|
|
1372
|
+
{
|
|
1373
|
+
auto then_it = sch.find("then");
|
|
1374
|
+
auto else_it = sch.find("else");
|
|
1375
|
+
|
|
1376
|
+
if (then_it != sch.object_range().end() || else_it != sch.object_range().end())
|
|
1377
|
+
{
|
|
1378
|
+
if_validator_ = builder->make_keyword_validator(sch_if, uris, {"if"});
|
|
1379
|
+
|
|
1380
|
+
if (then_it != sch.object_range().end())
|
|
1381
|
+
{
|
|
1382
|
+
then_validator_ = builder->make_keyword_validator(then_it->value(), uris, {"then"});
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
if (else_it != sch.object_range().end())
|
|
1386
|
+
{
|
|
1387
|
+
else_validator_ = builder->make_keyword_validator(else_it->value(), uris, {"else"});
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
}
|
|
1391
|
+
private:
|
|
1392
|
+
void do_validate(const Json& instance,
|
|
1393
|
+
const jsonpointer::json_pointer& instance_location,
|
|
1394
|
+
error_reporter& reporter,
|
|
1395
|
+
Json& patch) const final
|
|
1396
|
+
{
|
|
1397
|
+
if (if_validator_)
|
|
1398
|
+
{
|
|
1399
|
+
collecting_error_reporter local_reporter;
|
|
1400
|
+
|
|
1401
|
+
if_validator_->validate(instance, instance_location, local_reporter, patch);
|
|
1402
|
+
if (local_reporter.errors.empty())
|
|
1403
|
+
{
|
|
1404
|
+
if (then_validator_)
|
|
1405
|
+
then_validator_->validate(instance, instance_location, reporter, patch);
|
|
1406
|
+
}
|
|
1407
|
+
else
|
|
1408
|
+
{
|
|
1409
|
+
if (else_validator_)
|
|
1410
|
+
else_validator_->validate(instance, instance_location, reporter, patch);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
};
|
|
1415
|
+
|
|
1416
|
+
// enum_validator
|
|
1417
|
+
|
|
1418
|
+
template <class Json>
|
|
1419
|
+
class enum_validator : public keyword_validator<Json>
|
|
1420
|
+
{
|
|
1421
|
+
Json enum_validator_;
|
|
1422
|
+
|
|
1423
|
+
public:
|
|
1424
|
+
enum_validator(const Json& sch,
|
|
1425
|
+
const std::vector<schema_location>& uris)
|
|
1426
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""), enum_validator_(sch)
|
|
1427
|
+
{
|
|
1428
|
+
}
|
|
1429
|
+
private:
|
|
1430
|
+
void do_validate(const Json& instance,
|
|
1431
|
+
const jsonpointer::json_pointer& instance_location,
|
|
1432
|
+
error_reporter& reporter,
|
|
1433
|
+
Json&) const final
|
|
1434
|
+
{
|
|
1435
|
+
bool in_range = false;
|
|
1436
|
+
for (const auto& item : enum_validator_.array_range())
|
|
1437
|
+
{
|
|
1438
|
+
if (item == instance)
|
|
1439
|
+
{
|
|
1440
|
+
in_range = true;
|
|
1441
|
+
break;
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
if (!in_range)
|
|
1446
|
+
{
|
|
1447
|
+
reporter.error(validation_output("enum",
|
|
1448
|
+
this->absolute_keyword_location(),
|
|
1449
|
+
instance_location.to_uri_fragment(),
|
|
1450
|
+
instance.template as<std::string>() + " is not a valid enum value"));
|
|
1451
|
+
if (reporter.fail_early())
|
|
1452
|
+
{
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
};
|
|
1458
|
+
|
|
1459
|
+
// const_keyword
|
|
1460
|
+
|
|
1461
|
+
template <class Json>
|
|
1462
|
+
class const_keyword : public keyword_validator<Json>
|
|
1463
|
+
{
|
|
1464
|
+
Json const_validator_;
|
|
1465
|
+
|
|
1466
|
+
public:
|
|
1467
|
+
const_keyword(const Json& sch, const std::vector<schema_location>& uris)
|
|
1468
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""), const_validator_(sch)
|
|
1469
|
+
{
|
|
1470
|
+
}
|
|
1471
|
+
private:
|
|
1472
|
+
void do_validate(const Json& instance,
|
|
1473
|
+
const jsonpointer::json_pointer& instance_location,
|
|
1474
|
+
error_reporter& reporter,
|
|
1475
|
+
Json&) const final
|
|
1476
|
+
{
|
|
1477
|
+
if (const_validator_ != instance)
|
|
1478
|
+
reporter.error(validation_output("const",
|
|
1479
|
+
this->absolute_keyword_location(),
|
|
1480
|
+
instance_location.to_uri_fragment(),
|
|
1481
|
+
"Instance is not const"));
|
|
1482
|
+
}
|
|
1483
|
+
};
|
|
1484
|
+
|
|
1485
|
+
template <class Json>
|
|
1486
|
+
class type_validator : public keyword_validator<Json>
|
|
1487
|
+
{
|
|
1488
|
+
using validator_pointer = typename keyword_validator<Json>::self_pointer;
|
|
1489
|
+
|
|
1490
|
+
Json default_value_;
|
|
1491
|
+
std::vector<validator_pointer> type_mapping_;
|
|
1492
|
+
jsoncons::optional<enum_validator<Json>> enum_validator_;
|
|
1493
|
+
jsoncons::optional<const_keyword<Json>> const_validator_;
|
|
1494
|
+
std::vector<validator_pointer> combined_validators_;
|
|
1495
|
+
jsoncons::optional<conditional_validator<Json>> conditional_validator_;
|
|
1496
|
+
std::vector<std::string> expected_types_;
|
|
1497
|
+
|
|
1498
|
+
public:
|
|
1499
|
+
type_validator(const type_validator&) = delete;
|
|
1500
|
+
type_validator& operator=(const type_validator&) = delete;
|
|
1501
|
+
type_validator(type_validator&&) = default;
|
|
1502
|
+
type_validator& operator=(type_validator&&) = default;
|
|
1503
|
+
|
|
1504
|
+
type_validator(abstract_keyword_validator_factory<Json>* builder,
|
|
1505
|
+
const Json& sch,
|
|
1506
|
+
const std::vector<schema_location>& uris)
|
|
1507
|
+
: keyword_validator<Json>((!uris.empty() && uris.back().is_absolute()) ? uris.back().string() : ""), default_value_(jsoncons::null_type()),
|
|
1508
|
+
type_mapping_((uint8_t)(json_type::object_value)+1),
|
|
1509
|
+
enum_validator_(), const_validator_()
|
|
1510
|
+
{
|
|
1511
|
+
//std::cout << uris.size() << " uris: ";
|
|
1512
|
+
//for (const auto& uri : uris)
|
|
1513
|
+
//{
|
|
1514
|
+
// std::cout << uri.string() << ", ";
|
|
1515
|
+
//}
|
|
1516
|
+
//std::cout << "\n";
|
|
1517
|
+
std::set<std::string> known_keywords;
|
|
1518
|
+
|
|
1519
|
+
auto it = sch.find("type");
|
|
1520
|
+
if (it == sch.object_range().end())
|
|
1521
|
+
{
|
|
1522
|
+
initialize_type_mapping(builder, "", sch, uris, known_keywords);
|
|
1523
|
+
}
|
|
1524
|
+
else
|
|
1525
|
+
{
|
|
1526
|
+
switch (it->value().type())
|
|
1527
|
+
{
|
|
1528
|
+
case json_type::string_value:
|
|
1529
|
+
{
|
|
1530
|
+
auto type = it->value().template as<std::string>();
|
|
1531
|
+
initialize_type_mapping(builder, type, sch, uris, known_keywords);
|
|
1532
|
+
expected_types_.emplace_back(std::move(type));
|
|
1533
|
+
break;
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
case json_type::array_value: // "type": ["type1", "type2"]
|
|
1537
|
+
{
|
|
1538
|
+
for (const auto& item : it->value().array_range())
|
|
1539
|
+
{
|
|
1540
|
+
auto type = item.template as<std::string>();
|
|
1541
|
+
initialize_type_mapping(builder, type, sch, uris, known_keywords);
|
|
1542
|
+
expected_types_.emplace_back(std::move(type));
|
|
1543
|
+
}
|
|
1544
|
+
break;
|
|
1545
|
+
}
|
|
1546
|
+
default:
|
|
1547
|
+
break;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
const auto default_it = sch.find("default");
|
|
1552
|
+
if (default_it != sch.object_range().end())
|
|
1553
|
+
{
|
|
1554
|
+
default_value_ = default_it->value();
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
it = sch.find("enum");
|
|
1558
|
+
if (it != sch.object_range().end())
|
|
1559
|
+
{
|
|
1560
|
+
enum_validator_ = enum_validator<Json >(it->value(), uris);
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
it = sch.find("const");
|
|
1564
|
+
if (it != sch.object_range().end())
|
|
1565
|
+
{
|
|
1566
|
+
const_validator_ = const_keyword<Json>(it->value(), uris);
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
it = sch.find("not");
|
|
1570
|
+
if (it != sch.object_range().end())
|
|
1571
|
+
{
|
|
1572
|
+
combined_validators_.push_back(builder->make_not_validator(it->value(), uris));
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
it = sch.find("allOf");
|
|
1576
|
+
if (it != sch.object_range().end())
|
|
1577
|
+
{
|
|
1578
|
+
combined_validators_.push_back(builder->make_all_of_validator(it->value(), uris));
|
|
1579
|
+
}
|
|
1580
|
+
|
|
1581
|
+
it = sch.find("anyOf");
|
|
1582
|
+
if (it != sch.object_range().end())
|
|
1583
|
+
{
|
|
1584
|
+
combined_validators_.push_back(builder->make_any_of_validator(it->value(), uris));
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
it = sch.find("oneOf");
|
|
1588
|
+
if (it != sch.object_range().end())
|
|
1589
|
+
{
|
|
1590
|
+
combined_validators_.push_back(builder->make_one_of_validator(it->value(), uris));
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
it = sch.find("if");
|
|
1594
|
+
if (it != sch.object_range().end())
|
|
1595
|
+
{
|
|
1596
|
+
conditional_validator_ = conditional_validator<Json>(builder, it->value(), sch, uris);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
private:
|
|
1600
|
+
|
|
1601
|
+
void do_validate(const Json& instance,
|
|
1602
|
+
const jsonpointer::json_pointer& instance_location,
|
|
1603
|
+
error_reporter& reporter,
|
|
1604
|
+
Json& patch) const override final
|
|
1605
|
+
{
|
|
1606
|
+
auto type = type_mapping_[(uint8_t) instance.type()];
|
|
1607
|
+
|
|
1608
|
+
if (type)
|
|
1609
|
+
type->validate(instance, instance_location, reporter, patch);
|
|
1610
|
+
else
|
|
1611
|
+
{
|
|
1612
|
+
std::ostringstream ss;
|
|
1613
|
+
ss << "Expected ";
|
|
1614
|
+
for (std::size_t i = 0; i < expected_types_.size(); ++i)
|
|
1615
|
+
{
|
|
1616
|
+
if (i > 0)
|
|
1617
|
+
{
|
|
1618
|
+
ss << ", ";
|
|
1619
|
+
if (i+1 == expected_types_.size())
|
|
1620
|
+
{
|
|
1621
|
+
ss << "or ";
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
ss << expected_types_[i];
|
|
1625
|
+
}
|
|
1626
|
+
ss << ", found " << instance.type();
|
|
1627
|
+
|
|
1628
|
+
reporter.error(validation_output("type",
|
|
1629
|
+
this->absolute_keyword_location(),
|
|
1630
|
+
instance_location.to_uri_fragment(),
|
|
1631
|
+
ss.str()));
|
|
1632
|
+
if (reporter.fail_early())
|
|
1633
|
+
{
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
if (enum_validator_)
|
|
1639
|
+
{
|
|
1640
|
+
enum_validator_->validate(instance, instance_location, reporter, patch);
|
|
1641
|
+
if (reporter.error_count() > 0 && reporter.fail_early())
|
|
1642
|
+
{
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
if (const_validator_)
|
|
1648
|
+
{
|
|
1649
|
+
const_validator_->validate(instance, instance_location, reporter, patch);
|
|
1650
|
+
if (reporter.error_count() > 0 && reporter.fail_early())
|
|
1651
|
+
{
|
|
1652
|
+
return;
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
for (const auto& validator : combined_validators_)
|
|
1657
|
+
{
|
|
1658
|
+
validator->validate(instance, instance_location, reporter, patch);
|
|
1659
|
+
if (reporter.error_count() > 0 && reporter.fail_early())
|
|
1660
|
+
{
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
|
|
1666
|
+
if (conditional_validator_)
|
|
1667
|
+
{
|
|
1668
|
+
conditional_validator_->validate(instance, instance_location, reporter, patch);
|
|
1669
|
+
if (reporter.error_count() > 0 && reporter.fail_early())
|
|
1670
|
+
{
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
jsoncons::optional<Json> get_default_value(const jsonpointer::json_pointer&,
|
|
1677
|
+
const Json&,
|
|
1678
|
+
error_reporter&) const override
|
|
1679
|
+
{
|
|
1680
|
+
return default_value_;
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
void initialize_type_mapping(abstract_keyword_validator_factory<Json>* builder,
|
|
1684
|
+
const std::string& type,
|
|
1685
|
+
const Json& sch,
|
|
1686
|
+
const std::vector<schema_location>& uris,
|
|
1687
|
+
std::set<std::string>& keywords)
|
|
1688
|
+
{
|
|
1689
|
+
if (type == "null")
|
|
1690
|
+
{
|
|
1691
|
+
type_mapping_[(uint8_t)json_type::null_value] = builder->make_null_validator(uris);
|
|
1692
|
+
}
|
|
1693
|
+
else if (type == "object")
|
|
1694
|
+
{
|
|
1695
|
+
type_mapping_[(uint8_t)json_type::object_value] = builder->make_object_validator(sch, uris);
|
|
1696
|
+
}
|
|
1697
|
+
else if (type == "array")
|
|
1698
|
+
{
|
|
1699
|
+
type_mapping_[(uint8_t)json_type::array_value] = builder->make_array_validator(sch, uris);
|
|
1700
|
+
}
|
|
1701
|
+
else if (type == "string")
|
|
1702
|
+
{
|
|
1703
|
+
type_mapping_[(uint8_t)json_type::string_value] = builder->make_string_validator(sch, uris);
|
|
1704
|
+
// For binary types
|
|
1705
|
+
type_mapping_[(uint8_t) json_type::byte_string_value] = type_mapping_[(uint8_t) json_type::string_value];
|
|
1706
|
+
}
|
|
1707
|
+
else if (type == "boolean")
|
|
1708
|
+
{
|
|
1709
|
+
type_mapping_[(uint8_t)json_type::bool_value] = builder->make_boolean_validator(uris);
|
|
1710
|
+
}
|
|
1711
|
+
else if (type == "integer")
|
|
1712
|
+
{
|
|
1713
|
+
type_mapping_[(uint8_t)json_type::int64_value] = builder->make_integer_validator(sch, uris, keywords);
|
|
1714
|
+
type_mapping_[(uint8_t)json_type::uint64_value] = type_mapping_[(uint8_t)json_type::int64_value];
|
|
1715
|
+
type_mapping_[(uint8_t)json_type::double_value] = type_mapping_[(uint8_t)json_type::int64_value];
|
|
1716
|
+
}
|
|
1717
|
+
else if (type == "number")
|
|
1718
|
+
{
|
|
1719
|
+
type_mapping_[(uint8_t)json_type::double_value] = builder->make_number_validator(sch, uris, keywords);
|
|
1720
|
+
type_mapping_[(uint8_t)json_type::int64_value] = type_mapping_[(uint8_t)json_type::double_value];
|
|
1721
|
+
type_mapping_[(uint8_t)json_type::uint64_value] = type_mapping_[(uint8_t)json_type::double_value];
|
|
1722
|
+
}
|
|
1723
|
+
else if (type.empty())
|
|
1724
|
+
{
|
|
1725
|
+
type_mapping_[(uint8_t)json_type::null_value] = builder->make_null_validator(uris);
|
|
1726
|
+
type_mapping_[(uint8_t)json_type::object_value] = builder->make_object_validator(sch, uris);
|
|
1727
|
+
type_mapping_[(uint8_t)json_type::array_value] = builder->make_array_validator(sch, uris);
|
|
1728
|
+
type_mapping_[(uint8_t)json_type::string_value] = builder->make_string_validator(sch, uris);
|
|
1729
|
+
// For binary types
|
|
1730
|
+
type_mapping_[(uint8_t) json_type::byte_string_value] = type_mapping_[(uint8_t) json_type::string_value];
|
|
1731
|
+
type_mapping_[(uint8_t)json_type::bool_value] = builder->make_boolean_validator(uris);
|
|
1732
|
+
type_mapping_[(uint8_t)json_type::int64_value] = builder->make_integer_validator(sch, uris, keywords);
|
|
1733
|
+
type_mapping_[(uint8_t)json_type::uint64_value] = type_mapping_[(uint8_t)json_type::int64_value];
|
|
1734
|
+
type_mapping_[(uint8_t)json_type::double_value] = type_mapping_[(uint8_t)json_type::int64_value];
|
|
1735
|
+
type_mapping_[(uint8_t)json_type::double_value] = builder->make_number_validator(sch, uris, keywords);
|
|
1736
|
+
type_mapping_[(uint8_t)json_type::int64_value] = type_mapping_[(uint8_t)json_type::double_value];
|
|
1737
|
+
type_mapping_[(uint8_t)json_type::uint64_value] = type_mapping_[(uint8_t)json_type::double_value];
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
};
|
|
1741
|
+
|
|
1742
|
+
} // namespace jsonschema
|
|
1743
|
+
} // namespace jsoncons
|
|
1744
|
+
|
|
1745
|
+
#endif // JSONCONS_JSONSCHEMA_VALUE_RULES_HPP
|