]> git.kaiwu.me - njs.git/commitdiff
Object.defineProperty() method.
authorDmitry Volyntsev <xeioex@nginx.com>
Wed, 7 Jun 2017 14:57:40 +0000 (17:57 +0300)
committerDmitry Volyntsev <xeioex@nginx.com>
Wed, 7 Jun 2017 14:57:40 +0000 (17:57 +0300)
njs/njs_object.c
njs/njs_object_hash.h
njs/njs_vm.c
njs/test/njs_unit_test.c

index 265bf88b07bf3d8697b7b96393b0aecbcf4cd617..d2f1c3823eee65977f6fe6c3eab1fec698e58c63 100644 (file)
@@ -412,6 +412,109 @@ njs_object_keys(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
 }
 
 
+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;
+    nxt_str_t           key;
+    njs_value_t         *name;
+    njs_object_t        *object, *descriptor;
+    njs_object_prop_t   *prop, *pr;
+    nxt_lvlhsh_query_t  lhq, pq;
+
+    if (nargs < 4 || !njs_is_object(&args[1]) || !njs_is_object(&args[3])) {
+        vm->exception = &njs_exception_type_error;
+        return NXT_ERROR;
+    }
+
+    object = args[1].data.u.object;
+    name = &args[2];
+    descriptor = args[3].data.u.object;
+
+    if (name->short_string.size != NJS_STRING_LONG) {
+        key.start = name->short_string.start;
+        key.length = name->short_string.length;
+
+    } else {
+        key.start = name->data.u.string->start;
+        key.length = name->data.string_size;
+    }
+
+    lhq.key = key;
+    lhq.key_hash = nxt_djb_hash(key.start, 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, name);
+
+        if (nxt_slow_path(prop == NULL)) {
+            return NXT_ERROR;
+        }
+
+        prop->configurable = 0;
+        prop->enumerable = 0;
+        prop->writable = 0;
+
+        lhq.value = prop;
+
+    } else {
+        prop = lhq.value;
+    }
+
+    pq.key = nxt_string_value("value");
+    pq.key_hash = NJS_VALUE_HASH;
+    pq.proto = &njs_object_hash_proto;
+
+    pr = njs_object_property(vm, descriptor, &pq);
+
+    if (pr != NULL) {
+        prop->value = pr->value;
+    }
+
+    pq.key = nxt_string_value("configurable");
+    pq.key_hash = NJS_CONFIGURABLE_HASH;
+
+    pr = njs_object_property(vm, descriptor, &pq);
+
+    if (pr != NULL) {
+        prop->configurable = pr->value.data.truth;
+    }
+
+    pq.key = nxt_string_value("enumerable");
+    pq.key_hash = NJS_ENUMERABLE_HASH;
+
+    pr = njs_object_property(vm, descriptor, &pq);
+
+    if (pr != NULL) {
+        prop->enumerable = pr->value.data.truth;
+    }
+
+    pq.key = nxt_string_value("writable");
+    pq.key_hash = NJS_WRITABABLE_HASH;
+
+    pr = njs_object_property(vm, descriptor, &pq);
+
+    if (pr != NULL) {
+        prop->writable = pr->value.data.truth;
+    }
+
+    lhq.replace = 0;
+    lhq.pool = vm->mem_cache_pool;
+
+    ret = nxt_lvlhsh_insert(&object->hash, &lhq);
+    if (nxt_slow_path(ret != NXT_OK)) {
+        return NXT_ERROR;
+    }
+
+    vm->retval = args[1];
+
+    return NXT_OK;
+}
+
+
 /*
  * The __proto__ property of booleans, numbers and strings primitives,
  * of objects created by Boolean(), Number(), and String() constructors,
@@ -558,6 +661,15 @@ static const njs_object_prop_t  njs_object_constructor_properties[] =
         .value = njs_native_function(njs_object_keys, 0,
                                      NJS_SKIP_ARG, NJS_OBJECT_ARG),
     },
+
+    /* Object.defineProperty(). */
+    {
+        .type = NJS_METHOD,
+        .name = njs_string("defineProperty"),
+        .value = njs_native_function(njs_object_define_property, 0,
+                                     NJS_SKIP_ARG, NJS_OBJECT_ARG,
+                                     NJS_STRING_ARG, NJS_OBJECT_ARG),
+    },
 };
 
 
index 0f25e1d8cbe4ae0d06b5880a0f7098249f03cd6d..3a9edd01491a18b2f5fdc26eaefb7e0b8ffd0f90 100644 (file)
@@ -8,6 +8,22 @@
 #define _NJS_OBJECT_HASH_H_INCLUDED_
 
 
+#define NJS_CONFIGURABLE_HASH                                                 \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(NXT_DJB_HASH_INIT,                                       \
+        'c'), 'o'), 'n'), 'f'), 'i'), 'g'), 'u'), 'r'), 'a'), 'b'), 'l'), 'e')
+
+
 #define NJS_CONSTRUCTOR_HASH                                                  \
     nxt_djb_hash_add(                                                         \
     nxt_djb_hash_add(                                                         \
         'c'), 'o'), 'n'), 's'), 't'), 'r'), 'u'), 'c'), 't'), 'o'), 'r')
 
 
