Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions mutator/mutator.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ func combineErrorsWithDefault(p *pkg.Package) *pkg.Package {
return p
}

// inlinePrimitiveTypes takes any non-struct type declarations and inlines their
// use as the original type in function parameters, return types, and structs.
// inlinePrimitiveTypes takes any non-struct, non-interface type declarations
// and inlines their use as the original type in function parameters, return
// types, and structs.
//
// Removal of the type declaration is handled in subsequent mutations.
func inlinePrimitiveTypes(p *pkg.Package) *pkg.Package {
for _, d := range p.TypeDecls {
if _, ok := d.Type.(*pkg.StructType); ok {
switch d.Type.(type) {
case *pkg.StructType, *pkg.InterfaceType:
continue
}

Expand Down Expand Up @@ -354,6 +356,14 @@ func recurseType(typ pkg.Type, parentCtx typeContext, fn func(pkg.Type, typeCont
t.Type = recurseType(t.Type, parentCtx|iter, fn)
case *pkg.PointerType:
t.Type = recurseType(t.Type, parentCtx, fn)
case *pkg.InterfaceType:
for i := range t.Methods {
t.Methods[i].Return = recurseType(t.Methods[i].Return, parentCtx, fn)
}

for i := range t.Implementors {
t.Implementors[i].Type = recurseType(t.Implementors[i].Type, parentCtx, fn)
}
}

return fn(typ, parentCtx)
Expand Down
58 changes: 58 additions & 0 deletions mutator/mutator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,36 @@ func TestInlinePrimitiveTypes(t *testing.T) {
}}}},
},
},

{"struct not inlined",
pkg.Package{
TypeDecls: []pkg.TypeDecl{{Name: "ID", Type: &pkg.StructType{}}},
Clients: []pkg.Client{{Methods: []pkg.Method{{
Errors: map[int]pkg.Type{-1: &pkg.IdentType{Name: "ID"}},
}}}},
},
pkg.Package{
TypeDecls: []pkg.TypeDecl{{Name: "ID", Type: &pkg.StructType{}}},
Clients: []pkg.Client{{Methods: []pkg.Method{{
Errors: map[int]pkg.Type{-1: &pkg.IdentType{Name: "ID"}},
}}}},
},
},

{"interface not inlined",
pkg.Package{
TypeDecls: []pkg.TypeDecl{{Name: "ID", Type: &pkg.InterfaceType{}}},
Clients: []pkg.Client{{Methods: []pkg.Method{{
Errors: map[int]pkg.Type{-1: &pkg.IdentType{Name: "ID"}},
}}}},
},
pkg.Package{
TypeDecls: []pkg.TypeDecl{{Name: "ID", Type: &pkg.InterfaceType{}}},
Clients: []pkg.Client{{Methods: []pkg.Method{{
Errors: map[int]pkg.Type{-1: &pkg.IdentType{Name: "ID"}},
}}}},
},
},
}

for _, tc := range tcs {
Expand Down Expand Up @@ -229,6 +259,23 @@ func TestInlineResponseStruct(t *testing.T) {
}
}

interfacePkg := func(c ...pkg.Client) pkg.Package {
return pkg.Package{
TypeDecls: []pkg.TypeDecl{
{Name: "FieldThing", Type: &pkg.StructType{
Fields: []pkg.Field{{ID: "Field", Type: &pkg.IdentType{Name: "string"}}},
}},
{Name: "StructThing", Type: &pkg.StructType{
Fields: []pkg.Field{{ID: "Field", Type: &pkg.IdentType{Name: "FieldThing"}}},
}},
{Name: "InterfaceThing", Type: &pkg.InterfaceType{
Methods: []pkg.InterfaceMethod{{Name: "GetField", Return: &pkg.IdentType{Name: "FieldThing"}}},
}},
},
Clients: c,
}
}

inlineDoublePkg := func(c ...pkg.Client) pkg.Package {
return pkg.Package{
TypeDecls: []pkg.TypeDecl{
Expand Down Expand Up @@ -329,6 +376,17 @@ func TestInlineResponseStruct(t *testing.T) {
Return: []pkg.Type{&pkg.IdentType{Name: "StructThing"}},
}}}),
},

{"not inlined if used in one struct and interface",
interfacePkg(pkg.Client{Methods: []pkg.Method{{Return: []pkg.Type{
&pkg.IdentType{Name: "StructThing"},
&pkg.IdentType{Name: "InterfaceThing"},
}}}}),
interfacePkg(pkg.Client{Methods: []pkg.Method{{Return: []pkg.Type{
&pkg.IdentType{Name: "StructThing"},
&pkg.IdentType{Name: "InterfaceThing"},
}}}}),
},
}

