[njs] Added Object.getOwnPropertyNames().

Dmitry Volyntsev xeioex at nginx.com
Tue Mar 26 20:07:09 UTC 2019


details:   https://hg.nginx.org/njs/rev/5ef3dbe30d2d
branches:  
changeset: 849:5ef3dbe30d2d
user:      Artem S. Povalyukhin <artem.povaluhin at gmail.com>
date:      Tue Mar 26 08:04:02 2019 +0300
description:
Added Object.getOwnPropertyNames().

This closes #4 issue on Github.

diffstat:

 njs/njs_json.c           |    4 +-
 njs/njs_object.c         |  105 +++++++++++++++++++++++++++++++++++++++++++---
 njs/njs_object.h         |    4 +-
 njs/test/njs_unit_test.c |   35 +++++++++++++++
 4 files changed, 136 insertions(+), 12 deletions(-)

diffs (309 lines):

diff -r f4a15ccf03c9 -r 5ef3dbe30d2d njs/njs_json.c
--- a/njs/njs_json.c	Tue Mar 26 23:06:46 2019 +0300
+++ b/njs/njs_json.c	Tue Mar 26 08:04:02 2019 +0300
@@ -1099,7 +1099,7 @@ njs_json_push_parse_state(njs_vm_t *vm, 
         } else {
             state->type = NJS_JSON_OBJECT_START;
             state->prop_value = NULL;
-            state->keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS);
+            state->keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS, 0);
             if (state->keys == NULL) {
                 return NULL;
             }
