Compare commits

...

9 Commits

Author SHA1 Message Date
Ben Grant
1477b28798 WIP testing 2025-01-27 11:34:59 -08:00
Ben Grant
b3387f48c6 Pass data pointer to NAPI constructors 2025-01-07 17:58:48 -08:00
Ben Grant
228fb2ef14 Revert "Split NAPI tests out of the huge C++ file"
This reverts commit 9d10df2501.
2025-01-07 17:45:19 -08:00
Ben Grant
279b84c67e Fix napi_coerce_to_* 2025-01-07 17:41:39 -08:00
Ben Grant
9d10df2501 Split NAPI tests out of the huge C++ file 2025-01-07 17:23:46 -08:00
Ben Grant
698087b58c Arg checking in napi_define_class 2025-01-07 16:14:54 -08:00
Ben Grant
09276dcae9 Fix conflicting definitions 2025-01-07 16:13:45 -08:00
Ben Grant
aebf01719d Fix bugs with napi_define_class 2025-01-07 16:02:59 -08:00
Ben Grant
ffe3a66aaa Fix bugs in napi_create_class and napi_get_value_bigint_* 2025-01-07 16:01:33 -08:00
3 changed files with 166 additions and 77 deletions

View File

@@ -1,3 +1,4 @@
#include "headers.h"
#include "node_api.h"
#include "root.h"
@@ -195,10 +196,11 @@ void NapiRef::clear()
WTF_MAKE_ISO_ALLOCATED_IMPL(NapiRef);
static uint32_t getPropertyAttributes(napi_property_attributes attributes_)
static uint32_t getPropertyAttributes(napi_property_descriptor prop)
{
const uint32_t attributes = static_cast<uint32_t>(attributes_);
uint32_t result = 0;
const uint32_t attributes = static_cast<uint32_t>(prop.attributes);
if (!(attributes & static_cast<napi_property_attributes>(napi_key_configurable))) {
result |= JSC::PropertyAttribute::DontDelete;
}
@@ -207,20 +209,9 @@ static uint32_t getPropertyAttributes(napi_property_attributes attributes_)
result |= JSC::PropertyAttribute::DontEnum;
}
// if (!(attributes & napi_key_writable)) {
// // result |= JSC::PropertyAttribute::ReadOnly;
// }
return result;
}
static uint32_t getPropertyAttributes(napi_property_descriptor prop)
{
uint32_t result = getPropertyAttributes(prop.attributes);
// if (!(prop.getter && !prop.setter)) {
// result |= JSC::PropertyAttribute::ReadOnly;
// }
if (!(attributes & napi_key_writable || prop.setter != nullptr)) {
result |= JSC::PropertyAttribute::ReadOnly;
}
return result;
}
@@ -562,16 +553,10 @@ static void defineNapiProperty(Zig::GlobalObject* globalObject, JSC::JSObject* t
if (setterProperty) {
setter = NAPIFunction::create(vm, globalObject, 1, makeString("set "_s, propertyName.isSymbol() ? String() : propertyName.string()), setterProperty, dataPtr);
} else {
JSC::JSNativeStdFunction* setterFunction = JSC::JSNativeStdFunction::create(
globalObject->vm(), globalObject, 1, String(), [](JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) -> JSC::EncodedJSValue {
return JSC::JSValue::encode(JSC::jsBoolean(true));
});
setter = setterFunction;
}
auto getterSetter = JSC::GetterSetter::create(vm, globalObject, getter, setter);
to->putDirectAccessor(globalObject, propertyName, getterSetter, JSC::PropertyAttribute::Accessor | 0);
to->putDirectAccessor(globalObject, propertyName, getterSetter, PropertyAttribute::Accessor | getPropertyAttributes(property));
} else {
JSC::JSValue value = toJS(property.value);
@@ -1878,7 +1863,7 @@ JSC_DEFINE_HOST_FUNCTION(NapiClass_ConstructorFunction,
args.fill(vm, argc, [&](auto* slot) {
memcpy(slot, ADDRESS_OF_THIS_VALUE_IN_CALLFRAME(callFrame), sizeof(JSC::JSValue) * argc);
});
NAPICallFrame frame(JSC::ArgList(args), nullptr);
NAPICallFrame frame(JSC::ArgList(args), napi->dataPtr);
frame.newTarget = newTarget;
Bun::NapiHandleScope handleScope(jsCast<Zig::GlobalObject*>(globalObject));
@@ -2019,7 +2004,7 @@ extern "C" napi_status napi_define_class(napi_env env,
{
NAPI_PREMABLE
if (UNLIKELY(!result)) {
if (UNLIKELY(!result || !env || (property_count > 0 && !properties)) || !constructor) {
return napi_invalid_arg;
}
@@ -2061,6 +2046,8 @@ extern "C" napi_status napi_coerce_to_string(napi_env env, napi_value value,
// .toString() can throw
JSC::JSValue resultValue = JSC::JSValue(jsValue.toString(globalObject));
RETURN_IF_EXCEPTION(scope, napi_pending_exception);
JSC::EnsureStillAliveScope ensureStillAlive1(resultValue);
*result = toNapi(resultValue, globalObject);
@@ -2072,6 +2059,66 @@ extern "C" napi_status napi_coerce_to_string(napi_env env, napi_value value,
return napi_ok;
}
extern "C" napi_status napi_coerce_to_bool(napi_env env, napi_value value, napi_value* result)
{
NAPI_PREMABLE
if (!env || !value || !result) {
return napi_invalid_arg;
}
Zig::GlobalObject* globalObject = toJS(env);
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSValue jsValue = toJS(value);
// might throw
bool nativeBool = jsValue.toBoolean(globalObject);
RETURN_IF_EXCEPTION(scope, napi_pending_exception);
*result = toNapi(JSC::jsBoolean(nativeBool), globalObject);
return napi_ok;
}
extern "C" napi_status napi_coerce_to_number(napi_env env, napi_value value, napi_value* result)
{
NAPI_PREMABLE
if (!env || !value || !result) {
return napi_invalid_arg;
}
Zig::GlobalObject* globalObject = toJS(env);
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSValue jsValue = toJS(value);
// might throw
double nativeNumber = jsValue.toNumber(globalObject);
RETURN_IF_EXCEPTION(scope, napi_pending_exception);
*result = toNapi(JSC::jsNumber(nativeNumber), globalObject);
return napi_ok;
}
extern "C" napi_status napi_coerce_to_object(napi_env env, napi_value value, napi_value* result)
{
NAPI_PREMABLE
if (!env || !value || !result) {
return napi_invalid_arg;
}
Zig::GlobalObject* globalObject = toJS(env);
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSValue jsValue = toJS(value);
// might throw
JSObject* obj = jsValue.toObject(globalObject);
RETURN_IF_EXCEPTION(scope, napi_pending_exception);
*result = toNapi(obj, globalObject);
return napi_ok;
}
extern "C" napi_status napi_get_property_names(napi_env env, napi_value object,
napi_value* result)
{
@@ -2225,7 +2272,6 @@ extern "C" napi_status napi_get_value_int32(napi_env env, napi_value value, int3
extern "C" napi_status napi_get_value_uint32(napi_env env, napi_value value, uint32_t* result)
{
NAPI_PREMABLE
auto* globalObject = toJS(env);
JSC::JSValue jsValue = toJS(value);
@@ -2237,12 +2283,7 @@ extern "C" napi_status napi_get_value_uint32(napi_env env, napi_value value, uin
return napi_number_expected;
}
auto scope = DECLARE_CATCH_SCOPE(globalObject->vm());
// should never throw as we know it is a number
*result = jsValue.toUInt32(globalObject);
scope.assertNoException();
*result = jsValue.isUInt32() ? jsValue.asUInt32() : JSC::toUInt32(jsValue.asNumber());
return napi_ok;
}
@@ -2344,6 +2385,21 @@ extern "C" napi_status napi_get_value_string_utf8(napi_env env,
return napi_ok;
}
extern "C" napi_status napi_get_value_bool(napi_env env, napi_value value, bool* result)
{
NAPI_PREMABLE
if (!env || !value || !result) {
return napi_invalid_arg;
}
JSValue jsValue = toJS(value);
if (!jsValue.isBoolean()) {
return napi_boolean_expected;
}
*result = jsValue.asBoolean();
return napi_ok;
}
extern "C" napi_status napi_get_element(napi_env env, napi_value objectValue,
uint32_t index, napi_value* result)
{

View File

@@ -412,6 +412,7 @@ pub export fn napi_create_string_utf16(env: napi_env, str: ?[*]const char16_t, l
result.set(env, string.toJS(env));
return .ok;
}
pub extern fn napi_create_symbol(env: napi_env, description: napi_value, result: *napi_value) napi_status;
pub extern fn napi_create_error(env: napi_env, code: napi_value, msg: napi_value, result: *napi_value) napi_status;
pub extern fn napi_create_type_error(env: napi_env, code: napi_value, msg: napi_value, result: *napi_value) napi_status;
@@ -421,21 +422,8 @@ pub extern fn napi_get_value_double(env: napi_env, value: napi_value, result: *f
pub extern fn napi_get_value_int32(_: napi_env, value_: napi_value, result: ?*i32) napi_status;
pub extern fn napi_get_value_uint32(_: napi_env, value_: napi_value, result_: ?*u32) napi_status;
pub extern fn napi_get_value_int64(_: napi_env, value_: napi_value, result_: ?*i64) napi_status;
pub export fn napi_get_value_bool(_: napi_env, value_: napi_value, result_: ?*bool) napi_status {
log("napi_get_value_bool", .{});
const result = result_ orelse {
return invalidArg();
};
const value = value_.get();
pub extern fn napi_get_value_bool(_: napi_env, value_: napi_value, result_: ?*bool) napi_status;
result.* = value.to(bool);
return .ok;
}
inline fn maybeAppendNull(ptr: anytype, doit: bool) void {
if (doit) {
ptr.* = 0;
}
}
pub export fn napi_get_value_string_latin1(env: napi_env, value_: napi_value, buf_ptr_: ?[*:0]c_char, bufsize: usize, result_ptr: ?*usize) napi_status {
log("napi_get_value_string_latin1", .{});
const value = value_.get();
@@ -543,33 +531,9 @@ pub export fn napi_get_value_string_utf16(env: napi_env, value_: napi_value, buf
return .ok;
}
pub export fn napi_coerce_to_bool(env: napi_env, value_: napi_value, result_: ?*napi_value) napi_status {
log("napi_coerce_to_bool", .{});
const result = result_ orelse {
return invalidArg();
};
const value = value_.get();
result.set(env, JSValue.jsBoolean(value.coerce(bool, env)));
return .ok;
}
pub export fn napi_coerce_to_number(env: napi_env, value_: napi_value, result_: ?*napi_value) napi_status {
log("napi_coerce_to_number", .{});
const result = result_ orelse {
return invalidArg();
};
const value = value_.get();
result.set(env, JSC.JSValue.jsNumber(JSC.C.JSValueToNumber(env.ref(), value.asObjectRef(), TODO_EXCEPTION)));
return .ok;
}
pub export fn napi_coerce_to_object(env: napi_env, value_: napi_value, result_: ?*napi_value) napi_status {
log("napi_coerce_to_object", .{});
const result = result_ orelse {
return invalidArg();
};
const value = value_.get();
result.set(env, JSValue.c(JSC.C.JSValueToObject(env.ref(), value.asObjectRef(), TODO_EXCEPTION)));
return .ok;
}
pub extern fn napi_coerce_to_bool(env: napi_env, value_: napi_value, result_: ?*napi_value) napi_status;
pub extern fn napi_coerce_to_number(env: napi_env, value_: napi_value, result_: ?*napi_value) napi_status;
pub extern fn napi_coerce_to_object(env: napi_env, value_: napi_value, result_: ?*napi_value) napi_status;
pub export fn napi_get_prototype(env: napi_env, object_: napi_value, result_: ?*napi_value) napi_status {
log("napi_get_prototype", .{});
const result = result_ orelse {
@@ -1032,8 +996,8 @@ pub export fn napi_create_bigint_uint64(env: napi_env, value: u64, result_: ?*na
return .ok;
}
pub extern fn napi_create_bigint_words(env: napi_env, sign_bit: c_int, word_count: usize, words: [*c]const u64, result: *napi_value) napi_status;
pub extern fn napi_get_value_bigint_int64(env: napi_env, value: napi_value, result: ?*i64, lossless: ?*bool) napi_status;
pub extern fn napi_get_value_bigint_uint64(env: napi_env, value: napi_value, result: ?*u64, lossless: ?*bool) napi_status;
pub extern fn napi_get_value_bigint_int64(env: napi_env, value: napi_value, result: ?*i64, lossless: *bool) napi_status;
pub extern fn napi_get_value_bigint_uint64(env: napi_env, value: napi_value, result: ?*u64, lossless: *bool) napi_status;
pub extern fn napi_get_value_bigint_words(env: napi_env, value: napi_value, sign_bit: [*c]c_int, word_count: [*c]usize, words: [*c]u64) napi_status;
pub extern fn napi_get_all_property_names(env: napi_env, object: napi_value, key_mode: napi_key_collection_mode, key_filter: napi_key_filter, key_conversion: napi_key_conversion, result: *napi_value) napi_status;

View File

@@ -345,8 +345,14 @@ napi_value test_napi_handle_scope_nesting(const Napi::CallbackInfo &info) {
napi_value constructor(napi_env env, napi_callback_info info) {
napi_value this_value;
assert(napi_get_cb_info(env, info, nullptr, nullptr, &this_value, nullptr) ==
void *data = nullptr;
assert(napi_get_cb_info(env, info, nullptr, nullptr, &this_value, &data) ==
napi_ok);
if (data) {
printf("constructor data = %d\n", *reinterpret_cast<int *>(data));
} else {
printf("constructor data = nullptr\n");
}
napi_value property_value;
assert(napi_create_string_utf8(env, "meow", NAPI_AUTO_LENGTH,
&property_value) == napi_ok);
@@ -358,10 +364,12 @@ napi_value constructor(napi_env env, napi_callback_info info) {
}
napi_value get_class_with_constructor(const Napi::CallbackInfo &info) {
static int data = 500;
napi_env env = info.Env();
napi_value napi_class;
assert(napi_define_class(env, "NapiClass", NAPI_AUTO_LENGTH, constructor,
nullptr, 0, nullptr, &napi_class) == napi_ok);
static_cast<void *>(&data), 0, nullptr,
&napi_class) == napi_ok);
return napi_class;
}
@@ -1076,6 +1084,67 @@ static napi_value create_weird_bigints(const Napi::CallbackInfo &info) {
return array;
}
// returns an array of objects with a variety of differently-configured
// properties
static napi_value
create_objects_with_properties(const Napi::CallbackInfo &info) {
static int data = 123;
napi_callback method = [](napi_env env,
napi_callback_info info) -> napi_value {};
napi_callback getter = [](napi_env env,
napi_callback_info info) -> napi_value {};
napi_callback setter = [](napi_env env,
napi_callback_info info) -> napi_value {};
napi_value name_string;
NODE_API_CALL(env, napi_create_string_utf8(env, "name_string",
NAPI_AUTO_LENGTH, &name_string));
napi_value name_symbol;
NODE_API_CALL(env, napi_create_symbol(env, name_string, &name_symbol));
napi_value value;
NODE_API_CALL(env, napi_create_int32(env, 5, &value));
std::vector<napi_property_descriptor> properties;
for (const char *utf8name : std::to_array({nullptr, "utf8name"})) {
for (napi_value name : std::to_array({nullptr, name_string, name_symbol})) {
for (napi_callback method : std::to_array({nullptr, method})) {
for (napi_callback getter : std::to_array({nullptr, getter})) {
for (napi_callback setter : std::to_array({nullptr, setter})) {
for (napi_value value : std::to_array({nullptr, value})) {
for (napi_property_attributes writable :
std::to_array({0, napi_writable})) {
for (napi_property_attributes enumerable :
std::to_array({0, napi_enumerable})) {
for (napi_property_attributes configurable :
std::to_array({0, napi_configurable})) {
for (napi_property_attributes static_ :
std::to_array({0, napi_static})) {
properties.push_back({
.utf8name = utf8name,
.name = name,
.method = method,
.getter = getter,
.setter = setter,
.value = value,
.attributes =
writable | enumerable | configurable | static_,
.data = &data,
});
}
}
}
}
}
}
}
}
}
}
// axes:
// how named?
//
}
Napi::Value RunCallback(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env();
// this function is invoked without the GC callback