support bridge and makeTS
This commit is contained in:
parent
e9c25edc20
commit
31df7db22d
2
args.go
2
args.go
@ -25,7 +25,7 @@ type Obj struct {
|
||||
|
||||
func GetLogger(vm *goja.Runtime) *log.Logger {
|
||||
var logger *log.Logger
|
||||
if vm.GoData["logger"] != nil {
|
||||
if vm != nil && vm.GoData != nil && vm.GoData["logger"] != nil {
|
||||
if logger1, ok := vm.GoData["logger"].(*log.Logger); ok {
|
||||
logger = logger1
|
||||
}
|
||||
|
255
bridge.go
Normal file
255
bridge.go
Normal file
@ -0,0 +1,255 @@
|
||||
package gojs
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"apigo.cc/gojs/goja"
|
||||
"github.com/ssgo/u"
|
||||
)
|
||||
|
||||
func ToJS(in any) any {
|
||||
return go2js(in, 0)
|
||||
}
|
||||
|
||||
func ToMap(in any) Map {
|
||||
jsValue := go2js(in, 0)
|
||||
if mapValue, ok := jsValue.(Map); ok {
|
||||
return mapValue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func go2js(in any, n int) any {
|
||||
if n > 100 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var v reflect.Value
|
||||
if inV, ok := in.(reflect.Value); ok {
|
||||
v = inV
|
||||
} else {
|
||||
v = reflect.ValueOf(in)
|
||||
}
|
||||
for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
|
||||
if v.IsNil() {
|
||||
return nil
|
||||
}
|
||||
v = v.Elem()
|
||||
}
|
||||
if (v.Kind() == reflect.Slice || v.Kind() == reflect.Map || v.Kind() == reflect.Func) && v.IsNil() {
|
||||
return nil
|
||||
}
|
||||
if v.Kind() == reflect.Struct {
|
||||
v = reflect.ValueOf(MakeMap(in))
|
||||
}
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 {
|
||||
arr := make([]any, v.Len())
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
o := go2js(v.Index(i), n+1)
|
||||
arr[i] = o
|
||||
}
|
||||
return arr
|
||||
} else {
|
||||
return in
|
||||
}
|
||||
case reflect.Map:
|
||||
o := map[string]any{}
|
||||
for _, k2 := range v.MapKeys() {
|
||||
k2s := u.String(u.FinalValue(k2).Interface())
|
||||
if len(k2s) > 0 && k2s[0] != '_' {
|
||||
v2 := go2js(v.MapIndex(k2), n+1)
|
||||
o[k2s] = v2
|
||||
}
|
||||
}
|
||||
return o
|
||||
case reflect.Func:
|
||||
// skip goja supported functions
|
||||
switch v.Type().String() {
|
||||
case "func(goja.FunctionCall) goja.Value":
|
||||
return in
|
||||
case "func(goja.FunctionCall, *goja.Runtime) goja.Value":
|
||||
return in
|
||||
case "func(goja.ConstructorCall) *goja.Object":
|
||||
return in
|
||||
case "func(goja.ConstructorCall, *goja.Runtime) *goja.Object":
|
||||
return in
|
||||
}
|
||||
|
||||
t := v.Type()
|
||||
return func(argsIn goja.FunctionCall, vm *goja.Runtime) goja.Value {
|
||||
needArgs := make([]reflect.Type, 0)
|
||||
realArgs := make([]reflect.Value, t.NumIn())
|
||||
needArgsIndex := map[int]int{}
|
||||
for i := 0; i < t.NumIn(); i++ {
|
||||
inTypeString := t.In(i).String()
|
||||
|
||||
if inTypeString == "*goja.Runtime" {
|
||||
realArgs[i] = reflect.ValueOf(vm)
|
||||
continue
|
||||
} else if inTypeString == "goja.Value" {
|
||||
realArgs[i] = reflect.ValueOf(argsIn.This)
|
||||
continue
|
||||
}
|
||||
if !realArgs[i].IsValid() {
|
||||
needArgs = append(needArgs, t.In(i))
|
||||
needArgsIndex[len(needArgsIndex)] = i
|
||||
}
|
||||
}
|
||||
|
||||
for i, needArgType := range needArgs {
|
||||
var argValue reflect.Value
|
||||
isLastVariadicArg := false
|
||||
realNeedArgType := needArgType
|
||||
if needArgType.Kind() == reflect.Ptr {
|
||||
realNeedArgType = needArgType.Elem()
|
||||
}
|
||||
|
||||
if v.Type().IsVariadic() && needArgsIndex[i] == len(realArgs)-1 {
|
||||
// 可变参数函数的最后一个使用成员类型
|
||||
isLastVariadicArg = true
|
||||
argValue = reflect.New(needArgType.Elem())
|
||||
} else {
|
||||
argValue = reflect.New(needArgType)
|
||||
}
|
||||
if i > len(argsIn.Arguments)-1 {
|
||||
if !isLastVariadicArg && needArgType.Kind() != reflect.Interface && needArgType.Kind() != reflect.Ptr {
|
||||
panic(vm.NewGoError(fmt.Errorf("no enough args, need %d, given %d", len(needArgs), len(argsIn.Arguments))))
|
||||
}
|
||||
realArgs[needArgsIndex[i]] = reflect.ValueOf(argValue.Interface()).Elem()
|
||||
} else if realNeedArgType.Kind() == reflect.Func {
|
||||
jsFunc, ok := goja.AssertFunction(argsIn.Arguments[i])
|
||||
if !ok {
|
||||
panic(vm.NewGoError(fmt.Errorf("%s not a function", argsIn.Arguments[i].ExportType().String())))
|
||||
}
|
||||
|
||||
funcType := realNeedArgType
|
||||
argValue = reflect.MakeFunc(funcType, func(goArgs []reflect.Value) []reflect.Value {
|
||||
ins := make([]goja.Value, 0)
|
||||
j := 0
|
||||
for i := 0; i < len(goArgs); i++ {
|
||||
if j >= funcType.NumIn() {
|
||||
break
|
||||
}
|
||||
var jV any
|
||||
if funcType.IsVariadic() && j == funcType.NumIn()-1 && funcType.In(j).Kind() == reflect.Slice {
|
||||
jV = reflect.New(funcType.In(j).Elem()).Interface()
|
||||
} else {
|
||||
jV = reflect.New(funcType.In(j)).Interface()
|
||||
j++
|
||||
}
|
||||
u.Convert(goArgs[i].Interface(), jV)
|
||||
// ins = append(ins, MakeJsValue(vm, reflect.ValueOf(jV).Elem(), false))
|
||||
ins = append(ins, vm.ToValue(jV))
|
||||
}
|
||||
|
||||
outs := make([]reflect.Value, 0)
|
||||
jsResult, err := jsFunc(argsIn.This, ins...)
|
||||
|
||||
if funcType.NumOut() == 1 {
|
||||
// 只有一个返回值
|
||||
if funcType.Out(0).String() != "error" {
|
||||
out0P := reflect.New(funcType.Out(0)).Interface()
|
||||
u.Convert(jsResult.Export(), out0P)
|
||||
outs = append(outs, reflect.ValueOf(out0P).Elem())
|
||||
} else {
|
||||
if err == nil {
|
||||
outs = append(outs, reflect.New(funcType.Out(0)).Elem())
|
||||
} else {
|
||||
outs = append(outs, reflect.ValueOf(err))
|
||||
}
|
||||
}
|
||||
} else if funcType.NumOut() > 1 {
|
||||
// 以数组形式返回多个值
|
||||
rArr := make([]any, 0)
|
||||
if err == nil {
|
||||
if jsResult.ExportType().Kind() == reflect.Slice && jsResult.ExportType().Elem().Kind() != reflect.Uint8 {
|
||||
vm.ForOf(jsResult, func(v goja.Value) bool {
|
||||
rArr = append(rArr, v.Export())
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
k := 0
|
||||
for j := 0; j < funcType.NumOut(); j++ {
|
||||
if funcType.Out(j).String() != "error" {
|
||||
if k < len(rArr) {
|
||||
out0P := reflect.New(funcType.Out(j)).Interface()
|
||||
u.Convert(rArr[k], out0P)
|
||||
k++
|
||||
outs = append(outs, reflect.ValueOf(out0P).Elem())
|
||||
} else {
|
||||
outs = append(outs, reflect.New(funcType.Out(j)).Elem())
|
||||
}
|
||||
} else {
|
||||
if err == nil {
|
||||
outs = append(outs, reflect.New(funcType.Out(j)).Elem())
|
||||
} else {
|
||||
outs = append(outs, reflect.ValueOf(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return outs
|
||||
})
|
||||
if needArgType.Kind() == reflect.Ptr {
|
||||
argValueP := reflect.New(realNeedArgType)
|
||||
argValueP.Elem().Set(argValue)
|
||||
realArgs[needArgsIndex[i]] = argValueP
|
||||
} else {
|
||||
realArgs[needArgsIndex[i]] = argValue
|
||||
}
|
||||
} else {
|
||||
argValueP := argValue.Interface()
|
||||
u.Convert(argsIn.Arguments[i].Export(), argValueP)
|
||||
argValue = reflect.ValueOf(argValueP).Elem()
|
||||
realArgs[needArgsIndex[i]] = argValue
|
||||
}
|
||||
}
|
||||
|
||||
// 处理可变参数
|
||||
if len(argsIn.Arguments) > len(needArgs) {
|
||||
lastArgType := needArgs[len(needArgs)-1]
|
||||
if lastArgType.Kind() == reflect.Slice && lastArgType.Elem().Kind() != reflect.Uint8 {
|
||||
for i := len(needArgs); i < len(argsIn.Arguments); i++ {
|
||||
argValue := reflect.New(lastArgType.Elem()).Interface()
|
||||
u.Convert(argsIn.Arguments[i].Export(), argValue)
|
||||
realArgs = append(realArgs, reflect.ValueOf(argValue).Elem())
|
||||
}
|
||||
}
|
||||
}
|
||||
outValues := v.Call(realArgs)
|
||||
|
||||
outs := make([]any, 0)
|
||||
for _, outValue := range outValues {
|
||||
if outValue.Type().String() == "error" {
|
||||
if !outValue.IsNil() {
|
||||
// 抛出异常
|
||||
if err, ok := outValue.Interface().(error); ok {
|
||||
panic(vm.NewGoError(err))
|
||||
} else {
|
||||
panic(vm.NewGoError(errors.New(u.String(outValue.Interface()))))
|
||||
}
|
||||
}
|
||||
// 忽略error参数
|
||||
continue
|
||||
}
|
||||
outs = append(outs, outValue.Interface())
|
||||
}
|
||||
if len(outs) == 1 {
|
||||
return vm.ToValue(outs[0])
|
||||
} else if len(outs) > 1 {
|
||||
return vm.ToValue(outs)
|
||||
} else {
|
||||
return vm.ToValue(nil)
|
||||
}
|
||||
}
|
||||
case reflect.Invalid:
|
||||
return nil
|
||||
default:
|
||||
return in
|
||||
}
|
||||
}
|
12
go.mod
12
go.mod
@ -8,15 +8,15 @@ require (
|
||||
github.com/google/pprof v0.0.0-20230207041349-798e818bf904
|
||||
github.com/ssgo/log v1.7.7
|
||||
github.com/ssgo/tool v0.4.27
|
||||
github.com/ssgo/u v1.7.9
|
||||
golang.org/x/net v0.30.0
|
||||
golang.org/x/text v0.19.0
|
||||
github.com/ssgo/u v1.7.11
|
||||
golang.org/x/net v0.31.0
|
||||
golang.org/x/text v0.20.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/ssgo/config v1.7.7 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/ssgo/config v1.7.9 // indirect
|
||||
github.com/ssgo/standard v1.7.7 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/sys v0.27.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
494
makeTS.go
Normal file
494
makeTS.go
Normal file
@ -0,0 +1,494 @@
|
||||
package gojs
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/ssgo/u"
|
||||
)
|
||||
|
||||
type ArgInfo struct {
|
||||
index int
|
||||
isVariadic bool
|
||||
isOutArg bool
|
||||
isFunc bool
|
||||
isSkip bool
|
||||
isOptional bool
|
||||
funcInArgs []ArgInfo
|
||||
funcOutArgs []ArgInfo
|
||||
Name string
|
||||
Type string
|
||||
}
|
||||
|
||||
var numberMatcher = regexp.MustCompile("[a-z0-9]*(int|float)[a-z0-9]*")
|
||||
var mapMatcher = regexp.MustCompile("map\\[(\\w+)](\\w+)")
|
||||
|
||||
func makeArgTypeString(argType string) string {
|
||||
if strings.Contains(argType, "interface {}") {
|
||||
argType = strings.ReplaceAll(argType, "interface {}", "any")
|
||||
}
|
||||
if strings.HasPrefix(argType, "*") {
|
||||
argType = argType[1:]
|
||||
}
|
||||
if strings.HasPrefix(argType, "[]") {
|
||||
argType = argType[2:] + "[]"
|
||||
}
|
||||
if strings.Contains(argType, "int") || strings.Contains(argType, "float") {
|
||||
argType = numberMatcher.ReplaceAllString(argType, "number")
|
||||
}
|
||||
if strings.Contains(argType, "bool") {
|
||||
argType = strings.ReplaceAll(argType, "bool", "boolean")
|
||||
}
|
||||
if strings.Contains(argType, "booleanean") {
|
||||
argType = strings.ReplaceAll(argType, "booleanean", "boolean")
|
||||
}
|
||||
if strings.HasPrefix(argType, "map[") {
|
||||
argType = mapMatcher.ReplaceAllString(argType, "Map<$1, $2>")
|
||||
}
|
||||
//if strings.ContainsRune(argType, '.') {
|
||||
// argType = argType[strings.LastIndexByte(argType, '.')+1:]
|
||||
//}
|
||||
if strings.HasPrefix(argType, "<-") {
|
||||
argType = "any"
|
||||
}
|
||||
if argType == "" {
|
||||
argType = "void"
|
||||
}
|
||||
return argType
|
||||
}
|
||||
|
||||
func (argInfo *ArgInfo) String() string {
|
||||
argType := argInfo.Type
|
||||
if argInfo.isFunc {
|
||||
argType = "(" + makeInArgsString(argInfo.funcInArgs) + ") => " + makeOutArgsString(argInfo.funcOutArgs)
|
||||
} else {
|
||||
argType = makeArgTypeString(argType)
|
||||
}
|
||||
if argInfo.isOutArg {
|
||||
return argType
|
||||
} else {
|
||||
argName := argInfo.Name
|
||||
if argName == "" {
|
||||
argName = "arg" + u.String(argInfo.index+1)
|
||||
}
|
||||
if argInfo.isVariadic {
|
||||
argName = "..." + argName
|
||||
}
|
||||
return argName + u.StringIf(argInfo.isOptional, "?: ", ": ") + argType
|
||||
}
|
||||
}
|
||||
|
||||
func makeInArgs(args []ArgInfo) []string {
|
||||
arr := make([]string, 0)
|
||||
for _, arg := range args {
|
||||
if !arg.isSkip {
|
||||
arr = append(arr, arg.String())
|
||||
}
|
||||
}
|
||||
return arr
|
||||
}
|
||||
|
||||
func makeInArgsString(args []ArgInfo) string {
|
||||
return strings.Join(makeInArgs(args), ", ")
|
||||
}
|
||||
|
||||
func makeOutArgsString(args []ArgInfo) string {
|
||||
arr := makeInArgs(args)
|
||||
if len(arr) == 0 {
|
||||
return "void"
|
||||
} else if len(arr) == 1 {
|
||||
return arr[0]
|
||||
} else {
|
||||
return "[" + strings.Join(arr, ", ") + "]"
|
||||
}
|
||||
}
|
||||
|
||||
func makeFuncArgsNames(v reflect.Value, inArgs []ArgInfo, isMethod bool) {
|
||||
var fp *runtime.Func
|
||||
if v.IsValid() {
|
||||
fp = runtime.FuncForPC(v.Pointer())
|
||||
} else {
|
||||
// no name for Interface
|
||||
return
|
||||
}
|
||||
file, lineNo := fp.FileLine(fp.Entry())
|
||||
if file != "<autogenerated>" && u.FileExists(file) {
|
||||
lines, _ := u.ReadFileLines(file)
|
||||
if len(lines) >= lineNo {
|
||||
line := lines[lineNo-1]
|
||||
if !strings.Contains(line, "func") && lineNo-2 >= 0 && strings.Contains(lines[lineNo-2], "func") {
|
||||
line = lines[lineNo-2]
|
||||
}
|
||||
line = strings.ReplaceAll(line, "interface{}", "any")
|
||||
pos := strings.Index(line, "func")
|
||||
if pos != -1 {
|
||||
line = strings.TrimSpace(line[pos+4:])
|
||||
if isMethod {
|
||||
// skip method this arg
|
||||
pos = strings.Index(line, "(")
|
||||
if pos != -1 {
|
||||
line = strings.TrimSpace(line[pos+1:])
|
||||
makeFuncArgsName(line, inArgs[1:])
|
||||
}
|
||||
} else {
|
||||
makeFuncArgsName(line, inArgs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeFuncArgsName(line string, inArgs []ArgInfo) {
|
||||
pos := strings.Index(line, "(")
|
||||
if pos != -1 {
|
||||
line = strings.TrimSpace(line[pos+1:])
|
||||
for i := 0; i < len(inArgs); i++ {
|
||||
// find param name
|
||||
pos = strings.Index(line, " ")
|
||||
// support combined args a, b string
|
||||
pos1 := strings.Index(line, ",")
|
||||
if pos1 != -1 && pos1 < pos {
|
||||
inArgs[i].Name = line[0:pos1]
|
||||
line = strings.TrimSpace(line[pos1+1:])
|
||||
continue
|
||||
}
|
||||
if pos != -1 {
|
||||
inArgs[i].Name = line[0:pos]
|
||||
line = strings.TrimSpace(line[pos+1:])
|
||||
}
|
||||
// skip inline func
|
||||
if strings.HasPrefix(line, "func") {
|
||||
line = strings.TrimSpace(line[4:])
|
||||
leftQuotes := 0
|
||||
quoteStarted := false
|
||||
for pos = 0; pos < len(line); pos++ {
|
||||
if line[pos] == '(' {
|
||||
leftQuotes++
|
||||
quoteStarted = true
|
||||
continue
|
||||
}
|
||||
if quoteStarted && line[pos] == ')' {
|
||||
leftQuotes--
|
||||
}
|
||||
if quoteStarted && leftQuotes == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
makeFuncArgsName(line, inArgs[i].funcInArgs)
|
||||
line = strings.TrimSpace(line[pos+1:])
|
||||
}
|
||||
// skip ,
|
||||
pos = strings.Index(line, ",")
|
||||
if pos != -1 {
|
||||
line = strings.TrimSpace(line[pos+1:])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fixFieldElemType(argType string) string {
|
||||
if strings.HasPrefix(argType, "Map<") {
|
||||
argType = "Object/*" + argType + "*/"
|
||||
}
|
||||
return argType
|
||||
}
|
||||
|
||||
func makeFieldElemType(t reflect.Type, existsClasses *map[string]string, sameClassIndex *map[string]int, classes *[]string, isSkip bool) string {
|
||||
originT := t
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Kind() == reflect.Map {
|
||||
if t.Elem().Kind() == reflect.Struct && !isSkip {
|
||||
makeClass(t.Elem(), existsClasses, sameClassIndex, classes)
|
||||
}
|
||||
et := t.Elem()
|
||||
if et.Kind() == reflect.Pointer {
|
||||
et = et.Elem()
|
||||
}
|
||||
if et.Kind() == reflect.Struct || et.Kind() == reflect.Map || (et.Kind() == reflect.Slice && et.Elem().Kind() != reflect.Uint8) {
|
||||
return "Map<" + makeArgTypeString(t.Key().String()) + ", " + makeFieldElemType(t.Elem(), existsClasses, sameClassIndex, classes, isSkip) + ">"
|
||||
}
|
||||
return "Object"
|
||||
} else if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 {
|
||||
if t.Elem().Kind() == reflect.Struct && !isSkip {
|
||||
makeClass(t.Elem(), existsClasses, sameClassIndex, classes)
|
||||
}
|
||||
return "Array<" + makeFieldElemType(t.Elem(), existsClasses, sameClassIndex, classes, isSkip) + ">"
|
||||
} else if t.Kind() == reflect.Struct {
|
||||
if !isSkip {
|
||||
makeClass(originT, existsClasses, sameClassIndex, classes)
|
||||
}
|
||||
return makeArgTypeString(getFixedClassName(t.String(), existsClasses))
|
||||
//return makeArgTypeString(strings.ReplaceAll(t.String(), ".", "_"))
|
||||
} else if t.Kind() == reflect.Interface {
|
||||
if !isSkip {
|
||||
makeClass(originT, existsClasses, sameClassIndex, classes)
|
||||
}
|
||||
return makeArgTypeString(getFixedClassName(t.String(), existsClasses))
|
||||
} else if t.Kind() == reflect.Func {
|
||||
inArgs, outArgs := makeFuncInOutArgs(t, existsClasses, sameClassIndex, classes)
|
||||
//makeFuncArgsNames(reflect.MakeFunc(t, func(args []reflect.Value) (results []reflect.Value) {
|
||||
// return nil
|
||||
//}), inArgs, false)
|
||||
return "(" + makeInArgsString(inArgs) + ") => " + makeOutArgsString(outArgs)
|
||||
} else {
|
||||
return makeArgTypeString(getFixedTypeName(t))
|
||||
}
|
||||
}
|
||||
|
||||
func getFixedClassName(className string, existsClasses *map[string]string) string {
|
||||
if (*existsClasses)[className] != "" {
|
||||
return (*existsClasses)[className]
|
||||
}
|
||||
return strings.ReplaceAll(className, ".", "_")
|
||||
}
|
||||
|
||||
func getFixedTypeName(t reflect.Type) string {
|
||||
if t.String() != t.Kind().String() && !strings.HasPrefix(t.String(), "[]") {
|
||||
if t.Kind().String() == "slice" {
|
||||
return "[]any"
|
||||
}
|
||||
if t.Kind().String() == "chan" {
|
||||
return "any"
|
||||
}
|
||||
if t.Kind().String() == "func" {
|
||||
return "()=>void"
|
||||
}
|
||||
//fmt.Println(">>>>>", u.BYellow(t.String()), u.BYellow(t.String()), u.BYellow(t.Kind().String()))
|
||||
return makeArgTypeString(t.Kind().String())
|
||||
} else {
|
||||
return makeArgTypeString(t.String())
|
||||
}
|
||||
}
|
||||
|
||||
func makeClass(t reflect.Type, existsClasses *map[string]string, sameClassIndex *map[string]int, classes *[]string) {
|
||||
originT := t
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Name() == "" {
|
||||
return
|
||||
}
|
||||
fullTypeName := t.String()
|
||||
useTypeName := t.Name()
|
||||
if (*existsClasses)[fullTypeName] == "" {
|
||||
(*sameClassIndex)[useTypeName]++
|
||||
if (*sameClassIndex)[useTypeName] > 1 {
|
||||
useTypeName += u.String((*sameClassIndex)[useTypeName])
|
||||
}
|
||||
(*existsClasses)[fullTypeName] = useTypeName
|
||||
classItems := make([]string, 0)
|
||||
implements := make([]string, 0)
|
||||
if t.Kind() != reflect.Interface {
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
if !t.Field(i).IsExported() {
|
||||
continue
|
||||
}
|
||||
ft := t.Field(i).Type
|
||||
if ft.Kind() == reflect.Pointer {
|
||||
ft = ft.Elem()
|
||||
}
|
||||
ftStr := fixFieldElemType(makeFieldElemType(ft, existsClasses, sameClassIndex, classes, false))
|
||||
if t.Field(i).Anonymous {
|
||||
implements = append(implements, ftStr)
|
||||
continue
|
||||
}
|
||||
classItems = append(classItems, " "+u.GetLowerName(t.Field(i).Name)+": "+ftStr)
|
||||
}
|
||||
}
|
||||
if originT.Kind() != reflect.Pointer {
|
||||
originT = reflect.New(originT).Type()
|
||||
}
|
||||
for i := 0; i < originT.NumMethod(); i++ {
|
||||
if !originT.Method(i).IsExported() {
|
||||
continue
|
||||
}
|
||||
if methodInParent(originT.Method(i), t) {
|
||||
continue
|
||||
}
|
||||
inArgs, outArgs := makeFuncInOutArgs(originT.Method(i).Type, existsClasses, sameClassIndex, classes)
|
||||
if len(inArgs) > 0 {
|
||||
inArgs[0].isSkip = true
|
||||
}
|
||||
//fmt.Println(">>>>>", u.BYellow(originT.Method(i)))
|
||||
makeFuncArgsNames(originT.Method(i).Func, inArgs, true)
|
||||
classItems = append(classItems, " "+u.GetLowerName(originT.Method(i).Name)+"("+makeInArgsString(inArgs)+"): "+makeOutArgsString(outArgs))
|
||||
}
|
||||
for i := 0; i < t.NumMethod(); i++ {
|
||||
if !t.Method(i).IsExported() {
|
||||
continue
|
||||
}
|
||||
if methodInParent(t.Method(i), t) {
|
||||
continue
|
||||
}
|
||||
inArgs, outArgs := makeFuncInOutArgs(t.Method(i).Type, existsClasses, sameClassIndex, classes)
|
||||
if len(inArgs) > 0 {
|
||||
inArgs[0].isSkip = true
|
||||
}
|
||||
//fmt.Println(">>>>>", u.BYellow(t.Method(i)))
|
||||
makeFuncArgsNames(t.Method(i).Func, inArgs, true)
|
||||
classItems = append(classItems, " "+u.GetLowerName(t.Method(i).Name)+"("+makeInArgsString(inArgs)+"): "+makeOutArgsString(outArgs))
|
||||
}
|
||||
implementsStr := ""
|
||||
if len(implements) > 0 {
|
||||
implementsStr = " extends " + strings.Join(implements, ", ")
|
||||
}
|
||||
newClass := append([]string{}, "interface "+useTypeName+implementsStr+" {")
|
||||
newClass = append(newClass, classItems...)
|
||||
newClass = append(newClass, "}")
|
||||
*classes = append(*classes, strings.Join(newClass, "\n"))
|
||||
}
|
||||
}
|
||||
|
||||
func methodInParent(method reflect.Method, childType reflect.Type) bool {
|
||||
for i := 0; i < childType.NumField(); i++ {
|
||||
field := childType.Field(i)
|
||||
if field.Anonymous {
|
||||
parentType := field.Type
|
||||
parentTypeP := field.Type
|
||||
if field.Type.Kind() != reflect.Ptr {
|
||||
parentTypeP = reflect.New(field.Type).Type()
|
||||
} else {
|
||||
parentType = field.Type.Elem()
|
||||
}
|
||||
if _, exists := parentType.MethodByName(method.Name); exists {
|
||||
return true
|
||||
}
|
||||
if _, exists := parentTypeP.MethodByName(method.Name); exists {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func makeFuncInOutArgs(t reflect.Type, existsClasses *map[string]string, sameClassIndex *map[string]int, classes *[]string) (inArgs []ArgInfo, outArgs []ArgInfo) {
|
||||
inArgs = make([]ArgInfo, t.NumIn())
|
||||
outArgs = make([]ArgInfo, t.NumOut())
|
||||
isOptional := true
|
||||
for i := t.NumIn() - 1; i >= 0; i-- {
|
||||
arg := t.In(i)
|
||||
isSkip := false
|
||||
if arg.String() == "*goja.Runtime" {
|
||||
isSkip = true
|
||||
}
|
||||
if arg.String() == "goja.Value" {
|
||||
isSkip = true
|
||||
}
|
||||
if isOptional && arg.Kind() != reflect.Pointer {
|
||||
isOptional = false
|
||||
}
|
||||
argInfo := ArgInfo{
|
||||
index: i,
|
||||
isOutArg: false,
|
||||
isFunc: false,
|
||||
isSkip: isSkip,
|
||||
isOptional: isOptional,
|
||||
isVariadic: t.IsVariadic() && i == t.NumIn()-1,
|
||||
Name: "",
|
||||
Type: fixFieldElemType(makeFieldElemType(arg, existsClasses, sameClassIndex, classes, isSkip)),
|
||||
}
|
||||
//originArg := arg
|
||||
//if arg.Kind() == reflect.Pointer {
|
||||
// arg = arg.Elem()
|
||||
//}
|
||||
if arg.Kind() == reflect.Func {
|
||||
argInfo.isFunc = true
|
||||
argInfo.funcInArgs, argInfo.funcOutArgs = makeFuncInOutArgs(arg, existsClasses, sameClassIndex, classes)
|
||||
}
|
||||
//if !argInfo.isSkip && arg.Kind() == reflect.Struct {
|
||||
// makeClass(originArg, existsClasses, sameClassIndex, classes)
|
||||
//}
|
||||
inArgs[i] = argInfo
|
||||
}
|
||||
for i := t.NumOut() - 1; i >= 0; i-- {
|
||||
arg := t.Out(i)
|
||||
isSkip := false
|
||||
if arg.String() == "error" {
|
||||
isSkip = true
|
||||
}
|
||||
if arg.String() == "goja.Value" {
|
||||
isSkip = true
|
||||
}
|
||||
argInfo := ArgInfo{
|
||||
index: i,
|
||||
isOutArg: true,
|
||||
isFunc: false,
|
||||
isSkip: isSkip,
|
||||
isVariadic: false,
|
||||
Name: "",
|
||||
Type: fixFieldElemType(makeFieldElemType(arg, existsClasses, sameClassIndex, classes, isSkip)),
|
||||
}
|
||||
|
||||
//originArg := arg
|
||||
//if arg.Kind() == reflect.Pointer {
|
||||
// arg = arg.Elem()
|
||||
//}
|
||||
//if !argInfo.isSkip && arg.Kind() == reflect.Struct {
|
||||
// makeClass(originArg, existsClasses, sameClassIndex, classes)
|
||||
//}
|
||||
outArgs[i] = argInfo
|
||||
}
|
||||
return inArgs, outArgs
|
||||
}
|
||||
|
||||
func findObject(v reflect.Value, level int, existsClasses *map[string]string, sameClassIndex *map[string]int) (codes []string, classes []string) {
|
||||
codes = make([]string, 0)
|
||||
classes = make([]string, 0)
|
||||
if v.Kind() == reflect.Interface {
|
||||
v = v.Elem()
|
||||
}
|
||||
originT := v.Type()
|
||||
v = u.FinalValue(v)
|
||||
t := originT
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
indent := strings.Repeat(" ", level)
|
||||
if t.Kind() == reflect.Map {
|
||||
codes = append(codes, "{")
|
||||
for _, k := range v.MapKeys() {
|
||||
codes2, classes2 := findObject(v.MapIndex(k), level+1, existsClasses, sameClassIndex)
|
||||
classes = append(classes, classes2...)
|
||||
codes = append(codes, indent+" \""+k.String()+"\": "+strings.Join(codes2, "\n")+",")
|
||||
}
|
||||
codes = append(codes, indent+"}")
|
||||
} else if t.Kind() == reflect.Struct {
|
||||
makeClass(originT, existsClasses, sameClassIndex, &classes)
|
||||
codes = append(codes, "(null as any) as "+getFixedClassName(t.String(), existsClasses))
|
||||
} else if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 {
|
||||
codes = append(codes, "[")
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
codes2, classes2 := findObject(v.Index(i), level+1, existsClasses, sameClassIndex)
|
||||
classes = append(classes, classes2...)
|
||||
codes = append(codes, indent+" "+strings.Join(codes2, "\n")+",")
|
||||
}
|
||||
codes = append(codes, indent+"]")
|
||||
} else if t.Kind() == reflect.Func {
|
||||
inArgs, outArgs := makeFuncInOutArgs(t, existsClasses, sameClassIndex, &classes)
|
||||
makeFuncArgsNames(v, inArgs, false)
|
||||
codes = append(codes, "function ("+makeInArgsString(inArgs)+"): "+makeOutArgsString(outArgs)+" {return null as any}")
|
||||
} else {
|
||||
codes = append(codes, u.Json(v.Interface()))
|
||||
}
|
||||
return codes, classes
|
||||
}
|
||||
|
||||
func MakeTSCode(objects any) string {
|
||||
existsClasses := make(map[string]string)
|
||||
sameClassIndex := make(map[string]int)
|
||||
codes, classes := findObject(reflect.ValueOf(objects), 0, &existsClasses, &sameClassIndex)
|
||||
interfaceExports := make([]string, 0)
|
||||
for _, existsClassName := range existsClasses {
|
||||
interfaceExports = append(interfaceExports, existsClassName)
|
||||
}
|
||||
a := make([]string, 0)
|
||||
if len(interfaceExports) > 0 {
|
||||
a = append(a, strings.Join(classes, "\n\n"))
|
||||
}
|
||||
a = append(a, "export default "+strings.Join(codes, "\n"))
|
||||
return strings.Join(a, "\n")
|
||||
}
|
Loading…
Reference in New Issue
Block a user