Skip to content

Commit a8b59a6

Browse files
committed
Merge branch 'enable-bugprone-clang-tidy-checks' into enable-bugprone-easily-swappable-parameters
2 parents 6aeaf79 + 7b70275 commit a8b59a6

File tree

5 files changed

+213
-51
lines changed

5 files changed

+213
-51
lines changed

src/core/json/include/sourcemeta/core/json_object.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,8 +183,7 @@ template <typename Key, typename Value, typename Hash> class JSONObject {
183183
[[nodiscard]] inline auto empty() const -> bool { return this->data.empty(); }
184184

185185
/// Access an object entry by its underlying positional index
186-
[[nodiscard]] inline auto at(const size_type index) const noexcept
187-
-> const Entry & {
186+
[[nodiscard]] inline auto at(const size_type index) const -> const Entry & {
188187
return this->data.at(index);
189188
}
190189

src/core/jsonschema/bundle.cc

Lines changed: 43 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace {
99
auto embed_schema(sourcemeta::core::JSON &root,
1010
const sourcemeta::core::Pointer &container,
1111
const std::string &identifier,
12-
const sourcemeta::core::JSON &target) -> void {
12+
sourcemeta::core::JSON &&target) -> std::string {
1313
auto *current{&root};
1414
for (const auto &token : container) {
1515
if (token.is_property()) {
@@ -34,13 +34,15 @@ auto embed_schema(sourcemeta::core::JSON &root,
3434
key << "/x";
3535
}
3636

37-
current->assign(key.str(), target);
37+
current->assign(key.str(), std::move(target));
38+
return key.str();
3839
}
3940

4041
auto is_official_metaschema_reference(const sourcemeta::core::Pointer &pointer,
4142
const std::string &destination) -> bool {
42-
return !pointer.empty() && pointer.back().is_property() &&
43-
pointer.back().to_property() == "$schema" &&
43+
assert(!pointer.empty());
44+
assert(pointer.back().is_property());
45+
return pointer.back().to_property() == "$schema" &&
4446
sourcemeta::core::schema_official_resolver(destination).has_value();
4547
}
4648

@@ -53,6 +55,7 @@ auto bundle_schema(sourcemeta::core::JSON &root,
5355
const std::optional<std::string> &default_dialect,
5456
const std::optional<std::string> &default_id,
5557
const sourcemeta::core::SchemaFrame::Paths &paths,
58+
const sourcemeta::core::BundleCallback &callback,
5659
const std::size_t depth = 0) -> void {
5760
// Keep in mind that the resulting frame does miss some information. For
5861
// example, when we recurse to framing embedded schemas, we will frame them
@@ -65,12 +68,12 @@ auto bundle_schema(sourcemeta::core::JSON &root,
6568
// We only want to frame in "wrapper" mode for the top level object
6669
paths);
6770
} else {
68-
// Note that we only apply the default identifier to the top-level frame
69-
frame.analyse(subschema, walker, resolver, default_dialect);
71+
frame.analyse(subschema, walker, resolver, default_dialect, default_id);
7072
}
7173

7274
// Otherwise, given recursion, we would be modifying the
7375
// references list *while* looping on it
76+
// TODO: How can we avoid this very expensive copy?
7477
const auto references_copy = frame.references();
7578
for (const auto &[key, reference] : references_copy) {
7679
if (frame.traverse(reference.destination).has_value() ||
@@ -97,8 +100,8 @@ auto bundle_schema(sourcemeta::core::JSON &root,
97100
}
98101

99102
assert(reference.base.has_value());
100-
const auto identifier{reference.base.value()};
101-
const auto remote{resolver(identifier)};
103+
const auto &identifier{reference.base.value()};
104+
auto remote{resolver(identifier)};
102105
if (!remote.has_value()) {
103106
if (frame.traverse(identifier).has_value()) {
104107
throw sourcemeta::core::SchemaReferenceError(
@@ -110,53 +113,60 @@ auto bundle_schema(sourcemeta::core::JSON &root,
110113
identifier, "Could not resolve the reference to an external schema");
111114
}
112115

113-
// Otherwise, if the target schema does not declare an inline identifier,
114-
// references to that identifier from the outer schema won't resolve.
115-
sourcemeta::core::JSON copy{remote.value()};
116-
117-
if (!sourcemeta::core::is_schema(copy)) {
116+
if (!sourcemeta::core::is_schema(remote.value())) {
118117
throw sourcemeta::core::SchemaReferenceError(
119118
identifier, key.second,
120119
"The JSON document is not a valid JSON Schema");
121120
}
122121

123-
const auto dialect{sourcemeta::core::dialect(copy, default_dialect)};
124-
if (!dialect.has_value()) {
122+
const auto base_dialect{sourcemeta::core::base_dialect(
123+
remote.value(), resolver, default_dialect)};
124+
if (!base_dialect.has_value()) {
125125
throw sourcemeta::core::SchemaReferenceError(
126126
identifier, key.second,
127127
"The JSON document is not a valid JSON Schema");
128128
}
129129

130-
if (copy.is_object()) {
130+
if (remote.value().is_object()) {
131131
// Always insert an identifier, as a schema might refer to another schema
132132
// using another URI (i.e. due to relying on HTTP re-directions, etc)
133-
sourcemeta::core::reidentify(copy, identifier, resolver, default_dialect);
133+
sourcemeta::core::reidentify(remote.value(), identifier,
134+
base_dialect.value());
134135
}
135136

136-
embed_schema(root, container, identifier, copy);
137-
bundle_schema(root, container, copy, frame, walker, resolver,
138-
default_dialect, default_id, paths, depth + 1);
137+
bundle_schema(root, container, remote.value(), frame, walker, resolver,
138+
default_dialect, identifier, paths, callback, depth + 1);
139+
auto embed_key{
140+
embed_schema(root, container, identifier, std::move(remote).value())};
141+
142+
if (callback) {
143+
const auto origin{sourcemeta::core::identify(
144+
subschema, resolver,
145+
sourcemeta::core::SchemaIdentificationStrategy::Strict,
146+
default_dialect, default_id)};
147+
callback(origin, key.second, identifier, container.concat({embed_key}));
148+
}
139149
}
140150
}
141151

142152
} // namespace
143153

144154
namespace sourcemeta::core {
145155

146-
auto bundle(sourcemeta::core::JSON &schema, const SchemaWalker &walker,
156+
auto bundle(JSON &schema, const SchemaWalker &walker,
147157
const SchemaResolver &resolver,
148158
const std::optional<std::string> &default_dialect,
149159
const std::optional<std::string> &default_id,
150160
const std::optional<Pointer> &default_container,
151-
const SchemaFrame::Paths &paths) -> void {
152-
sourcemeta::core::SchemaFrame frame{
153-
sourcemeta::core::SchemaFrame::Mode::References};
161+
const SchemaFrame::Paths &paths, const BundleCallback &callback)
162+
-> void {
163+
SchemaFrame frame{SchemaFrame::Mode::References};
154164

155165
if (default_container.has_value()) {
156166
// This is undefined behavior
157167
assert(!default_container.value().empty());
158168
bundle_schema(schema, default_container.value(), schema, frame, walker,
159-
resolver, default_dialect, default_id, paths);
169+
resolver, default_dialect, default_id, paths, callback);
160170
return;
161171
}
162172

@@ -167,7 +177,7 @@ auto bundle(sourcemeta::core::JSON &schema, const SchemaWalker &walker,
167177
vocabularies.contains(
168178
"https://json-schema.org/draft/2019-09/vocab/core")) {
169179
bundle_schema(schema, {"$defs"}, schema, frame, walker, resolver,
170-
default_dialect, default_id, paths);
180+
default_dialect, default_id, paths, callback);
171181
return;
172182
} else if (vocabularies.contains("http://json-schema.org/draft-07/schema#") ||
173183
vocabularies.contains(
@@ -179,7 +189,7 @@ auto bundle(sourcemeta::core::JSON &schema, const SchemaWalker &walker,
179189
vocabularies.contains(
180190
"http://json-schema.org/draft-04/hyper-schema#")) {
181191
bundle_schema(schema, {"definitions"}, schema, frame, walker, resolver,
182-
default_dialect, default_id, paths);
192+
default_dialect, default_id, paths, callback);
183193
return;
184194
} else if (vocabularies.contains(
185195
"http://json-schema.org/draft-03/hyper-schema#") ||
@@ -201,19 +211,20 @@ auto bundle(sourcemeta::core::JSON &schema, const SchemaWalker &walker,
201211

202212
// We don't attempt to bundle on dialects where we
203213
// don't know where to put the embedded schemas
204-
throw sourcemeta::core::SchemaError(
214+
throw SchemaError(
205215
"Could not determine how to perform bundling in this dialect");
206216
}
207217

208-
auto bundle(const sourcemeta::core::JSON &schema, const SchemaWalker &walker,
218+
auto bundle(const JSON &schema, const SchemaWalker &walker,
209219
const SchemaResolver &resolver,
210220
const std::optional<std::string> &default_dialect,
211221
const std::optional<std::string> &default_id,
212222
const std::optional<Pointer> &default_container,
213-
const SchemaFrame::Paths &paths) -> sourcemeta::core::JSON {
214-
sourcemeta::core::JSON copy = schema;
223+
const SchemaFrame::Paths &paths, const BundleCallback &callback)
224+
-> JSON {
225+
JSON copy = schema;
215226
bundle(copy, walker, resolver, default_dialect, default_id, default_container,
216-
paths);
227+
paths, callback);
217228
return copy;
218229
}
219230

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

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,16 @@ auto reference_visit(
507507

508508
// TODO: Optionally let users bundle the metaschema too
509509

510+
/// @ingroup jsonschema
511+
/// A callback to get runtime reporting out of schema bundling:
512+
/// - Origin URI
513+
/// - Pointer (reference keyword from the origin)
514+
/// - Target URI
515+
/// - Embed pointer
516+
using BundleCallback =
517+
std::function<void(const std::optional<JSON::String> &, const Pointer &,
518+
const JSON::String &, const Pointer &)>;
519+
510520
/// @ingroup jsonschema
511521
///
512522
/// This function bundles a JSON Schema (starting from Draft 4) by embedding
@@ -562,7 +572,8 @@ auto bundle(JSON &schema, const SchemaWalker &walker,
562572
const std::optional<std::string> &default_dialect = std::nullopt,
563573
const std::optional<std::string> &default_id = std::nullopt,
564574
const std::optional<Pointer> &default_container = std::nullopt,
565-
const SchemaFrame::Paths &paths = {empty_pointer}) -> void;
575+
const SchemaFrame::Paths &paths = {empty_pointer},
576+
const BundleCallback &callback = nullptr) -> void;
566577

567578
/// @ingroup jsonschema
568579
///
@@ -621,7 +632,8 @@ auto bundle(const JSON &schema, const SchemaWalker &walker,
621632
const std::optional<std::string> &default_dialect = std::nullopt,
622633
const std::optional<std::string> &default_id = std::nullopt,
623634
const std::optional<Pointer> &default_container = std::nullopt,
624-
const SchemaFrame::Paths &paths = {empty_pointer}) -> JSON;
635+
const SchemaFrame::Paths &paths = {empty_pointer},
636+
const BundleCallback &callback = nullptr) -> JSON;
625637

626638
/// @ingroup jsonschema
627639
///

src/core/jsonschema/official_resolver.in.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ auto sourcemeta::core::schema_official_resolver(std::string_view identifier)
1010
R"EOF(@METASCHEMA_JSONSCHEMA_2020_12@)EOF");
1111
} else if (identifier ==
1212
"https://json-schema.org/draft/2020-12/hyper-schema" ||
13+
// Just for compatibility given that this is such a common issue
1314
identifier ==
1415
"https://json-schema.org/draft/2020-12/hyper-schema#") {
1516
return sourcemeta::core::parse_json(
@@ -64,6 +65,7 @@ auto sourcemeta::core::schema_official_resolver(std::string_view identifier)
6465
R"EOF(@METASCHEMA_JSONSCHEMA_2019_09@)EOF");
6566
} else if (identifier ==
6667
"https://json-schema.org/draft/2019-09/hyper-schema" ||
68+
// Just for compatibility given that this is such a common issue
6769
identifier ==
6870
"https://json-schema.org/draft/2019-09/hyper-schema#") {
6971
return sourcemeta::core::parse_json(

0 commit comments

Comments
 (0)