Compare commits

..

No commits in common. "master" and "v5.1.0" have entirely different histories.

67 changed files with 2940 additions and 3879 deletions

116
.eslintrc Normal file
View File

@ -0,0 +1,116 @@
{
"root": true,
"env": {
"node" : true,
"es6" : true,
"mocha" : true
},
"globals": {
"expect" : true,
"chai" : true,
"sinon" : true
},
"extends": ["eslint:recommended"],
"parserOptions": {
"ecmaVersion": 8,
"ecmaFeatures": {
"experimentalObjectRestSpread": true
}
},
"rules": {
"arrow-parens": ["error", "as-needed"],
"no-trailing-spaces": [
"error",
{
"skipBlankLines": true
}
],
"indent": [
"error",
"tab",
{
"SwitchCase": 1
}
],
"linebreak-style": [
"error",
"unix"
],
"max-len": ["error", 110],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"no-multiple-empty-lines": ["error", { "max": 3, "maxEOF": 1, "maxBOF": 1 }],
"keyword-spacing": ["error", { "before": true, "after": true }],
"space-before-blocks": ["error"],
"space-before-function-paren": ["error", {"anonymous": "always", "named": "never", "asyncArrow": "always"}],
"space-infix-ops": ["error"],
"space-unary-ops": [
"error", {
"words": true,
"nonwords": false,
"overrides": {
"!": true
}
}
],
"spaced-comment": [0],
"camelcase": ["error"],
"no-tabs": [0],
"comma-dangle": [0],
"global-require": [0],
"func-names": [0],
"no-param-reassign": [0],
"no-underscore-dangle": [0],
"no-restricted-syntax": [
"error",
{
"selector": "LabeledStatement",
"message": "Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand."
},
{
"selector": "WithStatement",
"message": "`with` is disallowed in strict mode because it makes code impossible to predict and optimize."
}
],
"no-mixed-operators": [0],
"no-plusplus": [0],
"comma-spacing": [0],
"default-case": [0],
"no-shadow": [0],
"no-console": [0],
"key-spacing": [0],
"no-return-assign": [0],
"consistent-return": [0],
"class-methods-use-this": [0],
"no-multi-spaces": [
"error",
{
"exceptions": {
"VariableDeclarator": true,
"Property": true,
"ImportDeclaration": true
}
}
],
"array-callback-return": [0],
"no-use-before-define": [
"error",
{
"functions": false,
"classes": true,
"variables": true
}
],
"padded-blocks": [0],
"space-in-parens": [0],
"valid-jsdoc": [0],
"no-unused-expressions": [0],
"import/no-dynamic-require": [0]
}
}

View File

@ -1,75 +0,0 @@
{
"ignorePatterns": [
"src/**"
],
"extends": [
"eslint:recommended",
"plugin:node/recommended"
],
"parserOptions": {
"ecmaVersion": 2022
},
"env": {
"node": true,
"es6": true
},
"rules": {
"arrow-parens": ["error", "always"],
"no-trailing-spaces": [
"error",
{
"skipBlankLines": true
}
],
"indent": [
"error",
"tab",
{
"SwitchCase": 1
}
],
"operator-linebreak": [
"error",
"after",
{
"overrides": {
"?": "before",
":": "before"
}
}
],
"max-len": ["error", 110],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"no-multiple-empty-lines": ["error", { "max": 3, "maxEOF": 1, "maxBOF": 1 }],
"keyword-spacing": ["error", { "before": true, "after": true }],
"space-before-blocks": ["error"],
"space-before-function-paren": ["error", {"anonymous": "always", "named": "never", "asyncArrow": "always"}],
"camelcase": ["error"],
"no-tabs": [0],
"global-require": [0],
"no-underscore-dangle": [0],
"no-plusplus": [0],
"no-shadow": [0],
"node/no-unpublished-require": [0],
"no-process-exit": [0],
"linebreak-style": [0],
"node/no-missing-require": [0],
"no-console": [0],
"node/no-unsupported-features/es-builtins": 0,
"node/no-unsupported-features/node-builtins": 0,
"func-names": [
"error",
"never",
{
"generators": "never"
}
]
}
}

1
.gitattributes vendored
View File

@ -1 +0,0 @@
test-addon/binding.gyp linguist-vendored

View File

@ -1,47 +0,0 @@
name: Cpplint
defaults:
run:
shell: bash
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
eslint:
name: Cpplint
runs-on: ubuntu-20.04
steps:
- name: Fetch Repository
uses: actions/checkout@v3
with:
persist-credentials: false
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18.16.0
cache: 'npm'
- name: Install Modules
run: npm ci
- name: Install Python
uses: actions/setup-python@v4
with:
python-version: '3.12'
- name: Install Cpplint
run: pip install cpplint
- name: Run Cpplint
run: |
node -e "require('.').cpcpplint()"
cpplint --recursive ./test-addon
cpplint --recursive ./include

View File

@ -1,36 +0,0 @@
name: ESLint
defaults:
run:
shell: bash
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
eslint:
name: ESLint
runs-on: ubuntu-20.04
steps:
- name: Fetch Repository
uses: actions/checkout@v3
with:
persist-credentials: false
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18.16.0
cache: 'npm'
- name: Install Modules
run: npm ci
- name: Run ESLint
run: npm run eslint

View File

@ -1,46 +0,0 @@
name: Publish to NPM
defaults:
run:
shell: bash
on:
workflow_dispatch
jobs:
Publish:
if: contains('["raub"]', github.actor)
runs-on: ubuntu-latest
steps:
- name: Fetch Repository
uses: actions/checkout@v3
with:
persist-credentials: false
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18.16.0
cache: 'npm'
- name: Get Package Version
id: package-version
run: node -p "'version='+require('./package').version" >> $GITHUB_OUTPUT
- name: Publish
run: |
npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
npm publish --ignore-scripts
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ steps.package-version.outputs.version }}
name: Release ${{ steps.package-version.outputs.version }}
body: Published at ${{ github.sha }}

View File

@ -1,43 +0,0 @@
name: Test
defaults:
run:
shell: bash
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
unit-tests:
name: Unit Tests
strategy:
matrix:
os: [ubuntu-20.04, windows-2022, macos-11, [self-hosted, linux, ARM64]]
runs-on: ${{ matrix.os }}
steps:
- name: Fetch Repository
uses: actions/checkout@v3
with:
persist-credentials: false
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18.16.0
cache: 'npm'
- name: Install Modules
run: npm ci
- name: Build Sample Addon
run: npm run build-test
- name: Run Unit Tests
run: npm run test-ci

4
.gitignore vendored
View File

@ -4,6 +4,8 @@
.DS_Store .DS_Store
.project .project
.DS_Store .DS_Store
.vscode
.eslintrc
node_modules/ node_modules/
test-addon/build/ test/build/
*.log *.log

20
.travis.yml Normal file
View File

@ -0,0 +1,20 @@
language: node_js
node_js:
- "12.13.0"
matrix:
include:
- name: "Linux"
os: linux
dist: xenial
sudo: false
- name: "MacOS"
os: osx
- name: "Windows"
os: windows
install:
- cd test
- npm ci

View File

@ -1,17 +0,0 @@
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**",
"${LocalAppData}/node-gyp/Cache/16.17.0/include/node",
"${LocalAppData}/node-gyp/Cache/18.16.0/include/node"
],
"windowsSdkVersion": "10.0.19041.0",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "windows-msvc-x64"
}
],
"version": 4
}

View File

@ -1,18 +1,15 @@
set noparent set noparent
linelength=110 linelength=110
filter=-build/header_guard
filter=-build/include
filter=-build/include_order
filter=-build/include_what_you_use
filter=-build/namespaces
filter=-legal/copyright filter=-legal/copyright
filter=-readability/todo filter=-build/include_order
filter=-runtime/indentation_namespace filter=-build/header_guard
filter=-build/namespaces
filter=-build/include_what_you_use
filter=-whitespace/blank_line filter=-whitespace/blank_line
filter=-whitespace/braces
filter=-whitespace/comments filter=-whitespace/comments
filter=-whitespace/tab
filter=-whitespace/end_of_line filter=-whitespace/end_of_line
filter=-whitespace/indent filter=-whitespace/indent
filter=-whitespace/operators filter=-whitespace/operators
filter=-whitespace/parens filter=-whitespace/parens
filter=-whitespace/tab filter=-readability/todo

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2023 Luis Blanco Copyright (c) 2018 Luis Blanco
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

154
README.md
View File

