vocabulary.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #pragma once
  2. #include <string_view>
  3. #include <unordered_map>
  4. #include <unordered_set>
  5. #include <jvalidate/enum.h>
  6. #include <jvalidate/forward.h>
  7. namespace jvalidate::detail {
  8. template <Adapter A> struct ParserContext;
  9. template <Adapter A> class Vocabulary {
  10. public:
  11. friend class ConstraintFactory<A>;
  12. using pConstraint = std::unique_ptr<constraint::Constraint>;
  13. using MakeConstraint = std::function<pConstraint(ParserContext<A> const &)>;
  14. private:
  15. schema::Version version_;
  16. std::unordered_map<std::string_view, MakeConstraint> make_;
  17. std::unordered_set<std::string_view> permitted_;
  18. std::unordered_set<std::string> vocabularies_;
  19. // TODO(samjaffe): Migrate this back to constraintsfactory
  20. std::unordered_set<std::string_view> keywords_{"$defs",
  21. "additionalItems",
  22. "additionalProperties",
  23. "allOf",
  24. "anyOf",
  25. "definitions",
  26. "dependencies",
  27. "dependentSchemas",
  28. "else",
  29. "extends",
  30. "if",
  31. "items",
  32. "not",
  33. "oneOf",
  34. "patternProperties",
  35. "prefixItems",
  36. "properties",
  37. "then",
  38. "unevaluatedItems",
  39. "unevaluatedProperties"};
  40. std::unordered_set<std::string_view> property_keywords_{
  41. "$defs", "definitions", "dependencies", "dependentSchemas", "patternProperties",
  42. "properties"};
  43. std::unordered_set<std::string_view> post_constraints_{"unevaluatedItems",
  44. "unevaluatedProperties"};
  45. public:
  46. Vocabulary() = default;
  47. Vocabulary(schema::Version version, std::unordered_map<std::string_view, MakeConstraint> make)
  48. : version_(version), make_(std::move(make)) {
  49. for (auto const & [keyword, _] : make_) {
  50. permitted_.emplace(keyword);
  51. }
  52. }
  53. void restrict(std::unordered_set<std::string> const & permitted_keywords,
  54. std::unordered_set<std::string> const & vocabularies) & {
  55. permitted_.clear();
  56. vocabularies_ = vocabularies;
  57. for (auto const & [keyword, _] : make_) {
  58. if (permitted_keywords.contains(std::string(keyword))) {
  59. permitted_.insert(keyword);
  60. }
  61. }
  62. }
  63. schema::Version version() const { return version_; }
  64. bool is_format_assertion() const {
  65. // In Draft07 and prior - format assertions were considered enabled by
  66. // default. This is - of course - problematic because very few
  67. // implementations actually had full support for format constraints.
  68. if (version_ < schema::Version::Draft2019_09) {
  69. return true;
  70. }
  71. // Some implementations wouldn't even bother with format constraints, and
  72. // others would provide implementations that either missed a number of edge
  73. // cases or were flat-out wrong on certail matters.
  74. // Therefore - starting in Draft 2019-09, the format keyword is an
  75. // annotation by default, instead of an assertion.
  76. if (version_ == schema::Version::Draft2019_09) {
  77. return permitted_.contains("/vocab/format");
  78. }
  79. // Draft 2020-12 makes this even more explicit - having separate vocabulary
  80. // documents for "format as assertion" and "format as annotation". Allowing
  81. // validators to add format constraints that are only used for annotating
  82. // results.
  83. return vocabularies_.contains("/vocab/format-assertion");
  84. }
  85. /**
  86. * @brief Is the given "key"word actually a keyword? As in, would
  87. * I expect to resolve a constraint out of it.
  88. */
  89. bool is_keyword(std::string_view word) const {
  90. return permitted_.contains(word) && make_.contains(word) && keywords_.contains(word);
  91. }
  92. /**
  93. * @brief Does the given "key"word represent a property object - that is to
  94. * say, an object containing some number of schemas mapped by arbitrary keys
  95. */
  96. bool is_property_keyword(std::string_view word) const {
  97. return is_keyword(word) && property_keywords_.contains(word);
  98. }
  99. bool is_constraint(std::string_view word) const {
  100. return permitted_.contains(word) && make_.contains(word) && make_.at(word);
  101. }
  102. auto constraint(std::string_view word, ParserContext<A> const & context) const {
  103. return std::make_pair(is_constraint(word) ? make_.at(word)(context) : nullptr,
  104. post_constraints_.contains(word));
  105. }
  106. };
  107. }