jsoncons 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (155) hide show
  1. checksums.yaml +7 -0
  2. data/ext/jsoncons/extconf.rb +43 -0
  3. data/ext/jsoncons/jsoncons.cpp +161 -0
  4. data/ext/jsoncons/jsoncons.h +10 -0
  5. data/jsoncons.gemspec +44 -0
  6. data/lib/jsoncons/jsoncons/examples/input/address-book.json +13 -0
  7. data/lib/jsoncons/jsoncons/examples/input/books.json +28 -0
  8. data/lib/jsoncons/jsoncons/examples/input/countries.json +7 -0
  9. data/lib/jsoncons/jsoncons/examples/input/employees.json +30 -0
  10. data/lib/jsoncons/jsoncons/examples/input/jsonschema/name.json +15 -0
  11. data/lib/jsoncons/jsoncons/examples/input/multiple-json-objects.json +3 -0
  12. data/lib/jsoncons/jsoncons/examples/input/sales.csv +6 -0
  13. data/lib/jsoncons/jsoncons/examples/input/store.json +28 -0
  14. data/lib/jsoncons/jsoncons/examples/input/tasks.csv +6 -0
  15. data/lib/jsoncons/jsoncons/include/jsoncons/allocator_holder.hpp +38 -0
  16. data/lib/jsoncons/jsoncons/include/jsoncons/basic_json.hpp +5905 -0
  17. data/lib/jsoncons/jsoncons/include/jsoncons/bigint.hpp +1611 -0
  18. data/lib/jsoncons/jsoncons/include/jsoncons/byte_string.hpp +820 -0
  19. data/lib/jsoncons/jsoncons/include/jsoncons/config/binary_config.hpp +226 -0
  20. data/lib/jsoncons/jsoncons/include/jsoncons/config/compiler_support.hpp +375 -0
  21. data/lib/jsoncons/jsoncons/include/jsoncons/config/jsoncons_config.hpp +309 -0
  22. data/lib/jsoncons/jsoncons/include/jsoncons/config/version.hpp +40 -0
  23. data/lib/jsoncons/jsoncons/include/jsoncons/conv_error.hpp +218 -0
  24. data/lib/jsoncons/jsoncons/include/jsoncons/decode_json.hpp +209 -0
  25. data/lib/jsoncons/jsoncons/include/jsoncons/decode_traits.hpp +651 -0
  26. data/lib/jsoncons/jsoncons/include/jsoncons/detail/endian.hpp +44 -0
  27. data/lib/jsoncons/jsoncons/include/jsoncons/detail/grisu3.hpp +312 -0
  28. data/lib/jsoncons/jsoncons/include/jsoncons/detail/optional.hpp +483 -0
  29. data/lib/jsoncons/jsoncons/include/jsoncons/detail/parse_number.hpp +1133 -0
  30. data/lib/jsoncons/jsoncons/include/jsoncons/detail/span.hpp +188 -0
  31. data/lib/jsoncons/jsoncons/include/jsoncons/detail/string_view.hpp +537 -0
  32. data/lib/jsoncons/jsoncons/include/jsoncons/detail/string_wrapper.hpp +370 -0
  33. data/lib/jsoncons/jsoncons/include/jsoncons/detail/write_number.hpp +567 -0
  34. data/lib/jsoncons/jsoncons/include/jsoncons/encode_json.hpp +315 -0
  35. data/lib/jsoncons/jsoncons/include/jsoncons/encode_traits.hpp +378 -0
  36. data/lib/jsoncons/jsoncons/include/jsoncons/json.hpp +18 -0
  37. data/lib/jsoncons/jsoncons/include/jsoncons/json_array.hpp +324 -0
  38. data/lib/jsoncons/jsoncons/include/jsoncons/json_content_handler.hpp +12 -0
  39. data/lib/jsoncons/jsoncons/include/jsoncons/json_cursor.hpp +448 -0
  40. data/lib/jsoncons/jsoncons/include/jsoncons/json_decoder.hpp +420 -0
  41. data/lib/jsoncons/jsoncons/include/jsoncons/json_encoder.hpp +1587 -0
  42. data/lib/jsoncons/jsoncons/include/jsoncons/json_error.hpp +156 -0
  43. data/lib/jsoncons/jsoncons/include/jsoncons/json_exception.hpp +241 -0
  44. data/lib/jsoncons/jsoncons/include/jsoncons/json_filter.hpp +653 -0
  45. data/lib/jsoncons/jsoncons/include/jsoncons/json_fwd.hpp +23 -0
  46. data/lib/jsoncons/jsoncons/include/jsoncons/json_object.hpp +1772 -0
  47. data/lib/jsoncons/jsoncons/include/jsoncons/json_options.hpp +862 -0
  48. data/lib/jsoncons/jsoncons/include/jsoncons/json_parser.hpp +2900 -0
  49. data/lib/jsoncons/jsoncons/include/jsoncons/json_reader.hpp +731 -0
  50. data/lib/jsoncons/jsoncons/include/jsoncons/json_traits_macros.hpp +1072 -0
  51. data/lib/jsoncons/jsoncons/include/jsoncons/json_traits_macros_deprecated.hpp +144 -0
  52. data/lib/jsoncons/jsoncons/include/jsoncons/json_type.hpp +206 -0
  53. data/lib/jsoncons/jsoncons/include/jsoncons/json_type_traits.hpp +1830 -0
  54. data/lib/jsoncons/jsoncons/include/jsoncons/json_visitor.hpp +1560 -0
  55. data/lib/jsoncons/jsoncons/include/jsoncons/json_visitor2.hpp +2079 -0
  56. data/lib/jsoncons/jsoncons/include/jsoncons/pretty_print.hpp +89 -0
  57. data/lib/jsoncons/jsoncons/include/jsoncons/ser_context.hpp +62 -0
  58. data/lib/jsoncons/jsoncons/include/jsoncons/sink.hpp +289 -0
  59. data/lib/jsoncons/jsoncons/include/jsoncons/source.hpp +777 -0
  60. data/lib/jsoncons/jsoncons/include/jsoncons/source_adaptor.hpp +148 -0
  61. data/lib/jsoncons/jsoncons/include/jsoncons/staj2_cursor.hpp +1189 -0
  62. data/lib/jsoncons/jsoncons/include/jsoncons/staj_cursor.hpp +1254 -0
  63. data/lib/jsoncons/jsoncons/include/jsoncons/staj_iterator.hpp +449 -0
  64. data/lib/jsoncons/jsoncons/include/jsoncons/tag_type.hpp +245 -0
  65. data/lib/jsoncons/jsoncons/include/jsoncons/text_source_adaptor.hpp +144 -0
  66. data/lib/jsoncons/jsoncons/include/jsoncons/traits_extension.hpp +884 -0
  67. data/lib/jsoncons/jsoncons/include/jsoncons/typed_array_view.hpp +250 -0
  68. data/lib/jsoncons/jsoncons/include/jsoncons/unicode_traits.hpp +1330 -0
  69. data/lib/jsoncons/jsoncons/include/jsoncons/uri.hpp +635 -0
  70. data/lib/jsoncons/jsoncons/include/jsoncons/value_converter.hpp +340 -0
  71. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson.hpp +23 -0
  72. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_cursor.hpp +320 -0
  73. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_decimal128.hpp +865 -0
  74. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_encoder.hpp +585 -0
  75. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_error.hpp +103 -0
  76. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_oid.hpp +245 -0
  77. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_options.hpp +75 -0
  78. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_parser.hpp +645 -0
  79. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_reader.hpp +92 -0
  80. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/bson_type.hpp +44 -0
  81. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/decode_bson.hpp +201 -0
  82. data/lib/jsoncons/jsoncons/include/jsoncons_ext/bson/encode_bson.hpp +144 -0
  83. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor.hpp +26 -0
  84. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_cursor.hpp +351 -0
  85. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_cursor2.hpp +265 -0
  86. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_detail.hpp +93 -0
  87. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_encoder.hpp +1766 -0
  88. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_error.hpp +105 -0
  89. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_options.hpp +113 -0
  90. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_parser.hpp +1942 -0
  91. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/cbor_reader.hpp +116 -0
  92. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/decode_cbor.hpp +203 -0
  93. data/lib/jsoncons/jsoncons/include/jsoncons_ext/cbor/encode_cbor.hpp +151 -0
  94. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv.hpp +17 -0
  95. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_cursor.hpp +358 -0
  96. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_encoder.hpp +954 -0
  97. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_error.hpp +85 -0
  98. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_options.hpp +973 -0
  99. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_parser.hpp +2099 -0
  100. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_reader.hpp +348 -0
  101. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/csv_serializer.hpp +12 -0
  102. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/decode_csv.hpp +208 -0
  103. data/lib/jsoncons/jsoncons/include/jsoncons_ext/csv/encode_csv.hpp +122 -0
  104. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jmespath/jmespath.hpp +5215 -0
  105. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jmespath/jmespath_error.hpp +215 -0
  106. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpatch/jsonpatch.hpp +579 -0
  107. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpatch/jsonpatch_error.hpp +121 -0
  108. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/expression.hpp +3329 -0
  109. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/flatten.hpp +432 -0
  110. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/json_location.hpp +445 -0
  111. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/json_query.hpp +115 -0
  112. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath.hpp +13 -0
  113. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath_error.hpp +240 -0
  114. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath_expression.hpp +2612 -0
  115. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpath/jsonpath_selector.hpp +1322 -0
  116. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpointer/jsonpointer.hpp +1577 -0
  117. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonpointer/jsonpointer_error.hpp +119 -0
  118. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/format_validator.hpp +968 -0
  119. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/json_validator.hpp +120 -0
  120. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/jsonschema.hpp +13 -0
  121. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/jsonschema_error.hpp +105 -0
  122. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/jsonschema_version.hpp +18 -0
  123. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/keyword_validator.hpp +1745 -0
  124. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/keyword_validator_factory.hpp +556 -0
  125. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/schema_draft7.hpp +198 -0
  126. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/schema_location.hpp +200 -0
  127. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/schema_version.hpp +35 -0
  128. data/lib/jsoncons/jsoncons/include/jsoncons_ext/jsonschema/subschema.hpp +144 -0
  129. data/lib/jsoncons/jsoncons/include/jsoncons_ext/mergepatch/mergepatch.hpp +103 -0
  130. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/decode_msgpack.hpp +202 -0
  131. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/encode_msgpack.hpp +142 -0
  132. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack.hpp +24 -0
  133. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_cursor.hpp +343 -0
  134. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_cursor2.hpp +259 -0
  135. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_encoder.hpp +753 -0
  136. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_error.hpp +94 -0
  137. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_options.hpp +74 -0
  138. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_parser.hpp +748 -0
  139. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_reader.hpp +116 -0
  140. data/lib/jsoncons/jsoncons/include/jsoncons_ext/msgpack/msgpack_type.hpp +63 -0
  141. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/decode_ubjson.hpp +201 -0
  142. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/encode_ubjson.hpp +142 -0
  143. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson.hpp +23 -0
  144. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_cursor.hpp +307 -0
  145. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_encoder.hpp +502 -0
  146. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_error.hpp +100 -0
  147. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_options.hpp +87 -0
  148. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_parser.hpp +880 -0
  149. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_reader.hpp +92 -0
  150. data/lib/jsoncons/jsoncons/include/jsoncons_ext/ubjson/ubjson_type.hpp +43 -0
  151. data/lib/jsoncons/version.rb +5 -0
  152. data/lib/jsoncons.rb +33 -0
  153. data/test/jsoncons_test.rb +108 -0
  154. data/test/test_helper.rb +7 -0
  155. metadata +268 -0
