2024-03-14 00:03:40 +00:00
|
|
|
package javascript
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
2024-05-23 01:28:15 +00:00
|
|
|
"reflect"
|
2024-03-14 00:03:40 +00:00
|
|
|
|
|
|
|
"github.com/dop251/goja"
|
|
|
|
)
|
|
|
|
|
|
|
|
type VM struct {
|
|
|
|
*goja.Runtime
|
|
|
|
|
|
|
|
Progress chan float64
|
|
|
|
SessionCookie *http.Cookie
|
|
|
|
GQLHandler http.Handler
|
|
|
|
}
|
|
|
|
|
2024-05-23 01:28:15 +00:00
|
|
|
// optionalFieldNameMapper wraps a goja.FieldNameMapper and returns the field name if the wrapped mapper returns an empty string.
|
|
|
|
type optionalFieldNameMapper struct {
|
|
|
|
mapper goja.FieldNameMapper
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tfm optionalFieldNameMapper) FieldName(t reflect.Type, f reflect.StructField) string {
|
|
|
|
if ret := tfm.mapper.FieldName(t, f); ret != "" {
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
return f.Name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tfm optionalFieldNameMapper) MethodName(t reflect.Type, m reflect.Method) string {
|
|
|
|
return tfm.mapper.MethodName(t, m)
|
|
|
|
}
|
|
|
|
|
2024-03-14 00:03:40 +00:00
|
|
|
func NewVM() *VM {
|
2024-05-23 01:28:15 +00:00
|
|
|
r := goja.New()
|
|
|
|
r.SetFieldNameMapper(optionalFieldNameMapper{goja.TagFieldNameMapper("json", true)})
|
|
|
|
return &VM{Runtime: r}
|
2024-03-14 00:03:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type APIAdder interface {
|
|
|
|
AddToVM(globalName string, vm *VM) error
|
|
|
|
}
|
|
|
|
|
|
|
|
type ObjectValueDef struct {
|
|
|
|
Name string
|
|
|
|
Value interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
type setter interface {
|
|
|
|
Set(name string, value interface{}) error
|
|
|
|
}
|
|
|
|
|
|
|
|
func Compile(path string) (*goja.Program, error) {
|
|
|
|
js, err := os.ReadFile(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to read file: %w", err)
|
|
|
|
}
|
|
|
|
return goja.Compile(path, string(js), true)
|
|
|
|
}
|
|
|
|
|
|
|
|
func CompileScript(name, script string) (*goja.Program, error) {
|
|
|
|
return goja.Compile(name, string(script), true)
|
|
|
|
}
|
|
|
|
|
|
|
|
func SetAll(s setter, defs ...ObjectValueDef) error {
|
|
|
|
for _, def := range defs {
|
|
|
|
if err := s.Set(def.Name, def.Value); err != nil {
|
|
|
|
return fmt.Errorf("failed to set %s: %w", def.Name, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v *VM) Throw(err error) {
|
|
|
|
e, newErr := v.New(v.Get("Error"), v.ToValue(err))
|
|
|
|
if newErr != nil {
|
|
|
|
panic(newErr)
|
|
|
|
}
|
|
|
|
|
|
|
|
panic(e)
|
|
|
|
}
|