|
@@ -10,9 +10,9 @@
|
|
|
#include <jvalidate/constraint/visitor.h>
|
|
#include <jvalidate/constraint/visitor.h>
|
|
|
#include <jvalidate/detail/expect.h>
|
|
#include <jvalidate/detail/expect.h>
|
|
|
#include <jvalidate/forward.h>
|
|
#include <jvalidate/forward.h>
|
|
|
-#include <jvalidate/result.h>
|
|
|
|
|
#include <jvalidate/schema.h>
|
|
#include <jvalidate/schema.h>
|
|
|
#include <jvalidate/status.h>
|
|
#include <jvalidate/status.h>
|
|
|
|
|
+#include <jvalidate/validation_result.h>
|
|
|
|
|
|
|
|
#define NOOP_UNLESS_TYPE(etype) \
|
|
#define NOOP_UNLESS_TYPE(etype) \
|
|
|
RETURN_UNLESS(document_.type() == adapter::Type::etype, Status::Noop)
|
|
RETURN_UNLESS(document_.type() == adapter::Type::etype, Status::Noop)
|
|
@@ -24,12 +24,13 @@ private:
|
|
|
A document_;
|
|
A document_;
|
|
|
detail::Pointer where_;
|
|
detail::Pointer where_;
|
|
|
schema::Node const & schema_;
|
|
schema::Node const & schema_;
|
|
|
- Result * result_;
|
|
|
|
|
|
|
+ ValidationResult * result_;
|
|
|
|
|
+ ValidationResult * local_result_;
|
|
|
std::unordered_map<std::string, RE> & regex_cache_;
|
|
std::unordered_map<std::string, RE> & regex_cache_;
|
|
|
|
|
|
|
|
public:
|
|
public:
|
|
|
ValidationVisitor(A const & json, schema::Node const & schema,
|
|
ValidationVisitor(A const & json, schema::Node const & schema,
|
|
|
- std::unordered_map<std::string, RE> & regex_cache, Result * result)
|
|
|
|
|
|
|
+ std::unordered_map<std::string, RE> & regex_cache, ValidationResult * result)
|
|
|
: ValidationVisitor(json, schema, {}, regex_cache, result) {}
|
|
: ValidationVisitor(json, schema, {}, regex_cache, result) {}
|
|
|
|
|
|
|
|
Status visit(constraint::TypeConstraint const & cons) const {
|
|
Status visit(constraint::TypeConstraint const & cons) const {
|
|
@@ -42,7 +43,7 @@ public:
|
|
|
|
|
|
|
|
Status visit(constraint::EnumConstraint const & cons) const {
|
|
Status visit(constraint::EnumConstraint const & cons) const {
|
|
|
for (auto const & option : cons.enumeration) {
|
|
for (auto const & option : cons.enumeration) {
|
|
|
- // TODO(samjaffe) Strictness
|
|
|
|
|
|
|
+ // TODO(samjaffe): Strictness
|
|
|
if (option->apply([this](auto const & frozen) { return document_.equals(frozen); })) {
|
|
if (option->apply([this](auto const & frozen) { return document_.equals(frozen); })) {
|
|
|
return Status::Accept;
|
|
return Status::Accept;
|
|
|
}
|
|
}
|
|
@@ -358,15 +359,15 @@ public:
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Status visit(constraint::UnevaluatedItemsConstraint const & cons) const {
|
|
Status visit(constraint::UnevaluatedItemsConstraint const & cons) const {
|
|
|
|
|
+ EXPECT_M(local_result_, "Invalid State - no result object for post-constraint");
|
|
|
NOOP_UNLESS_TYPE(Array);
|
|
NOOP_UNLESS_TYPE(Array);
|
|
|
|
|
|
|
|
Status rval = Status::Accept;
|
|
Status rval = Status::Accept;
|
|
|
auto array = document_.as_array();
|
|
auto array = document_.as_array();
|
|
|
for (size_t i = 0; i < array.size(); ++i) {
|
|
for (size_t i = 0; i < array.size(); ++i) {
|
|
|
- if (not result_->visited_items.contains(i)) {
|
|
|
|
|
|
|
+ if (not local_result_->visited_items.contains(i)) {
|
|
|
rval &= validate_subschema_on(cons.subschema, array[i], i);
|
|
rval &= validate_subschema_on(cons.subschema, array[i], i);
|
|
|
}
|
|
}
|
|
|
- // TODO(samjaffe): Special Rule
|
|
|
|
|
if (!rval && result_ == nullptr) {
|
|
if (!rval && result_ == nullptr) {
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
@@ -374,14 +375,14 @@ public:
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Status visit(constraint::UnevaluatedPropertiesConstraint const & cons) const {
|
|
Status visit(constraint::UnevaluatedPropertiesConstraint const & cons) const {
|
|
|
|
|
+ EXPECT_M(local_result_, "Invalid State - no result object for post-constraint");
|
|
|
NOOP_UNLESS_TYPE(Object);
|
|
NOOP_UNLESS_TYPE(Object);
|
|
|
|
|
|
|
|
Status rval = Status::Accept;
|
|
Status rval = Status::Accept;
|
|
|
for (auto const & [key, elem] : document_.as_object()) {
|
|
for (auto const & [key, elem] : document_.as_object()) {
|
|
|
- if (not result_->visited_properties.contains(key)) {
|
|
|
|
|
|
|
+ if (not local_result_->visited_properties.contains(key)) {
|
|
|
rval &= validate_subschema_on(cons.subschema, elem, key);
|
|
rval &= validate_subschema_on(cons.subschema, elem, key);
|
|
|
}
|
|
}
|
|
|
- // TODO(samjaffe): Special Rule
|
|
|
|
|
if (!rval && result_ == nullptr) {
|
|
if (!rval && result_ == nullptr) {
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
@@ -393,12 +394,13 @@ public:
|
|
|
return Status::Reject;
|
|
return Status::Reject;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- Status rval = Status::Noop;
|
|
|
|
|
- if (schema_.requires_result_context()) {
|
|
|
|
|
|
|
+ ValidationResult local_result;
|
|
|
|
|
+ if (schema_.requires_result_context() && not local_result_) {
|
|
|
// Ensure that we store results even if there aren't any...
|
|
// Ensure that we store results even if there aren't any...
|
|
|
- // TODO(samjaffe) Implement this
|
|
|
|
|
|
|
+ local_result_ = &local_result;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ Status rval = Status::Noop;
|
|
|
if (auto ref = schema_.reference_schema()) {
|
|
if (auto ref = schema_.reference_schema()) {
|
|
|
rval = validate_subschema(*ref);
|
|
rval = validate_subschema(*ref);
|
|
|
}
|
|
}
|
|
@@ -420,25 +422,26 @@ public:
|
|
|
|
|
|
|
|
private:
|
|
private:
|
|
|
ValidationVisitor(A const & json, detail::Pointer const & where, schema::Node const & schema,
|
|
ValidationVisitor(A const & json, detail::Pointer const & where, schema::Node const & schema,
|
|
|
- std::unordered_map<std::string, RE> & regex_cache, Result * result)
|
|
|
|
|
- : document_(json), where_(where), schema_(schema), regex_cache_(regex_cache),
|
|
|
|
|
- result_(result) {}
|
|
|
|
|
-
|
|
|
|
|
- template <typename K> Status validate(A const & document, K const & key) const {
|
|
|
|
|
- return validate_subschema_on(&schema_, document_, key);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ std::unordered_map<std::string, RE> & regex_cache, ValidationResult * result,
|
|
|
|
|
+ ValidationResult * local_result = nullptr)
|
|
|
|
|
+ : document_(json), where_(where), schema_(schema), regex_cache_(regex_cache), result_(result),
|
|
|
|
|
+ local_result_(local_result ?: result_) {}
|
|
|
|
|
|
|
|
Status validate_subschema(schema::Node const * subschema) const {
|
|
Status validate_subschema(schema::Node const * subschema) const {
|
|
|
- // TODO(samjaffe): Propagation for Unevaluated*Constraint
|
|
|
|
|
- return CRTP(document_, *subschema, where_, regex_cache_, result_).validate();
|
|
|
|
|
|
|
+ return CRTP(document_, *subschema, where_, regex_cache_, result_, local_result_).validate();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template <typename K>
|
|
template <typename K>
|
|
|
Status validate_subschema_on(schema::Node const * subschema, A const & document,
|
|
Status validate_subschema_on(schema::Node const * subschema, A const & document,
|
|
|
K const & key) const {
|
|
K const & key) const {
|
|
|
- Result next;
|
|
|
|
|
- Result * pnext = result_ ? &next : nullptr;
|
|
|
|
|
- return CRTP(document, *subschema, where_ / key, regex_cache_, pnext).validate();
|
|
|
|
|
|
|
+ ValidationResult next;
|
|
|
|
|
+ ValidationResult * pnext = result_ ? &next : nullptr;
|
|
|
|
|
+
|
|
|
|
|
+ auto status = CRTP(document, *subschema, where_ / key, regex_cache_, pnext).validate();
|
|
|
|
|
+ if (status != Status::Noop and local_result_) {
|
|
|
|
|
+ local_result_->record(key);
|
|
|
|
|
+ }
|
|
|
|
|
+ return status;
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|