@ -2,74 +2,140 @@
This is a part of [Node3D](https://github.com/node-3d) project. This is a part of [Node3D](https://github.com/node-3d) project.
[![NPM](https://badge.fury.io/js/addon-tools-raub.svg)](https://badge.fury.io/js/addon-tools-raub) [![NPM](https://nodei.co/npm/addon-tools-raub.png?compact=true)](https://www.npmjs.com/package/addon-tools-raub)
[![ESLint](https://github.com/node-3d/addon-tools-raub/actions/workflows/eslint.yml/badge.svg)](https://github.com/node-3d/addon-tools-raub/actions/workflows/eslint.yml)
[![Test](https://github.com/node-3d/addon-tools-raub/actions/workflows/test.yml/badge.svg)](https://github.com/node-3d/addon-tools-raub/actions/workflows/test.yml)
[![Cpplint](https://github.com/node-3d/addon-tools-raub/actions/workflows/cpplint.yml/badge.svg)](https://github.com/node-3d/addon-tools-raub/actions/workflows/cpplint.yml)
``` [![Build Status](https://api.travis-ci.com/node-3d/addon-tools-raub.svg?branch=master)](https://travis-ci.com/node-3d/addon-tools-raub)
npm i -s addon-tools-raub [![CodeFactor](https://www.codefactor.io/repository/github/node-3d/addon-tools-raub/badge)](https://www.codefactor.io/repository/github/node-3d/addon-tools-raub)
```
> npm i addon-tools-raub
## include/addon-tools.hpp ## Synopsis
Macro shortcuts for C++ addons using **NAPI**. This module contains numerous helpers for Node.js **NAPI**
See [docs inside the folder](/include). addons and dependency packages. On this page, helper scripts
are described. For details on **addon-tools.hpp** and some
additional snippets follow the links below.
Example of an addon method definition: **Go to**:
``` * [include/addon-tools.hpp](doc/addon-tools.md)
// hpp:
#include <addon-tools.hpp> Macro shortcuts for C++ addons using **NAPI**.
DBG_EXPORT JS_METHOD(doSomething); * [Es5 Class Wrapping](doc/class-wrapping.md)
// cpp:
DBG_EXPORT JS_METHOD(doSomething) { NAPI_ENV; An alternative, lightweight native class-defining mechanism for addons.
LET_INT32_ARG(0, param0); * [Snippets](doc/snippets.md)
std::cout << "param0: " << param0 << std::endl;
RET_UNDEFINED; Some repetitive bits of code for addons.
}
```
## index.js ## index.js
JavaScript helpers for Node.js addon development. The short list of helpers: Main exports for cross-platform addon configuration.
* `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 `<!@(...)`.
* `bin` - platform-dependent binary directory name.
* `platform` - platform name: `'windows', 'linux', 'osx'`.
## download.js
Downloads a file into the memory, **HTTP** or **HTTPS**.
`async WritableBuffer download(string url)` - accepts an **URL**, and
returns an in-memory buffer, when file is loaded.
Example use:
``` ```
'getBin', 'getPlatform', 'getInclude', 'getPaths', download(srcUrl).then(
'install', 'cpbin', 'download', 'read', 'write', 'copy', 'exists', data => useData(data),
'mkdir', 'stat', 'isDir', 'isFile', 'dirUp', 'ensuredir', 'copysafe', err => emit('error', err)
'readdir', 'subdirs', 'subfiles', 'traverse', 'copyall', );
'rmdir', 'rm', 'WritableBuffer', 'actionPack', // or
const data = await download(srcUrl);
useData(data);
``` ```
See the [TypeScript definitions](/index.d.ts) with comments. ## cpbin.js
Copies the addon binary from **src/build/Release** to the platform folder.
It is useful for development builds. Use it in your **src/package.json**:
```
"scripts": {
"build": "node-gyp rebuild && node -e \"require('addon-tools-raub/cpbin')('ADDON')\""
},
```
Here ADDON should be replaced with the name of your addon, without `.node` extension.
### Example for an ADDON's **index.js**: ## install.js
Downloads and unzips the platform specific binary for the calling package.
To use it, create a new script for your package, which may as well be named
**install.js**, with the following content:
``` ```
const { getBin } = require('addon-tools-raub'); 'use strict';
const core = require(`./${getBin()}/ADDON`); // uses the platform-specific ADDON.node const install = require('addon-tools-raub/install');
const prefix = 'https://github.com/USER/ADDON-NAME/releases/download';
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,
here `process.env.npm_package_config_install` is taken
([automatically](https://docs.npmjs.com/misc/config#per-package-config-settings))
from **package.json**:
```
"config": {
"install": "v2.0.0"
},
"scripts": {
"postinstall": "node install"
},
``` ```
### Example for **binding.gyp**: ## writable-buffer.js
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`.
Use `stream.get()` to obtain the data when writing was finished:
``` ```
'include_dirs': [ const stream = new WritableBuffer();
'<!@(node -p "require(\'addon-tools-raub\').getInclude()")', // ...
], sourceStream.pipe(stream);
sourceStream.on('end', () => useData(stream.get()));
``` ```
> NOTE: the optional `node-addon-api` dependency is used by the `getInclude()` helper. If not found,
the **napi.h** include path won't be a part of the returned string.
## utils.js
### Example of `cpbin` in **package.json :: scripts**: * `read` - (async) Reads a whole file to string, NOT A Buffer.
* `write` - (async) Write a file.
``` * `copy` - (async) Copy a file.
"build": "cd src && node-gyp rebuild -j max --silent && node -e \"require('addon-tools-raub').cpbin('segfault')\" && cd ..", * `exists` - (async) Check if a file/folder exists.
"build-only": "cd src && node-gyp build -j max --silent && node -e \"require('addon-tools-raub').cpbin('segfault')\" && cd ..", * `mkdir` - (async) Create an empty folder.
``` * `stat` - (async) Get status on a file.
* `isDir` - (async) Check if the path is a folder.
* `isFile` - (async) Check if the path is a file.
* `dirUp` - Cut the path one folder up.
* `ensuredir` - (async) Like `mkdir -p`, makes sure a directory exists.
* `copysafe` - (async) Copy a file, `dest` folder is created if needed.
* `readdir` - (async) Get file/folder names of the 1st level.
* `subdirs` - (async) Get folder paths (concatenated with input) of the 1st level.
* `subfiles` - (async) Get file paths (concatenated with input) of the 1st level.
* `traverse` - (async) Get all nested files recursively.
* `copyall` - (async) Copy a folder with all the contained files.
* `rmdir` - (async) Like `rm -rf`, removes everything recursively.
* `rm` - (async) Remove a file. Must be a file, not a folder. Just `fs.unlink`.

31
cpbin.js Normal file
View File

@ -0,0 +1,31 @@
'use strict';
const { copy, exists, mkdir, rm } = require('./utils');
const { bin } = require('.');
module.exports = async name => {
const srcDir = process.cwd().replace(/\\/g, '/');
if ( ! await exists(`${srcDir}/build/Release/${name}.node`) ) {
console.error(`Error. File "${srcDir}/build/Release/${name}.node" not found.`);
}
const binAbs = `${srcDir}/../${bin}`;
if ( ! await exists(binAbs) ) {
await mkdir(binAbs);
}
const destAbs = `${binAbs}/${name}.node`;
if (await exists(destAbs)) {
await rm(destAbs);
}
await copy(`${srcDir}/build/Release/${name}.node`, destAbs);
console.log(`The binary "${name}.node" was copied to "${bin}".`);
};

View File

@ -1,9 +1,8 @@
# include/addon-tools.hpp # include/addon-tools.hpp
There is a C++ header file, `addon-tools.hpp`, shipped with this package. It There is a C++ header file, `addon-tools.hpp`, shipped with this package. It
introduces several useful macros and utilities. Also it includes **NAPI** introduces several useful macros and utilities. Also it includes **Napi**
implicitly, so you can replace: implicitly, so you can replace:
``` ```
#include <napi.h> #include <napi.h>
``` ```
@ -11,31 +10,18 @@ with
``` ```
#include <addon-tools.hpp> #include <addon-tools.hpp>
``` ```
In **GYP**, the include directory should be set for your addon. In **GYP**, the include directory should be set for your addon.
An actual path to the directory is exported from the module An actual path to the directory is exported from the module
and is accessible with: and is accessible like this:
``` ```
require('addon-tools-raub').getInclude() // a string require('addon-tools-raub').include // a string
``` ```
For more examples, see [code snippets here](snippets.md).
### Helpers in **addon-tools.hpp**:
### ES5 Classes
The standard class-defining (i.e. exporting a JS class from the C++ side) tools
from **NAPI** are a bit repetitive and excessive. So instead, Addon Tools
comes with a set of helpers for old-school class definition.
Think of it as ES5 classes. Just a function, spawning instances that have their
constructor and prototype set accordingly. Such classes may be further extended
and/or manipulated from JS-land. See the [class-wrapping doc here](class-wrapping.md).
### Method Helpers
Usually all the helpers work within the context of a method. In this case we Usually all the helpers work within the context of a method. In this case we
have `Napi::CallbackInfo info` passed as an argument. And we can return `undefined` 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 in case a problem has occured. So most of these macros are only usable
within `Napi::Value`-returning functions. within `Napi::Value`-returning functions.
@ -44,10 +30,6 @@ within `Napi::Value`-returning functions.
#define NAPI_HS Napi::HandleScope scope(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.
<details> <details>
<summary><b>Return value</b></summary> <summary><b>Return value</b></summary>
@ -59,7 +41,6 @@ Other global helpers:
* `RET_NUM(VAL)` - return `Napi::Number`, expected `VAL` is of numeric type. * `RET_NUM(VAL)` - return `Napi::Number`, expected `VAL` is of numeric type.
* `RET_EXT(VAL)` - return `Napi::External`, expected `VAL` is a pointer. * `RET_EXT(VAL)` - return `Napi::External`, expected `VAL` is a pointer.
* `RET_BOOL(VAL)` - return `Napi::Boolean`, expected `VAL` is convertible to bool. * `RET_BOOL(VAL)` - return `Napi::Boolean`, expected `VAL` is convertible to bool.
* `RET_ARRAY_STR(VAL)` - return `Napi::Array`, expected `VAL` is `std::vector<std::string>`.
</details> </details>
@ -168,7 +149,6 @@ That extrapolates well to all the helpers below:
| `REQ_ARRAY_ARG` | `object` | `Napi::Array` | - | | `REQ_ARRAY_ARG` | `object` | `Napi::Array` | - |
| `USE_ARRAY_ARG` | `object` | `Napi::Array` | - | | `USE_ARRAY_ARG` | `object` | `Napi::Array` | - |
| `LET_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_FUN_ARG` | `function` | `Napi::Function` | - |
| `REQ_ARRV_ARG` | `ArrayBuffer` | `Napi::ArrayBuffer` | - | | `REQ_ARRV_ARG` | `ArrayBuffer` | `Napi::ArrayBuffer` | - |
| `REQ_BUF_ARG` | `Buffer` | `Napi::Buffer<uint8_t>` | - | | `REQ_BUF_ARG` | `Buffer` | `Napi::Buffer<uint8_t>` | - |

View File

@ -31,6 +31,7 @@ public:
JS_DECLARE_METHOD(ClassName, ClassName, destroy); JS_DECLARE_METHOD(ClassName, ClassName, destroy);
bool _isDestroyed; bool _isDestroyed;
}; };
``` ```
@ -61,10 +62,13 @@ void ClassName::init(Napi::Env env, Napi::Object exports) {
} }
ClassName::ClassName(const Napi::CallbackInfo &info) { NAPI_ENV; ClassName::ClassName(const Napi::CallbackInfo &info) { NAPI_ENV;
super(info); super(info);
_isDestroyed = false; _isDestroyed = false;
// ... // ...
} }
ClassName::~ClassName() { ClassName::~ClassName() {

197
doc/snippets.md Normal file
View File

@ -0,0 +1,197 @@
# Snippets
## C++ Addon building
**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.
A snippet for **src/package.json**:
```
{
"name": "build",
"version": "0.0.0",
"private": true,
"scripts": {
"build": "node-gyp rebuild && node -e \"require('addon-tools-raub/cpbin')('ADDON')\""
},
"dependencies": {
"addon-tools-raub": "5.0.0",
"DEPS": "1.0.0"
}
}
```
* `ADDON` - the name of this addon (and subsequently of its binary).
* `DEPS` - dependency package(s).
### Binary distribution
In **package.json** use the `"postinstall"` script to download the libraries.
For example the following structure might work. Note that **Addon Tools** will
append any given URL with `/${platform}.zip`
```
"config" : {
"install" : "v1.0.0"
},
"scripts": {
"postinstall": "install",
},
```
Here `config.install` is the tag name to download the binaries from.
To use it, create the *install.js* file in your addon:
```
const install = require('addon-tools-raub/install');
const prefix = 'https://github.com/USER/ADDON/releases/download';
const tag = process.env.npm_package_config_install;
install(`${prefix}/${tag}`);
```
**Addon Tools** will unzip the downloaded file into the platform binary
directory. E.g. on Windows it will be **bin-windows**.
* For a dependency package:
Place the following piece of code in the `index.js` without changes. Method `paths()`
is described [here](../README.md).
```
module.exports = require('addon-tools-raub').paths(__dirname);
```
* For a compiled addon:
Require it in your **index.js** from the platform-specific directory.
```
const { bin } = require('addon-tools-raub');
const core = require(`./${bin}/ADDON`);
```
Publishing binaries is done by attaching a zipped platform folder to the Github
release. Zip file must NOT contain platform folder as a subfolder, but rather
contain the final binaries. The tag of the release should be the same as in
`npm_package_config_install` - that is the way installer will find it.
> NOTE: You can publish your binaries to anywhere, not necessarily Github.
Just tweak **YOUR install.js** script as appropriate. The only limitation
from **Addon Tools** is that it should be a zipped set of files/folders.
### GYP Variables
```
'variables': {
'bin' : '<!(node -p "require(\'addon-tools-raub\').bin")',
'DEPS_include' : '<!(node -p "require(\'DEPS\').include")',
'DEPS_bin' : '<!(node -p "require(\'DEPS\').bin")',
},
```
* `bin` - the name of this platform's binary directory, e.g. *bin-linux*.
* `DEPS_include` - the include folder for some dependency package.
* `DEPS_bin` - the binary folder for some dependency package.
### Include directories
```
'include_dirs' : [
'<!@(node -p "require(\'addon-tools-raub\').include")',
'<(DEPS_include)',
],
```
The former contains both the path to include **Addon Tools** and the one for
**Napi** (which is preinstalled with Addon Tools). The latter can be any other
dependency include path(s).
<details>
<summary><b>See a snipped for src/binding.gyp here</b></summary>
* Assume `DEPS` is the name of an Addon Tools compliant dependency module.
* Assume `ADDON` is the name of this addon's resulting binary.
* Assume C++ code goes to `cpp` subdirectory.
```
{
'variables': {
'bin' : '<!(node -p "require(\'addon-tools-raub\').bin")',
'DEPS_include' : '<!(node -p "require(\'DEPS\').include")',
'DEPS_bin' : '<!(node -p "require(\'DEPS\').bin")',
},
'targets': [
{
'target_name' : 'bullet',
'sources' : [
'cpp/addon.cpp',
],
'include_dirs' : [
'<!@(node -p "require(\'addon-tools-raub\').include")',
'<(DEPS_include)',
],
'library_dirs' : [ '<(DEPS_bin)' ],
'libraries' : [ '-lDEPS' ],
'cflags!': ['-fno-exceptions'],
'cflags_cc!': ['-fno-exceptions'],
'conditions': [
[
'OS=="linux"',
{
'libraries': [
"-Wl,-rpath,'$$ORIGIN'",
"-Wl,-rpath,'$$ORIGIN/../node_modules/DEPS/<(bin)'",
"-Wl,-rpath,'$$ORIGIN/../../DEPS/<(bin)'",
],
'defines': ['__linux__'],
}
],
[
'OS=="mac"',
{
'libraries': [
'-Wl,-rpath,@loader_path',
'-Wl,-rpath,@loader_path/../node_modules/DEPS/<(bin)',
'-Wl,-rpath,@loader_path/../../DEPS/<(bin)',
],
'defines': ['__APPLE__'],
}
],
[
'OS=="win"',
{
'defines' : [
'WIN32_LEAN_AND_MEAN',
'VC_EXTRALEAN',
'_WIN32',
],
'msvs_settings' : {
'VCCLCompilerTool' : {
'AdditionalOptions' : [
'/GL', '/GF', '/EHsc', '/GS', '/Gy', '/GR-',
]
},
'VCLinkerTool' : {
'AdditionalOptions' : ['/RELEASE','/OPT:REF','/OPT:ICF','/LTCG'],
},
},
},
],
],
},
]
}
```
</details>

28
download.js Normal file
View File

@ -0,0 +1,28 @@
'use strict';
const https = require('https');
const http = require('http');
const WritableBuffer = require('./writable-buffer');
const protocols = { http, https };
module.exports = url => new Promise((res, rej) => {
url = url.toLowerCase();
const stream = new WritableBuffer();
const proto = protocols[url.match(/^https?/)[0]];
proto.get(url, response => {
response.pipe(stream);
response.on('end', () => res(stream.get()));
response.on('error', err => rej(err));
});
});

View File

@ -11,12 +11,6 @@
#endif #endif
#ifdef _WIN32
#define DBG_EXPORT __declspec(dllexport)
#else
#define DBG_EXPORT
#endif
#define NAPI_ENV Napi::Env env = info.Env(); #define NAPI_ENV Napi::Env env = info.Env();
#define NAPI_HS Napi::HandleScope scope(env); #define NAPI_HS Napi::HandleScope scope(env);
@ -55,13 +49,13 @@
#define CHECK_REQ_ARG(I, C, T) \ #define CHECK_REQ_ARG(I, C, T) \
if (info.Length() <= (I) || !info[I].C) { \ if (info.Length() <= (I) || ! info[I].C) { \
JS_THROW("Argument " #I " must be of type `" T "`"); \ JS_THROW("Argument " #I " must be of type `" T "`"); \
RET_UNDEFINED; \ RET_UNDEFINED; \
} }
#define CHECK_LET_ARG(I, C, T) \ #define CHECK_LET_ARG(I, C, T) \
if (!(IS_ARG_EMPTY(I) || info[I].C)) { \ if ( ! (IS_ARG_EMPTY(I) || info[I].C) ) { \
JS_THROW( \ JS_THROW( \
"Argument " #I \ "Argument " #I \
" must be of type `" T \ " must be of type `" T \
@ -191,7 +185,7 @@
#define REQ_ARRV_ARG(I, VAR) \ #define REQ_ARRV_ARG(I, VAR) \
CHECK_REQ_ARG(I, IsArrayBuffer(), "ArrayBuffer"); \ CHECK_REQ_ARG(I, IsArrayBuffer(), "ArrayBuffer"); \
Napi::ArrayBuffer VAR = info[I].As<Napi::ArrayBuffer>(); Napi::ArrayBuffer VAR = info[I].As<Napi::ArrayBuffer>();
@ -200,57 +194,17 @@
Napi::Buffer<uint8_t> VAR = info[I].As< Napi::Buffer<uint8_t> >(); Napi::Buffer<uint8_t> VAR = info[I].As< Napi::Buffer<uint8_t> >();
#define REQ_ARRAY_ARG(I, VAR) \ #define REQ_ARRAY_ARG(I, VAR) \
CHECK_REQ_ARG(I, IsArray(), "Array"); \ CHECK_REQ_ARG(I, IsArray(), "Array"); \
Napi::Array VAR = info[I].As<Napi::Array>(); Napi::Array VAR = info[I].As<Napi::Array>();
#define USE_ARRAY_ARG(I, VAR, DEF) \ #define USE_ARRAY_ARG(I, VAR, DEF) \
CHECK_LET_ARG(I, IsArray(), "Array"); \ CHECK_LET_ARG(I, IsArray(), "Array"); \
Napi::Array VAR = IS_ARG_EMPTY(I) ? (DEF) : info[I].As<Napi::Array>(); Napi::Array VAR = IS_ARG_EMPTY(I) ? (DEF) : info[I].As<Napi::Array>();
#define LET_ARRAY_ARG(I, VAR) USE_ARRAY_ARG(I, VAR, Napi::Array::New(env)) #define LET_ARRAY_ARG(I, VAR) USE_ARRAY_ARG(I, VAR, Napi::Array::New(env))
inline std::vector<std::string> arrayStrToVec(const Napi::Array &arr) {
uint32_t count = arr.Length();
std::vector<std::string> result(count);
for (uint32_t i = 0; i < count; i++) {
Napi::Value item = arr[i];
if (item.IsString()) {
result[i] = item.ToString().Utf8Value();
}
}
return result;
}
inline Napi::Array stringsToArray(Napi::Env env, const char **strings, size_t count) {
Napi::Array arr = JS_ARRAY;
for (size_t i = 0; i < count; i++) {
arr.Set(i, strings[i]);
}
return arr;
}
inline Napi::Array vecStrToArray(Napi::Env env, const std::vector<std::string> &strings) {
Napi::Array arr = JS_ARRAY;
size_t count = strings.size();
for (size_t i = 0; i < count; i++) {
arr.Set(i, strings[i]);
}
return arr;
}
#define LET_ARRAY_STR_ARG(I, VAR) \
USE_ARRAY_ARG(I, __ARRAY_ ## VAR, Napi::Array::New(env)); \
std::vector<std::string> VAR = arrayStrToVec(__ARRAY_ ## VAR);
#define RET_ARRAY_STR(VAL) RET_VALUE(vecStrToArray(env, VAL))
#define REQ_TYPED_ARRAY_ARG(I, VAR) \ #define REQ_TYPED_ARRAY_ARG(I, VAR) \
CHECK_REQ_ARG(I, IsTypedArray(), "TypedArray"); \ CHECK_REQ_ARG(I, IsTypedArray(), "TypedArray"); \
Napi::TypedArray VAR = info[I].As<Napi::TypedArray>(); Napi::TypedArray VAR = info[I].As<Napi::TypedArray>();
@ -270,7 +224,7 @@ inline Napi::Array vecStrToArray(Napi::Env env, const std::vector<std::string> &
CACHE = V; CACHE = V;
#define SETTER_CHECK(C, T) \ #define SETTER_CHECK(C, T) \
if (!value.C) { \ if ( ! value.C ) { \
JS_THROW("Value must be " T); \ JS_THROW("Value must be " T); \
RET_UNDEFINED; \ RET_UNDEFINED; \
} }
@ -376,6 +330,7 @@ inline Type* getArrayData(
Napi::Object obj, Napi::Object obj,
int *num = nullptr int *num = nullptr
) { ) {
Type *out = nullptr; Type *out = nullptr;
if (obj.IsTypedArray()) { if (obj.IsTypedArray()) {
@ -383,7 +338,7 @@ inline Type* getArrayData(
size_t offset = ta.ByteOffset(); size_t offset = ta.ByteOffset();
Napi::ArrayBuffer arr = ta.ArrayBuffer(); Napi::ArrayBuffer arr = ta.ArrayBuffer();
if (num) { if (num) {
*num = ta.ByteLength() / sizeof(Type); *num = arr.ByteLength() / sizeof(Type);
} }
uint8_t *base = reinterpret_cast<uint8_t *>(arr.Data()); uint8_t *base = reinterpret_cast<uint8_t *>(arr.Data());
out = reinterpret_cast<Type *>(base + offset); out = reinterpret_cast<Type *>(base + offset);
@ -401,22 +356,23 @@ inline Type* getArrayData(
} }
return out; return out;
} }
template<typename Type = uint8_t> template<typename Type = uint8_t>
inline Type* getBufferData( inline Type* getBufferData(
Napi::Env env, Napi::Env env,
Napi::Object obj, Napi::Object obj,
int *num = nullptr int *num = nullptr
) { ) {
Type *out = nullptr; Type *out = nullptr;
if (num) { if (num) {
*num = 0; *num = 0;
} }
if (!obj.IsBuffer()) { if ( ! obj.IsBuffer() ) {
JS_THROW("Argument must be of type `Buffer`."); JS_THROW("Argument must be of type `Buffer`.");
return out; return out;
} }
@ -428,10 +384,12 @@ inline Type* getBufferData(
out = arr.Data(); out = arr.Data();
return out; return out;
} }
inline void *getData(Napi::Env env, Napi::Object obj) { inline void *getData(Napi::Env env, Napi::Object obj) {
void *out = nullptr; void *out = nullptr;
if (obj.IsTypedArray() || obj.IsArrayBuffer()) { if (obj.IsTypedArray() || obj.IsArrayBuffer()) {
@ -448,6 +406,7 @@ inline void *getData(Napi::Env env, Napi::Object obj) {
} }
return out; return out;
} }
@ -477,10 +436,10 @@ inline void eventEmit(
Napi::Object that, Napi::Object that,
const std::string &name, const std::string &name,
int argc = 0, int argc = 0,
const Napi::Value *argv = nullptr, const Napi::Value *argv = nullptr
napi_async_context context = nullptr
) { ) {
if (!that.Has("emit")) {
if ( ! that.Has("emit") ) {
return; return;
} }
@ -495,11 +454,36 @@ inline void eventEmit(
args.push_back(napi_value(argv[i])); args.push_back(napi_value(argv[i]));
} }
if (context) { thatEmit.Call(that, args);
thatEmit.MakeCallback(that, args, context);
} else { }
thatEmit.Call(that, args);
inline void eventEmitAsync(
Napi::Object that,
const std::string &name,
int argc = 0,
const Napi::Value *argv = nullptr,
napi_async_context context = nullptr
) {
if ( ! that.Has("emit") ) {
return;
} }
Napi::Env env = that.Env();
Napi::String eventName = JS_STR(name);
Napi::Function thatEmit = that.Get("emit").As<Napi::Function>();
std::vector<napi_value> args;
args.push_back(napi_value(eventName));
for (int i = 0; i < argc; i++) {
args.push_back(napi_value(argv[i]));
}
thatEmit.MakeCallback(that, args, context);
} }

View File

@ -1,65 +0,0 @@
'use strict';
const path = require('node:path');
const nameWindows = 'windows';
const platformAndArch = `${process.platform}-${process.arch}`;
const platformNames = {
'win32-x64': nameWindows,
'linux-x64': 'linux',
'darwin-x64': 'osx',
'linux-arm64': 'aarch64',
};
const platformName = platformNames[platformAndArch] || platformAndArch;
const isWindows = platformName === nameWindows;
const getPaths = (dir) => {
dir = dir.replace(/\\/g, '/');
const bin = `${dir}/bin-${platformName}`;
const include = `${dir}/include`;
if (isWindows) {
process.env.path = `${bin};${process.env.path ? `${process.env.path}` : ''}`;
}
return { bin, include };
};
const getBin = () => {
return `bin-${platformName}`;
};
const getPlatform = () => {
return platformName;
};
const getInclude = () => {
let napi = null;
try {
napi = require('node-addon-api');
} catch (ex) {
// do nothing
}
const rootPath = path.resolve(`${__dirname}/..`).replace(/\\/g, '/');
const napiInclude = napi ? napi.include_dir.replace(/\\/g, '/') : '';
const thisInclude = `${rootPath}/include`;
const includePath = `${napiInclude} ${thisInclude}`;
return includePath;
};
module.exports = {
getPaths,
getBin,
getPlatform,
getInclude,
};

View File

@ -1,41 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const tools = require('.');
describe('AT / include', () => {
const stringMethods = ['getBin', 'getPlatform', 'getInclude'];
stringMethods.forEach((name) => {
describe(`#${name}()`, () => {
it('is a function', () => {
assert.strictEqual(typeof tools[name], 'function');
});
it('returns an object', () => {
assert.strictEqual(typeof tools[name](), 'string');
});
});
});
describe('#getPaths()', () => {
it('is a function', () => {
assert.strictEqual(typeof tools.getPaths, 'function');
});
it('returns an object', () => {
assert.strictEqual(typeof tools.getPaths(__dirname), 'object');
});
it('has "include" string', () => {
assert.strictEqual(typeof tools.getPaths(__dirname).include, 'string');
});
it('has "bin" string', () => {
assert.strictEqual(typeof tools.getPaths(__dirname).include, 'string');
});
});
});

View File

@ -1,81 +0,0 @@
# Snippets
## C++ Addon building
### Binary distribution
In **package.json** use the `"postinstall"` script to download the libraries.
For example the following structure might work. Note that **Addon Tools** will
append any given URL with `/${getPlatform()}.gz`
In **package.json**:
```
"scripts": {
"postinstall": "node install",
},
"dependencies": {
"addon-tools-raub": "^7.0.0",
},
"devDependencies": {
"node-addon-api": "^5.0.0"
}
```
Create the **install.js** file, see `install` in [index.d.ts](/index.d.ts).
**Addon Tools** will unpack (using **tar**) the downloaded file into the platform binary
directory. E.g. on Windows it will be **bin-windows**.
* For a dependency package:
Place the following piece of code into the `index.js` without changes.
```
module.exports = require('addon-tools-raub').getPaths(__dirname);
```
* For a compiled addon:
Require the `ADDON.node` in your **index.js** from the platform-specific directory.
```
const { getBin } = require('addon-tools-raub');
const core = require(`./${getBin()}/ADDON`);
```
Publishing binaries is done by attaching a GZIPped platform folder to a GitHub
release. Zip file must NOT contain platform folder as a subfolder, but rather
contain the final binaries. The tag of the release should be the same as in
**install.js**.
> NOTE: You can publish your binaries to anywhere, not necessarily GitHub.
Just tweak **YOUR install.js** script as appropriate. The only limitation
from **Addon Tools** is that it should be a GZIPped set of files/folders.
### GYP Variables
```
'variables': {
'bin': '<!(node -p "require(\'addon-tools-raub\').getBin()")',
'DEPS_include': '<!(node -p "require(\'DEPS\').getInclude()")',
'DEPS_bin': '<!(node -p "require(\'DEPS\').getBin()")',
},
```
* `bin` - the name of this platform's binary directory, e.g. *bin-linux*.
* `DEPS_include` - the include folder for some dependency package.
* `DEPS_bin` - the binary folder for some dependency package.
### Include directories
```
'include_dirs' : [
'<!@(node -p "require(\'addon-tools-raub\').getInclude()")',
'<(DEPS_include)',
],
```
See example of a working [**binding.gyp** here](/test-addon/binding.gyp)

361
index.d.ts vendored
View File

@ -1,361 +0,0 @@
declare module "addon-tools-raub" {
type Stats = import('node:fs').Stats;
type Writable = import('node:stream').Writable;
type Readable = import('node:stream').Readable;
type WritableOptions = import('node:stream').WritableOptions;
/**
* Get the internal paths for an addon
*
* Returns a set of platform dependent paths depending on the input dir
*/
export const getPaths: (dir: string) => Readonly<{
/**
* Path to binaries
*
* Platform binary directory absolute path for this `dir`
*/
bin: string;
/**
* Path to include
*
* Include directory for this `dir`
*/
include: string;
}>;
type TPlatformName = 'windows' | 'linux' | 'osx' | 'aarch64';
type TPlatformDir = `bin-${TPlatformName}`;
/**
* Get the platform-specific binary directory name
*/
export const getBin: () => TPlatformDir;
/**
* Get the platform identifier
*/
export const getPlatform: () => TPlatformName;
/**
* Get the include directories for **binding.gyp**
*
* Both 'addon-tools-raub' and 'node-addon-api' include paths.
* In binding.gyp: `'<!@(node -p "require(\'addon-tools-raub\').getInclude()")'`
*/
export const getInclude: () => string;
/**
* Install binaries
*
* Downloads and unpacks the platform specific binary for the calling package.
* To use it, create a new script for your package, which may as well be named
* **install.js**, with the following content:
*
* ```
* 'use strict';
* const { install } = require('addon-tools-raub');
* const prefix = 'https://github.com/USER/ADDON-NAME/releases/download';
* const tag = '1.0.0';
* install(`${prefix}/${tag}`);
* ```
*
* * `prefix` - the constant base part of the download url.
* * `tag` - the version-dependent part of the url.
*
* ```
* "scripts": {
* "postinstall": "node install"
* },
* ```
*/
export const install: (folder: string) => Promise<boolean>;
/**
* Copy binary
*
* Copies the addon binary from `src/build/Release` to the platform-specific folder.
*
* ```
* "scripts": {
* * "build": "node-gyp rebuild && node -e \"require('addon-tools-raub').cpbin('ADDON')\""
* },
* ```
*
* Here ADDON should be replaced with the name of your addon, without `.node` extension.
*/
export const cpbin: (name: string) => Promise<void>;
/**
* Packs binaries into GZIP
*
* Example of `actionPack` usage in **Github Actions**:
*
* ```
* - name: Pack Files
* id: pack-files
* run: node -e "require('addon-tools-raub').actionPack()" >> $GITHUB_OUTPUT
* - name: Store Binaries
* uses: softprops/action-gh-release@v1
* with:
* files: ${{ steps.pack-files.outputs.pack }}
* ```
*/
export const actionPack: () => Promise<void>;
/**
* Download to memory
*
* Accepts an **URL**, and returns an in-memory file Buffer,
* when the file is loaded. Use for small files, as the whole
* file will be loaded into memory at once.
*
* ```
* download(srcUrl).then(data => useData(data), err => emit('error', err));
* ```
* or
* ```
* const data = await download(srcUrl);
* useData(data);
* ```
*/
export const download: (url: string) => Promise<Buffer>;
/**
* (async) Read a file
*
* Reads a whole file to string, NOT A Buffer
*/
type ComposeFnParam = (source: any) => void;
/**
* WritableBuffer
*
* 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`.
*/
export class WritableBuffer implements Writable {
constructor();
/**
* Get the downloaded data
* Use `stream.get()` to obtain the data when writing was finished
*/
get(): Buffer;
// ----------- implements Writable
readonly writable: boolean;
readonly writableEnded: boolean;
readonly writableFinished: boolean;
readonly writableHighWaterMark: number;
readonly writableLength: number;
readonly writableObjectMode: boolean;
readonly writableCorked: number;
destroyed: boolean;
readonly closed: boolean;
readonly errored: Error | null;
readonly writableNeedDrain: boolean;
constructor(opts?: WritableOptions);
_write(chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void;
_writev?(
chunks: Array<{
chunk: any;
encoding: BufferEncoding;
}>,
callback: (error?: Error | null) => void,
): void;
_construct?(callback: (error?: Error | null) => void): void;
_destroy(error: Error | null, callback: (error?: Error | null) => void): void;
_final(callback: (error?: Error | null) => void): void;
write(chunk: any, callback?: (error: Error | null | undefined) => void): boolean;
write(chunk: any, encoding: BufferEncoding, callback?: (error: Error | null | undefined) => void): boolean;
setDefaultEncoding(encoding: BufferEncoding): this;
end(cb?: () => void): this;
end(chunk: any, cb?: () => void): this;
end(chunk: any, encoding: BufferEncoding, cb?: () => void): this;
cork(): void;
uncork(): void;
destroy(error?: Error): this;
addListener(event: "close", listener: () => void): this;
addListener(event: "drain", listener: () => void): this;
addListener(event: "error", listener: (err: Error) => void): this;
addListener(event: "finish", listener: () => void): this;
addListener(event: "pipe", listener: (src: Readable) => void): this;
addListener(event: "unpipe", listener: (src: Readable) => void): this;
addListener(event: string | symbol, listener: (...args: any[]) => void): this;
emit(event: "close"): boolean;
emit(event: "drain"): boolean;
emit(event: "error", err: Error): boolean;
emit(event: "finish"): boolean;
emit(event: "pipe", src: Readable): boolean;
emit(event: "unpipe", src: Readable): boolean;
emit(event: string | symbol, ...args: any[]): boolean;
on(event: "close", listener: () => void): this;
on(event: "drain", listener: () => void): this;
on(event: "error", listener: (err: Error) => void): this;
on(event: "finish", listener: () => void): this;
on(event: "pipe", listener: (src: Readable) => void): this;
on(event: "unpipe", listener: (src: Readable) => void): this;
on(event: string | symbol, listener: (...args: any[]) => void): this;
once(event: "close", listener: () => void): this;
once(event: "drain", listener: () => void): this;
once(event: "error", listener: (err: Error) => void): this;
once(event: "finish", listener: () => void): this;
once(event: "pipe", listener: (src: Readable) => void): this;
once(event: "unpipe", listener: (src: Readable) => void): this;
once(event: string | symbol, listener: (...args: any[]) => void): this;
prependListener(event: "close", listener: () => void): this;
prependListener(event: "drain", listener: () => void): this;
prependListener(event: "error", listener: (err: Error) => void): this;
prependListener(event: "finish", listener: () => void): this;
prependListener(event: "pipe", listener: (src: Readable) => void): this;
prependListener(event: "unpipe", listener: (src: Readable) => void): this;
prependListener(event: string | symbol, listener: (...args: any[]) => void): this;
prependOnceListener(event: "close", listener: () => void): this;
prependOnceListener(event: "drain", listener: () => void): this;
prependOnceListener(event: "error", listener: (err: Error) => void): this;
prependOnceListener(event: "finish", listener: () => void): this;
prependOnceListener(event: "pipe", listener: (src: Readable) => void): this;
prependOnceListener(event: "unpipe", listener: (src: Readable) => void): this;
prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;
removeListener(event: "close", listener: () => void): this;
removeListener(event: "drain", listener: () => void): this;
removeListener(event: "error", listener: (err: Error) => void): this;
removeListener(event: "finish", listener: () => void): this;
removeListener(event: "pipe", listener: (src: Readable) => void): this;
removeListener(event: "unpipe", listener: (src: Readable) => void): this;
removeListener(event: string | symbol, listener: (...args: any[]) => void): this;
pipe<T extends NodeJS.WritableStream>(
destination: T,
options?: {
end?: boolean | undefined;
},
): T;
compose<T extends NodeJS.ReadableStream>(
stream: T | ComposeFnParam | Iterable<T> | AsyncIterable<T>,
options?: { signal: AbortSignal },
): T;
off(eventName: string | symbol, listener: (...args: any[]) => void): this;
removeAllListeners(event?: string | symbol): this;
setMaxListeners(n: number): this;
getMaxListeners(): number;
listeners(eventName: string | symbol): Function[];
rawListeners(eventName: string | symbol): Function[];
emit(eventName: string | symbol, ...args: any[]): boolean;
listenerCount(eventName: string | symbol, listener?: Function): number;
eventNames(): Array<string | symbol>;
}
export const read: (name: string) => Promise<string>;
/**
* (async) Write a file
*/
export const write: (name: string, text: string) => Promise<void>;
/**
* (async) Copy a file
*/
export const copy: (src: string, dest: string) => Promise<void>;
/**
* (async) Check if a file/folder exists
*/
export const exists: (name: string) => Promise<boolean>;
/**
* (async) Create an empty folder
*/
export const mkdir: (name: string) => Promise<void>;
/**
* (async) Get status on a file
*/
export const stat: (name: string) => Promise<Stats>;
/**
* (async) Check if the path is a folder
*/
export const isDir: (name: string) => Promise<boolean>;
/**
* (async) Check if the path is a file
*/
export const isFile: (name: string) => Promise<boolean>;
/**
* Cut the path one folder up
*/
export const dirUp: (dir: string) => string;
/**
* (async) Create a directory
*
* Like `mkdir -p`, makes sure a directory exists
*/
export const ensuredir: (dir: string) => Promise<void>;
/**
* (async) Copy a file
*
* Copy a file, `dest` folder is created if needed
*/
export const copysafe: (src: string, dest: string) => Promise<void>;
/**
* (async) Read a directory
*
* Get file/folder names of the 1st level
*/
export const readdir: (src: string, dest: string) => Promise<ReadonlyArray<string>>;
/**
* (async) List subdirectories
*
* Get folder paths (concatenated with input) of the 1st level
*/
export const subdirs: (name: string) => Promise<ReadonlyArray<string>>;
/**
* (async) List nested files
*
* Get file paths (concatenated with input) of the 1st level
*/
export const subfiles: (name: string) => Promise<ReadonlyArray<string>>;
/**
* (async) Get all nested files recursively
*
* Folder paths are omitted by default.
* Order is: shallow-to-deep, each subdirectory lists dirs-then-files.
*/
export const traverse: (name: string, showDirs?: boolean) => Promise<ReadonlyArray<string>>;
/**
* (async) Copy a directory
*
* Copy a folder with all the contained files
*/
export const copyall: (src: string, dest: string) => Promise<void>;
/**
* (async) Remove a directory
*
* Like `rm -rf`, removes everything recursively
*/
export const rmdir: (name: string) => Promise<void>;
/**
* (async) Remove a file
*
* Must be a file, not a folder. Just `fs.unlink`.
*/
export const rm: (name: string) => Promise<void>;
}

View File

@ -1,3 +1,48 @@
'use strict'; 'use strict';
module.exports = Object.assign({}, require('./include'), require('./utils')); const platformNames = {
win32 : 'windows',
linux : 'linux',
darwin : 'osx',
};
const platformName = platformNames[process.platform];
const isWindows = process.platform === 'win32';
if ( ! platformName ) {
console.log(`Error: UNKNOWN PLATFORM "${process.platform}"`);
}
const rootPath = __dirname.replace(/\\/g, '/');
const napiInclude = require('node-addon-api').include.replace(/\\/g, '/');
const thisInclude = `${rootPath}/include`;
const includePath = `${napiInclude} ${thisInclude}`;
const paths = dir => {
dir = dir.replace(/\\/g, '/');
const bin = `${dir}/bin-${platformName}`;
const include = `${dir}/include`;
if (isWindows) {
process.env.path = `${bin};${process.env.path ? `${process.env.path}` : ''}`;
}
return { bin, include };
};
module.exports = {
paths,
bin : `bin-${platformName}`,
platform : platformName,
include : includePath,
};

74
install.js Normal file
View File

@ -0,0 +1,74 @@
'use strict';
const https = require('https');
const http = require('http');
const fs = require('fs');
const AdmZip = require('adm-zip');
const { bin, platform } = require('.');
const { mkdir, rm } = require('./utils');
const protocols = { http, https };
const onError = msg => {
console.error(msg);
process.exit(-1);
};
const zipPath = `${bin}/${bin}.zip`;
const install = async (url, count = 1) => {
try {
const proto = protocols[url.match(/^https?/)[0]];
const response = await new Promise((res, rej) => {
const request = proto.get(url, response => res(response));
request.on('error', err => rej(err));
});
response.on('error', err => { throw err; });
// Handle redirects
if ([301, 302, 303, 307].includes(response.statusCode)) {
if (count < 5) {
return install(response.headers.location, count + 1);
}
console.log(url);
throw new Error('Error: Too many redirects.');
}
// Handle bad status
if (response.statusCode !== 200) {
console.log(url);
throw new Error(`Response status was ${response.statusCode}`);
}
await mkdir(bin);
await new Promise((res, rej) => {
const zipWriter = fs.createWriteStream(zipPath);
zipWriter.on('error', err => rej(err));
zipWriter.on('finish', () => res());
response.pipe(zipWriter);
});
const zip = new AdmZip(zipPath);
zip.extractAllTo(bin, true);
await rm(zipPath);
} catch (ex) {
onError(ex.message);
}
};
module.exports = folder => {
const url = `${folder}/${platform}.zip`;
install(url).then();
};

1311
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{ {
"author": "Luis Blanco <luisblanco1337@gmail.com>", "author": "Luis Blanco <luisblanco1337@gmail.com>",
"name": "addon-tools-raub", "name": "addon-tools-raub",
"version": "7.4.0", "version": "5.1.0",
"description": "Helpers for Node.js addons and dependency packages", "description": "Helpers for Node.js addons and dependency packages",
"license": "MIT", "license": "MIT",
"main": "index.js", "main": "index.js",
@ -19,42 +19,26 @@
], ],
"files": [ "files": [
"include", "include",
"utils.js", "download.js",
"utils.d.ts", "cpbin.js",
"index.js", "index.js",
"index.d.ts", "install.js",
"utils", "utils.js",
"writable-buffer.js",
"LICENSE", "LICENSE",
"package.json", "package.json",
"README.md" "README.md"
], ],
"engines": { "engines": {
"node": ">=18.16.0", "node": ">=12.13.0",
"npm": ">=9.5.1" "npm": ">=6.12.0"
},
"scripts": {
"eslint": "eslint .",
"test": "node --test --watch .",
"test-ci": "node --test",
"build-test": "cd test-addon && node-gyp rebuild -j max --silent && cd .."
}, },
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/node-3d/addon-tools-raub.git" "url": "https://github.com/node-3d/addon-tools-raub.git"
}, },
"peerDependencies": { "dependencies": {
"node-addon-api": "^7.0.0" "adm-zip": "0.4.14",
}, "node-addon-api": "2.0.0"
"peerDependenciesMeta": {
"node-addon-api": {
"optional": true
}
},
"devDependencies": {
"@types/node": "^20.8.3",
"eslint": "^8.51.0",
"eslint-plugin-node": "^11.1.0",
"node-addon-api": "^7.0.0",
"typescript": "^5.2.2"
} }
} }

