From a9dcbab0fd4b5adfb40cb924f14ee2af9c8938eb Mon Sep 17 00:00:00 2001
From: Richard Musiol <mail@richard-musiol.de>
Date: Tue, 31 Jul 2018 15:12:57 +0200
Subject: [PATCH] syscall/js: extend ValueOf to support arrays and objects

This commits adds []interface{} and map[string]interface{} as quick
ways to create JavaScript arrays and objects. They correspond to the
JavaScript notations [...] and {...}. A type alias can be used for
a concise notation.

Change-Id: I98bb08dbef1e0f3bd3d65c732d6b09e1520026ba
Reviewed-on: https://go-review.googlesource.com/126855
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
---
 src/syscall/js/js.go      | 35 ++++++++++++++++++++++++++---------
 src/syscall/js/js_test.go | 15 +++++++++++++++
 2 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/src/syscall/js/js.go b/src/syscall/js/js.go
index 5deef35c2bb..336586ca2dd 100644
--- a/src/syscall/js/js.go
+++ b/src/syscall/js/js.go
@@ -64,6 +64,9 @@ var (
 	valueGlobal    = predefValue(5)
 	memory         = predefValue(6) // WebAssembly linear memory
 	jsGo           = predefValue(7) // instance of the Go class in JavaScript
+
+	objectConstructor = valueGlobal.Get("Object")
+	arrayConstructor  = valueGlobal.Get("Array")
 )
 
 // Undefined returns the JavaScript value "undefined".
@@ -83,15 +86,17 @@ func Global() Value {
 
 // ValueOf returns x as a JavaScript value:
 //
-//  | Go                    | JavaScript            |
-//  | --------------------- | --------------------- |
-//  | js.Value              | [its value]           |
-//  | js.TypedArray         | [typed array]         |
-//  | js.Callback           | function              |
-//  | nil                   | null                  |
-//  | bool                  | boolean               |
-//  | integers and floats   | number                |
-//  | string                | string                |
+//  | Go                     | JavaScript             |
+//  | ---------------------- | ---------------------- |
+//  | js.Value               | [its value]            |
+//  | js.TypedArray          | typed array            |
+//  | js.Callback            | function               |
+//  | nil                    | null                   |
+//  | bool                   | boolean                |
+//  | integers and floats    | number                 |
+//  | string                 | string                 |
+//  | []interface{}          | new array              |
+//  | map[string]interface{} | new object             |
 func ValueOf(x interface{}) Value {
 	switch x := x.(type) {
 	case Value:
@@ -138,6 +143,18 @@ func ValueOf(x interface{}) Value {
 		return floatValue(x)
 	case string:
 		return makeValue(stringVal(x))
+	case []interface{}:
+		a := arrayConstructor.New(len(x))
+		for i, s := range x {
+			a.SetIndex(i, s)
+		}
+		return a
+	case map[string]interface{}:
+		o := objectConstructor.New()
+		for k, v := range x {
+			o.Set(k, v)
+		}
+		return o
 	default:
 		panic("ValueOf: invalid value")
 	}
diff --git a/src/syscall/js/js_test.go b/src/syscall/js/js_test.go
index 753e262d52e..9cc931a31d3 100644
--- a/src/syscall/js/js_test.go
+++ b/src/syscall/js/js_test.go
@@ -254,6 +254,21 @@ func TestType(t *testing.T) {
 	}
 }
 
+type object = map[string]interface{}
+type array = []interface{}
+
+func TestValueOf(t *testing.T) {
+	a := js.ValueOf(array{0, array{0, 42, 0}, 0})
+	if got := a.Index(1).Index(1).Int(); got != 42 {
+		t.Errorf("got %v, want %v", got, 42)
+	}
+
+	o := js.ValueOf(object{"x": object{"y": 42}})
+	if got := o.Get("x").Get("y").Int(); got != 42 {
+		t.Errorf("got %v, want %v", got, 42)
+	}
+}
+
 func TestCallback(t *testing.T) {
 	c := make(chan struct{})
 	cb := js.NewCallback(func(args []js.Value) {
-- 
GitLab