summaryrefslogtreecommitdiff
diff options
authorXavier Guimard <yadd@debian.org>2020-10-06 13:26:32 +0200
committergit-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com>2020-10-06 16:38:43 +0000
commita6460e6803b6cc8673dcd25bad8c798094f1152e (patch)
tree031dba2828d0681aa6180084c43ce1f767a591d5
parent864a27dd3ed1c3a69b7863daf3079991d2244640 (diff)
Imported using git-ubuntu import.
Notes
Notes: * Team upload [ Debian Janitor ] * Use correct machine-readable copyright file URI. * Update renamed lintian tag names in lintian overrides. * Set fields Upstream-Name, Upstream-Contact in debian/copyright. * Set upstream metadata fields: Bug-Submit. * Remove obsolete fields Contact, Name from debian/upstream/metadata (already present in machine-readable debian/copyright). [ Xavier Guimard ] * Bump debhelper compatibility level to 13 * Use dh-sequence-nodejs * New upstream version 5.0.0+ds1 * Embed node-addon-api for build only * Update copyright * Don't launch 2 failed tests with mocha > 5 * Update build
-rw-r--r--.gitignore3
-rw-r--r--.travis.yml208
-rw-r--r--CHANGELOG.md7
-rw-r--r--README.md5
-rw-r--r--appveyor.yml134
-rw-r--r--binding.gyp19
-rw-r--r--debian/build_modules/node-addon-api/external-napi/node_api.h7
-rw-r--r--debian/build_modules/node-addon-api/index.js45
-rw-r--r--debian/build_modules/node-addon-api/napi-inl.deprecated.h192
-rw-r--r--debian/build_modules/node-addon-api/napi-inl.h4367
-rw-r--r--debian/build_modules/node-addon-api/napi.h2171
-rw-r--r--debian/build_modules/node-addon-api/package.json268
-rw-r--r--debian/build_modules/node-addon-api/src/node_api.cc3649
-rw-r--r--debian/build_modules/node-addon-api/src/node_api.gyp21
-rw-r--r--debian/build_modules/node-addon-api/src/node_api.h588
-rw-r--r--debian/build_modules/node-addon-api/src/node_api_types.h115
-rw-r--r--debian/build_modules/node-addon-api/src/node_internals.cc142
-rw-r--r--debian/build_modules/node-addon-api/src/node_internals.h157
-rw-r--r--debian/build_modules/node-addon-api/src/nothing.c0
-rw-r--r--debian/build_modules/node-addon-api/src/util-inl.h38
-rw-r--r--debian/build_modules/node-addon-api/src/util.h7
-rw-r--r--debian/build_modules/node-addon-api/tools/README.md67
-rw-r--r--debian/build_modules/node-addon-api/tools/check-napi.js100
-rwxr-xr-xdebian/build_modules/node-addon-api/tools/conversion.js313
-rw-r--r--debian/changelog23
-rw-r--r--debian/clean4
-rw-r--r--debian/control4
-rw-r--r--debian/copyright52
-rw-r--r--debian/patches/correct_require_path.patch31
-rw-r--r--debian/patches/series1
-rwxr-xr-xdebian/rules13
-rw-r--r--debian/salsa-ci.yml4
-rw-r--r--debian/source/lintian-overrides2
-rw-r--r--debian/tests/pkg-js/test2
-rw-r--r--debian/upstream/metadata3
-rw-r--r--lib/trace.js17
-rw-r--r--package.json22
-rw-r--r--scripts/build-appveyor.bat3
-rw-r--r--src/async.h12
-rw-r--r--src/backup.cc281
-rw-r--r--src/backup.h75
-rw-r--r--src/database.cc434
-rw-r--r--src/database.h100
-rw-r--r--src/macros.h170
-rw-r--r--src/node_sqlite3.cc90
-rw-r--r--src/statement.cc492
-rw-r--r--src/statement.h88
-rw-r--r--test/affected.test.js4
-rw-r--r--test/database_fail.test.js4
-rw-r--r--test/verbose.test.js60
50 files changed, 13440 insertions, 1174 deletions
diff --git a/.gitignore b/.gitignore
index cfbc04f..7990d97 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,4 +24,5 @@ test/nw/app.nw
local.env
.mason
.eslintrc.js
-setup.sh \ No newline at end of file
+setup.sh
+/build-tmp-napi-v3
diff --git a/.travis.yml b/.travis.yml
index f92e44d..14b7374 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -21,7 +21,7 @@ matrix:
- os: linux
dist: trusty
compiler: clang
- env: NODE_VERSION="13"
+ env: NODE_VERSION="14"
addons:
apt:
sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
@@ -29,78 +29,39 @@ matrix:
- os: linux
dist: trusty
compiler: clang
- env: NODE_VERSION="12"
+ env: NODE_VERSION="13"
addons:
apt:
sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- os: linux
+ dist: trusty
compiler: clang
- env: NODE_VERSION="11"
+ env: NODE_VERSION="12"
addons:
apt:
sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- os: linux
compiler: clang
- env: NODE_VERSION="10"
+ env: NODE_VERSION="11"
addons:
apt:
sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- os: linux
compiler: clang
- env: NODE_VERSION="9"
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5']
- - os: linux
- compiler: clang
- env: NODE_VERSION="8"
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5']
- - os: linux
- compiler: clang
- env: NODE_VERSION="7"
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5']
- - os: linux
- compiler: clang
- env: NODE_VERSION="6"
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5']
- - os: linux
- compiler: clang
- env: NODE_VERSION="5"
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5']
- - os: linux
- compiler: clang
- env: NODE_VERSION="4"
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5']
- # test building against external sqlite
- - os: linux
- compiler: clang
- env: NODE_VERSION="8" EXTERNAL_SQLITE=true PUBLISHABLE=false
+ env: NODE_VERSION="10"
addons:
apt:
sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5','libsqlite3-dev']
+ packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
# OS X
- os: osx
compiler: clang
+ env: NODE_VERSION="14" # node abi 83
+ - os: osx
+ compiler: clang
env: NODE_VERSION="13" # node abi 79
- os: osx
compiler: clang
@@ -110,29 +71,11 @@ matrix:
env: NODE_VERSION="11" # node abi 67
- os: osx
compiler: clang
- env: NODE_VERSION="10" # node abi 64
- - os: osx
- compiler: clang
- env: NODE_VERSION="9" # node abi 59
- - os: osx
- compiler: clang
- env: NODE_VERSION="8" # node abi 57
- - os: osx
- compiler: clang
- env: NODE_VERSION="7" # node abi 51
- - os: osx
- compiler: clang
- env: NODE_VERSION="6" # node abi 48
- - os: osx
- compiler: clang
- env: NODE_VERSION="5" # node abi 47
- - os: osx
- compiler: clang
- env: NODE_VERSION="4" # node abi 46
+ env: NODE_VERSION="10" # node abi 67
# electron Linux
- os: linux
compiler: clang
- env: NODE_VERSION="8" ELECTRON_VERSION="8.2.0"
+ env: NODE_VERSION="12" ELECTRON_VERSION="8.2.0"
dist: trusty
addons:
apt:
@@ -140,7 +83,7 @@ matrix:
packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- os: linux
compiler: clang
- env: NODE_VERSION="8" ELECTRON_VERSION="8.1.0"
+ env: NODE_VERSION="12" ELECTRON_VERSION="8.1.0"
dist: trusty
addons:
apt:
@@ -148,7 +91,7 @@ matrix:
packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- os: linux
compiler: clang
- env: NODE_VERSION="8" ELECTRON_VERSION="8.0.0"
+ env: NODE_VERSION="12" ELECTRON_VERSION="8.0.0"
dist: trusty
addons:
apt:
@@ -156,7 +99,7 @@ matrix:
packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- os: linux
compiler: clang
- env: NODE_VERSION="8" ELECTRON_VERSION="7.1.0"
+ env: NODE_VERSION="12" ELECTRON_VERSION="7.2.0"
dist: trusty
addons:
apt:
@@ -164,7 +107,7 @@ matrix:
packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- os: linux
compiler: clang
- env: NODE_VERSION="8" ELECTRON_VERSION="7.0.0"
+ env: NODE_VERSION="12" ELECTRON_VERSION="7.1.0"
dist: trusty
addons:
apt:
@@ -172,7 +115,7 @@ matrix:
packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- os: linux
compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="6.1.0"
+ env: NODE_VERSION="12" ELECTRON_VERSION="7.0.0"
dist: trusty
addons:
apt:
@@ -180,140 +123,45 @@ matrix:
packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- os: linux
compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="6.0.0"
- dist: trusty # needed for libc6 / 'version `GLIBC_2.17` not found' error on precise
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- - os: linux
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="5.0.0"
- dist: trusty # needed for libc6 / 'version `GLIBC_2.17` not found' error on precise
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- - os: linux
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="4.2.0"
- dist: trusty # needed for libc6 / 'version `GLIBC_2.17` not found' error on precise
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- - os: linux
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="4.1.0"
- dist: trusty # needed for libc6 / 'version `GLIBC_2.17` not found' error on precise
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- - os: linux
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="4.0.0"
- dist: trusty # needed for libc6 / 'version `GLIBC_2.17` not found' error on precise
+ env: NODE_VERSION="12" ELECTRON_VERSION="6.1.0"
+ dist: trusty
addons:
apt:
sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- os: linux
compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="3.0.6"
+ env: NODE_VERSION="12" ELECTRON_VERSION="6.0.0"
dist: trusty # needed for libc6 / 'version `GLIBC_2.17` not found' error on precise
addons:
apt:
sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
packages: [ 'clang-3.5', 'libstdc++-4.9-dev']
- - os: linux
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="2.0.1"
- dist: trusty # needed for libc6 / 'version `GLIBC_2.17` not found' error on precise
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5', 'libc6']
- - os: linux
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="1.8.4"
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5']
- - os: linux
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="1.7.12"
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5']
- - os: linux
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="1.6.2"
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5']
- - os: linux
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="1.3.14"
- addons:
- apt:
- sources: [ 'ubuntu-toolchain-r-test','llvm-toolchain-precise-3.5', 'gcc-multilib', 'g++-multilib', 'libsqlite3-dev:i386' ]
- packages: [ 'clang-3.5']
# electron MacOs
- os: osx
compiler: clang
- env: NODE_VERSION="8" ELECTRON_VERSION="8.2.0"
- - os: osx
- compiler: clang
- env: NODE_VERSION="8" ELECTRON_VERSION="8.1.0"
- - os: osx
- compiler: clang
- env: NODE_VERSION="8" ELECTRON_VERSION="8.0.0"
- - os: osx
- compiler: clang
- env: NODE_VERSION="8" ELECTRON_VERSION="7.1.0"
- - os: osx
- compiler: clang
- env: NODE_VERSION="8" ELECTRON_VERSION="7.0.0"
- - os: osx
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="6.1.0"
- - os: osx
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="6.0.0"
- - os: osx
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="5.0.0"
- - os: osx
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="4.2.0"
- - os: osx
- compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="4.1.0"
+ env: NODE_VERSION="12" ELECTRON_VERSION="8.2.0"
- os: osx
compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="4.0.0"
+ env: NODE_VERSION="12" ELECTRON_VERSION="8.1.0"
- os: osx
compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="3.0.6"
+ env: NODE_VERSION="12" ELECTRON_VERSION="8.0.0"
- os: osx
compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="2.0.1"
+ env: NODE_VERSION="12" ELECTRON_VERSION="7.2.0"
- os: osx
compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="1.8.4"
+ env: NODE_VERSION="12" ELECTRON_VERSION="7.1.0"
- os: osx
compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="1.7.12"
+ env: NODE_VERSION="12" ELECTRON_VERSION="7.0.0"
- os: osx
compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="1.6.2"
+ env: NODE_VERSION="12" ELECTRON_VERSION="6.1.0"
- os: osx
compiler: clang
- env: NODE_VERSION="6" ELECTRON_VERSION="1.3.14"
+ env: NODE_VERSION="12" ELECTRON_VERSION="6.0.0"
env:
global:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 48b5242..7401e59 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## 5.0.0
+- prebuilt: Node 14 support, dropped support for all version of Node < 10 [#1304](https://github.com/mapbox/node-sqlite3/pull/1304)
+- prebuilt: add electron 7.2 [#1324](https://github.com/mapbox/node-sqlite3/pull/1324)
+- napi: refactor codebase to use N-API instead of NAN (+ various improvements) [#1304](https://github.com/mapbox/node-sqlite3/pull/1304)
+- trace: don't require throw to add trace info for verbose [#1317](https://github.com/mapbox/node-sqlite3/pull/1317)
+- ci: remove permission setting [#1319](https://github.com/mapbox/node-sqlite3/pull/1319)
+
## 4.2.0
- electron: Electron v8, v8.1.x & v8.2.x [#1294](https://github.com/mapbox/node-sqlite3/pull/1294) [#1308](https://github.com/mapbox/node-sqlite3/pull/1308)
- sqlite3: update to 3.31.1 (3310100) [#1289](https://github.com/mapbox/node-sqlite3/pull/1289)
diff --git a/README.md b/README.md
index 9b691f2..06faeb9 100644
--- a/README.md
+++ b/README.md
@@ -7,12 +7,13 @@ Asynchronous, non-blocking [SQLite3](https://sqlite.org/) bindings for [Node.js]
[![Coverage Status](https://coveralls.io/repos/mapbox/node-sqlite3/badge.svg?branch=master&service=github)](https://coveralls.io/github/mapbox/node-sqlite3?branch=master)
[![Dependencies](https://david-dm.org/mapbox/node-sqlite3.svg)](https://david-dm.org/mapbox/node-sqlite3)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fnode-sqlite3.svg?type=shield)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2Fnode-sqlite3?ref=badge_shield)
+[![N-API v3 Badge](https://img.shields.io/badge/N--API-v3-green.svg)](https://nodejs.org/dist/latest/docs/api/n-api.html#n_api_n_api)
## Supported platforms
The `sqlite3` module works with:
-* Node.js v4.x, v6.x, v8.x, v10.x, v11.x, v12.x and v13.x.
-* Electron v1.3.X, v1.6.x, v1.7.x, v1.8.x, v2.0.x, v3.0.x, v4.0.x, v4.1.x, v4.2.x, v5.0.x, v6.0.x, v6.1.x, v7.0.x, v7.1.x, v8.0.x, v8.1.x and v8.2.x
+* Node.js v11.x, v12.x, v13.x and v14.x.
+* Electron v6.0.x, v6.1.x, v7.0.x, v7.1.x, v8.0.x, v8.1.x and v8.2.x
Binaries for most Node versions and platforms are provided by default via [node-pre-gyp](https://github.com/mapbox/node-pre-gyp).
diff --git a/appveyor.yml b/appveyor.yml
index 6ec3a59..249b240 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,31 +1,5 @@
environment:
matrix:
- - nodejs_version: 4
- platform: x64
- msvs_toolset: 12
- - nodejs_version: 4
- platform: x86
- msvs_toolset: 12
- - nodejs_version: 5
- platform: x64
- - nodejs_version: 5
- platform: x86
- - nodejs_version: 6
- platform: x64
- - nodejs_version: 6
- platform: x86
- - nodejs_version: 7
- platform: x64
- - nodejs_version: 7
- platform: x86
- - nodejs_version: 8
- platform: x64
- - nodejs_version: 8
- platform: x86
- - nodejs_version: 9
- platform: x64
- - nodejs_version: 9
- platform: x86
- nodejs_version: 10
platform: x64
- nodejs_version: 10
@@ -42,6 +16,10 @@ environment:
platform: x64
- nodejs_version: 13
platform: x86
+ - nodejs_version: 14
+ platform: x64
+ - nodejs_version: 14
+ platform: x86
# electron
- nodejs_version: 12
platform: x64
@@ -76,136 +54,52 @@ environment:
- nodejs_version: 12
platform: x64
NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 7.1.0
+ NODE_RUNTIME_VERSION: 7.2.0
TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- nodejs_version: 12
platform: x86
NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 7.1.0
+ NODE_RUNTIME_VERSION: 7.2.0
TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- nodejs_version: 12
platform: x64
NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 7.0.0
+ NODE_RUNTIME_VERSION: 7.1.0
TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- nodejs_version: 12
platform: x86
NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 7.0.0
+ NODE_RUNTIME_VERSION: 7.1.0
TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- nodejs_version: 12
platform: x64
NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 6.1.0
+ NODE_RUNTIME_VERSION: 7.0.0
TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- nodejs_version: 12
platform: x86
NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 6.1.0
+ NODE_RUNTIME_VERSION: 7.0.0
TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- nodejs_version: 12
platform: x64
NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 6.0.0
+ NODE_RUNTIME_VERSION: 6.1.0
TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- nodejs_version: 12
platform: x86
NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 6.0.0
+ NODE_RUNTIME_VERSION: 6.1.0
TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- nodejs_version: 12
platform: x64
NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 5.0.0
+ NODE_RUNTIME_VERSION: 6.0.0
TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- nodejs_version: 12
platform: x86
NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 5.0.0
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 10
- platform: x64
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 4.2.0
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 10
- platform: x64
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 4.1.0
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 10
- platform: x64
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 4.0.0
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 10
- platform: x86
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 4.0.0
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 10
- platform: x64
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 3.0.6
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 10
- platform: x86
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 3.0.6
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 8
- platform: x64
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 2.0.1
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 8
- platform: x86
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 2.0.1
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 8
- platform: x64
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 1.8.4
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 8
- platform: x86
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 1.8.4
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 7
- platform: x64
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 1.7.12
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 7
- platform: x86
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 1.7.12
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 6
- platform: x64
- msvs_toolset: 12
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 1.6.2
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 6
- platform: x86
- msvs_toolset: 12
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 1.6.2
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 6
- platform: x64
- msvs_toolset: 12
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 1.3.14
- TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
- - nodejs_version: 6
- platform: x86
- msvs_toolset: 12
- NODE_RUNTIME: electron
- NODE_RUNTIME_VERSION: 1.3.14
+ NODE_RUNTIME_VERSION: 6.0.0
TOOLSET_ARGS: --dist-url=https://electronjs.org/headers
os: Visual Studio 2015
diff --git a/binding.gyp b/binding.gyp
index 019df41..f1336f6 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -7,10 +7,21 @@
"targets": [
{
"target_name": "<(module_name)",
- "include_dirs": ["<!(node -e \"require('nan')\")"],
+ "cflags!": [ "-fno-exceptions" ],
+ "cflags_cc!": [ "-fno-exceptions" ],
+ "xcode_settings": { "GCC_ENABLE_CPP_EXCEPTIONS": "YES",
+ "CLANG_CXX_LIBRARY": "libc++",
+ "MACOSX_DEPLOYMENT_TARGET": "10.7",
+ },
+ "msvs_settings": {
+ "VCCLCompilerTool": { "ExceptionHandling": 1 },
+ },
+ "include_dirs": [
+ "<!@(node -p \"require('node-addon-api').include\")"],
"conditions": [
["sqlite != 'internal'", {
- "include_dirs": [ "<(sqlite)/include" ],
+ "include_dirs": [
+ "<!@(node -p \"require('node-addon-api').include\")", "<(sqlite)/include" ],
"libraries": [
"-l<(sqlite_libname)"
],
@@ -26,6 +37,7 @@
},
{
"dependencies": [
+ "<!(node -p \"require('node-addon-api').gyp\")",
"deps/sqlite3.gyp:sqlite3"
]
}
@@ -36,7 +48,8 @@
"src/database.cc",
"src/node_sqlite3.cc",
"src/statement.cc"
- ]
+ ],
+ "defines": [ "NAPI_VERSION=<(napi_build_version)", "NAPI_DISABLE_CPP_EXCEPTIONS=1" ]
},
{
"target_name": "action_after_build",
diff --git a/debian/build_modules/node-addon-api/external-napi/node_api.h b/debian/build_modules/node-addon-api/external-napi/node_api.h
new file mode 100644
index 0000000..52c45f6
--- /dev/null
+++ b/debian/build_modules/node-addon-api/external-napi/node_api.h
@@ -0,0 +1,7 @@
+#ifndef EXTERNAL_NODE_API_H_
+#define EXTERNAL_NODE_API_H_
+
+#define EXTERNAL_NAPI
+#include "../src/node_api.h"
+
+#endif
diff --git a/debian/build_modules/node-addon-api/index.js b/debian/build_modules/node-addon-api/index.js
new file mode 100644
index 0000000..74e90e8
--- /dev/null
+++ b/debian/build_modules/node-addon-api/index.js
@@ -0,0 +1,45 @@
+var path = require('path');
+
+var versionArray = process.version
+ .substr(1)
+ .replace(/-.*$/, '')
+ .split('.')
+ .map(function(item) {
+ return +item;
+ });
+
+// TODO: Check if the main node semantic version is within multiple ranges,
+// or detect presence of built-in N-API by some other mechanism TBD.
+
+// We know which version of Node.js first shipped the incarnation of the API
+// available in *this* package. So, if we find that the Node.js version is below
+// that, we indicate that the API is missing from Node.js.
+var isNodeApiBuiltin = (
+ versionArray[0] > 8 ||
+ (versionArray[0] == 8 && versionArray[1] >= 6) ||
+ (versionArray[0] == 6 && versionArray[1] >= 15) ||
+ (versionArray[0] == 6 && versionArray[1] >= 14 && versionArray[2] >= 2));
+
+// The flag is not needed when the Node version is not 8, nor if the API is
+// built-in, because we removed the flag at the same time as creating the final
+// incarnation of the built-in API.
+var needsFlag = (!isNodeApiBuiltin && versionArray[0] == 8);
+
+var include = [__dirname];
+var gyp = path.join(__dirname, 'src', 'node_api.gyp');
+
+if (isNodeApiBuiltin) {
+ gyp += ':nothing';
+} else {
+ gyp += ':node-api';
+ include.unshift(path.join(__dirname, 'external-napi'));
+}
+
+module.exports = {
+ include: include.map(function(item) {
+ return '"' + item + '"';
+ }).join(' '),
+ gyp: gyp,
+ isNodeApiBuiltin: isNodeApiBuiltin,
+ needsFlag: needsFlag
+};
diff --git a/debian/build_modules/node-addon-api/napi-inl.deprecated.h b/debian/build_modules/node-addon-api/napi-inl.deprecated.h
new file mode 100644
index 0000000..f19aca7
--- /dev/null
+++ b/debian/build_modules/node-addon-api/napi-inl.deprecated.h
@@ -0,0 +1,192 @@
+#ifndef SRC_NAPI_INL_DEPRECATED_H_
+#define SRC_NAPI_INL_DEPRECATED_H_
+
+////////////////////////////////////////////////////////////////////////////////
+// PropertyDescriptor class
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename Getter>
+inline PropertyDescriptor
+PropertyDescriptor::Accessor(const char* utf8name,
+ Getter getter,
+ napi_property_attributes attributes,
+ void* /*data*/) {
+ typedef details::CallbackData<Getter, Napi::Value> CbData;
+ // TODO: Delete when the function is destroyed
+ auto callbackData = new CbData({ getter, nullptr });
+
+ return PropertyDescriptor({
+ utf8name,
+ nullptr,
+ nullptr,
+ CbData::Wrapper,
+ nullptr,
+ nullptr,
+ attributes,
+ callbackData
+ });
+}
+
+template <typename Getter>
+inline PropertyDescriptor PropertyDescriptor::Accessor(const std::string& utf8name,
+ Getter getter,
+ napi_property_attributes attributes,
+ void* data) {
+ return Accessor(utf8name.c_str(), getter, attributes, data);
+}
+
+template <typename Getter>
+inline PropertyDescriptor PropertyDescriptor::Accessor(napi_value name,
+ Getter getter,
+ napi_property_attributes attributes,
+ void* /*data*/) {
+ typedef details::CallbackData<Getter, Napi::Value> CbData;
+ // TODO: Delete when the function is destroyed
+ auto callbackData = new CbData({ getter, nullptr });
+
+ return PropertyDescriptor({
+ nullptr,
+ name,
+ nullptr,
+ CbData::Wrapper,
+ nullptr,
+ nullptr,
+ attributes,
+ callbackData
+ });
+}
+
+template <typename Getter>
+inline PropertyDescriptor PropertyDescriptor::Accessor(Name name,
+ Getter getter,
+ napi_property_attributes attributes,
+ void* data) {
+ napi_value nameValue = name;
+ return PropertyDescriptor::Accessor(nameValue, getter, attributes, data);
+}
+
+template <typename Getter, typename Setter>
+inline PropertyDescriptor PropertyDescriptor::Accessor(const char* utf8name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes,
+ void* /*data*/) {
+ typedef details::AccessorCallbackData<Getter, Setter> CbData;
+ // TODO: Delete when the function is destroyed
+ auto callbackData = new CbData({ getter, setter, nullptr });
+
+ return PropertyDescriptor({
+ utf8name,
+ nullptr,
+ nullptr,
+ CbData::GetterWrapper,
+ CbData::SetterWrapper,
+ nullptr,
+ attributes,
+ callbackData
+ });
+}
+
+template <typename Getter, typename Setter>
+inline PropertyDescriptor PropertyDescriptor::Accessor(const std::string& utf8name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes,
+ void* data) {
+ return Accessor(utf8name.c_str(), getter, setter, attributes, data);
+}
+
+template <typename Getter, typename Setter>
+inline PropertyDescriptor PropertyDescriptor::Accessor(napi_value name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes,
+ void* /*data*/) {
+ typedef details::AccessorCallbackData<Getter, Setter> CbData;
+ // TODO: Delete when the function is destroyed
+ auto callbackData = new CbData({ getter, setter, nullptr });
+
+ return PropertyDescriptor({
+ nullptr,
+ name,
+ nullptr,
+ CbData::GetterWrapper,
+ CbData::SetterWrapper,
+ nullptr,
+ attributes,
+ callbackData
+ });
+}
+
+template <typename Getter, typename Setter>
+inline PropertyDescriptor PropertyDescriptor::Accessor(Name name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes,
+ void* data) {
+ napi_value nameValue = name;
+ return PropertyDescriptor::Accessor(nameValue, getter, setter, attributes, data);
+}
+
+template <typename Callable>
+inline PropertyDescriptor PropertyDescriptor::Function(const char* utf8name,
+ Callable cb,
+ napi_property_attributes attributes,
+ void* /*data*/) {
+ typedef decltype(cb(CallbackInfo(nullptr, nullptr))) ReturnType;
+ typedef details::CallbackData<Callable, ReturnType> CbData;
+ // TODO: Delete when the function is destroyed
+ auto callbackData = new CbData({ cb, nullptr });
+
+ return PropertyDescriptor({
+ utf8name,
+ nullptr,
+ CbData::Wrapper,
+ nullptr,
+ nullptr,
+ nullptr,
+ attributes,
+ callbackData
+ });
+}
+
+template <typename Callable>
+inline PropertyDescriptor PropertyDescriptor::Function(const std::string& utf8name,
+ Callable cb,
+ napi_property_attributes attributes,
+ void* data) {
+ return Function(utf8name.c_str(), cb, attributes, data);
+}
+
+template <typename Callable>
+inline PropertyDescriptor PropertyDescriptor::Function(napi_value name,
+ Callable cb,
+ napi_property_attributes attributes,
+ void* /*data*/) {
+ typedef decltype(cb(CallbackInfo(nullptr, nullptr))) ReturnType;
+ typedef details::CallbackData<Callable, ReturnType> CbData;
+ // TODO: Delete when the function is destroyed
+ auto callbackData = new CbData({ cb, nullptr });
+
+ return PropertyDescriptor({
+ nullptr,
+ name,
+ CbData::Wrapper,
+ nullptr,
+ nullptr,
+ nullptr,
+ attributes,
+ callbackData
+ });
+}
+
+template <typename Callable>
+inline PropertyDescriptor PropertyDescriptor::Function(Name name,
+ Callable cb,
+ napi_property_attributes attributes,
+ void* data) {
+ napi_value nameValue = name;
+ return PropertyDescriptor::Function(nameValue, cb, attributes, data);
+}
+
+#endif // !SRC_NAPI_INL_DEPRECATED_H_
diff --git a/debian/build_modules/node-addon-api/napi-inl.h b/debian/build_modules/node-addon-api/napi-inl.h
new file mode 100644
index 0000000..f72e1da
--- /dev/null
+++ b/debian/build_modules/node-addon-api/napi-inl.h
@@ -0,0 +1,4367 @@
+#ifndef SRC_NAPI_INL_H_
+#define SRC_NAPI_INL_H_
+
+////////////////////////////////////////////////////////////////////////////////
+// N-API C++ Wrapper Classes
+//
+// Inline header-only implementations for "N-API" ABI-stable C APIs for Node.js.
+////////////////////////////////////////////////////////////////////////////////
+
+// Note: Do not include this file directly! Include "napi.h" instead.
+
+#include <algorithm>
+#include <cstring>
+#include <mutex>
+#include <type_traits>
+
+namespace Napi {
+
+// Helpers to handle functions exposed from C++.
+namespace details {
+
+// Attach a data item to an object and delete it when the object gets
+// garbage-collected.
+// TODO: Replace this code with `napi_add_finalizer()` whenever it becomes
+// available on all supported versions of Node.js.
+template <typename FreeType>
+static inline napi_status AttachData(napi_env env,
+ napi_value obj,
+ FreeType* data,
+ napi_finalize finalizer = nullptr,
+ void* hint = nullptr) {
+ napi_status status;
+ if (finalizer == nullptr) {
+ finalizer = [](napi_env /*env*/, void* data, void* /*hint*/) {
+ delete static_cast<FreeType*>(data);
+ };
+ }
+#if (NAPI_VERSION < 5)
+ napi_value symbol, external;
+ status = napi_create_symbol(env, nullptr, &symbol);
+ if (status == napi_ok) {
+ status = napi_create_external(env,
+ data,
+ finalizer,
+ hint,
+ &external);
+ if (status == napi_ok) {
+ napi_property_descriptor desc = {
+ nullptr,
+ symbol,
+ nullptr,
+ nullptr,
+ nullptr,
+ external,
+ napi_default,
+ nullptr
+ };
+ status = napi_define_properties(env, obj, 1, &desc);
+ }
+ }
+#else // NAPI_VERSION >= 5
+ status = napi_add_finalizer(env, obj, data, finalizer, hint, nullptr);
+#endif
+ return status;
+}
+
+// For use in JS to C++ callback wrappers to catch any Napi::Error exceptions
+// and rethrow them as JavaScript exceptions before returning from the callback.
+template <typename Callable>
+inline napi_value WrapCallback(Callable callback) {
+#ifdef NAPI_CPP_EXCEPTIONS
+ try {
+ return callback();
+ } catch (const Error& e) {
+ e.ThrowAsJavaScriptException();
+ return nullptr;
+ }
+#else // NAPI_CPP_EXCEPTIONS
+ // When C++ exceptions are disabled, errors are immediately thrown as JS
+ // exceptions, so there is no need to catch and rethrow them here.
+ return callback();
+#endif // NAPI_CPP_EXCEPTIONS
+}
+
+template <typename Callable, typename Return>
+struct CallbackData {
+ static inline
+ napi_value Wrapper(napi_env env, napi_callback_info info) {
+ return details::WrapCallback([&] {
+ CallbackInfo callbackInfo(env, info);
+ CallbackData* callbackData =
+ static_cast<CallbackData*>(callbackInfo.Data());
+ callbackInfo.SetData(callbackData->data);
+ return callbackData->callback(callbackInfo);
+ });
+ }
+
+ Callable callback;
+ void* data;
+};
+
+template <typename Callable>
+struct CallbackData<Callable, void> {
+ static inline
+ napi_value Wrapper(napi_env env, napi_callback_info info) {
+ return details::WrapCallback([&] {
+ CallbackInfo callbackInfo(env, info);
+ CallbackData* callbackData =
+ static_cast<CallbackData*>(callbackInfo.Data());
+ callbackInfo.SetData(callbackData->data);
+ callbackData->callback(callbackInfo);
+ return nullptr;
+ });
+ }
+
+ Callable callback;
+ void* data;
+};
+
+template <typename T, typename Finalizer, typename Hint = void>
+struct FinalizeData {
+ static inline
+ void Wrapper(napi_env env, void* data, void* finalizeHint) {
+ FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
+ finalizeData->callback(Env(env), static_cast<T*>(data));
+ delete finalizeData;
+ }
+
+ static inline
+ void WrapperWithHint(napi_env env, void* data, void* finalizeHint) {
+ FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
+ finalizeData->callback(Env(env), static_cast<T*>(data), finalizeData->hint);
+ delete finalizeData;
+ }
+
+ Finalizer callback;
+ Hint* hint;
+};
+
+#if (NAPI_VERSION > 3)
+template <typename ContextType=void,
+ typename Finalizer=std::function<void(Env, void*, ContextType*)>,
+ typename FinalizerDataType=void>
+struct ThreadSafeFinalize {
+ static inline
+ void Wrapper(napi_env env, void* rawFinalizeData, void* /* rawContext */) {
+ if (rawFinalizeData == nullptr)
+ return;
+
+ ThreadSafeFinalize* finalizeData =
+ static_cast<ThreadSafeFinalize*>(rawFinalizeData);
+ finalizeData->callback(Env(env));
+ if (finalizeData->tsfn) {
+ *finalizeData->tsfn = nullptr;
+ }
+ delete finalizeData;
+ }
+
+ static inline
+ void FinalizeWrapperWithData(napi_env env,
+ void* rawFinalizeData,
+ void* /* rawContext */) {
+ if (rawFinalizeData == nullptr)
+ return;
+
+ ThreadSafeFinalize* finalizeData =
+ static_cast<ThreadSafeFinalize*>(rawFinalizeData);
+ finalizeData->callback(Env(env), finalizeData->data);
+ if (finalizeData->tsfn) {
+ *finalizeData->tsfn = nullptr;
+ }
+ delete finalizeData;
+ }
+
+ static inline
+ void FinalizeWrapperWithContext(napi_env env,
+ void* rawFinalizeData,
+ void* rawContext) {
+ if (rawFinalizeData == nullptr)
+ return;
+
+ ThreadSafeFinalize* finalizeData =
+ static_cast<ThreadSafeFinalize*>(rawFinalizeData);
+ finalizeData->callback(Env(env), static_cast<ContextType*>(rawContext));
+ if (finalizeData->tsfn) {
+ *finalizeData->tsfn = nullptr;
+ }
+ delete finalizeData;
+ }
+
+ static inline
+ void FinalizeFinalizeWrapperWithDataAndContext(napi_env env,
+ void* rawFinalizeData,
+ void* rawContext) {
+ if (rawFinalizeData == nullptr)
+ return;
+
+ ThreadSafeFinalize* finalizeData =
+ static_cast<ThreadSafeFinalize*>(rawFinalizeData);
+ finalizeData->callback(Env(env), finalizeData->data,
+ static_cast<ContextType*>(rawContext));
+ if (finalizeData->tsfn) {
+ *finalizeData->tsfn = nullptr;
+ }
+ delete finalizeData;
+ }
+
+ FinalizerDataType* data;
+ Finalizer callback;
+ napi_threadsafe_function* tsfn;
+};
+#endif
+
+template <typename Getter, typename Setter>
+struct AccessorCallbackData {
+ static inline
+ napi_value GetterWrapper(napi_env env, napi_callback_info info) {
+ return details::WrapCallback([&] {
+ CallbackInfo callbackInfo(env, info);
+ AccessorCallbackData* callbackData =
+ static_cast<AccessorCallbackData*>(callbackInfo.Data());
+ callbackInfo.SetData(callbackData->data);
+ return callbackData->getterCallback(callbackInfo);
+ });
+ }
+
+ static inline
+ napi_value SetterWrapper(napi_env env, napi_callback_info info) {
+ return details::WrapCallback([&] {
+ CallbackInfo callbackInfo(env, info);
+ AccessorCallbackData* callbackData =
+ static_cast<AccessorCallbackData*>(callbackInfo.Data());
+ callbackInfo.SetData(callbackData->data);
+ callbackData->setterCallback(callbackInfo);
+ return nullptr;
+ });
+ }
+
+ Getter getterCallback;
+ Setter setterCallback;
+ void* data;
+};
+
+} // namespace details
+
+#ifndef NODE_ADDON_API_DISABLE_DEPRECATED
+# include "napi-inl.deprecated.h"
+#endif // !NODE_ADDON_API_DISABLE_DEPRECATED
+
+////////////////////////////////////////////////////////////////////////////////
+// Module registration
+////////////////////////////////////////////////////////////////////////////////
+
+#define NODE_API_MODULE(modname, regfunc) \
+ napi_value __napi_ ## regfunc(napi_env env, \
+ napi_value exports) { \
+ return Napi::RegisterModule(env, exports, regfunc); \
+ } \
+ NAPI_MODULE(modname, __napi_ ## regfunc)
+
+// Adapt the NAPI_MODULE registration function:
+// - Wrap the arguments in NAPI wrappers.
+// - Catch any NAPI errors and rethrow as JS exceptions.
+inline napi_value RegisterModule(napi_env env,
+ napi_value exports,
+ ModuleRegisterCallback registerCallback) {
+ return details::WrapCallback([&] {
+ return napi_value(registerCallback(Napi::Env(env),
+ Napi::Object(env, exports)));
+ });
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Env class
+////////////////////////////////////////////////////////////////////////////////
+
+inline Env::Env(napi_env env) : _env(env) {
+}
+
+inline Env::operator napi_env() const {
+ return _env;
+}
+
+inline Object Env::Global() const {
+ napi_value value;
+ napi_status status = napi_get_global(*this, &value);
+ NAPI_THROW_IF_FAILED(*this, status, Object());
+ return Object(*this, value);
+}
+
+inline Value Env::Undefined() const {
+ napi_value value;
+ napi_status status = napi_get_undefined(*this, &value);
+ NAPI_THROW_IF_FAILED(*this, status, Value());
+ return Value(*this, value);
+}
+
+inline Value Env::Null() const {
+ napi_value value;
+ napi_status status = napi_get_null(*this, &value);
+ NAPI_THROW_IF_FAILED(*this, status, Value());
+ return Value(*this, value);
+}
+
+inline bool Env::IsExceptionPending() const {
+ bool result;
+ napi_status status = napi_is_exception_pending(_env, &result);
+ if (status != napi_ok) result = false; // Checking for a pending exception shouldn't throw.
+ return result;
+}
+
+inline Error Env::GetAndClearPendingException() {
+ napi_value value;
+ napi_status status = napi_get_and_clear_last_exception(_env, &value);
+ if (status != napi_ok) {
+ // Don't throw another exception when failing to get the exception!
+ return Error();
+ }
+ return Error(_env, value);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Value class
+////////////////////////////////////////////////////////////////////////////////
+
+inline Value::Value() : _env(nullptr), _value(nullptr) {
+}
+
+inline Value::Value(napi_env env, napi_value value) : _env(env), _value(value) {
+}
+
+inline Value::operator napi_value() const {
+ return _value;
+}
+
+inline bool Value::operator ==(const Value& other) const {
+ return StrictEquals(other);
+}
+
+inline bool Value::operator !=(const Value& other) const {
+ return !this->operator ==(other);
+}
+
+inline bool Value::StrictEquals(const Value& other) const {
+ bool result;
+ napi_status status = napi_strict_equals(_env, *this, other, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline Napi::Env Value::Env() const {
+ return Napi::Env(_env);
+}
+
+inline bool Value::IsEmpty() const {
+ return _value == nullptr;
+}
+
+inline napi_valuetype Value::Type() const {
+ if (IsEmpty()) {
+ return napi_undefined;
+ }
+
+ napi_valuetype type;
+ napi_status status = napi_typeof(_env, _value, &type);
+ NAPI_THROW_IF_FAILED(_env, status, napi_undefined);
+ return type;
+}
+
+inline bool Value::IsUndefined() const {
+ return Type() == napi_undefined;
+}
+
+inline bool Value::IsNull() const {
+ return Type() == napi_null;
+}
+
+inline bool Value::IsBoolean() const {
+ return Type() == napi_boolean;
+}
+
+inline bool Value::IsNumber() const {
+ return Type() == napi_number;
+}
+
+// Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
+// Once it is no longer experimental guard with the NAPI_VERSION in which it is
+// released instead.
+#ifdef NAPI_EXPERIMENTAL
+inline bool Value::IsBigInt() const {
+ return Type() == napi_bigint;
+}
+#endif // NAPI_EXPERIMENTAL
+
+#if (NAPI_VERSION > 4)
+inline bool Value::IsDate() const {
+ if (IsEmpty()) {
+ return false;
+ }
+
+ bool result;
+ napi_status status = napi_is_date(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+#endif
+
+inline bool Value::IsString() const {
+ return Type() == napi_string;
+}
+
+inline bool Value::IsSymbol() const {
+ return Type() == napi_symbol;
+}
+
+inline bool Value::IsArray() const {
+ if (IsEmpty()) {
+ return false;
+ }
+
+ bool result;
+ napi_status status = napi_is_array(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline bool Value::IsArrayBuffer() const {
+ if (IsEmpty()) {
+ return false;
+ }
+
+ bool result;
+ napi_status status = napi_is_arraybuffer(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline bool Value::IsTypedArray() const {
+ if (IsEmpty()) {
+ return false;
+ }
+
+ bool result;
+ napi_status status = napi_is_typedarray(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline bool Value::IsObject() const {
+ return Type() == napi_object || IsFunction();
+}
+
+inline bool Value::IsFunction() const {
+ return Type() == napi_function;
+}
+
+inline bool Value::IsPromise() const {
+ if (IsEmpty()) {
+ return false;
+ }
+
+ bool result;
+ napi_status status = napi_is_promise(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline bool Value::IsDataView() const {
+ if (IsEmpty()) {
+ return false;
+ }
+
+ bool result;
+ napi_status status = napi_is_dataview(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline bool Value::IsBuffer() const {
+ if (IsEmpty()) {
+ return false;
+ }
+
+ bool result;
+ napi_status status = napi_is_buffer(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline bool Value::IsExternal() const {
+ return Type() == napi_external;
+}
+
+template <typename T>
+inline T Value::As() const {
+ return T(_env, _value);
+}
+
+inline Boolean Value::ToBoolean() const {
+ napi_value result;
+ napi_status status = napi_coerce_to_bool(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, Boolean());
+ return Boolean(_env, result);
+}
+
+inline Number Value::ToNumber() const {
+ napi_value result;
+ napi_status status = napi_coerce_to_number(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, Number());
+ return Number(_env, result);
+}
+
+inline String Value::ToString() const {
+ napi_value result;
+ napi_status status = napi_coerce_to_string(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, String());
+ return String(_env, result);
+}
+
+inline Object Value::ToObject() const {
+ napi_value result;
+ napi_status status = napi_coerce_to_object(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, Object());
+ return Object(_env, result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Boolean class
+////////////////////////////////////////////////////////////////////////////////
+
+inline Boolean Boolean::New(napi_env env, bool val) {
+ napi_value value;
+ napi_status status = napi_get_boolean(env, val, &value);
+ NAPI_THROW_IF_FAILED(env, status, Boolean());
+ return Boolean(env, value);
+}
+
+inline Boolean::Boolean() : Napi::Value() {
+}
+
+inline Boolean::Boolean(napi_env env, napi_value value) : Napi::Value(env, value) {
+}
+
+inline Boolean::operator bool() const {
+ return Value();
+}
+
+inline bool Boolean::Value() const {
+ bool result;
+ napi_status status = napi_get_value_bool(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Number class
+////////////////////////////////////////////////////////////////////////////////
+
+inline Number Number::New(napi_env env, double val) {
+ napi_value value;
+ napi_status status = napi_create_double(env, val, &value);
+ NAPI_THROW_IF_FAILED(env, status, Number());
+ return Number(env, value);
+}
+
+inline Number::Number() : Value() {
+}
+
+inline Number::Number(napi_env env, napi_value value) : Value(env, value) {
+}
+
+inline Number::operator int32_t() const {
+ return Int32Value();
+}
+
+inline Number::operator uint32_t() const {
+ return Uint32Value();
+}
+
+inline Number::operator int64_t() const {
+ return Int64Value();
+}
+
+inline Number::operator float() const {
+ return FloatValue();
+}
+
+inline Number::operator double() const {
+ return DoubleValue();
+}
+
+inline int32_t Number::Int32Value() const {
+ int32_t result;
+ napi_status status = napi_get_value_int32(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, 0);
+ return result;
+}
+
+inline uint32_t Number::Uint32Value() const {
+ uint32_t result;
+ napi_status status = napi_get_value_uint32(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, 0);
+ return result;
+}
+
+inline int64_t Number::Int64Value() const {
+ int64_t result;
+ napi_status status = napi_get_value_int64(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, 0);
+ return result;
+}
+
+inline float Number::FloatValue() const {
+ return static_cast<float>(DoubleValue());
+}
+
+inline double Number::DoubleValue() const {
+ double result;
+ napi_status status = napi_get_value_double(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, 0);
+ return result;
+}
+
+// Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
+// Once it is no longer experimental guard with the NAPI_VERSION in which it is
+// released instead.
+#ifdef NAPI_EXPERIMENTAL
+////////////////////////////////////////////////////////////////////////////////
+// BigInt Class
+////////////////////////////////////////////////////////////////////////////////
+
+inline BigInt BigInt::New(napi_env env, int64_t val) {
+ napi_value value;
+ napi_status status = napi_create_bigint_int64(env, val, &value);
+ NAPI_THROW_IF_FAILED(env, status, BigInt());
+ return BigInt(env, value);
+}
+
+inline BigInt BigInt::New(napi_env env, uint64_t val) {
+ napi_value value;
+ napi_status status = napi_create_bigint_uint64(env, val, &value);
+ NAPI_THROW_IF_FAILED(env, status, BigInt());
+ return BigInt(env, value);
+}
+
+inline BigInt BigInt::New(napi_env env, int sign_bit, size_t word_count, const uint64_t* words) {
+ napi_value value;
+ napi_status status = napi_create_bigint_words(env, sign_bit, word_count, words, &value);
+ NAPI_THROW_IF_FAILED(env, status, BigInt());
+ return BigInt(env, value);
+}
+
+inline BigInt::BigInt() : Value() {
+}
+
+inline BigInt::BigInt(napi_env env, napi_value value) : Value(env, value) {
+}
+
+inline int64_t BigInt::Int64Value(bool* lossless) const {
+ int64_t result;
+ napi_status status = napi_get_value_bigint_int64(
+ _env, _value, &result, lossless);
+ NAPI_THROW_IF_FAILED(_env, status, 0);
+ return result;
+}
+
+inline uint64_t BigInt::Uint64Value(bool* lossless) const {
+ uint64_t result;
+ napi_status status = napi_get_value_bigint_uint64(
+ _env, _value, &result, lossless);
+ NAPI_THROW_IF_FAILED(_env, status, 0);
+ return result;
+}
+
+inline size_t BigInt::WordCount() const {
+ size_t word_count;
+ napi_status status = napi_get_value_bigint_words(
+ _env, _value, nullptr, &word_count, nullptr);
+ NAPI_THROW_IF_FAILED(_env, status, 0);
+ return word_count;
+}
+
+inline void BigInt::ToWords(int* sign_bit, size_t* word_count, uint64_t* words) {
+ napi_status status = napi_get_value_bigint_words(
+ _env, _value, sign_bit, word_count, words);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+#endif // NAPI_EXPERIMENTAL
+
+#if (NAPI_VERSION > 4)
+////////////////////////////////////////////////////////////////////////////////
+// Date Class
+////////////////////////////////////////////////////////////////////////////////
+
+inline Date Date::New(napi_env env, double val) {
+ napi_value value;
+ napi_status status = napi_create_date(env, val, &value);
+ NAPI_THROW_IF_FAILED(env, status, Date());
+ return Date(env, value);
+}
+
+inline Date::Date() : Value() {
+}
+
+inline Date::Date(napi_env env, napi_value value) : Value(env, value) {
+}
+
+inline Date::operator double() const {
+ return ValueOf();
+}
+
+inline double Date::ValueOf() const {
+ double result;
+ napi_status status = napi_get_date_value(
+ _env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, 0);
+ return result;
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Name class
+////////////////////////////////////////////////////////////////////////////////
+
+inline Name::Name() : Value() {
+}
+
+inline Name::Name(napi_env env, napi_value value) : Value(env, value) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// String class
+////////////////////////////////////////////////////////////////////////////////
+
+inline String String::New(napi_env env, const std::string& val) {
+ return String::New(env, val.c_str(), val.size());
+}
+
+inline String String::New(napi_env env, const std::u16string& val) {
+ return String::New(env, val.c_str(), val.size());
+}
+
+inline String String::New(napi_env env, const char* val) {
+ napi_value value;
+ napi_status status = napi_create_string_utf8(env, val, std::strlen(val), &value);
+ NAPI_THROW_IF_FAILED(env, status, String());
+ return String(env, value);
+}
+
+inline String String::New(napi_env env, const char16_t* val) {
+ napi_value value;
+ napi_status status = napi_create_string_utf16(env, val, std::u16string(val).size(), &value);
+ NAPI_THROW_IF_FAILED(env, status, String());
+ return String(env, value);
+}
+
+inline String String::New(napi_env env, const char* val, size_t length) {
+ napi_value value;
+ napi_status status = napi_create_string_utf8(env, val, length, &value);
+ NAPI_THROW_IF_FAILED(env, status, String());
+ return String(env, value);
+}
+
+inline String String::New(napi_env env, const char16_t* val, size_t length) {
+ napi_value value;
+ napi_status status = napi_create_string_utf16(env, val, length, &value);
+ NAPI_THROW_IF_FAILED(env, status, String());
+ return String(env, value);
+}
+
+inline String::String() : Name() {
+}
+
+inline String::String(napi_env env, napi_value value) : Name(env, value) {
+}
+
+inline String::operator std::string() const {
+ return Utf8Value();
+}
+
+inline String::operator std::u16string() const {
+ return Utf16Value();
+}
+
+inline std::string String::Utf8Value() const {
+ size_t length;
+ napi_status status = napi_get_value_string_utf8(_env, _value, nullptr, 0, &length);
+ NAPI_THROW_IF_FAILED(_env, status, "");
+
+ std::string value;
+ value.reserve(length + 1);
+ value.resize(length);
+ status = napi_get_value_string_utf8(_env, _value, &value[0], value.capacity(), nullptr);
+ NAPI_THROW_IF_FAILED(_env, status, "");
+ return value;
+}
+
+inline std::u16string String::Utf16Value() const {
+ size_t length;
+ napi_status status = napi_get_value_string_utf16(_env, _value, nullptr, 0, &length);
+ NAPI_THROW_IF_FAILED(_env, status, NAPI_WIDE_TEXT(""));
+
+ std::u16string value;
+ value.reserve(length + 1);
+ value.resize(length);
+ status = napi_get_value_string_utf16(_env, _value, &value[0], value.capacity(), nullptr);
+ NAPI_THROW_IF_FAILED(_env, status, NAPI_WIDE_TEXT(""));
+ return value;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Symbol class
+////////////////////////////////////////////////////////////////////////////////
+
+inline Symbol Symbol::New(napi_env env, const char* description) {
+ napi_value descriptionValue = description != nullptr ?
+ String::New(env, description) : static_cast<napi_value>(nullptr);
+ return Symbol::New(env, descriptionValue);
+}
+
+inline Symbol Symbol::New(napi_env env, const std::string& description) {
+ napi_value descriptionValue = String::New(env, description);
+ return Symbol::New(env, descriptionValue);
+}
+
+inline Symbol Symbol::New(napi_env env, String description) {
+ napi_value descriptionValue = description;
+ return Symbol::New(env, descriptionValue);
+}
+
+inline Symbol Symbol::New(napi_env env, napi_value description) {
+ napi_value value;
+ napi_status status = napi_create_symbol(env, description, &value);
+ NAPI_THROW_IF_FAILED(env, status, Symbol());
+ return Symbol(env, value);
+}
+
+inline Symbol Symbol::WellKnown(napi_env env, const std::string& name) {
+ return Napi::Env(env).Global().Get("Symbol").As<Object>().Get(name).As<Symbol>();
+}
+
+inline Symbol::Symbol() : Name() {
+}
+
+inline Symbol::Symbol(napi_env env, napi_value value) : Name(env, value) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Automagic value creation
+////////////////////////////////////////////////////////////////////////////////
+
+namespace details {
+template <typename T>
+struct vf_number {
+ static Number From(napi_env env, T value) {
+ return Number::New(env, static_cast<double>(value));
+ }
+};
+
+template<>
+struct vf_number<bool> {
+ static Boolean From(napi_env env, bool value) {
+ return Boolean::New(env, value);
+ }
+};
+
+struct vf_utf8_charp {
+ static String From(napi_env env, const char* value) {
+ return String::New(env, value);
+ }
+};
+
+struct vf_utf16_charp {
+ static String From(napi_env env, const char16_t* value) {
+ return String::New(env, value);
+ }
+};
+struct vf_utf8_string {
+ static String From(napi_env env, const std::string& value) {
+ return String::New(env, value);
+ }
+};
+
+struct vf_utf16_string {
+ static String From(napi_env env, const std::u16string& value) {
+ return String::New(env, value);
+ }
+};
+
+template <typename T>
+struct vf_fallback {
+ static Value From(napi_env env, const T& value) {
+ return Value(env, value);
+ }
+};
+
+template <typename...> struct disjunction : std::false_type {};
+template <typename B> struct disjunction<B> : B {};
+template <typename B, typename... Bs>
+struct disjunction<B, Bs...>
+ : std::conditional<bool(B::value), B, disjunction<Bs...>>::type {};
+
+template <typename T>
+struct can_make_string
+ : disjunction<typename std::is_convertible<T, const char *>::type,
+ typename std::is_convertible<T, const char16_t *>::type,
+ typename std::is_convertible<T, std::string>::type,
+ typename std::is_convertible<T, std::u16string>::type> {};
+}
+
+template <typename T>
+Value Value::From(napi_env env, const T& value) {
+ using Helper = typename std::conditional<
+ std::is_integral<T>::value || std::is_floating_point<T>::value,
+ details::vf_number<T>,
+ typename std::conditional<
+ details::can_make_string<T>::value,
+ String,
+ details::vf_fallback<T>
+ >::type
+ >::type;
+ return Helper::From(env, value);
+}
+
+template <typename T>
+String String::From(napi_env env, const T& value) {
+ struct Dummy {};
+ using Helper = typename std::conditional<
+ std::is_convertible<T, const char*>::value,
+ details::vf_utf8_charp,
+ typename std::conditional<
+ std::is_convertible<T, const char16_t*>::value,
+ details::vf_utf16_charp,
+ typename std::conditional<
+ std::is_convertible<T, std::string>::value,
+ details::vf_utf8_string,
+ typename std::conditional<
+ std::is_convertible<T, std::u16string>::value,
+ details::vf_utf16_string,
+ Dummy
+ >::type
+ >::type
+ >::type
+ >::type;
+ return Helper::From(env, value);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Object class
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename Key>
+inline Object::PropertyLValue<Key>::operator Value() const {
+ return Object(_env, _object).Get(_key);
+}
+
+template <typename Key> template <typename ValueType>
+inline Object::PropertyLValue<Key>& Object::PropertyLValue<Key>::operator =(ValueType value) {
+ Object(_env, _object).Set(_key, value);
+ return *this;
+}
+
+template <typename Key>
+inline Object::PropertyLValue<Key>::PropertyLValue(Object object, Key key)
+ : _env(object.Env()), _object(object), _key(key) {}
+
+inline Object Object::New(napi_env env) {
+ napi_value value;
+ napi_status status = napi_create_object(env, &value);
+ NAPI_THROW_IF_FAILED(env, status, Object());
+ return Object(env, value);
+}
+
+inline Object::Object() : Value() {
+}
+
+inline Object::Object(napi_env env, napi_value value) : Value(env, value) {
+}
+
+inline Object::PropertyLValue<std::string> Object::operator [](const char* utf8name) {
+ return PropertyLValue<std::string>(*this, utf8name);
+}
+
+inline Object::PropertyLValue<std::string> Object::operator [](const std::string& utf8name) {
+ return PropertyLValue<std::string>(*this, utf8name);
+}
+
+inline Object::PropertyLValue<uint32_t> Object::operator [](uint32_t index) {
+ return PropertyLValue<uint32_t>(*this, index);
+}
+
+inline Value Object::operator [](const char* utf8name) const {
+ return Get(utf8name);
+}
+
+inline Value Object::operator [](const std::string& utf8name) const {
+ return Get(utf8name);
+}
+
+inline Value Object::operator [](uint32_t index) const {
+ return Get(index);
+}
+
+inline bool Object::Has(napi_value key) const {
+ bool result;
+ napi_status status = napi_has_property(_env, _value, key, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline bool Object::Has(Value key) const {
+ bool result;
+ napi_status status = napi_has_property(_env, _value, key, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline bool Object::Has(const char* utf8name) const {
+ bool result;
+ napi_status status = napi_has_named_property(_env, _value, utf8name, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline bool Object::Has(const std::string& utf8name) const {
+ return Has(utf8name.c_str());
+}
+
+inline bool Object::HasOwnProperty(napi_value key) const {
+ bool result;
+ napi_status status = napi_has_own_property(_env, _value, key, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline bool Object::HasOwnProperty(Value key) const {
+ bool result;
+ napi_status status = napi_has_own_property(_env, _value, key, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline bool Object::HasOwnProperty(const char* utf8name) const {
+ napi_value key;
+ napi_status status = napi_create_string_utf8(_env, utf8name, std::strlen(utf8name), &key);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return HasOwnProperty(key);
+}
+
+inline bool Object::HasOwnProperty(const std::string& utf8name) const {
+ return HasOwnProperty(utf8name.c_str());
+}
+
+inline Value Object::Get(napi_value key) const {
+ napi_value result;
+ napi_status status = napi_get_property(_env, _value, key, &result);
+ NAPI_THROW_IF_FAILED(_env, status, Value());
+ return Value(_env, result);
+}
+
+inline Value Object::Get(Value key) const {
+ napi_value result;
+ napi_status status = napi_get_property(_env, _value, key, &result);
+ NAPI_THROW_IF_FAILED(_env, status, Value());
+ return Value(_env, result);
+}
+
+inline Value Object::Get(const char* utf8name) const {
+ napi_value result;
+ napi_status status = napi_get_named_property(_env, _value, utf8name, &result);
+ NAPI_THROW_IF_FAILED(_env, status, Value());
+ return Value(_env, result);
+}
+
+inline Value Object::Get(const std::string& utf8name) const {
+ return Get(utf8name.c_str());
+}
+
+template <typename ValueType>
+inline void Object::Set(napi_value key, const ValueType& value) {
+ napi_status status =
+ napi_set_property(_env, _value, key, Value::From(_env, value));
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+template <typename ValueType>
+inline void Object::Set(Value key, const ValueType& value) {
+ napi_status status =
+ napi_set_property(_env, _value, key, Value::From(_env, value));
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+template <typename ValueType>
+inline void Object::Set(const char* utf8name, const ValueType& value) {
+ napi_status status =
+ napi_set_named_property(_env, _value, utf8name, Value::From(_env, value));
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+template <typename ValueType>
+inline void Object::Set(const std::string& utf8name, const ValueType& value) {
+ Set(utf8name.c_str(), value);
+}
+
+inline bool Object::Delete(napi_value key) {
+ bool result;
+ napi_status status = napi_delete_property(_env, _value, key, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline bool Object::Delete(Value key) {
+ bool result;
+ napi_status status = napi_delete_property(_env, _value, key, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline bool Object::Delete(const char* utf8name) {
+ return Delete(String::New(_env, utf8name));
+}
+
+inline bool Object::Delete(const std::string& utf8name) {
+ return Delete(String::New(_env, utf8name));
+}
+
+inline bool Object::Has(uint32_t index) const {
+ bool result;
+ napi_status status = napi_has_element(_env, _value, index, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline Value Object::Get(uint32_t index) const {
+ napi_value value;
+ napi_status status = napi_get_element(_env, _value, index, &value);
+ NAPI_THROW_IF_FAILED(_env, status, Value());
+ return Value(_env, value);
+}
+
+template <typename ValueType>
+inline void Object::Set(uint32_t index, const ValueType& value) {
+ napi_status status =
+ napi_set_element(_env, _value, index, Value::From(_env, value));
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline bool Object::Delete(uint32_t index) {
+ bool result;
+ napi_status status = napi_delete_element(_env, _value, index, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+inline Array Object::GetPropertyNames() const {
+ napi_value result;
+ napi_status status = napi_get_property_names(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, Array());
+ return Array(_env, result);
+}
+
+inline void Object::DefineProperty(const PropertyDescriptor& property) {
+ napi_status status = napi_define_properties(_env, _value, 1,
+ reinterpret_cast<const napi_property_descriptor*>(&property));
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline void Object::DefineProperties(const std::initializer_list<PropertyDescriptor>& properties) {
+ napi_status status = napi_define_properties(_env, _value, properties.size(),
+ reinterpret_cast<const napi_property_descriptor*>(properties.begin()));
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline void Object::DefineProperties(const std::vector<PropertyDescriptor>& properties) {
+ napi_status status = napi_define_properties(_env, _value, properties.size(),
+ reinterpret_cast<const napi_property_descriptor*>(properties.data()));
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline bool Object::InstanceOf(const Function& constructor) const {
+ bool result;
+ napi_status status = napi_instanceof(_env, _value, constructor, &result);
+ NAPI_THROW_IF_FAILED(_env, status, false);
+ return result;
+}
+
+template <typename Finalizer, typename T>
+inline void Object::AddFinalizer(Finalizer finalizeCallback, T* data) {
+ details::FinalizeData<T, Finalizer>* finalizeData =
+ new details::FinalizeData<T, Finalizer>({ finalizeCallback, nullptr });
+ napi_status status =
+ details::AttachData(_env,
+ *this,
+ data,
+ details::FinalizeData<T, Finalizer>::Wrapper,
+ finalizeData);
+ if (status != napi_ok) {
+ delete finalizeData;
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+ }
+}
+
+template <typename Finalizer, typename T, typename Hint>
+inline void Object::AddFinalizer(Finalizer finalizeCallback,
+ T* data,
+ Hint* finalizeHint) {
+ details::FinalizeData<T, Finalizer, Hint>* finalizeData =
+ new details::FinalizeData<T, Finalizer, Hint>({ finalizeCallback, finalizeHint });
+ napi_status status =
+ details::AttachData(_env,
+ *this,
+ data,
+ details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
+ finalizeData);
+ if (status != napi_ok) {
+ delete finalizeData;
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// External class
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+inline External<T> External<T>::New(napi_env env, T* data) {
+ napi_value value;
+ napi_status status = napi_create_external(env, data, nullptr, nullptr, &value);
+ NAPI_THROW_IF_FAILED(env, status, External());
+ return External(env, value);
+}
+
+template <typename T>
+template <typename Finalizer>
+inline External<T> External<T>::New(napi_env env,
+ T* data,
+ Finalizer finalizeCallback) {
+ napi_value value;
+ details::FinalizeData<T, Finalizer>* finalizeData =
+ new details::FinalizeData<T, Finalizer>({ finalizeCallback, nullptr });
+ napi_status status = napi_create_external(
+ env,
+ data,
+ details::FinalizeData<T, Finalizer>::Wrapper,
+ finalizeData,
+ &value);
+ if (status != napi_ok) {
+ delete finalizeData;
+ NAPI_THROW_IF_FAILED(env, status, External());
+ }
+ return External(env, value);
+}
+
+template <typename T>
+template <typename Finalizer, typename Hint>
+inline External<T> External<T>::New(napi_env env,
+ T* data,
+ Finalizer finalizeCallback,
+ Hint* finalizeHint) {
+ napi_value value;
+ details::FinalizeData<T, Finalizer, Hint>* finalizeData =
+ new details::FinalizeData<T, Finalizer, Hint>({ finalizeCallback, finalizeHint });
+ napi_status status = napi_create_external(
+ env,
+ data,
+ details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
+ finalizeData,
+ &value);
+ if (status != napi_ok) {
+ delete finalizeData;
+ NAPI_THROW_IF_FAILED(env, status, External());
+ }
+ return External(env, value);
+}
+
+template <typename T>
+inline External<T>::External() : Value() {
+}
+
+template <typename T>
+inline External<T>::External(napi_env env, napi_value value) : Value(env, value) {
+}
+
+template <typename T>
+inline T* External<T>::Data() const {
+ void* data;
+ napi_status status = napi_get_value_external(_env, _value, &data);
+ NAPI_THROW_IF_FAILED(_env, status, nullptr);
+ return reinterpret_cast<T*>(data);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Array class
+////////////////////////////////////////////////////////////////////////////////
+
+inline Array Array::New(napi_env env) {
+ napi_value value;
+ napi_status status = napi_create_array(env, &value);
+ NAPI_THROW_IF_FAILED(env, status, Array());
+ return Array(env, value);
+}
+
+inline Array Array::New(napi_env env, size_t length) {
+ napi_value value;
+ napi_status status = napi_create_array_with_length(env, length, &value);
+ NAPI_THROW_IF_FAILED(env, status, Array());
+ return Array(env, value);
+}
+
+inline Array::Array() : Object() {
+}
+
+inline Array::Array(napi_env env, napi_value value) : Object(env, value) {
+}
+
+inline uint32_t Array::Length() const {
+ uint32_t result;
+ napi_status status = napi_get_array_length(_env, _value, &result);
+ NAPI_THROW_IF_FAILED(_env, status, 0);
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ArrayBuffer class
+////////////////////////////////////////////////////////////////////////////////
+
+inline ArrayBuffer ArrayBuffer::New(napi_env env, size_t byteLength) {
+ napi_value value;
+ void* data;
+ napi_status status = napi_create_arraybuffer(env, byteLength, &data, &value);
+ NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
+
+ return ArrayBuffer(env, value, data, byteLength);
+}
+
+inline ArrayBuffer ArrayBuffer::New(napi_env env,
+ void* externalData,
+ size_t byteLength) {
+ napi_value value;
+ napi_status status = napi_create_external_arraybuffer(
+ env, externalData, byteLength, nullptr, nullptr, &value);
+ NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
+
+ return ArrayBuffer(env, value, externalData, byteLength);
+}
+
+template <typename Finalizer>
+inline ArrayBuffer ArrayBuffer::New(napi_env env,
+ void* externalData,
+ size_t byteLength,
+ Finalizer finalizeCallback) {
+ napi_value value;
+ details::FinalizeData<void, Finalizer>* finalizeData =
+ new details::FinalizeData<void, Finalizer>({ finalizeCallback, nullptr });
+ napi_status status = napi_create_external_arraybuffer(
+ env,
+ externalData,
+ byteLength,
+ details::FinalizeData<void, Finalizer>::Wrapper,
+ finalizeData,
+ &value);
+ if (status != napi_ok) {
+ delete finalizeData;
+ NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
+ }
+
+ return ArrayBuffer(env, value, externalData, byteLength);
+}
+
+template <typename Finalizer, typename Hint>
+inline ArrayBuffer ArrayBuffer::New(napi_env env,
+ void* externalData,
+ size_t byteLength,
+ Finalizer finalizeCallback,
+ Hint* finalizeHint) {
+ napi_value value;
+ details::FinalizeData<void, Finalizer, Hint>* finalizeData =
+ new details::FinalizeData<void, Finalizer, Hint>({ finalizeCallback, finalizeHint });
+ napi_status status = napi_create_external_arraybuffer(
+ env,
+ externalData,
+ byteLength,
+ details::FinalizeData<void, Finalizer, Hint>::WrapperWithHint,
+ finalizeData,
+ &value);
+ if (status != napi_ok) {
+ delete finalizeData;
+ NAPI_THROW_IF_FAILED(env, status, ArrayBuffer());
+ }
+
+ return ArrayBuffer(env, value, externalData, byteLength);
+}
+
+inline ArrayBuffer::ArrayBuffer() : Object(), _data(nullptr), _length(0) {
+}
+
+inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value)
+ : Object(env, value), _data(nullptr), _length(0) {
+}
+
+inline ArrayBuffer::ArrayBuffer(napi_env env, napi_value value, void* data, size_t length)
+ : Object(env, value), _data(data), _length(length) {
+}
+
+inline void* ArrayBuffer::Data() {
+ EnsureInfo();
+ return _data;
+}
+
+inline size_t ArrayBuffer::ByteLength() {
+ EnsureInfo();
+ return _length;
+}
+
+inline void ArrayBuffer::EnsureInfo() const {
+ // The ArrayBuffer instance may have been constructed from a napi_value whose
+ // length/data are not yet known. Fetch and cache these values just once,
+ // since they can never change during the lifetime of the ArrayBuffer.
+ if (_data == nullptr) {
+ napi_status status = napi_get_arraybuffer_info(_env, _value, &_data, &_length);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// DataView class
+////////////////////////////////////////////////////////////////////////////////
+inline DataView DataView::New(napi_env env,
+ Napi::ArrayBuffer arrayBuffer) {
+ return New(env, arrayBuffer, 0, arrayBuffer.ByteLength());
+}
+
+inline DataView DataView::New(napi_env env,
+ Napi::ArrayBuffer arrayBuffer,
+ size_t byteOffset) {
+ if (byteOffset > arrayBuffer.ByteLength()) {
+ NAPI_THROW(RangeError::New(env,
+ "Start offset is outside the bounds of the buffer"),
+ DataView());
+ }
+ return New(env, arrayBuffer, byteOffset,
+ arrayBuffer.ByteLength() - byteOffset);
+}
+
+inline DataView DataView::New(napi_env env,
+ Napi::ArrayBuffer arrayBuffer,
+ size_t byteOffset,
+ size_t byteLength) {
+ if (byteOffset + byteLength > arrayBuffer.ByteLength()) {
+ NAPI_THROW(RangeError::New(env, "Invalid DataView length"),
+ DataView());
+ }
+ napi_value value;
+ napi_status status = napi_create_dataview(
+ env, byteLength, arrayBuffer, byteOffset, &value);
+ NAPI_THROW_IF_FAILED(env, status, DataView());
+ return DataView(env, value);
+}
+
+inline DataView::DataView() : Object() {
+}
+
+inline DataView::DataView(napi_env env, napi_value value) : Object(env, value) {
+ napi_status status = napi_get_dataview_info(
+ _env,
+ _value /* dataView */,
+ &_length /* byteLength */,
+ &_data /* data */,
+ nullptr /* arrayBuffer */,
+ nullptr /* byteOffset */);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline Napi::ArrayBuffer DataView::ArrayBuffer() const {
+ napi_value arrayBuffer;
+ napi_status status = napi_get_dataview_info(
+ _env,
+ _value /* dataView */,
+ nullptr /* byteLength */,
+ nullptr /* data */,
+ &arrayBuffer /* arrayBuffer */,
+ nullptr /* byteOffset */);
+ NAPI_THROW_IF_FAILED(_env, status, Napi::ArrayBuffer());
+ return Napi::ArrayBuffer(_env, arrayBuffer);
+}
+
+inline size_t DataView::ByteOffset() const {
+ size_t byteOffset;
+ napi_status status = napi_get_dataview_info(
+ _env,
+ _value /* dataView */,
+ nullptr /* byteLength */,
+ nullptr /* data */,
+ nullptr /* arrayBuffer */,
+ &byteOffset /* byteOffset */);
+ NAPI_THROW_IF_FAILED(_env, status, 0);
+ return byteOffset;
+}
+
+inline size_t DataView::ByteLength() const {
+ return _length;
+}
+
+inline void* DataView::Data() const {
+ return _data;
+}
+
+inline float DataView::GetFloat32(size_t byteOffset) const {
+ return ReadData<float>(byteOffset);
+}
+
+inline double DataView::GetFloat64(size_t byteOffset) const {
+ return ReadData<double>(byteOffset);
+}
+
+inline int8_t DataView::GetInt8(size_t byteOffset) const {
+ return ReadData<int8_t>(byteOffset);
+}
+
+inline int16_t DataView::GetInt16(size_t byteOffset) const {
+ return ReadData<int16_t>(byteOffset);
+}
+
+inline int32_t DataView::GetInt32(size_t byteOffset) const {
+ return ReadData<int32_t>(byteOffset);
+}
+
+inline uint8_t DataView::GetUint8(size_t byteOffset) const {
+ return ReadData<uint8_t>(byteOffset);
+}
+
+inline uint16_t DataView::GetUint16(size_t byteOffset) const {
+ return ReadData<uint16_t>(byteOffset);
+}
+
+inline uint32_t DataView::GetUint32(size_t byteOffset) const {
+ return ReadData<uint32_t>(byteOffset);
+}
+
+inline void DataView::SetFloat32(size_t byteOffset, float value) const {
+ WriteData<float>(byteOffset, value);
+}
+
+inline void DataView::SetFloat64(size_t byteOffset, double value) const {
+ WriteData<double>(byteOffset, value);
+}
+
+inline void DataView::SetInt8(size_t byteOffset, int8_t value) const {
+ WriteData<int8_t>(byteOffset, value);
+}
+
+inline void DataView::SetInt16(size_t byteOffset, int16_t value) const {
+ WriteData<int16_t>(byteOffset, value);
+}
+
+inline void DataView::SetInt32(size_t byteOffset, int32_t value) const {
+ WriteData<int32_t>(byteOffset, value);
+}
+
+inline void DataView::SetUint8(size_t byteOffset, uint8_t value) const {
+ WriteData<uint8_t>(byteOffset, value);
+}
+
+inline void DataView::SetUint16(size_t byteOffset, uint16_t value) const {
+ WriteData<uint16_t>(byteOffset, value);
+}
+
+inline void DataView::SetUint32(size_t byteOffset, uint32_t value) const {
+ WriteData<uint32_t>(byteOffset, value);
+}
+
+template <typename T>
+inline T DataView::ReadData(size_t byteOffset) const {
+ if (byteOffset + sizeof(T) > _length ||
+ byteOffset + sizeof(T) < byteOffset) { // overflow
+ NAPI_THROW(RangeError::New(_env,
+ "Offset is outside the bounds of the DataView"), 0);
+ }
+
+ return *reinterpret_cast<T*>(static_cast<uint8_t*>(_data) + byteOffset);
+}
+
+template <typename T>
+inline void DataView::WriteData(size_t byteOffset, T value) const {
+ if (byteOffset + sizeof(T) > _length ||
+ byteOffset + sizeof(T) < byteOffset) { // overflow
+ NAPI_THROW_VOID(RangeError::New(_env,
+ "Offset is outside the bounds of the DataView"));
+ }
+
+ *reinterpret_cast<T*>(static_cast<uint8_t*>(_data) + byteOffset) = value;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TypedArray class
+////////////////////////////////////////////////////////////////////////////////
+
+inline TypedArray::TypedArray()
+ : Object(), _type(TypedArray::unknown_array_type), _length(0) {
+}
+
+inline TypedArray::TypedArray(napi_env env, napi_value value)
+ : Object(env, value), _type(TypedArray::unknown_array_type), _length(0) {
+}
+
+inline TypedArray::TypedArray(napi_env env,
+ napi_value value,
+ napi_typedarray_type type,
+ size_t length)
+ : Object(env, value), _type(type), _length(length) {
+}
+
+inline napi_typedarray_type TypedArray::TypedArrayType() const {
+ if (_type == TypedArray::unknown_array_type) {
+ napi_status status = napi_get_typedarray_info(_env, _value,
+ &const_cast<TypedArray*>(this)->_type, &const_cast<TypedArray*>(this)->_length,
+ nullptr, nullptr, nullptr);
+ NAPI_THROW_IF_FAILED(_env, status, napi_int8_array);
+ }
+
+ return _type;
+}
+
+inline uint8_t TypedArray::ElementSize() const {
+ switch (TypedArrayType()) {
+ case napi_int8_array:
+ case napi_uint8_array:
+ case napi_uint8_clamped_array:
+ return 1;
+ case napi_int16_array:
+ case napi_uint16_array:
+ return 2;
+ case napi_int32_array:
+ case napi_uint32_array:
+ case napi_float32_array:
+ return 4;
+ case napi_float64_array:
+ return 8;
+ default:
+ return 0;
+ }
+}
+
+inline size_t TypedArray::ElementLength() const {
+ if (_type == TypedArray::unknown_array_type) {
+ napi_status status = napi_get_typedarray_info(_env, _value,
+ &const_cast<TypedArray*>(this)->_type, &const_cast<TypedArray*>(this)->_length,
+ nullptr, nullptr, nullptr);
+ NAPI_THROW_IF_FAILED(_env, status, 0);
+ }
+
+ return _length;
+}
+
+inline size_t TypedArray::ByteOffset() const {
+ size_t byteOffset;
+ napi_status status = napi_get_typedarray_info(
+ _env, _value, nullptr, nullptr, nullptr, nullptr, &byteOffset);
+ NAPI_THROW_IF_FAILED(_env, status, 0);
+ return byteOffset;
+}
+
+inline size_t TypedArray::ByteLength() const {
+ return ElementSize() * ElementLength();
+}
+
+inline Napi::ArrayBuffer TypedArray::ArrayBuffer() const {
+ napi_value arrayBuffer;
+ napi_status status = napi_get_typedarray_info(
+ _env, _value, nullptr, nullptr, nullptr, &arrayBuffer, nullptr);
+ NAPI_THROW_IF_FAILED(_env, status, Napi::ArrayBuffer());
+ return Napi::ArrayBuffer(_env, arrayBuffer);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TypedArrayOf<T> class
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+inline TypedArrayOf<T> TypedArrayOf<T>::New(napi_env env,
+ size_t elementLength,
+ napi_typedarray_type type) {
+ Napi::ArrayBuffer arrayBuffer = Napi::ArrayBuffer::New(env, elementLength * sizeof (T));
+ return New(env, elementLength, arrayBuffer, 0, type);
+}
+
+template <typename T>
+inline TypedArrayOf<T> TypedArrayOf<T>::New(napi_env env,
+ size_t elementLength,
+ Napi::ArrayBuffer arrayBuffer,
+ size_t bufferOffset,
+ napi_typedarray_type type) {
+ napi_value value;
+ napi_status status = napi_create_typedarray(
+ env, type, elementLength, arrayBuffer, bufferOffset, &value);
+ NAPI_THROW_IF_FAILED(env, status, TypedArrayOf<T>());
+
+ return TypedArrayOf<T>(
+ env, value, type, elementLength,
+ reinterpret_cast<T*>(reinterpret_cast<uint8_t*>(arrayBuffer.Data()) + bufferOffset));
+}
+
+template <typename T>
+inline TypedArrayOf<T>::TypedArrayOf() : TypedArray(), _data(nullptr) {
+}
+
+template <typename T>
+inline TypedArrayOf<T>::TypedArrayOf(napi_env env, napi_value value)
+ : TypedArray(env, value), _data(nullptr) {
+ napi_status status = napi_get_typedarray_info(
+ _env, _value, &_type, &_length, reinterpret_cast<void**>(&_data), nullptr, nullptr);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+template <typename T>
+inline TypedArrayOf<T>::TypedArrayOf(napi_env env,
+ napi_value value,
+ napi_typedarray_type type,
+ size_t length,
+ T* data)
+ : TypedArray(env, value, type, length), _data(data) {
+ if (!(type == TypedArrayTypeForPrimitiveType<T>() ||
+ (type == napi_uint8_clamped_array && std::is_same<T, uint8_t>::value))) {
+ NAPI_THROW_VOID(TypeError::New(env, "Array type must match the template parameter. "
+ "(Uint8 arrays may optionally have the \"clamped\" array type.)"));
+ }
+}
+
+template <typename T>
+inline T& TypedArrayOf<T>::operator [](size_t index) {
+ return _data[index];
+}
+
+template <typename T>
+inline const T& TypedArrayOf<T>::operator [](size_t index) const {
+ return _data[index];
+}
+
+template <typename T>
+inline T* TypedArrayOf<T>::Data() {
+ return _data;
+}
+
+template <typename T>
+inline const T* TypedArrayOf<T>::Data() const {
+ return _data;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Function class
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename CbData>
+static inline napi_status
+CreateFunction(napi_env env,
+ const char* utf8name,
+ napi_callback cb,
+ CbData* data,
+ napi_value* result) {
+ napi_status status =
+ napi_create_function(env, utf8name, NAPI_AUTO_LENGTH, cb, data, result);
+ if (status == napi_ok) {
+ status = Napi::details::AttachData(env, *result, data);
+ }
+
+ return status;
+}
+
+template <typename Callable>
+inline Function Function::New(napi_env env,
+ Callable cb,
+ const char* utf8name,
+ void* data) {
+ typedef decltype(cb(CallbackInfo(nullptr, nullptr))) ReturnType;
+ typedef details::CallbackData<Callable, ReturnType> CbData;
+ auto callbackData = new CbData({ cb, data });
+
+ napi_value value;
+ napi_status status = CreateFunction(env,
+ utf8name,
+ CbData::Wrapper,
+ callbackData,
+ &value);
+ if (status != napi_ok) {
+ delete callbackData;
+ NAPI_THROW_IF_FAILED(env, status, Function());
+ }
+
+ return Function(env, value);
+}
+
+template <typename Callable>
+inline Function Function::New(napi_env env,
+ Callable cb,
+ const std::string& utf8name,
+ void* data) {
+ return New(env, cb, utf8name.c_str(), data);
+}
+
+inline Function::Function() : Object() {
+}
+
+inline Function::Function(napi_env env, napi_value value) : Object(env, value) {
+}
+
+inline Value Function::operator ()(const std::initializer_list<napi_value>& args) const {
+ return Call(Env().Undefined(), args);
+}
+
+inline Value Function::Call(const std::initializer_list<napi_value>& args) const {
+ return Call(Env().Undefined(), args);
+}
+
+inline Value Function::Call(const std::vector<napi_value>& args) const {
+ return Call(Env().Undefined(), args);
+}
+
+inline Value Function::Call(size_t argc, const napi_value* args) const {
+ return Call(Env().Undefined(), argc, args);
+}
+
+inline Value Function::Call(napi_value recv, const std::initializer_list<napi_value>& args) const {
+ return Call(recv, args.size(), args.begin());
+}
+
+inline Value Function::Call(napi_value recv, const std::vector<napi_value>& args) const {
+ return Call(recv, args.size(), args.data());
+}
+
+inline Value Function::Call(napi_value recv, size_t argc, const napi_value* args) const {
+ napi_value result;
+ napi_status status = napi_call_function(
+ _env, recv, _value, argc, args, &result);
+ NAPI_THROW_IF_FAILED(_env, status, Value());
+ return Value(_env, result);
+}
+
+inline Value Function::MakeCallback(
+ napi_value recv,
+ const std::initializer_list<napi_value>& args,
+ napi_async_context context) const {
+ return MakeCallback(recv, args.size(), args.begin(), context);
+}
+
+inline Value Function::MakeCallback(
+ napi_value recv,
+ const std::vector<napi_value>& args,
+ napi_async_context context) const {
+ return MakeCallback(recv, args.size(), args.data(), context);
+}
+
+inline Value Function::MakeCallback(
+ napi_value recv,
+ size_t argc,
+ const napi_value* args,
+ napi_async_context context) const {
+ napi_value result;
+ napi_status status = napi_make_callback(
+ _env, context, recv, _value, argc, args, &result);
+ NAPI_THROW_IF_FAILED(_env, status, Value());
+ return Value(_env, result);
+}
+
+inline Object Function::New(const std::initializer_list<napi_value>& args) const {
+ return New(args.size(), args.begin());
+}
+
+inline Object Function::New(const std::vector<napi_value>& args) const {
+ return New(args.size(), args.data());
+}
+
+inline Object Function::New(size_t argc, const napi_value* args) const {
+ napi_value result;
+ napi_status status = napi_new_instance(
+ _env, _value, argc, args, &result);
+ NAPI_THROW_IF_FAILED(_env, status, Object());
+ return Object(_env, result);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Promise class
+////////////////////////////////////////////////////////////////////////////////
+
+inline Promise::Deferred Promise::Deferred::New(napi_env env) {
+ return Promise::Deferred(env);
+}
+
+inline Promise::Deferred::Deferred(napi_env env) : _env(env) {
+ napi_status status = napi_create_promise(_env, &_deferred, &_promise);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline Promise Promise::Deferred::Promise() const {
+ return Napi::Promise(_env, _promise);
+}
+
+inline Napi::Env Promise::Deferred::Env() const {
+ return Napi::Env(_env);
+}
+
+inline void Promise::Deferred::Resolve(napi_value value) const {
+ napi_status status = napi_resolve_deferred(_env, _deferred, value);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline void Promise::Deferred::Reject(napi_value value) const {
+ napi_status status = napi_reject_deferred(_env, _deferred, value);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline Promise::Promise(napi_env env, napi_value value) : Object(env, value) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Buffer<T> class
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+inline Buffer<T> Buffer<T>::New(napi_env env, size_t length) {
+ napi_value value;
+ void* data;
+ napi_status status = napi_create_buffer(env, length * sizeof (T), &data, &value);
+ NAPI_THROW_IF_FAILED(env, status, Buffer<T>());
+ return Buffer(env, value, length, static_cast<T*>(data));
+}
+
+template <typename T>
+inline Buffer<T> Buffer<T>::New(napi_env env, T* data, size_t length) {
+ napi_value value;
+ napi_status status = napi_create_external_buffer(
+ env, length * sizeof (T), data, nullptr, nullptr, &value);
+ NAPI_THROW_IF_FAILED(env, status, Buffer<T>());
+ return Buffer(env, value, length, data);
+}
+
+template <typename T>
+template <typename Finalizer>
+inline Buffer<T> Buffer<T>::New(napi_env env,
+ T* data,
+ size_t length,
+ Finalizer finalizeCallback) {
+ napi_value value;
+ details::FinalizeData<T, Finalizer>* finalizeData =
+ new details::FinalizeData<T, Finalizer>({ finalizeCallback, nullptr });
+ napi_status status = napi_create_external_buffer(
+ env,
+ length * sizeof (T),
+ data,
+ details::FinalizeData<T, Finalizer>::Wrapper,
+ finalizeData,
+ &value);
+ if (status != napi_ok) {
+ delete finalizeData;
+ NAPI_THROW_IF_FAILED(env, status, Buffer());
+ }
+ return Buffer(env, value, length, data);
+}
+
+template <typename T>
+template <typename Finalizer, typename Hint>
+inline Buffer<T> Buffer<T>::New(napi_env env,
+ T* data,
+ size_t length,
+ Finalizer finalizeCallback,
+ Hint* finalizeHint) {
+ napi_value value;
+ details::FinalizeData<T, Finalizer, Hint>* finalizeData =
+ new details::FinalizeData<T, Finalizer, Hint>({ finalizeCallback, finalizeHint });
+ napi_status status = napi_create_external_buffer(
+ env,
+ length * sizeof (T),
+ data,
+ details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
+ finalizeData,
+ &value);
+ if (status != napi_ok) {
+ delete finalizeData;
+ NAPI_THROW_IF_FAILED(env, status, Buffer());
+ }
+ return Buffer(env, value, length, data);
+}
+
+template <typename T>
+inline Buffer<T> Buffer<T>::Copy(napi_env env, const T* data, size_t length) {
+ napi_value value;
+ napi_status status = napi_create_buffer_copy(
+ env, length * sizeof (T), data, nullptr, &value);
+ NAPI_THROW_IF_FAILED(env, status, Buffer<T>());
+ return Buffer<T>(env, value);
+}
+
+template <typename T>
+inline Buffer<T>::Buffer() : Uint8Array(), _length(0), _data(nullptr) {
+}
+
+template <typename T>
+inline Buffer<T>::Buffer(napi_env env, napi_value value)
+ : Uint8Array(env, value), _length(0), _data(nullptr) {
+}
+
+template <typename T>
+inline Buffer<T>::Buffer(napi_env env, napi_value value, size_t length, T* data)
+ : Uint8Array(env, value), _length(length), _data(data) {
+}
+
+template <typename T>
+inline size_t Buffer<T>::Length() const {
+ EnsureInfo();
+ return _length;
+}
+
+template <typename T>
+inline T* Buffer<T>::Data() const {
+ EnsureInfo();
+ return _data;
+}
+
+template <typename T>
+inline void Buffer<T>::EnsureInfo() const {
+ // The Buffer instance may have been constructed from a napi_value whose
+ // length/data are not yet known. Fetch and cache these values just once,
+ // since they can never change during the lifetime of the Buffer.
+ if (_data == nullptr) {
+ size_t byteLength;
+ void* voidData;
+ napi_status status = napi_get_buffer_info(_env, _value, &voidData, &byteLength);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+ _length = byteLength / sizeof (T);
+ _data = static_cast<T*>(voidData);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Error class
+////////////////////////////////////////////////////////////////////////////////
+
+inline Error Error::New(napi_env env) {
+ napi_status status;
+ napi_value error = nullptr;
+
+ const napi_extended_error_info* info;
+ status = napi_get_last_error_info(env, &info);
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_last_error_info");
+
+ if (info->error_code == napi_pending_exception) {
+ status = napi_get_and_clear_last_exception(env, &error);
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
+ }
+ else {
+ const char* error_message = info->error_message != nullptr ?
+ info->error_message : "Error in native callback";
+
+ bool isExceptionPending;
+ status = napi_is_exception_pending(env, &isExceptionPending);
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending");
+
+ if (isExceptionPending) {
+ status = napi_get_and_clear_last_exception(env, &error);
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
+ }
+
+ napi_value message;
+ status = napi_create_string_utf8(
+ env,
+ error_message,
+ std::strlen(error_message),
+ &message);
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_string_utf8");
+
+ switch (info->error_code) {
+ case napi_object_expected:
+ case napi_string_expected:
+ case napi_boolean_expected:
+ case napi_number_expected:
+ status = napi_create_type_error(env, nullptr, message, &error);
+ break;
+ default:
+ status = napi_create_error(env, nullptr, message, &error);
+ break;
+ }
+ NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_error");
+ }
+
+ return Error(env, error);
+}
+
+inline Error Error::New(napi_env env, const char* message) {
+ return Error::New<Error>(env, message, std::strlen(message), napi_create_error);
+}
+
+inline Error Error::New(napi_env env, const std::string& message) {
+ return Error::New<Error>(env, message.c_str(), message.size(), napi_create_error);
+}
+
+inline NAPI_NO_RETURN void Error::Fatal(const char* location, const char* message) {
+ napi_fatal_error(location, NAPI_AUTO_LENGTH, message, NAPI_AUTO_LENGTH);
+}
+
+inline Error::Error() : ObjectReference() {
+}
+
+inline Error::Error(napi_env env, napi_value value) : ObjectReference(env, nullptr) {
+ if (value != nullptr) {
+ napi_status status = napi_create_reference(env, value, 1, &_ref);
+
+ // Avoid infinite recursion in the failure case.
+ // Don't try to construct & throw another Error instance.
+ NAPI_FATAL_IF_FAILED(status, "Error::Error", "napi_create_reference");
+ }
+}
+
+inline Error::Error(Error&& other) : ObjectReference(std::move(other)) {
+}
+
+inline Error& Error::operator =(Error&& other) {
+ static_cast<Reference<Object>*>(this)->operator=(std::move(other));
+ return *this;
+}
+
+inline Error::Error(const Error& other) : ObjectReference(other) {
+}
+
+inline Error& Error::operator =(Error& other) {
+ Reset();
+
+ _env = other.Env();
+ HandleScope scope(_env);
+
+ napi_value value = other.Value();
+ if (value != nullptr) {
+ napi_status status = napi_create_reference(_env, value, 1, &_ref);
+ NAPI_THROW_IF_FAILED(_env, status, *this);
+ }
+
+ return *this;
+}
+
+inline const std::string& Error::Message() const NAPI_NOEXCEPT {
+ if (_message.size() == 0 && _env != nullptr) {
+#ifdef NAPI_CPP_EXCEPTIONS
+ try {
+ _message = Get("message").As<String>();
+ }
+ catch (...) {
+ // Catch all errors here, to include e.g. a std::bad_alloc from
+ // the std::string::operator=, because this method may not throw.
+ }
+#else // NAPI_CPP_EXCEPTIONS
+ _message = Get("message").As<String>();
+#endif // NAPI_CPP_EXCEPTIONS
+ }
+ return _message;
+}
+
+inline void Error::ThrowAsJavaScriptException() const {
+ HandleScope scope(_env);
+ if (!IsEmpty()) {
+
+ // We intentionally don't use `NAPI_THROW_*` macros here to ensure
+ // that there is no possible recursion as `ThrowAsJavaScriptException`
+ // is part of `NAPI_THROW_*` macro definition for noexcept.
+
+ napi_status status = napi_throw(_env, Value());
+
+#ifdef NAPI_CPP_EXCEPTIONS
+ if (status != napi_ok) {
+ throw Error::New(_env);
+ }
+#else // NAPI_CPP_EXCEPTIONS
+ NAPI_FATAL_IF_FAILED(status, "Error::ThrowAsJavaScriptException", "napi_throw");
+#endif // NAPI_CPP_EXCEPTIONS
+ }
+}
+
+#ifdef NAPI_CPP_EXCEPTIONS
+
+inline const char* Error::what() const NAPI_NOEXCEPT {
+ return Message().c_str();
+}
+
+#endif // NAPI_CPP_EXCEPTIONS
+
+template <typename TError>
+inline TError Error::New(napi_env env,
+ const char* message,
+ size_t length,
+ create_error_fn create_error) {
+ napi_value str;
+ napi_status status = napi_create_string_utf8(env, message, length, &str);
+ NAPI_THROW_IF_FAILED(env, status, TError());
+
+ napi_value error;
+ status = create_error(env, nullptr, str, &error);
+ NAPI_THROW_IF_FAILED(env, status, TError());
+
+ return TError(env, error);
+}
+
+inline TypeError TypeError::New(napi_env env, const char* message) {
+ return Error::New<TypeError>(env, message, std::strlen(message), napi_create_type_error);
+}
+
+inline TypeError TypeError::New(napi_env env, const std::string& message) {
+ return Error::New<TypeError>(env, message.c_str(), message.size(), napi_create_type_error);
+}
+
+inline TypeError::TypeError() : Error() {
+}
+
+inline TypeError::TypeError(napi_env env, napi_value value) : Error(env, value) {
+}
+
+inline RangeError RangeError::New(napi_env env, const char* message) {
+ return Error::New<RangeError>(env, message, std::strlen(message), napi_create_range_error);
+}
+
+inline RangeError RangeError::New(napi_env env, const std::string& message) {
+ return Error::New<RangeError>(env, message.c_str(), message.size(), napi_create_range_error);
+}
+
+inline RangeError::RangeError() : Error() {
+}
+
+inline RangeError::RangeError(napi_env env, napi_value value) : Error(env, value) {
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Reference<T> class
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+inline Reference<T> Reference<T>::New(const T& value, uint32_t initialRefcount) {
+ napi_env env = value.Env();
+ napi_value val = value;
+
+ if (val == nullptr) {
+ return Reference<T>(env, nullptr);
+ }
+
+ napi_ref ref;
+ napi_status status = napi_create_reference(env, value, initialRefcount, &ref);
+ NAPI_THROW_IF_FAILED(env, status, Reference<T>());
+
+ return Reference<T>(env, ref);
+}
+
+
+template <typename T>
+inline Reference<T>::Reference() : _env(nullptr), _ref(nullptr), _suppressDestruct(false) {
+}
+
+template <typename T>
+inline Reference<T>::Reference(napi_env env, napi_ref ref)
+ : _env(env), _ref(ref), _suppressDestruct(false) {
+}
+
+template <typename T>
+inline Reference<T>::~Reference() {
+ if (_ref != nullptr) {
+ if (!_suppressDestruct) {
+ napi_delete_reference(_env, _ref);
+ }
+
+ _ref = nullptr;
+ }
+}
+
+template <typename T>
+inline Reference<T>::Reference(Reference<T>&& other)
+ : _env(other._env), _ref(other._ref), _suppressDestruct(other._suppressDestruct) {
+ other._env = nullptr;
+ other._ref = nullptr;
+ other._suppressDestruct = false;
+}
+
+template <typename T>
+inline Reference<T>& Reference<T>::operator =(Reference<T>&& other) {
+ Reset();
+ _env = other._env;
+ _ref = other._ref;
+ _suppressDestruct = other._suppressDestruct;
+ other._env = nullptr;
+ other._ref = nullptr;
+ other._suppressDestruct = false;
+ return *this;
+}
+
+template <typename T>
+inline Reference<T>::Reference(const Reference<T>& other)
+ : _env(other._env), _ref(nullptr), _suppressDestruct(false) {
+ HandleScope scope(_env);
+
+ napi_value value = other.Value();
+ if (value != nullptr) {
+ // Copying is a limited scenario (currently only used for Error object) and always creates a
+ // strong reference to the given value even if the incoming reference is weak.
+ napi_status status = napi_create_reference(_env, value, 1, &_ref);
+ NAPI_FATAL_IF_FAILED(status, "Reference<T>::Reference", "napi_create_reference");
+ }
+}
+
+template <typename T>
+inline Reference<T>::operator napi_ref() const {
+ return _ref;
+}
+
+template <typename T>
+inline bool Reference<T>::operator ==(const Reference<T> &other) const {
+ HandleScope scope(_env);
+ return this->Value().StrictEquals(other.Value());
+}
+
+template <typename T>
+inline bool Reference<T>::operator !=(const Reference<T> &other) const {
+ return !this->operator ==(other);
+}
+
+template <typename T>
+inline Napi::Env Reference<T>::Env() const {
+ return Napi::Env(_env);
+}
+
+template <typename T>
+inline bool Reference<T>::IsEmpty() const {
+ return _ref == nullptr;
+}
+
+template <typename T>
+inline T Reference<T>::Value() const {
+ if (_ref == nullptr) {
+ return T(_env, nullptr);
+ }
+
+ napi_value value;
+ napi_status status = napi_get_reference_value(_env, _ref, &value);
+ NAPI_THROW_IF_FAILED(_env, status, T());
+ return T(_env, value);
+}
+
+template <typename T>
+inline uint32_t Reference<T>::Ref() {
+ uint32_t result;
+ napi_status status = napi_reference_ref(_env, _ref, &result);
+ NAPI_THROW_IF_FAILED(_env, status, 1);
+ return result;
+}
+
+template <typename T>
+inline uint32_t Reference<T>::Unref() {
+ uint32_t result;
+ napi_status status = napi_reference_unref(_env, _ref, &result);
+ NAPI_THROW_IF_FAILED(_env, status, 1);
+ return result;
+}
+
+template <typename T>
+inline void Reference<T>::Reset() {
+ if (_ref != nullptr) {
+ napi_status status = napi_delete_reference(_env, _ref);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+ _ref = nullptr;
+ }
+}
+
+template <typename T>
+inline void Reference<T>::Reset(const T& value, uint32_t refcount) {
+ Reset();
+ _env = value.Env();
+
+ napi_value val = value;
+ if (val != nullptr) {
+ napi_status status = napi_create_reference(_env, value, refcount, &_ref);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+ }
+}
+
+template <typename T>
+inline void Reference<T>::SuppressDestruct() {
+ _suppressDestruct = true;
+}
+
+template <typename T>
+inline Reference<T> Weak(T value) {
+ return Reference<T>::New(value, 0);
+}
+
+inline ObjectReference Weak(Object value) {
+ return Reference<Object>::New(value, 0);
+}
+
+inline FunctionReference Weak(Function value) {
+ return Reference<Function>::New(value, 0);
+}
+
+template <typename T>
+inline Reference<T> Persistent(T value) {
+ return Reference<T>::New(value, 1);
+}
+
+inline ObjectReference Persistent(Object value) {
+ return Reference<Object>::New(value, 1);
+}
+
+inline FunctionReference Persistent(Function value) {
+ return Reference<Function>::New(value, 1);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ObjectReference class
+////////////////////////////////////////////////////////////////////////////////
+
+inline ObjectReference::ObjectReference(): Reference<Object>() {
+}
+
+inline ObjectReference::ObjectReference(napi_env env, napi_ref ref): Reference<Object>(env, ref) {
+}
+
+inline ObjectReference::ObjectReference(Reference<Object>&& other)
+ : Reference<Object>(std::move(other)) {
+}
+
+inline ObjectReference& ObjectReference::operator =(Reference<Object>&& other) {
+ static_cast<Reference<Object>*>(this)->operator=(std::move(other));
+ return *this;
+}
+
+inline ObjectReference::ObjectReference(ObjectReference&& other)
+ : Reference<Object>(std::move(other)) {
+}
+
+inline ObjectReference& ObjectReference::operator =(ObjectReference&& other) {
+ static_cast<Reference<Object>*>(this)->operator=(std::move(other));
+ return *this;
+}
+
+inline ObjectReference::ObjectReference(const ObjectReference& other)
+ : Reference<Object>(other) {
+}
+
+inline Napi::Value ObjectReference::Get(const char* utf8name) const {
+ EscapableHandleScope scope(_env);
+ return scope.Escape(Value().Get(utf8name));
+}
+
+inline Napi::Value ObjectReference::Get(const std::string& utf8name) const {
+ EscapableHandleScope scope(_env);
+ return scope.Escape(Value().Get(utf8name));
+}
+
+inline void ObjectReference::Set(const char* utf8name, napi_value value) {
+ HandleScope scope(_env);
+ Value().Set(utf8name, value);
+}
+
+inline void ObjectReference::Set(const char* utf8name, Napi::Value value) {
+ HandleScope scope(_env);
+ Value().Set(utf8name, value);
+}
+
+inline void ObjectReference::Set(const char* utf8name, const char* utf8value) {
+ HandleScope scope(_env);
+ Value().Set(utf8name, utf8value);
+}
+
+inline void ObjectReference::Set(const char* utf8name, bool boolValue) {
+ HandleScope scope(_env);
+ Value().Set(utf8name, boolValue);
+}
+
+inline void ObjectReference::Set(const char* utf8name, double numberValue) {
+ HandleScope scope(_env);
+ Value().Set(utf8name, numberValue);
+}
+
+inline void ObjectReference::Set(const std::string& utf8name, napi_value value) {
+ HandleScope scope(_env);
+ Value().Set(utf8name, value);
+}
+
+inline void ObjectReference::Set(const std::string& utf8name, Napi::Value value) {
+ HandleScope scope(_env);
+ Value().Set(utf8name, value);
+}
+
+inline void ObjectReference::Set(const std::string& utf8name, std::string& utf8value) {
+ HandleScope scope(_env);
+ Value().Set(utf8name, utf8value);
+}
+
+inline void ObjectReference::Set(const std::string& utf8name, bool boolValue) {
+ HandleScope scope(_env);
+ Value().Set(utf8name, boolValue);
+}
+
+inline void ObjectReference::Set(const std::string& utf8name, double numberValue) {
+ HandleScope scope(_env);
+ Value().Set(utf8name, numberValue);
+}
+
+inline Napi::Value ObjectReference::Get(uint32_t index) const {
+ EscapableHandleScope scope(_env);
+ return scope.Escape(Value().Get(index));
+}
+
+inline void ObjectReference::Set(uint32_t index, napi_value value) {
+ HandleScope scope(_env);
+ Value().Set(index, value);
+}
+
+inline void ObjectReference::Set(uint32_t index, Napi::Value value) {
+ HandleScope scope(_env);
+ Value().Set(index, value);
+}
+
+inline void ObjectReference::Set(uint32_t index, const char* utf8value) {
+ HandleScope scope(_env);
+ Value().Set(index, utf8value);
+}
+
+inline void ObjectReference::Set(uint32_t index, const std::string& utf8value) {
+ HandleScope scope(_env);
+ Value().Set(index, utf8value);
+}
+
+inline void ObjectReference::Set(uint32_t index, bool boolValue) {
+ HandleScope scope(_env);
+ Value().Set(index, boolValue);
+}
+
+inline void ObjectReference::Set(uint32_t index, double numberValue) {
+ HandleScope scope(_env);
+ Value().Set(index, numberValue);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// FunctionReference class
+////////////////////////////////////////////////////////////////////////////////
+
+inline FunctionReference::FunctionReference(): Reference<Function>() {
+}
+
+inline FunctionReference::FunctionReference(napi_env env, napi_ref ref)
+ : Reference<Function>(env, ref) {
+}
+
+inline FunctionReference::FunctionReference(Reference<Function>&& other)
+ : Reference<Function>(std::move(other)) {
+}
+
+inline FunctionReference& FunctionReference::operator =(Reference<Function>&& other) {
+ static_cast<Reference<Function>*>(this)->operator=(std::move(other));
+ return *this;
+}
+
+inline FunctionReference::FunctionReference(FunctionReference&& other)
+ : Reference<Function>(std::move(other)) {
+}
+
+inline FunctionReference& FunctionReference::operator =(FunctionReference&& other) {
+ static_cast<Reference<Function>*>(this)->operator=(std::move(other));
+ return *this;
+}
+
+inline Napi::Value FunctionReference::operator ()(
+ const std::initializer_list<napi_value>& args) const {
+ EscapableHandleScope scope(_env);
+ return scope.Escape(Value()(args));
+}
+
+inline Napi::Value FunctionReference::Call(const std::initializer_list<napi_value>& args) const {
+ EscapableHandleScope scope(_env);
+ Napi::Value result = Value().Call(args);
+ if (scope.Env().IsExceptionPending()) {
+ return Value();
+ }
+ return scope.Escape(result);
+}
+
+inline Napi::Value FunctionReference::Call(const std::vector<napi_value>& args) const {
+ EscapableHandleScope scope(_env);
+ Napi::Value result = Value().Call(args);
+ if (scope.Env().IsExceptionPending()) {
+ return Value();
+ }
+ return scope.Escape(result);
+}
+
+inline Napi::Value FunctionReference::Call(
+ napi_value recv, const std::initializer_list<napi_value>& args) const {
+ EscapableHandleScope scope(_env);
+ Napi::Value result = Value().Call(recv, args);
+ if (scope.Env().IsExceptionPending()) {
+ return Value();
+ }
+ return scope.Escape(result);
+}
+
+inline Napi::Value FunctionReference::Call(
+ napi_value recv, const std::vector<napi_value>& args) const {
+ EscapableHandleScope scope(_env);
+ Napi::Value result = Value().Call(recv, args);
+ if (scope.Env().IsExceptionPending()) {
+ return Value();
+ }
+ return scope.Escape(result);
+}
+
+inline Napi::Value FunctionReference::Call(
+ napi_value recv, size_t argc, const napi_value* args) const {
+ EscapableHandleScope scope(_env);
+ Napi::Value result = Value().Call(recv, argc, args);
+ if (scope.Env().IsExceptionPending()) {
+ return Value();
+ }
+ return scope.Escape(result);
+}
+
+inline Napi::Value FunctionReference::MakeCallback(
+ napi_value recv,
+ const std::initializer_list<napi_value>& args,
+ napi_async_context context) const {
+ EscapableHandleScope scope(_env);
+ Napi::Value result = Value().MakeCallback(recv, args, context);
+ if (scope.Env().IsExceptionPending()) {
+ return Value();
+ }
+ return scope.Escape(result);
+}
+
+inline Napi::Value FunctionReference::MakeCallback(
+ napi_value recv,
+ const std::vector<napi_value>& args,
+ napi_async_context context) const {
+ EscapableHandleScope scope(_env);
+ Napi::Value result = Value().MakeCallback(recv, args, context);
+ if (scope.Env().IsExceptionPending()) {
+ return Value();
+ }
+ return scope.Escape(result);
+}
+
+inline Napi::Value FunctionReference::MakeCallback(
+ napi_value recv,
+ size_t argc,
+ const napi_value* args,
+ napi_async_context context) const {
+ EscapableHandleScope scope(_env);
+ Napi::Value result = Value().MakeCallback(recv, argc, args, context);
+ if (scope.Env().IsExceptionPending()) {
+ return Value();
+ }
+ return scope.Escape(result);
+}
+
+inline Object FunctionReference::New(const std::initializer_list<napi_value>& args) const {
+ EscapableHandleScope scope(_env);
+ return scope.Escape(Value().New(args)).As<Object>();
+}
+
+inline Object FunctionReference::New(const std::vector<napi_value>& args) const {
+ EscapableHandleScope scope(_env);
+ return scope.Escape(Value().New(args)).As<Object>();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CallbackInfo class
+////////////////////////////////////////////////////////////////////////////////
+
+inline CallbackInfo::CallbackInfo(napi_env env, napi_callback_info info)
+ : _env(env), _info(info), _this(nullptr), _dynamicArgs(nullptr), _data(nullptr) {
+ _argc = _staticArgCount;
+ _argv = _staticArgs;
+ napi_status status = napi_get_cb_info(env, info, &_argc, _argv, &_this, &_data);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+
+ if (_argc > _staticArgCount) {
+ // Use either a fixed-size array (on the stack) or a dynamically-allocated
+ // array (on the heap) depending on the number of args.
+ _dynamicArgs = new napi_value[_argc];
+ _argv = _dynamicArgs;
+
+ status = napi_get_cb_info(env, info, &_argc, _argv, nullptr, nullptr);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+ }
+}
+
+inline CallbackInfo::~CallbackInfo() {
+ if (_dynamicArgs != nullptr) {
+ delete[] _dynamicArgs;
+ }
+}
+
+inline Value CallbackInfo::NewTarget() const {
+ napi_value newTarget;
+ napi_status status = napi_get_new_target(_env, _info, &newTarget);
+ NAPI_THROW_IF_FAILED(_env, status, Value());
+ return Value(_env, newTarget);
+}
+
+inline bool CallbackInfo::IsConstructCall() const {
+ return !NewTarget().IsEmpty();
+}
+
+inline Napi::Env CallbackInfo::Env() const {
+ return Napi::Env(_env);
+}
+
+inline size_t CallbackInfo::Length() const {
+ return _argc;
+}
+
+inline const Value CallbackInfo::operator [](size_t index) const {
+ return index < _argc ? Value(_env, _argv[index]) : Env().Undefined();
+}
+
+inline Value CallbackInfo::This() const {
+ if (_this == nullptr) {
+ return Env().Undefined();
+ }
+ return Object(_env, _this);
+}
+
+inline void* CallbackInfo::Data() const {
+ return _data;
+}
+
+inline void CallbackInfo::SetData(void* data) {
+ _data = data;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// PropertyDescriptor class
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename Getter>
+inline PropertyDescriptor
+PropertyDescriptor::Accessor(Napi::Env env,
+ Napi::Object object,
+ const char* utf8name,
+ Getter getter,
+ napi_property_attributes attributes,
+ void* data) {
+ typedef details::CallbackData<Getter, Napi::Value> CbData;
+ auto callbackData = new CbData({ getter, data });
+
+ napi_status status = AttachData(env, object, callbackData);
+ if (status != napi_ok) {
+ delete callbackData;
+ NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor());
+ }
+
+ return PropertyDescriptor({
+ utf8name,
+ nullptr,
+ nullptr,
+ CbData::Wrapper,
+ nullptr,
+ nullptr,
+ attributes,
+ callbackData
+ });
+}
+
+template <typename Getter>
+inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env,
+ Napi::Object object,
+ const std::string& utf8name,
+ Getter getter,
+ napi_property_attributes attributes,
+ void* data) {
+ return Accessor(env, object, utf8name.c_str(), getter, attributes, data);
+}
+
+template <typename Getter>
+inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env,
+ Napi::Object object,
+ Name name,
+ Getter getter,
+ napi_property_attributes attributes,
+ void* data) {
+ typedef details::CallbackData<Getter, Napi::Value> CbData;
+ auto callbackData = new CbData({ getter, data });
+
+ napi_status status = AttachData(env, object, callbackData);
+ if (status != napi_ok) {
+ delete callbackData;
+ NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor());
+ }
+
+ return PropertyDescriptor({
+ nullptr,
+ name,
+ nullptr,
+ CbData::Wrapper,
+ nullptr,
+ nullptr,
+ attributes,
+ callbackData
+ });
+}
+
+template <typename Getter, typename Setter>
+inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env,
+ Napi::Object object,
+ const char* utf8name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes,
+ void* data) {
+ typedef details::AccessorCallbackData<Getter, Setter> CbData;
+ auto callbackData = new CbData({ getter, setter, data });
+
+ napi_status status = AttachData(env, object, callbackData);
+ if (status != napi_ok) {
+ delete callbackData;
+ NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor());
+ }
+
+ return PropertyDescriptor({
+ utf8name,
+ nullptr,
+ nullptr,
+ CbData::GetterWrapper,
+ CbData::SetterWrapper,
+ nullptr,
+ attributes,
+ callbackData
+ });
+}
+
+template <typename Getter, typename Setter>
+inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env,
+ Napi::Object object,
+ const std::string& utf8name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes,
+ void* data) {
+ return Accessor(env, object, utf8name.c_str(), getter, setter, attributes, data);
+}
+
+template <typename Getter, typename Setter>
+inline PropertyDescriptor PropertyDescriptor::Accessor(Napi::Env env,
+ Napi::Object object,
+ Name name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes,
+ void* data) {
+ typedef details::AccessorCallbackData<Getter, Setter> CbData;
+ auto callbackData = new CbData({ getter, setter, data });
+
+ napi_status status = AttachData(env, object, callbackData);
+ if (status != napi_ok) {
+ delete callbackData;
+ NAPI_THROW_IF_FAILED(env, status, napi_property_descriptor());
+ }
+
+ return PropertyDescriptor({
+ nullptr,
+ name,
+ nullptr,
+ CbData::GetterWrapper,
+ CbData::SetterWrapper,
+ nullptr,
+ attributes,
+ callbackData
+ });
+}
+
+template <typename Callable>
+inline PropertyDescriptor PropertyDescriptor::Function(Napi::Env env,
+ Napi::Object /*object*/,
+ const char* utf8name,
+ Callable cb,
+ napi_property_attributes attributes,
+ void* data) {
+ return PropertyDescriptor({
+ utf8name,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ Napi::Function::New(env, cb, utf8name, data),
+ attributes,
+ nullptr
+ });
+}
+
+template <typename Callable>
+inline PropertyDescriptor PropertyDescriptor::Function(Napi::Env env,
+ Napi::Object object,
+ const std::string& utf8name,
+ Callable cb,
+ napi_property_attributes attributes,
+ void* data) {
+ return Function(env, object, utf8name.c_str(), cb, attributes, data);
+}
+
+template <typename Callable>
+inline PropertyDescriptor PropertyDescriptor::Function(Napi::Env env,
+ Napi::Object /*object*/,
+ Name name,
+ Callable cb,
+ napi_property_attributes attributes,
+ void* data) {
+ return PropertyDescriptor({
+ nullptr,
+ name,
+ nullptr,
+ nullptr,
+ nullptr,
+ Napi::Function::New(env, cb, nullptr, data),
+ attributes,
+ nullptr
+ });
+}
+
+inline PropertyDescriptor PropertyDescriptor::Value(const char* utf8name,
+ napi_value value,
+ napi_property_attributes attributes) {
+ return PropertyDescriptor({
+ utf8name, nullptr, nullptr, nullptr, nullptr, value, attributes, nullptr
+ });
+}
+
+inline PropertyDescriptor PropertyDescriptor::Value(const std::string& utf8name,
+ napi_value value,
+ napi_property_attributes attributes) {
+ return Value(utf8name.c_str(), value, attributes);
+}
+
+inline PropertyDescriptor PropertyDescriptor::Value(napi_value name,
+ napi_value value,
+ napi_property_attributes attributes) {
+ return PropertyDescriptor({
+ nullptr, name, nullptr, nullptr, nullptr, value, attributes, nullptr
+ });
+}
+
+inline PropertyDescriptor PropertyDescriptor::Value(Name name,
+ Napi::Value value,
+ napi_property_attributes attributes) {
+ napi_value nameValue = name;
+ napi_value valueValue = value;
+ return PropertyDescriptor::Value(nameValue, valueValue, attributes);
+}
+
+inline PropertyDescriptor::PropertyDescriptor(napi_property_descriptor desc)
+ : _desc(desc) {
+}
+
+inline PropertyDescriptor::operator napi_property_descriptor&() {
+ return _desc;
+}
+
+inline PropertyDescriptor::operator const napi_property_descriptor&() const {
+ return _desc;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// ObjectWrap<T> class
+////////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) {
+ napi_env env = callbackInfo.Env();
+ napi_value wrapper = callbackInfo.This();
+ napi_status status;
+ napi_ref ref;
+ T* instance = static_cast<T*>(this);
+ status = napi_wrap(env, wrapper, instance, FinalizeCallback, nullptr, &ref);
+ NAPI_THROW_IF_FAILED_VOID(env, status);
+
+ Reference<Object>* instanceRef = instance;
+ *instanceRef = Reference<Object>(env, ref);
+}
+
+template<typename T>
+inline ObjectWrap<T>::~ObjectWrap() {}
+
+template<typename T>
+inline T* ObjectWrap<T>::Unwrap(Object wrapper) {
+ T* unwrapped;
+ napi_status status = napi_unwrap(wrapper.Env(), wrapper, reinterpret_cast<void**>(&unwrapped));
+ NAPI_THROW_IF_FAILED(wrapper.Env(), status, nullptr);
+ return unwrapped;
+}
+
+template <typename T>
+inline Function
+ObjectWrap<T>::DefineClass(Napi::Env env,
+ const char* utf8name,
+ const size_t props_count,
+ const napi_property_descriptor* descriptors,
+ void* data) {
+ napi_status status;
+ std::vector<napi_property_descriptor> props(props_count);
+
+ // We copy the descriptors to a local array because before defining the class
+ // we must replace static method property descriptors with value property
+ // descriptors such that the value is a function-valued `napi_value` created
+ // with `CreateFunction()`.
+ //
+ // This replacement could be made for instance methods as well, but V8 aborts
+ // if we do that, because it expects methods defined on the prototype template
+ // to have `FunctionTemplate`s.
+ for (size_t index = 0; index < props_count; index++) {
+ props[index] = descriptors[index];
+ napi_property_descriptor* prop = &props[index];
+ if (prop->method == T::StaticMethodCallbackWrapper) {
+ status = CreateFunction(env,
+ utf8name,
+ prop->method,
+ static_cast<StaticMethodCallbackData*>(prop->data),
+ &(prop->value));
+ NAPI_THROW_IF_FAILED(env, status, Function());
+ prop->method = nullptr;
+ prop->data = nullptr;
+ } else if (prop->method == T::StaticVoidMethodCallbackWrapper) {
+ status = CreateFunction(env,
+ utf8name,
+ prop->method,
+ static_cast<StaticVoidMethodCallbackData*>(prop->data),
+ &(prop->value));
+ NAPI_THROW_IF_FAILED(env, status, Function());
+ prop->method = nullptr;
+ prop->data = nullptr;
+ }
+ }
+
+ napi_value value;
+ status = napi_define_class(env,
+ utf8name,
+ NAPI_AUTO_LENGTH,
+ T::ConstructorCallbackWrapper,
+ data,
+ props_count,
+ props.data(),
+ &value);
+ NAPI_THROW_IF_FAILED(env, status, Function());
+
+ // After defining the class we iterate once more over the property descriptors
+ // and attach the data associated with accessors and instance methods to the
+ // newly created JavaScript class.
+ for (size_t idx = 0; idx < props_count; idx++) {
+ const napi_property_descriptor* prop = &props[idx];
+
+ if (prop->getter == T::StaticGetterCallbackWrapper ||
+ prop->setter == T::StaticSetterCallbackWrapper) {
+ status = Napi::details::AttachData(env,
+ value,
+ static_cast<StaticAccessorCallbackData*>(prop->data));
+ NAPI_THROW_IF_FAILED(env, status, Function());
+ } else if (prop->getter == T::InstanceGetterCallbackWrapper ||
+ prop->setter == T::InstanceSetterCallbackWrapper) {
+ status = Napi::details::AttachData(env,
+ value,
+ static_cast<InstanceAccessorCallbackData*>(prop->data));
+ NAPI_THROW_IF_FAILED(env, status, Function());
+ } else if (prop->method != nullptr && !(prop->attributes & napi_static)) {
+ if (prop->method == T::InstanceVoidMethodCallbackWrapper) {
+ status = Napi::details::AttachData(env,
+ value,
+ static_cast<InstanceVoidMethodCallbackData*>(prop->data));
+ NAPI_THROW_IF_FAILED(env, status, Function());
+ } else if (prop->method == T::InstanceMethodCallbackWrapper) {
+ status = Napi::details::AttachData(env,
+ value,
+ static_cast<InstanceMethodCallbackData*>(prop->data));
+ NAPI_THROW_IF_FAILED(env, status, Function());
+ }
+ }
+ }
+
+ return Function(env, value);
+}
+
+template <typename T>
+inline Function ObjectWrap<T>::DefineClass(
+ Napi::Env env,
+ const char* utf8name,
+ const std::initializer_list<ClassPropertyDescriptor<T>>& properties,
+ void* data) {
+ return DefineClass(env,
+ utf8name,
+ properties.size(),
+ reinterpret_cast<const napi_property_descriptor*>(properties.begin()),
+ data);
+}
+
+template <typename T>
+inline Function ObjectWrap<T>::DefineClass(
+ Napi::Env env,
+ const char* utf8name,
+ const std::vector<ClassPropertyDescriptor<T>>& properties,
+ void* data) {
+ return DefineClass(env,
+ utf8name,
+ properties.size(),
+ reinterpret_cast<const napi_property_descriptor*>(properties.data()),
+ data);
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
+ const char* utf8name,
+ StaticVoidMethodCallback method,
+ napi_property_attributes attributes,
+ void* data) {
+ StaticVoidMethodCallbackData* callbackData = new StaticVoidMethodCallbackData({ method, data });
+
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.utf8name = utf8name;
+ desc.method = T::StaticVoidMethodCallbackWrapper;
+ desc.data = callbackData;
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
+ const char* utf8name,
+ StaticMethodCallback method,
+ napi_property_attributes attributes,
+ void* data) {
+ StaticMethodCallbackData* callbackData = new StaticMethodCallbackData({ method, data });
+
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.utf8name = utf8name;
+ desc.method = T::StaticMethodCallbackWrapper;
+ desc.data = callbackData;
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
+ Symbol name,
+ StaticVoidMethodCallback method,
+ napi_property_attributes attributes,
+ void* data) {
+ StaticVoidMethodCallbackData* callbackData = new StaticVoidMethodCallbackData({ method, data });
+
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.name = name;
+ desc.method = T::StaticVoidMethodCallbackWrapper;
+ desc.data = callbackData;
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticMethod(
+ Symbol name,
+ StaticMethodCallback method,
+ napi_property_attributes attributes,
+ void* data) {
+ StaticMethodCallbackData* callbackData = new StaticMethodCallbackData({ method, data });
+
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.name = name;
+ desc.method = T::StaticMethodCallbackWrapper;
+ desc.data = callbackData;
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
+ const char* utf8name,
+ StaticGetterCallback getter,
+ StaticSetterCallback setter,
+ napi_property_attributes attributes,
+ void* data) {
+ StaticAccessorCallbackData* callbackData =
+ new StaticAccessorCallbackData({ getter, setter, data });
+
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.utf8name = utf8name;
+ desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr;
+ desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr;
+ desc.data = callbackData;
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticAccessor(
+ Symbol name,
+ StaticGetterCallback getter,
+ StaticSetterCallback setter,
+ napi_property_attributes attributes,
+ void* data) {
+ StaticAccessorCallbackData* callbackData =
+ new StaticAccessorCallbackData({ getter, setter, data });
+
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.name = name;
+ desc.getter = getter != nullptr ? T::StaticGetterCallbackWrapper : nullptr;
+ desc.setter = setter != nullptr ? T::StaticSetterCallbackWrapper : nullptr;
+ desc.data = callbackData;
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
+ const char* utf8name,
+ InstanceVoidMethodCallback method,
+ napi_property_attributes attributes,
+ void* data) {
+ InstanceVoidMethodCallbackData* callbackData =
+ new InstanceVoidMethodCallbackData({ method, data});
+
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.utf8name = utf8name;
+ desc.method = T::InstanceVoidMethodCallbackWrapper;
+ desc.data = callbackData;
+ desc.attributes = attributes;
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
+ const char* utf8name,
+ InstanceMethodCallback method,
+ napi_property_attributes attributes,
+ void* data) {
+ InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data });
+
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.utf8name = utf8name;
+ desc.method = T::InstanceMethodCallbackWrapper;
+ desc.data = callbackData;
+ desc.attributes = attributes;
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
+ Symbol name,
+ InstanceVoidMethodCallback method,
+ napi_property_attributes attributes,
+ void* data) {
+ InstanceVoidMethodCallbackData* callbackData =
+ new InstanceVoidMethodCallbackData({ method, data});
+
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.name = name;
+ desc.method = T::InstanceVoidMethodCallbackWrapper;
+ desc.data = callbackData;
+ desc.attributes = attributes;
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceMethod(
+ Symbol name,
+ InstanceMethodCallback method,
+ napi_property_attributes attributes,
+ void* data) {
+ InstanceMethodCallbackData* callbackData = new InstanceMethodCallbackData({ method, data });
+
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.name = name;
+ desc.method = T::InstanceMethodCallbackWrapper;
+ desc.data = callbackData;
+ desc.attributes = attributes;
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceAccessor(
+ const char* utf8name,
+ InstanceGetterCallback getter,
+ InstanceSetterCallback setter,
+ napi_property_attributes attributes,
+ void* data) {
+ InstanceAccessorCallbackData* callbackData =
+ new InstanceAccessorCallbackData({ getter, setter, data });
+
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.utf8name = utf8name;
+ desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr;
+ desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr;
+ desc.data = callbackData;
+ desc.attributes = attributes;
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceAccessor(
+ Symbol name,
+ InstanceGetterCallback getter,
+ InstanceSetterCallback setter,
+ napi_property_attributes attributes,
+ void* data) {
+ InstanceAccessorCallbackData* callbackData =
+ new InstanceAccessorCallbackData({ getter, setter, data });
+
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.name = name;
+ desc.getter = getter != nullptr ? T::InstanceGetterCallbackWrapper : nullptr;
+ desc.setter = setter != nullptr ? T::InstanceSetterCallbackWrapper : nullptr;
+ desc.data = callbackData;
+ desc.attributes = attributes;
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(const char* utf8name,
+ Napi::Value value, napi_property_attributes attributes) {
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.utf8name = utf8name;
+ desc.value = value;
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::StaticValue(Symbol name,
+ Napi::Value value, napi_property_attributes attributes) {
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.name = name;
+ desc.value = value;
+ desc.attributes = static_cast<napi_property_attributes>(attributes | napi_static);
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceValue(
+ const char* utf8name,
+ Napi::Value value,
+ napi_property_attributes attributes) {
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.utf8name = utf8name;
+ desc.value = value;
+ desc.attributes = attributes;
+ return desc;
+}
+
+template <typename T>
+inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceValue(
+ Symbol name,
+ Napi::Value value,
+ napi_property_attributes attributes) {
+ napi_property_descriptor desc = napi_property_descriptor();
+ desc.name = name;
+ desc.value = value;
+ desc.attributes = attributes;
+ return desc;
+}
+
+template <typename T>
+inline void ObjectWrap<T>::Finalize(Napi::Env /*env*/) {}
+
+template <typename T>
+inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
+ napi_env env,
+ napi_callback_info info) {
+ napi_value new_target;
+ napi_status status = napi_get_new_target(env, info, &new_target);
+ if (status != napi_ok) return nullptr;
+
+ bool isConstructCall = (new_target != nullptr);
+ if (!isConstructCall) {
+ napi_throw_type_error(env, nullptr, "Class constructors cannot be invoked without 'new'");
+ return nullptr;
+ }
+
+ T* instance;
+ napi_value wrapper = details::WrapCallback([&] {
+ CallbackInfo callbackInfo(env, info);
+ instance = new T(callbackInfo);
+ return callbackInfo.This();
+ });
+
+ return wrapper;
+}
+
+template <typename T>
+inline napi_value ObjectWrap<T>::StaticVoidMethodCallbackWrapper(
+ napi_env env,
+ napi_callback_info info) {
+ return details::WrapCallback([&] {
+ CallbackInfo callbackInfo(env, info);
+ StaticVoidMethodCallbackData* callbackData =
+ reinterpret_cast<StaticVoidMethodCallbackData*>(callbackInfo.Data());
+ callbackInfo.SetData(callbackData->data);
+ callbackData->callback(callbackInfo);
+ return nullptr;
+ });
+}
+
+template <typename T>
+inline napi_value ObjectWrap<T>::StaticMethodCallbackWrapper(
+ napi_env env,
+ napi_callback_info info) {
+ return details::WrapCallback([&] {
+ CallbackInfo callbackInfo(env, info);
+ StaticMethodCallbackData* callbackData =
+ reinterpret_cast<StaticMethodCallbackData*>(callbackInfo.Data());
+ callbackInfo.SetData(callbackData->data);
+ return callbackData->callback(callbackInfo);
+ });
+}
+
+template <typename T>
+inline napi_value ObjectWrap<T>::StaticGetterCallbackWrapper(
+ napi_env env,
+ napi_callback_info info) {
+ return details::WrapCallback([&] {
+ CallbackInfo callbackInfo(env, info);
+ StaticAccessorCallbackData* callbackData =
+ reinterpret_cast<StaticAccessorCallbackData*>(callbackInfo.Data());
+ callbackInfo.SetData(callbackData->data);
+ return callbackData->getterCallback(callbackInfo);
+ });
+}
+
+template <typename T>
+inline napi_value ObjectWrap<T>::StaticSetterCallbackWrapper(
+ napi_env env,
+ napi_callback_info info) {
+ return details::WrapCallback([&] {
+ CallbackInfo callbackInfo(env, info);
+ StaticAccessorCallbackData* callbackData =
+ reinterpret_cast<StaticAccessorCallbackData*>(callbackInfo.Data());
+ callbackInfo.SetData(callbackData->data);
+ callbackData->setterCallback(callbackInfo, callbackInfo[0]);
+ return nullptr;
+ });
+}
+
+template <typename T>
+inline napi_value ObjectWrap<T>::InstanceVoidMethodCallbackWrapper(
+ napi_env env,
+ napi_callback_info info) {
+ return details::WrapCallback([&] {
+ CallbackInfo callbackInfo(env, info);
+ InstanceVoidMethodCallbackData* callbackData =
+ reinterpret_cast<InstanceVoidMethodCallbackData*>(callbackInfo.Data());
+ callbackInfo.SetData(callbackData->data);
+ T* instance = Unwrap(callbackInfo.This().As<Object>());
+ auto cb = callbackData->callback;
+ (instance->*cb)(callbackInfo);
+ return nullptr;
+ });
+}
+
+template <typename T>
+inline napi_value ObjectWrap<T>::InstanceMethodCallbackWrapper(
+ napi_env env,
+ napi_callback_info info) {
+ return details::WrapCallback([&] {
+ CallbackInfo callbackInfo(env, info);
+ InstanceMethodCallbackData* callbackData =
+ reinterpret_cast<InstanceMethodCallbackData*>(callbackInfo.Data());
+ callbackInfo.SetData(callbackData->data);
+ T* instance = Unwrap(callbackInfo.This().As<Object>());
+ auto cb = callbackData->callback;
+ return (instance->*cb)(callbackInfo);
+ });
+}
+
+template <typename T>
+inline napi_value ObjectWrap<T>::InstanceGetterCallbackWrapper(
+ napi_env env,
+ napi_callback_info info) {
+ return details::WrapCallback([&] {
+ CallbackInfo callbackInfo(env, info);
+ InstanceAccessorCallbackData* callbackData =
+ reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
+ callbackInfo.SetData(callbackData->data);
+ T* instance = Unwrap(callbackInfo.This().As<Object>());
+ auto cb = callbackData->getterCallback;
+ return (instance->*cb)(callbackInfo);
+ });
+}
+
+template <typename T>
+inline napi_value ObjectWrap<T>::InstanceSetterCallbackWrapper(
+ napi_env env,
+ napi_callback_info info) {
+ return details::WrapCallback([&] {
+ CallbackInfo callbackInfo(env, info);
+ InstanceAccessorCallbackData* callbackData =
+ reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
+ callbackInfo.SetData(callbackData->data);
+ T* instance = Unwrap(callbackInfo.This().As<Object>());
+ auto cb = callbackData->setterCallback;
+ (instance->*cb)(callbackInfo, callbackInfo[0]);
+ return nullptr;
+ });
+}
+
+template <typename T>
+inline void ObjectWrap<T>::FinalizeCallback(napi_env env, void* data, void* /*hint*/) {
+ T* instance = reinterpret_cast<T*>(data);
+ instance->Finalize(Napi::Env(env));
+ delete instance;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// HandleScope class
+////////////////////////////////////////////////////////////////////////////////
+
+inline HandleScope::HandleScope(napi_env env, napi_handle_scope scope)
+ : _env(env), _scope(scope) {
+}
+
+inline HandleScope::HandleScope(Napi::Env env) : _env(env) {
+ napi_status status = napi_open_handle_scope(_env, &_scope);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline HandleScope::~HandleScope() {
+ napi_status status = napi_close_handle_scope(_env, _scope);
+ NAPI_FATAL_IF_FAILED(status,
+ "HandleScope::~HandleScope",
+ "napi_close_handle_scope");
+}
+
+inline HandleScope::operator napi_handle_scope() const {
+ return _scope;
+}
+
+inline Napi::Env HandleScope::Env() const {
+ return Napi::Env(_env);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// EscapableHandleScope class
+////////////////////////////////////////////////////////////////////////////////
+
+inline EscapableHandleScope::EscapableHandleScope(
+ napi_env env, napi_escapable_handle_scope scope) : _env(env), _scope(scope) {
+}
+
+inline EscapableHandleScope::EscapableHandleScope(Napi::Env env) : _env(env) {
+ napi_status status = napi_open_escapable_handle_scope(_env, &_scope);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline EscapableHandleScope::~EscapableHandleScope() {
+ napi_status status = napi_close_escapable_handle_scope(_env, _scope);
+ NAPI_FATAL_IF_FAILED(status,
+ "EscapableHandleScope::~EscapableHandleScope",
+ "napi_close_escapable_handle_scope");
+}
+
+inline EscapableHandleScope::operator napi_escapable_handle_scope() const {
+ return _scope;
+}
+
+inline Napi::Env EscapableHandleScope::Env() const {
+ return Napi::Env(_env);
+}
+
+inline Value EscapableHandleScope::Escape(napi_value escapee) {
+ napi_value result;
+ napi_status status = napi_escape_handle(_env, _scope, escapee, &result);
+ NAPI_THROW_IF_FAILED(_env, status, Value());
+ return Value(_env, result);
+}
+
+
+#if (NAPI_VERSION > 2)
+////////////////////////////////////////////////////////////////////////////////
+// CallbackScope class
+////////////////////////////////////////////////////////////////////////////////
+
+inline CallbackScope::CallbackScope(
+ napi_env env, napi_callback_scope scope) : _env(env), _scope(scope) {
+}
+
+inline CallbackScope::CallbackScope(napi_env env, napi_async_context context)
+ : _env(env) {
+ napi_status status = napi_open_callback_scope(
+ _env, Object::New(env), context, &_scope);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline CallbackScope::~CallbackScope() {
+ napi_status status = napi_close_callback_scope(_env, _scope);
+ NAPI_FATAL_IF_FAILED(status,
+ "CallbackScope::~CallbackScope",
+ "napi_close_callback_scope");
+}
+
+inline CallbackScope::operator napi_callback_scope() const {
+ return _scope;
+}
+
+inline Napi::Env CallbackScope::Env() const {
+ return Napi::Env(_env);
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// AsyncContext class
+////////////////////////////////////////////////////////////////////////////////
+
+inline AsyncContext::AsyncContext(napi_env env, const char* resource_name)
+ : AsyncContext(env, resource_name, Object::New(env)) {
+}
+
+inline AsyncContext::AsyncContext(napi_env env,
+ const char* resource_name,
+ const Object& resource)
+ : _env(env),
+ _context(nullptr) {
+ napi_value resource_id;
+ napi_status status = napi_create_string_utf8(
+ _env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+
+ status = napi_async_init(_env, resource, resource_id, &_context);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline AsyncContext::~AsyncContext() {
+ if (_context != nullptr) {
+ napi_async_destroy(_env, _context);
+ _context = nullptr;
+ }
+}
+
+inline AsyncContext::AsyncContext(AsyncContext&& other) {
+ _env = other._env;
+ other._env = nullptr;
+ _context = other._context;
+ other._context = nullptr;
+}
+
+inline AsyncContext& AsyncContext::operator =(AsyncContext&& other) {
+ _env = other._env;
+ other._env = nullptr;
+ _context = other._context;
+ other._context = nullptr;
+ return *this;
+}
+
+inline AsyncContext::operator napi_async_context() const {
+ return _context;
+}
+
+inline Napi::Env AsyncContext::Env() const {
+ return Napi::Env(_env);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// AsyncWorker class
+////////////////////////////////////////////////////////////////////////////////
+
+inline AsyncWorker::AsyncWorker(const Function& callback)
+ : AsyncWorker(callback, "generic") {
+}
+
+inline AsyncWorker::AsyncWorker(const Function& callback,
+ const char* resource_name)
+ : AsyncWorker(callback, resource_name, Object::New(callback.Env())) {
+}
+
+inline AsyncWorker::AsyncWorker(const Function& callback,
+ const char* resource_name,
+ const Object& resource)
+ : AsyncWorker(Object::New(callback.Env()),
+ callback,
+ resource_name,
+ resource) {
+}
+
+inline AsyncWorker::AsyncWorker(const Object& receiver,
+ const Function& callback)
+ : AsyncWorker(receiver, callback, "generic") {
+}
+
+inline AsyncWorker::AsyncWorker(const Object& receiver,
+ const Function& callback,
+ const char* resource_name)
+ : AsyncWorker(receiver,
+ callback,
+ resource_name,
+ Object::New(callback.Env())) {
+}
+
+inline AsyncWorker::AsyncWorker(const Object& receiver,
+ const Function& callback,
+ const char* resource_name,
+ const Object& resource)
+ : _env(callback.Env()),
+ _receiver(Napi::Persistent(receiver)),
+ _callback(Napi::Persistent(callback)),
+ _suppress_destruct(false) {
+ napi_value resource_id;
+ napi_status status = napi_create_string_latin1(
+ _env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+
+ status = napi_create_async_work(_env, resource, resource_id, OnExecute,
+ OnWorkComplete, this, &_work);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline AsyncWorker::AsyncWorker(Napi::Env env)
+ : AsyncWorker(env, "generic") {
+}
+
+inline AsyncWorker::AsyncWorker(Napi::Env env,
+ const char* resource_name)
+ : AsyncWorker(env, resource_name, Object::New(env)) {
+}
+
+inline AsyncWorker::AsyncWorker(Napi::Env env,
+ const char* resource_name,
+ const Object& resource)
+ : _env(env),
+ _receiver(),
+ _callback(),
+ _suppress_destruct(false) {
+ napi_value resource_id;
+ napi_status status = napi_create_string_latin1(
+ _env, resource_name, NAPI_AUTO_LENGTH, &resource_id);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+
+ status = napi_create_async_work(_env, resource, resource_id, OnExecute,
+ OnWorkComplete, this, &_work);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline AsyncWorker::~AsyncWorker() {
+ if (_work != nullptr) {
+ napi_delete_async_work(_env, _work);
+ _work = nullptr;
+ }
+}
+
+inline void AsyncWorker::Destroy() {
+ delete this;
+}
+
+inline AsyncWorker::AsyncWorker(AsyncWorker&& other) {
+ _env = other._env;
+ other._env = nullptr;
+ _work = other._work;
+ other._work = nullptr;
+ _receiver = std::move(other._receiver);
+ _callback = std::move(other._callback);
+ _error = std::move(other._error);
+ _suppress_destruct = other._suppress_destruct;
+}
+
+inline AsyncWorker& AsyncWorker::operator =(AsyncWorker&& other) {
+ _env = other._env;
+ other._env = nullptr;
+ _work = other._work;
+ other._work = nullptr;
+ _receiver = std::move(other._receiver);
+ _callback = std::move(other._callback);
+ _error = std::move(other._error);
+ _suppress_destruct = other._suppress_destruct;
+ return *this;
+}
+
+inline AsyncWorker::operator napi_async_work() const {
+ return _work;
+}
+
+inline Napi::Env AsyncWorker::Env() const {
+ return Napi::Env(_env);
+}
+
+inline void AsyncWorker::Queue() {
+ napi_status status = napi_queue_async_work(_env, _work);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline void AsyncWorker::Cancel() {
+ napi_status status = napi_cancel_async_work(_env, _work);
+ NAPI_THROW_IF_FAILED_VOID(_env, status);
+}
+
+inline ObjectReference& AsyncWorker::Receiver() {
+ return _receiver;
+}
+
+inline FunctionReference& AsyncWorker::Callback() {
+ return _callback;
+}
+
+inline void AsyncWorker::SuppressDestruct() {
+ _suppress_destruct = true;
+}
+
+inline void AsyncWorker::OnOK() {
+ if (!_callback.IsEmpty()) {
+ _callback.Call(_receiver.Value(), GetResult(_callback.Env()));
+ }
+}
+
+inline void AsyncWorker::OnError(const Error& e) {
+ if (!_callback.IsEmpty()) {
+ _callback.Call(_receiver.Value(), std::initializer_list<napi_value>{ e.Value() });
+ }
+}
+
+inline void AsyncWorker::SetError(const std::string& error) {
+ _error = error;
+}
+
+inline std::vector<napi_value> AsyncWorker::GetResult(Napi::Env /*env*/) {
+ return {};
+}
+// The OnExecute method receives an napi_env argument. However, do NOT
+// use it within this method, as it does not run on the main thread and must
+// not run any method that would cause JavaScript to run. In practice, this
+// means that almost any use of napi_env will be incorrect.
+inline void AsyncWorker::OnExecute(napi_env /*DO_NOT_USE*/, void* this_pointer) {
+ AsyncWorker* self = static_cast<AsyncWorker*>(this_pointer);
+#ifdef NAPI_CPP_EXCEPTIONS
+ try {
+ self->Execute();
+ } catch (const std::exception& e) {
+ self->SetError(e.what());
+ }
+#else // NAPI_CPP_EXCEPTIONS
+ self->Execute();
+#endif // NAPI_CPP_EXCEPTIONS
+}
+
+inline void AsyncWorker::OnWorkComplete(
+ napi_env /*env*/, napi_status status, void* this_pointer) {
+ AsyncWorker* self = static_cast<AsyncWorker*>(this_pointer);
+ if (status != napi_cancelled) {
+ HandleScope scope(self->_env);
+ details::WrapCallback([&] {
+ if (self->_error.size() == 0) {
+ self->OnOK();
+ }
+ else {
+ self->OnError(Error::New(self->_env, self->_error));
+ }
+ return nullptr;
+ });
+ }
+ if (!self->_suppress_destruct) {
+ self->Destroy();
+ }
+}
+
+#if (NAPI_VERSION > 3)
+////////////////////////////////////////////////////////////////////////////////
+// ThreadSafeFunction class
+////////////////////////////////////////////////////////////////////////////////
+
+// static
+template <typename ResourceString>
+inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
+ const Function& callback,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount) {
+ return New(env, callback, Object(), resourceName, maxQueueSize,
+ initialThreadCount);
+}
+
+// static
+template <typename ResourceString, typename ContextType>
+inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
+ const Function& callback,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context) {
+ return New(env, callback, Object(), resourceName, maxQueueSize,
+ initialThreadCount, context);
+}
+
+// static
+template <typename ResourceString, typename Finalizer>
+inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
+ const Function& callback,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ Finalizer finalizeCallback) {
+ return New(env, callback, Object(), resourceName, maxQueueSize,
+ initialThreadCount, finalizeCallback);
+}
+
+// static
+template <typename ResourceString, typename Finalizer,
+ typename FinalizerDataType>
+inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
+ const Function& callback,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ Finalizer finalizeCallback,
+ FinalizerDataType* data) {
+ return New(env, callback, Object(), resourceName, maxQueueSize,
+ initialThreadCount, finalizeCallback, data);
+}
+
+// static
+template <typename ResourceString, typename ContextType, typename Finalizer>
+inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
+ const Function& callback,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context,
+ Finalizer finalizeCallback) {
+ return New(env, callback, Object(), resourceName, maxQueueSize,
+ initialThreadCount, context, finalizeCallback);
+}
+
+// static
+template <typename ResourceString, typename ContextType,
+ typename Finalizer, typename FinalizerDataType>
+inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
+ const Function& callback,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context,
+ Finalizer finalizeCallback,
+ FinalizerDataType* data) {
+ return New(env, callback, Object(), resourceName, maxQueueSize,
+ initialThreadCount, context, finalizeCallback, data);
+}
+
+// static
+template <typename ResourceString>
+inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount) {
+ return New(env, callback, resource, resourceName, maxQueueSize,
+ initialThreadCount, static_cast<void*>(nullptr) /* context */);
+}
+
+// static
+template <typename ResourceString, typename ContextType>
+inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context) {
+ return New(env, callback, resource, resourceName, maxQueueSize,
+ initialThreadCount, context,
+ [](Env, ContextType*) {} /* empty finalizer */);
+}
+
+// static
+template <typename ResourceString, typename Finalizer>
+inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ Finalizer finalizeCallback) {
+ return New(env, callback, resource, resourceName, maxQueueSize,
+ initialThreadCount, static_cast<void*>(nullptr) /* context */,
+ finalizeCallback, static_cast<void*>(nullptr) /* data */,
+ details::ThreadSafeFinalize<void, Finalizer>::Wrapper);
+}
+
+// static
+template <typename ResourceString, typename Finalizer,
+ typename FinalizerDataType>
+inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ Finalizer finalizeCallback,
+ FinalizerDataType* data) {
+ return New(env, callback, resource, resourceName, maxQueueSize,
+ initialThreadCount, static_cast<void*>(nullptr) /* context */,
+ finalizeCallback, data,
+ details::ThreadSafeFinalize<
+ void, Finalizer, FinalizerDataType>::FinalizeWrapperWithData);
+}
+
+// static
+template <typename ResourceString, typename ContextType, typename Finalizer>
+inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context,
+ Finalizer finalizeCallback) {
+ return New(env, callback, resource, resourceName, maxQueueSize,
+ initialThreadCount, context, finalizeCallback,
+ static_cast<void*>(nullptr) /* data */,
+ details::ThreadSafeFinalize<
+ ContextType, Finalizer>::FinalizeWrapperWithContext);
+}
+
+// static
+template <typename ResourceString, typename ContextType,
+ typename Finalizer, typename FinalizerDataType>
+inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context,
+ Finalizer finalizeCallback,
+ FinalizerDataType* data) {
+ return New(env, callback, resource, resourceName, maxQueueSize,
+ initialThreadCount, context, finalizeCallback, data,
+ details::ThreadSafeFinalize<ContextType, Finalizer,
+ FinalizerDataType>::FinalizeFinalizeWrapperWithDataAndContext);
+}
+
+inline ThreadSafeFunction::ThreadSafeFunction()
+ : _tsfn() {
+}
+
+inline ThreadSafeFunction::ThreadSafeFunction(
+ napi_threadsafe_function tsfn)
+ : _tsfn(tsfn) {
+}
+
+inline ThreadSafeFunction::operator napi_threadsafe_function() const {
+ return _tsfn;
+}
+
+inline napi_status ThreadSafeFunction::BlockingCall() const {
+ return CallInternal(nullptr, napi_tsfn_blocking);
+}
+
+template <>
+inline napi_status ThreadSafeFunction::BlockingCall(
+ void* data) const {
+ return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_blocking);
+}
+
+template <typename Callback>
+inline napi_status ThreadSafeFunction::BlockingCall(
+ Callback callback) const {
+ return CallInternal(new CallbackWrapper(callback), napi_tsfn_blocking);
+}
+
+template <typename DataType, typename Callback>
+inline napi_status ThreadSafeFunction::BlockingCall(
+ DataType* data, Callback callback) const {
+ auto wrapper = [data, callback](Env env, Function jsCallback) {
+ callback(env, jsCallback, data);
+ };
+ return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_blocking);
+}
+
+inline napi_status ThreadSafeFunction::NonBlockingCall() const {
+ return CallInternal(nullptr, napi_tsfn_nonblocking);
+}
+
+template <>
+inline napi_status ThreadSafeFunction::NonBlockingCall(
+ void* data) const {
+ return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_nonblocking);
+}
+
+template <typename Callback>
+inline napi_status ThreadSafeFunction::NonBlockingCall(
+ Callback callback) const {
+ return CallInternal(new CallbackWrapper(callback), napi_tsfn_nonblocking);
+}
+
+template <typename DataType, typename Callback>
+inline napi_status ThreadSafeFunction::NonBlockingCall(
+ DataType* data, Callback callback) const {
+ auto wrapper = [data, callback](Env env, Function jsCallback) {
+ callback(env, jsCallback, data);
+ };
+ return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_nonblocking);
+}
+
+inline void ThreadSafeFunction::Ref(napi_env env) const {
+ if (_tsfn != nullptr) {
+ napi_status status = napi_ref_threadsafe_function(env, _tsfn);
+ NAPI_THROW_IF_FAILED_VOID(env, status);
+ }
+}
+
+inline void ThreadSafeFunction::Unref(napi_env env) const {
+ if (_tsfn != nullptr) {
+ napi_status status = napi_unref_threadsafe_function(env, _tsfn);
+ NAPI_THROW_IF_FAILED_VOID(env, status);
+ }
+}
+
+inline napi_status ThreadSafeFunction::Acquire() const {
+ return napi_acquire_threadsafe_function(_tsfn);
+}
+
+inline napi_status ThreadSafeFunction::Release() {
+ return napi_release_threadsafe_function(_tsfn, napi_tsfn_release);
+}
+
+inline napi_status ThreadSafeFunction::Abort() {
+ return napi_release_threadsafe_function(_tsfn, napi_tsfn_abort);
+}
+
+inline ThreadSafeFunction::ConvertibleContext
+ThreadSafeFunction::GetContext() const {
+ void* context;
+ napi_status status = napi_get_threadsafe_function_context(_tsfn, &context);
+ NAPI_FATAL_IF_FAILED(status, "ThreadSafeFunction::GetContext", "napi_get_threadsafe_function_context");
+ return ConvertibleContext({ context });
+}
+
+// static
+template <typename ResourceString, typename ContextType,
+ typename Finalizer, typename FinalizerDataType>
+inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context,
+ Finalizer finalizeCallback,
+ FinalizerDataType* data,
+ napi_finalize wrapper) {
+ static_assert(details::can_make_string<ResourceString>::value
+ || std::is_convertible<ResourceString, napi_value>::value,
+ "Resource name should be convertible to the string type");
+
+ ThreadSafeFunction tsfn;
+ auto* finalizeData = new details::ThreadSafeFinalize<ContextType, Finalizer,
+ FinalizerDataType>({ data, finalizeCallback, &tsfn._tsfn });
+ napi_status status = napi_create_threadsafe_function(env, callback, resource,
+ Value::From(env, resourceName), maxQueueSize, initialThreadCount,
+ finalizeData, wrapper, context, CallJS, &tsfn._tsfn);
+ if (status != napi_ok) {
+ delete finalizeData;
+ NAPI_THROW_IF_FAILED(env, status, ThreadSafeFunction());
+ }
+
+ return tsfn;
+}
+
+inline napi_status ThreadSafeFunction::CallInternal(
+ CallbackWrapper* callbackWrapper,
+ napi_threadsafe_function_call_mode mode) const {
+ napi_status status = napi_call_threadsafe_function(
+ _tsfn, callbackWrapper, mode);
+ if (status != napi_ok && callbackWrapper != nullptr) {
+ delete callbackWrapper;
+ }
+
+ return status;
+}
+
+// static
+inline void ThreadSafeFunction::CallJS(napi_env env,
+ napi_value jsCallback,
+ void* /* context */,
+ void* data) {
+ if (env == nullptr && jsCallback == nullptr) {
+ return;
+ }
+
+ if (data != nullptr) {
+ auto* callbackWrapper = static_cast<CallbackWrapper*>(data);
+ (*callbackWrapper)(env, Function(env, jsCallback));
+ delete callbackWrapper;
+ } else if (jsCallback != nullptr) {
+ Function(env, jsCallback).Call({});
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Async Progress Worker class
+////////////////////////////////////////////////////////////////////////////////
+
+template<class T>
+inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback)
+ : AsyncProgressWorker(callback, "generic") {
+}
+
+template<class T>
+inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback,
+ const char* resource_name)
+ : AsyncProgressWorker(callback, resource_name, Object::New(callback.Env())) {
+}
+
+template<class T>
+inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback,
+ const char* resource_name,
+ const Object& resource)
+ : AsyncProgressWorker(Object::New(callback.Env()),
+ callback,
+ resource_name,
+ resource) {
+}
+
+template<class T>
+inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
+ const Function& callback)
+ : AsyncProgressWorker(receiver, callback, "generic") {
+}
+
+template<class T>
+inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
+ const Function& callback,
+ const char* resource_name)
+ : AsyncProgressWorker(receiver,
+ callback,
+ resource_name,
+ Object::New(callback.Env())) {
+}
+
+template<class T>
+inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
+ const Function& callback,
+ const char* resource_name,
+ const Object& resource)
+ : AsyncWorker(receiver, callback, resource_name, resource),
+ _asyncdata(nullptr),
+ _asyncsize(0) {
+ _tsfn = ThreadSafeFunction::New(callback.Env(), callback, resource_name, 1, 1);
+}
+
+#if NAPI_VERSION > 4
+template<class T>
+inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env)
+ : AsyncProgressWorker(env, "generic") {
+}
+
+template<class T>
+inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
+ const char* resource_name)
+ : AsyncProgressWorker(env, resource_name, Object::New(env)) {
+}
+
+template<class T>
+inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
+ const char* resource_name,
+ const Object& resource)
+ : AsyncWorker(env, resource_name, resource),
+ _asyncdata(nullptr),
+ _asyncsize(0) {
+ // TODO: Once the changes to make the callback optional for threadsafe
+ // functions are no longer optional we can remove the dummy Function here.
+ Function callback;
+ _tsfn = ThreadSafeFunction::New(env, callback, resource_name, 1, 1);
+}
+#endif
+
+template<class T>
+inline AsyncProgressWorker<T>::~AsyncProgressWorker() {
+ // Abort pending tsfn call.
+ // Don't send progress events after we've already completed.
+ _tsfn.Abort();
+ {
+ std::lock_guard<std::mutex> lock(_mutex);
+ _asyncdata = nullptr;
+ _asyncsize = 0;
+ }
+ _tsfn.Release();
+}
+
+template<class T>
+inline void AsyncProgressWorker<T>::Execute() {
+ ExecutionProgress progress(this);
+ Execute(progress);
+}
+
+template<class T>
+inline void AsyncProgressWorker<T>::WorkProgress_(Napi::Env /* env */, Napi::Function /* jsCallback */, void* _data) {
+ AsyncProgressWorker* self = static_cast<AsyncProgressWorker*>(_data);
+
+ T* data;
+ size_t size;
+ {
+ std::lock_guard<std::mutex> lock(self->_mutex);
+ data = self->_asyncdata;
+ size = self->_asyncsize;
+ self->_asyncdata = nullptr;
+ self->_asyncsize = 0;
+ }
+
+ self->OnProgress(data, size);
+ delete[] data;
+}
+
+template<class T>
+inline void AsyncProgressWorker<T>::SendProgress_(const T* data, size_t count) {
+ T* new_data = new T[count];
+ std::copy(data, data + count, new_data);
+
+ T* old_data;
+ {
+ std::lock_guard<std::mutex> lock(_mutex);
+ old_data = _asyncdata;
+ _asyncdata = new_data;
+ _asyncsize = count;
+ }
+ _tsfn.NonBlockingCall(this, WorkProgress_);
+
+ delete[] old_data;
+}
+
+template<class T>
+inline void AsyncProgressWorker<T>::Signal() const {
+ _tsfn.NonBlockingCall(this, WorkProgress_);
+}
+
+template<class T>
+inline void AsyncProgressWorker<T>::ExecutionProgress::Signal() const {
+ _worker->Signal();
+}
+
+template<class T>
+inline void AsyncProgressWorker<T>::ExecutionProgress::Send(const T* data, size_t count) const {
+ _worker->SendProgress_(data, count);
+}
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Memory Management class
+////////////////////////////////////////////////////////////////////////////////
+
+inline int64_t MemoryManagement::AdjustExternalMemory(Env env, int64_t change_in_bytes) {
+ int64_t result;
+ napi_status status = napi_adjust_external_memory(env, change_in_bytes, &result);
+ NAPI_THROW_IF_FAILED(env, status, 0);
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Version Management class
+////////////////////////////////////////////////////////////////////////////////
+
+inline uint32_t VersionManagement::GetNapiVersion(Env env) {
+ uint32_t result;
+ napi_status status = napi_get_version(env, &result);
+ NAPI_THROW_IF_FAILED(env, status, 0);
+ return result;
+}
+
+inline const napi_node_version* VersionManagement::GetNodeVersion(Env env) {
+ const napi_node_version* result;
+ napi_status status = napi_get_node_version(env, &result);
+ NAPI_THROW_IF_FAILED(env, status, 0);
+ return result;
+}
+
+} // namespace Napi
+
+#endif // SRC_NAPI_INL_H_
diff --git a/debian/build_modules/node-addon-api/napi.h b/debian/build_modules/node-addon-api/napi.h
new file mode 100644
index 0000000..2fc9b10
--- /dev/null
+++ b/debian/build_modules/node-addon-api/napi.h
@@ -0,0 +1,2171 @@
+#ifndef SRC_NAPI_H_
+#define SRC_NAPI_H_
+
+#include <node_api.h>
+#include <functional>
+#include <initializer_list>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <vector>
+
+// VS2015 RTM has bugs with constexpr, so require min of VS2015 Update 3 (known good version)
+#if !defined(_MSC_VER) || _MSC_FULL_VER >= 190024210
+#define NAPI_HAS_CONSTEXPR 1
+#endif
+
+// VS2013 does not support char16_t literal strings, so we'll work around it using wchar_t strings
+// and casting them. This is safe as long as the character sizes are the same.
+#if defined(_MSC_VER) && _MSC_VER <= 1800
+static_assert(sizeof(char16_t) == sizeof(wchar_t), "Size mismatch between char16_t and wchar_t");
+#define NAPI_WIDE_TEXT(x) reinterpret_cast<char16_t*>(L ## x)
+#else
+#define NAPI_WIDE_TEXT(x) u ## x
+#endif
+
+// If C++ exceptions are not explicitly enabled or disabled, enable them
+// if exceptions were enabled in the compiler settings.
+#if !defined(NAPI_CPP_EXCEPTIONS) && !defined(NAPI_DISABLE_CPP_EXCEPTIONS)
+ #if defined(_CPPUNWIND) || defined (__EXCEPTIONS)
+ #define NAPI_CPP_EXCEPTIONS
+ #else
+ #error Exception support not detected. \
+ Define either NAPI_CPP_EXCEPTIONS or NAPI_DISABLE_CPP_EXCEPTIONS.
+ #endif
+#endif
+
+#ifdef _NOEXCEPT
+ #define NAPI_NOEXCEPT _NOEXCEPT
+#else
+ #define NAPI_NOEXCEPT noexcept
+#endif
+
+#ifdef NAPI_CPP_EXCEPTIONS
+
+// When C++ exceptions are enabled, Errors are thrown directly. There is no need
+// to return anything after the throw statements. The variadic parameter is an
+// optional return value that is ignored.
+// We need _VOID versions of the macros to avoid warnings resulting from
+// leaving the NAPI_THROW_* `...` argument empty.
+
+#define NAPI_THROW(e, ...) throw e
+#define NAPI_THROW_VOID(e) throw e
+
+#define NAPI_THROW_IF_FAILED(env, status, ...) \
+ if ((status) != napi_ok) throw Napi::Error::New(env);
+
+#define NAPI_THROW_IF_FAILED_VOID(env, status) \
+ if ((status) != napi_ok) throw Napi::Error::New(env);
+
+#else // NAPI_CPP_EXCEPTIONS
+
+// When C++ exceptions are disabled, Errors are thrown as JavaScript exceptions,
+// which are pending until the callback returns to JS. The variadic parameter
+// is an optional return value; usually it is an empty result.
+// We need _VOID versions of the macros to avoid warnings resulting from
+// leaving the NAPI_THROW_* `...` argument empty.
+
+#define NAPI_THROW(e, ...) \
+ do { \
+ (e).ThrowAsJavaScriptException(); \
+ return __VA_ARGS__; \
+ } while (0)
+
+#define NAPI_THROW_VOID(e) \
+ do { \
+ (e).ThrowAsJavaScriptException(); \
+ return; \
+ } while (0)
+
+#define NAPI_THROW_IF_FAILED(env, status, ...) \
+ if ((status) != napi_ok) { \
+ Napi::Error::New(env).ThrowAsJavaScriptException(); \
+ return __VA_ARGS__; \
+ }
+
+#define NAPI_THROW_IF_FAILED_VOID(env, status) \
+ if ((status) != napi_ok) { \
+ Napi::Error::New(env).ThrowAsJavaScriptException(); \
+ return; \
+ }
+
+#endif // NAPI_CPP_EXCEPTIONS
+
+#define NAPI_FATAL_IF_FAILED(status, location, message) \
+ do { \
+ if ((status) != napi_ok) { \
+ Napi::Error::Fatal((location), (message)); \
+ } \
+ } while (0)
+
+////////////////////////////////////////////////////////////////////////////////
+/// N-API C++ Wrapper Classes
+///
+/// These classes wrap the "N-API" ABI-stable C APIs for Node.js, providing a
+/// C++ object model and C++ exception-handling semantics with low overhead.
+/// The wrappers are all header-only so that they do not affect the ABI.
+////////////////////////////////////////////////////////////////////////////////
+namespace Napi {
+
+ // Forward declarations
+ class Env;
+ class Value;
+ class Boolean;
+ class Number;
+// Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
+// Once it is no longer experimental guard with the NAPI_VERSION in which it is
+// released instead.
+#ifdef NAPI_EXPERIMENTAL
+ class BigInt;
+#endif // NAPI_EXPERIMENTAL
+#if (NAPI_VERSION > 4)
+ class Date;
+#endif
+ class String;
+ class Object;
+ class Array;
+ class Function;
+ template <typename T> class Buffer;
+ class Error;
+ class PropertyDescriptor;
+ class CallbackInfo;
+ template <typename T> class Reference;
+ class TypedArray;
+ template <typename T> class TypedArrayOf;
+
+ typedef TypedArrayOf<int8_t> Int8Array; ///< Typed-array of signed 8-bit integers
+ typedef TypedArrayOf<uint8_t> Uint8Array; ///< Typed-array of unsigned 8-bit integers
+ typedef TypedArrayOf<int16_t> Int16Array; ///< Typed-array of signed 16-bit integers
+ typedef TypedArrayOf<uint16_t> Uint16Array; ///< Typed-array of unsigned 16-bit integers
+ typedef TypedArrayOf<int32_t> Int32Array; ///< Typed-array of signed 32-bit integers
+ typedef TypedArrayOf<uint32_t> Uint32Array; ///< Typed-array of unsigned 32-bit integers
+ typedef TypedArrayOf<float> Float32Array; ///< Typed-array of 32-bit floating-point values
+ typedef TypedArrayOf<double> Float64Array; ///< Typed-array of 64-bit floating-point values
+// Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
+// Once it is no longer experimental guard with the NAPI_VERSION in which it is
+// released instead.
+#ifdef NAPI_EXPERIMENTAL
+ typedef TypedArrayOf<int64_t> BigInt64Array; ///< Typed array of signed 64-bit integers
+ typedef TypedArrayOf<uint64_t> BigUint64Array; ///< Typed array of unsigned 64-bit integers
+#endif // NAPI_EXPERIMENTAL
+
+ /// Defines the signature of a N-API C++ module's registration callback (init) function.
+ typedef Object (*ModuleRegisterCallback)(Env env, Object exports);
+
+ class MemoryManagement;
+
+ /// Environment for N-API values and operations.
+ ///
+ /// All N-API values and operations must be associated with an environment. An environment
+ /// instance is always provided to callback functions; that environment must then be used for any
+ /// creation of N-API values or other N-API operations within the callback. (Many methods infer
+ /// the environment from the `this` instance that the method is called on.)
+ ///
+ /// In the future, multiple environments per process may be supported, although current
+ /// implementations only support one environment per process.
+ ///
+ /// In the V8 JavaScript engine, a N-API environment approximately corresponds to an Isolate.
+ class Env {
+ public:
+ Env(napi_env env);
+
+ operator napi_env() const;
+
+ Object Global() const;
+ Value Undefined() const;
+ Value Null() const;
+
+ bool IsExceptionPending() const;
+ Error GetAndClearPendingException();
+
+ private:
+ napi_env _env;
+ };
+
+ /// A JavaScript value of unknown type.
+ ///
+ /// For type-specific operations, convert to one of the Value subclasses using a `To*` or `As()`
+ /// method. The `To*` methods do type coercion; the `As()` method does not.
+ ///
+ /// Napi::Value value = ...
+ /// if (!value.IsString()) throw Napi::TypeError::New(env, "Invalid arg...");
+ /// Napi::String str = value.As<Napi::String>(); // Cast to a string value
+ ///
+ /// Napi::Value anotherValue = ...
+ /// bool isTruthy = anotherValue.ToBoolean(); // Coerce to a boolean value
+ class Value {
+ public:
+ Value(); ///< Creates a new _empty_ Value instance.
+ Value(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
+
+ /// Creates a JS value from a C++ primitive.
+ ///
+ /// `value` may be any of:
+ /// - bool
+ /// - Any integer type
+ /// - Any floating point type
+ /// - const char* (encoded using UTF-8, null-terminated)
+ /// - const char16_t* (encoded using UTF-16-LE, null-terminated)
+ /// - std::string (encoded using UTF-8)
+ /// - std::u16string
+ /// - napi::Value
+ /// - napi_value
+ template <typename T>
+ static Value From(napi_env env, const T& value);
+
+ /// Converts to a N-API value primitive.
+ ///
+ /// If the instance is _empty_, this returns `nullptr`.
+ operator napi_value() const;
+
+ /// Tests if this value strictly equals another value.
+ bool operator ==(const Value& other) const;
+
+ /// Tests if this value does not strictly equal another value.
+ bool operator !=(const Value& other) const;
+
+ /// Tests if this value strictly equals another value.
+ bool StrictEquals(const Value& other) const;
+
+ /// Gets the environment the value is associated with.
+ Napi::Env Env() const;
+
+ /// Checks if the value is empty (uninitialized).
+ ///
+ /// An empty value is invalid, and most attempts to perform an operation on an empty value
+ /// will result in an exception. Note an empty value is distinct from JavaScript `null` or
+ /// `undefined`, which are valid values.
+ ///
+ /// When C++ exceptions are disabled at compile time, a method with a `Value` return type may
+ /// return an empty value to indicate a pending exception. So when not using C++ exceptions,
+ /// callers should check whether the value is empty before attempting to use it.
+ bool IsEmpty() const;
+
+ napi_valuetype Type() const; ///< Gets the type of the value.
+
+ bool IsUndefined() const; ///< Tests if a value is an undefined JavaScript value.
+ bool IsNull() const; ///< Tests if a value is a null JavaScript value.
+ bool IsBoolean() const; ///< Tests if a value is a JavaScript boolean.
+ bool IsNumber() const; ///< Tests if a value is a JavaScript number.
+// Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
+// Once it is no longer experimental guard with the NAPI_VERSION in which it is
+// released instead.
+#ifdef NAPI_EXPERIMENTAL
+ bool IsBigInt() const; ///< Tests if a value is a JavaScript bigint.
+#endif // NAPI_EXPERIMENTAL
+#if (NAPI_VERSION > 4)
+ bool IsDate() const; ///< Tests if a value is a JavaScript date.
+#endif
+ bool IsString() const; ///< Tests if a value is a JavaScript string.
+ bool IsSymbol() const; ///< Tests if a value is a JavaScript symbol.
+ bool IsArray() const; ///< Tests if a value is a JavaScript array.
+ bool IsArrayBuffer() const; ///< Tests if a value is a JavaScript array buffer.
+ bool IsTypedArray() const; ///< Tests if a value is a JavaScript typed array.
+ bool IsObject() const; ///< Tests if a value is a JavaScript object.
+ bool IsFunction() const; ///< Tests if a value is a JavaScript function.
+ bool IsPromise() const; ///< Tests if a value is a JavaScript promise.
+ bool IsDataView() const; ///< Tests if a value is a JavaScript data view.
+ bool IsBuffer() const; ///< Tests if a value is a Node buffer.
+ bool IsExternal() const; ///< Tests if a value is a pointer to external data.
+
+ /// Casts to another type of `Napi::Value`, when the actual type is known or assumed.
+ ///
+ /// This conversion does NOT coerce the type. Calling any methods inappropriate for the actual
+ /// value type will throw `Napi::Error`.
+ template <typename T> T As() const;
+
+ Boolean ToBoolean() const; ///< Coerces a value to a JavaScript boolean.
+ Number ToNumber() const; ///< Coerces a value to a JavaScript number.
+ String ToString() const; ///< Coerces a value to a JavaScript string.
+ Object ToObject() const; ///< Coerces a value to a JavaScript object.
+
+ protected:
+ /// !cond INTERNAL
+ napi_env _env;
+ napi_value _value;
+ /// !endcond
+ };
+
+ /// A JavaScript boolean value.
+ class Boolean : public Value {
+ public:
+ static Boolean New(
+ napi_env env, ///< N-API environment
+ bool value ///< Boolean value
+ );
+
+ Boolean(); ///< Creates a new _empty_ Boolean instance.
+ Boolean(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
+
+ operator bool() const; ///< Converts a Boolean value to a boolean primitive.
+ bool Value() const; ///< Converts a Boolean value to a boolean primitive.
+ };
+
+ /// A JavaScript number value.
+ class Number : public Value {
+ public:
+ static Number New(
+ napi_env env, ///< N-API environment
+ double value ///< Number value
+ );
+
+ Number(); ///< Creates a new _empty_ Number instance.
+ Number(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
+
+ operator int32_t() const; ///< Converts a Number value to a 32-bit signed integer value.
+ operator uint32_t() const; ///< Converts a Number value to a 32-bit unsigned integer value.
+ operator int64_t() const; ///< Converts a Number value to a 64-bit signed integer value.
+ operator float() const; ///< Converts a Number value to a 32-bit floating-point value.
+ operator double() const; ///< Converts a Number value to a 64-bit floating-point value.
+
+ int32_t Int32Value() const; ///< Converts a Number value to a 32-bit signed integer value.
+ uint32_t Uint32Value() const; ///< Converts a Number value to a 32-bit unsigned integer value.
+ int64_t Int64Value() const; ///< Converts a Number value to a 64-bit signed integer value.
+ float FloatValue() const; ///< Converts a Number value to a 32-bit floating-point value.
+ double DoubleValue() const; ///< Converts a Number value to a 64-bit floating-point value.
+ };
+
+// Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
+// Once it is no longer experimental guard with the NAPI_VERSION in which it is
+// released instead.
+#ifdef NAPI_EXPERIMENTAL
+ /// A JavaScript bigint value.
+ class BigInt : public Value {
+ public:
+ static BigInt New(
+ napi_env env, ///< N-API environment
+ int64_t value ///< Number value
+ );
+ static BigInt New(
+ napi_env env, ///< N-API environment
+ uint64_t value ///< Number value
+ );
+
+ /// Creates a new BigInt object using a specified sign bit and a
+ /// specified list of digits/words.
+ /// The resulting number is calculated as:
+ /// (-1)^sign_bit * (words[0] * (2^64)^0 + words[1] * (2^64)^1 + ...)
+ static BigInt New(
+ napi_env env, ///< N-API environment
+ int sign_bit, ///< Sign bit. 1 if negative.
+ size_t word_count, ///< Number of words in array
+ const uint64_t* words ///< Array of words
+ );
+
+ BigInt(); ///< Creates a new _empty_ BigInt instance.
+ BigInt(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
+
+ int64_t Int64Value(bool* lossless) const; ///< Converts a BigInt value to a 64-bit signed integer value.
+ uint64_t Uint64Value(bool* lossless) const; ///< Converts a BigInt value to a 64-bit unsigned integer value.
+
+ size_t WordCount() const; ///< The number of 64-bit words needed to store the result of ToWords().
+
+ /// Writes the contents of this BigInt to a specified memory location.
+ /// `sign_bit` must be provided and will be set to 1 if this BigInt is negative.
+ /// `*word_count` has to be initialized to the length of the `words` array.
+ /// Upon return, it will be set to the actual number of words that would
+ /// be needed to store this BigInt (i.e. the return value of `WordCount()`).
+ void ToWords(int* sign_bit, size_t* word_count, uint64_t* words);
+ };
+#endif // NAPI_EXPERIMENTAL
+
+#if (NAPI_VERSION > 4)
+ /// A JavaScript date value.
+ class Date : public Value {
+ public:
+ /// Creates a new Date value from a double primitive.
+ static Date New(
+ napi_env env, ///< N-API environment
+ double value ///< Number value
+ );
+
+ Date(); ///< Creates a new _empty_ Date instance.
+ Date(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
+ operator double() const; ///< Converts a Date value to double primitive
+
+ double ValueOf() const; ///< Converts a Date value to a double primitive.
+ };
+ #endif
+
+ /// A JavaScript string or symbol value (that can be used as a property name).
+ class Name : public Value {
+ public:
+ Name(); ///< Creates a new _empty_ Name instance.
+ Name(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
+ };
+
+ /// A JavaScript string value.
+ class String : public Name {
+ public:
+ /// Creates a new String value from a UTF-8 encoded C++ string.
+ static String New(
+ napi_env env, ///< N-API environment
+ const std::string& value ///< UTF-8 encoded C++ string
+ );
+
+ /// Creates a new String value from a UTF-16 encoded C++ string.
+ static String New(
+ napi_env env, ///< N-API environment
+ const std::u16string& value ///< UTF-16 encoded C++ string
+ );
+
+ /// Creates a new String value from a UTF-8 encoded C string.
+ static String New(
+ napi_env env, ///< N-API environment
+ const char* value ///< UTF-8 encoded null-terminated C string
+ );
+
+ /// Creates a new String value from a UTF-16 encoded C string.
+ static String New(
+ napi_env env, ///< N-API environment
+ const char16_t* value ///< UTF-16 encoded null-terminated C string
+ );
+
+ /// Creates a new String value from a UTF-8 encoded C string with specified length.
+ static String New(
+ napi_env env, ///< N-API environment
+ const char* value, ///< UTF-8 encoded C string (not necessarily null-terminated)
+ size_t length ///< length of the string in bytes
+ );
+
+ /// Creates a new String value from a UTF-16 encoded C string with specified length.
+ static String New(
+ napi_env env, ///< N-API environment
+ const char16_t* value, ///< UTF-16 encoded C string (not necessarily null-terminated)
+ size_t length ///< Length of the string in 2-byte code units
+ );
+
+ /// Creates a new String based on the original object's type.
+ ///
+ /// `value` may be any of:
+ /// - const char* (encoded using UTF-8, null-terminated)
+ /// - const char16_t* (encoded using UTF-16-LE, null-terminated)
+ /// - std::string (encoded using UTF-8)
+ /// - std::u16string
+ template <typename T>
+ static String From(napi_env env, const T& value);
+
+ String(); ///< Creates a new _empty_ String instance.
+ String(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
+
+ operator std::string() const; ///< Converts a String value to a UTF-8 encoded C++ string.
+ operator std::u16string() const; ///< Converts a String value to a UTF-16 encoded C++ string.
+ std::string Utf8Value() const; ///< Converts a String value to a UTF-8 encoded C++ string.
+ std::u16string Utf16Value() const; ///< Converts a String value to a UTF-16 encoded C++ string.
+ };
+
+ /// A JavaScript symbol value.
+ class Symbol : public Name {
+ public:
+ /// Creates a new Symbol value with an optional description.
+ static Symbol New(
+ napi_env env, ///< N-API environment
+ const char* description = nullptr ///< Optional UTF-8 encoded null-terminated C string
+ /// describing the symbol
+ );
+
+ /// Creates a new Symbol value with a description.
+ static Symbol New(
+ napi_env env, ///< N-API environment
+ const std::string& description ///< UTF-8 encoded C++ string describing the symbol
+ );
+
+ /// Creates a new Symbol value with a description.
+ static Symbol New(
+ napi_env env, ///< N-API environment
+ String description ///< String value describing the symbol
+ );
+
+ /// Creates a new Symbol value with a description.
+ static Symbol New(
+ napi_env env, ///< N-API environment
+ napi_value description ///< String value describing the symbol
+ );
+
+ /// Get a public Symbol (e.g. Symbol.iterator).
+ static Symbol WellKnown(napi_env, const std::string& name);
+
+ Symbol(); ///< Creates a new _empty_ Symbol instance.
+ Symbol(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
+ };
+
+ /// A JavaScript object value.
+ class Object : public Value {
+ public:
+ /// Enables property and element assignments using indexing syntax.
+ ///
+ /// Example:
+ ///
+ /// Napi::Value propertyValue = object1['A'];
+ /// object2['A'] = propertyValue;
+ /// Napi::Value elementValue = array[0];
+ /// array[1] = elementValue;
+ template <typename Key>
+ class PropertyLValue {
+ public:
+ /// Converts an L-value to a value.
+ operator Value() const;
+
+ /// Assigns a value to the property. The type of value can be
+ /// anything supported by `Object::Set`.
+ template <typename ValueType>
+ PropertyLValue& operator =(ValueType value);
+
+ private:
+ PropertyLValue() = delete;
+ PropertyLValue(Object object, Key key);
+ napi_env _env;
+ napi_value _object;
+ Key _key;
+
+ friend class Napi::Object;
+ };
+
+ /// Creates a new Object value.
+ static Object New(
+ napi_env env ///< N-API environment
+ );
+
+ Object(); ///< Creates a new _empty_ Object instance.
+ Object(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
+
+ /// Gets or sets a named property.
+ PropertyLValue<std::string> operator [](
+ const char* utf8name ///< UTF-8 encoded null-terminated property name
+ );
+
+ /// Gets or sets a named property.
+ PropertyLValue<std::string> operator [](
+ const std::string& utf8name ///< UTF-8 encoded property name
+ );
+
+ /// Gets or sets an indexed property or array element.
+ PropertyLValue<uint32_t> operator [](
+ uint32_t index /// Property / element index
+ );
+
+ /// Gets a named property.
+ Value operator [](
+ const char* utf8name ///< UTF-8 encoded null-terminated property name
+ ) const;
+
+ /// Gets a named property.
+ Value operator [](
+ const std::string& utf8name ///< UTF-8 encoded property name
+ ) const;
+
+ /// Gets an indexed property or array element.
+ Value operator [](
+ uint32_t index ///< Property / element index
+ ) const;
+
+ /// Checks whether a property is present.
+ bool Has(
+ napi_value key ///< Property key primitive
+ ) const;
+
+ /// Checks whether a property is present.
+ bool Has(
+ Value key ///< Property key
+ ) const;
+
+ /// Checks whether a named property is present.
+ bool Has(
+ const char* utf8name ///< UTF-8 encoded null-terminated property name
+ ) const;
+
+ /// Checks whether a named property is present.
+ bool Has(
+ const std::string& utf8name ///< UTF-8 encoded property name
+ ) const;
+
+ /// Checks whether a own property is present.
+ bool HasOwnProperty(
+ napi_value key ///< Property key primitive
+ ) const;
+
+ /// Checks whether a own property is present.
+ bool HasOwnProperty(
+ Value key ///< Property key
+ ) const;
+
+ /// Checks whether a own property is present.
+ bool HasOwnProperty(
+ const char* utf8name ///< UTF-8 encoded null-terminated property name
+ ) const;
+
+ /// Checks whether a own property is present.
+ bool HasOwnProperty(
+ const std::string& utf8name ///< UTF-8 encoded property name
+ ) const;
+
+ /// Gets a property.
+ Value Get(
+ napi_value key ///< Property key primitive
+ ) const;
+
+ /// Gets a property.
+ Value Get(
+ Value key ///< Property key
+ ) const;
+
+ /// Gets a named property.
+ Value Get(
+ const char* utf8name ///< UTF-8 encoded null-terminated property name
+ ) const;
+
+ /// Gets a named property.
+ Value Get(
+ const std::string& utf8name ///< UTF-8 encoded property name
+ ) const;
+
+ /// Sets a property.
+ template <typename ValueType>
+ void Set(
+ napi_value key, ///< Property key primitive
+ const ValueType& value ///< Property value primitive
+ );
+
+ /// Sets a property.
+ template <typename ValueType>
+ void Set(
+ Value key, ///< Property key
+ const ValueType& value ///< Property value
+ );
+
+ /// Sets a named property.
+ template <typename ValueType>
+ void Set(
+ const char* utf8name, ///< UTF-8 encoded null-terminated property name
+ const ValueType& value
+ );
+
+ /// Sets a named property.
+ template <typename ValueType>
+ void Set(
+ const std::string& utf8name, ///< UTF-8 encoded property name
+ const ValueType& value ///< Property value primitive
+ );
+
+ /// Delete property.
+ bool Delete(
+ napi_value key ///< Property key primitive
+ );
+
+ /// Delete property.
+ bool Delete(
+ Value key ///< Property key
+ );
+
+ /// Delete property.
+ bool Delete(
+ const char* utf8name ///< UTF-8 encoded null-terminated property name
+ );
+
+ /// Delete property.
+ bool Delete(
+ const std::string& utf8name ///< UTF-8 encoded property name
+ );
+
+ /// Checks whether an indexed property is present.
+ bool Has(
+ uint32_t index ///< Property / element index
+ ) const;
+
+ /// Gets an indexed property or array element.
+ Value Get(
+ uint32_t index ///< Property / element index
+ ) const;
+
+ /// Sets an indexed property or array element.
+ template <typename ValueType>
+ void Set(
+ uint32_t index, ///< Property / element index
+ const ValueType& value ///< Property value primitive
+ );
+
+ /// Deletes an indexed property or array element.
+ bool Delete(
+ uint32_t index ///< Property / element index
+ );
+
+ Array GetPropertyNames() const; ///< Get all property names
+
+ /// Defines a property on the object.
+ void DefineProperty(
+ const PropertyDescriptor& property ///< Descriptor for the property to be defined
+ );
+
+ /// Defines properties on the object.
+ void DefineProperties(
+ const std::initializer_list<PropertyDescriptor>& properties
+ ///< List of descriptors for the properties to be defined
+ );
+
+ /// Defines properties on the object.
+ void DefineProperties(
+ const std::vector<PropertyDescriptor>& properties
+ ///< Vector of descriptors for the properties to be defined
+ );
+
+ /// Checks if an object is an instance created by a constructor function.
+ ///
+ /// This is equivalent to the JavaScript `instanceof` operator.
+ bool InstanceOf(
+ const Function& constructor ///< Constructor function
+ ) const;
+
+ template <typename Finalizer, typename T>
+ inline void AddFinalizer(Finalizer finalizeCallback, T* data);
+
+ template <typename Finalizer, typename T, typename Hint>
+ inline void AddFinalizer(Finalizer finalizeCallback,
+ T* data,
+ Hint* finalizeHint);
+ };
+
+ template <typename T>
+ class External : public Value {
+ public:
+ static External New(napi_env env, T* data);
+
+ // Finalizer must implement `void operator()(Env env, T* data)`.
+ template <typename Finalizer>
+ static External New(napi_env env,
+ T* data,
+ Finalizer finalizeCallback);
+ // Finalizer must implement `void operator()(Env env, T* data, Hint* hint)`.
+ template <typename Finalizer, typename Hint>
+ static External New(napi_env env,
+ T* data,
+ Finalizer finalizeCallback,
+ Hint* finalizeHint);
+
+ External();
+ External(napi_env env, napi_value value);
+
+ T* Data() const;
+ };
+
+ class Array : public Object {
+ public:
+ static Array New(napi_env env);
+ static Array New(napi_env env, size_t length);
+
+ Array();
+ Array(napi_env env, napi_value value);
+
+ uint32_t Length() const;
+ };
+
+ /// A JavaScript array buffer value.
+ class ArrayBuffer : public Object {
+ public:
+ /// Creates a new ArrayBuffer instance over a new automatically-allocated buffer.
+ static ArrayBuffer New(
+ napi_env env, ///< N-API environment
+ size_t byteLength ///< Length of the buffer to be allocated, in bytes
+ );
+
+ /// Creates a new ArrayBuffer instance, using an external buffer with specified byte length.
+ static ArrayBuffer New(
+ napi_env env, ///< N-API environment
+ void* externalData, ///< Pointer to the external buffer to be used by the array
+ size_t byteLength ///< Length of the external buffer to be used by the array, in bytes
+ );
+
+ /// Creates a new ArrayBuffer instance, using an external buffer with specified byte length.
+ template <typename Finalizer>
+ static ArrayBuffer New(
+ napi_env env, ///< N-API environment
+ void* externalData, ///< Pointer to the external buffer to be used by the array
+ size_t byteLength, ///< Length of the external buffer to be used by the array,
+ /// in bytes
+ Finalizer finalizeCallback ///< Function to be called when the array buffer is destroyed;
+ /// must implement `void operator()(Env env, void* externalData)`
+ );
+
+ /// Creates a new ArrayBuffer instance, using an external buffer with specified byte length.
+ template <typename Finalizer, typename Hint>
+ static ArrayBuffer New(
+ napi_env env, ///< N-API environment
+ void* externalData, ///< Pointer to the external buffer to be used by the array
+ size_t byteLength, ///< Length of the external buffer to be used by the array,
+ /// in bytes
+ Finalizer finalizeCallback, ///< Function to be called when the array buffer is destroyed;
+ /// must implement `void operator()(Env env, void* externalData, Hint* hint)`
+ Hint* finalizeHint ///< Hint (second parameter) to be passed to the finalize callback
+ );
+
+ ArrayBuffer(); ///< Creates a new _empty_ ArrayBuffer instance.
+ ArrayBuffer(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
+
+ void* Data(); ///< Gets a pointer to the data buffer.
+ size_t ByteLength(); ///< Gets the length of the array buffer in bytes.
+
+ private:
+ mutable void* _data;
+ mutable size_t _length;
+
+ ArrayBuffer(napi_env env, napi_value value, void* data, size_t length);
+ void EnsureInfo() const;
+ };
+
+ /// A JavaScript typed-array value with unknown array type.
+ ///
+ /// For type-specific operations, cast to a `TypedArrayOf<T>` instance using the `As()`
+ /// method:
+ ///
+ /// Napi::TypedArray array = ...
+ /// if (t.TypedArrayType() == napi_int32_array) {
+ /// Napi::Int32Array int32Array = t.As<Napi::Int32Array>();
+ /// }
+ class TypedArray : public Object {
+ public:
+ TypedArray(); ///< Creates a new _empty_ TypedArray instance.
+ TypedArray(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
+
+ napi_typedarray_type TypedArrayType() const; ///< Gets the type of this typed-array.
+ Napi::ArrayBuffer ArrayBuffer() const; ///< Gets the backing array buffer.
+
+ uint8_t ElementSize() const; ///< Gets the size in bytes of one element in the array.
+ size_t ElementLength() const; ///< Gets the number of elements in the array.
+ size_t ByteOffset() const; ///< Gets the offset into the buffer where the array starts.
+ size_t ByteLength() const; ///< Gets the length of the array in bytes.
+
+ protected:
+ /// !cond INTERNAL
+ napi_typedarray_type _type;
+ size_t _length;
+
+ TypedArray(napi_env env, napi_value value, napi_typedarray_type type, size_t length);
+
+ static const napi_typedarray_type unknown_array_type = static_cast<napi_typedarray_type>(-1);
+
+ template <typename T>
+ static
+#if defined(NAPI_HAS_CONSTEXPR)
+ constexpr
+#endif
+ napi_typedarray_type TypedArrayTypeForPrimitiveType() {
+ return std::is_same<T, int8_t>::value ? napi_int8_array
+ : std::is_same<T, uint8_t>::value ? napi_uint8_array
+ : std::is_same<T, int16_t>::value ? napi_int16_array
+ : std::is_same<T, uint16_t>::value ? napi_uint16_array
+ : std::is_same<T, int32_t>::value ? napi_int32_array
+ : std::is_same<T, uint32_t>::value ? napi_uint32_array
+ : std::is_same<T, float>::value ? napi_float32_array
+ : std::is_same<T, double>::value ? napi_float64_array
+// Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
+// Once it is no longer experimental guard with the NAPI_VERSION in which it is
+// released instead.
+#ifdef NAPI_EXPERIMENTAL
+ : std::is_same<T, int64_t>::value ? napi_bigint64_array
+ : std::is_same<T, uint64_t>::value ? napi_biguint64_array
+#endif // NAPI_EXPERIMENTAL
+ : unknown_array_type;
+ }
+ /// !endcond
+ };
+
+ /// A JavaScript typed-array value with known array type.
+ ///
+ /// Note while it is possible to create and access Uint8 "clamped" arrays using this class,
+ /// the _clamping_ behavior is only applied in JavaScript.
+ template <typename T>
+ class TypedArrayOf : public TypedArray {
+ public:
+ /// Creates a new TypedArray instance over a new automatically-allocated array buffer.
+ ///
+ /// The array type parameter can normally be omitted (because it is inferred from the template
+ /// parameter T), except when creating a "clamped" array:
+ ///
+ /// Uint8Array::New(env, length, napi_uint8_clamped_array)
+ static TypedArrayOf New(
+ napi_env env, ///< N-API environment
+ size_t elementLength, ///< Length of the created array, as a number of elements
+#if defined(NAPI_HAS_CONSTEXPR)
+ napi_typedarray_type type = TypedArray::TypedArrayTypeForPrimitiveType<T>()
+#else
+ napi_typedarray_type type
+#endif
+ ///< Type of array, if different from the default array type for the template parameter T.
+ );
+
+ /// Creates a new TypedArray instance over a provided array buffer.
+ ///
+ /// The array type parameter can normally be omitted (because it is inferred from the template
+ /// parameter T), except when creating a "clamped" array:
+ ///
+ /// Uint8Array::New(env, length, buffer, 0, napi_uint8_clamped_array)
+ static TypedArrayOf New(
+ napi_env env, ///< N-API environment
+ size_t elementLength, ///< Length of the created array, as a number of elements
+ Napi::ArrayBuffer arrayBuffer, ///< Backing array buffer instance to use
+ size_t bufferOffset, ///< Offset into the array buffer where the typed-array starts
+#if defined(NAPI_HAS_CONSTEXPR)
+ napi_typedarray_type type = TypedArray::TypedArrayTypeForPrimitiveType<T>()
+#else
+ napi_typedarray_type type
+#endif
+ ///< Type of array, if different from the default array type for the template parameter T.
+ );
+
+ TypedArrayOf(); ///< Creates a new _empty_ TypedArrayOf instance.
+ TypedArrayOf(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
+
+ T& operator [](size_t index); ///< Gets or sets an element in the array.
+ const T& operator [](size_t index) const; ///< Gets an element in the array.
+
+ /// Gets a pointer to the array's backing buffer.
+ ///
+ /// This is not necessarily the same as the `ArrayBuffer::Data()` pointer, because the
+ /// typed-array may have a non-zero `ByteOffset()` into the `ArrayBuffer`.
+ T* Data();
+
+ /// Gets a pointer to the array's backing buffer.
+ ///
+ /// This is not necessarily the same as the `ArrayBuffer::Data()` pointer, because the
+ /// typed-array may have a non-zero `ByteOffset()` into the `ArrayBuffer`.
+ const T* Data() const;
+
+ private:
+ T* _data;
+
+ TypedArrayOf(napi_env env,
+ napi_value value,
+ napi_typedarray_type type,
+ size_t length,
+ T* data);
+ };
+
+ /// The DataView provides a low-level interface for reading/writing multiple
+ /// number types in an ArrayBuffer irrespective of the platform's endianness.
+ class DataView : public Object {
+ public:
+ static DataView New(napi_env env,
+ Napi::ArrayBuffer arrayBuffer);
+ static DataView New(napi_env env,
+ Napi::ArrayBuffer arrayBuffer,
+ size_t byteOffset);
+ static DataView New(napi_env env,
+ Napi::ArrayBuffer arrayBuffer,
+ size_t byteOffset,
+ size_t byteLength);
+
+ DataView(); ///< Creates a new _empty_ DataView instance.
+ DataView(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
+
+ Napi::ArrayBuffer ArrayBuffer() const; ///< Gets the backing array buffer.
+ size_t ByteOffset() const; ///< Gets the offset into the buffer where the array starts.
+ size_t ByteLength() const; ///< Gets the length of the array in bytes.
+
+ void* Data() const;
+
+ float GetFloat32(size_t byteOffset) const;
+ double GetFloat64(size_t byteOffset) const;
+ int8_t GetInt8(size_t byteOffset) const;
+ int16_t GetInt16(size_t byteOffset) const;
+ int32_t GetInt32(size_t byteOffset) const;
+ uint8_t GetUint8(size_t byteOffset) const;
+ uint16_t GetUint16(size_t byteOffset) const;
+ uint32_t GetUint32(size_t byteOffset) const;
+
+ void SetFloat32(size_t byteOffset, float value) const;
+ void SetFloat64(size_t byteOffset, double value) const;
+ void SetInt8(size_t byteOffset, int8_t value) const;
+ void SetInt16(size_t byteOffset, int16_t value) const;
+ void SetInt32(size_t byteOffset, int32_t value) const;
+ void SetUint8(size_t byteOffset, uint8_t value) const;
+ void SetUint16(size_t byteOffset, uint16_t value) const;
+ void SetUint32(size_t byteOffset, uint32_t value) const;
+
+ private:
+ template <typename T>
+ T ReadData(size_t byteOffset) const;
+
+ template <typename T>
+ void WriteData(size_t byteOffset, T value) const;
+
+ void* _data;
+ size_t _length;
+ };
+
+ class Function : public Object {
+ public:
+ /// Callable must implement operator() accepting a const CallbackInfo&
+ /// and return either void or Value.
+ template <typename Callable>
+ static Function New(napi_env env,
+ Callable cb,
+ const char* utf8name = nullptr,
+ void* data = nullptr);
+ /// Callable must implement operator() accepting a const CallbackInfo&
+ /// and return either void or Value.
+ template <typename Callable>
+ static Function New(napi_env env,
+ Callable cb,
+ const std::string& utf8name,
+ void* data = nullptr);
+
+ Function();
+ Function(napi_env env, napi_value value);
+
+ Value operator ()(const std::initializer_list<napi_value>& args) const;
+
+ Value Call(const std::initializer_list<napi_value>& args) const;
+ Value Call(const std::vector<napi_value>& args) const;
+ Value Call(size_t argc, const napi_value* args) const;
+ Value Call(napi_value recv, const std::initializer_list<napi_value>& args) const;
+ Value Call(napi_value recv, const std::vector<napi_value>& args) const;
+ Value Call(napi_value recv, size_t argc, const napi_value* args) const;
+
+ Value MakeCallback(napi_value recv,
+ const std::initializer_list<napi_value>& args,
+ napi_async_context context = nullptr) const;
+ Value MakeCallback(napi_value recv,
+ const std::vector<napi_value>& args,
+ napi_async_context context = nullptr) const;
+ Value MakeCallback(napi_value recv,
+ size_t argc,
+ const napi_value* args,
+ napi_async_context context = nullptr) const;
+
+ Object New(const std::initializer_list<napi_value>& args) const;
+ Object New(const std::vector<napi_value>& args) const;
+ Object New(size_t argc, const napi_value* args) const;
+ };
+
+ class Promise : public Object {
+ public:
+ class Deferred {
+ public:
+ static Deferred New(napi_env env);
+ Deferred(napi_env env);
+
+ Napi::Promise Promise() const;
+ Napi::Env Env() const;
+
+ void Resolve(napi_value value) const;
+ void Reject(napi_value value) const;
+
+ private:
+ napi_env _env;
+ napi_deferred _deferred;
+ napi_value _promise;
+ };
+
+ Promise(napi_env env, napi_value value);
+ };
+
+ template <typename T>
+ class Buffer : public Uint8Array {
+ public:
+ static Buffer<T> New(napi_env env, size_t length);
+ static Buffer<T> New(napi_env env, T* data, size_t length);
+
+ // Finalizer must implement `void operator()(Env env, T* data)`.
+ template <typename Finalizer>
+ static Buffer<T> New(napi_env env, T* data,
+ size_t length,
+ Finalizer finalizeCallback);
+ // Finalizer must implement `void operator()(Env env, T* data, Hint* hint)`.
+ template <typename Finalizer, typename Hint>
+ static Buffer<T> New(napi_env env, T* data,
+ size_t length,
+ Finalizer finalizeCallback,
+ Hint* finalizeHint);
+
+ static Buffer<T> Copy(napi_env env, const T* data, size_t length);
+
+ Buffer();
+ Buffer(napi_env env, napi_value value);
+ size_t Length() const;
+ T* Data() const;
+
+ private:
+ mutable size_t _length;
+ mutable T* _data;
+
+ Buffer(napi_env env, napi_value value, size_t length, T* data);
+ void EnsureInfo() const;
+ };
+
+ /// Holds a counted reference to a value; initially a weak reference unless otherwise specified,
+ /// may be changed to/from a strong reference by adjusting the refcount.
+ ///
+ /// The referenced value is not immediately destroyed when the reference count is zero; it is
+ /// merely then eligible for garbage-collection if there are no other references to the value.
+ template <typename T>
+ class Reference {
+ public:
+ static Reference<T> New(const T& value, uint32_t initialRefcount = 0);
+
+ Reference();
+ Reference(napi_env env, napi_ref ref);
+ ~Reference();
+
+ // A reference can be moved but cannot be copied.
+ Reference(Reference<T>&& other);
+ Reference<T>& operator =(Reference<T>&& other);
+ Reference<T>& operator =(Reference<T>&) = delete;
+
+ operator napi_ref() const;
+ bool operator ==(const Reference<T> &other) const;
+ bool operator !=(const Reference<T> &other) const;
+
+ Napi::Env Env() const;
+ bool IsEmpty() const;
+
+ // Note when getting the value of a Reference it is usually correct to do so
+ // within a HandleScope so that the value handle gets cleaned up efficiently.
+ T Value() const;
+
+ uint32_t Ref();
+ uint32_t Unref();
+ void Reset();
+ void Reset(const T& value, uint32_t refcount = 0);
+
+ // Call this on a reference that is declared as static data, to prevent its destructor
+ // from running at program shutdown time, which would attempt to reset the reference when
+ // the environment is no longer valid.
+ void SuppressDestruct();
+
+ protected:
+ Reference(const Reference<T>&);
+
+ /// !cond INTERNAL
+ napi_env _env;
+ napi_ref _ref;
+ /// !endcond
+
+ private:
+ bool _suppressDestruct;
+ };
+
+ class ObjectReference: public Reference<Object> {
+ public:
+ ObjectReference();
+ ObjectReference(napi_env env, napi_ref ref);
+
+ // A reference can be moved but cannot be copied.
+ ObjectReference(Reference<Object>&& other);
+ ObjectReference& operator =(Reference<Object>&& other);
+ ObjectReference(ObjectReference&& other);
+ ObjectReference& operator =(ObjectReference&& other);
+ ObjectReference& operator =(ObjectReference&) = delete;
+
+ Napi::Value Get(const char* utf8name) const;
+ Napi::Value Get(const std::string& utf8name) const;
+ void Set(const char* utf8name, napi_value value);
+ void Set(const char* utf8name, Napi::Value value);
+ void Set(const char* utf8name, const char* utf8value);
+ void Set(const char* utf8name, bool boolValue);
+ void Set(const char* utf8name, double numberValue);
+ void Set(const std::string& utf8name, napi_value value);
+ void Set(const std::string& utf8name, Napi::Value value);
+ void Set(const std::string& utf8name, std::string& utf8value);
+ void Set(const std::string& utf8name, bool boolValue);
+ void Set(const std::string& utf8name, double numberValue);
+
+ Napi::Value Get(uint32_t index) const;
+ void Set(uint32_t index, const napi_value value);
+ void Set(uint32_t index, const Napi::Value value);
+ void Set(uint32_t index, const char* utf8value);
+ void Set(uint32_t index, const std::string& utf8value);
+ void Set(uint32_t index, bool boolValue);
+ void Set(uint32_t index, double numberValue);
+
+ protected:
+ ObjectReference(const ObjectReference&);
+ };
+
+ class FunctionReference: public Reference<Function> {
+ public:
+ FunctionReference();
+ FunctionReference(napi_env env, napi_ref ref);
+
+ // A reference can be moved but cannot be copied.
+ FunctionReference(Reference<Function>&& other);
+ FunctionReference& operator =(Reference<Function>&& other);
+ FunctionReference(FunctionReference&& other);
+ FunctionReference& operator =(FunctionReference&& other);
+ FunctionReference(const FunctionReference&) = delete;
+ FunctionReference& operator =(FunctionReference&) = delete;
+
+ Napi::Value operator ()(const std::initializer_list<napi_value>& args) const;
+
+ Napi::Value Call(const std::initializer_list<napi_value>& args) const;
+ Napi::Value Call(const std::vector<napi_value>& args) const;
+ Napi::Value Call(napi_value recv, const std::initializer_list<napi_value>& args) const;
+ Napi::Value Call(napi_value recv, const std::vector<napi_value>& args) const;
+ Napi::Value Call(napi_value recv, size_t argc, const napi_value* args) const;
+
+ Napi::Value MakeCallback(napi_value recv,
+ const std::initializer_list<napi_value>& args,
+ napi_async_context context = nullptr) const;
+ Napi::Value MakeCallback(napi_value recv,
+ const std::vector<napi_value>& args,
+ napi_async_context context = nullptr) const;
+ Napi::Value MakeCallback(napi_value recv,
+ size_t argc,
+ const napi_value* args,
+ napi_async_context context = nullptr) const;
+
+ Object New(const std::initializer_list<napi_value>& args) const;
+ Object New(const std::vector<napi_value>& args) const;
+ };
+
+ // Shortcuts to creating a new reference with inferred type and refcount = 0.
+ template <typename T> Reference<T> Weak(T value);
+ ObjectReference Weak(Object value);
+ FunctionReference Weak(Function value);
+
+ // Shortcuts to creating a new reference with inferred type and refcount = 1.
+ template <typename T> Reference<T> Persistent(T value);
+ ObjectReference Persistent(Object value);
+ FunctionReference Persistent(Function value);
+
+ /// A persistent reference to a JavaScript error object. Use of this class depends somewhat
+ /// on whether C++ exceptions are enabled at compile time.
+ ///
+ /// ### Handling Errors With C++ Exceptions
+ ///
+ /// If C++ exceptions are enabled, then the `Error` class extends `std::exception` and enables
+ /// integrated error-handling for C++ exceptions and JavaScript exceptions.
+ ///
+ /// If a N-API call fails without executing any JavaScript code (for example due to an invalid
+ /// argument), then the N-API wrapper automatically converts and throws the error as a C++
+ /// exception of type `Napi::Error`. Or if a JavaScript function called by C++ code via N-API
+ /// throws a JavaScript exception, then the N-API wrapper automatically converts and throws it as
+ /// a C++ exception of type `Napi::Error`.
+ ///
+ /// If a C++ exception of type `Napi::Error` escapes from a N-API C++ callback, then the N-API
+ /// wrapper automatically converts and throws it as a JavaScript exception. Therefore, catching
+ /// a C++ exception of type `Napi::Error` prevents a JavaScript exception from being thrown.
+ ///
+ /// #### Example 1A - Throwing a C++ exception:
+ ///
+ /// Napi::Env env = ...
+ /// throw Napi::Error::New(env, "Example exception");
+ ///
+ /// Following C++ statements will not be executed. The exception will bubble up as a C++
+ /// exception of type `Napi::Error`, until it is either caught while still in C++, or else
+ /// automatically propataged as a JavaScript exception when the callback returns to JavaScript.
+ ///
+ /// #### Example 2A - Propagating a N-API C++ exception:
+ ///
+ /// Napi::Function jsFunctionThatThrows = someObj.As<Napi::Function>();
+ /// Napi::Value result = jsFunctionThatThrows({ arg1, arg2 });
+ ///
+ /// Following C++ statements will not be executed. The exception will bubble up as a C++
+ /// exception of type `Napi::Error`, until it is either caught while still in C++, or else
+ /// automatically propagated as a JavaScript exception when the callback returns to JavaScript.
+ ///
+ /// #### Example 3A - Handling a N-API C++ exception:
+ ///
+ /// Napi::Function jsFunctionThatThrows = someObj.As<Napi::Function>();
+ /// Napi::Value result;
+ /// try {
+ /// result = jsFunctionThatThrows({ arg1, arg2 });
+ /// } catch (const Napi::Error& e) {
+ /// cerr << "Caught JavaScript exception: " + e.what();
+ /// }
+ ///
+ /// Since the exception was caught here, it will not be propagated as a JavaScript exception.
+ ///
+ /// ### Handling Errors Without C++ Exceptions
+ ///
+ /// If C++ exceptions are disabled (by defining `NAPI_DISABLE_CPP_EXCEPTIONS`) then this class
+ /// does not extend `std::exception`, and APIs in the `Napi` namespace do not throw C++
+ /// exceptions when they fail. Instead, they raise _pending_ JavaScript exceptions and
+ /// return _empty_ `Value`s. Calling code should check `Value::IsEmpty()` before attempting
+ /// to use a returned value, and may use methods on the `Env` class to check for, get, and
+ /// clear a pending JavaScript exception. If the pending exception is not cleared, it will
+ /// be thrown when the native callback returns to JavaScript.
+ ///
+ /// #### Example 1B - Throwing a JS exception
+ ///
+ /// Napi::Env env = ...
+ /// Napi::Error::New(env, "Example exception").ThrowAsJavaScriptException();
+ /// return;
+ ///
+ /// After throwing a JS exception, the code should generally return immediately from the native
+ /// callback, after performing any necessary cleanup.
+ ///
+ /// #### Example 2B - Propagating a N-API JS exception:
+ ///
+ /// Napi::Function jsFunctionThatThrows = someObj.As<Napi::Function>();
+ /// Napi::Value result = jsFunctionThatThrows({ arg1, arg2 });
+ /// if (result.IsEmpty()) return;
+ ///
+ /// An empty value result from a N-API call indicates an error occurred, and a JavaScript
+ /// exception is pending. To let the exception propagate, the code should generally return
+ /// immediately from the native callback, after performing any necessary cleanup.
+ ///
+ /// #### Example 3B - Handling a N-API JS exception:
+ ///
+ /// Napi::Function jsFunctionThatThrows = someObj.As<Napi::Function>();
+ /// Napi::Value result = jsFunctionThatThrows({ arg1, arg2 });
+ /// if (result.IsEmpty()) {
+ /// Napi::Error e = env.GetAndClearPendingException();
+ /// cerr << "Caught JavaScript exception: " + e.Message();
+ /// }
+ ///
+ /// Since the exception was cleared here, it will not be propagated as a JavaScript exception
+ /// after the native callback returns.
+ class Error : public ObjectReference
+#ifdef NAPI_CPP_EXCEPTIONS
+ , public std::exception
+#endif // NAPI_CPP_EXCEPTIONS
+ {
+ public:
+ static Error New(napi_env env);
+ static Error New(napi_env env, const char* message);
+ static Error New(napi_env env, const std::string& message);
+
+ static NAPI_NO_RETURN void Fatal(const char* location, const char* message);
+
+ Error();
+ Error(napi_env env, napi_value value);
+
+ // An error can be moved or copied.
+ Error(Error&& other);
+ Error& operator =(Error&& other);
+ Error(const Error&);
+ Error& operator =(Error&);
+
+ const std::string& Message() const NAPI_NOEXCEPT;
+ void ThrowAsJavaScriptException() const;
+
+#ifdef NAPI_CPP_EXCEPTIONS
+ const char* what() const NAPI_NOEXCEPT override;
+#endif // NAPI_CPP_EXCEPTIONS
+
+ protected:
+ /// !cond INTERNAL
+ typedef napi_status (*create_error_fn)(napi_env envb, napi_value code, napi_value msg, napi_value* result);
+
+ template <typename TError>
+ static TError New(napi_env env,
+ const char* message,
+ size_t length,
+ create_error_fn create_error);
+ /// !endcond
+
+ private:
+ mutable std::string _message;
+ };
+
+ class TypeError : public Error {
+ public:
+ static TypeError New(napi_env env, const char* message);
+ static TypeError New(napi_env env, const std::string& message);
+
+ TypeError();
+ TypeError(napi_env env, napi_value value);
+ };
+
+ class RangeError : public Error {
+ public:
+ static RangeError New(napi_env env, const char* message);
+ static RangeError New(napi_env env, const std::string& message);
+
+ RangeError();
+ RangeError(napi_env env, napi_value value);
+ };
+
+ class CallbackInfo {
+ public:
+ CallbackInfo(napi_env env, napi_callback_info info);
+ ~CallbackInfo();
+
+ // Disallow copying to prevent multiple free of _dynamicArgs
+ CallbackInfo(CallbackInfo const &) = delete;
+ void operator=(CallbackInfo const &) = delete;
+
+ Napi::Env Env() const;
+ Value NewTarget() const;
+ bool IsConstructCall() const;
+ size_t Length() const;
+ const Value operator [](size_t index) const;
+ Value This() const;
+ void* Data() const;
+ void SetData(void* data);
+
+ private:
+ const size_t _staticArgCount = 6;
+ napi_env _env;
+ napi_callback_info _info;
+ napi_value _this;
+ size_t _argc;
+ napi_value* _argv;
+ napi_value _staticArgs[6];
+ napi_value* _dynamicArgs;
+ void* _data;
+ };
+
+ class PropertyDescriptor {
+ public:
+#ifndef NODE_ADDON_API_DISABLE_DEPRECATED
+ template <typename Getter>
+ static PropertyDescriptor Accessor(const char* utf8name,
+ Getter getter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Getter>
+ static PropertyDescriptor Accessor(const std::string& utf8name,
+ Getter getter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Getter>
+ static PropertyDescriptor Accessor(napi_value name,
+ Getter getter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Getter>
+ static PropertyDescriptor Accessor(Name name,
+ Getter getter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Getter, typename Setter>
+ static PropertyDescriptor Accessor(const char* utf8name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Getter, typename Setter>
+ static PropertyDescriptor Accessor(const std::string& utf8name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Getter, typename Setter>
+ static PropertyDescriptor Accessor(napi_value name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Getter, typename Setter>
+ static PropertyDescriptor Accessor(Name name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Callable>
+ static PropertyDescriptor Function(const char* utf8name,
+ Callable cb,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Callable>
+ static PropertyDescriptor Function(const std::string& utf8name,
+ Callable cb,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Callable>
+ static PropertyDescriptor Function(napi_value name,
+ Callable cb,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Callable>
+ static PropertyDescriptor Function(Name name,
+ Callable cb,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+#endif // !NODE_ADDON_API_DISABLE_DEPRECATED
+
+ template <typename Getter>
+ static PropertyDescriptor Accessor(Napi::Env env,
+ Napi::Object object,
+ const char* utf8name,
+ Getter getter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Getter>
+ static PropertyDescriptor Accessor(Napi::Env env,
+ Napi::Object object,
+ const std::string& utf8name,
+ Getter getter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Getter>
+ static PropertyDescriptor Accessor(Napi::Env env,
+ Napi::Object object,
+ Name name,
+ Getter getter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Getter, typename Setter>
+ static PropertyDescriptor Accessor(Napi::Env env,
+ Napi::Object object,
+ const char* utf8name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Getter, typename Setter>
+ static PropertyDescriptor Accessor(Napi::Env env,
+ Napi::Object object,
+ const std::string& utf8name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Getter, typename Setter>
+ static PropertyDescriptor Accessor(Napi::Env env,
+ Napi::Object object,
+ Name name,
+ Getter getter,
+ Setter setter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Callable>
+ static PropertyDescriptor Function(Napi::Env env,
+ Napi::Object object,
+ const char* utf8name,
+ Callable cb,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Callable>
+ static PropertyDescriptor Function(Napi::Env env,
+ Napi::Object object,
+ const std::string& utf8name,
+ Callable cb,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ template <typename Callable>
+ static PropertyDescriptor Function(Napi::Env env,
+ Napi::Object object,
+ Name name,
+ Callable cb,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ static PropertyDescriptor Value(const char* utf8name,
+ napi_value value,
+ napi_property_attributes attributes = napi_default);
+ static PropertyDescriptor Value(const std::string& utf8name,
+ napi_value value,
+ napi_property_attributes attributes = napi_default);
+ static PropertyDescriptor Value(napi_value name,
+ napi_value value,
+ napi_property_attributes attributes = napi_default);
+ static PropertyDescriptor Value(Name name,
+ Napi::Value value,
+ napi_property_attributes attributes = napi_default);
+
+ PropertyDescriptor(napi_property_descriptor desc);
+
+ operator napi_property_descriptor&();
+ operator const napi_property_descriptor&() const;
+
+ private:
+ napi_property_descriptor _desc;
+ };
+
+ /// Property descriptor for use with `ObjectWrap::DefineClass()`.
+ ///
+ /// This is different from the standalone `PropertyDescriptor` because it is specific to each
+ /// `ObjectWrap<T>` subclass. This prevents using descriptors from a different class when
+ /// defining a new class (preventing the callbacks from having incorrect `this` pointers).
+ template <typename T>
+ class ClassPropertyDescriptor {
+ public:
+ ClassPropertyDescriptor(napi_property_descriptor desc) : _desc(desc) {}
+
+ operator napi_property_descriptor&() { return _desc; }
+ operator const napi_property_descriptor&() const { return _desc; }
+
+ private:
+ napi_property_descriptor _desc;
+ };
+
+ /// Base class to be extended by C++ classes exposed to JavaScript; each C++ class instance gets
+ /// "wrapped" by a JavaScript object that is managed by this class.
+ ///
+ /// At initialization time, the `DefineClass()` method must be used to
+ /// hook up the accessor and method callbacks. It takes a list of
+ /// property descriptors, which can be constructed via the various
+ /// static methods on the base class.
+ ///
+ /// #### Example:
+ ///
+ /// class Example: public Napi::ObjectWrap<Example> {
+ /// public:
+ /// static void Initialize(Napi::Env& env, Napi::Object& target) {
+ /// Napi::Function constructor = DefineClass(env, "Example", {
+ /// InstanceAccessor("value", &Example::GetSomething, &Example::SetSomething),
+ /// InstanceMethod("doSomething", &Example::DoSomething),
+ /// });
+ /// target.Set("Example", constructor);
+ /// }
+ ///
+ /// Example(const Napi::CallbackInfo& info); // Constructor
+ /// Napi::Value GetSomething(const Napi::CallbackInfo& info);
+ /// void SetSomething(const Napi::CallbackInfo& info, const Napi::Value& value);
+ /// Napi::Value DoSomething(const Napi::CallbackInfo& info);
+ /// }
+ template <typename T>
+ class ObjectWrap : public Reference<Object> {
+ public:
+ ObjectWrap(const CallbackInfo& callbackInfo);
+ virtual ~ObjectWrap();
+
+ static T* Unwrap(Object wrapper);
+
+ // Methods exposed to JavaScript must conform to one of these callback signatures.
+ typedef void (*StaticVoidMethodCallback)(const CallbackInfo& info);
+ typedef Napi::Value (*StaticMethodCallback)(const CallbackInfo& info);
+ typedef Napi::Value (*StaticGetterCallback)(const CallbackInfo& info);
+ typedef void (*StaticSetterCallback)(const CallbackInfo& info, const Napi::Value& value);
+ typedef void (T::*InstanceVoidMethodCallback)(const CallbackInfo& info);
+ typedef Napi::Value (T::*InstanceMethodCallback)(const CallbackInfo& info);
+ typedef Napi::Value (T::*InstanceGetterCallback)(const CallbackInfo& info);
+ typedef void (T::*InstanceSetterCallback)(const CallbackInfo& info, const Napi::Value& value);
+
+ typedef ClassPropertyDescriptor<T> PropertyDescriptor;
+
+ static Function DefineClass(Napi::Env env,
+ const char* utf8name,
+ const std::initializer_list<PropertyDescriptor>& properties,
+ void* data = nullptr);
+ static Function DefineClass(Napi::Env env,
+ const char* utf8name,
+ const std::vector<PropertyDescriptor>& properties,
+ void* data = nullptr);
+ static PropertyDescriptor StaticMethod(const char* utf8name,
+ StaticVoidMethodCallback method,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ static PropertyDescriptor StaticMethod(const char* utf8name,
+ StaticMethodCallback method,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ static PropertyDescriptor StaticMethod(Symbol name,
+ StaticVoidMethodCallback method,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ static PropertyDescriptor StaticMethod(Symbol name,
+ StaticMethodCallback method,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ static PropertyDescriptor StaticAccessor(const char* utf8name,
+ StaticGetterCallback getter,
+ StaticSetterCallback setter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ static PropertyDescriptor StaticAccessor(Symbol name,
+ StaticGetterCallback getter,
+ StaticSetterCallback setter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ static PropertyDescriptor InstanceMethod(const char* utf8name,
+ InstanceVoidMethodCallback method,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ static PropertyDescriptor InstanceMethod(const char* utf8name,
+ InstanceMethodCallback method,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ static PropertyDescriptor InstanceMethod(Symbol name,
+ InstanceVoidMethodCallback method,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ static PropertyDescriptor InstanceMethod(Symbol name,
+ InstanceMethodCallback method,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ static PropertyDescriptor InstanceAccessor(const char* utf8name,
+ InstanceGetterCallback getter,
+ InstanceSetterCallback setter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ static PropertyDescriptor InstanceAccessor(Symbol name,
+ InstanceGetterCallback getter,
+ InstanceSetterCallback setter,
+ napi_property_attributes attributes = napi_default,
+ void* data = nullptr);
+ static PropertyDescriptor StaticValue(const char* utf8name,
+ Napi::Value value,
+ napi_property_attributes attributes = napi_default);
+ static PropertyDescriptor StaticValue(Symbol name,
+ Napi::Value value,
+ napi_property_attributes attributes = napi_default);
+ static PropertyDescriptor InstanceValue(const char* utf8name,
+ Napi::Value value,
+ napi_property_attributes attributes = napi_default);
+ static PropertyDescriptor InstanceValue(Symbol name,
+ Napi::Value value,
+ napi_property_attributes attributes = napi_default);
+ virtual void Finalize(Napi::Env env);
+
+ private:
+ static napi_value ConstructorCallbackWrapper(napi_env env, napi_callback_info info);
+ static napi_value StaticVoidMethodCallbackWrapper(napi_env env, napi_callback_info info);
+ static napi_value StaticMethodCallbackWrapper(napi_env env, napi_callback_info info);
+ static napi_value StaticGetterCallbackWrapper(napi_env env, napi_callback_info info);
+ static napi_value StaticSetterCallbackWrapper(napi_env env, napi_callback_info info);
+ static napi_value InstanceVoidMethodCallbackWrapper(napi_env env, napi_callback_info info);
+ static napi_value InstanceMethodCallbackWrapper(napi_env env, napi_callback_info info);
+ static napi_value InstanceGetterCallbackWrapper(napi_env env, napi_callback_info info);
+ static napi_value InstanceSetterCallbackWrapper(napi_env env, napi_callback_info info);
+ static void FinalizeCallback(napi_env env, void* data, void* hint);
+ static Function DefineClass(Napi::Env env,
+ const char* utf8name,
+ const size_t props_count,
+ const napi_property_descriptor* props,
+ void* data = nullptr);
+
+ template <typename TCallback>
+ struct MethodCallbackData {
+ TCallback callback;
+ void* data;
+ };
+ typedef MethodCallbackData<StaticVoidMethodCallback> StaticVoidMethodCallbackData;
+ typedef MethodCallbackData<StaticMethodCallback> StaticMethodCallbackData;
+ typedef MethodCallbackData<InstanceVoidMethodCallback> InstanceVoidMethodCallbackData;
+ typedef MethodCallbackData<InstanceMethodCallback> InstanceMethodCallbackData;
+
+ template <typename TGetterCallback, typename TSetterCallback>
+ struct AccessorCallbackData {
+ TGetterCallback getterCallback;
+ TSetterCallback setterCallback;
+ void* data;
+ };
+ typedef AccessorCallbackData<StaticGetterCallback, StaticSetterCallback>
+ StaticAccessorCallbackData;
+ typedef AccessorCallbackData<InstanceGetterCallback, InstanceSetterCallback>
+ InstanceAccessorCallbackData;
+ };
+
+ class HandleScope {
+ public:
+ HandleScope(napi_env env, napi_handle_scope scope);
+ explicit HandleScope(Napi::Env env);
+ ~HandleScope();
+
+ // Disallow copying to prevent double close of napi_handle_scope
+ HandleScope(HandleScope const &) = delete;
+ void operator=(HandleScope const &) = delete;
+
+ operator napi_handle_scope() const;
+
+ Napi::Env Env() const;
+
+ private:
+ napi_env _env;
+ napi_handle_scope _scope;
+ };
+
+ class EscapableHandleScope {
+ public:
+ EscapableHandleScope(napi_env env, napi_escapable_handle_scope scope);
+ explicit EscapableHandleScope(Napi::Env env);
+ ~EscapableHandleScope();
+
+ // Disallow copying to prevent double close of napi_escapable_handle_scope
+ EscapableHandleScope(EscapableHandleScope const &) = delete;
+ void operator=(EscapableHandleScope const &) = delete;
+
+ operator napi_escapable_handle_scope() const;
+
+ Napi::Env Env() const;
+ Value Escape(napi_value escapee);
+
+ private:
+ napi_env _env;
+ napi_escapable_handle_scope _scope;
+ };
+
+#if (NAPI_VERSION > 2)
+ class CallbackScope {
+ public:
+ CallbackScope(napi_env env, napi_callback_scope scope);
+ CallbackScope(napi_env env, napi_async_context context);
+ virtual ~CallbackScope();
+
+ // Disallow copying to prevent double close of napi_callback_scope
+ CallbackScope(CallbackScope const &) = delete;
+ void operator=(CallbackScope const &) = delete;
+
+ operator napi_callback_scope() const;
+
+ Napi::Env Env() const;
+
+ private:
+ napi_env _env;
+ napi_callback_scope _scope;
+ };
+#endif
+
+ class AsyncContext {
+ public:
+ explicit AsyncContext(napi_env env, const char* resource_name);
+ explicit AsyncContext(napi_env env, const char* resource_name, const Object& resource);
+ virtual ~AsyncContext();
+
+ AsyncContext(AsyncContext&& other);
+ AsyncContext& operator =(AsyncContext&& other);
+ AsyncContext(const AsyncContext&) = delete;
+ AsyncContext& operator =(AsyncContext&) = delete;
+
+ operator napi_async_context() const;
+
+ Napi::Env Env() const;
+
+ private:
+ napi_env _env;
+ napi_async_context _context;
+ };
+
+ class AsyncWorker {
+ public:
+ virtual ~AsyncWorker();
+
+ // An async worker can be moved but cannot be copied.
+ AsyncWorker(AsyncWorker&& other);
+ AsyncWorker& operator =(AsyncWorker&& other);
+ AsyncWorker(const AsyncWorker&) = delete;
+ AsyncWorker& operator =(AsyncWorker&) = delete;
+
+ operator napi_async_work() const;
+
+ Napi::Env Env() const;
+
+ void Queue();
+ void Cancel();
+ void SuppressDestruct();
+
+ ObjectReference& Receiver();
+ FunctionReference& Callback();
+
+ protected:
+ explicit AsyncWorker(const Function& callback);
+ explicit AsyncWorker(const Function& callback,
+ const char* resource_name);
+ explicit AsyncWorker(const Function& callback,
+ const char* resource_name,
+ const Object& resource);
+ explicit AsyncWorker(const Object& receiver,
+ const Function& callback);
+ explicit AsyncWorker(const Object& receiver,
+ const Function& callback,
+ const char* resource_name);
+ explicit AsyncWorker(const Object& receiver,
+ const Function& callback,
+ const char* resource_name,
+ const Object& resource);
+
+ explicit AsyncWorker(Napi::Env env);
+ explicit AsyncWorker(Napi::Env env,
+ const char* resource_name);
+ explicit AsyncWorker(Napi::Env env,
+ const char* resource_name,
+ const Object& resource);
+
+ virtual void Execute() = 0;
+ virtual void OnOK();
+ virtual void OnError(const Error& e);
+ virtual void Destroy();
+ virtual std::vector<napi_value> GetResult(Napi::Env env);
+
+ void SetError(const std::string& error);
+
+ private:
+ static void OnExecute(napi_env env, void* this_pointer);
+ static void OnWorkComplete(napi_env env,
+ napi_status status,
+ void* this_pointer);
+
+ napi_env _env;
+ napi_async_work _work;
+ ObjectReference _receiver;
+ FunctionReference _callback;
+ std::string _error;
+ bool _suppress_destruct;
+ };
+
+ #if (NAPI_VERSION > 3)
+ class ThreadSafeFunction {
+ public:
+ // This API may only be called from the main thread.
+ template <typename ResourceString>
+ static ThreadSafeFunction New(napi_env env,
+ const Function& callback,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount);
+
+ // This API may only be called from the main thread.
+ template <typename ResourceString, typename ContextType>
+ static ThreadSafeFunction New(napi_env env,
+ const Function& callback,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context);
+
+ // This API may only be called from the main thread.
+ template <typename ResourceString, typename Finalizer>
+ static ThreadSafeFunction New(napi_env env,
+ const Function& callback,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ Finalizer finalizeCallback);
+
+ // This API may only be called from the main thread.
+ template <typename ResourceString, typename Finalizer,
+ typename FinalizerDataType>
+ static ThreadSafeFunction New(napi_env env,
+ const Function& callback,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ Finalizer finalizeCallback,
+ FinalizerDataType* data);
+
+ // This API may only be called from the main thread.
+ template <typename ResourceString, typename ContextType, typename Finalizer>
+ static ThreadSafeFunction New(napi_env env,
+ const Function& callback,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context,
+ Finalizer finalizeCallback);
+
+ // This API may only be called from the main thread.
+ template <typename ResourceString, typename ContextType,
+ typename Finalizer, typename FinalizerDataType>
+ static ThreadSafeFunction New(napi_env env,
+ const Function& callback,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context,
+ Finalizer finalizeCallback,
+ FinalizerDataType* data);
+
+ // This API may only be called from the main thread.
+ template <typename ResourceString>
+ static ThreadSafeFunction New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount);
+
+ // This API may only be called from the main thread.
+ template <typename ResourceString, typename ContextType>
+ static ThreadSafeFunction New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context);
+
+ // This API may only be called from the main thread.
+ template <typename ResourceString, typename Finalizer>
+ static ThreadSafeFunction New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ Finalizer finalizeCallback);
+
+ // This API may only be called from the main thread.
+ template <typename ResourceString, typename Finalizer,
+ typename FinalizerDataType>
+ static ThreadSafeFunction New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ Finalizer finalizeCallback,
+ FinalizerDataType* data);
+
+ // This API may only be called from the main thread.
+ template <typename ResourceString, typename ContextType, typename Finalizer>
+ static ThreadSafeFunction New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context,
+ Finalizer finalizeCallback);
+
+ // This API may only be called from the main thread.
+ template <typename ResourceString, typename ContextType,
+ typename Finalizer, typename FinalizerDataType>
+ static ThreadSafeFunction New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context,
+ Finalizer finalizeCallback,
+ FinalizerDataType* data);
+
+ ThreadSafeFunction();
+ ThreadSafeFunction(napi_threadsafe_function tsFunctionValue);
+
+ operator napi_threadsafe_function() const;
+
+ // This API may be called from any thread.
+ napi_status BlockingCall() const;
+
+ // This API may be called from any thread.
+ template <typename Callback>
+ napi_status BlockingCall(Callback callback) const;
+
+ // This API may be called from any thread.
+ template <typename DataType, typename Callback>
+ napi_status BlockingCall(DataType* data, Callback callback) const;
+
+ // This API may be called from any thread.
+ napi_status NonBlockingCall() const;
+
+ // This API may be called from any thread.
+ template <typename Callback>
+ napi_status NonBlockingCall(Callback callback) const;
+
+ // This API may be called from any thread.
+ template <typename DataType, typename Callback>
+ napi_status NonBlockingCall(DataType* data, Callback callback) const;
+
+ // This API may only be called from the main thread.
+ void Ref(napi_env env) const;
+
+ // This API may only be called from the main thread.
+ void Unref(napi_env env) const;
+
+ // This API may be called from any thread.
+ napi_status Acquire() const;
+
+ // This API may be called from any thread.
+ napi_status Release();
+
+ // This API may be called from any thread.
+ napi_status Abort();
+
+ struct ConvertibleContext
+ {
+ template <class T>
+ operator T*() { return static_cast<T*>(context); }
+ void* context;
+ };
+
+ // This API may be called from any thread.
+ ConvertibleContext GetContext() const;
+
+ private:
+ using CallbackWrapper = std::function<void(Napi::Env, Napi::Function)>;
+
+ template <typename ResourceString, typename ContextType,
+ typename Finalizer, typename FinalizerDataType>
+ static ThreadSafeFunction New(napi_env env,
+ const Function& callback,
+ const Object& resource,
+ ResourceString resourceName,
+ size_t maxQueueSize,
+ size_t initialThreadCount,
+ ContextType* context,
+ Finalizer finalizeCallback,
+ FinalizerDataType* data,
+ napi_finalize wrapper);
+
+ napi_status CallInternal(CallbackWrapper* callbackWrapper,
+ napi_threadsafe_function_call_mode mode) const;
+
+ static void CallJS(napi_env env,
+ napi_value jsCallback,
+ void* context,
+ void* data);
+
+ napi_threadsafe_function _tsfn;
+ };
+
+ template<class T>
+ class AsyncProgressWorker : public AsyncWorker {
+ public:
+ virtual ~AsyncProgressWorker();
+
+ class ExecutionProgress {
+ friend class AsyncProgressWorker;
+ public:
+ void Signal() const;
+ void Send(const T* data, size_t count) const;
+ private:
+ explicit ExecutionProgress(AsyncProgressWorker* worker) : _worker(worker) {}
+ AsyncProgressWorker* const _worker;
+ };
+
+ protected:
+ explicit AsyncProgressWorker(const Function& callback);
+ explicit AsyncProgressWorker(const Function& callback,
+ const char* resource_name);
+ explicit AsyncProgressWorker(const Function& callback,
+ const char* resource_name,
+ const Object& resource);
+ explicit AsyncProgressWorker(const Object& receiver,
+ const Function& callback);
+ explicit AsyncProgressWorker(const Object& receiver,
+ const Function& callback,
+ const char* resource_name);
+ explicit AsyncProgressWorker(const Object& receiver,
+ const Function& callback,
+ const char* resource_name,
+ const Object& resource);
+
+// Optional callback of Napi::ThreadSafeFunction only available after NAPI_VERSION 4.
+// Refs: https://github.com/nodejs/node/pull/27791
+#if NAPI_VERSION > 4
+ explicit AsyncProgressWorker(Napi::Env env);
+ explicit AsyncProgressWorker(Napi::Env env,
+ const char* resource_name);
+ explicit AsyncProgressWorker(Napi::Env env,
+ const char* resource_name,
+ const Object& resource);
+#endif
+
+ virtual void Execute(const ExecutionProgress& progress) = 0;
+ virtual void OnProgress(const T* data, size_t count) = 0;
+
+ private:
+ static void WorkProgress_(Napi::Env env, Napi::Function jsCallback, void* data);
+
+ void Execute() override;
+ void Signal() const;
+ void SendProgress_(const T* data, size_t count);
+
+ std::mutex _mutex;
+ T* _asyncdata;
+ size_t _asyncsize;
+ ThreadSafeFunction _tsfn;
+ };
+ #endif
+
+ // Memory management.
+ class MemoryManagement {
+ public:
+ static int64_t AdjustExternalMemory(Env env, int64_t change_in_bytes);
+ };
+
+ // Version management
+ class VersionManagement {
+ public:
+ static uint32_t GetNapiVersion(Env env);
+ static const napi_node_version* GetNodeVersion(Env env);
+ };
+
+} // namespace Napi
+
+// Inline implementations of all the above class methods are included here.
+#include "napi-inl.h"
+
+#endif // SRC_NAPI_H_
diff --git a/debian/build_modules/node-addon-api/package.json b/debian/build_modules/node-addon-api/package.json
new file mode 100644
index 0000000..a23f6e8
--- /dev/null
+++ b/debian/build_modules/node-addon-api/package.json
@@ -0,0 +1,268 @@
+{
+ "_from": "node-addon-api@2.0.0",
+ "_id": "node-addon-api@2.0.0",
+ "_inBundle": false,
+ "_integrity": "sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA==",
+ "_location": "/node-addon-api",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "version",
+ "registry": true,
+ "raw": "node-addon-api@2.0.0",
+ "name": "node-addon-api",
+ "escapedName": "node-addon-api",
+ "rawSpec": "2.0.0",
+ "saveSpec": null,
+ "fetchSpec": "2.0.0"
+ },
+ "_requiredBy": [
+ "/"
+ ],
+ "_resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.0.tgz",
+ "_shasum": "f9afb8d777a91525244b01775ea0ddbe1125483b",
+ "_spec": "node-addon-api@2.0.0",
+ "_where": "/home/xavier/dev/debian/src/pkg-js/packages/node-sqlite3",
+ "bugs": {
+ "url": "https://github.com/nodejs/node-addon-api/issues"
+ },
+ "bundleDependencies": false,
+ "contributors": [
+ {
+ "name": "Abhishek Kumar Singh",
+ "url": "https://github.com/abhi11210646"
+ },
+ {
+ "name": "Alba Mendez",
+ "url": "https://github.com/jmendeth"
+ },
+ {
+ "name": "Andrew Petersen",
+ "url": "https://github.com/kirbysayshi"
+ },
+ {
+ "name": "Anisha Rohra",
+ "url": "https://github.com/anisha-rohra"
+ },
+ {
+ "name": "Anna Henningsen",
+ "url": "https://github.com/addaleax"
+ },
+ {
+ "name": "Arnaud Botella",
+ "url": "https://github.com/BotellaA"
+ },
+ {
+ "name": "Arunesh Chandra",
+ "url": "https://github.com/aruneshchandra"
+ },
+ {
+ "name": "Ben Berman",
+ "url": "https://github.com/rivertam"
+ },
+ {
+ "name": "Benjamin Byholm",
+ "url": "https://github.com/kkoopa"
+ },
+ {
+ "name": "Bill Gallafent",
+ "url": "https://github.com/gallafent"
+ },
+ {
+ "name": "Bruce A. MacNaughton",
+ "url": "https://github.com/bmacnaughton"
+ },
+ {
+ "name": "Cory Mickelson",
+ "url": "https://github.com/corymickelson"
+ },
+ {
+ "name": "David Halls",
+ "url": "https://github.com/davedoesdev"
+ },
+ {
+ "name": "Dongjin Na",
+ "url": "https://github.com/nadongguri"
+ },
+ {
+ "name": "Eric Bickle",
+ "url": "https://github.com/ebickle"
+ },
+ {
+ "name": "Gabriel Schulhof",
+ "url": "https://github.com/gabrielschulhof"
+ },
+ {
+ "name": "Gus Caplan",
+ "url": "https://github.com/devsnek"
+ },
+ {
+ "name": "Hitesh Kanwathirtha",
+ "url": "https://github.com/digitalinfinity"
+ },
+ {
+ "name": "Jake Barnes",
+ "url": "https://github.com/DuBistKomisch"
+ },
+ {
+ "name": "Jake Yoon",
+ "url": "https://github.com/yjaeseok"
+ },
+ {
+ "name": "Jason Ginchereau",
+ "url": "https://github.com/jasongin"
+ },
+ {
+ "name": "Jim Schlight",
+ "url": "https://github.com/jschlight"
+ },
+ {
+ "name": "Jinho Bang",
+ "url": "https://github.com/romandev"
+ },
+ {
+ "name": "joshgarde",
+ "url": "https://github.com/joshgarde"
+ },
+ {
+ "name": "Kevin Eady",
+ "url": "https://github.com/KevinEady"
+ },
+ {
+ "name": "Konstantin Tarkus",
+ "url": "https://github.com/koistya"
+ },
+ {
+ "name": "Kyle Farnung",
+ "url": "https://github.com/kfarnung"
+ },
+ {
+ "name": "legendecas",
+ "url": "https://github.com/legendecas"
+ },
+ {
+ "name": "Luciano Martorella",
+ "url": "https://github.com/lmartorella"
+ },
+ {
+ "name": "Mathias Küsel",
+ "url": "https://github.com/mathiask88"
+ },
+ {
+ "name": "Matteo Collina",
+ "url": "https://github.com/mcollina"
+ },
+ {
+ "name": "Michael Dawson",
+ "url": "https://github.com/mhdawson"
+ },
+ {
+ "name": "Michael Price",
+ "url": "https://github.com/mikepricedev"
+ },
+ {
+ "name": "Michele Campus",
+ "url": "https://github.com/kYroL01"
+ },
+ {
+ "name": "Mikhail Cheshkov",
+ "url": "https://github.com/mcheshkov"
+ },
+ {
+ "name": "Nicola Del Gobbo",
+ "url": "https://github.com/NickNaso"
+ },
+ {
+ "name": "Nick Soggin",
+ "url": "https://github.com/iSkore"
+ },
+ {
+ "name": "Nurbol Alpysbayev",
+ "url": "https://github.com/anurbol"
+ },
+ {
+ "name": "Philipp Renoth",
+ "url": "https://github.com/DaAitch"
+ },
+ {
+ "name": "Rolf Timmermans",
+ "url": "https://github.com/rolftimmermans"
+ },
+ {
+ "name": "Ross Weir",
+ "url": "https://github.com/ross-weir"
+ },
+ {
+ "name": "Ryuichi Okumura",
+ "url": "https://github.com/okuryu"
+ },
+ {
+ "name": "Sampson Gao",
+ "url": "https://github.com/sampsongao"
+ },
+ {
+ "name": "Sam Roberts",
+ "url": "https://github.com/sam-github"
+ },
+ {
+ "name": "Taylor Woll",
+ "url": "https://github.com/boingoing"
+ },
+ {
+ "name": "Thomas Gentilhomme",
+ "url": "https://github.com/fraxken"
+ },
+ {
+ "name": "Tim Rach",
+ "url": "https://github.com/timrach"
+ },
+ {
+ "name": "Tobias Nießen",
+ "url": "https://github.com/tniessen"
+ },
+ {
+ "name": "Tux3",
+ "url": "https://github.com/tux3"
+ },
+ {
+ "name": "Yohei Kishimoto",
+ "url": "https://github.com/morokosi"
+ }
+ ],
+ "dependencies": {},
+ "deprecated": false,
+ "description": "Node.js API (N-API)",
+ "devDependencies": {
+ "safe-buffer": "^5.1.1"
+ },
+ "directories": {},
+ "homepage": "https://github.com/nodejs/node-addon-api",
+ "keywords": [
+ "n-api",
+ "napi",
+ "addon",
+ "native",
+ "bindings",
+ "c",
+ "c++",
+ "nan",
+ "node-addon-api"
+ ],
+ "license": "MIT",
+ "main": "index.js",
+ "name": "node-addon-api",
+ "optionalDependencies": {},
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/nodejs/node-addon-api.git"
+ },
+ "scripts": {
+ "dev": "node test",
+ "dev:incremental": "node test",
+ "doc": "doxygen doc/Doxyfile",
+ "predev": "node-gyp rebuild -C test --debug",
+ "predev:incremental": "node-gyp configure build -C test --debug",
+ "pretest": "node-gyp rebuild -C test",
+ "test": "node test"
+ },
+ "version": "2.0.0"
+}
diff --git a/debian/build_modules/node-addon-api/src/node_api.cc b/debian/build_modules/node-addon-api/src/node_api.cc
new file mode 100644
index 0000000..dd16016
--- /dev/null
+++ b/debian/build_modules/node-addon-api/src/node_api.cc
@@ -0,0 +1,3649 @@
+/******************************************************************************
+ * Experimental prototype for demonstrating VM agnostic and ABI stable API
+ * for native modules to use instead of using Nan and V8 APIs directly.
+ *
+ * The current status is "Experimental" and should not be used for
+ * production applications. The API is still subject to change
+ * and as an experimental feature is NOT subject to semver.
+ *
+ ******************************************************************************/
+
+#include <node_buffer.h>
+#include <node_object_wrap.h>
+#include <limits.h> // INT_MAX
+#include <string.h>
+#include <algorithm>
+#include <cmath>
+#include <vector>
+#include "node_api.h"
+#include "node_internals.h"
+
+#define NAPI_VERSION 1
+
+static
+napi_status napi_set_last_error(napi_env env, napi_status error_code,
+ uint32_t engine_error_code = 0,
+ void* engine_reserved = nullptr);
+static
+napi_status napi_clear_last_error(napi_env env);
+
+struct napi_env__ {
+ explicit napi_env__(v8::Isolate* _isolate): isolate(_isolate),
+ has_instance_available(true), last_error() {}
+ ~napi_env__() {
+ last_exception.Reset();
+ has_instance.Reset();
+ wrap_template.Reset();
+ }
+ v8::Isolate* isolate;
+ v8::Persistent<v8::Value> last_exception;
+ v8::Persistent<v8::Value> has_instance;
+ v8::Persistent<v8::ObjectTemplate> wrap_template;
+ bool has_instance_available;
+ napi_extended_error_info last_error;
+ int open_handle_scopes = 0;
+};
+
+#define ENV_OBJECT_TEMPLATE(env, prefix, destination, field_count) \
+ do { \
+ if ((env)->prefix ## _template.IsEmpty()) { \
+ (destination) = v8::ObjectTemplate::New(isolate); \
+ (destination)->SetInternalFieldCount((field_count)); \
+ (env)->prefix ## _template.Reset(isolate, (destination)); \
+ } else { \
+ (destination) = v8::Local<v8::ObjectTemplate>::New( \
+ isolate, env->prefix ## _template); \
+ } \
+ } while (0)
+
+#define RETURN_STATUS_IF_FALSE(env, condition, status) \
+ do { \
+ if (!(condition)) { \
+ return napi_set_last_error((env), (status)); \
+ } \
+ } while (0)
+
+#define CHECK_ENV(env) \
+ if ((env) == nullptr) { \
+ return napi_invalid_arg; \
+ }
+
+#define CHECK_ARG(env, arg) \
+ RETURN_STATUS_IF_FALSE((env), ((arg) != nullptr), napi_invalid_arg)
+
+#define CHECK_MAYBE_EMPTY(env, maybe, status) \
+ RETURN_STATUS_IF_FALSE((env), !((maybe).IsEmpty()), (status))
+
+#define CHECK_MAYBE_NOTHING(env, maybe, status) \
+ RETURN_STATUS_IF_FALSE((env), !((maybe).IsNothing()), (status))
+
+// NAPI_PREAMBLE is not wrapped in do..while: try_catch must have function scope
+#define NAPI_PREAMBLE(env) \
+ CHECK_ENV((env)); \
+ RETURN_STATUS_IF_FALSE((env), (env)->last_exception.IsEmpty(), \
+ napi_pending_exception); \
+ napi_clear_last_error((env)); \
+ v8impl::TryCatch try_catch((env))
+
+#define CHECK_TO_TYPE(env, type, context, result, src, status) \
+ do { \
+ CHECK_ARG((env), (src)); \
+ auto maybe = v8impl::V8LocalValueFromJsValue((src))->To##type((context)); \
+ CHECK_MAYBE_EMPTY((env), maybe, (status)); \
+ (result) = maybe.ToLocalChecked(); \
+ } while (0)
+
+#define CHECK_TO_FUNCTION(env, result, src) \
+ do { \
+ CHECK_ARG((env), (src)); \
+ v8::Local<v8::Value> v8value = v8impl::V8LocalValueFromJsValue((src)); \
+ RETURN_STATUS_IF_FALSE((env), v8value->IsFunction(), napi_invalid_arg); \
+ (result) = v8value.As<v8::Function>(); \
+ } while (0)
+
+#define CHECK_TO_OBJECT(env, context, result, src) \
+ CHECK_TO_TYPE((env), Object, (context), (result), (src), napi_object_expected)
+
+#define CHECK_TO_STRING(env, context, result, src) \
+ CHECK_TO_TYPE((env), String, (context), (result), (src), napi_string_expected)
+
+#define CHECK_TO_NUMBER(env, context, result, src) \
+ CHECK_TO_TYPE((env), Number, (context), (result), (src), napi_number_expected)
+
+#define CHECK_TO_BOOL(env, context, result, src) \
+ CHECK_TO_TYPE((env), Boolean, (context), (result), (src), \
+ napi_boolean_expected)
+
+// n-api defines NAPI_AUTO_LENGHTH as the indicator that a string
+// is null terminated. For V8 the equivalent is -1. The assert
+// validates that our cast of NAPI_AUTO_LENGTH results in -1 as
+// needed by V8.
+#define CHECK_NEW_FROM_UTF8_LEN(env, result, str, len) \
+ do { \
+ static_assert(static_cast<int>(NAPI_AUTO_LENGTH) == -1, \
+ "Casting NAPI_AUTO_LENGTH to int must result in -1"); \
+ RETURN_STATUS_IF_FALSE((env), \
+ (len == NAPI_AUTO_LENGTH) || len <= INT_MAX, \
+ napi_invalid_arg); \
+ auto str_maybe = v8::String::NewFromUtf8( \
+ (env)->isolate, (str), v8::NewStringType::kInternalized, \
+ static_cast<int>(len)); \
+ CHECK_MAYBE_EMPTY((env), str_maybe, napi_generic_failure); \
+ (result) = str_maybe.ToLocalChecked(); \
+ } while (0)
+
+#define CHECK_NEW_FROM_UTF8(env, result, str) \
+ CHECK_NEW_FROM_UTF8_LEN((env), (result), (str), NAPI_AUTO_LENGTH)
+
+#define GET_RETURN_STATUS(env) \
+ (!try_catch.HasCaught() ? napi_ok \
+ : napi_set_last_error((env), napi_pending_exception))
+
+#define THROW_RANGE_ERROR_IF_FALSE(env, condition, error, message) \
+ do { \
+ if (!(condition)) { \
+ napi_throw_range_error((env), (error), (message)); \
+ return napi_set_last_error((env), napi_generic_failure); \
+ } \
+ } while (0)
+
+#define CREATE_TYPED_ARRAY( \
+ env, type, size_of_element, buffer, byte_offset, length, out) \
+ do { \
+ if ((size_of_element) > 1) { \
+ THROW_RANGE_ERROR_IF_FALSE( \
+ (env), (byte_offset) % (size_of_element) == 0, \
+ "ERR_NAPI_INVALID_TYPEDARRAY_ALIGNMENT", \
+ "start offset of "#type" should be a multiple of "#size_of_element); \
+ } \
+ THROW_RANGE_ERROR_IF_FALSE((env), (length) * (size_of_element) + \
+ (byte_offset) <= buffer->ByteLength(), \
+ "ERR_NAPI_INVALID_TYPEDARRAY_LENGTH", \
+ "Invalid typed array length"); \
+ (out) = v8::type::New((buffer), (byte_offset), (length)); \
+ } while (0)
+
+#define NAPI_CALL_INTO_MODULE(env, call, handle_exception) \
+ do { \
+ int open_handle_scopes = (env)->open_handle_scopes; \
+ napi_clear_last_error((env)); \
+ call; \
+ CHECK_EQ((env)->open_handle_scopes, open_handle_scopes); \
+ if (!(env)->last_exception.IsEmpty()) { \
+ handle_exception( \
+ v8::Local<v8::Value>::New((env)->isolate, (env)->last_exception)); \
+ (env)->last_exception.Reset(); \
+ } \
+ } while (0)
+
+#define NAPI_CALL_INTO_MODULE_THROW(env, call) \
+ NAPI_CALL_INTO_MODULE((env), call, (env)->isolate->ThrowException)
+
+namespace {
+namespace v8impl {
+
+// convert from n-api property attributes to v8::PropertyAttribute
+static inline v8::PropertyAttribute V8PropertyAttributesFromDescriptor(
+ const napi_property_descriptor* descriptor) {
+ unsigned int attribute_flags = v8::PropertyAttribute::None;
+
+ if (descriptor->getter != nullptr || descriptor->setter != nullptr) {
+ // The napi_writable attribute is ignored for accessor descriptors, but
+ // V8 requires the ReadOnly attribute to match nonexistence of a setter.
+ attribute_flags |= (descriptor->setter == nullptr ?
+ v8::PropertyAttribute::ReadOnly : v8::PropertyAttribute::None);
+ } else if ((descriptor->attributes & napi_writable) == 0) {
+ attribute_flags |= v8::PropertyAttribute::ReadOnly;
+ }
+
+ if ((descriptor->attributes & napi_enumerable) == 0) {
+ attribute_flags |= v8::PropertyAttribute::DontEnum;
+ }
+ if ((descriptor->attributes & napi_configurable) == 0) {
+ attribute_flags |= v8::PropertyAttribute::DontDelete;
+ }
+
+ return static_cast<v8::PropertyAttribute>(attribute_flags);
+}
+
+class HandleScopeWrapper {
+ public:
+ explicit HandleScopeWrapper(v8::Isolate* isolate) : scope(isolate) {}
+
+ private:
+ v8::HandleScope scope;
+};
+
+// In node v0.10 version of v8, there is no EscapableHandleScope and the
+// node v0.10 port use HandleScope::Close(Local<T> v) to mimic the behavior
+// of a EscapableHandleScope::Escape(Local<T> v), but it is not the same
+// semantics. This is an example of where the api abstraction fail to work
+// across different versions.
+class EscapableHandleScopeWrapper {
+ public:
+ explicit EscapableHandleScopeWrapper(v8::Isolate* isolate)
+ : scope(isolate), escape_called_(false) {}
+ bool escape_called() const {
+ return escape_called_;
+ }
+ template <typename T>
+ v8::Local<T> Escape(v8::Local<T> handle) {
+ escape_called_ = true;
+ return scope.Escape(handle);
+ }
+
+ private:
+ v8::EscapableHandleScope scope;
+ bool escape_called_;
+};
+
+static
+napi_handle_scope JsHandleScopeFromV8HandleScope(HandleScopeWrapper* s) {
+ return reinterpret_cast<napi_handle_scope>(s);
+}
+
+static
+HandleScopeWrapper* V8HandleScopeFromJsHandleScope(napi_handle_scope s) {
+ return reinterpret_cast<HandleScopeWrapper*>(s);
+}
+
+static
+napi_escapable_handle_scope JsEscapableHandleScopeFromV8EscapableHandleScope(
+ EscapableHandleScopeWrapper* s) {
+ return reinterpret_cast<napi_escapable_handle_scope>(s);
+}
+
+static
+EscapableHandleScopeWrapper*
+V8EscapableHandleScopeFromJsEscapableHandleScope(
+ napi_escapable_handle_scope s) {
+ return reinterpret_cast<EscapableHandleScopeWrapper*>(s);
+}
+
+//=== Conversion between V8 Handles and napi_value ========================
+
+// This asserts v8::Local<> will always be implemented with a single
+// pointer field so that we can pass it around as a void*.
+static_assert(sizeof(v8::Local<v8::Value>) == sizeof(napi_value),
+ "Cannot convert between v8::Local<v8::Value> and napi_value");
+
+static
+napi_deferred JsDeferredFromV8Persistent(v8::Persistent<v8::Value>* local) {
+ return reinterpret_cast<napi_deferred>(local);
+}
+
+static
+v8::Persistent<v8::Value>* V8PersistentFromJsDeferred(napi_deferred local) {
+ return reinterpret_cast<v8::Persistent<v8::Value>*>(local);
+}
+
+static
+napi_value JsValueFromV8LocalValue(v8::Local<v8::Value> local) {
+ return reinterpret_cast<napi_value>(*local);
+}
+
+static
+v8::Local<v8::Value> V8LocalValueFromJsValue(napi_value v) {
+ v8::Local<v8::Value> local;
+ memcpy(&local, &v, sizeof(v));
+ return local;
+}
+
+static inline void trigger_fatal_exception(
+ napi_env env, v8::Local<v8::Value> local_err) {
+ v8::TryCatch try_catch(env->isolate);
+ env->isolate->ThrowException(local_err);
+ node::FatalException(env->isolate, try_catch);
+}
+
+static inline napi_status V8NameFromPropertyDescriptor(napi_env env,
+ const napi_property_descriptor* p,
+ v8::Local<v8::Name>* result) {
+ if (p->utf8name != nullptr) {
+ CHECK_NEW_FROM_UTF8(env, *result, p->utf8name);
+ } else {
+ v8::Local<v8::Value> property_value =
+ v8impl::V8LocalValueFromJsValue(p->name);
+
+ RETURN_STATUS_IF_FALSE(env, property_value->IsName(), napi_name_expected);
+ *result = property_value.As<v8::Name>();
+ }
+
+ return napi_ok;
+}
+
+// Adapter for napi_finalize callbacks.
+class Finalizer {
+ protected:
+ Finalizer(napi_env env,
+ napi_finalize finalize_callback,
+ void* finalize_data,
+ void* finalize_hint)
+ : _env(env),
+ _finalize_callback(finalize_callback),
+ _finalize_data(finalize_data),
+ _finalize_hint(finalize_hint) {
+ }
+
+ ~Finalizer() {
+ }
+
+ public:
+ static Finalizer* New(napi_env env,
+ napi_finalize finalize_callback = nullptr,
+ void* finalize_data = nullptr,
+ void* finalize_hint = nullptr) {
+ return new Finalizer(
+ env, finalize_callback, finalize_data, finalize_hint);
+ }
+
+ static void Delete(Finalizer* finalizer) {
+ delete finalizer;
+ }
+
+ // node::Buffer::FreeCallback
+ static void FinalizeBufferCallback(char* data, void* hint) {
+ Finalizer* finalizer = static_cast<Finalizer*>(hint);
+ if (finalizer->_finalize_callback != nullptr) {
+ NAPI_CALL_INTO_MODULE_THROW(finalizer->_env,
+ finalizer->_finalize_callback(
+ finalizer->_env,
+ data,
+ finalizer->_finalize_hint));
+ }
+
+ Delete(finalizer);
+ }
+
+ protected:
+ napi_env _env;
+ napi_finalize _finalize_callback;
+ void* _finalize_data;
+ void* _finalize_hint;
+};
+
+// Wrapper around v8::Persistent that implements reference counting.
+class Reference : private Finalizer {
+ private:
+ Reference(napi_env env,
+ v8::Local<v8::Value> value,
+ uint32_t initial_refcount,
+ bool delete_self,
+ napi_finalize finalize_callback,
+ void* finalize_data,
+ void* finalize_hint)
+ : Finalizer(env, finalize_callback, finalize_data, finalize_hint),
+ _persistent(env->isolate, value),
+ _refcount(initial_refcount),
+ _delete_self(delete_self) {
+ if (initial_refcount == 0) {
+ _persistent.SetWeak(
+ this, FinalizeCallback, v8::WeakCallbackType::kParameter);
+ _persistent.MarkIndependent();
+ }
+ }
+
+ ~Reference() {
+ // The V8 Persistent class currently does not reset in its destructor:
+ // see NonCopyablePersistentTraits::kResetInDestructor = false.
+ // (Comments there claim that might change in the future.)
+ // To avoid memory leaks, it is better to reset at this time, however
+ // care must be taken to avoid attempting this after the Isolate has
+ // shut down, for example via a static (atexit) destructor.
+ _persistent.Reset();
+ }
+
+ public:
+ static Reference* New(napi_env env,
+ v8::Local<v8::Value> value,
+ uint32_t initial_refcount,
+ bool delete_self,
+ napi_finalize finalize_callback = nullptr,
+ void* finalize_data = nullptr,
+ void* finalize_hint = nullptr) {
+ return new Reference(env,
+ value,
+ initial_refcount,
+ delete_self,
+ finalize_callback,
+ finalize_data,
+ finalize_hint);
+ }
+
+ static void Delete(Reference* reference) {
+ delete reference;
+ }
+
+ uint32_t Ref() {
+ if (++_refcount == 1) {
+ _persistent.ClearWeak();
+ }
+
+ return _refcount;
+ }
+
+ uint32_t Unref() {
+ if (_refcount == 0) {
+ return 0;
+ }
+ if (--_refcount == 0) {
+ _persistent.SetWeak(
+ this, FinalizeCallback, v8::WeakCallbackType::kParameter);
+ _persistent.MarkIndependent();
+ }
+
+ return _refcount;
+ }
+
+ uint32_t RefCount() {
+ return _refcount;
+ }
+
+ v8::Local<v8::Value> Get() {
+ if (_persistent.IsEmpty()) {
+ return v8::Local<v8::Value>();
+ } else {
+ return v8::Local<v8::Value>::New(_env->isolate, _persistent);
+ }
+ }
+
+ private:
+ static void FinalizeCallback(const v8::WeakCallbackInfo<Reference>& data) {
+ Reference* reference = data.GetParameter();
+ reference->_persistent.Reset();
+
+ // Check before calling the finalize callback, because the callback might
+ // delete it.
+ bool delete_self = reference->_delete_self;
+ napi_env env = reference->_env;
+
+ if (reference->_finalize_callback != nullptr) {
+ NAPI_CALL_INTO_MODULE_THROW(env,
+ reference->_finalize_callback(
+ reference->_env,
+ reference->_finalize_data,
+ reference->_finalize_hint));
+ }
+
+ if (delete_self) {
+ Delete(reference);
+ }
+ }
+
+ v8::Persistent<v8::Value> _persistent;
+ uint32_t _refcount;
+ bool _delete_self;
+};
+
+class TryCatch : public v8::TryCatch {
+ public:
+ explicit TryCatch(napi_env env)
+ : v8::TryCatch(env->isolate), _env(env) {}
+
+ ~TryCatch() {
+ if (HasCaught()) {
+ _env->last_exception.Reset(_env->isolate, Exception());
+ }
+ }
+
+ private:
+ napi_env _env;
+};
+
+//=== Function napi_callback wrapper =================================
+
+// Use this data structure to associate callback data with each N-API function
+// exposed to JavaScript. The structure is stored in a v8::External which gets
+// passed into our callback wrapper. This reduces the performance impact of
+// calling through N-API.
+// Ref: benchmark/misc/function_call
+// Discussion (incl. perf. data): https://github.com/nodejs/node/pull/21072
+struct CallbackBundle {
+ // Bind the lifecycle of `this` C++ object to a JavaScript object.
+ // We never delete a CallbackBundle C++ object directly.
+ void BindLifecycleTo(v8::Isolate* isolate, v8::Local<v8::Value> target) {
+ handle.Reset(isolate, target);
+ handle.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
+ }
+
+ napi_env env; // Necessary to invoke C++ NAPI callback
+ void* cb_data; // The user provided callback data
+ napi_callback function_or_getter;
+ napi_callback setter;
+ node::Persistent<v8::Value> handle; // Die with this JavaScript object
+
+ private:
+ static void WeakCallback(v8::WeakCallbackInfo<CallbackBundle> const& info) {
+ // Use the "WeakCallback mechanism" to delete the C++ `bundle` object.
+ // This will be called when the v8::External containing `this` pointer
+ // is being GC-ed.
+ CallbackBundle* bundle = info.GetParameter();
+ if (bundle != nullptr) {
+ delete bundle;
+ }
+ }
+};
+
+// Base class extended by classes that wrap V8 function and property callback
+// info.
+class CallbackWrapper {
+ public:
+ CallbackWrapper(napi_value this_arg, size_t args_length, void* data)
+ : _this(this_arg), _args_length(args_length), _data(data) {}
+
+ virtual napi_value GetNewTarget() = 0;
+ virtual void Args(napi_value* buffer, size_t bufferlength) = 0;
+ virtual void SetReturnValue(napi_value value) = 0;
+
+ napi_value This() { return _this; }
+
+ size_t ArgsLength() { return _args_length; }
+
+ void* Data() { return _data; }
+
+ protected:
+ const napi_value _this;
+ const size_t _args_length;
+ void* _data;
+};
+
+template <typename Info, napi_callback CallbackBundle::*FunctionField>
+class CallbackWrapperBase : public CallbackWrapper {
+ public:
+ CallbackWrapperBase(const Info& cbinfo, const size_t args_length)
+ : CallbackWrapper(JsValueFromV8LocalValue(cbinfo.This()),
+ args_length,
+ nullptr),
+ _cbinfo(cbinfo) {
+ _bundle = reinterpret_cast<CallbackBundle*>(
+ v8::Local<v8::External>::Cast(cbinfo.Data())->Value());
+ _data = _bundle->cb_data;
+ }
+
+ napi_value GetNewTarget() override { return nullptr; }
+
+ protected:
+ void InvokeCallback() {
+ napi_callback_info cbinfo_wrapper = reinterpret_cast<napi_callback_info>(
+ static_cast<CallbackWrapper*>(this));
+
+ // All other pointers we need are stored in `_bundle`
+ napi_env env = _bundle->env;
+ napi_callback cb = _bundle->*FunctionField;
+
+ napi_value result;
+ NAPI_CALL_INTO_MODULE_THROW(env, result = cb(env, cbinfo_wrapper));
+
+ if (result != nullptr) {
+ this->SetReturnValue(result);
+ }
+ }
+
+ const Info& _cbinfo;
+ CallbackBundle* _bundle;
+};
+
+class FunctionCallbackWrapper
+ : public CallbackWrapperBase<v8::FunctionCallbackInfo<v8::Value>,
+ &CallbackBundle::function_or_getter> {
+ public:
+ static void Invoke(const v8::FunctionCallbackInfo<v8::Value>& info) {
+ FunctionCallbackWrapper cbwrapper(info);
+ cbwrapper.InvokeCallback();
+ }
+
+ explicit FunctionCallbackWrapper(
+ const v8::FunctionCallbackInfo<v8::Value>& cbinfo)
+ : CallbackWrapperBase(cbinfo, cbinfo.Length()) {}
+
+ napi_value GetNewTarget() override {
+ if (_cbinfo.IsConstructCall()) {
+ return v8impl::JsValueFromV8LocalValue(_cbinfo.NewTarget());
+ } else {
+ return nullptr;
+ }
+ }
+
+ /*virtual*/
+ void Args(napi_value* buffer, size_t buffer_length) override {
+ size_t i = 0;
+ size_t min = std::min(buffer_length, _args_length);
+
+ for (; i < min; i += 1) {
+ buffer[i] = v8impl::JsValueFromV8LocalValue(_cbinfo[i]);
+ }
+
+ if (i < buffer_length) {
+ napi_value undefined =
+ v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
+ for (; i < buffer_length; i += 1) {
+ buffer[i] = undefined;
+ }
+ }
+ }
+
+ /*virtual*/
+ void SetReturnValue(napi_value value) override {
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ _cbinfo.GetReturnValue().Set(val);
+ }
+};
+
+class GetterCallbackWrapper
+ : public CallbackWrapperBase<v8::PropertyCallbackInfo<v8::Value>,
+ &CallbackBundle::function_or_getter> {
+ public:
+ static void Invoke(v8::Local<v8::Name> property,
+ const v8::PropertyCallbackInfo<v8::Value>& info) {
+ GetterCallbackWrapper cbwrapper(info);
+ cbwrapper.InvokeCallback();
+ }
+
+ explicit GetterCallbackWrapper(
+ const v8::PropertyCallbackInfo<v8::Value>& cbinfo)
+ : CallbackWrapperBase(cbinfo, 0) {}
+
+ /*virtual*/
+ void Args(napi_value* buffer, size_t buffer_length) override {
+ if (buffer_length > 0) {
+ napi_value undefined =
+ v8impl::JsValueFromV8LocalValue(v8::Undefined(_cbinfo.GetIsolate()));
+ for (size_t i = 0; i < buffer_length; i += 1) {
+ buffer[i] = undefined;
+ }
+ }
+ }
+
+ /*virtual*/
+ void SetReturnValue(napi_value value) override {
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ _cbinfo.GetReturnValue().Set(val);
+ }
+};
+
+class SetterCallbackWrapper
+ : public CallbackWrapperBase<v8::PropertyCallbackInfo<void>,
+ &CallbackBundle::setter> {
+ public:
+ static void Invoke(v8::Local<v8::Name> property,
+ v8::Local<v8::Value> value,
+ const v8::PropertyCallbackInfo<void>& info) {
+ SetterCallbackWrapper cbwrapper(info, value);
+ cbwrapper.InvokeCallback();
+ }
+
+ SetterCallbackWrapper(const v8::PropertyCallbackInfo<void>& cbinfo,
+ const v8::Local<v8::Value>& value)
+ : CallbackWrapperBase(cbinfo, 1), _value(value) {}
+
+ /*virtual*/
+ void Args(napi_value* buffer, size_t buffer_length) override {
+ if (buffer_length > 0) {
+ buffer[0] = v8impl::JsValueFromV8LocalValue(_value);
+
+ if (buffer_length > 1) {
+ napi_value undefined = v8impl::JsValueFromV8LocalValue(
+ v8::Undefined(_cbinfo.GetIsolate()));
+ for (size_t i = 1; i < buffer_length; i += 1) {
+ buffer[i] = undefined;
+ }
+ }
+ }
+ }
+
+ /*virtual*/
+ void SetReturnValue(napi_value value) override {
+ // Ignore any value returned from a setter callback.
+ }
+
+ private:
+ const v8::Local<v8::Value>& _value;
+};
+
+// Creates an object to be made available to the static function callback
+// wrapper, used to retrieve the native callback function and data pointer.
+static
+v8::Local<v8::Value> CreateFunctionCallbackData(napi_env env,
+ napi_callback cb,
+ void* data) {
+ CallbackBundle* bundle = new CallbackBundle();
+ bundle->function_or_getter = cb;
+ bundle->cb_data = data;
+ bundle->env = env;
+ v8::Local<v8::Value> cbdata = v8::External::New(env->isolate, bundle);
+ bundle->BindLifecycleTo(env->isolate, cbdata);
+
+ return cbdata;
+}
+
+// Creates an object to be made available to the static getter/setter
+// callback wrapper, used to retrieve the native getter/setter callback
+// function and data pointer.
+static
+v8::Local<v8::Value> CreateAccessorCallbackData(napi_env env,
+ napi_callback getter,
+ napi_callback setter,
+ void* data) {
+ CallbackBundle* bundle = new CallbackBundle();
+ bundle->function_or_getter = getter;
+ bundle->setter = setter;
+ bundle->cb_data = data;
+ bundle->env = env;
+ v8::Local<v8::Value> cbdata = v8::External::New(env->isolate, bundle);
+ bundle->BindLifecycleTo(env->isolate, cbdata);
+
+ return cbdata;
+}
+
+int kWrapperFields = 3;
+
+// Pointer used to identify items wrapped by N-API. Used by FindWrapper and
+// napi_wrap().
+const char napi_wrap_name[] = "N-API Wrapper";
+
+// Search the object's prototype chain for the wrapper object. Usually the
+// wrapper would be the first in the chain, but it is OK for other objects to
+// be inserted in the prototype chain.
+static
+bool FindWrapper(v8::Local<v8::Object> obj,
+ v8::Local<v8::Object>* result = nullptr,
+ v8::Local<v8::Object>* parent = nullptr) {
+ v8::Local<v8::Object> wrapper = obj;
+
+ do {
+ v8::Local<v8::Value> proto = wrapper->GetPrototype();
+ if (proto.IsEmpty() || !proto->IsObject()) {
+ return false;
+ }
+ if (parent != nullptr) {
+ *parent = wrapper;
+ }
+ wrapper = proto.As<v8::Object>();
+ if (wrapper->InternalFieldCount() == kWrapperFields) {
+ v8::Local<v8::Value> external = wrapper->GetInternalField(1);
+ if (external->IsExternal() &&
+ external.As<v8::External>()->Value() == v8impl::napi_wrap_name) {
+ break;
+ }
+ }
+ } while (true);
+
+ if (result != nullptr) {
+ *result = wrapper;
+ }
+ return true;
+}
+
+static void DeleteEnv(napi_env env, void* data, void* hint) {
+ delete env;
+}
+
+static
+napi_env GetEnv(v8::Local<v8::Context> context) {
+ napi_env result;
+
+ auto isolate = context->GetIsolate();
+ auto global = context->Global();
+
+ // In the case of the string for which we grab the private and the value of
+ // the private on the global object we can call .ToLocalChecked() directly
+ // because we need to stop hard if either of them is empty.
+ //
+ // Re https://github.com/nodejs/node/pull/14217#discussion_r128775149
+ auto key = v8::Private::ForApi(isolate,
+ v8::String::NewFromOneByte(isolate,
+ reinterpret_cast<const uint8_t*>("N-API Environment"),
+ v8::NewStringType::kInternalized).ToLocalChecked());
+ auto value = global->GetPrivate(context, key).ToLocalChecked();
+
+ if (value->IsExternal()) {
+ result = static_cast<napi_env>(value.As<v8::External>()->Value());
+ } else {
+ result = new napi_env__(isolate);
+ auto external = v8::External::New(isolate, result);
+
+ // We must also stop hard if the result of assigning the env to the global
+ // is either nothing or false.
+ CHECK(global->SetPrivate(context, key, external).FromJust());
+
+ // Create a self-destructing reference to external that will get rid of the
+ // napi_env when external goes out of scope.
+ Reference::New(result, external, 0, true, DeleteEnv, nullptr, nullptr);
+ }
+
+ return result;
+}
+
+static
+napi_status Unwrap(napi_env env,
+ napi_value js_object,
+ void** result,
+ v8::Local<v8::Object>* wrapper,
+ v8::Local<v8::Object>* parent = nullptr) {
+ CHECK_ARG(env, js_object);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
+ RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
+ v8::Local<v8::Object> obj = value.As<v8::Object>();
+
+ RETURN_STATUS_IF_FALSE(
+ env, v8impl::FindWrapper(obj, wrapper, parent), napi_invalid_arg);
+
+ v8::Local<v8::Value> unwrappedValue = (*wrapper)->GetInternalField(0);
+ RETURN_STATUS_IF_FALSE(env, unwrappedValue->IsExternal(), napi_invalid_arg);
+
+ *result = unwrappedValue.As<v8::External>()->Value();
+
+ return napi_ok;
+}
+
+static
+napi_status ConcludeDeferred(napi_env env,
+ napi_deferred deferred,
+ napi_value result,
+ bool is_resolved) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Context> context = env->isolate->GetCurrentContext();
+ v8::Persistent<v8::Value>* deferred_ref =
+ V8PersistentFromJsDeferred(deferred);
+ v8::Local<v8::Value> v8_deferred =
+ v8::Local<v8::Value>::New(env->isolate, *deferred_ref);
+
+ auto v8_resolver = v8::Local<v8::Promise::Resolver>::Cast(v8_deferred);
+
+ v8::Maybe<bool> success = is_resolved ?
+ v8_resolver->Resolve(context, v8impl::V8LocalValueFromJsValue(result)) :
+ v8_resolver->Reject(context, v8impl::V8LocalValueFromJsValue(result));
+
+ deferred_ref->Reset();
+ delete deferred_ref;
+
+ RETURN_STATUS_IF_FALSE(env, success.FromMaybe(false), napi_generic_failure);
+
+ return GET_RETURN_STATUS(env);
+}
+
+} // end of namespace v8impl
+
+// Intercepts the Node-V8 module registration callback. Converts parameters
+// to NAPI equivalents and then calls the registration callback specified
+// by the NAPI module.
+void napi_module_register_cb(v8::Local<v8::Object> exports,
+ v8::Local<v8::Value> module,
+ v8::Local<v8::Context> context,
+ void* priv) {
+ napi_module* mod = static_cast<napi_module*>(priv);
+
+ // Create a new napi_env for this module or reference one if a pre-existing
+ // one is found.
+ napi_env env = v8impl::GetEnv(context);
+
+ napi_value _exports;
+ NAPI_CALL_INTO_MODULE_THROW(env,
+ _exports = mod->nm_register_func(env,
+ v8impl::JsValueFromV8LocalValue(exports)));
+
+ // If register function returned a non-null exports object different from
+ // the exports object we passed it, set that as the "exports" property of
+ // the module.
+ if (_exports != nullptr &&
+ _exports != v8impl::JsValueFromV8LocalValue(exports)) {
+ napi_value _module = v8impl::JsValueFromV8LocalValue(module);
+ napi_set_named_property(env, _module, "exports", _exports);
+ }
+}
+
+} // end of anonymous namespace
+
+// Registers a NAPI module.
+void napi_module_register(napi_module* mod) {
+ node::node_module* nm = new node::node_module {
+ NODE_MODULE_VERSION,
+ mod->nm_flags,
+ nullptr,
+ mod->nm_filename,
+ nullptr,
+ napi_module_register_cb,
+ mod->nm_modname,
+ mod, // priv
+ nullptr,
+ };
+ node::node_module_register(nm);
+}
+
+// Warning: Keep in-sync with napi_status enum
+static
+const char* error_messages[] = {nullptr,
+ "Invalid argument",
+ "An object was expected",
+ "A string was expected",
+ "A string or symbol was expected",
+ "A function was expected",
+ "A number was expected",
+ "A boolean was expected",
+ "An array was expected",
+ "Unknown failure",
+ "An exception is pending",
+ "The async work item was cancelled",
+ "napi_escape_handle already called on scope"};
+
+static inline napi_status napi_clear_last_error(napi_env env) {
+ env->last_error.error_code = napi_ok;
+
+ // TODO(boingoing): Should this be a callback?
+ env->last_error.engine_error_code = 0;
+ env->last_error.engine_reserved = nullptr;
+ return napi_ok;
+}
+
+static inline
+napi_status napi_set_last_error(napi_env env, napi_status error_code,
+ uint32_t engine_error_code,
+ void* engine_reserved) {
+ env->last_error.error_code = error_code;
+ env->last_error.engine_error_code = engine_error_code;
+ env->last_error.engine_reserved = engine_reserved;
+ return error_code;
+}
+
+napi_status napi_get_last_error_info(napi_env env,
+ const napi_extended_error_info** result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ // you must update this assert to reference the last message
+ // in the napi_status enum each time a new error message is added.
+ // We don't have a napi_status_last as this would result in an ABI
+ // change each time a message was added.
+ static_assert(
+ node::arraysize(error_messages) == napi_escape_called_twice + 1,
+ "Count of error messages must match count of error values");
+ CHECK_LE(env->last_error.error_code, napi_escape_called_twice);
+
+ // Wait until someone requests the last error information to fetch the error
+ // message string
+ env->last_error.error_message =
+ error_messages[env->last_error.error_code];
+
+ *result = &(env->last_error);
+ return napi_ok;
+}
+
+napi_status napi_fatal_exception(napi_env env, napi_value err) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, err);
+
+ v8::Local<v8::Value> local_err = v8impl::V8LocalValueFromJsValue(err);
+ v8impl::trigger_fatal_exception(env, local_err);
+
+ return napi_clear_last_error(env);
+}
+
+NAPI_NO_RETURN void napi_fatal_error(const char* location,
+ size_t location_len,
+ const char* message,
+ size_t message_len) {
+ std::string location_string;
+ std::string message_string;
+
+ if (location_len != NAPI_AUTO_LENGTH) {
+ location_string.assign(
+ const_cast<char*>(location), location_len);
+ } else {
+ location_string.assign(
+ const_cast<char*>(location), strlen(location));
+ }
+
+ if (message_len != NAPI_AUTO_LENGTH) {
+ message_string.assign(
+ const_cast<char*>(message), message_len);
+ } else {
+ message_string.assign(
+ const_cast<char*>(message), strlen(message));
+ }
+
+ node::FatalError(location_string.c_str(), message_string.c_str());
+}
+
+napi_status napi_create_function(napi_env env,
+ const char* utf8name,
+ size_t length,
+ napi_callback cb,
+ void* callback_data,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+ CHECK_ARG(env, cb);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Function> return_value;
+ v8::EscapableHandleScope scope(isolate);
+ v8::Local<v8::Value> cbdata =
+ v8impl::CreateFunctionCallbackData(env, cb, callback_data);
+
+ RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
+
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::MaybeLocal<v8::Function> maybe_function =
+ v8::Function::New(context,
+ v8impl::FunctionCallbackWrapper::Invoke,
+ cbdata);
+ CHECK_MAYBE_EMPTY(env, maybe_function, napi_generic_failure);
+
+ return_value = scope.Escape(maybe_function.ToLocalChecked());
+
+ if (utf8name != nullptr) {
+ v8::Local<v8::String> name_string;
+ CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
+ return_value->SetName(name_string);
+ }
+
+ *result = v8impl::JsValueFromV8LocalValue(return_value);
+
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_define_class(napi_env env,
+ const char* utf8name,
+ size_t length,
+ napi_callback constructor,
+ void* callback_data,
+ size_t property_count,
+ const napi_property_descriptor* properties,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+ CHECK_ARG(env, constructor);
+
+ v8::Isolate* isolate = env->isolate;
+
+ v8::EscapableHandleScope scope(isolate);
+ v8::Local<v8::Value> cbdata =
+ v8impl::CreateFunctionCallbackData(env, constructor, callback_data);
+
+ RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
+
+ v8::Local<v8::FunctionTemplate> tpl = v8::FunctionTemplate::New(
+ isolate, v8impl::FunctionCallbackWrapper::Invoke, cbdata);
+
+ v8::Local<v8::String> name_string;
+ CHECK_NEW_FROM_UTF8_LEN(env, name_string, utf8name, length);
+ tpl->SetClassName(name_string);
+
+ size_t static_property_count = 0;
+ for (size_t i = 0; i < property_count; i++) {
+ const napi_property_descriptor* p = properties + i;
+
+ if ((p->attributes & napi_static) != 0) {
+ // Static properties are handled separately below.
+ static_property_count++;
+ continue;
+ }
+
+ v8::Local<v8::Name> property_name;
+ napi_status status =
+ v8impl::V8NameFromPropertyDescriptor(env, p, &property_name);
+
+ if (status != napi_ok) {
+ return napi_set_last_error(env, status);
+ }
+
+ v8::PropertyAttribute attributes =
+ v8impl::V8PropertyAttributesFromDescriptor(p);
+
+ // This code is similar to that in napi_define_properties(); the
+ // difference is it applies to a template instead of an object.
+ if (p->getter != nullptr || p->setter != nullptr) {
+ v8::Local<v8::Value> cbdata = v8impl::CreateAccessorCallbackData(
+ env, p->getter, p->setter, p->data);
+
+ tpl->PrototypeTemplate()->SetAccessor(
+ property_name,
+ p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr,
+ p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr,
+ cbdata,
+ v8::AccessControl::DEFAULT,
+ attributes);
+ } else if (p->method != nullptr) {
+ v8::Local<v8::Value> cbdata =
+ v8impl::CreateFunctionCallbackData(env, p->method, p->data);
+
+ RETURN_STATUS_IF_FALSE(env, !cbdata.IsEmpty(), napi_generic_failure);
+
+ v8::Local<v8::FunctionTemplate> t =
+ v8::FunctionTemplate::New(isolate,
+ v8impl::FunctionCallbackWrapper::Invoke,
+ cbdata,
+ v8::Signature::New(isolate, tpl));
+
+ tpl->PrototypeTemplate()->Set(property_name, t, attributes);
+ } else {
+ v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
+ tpl->PrototypeTemplate()->Set(property_name, value, attributes);
+ }
+ }
+
+ *result = v8impl::JsValueFromV8LocalValue(scope.Escape(tpl->GetFunction()));
+
+ if (static_property_count > 0) {
+ std::vector<napi_property_descriptor> static_descriptors;
+ static_descriptors.reserve(static_property_count);
+
+ for (size_t i = 0; i < property_count; i++) {
+ const napi_property_descriptor* p = properties + i;
+ if ((p->attributes & napi_static) != 0) {
+ static_descriptors.push_back(*p);
+ }
+ }
+
+ napi_status status =
+ napi_define_properties(env,
+ *result,
+ static_descriptors.size(),
+ static_descriptors.data());
+ if (status != napi_ok) return status;
+ }
+
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_get_property_names(napi_env env,
+ napi_value object,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Object> obj;
+ CHECK_TO_OBJECT(env, context, obj, object);
+
+ auto maybe_propertynames = obj->GetPropertyNames(context);
+
+ CHECK_MAYBE_EMPTY(env, maybe_propertynames, napi_generic_failure);
+
+ *result = v8impl::JsValueFromV8LocalValue(
+ maybe_propertynames.ToLocalChecked());
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_set_property(napi_env env,
+ napi_value object,
+ napi_value key,
+ napi_value value) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, key);
+ CHECK_ARG(env, value);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Object> obj;
+
+ CHECK_TO_OBJECT(env, context, obj, object);
+
+ v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+
+ v8::Maybe<bool> set_maybe = obj->Set(context, k, val);
+
+ RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_has_property(napi_env env,
+ napi_value object,
+ napi_value key,
+ bool* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+ CHECK_ARG(env, key);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Object> obj;
+
+ CHECK_TO_OBJECT(env, context, obj, object);
+
+ v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
+ v8::Maybe<bool> has_maybe = obj->Has(context, k);
+
+ CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
+
+ *result = has_maybe.FromMaybe(false);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_get_property(napi_env env,
+ napi_value object,
+ napi_value key,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, key);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
+ v8::Local<v8::Object> obj;
+
+ CHECK_TO_OBJECT(env, context, obj, object);
+
+ auto get_maybe = obj->Get(context, k);
+
+ CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
+
+ v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
+ *result = v8impl::JsValueFromV8LocalValue(val);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_delete_property(napi_env env,
+ napi_value object,
+ napi_value key,
+ bool* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, key);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
+ v8::Local<v8::Object> obj;
+
+ CHECK_TO_OBJECT(env, context, obj, object);
+ v8::Maybe<bool> delete_maybe = obj->Delete(context, k);
+ CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
+
+ if (result != NULL)
+ *result = delete_maybe.FromMaybe(false);
+
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_has_own_property(napi_env env,
+ napi_value object,
+ napi_value key,
+ bool* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, key);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Object> obj;
+
+ CHECK_TO_OBJECT(env, context, obj, object);
+ v8::Local<v8::Value> k = v8impl::V8LocalValueFromJsValue(key);
+ RETURN_STATUS_IF_FALSE(env, k->IsName(), napi_name_expected);
+ v8::Maybe<bool> has_maybe = obj->HasOwnProperty(context, k.As<v8::Name>());
+ CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
+ *result = has_maybe.FromMaybe(false);
+
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_set_named_property(napi_env env,
+ napi_value object,
+ const char* utf8name,
+ napi_value value) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, value);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Object> obj;
+
+ CHECK_TO_OBJECT(env, context, obj, object);
+
+ v8::Local<v8::Name> key;
+ CHECK_NEW_FROM_UTF8(env, key, utf8name);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+
+ v8::Maybe<bool> set_maybe = obj->Set(context, key, val);
+
+ RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_has_named_property(napi_env env,
+ napi_value object,
+ const char* utf8name,
+ bool* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Object> obj;
+
+ CHECK_TO_OBJECT(env, context, obj, object);
+
+ v8::Local<v8::Name> key;
+ CHECK_NEW_FROM_UTF8(env, key, utf8name);
+
+ v8::Maybe<bool> has_maybe = obj->Has(context, key);
+
+ CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
+
+ *result = has_maybe.FromMaybe(false);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_get_named_property(napi_env env,
+ napi_value object,
+ const char* utf8name,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ v8::Local<v8::Name> key;
+ CHECK_NEW_FROM_UTF8(env, key, utf8name);
+
+ v8::Local<v8::Object> obj;
+
+ CHECK_TO_OBJECT(env, context, obj, object);
+
+ auto get_maybe = obj->Get(context, key);
+
+ CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
+
+ v8::Local<v8::Value> val = get_maybe.ToLocalChecked();
+ *result = v8impl::JsValueFromV8LocalValue(val);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_set_element(napi_env env,
+ napi_value object,
+ uint32_t index,
+ napi_value value) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, value);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Object> obj;
+
+ CHECK_TO_OBJECT(env, context, obj, object);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ auto set_maybe = obj->Set(context, index, val);
+
+ RETURN_STATUS_IF_FALSE(env, set_maybe.FromMaybe(false), napi_generic_failure);
+
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_has_element(napi_env env,
+ napi_value object,
+ uint32_t index,
+ bool* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Object> obj;
+
+ CHECK_TO_OBJECT(env, context, obj, object);
+
+ v8::Maybe<bool> has_maybe = obj->Has(context, index);
+
+ CHECK_MAYBE_NOTHING(env, has_maybe, napi_generic_failure);
+
+ *result = has_maybe.FromMaybe(false);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_get_element(napi_env env,
+ napi_value object,
+ uint32_t index,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Object> obj;
+
+ CHECK_TO_OBJECT(env, context, obj, object);
+
+ auto get_maybe = obj->Get(context, index);
+
+ CHECK_MAYBE_EMPTY(env, get_maybe, napi_generic_failure);
+
+ *result = v8impl::JsValueFromV8LocalValue(get_maybe.ToLocalChecked());
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_delete_element(napi_env env,
+ napi_value object,
+ uint32_t index,
+ bool* result) {
+ NAPI_PREAMBLE(env);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Object> obj;
+
+ CHECK_TO_OBJECT(env, context, obj, object);
+ v8::Maybe<bool> delete_maybe = obj->Delete(context, index);
+ CHECK_MAYBE_NOTHING(env, delete_maybe, napi_generic_failure);
+
+ if (result != NULL)
+ *result = delete_maybe.FromMaybe(false);
+
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_define_properties(napi_env env,
+ napi_value object,
+ size_t property_count,
+ const napi_property_descriptor* properties) {
+ NAPI_PREAMBLE(env);
+ if (property_count > 0) {
+ CHECK_ARG(env, properties);
+ }
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ v8::Local<v8::Object> obj;
+ CHECK_TO_OBJECT(env, context, obj, object);
+
+ for (size_t i = 0; i < property_count; i++) {
+ const napi_property_descriptor* p = &properties[i];
+
+ v8::Local<v8::Name> property_name;
+ napi_status status =
+ v8impl::V8NameFromPropertyDescriptor(env, p, &property_name);
+
+ if (status != napi_ok) {
+ return napi_set_last_error(env, status);
+ }
+
+ v8::PropertyAttribute attributes =
+ v8impl::V8PropertyAttributesFromDescriptor(p);
+
+ if (p->getter != nullptr || p->setter != nullptr) {
+ v8::Local<v8::Value> cbdata = v8impl::CreateAccessorCallbackData(
+ env,
+ p->getter,
+ p->setter,
+ p->data);
+
+ auto set_maybe = obj->SetAccessor(
+ context,
+ property_name,
+ p->getter ? v8impl::GetterCallbackWrapper::Invoke : nullptr,
+ p->setter ? v8impl::SetterCallbackWrapper::Invoke : nullptr,
+ cbdata,
+ v8::AccessControl::DEFAULT,
+ attributes);
+
+ if (!set_maybe.FromMaybe(false)) {
+ return napi_set_last_error(env, napi_invalid_arg);
+ }
+ } else if (p->method != nullptr) {
+ v8::Local<v8::Value> cbdata =
+ v8impl::CreateFunctionCallbackData(env, p->method, p->data);
+
+ CHECK_MAYBE_EMPTY(env, cbdata, napi_generic_failure);
+
+ v8::MaybeLocal<v8::Function> maybe_fn =
+ v8::Function::New(context,
+ v8impl::FunctionCallbackWrapper::Invoke,
+ cbdata);
+
+ CHECK_MAYBE_EMPTY(env, maybe_fn, napi_generic_failure);
+
+ auto define_maybe = obj->DefineOwnProperty(
+ context, property_name, maybe_fn.ToLocalChecked(), attributes);
+
+ if (!define_maybe.FromMaybe(false)) {
+ return napi_set_last_error(env, napi_generic_failure);
+ }
+ } else {
+ v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(p->value);
+
+ auto define_maybe =
+ obj->DefineOwnProperty(context, property_name, value, attributes);
+
+ if (!define_maybe.FromMaybe(false)) {
+ return napi_set_last_error(env, napi_invalid_arg);
+ }
+ }
+ }
+
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_is_array(napi_env env, napi_value value, bool* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+
+ *result = val->IsArray();
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_array_length(napi_env env,
+ napi_value value,
+ uint32_t* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ RETURN_STATUS_IF_FALSE(env, val->IsArray(), napi_array_expected);
+
+ v8::Local<v8::Array> arr = val.As<v8::Array>();
+ *result = arr->Length();
+
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_strict_equals(napi_env env,
+ napi_value lhs,
+ napi_value rhs,
+ bool* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, lhs);
+ CHECK_ARG(env, rhs);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> a = v8impl::V8LocalValueFromJsValue(lhs);
+ v8::Local<v8::Value> b = v8impl::V8LocalValueFromJsValue(rhs);
+
+ *result = a->StrictEquals(b);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_get_prototype(napi_env env,
+ napi_value object,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ v8::Local<v8::Object> obj;
+ CHECK_TO_OBJECT(env, context, obj, object);
+
+ v8::Local<v8::Value> val = obj->GetPrototype();
+ *result = v8impl::JsValueFromV8LocalValue(val);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_create_object(napi_env env, napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ *result = v8impl::JsValueFromV8LocalValue(
+ v8::Object::New(env->isolate));
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_array(napi_env env, napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ *result = v8impl::JsValueFromV8LocalValue(
+ v8::Array::New(env->isolate));
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_array_with_length(napi_env env,
+ size_t length,
+ napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ *result = v8impl::JsValueFromV8LocalValue(
+ v8::Array::New(env->isolate, length));
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_string_latin1(napi_env env,
+ const char* str,
+ size_t length,
+ napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ auto isolate = env->isolate;
+ auto str_maybe =
+ v8::String::NewFromOneByte(isolate,
+ reinterpret_cast<const uint8_t*>(str),
+ v8::NewStringType::kInternalized,
+ length);
+ CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
+
+ *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_string_utf8(napi_env env,
+ const char* str,
+ size_t length,
+ napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::String> s;
+ CHECK_NEW_FROM_UTF8_LEN(env, s, str, length);
+
+ *result = v8impl::JsValueFromV8LocalValue(s);
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_string_utf16(napi_env env,
+ const char16_t* str,
+ size_t length,
+ napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ auto isolate = env->isolate;
+ auto str_maybe =
+ v8::String::NewFromTwoByte(isolate,
+ reinterpret_cast<const uint16_t*>(str),
+ v8::NewStringType::kInternalized,
+ length);
+ CHECK_MAYBE_EMPTY(env, str_maybe, napi_generic_failure);
+
+ *result = v8impl::JsValueFromV8LocalValue(str_maybe.ToLocalChecked());
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_double(napi_env env,
+ double value,
+ napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ *result = v8impl::JsValueFromV8LocalValue(
+ v8::Number::New(env->isolate, value));
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_int32(napi_env env,
+ int32_t value,
+ napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ *result = v8impl::JsValueFromV8LocalValue(
+ v8::Integer::New(env->isolate, value));
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_uint32(napi_env env,
+ uint32_t value,
+ napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ *result = v8impl::JsValueFromV8LocalValue(
+ v8::Integer::NewFromUnsigned(env->isolate, value));
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_int64(napi_env env,
+ int64_t value,
+ napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ *result = v8impl::JsValueFromV8LocalValue(
+ v8::Number::New(env->isolate, static_cast<double>(value)));
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_boolean(napi_env env, bool value, napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+
+ if (value) {
+ *result = v8impl::JsValueFromV8LocalValue(v8::True(isolate));
+ } else {
+ *result = v8impl::JsValueFromV8LocalValue(v8::False(isolate));
+ }
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_symbol(napi_env env,
+ napi_value description,
+ napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+
+ if (description == nullptr) {
+ *result = v8impl::JsValueFromV8LocalValue(v8::Symbol::New(isolate));
+ } else {
+ v8::Local<v8::Value> desc = v8impl::V8LocalValueFromJsValue(description);
+ RETURN_STATUS_IF_FALSE(env, desc->IsString(), napi_string_expected);
+
+ *result = v8impl::JsValueFromV8LocalValue(
+ v8::Symbol::New(isolate, desc.As<v8::String>()));
+ }
+
+ return napi_clear_last_error(env);
+}
+
+static napi_status set_error_code(napi_env env,
+ v8::Local<v8::Value> error,
+ napi_value code,
+ const char* code_cstring) {
+ if ((code != nullptr) || (code_cstring != nullptr)) {
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Object> err_object = error.As<v8::Object>();
+
+ v8::Local<v8::Value> code_value = v8impl::V8LocalValueFromJsValue(code);
+ if (code != nullptr) {
+ code_value = v8impl::V8LocalValueFromJsValue(code);
+ RETURN_STATUS_IF_FALSE(env, code_value->IsString(), napi_string_expected);
+ } else {
+ CHECK_NEW_FROM_UTF8(env, code_value, code_cstring);
+ }
+
+ v8::Local<v8::Name> code_key;
+ CHECK_NEW_FROM_UTF8(env, code_key, "code");
+
+ v8::Maybe<bool> set_maybe = err_object->Set(context, code_key, code_value);
+ RETURN_STATUS_IF_FALSE(env,
+ set_maybe.FromMaybe(false),
+ napi_generic_failure);
+
+ // now update the name to be "name [code]" where name is the
+ // original name and code is the code associated with the Error
+ v8::Local<v8::String> name_string;
+ CHECK_NEW_FROM_UTF8(env, name_string, "");
+ v8::Local<v8::Name> name_key;
+ CHECK_NEW_FROM_UTF8(env, name_key, "name");
+
+ auto maybe_name = err_object->Get(context, name_key);
+ if (!maybe_name.IsEmpty()) {
+ v8::Local<v8::Value> name = maybe_name.ToLocalChecked();
+ if (name->IsString()) {
+ name_string = v8::String::Concat(name_string, name.As<v8::String>());
+ }
+ }
+ name_string = v8::String::Concat(name_string,
+ FIXED_ONE_BYTE_STRING(isolate, " ["));
+ name_string = v8::String::Concat(name_string, code_value.As<v8::String>());
+ name_string = v8::String::Concat(name_string,
+ FIXED_ONE_BYTE_STRING(isolate, "]"));
+
+ set_maybe = err_object->Set(context, name_key, name_string);
+ RETURN_STATUS_IF_FALSE(env,
+ set_maybe.FromMaybe(false),
+ napi_generic_failure);
+ }
+ return napi_ok;
+}
+
+napi_status napi_create_error(napi_env env,
+ napi_value code,
+ napi_value msg,
+ napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, msg);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
+ RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
+
+ v8::Local<v8::Value> error_obj =
+ v8::Exception::Error(message_value.As<v8::String>());
+ napi_status status = set_error_code(env, error_obj, code, nullptr);
+ if (status != napi_ok) return status;
+
+ *result = v8impl::JsValueFromV8LocalValue(error_obj);
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_type_error(napi_env env,
+ napi_value code,
+ napi_value msg,
+ napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, msg);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
+ RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
+
+ v8::Local<v8::Value> error_obj =
+ v8::Exception::TypeError(message_value.As<v8::String>());
+ napi_status status = set_error_code(env, error_obj, code, nullptr);
+ if (status != napi_ok) return status;
+
+ *result = v8impl::JsValueFromV8LocalValue(error_obj);
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_range_error(napi_env env,
+ napi_value code,
+ napi_value msg,
+ napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, msg);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> message_value = v8impl::V8LocalValueFromJsValue(msg);
+ RETURN_STATUS_IF_FALSE(env, message_value->IsString(), napi_string_expected);
+
+ v8::Local<v8::Value> error_obj =
+ v8::Exception::RangeError(message_value.As<v8::String>());
+ napi_status status = set_error_code(env, error_obj, code, nullptr);
+ if (status != napi_ok) return status;
+
+ *result = v8impl::JsValueFromV8LocalValue(error_obj);
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_typeof(napi_env env,
+ napi_value value,
+ napi_valuetype* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> v = v8impl::V8LocalValueFromJsValue(value);
+
+ if (v->IsNumber()) {
+ *result = napi_number;
+ } else if (v->IsString()) {
+ *result = napi_string;
+ } else if (v->IsFunction()) {
+ // This test has to come before IsObject because IsFunction
+ // implies IsObject
+ *result = napi_function;
+ } else if (v->IsExternal()) {
+ // This test has to come before IsObject because IsExternal
+ // implies IsObject
+ *result = napi_external;
+ } else if (v->IsObject()) {
+ *result = napi_object;
+ } else if (v->IsBoolean()) {
+ *result = napi_boolean;
+ } else if (v->IsUndefined()) {
+ *result = napi_undefined;
+ } else if (v->IsSymbol()) {
+ *result = napi_symbol;
+ } else if (v->IsNull()) {
+ *result = napi_null;
+ } else {
+ // Should not get here unless V8 has added some new kind of value.
+ return napi_set_last_error(env, napi_invalid_arg);
+ }
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_undefined(napi_env env, napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ *result = v8impl::JsValueFromV8LocalValue(
+ v8::Undefined(env->isolate));
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_null(napi_env env, napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ *result = v8impl::JsValueFromV8LocalValue(
+ v8::Null(env->isolate));
+
+ return napi_clear_last_error(env);
+}
+
+// Gets all callback info in a single call. (Ugly, but faster.)
+napi_status napi_get_cb_info(
+ napi_env env, // [in] NAPI environment handle
+ napi_callback_info cbinfo, // [in] Opaque callback-info handle
+ size_t* argc, // [in-out] Specifies the size of the provided argv array
+ // and receives the actual count of args.
+ napi_value* argv, // [out] Array of values
+ napi_value* this_arg, // [out] Receives the JS 'this' arg for the call
+ void** data) { // [out] Receives the data pointer for the callback.
+ CHECK_ENV(env);
+ CHECK_ARG(env, cbinfo);
+
+ v8impl::CallbackWrapper* info =
+ reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
+
+ if (argv != nullptr) {
+ CHECK_ARG(env, argc);
+ info->Args(argv, *argc);
+ }
+ if (argc != nullptr) {
+ *argc = info->ArgsLength();
+ }
+ if (this_arg != nullptr) {
+ *this_arg = info->This();
+ }
+ if (data != nullptr) {
+ *data = info->Data();
+ }
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_new_target(napi_env env,
+ napi_callback_info cbinfo,
+ napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, cbinfo);
+ CHECK_ARG(env, result);
+
+ v8impl::CallbackWrapper* info =
+ reinterpret_cast<v8impl::CallbackWrapper*>(cbinfo);
+
+ *result = info->GetNewTarget();
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_call_function(napi_env env,
+ napi_value recv,
+ napi_value func,
+ size_t argc,
+ const napi_value* argv,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, recv);
+ if (argc > 0) {
+ CHECK_ARG(env, argv);
+ }
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ v8::Local<v8::Value> v8recv = v8impl::V8LocalValueFromJsValue(recv);
+
+ v8::Local<v8::Function> v8func;
+ CHECK_TO_FUNCTION(env, v8func, func);
+
+ auto maybe = v8func->Call(context, v8recv, argc,
+ reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
+
+ if (try_catch.HasCaught()) {
+ return napi_set_last_error(env, napi_pending_exception);
+ } else {
+ if (result != nullptr) {
+ CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
+ *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
+ }
+ return napi_clear_last_error(env);
+ }
+}
+
+napi_status napi_get_global(napi_env env, napi_value* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ // TODO(ianhall): what if we need the global object from a different
+ // context in the same isolate?
+ // Should napi_env be the current context rather than the current isolate?
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ *result = v8impl::JsValueFromV8LocalValue(context->Global());
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_throw(napi_env env, napi_value error) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, error);
+
+ v8::Isolate* isolate = env->isolate;
+
+ isolate->ThrowException(v8impl::V8LocalValueFromJsValue(error));
+ // any VM calls after this point and before returning
+ // to the javascript invoker will fail
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_throw_error(napi_env env,
+ const char* code,
+ const char* msg) {
+ NAPI_PREAMBLE(env);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::String> str;
+ CHECK_NEW_FROM_UTF8(env, str, msg);
+
+ v8::Local<v8::Value> error_obj = v8::Exception::Error(str);
+ napi_status status = set_error_code(env, error_obj, nullptr, code);
+ if (status != napi_ok) return status;
+
+ isolate->ThrowException(error_obj);
+ // any VM calls after this point and before returning
+ // to the javascript invoker will fail
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_throw_type_error(napi_env env,
+ const char* code,
+ const char* msg) {
+ NAPI_PREAMBLE(env);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::String> str;
+ CHECK_NEW_FROM_UTF8(env, str, msg);
+
+ v8::Local<v8::Value> error_obj = v8::Exception::TypeError(str);
+ napi_status status = set_error_code(env, error_obj, nullptr, code);
+ if (status != napi_ok) return status;
+
+ isolate->ThrowException(error_obj);
+ // any VM calls after this point and before returning
+ // to the javascript invoker will fail
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_throw_range_error(napi_env env,
+ const char* code,
+ const char* msg) {
+ NAPI_PREAMBLE(env);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::String> str;
+ CHECK_NEW_FROM_UTF8(env, str, msg);
+
+ v8::Local<v8::Value> error_obj = v8::Exception::RangeError(str);
+ napi_status status = set_error_code(env, error_obj, nullptr, code);
+ if (status != napi_ok) return status;
+
+ isolate->ThrowException(error_obj);
+ // any VM calls after this point and before returning
+ // to the javascript invoker will fail
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_is_error(napi_env env, napi_value value, bool* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot
+ // throw JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ *result = val->IsNativeError();
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_value_double(napi_env env,
+ napi_value value,
+ double* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
+
+ *result = val.As<v8::Number>()->Value();
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_value_int32(napi_env env,
+ napi_value value,
+ int32_t* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+
+ if (val->IsInt32()) {
+ *result = val.As<v8::Int32>()->Value();
+ } else {
+ RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
+
+ // Empty context: https://github.com/nodejs/node/issues/14379
+ v8::Local<v8::Context> context;
+ *result = val->Int32Value(context).FromJust();
+ }
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_value_uint32(napi_env env,
+ napi_value value,
+ uint32_t* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+
+ if (val->IsUint32()) {
+ *result = val.As<v8::Uint32>()->Value();
+ } else {
+ RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
+
+ // Empty context: https://github.com/nodejs/node/issues/14379
+ v8::Local<v8::Context> context;
+ *result = val->Uint32Value(context).FromJust();
+ }
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_value_int64(napi_env env,
+ napi_value value,
+ int64_t* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+
+ // This is still a fast path very likely to be taken.
+ if (val->IsInt32()) {
+ *result = val.As<v8::Int32>()->Value();
+ return napi_clear_last_error(env);
+ }
+
+ RETURN_STATUS_IF_FALSE(env, val->IsNumber(), napi_number_expected);
+
+ // v8::Value::IntegerValue() converts NaN to INT64_MIN, inconsistent with
+ // v8::Value::Int32Value() that converts NaN to 0. So special-case NaN here.
+ double doubleValue = val.As<v8::Number>()->Value();
+ if (std::isnan(doubleValue)) {
+ *result = 0;
+ } else {
+ // Empty context: https://github.com/nodejs/node/issues/14379
+ v8::Local<v8::Context> context;
+ *result = val->IntegerValue(context).FromJust();
+ }
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ RETURN_STATUS_IF_FALSE(env, val->IsBoolean(), napi_boolean_expected);
+
+ *result = val.As<v8::Boolean>()->Value();
+
+ return napi_clear_last_error(env);
+}
+
+// Copies a JavaScript string into a LATIN-1 string buffer. The result is the
+// number of bytes (excluding the null terminator) copied into buf.
+// A sufficient buffer size should be greater than the length of string,
+// reserving space for null terminator.
+// If bufsize is insufficient, the string will be truncated and null terminated.
+// If buf is NULL, this method returns the length of the string (in bytes)
+// via the result parameter.
+// The result argument is optional unless buf is NULL.
+napi_status napi_get_value_string_latin1(napi_env env,
+ napi_value value,
+ char* buf,
+ size_t bufsize,
+ size_t* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
+
+ if (!buf) {
+ CHECK_ARG(env, result);
+ *result = val.As<v8::String>()->Length();
+ } else {
+ int copied = val.As<v8::String>()->WriteOneByte(
+ reinterpret_cast<uint8_t*>(buf), 0, bufsize - 1,
+ v8::String::NO_NULL_TERMINATION);
+
+ buf[copied] = '\0';
+ if (result != nullptr) {
+ *result = copied;
+ }
+ }
+
+ return napi_clear_last_error(env);
+}
+
+// Copies a JavaScript string into a UTF-8 string buffer. The result is the
+// number of bytes (excluding the null terminator) copied into buf.
+// A sufficient buffer size should be greater than the length of string,
+// reserving space for null terminator.
+// If bufsize is insufficient, the string will be truncated and null terminated.
+// If buf is NULL, this method returns the length of the string (in bytes)
+// via the result parameter.
+// The result argument is optional unless buf is NULL.
+napi_status napi_get_value_string_utf8(napi_env env,
+ napi_value value,
+ char* buf,
+ size_t bufsize,
+ size_t* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
+
+ if (!buf) {
+ CHECK_ARG(env, result);
+ *result = val.As<v8::String>()->Utf8Length();
+ } else {
+ int copied = val.As<v8::String>()->WriteUtf8(
+ buf, bufsize - 1, nullptr, v8::String::REPLACE_INVALID_UTF8 |
+ v8::String::NO_NULL_TERMINATION);
+
+ buf[copied] = '\0';
+ if (result != nullptr) {
+ *result = copied;
+ }
+ }
+
+ return napi_clear_last_error(env);
+}
+
+// Copies a JavaScript string into a UTF-16 string buffer. The result is the
+// number of 2-byte code units (excluding the null terminator) copied into buf.
+// A sufficient buffer size should be greater than the length of string,
+// reserving space for null terminator.
+// If bufsize is insufficient, the string will be truncated and null terminated.
+// If buf is NULL, this method returns the length of the string (in 2-byte
+// code units) via the result parameter.
+// The result argument is optional unless buf is NULL.
+napi_status napi_get_value_string_utf16(napi_env env,
+ napi_value value,
+ char16_t* buf,
+ size_t bufsize,
+ size_t* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ RETURN_STATUS_IF_FALSE(env, val->IsString(), napi_string_expected);
+
+ if (!buf) {
+ CHECK_ARG(env, result);
+ // V8 assumes UTF-16 length is the same as the number of characters.
+ *result = val.As<v8::String>()->Length();
+ } else {
+ int copied = val.As<v8::String>()->Write(
+ reinterpret_cast<uint16_t*>(buf), 0, bufsize - 1,
+ v8::String::NO_NULL_TERMINATION);
+
+ buf[copied] = '\0';
+ if (result != nullptr) {
+ *result = copied;
+ }
+ }
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_coerce_to_object(napi_env env,
+ napi_value value,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Object> obj;
+ CHECK_TO_OBJECT(env, context, obj, value);
+
+ *result = v8impl::JsValueFromV8LocalValue(obj);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_coerce_to_bool(napi_env env,
+ napi_value value,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Boolean> b;
+
+ CHECK_TO_BOOL(env, context, b, value);
+
+ *result = v8impl::JsValueFromV8LocalValue(b);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_coerce_to_number(napi_env env,
+ napi_value value,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Number> num;
+
+ CHECK_TO_NUMBER(env, context, num, value);
+
+ *result = v8impl::JsValueFromV8LocalValue(num);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_coerce_to_string(napi_env env,
+ napi_value value,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::String> str;
+
+ CHECK_TO_STRING(env, context, str, value);
+
+ *result = v8impl::JsValueFromV8LocalValue(str);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_wrap(napi_env env,
+ napi_value js_object,
+ void* native_object,
+ napi_finalize finalize_cb,
+ void* finalize_hint,
+ napi_ref* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, js_object);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(js_object);
+ RETURN_STATUS_IF_FALSE(env, value->IsObject(), napi_invalid_arg);
+ v8::Local<v8::Object> obj = value.As<v8::Object>();
+
+ // If we've already wrapped this object, we error out.
+ RETURN_STATUS_IF_FALSE(env, !v8impl::FindWrapper(obj), napi_invalid_arg);
+
+ // Create a wrapper object with an internal field to hold the wrapped pointer
+ // and a second internal field to identify the owner as N-API.
+ v8::Local<v8::ObjectTemplate> wrapper_template;
+ ENV_OBJECT_TEMPLATE(env, wrap, wrapper_template, v8impl::kWrapperFields);
+
+ auto maybe_object = wrapper_template->NewInstance(context);
+ CHECK_MAYBE_EMPTY(env, maybe_object, napi_generic_failure);
+ v8::Local<v8::Object> wrapper = maybe_object.ToLocalChecked();
+
+ // Store the pointer as an external in the wrapper.
+ wrapper->SetInternalField(0, v8::External::New(isolate, native_object));
+ wrapper->SetInternalField(1, v8::External::New(isolate,
+ reinterpret_cast<void*>(const_cast<char*>(v8impl::napi_wrap_name))));
+
+ // Insert the wrapper into the object's prototype chain.
+ v8::Local<v8::Value> proto = obj->GetPrototype();
+ CHECK(wrapper->SetPrototype(context, proto).FromJust());
+ CHECK(obj->SetPrototype(context, wrapper).FromJust());
+
+ v8impl::Reference* reference = nullptr;
+ if (result != nullptr) {
+ // The returned reference should be deleted via napi_delete_reference()
+ // ONLY in response to the finalize callback invocation. (If it is deleted
+ // before then, then the finalize callback will never be invoked.)
+ // Therefore a finalize callback is required when returning a reference.
+ CHECK_ARG(env, finalize_cb);
+ reference = v8impl::Reference::New(
+ env, obj, 0, false, finalize_cb, native_object, finalize_hint);
+ *result = reinterpret_cast<napi_ref>(reference);
+ } else if (finalize_cb != nullptr) {
+ // Create a self-deleting reference just for the finalize callback.
+ reference = v8impl::Reference::New(
+ env, obj, 0, true, finalize_cb, native_object, finalize_hint);
+ }
+
+ if (reference != nullptr) {
+ wrapper->SetInternalField(2, v8::External::New(isolate, reference));
+ }
+
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_unwrap(napi_env env, napi_value obj, void** result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ v8::Local<v8::Object> wrapper;
+ return napi_set_last_error(env, v8impl::Unwrap(env, obj, result, &wrapper));
+}
+
+napi_status napi_remove_wrap(napi_env env, napi_value obj, void** result) {
+ NAPI_PREAMBLE(env);
+ v8::Local<v8::Object> wrapper;
+ v8::Local<v8::Object> parent;
+ napi_status status = v8impl::Unwrap(env, obj, result, &wrapper, &parent);
+ if (status != napi_ok) {
+ return napi_set_last_error(env, status);
+ }
+
+ v8::Local<v8::Value> external = wrapper->GetInternalField(2);
+ if (external->IsExternal()) {
+ v8impl::Reference::Delete(
+ static_cast<v8impl::Reference*>(external.As<v8::External>()->Value()));
+ }
+
+ if (!parent.IsEmpty()) {
+ v8::Maybe<bool> maybe = parent->SetPrototype(
+ env->isolate->GetCurrentContext(), wrapper->GetPrototype());
+ CHECK_MAYBE_NOTHING(env, maybe, napi_generic_failure);
+ if (!maybe.FromMaybe(false)) {
+ return napi_set_last_error(env, napi_generic_failure);
+ }
+ }
+
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_create_external(napi_env env,
+ void* data,
+ napi_finalize finalize_cb,
+ void* finalize_hint,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+
+ v8::Local<v8::Value> external_value = v8::External::New(isolate, data);
+
+ // The Reference object will delete itself after invoking the finalizer
+ // callback.
+ v8impl::Reference::New(env,
+ external_value,
+ 0,
+ true,
+ finalize_cb,
+ data,
+ finalize_hint);
+
+ *result = v8impl::JsValueFromV8LocalValue(external_value);
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_value_external(napi_env env,
+ napi_value value,
+ void** result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ RETURN_STATUS_IF_FALSE(env, val->IsExternal(), napi_invalid_arg);
+
+ v8::Local<v8::External> external_value = val.As<v8::External>();
+ *result = external_value->Value();
+
+ return napi_clear_last_error(env);
+}
+
+// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
+napi_status napi_create_reference(napi_env env,
+ napi_value value,
+ uint32_t initial_refcount,
+ napi_ref* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> v8_value = v8impl::V8LocalValueFromJsValue(value);
+
+ if (!(v8_value->IsObject() || v8_value->IsFunction())) {
+ return napi_set_last_error(env, napi_object_expected);
+ }
+
+ v8impl::Reference* reference =
+ v8impl::Reference::New(env, v8_value, initial_refcount, false);
+
+ *result = reinterpret_cast<napi_ref>(reference);
+ return napi_clear_last_error(env);
+}
+
+// Deletes a reference. The referenced value is released, and may be GC'd unless
+// there are other references to it.
+napi_status napi_delete_reference(napi_env env, napi_ref ref) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, ref);
+
+ v8impl::Reference::Delete(reinterpret_cast<v8impl::Reference*>(ref));
+
+ return napi_clear_last_error(env);
+}
+
+// Increments the reference count, optionally returning the resulting count.
+// After this call the reference will be a strong reference because its
+// refcount is >0, and the referenced object is effectively "pinned".
+// Calling this when the refcount is 0 and the object is unavailable
+// results in an error.
+napi_status napi_reference_ref(napi_env env, napi_ref ref, uint32_t* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, ref);
+
+ v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
+ uint32_t count = reference->Ref();
+
+ if (result != nullptr) {
+ *result = count;
+ }
+
+ return napi_clear_last_error(env);
+}
+
+// Decrements the reference count, optionally returning the resulting count. If
+// the result is 0 the reference is now weak and the object may be GC'd at any
+// time if there are no other references. Calling this when the refcount is
+// already 0 results in an error.
+napi_status napi_reference_unref(napi_env env, napi_ref ref, uint32_t* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, ref);
+
+ v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
+
+ if (reference->RefCount() == 0) {
+ return napi_set_last_error(env, napi_generic_failure);
+ }
+
+ uint32_t count = reference->Unref();
+
+ if (result != nullptr) {
+ *result = count;
+ }
+
+ return napi_clear_last_error(env);
+}
+
+// Attempts to get a referenced value. If the reference is weak, the value might
+// no longer be available, in that case the call is still successful but the
+// result is NULL.
+napi_status napi_get_reference_value(napi_env env,
+ napi_ref ref,
+ napi_value* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, ref);
+ CHECK_ARG(env, result);
+
+ v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
+ *result = v8impl::JsValueFromV8LocalValue(reference->Get());
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_open_handle_scope(napi_env env, napi_handle_scope* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ *result = v8impl::JsHandleScopeFromV8HandleScope(
+ new v8impl::HandleScopeWrapper(env->isolate));
+ env->open_handle_scopes++;
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_close_handle_scope(napi_env env, napi_handle_scope scope) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, scope);
+ if (env->open_handle_scopes == 0) {
+ return napi_handle_scope_mismatch;
+ }
+
+ env->open_handle_scopes--;
+ delete v8impl::V8HandleScopeFromJsHandleScope(scope);
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_open_escapable_handle_scope(
+ napi_env env,
+ napi_escapable_handle_scope* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ *result = v8impl::JsEscapableHandleScopeFromV8EscapableHandleScope(
+ new v8impl::EscapableHandleScopeWrapper(env->isolate));
+ env->open_handle_scopes++;
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_close_escapable_handle_scope(
+ napi_env env,
+ napi_escapable_handle_scope scope) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, scope);
+ if (env->open_handle_scopes == 0) {
+ return napi_handle_scope_mismatch;
+ }
+
+ delete v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope);
+ env->open_handle_scopes--;
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_escape_handle(napi_env env,
+ napi_escapable_handle_scope scope,
+ napi_value escapee,
+ napi_value* result) {
+ // Omit NAPI_PREAMBLE and GET_RETURN_STATUS because V8 calls here cannot throw
+ // JS exceptions.
+ CHECK_ENV(env);
+ CHECK_ARG(env, scope);
+ CHECK_ARG(env, escapee);
+ CHECK_ARG(env, result);
+
+ v8impl::EscapableHandleScopeWrapper* s =
+ v8impl::V8EscapableHandleScopeFromJsEscapableHandleScope(scope);
+ if (!s->escape_called()) {
+ *result = v8impl::JsValueFromV8LocalValue(
+ s->Escape(v8impl::V8LocalValueFromJsValue(escapee)));
+ return napi_clear_last_error(env);
+ }
+ return napi_set_last_error(env, napi_escape_called_twice);
+}
+
+napi_status napi_new_instance(napi_env env,
+ napi_value constructor,
+ size_t argc,
+ const napi_value* argv,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, constructor);
+ if (argc > 0) {
+ CHECK_ARG(env, argv);
+ }
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ v8::Local<v8::Function> ctor;
+ CHECK_TO_FUNCTION(env, ctor, constructor);
+
+ auto maybe = ctor->NewInstance(context, argc,
+ reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)));
+
+ CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
+
+ *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_instanceof(napi_env env,
+ napi_value object,
+ napi_value constructor,
+ bool* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, object);
+ CHECK_ARG(env, result);
+
+ *result = false;
+
+ v8::Local<v8::Object> ctor;
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ CHECK_TO_OBJECT(env, context, ctor, constructor);
+
+ if (!ctor->IsFunction()) {
+ napi_throw_type_error(env,
+ "ERR_NAPI_CONS_FUNCTION",
+ "Constructor must be a function");
+
+ return napi_set_last_error(env, napi_function_expected);
+ }
+
+ if (env->has_instance_available) {
+ napi_value value, js_result = nullptr, has_instance = nullptr;
+ napi_status status = napi_generic_failure;
+ napi_valuetype value_type;
+
+ // Get "Symbol" from the global object
+ if (env->has_instance.IsEmpty()) {
+ status = napi_get_global(env, &value);
+ if (status != napi_ok) return status;
+ status = napi_get_named_property(env, value, "Symbol", &value);
+ if (status != napi_ok) return status;
+ status = napi_typeof(env, value, &value_type);
+ if (status != napi_ok) return status;
+
+ // Get "hasInstance" from Symbol
+ if (value_type == napi_function) {
+ status = napi_get_named_property(env, value, "hasInstance", &value);
+ if (status != napi_ok) return status;
+ status = napi_typeof(env, value, &value_type);
+ if (status != napi_ok) return status;
+
+ // Store Symbol.hasInstance in a global persistent reference
+ if (value_type == napi_symbol) {
+ env->has_instance.Reset(env->isolate,
+ v8impl::V8LocalValueFromJsValue(value));
+ has_instance = value;
+ }
+ }
+ } else {
+ has_instance = v8impl::JsValueFromV8LocalValue(
+ v8::Local<v8::Value>::New(env->isolate, env->has_instance));
+ }
+
+ if (has_instance) {
+ status = napi_get_property(env, constructor, has_instance, &value);
+ if (status != napi_ok) return status;
+ status = napi_typeof(env, value, &value_type);
+ if (status != napi_ok) return status;
+
+ // Call the function to determine whether the object is an instance of the
+ // constructor
+ if (value_type == napi_function) {
+ status = napi_call_function(env, constructor, value, 1, &object,
+ &js_result);
+ if (status != napi_ok) return status;
+ return napi_get_value_bool(env, js_result, result);
+ }
+ }
+
+ env->has_instance_available = false;
+ }
+
+ // If running constructor[Symbol.hasInstance](object) did not work, we perform
+ // a traditional instanceof (early Node.js 6.x).
+
+ v8::Local<v8::String> prototype_string;
+ CHECK_NEW_FROM_UTF8(env, prototype_string, "prototype");
+
+ auto maybe_prototype = ctor->Get(context, prototype_string);
+ CHECK_MAYBE_EMPTY(env, maybe_prototype, napi_generic_failure);
+
+ v8::Local<v8::Value> prototype_property = maybe_prototype.ToLocalChecked();
+ if (!prototype_property->IsObject()) {
+ napi_throw_type_error(
+ env,
+ "ERR_NAPI_CONS_PROTOTYPE_OBJECT",
+ "Constructor.prototype must be an object");
+
+ return napi_set_last_error(env, napi_object_expected);
+ }
+
+ auto maybe_ctor = prototype_property->ToObject(context);
+ CHECK_MAYBE_EMPTY(env, maybe_ctor, napi_generic_failure);
+ ctor = maybe_ctor.ToLocalChecked();
+
+ v8::Local<v8::Value> current_obj = v8impl::V8LocalValueFromJsValue(object);
+ if (!current_obj->StrictEquals(ctor)) {
+ for (v8::Local<v8::Value> original_obj = current_obj;
+ !(current_obj->IsNull() || current_obj->IsUndefined());) {
+ if (current_obj->StrictEquals(ctor)) {
+ *result = !(original_obj->IsNumber() ||
+ original_obj->IsBoolean() ||
+ original_obj->IsString());
+ break;
+ }
+ v8::Local<v8::Object> obj;
+ CHECK_TO_OBJECT(env, context, obj, v8impl::JsValueFromV8LocalValue(
+ current_obj));
+ current_obj = obj->GetPrototype();
+ }
+ }
+
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_async_init(napi_env env,
+ napi_value async_resource,
+ napi_value async_resource_name,
+ napi_async_context* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, async_resource_name);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ v8::Local<v8::Object> v8_resource;
+ if (async_resource != nullptr) {
+ CHECK_TO_OBJECT(env, context, v8_resource, async_resource);
+ } else {
+ v8_resource = v8::Object::New(isolate);
+ }
+
+ v8::Local<v8::String> v8_resource_name;
+ CHECK_TO_STRING(env, context, v8_resource_name, async_resource_name);
+
+ // TODO(jasongin): Consider avoiding allocation here by using
+ // a tagged pointer with 2×31 bit fields instead.
+ node::async_context* async_context = new node::async_context();
+
+ *async_context = node::EmitAsyncInit(isolate, v8_resource, v8_resource_name);
+ *result = reinterpret_cast<napi_async_context>(async_context);
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_async_destroy(napi_env env,
+ napi_async_context async_context) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, async_context);
+
+ v8::Isolate* isolate = env->isolate;
+ node::async_context* node_async_context =
+ reinterpret_cast<node::async_context*>(async_context);
+ node::EmitAsyncDestroy(isolate, *node_async_context);
+
+ delete node_async_context;
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_make_callback(napi_env env,
+ napi_async_context async_context,
+ napi_value recv,
+ napi_value func,
+ size_t argc,
+ const napi_value* argv,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, recv);
+ if (argc > 0) {
+ CHECK_ARG(env, argv);
+ }
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+
+ v8::Local<v8::Object> v8recv;
+ CHECK_TO_OBJECT(env, context, v8recv, recv);
+
+ v8::Local<v8::Function> v8func;
+ CHECK_TO_FUNCTION(env, v8func, func);
+
+ node::async_context* node_async_context =
+ reinterpret_cast<node::async_context*>(async_context);
+ if (node_async_context == nullptr) {
+ static node::async_context empty_context = { 0, 0 };
+ node_async_context = &empty_context;
+ }
+
+ v8::MaybeLocal<v8::Value> callback_result = node::MakeCallback(
+ isolate, v8recv, v8func, argc,
+ reinterpret_cast<v8::Local<v8::Value>*>(const_cast<napi_value*>(argv)),
+ *node_async_context);
+ CHECK_MAYBE_EMPTY(env, callback_result, napi_generic_failure);
+
+ if (result != nullptr) {
+ *result = v8impl::JsValueFromV8LocalValue(
+ callback_result.ToLocalChecked());
+ }
+
+ return GET_RETURN_STATUS(env);
+}
+
+// Methods to support catching exceptions
+napi_status napi_is_exception_pending(napi_env env, bool* result) {
+ // NAPI_PREAMBLE is not used here: this function must execute when there is a
+ // pending exception.
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ *result = !env->last_exception.IsEmpty();
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_and_clear_last_exception(napi_env env,
+ napi_value* result) {
+ // NAPI_PREAMBLE is not used here: this function must execute when there is a
+ // pending exception.
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+
+ if (env->last_exception.IsEmpty()) {
+ return napi_get_undefined(env, result);
+ } else {
+ *result = v8impl::JsValueFromV8LocalValue(
+ v8::Local<v8::Value>::New(env->isolate, env->last_exception));
+ env->last_exception.Reset();
+ }
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_buffer(napi_env env,
+ size_t length,
+ void** data,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+
+ auto maybe = node::Buffer::New(env->isolate, length);
+
+ CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
+
+ v8::Local<v8::Object> buffer = maybe.ToLocalChecked();
+
+ *result = v8impl::JsValueFromV8LocalValue(buffer);
+
+ if (data != nullptr) {
+ *data = node::Buffer::Data(buffer);
+ }
+
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_create_external_buffer(napi_env env,
+ size_t length,
+ void* data,
+ napi_finalize finalize_cb,
+ void* finalize_hint,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+
+ // The finalizer object will delete itself after invoking the callback.
+ v8impl::Finalizer* finalizer = v8impl::Finalizer::New(
+ env, finalize_cb, nullptr, finalize_hint);
+
+ auto maybe = node::Buffer::New(isolate,
+ static_cast<char*>(data),
+ length,
+ v8impl::Finalizer::FinalizeBufferCallback,
+ finalizer);
+
+ CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
+
+ *result = v8impl::JsValueFromV8LocalValue(maybe.ToLocalChecked());
+ return GET_RETURN_STATUS(env);
+ // Tell coverity that 'finalizer' should not be freed when we return
+ // as it will be deleted when the buffer to which it is associated
+ // is finalized.
+ // coverity[leaked_storage]
+}
+
+napi_status napi_create_buffer_copy(napi_env env,
+ size_t length,
+ const void* data,
+ void** result_data,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+
+ auto maybe = node::Buffer::Copy(env->isolate,
+ static_cast<const char*>(data), length);
+
+ CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
+
+ v8::Local<v8::Object> buffer = maybe.ToLocalChecked();
+ *result = v8impl::JsValueFromV8LocalValue(buffer);
+
+ if (result_data != nullptr) {
+ *result_data = node::Buffer::Data(buffer);
+ }
+
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_is_buffer(napi_env env, napi_value value, bool* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ *result = node::Buffer::HasInstance(v8impl::V8LocalValueFromJsValue(value));
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_buffer_info(napi_env env,
+ napi_value value,
+ void** data,
+ size_t* length) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+
+ v8::Local<v8::Value> buffer = v8impl::V8LocalValueFromJsValue(value);
+
+ if (data != nullptr) {
+ *data = node::Buffer::Data(buffer);
+ }
+ if (length != nullptr) {
+ *length = node::Buffer::Length(buffer);
+ }
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_is_arraybuffer(napi_env env, napi_value value, bool* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ *result = val->IsArrayBuffer();
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_arraybuffer(napi_env env,
+ size_t byte_length,
+ void** data,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::ArrayBuffer> buffer =
+ v8::ArrayBuffer::New(isolate, byte_length);
+
+ // Optionally return a pointer to the buffer's data, to avoid another call to
+ // retrieve it.
+ if (data != nullptr) {
+ *data = buffer->GetContents().Data();
+ }
+
+ *result = v8impl::JsValueFromV8LocalValue(buffer);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_create_external_arraybuffer(napi_env env,
+ void* external_data,
+ size_t byte_length,
+ napi_finalize finalize_cb,
+ void* finalize_hint,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, result);
+
+ v8::Isolate* isolate = env->isolate;
+ v8::Local<v8::ArrayBuffer> buffer =
+ v8::ArrayBuffer::New(isolate, external_data, byte_length);
+
+ if (finalize_cb != nullptr) {
+ // Create a self-deleting weak reference that invokes the finalizer
+ // callback.
+ v8impl::Reference::New(env,
+ buffer,
+ 0,
+ true,
+ finalize_cb,
+ external_data,
+ finalize_hint);
+ }
+
+ *result = v8impl::JsValueFromV8LocalValue(buffer);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_get_arraybuffer_info(napi_env env,
+ napi_value arraybuffer,
+ void** data,
+ size_t* byte_length) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, arraybuffer);
+
+ v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
+ RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
+
+ v8::ArrayBuffer::Contents contents =
+ value.As<v8::ArrayBuffer>()->GetContents();
+
+ if (data != nullptr) {
+ *data = contents.Data();
+ }
+
+ if (byte_length != nullptr) {
+ *byte_length = contents.ByteLength();
+ }
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_is_typedarray(napi_env env, napi_value value, bool* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ *result = val->IsTypedArray();
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_typedarray(napi_env env,
+ napi_typedarray_type type,
+ size_t length,
+ napi_value arraybuffer,
+ size_t byte_offset,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, arraybuffer);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
+ RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
+
+ v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
+ v8::Local<v8::TypedArray> typedArray;
+
+ switch (type) {
+ case napi_int8_array:
+ CREATE_TYPED_ARRAY(
+ env, Int8Array, 1, buffer, byte_offset, length, typedArray);
+ break;
+ case napi_uint8_array:
+ CREATE_TYPED_ARRAY(
+ env, Uint8Array, 1, buffer, byte_offset, length, typedArray);
+ break;
+ case napi_uint8_clamped_array:
+ CREATE_TYPED_ARRAY(
+ env, Uint8ClampedArray, 1, buffer, byte_offset, length, typedArray);
+ break;
+ case napi_int16_array:
+ CREATE_TYPED_ARRAY(
+ env, Int16Array, 2, buffer, byte_offset, length, typedArray);
+ break;
+ case napi_uint16_array:
+ CREATE_TYPED_ARRAY(
+ env, Uint16Array, 2, buffer, byte_offset, length, typedArray);
+ break;
+ case napi_int32_array:
+ CREATE_TYPED_ARRAY(
+ env, Int32Array, 4, buffer, byte_offset, length, typedArray);
+ break;
+ case napi_uint32_array:
+ CREATE_TYPED_ARRAY(
+ env, Uint32Array, 4, buffer, byte_offset, length, typedArray);
+ break;
+ case napi_float32_array:
+ CREATE_TYPED_ARRAY(
+ env, Float32Array, 4, buffer, byte_offset, length, typedArray);
+ break;
+ case napi_float64_array:
+ CREATE_TYPED_ARRAY(
+ env, Float64Array, 8, buffer, byte_offset, length, typedArray);
+ break;
+ default:
+ return napi_set_last_error(env, napi_invalid_arg);
+ }
+
+ *result = v8impl::JsValueFromV8LocalValue(typedArray);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_get_typedarray_info(napi_env env,
+ napi_value typedarray,
+ napi_typedarray_type* type,
+ size_t* length,
+ void** data,
+ napi_value* arraybuffer,
+ size_t* byte_offset) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, typedarray);
+
+ v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(typedarray);
+ RETURN_STATUS_IF_FALSE(env, value->IsTypedArray(), napi_invalid_arg);
+
+ v8::Local<v8::TypedArray> array = value.As<v8::TypedArray>();
+
+ if (type != nullptr) {
+ if (value->IsInt8Array()) {
+ *type = napi_int8_array;
+ } else if (value->IsUint8Array()) {
+ *type = napi_uint8_array;
+ } else if (value->IsUint8ClampedArray()) {
+ *type = napi_uint8_clamped_array;
+ } else if (value->IsInt16Array()) {
+ *type = napi_int16_array;
+ } else if (value->IsUint16Array()) {
+ *type = napi_uint16_array;
+ } else if (value->IsInt32Array()) {
+ *type = napi_int32_array;
+ } else if (value->IsUint32Array()) {
+ *type = napi_uint32_array;
+ } else if (value->IsFloat32Array()) {
+ *type = napi_float32_array;
+ } else if (value->IsFloat64Array()) {
+ *type = napi_float64_array;
+ }
+ }
+
+ if (length != nullptr) {
+ *length = array->Length();
+ }
+
+ v8::Local<v8::ArrayBuffer> buffer = array->Buffer();
+ if (data != nullptr) {
+ *data = static_cast<uint8_t*>(buffer->GetContents().Data()) +
+ array->ByteOffset();
+ }
+
+ if (arraybuffer != nullptr) {
+ *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
+ }
+
+ if (byte_offset != nullptr) {
+ *byte_offset = array->ByteOffset();
+ }
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_dataview(napi_env env,
+ size_t byte_length,
+ napi_value arraybuffer,
+ size_t byte_offset,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, arraybuffer);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(arraybuffer);
+ RETURN_STATUS_IF_FALSE(env, value->IsArrayBuffer(), napi_invalid_arg);
+
+ v8::Local<v8::ArrayBuffer> buffer = value.As<v8::ArrayBuffer>();
+ if (byte_length + byte_offset > buffer->ByteLength()) {
+ napi_throw_range_error(
+ env,
+ "ERR_NAPI_INVALID_DATAVIEW_ARGS",
+ "byte_offset + byte_length should be less than or "
+ "equal to the size in bytes of the array passed in");
+ return napi_set_last_error(env, napi_generic_failure);
+ }
+ v8::Local<v8::DataView> DataView = v8::DataView::New(buffer, byte_offset,
+ byte_length);
+
+ *result = v8impl::JsValueFromV8LocalValue(DataView);
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_is_dataview(napi_env env, napi_value value, bool* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, value);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
+ *result = val->IsDataView();
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_dataview_info(napi_env env,
+ napi_value dataview,
+ size_t* byte_length,
+ void** data,
+ napi_value* arraybuffer,
+ size_t* byte_offset) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, dataview);
+
+ v8::Local<v8::Value> value = v8impl::V8LocalValueFromJsValue(dataview);
+ RETURN_STATUS_IF_FALSE(env, value->IsDataView(), napi_invalid_arg);
+
+ v8::Local<v8::DataView> array = value.As<v8::DataView>();
+
+ if (byte_length != nullptr) {
+ *byte_length = array->ByteLength();
+ }
+
+ v8::Local<v8::ArrayBuffer> buffer = array->Buffer();
+ if (data != nullptr) {
+ *data = static_cast<uint8_t*>(buffer->GetContents().Data()) +
+ array->ByteOffset();
+ }
+
+ if (arraybuffer != nullptr) {
+ *arraybuffer = v8impl::JsValueFromV8LocalValue(buffer);
+ }
+
+ if (byte_offset != nullptr) {
+ *byte_offset = array->ByteOffset();
+ }
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_version(napi_env env, uint32_t* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+ *result = NAPI_VERSION;
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_get_node_version(napi_env env,
+ const napi_node_version** result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, result);
+ static const napi_node_version version = {
+ NODE_MAJOR_VERSION,
+ NODE_MINOR_VERSION,
+ NODE_PATCH_VERSION,
+ NODE_RELEASE
+ };
+ *result = &version;
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_adjust_external_memory(napi_env env,
+ int64_t change_in_bytes,
+ int64_t* adjusted_value) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, adjusted_value);
+
+ *adjusted_value = env->isolate->AdjustAmountOfExternalAllocatedMemory(
+ change_in_bytes);
+
+ return napi_clear_last_error(env);
+}
+
+namespace {
+namespace uvimpl {
+
+static napi_status ConvertUVErrorCode(int code) {
+ switch (code) {
+ case 0:
+ return napi_ok;
+ case UV_EINVAL:
+ return napi_invalid_arg;
+ case UV_ECANCELED:
+ return napi_cancelled;
+ }
+
+ return napi_generic_failure;
+}
+
+// Wrapper around uv_work_t which calls user-provided callbacks.
+class Work : public node::AsyncResource {
+ private:
+ explicit Work(napi_env env,
+ v8::Local<v8::Object> async_resource,
+ v8::Local<v8::String> async_resource_name,
+ napi_async_execute_callback execute,
+ napi_async_complete_callback complete = nullptr,
+ void* data = nullptr)
+ : AsyncResource(env->isolate,
+ async_resource,
+ *v8::String::Utf8Value(async_resource_name)),
+ _env(env),
+ _data(data),
+ _execute(execute),
+ _complete(complete) {
+ memset(&_request, 0, sizeof(_request));
+ _request.data = this;
+ }
+
+ ~Work() { }
+
+ public:
+ static Work* New(napi_env env,
+ v8::Local<v8::Object> async_resource,
+ v8::Local<v8::String> async_resource_name,
+ napi_async_execute_callback execute,
+ napi_async_complete_callback complete,
+ void* data) {
+ return new Work(env, async_resource, async_resource_name,
+ execute, complete, data);
+ }
+
+ static void Delete(Work* work) {
+ delete work;
+ }
+
+ static void ExecuteCallback(uv_work_t* req) {
+ Work* work = static_cast<Work*>(req->data);
+ work->_execute(work->_env, work->_data);
+ }
+
+ static void CompleteCallback(uv_work_t* req, int status) {
+ Work* work = static_cast<Work*>(req->data);
+
+ if (work->_complete != nullptr) {
+ napi_env env = work->_env;
+
+ // Establish a handle scope here so that every callback doesn't have to.
+ // Also it is needed for the exception-handling below.
+ v8::HandleScope scope(env->isolate);
+ CallbackScope callback_scope(work);
+
+ NAPI_CALL_INTO_MODULE(env,
+ work->_complete(env, ConvertUVErrorCode(status), work->_data),
+ [env] (v8::Local<v8::Value> local_err) {
+ // If there was an unhandled exception in the complete callback,
+ // report it as a fatal exception. (There is no JavaScript on the
+ // callstack that can possibly handle it.)
+ v8impl::trigger_fatal_exception(env, local_err);
+ });
+
+ // Note: Don't access `work` after this point because it was
+ // likely deleted by the complete callback.
+ }
+ }
+
+ uv_work_t* Request() {
+ return &_request;
+ }
+
+ private:
+ napi_env _env;
+ void* _data;
+ uv_work_t _request;
+ napi_async_execute_callback _execute;
+ napi_async_complete_callback _complete;
+};
+
+} // end of namespace uvimpl
+} // end of anonymous namespace
+
+#define CALL_UV(env, condition) \
+ do { \
+ int result = (condition); \
+ napi_status status = uvimpl::ConvertUVErrorCode(result); \
+ if (status != napi_ok) { \
+ return napi_set_last_error(env, status, result); \
+ } \
+ } while (0)
+
+napi_status napi_create_async_work(napi_env env,
+ napi_value async_resource,
+ napi_value async_resource_name,
+ napi_async_execute_callback execute,
+ napi_async_complete_callback complete,
+ void* data,
+ napi_async_work* result) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, execute);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Context> context = env->isolate->GetCurrentContext();
+
+ v8::Local<v8::Object> resource;
+ if (async_resource != nullptr) {
+ CHECK_TO_OBJECT(env, context, resource, async_resource);
+ } else {
+ resource = v8::Object::New(env->isolate);
+ }
+
+ v8::Local<v8::String> resource_name;
+ CHECK_TO_STRING(env, context, resource_name, async_resource_name);
+
+ uvimpl::Work* work =
+ uvimpl::Work::New(env, resource, resource_name,
+ execute, complete, data);
+
+ *result = reinterpret_cast<napi_async_work>(work);
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_delete_async_work(napi_env env, napi_async_work work) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, work);
+
+ uvimpl::Work::Delete(reinterpret_cast<uvimpl::Work*>(work));
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_queue_async_work(napi_env env, napi_async_work work) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, work);
+
+ // Consider: Encapsulate the uv_loop_t into an opaque pointer parameter.
+ // Currently the environment event loop is the same as the UV default loop.
+ // Someday (if node ever supports multiple isolates), it may be better to get
+ // the loop from node::Environment::GetCurrent(env->isolate)->event_loop();
+ uv_loop_t* event_loop = uv_default_loop();
+
+ uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
+
+ CALL_UV(env, uv_queue_work(event_loop,
+ w->Request(),
+ uvimpl::Work::ExecuteCallback,
+ uvimpl::Work::CompleteCallback));
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_cancel_async_work(napi_env env, napi_async_work work) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, work);
+
+ uvimpl::Work* w = reinterpret_cast<uvimpl::Work*>(work);
+
+ CALL_UV(env, uv_cancel(reinterpret_cast<uv_req_t*>(w->Request())));
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_create_promise(napi_env env,
+ napi_deferred* deferred,
+ napi_value* promise) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, deferred);
+ CHECK_ARG(env, promise);
+
+ auto maybe = v8::Promise::Resolver::New(env->isolate->GetCurrentContext());
+ CHECK_MAYBE_EMPTY(env, maybe, napi_generic_failure);
+
+ auto v8_resolver = maybe.ToLocalChecked();
+ auto v8_deferred = new v8::Persistent<v8::Value>();
+ v8_deferred->Reset(env->isolate, v8_resolver);
+
+ *deferred = v8impl::JsDeferredFromV8Persistent(v8_deferred);
+ *promise = v8impl::JsValueFromV8LocalValue(v8_resolver->GetPromise());
+ return GET_RETURN_STATUS(env);
+}
+
+napi_status napi_resolve_deferred(napi_env env,
+ napi_deferred deferred,
+ napi_value resolution) {
+ return v8impl::ConcludeDeferred(env, deferred, resolution, true);
+}
+
+napi_status napi_reject_deferred(napi_env env,
+ napi_deferred deferred,
+ napi_value resolution) {
+ return v8impl::ConcludeDeferred(env, deferred, resolution, false);
+}
+
+napi_status napi_is_promise(napi_env env,
+ napi_value promise,
+ bool* is_promise) {
+ CHECK_ENV(env);
+ CHECK_ARG(env, promise);
+ CHECK_ARG(env, is_promise);
+
+ *is_promise = v8impl::V8LocalValueFromJsValue(promise)->IsPromise();
+
+ return napi_clear_last_error(env);
+}
+
+napi_status napi_run_script(napi_env env,
+ napi_value script,
+ napi_value* result) {
+ NAPI_PREAMBLE(env);
+ CHECK_ARG(env, script);
+ CHECK_ARG(env, result);
+
+ v8::Local<v8::Value> v8_script = v8impl::V8LocalValueFromJsValue(script);
+
+ if (!v8_script->IsString()) {
+ return napi_set_last_error(env, napi_string_expected);
+ }
+
+ v8::Local<v8::Context> context = env->isolate->GetCurrentContext();
+
+ auto maybe_script = v8::Script::Compile(context,
+ v8::Local<v8::String>::Cast(v8_script));
+ CHECK_MAYBE_EMPTY(env, maybe_script, napi_generic_failure);
+
+ auto script_result =
+ maybe_script.ToLocalChecked()->Run(context);
+ CHECK_MAYBE_EMPTY(env, script_result, napi_generic_failure);
+
+ *result = v8impl::JsValueFromV8LocalValue(script_result.ToLocalChecked());
+ return GET_RETURN_STATUS(env);
+}
diff --git a/debian/build_modules/node-addon-api/src/node_api.gyp b/debian/build_modules/node-addon-api/src/node_api.gyp
new file mode 100644
index 0000000..3de7da1
--- /dev/null
+++ b/debian/build_modules/node-addon-api/src/node_api.gyp
@@ -0,0 +1,21 @@
+{
+ 'targets': [
+ {
+ 'target_name': 'nothing',
+ 'type': 'static_library',
+ 'sources': [ 'nothing.c' ]
+ },
+ {
+ 'target_name': 'node-api',
+ 'type': 'static_library',
+ 'sources': [
+ 'node_api.cc',
+ 'node_internals.cc',
+ ],
+ 'defines': [
+ 'EXTERNAL_NAPI',
+ ],
+ 'cflags_cc': ['-fvisibility=hidden']
+ }
+ ]
+}
diff --git a/debian/build_modules/node-addon-api/src/node_api.h b/debian/build_modules/node-addon-api/src/node_api.h
new file mode 100644
index 0000000..27028f7
--- /dev/null
+++ b/debian/build_modules/node-addon-api/src/node_api.h
@@ -0,0 +1,588 @@
+/******************************************************************************
+ * Experimental prototype for demonstrating VM agnostic and ABI stable API
+ * for native modules to use instead of using Nan and V8 APIs directly.
+ *
+ * The current status is "Experimental" and should not be used for
+ * production applications. The API is still subject to change
+ * and as an experimental feature is NOT subject to semver.
+ *
+ ******************************************************************************/
+#ifndef SRC_NODE_API_H_
+#define SRC_NODE_API_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+#include "node_api_types.h"
+
+#ifdef _WIN32
+ #ifdef BUILDING_NODE_EXTENSION
+ #ifdef EXTERNAL_NAPI
+ // Building external N-API, or native module against external N-API
+ #define NAPI_EXTERN /* nothing */
+ #else
+ // Building native module against node with built-in N-API
+ #define NAPI_EXTERN __declspec(dllimport)
+ #endif
+ #else
+ // Building node with built-in N-API
+ #define NAPI_EXTERN __declspec(dllexport)
+ #endif
+#else
+ #define NAPI_EXTERN /* nothing */
+#endif
+
+#ifdef _WIN32
+# define NAPI_MODULE_EXPORT __declspec(dllexport)
+#else
+# define NAPI_MODULE_EXPORT __attribute__((visibility("default")))
+#endif
+
+#ifdef __GNUC__
+#define NAPI_NO_RETURN __attribute__((noreturn))
+#else
+#define NAPI_NO_RETURN
+#endif
+
+
+typedef napi_value (*napi_addon_register_func)(napi_env env,
+ napi_value exports);
+
+typedef struct {
+ int nm_version;
+ unsigned int nm_flags;
+ const char* nm_filename;
+ napi_addon_register_func nm_register_func;
+ const char* nm_modname;
+ void* nm_priv;
+ void* reserved[4];
+} napi_module;
+
+#define NAPI_MODULE_VERSION 1
+
+#if defined(_MSC_VER)
+#pragma section(".CRT$XCU", read)
+#define NAPI_C_CTOR(fn) \
+ static void __cdecl fn(void); \
+ __declspec(dllexport, allocate(".CRT$XCU")) void(__cdecl * fn##_)(void) = \
+ fn; \
+ static void __cdecl fn(void)
+#else
+#define NAPI_C_CTOR(fn) \
+ static void fn(void) __attribute__((constructor)); \
+ static void fn(void)
+#endif
+
+#ifdef __cplusplus
+#define EXTERN_C_START extern "C" {
+#define EXTERN_C_END }
+#else
+#define EXTERN_C_START
+#define EXTERN_C_END
+#endif
+
+#define NAPI_MODULE_X(modname, regfunc, priv, flags) \
+ EXTERN_C_START \
+ static napi_module _module = \
+ { \
+ NAPI_MODULE_VERSION, \
+ flags, \
+ __FILE__, \
+ regfunc, \
+ #modname, \
+ priv, \
+ {0}, \
+ }; \
+ NAPI_C_CTOR(_register_ ## modname) { \
+ napi_module_register(&_module); \
+ } \
+ EXTERN_C_END
+
+#define NAPI_MODULE(modname, regfunc) \
+ NAPI_MODULE_X(modname, regfunc, NULL, 0)
+
+#define NAPI_AUTO_LENGTH SIZE_MAX
+
+EXTERN_C_START
+
+NAPI_EXTERN void napi_module_register(napi_module* mod);
+
+NAPI_EXTERN napi_status
+napi_get_last_error_info(napi_env env,
+ const napi_extended_error_info** result);
+
+NAPI_EXTERN napi_status napi_fatal_exception(napi_env env, napi_value err);
+
+NAPI_EXTERN NAPI_NO_RETURN void napi_fatal_error(const char* location,
+ size_t location_len,
+ const char* message,
+ size_t message_len);
+
+// Getters for defined singletons
+NAPI_EXTERN napi_status napi_get_undefined(napi_env env, napi_value* result);
+NAPI_EXTERN napi_status napi_get_null(napi_env env, napi_value* result);
+NAPI_EXTERN napi_status napi_get_global(napi_env env, napi_value* result);
+NAPI_EXTERN napi_status napi_get_boolean(napi_env env,
+ bool value,
+ napi_value* result);
+
+// Methods to create Primitive types/Objects
+NAPI_EXTERN napi_status napi_create_object(napi_env env, napi_value* result);
+NAPI_EXTERN napi_status napi_create_array(napi_env env, napi_value* result);
+NAPI_EXTERN napi_status napi_create_array_with_length(napi_env env,
+ size_t length,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_double(napi_env env,
+ double value,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_int32(napi_env env,
+ int32_t value,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_uint32(napi_env env,
+ uint32_t value,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_int64(napi_env env,
+ int64_t value,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_string_latin1(napi_env env,
+ const char* str,
+ size_t length,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_string_utf8(napi_env env,
+ const char* str,
+ size_t length,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_string_utf16(napi_env env,
+ const char16_t* str,
+ size_t length,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_symbol(napi_env env,
+ napi_value description,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_function(napi_env env,
+ const char* utf8name,
+ size_t length,
+ napi_callback cb,
+ void* data,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_error(napi_env env,
+ napi_value code,
+ napi_value msg,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_type_error(napi_env env,
+ napi_value code,
+ napi_value msg,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_range_error(napi_env env,
+ napi_value code,
+ napi_value msg,
+ napi_value* result);
+
+// Methods to get the the native napi_value from Primitive type
+NAPI_EXTERN napi_status napi_typeof(napi_env env,
+ napi_value value,
+ napi_valuetype* result);
+NAPI_EXTERN napi_status napi_get_value_double(napi_env env,
+ napi_value value,
+ double* result);
+NAPI_EXTERN napi_status napi_get_value_int32(napi_env env,
+ napi_value value,
+ int32_t* result);
+NAPI_EXTERN napi_status napi_get_value_uint32(napi_env env,
+ napi_value value,
+ uint32_t* result);
+NAPI_EXTERN napi_status napi_get_value_int64(napi_env env,
+ napi_value value,
+ int64_t* result);
+NAPI_EXTERN napi_status napi_get_value_bool(napi_env env,
+ napi_value value,
+ bool* result);
+
+// Copies LATIN-1 encoded bytes from a string into a buffer.
+NAPI_EXTERN napi_status napi_get_value_string_latin1(napi_env env,
+ napi_value value,
+ char* buf,
+ size_t bufsize,
+ size_t* result);
+
+// Copies UTF-8 encoded bytes from a string into a buffer.
+NAPI_EXTERN napi_status napi_get_value_string_utf8(napi_env env,
+ napi_value value,
+ char* buf,
+ size_t bufsize,
+ size_t* result);
+
+// Copies UTF-16 encoded bytes from a string into a buffer.
+NAPI_EXTERN napi_status napi_get_value_string_utf16(napi_env env,
+ napi_value value,
+ char16_t* buf,
+ size_t bufsize,
+ size_t* result);
+
+// Methods to coerce values
+// These APIs may execute user scripts
+NAPI_EXTERN napi_status napi_coerce_to_bool(napi_env env,
+ napi_value value,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_coerce_to_number(napi_env env,
+ napi_value value,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_coerce_to_object(napi_env env,
+ napi_value value,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_coerce_to_string(napi_env env,
+ napi_value value,
+ napi_value* result);
+
+// Methods to work with Objects
+NAPI_EXTERN napi_status napi_get_prototype(napi_env env,
+ napi_value object,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_get_property_names(napi_env env,
+ napi_value object,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_set_property(napi_env env,
+ napi_value object,
+ napi_value key,
+ napi_value value);
+NAPI_EXTERN napi_status napi_has_property(napi_env env,
+ napi_value object,
+ napi_value key,
+ bool* result);
+NAPI_EXTERN napi_status napi_get_property(napi_env env,
+ napi_value object,
+ napi_value key,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_delete_property(napi_env env,
+ napi_value object,
+ napi_value key,
+ bool* result);
+NAPI_EXTERN napi_status napi_has_own_property(napi_env env,
+ napi_value object,
+ napi_value key,
+ bool* result);
+NAPI_EXTERN napi_status napi_set_named_property(napi_env env,
+ napi_value object,
+ const char* utf8name,
+ napi_value value);
+NAPI_EXTERN napi_status napi_has_named_property(napi_env env,
+ napi_value object,
+ const char* utf8name,
+ bool* result);
+NAPI_EXTERN napi_status napi_get_named_property(napi_env env,
+ napi_value object,
+ const char* utf8name,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_set_element(napi_env env,
+ napi_value object,
+ uint32_t index,
+ napi_value value);
+NAPI_EXTERN napi_status napi_has_element(napi_env env,
+ napi_value object,
+ uint32_t index,
+ bool* result);
+NAPI_EXTERN napi_status napi_get_element(napi_env env,
+ napi_value object,
+ uint32_t index,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_delete_element(napi_env env,
+ napi_value object,
+ uint32_t index,
+ bool* result);
+NAPI_EXTERN napi_status
+napi_define_properties(napi_env env,
+ napi_value object,
+ size_t property_count,
+ const napi_property_descriptor* properties);
+
+// Methods to work with Arrays
+NAPI_EXTERN napi_status napi_is_array(napi_env env,
+ napi_value value,
+ bool* result);
+NAPI_EXTERN napi_status napi_get_array_length(napi_env env,
+ napi_value value,
+ uint32_t* result);
+
+// Methods to compare values
+NAPI_EXTERN napi_status napi_strict_equals(napi_env env,
+ napi_value lhs,
+ napi_value rhs,
+ bool* result);
+
+// Methods to work with Functions
+NAPI_EXTERN napi_status napi_call_function(napi_env env,
+ napi_value recv,
+ napi_value func,
+ size_t argc,
+ const napi_value* argv,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_new_instance(napi_env env,
+ napi_value constructor,
+ size_t argc,
+ const napi_value* argv,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_instanceof(napi_env env,
+ napi_value object,
+ napi_value constructor,
+ bool* result);
+
+// Methods to work with napi_callbacks
+
+// Gets all callback info in a single call. (Ugly, but faster.)
+NAPI_EXTERN napi_status napi_get_cb_info(
+ napi_env env, // [in] NAPI environment handle
+ napi_callback_info cbinfo, // [in] Opaque callback-info handle
+ size_t* argc, // [in-out] Specifies the size of the provided argv array
+ // and receives the actual count of args.
+ napi_value* argv, // [out] Array of values
+ napi_value* this_arg, // [out] Receives the JS 'this' arg for the call
+ void** data); // [out] Receives the data pointer for the callback.
+
+NAPI_EXTERN napi_status napi_get_new_target(napi_env env,
+ napi_callback_info cbinfo,
+ napi_value* result);
+NAPI_EXTERN napi_status
+napi_define_class(napi_env env,
+ const char* utf8name,
+ size_t length,
+ napi_callback constructor,
+ void* data,
+ size_t property_count,
+ const napi_property_descriptor* properties,
+ napi_value* result);
+
+// Methods to work with external data objects
+NAPI_EXTERN napi_status napi_wrap(napi_env env,
+ napi_value js_object,
+ void* native_object,
+ napi_finalize finalize_cb,
+ void* finalize_hint,
+ napi_ref* result);
+NAPI_EXTERN napi_status napi_unwrap(napi_env env,
+ napi_value js_object,
+ void** result);
+NAPI_EXTERN napi_status napi_remove_wrap(napi_env env,
+ napi_value js_object,
+ void** result);
+NAPI_EXTERN napi_status napi_create_external(napi_env env,
+ void* data,
+ napi_finalize finalize_cb,
+ void* finalize_hint,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_get_value_external(napi_env env,
+ napi_value value,
+ void** result);
+
+// Methods to control object lifespan
+
+// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
+NAPI_EXTERN napi_status napi_create_reference(napi_env env,
+ napi_value value,
+ uint32_t initial_refcount,
+ napi_ref* result);
+
+// Deletes a reference. The referenced value is released, and may
+// be GC'd unless there are other references to it.
+NAPI_EXTERN napi_status napi_delete_reference(napi_env env, napi_ref ref);
+
+// Increments the reference count, optionally returning the resulting count.
+// After this call the reference will be a strong reference because its
+// refcount is >0, and the referenced object is effectively "pinned".
+// Calling this when the refcount is 0 and the object is unavailable
+// results in an error.
+NAPI_EXTERN napi_status napi_reference_ref(napi_env env,
+ napi_ref ref,
+ uint32_t* result);
+
+// Decrements the reference count, optionally returning the resulting count.
+// If the result is 0 the reference is now weak and the object may be GC'd
+// at any time if there are no other references. Calling this when the
+// refcount is already 0 results in an error.
+NAPI_EXTERN napi_status napi_reference_unref(napi_env env,
+ napi_ref ref,
+ uint32_t* result);
+
+// Attempts to get a referenced value. If the reference is weak,
+// the value might no longer be available, in that case the call
+// is still successful but the result is NULL.
+NAPI_EXTERN napi_status napi_get_reference_value(napi_env env,
+ napi_ref ref,
+ napi_value* result);
+
+NAPI_EXTERN napi_status napi_open_handle_scope(napi_env env,
+ napi_handle_scope* result);
+NAPI_EXTERN napi_status napi_close_handle_scope(napi_env env,
+ napi_handle_scope scope);
+NAPI_EXTERN napi_status
+napi_open_escapable_handle_scope(napi_env env,
+ napi_escapable_handle_scope* result);
+NAPI_EXTERN napi_status
+napi_close_escapable_handle_scope(napi_env env,
+ napi_escapable_handle_scope scope);
+
+NAPI_EXTERN napi_status napi_escape_handle(napi_env env,
+ napi_escapable_handle_scope scope,
+ napi_value escapee,
+ napi_value* result);
+
+// Methods to support error handling
+NAPI_EXTERN napi_status napi_throw(napi_env env, napi_value error);
+NAPI_EXTERN napi_status napi_throw_error(napi_env env,
+ const char* code,
+ const char* msg);
+NAPI_EXTERN napi_status napi_throw_type_error(napi_env env,
+ const char* code,
+ const char* msg);
+NAPI_EXTERN napi_status napi_throw_range_error(napi_env env,
+ const char* code,
+ const char* msg);
+NAPI_EXTERN napi_status napi_is_error(napi_env env,
+ napi_value value,
+ bool* result);
+
+// Methods to support catching exceptions
+NAPI_EXTERN napi_status napi_is_exception_pending(napi_env env, bool* result);
+NAPI_EXTERN napi_status napi_get_and_clear_last_exception(napi_env env,
+ napi_value* result);
+
+// Methods to provide node::Buffer functionality with napi types
+NAPI_EXTERN napi_status napi_create_buffer(napi_env env,
+ size_t length,
+ void** data,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_external_buffer(napi_env env,
+ size_t length,
+ void* data,
+ napi_finalize finalize_cb,
+ void* finalize_hint,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_create_buffer_copy(napi_env env,
+ size_t length,
+ const void* data,
+ void** result_data,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_is_buffer(napi_env env,
+ napi_value value,
+ bool* result);
+NAPI_EXTERN napi_status napi_get_buffer_info(napi_env env,
+ napi_value value,
+ void** data,
+ size_t* length);
+
+// Methods to work with array buffers and typed arrays
+NAPI_EXTERN napi_status napi_is_arraybuffer(napi_env env,
+ napi_value value,
+ bool* result);
+NAPI_EXTERN napi_status napi_create_arraybuffer(napi_env env,
+ size_t byte_length,
+ void** data,
+ napi_value* result);
+NAPI_EXTERN napi_status
+napi_create_external_arraybuffer(napi_env env,
+ void* external_data,
+ size_t byte_length,
+ napi_finalize finalize_cb,
+ void* finalize_hint,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_get_arraybuffer_info(napi_env env,
+ napi_value arraybuffer,
+ void** data,
+ size_t* byte_length);
+NAPI_EXTERN napi_status napi_is_typedarray(napi_env env,
+ napi_value value,
+ bool* result);
+NAPI_EXTERN napi_status napi_create_typedarray(napi_env env,
+ napi_typedarray_type type,
+ size_t length,
+ napi_value arraybuffer,
+ size_t byte_offset,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_get_typedarray_info(napi_env env,
+ napi_value typedarray,
+ napi_typedarray_type* type,
+ size_t* length,
+ void** data,
+ napi_value* arraybuffer,
+ size_t* byte_offset);
+
+NAPI_EXTERN napi_status napi_create_dataview(napi_env env,
+ size_t length,
+ napi_value arraybuffer,
+ size_t byte_offset,
+ napi_value* result);
+NAPI_EXTERN napi_status napi_is_dataview(napi_env env,
+ napi_value value,
+ bool* result);
+NAPI_EXTERN napi_status napi_get_dataview_info(napi_env env,
+ napi_value dataview,
+ size_t* bytelength,
+ void** data,
+ napi_value* arraybuffer,
+ size_t* byte_offset);
+
+// Methods to manage simple async operations
+NAPI_EXTERN
+napi_status napi_create_async_work(napi_env env,
+ napi_value async_resource,
+ napi_value async_resource_name,
+ napi_async_execute_callback execute,
+ napi_async_complete_callback complete,
+ void* data,
+ napi_async_work* result);
+NAPI_EXTERN napi_status napi_delete_async_work(napi_env env,
+ napi_async_work work);
+NAPI_EXTERN napi_status napi_queue_async_work(napi_env env,
+ napi_async_work work);
+NAPI_EXTERN napi_status napi_cancel_async_work(napi_env env,
+ napi_async_work work);
+
+// Methods for custom handling of async operations
+NAPI_EXTERN napi_status napi_async_init(napi_env env,
+ napi_value async_resource,
+ napi_value async_resource_name,
+ napi_async_context* result);
+
+NAPI_EXTERN napi_status napi_async_destroy(napi_env env,
+ napi_async_context async_context);
+
+NAPI_EXTERN napi_status napi_make_callback(napi_env env,
+ napi_async_context async_context,
+ napi_value recv,
+ napi_value func,
+ size_t argc,
+ const napi_value* argv,
+ napi_value* result);
+
+// version management
+NAPI_EXTERN napi_status napi_get_version(napi_env env, uint32_t* result);
+
+NAPI_EXTERN
+napi_status napi_get_node_version(napi_env env,
+ const napi_node_version** version);
+
+// Promises
+NAPI_EXTERN napi_status napi_create_promise(napi_env env,
+ napi_deferred* deferred,
+ napi_value* promise);
+NAPI_EXTERN napi_status napi_resolve_deferred(napi_env env,
+ napi_deferred deferred,
+ napi_value resolution);
+NAPI_EXTERN napi_status napi_reject_deferred(napi_env env,
+ napi_deferred deferred,
+ napi_value rejection);
+NAPI_EXTERN napi_status napi_is_promise(napi_env env,
+ napi_value promise,
+ bool* is_promise);
+
+// Memory management
+NAPI_EXTERN napi_status napi_adjust_external_memory(napi_env env,
+ int64_t change_in_bytes,
+ int64_t* adjusted_value);
+
+// Runnig a script
+NAPI_EXTERN napi_status napi_run_script(napi_env env,
+ napi_value script,
+ napi_value* result);
+
+EXTERN_C_END
+
+#endif // SRC_NODE_API_H_
diff --git a/debian/build_modules/node-addon-api/src/node_api_types.h b/debian/build_modules/node-addon-api/src/node_api_types.h
new file mode 100644
index 0000000..230c1f4
--- /dev/null
+++ b/debian/build_modules/node-addon-api/src/node_api_types.h
@@ -0,0 +1,115 @@
+#ifndef SRC_NODE_API_TYPES_H_
+#define SRC_NODE_API_TYPES_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#if !defined __cplusplus || (defined(_MSC_VER) && _MSC_VER < 1900)
+ typedef uint16_t char16_t;
+#endif
+
+// JSVM API types are all opaque pointers for ABI stability
+// typedef undefined structs instead of void* for compile time type safety
+typedef struct napi_env__ *napi_env;
+typedef struct napi_value__ *napi_value;
+typedef struct napi_ref__ *napi_ref;
+typedef struct napi_handle_scope__ *napi_handle_scope;
+typedef struct napi_escapable_handle_scope__ *napi_escapable_handle_scope;
+typedef struct napi_callback_info__ *napi_callback_info;
+typedef struct napi_async_context__ *napi_async_context;
+typedef struct napi_async_work__ *napi_async_work;
+typedef struct napi_deferred__ *napi_deferred;
+
+typedef enum {
+ napi_default = 0,
+ napi_writable = 1 << 0,
+ napi_enumerable = 1 << 1,
+ napi_configurable = 1 << 2,
+
+ // Used with napi_define_class to distinguish static properties
+ // from instance properties. Ignored by napi_define_properties.
+ napi_static = 1 << 10,
+} napi_property_attributes;
+
+typedef enum {
+ // ES6 types (corresponds to typeof)
+ napi_undefined,
+ napi_null,
+ napi_boolean,
+ napi_number,
+ napi_string,
+ napi_symbol,
+ napi_object,
+ napi_function,
+ napi_external,
+} napi_valuetype;
+
+typedef enum {
+ napi_int8_array,
+ napi_uint8_array,
+ napi_uint8_clamped_array,
+ napi_int16_array,
+ napi_uint16_array,
+ napi_int32_array,
+ napi_uint32_array,
+ napi_float32_array,
+ napi_float64_array,
+} napi_typedarray_type;
+
+typedef enum {
+ napi_ok,
+ napi_invalid_arg,
+ napi_object_expected,
+ napi_string_expected,
+ napi_name_expected,
+ napi_function_expected,
+ napi_number_expected,
+ napi_boolean_expected,
+ napi_array_expected,
+ napi_generic_failure,
+ napi_pending_exception,
+ napi_cancelled,
+ napi_escape_called_twice,
+ napi_handle_scope_mismatch
+} napi_status;
+
+typedef napi_value (*napi_callback)(napi_env env,
+ napi_callback_info info);
+typedef void (*napi_finalize)(napi_env env,
+ void* finalize_data,
+ void* finalize_hint);
+typedef void (*napi_async_execute_callback)(napi_env env,
+ void* data);
+typedef void (*napi_async_complete_callback)(napi_env env,
+ napi_status status,
+ void* data);
+
+typedef struct {
+ // One of utf8name or name should be NULL.
+ const char* utf8name;
+ napi_value name;
+
+ napi_callback method;
+ napi_callback getter;
+ napi_callback setter;
+ napi_value value;
+
+ napi_property_attributes attributes;
+ void* data;
+} napi_property_descriptor;
+
+typedef struct {
+ const char* error_message;
+ void* engine_reserved;
+ uint32_t engine_error_code;
+ napi_status error_code;
+} napi_extended_error_info;
+
+typedef struct {
+ uint32_t major;
+ uint32_t minor;
+ uint32_t patch;
+ const char* release;
+} napi_node_version;
+
+#endif // SRC_NODE_API_TYPES_H_
diff --git a/debian/build_modules/node-addon-api/src/node_internals.cc b/debian/build_modules/node-addon-api/src/node_internals.cc
new file mode 100644
index 0000000..c4a7dd8
--- /dev/null
+++ b/debian/build_modules/node-addon-api/src/node_internals.cc
@@ -0,0 +1,142 @@
+#include "node_internals.h"
+#include <stdlib.h>
+#include <cstdarg>
+#include <vector>
+#include "uv.h"
+
+#if defined(_MSC_VER)
+#define getpid GetCurrentProcessId
+#else
+#include <unistd.h> // getpid
+#endif
+
+#if NODE_MAJOR_VERSION < 8 || NODE_MAJOR_VERSION == 8 && NODE_MINOR_VERSION < 6
+CallbackScope::CallbackScope(void *work) {
+}
+#endif // NODE_MAJOR_VERSION < 8
+
+namespace node {
+
+#if NODE_MAJOR_VERSION < 8
+
+async_context EmitAsyncInit(v8::Isolate* isolate,
+ v8::Local<v8::Object> resource,
+ v8::Local<v8::String> name,
+ async_id trigger_async_id) {
+ return async_context();
+}
+
+void EmitAsyncDestroy(v8::Isolate* isolate,
+ async_context asyncContext) {
+}
+
+AsyncResource::AsyncResource(v8::Isolate* isolate,
+ v8::Local<v8::Object> object,
+ const char *name) {
+}
+
+#endif // NODE_MAJOR_VERSION < 8
+
+#if NODE_MAJOR_VERSION < 8 || NODE_MAJOR_VERSION == 8 && NODE_MINOR_VERSION < 6
+
+v8::MaybeLocal<v8::Value> MakeCallback(v8::Isolate* isolate,
+ v8::Local<v8::Object> recv,
+ v8::Local<v8::Function> callback,
+ int argc,
+ v8::Local<v8::Value>* argv,
+ async_context asyncContext) {
+ return node::MakeCallback(isolate, recv, callback, argc, argv);
+}
+
+#endif // NODE_MAJOR_VERSION < 8 || NODE_MAJOR_VERSION == 8 && NODE_MINOR_VERSION < 6
+
+static void PrintErrorString(const char* format, ...) {
+ va_list ap;
+ va_start(ap, format);
+#ifdef _WIN32
+ HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
+
+ // Check if stderr is something other than a tty/console
+ if (stderr_handle == INVALID_HANDLE_VALUE ||
+ stderr_handle == nullptr ||
+ uv_guess_handle(_fileno(stderr)) != UV_TTY) {
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ return;
+ }
+
+ // Fill in any placeholders
+ int n = _vscprintf(format, ap);
+ std::vector<char> out(n + 1);
+ vsprintf(out.data(), format, ap);
+
+ // Get required wide buffer size
+ n = MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, nullptr, 0);
+
+ std::vector<wchar_t> wbuf(n);
+ MultiByteToWideChar(CP_UTF8, 0, out.data(), -1, wbuf.data(), n);
+
+ // Don't include the null character in the output
+ CHECK_GT(n, 0);
+ WriteConsoleW(stderr_handle, wbuf.data(), n - 1, nullptr, nullptr);
+#else
+ vfprintf(stderr, format, ap);
+#endif
+ va_end(ap);
+}
+
+void DumpBacktrace(FILE* fp) {
+}
+
+NO_RETURN void Abort() {
+ DumpBacktrace(stderr);
+ fflush(stderr);
+ ABORT_NO_BACKTRACE();
+}
+
+NO_RETURN void Assert(const char* const (*args)[4]) {
+ auto filename = (*args)[0];
+ auto linenum = (*args)[1];
+ auto message = (*args)[2];
+ auto function = (*args)[3];
+
+ char exepath[256];
+ size_t exepath_size = sizeof(exepath);
+ if (uv_exepath(exepath, &exepath_size))
+ snprintf(exepath, sizeof(exepath), "node");
+
+ char pid[12] = {0};
+ snprintf(pid, sizeof(pid), "[%u]", getpid());
+
+ fprintf(stderr, "%s%s: %s:%s:%s%s Assertion `%s' failed.\n",
+ exepath, pid, filename, linenum,
+ function, *function ? ":" : "", message);
+ fflush(stderr);
+
+ Abort();
+}
+
+static void OnFatalError(const char* location, const char* message) {
+ if (location) {
+ PrintErrorString("FATAL ERROR: %s %s\n", location, message);
+ } else {
+ PrintErrorString("FATAL ERROR: %s\n", message);
+ }
+ fflush(stderr);
+ ABORT();
+}
+
+NO_RETURN void FatalError(const char* location, const char* message) {
+ OnFatalError(location, message);
+ // to suppress compiler warning
+ ABORT();
+}
+
+} // namespace node
+
+#if NODE_MAJOR_VERSION < 6
+v8::Local<v8::Name> v8::Private::ForApi(v8::Isolate* isolate,
+ v8::Local<v8::String> key) {
+ return v8::Symbol::ForApi(isolate, key);
+}
+#endif // NODE_MAJOR_VERSION < 6
diff --git a/debian/build_modules/node-addon-api/src/node_internals.h b/debian/build_modules/node-addon-api/src/node_internals.h
new file mode 100644
index 0000000..bacccff
--- /dev/null
+++ b/debian/build_modules/node-addon-api/src/node_internals.h
@@ -0,0 +1,157 @@
+#ifndef SRC_NODE_INTERNALS_H_
+#define SRC_NODE_INTERNALS_H_
+
+//
+// This is a stripped down shim to allow node_api.cc to build outside of the node source tree.
+//
+
+#include "node_version.h"
+#include "util-inl.h"
+#include <stdio.h>
+#include <stdint.h>
+#include "uv.h"
+#include "node.h"
+#include <string>
+
+// Windows 8+ does not like abort() in Release mode
+#ifdef _WIN32
+#define ABORT_NO_BACKTRACE() raise(SIGABRT)
+#else
+#define ABORT_NO_BACKTRACE() abort()
+#endif
+
+#define ABORT() node::Abort()
+
+#ifdef __GNUC__
+#define LIKELY(expr) __builtin_expect(!!(expr), 1)
+#define UNLIKELY(expr) __builtin_expect(!!(expr), 0)
+#define PRETTY_FUNCTION_NAME __PRETTY_FUNCTION__
+#else
+#define LIKELY(expr) expr
+#define UNLIKELY(expr) expr
+#define PRETTY_FUNCTION_NAME ""
+#endif
+
+#define STRINGIFY_(x) #x
+#define STRINGIFY(x) STRINGIFY_(x)
+
+#define CHECK(expr) \
+ do { \
+ if (UNLIKELY(!(expr))) { \
+ static const char* const args[] = { __FILE__, STRINGIFY(__LINE__), \
+ #expr, PRETTY_FUNCTION_NAME }; \
+ node::Assert(&args); \
+ } \
+ } while (0)
+
+#define CHECK_EQ(a, b) CHECK((a) == (b))
+#define CHECK_GE(a, b) CHECK((a) >= (b))
+#define CHECK_GT(a, b) CHECK((a) > (b))
+#define CHECK_LE(a, b) CHECK((a) <= (b))
+#define CHECK_LT(a, b) CHECK((a) < (b))
+#define CHECK_NE(a, b) CHECK((a) != (b))
+
+#ifdef __GNUC__
+#define NO_RETURN __attribute__((noreturn))
+#else
+#define NO_RETURN
+#endif
+
+#ifndef NODE_RELEASE
+#define NODE_RELEASE "node"
+#endif
+
+#if NODE_MAJOR_VERSION < 8 || NODE_MAJOR_VERSION == 8 && NODE_MINOR_VERSION < 6
+class CallbackScope {
+ public:
+ CallbackScope(void *work);
+};
+#endif // NODE_MAJOR_VERSION < 8
+
+namespace node {
+
+// Copied from Node.js' src/node_persistent.h
+template <typename T>
+struct ResetInDestructorPersistentTraits {
+ static const bool kResetInDestructor = true;
+ template <typename S, typename M>
+ // Disallow copy semantics by leaving this unimplemented.
+ inline static void Copy(
+ const v8::Persistent<S, M>&,
+ v8::Persistent<T, ResetInDestructorPersistentTraits<T>>*);
+};
+
+// v8::Persistent does not reset the object slot in its destructor. That is
+// acknowledged as a flaw in the V8 API and expected to change in the future
+// but for now node::Persistent is the easier and safer alternative.
+template <typename T>
+using Persistent = v8::Persistent<T, ResetInDestructorPersistentTraits<T>>;
+
+#if NODE_MAJOR_VERSION < 8 || NODE_MAJOR_VERSION == 8 && NODE_MINOR_VERSION < 2
+typedef int async_id;
+
+typedef struct async_context {
+ node::async_id async_id;
+ node::async_id trigger_async_id;
+} async_context;
+#endif // NODE_MAJOR_VERSION < 8.2
+
+#if NODE_MAJOR_VERSION < 8 || NODE_MAJOR_VERSION == 8 && NODE_MINOR_VERSION < 6
+NODE_EXTERN async_context EmitAsyncInit(v8::Isolate* isolate,
+ v8::Local<v8::Object> resource,
+ v8::Local<v8::String> name,
+ async_id trigger_async_id = -1);
+
+NODE_EXTERN void EmitAsyncDestroy(v8::Isolate* isolate,
+ async_context asyncContext);
+
+v8::MaybeLocal<v8::Value> MakeCallback(v8::Isolate* isolate,
+ v8::Local<v8::Object> recv,
+ v8::Local<v8::Function> callback,
+ int argc,
+ v8::Local<v8::Value>* argv,
+ async_context asyncContext);
+
+#if NODE_MAJOR_VERSION < 8
+class AsyncResource {
+ public:
+ AsyncResource(v8::Isolate* isolate,
+ v8::Local<v8::Object> object,
+ const char *name);
+};
+#endif // node version below 8
+
+#endif // node version below 8.6
+
+// The slightly odd function signature for Assert() is to ease
+// instruction cache pressure in calls from ASSERT and CHECK.
+NO_RETURN void Abort();
+NO_RETURN void Assert(const char* const (*args)[4]);
+void DumpBacktrace(FILE* fp);
+
+template <typename T, size_t N>
+constexpr size_t arraysize(const T(&)[N]) { return N; }
+
+NO_RETURN void FatalError(const char* location, const char* message);
+
+} // namespace node
+
+#if NODE_MAJOR_VERSION < 8
+#define NewTarget This
+#endif // NODE_MAJOR_VERSION < 8
+
+#if NODE_MAJOR_VERSION < 6
+namespace v8 {
+ namespace Private {
+ v8::Local<v8::Name> ForApi(v8::Isolate* isolate, v8::Local<v8::String> key);
+ }
+}
+#define GetPrivate(context, key) Get((context), (key))
+#define SetPrivate(context, key, value) \
+ DefineOwnProperty((context), (key), (value), \
+ static_cast<v8::PropertyAttribute>(v8::DontEnum | \
+ v8::DontDelete | \
+ v8::ReadOnly))
+#endif // NODE_MAJOR_VERSION < 6
+
+#endif // SRC_NODE_INTERNALS_H_
diff --git a/debian/build_modules/node-addon-api/src/nothing.c b/debian/build_modules/node-addon-api/src/nothing.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/debian/build_modules/node-addon-api/src/nothing.c
diff --git a/debian/build_modules/node-addon-api/src/util-inl.h b/debian/build_modules/node-addon-api/src/util-inl.h
new file mode 100644
index 0000000..30aad16
--- /dev/null
+++ b/debian/build_modules/node-addon-api/src/util-inl.h
@@ -0,0 +1,38 @@
+#ifndef SRC_UTIL_INL_H_
+#define SRC_UTIL_INL_H_
+
+#include "util.h"
+#include "v8.h"
+
+namespace node {
+
+inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
+ const char* data,
+ int length) {
+ return v8::String::NewFromOneByte(isolate,
+ reinterpret_cast<const uint8_t*>(data),
+ v8::NewStringType::kNormal,
+ length).ToLocalChecked();
+}
+
+inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
+ const signed char* data,
+ int length) {
+ return v8::String::NewFromOneByte(isolate,
+ reinterpret_cast<const uint8_t*>(data),
+ v8::NewStringType::kNormal,
+ length).ToLocalChecked();
+}
+
+inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
+ const unsigned char* data,
+ int length) {
+ return v8::String::NewFromOneByte(isolate,
+ reinterpret_cast<const uint8_t*>(data),
+ v8::NewStringType::kNormal,
+ length).ToLocalChecked();
+}
+
+} // namespace node
+
+#endif // SRC_UTIL_INL_H_
diff --git a/debian/build_modules/node-addon-api/src/util.h b/debian/build_modules/node-addon-api/src/util.h
new file mode 100644
index 0000000..6765bc1
--- /dev/null
+++ b/debian/build_modules/node-addon-api/src/util.h
@@ -0,0 +1,7 @@
+#ifndef SRC_UTIL_H_
+#define SRC_UTIL_H_
+
+#define FIXED_ONE_BYTE_STRING(isolate, string) \
+ (node::OneByteString((isolate), (string), sizeof(string) - 1))
+
+#endif // SRC_UTIL_H_
diff --git a/debian/build_modules/node-addon-api/tools/README.md b/debian/build_modules/node-addon-api/tools/README.md
new file mode 100644
index 0000000..b71e5d9
--- /dev/null
+++ b/debian/build_modules/node-addon-api/tools/README.md
@@ -0,0 +1,67 @@
+# Migration Script
+
+The migration tool is designed to reduce repetitive work in the migration process. However, the script is not aiming to convert every thing for you. There are usually some small fixes and major reconstruction required.
+
+### How To Use
+
+To run the conversion script, first make sure you have the latest `node-addon-api` in your `node_modules` directory.
+```
+npm install node-addon-api
+```
+
+Then run the script passing your project directory
+```
+node ./node_modules/node-addon-api/tools/conversion.js ./
+```
+
+After finish, recompile and debug things that are missed by the script.
+
+
+### Quick Fixes
+Here is the list of things that can be fixed easily.
+ 1. Change your methods' return value to void if it doesn't return value to JavaScript.
+ 2. Use `.` to access attribute or to invoke member function in Napi::Object instead of `->`.
+ 3. `Napi::New(env, value);` to `Napi::[Type]::New(env, value);
+
+
+### Major Reconstructions
+The implementation of `Napi::ObjectWrap` is significantly different from NAN's. `Napi::ObjectWrap` takes a pointer to the wrapped object and creates a reference to the wrapped object inside ObjectWrap constructor. `Napi::ObjectWrap` also associates wrapped object's instance methods to Javascript module instead of static methods like NAN.
+
+So if you use Nan::ObjectWrap in your module, you will need to execute the following steps.
+
+ 1. Convert your [ClassName]::New function to a constructor function that takes a `Napi::CallbackInfo`. Declare it as
+```
+[ClassName](const Napi::CallbackInfo& info);
+```
+and define it as
+```
+[ClassName]::[ClassName](const Napi::CallbackInfo& info) : Napi::ObjectWrap<[ClassName]>(info){
+ ...
+}
+```
+This way, the `Napi::ObjectWrap` constructor will be invoked after the object has been instantiated and `Napi::ObjectWrap` can use the `this` pointer to create a reference to the wrapped object.
+
+ 2. Move your original constructor code into the new constructor. Delete your original constructor.
+ 3. In your class initialization function, associate native methods in the following way. The `&` character before methods is required because they are not static methods but instance methods.
+```
+Napi::FunctionReference constructor;
+
+void [ClassName]::Init(Napi::Env env, Napi::Object exports, Napi::Object module) {
+ Napi::HandleScope scope(env);
+ Napi::Function ctor = DefineClass(env, "Canvas", {
+ InstanceMethod("Func1", &[ClassName]::Func1),
+ InstanceMethod("Func2", &[ClassName]::Func2),
+ InstanceAccessor("Value", &[ClassName]::ValueGetter),
+ StaticMethod("MethodName", &[ClassName]::StaticMethod),
+ InstanceValue("Value", Napi::[Type]::New(env, value)),
+ });
+
+ constructor = Napi::Persistent(ctor);
+ constructor .SuppressDestruct();
+ exports.Set("[ClassName]", ctor);
+}
+```
+ 4. In function where you need to Unwrap the ObjectWrap in NAN like `[ClassName]* native = Nan::ObjectWrap::Unwrap<[ClassName]>(info.This());`, use `this` pointer directly as the unwrapped object as each ObjectWrap instance is associated with a unique object instance.
+
+
+If you still find issues after following this guide, please leave us an issue describing your problem and we will try to resolve it.
diff --git a/debian/build_modules/node-addon-api/tools/check-napi.js b/debian/build_modules/node-addon-api/tools/check-napi.js
new file mode 100644
index 0000000..48fdfc0
--- /dev/null
+++ b/debian/build_modules/node-addon-api/tools/check-napi.js
@@ -0,0 +1,100 @@
+'use strict';
+// Descend into a directory structure and, for each file matching *.node, output
+// based on the imports found in the file whether it's an N-API module or not.
+
+const fs = require('fs');
+const path = require('path');
+const child_process = require('child_process');
+
+// Read the output of the command, break it into lines, and use the reducer to
+// decide whether the file is an N-API module or not.
+function checkFile(file, command, argv, reducer) {
+ const child = child_process.spawn(command, argv, {
+ stdio: ['inherit', 'pipe', 'inherit']
+ });
+ let leftover = '';
+ let isNapi = undefined;
+ child.stdout.on('data', (chunk) => {
+ if (isNapi === undefined) {
+ chunk = (leftover + chunk.toString()).split(/[\r\n]+/);
+ leftover = chunk.pop();
+ isNapi = chunk.reduce(reducer, isNapi);
+ if (isNapi !== undefined) {
+ child.kill();
+ }
+ }
+ });
+ child.on('close', (code, signal) => {
+ if ((code === null && signal !== null) || (code !== 0)) {
+ console.log(
+ command + ' exited with code: ' + code + ' and signal: ' + signal);
+ } else {
+ // Green if it's a N-API module, red otherwise.
+ console.log(
+ '\x1b[' + (isNapi ? '42' : '41') + 'm' +
+ (isNapi ? ' N-API' : 'Not N-API') +
+ '\x1b[0m: ' + file);
+ }
+ });
+}
+
+// Use nm -a to list symbols.
+function checkFileUNIX(file) {
+ checkFile(file, 'nm', ['-a', file], (soFar, line) => {
+ if (soFar === undefined) {
+ line = line.match(/([0-9a-f]*)? ([a-zA-Z]) (.*$)/);
+ if (line[2] === 'U') {
+ if (/^napi/.test(line[3])) {
+ soFar = true;
+ }
+ }
+ }
+ return soFar;
+ });
+}
+
+// Use dumpbin /imports to list symbols.
+function checkFileWin32(file) {
+ checkFile(file, 'dumpbin', ['/imports', file], (soFar, line) => {
+ if (soFar === undefined) {
+ line = line.match(/([0-9a-f]*)? +([a-zA-Z0-9]) (.*$)/);
+ if (line && /^napi/.test(line[line.length - 1])) {
+ soFar = true;
+ }
+ }
+ return soFar;
+ });
+}
+
+// Descend into a directory structure and pass each file ending in '.node' to
+// one of the above checks, depending on the OS.
+function recurse(top) {
+ fs.readdir(top, (error, items) => {
+ if (error) {
+ throw ("error reading directory " + top + ": " + error);
+ }
+ items.forEach((item) => {
+ item = path.join(top, item);
+ fs.stat(item, ((item) => (error, stats) => {
+ if (error) {
+ throw ("error about " + item + ": " + error);
+ }
+ if (stats.isDirectory()) {
+ recurse(item);
+ } else if (/[.]node$/.test(item) &&
+ // Explicitly ignore files called 'nothing.node' because they are
+ // artefacts of node-addon-api having identified a version of
+ // Node.js that ships with a correct implementation of N-API.
+ path.basename(item) !== 'nothing.node') {
+ process.platform === 'win32' ?
+ checkFileWin32(item) :
+ checkFileUNIX(item);
+ }
+ })(item));
+ });
+ });
+}
+
+// Start with the directory given on the command line or the current directory
+// if nothing was given.
+recurse(process.argv.length > 3 ? process.argv[2] : '.');
diff --git a/debian/build_modules/node-addon-api/tools/conversion.js b/debian/build_modules/node-addon-api/tools/conversion.js
new file mode 100755
index 0000000..35afc21
--- /dev/null
+++ b/debian/build_modules/node-addon-api/tools/conversion.js
@@ -0,0 +1,313 @@
+#! /usr/bin/env node
+
+'use strict'
+
+const fs = require('fs');
+const path = require('path');
+
+const args = process.argv.slice(2);
+const dir = args[0];
+if (!dir) {
+ console.log('Usage: node ' + path.basename(__filename) + ' <target-dir>');
+ process.exit(1);
+}
+
+const NodeApiVersion = require('../package.json').version;
+
+const disable = args[1];
+if (disable != "--disable" && dir != "--disable") {
+ var ConfigFileOperations = {
+ 'package.json': [
+ [ /([ ]*)"dependencies": {/g, '$1"dependencies": {\n$1 "node-addon-api": "' + NodeApiVersion + '",'],
+ [ /[ ]*"nan": *"[^"]+"(,|)[\n\r]/g, '' ]
+ ],
+ 'binding.gyp': [
+ [ /([ ]*)'include_dirs': \[/g, '$1\'include_dirs\': [\n$1 \'<!@(node -p "require(\\\'node-addon-api\\\').include")\',' ],
+ [ /([ ]*)"include_dirs": \[/g, '$1"include_dirs": [\n$1 "<!@(node -p \\"require(\'node-addon-api\').include\\")",' ],
+ [ /([ ]*)'dependencies': \[/g, '$1\'dependencies\': [\n$1 \'<!(node -p "require(\\\'node-addon-api\\\').gyp")\','],
+ [ /([ ]*)"dependencies": \[/g, '$1"dependencies": [\n$1 "<!(node -p \'require(\\\"node-addon-api\\\").gyp\')",'],
+ [ /[ ]*("|')<!\(node -e ("|'|\\"|\\')require\(("|'|\\"|\\')nan("|'|\\"|\\')\)("|'|\\"|\\')\)("|')(,|)[\r\n]/g, '' ],
+ [ /([ ]*)("|')target_name("|'): ("|')(.+?)("|'),/g, '$1$2target_name$2: $4$5$6,\n $2cflags!$2: [ $2-fno-exceptions$2 ],\n $2cflags_cc!$2: [ $2-fno-exceptions$2 ],\n $2xcode_settings$2: { $2GCC_ENABLE_CPP_EXCEPTIONS$2: $2YES$2,\n $2CLANG_CXX_LIBRARY$2: $2libc++$2,\n $2MACOSX_DEPLOYMENT_TARGET$2: $210.7$2,\n },\n $2msvs_settings$2: {\n $2VCCLCompilerTool$2: { $2ExceptionHandling$2: 1 },\n },' ],
+ ]
+ };
+} else {
+ var ConfigFileOperations = {
+ 'package.json': [
+ [ /([ ]*)"dependencies": {/g, '$1"dependencies": {\n$1 "node-addon-api": "' + NodeApiVersion + '",'],
+ [ /[ ]*"nan": *"[^"]+"(,|)[\n\r]/g, '' ]
+ ],
+ 'binding.gyp': [
+ [ /([ ]*)'include_dirs': \[/g, '$1\'include_dirs\': [\n$1 \'<!@(node -p "require(\\\'node-addon-api\\\').include")\',' ],
+ [ /([ ]*)"include_dirs": \[/g, '$1"include_dirs": [\n$1 "<!@(node -p \'require(\\\"node-addon-api\\\").include\')",' ],
+ [ /([ ]*)'dependencies': \[/g, '$1\'dependencies\': [\n$1 \'<!(node -p "require(\\\'node-addon-api\\\').gyp")\','],
+ [ /([ ]*)"dependencies": \[/g, '$1"dependencies": [\n$1 "<!(node -p \'require(\\\"node-addon-api\\\").gyp\')",'],
+ [ /[ ]*("|')<!\(node -e ("|'|\\"|\\')require\(("|'|\\"|\\')nan("|'|\\"|\\')\)("|'|\\"|\\')\)("|')(,|)[\r\n]/g, '' ],
+ [ /([ ]*)("|')target_name("|'): ("|')(.+?)("|'),/g, '$1$2target_name$2: $4$5$6,\n $2cflags!$2: [ $2-fno-exceptions$2 ],\n $2cflags_cc!$2: [ $2-fno-exceptions$2 ],\n $2defines$2: [ $2NAPI_DISABLE_CPP_EXCEPTIONS$2 ],\n $2conditions$2: [\n [\'OS==\"win\"\', { $2defines$2: [ $2_HAS_EXCEPTIONS=1$2 ] }]\n ]' ],
+ ]
+ };
+}
+
+var SourceFileOperations = [
+ [ /Nan::SetMethod\(target,[\s]*\"(.*)\"[\s]*,[\s]*([^)]+)\)/g, 'exports.Set(Napi::String::New(env, \"$1\"), Napi::Function::New(env, $2))' ],
+
+ [ /v8::Local<v8::FunctionTemplate>\s+(\w+)\s*=\s*Nan::New<FunctionTemplate>\([\w\d:]+\);(?:\w+->Reset\(\1\))?\s+\1->SetClassName\(Nan::String::New\("(\w+)"\)\);/g, 'Napi::Function $1 = DefineClass(env, "$2", {' ],
+ [ /Local<FunctionTemplate>\s+(\w+)\s*=\s*Nan::New<FunctionTemplate>\([\w\d:]+\);\s+(\w+)\.Reset\((\1)\);\s+\1->SetClassName\((Nan::String::New|Nan::New<(v8::)*String>)\("(.+?)"\)\);/g, 'Napi::Function $1 = DefineClass(env, "$6", {'],
+ [ /Local<FunctionTemplate>\s+(\w+)\s*=\s*Nan::New<FunctionTemplate>\([\w\d:]+\);(?:\w+->Reset\(\1\))?\s+\1->SetClassName\(Nan::String::New\("(\w+)"\)\);/g, 'Napi::Function $1 = DefineClass(env, "$2", {' ],
+ [ /Nan::New<v8::FunctionTemplate>\(([\w\d:]+)\)->GetFunction\(\)/g, 'Napi::Function::New(env, $1)' ],
+ [ /Nan::New<FunctionTemplate>\(([\w\d:]+)\)->GetFunction()/g, 'Napi::Function::New(env, $1);' ],
+ [ /Nan::New<v8::FunctionTemplate>\(([\w\d:]+)\)/g, 'Napi::Function::New(env, $1)' ],
+ [ /Nan::New<FunctionTemplate>\(([\w\d:]+)\)/g, 'Napi::Function::New(env, $1)' ],
+
+ // FunctionTemplate to FunctionReference
+ [ /Nan::Persistent<(v8::)*FunctionTemplate>/g, 'Napi::FunctionReference' ],
+ [ /Nan::Persistent<(v8::)*Function>/g, 'Napi::FunctionReference' ],
+ [ /v8::Local<v8::FunctionTemplate>/g, 'Napi::FunctionReference' ],
+ [ /Local<FunctionTemplate>/g, 'Napi::FunctionReference' ],
+ [ /v8::FunctionTemplate/g, 'Napi::FunctionReference' ],
+ [ /FunctionTemplate/g, 'Napi::FunctionReference' ],
+
+
+ [ /([ ]*)Nan::SetPrototypeMethod\(\w+, "(\w+)", (\w+)\);/g, '$1InstanceMethod("$2", &$3),' ],
+ [ /([ ]*)(?:\w+\.Reset\(\w+\);\s+)?\(target\)\.Set\("(\w+)",\s*Nan::GetFunction\((\w+)\)\);/gm,
+ '});\n\n' +
+ '$1constructor = Napi::Persistent($3);\n' +
+ '$1constructor.SuppressDestruct();\n' +
+ '$1target.Set("$2", $3);' ],
+
+
+ // TODO: Other attribute combinations
+ [ /static_cast<PropertyAttribute>\(ReadOnly\s*\|\s*DontDelete\)/gm,
+ 'static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)' ],
+
+ [ /([\w\d:<>]+?)::Cast\((.+?)\)/g, '$2.As<$1>()' ],
+
+ [ /\*Nan::Utf8String\(([^)]+)\)/g, '$1->As<Napi::String>().Utf8Value().c_str()' ],
+ [ /Nan::Utf8String +(\w+)\(([^)]+)\)/g, 'std::string $1 = $2.As<Napi::String>()' ],
+ [ /Nan::Utf8String/g, 'std::string' ],
+
+ [ /v8::String::Utf8Value (.+?)\((.+?)\)/g, 'Napi::String $1(env, $2)' ],
+ [ /String::Utf8Value (.+?)\((.+?)\)/g, 'Napi::String $1(env, $2)' ],
+ [ /\.length\(\)/g, '.Length()' ],
+
+ [ /Nan::MakeCallback\(([^,]+),[\s\\]+([^,]+),/gm, '$2.MakeCallback($1,' ],
+
+ [ /class\s+(\w+)\s*:\s*public\s+Nan::ObjectWrap/g, 'class $1 : public Napi::ObjectWrap<$1>' ],
+ [ /(\w+)\(([^\)]*)\)\s*:\s*Nan::ObjectWrap\(\)\s*(,)?/gm, '$1($2) : Napi::ObjectWrap<$1>()$3' ],
+
+ // HandleOKCallback to OnOK
+ [ /HandleOKCallback/g, 'OnOK' ],
+ // HandleErrorCallback to OnError
+ [ /HandleErrorCallback/g, 'OnError' ],
+
+ // ex. .As<Function>() to .As<Napi::Object>()
+ [ /\.As<v8::(Value|Boolean|String|Number|Object|Array|Symbol|External|Function)>\(\)/g, '.As<Napi::$1>()' ],
+ [ /\.As<(Value|Boolean|String|Number|Object|Array|Symbol|External|Function)>\(\)/g, '.As<Napi::$1>()' ],
+
+ // ex. Nan::New<Number>(info[0]) to Napi::Number::New(info[0])
+ [ /Nan::New<(v8::)*Integer>\((.+?)\)/g, 'Napi::Number::New(env, $2)' ],
+ [ /Nan::New\(([0-9\.]+)\)/g, 'Napi::Number::New(env, $1)' ],
+ [ /Nan::New<(v8::)*String>\("(.+?)"\)/g, 'Napi::String::New(env, "$2")' ],
+ [ /Nan::New\("(.+?)"\)/g, 'Napi::String::New(env, "$1")' ],
+ [ /Nan::New<(v8::)*(.+?)>\(\)/g, 'Napi::$2::New(env)' ],
+ [ /Nan::New<(.+?)>\(\)/g, 'Napi::$1::New(env)' ],
+ [ /Nan::New<(v8::)*(.+?)>\(/g, 'Napi::$2::New(env, ' ],
+ [ /Nan::New<(.+?)>\(/g, 'Napi::$1::New(env, ' ],
+ [ /Nan::NewBuffer\(/g, 'Napi::Buffer<char>::New(env, ' ],
+ // TODO: Properly handle this
+ [ /Nan::New\(/g, 'Napi::New(env, ' ],
+
+ [ /\.IsInt32\(\)/g, '.IsNumber()' ],
+ [ /->IsInt32\(\)/g, '.IsNumber()' ],
+
+
+ [ /(.+?)->BooleanValue\(\)/g, '$1.As<Napi::Boolean>().Value()' ],
+ [ /(.+?)->Int32Value\(\)/g, '$1.As<Napi::Number>().Int32Value()' ],
+ [ /(.+?)->Uint32Value\(\)/g, '$1.As<Napi::Number>().Uint32Value()' ],
+ [ /(.+?)->IntegerValue\(\)/g, '$1.As<Napi::Number>().Int64Value()' ],
+ [ /(.+?)->NumberValue\(\)/g, '$1.As<Napi::Number>().DoubleValue()' ],
+
+ // ex. Nan::To<bool>(info[0]) to info[0].Value()
+ [ /Nan::To<v8::(Boolean|String|Number|Object|Array|Symbol|Function)>\((.+?)\)/g, '$2.To<Napi::$1>()' ],
+ [ /Nan::To<(Boolean|String|Number|Object|Array|Symbol|Function)>\((.+?)\)/g, '$2.To<Napi::$1>()' ],
+ // ex. Nan::To<bool>(info[0]) to info[0].As<Napi::Boolean>().Value()
+ [ /Nan::To<bool>\((.+?)\)/g, '$1.As<Napi::Boolean>().Value()' ],
+ // ex. Nan::To<int>(info[0]) to info[0].As<Napi::Number>().Int32Value()
+ [ /Nan::To<int>\((.+?)\)/g, '$1.As<Napi::Number>().Int32Value()' ],
+ // ex. Nan::To<int32_t>(info[0]) to info[0].As<Napi::Number>().Int32Value()
+ [ /Nan::To<int32_t>\((.+?)\)/g, '$1.As<Napi::Number>().Int32Value()' ],
+ // ex. Nan::To<uint32_t>(info[0]) to info[0].As<Napi::Number>().Uint32Value()
+ [ /Nan::To<uint32_t>\((.+?)\)/g, '$1.As<Napi::Number>().Uint32Value()' ],
+ // ex. Nan::To<int64_t>(info[0]) to info[0].As<Napi::Number>().Int64Value()
+ [ /Nan::To<int64_t>\((.+?)\)/g, '$1.As<Napi::Number>().Int64Value()' ],
+ // ex. Nan::To<float>(info[0]) to info[0].As<Napi::Number>().FloatValue()
+ [ /Nan::To<float>\((.+?)\)/g, '$1.As<Napi::Number>().FloatValue()' ],
+ // ex. Nan::To<double>(info[0]) to info[0].As<Napi::Number>().DoubleValue()
+ [ /Nan::To<double>\((.+?)\)/g, '$1.As<Napi::Number>().DoubleValue()' ],
+
+ [ /Nan::New\((\w+)\)->HasInstance\((\w+)\)/g, '$2.InstanceOf($1.Value())' ],
+
+ [ /Nan::Has\(([^,]+),\s*/gm, '($1).Has(' ],
+ [ /\.Has\([\s|\\]*Nan::New<(v8::)*String>\(([^)]+)\)\)/gm, '.Has($1)' ],
+ [ /\.Has\([\s|\\]*Nan::New\(([^)]+)\)\)/gm, '.Has($1)' ],
+
+ [ /Nan::Get\(([^,]+),\s*/gm, '($1).Get(' ],
+ [ /\.Get\([\s|\\]*Nan::New<(v8::)*String>\(([^)]+)\)\)/gm, '.Get($1)' ],
+ [ /\.Get\([\s|\\]*Nan::New\(([^)]+)\)\)/gm, '.Get($1)' ],
+
+ [ /Nan::Set\(([^,]+),\s*/gm, '($1).Set(' ],
+ [ /\.Set\([\s|\\]*Nan::New<(v8::)*String>\(([^)]+)\)\s*,/gm, '.Set($1,' ],
+ [ /\.Set\([\s|\\]*Nan::New\(([^)]+)\)\s*,/gm, '.Set($1,' ],
+
+
+ // ex. node::Buffer::HasInstance(info[0]) to info[0].IsBuffer()
+ [ /node::Buffer::HasInstance\((.+?)\)/g, '$1.IsBuffer()' ],
+ // ex. node::Buffer::Length(info[0]) to info[0].Length()
+ [ /node::Buffer::Length\((.+?)\)/g, '$1.As<Napi::Buffer<char>>().Length()' ],
+ // ex. node::Buffer::Data(info[0]) to info[0].Data()
+ [ /node::Buffer::Data\((.+?)\)/g, '$1.As<Napi::Buffer<char>>().Data()' ],
+ [ /Nan::CopyBuffer\(/g, 'Napi::Buffer::Copy(env, ' ],
+
+ // Nan::AsyncQueueWorker(worker)
+ [ /Nan::AsyncQueueWorker\((.+)\);/g, '$1.Queue();' ],
+ [ /Nan::(Undefined|Null|True|False)\(\)/g, 'env.$1()' ],
+
+ // Nan::ThrowError(error) to Napi::Error::New(env, error).ThrowAsJavaScriptException()
+ [ /([ ]*)return Nan::Throw(\w*?)Error\((.+?)\);/g, '$1Napi::$2Error::New(env, $3).ThrowAsJavaScriptException();\n$1return env.Null();' ],
+ [ /Nan::Throw(\w*?)Error\((.+?)\);\n(\s*)return;/g, 'Napi::$1Error::New(env, $2).ThrowAsJavaScriptException();\n$3return env.Null();' ],
+ [ /Nan::Throw(\w*?)Error\((.+?)\);/g, 'Napi::$1Error::New(env, $2).ThrowAsJavaScriptException();\n' ],
+ // Nan::RangeError(error) to Napi::RangeError::New(env, error)
+ [ /Nan::(\w*?)Error\((.+)\)/g, 'Napi::$1Error::New(env, $2)' ],
+
+ [ /Nan::Set\((.+?),\n* *(.+?),\n* *(.+?),\n* *(.+?)\)/g, '$1.Set($2, $3, $4)' ],
+
+ [ /Nan::(Escapable)?HandleScope\s+(\w+)\s*;/g, 'Napi::$1HandleScope $2(env);' ],
+ [ /Nan::(Escapable)?HandleScope/g, 'Napi::$1HandleScope' ],
+ [ /Nan::ForceSet\(([^,]+), ?/g, '$1->DefineProperty(' ],
+ [ /\.ForceSet\(Napi::String::New\(env, "(\w+)"\),\s*?/g, '.DefineProperty("$1", ' ],
+ // [ /Nan::GetPropertyNames\(([^,]+)\)/, '$1->GetPropertyNames()' ],
+ [ /Nan::Equals\(([^,]+),/g, '$1.StrictEquals(' ],
+
+
+ [ /(.+)->Set\(/g, '$1.Set\(' ],
+
+
+ [ /Nan::Callback/g, 'Napi::FunctionReference' ],
+
+
+ [ /Nan::Persistent<Object>/g, 'Napi::ObjectReference' ],
+ [ /Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target/g, 'Napi::Env& env, Napi::Object& target' ],
+
+ [ /(\w+)\*\s+(\w+)\s*=\s*Nan::ObjectWrap::Unwrap<\w+>\(info\.This\(\)\);/g, '$1* $2 = this;' ],
+ [ /Nan::ObjectWrap::Unwrap<(\w+)>\((.*)\);/g, '$2.Unwrap<$1>();' ],
+
+ [ /Nan::NAN_METHOD_RETURN_TYPE/g, 'void' ],
+ [ /NAN_INLINE/g, 'inline' ],
+
+ [ /Nan::NAN_METHOD_ARGS_TYPE/g, 'const Napi::CallbackInfo&' ],
+ [ /NAN_METHOD\(([\w\d:]+?)\)/g, 'Napi::Value $1(const Napi::CallbackInfo& info)'],
+ [ /static\s*NAN_GETTER\(([\w\d:]+?)\)/g, 'Napi::Value $1(const Napi::CallbackInfo& info)' ],
+ [ /NAN_GETTER\(([\w\d:]+?)\)/g, 'Napi::Value $1(const Napi::CallbackInfo& info)' ],
+ [ /static\s*NAN_SETTER\(([\w\d:]+?)\)/g, 'void $1(const Napi::CallbackInfo& info, const Napi::Value& value)' ],
+ [ /NAN_SETTER\(([\w\d:]+?)\)/g, 'void $1(const Napi::CallbackInfo& info, const Napi::Value& value)' ],
+ [ /void Init\((v8::)*Local<(v8::)*Object> exports\)/g, 'Napi::Object Init(Napi::Env env, Napi::Object exports)' ],
+ [ /NAN_MODULE_INIT\(([\w\d:]+?)\);/g, 'Napi::Object $1(Napi::Env env, Napi::Object exports);' ],
+ [ /NAN_MODULE_INIT\(([\w\d:]+?)\)/g, 'Napi::Object $1(Napi::Env env, Napi::Object exports)' ],
+
+
+ [ /::(Init(?:ialize)?)\(target\)/g, '::$1(env, target, module)' ],
+ [ /constructor_template/g, 'constructor' ],
+
+ [ /Nan::FunctionCallbackInfo<(v8::)?Value>[ ]*& [ ]*info\)[ ]*{\n*([ ]*)/gm, 'Napi::CallbackInfo& info) {\n$2Napi::Env env = info.Env();\n$2' ],
+ [ /Nan::FunctionCallbackInfo<(v8::)*Value>\s*&\s*info\);/g, 'Napi::CallbackInfo& info);' ],
+ [ /Nan::FunctionCallbackInfo<(v8::)*Value>\s*&/g, 'Napi::CallbackInfo&' ],
+
+ [ /Buffer::HasInstance\(([^)]+)\)/g, '$1.IsBuffer()' ],
+
+ [ /info\[(\d+)\]->/g, 'info[$1].' ],
+ [ /info\[([\w\d]+)\]->/g, 'info[$1].' ],
+ [ /info\.This\(\)->/g, 'info.This().' ],
+ [ /->Is(Object|String|Int32|Number)\(\)/g, '.Is$1()' ],
+ [ /info.GetReturnValue\(\).SetUndefined\(\)/g, 'return env.Undefined()' ],
+ [ /info\.GetReturnValue\(\)\.Set\(((\n|.)+?)\);/g, 'return $1;' ],
+
+
+ // ex. Local<Value> to Napi::Value
+ [ /v8::Local<v8::(Value|Boolean|String|Number|Object|Array|Symbol|External|Function)>/g, 'Napi::$1' ],
+ [ /Local<(Value|Boolean|String|Number|Object|Array|Symbol|External|Function)>/g, 'Napi::$1' ],
+
+ // Declare an env in helper functions that take a Napi::Value
+ [ /(\w+)\(Napi::Value (\w+)(,\s*[^\()]+)?\)\s*{\n*([ ]*)/gm, '$1(Napi::Value $2$3) {\n$4Napi::Env env = $2.Env();\n$4' ],
+
+ // delete #include <node.h> and/or <v8.h>
+ [ /#include +(<|")(?:node|nan).h("|>)/g, "#include $1napi.h$2\n#include $1uv.h$2" ],
+ // NODE_MODULE to NODE_API_MODULE
+ [ /NODE_MODULE/g, 'NODE_API_MODULE' ],
+ [ /Nan::/g, 'Napi::' ],
+ [ /nan.h/g, 'napi.h' ],
+
+ // delete .FromJust()
+ [ /\.FromJust\(\)/g, '' ],
+ // delete .ToLocalCheck()
+ [ /\.ToLocalChecked\(\)/g, '' ],
+ [ /^.*->SetInternalFieldCount\(.*$/gm, '' ],
+
+ // replace using node; and/or using v8; to using Napi;
+ [ /using (node|v8);/g, 'using Napi;' ],
+ [ /using namespace (node|Nan|v8);/g, 'using namespace Napi;' ],
+ // delete using v8::Local;
+ [ /using v8::Local;\n/g, '' ],
+ // replace using v8::XXX; with using Napi::XXX
+ [ /using v8::([A-Za-z]+);/g, 'using Napi::$1;' ],
+
+];
+
+var paths = listFiles(dir);
+paths.forEach(function(dirEntry) {
+ var filename = dirEntry.split('\\').pop().split('/').pop();
+
+ // Check whether the file is a source file or a config file
+ // then execute function accordingly
+ var sourcePattern = /.+\.h|.+\.cc|.+\.cpp/;
+ if (sourcePattern.test(filename)) {
+ convertFile(dirEntry, SourceFileOperations);
+ } else if (ConfigFileOperations[filename] != null) {
+ convertFile(dirEntry, ConfigFileOperations[filename]);
+ }
+});
+
+function listFiles(dir, filelist) {
+ var files = fs.readdirSync(dir);
+ filelist = filelist || [];
+ files.forEach(function(file) {
+ if (file === 'node_modules') {
+ return
+ }
+
+ if (fs.statSync(path.join(dir, file)).isDirectory()) {
+ filelist = listFiles(path.join(dir, file), filelist);
+ } else {
+ filelist.push(path.join(dir, file));
+ }
+ });
+ return filelist;
+}
+
+function convert(content, operations) {
+ for (let i = 0; i < operations.length; i ++) {
+ let operation = operations[i];
+ content = content.replace(operation[0], operation[1]);
+ }
+ return content;
+}
+
+function convertFile(fileName, operations) {
+ fs.readFile(fileName, "utf-8", function (err, file) {
+ if (err) throw err;
+
+ file = convert(file, operations);
+
+ fs.writeFile(fileName, file, function(err){
+ if (err) throw err;
+ });
+ });
+}
diff --git a/debian/changelog b/debian/changelog
index 8ae788d..32c6f70 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,26 @@
+node-sqlite3 (5.0.0+ds1-1) unstable; urgency=medium
+
+ * Team upload
+
+ [ Debian Janitor ]
+ * Use correct machine-readable copyright file URI.
+ * Update renamed lintian tag names in lintian overrides.
+ * Set fields Upstream-Name, Upstream-Contact in debian/copyright.
+ * Set upstream metadata fields: Bug-Submit.
+ * Remove obsolete fields Contact, Name from debian/upstream/metadata (already
+ present in machine-readable debian/copyright).
+
+ [ Xavier Guimard ]
+ * Bump debhelper compatibility level to 13
+ * Use dh-sequence-nodejs
+ * New upstream version 5.0.0+ds1
+ * Embed node-addon-api for build only
+ * Update copyright
+ * Don't launch 2 failed tests with mocha > 5
+ * Update build
+
+ -- Xavier Guimard <yadd@debian.org> Tue, 06 Oct 2020 13:26:32 +0200
+
node-sqlite3 (4.2.0+ds1-2) unstable; urgency=medium
* Limit build architectures to ones nodejs support.
diff --git a/debian/clean b/debian/clean
new file mode 100644
index 0000000..4e098ed
--- /dev/null
+++ b/debian/clean
@@ -0,0 +1,4 @@
+build-tmp-napi-v3/
+node_modules/
+test/support/big.db
+test/tmp/
diff --git a/debian/control b/debian/control
index 36ab2b9..dfae730 100644
--- a/debian/control
+++ b/debian/control
@@ -7,7 +7,7 @@ Uploaders: David Paleino <dapal@debian.org>,
Laszlo Boszormenyi (GCS) <gcs@debian.org>
Testsuite: autopkgtest-pkg-nodejs
Build-Depends:
- debhelper-compat (= 12)
+ debhelper-compat (= 13)
, chrpath
, node-pre-gyp (>= 0.10.2~)
, node-nan (>= 2.12.1)
@@ -15,7 +15,7 @@ Build-Depends:
, libnode-dev
, mocha
, libsqlite3-dev
- , pkg-js-tools (>= 0.8.10)
+ , dh-sequence-nodejs
Standards-Version: 4.5.0
Homepage: https://github.com/mapbox/node-sqlite3/wiki
Vcs-Git: https://salsa.debian.org/js-team/node-sqlite3.git
diff --git a/debian/copyright b/debian/copyright
index d1a817b..e16d30f 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -1,16 +1,31 @@
-Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Files-Excluded: deps/sqlite-*.tar.gz
+Upstream-Name: node-sqlite3
+Upstream-Contact: https://github.com/mapbox/node-sqlite3/issues
Files: *
Copyright: MabBox
License: BSD-3-clause
+Files: Dockerfile
+Copyright: 2004-2010 Internet Systems Consortium, Inc.
+ 1995-2003 Internet Software Consortium
+License: ISC
+
+Files: tools/docker/architecture/linux-*
+Copyright: 2019-present Samsung Electronics Co.
+License: ISC
+
Files: debian/*
Copyright: © 2011-2012, David Paleino <dapal@debian.org>,
© 2013 Jérémy Lal <kapouer@melix.org>,
© 2013- Laszlo Boszormenyi (GCS) <gcs@debian.org>
License: GPL-2+
+Files: debian/build_modules/node-addon-api/*
+Copyright: 2017 Node.js API collaborators <https://github.com/nodejs/node-addon-api#collaborators>
+License: Expat
+
License: BSD-3-clause
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -34,6 +49,25 @@ License: BSD-3-clause
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+License: Expat
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ .
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ .
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
License: GPL-2+
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -50,3 +84,19 @@ License: GPL-2+
.
On Debian systems, the complete text of the GNU General
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
+
+License: ISC
+ Permission to use, copy, modify, and /or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+ .
+ THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS.
+ IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
+ OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+ WHETHER IN AN ACTION OF CONTRACT,
+ NEGLIGENCE OR OTHER TORTIOUS ACTION,
+ ARISING OUT OF OR IN CONNECTION WITH THE USE
+ OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/debian/patches/correct_require_path.patch b/debian/patches/correct_require_path.patch
deleted file mode 100644
index 219bde6..0000000
--- a/debian/patches/correct_require_path.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-Description: correct node_sqlite3.node path
- Packaging ship only the release version of node_sqlite3.node in the same lib
- directory like the other parts of node-sqlite3 .
-Author: Laszlo Boszormenyi (GCS) <gcs@debian.org>
-Last-Update: 2013-12-05
-
----
-
---- node-sqlite3-2.1.19+ds1.orig/lib/binary_name.js
-+++ node-sqlite3-2.1.19+ds1/lib/binary_name.js
-@@ -35,10 +35,13 @@ Binary.prototype.getBasePath = function(
- }
-
- Binary.prototype.getRequirePath = function(configuration) {
-+ return './' + this.filename();
-+/*
- return './' + path.join('binding',
- configuration || this.configuration,
- this.getBasePath(),
- this.filename());
-+*/
- }
-
- Binary.prototype.getModuleAbi = function() {
-@@ -56,4 +59,4 @@ Binary.prototype.getRemotePath = functio
- return this.uri+this.configuration+'/'+this.getArchivePath();
- }
-
--module.exports.Binary = Binary;
-\ No newline at end of file
-+module.exports.Binary = Binary;
diff --git a/debian/patches/series b/debian/patches/series
index 2e133a1..327413f 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1 @@
-#correct_require_path.patch
disable-hard-test.patch
diff --git a/debian/rules b/debian/rules
index 6acf712..8a78555 100755
--- a/debian/rules
+++ b/debian/rules
@@ -8,23 +8,20 @@ export DEB_BUILD_MAINT_OPTIONS = hardening=+all
PKGDIR=$(CURDIR)/debian/node-sqlite3/
+%:
+ dh $@
+
override_dh_clean:
$(RM) -r $(CURDIR)/build \
$(CURDIR)/lib/binding
dh_clean
override_dh_auto_configure:
+ dh_auto_configure --buildsystem=nodejs
node-pre-gyp configure --sqlite=external --module_name=node_sqlite3
override_dh_auto_build:
node-pre-gyp build
-override_dh_fixperms:
- dh_fixperms
- chmod a-x $(PKGDIR)/usr/lib/*/nodejs/sqlite3/lib/binding/node-*/node_sqlite3.node
-
-%:
- dh $@ --with nodejs
-
.PHONY: override_dh_auto_configure override_dh_auto_build \
- override_dh_fixperms override_dh_auto_test
+ override_dh_clean
diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml
new file mode 100644
index 0000000..33c3a64
--- /dev/null
+++ b/debian/salsa-ci.yml
@@ -0,0 +1,4 @@
+---
+include:
+ - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
+ - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides
index e6c1fae..3f71e81 100644
--- a/debian/source/lintian-overrides
+++ b/debian/source/lintian-overrides
@@ -1,4 +1,4 @@
# only long lines, source is readable
source-is-missing test/null_error.test.js line length is 2185 characters (>512)
-insane-line-length-in-source-file test/null_error.test.js line length is 2193 characters (>512)
+very-long-line-length-in-source-file test/null_error.test.js line length is 2193 characters (>512)
source-contains-prebuilt-javascript-object test/null_error.test.js line length is 2185 characters (>512)
diff --git a/debian/tests/pkg-js/test b/debian/tests/pkg-js/test
index f0f4ec3..94e4f1b 100644
--- a/debian/tests/pkg-js/test
+++ b/debian/tests/pkg-js/test
@@ -1 +1 @@
-mocha -R spec --timeout 480000
+mocha -R spec --timeout 480000 `ls test/*.js|grep -v test/open_close.test.js | grep -v test/scheduling.test.js`
diff --git a/debian/upstream/metadata b/debian/upstream/metadata
index d275253..4b6a0f1 100644
--- a/debian/upstream/metadata
+++ b/debian/upstream/metadata
@@ -1,7 +1,6 @@
---
Archive: GitHub
Bug-Database: https://github.com/mapbox/node-sqlite3/issues
-Contact: https://github.com/mapbox/node-sqlite3/issues
-Name: node-sqlite3
+Bug-Submit: https://github.com/mapbox/node-sqlite3/issues/new
Repository: https://github.com/mapbox/node-sqlite3.git
Repository-Browse: https://github.com/mapbox/node-sqlite3
diff --git a/lib/trace.js b/lib/trace.js
index 987f38a..8e25e8a 100644
--- a/lib/trace.js
+++ b/lib/trace.js
@@ -15,17 +15,14 @@ function extendTrace(object, property, pos) {
var cb = arguments[pos];
if (typeof arguments[pos] === 'function') {
arguments[pos] = function replacement() {
- try {
- return cb.apply(this, arguments);
- } catch (err) {
- if (err && err.stack && !err.__augmented) {
- err.stack = filter(err).join('\n');
- err.stack += '\n--> in ' + name;
- err.stack += '\n' + filter(error).slice(1).join('\n');
- err.__augmented = true;
- }
- throw err;
+ var err = arguments[0];
+ if (err && err.stack && !err.__augmented) {
+ err.stack = filter(err).join('\n');
+ err.stack += '\n--> in ' + name;
+ err.stack += '\n' + filter(error).slice(1).join('\n');
+ err.__augmented = true;
}
+ return cb.apply(this, arguments);
};
}
return old.apply(this, arguments);
diff --git a/package.json b/package.json
index f4e4555..dfc3901 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "sqlite3",
"description": "Asynchronous, non-blocking SQLite3 bindings",
- "version": "4.2.0",
+ "version": "5.0.0",
"homepage": "https://github.com/mapbox/node-sqlite3",
"author": {
"name": "MapBox",
@@ -9,10 +9,13 @@
},
"binary": {
"module_name": "node_sqlite3",
- "module_path": "./lib/binding/{node_abi}-{platform}-{arch}",
+ "module_path": "./lib/binding/napi-v{napi_build_version}-{platform}-{arch}",
"host": "https://mapbox-node-binary.s3.amazonaws.com",
"remote_path": "./{name}/v{version}/{toolset}/",
- "package_name": "{node_abi}-{platform}-{arch}.tar.gz"
+ "package_name": "napi-v{napi_build_version}-{platform}-{arch}.tar.gz",
+ "napi_versions": [
+ 3
+ ]
},
"contributors": [
"Konstantin Käfer <mail@kkaefer.com>",
@@ -37,7 +40,7 @@
"url": "git://github.com/mapbox/node-sqlite3.git"
},
"dependencies": {
- "nan": "^2.12.1",
+ "node-addon-api": "2.0.0",
"node-pre-gyp": "^0.11.0"
},
"devDependencies": {
@@ -46,6 +49,17 @@
"eslint": "3.5.0",
"mocha": "^5.2.0"
},
+ "peerDependencies": {
+ "node-gyp": "3.x"
+ },
+ "peerDependenciesMeta": {
+ "node-gyp": {
+ "optional": true
+ }
+ },
+ "optionalDependencies": {
+ "node-gyp": "3.x"
+ },
"scripts": {
"install": "node-pre-gyp install --fallback-to-build",
"pretest": "node test/support/createdb.js",
diff --git a/scripts/build-appveyor.bat b/scripts/build-appveyor.bat
index d3befa4..942845d 100644
--- a/scripts/build-appveyor.bat
+++ b/scripts/build-appveyor.bat
@@ -35,9 +35,6 @@ ECHO downloading/installing node
powershell Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) $env:PLATFORM
IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-powershell Set-ExecutionPolicy Unrestricted -Scope CurrentUser -Force
-IF %ERRORLEVEL% NEQ 0 GOTO ERROR
-
ECHO available node.exe^:
call where node
ECHO available npm^:
diff --git a/src/async.h b/src/async.h
index 5232c12..9c4d892 100644
--- a/src/async.h
+++ b/src/async.h
@@ -1,8 +1,10 @@
#ifndef NODE_SQLITE3_SRC_ASYNC_H
#define NODE_SQLITE3_SRC_ASYNC_H
+#include <napi.h>
+#include <uv.h>
+
#include "threading.h"
-#include <node_version.h>
#if defined(NODE_SQLITE3_BOOST_THREADING)
#include <boost/thread/mutex.hpp>
@@ -26,10 +28,12 @@ public:
: callback(cb_), parent(parent_) {
watcher.data = this;
NODE_SQLITE3_MUTEX_INIT
- uv_async_init(uv_default_loop(), &watcher, reinterpret_cast<uv_async_cb>(listener));
+ uv_loop_t *loop;
+ napi_get_uv_event_loop(parent_->Env(), &loop);
+ uv_async_init(loop, &watcher, reinterpret_cast<uv_async_cb>(listener));
}
- static void listener(uv_async_t* handle, int status) {
+ static void listener(uv_async_t* handle) {
Async* async = static_cast<Async*>(handle->data);
std::vector<Item*> rows;
NODE_SQLITE3_MUTEX_LOCK(&async->mutex)
@@ -51,7 +55,7 @@ public:
// Need to call the listener again to ensure all items have been
// processed. Is this a bug in uv_async? Feels like uv_close
// should handle that.
- listener(&watcher, 0);
+ listener(&watcher);
uv_close((uv_handle_t*)&watcher, close);
}
diff --git a/src/backup.cc b/src/backup.cc
index 17eafc3..470d8f5 100644
--- a/src/backup.cc
+++ b/src/backup.cc
@@ -1,7 +1,5 @@
#include <string.h>
-#include <node.h>
-#include <node_buffer.h>
-#include <node_version.h>
+#include <napi.h>
#include "macros.h"
#include "database.h"
@@ -9,31 +7,28 @@
using namespace node_sqlite3;
-Nan::Persistent<FunctionTemplate> Backup::constructor_template;
+Napi::FunctionReference Backup::constructor;
-NAN_MODULE_INIT(Backup::Init) {
- Nan::HandleScope scope;
+Napi::Object Backup::Init(Napi::Env env, Napi::Object exports) {
+ Napi::HandleScope scope(env);
- Local<FunctionTemplate> t = Nan::New<FunctionTemplate>(New);
+ Napi::Function t = DefineClass(env, "Backup", {
+ InstanceMethod("step", &Backup::Step),
+ InstanceMethod("finish", &Backup::Finish),
+ InstanceAccessor("idle", &Backup::IdleGetter, nullptr),
+ InstanceAccessor("completed", &Backup::CompletedGetter, nullptr),
+ InstanceAccessor("failed", &Backup::FailedGetter, nullptr),
+ InstanceAccessor("remaining", &Backup::RemainingGetter, nullptr),
+ InstanceAccessor("pageCount", &Backup::PageCountGetter, nullptr),
+ InstanceAccessor("retryErrors", &Backup::RetryErrorGetter, &Backup::RetryErrorSetter),
+ });
- t->InstanceTemplate()->SetInternalFieldCount(1);
- t->SetClassName(Nan::New("Backup").ToLocalChecked());
+ constructor = Napi::Persistent(t);
+ constructor.SuppressDestruct();
- Nan::SetPrototypeMethod(t, "step", Step);
- Nan::SetPrototypeMethod(t, "finish", Finish);
-
- NODE_SET_GETTER(t, "idle", IdleGetter);
- NODE_SET_GETTER(t, "completed", CompletedGetter);
- NODE_SET_GETTER(t, "failed", FailedGetter);
- NODE_SET_GETTER(t, "remaining", RemainingGetter);
- NODE_SET_GETTER(t, "pageCount", PageCountGetter);
-
- NODE_SET_SETTER(t, "retryErrors", RetryErrorGetter, RetryErrorSetter);
-
- constructor_template.Reset(t);
- Nan::Set(target, Nan::New("Backup").ToLocalChecked(),
- Nan::GetFunction(t).ToLocalChecked());
+ exports.Set("Backup", t);
+ return exports;
}
void Backup::Process() {
@@ -64,33 +59,35 @@ void Backup::Schedule(Work_Callback callback, Baton* baton) {
}
template <class T> void Backup::Error(T* baton) {
- Nan::HandleScope scope;
+ Napi::Env env = baton->backup->Env();
+ Napi::HandleScope scope(env);
Backup* backup = baton->backup;
// Fail hard on logic errors.
assert(backup->status != 0);
- EXCEPTION(backup->message, backup->status, exception);
+ EXCEPTION(Napi::String::New(env, backup->message), backup->status, exception);
- Local<Function> cb = Nan::New(baton->callback);
+ Napi::Function cb = baton->callback.Value();
- if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[] = { exception };
- TRY_CATCH_CALL(backup->handle(), cb, 1, argv);
+ if (!cb.IsEmpty() && cb.IsFunction()) {
+ Napi::Value argv[] = { exception };
+ TRY_CATCH_CALL(backup->Value(), cb, 1, argv);
}
else {
- Local<Value> argv[] = { Nan::New("error").ToLocalChecked(), exception };
- EMIT_EVENT(backup->handle(), 2, argv);
+ Napi::Value argv[] = { Napi::String::New(env, "error"), exception };
+ EMIT_EVENT(backup->Value(), 2, argv);
}
}
void Backup::CleanQueue() {
- Nan::HandleScope scope;
+ Napi::Env env = this->Env();
+ Napi::HandleScope scope(env);
if (inited && !queue.empty()) {
// This backup has already been initialized and is now finished.
// Fire error for all remaining items in the queue.
- EXCEPTION("Backup is already finished", SQLITE_MISUSE, exception);
- Local<Value> argv[] = { exception };
+ EXCEPTION(Napi::String::New(env, "Backup is already finished"), SQLITE_MISUSE, exception);
+ Napi::Value argv[] = { exception };
bool called = false;
// Clear out the queue so that this object can get GC'ed.
@@ -98,11 +95,11 @@ void Backup::CleanQueue() {
Call* call = queue.front();
queue.pop();
- Local<Function> cb = Nan::New(call->baton->callback);
+ Napi::Function cb = call->baton->callback.Value();
if (inited && !cb.IsEmpty() &&
- cb->IsFunction()) {
- TRY_CATCH_CALL(handle(), cb, 1, argv);
+ cb.IsFunction()) {
+ TRY_CATCH_CALL(Value(), cb, 1, argv);
called = true;
}
@@ -115,8 +112,8 @@ void Backup::CleanQueue() {
// When we couldn't call a callback function, emit an error on the
// Backup object.
if (!called) {
- Local<Value> info[] = { Nan::New("error").ToLocalChecked(), exception };
- EMIT_EVENT(handle(), 2, info);
+ Napi::Value info[] = { Napi::String::New(env, "error"), exception };
+ EMIT_EVENT(Value(), 2, info);
}
}
else while (!queue.empty()) {
@@ -132,65 +129,74 @@ void Backup::CleanQueue() {
}
}
-NAN_METHOD(Backup::New) {
+Backup::Backup(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Backup>(info) {
+ Napi::Env env = info.Env();
if (!info.IsConstructCall()) {
- return Nan::ThrowTypeError("Use the new operator to create new Backup objects");
+ Napi::TypeError::New(env, "Use the new operator to create new Backup objects").ThrowAsJavaScriptException();
+ return;
}
int length = info.Length();
if (length <= 0 || !Database::HasInstance(info[0])) {
- return Nan::ThrowTypeError("Database object expected");
+ Napi::TypeError::New(env, "Database object expected").ThrowAsJavaScriptException();
+ return;
}
- else if (length <= 1 || !info[1]->IsString()) {
- return Nan::ThrowTypeError("Filename expected");
+ else if (length <= 1 || !info[1].IsString()) {
+ Napi::TypeError::New(env, "Filename expected").ThrowAsJavaScriptException();
+ return;
}
- else if (length <= 2 || !info[2]->IsString()) {
- return Nan::ThrowTypeError("Source database name expected");
+ else if (length <= 2 || !info[2].IsString()) {
+ Napi::TypeError::New(env, "Source database name expected").ThrowAsJavaScriptException();
+ return;
}
- else if (length <= 3 || !info[3]->IsString()) {
- return Nan::ThrowTypeError("Destination database name expected");
+ else if (length <= 3 || !info[3].IsString()) {
+ Napi::TypeError::New(env, "Destination database name expected").ThrowAsJavaScriptException();
+ return;
}
- else if (length <= 4 || !info[4]->IsBoolean()) {
- return Nan::ThrowTypeError("Direction flag expected");
+ else if (length <= 4 || !info[4].IsBoolean()) {
+ Napi::TypeError::New(env, "Direction flag expected").ThrowAsJavaScriptException();
+ return;
}
- else if (length > 5 && !info[5]->IsUndefined() && !info[5]->IsFunction()) {
- return Nan::ThrowTypeError("Callback expected");
+ else if (length > 5 && !info[5].IsUndefined() && !info[5].IsFunction()) {
+ Napi::TypeError::New(env, "Callback expected").ThrowAsJavaScriptException();
+ return;
}
- Database* db = Nan::ObjectWrap::Unwrap<Database>(info[0].As<Object>());
- Local<String> filename = Local<String>::Cast(info[1]);
- Local<String> sourceName = Local<String>::Cast(info[2]);
- Local<String> destName = Local<String>::Cast(info[3]);
- Local<Boolean> filenameIsDest = Local<Boolean>::Cast(info[4]);
-
- Nan::ForceSet(info.This(), Nan::New("filename").ToLocalChecked(), filename, ReadOnly);
- Nan::ForceSet(info.This(), Nan::New("sourceName").ToLocalChecked(), sourceName, ReadOnly);
- Nan::ForceSet(info.This(), Nan::New("destName").ToLocalChecked(), destName, ReadOnly);
- Nan::ForceSet(info.This(), Nan::New("filenameIsDest").ToLocalChecked(), filenameIsDest, ReadOnly);
-
- Backup* backup = new Backup(db);
- backup->Wrap(info.This());
-
- InitializeBaton* baton = new InitializeBaton(db, Local<Function>::Cast(info[5]), backup);
- baton->filename = std::string(*Nan::Utf8String(filename));
- baton->sourceName = std::string(*Nan::Utf8String(sourceName));
- baton->destName = std::string(*Nan::Utf8String(destName));
- baton->filenameIsDest = Nan::To<bool>(filenameIsDest).FromJust();
- db->Schedule(Work_BeginInitialize, baton);
+ Database* db = Napi::ObjectWrap<Database>::Unwrap(info[0].As<Napi::Object>());
+ Napi::String filename = info[1].As<Napi::String>();
+ Napi::String sourceName = info[2].As<Napi::String>();
+ Napi::String destName = info[3].As<Napi::String>();
+ Napi::Boolean filenameIsDest = info[4].As<Napi::Boolean>();
- info.GetReturnValue().Set(info.This());
+ info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("filename", filename));
+ info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("sourceName", sourceName));
+ info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("destName", destName));
+ info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("filenameIsDest", filenameIsDest));
+
+ init(db);
+
+ InitializeBaton* baton = new InitializeBaton(db, info[5].As<Napi::Function>(), this);
+ baton->filename = filename.Utf8Value();
+ baton->sourceName = sourceName.Utf8Value();
+ baton->destName = destName.Utf8Value();
+ baton->filenameIsDest = filenameIsDest.Value();
+ db->Schedule(Work_BeginInitialize, baton);
}
void Backup::Work_BeginInitialize(Database::Baton* baton) {
assert(baton->db->open);
baton->db->pending++;
- int status = uv_queue_work(uv_default_loop(),
- &baton->request, Work_Initialize, (uv_after_work_cb)Work_AfterInitialize);
+ Napi::Env env = baton->db->Env();
+ int status = napi_create_async_work(
+ env, NULL, Napi::String::New(env, "sqlite3.Backup.Initialize"),
+ Work_Initialize, Work_AfterInitialize, baton, &baton->request
+ );
assert(status == 0);
+ napi_queue_async_work(env, baton->request);
}
-void Backup::Work_Initialize(uv_work_t* req) {
+void Backup::Work_Initialize(napi_env e, void* data) {
BACKUP_INIT(InitializeBaton);
// In case stepping fails, we use a mutex to make sure we get the associated
@@ -219,28 +225,30 @@ void Backup::Work_Initialize(uv_work_t* req) {
sqlite3_mutex_leave(mtx);
}
-void Backup::Work_AfterInitialize(uv_work_t* req) {
- Nan::HandleScope scope;
-
+void Backup::Work_AfterInitialize(napi_env e, napi_status status, void* data) {
BACKUP_INIT(InitializeBaton);
+ Napi::Env env = backup->Env();
+ Napi::HandleScope scope(env);
+
if (backup->status != SQLITE_OK) {
Error(baton);
backup->FinishAll();
}
else {
backup->inited = true;
- Local<Function> cb = Nan::New(baton->callback);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[] = { Nan::Null() };
- TRY_CATCH_CALL(backup->handle(), cb, 1, argv);
+ Napi::Function cb = baton->callback.Value();
+ if (!cb.IsEmpty() && cb.IsFunction()) {
+ Napi::Value argv[] = { env.Null() };
+ TRY_CATCH_CALL(backup->Value(), cb, 1, argv);
}
}
BACKUP_END();
}
-NAN_METHOD(Backup::Step) {
- Backup* backup = Nan::ObjectWrap::Unwrap<Backup>(info.This());
+Napi::Value Backup::Step(const Napi::CallbackInfo& info) {
+ Backup* backup = this;
+ Napi::Env env = backup->Env();
REQUIRE_ARGUMENT_INTEGER(0, pages);
OPTIONAL_ARGUMENT_FUNCTION(1, callback);
@@ -248,14 +256,14 @@ NAN_METHOD(Backup::Step) {
StepBaton* baton = new StepBaton(backup, callback, pages);
backup->GetRetryErrors(baton->retryErrorsSet);
backup->Schedule(Work_BeginStep, baton);
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
void Backup::Work_BeginStep(Baton* baton) {
BACKUP_BEGIN(Step);
}
-void Backup::Work_Step(uv_work_t* req) {
+void Backup::Work_Step(napi_env e, void* data) {
BACKUP_INIT(StepBaton);
if (backup->_handle) {
backup->status = sqlite3_backup_step(backup->_handle, baton->pages);
@@ -279,11 +287,12 @@ void Backup::Work_Step(uv_work_t* req) {
}
}
-void Backup::Work_AfterStep(uv_work_t* req) {
- Nan::HandleScope scope;
-
+void Backup::Work_AfterStep(napi_env e, napi_status status, void* data) {
BACKUP_INIT(StepBaton);
+ Napi::Env env = backup->Env();
+ Napi::HandleScope scope(env);
+
if (backup->status == SQLITE_DONE) {
backup->completed = true;
} else if (!backup->_handle) {
@@ -295,45 +304,48 @@ void Backup::Work_AfterStep(uv_work_t* req) {
}
else {
// Fire callbacks.
- Local<Function> cb = Nan::New(baton->callback);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[] = { Nan::Null(), Nan::New(backup->status == SQLITE_DONE) };
- TRY_CATCH_CALL(backup->handle(), cb, 2, argv);
+ Napi::Function cb = baton->callback.Value();
+ if (!cb.IsEmpty() && cb.IsFunction()) {
+ Napi::Value argv[] = { env.Null(), Napi::Boolean::New(env, backup->status == SQLITE_DONE) };
+ TRY_CATCH_CALL(backup->Value(), cb, 2, argv);
}
}
BACKUP_END();
}
-NAN_METHOD(Backup::Finish) {
- Backup* backup = Nan::ObjectWrap::Unwrap<Backup>(info.This());
+Napi::Value Backup::Finish(const Napi::CallbackInfo& info) {
+ Backup* backup = this;
+ Napi::Env env = backup->Env();
OPTIONAL_ARGUMENT_FUNCTION(0, callback);
Baton* baton = new Baton(backup, callback);
backup->Schedule(Work_BeginFinish, baton);
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
void Backup::Work_BeginFinish(Baton* baton) {
BACKUP_BEGIN(Finish);
}
-void Backup::Work_Finish(uv_work_t* req) {
+void Backup::Work_Finish(napi_env e, void* data) {
BACKUP_INIT(Baton);
backup->FinishSqlite();
}
-void Backup::Work_AfterFinish(uv_work_t* req) {
- Nan::HandleScope scope;
-
+void Backup::Work_AfterFinish(napi_env e, napi_status status, void* data) {
BACKUP_INIT(Baton);
+
+ Napi::Env env = backup->Env();
+ Napi::HandleScope scope(env);
+
backup->FinishAll();
// Fire callback in case there was one.
- Local<Function> cb = Nan::New(baton->callback);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- TRY_CATCH_CALL(backup->handle(), cb, 0, NULL);
+ Napi::Function cb = baton->callback.Value();
+ if (!cb.IsEmpty() && cb.IsFunction()) {
+ TRY_CATCH_CALL(backup->Value(), cb, 0, NULL);
}
BACKUP_END();
@@ -362,55 +374,56 @@ void Backup::FinishSqlite() {
_destDb = NULL;
}
-NAN_GETTER(Backup::IdleGetter) {
- Backup* backup = Nan::ObjectWrap::Unwrap<Backup>(info.This());
+Napi::Value Backup::IdleGetter(const Napi::CallbackInfo& info) {
+ Backup* backup = this;
bool idle = backup->inited && !backup->locked && backup->queue.empty();
- info.GetReturnValue().Set(idle);
+ return Napi::Boolean::New(this->Env(), idle);
}
-NAN_GETTER(Backup::CompletedGetter) {
- Backup* backup = Nan::ObjectWrap::Unwrap<Backup>(info.This());
- info.GetReturnValue().Set(backup->completed);
+Napi::Value Backup::CompletedGetter(const Napi::CallbackInfo& info) {
+ Backup* backup = this;
+ return Napi::Boolean::New(this->Env(), backup->completed);
}
-NAN_GETTER(Backup::FailedGetter) {
- Backup* backup = Nan::ObjectWrap::Unwrap<Backup>(info.This());
- info.GetReturnValue().Set(backup->failed);
+Napi::Value Backup::FailedGetter(const Napi::CallbackInfo& info) {
+ Backup* backup = this;
+ return Napi::Boolean::New(this->Env(), backup->failed);
}
-NAN_GETTER(Backup::RemainingGetter) {
- Backup* backup = Nan::ObjectWrap::Unwrap<Backup>(info.This());
- info.GetReturnValue().Set(backup->remaining);
+Napi::Value Backup::RemainingGetter(const Napi::CallbackInfo& info) {
+ Backup* backup = this;
+ return Napi::Number::New(this->Env(), backup->remaining);
}
-NAN_GETTER(Backup::PageCountGetter) {
- Backup* backup = Nan::ObjectWrap::Unwrap<Backup>(info.This());
- info.GetReturnValue().Set(backup->pageCount);
+Napi::Value Backup::PageCountGetter(const Napi::CallbackInfo& info) {
+ Backup* backup = this;
+ return Napi::Number::New(this->Env(), backup->pageCount);
}
-NAN_GETTER(Backup::RetryErrorGetter) {
- Backup* backup = Nan::ObjectWrap::Unwrap<Backup>(info.This());
- info.GetReturnValue().Set(Nan::New(backup->retryErrors));
+Napi::Value Backup::RetryErrorGetter(const Napi::CallbackInfo& info) {
+ Backup* backup = this;
+ return backup->retryErrors.Value();
}
-NAN_SETTER(Backup::RetryErrorSetter) {
- Backup* backup = Nan::ObjectWrap::Unwrap<Backup>(info.This());
- if (!value->IsArray()) {
- return Nan::ThrowError("retryErrors must be an array");
+void Backup::RetryErrorSetter(const Napi::CallbackInfo& info, const Napi::Value& value) {
+ Backup* backup = this;
+ Napi::Env env = backup->Env();
+ if (!value.IsArray()) {
+ Napi::Error::New(env, "retryErrors must be an array").ThrowAsJavaScriptException();
+ return;
}
- Local<Array> array = Local<Array>::Cast(value);
- backup->retryErrors.Reset(array);
+ Napi::Array array = value.As<Napi::Array>();
+ backup->retryErrors.Reset(array, 1);
}
void Backup::GetRetryErrors(std::set<int>& retryErrorsSet) {
retryErrorsSet.clear();
- Local<Array> array = Nan::New(retryErrors);
- int length = array->Length();
+ Napi::Array array = retryErrors.Value();
+ int length = array.Length();
for (int i = 0; i < length; i++) {
- Local<Value> code = Nan::Get(array, i).ToLocalChecked();
- if (code->IsInt32()) {
- retryErrorsSet.insert(Nan::To<int32_t>(code).FromJust());
+ Napi::Value code = (array).Get(i);
+ if (code.IsNumber()) {
+ retryErrorsSet.insert(code.As<Napi::Number>().Int32Value());
}
}
}
-
diff --git a/src/backup.h b/src/backup.h
index 723f8c9..95edc1a 100644
--- a/src/backup.h
+++ b/src/backup.h
@@ -8,10 +8,9 @@
#include <set>
#include <sqlite3.h>
-#include <nan.h>
+#include <napi.h>
-using namespace v8;
-using namespace node;
+using namespace Napi;
namespace node_sqlite3 {
@@ -92,22 +91,20 @@ namespace node_sqlite3 {
* backup.finish();
*
*/
-class Backup : public Nan::ObjectWrap {
+class Backup : public Napi::ObjectWrap<Backup> {
public:
- static Nan::Persistent<FunctionTemplate> constructor_template;
+ static Napi::FunctionReference constructor;
- static NAN_MODULE_INIT(Init);
- static NAN_METHOD(New);
+ static Napi::Object Init(Napi::Env env, Napi::Object exports);
struct Baton {
- uv_work_t request;
+ napi_async_work request;
Backup* backup;
- Nan::Persistent<Function> callback;
+ Napi::FunctionReference callback;
- Baton(Backup* backup_, Local<Function> cb_) : backup(backup_) {
+ Baton(Backup* backup_, Napi::Function cb_) : backup(backup_) {
backup->Ref();
- request.data = this;
- callback.Reset(cb_);
+ callback.Reset(cb_, 1);
}
virtual ~Baton() {
backup->Unref();
@@ -121,7 +118,7 @@ public:
std::string sourceName;
std::string destName;
bool filenameIsDest;
- InitializeBaton(Database* db_, Local<Function> cb_, Backup* backup_) :
+ InitializeBaton(Database* db_, Napi::Function cb_, Backup* backup_) :
Baton(db_, cb_), backup(backup_), filenameIsDest(true) {
backup->Ref();
}
@@ -137,7 +134,7 @@ public:
struct StepBaton : Baton {
int pages;
std::set<int> retryErrorsSet;
- StepBaton(Backup* backup_, Local<Function> cb_, int pages_) :
+ StepBaton(Backup* backup_, Napi::Function cb_, int pages_) :
Baton(backup_, cb_), pages(pages_) {}
};
@@ -149,21 +146,23 @@ public:
Baton* baton;
};
- Backup(Database* db_) : Nan::ObjectWrap(),
- db(db_),
- _handle(NULL),
- _otherDb(NULL),
- _destDb(NULL),
- inited(false),
- locked(true),
- completed(false),
- failed(false),
- remaining(-1),
- pageCount(-1),
- finished(false) {
+ void init(Database* db_) {
+ db = db_;
+ _handle = NULL;
+ _otherDb = NULL;
+ _destDb = NULL;
+ inited = false;
+ locked = true;
+ completed = false;
+ failed = false;
+ remaining = -1;
+ pageCount = -1;
+ finished = false;
db->Ref();
}
+ Backup(const Napi::CallbackInfo& info);
+
~Backup() {
if (!finished) {
FinishAll();
@@ -173,21 +172,21 @@ public:
WORK_DEFINITION(Step);
WORK_DEFINITION(Finish);
- static NAN_GETTER(IdleGetter);
- static NAN_GETTER(CompletedGetter);
- static NAN_GETTER(FailedGetter);
- static NAN_GETTER(PageCountGetter);
- static NAN_GETTER(RemainingGetter);
- static NAN_GETTER(FatalErrorGetter);
- static NAN_GETTER(RetryErrorGetter);
+ Napi::Value IdleGetter(const Napi::CallbackInfo& info);
+ Napi::Value CompletedGetter(const Napi::CallbackInfo& info);
+ Napi::Value FailedGetter(const Napi::CallbackInfo& info);
+ Napi::Value PageCountGetter(const Napi::CallbackInfo& info);
+ Napi::Value RemainingGetter(const Napi::CallbackInfo& info);
+ Napi::Value FatalErrorGetter(const Napi::CallbackInfo& info);
+ Napi::Value RetryErrorGetter(const Napi::CallbackInfo& info);
- static NAN_SETTER(FatalErrorSetter);
- static NAN_SETTER(RetryErrorSetter);
+ void FatalErrorSetter(const Napi::CallbackInfo& info, const Napi::Value& value);
+ void RetryErrorSetter(const Napi::CallbackInfo& info, const Napi::Value& value);
protected:
static void Work_BeginInitialize(Database::Baton* baton);
- static void Work_Initialize(uv_work_t* req);
- static void Work_AfterInitialize(uv_work_t* req);
+ static void Work_Initialize(napi_env env, void* data);
+ static void Work_AfterInitialize(napi_env env, napi_status status, void* data);
void Schedule(Work_Callback callback, Baton* baton);
void Process();
@@ -215,7 +214,7 @@ protected:
bool finished;
std::queue<Call*> queue;
- Nan::Persistent<Array> retryErrors;
+ Napi::Reference<Array> retryErrors;
};
}
diff --git a/src/database.cc b/src/database.cc
index ace5fa0..7b33193 100644
--- a/src/database.cc
+++ b/src/database.cc
@@ -6,47 +6,45 @@
using namespace node_sqlite3;
-Nan::Persistent<FunctionTemplate> Database::constructor_template;
+Napi::FunctionReference Database::constructor;
-NAN_MODULE_INIT(Database::Init) {
- Nan::HandleScope scope;
+Napi::Object Database::Init(Napi::Env env, Napi::Object exports) {
+ Napi::HandleScope scope(env);
- Local<FunctionTemplate> t = Nan::New<FunctionTemplate>(New);
+ Napi::Function t = DefineClass(env, "Database", {
+ InstanceMethod("close", &Database::Close),
+ InstanceMethod("exec", &Database::Exec),
+ InstanceMethod("wait", &Database::Wait),
+ InstanceMethod("loadExtension", &Database::LoadExtension),
+ InstanceMethod("serialize", &Database::Serialize),
+ InstanceMethod("parallelize", &Database::Parallelize),
+ InstanceMethod("configure", &Database::Configure),
+ InstanceMethod("interrupt", &Database::Interrupt),
+ InstanceAccessor("open", &Database::OpenGetter, nullptr)
+ });
- t->InstanceTemplate()->SetInternalFieldCount(1);
- t->SetClassName(Nan::New("Database").ToLocalChecked());
+ constructor = Napi::Persistent(t);
+ constructor.SuppressDestruct();
- Nan::SetPrototypeMethod(t, "close", Close);
- Nan::SetPrototypeMethod(t, "exec", Exec);
- Nan::SetPrototypeMethod(t, "wait", Wait);
- Nan::SetPrototypeMethod(t, "loadExtension", LoadExtension);
- Nan::SetPrototypeMethod(t, "serialize", Serialize);
- Nan::SetPrototypeMethod(t, "parallelize", Parallelize);
- Nan::SetPrototypeMethod(t, "configure", Configure);
- Nan::SetPrototypeMethod(t, "interrupt", Interrupt);
-
- NODE_SET_GETTER(t, "open", OpenGetter);
-
- constructor_template.Reset(t);
-
- Nan::Set(target, Nan::New("Database").ToLocalChecked(),
- Nan::GetFunction(t).ToLocalChecked());
+ exports.Set("Database", t);
+ return exports;
}
void Database::Process() {
- Nan::HandleScope scope;
+ Napi::Env env = this->Env();
+ Napi::HandleScope scope(env);
if (!open && locked && !queue.empty()) {
- EXCEPTION("Database handle is closed", SQLITE_MISUSE, exception);
- Local<Value> argv[] = { exception };
+ EXCEPTION(Napi::String::New(env, "Database handle is closed"), SQLITE_MISUSE, exception);
+ Napi::Value argv[] = { exception };
bool called = false;
// Call all callbacks with the error object.
while (!queue.empty()) {
Call* call = queue.front();
- Local<Function> cb = Nan::New(call->baton->callback);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- TRY_CATCH_CALL(this->handle(), cb, 1, argv);
+ Napi::Function cb = call->baton->callback.Value();
+ if (!cb.IsUndefined() && cb.IsFunction()) {
+ TRY_CATCH_CALL(this->Value(), cb, 1, argv);
called = true;
}
queue.pop();
@@ -59,8 +57,8 @@ void Database::Process() {
// When we couldn't call a callback function, emit an error on the
// Database object.
if (!called) {
- Local<Value> info[] = { Nan::New("error").ToLocalChecked(), exception };
- EMIT_EVENT(handle(), 2, info);
+ Napi::Value info[] = { Napi::String::New(env, "error"), exception };
+ EMIT_EVENT(Value(), 2, info);
}
return;
}
@@ -82,18 +80,19 @@ void Database::Process() {
}
void Database::Schedule(Work_Callback callback, Baton* baton, bool exclusive) {
- Nan::HandleScope scope;
+ Napi::Env env = this->Env();
+ Napi::HandleScope scope(env);
if (!open && locked) {
- EXCEPTION("Database is closed", SQLITE_MISUSE, exception);
- Local<Function> cb = Nan::New(baton->callback);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[] = { exception };
- TRY_CATCH_CALL(handle(), cb, 1, argv);
+ EXCEPTION(Napi::String::New(env, "Database is closed"), SQLITE_MISUSE, exception);
+ Napi::Function cb = baton->callback.Value();
+ if (!cb.IsUndefined() && cb.IsFunction()) {
+ Napi::Value argv[] = { exception };
+ TRY_CATCH_CALL(Value(), cb, 1, argv);
}
else {
- Local<Value> argv[] = { Nan::New("error").ToLocalChecked(), exception };
- EMIT_EVENT(handle(), 2, argv);
+ Napi::Value argv[] = { Napi::String::New(env, "error"), exception };
+ EMIT_EVENT(Value(), 2, argv);
}
return;
}
@@ -107,47 +106,51 @@ void Database::Schedule(Work_Callback callback, Baton* baton, bool exclusive) {
}
}
-NAN_METHOD(Database::New) {
- if (!info.IsConstructCall()) {
- return Nan::ThrowTypeError("Use the new operator to create new Database objects");
+Database::Database(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Database>(info) {
+ init();
+ Napi::Env env = info.Env();
+
+ if (info.Length() <= 0 || !info[0].IsString()) {
+ Napi::TypeError::New(env, "String expected").ThrowAsJavaScriptException();
+ return;
}
+ std::string filename = info[0].As<Napi::String>();
- REQUIRE_ARGUMENT_STRING(0, filename);
- int pos = 1;
+ unsigned int pos = 1;
int mode;
- if (info.Length() >= pos && info[pos]->IsInt32()) {
- mode = Nan::To<int>(info[pos++]).FromJust();
- } else {
+ if (info.Length() >= pos && info[pos].IsNumber() && OtherIsInt(info[pos].As<Napi::Number>())) {
+ mode = info[pos++].As<Napi::Number>().Int32Value();
+ }
+ else {
mode = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX;
}
- Local<Function> callback;
- if (info.Length() >= pos && info[pos]->IsFunction()) {
- callback = Local<Function>::Cast(info[pos++]);
+ Napi::Function callback;
+ if (info.Length() >= pos && info[pos].IsFunction()) {
+ callback = info[pos++].As<Napi::Function>();
}
- Database* db = new Database();
- db->Wrap(info.This());
-
- Nan::ForceSet(info.This(), Nan::New("filename").ToLocalChecked(), info[0].As<String>(), ReadOnly);
- Nan::ForceSet(info.This(), Nan::New("mode").ToLocalChecked(), Nan::New(mode), ReadOnly);
+ info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("filename", info[0].As<Napi::String>(), napi_default));
+ info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("mode", Napi::Number::New(env, mode), napi_default));
// Start opening the database.
- OpenBaton* baton = new OpenBaton(db, callback, *filename, mode);
+ OpenBaton* baton = new OpenBaton(this, callback, filename.c_str(), mode);
Work_BeginOpen(baton);
-
- info.GetReturnValue().Set(info.This());
}
void Database::Work_BeginOpen(Baton* baton) {
- int status = uv_queue_work(uv_default_loop(),
- &baton->request, Work_Open, (uv_after_work_cb)Work_AfterOpen);
+ Napi::Env env = baton->db->Env();
+ int status = napi_create_async_work(
+ env, NULL, Napi::String::New(env, "sqlite3.Database.Open"),
+ Work_Open, Work_AfterOpen, baton, &baton->request
+ );
assert(status == 0);
+ napi_queue_async_work(env, baton->request);
}
-void Database::Work_Open(uv_work_t* req) {
- OpenBaton* baton = static_cast<OpenBaton*>(req->data);
+void Database::Work_Open(napi_env e, void* data) {
+ OpenBaton* baton = static_cast<OpenBaton*>(data);
Database* db = baton->db;
baton->status = sqlite3_open_v2(
@@ -168,54 +171,59 @@ void Database::Work_Open(uv_work_t* req) {
}
}
-void Database::Work_AfterOpen(uv_work_t* req) {
- Nan::HandleScope scope;
+void Database::Work_AfterOpen(napi_env e, napi_status status, void* data) {
+ OpenBaton* baton = static_cast<OpenBaton*>(data);
- OpenBaton* baton = static_cast<OpenBaton*>(req->data);
Database* db = baton->db;
- Local<Value> argv[1];
+ Napi::Env env = db->Env();
+ Napi::HandleScope scope(env);
+
+ Napi::Value argv[1];
if (baton->status != SQLITE_OK) {
- EXCEPTION(baton->message, baton->status, exception);
+ EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception);
argv[0] = exception;
}
else {
db->open = true;
- argv[0] = Nan::Null();
+ argv[0] = env.Null();
}
- Local<Function> cb = Nan::New(baton->callback);
+ Napi::Function cb = baton->callback.Value();
- if (!cb.IsEmpty() && cb->IsFunction()) {
- TRY_CATCH_CALL(db->handle(), cb, 1, argv);
+ if (!cb.IsUndefined() && cb.IsFunction()) {
+ TRY_CATCH_CALL(db->Value(), cb, 1, argv);
}
else if (!db->open) {
- Local<Value> info[] = { Nan::New("error").ToLocalChecked(), argv[0] };
- EMIT_EVENT(db->handle(), 2, info);
+ Napi::Value info[] = { Napi::String::New(env, "error"), argv[0] };
+ EMIT_EVENT(db->Value(), 2, info);
}
if (db->open) {
- Local<Value> info[] = { Nan::New("open").ToLocalChecked() };
- EMIT_EVENT(db->handle(), 1, info);
+ Napi::Value info[] = { Napi::String::New(env, "open") };
+ EMIT_EVENT(db->Value(), 1, info);
db->Process();
}
+ napi_delete_async_work(e, baton->request);
delete baton;
}
-NAN_GETTER(Database::OpenGetter) {
- Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
- info.GetReturnValue().Set(db->open);
+Napi::Value Database::OpenGetter(const Napi::CallbackInfo& info) {
+ Napi::Env env = this->Env();
+ Database* db = this;
+ return Napi::Boolean::New(env, db->open);
}
-NAN_METHOD(Database::Close) {
- Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
+Napi::Value Database::Close(const Napi::CallbackInfo& info) {
+ Napi::Env env = info.Env();
+ Database* db = this;
OPTIONAL_ARGUMENT_FUNCTION(0, callback);
Baton* baton = new Baton(db, callback);
db->Schedule(Work_BeginClose, baton, true);
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
void Database::Work_BeginClose(Baton* baton) {
@@ -227,13 +235,18 @@ void Database::Work_BeginClose(Baton* baton) {
baton->db->RemoveCallbacks();
baton->db->closing = true;
- int status = uv_queue_work(uv_default_loop(),
- &baton->request, Work_Close, (uv_after_work_cb)Work_AfterClose);
+ Napi::Env env = baton->db->Env();
+
+ int status = napi_create_async_work(
+ env, NULL, Napi::String::New(env, "sqlite3.Database.Close"),
+ Work_Close, Work_AfterClose, baton, &baton->request
+ );
assert(status == 0);
+ napi_queue_async_work(env, baton->request);
}
-void Database::Work_Close(uv_work_t* req) {
- Baton* baton = static_cast<Baton*>(req->data);
+void Database::Work_Close(napi_env e, void* data) {
+ Baton* baton = static_cast<Baton*>(data);
Database* db = baton->db;
baton->status = sqlite3_close(db->_handle);
@@ -246,132 +259,143 @@ void Database::Work_Close(uv_work_t* req) {
}
}
-void Database::Work_AfterClose(uv_work_t* req) {
- Nan::HandleScope scope;
+void Database::Work_AfterClose(napi_env e, napi_status status, void* data) {
+ Baton* baton = static_cast<Baton*>(data);
- Baton* baton = static_cast<Baton*>(req->data);
Database* db = baton->db;
+ Napi::Env env = db->Env();
+ Napi::HandleScope scope(env);
+
db->closing = false;
- Local<Value> argv[1];
+ Napi::Value argv[1];
if (baton->status != SQLITE_OK) {
- EXCEPTION(baton->message, baton->status, exception);
+ EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception);
argv[0] = exception;
}
else {
db->open = false;
// Leave db->locked to indicate that this db object has reached
// the end of its life.
- argv[0] = Nan::Null();
+ argv[0] = env.Null();
}
- Local<Function> cb = Nan::New(baton->callback);
+ Napi::Function cb = baton->callback.Value();
// Fire callbacks.
- if (!cb.IsEmpty() && cb->IsFunction()) {
- TRY_CATCH_CALL(db->handle(), cb, 1, argv);
+ if (!cb.IsUndefined() && cb.IsFunction()) {
+ TRY_CATCH_CALL(db->Value(), cb, 1, argv);
}
else if (db->open) {
- Local<Value> info[] = { Nan::New("error").ToLocalChecked(), argv[0] };
- EMIT_EVENT(db->handle(), 2, info);
+ Napi::Value info[] = { Napi::String::New(env, "error"), argv[0] };
+ EMIT_EVENT(db->Value(), 2, info);
}
if (!db->open) {
- Local<Value> info[] = { Nan::New("close").ToLocalChecked(), argv[0] };
- EMIT_EVENT(db->handle(), 1, info);
+ Napi::Value info[] = { Napi::String::New(env, "close"), argv[0] };
+ EMIT_EVENT(db->Value(), 1, info);
db->Process();
}
+ napi_delete_async_work(e, baton->request);
delete baton;
}
-NAN_METHOD(Database::Serialize) {
- Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
+Napi::Value Database::Serialize(const Napi::CallbackInfo& info) {
+ Napi::Env env = this->Env();
+ Database* db = this;
OPTIONAL_ARGUMENT_FUNCTION(0, callback);
bool before = db->serialize;
db->serialize = true;
- if (!callback.IsEmpty() && callback->IsFunction()) {
+ if (!callback.IsEmpty() && callback.IsFunction()) {
TRY_CATCH_CALL(info.This(), callback, 0, NULL);
db->serialize = before;
}
db->Process();
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
-NAN_METHOD(Database::Parallelize) {
- Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
+Napi::Value Database::Parallelize(const Napi::CallbackInfo& info) {
+ Napi::Env env = this->Env();
+ Database* db = this;
OPTIONAL_ARGUMENT_FUNCTION(0, callback);
bool before = db->serialize;
db->serialize = false;
- if (!callback.IsEmpty() && callback->IsFunction()) {
+ if (!callback.IsEmpty() && callback.IsFunction()) {
TRY_CATCH_CALL(info.This(), callback, 0, NULL);
db->serialize = before;
}
db->Process();
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
-NAN_METHOD(Database::Configure) {
- Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
+Napi::Value Database::Configure(const Napi::CallbackInfo& info) {
+ Napi::Env env = this->Env();
+ Database* db = this;
REQUIRE_ARGUMENTS(2);
- if (Nan::Equals(info[0], Nan::New("trace").ToLocalChecked()).FromJust()) {
- Local<Function> handle;
+ if (info[0].StrictEquals( Napi::String::New(env, "trace"))) {
+ Napi::Function handle;
Baton* baton = new Baton(db, handle);
db->Schedule(RegisterTraceCallback, baton);
}
- else if (Nan::Equals(info[0], Nan::New("profile").ToLocalChecked()).FromJust()) {
- Local<Function> handle;
+ else if (info[0].StrictEquals( Napi::String::New(env, "profile"))) {
+ Napi::Function handle;
Baton* baton = new Baton(db, handle);
db->Schedule(RegisterProfileCallback, baton);
}
- else if (Nan::Equals(info[0], Nan::New("busyTimeout").ToLocalChecked()).FromJust()) {
- if (!info[1]->IsInt32()) {
- return Nan::ThrowTypeError("Value must be an integer");
+ else if (info[0].StrictEquals( Napi::String::New(env, "busyTimeout"))) {
+ if (!info[1].IsNumber()) {
+ Napi::TypeError::New(env, "Value must be an integer").ThrowAsJavaScriptException();
+ return env.Null();
}
- Local<Function> handle;
+ Napi::Function handle;
Baton* baton = new Baton(db, handle);
- baton->status = Nan::To<int>(info[1]).FromJust();
+ baton->status = info[1].As<Napi::Number>().Int32Value();
db->Schedule(SetBusyTimeout, baton);
}
else {
- return Nan::ThrowError(Exception::Error(String::Concat(
+ Napi::TypeError::New(env, (StringConcat(
#if V8_MAJOR_VERSION > 6
info.GetIsolate(),
#endif
- Nan::To<String>(info[0]).ToLocalChecked(),
- Nan::New(" is not a valid configuration option").ToLocalChecked()
- )));
+ info[0].As<Napi::String>(),
+ Napi::String::New(env, " is not a valid configuration option")
+ )).Utf8Value().c_str()).ThrowAsJavaScriptException();
+ return env.Null();
}
db->Process();
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
-NAN_METHOD(Database::Interrupt) {
- Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
+Napi::Value Database::Interrupt(const Napi::CallbackInfo& info) {
+ Napi::Env env = this->Env();
+ Database* db = this;
if (!db->open) {
- return Nan::ThrowError("Database is not open");
+ Napi::Error::New(env, "Database is not open").ThrowAsJavaScriptException();
+ return env.Null();
}
if (db->closing) {
- return Nan::ThrowError("Database is closing");
+ Napi::Error::New(env, "Database is closing").ThrowAsJavaScriptException();
+ return env.Null();
}
sqlite3_interrupt(db->_handle);
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
void Database::SetBusyTimeout(Baton* baton) {
@@ -412,13 +436,14 @@ void Database::TraceCallback(void* db, const char* sql) {
void Database::TraceCallback(Database* db, std::string* sql) {
// Note: This function is called in the main V8 thread.
- Nan::HandleScope scope;
+ Napi::Env env = db->Env();
+ Napi::HandleScope scope(env);
- Local<Value> argv[] = {
- Nan::New("trace").ToLocalChecked(),
- Nan::New(sql->c_str()).ToLocalChecked()
+ Napi::Value argv[] = {
+ Napi::String::New(env, "trace"),
+ Napi::String::New(env, sql->c_str())
};
- EMIT_EVENT(db->handle(), 2, argv);
+ EMIT_EVENT(db->Value(), 2, argv);
delete sql;
}
@@ -452,14 +477,15 @@ void Database::ProfileCallback(void* db, const char* sql, sqlite3_uint64 nsecs)
}
void Database::ProfileCallback(Database *db, ProfileInfo* info) {
- Nan::HandleScope scope;
+ Napi::Env env = db->Env();
+ Napi::HandleScope scope(env);
- Local<Value> argv[] = {
- Nan::New("profile").ToLocalChecked(),
- Nan::New(info->sql.c_str()).ToLocalChecked(),
- Nan::New<Number>((double)info->nsecs / 1000000.0)
+ Napi::Value argv[] = {
+ Napi::String::New(env, "profile"),
+ Napi::String::New(env, info->sql.c_str()),
+ Napi::Number::New(env, (double)info->nsecs / 1000000.0)
};
- EMIT_EVENT(db->handle(), 3, argv);
+ EMIT_EVENT(db->Value(), 3, argv);
delete info;
}
@@ -496,28 +522,30 @@ void Database::UpdateCallback(void* db, int type, const char* database,
}
void Database::UpdateCallback(Database *db, UpdateInfo* info) {
- Nan::HandleScope scope;
-
- Local<Value> argv[] = {
- Nan::New(sqlite_authorizer_string(info->type)).ToLocalChecked(),
- Nan::New(info->database.c_str()).ToLocalChecked(),
- Nan::New(info->table.c_str()).ToLocalChecked(),
- Nan::New<Number>(info->rowid),
+ Napi::Env env = db->Env();
+ Napi::HandleScope scope(env);
+
+ Napi::Value argv[] = {
+ Napi::String::New(env, sqlite_authorizer_string(info->type)),
+ Napi::String::New(env, info->database.c_str()),
+ Napi::String::New(env, info->table.c_str()),
+ Napi::Number::New(env, info->rowid),
};
- EMIT_EVENT(db->handle(), 4, argv);
+ EMIT_EVENT(db->Value(), 4, argv);
delete info;
}
-NAN_METHOD(Database::Exec) {
- Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
+Napi::Value Database::Exec(const Napi::CallbackInfo& info) {
+ Napi::Env env = this->Env();
+ Database* db = this;
REQUIRE_ARGUMENT_STRING(0, sql);
OPTIONAL_ARGUMENT_FUNCTION(1, callback);
- Baton* baton = new ExecBaton(db, callback, *sql);
+ Baton* baton = new ExecBaton(db, callback, sql.c_str());
db->Schedule(Work_BeginExec, baton, true);
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
void Database::Work_BeginExec(Baton* baton) {
@@ -525,13 +553,17 @@ void Database::Work_BeginExec(Baton* baton) {
assert(baton->db->open);
assert(baton->db->_handle);
assert(baton->db->pending == 0);
- int status = uv_queue_work(uv_default_loop(),
- &baton->request, Work_Exec, (uv_after_work_cb)Work_AfterExec);
+ Napi::Env env = baton->db->Env();
+ int status = napi_create_async_work(
+ env, NULL, Napi::String::New(env, "sqlite3.Database.Exec"),
+ Work_Exec, Work_AfterExec, baton, &baton->request
+ );
assert(status == 0);
+ napi_queue_async_work(env, baton->request);
}
-void Database::Work_Exec(uv_work_t* req) {
- ExecBaton* baton = static_cast<ExecBaton*>(req->data);
+void Database::Work_Exec(napi_env e, void* data) {
+ ExecBaton* baton = static_cast<ExecBaton*>(data);
char* message = NULL;
baton->status = sqlite3_exec(
@@ -548,59 +580,64 @@ void Database::Work_Exec(uv_work_t* req) {
}
}
-void Database::Work_AfterExec(uv_work_t* req) {
- Nan::HandleScope scope;
+void Database::Work_AfterExec(napi_env e, napi_status status, void* data) {
+ ExecBaton* baton = static_cast<ExecBaton*>(data);
- ExecBaton* baton = static_cast<ExecBaton*>(req->data);
Database* db = baton->db;
- Local<Function> cb = Nan::New(baton->callback);
+ Napi::Env env = db->Env();
+ Napi::HandleScope scope(env);
+
+ Napi::Function cb = baton->callback.Value();
if (baton->status != SQLITE_OK) {
- EXCEPTION(baton->message, baton->status, exception);
+ EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[] = { exception };
- TRY_CATCH_CALL(db->handle(), cb, 1, argv);
+ if (!cb.IsUndefined() && cb.IsFunction()) {
+ Napi::Value argv[] = { exception };
+ TRY_CATCH_CALL(db->Value(), cb, 1, argv);
}
else {
- Local<Value> info[] = { Nan::New("error").ToLocalChecked(), exception };
- EMIT_EVENT(db->handle(), 2, info);
+ Napi::Value info[] = { Napi::String::New(env, "error"), exception };
+ EMIT_EVENT(db->Value(), 2, info);
}
}
- else if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[] = { Nan::Null() };
- TRY_CATCH_CALL(db->handle(), cb, 1, argv);
+ else if (!cb.IsUndefined() && cb.IsFunction()) {
+ Napi::Value argv[] = { env.Null() };
+ TRY_CATCH_CALL(db->Value(), cb, 1, argv);
}
db->Process();
+ napi_delete_async_work(e, baton->request);
delete baton;
}
-NAN_METHOD(Database::Wait) {
- Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
+Napi::Value Database::Wait(const Napi::CallbackInfo& info) {
+ Napi::Env env = info.Env();
+ Database* db = this;
OPTIONAL_ARGUMENT_FUNCTION(0, callback);
Baton* baton = new Baton(db, callback);
db->Schedule(Work_Wait, baton, true);
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
void Database::Work_Wait(Baton* baton) {
- Nan::HandleScope scope;
+ Napi::Env env = baton->db->Env();
+ Napi::HandleScope scope(env);
assert(baton->db->locked);
assert(baton->db->open);
assert(baton->db->_handle);
assert(baton->db->pending == 0);
- Local<Function> cb = Nan::New(baton->callback);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[] = { Nan::Null() };
- TRY_CATCH_CALL(baton->db->handle(), cb, 1, argv);
+ Napi::Function cb = baton->callback.Value();
+ if (!cb.IsUndefined() && cb.IsFunction()) {
+ Napi::Value argv[] = { env.Null() };
+ TRY_CATCH_CALL(baton->db->Value(), cb, 1, argv);
}
baton->db->Process();
@@ -608,16 +645,17 @@ void Database::Work_Wait(Baton* baton) {
delete baton;
}
-NAN_METHOD(Database::LoadExtension) {
- Database* db = Nan::ObjectWrap::Unwrap<Database>(info.This());
+Napi::Value Database::LoadExtension(const Napi::CallbackInfo& info) {
+ Napi::Env env = this->Env();
+ Database* db = this;
REQUIRE_ARGUMENT_STRING(0, filename);
OPTIONAL_ARGUMENT_FUNCTION(1, callback);
- Baton* baton = new LoadExtensionBaton(db, callback, *filename);
+ Baton* baton = new LoadExtensionBaton(db, callback, filename.c_str());
db->Schedule(Work_BeginLoadExtension, baton, true);
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
void Database::Work_BeginLoadExtension(Baton* baton) {
@@ -625,13 +663,17 @@ void Database::Work_BeginLoadExtension(Baton* baton) {
assert(baton->db->open);
assert(baton->db->_handle);
assert(baton->db->pending == 0);
- int status = uv_queue_work(uv_default_loop(),
- &baton->request, Work_LoadExtension, reinterpret_cast<uv_after_work_cb>(Work_AfterLoadExtension));
+ Napi::Env env = baton->db->Env();
+ int status = napi_create_async_work(
+ env, NULL, Napi::String::New(env, "sqlite3.Database.LoadExtension"),
+ Work_LoadExtension, Work_AfterLoadExtension, baton, &baton->request
+ );
assert(status == 0);
+ napi_queue_async_work(env, baton->request);
}
-void Database::Work_LoadExtension(uv_work_t* req) {
- LoadExtensionBaton* baton = static_cast<LoadExtensionBaton*>(req->data);
+void Database::Work_LoadExtension(napi_env e, void* data) {
+ LoadExtensionBaton* baton = static_cast<LoadExtensionBaton*>(data);
sqlite3_enable_load_extension(baton->db->_handle, 1);
@@ -651,32 +693,36 @@ void Database::Work_LoadExtension(uv_work_t* req) {
}
}
-void Database::Work_AfterLoadExtension(uv_work_t* req) {
- Nan::HandleScope scope;
+void Database::Work_AfterLoadExtension(napi_env e, napi_status status, void* data) {
+ LoadExtensionBaton* baton = static_cast<LoadExtensionBaton*>(data);
- LoadExtensionBaton* baton = static_cast<LoadExtensionBaton*>(req->data);
Database* db = baton->db;
- Local<Function> cb = Nan::New(baton->callback);
+
+ Napi::Env env = db->Env();
+ Napi::HandleScope scope(env);
+
+ Napi::Function cb = baton->callback.Value();
if (baton->status != SQLITE_OK) {
- EXCEPTION(baton->message, baton->status, exception);
+ EXCEPTION(Napi::String::New(env, baton->message.c_str()), baton->status, exception);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[] = { exception };
- TRY_CATCH_CALL(db->handle(), cb, 1, argv);
+ if (!cb.IsUndefined() && cb.IsFunction()) {
+ Napi::Value argv[] = { exception };
+ TRY_CATCH_CALL(db->Value(), cb, 1, argv);
}
else {
- Local<Value> info[] = { Nan::New("error").ToLocalChecked(), exception };
- EMIT_EVENT(db->handle(), 2, info);
+ Napi::Value info[] = { Napi::String::New(env, "error"), exception };
+ EMIT_EVENT(db->Value(), 2, info);
}
}
- else if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[] = { Nan::Null() };
- TRY_CATCH_CALL(db->handle(), cb, 1, argv);
+ else if (!cb.IsUndefined() && cb.IsFunction()) {
+ Napi::Value argv[] = { env.Null() };
+ TRY_CATCH_CALL(db->Value(), cb, 1, argv);
}
db->Process();
+ napi_delete_async_work(e, baton->request);
delete baton;
}
diff --git a/src/database.h b/src/database.h
index 1ec1015..b31f681 100644
--- a/src/database.h
+++ b/src/database.h
@@ -3,45 +3,48 @@
#define NODE_SQLITE3_SRC_DATABASE_H
+#include <assert.h>
#include <string>
#include <queue>
#include <sqlite3.h>
-#include <nan.h>
+#include <napi.h>
#include "async.h"
-using namespace v8;
+using namespace Napi;
namespace node_sqlite3 {
class Database;
-class Database : public Nan::ObjectWrap {
+class Database : public Napi::ObjectWrap<Database> {
public:
- static Nan::Persistent<FunctionTemplate> constructor_template;
- static NAN_MODULE_INIT(Init);
-
- static inline bool HasInstance(Local<Value> val) {
- Nan::HandleScope scope;
- if (!val->IsObject()) return false;
- Local<Object> obj = val.As<Object>();
- return Nan::New(constructor_template)->HasInstance(obj);
+ static Napi::FunctionReference constructor;
+ static Napi::Object Init(Napi::Env env, Napi::Object exports);
+
+ static inline bool HasInstance(Napi::Value val) {
+ Napi::Env env = val.Env();
+ Napi::HandleScope scope(env);
+ if (!val.IsObject()) return false;
+ Napi::Object obj = val.As<Napi::Object>();
+ return obj.InstanceOf(constructor.Value());
}
struct Baton {
- uv_work_t request;
+ napi_async_work request;
Database* db;
- Nan::Persistent<Function> callback;
+ Napi::FunctionReference callback;
int status;
std::string message;
- Baton(Database* db_, Local<Function> cb_) :
+ Baton(Database* db_, Napi::Function cb_) :
db(db_), status(SQLITE_OK) {
db->Ref();
- request.data = this;
- callback.Reset(cb_);
+ if (!cb_.IsUndefined() && cb_.IsFunction()) {
+ callback.Reset(cb_, 1);
+ }
}
virtual ~Baton() {
db->Unref();
@@ -52,19 +55,19 @@ public:
struct OpenBaton : Baton {
std::string filename;
int mode;
- OpenBaton(Database* db_, Local<Function> cb_, const char* filename_, int mode_) :
+ OpenBaton(Database* db_, Napi::Function cb_, const char* filename_, int mode_) :
Baton(db_, cb_), filename(filename_), mode(mode_) {}
};
struct ExecBaton : Baton {
std::string sql;
- ExecBaton(Database* db_, Local<Function> cb_, const char* sql_) :
+ ExecBaton(Database* db_, Napi::Function cb_, const char* sql_) :
Baton(db_, cb_), sql(sql_) {}
};
struct LoadExtensionBaton : Baton {
std::string filename;
- LoadExtensionBaton(Database* db_, Local<Function> cb_, const char* filename_) :
+ LoadExtensionBaton(Database* db_, Napi::Function cb_, const char* filename_) :
Baton(db_, cb_), filename(filename_) {}
};
@@ -100,19 +103,20 @@ public:
friend class Statement;
friend class Backup;
-protected:
- Database() : Nan::ObjectWrap(),
- _handle(NULL),
- open(false),
- closing(false),
- locked(false),
- pending(0),
- serialize(false),
- debug_trace(NULL),
- debug_profile(NULL),
- update_event(NULL) {
+ void init() {
+ _handle = NULL;
+ open = false;
+ closing = false;
+ locked = false;
+ pending = 0;
+ serialize = false;
+ debug_trace = NULL;
+ debug_profile = NULL;
+ update_event = NULL;
}
+ Database(const Napi::CallbackInfo& info);
+
~Database() {
RemoveCallbacks();
sqlite3_close(_handle);
@@ -120,40 +124,40 @@ protected:
open = false;
}
- static NAN_METHOD(New);
+protected:
static void Work_BeginOpen(Baton* baton);
- static void Work_Open(uv_work_t* req);
- static void Work_AfterOpen(uv_work_t* req);
+ static void Work_Open(napi_env env, void* data);
+ static void Work_AfterOpen(napi_env env, napi_status status, void* data);
- static NAN_GETTER(OpenGetter);
+ Napi::Value OpenGetter(const Napi::CallbackInfo& info);
void Schedule(Work_Callback callback, Baton* baton, bool exclusive = false);
void Process();
- static NAN_METHOD(Exec);
+ Napi::Value Exec(const Napi::CallbackInfo& info);
static void Work_BeginExec(Baton* baton);
- static void Work_Exec(uv_work_t* req);
- static void Work_AfterExec(uv_work_t* req);
+ static void Work_Exec(napi_env env, void* data);
+ static void Work_AfterExec(napi_env env, napi_status status, void* data);
- static NAN_METHOD(Wait);
+ Napi::Value Wait(const Napi::CallbackInfo& info);
static void Work_Wait(Baton* baton);
- static NAN_METHOD(Close);
+ Napi::Value Close(const Napi::CallbackInfo& info);
static void Work_BeginClose(Baton* baton);
- static void Work_Close(uv_work_t* req);
- static void Work_AfterClose(uv_work_t* req);
+ static void Work_Close(napi_env env, void* data);
+ static void Work_AfterClose(napi_env env, napi_status status, void* data);
- static NAN_METHOD(LoadExtension);
+ Napi::Value LoadExtension(const Napi::CallbackInfo& info);
static void Work_BeginLoadExtension(Baton* baton);
- static void Work_LoadExtension(uv_work_t* req);
- static void Work_AfterLoadExtension(uv_work_t* req);
+ static void Work_LoadExtension(napi_env env, void* data);
+ static void Work_AfterLoadExtension(napi_env env, napi_status status, void* data);
- static NAN_METHOD(Serialize);
- static NAN_METHOD(Parallelize);
+ Napi::Value Serialize(const Napi::CallbackInfo& info);
+ Napi::Value Parallelize(const Napi::CallbackInfo& info);
- static NAN_METHOD(Configure);
+ Napi::Value Configure(const Napi::CallbackInfo& info);
- static NAN_METHOD(Interrupt);
+ Napi::Value Interrupt(const Napi::CallbackInfo& info);
static void SetBusyTimeout(Baton* baton);
diff --git a/src/macros.h b/src/macros.h
index 9c0136c..ce94484 100644
--- a/src/macros.h
+++ b/src/macros.h
@@ -3,47 +3,71 @@
const char* sqlite_code_string(int code);
const char* sqlite_authorizer_string(int type);
-
+#include <vector>
+
+// TODO: better way to work around StringConcat?
+#include <napi.h>
+inline Napi::String StringConcat(Napi::Value str1, Napi::Value str2) {
+ return Napi::String::New(str1.Env(), str1.As<Napi::String>().Utf8Value() +
+ str2.As<Napi::String>().Utf8Value() );
+}
+
+// A Napi substitute IsInt32()
+inline bool OtherIsInt(Napi::Number source) {
+ double orig_val = source.DoubleValue();
+ double int_val = (double)source.Int32Value();
+ if (orig_val == int_val) {
+ return true;
+ } else {
+ return false;
+ }
+}
#define REQUIRE_ARGUMENTS(n) \
if (info.Length() < (n)) { \
- return Nan::ThrowTypeError("Expected " #n "arguments"); \
+ Napi::TypeError::New(env, "Expected " #n "arguments").ThrowAsJavaScriptException(); \
+ return env.Null(); \
}
#define REQUIRE_ARGUMENT_EXTERNAL(i, var) \
- if (info.Length() <= (i) || !info[i]->IsExternal()) { \
- return Nan::ThrowTypeError("Argument " #i " invalid"); \
+ if (info.Length() <= (i) || !info[i].IsExternal()) { \
+ Napi::TypeError::New(env, "Argument " #i " invalid").ThrowAsJavaScriptException(); \
+ return env.Null(); \
} \
- Local<External> var = Local<External>::Cast(info[i]);
+ Napi::External var = info[i].As<Napi::External>();
#define REQUIRE_ARGUMENT_FUNCTION(i, var) \
- if (info.Length() <= (i) || !info[i]->IsFunction()) { \
- return Nan::ThrowTypeError("Argument " #i " must be a function"); \
+ if (info.Length() <= (i) || !info[i].IsFunction()) { \
+ Napi::TypeError::New(env, "Argument " #i " must be a function").ThrowAsJavaScriptException(); \
+ return env.Null(); \
} \
- Local<Function> var = Local<Function>::Cast(info[i]);
+ Napi::Function var = info[i].As<Napi::Function>();
#define REQUIRE_ARGUMENT_STRING(i, var) \
- if (info.Length() <= (i) || !info[i]->IsString()) { \
- return Nan::ThrowTypeError("Argument " #i " must be a string"); \
+ if (info.Length() <= (i) || !info[i].IsString()) { \
+ Napi::TypeError::New(env, "Argument " #i " must be a string").ThrowAsJavaScriptException(); \
+ return env.Null(); \
} \
- Nan::Utf8String var(info[i]);
+ std::string var = info[i].As<Napi::String>();
#define REQUIRE_ARGUMENT_INTEGER(i, var) \
- if (info.Length() <= (i) || !info[i]->IsInt32()) { \
- return Nan::ThrowTypeError("Argument " #i " must be an integer"); \
+ if (info.Length() <= (i) || !info[i].IsNumber()) { \
+ Napi::TypeError::New(env, "Argument " #i " must be an integer").ThrowAsJavaScriptException(); \
+ return env.Null(); \
} \
- int var(Nan::To<int32_t>(info[i]).FromJust());
+ int var(info[i].As<Napi::Number>().Int32Value());
#define OPTIONAL_ARGUMENT_FUNCTION(i, var) \
- Local<Function> var; \
- if (info.Length() > i && !info[i]->IsUndefined()) { \
- if (!info[i]->IsFunction()) { \
- return Nan::ThrowTypeError("Argument " #i " must be a function"); \
+ Napi::Function var; \
+ if (info.Length() > i && !info[i].IsUndefined()) { \
+ if (!info[i].IsFunction()) { \
+ Napi::TypeError::New(env, "Argument " #i " must be a function").ThrowAsJavaScriptException(); \
+ return env.Null(); \
} \
- var = Local<Function>::Cast(info[i]); \
+ var = info[i].As<Napi::Function>(); \
}
@@ -52,70 +76,62 @@ const char* sqlite_authorizer_string(int type);
if (info.Length() <= (i)) { \
var = (default); \
} \
- else if (info[i]->IsInt32()) { \
- var = Nan::To<int32_t>(info[i]).FromJust(); \
+ else if (info[i].IsNumber()) { \
+ if (OtherIsInt(info[i].As<Number>())) { \
+ var = info[i].As<Napi::Number>().Int32Value(); \
+ } \
} \
else { \
- return Nan::ThrowTypeError("Argument " #i " must be an integer"); \
+ Napi::TypeError::New(env, "Argument " #i " must be an integer").ThrowAsJavaScriptException(); \
+ return env.Null(); \
}
#define DEFINE_CONSTANT_INTEGER(target, constant, name) \
- Nan::ForceSet(target, \
- Nan::New(#name).ToLocalChecked(), \
- Nan::New<Integer>(constant), \
- static_cast<PropertyAttribute>(ReadOnly | DontDelete) \
- );
+ Napi::PropertyDescriptor::Value(#name, Napi::Number::New(env, constant), \
+ static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)),
#define DEFINE_CONSTANT_STRING(target, constant, name) \
- Nan::ForceSet(target, \
- Nan::New(#name).ToLocalChecked(), \
- Nan::New(constant).ToLocalChecked(), \
- static_cast<PropertyAttribute>(ReadOnly | DontDelete) \
- );
-
-
-#define NODE_SET_GETTER(target, name, function) \
- Nan::SetAccessor((target)->InstanceTemplate(), \
- Nan::New(name).ToLocalChecked(), (function));
-
-#define NODE_SET_SETTER(target, name, getter, setter) \
- Nan::SetAccessor((target)->InstanceTemplate(), \
- Nan::New(name).ToLocalChecked(), getter, setter);
-
-#define GET_STRING(source, name, property) \
- Nan::Utf8String name(Nan::Get(source, \
- Nan::New(prop).ToLocalChecked()).ToLocalChecked());
-
-#define GET_INTEGER(source, name, prop) \
- int name = Nan::To<int>(Nan::Get(source, \
- Nan::New(property).ToLocalChecked()).ToLocalChecked()).FromJust();
+ Napi::PropertyDescriptor::Value(#name, Napi::String::New(env, constant), \
+ static_cast<napi_property_attributes>(napi_enumerable | napi_configurable)),
#define EXCEPTION(msg, errno, name) \
- Local<Value> name = Exception::Error(Nan::New( \
- std::string(sqlite_code_string(errno)) + \
- std::string(": ") + std::string(msg) \
- ).ToLocalChecked()); \
- Local<Object> name ##_obj = name.As<Object>(); \
- Nan::Set(name ##_obj, Nan::New("errno").ToLocalChecked(), Nan::New(errno));\
- Nan::Set(name ##_obj, Nan::New("code").ToLocalChecked(), \
- Nan::New(sqlite_code_string(errno)).ToLocalChecked());
+ Napi::Value name = Napi::Error::New(env, \
+ StringConcat( \
+ StringConcat( \
+ Napi::String::New(env, sqlite_code_string(errno)), \
+ Napi::String::New(env, ": ") \
+ ), \
+ (msg) \
+ ).Utf8Value() \
+ ).Value(); \
+ Napi::Object name ##_obj = name.As<Napi::Object>(); \
+ (name ##_obj).Set( Napi::String::New(env, "errno"), Napi::Number::New(env, errno)); \
+ (name ##_obj).Set( Napi::String::New(env, "code"), \
+ Napi::String::New(env, sqlite_code_string(errno)));
+
#define EMIT_EVENT(obj, argc, argv) \
TRY_CATCH_CALL((obj), \
- Nan::Get(obj, \
- Nan::New("emit").ToLocalChecked()).ToLocalChecked().As<Function>(),\
+ (obj).Get("emit").As<Napi::Function>(),\
argc, argv \
);
+// The Mac OS compiler complains when argv is NULL unless we
+// first assign it to a locally defined variable.
#define TRY_CATCH_CALL(context, callback, argc, argv) \
- Nan::MakeCallback((context), (callback), (argc), (argv))
+ Napi::Value* passed_argv = argv;\
+ std::vector<napi_value> args;\
+ if ((argc != 0) && (passed_argv != NULL)) {\
+ args.assign(passed_argv, passed_argv + argc);\
+ }\
+ (callback).MakeCallback(Napi::Value(context), args);
#define WORK_DEFINITION(name) \
- static NAN_METHOD(name); \
+ Napi::Value name(const Napi::CallbackInfo& info); \
static void Work_Begin##name(Baton* baton); \
- static void Work_##name(uv_work_t* req); \
- static void Work_After##name(uv_work_t* req);
+ static void Work_##name(napi_env env, void* data); \
+ static void Work_After##name(napi_env env, napi_status status, void* data);
#define STATEMENT_BEGIN(type) \
assert(baton); \
@@ -125,13 +141,16 @@ const char* sqlite_authorizer_string(int type);
assert(baton->stmt->prepared); \
baton->stmt->locked = true; \
baton->stmt->db->pending++; \
- int status = uv_queue_work(uv_default_loop(), \
- &baton->request, \
- Work_##type, reinterpret_cast<uv_after_work_cb>(Work_After##type)); \
- assert(status == 0);
+ Napi::Env env = baton->stmt->Env(); \
+ int status = napi_create_async_work( \
+ env, NULL, Napi::String::New(env, "sqlite3.Statement."#type), \
+ Work_##type, Work_After##type, baton, &baton->request \
+ ); \
+ assert(status == 0); \
+ napi_queue_async_work(env, baton->request);
#define STATEMENT_INIT(type) \
- type* baton = static_cast<type*>(req->data); \
+ type* baton = static_cast<type*>(data); \
Statement* stmt = baton->stmt;
#define STATEMENT_END() \
@@ -141,6 +160,7 @@ const char* sqlite_authorizer_string(int type);
stmt->db->pending--; \
stmt->Process(); \
stmt->db->Process(); \
+ napi_delete_async_work(e, baton->request); \
delete baton;
#define BACKUP_BEGIN(type) \
@@ -151,13 +171,16 @@ const char* sqlite_authorizer_string(int type);
assert(baton->backup->inited); \
baton->backup->locked = true; \
baton->backup->db->pending++; \
- int status = uv_queue_work(uv_default_loop(), \
- &baton->request, \
- Work_##type, reinterpret_cast<uv_after_work_cb>(Work_After##type)); \
- assert(status == 0);
+ Napi::Env env = baton->backup->Env(); \
+ int status = napi_create_async_work( \
+ env, NULL, Napi::String::New(env, "sqlite3.Backup."#type), \
+ Work_##type, Work_After##type, baton, &baton->request \
+ ); \
+ assert(status == 0); \
+ napi_queue_async_work(env, baton->request);
#define BACKUP_INIT(type) \
- type* baton = static_cast<type*>(req->data); \
+ type* baton = static_cast<type*>(data); \
Backup* backup = baton->backup;
#define BACKUP_END() \
@@ -167,6 +190,7 @@ const char* sqlite_authorizer_string(int type);
backup->db->pending--; \
backup->Process(); \
backup->db->Process(); \
+ napi_delete_async_work(e, baton->request); \
delete baton;
#define DELETE_FIELD(field) \
diff --git a/src/node_sqlite3.cc b/src/node_sqlite3.cc
index 10f88ea..b101b45 100644
--- a/src/node_sqlite3.cc
+++ b/src/node_sqlite3.cc
@@ -13,53 +13,57 @@ using namespace node_sqlite3;
namespace {
-NAN_MODULE_INIT(RegisterModule) {
- Nan::HandleScope scope;
+Napi::Object RegisterModule(Napi::Env env, Napi::Object exports) {
+ Napi::HandleScope scope(env);
- Database::Init(target);
- Statement::Init(target);
- Backup::Init(target);
+ Database::Init(env, exports);
+ Statement::Init(env, exports);
+ Backup::Init(env, exports);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_READONLY, OPEN_READONLY);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_READWRITE, OPEN_READWRITE);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_CREATE, OPEN_CREATE);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_FULLMUTEX, OPEN_FULLMUTEX);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_URI, OPEN_URI);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_SHAREDCACHE, OPEN_SHAREDCACHE);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_OPEN_PRIVATECACHE, OPEN_PRIVATECACHE);
- DEFINE_CONSTANT_STRING(target, SQLITE_VERSION, VERSION);
+ exports.DefineProperties({
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_READONLY, OPEN_READONLY)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_READWRITE, OPEN_READWRITE)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_CREATE, OPEN_CREATE)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_FULLMUTEX, OPEN_FULLMUTEX)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_URI, OPEN_URI)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_SHAREDCACHE, OPEN_SHAREDCACHE)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_OPEN_PRIVATECACHE, OPEN_PRIVATECACHE)
+ DEFINE_CONSTANT_STRING(exports, SQLITE_VERSION, VERSION)
#ifdef SQLITE_SOURCE_ID
- DEFINE_CONSTANT_STRING(target, SQLITE_SOURCE_ID, SOURCE_ID);
+ DEFINE_CONSTANT_STRING(exports, SQLITE_SOURCE_ID, SOURCE_ID)
#endif
- DEFINE_CONSTANT_INTEGER(target, SQLITE_VERSION_NUMBER, VERSION_NUMBER);
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_VERSION_NUMBER, VERSION_NUMBER)
- DEFINE_CONSTANT_INTEGER(target, SQLITE_OK, OK);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_ERROR, ERROR);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_INTERNAL, INTERNAL);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_PERM, PERM);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_ABORT, ABORT);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_BUSY, BUSY);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_LOCKED, LOCKED);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_NOMEM, NOMEM);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_READONLY, READONLY);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_INTERRUPT, INTERRUPT);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_IOERR, IOERR);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_CORRUPT, CORRUPT);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_NOTFOUND, NOTFOUND);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_FULL, FULL);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_CANTOPEN, CANTOPEN);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_PROTOCOL, PROTOCOL);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_EMPTY, EMPTY);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_SCHEMA, SCHEMA);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_TOOBIG, TOOBIG);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_CONSTRAINT, CONSTRAINT);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_MISMATCH, MISMATCH);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_MISUSE, MISUSE);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_NOLFS, NOLFS);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_AUTH, AUTH);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_FORMAT, FORMAT);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_RANGE, RANGE);
- DEFINE_CONSTANT_INTEGER(target, SQLITE_NOTADB, NOTADB);
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_OK, OK)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_ERROR, ERROR)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_INTERNAL, INTERNAL)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_PERM, PERM)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_ABORT, ABORT)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_BUSY, BUSY)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_LOCKED, LOCKED)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_NOMEM, NOMEM)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_READONLY, READONLY)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_INTERRUPT, INTERRUPT)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_IOERR, IOERR)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_CORRUPT, CORRUPT)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_NOTFOUND, NOTFOUND)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_FULL, FULL)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_CANTOPEN, CANTOPEN)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_PROTOCOL, PROTOCOL)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_EMPTY, EMPTY)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_SCHEMA, SCHEMA)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_TOOBIG, TOOBIG)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_CONSTRAINT, CONSTRAINT)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_MISMATCH, MISMATCH)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_MISUSE, MISUSE)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_NOLFS, NOLFS)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_AUTH, AUTH)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_FORMAT, FORMAT)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_RANGE, RANGE)
+ DEFINE_CONSTANT_INTEGER(exports, SQLITE_NOTADB, NOTADB)
+ });
+
+ return exports;
}
}
@@ -108,4 +112,4 @@ const char* sqlite_authorizer_string(int type) {
}
}
-NODE_MODULE(node_sqlite3, RegisterModule)
+NODE_API_MODULE(node_sqlite3, RegisterModule)
diff --git a/src/statement.cc b/src/statement.cc
index e09aeaf..15d6f91 100644
--- a/src/statement.cc
+++ b/src/statement.cc
@@ -1,7 +1,6 @@
#include <string.h>
-#include <node.h>
-#include <node_buffer.h>
-#include <node_version.h>
+#include <napi.h>
+#include <uv.h>
#include "macros.h"
#include "database.h"
@@ -9,27 +8,37 @@
using namespace node_sqlite3;
-Nan::Persistent<FunctionTemplate> Statement::constructor_template;
+Napi::FunctionReference Statement::constructor;
-NAN_MODULE_INIT(Statement::Init) {
- Nan::HandleScope scope;
+Napi::Object Statement::Init(Napi::Env env, Napi::Object exports) {
+ Napi::HandleScope scope(env);
- Local<FunctionTemplate> t = Nan::New<FunctionTemplate>(New);
+ Napi::Function t = DefineClass(env, "Statement", {
+ InstanceMethod("bind", &Statement::Bind),
+ InstanceMethod("get", &Statement::Get),
+ InstanceMethod("run", &Statement::Run),
+ InstanceMethod("all", &Statement::All),
+ InstanceMethod("each", &Statement::Each),
+ InstanceMethod("reset", &Statement::Reset),
+ InstanceMethod("finalize", &Statement::Finalize_),
+ });
- t->InstanceTemplate()->SetInternalFieldCount(1);
- t->SetClassName(Nan::New("Statement").ToLocalChecked());
+ constructor = Napi::Persistent(t);
+ constructor.SuppressDestruct();
- Nan::SetPrototypeMethod(t, "bind", Bind);
- Nan::SetPrototypeMethod(t, "get", Get);
- Nan::SetPrototypeMethod(t, "run", Run);
- Nan::SetPrototypeMethod(t, "all", All);
- Nan::SetPrototypeMethod(t, "each", Each);
- Nan::SetPrototypeMethod(t, "reset", Reset);
- Nan::SetPrototypeMethod(t, "finalize", Finalize);
+ exports.Set("Statement", t);
+ return exports;
+}
+
+// A Napi InstanceOf for Javascript Objects "Date" and "RegExp"
+bool OtherInstanceOf(Napi::Object source, char* object_type) {
+ if (object_type == "Date") {
+ return source.InstanceOf(source.Env().Global().Get("Date").As<Function>());
+ } else if (object_type == "RegExp") {
+ return source.InstanceOf(source.Env().Global().Get("RegExp").As<Function>());
+ }
- constructor_template.Reset(t);
- Nan::Set(target, Nan::New("Statement").ToLocalChecked(),
- Nan::GetFunction(t).ToLocalChecked());
+ return false;
}
void Statement::Process() {
@@ -60,67 +69,71 @@ void Statement::Schedule(Work_Callback callback, Baton* baton) {
}
template <class T> void Statement::Error(T* baton) {
- Nan::HandleScope scope;
-
Statement* stmt = baton->stmt;
+
+ Napi::Env env = stmt->Env();
+ Napi::HandleScope scope(env);
+
// Fail hard on logic errors.
assert(stmt->status != 0);
- EXCEPTION(stmt->message, stmt->status, exception);
+ EXCEPTION(Napi::String::New(env, stmt->message.c_str()), stmt->status, exception);
- Local<Function> cb = Nan::New(baton->callback);
+ Napi::Function cb = baton->callback.Value();
- if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[] = { exception };
- TRY_CATCH_CALL(stmt->handle(), cb, 1, argv);
+ if (!cb.IsUndefined() && cb.IsFunction()) {
+ Napi::Value argv[] = { exception };
+ TRY_CATCH_CALL(stmt->Value(), cb, 1, argv);
}
else {
- Local<Value> argv[] = { Nan::New("error").ToLocalChecked(), exception };
- EMIT_EVENT(stmt->handle(), 2, argv);
+ Napi::Value argv[] = { Napi::String::New(env, "error"), exception };
+ EMIT_EVENT(stmt->Value(), 2, argv);
}
}
// { Database db, String sql, Array params, Function callback }
-NAN_METHOD(Statement::New) {
- if (!info.IsConstructCall()) {
- return Nan::ThrowTypeError("Use the new operator to create new Statement objects");
- }
-
+Statement::Statement(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Statement>(info) {
+ Napi::Env env = info.Env();
int length = info.Length();
if (length <= 0 || !Database::HasInstance(info[0])) {
- return Nan::ThrowTypeError("Database object expected");
+ Napi::TypeError::New(env, "Database object expected").ThrowAsJavaScriptException();
+ return;
}
- else if (length <= 1 || !info[1]->IsString()) {
- return Nan::ThrowTypeError("SQL query expected");
+ else if (length <= 1 || !info[1].IsString()) {
+ Napi::TypeError::New(env, "SQL query expected").ThrowAsJavaScriptException();
+ return;
}
- else if (length > 2 && !info[2]->IsUndefined() && !info[2]->IsFunction()) {
- return Nan::ThrowTypeError("Callback expected");
+ else if (length > 2 && !info[2].IsUndefined() && !info[2].IsFunction()) {
+ Napi::TypeError::New(env, "Callback expected").ThrowAsJavaScriptException();
+ return;
}
- Database* db = Nan::ObjectWrap::Unwrap<Database>(info[0].As<Object>());
- Local<String> sql = Local<String>::Cast(info[1]);
+ Database* db = Napi::ObjectWrap<Database>::Unwrap(info[0].As<Napi::Object>());
+ Napi::String sql = info[1].As<Napi::String>();
- Nan::ForceSet(info.This(),Nan::New("sql").ToLocalChecked(), sql, ReadOnly);
+ info.This().As<Napi::Object>().DefineProperty(Napi::PropertyDescriptor::Value("sql", sql, napi_default));
- Statement* stmt = new Statement(db);
- stmt->Wrap(info.This());
+ init(db);
+ Statement* stmt = this;
- PrepareBaton* baton = new PrepareBaton(db, Local<Function>::Cast(info[2]), stmt);
- baton->sql = std::string(*Nan::Utf8String(sql));
+ PrepareBaton* baton = new PrepareBaton(db, info[2].As<Napi::Function>(), stmt);
+ baton->sql = std::string(sql.As<Napi::String>().Utf8Value().c_str());
db->Schedule(Work_BeginPrepare, baton);
-
- info.GetReturnValue().Set(info.This());
}
void Statement::Work_BeginPrepare(Database::Baton* baton) {
assert(baton->db->open);
baton->db->pending++;
- int status = uv_queue_work(uv_default_loop(),
- &baton->request, Work_Prepare, (uv_after_work_cb)Work_AfterPrepare);
+ Napi::Env env = baton->db->Env();
+ int status = napi_create_async_work(
+ env, NULL, Napi::String::New(env, "sqlite3.Statement.Prepare"),
+ Work_Prepare, Work_AfterPrepare, baton, &baton->request
+ );
assert(status == 0);
+ napi_queue_async_work(env, baton->request);
}
-void Statement::Work_Prepare(uv_work_t* req) {
+void Statement::Work_Prepare(napi_env e, void* data) {
STATEMENT_INIT(PrepareBaton);
// In case preparing fails, we use a mutex to make sure we get the associated
@@ -144,21 +157,22 @@ void Statement::Work_Prepare(uv_work_t* req) {
sqlite3_mutex_leave(mtx);
}
-void Statement::Work_AfterPrepare(uv_work_t* req) {
- Nan::HandleScope scope;
-
+void Statement::Work_AfterPrepare(napi_env e, napi_status status, void* data) {
STATEMENT_INIT(PrepareBaton);
+ Napi::Env env = stmt->Env();
+ Napi::HandleScope scope(env);
+
if (stmt->status != SQLITE_OK) {
Error(baton);
- stmt->Finalize();
+ stmt->Finalize_();
}
else {
stmt->prepared = true;
- Local<Function> cb = Nan::New(baton->callback);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[] = { Nan::Null() };
- TRY_CATCH_CALL(stmt->handle(), cb, 1, argv);
+ if (!baton->callback.IsEmpty() && baton->callback.Value().IsFunction()) {
+ Napi::Function cb = baton->callback.Value();
+ Napi::Value argv[] = { env.Null() };
+ TRY_CATCH_CALL(stmt->Value(), cb, 1, argv);
}
}
@@ -166,77 +180,88 @@ void Statement::Work_AfterPrepare(uv_work_t* req) {
}
template <class T> Values::Field*
- Statement::BindParameter(const Local<Value> source, T pos) {
- if (source->IsString() || source->IsRegExp()) {
- Nan::Utf8String val(source);
- return new Values::Text(pos, val.length(), *val);
- }
- else if (source->IsInt32()) {
- return new Values::Integer(pos, Nan::To<int32_t>(source).FromJust());
- }
- else if (source->IsNumber()) {
- return new Values::Float(pos, Nan::To<double>(source).FromJust());
+ Statement::BindParameter(const Napi::Value source, T pos) {
+ if (source.IsString()) {
+ std::string val = source.As<Napi::String>().Utf8Value();
+ return new Values::Text(pos, val.length(), val.c_str());
+ }
+ else if (OtherInstanceOf(source.As<Object>(), "RegExp")) {
+ std::string val = source.ToString().Utf8Value();
+ return new Values::Text(pos, val.length(), val.c_str());
+ }
+ else if (source.IsNumber()) {
+ if (OtherIsInt(source.As<Napi::Number>())) {
+ return new Values::Integer(pos, source.As<Napi::Number>().Int32Value());
+ } else {
+ return new Values::Float(pos, source.As<Napi::Number>().DoubleValue());
+ }
}
- else if (source->IsBoolean()) {
- return new Values::Integer(pos, Nan::To<bool>(source).FromJust() ? 1 : 0);
+ else if (source.IsBoolean()) {
+ return new Values::Integer(pos, source.As<Napi::Boolean>().Value() ? 1 : 0);
}
- else if (source->IsNull()) {
+ else if (source.IsNull()) {
return new Values::Null(pos);
}
- else if (Buffer::HasInstance(source)) {
- Local<Object> buffer = Nan::To<Object>(source).ToLocalChecked();
- return new Values::Blob(pos, Buffer::Length(buffer), Buffer::Data(buffer));
+ else if (source.IsBuffer()) {
+ Napi::Buffer<char> buffer = source.As<Napi::Buffer<char>>();
+ return new Values::Blob(pos, buffer.Length(), buffer.Data());
}
- else if (source->IsDate()) {
- return new Values::Float(pos, Nan::To<double>(source).FromJust());
+ else if (OtherInstanceOf(source.As<Object>(), "Date")) {
+ return new Values::Float(pos, source.ToNumber().DoubleValue());
+ }
+ else if (source.IsObject()) {
+ std::string val = source.ToString().Utf8Value();
+ return new Values::Text(pos, val.length(), val.c_str());
}
else {
return NULL;
}
}
-template <class T> T* Statement::Bind(Nan::NAN_METHOD_ARGS_TYPE info, int start, int last) {
- Nan::HandleScope scope;
+template <class T> T* Statement::Bind(const Napi::CallbackInfo& info, int start, int last) {
+ Napi::Env env = info.Env();
+ Napi::HandleScope scope(env);
if (last < 0) last = info.Length();
- Local<Function> callback;
- if (last > start && info[last - 1]->IsFunction()) {
- callback = Local<Function>::Cast(info[last - 1]);
+ Napi::Function callback;
+ if (last > start && info[last - 1].IsFunction()) {
+ callback = info[last - 1].As<Napi::Function>();
last--;
}
T* baton = new T(this, callback);
if (start < last) {
- if (info[start]->IsArray()) {
- Local<Array> array = Local<Array>::Cast(info[start]);
- int length = array->Length();
+ if (info[start].IsArray()) {
+ Napi::Array array = info[start].As<Napi::Array>();
+ int length = array.Length();
// Note: bind parameters start with 1.
for (int i = 0, pos = 1; i < length; i++, pos++) {
- baton->parameters.push_back(BindParameter(Nan::Get(array, i).ToLocalChecked(), pos));
+ baton->parameters.push_back(BindParameter((array).Get(i), pos));
}
}
- else if (!info[start]->IsObject() || info[start]->IsRegExp() || info[start]->IsDate() || Buffer::HasInstance(info[start])) {
+ else if (!info[start].IsObject() || OtherInstanceOf(info[start].As<Object>(), "RegExp") || OtherInstanceOf(info[start].As<Object>(), "Date") || info[start].IsBuffer()) {
// Parameters directly in array.
// Note: bind parameters start with 1.
for (int i = start, pos = 1; i < last; i++, pos++) {
baton->parameters.push_back(BindParameter(info[i], pos));
}
}
- else if (info[start]->IsObject()) {
- Local<Object> object = Local<Object>::Cast(info[start]);
- Local<Array> array = Nan::GetPropertyNames(object).ToLocalChecked();
- int length = array->Length();
+ else if (info[start].IsObject()) {
+ Napi::Object object = info[start].As<Napi::Object>();
+ Napi::Array array = object.GetPropertyNames();
+ int length = array.Length();
for (int i = 0; i < length; i++) {
- Local<Value> name = Nan::Get(array, i).ToLocalChecked();
+ Napi::Value name = (array).Get(i);
+ Napi::Number num = name.ToNumber();
- if (name->IsInt32()) {
+ if (num.Int32Value() == num.DoubleValue()) {
baton->parameters.push_back(
- BindParameter(Nan::Get(object, name).ToLocalChecked(), Nan::To<int32_t>(name).FromJust()));
+ BindParameter((object).Get(name), num.Int32Value()));
}
else {
- baton->parameters.push_back(BindParameter(Nan::Get(object, name).ToLocalChecked(),
- *Nan::Utf8String(name)));
+ baton->parameters.push_back(BindParameter((object).Get(name),
+ name.As<Napi::String>().Utf8Value().c_str()));
}
}
}
@@ -263,7 +288,7 @@ bool Statement::Bind(const Parameters & parameters) {
Values::Field* field = *it;
if (field != NULL) {
- int pos;
+ unsigned int pos;
if (field->index > 0) {
pos = field->index;
}
@@ -305,16 +330,18 @@ bool Statement::Bind(const Parameters & parameters) {
return true;
}
-NAN_METHOD(Statement::Bind) {
- Statement* stmt = Nan::ObjectWrap::Unwrap<Statement>(info.This());
+Napi::Value Statement::Bind(const Napi::CallbackInfo& info) {
+ Napi::Env env = info.Env();
+ Statement* stmt = this;
Baton* baton = stmt->Bind<Baton>(info);
if (baton == NULL) {
- return Nan::ThrowTypeError("Data type is not supported");
+ Napi::TypeError::New(env, "Data type is not supported").ThrowAsJavaScriptException();
+ return env.Null();
}
else {
stmt->Schedule(Work_BeginBind, baton);
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
}
@@ -322,7 +349,7 @@ void Statement::Work_BeginBind(Baton* baton) {
STATEMENT_BEGIN(Bind);
}
-void Statement::Work_Bind(uv_work_t* req) {
+void Statement::Work_Bind(napi_env e, void* data) {
STATEMENT_INIT(Baton);
sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->_handle);
@@ -331,20 +358,21 @@ void Statement::Work_Bind(uv_work_t* req) {
sqlite3_mutex_leave(mtx);
}
-void Statement::Work_AfterBind(uv_work_t* req) {
- Nan::HandleScope scope;
-
+void Statement::Work_AfterBind(napi_env e, napi_status status, void* data) {
STATEMENT_INIT(Baton);
+ Napi::Env env = stmt->Env();
+ Napi::HandleScope scope(env);
+
if (stmt->status != SQLITE_OK) {
Error(baton);
}
else {
// Fire callbacks.
- Local<Function> cb = Nan::New(baton->callback);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[] = { Nan::Null() };
- TRY_CATCH_CALL(stmt->handle(), cb, 1, argv);
+ Napi::Function cb = baton->callback.Value();
+ if (!cb.IsUndefined() && cb.IsFunction()) {
+ Napi::Value argv[] = { env.Null() };
+ TRY_CATCH_CALL(stmt->Value(), cb, 1, argv);
}
}
@@ -353,16 +381,18 @@ void Statement::Work_AfterBind(uv_work_t* req) {
-NAN_METHOD(Statement::Get) {
- Statement* stmt = Nan::ObjectWrap::Unwrap<Statement>(info.This());
+Napi::Value Statement::Get(const Napi::CallbackInfo& info) {
+ Napi::Env env = info.Env();
+ Statement* stmt = this;
Baton* baton = stmt->Bind<RowBaton>(info);
if (baton == NULL) {
- return Nan::ThrowError("Data type is not supported");
+ Napi::Error::New(env, "Data type is not supported").ThrowAsJavaScriptException();
+ return env.Null();
}
else {
stmt->Schedule(Work_BeginGet, baton);
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
}
@@ -370,7 +400,7 @@ void Statement::Work_BeginGet(Baton* baton) {
STATEMENT_BEGIN(Get);
}
-void Statement::Work_Get(uv_work_t* req) {
+void Statement::Work_Get(napi_env e, void* data) {
STATEMENT_INIT(RowBaton);
if (stmt->status != SQLITE_DONE || baton->parameters.size()) {
@@ -394,26 +424,27 @@ void Statement::Work_Get(uv_work_t* req) {
}
}
-void Statement::Work_AfterGet(uv_work_t* req) {
- Nan::HandleScope scope;
-
+void Statement::Work_AfterGet(napi_env e, napi_status status, void* data) {
STATEMENT_INIT(RowBaton);
+ Napi::Env env = stmt->Env();
+ Napi::HandleScope scope(env);
+
if (stmt->status != SQLITE_ROW && stmt->status != SQLITE_DONE) {
Error(baton);
}
else {
// Fire callbacks.
- Local<Function> cb = Nan::New(baton->callback);
- if (!cb.IsEmpty() && cb->IsFunction()) {
+ Napi::Function cb = baton->callback.Value();
+ if (!cb.IsUndefined() && cb.IsFunction()) {
if (stmt->status == SQLITE_ROW) {
// Create the result array from the data we acquired.
- Local<Value> argv[] = { Nan::Null(), RowToJS(&baton->row) };
- TRY_CATCH_CALL(stmt->handle(), cb, 2, argv);
+ Napi::Value argv[] = { env.Null(), RowToJS(env, &baton->row) };
+ TRY_CATCH_CALL(stmt->Value(), cb, 2, argv);
}
else {
- Local<Value> argv[] = { Nan::Null() };
- TRY_CATCH_CALL(stmt->handle(), cb, 1, argv);
+ Napi::Value argv[] = { env.Null() };
+ TRY_CATCH_CALL(stmt->Value(), cb, 1, argv);
}
}
}
@@ -421,16 +452,18 @@ void Statement::Work_AfterGet(uv_work_t* req) {
STATEMENT_END();
}
-NAN_METHOD(Statement::Run) {
- Statement* stmt = Nan::ObjectWrap::Unwrap<Statement>(info.This());
+Napi::Value Statement::Run(const Napi::CallbackInfo& info) {
+ Napi::Env env = info.Env();
+ Statement* stmt = this;
Baton* baton = stmt->Bind<RunBaton>(info);
if (baton == NULL) {
- return Nan::ThrowError("Data type is not supported");
+ Napi::Error::New(env, "Data type is not supported").ThrowAsJavaScriptException();
+ return env.Null();
}
else {
stmt->Schedule(Work_BeginRun, baton);
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
}
@@ -438,7 +471,7 @@ void Statement::Work_BeginRun(Baton* baton) {
STATEMENT_BEGIN(Run);
}
-void Statement::Work_Run(uv_work_t* req) {
+void Statement::Work_Run(napi_env e, void* data) {
STATEMENT_INIT(RunBaton);
sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->_handle);
@@ -464,39 +497,42 @@ void Statement::Work_Run(uv_work_t* req) {
sqlite3_mutex_leave(mtx);
}
-void Statement::Work_AfterRun(uv_work_t* req) {
- Nan::HandleScope scope;
-
+void Statement::Work_AfterRun(napi_env e, napi_status status, void* data) {
STATEMENT_INIT(RunBaton);
+ Napi::Env env = stmt->Env();
+ Napi::HandleScope scope(env);
+
if (stmt->status != SQLITE_ROW && stmt->status != SQLITE_DONE) {
Error(baton);
}
else {
// Fire callbacks.
- Local<Function> cb = Nan::New(baton->callback);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- Nan::Set(stmt->handle(), Nan::New("lastID").ToLocalChecked(), Nan::New<Number>(baton->inserted_id));
- Nan::Set(stmt->handle(), Nan::New("changes").ToLocalChecked(), Nan::New(baton->changes));
+ Napi::Function cb = baton->callback.Value();
+ if (!cb.IsUndefined() && cb.IsFunction()) {
+ (stmt->Value()).Set(Napi::String::New(env, "lastID"), Napi::Number::New(env, baton->inserted_id));
+ (stmt->Value()).Set( Napi::String::New(env, "changes"), Napi::Number::New(env, baton->changes));
- Local<Value> argv[] = { Nan::Null() };
- TRY_CATCH_CALL(stmt->handle(), cb, 1, argv);
+ Napi::Value argv[] = { env.Null() };
+ TRY_CATCH_CALL(stmt->Value(), cb, 1, argv);
}
}
STATEMENT_END();
}
-NAN_METHOD(Statement::All) {
- Statement* stmt = Nan::ObjectWrap::Unwrap<Statement>(info.This());
+Napi::Value Statement::All(const Napi::CallbackInfo& info) {
+ Napi::Env env = info.Env();
+ Statement* stmt = this;
Baton* baton = stmt->Bind<RowsBaton>(info);
if (baton == NULL) {
- return Nan::ThrowError("Data type is not supported");
+ Napi::Error::New(env, "Data type is not supported").ThrowAsJavaScriptException();
+ return env.Null();
}
else {
stmt->Schedule(Work_BeginAll, baton);
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
}
@@ -504,7 +540,7 @@ void Statement::Work_BeginAll(Baton* baton) {
STATEMENT_BEGIN(All);
}
-void Statement::Work_All(uv_work_t* req) {
+void Statement::Work_All(napi_env e, void* data) {
STATEMENT_INIT(RowsBaton);
sqlite3_mutex* mtx = sqlite3_db_mutex(stmt->db->_handle);
@@ -530,38 +566,39 @@ void Statement::Work_All(uv_work_t* req) {
sqlite3_mutex_leave(mtx);
}
-void Statement::Work_AfterAll(uv_work_t* req) {
- Nan::HandleScope scope;
-
+void Statement::Work_AfterAll(napi_env e, napi_status status, void* data) {
STATEMENT_INIT(RowsBaton);
+ Napi::Env env = stmt->Env();
+ Napi::HandleScope scope(env);
+
if (stmt->status != SQLITE_DONE) {
Error(baton);
}
else {
// Fire callbacks.
- Local<Function> cb = Nan::New(baton->callback);
- if (!cb.IsEmpty() && cb->IsFunction()) {
+ Napi::Function cb = baton->callback.Value();
+ if (!cb.IsUndefined() && cb.IsFunction()) {
if (baton->rows.size()) {
// Create the result array from the data we acquired.
- Local<Array> result(Nan::New<Array>(baton->rows.size()));
+ Napi::Array result(Napi::Array::New(env, baton->rows.size()));
Rows::const_iterator it = baton->rows.begin();
Rows::const_iterator end = baton->rows.end();
for (int i = 0; it < end; ++it, i++) {
- Nan::Set(result, i, RowToJS(*it));
+ (result).Set(i, RowToJS(env,*it));
delete *it;
}
- Local<Value> argv[] = { Nan::Null(), result };
- TRY_CATCH_CALL(stmt->handle(), cb, 2, argv);
+ Napi::Value argv[] = { env.Null(), result };
+ TRY_CATCH_CALL(stmt->Value(), cb, 2, argv);
}
else {
// There were no result rows.
- Local<Value> argv[] = {
- Nan::Null(),
- Nan::New<Array>(0)
+ Napi::Value argv[] = {
+ env.Null(),
+ Napi::Array::New(env, 0)
};
- TRY_CATCH_CALL(stmt->handle(), cb, 2, argv);
+ TRY_CATCH_CALL(stmt->Value(), cb, 2, argv);
}
}
}
@@ -569,24 +606,26 @@ void Statement::Work_AfterAll(uv_work_t* req) {
STATEMENT_END();
}
-NAN_METHOD(Statement::Each) {
- Statement* stmt = Nan::ObjectWrap::Unwrap<Statement>(info.This());
+Napi::Value Statement::Each(const Napi::CallbackInfo& info) {
+ Napi::Env env = info.Env();
+ Statement* stmt = this;
int last = info.Length();
- Local<Function> completed;
- if (last >= 2 && info[last - 1]->IsFunction() && info[last - 2]->IsFunction()) {
- completed = Local<Function>::Cast(info[--last]);
+ Napi::Function completed;
+ if (last >= 2 && info[last - 1].IsFunction() && info[last - 2].IsFunction()) {
+ completed = info[--last].As<Napi::Function>();
}
EachBaton* baton = stmt->Bind<EachBaton>(info, 0, last);
if (baton == NULL) {
- return Nan::ThrowError("Data type is not supported");
+ Napi::Error::New(env, "Data type is not supported").ThrowAsJavaScriptException();
+ return env.Null();
}
else {
- baton->completed.Reset(completed);
+ baton->completed.Reset(completed, 1);
stmt->Schedule(Work_BeginEach, baton);
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
}
@@ -595,13 +634,13 @@ void Statement::Work_BeginEach(Baton* baton) {
// the event loop. This prevents dangling events.
EachBaton* each_baton = static_cast<EachBaton*>(baton);
each_baton->async = new Async(each_baton->stmt, reinterpret_cast<uv_async_cb>(AsyncEach));
- each_baton->async->item_cb.Reset(each_baton->callback);
- each_baton->async->completed_cb.Reset(each_baton->completed);
+ each_baton->async->item_cb.Reset(each_baton->callback.Value(), 1);
+ each_baton->async->completed_cb.Reset(each_baton->completed.Value(), 1);
STATEMENT_BEGIN(Each);
}
-void Statement::Work_Each(uv_work_t* req) {
+void Statement::Work_Each(napi_env e, void* data) {
STATEMENT_INIT(EachBaton);
Async* async = baton->async;
@@ -651,11 +690,12 @@ void Statement::CloseCallback(uv_handle_t* handle) {
delete async;
}
-void Statement::AsyncEach(uv_async_t* handle, int status) {
- Nan::HandleScope scope;
-
+void Statement::AsyncEach(uv_async_t* handle) {
Async* async = static_cast<Async*>(handle->data);
+ Napi::Env env = async->stmt->Env();
+ Napi::HandleScope scope(env);
+
while (true) {
// Get the contents out of the data cache for us to process in the JS callback.
Rows rows;
@@ -667,41 +707,42 @@ void Statement::AsyncEach(uv_async_t* handle, int status) {
break;
}
- Local<Function> cb = Nan::New(async->item_cb);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[2];
- argv[0] = Nan::Null();
+ Napi::Function cb = async->item_cb.Value();
+ if (!cb.IsUndefined() && cb.IsFunction()) {
+ Napi::Value argv[2];
+ argv[0] = env.Null();
Rows::const_iterator it = rows.begin();
Rows::const_iterator end = rows.end();
for (int i = 0; it < end; ++it, i++) {
- argv[1] = RowToJS(*it);
+ argv[1] = RowToJS(env,*it);
async->retrieved++;
- TRY_CATCH_CALL(async->stmt->handle(), cb, 2, argv);
+ TRY_CATCH_CALL(async->stmt->Value(), cb, 2, argv);
delete *it;
}
}
}
- Local<Function> cb = Nan::New(async->completed_cb);
+ Napi::Function cb = async->completed_cb.Value();
if (async->completed) {
if (!cb.IsEmpty() &&
- cb->IsFunction()) {
- Local<Value> argv[] = {
- Nan::Null(),
- Nan::New(async->retrieved)
+ cb.IsFunction()) {
+ Napi::Value argv[] = {
+ env.Null(),
+ Napi::Number::New(env, async->retrieved)
};
- TRY_CATCH_CALL(async->stmt->handle(), cb, 2, argv);
+ TRY_CATCH_CALL(async->stmt->Value(), cb, 2, argv);
}
uv_close(reinterpret_cast<uv_handle_t*>(handle), CloseCallback);
}
}
-void Statement::Work_AfterEach(uv_work_t* req) {
- Nan::HandleScope scope;
-
+void Statement::Work_AfterEach(napi_env e, napi_status status, void* data) {
STATEMENT_INIT(EachBaton);
+ Napi::Env env = stmt->Env();
+ Napi::HandleScope scope(env);
+
if (stmt->status != SQLITE_DONE) {
Error(baton);
}
@@ -709,74 +750,76 @@ void Statement::Work_AfterEach(uv_work_t* req) {
STATEMENT_END();
}
-NAN_METHOD(Statement::Reset) {
- Statement* stmt = Nan::ObjectWrap::Unwrap<Statement>(info.This());
+Napi::Value Statement::Reset(const Napi::CallbackInfo& info) {
+ Napi::Env env = info.Env();
+ Statement* stmt = this;
OPTIONAL_ARGUMENT_FUNCTION(0, callback);
Baton* baton = new Baton(stmt, callback);
stmt->Schedule(Work_BeginReset, baton);
- info.GetReturnValue().Set(info.This());
+ return info.This();
}
void Statement::Work_BeginReset(Baton* baton) {
STATEMENT_BEGIN(Reset);
}
-void Statement::Work_Reset(uv_work_t* req) {
+void Statement::Work_Reset(napi_env e, void* data) {
STATEMENT_INIT(Baton);
sqlite3_reset(stmt->_handle);
stmt->status = SQLITE_OK;
}
-void Statement::Work_AfterReset(uv_work_t* req) {
- Nan::HandleScope scope;
-
+void Statement::Work_AfterReset(napi_env e, napi_status status, void* data) {
STATEMENT_INIT(Baton);
+ Napi::Env env = stmt->Env();
+ Napi::HandleScope scope(env);
+
// Fire callbacks.
- Local<Function> cb = Nan::New(baton->callback);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- Local<Value> argv[] = { Nan::Null() };
- TRY_CATCH_CALL(stmt->handle(), cb, 1, argv);
+ Napi::Function cb = baton->callback.Value();
+ if (!cb.IsUndefined() && cb.IsFunction()) {
+ Napi::Value argv[] = { env.Null() };
+ TRY_CATCH_CALL(stmt->Value(), cb, 1, argv);
}
STATEMENT_END();
}
-Local<Object> Statement::RowToJS(Row* row) {
- Nan::EscapableHandleScope scope;
+Napi::Value Statement::RowToJS(Napi::Env env, Row* row) {
+ Napi::EscapableHandleScope scope(env);
- Local<Object> result = Nan::New<Object>();
+ Napi::Object result = Napi::Object::New(env);
Row::const_iterator it = row->begin();
Row::const_iterator end = row->end();
for (int i = 0; it < end; ++it, i++) {
Values::Field* field = *it;
- Local<Value> value;
+ Napi::Value value;
switch (field->type) {
case SQLITE_INTEGER: {
- value = Nan::New<Number>(((Values::Integer*)field)->value);
+ value = Napi::Number::New(env, ((Values::Integer*)field)->value);
} break;
case SQLITE_FLOAT: {
- value = Nan::New<Number>(((Values::Float*)field)->value);
+ value = Napi::Number::New(env, ((Values::Float*)field)->value);
} break;
case SQLITE_TEXT: {
- value = Nan::New<String>(((Values::Text*)field)->value.c_str(), ((Values::Text*)field)->value.size()).ToLocalChecked();
+ value = Napi::String::New(env, ((Values::Text*)field)->value.c_str(), ((Values::Text*)field)->value.size());
} break;
case SQLITE_BLOB: {
- value = Nan::CopyBuffer(((Values::Blob*)field)->value, ((Values::Blob*)field)->length).ToLocalChecked();
+ value = Napi::Buffer<char>::Copy(env, ((Values::Blob*)field)->value, ((Values::Blob*)field)->length);
} break;
case SQLITE_NULL: {
- value = Nan::Null();
+ value = env.Null();
} break;
}
- Nan::Set(result, Nan::New(field->name.c_str()).ToLocalChecked(), value);
+ (result).Set(Napi::String::New(env, field->name.c_str()), value);
DELETE_FIELD(field);
}
@@ -816,31 +859,33 @@ void Statement::GetRow(Row* row, sqlite3_stmt* stmt) {
}
}
-NAN_METHOD(Statement::Finalize) {
- Statement* stmt = Nan::ObjectWrap::Unwrap<Statement>(info.This());
+Napi::Value Statement::Finalize_(const Napi::CallbackInfo& info) {
+ Napi::Env env = info.Env();
+ Statement* stmt = this;
OPTIONAL_ARGUMENT_FUNCTION(0, callback);
Baton* baton = new Baton(stmt, callback);
- stmt->Schedule(Finalize, baton);
+ stmt->Schedule(Finalize_, baton);
- info.GetReturnValue().Set(stmt->db->handle());
+ return stmt->db->Value();
}
-void Statement::Finalize(Baton* baton) {
- Nan::HandleScope scope;
+void Statement::Finalize_(Baton* baton) {
+ Napi::Env env = baton->stmt->Env();
+ Napi::HandleScope scope(env);
- baton->stmt->Finalize();
+ baton->stmt->Finalize_();
// Fire callback in case there was one.
- Local<Function> cb = Nan::New(baton->callback);
- if (!cb.IsEmpty() && cb->IsFunction()) {
- TRY_CATCH_CALL(baton->stmt->handle(), cb, 0, NULL);
+ Napi::Function cb = baton->callback.Value();
+ if (!cb.IsUndefined() && cb.IsFunction()) {
+ TRY_CATCH_CALL(baton->stmt->Value(), cb, 0, NULL);
}
delete baton;
}
-void Statement::Finalize() {
+void Statement::Finalize_() {
assert(!finalized);
finalized = true;
CleanQueue();
@@ -852,13 +897,14 @@ void Statement::Finalize() {
}
void Statement::CleanQueue() {
- Nan::HandleScope scope;
+ Napi::Env env = this->Env();
+ Napi::HandleScope scope(env);
if (prepared && !queue.empty()) {
// This statement has already been prepared and is now finalized.
// Fire error for all remaining items in the queue.
- EXCEPTION("Statement is already finalized", SQLITE_MISUSE, exception);
- Local<Value> argv[] = { exception };
+ EXCEPTION(Napi::String::New(env, "Statement is already finalized"), SQLITE_MISUSE, exception);
+ Napi::Value argv[] = { exception };
bool called = false;
// Clear out the queue so that this object can get GC'ed.
@@ -866,11 +912,11 @@ void Statement::CleanQueue() {
Call* call = queue.front();
queue.pop();
- Local<Function> cb = Nan::New(call->baton->callback);
+ Napi::Function cb = call->baton->callback.Value();
if (prepared && !cb.IsEmpty() &&
- cb->IsFunction()) {
- TRY_CATCH_CALL(handle(), cb, 1, argv);
+ cb.IsFunction()) {
+ TRY_CATCH_CALL(Value(), cb, 1, argv);
called = true;
}
@@ -883,8 +929,8 @@ void Statement::CleanQueue() {
// When we couldn't call a callback function, emit an error on the
// Statement object.
if (!called) {
- Local<Value> info[] = { Nan::New("error").ToLocalChecked(), exception };
- EMIT_EVENT(handle(), 2, info);
+ Napi::Value info[] = { Napi::String::New(env, "error"), exception };
+ EMIT_EVENT(Value(), 2, info);
}
}
else while (!queue.empty()) {
diff --git a/src/statement.h b/src/statement.h
index 90d295b..04a5721 100644
--- a/src/statement.h
+++ b/src/statement.h
@@ -1,10 +1,6 @@
#ifndef NODE_SQLITE3_SRC_STATEMENT_H
#define NODE_SQLITE3_SRC_STATEMENT_H
-
-#include "database.h"
-#include "threading.h"
-
#include <cstdlib>
#include <cstring>
#include <string>
@@ -12,10 +8,13 @@
#include <vector>
#include <sqlite3.h>
-#include <nan.h>
+#include <napi.h>
+#include <uv.h>
-using namespace v8;
-using namespace node;
+#include "database.h"
+#include "threading.h"
+
+using namespace Napi;
namespace node_sqlite3 {
@@ -71,23 +70,22 @@ typedef Row Parameters;
-class Statement : public Nan::ObjectWrap {
+class Statement : public Napi::ObjectWrap<Statement> {
public:
- static Nan::Persistent<FunctionTemplate> constructor_template;
+ static Napi::FunctionReference constructor;
- static NAN_MODULE_INIT(Init);
- static NAN_METHOD(New);
+ static Napi::Object Init(Napi::Env env, Napi::Object exports);
+ static Napi::Value New(const Napi::CallbackInfo& info);
struct Baton {
- uv_work_t request;
+ napi_async_work request;
Statement* stmt;
- Nan::Persistent<Function> callback;
+ Napi::FunctionReference callback;
Parameters parameters;
- Baton(Statement* stmt_, Local<Function> cb_) : stmt(stmt_) {
+ Baton(Statement* stmt_, Napi::Function cb_) : stmt(stmt_) {
stmt->Ref();
- request.data = this;
- callback.Reset(cb_);
+ callback.Reset(cb_, 1);
}
virtual ~Baton() {
for (unsigned int i = 0; i < parameters.size(); i++) {
@@ -100,20 +98,20 @@ public:
};
struct RowBaton : Baton {
- RowBaton(Statement* stmt_, Local<Function> cb_) :
+ RowBaton(Statement* stmt_, Napi::Function cb_) :
Baton(stmt_, cb_) {}
Row row;
};
struct RunBaton : Baton {
- RunBaton(Statement* stmt_, Local<Function> cb_) :
+ RunBaton(Statement* stmt_, Napi::Function cb_) :
Baton(stmt_, cb_), inserted_id(0), changes(0) {}
sqlite3_int64 inserted_id;
int changes;
};
struct RowsBaton : Baton {
- RowsBaton(Statement* stmt_, Local<Function> cb_) :
+ RowsBaton(Statement* stmt_, Napi::Function cb_) :
Baton(stmt_, cb_) {}
Rows rows;
};
@@ -121,10 +119,10 @@ public:
struct Async;
struct EachBaton : Baton {
- Nan::Persistent<Function> completed;
+ Napi::FunctionReference completed;
Async* async; // Isn't deleted when the baton is deleted.
- EachBaton(Statement* stmt_, Local<Function> cb_) :
+ EachBaton(Statement* stmt_, Napi::Function cb_) :
Baton(stmt_, cb_) {}
virtual ~EachBaton() {
completed.Reset();
@@ -134,7 +132,7 @@ public:
struct PrepareBaton : Database::Baton {
Statement* stmt;
std::string sql;
- PrepareBaton(Database* db_, Local<Function> cb_, Statement* stmt_) :
+ PrepareBaton(Database* db_, Napi::Function cb_, Statement* stmt_) :
Baton(db_, cb_), stmt(stmt_) {
stmt->Ref();
}
@@ -143,7 +141,7 @@ public:
if (!db->IsOpen() && db->IsLocked()) {
// The database handle was closed before the statement could be
// prepared.
- stmt->Finalize();
+ stmt->Finalize_();
}
}
};
@@ -166,15 +164,17 @@ public:
// Store the callbacks here because we don't have
// access to the baton in the async callback.
- Nan::Persistent<Function> item_cb;
- Nan::Persistent<Function> completed_cb;
+ Napi::FunctionReference item_cb;
+ Napi::FunctionReference completed_cb;
Async(Statement* st, uv_async_cb async_cb) :
stmt(st), completed(false), retrieved(0) {
watcher.data = this;
NODE_SQLITE3_MUTEX_INIT
stmt->Ref();
- uv_async_init(uv_default_loop(), &watcher, async_cb);
+ uv_loop_t *loop;
+ napi_get_uv_event_loop(stmt->Env(), &loop);
+ uv_async_init(loop, &watcher, async_cb);
}
~Async() {
@@ -185,18 +185,20 @@ public:
}
};
- Statement(Database* db_) : Nan::ObjectWrap(),
- db(db_),
- _handle(NULL),
- status(SQLITE_OK),
- prepared(false),
- locked(true),
- finalized(false) {
+ void init(Database* db_) {
+ db = db_;
+ _handle = NULL;
+ status = SQLITE_OK;
+ prepared = false;
+ locked = true;
+ finalized = false;
db->Ref();
}
+ Statement(const Napi::CallbackInfo& info);
+
~Statement() {
- if (!finalized) Finalize();
+ if (!finalized) Finalize_();
}
WORK_DEFINITION(Bind);
@@ -206,25 +208,25 @@ public:
WORK_DEFINITION(Each);
WORK_DEFINITION(Reset);
- static NAN_METHOD(Finalize);
+ Napi::Value Finalize_(const Napi::CallbackInfo& info);
protected:
static void Work_BeginPrepare(Database::Baton* baton);
- static void Work_Prepare(uv_work_t* req);
- static void Work_AfterPrepare(uv_work_t* req);
+ static void Work_Prepare(napi_env env, void* data);
+ static void Work_AfterPrepare(napi_env env, napi_status status, void* data);
- static void AsyncEach(uv_async_t* handle, int status);
+ static void AsyncEach(uv_async_t* handle);
static void CloseCallback(uv_handle_t* handle);
- static void Finalize(Baton* baton);
- void Finalize();
+ static void Finalize_(Baton* baton);
+ void Finalize_();
- template <class T> inline Values::Field* BindParameter(const Local<Value> source, T pos);
- template <class T> T* Bind(Nan::NAN_METHOD_ARGS_TYPE info, int start = 0, int end = -1);
+ template <class T> inline Values::Field* BindParameter(const Napi::Value source, T pos);
+ template <class T> T* Bind(const Napi::CallbackInfo& info, int start = 0, int end = -1);
bool Bind(const Parameters &parameters);
static void GetRow(Row* row, sqlite3_stmt* stmt);
- static Local<Object> RowToJS(Row* row);
+ static Napi::Value RowToJS(Napi::Env env, Row* row);
void Schedule(Work_Callback callback, Baton* baton);
void Process();
void CleanQueue();
diff --git a/test/affected.test.js b/test/affected.test.js
index f0bf192..031dc1b 100644
--- a/test/affected.test.js
+++ b/test/affected.test.js
@@ -11,7 +11,7 @@ describe('query properties', function() {
it('should return the correct lastID', function(done) {
var stmt = db.prepare("INSERT INTO foo VALUES(?, ?)");
var j = 1;
- for (var i = 0; i < 1000; i++) {
+ for (var i = 0; i < 5000; i++) {
stmt.run(i, "demo", function(err) {
if (err) throw err;
// Relies on SQLite's row numbering to be gapless and starting
@@ -25,7 +25,7 @@ describe('query properties', function() {
it('should return the correct changes count', function(done) {
db.run("UPDATE foo SET id = id + 1 WHERE id % 2 = 0", function(err) {
if (err) throw err;
- assert.equal(500, this.changes);
+ assert.equal(2500, this.changes);
done();
});
});
diff --git a/test/database_fail.test.js b/test/database_fail.test.js
index 35589ec..8b93676 100644
--- a/test/database_fail.test.js
+++ b/test/database_fail.test.js
@@ -10,11 +10,11 @@ describe('error handling', function() {
it('throw when calling Database() without new', function() {
assert.throws(function() {
sqlite3.Database(':memory:');
- }, (/Use the new operator to create new Database objects/));
+ }, (/Class constructors cannot be invoked without 'new'/));
assert.throws(function() {
sqlite3.Statement();
- }, (/Use the new operator to create new Statement objects/));
+ }, (/Class constructors cannot be invoked without 'new'/));
});
it('should error when calling Database#get on a missing table', function(done) {
diff --git a/test/verbose.test.js b/test/verbose.test.js
new file mode 100644
index 0000000..b680280
--- /dev/null
+++ b/test/verbose.test.js
@@ -0,0 +1,60 @@
+var sqlite3 = require('..');
+var assert = require('assert');
+
+var invalid_sql = 'update non_existent_table set id=1';
+
+var originalMethods = {
+ Database: {},
+ Statement: {},
+};
+
+function backupOriginalMethods() {
+ for (var obj in originalMethods) {
+ for (var attr in sqlite3[obj].prototype) {
+ originalMethods[obj][attr] = sqlite3[obj].prototype[attr];
+ }
+ }
+}
+
+function resetVerbose() {
+ for (var obj in originalMethods) {
+ for (var attr in originalMethods[obj]) {
+ sqlite3[obj].prototype[attr] = originalMethods[obj][attr];
+ }
+ }
+}
+
+describe('verbose', function() {
+ it('Shoud add trace info to error when verbose is called', function(done) {
+ var db = new sqlite3.Database(':memory:');
+ backupOriginalMethods();
+ sqlite3.verbose();
+
+ db.run(invalid_sql, function(err) {
+ assert(err instanceof Error);
+
+ assert(
+ err.stack.indexOf(`Database#run('${invalid_sql}'`) > -1,
+ `Stack shoud contain trace info, stack = ${err.stack}`
+ );
+
+ done();
+ resetVerbose();
+ });
+ });
+
+ it('Shoud not add trace info to error when verbose is not called', function(done) {
+ var db = new sqlite3.Database(':memory:');
+
+ db.run(invalid_sql, function(err) {
+ assert(err instanceof Error);
+
+ assert(
+ err.stack.indexOf(invalid_sql) === -1,
+ `Stack shoud not contain trace info, stack = ${err.stack}`
+ );
+
+ done();
+ });
+ });
+});