diff --git a/src/node_jsvmapi.cc b/src/node_jsvmapi.cc index ad98176e88f62a..de9ed3ded8ddaa 100644 --- a/src/node_jsvmapi.cc +++ b/src/node_jsvmapi.cc @@ -596,24 +596,23 @@ napi_status napi_create_function( return GET_RETURN_STATUS(); } -napi_status napi_create_constructor( +napi_status napi_define_class( napi_env e, const char* utf8name, - napi_callback cb, + napi_callback constructor, void* data, int property_count, - napi_property_descriptor* properties, + const napi_property_descriptor* properties, napi_value* result) { NAPI_PREAMBLE(e); CHECK_ARG(result); v8::Isolate *isolate = v8impl::V8IsolateFromJsEnv(e); v8::Local context = isolate->GetCurrentContext(); - v8::Local retval; v8::EscapableHandleScope scope(isolate); v8::Local cbdata = - v8impl::CreateFunctionCallbackData(e, cb, data); + v8impl::CreateFunctionCallbackData(e, constructor, data); RETURN_STATUS_IF_FALSE(!cbdata.IsEmpty(), napi_generic_failure); @@ -627,8 +626,16 @@ napi_status napi_create_constructor( CHECK_NEW_FROM_UTF8(isolate, namestring, utf8name); tpl->SetClassName(namestring); + int staticPropertyCount = 0; for (int i = 0; i < property_count; i++) { - napi_property_descriptor* p = properties + i; + const napi_property_descriptor* p = properties + i; + + if ((p->attributes & napi_static_property) != 0) { + // Static properties are handled separately below. + staticPropertyCount++; + continue; + } + v8::Local propertyname; CHECK_NEW_FROM_UTF8(isolate, propertyname, p->utf8name); @@ -671,8 +678,23 @@ napi_status napi_create_constructor( } } - retval = scope.Escape(tpl->GetFunction()); - *result = v8impl::JsValueFromV8LocalValue(retval); + *result = v8impl::JsValueFromV8LocalValue(scope.Escape(tpl->GetFunction())); + + if (staticPropertyCount > 0) { + std::vector staticDescriptors; + staticDescriptors.reserve(staticPropertyCount); + + for (int i = 0; i < property_count; i++) { + const napi_property_descriptor* p = properties + i; + if ((p->attributes & napi_static_property) != 0) { + staticDescriptors.push_back(*p); + } + } + + napi_status status = napi_define_properties( + e, *result, staticDescriptors.size(), staticDescriptors.data()); + if (status != napi_ok) return status; + } return GET_RETURN_STATUS(); } @@ -851,77 +873,80 @@ napi_status napi_get_element(napi_env e, return GET_RETURN_STATUS(); } -napi_status napi_define_property(napi_env e, napi_value o, - napi_property_descriptor* p) { +napi_status napi_define_properties(napi_env e, napi_value o, + int property_count, const napi_property_descriptor* properties) { NAPI_PREAMBLE(e); v8::Isolate *isolate = v8impl::V8IsolateFromJsEnv(e); v8::Local context = isolate->GetCurrentContext(); - v8::Local obj; - CHECK_TO_OBJECT(context, obj, o); + v8::Local obj = v8impl::V8LocalValueFromJsValue(o).As(); - v8::Local name; - CHECK_NEW_FROM_UTF8(isolate, name, p->utf8name); + for (int i = 0; i < property_count; i++) { + const napi_property_descriptor* p = &properties[i]; - v8::PropertyAttribute attributes = - static_cast(p->attributes); + v8::Local name; + CHECK_NEW_FROM_UTF8(isolate, name, p->utf8name); - if (p->method) { - v8::Local cbdata = v8impl::CreateFunctionCallbackData( - e, p->method, p->data); + v8::PropertyAttribute attributes = + static_cast(p->attributes & ~napi_static_property); - RETURN_STATUS_IF_FALSE(!cbdata.IsEmpty(), napi_generic_failure); + if (p->method) { + v8::Local cbdata = v8impl::CreateFunctionCallbackData( + e, p->method, p->data); - v8::Local t = v8::FunctionTemplate::New( - isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata); + RETURN_STATUS_IF_FALSE(!cbdata.IsEmpty(), napi_generic_failure); - auto define_maybe = obj->DefineOwnProperty( - context, - name, - t->GetFunction(), - attributes); + v8::Local t = v8::FunctionTemplate::New( + isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata); - // IsNothing seems like a serious failure, - // should we return a different error code if the define failed? - if (define_maybe.IsNothing() || !define_maybe.FromMaybe(false)) - { - return napi_set_last_error(napi_generic_failure); + auto define_maybe = obj->DefineOwnProperty( + context, + name, + t->GetFunction(), + attributes); + + // IsNothing seems like a serious failure, + // should we return a different error code if the define failed? + if (define_maybe.IsNothing() || !define_maybe.FromMaybe(false)) + { + return napi_set_last_error(napi_generic_failure); + } } - } - else if (p->getter || p->setter) { - v8::Local cbdata = v8impl::CreateAccessorCallbackData( - e, p->getter, p->setter, p->data); - - auto set_maybe = obj->SetAccessor( - context, - name, - v8impl::GetterCallbackWrapper::Invoke, - p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr, - cbdata, - v8::AccessControl::DEFAULT, - attributes); - - // IsNothing seems like a serious failure, - // should we return a different error code if the set failed? - if (set_maybe.IsNothing() || !set_maybe.FromMaybe(false)) - { - return napi_set_last_error(napi_generic_failure); + else if (p->getter || p->setter) { + v8::Local cbdata = v8impl::CreateAccessorCallbackData( + e, p->getter, p->setter, p->data); + + auto set_maybe = obj->SetAccessor( + context, + name, + v8impl::GetterCallbackWrapper::Invoke, + p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr, + cbdata, + v8::AccessControl::DEFAULT, + attributes); + + // IsNothing seems like a serious failure, + // should we return a different error code if the set failed? + if (set_maybe.IsNothing() || !set_maybe.FromMaybe(false)) + { + return napi_set_last_error(napi_generic_failure); + } } - } - else { - v8::Local value = v8impl::V8LocalValueFromJsValue(p->value); - - auto define_maybe = obj->DefineOwnProperty( - context, - name, - value, - attributes); - - // IsNothing seems like a serious failure, - // should we return a different error code if the define failed? - if (define_maybe.IsNothing() || !define_maybe.FromMaybe(false)) - { - return napi_set_last_error(napi_generic_failure); + else { + v8::Local value = v8impl::V8LocalValueFromJsValue(p->value); + + auto define_maybe = obj->DefineOwnProperty( + context, + name, + value, + attributes); + + // IsNothing seems like a serious failure, + // should we return a different error code if the define failed? + if (define_maybe.IsNothing() || !define_maybe.FromMaybe(false)) + { + return napi_set_last_error(napi_generic_failure); + } } } diff --git a/src/node_jsvmapi.h b/src/node_jsvmapi.h index ffb682b46ed4d0..fadafd165ca522 100644 --- a/src/node_jsvmapi.h +++ b/src/node_jsvmapi.h @@ -185,8 +185,10 @@ NODE_EXTERN napi_status napi_has_element(napi_env e, napi_value object, uint32_t i, bool* result); NODE_EXTERN napi_status napi_get_element(napi_env e, napi_value object, uint32_t i, napi_value* result); -NODE_EXTERN napi_status napi_define_property(napi_env e, napi_value object, - napi_property_descriptor* property); +NODE_EXTERN napi_status napi_define_properties(napi_env e, + napi_value object, + int property_count, + const napi_property_descriptor* properties); // Methods to work with Arrays NODE_EXTERN napi_status napi_is_array(napi_env e, napi_value v, bool* result); @@ -262,13 +264,13 @@ NODE_EXTERN napi_status napi_wrap(napi_env e, napi_value jsObject, void* nativeO napi_weakref* handle); NODE_EXTERN napi_status napi_unwrap(napi_env e, napi_value jsObject, void** result); -NODE_EXTERN napi_status napi_create_constructor(napi_env e, - const char* utf8name, - napi_callback cb, - void* data, - int property_count, - napi_property_descriptor* properties, - napi_value* result); +NODE_EXTERN napi_status napi_define_class(napi_env e, + const char* utf8name, + napi_callback constructor, + void* data, + int property_count, + const napi_property_descriptor* properties, + napi_value* result); // Methods to control object lifespan NODE_EXTERN napi_status napi_create_persistent(napi_env e, napi_value v, diff --git a/src/node_jsvmapi_types.h b/src/node_jsvmapi_types.h index 5941a29a26aa7d..0ba998c30167ce 100644 --- a/src/node_jsvmapi_types.h +++ b/src/node_jsvmapi_types.h @@ -21,7 +21,11 @@ enum napi_property_attributes { napi_default = 0, napi_read_only = 1 << 0, napi_dont_enum = 1 << 1, - napi_dont_delete = 1 << 2 + napi_dont_delete = 1 << 2, + + // Used with napi_define_class to distinguish static properties + // from instance properties. Ignored by napi_define_properties. + napi_static_property = 1 << 10, }; struct napi_property_descriptor { diff --git a/test/addons-abi/1_hello_world/binding.cc b/test/addons-abi/1_hello_world/binding.cc index 0a3654b98b45aa..d4615d3d91741e 100644 --- a/test/addons-abi/1_hello_world/binding.cc +++ b/test/addons-abi/1_hello_world/binding.cc @@ -12,7 +12,7 @@ void Method(napi_env env, napi_callback_info info) { void Init(napi_env env, napi_value exports, napi_value module) { napi_status status; napi_property_descriptor desc = { "hello", Method }; - status = napi_define_property(env, exports, &desc); + status = napi_define_properties(env, exports, 1, &desc); if (status != napi_ok) return; } diff --git a/test/addons-abi/2_function_arguments/binding.cc b/test/addons-abi/2_function_arguments/binding.cc index 92de2390874ce9..d4afc59a71eeed 100644 --- a/test/addons-abi/2_function_arguments/binding.cc +++ b/test/addons-abi/2_function_arguments/binding.cc @@ -49,7 +49,7 @@ void Add(napi_env env, napi_callback_info info) { void Init(napi_env env, napi_value exports, napi_value module) { napi_status status; napi_property_descriptor addDescriptor = { "add", Add }; - status = napi_define_property(env, exports, &addDescriptor); + status = napi_define_properties(env, exports, 1, &addDescriptor); if (status != napi_ok) return; } diff --git a/test/addons-abi/3_callbacks/binding.cc b/test/addons-abi/3_callbacks/binding.cc index 7d905c0cf80655..5faab51f411f9b 100644 --- a/test/addons-abi/3_callbacks/binding.cc +++ b/test/addons-abi/3_callbacks/binding.cc @@ -24,7 +24,7 @@ void RunCallback(napi_env env, const napi_callback_info info) { void Init(napi_env env, napi_value exports, napi_value module) { napi_status status; napi_property_descriptor desc = { "exports", RunCallback }; - status = napi_define_property(env, module, &desc); + status = napi_define_properties(env, module, 1, &desc); if (status != napi_ok) return; } diff --git a/test/addons-abi/4_object_factory/binding.cc b/test/addons-abi/4_object_factory/binding.cc index a3a6366e825fd2..c91c982f4e5322 100644 --- a/test/addons-abi/4_object_factory/binding.cc +++ b/test/addons-abi/4_object_factory/binding.cc @@ -25,7 +25,7 @@ void CreateObject(napi_env env, const napi_callback_info info) { void Init(napi_env env, napi_value exports, napi_value module) { napi_status status; napi_property_descriptor desc = { "exports", CreateObject }; - status = napi_define_property(env, module, &desc); + status = napi_define_properties(env, module, 1, &desc); if (status != napi_ok) return; } diff --git a/test/addons-abi/5_function_factory/binding.cc b/test/addons-abi/5_function_factory/binding.cc index 1b77c614882bc1..322cc8487d41b0 100644 --- a/test/addons-abi/5_function_factory/binding.cc +++ b/test/addons-abi/5_function_factory/binding.cc @@ -33,7 +33,7 @@ void CreateFunction(napi_env env, napi_callback_info info) { void Init(napi_env env, napi_value exports, napi_value module) { napi_status status; napi_property_descriptor desc = { "exports", CreateFunction }; - status = napi_define_property(env, module, &desc); + status = napi_define_properties(env, module, 1, &desc); if (status != napi_ok) return; } diff --git a/test/addons-abi/6_object_wrap/myobject.cc b/test/addons-abi/6_object_wrap/myobject.cc index da5a6397602621..b33d6f719ec4f5 100644 --- a/test/addons-abi/6_object_wrap/myobject.cc +++ b/test/addons-abi/6_object_wrap/myobject.cc @@ -21,7 +21,7 @@ void MyObject::Init(napi_env env, napi_value exports) { }; napi_value cons; - status = napi_create_constructor(env, "MyObject", New, nullptr, 3, properties, &cons); + status = napi_define_class(env, "MyObject", New, nullptr, 3, properties, &cons); if (status != napi_ok) return; status = napi_create_persistent(env, cons, &constructor); diff --git a/test/addons-abi/7_factory_wrap/binding.cc b/test/addons-abi/7_factory_wrap/binding.cc index 02e3972518e872..6042eaa8296f3a 100644 --- a/test/addons-abi/7_factory_wrap/binding.cc +++ b/test/addons-abi/7_factory_wrap/binding.cc @@ -22,7 +22,7 @@ void Init(napi_env env, napi_value exports, napi_value module) { if (status != napi_ok) return; napi_property_descriptor desc = { "exports", CreateObject }; - status = napi_define_property(env, module, &desc); + status = napi_define_properties(env, module, 1, &desc); if (status != napi_ok) return; } diff --git a/test/addons-abi/7_factory_wrap/myobject.cc b/test/addons-abi/7_factory_wrap/myobject.cc index e36450cf1d9e9a..d150e467c7dcc0 100644 --- a/test/addons-abi/7_factory_wrap/myobject.cc +++ b/test/addons-abi/7_factory_wrap/myobject.cc @@ -16,7 +16,7 @@ napi_status MyObject::Init(napi_env env) { }; napi_value cons; - status = napi_create_constructor(env, "MyObject", New, nullptr, 1, properties, &cons); + status = napi_define_class(env, "MyObject", New, nullptr, 1, properties, &cons); if (status != napi_ok) return status; status = napi_create_persistent(env, cons, &constructor); diff --git a/test/addons-abi/8_passing_wrapped/binding.cc b/test/addons-abi/8_passing_wrapped/binding.cc index e18b5366cb092d..b727079b812644 100644 --- a/test/addons-abi/8_passing_wrapped/binding.cc +++ b/test/addons-abi/8_passing_wrapped/binding.cc @@ -42,12 +42,11 @@ void Init(napi_env env, napi_value exports, napi_value module) { MyObject::Init(env); - napi_property_descriptor desc = { "createObject", CreateObject }; - status = napi_define_property(env, exports, &desc); - if (status != napi_ok) return; - - napi_property_descriptor desc2 = { "add", Add }; - status = napi_define_property(env, exports, &desc2); + napi_property_descriptor desc[] = { + { "createObject", CreateObject }, + { "add", Add }, + }; + status = napi_define_properties(env, exports, sizeof(desc) / sizeof(*desc), desc); if (status != napi_ok) return; } diff --git a/test/addons-abi/8_passing_wrapped/myobject.cc b/test/addons-abi/8_passing_wrapped/myobject.cc index 7206850f152e04..878170fe05fdd0 100644 --- a/test/addons-abi/8_passing_wrapped/myobject.cc +++ b/test/addons-abi/8_passing_wrapped/myobject.cc @@ -14,7 +14,7 @@ napi_status MyObject::Init(napi_env env) { napi_status status; napi_value cons; - status = napi_create_constructor(env, "MyObject", New, nullptr, 0, nullptr, &cons); + status = napi_define_class(env, "MyObject", New, nullptr, 0, nullptr, &cons); if (status != napi_ok) return status; status = napi_create_persistent(env, cons, &constructor); diff --git a/test/addons-abi/test_array/test_array.cc b/test/addons-abi/test_array/test_array.cc index cc57be60c9668a..1bd2a7cce6edca 100644 --- a/test/addons-abi/test_array/test_array.cc +++ b/test/addons-abi/test_array/test_array.cc @@ -128,10 +128,9 @@ void Init(napi_env env, napi_value exports, napi_value module) { { "New", New }, }; - for (int i = 0; i < sizeof(descriptors) / sizeof(*descriptors); i++) { - status = napi_define_property(env, exports, &descriptors[i]); - if (status != napi_ok) return; - } + status = napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); + if (status != napi_ok) return; } NODE_MODULE_ABI(addon, Init) diff --git a/test/addons-abi/test_constructor/test_constructor.cc b/test/addons-abi/test_constructor/test_constructor.cc index 328cccafcb8221..cf7b01405a68a6 100644 --- a/test/addons-abi/test_constructor/test_constructor.cc +++ b/test/addons-abi/test_constructor/test_constructor.cc @@ -91,7 +91,7 @@ void Init(napi_env env, napi_value exports, napi_value module) { }; napi_value cons; - status = napi_create_constructor(env, "MyObject", New, + status = napi_define_class(env, "MyObject", New, nullptr, sizeof(properties)/sizeof(*properties), properties, &cons); if (status != napi_ok) return; diff --git a/test/addons-abi/test_exception/test_exception.cc b/test/addons-abi/test_exception/test_exception.cc index dbef98c701cfc6..698a246a86e65f 100644 --- a/test/addons-abi/test_exception/test_exception.cc +++ b/test/addons-abi/test_exception/test_exception.cc @@ -65,10 +65,9 @@ NAPI_MODULE_INIT(Init) { { "wasPending", wasPending }, }; - for (int i = 0; i < sizeof(descriptors) / sizeof(*descriptors); i++) { - status = napi_define_property(env, exports, &descriptors[i]); - if (status != napi_ok) return; - } + status = napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); + if (status != napi_ok) return; } NODE_MODULE_ABI(addon, Init) diff --git a/test/addons-abi/test_instanceof/test_instanceof.cc b/test/addons-abi/test_instanceof/test_instanceof.cc index 5cca490a7ae7b6..af13e25eaaf761 100644 --- a/test/addons-abi/test_instanceof/test_instanceof.cc +++ b/test/addons-abi/test_instanceof/test_instanceof.cc @@ -28,10 +28,9 @@ void Init(napi_env env, napi_value exports, napi_value module) { { "doInstanceOf", doInstanceOf }, }; - for (int i = 0; i < sizeof(descriptors) / sizeof(*descriptors); i++) { - status = napi_define_property(env, exports, &descriptors[i]); - if (status != napi_ok) return; - } + status = napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); + if (status != napi_ok) return; } NODE_MODULE_ABI(addon, Init) diff --git a/test/addons-abi/test_number/test_number.cc b/test/addons-abi/test_number/test_number.cc index 6db4ef7a47c4f2..68872f36528df9 100644 --- a/test/addons-abi/test_number/test_number.cc +++ b/test/addons-abi/test_number/test_number.cc @@ -44,10 +44,9 @@ void Init(napi_env env, napi_value exports, napi_value module) { { "Test", Test }, }; - for (int i = 0; i < sizeof(descriptors) / sizeof(*descriptors); i++) { - status = napi_define_property(env, exports, &descriptors[i]); - if (status != napi_ok) return; - } + status = napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); + if (status != napi_ok) return; } NODE_MODULE_ABI(addon, Init) diff --git a/test/addons-abi/test_object/test_object.cc b/test/addons-abi/test_object/test_object.cc index 7db8bb2934c4e0..f6c3653a2d2b4a 100644 --- a/test/addons-abi/test_object/test_object.cc +++ b/test/addons-abi/test_object/test_object.cc @@ -224,10 +224,9 @@ void Init(napi_env env, napi_value exports, napi_value module) { { "Inflate", Inflate }, }; - for (int i = 0; i < sizeof(descriptors) / sizeof(*descriptors); i++) { - status = napi_define_property(env, exports, &descriptors[i]); - if (status != napi_ok) return; - } + status = napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); + if (status != napi_ok) return; } NODE_MODULE_ABI(addon, Init) diff --git a/test/addons-abi/test_properties/test_properties.cc b/test/addons-abi/test_properties/test_properties.cc index 8e703258de5bce..d4773b10bd7287 100644 --- a/test/addons-abi/test_properties/test_properties.cc +++ b/test/addons-abi/test_properties/test_properties.cc @@ -78,10 +78,9 @@ void Init(napi_env env, napi_value exports, napi_value module) { static_cast(napi_read_only | napi_dont_enum) }, }; - for (int i = 0; i < sizeof(properties) / sizeof(*properties); i++) { - status = napi_define_property(env, exports, &properties[i]); - if (status != napi_ok) return; - } + status = napi_define_properties( + env, exports, sizeof(properties) / sizeof(*properties), properties); + if (status != napi_ok) return; } NODE_MODULE_ABI(addon, Init) diff --git a/test/addons-abi/test_string/test_string.cc b/test/addons-abi/test_string/test_string.cc index 67b889da22a685..3c0d0812db92a8 100644 --- a/test/addons-abi/test_string/test_string.cc +++ b/test/addons-abi/test_string/test_string.cc @@ -122,10 +122,9 @@ void Init(napi_env env, napi_value exports, napi_value module) { { "Utf8Length", Utf8Length }, }; - for (int i = 0; i < sizeof(properties) / sizeof(*properties); i++) { - status = napi_define_property(env, exports, &properties[i]); - if (status != napi_ok) return; - } + status = napi_define_properties( + env, exports, sizeof(properties) / sizeof(*properties), properties); + if (status != napi_ok) return; } NODE_MODULE_ABI(addon, Init) diff --git a/test/addons-abi/test_symbol/test_symbol.cc b/test/addons-abi/test_symbol/test_symbol.cc index 3f3236c902f420..ee0b4027265d28 100644 --- a/test/addons-abi/test_symbol/test_symbol.cc +++ b/test/addons-abi/test_symbol/test_symbol.cc @@ -87,10 +87,9 @@ void Init(napi_env env, napi_value exports, napi_value module) { { "New", New }, }; - for (int i = 0; i < sizeof(properties) / sizeof(*properties); i++) { - status = napi_define_property(env, exports, &properties[i]); - if (status != napi_ok) return; - } + status = napi_define_properties( + env, exports, sizeof(properties) / sizeof(*properties), properties); + if (status != napi_ok) return; } NODE_MODULE_ABI(addon, Init) diff --git a/test/addons-abi/test_typedarray/test_typedarray.cc b/test/addons-abi/test_typedarray/test_typedarray.cc index d2463af5aa7e00..4e75987b6641ce 100644 --- a/test/addons-abi/test_typedarray/test_typedarray.cc +++ b/test/addons-abi/test_typedarray/test_typedarray.cc @@ -105,10 +105,9 @@ void Init(napi_env env, napi_value exports, napi_value module) { { "Multiply", Multiply }, }; - for (int i = 0; i < sizeof(descriptors) / sizeof(*descriptors); i++) { - status = napi_define_property(env, exports, &descriptors[i]); - if (status != napi_ok) return; - } + status = napi_define_properties( + env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); + if (status != napi_ok) return; } NODE_MODULE_ABI(addon, Init)