Upgrade dependencies

This commit is contained in:
Ingo Oppermann
2022-09-08 15:39:56 +02:00
parent f1d71c202b
commit c522de043d
425 changed files with 21220 additions and 23815 deletions

View File

@@ -188,7 +188,6 @@ const indexTemplate = `<!-- HTML for static distribution bundle build -->
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />

12
vendor/github.com/swaggo/files/filebox.go generated vendored Normal file
View File

@@ -0,0 +1,12 @@
package swaggerFiles
import (
"golang.org/x/net/webdav"
)
func NewHandler() *webdav.Handler {
return &webdav.Handler{
FileSystem: FS,
LockSystem: webdav.NewMemLS(),
}
}

View File

@@ -10,6 +10,8 @@ build:
ignore:
- goos: darwin
goarch: arm64
env:
- CGO_ENABLED=0
archives:
-
replacements:

View File

@@ -29,6 +29,7 @@ Swag converts Go annotations to Swagger Documentation 2.0. We've created a varie
- [Examples](#examples)
- [Descriptions over multiple lines](#descriptions-over-multiple-lines)
- [User defined structure with an array type](#user-defined-structure-with-an-array-type)
- [Function scoped struct declaration](#function-scoped-struct-declaration)
- [Model composition in response](#model-composition-in-response)
- [Add a headers in response](#add-a-headers-in-response)
- [Use multiple path params](#use-multiple-path-params)
@@ -99,6 +100,7 @@ OPTIONS:
--codeExampleFiles value, --cef value Parse folder containing code example files to use for the x-codeSamples extension, disabled by default
--parseInternal Parse go files in internal packages, disabled by default (default: false)
--generatedTime Generate timestamp at the top of docs.go, disabled by default (default: false)
--requiredByDefault Set validation required for all fields by default (default: false)
--parseDepth value Dependency parse depth (default: 100)
--instanceName value This parameter can be used to name different swagger document instances. It is optional.
--overridesFile value File to read global type overrides from. (default: ".swaggo")
@@ -127,8 +129,10 @@ OPTIONS:
- [echo](http://github.com/swaggo/echo-swagger)
- [buffalo](https://github.com/swaggo/buffalo-swagger)
- [net/http](https://github.com/swaggo/http-swagger)
- [gorilla/mux](https://github.com/swaggo/http-swagger)
- [go-chi/chi](https://github.com/swaggo/http-swagger)
- [flamingo](https://github.com/i-love-flamingo/swagger)
- [fiber](https://github.com/arsmn/fiber-swagger)
- [fiber](https://github.com/gofiber/swagger)
- [atreugo](https://github.com/Nerzal/atreugo-swagger)
## How to use it with Gin
@@ -488,7 +492,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="validate"></a>validate | `string` | Determines the validation for the parameter. Possible values are: `required,optional`.
<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.
@@ -537,6 +541,30 @@ type Account struct {
}
```
### Function scoped struct declaration
You can declare your request response structs inside a function body.
You must have to follow the naming convention `<package-name>.<function-name>.<struct-name> `.
```go
package main
// @Param request body main.MyHandler.request true "query params"
// @Success 200 {object} main.MyHandler.response
// @Router /test [post]
func MyHandler() {
type request struct {
RequestField string
}
type response struct {
ResponseField string
}
}
```
### Model composition in response
```go
// JSONResult's data field will be overridden by the specific type proto.Order

View File

@@ -123,6 +123,12 @@ OPTIONS:
- [echo](http://github.com/swaggo/echo-swagger)
- [buffalo](https://github.com/swaggo/buffalo-swagger)
- [net/http](https://github.com/swaggo/http-swagger)
- [net/http](https://github.com/swaggo/http-swagger)
- [gorilla/mux](https://github.com/swaggo/http-swagger)
- [go-chi/chi](https://github.com/swaggo/http-swagger)
- [flamingo](https://github.com/i-love-flamingo/swagger)
- [fiber](https://github.com/gofiber/swagger)
- [atreugo](https://github.com/Nerzal/atreugo-swagger)
## 如何与Gin集成

View File

@@ -18,6 +18,7 @@ var _ FieldParser = &tagBaseFieldParser{p: nil, field: nil, tag: ""}
const (
requiredLabel = "required"
optionalLabel = "optional"
swaggerTypeTag = "swaggertype"
swaggerIgnoreTag = "swaggerignore"
)
@@ -472,8 +473,11 @@ func (ps *tagBaseFieldParser) IsRequired() (bool, error) {
bindingTag := ps.tag.Get(bindingTag)
if bindingTag != "" {
for _, val := range strings.Split(bindingTag, ",") {
if val == requiredLabel {
switch val {
case requiredLabel:
return true, nil
case optionalLabel:
return false, nil
}
}
}
@@ -481,13 +485,16 @@ func (ps *tagBaseFieldParser) IsRequired() (bool, error) {
validateTag := ps.tag.Get(validateTag)
if validateTag != "" {
for _, val := range strings.Split(validateTag, ",") {
if val == requiredLabel {
switch val {
case requiredLabel:
return true, nil
case optionalLabel:
return false, nil
}
}
}
return false, nil
return ps.p.RequiredByDefault, nil
}
func parseValidTags(validTag string, sf *structField) {

View File

@@ -78,7 +78,7 @@ func formatComments(fileName string, contents []byte, formattedComments []byte,
}
func formatFuncDoc(commentList []*ast.Comment, formattedComments io.Writer, oldCommentsMap map[string]string) {
w := tabwriter.NewWriter(formattedComments, 0, 0, 2, ' ', 0)
w := tabwriter.NewWriter(formattedComments, 0, 0, 1, ' ', 0)
for _, comment := range commentList {
text := comment.Text

View File

@@ -4,10 +4,39 @@
package swag
import (
"errors"
"fmt"
"go/ast"
"strings"
)
var genericsDefinitions = map[*TypeSpecDef]map[string]*TypeSpecDef{}
type genericTypeSpec struct {
ArrayDepth int
TypeSpec *TypeSpecDef
Name string
}
func (s *genericTypeSpec) Type() ast.Expr {
if s.TypeSpec != nil {
return &ast.SelectorExpr{
X: &ast.Ident{Name: ""},
Sel: &ast.Ident{Name: s.Name},
}
}
return &ast.Ident{Name: s.Name}
}
func (s *genericTypeSpec) TypeDocName() string {
if s.TypeSpec != nil {
return strings.Replace(TypeDocName(s.TypeSpec.FullName(), s.TypeSpec.TypeSpec), "-", "_", -1)
}
return s.Name
}
func typeSpecFullName(typeSpecDef *TypeSpecDef) string {
fullName := typeSpecDef.FullName()
@@ -26,29 +55,38 @@ func typeSpecFullName(typeSpecDef *TypeSpecDef) string {
return fullName
}
func (pkgDefs *PackagesDefinitions) parametrizeStruct(original *TypeSpecDef, fullGenericForm string) *TypeSpecDef {
genericParams := strings.Split(strings.TrimRight(fullGenericForm, "]"), "[")
if len(genericParams) == 1 {
func (pkgDefs *PackagesDefinitions) parametrizeStruct(original *TypeSpecDef, fullGenericForm string, parseDependency bool) *TypeSpecDef {
if spec, ok := genericsDefinitions[original][fullGenericForm]; ok {
return spec
}
pkgName := strings.Split(fullGenericForm, ".")[0]
genericTypeName, genericParams := splitStructName(fullGenericForm)
if genericParams == nil {
return nil
}
genericParams = strings.Split(genericParams[1], ",")
for i, p := range genericParams {
genericParams[i] = strings.TrimSpace(p)
}
genericParamTypeDefs := map[string]*TypeSpecDef{}
genericParamTypeDefs := map[string]*genericTypeSpec{}
if len(genericParams) != len(original.TypeSpec.TypeParams.List) {
return nil
}
for i, genericParam := range genericParams {
tdef, ok := pkgDefs.uniqueDefinitions[genericParam]
if !ok {
return nil
arrayDepth := 0
for {
if len(genericParam) <= 2 || genericParam[:2] != "[]" {
break
}
genericParam = genericParam[2:]
arrayDepth++
}
genericParamTypeDefs[original.TypeSpec.TypeParams.List[i].Names[0].Name] = tdef
tdef := pkgDefs.FindTypeSpec(genericParam, original.File, parseDependency)
genericParamTypeDefs[original.TypeSpec.TypeParams.List[i].Names[0].Name] = &genericTypeSpec{
ArrayDepth: arrayDepth,
TypeSpec: tdef,
Name: genericParam,
}
}
parametrizedTypeSpec := &TypeSpecDef{
@@ -66,16 +104,34 @@ func (pkgDefs *PackagesDefinitions) parametrizeStruct(original *TypeSpecDef, ful
Obj: original.TypeSpec.Name.Obj,
}
genNameParts := strings.Split(fullGenericForm, "[")
if strings.Contains(genNameParts[0], ".") {
genNameParts[0] = strings.Split(genNameParts[0], ".")[1]
if strings.Contains(genericTypeName, ".") {
genericTypeName = strings.Split(genericTypeName, ".")[1]
}
ident.Name = genNameParts[0] + "-" + strings.Replace(strings.Join(genericParams, "-"), ".", "_", -1)
ident.Name = strings.Replace(strings.Replace(ident.Name, "\t", "", -1), " ", "", -1)
var typeName = []string{TypeDocName(fullTypeName(pkgName, genericTypeName), parametrizedTypeSpec.TypeSpec)}
for _, def := range original.TypeSpec.TypeParams.List {
if specDef, ok := genericParamTypeDefs[def.Names[0].Name]; ok {
var prefix = ""
if specDef.ArrayDepth > 0 {
prefix = "array_"
if specDef.ArrayDepth > 1 {
prefix = fmt.Sprintf("array%d_", specDef.ArrayDepth)
}
}
typeName = append(typeName, prefix+specDef.TypeDocName())
}
}
ident.Name = strings.Join(typeName, "-")
ident.Name = strings.Replace(ident.Name, ".", "_", -1)
pkgNamePrefix := pkgName + "_"
if strings.HasPrefix(ident.Name, pkgNamePrefix) {
ident.Name = fullTypeName(pkgName, ident.Name[len(pkgNamePrefix):])
}
ident.Name = string(IgnoreNameOverridePrefix) + ident.Name
parametrizedTypeSpec.TypeSpec.Name = ident
origStructType := original.TypeSpec.Type.(*ast.StructType)
newStructTypeDef := &ast.StructType{
@@ -94,16 +150,153 @@ func (pkgDefs *PackagesDefinitions) parametrizeStruct(original *TypeSpecDef, ful
Tag: field.Tag,
Comment: field.Comment,
}
if genTypeSpec, ok := genericParamTypeDefs[field.Type.(*ast.Ident).Name]; ok {
newField.Type = genTypeSpec.TypeSpec.Type
} else {
newField.Type = field.Type
}
newField.Type = resolveType(field.Type, field, genericParamTypeDefs)
newStructTypeDef.Fields.List = append(newStructTypeDef.Fields.List, newField)
}
parametrizedTypeSpec.TypeSpec.Type = newStructTypeDef
if genericsDefinitions[original] == nil {
genericsDefinitions[original] = map[string]*TypeSpecDef{}
}
genericsDefinitions[original][fullGenericForm] = parametrizedTypeSpec
return parametrizedTypeSpec
}
// splitStructName splits a generic struct name in his parts
func splitStructName(fullGenericForm string) (string, []string) {
// split only at the first '[' and remove the last ']'
if fullGenericForm[len(fullGenericForm)-1] != ']' {
return "", nil
}
genericParams := strings.SplitN(strings.TrimSpace(fullGenericForm)[:len(fullGenericForm)-1], "[", 2)
if len(genericParams) == 1 {
return "", nil
}
// generic type name
genericTypeName := genericParams[0]
// generic params
insideBrackets := 0
lastParam := ""
params := strings.Split(genericParams[1], ",")
genericParams = []string{}
for _, p := range params {
numOpened := strings.Count(p, "[")
numClosed := strings.Count(p, "]")
if numOpened == numClosed && insideBrackets == 0 {
genericParams = append(genericParams, strings.TrimSpace(p))
continue
}
insideBrackets += numOpened - numClosed
lastParam += p + ","
if insideBrackets == 0 {
genericParams = append(genericParams, strings.TrimSpace(strings.TrimRight(lastParam, ",")))
lastParam = ""
}
}
return genericTypeName, genericParams
}
func resolveType(expr ast.Expr, field *ast.Field, genericParamTypeDefs map[string]*genericTypeSpec) ast.Expr {
switch astExpr := expr.(type) {
case *ast.Ident:
if genTypeSpec, ok := genericParamTypeDefs[astExpr.Name]; ok {
if genTypeSpec.ArrayDepth > 0 {
genTypeSpec.ArrayDepth--
return &ast.ArrayType{Elt: resolveType(expr, field, genericParamTypeDefs)}
}
return genTypeSpec.Type()
}
case *ast.ArrayType:
return &ast.ArrayType{
Elt: resolveType(astExpr.Elt, field, genericParamTypeDefs),
Len: astExpr.Len,
Lbrack: astExpr.Lbrack,
}
}
return field.Type
}
func getGenericFieldType(file *ast.File, field ast.Expr) (string, error) {
switch fieldType := field.(type) {
case *ast.IndexListExpr:
fullName, err := getGenericTypeName(file, fieldType.X)
if err != nil {
return "", err
}
fullName += "["
for _, index := range fieldType.Indices {
var fieldName string
var err error
switch item := index.(type) {
case *ast.ArrayType:
fieldName, err = getFieldType(file, item.Elt)
fieldName = "[]" + fieldName
default:
fieldName, err = getFieldType(file, index)
}
if err != nil {
return "", err
}
fullName += fieldName + ","
}
return strings.TrimRight(fullName, ",") + "]", nil
case *ast.IndexExpr:
x, err := getFieldType(file, fieldType.X)
if err != nil {
return "", err
}
i, err := getFieldType(file, fieldType.Index)
if err != nil {
return "", err
}
packageName := ""
if !strings.Contains(x, ".") {
if file.Name == nil {
return "", errors.New("file name is nil")
}
packageName, _ = getFieldType(file, file.Name)
}
return strings.TrimLeft(fmt.Sprintf("%s.%s[%s]", packageName, x, i), "."), nil
}
return "", fmt.Errorf("unknown field type %#v", field)
}
func getGenericTypeName(file *ast.File, field ast.Expr) (string, error) {
switch indexType := field.(type) {
case *ast.Ident:
spec := &TypeSpecDef{
File: file,
TypeSpec: indexType.Obj.Decl.(*ast.TypeSpec),
PkgPath: file.Name.Name,
}
return spec.FullName(), nil
case *ast.ArrayType:
spec := &TypeSpecDef{
File: file,
TypeSpec: indexType.Elt.(*ast.Ident).Obj.Decl.(*ast.TypeSpec),
PkgPath: file.Name.Name,
}
return spec.FullName(), nil
case *ast.SelectorExpr:
return fmt.Sprintf("%s.%s", indexType.X.(*ast.Ident).Name, indexType.Sel.Name), nil
}
return "", fmt.Errorf("unknown type %#v", field)
}

View File

@@ -3,10 +3,19 @@
package swag
import (
"fmt"
"go/ast"
)
func typeSpecFullName(typeSpecDef *TypeSpecDef) string {
return typeSpecDef.FullName()
}
func (pkgDefs *PackagesDefinitions) parametrizeStruct(original *TypeSpecDef, fullGenericForm string) *TypeSpecDef {
func (pkgDefs *PackagesDefinitions) parametrizeStruct(original *TypeSpecDef, fullGenericForm string, parseDependency bool) *TypeSpecDef {
return original
}
func getGenericFieldType(file *ast.File, field ast.Expr) (string, error) {
return "", fmt.Errorf("unknown field type %#v", field)
}

View File

@@ -213,7 +213,7 @@ func (operation *Operation) ParseMetadata(attribute, lowerAttribute, lineRemaind
return nil
}
var paramPattern = regexp.MustCompile(`(\S+)\s+(\w+)\s+([\S.]+)\s+(\w+)\s+"([^"]+)"`)
var paramPattern = regexp.MustCompile(`(\S+)\s+(\w+)\s+([\S. ]+?)\s+(\w+)\s+"([^"]+)"`)
func findInSlice(arr []string, target string) bool {
for _, str := range arr {
@@ -818,7 +818,7 @@ func findTypeDef(importPath, typeName string) (*ast.TypeSpec, error) {
return nil, fmt.Errorf("type spec not found")
}
var responsePattern = regexp.MustCompile(`^([\w,]+)\s+([\w{}]+)\s+([\w\-.\\{}=,\[\]]+)[^"]*(.*)?`)
var responsePattern = regexp.MustCompile(`^([\w,]+)\s+([\w{}]+)\s+([\w\-.\\{}=,\[\s\]]+)\s*(".*)?`)
// ResponseType{data1=Type1,data2=Type2}.
var combinedPattern = regexp.MustCompile(`^([\w\-./\[\]]+){(.*)}$`)
@@ -978,7 +978,7 @@ func (operation *Operation) ParseResponseComment(commentLine string, astFile *as
description := strings.Trim(matches[4], "\"")
schema, err := operation.parseAPIObjectSchema(commentLine, strings.Trim(matches[2], "{}"), matches[3], astFile)
schema, err := operation.parseAPIObjectSchema(commentLine, strings.Trim(matches[2], "{}"), strings.TrimSpace(matches[3]), astFile)
if err != nil {
return err
}
@@ -1043,7 +1043,7 @@ func (operation *Operation) ParseResponseHeaderComment(commentLine string, _ *as
header := newHeaderSpec(strings.Trim(matches[2], "{}"), strings.Trim(matches[4], "\""))
headerKey := matches[3]
headerKey := strings.TrimSpace(matches[3])
if strings.EqualFold(matches[1], "all") {
if operation.Responses.Default != nil {
@@ -1130,7 +1130,7 @@ func (operation *Operation) ParseEmptyResponseOnly(commentLine string) error {
return fmt.Errorf("can not parse response comment \"%s\"", commentLine)
}
operation.AddResponse(code, spec.NewResponse())
operation.AddResponse(code, spec.NewResponse().WithDescription(http.StatusText(code)))
}
return nil

View File

@@ -107,6 +107,7 @@ func (pkgDefs *PackagesDefinitions) ParseTypes() (map[*TypeSpecDef]*Schema, erro
parsedSchemas := make(map[*TypeSpecDef]*Schema)
for astFile, info := range pkgDefs.files {
pkgDefs.parseTypesFromFile(astFile, info.PackagePath, parsedSchemas)
pkgDefs.parseFunctionScopedTypesFromFile(astFile, info.PackagePath, parsedSchemas)
}
return parsedSchemas, nil
}
@@ -161,6 +162,64 @@ func (pkgDefs *PackagesDefinitions) parseTypesFromFile(astFile *ast.File, packag
}
}
func (pkgDefs *PackagesDefinitions) parseFunctionScopedTypesFromFile(astFile *ast.File, packagePath string, parsedSchemas map[*TypeSpecDef]*Schema) {
for _, astDeclaration := range astFile.Decls {
if funcDeclaration, ok := astDeclaration.(*ast.FuncDecl); ok {
for _, stmt := range funcDeclaration.Body.List {
if declStmt, ok := (stmt).(*ast.DeclStmt); ok {
if genDecl, ok := (declStmt.Decl).(*ast.GenDecl); ok && genDecl.Tok == token.TYPE {
for _, astSpec := range genDecl.Specs {
if typeSpec, ok := astSpec.(*ast.TypeSpec); ok {
typeSpecDef := &TypeSpecDef{
PkgPath: packagePath,
File: astFile,
TypeSpec: typeSpec,
ParentSpec: astDeclaration,
}
if idt, ok := typeSpec.Type.(*ast.Ident); ok && IsGolangPrimitiveType(idt.Name) && parsedSchemas != nil {
parsedSchemas[typeSpecDef] = &Schema{
PkgPath: typeSpecDef.PkgPath,
Name: astFile.Name.Name,
Schema: PrimitiveSchema(TransToValidSchemeType(idt.Name)),
}
}
if pkgDefs.uniqueDefinitions == nil {
pkgDefs.uniqueDefinitions = make(map[string]*TypeSpecDef)
}
fullName := typeSpecFullName(typeSpecDef)
anotherTypeDef, ok := pkgDefs.uniqueDefinitions[fullName]
if ok {
if typeSpecDef.PkgPath == anotherTypeDef.PkgPath {
continue
} else {
delete(pkgDefs.uniqueDefinitions, fullName)
}
} else {
pkgDefs.uniqueDefinitions[fullName] = typeSpecDef
}
if pkgDefs.packages[typeSpecDef.PkgPath] == nil {
pkgDefs.packages[typeSpecDef.PkgPath] = &PackageDefinitions{
Name: astFile.Name.Name,
TypeDefinitions: map[string]*TypeSpecDef{fullName: typeSpecDef},
}
} else if _, ok = pkgDefs.packages[typeSpecDef.PkgPath].TypeDefinitions[fullName]; !ok {
pkgDefs.packages[typeSpecDef.PkgPath].TypeDefinitions[fullName] = typeSpecDef
}
}
}
}
}
}
}
}
}
func (pkgDefs *PackagesDefinitions) findTypeSpec(pkgPath string, typeName string) *TypeSpecDef {
if pkgDefs.packages == nil {
return nil
@@ -338,7 +397,7 @@ func (pkgDefs *PackagesDefinitions) FindTypeSpec(typeName string, file *ast.File
}
if strings.Contains(tName, joinedParts) {
if parametrized := pkgDefs.parametrizeStruct(tSpec, typeName); parametrized != nil {
if parametrized := pkgDefs.parametrizeStruct(tSpec, typeName, parseDependency); parametrized != nil {
return parametrized
}
}

View File

@@ -130,6 +130,9 @@ type Parser struct {
// Strict whether swag should error or warn when it detects cases which are most likely user errors
Strict bool
// RequiredByDefault set validation required for all fields by default
RequiredByDefault bool
// structStack stores full names of the structures that were already parsed or are being parsed now
structStack []*TypeSpecDef
@@ -868,6 +871,14 @@ func convertFromSpecificToPrimitive(typeName string) (string, error) {
}
func (parser *Parser) getTypeSchema(typeName string, file *ast.File, ref bool) (*spec.Schema, error) {
if override, ok := parser.Overrides[typeName]; ok {
parser.debug.Printf("Override detected for %s: using %s instead", typeName, override)
typeName = override
}
if IsInterfaceLike(typeName) {
return &spec.Schema{}, nil
}
if IsGolangPrimitiveType(typeName) {
return PrimitiveSchema(TransToValidSchemeType(typeName)), nil
}
@@ -1005,7 +1016,12 @@ func (parser *Parser) isInStructStack(typeSpecDef *TypeSpecDef) bool {
// with a schema for the given type
func (parser *Parser) ParseDefinition(typeSpecDef *TypeSpecDef) (*Schema, error) {
typeName := typeSpecDef.FullName()
refTypeName := TypeDocName(typeName, typeSpecDef.TypeSpec)
var refTypeName string
if fn, ok := (typeSpecDef.ParentSpec).(*ast.FuncDecl); ok {
refTypeName = TypeDocNameFuncScoped(typeName, typeSpecDef.TypeSpec, fn.Name.Name)
} else {
refTypeName = TypeDocName(typeName, typeSpecDef.TypeSpec)
}
schema, found := parser.parsedSchemas[typeSpecDef]
if found {
@@ -1055,13 +1071,21 @@ func (parser *Parser) ParseDefinition(typeSpecDef *TypeSpecDef) (*Schema, error)
}
func fullTypeName(pkgName, typeName string) string {
if pkgName != "" {
if pkgName != "" && !ignoreNameOverride(typeName) {
return pkgName + "." + typeName
}
return typeName
}
func fullTypeNameFunctionScoped(pkgName, fnName, typeName string) string {
if pkgName != "" {
return pkgName + "." + fnName + "." + typeName
}
return typeName
}
// fillDefinitionDescription additionally fills fields in definition (spec.Schema)
// TODO: If .go file contains many types, it may work for a long time
func fillDefinitionDescription(definition *spec.Schema, file *ast.File, typeSpecDef *TypeSpecDef) {
@@ -1214,7 +1238,7 @@ func (parser *Parser) parseStructField(file *ast.File, field *ast.Field) (map[st
}
}
typeName, err := getFieldType(field.Type)
typeName, err := getFieldType(file, field.Type)
if err != nil {
return nil, nil, err
}
@@ -1258,7 +1282,7 @@ func (parser *Parser) parseStructField(file *ast.File, field *ast.Field) (map[st
}
if schema == nil {
typeName, err := getFieldType(field.Type)
typeName, err := getFieldType(file, field.Type)
if err == nil {
// named type
schema, err = parser.getTypeSchema(typeName, file, true)
@@ -1291,26 +1315,26 @@ func (parser *Parser) parseStructField(file *ast.File, field *ast.Field) (map[st
return map[string]spec.Schema{fieldName: *schema}, tagRequired, nil
}
func getFieldType(field ast.Expr) (string, error) {
func getFieldType(file *ast.File, field ast.Expr) (string, error) {
switch fieldType := field.(type) {
case *ast.Ident:
return fieldType.Name, nil
case *ast.SelectorExpr:
packageName, err := getFieldType(fieldType.X)
packageName, err := getFieldType(file, fieldType.X)
if err != nil {
return "", err
}
return fullTypeName(packageName, fieldType.Sel.Name), nil
case *ast.StarExpr:
fullName, err := getFieldType(fieldType.X)
fullName, err := getFieldType(file, fieldType.X)
if err != nil {
return "", err
}
return fullName, nil
default:
return "", fmt.Errorf("unknown field type %#v", field)
return getGenericFieldType(file, field)
}
}
@@ -1421,7 +1445,6 @@ func defineTypeOfExample(schemaType, arrayType, exampleValue string) (interface{
result[mapData[0]] = v
continue
}
return nil, fmt.Errorf("example value %s should format: key:value", exampleValue)
@@ -1556,7 +1579,7 @@ func walkWith(excludes map[string]struct{}, parseVendor bool) func(path string,
if f.IsDir() {
if !parseVendor && f.Name() == "vendor" || // ignore "vendor"
f.Name() == "docs" || // exclude docs
len(f.Name()) > 1 && f.Name()[0] == '.' { // exclude all hidden folder
len(f.Name()) > 1 && f.Name()[0] == '.' && f.Name() != ".." { // exclude all hidden folder
return filepath.SkipDir
}

View File

@@ -26,12 +26,17 @@ const (
STRING = "string"
// FUNC represent a function value.
FUNC = "func"
// ERROR represent a error value.
ERROR = "error"
// INTERFACE represent a interface value.
INTERFACE = "interface{}"
// ANY represent a any value.
ANY = "any"
// NIL represent a empty value.
NIL = "nil"
// IgnoreNameOverridePrefix Prepend to model to avoid renaming based on comment.
IgnoreNameOverridePrefix = '$'
)
// CheckSchemaType checks if typeName is not a name of primitive type.
@@ -63,6 +68,11 @@ func IsPrimitiveType(typeName string) bool {
return false
}
// IsInterfaceLike determines whether the swagger type name is an go named interface type like error type.
func IsInterfaceLike(typeName string) bool {
return typeName == ERROR || typeName == ANY
}
// IsNumericType determines whether the swagger type name is a numeric type.
func IsNumericType(typeName string) bool {
return typeName == INTEGER || typeName == NUMBER
@@ -106,8 +116,7 @@ func IsGolangPrimitiveType(typeName string) bool {
"float32",
"float64",
"bool",
"string",
"any":
"string":
return true
}
@@ -126,7 +135,7 @@ func TransToValidCollectionFormat(format string) string {
// TypeDocName get alias from comment '// @name ', otherwise the original type name to display in doc.
func TypeDocName(pkgName string, spec *ast.TypeSpec) string {
if spec != nil {
if spec != nil && !ignoreNameOverride(pkgName) {
if spec.Comment != nil {
for _, comment := range spec.Comment.List {
texts := strings.Split(strings.TrimSpace(strings.TrimLeft(comment.Text, "/")), " ")
@@ -141,6 +150,38 @@ func TypeDocName(pkgName string, spec *ast.TypeSpec) string {
}
}
if ignoreNameOverride(pkgName) {
return pkgName[1:]
}
return pkgName
}
func ignoreNameOverride(name string) bool {
return len(name) != 0 && name[0] == IgnoreNameOverridePrefix
}
// TypeDocNameFuncScoped get alias from comment '// @name ', otherwise the original type name to display in doc.
func TypeDocNameFuncScoped(pkgName string, spec *ast.TypeSpec, fnName string) string {
if spec != nil && !ignoreNameOverride(pkgName) {
if spec.Comment != nil {
for _, comment := range spec.Comment.List {
texts := strings.Split(strings.TrimSpace(strings.TrimLeft(comment.Text, "/")), " ")
if len(texts) > 1 && strings.ToLower(texts[0]) == "@name" {
return texts[1]
}
}
}
if spec.Name != nil {
return fullTypeNameFunctionScoped(strings.Split(pkgName, ".")[0], fnName, spec.Name.Name)
}
}
if ignoreNameOverride(pkgName) {
return pkgName[1:]
}
return pkgName
}

View File

@@ -39,6 +39,15 @@ func Register(name string, swagger Swagger) {
swags[name] = swagger
}
// GetSwagger returns the swagger instance for given name.
// If not found, returns nil.
func GetSwagger(name string) Swagger {
swaggerMu.RLock()
defer swaggerMu.RUnlock()
return swags[name]
}
// ReadDoc reads swagger document. An optional name parameter can be passed to read a specific document.
// The default name is "swagger".
func ReadDoc(optionalName ...string) (string, error) {

View File

@@ -22,7 +22,8 @@ type TypeSpecDef struct {
TypeSpec *ast.TypeSpec
// path of package starting from under ${GOPATH}/src or from module path in go.mod
PkgPath string
PkgPath string
ParentSpec ast.Decl
}
// Name the name of the typeSpec.
@@ -36,7 +37,13 @@ func (t *TypeSpecDef) Name() string {
// FullName full name of the typeSpec.
func (t *TypeSpecDef) FullName() string {
return fullTypeName(t.File.Name.Name, t.TypeSpec.Name.Name)
var fullName string
if parentFun, ok := (t.ParentSpec).(*ast.FuncDecl); ok && parentFun != nil {
fullName = fullTypeNameFunctionScoped(t.File.Name.Name, parentFun.Name.Name, t.TypeSpec.Name.Name)
} else {
fullName = fullTypeName(t.File.Name.Name, t.TypeSpec.Name.Name)
}
return fullName
}
// FullPath of the typeSpec.

View File

@@ -1,4 +1,4 @@
package swag
// Version of swag.
const Version = "v1.8.3"
const Version = "v1.8.5"