22#define CALLBACK_BRIDGE_H
33
44#include < vector>
5- #include < nan.h>
65#include < algorithm>
76#include < uv.h>
8-
9- #define COMMA ,
7+ # include " common.h "
8+ #include < napi.h >
109
1110template <typename T, typename L = void *>
1211class CallbackBridge {
1312 public:
14- CallbackBridge (v8::Local<v8::Function> , bool );
13+ CallbackBridge (napi_env, napi_value , bool );
1514 virtual ~CallbackBridge ();
1615
1716 // Executes the callback
1817 T operator ()(std::vector<void *>);
1918
19+ // Needed for napi_wrap
20+ napi_value NewInstance (napi_env env);
21+
2022 protected:
2123 // We will expose a bridge object to the JS callback that wraps this instance so we don't loose context.
2224 // 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 );
2426 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;
2931
3032 // The callback that will get called in the main thread after the worker thread used for the sass
3133 // compilation step makes a call to uv_async_send()
@@ -34,13 +36,16 @@ class CallbackBridge {
3436 // The V8 values sent to our ReturnCallback must be read on the main thread not the sass worker thread.
3537 // This gives a chance to specialized subclasses to transform those values into whatever makes sense to
3638 // 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+
3841
42+ virtual std::vector<napi_value> pre_process_args (napi_env, std::vector<L>) const = 0;
3943
40- virtual std::vector<v8::Local<v8::Value>> pre_process_args (std::vector<L>) const =0;
44+ // ASYNC
45+ // Nan::AsyncResource* async_resource;
4146
42- Nan::Callback* callback ;
43- Nan::AsyncResource* async_resource ;
47+ napi_env e ;
48+ napi_ref callback ;
4449 bool is_sync;
4550
4651 uv_mutex_t cv_mutex;
@@ -52,45 +57,57 @@ class CallbackBridge {
5257};
5358
5459template <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+ }
5673
5774template <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) {
5976 /*
6077 * This is invoked from the main JavaScript thread.
6178 * V8 context is available.
6279 */
63- Nan ::HandleScope scope;
80+ Napi ::HandleScope scope ( this -> e ) ;
6481 uv_mutex_init (&this ->cv_mutex );
6582 uv_cond_init (&this ->condition_variable );
6683 if (!is_sync) {
6784 this ->async = new uv_async_t ;
6885 this ->async ->data = (void *) this ;
6986 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" );
7187 }
7288
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 ));
7694}
7795
7896template <typename T, typename L>
7997CallbackBridge<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+
82101 uv_cond_destroy (&this ->condition_variable );
83102 uv_mutex_destroy (&this ->cv_mutex );
84103
85104 if (!is_sync) {
86105 uv_close ((uv_handle_t *)this ->async , &async_gone);
87- delete this ->async_resource ;
88106 }
89107}
90108
91109template <typename T, typename L>
92110T CallbackBridge<T, L>::operator ()(std::vector<void *> argv) {
93- // argv.push_back(wrapper);
94111 if (this ->is_sync ) {
95112 /*
96113 * This is invoked from the main JavaScript thread.
@@ -100,18 +117,32 @@ T CallbackBridge<T, L>::operator()(std::vector<void*> argv) {
100117 * from types invoked by pre_process_args() and
101118 * post_process_args().
102119 */
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 ;
108131 }
109132
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));
111144
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);
115146 } else {
116147 /*
117148 * This is invoked from the worker thread.
@@ -153,24 +184,46 @@ void CallbackBridge<T, L>::dispatched_async_uv_callback(uv_async_t *req) {
153184 * from types invoked by pre_process_args() and
154185 * post_process_args().
155186 */
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 ;
162196 }
163- argv_v8.push_back (Nan::New (bridge->wrapper ));
164-
165- bridge->callback ->Call (argv_v8.size (), &argv_v8[0 ], bridge->async_resource );
166197
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 ;
169214 }
170215}
171216
172217template <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);
174227
175228 /*
176229 * Callback function invoked by the user code.
@@ -179,10 +232,7 @@ NAN_METHOD(CallbackBridge<T COMMA L>::ReturnCallback) {
179232 *
180233 * Implicit Local<> handle scope created by NAN_METHOD(.)
181234 */
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);
186236
187237 {
188238 uv_mutex_lock (&bridge->cv_mutex );
@@ -192,32 +242,38 @@ NAN_METHOD(CallbackBridge<T COMMA L>::ReturnCallback) {
192242
193243 uv_cond_broadcast (&bridge->condition_variable );
194244
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));
197252 }
253+
254+ return nullptr ;
198255}
199256
200257template <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));
214268
215- return Nan::New ( wrapper_constructor) ;
269+ return wrapper_constructor;
216270}
217271
218272template <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;
221277}
222278
223279template <typename T, typename L>
0 commit comments