From fda75e79a7eb54debedc0f4fd15a74f9158622ab Mon Sep 17 00:00:00 2001 From: Dmitry Volyntsev Date: Fri, 9 Jun 2017 20:28:15 +0300 Subject: [PATCH] Object.defineProperties() method. --- njs/njs_object.c | 85 +++++++++++++++++++++++++++++++++++----- njs/test/njs_unit_test.c | 21 ++++++++++ nxt/nxt_lvlhsh.h | 6 +++ 3 files changed, 103 insertions(+), 9 deletions(-) diff --git a/njs/njs_object.c b/njs/njs_object.c index d81f75cc..844ad2a3 100644 --- a/njs/njs_object.c +++ b/njs/njs_object.c @@ -26,6 +26,8 @@ static nxt_int_t njs_object_hash_test(nxt_lvlhsh_query_t *lhq, void *data); +static njs_ret_t njs_define_property(njs_vm_t *vm, njs_object_t *object, + njs_value_t *name, njs_object_t *descriptor); nxt_noinline njs_object_t * @@ -416,27 +418,85 @@ static njs_ret_t njs_object_define_property(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - nxt_int_t ret; - njs_object_t *object, *descriptor; - njs_object_prop_t *prop, *pr; - nxt_lvlhsh_query_t lhq, pq; + nxt_int_t ret; if (nargs < 4 || !njs_is_object(&args[1]) || !njs_is_object(&args[3])) { vm->exception = &njs_exception_type_error; return NXT_ERROR; } + ret = njs_define_property(vm, args[1].data.u.object, &args[2], + args[3].data.u.object); + + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + + vm->retval = args[1]; + + return NXT_OK; +} + + +static njs_ret_t +njs_object_define_properties(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + nxt_int_t ret; + nxt_lvlhsh_t *hash; + njs_object_t *object; + nxt_lvlhsh_each_t lhe; + njs_object_prop_t *prop; + + if (nargs < 3 || !njs_is_object(&args[1]) || !njs_is_object(&args[2])) { + vm->exception = &njs_exception_type_error; + return NXT_ERROR; + } + + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + object = args[1].data.u.object; - descriptor = args[3].data.u.object; + hash = &args[2].data.u.object->hash; + + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); - njs_string_get(&args[2], &lhq.key); + if (prop == NULL) { + break; + } + + if (prop->enumerable && njs_is_object(&prop->value)) { + ret = njs_define_property(vm, object, &prop->name, + prop->value.data.u.object); + + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; + } + } + } + + vm->retval = args[1]; + + return NXT_OK; +} + + +static njs_ret_t +njs_define_property(njs_vm_t *vm, njs_object_t *object, njs_value_t *name, + njs_object_t *descriptor) +{ + nxt_int_t ret; + njs_object_prop_t *prop, *pr; + nxt_lvlhsh_query_t lhq, pq; + + njs_string_get(name, &lhq.key); lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); lhq.proto = &njs_object_hash_proto; ret = nxt_lvlhsh_find(&object->hash, &lhq); if (ret != NXT_OK) { - prop = njs_object_prop_alloc(vm, &args[2]); + prop = njs_object_prop_alloc(vm, name); if (nxt_slow_path(prop == NULL)) { return NXT_ERROR; @@ -497,8 +557,6 @@ njs_object_define_property(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, return NXT_ERROR; } - vm->retval = args[1]; - return NXT_OK; } @@ -673,6 +731,15 @@ static const njs_object_prop_t njs_object_constructor_properties[] = NJS_STRING_ARG, NJS_OBJECT_ARG), }, + /* Object.defineProperties(). */ + { + .type = NJS_METHOD, + .name = njs_long_string("defineProperties"), + .value = njs_native_function(njs_object_define_properties, 0, + NJS_SKIP_ARG, NJS_OBJECT_ARG, + NJS_OBJECT_ARG), + }, + /* Object.getPrototypeOf(). */ { .type = NJS_METHOD, diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 19473a82..0a0306e6 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -5932,6 +5932,27 @@ static njs_unit_test_t njs_test[] = { nxt_string("var o = {}; Object.defineProperty(o)"), nxt_string("TypeError") }, + { nxt_string("var o = Object.defineProperties({}, {a:{value:1}}); o.a"), + nxt_string("1") }, + + { nxt_string("var o = Object.defineProperties({}, {a:{enumerable:true}, b:{enumerable:true}});" + "Object.keys(o)"), + nxt_string("a,b") }, + + { nxt_string("var desc = Object.defineProperty({b:{value:1, enumerable:true}}, 'a', {});" + "var o = Object.defineProperties({}, desc);" + "Object.keys(o)"), + nxt_string("b") }, + + { nxt_string("var o = Object.defineProperties({a:1}, {}); o.a"), + nxt_string("1") }, + + { nxt_string("Object.defineProperties(1, {})"), + nxt_string("TypeError") }, + + { nxt_string("Object.defineProperties({}, 1)"), + nxt_string("TypeError") }, + { nxt_string("var o = {a:1}; o.hasOwnProperty('a')"), nxt_string("true") }, diff --git a/nxt/nxt_lvlhsh.h b/nxt/nxt_lvlhsh.h index 7b289833..b969928e 100644 --- a/nxt/nxt_lvlhsh.h +++ b/nxt/nxt_lvlhsh.h @@ -173,6 +173,12 @@ typedef struct { } nxt_lvlhsh_each_t; +#define nxt_lvlhsh_each_init(lhe, _proto) \ + do { \ + memset(lhe, 0, sizeof(nxt_lvlhsh_each_t)); \ + (lhe)->proto = _proto; \ + } while (0) + NXT_EXPORT void *nxt_lvlhsh_each(nxt_lvlhsh_t *lh, nxt_lvlhsh_each_t *le); -- 2.47.3