[njs] Fixed Object.defineProperties() according to the specification.
Dmitry Volyntsev
xeioex at nginx.com
Wed Nov 27 14:15:29 UTC 2019
details: https://hg.nginx.org/njs/rev/ba1499515923
branches:
changeset: 1265:ba1499515923
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Wed Nov 27 15:48:32 2019 +0300
description:
Fixed Object.defineProperties() according to the specification.
This closes #210 issue on Github.
diffstat:
src/njs_object.c | 65 ++++++++++++++++++++++++++++-------------------
src/njs_object_prop.c | 7 ++++-
src/test/njs_unit_test.c | 37 +++++++++++++++++++++++++-
3 files changed, 79 insertions(+), 30 deletions(-)
diffs (164 lines):
diff -r 4e0d11660ce1 -r ba1499515923 src/njs_object.c
--- a/src/njs_object.c Wed Nov 27 15:40:44 2019 +0300
+++ b/src/njs_object.c Wed Nov 27 15:48:32 2019 +0300
@@ -1262,44 +1262,55 @@ static njs_int_t
njs_object_define_properties(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
njs_index_t unused)
{
- njs_int_t ret;
- njs_value_t *value, *desc;
- njs_lvlhsh_t *hash;
- njs_lvlhsh_each_t lhe;
- njs_object_prop_t *prop;
+ uint32_t i, length;
+ njs_int_t ret;
+ njs_array_t *keys;
+ njs_value_t desc, *value, *descs;
+ njs_object_prop_t *prop;
+ njs_property_query_t pq;
if (!njs_is_object(njs_arg(args, nargs, 1))) {
njs_type_error(vm, "Object.defineProperties is called on non-object");
return NJS_ERROR;
}
- value = njs_argument(args, 1);
-
- desc = njs_arg(args, nargs, 2);
-
- if (!njs_is_object(desc)) {
- njs_type_error(vm, "descriptor is not an object");
+ descs = njs_arg(args, nargs, 2);
+ ret = njs_value_to_object(vm, descs);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+
+ keys = njs_value_own_enumerate(vm, descs, NJS_ENUM_KEYS,
+ NJS_ENUM_STRING | NJS_ENUM_SYMBOL, 0);
+ if (njs_slow_path(keys == NULL)) {
return NJS_ERROR;
}
- njs_lvlhsh_each_init(&lhe, &njs_object_hash_proto);
-
- hash = njs_object_hash(desc);
-
- for ( ;; ) {
- prop = njs_lvlhsh_each(hash, &lhe);
-
- if (prop == NULL) {
- break;
+ length = keys->length;
+ value = njs_argument(args, 1);
+ njs_property_query_init(&pq, NJS_PROPERTY_QUERY_GET, 0);
+
+ for (i = 0; i < length; i++) {
+ ret = njs_property_query(vm, &pq, descs, &keys->start[i]);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
}
- if (prop->enumerable && njs_is_object(&prop->value)) {
- ret = njs_object_prop_define(vm, value, &prop->name, &prop->value,
- NJS_OBJECT_PROP_DESCRIPTOR);
-
- if (njs_slow_path(ret != NJS_OK)) {
- return NJS_ERROR;
- }
+ prop = pq.lhq.value;
+
+ if (ret == NJS_DECLINED || !prop->enumerable) {
+ continue;
+ }
+
+ ret = njs_value_property(vm, descs, &keys->start[i], &desc);
+ if (njs_slow_path(ret == NJS_ERROR)) {
+ return ret;
+ }
+
+ ret = njs_object_prop_define(vm, value, &keys->start[i], &desc,
+ NJS_OBJECT_PROP_DESCRIPTOR);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return NJS_ERROR;
}
}
diff -r 4e0d11660ce1 -r ba1499515923 src/njs_object_prop.c
--- a/src/njs_object_prop.c Wed Nov 27 15:40:44 2019 +0300
+++ b/src/njs_object_prop.c Wed Nov 27 15:48:32 2019 +0300
@@ -311,7 +311,7 @@ njs_object_prop_define(njs_vm_t *vm, njs
if (njs_is_valid(&prop->value)
&& prev->type != NJS_PROPERTY_HANDLER
- && !njs_values_strict_equal(&prop->value, &prev->value))
+ && !njs_values_same(&prop->value, &prev->value))
{
goto exception;
}
@@ -464,6 +464,11 @@ njs_descriptor_prop(njs_vm_t *vm, njs_ob
static const njs_value_t get_string = njs_string("get");
+ if (!njs_is_object(desc)) {
+ njs_type_error(vm, "property descriptor must be an object");
+ return NJS_ERROR;
+ }
+
data = 0;
accessor = 0;
diff -r 4e0d11660ce1 -r ba1499515923 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Wed Nov 27 15:40:44 2019 +0300
+++ b/src/test/njs_unit_test.c Wed Nov 27 15:48:32 2019 +0300
@@ -11103,6 +11103,39 @@ static njs_unit_test_t njs_test[] =
"Object.keys(o)"),
njs_str("b") },
+ { njs_str("var o = Object.defineProperties({}, { get x() { return { value: 1 }; } });"
+ "Object.getOwnPropertyDescriptor(o, 'x').value"),
+ njs_str("1") },
+
+ { njs_str("Object.defineProperties({}, { get x() { return 1; } })"),
+ njs_str("TypeError: property descriptor must be an object") },
+
+ { njs_str("var obj = {}; var desc = {value:NaN}; Object.defineProperty(obj, 'foo', desc); "
+ "Object.defineProperties(obj, { foo: desc } ).foo"),
+ njs_str("NaN") },
+
+ { njs_str("var obj = {}; var desc = {value:-0}; Object.defineProperty(obj, 'foo', desc); "
+ "Object.defineProperties(obj, { foo: desc } ).foo"),
+ njs_str("-0") },
+
+ { njs_str("var obj = {}; var desc = {value:-0}; Object.defineProperty(obj, 'foo', {value:0}); "
+ "Object.defineProperties(obj, { foo: desc } ).foo"),
+ njs_str("TypeError: Cannot redefine property: \"foo\"") },
+
+ { njs_str("var obj = {}; var desc = {value:0}; Object.defineProperty(obj, 'foo', {value:-0}); "
+ "Object.defineProperties(obj, { foo: desc } ).foo"),
+ njs_str("TypeError: Cannot redefine property: \"foo\"") },
+
+ { njs_str("var descs = {a:{value:1}}; Object.defineProperty(descs, 'b', {value:{value:2}});"
+ "var o = Object.defineProperties({}, descs);"
+ "njs.dump([o.a, o.b])"),
+ njs_str("[1,undefined]") },
+
+ { njs_str("var descs = {a:{value:1}}; Object.defineProperty(descs, 'b', {value:{value:2}, enumerable:true});"
+ "var o = Object.defineProperties({}, descs);"
+ "njs.dump([o.a, o.b])"),
+ njs_str("[1,2]") },
+
{ njs_str("var o = {a:1}; delete o.a;"
"Object.defineProperty(o, 'a', { value: 1 }); o.a"),
njs_str("1") },
@@ -11192,8 +11225,8 @@ static njs_unit_test_t njs_test[] =
{ njs_str("Object.defineProperties(1, {})"),
njs_str("TypeError: Object.defineProperties is called on non-object") },
- { njs_str("Object.defineProperties({}, 1)"),
- njs_str("TypeError: descriptor is not an object") },
+ { njs_str("njs.dump(Object.defineProperties({}, 1))"),
+ njs_str("{}") },
{ njs_str("Object.defineProperties(Object.freeze({b:1}), {b:{value:1}}).b"),
njs_str("1") },
More information about the nginx-devel
mailing list