[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