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.
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:
This test fails with:
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.