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 < napi.h >
8+ #include " common.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;
3840
3941
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;
4143
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;
4449 bool is_sync;
4550
4651 uv_mutex_t cv_mutex;
@@ -52,39 +57,68 @@ 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+ 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+ }
5686
5787template <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) {
5989 /*
6090 * This is invoked from the main JavaScript thread.
6191 * V8 context is available.
6292 */
63- Nan::HandleScope scope;
6493 uv_mutex_init (&this ->cv_mutex );
6594 uv_cond_init (&this ->condition_variable );
6695 if (!is_sync) {
6796 this ->async = new uv_async_t ;
6897 this ->async ->data = (void *) this ;
6998 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");
71101 }
72102
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 ));
76108}
77109
78110template <typename T, typename L>
79111CallbackBridge<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+
82115 uv_cond_destroy (&this ->condition_variable );
83116 uv_mutex_destroy (&this ->cv_mutex );
84117
85118 if (!is_sync) {
86119 uv_close ((uv_handle_t *)this ->async , &async_gone);
87- delete this ->async_resource ;
120+ // ASYNC
121+ // delete this->async_resource;
88122 }
89123}
90124
@@ -100,18 +134,32 @@ T CallbackBridge<T, L>::operator()(std::vector<void*> argv) {
100134 * from types invoked by pre_process_args() and
101135 * post_process_args().
102136 */
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 ;
108148 }
109149
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 );
111157
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);
115163 } else {
116164 /*
117165 * This is invoked from the worker thread.
@@ -153,24 +201,46 @@ void CallbackBridge<T, L>::dispatched_async_uv_callback(uv_async_t *req) {
153201 * from types invoked by pre_process_args() and
154202 * post_process_args().
155203 */
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 ;
162213 }
163- argv_v8.push_back (Nan::New (bridge->wrapper ));
164214
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 ;
169231 }
170232}
171233
172234template <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);
174244
175245 /*
176246 * Callback function invoked by the user code.
@@ -179,10 +249,7 @@ NAN_METHOD(CallbackBridge<T COMMA L>::ReturnCallback) {
179249 *
180250 * Implicit Local<> handle scope created by NAN_METHOD(.)
181251 */
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);
186253
187254 {
188255 uv_mutex_lock (&bridge->cv_mutex );
@@ -192,32 +259,30 @@ NAN_METHOD(CallbackBridge<T COMMA L>::ReturnCallback) {
192259
193260 uv_cond_broadcast (&bridge->condition_variable );
194261
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));
199264
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 );
213268 }
214269
215- return Nan::New (wrapper_constructor) ;
270+ return nullptr ;
216271}
217272
218273template <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;
221286}
222287
223288template <typename T, typename L>
0 commit comments