diff --git a/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_resolver.h b/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_resolver.h index 37060e8a0..d8d3c0a5f 100644 --- a/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_resolver.h +++ b/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_resolver.h @@ -145,6 +145,7 @@ class SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT FlatFileSchemaResolver { struct Entry { std::filesystem::path path; std::optional default_dialect; + std::string original_identifier; }; private: diff --git a/src/jsonschema/resolver.cc b/src/jsonschema/resolver.cc index 61c405d5b..dc5575db1 100644 --- a/src/jsonschema/resolver.cc +++ b/src/jsonschema/resolver.cc @@ -95,8 +95,9 @@ auto FlatFileSchemaResolver::add( throw SchemaError(error.str()); } - const auto result{this->schemas.emplace(identifier.value(), - Entry{canonical, default_dialect})}; + const auto result{this->schemas.emplace( + identifier.value(), + Entry{canonical, default_dialect, identifier.value()})}; if (!result.second && result.first->second.path != canonical) { std::ostringstream error; error << "Cannot register the same identifier twice: " @@ -128,6 +129,14 @@ auto FlatFileSchemaResolver::operator()(std::string_view identifier) const schema.assign("$schema", JSON{result->second.default_dialect.value()}); } + sourcemeta::jsontoolkit::reidentify(schema, + result->second.original_identifier, + *this, result->second.default_dialect); + // Because we allow re-identification, we can get into issues unless we + // always try to relativize references + sourcemeta::jsontoolkit::relativize(schema, default_schema_walker, *this, + result->second.default_dialect, + result->second.original_identifier); sourcemeta::jsontoolkit::reidentify(schema, result->first, *this, result->second.default_dialect); diff --git a/test/jsonschema/jsonschema_flat_file_resolver_test.cc b/test/jsonschema/jsonschema_flat_file_resolver_test.cc index 876e20138..14fa3107e 100644 --- a/test/jsonschema/jsonschema_flat_file_resolver_test.cc +++ b/test/jsonschema/jsonschema_flat_file_resolver_test.cc @@ -196,3 +196,24 @@ TEST(JSONSchema_FlatFileSchemaResolver, reidentify) { EXPECT_EQ(resolver("https://example.com").value(), expected); } + +TEST(JSONSchema_FlatFileSchemaResolver, with_absolute_references) { + sourcemeta::jsontoolkit::FlatFileSchemaResolver resolver; + const auto schema_path{std::filesystem::path{SCHEMAS_PATH} / + "2020-12-absolute-ref.json"}; + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$id": "https://www.sourcemeta.com/2020-12-absolute-ref.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "2020-12-id.json" + })JSON"); + + const auto &identifier{resolver.add(schema_path)}; + EXPECT_EQ(identifier, "https://www.sourcemeta.com/2020-12-absolute-ref.json"); + EXPECT_TRUE(resolver("https://www.sourcemeta.com/2020-12-absolute-ref.json") + .has_value()); + EXPECT_EQ( + resolver("https://www.sourcemeta.com/2020-12-absolute-ref.json").value(), + expected); +} diff --git a/test/jsonschema/schemas/2020-12-absolute-ref.json b/test/jsonschema/schemas/2020-12-absolute-ref.json new file mode 100644 index 000000000..23ceb2193 --- /dev/null +++ b/test/jsonschema/schemas/2020-12-absolute-ref.json @@ -0,0 +1,5 @@ +{ + "$id": "https://www.sourcemeta.com/2020-12-absolute-ref.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "https://www.sourcemeta.com/2020-12-id.json" +}