+#define NJS_ENUMERABLE_HASH                                                   \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(NXT_DJB_HASH_INIT,                                       \
+        'e'), 'n'), 'u'), 'm'), 'e'), 'r'), 'a'), 'b'), 'l'), 'e')
+
+
 #define NJS_INDEX_HASH                                                        \
     nxt_djb_hash_add(                                                         \
     nxt_djb_hash_add(                                                         \
         't'), 'o'), 'S'), 't'), 'r'), 'i'), 'n'), 'g')
 
 
+#define NJS_VALUE_HASH                                                        \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(NXT_DJB_HASH_INIT,                                       \
+        'v'), 'a'), 'l'), 'u'), 'e')
+
+
 #define NJS_VALUE_OF_HASH                                                     \
     nxt_djb_hash_add(                                                         \
     nxt_djb_hash_add(                                                         \
         't'), 'o'), 'I'), 'S'), 'O'), 'S'), 't'), 'r'), 'i'), 'n'), 'g')
 
 
+#define NJS_WRITABABLE_HASH                                                   \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(                                                         \
+    nxt_djb_hash_add(NXT_DJB_HASH_INIT,                                       \
+        'w'), 'r'), 'i'), 't'), 'a'), 'b'), 'l'), 'e')
+
+
 #endif /* _NJS_OBJECT_HASH_H_INCLUDED_ */
index 4d4746cd1cc3b488b9914805c6bc9ccd48d1f521..5b3dcd5aa8ad13bcccac9cb5f79aa5ae3d948ec8 100644 (file)
@@ -746,7 +746,9 @@ njs_vmcode_property_set(njs_vm_t *vm, njs_value_t *object,
         return ret;
     }
 
-    prop->value = *value;
+    if (prop->writable) {
+        prop->value = *value;
+    }
 
     return sizeof(njs_vmcode_prop_set_t);
 }
index cd8288c65ac1c33289017522d2095a945322d14d..97a82a9ca49c8651060db069e8e37e684f084e7e 100644 (file)
@@ -5874,6 +5874,64 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("Object.keys(1)"),
       nxt_string("TypeError") },
 
+    { nxt_string("var o = {}; Object.defineProperty(o, 'a', {}); o.a"),
+      nxt_string("undefined") },
+
+    { nxt_string("Object.defineProperty({}, 'a', {value:1})"),
+      nxt_string("[object Object]") },
+
+    { nxt_string("var o = {}; Object.defineProperty(o, 'a', {value:1}); o.a"),
+      nxt_string("1") },
+
+    { nxt_string("var o = {a:1, c:2}; Object.defineProperty(o, 'b', {});"
+                 "Object.keys(o)"),
+      nxt_string("a,c") },
+
+    { nxt_string("var o = {a:1, c:2};"
+                 "Object.defineProperty(o, 'b', {enumerable:false});"
+                 "Object.keys(o)"),
+      nxt_string("a,c") },
+
+    { nxt_string("var o = {a:1, c:3};"
+                 "Object.defineProperty(o, 'b', {enumerable:true});"
+                 "Object.keys(o)"),
+      nxt_string("a,c,b") },
+
+    { nxt_string("var o = {}; Object.defineProperty(o, 'a', {}); o.a = 1; o.a"),
+      nxt_string("undefined") },
+
+    { nxt_string("var o = {}; Object.defineProperty(o, 'a', {writable:false});"
+                 "o.a = 1; o.a"),
+      nxt_string("undefined") },
+
+    { nxt_string("var o = {}; Object.defineProperty(o, 'a', {writable:true});"
+                 "o.a = 1; o.a"),
+      nxt_string("1") },
+
+    { nxt_string("var o = {};"
+                 "Object.defineProperty(o, 'a', {value:1}); delete o.a; o.a"),
+      nxt_string("1") },
+
+    { nxt_string("var o = {};"
+                 "Object.defineProperty(o, 'a', {value:1, configurable:true});"
+                 "delete o.a; o.a"),
+      nxt_string("undefined") },
+
+    { nxt_string("var o = {};"
+                 "Object.defineProperty(o, 'a', {value:1, configurable:false});"
+                 "delete o.a; o.a"),
+      nxt_string("1") },
+
+    { nxt_string("var o = {};"
+                 "Object.defineProperty(o, 'a', Object.create({value:2})); o.a"),
+      nxt_string("2") },
+
+    { nxt_string("var o = {}; Object.defineProperty()"),
+      nxt_string("TypeError") },
+
+    { nxt_string("var o = {}; Object.defineProperty(o)"),
+      nxt_string("TypeError") },
+
     { nxt_string("var d = new Date(''); d +' '+ d.getTime()"),
       nxt_string("Invalid Date NaN") },