@ 260528.1 · fetching
current
#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;
}