optimized goctl format (#336)
* fix format * refactor * refactor * optimized * refactor * refactor * refactor * add js path prefix
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
|||||||
"bufio"
|
"bufio"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"go/format"
|
||||||
"go/scanner"
|
"go/scanner"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@@ -13,6 +14,7 @@ import (
|
|||||||
"github.com/tal-tech/go-zero/core/errorx"
|
"github.com/tal-tech/go-zero/core/errorx"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
|
"github.com/tal-tech/go-zero/tools/goctl/api/parser"
|
||||||
"github.com/tal-tech/go-zero/tools/goctl/api/util"
|
"github.com/tal-tech/go-zero/tools/goctl/api/util"
|
||||||
|
ctlutil "github.com/tal-tech/go-zero/tools/goctl/util"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -103,24 +105,108 @@ func apiFormat(data string) (string, error) {
|
|||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
s := bufio.NewScanner(strings.NewReader(data))
|
s := bufio.NewScanner(strings.NewReader(data))
|
||||||
var tapCount = 0
|
var tapCount = 0
|
||||||
|
var newLineCount = 0
|
||||||
|
var preLine string
|
||||||
for s.Scan() {
|
for s.Scan() {
|
||||||
line := strings.TrimSpace(s.Text())
|
line := strings.TrimSpace(s.Text())
|
||||||
|
if len(line) == 0 {
|
||||||
|
if newLineCount > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newLineCount++
|
||||||
|
} else {
|
||||||
|
if preLine == rightBrace {
|
||||||
|
builder.WriteString(ctlutil.NL)
|
||||||
|
}
|
||||||
|
newLineCount = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if tapCount == 0 {
|
||||||
|
format, err := formatGoTypeDef(line, s, &builder)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if format {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
noCommentLine := util.RemoveComment(line)
|
noCommentLine := util.RemoveComment(line)
|
||||||
if noCommentLine == rightParenthesis || noCommentLine == rightBrace {
|
if noCommentLine == rightParenthesis || noCommentLine == rightBrace {
|
||||||
tapCount -= 1
|
tapCount -= 1
|
||||||
}
|
}
|
||||||
if tapCount < 0 {
|
if tapCount < 0 {
|
||||||
line = strings.TrimSuffix(line, rightBrace)
|
line := strings.TrimSuffix(noCommentLine, rightBrace)
|
||||||
line = strings.TrimSpace(line)
|
line = strings.TrimSpace(line)
|
||||||
if strings.HasSuffix(line, leftBrace) {
|
if strings.HasSuffix(line, leftBrace) {
|
||||||
tapCount += 1
|
tapCount += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
util.WriteIndent(&builder, tapCount)
|
util.WriteIndent(&builder, tapCount)
|
||||||
builder.WriteString(line + "\n")
|
builder.WriteString(line + ctlutil.NL)
|
||||||
if strings.HasSuffix(noCommentLine, leftParenthesis) || strings.HasSuffix(noCommentLine, leftBrace) {
|
if strings.HasSuffix(noCommentLine, leftParenthesis) || strings.HasSuffix(noCommentLine, leftBrace) {
|
||||||
tapCount += 1
|
tapCount += 1
|
||||||
}
|
}
|
||||||
|
preLine = line
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(builder.String()), nil
|
return strings.TrimSpace(builder.String()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func formatGoTypeDef(line string, scanner *bufio.Scanner, builder *strings.Builder) (bool, error) {
|
||||||
|
noCommentLine := util.RemoveComment(line)
|
||||||
|
tokenCount := 0
|
||||||
|
if strings.HasPrefix(noCommentLine, "type") && (strings.HasSuffix(noCommentLine, leftParenthesis) ||
|
||||||
|
strings.HasSuffix(noCommentLine, leftBrace)) {
|
||||||
|
var typeBuilder strings.Builder
|
||||||
|
typeBuilder.WriteString(mayInsertStructKeyword(line, &tokenCount) + ctlutil.NL)
|
||||||
|
for scanner.Scan() {
|
||||||
|
noCommentLine := util.RemoveComment(scanner.Text())
|
||||||
|
typeBuilder.WriteString(mayInsertStructKeyword(scanner.Text(), &tokenCount) + ctlutil.NL)
|
||||||
|
if noCommentLine == rightBrace || noCommentLine == rightParenthesis {
|
||||||
|
tokenCount--
|
||||||
|
}
|
||||||
|
if tokenCount == 0 {
|
||||||
|
ts, err := format.Source([]byte(typeBuilder.String()))
|
||||||
|
if err != nil {
|
||||||
|
return false, errors.New("error format \n" + typeBuilder.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
result := strings.ReplaceAll(string(ts), " struct ", " ")
|
||||||
|
result = strings.ReplaceAll(result, "type ()", "")
|
||||||
|
builder.WriteString(result)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mayInsertStructKeyword(line string, token *int) string {
|
||||||
|
insertStruct := func() string {
|
||||||
|
if strings.Contains(line, " struct") {
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
index := strings.Index(line, leftBrace)
|
||||||
|
return line[:index] + " struct " + line[index:]
|
||||||
|
}
|
||||||
|
|
||||||
|
noCommentLine := util.RemoveComment(line)
|
||||||
|
if strings.HasSuffix(noCommentLine, leftBrace) {
|
||||||
|
*token++
|
||||||
|
return insertStruct()
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(noCommentLine, rightBrace) {
|
||||||
|
noCommentLine = strings.TrimSuffix(noCommentLine, rightBrace)
|
||||||
|
noCommentLine = util.RemoveComment(noCommentLine)
|
||||||
|
if strings.HasSuffix(noCommentLine, leftBrace) {
|
||||||
|
return insertStruct()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if strings.HasSuffix(noCommentLine, leftParenthesis) {
|
||||||
|
*token++
|
||||||
|
}
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ handler: GreetHandler
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
formattedStr = `type Request struct {
|
formattedStr = `type Request {
|
||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
type Response struct {
|
type Response {
|
||||||
Message string
|
Message string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ service A-api {
|
|||||||
}`
|
}`
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInlineTypeNotExist(t *testing.T) {
|
func TestFormat(t *testing.T) {
|
||||||
r, err := apiFormat(notFormattedStr)
|
r, err := apiFormat(notFormattedStr)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, r, formattedStr)
|
assert.Equal(t, r, formattedStr)
|
||||||
|
|||||||
@@ -90,6 +90,12 @@ func writeType(writer io.Writer, tp spec.Type, types []spec.Type) error {
|
|||||||
|
|
||||||
func writeMembers(writer io.Writer, types []spec.Type, members []spec.Member, allMembers *[]spec.Member, indent int) error {
|
func writeMembers(writer io.Writer, types []spec.Type, members []spec.Member, allMembers *[]spec.Member, indent int) error {
|
||||||
for _, member := range members {
|
for _, member := range members {
|
||||||
|
if !member.IsInline {
|
||||||
|
_, err := member.GetPropertyName()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
if !member.IsBodyMember() {
|
if !member.IsBodyMember() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,10 +63,6 @@ func (m Member) IsOmitempty() bool {
|
|||||||
|
|
||||||
func (m Member) GetPropertyName() (string, error) {
|
func (m Member) GetPropertyName() (string, error) {
|
||||||
tags := m.Tags()
|
tags := m.Tags()
|
||||||
if len(tags) == 0 {
|
|
||||||
return "", errors.New("json property name not exist, member: " + m.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
if stringx.Contains(definedKeys, tag.Key) {
|
if stringx.Contains(definedKeys, tag.Key) {
|
||||||
if tag.Name == "-" {
|
if tag.Name == "-" {
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ func genHandler(dir, webApi, caller string, api *spec.ApiSpec, unwrapApi bool) e
|
|||||||
imports += fmt.Sprintf(`import * as components from "%s"`, "./"+outputFile)
|
imports += fmt.Sprintf(`import * as components from "%s"`, "./"+outputFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
apis, err := genApi(api, localTypes, caller, prefixForType)
|
apis, err := genApi(api, caller, prefixForType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -119,32 +119,34 @@ func genTypes(localTypes []spec.Type, inlineType func(string) (*spec.Type, error
|
|||||||
return types, nil
|
return types, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func genApi(api *spec.ApiSpec, localTypes []spec.Type, caller string, prefixForType func(string) string) (string, error) {
|
func genApi(api *spec.ApiSpec, caller string, prefixForType func(string) string) (string, error) {
|
||||||
var builder strings.Builder
|
var builder strings.Builder
|
||||||
for _, route := range api.Service.Routes() {
|
for _, group := range api.Service.Groups {
|
||||||
handler, ok := apiutil.GetAnnotationValue(route.Annotations, "server", "handler")
|
for _, route := range group.Routes {
|
||||||
if !ok {
|
handler, ok := apiutil.GetAnnotationValue(route.Annotations, "server", "handler")
|
||||||
return "", fmt.Errorf("missing handler annotation for route %q", route.Path)
|
if !ok {
|
||||||
}
|
return "", fmt.Errorf("missing handler annotation for route %q", route.Path)
|
||||||
handler = util.Untitle(handler)
|
|
||||||
handler = strings.Replace(handler, "Handler", "", 1)
|
|
||||||
comment := commentForRoute(route)
|
|
||||||
if len(comment) > 0 {
|
|
||||||
fmt.Fprintf(&builder, "%s\n", comment)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(&builder, "export function %s(%s) {\n", handler, paramsForRoute(route, prefixForType))
|
|
||||||
writeIndent(&builder, 1)
|
|
||||||
responseGeneric := "<null>"
|
|
||||||
if len(route.ResponseType.Name) > 0 {
|
|
||||||
val, err := goTypeToTs(route.ResponseType.Name, prefixForType)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
}
|
||||||
responseGeneric = fmt.Sprintf("<%s>", val)
|
handler = util.Untitle(handler)
|
||||||
|
handler = strings.Replace(handler, "Handler", "", 1)
|
||||||
|
comment := commentForRoute(route)
|
||||||
|
if len(comment) > 0 {
|
||||||
|
fmt.Fprintf(&builder, "%s\n", comment)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&builder, "export function %s(%s) {\n", handler, paramsForRoute(route, prefixForType))
|
||||||
|
writeIndent(&builder, 1)
|
||||||
|
responseGeneric := "<null>"
|
||||||
|
if len(route.ResponseType.Name) > 0 {
|
||||||
|
val, err := goTypeToTs(route.ResponseType.Name, prefixForType)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
responseGeneric = fmt.Sprintf("<%s>", val)
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&builder, `return %s.%s%s(%s)`, caller, strings.ToLower(route.Method),
|
||||||
|
util.Title(responseGeneric), callParamsForRoute(route, group))
|
||||||
|
builder.WriteString("\n}\n\n")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&builder, `return %s.%s%s(%s)`, caller, strings.ToLower(route.Method),
|
|
||||||
util.Title(responseGeneric), callParamsForRoute(route))
|
|
||||||
builder.WriteString("\n}\n\n")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
apis := builder.String()
|
apis := builder.String()
|
||||||
@@ -188,21 +190,28 @@ func commentForRoute(route spec.Route) string {
|
|||||||
return builder.String()
|
return builder.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func callParamsForRoute(route spec.Route) string {
|
func callParamsForRoute(route spec.Route, group spec.Group) string {
|
||||||
hasParams := pathHasParams(route)
|
hasParams := pathHasParams(route)
|
||||||
hasBody := hasRequestBody(route)
|
hasBody := hasRequestBody(route)
|
||||||
if hasParams && hasBody {
|
if hasParams && hasBody {
|
||||||
return fmt.Sprintf("%s, %s, %s", pathForRoute(route), "params", "req")
|
return fmt.Sprintf("%s, %s, %s", pathForRoute(route, group), "params", "req")
|
||||||
} else if hasParams {
|
} else if hasParams {
|
||||||
return fmt.Sprintf("%s, %s", pathForRoute(route), "params")
|
return fmt.Sprintf("%s, %s", pathForRoute(route, group), "params")
|
||||||
} else if hasBody {
|
} else if hasBody {
|
||||||
return fmt.Sprintf("%s, %s", pathForRoute(route), "req")
|
return fmt.Sprintf("%s, %s", pathForRoute(route, group), "req")
|
||||||
}
|
}
|
||||||
return pathForRoute(route)
|
return pathForRoute(route, group)
|
||||||
}
|
}
|
||||||
|
|
||||||
func pathForRoute(route spec.Route) string {
|
func pathForRoute(route spec.Route, group spec.Group) string {
|
||||||
return "\"" + route.Path + "\""
|
value, ok := apiutil.GetAnnotationValue(group.Annotations, "server", pathPrefix)
|
||||||
|
if !ok {
|
||||||
|
return "\"" + route.Path + "\""
|
||||||
|
} else {
|
||||||
|
value = strings.TrimPrefix(value, `"`)
|
||||||
|
value = strings.TrimSuffix(value, `"`)
|
||||||
|
return fmt.Sprintf(`"%s/%s"`, value, strings.TrimPrefix(route.Path, "/"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func pathHasParams(route spec.Route) bool {
|
func pathHasParams(route spec.Route) bool {
|
||||||
|
|||||||
@@ -2,4 +2,5 @@ package tsgen
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
packagePrefix = "components."
|
packagePrefix = "components."
|
||||||
|
pathPrefix = "pathPrefix"
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user