gomonkey

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 2, 2024 License: BSD-3-Clause Imports: 8 Imported by: 0

README

GoMonkey

Go Reference

Go bindings to Mozilla Javascript Engine SpiderMonkey.

Usage

$ go get github.com/bhuisgen/gomonkey
Using JS contexts
var wg sync.WaitGroup

wg.Add(1)
go func() {
  defer wg.Done()

  // lock the goroutine to its own OS thread
  runtime.LockOSThread()
  defer runtime.UnlockOSThread()

  // create the context
  ctx, err := gomonkey.NewContext()
  if err != nil {
    return
  }
  defer ctx.Destroy() // destroy after usage

  // use the context only inside this goroutine
}()

wg.Wait()
Using JS objects
var wg sync.WaitGroup

wg.Add(1)
go func() {
  runtime.LockOSThread()
  defer func() {
    runtime.UnlockOSThread()
    wg.Done()
  }()

  ctx, err := gomonkey.NewContext()
  if err != nil {
    return
  }
  defer ctx.Destroy()

  // get the global object ...

  global, err := ctx.Global()
  if err != nil {
    return
  }
  defer global.Release() // release after usage

  // ... or create a new object ...

  object, err := gomonkey.NewObject(ctx)
  if err != nil {
    return
  }
  defer object.Release() // release after usage

  // ... add a property ...

  propValue1, err := gomonkey.NewValueString(ctx, "string")
  if err != nil {
    return
  }
  defer propValue1.Release() // release after usage
  if err := object.Set("key1", propValue1); err != nil {
    return
  }

  // ... check if a property exists ...

  b := object.Has("key2")
  _ = b // use result

  // ... get a property value ...

  propValue3, err := object.Get("key3")
  if err != nil {
    return
  }
  defer propValue3.Release() // release after usage

  // ... delete a property ...

  if err := object.Delete("key4"); err != nil {
    return
  }
}()

wg.Wait()
Evaluate code

To evaluate some JS code, evaluate it directly:

var wg sync.WaitGroup

wg.Add(1)
go func() {
  runtime.LockOSThread()
  defer func() {
    runtime.UnlockOSThread()
    wg.Done()
  }()

  ctx, err := gomonkey.NewContext()
  if err != nil {
    return
  }
  defer ctx.Destroy()

  result, err := ctx.Evaluate([]byte("(() => { return 'result'; })()"))
  if err != nil {
    return
  }
  defer result.Release() // release after usage

  if !result.IsString() { // check value type
    return
  }
  _ = result.String() // use the value
}()

wg.Wait()
Execute a script

If you need to execute multiple times the same JS code, compile it as a script and execute it as many times as needed:

var wg sync.WaitGroup

wg.Add(1)
go func() {
  runtime.LockOSThread()
  defer func() {
    runtime.UnlockOSThread()
    wg.Done()
  }()

  ctx, err := gomonkey.NewContext()
  if err != nil {
    return
  }
  defer ctx.Destroy()

  // load your script ...

  code, err := os.ReadFile("script.js")
  if err != nil {
    return
  }

  // compile the script ...

  script, err := ctx.CompileScript("script.js", code)
  if err != nil {
    return
  }
  defer script.Release() // release after usage

  // .. and execute it ...

  result1, err := ctx.ExecuteScript(script)
  if err != nil {
    return
  }
  defer result1.Release() // release after usage

  if !result1.IsString() { // check value type
    return
  }
  _ = result1.String() // use the value

  // ... one more time please ...

  result2, err := ctx.ExecuteScript(script)
  if err != nil {
    return
  }
  defer result2.Release() // release after usage

  if !result2.IsString() { // check value type
    return
  }
  _ = result2.String() // use the value
}()

wg.Wait()
Execute a script shared between contexts

To share a script between several contexts, compile it as a stencil:

var wg sync.WaitGroup

ch := make(chan *gomonkey.Stencil)

// compile script as a stencil in a frontend context ...

wg.Add(1)
go func(ch chan<- *gomonkey.Stencil) {
  runtime.LockOSThread()
  defer func() {
    runtime.UnlockOSThread()
    wg.Done()
  }()

  ctx, err := gomonkey.NewFrontendContext()
  if err != nil {
    return
  }
  defer ctx.Destroy()

  code, err := os.ReadFile("script.js")
  if err != nil {
    return
  }

  stencil, err := ctx.CompileScriptToStencil("script.js", code)
  if err != nil {
    return
  }

  ch <- stencil
  close(ch)
}(ch)

