| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- #pragma once
- #include <map>
- #include <ostream>
- #include <unordered_set>
- #include <variant>
- #include <vector>
- #include <jvalidate/detail/pointer.h>
- #include <jvalidate/forward.h>
- namespace jvalidate {
- class ValidationResult {
- public:
- template <Adapter A, RegexEngine RE> friend class ValidationVisitor;
- using DocPointer = detail::Pointer;
- using SchemaPointer = detail::Pointer;
- using Annotation = std::variant<std::string, std::vector<std::string>>;
- struct LocalResult {
- /* bool valid; */
- std::map<std::string, Annotation> errors;
- std::map<std::string, Annotation> annotations;
- };
- struct indent {
- indent(int i) : i(i) {}
- friend std::ostream & operator<<(std::ostream & os, indent id) {
- while (id.i-- > 0)
- os << " ";
- return os;
- }
- int i;
- };
- private:
- std::map<DocPointer, std::map<SchemaPointer, LocalResult>> results_;
- public:
- friend std::ostream & operator<<(std::ostream & os, ValidationResult const & result) {
- os << "{\n" << indent(1) << R"("details": [)" << '\n';
- for (auto const & [doc_path, by_schema] : result.results_) {
- for (auto const & [schema_path, local] : by_schema) {
- os << indent(2) << '{' << '\n';
- os << indent(3) << R"("evaluationPath": ")" << schema_path << '"' << ',' << '\n';
- os << indent(3) << R"("instanceLocation": ")" << doc_path << '"';
- print(os, local.annotations, "annotations", 3);
- print(os, local.errors, "errors", 3);
- os << '\n' << indent(2) << '}' << '\n';
- }
- }
- return os << indent(1) << ']' << '\n' << '}';
- }
- static void print(std::ostream & os, std::map<std::string, Annotation> const & named,
- std::string_view name, int const i) {
- if (named.empty()) {
- return;
- }
- os << ',' << '\n';
- os << indent(i) << '"' << name << '"' << ':' << ' ' << '{' << '\n';
- for (auto const & [key, anno] : named) {
- os << indent(i + 1) << '"' << key << '"' << ':' << ' ';
- if (auto const * str = std::get_if<0>(&anno)) {
- os << '"' << *str << '"';
- } else if (auto const * vec = std::get_if<1>(&anno)) {
- os << '[';
- char const * div = "\n";
- for (size_t i = 0; i < vec->size(); ++i) {
- os << std::exchange(div, ",\n") << indent(i + 2) << '"' << vec->at(i) << '"';
- }
- os << indent(i + 1) << ']';
- }
- os << '\n';
- }
- os << indent(i) << '}';
- }
- bool has(detail::Pointer const & where, detail::Pointer const & schema_path) const {
- return has(where) && results_.at(where).contains(schema_path);
- }
- bool has(detail::Pointer const & where) const { return results_.contains(where); }
- Annotation const * annotation(detail::Pointer const & where, detail::Pointer const & schema_path,
- std::string const & name) const {
- if (not results_.contains(where)) {
- return nullptr;
- }
- auto const & by_schema = results_.at(where);
- if (not by_schema.contains(schema_path)) {
- return nullptr;
- }
- auto const & local = by_schema.at(schema_path);
- if (not local.annotations.contains(name)) {
- return nullptr;
- }
- return &local.annotations.at(name);
- }
- Annotation const * error(detail::Pointer const & where, detail::Pointer const & schema_path,
- std::string const & name) const {
- if (not results_.contains(where)) {
- return nullptr;
- }
- auto const & by_schema = results_.at(where);
- if (not by_schema.contains(schema_path)) {
- return nullptr;
- }
- auto const & local = by_schema.at(schema_path);
- if (not local.errors.contains(name)) {
- return nullptr;
- }
- return &local.errors.at(name);
- }
- private:
- void merge(ValidationResult && result) {
- for (auto && [where, by_schema] : result.results_) {
- for (auto && [schema_path, local] : by_schema) {
- results_[where][schema_path].annotations.merge(local.annotations);
- results_[where][schema_path].errors.merge(local.errors);
- }
- }
- }
- void error(detail::Pointer const & where, detail::Pointer const & schema_path,
- std::string const & name, Annotation message) {
- results_[where][schema_path].errors.emplace(name, std::move(message));
- }
- void annotate(detail::Pointer const & where, detail::Pointer const & schema_path,
- std::string const & name, Annotation message) {
- results_[where][schema_path].annotations.emplace(name, std::move(message));
- }
- };
- }
|