Skip to content

Commit

Permalink
[WIP] Extend schema walker to account for conditional instance locations
Browse files Browse the repository at this point in the history
Signed-off-by: Juan Cruz Viotti <[email protected]>
  • Loading branch information
jviotti committed Feb 12, 2025
1 parent 77e6776 commit e36bfc0
Show file tree
Hide file tree
Showing 14 changed files with 113 additions and 70 deletions.
2 changes: 1 addition & 1 deletion src/core/jsonschema/frame.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1084,7 +1084,7 @@ auto find_adjacent_dependencies(
}

break;
case SchemaKeywordType::ApplicatorMembersInPlace:
case SchemaKeywordType::ApplicatorMembersInPlaceSome:
if (property.second.is_object()) {
for (const auto &pair : property.second.as_object()) {
find_adjacent_dependencies(
Expand Down
10 changes: 7 additions & 3 deletions src/core/jsonschema/include/sourcemeta/core/jsonschema_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ enum class SchemaKeywordType : std::uint8_t {
ApplicatorMembersTraversePropertyRegex,
/// The JSON Schema keyword is an applicator that potentially
/// takes a JSON Schema definition as an argument
/// The instance traverses to any property
ApplicatorValueTraverseAnyProperty,
/// The instance traverses to some of the properties
ApplicatorValueTraverseSomeProperty,
/// The JSON Schema keyword is an applicator that potentially
/// takes a JSON Schema definition as an argument
/// The instance traverses to any property key
Expand All @@ -99,6 +99,10 @@ enum class SchemaKeywordType : std::uint8_t {
ApplicatorValueTraverseAnyItem,
/// The JSON Schema keyword is an applicator that potentially
/// takes a JSON Schema definition as an argument
/// The instance traverses to some of the items
ApplicatorValueTraverseSomeItem,
/// The JSON Schema keyword is an applicator that potentially
/// takes a JSON Schema definition as an argument
/// The instance traverses back to the parent
ApplicatorValueTraverseParent,
/// The JSON Schema keyword is an applicator that potentially
Expand All @@ -120,7 +124,7 @@ enum class SchemaKeywordType : std::uint8_t {
/// takes an object as argument, whose values are potentially
/// JSON Schema definitions without affecting the instance location.
/// The instance does not traverse
ApplicatorMembersInPlace,
ApplicatorMembersInPlaceSome,
/// The JSON Schema keyword is an applicator that potentially
/// takes an array of potentially JSON Schema definitions
/// as an argument without affecting the instance location
Expand Down
65 changes: 33 additions & 32 deletions src/core/jsonschema/official_walker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -53,19 +53,19 @@ auto sourcemeta::core::schema_official_walker(
ApplicatorMembersTraversePropertyStatic,
HTTPS_BASE "2020-12/vocab/validation", "required")
WALK(HTTPS_BASE "2020-12/vocab/applicator", "additionalProperties",
ApplicatorValueTraverseAnyProperty, "properties", "patternProperties")
ApplicatorValueTraverseSomeProperty, "properties", "patternProperties")
WALK(HTTPS_BASE "2020-12/vocab/applicator", "patternProperties",
ApplicatorMembersTraversePropertyRegex)
WALK(HTTPS_BASE "2020-12/vocab/applicator", "propertyNames",
ApplicatorValueTraverseAnyPropertyKey)
WALK(HTTPS_BASE "2020-12/vocab/applicator", "dependentSchemas",
ApplicatorMembersInPlace)
ApplicatorMembersInPlaceSome)
WALK_MAYBE_DEPENDENT(HTTPS_BASE "2020-12/vocab/applicator", "contains",
ApplicatorValueTraverseAnyItem,
HTTPS_BASE "2020-12/vocab/validation", "minContains",
"maxContains")
WALK(HTTPS_BASE "2020-12/vocab/applicator", "items",
ApplicatorValueTraverseAnyItem, "prefixItems")
ApplicatorValueTraverseSomeItem, "prefixItems")
WALK(HTTPS_BASE "2020-12/vocab/applicator", "prefixItems",
ApplicatorElementsTraverseItem)
// For the purpose of compiler optimizations
Expand Down Expand Up @@ -98,12 +98,13 @@ auto sourcemeta::core::schema_official_walker(
WALK(HTTPS_BASE "2020-12/vocab/meta-data", "default", Annotation)
WALK(HTTPS_BASE "2020-12/vocab/meta-data", "deprecated", Annotation)
WALK(HTTPS_BASE "2020-12/vocab/format-annotation", "format", Annotation)
WALK_MAYBE_DEPENDENT(
HTTPS_BASE "2020-12/vocab/unevaluated", "unevaluatedProperties",
ApplicatorValueTraverseAnyProperty, HTTPS_BASE "2020-12/vocab/applicator",
"properties", "patternProperties", "additionalProperties")
WALK_MAYBE_DEPENDENT(HTTPS_BASE "2020-12/vocab/unevaluated",
"unevaluatedItems", ApplicatorValueTraverseAnyItem,
"unevaluatedProperties",
ApplicatorValueTraverseSomeProperty,
HTTPS_BASE "2020-12/vocab/applicator", "properties",
"patternProperties", "additionalProperties")
WALK_MAYBE_DEPENDENT(HTTPS_BASE "2020-12/vocab/unevaluated",
"unevaluatedItems", ApplicatorValueTraverseSomeItem,
HTTPS_BASE "2020-12/vocab/applicator", "prefixItems",
"items", "contains")
WALK(HTTPS_BASE "2020-12/vocab/content", "contentSchema",
Expand Down Expand Up @@ -145,24 +146,24 @@ auto sourcemeta::core::schema_official_walker(
WALK(HTTPS_BASE "2019-09/vocab/applicator", "patternProperties",
ApplicatorMembersTraversePropertyRegex)
WALK(HTTPS_BASE "2019-09/vocab/applicator", "additionalProperties",
ApplicatorValueTraverseAnyProperty, "properties", "patternProperties")
ApplicatorValueTraverseSomeProperty, "properties", "patternProperties")
WALK(HTTPS_BASE "2019-09/vocab/applicator", "propertyNames",
ApplicatorValueTraverseAnyPropertyKey)
WALK(HTTPS_BASE "2019-09/vocab/applicator", "dependentSchemas",
ApplicatorMembersInPlace)
ApplicatorMembersInPlaceSome)
WALK(HTTPS_BASE "2019-09/vocab/applicator", "unevaluatedProperties",
ApplicatorValueTraverseAnyProperty, "properties", "patternProperties",
ApplicatorValueTraverseSomeProperty, "properties", "patternProperties",
"additionalProperties")
WALK(HTTPS_BASE "2019-09/vocab/applicator", "unevaluatedItems",
ApplicatorValueTraverseAnyItem, "items", "additionalItems")
ApplicatorValueTraverseSomeItem, "items", "additionalItems")
WALK(HTTPS_BASE "2019-09/vocab/applicator", "items",
ApplicatorValueOrElementsTraverseAnyItemOrItem)
WALK_MAYBE_DEPENDENT(HTTPS_BASE "2019-09/vocab/applicator", "contains",
ApplicatorValueTraverseAnyItem,
HTTPS_BASE "2019-09/vocab/validation", "minContains",
"maxContains")
WALK(HTTPS_BASE "2019-09/vocab/applicator", "additionalItems",
ApplicatorValueTraverseAnyItem, "items")
ApplicatorValueTraverseSomeItem, "items")
// For the purpose of compiler optimizations
WALK_MAYBE_DEPENDENT(HTTPS_BASE "2019-09/vocab/validation", "type", Assertion,
HTTPS_BASE "2019-09/vocab/applicator", "properties")
Expand Down Expand Up @@ -244,7 +245,7 @@ auto sourcemeta::core::schema_official_walker(
WALK_ANY(HTTP_BASE "draft-07/schema#", HTTP_BASE "draft-07/hyper-schema#",
"items", ApplicatorValueOrElementsTraverseAnyItemOrItem, "$ref")
WALK_ANY(HTTP_BASE "draft-07/schema#", HTTP_BASE "draft-07/hyper-schema#",
"additionalItems", ApplicatorValueTraverseAnyItem, "items")
"additionalItems", ApplicatorValueTraverseSomeItem, "items")
WALK_ANY(HTTP_BASE "draft-07/schema#", HTTP_BASE "draft-07/hyper-schema#",
"maxItems", Assertion, "$ref")
WALK_ANY(HTTP_BASE "draft-07/schema#", HTTP_BASE "draft-07/hyper-schema#",
Expand All @@ -266,10 +267,10 @@ auto sourcemeta::core::schema_official_walker(
WALK_ANY(HTTP_BASE "draft-07/schema#", HTTP_BASE "draft-07/hyper-schema#",
"patternProperties", ApplicatorMembersTraversePropertyRegex, "$ref")
WALK_ANY(HTTP_BASE "draft-07/schema#", HTTP_BASE "draft-07/hyper-schema#",
"additionalProperties", ApplicatorValueTraverseAnyProperty,
"additionalProperties", ApplicatorValueTraverseSomeProperty,
"properties", "patternProperties")
WALK_ANY(HTTP_BASE "draft-07/schema#", HTTP_BASE "draft-07/hyper-schema#",
"dependencies", ApplicatorMembersInPlace, "$ref")
"dependencies", ApplicatorMembersInPlaceSome, "$ref")
WALK_ANY(HTTP_BASE "draft-07/schema#", HTTP_BASE "draft-07/hyper-schema#",
"propertyNames", ApplicatorValueTraverseAnyPropertyKey, "$ref")
WALK_ANY(HTTP_BASE "draft-07/schema#", HTTP_BASE "draft-07/hyper-schema#",
Expand Down Expand Up @@ -362,7 +363,7 @@ auto sourcemeta::core::schema_official_walker(
WALK_ANY(HTTP_BASE "draft-06/schema#", HTTP_BASE "draft-06/hyper-schema#",
"items", ApplicatorValueOrElementsTraverseAnyItemOrItem, "$ref")
WALK_ANY(HTTP_BASE "draft-06/schema#", HTTP_BASE "draft-06/hyper-schema#",
"additionalItems", ApplicatorValueTraverseAnyItem, "items")
"additionalItems", ApplicatorValueTraverseSomeItem, "items")
WALK_ANY(HTTP_BASE "draft-06/schema#", HTTP_BASE "draft-06/hyper-schema#",
"maxItems", Assertion, "$ref")
WALK_ANY(HTTP_BASE "draft-06/schema#", HTTP_BASE "draft-06/hyper-schema#",
Expand All @@ -384,10 +385,10 @@ auto sourcemeta::core::schema_official_walker(
WALK_ANY(HTTP_BASE "draft-06/schema#", HTTP_BASE "draft-06/hyper-schema#",
"patternProperties", ApplicatorMembersTraversePropertyRegex, "$ref")
WALK_ANY(HTTP_BASE "draft-06/schema#", HTTP_BASE "draft-06/hyper-schema#",
"additionalProperties", ApplicatorValueTraverseAnyProperty,
"additionalProperties", ApplicatorValueTraverseSomeProperty,
"properties", "patternProperties")
WALK_ANY(HTTP_BASE "draft-06/schema#", HTTP_BASE "draft-06/hyper-schema#",
"dependencies", ApplicatorMembersInPlace, "$ref")
"dependencies", ApplicatorMembersInPlaceSome, "$ref")
WALK_ANY(HTTP_BASE "draft-06/schema#", HTTP_BASE "draft-06/hyper-schema#",
"propertyNames", ApplicatorValueTraverseAnyPropertyKey, "$ref")
WALK_ANY(HTTP_BASE "draft-06/schema#", HTTP_BASE "draft-06/hyper-schema#",
Expand Down Expand Up @@ -467,7 +468,7 @@ auto sourcemeta::core::schema_official_walker(
WALK_ANY(HTTP_BASE "draft-04/schema#", HTTP_BASE "draft-04/hyper-schema#",
"items", ApplicatorValueOrElementsTraverseAnyItemOrItem, "$ref")
WALK_ANY(HTTP_BASE "draft-04/schema#", HTTP_BASE "draft-04/hyper-schema#",
"additionalItems", ApplicatorValueTraverseAnyItem, "items")
"additionalItems", ApplicatorValueTraverseSomeItem, "items")
WALK_ANY(HTTP_BASE "draft-04/schema#", HTTP_BASE "draft-04/hyper-schema#",
"maxItems", Assertion, "$ref")
WALK_ANY(HTTP_BASE "draft-04/schema#", HTTP_BASE "draft-04/hyper-schema#",
Expand All @@ -487,10 +488,10 @@ auto sourcemeta::core::schema_official_walker(
WALK_ANY(HTTP_BASE "draft-04/schema#", HTTP_BASE "draft-04/hyper-schema#",
"patternProperties", ApplicatorMembersTraversePropertyRegex, "$ref")
WALK_ANY(HTTP_BASE "draft-04/schema#", HTTP_BASE "draft-04/hyper-schema#",
"additionalProperties", ApplicatorValueTraverseAnyProperty,
"additionalProperties", ApplicatorValueTraverseSomeProperty,
"properties", "patternProperties")
WALK_ANY(HTTP_BASE "draft-04/schema#", HTTP_BASE "draft-04/hyper-schema#",
"dependencies", ApplicatorMembersInPlace, "$ref")
"dependencies", ApplicatorMembersInPlaceSome, "$ref")
WALK_ANY(HTTP_BASE "draft-04/schema#", HTTP_BASE "draft-04/hyper-schema#",
"allOf", ApplicatorElementsInPlaceInline, "$ref")
WALK_ANY(HTTP_BASE "draft-04/schema#", HTTP_BASE "draft-04/hyper-schema#",
Expand Down Expand Up @@ -538,17 +539,17 @@ auto sourcemeta::core::schema_official_walker(
WALK(HTTP_BASE "draft-03/schema#", "patternProperties",
ApplicatorMembersTraversePropertyRegex, "$ref")
WALK(HTTP_BASE "draft-03/schema#", "additionalProperties",
ApplicatorValueTraverseAnyProperty, "properties", "patternProperties")
ApplicatorValueTraverseSomeProperty, "properties", "patternProperties")
WALK(HTTP_BASE "draft-03/schema#", "items",
ApplicatorValueOrElementsTraverseAnyItemOrItem, "$ref")
WALK(HTTP_BASE "draft-03/schema#", "additionalItems",
ApplicatorValueTraverseAnyItem, "items")
ApplicatorValueTraverseSomeItem, "items")
WALK(HTTP_BASE "draft-03/schema#", "minItems", Assertion, "$ref")
WALK(HTTP_BASE "draft-03/schema#", "maxItems", Assertion, "$ref")
WALK(HTTP_BASE "draft-03/schema#", "uniqueItems", Assertion, "$ref")
WALK(HTTP_BASE "draft-03/schema#", "required", Assertion, "$ref")
WALK(HTTP_BASE "draft-03/schema#", "dependencies", ApplicatorMembersInPlace,
"$ref")
WALK(HTTP_BASE "draft-03/schema#", "dependencies",
ApplicatorMembersInPlaceSome, "$ref")
WALK(HTTP_BASE "draft-03/schema#", "enum", Assertion, "$ref")
WALK(HTTP_BASE "draft-03/schema#", "pattern", Assertion, "$ref")
WALK(HTTP_BASE "draft-03/schema#", "minLength", Assertion, "$ref")
Expand Down Expand Up @@ -582,7 +583,7 @@ auto sourcemeta::core::schema_official_walker(
WALK(HTTP_BASE "draft-02/schema#", "properties",
ApplicatorMembersTraversePropertyStatic)
WALK(HTTP_BASE "draft-02/schema#", "additionalProperties",
ApplicatorValueTraverseAnyProperty, "properties")
ApplicatorValueTraverseSomeProperty, "properties")
WALK(HTTP_BASE "draft-02/schema#", "type", ApplicatorElementsInPlace)
WALK(HTTP_BASE "draft-02/schema#", "enum", Assertion)
WALK(HTTP_BASE "draft-02/schema#", "maximum", Assertion)
Expand Down Expand Up @@ -617,7 +618,7 @@ auto sourcemeta::core::schema_official_walker(
WALK(HTTP_BASE "draft-02/hyper-schema#", "extends",
ApplicatorValueOrElementsInPlace)
WALK(HTTP_BASE "draft-02/hyper-schema#", "additionalProperties",
ApplicatorValueTraverseAnyProperty, "properties")
ApplicatorValueTraverseSomeProperty, "properties")

// Draft1
WALK(HTTP_BASE "draft-01/schema#", "$schema", Other)
Expand All @@ -628,7 +629,7 @@ auto sourcemeta::core::schema_official_walker(
WALK(HTTP_BASE "draft-01/schema#", "properties",
ApplicatorMembersTraversePropertyStatic)
WALK(HTTP_BASE "draft-01/schema#", "additionalProperties",
ApplicatorValueTraverseAnyProperty, "properties")
ApplicatorValueTraverseSomeProperty, "properties")
WALK(HTTP_BASE "draft-01/schema#", "type", ApplicatorElementsInPlace)
WALK(HTTP_BASE "draft-01/schema#", "enum", Assertion)
WALK(HTTP_BASE "draft-01/schema#", "maximum", Assertion)
Expand Down Expand Up @@ -661,7 +662,7 @@ auto sourcemeta::core::schema_official_walker(
WALK(HTTP_BASE "draft-01/hyper-schema#", "requires",
ApplicatorValueTraverseParent)
WALK(HTTP_BASE "draft-01/hyper-schema#", "additionalProperties",
ApplicatorValueTraverseAnyProperty, "properties")
ApplicatorValueTraverseSomeProperty, "properties")

// Draft0
WALK(HTTP_BASE "draft-00/schema#", "$schema", Other)
Expand All @@ -672,7 +673,7 @@ auto sourcemeta::core::schema_official_walker(
WALK(HTTP_BASE "draft-00/schema#", "properties",
ApplicatorMembersTraversePropertyStatic)
WALK(HTTP_BASE "draft-00/schema#", "additionalProperties",
ApplicatorValueTraverseAnyProperty, "properties")
ApplicatorValueTraverseSomeProperty, "properties")
WALK(HTTP_BASE "draft-00/schema#", "type", ApplicatorElementsInPlace)
WALK(HTTP_BASE "draft-00/schema#", "enum", Assertion)
WALK(HTTP_BASE "draft-00/schema#", "maximum", Assertion)
Expand Down Expand Up @@ -705,7 +706,7 @@ auto sourcemeta::core::schema_official_walker(
WALK(HTTP_BASE "draft-00/hyper-schema#", "requires",
ApplicatorValueTraverseParent)
WALK(HTTP_BASE "draft-00/hyper-schema#", "additionalProperties",
ApplicatorValueTraverseAnyProperty, "properties")
ApplicatorValueTraverseSomeProperty, "properties")
#undef HTTP_BASE
#undef WALK
#undef WALK_ANY
Expand Down
31 changes: 27 additions & 4 deletions src/core/jsonschema/walker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,17 @@ auto walk(const std::optional<sourcemeta::core::Pointer> &parent,
for (auto &pair : subschema.as_object()) {
switch (walker(pair.first, vocabularies).type) {
case sourcemeta::core::SchemaKeywordType::
ApplicatorValueTraverseAnyProperty: {
ApplicatorValueTraverseSomeProperty: {
sourcemeta::core::Pointer new_pointer{pointer};
new_pointer.emplace_back(pair.first);
auto new_instance_location{instance_location};
new_instance_location.emplace_back(
sourcemeta::core::PointerTemplate::Conditional{});
new_instance_location.emplace_back(
sourcemeta::core::PointerTemplate::Wildcard::Property);
walk(pointer, new_pointer, new_instance_location,
{sourcemeta::core::PointerTemplate::Wildcard::Property},
{sourcemeta::core::PointerTemplate::Conditional{},
sourcemeta::core::PointerTemplate::Wildcard::Property},
subschemas, pair.second, walker, resolver, new_dialect, type,
level + 1, orphan);
} break;
Expand Down Expand Up @@ -90,6 +93,22 @@ auto walk(const std::optional<sourcemeta::core::Pointer> &parent,
orphan);
} break;

case sourcemeta::core::SchemaKeywordType::
ApplicatorValueTraverseSomeItem: {
sourcemeta::core::Pointer new_pointer{pointer};
new_pointer.emplace_back(pair.first);
auto new_instance_location{instance_location};
new_instance_location.emplace_back(
sourcemeta::core::PointerTemplate::Conditional{});
new_instance_location.emplace_back(
sourcemeta::core::PointerTemplate::Wildcard::Item);
walk(pointer, new_pointer, new_instance_location,
{sourcemeta::core::PointerTemplate::Conditional{},
sourcemeta::core::PointerTemplate::Wildcard::Item},
subschemas, pair.second, walker, resolver, new_dialect, type,
level + 1, orphan);
} break;

case sourcemeta::core::SchemaKeywordType::ApplicatorValueTraverseParent: {
sourcemeta::core::Pointer new_pointer{pointer};
new_pointer.emplace_back(pair.first);
Expand Down Expand Up @@ -176,13 +195,17 @@ auto walk(const std::optional<sourcemeta::core::Pointer> &parent,

break;

case sourcemeta::core::SchemaKeywordType::ApplicatorMembersInPlace:
case sourcemeta::core::SchemaKeywordType::ApplicatorMembersInPlaceSome:
if (pair.second.is_object()) {
for (auto &subpair : pair.second.as_object()) {
sourcemeta::core::Pointer new_pointer{pointer};
new_pointer.emplace_back(pair.first);
new_pointer.emplace_back(subpair.first);
walk(pointer, new_pointer, instance_location, {}, subschemas,
auto new_instance_location{instance_location};
new_instance_location.emplace_back(
sourcemeta::core::PointerTemplate::Conditional{});
walk(pointer, new_pointer, new_instance_location,
{sourcemeta::core::PointerTemplate::Conditional{}}, subschemas,
subpair.second, walker, resolver, new_dialect, type, level + 1,
orphan);
}
Expand Down
8 changes: 5 additions & 3 deletions test/jsonschema/jsonschema_official_walker_2019_09_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ TEST(JSONSchema_official_walker_2019_09, applicator_dependentSchemas) {
using namespace sourcemeta::core;
const auto result{schema_official_walker("dependentSchemas",
VOCABULARIES_2019_09_APPLICATOR)};
EXPECT_EQ(result.type, SchemaKeywordType::ApplicatorMembersInPlace);
EXPECT_EQ(result.type, SchemaKeywordType::ApplicatorMembersInPlaceSome);
EXPECT_TRUE(result.vocabulary.has_value());
EXPECT_EQ(result.vocabulary.value(),
"https://json-schema.org/draft/2019-09/vocab/applicator");
Expand Down Expand Up @@ -299,7 +299,8 @@ TEST(JSONSchema_official_walker_2019_09, applicator_additionalProperties) {
using namespace sourcemeta::core;
const auto result{schema_official_walker("additionalProperties",
VOCABULARIES_2019_09_APPLICATOR)};
EXPECT_EQ(result.type, SchemaKeywordType::ApplicatorValueTraverseAnyProperty);
EXPECT_EQ(result.type,
SchemaKeywordType::ApplicatorValueTraverseSomeProperty);
EXPECT_TRUE(result.vocabulary.has_value());
EXPECT_EQ(result.vocabulary.value(),
"https://json-schema.org/draft/2019-09/vocab/applicator");
Expand Down Expand Up @@ -335,7 +336,8 @@ TEST(JSONSchema_official_walker_2019_09, applicator_unevaluatedProperties) {
using namespace sourcemeta::core;
const auto result{schema_official_walker("unevaluatedProperties",
VOCABULARIES_2019_09_APPLICATOR)};
EXPECT_EQ(result.type, SchemaKeywordType::ApplicatorValueTraverseAnyProperty);
EXPECT_EQ(result.type,
SchemaKeywordType::ApplicatorValueTraverseSomeProperty);
EXPECT_TRUE(result.vocabulary.has_value());
EXPECT_EQ(result.vocabulary.value(),
"https://json-schema.org/draft/2019-09/vocab/applicator");
Expand Down
Loading

0 comments on commit e36bfc0

Please sign in to comment.