1
16
17 package schemamutation
18
19 import (
20 "k8s.io/kube-openapi/pkg/validation/spec"
21 )
22
23
24
25 type Walker struct {
26
27
28
29
30 SchemaCallback func(schema *spec.Schema) *spec.Schema
31
32
33
34
35 RefCallback func(ref *spec.Ref) *spec.Ref
36 }
37
38 type SchemaCallbackFunc func(schema *spec.Schema) *spec.Schema
39 type RefCallbackFunc func(ref *spec.Ref) *spec.Ref
40
41 var SchemaCallBackNoop SchemaCallbackFunc = func(schema *spec.Schema) *spec.Schema {
42 return schema
43 }
44 var RefCallbackNoop RefCallbackFunc = func(ref *spec.Ref) *spec.Ref {
45 return ref
46 }
47
48
49
50 func ReplaceReferences(walkRef func(ref *spec.Ref) *spec.Ref, sp *spec.Swagger) *spec.Swagger {
51 walker := &Walker{RefCallback: walkRef, SchemaCallback: SchemaCallBackNoop}
52 return walker.WalkRoot(sp)
53 }
54
55 func (w *Walker) WalkSchema(schema *spec.Schema) *spec.Schema {
56 if schema == nil {
57 return nil
58 }
59
60 orig := schema
61 clone := func() {
62 if orig == schema {
63 schema = &spec.Schema{}
64 *schema = *orig
65 }
66 }
67
68
69
70 schema = w.SchemaCallback(schema)
71
72 if r := w.RefCallback(&schema.Ref); r != &schema.Ref {
73 clone()
74 schema.Ref = *r
75 }
76
77 definitionsCloned := false
78 for k, v := range schema.Definitions {
79 if s := w.WalkSchema(&v); s != &v {
80 if !definitionsCloned {
81 definitionsCloned = true
82 clone()
83 schema.Definitions = make(spec.Definitions, len(orig.Definitions))
84 for k2, v2 := range orig.Definitions {
85 schema.Definitions[k2] = v2
86 }
87 }
88 schema.Definitions[k] = *s
89 }
90 }
91
92 propertiesCloned := false
93 for k, v := range schema.Properties {
94 if s := w.WalkSchema(&v); s != &v {
95 if !propertiesCloned {
96 propertiesCloned = true
97 clone()
98 schema.Properties = make(map[string]spec.Schema, len(orig.Properties))
99 for k2, v2 := range orig.Properties {
100 schema.Properties[k2] = v2
101 }
102 }
103 schema.Properties[k] = *s
104 }
105 }
106
107 patternPropertiesCloned := false
108 for k, v := range schema.PatternProperties {
109 if s := w.WalkSchema(&v); s != &v {
110 if !patternPropertiesCloned {
111 patternPropertiesCloned = true
112 clone()
113 schema.PatternProperties = make(map[string]spec.Schema, len(orig.PatternProperties))
114 for k2, v2 := range orig.PatternProperties {
115 schema.PatternProperties[k2] = v2
116 }
117 }
118 schema.PatternProperties[k] = *s
119 }
120 }
121
122 allOfCloned := false
123 for i := range schema.AllOf {
124 if s := w.WalkSchema(&schema.AllOf[i]); s != &schema.AllOf[i] {
125 if !allOfCloned {
126 allOfCloned = true
127 clone()
128 schema.AllOf = make([]spec.Schema, len(orig.AllOf))
129 copy(schema.AllOf, orig.AllOf)
130 }
131 schema.AllOf[i] = *s
132 }
133 }
134
135 anyOfCloned := false
136 for i := range schema.AnyOf {
137 if s := w.WalkSchema(&schema.AnyOf[i]); s != &schema.AnyOf[i] {
138 if !anyOfCloned {
139 anyOfCloned = true
140 clone()
141 schema.AnyOf = make([]spec.Schema, len(orig.AnyOf))
142 copy(schema.AnyOf, orig.AnyOf)
143 }
144 schema.AnyOf[i] = *s
145 }
146 }
147
148 oneOfCloned := false
149 for i := range schema.OneOf {
150 if s := w.WalkSchema(&schema.OneOf[i]); s != &schema.OneOf[i] {
151 if !oneOfCloned {
152 oneOfCloned = true
153 clone()
154 schema.OneOf = make([]spec.Schema, len(orig.OneOf))
155 copy(schema.OneOf, orig.OneOf)
156 }
157 schema.OneOf[i] = *s
158 }
159 }
160
161 if schema.Not != nil {
162 if s := w.WalkSchema(schema.Not); s != schema.Not {
163 clone()
164 schema.Not = s
165 }
166 }
167
168 if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil {
169 if s := w.WalkSchema(schema.AdditionalProperties.Schema); s != schema.AdditionalProperties.Schema {
170 clone()
171 schema.AdditionalProperties = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalProperties.Allows}
172 }
173 }
174
175 if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil {
176 if s := w.WalkSchema(schema.AdditionalItems.Schema); s != schema.AdditionalItems.Schema {
177 clone()
178 schema.AdditionalItems = &spec.SchemaOrBool{Schema: s, Allows: schema.AdditionalItems.Allows}
179 }
180 }
181
182 if schema.Items != nil {
183 if schema.Items.Schema != nil {
184 if s := w.WalkSchema(schema.Items.Schema); s != schema.Items.Schema {
185 clone()
186 schema.Items = &spec.SchemaOrArray{Schema: s}
187 }
188 } else {
189 itemsCloned := false
190 for i := range schema.Items.Schemas {
191 if s := w.WalkSchema(&schema.Items.Schemas[i]); s != &schema.Items.Schemas[i] {
192 if !itemsCloned {
193 clone()
194 schema.Items = &spec.SchemaOrArray{
195 Schemas: make([]spec.Schema, len(orig.Items.Schemas)),
196 }
197 itemsCloned = true
198 copy(schema.Items.Schemas, orig.Items.Schemas)
199 }
200 schema.Items.Schemas[i] = *s
201 }
202 }
203 }
204 }
205
206 return schema
207 }
208
209 func (w *Walker) walkParameter(param *spec.Parameter) *spec.Parameter {
210 if param == nil {
211 return nil
212 }
213
214 orig := param
215 cloned := false
216 clone := func() {
217 if !cloned {
218 cloned = true
219 param = &spec.Parameter{}
220 *param = *orig
221 }
222 }
223
224 if r := w.RefCallback(¶m.Ref); r != ¶m.Ref {
225 clone()
226 param.Ref = *r
227 }
228 if s := w.WalkSchema(param.Schema); s != param.Schema {
229 clone()
230 param.Schema = s
231 }
232 if param.Items != nil {
233 if r := w.RefCallback(¶m.Items.Ref); r != ¶m.Items.Ref {
234 param.Items.Ref = *r
235 }
236 }
237
238 return param
239 }
240
241 func (w *Walker) walkParameters(params []spec.Parameter) ([]spec.Parameter, bool) {
242 if params == nil {
243 return nil, false
244 }
245
246 orig := params
247 cloned := false
248 clone := func() {
249 if !cloned {
250 cloned = true
251 params = make([]spec.Parameter, len(params))
252 copy(params, orig)
253 }
254 }
255
256 for i := range params {
257 if s := w.walkParameter(¶ms[i]); s != ¶ms[i] {
258 clone()
259 params[i] = *s
260 }
261 }
262
263 return params, cloned
264 }
265
266 func (w *Walker) walkResponse(resp *spec.Response) *spec.Response {
267 if resp == nil {
268 return nil
269 }
270
271 orig := resp
272 cloned := false
273 clone := func() {
274 if !cloned {
275 cloned = true
276 resp = &spec.Response{}
277 *resp = *orig
278 }
279 }
280
281 if r := w.RefCallback(&resp.Ref); r != &resp.Ref {
282 clone()
283 resp.Ref = *r
284 }
285 if s := w.WalkSchema(resp.Schema); s != resp.Schema {
286 clone()
287 resp.Schema = s
288 }
289
290 return resp
291 }
292
293 func (w *Walker) walkResponses(resps *spec.Responses) *spec.Responses {
294 if resps == nil {
295 return nil
296 }
297
298 orig := resps
299 cloned := false
300 clone := func() {
301 if !cloned {
302 cloned = true
303 resps = &spec.Responses{}
304 *resps = *orig
305 }
306 }
307
308 if r := w.walkResponse(resps.ResponsesProps.Default); r != resps.ResponsesProps.Default {
309 clone()
310 resps.Default = r
311 }
312
313 responsesCloned := false
314 for k, v := range resps.ResponsesProps.StatusCodeResponses {
315 if r := w.walkResponse(&v); r != &v {
316 if !responsesCloned {
317 responsesCloned = true
318 clone()
319 resps.ResponsesProps.StatusCodeResponses = make(map[int]spec.Response, len(orig.StatusCodeResponses))
320 for k2, v2 := range orig.StatusCodeResponses {
321 resps.ResponsesProps.StatusCodeResponses[k2] = v2
322 }
323 }
324 resps.ResponsesProps.StatusCodeResponses[k] = *r
325 }
326 }
327
328 return resps
329 }
330
331 func (w *Walker) walkOperation(op *spec.Operation) *spec.Operation {
332 if op == nil {
333 return nil
334 }
335
336 orig := op
337 cloned := false
338 clone := func() {
339 if !cloned {
340 cloned = true
341 op = &spec.Operation{}
342 *op = *orig
343 }
344 }
345
346 parametersCloned := false
347 for i := range op.Parameters {
348 if s := w.walkParameter(&op.Parameters[i]); s != &op.Parameters[i] {
349 if !parametersCloned {
350 parametersCloned = true
351 clone()
352 op.Parameters = make([]spec.Parameter, len(orig.Parameters))
353 copy(op.Parameters, orig.Parameters)
354 }
355 op.Parameters[i] = *s
356 }
357 }
358
359 if r := w.walkResponses(op.Responses); r != op.Responses {
360 clone()
361 op.Responses = r
362 }
363
364 return op
365 }
366
367 func (w *Walker) walkPathItem(pathItem *spec.PathItem) *spec.PathItem {
368 if pathItem == nil {
369 return nil
370 }
371
372 orig := pathItem
373 cloned := false
374 clone := func() {
375 if !cloned {
376 cloned = true
377 pathItem = &spec.PathItem{}
378 *pathItem = *orig
379 }
380 }
381
382 if p, changed := w.walkParameters(pathItem.Parameters); changed {
383 clone()
384 pathItem.Parameters = p
385 }
386 if op := w.walkOperation(pathItem.Get); op != pathItem.Get {
387 clone()
388 pathItem.Get = op
389 }
390 if op := w.walkOperation(pathItem.Head); op != pathItem.Head {
391 clone()
392 pathItem.Head = op
393 }
394 if op := w.walkOperation(pathItem.Delete); op != pathItem.Delete {
395 clone()
396 pathItem.Delete = op
397 }
398 if op := w.walkOperation(pathItem.Options); op != pathItem.Options {
399 clone()
400 pathItem.Options = op
401 }
402 if op := w.walkOperation(pathItem.Patch); op != pathItem.Patch {
403 clone()
404 pathItem.Patch = op
405 }
406 if op := w.walkOperation(pathItem.Post); op != pathItem.Post {
407 clone()
408 pathItem.Post = op
409 }
410 if op := w.walkOperation(pathItem.Put); op != pathItem.Put {
411 clone()
412 pathItem.Put = op
413 }
414
415 return pathItem
416 }
417
418 func (w *Walker) walkPaths(paths *spec.Paths) *spec.Paths {
419 if paths == nil {
420 return nil
421 }
422
423 orig := paths
424 cloned := false
425 clone := func() {
426 if !cloned {
427 cloned = true
428 paths = &spec.Paths{}
429 *paths = *orig
430 }
431 }
432
433 pathsCloned := false
434 for k, v := range paths.Paths {
435 if p := w.walkPathItem(&v); p != &v {
436 if !pathsCloned {
437 pathsCloned = true
438 clone()
439 paths.Paths = make(map[string]spec.PathItem, len(orig.Paths))
440 for k2, v2 := range orig.Paths {
441 paths.Paths[k2] = v2
442 }
443 }
444 paths.Paths[k] = *p
445 }
446 }
447
448 return paths
449 }
450
451 func (w *Walker) WalkRoot(swagger *spec.Swagger) *spec.Swagger {
452 if swagger == nil {
453 return nil
454 }
455
456 orig := swagger
457 cloned := false
458 clone := func() {
459 if !cloned {
460 cloned = true
461 swagger = &spec.Swagger{}
462 *swagger = *orig
463 }
464 }
465
466 parametersCloned := false
467 for k, v := range swagger.Parameters {
468 if p := w.walkParameter(&v); p != &v {
469 if !parametersCloned {
470 parametersCloned = true
471 clone()
472 swagger.Parameters = make(map[string]spec.Parameter, len(orig.Parameters))
473 for k2, v2 := range orig.Parameters {
474 swagger.Parameters[k2] = v2
475 }
476 }
477 swagger.Parameters[k] = *p
478 }
479 }
480
481 responsesCloned := false
482 for k, v := range swagger.Responses {
483 if r := w.walkResponse(&v); r != &v {
484 if !responsesCloned {
485 responsesCloned = true
486 clone()
487 swagger.Responses = make(map[string]spec.Response, len(orig.Responses))
488 for k2, v2 := range orig.Responses {
489 swagger.Responses[k2] = v2
490 }
491 }
492 swagger.Responses[k] = *r
493 }
494 }
495
496 definitionsCloned := false
497 for k, v := range swagger.Definitions {
498 if s := w.WalkSchema(&v); s != &v {
499 if !definitionsCloned {
500 definitionsCloned = true
501 clone()
502 swagger.Definitions = make(spec.Definitions, len(orig.Definitions))
503 for k2, v2 := range orig.Definitions {
504 swagger.Definitions[k2] = v2
505 }
506 }
507 swagger.Definitions[k] = *s
508 }
509 }
510
511 if swagger.Paths != nil {
512 if p := w.walkPaths(swagger.Paths); p != swagger.Paths {
513 clone()
514 swagger.Paths = p
515 }
516 }
517
518 return swagger
519 }
520
View as plain text