Compare commits
2 Commits
fa8fa86074
...
e754f0afed
Author | SHA1 | Date | |
---|---|---|---|
|
e754f0afed | ||
|
7ab40bd68f |
398
gojs.go
398
gojs.go
@ -7,30 +7,54 @@ import (
|
||||
"fmt"
|
||||
"github.com/ssgo/log"
|
||||
"github.com/ssgo/u"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var pluginNameMatcher = regexp.MustCompile(`(\w+?)\.`)
|
||||
// var pluginNameMatcher = regexp.MustCompile(`(\w+?)\.`)
|
||||
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 {
|
||||
Globals map[string]interface{}
|
||||
Imports map[string]string
|
||||
Logger *log.Logger
|
||||
DevMode bool
|
||||
}
|
||||
|
||||
//type watchInfo struct {
|
||||
// mtime int64
|
||||
// code string
|
||||
// codePath string
|
||||
//}
|
||||
|
||||
type JSRuntime struct {
|
||||
imports map[string]string
|
||||
imported map[string]string
|
||||
freeJsValues []quickjs.Value
|
||||
rt quickjs.Runtime
|
||||
JsCtx *quickjs.Context
|
||||
GoCtx *plugin.Context
|
||||
logger *log.Logger
|
||||
plugins map[string]*plugin.Plugin
|
||||
imports map[string]string
|
||||
imported map[string]string
|
||||
freeJsValues []quickjs.Value
|
||||
rt quickjs.Runtime
|
||||
JsCtx *quickjs.Context
|
||||
GoCtx *plugin.Context
|
||||
logger *log.Logger
|
||||
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() {
|
||||
@ -48,10 +72,20 @@ func fixPluginId(id string) string {
|
||||
return "_" + pluginIdFixer.ReplaceAllString(id, "_")
|
||||
}
|
||||
|
||||
func (rt *JSRuntime) run(code string) (out interface{}, err error, stack string) {
|
||||
func (rt *JSRuntime) run(code string, isClosure bool, setToVar string, fromFilename string) (out interface{}, jsErr *JSError) {
|
||||
// support import
|
||||
tryPlugins := map[string]bool{}
|
||||
code = importMatcher.ReplaceAllStringFunc(code, func(importStr string) string {
|
||||
fixedCode := ""
|
||||
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)
|
||||
importVar := rt.imported[m[2]]
|
||||
if importVar == "" {
|
||||
@ -65,45 +99,41 @@ func (rt *JSRuntime) run(code string) (out interface{}, err error, stack string)
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
if plugin.Get(m[2]) != nil {
|
||||
isTS = true
|
||||
} else {
|
||||
importVar = "{}"
|
||||
jsFile += ".js"
|
||||
}
|
||||
return "let " + m[1] + " = " + importVar
|
||||
} else {
|
||||
}
|
||||
if isTS {
|
||||
if plg := plugin.Get(m[2]); plg != nil {
|
||||
tryPlugins[m[2]] = true
|
||||
return "let " + m[1] + " = " + fixPluginId(m[2])
|
||||
} else {
|
||||
rt.logger.Error("unknown plugin: " + m[2])
|
||||
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, ", ") + "]')"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
} else {
|
||||
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{}
|
||||
//for _, m := range pluginNameMatcher.FindAllStringSubmatch(code, 1024) {
|
||||
//for _, m := range pluginNameMatcher.FindAllStringSubmatch(fixedCode, 1024) {
|
||||
// tryPlugins[m[1]] = true
|
||||
//}
|
||||
|
||||
@ -113,8 +143,10 @@ func (rt *JSRuntime) run(code string) (out interface{}, err error, stack string)
|
||||
rt.plugins[plg.Id] = &plg
|
||||
rt.JsCtx.Globals().Set(fixPluginId(plg.Id), MakeJsValueForPlugin(rt.GoCtx, plg.Objects, plg.Id, false))
|
||||
if plg.JsCode != "" {
|
||||
if result, err := rt.JsCtx.Eval(plg.JsCode); err != nil {
|
||||
stack := GetJSError(err, plg.JsCode)
|
||||
rt.codeLines[plg.Id+".js"] = strings.Split(plg.JsCode, "\n")
|
||||
rt.realCodeLines[plg.Id+".js"] = strings.Split(plg.JsCode, "\n")
|
||||
if result, err := rt.JsCtx.EvalFile(plg.JsCode, plg.Id+".js"); err != nil {
|
||||
stack := rt.getJSError(err)
|
||||
rt.logger.Error(err.Error(), "stack", stack)
|
||||
} else {
|
||||
result.Free()
|
||||
@ -123,43 +155,200 @@ func (rt *JSRuntime) run(code string) (out interface{}, err error, stack string)
|
||||
}
|
||||
}
|
||||
|
||||
if r, err := rt.JsCtx.Eval(code); err == nil {
|
||||
rt.codeLines[fromFilename] = strings.Split(code, "\n")
|
||||
rt.realCodeLines[fromFilename] = strings.Split(fixedCode, "\n")
|
||||
if r, err := rt.JsCtx.EvalFile(fixedCode, fromFilename); err == nil {
|
||||
result := MakeFromJsValue(r)
|
||||
r.Free()
|
||||
return result, nil, ""
|
||||
return result, nil
|
||||
} else {
|
||||
// 检查错误
|
||||
stack := GetJSError(err, code)
|
||||
rt.logger.Error(err.Error(), "stack", stack)
|
||||
return nil, err, stack
|
||||
stack := rt.getJSError(err)
|
||||
//stack2 := getJSError(err, fixedCode)
|
||||
rt.logger.Error(err.Error(), "stack", stack) //, "stack2", stack2)
|
||||
return nil, &JSError{error: err}
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *JSRuntime) Exec(code string) (err error, stack string) {
|
||||
_, err, stack = rt.run(code)
|
||||
return err, stack
|
||||
func (rt *JSRuntime) Exec(code string) (jsErr *JSError) {
|
||||
return rt.ExecAt(code, "")
|
||||
}
|
||||
|
||||
func (rt *JSRuntime) ExecFile(filename string) (err error, stack string) {
|
||||
func (rt *JSRuntime) ExecAt(code string, dir string) (jsErr *JSError) {
|
||||
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 {
|
||||
return rt.Exec(code)
|
||||
return rt.execAtFile(code, filename)
|
||||
} else {
|
||||
return err, ""
|
||||
rt.logger.Error(err.Error())
|
||||
return &JSError{error: err}
|
||||
}
|
||||
}
|
||||
|
||||
func (rt *JSRuntime) Run(code string) (out interface{}, err error, stack string) {
|
||||
return rt.run("(function(){" + code + "})()")
|
||||
func (rt *JSRuntime) execAtFile(code string, filename string) (jsErr *JSError) {
|
||||
if filename == "" {
|
||||
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) RunFile(filename string) (out interface{}, err error, stack string) {
|
||||
func (rt *JSRuntime) Run(code string) (out interface{}, jsErr *JSError) {
|
||||
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 {
|
||||
return rt.Run(code)
|
||||
return rt.runAtFile(code, filename)
|
||||
} else {
|
||||
return nil, err, ""
|
||||
rt.logger.Error(err.Error())
|
||||
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) {
|
||||
for _, plg := range plugin.List() {
|
||||
if plg.Init != nil {
|
||||
@ -170,7 +359,7 @@ func SetPluginsConfig(conf map[string]plugin.Config) {
|
||||
|
||||
func New(option *RuntimeOption) *JSRuntime {
|
||||
if option == nil {
|
||||
option = &RuntimeOption{nil, map[string]string{}, log.DefaultLogger}
|
||||
option = &RuntimeOption{nil, nil, nil, false}
|
||||
}
|
||||
|
||||
if option.Imports == nil {
|
||||
@ -189,18 +378,33 @@ func New(option *RuntimeOption) *JSRuntime {
|
||||
})
|
||||
|
||||
rt := &JSRuntime{
|
||||
imports: option.Imports,
|
||||
imported: map[string]string{},
|
||||
freeJsValues: make([]quickjs.Value, 0),
|
||||
rt: jsRt,
|
||||
JsCtx: jsCtx,
|
||||
GoCtx: goCtx,
|
||||
logger: option.Logger,
|
||||
plugins: map[string]*plugin.Plugin{},
|
||||
imports: option.Imports,
|
||||
imported: map[string]string{},
|
||||
freeJsValues: make([]quickjs.Value, 0),
|
||||
rt: jsRt,
|
||||
JsCtx: jsCtx,
|
||||
GoCtx: goCtx,
|
||||
logger: option.Logger,
|
||||
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.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 {
|
||||
for k, obj := range option.Globals {
|
||||
@ -209,7 +413,12 @@ func New(option *RuntimeOption) *JSRuntime {
|
||||
}
|
||||
|
||||
// 注入 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{}) {
|
||||
fmt.Println(makeStringArray(args, u.TextNone, u.BgNone)...)
|
||||
},
|
||||
@ -222,7 +431,10 @@ func New(option *RuntimeOption) *JSRuntime {
|
||||
"error": func(args ...interface{}) {
|
||||
fmt.Println(makeStringArray(args, u.TextWhite, u.BgRed)...)
|
||||
},
|
||||
"input": func() string {
|
||||
"input": func(prompt *string) string {
|
||||
if prompt != nil {
|
||||
fmt.Print(*prompt)
|
||||
}
|
||||
line := ""
|
||||
_, _ = fmt.Scanln(&line)
|
||||
return line
|
||||
@ -230,7 +442,7 @@ func New(option *RuntimeOption) *JSRuntime {
|
||||
}, false))
|
||||
|
||||
// 注入 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{}) {
|
||||
rt.logger.Debug(message, makeMapToArray(args)...)
|
||||
},
|
||||
@ -270,7 +482,7 @@ func makeStringArray(args []interface{}, color u.TextColor, bg u.BgColor) []inte
|
||||
return stringArgs
|
||||
}
|
||||
|
||||
func Run(code string, option *RuntimeOption) (out interface{}, err error, stack string) {
|
||||
func Run(code string, option *RuntimeOption) (out interface{}, jsErr *JSError) {
|
||||
rt := New(option)
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
@ -281,29 +493,51 @@ func Run(code string, option *RuntimeOption) (out interface{}, err error, stack
|
||||
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, ""
|
||||
}
|
||||
func RunAt(code, dir string, option *RuntimeOption) (out interface{}, jsErr *JSError) {
|
||||
rt := New(option)
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
rt.logger.Error(u.String(err))
|
||||
}
|
||||
rt.Close()
|
||||
}()
|
||||
return rt.RunAt(code, dir)
|
||||
}
|
||||
|
||||
var jsErrorCodeMatcher = regexp.MustCompile(`code:(\d+)`)
|
||||
func RunFile(filename string, option *RuntimeOption) (out interface{}, jsErr *JSError) {
|
||||
rt := New(option)
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
rt.logger.Error(u.String(err))
|
||||
}
|
||||
rt.Close()
|
||||
}()
|
||||
return rt.RunFile(filename)
|
||||
}
|
||||
|
||||
func GetJSError(err error, code string) string {
|
||||
var jsErrorCodeMatcher = regexp.MustCompile(`([\w./\\\-]+):(\d+)`)
|
||||
|
||||
func (rt *JSRuntime) getJSError(err error) string {
|
||||
if err != nil {
|
||||
var jsErr *quickjs.Error
|
||||
if errors.As(err, &jsErr) {
|
||||
// 在错误信息中加入代码
|
||||
codeLines := strings.Split(code, "\n")
|
||||
return jsErrorCodeMatcher.ReplaceAllStringFunc(jsErr.Stack, func(s2 string) string {
|
||||
errorLineNumber := u.Int(jsErrorCodeMatcher.FindStringSubmatch(s2)[1])
|
||||
m := jsErrorCodeMatcher.FindStringSubmatch(s2)
|
||||
filename := m[1]
|
||||
errorLineNumber := u.Int(m[2])
|
||||
errorLine := ""
|
||||
if len(codeLines) >= errorLineNumber {
|
||||
errorLine = codeLines[errorLineNumber-1]
|
||||
codeLines := rt.codeLines[filename]
|
||||
realCodeLines := rt.realCodeLines[filename]
|
||||
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 {
|
||||
return err.Error()
|
||||
|
85
ts.go
85
ts.go
@ -261,53 +261,55 @@ func makeFuncInOutArgs(t reflect.Type, existsClasses *map[string]bool, classes *
|
||||
// *plugin.Context
|
||||
for i := t.NumIn() - 1; i >= 0; i-- {
|
||||
arg := t.In(i)
|
||||
isSkip := false
|
||||
if arg.String() == "*plugin.Context" {
|
||||
isSkip = true
|
||||
}
|
||||
argInfo := ArgInfo{
|
||||
index: i,
|
||||
isOutArg: false,
|
||||
isFunc: false,
|
||||
isSkip: false,
|
||||
isSkip: isSkip,
|
||||
isOptional: arg.Kind() == reflect.Pointer,
|
||||
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)
|
||||
Type: makeFieldElemType(arg, existsClasses, 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, 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)
|
||||
isSkip := false
|
||||
if arg.String() == "error" {
|
||||
isSkip = true
|
||||
}
|
||||
argInfo := ArgInfo{
|
||||
index: i,
|
||||
isOutArg: true,
|
||||
isFunc: false,
|
||||
isSkip: false,
|
||||
isSkip: isSkip,
|
||||
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)
|
||||
Type: makeFieldElemType(arg, existsClasses, classes, isSkip),
|
||||
}
|
||||
//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
|
||||
@ -316,9 +318,17 @@ 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) {
|
||||
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 v.Kind() == reflect.Map {
|
||||
if t.Kind() == reflect.Map {
|
||||
codes = append(codes, "{")
|
||||
for _, k := range v.MapKeys() {
|
||||
codes2, classes2 := findObject(v.MapIndex(k), level+1, existsClasses)
|
||||
@ -326,15 +336,10 @@ 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+"}")
|
||||
} 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 {
|
||||
} else if t.Kind() == reflect.Struct {
|
||||
makeClass(originT, existsClasses, &classes)
|
||||
codes = append(codes, "null as "+t.Name())
|
||||
} 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)
|
||||
@ -342,8 +347,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+"]")
|
||||
} else if v.Kind() == reflect.Func {
|
||||
inArgs, outArgs := makeFuncInOutArgs(v.Type(), existsClasses, &classes)
|
||||
} else if t.Kind() == reflect.Func {
|
||||
inArgs, outArgs := makeFuncInOutArgs(t, existsClasses, &classes)
|
||||
makeFuncArgsNames(v, inArgs, false)
|
||||
codes = append(codes, "function ("+makeInArgsString(inArgs)+"): "+makeOutArgsString(outArgs)+" {return}")
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user