[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