github.com/snyk/vervet/v6@v6.2.4/ref_alias_resolver.go (about)

     1  package vervet
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  
     7  	"github.com/getkin/kin-openapi/openapi3"
     8  	"github.com/mitchellh/reflectwalk"
     9  )
    10  
    11  // refAliasResolver rewrites references in an OpenAPI document object to local
    12  // references, so that the spec is self-contained.
    13  type refAliasResolver struct {
    14  	doc         *openapi3.T
    15  	refAliases  map[string]string
    16  	curRefType  reflect.Value
    17  	curRefField reflect.Value
    18  }
    19  
    20  // newRefAliasResolver returns a new refAliasResolver.
    21  func newRefAliasResolver(doc *openapi3.T) *refAliasResolver {
    22  	res := &refAliasResolver{doc: doc}
    23  	if doc.Components == nil {
    24  		return res
    25  	}
    26  
    27  	res.refAliases = make(map[string]string, len(doc.Components.Extensions))
    28  
    29  	for refAlias, extValue := range doc.Components.Extensions {
    30  		contents, ok := extValue.(map[string]interface{})
    31  		if !ok {
    32  			continue
    33  		}
    34  		ref, ok := contents["$ref"].(string)
    35  		if ok && ref != "" {
    36  			res.refAliases["#/components/"+refAlias] = ref
    37  		}
    38  	}
    39  
    40  	return res
    41  }
    42  
    43  func (l *refAliasResolver) resolveRefAlias(ref string) string {
    44  	if ref != "" && ref[0] == '#' {
    45  		for refAlias, refTarget := range l.refAliases {
    46  			if strings.HasPrefix(ref, refAlias) {
    47  				return strings.Replace(ref, refAlias, refTarget+"#", 1)
    48  			}
    49  		}
    50  	}
    51  	return ref
    52  }
    53  
    54  // resolve rewrites all references in the OpenAPI document to local references.
    55  func (l *refAliasResolver) resolve() error {
    56  	return reflectwalk.Walk(l.doc, l)
    57  }
    58  
    59  // Struct implements reflectwalk.StructWalker.
    60  func (l *refAliasResolver) Struct(v reflect.Value) error {
    61  	l.curRefType, l.curRefField = v, v.FieldByName("Ref")
    62  	return nil
    63  }
    64  
    65  // StructField implements reflectwalk.StructWalker.
    66  func (l *refAliasResolver) StructField(sf reflect.StructField, v reflect.Value) error {
    67  	if !l.curRefField.IsValid() {
    68  		return nil
    69  	}
    70  	ref := l.curRefField.String()
    71  	if ref == "" {
    72  		return nil
    73  	}
    74  	ref = l.resolveRefAlias(ref)
    75  	l.curRefField.Set(reflect.ValueOf(ref))
    76  	return nil
    77  }