generates nested types in doc (#2201)

Co-authored-by: Link_Zhao <Link_Zhao@epam.com>
master
Zlx 2 years ago committed by GitHub
parent f70805ee60
commit 9d6c8f67f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
_ "embed" _ "embed"
"fmt" "fmt"
"go/format"
"html/template" "html/template"
"strconv" "strconv"
"strings" "strings"
@ -35,12 +36,12 @@ func genDoc(api *spec.ApiSpec, dir, filename string) error {
routeComment = "N/A" routeComment = "N/A"
} }
requestContent, err := buildDoc(route.RequestType) requestContent, err := buildDoc(route.RequestType, api)
if err != nil { if err != nil {
return err return err
} }
responseContent, err := buildDoc(route.ResponseType) responseContent, err := buildDoc(route.ResponseType, api)
if err != nil { if err != nil {
return err return err
} }
@ -60,7 +61,6 @@ func genDoc(api *spec.ApiSpec, dir, filename string) error {
if err != nil { if err != nil {
return err return err
} }
builder.Write(tmplBytes.Bytes()) builder.Write(tmplBytes.Bytes())
} }
@ -68,7 +68,7 @@ func genDoc(api *spec.ApiSpec, dir, filename string) error {
return err return err
} }
func buildDoc(route spec.Type) (string, error) { func buildDoc(route spec.Type, api *spec.ApiSpec) (string, error) {
if route == nil || len(route.Name()) == 0 { if route == nil || len(route.Name()) == 0 {
return "", nil return "", nil
} }
@ -78,12 +78,15 @@ func buildDoc(route spec.Type) (string, error) {
if definedType, ok := route.(spec.DefineStruct); ok { if definedType, ok := route.(spec.DefineStruct); ok {
associatedTypes(definedType, &tps) associatedTypes(definedType, &tps)
} }
value, err := gogen.BuildTypes(tps) value, err := gogen.BuildTypes(tps, api)
if err != nil { if err != nil {
return "", err return "", err
} }
formatted, err := format.Source([]byte(value))
return fmt.Sprintf("\n\n```golang\n%s\n```\n", value), nil if err != nil {
return "", err
}
return fmt.Sprintf("\n\n```golang\n%s\n```\n", string(formatted)), nil
} }
func associatedTypes(tp spec.DefineStruct, tps *[]spec.Type) { func associatedTypes(tp spec.DefineStruct, tps *[]spec.Type) {

@ -21,7 +21,7 @@ const typesFile = "types"
var typesTemplate string var typesTemplate string
// BuildTypes gen types to string // BuildTypes gen types to string
func BuildTypes(types []spec.Type) (string, error) { func BuildTypes(types []spec.Type, api *spec.ApiSpec) (string, error) {
var builder strings.Builder var builder strings.Builder
first := true first := true
for _, tp := range types { for _, tp := range types {
@ -30,7 +30,7 @@ func BuildTypes(types []spec.Type) (string, error) {
} else { } else {
builder.WriteString("\n\n") builder.WriteString("\n\n")
} }
if err := writeType(&builder, tp); err != nil { if err := writeType(&builder, tp, api); err != nil {
return "", apiutil.WrapErr(err, "Type "+tp.Name()+" generate error") return "", apiutil.WrapErr(err, "Type "+tp.Name()+" generate error")
} }
} }
@ -39,7 +39,7 @@ func BuildTypes(types []spec.Type) (string, error) {
} }
func genTypes(dir string, cfg *config.Config, api *spec.ApiSpec) error { func genTypes(dir string, cfg *config.Config, api *spec.ApiSpec) error {
val, err := BuildTypes(api.Types) val, err := BuildTypes(api.Types, api)
if err != nil { if err != nil {
return err return err
} }
@ -68,7 +68,7 @@ func genTypes(dir string, cfg *config.Config, api *spec.ApiSpec) error {
}) })
} }
func writeType(writer io.Writer, tp spec.Type) error { func writeType(writer io.Writer, tp spec.Type, api *spec.ApiSpec) error {
structType, ok := tp.(spec.DefineStruct) structType, ok := tp.(spec.DefineStruct)
if !ok { if !ok {
return fmt.Errorf("unspport struct type: %s", tp.Name()) return fmt.Errorf("unspport struct type: %s", tp.Name())
@ -76,15 +76,7 @@ func writeType(writer io.Writer, tp spec.Type) error {
fmt.Fprintf(writer, "type %s struct {\n", util.Title(tp.Name())) fmt.Fprintf(writer, "type %s struct {\n", util.Title(tp.Name()))
for _, member := range structType.Members { for _, member := range structType.Members {
if member.IsInline { if err := writeProperty(writer, member.Name, member.Tag, member.GetComment(), member.Type, 1, api); err != nil {
if _, err := fmt.Fprintf(writer, "%s\n", strings.Title(member.Type.Name())); err != nil {
return err
}
continue
}
if err := writeProperty(writer, member.Name, member.Tag, member.GetComment(), member.Type, 1); err != nil {
return err return err
} }
} }

@ -0,0 +1,3 @@
type Common {
Some string `json:"some"` // some imported type
}

@ -0,0 +1,48 @@
import "./api_common.api"
type Resp {
R1 string `json:"r1"`
R2 bool `json:"r2"`
R3 Common `json:"r3"`
}
type CommonResponse {
Code int `json:"code"` // 100 | 200
Message string `json:"message"`
Common
Response Resp `json:"response"`
}
type LoginResponseDto {
Id string `bson:"_id" json:"id"`
Name string `json:"name"`
AccessToken string `json:"accessToken"`
}
type UserCreateDto {
Id string `json:"id"`
}
type LoginRequest {
Username string `json:"username,optional"` // user name is optional
Password string `json:"password,optional"`
}
type LoginResponse {
*CommonResponse
Result *LoginResponseDto `json:"result"`
}
type UserCreateRequest {
Username string `json:"username,optional"` // some dsada
Password string `json:"password,optional"`
}
type UserCreateResponse {
*CommonResponse
Result *UserCreateDto `json:"result"` // result
}
service user-api {
@handler UserHandler
post /user/signin(UserCreateRequest) returns (UserCreateResponse)
@handler LoginHandler
post /user/login(LoginRequest) returns (LoginResponse)
}

@ -4,6 +4,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"os"
"strings" "strings"
"text/template" "text/template"
@ -57,15 +58,21 @@ func genFile(c fileGenConfig) error {
return err return err
} }
func writeProperty(writer io.Writer, name, tag, comment string, tp spec.Type, indent int) error { func writeProperty(writer io.Writer, name, tag, comment string, tp spec.Type, indent int, api *spec.ApiSpec) error {
util.WriteIndent(writer, indent) util.WriteIndent(writer, indent)
var err error var err error
if len(comment) > 0 { var refPropertyName = tp.Name()
comment = strings.TrimPrefix(comment, "//") if isCustomType(refPropertyName) {
comment = "//" + comment strs := getRefProperty(api, refPropertyName, name)
_, err = fmt.Fprintf(writer, "%s %s %s %s\n", strings.Title(name), tp.Name(), tag, comment) _, err = fmt.Fprintf(writer, "%s\n", strs)
} else { } else {
_, err = fmt.Fprintf(writer, "%s %s %s\n", strings.Title(name), tp.Name(), tag) if len(comment) > 0 {
comment = strings.TrimPrefix(comment, "//")
comment = "//" + comment
_, err = fmt.Fprintf(writer, "%s %s %s %s\n", strings.Title(name), tp.Name(), tag, comment)
} else {
_, err = fmt.Fprintf(writer, "%s %s %s\n", strings.Title(name), tp.Name(), tag)
}
} }
return err return err
@ -181,3 +188,58 @@ func golangExpr(ty spec.Type, pkg ...string) string {
return "" return ""
} }
func isCustomType(t string) bool {
var builtinType = []string{"string", "bool", "int", "uint", "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "float32", "float64", "uintptr", "complex64", "complex128"}
var is bool = true
for _, v := range builtinType {
if t == v {
is = false
break
}
}
return is
}
// Generate nested types recursively
func getRefProperty(api *spec.ApiSpec, refPropertyName string, name string) string {
var str string = ""
for _, t := range api.Types {
if strings.TrimLeft(refPropertyName, "*") == t.Name() {
switch tm := t.(type) {
case spec.DefineStruct:
for _, m := range tm.Members {
if isCustomType(m.Type.Name()) {
// recursive
str += getRefProperty(api, m.Type.Name(), m.Name)
} else {
if len(m.Comment) > 0 {
comment := strings.TrimPrefix(m.Comment, "//")
comment = "//" + comment
str += fmt.Sprintf("%s %s %s %s\n\t", m.Name, m.Type.Name(), m.Tag, comment)
} else {
str += fmt.Sprintf("%s %s %s\n\t", m.Name, m.Type.Name(), m.Tag)
}
}
}
}
}
}
if name == "" {
temp := `${str}`
return os.Expand(temp, func(k string) string {
return str
})
} else {
temp := `${name} struct {
${str}}`
return os.Expand(temp, func(k string) string {
return map[string]string{
"name": name,
"str": str,
}[k]
})
}
}

Loading…
Cancel
Save