Skip to content

Commit 29dbce2

Browse files
authored
Fix various documentation issues (#743)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent bc2d211 commit 29dbce2

11 files changed

Lines changed: 4412 additions & 2273 deletions

schemas/documentation.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@
308308
},
309309
{
310310
"type": "object",
311-
"required": [ "kind", "identifier" ],
311+
"required": [ "kind", "identifier", "path" ],
312312
"properties": {
313313
"kind": {
314314
"const": "recursiveRef"
@@ -317,6 +317,13 @@
317317
"description": "The identifier of the target table in the same documentation tree",
318318
"type": "integer",
319319
"minimum": 0
320+
},
321+
"path": {
322+
"type": "array",
323+
"minItems": 1,
324+
"items": {
325+
"$ref": "#/$defs/pathSegment"
326+
}
320327
}
321328
},
322329
"additionalProperties": false

schemas/documentation.test.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,13 @@
409409
],
410410
"type": {
411411
"kind": "recursiveRef",
412-
"identifier": 0
412+
"identifier": 0,
413+
"path": [
414+
{
415+
"type": "synthetic",
416+
"value": "root"
417+
}
418+
]
413419
}
414420
},
415421
{

src/alterschema/common/required_properties_in_properties.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ class RequiredPropertiesInProperties final : public SchemaTransformRule {
3333
Vocabularies::Known::JSON_Schema_Draft_3})) &&
3434
schema.is_object() && schema.defines("required") &&
3535
schema.at("required").is_array() && !schema.at("required").empty() &&
36-
!schema.defines("additionalProperties"));
36+
(!schema.defines("additionalProperties") ||
37+
(schema.at("additionalProperties").is_boolean() &&
38+
schema.at("additionalProperties").to_boolean())));
3739

3840
std::vector<Pointer> locations;
3941
std::size_t index{0};

src/documentation/documentation.cc

Lines changed: 82 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,11 @@ auto resolve_destination(const sourcemeta::core::JSON::String &raw_ref,
3434
return std::nullopt;
3535
}
3636

37-
using VisitedSchemas = std::map<const sourcemeta::core::JSON *, std::size_t>;
37+
struct VisitedEntry {
38+
std::size_t identifier;
39+
sourcemeta::core::JSON path;
40+
};
41+
using VisitedSchemas = std::map<const sourcemeta::core::JSON *, VisitedEntry>;
3842
using RefChain = std::set<const sourcemeta::core::JSON *>;
3943

