[njs] Object.entries() method.

Valentin Bartenev vbart at nginx.com
Mon Dec 3 19:07:22 UTC 2018


details:   https://hg.nginx.org/njs/rev/ce3a943df9c4
branches:  
changeset: 683:ce3a943df9c4
user:      Valentin Bartenev <vbart at nginx.com>
date:      Mon Dec 03 19:23:27 2018 +0300
description:
Object.entries() method.

diffstat:

 njs/njs_object.c         |  151 ++++++++++++++++++++++++++++++++++++++++++++++-
 njs/njs_object.h         |    1 +
 njs/test/njs_unit_test.c |   37 +++++++++++
 3 files changed, 188 insertions(+), 1 deletions(-)

diffs (261 lines):

diff -r 1af8f40573f2 -r ce3a943df9c4 njs/njs_object.c
--- a/njs/njs_object.c	Mon Dec 03 19:20:58 2018 +0300
+++ b/njs/njs_object.c	Mon Dec 03 19:23:27 2018 +0300
@@ -914,6 +914,35 @@ njs_object_values(njs_vm_t *vm, njs_valu
 }
 
 
+static njs_ret_t
+njs_object_entries(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
+    njs_index_t unused)
+ {
+    njs_array_t        *array;
+    const njs_value_t  *value;
+
+    value = njs_arg(args, nargs, 1);
+
+    if (njs_is_null_or_void(value)) {
+        njs_type_error(vm, "cannot convert %s argument to object",
+                       njs_type_string(value->type));
+
+        return NXT_ERROR;
+    }
+
+    array = njs_object_enumerate(vm, value, NJS_ENUM_BOTH);
+    if (array == NULL) {
+        return NXT_ERROR;
+    }
+
+    vm->retval.data.u.array = array;
+    vm->retval.type = NJS_ARRAY;
+    vm->retval.data.truth = 1;
+
+    return NXT_OK;
+}
+
+
 njs_array_t *
 njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value,
     njs_object_enum_t kind)
@@ -921,7 +950,7 @@ njs_object_enumerate(njs_vm_t *vm, const
     u_char             *dst;
     uint32_t           i, length, size, items_length, properties;
     njs_value_t        *string, *item;
-    njs_array_t        *items, *array;
+    njs_array_t        *items, *array, *entry;
     nxt_lvlhsh_t       *hash;
     const u_char       *src, *end;
     njs_object_prop_t  *prop;
@@ -1013,6 +1042,29 @@ njs_object_enumerate(njs_vm_t *vm, const
             }
 
             break;
+
+        case NJS_ENUM_BOTH:
+            for (i = 0; i < length; i++) {
+                if (njs_is_valid(&array->start[i])) {
+                    entry = njs_array_alloc(vm, 2, 0);
+                    if (nxt_slow_path(entry == NULL)) {
+                        return NULL;
+                    }
+
+                    njs_uint32_to_string(&entry->start[0], i);
+
+                    /* GC: retain. */
+                    entry->start[1] = array->start[i];
+
+                    item->data.u.array = entry;
+                    item->type = NJS_ARRAY;
+                    item->data.truth = 1;
+
+                    item++;
+                }
+            }
+
+            break;
         }
 
     } else if (length != 0) {
@@ -1057,6 +1109,66 @@ njs_object_enumerate(njs_vm_t *vm, const
             }
 
             break;
+
+        case NJS_ENUM_BOTH:
+            if (string_prop.size == (size_t) length) {
+                /* Byte or ASCII string. */
+
+                for (i = 0; i < length; i++) {
+                    entry = njs_array_alloc(vm, 2, 0);
+                    if (nxt_slow_path(entry == NULL)) {
+                        return NULL;
+                    }
+
+                    njs_uint32_to_string(&entry->start[0], i);
+
+                    string = &entry->start[1];
+
+                    dst = njs_string_short_start(string);
+                    dst[0] = string_prop.start[i];
+
+                    njs_string_short_set(string, 1, 1);
+
+                    item->data.u.array = entry;
+                    item->type = NJS_ARRAY;
+                    item->data.truth = 1;
+
+                    item++;
+                }
+
+            } else {
+                /* UTF-8 string. */
+
+                src = string_prop.start;
+                end = src + string_prop.size;
+                i = 0;
+
+                do {
+                    entry = njs_array_alloc(vm, 2, 0);
+                    if (nxt_slow_path(entry == NULL)) {
+                        return NULL;
+                    }
+
+                    njs_uint32_to_string(&entry->start[0], i++);
+
+                    string = &entry->start[1];
+
+                    dst = njs_string_short_start(string);
+                    dst = nxt_utf8_copy(dst, &src, end);
+                    size = dst - njs_string_short_start(value);
+
+                    njs_string_short_set(string, size, 1);
+
+                    item->data.u.array = entry;
+                    item->type = NJS_ARRAY;
+                    item->data.truth = 1;
+
+                    item++;
+
+                } while (src != end);
+            }
+
+            break;
         }
     }
 
