Compare commits
No commits in common. "e754f0afed4f7c1c42fc596923f03c874c0a7559" and "fa8fa86074443dab3e027b736daa86b4d6905228" have entirely different histories.
e754f0afed
...
fa8fa86074
362
gojs.go
362
gojs.go
@ -7,33 +7,21 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/ssgo/log"
|
"github.com/ssgo/log"
|
||||||
"github.com/ssgo/u"
|
"github.com/ssgo/u"
|
||||||
"os"
|
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// var pluginNameMatcher = regexp.MustCompile(`(\w+?)\.`)
|
var pluginNameMatcher = regexp.MustCompile(`(\w+?)\.`)
|
||||||
var exportMatcher = regexp.MustCompile(`export\s+([\w{}, ]+)\s*;?`)
|
var exportMatcher = regexp.MustCompile(`export\s+([\w{}, ]+)\s*;?`)
|
||||||
var importMatcher = regexp.MustCompile(`import\s+([\w{}, ]+)\s+from\s+['"]([\w./\\\- ]+)['"]`)
|
var importMatcher = regexp.MustCompile(`import\s+([\w{}, ]+)\s+from\s+['"]([\w./\- ]+)['"]`)
|
||||||
var flowMethodTypeMatcher = regexp.MustCompile(`\):\s*([\w<>\[\]]+)\s*{`)
|
|
||||||
var functionArgsForFlowMatcher = regexp.MustCompile(`\([\w<>\[\]:,\s]+`)
|
|
||||||
var flowVarTypeMatcher = regexp.MustCompile(`(\w+)\s*:\s*([\w<>\[\]]+)\s*(=|,|\)|$)`)
|
|
||||||
|
|
||||||
type RuntimeOption struct {
|
type RuntimeOption struct {
|
||||||
Globals map[string]interface{}
|
Globals map[string]interface{}
|
||||||
Imports map[string]string
|
Imports map[string]string
|
||||||
Logger *log.Logger
|
Logger *log.Logger
|
||||||
DevMode bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//type watchInfo struct {
|
|
||||||
// mtime int64
|
|
||||||
// code string
|
|
||||||
// codePath string
|
|
||||||
//}
|
|
||||||
|
|
||||||
type JSRuntime struct {
|
type JSRuntime struct {
|
||||||
imports map[string]string
|
imports map[string]string
|
||||||
imported map[string]string
|
imported map[string]string
|
||||||
@ -43,18 +31,6 @@ type JSRuntime struct {
|
|||||||
GoCtx *plugin.Context
|
GoCtx *plugin.Context
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
plugins map[string]*plugin.Plugin
|
plugins map[string]*plugin.Plugin
|
||||||
rootPath string
|
|
||||||
currentPath string
|
|
||||||
devMode bool
|
|
||||||
codeLines map[string][]string
|
|
||||||
realCodeLines map[string][]string
|
|
||||||
anonymousIndex uint
|
|
||||||
//watchList map[string]watchInfo // watch file changed, for dev mode
|
|
||||||
}
|
|
||||||
|
|
||||||
type JSError struct {
|
|
||||||
error
|
|
||||||
stack string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *JSRuntime) Close() {
|
func (rt *JSRuntime) Close() {
|
||||||
@ -72,20 +48,10 @@ func fixPluginId(id string) string {
|
|||||||
return "_" + pluginIdFixer.ReplaceAllString(id, "_")
|
return "_" + pluginIdFixer.ReplaceAllString(id, "_")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *JSRuntime) run(code string, isClosure bool, setToVar string, fromFilename string) (out interface{}, jsErr *JSError) {
|
func (rt *JSRuntime) run(code string) (out interface{}, err error, stack string) {
|
||||||
// support import
|
// support import
|
||||||
tryPlugins := map[string]bool{}
|
tryPlugins := map[string]bool{}
|
||||||
fixedCode := ""
|
code = importMatcher.ReplaceAllStringFunc(code, func(importStr string) string {
|
||||||
if isClosure {
|
|
||||||
if setToVar == "" {
|
|
||||||
fixedCode = "(function(){" + code + "})()"
|
|
||||||
} else {
|
|
||||||
fixedCode = "let " + setToVar + " = (function(){" + code + "})()"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fixedCode = code
|
|
||||||
}
|
|
||||||
fixedCode = importMatcher.ReplaceAllStringFunc(fixedCode, func(importStr string) string {
|
|
||||||
m := importMatcher.FindStringSubmatch(importStr)
|
m := importMatcher.FindStringSubmatch(importStr)
|
||||||
importVar := rt.imported[m[2]]
|
importVar := rt.imported[m[2]]
|
||||||
if importVar == "" {
|
if importVar == "" {
|
||||||
@ -98,42 +64,46 @@ func (rt *JSRuntime) run(code string, isClosure bool, setToVar string, fromFilen
|
|||||||
}
|
}
|
||||||
if strings.HasSuffix(baseName, ".js") {
|
if strings.HasSuffix(baseName, ".js") {
|
||||||
baseName = baseName[0 : len(baseName)-3]
|
baseName = baseName[0 : len(baseName)-3]
|
||||||
} else {
|
|
||||||
if plugin.Get(m[2]) != nil {
|
|
||||||
isTS = true
|
|
||||||
} else {
|
} else {
|
||||||
jsFile += ".js"
|
jsFile += ".js"
|
||||||
}
|
}
|
||||||
|
if !isTS && (rt.imports[m[2]] != "" || u.FileExists(jsFile)) {
|
||||||
|
importCode := rt.imports[m[2]]
|
||||||
|
if importCode == "" {
|
||||||
|
importCode, _ = u.ReadFile(jsFile)
|
||||||
}
|
}
|
||||||
if isTS {
|
if importCode != "" {
|
||||||
|
importVar = "import_" + u.UniqueId()
|
||||||
|
rt.imported[m[2]] = importVar
|
||||||
|
importedCode := exportMatcher.ReplaceAllStringFunc(importCode, func(exportStr string) string {
|
||||||
|
if strings.Contains(exportStr, "export default") {
|
||||||
|
exportStr = strings.Replace(exportStr, "export default", "return", 1)
|
||||||
|
}
|
||||||
|
exportStr = strings.Replace(exportStr, "export", "return", 1)
|
||||||
|
return exportStr
|
||||||
|
})
|
||||||
|
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 {
|
||||||
if plg := plugin.Get(m[2]); plg != nil {
|
if plg := plugin.Get(m[2]); plg != nil {
|
||||||
tryPlugins[m[2]] = true
|
tryPlugins[m[2]] = true
|
||||||
return "let " + m[1] + " = " + fixPluginId(m[2])
|
return "let " + m[1] + " = " + fixPluginId(m[2])
|
||||||
} else {
|
}
|
||||||
rt.logger.Error("unknown plugin: " + m[2])
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if varName, searchList, err := rt.Import(m[2]); err == nil {
|
|
||||||
return "let " + m[1] + " = " + varName
|
|
||||||
} else {
|
|
||||||
return "throw new Error('import file not found: " + jsFile + " in [" + strings.Join(searchList, ", ") + "]')"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return "let " + m[1] + " = " + importVar
|
return "let " + m[1] + " = " + importVar
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
fixedCode = flowMethodTypeMatcher.ReplaceAllString(fixedCode, ") {")
|
|
||||||
fixedCode = functionArgsForFlowMatcher.ReplaceAllStringFunc(fixedCode, func(str string) string {
|
|
||||||
//if flowVarTypeMatcher.MatchString(str) {
|
|
||||||
// fmt.Println(">>>>>>>>", str, u.BCyan(flowVarTypeMatcher.ReplaceAllString(str, "$1 $3")))
|
|
||||||
//}
|
|
||||||
return flowVarTypeMatcher.ReplaceAllString(str, "$1 $3")
|
|
||||||
})
|
|
||||||
//tryPlugins := map[string]bool{}
|
//tryPlugins := map[string]bool{}
|
||||||
//for _, m := range pluginNameMatcher.FindAllStringSubmatch(fixedCode, 1024) {
|
//for _, m := range pluginNameMatcher.FindAllStringSubmatch(code, 1024) {
|
||||||
// tryPlugins[m[1]] = true
|
// tryPlugins[m[1]] = true
|
||||||
//}
|
//}
|
||||||
|
|
||||||
@ -143,10 +113,8 @@ func (rt *JSRuntime) run(code string, isClosure bool, setToVar string, fromFilen
|
|||||||
rt.plugins[plg.Id] = &plg
|
rt.plugins[plg.Id] = &plg
|
||||||
rt.JsCtx.Globals().Set(fixPluginId(plg.Id), MakeJsValueForPlugin(rt.GoCtx, plg.Objects, plg.Id, false))
|
rt.JsCtx.Globals().Set(fixPluginId(plg.Id), MakeJsValueForPlugin(rt.GoCtx, plg.Objects, plg.Id, false))
|
||||||
if plg.JsCode != "" {
|
if plg.JsCode != "" {
|
||||||
rt.codeLines[plg.Id+".js"] = strings.Split(plg.JsCode, "\n")
|
if result, err := rt.JsCtx.Eval(plg.JsCode); err != nil {
|
||||||
rt.realCodeLines[plg.Id+".js"] = strings.Split(plg.JsCode, "\n")
|
stack := GetJSError(err, plg.JsCode)
|
||||||
if result, err := rt.JsCtx.EvalFile(plg.JsCode, plg.Id+".js"); err != nil {
|
|
||||||
stack := rt.getJSError(err)
|
|
||||||
rt.logger.Error(err.Error(), "stack", stack)
|
rt.logger.Error(err.Error(), "stack", stack)
|
||||||
} else {
|
} else {
|
||||||
result.Free()
|
result.Free()
|
||||||
@ -155,200 +123,43 @@ func (rt *JSRuntime) run(code string, isClosure bool, setToVar string, fromFilen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.codeLines[fromFilename] = strings.Split(code, "\n")
|
if r, err := rt.JsCtx.Eval(code); err == nil {
|
||||||
rt.realCodeLines[fromFilename] = strings.Split(fixedCode, "\n")
|
|
||||||
if r, err := rt.JsCtx.EvalFile(fixedCode, fromFilename); err == nil {
|
|
||||||
result := MakeFromJsValue(r)
|
result := MakeFromJsValue(r)
|
||||||
r.Free()
|
r.Free()
|
||||||
return result, nil
|
return result, nil, ""
|
||||||
} else {
|
} else {
|
||||||
// 检查错误
|
// 检查错误
|
||||||
stack := rt.getJSError(err)
|
stack := GetJSError(err, code)
|
||||||
//stack2 := getJSError(err, fixedCode)
|
rt.logger.Error(err.Error(), "stack", stack)
|
||||||
rt.logger.Error(err.Error(), "stack", stack) //, "stack2", stack2)
|
return nil, err, stack
|
||||||
return nil, &JSError{error: err}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *JSRuntime) Exec(code string) (jsErr *JSError) {
|
func (rt *JSRuntime) Exec(code string) (err error, stack string) {
|
||||||
return rt.ExecAt(code, "")
|
_, err, stack = rt.run(code)
|
||||||
|
return err, stack
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *JSRuntime) ExecAt(code string, dir string) (jsErr *JSError) {
|
func (rt *JSRuntime) ExecFile(filename string) (err error, stack string) {
|
||||||
rt.anonymousIndex++
|
|
||||||
filename := filepath.Join(dir, fmt.Sprintf("anonymous%d.js", rt.anonymousIndex))
|
|
||||||
return rt.execAtFile(code, filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *JSRuntime) ExecFile(filename string) (jsErr *JSError) {
|
|
||||||
if code, err := u.ReadFile(filename); err == nil {
|
if code, err := u.ReadFile(filename); err == nil {
|
||||||
return rt.execAtFile(code, filename)
|
return rt.Exec(code)
|
||||||
} else {
|
} else {
|
||||||
rt.logger.Error(err.Error())
|
return err, ""
|
||||||
return &JSError{error: err}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *JSRuntime) execAtFile(code string, filename string) (jsErr *JSError) {
|
func (rt *JSRuntime) Run(code string) (out interface{}, err error, stack string) {
|
||||||
if filename == "" {
|
return rt.run("(function(){" + code + "})()")
|
||||||
rt.currentPath = rt.rootPath
|
|
||||||
} else {
|
|
||||||
if !filepath.IsAbs(filename) {
|
|
||||||
filename, _ = filepath.Abs(filename)
|
|
||||||
}
|
|
||||||
rt.currentPath = filepath.Dir(filename)
|
|
||||||
}
|
|
||||||
_, jsErr = rt.run(code, false, "", filename)
|
|
||||||
return jsErr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *JSRuntime) Run(code string) (out interface{}, jsErr *JSError) {
|
func (rt *JSRuntime) RunFile(filename string) (out interface{}, err error, stack string) {
|
||||||
return rt.RunAt(code, "")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *JSRuntime) RunAt(code string, dir string) (out interface{}, jsErr *JSError) {
|
|
||||||
rt.anonymousIndex++
|
|
||||||
filename := filepath.Join(dir, fmt.Sprintf("anonymous%d.js", rt.anonymousIndex))
|
|
||||||
return rt.runAtFile(code, filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *JSRuntime) RunFile(filename string) (out interface{}, jsErr *JSError) {
|
|
||||||
rt.currentPath = filepath.Dir(filename)
|
|
||||||
if code, err := u.ReadFile(filename); err == nil {
|
if code, err := u.ReadFile(filename); err == nil {
|
||||||
return rt.runAtFile(code, filename)
|
return rt.Run(code)
|
||||||
} else {
|
} else {
|
||||||
rt.logger.Error(err.Error())
|
return nil, err, ""
|
||||||
return nil, &JSError{error: err}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rt *JSRuntime) runAtFile(code string, filename string) (out interface{}, jsErr *JSError) {
|
|
||||||
if filename == "" {
|
|
||||||
rt.currentPath = rt.rootPath
|
|
||||||
} else {
|
|
||||||
if !filepath.IsAbs(filename) {
|
|
||||||
filename, _ = filepath.Abs(filename)
|
|
||||||
}
|
|
||||||
rt.currentPath = filepath.Dir(filename)
|
|
||||||
}
|
|
||||||
return rt.run(code, true, "", filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendSearchFiles(list *[]string, dir, moduleName string, hasJsExt bool) string {
|
|
||||||
filename := moduleName
|
|
||||||
if dir != "" {
|
|
||||||
filename = filepath.Join(dir, moduleName)
|
|
||||||
}
|
|
||||||
if hasJsExt {
|
|
||||||
if u.FileExists(filename) {
|
|
||||||
return filename
|
|
||||||
}
|
|
||||||
*list = append(*list, filename)
|
|
||||||
} else {
|
|
||||||
tryFilename := filename + ".js"
|
|
||||||
if u.FileExists(tryFilename) {
|
|
||||||
return tryFilename
|
|
||||||
}
|
|
||||||
*list = append(*list, tryFilename)
|
|
||||||
tryFilename = filepath.Join(filename, "index.js")
|
|
||||||
if u.FileExists(tryFilename) {
|
|
||||||
return tryFilename
|
|
||||||
}
|
|
||||||
*list = append(*list, tryFilename)
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rt *JSRuntime) Import(moduleName string) (varName string, searchList []string, jsErr *JSError) {
|
|
||||||
searchList = make([]string, 0)
|
|
||||||
|
|
||||||
// if imported
|
|
||||||
importVar := rt.imported[moduleName]
|
|
||||||
if importVar != "" {
|
|
||||||
return importVar, searchList, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// check imports set
|
|
||||||
importCode := rt.imports[moduleName]
|
|
||||||
importFile := ""
|
|
||||||
|
|
||||||
// search file
|
|
||||||
if importCode == "" {
|
|
||||||
hasJsExt := strings.HasSuffix(moduleName, ".js")
|
|
||||||
importFile = appendSearchFiles(&searchList, "", moduleName, hasJsExt)
|
|
||||||
if importFile == "" && !filepath.IsAbs(moduleName) {
|
|
||||||
importFile = appendSearchFiles(&searchList, rt.currentPath, moduleName, hasJsExt)
|
|
||||||
if importFile == "" && rt.rootPath != rt.currentPath {
|
|
||||||
importFile = appendSearchFiles(&searchList, rt.rootPath, moduleName, hasJsExt)
|
|
||||||
}
|
|
||||||
usedNodeModuleDir := ""
|
|
||||||
if importFile == "" {
|
|
||||||
parentPath := rt.currentPath
|
|
||||||
for i := 0; i < 100; i++ {
|
|
||||||
nodeModuleDir := filepath.Join(parentPath, "node_modules")
|
|
||||||
if u.FileExists(nodeModuleDir) {
|
|
||||||
importFile = appendSearchFiles(&searchList, nodeModuleDir, moduleName, hasJsExt)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
parentPath = filepath.Dir(parentPath)
|
|
||||||
if parentPath == "" || parentPath == "." {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if importFile == "" && rt.rootPath != rt.currentPath {
|
|
||||||
parentPath := rt.rootPath
|
|
||||||
for i := 0; i < 100; i++ {
|
|
||||||
nodeModuleDir := filepath.Join(parentPath, "node_modules")
|
|
||||||
if u.FileExists(nodeModuleDir) {
|
|
||||||
if nodeModuleDir != usedNodeModuleDir {
|
|
||||||
importFile = appendSearchFiles(&searchList, nodeModuleDir, moduleName, hasJsExt)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
parentPath = filepath.Dir(parentPath)
|
|
||||||
if parentPath == "" || parentPath == "." {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if importFile != "" {
|
|
||||||
if !filepath.IsAbs(importFile) {
|
|
||||||
importFile, _ = filepath.Abs(importFile)
|
|
||||||
}
|
|
||||||
importVar = rt.imported[importFile]
|
|
||||||
if importVar != "" {
|
|
||||||
return importVar, searchList, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if code, err := u.ReadFile(importFile); err == nil {
|
|
||||||
importCode = code
|
|
||||||
} else {
|
|
||||||
rt.logger.Error(err.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if importCode != "" {
|
|
||||||
importVar = fmt.Sprintf("_import_%d_%s", len(rt.imported), u.UniqueId())
|
|
||||||
rt.imported[importFile] = importVar
|
|
||||||
importCode = exportMatcher.ReplaceAllStringFunc(importCode, func(exportStr string) string {
|
|
||||||
if strings.Contains(exportStr, "export default") {
|
|
||||||
exportStr = strings.Replace(exportStr, "export default", "return", 1)
|
|
||||||
}
|
|
||||||
exportStr = strings.Replace(exportStr, "export", "return", 1)
|
|
||||||
return exportStr
|
|
||||||
})
|
|
||||||
if _, err := rt.run(importCode, true, importVar, importFile); err == nil {
|
|
||||||
return importVar, searchList, nil
|
|
||||||
} else {
|
|
||||||
return "", searchList, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", searchList, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetPluginsConfig(conf map[string]plugin.Config) {
|
func SetPluginsConfig(conf map[string]plugin.Config) {
|
||||||
for _, plg := range plugin.List() {
|
for _, plg := range plugin.List() {
|
||||||
if plg.Init != nil {
|
if plg.Init != nil {
|
||||||
@ -359,7 +170,7 @@ func SetPluginsConfig(conf map[string]plugin.Config) {
|
|||||||
|
|
||||||
func New(option *RuntimeOption) *JSRuntime {
|
func New(option *RuntimeOption) *JSRuntime {
|
||||||
if option == nil {
|
if option == nil {
|
||||||
option = &RuntimeOption{nil, nil, nil, false}
|
option = &RuntimeOption{nil, map[string]string{}, log.DefaultLogger}
|
||||||
}
|
}
|
||||||
|
|
||||||
if option.Imports == nil {
|
if option.Imports == nil {
|
||||||
@ -386,25 +197,10 @@ func New(option *RuntimeOption) *JSRuntime {
|
|||||||
GoCtx: goCtx,
|
GoCtx: goCtx,
|
||||||
logger: option.Logger,
|
logger: option.Logger,
|
||||||
plugins: map[string]*plugin.Plugin{},
|
plugins: map[string]*plugin.Plugin{},
|
||||||
codeLines: map[string][]string{},
|
|
||||||
realCodeLines: map[string][]string{},
|
|
||||||
}
|
|
||||||
if rt.imports["console"] == "" {
|
|
||||||
rt.imports["console"] = "return _console"
|
|
||||||
}
|
|
||||||
if rt.imports["logger"] == "" {
|
|
||||||
rt.imports["logger"] = "return _logger"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.GoCtx.SetData("_freeJsValues", &rt.freeJsValues)
|
rt.GoCtx.SetData("_freeJsValues", &rt.freeJsValues)
|
||||||
|
|
||||||
rt.rootPath, _ = os.Getwd()
|
|
||||||
rt.currentPath = rt.rootPath
|
|
||||||
//goCtx.SetData("_rootPath", rt.rootPath)
|
|
||||||
//goCtx.SetData("_currentPath", rt.rootPath)
|
|
||||||
//rt.JsCtx.Globals().Set("_rootPath", jsCtx.String(rt.rootPath))
|
|
||||||
//rt.JsCtx.Globals().Set("_currentPath", jsCtx.String(rt.rootPath))
|
|
||||||
|
|
||||||
// 全局变量
|
// 全局变量
|
||||||
if option.Globals != nil {
|
if option.Globals != nil {
|
||||||
for k, obj := range option.Globals {
|
for k, obj := range option.Globals {
|
||||||
@ -413,12 +209,7 @@ func New(option *RuntimeOption) *JSRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 注入 console
|
// 注入 console
|
||||||
rt.JsCtx.Globals().Set("_console", MakeJsValue(rt.GoCtx, map[string]interface{}{
|
rt.JsCtx.Globals().Set("console", MakeJsValue(rt.GoCtx, map[string]interface{}{
|
||||||
"print": func(args ...interface{}) {
|
|
||||||
},
|
|
||||||
"println": func(args ...interface{}) {
|
|
||||||
fmt.Println(makeStringArray(args, u.TextNone, u.BgNone)...)
|
|
||||||
},
|
|
||||||
"log": func(args ...interface{}) {
|
"log": func(args ...interface{}) {
|
||||||
fmt.Println(makeStringArray(args, u.TextNone, u.BgNone)...)
|
fmt.Println(makeStringArray(args, u.TextNone, u.BgNone)...)
|
||||||
},
|
},
|
||||||
@ -431,10 +222,7 @@ func New(option *RuntimeOption) *JSRuntime {
|
|||||||
"error": func(args ...interface{}) {
|
"error": func(args ...interface{}) {
|
||||||
fmt.Println(makeStringArray(args, u.TextWhite, u.BgRed)...)
|
fmt.Println(makeStringArray(args, u.TextWhite, u.BgRed)...)
|
||||||
},
|
},
|
||||||
"input": func(prompt *string) string {
|
"input": func() string {
|
||||||
if prompt != nil {
|
|
||||||
fmt.Print(*prompt)
|
|
||||||
}
|
|
||||||
line := ""
|
line := ""
|
||||||
_, _ = fmt.Scanln(&line)
|
_, _ = fmt.Scanln(&line)
|
||||||
return line
|
return line
|
||||||
@ -442,7 +230,7 @@ func New(option *RuntimeOption) *JSRuntime {
|
|||||||
}, false))
|
}, false))
|
||||||
|
|
||||||
// 注入 logger
|
// 注入 logger
|
||||||
rt.JsCtx.Globals().Set("_logger", MakeJsValue(rt.GoCtx, map[string]interface{}{
|
rt.JsCtx.Globals().Set("logger", MakeJsValue(rt.GoCtx, map[string]interface{}{
|
||||||
"debug": func(message string, args *map[string]interface{}) {
|
"debug": func(message string, args *map[string]interface{}) {
|
||||||
rt.logger.Debug(message, makeMapToArray(args)...)
|
rt.logger.Debug(message, makeMapToArray(args)...)
|
||||||
},
|
},
|
||||||
@ -482,7 +270,7 @@ func makeStringArray(args []interface{}, color u.TextColor, bg u.BgColor) []inte
|
|||||||
return stringArgs
|
return stringArgs
|
||||||
}
|
}
|
||||||
|
|
||||||
func Run(code string, option *RuntimeOption) (out interface{}, jsErr *JSError) {
|
func Run(code string, option *RuntimeOption) (out interface{}, err error, stack string) {
|
||||||
rt := New(option)
|
rt := New(option)
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
@ -493,51 +281,29 @@ func Run(code string, option *RuntimeOption) (out interface{}, jsErr *JSError) {
|
|||||||
return rt.Run(code)
|
return rt.Run(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunAt(code, dir string, option *RuntimeOption) (out interface{}, jsErr *JSError) {
|
func RunFile(filename string, option *RuntimeOption) (out interface{}, err error, stack string) {
|
||||||
rt := New(option)
|
if code, err := u.ReadFile(filename); err == nil {
|
||||||
defer func() {
|
return Run(code, option)
|
||||||
if err := recover(); err != nil {
|
} else {
|
||||||
rt.logger.Error(u.String(err))
|
return nil, err, ""
|
||||||
}
|
}
|
||||||
rt.Close()
|
|
||||||
}()
|
|
||||||
return rt.RunAt(code, dir)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunFile(filename string, option *RuntimeOption) (out interface{}, jsErr *JSError) {
|
var jsErrorCodeMatcher = regexp.MustCompile(`code:(\d+)`)
|
||||||
rt := New(option)
|
|
||||||
defer func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
rt.logger.Error(u.String(err))
|
|
||||||
}
|
|
||||||
rt.Close()
|
|
||||||
}()
|
|
||||||
return rt.RunFile(filename)
|
|
||||||
}
|
|
||||||
|
|
||||||
var jsErrorCodeMatcher = regexp.MustCompile(`([\w./\\\-]+):(\d+)`)
|
func GetJSError(err error, code string) string {
|
||||||
|
|
||||||
func (rt *JSRuntime) getJSError(err error) string {
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var jsErr *quickjs.Error
|
var jsErr *quickjs.Error
|
||||||
if errors.As(err, &jsErr) {
|
if errors.As(err, &jsErr) {
|
||||||
// 在错误信息中加入代码
|
// 在错误信息中加入代码
|
||||||
|
codeLines := strings.Split(code, "\n")
|
||||||
return jsErrorCodeMatcher.ReplaceAllStringFunc(jsErr.Stack, func(s2 string) string {
|
return jsErrorCodeMatcher.ReplaceAllStringFunc(jsErr.Stack, func(s2 string) string {
|
||||||
m := jsErrorCodeMatcher.FindStringSubmatch(s2)
|
errorLineNumber := u.Int(jsErrorCodeMatcher.FindStringSubmatch(s2)[1])
|
||||||
filename := m[1]
|
|
||||||
errorLineNumber := u.Int(m[2])
|
|
||||||
errorLine := ""
|
errorLine := ""
|
||||||
codeLines := rt.codeLines[filename]
|
if len(codeLines) >= errorLineNumber {
|
||||||
realCodeLines := rt.realCodeLines[filename]
|
errorLine = codeLines[errorLineNumber-1]
|
||||||
realCodeLineStr := ""
|
|
||||||
if codeLines != nil && len(codeLines) >= errorLineNumber {
|
|
||||||
errorLine = strings.TrimSpace(codeLines[errorLineNumber-1])
|
|
||||||
realErrorLine := strings.TrimSpace(realCodeLines[errorLineNumber-1])
|
|
||||||
if errorLine != realErrorLine {
|
|
||||||
realCodeLineStr = " > ```" + realErrorLine + "```"
|
|
||||||
}
|
}
|
||||||
}
|
return s2 + " ```" + errorLine + "```"
|
||||||
return s2 + " ```" + errorLine + "```" + realCodeLineStr
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
return err.Error()
|
return err.Error()
|
||||||
|
85
ts.go
85
ts.go
@ -261,55 +261,53 @@ func makeFuncInOutArgs(t reflect.Type, existsClasses *map[string]bool, classes *
|
|||||||
// *plugin.Context
|
// *plugin.Context
|
||||||
for i := t.NumIn() - 1; i >= 0; i-- {
|
for i := t.NumIn() - 1; i >= 0; i-- {
|
||||||
arg := t.In(i)
|
arg := t.In(i)
|
||||||
isSkip := false
|
|
||||||
if arg.String() == "*plugin.Context" {
|
|
||||||
isSkip = true
|
|
||||||
}
|
|
||||||
argInfo := ArgInfo{
|
argInfo := ArgInfo{
|
||||||
index: i,
|
index: i,
|
||||||
isOutArg: false,
|
isOutArg: false,
|
||||||
isFunc: false,
|
isFunc: false,
|
||||||
isSkip: isSkip,
|
isSkip: false,
|
||||||
isOptional: arg.Kind() == reflect.Pointer,
|
isOptional: arg.Kind() == reflect.Pointer,
|
||||||
isVariadic: t.IsVariadic() && i == t.NumIn()-1,
|
isVariadic: t.IsVariadic() && i == t.NumIn()-1,
|
||||||
Name: "",
|
Name: "",
|
||||||
Type: makeFieldElemType(arg, existsClasses, classes, isSkip),
|
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)
|
||||||
}
|
}
|
||||||
//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
|
inArgs[i] = argInfo
|
||||||
}
|
}
|
||||||
for i := t.NumOut() - 1; i >= 0; i-- {
|
for i := t.NumOut() - 1; i >= 0; i-- {
|
||||||
arg := t.Out(i)
|
arg := t.Out(i)
|
||||||
isSkip := false
|
|
||||||
if arg.String() == "error" {
|
|
||||||
isSkip = true
|
|
||||||
}
|
|
||||||
argInfo := ArgInfo{
|
argInfo := ArgInfo{
|
||||||
index: i,
|
index: i,
|
||||||
isOutArg: true,
|
isOutArg: true,
|
||||||
isFunc: false,
|
isFunc: false,
|
||||||
isSkip: isSkip,
|
isSkip: false,
|
||||||
isVariadic: false,
|
isVariadic: false,
|
||||||
Name: "",
|
Name: "",
|
||||||
Type: makeFieldElemType(arg, existsClasses, classes, isSkip),
|
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)
|
||||||
}
|
}
|
||||||
//originArg := arg
|
|
||||||
//if arg.Kind() == reflect.Pointer {
|
|
||||||
// arg = arg.Elem()
|
|
||||||
//}
|
|
||||||
//if !argInfo.isSkip && arg.Kind() == reflect.Struct {
|
|
||||||
// makeClass(originArg, existsClasses, classes)
|
|
||||||
//}
|
|
||||||
outArgs[i] = argInfo
|
outArgs[i] = argInfo
|
||||||
}
|
}
|
||||||
return inArgs, outArgs
|
return inArgs, outArgs
|
||||||
@ -318,17 +316,9 @@ func makeFuncInOutArgs(t reflect.Type, existsClasses *map[string]bool, classes *
|
|||||||
func findObject(v reflect.Value, level int, existsClasses *map[string]bool) (codes []string, classes []string) {
|
func findObject(v reflect.Value, level int, existsClasses *map[string]bool) (codes []string, classes []string) {
|
||||||
codes = make([]string, 0)
|
codes = make([]string, 0)
|
||||||
classes = make([]string, 0)
|
classes = make([]string, 0)
|
||||||
if v.Kind() == reflect.Interface {
|
|
||||||
v = v.Elem()
|
|
||||||
}
|
|
||||||
originT := v.Type()
|
|
||||||
v = u.FinalValue(v)
|
v = u.FinalValue(v)
|
||||||
t := originT
|
|
||||||
if t.Kind() == reflect.Pointer {
|
|
||||||
t = t.Elem()
|
|
||||||
}
|
|
||||||
indent := strings.Repeat(" ", level)
|
indent := strings.Repeat(" ", level)
|
||||||
if t.Kind() == reflect.Map {
|
if v.Kind() == reflect.Map {
|
||||||
codes = append(codes, "{")
|
codes = append(codes, "{")
|
||||||
for _, k := range v.MapKeys() {
|
for _, k := range v.MapKeys() {
|
||||||
codes2, classes2 := findObject(v.MapIndex(k), level+1, existsClasses)
|
codes2, classes2 := findObject(v.MapIndex(k), level+1, existsClasses)
|
||||||
@ -336,10 +326,15 @@ func findObject(v reflect.Value, level int, existsClasses *map[string]bool) (cod
|
|||||||
codes = append(codes, indent+" \""+k.String()+"\": "+strings.Join(codes2, "\n")+",")
|
codes = append(codes, indent+" \""+k.String()+"\": "+strings.Join(codes2, "\n")+",")
|
||||||
}
|
}
|
||||||
codes = append(codes, indent+"}")
|
codes = append(codes, indent+"}")
|
||||||
} else if t.Kind() == reflect.Struct {
|
} else if v.Kind() == reflect.Struct {
|
||||||
makeClass(originT, existsClasses, &classes)
|
//codes = append(codes, "{")
|
||||||
codes = append(codes, "null as "+t.Name())
|
//for _, k := range v.MapKeys() {
|
||||||
} else if t.Kind() == reflect.Slice && t.Elem().Kind() != reflect.Uint8 {
|
// 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, "[")
|
codes = append(codes, "[")
|
||||||
for i := 0; i < v.Len(); i++ {
|
for i := 0; i < v.Len(); i++ {
|
||||||
codes2, classes2 := findObject(v.Index(i), level+1, existsClasses)
|
codes2, classes2 := findObject(v.Index(i), level+1, existsClasses)
|
||||||
@ -347,8 +342,8 @@ func findObject(v reflect.Value, level int, existsClasses *map[string]bool) (cod
|
|||||||
codes = append(codes, indent+" "+strings.Join(codes2, "\n")+",")
|
codes = append(codes, indent+" "+strings.Join(codes2, "\n")+",")
|
||||||
}
|
}
|
||||||
codes = append(codes, indent+"]")
|
codes = append(codes, indent+"]")
|
||||||
} else if t.Kind() == reflect.Func {
|
} else if v.Kind() == reflect.Func {
|
||||||
inArgs, outArgs := makeFuncInOutArgs(t, existsClasses, &classes)
|
inArgs, outArgs := makeFuncInOutArgs(v.Type(), existsClasses, &classes)
|
||||||
makeFuncArgsNames(v, inArgs, false)
|
makeFuncArgsNames(v, inArgs, false)
|
||||||
codes = append(codes, "function ("+makeInArgsString(inArgs)+"): "+makeOutArgsString(outArgs)+" {return}")
|
codes = append(codes, "function ("+makeInArgsString(inArgs)+"): "+makeOutArgsString(outArgs)+" {return}")
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
Reference in New Issue
Block a user