aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/go-openapi/analysis/flatten.go
diff options
context:
space:
mode:
authorGravatar Chris O'Haver <cohaver@infoblox.com> 2017-09-29 15:58:50 -0400
committerGravatar John Belamaric <jbelamaric@infoblox.com> 2017-09-29 15:58:50 -0400
commit4b3a430ff2e6a39278eebd1493936c3a8a161fa0 (patch)
treea48c18346039c9b7808ec2395eeda49f8a0e1f0c /vendor/github.com/go-openapi/analysis/flatten.go
parent45b0252c1aa3c9afb1951d4185644e23805167e5 (diff)
downloadcoredns-4b3a430ff2e6a39278eebd1493936c3a8a161fa0.tar.gz
coredns-4b3a430ff2e6a39278eebd1493936c3a8a161fa0.tar.zst
coredns-4b3a430ff2e6a39278eebd1493936c3a8a161fa0.zip
plugin/kubernetes: Enable protobuf, Update client api package (#1114)
* vendor * code
Diffstat (limited to 'vendor/github.com/go-openapi/analysis/flatten.go')
-rw-r--r--vendor/github.com/go-openapi/analysis/flatten.go756
1 files changed, 756 insertions, 0 deletions
diff --git a/vendor/github.com/go-openapi/analysis/flatten.go b/vendor/github.com/go-openapi/analysis/flatten.go
new file mode 100644
index 000000000..23d7242f4
--- /dev/null
+++ b/vendor/github.com/go-openapi/analysis/flatten.go
@@ -0,0 +1,756 @@
+package analysis
+
+import (
+ "fmt"
+ "log"
+ "net/http"
+ "path"
+ "sort"
+ "strings"
+
+ "strconv"
+
+ "github.com/go-openapi/jsonpointer"
+ swspec "github.com/go-openapi/spec"
+ "github.com/go-openapi/swag"
+)
+
+// FlattenOpts configuration for flattening a swagger specification.
+type FlattenOpts struct {
+ Spec *Spec
+ BasePath string
+
+ _ struct{} // require keys
+}
+
+// ExpandOpts creates a spec.ExpandOptions to configure expanding a specification document.
+func (f *FlattenOpts) ExpandOpts(skipSchemas bool) *swspec.ExpandOptions {
+ return &swspec.ExpandOptions{RelativeBase: f.BasePath, SkipSchemas: skipSchemas}
+}
+
+// Swagger gets the swagger specification for this flatten operation
+func (f *FlattenOpts) Swagger() *swspec.Swagger {
+ return f.Spec.spec
+}
+
+// Flatten an analyzed spec.
+//
+// To flatten a spec means:
+//
+// Expand the parameters, responses, path items, parameter items and header items.
+// Import external (http, file) references so they become internal to the document.
+// Move every inline schema to be a definition with an auto-generated name in a depth-first fashion.
+// Rewritten schemas get a vendor extension x-go-gen-location so we know in which package they need to be rendered.
+func Flatten(opts FlattenOpts) error {
+ // recursively expand responses, parameters, path items and items
+ err := swspec.ExpandSpec(opts.Swagger(), opts.ExpandOpts(true))
+ if err != nil {
+ return err
+ }
+ opts.Spec.reload() // re-analyze
+
+ // at this point there are no other references left but schemas
+ if err := importExternalReferences(&opts); err != nil {
+ return err
+ }
+ opts.Spec.reload() // re-analyze
+
+ // rewrite the inline schemas (schemas that aren't simple types or arrays of simple types)
+ if err := nameInlinedSchemas(&opts); err != nil {
+ return err
+ }
+ opts.Spec.reload() // re-analyze
+
+ // TODO: simplifiy known schema patterns to flat objects with properties?
+ return nil
+}
+
+func nameInlinedSchemas(opts *FlattenOpts) error {
+ namer := &inlineSchemaNamer{Spec: opts.Swagger(), Operations: opRefsByRef(gatherOperations(opts.Spec, nil))}
+ depthFirst := sortDepthFirst(opts.Spec.allSchemas)
+
+ for _, key := range depthFirst {
+ sch := opts.Spec.allSchemas[key]
+ if sch.Schema != nil && sch.Schema.Ref.String() == "" && !sch.TopLevel { // inline schema
+ asch, err := Schema(SchemaOpts{Schema: sch.Schema, Root: opts.Swagger(), BasePath: opts.BasePath})
+ if err != nil {
+ return fmt.Errorf("schema analysis [%s]: %v", sch.Ref.String(), err)
+ }
+
+ if !asch.IsSimpleSchema { // complex schemas get moved
+ if err := namer.Name(key, sch.Schema, asch); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ return nil
+}
+
+var depthGroupOrder = []string{"sharedOpParam", "opParam", "codeResponse", "defaultResponse", "definition"}
+
+func sortDepthFirst(data map[string]SchemaRef) (sorted []string) {
+ // group by category (shared params, op param, statuscode response, default response, definitions)
+ // sort groups internally by number of parts in the key and lexical names
+ // flatten groups into a single list of keys
+ grouped := make(map[string]keys, len(data))
+ for k := range data {
+ split := keyParts(k)
+ var pk string
+ if split.IsSharedOperationParam() {
+ pk = "sharedOpParam"
+ }
+ if split.IsOperationParam() {
+ pk = "opParam"
+ }
+ if split.IsStatusCodeResponse() {
+ pk = "codeResponse"
+ }
+ if split.IsDefaultResponse() {
+ pk = "defaultResponse"
+ }
+ if split.IsDefinition() {
+ pk = "definition"
+ }
+ grouped[pk] = append(grouped[pk], key{len(split), k})
+ }
+
+ for _, pk := range depthGroupOrder {
+ res := grouped[pk]
+ sort.Sort(res)
+ for _, v := range res {
+ sorted = append(sorted, v.Key)
+ }
+ }
+
+ return
+}
+
+type key struct {
+ Segments int
+ Key string
+}
+type keys []key
+
+func (k keys) Len() int { return len(k) }
+func (k keys) Swap(i, j int) { k[i], k[j] = k[j], k[i] }
+func (k keys) Less(i, j int) bool {
+ return k[i].Segments > k[j].Segments || (k[i].Segments == k[j].Segments && k[i].Key < k[j].Key)
+}
+
+type inlineSchemaNamer struct {
+ Spec *swspec.Swagger
+ Operations map[string]opRef
+}
+
+func opRefsByRef(oprefs map[string]opRef) map[string]opRef {
+ result := make(map[string]opRef, len(oprefs))
+ for _, v := range oprefs {
+ result[v.Ref.String()] = v
+ }
+ return result
+}
+
+func (isn *inlineSchemaNamer) Name(key string, schema *swspec.Schema, aschema *AnalyzedSchema) error {
+ if swspec.Debug {
+ log.Printf("naming inlined schema at %s", key)
+ }
+
+ parts := keyParts(key)
+ for _, name := range namesFromKey(parts, aschema, isn.Operations) {
+ if name != "" {
+ // create unique name
+ newName := uniqifyName(isn.Spec.Definitions, swag.ToJSONName(name))
+
+ // clone schema
+ sch, err := cloneSchema(schema)
+ if err != nil {
+ return err
+ }
+
+ // replace values on schema
+ if err := rewriteSchemaToRef(isn.Spec, key, swspec.MustCreateRef("#/definitions/"+newName)); err != nil {
+ return fmt.Errorf("name inlined schema: %v", err)
+ }
+
+ sch.AddExtension("x-go-gen-location", genLocation(parts))
+ // fmt.Printf("{\n %q,\n \"\",\n spec.MustCreateRef(%q),\n \"\",\n},\n", key, "#/definitions/"+newName)
+ // save cloned schema to definitions
+ saveSchema(isn.Spec, newName, sch)
+ }
+ }
+ return nil
+}
+
+func genLocation(parts splitKey) string {
+ if parts.IsOperation() {
+ return "operations"
+ }
+ if parts.IsDefinition() {
+ return "models"
+ }
+ return ""
+}
+
+func uniqifyName(definitions swspec.Definitions, name string) string {
+ if name == "" {
+ name = "oaiGen"
+ }
+ if len(definitions) == 0 {
+ return name
+ }
+
+ if _, ok := definitions[name]; !ok {
+ return name
+ }
+ name += "OAIGen"
+ var idx int
+ unique := name
+ _, known := definitions[unique]
+ for known {
+ idx++
+ unique = fmt.Sprintf("%s%d", name, idx)
+ _, known = definitions[unique]
+ }
+ return unique
+}
+
+func namesFromKey(parts splitKey, aschema *AnalyzedSchema, operations map[string]opRef) []string {
+ var baseNames [][]string
+ var startIndex int
+ if parts.IsOperation() {
+ // params
+ if parts.IsOperationParam() || parts.IsSharedOperationParam() {
+ piref := parts.PathItemRef()
+ if piref.String() != "" && parts.IsOperationParam() {
+ if op, ok := operations[piref.String()]; ok {
+ startIndex = 5
+ baseNames = append(baseNames, []string{op.ID, "params", "body"})
+ }
+ } else if parts.IsSharedOperationParam() {
+ pref := parts.PathRef()
+ for k, v := range operations {
+ if strings.HasPrefix(k, pref.String()) {
+ startIndex = 4
+ baseNames = append(baseNames, []string{v.ID, "params", "body"})
+ }
+ }
+ }
+ }
+ // responses
+ if parts.IsOperationResponse() {
+ piref := parts.PathItemRef()
+ if piref.String() != "" {
+ if op, ok := operations[piref.String()]; ok {
+ startIndex = 6
+ baseNames = append(baseNames, []string{op.ID, parts.ResponseName(), "body"})
+ }
+ }
+ }
+ }
+
+ // definitions
+ if parts.IsDefinition() {
+ nm := parts.DefinitionName()
+ if nm != "" {
+ startIndex = 2
+ baseNames = append(baseNames, []string{parts.DefinitionName()})
+ }
+ }
+
+ var result []string
+ for _, segments := range baseNames {
+ nm := parts.BuildName(segments, startIndex, aschema)
+ if nm != "" {
+ result = append(result, nm)
+ }
+ }
+ sort.Strings(result)
+ return result
+}
+
+const (
+ pths = "paths"
+ responses = "responses"
+ parameters = "parameters"
+ definitions = "definitions"
+)
+
+var ignoredKeys map[string]struct{}
+
+func init() {
+ ignoredKeys = map[string]struct{}{
+ "schema": {},
+ "properties": {},
+ "not": {},
+ "anyOf": {},
+ "oneOf": {},
+ }
+}
+
+type splitKey []string
+
+func (s splitKey) IsDefinition() bool {
+ return len(s) > 1 && s[0] == definitions
+}
+
+func (s splitKey) DefinitionName() string {
+ if !s.IsDefinition() {
+ return ""
+ }
+ return s[1]
+}
+
+func (s splitKey) BuildName(segments []string, startIndex int, aschema *AnalyzedSchema) string {
+ for _, part := range s[startIndex:] {
+ if _, ignored := ignoredKeys[part]; !ignored {
+ if part == "items" || part == "additionalItems" {
+ if aschema.IsTuple || aschema.IsTupleWithExtra {
+ segments = append(segments, "tuple")
+ } else {
+ segments = append(segments, "items")
+ }
+ if part == "additionalItems" {
+ segments = append(segments, part)
+ }
+ continue
+ }
+ segments = append(segments, part)
+ }
+ }
+ return strings.Join(segments, " ")
+}
+
+func (s splitKey) IsOperation() bool {
+ return len(s) > 1 && s[0] == pths
+}
+
+func (s splitKey) IsSharedOperationParam() bool {
+ return len(s) > 2 && s[0] == pths && s[2] == parameters
+}
+
+func (s splitKey) IsOperationParam() bool {
+ return len(s) > 3 && s[0] == pths && s[3] == parameters
+}
+
+func (s splitKey) IsOperationResponse() bool {
+ return len(s) > 3 && s[0] == pths && s[3] == responses
+}
+
+func (s splitKey) IsDefaultResponse() bool {
+ return len(s) > 4 && s[0] == pths && s[3] == responses && s[4] == "default"
+}
+
+func (s splitKey) IsStatusCodeResponse() bool {
+ isInt := func() bool {
+ _, err := strconv.Atoi(s[4])
+ return err == nil
+ }
+ return len(s) > 4 && s[0] == pths && s[3] == responses && isInt()
+}
+
+func (s splitKey) ResponseName() string {
+ if s.IsStatusCodeResponse() {
+ code, _ := strconv.Atoi(s[4])
+ return http.StatusText(code)
+ }
+ if s.IsDefaultResponse() {
+ return "Default"
+ }
+ return ""
+}
+
+var validMethods map[string]struct{}
+
+func init() {
+ validMethods = map[string]struct{}{
+ "GET": {},
+ "HEAD": {},
+ "OPTIONS": {},
+ "PATCH": {},
+ "POST": {},
+ "PUT": {},
+ "DELETE": {},
+ }
+}
+
+func (s splitKey) PathItemRef() swspec.Ref {
+ if len(s) < 3 {
+ return swspec.Ref{}
+ }
+ pth, method := s[1], s[2]
+ if _, validMethod := validMethods[strings.ToUpper(method)]; !validMethod && !strings.HasPrefix(method, "x-") {
+ return swspec.Ref{}
+ }
+ return swspec.MustCreateRef("#" + path.Join("/", pths, jsonpointer.Escape(pth), strings.ToUpper(method)))
+}
+
+func (s splitKey) PathRef() swspec.Ref {
+ if !s.IsOperation() {
+ return swspec.Ref{}
+ }
+ return swspec.MustCreateRef("#" + path.Join("/", pths, jsonpointer.Escape(s[1])))
+}
+
+func keyParts(key string) splitKey {
+ var res []string
+ for _, part := range strings.Split(key[1:], "/") {
+ if part != "" {
+ res = append(res, jsonpointer.Unescape(part))
+ }
+ }
+ return res
+}
+
+func rewriteSchemaToRef(spec *swspec.Swagger, key string, ref swspec.Ref) error {
+ if swspec.Debug {
+ log.Printf("rewriting schema to ref for %s with %s", key, ref.String())
+ }
+ pth := key[1:]
+ ptr, err := jsonpointer.New(pth)
+ if err != nil {
+ return err
+ }
+
+ value, _, err := ptr.Get(spec)
+ if err != nil {
+ return err
+ }
+
+ switch refable := value.(type) {
+ case *swspec.Schema:
+ return rewriteParentRef(spec, key, ref)
+ case *swspec.SchemaOrBool:
+ if refable.Schema != nil {
+ refable.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+ }
+ case *swspec.SchemaOrArray:
+ if refable.Schema != nil {
+ refable.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+ }
+ case swspec.Schema:
+ return rewriteParentRef(spec, key, ref)
+ default:
+ return fmt.Errorf("no schema with ref found at %s for %T", key, value)
+ }
+
+ return nil
+}
+
+func rewriteParentRef(spec *swspec.Swagger, key string, ref swspec.Ref) error {
+ pth := key[1:]
+ parent, entry := path.Dir(pth), path.Base(pth)
+ if swspec.Debug {
+ log.Println("getting schema holder at:", parent)
+ }
+
+ pptr, err := jsonpointer.New(parent)
+ if err != nil {
+ return err
+ }
+ pvalue, _, err := pptr.Get(spec)
+ if err != nil {
+ return fmt.Errorf("can't get parent for %s: %v", parent, err)
+ }
+ if swspec.Debug {
+ log.Printf("rewriting holder for %T", pvalue)
+ }
+
+ switch container := pvalue.(type) {
+ case swspec.Response:
+ if err := rewriteParentRef(spec, "#"+parent, ref); err != nil {
+ return err
+ }
+
+ case *swspec.Response:
+ container.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+
+ case *swspec.Responses:
+ statusCode, err := strconv.Atoi(entry)
+ if err != nil {
+ return fmt.Errorf("%s not a number: %v", pth, err)
+ }
+ resp := container.StatusCodeResponses[statusCode]
+ resp.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+ container.StatusCodeResponses[statusCode] = resp
+
+ case map[string]swspec.Response:
+ resp := container[entry]
+ resp.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+ container[entry] = resp
+
+ case swspec.Parameter:
+ if err := rewriteParentRef(spec, "#"+parent, ref); err != nil {
+ return err
+ }
+
+ case map[string]swspec.Parameter:
+ param := container[entry]
+ param.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+ container[entry] = param
+
+ case []swspec.Parameter:
+ idx, err := strconv.Atoi(entry)
+ if err != nil {
+ return fmt.Errorf("%s not a number: %v", pth, err)
+ }
+ param := container[idx]
+ param.Schema = &swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+ container[idx] = param
+
+ case swspec.Definitions:
+ container[entry] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+
+ case map[string]swspec.Schema:
+ container[entry] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+
+ case []swspec.Schema:
+ idx, err := strconv.Atoi(entry)
+ if err != nil {
+ return fmt.Errorf("%s not a number: %v", pth, err)
+ }
+ container[idx] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+
+ case *swspec.SchemaOrArray:
+ idx, err := strconv.Atoi(entry)
+ if err != nil {
+ return fmt.Errorf("%s not a number: %v", pth, err)
+ }
+ container.Schemas[idx] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+ default:
+ return fmt.Errorf("unhandled parent schema rewrite %s (%T)", key, pvalue)
+ }
+ return nil
+}
+
+func cloneSchema(schema *swspec.Schema) (*swspec.Schema, error) {
+ var sch swspec.Schema
+ if err := swag.FromDynamicJSON(schema, &sch); err != nil {
+ return nil, fmt.Errorf("name inlined schema: %v", err)
+ }
+ return &sch, nil
+}
+
+func importExternalReferences(opts *FlattenOpts) error {
+ groupedRefs := reverseIndexForSchemaRefs(opts)
+
+ for refStr, entry := range groupedRefs {
+ if !entry.Ref.HasFragmentOnly {
+ if swspec.Debug {
+ log.Printf("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr)
+ }
+ // resolve to actual schema
+ sch, err := swspec.ResolveRefWithBase(opts.Swagger(), &entry.Ref, opts.ExpandOpts(false))
+ if err != nil {
+ return err
+ }
+ if sch == nil {
+ return fmt.Errorf("no schema found at %s for [%s]", refStr, strings.Join(entry.Keys, ", "))
+ }
+ if swspec.Debug {
+ log.Printf("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr)
+ }
+
+ // generate a unique name
+ newName := uniqifyName(opts.Swagger().Definitions, nameFromRef(entry.Ref))
+ if swspec.Debug {
+ log.Printf("new name for [%s]: %s", strings.Join(entry.Keys, ", "), newName)
+ }
+
+ // rewrite the external refs to local ones
+ for _, key := range entry.Keys {
+ if err := updateRef(opts.Swagger(), key, swspec.MustCreateRef("#"+path.Join("/definitions", newName))); err != nil {
+ return err
+ }
+ }
+
+ // add the resolved schema to the definitions
+ saveSchema(opts.Swagger(), newName, sch)
+ }
+ }
+ return nil
+}
+
+type refRevIdx struct {
+ Ref swspec.Ref
+ Keys []string
+}
+
+func reverseIndexForSchemaRefs(opts *FlattenOpts) map[string]refRevIdx {
+ collected := make(map[string]refRevIdx)
+ for key, schRef := range opts.Spec.references.schemas {
+ if entry, ok := collected[schRef.String()]; ok {
+ entry.Keys = append(entry.Keys, key)
+ collected[schRef.String()] = entry
+ } else {
+ collected[schRef.String()] = refRevIdx{
+ Ref: schRef,
+ Keys: []string{key},
+ }
+ }
+ }
+ return collected
+}
+
+func nameFromRef(ref swspec.Ref) string {
+ u := ref.GetURL()
+ if u.Fragment != "" {
+ return swag.ToJSONName(path.Base(u.Fragment))
+ }
+ if u.Path != "" {
+ bn := path.Base(u.Path)
+ if bn != "" && bn != "/" {
+ ext := path.Ext(bn)
+ if ext != "" {
+ return swag.ToJSONName(bn[:len(bn)-len(ext)])
+ }
+ return swag.ToJSONName(bn)
+ }
+ }
+ return swag.ToJSONName(strings.Replace(u.Host, ".", " ", -1))
+}
+
+func saveSchema(spec *swspec.Swagger, name string, schema *swspec.Schema) {
+ if schema == nil {
+ return
+ }
+ if spec.Definitions == nil {
+ spec.Definitions = make(map[string]swspec.Schema, 150)
+ }
+ spec.Definitions[name] = *schema
+}
+
+func updateRef(spec *swspec.Swagger, key string, ref swspec.Ref) error {
+ if swspec.Debug {
+ log.Printf("updating ref for %s with %s", key, ref.String())
+ }
+ pth := key[1:]
+ ptr, err := jsonpointer.New(pth)
+ if err != nil {
+ return err
+ }
+
+ value, _, err := ptr.Get(spec)
+ if err != nil {
+ return err
+ }
+
+ switch refable := value.(type) {
+ case *swspec.Schema:
+ refable.Ref = ref
+ case *swspec.SchemaOrBool:
+ if refable.Schema != nil {
+ refable.Schema.Ref = ref
+ }
+ case *swspec.SchemaOrArray:
+ if refable.Schema != nil {
+ refable.Schema.Ref = ref
+ }
+ case swspec.Schema:
+ parent, entry := path.Dir(pth), path.Base(pth)
+ if swspec.Debug {
+ log.Println("getting schema holder at:", parent)
+ }
+
+ pptr, err := jsonpointer.New(parent)
+ if err != nil {
+ return err
+ }
+ pvalue, _, err := pptr.Get(spec)
+ if err != nil {
+ return fmt.Errorf("can't get parent for %s: %v", parent, err)
+ }
+
+ switch container := pvalue.(type) {
+ case swspec.Definitions:
+ container[entry] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+
+ case map[string]swspec.Schema:
+ container[entry] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+
+ case []swspec.Schema:
+ idx, err := strconv.Atoi(entry)
+ if err != nil {
+ return fmt.Errorf("%s not a number: %v", pth, err)
+ }
+ container[idx] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+
+ case *swspec.SchemaOrArray:
+ idx, err := strconv.Atoi(entry)
+ if err != nil {
+ return fmt.Errorf("%s not a number: %v", pth, err)
+ }
+ container.Schemas[idx] = swspec.Schema{SchemaProps: swspec.SchemaProps{Ref: ref}}
+
+ }
+
+ default:
+ return fmt.Errorf("no schema with ref found at %s for %T", key, value)
+ }
+
+ return nil
+}
+
+func containsString(names []string, name string) bool {
+ for _, nm := range names {
+ if nm == name {
+ return true
+ }
+ }
+ return false
+}
+
+type opRef struct {
+ Method string
+ Path string
+ Key string
+ ID string
+ Op *swspec.Operation
+ Ref swspec.Ref
+}
+
+type opRefs []opRef
+
+func (o opRefs) Len() int { return len(o) }
+func (o opRefs) Swap(i, j int) { o[i], o[j] = o[j], o[i] }
+func (o opRefs) Less(i, j int) bool { return o[i].Key < o[j].Key }
+
+func gatherOperations(specDoc *Spec, operationIDs []string) map[string]opRef {
+ var oprefs opRefs
+
+ for method, pathItem := range specDoc.Operations() {
+ for pth, operation := range pathItem {
+ vv := *operation
+ oprefs = append(oprefs, opRef{
+ Key: swag.ToGoName(strings.ToLower(method) + " " + pth),
+ Method: method,
+ Path: pth,
+ ID: vv.ID,
+ Op: &vv,
+ Ref: swspec.MustCreateRef("#" + path.Join("/paths", jsonpointer.Escape(pth), method)),
+ })
+ }
+ }
+
+ sort.Sort(oprefs)
+
+ operations := make(map[string]opRef)
+ for _, opr := range oprefs {
+ nm := opr.ID
+ if nm == "" {
+ nm = opr.Key
+ }
+
+ oo, found := operations[nm]
+ if found && oo.Method != opr.Method && oo.Path != opr.Path {
+ nm = opr.Key
+ }
+ if len(operationIDs) == 0 || containsString(operationIDs, opr.ID) || containsString(operationIDs, nm) {
+ opr.ID = nm
+ opr.Op.ID = nm
+ operations[nm] = opr
+ }
+ }
+
+ return operations
+}