diff --git a/BUILD.gn b/BUILD.gn index 91e4611645..e0b98fa557 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -18,6 +18,7 @@ pool("serialized_action_pool") { group("ten_framework_all") { deps = [ "//core/src/ten_runtime", + "//core/src/ten_runtime/binding", "//core/src/ten_rust", "//packages/core_apps", "//packages/core_extensions", diff --git a/build/ten_runtime/options.gni b/build/ten_runtime/options.gni index 9333b85048..d542dbfeda 100644 --- a/build/ten_runtime/options.gni +++ b/build/ten_runtime/options.gni @@ -22,6 +22,7 @@ declare_args() { declare_args() { ten_enable_go_binding = true ten_enable_python_binding = true + ten_enable_nodejs_binding = true } # ten_runtime extensions diff --git a/core/include_internal/ten_runtime/binding/nodejs/app/app.h b/core/include_internal/ten_runtime/binding/nodejs/app/app.h new file mode 100644 index 0000000000..46d5e8bef2 --- /dev/null +++ b/core/include_internal/ten_runtime/binding/nodejs/app/app.h @@ -0,0 +1,12 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#include "ten_runtime/ten_config.h" + +#include "include_internal/ten_runtime/binding/nodejs/common/nodejs_stuff.h" + +TEN_RUNTIME_API napi_value ten_nodejs_app_module_init(napi_env env, + napi_value exports); diff --git a/core/include_internal/ten_runtime/binding/nodejs/common/common.h b/core/include_internal/ten_runtime/binding/nodejs/common/common.h new file mode 100644 index 0000000000..bf01dce062 --- /dev/null +++ b/core/include_internal/ten_runtime/binding/nodejs/common/common.h @@ -0,0 +1,9 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#pragma once + +#include "include_internal/ten_runtime/binding/nodejs/common/nodejs_stuff.h" diff --git a/core/include_internal/ten_runtime/binding/nodejs/common/nodejs_stuff.h b/core/include_internal/ten_runtime/binding/nodejs/common/nodejs_stuff.h new file mode 100644 index 0000000000..b24e98468d --- /dev/null +++ b/core/include_internal/ten_runtime/binding/nodejs/common/nodejs_stuff.h @@ -0,0 +1,9 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#pragma once + +#include diff --git a/core/src/ten_runtime/binding/BUILD.gn b/core/src/ten_runtime/binding/BUILD.gn index f84d5c611e..422564139a 100644 --- a/core/src/ten_runtime/binding/BUILD.gn +++ b/core/src/ten_runtime/binding/BUILD.gn @@ -18,4 +18,8 @@ glob("binding") { if (ten_enable_python_binding) { deps += [ "python" ] } + + if (ten_enable_nodejs_binding) { + deps += [ "nodejs" ] + } } diff --git a/core/src/ten_runtime/binding/nodejs/BUILD.gn b/core/src/ten_runtime/binding/nodejs/BUILD.gn new file mode 100644 index 0000000000..460f774374 --- /dev/null +++ b/core/src/ten_runtime/binding/nodejs/BUILD.gn @@ -0,0 +1,48 @@ +# +# Copyright © 2024 Agora +# This file is part of TEN Framework, an open source project. +# Licensed under the Apache License, Version 2.0, with certain conditions. +# Refer to the "LICENSE" file in the root directory for more information. +# +import("//build/feature/ten_package.gni") +import("//build/options.gni") +import("//build/ten_runtime/feature/publish.gni") +import("//build/ten_runtime/options.gni") +import("//build/ten_runtime/ten.gni") +import("//core/src/ten_runtime/output_libs.gni") + +ten_package("ten_nodejs_binding_system_package") { + package_kind = "system" + package_output_root_dir_name = "ten_runtime_nodejs" + + resources = [ + "//core/src/ten_runtime/binding/nodejs/interface=>interface", + "manifest.json", + ] + + foreach(lib, ten_runtime_nodejs_output_libs) { + libname = get_path_info(rebase_path(lib), "file") + resources += [ "${lib}=>lib/${libname}" ] + } + + deps = [ "native:ten_runtime_nodejs" ] +} + +if (ten_enable_package_manager) { + ten_package_publish("upload_ten_nodejs_binding_system_package_to_server") { + base_dir = + rebase_path("${root_out_dir}/ten_packages/system/ten_runtime_nodejs") + deps = [ + ":ten_nodejs_binding_system_package", + "native:ten_runtime_nodejs", + ] + } +} + +group("nodejs") { + deps = [ "native:ten_runtime_nodejs" ] + + if (ten_enable_package_manager) { + deps += [ ":upload_ten_nodejs_binding_system_package_to_server" ] + } +} diff --git a/core/src/ten_runtime/binding/nodejs/interface/index.ts b/core/src/ten_runtime/binding/nodejs/interface/index.ts new file mode 100644 index 0000000000..977d3b1047 --- /dev/null +++ b/core/src/ten_runtime/binding/nodejs/interface/index.ts @@ -0,0 +1,6 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// diff --git a/core/src/ten_runtime/binding/nodejs/manifest.json b/core/src/ten_runtime/binding/nodejs/manifest.json new file mode 100644 index 0000000000..252ba2d4f5 --- /dev/null +++ b/core/src/ten_runtime/binding/nodejs/manifest.json @@ -0,0 +1,21 @@ +{ + "type": "system", + "name": "ten_runtime_nodejs", + "version": "0.4.2", + "dependencies": [ + { + "type": "system", + "name": "ten_runtime", + "version": "0.4.2" + } + ], + "package": { + "include": [ + "manifest.json", + "BUILD.gn", + "interface/**", + "tools/**", + "lib/**" + ] + } +} \ No newline at end of file diff --git a/core/src/ten_runtime/binding/nodejs/native/BUILD.gn b/core/src/ten_runtime/binding/nodejs/native/BUILD.gn new file mode 100644 index 0000000000..e5ed05f4e7 --- /dev/null +++ b/core/src/ten_runtime/binding/nodejs/native/BUILD.gn @@ -0,0 +1,35 @@ +# +# Copyright © 2024 Agora +# This file is part of TEN Framework, an open source project. +# Licensed under the Apache License, Version 2.0, with certain conditions. +# Refer to the "LICENSE" file in the root directory for more information. +# +import("//build/ten_runtime/ten.gni") + +config("ten_runtime_nodejs_config") { + include_dirs = ten_runtime_common_includes + include_dirs += [ "//third_party/node-api-headers/include" ] + + if (!is_win) { + cflags = [ "-fPIC" ] + } +} + +ten_shared_library("ten_runtime_nodejs") { + configs = [ ":ten_runtime_nodejs_config" ] + + if (is_mac || is_linux) { + add_configs = [ "//.gnfiles/build/toolchain/common:allow_undefined" ] + remove_configs = [ "//.gnfiles/build/toolchain/common:disallow_undefined" ] + } + + sources = [ + "//core/src/ten_runtime/binding/nodejs/native/build_template/preserved_metadata.c", + "init.c", + ] + + deps = [ + "app", + "//core/src/ten_runtime:ten_runtime_library", + ] +} diff --git a/core/src/ten_runtime/binding/nodejs/native/app/BUILD.gn b/core/src/ten_runtime/binding/nodejs/native/app/BUILD.gn new file mode 100644 index 0000000000..4efad5fea5 --- /dev/null +++ b/core/src/ten_runtime/binding/nodejs/native/app/BUILD.gn @@ -0,0 +1,14 @@ +# +# Copyright © 2024 Agora +# This file is part of TEN Framework, an open source project. +# Licensed under the Apache License, Version 2.0, with certain conditions. +# Refer to the "LICENSE" file in the root directory for more information. +# +import("//build/ten_runtime/glob.gni") + +glob("app") { + configs = [ + "//core/src/ten_runtime/binding/nodejs/native:ten_runtime_nodejs_config", + ] + file_list = all_native_files +} diff --git a/core/src/ten_runtime/binding/nodejs/native/app/app.c b/core/src/ten_runtime/binding/nodejs/native/app/app.c new file mode 100644 index 0000000000..9093b8796d --- /dev/null +++ b/core/src/ten_runtime/binding/nodejs/native/app/app.c @@ -0,0 +1,13 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#include "include_internal/ten_runtime/binding/nodejs/app/app.h" + +#include "include_internal/ten_runtime/binding/nodejs/common/common.h" + +napi_value ten_nodejs_app_module_init(napi_env env, napi_value exports) { + return exports; +} diff --git a/core/src/ten_runtime/binding/nodejs/native/build_template/preserved_metadata.c b/core/src/ten_runtime/binding/nodejs/native/build_template/preserved_metadata.c new file mode 100644 index 0000000000..780be42149 --- /dev/null +++ b/core/src/ten_runtime/binding/nodejs/native/build_template/preserved_metadata.c @@ -0,0 +1,13 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#include "include_internal/ten_runtime/common/preserved_metadata.h" + +static char metadata[] = "version=0.1.0"; + +void ten_preserved_metadata(void) { + ((char volatile *)metadata)[0] = metadata[0]; +} diff --git a/core/src/ten_runtime/binding/nodejs/native/build_template/preserved_metadata.c.jinja2 b/core/src/ten_runtime/binding/nodejs/native/build_template/preserved_metadata.c.jinja2 new file mode 100644 index 0000000000..709afe0afb --- /dev/null +++ b/core/src/ten_runtime/binding/nodejs/native/build_template/preserved_metadata.c.jinja2 @@ -0,0 +1,13 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#include "include_internal/ten_runtime/common/preserved_metadata.h" + +static char metadata[] = "version={{ VERSION }}"; + +void ten_preserved_metadata(void) { + ((char volatile *)metadata)[0] = metadata[0]; +} diff --git a/core/src/ten_runtime/binding/nodejs/native/init.c b/core/src/ten_runtime/binding/nodejs/native/init.c new file mode 100644 index 0000000000..f1f9f6980c --- /dev/null +++ b/core/src/ten_runtime/binding/nodejs/native/init.c @@ -0,0 +1,15 @@ +// +// Copyright © 2024 Agora +// This file is part of TEN Framework, an open source project. +// Licensed under the Apache License, Version 2.0, with certain conditions. +// Refer to the "LICENSE" file in the root directory for more information. +// +#include "include_internal/ten_runtime/binding/nodejs/app/app.h" +#include "include_internal/ten_runtime/binding/nodejs/common/common.h" + +napi_value Init(napi_env env, napi_value exports) { + ten_nodejs_app_module_init(env, exports); + return exports; +} + +NAPI_MODULE(ten_runtime_nodejs, Init) diff --git a/core/src/ten_runtime/binding/python/BUILD.gn b/core/src/ten_runtime/binding/python/BUILD.gn index ad78b63644..04ba779d9f 100644 --- a/core/src/ten_runtime/binding/python/BUILD.gn +++ b/core/src/ten_runtime/binding/python/BUILD.gn @@ -47,8 +47,4 @@ group("python") { if (ten_enable_package_manager) { deps += [ ":upload_ten_python_binding_system_package_to_server" ] } - - if (ten_enable_package_manager) { - deps += [ ":upload_ten_python_binding_system_package_to_server" ] - } } diff --git a/core/src/ten_runtime/output_libs.gni b/core/src/ten_runtime/output_libs.gni index d27aee3648..7377f3165f 100644 --- a/core/src/ten_runtime/output_libs.gni +++ b/core/src/ten_runtime/output_libs.gni @@ -24,10 +24,14 @@ if (is_linux) { ten_runtime_go_output_libs = [ "${root_out_dir}/libten_runtime_go.so" ] ten_runtime_python_output_libs = [ "${root_out_dir}/libten_runtime_python.so" ] + ten_runtime_nodejs_output_libs = + [ "${root_out_dir}/libten_runtime_nodejs.so" ] } else if (is_mac) { ten_runtime_go_output_libs = [ "${root_out_dir}/libten_runtime_go.dylib" ] ten_runtime_python_output_libs = [ "${root_out_dir}/libten_runtime_python.dylib" ] + ten_runtime_nodejs_output_libs = + [ "${root_out_dir}/libten_runtime_nodejs.dylib" ] } else if (is_win) { ten_runtime_go_output_libs = [ "${root_out_dir}/ten_runtime_go.dll", @@ -37,6 +41,10 @@ if (is_linux) { "${root_out_dir}/ten_runtime_python.dll", "${root_out_dir}/ten_runtime_python.dll.lib", ] + ten_runtime_nodejs_output_libs = [ + "${root_out_dir}/ten_runtime_nodejs.dll", + "${root_out_dir}/ten_runtime_nodejs.dll.lib", + ] } template("ten_runtime_copy_deps") { diff --git a/third_party/node-api-headers/.gitignore b/third_party/node-api-headers/.gitignore new file mode 100644 index 0000000000..f8a75e252a --- /dev/null +++ b/third_party/node-api-headers/.gitignore @@ -0,0 +1,3 @@ +.vscode +node_modules/ + diff --git a/third_party/node-api-headers/.npmignore b/third_party/node-api-headers/.npmignore new file mode 100644 index 0000000000..127db70aba --- /dev/null +++ b/third_party/node-api-headers/.npmignore @@ -0,0 +1,2 @@ +scripts/ +.github/ diff --git a/third_party/node-api-headers/.release-please-manifest.json b/third_party/node-api-headers/.release-please-manifest.json new file mode 100644 index 0000000000..73d3293b98 --- /dev/null +++ b/third_party/node-api-headers/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "1.4.0" +} diff --git a/third_party/node-api-headers/CHANGELOG.md b/third_party/node-api-headers/CHANGELOG.md new file mode 100644 index 0000000000..b082798e55 --- /dev/null +++ b/third_party/node-api-headers/CHANGELOG.md @@ -0,0 +1,101 @@ +# node-api-headers Changelog + +## [1.4.0](https://github.com/nodejs/node-api-headers/compare/v1.3.0...v1.4.0) (2024-10-30) + + +### Features + +* **no-release:** add conditional support in `#if` ([#52](https://github.com/nodejs/node-api-headers/issues/52)) ([e1b8feb](https://github.com/nodejs/node-api-headers/commit/e1b8feb060cf85522538ec1b8a1d6eb782620022)) +* update headers from nodejs/node tag v23.1.0 ([#56](https://github.com/nodejs/node-api-headers/issues/56)) ([3336912](https://github.com/nodejs/node-api-headers/commit/33369124c7f8a670422a0c5a27ad149da83ed8d6)) + +## [1.3.0](https://github.com/nodejs/node-api-headers/compare/v1.2.0...v1.3.0) (2024-09-04) + + +### Features + +* update headers from nodejs/node tag v22.7.0 ([#48](https://github.com/nodejs/node-api-headers/issues/48)) ([6c73c34](https://github.com/nodejs/node-api-headers/commit/6c73c34b72e836531530f863eac315bd42e4569e)) + +## [1.2.0](https://github.com/nodejs/node-api-headers/compare/node-api-headers-v1.1.0...node-api-headers-v1.2.0) (2024-07-09) + + +### Features + +* update headers from nodejs/node tag v22.1.0 ([d5cfe19](https://github.com/nodejs/node-api-headers/commit/d5cfe19da8b974ca35764dd1c73b91d57cd3c4ce)) + +## 2023-08-05 Version 1.1.0, @NickNaso + +### Notable changes + +- Update headers from nodejs/node tag v20.3.0. + +### Commits + +- \[[`1f5a85dbb0`](https://github.com/nodejs/node-api-headers/commit/1f5a85dbb0)] - Update headers from nodejs/node tag v20.3.0 (#30) (github-actions\[bot]) + +## 2023-05-18 Version 1.0.1, @NickNaso + +### Notable changes + +- Update headers from nodejs/node tag v20.2.0. + +### Commits + +- \[[`d61451e6a3`](https://github.com/nodejs/node-api-headers/commit/d61451e6a3)] - Update headers from nodejs/node tag v20.2.0 (#27) (github-actions\[bot]) + +## 2023-04-20 Version 1.0.0, @NickNaso + +### Notable changes + +- Explain package version rationale. +- Update headers from nodejs/node tag v19.9.0. + +### Commits + +- \[[`130338da33`](https://github.com/nodejs/node-api-headers/commit/130338da33)] - **doc**: explain package version rationale (#26) (Chengzhong Wu) +- \[[`1a328031da`](https://github.com/nodejs/node-api-headers/commit/1a328031da)] - Update headers from nodejs/node tag v19.9.0 (#24) (github-actions\[bot]) + +## 2023-04-06 Version 0.0.5, @NickNaso + +### Notable changes + +- Provide def file for windows import lib. + +### Commits + +- \[[`15477c5898`](https://github.com/nodejs/node-api-headers/commit/15477c5898)] - Update headers from nodejs/node tag v19.8.1 (#22) (github-actions\[bot]) +- \[[`d7fa23b60e`](https://github.com/nodejs/node-api-headers/commit/d7fa23b60e)] - Use git status instead of git diff for change calculation (#21) (Kevin Eady) +- \[[`ea0dc01425`](https://github.com/nodejs/node-api-headers/commit/ea0dc01425)] - **fix**: moved def files on a proper folder. (#19) (Nicola Del Gobbo) +- \[[`069c3eb6f8`](https://github.com/nodejs/node-api-headers/commit/069c3eb6f8)] - **doc**: how to create a new release. (#18) (Nicola Del Gobbo) +- \[[`d23c2879c8`](https://github.com/nodejs/node-api-headers/commit/d23c2879c8)] - Provide def file for windows import lib (#17) (Leonid Pospelov) + +## 2023-03-17 Version 0.0.4, @NickNaso + +### Notable changes + +- Update headers from nodejs/node tag v19.8.0. + +### Commits + +- \[[`a1f0d41240`](https://github.com/nodejs/node-api-headers/commit/a1f0d41240)] - Merge pull request #14 from nodejs/update-headers/v19.8.0 (Nicola Del Gobbo) +- \[[`7548267285`](https://github.com/nodejs/node-api-headers/commit/7548267285)] - Update headers from nodejs/node tag v19.8.0 (github-actions\[bot]) + +## 2023-03-08 Version 0.0.3, @NickNaso + +### Notable changes + +- Add helper scripts for updating headers and symbols.js. + +### Commits + +- \[[`4fdbdd1710`](https://github.com/nodejs/node-api-headers/commit/4fdbdd1710)] - Update headers from nodejs/node tag v19.6.0 (#9) (github-actions\[bot]) +- \[[`ecefbdd00f`](https://github.com/nodejs/node-api-headers/commit/ecefbdd00f)] - Add helper scripts for updating headers and symbols.js (#7) (Kevin Eady) + +## 2022-12-29 Version 0.0.2, @NickNaso + +### Notable changes + +- Fixed wrong symblos in v6. + +### Commits + +- \[[`9c0b4ecaa5`](https://github.com/nodejs/node-api-headers/commit/9c0b4ecaa5)] - **fix**: wrong symblos in v6 (#6) (Nicola Del Gobbo) diff --git a/third_party/node-api-headers/CODE_OF_CONDUCT.md b/third_party/node-api-headers/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..eb07a975ec --- /dev/null +++ b/third_party/node-api-headers/CODE_OF_CONDUCT.md @@ -0,0 +1,4 @@ +# Code of Conduct + +The Node.js Code of Conduct, which applies to this project, can be found at +https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md. diff --git a/third_party/node-api-headers/CONTRIBUTING.md b/third_party/node-api-headers/CONTRIBUTING.md new file mode 100644 index 0000000000..9446956751 --- /dev/null +++ b/third_party/node-api-headers/CONTRIBUTING.md @@ -0,0 +1,32 @@ +# Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +* (a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +* (b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +* (c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +* (d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. + +## Moderation Policy + +The [Node.js Moderation Policy] applies to this project. + +[Node.js Moderation Policy]: +https://github.com/nodejs/admin/blob/master/Moderation-Policy.md \ No newline at end of file diff --git a/third_party/node-api-headers/CREATING_A_RELEASE.md b/third_party/node-api-headers/CREATING_A_RELEASE.md new file mode 100644 index 0000000000..abc1a3710a --- /dev/null +++ b/third_party/node-api-headers/CREATING_A_RELEASE.md @@ -0,0 +1,68 @@ +# Creating a release + +Only collaborators in npm for **node-api-headers** can create releases. If you +want to be able to do releases ask one of the existing collaborators to add +you. If necessary you can ask the build Working Group who manages the Node.js +npm user to add you if there are no other active collaborators. + +Generally, the release is handled by the +[release-please](https://github.com/nodejs/node-api-headers/blob/main/.github/workflows/release-please.yml) +GitHub action. It will bump the version in `package.json` and publish +node-api-headers to npm. + +In cases that the release-please action is not working, please follow the steps +below to publish node-api-headers manually. + +## Publish new release manually + +### Prerequisites + +Before to start creating a new release check if you have installed the following +tools: + +* [Changelog maker](https://www.npmjs.com/package/changelog-maker) + +If not please follow the instruction reported in the tool's documentation to +install it. + +### Steps + +These are the steps to follow to create a new release: + +* Open an issue in the **node-api-headers** repo documenting the intent to +create a new release. Give people some time to comment or suggest PRs that +should land first. + +* Update the version in **package.json** appropriately. + +* Update the [README.md][] to show the latest stable version of Node-API. + +* Generate the changelog for the new version using **changelog maker** tool. +From the root folder of the repo launch the following command: + +```bash +> changelog-maker --format=markdown +``` + +* Use the output generated by **changelog maker** to update the +[CHANGELOG.md][] following the style used in publishing the previous release. + +* Add any new contributors to the "contributors" section in the +**package.json**. + +* Do a clean checkout of `node-api-headers`. + +* Login and then run `npm publish`. + +* Create a release in Github (look at existing releases for an example). + +* Validate that you can run `npm install node-api-headers` successfully +and that the correct version is installed. + +* Comment on the issue opened in the first step that the release has been created +and close the issue. + +* Tweet that the release has been created. + +[README.md]: ./README.md +[CHANGELOG.md]: ./CHANGELOG.md \ No newline at end of file diff --git a/third_party/node-api-headers/LICENSE b/third_party/node-api-headers/LICENSE new file mode 100644 index 0000000000..a32c171a03 --- /dev/null +++ b/third_party/node-api-headers/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Node.js + +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. diff --git a/third_party/node-api-headers/README.md b/third_party/node-api-headers/README.md new file mode 100644 index 0000000000..52ddb80c39 --- /dev/null +++ b/third_party/node-api-headers/README.md @@ -0,0 +1,106 @@ +# node-api-headers + +- **[Introduction](#introduction)** +- **[Contributing](CONTRIBUTING.md)** +- **[Code of Conduct](CODE_OF_CONDUCT.md)** +- **[Install](#install)** +- **[API](#api)** +- **[Creating a release](CREATING_A_RELEASE.md)** +- **[Team](#team)** +- **[License](#license)** + +## Current Node-API version: 9 + +(See [CHANGELOG.md](CHANGELOG.md) for complete Changelog) + + + +## Introduction + +**node-api-headers** contains the header files for the C-based Node-API +provided by Node.js. Node-API is an API for building native addons that +guarantees the ABI (Application Binary Interface) stability across versions +of Node.js (see: [Node-API](https://nodejs.org/dist/latest/docs/api/n-api.html)). + +Node-API headers are in the `include` folder. The Node-APIs that provide +ECMAScript features from native code can be found in `js_native_api_types.h` +and `js_native_api.h`. The APIs defined in these headers are included in +`node_api_types.h` and `node_api.h`. +The headers are structured in this way in order to allow implementations of +Node-API outside of Node.js considering that for those implementations the +Node.js specific APIs may not be applicable. + +**node-api-headers** is also a package published on **npm** that could be used +in a process to compile and build native addons for Node.js. + + + +## Install + +``` +npm i node-api-headers +``` + + + +## Versions + +Node-API C headers are backward-compatible. Its version (e.g. `8`) is released +separately from the Node.js version stream (e.g. `19.8.1`) and changes are +backported to active Node.js LTS lines (e.g. `16.x` and `18.x`). + +This package publishes semver-minor versions with new Node-API C headers changes. +JS API breaking changes are published with new semver-major versions. + + + +## API + +The module exports two properties `include_dir` and `symbols`. +### `include_dir` + +This property is a string that represents the include path for the Node-API +headers. + +### `def_paths` + +This property is an object that has two keys `js_native_api_def` and +`node_api_def` which represents the path of the module definition file for the +`js_native_api` and `node_api` respectively. + +### `symbols` + +This property is an object that represents the symbols exported by Node-API +grouped by version and api types. + +```js + V1: { + js_native_api_symbols: [ + // List of symbols in js_native_api.h for the version 1. + ], + node_api_symbols: [ + // List of symbols in node_api.h for the version 1 + ] + }, + // ... +``` + + + +## Team members + +### Active +| Name | GitHub Link | +| ------------------- | ----------------------------------------------------- | +| Anna Henningsen | [addaleax](https://github.com/addaleax) | +| Chengzhong Wu | [legendecas](https://github.com/legendecas) | +| Gabriel Schulhof | [gabrielschulhof](https://github.com/gabrielschulhof) | +| Hitesh Kanwathirtha | [digitalinfinity](https://github.com/digitalinfinity) | +| Jim Schlight | [jschlight](https://github.com/jschlight) | +| Michael Dawson | [mhdawson](https://github.com/mhdawson) | +| Kevin Eady | [KevinEady](https://github.com/KevinEady) +| Nicola Del Gobbo | [NickNaso](https://github.com/NickNaso) | + + + +Licensed under [MIT](./LICENSE.md) diff --git a/third_party/node-api-headers/def/js_native_api.def b/third_party/node-api-headers/def/js_native_api.def new file mode 100644 index 0000000000..dc0d9d5ba1 --- /dev/null +++ b/third_party/node-api-headers/def/js_native_api.def @@ -0,0 +1,120 @@ +NAME NODE.EXE +EXPORTS +napi_adjust_external_memory +napi_call_function +napi_close_escapable_handle_scope +napi_close_handle_scope +napi_coerce_to_bool +napi_coerce_to_number +napi_coerce_to_object +napi_coerce_to_string +napi_create_array +napi_create_array_with_length +napi_create_arraybuffer +napi_create_dataview +napi_create_double +napi_create_error +napi_create_external +napi_create_external_arraybuffer +napi_create_function +napi_create_int32 +napi_create_int64 +napi_create_object +napi_create_promise +napi_create_range_error +napi_create_reference +napi_create_string_latin1 +napi_create_string_utf16 +napi_create_string_utf8 +napi_create_symbol +napi_create_type_error +napi_create_typedarray +napi_create_uint32 +napi_define_class +napi_define_properties +napi_delete_element +napi_delete_property +napi_delete_reference +napi_escape_handle +napi_get_and_clear_last_exception +napi_get_array_length +napi_get_arraybuffer_info +napi_get_boolean +napi_get_cb_info +napi_get_dataview_info +napi_get_element +napi_get_global +napi_get_last_error_info +napi_get_named_property +napi_get_new_target +napi_get_null +napi_get_property +napi_get_property_names +napi_get_prototype +napi_get_reference_value +napi_get_typedarray_info +napi_get_undefined +napi_get_value_bool +napi_get_value_double +napi_get_value_external +napi_get_value_int32 +napi_get_value_int64 +napi_get_value_string_latin1 +napi_get_value_string_utf16 +napi_get_value_string_utf8 +napi_get_value_uint32 +napi_get_version +napi_has_element +napi_has_named_property +napi_has_own_property +napi_has_property +napi_instanceof +napi_is_array +napi_is_arraybuffer +napi_is_dataview +napi_is_error +napi_is_exception_pending +napi_is_promise +napi_is_typedarray +napi_new_instance +napi_open_escapable_handle_scope +napi_open_handle_scope +napi_reference_ref +napi_reference_unref +napi_reject_deferred +napi_remove_wrap +napi_resolve_deferred +napi_run_script +napi_set_element +napi_set_named_property +napi_set_property +napi_strict_equals +napi_throw +napi_throw_error +napi_throw_range_error +napi_throw_type_error +napi_typeof +napi_unwrap +napi_wrap +napi_add_finalizer +napi_create_date +napi_get_date_value +napi_is_date +napi_create_bigint_int64 +napi_create_bigint_uint64 +napi_create_bigint_words +napi_get_all_property_names +napi_get_instance_data +napi_get_value_bigint_int64 +napi_get_value_bigint_uint64 +napi_get_value_bigint_words +napi_set_instance_data +napi_detach_arraybuffer +napi_is_detached_arraybuffer +napi_check_object_type_tag +napi_object_freeze +napi_object_seal +napi_type_tag_object +node_api_create_syntax_error +node_api_symbol_for +node_api_throw_syntax_error \ No newline at end of file diff --git a/third_party/node-api-headers/def/node_api.def b/third_party/node-api-headers/def/node_api.def new file mode 100644 index 0000000000..81c7d35567 --- /dev/null +++ b/third_party/node-api-headers/def/node_api.def @@ -0,0 +1,151 @@ +NAME NODE.EXE +EXPORTS +napi_async_destroy +napi_async_init +napi_cancel_async_work +napi_create_async_work +napi_create_buffer +napi_create_buffer_copy +napi_create_external_buffer +napi_delete_async_work +napi_fatal_error +napi_get_buffer_info +napi_get_node_version +napi_is_buffer +napi_make_callback +napi_module_register +napi_queue_async_work +napi_adjust_external_memory +napi_call_function +napi_close_escapable_handle_scope +napi_close_handle_scope +napi_coerce_to_bool +napi_coerce_to_number +napi_coerce_to_object +napi_coerce_to_string +napi_create_array +napi_create_array_with_length +napi_create_arraybuffer +napi_create_dataview +napi_create_double +napi_create_error +napi_create_external +napi_create_external_arraybuffer +napi_create_function +napi_create_int32 +napi_create_int64 +napi_create_object +napi_create_promise +napi_create_range_error +napi_create_reference +napi_create_string_latin1 +napi_create_string_utf16 +napi_create_string_utf8 +napi_create_symbol +napi_create_type_error +napi_create_typedarray +napi_create_uint32 +napi_define_class +napi_define_properties +napi_delete_element +napi_delete_property +napi_delete_reference +napi_escape_handle +napi_get_and_clear_last_exception +napi_get_array_length +napi_get_arraybuffer_info +napi_get_boolean +napi_get_cb_info +napi_get_dataview_info +napi_get_element +napi_get_global +napi_get_last_error_info +napi_get_named_property +napi_get_new_target +napi_get_null +napi_get_property +napi_get_property_names +napi_get_prototype +napi_get_reference_value +napi_get_typedarray_info +napi_get_undefined +napi_get_value_bool +napi_get_value_double +napi_get_value_external +napi_get_value_int32 +napi_get_value_int64 +napi_get_value_string_latin1 +napi_get_value_string_utf16 +napi_get_value_string_utf8 +napi_get_value_uint32 +napi_get_version +napi_has_element +napi_has_named_property +napi_has_own_property +napi_has_property +napi_instanceof +napi_is_array +napi_is_arraybuffer +napi_is_dataview +napi_is_error +napi_is_exception_pending +napi_is_promise +napi_is_typedarray +napi_new_instance +napi_open_escapable_handle_scope +napi_open_handle_scope +napi_reference_ref +napi_reference_unref +napi_reject_deferred +napi_remove_wrap +napi_resolve_deferred +napi_run_script +napi_set_element +napi_set_named_property +napi_set_property +napi_strict_equals +napi_throw +napi_throw_error +napi_throw_range_error +napi_throw_type_error +napi_typeof +napi_unwrap +napi_wrap +napi_get_uv_event_loop +napi_add_env_cleanup_hook +napi_close_callback_scope +napi_fatal_exception +napi_open_callback_scope +napi_remove_env_cleanup_hook +napi_acquire_threadsafe_function +napi_call_threadsafe_function +napi_create_threadsafe_function +napi_get_threadsafe_function_context +napi_ref_threadsafe_function +napi_release_threadsafe_function +napi_unref_threadsafe_function +napi_add_finalizer +napi_create_date +napi_get_date_value +napi_is_date +napi_create_bigint_int64 +napi_create_bigint_uint64 +napi_create_bigint_words +napi_get_all_property_names +napi_get_instance_data +napi_get_value_bigint_int64 +napi_get_value_bigint_uint64 +napi_get_value_bigint_words +napi_set_instance_data +napi_detach_arraybuffer +napi_is_detached_arraybuffer +napi_add_async_cleanup_hook +napi_remove_async_cleanup_hook +napi_check_object_type_tag +napi_object_freeze +napi_object_seal +napi_type_tag_object +node_api_get_module_file_name +node_api_create_syntax_error +node_api_symbol_for +node_api_throw_syntax_error \ No newline at end of file diff --git a/third_party/node-api-headers/include/js_native_api.h b/third_party/node-api-headers/include/js_native_api.h new file mode 100644 index 0000000000..b4d349eabc --- /dev/null +++ b/third_party/node-api-headers/include/js_native_api.h @@ -0,0 +1,577 @@ +#ifndef SRC_JS_NATIVE_API_H_ +#define SRC_JS_NATIVE_API_H_ + +// This file needs to be compatible with C compilers. +#include // NOLINT(modernize-deprecated-headers) +#include // NOLINT(modernize-deprecated-headers) + +// Use INT_MAX, this should only be consumed by the pre-processor anyway. +#define NAPI_VERSION_EXPERIMENTAL 2147483647 +#ifndef NAPI_VERSION +// The baseline version for N-API. +// The NAPI_VERSION controls which version will be used by default when +// compilling a native addon. If the addon developer specifically wants to use +// functions available in a new version of N-API that is not yet ported in all +// LTS versions, they can set NAPI_VERSION knowing that they have specifically +// depended on that version. +#define NAPI_VERSION 8 +#endif + +#include "js_native_api_types.h" + +// If you need __declspec(dllimport), either include instead, or +// define NAPI_EXTERN as __declspec(dllimport) on the compiler's command line. +#ifndef NAPI_EXTERN +#ifdef _WIN32 +#define NAPI_EXTERN __declspec(dllexport) +#elif defined(__wasm__) +#define NAPI_EXTERN \ + __attribute__((visibility("default"))) \ + __attribute__((__import_module__("napi"))) +#else +#define NAPI_EXTERN __attribute__((visibility("default"))) +#endif +#endif + +#define NAPI_AUTO_LENGTH SIZE_MAX + +#ifdef __cplusplus +#define EXTERN_C_START extern "C" { +#define EXTERN_C_END } +#else +#define EXTERN_C_START +#define EXTERN_C_END +#endif + +EXTERN_C_START + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_last_error_info( + node_api_basic_env env, const napi_extended_error_info** result); + +// Getters for defined singletons +NAPI_EXTERN napi_status NAPI_CDECL napi_get_undefined(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_null(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_global(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_boolean(napi_env env, + bool value, + napi_value* result); + +// Methods to create Primitive types/Objects +NAPI_EXTERN napi_status NAPI_CDECL napi_create_object(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_array(napi_env env, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_array_with_length(napi_env env, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_double(napi_env env, + double value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_int32(napi_env env, + int32_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_uint32(napi_env env, + uint32_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_int64(napi_env env, + int64_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_latin1( + napi_env env, const char* str, size_t length, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf8(napi_env env, + const char* str, + size_t length, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_string_utf16(napi_env env, + const char16_t* str, + size_t length, + napi_value* result); + + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_symbol(napi_env env, + napi_value description, + napi_value* result); +#if NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL +node_api_symbol_for(napi_env env, + const char* utf8description, + size_t length, + napi_value* result); +#endif // NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL 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_CDECL napi_create_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_type_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_range_error(napi_env env, + napi_value code, + napi_value msg, + napi_value* result); +#if NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL node_api_create_syntax_error( + napi_env env, napi_value code, napi_value msg, napi_value* result); +#endif // NAPI_VERSION >= 9 + +// Methods to get the native napi_value from Primitive type +NAPI_EXTERN napi_status NAPI_CDECL napi_typeof(napi_env env, + napi_value value, + napi_valuetype* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_double(napi_env env, + napi_value value, + double* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int32(napi_env env, + napi_value value, + int32_t* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_uint32(napi_env env, + napi_value value, + uint32_t* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_int64(napi_env env, + napi_value value, + int64_t* result); +NAPI_EXTERN napi_status NAPI_CDECL 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_CDECL 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_CDECL 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_CDECL 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_CDECL napi_coerce_to_bool(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_number(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_object(napi_env env, + napi_value value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_coerce_to_string(napi_env env, + napi_value value, + napi_value* result); + +// Methods to work with Objects +NAPI_EXTERN napi_status NAPI_CDECL napi_get_prototype(napi_env env, + napi_value object, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_property_names(napi_env env, + napi_value object, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_set_property(napi_env env, + napi_value object, + napi_value key, + napi_value value); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_property(napi_env env, + napi_value object, + napi_value key, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_own_property(napi_env env, + napi_value object, + napi_value key, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_set_named_property(napi_env env, + napi_value object, + const char* utf8name, + napi_value value); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_named_property(napi_env env, + napi_value object, + const char* utf8name, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_named_property(napi_env env, + napi_value object, + const char* utf8name, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_set_element(napi_env env, + napi_value object, + uint32_t index, + napi_value value); +NAPI_EXTERN napi_status NAPI_CDECL napi_has_element(napi_env env, + napi_value object, + uint32_t index, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_element(napi_env env, + napi_value object, + uint32_t index, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_delete_element(napi_env env, + napi_value object, + uint32_t index, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +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_CDECL napi_is_array(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_array_length(napi_env env, + napi_value value, + uint32_t* result); + +// Methods to compare values +NAPI_EXTERN napi_status NAPI_CDECL napi_strict_equals(napi_env env, + napi_value lhs, + napi_value rhs, + bool* result); + +// Methods to work with Functions +NAPI_EXTERN napi_status NAPI_CDECL 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_CDECL napi_new_instance(napi_env env, + napi_value constructor, + size_t argc, + const napi_value* argv, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL 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_CDECL napi_get_cb_info( + napi_env env, // [in] Node-API 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_CDECL napi_get_new_target( + napi_env env, napi_callback_info cbinfo, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +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_CDECL +napi_wrap(napi_env env, + napi_value js_object, + void* native_object, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_ref* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_unwrap(napi_env env, + napi_value js_object, + void** result); +NAPI_EXTERN napi_status NAPI_CDECL napi_remove_wrap(napi_env env, + napi_value js_object, + void** result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_external(napi_env env, + void* data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL 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_CDECL +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_CDECL 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_CDECL 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_CDECL 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_CDECL napi_get_reference_value(napi_env env, + napi_ref ref, + napi_value* result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_open_handle_scope(napi_env env, napi_handle_scope* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_close_handle_scope(napi_env env, napi_handle_scope scope); +NAPI_EXTERN napi_status NAPI_CDECL napi_open_escapable_handle_scope( + napi_env env, napi_escapable_handle_scope* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_close_escapable_handle_scope( + napi_env env, napi_escapable_handle_scope scope); + +NAPI_EXTERN napi_status NAPI_CDECL +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_CDECL napi_throw(napi_env env, napi_value error); +NAPI_EXTERN napi_status NAPI_CDECL napi_throw_error(napi_env env, + const char* code, + const char* msg); +NAPI_EXTERN napi_status NAPI_CDECL napi_throw_type_error(napi_env env, + const char* code, + const char* msg); +NAPI_EXTERN napi_status NAPI_CDECL napi_throw_range_error(napi_env env, + const char* code, + const char* msg); +#if NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL node_api_throw_syntax_error(napi_env env, + const char* code, + const char* msg); +#endif // NAPI_VERSION >= 9 +NAPI_EXTERN napi_status NAPI_CDECL napi_is_error(napi_env env, + napi_value value, + bool* result); + +// Methods to support catching exceptions +NAPI_EXTERN napi_status NAPI_CDECL napi_is_exception_pending(napi_env env, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_and_clear_last_exception(napi_env env, napi_value* result); + +// Methods to work with array buffers and typed arrays +NAPI_EXTERN napi_status NAPI_CDECL napi_is_arraybuffer(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_create_arraybuffer(napi_env env, + size_t byte_length, + void** data, + napi_value* result); +#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_external_arraybuffer(napi_env env, + void* external_data, + size_t byte_length, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED +NAPI_EXTERN napi_status NAPI_CDECL napi_get_arraybuffer_info( + napi_env env, napi_value arraybuffer, void** data, size_t* byte_length); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_typedarray(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +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_CDECL +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_CDECL napi_create_dataview(napi_env env, + size_t length, + napi_value arraybuffer, + size_t byte_offset, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_dataview(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_dataview_info(napi_env env, + napi_value dataview, + size_t* bytelength, + void** data, + napi_value* arraybuffer, + size_t* byte_offset); + +// version management +NAPI_EXTERN napi_status NAPI_CDECL napi_get_version(node_api_basic_env env, + uint32_t* result); + +// Promises +NAPI_EXTERN napi_status NAPI_CDECL napi_create_promise(napi_env env, + napi_deferred* deferred, + napi_value* promise); +NAPI_EXTERN napi_status NAPI_CDECL napi_resolve_deferred(napi_env env, + napi_deferred deferred, + napi_value resolution); +NAPI_EXTERN napi_status NAPI_CDECL napi_reject_deferred(napi_env env, + napi_deferred deferred, + napi_value rejection); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_promise(napi_env env, + napi_value value, + bool* is_promise); + +// Running a script +NAPI_EXTERN napi_status NAPI_CDECL napi_run_script(napi_env env, + napi_value script, + napi_value* result); + +// Memory management +NAPI_EXTERN napi_status NAPI_CDECL napi_adjust_external_memory( + node_api_basic_env env, int64_t change_in_bytes, int64_t* adjusted_value); + +#if NAPI_VERSION >= 5 + +// Dates +NAPI_EXTERN napi_status NAPI_CDECL napi_create_date(napi_env env, + double time, + napi_value* result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_is_date(napi_env env, + napi_value value, + bool* is_date); + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_date_value(napi_env env, + napi_value value, + double* result); + +// Add finalizer for pointer +NAPI_EXTERN napi_status NAPI_CDECL +napi_add_finalizer(napi_env env, + napi_value js_object, + void* finalize_data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_ref* result); + +#endif // NAPI_VERSION >= 5 + + +#if NAPI_VERSION >= 6 + +// BigInt +NAPI_EXTERN napi_status NAPI_CDECL napi_create_bigint_int64(napi_env env, + int64_t value, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_bigint_uint64(napi_env env, uint64_t value, napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_bigint_words(napi_env env, + int sign_bit, + size_t word_count, + const uint64_t* words, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_int64(napi_env env, + napi_value value, + int64_t* result, + bool* lossless); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_value_bigint_uint64( + napi_env env, napi_value value, uint64_t* result, bool* lossless); +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_value_bigint_words(napi_env env, + napi_value value, + int* sign_bit, + size_t* word_count, + uint64_t* words); + +// Object +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_all_property_names(napi_env env, + napi_value object, + napi_key_collection_mode key_mode, + napi_key_filter key_filter, + napi_key_conversion key_conversion, + napi_value* result); + +// Instance data +NAPI_EXTERN napi_status NAPI_CDECL +napi_set_instance_data(node_api_basic_env env, + void* data, + napi_finalize finalize_cb, + void* finalize_hint); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_instance_data(node_api_basic_env env, void** data); +#endif // NAPI_VERSION >= 6 + +#if NAPI_VERSION >= 7 +// ArrayBuffer detaching +NAPI_EXTERN napi_status NAPI_CDECL +napi_detach_arraybuffer(napi_env env, napi_value arraybuffer); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_is_detached_arraybuffer(napi_env env, napi_value value, bool* result); +#endif // NAPI_VERSION >= 7 + +#if NAPI_VERSION >= 8 +// Type tagging +NAPI_EXTERN napi_status NAPI_CDECL napi_type_tag_object( + napi_env env, napi_value value, const napi_type_tag* type_tag); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_check_object_type_tag(napi_env env, + napi_value value, + const napi_type_tag* type_tag, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_object_freeze(napi_env env, + napi_value object); +NAPI_EXTERN napi_status NAPI_CDECL napi_object_seal(napi_env env, + napi_value object); +#endif // NAPI_VERSION >= 8 + +EXTERN_C_END + +#endif // SRC_JS_NATIVE_API_H_ diff --git a/third_party/node-api-headers/include/js_native_api_types.h b/third_party/node-api-headers/include/js_native_api_types.h new file mode 100644 index 0000000000..7853a8d7a3 --- /dev/null +++ b/third_party/node-api-headers/include/js_native_api_types.h @@ -0,0 +1,195 @@ +#ifndef SRC_JS_NATIVE_API_TYPES_H_ +#define SRC_JS_NATIVE_API_TYPES_H_ + +// This file needs to be compatible with C compilers. +// This is a public include file, and these includes have essentially +// became part of it's API. +#include // NOLINT(modernize-deprecated-headers) +#include // NOLINT(modernize-deprecated-headers) + +#if !defined __cplusplus || (defined(_MSC_VER) && _MSC_VER < 1900) +typedef uint16_t char16_t; +#endif + +#ifndef NAPI_CDECL +#ifdef _WIN32 +#define NAPI_CDECL __cdecl +#else +#define NAPI_CDECL +#endif +#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; + +// We need to mark APIs which can be called during garbage collection (GC), +// meaning that they do not affect the state of the JS engine, and can +// therefore be called synchronously from a finalizer that itself runs +// synchronously during GC. Such APIs can receive either a `napi_env` or a +// `node_api_basic_env` as their first parameter, because we should be able to +// also call them during normal, non-garbage-collecting operations, whereas +// APIs that affect the state of the JS engine can only receive a `napi_env` as +// their first parameter, because we must not call them during GC. In lieu of +// inheritance, we use the properties of the const qualifier to accomplish +// this, because both a const and a non-const value can be passed to an API +// expecting a const value, but only a non-const value can be passed to an API +// expecting a non-const value. +// +// In conjunction with appropriate CFLAGS to warn us if we're passing a const +// (basic) environment into an API that expects a non-const environment, and +// the definition of basic finalizer function pointer types below, which +// receive a basic environment as their first parameter, and can thus only call +// basic APIs (unless the user explicitly casts the environment), we achieve +// the ability to ensure at compile time that we do not call APIs that affect +// the state of the JS engine from a synchronous (basic) finalizer. +typedef struct napi_env__* node_api_nogc_env; +typedef node_api_nogc_env node_api_basic_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_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, + +#if NAPI_VERSION >= 8 + // Default for class methods. + napi_default_method = napi_writable | napi_configurable, + + // Default for object properties, like in JS obj[prop]. + napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable, +#endif // NAPI_VERSION >= 8 +} 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_bigint, +} 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_bigint64_array, + napi_biguint64_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_callback_scope_mismatch, + napi_queue_full, + napi_closing, + napi_bigint_expected, + napi_date_expected, + napi_arraybuffer_expected, + napi_detachable_arraybuffer_expected, + napi_would_deadlock, // unused + napi_no_external_buffers_allowed, + napi_cannot_run_js, +} napi_status; +// Note: when adding a new enum value to `napi_status`, please also update +// * `const int last_status` in the definition of `napi_get_last_error_info()' +// in file js_native_api_v8.cc. +// * `const char* error_messages[]` in file js_native_api_v8.cc with a brief +// message explaining the error. +// * the definition of `napi_status` in doc/api/n-api.md to reflect the newly +// added value(s). + +typedef napi_value(NAPI_CDECL* napi_callback)(napi_env env, + napi_callback_info info); +typedef void(NAPI_CDECL* napi_finalize)(napi_env env, + void* finalize_data, + void* finalize_hint); + +typedef napi_finalize node_api_nogc_finalize; +typedef node_api_nogc_finalize node_api_basic_finalize; + +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; + +#if NAPI_VERSION >= 6 +typedef enum { + napi_key_include_prototypes, + napi_key_own_only +} napi_key_collection_mode; + +typedef enum { + napi_key_all_properties = 0, + napi_key_writable = 1, + napi_key_enumerable = 1 << 1, + napi_key_configurable = 1 << 2, + napi_key_skip_strings = 1 << 3, + napi_key_skip_symbols = 1 << 4 +} napi_key_filter; + +typedef enum { + napi_key_keep_numbers, + napi_key_numbers_to_strings +} napi_key_conversion; +#endif // NAPI_VERSION >= 6 + +#if NAPI_VERSION >= 8 +typedef struct { + uint64_t lower; + uint64_t upper; +} napi_type_tag; +#endif // NAPI_VERSION >= 8 + +#endif // SRC_JS_NATIVE_API_TYPES_H_ diff --git a/third_party/node-api-headers/include/node_api.h b/third_party/node-api-headers/include/node_api.h new file mode 100644 index 0000000000..80a0f45c87 --- /dev/null +++ b/third_party/node-api-headers/include/node_api.h @@ -0,0 +1,263 @@ +#ifndef SRC_NODE_API_H_ +#define SRC_NODE_API_H_ + +#if defined(BUILDING_NODE_EXTENSION) && !defined(NAPI_EXTERN) +#ifdef _WIN32 +// Building native addon against node +#define NAPI_EXTERN __declspec(dllimport) +#elif defined(__wasm__) +#define NAPI_EXTERN __attribute__((__import_module__("napi"))) +#endif +#endif +#include "js_native_api.h" +#include "node_api_types.h" + +struct uv_loop_s; // Forward declaration. + +#ifdef _WIN32 +#define NAPI_MODULE_EXPORT __declspec(dllexport) +#else +#ifdef __EMSCRIPTEN__ +#define NAPI_MODULE_EXPORT \ + __attribute__((visibility("default"))) __attribute__((used)) +#else +#define NAPI_MODULE_EXPORT __attribute__((visibility("default"))) +#endif +#endif + +#if defined(__GNUC__) +#define NAPI_NO_RETURN __attribute__((noreturn)) +#elif defined(_WIN32) +#define NAPI_NO_RETURN __declspec(noreturn) +#else +#define NAPI_NO_RETURN +#endif + +typedef napi_value(NAPI_CDECL* napi_addon_register_func)(napi_env env, + napi_value exports); +typedef int32_t(NAPI_CDECL* node_api_addon_get_api_version_func)(void); + +// Used by deprecated registration method napi_module_register. +typedef struct napi_module { + 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 + +#define NAPI_MODULE_INITIALIZER_X(base, version) \ + NAPI_MODULE_INITIALIZER_X_HELPER(base, version) +#define NAPI_MODULE_INITIALIZER_X_HELPER(base, version) base##version + +#ifdef __wasm__ +#define NAPI_MODULE_INITIALIZER_BASE napi_register_wasm_v +#else +#define NAPI_MODULE_INITIALIZER_BASE napi_register_module_v +#endif + +#define NODE_API_MODULE_GET_API_VERSION_BASE node_api_module_get_api_version_v + +#define NAPI_MODULE_INITIALIZER \ + NAPI_MODULE_INITIALIZER_X(NAPI_MODULE_INITIALIZER_BASE, NAPI_MODULE_VERSION) + +#define NODE_API_MODULE_GET_API_VERSION \ + NAPI_MODULE_INITIALIZER_X(NODE_API_MODULE_GET_API_VERSION_BASE, \ + NAPI_MODULE_VERSION) + +#define NAPI_MODULE_INIT() \ + EXTERN_C_START \ + NAPI_MODULE_EXPORT int32_t NODE_API_MODULE_GET_API_VERSION(void) { \ + return NAPI_VERSION; \ + } \ + NAPI_MODULE_EXPORT napi_value NAPI_MODULE_INITIALIZER(napi_env env, \ + napi_value exports); \ + EXTERN_C_END \ + napi_value NAPI_MODULE_INITIALIZER(napi_env env, napi_value exports) + +#define NAPI_MODULE(modname, regfunc) \ + NAPI_MODULE_INIT() { return regfunc(env, exports); } + +// Deprecated. Use NAPI_MODULE. +#define NAPI_MODULE_X(modname, regfunc, priv, flags) \ + NAPI_MODULE(modname, regfunc) + +EXTERN_C_START + +// Deprecated. Replaced by symbol-based registration defined by NAPI_MODULE +// and NAPI_MODULE_INIT macros. +#if defined(__cplusplus) && __cplusplus >= 201402L +[[deprecated]] +#endif +NAPI_EXTERN void NAPI_CDECL +napi_module_register(napi_module* mod); + +NAPI_EXTERN NAPI_NO_RETURN void NAPI_CDECL +napi_fatal_error(const char* location, + size_t location_len, + const char* message, + size_t message_len); + +// Methods for custom handling of async operations +NAPI_EXTERN napi_status NAPI_CDECL +napi_async_init(napi_env env, + napi_value async_resource, + napi_value async_resource_name, + napi_async_context* result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_async_destroy(napi_env env, napi_async_context async_context); + +NAPI_EXTERN napi_status NAPI_CDECL +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); + +// Methods to provide node::Buffer functionality with napi types +NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer(napi_env env, + size_t length, + void** data, + napi_value* result); +#ifndef NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_external_buffer(napi_env env, + size_t length, + void* data, + node_api_basic_finalize finalize_cb, + void* finalize_hint, + napi_value* result); +#endif // NODE_API_NO_EXTERNAL_BUFFERS_ALLOWED + + +NAPI_EXTERN napi_status NAPI_CDECL napi_create_buffer_copy(napi_env env, + size_t length, + const void* data, + void** result_data, + napi_value* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_is_buffer(napi_env env, + napi_value value, + bool* result); +NAPI_EXTERN napi_status NAPI_CDECL napi_get_buffer_info(napi_env env, + napi_value value, + void** data, + size_t* length); + +// Methods to manage simple async operations +NAPI_EXTERN napi_status NAPI_CDECL +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_CDECL napi_delete_async_work(napi_env env, + napi_async_work work); +NAPI_EXTERN napi_status NAPI_CDECL napi_queue_async_work(node_api_basic_env env, + napi_async_work work); +NAPI_EXTERN napi_status NAPI_CDECL +napi_cancel_async_work(node_api_basic_env env, napi_async_work work); + +// version management +NAPI_EXTERN napi_status NAPI_CDECL napi_get_node_version( + node_api_basic_env env, const napi_node_version** version); + +#if NAPI_VERSION >= 2 + +// Return the current libuv event loop for a given environment +NAPI_EXTERN napi_status NAPI_CDECL +napi_get_uv_event_loop(node_api_basic_env env, struct uv_loop_s** loop); + +#endif // NAPI_VERSION >= 2 + +#if NAPI_VERSION >= 3 + +NAPI_EXTERN napi_status NAPI_CDECL napi_fatal_exception(napi_env env, + napi_value err); + +NAPI_EXTERN napi_status NAPI_CDECL napi_add_env_cleanup_hook( + node_api_basic_env env, napi_cleanup_hook fun, void* arg); + +NAPI_EXTERN napi_status NAPI_CDECL napi_remove_env_cleanup_hook( + node_api_basic_env env, napi_cleanup_hook fun, void* arg); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_open_callback_scope(napi_env env, + napi_value resource_object, + napi_async_context context, + napi_callback_scope* result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_close_callback_scope(napi_env env, napi_callback_scope scope); + +#endif // NAPI_VERSION >= 3 + +#if NAPI_VERSION >= 4 + +// Calling into JS from other threads +NAPI_EXTERN napi_status NAPI_CDECL +napi_create_threadsafe_function(napi_env env, + napi_value func, + napi_value async_resource, + napi_value async_resource_name, + size_t max_queue_size, + size_t initial_thread_count, + void* thread_finalize_data, + napi_finalize thread_finalize_cb, + void* context, + napi_threadsafe_function_call_js call_js_cb, + napi_threadsafe_function* result); + +NAPI_EXTERN napi_status NAPI_CDECL napi_get_threadsafe_function_context( + napi_threadsafe_function func, void** result); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_call_threadsafe_function(napi_threadsafe_function func, + void* data, + napi_threadsafe_function_call_mode is_blocking); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_acquire_threadsafe_function(napi_threadsafe_function func); + +NAPI_EXTERN napi_status NAPI_CDECL napi_release_threadsafe_function( + napi_threadsafe_function func, napi_threadsafe_function_release_mode mode); + +NAPI_EXTERN napi_status NAPI_CDECL napi_unref_threadsafe_function( + node_api_basic_env env, napi_threadsafe_function func); + +NAPI_EXTERN napi_status NAPI_CDECL napi_ref_threadsafe_function( + node_api_basic_env env, napi_threadsafe_function func); + +#endif // NAPI_VERSION >= 4 + +#if NAPI_VERSION >= 8 + +NAPI_EXTERN napi_status NAPI_CDECL +napi_add_async_cleanup_hook(node_api_basic_env env, + napi_async_cleanup_hook hook, + void* arg, + napi_async_cleanup_hook_handle* remove_handle); + +NAPI_EXTERN napi_status NAPI_CDECL +napi_remove_async_cleanup_hook(napi_async_cleanup_hook_handle remove_handle); + +#endif // NAPI_VERSION >= 8 + +#if NAPI_VERSION >= 9 + +NAPI_EXTERN napi_status NAPI_CDECL +node_api_get_module_file_name(node_api_basic_env env, const char** result); + +#endif // NAPI_VERSION >= 9 + +EXTERN_C_END + +#endif // SRC_NODE_API_H_ diff --git a/third_party/node-api-headers/include/node_api_types.h b/third_party/node-api-headers/include/node_api_types.h new file mode 100644 index 0000000000..9c2f03f4d0 --- /dev/null +++ b/third_party/node-api-headers/include/node_api_types.h @@ -0,0 +1,52 @@ +#ifndef SRC_NODE_API_TYPES_H_ +#define SRC_NODE_API_TYPES_H_ + +#include "js_native_api_types.h" + +typedef struct napi_callback_scope__* napi_callback_scope; +typedef struct napi_async_context__* napi_async_context; +typedef struct napi_async_work__* napi_async_work; + +#if NAPI_VERSION >= 3 +typedef void(NAPI_CDECL* napi_cleanup_hook)(void* arg); +#endif // NAPI_VERSION >= 3 + +#if NAPI_VERSION >= 4 +typedef struct napi_threadsafe_function__* napi_threadsafe_function; +#endif // NAPI_VERSION >= 4 + +#if NAPI_VERSION >= 4 +typedef enum { + napi_tsfn_release, + napi_tsfn_abort +} napi_threadsafe_function_release_mode; + +typedef enum { + napi_tsfn_nonblocking, + napi_tsfn_blocking +} napi_threadsafe_function_call_mode; +#endif // NAPI_VERSION >= 4 + +typedef void(NAPI_CDECL* napi_async_execute_callback)(napi_env env, void* data); +typedef void(NAPI_CDECL* napi_async_complete_callback)(napi_env env, + napi_status status, + void* data); +#if NAPI_VERSION >= 4 +typedef void(NAPI_CDECL* napi_threadsafe_function_call_js)( + napi_env env, napi_value js_callback, void* context, void* data); +#endif // NAPI_VERSION >= 4 + +typedef struct { + uint32_t major; + uint32_t minor; + uint32_t patch; + const char* release; +} napi_node_version; + +#if NAPI_VERSION >= 8 +typedef struct napi_async_cleanup_hook_handle__* napi_async_cleanup_hook_handle; +typedef void(NAPI_CDECL* napi_async_cleanup_hook)( + napi_async_cleanup_hook_handle handle, void* data); +#endif // NAPI_VERSION >= 8 + +#endif // SRC_NODE_API_TYPES_H_ diff --git a/third_party/node-api-headers/index.js b/third_party/node-api-headers/index.js new file mode 100644 index 0000000000..d9123bbef8 --- /dev/null +++ b/third_party/node-api-headers/index.js @@ -0,0 +1,17 @@ +'use strict' + +const path = require('path'); +const symbols = require('./symbols'); + +const include_dir = path.resolve(__dirname, 'include'); +const defRoot = path.resolve(__dirname, 'def') +const def_paths = { + js_native_api_def: path.join(defRoot, 'js_native_api.def'), + node_api_def: path.join(defRoot, 'node_api.def') +} + +module.exports = { + include_dir, + def_paths, + symbols +} diff --git a/third_party/node-api-headers/lib/clang-utils.js b/third_party/node-api-headers/lib/clang-utils.js new file mode 100644 index 0000000000..2f2b032735 --- /dev/null +++ b/third_party/node-api-headers/lib/clang-utils.js @@ -0,0 +1,50 @@ +'use strict'; + +const { spawn } = require('child_process'); + +/** + * @param {Array} [args] + * @returns {Promise<{exitCode: number | null, stdout: string, stderr: string}>} + */ +async function runClang(args = []) { + try { + const { exitCode, stdout, stderr } = await new Promise((resolve, reject) => { + const spawned = spawn('clang', + ['-Xclang', ...args] + ); + + let stdout = ''; + let stderr = ''; + + spawned.stdout?.on('data', (data) => { + stdout += data.toString('utf-8'); + }); + spawned.stderr?.on('data', (data) => { + stderr += data.toString('utf-8'); + }); + + spawned.on('exit', function (exitCode) { + resolve({ exitCode, stdout, stderr }); + }); + + spawned.on('error', function (err) { + reject(err); + }); + }); + + if (exitCode !== 0) { + throw new Error(`clang exited with non-zero exit code ${exitCode}. stderr: ${stderr ? stderr : ''}`); + } + + return { exitCode, stdout, stderr }; + } catch (err) { + if (err.code === 'ENOENT') { + throw new Error('This tool requires clang to be installed.'); + } + throw err; + } +} + +module.exports = { + runClang +}; diff --git a/third_party/node-api-headers/lib/parse-utils.js b/third_party/node-api-headers/lib/parse-utils.js new file mode 100644 index 0000000000..7b2e755016 --- /dev/null +++ b/third_party/node-api-headers/lib/parse-utils.js @@ -0,0 +1,92 @@ +const parser = require("acorn"); + +/** + * @param {string} text Code to evaluate + * @returns {boolean | undefined} The result of the evaluation, `undefined` if + * parsing failed or the result is unknown. + */ +function evaluate(text) { + try { + const ast = parser.parse(text, { ecmaVersion: 2020 }); + + const expressionStatement = ast.body[0]; + + if (expressionStatement.type !== "ExpressionStatement") { + throw new Error("Expected an ExpressionStatement"); + } + + return visitExpression(expressionStatement.expression); + } catch { + // Return an unknown result if parsing failed + return undefined; + } +} + +/** + * @param {import("acorn").Expression} node + */ +const visitExpression = (node) => { + if (node.type === "LogicalExpression") { + return visitLogicalExpression(node); + } else if (node.type === "UnaryExpression") { + return visitUnaryExpression(node); + } else if (node.type === "CallExpression") { + return visitCallExpression(node); + } else { + throw new Error(`Unknown node type: ${node.type} ${JSON.stringify(node)}`); + } +}; + +/** + * @param {import("acorn").LogicalExpression} node + */ +const visitLogicalExpression = (node) => { + const left = visitExpression(node.left); + const right = visitExpression(node.right); + + if (node.operator === "&&") { + // We can shortcircuit regardless of `unknown` if either are false. + if (left === false || right === false) { + return false; + } else if (left === undefined || right === undefined) { + return undefined; + } else { + return left && right; + } + } else if (node.operator === "||") { + if (left === undefined || right === undefined) { + return undefined; + } else { + return left || right; + } + } +}; + +/** + * @param {import("acorn").UnaryExpression} node + */ +const visitUnaryExpression = (node) => { + const argument = visitExpression(node.argument); + if (typeof argument === 'boolean') { + return !argument; + } +}; + +/** + * @param {import("acorn").CallExpression} node + */ +const visitCallExpression = (node) => { + const isDefinedExperimentalCall = + // is `defined(arg)` call + node.callee.type === 'Identifier' && node.callee.name === 'defined' && node.arguments.length == 1 + // and that arg is `NAPI_EXPERIMENTAL` + && node.arguments[0].type === 'Identifier' && node.arguments[0].name === 'NAPI_EXPERIMENTAL'; + + if (isDefinedExperimentalCall) { + return false; + } +}; + +module.exports = { + evaluate +}; diff --git a/third_party/node-api-headers/package.json b/third_party/node-api-headers/package.json new file mode 100644 index 0000000000..017260b182 --- /dev/null +++ b/third_party/node-api-headers/package.json @@ -0,0 +1,59 @@ +{ + "bugs": { + "url": "https://github.com/nodejs/node-api-headers/issues" + }, + "contributors": [ + { + "name": "Gabriel Schulhof", + "url": "https://github.com/gabrielschulhof" + }, + { + "name": "Jim Schlight", + "url": "https://github.com/jschlight" + }, + { + "name": "Kevin Eady", + "url": "https://github.com/KevinEady" + }, + { + "name": "legendecas", + "url": "https://github.com/legendecas" + }, + { + "name": "Leonid Pospelov", + "url": "https://github.com/Pospelove" + }, + { + "name": "Michael Dawson", + "url": "https://github.com/mhdawson" + }, + { + "name": "Nicola Del Gobbo", + "url": "https://github.com/NickNaso" + } + ], + "description": "Node-API headers", + "devDependencies": { + "acorn": "^8.12.1" + }, + "directories": {}, + "gypfile": false, + "homepage": "https://github.com/nodejs/node-api-headers", + "keywords": [], + "license": "MIT", + "main": "index.js", + "name": "node-api-headers", + "readme": "README.md", + "repository": { + "type": "git", + "url": "git://github.com/nodejs/node-api-headers.git" + }, + "scripts": { + "update-headers": "node --no-warnings scripts/update-headers.js", + "write-symbols": "node --no-warnings scripts/write-symbols.js", + "write-win32-def": "node --no-warnings scripts/write-win32-def.js", + "test": "node test/parse-utils.js " + }, + "version": "1.4.0", + "support": true +} diff --git a/third_party/node-api-headers/release-please-config.json b/third_party/node-api-headers/release-please-config.json new file mode 100644 index 0000000000..77c36456c4 --- /dev/null +++ b/third_party/node-api-headers/release-please-config.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "release-type": "node", + "pull-request-title-pattern": "chore: release v${version}", + "bootstrap-sha": "9d78c7da25c5f90617600e23d2a8e7a23288f1ae", + "packages": { + ".": { + "include-component-in-tag": false, + "changelog-path": "CHANGELOG.md" + } + } +} diff --git a/third_party/node-api-headers/scripts/update-headers.js b/third_party/node-api-headers/scripts/update-headers.js new file mode 100644 index 0000000000..2683314913 --- /dev/null +++ b/third_party/node-api-headers/scripts/update-headers.js @@ -0,0 +1,240 @@ +'use strict'; + +const { writeFile } = require('fs/promises'); +const { Readable } = require('stream'); +const { resolve } = require('path'); +const { parseArgs } = require('util') +const { createInterface } = require('readline'); +const { inspect } = require('util'); +const { runClang } = require('../lib/clang-utils'); +const { evaluate } = require('../lib/parse-utils'); + +/** + * @returns {Promise} Version string, eg. `'v19.6.0'`. + */ +async function getLatestReleaseVersion() { + const response = await fetch('https://nodejs.org/download/release/index.json'); + const json = await response.json(); + return json[0].version; +} + +/** + * @param {NodeJS.ReadableStream} stream + * @param {string} destination + * @param {boolean} verbose + * @returns {Promise} The `writeFile` Promise. + */ +function removeExperimentals(stream, destination, verbose = false) { + return new Promise((resolve, reject) => { + const debug = (...args) => { + if (verbose) { + console.log(...args); + } + }; + const rl = createInterface(stream); + + /** @type {Array<'write' | 'ignore' | 'preprocessor'>} */ + const mode = ['write']; + + /** @type {Array} */ + const preprocessor = []; + + /** @type {Array} */ + const macroStack = []; + + /** @type {RegExpMatchArray | null} */ + let matches; + + let lineNumber = 0; + let toWrite = ''; + + const handlePreprocessor = (expression) => { + const result = evaluate(expression); + + macroStack.push(expression); + + if (result === false) { + debug(`Line ${lineNumber} Ignored '${expression}'`); + mode.push('ignore'); + return false; + } else { + debug(`Line ${lineNumber} Pushed '${expression}'`); + mode.push('write'); + return true; + } + }; + + rl.on('line', function lineHandler(line) { + ++lineNumber; + if (matches = line.match(/^\s*#if(n)?def\s+([A-Za-z_][A-Za-z0-9_]*)/)) { + const negated = Boolean(matches[1]); + const identifier = matches[2]; + macroStack.push(identifier); + + debug(`Line ${lineNumber} Pushed ${identifier}`); + + if (identifier === 'NAPI_EXPERIMENTAL') { + if (negated) { + mode.push('write'); + } else { + mode.push('ignore'); + } + return; + } else { + mode.push('write'); + } + } + else if (matches = line.match(/^\s*#if\s+(.+)$/)) { + const expression = matches[1]; + if (expression.endsWith('\\')) { + if (preprocessor.length) { + reject(new Error(`Unexpected preprocessor continuation on line ${lineNumber}`)); + return; + } + preprocessor.push(expression.substring(0, expression.length - 1)); + + mode.push('preprocessor'); + return; + } else { + if (!handlePreprocessor(expression)) { + return; + } + } + } + else if (line.match(/^#else(?:\s+|$)/)) { + const identifier = macroStack[macroStack.length - 1]; + + debug(`Line ${lineNumber} Peeked ${identifier}`); + + if (!identifier) { + rl.off('line', lineHandler); + reject(new Error(`Macro stack is empty handling #else on line ${lineNumber}`)); + return; + } + + if (identifier.indexOf('NAPI_EXPERIMENTAL') > -1) { + const lastMode = mode[mode.length - 1]; + mode[mode.length - 1] = (lastMode === 'ignore') ? 'write' : 'ignore'; + return; + } + } + else if (line.match(/^\s*#endif(?:\s+|$)/)) { + const identifier = macroStack.pop(); + mode.pop(); + + debug(`Line ${lineNumber} Popped ${identifier}`); + + if (!identifier) { + rl.off('line', lineHandler); + reject(new Error(`Macro stack is empty handling #endif on line ${lineNumber}`)); + return; + } + + if (identifier.indexOf('NAPI_EXPERIMENTAL') > -1) { + return; + } + } + + if (mode.length === 0) { + rl.off('line', lineHandler); + reject(new Error(`Write mode empty handling #endif on line ${lineNumber}`)); + return; + } + + if (mode[mode.length - 1] === 'write') { + toWrite += `${line}\n`; + } else if (mode[mode.length - 1] === 'preprocessor') { + if (!preprocessor) { + reject(new Error(`Preprocessor mode without preprocessor on line ${lineNumber}`)); + return; + } + + if (line.endsWith('\\')) { + preprocessor.push(line.substring(0, line.length - 1)); + return; + } + + preprocessor.push(line); + + const expression = preprocessor.join(''); + preprocessor.length = 0; + mode.pop(); + + if (!handlePreprocessor(expression)) { + return; + } + } + + }); + + rl.on('close', () => { + if (macroStack.length > 0) { + reject(new Error(`Macro stack is not empty at EOF: ${inspect(macroStack)}`)); + } + else if (mode.length > 1) { + reject(new Error(`Write mode greater than 1 at EOF: ${inspect(mode)}`)); + } + else if (toWrite.match(/^\s*#if(?:n)?def\s+NAPI_EXPERIMENTAL/m)) { + reject(new Error(`Output has match for NAPI_EXPERIMENTAL`)); + } + else { + resolve(writeFile(destination, toWrite)); + } + }); + }); +} + +/** + * Validate syntax for a file using clang. + * @param {string} path Path for file to validate with clang. + */ +async function validateSyntax(path) { + try { + await runClang(['-fsyntax-only', path]); + } catch (e) { + throw new Error(`Syntax validation failed for ${path}: ${e}`); + } +} + +async function main() { + const { values: { tag, verbose } } = parseArgs({ + options: { + tag: { + type: 'string', + short: 't', + default: await getLatestReleaseVersion() + }, + verbose: { + type: 'boolean', + short: 'v', + }, + }, + }); + + console.log(`feat: update headers from nodejs/node tag ${tag}`); + + const files = ['js_native_api_types.h', 'js_native_api.h', 'node_api_types.h', 'node_api.h']; + + for (const filename of files) { + const url = `https://raw.githubusercontent.com/nodejs/node/${tag}/src/${filename}`; + const path = resolve(__dirname, '..', 'include', filename); + + if (verbose) { + console.log(` ${url} -> ${path}`); + } + + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Fetch of ${url} returned ${response.status} ${response.statusText}`); + } + + await removeExperimentals(Readable.fromWeb(response.body), path, verbose); + + await validateSyntax(path); + } +} + +main().catch(e => { + console.error(e); + process.exitCode = 1; +}); diff --git a/third_party/node-api-headers/scripts/write-symbols.js b/third_party/node-api-headers/scripts/write-symbols.js new file mode 100644 index 0000000000..e45d7df293 --- /dev/null +++ b/third_party/node-api-headers/scripts/write-symbols.js @@ -0,0 +1,154 @@ +'use strict'; + +const { resolve: resolvePath } = require('path'); +const { writeFile } = require('fs/promises'); +const { runClang } = require('../lib/clang-utils'); + +/** @typedef {{ js_native_api_symbols: string[]; node_api_symbols: string[]; }} SymbolInfo */ + +/** + * @param {number} [version] + * @returns {Promise} + */ +async function getSymbolsForVersion(version) { + try { + const { stdout } = await runClang([ '-ast-dump=json', '-fsyntax-only', '-fno-diagnostics-color', `-DNAPI_VERSION=${version}`, resolvePath(__dirname, '..', 'include', 'node_api.h')]) + + const ast = JSON.parse(stdout); + + /** @type {SymbolInfo} */ + const symbols = { js_native_api_symbols: [], node_api_symbols: [] }; + + for (const statement of ast.inner) { + if (statement.kind !== 'FunctionDecl') { + continue; + } + + const name = statement.name; + const file = statement.loc.includedFrom?.file; + + if (file) { + symbols.js_native_api_symbols.push(name); + } else { + symbols.node_api_symbols.push(name); + } + } + + symbols.js_native_api_symbols.sort(); + symbols.node_api_symbols.sort(); + + return symbols; + } catch (err) { + if (err.code === 'ENOENT') { + throw new Error('This tool requires clang to be installed.'); + } + throw err; + } +} + +/** @returns {Promise<{maxVersion: number, symbols: {[x: string]: SymbolInfo}}>} */ +async function getAllSymbols() { + /** @type {{[x: string]: SymbolInfo}} */ + const allSymbols = {}; + let version = 1; + + console.log('Processing symbols from clang:') + while (true) { + const symbols = await getSymbolsForVersion(version); + + if (version > 1) { + const previousSymbols = allSymbols[`v${version - 1}`]; + if (previousSymbols.js_native_api_symbols.length == symbols.js_native_api_symbols.length && previousSymbols.node_api_symbols.length === symbols.node_api_symbols.length) { + --version; + break; + } + } + allSymbols[`v${version}`] = symbols; + console.log(` v${version}: ${symbols.js_native_api_symbols.length} js_native_api_symbols, ${symbols.node_api_symbols.length} node_api_symbols`); + ++version; + } + + return { + maxVersion: version, + symbols: allSymbols + }; +} + +/** + * @param {SymbolInfo} previousSymbols + * @param {SymbolInfo} currentSymbols + * @returns {SymbolInfo} + */ +function getUniqueSymbols(previousSymbols, currentSymbols) { + /** @type {SymbolInfo} */ + const symbols = { js_native_api_symbols: [], node_api_symbols: [] }; + for (const symbol of currentSymbols.js_native_api_symbols) { + if (!previousSymbols.js_native_api_symbols.includes(symbol)) { + symbols.js_native_api_symbols.push(symbol); + } + } + for (const symbol of currentSymbols.node_api_symbols) { + if (!previousSymbols.node_api_symbols.includes(symbol)) { + symbols.node_api_symbols.push(symbol); + } + } + return symbols; +} + +/** + * @param {string[]} strings + */ +function joinStrings(strings, prependNewLine = false) { + if (strings.length === 0) return ''; + return `${prependNewLine ? ',\n ' : ''}'${strings.join("',\n '")}'`; +} + +async function getSymbolData() { + const { maxVersion, symbols } = await getAllSymbols(); + + let data = `'use strict' + +const v1 = { + js_native_api_symbols: [ + ${joinStrings(symbols.v1.js_native_api_symbols)} + ], + node_api_symbols: [ + ${joinStrings(symbols.v1.node_api_symbols)} + ] +} +`; + + for (let version = 2; version <= maxVersion; ++version) { + const newSymbols = getUniqueSymbols(symbols[`v${version - 1}`], symbols[`v${version}`]); + + data += ` +const v${version} = { + js_native_api_symbols: [ + ...v${version - 1}.js_native_api_symbols${joinStrings(newSymbols.js_native_api_symbols, true)} + ], + node_api_symbols: [ + ...v${version - 1}.node_api_symbols${joinStrings(newSymbols.node_api_symbols, true)} + ] +} +`; + } + + data += ` +module.exports = { + ${new Array(maxVersion).fill(undefined).map((_, i) => `v${i + 1}`).join(',\n ')} +} +` + return data; +} + +async function main() { + const path = resolvePath(__dirname, '../symbols.js'); + const data = await getSymbolData(); + console.log(`Writing symbols to ${path}`) + return writeFile(path, data); +} + +main().catch(e => { + console.error(e); + process.exitCode = 1; +}); diff --git a/third_party/node-api-headers/scripts/write-win32-def.js b/third_party/node-api-headers/scripts/write-win32-def.js new file mode 100644 index 0000000000..1333bce397 --- /dev/null +++ b/third_party/node-api-headers/scripts/write-win32-def.js @@ -0,0 +1,52 @@ +'use strict'; + +const { resolve: resolvePath, join: joinPath } = require('path'); +const { writeFile, mkdir } = require('fs/promises'); +const { symbols } = require('..'); + +function getNodeApiDef() { + const symbolsSet = new Set(); + for (const ver of Object.values(symbols)) { + for (const sym of ver.node_api_symbols) { + symbolsSet.add(sym); + } + for (const sym of ver.js_native_api_symbols) { + symbolsSet.add(sym); + } + } + return 'NAME NODE.EXE\nEXPORTS\n' + Array.from(symbolsSet).join('\n'); +} + +function getJsNativeApiDef() { + const symbolsSet = new Set(); + for (const ver of Object.values(symbols)) { + for (const sym of ver.js_native_api_symbols) { + symbolsSet.add(sym); + } + } + return 'NAME NODE.EXE\nEXPORTS\n' + Array.from(symbolsSet).join('\n'); +} + +async function main() { + const def = resolvePath(__dirname, '../def'); + try { + await mkdir(def) + } catch (e) { + if (e.code !== 'EEXIST') { + throw e; + } + } + + const nodeApiDefPath = joinPath(def, 'node_api.def'); + console.log(`Writing Windows .def file to ${nodeApiDefPath}`); + await writeFile(nodeApiDefPath, getNodeApiDef()); + + const jsNativeApiDefPath = joinPath(def, 'js_native_api.def'); + console.log(`Writing Windows .def file to ${jsNativeApiDefPath}`); + await writeFile(jsNativeApiDefPath, getJsNativeApiDef()); +} + +main().catch(e => { + console.error(e); + process.exitCode = 1; +}); diff --git a/third_party/node-api-headers/symbols.js b/third_party/node-api-headers/symbols.js new file mode 100644 index 0000000000..855526ad5b --- /dev/null +++ b/third_party/node-api-headers/symbols.js @@ -0,0 +1,241 @@ +'use strict' + +const v1 = { + js_native_api_symbols: [ + 'napi_adjust_external_memory', + 'napi_call_function', + 'napi_close_escapable_handle_scope', + 'napi_close_handle_scope', + 'napi_coerce_to_bool', + 'napi_coerce_to_number', + 'napi_coerce_to_object', + 'napi_coerce_to_string', + 'napi_create_array', + 'napi_create_array_with_length', + 'napi_create_arraybuffer', + 'napi_create_dataview', + 'napi_create_double', + 'napi_create_error', + 'napi_create_external', + 'napi_create_external_arraybuffer', + 'napi_create_function', + 'napi_create_int32', + 'napi_create_int64', + 'napi_create_object', + 'napi_create_promise', + 'napi_create_range_error', + 'napi_create_reference', + 'napi_create_string_latin1', + 'napi_create_string_utf16', + 'napi_create_string_utf8', + 'napi_create_symbol', + 'napi_create_type_error', + 'napi_create_typedarray', + 'napi_create_uint32', + 'napi_define_class', + 'napi_define_properties', + 'napi_delete_element', + 'napi_delete_property', + 'napi_delete_reference', + 'napi_escape_handle', + 'napi_get_and_clear_last_exception', + 'napi_get_array_length', + 'napi_get_arraybuffer_info', + 'napi_get_boolean', + 'napi_get_cb_info', + 'napi_get_dataview_info', + 'napi_get_element', + 'napi_get_global', + 'napi_get_last_error_info', + 'napi_get_named_property', + 'napi_get_new_target', + 'napi_get_null', + 'napi_get_property', + 'napi_get_property_names', + 'napi_get_prototype', + 'napi_get_reference_value', + 'napi_get_typedarray_info', + 'napi_get_undefined', + 'napi_get_value_bool', + 'napi_get_value_double', + 'napi_get_value_external', + 'napi_get_value_int32', + 'napi_get_value_int64', + 'napi_get_value_string_latin1', + 'napi_get_value_string_utf16', + 'napi_get_value_string_utf8', + 'napi_get_value_uint32', + 'napi_get_version', + 'napi_has_element', + 'napi_has_named_property', + 'napi_has_own_property', + 'napi_has_property', + 'napi_instanceof', + 'napi_is_array', + 'napi_is_arraybuffer', + 'napi_is_dataview', + 'napi_is_error', + 'napi_is_exception_pending', + 'napi_is_promise', + 'napi_is_typedarray', + 'napi_new_instance', + 'napi_open_escapable_handle_scope', + 'napi_open_handle_scope', + 'napi_reference_ref', + 'napi_reference_unref', + 'napi_reject_deferred', + 'napi_remove_wrap', + 'napi_resolve_deferred', + 'napi_run_script', + 'napi_set_element', + 'napi_set_named_property', + 'napi_set_property', + 'napi_strict_equals', + 'napi_throw', + 'napi_throw_error', + 'napi_throw_range_error', + 'napi_throw_type_error', + 'napi_typeof', + 'napi_unwrap', + 'napi_wrap' + ], + node_api_symbols: [ + 'napi_async_destroy', + 'napi_async_init', + 'napi_cancel_async_work', + 'napi_create_async_work', + 'napi_create_buffer', + 'napi_create_buffer_copy', + 'napi_create_external_buffer', + 'napi_delete_async_work', + 'napi_fatal_error', + 'napi_get_buffer_info', + 'napi_get_node_version', + 'napi_is_buffer', + 'napi_make_callback', + 'napi_module_register', + 'napi_queue_async_work' + ] +} + +const v2 = { + js_native_api_symbols: [ + ...v1.js_native_api_symbols + ], + node_api_symbols: [ + ...v1.node_api_symbols, + 'napi_get_uv_event_loop' + ] +} + +const v3 = { + js_native_api_symbols: [ + ...v2.js_native_api_symbols + ], + node_api_symbols: [ + ...v2.node_api_symbols, + 'napi_add_env_cleanup_hook', + 'napi_close_callback_scope', + 'napi_fatal_exception', + 'napi_open_callback_scope', + 'napi_remove_env_cleanup_hook' + ] +} + +const v4 = { + js_native_api_symbols: [ + ...v3.js_native_api_symbols + ], + node_api_symbols: [ + ...v3.node_api_symbols, + 'napi_acquire_threadsafe_function', + 'napi_call_threadsafe_function', + 'napi_create_threadsafe_function', + 'napi_get_threadsafe_function_context', + 'napi_ref_threadsafe_function', + 'napi_release_threadsafe_function', + 'napi_unref_threadsafe_function' + ] +} + +const v5 = { + js_native_api_symbols: [ + ...v4.js_native_api_symbols, + 'napi_add_finalizer', + 'napi_create_date', + 'napi_get_date_value', + 'napi_is_date' + ], + node_api_symbols: [ + ...v4.node_api_symbols + ] +} + +const v6 = { + js_native_api_symbols: [ + ...v5.js_native_api_symbols, + 'napi_create_bigint_int64', + 'napi_create_bigint_uint64', + 'napi_create_bigint_words', + 'napi_get_all_property_names', + 'napi_get_instance_data', + 'napi_get_value_bigint_int64', + 'napi_get_value_bigint_uint64', + 'napi_get_value_bigint_words', + 'napi_set_instance_data' + ], + node_api_symbols: [ + ...v5.node_api_symbols + ] +} + +const v7 = { + js_native_api_symbols: [ + ...v6.js_native_api_symbols, + 'napi_detach_arraybuffer', + 'napi_is_detached_arraybuffer' + ], + node_api_symbols: [ + ...v6.node_api_symbols + ] +} + +const v8 = { + js_native_api_symbols: [ + ...v7.js_native_api_symbols, + 'napi_check_object_type_tag', + 'napi_object_freeze', + 'napi_object_seal', + 'napi_type_tag_object' + ], + node_api_symbols: [ + ...v7.node_api_symbols, + 'napi_add_async_cleanup_hook', + 'napi_remove_async_cleanup_hook' + ] +} + +const v9 = { + js_native_api_symbols: [ + ...v8.js_native_api_symbols, + 'node_api_create_syntax_error', + 'node_api_symbol_for', + 'node_api_throw_syntax_error' + ], + node_api_symbols: [ + ...v8.node_api_symbols, + 'node_api_get_module_file_name' + ] +} + +module.exports = { + v1, + v2, + v3, + v4, + v5, + v6, + v7, + v8, + v9 +} diff --git a/third_party/node-api-headers/test/parse-utils.js b/third_party/node-api-headers/test/parse-utils.js new file mode 100644 index 0000000000..e11b57f959 --- /dev/null +++ b/third_party/node-api-headers/test/parse-utils.js @@ -0,0 +1,21 @@ +const test = require('node:test'); +const assert = require('node:assert'); +const { evaluate } = require("../lib/parse-utils"); + +/** @type {Array<[string, boolean | undefined]>} */ +const testCases = [ + [`defined(NAPI_EXPERIMENTAL)`, false], + [`!defined(NAPI_EXPERIMENTAL)`, true], + [`defined(NAPI_EXPERIMENTAL) || defined(NODE_API_EXPERIMENTAL_NOGC_ENV_OPT_OUT)`, undefined], + [`defined(NAPI_EXPERIMENTAL) && defined(NODE_API_EXPERIMENTAL_NOGC_ENV_OPT_OUT)`, false], + [`!defined(NAPI_EXPERIMENTAL) || (defined(NAPI_EXPERIMENTAL) && (defined(NODE_API_EXPERIMENTAL_NOGC_ENV_OPT_OUT) || defined(NODE_API_EXPERIMENTAL_BASIC_ENV_OPT_OUT)))`, true], + [`NAPI_VERSION >= 9`, undefined], + [`!defined __cplusplus || (defined(_MSC_VER) && _MSC_VER < 1900)`, undefined], // parser error on `defined __cplusplus` +]; + +for (const [text, expected] of testCases) { + test(`${text} -> ${expected}`, (t) => { + const result = evaluate(text); + assert.strictEqual(result, expected); + }); +}