From 9581e8445a5e8914d6acdc383c2fd69bd785da40 Mon Sep 17 00:00:00 2001 From: anqiansong Date: Sun, 11 Sep 2022 22:56:53 +0800 Subject: [PATCH] fix: issue #2359 (#2368) * Revert changes * Unrap nested structure for doc code generation * Revert changes * Remove useless code * Remove useless code * Format code --- tools/goctl/api/docgen/doc.go | 103 +++++++++++++++--- tools/goctl/api/gogen/gentypes.go | 18 ++- tools/goctl/api/gogen/testdata/api_common.api | 3 - .../gogen/testdata/api_has_nested_type.api | 48 -------- tools/goctl/api/gogen/util.go | 74 +------------ 5 files changed, 109 insertions(+), 137 deletions(-) delete mode 100644 tools/goctl/api/gogen/testdata/api_common.api delete mode 100644 tools/goctl/api/gogen/testdata/api_has_nested_type.api diff --git a/tools/goctl/api/docgen/doc.go b/tools/goctl/api/docgen/doc.go index ffa0e183..c4b0cbed 100644 --- a/tools/goctl/api/docgen/doc.go +++ b/tools/goctl/api/docgen/doc.go @@ -4,15 +4,15 @@ import ( "bytes" _ "embed" "fmt" - "go/format" "html/template" + "io" "strconv" "strings" "github.com/zeromicro/go-zero/core/stringx" - "github.com/zeromicro/go-zero/tools/goctl/api/gogen" "github.com/zeromicro/go-zero/tools/goctl/api/spec" - "github.com/zeromicro/go-zero/tools/goctl/api/util" + apiutil "github.com/zeromicro/go-zero/tools/goctl/api/util" + "github.com/zeromicro/go-zero/tools/goctl/util" ) //go:embed markdown.tpl @@ -23,7 +23,7 @@ func genDoc(api *spec.ApiSpec, dir, filename string) error { return nil } - fp, _, err := util.MaybeCreateFile(dir, "", filename) + fp, _, err := apiutil.MaybeCreateFile(dir, "", filename) if err != nil { return err } @@ -36,12 +36,12 @@ func genDoc(api *spec.ApiSpec, dir, filename string) error { routeComment = "N/A" } - requestContent, err := buildDoc(route.RequestType, api) + requestContent, err := buildDoc(route.RequestType, api.Types) if err != nil { return err } - responseContent, err := buildDoc(route.ResponseType, api) + responseContent, err := buildDoc(route.ResponseType, api.Types) if err != nil { return err } @@ -61,6 +61,7 @@ func genDoc(api *spec.ApiSpec, dir, filename string) error { if err != nil { return err } + builder.Write(tmplBytes.Bytes()) } @@ -68,7 +69,7 @@ func genDoc(api *spec.ApiSpec, dir, filename string) error { return err } -func buildDoc(route spec.Type, api *spec.ApiSpec) (string, error) { +func buildDoc(route spec.Type, types []spec.Type) (string, error) { if route == nil || len(route.Name()) == 0 { return "", nil } @@ -78,15 +79,12 @@ func buildDoc(route spec.Type, api *spec.ApiSpec) (string, error) { if definedType, ok := route.(spec.DefineStruct); ok { associatedTypes(definedType, &tps) } - value, err := gogen.BuildTypes(tps, api) + value, err := buildTypes(tps, types) if err != nil { return "", err } - formatted, err := format.Source([]byte(value)) - if err != nil { - return "", err - } - return fmt.Sprintf("\n\n```golang\n%s\n```\n", string(formatted)), nil + + return fmt.Sprintf("\n\n```golang\n%s\n```\n", value), nil } func associatedTypes(tp spec.DefineStruct, tps *[]spec.Type) { @@ -107,3 +105,82 @@ func associatedTypes(tp spec.DefineStruct, tps *[]spec.Type) { } } } + +// buildTypes gen types to string +func buildTypes(types []spec.Type, all []spec.Type) (string, error) { + var builder strings.Builder + first := true + for _, tp := range types { + if first { + first = false + } else { + builder.WriteString("\n\n") + } + if err := writeType(&builder, tp, all); err != nil { + return "", apiutil.WrapErr(err, "Type "+tp.Name()+" generate error") + } + } + + return builder.String(), nil +} + +func writeType(writer io.Writer, tp spec.Type, all []spec.Type) error { + fmt.Fprintf(writer, "type %s struct {\n", util.Title(tp.Name())) + if err := writerMembers(writer, tp, all); err != nil { + return err + } + fmt.Fprintf(writer, "}") + return nil +} + +func writerMembers(writer io.Writer, tp spec.Type, all []spec.Type) error { + structType, ok := tp.(spec.DefineStruct) + if !ok { + return fmt.Errorf("unspport struct type: %s", tp.Name()) + } + + getTargetType := func(tp string) spec.Type { + for _, v := range all { + if v.Name() == tp { + return v + } + } + return nil + } + for _, member := range structType.Members { + if member.IsInline { + inlineType := getTargetType(member.Type.Name()) + if inlineType == nil { + if _, err := fmt.Fprintf(writer, "%s\n", strings.Title(member.Type.Name())); err != nil { + return err + } + } else { + if err := writerMembers(writer, inlineType, all); err != nil { + return err + } + } + + continue + } + + if err := writeProperty(writer, member.Name, member.Tag, member.GetComment(), member.Type, 1); err != nil { + return err + } + } + + return nil +} + +func writeProperty(writer io.Writer, name, tag, comment string, tp spec.Type, indent int) error { + apiutil.WriteIndent(writer, indent) + var err error + 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 +} diff --git a/tools/goctl/api/gogen/gentypes.go b/tools/goctl/api/gogen/gentypes.go index 3b2e53ad..9e91735f 100644 --- a/tools/goctl/api/gogen/gentypes.go +++ b/tools/goctl/api/gogen/gentypes.go @@ -21,7 +21,7 @@ const typesFile = "types" var typesTemplate string // BuildTypes gen types to string -func BuildTypes(types []spec.Type, api *spec.ApiSpec) (string, error) { +func BuildTypes(types []spec.Type) (string, error) { var builder strings.Builder first := true for _, tp := range types { @@ -30,7 +30,7 @@ func BuildTypes(types []spec.Type, api *spec.ApiSpec) (string, error) { } else { builder.WriteString("\n\n") } - if err := writeType(&builder, tp, api); err != nil { + if err := writeType(&builder, tp); err != nil { return "", apiutil.WrapErr(err, "Type "+tp.Name()+" generate error") } } @@ -39,7 +39,7 @@ func BuildTypes(types []spec.Type, api *spec.ApiSpec) (string, error) { } func genTypes(dir string, cfg *config.Config, api *spec.ApiSpec) error { - val, err := BuildTypes(api.Types, api) + val, err := BuildTypes(api.Types) if err != nil { 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, api *spec.ApiSpec) error { +func writeType(writer io.Writer, tp spec.Type) error { structType, ok := tp.(spec.DefineStruct) if !ok { return fmt.Errorf("unspport struct type: %s", tp.Name()) @@ -76,7 +76,15 @@ func writeType(writer io.Writer, tp spec.Type, api *spec.ApiSpec) error { fmt.Fprintf(writer, "type %s struct {\n", util.Title(tp.Name())) for _, member := range structType.Members { - if err := writeProperty(writer, member.Name, member.Tag, member.GetComment(), member.Type, 1, api); err != nil { + if member.IsInline { + 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 } } diff --git a/tools/goctl/api/gogen/testdata/api_common.api b/tools/goctl/api/gogen/testdata/api_common.api deleted file mode 100644 index 3cdfe869..00000000 --- a/tools/goctl/api/gogen/testdata/api_common.api +++ /dev/null @@ -1,3 +0,0 @@ -type Common { - Some string `json:"some"` // some imported type -} \ No newline at end of file diff --git a/tools/goctl/api/gogen/testdata/api_has_nested_type.api b/tools/goctl/api/gogen/testdata/api_has_nested_type.api deleted file mode 100644 index e75ae13d..00000000 --- a/tools/goctl/api/gogen/testdata/api_has_nested_type.api +++ /dev/null @@ -1,48 +0,0 @@ -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) -} \ No newline at end of file diff --git a/tools/goctl/api/gogen/util.go b/tools/goctl/api/gogen/util.go index 82e259e3..a8798ebd 100644 --- a/tools/goctl/api/gogen/util.go +++ b/tools/goctl/api/gogen/util.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "io" - "os" "strings" "text/template" @@ -58,21 +57,15 @@ func genFile(c fileGenConfig) error { return err } -func writeProperty(writer io.Writer, name, tag, comment string, tp spec.Type, indent int, api *spec.ApiSpec) error { +func writeProperty(writer io.Writer, name, tag, comment string, tp spec.Type, indent int) error { util.WriteIndent(writer, indent) var err error - var refPropertyName = tp.Name() - if isCustomType(refPropertyName) { - strs := getRefProperty(api, refPropertyName, name) - _, err = fmt.Fprintf(writer, "%s\n", strs) + 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 { - 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) - } + _, err = fmt.Fprintf(writer, "%s %s %s\n", strings.Title(name), tp.Name(), tag) } return err @@ -188,58 +181,3 @@ func golangExpr(ty spec.Type, pkg ...string) string { 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] - }) - } -}