View File

@ -1,37 +0,0 @@
{
'targets': [{
'target_name': 'test',
'sources': [
'test.cpp',
],
'cflags_cc': ['-std=c++17', '-fno-exceptions'],
'include_dirs': [
'<!@(node -p "require(\'..\').getInclude()")',
],
'conditions': [
['OS=="linux"', {
'defines': ['__linux__'],
}],
['OS=="mac"', {
'MACOSX_DEPLOYMENT_TARGET': '10.9',
'defines': ['__APPLE__'],
'CLANG_CXX_LIBRARY': 'libc++',
'OTHER_CFLAGS': ['-std=c++17', '-fno-exceptions'],
}],
['OS=="win"', {
'defines' : ['WIN32_LEAN_AND_MEAN', 'VC_EXTRALEAN', '_WIN32', '_HAS_EXCEPTIONS=0'],
'msvs_settings' : {
'VCCLCompilerTool' : {
'AdditionalOptions' : [
'/O2','/Oy','/GL','/GF','/Gm-', '/std:c++17',
'/EHa-s-c-','/MT','/GS','/Gy','/GR-','/Gd',
],
},
'VCLinkerTool' : {
'AdditionalOptions' : ['/DEBUG:NONE', '/LTCG', '/OPT:NOREF'],
},
},
}],
],
}],
}