for _, tc := range tcs {
Expand Down
6 changes: 3 additions & 3 deletions openapi/v2/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,7 @@ func (a *AllOfSchema) UnmarshalYAML(um func(interface{}) error) error {
// ObjectSchema is a schema definition for an object.
type ObjectSchema struct {
SchemaFields `yaml:",inline"`
Descriminator *string
Discriminator *string

Properties *SchemaMap
Required *[]string
Expand All @@ -775,7 +775,7 @@ type ObjectSchema struct {
func (o *ObjectSchema) UnmarshalYAML(um func(interface{}) error) error {
var oy struct {
SchemaFields `yaml:",inline"`
Descriminator *string
Discriminator *string

Properties *SchemaMap
Required *[]string
Expand All @@ -789,7 +789,7 @@ func (o *ObjectSchema) UnmarshalYAML(um func(interface{}) error) error {
}

o.SchemaFields = oy.SchemaFields
o.Descriminator = oy.Descriminator
o.Discriminator = oy.Discriminator
o.Properties = oy.Properties
o.Required = oy.Required
o.MinProperties = oy.MinProperties
Expand Down
77 changes: 62 additions & 15 deletions pkg/pkg.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,21 +71,22 @@ type StructType struct {

// Equal implements equality for Types
func (t *StructType) Equal(o Type) bool {
if ot, ok := o.(*StructType); ok {
if len(t.Fields) != len(ot.Fields) {
return false
}
ot, ok := o.(*StructType)
if !ok {
return false
}

for i, f := range t.Fields {
if !f.equal(ot.Fields[i]) {
return false
}
}
if len(t.Fields) != len(ot.Fields) {
return false
}

return true
for i, f := range t.Fields {
if !f.equal(ot.Fields[i]) {
return false
}
}

return false
return true
}

// IterType is used for return types, indicating they're iterators
Expand Down Expand Up @@ -117,18 +118,64 @@ func (t *MapType) Equal(o Type) bool {
return false
}

// InterfaceType is an empty interface
type InterfaceType struct{}
// EmptyInterfaceType is an empty interface
type EmptyInterfaceType struct{}

// Equal implements equality for Types
func (t *InterfaceType) Equal(o Type) bool {
_, ok := o.(*InterfaceType)
func (t *EmptyInterfaceType) Equal(o Type) bool {
_, ok := o.(*EmptyInterfaceType)
return ok
}

// InterfaceType is an interface that represents the common values in an
// OpenAPI discriminator type.
type InterfaceType struct {
Methods []InterfaceMethod
Implementors []InterfaceImplementor
}

// Equal implements equality for Types
func (t *InterfaceType) Equal(o Type) bool {
ot, ok := o.(*InterfaceType)
if !ok {
return false
}

if len(t.Methods) != len(ot.Methods) {
return false
}

for i, m := range t.Methods {
if !m.equal(ot.Methods[i]) {
return false
}
}

return true
}

// InterfaceMethod is a method on an interface
type InterfaceMethod struct {
Name string
Return Type
Comment string
}

func (m InterfaceMethod) equal(o InterfaceMethod) bool {
return m.Name == o.Name && m.Return.Equal(o.Return)
}

// InterfaceImplementor is an Implementor of an interface created from
// discriminators
type InterfaceImplementor struct {
Discriminator string
Type Type
}

// TypeDecl is a type declaration.
type TypeDecl struct {
Name string
Orig string
Comment string
Type Type
}
Expand Down
13 changes: 12 additions & 1 deletion pkg/pkg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,18 @@ func TestTypeEqual(t *testing.T) {
&StructType{Fields: []Field{{ID: "Name", Type: &IdentType{Name: "Thing"}}}},
&MapType{Key: &IdentType{Name: "string"}, Value: &IdentType{Name: "int"}},
&MapType{Key: &IdentType{Name: "int"}, Value: &SliceType{&IdentType{Name: "int"}}},
&InterfaceType{},
&EmptyInterfaceType{},
&InterfaceType{Methods: []InterfaceMethod{}},
&InterfaceType{Methods: []InterfaceMethod{
{Name: "GetFoo", Return: &IdentType{Name: "string"}},
}},
&InterfaceType{Methods: []InterfaceMethod{
{Name: "GetFoo", Return: &IdentType{Name: "int"}},
}},
&InterfaceType{Methods: []InterfaceMethod{
{Name: "GetBar", Return: &IdentType{Name: "int"}},
{Name: "GetFoo", Return: &IdentType{Name: "string"}},
}},
}

for i := range cases {
Expand Down
Loading