Skip to content

Commit 1fdd2a1

Browse files
authored
Take a default identifier on every SchemaFrame application (#1795)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent b576aec commit 1fdd2a1

File tree

7 files changed

+89
-43
lines changed

7 files changed

+89
-43
lines changed

src/core/jsonschema/bundle.cc

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ auto bundle_schema(sourcemeta::core::JSON &root,
5151
const sourcemeta::core::SchemaWalker &walker,
5252
const sourcemeta::core::SchemaResolver &resolver,
5353
const std::optional<std::string> &default_dialect,
54+
const std::optional<std::string> &default_id,
5455
const sourcemeta::core::SchemaFrame::Paths &paths,
5556
const std::size_t depth = 0) -> void {
5657
// Keep in mind that the resulting frame does miss some information. For
@@ -60,10 +61,11 @@ auto bundle_schema(sourcemeta::core::JSON &root,
6061
// function, given we don't pass the frame back to the caller
6162
if (depth == 0) {
6263
frame.analyse(
63-
subschema, walker, resolver, default_dialect, std::nullopt,
64+
subschema, walker, resolver, default_dialect, default_id,
6465
// We only want to frame in "wrapper" mode for the top level object
6566
paths);
6667
} else {
68+
// Note that we only apply the default identifier to the top-level frame
6769
frame.analyse(subschema, walker, resolver, default_dialect);
6870
}
6971

@@ -133,7 +135,7 @@ auto bundle_schema(sourcemeta::core::JSON &root,
133135

134136
embed_schema(root, container, identifier, copy);
135137
bundle_schema(root, container, copy, frame, walker, resolver,
136-
default_dialect, paths, depth + 1);
138+
default_dialect, default_id, paths, depth + 1);
137139
}
138140
}
139141

@@ -144,6 +146,7 @@ namespace sourcemeta::core {
144146
auto bundle(sourcemeta::core::JSON &schema, const SchemaWalker &walker,
145147
const SchemaResolver &resolver,
146148
const std::optional<std::string> &default_dialect,
149+
const std::optional<std::string> &default_id,
147150
const std::optional<Pointer> &default_container,
148151
const SchemaFrame::Paths &paths) -> void {
149152
sourcemeta::core::SchemaFrame frame{
@@ -153,7 +156,7 @@ auto bundle(sourcemeta::core::JSON &schema, const SchemaWalker &walker,
153156
// This is undefined behavior
154157
assert(!default_container.value().empty());
155158
bundle_schema(schema, default_container.value(), schema, frame, walker,
156-
resolver, default_dialect, paths);
159+
resolver, default_dialect, default_id, paths);
157160
return;
158161
}
159162

@@ -164,7 +167,7 @@ auto bundle(sourcemeta::core::JSON &schema, const SchemaWalker &walker,
164167
vocabularies.contains(
165168
"https://json-schema.org/draft/2019-09/vocab/core")) {
166169
bundle_schema(schema, {"$defs"}, schema, frame, walker, resolver,
167-
default_dialect, paths);
170+
default_dialect, default_id, paths);
168171
return;
169172
} else if (vocabularies.contains("http://json-schema.org/draft-07/schema#") ||
170173
vocabularies.contains(
@@ -176,7 +179,7 @@ auto bundle(sourcemeta::core::JSON &schema, const SchemaWalker &walker,
176179
vocabularies.contains(
177180
"http://json-schema.org/draft-04/hyper-schema#")) {
178181
bundle_schema(schema, {"definitions"}, schema, frame, walker, resolver,
179-
default_dialect, paths);
182+
default_dialect, default_id, paths);
180183
return;
181184
} else if (vocabularies.contains(
182185
"http://json-schema.org/draft-03/hyper-schema#") ||
@@ -190,7 +193,7 @@ auto bundle(sourcemeta::core::JSON &schema, const SchemaWalker &walker,
190193
vocabularies.contains(
191194
"http://json-schema.org/draft-00/hyper-schema#") ||
192195
vocabularies.contains("http://json-schema.org/draft-00/schema#")) {
193-
frame.analyse(schema, walker, resolver, default_dialect);
196+
frame.analyse(schema, walker, resolver, default_dialect, default_id);
194197
if (frame.standalone()) {
195198
return;
196199
}
@@ -205,10 +208,12 @@ auto bundle(sourcemeta::core::JSON &schema, const SchemaWalker &walker,
205208
auto bundle(const sourcemeta::core::JSON &schema, const SchemaWalker &walker,
206209
const SchemaResolver &resolver,
207210
const std::optional<std::string> &default_dialect,
211+
const std::optional<std::string> &default_id,
208212
const std::optional<Pointer> &default_container,
209213
const SchemaFrame::Paths &paths) -> sourcemeta::core::JSON {
210214
sourcemeta::core::JSON copy = schema;
211-
bundle(copy, walker, resolver, default_dialect, default_container, paths);
215+
bundle(copy, walker, resolver, default_dialect, default_id, default_container,
216+
paths);
212217
return copy;
213218
}
214219

src/core/jsonschema/include/sourcemeta/core/jsonschema.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ SOURCEMETA_CORE_JSONSCHEMA_EXPORT
544544
auto bundle(JSON &schema, const SchemaWalker &walker,
545545
const SchemaResolver &resolver,
546546
const std::optional<std::string> &default_dialect = std::nullopt,
547+
const std::optional<std::string> &default_id = std::nullopt,
547548
const std::optional<Pointer> &default_container = std::nullopt,
548549
const SchemaFrame::Paths &paths = {empty_pointer}) -> void;
549550

@@ -602,6 +603,7 @@ SOURCEMETA_CORE_JSONSCHEMA_EXPORT
602603
auto bundle(const JSON &schema, const SchemaWalker &walker,
603604
const SchemaResolver &resolver,
604605
const std::optional<std::string> &default_dialect = std::nullopt,
606+
const std::optional<std::string> &default_id = std::nullopt,
605607
const std::optional<Pointer> &default_container = std::nullopt,
606608
const SchemaFrame::Paths &paths = {empty_pointer}) -> JSON;
607609

src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -229,17 +229,17 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaTransformer {
229229
const std::string_view, const std::string_view)>;
230230

231231
/// Apply the bundle of rules to a schema
232-
auto
233-
apply(JSON &schema, const SchemaWalker &walker,
234-
const SchemaResolver &resolver, const Callback &callback,
235-
const std::optional<std::string> &default_dialect = std::nullopt) const
232+
auto apply(JSON &schema, const SchemaWalker &walker,
233+
const SchemaResolver &resolver, const Callback &callback,
234+
const std::optional<JSON::String> &default_dialect = std::nullopt,
235+
const std::optional<JSON::String> &default_id = std::nullopt) const
236236
-> bool;
237237

238238
/// Report back the rules from the bundle that need to be applied to a schema
239-
auto
240-
check(const JSON &schema, const SchemaWalker &walker,
241-
const SchemaResolver &resolver, const Callback &callback,
242-
const std::optional<std::string> &default_dialect = std::nullopt) const
239+
auto check(const JSON &schema, const SchemaWalker &walker,
240+
const SchemaResolver &resolver, const Callback &callback,
241+
const std::optional<JSON::String> &default_dialect = std::nullopt,
242+
const std::optional<JSON::String> &default_id = std::nullopt) const
243243
-> bool;
244244

245245
private:

src/core/jsonschema/transformer.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,10 @@ auto SchemaTransformRule::check(const JSON &schema, const JSON &root,
100100
auto SchemaTransformer::check(
101101
const JSON &schema, const SchemaWalker &walker,
102102
const SchemaResolver &resolver, const SchemaTransformer::Callback &callback,
103-
const std::optional<std::string> &default_dialect) const -> bool {
103+
const std::optional<JSON::String> &default_dialect,
104+
const std::optional<JSON::String> &default_id) const -> bool {
104105
SchemaFrame frame{SchemaFrame::Mode::Locations};
105-
frame.analyse(schema, walker, resolver, default_dialect);
106+
frame.analyse(schema, walker, resolver, default_dialect, default_id);
106107

107108
bool result{true};
108109
for (const auto &entry : frame.locations()) {
@@ -142,15 +143,16 @@ auto SchemaTransformer::check(
142143
auto SchemaTransformer::apply(
143144
JSON &schema, const SchemaWalker &walker, const SchemaResolver &resolver,
144145
const SchemaTransformer::Callback &callback,
145-
const std::optional<std::string> &default_dialect) const -> bool {
146+
const std::optional<JSON::String> &default_dialect,
147+
const std::optional<JSON::String> &default_id) const -> bool {
146148
// There is no point in applying an empty bundle
147149
assert(!this->rules.empty());
148150
std::set<std::pair<Pointer, JSON::String>> processed_rules;
149151

150152
bool result{true};
151153
while (true) {
152154
SchemaFrame frame{SchemaFrame::Mode::References};
153-
frame.analyse(schema, walker, resolver, default_dialect);
155+
frame.analyse(schema, walker, resolver, default_dialect, default_id);
154156

155157
bool applied{false};
156158
for (const auto &entry : frame.locations()) {

test/jsonschema/jsonschema_bundle_2020_12_test.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ TEST(JSONSchema_bundle_2020_12, bundle_to_definitions) {
631631
})JSON");
632632

633633
sourcemeta::core::bundle(document, sourcemeta::core::schema_official_walker,
634-
test_resolver, std::nullopt,
634+
test_resolver, std::nullopt, std::nullopt,
635635
sourcemeta::core::Pointer{"definitions"});
636636

637637
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
@@ -659,7 +659,8 @@ TEST(JSONSchema_bundle_2020_12, custom_nested_object_path_non_existent) {
659659

660660
sourcemeta::core::bundle(
661661
document, sourcemeta::core::schema_official_walker, test_resolver,
662-
std::nullopt, sourcemeta::core::Pointer{"x-definitions", "foo", "bar"});
662+
std::nullopt, std::nullopt,
663+
sourcemeta::core::Pointer{"x-definitions", "foo", "bar"});
663664

664665
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
665666
"$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -691,7 +692,8 @@ TEST(JSONSchema_bundle_2020_12, custom_nested_object_path_half_existent) {
691692

692693
sourcemeta::core::bundle(
693694
document, sourcemeta::core::schema_official_walker, test_resolver,
694-
std::nullopt, sourcemeta::core::Pointer{"x-definitions", "foo", "bar"});
695+
std::nullopt, std::nullopt,
696+
sourcemeta::core::Pointer{"x-definitions", "foo", "bar"});
695697

696698
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
697699
"$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -724,7 +726,7 @@ TEST(JSONSchema_bundle_2020_12,
724726

725727
sourcemeta::core::bundle(
726728
document, sourcemeta::core::schema_official_walker, test_resolver,
727-
std::nullopt,
729+
std::nullopt, std::nullopt,
728730
sourcemeta::core::Pointer{"x-definitions", 0, "foo", "bar"});
729731

730732
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
@@ -759,7 +761,7 @@ TEST(JSONSchema_bundle_2020_12, custom_nested_object_path_not_object) {
759761

760762
EXPECT_THROW(sourcemeta::core::bundle(
761763
document, sourcemeta::core::schema_official_walker,
762-
test_resolver, std::nullopt,
764+
test_resolver, std::nullopt, std::nullopt,
763765
sourcemeta::core::Pointer{"x-definitions", "foo", "bar"}),
764766
sourcemeta::core::SchemaError);
765767
}

test/jsonschema/jsonschema_bundle_draft7_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ TEST(JSONSchema_bundle_draft7, bundle_to_defs) {
539539
})JSON");
540540

541541
sourcemeta::core::bundle(document, sourcemeta::core::schema_official_walker,
542-
test_resolver, std::nullopt,
542+
test_resolver, std::nullopt, std::nullopt,
543543
sourcemeta::core::Pointer{"$defs"});
544544

545545
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({

test/jsonschema/jsonschema_bundle_test.cc

Lines changed: 53 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,41 @@ TEST(JSONSchema_bundle, across_dialects_const) {
117117
EXPECT_EQ(result, expected);
118118
}
119119

120+
TEST(JSONSchema_bundle, with_default_id) {
121+
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
122+
"$schema": "https://json-schema.org/draft/2020-12/schema",
123+
"items": { "$ref": "test-2" }
124+
})JSON");
125+
126+
sourcemeta::core::bundle(document, sourcemeta::core::schema_official_walker,
127+
test_resolver, std::nullopt,
128+
"https://www.sourcemeta.com/default");
129+
130+
const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({
131+
"$schema": "https://json-schema.org/draft/2020-12/schema",
132+
"items": { "$ref": "test-2" },
133+
"$defs": {
134+
"https://www.sourcemeta.com/test-2": {
135+
"$schema": "https://json-schema.org/draft/2019-09/schema",
136+
"$id": "https://www.sourcemeta.com/test-2",
137+
"$ref": "test-3"
138+
},
139+
"https://www.sourcemeta.com/test-3": {
140+
"$schema": "http://json-schema.org/draft-06/schema#",
141+
"$id": "https://www.sourcemeta.com/test-3",
142+
"allOf": [ { "$ref": "test-4" } ]
143+
},
144+
"https://www.sourcemeta.com/test-4": {
145+
"$schema": "http://json-schema.org/draft-04/schema#",
146+
"id": "https://www.sourcemeta.com/test-4",
147+
"type": "string"
148+
}
149+
}
150+
})JSON");
151+
152+
EXPECT_EQ(document, expected);
153+
}
154+
120155
TEST(JSONSchema_bundle, with_default_dialect) {
121156
sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
122157
"properties": {
@@ -202,15 +237,15 @@ TEST(JSONSchema_bundle, custom_paths_no_external) {
202237
}
203238
})JSON")};
204239

205-
sourcemeta::core::bundle(schema, sourcemeta::core::schema_official_walker,
206-
test_resolver,
207-
"https://json-schema.org/draft/2020-12/schema",
208-
sourcemeta::core::Pointer{"components"},
209-
{
210-
sourcemeta::core::Pointer{"wrapper"},
211-
sourcemeta::core::Pointer{"common", "test"},
212-
sourcemeta::core::Pointer{"common", "with-id"},
213-
});
240+
sourcemeta::core::bundle(
241+
schema, sourcemeta::core::schema_official_walker, test_resolver,
242+
"https://json-schema.org/draft/2020-12/schema", std::nullopt,
243+
sourcemeta::core::Pointer{"components"},
244+
{
245+
sourcemeta::core::Pointer{"wrapper"},
246+
sourcemeta::core::Pointer{"common", "test"},
247+
sourcemeta::core::Pointer{"common", "with-id"},
248+
});
214249

215250
const auto expected{sourcemeta::core::parse_json(R"JSON({
216251
"wrapper": {
@@ -248,15 +283,15 @@ TEST(JSONSchema_bundle, custom_paths_with_externals) {
248283
}
249284
})JSON")};
250285

251-
sourcemeta::core::bundle(schema, sourcemeta::core::schema_official_walker,
252-
test_resolver,
253-
"https://json-schema.org/draft/2020-12/schema",
254-
sourcemeta::core::Pointer{"components"},
255-
{
256-
sourcemeta::core::Pointer{"wrapper"},
257-
sourcemeta::core::Pointer{"common", "test"},
258-
sourcemeta::core::Pointer{"common", "with-id"},
259-
});
286+
sourcemeta::core::bundle(
287+
schema, sourcemeta::core::schema_official_walker, test_resolver,
288+
"https://json-schema.org/draft/2020-12/schema", std::nullopt,
289+
sourcemeta::core::Pointer{"components"},
290+
{
291+
sourcemeta::core::Pointer{"wrapper"},
292+
sourcemeta::core::Pointer{"common", "test"},
293+
sourcemeta::core::Pointer{"common", "with-id"},
294+
});
260295

261296
const auto expected{sourcemeta::core::parse_json(R"JSON({
262297
"wrapper": {

0 commit comments

Comments
 (0)