///|
pub(all) struct JsError {
message : String
stack : String
}
///|
pub extern "js" fn JsError::isError(value : @core.Any) -> Bool =
#| (value) => Error.isError(value)
///|
pub fn JsError::new(message : String, cause? : JsError) -> JsError {
let args : Array[@core.Any] = if cause is Some(cause) {
[
@core.any(message).cast(),
@core.from_entries([("cause", cause |> @core.any)]).cast(),
]
} else {
[@core.any(message).cast()]
}
ffi_new_error(args)
}
///|
extern "js" fn ffi_new_error(args : Array[@core.Any]) -> JsError =
#| (args) => new Error(...args)
///|
pub suberror ThrowError Any
///|
pub impl Show for ThrowError with output(self, logger) {
logger.write_string("@js.Error: ")
let ThrowError(inner) = self
logger.write_object(inner)
}
///|
/// Wraps a synchronous function call, converting any thrown JS errors into ThrowError
/// ```moonbit skip
/// let result = throwable(() => undefined()._invoke([]))
/// ```
pub fn[T] throwable(f : () -> T raise?) -> T raise ThrowError {
match throwable_result(f |> @core.identity) {
Ok(result) => result |> @core.identity
Err(e) => raise ThrowError(e |> @core.identity)
}
}
///|
/// Wraps a synchronous function call that returns Result, converting any thrown JS errors into JsError
fn throwable_result(f : () -> Result[Any, Any]) -> Result[Any, Any] {
ffi_wrap_sync(@core.identity(f), Ok(_), Err(_))
}
///|
extern "js" fn ffi_wrap_sync(
f : Any,
ok : (Any) -> Result[Any, Any],
err : (Any) -> Result[Any, Any],
) -> Result[Any, Any] =
#|(f, ok, err) => {
#| try {
#| return ok(f())
#| } catch(e) {
#| return err(e)
#| }
#|}