func parseObject(d *ast.Object, k string, m *swagger.Schema, realTypes *[]string, astPkgs map[string]*ast.Package) { ts, ok := d.Decl.(*ast.TypeSpec) if !ok { ColorLog("Unknown type without TypeSec: %v\n", d) os.Exit(1) } // TODO support other types, such as `ArrayType`, `MapType`, `InterfaceType` etc... st, ok := ts.Type.(*ast.StructType) if !ok { return } m.Title = k if st.Fields.List != nil { m.Properties = make(map[string]swagger.Propertie) for _, field := range st.Fields.List { isSlice, realType, sType := typeAnalyser(field) *realTypes = append(*realTypes, realType) mp := swagger.Propertie{} if isSlice { mp.Type = "array" if isBasicType(realType) { typeFormat := strings.Split(sType, ":") mp.Items = &swagger.Propertie{ Type: typeFormat[0], Format: typeFormat[1], } } else { mp.Items = &swagger.Propertie{ Ref: "#/definitions/" + realType, } } } else { if sType == "object" { mp.Ref = "#/definitions/" + realType } else if isBasicType(realType) { typeFormat := strings.Split(sType, ":") mp.Type = typeFormat[0] mp.Format = typeFormat[1] } else if realType == "map" { typeFormat := strings.Split(sType, ":") mp.AdditionalProperties = &swagger.Propertie{ Type: typeFormat[0], Format: typeFormat[1], } } } if field.Names != nil { // set property name as field name var name = field.Names[0].Name // if no tag skip tag processing if field.Tag == nil { m.Properties[name] = mp continue } var tagValues []string stag := reflect.StructTag(strings.Trim(field.Tag.Value, "`")) tag := stag.Get("json") if tag != "" { tagValues = strings.Split(tag, ",") } // dont add property if json tag first value is "-" if len(tagValues) == 0 || tagValues[0] != "-" { // set property name to the left most json tag value only if is not omitempty if len(tagValues) > 0 && tagValues[0] != "omitempty" { name = tagValues[0] } if thrifttag := stag.Get("thrift"); thrifttag != "" { ts := strings.Split(thrifttag, ",") if ts[0] != "" { name = ts[0] } } if required := stag.Get("required"); required != "" { m.Required = append(m.Required, name) } if desc := stag.Get("description"); desc != "" { mp.Description = desc } m.Properties[name] = mp } if ignore := stag.Get("ignore"); ignore != "" { continue } } else { for _, pkg := range astPkgs { for _, fl := range pkg.Files { for nameOfObj, obj := range fl.Scope.Objects { if obj.Name == fmt.Sprint(field.Type) { parseObject(obj, nameOfObj, m, realTypes, astPkgs) } } } } } } } }
func getModel(str string) (pkgpath, objectname string, m swagger.Schema, realTypes []string) { strs := strings.Split(str, ".") objectname = strs[len(strs)-1] pkgpath = strings.Join(strs[:len(strs)-1], "/") curpath, _ := os.Getwd() pkgRealpath := path.Join(curpath, pkgpath) fileSet := token.NewFileSet() astPkgs, err := parser.ParseDir(fileSet, pkgRealpath, func(info os.FileInfo) bool { name := info.Name() return !info.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") }, parser.ParseComments) if err != nil { ColorLog("[ERRO] the model %s parser.ParseDir error\n", str) os.Exit(1) } m.Type = "object" for _, pkg := range astPkgs { for _, fl := range pkg.Files { for k, d := range fl.Scope.Objects { if d.Kind == ast.Typ { if k != objectname { continue } ts, ok := d.Decl.(*ast.TypeSpec) if !ok { ColorLog("Unknown type without TypeSec: %v", d) os.Exit(1) } st, ok := ts.Type.(*ast.StructType) if !ok { continue } m.Title = k if st.Fields.List != nil { m.Properties = make(map[string]swagger.Propertie) for _, field := range st.Fields.List { isSlice, realType, sType := typeAnalyser(field) realTypes = append(realTypes, realType) mp := swagger.Propertie{} // add type slice if isSlice { mp.Type = "array" if isBasicType(realType) { typeFormat := strings.Split(sType, ":") mp.Items = &swagger.Propertie{ Type: typeFormat[0], Format: typeFormat[1], } } else { mp.Items = &swagger.Propertie{ Ref: "#/definitions/" + realType, } } } else { if isBasicType(realType) { typeFormat := strings.Split(sType, ":") mp.Type = typeFormat[0] mp.Format = typeFormat[1] } else if sType == "object" { mp.Ref = "#/definitions/" + realType } } // dont add property if anonymous field if field.Names != nil { // set property name as field name var name = field.Names[0].Name // if no tag skip tag processing if field.Tag == nil { m.Properties[name] = mp continue } var tagValues []string stag := reflect.StructTag(strings.Trim(field.Tag.Value, "`")) tag := stag.Get("json") if tag != "" { tagValues = strings.Split(tag, ",") } // dont add property if json tag first value is "-" if len(tagValues) == 0 || tagValues[0] != "-" { // set property name to the left most json tag value only if is not omitempty if len(tagValues) > 0 && tagValues[0] != "omitempty" { name = tagValues[0] } if thrifttag := stag.Get("thrift"); thrifttag != "" { ts := strings.Split(thrifttag, ",") if ts[0] != "" { name = ts[0] } } if required := stag.Get("required"); required != "" { m.Required = append(m.Required, name) } if desc := stag.Get("description"); desc != "" { mp.Description = desc } m.Properties[name] = mp } if ignore := stag.Get("ignore"); ignore != "" { continue } } } } } } } } if m.Title == "" { ColorLog("can't find the object: %s", str) os.Exit(1) } if len(rootapi.Definitions) == 0 { rootapi.Definitions = make(map[string]swagger.Schema) } rootapi.Definitions[objectname] = m return }