diff --git a/context.go b/context.go index 718757068..557735503 100644 --- a/context.go +++ b/context.go @@ -169,6 +169,22 @@ func valueResult(ctx *Context, rtn C.RtnValue) (*Value, error) { return &Value{rtn.value, ctx}, nil } +func valueStrings(ctx *Context, rtn C.RtnStrings) ([]string, error) { + if rtn.strings == nil { + return []string{}, newJSError(rtn.error) + } + length := rtn.length + slice := (*[1 << 28]*C.char)(unsafe.Pointer(rtn.strings))[:length:length] + var result []string + for i := 0; i < len(slice); i++ { + s := slice[i] + defer C.free(unsafe.Pointer(s)) + result = append(result, C.GoString(s)) + } + defer C.free(unsafe.Pointer(rtn.strings)) + return result, nil +} + func objectResult(ctx *Context, rtn C.RtnValue) (*Object, error) { if rtn.value == nil { return nil, newJSError(rtn.error) diff --git a/deps/depot_tools b/deps/depot_tools index db41eed6b..85d7fe7fe 160000 --- a/deps/depot_tools +++ b/deps/depot_tools @@ -1 +1 @@ -Subproject commit db41eed6b7442273b54bac9695567d97b60718de +Subproject commit 85d7fe7fe82ad5876c2bb95784d9b9f282115f92 diff --git a/object.go b/object.go index 08a0a6b6b..0855fb2ce 100644 --- a/object.go +++ b/object.go @@ -79,6 +79,13 @@ func (o *Object) SetIdx(idx uint32, val interface{}) error { return nil } +// Returns an array containing the names of the enumerable properties of this object, +// including properties from prototype objects +func (o *Object) GetEnumerablePropertyNames() ([]string, error) { + rtn := C.ObjectGetPropertyNames(o.ptr) + return valueStrings(o.ctx, rtn) +} + // SetInternalField sets the value of an internal field for an ObjectTemplate instance. // Panics if the index isn't in the range set by (*ObjectTemplate).SetInternalFieldCount. func (o *Object) SetInternalField(idx uint32, val interface{}) error { diff --git a/object_test.go b/object_test.go index b40d1b0db..16649e817 100644 --- a/object_test.go +++ b/object_test.go @@ -6,6 +6,7 @@ package v8go_test import ( "fmt" + "reflect" "testing" v8 "rogchap.com/v8go" @@ -202,6 +203,27 @@ func TestObjectDelete(t *testing.T) { } +func TestGetEnumerablePropertyNames(t *testing.T) { + t.Parallel() + + ctx := v8.NewContext() + defer ctx.Isolate().Dispose() + defer ctx.Close() + val, _ := ctx.RunScript("const foo = {}; foo", "") + obj, _ := val.AsObject() + obj.Set("bar2", "baz2") + obj.Set("foo", "foobar") + obj.Set("hello", "world") + + expectedProperties := []string{"bar2", "foo", "hello"} + properties, err := obj.GetEnumerablePropertyNames() + fatalIf(t, err) + + if !reflect.DeepEqual(properties, expectedProperties) { + t.Error("properteis are not the same") + } +} + func ExampleObject_global() { iso := v8.NewIsolate() defer iso.Dispose() diff --git a/v8go.cc b/v8go.cc index 97390883e..7707d534d 100644 --- a/v8go.cc +++ b/v8go.cc @@ -1297,6 +1297,38 @@ void ObjectSet(ValuePtr ptr, const char* key, ValuePtr prop_val) { obj->Set(local_ctx, key_val, prop_val->ptr.Get(iso)).Check(); } +RtnStrings ObjectGetPropertyNames(ValuePtr ptr) { + LOCAL_OBJECT(ptr); + RtnStrings rtn = {}; + + Local names; + if (!obj->GetPropertyNames(local_ctx).ToLocal(&names)) { + rtn.error = ExceptionError(try_catch, iso, local_ctx); + return rtn; + } + + uint32_t length = names->Length(); + const char** strings = (const char**)malloc(length * sizeof(const char*)); + + for (uint32_t i = 0; i < length; i++) { + Local name_from_array; + if (!names->Get(local_ctx, i).ToLocal(&name_from_array)) { + for (i = i - 1; i > 0; i--) { + free(&strings[i]); + } + free(strings); + rtn.error = ExceptionError(try_catch, iso, local_ctx); + return rtn; + } + String::Utf8Value ds(iso, name_from_array); + strings[i] = CopyString(ds); + } + + rtn.strings = strings; + rtn.length = length; + return rtn; +} + void ObjectSetIdx(ValuePtr ptr, uint32_t idx, ValuePtr prop_val) { LOCAL_OBJECT(ptr); obj->Set(local_ctx, idx, prop_val->ptr.Get(iso)).Check(); diff --git a/v8go.h b/v8go.h index 7acaf0425..4bb9c2947 100644 --- a/v8go.h +++ b/v8go.h @@ -111,6 +111,12 @@ typedef struct { RtnError error; } RtnString; +typedef struct { + const char** strings; + int length; + RtnError error; +} RtnStrings; + typedef struct { size_t total_heap_size; size_t total_heap_size_executable; @@ -271,6 +277,7 @@ int ValueIsModuleNamespaceObject(ValuePtr ptr); extern void ObjectSet(ValuePtr ptr, const char* key, ValuePtr val_ptr); extern void ObjectSetIdx(ValuePtr ptr, uint32_t idx, ValuePtr val_ptr); +RtnStrings ObjectGetPropertyNames(ValuePtr ptr); extern int ObjectSetInternalField(ValuePtr ptr, int idx, ValuePtr val_ptr); extern int ObjectInternalFieldCount(ValuePtr ptr); extern RtnValue ObjectGet(ValuePtr ptr, const char* key);