// ... and execute it from another context ...

wg.Add(1)
go func(ch <-chan *gomonkey.Stencil) {
  runtime.LockOSThread()
  defer func() {
    runtime.UnlockOSThread()
    wg.Done()
  }()

  ctx, err := gomonkey.NewContext()
  if err != nil {
    return
  }
  defer ctx.Destroy()

  stencil := <-ch         // share the stencil
  defer stencil.Release() // release the stencil from the last goroutine

  for i := 0; i < 10; i++ {
    value, err := ctx.ExecuteScriptFromStencil(stencil)
    if err != nil {
      return
    }
    defer value.Release() // release after usage
  }
}(ch)

wg.Wait()
Create a global function
var wg sync.WaitGroup

wg.Add(1)
go func() {
  runtime.LockOSThread()
  defer func() {
    runtime.UnlockOSThread()
    wg.Done()
  }()

  ctx, err := gomonkey.NewContext()
  if err != nil {
    return
  }
  defer ctx.Destroy()

  // get the global object ...

  global, err := ctx.Global()
  if err != nil {
    return
  }
  defer global.Release() // release after usage

  // ... implement your Go function ...

  hello := func(args []*gomonkey.Value) (*gomonkey.Value, error) {
    // parse any arguments but do not release them
    for _, arg := range args {
      _ = arg
    }
    // create the returned value
    retValue, err := gomonkey.NewValueString(ctx, "hello world!")
    if err != nil {
      return nil, errors.New("create value")
    }
    return retValue, nil // do not release it
  }

  // ... and register it as a JS function

  if err := ctx.DefineFunction(global, "hello", hello, 0, 0); err != nil {
    return
  }
}()

wg.Wait()
Create a function object
var wg sync.WaitGroup

wg.Add(1)
go func() {
  runtime.LockOSThread()
  defer func() {
    runtime.UnlockOSThread()
    wg.Done()
  }()

  ctx, err := gomonkey.NewContext()
  if err != nil {
    return
  }
  defer ctx.Destroy()

  // create a new function ...

  fn, err := gomonkey.NewFunction(ctx, "name", func(args []*gomonkey.Value) (*gomonkey.Value, error) {
    // parse any arguments but do not release them
    for _, arg := range args {
      _ = arg
    }
    // create the returned value
    retValue, err := gomonkey.NewValueString(ctx, "hello world!")
    if err != nil {
      return nil, errors.New("create value")
    }
    return retValue, nil // do not release it
  })
  if err != nil {
    return
  }
  defer fn.Release() // release after usage

  // ... you can call it with a receiver (object) ...

  receiver, err := gomonkey.NewObject(ctx)
  if err != nil {
    return
  }
  defer receiver.Release() // release after usage

  arg0, err := gomonkey.NewValueString(ctx, "value")
  if err != nil {
    return
  }
  defer arg0.Release() // release after usage

  result, err := fn.Call(receiver, arg0)
  if err != nil {
    return
  }
  defer result.Release() // release after usage
}()

wg.Wait()
Create an object method
var wg sync.WaitGroup

wg.Add(1)
go func() {
  runtime.LockOSThread()
  defer func() {
    runtime.UnlockOSThread()
    wg.Done()
  }()

  ctx, err := gomonkey.NewContext()
  if err != nil {
    return
  }
  defer ctx.Destroy()

  // create a new object ...

  object, err := gomonkey.NewObject(ctx)
  if err != nil {
    return
  }
  defer object.Release() // release after usage

  // ... create a function ...

  fn, err := gomonkey.NewFunction(ctx, "hello", func(args []*gomonkey.Value) (*gomonkey.Value, error) {
    // parse any arguments but do not release them
    for _, arg := range args {
      _ = arg
    }
    // create the returned value
    retValue, err := gomonkey.NewValueString(ctx, "hello world!")
    if err != nil {
      return nil, errors.New("create value")
    }
    return retValue, nil // do not release it
  })
  if err != nil {
    return
  }

  // ... set it as a property on the object ...

  if err := object.Set("showHello", fn.AsValue()); err != nil {
    return
  }

  // ... and call this new method ...

  result, err := object.Call("showHello")
  if err != nil {
    return
  }
  defer result.Release() // release after usage
}()

wg.Wait()

Setup

The shared library libmozjs-115.so is required for compilation and execution.

Prebuilt libraries are available for different OS/arch in the deps/lib directory:

