@gjsify/napi 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +203 -0
- package/lib/esm/_virtual/_rolldown/runtime.js +1 -0
- package/lib/esm/index.js +1 -0
- package/lib/types/index.d.ts +25 -0
- package/meson.build +126 -0
- package/package.json +100 -0
- package/prebuilds/linux-x86_64/GjsifyNapi-1.0.gir +19 -0
- package/prebuilds/linux-x86_64/GjsifyNapi-1.0.typelib +0 -0
- package/prebuilds/linux-x86_64/libgjsifynapi.so +0 -0
- package/src/cc/arraybuffer.cc +772 -0
- package/src/cc/async_work.cc +439 -0
- package/src/cc/common.h +519 -0
- package/src/cc/env.cc +262 -0
- package/src/cc/error.cc +300 -0
- package/src/cc/function.cc +358 -0
- package/src/cc/module.cc +625 -0
- package/src/cc/napi.def +22 -0
- package/src/cc/napi.export.map +16 -0
- package/src/cc/napi.exported-symbols.txt +15 -0
- package/src/cc/object.cc +728 -0
- package/src/cc/ref.cc +510 -0
- package/src/cc/stubs.cc +100 -0
- package/src/cc/tsfn.cc +602 -0
- package/src/cc/value.cc +656 -0
- package/src/cc/wrap.cc +321 -0
- package/src/napi-headers/js_native_api.h +639 -0
- package/src/napi-headers/js_native_api_types.h +249 -0
- package/src/napi-headers/node_api.h +270 -0
- package/src/napi-headers/node_api_types.h +63 -0
- package/src/vala/gjs-1.0.vapi +6 -0
- package/src/vala/mozjs-140.vapi +6 -0
- package/src/vala/napi.vala +49 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
// SPDX-License-Identifier: MIT
|
|
2
|
+
// @gjsify/napi — callback trampoline, functions, classes, calls, wrap slice.
|
|
3
|
+
//
|
|
4
|
+
// Reference: refs/node/src/js_native_api_v8.cc (Node.js contributors, MIT) —
|
|
5
|
+
// FunctionCallbackWrapper (cc:424-523), napi_create_function (cc:944-968),
|
|
6
|
+
// napi_define_class (cc:970-1064), napi_get_cb_info (cc:2133-2162),
|
|
7
|
+
// napi_get_new_target (cc:2164-2176 + GetNewTarget cc:502-509),
|
|
8
|
+
// napi_call_function (cc:2178-2208), napi_new_instance (cc:3004-3030),
|
|
9
|
+
// napi_wrap/unwrap/remove_wrap (cc:339-374, 525-586). Natives-with-data via
|
|
10
|
+
// js::NewFunctionWithReserved follow GJS's own pattern
|
|
11
|
+
// (refs/gjs/gjs/jsapi-dynamic-class.cpp:152-159; GNOME contributors,
|
|
12
|
+
// MIT/LGPLv2+). `JS_New` is gone in mozjs-140 — construction goes through
|
|
13
|
+
// JS::Construct (js/CallAndConstruct.h:125).
|
|
14
|
+
|
|
15
|
+
#include "common.h"
|
|
16
|
+
|
|
17
|
+
#include <algorithm>
|
|
18
|
+
|
|
19
|
+
namespace gjsify_napi {
|
|
20
|
+
|
|
21
|
+
JSObject* new_bundle_function(napi_env env, const char* utf8name,
|
|
22
|
+
size_t length, napi_callback cb, void* data,
|
|
23
|
+
unsigned flags, bool construct_as_class) {
|
|
24
|
+
std::string name;
|
|
25
|
+
if (utf8name != nullptr) {
|
|
26
|
+
name = (length == NAPI_AUTO_LENGTH) ? std::string(utf8name)
|
|
27
|
+
: std::string(utf8name, length);
|
|
28
|
+
}
|
|
29
|
+
auto* bundle = new CallbackBundle{env, cb, data, construct_as_class};
|
|
30
|
+
JSFunction* fn = js::NewFunctionWithReserved(
|
|
31
|
+
env->cx, function_trampoline, 0, flags, name.c_str());
|
|
32
|
+
if (fn == nullptr) {
|
|
33
|
+
delete bundle;
|
|
34
|
+
return nullptr;
|
|
35
|
+
}
|
|
36
|
+
JSObject* fn_obj = JS_GetFunctionObject(fn);
|
|
37
|
+
js::SetFunctionNativeReserved(fn_obj, 0, JS::PrivateValue(bundle));
|
|
38
|
+
|
|
39
|
+
// A plain napi function (napi_create_function or a napi_define_properties
|
|
40
|
+
// method) is constructible and, like every V8 function Node hands back,
|
|
41
|
+
// owns a `.prototype` object — SpiderMonkey natives get none, so `new fn()`
|
|
42
|
+
// and `class X extends fn` (test_new_target) would fault on a missing/
|
|
43
|
+
// undefined prototype. Give it the standard function-prototype shape
|
|
44
|
+
// (writable, non-enumerable, non-configurable) plus the `.constructor`
|
|
45
|
+
// back-reference. napi_define_class (construct_as_class) is skipped: it
|
|
46
|
+
// wires its own ctor.prototype ↔ proto.constructor pair afterwards.
|
|
47
|
+
if ((flags & JSFUN_CONSTRUCTOR) && !construct_as_class) {
|
|
48
|
+
JS::RootedObject fn_rooted(env->cx, fn_obj);
|
|
49
|
+
JS::RootedObject proto(env->cx, JS_NewPlainObject(env->cx));
|
|
50
|
+
if (proto == nullptr ||
|
|
51
|
+
!JS_DefineProperty(env->cx, fn_rooted, "prototype", proto,
|
|
52
|
+
JSPROP_PERMANENT) ||
|
|
53
|
+
!JS_DefineProperty(env->cx, proto, "constructor", fn_rooted, 0)) {
|
|
54
|
+
delete bundle;
|
|
55
|
+
return nullptr;
|
|
56
|
+
}
|
|
57
|
+
env->bundles.push_back(bundle);
|
|
58
|
+
return fn_rooted;
|
|
59
|
+
}
|
|
60
|
+
env->bundles.push_back(bundle);
|
|
61
|
+
return fn_obj;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// The shared JSNative every napi-created function dispatches through
|
|
65
|
+
// (V8-Node's FunctionCallbackWrapper analog). Opens a handle scope around the
|
|
66
|
+
// napi callback, boxes args/this into scope-bound arena slots, applies the §6
|
|
67
|
+
// trampoline exit rule: pending exception ⇒ return false (SpiderMonkey
|
|
68
|
+
// propagates the already-set pending exception — no rethrow step), else set
|
|
69
|
+
// rval and return true.
|
|
70
|
+
bool function_trampoline(JSContext* cx, unsigned argc, JS::Value* vp) {
|
|
71
|
+
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
|
72
|
+
const JS::Value bundle_val =
|
|
73
|
+
js::GetFunctionNativeReserved(&args.callee(), 0);
|
|
74
|
+
auto* bundle = static_cast<CallbackBundle*>(bundle_val.toPrivate());
|
|
75
|
+
napi_env env = bundle->env;
|
|
76
|
+
// Early-teardown guard: bundles outlive teardown() (freed only in the
|
|
77
|
+
// env destructor at context dispose), so this dereference is safe and a
|
|
78
|
+
// call into a torn-down addon env fails as a JS error, not a UAF.
|
|
79
|
+
if (env->torn_down) {
|
|
80
|
+
JS_ReportErrorUTF8(
|
|
81
|
+
cx, "gjsify-napi: addon environment has been torn down");
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
napi_handle_scope scope = nullptr;
|
|
86
|
+
if (napi_open_handle_scope(env, &scope) != napi_ok) {
|
|
87
|
+
JS_ReportErrorUTF8(cx, "gjsify-napi: failed to open handle scope");
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
std::vector<napi_value> argv(args.length());
|
|
92
|
+
for (unsigned i = 0; i < args.length(); i++) {
|
|
93
|
+
argv[i] = arena_push(env, args[i]);
|
|
94
|
+
}
|
|
95
|
+
CallbackInfo info;
|
|
96
|
+
info.argv = argv.data();
|
|
97
|
+
info.argc = args.length();
|
|
98
|
+
info.data = bundle->data;
|
|
99
|
+
|
|
100
|
+
// `this` construction. SM natives get no auto-created instance, so the
|
|
101
|
+
// constructor path builds one from new.target.prototype (V8 semantics);
|
|
102
|
+
// class instances use the fast-tier JSClass (§5d).
|
|
103
|
+
JS::RootedObject constructed_this(cx);
|
|
104
|
+
if (args.isConstructing()) {
|
|
105
|
+
JS::RootedObject new_target(cx, &args.newTarget().toObject());
|
|
106
|
+
JS::RootedValue proto_v(cx);
|
|
107
|
+
if (!JS_GetProperty(cx, new_target, "prototype", &proto_v)) {
|
|
108
|
+
napi_close_handle_scope(env, scope);
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
JS::RootedObject proto(
|
|
112
|
+
cx, proto_v.isObject() ? &proto_v.toObject() : nullptr);
|
|
113
|
+
constructed_this = JS_NewObjectWithGivenProto(
|
|
114
|
+
cx, bundle->construct_as_class ? &instance_class : nullptr, proto);
|
|
115
|
+
if (!constructed_this) {
|
|
116
|
+
napi_close_handle_scope(env, scope);
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
info.this_arg = arena_push(env, JS::ObjectValue(*constructed_this));
|
|
120
|
+
info.new_target = arena_push(env, args.newTarget());
|
|
121
|
+
} else {
|
|
122
|
+
// v8::FunctionCallbackInfo::This() parity: undefined/null receiver
|
|
123
|
+
// (sloppy call) → the global proxy; primitive receivers are boxed.
|
|
124
|
+
JS::RootedValue thisv(cx, args.thisv());
|
|
125
|
+
if (thisv.isNullOrUndefined()) {
|
|
126
|
+
thisv = JS::ObjectValue(*env->global);
|
|
127
|
+
} else if (!thisv.isObject()) {
|
|
128
|
+
JSObject* boxed = JS::ToObject(cx, thisv);
|
|
129
|
+
if (boxed == nullptr) {
|
|
130
|
+
napi_close_handle_scope(env, scope);
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
thisv = JS::ObjectValue(*boxed);
|
|
134
|
+
}
|
|
135
|
+
info.this_arg = arena_push(env, thisv);
|
|
136
|
+
info.new_target = nullptr;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
napi_value result =
|
|
140
|
+
bundle->cb(env, reinterpret_cast<napi_callback_info>(&info));
|
|
141
|
+
|
|
142
|
+
const bool pending = JS_IsExceptionPending(cx);
|
|
143
|
+
if (!pending) {
|
|
144
|
+
// Read results BEFORE closing the scope (closing releases the arena
|
|
145
|
+
// slots); args.rval() is rooted by the JS stack.
|
|
146
|
+
if (args.isConstructing()) {
|
|
147
|
+
// Construction result: the callback's returned object if it is
|
|
148
|
+
// one, else the created `this` (V8 semantics).
|
|
149
|
+
const JS::Value ret =
|
|
150
|
+
result != nullptr ? napi_value_to_js(result) : JS::Value();
|
|
151
|
+
args.rval().setObject(ret.isObject() ? ret.toObject()
|
|
152
|
+
: *constructed_this);
|
|
153
|
+
} else {
|
|
154
|
+
args.rval().set(result != nullptr ? napi_value_to_js(result)
|
|
155
|
+
: JS::UndefinedValue());
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// Balance check: our scope must still be the top one. An imbalanced
|
|
159
|
+
// callback is a fatal error in Node (CallIntoModule handle_exception);
|
|
160
|
+
// match that hard stance.
|
|
161
|
+
if (napi_close_handle_scope(env, scope) != napi_ok) {
|
|
162
|
+
napi_fatal_error("gjsify_napi::function_trampoline", NAPI_AUTO_LENGTH,
|
|
163
|
+
"handle scope imbalance after native callback",
|
|
164
|
+
NAPI_AUTO_LENGTH);
|
|
165
|
+
}
|
|
166
|
+
return !pending;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
} // namespace gjsify_napi
|
|
170
|
+
|
|
171
|
+
napi_status NAPI_CDECL napi_create_function(napi_env env, const char* utf8name,
|
|
172
|
+
size_t length, napi_callback cb,
|
|
173
|
+
void* callback_data,
|
|
174
|
+
napi_value* result) {
|
|
175
|
+
GJSIFY_NAPI_PREAMBLE(env);
|
|
176
|
+
GJSIFY_NAPI_CHECK_ARG(env, result);
|
|
177
|
+
GJSIFY_NAPI_CHECK_ARG(env, cb);
|
|
178
|
+
// JSFUN_CONSTRUCTOR (jsapi.h:540): napi functions are constructible
|
|
179
|
+
// (V8 FunctionTemplate default) — without it `new fn()` throws in SM.
|
|
180
|
+
JSObject* fn_obj = gjsify_napi::new_bundle_function(
|
|
181
|
+
env, utf8name, length, cb, callback_data, JSFUN_CONSTRUCTOR,
|
|
182
|
+
/* construct_as_class = */ false);
|
|
183
|
+
if (fn_obj == nullptr) {
|
|
184
|
+
return gjsify_napi::set_last_error(env, napi_generic_failure);
|
|
185
|
+
}
|
|
186
|
+
*result = gjsify_napi::arena_push(env, JS::ObjectValue(*fn_obj));
|
|
187
|
+
return napi_ok; // preamble already cleared last_error
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
napi_status NAPI_CDECL napi_get_cb_info(napi_env env, napi_callback_info cbinfo,
|
|
191
|
+
size_t* argc, napi_value* argv,
|
|
192
|
+
napi_value* this_arg, void** data) {
|
|
193
|
+
GJSIFY_NAPI_CHECK_ENV(env);
|
|
194
|
+
GJSIFY_NAPI_CHECK_ARG(env, cbinfo);
|
|
195
|
+
auto* info = reinterpret_cast<gjsify_napi::CallbackInfo*>(cbinfo);
|
|
196
|
+
|
|
197
|
+
if (argv != nullptr) {
|
|
198
|
+
GJSIFY_NAPI_CHECK_ARG(env, argc);
|
|
199
|
+
const size_t provided = std::min(*argc, info->argc);
|
|
200
|
+
std::copy(info->argv, info->argv + provided, argv);
|
|
201
|
+
if (provided < *argc) {
|
|
202
|
+
// Pad missing arguments with undefined (cc:2146-2153).
|
|
203
|
+
napi_value undefined =
|
|
204
|
+
gjsify_napi::arena_push(env, JS::UndefinedValue());
|
|
205
|
+
std::fill(argv + provided, argv + *argc, undefined);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (argc != nullptr) {
|
|
209
|
+
*argc = info->argc;
|
|
210
|
+
}
|
|
211
|
+
if (this_arg != nullptr) {
|
|
212
|
+
*this_arg = info->this_arg;
|
|
213
|
+
}
|
|
214
|
+
if (data != nullptr) {
|
|
215
|
+
*data = info->data;
|
|
216
|
+
}
|
|
217
|
+
return gjsify_napi::clear_last_error(env);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
napi_status NAPI_CDECL napi_get_new_target(napi_env env,
|
|
221
|
+
napi_callback_info cbinfo,
|
|
222
|
+
napi_value* result) {
|
|
223
|
+
GJSIFY_NAPI_CHECK_ENV(env);
|
|
224
|
+
GJSIFY_NAPI_CHECK_ARG(env, cbinfo);
|
|
225
|
+
GJSIFY_NAPI_CHECK_ARG(env, result);
|
|
226
|
+
auto* info = reinterpret_cast<gjsify_napi::CallbackInfo*>(cbinfo);
|
|
227
|
+
// nullptr when not constructing (GetNewTarget, cc:502-509).
|
|
228
|
+
*result = info->new_target;
|
|
229
|
+
return gjsify_napi::clear_last_error(env);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
napi_status NAPI_CDECL napi_call_function(napi_env env, napi_value recv,
|
|
233
|
+
napi_value func, size_t argc,
|
|
234
|
+
const napi_value* argv,
|
|
235
|
+
napi_value* result) {
|
|
236
|
+
GJSIFY_NAPI_PREAMBLE(env);
|
|
237
|
+
GJSIFY_NAPI_CHECK_ARG(env, recv);
|
|
238
|
+
GJSIFY_NAPI_CHECK_ARG(env, func);
|
|
239
|
+
if (argc > 0) {
|
|
240
|
+
GJSIFY_NAPI_CHECK_ARG(env, argv);
|
|
241
|
+
}
|
|
242
|
+
JS::Value fn_v = gjsify_napi::napi_value_to_js(func);
|
|
243
|
+
GJSIFY_NAPI_RETURN_STATUS_IF_FALSE(
|
|
244
|
+
env, fn_v.isObject() && JS::IsCallable(&fn_v.toObject()),
|
|
245
|
+
napi_function_expected);
|
|
246
|
+
|
|
247
|
+
// Rooted contiguous copy of the arguments: the arena slots themselves
|
|
248
|
+
// are traced, but HandleValueArray needs contiguous rooted storage.
|
|
249
|
+
JS::RootedVector<JS::Value> call_args(env->cx);
|
|
250
|
+
for (size_t i = 0; i < argc; i++) {
|
|
251
|
+
GJSIFY_NAPI_CHECK_ARG(env, argv[i]);
|
|
252
|
+
if (!call_args.append(gjsify_napi::napi_value_to_js(argv[i]))) {
|
|
253
|
+
return gjsify_napi::set_last_error(env, napi_generic_failure);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
JS::RootedValue this_v(env->cx, gjsify_napi::napi_value_to_js(recv));
|
|
257
|
+
JS::RootedValue fn_rooted(env->cx, fn_v);
|
|
258
|
+
JS::RootedValue rval(env->cx);
|
|
259
|
+
if (!JS::Call(env->cx, this_v, fn_rooted, JS::HandleValueArray(call_args),
|
|
260
|
+
&rval)) {
|
|
261
|
+
// §6 must-not-abort contract: a JS throw (ANY value, including
|
|
262
|
+
// null/undefined) stays pending and is never normalized; a false
|
|
263
|
+
// return WITHOUT a pending exception (OOM/over-recursion — SM's
|
|
264
|
+
// analog of V8 termination) is napi_generic_failure, never a crash.
|
|
265
|
+
return gjsify_napi::set_last_error(
|
|
266
|
+
env, JS_IsExceptionPending(env->cx) ? napi_pending_exception
|
|
267
|
+
: napi_generic_failure);
|
|
268
|
+
}
|
|
269
|
+
if (result != nullptr) {
|
|
270
|
+
*result = gjsify_napi::arena_push(env, rval);
|
|
271
|
+
}
|
|
272
|
+
return napi_ok;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
napi_status NAPI_CDECL napi_new_instance(napi_env env, napi_value constructor,
|
|
276
|
+
size_t argc, const napi_value* argv,
|
|
277
|
+
napi_value* result) {
|
|
278
|
+
GJSIFY_NAPI_PREAMBLE(env);
|
|
279
|
+
GJSIFY_NAPI_CHECK_ARG(env, constructor);
|
|
280
|
+
if (argc > 0) {
|
|
281
|
+
GJSIFY_NAPI_CHECK_ARG(env, argv);
|
|
282
|
+
}
|
|
283
|
+
GJSIFY_NAPI_CHECK_ARG(env, result);
|
|
284
|
+
JS::Value ctor_v = gjsify_napi::napi_value_to_js(constructor);
|
|
285
|
+
GJSIFY_NAPI_RETURN_STATUS_IF_FALSE(
|
|
286
|
+
env, ctor_v.isObject() && JS::IsCallable(&ctor_v.toObject()),
|
|
287
|
+
napi_function_expected);
|
|
288
|
+
|
|
289
|
+
JS::RootedVector<JS::Value> call_args(env->cx);
|
|
290
|
+
for (size_t i = 0; i < argc; i++) {
|
|
291
|
+
GJSIFY_NAPI_CHECK_ARG(env, argv[i]);
|
|
292
|
+
if (!call_args.append(gjsify_napi::napi_value_to_js(argv[i]))) {
|
|
293
|
+
return gjsify_napi::set_last_error(env, napi_generic_failure);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
JS::RootedValue ctor_rooted(env->cx, ctor_v);
|
|
297
|
+
JS::RootedObject instance(env->cx);
|
|
298
|
+
// JS_New is gone in mozjs-140; JS::Construct implements [[Construct]].
|
|
299
|
+
if (!JS::Construct(env->cx, ctor_rooted, JS::HandleValueArray(call_args),
|
|
300
|
+
&instance)) {
|
|
301
|
+
return gjsify_napi::set_last_error(
|
|
302
|
+
env, JS_IsExceptionPending(env->cx) ? napi_pending_exception
|
|
303
|
+
: napi_generic_failure);
|
|
304
|
+
}
|
|
305
|
+
*result = gjsify_napi::arena_push(env, JS::ObjectValue(*instance));
|
|
306
|
+
return napi_ok;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
napi_status NAPI_CDECL napi_define_class(
|
|
310
|
+
napi_env env, const char* utf8name, size_t length,
|
|
311
|
+
napi_callback constructor, void* callback_data, size_t property_count,
|
|
312
|
+
const napi_property_descriptor* properties, napi_value* result) {
|
|
313
|
+
GJSIFY_NAPI_PREAMBLE(env);
|
|
314
|
+
GJSIFY_NAPI_CHECK_ARG(env, result);
|
|
315
|
+
GJSIFY_NAPI_CHECK_ARG(env, constructor);
|
|
316
|
+
GJSIFY_NAPI_CHECK_ARG(env, utf8name);
|
|
317
|
+
if (property_count > 0) {
|
|
318
|
+
GJSIFY_NAPI_CHECK_ARG(env, properties);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
JS::RootedObject ctor_obj(
|
|
322
|
+
env->cx,
|
|
323
|
+
gjsify_napi::new_bundle_function(env, utf8name, length, constructor,
|
|
324
|
+
callback_data, JSFUN_CONSTRUCTOR,
|
|
325
|
+
/* construct_as_class = */ true));
|
|
326
|
+
if (!ctor_obj) {
|
|
327
|
+
return gjsify_napi::set_last_error(env, napi_generic_failure);
|
|
328
|
+
}
|
|
329
|
+
JS::RootedObject proto(env->cx, JS_NewPlainObject(env->cx));
|
|
330
|
+
if (!proto) {
|
|
331
|
+
return gjsify_napi::set_last_error(env, napi_generic_failure);
|
|
332
|
+
}
|
|
333
|
+
// Wire ctor.prototype ↔ proto.constructor like a normal JS function:
|
|
334
|
+
// prototype = writable, non-enumerable, non-configurable; constructor =
|
|
335
|
+
// writable, non-enumerable, configurable.
|
|
336
|
+
if (!JS_DefineProperty(env->cx, ctor_obj, "prototype", proto,
|
|
337
|
+
JSPROP_PERMANENT) ||
|
|
338
|
+
!JS_DefineProperty(env->cx, proto, "constructor", ctor_obj, 0)) {
|
|
339
|
+
return gjsify_napi::set_last_error(env, napi_generic_failure);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// Non-static descriptors go on the prototype, napi_static ones on the
|
|
343
|
+
// constructor (cc:1048-1061), through the napi_define_properties path.
|
|
344
|
+
for (size_t i = 0; i < property_count; i++) {
|
|
345
|
+
const napi_property_descriptor& p = properties[i];
|
|
346
|
+
JS::RootedObject target(env->cx, (p.attributes & napi_static)
|
|
347
|
+
? ctor_obj.get()
|
|
348
|
+
: proto.get());
|
|
349
|
+
napi_status status =
|
|
350
|
+
gjsify_napi::apply_property_descriptor(env, target, p);
|
|
351
|
+
if (status != napi_ok) {
|
|
352
|
+
return status; // last_error already set
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
*result = gjsify_napi::arena_push(env, JS::ObjectValue(*ctor_obj));
|
|
357
|
+
return napi_ok;
|
|
358
|
+
}
|