]> git.kaiwu.me - njs.git/commitdiff
Object.entries() method.
authorValentin Bartenev <vbart@nginx.com>
Mon, 3 Dec 2018 16:23:27 +0000 (19:23 +0300)
committerValentin Bartenev <vbart@nginx.com>
Mon, 3 Dec 2018 16:23:27 +0000 (19:23 +0300)
njs/njs_object.c
njs/njs_object.h
njs/test/njs_unit_test.c

index 6248bbeebe465aef1590f3a3bf6d44ee72586f1e..c6414d2031af84a590f0bb672818b63a0d89e937 100644 (file)
@@ -914,6 +914,35 @@ njs_object_values(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
 }
 
 
+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 njs_value_t *value,
     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;
@@ -1012,6 +1041,29 @@ njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value,
                 }
             }
 
+            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;
         }
 
@@ -1056,6 +1108,66 @@ njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value,
                 } while (src != end);
             }
 
+            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;
         }
     }
@@ -1094,6 +1206,35 @@ njs_object_enumerate(njs_vm_t *vm, const njs_value_t *value,
                 }
             }
 
+            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_object_constructor_properties[] =
                                      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,
index ab7b1380437f2e1fa4c769398ca3e677f6776545..6c1c523956c92bcd1880cf28a4b10ae567de2302 100644 (file)
@@ -20,6 +20,7 @@ typedef enum {
 typedef enum {
     NJS_ENUM_KEYS = 0,
     NJS_ENUM_VALUES,
+    NJS_ENUM_BOTH,
 } njs_object_enum_t;
 
 
index e05489164c9c54dd566c02117d4f483207491082..3f84c3b549ad552d671088f6c404f74e29a8a302 100644 (file)
@@ -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") },