View File

@ -1,45 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const test = require('./build/Release/test.node');
const arrayArgLetMsg = { message: 'Argument 0 must be of type `Array` or be `null`/`undefined`' };
describe('AT / HPP / LET_ARRAY_ARG', () => {
it('exports letArrayStrArg', () => {
assert.strictEqual(typeof test.letArrayStrArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.letArrayStrArg('1'), arrayArgLetMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.letArrayStrArg(1), arrayArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.letArrayStrArg(true), arrayArgLetMsg);
});
it('throws if arg was passed a pointer', () => {
assert.throws(() => test.letArrayStrArg(test.retExt()), arrayArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.letArrayStrArg({}), arrayArgLetMsg);
});
it('accepts an empty arg', () => {
assert.ok(Array.isArray(test.letArrayStrArg()));
});
it('accepts undefined', () => {
assert.ok(Array.isArray(test.letArrayStrArg(undefined)));
});
it('accepts null', () => {
assert.ok(Array.isArray(test.letArrayStrArg(null)));
});
it('accepts an array', () => {
assert.ok(Array.isArray(test.letArrayStrArg([])));
});
it('returns same array', () => {
assert.deepStrictEqual(test.letArrayStrArg(['a', 'b']),['a', 'b']);
});
});

View File

@ -1,109 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const test = require('./build/Release/test.node');
const arrayArgMsg = { message: 'Argument 0 must be of type `Array`' };
const arrayArgLetMsg = { message: 'Argument 0 must be of type `Array` or be `null`/`undefined`' };
describe('AT / HPP / REQ_ARRAY_ARG', () => {
it('exports reqArrayArg', () => {
assert.strictEqual(typeof test.reqArrayArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqArrayArg(), arrayArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqArrayArg(undefined), arrayArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqArrayArg(null), arrayArgMsg);
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.reqArrayArg('1'), arrayArgMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.reqArrayArg(1), arrayArgMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.reqArrayArg(true), arrayArgMsg);
});
it('throws if arg was passed a pointer', () => {
assert.throws(() => test.reqArrayArg(test.retExt()), arrayArgMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.reqArrayArg({}), arrayArgMsg);
});
it('accepts an array', () => {
assert.ok(Array.isArray(test.reqArrayArg([])));
});
});
describe('addon-tools.hpp: LET_ARRAY_ARG', () => {
it('exports letArrayArg', () => {
assert.strictEqual(typeof test.letArrayArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.letArrayArg('1'), arrayArgLetMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.letArrayArg(1), arrayArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.letArrayArg(true), arrayArgLetMsg);
});
it('throws if arg was passed a pointer', () => {
assert.throws(() => test.letArrayArg(test.retExt()), arrayArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.letArrayArg({}), arrayArgLetMsg);
});
it('accepts an empty arg', () => {
assert.ok(Array.isArray(test.letArrayArg()));
});
it('accepts undefined', () => {
assert.ok(Array.isArray(test.letArrayArg(undefined)));
});
it('accepts null', () => {
assert.ok(Array.isArray(test.letArrayArg(null)));
});
it('accepts an array', () => {
assert.ok(Array.isArray(test.letArrayArg([])));
});
});
describe('addon-tools.hpp: USE_ARRAY_ARG', () => {
it('exports useArrayArg', () => {
assert.strictEqual(typeof test.useArrayArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.useArrayArg('1'), arrayArgLetMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.useArrayArg(1), arrayArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.useArrayArg(true), arrayArgLetMsg);
});
it('throws if arg was passed a pointer', () => {
assert.throws(() => test.useArrayArg(test.retExt()), arrayArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.useArrayArg({}), arrayArgLetMsg);
});
it('accepts an empty arg', () => {
assert.ok(Array.isArray(test.useArrayArg()));
});
it('accepts undefined', () => {
assert.ok(Array.isArray(test.useArrayArg(undefined)));
});
it('accepts null', () => {
assert.ok(Array.isArray(test.useArrayArg(null)));
});
it('accepts an array', () => {
assert.ok(Array.isArray(test.useArrayArg([])));
});
});

View File

