robertkrimen / otto

A JavaScript interpreter in Go (golang)
http://godoc.org/github.com/robertkrimen/otto
MIT License
8.12k stars 587 forks source link

Otto.ToValue fails on nested maps and arrays #13

Closed snej closed 11 years ago

snej commented 11 years ago

I need to pass structured Go data (maps and arrays) as parameters to a JS function. Otto.ToValue looks as though it should be able to do this, and in fact the call succeeds, but when the JS code tries to access values inside the top-level value it fails. The failure seems to occur when the nested value is itself a map or array.

Here's a test case:

func TestOttoMapToValue(t *testing.T) {
    o := otto.New()
    goMap := map[string]interface{}{"s": "a string", "n": 1234, "a": []string{"foo", "bar"}}
    v, err := o.ToValue(goMap)
    if err != nil {
        t.Fatalf("Error from ToValue: %v", err)
    }
    fnobj, err := o.Object("(function(v){return [v.s, v.n, v.a];})")
    if err != nil {
        t.Fatalf("Error from Object: %v", err)
    }
    fnval := fnobj.Value()
    _, err = fnval.Call(fnval, v)
    if err != nil {
        t.Fatalf("Error from Call: %v", err)
    }
}

This test fails with:

Error from Call: TypeError: Invalid value (slice): Missing runtime: [foo bar] ([]string) (line 1)

The failure appears to happen when the function toValue (in value.go) is called with a parameter that's a slice, which it can't handle because it has no Otto context within which to allocate a JS array.

The solution might be for Otto.ToValue to descend recursively into the input value, converting the values contained inside it into JS objects immediately, rather than using the lazy approach it seems to be taking now.

There is a workaround to this limitation, which is to use Go's fmt/json package to encode the value as a JSON string and then call Otto.Object() to evaluate it into a JS value. But this is inevitably going to be more expensive, and the project I'm working on needs better performance.

robertkrimen commented 11 years ago

Hi. Yes, thank you, there are actually a couple of things I'm seeing wrong with the goMap type.

Thankfully I think the fixes are pretty straightforward.

snej commented 11 years ago

Works great now; thanks!