From a20d5b30528bfc6fd72dc7c8fc50df16a6560ca2 Mon Sep 17 00:00:00 2001 From: heldiam Date: Tue, 25 Sep 2018 17:59:48 +0800 Subject: [PATCH] =?UTF-8?q?swagger=E7=BB=93=E6=9E=84=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- generate/swaggergen/g_docs.go | 185 +++++++++++++--------------------- 1 file changed, 68 insertions(+), 117 deletions(-) diff --git a/generate/swaggergen/g_docs.go b/generate/swaggergen/g_docs.go index d3ffd86..9b90959 100644 --- a/generate/swaggergen/g_docs.go +++ b/generate/swaggergen/g_docs.go @@ -37,7 +37,6 @@ import ( "github.com/astaxie/beego/utils" "github.com/beego/bee/logger" bu "github.com/beego/bee/utils" - "sort" ) const ( @@ -55,6 +54,7 @@ var controllerList map[string]map[string]*swagger.Item //controllername Paths it var modelsList map[string]map[string]swagger.Schema var rootapi swagger.Swagger var astPkgs []*ast.Package +var finds map[string]string // refer to builtin.go var basicTypes = map[string]string{ @@ -92,6 +92,7 @@ func init() { controllerList = make(map[string]map[string]*swagger.Item) modelsList = make(map[string]map[string]swagger.Schema) astPkgs = make([]*ast.Package, 0) + finds = make(map[string]string, 0) } func ParsePackagesFromDir(dirpath string) { @@ -263,8 +264,17 @@ func GenerateDocs(curpath string) { for _, l := range stmt.Rhs { if v, ok := l.(*ast.CallExpr); ok { // Analyse NewNamespace, it will return version and the subfunction - if selName := v.Fun.(*ast.SelectorExpr).Sel.String(); selName != "NewNamespace" { - continue + //if selName := v.Fun.(*ast.SelectorExpr).Sel.String(); selName != "NewNamespace" { + // continue + //} + if sel, ok := v.Fun.(*ast.SelectorExpr); ok { + if sel.Sel.String() != "NewNamespace" { + continue + } + } else if ident, ok := v.Fun.(*ast.Ident); ok { + if ident.String() != "NewNamespace" { + continue + } } version, params := analyseNewNamespace(v) if rootapi.BasePath == "" && version != "" { @@ -392,6 +402,29 @@ func analyseNSInclude(baseurl string, ce *ast.CallExpr) string { return cname } +//从gopath中查询包 +func findPackage(packagename string) bool { + if _, ok := finds[packagename]; ok { + return false + } + finds[packagename] = packagename + gopaths := bu.GetGOPATHs() + find := false + //这里可以通过参数解析指定目录,跳过多余的目录解析 + for _, v := range gopaths { + filepath.Walk(filepath.Join(v, "src"), func(path string, info os.FileInfo, err error) error { + if info.IsDir() { + if info.Name() == packagename { + parsePackageFromDir(path) + find = true + } + } + return nil + }) + } + return find +} + func analyseControllerPkg(vendorPath, localName, pkgpath string) { pkgpath = strings.Trim(pkgpath, "\"") if isSystemPackage(pkgpath) { @@ -444,6 +477,11 @@ func analyseControllerPkg(vendorPath, localName, pkgpath string) { } for _, pkg := range astPkgs { for _, fl := range pkg.Files { + for _, v := range fl.Imports { + for _, v1 := range gopaths { + parsePackageFromDir(filepath.Join(v1+"/src/", strings.Trim(v.Path.Value, "\""))) + } + } for _, d := range fl.Decls { switch specDecl := d.(type) { case *ast.FuncDecl: @@ -559,12 +597,20 @@ func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error { schema.Format = typeFormat[1] } else { m, mod, realTypes := getModel(schemaName) - schema.Ref = "#/definitions/" + m - if _, ok := modelsList[pkgpath+controllerName]; !ok { - modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema) + if mod.Type != "object" { + if sType, ok := basicTypes[mod.Type]; ok { + typeFormat := strings.Split(sType, ":") + schema.Type = typeFormat[0] + schema.Format = typeFormat[1] + } + } else { + schema.Ref = "#/definitions/" + m + if _, ok := modelsList[pkgpath+controllerName]; !ok { + modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema) + } + modelsList[pkgpath+controllerName][schemaName] = mod + appendModels(pkgpath, controllerName, realTypes) } - modelsList[pkgpath+controllerName][schemaName] = mod - appendModels(pkgpath, controllerName, realTypes) } if isArray { rs.Schema = &swagger.Schema{ @@ -756,7 +802,6 @@ func setParamType(para *swagger.Parameter, typ string, pkgpath, controllerName s paraFormat = typeFormat[1] } else { m, mod, realTypes := getModel(typ) - fmt.Printf("类型:%s\n", mod.Type) if mod.Type != "object" { if sType, ok := basicTypes[mod.Type]; ok { typeFormat := strings.Split(sType, ":") @@ -879,7 +924,13 @@ func getparams(str string) []string { func getModel(str string) (objectname string, m swagger.Schema, realTypes []string) { strs := strings.Split(str, ".") + if len(strs) > 2 { + strs[0] = strs[len(strs)-2] + } objectname = strs[len(strs)-1] + if isBasicType(objectname) { + return + } packageName := "" m.Type = "object" for _, pkg := range astPkgs { @@ -901,7 +952,12 @@ func getModel(str string) (objectname string, m swagger.Schema, realTypes []stri } } if m.Title == "" { - beeLogger.Log.Warnf("Cannot find the object: %s", str) + find := findPackage(strs[0]) + if find { + return getModel(strs[0] + "." + objectname) + } else { + beeLogger.Log.Warnf("Cannot find the object: %s", str) + } // TODO remove when all type have been supported //os.Exit(1) } @@ -919,117 +975,12 @@ func parseObject(d *ast.Object, k string, m *swagger.Schema, realTypes *[]string beeLogger.Log.Fatalf("Unknown type without TypeSec: %v\n", d) } // TODO support other types, such as `ArrayType`, `MapType`, `InterfaceType` etc... - _, ok = ts.Type.(*ast.StructType) + st, ok := ts.Type.(*ast.StructType) if !ok { m.Title = fmt.Sprintf("%v", reflect.ValueOf(ts.Type)) m.Type = fmt.Sprintf("%v", reflect.ValueOf(ts.Type)) return - switch t := ts.Type.(type) { - case *ast.ArrayType: - m.Title = k - m.Type = "array" - if isBasicType(fmt.Sprint(t.Elt)) { - typeFormat := strings.Split(basicTypes[fmt.Sprint(t.Elt)], ":") - m.Format = typeFormat[0] - } else { - objectName := packageName + "." + fmt.Sprint(t.Elt) - if _, ok := rootapi.Definitions[objectName]; !ok { - objectName, _, _ = getModel(objectName) - } - m.Items = &swagger.Schema{ - Ref: "#/definitions/" + objectName, - } - } - case *ast.Ident: - parseIdent(t, k, m, astPkgs) - case *ast.StructType: - parseStruct(t, k, m, realTypes, astPkgs, packageName) - } } -} - -// parse as enum, in the package, find out all consts with the same type -func parseIdent(st *ast.Ident, k string, m *swagger.Schema, astPkgs []*ast.Package) { - m.Title = k - basicType := fmt.Sprint(st) - if object, isStdLibObject := stdlibObject[basicType]; isStdLibObject { - basicType = object - } - if k, ok := basicTypes[basicType]; ok { - typeFormat := strings.Split(k, ":") - m.Type = typeFormat[0] - m.Format = typeFormat[1] - } - enums := make(map[int]string) - enumValues := make(map[int]interface{}) - for _, pkg := range astPkgs { - for _, fl := range pkg.Files { - for _, obj := range fl.Scope.Objects { - if obj.Kind == ast.Con { - vs, ok := obj.Decl.(*ast.ValueSpec) - if !ok { - beeLogger.Log.Fatalf("Unknown type without ValueSpec: %v\n", vs) - } - - ti, ok := vs.Type.(*ast.Ident) - if !ok { - // TODO type inference, iota not support yet - continue - } - // Only add the enums that are defined by the current identifier - if ti.Name != k { - continue - } - - // For all names and values, aggregate them by it's position so that we can sort them later. - for i, val := range vs.Values { - v, ok := val.(*ast.BasicLit) - if !ok { - beeLogger.Log.Warnf("Unknown type without BasicLit: %v\n", v) - continue - } - enums[int(val.Pos())] = fmt.Sprintf("%s = %s", vs.Names[i].Name, v.Value) - switch v.Kind { - case token.INT: - vv, err := strconv.Atoi(v.Value) - if err != nil { - beeLogger.Log.Warnf("Unknown type with BasicLit to int: %v\n", v.Value) - continue - } - enumValues[int(val.Pos())] = vv - case token.FLOAT: - vv, err := strconv.ParseFloat(v.Value, 64) - if err != nil { - beeLogger.Log.Warnf("Unknown type with BasicLit to int: %v\n", v.Value) - continue - } - enumValues[int(val.Pos())] = vv - default: - enumValues[int(val.Pos())] = strings.Trim(v.Value, `"`) - } - - } - } - } - } - } - // Sort the enums by position - if len(enums) > 0 { - var keys []int - for k := range enums { - keys = append(keys, k) - } - sort.Ints(keys) - for _, k := range keys { - m.Enum = append(m.Enum, enums[k]) - } - // Automatically use the first enum value as the example. - m.Example = enumValues[keys[0]] - } - -} - -func parseStruct(st *ast.StructType, k string, m *swagger.Schema, realTypes *[]string, astPkgs []*ast.Package, packageName string) { m.Title = k if st.Fields.List != nil { m.Properties = make(map[string]swagger.Propertie) @@ -1049,7 +1000,7 @@ func parseStruct(st *ast.StructType, k string, m *swagger.Schema, realTypes *[]s mp := swagger.Propertie{} if isSlice { mp.Type = "array" - if sType, ok := basicTypes[(strings.Replace(realType, "[]", "", -1))]; ok { + if isBasicType(strings.Replace(realType, "[]", "", -1)) { typeFormat := strings.Split(sType, ":") mp.Items = &swagger.Propertie{ Type: typeFormat[0],