@ 260528.1 · fetching

231103.1 · 7f4a9ed91bbecb84e39f4bc8030247ce5116ddf8

Reorganize examples into categorized folders (#341)

* refactor: create directory structure to organize exmaples
* test: update test_all to work with new directory structure
* fix: bug in test_all if no package.json scripts
* test: cleanup output of test_all
* fix: remove default test script that throws from thread_safe_function_with_object_wrap
* fix: remove build_with_cmake from .gitignore
* fix: swith to ' from " and remove subdir from getAllTests call
* test: add extra test cases for npm start and just running the pkgJson.main with node
* refactor: move all examples to src directory
* refactor: add numbers to categories so they are ordered in the src folder
* refactor: simplify getAllExamples in test_all.js
* docs: add directory structure to README.md
* docs: update directory structure to README.md
* docs: update directory structure to README.md
* docs: update directory structure to README.md
* docs: update directory structure example in readme
* add back build_with_cmake --------- Co-authored-by: legendecas <legendecas@gmail.com>

reading declarations

Changes to src/2-js-to-native-conversion/object-template-demo/napi/. All files

src/2-js-to-native-conversion/object-template-demo/napi/binding.gyp

new file mode 100644@@ -0,0 +1,8 @@+{+  "targets": [+    {+      "target_name": "object_template_demo",+      "sources": [ "object-template-demo.cc", "proxy-template.cc" ]+    }+  ]+}

src/2-js-to-native-conversion/object-template-demo/napi/index.js

new file mode 100644@@ -0,0 +1,10 @@+const addon = require('bindings')('object_template_demo');++const interceptor = addon.create();+console.log(interceptor.prop); // 'foo'+interceptor.prop = 'setting a value';+console.log(interceptor.prop); // 'setting a value'+delete interceptor.something;+console.log(interceptor.prop); // 'goober';+console.log(Object.prototype.hasOwnProperty.call(interceptor, "thing")); // true+console.log(Object.keys(interceptor)[0]); // 'value'

src/2-js-to-native-conversion/object-template-demo/napi/node-api-common.h

new file mode 100644@@ -0,0 +1,141 @@+#include <node_api.h>+#include <initializer_list>+#include <utility>++// Empty value so that macros here are able to return NULL or void+#define NODE_API_RETVAL_NOTHING  // Intentionally blank #define++#define GET_AND_THROW_LAST_ERROR(env)                                          \+  do {                                                                         \+    const napi_extended_error_info* error_info;                                \+    napi_get_last_error_info((env), &error_info);                              \+    bool is_pending;                                                           \+    const char* err_message = error_info->error_message;                       \+    napi_is_exception_pending((env), &is_pending);                             \+    /* If an exception is already pending, don't rethrow it */                 \+    if (!is_pending) {                                                         \+      const char* error_message =                                              \+          err_message != NULL ? err_message : "empty error message";           \+      napi_throw_error((env), NULL, error_message);                            \+    }                                                                          \+  } while (0)++#define NODE_API_ASSERT_BASE(env, assertion, message, ret_val)                 \+  do {                                                                         \+    if (!(assertion)) {                                                        \+      napi_throw_error(                                                        \+          (env), NULL, "assertion (" #assertion ") failed: " message);         \+      return ret_val;                                                          \+    }                                                                          \+  } while (0)++// Returns NULL on failed assertion.+// This is meant to be used inside napi_callback methods.+#define NODE_API_ASSERT(env, assertion, message)                               \+  NODE_API_ASSERT_BASE(env, assertion, message, NULL)++#define NODE_API_CALL_BASE(env, the_call, ret_val)                             \+  do {                                                                         \+    if ((the_call) != napi_ok) {                                               \+      GET_AND_THROW_LAST_ERROR((env));                                         \+      return ret_val;                                                          \+    }                                                                          \+  } while (0)++// Returns NULL if the_call doesn't return napi_ok.+#define NODE_API_CALL(env, the_call) NODE_API_CALL_BASE(env, the_call, NULL)++// Returns empty if the_call doesn't return napi_ok.+#define NODE_API_CALL_RETURN_VOID(env, the_call)                               \+  NODE_API_CALL_BASE(env, the_call, NODE_API_RETVAL_NOTHING)++#define CHECK_NAPI(...)                                                        \+  do {                                                                         \+    napi_status res__ = (__VA_ARGS__);                                         \+    if (res__ != napi_ok) {                                                    \+      return res__;                                                            \+    }                                                                          \+  } while (0)++#define NAPI_CALL(expr) NODE_API_CALL(env, expr);++#ifdef __cpp_lib_span+#include <span>+using std::span;+#else+/**+ * @brief A span of values that can be used to pass arguments to function.+ *+ * For C++20 we should consider to replace it with std::span.+ */+template <typename T>+struct span {+  constexpr span(std::initializer_list<T> il) noexcept+      : data_{const_cast<T*>(il.begin())}, size_{il.size()} {}+  constexpr span(T* data, size_t size) noexcept : data_{data}, size_{size} {}+  [[nodiscard]] constexpr T* data() const noexcept { return data_; }+  [[nodiscard]] constexpr size_t size() const noexcept { return size_; }+  [[nodiscard]] constexpr T* begin() const noexcept { return data_; }+  [[nodiscard]] constexpr T* end() const noexcept { return data_ + size_; }+  const T& operator[](size_t index) const noexcept { return *(data_ + index); }++ private:+  T* data_;+  size_t size_;+};+#endif  // __cpp_lib_span++struct RefHolder {+  RefHolder(std::nullptr_t = nullptr) noexcept {}+  explicit RefHolder(napi_env env, napi_value value) : env_(env) {+    // Start with 2 to avoid ever going to 0 that creates a weak ref.+    napi_create_reference(env, value, 2, &ref_);+  }++  // The class is movable.+  RefHolder(RefHolder&& other) noexcept+      : env_(std::exchange(other.env_, nullptr)),+        ref_(std::exchange(other.ref_, nullptr)) {}++  RefHolder& operator=(RefHolder&& other) noexcept {+    if (this != &other) {+      swap(*this, other);+      RefHolder temp(std::move(other));+    }+    return *this;+  }++  // The class is not copyable.+  RefHolder(const RefHolder& other) = delete;+  RefHolder& operator=(const RefHolder& other) = delete;++  ~RefHolder() noexcept {+    if (env_ != nullptr && ref_ != nullptr) {+      uint32_t refCount{};+      napi_reference_unref(env_, ref_, &refCount);+      if (refCount == 1) {+        napi_delete_reference(env_, ref_);+      }+    }+  }++  operator napi_value() const {+    napi_value result{};+    if (ref_ != nullptr) {+      napi_get_reference_value(env_, ref_, &result);+    }+    return result;+  }++  explicit operator bool() const noexcept { return ref_ != nullptr; }++  friend void swap(RefHolder& left, RefHolder& right) noexcept {+    using std::swap;+    swap(left.env_, right.env_);+    swap(left.ref_, right.ref_);+  }++ private:+  napi_env env_{};+  napi_ref ref_{};+};

src/2-js-to-native-conversion/object-template-demo/napi/object-template-demo.cc

new file mode 100644@@ -0,0 +1,306 @@+#include <cstring>+#include <memory>+#include <string>+#include "proxy-template.h"++struct InstanceData {+  RefHolder constructor_;+  std::unique_ptr<ProxyTemplate> proxyTemplate_;+};++class NamedInterceptor {+  char buf[256];++ public:+  NamedInterceptor() { std::strncpy(this->buf, "foo", sizeof(this->buf)); }+  static napi_value Init(napi_env env, napi_value exports);+  static napi_value Constructor(napi_env env);+  static napi_value NewInstance(napi_env env);+  static napi_value New(napi_env env, napi_callback_info info);+  static napi_value CreateNew(napi_env env, napi_callback_info info);++  static napi_status ToUtf8String(napi_env env,+                                  napi_value value,+                                  std::string* result);+  static napi_status PropertyGetter(napi_env env,+                                    napi_value target,+                                    napi_value key,+                                    napi_value receiver,+                                    napi_value* result);+  static napi_status PropertySetter(napi_env env,+                                    napi_value target,+                                    napi_value key,+                                    napi_value value,+                                    napi_value receiver,+                                    bool* result);+  static napi_status PropertyDeleter(napi_env env,+                                     napi_value target,+                                     napi_value key,+                                     bool* result);+  static napi_status PropertyQuery(napi_env env,+                                   napi_value target,+                                   napi_value key,+                                   bool* result);+  static napi_status GetOwnPropertyDescriptor(napi_env env,+                                              napi_value target,+                                              napi_value key,+                                              napi_value* result);+  static napi_status OwnKeys(napi_env env,+                             napi_value target,+                             napi_value* result);+};++napi_value NamedInterceptor::CreateNew(napi_env env, napi_callback_info info) {+  return NamedInterceptor::NewInstance(env);+}++napi_value NamedInterceptor::Init(napi_env env, napi_value exports) {+  napi_value constructor{};+  NAPI_CALL(napi_define_class(env,+                              "NamedInterceptor",+                              NAPI_AUTO_LENGTH,+                              NamedInterceptor::New,+                              nullptr,+                              0,+                              nullptr,+                              &constructor));++  ProxyHandlerBuilder handlerBuilder{};+  NAPI_CALL(handlerBuilder.Get(env, &PropertyGetter));+  NAPI_CALL(handlerBuilder.Set(env, &PropertySetter));+  NAPI_CALL(handlerBuilder.DeleteProperty(env, &PropertyDeleter));+  NAPI_CALL(handlerBuilder.Has(env, &PropertyQuery));+  NAPI_CALL(+      handlerBuilder.GetOwnPropertyDescriptor(env, &GetOwnPropertyDescriptor));+  NAPI_CALL(handlerBuilder.OwnKeys(env, &OwnKeys));+  napi_value proxyHandler{};+  NAPI_CALL(handlerBuilder.NewHandler(env, &proxyHandler));+  NAPI_CALL(napi_set_instance_data(+      env,+      new InstanceData{RefHolder(env, constructor),+                       std::make_unique<ProxyTemplate>(env, proxyHandler)},+      [](napi_env /*env*/, void* data, void* /*hint*/) {+        delete static_cast<InstanceData*>(data);+      },+      nullptr));++  napi_value createFunc{};+  NAPI_CALL(napi_create_function(+      env, "create", NAPI_AUTO_LENGTH, CreateNew, nullptr, &createFunc));++  NAPI_CALL(napi_set_named_property(env, exports, "create", createFunc));+  return exports;+}++napi_value NamedInterceptor::Constructor(napi_env env) {+  InstanceData* instanceData{};+  NAPI_CALL(+      napi_get_instance_data(env, reinterpret_cast<void**>(&instanceData)));+  return instanceData->constructor_;+}++napi_value NamedInterceptor::NewInstance(napi_env env) {+  napi_escapable_handle_scope scope{};+  NAPI_CALL(napi_open_escapable_handle_scope(env, &scope));++  napi_value instance{};+  NAPI_CALL(napi_new_instance(env, Constructor(env), 0, nullptr, &instance));++  napi_value result{};+  NAPI_CALL(napi_escape_handle(env, scope, instance, &result));+  NAPI_CALL(napi_close_escapable_handle_scope(env, scope));+  return result;+}++napi_value NamedInterceptor::New(napi_env env, napi_callback_info info) {+  napi_value newTarget{};+  NAPI_CALL(napi_get_new_target(env, info, &newTarget));+  NODE_API_ASSERT_BASE(+      env, newTarget != nullptr, "Must be invoked as a constructor.", nullptr);++  napi_value proxyTarget{}, result{};+  NAPI_CALL(napi_create_function(+      env,+      "target",+      NAPI_AUTO_LENGTH,+      [](napi_env, napi_callback_info) -> napi_value { return nullptr; },+      nullptr,+      &proxyTarget));++  NamedInterceptor* obj = new NamedInterceptor();++  NAPI_CALL(napi_wrap(+      env,+      proxyTarget,+      obj,+      [](napi_env /*env*/, void* data, void* /*hint*/) {+        delete reinterpret_cast<NamedInterceptor*>(data);+      },+      nullptr,+      nullptr));++  InstanceData* instanceData{};+  NAPI_CALL(+      napi_get_instance_data(env, reinterpret_cast<void**>(&instanceData)));+  NAPI_CALL(+      instanceData->proxyTemplate_->NewInstance(env, proxyTarget, &result));+  return result;+}++napi_status NamedInterceptor::ToUtf8String(napi_env env,+                                           napi_value value,+                                           std::string* result) {+  size_t size{};+  CHECK_NAPI(napi_get_value_string_utf8(env, value, nullptr, 0, &size));+  result->assign(size, ' ');+  return napi_get_value_string_utf8(+      env, value, &(*result)[0], size + 1, nullptr);+}++napi_status NamedInterceptor::PropertyGetter(napi_env env,+                                             napi_value target,+                                             napi_value key,+                                             napi_value receiver,+                                             napi_value* result) {+  NamedInterceptor* interceptor{};+  CHECK_NAPI(napi_unwrap(env, target, reinterpret_cast<void**>(&interceptor)));+  std::string keyStr;+  CHECK_NAPI(ToUtf8String(env, key, &keyStr));+  if (keyStr == "prop") {+    return napi_create_string_utf8(+        env, interceptor->buf, NAPI_AUTO_LENGTH, result);+  } else {+    return napi_create_string_utf8(env, "bar", NAPI_AUTO_LENGTH, result);+  }+}++napi_status NamedInterceptor::PropertySetter(napi_env env,+                                             napi_value target,+                                             napi_value key,+                                             napi_value value,+                                             napi_value receiver,+                                             bool* result) {+  NamedInterceptor* interceptor{};+  CHECK_NAPI(napi_unwrap(env, target, reinterpret_cast<void**>(&interceptor)));+  std::string keyStr;+  CHECK_NAPI(ToUtf8String(env, key, &keyStr));+  if (keyStr == "prop") {+    std::string valueStr;+    CHECK_NAPI(ToUtf8String(env, value, &valueStr));+    std::strncpy(interceptor->buf, valueStr.data(), sizeof(interceptor->buf));+    *result = true;+  } else {+    *result = false;+  }+  return napi_ok;+}++napi_status NamedInterceptor::PropertyDeleter(napi_env env,+                                              napi_value target,+                                              napi_value key,+                                              bool* result) {+  NamedInterceptor* interceptor{};+  CHECK_NAPI(napi_unwrap(env, target, reinterpret_cast<void**>(&interceptor)));+  std::strncpy(interceptor->buf, "goober", sizeof(interceptor->buf));+  *result = true;+  return napi_ok;+}++napi_status NamedInterceptor::PropertyQuery(napi_env env,+                                            napi_value target,+                                            napi_value key,+                                            bool* result) {+  std::string keyStr;+  CHECK_NAPI(ToUtf8String(env, key, &keyStr));++  if (keyStr == "thing") {+    *result = true;+  }+  if (keyStr == "value") {+    *result = true;+  }+  return napi_ok;+}++napi_status NamedInterceptor::GetOwnPropertyDescriptor(napi_env env,+                                                       napi_value target,+                                                       napi_value key,+                                                       napi_value* result) {+  std::string keyStr;+  CHECK_NAPI(ToUtf8String(env, key, &keyStr));++  if (keyStr == "thing") {+    CHECK_NAPI(napi_create_object(env, result));+    napi_value trueValue{};+    CHECK_NAPI(napi_get_boolean(env, true, &trueValue));+    CHECK_NAPI(+        napi_set_named_property(env, *result, "configurable", trueValue));+    CHECK_NAPI(napi_set_named_property(env, *result, "writable", trueValue));+  }+  if (keyStr == "value") {+    CHECK_NAPI(napi_create_object(env, result));+    napi_value trueValue{};+    CHECK_NAPI(napi_get_boolean(env, true, &trueValue));+    CHECK_NAPI(+        napi_set_named_property(env, *result, "configurable", trueValue));+    CHECK_NAPI(napi_set_named_property(env, *result, "writable", trueValue));+    CHECK_NAPI(napi_set_named_property(env, *result, "enumerable", trueValue));+  }+  if (keyStr == "arguments" || keyStr == "caller") {+    CHECK_NAPI(napi_create_object(env, result));+    napi_value trueValue{}, falseValue{};+    CHECK_NAPI(napi_get_boolean(env, false, &falseValue));+    CHECK_NAPI(napi_get_boolean(env, false, &trueValue));+    CHECK_NAPI(+        napi_set_named_property(env, *result, "configurable", falseValue));+    CHECK_NAPI(napi_set_named_property(env, *result, "writable", falseValue));+    CHECK_NAPI(napi_set_named_property(env, *result, "enumerable", falseValue));+    napi_value nullValue{};+    CHECK_NAPI(napi_get_null(env, &nullValue));+    CHECK_NAPI(napi_set_named_property(env, *result, "value", nullValue));+  }+  if (keyStr == "prototype") {+    CHECK_NAPI(napi_create_object(env, result));+    napi_value trueValue{}, falseValue{};+    CHECK_NAPI(napi_get_boolean(env, false, &falseValue));+    CHECK_NAPI(napi_get_boolean(env, true, &trueValue));+    CHECK_NAPI(+        napi_set_named_property(env, *result, "configurable", falseValue));+    CHECK_NAPI(napi_set_named_property(env, *result, "writable", trueValue));+    CHECK_NAPI(napi_set_named_property(env, *result, "enumerable", falseValue));+    napi_value nullValue{};+    CHECK_NAPI(napi_get_null(env, &nullValue));+    CHECK_NAPI(napi_set_named_property(env, *result, "value", nullValue));+  }+  return napi_ok;+}++napi_status NamedInterceptor::OwnKeys(napi_env env,+                                      napi_value target,+                                      napi_value* result) {+  CHECK_NAPI(napi_get_all_property_names(env,+                                         target,+                                         napi_key_own_only,+                                         napi_key_all_properties,+                                         napi_key_keep_numbers,+                                         result));++  uint32_t arraySize{};+  CHECK_NAPI(napi_get_array_length(env, *result, &arraySize));+  napi_value firstElement{};+  CHECK_NAPI(napi_get_element(env, *result, 0, &firstElement));+  CHECK_NAPI(napi_set_element(env, *result, arraySize, firstElement));+  napi_value arraySizeValue{};+  CHECK_NAPI(napi_create_uint32(env, arraySize, &arraySizeValue));+  CHECK_NAPI(napi_set_named_property(env, *result, "length", arraySizeValue));+  napi_value value{};+  CHECK_NAPI(napi_create_string_utf8(env, "value", NAPI_AUTO_LENGTH, &value));+  CHECK_NAPI(napi_set_element(env, *result, 0, value));+  return napi_ok;+}++extern "C" napi_value Init(napi_env env, napi_value exports) {+  return NamedInterceptor::Init(env, exports);+}++NAPI_MODULE(NODE_GYP_MODULE_NAME, Init);

src/2-js-to-native-conversion/object-template-demo/napi/package.json

new file mode 100644@@ -0,0 +1,14 @@+{+  "name": "object_template_demo",+  "version": "0.0.0",+  "description": "Intercept named property access using Proxy",+  "main": "index.js",+  "private": true,+  "gypfile": true,+  "scripts": {+    "test": "node index.js"+  },+  "dependencies": {+    "bindings": "~1.5.0"+  }+}

src/2-js-to-native-conversion/object-template-demo/napi/proxy-template.cc

new file mode 100644@@ -0,0 +1,726 @@+#include "proxy-template.h"+#include <vector>++namespace {++static napi_status SetTrap(napi_env env,+                           napi_value handler,+                           const char* propertyName,+                           napi_value trap) noexcept {+  if (trap != nullptr) {+    CHECK_NAPI(napi_set_named_property(env, handler, propertyName, trap));+  }+  return napi_ok;+}++using TrapCaller = napi_status (*)(napi_env env,+                                   void* trap,+                                   napi_span<napi_value> args,+                                   napi_value* result);++struct TrapCallInfo {+  TrapCaller Caller;+  void* trap;+};++template <size_t argCount>+napi_callback CreateTrapCallback() noexcept {+  return [](napi_env env, napi_callback_info info) noexcept -> napi_value {+    TrapCallInfo* trapCallInfo{};+    napi_value args[argCount]{};+    size_t actualArgCount{argCount};+    NAPI_CALL(napi_get_cb_info(env,+                               info,+                               &actualArgCount,+                               args,+                               nullptr,+                               reinterpret_cast<void**>(&trapCallInfo)));+    NODE_API_ASSERT_BASE(env,+                         actualArgCount == argCount,+                         "proxy trap requires argCount arguments.",+                         nullptr);+    napi_value result{};+    NAPI_CALL(trapCallInfo->Caller(+        env, trapCallInfo->trap, span<napi_value>(args, argCount), &result));+    return result;+  };+}++napi_status ToVector(napi_env env,+                     napi_value arrayValue,+                     std::vector<napi_value>* result) {+  bool isArray{};+  CHECK_NAPI(napi_is_array(env, arrayValue, &isArray));+  if (isArray) {+    uint32_t arraySize{};+    CHECK_NAPI(napi_get_array_length(env, arrayValue, &arraySize));+    result->reserve(result->size() + arraySize);+    for (uint32_t i = 0; i < arraySize; ++i) {+      napi_value arrayElement{};+      CHECK_NAPI(napi_get_element(env, arrayValue, i, &arrayElement));+      result->push_back(arrayElement);+    }+  }+  return napi_ok;+}++}  // namespace++napi_status ProxyHandlerBuilder::NewHandler(napi_env env,+                                            napi_value* result) noexcept {+  CHECK_NAPI(napi_create_object(env, result));++  CHECK_NAPI(SetTrap(env, *result, "apply", apply_));+  CHECK_NAPI(SetTrap(env, *result, "construct", construct_));+  CHECK_NAPI(SetTrap(env, *result, "defineProperty", defineProperty_));+  CHECK_NAPI(SetTrap(env, *result, "deleteProperty", deleteProperty_));+  CHECK_NAPI(SetTrap(env, *result, "get", get_));+  CHECK_NAPI(SetTrap(+      env, *result, "getOwnPropertyDescriptor", getOwnPropertyDescriptor_));+  CHECK_NAPI(SetTrap(env, *result, "getPrototypeOf", getPrototypeOf_));+  CHECK_NAPI(SetTrap(env, *result, "has", has_));+  CHECK_NAPI(SetTrap(env, *result, "isExtensible", isExtensible_));+  CHECK_NAPI(SetTrap(env, *result, "ownKeys", ownKeys_));+  CHECK_NAPI(SetTrap(env, *result, "preventExtensions", preventExtensions_));+  CHECK_NAPI(SetTrap(env, *result, "set", set_));+  CHECK_NAPI(SetTrap(env, *result, "setPrototypeOf", setPrototypeOf_));+  return napi_ok;+}++napi_value ProxyHandlerBuilder::Apply() noexcept {+  return apply_;+}++void ProxyHandlerBuilder::Apply(napi_value trap) noexcept {+  apply_ = trap;+}++napi_status ProxyHandlerBuilder::Apply(napi_env env,+                                       napi_callback trap,+                                       void* data) noexcept {+  return napi_create_function(+      env, "apply", NAPI_AUTO_LENGTH, trap, data, &apply_);+}++napi_status ProxyHandlerBuilder::Apply(+    napi_env env,+    napi_status (*trap)(napi_env env,+                        napi_value target,+                        napi_value thisArg,+                        napi_value argumentList,+                        napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 return reinterpret_cast<TrapType>(trap)(+                                     env, args[0], args[1], args[2], result);+                               },+                               reinterpret_cast<void*>(trap)};+  return Apply(env, CreateTrapCallback<3>(), &callInfo);+}++napi_status ProxyHandlerBuilder::Apply(+    napi_env env,+    napi_status (*trap)(napi_env env,+                        napi_value target,+                        napi_value thisArg,+                        napi_span<napi_value> argumentList,+                        napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{+      [](napi_env env,+         void* trap,+         napi_span<napi_value> args,+         napi_value* result) noexcept {+        std::vector<napi_value> argVector;+        CHECK_NAPI(ToVector(env, args[2], &argVector));+        return reinterpret_cast<TrapType>(trap)(+            env,+            args[0],+            args[1],+            span<napi_value>(argVector.data(), argVector.size()),+            result);+      },+      reinterpret_cast<void*>(trap)};+  return Apply(env, CreateTrapCallback<3>(), &callInfo);+}++napi_value ProxyHandlerBuilder::Construct() noexcept {+  return construct_;+}++void ProxyHandlerBuilder::Construct(napi_value trap) noexcept {+  construct_ = trap;+}++napi_status ProxyHandlerBuilder::Construct(napi_env env,+                                           napi_callback trap,+                                           void* data) noexcept {+  return napi_create_function(+      env, "construct", NAPI_AUTO_LENGTH, trap, data, &construct_);+}++napi_status ProxyHandlerBuilder::Construct(+    napi_env env,+    napi_status (*trap)(napi_env env,+                        napi_value target,+                        napi_value argumentList,+                        napi_value newTarget,+                        napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 return reinterpret_cast<TrapType>(trap)(+                                     env, args[0], args[1], args[2], result);+                               },+                               reinterpret_cast<void*>(trap)};+  return Construct(env, CreateTrapCallback<3>(), &callInfo);+}++napi_status ProxyHandlerBuilder::Construct(+    napi_env env,+    napi_status (*trap)(napi_env env,+                        napi_value target,+                        napi_span<napi_value> argumentList,+                        napi_value newTarget,+                        napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{+      [](napi_env env,+         void* trap,+         napi_span<napi_value> args,+         napi_value* result) noexcept {+        std::vector<napi_value> argVector;+        CHECK_NAPI(ToVector(env, args[1], &argVector));+        return reinterpret_cast<TrapType>(trap)(+            env,+            args[0],+            span<napi_value>(argVector.data(), argVector.size()),+            args[2],+            result);+      },+      reinterpret_cast<void*>(trap)};+  return Construct(env, CreateTrapCallback<3>(), &callInfo);+}++napi_value ProxyHandlerBuilder::DefineProperty() noexcept {+  return defineProperty_;+}++void ProxyHandlerBuilder::DefineProperty(napi_value trap) noexcept {+  defineProperty_ = trap;+}++napi_status ProxyHandlerBuilder::DefineProperty(napi_env env,+                                                napi_callback trap,+                                                void* data) noexcept {+  return napi_create_function(+      env, "defineProperty", NAPI_AUTO_LENGTH, trap, data, &defineProperty_);+}++napi_status ProxyHandlerBuilder::DefineProperty(+    napi_env env,+    napi_status (*trap)(napi_env env,+                        napi_value target,+                        napi_value key,+                        napi_value descriptor,+                        napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 return reinterpret_cast<TrapType>(trap)(+                                     env, args[0], args[1], args[2], result);+                               },+                               reinterpret_cast<void*>(trap)};+  return DefineProperty(env, CreateTrapCallback<3>(), &callInfo);+}++napi_status ProxyHandlerBuilder::DefineProperty(+    napi_env env,+    napi_status (*trap)(napi_env env,+                        napi_value target,+                        napi_value key,+                        napi_value descriptor,+                        bool* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{+      [](napi_env env,+         void* trap,+         napi_span<napi_value> args,+         napi_value* result) noexcept {+        bool boolResult{};+        CHECK_NAPI(reinterpret_cast<TrapType>(trap)(+            env, args[0], args[1], args[2], &boolResult));+        return napi_get_boolean(env, boolResult, result);+      },+      reinterpret_cast<void*>(trap)};+  return DefineProperty(env, CreateTrapCallback<3>(), &callInfo);+}++napi_value ProxyHandlerBuilder::DeleteProperty() noexcept {+  return deleteProperty_;+}++void ProxyHandlerBuilder::DeleteProperty(napi_value trap) noexcept {+  deleteProperty_ = trap;+}++napi_status ProxyHandlerBuilder::DeleteProperty(napi_env env,+                                                napi_callback trap,+                                                void* data) noexcept {+  return napi_create_function(+      env, "deleteProperty", NAPI_AUTO_LENGTH, trap, data, &deleteProperty_);+}++napi_status ProxyHandlerBuilder::DeleteProperty(+    napi_env env,+    napi_status (*trap)(+        napi_env env, napi_value target, napi_value key, napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 return reinterpret_cast<TrapType>(trap)(+                                     env, args[0], args[1], result);+                               },+                               reinterpret_cast<void*>(trap)};+  return DeleteProperty(env, CreateTrapCallback<2>(), &callInfo);+}++napi_status ProxyHandlerBuilder::DeleteProperty(+    napi_env env,+    napi_status (*trap)(+        napi_env env, napi_value target, napi_value key, bool* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 bool boolResult{};+                                 CHECK_NAPI(reinterpret_cast<TrapType>(trap)(+                                     env, args[0], args[1], &boolResult));+                                 return napi_get_boolean(+                                     env, boolResult, result);+                               },+                               reinterpret_cast<void*>(trap)};+  return DeleteProperty(env, CreateTrapCallback<2>(), &callInfo);+}++napi_value ProxyHandlerBuilder::Get() noexcept {+  return get_;+}++void ProxyHandlerBuilder::Get(napi_value trap) noexcept {+  get_ = trap;+}++napi_status ProxyHandlerBuilder::Get(napi_env env,+                                     napi_callback trap,+                                     void* data) noexcept {+  return napi_create_function(env, "get", NAPI_AUTO_LENGTH, trap, data, &get_);+}++napi_status ProxyHandlerBuilder::Get(napi_env env,+                                     napi_status (*trap)(napi_env env,+                                                         napi_value target,+                                                         napi_value key,+                                                         napi_value receiver,+                                                         napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 return reinterpret_cast<TrapType>(trap)(+                                     env, args[0], args[1], args[2], result);+                               },+                               reinterpret_cast<void*>(trap)};+  return Get(env, CreateTrapCallback<3>(), &callInfo);+}++napi_value ProxyHandlerBuilder::GetOwnPropertyDescriptor() noexcept {+  return getOwnPropertyDescriptor_;+}++void ProxyHandlerBuilder::GetOwnPropertyDescriptor(napi_value trap) noexcept {+  getOwnPropertyDescriptor_ = trap;+}++napi_status ProxyHandlerBuilder::GetOwnPropertyDescriptor(napi_env env,+                                                          napi_callback trap,+                                                          void* data) noexcept {+  return napi_create_function(env,+                              "getOwnPropertyDescriptor",+                              NAPI_AUTO_LENGTH,+                              trap,+                              data,+                              &getOwnPropertyDescriptor_);+}++napi_status ProxyHandlerBuilder::GetOwnPropertyDescriptor(+    napi_env env,+    napi_status (*trap)(+        napi_env env, napi_value target, napi_value key, napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 return reinterpret_cast<TrapType>(trap)(+                                     env, args[0], args[1], result);+                               },+                               reinterpret_cast<void*>(trap)};+  return GetOwnPropertyDescriptor(env, CreateTrapCallback<2>(), &callInfo);+}++napi_value ProxyHandlerBuilder::GetPrototypeOf() noexcept {+  return getPrototypeOf_;+}++void ProxyHandlerBuilder::GetPrototypeOf(napi_value trap) noexcept {+  getPrototypeOf_ = trap;+}++napi_status ProxyHandlerBuilder::GetPrototypeOf(napi_env env,+                                                napi_callback trap,+                                                void* data) noexcept {+  return napi_create_function(+      env, "getPrototypeOf", NAPI_AUTO_LENGTH, trap, data, &getPrototypeOf_);+}++napi_status ProxyHandlerBuilder::GetPrototypeOf(+    napi_env env,+    napi_status (*trap)(napi_env env, napi_value target, napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 return reinterpret_cast<TrapType>(trap)(+                                     env, args[0], result);+                               },+                               reinterpret_cast<void*>(trap)};+  return GetPrototypeOf(env, CreateTrapCallback<1>(), &callInfo);+}++napi_value ProxyHandlerBuilder::Has() noexcept {+  return has_;+}++void ProxyHandlerBuilder::Has(napi_value trap) noexcept {+  has_ = trap;+}++napi_status ProxyHandlerBuilder::Has(napi_env env,+                                     napi_callback trap,+                                     void* data) noexcept {+  return napi_create_function(env, "has", NAPI_AUTO_LENGTH, trap, data, &has_);+}++napi_status ProxyHandlerBuilder::Has(napi_env env,+                                     napi_status (*trap)(napi_env env,+                                                         napi_value target,+                                                         napi_value key,+                                                         napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 return reinterpret_cast<TrapType>(trap)(+                                     env, args[0], args[1], result);+                               },+                               reinterpret_cast<void*>(trap)};+  return Has(env, CreateTrapCallback<2>(), &callInfo);+}++napi_status ProxyHandlerBuilder::Has(napi_env env,+                                     napi_status (*trap)(napi_env env,+                                                         napi_value target,+                                                         napi_value key,+                                                         bool* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 bool boolResult{};+                                 CHECK_NAPI(reinterpret_cast<TrapType>(trap)(+                                     env, args[0], args[1], &boolResult));+                                 return napi_get_boolean(+                                     env, boolResult, result);+                               },+                               reinterpret_cast<void*>(trap)};+  return Has(env, CreateTrapCallback<2>(), &callInfo);+}++napi_value ProxyHandlerBuilder::IsExtensible() noexcept {+  return isExtensible_;+}++void ProxyHandlerBuilder::IsExtensible(napi_value trap) noexcept {+  isExtensible_ = trap;+}++napi_status ProxyHandlerBuilder::IsExtensible(napi_env env,+                                              napi_callback trap,+                                              void* data) noexcept {+  return napi_create_function(+      env, "isExtensible", NAPI_AUTO_LENGTH, trap, data, &isExtensible_);+}++napi_status ProxyHandlerBuilder::IsExtensible(+    napi_env env,+    napi_status (*trap)(napi_env env, napi_value target, napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 return reinterpret_cast<TrapType>(trap)(+                                     env, args[0], result);+                               },+                               reinterpret_cast<void*>(trap)};+  return IsExtensible(env, CreateTrapCallback<1>(), &callInfo);+}++napi_status ProxyHandlerBuilder::IsExtensible(+    napi_env env,+    napi_status (*trap)(napi_env env, napi_value target, bool* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{+      [](napi_env env,+         void* trap,+         napi_span<napi_value> args,+         napi_value* result) noexcept {+        bool boolResult{};+        CHECK_NAPI(reinterpret_cast<TrapType>(trap)(env, args[0], &boolResult));+        return napi_get_boolean(env, boolResult, result);+      },+      reinterpret_cast<void*>(trap)};+  return IsExtensible(env, CreateTrapCallback<1>(), &callInfo);+}++napi_value ProxyHandlerBuilder::OwnKeys() noexcept {+  return ownKeys_;+}++void ProxyHandlerBuilder::OwnKeys(napi_value trap) noexcept {+  ownKeys_ = trap;+}++napi_status ProxyHandlerBuilder::OwnKeys(napi_env env,+                                         napi_callback trap,+                                         void* data) noexcept {+  return napi_create_function(+      env, "ownKeys", NAPI_AUTO_LENGTH, trap, data, &ownKeys_);+}++napi_status ProxyHandlerBuilder::OwnKeys(+    napi_env env,+    napi_status (*trap)(napi_env env, napi_value target, napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 return reinterpret_cast<TrapType>(trap)(+                                     env, args[0], result);+                               },+                               reinterpret_cast<void*>(trap)};+  return OwnKeys(env, CreateTrapCallback<1>(), &callInfo);+}++napi_value ProxyHandlerBuilder::PreventExtensions() noexcept {+  return preventExtensions_;+}++void ProxyHandlerBuilder::PreventExtensions(napi_value trap) noexcept {+  preventExtensions_ = trap;+}++napi_status ProxyHandlerBuilder::PreventExtensions(napi_env env,+                                                   napi_callback trap,+                                                   void* data) noexcept {+  return napi_create_function(env,+                              "preventExtensions",+                              NAPI_AUTO_LENGTH,+                              trap,+                              data,+                              &preventExtensions_);+}++napi_status ProxyHandlerBuilder::PreventExtensions(+    napi_env env,+    napi_status (*trap)(napi_env env, napi_value target, napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 return reinterpret_cast<TrapType>(trap)(+                                     env, args[0], result);+                               },+                               reinterpret_cast<void*>(trap)};+  return PreventExtensions(env, CreateTrapCallback<1>(), &callInfo);+}++napi_status ProxyHandlerBuilder::PreventExtensions(+    napi_env env,+    napi_status (*trap)(napi_env env, napi_value target, bool* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{+      [](napi_env env,+         void* trap,+         napi_span<napi_value> args,+         napi_value* result) noexcept {+        bool boolResult{};+        CHECK_NAPI(reinterpret_cast<TrapType>(trap)(env, args[0], &boolResult));+        return napi_get_boolean(env, boolResult, result);+      },+      reinterpret_cast<void*>(trap)};+  return PreventExtensions(env, CreateTrapCallback<1>(), &callInfo);+}++napi_value ProxyHandlerBuilder::Set() noexcept {+  return set_;+}++void ProxyHandlerBuilder::Set(napi_value trap) noexcept {+  set_ = trap;+}++napi_status ProxyHandlerBuilder::Set(napi_env env,+                                     napi_callback trap,+                                     void* data) noexcept {+  return napi_create_function(env, "set", NAPI_AUTO_LENGTH, trap, data, &set_);+}++napi_status ProxyHandlerBuilder::Set(napi_env env,+                                     napi_status (*trap)(napi_env env,+                                                         napi_value target,+                                                         napi_value key,+                                                         napi_value value,+                                                         napi_value receiver,+                                                         napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{+      [](napi_env env,+         void* trap,+         napi_span<napi_value> args,+         napi_value* result) noexcept {+        return reinterpret_cast<TrapType>(trap)(+            env, args[0], args[1], args[2], args[3], result);+      },+      reinterpret_cast<void*>(trap)};+  return Set(env, CreateTrapCallback<4>(), &callInfo);+}++napi_status ProxyHandlerBuilder::Set(napi_env env,+                                     napi_status (*trap)(napi_env env,+                                                         napi_value target,+                                                         napi_value key,+                                                         napi_value value,+                                                         napi_value receiver,+                                                         bool* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{+      [](napi_env env,+         void* trap,+         napi_span<napi_value> args,+         napi_value* result) noexcept {+        bool boolResult{};+        CHECK_NAPI(reinterpret_cast<TrapType>(trap)(+            env, args[0], args[1], args[2], args[3], &boolResult));+        return napi_get_boolean(env, boolResult, result);+      },+      reinterpret_cast<void*>(trap)};+  return Set(env, CreateTrapCallback<4>(), &callInfo);+}++napi_value ProxyHandlerBuilder::SetPrototypeOf() noexcept {+  return setPrototypeOf_;+}++void ProxyHandlerBuilder::SetPrototypeOf(napi_value trap) noexcept {+  setPrototypeOf_ = trap;+}++napi_status ProxyHandlerBuilder::SetPrototypeOf(napi_env env,+                                                napi_callback trap,+                                                void* data) noexcept {+  return napi_create_function(+      env, "setPrototypeOf", NAPI_AUTO_LENGTH, trap, data, &setPrototypeOf_);+}++napi_status ProxyHandlerBuilder::SetPrototypeOf(+    napi_env env,+    napi_status (*trap)(napi_env env,+                        napi_value target,+                        napi_value prototype,+                        napi_value* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 return reinterpret_cast<TrapType>(trap)(+                                     env, args[0], args[1], result);+                               },+                               reinterpret_cast<void*>(trap)};+  return SetPrototypeOf(env, CreateTrapCallback<2>(), &callInfo);+}++napi_status ProxyHandlerBuilder::SetPrototypeOf(+    napi_env env,+    napi_status (*trap)(+        napi_env env, napi_value target, napi_value prototype, bool* result)) {+  using TrapType = decltype(trap);+  static TrapCallInfo callInfo{[](napi_env env,+                                  void* trap,+                                  napi_span<napi_value> args,+                                  napi_value* result) noexcept {+                                 bool boolResult{};+                                 CHECK_NAPI(reinterpret_cast<TrapType>(trap)(+                                     env, args[0], args[1], &boolResult));+                                 return napi_get_boolean(+                                     env, boolResult, result);+                               },+                               reinterpret_cast<void*>(trap)};+  return SetPrototypeOf(env, CreateTrapCallback<2>(), &callInfo);+}++//=============++ProxyTemplate::ProxyTemplate(napi_env env, napi_value proxyHandler) noexcept+    : proxyHandler_(RefHolder(env, proxyHandler)) {}++napi_status ProxyTemplate::NewInstance(napi_env env,+                                       napi_value target,+                                       napi_value* result) noexcept {+  napi_value proxyConstructor{};+  CHECK_NAPI(GetProxyConstructor(env, &proxyConstructor));++  napi_value args[] = {target, static_cast<napi_value>(proxyHandler_)};+  return napi_new_instance(env, proxyConstructor, 2, args, result);+}++napi_status ProxyTemplate::GetProxyConstructor(napi_env env,+                                               napi_value* result) noexcept {+  if (!proxyConstructor_) {+    napi_value global{}, proxyConstructor{};+    CHECK_NAPI(napi_get_global(env, &global));+    CHECK_NAPI(+        napi_get_named_property(env, global, "Proxy", &proxyConstructor));+    proxyConstructor_ = RefHolder(env, proxyConstructor);+  }+  *result = proxyConstructor_;+  return napi_ok;+}

src/2-js-to-native-conversion/object-template-demo/napi/proxy-template.h

new file mode 100644@@ -0,0 +1,249 @@+#include "node-api-common.h"++template <typename T>+using napi_span = span<T>;++// Creates a handler object for a JavaScript Proxy.+// See+// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy+// for details about JavaScript Proxy.+//+// There are four different ways we can set each Proxy handler trap:+// - using napi_value function.+// - using napi_callback that creates function.+// - using a callback signature that matches Proxy handler definition arguments.+// - using a callback based on the Proxy handler trap signature where we replace+//   napi_value with strongly typed values such as bool or+//   napi_span<napi_value>.+//+// Note that ProxyHandlerBuilder keeps handler trap functions as napi_value+// and thus cannot be persisted. The typical usage is to create new+// ProxyHandlerBuilder instance on the call stack, set handler traps, create+// handler to pass to Proxy constructor or ProxyTemplate, and not to reuse the+// ProxyHandlerBuilder instance.+struct ProxyHandlerBuilder {+  napi_status NewHandler(napi_env env, napi_value* result) noexcept;++  napi_value Apply() noexcept;+  void Apply(napi_value trap) noexcept;+  napi_status Apply(napi_env env,+                    napi_callback trap,+                    void* data = nullptr) noexcept;+  napi_status Apply(napi_env env,+                    napi_status (*trap)(napi_env env,+                                        napi_value target,+                                        napi_value thisArg,+                                        napi_value argumentList,+                                        napi_value* result));+  napi_status Apply(napi_env env,+                    napi_status (*trap)(napi_env env,+                                        napi_value target,+                                        napi_value thisArg,+                                        napi_span<napi_value> argumentList,+                                        napi_value* result));++  napi_value Construct() noexcept;+  void Construct(napi_value trap) noexcept;+  napi_status Construct(napi_env env,+                        napi_callback trap,+                        void* data = nullptr) noexcept;+  napi_status Construct(napi_env env,+                        napi_status (*trap)(napi_env env,+                                            napi_value target,+                                            napi_value argumentList,+                                            napi_value newTarget,+                                            napi_value* result));+  napi_status Construct(napi_env env,+                        napi_status (*trap)(napi_env env,+                                            napi_value target,+                                            napi_span<napi_value> argumentList,+                                            napi_value newTarget,+                                            napi_value* result));++  napi_value DefineProperty() noexcept;+  void DefineProperty(napi_value trap) noexcept;+  napi_status DefineProperty(napi_env env,+                             napi_callback trap,+                             void* data = nullptr) noexcept;+  napi_status DefineProperty(napi_env env,+                             napi_status (*trap)(napi_env env,+                                                 napi_value target,+                                                 napi_value key,+                                                 napi_value descriptor,+                                                 napi_value* result));+  napi_status DefineProperty(napi_env env,+                             napi_status (*trap)(napi_env env,+                                                 napi_value target,+                                                 napi_value key,+                                                 napi_value descriptor,+                                                 bool* result));++  napi_value DeleteProperty() noexcept;+  void DeleteProperty(napi_value trap) noexcept;+  napi_status DeleteProperty(napi_env env,+                             napi_callback trap,+                             void* data = nullptr) noexcept;+  napi_status DeleteProperty(napi_env env,+                             napi_status (*trap)(napi_env env,+                                                 napi_value target,+                                                 napi_value key,+                                                 napi_value* result));+  napi_status DeleteProperty(napi_env env,+                             napi_status (*trap)(napi_env env,+                                                 napi_value target,+                                                 napi_value key,+                                                 bool* result));++  napi_value Get() noexcept;+  void Get(napi_value trap) noexcept;+  napi_status Get(napi_env env,+                  napi_callback trap,+                  void* data = nullptr) noexcept;+  napi_status Get(napi_env env,+                  napi_status (*trap)(napi_env env,+                                      napi_value target,+                                      napi_value key,+                                      napi_value receiver,+                                      napi_value* result));++  napi_value GetOwnPropertyDescriptor() noexcept;+  void GetOwnPropertyDescriptor(napi_value trap) noexcept;+  napi_status GetOwnPropertyDescriptor(napi_env env,+                                       napi_callback trap,+                                       void* data = nullptr) noexcept;+  napi_status GetOwnPropertyDescriptor(napi_env env,+                                       napi_status (*trap)(napi_env env,+                                                           napi_value target,+                                                           napi_value key,+                                                           napi_value* result));++  napi_value GetPrototypeOf() noexcept;+  void GetPrototypeOf(napi_value trap) noexcept;+  napi_status GetPrototypeOf(napi_env env,+                             napi_callback trap,+                             void* data = nullptr) noexcept;+  napi_status GetPrototypeOf(napi_env env,+                             napi_status (*trap)(napi_env env,+                                                 napi_value target,+                                                 napi_value* result));++  napi_value Has() noexcept;+  void Has(napi_value trap) noexcept;+  napi_status Has(napi_env env,+                  napi_callback trap,+                  void* data = nullptr) noexcept;+  napi_status Has(napi_env env,+                  napi_status (*trap)(napi_env env,+                                      napi_value target,+                                      napi_value key,+                                      napi_value* result));+  napi_status Has(napi_env env,+                  napi_status (*trap)(napi_env env,+                                      napi_value target,+                                      napi_value key,+                                      bool* result));++  napi_value IsExtensible() noexcept;+  void IsExtensible(napi_value trap) noexcept;+  napi_status IsExtensible(napi_env env,+                           napi_callback trap,+                           void* data = nullptr) noexcept;+  napi_status IsExtensible(napi_env env,+                           napi_status (*trap)(napi_env env,+                                               napi_value target,+                                               napi_value* result));+  napi_status IsExtensible(napi_env env,+                           napi_status (*trap)(napi_env env,+                                               napi_value target,+                                               bool* result));++  napi_value OwnKeys() noexcept;+  void OwnKeys(napi_value trap) noexcept;+  napi_status OwnKeys(napi_env env,+                      napi_callback trap,+                      void* data = nullptr) noexcept;+  napi_status OwnKeys(napi_env env,+                      napi_status (*trap)(napi_env env,+                                          napi_value target,+                                          napi_value* result));++  napi_value PreventExtensions() noexcept;+  void PreventExtensions(napi_value trap) noexcept;+  napi_status PreventExtensions(napi_env env,+                                napi_callback trap,+                                void* data = nullptr) noexcept;+  napi_status PreventExtensions(napi_env env,+                                napi_status (*trap)(napi_env env,+                                                    napi_value target,+                                                    napi_value* result));+  napi_status PreventExtensions(napi_env env,+                                napi_status (*trap)(napi_env env,+                                                    napi_value target,+                                                    bool* result));++  napi_value Set() noexcept;+  void Set(napi_value trap) noexcept;+  napi_status Set(napi_env env,+                  napi_callback trap,+                  void* data = nullptr) noexcept;+  napi_status Set(napi_env env,+                  napi_status (*trap)(napi_env env,+                                      napi_value target,+                                      napi_value key,+                                      napi_value value,+                                      napi_value receiver,+                                      napi_value* result));+  napi_status Set(napi_env env,+                  napi_status (*trap)(napi_env env,+                                      napi_value target,+                                      napi_value key,+                                      napi_value value,+                                      napi_value receiver,+                                      bool* result));++  napi_value SetPrototypeOf() noexcept;+  void SetPrototypeOf(napi_value trap) noexcept;+  napi_status SetPrototypeOf(napi_env env,+                             napi_callback trap,+                             void* data = nullptr) noexcept;+  napi_status SetPrototypeOf(napi_env env,+                             napi_status (*trap)(napi_env env,+                                                 napi_value target,+                                                 napi_value prototype,+                                                 napi_value* result));+  napi_status SetPrototypeOf(napi_env env,+                             napi_status (*trap)(napi_env env,+                                                 napi_value target,+                                                 napi_value prototype,+                                                 bool* result));++ private:+  napi_value apply_{};+  napi_value construct_{};+  napi_value defineProperty_{};+  napi_value deleteProperty_{};+  napi_value get_{};+  napi_value getOwnPropertyDescriptor_{};+  napi_value getPrototypeOf_{};+  napi_value has_{};+  napi_value isExtensible_{};+  napi_value ownKeys_{};+  napi_value preventExtensions_{};+  napi_value set_{};+  napi_value setPrototypeOf_{};+};++struct ProxyTemplate {+  ProxyTemplate(napi_env env, napi_value proxyHandler) noexcept;++  napi_status NewInstance(napi_env env,+                          napi_value target,+                          napi_value* result) noexcept;++ private:+  napi_status GetProxyConstructor(napi_env env, napi_value* result) noexcept;++ private:+  RefHolder proxyConstructor_{};+  RefHolder proxyHandler_{};+};