@@ -2193,6 +2193,11 @@ func extractSchemaChanges(
21932193 return
21942194 }
21952195
2196+ if isOrderInsensitiveSchemaCompositionLabel (label ) {
2197+ extractOrderInsensitiveSchemaChanges (lSchema , rSchema , label , sc , changes )
2198+ return
2199+ }
2200+
21962201 x := "%x"
21972202 // create hash key maps to check equality
21982203 lKeys := make ([]string , 0 , len (lSchema ))
@@ -2274,6 +2279,139 @@ func extractSchemaChanges(
22742279 }
22752280}
22762281
2282+ type schemaCompositionEntry struct {
2283+ identity string
2284+ proxy * base.SchemaProxy
2285+ }
2286+
2287+ func isOrderInsensitiveSchemaCompositionLabel (label string ) bool {
2288+ switch label {
2289+ case v3 .AllOfLabel , v3 .AnyOfLabel , v3 .OneOfLabel :
2290+ return true
2291+ default :
2292+ return false
2293+ }
2294+ }
2295+
2296+ func schemaCompositionEntryIdentity (proxy * base.SchemaProxy ) string {
2297+ if proxy == nil {
2298+ return "nil"
2299+ }
2300+ if proxy .IsReference () {
2301+ return "ref:" + proxy .GetReference ()
2302+ }
2303+ return fmt .Sprintf ("hash:%x" , proxy .Hash ())
2304+ }
2305+
2306+ func buildSchemaCompositionEntries (schema []low.ValueReference [* base.SchemaProxy ]) []schemaCompositionEntry {
2307+ entries := make ([]schemaCompositionEntry , 0 , len (schema ))
2308+ for i := range schema {
2309+ proxy := schema [i ].Value
2310+ entries = append (entries , schemaCompositionEntry {
2311+ identity : schemaCompositionEntryIdentity (proxy ),
2312+ proxy : proxy ,
2313+ })
2314+ }
2315+ return entries
2316+ }
2317+
2318+ func matchSchemaCompositionIdentityCounts (
2319+ leftEntries , rightEntries []schemaCompositionEntry ,
2320+ ) map [string ]int {
2321+ rightCounts := make (map [string ]int )
2322+ matchedCounts := make (map [string ]int )
2323+
2324+ for i := range rightEntries {
2325+ rightCounts [rightEntries [i ].identity ]++
2326+ }
2327+ for i := range leftEntries {
2328+ identity := leftEntries [i ].identity
2329+ if matchedCounts [identity ] < rightCounts [identity ] {
2330+ matchedCounts [identity ]++
2331+ }
2332+ }
2333+ return matchedCounts
2334+ }
2335+
2336+ func filterUnmatchedSchemaCompositionEntries (
2337+ entries []schemaCompositionEntry ,
2338+ matchedCounts map [string ]int ,
2339+ ) []schemaCompositionEntry {
2340+ usedCounts := make (map [string ]int )
2341+ unmatched := make ([]schemaCompositionEntry , 0 , len (entries ))
2342+
2343+ for i := range entries {
2344+ identity := entries [i ].identity
2345+ if usedCounts [identity ] < matchedCounts [identity ] {
2346+ usedCounts [identity ]++
2347+ continue
2348+ }
2349+ unmatched = append (unmatched , entries [i ])
2350+ }
2351+ return unmatched
2352+ }
2353+
2354+ func schemaCompositionChangeBreaking (label string , changeType int ) bool {
2355+ switch label {
2356+ case v3 .AllOfLabel :
2357+ if changeType == ObjectAdded {
2358+ return BreakingAdded (CompSchema , PropAllOf )
2359+ }
2360+ return BreakingRemoved (CompSchema , PropAllOf )
2361+ case v3 .AnyOfLabel :
2362+ if changeType == ObjectAdded {
2363+ return BreakingAdded (CompSchema , PropAnyOf )
2364+ }
2365+ return BreakingRemoved (CompSchema , PropAnyOf )
2366+ case v3 .OneOfLabel :
2367+ if changeType == ObjectAdded {
2368+ return BreakingAdded (CompSchema , PropOneOf )
2369+ }
2370+ return BreakingRemoved (CompSchema , PropOneOf )
2371+ case v3 .PrefixItemsLabel :
2372+ if changeType == ObjectAdded {
2373+ return BreakingAdded (CompSchema , PropPrefixItems )
2374+ }
2375+ return BreakingRemoved (CompSchema , PropPrefixItems )
2376+ default :
2377+ return changeType != ObjectAdded
2378+ }
2379+ }
2380+
2381+ func extractOrderInsensitiveSchemaChanges (
2382+ lSchema []low.ValueReference [* base.SchemaProxy ],
2383+ rSchema []low.ValueReference [* base.SchemaProxy ],
2384+ label string ,
2385+ sc * []* SchemaChanges ,
2386+ changes * []* Change ,
2387+ ) {
2388+ leftEntries := buildSchemaCompositionEntries (lSchema )
2389+ rightEntries := buildSchemaCompositionEntries (rSchema )
2390+ matchedCounts := matchSchemaCompositionIdentityCounts (leftEntries , rightEntries )
2391+
2392+ leftUnmatched := filterUnmatchedSchemaCompositionEntries (leftEntries , matchedCounts )
2393+ rightUnmatched := filterUnmatchedSchemaCompositionEntries (rightEntries , matchedCounts )
2394+
2395+ pairs := min (len (leftUnmatched ), len (rightUnmatched ))
2396+ for i := 0 ; i < pairs ; i ++ {
2397+ * sc = append (* sc , CompareSchemas (leftUnmatched [i ].proxy , rightUnmatched [i ].proxy ))
2398+ }
2399+
2400+ for i := pairs ; i < len (leftUnmatched ); i ++ {
2401+ CreateChange (changes , ObjectRemoved , label ,
2402+ leftUnmatched [i ].proxy .GetValueNode (), nil ,
2403+ schemaCompositionChangeBreaking (label , ObjectRemoved ),
2404+ leftUnmatched [i ].proxy , nil )
2405+ }
2406+
2407+ for i := pairs ; i < len (rightUnmatched ); i ++ {
2408+ CreateChange (changes , ObjectAdded , label ,
2409+ nil , rightUnmatched [i ].proxy .GetValueNode (),
2410+ schemaCompositionChangeBreaking (label , ObjectAdded ),
2411+ nil , rightUnmatched [i ].proxy )
2412+ }
2413+ }
2414+
22772415// checkDependentRequiredChanges compares two DependentRequired maps and returns any changes found
22782416func checkDependentRequiredChanges (
22792417 left , right * orderedmap.Map [low.KeyReference [string ], low.ValueReference [[]string ]],
0 commit comments