Skip to content

Commit

Permalink
Merge branch 'master' into fixed-query-order
Browse files Browse the repository at this point in the history
  • Loading branch information
sdghchj committed May 29, 2020
2 parents 16c21c4 + 51088c1 commit 59734e3
Show file tree
Hide file tree
Showing 12 changed files with 895 additions and 51 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Expand Up @@ -3,7 +3,7 @@ jobs:
test:
strategy:
matrix:
go: [ '1.11.x', '1.12.x' ]
go: [ '1.13.x', '1.14.x' ]
platform: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.platform }}
steps:
Expand Down Expand Up @@ -37,4 +37,4 @@ jobs:
working-directory: ./src/github.com/${{ github.repository }}
run: make test
env:
GOPATH: ${{ runner.workspace }}
GOPATH: ${{ runner.workspace }}
2 changes: 0 additions & 2 deletions .travis.yml
@@ -1,8 +1,6 @@
language: go

go:
- 1.11.x
- 1.12.x
- 1.13.x
- 1.14.x

Expand Down
3 changes: 3 additions & 0 deletions README.md
@@ -1,5 +1,7 @@
# swag

🌍 *[English](README.md)[简体中文](README_zh-CN.md)*

<img align="right" width="180px" src="https://raw.githubusercontent.com/swaggo/swag/master/assets/swaggo.png">

