Skip to content

Commit d6f0380

Browse files
committed
Address review feedback
1 parent 92853c5 commit d6f0380

File tree

3 files changed

+88
-49
lines changed

3 files changed

+88
-49
lines changed

doc/api/n-api.md

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,7 +1074,7 @@ later by native code. The API allows the caller to pass in a finalize callback,
10741074
in case the underlying native resource needs to be cleaned up when the external
10751075
JavaScript value gets collected.
10761076

1077-
Note: The created value is not an object, and therefore does not support
1077+
*Note*: The created value is not an object, and therefore does not support
10781078
additional properties. It is considered a distinct value type: calling
10791079
`napi_typeof()` with an external value yields `napi_external`.
10801080

@@ -1368,7 +1368,8 @@ Returns `napi_ok` if the API succeeded.
13681368
13691369
This API is used to retrieve the underlying data buffer of an ArrayBuffer and
13701370
its length.
1371-
WARNING: Use caution while using this API. The lifetime of the underlying data
1371+
1372+
*WARNING*: Use caution while using this API. The lifetime of the underlying data
13721373
buffer is managed by the ArrayBuffer even after it's returned. A
13731374
possible safe way to use this API is in conjunction with [`napi_create_reference`][],
13741375
which can be used to guarantee control over the lifetime of the
@@ -1395,7 +1396,8 @@ Returns `napi_ok` if the API succeeded.
13951396

13961397
This API is used to retrieve the underlying data buffer of a `node::Buffer`
13971398
and it's length.
1398-
Warning: Use caution while using this API since the underlying data buffer's
1399+
1400+
*Warning*: Use caution while using this API since the underlying data buffer's
13991401
lifetime is not guaranteed if it's managed by the VM.
14001402

14011403
#### *napi_get_prototype*
@@ -1442,7 +1444,8 @@ to start projecting the TypedArray.
14421444
Returns `napi_ok` if the API succeeded.
14431445

14441446
This API returns various properties of a typed array.
1445-
Warning: Use caution while using this API since the underlying data buffer
1447+
1448+
*Warning*: Use caution while using this API since the underlying data buffer
14461449
is managed by the VM
14471450

14481451
#### *napi_get_value_bool*
@@ -2792,13 +2795,13 @@ The optional returned reference is initially a weak reference, meaning it
27922795
has a reference count of 0. Typically this reference count would be incremented
27932796
temporarily during async operations that require the instance to remain valid.
27942797
2795-
Caution: The optional returned reference (if obtained) should be deleted via
2798+
*Caution*: The optional returned reference (if obtained) should be deleted via
27962799
[`napi_delete_reference`][] ONLY in response to the finalize callback
27972800
invocation. (If it is deleted before then, then the finalize callback may never
2798-
be invoked.) Therefore when obtaining a reference a finalize callback is also
2801+
be invoked.) Therefore, when obtaining a reference a finalize callback is also
27992802
required in order to enable correct proper of the reference.
28002803
2801-
Note: This API may modify the prototype chain of the wrapper object.
2804+
*Note*: This API may modify the prototype chain of the wrapper object.
28022805
Afterward, additional manipulation of the wrapper's prototype chain may cause
28032806
`napi_unwrap()` to fail.
28042807

