[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