wip doc
This commit is contained in:
parent
77995f76f6
commit
90a417bedf
|
@ -58,8 +58,6 @@ have `CallbackInfo info` passed as an argument.
|
||||||
* `JS_NUM(VAL)` - create a `Napi::Number` value.
|
* `JS_NUM(VAL)` - create a `Napi::Number` value.
|
||||||
* `JS_EXT(VAL)` - create a `Napi::External` (from pointer) value.
|
* `JS_EXT(VAL)` - create a `Napi::External` (from pointer) value.
|
||||||
* `JS_BOOL(VAL)` - create a `Napi::Boolean` value.
|
* `JS_BOOL(VAL)` - create a `Napi::Boolean` value.
|
||||||
* `JS_FUN(VAL)` - create a `Napi::Function` value.
|
|
||||||
* `JS_OBJ(VAL)` - create a `Napi::Object` value.
|
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
@ -70,7 +68,7 @@ have `CallbackInfo info` passed as an argument.
|
||||||
|
|
||||||
These checks throw JS TypeError if not passed. Here `T` is always used as a typename
|
These checks throw JS TypeError if not passed. Here `T` is always used as a typename
|
||||||
in error messages. `C` is a
|
in error messages. `C` is a
|
||||||
[Napi::Value](https://github.com/nodejs/node-addon-api/blob/master/doc/value.md#isboolean)
|
[Napi::Value](https://github.com/nodejs/node-addon-api/blob/master/doc/value.md)
|
||||||
check method, like `IsObject()`. `I` is the index of argument as in `info[I]`,
|
check method, like `IsObject()`. `I` is the index of argument as in `info[I]`,
|
||||||
starting from `0`.
|
starting from `0`.
|
||||||
|
|
||||||
|
@ -151,7 +149,6 @@ That extrapolates well to all the helpers below:
|
||||||
|
|
||||||
```
|
```
|
||||||
NAN_METHOD(test) {
|
NAN_METHOD(test) {
|
||||||
|
|
||||||
REQ_UINT32_ARG(0, width);
|
REQ_UINT32_ARG(0, width);
|
||||||
REQ_UINT32_ARG(1, height);
|
REQ_UINT32_ARG(1, height);
|
||||||
LET_FLOAT_ARG(2, z);
|
LET_FLOAT_ARG(2, z);
|
||||||
|
@ -162,37 +159,6 @@ NAN_METHOD(test) {
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
||||||
<details>
|
|
||||||
|
|
||||||
<summary>Set object accessors</summary>
|
|
||||||
|
|
||||||
Simplified accessor assignment, adds accessors of NAME for OBJ. Read accessor is
|
|
||||||
assumed to have the name `NAME+'Getter'` and write accessor is `NAME+'Setter'`.
|
|
||||||
|
|
||||||
* `ACCESSOR_RW(CLASS, NAME)` - add read and write accessors NAME of CLASS.
|
|
||||||
* `ACCESSOR_R(CLASS, NAME)` - add read accessor NAME of CLASS.
|
|
||||||
* `ACCESSOR_M(CLASS, NAME)` - add method NAME of CLASS.
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
void MyClass::init(Napi::Env env, Napi::Object exports) {
|
|
||||||
...
|
|
||||||
Napi::Function ctor = DefineClass(env, "MyClass", {
|
|
||||||
ACCESSOR_R(MyClass, isDestroyed),
|
|
||||||
ACCESSOR_RW(MyClass, x),
|
|
||||||
ACCESSOR_M(MyClass, reset),
|
|
||||||
});
|
|
||||||
...
|
|
||||||
}
|
|
||||||
JS_GETTER(MyClass::isDestroyedGetter) { ...
|
|
||||||
JS_GETTER(MyClass::xGetter) { ...
|
|
||||||
JS_SETTER(MyClass::xSetter) { ...
|
|
||||||
JS_METHOD(MyClass::save) { ...
|
|
||||||
```
|
|
||||||
|
|
||||||
</details>
|
|
||||||
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
<summary>Setter argument</summary>
|
<summary>Setter argument</summary>
|
||||||
|
@ -215,24 +181,29 @@ argument, from which a C++ value is extracted.
|
||||||
* `SETTER_ARRV_ARG`
|
* `SETTER_ARRV_ARG`
|
||||||
|
|
||||||
```
|
```
|
||||||
JS_SETTER(MyClass::x) { SETTER_STR_ARG;
|
JS_IMPLEMENT_SETTER(MyClass, x) { THIS_CHECK; SETTER_STR_ARG;
|
||||||
// Variable created: std::string v;
|
// Variable created: std::string v;
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See also: [Class Wrapping](class-wrapping.md)
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
|
|
||||||
<summary>Data retrieval</summary>
|
<summary>JS Data to C++ Data</summary>
|
||||||
|
|
||||||
* `T *getArrayData(value, num = NULL)` - extracts TypedArray data of any type from
|
* `T *getArrayData(value, num = NULL)` - extracts TypedArray data of any type from
|
||||||
the given JS value. Does not accept `Array`. Checks with `IsArrayBuffer()`.
|
the given JS value. Does not accept `Array`. Checks with `IsArrayBuffer()`.
|
||||||
Returns `nullptr` for empty JS values. For unacceptable values throws TypeError.
|
Returns `nullptr` for empty JS values. For unacceptable values throws TypeError.
|
||||||
|
|
||||||
* `void *getData(value)` - if value is a TypedArray, then the result of
|
* `T *getBufferData(value, num = NULL)` - extracts Buffer data from
|
||||||
`getArrayData(value)` is returned. Otherwise if value has `'data'` property, it's
|
the given JS value. Checks with `IsBuffer()`.
|
||||||
content is then returned as `node::Buffer`. Returns `nullptr` in other cases.
|
Returns `nullptr` for empty JS values. For unacceptable values throws TypeError.
|
||||||
|
|
||||||
|
* `void *getData(value)` - if `value` or `value.data` is a `TypedArray|Buffer`,
|
||||||
|
calls `getArrayData` or `getArrayData` respectively. Returns `nullptr` in other cases.
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
|
@ -1,5 +1,16 @@
|
||||||
# Es5 class wrapping
|
# Es5 class wrapping
|
||||||
|
|
||||||
|
For NAPI addons this allows to call `super()` from C++ and makes the class
|
||||||
|
constructor callable with `ClassName.call(obj, ...args)`.
|
||||||
|
Also multiple C++ objects can be attached to a single JS object
|
||||||
|
if it is necessary in an inheritance scenario.
|
||||||
|
On JS side `util.inherits`
|
||||||
|
[is used](https://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor),
|
||||||
|
and on C++ side `inheritEs5`.
|
||||||
|
This implementation is using composition rather than inheritance, so
|
||||||
|
it is easily pluggable.
|
||||||
|
|
||||||
|
|
||||||
## Class Declaration
|
## Class Declaration
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -40,7 +51,6 @@ the second is the name of the setter to be created.
|
||||||
## Class Implementation
|
## Class Implementation
|
||||||
|
|
||||||
```
|
```
|
||||||
// Some utility stuff
|
|
||||||
IMPLEMENT_ES5_CLASS(ClassName);
|
IMPLEMENT_ES5_CLASS(ClassName);
|
||||||
|
|
||||||
// Fill the properties and export the class
|
// Fill the properties and export the class
|
||||||
|
@ -83,5 +93,16 @@ JS_IMPLEMENT_GETTER(ClassName, isDestroyed) { THIS_CHECK;
|
||||||
RET_BOOL(_isDestroyed);
|
RET_BOOL(_isDestroyed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`IMPLEMENT_ES5_CLASS` - implements some utility functions for class wrapping.
|
||||||
|
`JS_ASSIGN_METHOD` - in `init()`, assigns the given method to this class.
|
||||||
|
`JS_ASSIGN_GETTER` - in `init()`, assigns the given getter to this class.
|
||||||
|
`JS_ASSIGN_SETTER` - in `init()`, assigns both getter and setter to this class.
|
||||||
|
It also takes only one argument because both have the same name.
|
||||||
|
`JS_IMPLEMENT_METHOD` - implements a method, the first argument is this class,
|
||||||
|
the second is the name of the method being implemented.
|
||||||
|
`JS_IMPLEMENT_GETTER` - implements a getter, the first argument is this class,
|
||||||
|
the second is the name of the getter being implemented.
|
||||||
|
`JS_IMPLEMENT_SETTER` - implements a setter, the first argument is this class,
|
||||||
|
the second is the name of the setter being implemented.
|
||||||
|
|
|
@ -310,25 +310,21 @@
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define NAPI_CALL(the_call, ATE) \
|
#define NAPI_CALL(the_call) \
|
||||||
do { \
|
do { \
|
||||||
if ((the_call) != napi_ok) { \
|
if ((the_call) != napi_ok) { \
|
||||||
GET_AND_THROW_LAST_ERROR(); \
|
GET_AND_THROW_LAST_ERROR(); \
|
||||||
ATE; \
|
RET_UNDEFINED; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define JS_RUN_3(code, VAR, ATE) \
|
#define JS_RUN(code, VAR) \
|
||||||
napi_value __RESULT_ ## VAR; \
|
napi_value __RESULT_ ## VAR; \
|
||||||
NAPI_CALL( \
|
NAPI_CALL( \
|
||||||
napi_run_script(env, napi_value(JS_STR(code)), &__RESULT_ ## VAR), \
|
napi_run_script(env, napi_value(JS_STR(code)), &__RESULT_ ## VAR) \
|
||||||
ATE \
|
|
||||||
); \
|
); \
|
||||||
Napi::Value VAR(env, __RESULT_ ## VAR);
|
Napi::Value VAR(env, __RESULT_ ## VAR);
|
||||||
|
|
||||||
#define JS_RUN_2(code, VAR) JS_RUN_3(code, VAR, return)
|
|
||||||
#define JS_RUN JS_RUN_3
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Type = uint8_t>
|
template<typename Type = uint8_t>
|
||||||
inline Type* getArrayData(
|
inline Type* getArrayData(
|
||||||
|
@ -400,6 +396,8 @@ inline void *getData(Napi::Env env, Napi::Object obj) {
|
||||||
|
|
||||||
if (obj.IsTypedArray() || obj.IsArrayBuffer()) {
|
if (obj.IsTypedArray() || obj.IsArrayBuffer()) {
|
||||||
pixels = getArrayData<uint8_t>(env, obj);
|
pixels = getArrayData<uint8_t>(env, obj);
|
||||||
|
} else if (obj.IsBuffer()) {
|
||||||
|
pixels = getBufferData<uint8_t>(env, obj);
|
||||||
} else if (obj.Has("data")) {
|
} else if (obj.Has("data")) {
|
||||||
Napi::Object data = obj.Get("data").As<Napi::Object>();
|
Napi::Object data = obj.Get("data").As<Napi::Object>();
|
||||||
if (data.IsTypedArray() || data.IsArrayBuffer()) {
|
if (data.IsTypedArray() || data.IsArrayBuffer()) {
|
||||||
|
@ -414,23 +412,25 @@ inline void *getData(Napi::Env env, Napi::Object obj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void consoleLog(
|
inline Napi::Value consoleLog(
|
||||||
Napi::Env env,
|
Napi::Env env,
|
||||||
int argc,
|
int argc,
|
||||||
const Napi::Value *argv
|
const Napi::Value *argv
|
||||||
) {
|
) {
|
||||||
JS_RUN_2("console.log", log);
|
JS_RUN("console.log", log);
|
||||||
std::vector<napi_value> args;
|
std::vector<napi_value> args;
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
args.push_back(napi_value(argv[i]));
|
args.push_back(napi_value(argv[i]));
|
||||||
}
|
}
|
||||||
log.As<Napi::Function>().Call(args);
|
log.As<Napi::Function>().Call(args);
|
||||||
|
RET_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void consoleLog(Napi::Env env, const std::string &message) {
|
inline Napi::Value consoleLog(Napi::Env env, const std::string &message) {
|
||||||
Napi::Value arg = JS_STR(message);
|
Napi::Value arg = JS_STR(message);
|
||||||
consoleLog(env, 1, &arg);
|
consoleLog(env, 1, &arg);
|
||||||
|
RET_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -490,31 +490,26 @@ inline void eventEmitAsync(
|
||||||
|
|
||||||
|
|
||||||
inline void inheritEs5(
|
inline void inheritEs5(
|
||||||
napi_env env,
|
Napi::Env env,
|
||||||
Napi::Function ctor,
|
Napi::Function ctor,
|
||||||
Napi::Function superCtor
|
Napi::Function superCtor
|
||||||
) {
|
) {
|
||||||
|
|
||||||
napi_value global;
|
Napi::Object global = env.Global();
|
||||||
napi_value globalObject;
|
Napi::Object globalObject = global.Get("Object").As<Napi::Object>();
|
||||||
napi_value setProto;
|
Napi::Function setProto = globalObject.Get("setPrototypeOf").As<Napi::Function>();
|
||||||
napi_value ctorProtoProp;
|
Napi::Value ctorProtoProp = ctor.Get("prototype");
|
||||||
napi_value superCtorProtoProp;
|
Napi::Value superCtorProtoProp = superCtor.Get("prototype");
|
||||||
napi_value argv[2];
|
|
||||||
|
|
||||||
napi_get_global(env, &global);
|
napi_value argv[2];
|
||||||
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[0] = ctorProtoProp;
|
||||||
argv[1] = superCtorProtoProp;
|
argv[1] = superCtorProtoProp;
|
||||||
napi_call_function(env, global, setProto, 2, argv, nullptr);
|
setProto.Call(global, 2, argv);
|
||||||
|
|
||||||
argv[0] = ctor;
|
argv[0] = ctor;
|
||||||
argv[1] = superCtor;
|
argv[1] = superCtor;
|
||||||
napi_call_function(env, global, setProto, 2, argv, nullptr);
|
setProto.Call(global, 2, argv);
|
||||||
|
|
||||||
ctor.Set("super_", superCtor);
|
ctor.Set("super_", superCtor);
|
||||||
|
|
||||||
|
@ -640,11 +635,11 @@ private: \
|
||||||
);
|
);
|
||||||
|
|
||||||
#define JS_DECLARE_METHOD(CLASS, NAME) \
|
#define JS_DECLARE_METHOD(CLASS, NAME) \
|
||||||
inline static Napi::Value __st_##NAME(const Napi::CallbackInfo &info) { \
|
inline static JS_METHOD(__st_##NAME) { \
|
||||||
JS_GET_THAT(CLASS); \
|
JS_GET_THAT(CLASS); \
|
||||||
return that->__i_##NAME(info); \
|
return that->__i_##NAME(info); \
|
||||||
}; \
|
}; \
|
||||||
Napi::Value __i_##NAME(const Napi::CallbackInfo &info);
|
JS_METHOD(__i_##NAME);
|
||||||
|
|
||||||
#define JS_DECLARE_GETTER(CLASS, NAME) JS_DECLARE_METHOD(CLASS, NAME##Getter)
|
#define JS_DECLARE_GETTER(CLASS, NAME) JS_DECLARE_METHOD(CLASS, NAME##Getter)
|
||||||
|
|
||||||
|
@ -661,9 +656,10 @@ private: \
|
||||||
);
|
);
|
||||||
|
|
||||||
#define JS_IMPLEMENT_METHOD(CLASS, NAME) \
|
#define JS_IMPLEMENT_METHOD(CLASS, NAME) \
|
||||||
Napi::Value CLASS::__i_##NAME(const Napi::CallbackInfo &info)
|
JS_METHOD(CLASS::__i_##NAME)
|
||||||
|
|
||||||
#define JS_IMPLEMENT_GETTER(CLASS, NAME) JS_IMPLEMENT_METHOD(CLASS, NAME##Getter)
|
#define JS_IMPLEMENT_GETTER(CLASS, NAME) \
|
||||||
|
JS_IMPLEMENT_METHOD(CLASS, NAME##Getter)
|
||||||
|
|
||||||
#define JS_IMPLEMENT_SETTER(CLASS, NAME) \
|
#define JS_IMPLEMENT_SETTER(CLASS, NAME) \
|
||||||
Napi::Value CLASS::__i_##NAME##Setter( \
|
Napi::Value CLASS::__i_##NAME##Setter( \
|
||||||
|
|
Loading…
Reference in New Issue