2
2
#define CALLBACK_BRIDGE_H
3
3
4
4
#include < vector>
5
- #include < nan.h>
6
5
#include < algorithm>
7
6
#include < uv.h>
8
-
9
- #define COMMA ,
7
+ # include < napi.h >
8
+ #include " common.h "
10
9
11
10
template <typename T, typename L = void *>
12
11
class CallbackBridge {
13
12
public:
14
- CallbackBridge (v8::Local<v8::Function> , bool );
13
+ CallbackBridge (napi_env, napi_value , bool );
15
14
virtual ~CallbackBridge ();
16
15
17
16
// Executes the callback
18
17
T operator ()(std::vector<void *>);
19
18
19
+ // Needed for napi_wrap
20
+ napi_value NewInstance (napi_env env);
21
+
20
22
protected:
21
23
// We will expose a bridge object to the JS callback that wraps this instance so we don't loose context.
22
24
// This is the V8 constructor for such objects.
23
- static Nan::MaybeLocal<v8::Function> get_wrapper_constructor ();
25
+ static napi_ref get_wrapper_constructor (napi_env env );
24
26
static void async_gone (uv_handle_t *handle);
25
- static NAN_METHOD ( New);
26
- static NAN_METHOD ( ReturnCallback);
27
- static Nan::Persistent<v8::Function> wrapper_constructor;
28
- Nan::Persistent<v8::Object> wrapper;
27
+ static napi_value New (napi_env env, napi_callback_info info );
28
+ static napi_value ReturnCallback (napi_env env, napi_callback_info info );
29
+ static napi_ref wrapper_constructor;
30
+ napi_ref wrapper;
29
31
30
32
// The callback that will get called in the main thread after the worker thread used for the sass
31
33
// compilation step makes a call to uv_async_send()
@@ -34,13 +36,16 @@ class CallbackBridge {
34
36
// The V8 values sent to our ReturnCallback must be read on the main thread not the sass worker thread.
35
37
// This gives a chance to specialized subclasses to transform those values into whatever makes sense to
36
38
// sass before we resume the worker thread.
37
- virtual T post_process_return_value (v8::Local<v8::Value> ) const =0;
39
+ virtual T post_process_return_value (napi_env, napi_value ) const = 0;
38
40
39
41
40
- virtual std::vector<v8::Local<v8::Value>> pre_process_args (std::vector<L>) const =0;
42
+ virtual std::vector<napi_value> pre_process_args (napi_env, std::vector<L>) const = 0;
41
43
42
- Nan::Callback* callback;
43
- Nan::AsyncResource* async_resource;
44
+ // ASYNC
45
+ // Nan::AsyncResource* async_resource;
46
+
47
+ napi_env e;
48
+ napi_ref callback;
44
49
bool is_sync;
45
50
46
51
uv_mutex_t cv_mutex;
@@ -52,39 +57,68 @@ class CallbackBridge {
52
57
};
53
58
54
59
template <typename T, typename L>
55
- Nan::Persistent<v8::Function> CallbackBridge<T, L>::wrapper_constructor;
60
+ napi_ref CallbackBridge<T, L>::wrapper_constructor = nullptr ;
61
+
62
+ template <typename T, typename L>
63
+ void CallbackBridge_Destructor (napi_env env, void * obj, void * hint) {
64
+ CallbackBridge<T, L>* bridge = static_cast <CallbackBridge<T, L>*>(obj);
65
+ delete bridge;
66
+ }
67
+
68
+ template <typename T, typename L>
69
+ napi_value CallbackBridge<T, L>::NewInstance(napi_env env) {
70
+ Napi::EscapableHandleScope scope (env);
71
+
72
+ napi_value instance;
73
+ napi_value constructorHandle;
74
+ CHECK_NAPI_RESULT (napi_get_reference_value (env, get_wrapper_constructor (env), &constructorHandle));
75
+ CHECK_NAPI_RESULT (napi_new_instance (env, constructorHandle, 0 , nullptr , &instance));
76
+
77
+ return scope.Escape (instance);
78
+ }
79
+
80
+ template <typename T, typename L>
81
+ napi_value CallbackBridge<T, L>::New(napi_env env, napi_callback_info info) {
82
+ napi_value _this;
83
+ CHECK_NAPI_RESULT (napi_get_cb_info (env, info, nullptr , nullptr , &_this, nullptr ));
84
+ return _this;
85
+ }
56
86
57
87
template <typename T, typename L>
58
- CallbackBridge<T, L>::CallbackBridge(v8::Local<v8::Function> callback, bool is_sync) : callback( new Nan::Callback(callback) ), is_sync(is_sync) {
88
+ CallbackBridge<T, L>::CallbackBridge(napi_env env, napi_value callback, bool is_sync) : e(env ), is_sync(is_sync) {
59
89
/*
60
90
* This is invoked from the main JavaScript thread.
61
91
* V8 context is available.
62
92
*/
63
- Nan::HandleScope scope;
64
93
uv_mutex_init (&this ->cv_mutex );
65
94
uv_cond_init (&this ->condition_variable );
66
95
if (!is_sync) {
67
96
this ->async = new uv_async_t ;
68
97
this ->async ->data = (void *) this ;
69
98
uv_async_init (uv_default_loop (), this ->async , (uv_async_cb) dispatched_async_uv_callback);
70
- this ->async_resource = new Nan::AsyncResource (" node-sass:CallbackBridge" );
99
+ // ASYNC
100
+ // this->async_resource = new Nan::AsyncResource("node-sass:CallbackBridge");
71
101
}
72
102
73
- v8::Local<v8::Function> func = CallbackBridge<T, L>::get_wrapper_constructor ().ToLocalChecked ();
74
- wrapper.Reset (Nan::NewInstance (func).ToLocalChecked ());
75
- Nan::SetInternalFieldPointer (Nan::New (wrapper), 0 , this );
103
+ CHECK_NAPI_RESULT (napi_create_reference (env, callback, 1 , &this ->callback ));
104
+
105
+ napi_value instance = CallbackBridge::NewInstance (env);
106
+ CHECK_NAPI_RESULT (napi_wrap (env, instance, this , CallbackBridge_Destructor<T,L>, nullptr , nullptr ));
107
+ CHECK_NAPI_RESULT (napi_create_reference (env, instance, 1 , &this ->wrapper ));
76
108
}
77
109
78
110
template <typename T, typename L>
79
111
CallbackBridge<T, L>::~CallbackBridge () {
80
- delete this ->callback ;
81
- this ->wrapper .Reset ();
112
+ CHECK_NAPI_RESULT (napi_delete_reference (e, this ->callback ));
113
+ CHECK_NAPI_RESULT (napi_delete_reference (e, this ->wrapper ));
114
+
82
115
uv_cond_destroy (&this ->condition_variable );
83
116
uv_mutex_destroy (&this ->cv_mutex );
84
117
85
118
if (!is_sync) {
86
119
uv_close ((uv_handle_t *)this ->async , &async_gone);
87
- delete this ->async_resource ;
120
+ // ASYNC
121
+ // delete this->async_resource;
88
122
}
89
123
}
90
124
@@ -100,18 +134,32 @@ T CallbackBridge<T, L>::operator()(std::vector<void*> argv) {
100
134
* from types invoked by pre_process_args() and
101
135
* post_process_args().
102
136
*/
103
- Nan::HandleScope scope;
104
- Nan::TryCatch try_catch;
105
- std::vector<v8::Local<v8::Value>> argv_v8 = pre_process_args (argv);
106
- if (try_catch.HasCaught ()) {
107
- Nan::FatalException (try_catch);
137
+ Napi::HandleScope scope (this ->e );
138
+
139
+ std::vector<napi_value> argv_v8 = pre_process_args (this ->e , argv);
140
+
141
+ bool isPending;
142
+ CHECK_NAPI_RESULT (napi_is_exception_pending (this ->e , &isPending));
143
+
144
+ if (isPending) {
145
+ CHECK_NAPI_RESULT (napi_throw_error (this ->e , nullptr , " Error processing arguments" ));
146
+ // This should be a FatalException but we still have to return something, this value might be uninitialized
147
+ return this ->return_value ;
108
148
}
109
149
110
- argv_v8.push_back (Nan::New (wrapper));
150
+ napi_value _this;
151
+ CHECK_NAPI_RESULT (napi_get_reference_value (this ->e , this ->wrapper , &_this));
152
+ argv_v8.push_back (_this);
153
+
154
+ napi_value cb;
155
+ CHECK_NAPI_RESULT (napi_get_reference_value (this ->e , this ->callback , &cb));
156
+ assert (cb != nullptr );
111
157
112
- return this ->post_process_return_value (
113
- Nan::Call (*this ->callback , argv_v8.size (), &argv_v8[0 ]).ToLocalChecked ()
114
- );
158
+ napi_value result;
159
+ // TODO: Is receiver set correctly ?
160
+ CHECK_NAPI_RESULT (napi_make_callback (this ->e , nullptr , _this, cb, argv_v8.size (), &argv_v8[0 ], &result));
161
+
162
+ return this ->post_process_return_value (this ->e , result);
115
163
} else {
116
164
/*
117
165
* This is invoked from the worker thread.
@@ -153,24 +201,46 @@ void CallbackBridge<T, L>::dispatched_async_uv_callback(uv_async_t *req) {
153
201
* from types invoked by pre_process_args() and
154
202
* post_process_args().
155
203
*/
156
- Nan::HandleScope scope;
157
- Nan::TryCatch try_catch;
158
-
159
- std::vector<v8::Local<v8::Value>> argv_v8 = bridge->pre_process_args (bridge->argv );
160
- if (try_catch.HasCaught ()) {
161
- Nan::FatalException (try_catch);
204
+ Napi::HandleScope scope (bridge->e );
205
+ std::vector<napi_value> argv_v8 = bridge->pre_process_args (bridge->e , bridge->argv );
206
+ bool isPending;
207
+
208
+ CHECK_NAPI_RESULT (napi_is_exception_pending (bridge->e , &isPending));
209
+ if (isPending) {
210
+ CHECK_NAPI_RESULT (napi_throw_error (bridge->e , nullptr , " Error processing arguments" ));
211
+ // This should be a FatalException
212
+ return ;
162
213
}
163
- argv_v8.push_back (Nan::New (bridge->wrapper ));
164
214
165
- bridge->callback ->Call (argv_v8.size (), &argv_v8[0 ], bridge->async_resource );
166
-
167
- if (try_catch.HasCaught ()) {
168
- Nan::FatalException (try_catch);
215
+ napi_value _this;
216
+ CHECK_NAPI_RESULT (napi_get_reference_value (bridge->e , bridge->wrapper , &_this));
217
+ argv_v8.push_back (_this);
218
+
219
+ napi_value cb;
220
+ CHECK_NAPI_RESULT (napi_get_reference_value (bridge->e , bridge->callback , &cb));
221
+ assert (cb != nullptr );
222
+
223
+ napi_value result;
224
+ // TODO: Is receiver set correctly ?
225
+ CHECK_NAPI_RESULT (napi_make_callback (bridge->e , nullptr , _this, cb, argv_v8.size (), &argv_v8[0 ], &result));
226
+ CHECK_NAPI_RESULT (napi_is_exception_pending (bridge->e , &isPending));
227
+ if (isPending) {
228
+ CHECK_NAPI_RESULT (napi_throw_error (bridge->e , nullptr , " Error thrown in callback" ));
229
+ // This should be a FatalException
230
+ return ;
169
231
}
170
232
}
171
233
172
234
template <typename T, typename L>
173
- NAN_METHOD (CallbackBridge<T COMMA L>::ReturnCallback) {
235
+ napi_value CallbackBridge<T, L>::ReturnCallback(napi_env env, napi_callback_info info) {
236
+ size_t argc = 1 ;
237
+ napi_value arg;
238
+ napi_value _this;
239
+ CHECK_NAPI_RESULT (napi_get_cb_info (env, info, &argc, &arg, &_this, nullptr ));
240
+
241
+ void * unwrapped;
242
+ CHECK_NAPI_RESULT (napi_unwrap (env, _this, &unwrapped));
243
+ CallbackBridge* bridge = static_cast <CallbackBridge*>(unwrapped);
174
244
175
245
/*
176
246
* Callback function invoked by the user code.
@@ -179,10 +249,7 @@ NAN_METHOD(CallbackBridge<T COMMA L>::ReturnCallback) {
179
249
*
180
250
* Implicit Local<> handle scope created by NAN_METHOD(.)
181
251
*/
182
- CallbackBridge<T, L>* bridge = static_cast <CallbackBridge<T, L>*>(Nan::GetInternalFieldPointer (info.This (), 0 ));
183
- Nan::TryCatch try_catch;
184
-
185
- bridge->return_value = bridge->post_process_return_value (info[0 ]);
252
+ bridge->return_value = bridge->post_process_return_value (env, arg);
186
253
187
254
{
188
255
uv_mutex_lock (&bridge->cv_mutex );
@@ -192,32 +259,30 @@ NAN_METHOD(CallbackBridge<T COMMA L>::ReturnCallback) {
192
259
193
260
uv_cond_broadcast (&bridge->condition_variable );
194
261
195
- if (try_catch.HasCaught ()) {
196
- Nan::FatalException (try_catch);
197
- }
198
- }
262
+ bool isPending;
263
+ CHECK_NAPI_RESULT (napi_is_exception_pending (env, &isPending));
199
264
200
- template <typename T, typename L>
201
- Nan::MaybeLocal<v8::Function> CallbackBridge<T, L>::get_wrapper_constructor() {
202
- /* Uses handle scope created in the CallbackBridge<T, L> constructor */
203
- if (wrapper_constructor.IsEmpty ()) {
204
- v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
205
- tpl->SetClassName (Nan::New (" CallbackBridge" ).ToLocalChecked ());
206
- tpl->InstanceTemplate ()->SetInternalFieldCount (1 );
207
-
208
- Nan::SetPrototypeTemplate (tpl, " success" ,
209
- Nan::New<v8::FunctionTemplate>(ReturnCallback)
210
- );
211
-
212
- wrapper_constructor.Reset (Nan::GetFunction (tpl).ToLocalChecked ());
265
+ if (isPending) {
266
+ // TODO: Call node::FatalException or add napi_fatal_exception ?
267
+ assert (false );
213
268
}
214
269
215
- return Nan::New (wrapper_constructor) ;
270
+ return nullptr ;
216
271
}
217
272
218
273
template <typename T, typename L>
219
- NAN_METHOD (CallbackBridge<T COMMA L>::New) {
220
- info.GetReturnValue ().Set (info.This ());
274
+ napi_ref CallbackBridge<T, L>::get_wrapper_constructor(napi_env env) {
275
+ // TODO: cache wrapper_constructor
276
+
277
+ napi_property_descriptor methods[] = {
278
+ { " success" , nullptr , CallbackBridge::ReturnCallback },
279
+ };
280
+
281
+ napi_value ctor;
282
+ CHECK_NAPI_RESULT (napi_define_class (env, " CallbackBridge" , NAPI_AUTO_LENGTH, CallbackBridge::New, nullptr , 1 , methods, &ctor));
283
+ CHECK_NAPI_RESULT (napi_create_reference (env, ctor, 1 , &wrapper_constructor));
284
+
285
+ return wrapper_constructor;
221
286
}
222
287
223
288
template <typename T, typename L>
0 commit comments