OS CPU Version
FreeBSD amd64 FreeBSD 14
Linux amd64 Debian 12
NetBSD amd64 NetBSD 9
OpenBSD amd64 OpenBSD 7

If your system is not available, you have to build the library. Please follow the instructions in the build document.

Copy the library in your system library path :

FreeBSD:

$ sudo cp deps/lib/freebsd_amd64/release/lib/libmozjs-115.so /usr/lib/

Linux:

$ sudo cp deps/lib/linux_amd64/release/lib/libmozjs-115.so /usr/lib/x86_64-linux-gnu/

NetBSD:

$ sudo cp deps/lib/netbsd_amd64/release/lib/libmozjs-115.so /usr/lib/

OpenBSD:

$ sudo cp deps/lib/openbsd_amd64/release/lib/libmozjs-115.so /usr/lib/

To troubleshoot any missing system libraries, use the ldd command.

Development

Build SpiderMonkey with debug support

The SpiderMonkey library should be built with debugging support during development. Please refer to the instructions in the build document.

Test the Go bindings

First step is to run the unit tests:

$ go test ./tests/...

Then run the smoke tests:

$ go run cmd/smoke/main.go

Documentation

Overview

Package gomonkey implements the go bindings to SpiderMonkey.

Index

Constants

View Source
const (
	PropertyAttributeDefault   PropertyAttributes = 0
	PropertyAttributeEnumerate                    = 1 << iota
	PropertyAttributeReadOnly
	PropertyAttributePermanent
)

Variables

This section is empty.

Functions

func Init

func Init()

Init initializes SpiderMonkey.

func JSONStringify

func JSONStringify(c *Context, v Valuer) (string, error)

JSONStringify encodes a JS value to a JSON-encoded string.

func ShutDown

func ShutDown()

ShutDown shutdowns SpiderMonkey.

func Version

func Version() string

Version returns the version of SpiderMonkey.

Types

type ArrayObject

type ArrayObject struct {
	// contains filtered or unexported fields
}

ArrayObject implements a JS array object.

func NewArrayObject

func NewArrayObject(ctx *Context, values ...*Value) (*ArrayObject, error)

NewArrayObject creates a new array.

func (*ArrayObject) AsObject

func (o *ArrayObject) AsObject() (*Object, error)

AsObject casts as a JS object.

func (*ArrayObject) AsValue

func (o *ArrayObject) AsValue() *Value

AsValue casts as a JS value.

func (*ArrayObject) Length

func (o *ArrayObject) Length() uint

Length returns the array length.

func (*ArrayObject) Release

func (o *ArrayObject) Release()

Release releases the array.

type Context

type Context struct {
	// contains filtered or unexported fields
}

Context represents a JS context.

func NewContext

func NewContext(options ...ContextOptionFunc) (*Context, error)

NewContext creates a new context.

func (*Context) CallFunctionName

func (c *Context) CallFunctionName(name string, receiver Valuer, args ...*Value) (*Value, error)

CallFunctionName executes a JS function by its name.

func (*Context) CallFunctionValue

func (c *Context) CallFunctionValue(function Valuer, receiver Valuer, args ...*Value) (*Value, error)

CallFunctionName executes a JS function by its value.

func (*Context) CompileScript

func (c *Context) CompileScript(name string, code []byte) (*Script, error)

CompileScript compiles a JS code into a script.

func (*Context) DefineElement

func (c *Context) DefineElement(object *Object, index uint, value *Value, attrs PropertyAttributes) error

DefineElement defines a new element on the given JS object.

func (*Context) DefineFunction

func (c *Context) DefineFunction(object *Object, name string, callback FunctionCallback, args uint,
	attrs PropertyAttributes) error

DefineFunction defines a new JS function and sets it as a property of the given JS object.

func (*Context) DefineObject

func (c *Context) DefineObject(object *Object, name string, attrs PropertyAttributes) (*Object, error)

DefineObject defines a new JS object and sets it as a property of the given JS object.

func (*Context) DefineProperty

func (c *Context) DefineProperty(object *Object, name string, value *Value, attrs PropertyAttributes) error

DefineProperty defines a new property on the given JS object.

func (*Context) Destroy

func (c *Context) Destroy()

Destroy destroys the context.

func (*Context) Evaluate

func (c *Context) Evaluate(code []byte) (*Value, error)

Evaluates executes a JS code.

func (*Context) ExecuteScript

func (c *Context) ExecuteScript(script *Script) (*Value, error)

Execute executes a script.

func (*Context) ExecuteScriptFromStencil

