1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package analysis
16
17 import (
18 "fmt"
19 "reflect"
20
21 "github.com/go-openapi/spec"
22 )
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 func Mixin(primary *spec.Swagger, mixins ...*spec.Swagger) []string {
55 skipped := make([]string, 0, len(mixins))
56 opIDs := getOpIDs(primary)
57 initPrimary(primary)
58
59 for i, m := range mixins {
60 skipped = append(skipped, mergeSwaggerProps(primary, m)...)
61
62 skipped = append(skipped, mergeConsumes(primary, m)...)
63
64 skipped = append(skipped, mergeProduces(primary, m)...)
65
66 skipped = append(skipped, mergeTags(primary, m)...)
67
68 skipped = append(skipped, mergeSchemes(primary, m)...)
69
70 skipped = append(skipped, mergeSecurityDefinitions(primary, m)...)
71
72 skipped = append(skipped, mergeSecurityRequirements(primary, m)...)
73
74 skipped = append(skipped, mergeDefinitions(primary, m)...)
75
76
77 skipped = append(skipped, mergePaths(primary, m, opIDs, i)...)
78
79 skipped = append(skipped, mergeParameters(primary, m)...)
80
81 skipped = append(skipped, mergeResponses(primary, m)...)
82 }
83
84 return skipped
85 }
86
87
88
89 func getOpIDs(s *spec.Swagger) map[string]bool {
90 rv := make(map[string]bool)
91 if s.Paths == nil {
92 return rv
93 }
94
95 for _, v := range s.Paths.Paths {
96 piops := pathItemOps(v)
97
98 for _, op := range piops {
99 rv[op.ID] = true
100 }
101 }
102
103 return rv
104 }
105
106 func pathItemOps(p spec.PathItem) []*spec.Operation {
107 var rv []*spec.Operation
108 rv = appendOp(rv, p.Get)
109 rv = appendOp(rv, p.Put)
110 rv = appendOp(rv, p.Post)
111 rv = appendOp(rv, p.Delete)
112 rv = appendOp(rv, p.Head)
113 rv = appendOp(rv, p.Patch)
114
115 return rv
116 }
117
118 func appendOp(ops []*spec.Operation, op *spec.Operation) []*spec.Operation {
119 if op == nil {
120 return ops
121 }
122
123 return append(ops, op)
124 }
125
126 func mergeSecurityDefinitions(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
127 for k, v := range m.SecurityDefinitions {
128 if _, exists := primary.SecurityDefinitions[k]; exists {
129 warn := fmt.Sprintf(
130 "SecurityDefinitions entry '%v' already exists in primary or higher priority mixin, skipping\n", k)
131 skipped = append(skipped, warn)
132
133 continue
134 }
135
136 primary.SecurityDefinitions[k] = v
137 }
138
139 return
140 }
141
142 func mergeSecurityRequirements(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
143 for _, v := range m.Security {
144 found := false
145 for _, vv := range primary.Security {
146 if reflect.DeepEqual(v, vv) {
147 found = true
148
149 break
150 }
151 }
152
153 if found {
154 warn := fmt.Sprintf(
155 "Security requirement: '%v' already exists in primary or higher priority mixin, skipping\n", v)
156 skipped = append(skipped, warn)
157
158 continue
159 }
160 primary.Security = append(primary.Security, v)
161 }
162
163 return
164 }
165
166 func mergeDefinitions(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
167 for k, v := range m.Definitions {
168
169 if _, exists := primary.Definitions[k]; exists {
170 warn := fmt.Sprintf(
171 "definitions entry '%v' already exists in primary or higher priority mixin, skipping\n", k)
172 skipped = append(skipped, warn)
173
174 continue
175 }
176 primary.Definitions[k] = v
177 }
178
179 return
180 }
181
182 func mergePaths(primary *spec.Swagger, m *spec.Swagger, opIDs map[string]bool, mixIndex int) (skipped []string) {
183 if m.Paths != nil {
184 for k, v := range m.Paths.Paths {
185 if _, exists := primary.Paths.Paths[k]; exists {
186 warn := fmt.Sprintf(
187 "paths entry '%v' already exists in primary or higher priority mixin, skipping\n", k)
188 skipped = append(skipped, warn)
189
190 continue
191 }
192
193
194
195
196
197
198
199 piops := pathItemOps(v)
200 for _, piop := range piops {
201 if opIDs[piop.ID] {
202 piop.ID = fmt.Sprintf("%v%v%v", piop.ID, "Mixin", mixIndex)
203 }
204 opIDs[piop.ID] = true
205 }
206 primary.Paths.Paths[k] = v
207 }
208 }
209
210 return
211 }
212
213 func mergeParameters(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
214 for k, v := range m.Parameters {
215
216
217
218 if _, exists := primary.Parameters[k]; exists {
219 warn := fmt.Sprintf(
220 "top level parameters entry '%v' already exists in primary or higher priority mixin, skipping\n", k)
221 skipped = append(skipped, warn)
222
223 continue
224 }
225 primary.Parameters[k] = v
226 }
227
228 return
229 }
230
231 func mergeResponses(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
232 for k, v := range m.Responses {
233
234
235
236 if _, exists := primary.Responses[k]; exists {
237 warn := fmt.Sprintf(
238 "top level responses entry '%v' already exists in primary or higher priority mixin, skipping\n", k)
239 skipped = append(skipped, warn)
240
241 continue
242 }
243 primary.Responses[k] = v
244 }
245
246 return skipped
247 }
248
249 func mergeConsumes(primary *spec.Swagger, m *spec.Swagger) []string {
250 for _, v := range m.Consumes {
251 found := false
252 for _, vv := range primary.Consumes {
253 if v == vv {
254 found = true
255
256 break
257 }
258 }
259
260 if found {
261
262 continue
263 }
264 primary.Consumes = append(primary.Consumes, v)
265 }
266
267 return []string{}
268 }
269
270 func mergeProduces(primary *spec.Swagger, m *spec.Swagger) []string {
271 for _, v := range m.Produces {
272 found := false
273 for _, vv := range primary.Produces {
274 if v == vv {
275 found = true
276
277 break
278 }
279 }
280
281 if found {
282
283 continue
284 }
285 primary.Produces = append(primary.Produces, v)
286 }
287
288 return []string{}
289 }
290
291 func mergeTags(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
292 for _, v := range m.Tags {
293 found := false
294 for _, vv := range primary.Tags {
295 if v.Name == vv.Name {
296 found = true
297
298 break
299 }
300 }
301
302 if found {
303 warn := fmt.Sprintf(
304 "top level tags entry with name '%v' already exists in primary or higher priority mixin, skipping\n",
305 v.Name,
306 )
307 skipped = append(skipped, warn)
308
309 continue
310 }
311
312 primary.Tags = append(primary.Tags, v)
313 }
314
315 return
316 }
317
318 func mergeSchemes(primary *spec.Swagger, m *spec.Swagger) []string {
319 for _, v := range m.Schemes {
320 found := false
321 for _, vv := range primary.Schemes {
322 if v == vv {
323 found = true
324
325 break
326 }
327 }
328
329 if found {
330
331 continue
332 }
333 primary.Schemes = append(primary.Schemes, v)
334 }
335
336 return []string{}
337 }
338
339 func mergeSwaggerProps(primary *spec.Swagger, m *spec.Swagger) []string {
340 var skipped, skippedInfo, skippedDocs []string
341
342 primary.Extensions, skipped = mergeExtensions(primary.Extensions, m.Extensions)
343
344
345 if primary.Host == "" {
346 primary.Host = m.Host
347 }
348
349 if primary.BasePath == "" {
350 primary.BasePath = m.BasePath
351 }
352
353 if primary.Info == nil {
354 primary.Info = m.Info
355 } else if m.Info != nil {
356 skippedInfo = mergeInfo(primary.Info, m.Info)
357 skipped = append(skipped, skippedInfo...)
358 }
359
360 if primary.ExternalDocs == nil {
361 primary.ExternalDocs = m.ExternalDocs
362 } else if m != nil {
363 skippedDocs = mergeExternalDocs(primary.ExternalDocs, m.ExternalDocs)
364 skipped = append(skipped, skippedDocs...)
365 }
366
367 return skipped
368 }
369
370
371 func mergeExternalDocs(primary *spec.ExternalDocumentation, m *spec.ExternalDocumentation) []string {
372 if primary.Description == "" {
373 primary.Description = m.Description
374 }
375
376 if primary.URL == "" {
377 primary.URL = m.URL
378 }
379
380 return nil
381 }
382
383 func mergeInfo(primary *spec.Info, m *spec.Info) []string {
384 var sk, skipped []string
385
386 primary.Extensions, sk = mergeExtensions(primary.Extensions, m.Extensions)
387 skipped = append(skipped, sk...)
388
389 if primary.Description == "" {
390 primary.Description = m.Description
391 }
392
393 if primary.Title == "" {
394 primary.Description = m.Description
395 }
396
397 if primary.TermsOfService == "" {
398 primary.TermsOfService = m.TermsOfService
399 }
400
401 if primary.Version == "" {
402 primary.Version = m.Version
403 }
404
405 if primary.Contact == nil {
406 primary.Contact = m.Contact
407 } else if m.Contact != nil {
408 var csk []string
409 primary.Contact.Extensions, csk = mergeExtensions(primary.Contact.Extensions, m.Contact.Extensions)
410 skipped = append(skipped, csk...)
411
412 if primary.Contact.Name == "" {
413 primary.Contact.Name = m.Contact.Name
414 }
415
416 if primary.Contact.URL == "" {
417 primary.Contact.URL = m.Contact.URL
418 }
419
420 if primary.Contact.Email == "" {
421 primary.Contact.Email = m.Contact.Email
422 }
423 }
424
425 if primary.License == nil {
426 primary.License = m.License
427 } else if m.License != nil {
428 var lsk []string
429 primary.License.Extensions, lsk = mergeExtensions(primary.License.Extensions, m.License.Extensions)
430 skipped = append(skipped, lsk...)
431
432 if primary.License.Name == "" {
433 primary.License.Name = m.License.Name
434 }
435
436 if primary.License.URL == "" {
437 primary.License.URL = m.License.URL
438 }
439 }
440
441 return skipped
442 }
443
444 func mergeExtensions(primary spec.Extensions, m spec.Extensions) (result spec.Extensions, skipped []string) {
445 if primary == nil {
446 result = m
447
448 return
449 }
450
451 if m == nil {
452 result = primary
453
454 return
455 }
456
457 result = primary
458 for k, v := range m {
459 if _, found := primary[k]; found {
460 skipped = append(skipped, k)
461
462 continue
463 }
464
465 primary[k] = v
466 }
467
468 return
469 }
470
471 func initPrimary(primary *spec.Swagger) {
472 if primary.SecurityDefinitions == nil {
473 primary.SecurityDefinitions = make(map[string]*spec.SecurityScheme)
474 }
475
476 if primary.Security == nil {
477 primary.Security = make([]map[string][]string, 0, 10)
478 }
479
480 if primary.Produces == nil {
481 primary.Produces = make([]string, 0, 10)
482 }
483
484 if primary.Consumes == nil {
485 primary.Consumes = make([]string, 0, 10)
486 }
487
488 if primary.Tags == nil {
489 primary.Tags = make([]spec.Tag, 0, 10)
490 }
491
492 if primary.Schemes == nil {
493 primary.Schemes = make([]string, 0, 10)
494 }
495
496 if primary.Paths == nil {
497 primary.Paths = &spec.Paths{Paths: make(map[string]spec.PathItem)}
498 }
499
500 if primary.Paths.Paths == nil {
501 primary.Paths.Paths = make(map[string]spec.PathItem)
502 }
503
504 if primary.Definitions == nil {
505 primary.Definitions = make(spec.Definitions)
506 }
507
508 if primary.Parameters == nil {
509 primary.Parameters = make(map[string]spec.Parameter)
510 }
511
512 if primary.Responses == nil {
513 primary.Responses = make(map[string]spec.Response)
514 }
515 }
516
View as plain text