@@ -1677,7 +1677,7 @@ njs_json_push_stringify_state(njs_vm_t *
                 state->keys = njs_extern_keys_array(vm, value->external.proto);
 
             } else {
-                state->keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS);
+                state->keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS, 0);
             }
 
             if (state->keys == NULL) {
diff -r f4a15ccf03c9 -r 5ef3dbe30d2d njs/njs_object.c
--- a/njs/njs_object.c	Tue Mar 26 23:06:46 2019 +0300
+++ b/njs/njs_object.c	Tue Mar 26 08:04:02 2019 +0300
@@ -417,7 +417,7 @@ njs_object_property_query(njs_vm_t *vm, 
     do {
         pq->prototype = proto;
 
-        /* length and other shared properties should be Own property */
+        /* TODO: length should be Own property */
 
         if (nxt_fast_path(!pq->own || proto == object)) {
             ret = nxt_lvlhsh_find(&proto->hash, &pq->lhq);
@@ -879,7 +879,7 @@ njs_object_keys(njs_vm_t *vm, njs_value_
         return NXT_ERROR;
     }
 
-    keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS);
+    keys = njs_object_enumerate(vm, value, NJS_ENUM_KEYS, 0);
     if (keys == NULL) {
         return NXT_ERROR;
     }
@@ -908,7 +908,7 @@ njs_object_values(njs_vm_t *vm, njs_valu
         return NXT_ERROR;
     }
 
-    array = njs_object_enumerate(vm, value, NJS_ENUM_VALUES);
+    array = njs_object_enumerate(vm, value, NJS_ENUM_VALUES, 0);
     if (array == NULL) {
         return NXT_ERROR;
     }
@@ -937,7 +937,7 @@ njs_object_entries(njs_vm_t *vm, njs_val
         return NXT_ERROR;
     }
 
-    array = njs_object_enumerate(vm, value, NJS_ENUM_BOTH);
+    array = njs_object_enumerate(vm, value, NJS_ENUM_BOTH, 0);
     if (array == NULL) {
         return NXT_ERROR;
     }
@@ -952,8 +952,9 @@ njs_object_entries(njs_vm_t *vm, njs_val
 
 njs_array_t *
 njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value,
-    njs_object_enum_t kind)
+    njs_object_enum_t kind, nxt_bool_t all)
 {
+    nxt_bool_t         exotic_length;
     u_char             *dst;
     uint32_t           i, length, size, items_length, properties;
     njs_value_t        *string, *item;
@@ -964,6 +965,12 @@ njs_object_enumerate(njs_vm_t *vm, const
     njs_string_prop_t  string_prop;
     nxt_lvlhsh_each_t  lhe;
 
+    static const njs_value_t  njs_string_length = njs_string("length");
+
+    /* TODO: "length" is in a shared_hash. */
+
+    exotic_length = 0;
+
     array = NULL;
     length = 0;
     items_length = 0;
@@ -979,6 +986,8 @@ njs_object_enumerate(njs_vm_t *vm, const
             }
         }
 
+        exotic_length = all;
+
         break;
 
     case NJS_STRING:
@@ -992,8 +1001,15 @@ njs_object_enumerate(njs_vm_t *vm, const
 
         length = njs_string_prop(&string_prop, string);
         items_length += length;
+        exotic_length = all;
+
         break;
 
+    case NJS_FUNCTION:
+        exotic_length = all && (value->data.u.function->native == 0);
+
+        /* Fall through. */
+
     default:
         break;
     }
@@ -1013,7 +1029,22 @@ njs_object_enumerate(njs_vm_t *vm, const
                 break;
             }
 
-            if (prop->type != NJS_WHITEOUT && prop->enumerable) {
+            if (prop->type != NJS_WHITEOUT && (prop->enumerable || all)) {
+                properties++;
+            }
+        }
+
+        if (nxt_slow_path(all)) {
+            nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
+            hash = &value->data.u.object->shared_hash;
+
+            for ( ;; ) {
+                prop = nxt_lvlhsh_each(hash, &lhe);
+
+                if (prop == NULL) {
+                    break;
+                }
+
                 properties++;
             }
         }
@@ -1021,7 +1052,7 @@ njs_object_enumerate(njs_vm_t *vm, const
         items_length += properties;
     }
 
-    items = njs_array_alloc(vm, items_length, NJS_ARRAY_SPARE);
+    items = njs_array_alloc(vm, items_length + exotic_length, NJS_ARRAY_SPARE);
     if (nxt_slow_path(items == NULL)) {
         return NULL;
     }
@@ -1179,12 +1210,17 @@ njs_object_enumerate(njs_vm_t *vm, const
         }
     }
 
+    if (nxt_slow_path(exotic_length != 0)) {
+        *item++ = njs_string_length;
+    }
+
     if (nxt_fast_path(properties != 0)) {
         nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
 
         switch (kind) {
 
         case NJS_ENUM_KEYS:
+            hash = &value->data.u.object->hash;
             for ( ;; ) {
                 prop = nxt_lvlhsh_each(hash, &lhe);
 
@@ -1192,7 +1228,22 @@ njs_object_enumerate(njs_vm_t *vm, const
                     break;
                 }
 
-                if (prop->type != NJS_WHITEOUT && prop->enumerable) {
+                if (prop->type != NJS_WHITEOUT && (prop->enumerable || all)) {
+                    njs_string_copy(item++, &prop->name);
+                }
+            }
+
+            if (nxt_slow_path(all)) {
+                nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
+                hash = &value->data.u.object->shared_hash;
+
+                for ( ;; ) {
+                    prop = nxt_lvlhsh_each(hash, &lhe);
+
+                    if (prop == NULL) {
+                        break;
+                    }
+
                     njs_string_copy(item++, &prop->name);
                 }
             }
@@ -1200,6 +1251,7 @@ njs_object_enumerate(njs_vm_t *vm, const
             break;
 
         case NJS_ENUM_VALUES:
+            hash = &value->data.u.object->hash;
             for ( ;; ) {
                 prop = nxt_lvlhsh_each(hash, &lhe);
 
@@ -1721,6 +1773,35 @@ njs_object_get_own_property_descriptor(n
 
 
 static njs_ret_t
+njs_object_get_own_property_names(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t unused)
+{
+    njs_array_t        *names;
+    const njs_value_t  *value;
+
+    value = njs_arg(args, nargs, 1);
+
+    if (njs_is_null_or_undefined(value)) {
+        njs_type_error(vm, "cannot convert %s argument to object",
+                       njs_type_string(value->type));
+
+        return NXT_ERROR;
+    }
+
+    names = njs_object_enumerate(vm, value, NJS_ENUM_KEYS, 1);
+    if (names == NULL) {
+        return NXT_ERROR;
+    }
+
+    vm->retval.data.u.array = names;
+    vm->retval.type = NJS_ARRAY;
+    vm->retval.data.truth = 1;
+
+    return NXT_OK;
+}
+
+
+static njs_ret_t
 njs_object_get_prototype_of(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
 {
@@ -2152,6 +2233,14 @@ static const njs_object_prop_t  njs_obje
                                      NJS_STRING_ARG),
     },
 
+    /* Object.getOwnPropertyNames(). */
+    {
+        .type = NJS_METHOD,
+        .name = njs_long_string("getOwnPropertyNames"),
+        .value = njs_native_function(njs_object_get_own_property_names, 0,
+                                     NJS_SKIP_ARG, NJS_OBJECT_ARG),
+    },
+
     /* Object.getPrototypeOf(). */
     {
         .type = NJS_METHOD,
diff -r f4a15ccf03c9 -r 5ef3dbe30d2d njs/njs_object.h
--- a/njs/njs_object.h	Tue Mar 26 23:06:46 2019 +0300
+++ b/njs/njs_object.h	Tue Mar 26 08:04:02 2019 +0300
@@ -18,7 +18,7 @@ typedef enum {
 
 
 typedef enum {
-    NJS_ENUM_KEYS = 0,
+    NJS_ENUM_KEYS,
     NJS_ENUM_VALUES,
     NJS_ENUM_BOTH,
 } njs_object_enum_t;
@@ -87,7 +87,7 @@ njs_object_t *njs_object_value_copy(njs_
 njs_object_t *njs_object_value_alloc(njs_vm_t *vm, const njs_value_t *value,
     nxt_uint_t type);
 njs_array_t *njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value,
-    njs_object_enum_t kind);
+    njs_object_enum_t kind, nxt_bool_t all);
 njs_ret_t njs_value_property(njs_vm_t *vm, njs_value_t *value,
     const njs_value_t *property, njs_value_t *retval);
 njs_object_prop_t *njs_object_property(njs_vm_t *vm, const njs_object_t *obj,
diff -r f4a15ccf03c9 -r 5ef3dbe30d2d njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Tue Mar 26 23:06:46 2019 +0300
+++ b/njs/test/njs_unit_test.c	Tue Mar 26 08:04:02 2019 +0300
@@ -8673,6 +8673,41 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("var o = {}; o[void 0] = 'a'; Object.getOwnPropertyDescriptor(o, undefined).value"),
       nxt_string("a") },
 
+    { nxt_string("Object.getOwnPropertyNames()"),
+      nxt_string("TypeError: cannot convert undefined argument to object") },
+
+    { nxt_string("Array.isArray(Object.getOwnPropertyNames({}))"),
+      nxt_string("true") },
+
+    { nxt_string("Object.getOwnPropertyNames({a:1, b:1, c:1})"),
+      nxt_string("a,b,c") },
+
+    { nxt_string("Object.getOwnPropertyNames(Object.defineProperty({a:1}, 'b', {}))"),
+      nxt_string("a,b") },
+
+    { nxt_string("Object.getOwnPropertyNames(Object.defineProperty([], 'b', {}))"),
+      nxt_string("length,b") },
+
+    { nxt_string("Object.getOwnPropertyNames(Object.defineProperty(new String(), 'b', {}))"),
+      nxt_string("length,b") },
+
+    { nxt_string("Object.getOwnPropertyNames([1,2,3])"),
+      nxt_string("0,1,2,length") },
+
+    { nxt_string("Object.getOwnPropertyNames('abc')"),
+      nxt_string("0,1,2,length") },
+
+    { nxt_string("Object.getOwnPropertyNames(function() {})"),
+      nxt_string("length,prototype") },
+
+    { nxt_string("Object.getOwnPropertyNames(Array)"),
+      nxt_string("name,length,prototype,isArray,of") },
+
+#if 0
+    { nxt_string("Object.getOwnPropertyNames(Array.isArray)"),
+      nxt_string("length") },
+#endif
+
     { nxt_string("Object.defineProperty(Object.freeze({}), 'b', {})"),
       nxt_string("TypeError: object is not extensible") },
 


More information about the nginx-devel mailing list