Add ES5 classes

This commit is contained in:
Luis Blanco 2019-09-03 22:06:57 +03:00
parent bb46894d97
commit 98aaf2d4ba
1 changed files with 153 additions and 1 deletions

View File

@ -1,7 +1,7 @@
#ifndef _ADDON_TOOLS_HPP_ #ifndef _ADDON_TOOLS_HPP_
#define _ADDON_TOOLS_HPP_ #define _ADDON_TOOLS_HPP_
#define NODE_ADDON_API_DISABLE_DEPRECATED
#include <napi.h> #include <napi.h>
@ -479,5 +479,157 @@ inline void eventEmitAsync(
} }
inline void inheritEs5(napi_env env, Napi::Function ctor, Napi::Function superCtor) {
napi_value global, globalObject, setProto, ctorProtoProp, superCtorProtoProp;
napi_value argv[2];
napi_get_global(env, &global);
napi_get_named_property(env, global, "Object", &globalObject);
napi_get_named_property(env, globalObject, "setPrototypeOf", &setProto);
napi_get_named_property(env, ctor, "prototype", &ctorProtoProp);
napi_get_named_property(env, superCtor, "prototype", &superCtorProtoProp);
argv[0] = ctorProtoProp;
argv[1] = superCtorProtoProp;
napi_call_function(env, global, setProto, 2, argv, nullptr);
argv[0] = ctor;
argv[1] = superCtor;
napi_call_function(env, global, setProto, 2, argv, nullptr);
ctor.Set("super_", superCtor); \
}
typedef Napi::Value (*StaticMethodCallback)(const Napi::CallbackInfo& info);
typedef Napi::Value (*StaticGetterCallback)(const Napi::CallbackInfo& info);
typedef void (*StaticSetterCallback)(const Napi::CallbackInfo& info);
#define DECLARE_ES5_CLASS(CLASS, NAME) \
static Napi::FunctionReference _ctorEs5; \
static const char *_nameEs5; \
static void CLASS::_finalizeEs5(napi_env e, void *dest, void* hint); \
static napi_value CLASS::_createEs5(napi_env e, napi_callback_info i); \
inline void super( \
const Napi::CallbackInfo& info, \
int argc = 0, \
const Napi::Value *argv = nullptr \
) { \
Napi::Function ctor = _ctorEs5.Value(); \
if (ctor.Has("super_")) { \
Napi::Function _super = ctor.Get("super_").As<Napi::Function>(); \
std::vector<napi_value> args; \
for (int i = 0; i < argc; i++) { \
args.push_back(argv[i]); \
} \
_super.Call(info.This(), args); \
} \
}; \
inline static Napi::Function wrap(Napi::Env env) { \
napi_value __initResult; \
napi_create_function(env, #NAME, 0, CLASS::_createEs5, nullptr, &__initResult); \
Napi::Function ctor = Napi::Function(env, __initResult); \
_ctorEs5 = Napi::Persistent(ctor); \
_ctorEs5.SuppressDestruct(); \
return ctor; \
}; \
inline static Napi::Function wrap( \
Napi::Env env, \
Napi::Function superCtor \
) { \
Napi::Function ctor = wrap(env); \
inheritEs5(env, ctor, superCtor); \
return ctor; \
}; \
inline static void method( \
const char *name, \
StaticMethodCallback cb \
) { \
Napi::Function proto = _ctorEs5.Value().Get("prototype").As<Napi::Function>(); \
proto.DefineProperty( \
Napi::PropertyDescriptor::Function(proto.Env(), proto, name, cb) \
); \
}; \
inline static void accessorR( \
const char *name, \
StaticGetterCallback getter \
) { \
Napi::Function proto = _ctorEs5.Value().Get("prototype").As<Napi::Function>(); \
proto.DefineProperty( \
Napi::PropertyDescriptor::Accessor(proto.Env(), proto, name, getter) \
); \
}; \
inline static void accessorRw( \
const char *name, \
StaticGetterCallback getter, \
StaticSetterCallback setter \
) { \
Napi::Function proto = _ctorEs5.Value().Get("prototype").As<Napi::Function>(); \
proto.DefineProperty( \
Napi::PropertyDescriptor::Accessor( \
proto.Env(), \
proto, \
name, \
getter, \
setter \
) \
); \
};
#define JS_GET_THAT(CLASS) \
CLASS *that; \
Napi::Object thatObj = info.This().As<Napi::Object>(); \
napi_unwrap(info.Env(), thatObj.Get(_nameEs5), reinterpret_cast<void**>(&that));
#define JS_DECLARE_METHOD(CLASS, NAME) \
inline static Napi::Value __st_##NAME(const Napi::CallbackInfo &info) { \
JS_GET_THAT(CLASS); \
return that->__i_##NAME(info); \
}; \
Napi::Value __i_##NAME(const Napi::CallbackInfo &info);
#define JS_DECLARE_GETTER(CLASS, NAME) JS_DECLARE_METHOD(CLASS, NAME##Getter)
#define JS_DECLARE_SETTER(CLASS, NAME) \
inline static void __st_##NAME##Setter( \
const Napi::CallbackInfo &info \
) { \
JS_GET_THAT(CLASS); \
that->__i_##NAME(info, info[0]); \
}; \
void __i_##NAME##Setter(const Napi::CallbackInfo &info, const Napi::Value &value);
#define JS_IMPLEMENT_METHOD(CLASS, NAME) \
Napi::Value CLASS::__i_##NAME(const Napi::CallbackInfo &info)
#define JS_IMPLEMENT_GETTER(CLASS, NAME) JS_IMPLEMENT_METHOD(CLASS, NAME##Getter)
#define JS_IMPLEMENT_SETTER(CLASS, NAME) \
void CLASS::__i_##NAME##Setter( \
const Napi::CallbackInfo &info, \
const Napi::Value &value \
)
#define JS_ASSIGN_METHOD(NAME) method(#NAME, __st_##NAME)
#define JS_ASSIGN_GETTER(NAME) accessorR(#NAME, __st_##NAME##Getter)
#define JS_ASSIGN_SETTER(NAME) accessorRw(#NAME, __st_##NAME##Getter, __st_##NAME##Setter)
#define IMPLEMENT_ES5_CLASS(CLASS) \
Napi::FunctionReference CLASS::_ctorEs5; \
const char *CLASS::_nameEs5 = "CLASS##__TIMESTAMP__"; \
void CLASS::_finalizeEs5(napi_env e, void *dest, void* hint) { \
CLASS *instance = reinterpret_cast<CLASS*>(dest); \
delete instance; \
} \
napi_value CLASS::_createEs5(napi_env env, napi_callback_info i) { \
Napi::CallbackInfo info(env, i); \
CLASS *instance = new CLASS(info); \
Napi::Object wrapObj = Napi::Object::New(env); \
info.This().As<Napi::Object>().Set(_nameEs5, wrapObj); \
napi_wrap(env, wrapObj, instance, CLASS::_finalizeEs5, nullptr, nullptr); \
return info.Env().Undefined(); \
}
#endif // _ADDON_TOOLS_HPP_ #endif // _ADDON_TOOLS_HPP_