Skip to content

Commit

Permalink
n-api: add napi_delete_property()
Browse files Browse the repository at this point in the history
Fixes: #13924
Backport-PR-URL: #19447
PR-URL: #13934
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Jason Ginchereau <jasongin@microsoft.com>
  • Loading branch information
cjihrig authored and MylesBorins committed Apr 16, 2018
1 parent cadec3b commit 80cf25a
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 0 deletions.
23 changes: 23 additions & 0 deletions doc/api/n-api.md
Expand Up @@ -2276,6 +2276,28 @@ Returns `napi_ok` if the API succeeded.
This API checks if the Object passed in has the named property.


#### *napi_delete_property*
<!-- YAML
added: REPLACEME
-->
```C
napi_status napi_delete_property(napi_env env,
napi_value object,
napi_value key,
bool* result);
```
- `[in] env`: The environment that the N-API call is invoked under.
- `[in] object`: The object to query.
- `[in] key`: The name of the property to delete.
- `[out] result`: Whether the property deletion succeeded or not. `result` can
optionally be ignored by passing `NULL`.
Returns `napi_ok` if the API succeeded.
This API attempts to delete the `key` own property from `object`.
#### *napi_set_named_property*
<!-- YAML
added: v8.0.0
Expand Down Expand Up @@ -3074,6 +3096,7 @@ support it:
[`napi_delete_async_work`]: #n_api_napi_delete_async_work
[`napi_define_class`]: #n_api_napi_define_class
[`napi_delete_element`]: #n_api_napi_delete_element
[`napi_delete_property`]: #n_api_napi_delete_property
[`napi_delete_reference`]: #n_api_napi_delete_reference
[`napi_escape_handle`]: #n_api_napi_escape_handle
[`napi_get_array_length`]: #n_api_napi_get_array_length
Expand Down
22 changes: 22 additions & 0 deletions src/node_api.cc
Expand Up @@ -1005,6 +1005,28 @@ napi_status napi_get_property(napi_env env,
return GET_RETURN_STATUS(env);
}

napi_status napi_delete_property(napi_env env,
napi_value object,
napi_value key,
bool* result) {
NAPI_PREAMBLE(env);
CHECK_ARG(env, key);

v8::Isolate* isolate = env->isolate;
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
v8::Local<v8::Object> obj;

CHECK_TO_OBJECT(env, context, obj, object);
v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);

if (result != NULL)
*result = delete_maybe.FromMaybe(false);

return GET_RETURN_STATUS(env);
}

napi_status napi_set_named_property(napi_env env,
napi_value object,
const char* utf8name,
Expand Down
4 changes: 4 additions & 0 deletions src/node_api.h
Expand Up @@ -226,6 +226,10 @@ NAPI_EXTERN napi_status napi_get_property(napi_env env,
napi_value object,
napi_value key,
napi_value* result);
NAPI_EXTERN napi_status napi_delete_property(napi_env env,
napi_value object,
napi_value key,
bool* result);
NAPI_EXTERN napi_status napi_set_named_property(napi_env env,
napi_value object,
const char* utf8name,
Expand Down
44 changes: 44 additions & 0 deletions test/addons-napi/test_object/test.js
Expand Up @@ -120,3 +120,47 @@ assert.strictEqual(newObject.test_string, 'test string');
assert(wrapper.protoA, true);
assert(wrapper.protoB, true);
}

{
// Verify that normal and nonexistent properties can be deleted.
const sym = Symbol();
const obj = { foo: 'bar', [sym]: 'baz' };

assert.strictEqual('foo' in obj, true);
assert.strictEqual(sym in obj, true);
assert.strictEqual('does_not_exist' in obj, false);
assert.strictEqual(test_object.Delete(obj, 'foo'), true);
assert.strictEqual('foo' in obj, false);
assert.strictEqual(sym in obj, true);
assert.strictEqual('does_not_exist' in obj, false);
assert.strictEqual(test_object.Delete(obj, sym), true);
assert.strictEqual('foo' in obj, false);
assert.strictEqual(sym in obj, false);
assert.strictEqual('does_not_exist' in obj, false);
}

{
// Verify that non-configurable properties are not deleted.
const obj = {};

Object.defineProperty(obj, 'foo', { configurable: false });
assert.strictEqual(test_object.Delete(obj, 'foo'), false);
assert.strictEqual('foo' in obj, true);
}

{
// Verify that prototype properties are not deleted.
function Foo() {
this.foo = 'bar';
}

Foo.prototype.foo = 'baz';

const obj = new Foo();

assert.strictEqual(obj.foo, 'bar');
assert.strictEqual(test_object.Delete(obj, 'foo'), true);
assert.strictEqual(obj.foo, 'baz');
assert.strictEqual(test_object.Delete(obj, 'foo'), true);
assert.strictEqual(obj.foo, 'baz');
}
26 changes: 26 additions & 0 deletions test/addons-napi/test_object/test_object.c
Expand Up @@ -86,6 +86,31 @@ napi_value Has(napi_env env, napi_callback_info info) {
return ret;
}

napi_value Delete(napi_env env, napi_callback_info info) {
size_t argc = 2;
napi_value args[2];

NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
NAPI_ASSERT(env, argc == 2, "Wrong number of arguments");

napi_valuetype valuetype0;
NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));
NAPI_ASSERT(env, valuetype0 == napi_object,
"Wrong type of arguments. Expects an object as first argument.");

napi_valuetype valuetype1;
NAPI_CALL(env, napi_typeof(env, args[1], &valuetype1));
NAPI_ASSERT(env, valuetype1 == napi_string || valuetype1 == napi_symbol,
"Wrong type of arguments. Expects a string or symbol as second.");

bool result;
napi_value ret;
NAPI_CALL(env, napi_delete_property(env, args[0], args[1], &result));
NAPI_CALL(env, napi_get_boolean(env, result, &ret));

return ret;
}

napi_value New(napi_env env, napi_callback_info info) {
napi_value ret;
NAPI_CALL(env, napi_create_object(env, &ret));
Expand Down Expand Up @@ -171,6 +196,7 @@ void Init(napi_env env, napi_value exports, napi_value module, void* priv) {
DECLARE_NAPI_PROPERTY("Get", Get),
DECLARE_NAPI_PROPERTY("Set", Set),
DECLARE_NAPI_PROPERTY("Has", Has),
DECLARE_NAPI_PROPERTY("Delete", Delete),
DECLARE_NAPI_PROPERTY("New", New),
DECLARE_NAPI_PROPERTY("Inflate", Inflate),
DECLARE_NAPI_PROPERTY("Wrap", Wrap),
Expand Down

0 comments on commit 80cf25a

Please sign in to comment.