Skip to content

Commit

Permalink
Use ordered maps
Browse files Browse the repository at this point in the history
Signed-off-by: Pierre Fenoll <pierrefenoll@gmail.com>
  • Loading branch information
fenollp committed Dec 18, 2022
1 parent 3be535f commit 54b3980
Show file tree
Hide file tree
Showing 33 changed files with 553 additions and 253 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
fail-fast: true
matrix:
go: ['1.16', '1.x']
go: ['1.x']
os:
- ubuntu-latest
- windows-latest
Expand Down Expand Up @@ -88,7 +88,7 @@ jobs:
run: |
! git grep -InE 'json:"' | grep -v _test.go | grep -v yaml:
- if: runner.os == 'Linux' && matrix.go != '1.16'
- if: runner.os == 'Linux'
name: nilness
run: go run golang.org/x/tools/go/analysis/passes/nilness/cmd/nilness@latest ./...

Expand Down
15 changes: 13 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
module github.com/getkin/kin-openapi

go 1.16
go 1.18

require (
github.com/go-openapi/jsonpointer v0.19.5
github.com/gorilla/mux v1.8.0
github.com/invopop/yaml v0.1.0
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
github.com/stretchr/testify v1.8.1
gopkg.in/yaml.v2 v2.4.0 // indirect
github.com/wk8/go-ordered-map/v2 v2.1.5
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/buger/jsonparser v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-openapi/swag v0.19.5 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
11 changes: 10 additions & 1 deletion go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -9,14 +13,17 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/invopop/yaml v0.1.0 h1:YW3WGUoJEXYfzWBjn00zIlrw7brGVD0fUKRYDPAPhrc=
github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand All @@ -29,6 +36,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/wk8/go-ordered-map/v2 v2.1.5 h1:jLbYIFyWQMUwHLO20cImlCRBoNc5lp0nmE2dvwcxc7k=
github.com/wk8/go-ordered-map/v2 v2.1.5/go.mod h1:9Xvgm2mV2kSq2SAm0Y608tBmu8akTzI7c2bz7/G7ZN4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
12 changes: 5 additions & 7 deletions openapi2/openapi2.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type T struct {
Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"`
Host string `json:"host,omitempty" yaml:"host,omitempty"`
BasePath string `json:"basePath,omitempty" yaml:"basePath,omitempty"`
Paths map[string]*PathItem `json:"paths,omitempty" yaml:"paths,omitempty"`
Paths *Paths `json:"paths,omitempty" yaml:"paths,omitempty"`
Definitions map[string]*openapi3.SchemaRef `json:"definitions,omitempty" yaml:"definitions,omitempty"`
Parameters map[string]*Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"`
Responses map[string]*Response `json:"responses,omitempty" yaml:"responses,omitempty"`
Expand All @@ -40,15 +40,13 @@ func (doc *T) UnmarshalJSON(data []byte) error {
}

func (doc *T) AddOperation(path string, method string, operation *Operation) {
paths := doc.Paths
if paths == nil {
paths = make(map[string]*PathItem)
doc.Paths = paths
if doc.Paths == nil {
doc.Paths = NewPaths()
}
pathItem := paths[path]
pathItem := doc.Paths.Value(path)
if pathItem == nil {
pathItem = &PathItem{}
paths[path] = pathItem
doc.Paths.Set(path, pathItem)
}
pathItem.SetOperation(method, operation)
}
Expand Down
80 changes: 80 additions & 0 deletions openapi2/paths.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package openapi2

import (
"encoding/json"

orderedmap "github.com/wk8/go-ordered-map/v2"
)

type Paths struct {
om *orderedmap.OrderedMap[string, *PathItem]
}

// MarshalJSON returns the JSON encoding of Paths.
func (paths *Paths) MarshalJSON() ([]byte, error) {
if paths == nil || paths.om == nil {
return []byte("{}"), nil
}
return paths.om.MarshalJSON()
}

// UnmarshalJSON sets Paths to a copy of data.
func (paths *Paths) UnmarshalJSON(data []byte) error {
return json.Unmarshal(data, &paths.om)
}

func (paths *Paths) Value(key string) *PathItem {
// if paths == nil || paths.om == nil {
// return nil
// }
return paths.om.Value(key)
}

func (paths *Paths) Set(key string, value *PathItem) {
// if paths != nil || paths.om != nil {
_, _ = paths.om.Set(key, value)
// }
}

func (paths *Paths) Len() int {
if paths == nil || paths.om == nil {
return 0
}
return paths.om.Len()
}

func (paths *Paths) Iter() *pathsKV {
if paths == nil || paths.om == nil {
return nil
}
return (*pathsKV)(paths.om.Oldest())
}

type pathsKV orderedmap.Pair[string, *PathItem] //FIXME: pub?

func (pair *pathsKV) Next() *pathsKV {
ompair := (*orderedmap.Pair[string, *PathItem])(pair)
return (*pathsKV)(ompair.Next())
}

// NewPathsWithCapacity builds a paths object of the given capacity.
func NewPathsWithCapacity(cap int) *Paths {
return &Paths{om: orderedmap.New[string, *PathItem](cap)}
}

// NewPaths builds a paths object with path items in insertion order.
func NewPaths(opts ...NewPathsOption) *Paths {
paths := NewPathsWithCapacity(len(opts))
for _, opt := range opts {
opt(paths)
}
return paths
}

// NewPathsOption describes options to NewPaths func
type NewPathsOption func(*Paths)

// WithPath adds paths as an option to NewPaths
func WithPath(path string, pathItem *PathItem) NewPathsOption {
return func(paths *Paths) { paths.Set(path, pathItem) }
}
4 changes: 2 additions & 2 deletions openapi2conv/issue558_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ paths:
`
doc3, err := v2v3YAML([]byte(spec))
require.NoError(t, err)
require.NotEmpty(t, doc3.Paths["/test"].Get.Deprecated)
require.NotEmpty(t, doc3.Paths.Value("/test").Get.Deprecated)
_, err = yaml.Marshal(doc3)
require.NoError(t, err)

doc2, err := FromV3(doc3)
require.NoError(t, err)
require.NotEmpty(t, doc2.Paths["/test"].Get.Deprecated)
require.NotEmpty(t, doc2.Paths.Value("/test").Get.Deprecated)
}
4 changes: 2 additions & 2 deletions openapi2conv/issue573_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ func TestIssue573(t *testing.T) {

// Make sure the response content appears for each mime-type originally
// appeared in "produces".
pingGetContent := v3.Paths["/ping"].Get.Responses["200"].Value.Content
pingGetContent := v3.Paths.Value("/ping").Get.Responses["200"].Value.Content
require.Len(t, pingGetContent, 2)
require.Contains(t, pingGetContent, "application/toml")
require.Contains(t, pingGetContent, "application/xml")

// Is "produces" is not explicitly specified, default to "application/json".
pingPostContent := v3.Paths["/ping"].Post.Responses["200"].Value.Content
pingPostContent := v3.Paths.Value("/ping").Post.Responses["200"].Value.Content
require.Len(t, pingPostContent, 1)
require.Contains(t, pingPostContent, "application/json")
}
43 changes: 21 additions & 22 deletions openapi2conv/openapi2_conv.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"sort"
"strings"

orderedmap "github.com/wk8/go-ordered-map/v2"

"github.com/getkin/kin-openapi/openapi2"
"github.com/getkin/kin-openapi/openapi3"
)
Expand Down Expand Up @@ -69,16 +71,14 @@ func ToV3(doc2 *openapi2.T) (*openapi3.T, error) {
}
}

if paths := doc2.Paths; len(paths) != 0 {
doc3Paths := make(map[string]*openapi3.PathItem, len(paths))
for path, pathItem := range paths {
r, err := ToV3PathItem(doc2, &doc3.Components, pathItem, doc2.Consumes)
if err != nil {
return nil, err
}
doc3Paths[path] = r
doc3.Paths = openapi3.NewPathsWithCapacity(doc2.Paths.Len())
for pair := doc2.Paths.Iter(); pair != nil; pair = pair.Next() {
path, pathItem := pair.Key, pair.Value
r, err := ToV3PathItem(doc2, &doc3.Components, pathItem, doc2.Consumes)
if err != nil {
return nil, err
}
doc3.Paths = doc3Paths
doc3.Paths.Set(path, r)
}

if responses := doc2.Responses; len(responses) != 0 {
Expand Down Expand Up @@ -556,9 +556,9 @@ func ToV3SecurityScheme(securityScheme *openapi2.SecurityScheme) (*openapi3.Secu
result.Type = "oauth2"
flows := &openapi3.OAuthFlows{}
result.Flows = flows
scopesMap := make(map[string]string)
scopesMap := orderedmap.New[string, string](len(securityScheme.Scopes))
for scope, desc := range securityScheme.Scopes {
scopesMap[scope] = desc
scopesMap.Set(scope, desc)
}
flow := &openapi3.OAuthFlow{
AuthorizationURL: securityScheme.AuthorizationURL,
Expand Down Expand Up @@ -628,7 +628,8 @@ func FromV3(doc3 *openapi3.T) (*openapi2.T, error) {
if isHTTP {
doc2.Schemes = append(doc2.Schemes, "http")
}
for path, pathItem := range doc3.Paths {
for pair := doc3.Paths.Iter(); pair != nil; pair = pair.Next() {
path, pathItem := pair.Key, pair.Value
if pathItem == nil {
continue
}
Expand All @@ -654,7 +655,7 @@ func FromV3(doc3 *openapi3.T) (*openapi2.T, error) {
params = append(params, p)
}
sort.Sort(params)
doc2.Paths[path].Parameters = params
doc2.Paths.Value(path).Parameters = params
}

for name, param := range doc3.Components.Parameters {
Expand Down Expand Up @@ -1179,9 +1180,9 @@ func FromV3SecurityScheme(doc3 *openapi3.T, ref *openapi3.SecuritySchemeRef) (*o
return nil, nil
}

result.Scopes = make(map[string]string, len(flow.Scopes))
for scope, desc := range flow.Scopes {
result.Scopes[scope] = desc
result.Scopes = make(map[string]string, flow.Scopes.Len())
for pair := flow.Scopes.Oldest(); pair != nil; pair = pair.Next() {
result.Scopes[pair.Key] = pair.Value
}
}
default:
Expand All @@ -1204,15 +1205,13 @@ func stripNonCustomExtensions(extensions map[string]interface{}) {
}

func addPathExtensions(doc2 *openapi2.T, path string, extensionProps openapi3.ExtensionProps) {
paths := doc2.Paths
if paths == nil {
paths = make(map[string]*openapi2.PathItem)
doc2.Paths = paths
if doc2.Paths == nil {
doc2.Paths = openapi2.NewPaths()
}
pathItem := paths[path]
pathItem := doc2.Paths.Value(path)
if pathItem == nil {
pathItem = &openapi2.PathItem{}
paths[path] = pathItem
doc2.Paths.Set(path, pathItem)
}
pathItem.ExtensionProps = extensionProps
}

0 comments on commit 54b3980

Please sign in to comment.