From 9672a115a3e05a2b2069b4b59837e19a8a443f16 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Wed, 18 Sep 2024 08:22:38 +0300 Subject: [PATCH] Upgrade JSON Toolkit to `e86ad1e3` Signed-off-by: Juan Cruz Viotti --- DEPENDENCIES | 2 +- .../sourcemeta/jsontoolkit/json_object.h | 20 ++- .../sourcemeta/jsontoolkit/jsonpointer.h | 135 +++++++++++++++++- .../jsontoolkit/jsonpointer_pointer.h | 49 +++++++ .../src/jsonpointer/jsonpointer.cc | 86 +++++++++-- vendor/jsontoolkit/src/jsonschema/bundle.cc | 13 +- vendor/jsontoolkit/src/jsonschema/compile.cc | 9 +- .../src/jsonschema/compile_describe.cc | 49 ++++++- .../src/jsonschema/compile_evaluate.cc | 48 ++++++- .../src/jsonschema/compile_helpers.h | 20 +++ .../src/jsonschema/compile_json.cc | 3 + .../src/jsonschema/default_compiler_draft4.h | 101 +++++++++++-- .../jsontoolkit/jsonschema_bundle.h | 8 +- .../jsontoolkit/jsonschema_compile.h | 34 +++-- .../sourcemeta/jsontoolkit/jsonschema_error.h | 14 ++ 15 files changed, 525 insertions(+), 66 deletions(-) diff --git a/DEPENDENCIES b/DEPENDENCIES index 0cce3fe7..d6a42a3f 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -1,5 +1,5 @@ vendorpull https://github.com/sourcemeta/vendorpull dea311b5bfb53b6926a4140267959ae334d3ecf4 noa https://github.com/sourcemeta/noa 7e26abce7a4e31e86a16ef2851702a56773ca527 -jsontoolkit https://github.com/sourcemeta/jsontoolkit 6c78f131029c647be79cc5da5874fa8d50415cde +jsontoolkit https://github.com/sourcemeta/jsontoolkit e86ad1e333c11b6fc2659a0f32ae883ef1040e20 hydra https://github.com/sourcemeta/hydra 3c53d3fdef79e9ba603d48470a508cc45472a0dc alterschema https://github.com/sourcemeta/alterschema a31722f04ae2d7e57f2fe5bbb0613670866c0840 diff --git a/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json_object.h b/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json_object.h index 1330eeec..b9d2b774 100644 --- a/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json_object.h +++ b/vendor/jsontoolkit/src/json/include/sourcemeta/jsontoolkit/json_object.h @@ -35,9 +35,27 @@ template class JSONObject { // Operators // We cannot default given that this class references // a JSON "value" as an incomplete type - auto operator<(const JSONObject &) const noexcept -> bool { + + auto operator<(const JSONObject &other) const noexcept -> bool { + // The `std::unordered_map` container, by definition, does not provide + // ordering. However, we still want some level of ordering to allow + // arrays of objects to be sorted. + + // First try a size comparison + if (this->data.size() != other.data.size()) { + return this->data.size() < other.data.size(); + } + + // Otherwise do value comparison for common properties + for (const auto &[key, value] : this->data) { + if (other.data.contains(key) && value < other.data.at(key)) { + return true; + } + } + return false; } + auto operator<=(const JSONObject &other) const noexcept -> bool { return this->data <= other.data; } diff --git a/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer.h b/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer.h index fe789e60..73196bb3 100644 --- a/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer.h +++ b/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer.h @@ -37,6 +37,10 @@ using WeakPointer = GenericPointer>; /// A global constant instance of the empty JSON Pointer. const Pointer empty_pointer; +/// @ingroup jsonpointer +/// A global constant instance of the empty JSON WeakPointer. +const WeakPointer empty_weak_pointer; + /// @ingroup jsonpointer /// Get a value from a JSON document using a JSON Pointer (`const` overload). /// @@ -59,6 +63,67 @@ const Pointer empty_pointer; SOURCEMETA_JSONTOOLKIT_JSONPOINTER_EXPORT auto get(const JSON &document, const Pointer &pointer) -> const JSON &; +/// @ingroup jsonpointer +/// Get a value from a JSON document using a JSON WeakPointer (`const` +/// overload). +/// +/// ```cpp +/// #include +/// #include +/// #include +/// #include +/// +/// std::istringstream stream{"[ { \"foo\": 1 }, { \"bar\": 2 } ]"}; +/// const sourcemeta::jsontoolkit::JSON document = +/// sourcemeta::jsontoolkit::parse(stream); +/// +/// const std::string bar = "bar"; +/// const sourcemeta::jsontoolkit::WeakPointer pointer{1, std::cref(bar)}; +/// const sourcemeta::jsontoolkit::JSON &value{ +/// sourcemeta::jsontoolkit::get(document, pointer)}; +/// assert(value.is_integer()); +/// assert(value.to_integer() == 2); +/// ``` +SOURCEMETA_JSONTOOLKIT_JSONPOINTER_EXPORT +auto get(const JSON &document, const WeakPointer &pointer) -> const JSON &; + +/// @ingroup jsonpointer +/// Check that a path represented by a JSON Pointer exists in the given +/// document. For example: +/// +/// ```cpp +/// #include +/// #include +/// #include +/// #include +/// +/// std::istringstream stream{"[ { \"foo\": 1 }, { \"bar\": 2 } ]"}; +/// const auto document{sourcemeta::jsontoolkit::parse(stream)}; +/// const sourcemeta::jsontoolkit::Pointer pointer{1, "bar"}; +/// assert(sourcemeta::jsontoolkit::has(document, pointer)); +/// ``` +SOURCEMETA_JSONTOOLKIT_JSONPOINTER_EXPORT +auto has(const JSON &document, const Pointer &pointer) -> bool; + +/// @ingroup jsonpointer +/// Check that a path represented by a JSON WeakPointer exists in the given +/// document. For example: +/// +/// ```cpp +/// #include +/// #include +/// #include +/// #include +/// +/// std::istringstream stream{"[ { \"foo\": 1 }, { \"bar\": 2 } ]"}; +/// const auto document{sourcemeta::jsontoolkit::parse(stream)}; +/// const std::string bar = "bar"; +/// const sourcemeta::jsontoolkit::WeakPointer pointer{1, std::cref(bar)}; +/// assert(sourcemeta::jsontoolkit::has(document, pointer)); +/// ``` +SOURCEMETA_JSONTOOLKIT_JSONPOINTER_EXPORT +auto has(const JSON &document, const WeakPointer &pointer) -> bool; + /// @ingroup jsonpointer /// Get a value from a JSON document using a JSON Pointer (non-`const` /// overload). @@ -98,13 +163,38 @@ auto get(JSON &document, const Pointer &pointer) -> JSON &; /// sourcemeta::jsontoolkit::parse(stream); /// /// const sourcemeta::jsontoolkit::JSON &value{ -/// sourcemeta::jsontoolkit::get(document, "bar")}; +/// sourcemeta::jsontoolkit::get(document, +/// sourcemeta::jsontoolkit::Pointer{"foo"})}; /// assert(value.is_integer()); -/// assert(value.to_integer() == 2); +/// assert(value.to_integer() == 1); /// ``` SOURCEMETA_JSONTOOLKIT_JSONPOINTER_EXPORT auto get(const JSON &document, const Pointer::Token &token) -> const JSON &; +/// @ingroup jsonpointer +/// Get a value from a JSON document using a JSON WeakPointer token (`const` +/// overload). +/// +/// ```cpp +/// #include +/// #include +/// #include +/// #include +/// +/// std::istringstream stream{"{ \"foo\": 1 }"}; +/// const sourcemeta::jsontoolkit::JSON document = +/// sourcemeta::jsontoolkit::parse(stream); +/// +/// const std::string foo = "foo"; +/// const sourcemeta::jsontoolkit::JSON &value{ +/// sourcemeta::jsontoolkit::get(document, +/// sourcemeta::jsontoolkit::WeakPointer{std::cref(foo)})}; +/// assert(value.is_integer()); +/// assert(value.to_integer() == 1); +/// ``` +SOURCEMETA_JSONTOOLKIT_JSONPOINTER_EXPORT +auto get(const JSON &document, const WeakPointer::Token &token) -> const JSON &; + /// @ingroup jsonpointer /// Get a value from a JSON document using a JSON Pointer token (non-`const` /// overload). @@ -233,6 +323,27 @@ auto stringify(const Pointer &pointer, std::basic_ostream &stream) -> void; +/// @ingroup jsonpointer +/// +/// Stringify the input JSON WeakPointer into a given C++ standard output +/// stream. For example: +/// +/// ```cpp +/// #include +/// #include +/// #include +/// +/// const std::string foo = "foo"; +/// const sourcemeta::jsontoolkit::WeakPointer pointer{std::cref(foo)}; +/// std::ostringstream stream; +/// sourcemeta::jsontoolkit::stringify(pointer, stream); +/// std::cout << stream.str() << std::endl; +/// ``` +SOURCEMETA_JSONTOOLKIT_JSONPOINTER_EXPORT +auto stringify(const WeakPointer &pointer, + std::basic_ostream &stream) + -> void; + /// @ingroup jsonpointer /// /// Stringify the input JSON Pointer into a C++ standard string. For example: @@ -251,6 +362,26 @@ auto to_string(const Pointer &pointer) -> std::basic_string>; +/// @ingroup jsonpointer +/// +/// Stringify the input JSON WeakPointer into a C++ standard string. For +/// example: +/// +/// ```cpp +/// #include +/// #include +/// #include +/// +/// const std::string foo = "foo"; +/// const sourcemeta::jsontoolkit::WeakPointer pointer{foo}; +/// const std::string result{sourcemeta::jsontoolkit::to_string(pointer)}; +/// std::cout << result << std::endl; +/// ``` +SOURCEMETA_JSONTOOLKIT_JSONPOINTER_EXPORT +auto to_string(const WeakPointer &pointer) + -> std::basic_string>; + /// @ingroup jsonpointer /// /// Stringify the input JSON Pointer into a properly escaped URI fragment. For diff --git a/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_pointer.h b/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_pointer.h index 44c1ab0a..801021d4 100644 --- a/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_pointer.h +++ b/vendor/jsontoolkit/src/jsonpointer/include/sourcemeta/jsontoolkit/jsonpointer_pointer.h @@ -5,10 +5,12 @@ #include // std::copy, std::equal #include // assert +#include // std::reference_wrapper #include // std::initializer_list #include // std::advance, std::back_inserter #include // std::basic_ostringstream #include // std::runtime_error +#include // std::enable_if_t, std::is_same_v #include // std::move #include // std::vector @@ -238,6 +240,53 @@ template class GenericPointer { std::back_inserter(this->data)); } + /// Push a JSON Pointer into the back of a JSON WeakPointer. Make sure that + /// the pointer you are pushing remains alive for the duration of the + /// WeakPointer. For example: + /// + /// ```cpp + /// #include + /// #include + /// + /// const std::string foo{"foo"}; + /// sourcemeta::jsontoolkit::WeakPointer pointer{std::cref(foo)}; + /// const sourcemeta::jsontoolkit::Pointer other{"bar", "baz"}; + /// pointer.push_back(other); + /// assert(pointer.size() == 3); + /// + /// assert(pointer.at(0).is_property()); + /// assert(pointer.at(1).is_property()); + /// assert(pointer.at(2).is_property()); + /// + /// assert(pointer.at(0).to_property() == "foo"); + /// assert(pointer.at(1).to_property() == "bar"); + /// assert(pointer.at(2).to_property() == "baz"); + /// ``` + template >>> + auto push_back(const GenericPointer &other) -> void { + if (other.empty()) { + return; + } else if (other.size() == 1) { + const auto &token{other.back()}; + if (token.is_property()) { + this->data.emplace_back(token.to_property()); + } else { + this->data.emplace_back(token.to_index()); + } + } else { + this->data.reserve(this->data.size() + other.size()); + for (const auto &token : other) { + if (token.is_property()) { + this->data.emplace_back(token.to_property()); + } else { + this->data.emplace_back(token.to_index()); + } + } + } + } + /// Push a property token into the back of a JSON Pointer. /// For example: /// diff --git a/vendor/jsontoolkit/src/jsonpointer/jsonpointer.cc b/vendor/jsontoolkit/src/jsonpointer/jsonpointer.cc index 9c98c07e..9664ea0d 100644 --- a/vendor/jsontoolkit/src/jsonpointer/jsonpointer.cc +++ b/vendor/jsontoolkit/src/jsonpointer/jsonpointer.cc @@ -13,16 +13,14 @@ #include // std::move namespace { -template