...

Source file src/github.com/go-openapi/analysis/internal/flatten/sortref/sort_ref.go

Documentation: github.com/go-openapi/analysis/internal/flatten/sortref

     1  package sortref
     2  
     3  import (
     4  	"reflect"
     5  	"sort"
     6  	"strings"
     7  
     8  	"github.com/go-openapi/analysis/internal/flatten/normalize"
     9  	"github.com/go-openapi/spec"
    10  )
    11  
    12  var depthGroupOrder = []string{
    13  	"sharedParam", "sharedResponse", "sharedOpParam", "opParam", "codeResponse", "defaultResponse", "definition",
    14  }
    15  
    16  type mapIterator struct {
    17  	len     int
    18  	mapIter *reflect.MapIter
    19  }
    20  
    21  func (i *mapIterator) Next() bool {
    22  	return i.mapIter.Next()
    23  }
    24  
    25  func (i *mapIterator) Len() int {
    26  	return i.len
    27  }
    28  
    29  func (i *mapIterator) Key() string {
    30  	return i.mapIter.Key().String()
    31  }
    32  
    33  func mustMapIterator(anyMap interface{}) *mapIterator {
    34  	val := reflect.ValueOf(anyMap)
    35  
    36  	return &mapIterator{mapIter: val.MapRange(), len: val.Len()}
    37  }
    38  
    39  // DepthFirst sorts a map of anything. It groups keys by category
    40  // (shared params, op param, statuscode response, default response, definitions)
    41  // sort groups internally by number of parts in the key and lexical names
    42  // flatten groups into a single list of keys
    43  func DepthFirst(in interface{}) []string {
    44  	iterator := mustMapIterator(in)
    45  	sorted := make([]string, 0, iterator.Len())
    46  	grouped := make(map[string]Keys, iterator.Len())
    47  
    48  	for iterator.Next() {
    49  		k := iterator.Key()
    50  		split := KeyParts(k)
    51  		var pk string
    52  
    53  		if split.IsSharedOperationParam() {
    54  			pk = "sharedOpParam"
    55  		}
    56  		if split.IsOperationParam() {
    57  			pk = "opParam"
    58  		}
    59  		if split.IsStatusCodeResponse() {
    60  			pk = "codeResponse"
    61  		}
    62  		if split.IsDefaultResponse() {
    63  			pk = "defaultResponse"
    64  		}
    65  		if split.IsDefinition() {
    66  			pk = "definition"
    67  		}
    68  		if split.IsSharedParam() {
    69  			pk = "sharedParam"
    70  		}
    71  		if split.IsSharedResponse() {
    72  			pk = "sharedResponse"
    73  		}
    74  		grouped[pk] = append(grouped[pk], Key{Segments: len(split), Key: k})
    75  	}
    76  
    77  	for _, pk := range depthGroupOrder {
    78  		res := grouped[pk]
    79  		sort.Sort(res)
    80  
    81  		for _, v := range res {
    82  			sorted = append(sorted, v.Key)
    83  		}
    84  	}
    85  
    86  	return sorted
    87  }
    88  
    89  // topMostRefs is able to sort refs by hierarchical then lexicographic order,
    90  // yielding refs ordered breadth-first.
    91  type topmostRefs []string
    92  
    93  func (k topmostRefs) Len() int      { return len(k) }
    94  func (k topmostRefs) Swap(i, j int) { k[i], k[j] = k[j], k[i] }
    95  func (k topmostRefs) Less(i, j int) bool {
    96  	li, lj := len(strings.Split(k[i], "/")), len(strings.Split(k[j], "/"))
    97  	if li == lj {
    98  		return k[i] < k[j]
    99  	}
   100  
   101  	return li < lj
   102  }
   103  
   104  // TopmostFirst sorts references by depth
   105  func TopmostFirst(refs []string) []string {
   106  	res := topmostRefs(refs)
   107  	sort.Sort(res)
   108  
   109  	return res
   110  }
   111  
   112  // RefRevIdx is a reverse index for references
   113  type RefRevIdx struct {
   114  	Ref  spec.Ref
   115  	Keys []string
   116  }
   117  
   118  // ReverseIndex builds a reverse index for references in schemas
   119  func ReverseIndex(schemas map[string]spec.Ref, basePath string) map[string]RefRevIdx {
   120  	collected := make(map[string]RefRevIdx)
   121  	for key, schRef := range schemas {
   122  		// normalize paths before sorting,
   123  		// so we get together keys that are from the same external file
   124  		normalizedPath := normalize.Path(schRef, basePath)
   125  
   126  		entry, ok := collected[normalizedPath]
   127  		if ok {
   128  			entry.Keys = append(entry.Keys, key)
   129  			collected[normalizedPath] = entry
   130  
   131  			continue
   132  		}
   133  
   134  		collected[normalizedPath] = RefRevIdx{
   135  			Ref:  schRef,
   136  			Keys: []string{key},
   137  		}
   138  	}
   139  
   140  	return collected
   141  }
   142  

View as plain text