mergeOpenapiSchemas merges two openAPI schemas and returns the schema all of whose fields are composed.
(s1, s2 openapi3.Schema, allOf bool, seenSchemaRef map[string]bool)
| 251 | // mergeOpenapiSchemas merges two openAPI schemas and returns the schema |
| 252 | // all of whose fields are composed. |
| 253 | func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool, seenSchemaRef map[string]bool) (openapi3.Schema, error) { |
| 254 | var result openapi3.Schema |
| 255 | |
| 256 | result.Extensions = make(map[string]any, len(s1.Extensions)+len(s2.Extensions)) |
| 257 | maps.Copy(result.Extensions, s1.Extensions) |
| 258 | // TODO: Check for collisions |
| 259 | maps.Copy(result.Extensions, s2.Extensions) |
| 260 | |
| 261 | result.OneOf = append(s1.OneOf, s2.OneOf...) |
| 262 | |
| 263 | // We are going to make AllOf transitive, so that merging an AllOf that |
| 264 | // contains AllOf's will result in a flat object. |
| 265 | var err error |
| 266 | if s1.AllOf != nil { |
| 267 | var merged openapi3.Schema |
| 268 | merged, err = mergeAllOf(s1.AllOf, seenSchemaRef) |
| 269 | if err != nil { |
| 270 | return openapi3.Schema{}, fmt.Errorf("error transitive merging AllOf on schema 1") |
| 271 | } |
| 272 | s1 = merged |
| 273 | } |
| 274 | if s2.AllOf != nil { |
| 275 | var merged openapi3.Schema |
| 276 | merged, err = mergeAllOf(s2.AllOf, seenSchemaRef) |
| 277 | if err != nil { |
| 278 | return openapi3.Schema{}, fmt.Errorf("error transitive merging AllOf on schema 2") |
| 279 | } |
| 280 | s2 = merged |
| 281 | } |
| 282 | |
| 283 | result.AllOf = append(s1.AllOf, s2.AllOf...) |
| 284 | |
| 285 | if s1.Type.Slice() != nil && s2.Type.Slice() != nil && !equalTypes(s1.Type, s2.Type) { |
| 286 | return openapi3.Schema{}, fmt.Errorf("can not merge incompatible types: %v, %v", s1.Type.Slice(), s2.Type.Slice()) |
| 287 | } |
| 288 | result.Type = s1.Type |
| 289 | |
| 290 | if s1.Format != s2.Format { |
| 291 | return openapi3.Schema{}, errors.New("can not merge incompatible formats") |
| 292 | } |
| 293 | result.Format = s1.Format |
| 294 | |
| 295 | // For Enums, do we union, or intersect? This is a bit vague. I choose |
| 296 | // to be more permissive and union. |
| 297 | result.Enum = append(s1.Enum, s2.Enum...) |
| 298 | |
| 299 | // I don't know how to handle two different defaults. |
| 300 | if s1.Default != nil || s2.Default != nil { |
| 301 | return openapi3.Schema{}, errors.New("merging two sets of defaults is undefined") |
| 302 | } |
| 303 | if s1.Default != nil { |
| 304 | result.Default = s1.Default |
| 305 | } |
| 306 | if s2.Default != nil { |
| 307 | result.Default = s2.Default |
| 308 | } |
| 309 | |
| 310 | // We skip Example |