details: https://hg.nginx.org/njs/rev/5ef3dbe30d2d branches: changeset: 849:5ef3dbe30d2d user: Artem S. Povalyukhin <artem.povalu...@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") }, _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel