Ai
4 Star 6 Fork 4

王军/golib

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
easyjs.go 5.90 KB
一键复制 编辑 原始数据 按行查看 历史
王军 提交于 2025-05-05 17:21 +08:00 . 修复错误
/*
* @Author: wangjun haodreams@163.com
* @Date: 2024-11-05 22:32:47
* @LastEditors: wangjun haodreams@163.com
* @LastEditTime: 2025-05-05 16:59:24
* @FilePath: \golib\easyjs\easyjs.go
* @Description: 这个包比js包更合理更科学
*/
package easyjs
import (
"bytes"
"fmt"
"os"
"path/filepath"
"reflect"
"runtime"
"strings"
"gitee.com/haodreams/golib/logs"
"github.com/dop251/goja"
)
var jsDir = "js/"
func SetJsDir(dir string) {
if !strings.HasSuffix(dir, "/") {
dir += "/"
}
jsDir = dir
logs.Info("SET javascript path:", dir)
}
func GetJsDir() string {
return jsDir
}
type Namer interface {
Name() string
}
type Exporter interface {
Export() string
}
// 需要用这个替换已有的
func RunScript(vm *goja.Runtime, name string, src string) (goja.Value, error) {
buf := bytes.NewBufferString(src)
newBuf := bytes.NewBuffer(nil)
for line, err := buf.ReadString('\n'); err == nil || len(line) > 0; line, err = buf.ReadString('\n') {
if strings.HasPrefix(line, "import ") {
newBuf.WriteString("// ")
}
newBuf.WriteString(line)
}
//src = strings.ReplaceAll(src, "import * as", "// import * as")
return vm.RunScript(name, newBuf.String())
}
// 注册一个对象
// 性能测试结果看 go的对象比js对象性能高
func Register(vm *goja.Runtime, objs ...any) {
for _, obj := range objs {
typ := reflect.TypeOf(obj)
name := typ.String()
name = strings.ToLower(name)
if n, ok := obj.(Namer); ok {
name = n.Name()
}
idx := strings.LastIndexByte(name, '.')
if idx >= 0 {
//logs.Info(idx, name[idx+1:])
name = name[idx+1:]
}
vm.Set(name, obj)
}
}
// YYYY/MM/DD HH:mm:ss
// 初始化js需要的组件
func Init(vm *goja.Runtime) {
//注册console组件
console := vm.NewObject()
console.Set("trace", func(v any) string {
if v != nil {
return Stack(vm) + fmt.Sprint(v)
}
return Stack(vm)
})
console.Set("log", func(v ...any) {
logs.LiteInfo(Stack(vm), v...)
})
console.Set("info", func(v ...any) {
logs.LiteInfo(Stack(vm), v...)
})
console.Set("warn", func(v ...any) {
logs.LiteWarn(Stack(vm), v...)
})
console.Set("error", func(v ...any) {
logs.LiteError(Stack(vm), v...)
})
console.Set("print", func(v ...any) {
//logs.LiteError(Stack(vm), v...)
fmt.Println(v...)
})
vm.Set("console", console)
vm.Set("ExportObject", Exports)
//注册加载库
vm.Set("require", func(name string) goja.Value {
data, err := os.ReadFile(GetJsDir() + name)
if err != nil {
vm.Interrupt(err)
return nil
}
_, err = RunScript(vm, name, string(data))
if err != nil {
vm.Interrupt(err)
return nil
}
name = filepath.Base(name)
ext := filepath.Ext(name)
if ext != "" {
name = strings.TrimSuffix(name, ext)
}
return vm.Get(name)
})
//注册时间模块
vm.Set("dayjs", func(arg any, fmt string) *Dayjs {
dayjs := new(Dayjs)
dayjs.ms = ParseTime(arg, fmt)
return dayjs
})
//自动注册系统和编码转换模块
Register(vm, &OS{},&FS{}, &Iconv{})
}
func Stack(vm *goja.Runtime) string {
stacks := make([]goja.StackFrame, 2)
ss := vm.CaptureCallStack(2, stacks)
i := len(ss) - 1
if i < 0 {
return ""
}
pos := ss[i].Position()
if pos.Line > 0 {
if pos.Filename != "" {
return fmt.Sprintf("%s:%d ", pos.Filename, pos.Line)
}
return fmt.Sprintf("main.js:%d ", pos.Line)
}
return ""
}
func expors(buf *bytes.Buffer, v reflect.Value, have *bool) {
//导出属性名
t := v.Type()
v = reflect.Indirect(v)
t1 := t
if t.Kind() == reflect.Ptr {
t1 = t.Elem()
}
if t1.Kind() == reflect.Interface {
return
}
for i := 0; i < t1.NumField(); i++ {
ft := t1.Field(i)
field := v.Field(i)
if ft.Anonymous {
expors(buf, field, have)
continue
}
name := ft.Name
if name == "" {
continue
}
if !(name[0] >= 'A' && name[0] <= 'Z') {
continue
}
if field.CanInterface() {
val := fmt.Sprint(field.Interface())
if val == "" {
val = "null"
} else if strings.HasPrefix(val, "map") {
val = "{}"
}
buf.WriteString(fmt.Sprintf("export const %s = %s;\n", name, val))
} else {
buf.WriteString(fmt.Sprintf("export const %s = null;\n", name))
}
}
//导出方法名
for i := 0; i < t.NumMethod(); i++ {
method := t.Method(i)
name := method.Name
if !(name[0] >= 'A' && name[0] <= 'Z') {
continue
}
buf.WriteString(fmt.Sprintf("export function %s (", name))
for j := 0; j < method.Type.NumIn(); j++ {
if j == 0 {
continue
}
param := method.Type.In(j).String()
pos := strings.LastIndexByte(param, '.')
if pos >= 0 {
param = param[pos+1:]
}
param = ConverJsType(param)
if j == 1 {
buf.WriteString(fmt.Sprintf("%s_%d", param, j))
} else {
buf.WriteString(fmt.Sprintf(",%s_%d", param, j))
}
}
buf.WriteString("){return null};\n")
}
}
func Exports(obj any) string {
buf := bytes.NewBufferString("// Code generated by jun. DO NOT EDIT.\n")
// 获取结构体的类型
v := reflect.ValueOf(obj)
name := v.Type().Elem().Name()
name = strings.ToLower(name)
if n, ok := obj.(Namer); ok {
name = n.Name()
}
buf.WriteString(fmt.Sprintf("// import * as %s from './lib/%s.js'\n\n", name, name))
have := false
expors(buf, v, &have)
if e, ok := obj.(Exporter); ok {
buf.WriteString(e.Export())
}
buf.WriteString("\n")
dir := jsDir + "lib/"
_, err := os.Stat(dir)
if err != nil {
os.MkdirAll(dir, 0755)
}
if runtime.GOOS != "android" {
os.WriteFile(dir+strings.ToLower(name)+".js", buf.Bytes(), 0644)
}
return buf.String()
}
func ConverJsType(t string) string {
switch t {
case "interface {}":
return "any"
case "map[string]string":
return "any"
}
if strings.Contains(t, "interface") {
return "any"
}
t = strings.ReplaceAll(t, "[]", "Arr")
return t
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/haodreams/golib.git
git@gitee.com:haodreams/golib.git
haodreams
golib
golib
v1.0.0

搜索帮助