func (c *Context) ExecuteScriptFromStencil(stencil *Stencil) (*Value, error)

Execute executes a script from a stencil.

func (*Context) Global

func (c *Context) Global() (*Object, error)

Global returns the global object.

func (*Context) RequestInterrupt

func (c *Context) RequestInterrupt()

RequestInterrupt requests the context interruption.

type ContextOptionFunc

type ContextOptionFunc func(c *Context) error

ContextOptionFunc represents a context option function.

func WithGCIncrementalEnabled

func WithGCIncrementalEnabled(state bool) ContextOptionFunc

WithGCIncrementalEnabled enables the incremental GC.

func WithGCMaxBytes

func WithGCMaxBytes(max uint) ContextOptionFunc

WithGCMaxBytes sets the maximum heap size in bytes before GC.

func WithGCSliceTimeBudget

func WithGCSliceTimeBudget(d time.Duration) ContextOptionFunc

WithGCSliceTimeBudget sets the maximal time to spend in an incremental GC slice.

func WithHeapMaxBytes

func WithHeapMaxBytes(max uint) ContextOptionFunc

WithHeapMaxBytes sets the maximum heap size in bytes.

func WithNativeStackSize

func WithNativeStackSize(size uint) ContextOptionFunc

WithNativeStackSize sets the native stack size in bytes.

type FrontendContext

type FrontendContext struct {
	// contains filtered or unexported fields
}

FrontendContext represents a JS frontend context.

func NewFrontendContext

func NewFrontendContext(options ...FrontendContextOptionFunc) (*FrontendContext, error)

NewFrontendContext creates a new context.

func (*FrontendContext) CompileScriptToStencil

func (c *FrontendContext) CompileScriptToStencil(name string, code []byte) (*Stencil, error)

CompileScriptToStencil compiles a script to a stencil.

func (*FrontendContext) Destroy

func (c *FrontendContext) Destroy()

Destroy destroys the context.

type FrontendContextOptionFunc

type FrontendContextOptionFunc func(c *FrontendContext) error

FrontendContextOptionFunc represents a frontend context option function.

func WithFrontendNativeStackSize

func WithFrontendNativeStackSize(size uint) FrontendContextOptionFunc

WithNativeStackSize sets the native stack size in bytes.

type Function

type Function struct {
	// contains filtered or unexported fields
}

Function represents a JS function.

func NewFunction

func NewFunction(ctx *Context, name string, callback FunctionCallback) (*Function, error)

NewFunction creates a new JS function.

func (*Function) AsValue

func (f *Function) AsValue() *Value

AsValue casts as a JS value.

func (*Function) Call

func (f *Function) Call(recv Valuer, args ...*Value) (*Value, error)

Call calls the function.

func (*Function) Release

func (f *Function) Release()

Release releases the function.

type FunctionCallback

type FunctionCallback func(args []*Value) (*Value, error)

FunctionCallback implements a JS function callback.

type JSError

type JSError struct {
	Message     string
	Filename    string
	LineNumber  int
	ErrorNumber int
}

JSError implements a JS error.

func (*JSError) Error

func (e *JSError) Error() string

Error returns the error message.

func (*JSError) Format

func (e *JSError) Format(f fmt.State, verb rune)

Format implements fmt.Formatter.

type Object

type Object struct {
	// contains filtered or unexported fields
}

Object implements a JS object.

func JSONParse

func JSONParse(c *Context, str string) (*Object, error)

JSONParse decodes a JSON-encoded string to a JS object.

func NewObject

func NewObject(ctx *Context) (*Object, error)

NewObject creates a new object.

func (*Object) AsValue

func (o *Object) AsValue() *Value

AsValue casts as a JS value.

func (*Object) Call

func (o *Object) Call(name string, args ...*Value) (*Value, error)

Call calls a method.

func (*Object) Delete

func (o *Object) Delete(key string) error

Delete deletes an object property.

func (*Object) DeleteElement

func (o *Object) DeleteElement(index int) error

DeleteElement deletes an object element.

func (*Object) Get

func (o *Object) Get(key string) (*Value, error)

Get returns an object property.

func (*Object) GetElement

func (o *Object) GetElement(index int) (*Value, error)

GetElement returns an object element.

func (*Object) Has

func (o *Object) Has(key string) bool

Has checks if the object has the given property.

func (*Object) HasElement

func (o *Object) HasElement(index int) bool

HasElement checks if the object has the given element.

func (*Object) Release

func (o *Object) Release()

Release releases the object.

func (*Object) Set

