|
|
@@ -3,7 +3,9 @@
|
|
|
#include <filesystem>
|
|
|
#include <fstream>
|
|
|
#include <iostream>
|
|
|
+#include <sstream>
|
|
|
#include <stdexcept>
|
|
|
+#include <string_view>
|
|
|
|
|
|
#include <curl/curl.h>
|
|
|
|
|
|
@@ -37,17 +39,6 @@ size_t transfer_to_buffer(char * data, size_t size, size_t nmemb, void * userdat
|
|
|
return actual_size;
|
|
|
}
|
|
|
|
|
|
-Json::Value load_stream(std::filesystem::path const & file) {
|
|
|
- std::ifstream in(file);
|
|
|
- Json::Value json;
|
|
|
- Json::CharReaderBuilder builder;
|
|
|
- std::string error;
|
|
|
- if (!Json::parseFromStream(builder, in, &json, &error)) {
|
|
|
- throw std::invalid_argument(error);
|
|
|
- }
|
|
|
- return json;
|
|
|
-}
|
|
|
-
|
|
|
bool curl_get(jvalidate::URI const & uri, Json::Value & out) {
|
|
|
if (uri.scheme().starts_with("http")) {
|
|
|
std::stringstream ss;
|
|
|
@@ -72,23 +63,91 @@ bool curl_get(jvalidate::URI const & uri, Json::Value & out) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+struct ProgramArgs {
|
|
|
+ ProgramArgs(std::string_view program, std::vector<std::string_view> args) {
|
|
|
+ size_t nargs = 0;
|
|
|
+ for (size_t i = 0; i < args.size(); ++i) {
|
|
|
+ if (args[i] == "--verbose" || args[i] == "-v") {
|
|
|
+ verbose = true;
|
|
|
+ } else if (args[i] == "--explain") {
|
|
|
+ format_as_explaination = true;
|
|
|
+ } else {
|
|
|
+ switch (nargs++) {
|
|
|
+ case 0:
|
|
|
+ schema = args[i];
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ object = args[i];
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (nargs != 2) {
|
|
|
+ throw std::invalid_argument("usage: " + std::string(program) +
|
|
|
+ " [--verbose|-v] [--explain] schema object");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ bool verbose = false;
|
|
|
+ bool format_as_explaination = false;
|
|
|
+ std::string_view schema;
|
|
|
+ std::string_view object;
|
|
|
+};
|
|
|
+
|
|
|
int main(int argc, char const * const * argv) {
|
|
|
- if (argc <= 2) {
|
|
|
- std::cerr << "usage: " << argv[0] << " schema object\n";
|
|
|
+ ProgramArgs const args{argv[0], {argv + 1, argv + argc}};
|
|
|
+
|
|
|
+ Json::Value jschema;
|
|
|
+ Json::Value jobject;
|
|
|
+ if (!load_file(args.schema, jschema) || !load_file(args.object, jobject)) {
|
|
|
return EXIT_FAILURE;
|
|
|
}
|
|
|
|
|
|
- Json::Value jschema = load_stream(argv[1]);
|
|
|
- Json::Value jobject = load_stream(argv[2]);
|
|
|
-
|
|
|
using enum jvalidate::schema::Version;
|
|
|
jvalidate::Schema schema(jschema, Draft2020_12, &curl_get);
|
|
|
|
|
|
jvalidate::ValidationResult result;
|
|
|
- if (!jvalidate::Validator(schema, {.only_return_results_with_error = true})
|
|
|
- .validate(jobject, &result)) {
|
|
|
- std::cout << result;
|
|
|
+ bool compact_error = !args.verbose && !args.format_as_explaination;
|
|
|
+ if (jvalidate::Validator(schema, {.only_return_results_with_error = compact_error})
|
|
|
+ .validate(jobject, &result)) {
|
|
|
+ return EXIT_SUCCESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!args.format_as_explaination) {
|
|
|
+ std::cout << result << "\n";
|
|
|
+ return EXIT_FAILURE;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::stringstream ss;
|
|
|
+ ss << result;
|
|
|
+ Json::Value json;
|
|
|
+ load_stream(ss, json);
|
|
|
+
|
|
|
+ std::map<std::string, Json::Value> because;
|
|
|
+ for (Json::Value const & elem : json["details"]) {
|
|
|
+ std::string const & path = elem["evaluationPath"].asString();
|
|
|
+ if (size_t pos = path.find("/if"); pos != std::string::npos && elem.isMember("errors")) {
|
|
|
+ because.emplace(path.substr(0, pos), elem);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Json::Value out;
|
|
|
+ for (Json::Value & elem : json["details"]) {
|
|
|
+ if (!elem.isMember("errors") || elem["valid"].asBool()) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (std::string const & path = elem["evaluationPath"].asString();
|
|
|
+ auto const & [key, reason] : because) {
|
|
|
+ if (path.starts_with(key)) {
|
|
|
+ elem["because"] = reason;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ out.append(std::move(elem));
|
|
|
}
|
|
|
+ std::cout << out << std::endl;
|
|
|
|
|
|
- return EXIT_SUCCESS;
|
|
|
+ return EXIT_FAILURE;
|
|
|
}
|