@ -1,100 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const test = require('./build/Release/test.node');
const boolArgMsg = { message: 'Argument 0 must be of type `Bool`' };
const boolArgLetMsg = { message: 'Argument 0 must be of type `Bool` or be `null`/`undefined`' };
describe('AT / HPP / REQ_BOOL_ARG', () => {
it('exports reqBoolArg', () => {
assert.strictEqual(typeof test.reqBoolArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqBoolArg(), boolArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqBoolArg(undefined), boolArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqBoolArg(null), boolArgMsg);
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.reqBoolArg('1'), boolArgMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.reqBoolArg(1), boolArgMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.reqBoolArg({}), boolArgMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.reqBoolArg([]), boolArgMsg);
});
it('accepts a boolean', () => {
assert.ok(test.reqBoolArg(true));
});
});
describe('addon-tools.hpp: LET_BOOL_ARG', () => {
it('exports letBoolArg', () => {
assert.strictEqual(typeof test.letBoolArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.letBoolArg('1'), boolArgLetMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.letBoolArg(1), boolArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.letBoolArg({}), boolArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.letBoolArg([]), boolArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(test.letBoolArg(), false);
});
it('accepts undefined', () => {
assert.strictEqual(test.letBoolArg(undefined), false);
});
it('accepts null', () => {
assert.strictEqual(test.letBoolArg(null), false);
});
it('accepts a boolean', () => {
assert.ok(test.letBoolArg(true));
});
});
describe('addon-tools.hpp: USE_BOOL_ARG', () => {
it('exports useBoolArg', () => {
assert.strictEqual(typeof test.useBoolArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.useBoolArg('1'), boolArgLetMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.useBoolArg(1), boolArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.useBoolArg({}), boolArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.useBoolArg([]), boolArgLetMsg);
});
it('accepts an empty arg', () => {
assert.ok(test.useBoolArg());
});
it('accepts undefined', () => {
assert.ok(test.useBoolArg(undefined));
});
it('accepts null', () => {
assert.ok(test.useBoolArg(null));
});
it('accepts a boolean', () => {
assert.ok(test.useBoolArg(true));
});
});

View File

@ -1,100 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const test = require('./build/Release/test.node');
const numArgMsg = { message: 'Argument 0 must be of type `Number`' };
const numArgLetMsg = { message: 'Argument 0 must be of type `Number` or be `null`/`undefined`' };
describe('AT / HPP / REQ_DOUBLE_ARG', () => {
it('exports reqDoubleArg', () => {
assert.strictEqual(typeof test.reqDoubleArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqDoubleArg(), numArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqDoubleArg(undefined), numArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqDoubleArg(null), numArgMsg);
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.reqDoubleArg('1'), numArgMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.reqDoubleArg(true), numArgMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.reqDoubleArg({}), numArgMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.reqDoubleArg([]), numArgMsg);
});
it('accepts a number', () => {
assert.strictEqual(test.reqDoubleArg(55), 55);
});
});
describe('addon-tools.hpp: LET_DOUBLE_ARG', () => {
it('exports letDoubleArg', () => {
assert.strictEqual(typeof test.letDoubleArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.letDoubleArg('1'), numArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.letDoubleArg(true), numArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.letDoubleArg({}), numArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.letDoubleArg([]), numArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(test.letDoubleArg(), 0);
});
it('accepts undefined', () => {
assert.strictEqual(test.letDoubleArg(undefined), 0);
});
it('accepts null', () => {
assert.strictEqual(test.letDoubleArg(null), 0);
});
it('accepts a number', () => {
assert.strictEqual(test.letDoubleArg(55), 55);
});
});
describe('addon-tools.hpp: USE_DOUBLE_ARG', () => {
it('exports useDoubleArg', () => {
assert.strictEqual(typeof test.useDoubleArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.useDoubleArg('1'), numArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.useDoubleArg(true), numArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.useDoubleArg({}), numArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.useDoubleArg([]), numArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(test.useDoubleArg(), 10);
});
it('accepts undefined', () => {
assert.strictEqual(test.useDoubleArg(undefined), 10);
});
it('accepts null', () => {
assert.strictEqual(test.useDoubleArg(null), 10);
});
it('accepts a number', () => {
assert.strictEqual(test.useDoubleArg(55), 55);
});
});

View File

@ -1,109 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const test = require('./build/Release/test.node');
const extArgMsg = { message: 'Argument 0 must be of type `Pointer`' };
const extArgLetMsg = { message: 'Argument 0 must be of type `Pointer` or be `null`/`undefined`' };
describe('AT / HPP / REQ_EXT_ARG', () => {
it('exports reqExtArg', () => {
assert.strictEqual(typeof test.reqExtArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqExtArg(), extArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqExtArg(undefined), extArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqExtArg(null), extArgMsg);
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.reqExtArg('1'), extArgMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.reqExtArg(1), extArgMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.reqExtArg(true), extArgMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.reqExtArg({}), extArgMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.reqExtArg([]), extArgMsg);
});
it('accepts a pointer', () => {
assert.strictEqual(typeof test.reqExtArg(test.retExt()), 'object');
});
});
describe('addon-tools.hpp: LET_EXT_ARG', () => {
it('exports letExtArg', () => {
assert.strictEqual(typeof test.letExtArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.letExtArg('1'), extArgLetMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.letExtArg(1), extArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.letExtArg(true), extArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.letExtArg({}), extArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.letExtArg([]), extArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(typeof test.letExtArg(), 'object');
});
it('accepts undefined', () => {
assert.strictEqual(typeof test.letExtArg(undefined), 'object');
});
it('accepts null', () => {
assert.strictEqual(typeof test.letExtArg(null), 'object');
});
it('accepts a pointer', () => {
assert.strictEqual(typeof test.reqExtArg(test.retExt()), 'object');
});
});
describe('addon-tools.hpp: USE_EXT_ARG', () => {
it('exports useExtArg', () => {
assert.strictEqual(typeof test.useExtArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.useExtArg('1'), extArgLetMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.useExtArg(1), extArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.useExtArg(true), extArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.useExtArg({}), extArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.useExtArg([]), extArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(typeof test.useExtArg(), 'object');
});
it('accepts undefined', () => {
assert.strictEqual(typeof test.useExtArg(undefined), 'object');
});
it('accepts null', () => {
assert.strictEqual(typeof test.useExtArg(null), 'object');
});
it('accepts a number', () => {
assert.strictEqual(typeof test.useExtArg(test.retExt()), 'object');
});
});

View File

@ -1,100 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const test = require('./build/Release/test.node');
const numArgMsg = { message: 'Argument 0 must be of type `Number`' };
const numArgLetMsg = { message: 'Argument 0 must be of type `Number` or be `null`/`undefined`' };
describe('AT / HPP / REQ_FLOAT_ARG', () => {
it('exports reqFloatArg', () => {
assert.strictEqual(typeof test.reqFloatArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqFloatArg(), numArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqFloatArg(undefined), numArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqFloatArg(null), numArgMsg);
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.reqFloatArg('1'), numArgMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.reqFloatArg(true), numArgMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.reqFloatArg({}), numArgMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.reqFloatArg([]), numArgMsg);
});
it('accepts a number', () => {
assert.strictEqual(test.reqFloatArg(55), 55);
});
});
describe('addon-tools.hpp: LET_FLOAT_ARG', () => {
it('exports letFloatArg', () => {
assert.strictEqual(typeof test.letFloatArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.letFloatArg('1'), numArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.letFloatArg(true), numArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.letFloatArg({}), numArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.letFloatArg([]), numArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(test.letFloatArg(), 0);
});
it('accepts undefined', () => {
assert.strictEqual(test.letFloatArg(undefined), 0);
});
it('accepts null', () => {
assert.strictEqual(test.letFloatArg(null), 0);
});
it('accepts a number', () => {
assert.strictEqual(test.letFloatArg(55), 55);
});
});
describe('addon-tools.hpp: USE_FLOAT_ARG', () => {
it('exports useFloatArg', () => {
assert.strictEqual(typeof test.useFloatArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.useFloatArg('1'), numArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.useFloatArg(true), numArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.useFloatArg({}), numArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.useFloatArg([]), numArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(test.useFloatArg(), 10);
});
it('accepts undefined', () => {
assert.strictEqual(test.useFloatArg(undefined), 10);
});
it('accepts null', () => {
assert.strictEqual(test.useFloatArg(null), 10);
});
it('accepts a number', () => {
assert.strictEqual(test.useFloatArg(55), 55);
});
});

View File

@ -1,100 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const test = require('./build/Release/test.node');
const intArgMsg = { message: 'Argument 0 must be of type `Int32`' };
const intArgLetMsg = { message: 'Argument 0 must be of type `Int32` or be `null`/`undefined`' };
describe('AT / HPP / REQ_INT_ARG, REQ_INT32_ARG', () => {
it('exports reqIntArg', () => {
assert.strictEqual(typeof test.reqIntArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqIntArg(), intArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqIntArg(undefined), intArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqIntArg(null), intArgMsg);
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.reqIntArg('1'), intArgMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.reqIntArg(true), intArgMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.reqIntArg({}), intArgMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.reqIntArg([]), intArgMsg);
});
it('accepts a number', () => {
assert.strictEqual(test.reqIntArg(55), 55);
});
});
describe('addon-tools.hpp: LET_INT_ARG / LET_INT32_ARG', () => {
it('exports letIntArg', () => {
assert.strictEqual(typeof test.letIntArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.letIntArg('1'), intArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.letIntArg(true), intArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.letIntArg({}), intArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.letIntArg([]), intArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(test.letIntArg(), 0);
});
it('accepts undefined', () => {
assert.strictEqual(test.letIntArg(undefined), 0);
});
it('accepts null', () => {
assert.strictEqual(test.letIntArg(null), 0);
});
it('accepts a number', () => {
assert.strictEqual(test.letIntArg(55), 55);
});
});
describe('addon-tools.hpp: USE_INT_ARG / USE_INT32_ARG', () => {
it('exports useIntArg', () => {
assert.strictEqual(typeof test.useIntArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.useIntArg('1'), intArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.useIntArg(true), intArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.useIntArg({}), intArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.useIntArg([]), intArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(test.useIntArg(), 10);
});
it('accepts undefined', () => {
assert.strictEqual(test.useIntArg(undefined), 10);
});
it('accepts null', () => {
assert.strictEqual(test.useIntArg(null), 10);
});
it('accepts a number', () => {
assert.strictEqual(test.useIntArg(55), 55);
});
});

View File

@ -1,109 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const test = require('./build/Release/test.node');
const objArgMsg = { message: 'Argument 0 must be of type `Object`' };
const objArgLetMsg = { message: 'Argument 0 must be of type `Object` or be `null`/`undefined`' };
describe('AT / HPP / REQ_OBJ_ARG', () => {
it('exports reqObjArg', () => {
assert.strictEqual(typeof test.reqObjArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqObjArg(), objArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqObjArg(undefined), objArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqObjArg(null), objArgMsg);
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.reqObjArg('1'), objArgMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.reqObjArg(1), objArgMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.reqObjArg(true), objArgMsg);
});
it('throws if arg was passed a pointer', () => {
assert.throws(() => test.reqObjArg(test.retExt()), objArgMsg);
});
it('accepts an object', () => {
assert.strictEqual(typeof test.reqObjArg({}), 'object');
});
it('accepts an array', () => {
assert.ok(Array.isArray(test.reqObjArg([])));
});
});
describe('addon-tools.hpp: LET_OBJ_ARG', () => {
it('exports letObjArg', () => {
assert.strictEqual(typeof test.letObjArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.letObjArg('1'), objArgLetMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.letObjArg(1), objArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.letObjArg(true), objArgLetMsg);
});
it('throws if arg was passed a pointer', () => {
assert.throws(() => test.letObjArg(test.retExt()), objArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(typeof test.letObjArg(), 'object');
});
it('accepts undefined', () => {
assert.strictEqual(typeof test.letObjArg(undefined), 'object');
});
it('accepts null', () => {
assert.strictEqual(typeof test.letObjArg(null), 'object');
});
it('accepts an object', () => {
assert.strictEqual(typeof test.letObjArg({}), 'object');
});
it('accepts an array', () => {
assert.ok(Array.isArray(test.letObjArg([])));
});
});
describe('addon-tools.hpp: USE_OBJ_ARG', () => {
it('exports useObjArg', () => {
assert.strictEqual(typeof test.useObjArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.useObjArg('1'), objArgLetMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.useObjArg(1), objArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.useObjArg(true), objArgLetMsg);
});
it('throws if arg was passed a pointer', () => {
assert.throws(() => test.useObjArg(test.retExt()), objArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(typeof test.useObjArg(), 'object');
});
it('accepts undefined', () => {
assert.strictEqual(typeof test.useObjArg(undefined), 'object');
});
it('accepts null', () => {
assert.strictEqual(typeof test.useObjArg(null), 'object');
});
it('accepts an object', () => {
assert.strictEqual(typeof test.useObjArg({}), 'object');
});
it('accepts an array', () => {
assert.ok(Array.isArray(test.useObjArg([])));
});
});

View File

@ -1,100 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const test = require('./build/Release/test.node');
const numArgMsg = { message: 'Argument 0 must be of type `Number`' };
const numArgLetMsg = { message: 'Argument 0 must be of type `Number` or be `null`/`undefined`' };
describe('AT / HPP / REQ_OFFS_ARG', () => {
it('exports reqOffsArg', () => {
assert.strictEqual(typeof test.reqOffsArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqOffsArg(), numArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqOffsArg(undefined), numArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqOffsArg(null), numArgMsg);
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.reqOffsArg('1'), numArgMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.reqOffsArg(true), numArgMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.reqOffsArg({}), numArgMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.reqOffsArg([]), numArgMsg);
});
it('accepts a number', () => {
assert.strictEqual(test.reqOffsArg(55), 55);
});
});
describe('addon-tools.hpp: LET_OFFS_ARG', () => {
it('exports letOffsArg', () => {
assert.strictEqual(typeof test.letOffsArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.letOffsArg('1'), numArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.letOffsArg(true), numArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.letOffsArg({}), numArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.letOffsArg([]), numArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(test.letOffsArg(), 0);
});
it('accepts undefined', () => {
assert.strictEqual(test.letOffsArg(undefined), 0);
});
it('accepts null', () => {
assert.strictEqual(test.letOffsArg(null), 0);
});
it('accepts a number', () => {
assert.strictEqual(test.letOffsArg(55), 55);
});
});
describe('addon-tools.hpp: USE_OFFS_ARG', () => {
it('exports useOffsArg', () => {
assert.strictEqual(typeof test.useOffsArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.useOffsArg('1'), numArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.useOffsArg(true), numArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.useOffsArg({}), numArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.useOffsArg([]), numArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(test.useOffsArg(), 10);
});
it('accepts undefined', () => {
assert.strictEqual(test.useOffsArg(undefined), 10);
});
it('accepts null', () => {
assert.strictEqual(test.useOffsArg(null), 10);
});
it('accepts a number', () => {
assert.strictEqual(test.useOffsArg(55), 55);
});
});

View File

@ -1,100 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const test = require('./build/Release/test.node');
const strArgMsg = { message: 'Argument 0 must be of type `String`' };
const strArgLetMsg = { message: 'Argument 0 must be of type `String` or be `null`/`undefined`' };
describe('AT / HPP / REQ_STR_ARG', () => {
it('exports reqStrArg', () => {
assert.strictEqual(typeof test.reqStrArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqStrArg(), strArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqStrArg(undefined), strArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqStrArg(null), strArgMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.reqStrArg(1), strArgMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.reqStrArg(true), strArgMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.reqStrArg({}), strArgMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.reqStrArg([]), strArgMsg);
});
it('accepts a string', () => {
assert.strictEqual(test.reqStrArg('1abc'), '1abc');
});
});
describe('addon-tools.hpp: LET_STR_ARG', () => {
it('exports letStrArg', () => {
assert.strictEqual(typeof test.letStrArg, 'function');
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.letStrArg(1), strArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.letStrArg(true), strArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.letStrArg({}), strArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.letStrArg([]), strArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(test.letStrArg(), '');
});
it('accepts undefined', () => {
assert.strictEqual(test.letStrArg(undefined), '');
});
it('accepts null', () => {
assert.strictEqual(test.letStrArg(null), '');
});
it('accepts a string', () => {
assert.strictEqual(test.letStrArg('1abc'), '1abc');
});
});
describe('addon-tools.hpp: USE_STR_ARG', () => {
it('exports useStrArg', () => {
assert.strictEqual(typeof test.useStrArg, 'function');
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.useStrArg(1), strArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.useStrArg(true), strArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.useStrArg({}), strArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.useStrArg([]), strArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(test.useStrArg(), 'default');
});
it('accepts undefined', () => {
assert.strictEqual(test.useStrArg(undefined), 'default');
});
it('accepts null', () => {
assert.strictEqual(test.useStrArg(null), 'default');
});
it('accepts a string', () => {
assert.strictEqual(test.useStrArg('1abc'), '1abc');
});
});

View File

@ -1,100 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const test = require('./build/Release/test.node');
const uintArgMsg = { message: 'Argument 0 must be of type `Uint32`' };
const uintArgLetMsg = { message: 'Argument 0 must be of type `Uint32` or be `null`/`undefined`' };
describe('AT / HPP / REQ_UINT_ARG, REQ_UINT32_ARG', () => {
it('exports reqUintArg', () => {
assert.strictEqual(typeof test.reqUintArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqUintArg(), uintArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqUintArg(undefined), uintArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqUintArg(null), uintArgMsg);
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.reqUintArg('1'), uintArgMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.reqUintArg(true), uintArgMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.reqUintArg({}), uintArgMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.reqUintArg([]), uintArgMsg);
});
it('accepts a number', () => {
assert.strictEqual(test.reqUintArg(55), 55);
});
});
describe('addon-tools.hpp: LET_UINT_ARG / LET_UINT32_ARG', () => {
it('exports letUintArg', () => {
assert.strictEqual(typeof test.letUintArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.letUintArg('1'), uintArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.letUintArg(true), uintArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.letUintArg({}), uintArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.letUintArg([]), uintArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(test.letUintArg(), 0);
});
it('accepts undefined', () => {
assert.strictEqual(test.letUintArg(undefined), 0);
});
it('accepts null', () => {
assert.strictEqual(test.letUintArg(null), 0);
});
it('accepts a number', () => {
assert.strictEqual(test.letUintArg(55), 55);
});
});
describe('addon-tools.hpp: USE_UINT_ARG / USE_UINT32_ARG', () => {
it('exports useUintArg', () => {
assert.strictEqual(typeof test.useUintArg, 'function');
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.useUintArg('1'), uintArgLetMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.useUintArg(true), uintArgLetMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.useUintArg({}), uintArgLetMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.useUintArg([]), uintArgLetMsg);
});
it('accepts an empty arg', () => {
assert.strictEqual(test.useUintArg(), 10);
});
it('accepts undefined', () => {
assert.strictEqual(test.useUintArg(undefined), 10);
});
it('accepts null', () => {
assert.strictEqual(test.useUintArg(null), 10);
});
it('accepts a number', () => {
assert.strictEqual(test.useUintArg(55), 55);
});
});

View File

@ -1,211 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const test = require('./build/Release/test.node');
describe('AT / HPP / Function arguments', () => {
const arg3Msg = { message: 'Expected at least 3 arguments' };
describe('REQ_ARGS', () => {
it('exports reqArgs3', () => {
assert.strictEqual(typeof test.reqArgs3, 'function');
});
it('throws if no args passed', () => {
assert.throws(() => test.reqArgs3(), arg3Msg);
});
it('throws if 1 arg passed', () => {
assert.throws(() => test.reqArgs3(1), arg3Msg);
});
it('returns true if 3 args passed', () => {
assert.ok(test.reqArgs3(1, 2, 3));
});
it('returns true if 5 args passed', () => {
assert.ok(test.reqArgs3(1, 2, 3, 4, 5));
});
});
describe('IS_ARG_EMPTY', () => {
it('exports isArg0Empty', () => {
assert.strictEqual(typeof test.isArg0Empty, 'function');
});
it('returns true for absent arg', () => {
assert.ok(test.isArg0Empty());
});
it('returns true for undefined arg', () => {
assert.ok(test.isArg0Empty(undefined));
});
it('returns true for null arg', () => {
assert.ok(test.isArg0Empty(null));
});
it('returns false for non-empty value', () => {
assert.strictEqual(test.isArg0Empty(1), false);
});
});
// ------------------------------ FUN_ARG
const funArgMsg = { message: 'Argument 0 must be of type `Function`' };
describe('REQ_FUN_ARG', () => {
it('exports reqFunArg', () => {
assert.strictEqual(typeof test.reqFunArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqFunArg(), funArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqFunArg(undefined), funArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqFunArg(null), funArgMsg);
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.reqFunArg('1'), funArgMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.reqFunArg(1), funArgMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.reqFunArg(true), funArgMsg);
});
it('throws if arg was passed a pointer', () => {
assert.throws(() => test.reqFunArg(test.retExt()), funArgMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.reqFunArg({}), funArgMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.reqFunArg([]), funArgMsg);
});
it('accepts a function', () => {
assert.strictEqual(typeof test.reqFunArg(() => {}), 'function');
});
});
// ------------------------------ ARRV_ARG
const arrvArgMsg = { message: 'Argument 0 must be of type `ArrayBuffer`' };
describe('REQ_ARRV_ARG', () => {
it('exports reqArrvArg', () => {
assert.strictEqual(typeof test.reqArrvArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqArrvArg(), arrvArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqArrvArg(undefined), arrvArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqArrvArg(null), arrvArgMsg);
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.reqArrvArg('1'), arrvArgMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.reqArrvArg(1), arrvArgMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.reqArrvArg(true), arrvArgMsg);
});
it('throws if arg was passed a pointer', () => {
assert.throws(() => test.reqArrvArg(test.retExt()), arrvArgMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.reqArrvArg({}), arrvArgMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.reqArrvArg([]), arrvArgMsg);
});
it('accepts an array buffer', () => {
const { buffer } = new Uint8Array([1, 2, 3]);
assert.strictEqual(test.reqArrvArg(buffer), buffer);
});
});
// ------------------------------ BUF_ARG
const bufArgMsg = { message: 'Argument 0 must be of type `Buffer`' };
describe('REQ_BUF_ARG', () => {
it('exports reqBufArg', () => {
assert.strictEqual(typeof test.reqBufArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqBufArg(), bufArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqBufArg(undefined), bufArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqBufArg(null), bufArgMsg);
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.reqBufArg('1'), bufArgMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.reqBufArg(1), bufArgMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.reqBufArg(true), bufArgMsg);
});
it('throws if arg was passed a pointer', () => {
assert.throws(() => test.reqBufArg(test.retExt()), bufArgMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.reqBufArg({}), bufArgMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.reqBufArg([]), bufArgMsg);
});
it('accepts a buffer', () => {
const buffer = Buffer.from([1, 2, 3]);
assert.strictEqual(test.reqBufArg(buffer), buffer);
});
});
// ------------------------------ TYPED_ARRAY_ARG
const typedArgMsg = { message: 'Argument 0 must be of type `TypedArray`' };
describe('REQ_TYPED_ARRAY_ARG', () => {
it('exports reqTypedArg', () => {
assert.strictEqual(typeof test.reqTypedArg, 'function');
});
it('throws if arg was not passed', () => {
assert.throws(() => test.reqTypedArg(), typedArgMsg);
});
it('throws if arg was passed undefined', () => {
assert.throws(() => test.reqTypedArg(undefined), typedArgMsg);
});
it('throws if arg was passed null', () => {
assert.throws(() => test.reqTypedArg(null), typedArgMsg);
});
it('throws if arg was passed a string', () => {
assert.throws(() => test.reqTypedArg('1'), typedArgMsg);
});
it('throws if arg was passed a number', () => {
assert.throws(() => test.reqTypedArg(1), typedArgMsg);
});
it('throws if arg was passed a boolean', () => {
assert.throws(() => test.reqTypedArg(true), typedArgMsg);
});
it('throws if arg was passed a pointer', () => {
assert.throws(() => test.reqTypedArg(test.retExt()), typedArgMsg);
});
it('throws if arg was passed an object', () => {
assert.throws(() => test.reqTypedArg({}), typedArgMsg);
});
it('throws if arg was passed an array', () => {
assert.throws(() => test.reqTypedArg([]), typedArgMsg);
});
it('accepts a typed array', () => {
const typed = new Uint8Array([1, 2, 3]);
assert.strictEqual(test.reqTypedArg(typed), typed);
});
});
});

50
test/binding.gyp Normal file
View File

@ -0,0 +1,50 @@
{
'targets': [
{
'target_name': 'test',
'sources': [
'test.cpp',
],
'cflags!': ['-fno-exceptions'],
'cflags_cc!': ['-fno-exceptions'],
'include_dirs': [
'<!@(node -p "require(\'..\').include")',
],
'conditions': [
[
'OS=="linux"',
{
'defines': ['__linux__'],
}
],
[
'OS=="mac"',
{
'defines': ['__APPLE__'],
}
],
[
'OS=="win"',
{
'defines' : [
'WIN32_LEAN_AND_MEAN',
'VC_EXTRALEAN',
'_WIN32',
],
'msvs_settings' : {
'VCCLCompilerTool' : {
'AdditionalOptions' : [
'/O2','/Oy','/GL','/GF','/Gm-',
'/EHsc','/MT','/GS','/Gy','/GR-','/Gd',
]
},
'VCLinkerTool' : {
'AdditionalOptions' : ['/OPT:REF','/OPT:ICF','/LTCG']
},
},
},
],
],
},
],
}

850
test/package-lock.json generated Normal file
View File

@ -0,0 +1,850 @@
{
"name": "test",
"version": "0.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"ansi-colors": {
"version": "3.2.3",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.3.tgz",
"integrity": "sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw=="
},
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
},
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"requires": {
"color-convert": "^1.9.0"
}
},
"anymatch": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
"integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
"requires": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
}
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"requires": {
"sprintf-js": "~1.0.2"
}
},
"assertion-error": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw=="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"binary-extensions": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
"integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow=="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"requires": {
"fill-range": "^7.0.1"
}
},
"browser-stdout": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw=="
},
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
"chai": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/chai/-/chai-4.2.0.tgz",
"integrity": "sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw==",
"requires": {
"assertion-error": "^1.1.0",
"check-error": "^1.0.2",
"deep-eql": "^3.0.1",
"get-func-name": "^2.0.0",
"pathval": "^1.1.0",
"type-detect": "^4.0.5"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"dependencies": {
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"check-error": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
"integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII="
},
"chokidar": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.0.tgz",
"integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==",
"requires": {
"anymatch": "~3.1.1",
"braces": "~3.0.2",
"fsevents": "~2.1.1",
"glob-parent": "~5.1.0",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.2.0"
}
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"requires": {
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
"wrap-ansi": "^5.1.0"
},
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
},
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"requires": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
}
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"requires": {
"ansi-regex": "^4.1.0"
}
}
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"requires": {
"ms": "^2.1.1"
}
},
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
},
"deep-eql": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz",
"integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==",
"requires": {
"type-detect": "^4.0.0"
}
},
"define-properties": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
"integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
"requires": {
"object-keys": "^1.0.12"
}
},
"diff": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA=="
},
"emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
},
"es-abstract": {
"version": "1.17.5",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.5.tgz",
"integrity": "sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg==",
"requires": {
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"has": "^1.0.3",
"has-symbols": "^1.0.1",
"is-callable": "^1.1.5",
"is-regex": "^1.0.5",
"object-inspect": "^1.7.0",
"object-keys": "^1.1.1",
"object.assign": "^4.1.0",
"string.prototype.trimleft": "^2.1.1",
"string.prototype.trimright": "^2.1.1"
}
},
"es-to-primitive": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
"integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
"requires": {
"is-callable": "^1.1.4",
"is-date-object": "^1.0.1",
"is-symbol": "^1.0.2"
}
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"requires": {
"to-regex-range": "^5.0.1"
}
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"requires": {
"locate-path": "^3.0.0"
}
},
"flat": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/flat/-/flat-4.1.0.tgz",
"integrity": "sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw==",
"requires": {
"is-buffer": "~2.0.3"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"fsevents": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz",
"integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==",
"optional": true
},
"function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"get-func-name": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
"integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE="
},
"glob": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"glob-parent": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
"requires": {
"is-glob": "^4.0.1"
}
},
"growl": {
"version": "1.10.5",
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz",
"integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA=="
},
"has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"requires": {
"function-bind": "^1.1.1"
}
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
"has-symbols": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg=="
},
"he": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"requires": {
"binary-extensions": "^2.0.0"
}
},
"is-buffer": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
"integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A=="
},
"is-callable": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz",
"integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q=="
},
"is-date-object": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
"integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g=="
},
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
},
"is-glob": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
"requires": {
"is-extglob": "^2.1.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
},
"is-regex": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz",
"integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==",
"requires": {
"has": "^1.0.3"
}
},
"is-symbol": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
"integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
"requires": {
"has-symbols": "^1.0.1"
}
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"js-yaml": {
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"requires": {
"p-locate": "^3.0.0",
"path-exists": "^3.0.0"
}
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"log-symbols": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
"integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
"requires": {
"chalk": "^2.4.2"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"mkdirp": {
"version": "0.5.3",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.3.tgz",
"integrity": "sha512-P+2gwrFqx8lhew375MQHHeTlY8AuOJSrGf0R5ddkEndUkmwpgUob/vQuBD1V22/Cw1/lJr4x+EjllSezBThzBg==",
"requires": {
"minimist": "^1.2.5"
}
},
"mocha": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-7.1.1.tgz",
"integrity": "sha512-3qQsu3ijNS3GkWcccT5Zw0hf/rWvu1fTN9sPvEd81hlwsr30GX2GcDSSoBxo24IR8FelmrAydGC6/1J5QQP4WA==",
"requires": {
"ansi-colors": "3.2.3",
"browser-stdout": "1.3.1",
"chokidar": "3.3.0",
"debug": "3.2.6",
"diff": "3.5.0",
"escape-string-regexp": "1.0.5",
"find-up": "3.0.0",
"glob": "7.1.3",
"growl": "1.10.5",
"he": "1.2.0",
"js-yaml": "3.13.1",
"log-symbols": "3.0.0",
"minimatch": "3.0.4",
"mkdirp": "0.5.3",
"ms": "2.1.1",
"node-environment-flags": "1.0.6",
"object.assign": "4.1.0",
"strip-json-comments": "2.0.1",
"supports-color": "6.0.0",
"which": "1.3.1",
"wide-align": "1.1.3",
"yargs": "13.3.2",
"yargs-parser": "13.1.2",
"yargs-unparser": "1.6.0"
}
},
"ms": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
},
"node-environment-flags": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.6.tgz",
"integrity": "sha512-5Evy2epuL+6TM0lCQGpFIj6KwiEsGh1SrHUhTbNX+sLbBtjidPZFAnVK9y5yU1+h//RitLbRHTIMyxQPtxMdHw==",
"requires": {
"object.getownpropertydescriptors": "^2.0.3",
"semver": "^5.7.0"
}
},
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
},
"object-inspect": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz",
"integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw=="
},
"object-keys": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
},
"object.assign": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz",
"integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==",
"requires": {
"define-properties": "^1.1.2",
"function-bind": "^1.1.1",
"has-symbols": "^1.0.0",
"object-keys": "^1.0.11"
}
},
"object.getownpropertydescriptors": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz",
"integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==",
"requires": {
"define-properties": "^1.1.3",
"es-abstract": "^1.17.0-next.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"p-limit": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz",
"integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==",
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"requires": {
"p-limit": "^2.0.0"
}
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"pathval": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz",
"integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA="
},
"picomatch": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg=="
},
"readdirp": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.2.0.tgz",
"integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==",
"requires": {
"picomatch": "^2.0.4"
}
},
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
},
"require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
},
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
},
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"requires": {
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^4.0.0"
}
},
"string.prototype.trimleft": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz",
"integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==",
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
},
"string.prototype.trimright": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz",
"integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==",
"requires": {
"define-properties": "^1.1.3",
"function-bind": "^1.1.1"
}
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"requires": {
"ansi-regex": "^3.0.0"
}
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
},
"supports-color": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz",
"integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==",
"requires": {
"has-flag": "^3.0.0"
}
},
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"requires": {
"is-number": "^7.0.0"
}
},
"type-detect": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="
},
"which": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
"requires": {
"isexe": "^2.0.0"
}
},
"which-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
},
"wide-align": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"requires": {
"string-width": "^1.0.2 || 2"
}
},
"wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"requires": {
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
"strip-ansi": "^5.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
},
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"requires": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
}
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"requires": {
"ansi-regex": "^4.1.0"
}
}
}
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"y18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
},
"yargs": {
"version": "13.3.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
"integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
"requires": {
"cliui": "^5.0.0",
"find-up": "^3.0.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^3.0.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^13.1.2"
},
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
},
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"requires": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
}
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"requires": {
"ansi-regex": "^4.1.0"
}
}
}
},
"yargs-parser": {
"version": "13.1.2",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
},
"yargs-unparser": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz",
"integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==",
"requires": {
"flat": "^4.1.0",
"lodash": "^4.17.15",
"yargs": "^13.3.0"
}
}
}
}

