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
24 changes: 14 additions & 10 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,8 @@ func (p *Parser) Parse() (Definition, error) {
}
p.def.Services = append(p.def.Services, s)
case *types.Struct:
p.parseObject(pkg, obj, item)
// depth=1 to be consistent with parseMethod param objects
p.parseObject(pkg, obj, item, 1)
}
}
}
Expand Down Expand Up @@ -299,15 +300,15 @@ func (p *Parser) parseMethod(pkg *packages.Package, serviceName string, methodTy
if inputParams.Len() != 1 {
return m, p.wrapErr(errors.New("invalid method signature: expected Method(MethodRequest) MethodResponse"), pkg, methodType.Pos())
}
m.InputObject, err = p.parseFieldType(pkg, inputParams.At(0))
m.InputObject, err = p.parseFieldType(pkg, inputParams.At(0), 0)
if err != nil {
return m, errors.Wrap(err, "parse input object type")
}
outputParams := sig.Results()
if outputParams.Len() != 1 {
return m, p.wrapErr(errors.New("invalid method signature: expected Method(MethodRequest) MethodResponse"), pkg, methodType.Pos())
}
m.OutputObject, err = p.parseFieldType(pkg, outputParams.At(0))
m.OutputObject, err = p.parseFieldType(pkg, outputParams.At(0), 0)
if err != nil {
return m, errors.Wrap(err, "parse output object type")
}
Expand All @@ -316,7 +317,9 @@ func (p *Parser) parseMethod(pkg *packages.Package, serviceName string, methodTy
}

// parseObject parses a struct type and adds it to the Definition.
func (p *Parser) parseObject(pkg *packages.Package, o types.Object, v *types.Struct) error {
//
// depth is 0-indexed.
func (p *Parser) parseObject(pkg *packages.Package, o types.Object, v *types.Struct, depth int) error {
var obj Object
obj.Name = o.Name()
obj.Comment = p.commentForType(obj.Name)
Expand Down Expand Up @@ -344,7 +347,7 @@ func (p *Parser) parseObject(pkg *packages.Package, o types.Object, v *types.Str

obj.Fields = []Field{}
for i := 0; i < st.NumFields(); i++ {
field, err := p.parseField(pkg, obj.Name, st.Field(i), st.Tag(i))
field, err := p.parseField(pkg, obj.Name, st.Field(i), st.Tag(i), depth)
if err != nil {
return err
}
Expand Down Expand Up @@ -375,7 +378,7 @@ func (p *Parser) parseTags(tag string) (map[string]FieldTag, error) {
return fieldTags, nil
}

func (p *Parser) parseField(pkg *packages.Package, objectName string, v *types.Var, tag string) (Field, error) {
func (p *Parser) parseField(pkg *packages.Package, objectName string, v *types.Var, tag string, depth int) (Field, error) {
var f Field
f.Name = v.Name()
f.NameLowerCamel = camelizeDown(f.Name)
Expand All @@ -389,7 +392,8 @@ func (p *Parser) parseField(pkg *packages.Package, objectName string, v *types.V
}
f.Comment = p.commentForField(objectName, f.Name)
f.Metadata = map[string]interface{}{}
if !v.Exported() {
if depth <= 1 && !v.Exported() {
// request/response struct field
return f, p.wrapErr(errors.New(f.Name+" must be exported"), pkg, v.Pos())
}
var err error
Expand All @@ -400,14 +404,14 @@ func (p *Parser) parseField(pkg *packages.Package, objectName string, v *types.V
if example, ok := f.Metadata["example"]; ok {
f.Example = example
}
f.Type, err = p.parseFieldType(pkg, v)
f.Type, err = p.parseFieldType(pkg, v, depth)
if err != nil {
return f, errors.Wrap(err, "parse type")
}
return f, nil
}

func (p *Parser) parseFieldType(pkg *packages.Package, obj types.Object) (FieldType, error) {
func (p *Parser) parseFieldType(pkg *packages.Package, obj types.Object, depth int) (FieldType, error) {
var ftype FieldType
pkgPath := pkg.PkgPath
resolver := func(other *types.Package) string {
Expand Down Expand Up @@ -437,7 +441,7 @@ func (p *Parser) parseFieldType(pkg *packages.Package, obj types.Object) (FieldT
}
if named, ok := typ.(*types.Named); ok {
if structure, ok := named.Underlying().(*types.Struct); ok {
if err := p.parseObject(pkg, named.Obj(), structure); err != nil {
if err := p.parseObject(pkg, named.Obj(), structure, depth+1); err != nil {
return ftype, err
}
ftype.IsObject = true
Expand Down
21 changes: 21 additions & 0 deletions parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,27 @@ You will love it.`)
// log.Println(string(b))
}

func TestParseUnexportedFields(t *testing.T) {
t.Run("response field", func(t *testing.T) {
is := is.New(t)
patterns := []string{"./testdata/unexported-fields"}
p := New(patterns...)
p.Verbose = testing.Verbose()
_, err := p.Parse()
is.True(err != nil)
is.True(strings.Contains(err.Error(), "result must be exported"))
})

t.Run("deeper field", func(t *testing.T) {
is := is.New(t)
patterns := []string{"./testdata/unexported-deeper-fields"}
p := New(patterns...)
p.Verbose = testing.Verbose()
_, err := p.Parse()
is.NoErr(err)
})
}

func TestFieldTypeIsOptional(t *testing.T) {
is := is.New(t)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package unexporteddeeper

import "math/big"

type CalculatorService interface {
Calculate(CalculateRequest) CalculateResponse
}

type CalculateRequest struct{}

type CalculateResponse struct {
// big.Int has unexported fields
Result big.Int
}
11 changes: 11 additions & 0 deletions parser/testdata/unexported-fields/unexported-fields.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package unexported

type CalculatorService interface {
Calculate(CalculateRequest) CalculateResponse
}

type CalculateRequest struct{}

type CalculateResponse struct {
result int
}