diff --git a/src/core/jsonschema/jsonschema.cc b/src/core/jsonschema/jsonschema.cc index a947ab561..4e388e1f2 100644 --- a/src/core/jsonschema/jsonschema.cc +++ b/src/core/jsonschema/jsonschema.cc @@ -731,7 +731,10 @@ auto sourcemeta::core::wrap(const sourcemeta::core::JSON &schema, // at least an artificial one, otherwise a standalone instance of `$schema` // outside of the root of a schema resource is not valid according to // JSON Schema - constexpr auto WRAPPER_IDENTIFIER{"tag:core.sourcemeta.com,2025:wrap"}; + // However, note that we use a relative URI so that references to + // other schemas whose top-level identifiers are relative URIs don't + // get affected. Otherwise, we would cause unintended base resolution. + constexpr auto WRAPPER_IDENTIFIER{"__sourcemeta-core-wrap__"}; const auto id{identify(copy, resolver, SchemaIdentificationStrategy::Strict, default_dialect) .value_or(WRAPPER_IDENTIFIER)}; diff --git a/test/jsonschema/jsonschema_wrap_test.cc b/test/jsonschema/jsonschema_wrap_test.cc index c5bc3ffdd..97013786f 100644 --- a/test/jsonschema/jsonschema_wrap_test.cc +++ b/test/jsonschema/jsonschema_wrap_test.cc @@ -54,11 +54,11 @@ TEST(JSONSchema_wrap, schema_without_identifier) { const auto expected{sourcemeta::core::parse_json(R"JSON({ "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "tag:core.sourcemeta.com,2025:wrap#/items", + "$ref": "__sourcemeta-core-wrap__#/items", "$defs": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "tag:core.sourcemeta.com,2025:wrap", + "$id": "__sourcemeta-core-wrap__", "items": { "type": "string" } @@ -69,6 +69,36 @@ TEST(JSONSchema_wrap, schema_without_identifier) { EXPECT_EQ(result, expected); } +TEST(JSONSchema_wrap, schema_without_identifier_and_relative_uri) { + const auto schema{sourcemeta::core::parse_json(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "items": { + "$ref": "relative" + } + })JSON")}; + + const auto result{sourcemeta::core::wrap( + schema, {"items"}, sourcemeta::core::schema_official_resolver)}; + + // We don't want the relative reference to be resolved against + // an absolute base + const auto expected{sourcemeta::core::parse_json(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "__sourcemeta-core-wrap__#/items", + "$defs": { + "schema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "__sourcemeta-core-wrap__", + "items": { + "$ref": "relative" + } + } + } + })JSON")}; + + EXPECT_EQ(result, expected); +} + TEST(JSONSchema_wrap, schema_without_identifier_with_default_dialect) { const auto schema{sourcemeta::core::parse_json(R"JSON({ "items": { @@ -82,11 +112,11 @@ TEST(JSONSchema_wrap, schema_without_identifier_with_default_dialect) { const auto expected{sourcemeta::core::parse_json(R"JSON({ "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "tag:core.sourcemeta.com,2025:wrap#/items", + "$ref": "__sourcemeta-core-wrap__#/items", "$defs": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "tag:core.sourcemeta.com,2025:wrap", + "$id": "__sourcemeta-core-wrap__", "items": { "type": "string" } @@ -112,11 +142,11 @@ TEST(JSONSchema_wrap, const auto expected{sourcemeta::core::parse_json(R"JSON({ "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "tag:core.sourcemeta.com,2025:wrap#/items", + "$ref": "__sourcemeta-core-wrap__#/items", "$defs": { "schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "tag:core.sourcemeta.com,2025:wrap", + "$id": "__sourcemeta-core-wrap__", "items": { "type": "string" }