Skip to content

Commit ec936ca

Browse files
authored
Support the Flag and Basic standard output formats (#471)
See: sourcemeta/jsonschema#213 See: sourcemeta/jsonschema#58 Signed-off-by: Juan Cruz Viotti <[email protected]>
1 parent 5728172 commit ec936ca

File tree

7 files changed

+554
-3
lines changed

7 files changed

+554
-3
lines changed

README.markdown

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ Features
4141
- **Compliance:** Blaze achieves a 100% compliance score in the official
4242
[Bowtie](https://bowtie.report/#/implementations/cpp-blaze) benchmark, while
4343
popular validators like [AJV](https://bowtie.report/#/implementations/js-ajv)
44-
only achieve an average 85% compliance. Furthermore, Blaze is built and
45-
maintained by a [JSON Schema TSC member](https://www.jviotti.com)
44+
only achieve an average 85% compliance. It also supports the [Standard
45+
Output](https://json-schema.org/draft/2020-12/json-schema-core#name-output-formatting)
46+
format (Flag, and Basic). Furthermore, Blaze is built and maintained by a
47+
[JSON Schema TSC member](https://www.jviotti.com)
4648

4749
- **Extensibility:** Blaze supports the implementation of custom vocabularies
4850
of arbitrary complexity, and the ability to setup custom resolution of

src/compiler/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ sourcemeta_library(NAMESPACE sourcemeta PROJECT blaze NAME compiler
33
PRIVATE_HEADERS error.h output.h unevaluated.h
44
SOURCES
55
compile.cc compile_describe.cc compile_json.cc
6-
compile_output_simple.cc compile_output_trace.cc
76
compile_helpers.h default_compiler.cc unevaluated.cc
7+
compile_output_simple.cc
8+
compile_output_trace.cc
9+
compile_output_standard.cc
810
default_compiler_2020_12.h
911
default_compiler_2019_09.h
1012
default_compiler_draft7.h
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include <sourcemeta/blaze/compiler.h>
2+
3+
#include <cassert> // assert
4+
#include <functional> // std::ref
5+
6+
namespace sourcemeta::blaze {
7+
8+
auto standard(Evaluator &evaluator, const Template &schema,
9+
const sourcemeta::core::JSON &instance,
10+
const StandardOutput format) -> sourcemeta::core::JSON {
11+
// We avoid a callback for this specific case for performance reasons
12+
if (format == StandardOutput::Flag) {
13+
auto result{sourcemeta::core::JSON::make_object()};
14+
const auto valid{evaluator.validate(schema, instance)};
15+
result.assign("valid", sourcemeta::core::JSON{valid});
16+
return result;
17+
} else {
18+
assert(format == StandardOutput::Basic);
19+
SimpleOutput output{instance};
20+
const auto valid{evaluator.validate(schema, instance, std::ref(output))};
21+
22+
if (valid) {
23+
auto result{sourcemeta::core::JSON::make_object()};
24+
result.assign("valid", sourcemeta::core::JSON{valid});
25+
auto annotations{sourcemeta::core::JSON::make_array()};
26+
for (const auto &annotation : output.annotations()) {
27+
auto unit{sourcemeta::core::JSON::make_object()};
28+
unit.assign(
29+
"keywordLocation",
30+
sourcemeta::core::to_json(annotation.first.evaluate_path).value());
31+
unit.assign("absoluteKeywordLocation",
32+
sourcemeta::core::JSON{annotation.first.schema_location});
33+
unit.assign("instanceLocation", sourcemeta::core::to_json(
34+
annotation.first.instance_location)
35+
.value());
36+
unit.assign("annotation", sourcemeta::core::to_json(annotation.second));
37+
annotations.push_back(std::move(unit));
38+
}
39+
40+
if (!annotations.empty()) {
41+
result.assign("annotations", std::move(annotations));
42+
}
43+
44+
return result;
45+
} else {
46+
auto result{sourcemeta::core::JSON::make_object()};
47+
result.assign("valid", sourcemeta::core::JSON{valid});
48+
auto errors{sourcemeta::core::JSON::make_array()};
49+
for (const auto &entry : output) {
50+
auto unit{sourcemeta::core::JSON::make_object()};
51+
unit.assign("keywordLocation",
52+
sourcemeta::core::to_json(entry.evaluate_path).value());
53+
unit.assign("absoluteKeywordLocation",
54+
sourcemeta::core::JSON{entry.schema_location});
55+
unit.assign("instanceLocation",
56+
sourcemeta::core::to_json(entry.instance_location).value());
57+
unit.assign("error", sourcemeta::core::JSON{entry.message});
58+
errors.push_back(std::move(unit));
59+
}
60+
61+
assert(!errors.empty());
62+
result.assign("errors", std::move(errors));
63+
return result;
64+
}
65+
}
66+
}
67+
68+
} // namespace sourcemeta::blaze

src/compiler/include/sourcemeta/blaze/compiler_output.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,71 @@ describe(const bool valid, const Instruction &step,
264264
const sourcemeta::core::JSON &instance,
265265
const sourcemeta::core::JSON &annotation) -> std::string;
266266

267+
/// @ingroup compiler
268+
/// Represents standard output formats
269+
/// See
270+
/// https://json-schema.org/draft/2020-12/json-schema-core#name-output-structure
271+
/// See
272+
/// https://json-schema.org/draft/2019-09/draft-handrews-json-schema-02#rfc.section.10
273+
enum class StandardOutput {
274+
Flag,
275+
Basic
276+
// TODO: Implement the "detailed" and "verbose" output formats
277+
};
278+
279+
// TODO: Integrate with
280+
// https://github.com/json-schema-org/JSON-Schema-Test-Suite/tree/main/output-tests
281+
282+
/// @ingroup compiler
283+
/// Perform JSON Schema evaluation using Standard Output formats. For example:
284+
///
285+
/// ```cpp
286+
/// #include <sourcemeta/blaze/evaluator.h>
287+
/// #include <sourcemeta/blaze/compiler.h>
288+
///
289+
/// #include <sourcemeta/core/json.h>
290+
/// #include <sourcemeta/core/jsonschema.h>
291+
///
292+
/// #include <cassert>
293+
/// #include <iostream>
294+
///
295+
/// const sourcemeta::core::JSON schema =
296+
/// sourcemeta::core::parse_json(R"JSON({
297+
/// "$schema": "https://json-schema.org/draft/2020-12/schema",
298+
/// "type": "string"
299+
/// })JSON");
300+
///
301+
/// const auto schema_template{sourcemeta::blaze::compile(
302+
/// schema, sourcemeta::core::schema_official_walker,
303+
/// sourcemeta::core::schema_official_resolver,
304+
/// sourcemeta::core::default_schema_compiler)};
305+
///
306+
/// const sourcemeta::core::JSON instance{"foo bar"};
307+
///
308+
/// sourcemeta::blaze::Evaluator evaluator;
309+
///
310+
/// const auto result{sourcemeta::blaze::standard(
311+
/// evaluator, schema_template, instance,
312+
/// sourcemeta::blaze::StandardOutput::Basic)};
313+
///
314+
/// assert(result.is_object());
315+
/// assert(result.defines("valid"));
316+
/// assert(result.at("valid").is_boolean());
317+
/// assert(result.at("valid").to_boolean());
318+
///
319+
/// sourcemeta::core::prettify(result,
320+
/// std::cout, sourcemeta::blaze::standard_output_compare);
321+
/// std::cout << "\n";
322+
/// ```
323+
///
324+
/// Note that this output format is not a class like the others
325+
/// in order to have additional control over how and whether to
326+
/// pass a callback to the evaluator instance.
327+
auto SOURCEMETA_BLAZE_COMPILER_EXPORT
328+
standard(Evaluator &evaluator, const Template &schema,
329+
const sourcemeta::core::JSON &instance, const StandardOutput format)
330+
-> sourcemeta::core::JSON;
331+
267332
} // namespace sourcemeta::blaze
268333

269334
#endif

test/compiler/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ sourcemeta_googletest(NAMESPACE sourcemeta PROJECT blaze NAME compiler
33
SOURCES
44
compiler_output_simple_test.cc
55
compiler_output_trace_test.cc
6+
compiler_output_standard_flag_test.cc
7+
compiler_output_standard_basic_test.cc
68
compiler_unevaluated_2019_09_test.cc
79
compiler_unevaluated_2020_12_test.cc
810
compiler_json_test.cc

0 commit comments

Comments
 (0)