What is the best way to inherit from EventTarget on the native side? #35870
Replies: 5 comments 8 replies
-
During bootstrap, we could pass a reference to the |
Beta Was this translation helpful? Give feedback.
-
Ok, #36088 will get us part of the way there. It stores references to the |
Beta Was this translation helpful? Give feedback.
-
I wonder if the implementation of a WebIDL interface can be done in a way similar to how https://github.com/jsdom/webidl2js works - generating JS code that defines classes, whose methods call into native bindings with whatever arguments specified in the definition (and maybe generate the argument unwrapping too), instead of generating native code that define such classes. The implementation is still mostly done in C/C++ but it seems easier (and more readable) to just generate the glue in JS. |
Beta Was this translation helpful? Give feedback.
-
@gabrielschulhof .. as far as n-api support is concerned, what are you imagining? We can easily have an API like the following: napi_status napi_create_eventtarget(napi_env env, napi_value* result);
napi_status napi_create_event(napi_env, napi_value name, napi_value* result);
napi_status napi_eventtarget_dispatch(napi_env env, napi_value eventarget, napi_value event);
napi_status napi_eventtarget_addlistener(napi_env, napi_value eventarget, napi_value name, napi_value handler, napi_value options);
napi_status napi_eventtarget_removelistener(napi_env, napi_value eventtarget, napi_value name, napi_value handler); Which could allow creating instances of
|
Beta Was this translation helpful? Give feedback.
-
Here's a harebrained scheme^W^Wpossible implementation of generic inheritance: static napi_status napi_define_subclass(napi_env env,
napi_value parent_ctor,
const char* name,
size_t length,
napi_callback ctor,
napi_callback native_getSuperParams,
size_t n_props,
napi_property_descriptor* props,
void* data,
napi_value* child_ctor) {
std::string formal_args_remainder;
std::string class_body;
std::string key;
std::string propname;
size_t idx, n_params;
for (idx = 0, n_params = 0; idx < n_props; idx++) {
if (!(props[idx].attributes & napi_static)) {
if (props[idx].name != nullptr) {
propname = "prop" + std::to_string(n_params++);
formal_args_remainder += ", " + propname;
key = "[" + propname + "]";
} else {
key = std::string(props[idx].utf8name);
}
if (props[idx].value != nullptr) {
propname = "prop" + std::to_string(n_params++);
formal_args_remainder += ", " + propname;
class_body += " " + key + " = " + propname + ";\n";
} else if (props[idx].method != nullptr) {
propname = "prop" + std::to_string(n_params++);
formal_args_remainder += ", " + propname;
class_body += " " + key + "() { return " + propname +
".apply(this, arguments); }\n";
} else {
if (props[idx].getter != nullptr) {
propname = "prop" + std::to_string(n_params++);
formal_args_remainder += ", " + propname;
class_body += " get " + key + "() { return " + propname +
".apply(this, arguments); }\n";
}
if (props[idx].setter != nullptr) {
propname = "prop" + std::to_string(n_params++);
formal_args_remainder += ", " + propname;
class_body += " set " + key + "(x) { return " + propname +
".apply(this, arguments); }\n";
}
}
}
}
std::string str =
"(function(parent, ctor, getSuperParams" + formal_args_remainder + ") {\n"
" class " + name + " extends parent {\n"
" constructor(){\n"
" super(...getSuperParams(arguments));\n"
" ctor.apply(this, arguments);\n"
" }\n"
+ class_body +
" }\n"
" return " + name + ";\n"
"})";
napi_value call_args[n_params + 3];
call_args[0] = parent_ctor;
NAPI_CALL(napi_create_function(env, name, length, ctor, data, &call_args[1]));
NAPI_CALL(napi_create_function(env,
name,
length,
native_getSuperParams,
data,
&call_args[2]));
for (idx = 0, n_params = 3; idx < n_props; idx++) {
if (!(props[idx].attributes & napi_static)) {
if (props[idx].name != nullptr) {
call_args[n_params++] = props[idx].name;
}
if (props[idx].value != nullptr) {
call_args[n_params++] = props[idx].value;
} else if (props[idx].method != nullptr) {
napi_value method;
NAPI_CALL(napi_create_function(env,
props[idx].utf8name,
NAPI_AUTO_LENGTH,
props[idx].method,
props[idx].data,
&method));
call_args[n_params++] = method;
} else {
if (props[idx].getter != nullptr) {
napi_value getter;
NAPI_CALL(napi_create_function(env,
props[idx].utf8name,
NAPI_AUTO_LENGTH,
props[idx].getter,
props[idx].data,
&getter));
call_args[n_params++] = getter;
}
if (props[idx].setter != nullptr) {
napi_value setter;
NAPI_CALL(napi_create_function(env,
props[idx].utf8name,
NAPI_AUTO_LENGTH,
props[idx].setter,
props[idx].data,
&setter));
call_args[n_params++] = setter;
}
}
}
}
napi_value js_str;
NAPI_CALL(napi_create_string_utf8(env,
str.c_str(),
NAPI_AUTO_LENGTH,
&js_str));
napi_value fn;
NAPI_CALL(napi_run_script(env, js_str, &fn));
napi_value result;
NAPI_CALL(napi_call_function(env,
fn,
fn,
sizeof(call_args) / sizeof(*call_args),
call_args,
&result));
for (idx = 0; idx < n_props; idx++)
if (props[idx].attributes & napi_static)
NAPI_CALL(napi_define_properties(env, result, 1, &props[idx]));
*child_ctor = result;
return napi_ok;
} |
Beta Was this translation helpful? Give feedback.
-
As I work on https://github.com/nodejs/webidl-napi I see that some of the interfaces described in webgpu.idl extend
EventTarget
. We now haveEventTarget
in Node.js. So, are there some links that point me to how to use it from a native add-on? I don't think I can inherit from it outright except via prototype assignment.Looking at https://www.nearform.com/blog/node-js-and-the-struggles-of-being-an-eventtarget/ so far.
Beta Was this translation helpful? Give feedback.
All reactions