1//go:build !d2_host_eval23package jsrunner45import (6 "context"7 "errors"8 "fmt"9 "os"1011 "github.com/dop251/goja"12)1314type gojaRunner struct {15 vm *goja.Runtime16}1718type gojaValue struct {19 val goja.Value20 vm *goja.Runtime21}2223func NewJSRunner() JSRunner {24 return &gojaRunner{vm: goja.New()}25}2627func (g *gojaRunner) MustGet(key string) (JSValue, error) {28 return nil, nil29}3031func (g *gojaRunner) Engine() Engine {32 return Goja33}3435func (g *gojaRunner) RunString(code string) (JSValue, error) {36 val, err := g.vm.RunString(code)37 if err != nil {38 return nil, err39 }40 return &gojaValue{val: val, vm: g.vm}, nil41}4243func (v *gojaValue) String() string {44 return v.val.String()45}4647func (v *gojaValue) Export() interface{} {48 return v.val.Export()49}5051func (g *gojaRunner) NewObject() JSObject {52 return &gojaValue{val: g.vm.NewObject(), vm: g.vm}53}5455func (g *gojaRunner) Set(name string, value interface{}) error {56 if name == "console" {57 console, err := g.createConsole()58 if err != nil {59 return err60 }61 return g.vm.Set(name, console)62 }63 return g.vm.Set(name, value)64}6566func (g *gojaRunner) WaitPromise(ctx context.Context, val JSValue) (interface{}, error) {67 gVal := val.(*gojaValue)68 promise := gVal.val.Export().(*goja.Promise)69 for promise.State() == goja.PromiseStatePending {70 if err := ctx.Err(); err != nil {71 return nil, err72 }73 }74 if promise.State() == goja.PromiseStateRejected {75 return nil, errors.New("promise rejected")76 }77 return promise.Result().Export(), nil78}7980func (g *gojaRunner) createConsole() (*goja.Object, error) {81 console := g.vm.NewObject()82 if err := console.Set("log", g.vm.ToValue(func(call goja.FunctionCall) goja.Value {83 args := make([]interface{}, len(call.Arguments))84 for i, arg := range call.Arguments {85 args[i] = arg.Export()86 }87 fmt.Println(args...)88 return nil89 })); err != nil {90 return nil, err91 }92 if err := console.Set("error", g.vm.ToValue(func(call goja.FunctionCall) goja.Value {93 args := make([]interface{}, len(call.Arguments))94 for i, arg := range call.Arguments {95 args[i] = arg.Export()96 }97 fmt.Fprintln(os.Stderr, args...)98 return nil99 })); err != nil {100 return nil, err101 }102 return console, nil103}