Skip to content

Commit

Permalink
n-api: add napi_has_own_property()
Browse files Browse the repository at this point in the history
Refs: #13925
Backport-PR-URL: #19447
PR-URL: #14063
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
  • Loading branch information
cjihrig authored and MylesBorins committed Apr 16, 2018
1 parent 6ba38e8 commit a5517d8
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 0 deletions.
24 changes: 24 additions & 0 deletions doc/api/n-api.md
Expand Up @@ -2298,6 +2298,29 @@ Returns `napi_ok` if the API succeeded.
This API attempts to delete the `key` own property from `object`.
#### *napi_has_own_property*
<!-- YAML
added: REPLACEME
-->
```C
napi_status napi_has_own_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 own property whose existence to check.
- `[out] result`: Whether the own property exists on the object or not.

Returns `napi_ok` if the API succeeded.

This API checks if the Object passed in has the named own property. `key` must
be a string or a Symbol, or an error will be thrown. N-API will not perform any
conversion between data types.


#### *napi_set_named_property*
<!-- YAML
added: v8.0.0
Expand Down Expand Up @@ -3103,6 +3126,7 @@ support it:
[`napi_get_element`]: #n_api_napi_get_element
[`napi_get_property`]: #n_api_napi_get_property
[`napi_has_property`]: #n_api_napi_has_property
[`napi_has_own_property`]: #n_api_napi_has_own_property
[`napi_set_property`]: #n_api_napi_set_property
[`napi_get_reference_value`]: #n_api_napi_get_reference_value
[`napi_is_error`]: #n_api_napi_is_error
Expand Down
21 changes: 21 additions & 0 deletions src/node_api.cc
Expand Up @@ -1045,6 +1045,27 @@ napi_status napi_delete_property(napi_env env,
return GET_RETURN_STATUS(env);
}

NAPI_EXTERN napi_status napi_has_own_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::Object> obj;

CHECK_TO_OBJECT(env, context, obj, object);
v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
*result = has_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 @@ -230,6 +230,10 @@ NAPI_EXTERN napi_status napi_delete_property(napi_env env,
napi_value object,
napi_value key,
bool* result);
NAPI_EXTERN napi_status napi_has_own_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
34 changes: 34 additions & 0 deletions test/addons-napi/test_object/test.js
Expand Up @@ -50,6 +50,40 @@ assert.strictEqual(newObject.test_string, 'test string');
Object.prototype.toString);
}

{
// Verify that napi_has_own_property() fails if property is not a name.
[true, false, null, undefined, {}, [], 0, 1, () => {}].forEach((value) => {
assert.throws(() => {
test_object.HasOwn({}, value);
}, /^Error: A string or symbol was expected$/);
});
}

{
// Verify that napi_has_own_property() does not walk the prototype chain.
const symbol1 = Symbol();
const symbol2 = Symbol();

function MyObject() {
this.foo = 42;
this.bar = 43;
this[symbol1] = 44;
}

MyObject.prototype.bar = 45;
MyObject.prototype.baz = 46;
MyObject.prototype[symbol2] = 47;

const obj = new MyObject();

assert.strictEqual(test_object.HasOwn(obj, 'foo'), true);
assert.strictEqual(test_object.HasOwn(obj, 'bar'), true);
assert.strictEqual(test_object.HasOwn(obj, symbol1), true);
assert.strictEqual(test_object.HasOwn(obj, 'baz'), false);
assert.strictEqual(test_object.HasOwn(obj, 'toString'), false);
assert.strictEqual(test_object.HasOwn(obj, symbol2), false);
}

{
// test_object.Inflate increases all properties by 1
const cube = {
Expand Down
29 changes: 29 additions & 0 deletions test/addons-napi/test_object/test_object.c
Expand Up @@ -86,6 +86,34 @@ napi_value Has(napi_env env, napi_callback_info info) {
return ret;
}

napi_value HasOwn(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 has_property;
NAPI_CALL(env, napi_has_own_property(env, args[0], args[1], &has_property));

napi_value ret;
NAPI_CALL(env, napi_get_boolean(env, has_property, &ret));

return ret;
}

napi_value Delete(napi_env env, napi_callback_info info) {
size_t argc = 2;
napi_value args[2];
Expand Down Expand Up @@ -196,6 +224,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("HasOwn", HasOwn),
DECLARE_NAPI_PROPERTY("Delete", Delete),
DECLARE_NAPI_PROPERTY("New", New),
DECLARE_NAPI_PROPERTY("Inflate", Inflate),
Expand Down

0 comments on commit a5517d8

Please sign in to comment.