Skip to content

Commit

Permalink
refactor: build spec.Schema; parse object in request (#728)
Browse files Browse the repository at this point in the history
  • Loading branch information
sdghchj committed Jun 8, 2020
1 parent df209af commit 67cb097
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 179 deletions.
14 changes: 9 additions & 5 deletions gen/gen.go
Expand Up @@ -8,7 +8,7 @@ import (
"io"
"log"
"os"
"path"
"path/filepath"
"strings"
"text/template"
"time"
Expand Down Expand Up @@ -95,10 +95,14 @@ func (g *Gen) Build(config *Config) error {
return err
}

packageName := path.Base(config.OutputDir)
docFileName := path.Join(config.OutputDir, "docs.go")
jsonFileName := path.Join(config.OutputDir, "swagger.json")
yamlFileName := path.Join(config.OutputDir, "swagger.yaml")
absOutputDir, err := filepath.Abs(config.OutputDir)
if err != nil {
return err
}
packageName := filepath.Base(absOutputDir)
docFileName := filepath.Join(config.OutputDir, "docs.go")
jsonFileName := filepath.Join(config.OutputDir, "swagger.json")
yamlFileName := filepath.Join(config.OutputDir, "swagger.yaml")

docs, err := os.Create(docFileName)
if err != nil {
Expand Down
41 changes: 20 additions & 21 deletions gen/gen_test.go
Expand Up @@ -4,7 +4,6 @@ import (
"errors"
"os"
"os/exec"
"path"
"path/filepath"
"testing"

Expand All @@ -24,9 +23,9 @@ func TestGen_Build(t *testing.T) {
assert.NoError(t, New().Build(config))

expectedFiles := []string{
path.Join(config.OutputDir, "docs.go"),
path.Join(config.OutputDir, "swagger.json"),
path.Join(config.OutputDir, "swagger.yaml"),
filepath.Join(config.OutputDir, "docs.go"),
filepath.Join(config.OutputDir, "swagger.json"),
filepath.Join(config.OutputDir, "swagger.yaml"),
}
for _, expectedFile := range expectedFiles {
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
Expand All @@ -48,9 +47,9 @@ func TestGen_BuildSnakecase(t *testing.T) {
assert.NoError(t, New().Build(config))

expectedFiles := []string{
path.Join(config.OutputDir, "docs.go"),
path.Join(config.OutputDir, "swagger.json"),
path.Join(config.OutputDir, "swagger.yaml"),
filepath.Join(config.OutputDir, "docs.go"),
filepath.Join(config.OutputDir, "swagger.json"),
filepath.Join(config.OutputDir, "swagger.yaml"),
}
for _, expectedFile := range expectedFiles {
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
Expand All @@ -72,9 +71,9 @@ func TestGen_BuildLowerCamelcase(t *testing.T) {
assert.NoError(t, New().Build(config))

expectedFiles := []string{
path.Join(config.OutputDir, "docs.go"),
path.Join(config.OutputDir, "swagger.json"),
path.Join(config.OutputDir, "swagger.yaml"),
filepath.Join(config.OutputDir, "docs.go"),
filepath.Join(config.OutputDir, "swagger.json"),
filepath.Join(config.OutputDir, "swagger.yaml"),
}
for _, expectedFile := range expectedFiles {
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
Expand Down Expand Up @@ -116,8 +115,8 @@ func TestGen_jsonToYAML(t *testing.T) {
assert.Error(t, gen.Build(config))

expectedFiles := []string{
path.Join(config.OutputDir, "docs.go"),
path.Join(config.OutputDir, "swagger.json"),
filepath.Join(config.OutputDir, "docs.go"),
filepath.Join(config.OutputDir, "swagger.json"),
}
for _, expectedFile := range expectedFiles {
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
Expand Down Expand Up @@ -226,9 +225,9 @@ func TestGen_configWithOutputDir(t *testing.T) {
assert.NoError(t, New().Build(config))

expectedFiles := []string{
path.Join(config.OutputDir, "docs.go"),
path.Join(config.OutputDir, "swagger.json"),
path.Join(config.OutputDir, "swagger.yaml"),
filepath.Join(config.OutputDir, "docs.go"),
filepath.Join(config.OutputDir, "swagger.json"),
filepath.Join(config.OutputDir, "swagger.yaml"),
}
for _, expectedFile := range expectedFiles {
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
Expand Down Expand Up @@ -334,9 +333,9 @@ func TestGen_GeneratedDoc(t *testing.T) {
assert.NoError(t, cmd.Run())

expectedFiles := []string{
path.Join(config.OutputDir, "docs.go"),
path.Join(config.OutputDir, "swagger.json"),
path.Join(config.OutputDir, "swagger.yaml"),
filepath.Join(config.OutputDir, "docs.go"),
filepath.Join(config.OutputDir, "swagger.json"),
filepath.Join(config.OutputDir, "swagger.yaml"),
}
for _, expectedFile := range expectedFiles {
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
Expand All @@ -360,9 +359,9 @@ func TestGen_cgoImports(t *testing.T) {
assert.NoError(t, New().Build(config))

expectedFiles := []string{
path.Join(config.OutputDir, "docs.go"),
path.Join(config.OutputDir, "swagger.json"),
path.Join(config.OutputDir, "swagger.yaml"),
filepath.Join(config.OutputDir, "docs.go"),
filepath.Join(config.OutputDir, "swagger.json"),
filepath.Join(config.OutputDir, "swagger.yaml"),
}
for _, expectedFile := range expectedFiles {
if _, err := os.Stat(expectedFile); os.IsNotExist(err) {
Expand Down
103 changes: 31 additions & 72 deletions operation.go
Expand Up @@ -13,7 +13,6 @@ import (
"strconv"
"strings"

"github.com/go-openapi/jsonreference"
"github.com/go-openapi/spec"
"golang.org/x/tools/go/loader"
)
Expand Down Expand Up @@ -261,19 +260,11 @@ func (operation *Operation) ParseParamComment(commentLine string, astFile *ast.F
return nil
}
case "body":
switch objectType {
case "primitive":
param.Schema.Type = spec.StringOrArray{refType}
case "array":
refType = "[]" + refType
fallthrough
case "object":
schema, err := operation.parseObjectSchema(refType, astFile)
if err != nil {
return err
}
param.Schema = schema
schema, err := operation.parseAPIObjectSchema(objectType, refType, astFile)
if err != nil {
return err
}
param.Schema = schema
default:
return fmt.Errorf("%s is not supported paramType", paramType)
}
Expand Down Expand Up @@ -631,46 +622,36 @@ var combinedPattern = regexp.MustCompile(`^([\w\-\.\/\[\]]+)\{(.*)\}$`)
func (operation *Operation) parseObjectSchema(refType string, astFile *ast.File) (*spec.Schema, error) {
switch {
case refType == "interface{}":
return &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{"object"}}}, nil
return PrimitiveSchema("object"), nil
case IsGolangPrimitiveType(refType):
refType = TransToValidSchemeType(refType)
return &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{refType}}}, nil
return PrimitiveSchema(refType), nil
case IsPrimitiveType(refType):
return &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{refType}}}, nil
return PrimitiveSchema(refType), nil
case strings.HasPrefix(refType, "[]"):
schema, err := operation.parseObjectSchema(refType[2:], astFile)
if err != nil {
return nil, err
}
return &spec.Schema{SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{Schema: schema}},
}, nil
return spec.ArrayProperty(schema), nil
case strings.HasPrefix(refType, "map["):
//ignore key type
idx := strings.Index(refType, "]")
if idx < 0 {
return nil, fmt.Errorf("invalid type: %s", refType)
}
refType = refType[idx+1:]
var valueSchema spec.SchemaOrBool
if refType == "interface{}" {
valueSchema.Allows = true
} else {
schema, err := operation.parseObjectSchema(refType, astFile)
if err != nil {
return &spec.Schema{}, err
}
valueSchema.Schema = schema
return spec.MapProperty(nil), nil

}
return &spec.Schema{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
AdditionalProperties: &valueSchema,
},
}, nil
schema, err := operation.parseObjectSchema(refType, astFile)
if err != nil {
return nil, err
}
return spec.MapProperty(schema), nil
case strings.Contains(refType, "{"):
return operation.parseResponseCombinedObjectSchema(refType, astFile)
return operation.parseCombinedObjectSchema(refType, astFile)
default:
if operation.parser != nil { // checking refType has existing in 'TypeDefinitions'
refNewType, typeSpec, err := operation.registerSchemaType(refType, astFile)
Expand All @@ -679,13 +660,12 @@ func (operation *Operation) parseObjectSchema(refType string, astFile *ast.File)
}
refType = TypeDocName(refNewType, typeSpec)
}
return &spec.Schema{SchemaProps: spec.SchemaProps{Ref: spec.Ref{
Ref: jsonreference.MustCreateRef("#/definitions/" + refType),
}}}, nil

return RefSchema(refType), nil
}
}

func (operation *Operation) parseResponseCombinedObjectSchema(refType string, astFile *ast.File) (*spec.Schema, error) {
func (operation *Operation) parseCombinedObjectSchema(refType string, astFile *ast.File) (*spec.Schema, error) {
matches := combinedPattern.FindStringSubmatch(refType)
if len(matches) != 3 {
return nil, fmt.Errorf("invalid type: %s", refType)
Expand Down Expand Up @@ -714,44 +694,26 @@ func (operation *Operation) parseResponseCombinedObjectSchema(refType string, as
props := map[string]spec.Schema{}
for _, field := range fields {
if matches := strings.SplitN(field, "=", 2); len(matches) == 2 {
if strings.HasPrefix(matches[1], "[]") {
itemSchema, err := operation.parseObjectSchema(matches[1][2:], astFile)
if err != nil {
return nil, err
}
props[matches[0]] = spec.Schema{SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{Schema: itemSchema}},
}
} else {
schema, err := operation.parseObjectSchema(matches[1], astFile)
if err != nil {
return nil, err
}
props[matches[0]] = *schema
schema, err := operation.parseObjectSchema(matches[1], astFile)
if err != nil {
return nil, err
}
props[matches[0]] = *schema
}
}

if len(props) == 0 {
return schema, nil
}
return &spec.Schema{
return spec.ComposedSchema(*schema, spec.Schema{
SchemaProps: spec.SchemaProps{
AllOf: []spec.Schema{
*schema,
{
SchemaProps: spec.SchemaProps{
Type: []string{"object"},
Properties: props,
},
},
},
Type: []string{"object"},
Properties: props,
},
}, nil
}), nil
}

func (operation *Operation) parseResponseSchema(schemaType, refType string, astFile *ast.File) (*spec.Schema, error) {
func (operation *Operation) parseAPIObjectSchema(schemaType, refType string, astFile *ast.File) (*spec.Schema, error) {
switch schemaType {
case "object":
if !strings.HasPrefix(refType, "[]") {
Expand All @@ -764,12 +726,9 @@ func (operation *Operation) parseResponseSchema(schemaType, refType string, astF
if err != nil {
return nil, err
}
return &spec.Schema{SchemaProps: spec.SchemaProps{
Type: []string{"array"},
Items: &spec.SchemaOrArray{Schema: schema}},
}, nil
return spec.ArrayProperty(schema), nil
default:
return &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{schemaType}}}, nil
return PrimitiveSchema(schemaType), nil
}
}

Expand All @@ -794,7 +753,7 @@ func (operation *Operation) ParseResponseComment(commentLine string, astFile *as

schemaType := strings.Trim(matches[2], "{}")
refType := matches[3]
schema, err := operation.parseResponseSchema(schemaType, refType, astFile)
schema, err := operation.parseAPIObjectSchema(schemaType, refType, astFile)
if err != nil {
return err
}
Expand Down

0 comments on commit 67cb097

Please sign in to comment.