src/node_api.cc

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1995,13 +1995,16 @@ napi_status napi_unwrap(napi_env env, napi_value js_object, void** result) {
19951995
RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
19961996
v8::Local<v8::Object> obj = value.As<v8::Object>();
19971997

1998-
// The object's prototype should be a wrapper with an internal field.
1999-
v8::Local<v8::Value> proto = obj->GetPrototype();
2000-
RETURN_STATUS_IF_FALSE(
2001-
env, !proto.IsEmpty() && proto->IsObject(), napi_invalid_arg);
2002-
v8::Local<v8::Object> wrapper = proto.As<v8::Object>();
2003-
RETURN_STATUS_IF_FALSE(
2004-
env, wrapper->InternalFieldCount() == 1, napi_invalid_arg);
1998+
// Search the object's prototype chain for the wrapper with an internal field.
1999+
// Usually the wrapper would be the first in the chain, but it is OK for
2000+
// other objects to be inserted in the prototype chain.
2001+
v8::Local<v8::Object> wrapper = obj;
2002+
do {
2003+
v8::Local<v8::Value> proto = wrapper->GetPrototype();
2004+
RETURN_STATUS_IF_FALSE(
2005+
env, !proto.IsEmpty() && proto->IsObject(), napi_invalid_arg);
2006+
wrapper = proto.As<v8::Object>();
2007+
} while (wrapper->InternalFieldCount() != 1);
20052008

20062009
v8::Local<v8::Value> unwrappedValue = wrapper->GetInternalField(0);
20072010
RETURN_STATUS_IF_FALSE(env, unwrappedValue->IsExternal(), napi_invalid_arg);

test/addons-napi/test_object/test.js

Lines changed: 68 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31,40 +31,73 @@ assert(test_object.Has(newObject, 'test_number'));
3131
assert.strictEqual(newObject.test_number, 987654321);
3232
assert.strictEqual(newObject.test_string, 'test string');
3333

34-
// test_object.Inflate increases all properties by 1
35-
const cube = {
36-
x: 10,
37-
y: 10,
38-
z: 10
39-
};
34+
{
35+
// test_object.Inflate increases all properties by 1
36+
const cube = {
37+
x: 10,
38+
y: 10,
39+
z: 10
40+
};
4041

41-
assert.deepStrictEqual(test_object.Inflate(cube), {x: 11, y: 11, z: 11});
42-
assert.deepStrictEqual(test_object.Inflate(cube), {x: 12, y: 12, z: 12});
43-
assert.deepStrictEqual(test_object.Inflate(cube), {x: 13, y: 13, z: 13});
44-
cube.t = 13;
45-
assert.deepStrictEqual(test_object.Inflate(cube), {x: 14, y: 14, z: 14, t: 14});
46-
47-
const sym1 = Symbol('1');
48-
const sym2 = Symbol('2');
49-
const sym3 = Symbol('3');
50-
const sym4 = Symbol('4');
51-
const object2 = {
52-
[sym1]: '@@iterator',
53-
[sym2]: sym3
54-
};
42+
assert.deepStrictEqual(test_object.Inflate(cube), {x: 11, y: 11, z: 11});
43+
assert.deepStrictEqual(test_object.Inflate(cube), {x: 12, y: 12, z: 12});
44+
assert.deepStrictEqual(test_object.Inflate(cube), {x: 13, y: 13, z: 13});
45+
cube.t = 13;
46+
assert.deepStrictEqual(
47+
test_object.Inflate(cube), {x: 14, y: 14, z: 14, t: 14});
48+
49+
const sym1 = Symbol('1');
50+
const sym2 = Symbol('2');
51+
const sym3 = Symbol('3');
52+
const sym4 = Symbol('4');
53+
const object2 = {
54+
[sym1]: '@@iterator',
55+
[sym2]: sym3
56+
};
57+
58+
assert(test_object.Has(object2, sym1));
59+
assert(test_object.Has(object2, sym2));
60+
assert.strictEqual(test_object.Get(object2, sym1), '@@iterator');
61+
assert.strictEqual(test_object.Get(object2, sym2), sym3);
62+
assert(test_object.Set(object2, 'string', 'value'));
63+
assert(test_object.Set(object2, sym4, 123));
64+
assert(test_object.Has(object2, 'string'));
65+
assert(test_object.Has(object2, sym4));
66+
assert.strictEqual(test_object.Get(object2, 'string'), 'value');
67+
assert.strictEqual(test_object.Get(object2, sym4), 123);
68+
}
69+
70+
{
71+
// Wrap a pointer in a JS object, then verify the pointer can be unwrapped.
72+
const wrapper = {};
73+
test_object.Wrap(wrapper);
74+
75+
assert(test_object.Unwrap(wrapper));
76+
}
77+
78+
{
79+
// Verify that wrapping doesn't break an object's prototype chain.
80+
const wrapper = {};
81+
const protoA = { protoA: true };
82+
Object.setPrototypeOf(wrapper, protoA);
83+
test_object.Wrap(wrapper);
84+
85+
assert(test_object.Unwrap(wrapper));
86+
assert(wrapper.protoA);
87+
}
88+
89+
{
90+
// Verify the pointer can be unwrapped after inserting in the prototype chain.
91+
const wrapper = {};
92+
const protoA = { protoA: true };
93+
Object.setPrototypeOf(wrapper, protoA);
94+
test_object.Wrap(wrapper);
95+
96+
const protoB = { protoB: true };
97+
Object.setPrototypeOf(protoB, Object.getPrototypeOf(wrapper));
98+
Object.setPrototypeOf(wrapper, protoB);
5599

56-
assert(test_object.Has(object2, sym1));
57-
assert(test_object.Has(object2, sym2));
58-
assert.strictEqual(test_object.Get(object2, sym1), '@@iterator');
59-
assert.strictEqual(test_object.Get(object2, sym2), sym3);
60-
assert(test_object.Set(object2, 'string', 'value'));
61-
assert(test_object.Set(object2, sym4, 123));
62-
assert(test_object.Has(object2, 'string'));
63-
assert(test_object.Has(object2, sym4));
64-
assert.strictEqual(test_object.Get(object2, 'string'), 'value');
65-
assert.strictEqual(test_object.Get(object2, sym4), 123);
66-
67-
// Wrap a pointer in a JS object, then verify that the pointer can be unwrapped.
68-
const wrapper = {};
69-
test_object.Wrap(wrapper);
70-
assert(test_object.Unwrap(wrapper));
100+
assert(test_object.Unwrap(wrapper));
101+
assert(wrapper.protoA, true);
102+
assert(wrapper.protoB, true);
103+
}

0 commit comments

Comments
 (0)