Skip to content

Commit 39f5a20

Browse files
committed
[WIP] Fix a reachability children $defs/definitions bug
Signed-off-by: Juan Cruz Viotti <[email protected]>
1 parent eacb685 commit 39f5a20

File tree

3 files changed

+103
-10
lines changed

3 files changed

+103
-10
lines changed

src/core/jsonschema/frame.cc

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,7 +1462,8 @@ auto SchemaFrame::populate_reachability(const Location &base,
14621462
if (pointer == base.pointer) {
14631463
is_reachable = true;
14641464
} else if (pointer.starts_with(base.pointer)) {
1465-
is_reachable = pointers_with_non_orphan.contains(pointer_reference);
1465+
is_reachable =
1466+
base.orphan || pointers_with_non_orphan.contains(pointer_reference);
14661467
}
14671468

14681469
cache.emplace(pointer_reference, is_reachable);
@@ -1494,7 +1495,7 @@ auto SchemaFrame::populate_reachability(const Location &base,
14941495
if (pointer == base.pointer) {
14951496
is_reachable = true;
14961497
} else if (pointer.starts_with(base.pointer)) {
1497-
is_reachable = has_non_orphan;
1498+
is_reachable = base.orphan || has_non_orphan;
14981499
}
14991500

15001501
cache.emplace(pointer_reference, is_reachable);
@@ -1504,6 +1505,63 @@ auto SchemaFrame::populate_reachability(const Location &base,
15041505
}
15051506
}
15061507

1508+
// ---------------------------------------------------------------------------
1509+
// (1b) Filter out descendants that cross a LocationMembers boundary
1510+
// ---------------------------------------------------------------------------
1511+
1512+
if (base.orphan) {
1513+
std::unordered_map<SchemaBaseDialect, Vocabularies> base_vocab_cache;
1514+
for (auto &[cache_pointer, cache_reachable] : cache) {
1515+
if (!cache_reachable) {
1516+
continue;
1517+
}
1518+
const auto &pointer{cache_pointer.get()};
1519+
if (pointer == base.pointer) {
1520+
continue;
1521+
}
1522+
1523+
auto check_location{this->traverse(pointer)};
1524+
while (check_location.has_value()) {
1525+
const auto &location{check_location->get()};
1526+
if (location.pointer == base.pointer) {
1527+
break;
1528+
}
1529+
1530+
if (!location.parent.has_value()) {
1531+
break;
1532+
}
1533+
1534+
const auto parent_location{this->traverse(location.parent.value())};
1535+
if (!parent_location.has_value()) {
1536+
break;
1537+
}
1538+
1539+
const auto relative{
1540+
location.pointer.slice(location.parent.value().size())};
1541+
if (!relative.empty() && relative.at(0).is_property()) {
1542+
const auto &parent_loc{parent_location->get()};
1543+
auto vocab_iterator = base_vocab_cache.find(parent_loc.base_dialect);
1544+
if (vocab_iterator == base_vocab_cache.end()) {
1545+
auto [inserted_iterator, inserted] = base_vocab_cache.emplace(
1546+
parent_loc.base_dialect,
1547+
this->vocabularies(parent_loc, resolver));
1548+
vocab_iterator = inserted_iterator;
1549+
}
1550+
1551+
const auto &keyword_result{
1552+
walker(relative.at(0).to_property(), vocab_iterator->second)};
1553+
if (keyword_result.type == SchemaKeywordType::LocationMembers) {
1554+
cache_reachable = false;
1555+
unreachable_pointers.push_back(cache_pointer);
1556+
break;
1557+
}
1558+
}
1559+
1560+
check_location = parent_location;
1561+
}
1562+
}
1563+
}
1564+
15071565
// ---------------------------------------------------------------------------
15081566
// (2) Build a reverse mapping from reference destinations to their sources
15091567
// ---------------------------------------------------------------------------

test/jsonschema/jsonschema_frame_2019_09_test.cc

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2987,3 +2987,38 @@ TEST(JSONSchema_frame_2019_09, invalid_recursive_ref_not_string) {
29872987
FAIL();
29882988
}
29892989
}
2990+
2991+
TEST(JSONSchema_frame_2019_09, ref_from_def_to_sibling_def) {
2992+
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
2993+
"$schema": "https://json-schema.org/draft/2019-09/schema",
2994+
"$defs": {
2995+
"foo": {
2996+
"properties": {
2997+
"bar": { "$ref": "#/$defs/bar" }
2998+
}
2999+
},
3000+
"bar": {}
3001+
}
3002+
})JSON");
3003+
3004+
sourcemeta::core::SchemaFrame frame{
3005+
sourcemeta::core::SchemaFrame::Mode::References};
3006+
frame.analyse(document, sourcemeta::core::schema_walker,
3007+
sourcemeta::core::schema_resolver);
3008+
3009+
// Reachability
3010+
3011+
EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "", frame.root());
3012+
EXPECT_FRAME_LOCATION_NON_REACHABLE(frame, Static, "#/$defs/foo",
3013+
frame.root());
3014+
EXPECT_FRAME_LOCATION_NON_REACHABLE(
3015+
frame, Static, "#/$defs/foo/properties/bar", frame.root());
3016+
EXPECT_FRAME_LOCATION_NON_REACHABLE(frame, Static, "#/$defs/bar",
3017+
frame.root());
3018+
3019+
EXPECT_FRAME_LOCATION_NON_REACHABLE(frame, Static, "", "#/$defs/foo");
3020+
EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "#/$defs/foo", "#/$defs/foo");
3021+
EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "#/$defs/foo/properties/bar",
3022+
"#/$defs/foo");
3023+
EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "#/$defs/bar", "#/$defs/foo");
3024+
}