func (o *Object) Set(key string, value *Value) error

Set defines an object property.

func (*Object) SetElement

func (o *Object) SetElement(index int, value *Value) error

SetElement defines an object element.

type PropertyAttributes

type PropertyAttributes uint8

PropertyAttributes represents the attributes of a property.

func (PropertyAttributes) Has

Has checks if an attribute is set.

type Script

type Script struct {
	// contains filtered or unexported fields
}

Script represents a JS script.

func (*Script) Release

func (s *Script) Release()

Release releases the script.

type Stencil

type Stencil struct {
	// contains filtered or unexported fields
}

Stencil implements a JS stencil.

func (*Stencil) Release

func (s *Stencil) Release()

Release releases the stencil.

type Value

type Value struct {
	// contains filtered or unexported fields
}

Value implements a JS Value.

func NewValueBoolean

func NewValueBoolean(ctx *Context, b bool) (*Value, error)

NewValueBoolean creates a new JS boolean value.

func NewValueInt32

func NewValueInt32(ctx *Context, i int32) (*Value, error)

NewValueInt32 creates a new JS int32 value.

func NewValueNull

func NewValueNull(ctx *Context) (*Value, error)

NewValueNull creates a new JS null value.

func NewValueNumber

func NewValueNumber(ctx *Context, f float64) (*Value, error)

NewValueNumber creates a new JS number value.

func NewValueString

func NewValueString(ctx *Context, str string) (*Value, error)

NewValueString creates a new JS string value.

func NewValueUndefined

func NewValueUndefined(ctx *Context) (*Value, error)

NewValueUndefined creates a new JS undefined value.

func (*Value) AsFunction

func (v *Value) AsFunction() (*Function, error)

AsFunction casts as a JS function.

func (*Value) AsObject

func (v *Value) AsObject() (*Object, error)

AsObject casts as a JS object.

func (*Value) AsValue

func (v *Value) AsValue() *Value

AsValue casts as a JS value.

func (*Value) Format

func (v *Value) Format(f fmt.State, verb rune)

Format implements fmt.Formatter.

func (*Value) IsBoolean

func (v *Value) IsBoolean() bool

IsBoolean checks if the JS value is a JS boolean.

func (*Value) IsFalse

func (v *Value) IsFalse() bool

IsFalse checks if the JS value is a JS boolean sets to false.

func (*Value) IsFunction

func (v *Value) IsFunction() bool

IsFunction checks if the JS value is a JS function.

func (*Value) IsInt32

func (v *Value) IsInt32() bool

IsInt32 checks if the JS value is a JS int32.

func (*Value) IsNull

func (v *Value) IsNull() bool

IsNull checks if the JS value is null.

func (*Value) IsNullOrUndefined

func (v *Value) IsNullOrUndefined() bool

IsNullOrUndefined checks if the JS value is null or undefined.

func (*Value) IsNumber

func (v *Value) IsNumber() bool

IsNumber checks if the JS value is a JS number.

func (*Value) IsObject

func (v *Value) IsObject() bool

IsObject checks if the JS value is a JS object.

func (*Value) IsString

func (v *Value) IsString() bool

IsString checks if the JS value is a JS string.

func (*Value) IsSymbol

func (v *Value) IsSymbol() bool

IsSymbol checks if the JS value is a JS symbol.

func (*Value) IsTrue

func (v *Value) IsTrue() bool

IsTrue checks if the JS value is a JS boolean sets to true.

func (*Value) IsUndefined

func (v *Value) IsUndefined() bool

IsUndefined checks if the JS value is undefined.

func (*Value) MarshalJSON

func (v *Value) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler.

func (*Value) Release

func (v *Value) Release()

Release releases the value.

func (*Value) String

func (v *Value) String() string

String returns the value string representation.

func (*Value) ToBoolean

func (v *Value) ToBoolean() bool

ToBoolean returns the JS boolean value.

func (*Value) ToInt32

func (v *Value) ToInt32() int32

ToInt32 returns the JS int32 value.

func (*Value) ToNumber

func (v *Value) ToNumber() float64

ToNumber returns the JS number value.

func (*Value) ToString

func (v *Value) ToString() string

ToString returns the JS string value.

type Valuer

type Valuer interface {
	AsValue() *Value
}

Valuer represents any object extending a JS value.

Directories

Path Synopsis
cmd
example
This command executes the code examples in the README file.
This command executes the code examples in the README file.
smoke
This command executes the smoke tests.
This command executes the smoke tests.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL