goctl added
This commit is contained in:
13
tools/goctl/api/util/annotation.go
Normal file
13
tools/goctl/api/util/annotation.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package util
|
||||
|
||||
import "zero/tools/goctl/api/spec"
|
||||
|
||||
func GetAnnotationValue(annos []spec.Annotation, key, field string) (string, bool) {
|
||||
for _, anno := range annos {
|
||||
if anno.Name == key {
|
||||
value, ok := anno.Properties[field]
|
||||
return value, ok
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
107
tools/goctl/api/util/case.go
Normal file
107
tools/goctl/api/util/case.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package util
|
||||
|
||||
func IsUpperCase(r rune) bool {
|
||||
if r >= 'A' && r <= 'Z' {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func IsLowerCase(r rune) bool {
|
||||
if r >= 'a' && r <= 'z' {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func ToSnakeCase(s string) string {
|
||||
out := []rune{}
|
||||
for index, r := range s {
|
||||
if index == 0 {
|
||||
out = append(out, ToLowerCase(r))
|
||||
continue
|
||||
}
|
||||
|
||||
if IsUpperCase(r) && index != 0 {
|
||||
if IsLowerCase(rune(s[index-1])) {
|
||||
out = append(out, '_', ToLowerCase(r))
|
||||
continue
|
||||
}
|
||||
if index < len(s)-1 && IsLowerCase(rune(s[index+1])) {
|
||||
out = append(out, '_', ToLowerCase(r))
|
||||
continue
|
||||
}
|
||||
out = append(out, ToLowerCase(r))
|
||||
continue
|
||||
}
|
||||
out = append(out, r)
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func ToCamelCase(s string) string {
|
||||
s = ToLower(s)
|
||||
out := []rune{}
|
||||
for index, r := range s {
|
||||
if r == '_' {
|
||||
continue
|
||||
}
|
||||
if index == 0 {
|
||||
out = append(out, ToUpperCase(r))
|
||||
continue
|
||||
}
|
||||
|
||||
if index > 0 && s[index-1] == '_' {
|
||||
out = append(out, ToUpperCase(r))
|
||||
continue
|
||||
}
|
||||
|
||||
out = append(out, r)
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func ToLowerCase(r rune) rune {
|
||||
dx := 'A' - 'a'
|
||||
if IsUpperCase(r) {
|
||||
return r - dx
|
||||
}
|
||||
return r
|
||||
}
|
||||
func ToUpperCase(r rune) rune {
|
||||
dx := 'A' - 'a'
|
||||
if IsLowerCase(r) {
|
||||
return r + dx
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func ToLower(s string) string {
|
||||
out := []rune{}
|
||||
for _, r := range s {
|
||||
out = append(out, ToLowerCase(r))
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func ToUpper(s string) string {
|
||||
out := []rune{}
|
||||
for _, r := range s {
|
||||
out = append(out, ToUpperCase(r))
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
func LowerFirst(s string) string {
|
||||
if len(s) == 0 {
|
||||
return s
|
||||
}
|
||||
return ToLower(s[:1]) + s[1:]
|
||||
}
|
||||
|
||||
func UpperFirst(s string) string {
|
||||
if len(s) == 0 {
|
||||
return s
|
||||
}
|
||||
return ToUpper(s[:1]) + s[1:]
|
||||
}
|
||||
58
tools/goctl/api/util/tag.go
Normal file
58
tools/goctl/api/util/tag.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func TagLookup(tag, key string) (value string, ok bool) {
|
||||
tag = strings.Replace(tag, "`", "", -1)
|
||||
for tag != "" {
|
||||
// Skip leading space.
|
||||
i := 0
|
||||
for i < len(tag) && tag[i] == ' ' {
|
||||
i++
|
||||
}
|
||||
tag = tag[i:]
|
||||
if tag == "" {
|
||||
break
|
||||
}
|
||||
|
||||
// Scan to colon. A space, a quote or a control character is a syntax error.
|
||||
// Strictly speaking, control chars include the range [0x7f, 0x9f], not just
|
||||
// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
|
||||
// as it is simpler to inspect the tag's bytes than the tag's runes.
|
||||
i = 0
|
||||
for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
|
||||
i++
|
||||
}
|
||||
if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
|
||||
break
|
||||
}
|
||||
name := string(tag[:i])
|
||||
tag = tag[i+1:]
|
||||
|
||||
// Scan quoted string to find value.
|
||||
i = 1
|
||||
for i < len(tag) && tag[i] != '"' {
|
||||
if tag[i] == '\\' {
|
||||
i++
|
||||
}
|
||||
i++
|
||||
}
|
||||
if i >= len(tag) {
|
||||
break
|
||||
}
|
||||
qvalue := string(tag[:i+1])
|
||||
tag = tag[i+1:]
|
||||
|
||||
if key == name {
|
||||
value, err := strconv.Unquote(qvalue)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
return value, true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
159
tools/goctl/api/util/types.go
Normal file
159
tools/goctl/api/util/types.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"zero/tools/goctl/api/spec"
|
||||
)
|
||||
|
||||
func DecomposeType(t string) (result []string, err error) {
|
||||
add := func(tp string) error {
|
||||
ret, err := DecomposeType(tp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
result = append(result, ret...)
|
||||
return nil
|
||||
}
|
||||
if strings.HasPrefix(t, "map") {
|
||||
t = strings.ReplaceAll(t, "map", "")
|
||||
if t[0] == '[' {
|
||||
pos := strings.Index(t, "]")
|
||||
if pos > 1 {
|
||||
if err = add(t[1:pos]); err != nil {
|
||||
return
|
||||
}
|
||||
if len(t) > pos+1 {
|
||||
err = add(t[pos+1:])
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if strings.HasPrefix(t, "[]") {
|
||||
if len(t) > 2 {
|
||||
err = add(t[2:])
|
||||
return
|
||||
}
|
||||
} else if strings.HasPrefix(t, "*") {
|
||||
err = add(t[1:])
|
||||
return
|
||||
} else {
|
||||
result = append(result, t)
|
||||
return
|
||||
}
|
||||
|
||||
err = fmt.Errorf("bad type %q", t)
|
||||
return
|
||||
}
|
||||
|
||||
func GetAllTypes(api *spec.ApiSpec, route spec.Route) []spec.Type {
|
||||
var rts []spec.Type
|
||||
types := api.Types
|
||||
getTypeRecursive(route.RequestType, types, &rts)
|
||||
getTypeRecursive(route.ResponseType, types, &rts)
|
||||
return rts
|
||||
}
|
||||
|
||||
func GetLocalTypes(api *spec.ApiSpec, route spec.Route) []spec.Type {
|
||||
sharedTypes := GetSharedTypes(api)
|
||||
isSharedType := func(ty spec.Type) bool {
|
||||
for _, item := range sharedTypes {
|
||||
if item.Name == ty.Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var rts = GetAllTypes(api, route)
|
||||
|
||||
var result []spec.Type
|
||||
for _, item := range rts {
|
||||
if !isSharedType(item) {
|
||||
result = append(result, item)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func getTypeRecursive(ty spec.Type, allTypes []spec.Type, result *[]spec.Type) {
|
||||
isCustomType := func(name string) (*spec.Type, bool) {
|
||||
for _, item := range allTypes {
|
||||
if item.Name == name {
|
||||
return &item, true
|
||||
}
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
if len(ty.Name) > 0 {
|
||||
*result = append(*result, ty)
|
||||
}
|
||||
for _, member := range ty.Members {
|
||||
decomposedItems, _ := DecomposeType(member.Type)
|
||||
if len(decomposedItems) == 0 {
|
||||
continue
|
||||
}
|
||||
var customTypes []spec.Type
|
||||
for _, item := range decomposedItems {
|
||||
c, e := isCustomType(item)
|
||||
if e {
|
||||
customTypes = append(customTypes, *c)
|
||||
}
|
||||
}
|
||||
for _, ty := range customTypes {
|
||||
hasAppend := false
|
||||
for _, item := range *result {
|
||||
if ty.Name == item.Name {
|
||||
hasAppend = true
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
if !hasAppend {
|
||||
getTypeRecursive(ty, allTypes, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetSharedTypes(api *spec.ApiSpec) []spec.Type {
|
||||
types := api.Types
|
||||
var result []spec.Type
|
||||
var container []spec.Type
|
||||
hasInclude := func(all []spec.Type, ty spec.Type) bool {
|
||||
for _, item := range all {
|
||||
if item.Name == ty.Name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
for _, route := range api.Service.Routes {
|
||||
var rts []spec.Type
|
||||
getTypeRecursive(route.RequestType, types, &rts)
|
||||
getTypeRecursive(route.ResponseType, types, &rts)
|
||||
for _, item := range rts {
|
||||
if len(item.Name) == 0 {
|
||||
continue
|
||||
}
|
||||
if hasInclude(container, item) {
|
||||
hasAppend := false
|
||||
for _, r := range result {
|
||||
if item.Name == r.Name {
|
||||
hasAppend = true
|
||||
break
|
||||
}
|
||||
|
||||
}
|
||||
if !hasAppend {
|
||||
result = append(result, item)
|
||||
}
|
||||
} else {
|
||||
container = append(container, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
74
tools/goctl/api/util/util.go
Normal file
74
tools/goctl/api/util/util.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"zero/tools/goctl/api/spec"
|
||||
|
||||
"zero/core/lang"
|
||||
"zero/tools/goctl/util"
|
||||
)
|
||||
|
||||
func MaybeCreateFile(dir, subdir, file string) (fp *os.File, created bool, err error) {
|
||||
lang.Must(util.MkdirIfNotExist(path.Join(dir, subdir)))
|
||||
fpath := path.Join(dir, subdir, file)
|
||||
if util.FileExists(fpath) {
|
||||
fmt.Printf("%s exists, ignored generation\n", fpath)
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
fp, err = util.CreateIfNotExist(fpath)
|
||||
created = err == nil
|
||||
return
|
||||
}
|
||||
|
||||
func ClearAndOpenFile(fpath string) (*os.File, error) {
|
||||
f, err := os.OpenFile(fpath, os.O_WRONLY|os.O_TRUNC, 0600)
|
||||
|
||||
_, err = f.WriteString("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func WrapErr(err error, message string) error {
|
||||
return errors.New(message + ", " + err.Error())
|
||||
}
|
||||
|
||||
func Copy(src, dst string) (int64, error) {
|
||||
sourceFileStat, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if !sourceFileStat.Mode().IsRegular() {
|
||||
return 0, fmt.Errorf("%s is not a regular file", src)
|
||||
}
|
||||
|
||||
source, err := os.Open(src)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer source.Close()
|
||||
|
||||
destination, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer destination.Close()
|
||||
nBytes, err := io.Copy(destination, source)
|
||||
return nBytes, err
|
||||
}
|
||||
|
||||
func ComponentName(api *spec.ApiSpec) string {
|
||||
name := api.Service.Name
|
||||
if strings.HasSuffix(name, "-api") {
|
||||
return name[:len(name)-4] + "Components"
|
||||
}
|
||||
return name + "Components"
|
||||
}
|
||||
Reference in New Issue
Block a user