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 " common.h "
8
+ #include < napi.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;
40
+
38
41
42
+ virtual std::vector<napi_value> pre_process_args (napi_env, std::vector<L>) const = 0;
39
43
40
- virtual std::vector<v8::Local<v8::Value>> pre_process_args (std::vector<L>) const =0;
44
+ // ASYNC
45
+ // Nan::AsyncResource* async_resource;
41
46
42
- Nan::Callback* callback ;
43
- Nan::AsyncResource* async_resource ;
47
+ napi_env e ;
48
+ napi_ref callback ;
44
49
bool is_sync;
45
50
46
51
uv_mutex_t cv_mutex;
@@ -52,45 +57,57 @@ 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
+ napi_value CallbackBridge<T, L>::NewInstance(napi_env env) {
64
+ Napi::EscapableHandleScope scope (env);
65
+
66
+ napi_value instance;
67
+ napi_value constructorHandle;
68
+ CHECK_NAPI_RESULT (napi_get_reference_value (env, get_wrapper_constructor (env), &constructorHandle));
69
+ CHECK_NAPI_RESULT (napi_new_instance (env, constructorHandle, 0 , nullptr , &instance));
70
+
71
+ return scope.Escape (instance);
72
+ }
56
73
57
74
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) {
75
+ CallbackBridge<T, L>::CallbackBridge(napi_env env, napi_value callback, bool is_sync) : e(env ), is_sync(is_sync) {
59
76
/*
60
77
* This is invoked from the main JavaScript thread.
61
78
* V8 context is available.
62
79
*/
63
- Nan ::HandleScope scope;
80
+ Napi ::HandleScope scope ( this -> e ) ;
64
81
uv_mutex_init (&this ->cv_mutex );
65
82
uv_cond_init (&this ->condition_variable );
66
83
if (!is_sync) {
67
84
this ->async = new uv_async_t ;
68
85
this ->async ->data = (void *) this ;
69
86
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" );
71
87
}
72
88
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 );
89
+ CHECK_NAPI_RESULT (napi_create_reference (env, callback, 1 , &this ->callback ));
90
+
91
+ napi_value instance = CallbackBridge::NewInstance (env);
92
+ CHECK_NAPI_RESULT (napi_wrap (env, instance, this , nullptr , nullptr , nullptr ));
93
+ CHECK_NAPI_RESULT (napi_create_reference (env, instance, 1 , &this ->wrapper ));
76
94
}
77
95
78
96
template <typename T, typename L>
79
97
CallbackBridge<T, L>::~CallbackBridge () {
80
- delete this ->callback ;
81
- this ->wrapper .Reset ();
98
+ CHECK_NAPI_RESULT (napi_delete_reference (e, this ->callback ));
99
+ CHECK_NAPI_RESULT (napi_delete_reference (e, this ->wrapper ));
100
+
82
101
uv_cond_destroy (&this ->condition_variable );
83
102
uv_mutex_destroy (&this ->cv_mutex );
84
103
85
104
if (!is_sync) {
86
105
uv_close ((uv_handle_t *)this ->async , &async_gone);
87
- delete this ->async_resource ;
88
106
}
89
107
}
90
108
91
109
template <typename T, typename L>
92
110
T CallbackBridge<T, L>::operator ()(std::vector<void *> argv) {
93
- // argv.push_back(wrapper);
94
111
if (this ->is_sync ) {
95
112
/*
96
113
* This is invoked from the main JavaScript thread.
@@ -100,18 +117,32 @@ T CallbackBridge<T, L>::operator()(std::vector<void*> argv) {
100
117
* from types invoked by pre_process_args() and
101
118
* post_process_args().
102
119
*/
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);
120
+ Napi::HandleScope scope (this ->e );
121
+
122
+ std::vector<napi_value> argv_v8 = pre_process_args (this ->e , argv);
123
+
124
+ bool isPending;
125
+ CHECK_NAPI_RESULT (napi_is_exception_pending (this ->e , &isPending));
126
+
127
+ if (isPending) {
128
+ CHECK_NAPI_RESULT (napi_throw_error (this ->e , nullptr , " Error processing arguments" ));
129
+ // This should be a FatalException but we still have to return something, this value might be uninitialized
130
+ return this ->return_value ;
108
131
}
109
132
110
- argv_v8.push_back (Nan::New (wrapper));
133
+ napi_value _this;
134
+ CHECK_NAPI_RESULT (napi_get_reference_value (this ->e , this ->wrapper , &_this));
135
+ argv_v8.push_back (_this);
136
+
137
+ napi_value cb;
138
+ CHECK_NAPI_RESULT (napi_get_reference_value (this ->e , this ->callback , &cb));
139
+ assert (cb != nullptr );
140
+
141
+ napi_value result;
142
+ // TODO: Is receiver set correctly ?
143
+ CHECK_NAPI_RESULT (napi_make_callback (this ->e , nullptr , _this, cb, argv_v8.size (), &argv_v8[0 ], &result));
111
144
112
- return this ->post_process_return_value (
113
- Nan::Call (*this ->callback , argv_v8.size (), &argv_v8[0 ]).ToLocalChecked ()
114
- );
145
+ return this ->post_process_return_value (this ->e , result);
115
146
} else {
116
147
/*
117
148
* This is invoked from the worker thread.
@@ -153,24 +184,46 @@ void CallbackBridge<T, L>::dispatched_async_uv_callback(uv_async_t *req) {
153
184
* from types invoked by pre_process_args() and
154
185
* post_process_args().
155
186
*/
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);
187
+ Napi::HandleScope scope (bridge->e );
188
+ std::vector<napi_value> argv_v8 = bridge->pre_process_args (bridge->e , bridge->argv );
189
+ bool isPending;
190
+
191
+ CHECK_NAPI_RESULT (napi_is_exception_pending (bridge->e , &isPending));
192
+ if (isPending) {
193
+ CHECK_NAPI_RESULT (napi_throw_error (bridge->e , nullptr , " Error processing arguments" ));
194
+ // This should be a FatalException
195
+ return ;
162
196
}
163
- argv_v8.push_back (Nan::New (bridge->wrapper ));
164
-
165
- bridge->callback ->Call (argv_v8.size (), &argv_v8[0 ], bridge->async_resource );
166
197
167
- if (try_catch.HasCaught ()) {
168
- Nan::FatalException (try_catch);
198
+ napi_value _this;
199
+ CHECK_NAPI_RESULT (napi_get_reference_value (bridge->e , bridge->wrapper , &_this));
200
+ argv_v8.push_back (_this);
201
+
202
+ napi_value cb;
203
+ CHECK_NAPI_RESULT (napi_get_reference_value (bridge->e , bridge->callback , &cb));
204
+ assert (cb != nullptr );
205
+
206
+ napi_value result;
207
+ // TODO: Is receiver set correctly ?
208
+ CHECK_NAPI_RESULT (napi_make_callback (bridge->e , nullptr , _this, cb, argv_v8.size (), &argv_v8[0 ], &result));
209
+ CHECK_NAPI_RESULT (napi_is_exception_pending (bridge->e , &isPending));
210
+ if (isPending) {
211
+ CHECK_NAPI_RESULT (napi_throw_error (bridge->e , nullptr , " Error thrown in callback" ));
212
+ // This should be a FatalException
213
+ return ;
169
214
}
170
215
}
171
216
172
217
template <typename T, typename L>
173
- NAN_METHOD (CallbackBridge<T COMMA L>::ReturnCallback) {
218
+ napi_value CallbackBridge<T, L>::ReturnCallback(napi_env env, napi_callback_info info) {
219
+ size_t argc = 1 ;
220
+ napi_value arg;
221
+ napi_value _this;
222
+ CHECK_NAPI_RESULT (napi_get_cb_info (env, info, &argc, &arg, &_this, nullptr ));
223
+
224
+ void * unwrapped;
225
+ CHECK_NAPI_RESULT (napi_unwrap (env, _this, &unwrapped));
226
+ CallbackBridge* bridge = static_cast <CallbackBridge*>(unwrapped);
174
227
175
228
/*
176
229
* Callback function invoked by the user code.
@@ -179,10 +232,7 @@ NAN_METHOD(CallbackBridge<T COMMA L>::ReturnCallback) {
179
232
*
180
233
* Implicit Local<> handle scope created by NAN_METHOD(.)
181
234
*/
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 ]);
235
+ bridge->return_value = bridge->post_process_return_value (env, arg);
186
236
187
237
{
188
238
uv_mutex_lock (&bridge->cv_mutex );
@@ -192,32 +242,38 @@ NAN_METHOD(CallbackBridge<T COMMA L>::ReturnCallback) {
192
242
193
243
uv_cond_broadcast (&bridge->condition_variable );
194
244
195
- if (try_catch.HasCaught ()) {
196
- Nan::FatalException (try_catch);
245
+ bool isPending;
246
+ CHECK_NAPI_RESULT (napi_is_exception_pending (env, &isPending));
247
+
248
+ if (isPending) {
249
+ napi_value result;
250
+ CHECK_NAPI_RESULT (napi_get_and_clear_last_exception (env, &result));
251
+ CHECK_NAPI_RESULT (napi_fatal_exception (env, result));
197
252
}
253
+
254
+ return nullptr ;
198
255
}
199
256
200
257
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 ());
213
- }
258
+ napi_ref CallbackBridge<T, L>::get_wrapper_constructor(napi_env env) {
259
+ // TODO: cache wrapper_constructor
260
+
261
+ napi_property_descriptor methods[] = {
262
+ { " success" , nullptr , CallbackBridge::ReturnCallback },
263
+ };
264
+
265
+ napi_value ctor;
266
+ CHECK_NAPI_RESULT (napi_define_class (env, " CallbackBridge" , NAPI_AUTO_LENGTH, CallbackBridge::New, nullptr , 1 , methods, &ctor));
267
+ CHECK_NAPI_RESULT (napi_create_reference (env, ctor, 1 , &wrapper_constructor));
214
268
215
- return Nan::New ( wrapper_constructor) ;
269
+ return wrapper_constructor;
216
270
}
217
271
218
272
template <typename T, typename L>
219
- NAN_METHOD (CallbackBridge<T COMMA L>::New) {
220
- info.GetReturnValue ().Set (info.This ());
273
+ napi_value CallbackBridge<T, L>::New(napi_env env, napi_callback_info info) {
274
+ napi_value _this;
275
+ CHECK_NAPI_RESULT (napi_get_cb_info (env, info, nullptr , nullptr , &_this, nullptr ));
276
+ return _this;
221
277
}
222
278
223
279
template <typename T, typename L>
0 commit comments