15
test/package.json Normal file
View File

@ -0,0 +1,15 @@
{
"name": "test",
"version": "0.0.0",
"private": true,
"main": "mocha",
"scripts": {
"test": "mocha",
"build": "node-gyp rebuild",
"preinstall": "cd .. && npm ci"
},
"dependencies": {
"chai": "4.2.0",
"mocha": "7.1.1"
}
}

106
test/test-hpp-arg-array.js Normal file
View File

@ -0,0 +1,106 @@
'use strict';
const { expect } = require('chai');
const test = require('./build/Release/test.node');
const arrayArgMsg = 'Argument 0 must be of type `Array`';
describe('REQ_ARRAY_ARG', () => {
it('exports reqArrayArg', () => {
expect(test.reqArrayArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqArrayArg()).to.throw(arrayArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqArrayArg(undefined)).to.throw(arrayArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqArrayArg(null)).to.throw(arrayArgMsg);
});
it('throws if arg was passed a string', () => {
expect(() => test.reqArrayArg('1')).to.throw(arrayArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.reqArrayArg(1)).to.throw(arrayArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.reqArrayArg(true)).to.throw(arrayArgMsg);
});
it('throws if arg was passed a pointer', () => {
expect(() => test.reqArrayArg(test.retExt())).to.throw(arrayArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.reqArrayArg({})).to.throw(arrayArgMsg);
});
it('accepts an array', () => {
expect(test.reqArrayArg([])).to.be.an('array');
});
});
describe('LET_ARRAY_ARG', () => {
it('exports letArrayArg', () => {
expect(test.letArrayArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.letArrayArg('1')).to.throw(arrayArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.letArrayArg(1)).to.throw(arrayArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.letArrayArg(true)).to.throw(arrayArgMsg);
});
it('throws if arg was passed a pointer', () => {
expect(() => test.letArrayArg(test.retExt())).to.throw(arrayArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.letArrayArg({})).to.throw(arrayArgMsg);
});
it('accepts an empty arg', () => {
expect(test.letArrayArg()).to.be.an('array');
});
it('accepts undefined', () => {
expect(test.letArrayArg(undefined)).to.be.an('array');
});
it('accepts null', () => {
expect(test.letArrayArg(null)).to.be.an('array');
});
it('accepts an array', () => {
expect(test.letArrayArg([])).to.be.an('array');
});
});
describe('USE_ARRAY_ARG', () => {
it('exports useArrayArg', () => {
expect(test.useArrayArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.useArrayArg('1')).to.throw(arrayArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.useArrayArg(1)).to.throw(arrayArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.useArrayArg(true)).to.throw(arrayArgMsg);
});
it('throws if arg was passed a pointer', () => {
expect(() => test.useArrayArg(test.retExt())).to.throw(arrayArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.useArrayArg({})).to.throw(arrayArgMsg);
});
it('accepts an empty arg', () => {
expect(test.useArrayArg()).to.be.an('array');
});
it('accepts undefined', () => {
expect(test.useArrayArg(undefined)).to.be.an('array');
});
it('accepts null', () => {
expect(test.useArrayArg(null)).to.be.an('array');
});
it('accepts an array', () => {
expect(test.useArrayArg([])).to.be.an('array');
});
});

97
test/test-hpp-arg-bool.js Normal file
View File

@ -0,0 +1,97 @@
'use strict';
const { expect } = require('chai');
const test = require('./build/Release/test.node');
const boolArgMsg = 'Argument 0 must be of type `Bool`';
describe('REQ_BOOL_ARG', () => {
it('exports reqBoolArg', () => {
expect(test.reqBoolArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqBoolArg()).to.throw(boolArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqBoolArg(undefined)).to.throw(boolArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqBoolArg(null)).to.throw(boolArgMsg);
});
it('throws if arg was passed a string', () => {
expect(() => test.reqBoolArg('1')).to.throw(boolArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.reqBoolArg(1)).to.throw(boolArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.reqBoolArg({})).to.throw(boolArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.reqBoolArg([])).to.throw(boolArgMsg);
});
it('accepts a boolean', () => {
expect(test.reqBoolArg(true)).to.be.equal(true);
});
});
describe('LET_BOOL_ARG', () => {
it('exports letBoolArg', () => {
expect(test.letBoolArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.letBoolArg('1')).to.throw(boolArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.letBoolArg(1)).to.throw(boolArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.letBoolArg({})).to.throw(boolArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.letBoolArg([])).to.throw(boolArgMsg);
});
it('accepts an empty arg', () => {
expect(test.letBoolArg()).to.be.equal(false);
});
it('accepts undefined', () => {
expect(test.letBoolArg(undefined)).to.be.equal(false);
});
it('accepts null', () => {
expect(test.letBoolArg(null)).to.be.equal(false);
});
it('accepts a boolean', () => {
expect(test.letBoolArg(true)).to.be.equal(true);
});
});
describe('USE_BOOL_ARG', () => {
it('exports useBoolArg', () => {
expect(test.useBoolArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.useBoolArg('1')).to.throw(boolArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.useBoolArg(1)).to.throw(boolArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.useBoolArg({})).to.throw(boolArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.useBoolArg([])).to.throw(boolArgMsg);
});
it('accepts an empty arg', () => {
expect(test.useBoolArg()).to.be.equal(true);
});
it('accepts undefined', () => {
expect(test.useBoolArg(undefined)).to.be.equal(true);
});
it('accepts null', () => {
expect(test.useBoolArg(null)).to.be.equal(true);
});
it('accepts a boolean', () => {
expect(test.useBoolArg(true)).to.be.equal(true);
});
});

View File

@ -0,0 +1,97 @@
'use strict';
const { expect } = require('chai');
const test = require('./build/Release/test.node');
const numArgMsg = 'Argument 0 must be of type `Number`';
describe('REQ_DOUBLE_ARG', () => {
it('exports reqDoubleArg', () => {
expect(test.reqDoubleArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqDoubleArg()).to.throw(numArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqDoubleArg(undefined)).to.throw(numArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqDoubleArg(null)).to.throw(numArgMsg);
});
it('throws if arg was passed a string', () => {
expect(() => test.reqDoubleArg('1')).to.throw(numArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.reqDoubleArg(true)).to.throw(numArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.reqDoubleArg({})).to.throw(numArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.reqDoubleArg([])).to.throw(numArgMsg);
});
it('accepts a number', () => {
expect(test.reqDoubleArg(55)).to.be.equal(55);
});
});
describe('LET_DOUBLE_ARG', () => {
it('exports letDoubleArg', () => {
expect(test.letDoubleArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.letDoubleArg('1')).to.throw(numArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.letDoubleArg(true)).to.throw(numArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.letDoubleArg({})).to.throw(numArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.letDoubleArg([])).to.throw(numArgMsg);
});
it('accepts an empty arg', () => {
expect(test.letDoubleArg()).to.be.equal(0);
});
it('accepts undefined', () => {
expect(test.letDoubleArg(undefined)).to.be.equal(0);
});
it('accepts null', () => {
expect(test.letDoubleArg(null)).to.be.equal(0);
});
it('accepts a number', () => {
expect(test.letDoubleArg(55)).to.be.equal(55);
});
});
describe('USE_DOUBLE_ARG', () => {
it('exports useDoubleArg', () => {
expect(test.useDoubleArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.useDoubleArg('1')).to.throw(numArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.useDoubleArg(true)).to.throw(numArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.useDoubleArg({})).to.throw(numArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.useDoubleArg([])).to.throw(numArgMsg);
});
it('accepts an empty arg', () => {
expect(test.useDoubleArg()).to.be.equal(10);
});
it('accepts undefined', () => {
expect(test.useDoubleArg(undefined)).to.be.equal(10);
});
it('accepts null', () => {
expect(test.useDoubleArg(null)).to.be.equal(10);
});
it('accepts a number', () => {
expect(test.useDoubleArg(55)).to.be.equal(55);
});
});

106
test/test-hpp-arg-ext.js Normal file
View File

@ -0,0 +1,106 @@
'use strict';
const { expect } = require('chai');
const test = require('./build/Release/test.node');
const extArgMsg = 'Argument 0 must be of type `Pointer`';
describe('REQ_EXT_ARG', () => {
it('exports reqExtArg', () => {
expect(test.reqExtArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqExtArg()).to.throw(extArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqExtArg(undefined)).to.throw(extArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqExtArg(null)).to.throw(extArgMsg);
});
it('throws if arg was passed a string', () => {
expect(() => test.reqExtArg('1')).to.throw(extArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.reqExtArg(1)).to.throw(extArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.reqExtArg(true)).to.throw(extArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.reqExtArg({})).to.throw(extArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.reqExtArg([])).to.throw(extArgMsg);
});
it('accepts a pointer', () => {
expect(test.reqExtArg(test.retExt())).to.be.an('object');
});
});
describe('LET_EXT_ARG', () => {
it('exports letExtArg', () => {
expect(test.letExtArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.letExtArg('1')).to.throw(extArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.letExtArg(1)).to.throw(extArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.letExtArg(true)).to.throw(extArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.letExtArg({})).to.throw(extArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.letExtArg([])).to.throw(extArgMsg);
});
it('accepts an empty arg', () => {
expect(test.letExtArg()).to.be.an('object');
});
it('accepts undefined', () => {
expect(test.letExtArg(undefined)).to.be.an('object');
});
it('accepts null', () => {
expect(test.letExtArg(null)).to.be.an('object');
});
it('accepts a pointer', () => {
expect(test.reqExtArg(test.retExt())).to.be.an('object');
});
});
describe('USE_EXT_ARG', () => {
it('exports useExtArg', () => {
expect(test.useExtArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.useExtArg('1')).to.throw(extArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.useExtArg(1)).to.throw(extArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.useExtArg(true)).to.throw(extArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.useExtArg({})).to.throw(extArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.useExtArg([])).to.throw(extArgMsg);
});
it('accepts an empty arg', () => {
expect(test.useExtArg()).to.be.an('object');
});
it('accepts undefined', () => {
expect(test.useExtArg(undefined)).to.be.an('object');
});
it('accepts null', () => {
expect(test.useExtArg(null)).to.be.an('object');
});
it('accepts a number', () => {
expect(test.useExtArg(test.retExt())).to.be.an('object');
});
});

View File

@ -0,0 +1,97 @@
'use strict';
const { expect } = require('chai');
const test = require('./build/Release/test.node');
const numArgMsg = 'Argument 0 must be of type `Number`';
describe('REQ_FLOAT_ARG', () => {
it('exports reqFloatArg', () => {
expect(test.reqFloatArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqFloatArg()).to.throw(numArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqFloatArg(undefined)).to.throw(numArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqFloatArg(null)).to.throw(numArgMsg);
});
it('throws if arg was passed a string', () => {
expect(() => test.reqFloatArg('1')).to.throw(numArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.reqFloatArg(true)).to.throw(numArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.reqFloatArg({})).to.throw(numArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.reqFloatArg([])).to.throw(numArgMsg);
});
it('accepts a number', () => {
expect(test.reqFloatArg(55)).to.be.equal(55);
});
});
describe('LET_FLOAT_ARG', () => {
it('exports letFloatArg', () => {
expect(test.letFloatArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.letFloatArg('1')).to.throw(numArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.letFloatArg(true)).to.throw(numArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.letFloatArg({})).to.throw(numArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.letFloatArg([])).to.throw(numArgMsg);
});
it('accepts an empty arg', () => {
expect(test.letFloatArg()).to.be.equal(0);
});
it('accepts undefined', () => {
expect(test.letFloatArg(undefined)).to.be.equal(0);
});
it('accepts null', () => {
expect(test.letFloatArg(null)).to.be.equal(0);
});
it('accepts a number', () => {
expect(test.letFloatArg(55)).to.be.equal(55);
});
});
describe('USE_FLOAT_ARG', () => {
it('exports useFloatArg', () => {
expect(test.useFloatArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.useFloatArg('1')).to.throw(numArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.useFloatArg(true)).to.throw(numArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.useFloatArg({})).to.throw(numArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.useFloatArg([])).to.throw(numArgMsg);
});
it('accepts an empty arg', () => {
expect(test.useFloatArg()).to.be.equal(10);
});
it('accepts undefined', () => {
expect(test.useFloatArg(undefined)).to.be.equal(10);
});
it('accepts null', () => {
expect(test.useFloatArg(null)).to.be.equal(10);
});
it('accepts a number', () => {
expect(test.useFloatArg(55)).to.be.equal(55);
});
});

97
test/test-hpp-arg-int.js Normal file
View File

@ -0,0 +1,97 @@
'use strict';
const { expect } = require('chai');
const test = require('./build/Release/test.node');
const intArgMsg = 'Argument 0 must be of type `Int32`';
describe('REQ_INT_ARG / REQ_INT32_ARG', () => {
it('exports reqIntArg', () => {
expect(test.reqIntArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqIntArg()).to.throw(intArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqIntArg(undefined)).to.throw(intArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqIntArg(null)).to.throw(intArgMsg);
});
it('throws if arg was passed a string', () => {
expect(() => test.reqIntArg('1')).to.throw(intArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.reqIntArg(true)).to.throw(intArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.reqIntArg({})).to.throw(intArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.reqIntArg([])).to.throw(intArgMsg);
});
it('accepts a number', () => {
expect(test.reqIntArg(55)).to.be.equal(55);
});
});
describe('LET_INT_ARG / LET_INT32_ARG', () => {
it('exports letIntArg', () => {
expect(test.letIntArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.letIntArg('1')).to.throw(intArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.letIntArg(true)).to.throw(intArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.letIntArg({})).to.throw(intArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.letIntArg([])).to.throw(intArgMsg);
});
it('accepts an empty arg', () => {
expect(test.letIntArg()).to.be.equal(0);
});
it('accepts undefined', () => {
expect(test.letIntArg(undefined)).to.be.equal(0);
});
it('accepts null', () => {
expect(test.letIntArg(null)).to.be.equal(0);
});
it('accepts a number', () => {
expect(test.letIntArg(55)).to.be.equal(55);
});
});
describe('USE_INT_ARG / USE_INT32_ARG', () => {
it('exports useIntArg', () => {
expect(test.useIntArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.useIntArg('1')).to.throw(intArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.useIntArg(true)).to.throw(intArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.useIntArg({})).to.throw(intArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.useIntArg([])).to.throw(intArgMsg);
});
it('accepts an empty arg', () => {
expect(test.useIntArg()).to.be.equal(10);
});
it('accepts undefined', () => {
expect(test.useIntArg(undefined)).to.be.equal(10);
});
it('accepts null', () => {
expect(test.useIntArg(null)).to.be.equal(10);
});
it('accepts a number', () => {
expect(test.useIntArg(55)).to.be.equal(55);
});
});

