113 lines
2.2 KiB
Go
113 lines
2.2 KiB
Go
//go:build !js && !wasm
|
|
|
|
package jsrunner
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
|
|
"github.com/dop251/goja"
|
|
)
|
|
|
|
type gojaRunner struct {
|
|
vm *goja.Runtime
|
|
}
|
|
|
|
type gojaValue struct {
|
|
val goja.Value
|
|
vm *goja.Runtime
|
|
}
|
|
|
|
func NewJSRunner() JSRunner {
|
|
return &gojaRunner{vm: goja.New()}
|
|
}
|
|
|
|
// UNUSED
|
|
func (g *gojaRunner) MustGet(key string) (JSValue, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (g *gojaRunner) Engine() Engine {
|
|
return Goja
|
|
}
|
|
|
|
func (g *gojaRunner) RunString(code string) (JSValue, error) {
|
|
val, err := g.vm.RunString(code)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &gojaValue{val: val, vm: g.vm}, nil
|
|
}
|
|
|
|
func (v *gojaValue) String() string {
|
|
return v.val.String()
|
|
}
|
|
|
|
func (v *gojaValue) Export() interface{} {
|
|
return v.val.Export()
|
|
}
|
|
|
|
func (g *gojaRunner) NewObject() JSObject {
|
|
return &gojaValue{val: g.vm.NewObject(), vm: g.vm}
|
|
}
|
|
|
|
func (g *gojaRunner) Set(name string, value interface{}) error {
|
|
if name == "console" {
|
|
console, err := g.createConsole()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return g.vm.Set(name, console)
|
|
}
|
|
return g.vm.Set(name, value)
|
|
}
|
|
|
|
func (g *gojaRunner) WaitPromise(ctx context.Context, val JSValue) (interface{}, error) {
|
|
gVal := val.(*gojaValue)
|
|
p := gVal.val.Export()
|
|
promise := p.(*goja.Promise)
|
|
|
|
for promise.State() == goja.PromiseStatePending {
|
|
if err := ctx.Err(); err != nil {
|
|
return nil, err
|
|
}
|
|
continue
|
|
}
|
|
|
|
if promise.State() == goja.PromiseStateRejected {
|
|
return nil, errors.New("Promise rejected")
|
|
}
|
|
|
|
return promise.Result().Export(), nil
|
|
}
|
|
|
|
func (g *gojaRunner) createConsole() (*goja.Object, error) {
|
|
vm := g.vm
|
|
console := vm.NewObject()
|
|
|
|
if err := console.Set("log", vm.ToValue(func(call goja.FunctionCall) goja.Value {
|
|
args := make([]interface{}, len(call.Arguments))
|
|
for i, arg := range call.Arguments {
|
|
args[i] = arg.Export()
|
|
}
|
|
fmt.Println(args...)
|
|
return nil
|
|
})); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := console.Set("error", vm.ToValue(func(call goja.FunctionCall) goja.Value {
|
|
args := make([]interface{}, len(call.Arguments))
|
|
for i, arg := range call.Arguments {
|
|
args[i] = arg.Export()
|
|
}
|
|
fmt.Fprintln(os.Stderr, args...)
|
|
return nil
|
|
})); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return console, nil
|
|
}
|