| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- #pragma once
- #include <jvalidate/_config.h> // IWYU pragma: keep
- #include <jvalidate/_macro.h>
- #include <jvalidate/detail/expect.h>
- #include <jvalidate/detail/on_block_exit.h>
- #include <jvalidate/forward.h>
- #include <jvalidate/regex.h>
- #include <jvalidate/validation_config.h>
- #include <jvalidate/validation_visitor.h>
- namespace jvalidate::detail {
- /**
- * @brief An implementation of an "Extension Constraint Visitor" plugin that
- * does nothing.
- */
- struct StubExtensionVisitor {};
- }
- namespace jvalidate {
- /**
- * @brief A validator is the tool by which a JSON object is actually validated
- * against a schema.
- *
- * @tparam RE A type that can be used to solve regular expressions
- */
- template <RegexEngine RE = JVALIDATE_IIF(JVALIDATE_HAS_ICU, ICURegexEngine, StdRegexEngine),
- typename ExtensionVisitor = detail::StubExtensionVisitor>
- class Validator {
- private:
- schema::Node const & schema_;
- ValidationConfig cfg_;
- ExtensionVisitor extension_{};
- RE regex_{};
- FormatValidator format_{RE::is_regex};
- public:
- /**
- * @brief Construct a Validator
- *
- * @param schema The root schema being validated against. Must outlive this.
- *
- * @param cfg Any special (runtime) configuration rules being applied to the
- * validator.
- */
- explicit Validator(schema::Node const & schema, ValidationConfig const & cfg = {})
- : schema_(schema), cfg_(cfg) {}
- /**
- * @brief Construct a Validator
- *
- * @param schema The root schema being validated against. Must outlive this.
- *
- * @param extension An extension visitor for processing user-defined
- * constraints
- *
- * @param cfg Any special (runtime) configuration rules being applied to the
- * validator.
- */
- explicit Validator(schema::Node const & schema, ExtensionVisitor extension,
- ValidationConfig const & cfg = {})
- : schema_(schema), cfg_(cfg), extension_(extension) {}
- /**
- * @brief Construct a Validator
- *
- * @param schema The root schema being validated against. Must outlive this.
- *
- * @param user_defined_formats A map of format-name to string validator for
- * user-defined format tools.
- *
- * @param cfg Any special (runtime) configuration rules being applied to the
- * validator. Because user_defined_formats is provided by this constructor,
- * we default to validate_format:=true.
- */
- Validator(schema::Node const & schema,
- FormatValidator::UserDefinedFormats const & user_defined_formats,
- ValidationConfig const & cfg = {.validate_format = true})
- : schema_(schema), cfg_(cfg), format_(user_defined_formats, RE::is_regex) {}
- /**
- * @brief Construct a Validator
- *
- * @param schema The root schema being validated against. Must outlive this.
- *
- * @param extension An extension visitor for processing user-defined
- * constraints
- *
- * @param user_defined_formats A map of format-name to string validator for
- * user-defined format tools.
- *
- * @param cfg Any special (runtime) configuration rules being applied to the
- * validator. Because user_defined_formats is provided by this constructor,
- * we default to validate_format:=true.
- */
- Validator(schema::Node const & schema, ExtensionVisitor extension,
- FormatValidator::UserDefinedFormats const & user_defined_formats,
- ValidationConfig const & cfg = {.validate_format = true})
- : schema_(schema), cfg_(cfg), extension_(extension),
- format_(user_defined_formats, RE::is_regex) {}
- template <typename... Args> Validator(schema::Node &&, Args &&...) = delete;
- /**
- * @brief Run validation on the given JSON
- *
- * @tparam A Any Adapter type, in principle a subclass of adapter::Adapter.
- * Disallows mutation via ValidationConfig.construct_default_values
- *
- * @param json The value being validated
- *
- * @param result An optional out-param of detailed information about
- * validation failures. If result is not provided, then the validator will
- * terminate on the first error. Otherwise it will run through the entire
- * schema to provide a record of all of the failures.
- */
- template <Adapter A>
- requires(not MutableAdapter<A>)
- bool validate(A const & json, ValidationResult * result = nullptr) {
- EXPECT_M(not cfg_.construct_default_values,
- "Cannot perform mutations on an immutable JSON Adapter");
- detail::OnBlockExit const _ = [&result, this]() { post_process(result); };
- ValidationVisitor visitor(schema_, json, cfg_, regex_, format_, extension_, result);
- return static_cast<bool>(visitor.validate(json));
- }
- /**
- * @brief Run validation on the given JSON
- *
- * @tparam A Any Adapter type that supports assignment, in principle a
- * subclass of adapter::Adapter.
- *
- * @param json The value being validated. Because A is a reference-wrapper,
- * the underlying value may be mutated.
- *
- * @param result An optional out-param of detailed information about
- * validation failures. If result is not provided, then the validator will
- * terminate on the first error. Otherwise it will run through the entire
- * schema to provide a record of all of the failures.
- */
- template <MutableAdapter A> bool validate(A const & json, ValidationResult * result = nullptr) {
- detail::OnBlockExit const _ = [&result, this]() { post_process(result); };
- ValidationVisitor visitor(schema_, json, cfg_, regex_, format_, extension_, result);
- return static_cast<bool>(visitor.validate(json));
- }
- /**
- * @brief Run validation on the given JSON
- *
- * @tparam JSON A concrete JSON type. Will be turned into an Adapter, or a
- * MutableAdapter (if json is non-const and exists).
- *
- * @param json The value being validated.
- *
- * @param result An optional out-param of detailed information about
- * validation failures. If result is not provided, then the validator will
- * terminate on the first error. Otherwise it will run through the entire
- * schema to provide a record of all of the failures.
- */
- template <typename JSON>
- requires(not Adapter<JSON>)
- bool validate(JSON & json, ValidationResult * result = nullptr) {
- return validate(adapter::AdapterFor<JSON>(json), result);
- }
- private:
- void post_process(ValidationResult *& result) const {
- if (result == nullptr) {
- return;
- }
- if (cfg_.only_return_results_with_error) {
- *result = result->only_errors();
- }
- }
- };
- }
|