diff --git a/napi-inl.h b/napi-inl.h index b55ec4803..9ef47c883 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -757,6 +757,28 @@ inline void Object::Set(const std::string& utf8name, double numberValue) { Set(utf8name.c_str(), Number::New(Env(), numberValue)); } +inline bool Object::Delete(napi_value key) { + bool result; + napi_status status = napi_delete_property(_env, _value, key, &result); + NAPI_THROW_IF_FAILED(_env, status, false); + return result; +} + +inline bool Object::Delete(Value key) { + bool result; + napi_status status = napi_delete_property(_env, _value, key, &result); + NAPI_THROW_IF_FAILED(_env, status, false); + return result; +} + +inline bool Object::Delete(const char* utf8name) { + return Delete(String::New(_env, utf8name)); +} + +inline bool Object::Delete(const std::string& utf8name) { + return Delete(String::New(_env, utf8name)); +} + inline bool Object::Has(uint32_t index) const { bool result; napi_status status = napi_has_element(_env, _value, index, &result); @@ -797,6 +819,13 @@ inline void Object::Set(uint32_t index, double numberValue) { Set(index, static_cast(Number::New(Env(), numberValue))); } +inline bool Object::Delete(uint32_t index) { + bool result; + napi_status status = napi_delete_element(_env, _value, index, &result); + NAPI_THROW_IF_FAILED(_env, status, false); + return result; +} + inline Array Object::GetPropertyNames() { napi_value result; napi_status status = napi_get_property_names(_env, _value, &result); @@ -1657,7 +1686,7 @@ inline Reference& Reference::operator =(Reference&& other) { } template -inline Reference::Reference(const Reference& other) +inline Reference::Reference(const Reference& other) : _env(other._env), _ref(nullptr), _suppressDestruct(false) { HandleScope scope(_env); diff --git a/napi.h b/napi.h index 7ffd1b137..96d2e7af7 100644 --- a/napi.h +++ b/napi.h @@ -491,6 +491,26 @@ namespace Napi { double numberValue ///< Property value ); + /// Delete property. + bool Delete( + napi_value key ///< Property key primitive + ); + + /// Delete property. + bool Delete( + Value key ///< Property key + ); + + /// Delete property. + bool Delete( + const char* utf8name ///< UTF-8 encoded null-terminated property name + ); + + /// Delete property. + bool Delete( + const std::string& utf8name ///< UTF-8 encoded property name + ); + /// Checks whether an indexed property is present. bool Has( uint32_t index ///< Property / element index @@ -537,6 +557,11 @@ namespace Napi { double numberValue ///< Property value ); + /// Deletes an indexed property or array element. + bool Delete( + uint32_t index ///< Property / element index + ); + Array GetPropertyNames(); ///< Get all property names /// Defines a property on the object. diff --git a/test/object.cc b/test/object.cc index 361830117..f4d8218e4 100644 --- a/test/object.cc +++ b/test/object.cc @@ -102,6 +102,12 @@ void SetProperty(const CallbackInfo& info) { obj.Set(name, value); } +Value DeleteProperty(const CallbackInfo& info) { + Object obj = info[0].As(); + Name name = info[1].As(); + return Boolean::New(info.Env(), obj.Delete(name)); +} + Object InitObject(Env env) { Object exports = Object::New(env); @@ -110,6 +116,7 @@ Object InitObject(Env env) { exports["defineValueProperty"] = Function::New(env, DefineValueProperty); exports["getProperty"] = Function::New(env, GetProperty); exports["setProperty"] = Function::New(env, SetProperty); + exports["deleteProperty"] = Function::New(env, DeleteProperty); return exports; } diff --git a/test/object.js b/test/object.js index 7728b1a4b..639d10ca4 100644 --- a/test/object.js +++ b/test/object.js @@ -82,6 +82,18 @@ function test(binding) { assert.strictEqual(obj.test, 1); } + { + const obj = { one: 1, two: 2 }; + Object.defineProperty(obj, "three", {configurable: false, value: 3}); + assert.strictEqual(binding.object.deleteProperty(obj, 'one'), true); + assert.strictEqual(binding.object.deleteProperty(obj, 'missing'), true); + + /* Returns true for all cases except when the property is an own non- + configurable property, in which case, false is returned in non-strict mode. */ + assert.strictEqual(binding.object.deleteProperty(obj, 'three'), false); + assert.deepStrictEqual(obj, { two: 2 }); + } + { const obj = {'one': 1, 'two': 2, 'three': 3}; var arr = binding.object.GetPropertyNames(obj); @@ -94,4 +106,7 @@ function test(binding) { assert.throws(() => { binding.object.setProperty(undefined, 'test', 1); }, /object was expected/); + assert.throws(() => { + binding.object.deleteProperty(undefined, 'test'); + }, /object was expected/); }