vocabulary.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. #pragma once
  2. #include <functional>
  3. #include <memory>
  4. #include <string_view>
  5. #include <jvalidate/forward.h>
  6. namespace jvalidate::detail {
  7. template <Adapter A> struct ParserContext;
  8. }
  9. namespace jvalidate::vocabulary {
  10. /**
  11. * @brief Metadata tag for marking a keyword as no longer supported. This is
  12. * needed because we store the constraints by version using
  13. * std::map::lower_bound, instead of needing to pound them out for every version
  14. * of the JSON Schema specification.
  15. *
  16. * While it is permitted to reuse keywords that have been removed, it should be
  17. * avoided to minimize confusion.
  18. */
  19. constexpr struct {
  20. } Removed;
  21. constexpr struct {
  22. } Literal;
  23. /**
  24. * @brief Metadata tag for marking a keyword as containing either a single
  25. * subschema, or an array of subschema (e.g. "not", "oneOf", etc.). When parsing
  26. * a schema, we need to be able to identify these to search for "$id" and
  27. * "$anchor" tags, as they can allow us to jump into otherwise unreachable
  28. * sections of the schema.
  29. */
  30. constexpr struct {
  31. } Keyword;
  32. /**
  33. * @brief Metadata tag for marking a keyword as containing a map of names onto
  34. * subschemas (e.g. "properties"). Because the keys in this node of the schema
  35. * are arbitrary strings, we need to jump past them whe searching for the "$id"
  36. * and "$anchor" tags.
  37. * We cannot simply do a blind recursive-walk of the schema JSON, because you
  38. * could put an "$id" tag in an "example" block, where it should not be scanned.
  39. */
  40. constexpr struct {
  41. } KeywordMap;
  42. /**
  43. * @brief Metadata tag for marking a keyword as needing to wait until after all
  44. * other (non-PostConstraint) keywords are validated.
  45. * This tag is used specifically to mark "unevaluatedItems" and
  46. * "unevaluatedProperties", since the rules they use to decide where to run
  47. * cannot be compiled the way that "additionalItems" and "additionalProperties"
  48. * can.
  49. */
  50. constexpr struct {
  51. } PostConstraint;
  52. struct DependentKeyword : std::string_view {};
  53. /**
  54. * @brief This type represents a union of several different "parsing handler"
  55. * states, aligned to a specific starting version:
  56. * A) Annotation keywords
  57. * A.1) Removed - This keyword is no longer supported.
  58. * A.2) Literal - This is a pure annotation. e.g. "$comment".
  59. * A.3) KeywordMap - This keyword does not produce any constraints,
  60. * but must be evaluated for annotations and anchors. e.g. "$defs".
  61. * A.4) DependentKeyword(id) - A keyword whose annotations are only evaluated
  62. * if the depended on keyword is also present in the current schema. It
  63. * may be connected to a constraint, but that constraint will be parsed
  64. * in the depended keyword.
  65. *
  66. * B) Constraint keywords
  67. * B.1) Make - A parser that does not contain any subschemas.
  68. * B.2) Make, Keyword - A parser that contains either a single
  69. * subschema or an array of subschemas. e.g. "not", "oneOf".
  70. * B.3) Make, KeywordMap - A parser that contains a key-value mapping onto
  71. * subschemas. e.g. "properties".
  72. * B.4) Make, PostConstraint - A parser whose constraint applies in
  73. * Unevaluated Locations (11). Assumed to be a single subschema.
  74. */
  75. template <Adapter A> struct Metadata {
  76. using pConstraint = std::unique_ptr<constraint::Constraint>;
  77. Metadata(decltype(Removed)) {}
  78. Metadata(decltype(Literal)) {}
  79. Metadata(decltype(KeywordMap)) : is_keyword(true), is_keyword_map(true) {}
  80. Metadata(DependentKeyword dep) : is_keyword(true) {}
  81. template <typename F> Metadata(F make) : make(make) {}
  82. template <typename F> Metadata(F make, decltype(Keyword)) : make(make), is_keyword(true) {}
  83. template <typename F>
  84. Metadata(F make, decltype(KeywordMap)) : make(make), is_keyword(true), is_keyword_map(true) {}
  85. template <typename F>
  86. Metadata(F make, decltype(PostConstraint))
  87. : make(make), is_keyword(true), is_post_constraint(true) {}
  88. explicit operator bool() const { return make || is_keyword; }
  89. operator std::function<pConstraint(detail::ParserContext<A> const &)>() const { return make; }
  90. std::function<pConstraint(detail::ParserContext<A> const &)> make = nullptr;
  91. bool is_keyword = false;
  92. bool is_keyword_map = false;
  93. bool is_post_constraint = false;
  94. };
  95. }