Skip to content

Commit

Permalink
feat(parser): support anonymous field (#40)
Browse files Browse the repository at this point in the history
* feat: support anonymous field

* remove debug print
  • Loading branch information
easonlin404 authored Feb 4, 2018
1 parent 00391fb commit 652a19a
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 24 deletions.
6 changes: 6 additions & 0 deletions example/simple/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ func Upload(ctx *gin.Context) {
//write your code
}

// @Summary use Anonymous field
// @Success 200 {object} web.RevValue "ok"
func AnonymousField() {

}

type Pet3 struct {
ID int `json:"id"`
}
64 changes: 61 additions & 3 deletions example/simple/docs/docs.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
// This file was generated by swaggo/swag at
// 2017-11-09 17:06:49.294949095 -0800 PST m=+0.071072332
// 2018-02-04 17:07:16.008489 +0800 CST m=+0.080555450

package docs

Expand Down Expand Up @@ -28,6 +28,50 @@ var doc = `{
"host": "petstore.swagger.io",
"basePath": "/v2",
"paths": {
"/file/upload": {
"post": {
"description": "Upload file",
"consumes": [
"multipart/form-data"
],
"produces": [
"application/json"
],
"summary": "Upload file",
"operationId": "file.upload",
"parameters": [
{
"type": "file",
"description": "this is a test file",
"name": "file",
"in": "formData",
"required": true
}
],
"responses": {
"200": {
"description": "ok",
"schema": {
"type": "string"
}
},
"400": {
"description": "We need ID!!",
"schema": {
"type": "object",
"$ref": "#/definitions/web.APIError"
}
},
"404": {
"description": "Can not find ID",
"schema": {
"type": "object",
"$ref": "#/definitions/web.APIError"
}
}
}
}
},
"/testapi/get-string-by-int/{some_id}": {
"get": {
"description": "get string by ID",
Expand Down Expand Up @@ -148,7 +192,7 @@ var doc = `{
"type": "string"
},
"ErrorCode": {
"type": "int"
"type": "integer"
},
"ErrorMessage": {
"type": "string"
Expand All @@ -162,7 +206,7 @@ var doc = `{
"type": "object"
},
"ID": {
"type": "int"
"type": "integer"
},
"Name": {
"type": "string"
Expand All @@ -177,6 +221,20 @@ var doc = `{
"type": "array"
}
}
},
"web.RevValue": {
"type": "object",
"properties": {
"Data": {
"type": "integer"
},
"Err": {
"type": "int32"
},
"Status": {
"type": "bool"
}
}
}
}
}`
Expand Down
15 changes: 14 additions & 1 deletion example/simple/web/handler.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package web

import "time"
import (
"time"
)

type Pet struct {
ID int `json:"id"`
Expand All @@ -26,3 +28,14 @@ type APIError struct {
ErrorMessage string
CreatedAt time.Time
}

type RevValueBase struct {
Status bool `json:"Status"`

Err int32 `json:"Err"`
}
type RevValue struct {
RevValueBase

Data int `json:"Data"`
}
4 changes: 4 additions & 0 deletions operation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ func TestParseResponseCommentWithObjectType(t *testing.T) {
assert.Equal(t, expected, string(b))
}

func TestParseResponseCommentWithObjectTypeAnonymousField(t *testing.T) {
//TODO: test Anonymous
}

func TestParseResponseCommentWithObjectTypeErr(t *testing.T) {
comment := `@Success 200 {object} model.OrderRow "Error message, if code != 200"`
operation := NewOperation()
Expand Down
72 changes: 52 additions & 20 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,26 +187,10 @@ func (parser *Parser) ParseDefinitions() {
var properties map[string]spec.Schema
properties = make(map[string]spec.Schema)

switch typeSpec.Type.(type) {
case *ast.StructType:
structDecl := typeSpec.Type.(*ast.StructType)
fields := structDecl.Fields.List

for _, field := range fields {
name := field.Names[0].Name
propName := getPropertyName(field)
properties[name] = spec.Schema{
SchemaProps: spec.SchemaProps{Type: []string{propName}},
}
}
ss := strings.Split(refTypeName, ".")
pkgName := ss[0]

case *ast.ArrayType:
log.Panic("ParseDefinitions not supported 'Array' yet.")
case *ast.InterfaceType:
log.Panic("ParseDefinitions not supported 'Interface' yet.")
case *ast.MapType:
log.Panic("ParseDefinitions not supported 'Map' yet.")
}
parser.parseTypeSpec(pkgName, typeSpec, properties)

parser.swagger.Definitions[refTypeName] = spec.Schema{
SchemaProps: spec.SchemaProps{
Expand All @@ -218,15 +202,63 @@ func (parser *Parser) ParseDefinitions() {
}
}

func (parser *Parser) parseTypeSpec(pkgName string, typeSpec *ast.TypeSpec, properties map[string]spec.Schema) {
switch typeSpec.Type.(type) {
case *ast.StructType:
structDecl := typeSpec.Type.(*ast.StructType)
fields := structDecl.Fields.List

for _, field := range fields {
if field.Names == nil { //anonymous field
parser.parseAnonymousField(pkgName, field, properties)
} else {
name, propName := parser.parseField(field)
properties[name] = spec.Schema{
SchemaProps: spec.SchemaProps{Type: []string{propName}},
}
}
}

case *ast.ArrayType:
log.Panic("ParseDefinitions not supported 'Array' yet.")
case *ast.InterfaceType:
log.Panic("ParseDefinitions not supported 'Interface' yet.")
case *ast.MapType:
log.Panic("ParseDefinitions not supported 'Map' yet.")
}
}

func (parser *Parser) parseAnonymousField(pkgName string, field *ast.Field, properties map[string]spec.Schema) {
if astTypeIdent, ok := field.Type.(*ast.Ident); ok {
findPgkName := pkgName
findBaseTypeName := astTypeIdent.Name
ss := strings.Split(astTypeIdent.Name, ".")
if len(ss) > 1 {
findPgkName = ss[0]
findBaseTypeName = ss[1]
}

baseTypeSpec := parser.TypeDefinitions[findPgkName][findBaseTypeName]
parser.parseTypeSpec(findPgkName, baseTypeSpec, properties)
}
}

func (parser *Parser) parseField(field *ast.Field) (propName, schemaType string) {
return field.Names[0].Name, getPropertyName(field)
}

// GetAllGoFileInfo gets all Go source files information for gived searchDir.
func (parser *Parser) getAllGoFileInfo(searchDir string) {
filepath.Walk(searchDir, func(path string, f os.FileInfo, err error) error {
//exclude vendor folder
if ext := filepath.Ext(path); ext == ".go" && !strings.Contains(string(os.PathSeparator)+path, string(os.PathSeparator)+"vendor"+string(os.PathSeparator)) {
astFile, err := goparser.ParseFile(token.NewFileSet(), path, nil, goparser.ParseComments)
fset := token.NewFileSet() // positions are relative to fset
astFile, err := goparser.ParseFile(fset, path, nil, goparser.ParseComments)

if err != nil {
log.Panicf("ParseFile panic:%+v", err)
}

parser.files[path] = astFile

}
Expand Down
14 changes: 14 additions & 0 deletions parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,20 @@ func TestParseSimpleApi(t *testing.T) {
"type": "array"
}
}
},
"web.RevValue": {
"type": "object",
"properties": {
"Data": {
"type": "integer"
},
"Err": {
"type": "int32"
},
"Status": {
"type": "bool"
}
}
}
}
}`
Expand Down

0 comments on commit 652a19a

Please sign in to comment.