github.com/snyk/vervet/v3@v3.7.0/merge.go (about) 1 package vervet 2 3 import ( 4 "sort" 5 6 "github.com/getkin/kin-openapi/openapi3" 7 ) 8 9 // Merge adds the paths and components from a source OpenAPI document root, 10 // to a destination document root. 11 // 12 // TODO: This is a naive implementation that should be improved to detect and 13 // resolve conflicts better. For example, distinct resources might have 14 // localized references with the same URIs but different content. 15 // Content-addressible resource versions may further facilitate governance; 16 // this also would facilitate detecting and relocating such conflicts. 17 func Merge(dst, src *openapi3.T, replace bool) { 18 mergeComponents(dst, src, replace) 19 mergeInfo(dst, src, replace) 20 mergePaths(dst, src, replace) 21 mergeSecurityRequirements(dst, src, replace) 22 mergeServers(dst, src, replace) 23 mergeTags(dst, src, replace) 24 } 25 26 func mergeTags(dst, src *openapi3.T, replace bool) { 27 m := map[string]*openapi3.Tag{} 28 for _, t := range dst.Tags { 29 m[t.Name] = t 30 } 31 for _, t := range src.Tags { 32 if _, ok := m[t.Name]; !ok || replace { 33 m[t.Name] = t 34 } 35 } 36 dst.Tags = openapi3.Tags{} 37 var tagNames []string 38 for tagName := range m { 39 tagNames = append(tagNames, tagName) 40 } 41 sort.Strings(tagNames) 42 for _, tagName := range tagNames { 43 dst.Tags = append(dst.Tags, m[tagName]) 44 } 45 } 46 47 func initDestinationComponents(dst, src *openapi3.T) { 48 if src.Components.Schemas != nil && dst.Components.Schemas == nil { 49 dst.Components.Schemas = make(map[string]*openapi3.SchemaRef) 50 } 51 if src.Components.Parameters != nil && dst.Components.Parameters == nil { 52 dst.Components.Parameters = make(map[string]*openapi3.ParameterRef) 53 } 54 if src.Components.Headers != nil && dst.Components.Headers == nil { 55 dst.Components.Headers = make(map[string]*openapi3.HeaderRef) 56 } 57 if src.Components.RequestBodies != nil && dst.Components.RequestBodies == nil { 58 dst.Components.RequestBodies = make(map[string]*openapi3.RequestBodyRef) 59 } 60 if src.Components.Responses != nil && dst.Components.Responses == nil { 61 dst.Components.Responses = make(map[string]*openapi3.ResponseRef) 62 } 63 if src.Components.SecuritySchemes != nil && dst.Components.SecuritySchemes == nil { 64 dst.Components.SecuritySchemes = make(map[string]*openapi3.SecuritySchemeRef) 65 } 66 if src.Components.Examples != nil && dst.Components.Examples == nil { 67 dst.Components.Examples = make(map[string]*openapi3.ExampleRef) 68 } 69 if src.Components.Links != nil && dst.Components.Links == nil { 70 dst.Components.Links = make(map[string]*openapi3.LinkRef) 71 } 72 if src.Components.Callbacks != nil && dst.Components.Callbacks == nil { 73 dst.Components.Callbacks = make(map[string]*openapi3.CallbackRef) 74 } 75 } 76 77 func mergeComponents(dst, src *openapi3.T, replace bool) { 78 initDestinationComponents(dst, src) 79 for k, v := range src.Components.Schemas { 80 if _, ok := dst.Components.Schemas[k]; !ok || replace { 81 dst.Components.Schemas[k] = v 82 } 83 } 84 for k, v := range src.Components.Parameters { 85 if _, ok := dst.Components.Parameters[k]; !ok || replace { 86 dst.Components.Parameters[k] = v 87 } 88 } 89 for k, v := range src.Components.Headers { 90 if _, ok := dst.Components.Headers[k]; !ok || replace { 91 dst.Components.Headers[k] = v 92 } 93 } 94 for k, v := range src.Components.RequestBodies { 95 if _, ok := dst.Components.RequestBodies[k]; !ok || replace { 96 dst.Components.RequestBodies[k] = v 97 } 98 } 99 for k, v := range src.Components.Responses { 100 if _, ok := dst.Components.Responses[k]; !ok || replace { 101 dst.Components.Responses[k] = v 102 } 103 } 104 for k, v := range src.Components.SecuritySchemes { 105 if _, ok := dst.Components.SecuritySchemes[k]; !ok || replace { 106 dst.Components.SecuritySchemes[k] = v 107 } 108 } 109 for k, v := range src.Components.Examples { 110 if _, ok := dst.Components.Examples[k]; !ok || replace { 111 dst.Components.Examples[k] = v 112 } 113 } 114 for k, v := range src.Components.Links { 115 if _, ok := dst.Components.Links[k]; !ok || replace { 116 dst.Components.Links[k] = v 117 } 118 } 119 for k, v := range src.Components.Callbacks { 120 if _, ok := dst.Components.Callbacks[k]; !ok || replace { 121 dst.Components.Callbacks[k] = v 122 } 123 } 124 } 125 126 func mergeInfo(dst, src *openapi3.T, replace bool) { 127 if src.Info != nil && (dst.Info == nil || replace) { 128 dst.Info = src.Info 129 } 130 } 131 132 func mergePaths(dst, src *openapi3.T, replace bool) { 133 if src.Paths != nil && dst.Paths == nil { 134 dst.Paths = make(openapi3.Paths) 135 } 136 for k, v := range src.Paths { 137 if _, ok := dst.Paths[k]; !ok || replace { 138 dst.Paths[k] = v 139 } 140 } 141 } 142 143 func mergeSecurityRequirements(dst, src *openapi3.T, replace bool) { 144 if len(src.Security) > 0 && (len(dst.Security) == 0 || replace) { 145 dst.Security = src.Security 146 } 147 } 148 149 func mergeServers(dst, src *openapi3.T, replace bool) { 150 if len(src.Servers) > 0 && (len(dst.Security) == 0 || replace) { 151 dst.Servers = src.Servers 152 } 153 }