Skip to content

Commit 0b7750a

Browse files
authored
napi: Property & class definition improvements (#101)
 - Rename napi_create_constructor to napi_define_class and include support for defining static properties on the class at the same time - Rename napi_define_property to napi_define_properties to allow for defining multiple properties at the same time - Update tests for the changes
1 parent 490d42e commit 0b7750a

23 files changed

Lines changed: 173 additions & 125 deletions

File tree

src/node_jsrtapi.cc

Lines changed: 112 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <node_object_wrap.h>
2424
#include <env.h>
2525
#include <vector>
26+
#include <algorithm>
2627
#include "ChakraCore.h"
2728

2829
#include "src/jsrtutils.h"
@@ -294,8 +295,13 @@ napi_status napi_create_function(napi_env e, napi_callback cb, void* data, napi_
294295
return napi_ok;
295296
}
296297

297-
napi_status napi_create_constructor(napi_env e, const char* utf8name, napi_callback cb,
298-
void* data, int property_count, napi_property_descriptor* properties, napi_value* result) {
298+
napi_status napi_define_class(napi_env e,
299+
const char* utf8name,
300+
napi_callback cb,
301+
void* data,
302+
int property_count,
303+
const napi_property_descriptor* properties,
304+
napi_value* result) {
299305
CHECK_ARG(result);
300306

301307
napi_value namestring;
@@ -315,8 +321,41 @@ napi_status napi_create_constructor(napi_env e, const char* utf8name, napi_callb
315321
CHECK_JSRT(JsCreatePropertyIdUtf8("constructor", 12, &pid));
316322
CHECK_JSRT(JsSetProperty(prototype, pid, constructor, false));
317323

324+
int instancePropertyCount = 0;
325+
int staticPropertyCount = 0;
318326
for (int i = 0; i < property_count; i++) {
319-
CHECK_NAPI(napi_define_property(e, reinterpret_cast<napi_value>(prototype), &properties[i]));
327+
if ((properties[i].attributes & napi_static_property) != 0) {
328+
staticPropertyCount++;
329+
}
330+
else {
331+
instancePropertyCount++;
332+
}
333+
}
334+
335+
std::vector<napi_property_descriptor> descriptors;
336+
descriptors.reserve(std::max(instancePropertyCount, staticPropertyCount));
337+
338+
if (instancePropertyCount > 0) {
339+
for (int i = 0; i < property_count; i++) {
340+
if ((properties[i].attributes & napi_static_property) == 0) {
341+
descriptors.push_back(properties[i]);
342+
}
343+
}
344+
345+
CHECK_NAPI(napi_define_properties(
346+
e, reinterpret_cast<napi_value>(prototype), descriptors.size(), descriptors.data()));
347+
}
348+
349+
if (staticPropertyCount > 0) {
350+
descriptors.clear();
351+
for (int i = 0; i < property_count; i++) {
352+
if (!(properties[i].attributes & napi_static_property) != 0) {
353+
descriptors.push_back(properties[i]);
354+
}
355+
}
356+
357+
CHECK_NAPI(napi_define_properties(
358+
e, reinterpret_cast<napi_value>(constructor), descriptors.size(), descriptors.data()));
320359
}
321360

322361
*result = reinterpret_cast<napi_value>(constructor);
@@ -364,69 +403,82 @@ napi_status napi_set_property(napi_env e, napi_value o,
364403
return napi_ok;
365404
}
366405

367-
napi_status napi_define_property(napi_env e, napi_value o,
368-
napi_property_descriptor* p) {
369-
napi_value descriptor;
370-
CHECK_NAPI(napi_create_object(e, &descriptor));
371-
372-
napi_propertyname configurableProperty;
373-
CHECK_NAPI(napi_property_name(e, "configurable", &configurableProperty));
374-
napi_value configurable;
375-
CHECK_NAPI(napi_create_boolean(e, !(p->attributes & napi_dont_delete), &configurable));
376-
CHECK_NAPI(napi_set_property(e, descriptor, configurableProperty, configurable));
406+
napi_status napi_define_properties(napi_env e,
407+
napi_value o,
408+
int property_count,
409+
const napi_property_descriptor* properties) {
410+
JsPropertyIdRef configurableProperty;
411+
CHECK_JSRT(JsCreatePropertyIdUtf8("configurable", 12, &configurableProperty));
377412

378-
napi_propertyname enumerableProperty;
379-
CHECK_NAPI(napi_property_name(e, "enumerable", &enumerableProperty));
380-
napi_value enumerable;
381-
CHECK_NAPI(napi_create_boolean(e, !(p->attributes & napi_dont_enum), &enumerable));
382-
CHECK_NAPI(napi_set_property(e, descriptor, enumerableProperty, enumerable));
413+
JsPropertyIdRef enumerableProperty;
414+
CHECK_JSRT(JsCreatePropertyIdUtf8("enumerable", 10, &enumerableProperty));
383415

384-
if (p->method) {
385-
napi_propertyname valueProperty;
386-
CHECK_NAPI(napi_property_name(e, "value", &valueProperty));
387-
napi_value method;
388-
CHECK_NAPI(napi_create_function(e, p->method, p->data, &method));
389-
CHECK_NAPI(napi_set_property(e, descriptor, valueProperty, method));
390-
}
391-
else if (p->getter || p->setter) {
392-
if (p->getter) {
393-
napi_propertyname getProperty;
394-
CHECK_NAPI(napi_property_name(e, "get", &getProperty));
395-
napi_value getter;
396-
CHECK_NAPI(napi_create_function(e, p->getter, p->data, &getter));
397-
CHECK_NAPI(napi_set_property(e, descriptor, getProperty, getter));
416+
for (int i = 0; i < property_count; i++) {
417+
const napi_property_descriptor* p = properties + i;
418+
419+
JsValueRef descriptor;
420+
CHECK_JSRT(JsCreateObject(&descriptor));
421+
422+
JsValueRef configurable;
423+
CHECK_JSRT(JsBoolToBoolean(!(p->attributes & napi_dont_delete), &configurable));
424+
CHECK_JSRT(JsSetProperty(descriptor, configurableProperty, configurable, true));
425+
426+
JsValueRef enumerable;
427+
CHECK_JSRT(JsBoolToBoolean(!(p->attributes & napi_dont_enum), &enumerable));
428+
CHECK_JSRT(JsSetProperty(descriptor, enumerableProperty, enumerable, true));
429+
430+
if (p->method) {
431+
JsPropertyIdRef valueProperty;
432+
CHECK_JSRT(JsCreatePropertyIdUtf8("value", 5, &valueProperty));
433+
JsValueRef method;
434+
CHECK_NAPI(napi_create_function(e, p->method, p->data,
435+
reinterpret_cast<napi_value*>(&method)));
436+
CHECK_JSRT(JsSetProperty(descriptor, valueProperty, method, true));
398437
}
399-
400-
if (p->setter) {
401-
napi_propertyname setProperty;
402-
CHECK_NAPI(napi_property_name(e, "set", &setProperty));
403-
napi_value setter;
404-
CHECK_NAPI(napi_create_function(e, p->setter, p->data, &setter));
405-
CHECK_NAPI(napi_set_property(e, descriptor, setProperty, setter));
438+
else if (p->getter || p->setter) {
439+
if (p->getter) {
440+
JsPropertyIdRef getProperty;
441+
CHECK_JSRT(JsCreatePropertyIdUtf8("get", 3, &getProperty));
442+
JsValueRef getter;
443+
CHECK_NAPI(napi_create_function(e, p->getter, p->data,
444+
reinterpret_cast<napi_value*>(&getter)));
445+
CHECK_JSRT(JsSetProperty(descriptor, getProperty, getter, true));
446+
}
447+
448+
if (p->setter) {
449+
JsPropertyIdRef setProperty;
450+
CHECK_JSRT(JsCreatePropertyIdUtf8("set", 5, &setProperty));
451+
JsValueRef setter;
452+
CHECK_NAPI(napi_create_function(e, p->setter, p->data,
453+
reinterpret_cast<napi_value*>(&setter)));
454+
CHECK_JSRT(JsSetProperty(descriptor, setProperty, setter, true));
455+
}
456+
}
457+
else {
458+
RETURN_STATUS_IF_FALSE(p->value != nullptr, napi_invalid_arg);
459+
460+
JsPropertyIdRef writableProperty;
461+
CHECK_JSRT(JsCreatePropertyIdUtf8("writable", 8, &writableProperty));
462+
JsValueRef writable;
463+
CHECK_JSRT(JsBoolToBoolean(!(p->attributes & napi_read_only), &writable));
464+
CHECK_JSRT(JsSetProperty(descriptor, writableProperty, writable, true));
465+
466+
JsPropertyIdRef valueProperty;
467+
CHECK_JSRT(JsCreatePropertyIdUtf8("value", 5, &valueProperty));
468+
CHECK_JSRT(JsSetProperty(descriptor, valueProperty,
469+
reinterpret_cast<JsValueRef>(p->value), true));
406470
}
407-
}
408-
else {
409-
RETURN_STATUS_IF_FALSE(p->value != nullptr, napi_invalid_arg);
410-
411-
napi_propertyname writableProperty;
412-
CHECK_NAPI(napi_property_name(e, "writable", &writableProperty));
413-
napi_value writable;
414-
CHECK_NAPI(napi_create_boolean(e, !(p->attributes & napi_read_only), &writable));
415-
CHECK_NAPI(napi_set_property(e, descriptor, writableProperty, writable));
416471

417-
napi_propertyname valueProperty;
418-
CHECK_NAPI(napi_property_name(e, "value", &valueProperty));
419-
CHECK_NAPI(napi_set_property(e, descriptor, valueProperty, p->value));
472+
JsPropertyIdRef nameProperty;
473+
CHECK_JSRT(JsCreatePropertyIdUtf8(p->utf8name, strlen(p->utf8name), &nameProperty));
474+
bool result;
475+
CHECK_JSRT(JsDefineProperty(
476+
reinterpret_cast<JsValueRef>(o),
477+
reinterpret_cast<JsPropertyIdRef>(nameProperty),
478+
reinterpret_cast<JsValueRef>(descriptor),
479+
&result));
420480
}
421481

422-
napi_propertyname nameProperty;
423-
CHECK_NAPI(napi_property_name(e, p->utf8name, &nameProperty));
424-
bool result;
425-
CHECK_JSRT(JsDefineProperty(
426-
reinterpret_cast<JsValueRef>(o),
427-
reinterpret_cast<JsPropertyIdRef>(nameProperty),
428-
reinterpret_cast<JsValueRef>(descriptor),
429-
&result));
430482
return napi_ok;
431483
}
432484

@@ -679,7 +731,7 @@ napi_status napi_get_cb_args(napi_env e, napi_callback_info cbinfo,
679731
const CallbackInfo *info = reinterpret_cast<CallbackInfo*>(cbinfo);
680732

681733
int i = 0;
682-
int min = bufferlength < (info->argc) - 1 ? bufferlength : (info->argc) - 1;
734+
int min = std::min(bufferlength, info->argc - 1);
683735

684736
for (; i < min; i++) {
685737
buffer[i] = info->argv[i + 1];

src/node_jsvmapi.h

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,10 @@ NODE_EXTERN napi_status napi_has_element(napi_env e, napi_value object,
186186
uint32_t i, bool* result);
187187
NODE_EXTERN napi_status napi_get_element(napi_env e, napi_value object,
188188
uint32_t i, napi_value* result);
189-
NODE_EXTERN napi_status napi_define_property(napi_env e, napi_value object,
190-
napi_property_descriptor* property);
189+
NODE_EXTERN napi_status napi_define_properties(napi_env e,
190+
napi_value object,
191+
int property_count,
192+
const napi_property_descriptor* properties);
191193

192194
// Methods to work with Arrays
193195
NODE_EXTERN napi_status napi_is_array(napi_env e, napi_value v, bool* result);
@@ -263,13 +265,13 @@ NODE_EXTERN napi_status napi_wrap(napi_env e, napi_value jsObject, void* nativeO
263265
napi_weakref* handle);
264266
NODE_EXTERN napi_status napi_unwrap(napi_env e, napi_value jsObject, void** result);
265267

266-
NODE_EXTERN napi_status napi_create_constructor(napi_env e,
267-
const char* utf8name,
268-
napi_callback cb,
269-
void* data,
270-
int property_count,
271-
napi_property_descriptor* properties,
272-
napi_value* result);
268+
NODE_EXTERN napi_status napi_define_class(napi_env e,
269+
const char* utf8name,
270+
napi_callback constructor,
271+
void* data,
272+
int property_count,
273+
const napi_property_descriptor* properties,
274+
napi_value* result);
273275

274276
// Methods to control object lifespan
275277
NODE_EXTERN napi_status napi_create_persistent(napi_env e, napi_value v,

src/node_jsvmapi_types.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef SRC_NODE_JSVMAPI_TYPES_H_
22
#define SRC_NODE_JSVMAPI_TYPES_H_
33

4+
#include <stddef.h>
45
#include <stdint.h>
56

67
// JSVM API types are all opaque pointers for ABI stability
@@ -21,7 +22,11 @@ enum napi_property_attributes {
2122
napi_default = 0,
2223
napi_read_only = 1 << 0,
2324
napi_dont_enum = 1 << 1,
24-
napi_dont_delete = 1 << 2
25+
napi_dont_delete = 1 << 2,
26+
27+
// Used with napi_define_class to distinguish static properties
28+
// from instance properties. Ignored by napi_define_properties.
29+
napi_static_property = 1 << 10,
2530
};
2631

2732
struct napi_property_descriptor {

test/addons-abi/1_hello_world/binding.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ void Method(napi_env env, napi_callback_info info) {
1212
void Init(napi_env env, napi_value exports, napi_value module) {
1313
napi_status status;
1414
napi_property_descriptor desc = { "hello", Method };
15-
status = napi_define_property(env, exports, &desc);
15+
status = napi_define_properties(env, exports, 1, &desc);
1616
if (status != napi_ok) return;
1717
}
1818

test/addons-abi/2_function_arguments/binding.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ void Add(napi_env env, napi_callback_info info) {
4949
void Init(napi_env env, napi_value exports, napi_value module) {
5050
napi_status status;
5151
napi_property_descriptor addDescriptor = { "add", Add };
52-
status = napi_define_property(env, exports, &addDescriptor);
52+
status = napi_define_properties(env, exports, 1, &addDescriptor);
5353
if (status != napi_ok) return;
5454
}
5555

test/addons-abi/3_callbacks/binding.cc

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,9 @@ void Init(napi_env env, napi_value exports, napi_value module) {
4141
{ "RunCallback", RunCallback },
4242
{ "RunCallbackWithRecv", RunCallbackWithRecv }
4343
};
44-
for (int index = 0; index < 2; index++) {
45-
status = napi_define_property(env, exports, &desc[index]);
46-
if (status != napi_ok) return;
47-
}
44+
status = napi_define_properties(
45+
env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc);
46+
if (status != napi_ok) return;
4847
}
4948

5049
NODE_MODULE_ABI(addon, Init)

test/addons-abi/4_object_factory/binding.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void CreateObject(napi_env env, const napi_callback_info info) {
2525
void Init(napi_env env, napi_value exports, napi_value module) {
2626
napi_status status;
2727
napi_property_descriptor desc = { "exports", CreateObject };
28-
status = napi_define_property(env, module, &desc);
28+
status = napi_define_properties(env, module, 1, &desc);
2929
if (status != napi_ok) return;
3030
}
3131

test/addons-abi/5_function_factory/binding.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ void CreateFunction(napi_env env, napi_callback_info info) {
3333
void Init(napi_env env, napi_value exports, napi_value module) {
3434
napi_status status;
3535
napi_property_descriptor desc = { "exports", CreateFunction };
36-
status = napi_define_property(env, module, &desc);
36+
status = napi_define_properties(env, module, 1, &desc);
3737
if (status != napi_ok) return;
3838
}
3939

test/addons-abi/6_object_wrap/myobject.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ void MyObject::Init(napi_env env, napi_value exports) {
2121
};
2222

2323
napi_value cons;
24-
status = napi_create_constructor(env, "MyObject", New, nullptr, 3, properties, &cons);
24+
status = napi_define_class(env, "MyObject", New, nullptr, 3, properties, &cons);
2525
if (status != napi_ok) return;
2626

2727
status = napi_create_persistent(env, cons, &constructor);

test/addons-abi/7_factory_wrap/binding.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ void Init(napi_env env, napi_value exports, napi_value module) {
2222
if (status != napi_ok) return;
2323

2424
napi_property_descriptor desc = { "exports", CreateObject };
25-
status = napi_define_property(env, module, &desc);
25+
status = napi_define_properties(env, module, 1, &desc);
2626
if (status != napi_ok) return;
2727
}
2828

0 commit comments

Comments
 (0)