feature (backend-rs, macro-rs): prittify error outputs for napi export
Co-authored-by: sup39 <dev@sup39.dev>
This commit is contained in:
parent
9ec9c31ab5
commit
1cc24b9c25
3 changed files with 96 additions and 5 deletions
90
packages/backend-rs/src/util/error_chain.rs
Normal file
90
packages/backend-rs/src/util/error_chain.rs
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
//! Error formatter used until backtracing methods are standarized
|
||||||
|
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
/// Prettifies [`Error`] message (mainly for napi export)
|
||||||
|
pub fn format_error(mut error: &dyn Error) -> String {
|
||||||
|
let mut to_return = String::new();
|
||||||
|
|
||||||
|
to_return.push_str(&format!(
|
||||||
|
concat!(" raw: {0:?}", "\n", " message: {0}"),
|
||||||
|
error,
|
||||||
|
));
|
||||||
|
|
||||||
|
while let Some(source) = error.source() {
|
||||||
|
to_return.push('\n');
|
||||||
|
to_return.push_str(&format!("caused by: {}", source));
|
||||||
|
error = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
to_return
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod unit_test {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn format_error() {
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
#[error("inner error 1")]
|
||||||
|
struct InnerError1;
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
#[error("unexpected string '{0}'")]
|
||||||
|
struct InnerError2(String);
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
enum ErrorVariants {
|
||||||
|
#[error("error 1 occured")]
|
||||||
|
Error1(#[from] InnerError1),
|
||||||
|
#[error("error 2 occured")]
|
||||||
|
Error2(#[from] InnerError2),
|
||||||
|
}
|
||||||
|
|
||||||
|
fn causes_inner_error_1() -> Result<(), InnerError1> {
|
||||||
|
Err(InnerError1)
|
||||||
|
}
|
||||||
|
fn causes_inner_error_2() -> Result<(), InnerError2> {
|
||||||
|
Err(InnerError2("foo".to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn causes_error_1() -> Result<(), ErrorVariants> {
|
||||||
|
causes_inner_error_1()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn causes_error_2() -> Result<(), ErrorVariants> {
|
||||||
|
causes_inner_error_2()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
let error_1 = causes_error_1().unwrap_err();
|
||||||
|
let error_2 = causes_error_2().unwrap_err();
|
||||||
|
|
||||||
|
let error_message_1 = super::format_error(&error_1);
|
||||||
|
let error_message_2 = super::format_error(&error_2);
|
||||||
|
|
||||||
|
// We can't assume consistency in `Debug` output, so the output texts
|
||||||
|
// may need to be updated in the future, and we shouldn't make this kind
|
||||||
|
// of assumption in the actual program.
|
||||||
|
let expected_message_1 = "
|
||||||
|
raw: Error1(InnerError1)
|
||||||
|
message: error 1 occured
|
||||||
|
caused by: inner error 1
|
||||||
|
";
|
||||||
|
let expected_message_2 = r#"
|
||||||
|
raw: Error2(InnerError2("foo"))
|
||||||
|
message: error 2 occured
|
||||||
|
caused by: unexpected string 'foo'
|
||||||
|
"#;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
error_message_1,
|
||||||
|
expected_message_1[1..expected_message_1.len() - 1]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
error_message_2,
|
||||||
|
expected_message_2[1..expected_message_2.len() - 1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
//! Basic utilities such as ID generator and HTTP client
|
//! Basic utilities such as ID generator and HTTP client
|
||||||
|
|
||||||
|
pub mod error_chain;
|
||||||
pub mod http_client;
|
pub mod http_client;
|
||||||
pub mod id;
|
pub mod id;
|
||||||
pub mod random;
|
pub mod random;
|
||||||
|
|
|
@ -212,7 +212,7 @@ pub fn ts_export(
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// ## Function with `Result<T, E>` return type
|
/// ## Function with `Result<T, E>` return type
|
||||||
/// ```
|
/// ```ignore
|
||||||
/// #[derive(thiserror::Error, Debug)]
|
/// #[derive(thiserror::Error, Debug)]
|
||||||
/// pub enum IntegerDivisionError {
|
/// pub enum IntegerDivisionError {
|
||||||
/// #[error("Divided by zero")]
|
/// #[error("Divided by zero")]
|
||||||
|
@ -233,7 +233,7 @@ pub fn ts_export(
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
/// generates
|
/// generates
|
||||||
/// ```
|
/// ```ignore
|
||||||
/// # #[derive(thiserror::Error, Debug)]
|
/// # #[derive(thiserror::Error, Debug)]
|
||||||
/// # pub enum IntegerDivisionError {
|
/// # pub enum IntegerDivisionError {
|
||||||
/// # #[error("Divided by zero")]
|
/// # #[error("Divided by zero")]
|
||||||
|
@ -252,7 +252,7 @@ pub fn ts_export(
|
||||||
/// # }
|
/// # }
|
||||||
/// #[napi_derive::napi(js_name = "integerDivide",)]
|
/// #[napi_derive::napi(js_name = "integerDivide",)]
|
||||||
/// pub fn integer_divide_napi(dividend: i64, divisor: i64) -> napi::Result<i64> {
|
/// pub fn integer_divide_napi(dividend: i64, divisor: i64) -> napi::Result<i64> {
|
||||||
/// integer_divide(dividend, divisor).map_err(|err| napi::Error::from_reason(err.to_string()))
|
/// integer_divide(dividend, divisor).map_err(|err| napi::Error::from_reason(crate::util::error_chain::format_error(&err)))
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
|
@ -329,7 +329,7 @@ fn napi_impl(macro_attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
};
|
};
|
||||||
// add modifier to function call result
|
// add modifier to function call result
|
||||||
function_call_modifiers.push(quote! {
|
function_call_modifiers.push(quote! {
|
||||||
.map_err(|err| napi::Error::from_reason(err.to_string()))
|
.map_err(|err| napi::Error::from_reason(crate::util::error_chain::format_error(&err)))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -539,7 +539,7 @@ mod tests {
|
||||||
divisor: i64,
|
divisor: i64,
|
||||||
) -> napi::Result<i64> {
|
) -> napi::Result<i64> {
|
||||||
integer_divide(dividend, divisor)
|
integer_divide(dividend, divisor)
|
||||||
.map_err(|err| napi::Error::from_reason(err.to_string()))
|
.map_err(|err| napi::Error::from_reason(crate::util::error_chain::format_error(&err)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
Loading…
Reference in a new issue