# Addon Tools
This is a part of [Node3D](https://github.com/node-3d) project.
[](https://www.npmjs.com/package/addon-tools-raub)
[](https://travis-ci.com/node-3d/addon-tools-raub)
[](https://www.codefactor.io/repository/github/node-3d/addon-tools-raub)
> npm i -s addon-tools-raub
## Synopsis
Helpers for Node.js **NAPI** addons and dependency packages:
* Supported platforms (x64): Windows, Linux, OSX.
* C++ helpers:
* Macro shortcuts for NAPI.
* `consoleLog()` function.
* `eventEmit()` function.
* `getData()` function.
* Module helpers:
* Crossplatform commands for GYP: `cp`, `rm`, `mkdir`.
* Deps unzip installer.
* Url-to-buffer downloader.
Useful links: [N-API Docs](https://nodejs.org/api/n-api.html),
[Napi Docs](https://github.com/nodejs/node-addon-api/blob/master/doc/setup.md),
[GYP Docs](https://gyp.gsrc.io/docs/UserDocumentation.md).
**Jump to**:
[Snippets](#snippets)
[include/addon-tools.hpp](#includeaddon-toolshpp)
[index.js](#indexjs)
[Crossplatform commands](#crossplatform-commands)
[Function consoleLog](#function-consolelog)
[Function eventEmit](#function-eventEmit)
---
## Snippets
### Crossplatform commands
```
'variables': {
'rm' : '
See a snipped for binding.gyp here
* Assume `EXT_LIB` is the name of a binary dependency.
* Assume `deps-EXT_LIB` is the name of an Addon Tools compliant dependency module.
* Assume `MY_ADDON` is the name of this addon's resulting binary.
* Assume C++ code goes to `cpp` subdirectory.
```
{
'variables': {
'rm' : '
---
## include/addon-tools.hpp
There is a C++ header file, `addon-tools.hpp`, shipped with this package. It
introduces several useful macros and utilities. Also it includes Napi automatically,
so that you can replace:
```
#include
```
with
```
#include
```
In gyp, the include directory should be set for your addon to know where
to get it. An actual path to the directory is exported from the module
and is accessible like this:
```
require('addon-tools-raub').include // a string
```
### Helpers in **addon-tools.hpp**:
Usually all the helpers work within the context of JS call. In this case we
have `CallbackInfo info` passed as an argument.
```
#define NAPI_ENV Napi::Env env = info.Env();
#define NAPI_HS Napi::HandleScope scope(env);
```
Return value
* `RET_VALUE(VAL)`- return a given Napi::Value.
* `RET_UNDEFINED`- return `undefined`.
* `RET_NULL` - return `null`.
* `RET_STR(VAL)` - return `Napi::String`, expected `VAL` is `const char *`.
* `RET_NUM(VAL)` - return `Napi::Number`, expected `VAL` is `double`.
* `RET_EXT(VAL)` - return `Napi::External`, expected `VAL` is `void *`.
* `RET_BOOL(VAL)` - return `Napi::Boolean`, expected `VAL` is `bool`.
* `RET_FUN(VAL)` - return `Napi::Function`, expected `VAL` is a `napi_value`.
* `RET_OBJ(VAL)` - return `Napi::Object`, expected `VAL` is a `napi_value`.
New JS value
* `JS_STR(VAL)` - create a `Napi::String` value.
* `JS_NUM(VAL)` - create a `Napi::Number` value.
* `JS_EXT(VAL)` - create a `Napi::External` (from pointer) 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.
Method check
These checks throw JS TypeError if not passed. Here `T` is always used as a typename
in error messages. `C` is a
[Napi::Value](https://github.com/nodejs/node-addon-api/blob/master/doc/value.md#isboolean)
check method, like `IsObject()`. `I` is the index of argument as in `info[I]`,
starting from `0`.
* `REQ_ARGS(N)` - check if at least `N` arguments passed
* `IS_ARG_EMPTY(I)` - check if argument `I` is `undefined` or `null`
* `CHECK_REQ_ARG(I, C, T)` - check if argument `I` is approved by `C` check.
* `CHECK_LET_ARG(I, C, T)` - check if argument `I` is approved by `C` check or empty.
* `CTOR_CHECK(T)` - check if method is called as a constructor
* `SETTER_CHECK(C, T)` - check if setter `value` is approved by `C` check.
* `DES_CHECK` - within dynamic method check if the instance wasn't
destroyed by `destroy()`.
Method arguments
The idea is to ease the transition from what inside the `CallbackInfo` to
what you work with in C++.
Three types of argument retrieval are supported: `REQ_`, `USE_` and `LET_`.
The difference:
* `REQ_` - 2 params, requires an argument to have a value
* `USE_` - 3 params, allows the argument to be empty and have a default
* `LET_` - 2 params, is `USE_` with a preset zero-default.
What it does, basically:
```
// REQ_DOUBLE_ARG(0, x)
double x = info[0].ToNumber().DoubleValue();
// USE_DOUBLE_ARG(0, x, 5.7)
double x = IS_ARG_EMPTY(0) ? 5.7 : info[0].ToNumber().DoubleValue();
// LET_DOUBLE_ARG(0, x)
double x = IS_ARG_EMPTY(0) ? 0.0 : info[0].ToNumber().DoubleValue();
```
That extrapolates well to all the helpers below:
* `REQ_STR_ARG` - JS `string` => C++ `std::string`.
* `USE_STR_ARG`
* `LET_STR_ARG` - default: `""`.
* `REQ_INT32_ARG` - JS `number` => C++ `int32_t`.
* `USE_INT32_ARG`
* `LET_INT32_ARG` - default: `0`.
* `REQ_INT_ARG` - JS `number` => C++ `int32_t`.
* `USE_INT_ARG`
* `LET_INT_ARG` - default: `0`.
* `REQ_UINT32_ARG` - JS `number` => C++ `uint32_t`.
* `USE_UINT32_ARG`
* `LET_UINT32_ARG` - default: `0`.
* `REQ_UINT_ARG` - JS `number` => C++ `uint32_t`.
* `USE_UINT_ARG`
* `LET_UINT_ARG` - default: `0`.
* `REQ_BOOL_ARG` - JS `Boolean` => C++ `bool`.
* `USE_BOOL_ARG`
* `LET_BOOL_ARG` - default: `false`.
* `REQ_OFFS_ARG` - JS `number` => C++ `size_t`.
* `USE_OFFS_ARG`
* `LET_OFFS_ARG` - default: `0`.
* `REQ_DOUBLE_ARG` - JS `number` => C++ `double`.
* `USE_DOUBLE_ARG`
* `LET_DOUBLE_ARG` - default: `0.0`.
* `REQ_FLOAT_ARG` - JS `number` => C++ `float`.
* `USE_FLOAT_ARG`
* `LET_FLOAT_ARG` - default: `0.f`.
* `REQ_EXT_ARG` - JS `native` => C++ `void*`.
* `USE_EXT_ARG`
* `LET_EXT_ARG` - default: `nullptr`.
* `REQ_FUN_ARG` - JS `function` => C++ `Napi::Function`.
* `REQ_OBJ_ARG` - JS `object` => C++ `Napi::Object`.
* `USE_OBJ_ARG`
* `LET_OBJ_ARG` - default: `{}`.
* `REQ_ARRV_ARG` - JS `ArrayBuffer` => C++ `Napi::ArrayBuffer`.
* `REQ_BUF_ARG` - JS `Buffer` => C++ `Napi::Buffer`.
```
NAN_METHOD(test) {
REQ_UINT32_ARG(0, width);
REQ_UINT32_ARG(1, height);
LET_FLOAT_ARG(2, z);
// Variables created: unsigned int width, height; float z;
...
```
Set object accessors
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) { ...
```
Setter argument
Works similar to method arguments. But there is always `value`
argument, from which a C++ value is extracted.
* `SETTER_STR_ARG`
* `SETTER_INT32_ARG`
* `SETTER_INT_ARG`
* `SETTER_BOOL_ARG`
* `SETTER_UINT32_ARG`
* `SETTER_UINT_ARG`
* `SETTER_OFFS_ARG`
* `SETTER_DOUBLE_ARG`
* `SETTER_FLOAT_ARG`
* `SETTER_EXT_ARG`
* `SETTER_FUN_ARG`
* `SETTER_OBJ_ARG`
* `SETTER_ARRV_ARG`
```
JS_SETTER(MyClass::x) { SETTER_STR_ARG;
// Variable created: std::string v;
...
```
Data retrieval
* `T *getArrayData(value, num = NULL)` - extracts TypedArray data of any type from
the given JS value. Does not accept `Array`. Checks with `IsArrayBuffer()`.
Returns `nullptr` for empty JS values. For unacceptable values throws TypeError.
* `void *getData(value)` - if value is a TypedArray, then the result of
`getArrayData(value)` is returned. Otherwise if value has `'data'` property, it's
content is then returned as `node::Buffer`. Returns `nullptr` in other cases.
---
## index.js
Exports:
* `paths(dir)` - function. Returns a set of platform dependent paths depending on
input `dir`.
* `bin` - platform binary directory absolute path.
* `include` - include directory for this `dir`.
* `include` - both `'addon-tools-raub'` and `'node-addon-api'` include paths.
Use with `node -p` through list context command expansion ` Note: only use this within JS function stack
## Function eventEmit
In N-API there is no inheritance. And no `eval('require(...)')` possible at
the time of module init. But `require('events')` is very tempting...
The solution is:
```
// JS
const EventEmitter = require('events');
const { bin } = require('addon-tools-raub');
const MyClass = require(`./${bin}/addon`);
MyClass.prototype.__proto__ = EventEmitter.prototype;
// Since now it is possible to call `emit` from instancess of MyClass
```
```
// C++
void MyClass::emit(const Napi::CallbackInfo& info, const char* name) {
NAPI_ENV;
THIS_OBJ(that);
eventEmit(env, that, name);
}
```
Signature:
```
inline void eventEmit(
Napi::Env env,
Napi::Object that,
const std::string &name,
int argc = 0,
Napi::Value *argv = nullptr
)
```