anchor.h 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. #pragma once
  2. #include <algorithm>
  3. #include <cctype>
  4. #include <compare>
  5. #include <string>
  6. #include <string_view>
  7. #include <jvalidate/compat/compare.h>
  8. #include <jvalidate/detail/expect.h>
  9. namespace jvalidate::detail {
  10. /**
  11. * @brief An Anchor is a simple name that refers to a named location (shorhand)
  12. * in a JSON-schema. As compared to a URI - which can refer to either internal
  13. * starting-points in the active schema or external documents on disk or at an
  14. * external URL-location.
  15. *
  16. * Anchors are useful in cases where there is a complicated or long path to a
  17. * commonly used definition. Consider for example:
  18. * { "$ref": "#/properties/Column/definitions/Row" }
  19. * vs.
  20. * { "$ref": "#ColRow" }
  21. *
  22. * This can be much easier to read, or find an object when doing a quick lookup,
  23. * since editors generally don't have a "lookup this JSON-Pointer" option.
  24. *
  25. * An anchor may only be a plain-name fragment (first character is alpha or '_',
  26. * all other characters are alphanumeric, '_', '.', or '-').
  27. * When defining an anchor using the "$anchor" or "$dynamicAnchor" tags, only
  28. * this fragment is used. When defining an anchor as part of an "$id" tag, the
  29. * form is `<URI>#<ANCHOR>`, the same as when accessing the anchor through a
  30. * "$ref". In the same document - you can reference the anchor by `#<ANCHOR>`,
  31. * just like how you can eschew the URI in a JSON-Pointer within the same doc.
  32. *
  33. * @see https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-01#section-8.2.2
  34. */
  35. class Anchor {
  36. private:
  37. std::string content_;
  38. public:
  39. Anchor() = default;
  40. explicit Anchor(std::string_view content) : content_(content) {
  41. EXPECT_M(content.empty() || content[0] == '_' || std::isalpha(content[0]),
  42. "First character of an Anchor must be alphabetic or '_'");
  43. EXPECT_M(
  44. std::all_of(content.begin(), content.end(),
  45. [](char c) { return std::isalnum(c) || c == '_' || c == '.' || c == '-'; }),
  46. "Illegal character(s) in anchor");
  47. }
  48. explicit operator std::string const &() const { return content_; }
  49. bool empty() const { return content_.empty(); }
  50. friend std::ostream & operator<<(std::ostream & os, Anchor const & self) {
  51. return os << self.content_;
  52. }
  53. auto operator<=>(Anchor const & lhs) const = default;
  54. };
  55. }