mirror of https://github.com/lukechilds/node.git
Browse Source
Add support for abi stable module API (N-API) as "Experimental feature". The goal of this API is to provide a stable Node API for native module developers. N-API aims to provide ABI compatibility guarantees across different Node versions and also across different Node VMs - allowing N-API enabled native modules to just work across different versions and flavors of Node.js without recompilation. A more detailed introduction is provided in: https://github.com/nodejs/node-eps/blob/master/005-ABI-Stable-Module-API.md and https://github.com/nodejs/abi-stable-node/blob/doc/VM%20Summit.pdf. The feature, during its experimental state, will be guarded by a runtime flag "--napi-modules". Only when this flag is added to the command line will N-API modules along with regular non N-API modules be supported. The API is defined by the methods in "src/node_api.h" and "src/node_api_types.h". This is the best starting point to review the API surface. More documentation will follow. In addition to the implementation of the API using V8, which is included in this PR, the API has also been validated against chakracore and that port is available in https://github.com/nodejs/abi-stable-node/tree/api-prototype-chakracore-8.x. The current plan is to provide N-API support in versions 8.X and 6.X directly. For older versions, such as 4.X or pre N-API versions of 6.X, we plan to create an external npm module to provide a migration path that will allow modules targeting older Node.js versions to use the API, albeit without getting the advantage of not having to recompile. In addition, we also plan an external npm package with C++ sugar to simplify the use of the API. The sugar will be in-line only and will only use the exported N-API methods but is not part of the N-API itself. The current version is in: https://github.com/nodejs/node-api. This PR is a result of work in the abi-stable-node repo: https://github.com/nodejs/abi-stable-node/tree/doc, with this PR being the cumulative work on the api-prototype-8.x branch with the following contributors in alphabetical order: Author: Arunesh Chandra <arunesh.chandra@microsoft.com> Author: Gabriel Schulhof <gabriel.schulhof@intel.com> Author: Hitesh Kanwathirtha <hiteshk@microsoft.com> Author: Ian Halliday <ianhall@microsoft.com> Author: Jason Ginchereau <jasongin@microsoft.com> Author: Michael Dawson <michael_dawson@ca.ibm.com> Author: Sampson Gao <sampsong@ca.ibm.com> Author: Taylor Woll <taylor.woll@microsoft.com> PR-URL: https://github.com/nodejs/node/pull/11975 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: James M Snell <jasnell@gmail.com>v6
Jason Ginchereau
8 years ago
committed by
Anna Henningsen
88 changed files with 6580 additions and 23 deletions
File diff suppressed because it is too large
@ -0,0 +1,479 @@ |
|||
/******************************************************************************
|
|||
* Experimental prototype for demonstrating VM agnostic and ABI stable API |
|||
* for native modules to use instead of using Nan and V8 APIs directly. |
|||
* |
|||
* The current status is "Experimental" and should not be used for |
|||
* production applications. The API is still subject to change |
|||
* and as an experimental feature is NOT subject to semver. |
|||
* |
|||
******************************************************************************/ |
|||
#ifndef SRC_NODE_API_H_ |
|||
#define SRC_NODE_API_H_ |
|||
|
|||
#include <stddef.h> |
|||
#include <stdbool.h> |
|||
#include "node_api_types.h" |
|||
|
|||
#ifdef _WIN32 |
|||
#ifdef BUILDING_NODE_EXTENSION |
|||
#ifdef EXTERNAL_NAPI |
|||
// Building external N-API, or native module against external N-API
|
|||
#define NAPI_EXTERN /* nothing */ |
|||
#else |
|||
// Building native module against node with built-in N-API
|
|||
#define NAPI_EXTERN __declspec(dllimport) |
|||
#endif |
|||
#else |
|||
// Building node with built-in N-API
|
|||
#define NAPI_EXTERN __declspec(dllexport) |
|||
#endif |
|||
#else |
|||
#define NAPI_EXTERN /* nothing */ |
|||
#endif |
|||
|
|||
#ifdef _WIN32 |
|||
# define NAPI_MODULE_EXPORT __declspec(dllexport) |
|||
#else |
|||
# define NAPI_MODULE_EXPORT __attribute__((visibility("default"))) |
|||
#endif |
|||
|
|||
|
|||
typedef void (*napi_addon_register_func)(napi_env env, |
|||
napi_value exports, |
|||
napi_value module, |
|||
void* priv); |
|||
|
|||
typedef struct { |
|||
int nm_version; |
|||
unsigned int nm_flags; |
|||
const char* nm_filename; |
|||
napi_addon_register_func nm_register_func; |
|||
const char* nm_modname; |
|||
void* nm_priv; |
|||
void* reserved[4]; |
|||
} napi_module; |
|||
|
|||
#define NAPI_MODULE_VERSION 1 |
|||
|
|||
#if defined(_MSC_VER) |
|||
#pragma section(".CRT$XCU", read) |
|||
#define NAPI_C_CTOR(fn) \ |
|||
static void __cdecl fn(void); \ |
|||
__declspec(dllexport, allocate(".CRT$XCU")) void(__cdecl * fn##_)(void) = \ |
|||
fn; \ |
|||
static void __cdecl fn(void) |
|||
#else |
|||
#define NAPI_C_CTOR(fn) \ |
|||
static void fn(void) __attribute__((constructor)); \ |
|||
static void fn(void) |
|||
#endif |
|||
|
|||
#ifdef __cplusplus |
|||
#define EXTERN_C_START extern "C" { |
|||
#define EXTERN_C_END } |
|||
#else |
|||
#define EXTERN_C_START |
|||
#define EXTERN_C_END |
|||
#endif |
|||
|
|||
#define NAPI_MODULE_X(modname, regfunc, priv, flags) \ |
|||
EXTERN_C_START \ |
|||
static napi_module _module = \ |
|||
{ \ |
|||
NAPI_MODULE_VERSION, \ |
|||
flags, \ |
|||
__FILE__, \ |
|||
regfunc, \ |
|||
#modname, \ |
|||
priv, \ |
|||
{0}, \ |
|||
}; \ |
|||
NAPI_C_CTOR(_register_ ## modname) { \ |
|||
napi_module_register(&_module); \ |
|||
} \ |
|||
EXTERN_C_END |
|||
|
|||
#define NAPI_MODULE(modname, regfunc) \ |
|||
NAPI_MODULE_X(modname, regfunc, NULL, 0) |
|||
|
|||
EXTERN_C_START |
|||
|
|||
NAPI_EXTERN void napi_module_register(napi_module* mod); |
|||
|
|||
NAPI_EXTERN napi_status |
|||
napi_get_last_error_info(napi_env env, |
|||
const napi_extended_error_info** result); |
|||
|
|||
// Getters for defined singletons
|
|||
NAPI_EXTERN napi_status napi_get_undefined(napi_env env, napi_value* result); |
|||
NAPI_EXTERN napi_status napi_get_null(napi_env env, napi_value* result); |
|||
NAPI_EXTERN napi_status napi_get_global(napi_env env, napi_value* result); |
|||
NAPI_EXTERN napi_status napi_get_boolean(napi_env env, |
|||
bool value, |
|||
napi_value* result); |
|||
|
|||
// Methods to create Primitive types/Objects
|
|||
NAPI_EXTERN napi_status napi_create_object(napi_env env, napi_value* result); |
|||
NAPI_EXTERN napi_status napi_create_array(napi_env env, napi_value* result); |
|||
NAPI_EXTERN napi_status napi_create_array_with_length(napi_env env, |
|||
size_t length, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_create_number(napi_env env, |
|||
double value, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_create_string_utf8(napi_env env, |
|||
const char* str, |
|||
size_t length, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_create_string_utf16(napi_env env, |
|||
const char16_t* str, |
|||
size_t length, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_create_symbol(napi_env env, |
|||
napi_value description, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_create_function(napi_env env, |
|||
const char* utf8name, |
|||
napi_callback cb, |
|||
void* data, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_create_error(napi_env env, |
|||
napi_value msg, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_create_type_error(napi_env env, |
|||
napi_value msg, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_create_range_error(napi_env env, |
|||
napi_value msg, |
|||
napi_value* result); |
|||
|
|||
// Methods to get the the native napi_value from Primitive type
|
|||
NAPI_EXTERN napi_status napi_typeof(napi_env env, |
|||
napi_value value, |
|||
napi_valuetype* result); |
|||
NAPI_EXTERN napi_status napi_get_value_double(napi_env env, |
|||
napi_value value, |
|||
double* result); |
|||
NAPI_EXTERN napi_status napi_get_value_int32(napi_env env, |
|||
napi_value value, |
|||
int32_t* result); |
|||
NAPI_EXTERN napi_status napi_get_value_uint32(napi_env env, |
|||
napi_value value, |
|||
uint32_t* result); |
|||
NAPI_EXTERN napi_status napi_get_value_int64(napi_env env, |
|||
napi_value value, |
|||
int64_t* result); |
|||
NAPI_EXTERN napi_status napi_get_value_bool(napi_env env, |
|||
napi_value value, |
|||
bool* result); |
|||
|
|||
// Gets the number of CHARACTERS in the string.
|
|||
NAPI_EXTERN napi_status napi_get_value_string_length(napi_env env, |
|||
napi_value value, |
|||
size_t* result); |
|||
|
|||
// Copies UTF-8 encoded bytes from a string into a buffer.
|
|||
NAPI_EXTERN napi_status napi_get_value_string_utf8(napi_env env, |
|||
napi_value value, |
|||
char* buf, |
|||
size_t bufsize, |
|||
size_t* result); |
|||
|
|||
// Copies UTF-16 encoded bytes from a string into a buffer.
|
|||
NAPI_EXTERN napi_status napi_get_value_string_utf16(napi_env env, |
|||
napi_value value, |
|||
char16_t* buf, |
|||
size_t bufsize, |
|||
size_t* result); |
|||
|
|||
// Methods to coerce values
|
|||
// These APIs may execute user scripts
|
|||
NAPI_EXTERN napi_status napi_coerce_to_bool(napi_env env, |
|||
napi_value value, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_coerce_to_number(napi_env env, |
|||
napi_value value, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_coerce_to_object(napi_env env, |
|||
napi_value value, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_coerce_to_string(napi_env env, |
|||
napi_value value, |
|||
napi_value* result); |
|||
|
|||
// Methods to work with Objects
|
|||
NAPI_EXTERN napi_status napi_get_prototype(napi_env env, |
|||
napi_value object, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_get_property_names(napi_env env, |
|||
napi_value object, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_set_property(napi_env env, |
|||
napi_value object, |
|||
napi_value key, |
|||
napi_value value); |
|||
NAPI_EXTERN napi_status napi_has_property(napi_env env, |
|||
napi_value object, |
|||
napi_value key, |
|||
bool* result); |
|||
NAPI_EXTERN napi_status napi_get_property(napi_env env, |
|||
napi_value object, |
|||
napi_value key, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_set_named_property(napi_env env, |
|||
napi_value object, |
|||
const char* utf8name, |
|||
napi_value value); |
|||
NAPI_EXTERN napi_status napi_has_named_property(napi_env env, |
|||
napi_value object, |
|||
const char* utf8name, |
|||
bool* result); |
|||
NAPI_EXTERN napi_status napi_get_named_property(napi_env env, |
|||
napi_value object, |
|||
const char* utf8name, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_set_element(napi_env env, |
|||
napi_value object, |
|||
uint32_t index, |
|||
napi_value value); |
|||
NAPI_EXTERN napi_status napi_has_element(napi_env env, |
|||
napi_value object, |
|||
uint32_t index, |
|||
bool* result); |
|||
NAPI_EXTERN napi_status napi_get_element(napi_env env, |
|||
napi_value object, |
|||
uint32_t index, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status |
|||
napi_define_properties(napi_env env, |
|||
napi_value object, |
|||
size_t property_count, |
|||
const napi_property_descriptor* properties); |
|||
|
|||
// Methods to work with Arrays
|
|||
NAPI_EXTERN napi_status napi_is_array(napi_env env, |
|||
napi_value value, |
|||
bool* result); |
|||
NAPI_EXTERN napi_status napi_get_array_length(napi_env env, |
|||
napi_value value, |
|||
uint32_t* result); |
|||
|
|||
// Methods to compare values
|
|||
NAPI_EXTERN napi_status napi_strict_equals(napi_env env, |
|||
napi_value lhs, |
|||
napi_value rhs, |
|||
bool* result); |
|||
|
|||
// Methods to work with Functions
|
|||
NAPI_EXTERN napi_status napi_call_function(napi_env env, |
|||
napi_value recv, |
|||
napi_value func, |
|||
size_t argc, |
|||
const napi_value* argv, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_new_instance(napi_env env, |
|||
napi_value constructor, |
|||
size_t argc, |
|||
const napi_value* argv, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_instanceof(napi_env env, |
|||
napi_value object, |
|||
napi_value constructor, |
|||
bool* result); |
|||
|
|||
// Napi version of node::MakeCallback(...)
|
|||
NAPI_EXTERN napi_status napi_make_callback(napi_env env, |
|||
napi_value recv, |
|||
napi_value func, |
|||
size_t argc, |
|||
const napi_value* argv, |
|||
napi_value* result); |
|||
|
|||
// Methods to work with napi_callbacks
|
|||
|
|||
// Gets all callback info in a single call. (Ugly, but faster.)
|
|||
NAPI_EXTERN napi_status napi_get_cb_info( |
|||
napi_env env, // [in] NAPI environment handle
|
|||
napi_callback_info cbinfo, // [in] Opaque callback-info handle
|
|||
size_t* argc, // [in-out] Specifies the size of the provided argv array
|
|||
// and receives the actual count of args.
|
|||
napi_value* argv, // [out] Array of values
|
|||
napi_value* thisArg, // [out] Receives the JS 'this' arg for the call
|
|||
void** data); // [out] Receives the data pointer for the callback.
|
|||
|
|||
NAPI_EXTERN napi_status napi_get_cb_args_length(napi_env env, |
|||
napi_callback_info cbinfo, |
|||
size_t* result); |
|||
NAPI_EXTERN napi_status napi_get_cb_args(napi_env env, |
|||
napi_callback_info cbinfo, |
|||
napi_value* buf, |
|||
size_t bufsize); |
|||
NAPI_EXTERN napi_status napi_get_cb_this(napi_env env, |
|||
napi_callback_info cbinfo, |
|||
napi_value* result); |
|||
|
|||
NAPI_EXTERN napi_status napi_get_cb_data(napi_env env, |
|||
napi_callback_info cbinfo, |
|||
void** result); |
|||
NAPI_EXTERN napi_status napi_is_construct_call(napi_env env, |
|||
napi_callback_info cbinfo, |
|||
bool* result); |
|||
NAPI_EXTERN napi_status napi_set_return_value(napi_env env, |
|||
napi_callback_info cbinfo, |
|||
napi_value value); |
|||
NAPI_EXTERN napi_status |
|||
napi_define_class(napi_env env, |
|||
const char* utf8name, |
|||
napi_callback constructor, |
|||
void* data, |
|||
size_t property_count, |
|||
const napi_property_descriptor* properties, |
|||
napi_value* result); |
|||
|
|||
// Methods to work with external data objects
|
|||
NAPI_EXTERN napi_status napi_wrap(napi_env env, |
|||
napi_value js_object, |
|||
void* native_object, |
|||
napi_finalize finalize_cb, |
|||
void* finalize_hint, |
|||
napi_ref* result); |
|||
NAPI_EXTERN napi_status napi_unwrap(napi_env env, |
|||
napi_value js_object, |
|||
void** result); |
|||
NAPI_EXTERN napi_status napi_create_external(napi_env env, |
|||
void* data, |
|||
napi_finalize finalize_cb, |
|||
void* finalize_hint, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_get_value_external(napi_env env, |
|||
napi_value value, |
|||
void** result); |
|||
|
|||
// Methods to control object lifespan
|
|||
|
|||
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
|
|||
NAPI_EXTERN napi_status napi_create_reference(napi_env env, |
|||
napi_value value, |
|||
uint32_t initial_refcount, |
|||
napi_ref* result); |
|||
|
|||
// Deletes a reference. The referenced value is released, and may
|
|||
// be GC'd unless there are other references to it.
|
|||
NAPI_EXTERN napi_status napi_delete_reference(napi_env env, napi_ref ref); |
|||
|
|||
// Increments the reference count, optionally returning the resulting count.
|
|||
// After this call the reference will be a strong reference because its
|
|||
// refcount is >0, and the referenced object is effectively "pinned".
|
|||
// Calling this when the refcount is 0 and the object is unavailable
|
|||
// results in an error.
|
|||
NAPI_EXTERN napi_status napi_reference_ref(napi_env env, |
|||
napi_ref ref, |
|||
uint32_t* result); |
|||
|
|||
// Decrements the reference count, optionally returning the resulting count.
|
|||
// If the result is 0 the reference is now weak and the object may be GC'd
|
|||
// at any time if there are no other references. Calling this when the
|
|||
// refcount is already 0 results in an error.
|
|||
NAPI_EXTERN napi_status napi_reference_unref(napi_env env, |
|||
napi_ref ref, |
|||
uint32_t* result); |
|||
|
|||
// Attempts to get a referenced value. If the reference is weak,
|
|||
// the value might no longer be available, in that case the call
|
|||
// is still successful but the result is NULL.
|
|||
NAPI_EXTERN napi_status napi_get_reference_value(napi_env env, |
|||
napi_ref ref, |
|||
napi_value* result); |
|||
|
|||
NAPI_EXTERN napi_status napi_open_handle_scope(napi_env env, |
|||
napi_handle_scope* result); |
|||
NAPI_EXTERN napi_status napi_close_handle_scope(napi_env env, |
|||
napi_handle_scope scope); |
|||
NAPI_EXTERN napi_status |
|||
napi_open_escapable_handle_scope(napi_env env, |
|||
napi_escapable_handle_scope* result); |
|||
NAPI_EXTERN napi_status |
|||
napi_close_escapable_handle_scope(napi_env env, |
|||
napi_escapable_handle_scope scope); |
|||
|
|||
NAPI_EXTERN napi_status napi_escape_handle(napi_env env, |
|||
napi_escapable_handle_scope scope, |
|||
napi_value escapee, |
|||
napi_value* result); |
|||
|
|||
// Methods to support error handling
|
|||
NAPI_EXTERN napi_status napi_throw(napi_env env, napi_value error); |
|||
NAPI_EXTERN napi_status napi_throw_error(napi_env env, const char* msg); |
|||
NAPI_EXTERN napi_status napi_throw_type_error(napi_env env, const char* msg); |
|||
NAPI_EXTERN napi_status napi_throw_range_error(napi_env env, const char* msg); |
|||
NAPI_EXTERN napi_status napi_is_error(napi_env env, |
|||
napi_value value, |
|||
bool* result); |
|||
|
|||
// Methods to support catching exceptions
|
|||
NAPI_EXTERN napi_status napi_is_exception_pending(napi_env env, bool* result); |
|||
NAPI_EXTERN napi_status napi_get_and_clear_last_exception(napi_env env, |
|||
napi_value* result); |
|||
|
|||
// Methods to provide node::Buffer functionality with napi types
|
|||
NAPI_EXTERN napi_status napi_create_buffer(napi_env env, |
|||
size_t length, |
|||
void** data, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_create_external_buffer(napi_env env, |
|||
size_t length, |
|||
void* data, |
|||
napi_finalize finalize_cb, |
|||
void* finalize_hint, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_create_buffer_copy(napi_env env, |
|||
size_t length, |
|||
const void* data, |
|||
void** result_data, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_is_buffer(napi_env env, |
|||
napi_value value, |
|||
bool* result); |
|||
NAPI_EXTERN napi_status napi_get_buffer_info(napi_env env, |
|||
napi_value value, |
|||
void** data, |
|||
size_t* length); |
|||
|
|||
// Methods to work with array buffers and typed arrays
|
|||
NAPI_EXTERN napi_status napi_is_arraybuffer(napi_env env, |
|||
napi_value value, |
|||
bool* result); |
|||
NAPI_EXTERN napi_status napi_create_arraybuffer(napi_env env, |
|||
size_t byte_length, |
|||
void** data, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status |
|||
napi_create_external_arraybuffer(napi_env env, |
|||
void* external_data, |
|||
size_t byte_length, |
|||
napi_finalize finalize_cb, |
|||
void* finalize_hint, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_get_arraybuffer_info(napi_env env, |
|||
napi_value arraybuffer, |
|||
void** data, |
|||
size_t* byte_length); |
|||
NAPI_EXTERN napi_status napi_is_typedarray(napi_env env, |
|||
napi_value value, |
|||
bool* result); |
|||
NAPI_EXTERN napi_status napi_create_typedarray(napi_env env, |
|||
napi_typedarray_type type, |
|||
size_t length, |
|||
napi_value arraybuffer, |
|||
size_t byte_offset, |
|||
napi_value* result); |
|||
NAPI_EXTERN napi_status napi_get_typedarray_info(napi_env env, |
|||
napi_value typedarray, |
|||
napi_typedarray_type* type, |
|||
size_t* length, |
|||
void** data, |
|||
napi_value* arraybuffer, |
|||
size_t* byte_offset); |
|||
EXTERN_C_END |
|||
|
|||
#endif // SRC_NODE_API_H__
|
@ -0,0 +1,95 @@ |
|||
#ifndef SRC_NODE_API_TYPES_H_ |
|||
#define SRC_NODE_API_TYPES_H_ |
|||
|
|||
#include <stddef.h> |
|||
#include <stdint.h> |
|||
|
|||
#if !defined __cplusplus || (defined(_MSC_VER) && _MSC_VER < 1900) |
|||
typedef uint16_t char16_t; |
|||
#endif |
|||
|
|||
// JSVM API types are all opaque pointers for ABI stability
|
|||
// typedef undefined structs instead of void* for compile time type safety
|
|||
typedef struct napi_env__ *napi_env; |
|||
typedef struct napi_value__ *napi_value; |
|||
typedef struct napi_ref__ *napi_ref; |
|||
typedef struct napi_handle_scope__ *napi_handle_scope; |
|||
typedef struct napi_escapable_handle_scope__ *napi_escapable_handle_scope; |
|||
typedef struct napi_callback_info__ *napi_callback_info; |
|||
|
|||
typedef void (*napi_callback)(napi_env env, |
|||
napi_callback_info info); |
|||
typedef void (*napi_finalize)(napi_env env, |
|||
void* finalize_data, |
|||
void* finalize_hint); |
|||
|
|||
typedef enum { |
|||
napi_default = 0, |
|||
napi_read_only = 1 << 0, |
|||
napi_dont_enum = 1 << 1, |
|||
napi_dont_delete = 1 << 2, |
|||
|
|||
// Used with napi_define_class to distinguish static properties
|
|||
// from instance properties. Ignored by napi_define_properties.
|
|||
napi_static_property = 1 << 10, |
|||
} napi_property_attributes; |
|||
|
|||
typedef struct { |
|||
const char* utf8name; |
|||
|
|||
napi_callback method; |
|||
napi_callback getter; |
|||
napi_callback setter; |
|||
napi_value value; |
|||
|
|||
napi_property_attributes attributes; |
|||
void* data; |
|||
} napi_property_descriptor; |
|||
|
|||
typedef enum { |
|||
// ES6 types (corresponds to typeof)
|
|||
napi_undefined, |
|||
napi_null, |
|||
napi_boolean, |
|||
napi_number, |
|||
napi_string, |
|||
napi_symbol, |
|||
napi_object, |
|||
napi_function, |
|||
napi_external, |
|||
} napi_valuetype; |
|||
|
|||
typedef enum { |
|||
napi_int8_array, |
|||
napi_uint8_array, |
|||
napi_uint8_clamped_array, |
|||
napi_int16_array, |
|||
napi_uint16_array, |
|||
napi_int32_array, |
|||
napi_uint32_array, |
|||
napi_float32_array, |
|||
napi_float64_array, |
|||
} napi_typedarray_type; |
|||
|
|||
typedef enum { |
|||
napi_ok, |
|||
napi_invalid_arg, |
|||
napi_object_expected, |
|||
napi_string_expected, |
|||
napi_function_expected, |
|||
napi_number_expected, |
|||
napi_boolean_expected, |
|||
napi_array_expected, |
|||
napi_generic_failure, |
|||
napi_pending_exception, |
|||
napi_status_last |
|||
} napi_status; |
|||
|
|||
typedef struct { |
|||
const char* error_message; |
|||
void* engine_reserved; |
|||
uint32_t engine_error_code; |
|||
napi_status error_code; |
|||
} napi_extended_error_info; |
|||
|
|||
#endif // SRC_NODE_API_TYPES_H_
|
@ -0,0 +1,7 @@ |
|||
.buildstamp |
|||
.docbuildstamp |
|||
Makefile |
|||
*.Makefile |
|||
*.mk |
|||
gyp-mac-tool |
|||
/*/build |
@ -0,0 +1,22 @@ |
|||
#include <node_api.h> |
|||
|
|||
void Method(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
napi_value world; |
|||
status = napi_create_string_utf8(env, "world", -1, &world); |
|||
if (status != napi_ok) return; |
|||
status = napi_set_return_value(env, info, world); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
napi_property_descriptor desc = DECLARE_NAPI_METHOD("hello", Method); |
|||
status = napi_define_properties(env, exports, 1, &desc); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "binding", |
|||
"sources": [ "binding.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,6 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
const addon = require(`./build/${common.buildType}/binding`); |
|||
|
|||
assert.strictEqual(addon.hello(), 'world'); |
@ -0,0 +1,58 @@ |
|||
#include <node_api.h> |
|||
|
|||
void Add(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc < 2) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[2]; |
|||
status = napi_get_cb_args(env, info, args, 2); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype0; |
|||
status = napi_typeof(env, args[0], &valuetype0); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype1; |
|||
status = napi_typeof(env, args[1], &valuetype1); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype0 != napi_number || valuetype1 != napi_number) { |
|||
napi_throw_type_error(env, "Wrong arguments"); |
|||
return; |
|||
} |
|||
|
|||
double value0; |
|||
status = napi_get_value_double(env, args[0], &value0); |
|||
if (status != napi_ok) return; |
|||
|
|||
double value1; |
|||
status = napi_get_value_double(env, args[1], &value1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value sum; |
|||
status = napi_create_number(env, value0 + value1, &sum); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, sum); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
napi_property_descriptor addDescriptor = DECLARE_NAPI_METHOD("add", Add); |
|||
status = napi_define_properties(env, exports, 1, &addDescriptor); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "binding", |
|||
"sources": [ "binding.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,6 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
const addon = require(`./build/${common.buildType}/binding`); |
|||
|
|||
assert.strictEqual(addon.add(3, 5), 8); |
@ -0,0 +1,51 @@ |
|||
#include <node_api.h> |
|||
|
|||
#define NAPI_CALL(env, theCall) \ |
|||
if ((theCall) != napi_ok) { \ |
|||
const napi_extended_error_info* error; \ |
|||
napi_get_last_error_info((env), &error); \ |
|||
const char* errorMessage = error->error_message; \ |
|||
errorMessage = errorMessage ? errorMessage : "empty error message"; \ |
|||
napi_throw_error((env), errorMessage); \ |
|||
return; \ |
|||
} |
|||
|
|||
void RunCallback(napi_env env, napi_callback_info info) { |
|||
napi_value args[1]; |
|||
NAPI_CALL(env, napi_get_cb_args(env, info, args, 1)); |
|||
|
|||
napi_value cb = args[0]; |
|||
|
|||
napi_value argv[1]; |
|||
NAPI_CALL(env, napi_create_string_utf8(env, "hello world", -1, argv)); |
|||
|
|||
napi_value global; |
|||
NAPI_CALL(env, napi_get_global(env, &global)); |
|||
|
|||
NAPI_CALL(env, napi_call_function(env, global, cb, 1, argv, NULL)); |
|||
} |
|||
|
|||
void RunCallbackWithRecv(napi_env env, napi_callback_info info) { |
|||
napi_value args[2]; |
|||
NAPI_CALL(env, napi_get_cb_args(env, info, args, 2)); |
|||
|
|||
napi_value cb = args[0]; |
|||
napi_value recv = args[1]; |
|||
|
|||
NAPI_CALL(env, napi_call_function(env, recv, cb, 0, NULL, NULL)); |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
napi_property_descriptor desc[2] = { |
|||
DECLARE_NAPI_METHOD("RunCallback", RunCallback), |
|||
DECLARE_NAPI_METHOD("RunCallbackWithRecv", RunCallbackWithRecv), |
|||
}; |
|||
status = napi_define_properties(env, exports, 2, desc); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "binding", |
|||
"sources": [ "binding.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,22 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
const addon = require(`./build/${common.buildType}/binding`); |
|||
|
|||
addon.RunCallback(function(msg) { |
|||
assert.strictEqual(msg, 'hello world'); |
|||
}); |
|||
|
|||
function testRecv(desiredRecv) { |
|||
addon.RunCallbackWithRecv(function() { |
|||
assert.strictEqual(this, desiredRecv); |
|||
}, desiredRecv); |
|||
} |
|||
|
|||
testRecv(undefined); |
|||
testRecv(null); |
|||
testRecv(5); |
|||
testRecv(true); |
|||
testRecv('Hello'); |
|||
testRecv([]); |
|||
testRecv({}); |
@ -0,0 +1,31 @@ |
|||
#include <node_api.h> |
|||
|
|||
void CreateObject(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value obj; |
|||
status = napi_create_object(env, &obj); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_named_property(env, obj, "msg", args[0]); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, obj); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
napi_property_descriptor desc = DECLARE_NAPI_METHOD("exports", CreateObject); |
|||
status = napi_define_properties(env, module, 1, &desc); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "binding", |
|||
"sources": [ "binding.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,8 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
const addon = require(`./build/${common.buildType}/binding`); |
|||
|
|||
const obj1 = addon('hello'); |
|||
const obj2 = addon('world'); |
|||
assert.strictEqual(`${obj1.msg} ${obj2.msg}`, 'hello world'); |
@ -0,0 +1,36 @@ |
|||
#include <node_api.h> |
|||
|
|||
void MyFunction(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value str; |
|||
status = napi_create_string_utf8(env, "hello world", -1, &str); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, str); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void CreateFunction(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value fn; |
|||
status = napi_create_function(env, "theFunction", MyFunction, NULL, &fn); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, fn); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
napi_property_descriptor desc = |
|||
DECLARE_NAPI_METHOD("exports", CreateFunction); |
|||
status = napi_define_properties(env, module, 1, &desc); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "binding", |
|||
"sources": [ "binding.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,7 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
const addon = require(`./build/${common.buildType}/binding`); |
|||
|
|||
const fn = addon(); |
|||
assert.strictEqual(fn(), 'hello world'); // 'hello world'
|
@ -0,0 +1,7 @@ |
|||
#include "myobject.h" |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
MyObject::Init(env, exports); |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "binding", |
|||
"sources": [ "binding.cc", "myobject.cc" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,201 @@ |
|||
#include "myobject.h" |
|||
|
|||
napi_ref MyObject::constructor; |
|||
|
|||
MyObject::MyObject(double value) |
|||
: value_(value), env_(nullptr), wrapper_(nullptr) {} |
|||
|
|||
MyObject::~MyObject() { napi_delete_reference(env_, wrapper_); } |
|||
|
|||
void MyObject::Destructor( |
|||
napi_env env, void* nativeObject, void* /*finalize_hint*/) { |
|||
MyObject* obj = static_cast<MyObject*>(nativeObject); |
|||
delete obj; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void MyObject::Init(napi_env env, napi_value exports) { |
|||
napi_status status; |
|||
napi_property_descriptor properties[] = { |
|||
{ "value", nullptr, GetValue, SetValue, 0, napi_default, 0 }, |
|||
DECLARE_NAPI_METHOD("plusOne", PlusOne), |
|||
DECLARE_NAPI_METHOD("multiply", Multiply), |
|||
}; |
|||
|
|||
napi_value cons; |
|||
status = |
|||
napi_define_class(env, "MyObject", New, nullptr, 3, properties, &cons); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_create_reference(env, cons, 1, &constructor); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_named_property(env, exports, "MyObject", cons); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void MyObject::New(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
bool is_constructor; |
|||
status = napi_is_construct_call(env, info, &is_constructor); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (is_constructor) { |
|||
// Invoked as constructor: `new MyObject(...)`
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
double value = 0; |
|||
|
|||
napi_valuetype valuetype; |
|||
status = napi_typeof(env, args[0], &valuetype); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype != napi_undefined) { |
|||
status = napi_get_value_double(env, args[0], &value); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
MyObject* obj = new MyObject(value); |
|||
|
|||
napi_value jsthis; |
|||
status = napi_get_cb_this(env, info, &jsthis); |
|||
if (status != napi_ok) return; |
|||
|
|||
obj->env_ = env; |
|||
status = napi_wrap(env, |
|||
jsthis, |
|||
obj, |
|||
MyObject::Destructor, |
|||
nullptr, // finalize_hint
|
|||
&obj->wrapper_); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, jsthis); |
|||
if (status != napi_ok) return; |
|||
} else { |
|||
// Invoked as plain function `MyObject(...)`, turn into construct call.
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
const int argc = 1; |
|||
napi_value argv[argc] = {args[0]}; |
|||
|
|||
napi_value cons; |
|||
status = napi_get_reference_value(env, constructor, &cons); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value instance; |
|||
status = napi_new_instance(env, cons, argc, argv, &instance); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, instance); |
|||
if (status != napi_ok) return; |
|||
} |
|||
} |
|||
|
|||
void MyObject::GetValue(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value jsthis; |
|||
status = napi_get_cb_this(env, info, &jsthis); |
|||
if (status != napi_ok) return; |
|||
|
|||
MyObject* obj; |
|||
status = napi_unwrap(env, jsthis, reinterpret_cast<void**>(&obj)); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value num; |
|||
status = napi_create_number(env, obj->value_, &num); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, num); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void MyObject::SetValue(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value value; |
|||
status = napi_get_cb_args(env, info, &value, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value jsthis; |
|||
status = napi_get_cb_this(env, info, &jsthis); |
|||
if (status != napi_ok) return; |
|||
|
|||
MyObject* obj; |
|||
status = napi_unwrap(env, jsthis, reinterpret_cast<void**>(&obj)); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_get_value_double(env, value, &obj->value_); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void MyObject::PlusOne(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value jsthis; |
|||
status = napi_get_cb_this(env, info, &jsthis); |
|||
if (status != napi_ok) return; |
|||
|
|||
MyObject* obj; |
|||
status = napi_unwrap(env, jsthis, reinterpret_cast<void**>(&obj)); |
|||
if (status != napi_ok) return; |
|||
|
|||
obj->value_ += 1; |
|||
|
|||
napi_value num; |
|||
status = napi_create_number(env, obj->value_, &num); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, num); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void MyObject::Multiply(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype; |
|||
status = napi_typeof(env, args[0], &valuetype); |
|||
if (status != napi_ok) return; |
|||
|
|||
double multiple = 1; |
|||
if (valuetype != napi_undefined) { |
|||
status = napi_get_value_double(env, args[0], &multiple); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
napi_value jsthis; |
|||
status = napi_get_cb_this(env, info, &jsthis); |
|||
if (status != napi_ok) return; |
|||
|
|||
MyObject* obj; |
|||
status = napi_unwrap(env, jsthis, reinterpret_cast<void**>(&obj)); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value cons; |
|||
status = napi_get_reference_value(env, constructor, &cons); |
|||
if (status != napi_ok) return; |
|||
|
|||
const int kArgCount = 1; |
|||
napi_value argv[kArgCount]; |
|||
status = napi_create_number(env, obj->value_ * multiple, argv); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value instance; |
|||
status = napi_new_instance(env, cons, kArgCount, argv, &instance); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, instance); |
|||
if (status != napi_ok) return; |
|||
} |
@ -0,0 +1,26 @@ |
|||
#ifndef TEST_ADDONS_NAPI_6_OBJECT_WRAP_MYOBJECT_H_ |
|||
#define TEST_ADDONS_NAPI_6_OBJECT_WRAP_MYOBJECT_H_ |
|||
|
|||
#include <node_api.h> |
|||
|
|||
class MyObject { |
|||
public: |
|||
static void Init(napi_env env, napi_value exports); |
|||
static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); |
|||
|
|||
private: |
|||
explicit MyObject(double value_ = 0); |
|||
~MyObject(); |
|||
|
|||
static void New(napi_env env, napi_callback_info info); |
|||
static void GetValue(napi_env env, napi_callback_info info); |
|||
static void SetValue(napi_env env, napi_callback_info info); |
|||
static void PlusOne(napi_env env, napi_callback_info info); |
|||
static void Multiply(napi_env env, napi_callback_info info); |
|||
static napi_ref constructor; |
|||
double value_; |
|||
napi_env env_; |
|||
napi_ref wrapper_; |
|||
}; |
|||
|
|||
#endif // TEST_ADDONS_NAPI_6_OBJECT_WRAP_MYOBJECT_H_
|
@ -0,0 +1,19 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
const addon = require(`./build/${common.buildType}/binding`); |
|||
|
|||
const obj = new addon.MyObject(9); |
|||
assert.strictEqual(obj.value, 9); |
|||
obj.value = 10; |
|||
assert.strictEqual(obj.value, 10); |
|||
assert.strictEqual(obj.plusOne(), 11); |
|||
assert.strictEqual(obj.plusOne(), 12); |
|||
assert.strictEqual(obj.plusOne(), 13); |
|||
|
|||
assert.strictEqual(obj.multiply().value, 13); |
|||
assert.strictEqual(obj.multiply(10).value, 130); |
|||
|
|||
const newobj = obj.multiply(-1); |
|||
assert.strictEqual(newobj.value, -13); |
|||
assert.notStrictEqual(obj, newobj); |
@ -0,0 +1,32 @@ |
|||
#include "myobject.h" |
|||
|
|||
void CreateObject(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value instance; |
|||
status = MyObject::NewInstance(env, args[0], &instance); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, instance); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
status = MyObject::Init(env); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_property_descriptor desc = DECLARE_NAPI_METHOD("exports", CreateObject); |
|||
status = napi_define_properties(env, module, 1, &desc); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "binding", |
|||
"sources": [ "binding.cc", "myobject.cc" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,110 @@ |
|||
#include "myobject.h" |
|||
|
|||
MyObject::MyObject() : env_(nullptr), wrapper_(nullptr) {} |
|||
|
|||
MyObject::~MyObject() { napi_delete_reference(env_, wrapper_); } |
|||
|
|||
void MyObject::Destructor(napi_env env, |
|||
void* nativeObject, |
|||
void* /*finalize_hint*/) { |
|||
MyObject* obj = static_cast<MyObject*>(nativeObject); |
|||
delete obj; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
napi_ref MyObject::constructor; |
|||
|
|||
napi_status MyObject::Init(napi_env env) { |
|||
napi_status status; |
|||
napi_property_descriptor properties[] = { |
|||
DECLARE_NAPI_METHOD("plusOne", PlusOne), |
|||
}; |
|||
|
|||
napi_value cons; |
|||
status = |
|||
napi_define_class(env, "MyObject", New, nullptr, 1, properties, &cons); |
|||
if (status != napi_ok) return status; |
|||
|
|||
status = napi_create_reference(env, cons, 1, &constructor); |
|||
if (status != napi_ok) return status; |
|||
|
|||
return napi_ok; |
|||
} |
|||
|
|||
void MyObject::New(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype; |
|||
status = napi_typeof(env, args[0], &valuetype); |
|||
if (status != napi_ok) return; |
|||
|
|||
MyObject* obj = new MyObject(); |
|||
|
|||
if (valuetype == napi_undefined) { |
|||
obj->counter_ = 0; |
|||
} else { |
|||
status = napi_get_value_double(env, args[0], &obj->counter_); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
napi_value jsthis; |
|||
status = napi_get_cb_this(env, info, &jsthis); |
|||
if (status != napi_ok) return; |
|||
|
|||
obj->env_ = env; |
|||
status = napi_wrap(env, |
|||
jsthis, |
|||
obj, |
|||
MyObject::Destructor, |
|||
nullptr, /* finalize_hint */ |
|||
&obj->wrapper_); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, jsthis); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
napi_status MyObject::NewInstance(napi_env env, |
|||
napi_value arg, |
|||
napi_value* instance) { |
|||
napi_status status; |
|||
|
|||
const int argc = 1; |
|||
napi_value argv[argc] = {arg}; |
|||
|
|||
napi_value cons; |
|||
status = napi_get_reference_value(env, constructor, &cons); |
|||
if (status != napi_ok) return status; |
|||
|
|||
status = napi_new_instance(env, cons, argc, argv, instance); |
|||
if (status != napi_ok) return status; |
|||
|
|||
return napi_ok; |
|||
} |
|||
|
|||
void MyObject::PlusOne(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value jsthis; |
|||
status = napi_get_cb_this(env, info, &jsthis); |
|||
if (status != napi_ok) return; |
|||
|
|||
MyObject* obj; |
|||
status = napi_unwrap(env, jsthis, reinterpret_cast<void**>(&obj)); |
|||
if (status != napi_ok) return; |
|||
|
|||
obj->counter_ += 1; |
|||
|
|||
napi_value num; |
|||
status = napi_create_number(env, obj->counter_, &num); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, num); |
|||
if (status != napi_ok) return; |
|||
} |
@ -0,0 +1,26 @@ |
|||
#ifndef TEST_ADDONS_NAPI_7_FACTORY_WRAP_MYOBJECT_H_ |
|||
#define TEST_ADDONS_NAPI_7_FACTORY_WRAP_MYOBJECT_H_ |
|||
|
|||
#include <node_api.h> |
|||
|
|||
class MyObject { |
|||
public: |
|||
static napi_status Init(napi_env env); |
|||
static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); |
|||
static napi_status NewInstance(napi_env env, |
|||
napi_value arg, |
|||
napi_value* instance); |
|||
|
|||
private: |
|||
MyObject(); |
|||
~MyObject(); |
|||
|
|||
static napi_ref constructor; |
|||
static void New(napi_env env, napi_callback_info info); |
|||
static void PlusOne(napi_env env, napi_callback_info info); |
|||
double counter_; |
|||
napi_env env_; |
|||
napi_ref wrapper_; |
|||
}; |
|||
|
|||
#endif // TEST_ADDONS_NAPI_7_FACTORY_WRAP_MYOBJECT_H_
|
@ -0,0 +1,14 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
const createObject = require(`./build/${common.buildType}/binding`); |
|||
|
|||
const obj = createObject(10); |
|||
assert.strictEqual(obj.plusOne(), 11); |
|||
assert.strictEqual(obj.plusOne(), 12); |
|||
assert.strictEqual(obj.plusOne(), 13); |
|||
|
|||
const obj2 = createObject(20); |
|||
assert.strictEqual(obj2.plusOne(), 21); |
|||
assert.strictEqual(obj2.plusOne(), 22); |
|||
assert.strictEqual(obj2.plusOne(), 23); |
@ -0,0 +1,57 @@ |
|||
#include "myobject.h" |
|||
|
|||
void CreateObject(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value instance; |
|||
status = MyObject::NewInstance(env, args[0], &instance); |
|||
|
|||
status = napi_set_return_value(env, info, instance); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void Add(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value args[2]; |
|||
status = napi_get_cb_args(env, info, args, 2); |
|||
if (status != napi_ok) return; |
|||
|
|||
MyObject* obj1; |
|||
status = napi_unwrap(env, args[0], reinterpret_cast<void**>(&obj1)); |
|||
if (status != napi_ok) return; |
|||
|
|||
MyObject* obj2; |
|||
status = napi_unwrap(env, args[1], reinterpret_cast<void**>(&obj2)); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value sum; |
|||
status = napi_create_number(env, obj1->Val() + obj2->Val(), &sum); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, sum); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
MyObject::Init(env); |
|||
|
|||
napi_property_descriptor desc[] = { |
|||
DECLARE_NAPI_METHOD("createObject", CreateObject), |
|||
DECLARE_NAPI_METHOD("add", Add), |
|||
}; |
|||
status = |
|||
napi_define_properties(env, exports, sizeof(desc) / sizeof(*desc), desc); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "binding", |
|||
"sources": [ "binding.cc", "myobject.cc" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,81 @@ |
|||
#include "myobject.h" |
|||
|
|||
MyObject::MyObject() : env_(nullptr), wrapper_(nullptr) {} |
|||
|
|||
MyObject::~MyObject() { napi_delete_reference(env_, wrapper_); } |
|||
|
|||
void MyObject::Destructor( |
|||
napi_env env, void* nativeObject, void* /*finalize_hint*/) { |
|||
MyObject* obj = static_cast<MyObject*>(nativeObject); |
|||
delete obj; |
|||
} |
|||
|
|||
napi_ref MyObject::constructor; |
|||
|
|||
napi_status MyObject::Init(napi_env env) { |
|||
napi_status status; |
|||
|
|||
napi_value cons; |
|||
status = napi_define_class(env, "MyObject", New, nullptr, 0, nullptr, &cons); |
|||
if (status != napi_ok) return status; |
|||
|
|||
status = napi_create_reference(env, cons, 1, &constructor); |
|||
if (status != napi_ok) return status; |
|||
|
|||
return napi_ok; |
|||
} |
|||
|
|||
void MyObject::New(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
MyObject* obj = new MyObject(); |
|||
|
|||
napi_valuetype valuetype; |
|||
status = napi_typeof(env, args[0], &valuetype); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype == napi_undefined) { |
|||
obj->val_ = 0; |
|||
} else { |
|||
status = napi_get_value_double(env, args[0], &obj->val_); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
napi_value jsthis; |
|||
status = napi_get_cb_this(env, info, &jsthis); |
|||
if (status != napi_ok) return; |
|||
|
|||
obj->env_ = env; |
|||
status = napi_wrap(env, |
|||
jsthis, |
|||
obj, |
|||
MyObject::Destructor, |
|||
nullptr, // finalize_hint
|
|||
&obj->wrapper_); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, jsthis); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
napi_status MyObject::NewInstance(napi_env env, |
|||
napi_value arg, |
|||
napi_value* instance) { |
|||
napi_status status; |
|||
|
|||
const int argc = 1; |
|||
napi_value argv[argc] = {arg}; |
|||
|
|||
napi_value cons; |
|||
status = napi_get_reference_value(env, constructor, &cons); |
|||
if (status != napi_ok) return status; |
|||
|
|||
status = napi_new_instance(env, cons, argc, argv, instance); |
|||
if (status != napi_ok) return status; |
|||
|
|||
return napi_ok; |
|||
} |
@ -0,0 +1,26 @@ |
|||
#ifndef TEST_ADDONS_NAPI_8_PASSING_WRAPPED_MYOBJECT_H_ |
|||
#define TEST_ADDONS_NAPI_8_PASSING_WRAPPED_MYOBJECT_H_ |
|||
|
|||
#include <node_api.h> |
|||
|
|||
class MyObject { |
|||
public: |
|||
static napi_status Init(napi_env env); |
|||
static void Destructor(napi_env env, void* nativeObject, void* finalize_hint); |
|||
static napi_status NewInstance(napi_env env, |
|||
napi_value arg, |
|||
napi_value* instance); |
|||
double Val() const { return val_; } |
|||
|
|||
private: |
|||
MyObject(); |
|||
~MyObject(); |
|||
|
|||
static napi_ref constructor; |
|||
static void New(napi_env env, napi_callback_info info); |
|||
double val_; |
|||
napi_env env_; |
|||
napi_ref wrapper_; |
|||
}; |
|||
|
|||
#endif // TEST_ADDONS_NAPI_8_PASSING_WRAPPED_MYOBJECT_H_
|
@ -0,0 +1,9 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
const addon = require(`./build/${common.buildType}/binding`); |
|||
|
|||
const obj1 = addon.createObject(10); |
|||
const obj2 = addon.createObject(20); |
|||
const result = addon.add(obj1, obj2); |
|||
assert.strictEqual(result, 30); |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_array", |
|||
"sources": [ "test_array.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,37 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
|
|||
// Testing api calls for arrays
|
|||
const test_array = require(`./build/${common.buildType}/test_array`); |
|||
|
|||
const array = [ |
|||
1, |
|||
9, |
|||
48, |
|||
13493, |
|||
9459324, |
|||
{ name: 'hello' }, |
|||
[ |
|||
'world', |
|||
'node', |
|||
'abi' |
|||
] |
|||
]; |
|||
|
|||
assert.strictEqual(test_array.Test(array, array.length + 1), |
|||
'Index out of bound!'); |
|||
|
|||
assert.throws( |
|||
() => { |
|||
test_array.Test(array, -2); |
|||
}, |
|||
/Invalid index\. Expects a positive integer\./ |
|||
); |
|||
|
|||
array.forEach(function(element, index) { |
|||
assert.strictEqual(test_array.Test(array, index), element); |
|||
}); |
|||
|
|||
|
|||
assert.deepStrictEqual(test_array.New(array), array); |
@ -0,0 +1,137 @@ |
|||
#include <node_api.h> |
|||
#include <string.h> |
|||
|
|||
void Test(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc < 2) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[2]; |
|||
status = napi_get_cb_args(env, info, args, 2); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype0; |
|||
status = napi_typeof(env, args[0], &valuetype0); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype0 != napi_object) { |
|||
napi_throw_type_error( |
|||
env, "Wrong type of argments. Expects an array as first argument."); |
|||
return; |
|||
} |
|||
|
|||
napi_valuetype valuetype1; |
|||
status = napi_typeof(env, args[1], &valuetype1); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype1 != napi_number) { |
|||
napi_throw_type_error( |
|||
env, "Wrong type of argments. Expects an integer as second argument."); |
|||
return; |
|||
} |
|||
|
|||
napi_value array = args[0]; |
|||
int index; |
|||
status = napi_get_value_int32(env, args[1], &index); |
|||
if (status != napi_ok) return; |
|||
|
|||
bool isarray; |
|||
status = napi_is_array(env, array, &isarray); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (isarray) { |
|||
uint32_t size; |
|||
status = napi_get_array_length(env, array, &size); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (index >= (int)(size)) { |
|||
napi_value str; |
|||
status = napi_create_string_utf8(env, "Index out of bound!", -1, &str); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, str); |
|||
if (status != napi_ok) return; |
|||
} else if (index < 0) { |
|||
napi_throw_type_error(env, "Invalid index. Expects a positive integer."); |
|||
} else { |
|||
napi_value ret; |
|||
status = napi_get_element(env, array, index, &ret); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, ret); |
|||
if (status != napi_ok) return; |
|||
} |
|||
} |
|||
} |
|||
|
|||
void New(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc < 1) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype; |
|||
status = napi_typeof(env, args[0], &valuetype); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype != napi_object) { |
|||
napi_throw_type_error( |
|||
env, "Wrong type of argments. Expects an array as first argument."); |
|||
return; |
|||
} |
|||
|
|||
napi_value ret; |
|||
status = napi_create_array(env, &ret); |
|||
if (status != napi_ok) return; |
|||
|
|||
uint32_t i, length; |
|||
status = napi_get_array_length(env, args[0], &length); |
|||
if (status != napi_ok) return; |
|||
|
|||
for (i = 0; i < length; i++) { |
|||
napi_value e; |
|||
status = napi_get_element(env, args[0], i, &e); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_element(env, ret, i, e); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
status = napi_set_return_value(env, info, ret); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
napi_property_descriptor descriptors[] = { |
|||
DECLARE_NAPI_METHOD("Test", Test), |
|||
DECLARE_NAPI_METHOD("New", New), |
|||
}; |
|||
|
|||
status = napi_define_properties( |
|||
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_buffer", |
|||
"sources": [ "test_buffer.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,25 @@ |
|||
'use strict'; |
|||
// Flags: --expose-gc
|
|||
|
|||
const common = require('../../common'); |
|||
const binding = require(`./build/${common.buildType}/test_buffer`); |
|||
const assert = require('assert'); |
|||
|
|||
assert.strictEqual(binding.newBuffer().toString(), binding.theText, |
|||
'buffer returned by newBuffer() has wrong contents'); |
|||
assert.strictEqual(binding.newExternalBuffer().toString(), binding.theText, |
|||
'buffer returned by newExternalBuffer() has wrong contents'); |
|||
console.log('gc1'); |
|||
global.gc(); |
|||
assert.strictEqual(binding.getDeleterCallCount(), 1, 'deleter was not called'); |
|||
assert.strictEqual(binding.copyBuffer().toString(), binding.theText, |
|||
'buffer returned by copyBuffer() has wrong contents'); |
|||
|
|||
let buffer = binding.staticBuffer(); |
|||
assert.strictEqual(binding.bufferHasInstance(buffer), true, |
|||
'buffer type checking fails'); |
|||
assert.strictEqual(binding.bufferInfo(buffer), true, 'buffer data is accurate'); |
|||
buffer = null; |
|||
global.gc(); |
|||
console.log('gc2'); |
|||
assert.strictEqual(binding.getDeleterCallCount(), 2, 'deleter was not called'); |
@ -0,0 +1,160 @@ |
|||
#include <stdlib.h> |
|||
#include <string.h> |
|||
#include <node_api.h> |
|||
|
|||
#define JS_ASSERT(env, assertion, message) \ |
|||
if (!(assertion)) { \ |
|||
napi_throw_error( \ |
|||
(env), \ |
|||
"assertion (" #assertion ") failed: " message); \ |
|||
return; \ |
|||
} |
|||
|
|||
#define NAPI_CALL(env, theCall) \ |
|||
if ((theCall) != napi_ok) { \ |
|||
const napi_extended_error_info* error; \ |
|||
napi_get_last_error_info((env), &error); \ |
|||
const char* errorMessage = error->error_message; \ |
|||
errorMessage = errorMessage ? errorMessage : "empty error message"; \ |
|||
napi_throw_error((env), errorMessage); \ |
|||
return; \ |
|||
} |
|||
|
|||
static const char theText[] = |
|||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit."; |
|||
|
|||
static int deleterCallCount = 0; |
|||
static void deleteTheText(napi_env env, void* data, void* finalize_hint) { |
|||
JS_ASSERT(env, data != NULL && strcmp(data, theText) == 0, "invalid data"); |
|||
(void)finalize_hint; |
|||
free(data); |
|||
deleterCallCount++; |
|||
} |
|||
|
|||
static void noopDeleter(napi_env env, void* data, void* finalize_hint) { |
|||
JS_ASSERT(env, data != NULL && strcmp(data, theText) == 0, "invalid data"); |
|||
(void)finalize_hint; |
|||
deleterCallCount++; |
|||
} |
|||
|
|||
void newBuffer(napi_env env, napi_callback_info info) { |
|||
napi_value theBuffer; |
|||
char* theCopy; |
|||
const unsigned int kBufferSize = sizeof(theText); |
|||
|
|||
NAPI_CALL(env, |
|||
napi_create_buffer( |
|||
env, |
|||
sizeof(theText), |
|||
(void**)(&theCopy), |
|||
&theBuffer)); |
|||
JS_ASSERT(env, theCopy, "Failed to copy static text for newBuffer"); |
|||
memcpy(theCopy, theText, kBufferSize); |
|||
NAPI_CALL(env, napi_set_return_value(env, info, theBuffer)); |
|||
} |
|||
|
|||
void newExternalBuffer(napi_env env, napi_callback_info info) { |
|||
napi_value theBuffer; |
|||
char* theCopy = strdup(theText); |
|||
JS_ASSERT(env, theCopy, "Failed to copy static text for newExternalBuffer"); |
|||
NAPI_CALL(env, |
|||
napi_create_external_buffer( |
|||
env, |
|||
sizeof(theText), |
|||
theCopy, |
|||
deleteTheText, |
|||
NULL, // finalize_hint
|
|||
&theBuffer)); |
|||
NAPI_CALL(env, napi_set_return_value(env, info, theBuffer)); |
|||
} |
|||
|
|||
void getDeleterCallCount(napi_env env, napi_callback_info info) { |
|||
napi_value callCount; |
|||
NAPI_CALL(env, napi_create_number(env, deleterCallCount, &callCount)); |
|||
NAPI_CALL(env, napi_set_return_value(env, info, callCount)); |
|||
} |
|||
|
|||
void copyBuffer(napi_env env, napi_callback_info info) { |
|||
napi_value theBuffer; |
|||
NAPI_CALL(env, napi_create_buffer_copy( |
|||
env, sizeof(theText), theText, NULL, &theBuffer)); |
|||
NAPI_CALL(env, napi_set_return_value(env, info, theBuffer)); |
|||
} |
|||
|
|||
void bufferHasInstance(napi_env env, napi_callback_info info) { |
|||
size_t argc; |
|||
NAPI_CALL(env, napi_get_cb_args_length(env, info, &argc)); |
|||
JS_ASSERT(env, argc == 1, "Wrong number of arguments"); |
|||
napi_value theBuffer; |
|||
NAPI_CALL(env, napi_get_cb_args(env, info, &theBuffer, 1)); |
|||
bool hasInstance; |
|||
napi_valuetype theType; |
|||
NAPI_CALL(env, napi_typeof(env, theBuffer, &theType)); |
|||
JS_ASSERT(env, |
|||
theType == napi_object, |
|||
"bufferHasInstance: instance is not an object"); |
|||
NAPI_CALL(env, napi_is_buffer(env, theBuffer, &hasInstance)); |
|||
JS_ASSERT(env, hasInstance, "bufferHasInstance: instance is not a buffer"); |
|||
napi_value returnValue; |
|||
NAPI_CALL(env, napi_get_boolean(env, hasInstance, &returnValue)); |
|||
NAPI_CALL(env, napi_set_return_value(env, info, returnValue)); |
|||
} |
|||
|
|||
void bufferInfo(napi_env env, napi_callback_info info) { |
|||
size_t argc; |
|||
NAPI_CALL(env, napi_get_cb_args_length(env, info, &argc)); |
|||
JS_ASSERT(env, argc == 1, "Wrong number of arguments"); |
|||
napi_value theBuffer, returnValue; |
|||
NAPI_CALL(env, napi_get_cb_args(env, info, &theBuffer, 1)); |
|||
char* bufferData; |
|||
size_t bufferLength; |
|||
NAPI_CALL(env, |
|||
napi_get_buffer_info( |
|||
env, |
|||
theBuffer, |
|||
(void**)(&bufferData), |
|||
&bufferLength)); |
|||
NAPI_CALL(env, napi_get_boolean(env, |
|||
!strcmp(bufferData, theText) && bufferLength == sizeof(theText), |
|||
&returnValue)); |
|||
NAPI_CALL(env, napi_set_return_value(env, info, returnValue)); |
|||
} |
|||
|
|||
void staticBuffer(napi_env env, napi_callback_info info) { |
|||
napi_value theBuffer; |
|||
NAPI_CALL( |
|||
env, |
|||
napi_create_external_buffer(env, |
|||
sizeof(theText), |
|||
(void*)theText, |
|||
noopDeleter, |
|||
NULL, // finalize_hint
|
|||
&theBuffer)); |
|||
NAPI_CALL(env, napi_set_return_value(env, info, theBuffer)); |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_value theValue; |
|||
|
|||
NAPI_CALL(env, napi_create_string_utf8(env, |
|||
theText, sizeof(theText), &theValue)); |
|||
NAPI_CALL(env, napi_set_named_property(env, exports, "theText", theValue)); |
|||
|
|||
napi_property_descriptor methods[] = { |
|||
DECLARE_NAPI_METHOD("newBuffer", newBuffer), |
|||
DECLARE_NAPI_METHOD("newExternalBuffer", newExternalBuffer), |
|||
DECLARE_NAPI_METHOD("getDeleterCallCount", getDeleterCallCount), |
|||
DECLARE_NAPI_METHOD("copyBuffer", copyBuffer), |
|||
DECLARE_NAPI_METHOD("bufferHasInstance", bufferHasInstance), |
|||
DECLARE_NAPI_METHOD("bufferInfo", bufferInfo), |
|||
DECLARE_NAPI_METHOD("staticBuffer", staticBuffer), |
|||
}; |
|||
NAPI_CALL(env, |
|||
napi_define_properties( |
|||
env, exports, sizeof(methods) / sizeof(methods[0]), methods)); |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_constructor", |
|||
"sources": [ "test_constructor.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,28 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
|
|||
// Testing api calls for a constructor that defines properties
|
|||
const TestConstructor = require(`./build/${common.buildType}/test_constructor`); |
|||
const test_object = new TestConstructor(); |
|||
|
|||
assert.strictEqual(test_object.echo('hello'), 'hello'); |
|||
|
|||
test_object.readwriteValue = 1; |
|||
assert.strictEqual(test_object.readwriteValue, 1); |
|||
test_object.readwriteValue = 2; |
|||
assert.strictEqual(test_object.readwriteValue, 2); |
|||
|
|||
assert.throws(() => { test_object.readonlyValue = 3; }); |
|||
|
|||
assert.ok(test_object.hiddenValue); |
|||
|
|||
// All properties except 'hiddenValue' should be enumerable.
|
|||
const propertyNames = []; |
|||
for (const name in test_object) { |
|||
propertyNames.push(name); |
|||
} |
|||
assert.ok(propertyNames.indexOf('echo') >= 0); |
|||
assert.ok(propertyNames.indexOf('readwriteValue') >= 0); |
|||
assert.ok(propertyNames.indexOf('readonlyValue') >= 0); |
|||
assert.ok(propertyNames.indexOf('hiddenValue') < 0); |
@ -0,0 +1,104 @@ |
|||
#include <node_api.h> |
|||
|
|||
static double value_ = 1; |
|||
napi_ref constructor_; |
|||
|
|||
void GetValue(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc != 0) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value number; |
|||
status = napi_create_number(env, value_, &number); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, number); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void SetValue(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc != 1) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value arg; |
|||
status = napi_get_cb_args(env, info, &arg, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_get_value_double(env, arg, &value_); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void Echo(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc != 1) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value arg; |
|||
status = napi_get_cb_args(env, info, &arg, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, arg); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void New(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value jsthis; |
|||
status = napi_get_cb_this(env, info, &jsthis); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, jsthis); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
napi_value number; |
|||
status = napi_create_number(env, value_, &number); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_property_descriptor properties[] = { |
|||
{ "echo", Echo, 0, 0, 0, napi_default, 0 }, |
|||
{ "accessorValue", 0, GetValue, SetValue, 0, napi_default, 0}, |
|||
{ "readwriteValue", 0, 0, 0, number, napi_default, 0 }, |
|||
{ "readonlyValue", 0, 0, 0, number, napi_read_only, 0}, |
|||
{ "hiddenValue", 0, 0, 0, number, napi_read_only | napi_dont_enum, 0}, |
|||
}; |
|||
|
|||
napi_value cons; |
|||
status = napi_define_class(env, "MyObject", New, |
|||
NULL, sizeof(properties)/sizeof(*properties), properties, &cons); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_named_property(env, module, "exports", cons); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_create_reference(env, cons, 1, &constructor_); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_conversions", |
|||
"sources": [ "test_conversions.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,140 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
const test = require(`./build/${common.buildType}/test_conversions`); |
|||
|
|||
const boolExpected = /boolean was expected/; |
|||
const numberExpected = /number was expected/; |
|||
const stringExpected = /string was expected/; |
|||
|
|||
const testSym = Symbol('test'); |
|||
|
|||
assert.strictEqual(false, test.asBool(false)); |
|||
assert.strictEqual(true, test.asBool(true)); |
|||
assert.throws(() => test.asBool(undefined), boolExpected); |
|||
assert.throws(() => test.asBool(null), boolExpected); |
|||
assert.throws(() => test.asBool(Number.NaN), boolExpected); |
|||
assert.throws(() => test.asBool(0), boolExpected); |
|||
assert.throws(() => test.asBool(''), boolExpected); |
|||
assert.throws(() => test.asBool('0'), boolExpected); |
|||
assert.throws(() => test.asBool(1), boolExpected); |
|||
assert.throws(() => test.asBool('1'), boolExpected); |
|||
assert.throws(() => test.asBool('true'), boolExpected); |
|||
assert.throws(() => test.asBool({}), boolExpected); |
|||
assert.throws(() => test.asBool([]), boolExpected); |
|||
assert.throws(() => test.asBool(testSym), boolExpected); |
|||
|
|||
[test.asInt32, test.asUInt32, test.asInt64].forEach((asInt) => { |
|||
assert.strictEqual(0, asInt(0)); |
|||
assert.strictEqual(1, asInt(1)); |
|||
assert.strictEqual(1, asInt(1.0)); |
|||
assert.strictEqual(1, asInt(1.1)); |
|||
assert.strictEqual(1, asInt(1.9)); |
|||
assert.strictEqual(0, asInt(0.9)); |
|||
assert.strictEqual(999, asInt(999.9)); |
|||
assert.strictEqual(0, asInt(Number.NaN)); |
|||
assert.throws(() => asInt(undefined), numberExpected); |
|||
assert.throws(() => asInt(null), numberExpected); |
|||
assert.throws(() => asInt(false), numberExpected); |
|||
assert.throws(() => asInt(''), numberExpected); |
|||
assert.throws(() => asInt('1'), numberExpected); |
|||
assert.throws(() => asInt({}), numberExpected); |
|||
assert.throws(() => asInt([]), numberExpected); |
|||
assert.throws(() => asInt(testSym), numberExpected); |
|||
}); |
|||
|
|||
assert.strictEqual(-1, test.asInt32(-1)); |
|||
assert.strictEqual(-1, test.asInt64(-1)); |
|||
assert.strictEqual(Math.pow(2, 32) - 1, test.asUInt32(-1)); |
|||
|
|||
assert.strictEqual(0, test.asDouble(0)); |
|||
assert.strictEqual(1, test.asDouble(1)); |
|||
assert.strictEqual(1.0, test.asDouble(1.0)); |
|||
assert.strictEqual(1.1, test.asDouble(1.1)); |
|||
assert.strictEqual(1.9, test.asDouble(1.9)); |
|||
assert.strictEqual(0.9, test.asDouble(0.9)); |
|||
assert.strictEqual(999.9, test.asDouble(999.9)); |
|||
assert.strictEqual(-1, test.asDouble(-1)); |
|||
assert.ok(Number.isNaN(test.asDouble(Number.NaN))); |
|||
assert.throws(() => test.asDouble(undefined), numberExpected); |
|||
assert.throws(() => test.asDouble(null), numberExpected); |
|||
assert.throws(() => test.asDouble(false), numberExpected); |
|||
assert.throws(() => test.asDouble(''), numberExpected); |
|||
assert.throws(() => test.asDouble('1'), numberExpected); |
|||
assert.throws(() => test.asDouble({}), numberExpected); |
|||
assert.throws(() => test.asDouble([]), numberExpected); |
|||
assert.throws(() => test.asDouble(testSym), numberExpected); |
|||
|
|||
assert.strictEqual('', test.asString('')); |
|||
assert.strictEqual('test', test.asString('test')); |
|||
assert.throws(() => test.asString(undefined), stringExpected); |
|||
assert.throws(() => test.asString(null), stringExpected); |
|||
assert.throws(() => test.asString(false), stringExpected); |
|||
assert.throws(() => test.asString(1), stringExpected); |
|||
assert.throws(() => test.asString(1.1), stringExpected); |
|||
assert.throws(() => test.asString(Number.NaN), stringExpected); |
|||
assert.throws(() => test.asString({}), stringExpected); |
|||
assert.throws(() => test.asString([]), stringExpected); |
|||
assert.throws(() => test.asString(testSym), stringExpected); |
|||
|
|||
assert.strictEqual(true, test.toBool(true)); |
|||
assert.strictEqual(true, test.toBool(1)); |
|||
assert.strictEqual(true, test.toBool(-1)); |
|||
assert.strictEqual(true, test.toBool('true')); |
|||
assert.strictEqual(true, test.toBool('false')); |
|||
assert.strictEqual(true, test.toBool({})); |
|||
assert.strictEqual(true, test.toBool([])); |
|||
assert.strictEqual(true, test.toBool(testSym)); |
|||
assert.strictEqual(false, test.toBool(false)); |
|||
assert.strictEqual(false, test.toBool(undefined)); |
|||
assert.strictEqual(false, test.toBool(null)); |
|||
assert.strictEqual(false, test.toBool(0)); |
|||
assert.strictEqual(false, test.toBool(Number.NaN)); |
|||
assert.strictEqual(false, test.toBool('')); |
|||
|
|||
assert.strictEqual(0, test.toNumber(0)); |
|||
assert.strictEqual(1, test.toNumber(1)); |
|||
assert.strictEqual(1.1, test.toNumber(1.1)); |
|||
assert.strictEqual(-1, test.toNumber(-1)); |
|||
assert.strictEqual(0, test.toNumber('0')); |
|||
assert.strictEqual(1, test.toNumber('1')); |
|||
assert.strictEqual(1.1, test.toNumber('1.1')); |
|||
assert.strictEqual(0, test.toNumber([])); |
|||
assert.strictEqual(0, test.toNumber(false)); |
|||
assert.strictEqual(0, test.toNumber(null)); |
|||
assert.strictEqual(0, test.toNumber('')); |
|||
assert.ok(Number.isNaN(test.toNumber(Number.NaN))); |
|||
assert.ok(Number.isNaN(test.toNumber({}))); |
|||
assert.ok(Number.isNaN(test.toNumber(undefined))); |
|||
assert.throws(() => test.toNumber(testSym), TypeError); |
|||
|
|||
assert.deepStrictEqual({}, test.toObject({})); |
|||
assert.deepStrictEqual({ 'test': 1 }, test.toObject({ 'test': 1 })); |
|||
assert.deepStrictEqual([], test.toObject([])); |
|||
assert.deepStrictEqual([ 1, 2, 3 ], test.toObject([ 1, 2, 3 ])); |
|||
assert.deepStrictEqual(new Boolean(false), test.toObject(false)); |
|||
assert.deepStrictEqual(new Boolean(true), test.toObject(true)); |
|||
assert.deepStrictEqual(new String(''), test.toObject('')); |
|||
assert.deepStrictEqual(new Number(0), test.toObject(0)); |
|||
assert.deepStrictEqual(new Number(Number.NaN), test.toObject(Number.NaN)); |
|||
assert.deepStrictEqual(new Object(testSym), test.toObject(testSym)); |
|||
assert.notDeepStrictEqual(false, test.toObject(false)); |
|||
assert.notDeepStrictEqual(true, test.toObject(true)); |
|||
assert.notDeepStrictEqual('', test.toObject('')); |
|||
assert.notDeepStrictEqual(0, test.toObject(0)); |
|||
assert.ok(!Number.isNaN(test.toObject(Number.NaN))); |
|||
|
|||
assert.strictEqual('', test.toString('')); |
|||
assert.strictEqual('test', test.toString('test')); |
|||
assert.strictEqual('undefined', test.toString(undefined)); |
|||
assert.strictEqual('null', test.toString(null)); |
|||
assert.strictEqual('false', test.toString(false)); |
|||
assert.strictEqual('true', test.toString(true)); |
|||
assert.strictEqual('0', test.toString(0)); |
|||
assert.strictEqual('1.1', test.toString(1.1)); |
|||
assert.strictEqual('NaN', test.toString(Number.NaN)); |
|||
assert.strictEqual('[object Object]', test.toString({})); |
|||
assert.strictEqual('test', test.toString({ toString: () => 'test' })); |
|||
assert.strictEqual('', test.toString([])); |
|||
assert.strictEqual('1,2,3', test.toString([ 1, 2, 3 ])); |
|||
assert.throws(() => test.toString(testSym), TypeError); |
@ -0,0 +1,237 @@ |
|||
#include <node_api.h> |
|||
|
|||
void ThrowLastError(napi_env env) { |
|||
const napi_extended_error_info* error_info; |
|||
napi_get_last_error_info(env, &error_info); |
|||
if (error_info->error_code != napi_ok) { |
|||
napi_throw_error(env, error_info->error_message); |
|||
} |
|||
} |
|||
|
|||
void AsBool(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value input; |
|||
status = napi_get_cb_args(env, info, &input, 1); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
bool value; |
|||
status = napi_get_value_bool(env, input, &value); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
napi_value output; |
|||
status = napi_get_boolean(env, value, &output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
done: |
|||
if (status != napi_ok) ThrowLastError(env); |
|||
} |
|||
|
|||
void AsInt32(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value input; |
|||
status = napi_get_cb_args(env, info, &input, 1); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
int32_t value; |
|||
status = napi_get_value_int32(env, input, &value); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
napi_value output; |
|||
status = napi_create_number(env, value, &output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
done: |
|||
if (status != napi_ok) ThrowLastError(env); |
|||
} |
|||
|
|||
void AsUInt32(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value input; |
|||
status = napi_get_cb_args(env, info, &input, 1); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
uint32_t value; |
|||
status = napi_get_value_uint32(env, input, &value); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
napi_value output; |
|||
status = napi_create_number(env, value, &output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
done: |
|||
if (status != napi_ok) ThrowLastError(env); |
|||
} |
|||
|
|||
void AsInt64(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value input; |
|||
status = napi_get_cb_args(env, info, &input, 1); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
int64_t value; |
|||
status = napi_get_value_int64(env, input, &value); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
napi_value output; |
|||
status = napi_create_number(env, (double)value, &output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
done: |
|||
if (status != napi_ok) ThrowLastError(env); |
|||
} |
|||
|
|||
void AsDouble(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value input; |
|||
status = napi_get_cb_args(env, info, &input, 1); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
double value; |
|||
status = napi_get_value_double(env, input, &value); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
napi_value output; |
|||
status = napi_create_number(env, value, &output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
done: |
|||
if (status != napi_ok) ThrowLastError(env); |
|||
} |
|||
|
|||
void AsString(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value input; |
|||
status = napi_get_cb_args(env, info, &input, 1); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
char value[100]; |
|||
status = napi_get_value_string_utf8(env, input, value, sizeof(value), NULL); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
napi_value output; |
|||
status = napi_create_string_utf8(env, value, -1, &output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
done: |
|||
if (status != napi_ok) ThrowLastError(env); |
|||
} |
|||
|
|||
void ToBool(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value input; |
|||
status = napi_get_cb_args(env, info, &input, 1); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
napi_value output; |
|||
status = napi_coerce_to_bool(env, input, &output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
done: |
|||
if (status != napi_ok) ThrowLastError(env); |
|||
} |
|||
|
|||
void ToNumber(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value input; |
|||
status = napi_get_cb_args(env, info, &input, 1); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
napi_value output; |
|||
status = napi_coerce_to_number(env, input, &output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
done: |
|||
if (status != napi_ok) ThrowLastError(env); |
|||
} |
|||
|
|||
void ToObject(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value input; |
|||
status = napi_get_cb_args(env, info, &input, 1); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
napi_value output; |
|||
status = napi_coerce_to_object(env, input, &output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
done: |
|||
if (status != napi_ok) ThrowLastError(env); |
|||
} |
|||
|
|||
void ToString(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value input; |
|||
status = napi_get_cb_args(env, info, &input, 1); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
napi_value output; |
|||
status = napi_coerce_to_string(env, input, &output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) goto done; |
|||
|
|||
done: |
|||
if (status != napi_ok) ThrowLastError(env); |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_property_descriptor descriptors[] = { |
|||
DECLARE_NAPI_METHOD("asBool", AsBool), |
|||
DECLARE_NAPI_METHOD("asInt32", AsInt32), |
|||
DECLARE_NAPI_METHOD("asUInt32", AsUInt32), |
|||
DECLARE_NAPI_METHOD("asInt64", AsInt64), |
|||
DECLARE_NAPI_METHOD("asDouble", AsDouble), |
|||
DECLARE_NAPI_METHOD("asString", AsString), |
|||
DECLARE_NAPI_METHOD("toBool", ToBool), |
|||
DECLARE_NAPI_METHOD("toNumber", ToNumber), |
|||
DECLARE_NAPI_METHOD("toObject", ToObject), |
|||
DECLARE_NAPI_METHOD("toString", ToString), |
|||
}; |
|||
|
|||
napi_status status = napi_define_properties( |
|||
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_error", |
|||
"sources": [ "test_error.cc" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,57 @@ |
|||
'use strict'; |
|||
|
|||
const common = require('../../common'); |
|||
const test_error = require(`./build/${common.buildType}/test_error`); |
|||
const assert = require('assert'); |
|||
const theError = new Error('Some error'); |
|||
const theTypeError = new TypeError('Some type error'); |
|||
const theSyntaxError = new SyntaxError('Some syntax error'); |
|||
const theRangeError = new RangeError('Some type error'); |
|||
const theReferenceError = new ReferenceError('Some reference error'); |
|||
const theURIError = new URIError('Some URI error'); |
|||
const theEvalError = new EvalError('Some eval error'); |
|||
|
|||
class MyError extends Error { } |
|||
const myError = new MyError('Some MyError'); |
|||
|
|||
// Test that native error object is correctly classed
|
|||
assert.strictEqual(test_error.checkError(theError), true, |
|||
'Error object correctly classed by napi_is_error'); |
|||
|
|||
// Test that native type error object is correctly classed
|
|||
assert.strictEqual(test_error.checkError(theTypeError), true, |
|||
'Type error object correctly classed by napi_is_error'); |
|||
|
|||
// Test that native syntax error object is correctly classed
|
|||
assert.strictEqual(test_error.checkError(theSyntaxError), true, |
|||
'Syntax error object correctly classed by napi_is_error'); |
|||
|
|||
// Test that native range error object is correctly classed
|
|||
assert.strictEqual(test_error.checkError(theRangeError), true, |
|||
'Range error object correctly classed by napi_is_error'); |
|||
|
|||
// Test that native reference error object is correctly classed
|
|||
assert.strictEqual(test_error.checkError(theReferenceError), true, |
|||
'Reference error object correctly classed by' + |
|||
' napi_is_error'); |
|||
|
|||
// Test that native URI error object is correctly classed
|
|||
assert.strictEqual(test_error.checkError(theURIError), true, |
|||
'URI error object correctly classed by napi_is_error'); |
|||
|
|||
// Test that native eval error object is correctly classed
|
|||
assert.strictEqual(test_error.checkError(theEvalError), true, |
|||
'Eval error object correctly classed by napi_is_error'); |
|||
|
|||
// Test that class derived from native error is correctly classed
|
|||
assert.strictEqual(test_error.checkError(myError), true, |
|||
'Class derived from native error correctly classed by' + |
|||
' napi_is_error'); |
|||
|
|||
// Test that non-error object is correctly classed
|
|||
assert.strictEqual(test_error.checkError({}), false, |
|||
'Non-error object correctly classed by napi_is_error'); |
|||
|
|||
// Test that non-error primitive is correctly classed
|
|||
assert.strictEqual(test_error.checkError('non-object'), false, |
|||
'Non-error primitive correctly classed by napi_is_error'); |
@ -0,0 +1,37 @@ |
|||
#include <node_api.h> |
|||
|
|||
void checkError(napi_env e, napi_callback_info info) { |
|||
napi_status status; |
|||
napi_value jsError; |
|||
|
|||
status = napi_get_cb_args(e, info, &jsError, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
bool r; |
|||
status = napi_is_error(e, jsError, &r); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value result; |
|||
status = napi_get_boolean(e, r, &result); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(e, info, result); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
napi_property_descriptor descriptors[] = { |
|||
DECLARE_NAPI_METHOD("checkError", checkError), |
|||
}; |
|||
|
|||
status = napi_define_properties( |
|||
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_exception", |
|||
"sources": [ "test_exception.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,53 @@ |
|||
'use strict'; |
|||
|
|||
const common = require('../../common'); |
|||
const test_exception = require(`./build/${common.buildType}/test_exception`); |
|||
const assert = require('assert'); |
|||
const theError = new Error('Some error'); |
|||
const throwTheError = function() { |
|||
throw theError; |
|||
}; |
|||
let caughtError; |
|||
|
|||
const throwNoError = function() {}; |
|||
|
|||
// Test that the native side successfully captures the exception
|
|||
let returnedError = test_exception.returnException(throwTheError); |
|||
assert.strictEqual(theError, returnedError, |
|||
'Returned error is strictly equal to the thrown error'); |
|||
|
|||
// Test that the native side passes the exception through
|
|||
assert.throws( |
|||
() => { |
|||
test_exception.allowException(throwTheError); |
|||
}, |
|||
function(err) { |
|||
return err === theError; |
|||
}, |
|||
'Thrown exception was allowed to pass through unhindered' |
|||
); |
|||
|
|||
// Test that the exception thrown above was marked as pending
|
|||
// before it was handled on the JS side
|
|||
assert.strictEqual(test_exception.wasPending(), true, |
|||
'VM was marked as having an exception pending' + |
|||
' when it was allowed through'); |
|||
|
|||
// Test that the native side does not capture a non-existing exception
|
|||
returnedError = test_exception.returnException(throwNoError); |
|||
assert.strictEqual(undefined, returnedError, |
|||
'Returned error is undefined when no exception is thrown'); |
|||
|
|||
// Test that no exception appears that was not thrown by us
|
|||
try { |
|||
test_exception.allowException(throwNoError); |
|||
} catch (anError) { |
|||
caughtError = anError; |
|||
} |
|||
assert.strictEqual(undefined, caughtError, |
|||
'No exception originated on the native side'); |
|||
|
|||
// Test that the exception state remains clear when no exception is thrown
|
|||
assert.strictEqual(test_exception.wasPending(), false, |
|||
'VM was not marked as having an exception pending' + |
|||
' when none was allowed through'); |
@ -0,0 +1,75 @@ |
|||
#include <node_api.h> |
|||
|
|||
static bool exceptionWasPending = false; |
|||
|
|||
void returnException(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
napi_value jsFunction; |
|||
|
|||
status = napi_get_cb_args(env, info, &jsFunction, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value global; |
|||
status = napi_get_global(env, &global); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value result; |
|||
status = napi_call_function(env, global, jsFunction, 0, 0, &result); |
|||
if (status == napi_pending_exception) { |
|||
napi_value ex; |
|||
status = napi_get_and_clear_last_exception(env, &ex); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, ex); |
|||
if (status != napi_ok) return; |
|||
} |
|||
} |
|||
|
|||
void allowException(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
napi_value jsFunction; |
|||
|
|||
status = napi_get_cb_args(env, info, &jsFunction, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value global; |
|||
status = napi_get_global(env, &global); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value result; |
|||
status = napi_call_function(env, global, jsFunction, 0, 0, &result); |
|||
// Ignore status and check napi_is_exception_pending() instead.
|
|||
|
|||
status = napi_is_exception_pending(env, &exceptionWasPending); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void wasPending(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value result; |
|||
status = napi_get_boolean(env, exceptionWasPending, &result); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, result); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
napi_property_descriptor descriptors[] = { |
|||
DECLARE_NAPI_METHOD("returnException", returnException), |
|||
DECLARE_NAPI_METHOD("allowException", allowException), |
|||
DECLARE_NAPI_METHOD("wasPending", wasPending), |
|||
}; |
|||
|
|||
status = napi_define_properties( |
|||
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_function", |
|||
"sources": [ "test_function.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,28 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
|
|||
// testing api calls for function
|
|||
const test_function = require(`./build/${common.buildType}/test_function`); |
|||
|
|||
|
|||
function func1() { |
|||
return 1; |
|||
} |
|||
assert.strictEqual(test_function.Test(func1), 1); |
|||
|
|||
function func2() { |
|||
console.log('hello world!'); |
|||
return null; |
|||
} |
|||
assert.strictEqual(test_function.Test(func2), null); |
|||
|
|||
function func3(input) { |
|||
return input + 1; |
|||
} |
|||
assert.strictEqual(test_function.Test(func3, 1), 2); |
|||
|
|||
function func4(input) { |
|||
return func3(input); |
|||
} |
|||
assert.strictEqual(test_function.Test(func4, 1), 2); |
@ -0,0 +1,55 @@ |
|||
#include <node_api.h> |
|||
|
|||
void Test(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc < 1) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[10]; |
|||
status = napi_get_cb_args(env, info, args, 10); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype; |
|||
status = napi_typeof(env, args[0], &valuetype); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype != napi_function) { |
|||
napi_throw_type_error(env, "Wrong type of argments. Expects a function."); |
|||
return; |
|||
} |
|||
|
|||
napi_value function = args[0]; |
|||
napi_value* argv = args + 1; |
|||
argc = argc - 1; |
|||
|
|||
napi_value global; |
|||
status = napi_get_global(env, &global); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value result; |
|||
status = napi_call_function(env, global, function, argc, argv, &result); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, result); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
napi_value fn; |
|||
status = napi_create_function(env, NULL, Test, NULL, &fn); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_named_property(env, exports, "Test", fn); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_instanceof", |
|||
"sources": [ "test_instanceof.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,87 @@ |
|||
'use strict'; |
|||
const fs = require('fs'); |
|||
|
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
|
|||
// addon is referenced through the eval expression in testFile
|
|||
// eslint-disable-next-line no-unused-vars
|
|||
const addon = require(`./build/${common.buildType}/test_instanceof`); |
|||
const path = require('path'); |
|||
|
|||
// The following assert functions are referenced by v8's unit tests
|
|||
// See for instance deps/v8/test/mjsunit/instanceof.js
|
|||
// eslint-disable-next-line no-unused-vars
|
|||
function assertTrue(assertion) { |
|||
return assert.strictEqual(true, assertion); |
|||
} |
|||
|
|||
// eslint-disable-next-line no-unused-vars
|
|||
function assertFalse(assertion) { |
|||
assert.strictEqual(false, assertion); |
|||
} |
|||
|
|||
// eslint-disable-next-line no-unused-vars
|
|||
function assertEquals(leftHandSide, rightHandSide) { |
|||
assert.strictEqual(leftHandSide, rightHandSide); |
|||
} |
|||
|
|||
// eslint-disable-next-line no-unused-vars
|
|||
function assertThrows(statement) { |
|||
assert.throws(function() { |
|||
eval(statement); |
|||
}, Error); |
|||
} |
|||
|
|||
function testFile(fileName) { |
|||
const contents = fs.readFileSync(fileName, { encoding: 'utf8' }); |
|||
eval(contents.replace(/[(]([^\s(]+)\s+instanceof\s+([^)]+)[)]/g, |
|||
'(addon.doInstanceOf($1, $2))')); |
|||
} |
|||
|
|||
testFile( |
|||
path.join(path.resolve(__dirname, '..', '..', '..', |
|||
'deps', 'v8', 'test', 'mjsunit'), |
|||
'instanceof.js')); |
|||
testFile( |
|||
path.join(path.resolve(__dirname, '..', '..', '..', |
|||
'deps', 'v8', 'test', 'mjsunit'), |
|||
'instanceof-2.js')); |
|||
|
|||
// We can only perform this test if we have a working Symbol.hasInstance
|
|||
if (typeof Symbol !== 'undefined' && 'hasInstance' in Symbol && |
|||
typeof Symbol.hasInstance === 'symbol') { |
|||
|
|||
function compareToNative(theObject, theConstructor) { |
|||
assert.strictEqual(addon.doInstanceOf(theObject, theConstructor), |
|||
(theObject instanceof theConstructor)); |
|||
} |
|||
|
|||
const MyClass = function MyClass() {}; |
|||
Object.defineProperty(MyClass, Symbol.hasInstance, { |
|||
value: function(candidate) { |
|||
return 'mark' in candidate; |
|||
} |
|||
}); |
|||
|
|||
const MySubClass = function MySubClass() {}; |
|||
MySubClass.prototype = new MyClass(); |
|||
|
|||
let x = new MySubClass(); |
|||
let y = new MySubClass(); |
|||
x.mark = true; |
|||
|
|||
compareToNative(x, MySubClass); |
|||
compareToNative(y, MySubClass); |
|||
compareToNative(x, MyClass); |
|||
compareToNative(y, MyClass); |
|||
|
|||
x = new MyClass(); |
|||
y = new MyClass(); |
|||
x.mark = true; |
|||
|
|||
compareToNative(x, MySubClass); |
|||
compareToNative(y, MySubClass); |
|||
compareToNative(x, MyClass); |
|||
compareToNative(y, MyClass); |
|||
} |
@ -0,0 +1,39 @@ |
|||
#include <node_api.h> |
|||
#include <stdio.h> |
|||
|
|||
void doInstanceOf(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value arguments[2]; |
|||
|
|||
status = napi_get_cb_args(env, info, arguments, 2); |
|||
if (status != napi_ok) return; |
|||
|
|||
bool instanceof; |
|||
status = napi_instanceof(env, arguments[0], arguments[1], &instanceof); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value result; |
|||
status = napi_get_boolean(env, instanceof, &result); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, result); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
napi_property_descriptor descriptors[] = { |
|||
DECLARE_NAPI_METHOD("doInstanceOf", doInstanceOf), |
|||
}; |
|||
|
|||
status = napi_define_properties( |
|||
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_number", |
|||
"sources": [ "test_number.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,39 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
const test_number = require(`./build/${common.buildType}/test_number`); |
|||
|
|||
|
|||
// testing api calls for number
|
|||
assert.strictEqual(0, test_number.Test(0)); |
|||
assert.strictEqual(1, test_number.Test(1)); |
|||
assert.strictEqual(-1, test_number.Test(-1)); |
|||
assert.strictEqual(100, test_number.Test(100)); |
|||
assert.strictEqual(2121, test_number.Test(2121)); |
|||
assert.strictEqual(-1233, test_number.Test(-1233)); |
|||
assert.strictEqual(986583, test_number.Test(986583)); |
|||
assert.strictEqual(-976675, test_number.Test(-976675)); |
|||
|
|||
const num1 = 98765432213456789876546896323445679887645323232436587988766545658; |
|||
assert.strictEqual(num1, test_number.Test(num1)); |
|||
|
|||
const num2 = -4350987086545760976737453646576078997096876957864353245245769809; |
|||
assert.strictEqual(num2, test_number.Test(num2)); |
|||
|
|||
const num3 = Number.MAX_SAFE_INTEGER; |
|||
assert.strictEqual(num3, test_number.Test(num3)); |
|||
|
|||
const num4 = Number.MAX_SAFE_INTEGER + 10; |
|||
assert.strictEqual(num4, test_number.Test(num4)); |
|||
|
|||
const num5 = Number.MAX_VALUE; |
|||
assert.strictEqual(num5, test_number.Test(num5)); |
|||
|
|||
const num6 = Number.MAX_VALUE + 10; |
|||
assert.strictEqual(num6, test_number.Test(num6)); |
|||
|
|||
const num7 = Number.POSITIVE_INFINITY; |
|||
assert.strictEqual(num7, test_number.Test(num7)); |
|||
|
|||
const num8 = Number.NEGATIVE_INFINITY; |
|||
assert.strictEqual(num8, test_number.Test(num8)); |
@ -0,0 +1,55 @@ |
|||
#include <node_api.h> |
|||
|
|||
void Test(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc < 1) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype; |
|||
status = napi_typeof(env, args[0], &valuetype); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype != napi_number) { |
|||
napi_throw_type_error(env, "Wrong type of argments. Expects a number."); |
|||
return; |
|||
} |
|||
|
|||
double input; |
|||
status = napi_get_value_double(env, args[0], &input); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value output; |
|||
status = napi_create_number(env, input, &output); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
napi_property_descriptor descriptors[] = { |
|||
DECLARE_NAPI_METHOD("Test", Test), |
|||
}; |
|||
|
|||
status = napi_define_properties( |
|||
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_object", |
|||
"sources": [ "test_object.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,65 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
|
|||
// Testing api calls for objects
|
|||
const test_object = require(`./build/${common.buildType}/test_object`); |
|||
|
|||
|
|||
const object = { |
|||
hello: 'world', |
|||
array: [ |
|||
1, 94, 'str', 12.321, { test: 'obj in arr' } |
|||
], |
|||
newObject: { |
|||
test: 'obj in obj' |
|||
} |
|||
}; |
|||
|
|||
assert.strictEqual(test_object.Get(object, 'hello'), 'world'); |
|||
assert.deepStrictEqual(test_object.Get(object, 'array'), |
|||
[ 1, 94, 'str', 12.321, { test: 'obj in arr' } ]); |
|||
assert.deepStrictEqual(test_object.Get(object, 'newObject'), |
|||
{ test: 'obj in obj' }); |
|||
|
|||
assert(test_object.Has(object, 'hello')); |
|||
assert(test_object.Has(object, 'array')); |
|||
assert(test_object.Has(object, 'newObject')); |
|||
|
|||
const newObject = test_object.New(); |
|||
assert(test_object.Has(newObject, 'test_number')); |
|||
assert.strictEqual(newObject.test_number, 987654321); |
|||
assert.strictEqual(newObject.test_string, 'test string'); |
|||
|
|||
// test_object.Inflate increases all properties by 1
|
|||
const cube = { |
|||
x: 10, |
|||
y: 10, |
|||
z: 10 |
|||
}; |
|||
|
|||
assert.deepStrictEqual(test_object.Inflate(cube), {x: 11, y: 11, z: 11}); |
|||
assert.deepStrictEqual(test_object.Inflate(cube), {x: 12, y: 12, z: 12}); |
|||
assert.deepStrictEqual(test_object.Inflate(cube), {x: 13, y: 13, z: 13}); |
|||
cube.t = 13; |
|||
assert.deepStrictEqual(test_object.Inflate(cube), {x: 14, y: 14, z: 14, t: 14}); |
|||
|
|||
const sym1 = Symbol('1'); |
|||
const sym2 = Symbol('2'); |
|||
const sym3 = Symbol('3'); |
|||
const sym4 = Symbol('4'); |
|||
const object2 = { |
|||
[sym1]: '@@iterator', |
|||
[sym2]: sym3 |
|||
}; |
|||
|
|||
assert(test_object.Has(object2, sym1)); |
|||
assert(test_object.Has(object2, sym2)); |
|||
assert.strictEqual(test_object.Get(object2, sym1), '@@iterator'); |
|||
assert.strictEqual(test_object.Get(object2, sym2), sym3); |
|||
assert(test_object.Set(object2, 'string', 'value')); |
|||
assert(test_object.Set(object2, sym4, 123)); |
|||
assert(test_object.Has(object2, 'string')); |
|||
assert(test_object.Has(object2, sym4)); |
|||
assert.strictEqual(test_object.Get(object2, 'string'), 'value'); |
|||
assert.strictEqual(test_object.Get(object2, sym4), 123); |
@ -0,0 +1,246 @@ |
|||
#include <node_api.h> |
|||
|
|||
void Get(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc < 2) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[2]; |
|||
status = napi_get_cb_args(env, info, args, 2); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype0; |
|||
status = napi_typeof(env, args[0], &valuetype0); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype0 != napi_object) { |
|||
napi_throw_type_error( |
|||
env, "Wrong type of argments. Expects an object as first argument."); |
|||
return; |
|||
} |
|||
|
|||
napi_valuetype valuetype1; |
|||
status = napi_typeof(env, args[1], &valuetype1); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype1 != napi_string && valuetype1 != napi_symbol) { |
|||
napi_throw_type_error(env, |
|||
"Wrong type of argments. Expects a string or symbol as second."); |
|||
return; |
|||
} |
|||
|
|||
napi_value object = args[0]; |
|||
napi_value output; |
|||
status = napi_get_property(env, object, args[1], &output); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void Set(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc < 3) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[3]; |
|||
status = napi_get_cb_args(env, info, args, 3); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype0; |
|||
status = napi_typeof(env, args[0], &valuetype0); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype0 != napi_object) { |
|||
napi_throw_type_error(env, |
|||
"Wrong type of argments. Expects an object as first argument."); |
|||
return; |
|||
} |
|||
|
|||
napi_valuetype valuetype1; |
|||
status = napi_typeof(env, args[1], &valuetype1); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype1 != napi_string && valuetype1 != napi_symbol) { |
|||
napi_throw_type_error(env, |
|||
"Wrong type of argments. Expects a string or symbol as second."); |
|||
return; |
|||
} |
|||
|
|||
napi_value object = args[0]; |
|||
status = napi_set_property(env, object, args[1], args[2]); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value valuetrue; |
|||
status = napi_get_boolean(env, true, &valuetrue); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, valuetrue); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void Has(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc < 2) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[2]; |
|||
status = napi_get_cb_args(env, info, args, 2); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype0; |
|||
status = napi_typeof(env, args[0], &valuetype0); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype0 != napi_object) { |
|||
napi_throw_type_error( |
|||
env, "Wrong type of argments. Expects an object as first argument."); |
|||
return; |
|||
} |
|||
|
|||
napi_valuetype valuetype1; |
|||
status = napi_typeof(env, args[1], &valuetype1); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype1 != napi_string && valuetype1 != napi_symbol) { |
|||
napi_throw_type_error(env, |
|||
"Wrong type of argments. Expects a string or symbol as second."); |
|||
return; |
|||
} |
|||
|
|||
napi_value obj = args[0]; |
|||
bool has_property; |
|||
status = napi_has_property(env, obj, args[1], &has_property); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value ret; |
|||
status = napi_get_boolean(env, has_property, &ret); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, ret); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void New(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
napi_value ret; |
|||
status = napi_create_object(env, &ret); |
|||
|
|||
napi_value num; |
|||
status = napi_create_number(env, 987654321, &num); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_named_property(env, ret, "test_number", num); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value str; |
|||
status = napi_create_string_utf8(env, "test string", -1, &str); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_named_property(env, ret, "test_string", str); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, ret); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void Inflate(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc < 1) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype; |
|||
status = napi_typeof(env, args[0], &valuetype); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype != napi_object) { |
|||
napi_throw_type_error( |
|||
env, "Wrong type of argments. Expects an object as first argument."); |
|||
return; |
|||
} |
|||
|
|||
napi_value obj = args[0]; |
|||
|
|||
napi_value propertynames; |
|||
status = napi_get_property_names(env, obj, &propertynames); |
|||
if (status != napi_ok) return; |
|||
|
|||
uint32_t i, length; |
|||
status = napi_get_array_length(env, propertynames, &length); |
|||
if (status != napi_ok) return; |
|||
|
|||
for (i = 0; i < length; i++) { |
|||
napi_value property_str; |
|||
status = napi_get_element(env, propertynames, i, &property_str); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value value; |
|||
status = napi_get_property(env, obj, property_str, &value); |
|||
if (status != napi_ok) return; |
|||
|
|||
double double_val; |
|||
status = napi_get_value_double(env, value, &double_val); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_create_number(env, double_val + 1, &value); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_property(env, obj, property_str, value); |
|||
if (status != napi_ok) return; |
|||
} |
|||
status = napi_set_return_value(env, info, obj); |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
napi_property_descriptor descriptors[] = { |
|||
DECLARE_NAPI_METHOD("Get", Get), |
|||
DECLARE_NAPI_METHOD("Set", Set), |
|||
DECLARE_NAPI_METHOD("Has", Has), |
|||
DECLARE_NAPI_METHOD("New", New), |
|||
DECLARE_NAPI_METHOD("Inflate", Inflate), |
|||
}; |
|||
|
|||
status = napi_define_properties( |
|||
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_properties", |
|||
"sources": [ "test_properties.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,27 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
|
|||
// Testing api calls for defining properties
|
|||
const test_object = require(`./build/${common.buildType}/test_properties`); |
|||
|
|||
assert.strictEqual(test_object.echo('hello'), 'hello'); |
|||
|
|||
test_object.readwriteValue = 1; |
|||
assert.strictEqual(test_object.readwriteValue, 1); |
|||
test_object.readwriteValue = 2; |
|||
assert.strictEqual(test_object.readwriteValue, 2); |
|||
|
|||
assert.throws(() => { test_object.readonlyValue = 3; }); |
|||
|
|||
assert.ok(test_object.hiddenValue); |
|||
|
|||
// All properties except 'hiddenValue' should be enumerable.
|
|||
const propertyNames = []; |
|||
for (const name in test_object) { |
|||
propertyNames.push(name); |
|||
} |
|||
assert.ok(propertyNames.indexOf('echo') >= 0); |
|||
assert.ok(propertyNames.indexOf('readwriteValue') >= 0); |
|||
assert.ok(propertyNames.indexOf('readonlyValue') >= 0); |
|||
assert.ok(propertyNames.indexOf('hiddenValue') < 0); |
@ -0,0 +1,85 @@ |
|||
#include <node_api.h> |
|||
|
|||
static double value_ = 1; |
|||
|
|||
void GetValue(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc != 0) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value number; |
|||
status = napi_create_number(env, value_, &number); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, number); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void SetValue(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc != 1) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value arg; |
|||
status = napi_get_cb_args(env, info, &arg, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_get_value_double(env, arg, &value_); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void Echo(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc != 1) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value arg; |
|||
status = napi_get_cb_args(env, info, &arg, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, arg); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
napi_value number; |
|||
status = napi_create_number(env, value_, &number); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_property_descriptor properties[] = { |
|||
{ "echo", Echo, 0, 0, 0, napi_default, 0 }, |
|||
{ "accessorValue", 0, GetValue, SetValue, 0, napi_default, 0 }, |
|||
{ "readwriteValue", 0, 0, 0, number, napi_default, 0 }, |
|||
{ "readonlyValue", 0, 0, 0, number, napi_read_only, 0 }, |
|||
{ "hiddenValue", 0, 0, 0, number, napi_read_only | napi_dont_enum, 0 }, |
|||
}; |
|||
|
|||
status = napi_define_properties( |
|||
env, exports, sizeof(properties) / sizeof(*properties), properties); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_string", |
|||
"sources": [ "test_string.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,26 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
|
|||
// testing api calls for string
|
|||
const test_string = require(`./build/${common.buildType}/test_string`); |
|||
|
|||
const str1 = 'hello world'; |
|||
assert.strictEqual(test_string.Copy(str1), str1); |
|||
assert.strictEqual(test_string.Length(str1), 11); |
|||
assert.strictEqual(test_string.Utf8Length(str1), 11); |
|||
|
|||
const str2 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; |
|||
assert.strictEqual(test_string.Copy(str2), str2); |
|||
assert.strictEqual(test_string.Length(str2), 62); |
|||
assert.strictEqual(test_string.Utf8Length(str2), 62); |
|||
|
|||
const str3 = '?!@#$%^&*()_+-=[]{}/.,<>\'"\\'; |
|||
assert.strictEqual(test_string.Copy(str3), str3); |
|||
assert.strictEqual(test_string.Length(str3), 27); |
|||
assert.strictEqual(test_string.Utf8Length(str3), 27); |
|||
|
|||
const str4 = '\u{2003}\u{2101}\u{2001}'; |
|||
assert.strictEqual(test_string.Copy(str4), str4); |
|||
assert.strictEqual(test_string.Length(str4), 3); |
|||
assert.strictEqual(test_string.Utf8Length(str4), 9); |
@ -0,0 +1,134 @@ |
|||
#include <node_api.h> |
|||
|
|||
void Copy(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc < 1) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype; |
|||
status = napi_typeof(env, args[0], &valuetype); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype != napi_string) { |
|||
napi_throw_type_error(env, "Wrong type of argments. Expects a string."); |
|||
return; |
|||
} |
|||
|
|||
char buffer[128]; |
|||
int buffer_size = 128; |
|||
|
|||
status = |
|||
napi_get_value_string_utf8(env, args[0], buffer, buffer_size, NULL); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value output; |
|||
status = napi_create_string_utf8(env, buffer, -1, &output); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void Length(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc < 1) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype; |
|||
status = napi_typeof(env, args[0], &valuetype); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype != napi_string) { |
|||
napi_throw_type_error(env, "Wrong type of argments. Expects a string."); |
|||
return; |
|||
} |
|||
|
|||
size_t length; |
|||
status = napi_get_value_string_length(env, args[0], &length); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value output; |
|||
status = napi_create_number(env, (double)length, &output); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void Utf8Length(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc < 1) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype; |
|||
status = napi_typeof(env, args[0], &valuetype); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype != napi_string) { |
|||
napi_throw_type_error(env, "Wrong type of argments. Expects a string."); |
|||
return; |
|||
} |
|||
|
|||
size_t length; |
|||
status = napi_get_value_string_utf8(env, args[0], NULL, 0, &length); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value output; |
|||
status = napi_create_number(env, (double)length, &output); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
napi_property_descriptor properties[] = { |
|||
DECLARE_NAPI_METHOD("Copy", Copy), |
|||
DECLARE_NAPI_METHOD("Length", Length), |
|||
DECLARE_NAPI_METHOD("Utf8Length", Utf8Length), |
|||
}; |
|||
|
|||
status = napi_define_properties( |
|||
env, exports, sizeof(properties) / sizeof(*properties), properties); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_symbol", |
|||
"sources": [ "test_symbol.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,20 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
|
|||
// testing api calls for symbol
|
|||
const test_symbol = require(`./build/${common.buildType}/test_symbol`); |
|||
|
|||
const sym = test_symbol.New('test'); |
|||
assert.strictEqual(sym.toString(), 'Symbol(test)'); |
|||
|
|||
|
|||
const myObj = {}; |
|||
const fooSym = test_symbol.New('foo'); |
|||
const otherSym = test_symbol.New('bar'); |
|||
myObj['foo'] = 'bar'; |
|||
myObj[fooSym] = 'baz'; |
|||
myObj[otherSym] = 'bing'; |
|||
assert.strictEqual(myObj.foo, 'bar'); |
|||
assert.strictEqual(myObj[fooSym], 'baz'); |
|||
assert.strictEqual(myObj[otherSym], 'bing'); |
@ -0,0 +1,15 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
|
|||
// testing api calls for symbol
|
|||
const test_symbol = require(`./build/${common.buildType}/test_symbol`); |
|||
|
|||
const fooSym = test_symbol.New('foo'); |
|||
const myObj = {}; |
|||
myObj['foo'] = 'bar'; |
|||
myObj[fooSym] = 'baz'; |
|||
Object.keys(myObj); // -> [ 'foo' ]
|
|||
Object.getOwnPropertyNames(myObj); // -> [ 'foo' ]
|
|||
Object.getOwnPropertySymbols(myObj); // -> [ Symbol(foo) ]
|
|||
assert.strictEqual(Object.getOwnPropertySymbols(myObj)[0], fooSym); |
@ -0,0 +1,19 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
|
|||
// testing api calls for symbol
|
|||
const test_symbol = require(`./build/${common.buildType}/test_symbol`); |
|||
|
|||
assert.notStrictEqual(test_symbol.New(), test_symbol.New()); |
|||
assert.notStrictEqual(test_symbol.New('foo'), test_symbol.New('foo')); |
|||
assert.notStrictEqual(test_symbol.New('foo'), test_symbol.New('bar')); |
|||
|
|||
const foo1 = test_symbol.New('foo'); |
|||
const foo2 = test_symbol.New('foo'); |
|||
const object = { |
|||
[foo1]: 1, |
|||
[foo2]: 2, |
|||
}; |
|||
assert.strictEqual(object[foo1], 1); |
|||
assert.strictEqual(object[foo2], 2); |
@ -0,0 +1,94 @@ |
|||
#include <node_api.h> |
|||
|
|||
void Test(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc < 1) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[1]; |
|||
status = napi_get_cb_args(env, info, args, 1); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype; |
|||
status = napi_typeof(env, args[0], &valuetype); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype != napi_symbol) { |
|||
napi_throw_type_error(env, "Wrong type of argments. Expects a symbol."); |
|||
return; |
|||
} |
|||
|
|||
char buffer[128]; |
|||
int buffer_size = 128; |
|||
|
|||
status = |
|||
napi_get_value_string_utf8(env, args[0], buffer, buffer_size, NULL); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value output; |
|||
status = napi_create_string_utf8(env, buffer, -1, &output); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, output); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void New(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc >= 1) { |
|||
napi_value args[1]; |
|||
napi_get_cb_args(env, info, args, 1); |
|||
|
|||
napi_valuetype valuetype; |
|||
status = napi_typeof(env, args[0], &valuetype); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype != napi_string) { |
|||
napi_throw_type_error(env, "Wrong type of argments. Expects a string."); |
|||
return; |
|||
} |
|||
|
|||
napi_value symbol; |
|||
status = napi_create_symbol(env, args[0], &symbol); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, symbol); |
|||
if (status != napi_ok) return; |
|||
} else { |
|||
napi_value symbol; |
|||
status = napi_create_symbol(env, NULL, &symbol); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, symbol); |
|||
if (status != napi_ok) return; |
|||
} |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
napi_property_descriptor properties[] = { |
|||
DECLARE_NAPI_METHOD("New", New), |
|||
}; |
|||
|
|||
status = napi_define_properties( |
|||
env, exports, sizeof(properties) / sizeof(*properties), properties); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,8 @@ |
|||
{ |
|||
"targets": [ |
|||
{ |
|||
"target_name": "test_typedarray", |
|||
"sources": [ "test_typedarray.c" ] |
|||
} |
|||
] |
|||
} |
@ -0,0 +1,39 @@ |
|||
'use strict'; |
|||
const common = require('../../common'); |
|||
const assert = require('assert'); |
|||
|
|||
// Testing api calls for arrays
|
|||
const test_typedarray = require(`./build/${common.buildType}/test_typedarray`); |
|||
|
|||
const byteArray = new Uint8Array(3); |
|||
byteArray[0] = 0; |
|||
byteArray[1] = 1; |
|||
byteArray[2] = 2; |
|||
assert.strictEqual(byteArray.length, 3); |
|||
|
|||
const doubleArray = new Float64Array(3); |
|||
doubleArray[0] = 0.0; |
|||
doubleArray[1] = 1.1; |
|||
doubleArray[2] = 2.2; |
|||
assert.strictEqual(doubleArray.length, 3); |
|||
|
|||
const byteResult = test_typedarray.Multiply(byteArray, 3); |
|||
assert.ok(byteResult instanceof Uint8Array); |
|||
assert.strictEqual(byteResult.length, 3); |
|||
assert.strictEqual(byteResult[0], 0); |
|||
assert.strictEqual(byteResult[1], 3); |
|||
assert.strictEqual(byteResult[2], 6); |
|||
|
|||
const doubleResult = test_typedarray.Multiply(doubleArray, -3); |
|||
assert.ok(doubleResult instanceof Float64Array); |
|||
assert.strictEqual(doubleResult.length, 3); |
|||
assert.strictEqual(doubleResult[0], 0); |
|||
assert.strictEqual(Math.round(10 * doubleResult[1]) / 10, -3.3); |
|||
assert.strictEqual(Math.round(10 * doubleResult[2]) / 10, -6.6); |
|||
|
|||
const externalResult = test_typedarray.External(); |
|||
assert.ok(externalResult instanceof Int8Array); |
|||
assert.strictEqual(externalResult.length, 3); |
|||
assert.strictEqual(externalResult[0], 0); |
|||
assert.strictEqual(externalResult[1], 1); |
|||
assert.strictEqual(externalResult[2], 2); |
@ -0,0 +1,144 @@ |
|||
#include <node_api.h> |
|||
#include <string.h> |
|||
|
|||
void Multiply(napi_env env, napi_callback_info info) { |
|||
napi_status status; |
|||
|
|||
size_t argc; |
|||
status = napi_get_cb_args_length(env, info, &argc); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (argc != 2) { |
|||
napi_throw_type_error(env, "Wrong number of arguments"); |
|||
return; |
|||
} |
|||
|
|||
napi_value args[2]; |
|||
status = napi_get_cb_args(env, info, args, 2); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_valuetype valuetype0; |
|||
status = napi_typeof(env, args[0], &valuetype0); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype0 != napi_object) { |
|||
napi_throw_type_error( |
|||
env, |
|||
"Wrong type of argments. Expects a typed array as first argument."); |
|||
return; |
|||
} |
|||
|
|||
napi_value input_array = args[0]; |
|||
bool istypedarray; |
|||
status = napi_is_typedarray(env, input_array, &istypedarray); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (!istypedarray) { |
|||
napi_throw_type_error( |
|||
env, |
|||
"Wrong type of argments. Expects a typed array as first argument."); |
|||
return; |
|||
} |
|||
|
|||
napi_valuetype valuetype1; |
|||
status = napi_typeof(env, args[1], &valuetype1); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (valuetype1 != napi_number) { |
|||
napi_throw_type_error( |
|||
env, "Wrong type of argments. Expects a number as second argument."); |
|||
return; |
|||
} |
|||
|
|||
double multiplier; |
|||
status = napi_get_value_double(env, args[1], &multiplier); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_typedarray_type type; |
|||
napi_value input_buffer; |
|||
size_t byte_offset; |
|||
size_t i, length; |
|||
status = napi_get_typedarray_info( |
|||
env, input_array, &type, &length, NULL, &input_buffer, &byte_offset); |
|||
if (status != napi_ok) return; |
|||
|
|||
void* data; |
|||
size_t byte_length; |
|||
status = napi_get_arraybuffer_info(env, input_buffer, &data, &byte_length); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value output_buffer; |
|||
void* output_ptr = NULL; |
|||
status = |
|||
napi_create_arraybuffer(env, byte_length, &output_ptr, &output_buffer); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value output_array; |
|||
status = napi_create_typedarray( |
|||
env, type, length, output_buffer, byte_offset, &output_array); |
|||
if (status != napi_ok) return; |
|||
|
|||
if (type == napi_uint8_array) { |
|||
uint8_t* input_bytes = (uint8_t*)(data) + byte_offset; |
|||
uint8_t* output_bytes = (uint8_t*)(output_ptr); |
|||
for (i = 0; i < length; i++) { |
|||
output_bytes[i] = (uint8_t)(input_bytes[i] * multiplier); |
|||
} |
|||
} else if (type == napi_float64_array) { |
|||
double* input_doubles = (double*)((uint8_t*)(data) + byte_offset); |
|||
double* output_doubles = (double*)(output_ptr); |
|||
for (i = 0; i < length; i++) { |
|||
output_doubles[i] = input_doubles[i] * multiplier; |
|||
} |
|||
} else { |
|||
napi_throw_error(env, "Typed array was of a type not expected by test."); |
|||
return; |
|||
} |
|||
|
|||
status = napi_set_return_value(env, info, output_array); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
void External(napi_env env, napi_callback_info info) { |
|||
static int8_t externalData[] = {0, 1, 2}; |
|||
|
|||
napi_value output_buffer; |
|||
napi_status status = napi_create_external_arraybuffer( |
|||
env, |
|||
externalData, |
|||
sizeof(externalData), |
|||
NULL, // finalize_callback
|
|||
NULL, // finalize_hint
|
|||
&output_buffer); |
|||
if (status != napi_ok) return; |
|||
|
|||
napi_value output_array; |
|||
status = napi_create_typedarray(env, |
|||
napi_int8_array, |
|||
sizeof(externalData) / sizeof(uint8_t), |
|||
output_buffer, |
|||
0, |
|||
&output_array); |
|||
if (status != napi_ok) return; |
|||
|
|||
status = napi_set_return_value(env, info, output_array); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
#define DECLARE_NAPI_METHOD(name, func) \ |
|||
{ name, func, 0, 0, 0, napi_default, 0 } |
|||
|
|||
void Init(napi_env env, napi_value exports, napi_value module, void* priv) { |
|||
napi_status status; |
|||
|
|||
napi_property_descriptor descriptors[] = { |
|||
DECLARE_NAPI_METHOD("Multiply", Multiply), |
|||
DECLARE_NAPI_METHOD("External", External), |
|||
}; |
|||
|
|||
status = napi_define_properties( |
|||
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors); |
|||
if (status != napi_ok) return; |
|||
} |
|||
|
|||
NAPI_MODULE(addon, Init) |
@ -0,0 +1,6 @@ |
|||
import sys, os |
|||
sys.path.append(os.path.join(os.path.dirname(__file__), '..')) |
|||
import testpy |
|||
|
|||
def GetConfiguration(context, root): |
|||
return testpy.AddonTestConfiguration(context, root, 'addons-napi', ['--napi-modules']) |
Loading…
Reference in new issue