@@ -35,6 +35,70 @@ inline auto APPLIES_TO_POINTERS(std::vector<Pointer> &&keywords)
3535 return {std::move (keywords)};
3636}
3737
38+ // TODO: Move upstream
39+ inline auto IS_IN_PLACE_APPLICATOR (const SchemaKeywordType type) -> bool {
40+ return type == SchemaKeywordType::ApplicatorValueOrElementsInPlace ||
41+ type == SchemaKeywordType::ApplicatorMembersInPlaceSome ||
42+ type == SchemaKeywordType::ApplicatorElementsInPlace ||
43+ type == SchemaKeywordType::ApplicatorElementsInPlaceSome ||
44+ type == SchemaKeywordType::ApplicatorElementsInPlaceSomeNegate ||
45+ type == SchemaKeywordType::ApplicatorValueInPlaceMaybe ||
46+ type == SchemaKeywordType::ApplicatorValueInPlaceOther ||
47+ type == SchemaKeywordType::ApplicatorValueInPlaceNegate;
48+ }
49+
50+ // Walk up from a schema location, continuing as long as the traversal
51+ // predicate returns true for each keyword type encountered. Returns a
52+ // reference to the pointer of the ancestor where the match callback returned
53+ // true, or nullopt if no match was found or the traversal predicate stopped
54+ // the walk.
55+ template <typename TraversePredicate, typename MatchCallback>
56+ auto WALK_UP (const JSON &root, const SchemaFrame &frame,
57+ const SchemaFrame::Location &location, const SchemaWalker &walker,
58+ const SchemaResolver &resolver,
59+ const TraversePredicate &should_continue,
60+ const MatchCallback &matches)
61+ -> std::optional<std::reference_wrapper<const WeakPointer>> {
62+ auto current_pointer{location.pointer };
63+ auto current_parent{location.parent };
64+
65+ while (current_parent.has_value ()) {
66+ const auto &parent_pointer{current_parent.value ()};
67+ const auto relative_pointer{current_pointer.resolve_from (parent_pointer)};
68+ assert (!relative_pointer.empty () && relative_pointer.at (0 ).is_property ());
69+ const auto parent{frame.traverse (frame.uri (parent_pointer).value ().get ())};
70+ assert (parent.has_value ());
71+ const auto keyword_type{
72+ walker (relative_pointer.at (0 ).to_property (),
73+ frame.vocabularies (parent.value ().get (), resolver))
74+ .type };
75+
76+ if (!should_continue (keyword_type)) {
77+ return std::nullopt ;
78+ }
79+
80+ if (matches (get (root, parent_pointer))) {
81+ return std::cref (parent.value ().get ().pointer );
82+ }
83+
84+ current_pointer = parent_pointer;
85+ current_parent = parent.value ().get ().parent ;
86+ }
87+
88+ return std::nullopt ;
89+ }
90+
91+ template <typename MatchCallback>
92+ auto WALK_UP_IN_PLACE_APPLICATORS (const JSON &root, const SchemaFrame &frame,
93+ const SchemaFrame::Location &location,
94+ const SchemaWalker &walker,
95+ const SchemaResolver &resolver,
96+ const MatchCallback &matches)
97+ -> std::optional<std::reference_wrapper<const WeakPointer>> {
98+ return WALK_UP (root, frame, location, walker, resolver,
99+ IS_IN_PLACE_APPLICATOR, matches);
100+ }
101+
38102#define ONLY_CONTINUE_IF (condition ) \
39103 if (!(condition)) { \
40104 return false ; \
@@ -55,6 +119,7 @@ inline auto APPLIES_TO_POINTERS(std::vector<Pointer> &&keywords)
55119#include " canonicalizer/properties_implicit.h"
56120#include " canonicalizer/type_array_to_any_of.h"
57121#include " canonicalizer/type_boolean_as_enum.h"
122+ #include " canonicalizer/type_inherit_in_place.h"
58123#include " canonicalizer/type_null_as_enum.h"
59124#include " canonicalizer/type_union_implicit.h"
60125
@@ -155,6 +220,7 @@ namespace sourcemeta::blaze {
155220auto add (sourcemeta::core::SchemaTransformer &bundle,
156221 const AlterSchemaMode mode) -> void {
157222 if (mode == AlterSchemaMode::Canonicalizer) {
223+ bundle.add <TypeInheritInPlace>();
158224 bundle.add <TypeUnionImplicit>();
159225 bundle.add <TypeArrayToAnyOf>();
160226 }
0 commit comments