瀏覽代碼

fix: issue #2359 (#2368)

* Revert changes

* Unrap nested structure for doc code generation

* Revert changes

* Remove useless code

* Remove useless code

* Format code
anqiansong 2 年之前
父節點
當前提交
9581e8445a

+ 90 - 13
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
+}

+ 13 - 5
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
 		}
 	}

+ 0 - 3
tools/goctl/api/gogen/testdata/api_common.api

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

+ 0 - 48
tools/goctl/api/gogen/testdata/api_has_nested_type.api

@@ -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)
-}

+ 6 - 68
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]
-		})
-	}
-}