add export plugins code to typescript
add RunFile
This commit is contained in:
parent
c4fcb3fb21
commit
8179d73ae0
@ -165,9 +165,9 @@ func _makeJsValue(ctx *plugin.Context, in interface{}, n int, key string, plugin
|
||||
// pluginConf := GetPluginConfig(pluginName)
|
||||
// realArgs[i] = reflect.ValueOf(pluginConf)
|
||||
// continue
|
||||
} else if injectObject := ctx.GetInject(inTypeString); injectObject != nil {
|
||||
realArgs[i] = reflect.ValueOf(injectObject)
|
||||
continue
|
||||
//} else if injectObject := ctx.GetInject(inTypeString); injectObject != nil {
|
||||
// realArgs[i] = reflect.ValueOf(injectObject)
|
||||
// continue
|
||||
}
|
||||
|
||||
if !realArgs[i].IsValid() {
|
||||
|
8
go.mod
8
go.mod
@ -5,12 +5,12 @@ go 1.17
|
||||
require (
|
||||
apigo.cloud/git/apigo/plugin v1.0.1
|
||||
apigo.cloud/git/apigo/qjs v0.0.1
|
||||
github.com/ssgo/log v0.6.12
|
||||
github.com/ssgo/u v0.6.12
|
||||
github.com/ssgo/log v1.7.2
|
||||
github.com/ssgo/u v1.7.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/ssgo/config v0.6.12 // indirect
|
||||
github.com/ssgo/standard v0.6.12 // indirect
|
||||
github.com/ssgo/config v1.7.2 // indirect
|
||||
github.com/ssgo/standard v1.7.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
113
gojs.go
113
gojs.go
@ -7,13 +7,24 @@ import (
|
||||
"fmt"
|
||||
"github.com/ssgo/log"
|
||||
"github.com/ssgo/u"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var pluginNameMatcher = regexp.MustCompile(`(\w+?)\.`)
|
||||
var exportMatcher = regexp.MustCompile(`export\s+([\w{}, ]+)\s*;?`)
|
||||
var importMatcher = regexp.MustCompile(`import\s+([\w{}, ]+)\s+from\s+['"]([\w./\- ]+)['"]`)
|
||||
|
||||
type RuntimeOption struct {
|
||||
Globals map[string]interface{}
|
||||
Imports map[string]string
|
||||
Logger *log.Logger
|
||||
}
|
||||
|
||||
type JSRuntime struct {
|
||||
imports map[string]string
|
||||
imported map[string]string
|
||||
freeJsValues []quickjs.Value
|
||||
rt quickjs.Runtime
|
||||
JsCtx *quickjs.Context
|
||||
@ -31,7 +42,52 @@ func (rt *JSRuntime) Close() {
|
||||
rt.rt.Close()
|
||||
}
|
||||
|
||||
func (rt *JSRuntime) initCode(code string) {
|
||||
func (rt *JSRuntime) run(code string) (out interface{}, err error, stack string) {
|
||||
// support import
|
||||
code = importMatcher.ReplaceAllStringFunc(code, func(importStr string) string {
|
||||
m := importMatcher.FindStringSubmatch(importStr)
|
||||
importVar := rt.imported[m[2]]
|
||||
if importVar == "" {
|
||||
baseName := path.Base(m[2])
|
||||
jsFile := m[2]
|
||||
isTS := false
|
||||
if strings.HasSuffix(baseName, ".ts") {
|
||||
isTS = true
|
||||
baseName = baseName[0 : len(baseName)-3]
|
||||
}
|
||||
if strings.HasSuffix(baseName, ".js") {
|
||||
baseName = baseName[0 : len(baseName)-3]
|
||||
} else {
|
||||
jsFile += ".js"
|
||||
}
|
||||
if !isTS && (rt.imports[m[2]] != "" || u.FileExists(jsFile)) {
|
||||
importCode := rt.imports[m[2]]
|
||||
if importCode == "" {
|
||||
importCode, _ = u.ReadFile(jsFile)
|
||||
}
|
||||
if importCode != "" {
|
||||
importVar = "import_" + u.UniqueId()
|
||||
rt.imported[m[2]] = importVar
|
||||
importedCode := exportMatcher.ReplaceAllStringFunc(importCode, func(exportStr string) string {
|
||||
return strings.Replace(exportStr, "export", "return", 1)
|
||||
})
|
||||
err, stack := rt.Exec("let " + importVar + " = (function(){" + importedCode + "})()")
|
||||
if err != nil {
|
||||
rt.logger.Error(err.Error(), "stack", stack)
|
||||
}
|
||||
} else {
|
||||
importVar = "{}"
|
||||
}
|
||||
return "let " + m[1] + " = " + importVar
|
||||
} else {
|
||||
// ignore ts and plugin
|
||||
return ""
|
||||
}
|
||||
} else {
|
||||
return "let " + m[1] + " = " + importVar
|
||||
}
|
||||
})
|
||||
|
||||
tryPlugins := map[string]bool{}
|
||||
for _, m := range pluginNameMatcher.FindAllStringSubmatch(code, 1024) {
|
||||
tryPlugins[m[1]] = true
|
||||
@ -51,9 +107,7 @@ func (rt *JSRuntime) initCode(code string) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *JSRuntime) run(code string) (out interface{}, err error, stack string) {
|
||||
if r, err := rt.JsCtx.Eval(code); err == nil {
|
||||
result := MakeFromJsValue(r)
|
||||
r.Free()
|
||||
@ -67,16 +121,30 @@ func (rt *JSRuntime) run(code string) (out interface{}, err error, stack string)
|
||||
}
|
||||
|
||||
func (rt *JSRuntime) Exec(code string) (err error, stack string) {
|
||||
rt.initCode(code)
|
||||
_, err, stack = rt.run(code)
|
||||
return err, stack
|
||||
}
|
||||
|
||||
func (rt *JSRuntime) ExecFile(filename string) (err error, stack string) {
|
||||
if code, err := u.ReadFile(filename); err == nil {
|
||||
return rt.Exec(code)
|
||||
} else {
|
||||
return err, ""
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *JSRuntime) Run(code string) (out interface{}, err error, stack string) {
|
||||
rt.initCode(code)
|
||||
return rt.run("(function(){" + code + "})()")
|
||||
}
|
||||
|
||||
func (rt *JSRuntime) RunFile(filename string) (out interface{}, err error, stack string) {
|
||||
if code, err := u.ReadFile(filename); err == nil {
|
||||
return rt.Run(code)
|
||||
} else {
|
||||
return nil, err, ""
|
||||
}
|
||||
}
|
||||
|
||||
func SetPluginsConfig(conf map[string]plugin.Config) {
|
||||
for _, plg := range plugin.List() {
|
||||
if plg.Init != nil {
|
||||
@ -85,33 +153,42 @@ func SetPluginsConfig(conf map[string]plugin.Config) {
|
||||
}
|
||||
}
|
||||
|
||||
func New(globals map[string]interface{}, logger *log.Logger) *JSRuntime {
|
||||
if logger == nil {
|
||||
logger = log.DefaultLogger
|
||||
func New(option *RuntimeOption) *JSRuntime {
|
||||
if option == nil {
|
||||
option = &RuntimeOption{nil, map[string]string{}, log.DefaultLogger}
|
||||
}
|
||||
|
||||
if option.Imports == nil {
|
||||
option.Imports = map[string]string{}
|
||||
}
|
||||
if option.Logger == nil {
|
||||
option.Logger = log.DefaultLogger
|
||||
}
|
||||
|
||||
// 初始化JS虚拟机
|
||||
jsRt := quickjs.NewRuntime()
|
||||
jsCtx := jsRt.NewContext()
|
||||
goCtx := plugin.NewContext(map[string]interface{}{
|
||||
"*log.Logger": logger,
|
||||
"*log.Logger": option.Logger,
|
||||
"*quickjs.Context": jsCtx,
|
||||
})
|
||||
|
||||
rt := &JSRuntime{
|
||||
imports: option.Imports,
|
||||
imported: map[string]string{},
|
||||
freeJsValues: make([]quickjs.Value, 0),
|
||||
rt: jsRt,
|
||||
JsCtx: jsCtx,
|
||||
GoCtx: goCtx,
|
||||
logger: logger,
|
||||
logger: option.Logger,
|
||||
plugins: map[string]*plugin.Plugin{},
|
||||
}
|
||||
|
||||
rt.GoCtx.SetData("_freeJsValues", &rt.freeJsValues)
|
||||
|
||||
// 全局变量
|
||||
if globals != nil {
|
||||
for k, obj := range globals {
|
||||
if option.Globals != nil {
|
||||
for k, obj := range option.Globals {
|
||||
rt.JsCtx.Globals().Set(k, MakeJsValue(rt.GoCtx, obj, false))
|
||||
}
|
||||
}
|
||||
@ -173,8 +250,8 @@ func makeStringArray(args []interface{}, color u.TextColor, bg u.BgColor) []inte
|
||||
return stringArgs
|
||||
}
|
||||
|
||||
func Run(code string, globals map[string]interface{}, logger *log.Logger) (out interface{}, err error, stack string) {
|
||||
rt := New(globals, logger)
|
||||
func Run(code string, option *RuntimeOption) (out interface{}, err error, stack string) {
|
||||
rt := New(option)
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
rt.logger.Error(u.String(err))
|
||||
@ -184,6 +261,14 @@ func Run(code string, globals map[string]interface{}, logger *log.Logger) (out i
|
||||
return rt.Run(code)
|
||||
}
|
||||
|
||||
func RunFile(filename string, option *RuntimeOption) (out interface{}, err error, stack string) {
|
||||
if code, err := u.ReadFile(filename); err == nil {
|
||||
return Run(code, option)
|
||||
} else {
|
||||
return nil, err, ""
|
||||
}
|
||||
}
|
||||
|
||||
var jsErrorCodeMatcher = regexp.MustCompile(`code:(\d+)`)
|
||||
|
||||
func GetJSError(err error, code string) string {
|
||||
|
72
gojs_test.go
72
gojs_test.go
@ -7,11 +7,11 @@ import (
|
||||
"github.com/ssgo/log"
|
||||
"github.com/ssgo/u"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
||||
type Object struct {
|
||||
id string
|
||||
}
|
||||
@ -20,18 +20,48 @@ func (obj *Object) GetId() string {
|
||||
return obj.id
|
||||
}
|
||||
|
||||
type TestBirthday struct {
|
||||
Year int
|
||||
Month int
|
||||
Day int
|
||||
}
|
||||
|
||||
type TestBaseUser struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
|
||||
type TestUser struct {
|
||||
TestBaseUser
|
||||
Birthday *TestBirthday
|
||||
}
|
||||
|
||||
func (b *TestBirthday) String() string {
|
||||
return fmt.Sprintln(b.Year, b.Month, b.Day)
|
||||
}
|
||||
|
||||
func (u *TestUser) GetBirthdayString() string {
|
||||
return u.Birthday.String()
|
||||
}
|
||||
|
||||
func init() {
|
||||
defaultObject := Object{id: "o-00"}
|
||||
plugin.Register(plugin.Plugin{
|
||||
plg := plugin.Plugin{
|
||||
Id: "obj",
|
||||
Name: "test obj plugin",
|
||||
Objects: map[string]interface{}{
|
||||
"name": "1233",
|
||||
"list1": []interface{}{1, "2", map[string]interface{}{"aaa": 111, "bbb": "222"}, true},
|
||||
"log": log.DefaultLogger.Info,
|
||||
"getId": defaultObject.GetId,
|
||||
"new": func(id string) interface{} {
|
||||
return &Object{id: id}
|
||||
},
|
||||
"echo": func(text string, echoFunc func(text string) string) interface{} {
|
||||
return echoFunc(text)
|
||||
"test1": func(id int, id2 uint16, id3 float64) *TestUser {
|
||||
return nil
|
||||
},
|
||||
"echo": func(text string, echoFunc func(text string, t2 int) string, t3 []uint32, t4 *bool) interface{} {
|
||||
return echoFunc(text, 0)
|
||||
},
|
||||
"echoTimes": func(echoFunc func(text string)) {
|
||||
for i := 0; i < 5; i++ {
|
||||
@ -40,6 +70,10 @@ func init() {
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
plugin.Register(plg)
|
||||
gojs.SetPluginsConfig(map[string]plugin.Config{
|
||||
"obj": plugin.Config{},
|
||||
})
|
||||
}
|
||||
|
||||
@ -52,6 +86,12 @@ func test(t *testing.T, name string, check bool, extArgs ...interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTS(t *testing.T) {
|
||||
plg := plugin.Get("obj")
|
||||
plgCode := gojs.MakePluginCode(plg)
|
||||
test(t, "ts code", strings.Contains(plgCode, "(echoFunc: (text: string) => void)"))
|
||||
}
|
||||
|
||||
func TestGlobal(t *testing.T) {
|
||||
code := `
|
||||
log('test', 'name', 'log')
|
||||
@ -63,18 +103,20 @@ return plus(number,2)
|
||||
"plus": func(i, j int) int { return i + j },
|
||||
}
|
||||
|
||||
r, _, _ := gojs.Run(code, globals, log.DefaultLogger)
|
||||
r, _, _ := gojs.Run(code, &gojs.RuntimeOption{
|
||||
Globals: globals,
|
||||
})
|
||||
test(t, "call", u.Int(r) == 11, r)
|
||||
}
|
||||
|
||||
func TestPlugin(t *testing.T) {
|
||||
r, _, _ := gojs.Run("return obj.getId()", nil, log.DefaultLogger)
|
||||
r, _, _ := gojs.Run("return obj.getId()", nil)
|
||||
test(t, "obj.getId()", u.String(r) == "o-00", r)
|
||||
|
||||
r, _, _ = gojs.Run(`
|
||||
o = obj.new('o-01')
|
||||
return o.getId()
|
||||
`, nil, log.DefaultLogger)
|
||||
`, nil)
|
||||
test(t, "new obj.getId()", u.String(r) == "o-01", r)
|
||||
|
||||
t1 := time.Now()
|
||||
@ -82,11 +124,11 @@ return o.getId()
|
||||
out = ''
|
||||
obj.echo('123', function(text){
|
||||
out = text
|
||||
})
|
||||
}, null)
|
||||
return out
|
||||
`, nil, log.DefaultLogger)
|
||||
`, nil)
|
||||
t2 := time.Now()
|
||||
fmt.Println("time:", t2.UnixMicro() - t1.UnixMicro())
|
||||
fmt.Println("time:", t2.UnixMicro()-t1.UnixMicro())
|
||||
test(t, "callback", u.String(r) == "123", r)
|
||||
|
||||
t1 = time.Now()
|
||||
@ -96,20 +138,19 @@ obj.echoTimes(function(text){
|
||||
out += text
|
||||
})
|
||||
return out
|
||||
`, nil, log.DefaultLogger)
|
||||
`, nil)
|
||||
t2 = time.Now()
|
||||
fmt.Println("time:", t2.UnixMicro() - t1.UnixMicro())
|
||||
fmt.Println("time:", t2.UnixMicro()-t1.UnixMicro())
|
||||
test(t, "callbacks", u.String(r) == "01234", r)
|
||||
}
|
||||
|
||||
|
||||
func BenchmarkEcho(tb *testing.B) {
|
||||
tb.StopTimer()
|
||||
ms1 := runtime.MemStats{}
|
||||
runtime.ReadMemStats(&ms1)
|
||||
tb.StartTimer()
|
||||
for i := 0; i < tb.N; i++ {
|
||||
gojs.Run(`return 1`, nil, log.DefaultLogger)
|
||||
gojs.Run(`return 1`, nil)
|
||||
}
|
||||
tb.StopTimer()
|
||||
|
||||
@ -122,7 +163,6 @@ func BenchmarkEcho(tb *testing.B) {
|
||||
fmt.Println(">>", ms1.HeapInuse, ms2.HeapInuse, ms3.HeapInuse)
|
||||
}
|
||||
|
||||
|
||||
func BenchmarkCallback(tb *testing.B) {
|
||||
tb.StopTimer()
|
||||
ms1 := runtime.MemStats{}
|
||||
@ -135,7 +175,7 @@ obj.echoTimes(function(text){
|
||||
out += text
|
||||
})
|
||||
return out
|
||||
`, nil, log.DefaultLogger)
|
||||
`, nil)
|
||||
}
|
||||
tb.StopTimer()
|
||||
|
||||
|
360
ts.go
Normal file
360
ts.go
Normal file
@ -0,0 +1,360 @@
|
||||
package gojs
|
||||
|
||||
import (
|
||||
"apigo.cloud/git/apigo/plugin"
|
||||
"github.com/ssgo/u"
|
||||
"path"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ArgInfo struct {
|
||||
index int
|
||||
isVariadic bool
|
||||
isOutArg bool
|
||||
isFunc bool
|
||||
isSkip 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:]
|
||||
//}
|
||||
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 + ": " + 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) {
|
||||
fp := runtime.FuncForPC(v.Pointer())
|
||||
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 makeFieldElemType(t reflect.Type, existsClasses *map[string]bool, 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, classes)
|
||||
}
|
||||
return "Map<" + makeArgTypeString(t.Key().String()) + ", " + makeFieldElemType(t.Elem(), existsClasses, classes, isSkip) + ">"
|
||||
} else if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 {
|
||||
if t.Elem().Kind() == reflect.Struct && !isSkip {
|
||||
makeClass(t.Elem(), existsClasses, classes)
|
||||
}
|
||||
return "Array<" + makeFieldElemType(t.Elem(), existsClasses, classes, isSkip) + ">"
|
||||
} else if t.Kind() == reflect.Struct {
|
||||
if !isSkip {
|
||||
makeClass(originT, existsClasses, classes)
|
||||
}
|
||||
return makeArgTypeString(t.Name())
|
||||
} else {
|
||||
return makeArgTypeString(t.String())
|
||||
}
|
||||
}
|
||||
|
||||
func makeClass(t reflect.Type, existsClasses *map[string]bool, classes *[]string) {
|
||||
originT := t
|
||||
if t.Kind() == reflect.Pointer {
|
||||
t = t.Elem()
|
||||
}
|
||||
if !(*existsClasses)[t.Name()] {
|
||||
(*existsClasses)[t.Name()] = true
|
||||
classItems := make([]string, 0)
|
||||
implements := make([]string, 0)
|
||||
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 := makeFieldElemType(ft, existsClasses, classes, false)
|
||||
if t.Field(i).Anonymous {
|
||||
implements = append(implements, ftStr)
|
||||
continue
|
||||
}
|
||||
classItems = append(classItems, " "+u.GetLowerName(t.Field(i).Name)+": "+ftStr)
|
||||
}
|
||||
for i := 0; i < originT.NumMethod(); i++ {
|
||||
if !originT.Method(i).IsExported() {
|
||||
continue
|
||||
}
|
||||
inArgs, outArgs := makeFuncInOutArgs(originT.Method(i).Type, existsClasses, classes)
|
||||
if len(inArgs) > 0 {
|
||||
inArgs[0].isSkip = true
|
||||
}
|
||||
makeFuncArgsNames(originT.Method(i).Func, inArgs, true)
|
||||
classItems = append(classItems, " "+u.GetLowerName(originT.Method(i).Name)+"("+makeInArgsString(inArgs)+"): "+makeOutArgsString(outArgs))
|
||||
}
|
||||
implementsStr := ""
|
||||
if len(implements) > 0 {
|
||||
implementsStr = " extends " + strings.Join(implements, ", ")
|
||||
}
|
||||
newClass := append([]string{}, "interface "+t.Name()+implementsStr+" {")
|
||||
newClass = append(newClass, classItems...)
|
||||
newClass = append(newClass, "}")
|
||||
*classes = append(*classes, strings.Join(newClass, "\n"))
|
||||
}
|
||||
}
|
||||
|
||||
func makeFuncInOutArgs(t reflect.Type, existsClasses *map[string]bool, classes *[]string) (inArgs []ArgInfo, outArgs []ArgInfo) {
|
||||
inArgs = make([]ArgInfo, t.NumIn())
|
||||
outArgs = make([]ArgInfo, t.NumOut())
|
||||
// *plugin.Context
|
||||
for i := t.NumIn() - 1; i >= 0; i-- {
|
||||
arg := t.In(i)
|
||||
argInfo := ArgInfo{
|
||||
index: i,
|
||||
isOutArg: false,
|
||||
isFunc: false,
|
||||
isSkip: false,
|
||||
isVariadic: t.IsVariadic() && i == t.NumIn()-1,
|
||||
Name: "",
|
||||
Type: makeFieldElemType(arg, existsClasses, classes, true),
|
||||
}
|
||||
if arg.String() == "*plugin.Context" {
|
||||
argInfo.isSkip = true
|
||||
}
|
||||
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, classes)
|
||||
}
|
||||
if !argInfo.isSkip && arg.Kind() == reflect.Struct {
|
||||
makeClass(originArg, existsClasses, classes)
|
||||
}
|
||||
inArgs[i] = argInfo
|
||||
}
|
||||
for i := t.NumOut() - 1; i >= 0; i-- {
|
||||
arg := t.Out(i)
|
||||
argInfo := ArgInfo{
|
||||
index: i,
|
||||
isOutArg: true,
|
||||
isFunc: false,
|
||||
isSkip: false,
|
||||
isVariadic: false,
|
||||
Name: "",
|
||||
Type: makeFieldElemType(arg, existsClasses, classes, true),
|
||||
}
|
||||
if arg.String() == "error" {
|
||||
argInfo.isSkip = true
|
||||
}
|
||||
originArg := arg
|
||||
if arg.Kind() == reflect.Pointer {
|
||||
arg = arg.Elem()
|
||||
}
|
||||
if !argInfo.isSkip && arg.Kind() == reflect.Struct {
|
||||
makeClass(originArg, existsClasses, classes)
|
||||
}
|
||||
outArgs[i] = argInfo
|
||||
}
|
||||
return inArgs, outArgs
|
||||
}
|
||||
|
||||
func findObject(v reflect.Value, level int, existsClasses *map[string]bool) (codes []string, classes []string) {
|
||||
codes = make([]string, 0)
|
||||
classes = make([]string, 0)
|
||||
v = u.FinalValue(v)
|
||||
indent := strings.Repeat(" ", level)
|
||||
if v.Kind() == reflect.Map {
|
||||
codes = append(codes, "{")
|
||||
for _, k := range v.MapKeys() {
|
||||
codes2, classes2 := findObject(v.MapIndex(k), level+1, existsClasses)
|
||||
classes = append(classes, classes2...)
|
||||
codes = append(codes, indent+" \""+k.String()+"\": "+strings.Join(codes2, "\n")+",")
|
||||
}
|
||||
codes = append(codes, indent+"}")
|
||||
} else if v.Kind() == reflect.Struct {
|
||||
//codes = append(codes, "{")
|
||||
//for _, k := range v.MapKeys() {
|
||||
// codes2, classes2 := findObject(v.MapIndex(k), level+1, existsClasses)
|
||||
// classes = append(classes, classes2...)
|
||||
// codes = append(codes, indent+" \""+k.String()+"\": "+strings.Join(codes2, "\n")+",")
|
||||
//}
|
||||
//codes = append(codes, indent+"}")
|
||||
} else if v.Kind() == reflect.Slice && v.Type().Elem().Kind() != reflect.Uint8 {
|
||||
codes = append(codes, "[")
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
codes2, classes2 := findObject(v.Index(i), level+1, existsClasses)
|
||||
classes = append(classes, classes2...)
|
||||
codes = append(codes, indent+" "+strings.Join(codes2, "\n")+",")
|
||||
}
|
||||
codes = append(codes, indent+"]")
|
||||
} else if v.Kind() == reflect.Func {
|
||||
inArgs, outArgs := makeFuncInOutArgs(v.Type(), existsClasses, &classes)
|
||||
makeFuncArgsNames(v, inArgs, false)
|
||||
codes = append(codes, "function ("+makeInArgsString(inArgs)+"): "+makeOutArgsString(outArgs)+" {return}")
|
||||
} else {
|
||||
codes = append(codes, u.Json(v.Interface()))
|
||||
}
|
||||
return codes, classes
|
||||
}
|
||||
|
||||
func MakeAllPluginCode() {
|
||||
for _, plg := range plugin.List() {
|
||||
code := MakePluginCode(&plg)
|
||||
_ = u.WriteFile(path.Join("plugins", plg.Id+".ts"), code)
|
||||
}
|
||||
}
|
||||
|
||||
func MakePluginCode(plg *plugin.Plugin) string {
|
||||
if plg == nil {
|
||||
return ""
|
||||
}
|
||||
existsClasses := make(map[string]bool)
|
||||
codes, classes := findObject(reflect.ValueOf(plg.Objects), 0, &existsClasses)
|
||||
return strings.Join(classes, "\n\n") + "\n\nexport default " + strings.Join(codes, "\n")
|
||||
}
|
Loading…
Reference in New Issue
Block a user