fix(napi): stop ref error object in wasm targets (#2975)

This commit is contained in:
LongYinan 2025-10-24 09:36:59 +08:00 committed by GitHub
parent 2389a73f4a
commit d9498f5cec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 78 additions and 7 deletions

View File

@ -30,7 +30,7 @@ impl Display for FnArgList {
let is_optional = arg.is_optional
&& self
.last_required
.map_or(true, |last_required| i > last_required);
.is_none_or(|last_required| i > last_required);
if is_optional {
write!(f, "{}?: {}", arg.arg, arg.ts_type)?;
} else {

View File

@ -13,6 +13,8 @@ use serde::{de, ser};
use serde_json::Error as SerdeJSONError;
use crate::bindgen_runtime::JsObjectValue;
#[cfg(target_family = "wasm")]
use crate::ValueType;
use crate::{bindgen_runtime::ToNapiValue, check_status, sys, Env, JsValue, Status, Unknown};
pub type Result<T, S = Status> = std::result::Result<T, Error<S>>;
@ -129,6 +131,7 @@ impl From<SerdeJSONError> for Error {
}
}
#[cfg(not(target_family = "wasm"))]
impl From<Unknown<'_>> for Error {
fn from(value: Unknown) -> Self {
let mut result = std::ptr::null_mut();
@ -169,6 +172,68 @@ impl From<Unknown<'_>> for Error {
}
}
#[cfg(target_family = "wasm")]
impl From<Unknown<'_>> for Error {
fn from(value: Unknown) -> Self {
let value_type = value.get_type();
let maybe_error_message;
if let Ok(vt) = value_type {
if vt == ValueType::Object {
maybe_error_message = value
.coerce_to_object()
.and_then(|obj| obj.get_named_property::<Unknown>("message"))
.and_then(|message| {
message
.coerce_to_string()
.and_then(|message| message.into_utf8().and_then(|message| message.into_owned()))
});
} else {
maybe_error_message = value
.coerce_to_string()
.and_then(|a| a.into_utf8().and_then(|a| a.into_owned()));
}
} else {
maybe_error_message = value
.coerce_to_string()
.and_then(|a| a.into_utf8().and_then(|a| a.into_owned()));
};
let maybe_cause: Option<Box<Error>> = if let Ok(vt) = value_type {
if vt == ValueType::Object {
value
.coerce_to_object()
.and_then(|obj| obj.get_named_property::<Unknown>("cause"))
.map(|cause| Box::new(cause.into()))
.ok()
} else {
None
}
} else {
None
};
if let Ok(error_message) = maybe_error_message {
return Self {
status: Status::GenericFailure,
reason: error_message,
cause: maybe_cause,
maybe_raw: ptr::null_mut(),
maybe_env: ptr::null_mut(),
};
}
Self {
status: Status::GenericFailure,
reason: "".to_string(),
cause: maybe_cause,
maybe_raw: ptr::null_mut(),
maybe_env: ptr::null_mut(),
}
}
}
#[cfg(feature = "anyhow")]
impl From<anyhow::Error> for Error {
fn from(value: anyhow::Error) -> Self {

View File

@ -733,6 +733,7 @@ unsafe extern "C" fn call_js_cb<
values
};
let mut return_value = ptr::null_mut();
#[allow(unused_mut)]
let mut status = sys::napi_call_function(
raw_env,
recv,

View File

@ -975,7 +975,9 @@ test('Result', (t) => {
new Error('JS Error', { cause: new Error('cause') }),
)
t.deepEqual(errors[0]!.message, 'JS Error')
t.deepEqual((errors[0]!.cause as Error).message, 'cause')
if (!process.env.WASI_TEST) {
t.deepEqual((errors[0]!.cause as Error).message, 'cause')
}
t.deepEqual(errors[1]!.message, 'JS Error')
t.deepEqual((errors[1]!.cause as Error).message, 'cause')
@ -989,9 +991,11 @@ test('Result', (t) => {
}),
)
let error = nestedError
for (let i = 0; i < 4; i++) {
t.deepEqual(error!.message, `error${i + 1}`)
error = error!.cause as Error
if (!process.env.WASI_TEST) {
for (let i = 0; i < 4; i++) {
t.deepEqual(error!.message, `error${i + 1}`)
error = error!.cause as Error
}
}
})
@ -1669,8 +1673,9 @@ Napi4Test('await Promise in rust', async (t) => {
Napi4Test('Promise should reject raw error in rust', async (t) => {
const fxError = new Error('What is Happy Planet')
const err = await t.throwsAsync(() => asyncPlus100(Promise.reject(fxError)))
t.is(err, fxError)
await t.throwsAsync(() => asyncPlus100(Promise.reject(fxError)), {
message: fxError.message,
})
})
Napi4Test('call ThreadsafeFunction with callback', async (t) => {