feat: add swag tool

This commit is contained in:
Rogee
2024-12-25 16:18:41 +08:00
parent 2f2feb35c2
commit 77e36d5aaf
16 changed files with 76 additions and 54 deletions

View File

@@ -85,7 +85,7 @@ func (ps *tagBaseFieldParser) FieldNames() ([]string, error) {
return nil, nil
}
}
var names = make([]string, 0, len(ps.field.Names))
names := make([]string, 0, len(ps.field.Names))
for _, name := range ps.field.Names {
switch ps.p.PropNamingStrategy {
case SnakeCase:
@@ -247,7 +247,7 @@ func (ps *tagBaseFieldParser) ComplementSchema(schema *spec.Schema) error {
}
if IsRefSchema(schema) {
var newSchema = spec.Schema{}
newSchema := spec.Schema{}
err := ps.complementSchema(&newSchema, types)
if err != nil {
return err
@@ -658,9 +658,11 @@ const (
// These code copy from
// https://github.com/go-playground/validator/blob/d4271985b44b735c6f76abc7a06532ee997f9476/baked_in.go#L207
// ---.
var oneofValsCache = map[string][]string{}
var oneofValsCacheRWLock = sync.RWMutex{}
var splitParamsRegex = regexp.MustCompile(`'[^']*'|\S+`)
var (
oneofValsCache = map[string][]string{}
oneofValsCacheRWLock = sync.RWMutex{}
splitParamsRegex = regexp.MustCompile(`'[^']*'|\S+`)
)
func parseOneOfParam2(param string) []string {
oneofValsCacheRWLock.RLock()

View File

@@ -680,7 +680,8 @@ func TestValidTags(t *testing.T) {
Names: []*ast.Ident{{Name: "Test"}},
Tag: &ast.BasicLit{
Value: `json:"test" validate:"required,oneof=one two"`,
}},
},
},
).ComplementSchema(&schema)
assert.NoError(t, err)
assert.Empty(t, schema.Enum)
@@ -695,7 +696,8 @@ func TestValidTags(t *testing.T) {
Names: []*ast.Ident{{Name: "Test"}},
Tag: &ast.BasicLit{
Value: `form:"test[]"`,
}},
},
},
).FieldNames()
assert.NoError(t, err)
assert.Equal(t, "test", filednames[0])
@@ -706,7 +708,8 @@ func TestValidTags(t *testing.T) {
Names: []*ast.Ident{{Name: "Test"}},
Tag: &ast.BasicLit{
Value: `form:"test"`,
}},
},
},
).FieldNames()
assert.NoError(t, err)
assert.Equal(t, "test", filednames[0])

View File

