Skip to content

Commit 77350ee

Browse files
NickNasomhdawson
authored andcommitted
src: added Freeze and Seal method to Object class.
PR-URL: #955 Reviewed-By: Gabriel Schulhof <[email protected]> Reviewed-By: Michael Dawson <[email protected]>
1 parent bc5147c commit 77350ee

File tree

8 files changed

+113
-0
lines changed

8 files changed

+113
-0
lines changed

doc/object.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,30 @@ void Napi::Object::DefineProperties (____ properties)
217217
218218
Defines properties on the object.
219219
220+
### Freeze()
221+
222+
```cpp
223+
void Napi::Object::Freeze()
224+
```
225+
226+
The `Napi::Object::Freeze()` method freezes an object. A frozen object can no
227+
longer changed. Freezing an object prevents new properties from being added to
228+
it, existing properties from being removed, prevents changing the
229+
enumerability, configurability, or writability of existing properties and
230+
prevents the valuee of existing properties from being changed. In addition,
231+
freezing an object also prevents its prototype from being changed.
232+
233+
### Seal()
234+
235+
```cpp
236+
void Napi::Object::Seal()
237+
```
238+
239+
The `Napi::Object::Seal()` method seals an object, preventing new properties
240+
from being added to it and marking all existing properties as non-configurable.
241+
Values of present properties can still be changed as long as thery are
242+
writable.
243+
220244
### operator\[\]()
221245

222246
```cpp

napi-inl.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,6 +1379,18 @@ inline void Object::AddFinalizer(Finalizer finalizeCallback,
13791379
}
13801380
}
13811381

1382+
#if NAPI_VERSION >= 8
1383+
inline void Object::Freeze() {
1384+
napi_status status = napi_object_freeze(_env, _value);
1385+
NAPI_THROW_IF_FAILED_VOID(_env, status);
1386+
}
1387+
1388+
inline void Object::Seal() {
1389+
napi_status status = napi_object_seal(_env, _value);
1390+
NAPI_THROW_IF_FAILED_VOID(_env, status);
1391+
}
1392+
#endif // NAPI_VERSION >= 8
1393+
13821394
////////////////////////////////////////////////////////////////////////////////
13831395
// External class
13841396
////////////////////////////////////////////////////////////////////////////////

napi.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,10 @@ namespace Napi {
776776
inline void AddFinalizer(Finalizer finalizeCallback,
777777
T* data,
778778
Hint* finalizeHint);
779+
#if NAPI_VERSION >= 8
780+
void Freeze();
781+
void Seal();
782+
#endif // NAPI_VERSION >= 8
779783
};
780784

781785
template <typename T>

test/binding.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ Object InitObjectReference(Env env);
6767
Object InitReference(Env env);
6868
Object InitVersionManagement(Env env);
6969
Object InitThunkingManual(Env env);
70+
#if (NAPI_VERSION > 7)
71+
Object InitObjectFreezeSeal(Env env);
72+
#endif
7073

7174
Object Init(Env env, Object exports) {
7275
#if (NAPI_VERSION > 5)
@@ -141,6 +144,9 @@ Object Init(Env env, Object exports) {
141144
exports.Set("reference", InitReference(env));
142145
exports.Set("version_management", InitVersionManagement(env));
143146
exports.Set("thunking_manual", InitThunkingManual(env));
147+
#if (NAPI_VERSION > 7)
148+
exports.Set("object_freeze_seal", InitObjectFreezeSeal(env));
149+
#endif
144150
return exports;
145151
}
146152

test/binding.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
'object/has_own_property.cc',
4040
'object/has_property.cc',
4141
'object/object.cc',
42+
'object/object_freeze_seal.cc',
4243
'object/set_property.cc',
4344
'object/subscript_operator.cc',
4445
'promise.cc',

test/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ if (majorNodeVersion < 12) {
112112
testModules.splice(testModules.indexOf('objectwrap_worker_thread'), 1);
113113
}
114114

115+
if (napiVersion < 8) {
116+
testModules.splice(testModules.indexOf('object/object_freeze_seal'), 1);
117+
}
118+
115119
(async function() {
116120
console.log(`Testing with Node-API Version '${napiVersion}'.`);
117121

test/object/object_freeze_seal.cc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#include "napi.h"
2+
3+
#if (NAPI_VERSION > 7)
4+
5+
using namespace Napi;
6+
7+
void Freeze(const CallbackInfo& info) {
8+
Object obj = info[0].As<Object>();
9+
obj.Freeze();
10+
}
11+
12+
void Seal(const CallbackInfo& info) {
13+
Object obj = info[0].As<Object>();
14+
obj.Seal();
15+
}
16+
17+
Object InitObjectFreezeSeal(Env env) {
18+
Object exports = Object::New(env);
19+
exports["freeze"] = Function::New(env, Freeze);
20+
exports["seal"] = Function::New(env, Seal);
21+
return exports;
22+
}
23+
24+
#endif

test/object/object_freeze_seal.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
const buildType = process.config.target_defaults.default_configuration;
3+
const assert = require('assert');
4+
5+
test(require(`../build/${buildType}/binding.node`));
6+
test(require(`../build/${buildType}/binding_noexcept.node`));
7+
8+
function test(binding) {
9+
{
10+
const obj = { x: 'a', y: 'b', z: 'c' };
11+
binding.object_freeze_seal.freeze(obj);
12+
assert.strictEqual(Object.isFrozen(obj), true);
13+
assert.throws(() => {
14+
obj.x = 10;
15+
}, /Cannot assign to read only property 'x' of object '#<Object>/);
16+
assert.throws(() => {
17+
obj.w = 15;
18+
}, /Cannot add property w, object is not extensible/);
19+
assert.throws(() => {
20+
delete obj.x;
21+
}, /Cannot delete property 'x' of #<Object>/);
22+
}
23+
24+
{
25+
const obj = { x: 'a', y: 'b', z: 'c' };
26+
binding.object_freeze_seal.seal(obj);
27+
assert.strictEqual(Object.isSealed(obj), true);
28+
assert.throws(() => {
29+
obj.w = 'd';
30+
}, /Cannot add property w, object is not extensible/);
31+
assert.throws(() => {
32+
delete obj.x;
33+
}, /Cannot delete property 'x' of #<Object>/);
34+
// Sealed objects allow updating existing properties,
35+
// so this should not throw.
36+
obj.x = 'd';
37+
}
38+
}

0 commit comments

Comments
 (0)