C++ header addon-tools.hpp introduces several macros and utilities.
Also it includes NAPI implicitly, so you can replace:
#include <napi.h>with
#include <addon-tools.hpp>For GYP, the include directory is accessible with:
'include_dirs': [
'<!@(node -e "import(\'@node-3d/addon-tools\').then((m) => m.printInclude())")',
],Console logging and "global" logging helpers for C++ side are available:
Global logging expects a named logger to be created from JS side. See JS Utils section in README.
// to `console` by default
const logger = utils.createLogger({ name: 'my-logger' }); consoleLog(env, "test");
// or
Napi::Value args[2] = { JS_STR("test"), JS_NUM(2) };
consoleLog(env, 2, &args[0]);
// or
globalLog(env, "cpp", "info", "test");
// or
globalLog(env, "cpp", "warn", 2, &args[0]);Most of the helpers work within functions, where Napi::CallbackInfo info is
passed as an argument, and Napi::Value is to be returned.
#define NAPI_ENV Napi::Env env = info.Env();
#define NAPI_HS Napi::HandleScope scope(env);Other global helpers:
DBG_EXPORT- set symbol visibility (mainly for callstack traces). On Windows, that is equal to exporting a symbol:__declspec(dllexport). On Unix it does nothing.JS_THROW(text)- throws JS exception with the given text message.
Return value
RET_VALUE(VAL)- return a given Napi::Value.RET_UNDEFINED- returnundefined.RET_NULL- returnnull.RET_STR(VAL)- returnNapi::String, expectedVALisconst char *.RET_NUM(VAL)- returnNapi::Number, expectedVALis of numeric type.RET_EXT(VAL)- returnNapi::External, expectedVALis a pointer.RET_BOOL(VAL)- returnNapi::Boolean, expectedVALis convertible to bool.RET_ARRAY_STR(VAL)- returnNapi::Array, expectedVALisstd::vector<std::string>.
New JS value
JS_UNDEFINED- anundefinedvalue.JS_NULL- anullvalue.JS_STR(VAL)- create aNapi::String, expectedVALisconst char *.JS_NUM(VAL)- create aNapi::Number, expectedVALis of numeric type.JS_EXT(VAL)- create aNapi::External, expectedVALis a pointer.JS_BOOL(VAL)- create aNapi::Boolean, expectedVALis convertible to bool.JS_OBJECT- a new emptyObjectinstance.JS_ARRAY- a new emptyArrayinstance.
Method check
These checks throw JS TypeError if not passed. T is always used as a typename
in error messages. C is a
Napi::Value
check method, like IsObject(). I is the index of argument as in info[I],
starting from 0.
REQ_ARGS(N)- check if at leastNarguments passedIS_ARG_EMPTY(I)- check if argumentIisundefinedornullCHECK_REQ_ARG(I, C, T)- check if argumentIis approved byCcheck.CHECK_LET_ARG(I, C, T)- check if argumentIis approved byCcheck or empty.SETTER_CHECK(C, T)- check if settervalueis approved byCcheck.DES_CHECK- for void-returning methods, check if the instance wasn't destroyed bydestroy().THIS_CHECK- check if the instance wasn't destroyed bydestroy(), and then fetchenv.
Method arguments
Following macros convert JS arguments into C++ variables. Three types of argument retrieval are supported:
REQ_- 2 params, requires an argument to have a value of specific type.USE_- 3 params, allows the argument to be empty and have a default.LET_- 2 params, isUSE_with a preset zero-default.SOFT_- 2 params, isLET_without type and arity checks.WEAK_- 2 params, uses type coercion, doesn't check if arg exists.
Numeric helpers are intentionally lightweight. If the JS argument passes the
macro's type check, the helper performs the corresponding Napi::Number
conversion and stores the result in the requested C++ type. Additional rules
such as fractional rejection, signedness constraints, or full 64-bit JS range
validation are left to the caller.
What it does, basically:
// REQ_DOUBLE_ARG(0, x)
if (info.Length() < 1 || !info[0].IsNumber()) { JS_THROW; RET_UNDEFINED; }
double x = info[0].As<Napi::Number>().DoubleValue();
// USE_DOUBLE_ARG(0, x, 5.7)
if (info.Length() < 1 || !info[0].IsNumber()) { JS_THROW; RET_UNDEFINED; }
double x = IS_ARG_EMPTY(0) ? 5.7 : info[0].ToNumber().DoubleValue();
// LET_DOUBLE_ARG(0, x)
USE_DOUBLE_ARG(0, x, 0.0);
// SOFT_DOUBLE_ARG(0, x)
double x = info.Length() < 1 ? 0.0 : info[0].ToNumber().DoubleValue();
// WEAK_DOUBLE_ARG(0, x)
double x = info[0].ToNumber().DoubleValue();That extrapolates well to all the helpers below:
| Macro | JS type | C++ type | Default |
|---|---|---|---|
REQ_STR_ARG |
string |
std::string |
- |
USE_STR_ARG |
string |
std::string |
- |
WEAK_STR_ARG |
string |
std::string |
- |
LET_STR_ARG |
string |
std::string |
"" |
REQ_INT32_ARG |
number |
int32_t |
- |
USE_INT32_ARG |
number |
int32_t |
- |
WEAK_INT32_ARG |
number |
int32_t |
- |
LET_INT32_ARG |
number |
int32_t |
0 |
REQ_INT_ARG |
number |
int32_t |
- |
USE_INT_ARG |
number |
int32_t |
- |
WEAK_INT_ARG |
number |
int32_t |
- |
LET_INT_ARG |
number |
int32_t |
0 |
REQ_UINT32_ARG |
number |
uint32_t |
- |
USE_UINT32_ARG |
number |
uint32_t |
- |
WEAK_UINT32_ARG |
number |
uint32_t |
- |
LET_UINT32_ARG |
number |
uint32_t |
0 |
REQ_UINT_ARG |
number |
uint32_t |
- |
USE_UINT_ARG |
number |
uint32_t |
- |
WEAK_UINT_ARG |
number |
uint32_t |
- |
LET_UINT_ARG |
number |
uint32_t |
0 |
REQ_INT64_ARG |
number |
int64_t |
- |
USE_INT64_ARG |
number |
int64_t |
- |
WEAK_INT64_ARG |
number |
int64_t |
- |
LET_INT64_ARG |
number |
int64_t |
0 |
REQ_UINT64_ARG |
number |
uint64_t |
- |
USE_UINT64_ARG |
number |
uint64_t |
- |
WEAK_UINT64_ARG |
number |
uint64_t |
- |
LET_UINT64_ARG |
number |
uint64_t |
0 |
REQ_BOOL_ARG |
Boolean |
bool |
- |
USE_BOOL_ARG |
Boolean |
bool |
- |
WEAK_BOOL_ARG |
Boolean |
bool |
- |
LET_BOOL_ARG |
Boolean |
bool |
false |
SOFT_BOOL_ARG |
Boolean |
bool |
false |
REQ_OFFS_ARG |
number |
size_t |
- |
USE_OFFS_ARG |
number |
size_t |
- |
WEAK_OFFS_ARG |
number |
size_t |
- |
LET_OFFS_ARG |
number |
size_t |
0 |
REQ_DOUBLE_ARG |
number |
double |
- |
USE_DOUBLE_ARG |
number |
double |
- |
WEAK_DOUBLE_ARG |
number |
double |
- |
LET_DOUBLE_ARG |
number |
double |
0.0 |
REQ_FLOAT_ARG |
number |
float |
- |
USE_FLOAT_ARG |
number |
float |
- |
WEAK_FLOAT_ARG |
number |
float |
- |
LET_FLOAT_ARG |
number |
float |
0.f |
REQ_EXT_ARG |
native |
void* |
- |
USE_EXT_ARG |
native |
void* |
- |
LET_EXT_ARG |
native |
void* |
nullptr |
REQ_OBJ_ARG |
object |
Napi::Object |
- |
USE_OBJ_ARG |
object |
Napi::Object |
- |
LET_OBJ_ARG |
object |
Napi::Object |
{} |
REQ_ARRAY_ARG |
object |
Napi::Array |
- |
USE_ARRAY_ARG |
object |
Napi::Array |
- |
LET_ARRAY_ARG |
object |
Napi::Array |
[] |
LET_ARRAY_STR_ARG |
object |
std::vector<std::string> |
std::vector<std::string>() |
REQ_FUN_ARG |
function |
Napi::Function |
- |
REQ_ARRV_ARG |
ArrayBuffer |
Napi::ArrayBuffer |
- |
REQ_BUF_ARG |
Buffer |
Napi::Buffer<uint8_t> |
- |
JS_METHOD(test) {
REQ_UINT32_ARG(0, width); // uint32_t width
REQ_UINT32_ARG(1, height); // uint32_t height
LET_FLOAT_ARG(2, z); // float z
// An error is thrown if width or height are not passed as numbers.
// Argument z can be undefined, null, or number; error otherwise.
...Setter argument
Works similar to method arguments. But there is always value
argument, from which a C++ value is extracted.
SETTER_STR_ARGSETTER_INT32_ARGSETTER_INT_ARGSETTER_BOOL_ARGSETTER_UINT32_ARGSETTER_UINT_ARGSETTER_INT64_ARGSETTER_UINT64_ARGSETTER_OFFS_ARGSETTER_DOUBLE_ARGSETTER_FLOAT_ARGSETTER_EXT_ARGSETTER_FUN_ARGSETTER_OBJ_ARGSETTER_ARRV_ARG
JS_IMPLEMENT_SETTER(MyClass, x) { THIS_CHECK; SETTER_STR_ARG;
// Variable created: std::string v;
...See also: Class Wrapping
JS Data to C++ Data
-
const T *getArrayData(env, obj, num = NULL)- extracts TypedArray data of any type from the given JS object. Does not acceptArray. Checks withIsArrayBuffer(). The byte length must contain completeTitems and the data pointer must be properly aligned forT. Returnsnullptrfor empty JS values. For unacceptable values throws TypeError. -
const T *getBufferData(env, obj, num = NULL)- extracts Buffer data from the given JS object. Checks withIsBuffer(). The byte length must contain completeTitems and the data pointer must be properly aligned forT. Returnsnullptrfor empty JS values. For unacceptable values throws TypeError. -
const void *getData(env, obj)- ifobjis aTypedArray|Buffer, callsgetArrayDataorgetBufferDataon it. Otherwise, ifobj.datais aTypedArray|Buffer, callsgetArrayDataorgetBufferDataon it. Returnsnullptrin other cases.
Addon Tools provides C++ macro helpers for ES5 Classes (function-based).
The generated wrappers validate this before forwarding calls, while the
public class helper exposes a low-level unwrap() probe for manual use.
See the class-wrapping doc here.