@@ -57,7 +57,7 @@ func TestFormat_DefaultExcludes(t *testing.T) {
func TestFormat_ParseError(t *testing.T) {
fx := setup(t)
os.WriteFile(filepath.Join(fx.basedir, "parse_error.go"), []byte(`package main
func invalid() {`), 0644)
func invalid() {`), 0o644)
assert.Error(t, New().Build(&Config{SearchDir: fx.basedir}))
}
@@ -69,9 +69,9 @@ func TestFormat_ReadError(t *testing.T) {
func TestFormat_WriteError(t *testing.T) {
fx := setup(t)
os.Chmod(fx.basedir, 0555)
os.Chmod(fx.basedir, 0o555)
assert.Error(t, New().Build(&Config{SearchDir: fx.basedir}))
os.Chmod(fx.basedir, 0755)
os.Chmod(fx.basedir, 0o755)
}
func TestFormat_InvalidSearchDir(t *testing.T) {
@@ -91,10 +91,10 @@ func setup(t *testing.T) *fixture {
}
for filename, contents := range testFiles {
fullpath := filepath.Join(fx.basedir, filepath.Clean(filename))
if err := os.MkdirAll(filepath.Dir(fullpath), 0755); err != nil {
if err := os.MkdirAll(filepath.Dir(fullpath), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(fullpath, contents, 0644); err != nil {
if err := os.WriteFile(fullpath, contents, 0o644); err != nil {
t.Fatal(err)
}
}

View File

@@ -227,7 +227,6 @@ func Test_AlignAttribute(t *testing.T) {
`
testFormat(t, "align.go", contents, want)
}
func Test_SyntaxError(t *testing.T) {

View File

@@ -90,7 +90,7 @@ func (pkgDefs *PackagesDefinitions) getTypeFromGenericParam(genericParam string,
TypeSpec: &ast.TypeSpec{
Name: ast.NewIdent(string(IgnoreNameOverridePrefix) + "map_" + parts[0] + "_" + typeSpecDef.TypeName()),
Type: &ast.MapType{
Key: ast.NewIdent(parts[0]), //assume key is string or integer
Key: ast.NewIdent(parts[0]), // assume key is string or integer
Value: expr,
},
},
@@ -123,7 +123,7 @@ func (pkgDefs *PackagesDefinitions) parametrizeGenericType(file *ast.File, origi
return nil
}
//generic[x,y any,z any] considered, TODO what if the type is not `any`, but a concrete one, such as `int32|int64` or an certain interface{}
// generic[x,y any,z any] considered, TODO what if the type is not `any`, but a concrete one, such as `int32|int64` or an certain interface{}
var formals []formalParamType
for _, field := range original.TypeSpec.TypeParams.List {
for _, ident := range field.Names {
@@ -206,7 +206,7 @@ func (pkgDefs *PackagesDefinitions) parametrizeGenericType(file *ast.File, origi
// splitGenericsTypeName splits a generic struct name in his parts
func splitGenericsTypeName(fullGenericForm string) (string, []string) {
//remove all spaces character
// remove all spaces character
fullGenericForm = strings.Map(func(r rune) rune {
if unicode.IsSpace(r) {
return -1
@@ -254,7 +254,7 @@ func (pkgDefs *PackagesDefinitions) getParametrizedType(genTypeSpec *genericType
}
}
//a primitive type name or a type name in current package
// a primitive type name or a type name in current package
return &ast.Ident{Name: genTypeSpec.Name}
}

View File

@@ -164,7 +164,8 @@ func TestParametrizeStruct(t *testing.T) {
Name: &ast.Ident{Name: "Field"},
TypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "T"}}}, {Names: []*ast.Ident{{Name: "T2"}}}}},
Type: &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},
}}, "test.Field[string, []string]")
},
}, "test.Field[string, []string]")
assert.NotNil(t, typeSpec)
assert.Equal(t, "$test.Field-string-array_string", typeSpec.Name())
assert.Equal(t, "test.Field-string-array_string", typeSpec.TypeName())
@@ -177,7 +178,8 @@ func TestParametrizeStruct(t *testing.T) {
Name: &ast.Ident{Name: "Field"},
TypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "T"}}}}},
Type: &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},
}}, "test.Field[string, string]")
},
}, "test.Field[string, string]")
assert.Nil(t, typeSpec)
// definition contains two type params, but only one is used
@@ -188,7 +190,8 @@ func TestParametrizeStruct(t *testing.T) {
Name: &ast.Ident{Name: "Field"},
TypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "T"}}}, {Names: []*ast.Ident{{Name: "T2"}}}}},
Type: &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},
}}, "test.Field[string]")
},
}, "test.Field[string]")
assert.Nil(t, typeSpec)
// name is not a valid type name
@@ -199,7 +202,8 @@ func TestParametrizeStruct(t *testing.T) {
Name: &ast.Ident{Name: "Field"},
TypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "T"}}}, {Names: []*ast.Ident{{Name: "T2"}}}}},
Type: &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},
}}, "test.Field[string")
},
}, "test.Field[string")
assert.Nil(t, typeSpec)
typeSpec = pd.parametrizeGenericType(
@@ -209,7 +213,8 @@ func TestParametrizeStruct(t *testing.T) {
Name: &ast.Ident{Name: "Field"},
TypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "T"}}}, {Names: []*ast.Ident{{Name: "T2"}}}}},
Type: &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},
}}, "test.Field[string, [string]")
},
}, "test.Field[string, [string]")
assert.Nil(t, typeSpec)
typeSpec = pd.parametrizeGenericType(
@@ -219,7 +224,8 @@ func TestParametrizeStruct(t *testing.T) {
Name: &ast.Ident{Name: "Field"},
TypeParams: &ast.FieldList{List: []*ast.Field{{Names: []*ast.Ident{{Name: "T"}}}, {Names: []*ast.Ident{{Name: "T2"}}}}},
Type: &ast.StructType{Struct: 100, Fields: &ast.FieldList{Opening: 101, Closing: 102}},
}}, "test.Field[string, ]string]")
},
}, "test.Field[string, ]string]")
assert.Nil(t, typeSpec)
}

View File