@@ -1095,6 +1207,35 @@ njs_object_enumerate(njs_vm_t *vm, const
             }
 
             break;
+
+        case NJS_ENUM_BOTH:
+            for ( ;; ) {
+                prop = nxt_lvlhsh_each(hash, &lhe);
+
+                if (prop == NULL) {
+                    break;
+                }
+
+                if (prop->type != NJS_WHITEOUT && prop->enumerable) {
+                    entry = njs_array_alloc(vm, 2, 0);
+                    if (nxt_slow_path(entry == NULL)) {
+                        return NULL;
+                    }
+
+                    njs_string_copy(&entry->start[0], &prop->name);
+
+                    /* GC: retain. */
+                    entry->start[1] = prop->value;
+
+                    item->data.u.array = entry;
+                    item->type = NJS_ARRAY;
+                    item->data.truth = 1;
+
+                    item++;
+                }
+            }
+
+            break;
         }
     }
 
@@ -1970,6 +2111,14 @@ static const njs_object_prop_t  njs_obje
                                      NJS_SKIP_ARG, NJS_OBJECT_ARG),
     },
 
+    /* ES8: Object.entries(). */
+    {
+        .type = NJS_METHOD,
+        .name = njs_string("entries"),
+        .value = njs_native_function(njs_object_entries, 0,
+                                     NJS_SKIP_ARG, NJS_OBJECT_ARG),
+    },
+
     /* Object.defineProperty(). */
     {
         .type = NJS_METHOD,
diff -r 1af8f40573f2 -r ce3a943df9c4 njs/njs_object.h
--- a/njs/njs_object.h	Mon Dec 03 19:20:58 2018 +0300
+++ b/njs/njs_object.h	Mon Dec 03 19:23:27 2018 +0300
@@ -20,6 +20,7 @@ typedef enum {
 typedef enum {
     NJS_ENUM_KEYS = 0,
     NJS_ENUM_VALUES,
+    NJS_ENUM_BOTH,
 } njs_object_enum_t;
 
 
diff -r 1af8f40573f2 -r ce3a943df9c4 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Mon Dec 03 19:20:58 2018 +0300
+++ b/njs/test/njs_unit_test.c	Mon Dec 03 19:23:27 2018 +0300
@@ -7445,6 +7445,29 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("Object.values()"),
       nxt_string("TypeError: cannot convert undefined argument to object") },
 
+    { nxt_string("Object.entries('abc')"),
+      nxt_string("0,a,1,b,2,c") },
+
+    { nxt_string("JSON.stringify(Object.entries('эюя'))"),
+      nxt_string("[[\"0\",\"э\"],[\"1\",\"ю\"],[\"2\",\"я\"]]") },
+
+    { nxt_string("var o = {a:\"а\", b:\"б\", c:\"ц\"};"
+                 "JSON.stringify(Object.entries(o))"),
+      nxt_string("[[\"a\",\"а\"],[\"b\",\"б\"],[\"c\",\"ц\"]]") },
+
+    { nxt_string("JSON.stringify(Object.entries([0]))"),
+      nxt_string("[[\"0\",0]]") },
+
+    { nxt_string("var s = new String('αβ'); s.two = null; s[3] = true;"
+                 "Object.entries(s)"),
+      nxt_string("0,α,1,β,two,,3,true") },
+
+    { nxt_string("Object.entries(true)"),
+      nxt_string("") },
+
+    { nxt_string("Object.entries()"),
+      nxt_string("TypeError: cannot convert undefined argument to object") },
+
     { nxt_string("var o = {}; Object.defineProperty(o, 'a', {}); o.a"),
       nxt_string("undefined") },
 
@@ -7482,6 +7505,20 @@ static njs_unit_test_t  njs_test[] =
                  "Object.values(o)"),
       nxt_string("1,3,2") },
 
+    { nxt_string("var o = {a:1, c:2}; Object.defineProperty(o, 'b', {});"
+                 "Object.entries(o)"),
+      nxt_string("a,1,c,2") },
+
+    { nxt_string("var o = {a:1, c:2};"
+                 "Object.defineProperty(o, 'b', {enumerable:false, value:3});"
+                 "Object.entries(o)"),
+      nxt_string("a,1,c,2") },
+
+    { nxt_string("var o = {a:1, c:3};"
+                 "Object.defineProperty(o, 'b', {enumerable:true, value:2});"
+                 "Object.entries(o)"),
+      nxt_string("a,1,c,3,b,2") },
+
     { nxt_string("var o = {}; Object.defineProperty(o, 'a', {}); o.a = 1"),
       nxt_string("TypeError: Cannot assign to read-only property 'a' of object") },
 


More information about the nginx-devel mailing list