github.com/snyk/vervet/v3@v3.7.0/ref_alias_resolver.go (about)

     1  package vervet
     2  
     3  import (
     4  	"encoding/json"
     5  	"reflect"
     6  	"strings"
     7  
     8  	"github.com/getkin/kin-openapi/jsoninfo"
     9  	"github.com/getkin/kin-openapi/openapi3"
    10  	"github.com/mitchellh/reflectwalk"
    11  )
    12  
    13  // refAliasResolver rewrites references in an OpenAPI document object to local
    14  // references, so that the spec is self-contained.
    15  type refAliasResolver struct {
    16  	doc         *openapi3.T
    17  	refAliases  map[string]string
    18  	curRefType  reflect.Value
    19  	curRefField reflect.Value
    20  }
    21  
    22  // newRefAliasResolver returns a new refAliasResolver.
    23  func newRefAliasResolver(doc *openapi3.T) (*refAliasResolver, error) {
    24  	refAliases := map[string]string{}
    25  	for refAlias, extValue := range doc.Components.ExtensionProps.Extensions {
    26  		contents, ok := extValue.(json.RawMessage)
    27  		if !ok {
    28  			continue
    29  		}
    30  		dec, err := jsoninfo.NewObjectDecoder(contents)
    31  		if err != nil {
    32  			return nil, err
    33  		}
    34  		var ref openapi3.Ref
    35  		if err := doc.Components.ExtensionProps.DecodeWith(dec, &ref); err == nil && ref.Ref != "" {
    36  			refAliases["#/components/"+refAlias] = ref.Ref
    37  		}
    38  	}
    39  
    40  	return &refAliasResolver{doc: doc, refAliases: refAliases}, nil
    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  }