106
test/test-hpp-arg-obj.js Normal file
View File

@ -0,0 +1,106 @@
'use strict';
const { expect } = require('chai');
const test = require('./build/Release/test.node');
const objArgMsg = 'Argument 0 must be of type `Object`';
describe('REQ_OBJ_ARG', () => {
it('exports reqObjArg', () => {
expect(test.reqObjArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqObjArg()).to.throw(objArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqObjArg(undefined)).to.throw(objArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqObjArg(null)).to.throw(objArgMsg);
});
it('throws if arg was passed a string', () => {
expect(() => test.reqObjArg('1')).to.throw(objArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.reqObjArg(1)).to.throw(objArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.reqObjArg(true)).to.throw(objArgMsg);
});
it('throws if arg was passed a pointer', () => {
expect(() => test.reqObjArg(test.retExt())).to.throw(objArgMsg);
});
it('accepts an object', () => {
expect(test.reqObjArg({})).to.be.an('object');
});
it('accepts an array', () => {
expect(test.reqObjArg([])).to.be.an('array');
});
});
describe('LET_OBJ_ARG', () => {
it('exports letObjArg', () => {
expect(test.letObjArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.letObjArg('1')).to.throw(objArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.letObjArg(1)).to.throw(objArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.letObjArg(true)).to.throw(objArgMsg);
});
it('throws if arg was passed a pointer', () => {
expect(() => test.letObjArg(test.retExt())).to.throw(objArgMsg);
});
it('accepts an empty arg', () => {
expect(test.letObjArg()).to.be.an('object');
});
it('accepts undefined', () => {
expect(test.letObjArg(undefined)).to.be.an('object');
});
it('accepts null', () => {
expect(test.letObjArg(null)).to.be.an('object');
});
it('accepts an object', () => {
expect(test.letObjArg({})).to.be.an('object');
});
it('accepts an array', () => {
expect(test.letObjArg([])).to.be.an('array');
});
});
describe('USE_OBJ_ARG', () => {
it('exports useObjArg', () => {
expect(test.useObjArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.useObjArg('1')).to.throw(objArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.useObjArg(1)).to.throw(objArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.useObjArg(true)).to.throw(objArgMsg);
});
it('throws if arg was passed a pointer', () => {
expect(() => test.useObjArg(test.retExt())).to.throw(objArgMsg);
});
it('accepts an empty arg', () => {
expect(test.useObjArg()).to.be.an('object');
});
it('accepts undefined', () => {
expect(test.useObjArg(undefined)).to.be.an('object');
});
it('accepts null', () => {
expect(test.useObjArg(null)).to.be.an('object');
});
it('accepts an object', () => {
expect(test.useObjArg({})).to.be.an('object');
});
it('accepts an array', () => {
expect(test.useObjArg([])).to.be.an('array');
});
});

97
test/test-hpp-arg-offs.js Normal file
View File

@ -0,0 +1,97 @@
'use strict';
const { expect } = require('chai');
const test = require('./build/Release/test.node');
const numArgMsg = 'Argument 0 must be of type `Number`';
describe('REQ_OFFS_ARG', () => {
it('exports reqOffsArg', () => {
expect(test.reqOffsArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqOffsArg()).to.throw(numArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqOffsArg(undefined)).to.throw(numArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqOffsArg(null)).to.throw(numArgMsg);
});
it('throws if arg was passed a string', () => {
expect(() => test.reqOffsArg('1')).to.throw(numArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.reqOffsArg(true)).to.throw(numArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.reqOffsArg({})).to.throw(numArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.reqOffsArg([])).to.throw(numArgMsg);
});
it('accepts a number', () => {
expect(test.reqOffsArg(55)).to.be.equal(55);
});
});
describe('LET_OFFS_ARG', () => {
it('exports letOffsArg', () => {
expect(test.letOffsArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.letOffsArg('1')).to.throw(numArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.letOffsArg(true)).to.throw(numArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.letOffsArg({})).to.throw(numArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.letOffsArg([])).to.throw(numArgMsg);
});
it('accepts an empty arg', () => {
expect(test.letOffsArg()).to.be.equal(0);
});
it('accepts undefined', () => {
expect(test.letOffsArg(undefined)).to.be.equal(0);
});
it('accepts null', () => {
expect(test.letOffsArg(null)).to.be.equal(0);
});
it('accepts a number', () => {
expect(test.letOffsArg(55)).to.be.equal(55);
});
});
describe('USE_OFFS_ARG', () => {
it('exports useOffsArg', () => {
expect(test.useOffsArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.useOffsArg('1')).to.throw(numArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.useOffsArg(true)).to.throw(numArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.useOffsArg({})).to.throw(numArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.useOffsArg([])).to.throw(numArgMsg);
});
it('accepts an empty arg', () => {
expect(test.useOffsArg()).to.be.equal(10);
});
it('accepts undefined', () => {
expect(test.useOffsArg(undefined)).to.be.equal(10);
});
it('accepts null', () => {
expect(test.useOffsArg(null)).to.be.equal(10);
});
it('accepts a number', () => {
expect(test.useOffsArg(55)).to.be.equal(55);
});
});

97
test/test-hpp-arg-str.js Normal file
View File

@ -0,0 +1,97 @@
'use strict';
const { expect } = require('chai');
const test = require('./build/Release/test.node');
const strArgMsg = 'Argument 0 must be of type `String`';
describe('REQ_STR_ARG', () => {
it('exports reqStrArg', () => {
expect(test.reqStrArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqStrArg()).to.throw(strArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqStrArg(undefined)).to.throw(strArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqStrArg(null)).to.throw(strArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.reqStrArg(1)).to.throw(strArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.reqStrArg(true)).to.throw(strArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.reqStrArg({})).to.throw(strArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.reqStrArg([])).to.throw(strArgMsg);
});
it('accepts a string', () => {
expect(test.reqStrArg('1abc')).to.be.equal('1abc');
});
});
describe('LET_STR_ARG', () => {
it('exports letStrArg', () => {
expect(test.letStrArg).to.be.a('function');
});
it('throws if arg was passed a number', () => {
expect(() => test.letStrArg(1)).to.throw(strArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.letStrArg(true)).to.throw(strArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.letStrArg({})).to.throw(strArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.letStrArg([])).to.throw(strArgMsg);
});
it('accepts an empty arg', () => {
expect(test.letStrArg()).to.be.equal('');
});
it('accepts undefined', () => {
expect(test.letStrArg(undefined)).to.be.equal('');
});
it('accepts null', () => {
expect(test.letStrArg(null)).to.be.equal('');
});
it('accepts a string', () => {
expect(test.letStrArg('1abc')).to.be.equal('1abc');
});
});
describe('USE_STR_ARG', () => {
it('exports useStrArg', () => {
expect(test.useStrArg).to.be.a('function');
});
it('throws if arg was passed a number', () => {
expect(() => test.useStrArg(1)).to.throw(strArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.useStrArg(true)).to.throw(strArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.useStrArg({})).to.throw(strArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.useStrArg([])).to.throw(strArgMsg);
});
it('accepts an empty arg', () => {
expect(test.useStrArg()).to.be.equal('default');
});
it('accepts undefined', () => {
expect(test.useStrArg(undefined)).to.be.equal('default');
});
it('accepts null', () => {
expect(test.useStrArg(null)).to.be.equal('default');
});
it('accepts a string', () => {
expect(test.useStrArg('1abc')).to.be.equal('1abc');
});
});

97
test/test-hpp-arg-uint.js Normal file
View File

@ -0,0 +1,97 @@
'use strict';
const { expect } = require('chai');
const test = require('./build/Release/test.node');
const uintArgMsg = 'Argument 0 must be of type `Uint32`';
describe('REQ_UINT_ARG / REQ_UINT32_ARG', () => {
it('exports reqUintArg', () => {
expect(test.reqUintArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqUintArg()).to.throw(uintArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqUintArg(undefined)).to.throw(uintArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqUintArg(null)).to.throw(uintArgMsg);
});
it('throws if arg was passed a string', () => {
expect(() => test.reqUintArg('1')).to.throw(uintArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.reqUintArg(true)).to.throw(uintArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.reqUintArg({})).to.throw(uintArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.reqUintArg([])).to.throw(uintArgMsg);
});
it('accepts a number', () => {
expect(test.reqUintArg(55)).to.be.equal(55);
});
});
describe('LET_UINT_ARG / LET_UINT32_ARG', () => {
it('exports letUintArg', () => {
expect(test.letUintArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.letUintArg('1')).to.throw(uintArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.letUintArg(true)).to.throw(uintArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.letUintArg({})).to.throw(uintArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.letUintArg([])).to.throw(uintArgMsg);
});
it('accepts an empty arg', () => {
expect(test.letUintArg()).to.be.equal(0);
});
it('accepts undefined', () => {
expect(test.letUintArg(undefined)).to.be.equal(0);
});
it('accepts null', () => {
expect(test.letUintArg(null)).to.be.equal(0);
});
it('accepts a number', () => {
expect(test.letUintArg(55)).to.be.equal(55);
});
});
describe('USE_UINT_ARG / USE_UINT32_ARG', () => {
it('exports useUintArg', () => {
expect(test.useUintArg).to.be.a('function');
});
it('throws if arg was passed a string', () => {
expect(() => test.useUintArg('1')).to.throw(uintArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.useUintArg(true)).to.throw(uintArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.useUintArg({})).to.throw(uintArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.useUintArg([])).to.throw(uintArgMsg);
});
it('accepts an empty arg', () => {
expect(test.useUintArg()).to.be.equal(10);
});
it('accepts undefined', () => {
expect(test.useUintArg(undefined)).to.be.equal(10);
});
it('accepts null', () => {
expect(test.useUintArg(null)).to.be.equal(10);
});
it('accepts a number', () => {
expect(test.useUintArg(55)).to.be.equal(55);
});
});

219
test/test-hpp-arg.js Normal file
View File

@ -0,0 +1,219 @@
'use strict';
const { expect } = require('chai');
const test = require('./build/Release/test.node');
describe('Function arguments', () => {
describe('REQ_ARGS', () => {
it('exports reqArgs3', () => {
expect(test.reqArgs3).to.be.a('function');
});
it('throws if no args passed', () => {
expect(() => test.reqArgs3()).to.throw('Expected at least 3 arguments');
});
it('throws if 1 arg passed', () => {
expect(() => test.reqArgs3(1)).to.throw('Expected at least 3 arguments');
});
it('returns true if 3 args passed', () => {
expect(test.reqArgs3(1, 2, 3)).to.be.true;
});
it('returns true if 5 args passed', () => {
expect(test.reqArgs3(1, 2, 3, 4, 5)).to.be.true;
});
});
describe('IS_ARG_EMPTY', () => {
it('exports isArg0Empty', () => {
expect(test.isArg0Empty).to.be.a('function');
});
it('returns true for absent arg', () => {
expect(test.isArg0Empty()).to.be.true;
});
it('returns true for undefined arg', () => {
expect(test.isArg0Empty(undefined)).to.be.true;
});
it('returns true for null arg', () => {
expect(test.isArg0Empty(null)).to.be.true;
});
it('returns false for non-empty value', () => {
expect(test.isArg0Empty(1)).to.be.false;
});
});
require('./test-hpp-arg-str');
require('./test-hpp-arg-int');
require('./test-hpp-arg-uint');
require('./test-hpp-arg-bool');
require('./test-hpp-arg-offs');
require('./test-hpp-arg-double');
require('./test-hpp-arg-float');
require('./test-hpp-arg-ext');
require('./test-hpp-arg-obj');
require('./test-hpp-arg-array');
// ------------------------------ FUN_ARG
const funArgMsg = 'Argument 0 must be of type `Function`';
describe('REQ_FUN_ARG', () => {
it('exports reqFunArg', () => {
expect(test.reqFunArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqFunArg()).to.throw(funArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqFunArg(undefined)).to.throw(funArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqFunArg(null)).to.throw(funArgMsg);
});
it('throws if arg was passed a string', () => {
expect(() => test.reqFunArg('1')).to.throw(funArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.reqFunArg(1)).to.throw(funArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.reqFunArg(true)).to.throw(funArgMsg);
});
it('throws if arg was passed a pointer', () => {
expect(() => test.reqFunArg(test.retExt())).to.throw(funArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.reqFunArg({})).to.throw(funArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.reqFunArg([])).to.throw(funArgMsg);
});
it('accepts a function', () => {
expect(test.reqFunArg(() => {})).to.be.a('function');
});
});
// ------------------------------ ARRV_ARG
const arrvArgMsg = 'Argument 0 must be of type `ArrayBuffer`';
describe('REQ_ARRV_ARG', () => {
it('exports reqArrvArg', () => {
expect(test.reqArrvArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqArrvArg()).to.throw(arrvArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqArrvArg(undefined)).to.throw(arrvArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqArrvArg(null)).to.throw(arrvArgMsg);
});
it('throws if arg was passed a string', () => {
expect(() => test.reqArrvArg('1')).to.throw(arrvArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.reqArrvArg(1)).to.throw(arrvArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.reqArrvArg(true)).to.throw(arrvArgMsg);
});
it('throws if arg was passed a pointer', () => {
expect(() => test.reqArrvArg(test.retExt())).to.throw(arrvArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.reqArrvArg({})).to.throw(arrvArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.reqArrvArg([])).to.throw(arrvArgMsg);
});
it('accepts an array buffer', () => {
const { buffer } = new Uint8Array([1, 2, 3]);
expect(test.reqArrvArg(buffer)).to.be.equal(buffer);
});
});
// ------------------------------ BUF_ARG
const bufArgMsg = 'Argument 0 must be of type `Buffer`';
describe('REQ_BUF_ARG', () => {
it('exports reqBufArg', () => {
expect(test.reqBufArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqBufArg()).to.throw(bufArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqBufArg(undefined)).to.throw(bufArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqBufArg(null)).to.throw(bufArgMsg);
});
it('throws if arg was passed a string', () => {
expect(() => test.reqBufArg('1')).to.throw(bufArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.reqBufArg(1)).to.throw(bufArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.reqBufArg(true)).to.throw(bufArgMsg);
});
it('throws if arg was passed a pointer', () => {
expect(() => test.reqBufArg(test.retExt())).to.throw(bufArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.reqBufArg({})).to.throw(bufArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.reqBufArg([])).to.throw(bufArgMsg);
});
it('accepts a buffer', () => {
const buffer = Buffer.from([1, 2, 3]);
expect(test.reqBufArg(buffer)).to.be.equal(buffer);
});
});
// ------------------------------ TYPED_ARRAY_ARG
const typedArgMsg = 'Argument 0 must be of type `TypedArray`';
describe('REQ_TYPED_ARRAY_ARG', () => {
it('exports reqTypedArg', () => {
expect(test.reqTypedArg).to.be.a('function');
});
it('throws if arg was not passed', () => {
expect(() => test.reqTypedArg()).to.throw(typedArgMsg);
});
it('throws if arg was passed undefined', () => {
expect(() => test.reqTypedArg(undefined)).to.throw(typedArgMsg);
});
it('throws if arg was passed null', () => {
expect(() => test.reqTypedArg(null)).to.throw(typedArgMsg);
});
it('throws if arg was passed a string', () => {
expect(() => test.reqTypedArg('1')).to.throw(typedArgMsg);
});
it('throws if arg was passed a number', () => {
expect(() => test.reqTypedArg(1)).to.throw(typedArgMsg);
});
it('throws if arg was passed a boolean', () => {
expect(() => test.reqTypedArg(true)).to.throw(typedArgMsg);
});
it('throws if arg was passed a pointer', () => {
expect(() => test.reqTypedArg(test.retExt())).to.throw(typedArgMsg);
});
it('throws if arg was passed an object', () => {
expect(() => test.reqTypedArg({})).to.throw(typedArgMsg);
});
it('throws if arg was passed an array', () => {
expect(() => test.reqTypedArg([])).to.throw(typedArgMsg);
});
it('accepts a typed array', () => {
const typed = new Uint8Array([1, 2, 3]);
expect(test.reqTypedArg(typed)).to.be.equal(typed);
});
});
});

8
test/test-hpp.js Normal file
View File

@ -0,0 +1,8 @@
'use strict';
describe('addon-tools.hpp', () => {
require('./test-hpp-arg');
});

39
test/test-index.js Normal file
View File

@ -0,0 +1,39 @@
'use strict';
const { expect } = require('chai');
describe('index.js', () => {
const tools = require('..');
describe(
'Properties',
() => ['bin', 'platform', 'include'].forEach(
m => it(`#${m} is a string`, () => {
expect(tools[m]).to.be.a('string');
})
)
);
describe('#paths()', () => {
it('is a function', () => {
expect(tools.paths).to.be.a('function');
});
it('returns an object', () => {
expect(tools.paths(__dirname)).to.be.an('object');
});
it('has "include" string', () => {
expect(tools.paths(__dirname).include).to.be.a('string');
});
it('has "bin" string', () => {
expect(tools.paths(__dirname).include).to.be.a('string');
});
});
});

