From b0182d7f0e5a035cf0af9c9d0e202da51f31e95a Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Thu, 30 Jan 2025 14:22:07 -0400 Subject: [PATCH] Upgrade Core to `47ba2307b9bfab9fb378386207b3172c97ed1363` (#208) Signed-off-by: Juan Cruz Viotti --- DEPENDENCIES | 2 +- .../core/src/core/jsonschema/CMakeLists.txt | 2 +- vendor/core/src/core/jsonschema/bundle.cc | 2 +- .../include/sourcemeta/core/jsonschema.h | 112 +++++++++++++----- .../sourcemeta/core/jsonschema_bundle.h | 4 +- .../sourcemeta/core/jsonschema_frame.h | 2 +- .../sourcemeta/core/jsonschema_resolver.h | 8 +- .../sourcemeta/core/jsonschema_transform.h | 2 +- .../sourcemeta/core/jsonschema_unevaluated.h | 4 +- .../sourcemeta/core/jsonschema_walker.h | 8 +- vendor/core/src/core/jsonschema/jsonschema.cc | 80 ++++++++++++- .../core/jsonschema/official_resolver.in.cc | 2 +- vendor/core/src/core/jsonschema/relativize.cc | 49 -------- vendor/core/src/core/jsonschema/resolver.cc | 15 ++- .../include/sourcemeta/core/alterschema.h | 2 +- 15 files changed, 191 insertions(+), 103 deletions(-) delete mode 100644 vendor/core/src/core/jsonschema/relativize.cc diff --git a/DEPENDENCIES b/DEPENDENCIES index 6320bfe..62b0675 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -1,5 +1,5 @@ vendorpull https://github.com/sourcemeta/vendorpull 70342aaf458e6cb80baeb5b718901075fc42ede6 -core https://github.com/sourcemeta/core 1257bcddc2797de7c95dedefebf6c2fb1e00717a +core https://github.com/sourcemeta/core 47ba2307b9bfab9fb378386207b3172c97ed1363 bearssl https://www.bearssl.org/git/BearSSL 8ef7680081c61b486622f2d983c0d3d21e83caad zlib https://github.com/madler/zlib 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf uwebsockets https://github.com/uNetworking/uWebSockets v20.72.0 diff --git a/vendor/core/src/core/jsonschema/CMakeLists.txt b/vendor/core/src/core/jsonschema/CMakeLists.txt index 228b279..34ce264 100644 --- a/vendor/core/src/core/jsonschema/CMakeLists.txt +++ b/vendor/core/src/core/jsonschema/CMakeLists.txt @@ -8,7 +8,7 @@ sourcemeta_library(NAMESPACE sourcemeta PROJECT core NAME jsonschema keywords.h transform.h SOURCES jsonschema.cc default_walker.cc frame.cc resolver.cc walker.cc bundle.cc - unevaluated.cc relativize.cc unidentify.cc + unevaluated.cc unidentify.cc transform_rule.cc transformer.cc "${CMAKE_CURRENT_BINARY_DIR}/official_resolver.cc") diff --git a/vendor/core/src/core/jsonschema/bundle.cc b/vendor/core/src/core/jsonschema/bundle.cc index 11e4fdb..9db37f5 100644 --- a/vendor/core/src/core/jsonschema/bundle.cc +++ b/vendor/core/src/core/jsonschema/bundle.cc @@ -48,7 +48,7 @@ auto is_official_metaschema_reference(const sourcemeta::core::Pointer &pointer, const std::string &destination) -> bool { return !pointer.empty() && pointer.back().is_property() && pointer.back().to_property() == "$schema" && - sourcemeta::core::official_resolver(destination).has_value(); + sourcemeta::core::schema_official_resolver(destination).has_value(); } auto bundle_schema(sourcemeta::core::JSON &root, const std::string &container, diff --git a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema.h b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema.h index cd54175..b36615a 100644 --- a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema.h +++ b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema.h @@ -15,9 +15,10 @@ #include #include -#include // std::map -#include // std::optional -#include // std::string +#include // std::function +#include // std::map +#include // std::optional +#include // std::string /// @defgroup jsonschema JSON Schema /// @brief A set of JSON Schema utilities across draft versions. @@ -73,7 +74,7 @@ enum class SchemaIdentificationStrategy : std::uint8_t { /// })JSON"); /// /// std::optional id{sourcemeta::core::identify( -/// document, sourcemeta::core::official_resolver)}; +/// document, sourcemeta::core::schema_official_resolver)}; /// assert(id.has_value()); /// assert(id.value() == "https://sourcemeta.com/example-schema"); /// ``` @@ -120,7 +121,7 @@ auto identify(const JSON &schema, const std::string &base_dialect, /// "https://json-schema.org/draft/2020-12/schema"); /// /// std::optional id{sourcemeta::core::identify( -/// document, sourcemeta::core::official_resolver)}; +/// document, sourcemeta::core::schema_official_resolver)}; /// assert(!id.has_value()); /// ``` SOURCEMETA_CORE_JSONSCHEMA_EXPORT @@ -144,10 +145,10 @@ auto anonymize(JSON &schema, const std::string &base_dialect) -> void; /// /// sourcemeta::core::reidentify(document, /// "https://example.com/my-new-id", -/// sourcemeta::core::official_resolver); +/// sourcemeta::core::schema_official_resolver); /// /// std::optional id{sourcemeta::core::identify( -/// document, sourcemeta::core::official_resolver)}; +/// document, sourcemeta::core::schema_official_resolver)}; /// assert(id.has_value()); /// assert(id.value() == "https://example.com/my-new-id"); /// ``` @@ -209,7 +210,7 @@ auto dialect(const JSON &schema, /// /// const sourcemeta::core::JSON metaschema{ /// sourcemeta::core::metaschema( -/// document, sourcemeta::core::official_resolver)}; +/// document, sourcemeta::core::schema_official_resolver)}; /// /// sourcemeta::core::prettify(metaschema, std::cout); /// std::cout << std::endl; @@ -241,7 +242,7 @@ auto metaschema( /// /// const std::optional base_dialect{ /// sourcemeta::core::base_dialect( -/// document, sourcemeta::core::official_resolver)}; +/// document, sourcemeta::core::schema_official_resolver)}; /// /// assert(base_dialect.has_value()); /// assert(base_dialect.value() == @@ -274,7 +275,7 @@ auto base_dialect(const JSON &schema, const SchemaResolver &resolver, /// /// const std::map vocabularies{ /// sourcemeta::core::vocabularies( -/// document, sourcemeta::core::official_resolver)}; +/// document, sourcemeta::core::schema_official_resolver)}; /// /// assert(vocabularies.at("https://json-schema.org/draft/2020-12/vocab/core")); /// assert(vocabularies.at("https://json-schema.org/draft/2020-12/vocab/applicator")); @@ -323,8 +324,8 @@ auto schema_format_compare(const JSON::String &left, const JSON::String &right) /// @ingroup jsonschema /// -/// Try to turn every possible absolute reference in a schema into a relative -/// one. For example: +/// Remove every identifer from a schema, rephrasing references (if any) as +/// needed. For example: /// /// ```cpp /// #include @@ -335,32 +336,42 @@ auto schema_format_compare(const JSON::String &left, const JSON::String &right) /// sourcemeta::core::parse_json(R"JSON({ /// "$id": "https://www.example.com/schema", /// "$schema": "https://json-schema.org/draft/2020-12/schema", -/// "$ref": "https://www.example.com/another", +/// "$ref": "another", /// })JSON"); /// -/// sourcemeta::core::relativize(schema, +/// sourcemeta::core::unidentify(schema, /// sourcemeta::core::schema_official_walker, -/// sourcemeta::core::official_resolver); +/// sourcemeta::core::schema_official_resolver); /// /// const sourcemeta::core::JSON expected = /// sourcemeta::core::parse_json(R"JSON({ -/// "$id": "https://www.example.com/schema", /// "$schema": "https://json-schema.org/draft/2020-12/schema", -/// "$ref": "another", +/// "$ref": "https://www.example.com/another", /// })JSON"); /// /// assert(schema == expected); /// ``` SOURCEMETA_CORE_JSONSCHEMA_EXPORT -auto relativize( +auto unidentify( JSON &schema, const SchemaWalker &walker, const SchemaResolver &resolver, - const std::optional &default_dialect = std::nullopt, - const std::optional &default_id = std::nullopt) -> void; + const std::optional &default_dialect = std::nullopt) -> void; /// @ingroup jsonschema /// -/// Remove every identifer from a schema, rephrasing references (if any) as -/// needed. For example: +/// Visit every reference in a schema. The arguments are as follows: +/// +/// - The current subschema +/// - The base URI of the current subschema +/// - The reference vocabulary +/// - The reference keyword name +/// - The reference reference destination +using SchemaVisitorReference = std::function; + +/// @ingroup jsonschema +/// +/// A reference visitor to try to turn every possible absolute reference in a +/// schema into a relative one. For example: /// /// ```cpp /// #include @@ -371,25 +382,70 @@ auto relativize( /// sourcemeta::core::parse_json(R"JSON({ /// "$id": "https://www.example.com/schema", /// "$schema": "https://json-schema.org/draft/2020-12/schema", -/// "$ref": "another", +/// "$ref": "https://www.example.com/another", /// })JSON"); /// -/// sourcemeta::core::unidentify(schema, +/// sourcemeta::core::reference_visit(schema, /// sourcemeta::core::schema_official_walker, -/// sourcemeta::core::official_resolver); +/// sourcemeta::core::schema_official_resolver, +/// sourcemeta::core::reference_visitor_relativize); /// /// const sourcemeta::core::JSON expected = /// sourcemeta::core::parse_json(R"JSON({ +/// "$id": "https://www.example.com/schema", /// "$schema": "https://json-schema.org/draft/2020-12/schema", -/// "$ref": "https://www.example.com/another", +/// "$ref": "another", /// })JSON"); /// /// assert(schema == expected); /// ``` SOURCEMETA_CORE_JSONSCHEMA_EXPORT -auto unidentify( +auto reference_visitor_relativize(JSON &subschema, const URI &base, + const JSON::String &vocabulary, + const JSON::String &keyword, URI &value) + -> void; + +/// @ingroup jsonschema +/// +/// A utility function to loop over every reference in a schema, allowing +/// modifications to their subschemas if desired. Note that the consumer is +/// responsible for not making the schema invalid. For example: +/// +/// ```cpp +/// #include +/// #include +/// +/// sourcemeta::core::JSON schema = +/// sourcemeta::core::parse_json(R"JSON({ +/// "$id": "https://www.example.com/schema", +/// "$schema": "https://json-schema.org/draft/2020-12/schema", +/// "$ref": "https://www.example.com/another", +/// })JSON"); +/// +/// static auto visitor(JSON &subschema, +/// const URI &base, +/// const JSON::String &vocabulary, +/// const JSON::String &keyword, +/// URI &value) -> void { +/// sourcemeta::core::prettify(subschema, std::cerr); +/// std::cerr << "\n"; +/// std::cerr << base.recompose() << "\n"; +/// std::cerr << vocabulary << "\n"; +/// std::cerr << keyword << "\n"; +/// std::cerr << value.recompose() << "\n"; +/// } +/// +/// sourcemeta::core::reference_visit(schema, +/// sourcemeta::core::schema_official_walker, +/// sourcemeta::core::schema_official_resolver, +/// visitor); +/// ``` +SOURCEMETA_CORE_JSONSCHEMA_EXPORT +auto reference_visit( JSON &schema, const SchemaWalker &walker, const SchemaResolver &resolver, - const std::optional &default_dialect = std::nullopt) -> void; + const SchemaVisitorReference &callback, + const std::optional &default_dialect = std::nullopt, + const std::optional &default_id = std::nullopt) -> void; } // namespace sourcemeta::core diff --git a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_bundle.h b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_bundle.h index 0003ff6..cff5c3d 100644 --- a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_bundle.h +++ b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_bundle.h @@ -38,7 +38,7 @@ namespace sourcemeta::core { /// "type": "string" /// })JSON"); /// } else { -/// return sourcemeta::core::official_resolver(identifier); +/// return sourcemeta::core::schema_official_resolver(identifier); /// } /// } /// @@ -94,7 +94,7 @@ auto bundle(sourcemeta::core::JSON &schema, const SchemaWalker &walker, /// "type": "string" /// })JSON"); /// } else { -/// return sourcemeta::core::official_resolver(identifier); +/// return sourcemeta::core::schema_official_resolver(identifier); /// } /// } /// diff --git a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h index 98adfda..e302fff 100644 --- a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h +++ b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h @@ -47,7 +47,7 @@ namespace sourcemeta::core { /// sourcemeta::core::SchemaSchemaFrame frame; /// frame.analyse(document, /// sourcemeta::core::schema_official_walker, -/// sourcemeta::core::official_resolver); +/// sourcemeta::core::schema_official_resolver); /// /// // IDs /// assert(frame.locations().contains({sourcemeta::core::SchemaReferenceType::Static, diff --git a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_resolver.h b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_resolver.h index a727087..16d75e3 100644 --- a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_resolver.h +++ b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_resolver.h @@ -24,7 +24,7 @@ namespace sourcemeta::core { /// /// For convenience, we provide the following default resolvers: /// -/// - sourcemeta::core::official_resolver +/// - sourcemeta::core::schema_official_resolver /// /// You can implement resolvers to read from a local storage, to send HTTP /// requests, or anything your application might require. Unless your resolver @@ -35,7 +35,7 @@ using SchemaResolver = std::function(std::string_view)>; /// @ingroup jsonschema /// A default resolver that relies on built-in official schemas. SOURCEMETA_CORE_JSONSCHEMA_EXPORT -auto official_resolver(std::string_view identifier) +auto schema_official_resolver(std::string_view identifier) -> std::optional; /// @ingroup jsonschema @@ -48,7 +48,7 @@ auto official_resolver(std::string_view identifier) /// /// // (1) Create a map resolver that falls back to the official resolver /// sourcemeta::core::SchemaMapResolver -/// resolver{sourcemeta::core::official_resolver}; +/// resolver{sourcemeta::core::schema_official_resolver}; /// /// const sourcemeta::core::JSON schema = /// sourcemeta::core::parse_json(R"JSON({ @@ -105,7 +105,7 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaMapResolver { /// /// // (1) Create a flat file resolver that falls back to the official resolver /// sourcemeta::core::SchemaFlatFileResolver -/// resolver{sourcemeta::core::official_resolver}; +/// resolver{sourcemeta::core::schema_official_resolver}; /// /// // (2) Register a schema by path /// resolver.add("path/to/example.schema.json"); diff --git a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h index 33a67d5..862ebb2 100644 --- a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h +++ b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h @@ -164,7 +164,7 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaTransformRule { /// /// // Apply the transformation bundle to the schema /// bundle.apply(schema, sourcemeta::core::schema_official_walker, -/// sourcemeta::core::official_resolver); +/// sourcemeta::core::schema_official_resolver); /// /// // `foo` keywords are gone /// assert(!schema.defines("foo")); diff --git a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_unevaluated.h b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_unevaluated.h index 674b6d9..b8cee85 100644 --- a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_unevaluated.h +++ b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_unevaluated.h @@ -57,11 +57,11 @@ using SchemaUnevaluatedEntries = std::map; /// sourcemeta::core::SchemaSchemaFrame frame; /// frame.analyse(document, /// sourcemeta::core::schema_official_walker, -/// sourcemeta::core::official_resolver); +/// sourcemeta::core::schema_official_resolver); /// const auto result{sourcemeta::core::unevaluated( /// schema, frame, /// sourcemeta::core::schema_official_walker, -/// sourcemeta::core::official_resolver)}; +/// sourcemeta::core::schema_official_resolver)}; /// /// assert(result.contains("#/unevaluatedProperties")); /// assert(!result.at("#/unevaluatedProperties").dynamic); diff --git a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_walker.h b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_walker.h index 1da28db..c8d7706 100644 --- a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_walker.h +++ b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_walker.h @@ -97,7 +97,7 @@ struct SchemaIteratorEntry { /// for (const auto &entry : /// sourcemeta::core::SchemaIterator{ /// document, sourcemeta::core::schema_official_walker, -/// sourcemeta::core::official_resolver}) { +/// sourcemeta::core::schema_official_resolver}) { /// sourcemeta::core::prettify( /// sourcemeta::core::get(document, entry.pointer), std::cout); /// std::cout << "\n"; @@ -164,7 +164,7 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaIterator { /// for (const auto &entry : /// sourcemeta::core::SchemaIteratorFlat{ /// document, sourcemeta::core::schema_official_walker, -/// sourcemeta::core::official_resolver}) { +/// sourcemeta::core::schema_official_resolver}) { /// sourcemeta::core::prettify( /// sourcemeta::core::get(document, entry.pointer), std::cout); /// std::cout << "\n"; @@ -222,7 +222,7 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaIteratorFlat { /// /// const auto vocabularies{ /// sourcemeta::core::vocabularies( -/// document, sourcemeta::core::official_resolver)}; +/// document, sourcemeta::core::schema_official_resolver)}; /// /// assert(sourcemeta::core::schema_keyword_priority( /// "prefixItems", vocabularies, @@ -261,7 +261,7 @@ auto SOURCEMETA_CORE_JSONSCHEMA_EXPORT schema_keyword_priority( /// for (const auto &entry : /// sourcemeta::core::SchemaKeywordIterator{ /// document, sourcemeta::core::schema_official_walker, -/// sourcemeta::core::official_resolver}) { +/// sourcemeta::core::schema_official_resolver}) { /// sourcemeta::core::stringify(entry.pointer, std::cout); /// std::cout << "\n"; /// } diff --git a/vendor/core/src/core/jsonschema/jsonschema.cc b/vendor/core/src/core/jsonschema/jsonschema.cc index 34e2d59..cbda45b 100644 --- a/vendor/core/src/core/jsonschema/jsonschema.cc +++ b/vendor/core/src/core/jsonschema/jsonschema.cc @@ -9,6 +9,8 @@ #include // std::remove_reference_t #include // std::move +#include + auto sourcemeta::core::is_schema(const sourcemeta::core::JSON &schema) -> bool { return schema.is_object() || schema.is_boolean(); } @@ -96,7 +98,17 @@ auto sourcemeta::core::identify( return default_id; } - return identify(schema, maybe_base_dialect.value(), default_id); + const auto result{identify(schema, maybe_base_dialect.value(), default_id)}; + + // A last shot supporting identifiers alongside `$ref` in loose mode + if (!result.has_value() && strategy == SchemaIdentificationStrategy::Loose) { + const auto keyword{id_keyword(maybe_base_dialect.value())}; + if (schema.defines(keyword) && schema.at(keyword).is_string()) { + return schema.at(keyword).to_string(); + } + } + + return result; } auto sourcemeta::core::identify(const JSON &schema, @@ -108,6 +120,7 @@ auto sourcemeta::core::identify(const JSON &schema, } const auto keyword{id_keyword(base_dialect)}; + if (!schema.defines(keyword)) { return default_id; } @@ -547,3 +560,68 @@ auto sourcemeta::core::schema_format_compare( return left < right; } } + +auto sourcemeta::core::reference_visit( + sourcemeta::core::JSON &schema, + const sourcemeta::core::SchemaWalker &walker, + const sourcemeta::core::SchemaResolver &resolver, + const sourcemeta::core::SchemaVisitorReference &callback, + const std::optional &default_dialect, + const std::optional &default_id) -> void { + sourcemeta::core::SchemaFrame frame; + frame.analyse(schema, walker, resolver, default_dialect, default_id); + for (const auto &entry : frame.locations()) { + if (entry.second.type != + sourcemeta::core::SchemaFrame::LocationType::Resource && + entry.second.type != + sourcemeta::core::SchemaFrame::LocationType::Subschema) { + continue; + } + + auto &subschema{sourcemeta::core::get(schema, entry.second.pointer)}; + assert(sourcemeta::core::is_schema(subschema)); + if (!subschema.is_object()) { + continue; + } + + const sourcemeta::core::URI base{entry.second.base}; + // Assume the base is canonicalized already + assert( + sourcemeta::core::URI{entry.second.base}.canonicalize().recompose() == + base.recompose()); + for (const auto &property : subschema.as_object()) { + const auto walker_result{ + walker(property.first, frame.vocabularies(entry.second, resolver))}; + if (walker_result.type != + sourcemeta::core::SchemaKeywordType::Reference || + !property.second.is_string()) { + continue; + } + + assert(property.second.is_string()); + assert(walker_result.vocabulary.has_value()); + sourcemeta::core::URI reference{property.second.to_string()}; + callback(subschema, base, walker_result.vocabulary.value(), + property.first, reference); + } + } +} + +auto sourcemeta::core::reference_visitor_relativize( + sourcemeta::core::JSON &subschema, const sourcemeta::core::URI &base, + const sourcemeta::core::JSON::String &vocabulary, + const sourcemeta::core::JSON::String &keyword, URI &reference) -> void { + // In 2019-09, `$recursiveRef` can only be `#`, so there + // is nothing else we can possibly do + if (vocabulary == "https://json-schema.org/draft/2019-09/vocab/core" && + keyword == "$recursiveRef") { + return; + } + + reference.relative_to(base); + reference.canonicalize(); + + if (reference.is_relative()) { + subschema.assign(keyword, sourcemeta::core::JSON{reference.recompose()}); + } +} diff --git a/vendor/core/src/core/jsonschema/official_resolver.in.cc b/vendor/core/src/core/jsonschema/official_resolver.in.cc index 91fbbe6..64e7759 100644 --- a/vendor/core/src/core/jsonschema/official_resolver.in.cc +++ b/vendor/core/src/core/jsonschema/official_resolver.in.cc @@ -1,6 +1,6 @@ #include -auto sourcemeta::core::official_resolver(std::string_view identifier) +auto sourcemeta::core::schema_official_resolver(std::string_view identifier) -> std::optional { // JSON Schema 2020-12 if (identifier == "https://json-schema.org/draft/2020-12/schema") { diff --git a/vendor/core/src/core/jsonschema/relativize.cc b/vendor/core/src/core/jsonschema/relativize.cc deleted file mode 100644 index 809dcca..0000000 --- a/vendor/core/src/core/jsonschema/relativize.cc +++ /dev/null @@ -1,49 +0,0 @@ -#include - -namespace sourcemeta::core { - -auto relativize(JSON &schema, const SchemaWalker &walker, - const SchemaResolver &resolver, - const std::optional &default_dialect, - const std::optional &default_id) -> void { - SchemaFrame frame; - frame.analyse(schema, walker, resolver, default_dialect, default_id); - - for (const auto &entry : frame.locations()) { - if (entry.second.type != SchemaFrame::LocationType::Resource && - entry.second.type != SchemaFrame::LocationType::Subschema) { - continue; - } - - auto &subschema{get(schema, entry.second.pointer)}; - assert(is_schema(subschema)); - if (!subschema.is_object()) { - continue; - } - - const auto base{URI{entry.second.base}.canonicalize()}; - for (const auto &property : subschema.as_object()) { - if (walker(property.first, frame.vocabularies(entry.second, resolver)) - .type != SchemaKeywordType::Reference || - !property.second.is_string()) { - continue; - } - - // In 2019-09, `$recursiveRef` can only be `#`, so there - // is nothing else we can possibly do - if (property.first == "$recursiveRef") { - continue; - } - - URI reference{property.second.to_string()}; - reference.relative_to(base); - reference.canonicalize(); - - if (reference.is_relative()) { - subschema.assign(property.first, JSON{reference.recompose()}); - } - } - } -} - -} // namespace sourcemeta::core diff --git a/vendor/core/src/core/jsonschema/resolver.cc b/vendor/core/src/core/jsonschema/resolver.cc index 4b70602..eec5bc3 100644 --- a/vendor/core/src/core/jsonschema/resolver.cc +++ b/vendor/core/src/core/jsonschema/resolver.cc @@ -101,7 +101,7 @@ auto SchemaFlatFileResolver::add( const auto identifier{sourcemeta::core::identify( schema, *this, SchemaIdentificationStrategy::Loose, default_dialect, default_id)}; - if (!identifier.has_value()) { + if (!identifier.has_value() && !default_id.has_value()) { std::ostringstream error; error << "Cannot identify schema: " << canonical.string(); throw SchemaError(error.str()); @@ -109,7 +109,9 @@ auto SchemaFlatFileResolver::add( // Filesystems behave differently with regards to casing. To unify // them, assume they are case-insensitive. - const auto effective_identifier{to_lowercase(identifier.value())}; + const auto effective_identifier{to_lowercase( + default_id.has_value() ? identifier.value_or(default_id.value()) + : identifier.value())}; const auto result{this->schemas.emplace( effective_identifier, @@ -117,7 +119,7 @@ auto SchemaFlatFileResolver::add( if (!result.second && result.first->second.path != canonical) { std::ostringstream error; error << "Cannot register the same identifier twice: " - << identifier.value(); + << effective_identifier; throw SchemaError(error.str()); } @@ -150,9 +152,10 @@ auto SchemaFlatFileResolver::operator()(std::string_view identifier) const *this, result->second.default_dialect); // Because we allow re-identification, we can get into issues unless we // always try to relativize references - sourcemeta::core::relativize(schema, schema_official_walker, *this, - result->second.default_dialect, - result->second.original_identifier); + sourcemeta::core::reference_visit( + schema, schema_official_walker, *this, + sourcemeta::core::reference_visitor_relativize, + result->second.default_dialect, result->second.original_identifier); sourcemeta::core::reidentify(schema, result->first, *this, result->second.default_dialect); diff --git a/vendor/core/src/extension/alterschema/include/sourcemeta/core/alterschema.h b/vendor/core/src/extension/alterschema/include/sourcemeta/core/alterschema.h index 09798fa..8c4bf3e 100644 --- a/vendor/core/src/extension/alterschema/include/sourcemeta/core/alterschema.h +++ b/vendor/core/src/extension/alterschema/include/sourcemeta/core/alterschema.h @@ -78,7 +78,7 @@ enum class AlterSchemaCategory { /// })JSON"); /// /// bundle.apply(schema, sourcemeta::core::schema_official_walker, -/// sourcemeta::core::official_resolver); +/// sourcemeta::core::schema_official_resolver); /// ``` SOURCEMETA_CORE_ALTERSCHEMA_EXPORT auto add(SchemaTransformer &bundle, const AlterSchemaCategory category) -> void;