4044
auto type_expression_of(const sourcemeta::core::JSON &schema,
@@ -71,8 +75,9 @@ auto type_expression_of(const sourcemeta::core::JSON &schema,
7175
if (visited_entry != visited.end()) {
7276
result.assign("kind", sourcemeta::core::JSON{"recursiveRef"});
7377
result.assign("identifier",
74-
sourcemeta::core::JSON{
75-
static_cast<std::int64_t>(visited_entry->second)});
78+
sourcemeta::core::JSON{static_cast<std::int64_t>(
79+
visited_entry->second.identifier)});
80+
result.assign("path", visited_entry->second.path);
7681
return result;
7782
}
7883

@@ -689,7 +694,8 @@ auto walk_properties(const sourcemeta::core::JSON &schema,
689694
resolved.at("type").is_string()) {
690695
const auto &resolved_type{resolved.at("type").to_string()};
691696
if (resolved_type == "object") {
692-
visited.emplace(&resolved, row_identifier);
697+
visited.emplace(&resolved, VisitedEntry{.identifier = row_identifier,
698+
.path = path});
693699
walk_properties(resolved, path, rows, frame, root, visited,
694700
next_identifier);
695701
walk_pattern_properties(resolved, path, rows, frame, root, visited,
@@ -704,26 +710,30 @@ auto walk_properties(const sourcemeta::core::JSON &schema,
704710
!resolved.defines("prefixItems")) {
705711
const auto &items_schema{
706712
resolve_ref(resolved.at("items"), frame, root, visited)};
707-
if (items_schema.is_object() && items_schema.defines("type") &&
708-
items_schema.at("type").is_string() &&
709-
items_schema.at("type").to_string() == "object") {
713+
if (items_schema.is_object()) {
710714
auto wildcard_path{path};
711715
wildcard_path.push_back(make_path_segment("wildcard", "*"));
712716
const auto items_row_id{next_identifier};
713717
emit_row(items_schema, wildcard_path, rows, frame, root, visited,
714718
next_identifier);
715-
visited.emplace(&items_schema, items_row_id);
716-
walk_properties(items_schema, wildcard_path, rows, frame, root,
717-
visited, next_identifier);
718-
walk_pattern_properties(items_schema, wildcard_path, rows, frame,
719-
root, visited, next_identifier);
720-
walk_wildcard_keyword(items_schema, "additionalProperties",
721-
wildcard_path, rows, frame, root, visited,
722-
next_identifier);
723-
walk_wildcard_keyword(items_schema, "unevaluatedProperties",
724-
wildcard_path, rows, frame, root, visited,
725-
next_identifier);
726-
visited.erase(&items_schema);
719+
if (items_schema.defines("type") &&
720+
items_schema.at("type").is_string() &&
721+
items_schema.at("type").to_string() == "object") {
722+
visited.emplace(&items_schema,
723+
VisitedEntry{.identifier = items_row_id,
724+
.path = wildcard_path});
725+
walk_properties(items_schema, wildcard_path, rows, frame, root,
726+
visited, next_identifier);
727+
walk_pattern_properties(items_schema, wildcard_path, rows, frame,
728+
root, visited, next_identifier);
729+
walk_wildcard_keyword(items_schema, "additionalProperties",
730+
wildcard_path, rows, frame, root, visited,
731+
next_identifier);
732+
walk_wildcard_keyword(items_schema, "unevaluatedProperties",
733+
wildcard_path, rows, frame, root, visited,
734+
next_identifier);
735+
visited.erase(&items_schema);
736+
}
727737
}
728738
}
729739
}
@@ -738,19 +748,31 @@ auto walk_wildcard_keyword(const sourcemeta::core::JSON &schema,
738748
const sourcemeta::core::JSON &root,
739749
VisitedSchemas &visited,
740750
std::size_t &next_identifier) -> void {
741-
if (!schema.is_object() || !schema.defines(keyword) ||
742-
!schema.at(keyword).is_object()) {
751+
if (!schema.is_object() || !schema.defines(keyword)) {
743752
return;
744753
}
745754

755+
const auto &value{schema.at(keyword)};
756+
746757
if (keyword == "unevaluatedItems" && schema.defines("prefixItems")) {
747758
return;
748759
}
749760

761+
if (value.is_boolean() && value.to_boolean()) {
762+
auto path{base_path};
763+
path.push_back(make_path_segment("wildcard", "*"));
764+
emit_row(value, std::move(path), rows, frame, root, visited,
765+
next_identifier);
766+
return;
767+
}
768+
769+
if (!value.is_object()) {
770+
return;
771+
}
772+
750773
auto path{base_path};
751774
path.push_back(make_path_segment("wildcard", "*"));
752-
emit_row(schema.at(keyword), std::move(path), rows, frame, root, visited,
753-
next_identifier);
775+
emit_row(value, std::move(path), rows, frame, root, visited, next_identifier);
754776
}
755777

756778
auto walk_pattern_properties(const sourcemeta::core::JSON &schema,
@@ -1128,14 +1150,19 @@ auto walk_schema(const sourcemeta::core::JSON &schema, const bool include_root,
11281150
auto type_expr{sourcemeta::core::JSON::make_object()};
11291151
type_expr.assign("kind", sourcemeta::core::JSON{"recursiveRef"});
11301152
type_expr.assign("identifier",
1131-
sourcemeta::core::JSON{
1132-
static_cast<std::int64_t>(visited_entry->second)});
1153+
sourcemeta::core::JSON{static_cast<std::int64_t>(
1154+
visited_entry->second.identifier)});
1155+
type_expr.assign("path", visited_entry->second.path);
11331156
row.assign("type", std::move(type_expr));
11341157
rows.push_back(std::move(row));
11351158
documentation.assign("rows", std::move(rows));
11361159
return documentation;
11371160
}
1138-
visited.emplace(&target_schema, next_identifier);
1161+
auto ref_path{sourcemeta::core::JSON::make_array()};
1162+
ref_path.push_back(make_path_segment("synthetic", "root"));
1163+
visited.emplace(&target_schema,
1164+
VisitedEntry{.identifier = next_identifier,
1165+
.path = std::move(ref_path)});
11391166
auto result{walk_schema(target_schema, include_root, frame, root, visited,
11401167
next_identifier)};
11411168
visited.erase(&target_schema);
@@ -1166,7 +1193,11 @@ auto walk_schema(const sourcemeta::core::JSON &schema, const bool include_root,
11661193
next_identifier);
11671194
const auto root_row_identifier{static_cast<std::size_t>(
11681195
rows.at(rows.size() - 1).at("identifier").to_integer())};
1169-
visited.emplace(&schema, root_row_identifier);
1196+
auto visited_root_path{sourcemeta::core::JSON::make_array()};
1197+
visited_root_path.push_back(make_path_segment("synthetic", "root"));
1198+
visited.emplace(&schema,
1199+
VisitedEntry{.identifier = root_row_identifier,
1200+
.path = std::move(visited_root_path)});
11701201
}
11711202

11721203
if (!schema.is_object()) {
@@ -1201,25 +1232,28 @@ auto walk_schema(const sourcemeta::core::JSON &schema, const bool include_root,
12011232
schema.at("items").is_object() && !schema.defines("prefixItems")) {
12021233
const auto &items_schema{
12031234
resolve_ref(schema.at("items"), frame, root, visited)};
1204-
if (items_schema.is_object() && items_schema.defines("type") &&
1205-
items_schema.at("type").is_string() &&
1206-
items_schema.at("type").to_string() == "object") {
1235+
if (items_schema.is_object()) {
12071236
auto wildcard_path{sourcemeta::core::JSON::make_array()};
12081237
wildcard_path.push_back(make_path_segment("wildcard", "*"));
12091238
const auto items_row_id{next_identifier};
12101239
emit_row(items_schema, wildcard_path, rows, frame, root, visited,
12111240
next_identifier);
1212-
visited.emplace(&items_schema, items_row_id);
1213-
walk_properties(items_schema, wildcard_path, rows, frame, root, visited,
1214-
next_identifier);
1215-
walk_pattern_properties(items_schema, wildcard_path, rows, frame, root,
1216-
visited, next_identifier);
1217-
walk_wildcard_keyword(items_schema, "additionalProperties", wildcard_path,
1218-
rows, frame, root, visited, next_identifier);
1219-
walk_wildcard_keyword(items_schema, "unevaluatedProperties",
1220-
wildcard_path, rows, frame, root, visited,
1221-
next_identifier);
1222-
visited.erase(&items_schema);
1241+
if (items_schema.defines("type") && items_schema.at("type").is_string() &&
1242+
items_schema.at("type").to_string() == "object") {
1243+
visited.emplace(&items_schema, VisitedEntry{.identifier = items_row_id,
1244+
.path = wildcard_path});
1245+
walk_properties(items_schema, wildcard_path, rows, frame, root, visited,
1246+
next_identifier);
1247+
walk_pattern_properties(items_schema, wildcard_path, rows, frame, root,
1248+
visited, next_identifier);
1249+
walk_wildcard_keyword(items_schema, "additionalProperties",
1250+
wildcard_path, rows, frame, root, visited,
1251+
next_identifier);
1252+
walk_wildcard_keyword(items_schema, "unevaluatedProperties",
1253+
wildcard_path, rows, frame, root, visited,
1254+
next_identifier);
1255+
visited.erase(&items_schema);
1256+
}
12231257
}
12241258
}
12251259

@@ -1276,26 +1310,21 @@ auto walk_schema(const sourcemeta::core::JSON &schema, const bool include_root,
12761310
}
12771311
}
12781312

1279-
if (schema.is_object() && schema.defines("not") &&
1280-
schema.at("not").is_object()) {
1313+
if (schema.is_object() && schema.defines("not")) {
12811314
const auto &not_schema{schema.at("not")};
12821315
const auto is_branching{
1283-
not_schema.defines("anyOf") || not_schema.defines("oneOf") ||
1284-
not_schema.defines("allOf") || not_schema.defines("not")};
1285-
if (is_branching) {
1316+
not_schema.is_object() &&
1317+
(not_schema.defines("anyOf") || not_schema.defines("oneOf") ||
1318+
not_schema.defines("allOf") || not_schema.defines("not"))};
1319+
const auto has_inline_constraints{!is_branching && not_schema.is_object() &&
1320+
!constraints_of(not_schema).empty()};
1321+
if (!has_inline_constraints) {
12861322
walk_branching_subschema("Must NOT match", "value", not_schema,
12871323
doc_children, frame, root, visited,
12881324
next_identifier, false);
12891325
}
12901326
}
12911327

1292-
if (schema.is_object() && schema.defines("not") &&
1293-
schema.at("not").is_boolean()) {
1294-
walk_branching_subschema("Must NOT match", "value", schema.at("not"),
1295-
doc_children, frame, root, visited,
1296-
next_identifier, false);
1297-
}
1298-
12991328
assert(!rows.empty() || !doc_children.empty());
13001329

13011330
documentation.assign("rows", std::move(rows));

0 commit comments

Comments
 (0)