View File

@ -3,12 +3,12 @@
JS_METHOD(empty) { NAPI_ENV; JS_METHOD(empty) { NAPI_ENV;
NAPI_HS; NAPI_HS;
RET_UNDEFINED; return env.Undefined();
} }
JS_METHOD(throwing) { NAPI_ENV; JS_METHOD(throwing) { NAPI_ENV;
JS_THROW("Some error"); JS_THROW("Some error");
RET_UNDEFINED; return env.Undefined();
} }
JS_METHOD(retUndefined) { NAPI_ENV; JS_METHOD(retUndefined) { NAPI_ENV;
@ -202,11 +202,6 @@ JS_METHOD(letArrayArg) { NAPI_ENV;
RET_VALUE(arg); RET_VALUE(arg);
} }
JS_METHOD(letArrayStrArg) { NAPI_ENV;
LET_ARRAY_STR_ARG(0, arg);
RET_ARRAY_STR(arg);
}
JS_METHOD(reqFunArg) { NAPI_ENV; JS_METHOD(reqFunArg) { NAPI_ENV;
REQ_FUN_ARG(0, arg); REQ_FUN_ARG(0, arg);
RET_VALUE(arg); RET_VALUE(arg);
@ -234,6 +229,7 @@ JS_METHOD(reqTypedArg) { NAPI_ENV;
); );
Napi::Object init(Napi::Env env, Napi::Object exports) { Napi::Object init(Napi::Env env, Napi::Object exports) {
TEST_SET_METHOD(empty); TEST_SET_METHOD(empty);
TEST_SET_METHOD(throwing); TEST_SET_METHOD(throwing);
@ -289,14 +285,13 @@ Napi::Object init(Napi::Env env, Napi::Object exports) {
TEST_SET_METHOD(useArrayArg); TEST_SET_METHOD(useArrayArg);
TEST_SET_METHOD(letArrayArg); TEST_SET_METHOD(letArrayArg);
TEST_SET_METHOD(letArrayStrArg);
TEST_SET_METHOD(reqFunArg); TEST_SET_METHOD(reqFunArg);
TEST_SET_METHOD(reqArrvArg); TEST_SET_METHOD(reqArrvArg);
TEST_SET_METHOD(reqBufArg); TEST_SET_METHOD(reqBufArg);
TEST_SET_METHOD(reqTypedArg); TEST_SET_METHOD(reqTypedArg);
return exports; return exports;
} }
NODE_API_MODULE(test, init) NODE_API_MODULE(test, init)

4
test/test.js Normal file
View File

@ -0,0 +1,4 @@
'use strict';
require('./test-index');
require('./test-hpp');

View File

@ -1,10 +1,9 @@
'use strict'; 'use strict';
const fs = require('node:fs'); const fs = require('fs');
// (async) Reads a whole file to string, NOT A Buffer // (async) Reads a whole file to string, NOT A Buffer
const read = (name) => new Promise( const read = name => new Promise(
(res, rej) => fs.readFile( (res, rej) => fs.readFile(
name, name,
(err, data) => (err ? rej(err) : res(data.toString())) (err, data) => (err ? rej(err) : res(data.toString()))
@ -14,7 +13,7 @@ const read = (name) => new Promise(
// (async) Write a file // (async) Write a file
const write = (name, text) => new Promise( const write = (name, text) => new Promise(
(res, rej) => fs.writeFile(name, text, (err) => (err ? rej(err) : res())) (res, rej) => fs.writeFile(name, text, err => (err ? rej(err) : res()))
); );
@ -22,7 +21,7 @@ const write = (name, text) => new Promise(
const copy = async (src, dest) => { const copy = async (src, dest) => {
try { try {
await new Promise( await new Promise(
(res, rej) => fs.copyFile(src, dest, (err) => (err ? rej(err) : res())) (res, rej) => fs.copyFile(src, dest, err => (err ? rej(err) : res()))
); );
} catch (e) { } catch (e) {
if (e.code !== 'EBUSY') { if (e.code !== 'EBUSY') {
@ -33,46 +32,46 @@ const copy = async (src, dest) => {
// (async) Check if a file/folder exists // (async) Check if a file/folder exists
const exists = (name) => new Promise( const exists = name => new Promise(
(res) => fs.access( res => fs.access(
name, name,
fs.constants.F_OK, fs.constants.F_OK,
(err) => res(err ? false : true) err => res(err ? false : true)
) )
); );
// (async) Create an empty folder // (async) Create an empty folder
const mkdir = async (name) => { const mkdir = async name => {
if (await exists(name)) { if (await exists(name)) {
return; return;
} }
return new Promise( return new Promise(
(res, rej) => fs.mkdir(name, (err) => (err ? rej(err) : res())) (res, rej) => fs.mkdir(name, err => (err ? rej(err) : res()))
); );
}; };
// (async) Get status on a file // (async) Get status on a file
const stat = (name) => new Promise( const stat = name => new Promise(
(res, rej) => fs.stat(name, (err, stats) => (err ? rej(err) : res(stats))) (res, rej) => fs.stat(name, (err, stats) => (err ? rej(err) : res(stats)))
); );
// (async) Check if the path is a folder // (async) Check if the path is a folder
const isDir = async (name) => (await stat(name)).isDirectory(); const isDir = async name => (await stat(name)).isDirectory();
// (async) Check if the path is a file // (async) Check if the path is a file
const isFile = async (name) => (await stat(name)).isFile(); const isFile = async name => (await stat(name)).isFile();
// Cut the path one folder up // Cut the path one folder up
const dirUp = (dir) => dir.replace(/\\/g, '/').split('/').slice(0, -1).join('/'); const dirUp = dir => dir.replace(/\\/g, '/').split('/').slice(0, -1).join('/');
// (async) Like `mkdir -p`, makes sure a directory exists // (async) Like `mkdir -p`, makes sure a directory exists
const ensuredir = async (dir) => { const ensuredir = async dir => {
if (await exists(dir) && await isDir(dir)) { if (await exists(dir) && await isDir(dir)) {
return; return;
} }
@ -89,7 +88,7 @@ const copysafe = async (src, dest) => {
// (async) Get file/folder names of the 1st level // (async) Get file/folder names of the 1st level
const readdir = (name) => new Promise( const readdir = name => new Promise(
(res, rej) => fs.readdir( (res, rej) => fs.readdir(
name, name,
(err, dirents) => (err ? rej(err) : res(dirents)) (err, dirents) => (err ? rej(err) : res(dirents))
@ -98,18 +97,18 @@ const readdir = (name) => new Promise(
// (async) Get folder paths (concatenated with input) of the 1st level // (async) Get folder paths (concatenated with input) of the 1st level
const subdirs = async (name) => { const subdirs = async name => {
const all = await readdir(name); const all = await readdir(name);
const mapped = await Promise.all(all.map((d) => isDir(`${name}/${d}`))); const mapped = await Promise.all(all.map(d => isDir(`${name}/${d}`)));
return all.filter((_, i) => mapped[i]); return all.filter((_, i) => mapped[i]);
}; };
// (async) Get file paths (concatenated with input) of the 1st level // (async) Get file paths (concatenated with input) of the 1st level
const subfiles = async (name) => { const subfiles = async name => {
const all = await readdir(name); const all = await readdir(name);
const mapped = await Promise.all(all.map((d) => isFile(`${name}/${d}`))); const mapped = await Promise.all(all.map(d => isFile(`${name}/${d}`)));
return all.filter((_, i) => mapped[i]).map((f) => `${name}/${f}`); return all.filter((_, i) => mapped[i]).map(f => `${name}/${f}`);
}; };
@ -122,7 +121,7 @@ const traverse = async (name, showDirs = false) => {
while (stack.length) { while (stack.length) {
const dir = stack.pop(); const dir = stack.pop();
dirs.push(dir); dirs.push(dir);
(await subdirs(dir)).forEach((d) => stack.push(`${dir}/${d}`)); (await subdirs(dir)).forEach(d => stack.push(`${dir}/${d}`));
} }
return (showDirs ? dirs : []).concat( return (showDirs ? dirs : []).concat(
...(await Promise.all(dirs.map(subfiles))) ...(await Promise.all(dirs.map(subfiles)))
@ -146,8 +145,8 @@ const copyall = async (src, dest) => {
// (async) Like `rm -rf`, removes everything recursively // (async) Like `rm -rf`, removes everything recursively
const rmdir = async (name) => { const rmdir = async name => {
if (!await exists(name)) { if ( ! await exists(name) ) {
return; return;
} }
const paths = await traverse(name, true); const paths = await traverse(name, true);
@ -157,7 +156,7 @@ const rmdir = async (name) => {
await new Promise( await new Promise(
(res, rej) => fs[dir ? 'rmdir' : 'unlink']( (res, rej) => fs[dir ? 'rmdir' : 'unlink'](
target, target,
(err) => (err ? rej(err) : res()) err => (err ? rej(err) : res())
) )
); );
} }
@ -165,12 +164,12 @@ const rmdir = async (name) => {
// (async) Remove a file. Must be a file, not a folder. Just `fs.unlink`. // (async) Remove a file. Must be a file, not a folder. Just `fs.unlink`.
const rm = async (name) => { const rm = async name => {
if (!await exists(name)) { if ( ! await exists(name) ) {
return; return;
} }
await new Promise( await new Promise(
(res, rej) => fs.unlink(name, (err) => (err ? rej(err) : res())) (res, rej) => fs.unlink(name, err => (err ? rej(err) : res()))
); );
}; };

View File

@ -1,20 +0,0 @@
'use strict';
const util = require('node:util');
const exec = util.promisify(require('node:child_process').exec);
const { getPlatform, getBin } = require('../include');
const actionPack = async () => {
try {
await exec(`cd ${getBin()} && tar -czf ../${getPlatform()}.gz *`);
console.log(`pack=${getPlatform()}.gz`);
} catch (error) {
console.error(error);
process.exit(-1);
}
};
module.exports = { actionPack };

View File

@ -1,31 +0,0 @@
'use strict';
const { copy, exists, mkdir, rm } = require('./files');
const { getBin } = require('../include');
const cpbin = async (name) => {
const srcDir = process.cwd().replace(/\\/g, '/');
if (!await exists(`${srcDir}/build/Release/${name}.node`) ) {
console.error(`Error. File "${srcDir}/build/Release/${name}.node" not found.`);
}
const binAbs = `${srcDir}/../${getBin()}`;
if (!await exists(binAbs)) {
await mkdir(binAbs);
}
const destAbs = `${binAbs}/${name}.node`;
if (await exists(destAbs)) {
await rm(destAbs);
}
await copy(`${srcDir}/build/Release/${name}.node`, destAbs);
console.log(`The binary "${name}.node" was copied to "${getBin()}".`);
};
module.exports = { cpbin };

View File

@ -1,24 +0,0 @@
'use strict';
const { copy, exists } = require('./files');
const cpcpplint = async () => {
const cpplintDest = `${process.cwd()}/CPPLINT.cfg`.replace(/\\/g, '/');
const cpplintSrc = `${__dirname}/CPPLINT.cfg`.replace(/\\/g, '/');
if (!await exists(cpplintSrc) ) {
console.error('Error. File "CPPLINT.cfg" not found.');
return;
}
if (await exists(cpplintDest) ) {
console.warn('Warning. Dest "CPPLINT.cfg" exists and will be overwritten.');
}
await copy(cpplintSrc, cpplintDest);
console.log(`"CPPLINT.cfg" was copied to "${cpplintDest}".`);
};
module.exports = { cpcpplint };

View File

@ -1,46 +0,0 @@
'use strict';
const https = require('node:https');
const http = require('node:http');
const { WritableBuffer } = require('./writable-buffer');
const protocols = { http, https };
const downloadRecursive = async (url, count = 1) => {
const stream = new WritableBuffer();
const proto = protocols[url.match(/^https?/i)[0].toLowerCase()];
const response = await new Promise((res, rej) => {
const request = proto.get(url, (response) => res(response));
request.on('error', (err) => rej(err));
});
// Handle redirects
if ([301, 302, 303, 307].includes(response.statusCode)) {
if (count < 5) {
return downloadRecursive(response.headers.location, count + 1);
}
console.log(url);
throw new Error('Error: Too many redirects.');
}
// Handle bad status
if (response.statusCode !== 200) {
console.log(url);
throw new Error(`Response status was ${response.statusCode}`);
}
response.pipe(stream);
return new Promise((res, rej) => {
response.on('error', (err) => rej(err));
response.on('end', () => res(stream.get()));
});
};
const download = (url) => downloadRecursive(url);
module.exports = { download };

View File

@ -1,13 +0,0 @@
'use strict';
module.exports = Object.assign(
{},
require('./action-pack'),
require('./cpbin'),
require('./cpcpplint'),
require('./download'),
require('./files'),
require('./install'),
require('./writable-buffer'),
);

View File

@ -1,72 +0,0 @@
'use strict';
const fs = require('node:fs');
const https = require('node:https');
const http = require('node:http');
const util = require('node:util');
const exec = util.promisify(require('node:child_process').exec);
const { getBin, getPlatform } = require('../include');
const { mkdir, rmdir, rm } = require('./files');
const protocols = { http, https };
const installRecursive = async (url, count = 1) => {
try {
const proto = protocols[url.match(/^https?/)[0]];
const response = await new Promise((res, rej) => {
const request = proto.get(url, (response) => res(response));
request.on('error', (err) => rej(err));
});
response.on('error', (err) => { throw err; });
// Handle redirects
if ([301, 302, 303, 307].includes(response.statusCode)) {
if (count < 5) {
return installRecursive(response.headers.location, count + 1);
}
console.warn(url);
throw new Error('Error: Too many redirects.');
}
// Handle bad status
if (response.statusCode !== 200) {
console.warn(url);
throw new Error(`Response status was ${response.statusCode}`);
}
await rmdir(getBin());
await mkdir(getBin());
const packPath = `${getBin()}/${getPlatform()}.gz`;
await new Promise((res, rej) => {
const packWriter = fs.createWriteStream(packPath);
packWriter.on('error', (err) => rej(err));
packWriter.on('finish', () => res());
response.pipe(packWriter);
});
const { stderr } = await exec(`tar -xzf ${packPath} --directory ${getBin()}`);
if (stderr) {
console.warn(stderr);
}
await rm(packPath);
return true;
} catch (error) {
console.error(error.message);
return false;
}
};
const install = async (folder) => {
const url = `${folder}/${getPlatform()}.gz`;
return installRecursive(url);
};
module.exports = { install };

View File

@ -1,22 +0,0 @@
'use strict';
const assert = require('node:assert').strict;
const { describe, it } = require('node:test');
const utils = require('.');
describe('AT / utils', () => {
const methods = [
'install', 'cpbin', 'download', 'read', 'write', 'copy', 'exists',
'mkdir', 'stat', 'isDir', 'isFile', 'dirUp', 'ensuredir', 'copysafe',
'readdir', 'subdirs', 'subfiles', 'traverse', 'copyall',
'rmdir', 'rm', 'WritableBuffer', 'actionPack',
];
methods.forEach((name) => {
it(`exports the "${name}" function`, () => {
assert.strictEqual(typeof utils[name], 'function');
});
});
});

View File

@ -1,7 +1,6 @@
'use strict'; 'use strict';
const { Writable } = require('node:stream'); const { Writable } = require('stream');
const CHUNK_SIZE = 1024; const CHUNK_SIZE = 1024;
const INITIAL_SIZE = 8 * CHUNK_SIZE; const INITIAL_SIZE = 8 * CHUNK_SIZE;
@ -9,48 +8,58 @@ const INCREMENT_SIZE = 8 * CHUNK_SIZE;
class WritableBuffer extends Writable { class WritableBuffer extends Writable {
constructor() { constructor() {
super(); super();
this._buffer = Buffer.alloc(INITIAL_SIZE); this._buffer = new Buffer(INITIAL_SIZE);
this._size = 0; this._size = 0;
} }
get() { get() {
if (!this._size) {
if ( ! this._size ) {
return null; return null;
} }
const data = Buffer.alloc(this._size); const data = new Buffer(this._size);
this._buffer.copy(data, 0, 0, this._size); this._buffer.copy(data, 0, 0, this._size);
return data; return data;
} }
_increaseAsNeeded(incomingSize) { _increaseAsNeeded(incomingSize) {
if ((this._buffer.length - this._size) >= incomingSize) {
if ( (this._buffer.length - this._size) >= incomingSize ) {
return; return;
} }
const freeSpace = this._buffer.length - this._size; const freeSpace = this._buffer.length - this._size;
const factor = Math.ceil((incomingSize - freeSpace) / INCREMENT_SIZE); const factor = Math.ceil((incomingSize - freeSpace) / INCREMENT_SIZE);
const newBuffer = Buffer.alloc(this._buffer.length + (INCREMENT_SIZE * factor)); const newBuffer = new Buffer(this._buffer.length + (INCREMENT_SIZE * factor));
this._buffer.copy(newBuffer, 0, 0, this._size); this._buffer.copy(newBuffer, 0, 0, this._size);
this._buffer = newBuffer; this._buffer = newBuffer;
} }
_write(chunk, encoding, callback) { _write(chunk, encoding, callback) {
this._increaseAsNeeded(chunk.length); this._increaseAsNeeded(chunk.length);
chunk.copy(this._buffer, this._size, 0); chunk.copy(this._buffer, this._size, 0);
this._size += chunk.length; this._size += chunk.length;
callback(); callback();
} }
} }
module.exports = { WritableBuffer }; module.exports = WritableBuffer;