@@ -598,7 +598,7 @@ func setCollectionFormatParam(param *spec.Parameter, name, schemaType, attr, com
return fmt.Errorf("%s is attribute to set to an array. comment=%s got=%s", name, commentLine, schemaType)
}
func setDefault(param *spec.Parameter, schemaType string, value string) error {
func setDefault(param *spec.Parameter, schemaType, value string) error {
val, err := defineType(schemaType, value)
if err != nil {
return nil // Don't set a default value if it's not valid
@@ -609,7 +609,7 @@ func setDefault(param *spec.Parameter, schemaType string, value string) error {
return nil
}
func setSchemaExample(param *spec.Parameter, schemaType string, value string) error {
func setSchemaExample(param *spec.Parameter, schemaType, value string) error {
val, err := defineType(schemaType, value)
if err != nil {
return nil // Don't set a example value if it's not valid
@@ -630,7 +630,7 @@ func setSchemaExample(param *spec.Parameter, schemaType string, value string) er
return nil
}
func setExample(param *spec.Parameter, schemaType string, value string) error {
func setExample(param *spec.Parameter, schemaType, value string) error {
val, err := defineType(schemaType, value)
if err != nil {
return nil // Don't set a example value if it's not valid
@@ -642,7 +642,7 @@ func setExample(param *spec.Parameter, schemaType string, value string) error {
}
// defineType enum value define the type (object and array unsupported).
func defineType(schemaType string, value string) (v interface{}, err error) {
func defineType(schemaType, value string) (v interface{}, err error) {
schemaType = TransToValidSchemeType(schemaType)
switch schemaType {
@@ -1187,7 +1187,7 @@ func (operation *Operation) AddResponse(code int, response *spec.Response) {
}
// createParameter returns swagger spec.Parameter for given paramType, description, paramName, schemaType, required.
func createParameter(paramType, description, paramName, objectType, schemaType string, format string, required bool, enums []interface{}, collectionFormat string) spec.Parameter {
func createParameter(paramType, description, paramName, objectType, schemaType, format string, required bool, enums []interface{}, collectionFormat string) spec.Parameter {
// //five possible parameter types. query, path, body, header, form
result := spec.Parameter{
ParamProps: spec.ParamProps{
@@ -1223,7 +1223,7 @@ func createParameter(paramType, description, paramName, objectType, schemaType s
return result
}
func getCodeExampleForSummary(summaryName string, dirPath string) ([]byte, error) {
func getCodeExampleForSummary(summaryName, dirPath string) ([]byte, error) {
dirEntries, err := os.ReadDir(dirPath)
if err != nil {
return nil, err

View File

@@ -100,16 +100,16 @@ func (pkg *PackageDefinitions) evaluateConstValue(file *ast.File, iota int, expr
valueExpr.Value = strings.Replace(valueExpr.Value, "_", "", -1)
}
if len(valueExpr.Value) >= 2 && valueExpr.Value[0] == '0' {
var start, base = 2, 8
start, base := 2, 8
switch valueExpr.Value[1] {
case 'x', 'X':
//hex
// hex
base = 16
case 'b', 'B':
//binary
// binary
base = 2
default:
//octet
// octet
start = 1
}
if x, err := strconv.ParseInt(valueExpr.Value[start:], base, 64); err == nil {
@@ -121,7 +121,7 @@ func (pkg *PackageDefinitions) evaluateConstValue(file *ast.File, iota int, expr
}
}
//a basic literal integer is int type in default, or must have an explicit converting type in front
// a basic literal integer is int type in default, or must have an explicit converting type in front
if x, err := strconv.ParseInt(valueExpr.Value, 10, 64); err == nil {
return int(x), nil
} else if x, err := strconv.ParseUint(valueExpr.Value, 10, 64); err == nil {
@@ -153,7 +153,7 @@ func (pkg *PackageDefinitions) evaluateConstValue(file *ast.File, iota int, expr
case *ast.ParenExpr:
return pkg.evaluateConstValue(file, iota, valueExpr.X, globalEvaluator, recursiveStack)
case *ast.CallExpr:
//data conversion
// data conversion
if len(valueExpr.Args) != 1 {
return nil, nil
}

View File

@@ -272,7 +272,6 @@ func (pkgDefs *PackagesDefinitions) parseFunctionScopedTypesFromFile(astFile *as
}
}
}
}
}
}
@@ -420,7 +419,7 @@ func (pkgDefs *PackagesDefinitions) removeAllNotUniqueTypes() {
}
}
func (pkgDefs *PackagesDefinitions) findTypeSpec(pkgPath string, typeName string) *TypeSpecDef {
func (pkgDefs *PackagesDefinitions) findTypeSpec(pkgPath, typeName string) *TypeSpecDef {
if pkgDefs.packages == nil {
return nil
}

View File

@@ -367,7 +367,7 @@ func ParseUsingGoList(enabled bool) func(parser *Parser) {
}
// ParseAPI parses general api info for given searchDir and mainAPIFile.
func (parser *Parser) ParseAPI(searchDir string, mainAPIFile string, parseDepth int) error {
func (parser *Parser) ParseAPI(searchDir, mainAPIFile string, parseDepth int) error {
return parser.ParseAPIMultiSearchDir([]string{searchDir}, mainAPIFile, parseDepth)
}
@@ -902,7 +902,7 @@ func isGeneralAPIComment(comments []string) bool {
return true
}
func getMarkdownForTag(tagName string, dirPath string) ([]byte, error) {
func getMarkdownForTag(tagName, dirPath string) ([]byte, error) {
if tagName == "" {
// this happens when parsing the @description.markdown attribute
// it will be called properly another time with tagName="api"
@@ -970,7 +970,6 @@ func getTagsFromComment(comment string) (tags []string) {
}
}
return
}
func (parser *Parser) matchTag(tag string) bool {
@@ -1342,8 +1341,8 @@ func (parser *Parser) ParseDefinition(typeSpecDef *TypeSpecDef) (*Schema, error)
if len(typeSpecDef.Enums) > 0 {
var varnames []string
var enumComments = make(map[string]string)
var enumDescriptions = make([]string, 0, len(typeSpecDef.Enums))
enumComments := make(map[string]string)
enumDescriptions := make([]string, 0, len(typeSpecDef.Enums))
for _, value := range typeSpecDef.Enums {
definition.Enum = append(definition.Enum, value.Value)
varnames = append(varnames, value.key)
@@ -1409,8 +1408,7 @@ func (parser *Parser) fillDefinitionDescription(definition *spec.Schema, file *a
if typeSpec.Name != nil {
typeName = typeSpec.Name.Name
}
definition.Description, err =
parser.extractDeclarationDescription(typeName, typeSpec.Doc, typeSpec.Comment, generalDeclaration.Doc)
definition.Description, err = parser.extractDeclarationDescription(typeName, typeSpec.Doc, typeSpec.Comment, generalDeclaration.Doc)
if err != nil {
return
}

View File

@@ -3,6 +3,7 @@ package swag
import (
"errors"
"fmt"
"github.com/go-openapi/spec"
)
@@ -184,7 +185,7 @@ func IsComplexSchema(schema *spec.Schema) bool {
return true
}
//Object included, such as Object or []Object
// Object included, such as Object or []Object
for _, st := range schema.Type {
if st == OBJECT {
return true
@@ -254,7 +255,7 @@ func BuildCustomSchema(types []string) (*spec.Schema, error) {
}
// MergeSchema merge schemas
func MergeSchema(dst *spec.Schema, src *spec.Schema) *spec.Schema {
func MergeSchema(dst, src *spec.Schema) *spec.Schema {
if len(src.Type) > 0 {
dst.Type = src.Type
}

View File

@@ -33,7 +33,7 @@ func (i *Spec) ReadDoc() string {
},
"escape": func(v interface{}) string {
// escape tabs
var str = strings.ReplaceAll(v.(string), "\t", "\\t")
str := strings.ReplaceAll(v.(string), "\t", "\\t")
// replace " with \", and if that results in \\", replace that with \\\"
str = strings.ReplaceAll(str, "\"", "\\\"")

View File

@@ -106,7 +106,7 @@ func (t *TypeSpecDef) SetSchemaName() {
// AstFileInfo information of an ast.File.
type AstFileInfo struct {
//FileSet the FileSet object which is used to parse this go source file
// FileSet the FileSet object which is used to parse this go source file
FileSet *token.FileSet
// File ast.File

View File

@@ -1,8 +1,9 @@
package swag
import (
"github.com/stretchr/testify/assert"
"testing"
"github.com/stretchr/testify/assert"
)
func TestFieldsByAnySpace(t *testing.T) {
@@ -15,14 +16,16 @@ func TestFieldsByAnySpace(t *testing.T) {
args args
want []string
}{
{"test1",
{
"test1",
args{
" aa bb cc dd ff",
2,
},
[]string{"aa", "bb\tcc dd \t\tff"},
},
{"test2",
{
"test2",
args{
` aa "bb cc dd ff"`,
2,