From 7f4dd4f37dddaaa9d5a4a5eda6340f17715cbb2b Mon Sep 17 00:00:00 2001 From: Luis Blanco Date: Tue, 12 Nov 2019 17:06:34 +0300 Subject: [PATCH] Review docs --- README.md | 15 +++-- doc/addon-tools.md | 153 +++++++++++++++++++++--------------------- doc/class-wrapping.md | 41 ++++++----- doc/snippets.md | 4 +- 4 files changed, 108 insertions(+), 105 deletions(-) diff --git a/README.md b/README.md index 93d698d..5cc69e7 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,14 @@ additional snippets follow the links below. **Go to**: * [include/addon-tools.hpp](doc/addon-tools.md) -Macro shortcuts for C++ addons using NAPI. + + Macro shortcuts for C++ addons using **NAPI**. * [Es5 Class Wrapping](doc/class-wrapping.md) -An alternative, lightweight native class-defining mechanism for addons. + + An alternative, lightweight native class-defining mechanism for addons. * [Snippets](doc/snippets.md) -Some repetitive bits of code for addons. + + Some repetitive bits of code for addons. ## index.js @@ -84,8 +87,8 @@ const tag = process.env.npm_package_config_install; install(`${prefix}/${tag}`); ``` -`prefix` - the constant base part of the download url. -`tag` - the version-dependent part of the url, +* `prefix` - the constant base part of the download url. +* `tag` - the version-dependent part of the url, here `process.env.npm_package_config_install` is taken ([automatically](https://docs.npmjs.com/misc/config#per-package-config-settings)) from **package.json**: @@ -105,7 +108,7 @@ from **package.json**: A [Writable](https://nodejs.org/api/stream.html#stream_writable_streams) stream buffer, that is stored in-memory and can be fully obtained when writing was finished. It is equivalent to stream-writing -a temporary file and then reading it into a Buffer. +a temporary file and then reading it into a `Buffer`. Use `stream.get()` to obtain the data when writing was finished: ``` diff --git a/doc/addon-tools.md b/doc/addon-tools.md index 675cdeb..e36802e 100644 --- a/doc/addon-tools.md +++ b/doc/addon-tools.md @@ -1,31 +1,29 @@ # 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: - +introduces several useful macros and utilities. Also it includes **Napi** +implicitly, so 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 +In **GYP**, the include directory should be set for your addon. +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. +Usually all the helpers work within the context of a method. In this case we +have `CallbackInfo info` passed as an argument. And we can return `undefined` +in case a problem has occured. So most of these macros are only usable +within `Napi::Value`-returning functions. ``` #define NAPI_ENV Napi::Env env = info.Env(); @@ -34,17 +32,15 @@ have `CallbackInfo info` passed as an argument.
-Return value +**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`. +* `RET_NUM(VAL)` - return `Napi::Number`, expected `VAL` is of numeric type. +* `RET_EXT(VAL)` - return `Napi::External`, expected `VAL` is a pointer. +* `RET_BOOL(VAL)` - return `Napi::Boolean`, expected `VAL` is convertible to bool.
@@ -52,21 +48,21 @@ have `CallbackInfo info` passed as an argument.
-New JS 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_STR(VAL)` - create a `Napi::String`, expected `VAL` is `const char *`. +* `JS_NUM(VAL)` - create a `Napi::Number`, expected `VAL` is of numeric type. +* `JS_EXT(VAL)` - create a `Napi::External`, expected `VAL` is a pointer. +* `JS_BOOL(VAL)` - create a `Napi::Boolean`, expected `VAL` is convertible to bool.
-Method check +**Method check** -These checks throw JS TypeError if not passed. Here `T` is always used as a typename +These checks throw JS `TypeError` if not passed. `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) check method, like `IsObject()`. `I` is the index of argument as in `info[I]`, @@ -76,22 +72,21 @@ starting from `0`. * `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 +* `DES_CHECK` - for void-returning methods, check if the instance wasn't destroyed by `destroy()`. +* `THIS_CHECK` - check if the instance wasn't +destroyed by `destroy()`, and then fetch `env`.
-Method arguments +**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: +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 * `USE_` - 3 params, allows the argument to be empty and have a default * `LET_` - 2 params, is `USE_` with a preset zero-default. @@ -109,50 +104,53 @@ 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`. +| Macro | JS type | C++ type | Default | +| :--- | :---: | :---: | :---: | +| `REQ_STR_ARG` | `string` | `std::string` | - | +| `USE_STR_ARG` | `string` | `std::string` | - | +| `LET_STR_ARG` | `string` | `std::string` | `""` | +| `REQ_INT32_ARG` | `number` | `int32_t` | - | +| `USE_INT32_ARG` | `number` | `int32_t` | - | +| `LET_INT32_ARG` | `number` | `int32_t` | `0` | +| `REQ_INT_ARG` | `number` | `int32_t` | - | +| `USE_INT_ARG` | `number` | `int32_t` | - | +| `LET_INT_ARG` | `number` | `int32_t` | `0` | +| `REQ_UINT32_ARG` | `number` | `uint32_t` | - | +| `USE_UINT32_ARG` | `number` | `uint32_t` | - | +| `LET_UINT32_ARG` | `number` | `uint32_t` | `0` | +| `REQ_UINT_ARG` | `number` | `uint32_t` | - | +| `USE_UINT_ARG` | `number` | `uint32_t` | - | +| `LET_UINT_ARG` | `number` | `uint32_t` | `0` | +| `REQ_BOOL_ARG` | `Boolean` | `bool` | - | +| `USE_BOOL_ARG` | `Boolean` | `bool` | - | +| `LET_BOOL_ARG` | `Boolean` | `bool` | `false` | +| `REQ_OFFS_ARG` | `number` | `size_t` | - | +| `USE_OFFS_ARG` | `number` | `size_t` | - | +| `LET_OFFS_ARG` | `number` | `size_t` | `0` | +| `REQ_DOUBLE_ARG` | `number` | `double` | - | +| `USE_DOUBLE_ARG` | `number` | `double` | - | +| `LET_DOUBLE_ARG` | `number` | `double` | `0.0` | +| `REQ_FLOAT_ARG` | `number` | `float` | - | +| `USE_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_FUN_ARG` | `function` | `Napi::Function` | - | +| `REQ_OBJ_ARG` | `object` | `Napi::Object` | - | +| `USE_OBJ_ARG` | `object` | `Napi::Object` | - | +| `LET_OBJ_ARG` | `object` | `Napi::Object` | `{}` | +| `REQ_ARRV_ARG` | `ArrayBuffer` | `Napi::ArrayBuffer` | - | +| `REQ_BUF_ARG` | `Buffer` | `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; +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. ... ``` @@ -161,7 +159,7 @@ NAN_METHOD(test) {
-Setter argument +**Setter argument** Works similar to method arguments. But there is always `value` argument, from which a C++ value is extracted. @@ -193,7 +191,7 @@ See also: [Class Wrapping](class-wrapping.md)
-JS Data to C++ Data +**JS Data to C++ Data** * `T *getArrayData(value, num = NULL)` - extracts TypedArray data of any type from the given JS value. Does not accept `Array`. Checks with `IsArrayBuffer()`. @@ -203,7 +201,10 @@ Returns `nullptr` for empty JS values. For unacceptable values throws TypeError. the given JS value. Checks with `IsBuffer()`. 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. +* `void *getData(value)` - if `value` is a `TypedArray|Buffer`, +calls `getArrayData` or `getArrayData` on it. Otherwise, if +`value.data` is a `TypedArray|Buffer`, +calls `getArrayData` or `getArrayData` on it. +Returns `nullptr` in other cases.
diff --git a/doc/class-wrapping.md b/doc/class-wrapping.md index 259ec93..5051686 100644 --- a/doc/class-wrapping.md +++ b/doc/class-wrapping.md @@ -1,14 +1,15 @@ # 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 +This wrapping implementation diverges from standard ES6 style wrapping. +It also uses composition rather than inheritance, so it is easily pluggable. + +* For **NAPI** addons, `super()` can be called from C++ side. +* Constructor is callable with `ClassName.call(obj, ...args)`. +* Multiple C++ objects can be attached to a single JS object if it is necessary in an inheritance scenario. -On JS side `util.inherits` +* 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. +and on C++ side there is `inheritEs5` function. ## Class Declaration @@ -34,17 +35,15 @@ public: }; ``` -`DECLARE_ES5_CLASS` - adds utility declarations, the first argument +* `DECLARE_ES5_CLASS` - adds utility declarations, the first argument must be this class name, and the second argument will become the name (arbitrary) of this function (constructor) in JS. - -`init` - can be used to initialize this class and export it. - -`JS_DECLARE_METHOD` - declares a method, the first argument is this class, +* `init` - can be used to initialize this class and export it. +* `JS_DECLARE_METHOD` - declares a method, the first argument is this class, the second is the name of the method to be created. -`JS_DECLARE_GETTER` - declares a getter, the first argument is this class, +* `JS_DECLARE_GETTER` - declares a getter, the first argument is this class, the second is the name of the getter to be created. -`JS_DECLARE_SETTER` - declares a setter, the first argument is this class, +* `JS_DECLARE_SETTER` - declares a setter, the first argument is this class, the second is the name of the setter to be created. @@ -95,14 +94,14 @@ JS_IMPLEMENT_GETTER(ClassName, isDestroyed) { THIS_CHECK; ``` -`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. +* `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, +* `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, +* `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, +* `JS_IMPLEMENT_SETTER` - implements a setter, the first argument is this class, the second is the name of the setter being implemented. diff --git a/doc/snippets.md b/doc/snippets.md index 2b7a19e..cfaff5e 100644 --- a/doc/snippets.md +++ b/doc/snippets.md @@ -2,7 +2,7 @@ ## C++ Addon building -N-API addons are built separately from the installation, so we can't/shouldn't +**NAPI** addons are built separately from the installation, so we shouldn't put the file **binding.gyp** to the module root anymore. It is better to have a separate folder with a separate **package.json**, **binding.gyp** and the sources. @@ -114,7 +114,7 @@ dependency include path(s).
-See a snipped for src/binding.gyp here +**See a snipped for src/binding.gyp here** * Assume `DEPS` is the name of an Addon Tools compliant dependency module. * Assume `ADDON` is the name of this addon's resulting binary.