[![Travis Status](https://img.shields.io/travis/swaggo/swag/master.svg)](https://travis-ci.org/swaggo/swag)
Expand Down Expand Up @@ -456,6 +458,7 @@ type Foo struct {

Field Name | Type | Description
---|:---:|---
<a name="validate"></a>validate | `string` | Determines the validation for the parameter. Possible values are: `required`.
<a name="parameterDefault"></a>default | * | Declares the value of the parameter that the server will use if none is provided, for example a "count" to control the number of results per page might default to 100 if not supplied by the client in the request. (Note: "default" has no meaning for required parameters.) See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-6.2. Unlike JSON Schema this value MUST conform to the defined [`type`](#parameterType) for this parameter.
<a name="parameterMaximum"></a>maximum | `number` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.2.
<a name="parameterMinimum"></a>minimum | `number` | See https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.1.3.
Expand Down
740 changes: 740 additions & 0 deletions README_zh-CN.md

Large diffs are not rendered by default.

35 changes: 20 additions & 15 deletions cmd/swag/main.go
Expand Up @@ -24,28 +24,32 @@ const (

var initFlags = []cli.Flag{
&cli.StringFlag{
Name: generalInfoFlag + ", g",
Value: "main.go",
Usage: "Go file path in which 'swagger general API Info' is written",
Name: generalInfoFlag,
Aliases: []string{"g"},
Value: "main.go",
Usage: "Go file path in which 'swagger general API Info' is written",
},
&cli.StringFlag{
Name: searchDirFlag + ", d",
Value: "./",
Usage: "Directory you want to parse",
Name: searchDirFlag,
Aliases: []string{"d"},
Value: "./",
Usage: "Directory you want to parse",
},
&cli.StringFlag{
Name: excludeFlag,
Usage: "exclude directories and files when searching, comma separated",
},
&cli.StringFlag{
Name: propertyStrategyFlag + ", p",
Value: "camelcase",
Usage: "Property Naming Strategy like snakecase,camelcase,pascalcase",
Name: propertyStrategyFlag,
Aliases: []string{"p"},
Value: "camelcase",
Usage: "Property Naming Strategy like snakecase,camelcase,pascalcase",
},
&cli.StringFlag{
Name: outputFlag + ", o",
Value: "./docs",
Usage: "Output directory for all the generated files(swagger.json, swagger.yaml and doc.go)",
Name: outputFlag,
Aliases: []string{"o"},
Value: "./docs",
Usage: "Output directory for all the generated files(swagger.json, swagger.yaml and doc.go)",
},
&cli.BoolFlag{
Name: parseVendorFlag,
Expand All @@ -56,9 +60,10 @@ var initFlags = []cli.Flag{
Usage: "Parse go files in outside dependency folder, disabled by default",
},
&cli.StringFlag{
Name: markdownFilesFlag + ", md",
Value: "",
Usage: "Parse folder containing markdown files to use as description, disabled by default",
Name: markdownFilesFlag,
Aliases: []string{"md"},
Value: "",
Usage: "Parse folder containing markdown files to use as description, disabled by default",
},
&cli.BoolFlag{
Name: "generatedTime",
Expand Down
43 changes: 12 additions & 31 deletions operation.go
Expand Up @@ -265,33 +265,14 @@ func (operation *Operation) ParseParamComment(commentLine string, astFile *ast.F
case "primitive":
param.Schema.Type = spec.StringOrArray{refType}
case "array":
param.Schema.Type = spec.StringOrArray{objectType}
param.Schema.Items = &spec.SchemaOrArray{
Schema: &spec.Schema{
SchemaProps: spec.SchemaProps{},
},
}
// Array of Primitive or Object
if IsPrimitiveType(refType) {
param.Schema.Items.Schema.Type = spec.StringOrArray{refType}
} else {
refType, typeSpec, err := operation.registerSchemaType(refType, astFile)
if err != nil {
return err
}
param.Schema.Items.Schema.Ref = spec.Ref{
Ref: jsonreference.MustCreateRef("#/definitions/" + TypeDocName(refType, typeSpec)),
}
}
refType = "[]" + refType
fallthrough
case "object":
refType, typeSpec, err := operation.registerSchemaType(refType, astFile)
schema, err := operation.parseObjectSchema(refType, astFile)
if err != nil {
return err
}
param.Schema.Type = []string{}
param.Schema.Ref = spec.Ref{
Ref: jsonreference.MustCreateRef("#/definitions/" + TypeDocName(refType, typeSpec)),
}
param.Schema = schema
}
default:
return fmt.Errorf("%s is not supported paramType", paramType)
Expand Down Expand Up @@ -647,7 +628,7 @@ var responsePattern = regexp.MustCompile(`([\d]+)[\s]+([\w\{\}]+)[\s]+([\w\-\.\/
//RepsonseType{data1=Type1,data2=Type2}
var combinedPattern = regexp.MustCompile(`^([\w\-\.\/\[\]]+)\{(.*)\}$`)

func (operation *Operation) parseResponseObjectSchema(refType string, astFile *ast.File) (*spec.Schema, error) {
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
Expand All @@ -657,7 +638,7 @@ func (operation *Operation) parseResponseObjectSchema(refType string, astFile *a
case IsPrimitiveType(refType):
return &spec.Schema{SchemaProps: spec.SchemaProps{Type: []string{refType}}}, nil
case strings.HasPrefix(refType, "[]"):
schema, err := operation.parseResponseObjectSchema(refType[2:], astFile)
schema, err := operation.parseObjectSchema(refType[2:], astFile)
if err != nil {
return nil, err
}
Expand All @@ -676,7 +657,7 @@ func (operation *Operation) parseResponseObjectSchema(refType string, astFile *a
if refType == "interface{}" {
valueSchema.Allows = true
} else {
schema, err := operation.parseResponseObjectSchema(refType, astFile)
schema, err := operation.parseObjectSchema(refType, astFile)
if err != nil {
return &spec.Schema{}, err
}
Expand Down Expand Up @@ -710,7 +691,7 @@ func (operation *Operation) parseResponseCombinedObjectSchema(refType string, as
return nil, fmt.Errorf("invalid type: %s", refType)
}
refType = matches[1]
schema, err := operation.parseResponseObjectSchema(refType, astFile)
schema, err := operation.parseObjectSchema(refType, astFile)
if err != nil {
return nil, err
}
Expand All @@ -734,7 +715,7 @@ func (operation *Operation) parseResponseCombinedObjectSchema(refType string, as
for _, field := range fields {
if matches := strings.SplitN(field, "=", 2); len(matches) == 2 {
if strings.HasPrefix(matches[1], "[]") {
itemSchema, err := operation.parseResponseObjectSchema(matches[1][2:], astFile)
itemSchema, err := operation.parseObjectSchema(matches[1][2:], astFile)
if err != nil {
return nil, err
}
Expand All @@ -743,7 +724,7 @@ func (operation *Operation) parseResponseCombinedObjectSchema(refType string, as
Items: &spec.SchemaOrArray{Schema: itemSchema}},
}
} else {
schema, err := operation.parseResponseObjectSchema(matches[1], astFile)
schema, err := operation.parseObjectSchema(matches[1], astFile)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -774,12 +755,12 @@ func (operation *Operation) parseResponseSchema(schemaType, refType string, astF
switch schemaType {
case "object":
if !strings.HasPrefix(refType, "[]") {
return operation.parseResponseObjectSchema(refType, astFile)
return operation.parseObjectSchema(refType, astFile)
}
refType = refType[2:]
fallthrough
case "array":
schema, err := operation.parseResponseObjectSchema(refType, astFile)
schema, err := operation.parseObjectSchema(refType, astFile)
if err != nil {
return nil, err
}
Expand Down
97 changes: 97 additions & 0 deletions operation_test.go
Expand Up @@ -938,6 +938,53 @@ func TestParseParamCommentByBodyType(t *testing.T) {
assert.Equal(t, expected, string(b))
}

func TestParseParamCommentByBodyTypeWithDeepNestedFields(t *testing.T) {
comment := `@Param body body model.CommonHeader{data=string,data2=int} true "test deep"`
operation := NewOperation()
operation.parser = New()

operation.parser.TypeDefinitions["model"] = make(map[string]*ast.TypeSpec)
operation.parser.TypeDefinitions["model"]["CommonHeader"] = &ast.TypeSpec{}

err := operation.ParseComment(comment, nil)
assert.NoError(t, err)
assert.Len(t, operation.Parameters, 1)
assert.Equal(t, "test deep", operation.Parameters[0].Description)
assert.True(t, operation.Parameters[0].Required)

b, err := json.MarshalIndent(operation, "", " ")
assert.NoError(t, err)
expected := `{
"parameters": [
{
"description": "test deep",
"name": "body",
"in": "body",
"required": true,
"schema": {
"allOf": [
{
"$ref": "#/definitions/model.CommonHeader"
},
{
"type": "object",
"properties": {
"data": {
"type": "string"
},
"data2": {
"type": "integer"
}
}
}
]
}
}
]
}`
assert.Equal(t, expected, string(b))
}

func TestParseParamCommentByBodyTypeArrayOfPrimitiveGo(t *testing.T) {
comment := `@Param some_id body []int true "Some ID"`
operation := NewOperation()
Expand Down Expand Up @@ -965,6 +1012,56 @@ func TestParseParamCommentByBodyTypeArrayOfPrimitiveGo(t *testing.T) {
assert.Equal(t, expected, string(b))
}

func TestParseParamCommentByBodyTypeArrayOfPrimitiveGoWithDeepNestedFields(t *testing.T) {
comment := `@Param body body []model.CommonHeader{data=string,data2=int} true "test deep"`
operation := NewOperation()
operation.parser = New()

operation.parser.TypeDefinitions["model"] = make(map[string]*ast.TypeSpec)
operation.parser.TypeDefinitions["model"]["CommonHeader"] = &ast.TypeSpec{}

err := operation.ParseComment(comment, nil)
assert.NoError(t, err)
assert.Len(t, operation.Parameters, 1)
assert.Equal(t, "test deep", operation.Parameters[0].Description)
assert.True(t, operation.Parameters[0].Required)

b, err := json.MarshalIndent(operation, "", " ")
assert.NoError(t, err)
expected := `{
"parameters": [
{
"description": "test deep",
"name": "body",
"in": "body",
"required": true,
"schema": {
"type": "array",
"items": {
"allOf": [
{
"$ref": "#/definitions/model.CommonHeader"
},
{
"type": "object",
"properties": {
"data": {
"type": "string"
},
"data2": {
"type": "integer"
}
}
}
]
}
}
}
]
}`
assert.Equal(t, expected, string(b))
}

func TestParseParamCommentByBodyTypeErr(t *testing.T) {
comment := `@Param some_id body model.OrderRow true "Some ID"`
operation := NewOperation()
Expand Down
11 changes: 11 additions & 0 deletions parser.go
Expand Up @@ -859,6 +859,17 @@ func (parser *Parser) parseStructField(pkgName string, field *ast.Field) (map[st
}

typeSpec := parser.TypeDefinitions[pkgName][typeName]
if typeSpec == nil {
// Check if the pkg name is an alias and try to define type spec using real package name
if aliases, ok := parser.ImportAliases[pkgName]; ok {
for alias := range aliases {
typeSpec = parser.TypeDefinitions[alias][typeName]
if typeSpec != nil {
break
}
}
}
}
if typeSpec != nil {
schema, err := parser.parseTypeExpr(pkgName, typeName, typeSpec.Type)
if err != nil {
Expand Down
2 changes: 2 additions & 0 deletions testdata/alias_import/data/applicationresponse.go
Expand Up @@ -5,6 +5,8 @@ import (
)

type ApplicationResponse struct {
typesapplication.TypeToEmbed

Application typesapplication.Application `json:"application"`
ApplicationArray []typesapplication.Application `json:"application_array"`
ApplicationTime typesapplication.DateOnly `json:"application_time"`
Expand Down
3 changes: 3 additions & 0 deletions testdata/alias_import/expected.json
Expand Up @@ -56,6 +56,9 @@
},
"application_time": {
"type": "string"
},
"embedded": {
"type": "string"
}
}
},
Expand Down
4 changes: 4 additions & 0 deletions testdata/alias_import/types/application.go
Expand Up @@ -7,3 +7,7 @@ type Application struct {
}

type DateOnly time.Time

type TypeToEmbed struct {
Embedded string
}
2 changes: 1 addition & 1 deletion version.go
@@ -1,4 +1,4 @@
package swag

// Version of swag
const Version = "v1.6.5"
const Version = "v1.6.6"

0 comments on commit 59734e3

Please sign in to comment.