test/jsonschema/jsonschema_frame_2020_12_test.cc

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3734,10 +3734,10 @@ TEST(JSONSchema_frame_2020_12, property_ref_defs) {
37343734
EXPECT_FRAME_LOCATION_REACHABLE(
37353735
frame, Static, "https://www.sourcemeta.com/schema#/$defs/helper",
37363736
"https://www.sourcemeta.com/schema#/$defs/helper");
3737-
EXPECT_FRAME_LOCATION_NON_REACHABLE(
3737+
EXPECT_FRAME_LOCATION_REACHABLE(
37383738
frame, Static, "https://www.sourcemeta.com/schema#/$defs/helper/items",
37393739
"https://www.sourcemeta.com/schema#/$defs/helper");
3740-
EXPECT_FRAME_LOCATION_NON_REACHABLE(
3740+
EXPECT_FRAME_LOCATION_REACHABLE(
37413741
frame, Static,
37423742
"https://www.sourcemeta.com/schema#/$defs/helper/items/"
37433743
"additionalProperties",
@@ -3758,7 +3758,7 @@ TEST(JSONSchema_frame_2020_12, property_ref_defs) {
37583758
EXPECT_FRAME_LOCATION_REACHABLE(
37593759
frame, Static, "https://www.sourcemeta.com/schema#/$defs/helper/items",
37603760
"https://www.sourcemeta.com/schema#/$defs/helper/items");
3761-
EXPECT_FRAME_LOCATION_NON_REACHABLE(
3761+
EXPECT_FRAME_LOCATION_REACHABLE(
37623762
frame, Static,
37633763
"https://www.sourcemeta.com/schema#/$defs/helper/items/"
37643764
"additionalProperties",
@@ -4247,8 +4247,8 @@ TEST(JSONSchema_frame_2020_12, cross_id_anonymous_nested) {
42474247
EXPECT_FRAME_LOCATION_NON_REACHABLE(frame, Static, "", "#/$defs/schema");
42484248
EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "#/$defs/schema",
42494249
"#/$defs/schema");
4250-
EXPECT_FRAME_LOCATION_NON_REACHABLE(frame, Static, "#/$defs/schema/items",
4251-
"#/$defs/schema");
4250+
EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "#/$defs/schema/items",
4251+
"#/$defs/schema");
42524252

42534253
EXPECT_FRAME_LOCATION_NON_REACHABLE(frame, Static, "",
42544254
"#/$defs/schema/items");
@@ -6626,7 +6626,7 @@ TEST(JSONSchema_frame_2020_12, static_ref_to_dynamic_anchor) {
66266626
EXPECT_FRAME_LOCATION_REACHABLE(frame, Dynamic, "#target", "#/$defs/string");
66276627
EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "#/$defs/string",
66286628
"#/$defs/string");
6629-
EXPECT_FRAME_LOCATION_NON_REACHABLE(
6629+
EXPECT_FRAME_LOCATION_REACHABLE(
66306630
frame, Static, "#/$defs/string/additionalProperties", "#/$defs/string");
66316631
EXPECT_FRAME_LOCATION_NON_REACHABLE(
66326632
frame, Static, "#/$defs/string/additionalProperties/$defs/nested",
@@ -6850,11 +6850,11 @@ TEST(JSONSchema_frame_2020_12, property_named_defs) {
68506850
EXPECT_FRAME_LOCATION_REACHABLE(frame, Static,
68516851
"https://example.com/schema#/$defs/helper",
68526852
"https://example.com/schema#/$defs/helper");
6853-
EXPECT_FRAME_LOCATION_NON_REACHABLE(
6853+
EXPECT_FRAME_LOCATION_REACHABLE(
68546854
frame, Static,
68556855
"https://example.com/schema#/$defs/helper/properties/$defs",
68566856
"https://example.com/schema#/$defs/helper");
6857-
EXPECT_FRAME_LOCATION_NON_REACHABLE(
6857+
EXPECT_FRAME_LOCATION_REACHABLE(
68586858
frame, Static,
68596859
"https://example.com/schema#/$defs/helper/properties/definitions",
68606860
"https://example.com/schema#/$defs/helper");

0 commit comments

Comments
 (0)