@@ -0,0 +1,556 @@
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_FACTORY_HPP
8
+ #define JSONCONS_JSONSCHEMA_KEYWORD_VALIDATOR_FACTORY_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/keyword_validator.hpp>
16
+ #include <jsoncons_ext/jsonschema/schema_draft7.hpp>
17
+ #include <jsoncons_ext/jsonschema/schema_version.hpp>
18
+ #include <cassert>
19
+ #include <set>
20
+ #include <sstream>
21
+ #include <iostream>
22
+ #include <cassert>
23
+ #if defined(JSONCONS_HAS_STD_REGEX)
24
+ #include <regex>
25
+ #endif
26
+
27
+ namespace jsoncons {
28
+ namespace jsonschema {
29
+
30
+ template <class Json>
31
+ using uri_resolver = std::function<Json(const jsoncons::uri & /*id*/)>;
32
+
33
+ template <class Json>
34
+ class reference_schema : public keyword_validator<Json>
35
+ {
36
+ using validator_pointer = typename keyword_validator<Json>::self_pointer;
37
+
38
+ validator_pointer referred_schema_;
39
+
40
+ public:
41
+ reference_schema(const std::string& id)
42
+ : keyword_validator<Json>(id), referred_schema_(nullptr) {}
43
+
44
+ void set_referred_schema(validator_pointer target) { referred_schema_ = target; }
45
+
46
+ private:
47
+
48
+ void do_validate(const Json& instance,
49
+ const jsonpointer::json_pointer& instance_location,
50
+ error_reporter& reporter,
51
+ Json& patch) const override
52
+ {
53
+ if (!referred_schema_)
54
+ {
55
+ reporter.error(validation_output("",
56
+ this->absolute_keyword_location(),
57
+ instance_location.to_uri_fragment(),
58
+ "Unresolved schema reference " + this->absolute_keyword_location()));
59
+ return;
60
+ }
61
+
62
+ referred_schema_->validate(instance, instance_location, reporter, patch);
63
+ }
64
+
65
+ jsoncons::optional<Json> get_default_value(const jsonpointer::json_pointer& instance_location,
66
+ const Json& instance,
67
+ error_reporter& reporter) const override
68
+ {
69
+ if (!referred_schema_)
70
+ {
71
+ reporter.error(validation_output("",
72
+ this->absolute_keyword_location(),
73
+ instance_location.to_uri_fragment(),
74
+ "Unresolved schema reference " + this->absolute_keyword_location()));
75
+ return jsoncons::optional<Json>();
76
+ }
77
+
78
+ return referred_schema_->get_default_value(instance_location, instance, reporter);
79
+ }
80
+ };
81
+
82
+ template <class Json>
83
+ class keyword_validator_factory;
84
+
85
+ template <class Json>
86
+ class json_schema
87
+ {
88
+ using validator_pointer = typename keyword_validator<Json>::self_pointer;
89
+
90
+ friend class keyword_validator_factory<Json>;
91
+
92
+ std::vector<std::unique_ptr<keyword_validator<Json>>> subschemas_;
93
+ validator_pointer root_;
94
+ public:
95
+ json_schema(std::vector<std::unique_ptr<keyword_validator<Json>>>&& subschemas,
96
+ validator_pointer root)
97
+ : subschemas_(std::move(subschemas)), root_(root)
98
+ {
99
+ if (root_ == nullptr)
100
+ JSONCONS_THROW(schema_error("There is no root schema to validate an instance against"));
101
+ }
102
+
103
+ json_schema(const json_schema&) = delete;
104
+ json_schema(json_schema&&) = default;
105
+ json_schema& operator=(const json_schema&) = delete;
106
+ json_schema& operator=(json_schema&&) = default;
107
+
108
+ void validate(const Json& instance,
109
+ const jsonpointer::json_pointer& instance_location,
110
+ error_reporter& reporter,
111
+ Json& patch) const
112
+ {
113
+ JSONCONS_ASSERT(root_ != nullptr);
114
+ root_->validate(instance, instance_location, reporter, patch);
115
+ }
116
+ };
117
+
118
+ template <class Json>
119
+ struct default_uri_resolver
120
+ {
121
+ Json operator()(const jsoncons::uri& uri)
122
+ {
123
+ if (uri.path() == "/draft-07/schema")
124
+ {
125
+ return jsoncons::jsonschema::schema_draft7<Json>::get_schema();
126
+ }
127
+
128
+ JSONCONS_THROW(jsonschema::schema_error("Don't know how to load JSON Schema " + std::string(uri.base())));
129
+ }
130
+ };
131
+
132
+ template <class Json>
133
+ class keyword_validator_factory : public abstract_keyword_validator_factory<Json>
134
+ {
135
+ using validator_pointer = typename keyword_validator<Json>::self_pointer;
136
+
137
+ struct subschema_registry
138
+ {
139
+ std::map<std::string, validator_pointer> schemas; // schemas
140
+ std::map<std::string, reference_schema<Json>*> unresolved; // unresolved references
141
+ std::map<std::string, Json> unprocessed_keywords;
142
+ };
143
+
144
+ uri_resolver<Json> resolver_;
145
+ validator_pointer root_;
146
+
147
+ // Owns all schemas
148
+ std::vector<std::unique_ptr<keyword_validator<Json>>> subschemas_;
149
+
150
+ // Map location to subschema_registry
151
+ std::map<std::string, subschema_registry> subschema_registries_;
152
+
153
+ public:
154
+ keyword_validator_factory(uri_resolver<Json>&& resolver) noexcept
155
+
156
+ : resolver_(std::move(resolver))
157
+ {
158
+ }
159
+
160
+ keyword_validator_factory(const keyword_validator_factory&) = delete;
161
+ keyword_validator_factory& operator=(const keyword_validator_factory&) = delete;
162
+ keyword_validator_factory(keyword_validator_factory&&) = default;
163
+ keyword_validator_factory& operator=(keyword_validator_factory&&) = default;
164
+
165
+ std::shared_ptr<json_schema<Json>> get_schema()
166
+ {
167
+ return std::make_shared<json_schema<Json>>(std::move(subschemas_), root_);
168
+ }
169
+
170
+ validator_pointer make_required_validator(const std::vector<schema_location>& uris,
171
+ const std::vector<std::string>& r) override
172
+ {
173
+ auto sch_orig = jsoncons::make_unique<required_validator<Json>>(uris, r);
174
+ auto sch = sch_orig.get();
175
+ subschemas_.emplace_back(std::move(sch_orig));
176
+ return sch;
177
+ }
178
+
179
+ validator_pointer make_null_validator(const std::vector<schema_location>& uris) override
180
+ {
181
+ auto sch_orig = jsoncons::make_unique<null_validator<Json>>(uris);
182
+ auto sch = sch_orig.get();
183
+ subschemas_.emplace_back(std::move(sch_orig));
184
+ return sch;
185
+ }
186
+
187
+ validator_pointer make_true_validator(const std::vector<schema_location>& uris) override
188
+ {
189
+ auto sch_orig = jsoncons::make_unique<true_validator<Json>>(uris);
190
+ auto sch = sch_orig.get();
191
+ subschemas_.emplace_back(std::move(sch_orig));
192
+ return sch;
193
+ }
194
+
195
+ validator_pointer make_false_validator(const std::vector<schema_location>& uris) override
196
+ {
197
+ auto sch_orig = jsoncons::make_unique<false_validator<Json>>(uris);
198
+ auto sch = sch_orig.get();
199
+ subschemas_.emplace_back(std::move(sch_orig));
200
+ return sch;
201
+ }
202
+
203
+ validator_pointer make_object_validator(const Json& schema,
204
+ const std::vector<schema_location>& uris) override
205
+ {
206
+ auto sch_orig = jsoncons::make_unique<object_validator<Json>>(this, schema, uris);
207
+ auto sch = sch_orig.get();
208
+ subschemas_.emplace_back(std::move(sch_orig));
209
+ return sch;
210
+ }
211
+
212
+ validator_pointer make_array_validator(const Json& schema,
213
+ const std::vector<schema_location>& uris) override
214
+ {
215
+ auto sch_orig = jsoncons::make_unique<array_validator<Json>>(this, schema, uris);
216
+ auto sch = sch_orig.get();
217
+ subschemas_.emplace_back(std::move(sch_orig));
218
+ return sch;
219
+ }
220
+
221
+ validator_pointer make_string_validator(const Json& schema,
222
+ const std::vector<schema_location>& uris) override
223
+ {
224
+ auto sch_orig = jsoncons::make_unique<string_validator<Json>>(schema, uris);
225
+ auto sch = sch_orig.get();
226
+ subschemas_.emplace_back(std::move(sch_orig));
227
+ return sch;
228
+ }
229
+
230
+ validator_pointer make_boolean_validator(const std::vector<schema_location>& uris) override
231
+ {
232
+ auto sch_orig = jsoncons::make_unique<boolean_validator<Json>>(uris);
233
+ auto sch = sch_orig.get();
234
+ subschemas_.emplace_back(std::move(sch_orig));
235
+ return sch;
236
+ }
237
+
238
+ validator_pointer make_integer_validator(const Json& schema,
239
+ const std::vector<schema_location>& uris,
240
+ std::set<std::string>& keywords) override
241
+ {
242
+ auto sch_orig = jsoncons::make_unique<integer_validator<Json>>(schema, uris, keywords);
243
+ auto sch = sch_orig.get();
244
+ subschemas_.emplace_back(std::move(sch_orig));
245
+ return sch;
246
+ }
247
+
248
+ validator_pointer make_number_validator(const Json& schema,
249
+ const std::vector<schema_location>& uris,
250
+ std::set<std::string>& keywords) override
251
+ {
252
+ auto sch_orig = jsoncons::make_unique<number_validator<Json>>(schema, uris, keywords);
253
+ auto sch = sch_orig.get();
254
+ subschemas_.emplace_back(std::move(sch_orig));
255
+ return sch;
256
+ }
257
+
258
+ validator_pointer make_not_validator(const Json& schema,
259
+ const std::vector<schema_location>& uris) override
260
+ {
261
+ auto sch_orig = jsoncons::make_unique<not_validator<Json>>(this, schema, uris);
262
+ auto sch = sch_orig.get();
263
+ subschemas_.emplace_back(std::move(sch_orig));
264
+ return sch;
265
+ }
266
+
267
+ validator_pointer make_all_of_validator(const Json& schema,
268
+ const std::vector<schema_location>& uris) override
269
+ {
270
+ auto sch_orig = jsoncons::make_unique<combining_validator<Json,all_of_criterion<Json>>>(this, schema, uris);
271
+ auto sch = sch_orig.get();
272
+ subschemas_.emplace_back(std::move(sch_orig));
273
+ return sch;
274
+ }
275
+
276
+ validator_pointer make_any_of_validator(const Json& schema,
277
+ const std::vector<schema_location>& uris) override
278
+ {
279
+ auto sch_orig = jsoncons::make_unique<combining_validator<Json,any_of_criterion<Json>>>(this, schema, uris);
280
+ auto sch = sch_orig.get();
281
+ subschemas_.emplace_back(std::move(sch_orig));
282
+ return sch;
283
+ }
284
+
285
+ validator_pointer make_one_of_validator(const Json& schema,
286
+ const std::vector<schema_location>& uris) override
287
+ {
288
+ auto sch_orig = jsoncons::make_unique<combining_validator<Json,one_of_criterion<Json>>>(this, schema, uris);
289
+ auto sch = sch_orig.get();
290
+ subschemas_.emplace_back(std::move(sch_orig));
291
+ return sch;
292
+ }
293
+
294
+ validator_pointer make_type_validator(const Json& schema,
295
+ const std::vector<schema_location>& uris) override
296
+ {
297
+ auto sch_orig = jsoncons::make_unique<type_validator<Json>>(this, schema, uris);
298
+ auto sch = sch_orig.get();
299
+ subschemas_.emplace_back(std::move(sch_orig));
300
+ return sch;
301
+ }
302
+
303
+ validator_pointer make_keyword_validator(const Json& schema,
304
+ const std::vector<schema_location>& uris,
305
+ const std::vector<std::string>& keys) override
306
+ {
307
+ std::vector<schema_location> new_uris = update_uris(schema, uris, keys);
308
+
309
+ validator_pointer sch = nullptr;
310
+
311
+ switch (schema.type())
312
+ {
313
+ case json_type::bool_value:
314
+ if (schema.template as<bool>())
315
+ {
316
+ sch = make_true_validator(new_uris);
317
+ }
318
+ else
319
+ {
320
+ sch = make_false_validator(new_uris);
321
+ }
322
+ break;
323
+ case json_type::object_value:
324
+ {
325
+ auto it = schema.find("definitions");
326
+ if (it != schema.object_range().end())
327
+ {
328
+ for (const auto& def : it->value().object_range())
329
+ make_keyword_validator(def.value(), new_uris, {"definitions", def.key()});
330
+ }
331
+
332
+ it = schema.find("$ref");
333
+ if (it != schema.object_range().end()) // this schema is a reference
334
+ {
335
+ schema_location relative(it->value().template as<std::string>());
336
+ schema_location id = relative.resolve(new_uris.back());
337
+ sch = get_or_create_reference(id);
338
+ }
339
+ else
340
+ {
341
+ sch = make_type_validator(schema, new_uris);
342
+ }
343
+ break;
344
+ }
345
+ default:
346
+ JSONCONS_THROW(schema_error("invalid JSON-type for a schema for " + new_uris[0].string() + ", expected: boolean or object"));
347
+ break;
348
+ }
349
+
350
+ for (const auto& uri : new_uris)
351
+ {
352
+ insert(uri, sch);
353
+
354
+ if (schema.type() == json_type::object_value)
355
+ {
356
+ for (const auto& item : schema.object_range())
357
+ insert_unknown_keyword(uri, item.key(), item.value()); // save unknown keywords for later reference
358
+ }
359
+ }
360
+ return sch;
361
+ }
362
+
363
+ void load_root(const Json& sch)
364
+ {
365
+ if (sch.is_object())
366
+ {
367
+ auto it = sch.find("$schema");
368
+ if (it != sch.object_range().end())
369
+ {
370
+ auto sv = it->value().as_string_view();
371
+ if (!schema_version::contains(sv))
372
+ {
373
+ std::string message("Unsupported schema version ");
374
+ message.append(sv.data(), sv.size());
375
+ JSONCONS_THROW(schema_error(message));
376
+ }
377
+ }
378
+ }
379
+ load(sch);
380
+ }
381
+
382
+ void load(const Json& sch)
383
+ {
384
+ subschema_registries_.clear();
385
+ root_ = make_keyword_validator(sch, {{"#"}}, {});
386
+
387
+ // load all external schemas that have not already been loaded
388
+
389
+ std::size_t loaded_count = 0;
390
+ do
391
+ {
392
+ loaded_count = 0;
393
+
394
+ std::vector<std::string> locations;
395
+ for (const auto& item : subschema_registries_)
396
+ locations.push_back(item.first);
397
+
398
+ for (const auto& loc : locations)
399
+ {
400
+ if (subschema_registries_[loc].schemas.empty()) // registry for this file is empty
401
+ {
402
+ if (resolver_)
403
+ {
404
+ Json external_schema = resolver_(loc);
405
+ make_keyword_validator(external_schema, {{loc}}, {});
406
+ ++loaded_count;
407
+ }
408
+ else
409
+ {
410
+ JSONCONS_THROW(schema_error("External schema reference '" + loc + "' needs to be loaded, but no resolver provided"));
411
+ }
412
+ }
413
+ }
414
+ }
415
+ while (loaded_count > 0);
416
+
417
+ for (const auto &file : subschema_registries_)
418
+ {
419
+ if (!file.second.unresolved.empty())
420
+ {
421
+ JSONCONS_THROW(schema_error("after all files have been parsed, '" +
422
+ (file.first == "" ? "<root>" : file.first) +
423
+ "' has still undefined references."));
424
+ }
425
+ }
426
+ }
427
+
428
+ private:
429
+
430
+ void insert(const schema_location& uri, validator_pointer s)
431
+ {
432
+ auto& file = get_or_create_file(std::string(uri.base()));
433
+ auto schemas_it = file.schemas.find(std::string(uri.fragment()));
434
+ if (schemas_it != file.schemas.end())
435
+ {
436
+ JSONCONS_THROW(schema_error("schema with " + uri.string() + " already inserted"));
437
+ return;
438
+ }
439
+
440
+ file.schemas.insert({std::string(uri.fragment()), s});
441
+
442
+ // is there an unresolved reference to this newly inserted schema?
443
+ auto unresolved_it = file.unresolved.find(std::string(uri.fragment()));
444
+ if (unresolved_it != file.unresolved.end())
445
+ {
446
+ unresolved_it->second->set_referred_schema(s);
447
+ file.unresolved.erase(unresolved_it);
448
+
449
+ }
450
+ }
451
+
452
+ void insert_unknown_keyword(const schema_location& uri,
453
+ const std::string& key,
454
+ const Json& value)
455
+ {
456
+ auto &file = get_or_create_file(std::string(uri.base()));
457
+ auto new_u = uri.append(key);
458
+ schema_location new_uri(new_u);
459
+
460
+ if (new_uri.has_fragment() && !new_uri.has_identifier())
461
+ {
462
+ auto fragment = std::string(new_uri.fragment());
463
+ // is there a reference looking for this unknown-keyword, which is thus no longer a unknown keyword but a schema
464
+ auto unresolved = file.unresolved.find(fragment);
465
+ if (unresolved != file.unresolved.end())
466
+ make_keyword_validator(value, {{new_uri}}, {});
467
+ else // no, nothing ref'd it, keep for later
468
+ file.unprocessed_keywords[fragment] = value;
469
+
470
+ // recursively add possible subschemas of unknown keywords
471
+ if (value.type() == json_type::object_value)
472
+ for (const auto& subsch : value.object_range())
473
+ {
474
+ insert_unknown_keyword(new_uri, subsch.key(), subsch.value());
475
+ }
476
+ }
477
+ }
478
+
479
+ validator_pointer get_or_create_reference(const schema_location& uri)
480
+ {
481
+ auto &file = get_or_create_file(std::string(uri.base()));
482
+
483
+ // a schema already exists
484
+ auto sch = file.schemas.find(std::string(uri.fragment()));
485
+ if (sch != file.schemas.end())
486
+ return sch->second;
487
+
488
+ // referencing an unknown keyword, turn it into schema
489
+ //
490
+ // an unknown keyword can only be referenced by a JSONPointer,
491
+ // not by a plain name identifier
492
+ if (uri.has_fragment() && !uri.has_identifier())
493
+ {
494
+ std::string fragment = std::string(uri.fragment());
495
+ auto unprocessed_keywords_it = file.unprocessed_keywords.find(fragment);
496
+ if (unprocessed_keywords_it != file.unprocessed_keywords.end())
497
+ {
498
+ auto &subsch = unprocessed_keywords_it->second;
499
+ auto s = make_keyword_validator(subsch, {{uri}}, {}); // A JSON Schema MUST be an object or a boolean.
500
+ file.unprocessed_keywords.erase(unprocessed_keywords_it);
501
+ return s;
502
+ }
503
+ }
504
+
505
+ // get or create a reference_schema
506
+ auto ref = file.unresolved.find(std::string(uri.fragment()));
507
+ if (ref != file.unresolved.end())
508
+ {
509
+ return ref->second; // unresolved, use existing reference
510
+ }
511
+ else
512
+ {
513
+ auto orig = jsoncons::make_unique<reference_schema<Json>>(uri.string());
514
+ auto p = file.unresolved.insert(ref,
515
+ {std::string(uri.fragment()), orig.get()})
516
+ ->second; // unresolved, create new reference
517
+
518
+ subschemas_.emplace_back(std::move(orig));
519
+ return p;
520
+ }
521
+ }
522
+
523
+ subschema_registry& get_or_create_file(const std::string& loc)
524
+ {
525
+ auto file = subschema_registries_.find(loc);
526
+ if (file != subschema_registries_.end())
527
+ return file->second;
528
+ else
529
+ return subschema_registries_.insert(file, {loc, {}})->second;
530
+ }
531
+
532
+ };
533
+
534
+ template <class Json>
535
+ std::shared_ptr<json_schema<Json>> make_schema(const Json& schema)
536
+ {
537
+ keyword_validator_factory<Json> loader{default_uri_resolver<Json>()};
538
+ loader.load_root(schema);
539
+
540
+ return loader.get_schema();
541
+ }
542
+
543
+ template <class Json,class URIResolver>
544
+ typename std::enable_if<traits_extension::is_unary_function_object_exact<URIResolver,Json,std::string>::value,std::shared_ptr<json_schema<Json>>>::type
545
+ make_schema(const Json& schema, const URIResolver& resolver)
546
+ {
547
+ keyword_validator_factory<Json> loader(resolver);
548
+ loader.load_root(schema);
549
+
550
+ return loader.get_schema();
551
+ }
552
+
553
+ } // namespace jsonschema
554
+ } // namespace jsoncons
555
+
556
+ #endif // JSONCONS_JSONSCHEMA_SCHEMA_LOADER_HPP