| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- #pragma once
- #include <functional>
- #include <memory>
- #include <string_view>
- #include <jvalidate/forward.h>
- namespace jvalidate::detail {
- template <Adapter A> struct ParserContext;
- }
- namespace jvalidate::vocabulary {
- /**
- * @brief Metadata tag for marking a keyword as no longer supported. This is
- * needed because we store the constraints by version using
- * std::map::lower_bound, instead of needing to pound them out for every version
- * of the JSON Schema specification.
- *
- * While it is permitted to reuse keywords that have been removed, it should be
- * avoided to minimize confusion.
- */
- constexpr struct {
- } Removed;
- constexpr struct {
- } Literal;
- /**
- * @brief Metadata tag for marking a keyword as containing either a single
- * subschema, or an array of subschema (e.g. "not", "oneOf", etc.). When parsing
- * a schema, we need to be able to identify these to search for "$id" and
- * "$anchor" tags, as they can allow us to jump into otherwise unreachable
- * sections of the schema.
- */
- constexpr struct {
- } Keyword;
- /**
- * @brief Metadata tag for marking a keyword as containing a map of names onto
- * subschemas (e.g. "properties"). Because the keys in this node of the schema
- * are arbitrary strings, we need to jump past them whe searching for the "$id"
- * and "$anchor" tags.
- * We cannot simply do a blind recursive-walk of the schema JSON, because you
- * could put an "$id" tag in an "example" block, where it should not be scanned.
- */
- constexpr struct {
- } KeywordMap;
- /**
- * @brief Metadata tag for marking a keyword as needing to wait until after all
- * other (non-PostConstraint) keywords are validated.
- * This tag is used specifically to mark "unevaluatedItems" and
- * "unevaluatedProperties", since the rules they use to decide where to run
- * cannot be compiled the way that "additionalItems" and "additionalProperties"
- * can.
- */
- constexpr struct {
- } PostConstraint;
- /**
- * @brief A Metadata tag for marking a keyword as participating as dependent on
- * another keyword in order to generate annotations or validate instances.
- * However - we still must evaluate the keyword for "$id" and "$anchor" tags,
- * since jumping past the keyword is permissible.
- * Currently the only example of this is the handling of "if"/"then"/"else",
- * where the "then" and "else" clauses should not be directly used if the "if"
- * clause is not present in the schema.
- */
- struct DependentKeyword : std::string_view {};
- enum class KeywordType : char { None, Keyword, KeywordMap };
- /**
- * @brief This type represents a union of several different "parsing handler"
- * states, aligned to a specific starting version:
- * A) Annotation keywords
- * A.1) Removed - This keyword is no longer supported.
- * A.2) Literal - This is a pure annotation. e.g. "$comment".
- * A.3) KeywordMap - This keyword does not produce any constraints,
- * but must be evaluated for annotations and anchors. e.g. "$defs".
- * A.4) DependentKeyword(id) - A keyword whose annotations are only evaluated
- * if the depended on keyword is also present in the current schema. It
- * may be connected to a constraint, but that constraint will be parsed
- * in the depended keyword.
- *
- * B) Constraint keywords
- * B.1) Make - A parser that does not contain any subschemas.
- * B.2) Make, Keyword - A parser that contains either a single
- * subschema or an array of subschemas. e.g. "not", "oneOf".
- * B.3) Make, KeywordMap - A parser that contains a key-value mapping onto
- * subschemas. e.g. "properties".
- * B.4) Make, PostConstraint - A parser whose constraint applies in
- * Unevaluated Locations (11). Assumed to be a single subschema.
- */
- template <Adapter A> struct Metadata {
- using pConstraint = std::unique_ptr<constraint::Constraint>;
- Metadata(decltype(Removed)) : valid(false) {}
- Metadata(decltype(Literal)) {}
- Metadata(decltype(KeywordMap)) : type(KeywordType::KeywordMap) {}
- Metadata(DependentKeyword dep) : type(KeywordType::Keyword) {}
- template <typename F> Metadata(F make) : make(make) {}
- template <typename F>
- Metadata(F make, decltype(Keyword)) : make(make), type(KeywordType::Keyword) {}
- template <typename F>
- Metadata(F make, decltype(KeywordMap)) : make(make), type(KeywordType::KeywordMap) {}
- template <typename F>
- Metadata(F make, decltype(PostConstraint))
- : make(make), type(KeywordType::Keyword), is_post_constraint(true) {}
- explicit operator bool() const { return valid; }
- operator std::function<pConstraint(detail::ParserContext<A> const &)>() const { return make; }
- std::function<pConstraint(detail::ParserContext<A> const &)> make = nullptr;
- bool valid = true;
- KeywordType type = KeywordType::None;
- bool is_post_constraint = false;
- };
- }
|