| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465 |
- #pragma once
- #include <algorithm>
- #include <cctype>
- #include <ostream>
- #include <string>
- #include <string_view>
- #include <jvalidate/compat/compare.h> // IWYU pragma: keep
- #include <jvalidate/detail/expect.h>
- namespace jvalidate::detail {
- /**
- * @brief An Anchor is a simple name that refers to a named location (shorhand)
- * in a JSON-schema. As compared to a URI - which can refer to either internal
- * starting-points in the active schema or external documents on disk or at an
- * external URL-location.
- *
- * Anchors are useful in cases where there is a complicated or long path to a
- * commonly used definition. Consider for example:
- * { "$ref": "#/properties/Column/definitions/Row" }
- * vs.
- * { "$ref": "#ColRow" }
- *
- * This can be much easier to read, or find an object when doing a quick lookup,
- * since editors generally don't have a "lookup this JSON-Pointer" option.
- *
- * An anchor may only be a plain-name fragment (first character is alpha or '_',
- * all other characters are alphanumeric, '_', '.', or '-').
- * When defining an anchor using the "$anchor" or "$dynamicAnchor" tags, only
- * this fragment is used. When defining an anchor as part of an "$id" tag, the
- * form is `<URI>#<ANCHOR>`, the same as when accessing the anchor through a
- * "$ref". In the same document - you can reference the anchor by `#<ANCHOR>`,
- * just like how you can eschew the URI in a JSON-Pointer within the same doc.
- *
- * @see https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-01#section-8.2.2
- */
- class Anchor {
- private:
- std::string content_;
- public:
- Anchor() = default;
- explicit Anchor(std::string_view content) : content_(content) {
- EXPECT_M(content.empty() || content[0] == '_' || std::isalpha(content[0]),
- "First character of an Anchor must be alphabetic or '_'");
- EXPECT_M(std::ranges::all_of(content, &Anchor::is_valid_char),
- "Illegal character(s) in anchor");
- }
- explicit operator std::string const &() const { return content_; }
- bool empty() const { return content_.empty(); }
- friend std::ostream & operator<<(std::ostream & os, Anchor const & self) {
- return os << self.content_;
- }
- auto operator<=>(Anchor const & lhs) const = default;
- private:
- // NOLINTNEXTLINE(readability-identifier-length,readability-implicit-bool-conversion)
- static bool is_valid_char(char c) { return std::isalnum(c) || c == '_' || c == '.' || c == '-'; }
- };
- }
|