use crate::{
builtins::BuiltIn,
context::intrinsics::StandardConstructors,
object::{
internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData,
},
property::Attribute,
Context, JsResult, JsString, JsValue,
};
use boa_profiler::Profiler;
use tap::{Conv, Pipe};
pub(crate) mod aggregate;
pub(crate) mod eval;
pub(crate) mod range;
pub(crate) mod reference;
pub(crate) mod syntax;
pub(crate) mod r#type;
pub(crate) mod uri;
#[cfg(test)]
mod tests;
pub(crate) use self::aggregate::AggregateError;
pub(crate) use self::eval::EvalError;
pub(crate) use self::r#type::TypeError;
pub(crate) use self::range::RangeError;
pub(crate) use self::reference::ReferenceError;
pub(crate) use self::syntax::SyntaxError;
pub(crate) use self::uri::UriError;
use super::JsArgs;
#[derive(Debug, Clone, Copy)]
pub(crate) struct Error;
impl BuiltIn for Error {
const NAME: &'static str = "Error";
fn init(context: &mut Context) -> Option<JsValue> {
let _timer = Profiler::global().start_event(Self::NAME, "init");
let attribute = Attribute::WRITABLE | Attribute::NON_ENUMERABLE | Attribute::CONFIGURABLE;
ConstructorBuilder::with_standard_constructor(
context,
Self::constructor,
context.intrinsics().constructors().error().clone(),
)
.name(Self::NAME)
.length(Self::LENGTH)
.property("name", Self::NAME, attribute)
.property("message", "", attribute)
.method(Self::to_string, "toString", 0)
.build()
.conv::<JsValue>()
.pipe(Some)
}
}
impl Error {
pub(crate) const LENGTH: usize = 1;
pub(crate) fn install_error_cause(
o: &JsObject,
options: &JsValue,
context: &mut Context,
) -> JsResult<()> {
if let Some(options) = options.as_object() {
if options.has_property("cause", context)? {
let cause = options.get("cause", context)?;
o.create_non_enumerable_data_property_or_throw("cause", cause, context);
}
}
Ok(())
}
pub(crate) fn constructor(
new_target: &JsValue,
args: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let prototype =
get_prototype_from_constructor(new_target, StandardConstructors::error, context)?;
let o = JsObject::from_proto_and_data(prototype, ObjectData::error());
let message = args.get_or_undefined(0);
if !message.is_undefined() {
let msg = message.to_string(context)?;
o.create_non_enumerable_data_property_or_throw("message", msg, context);
}
Self::install_error_cause(&o, args.get_or_undefined(1), context)?;
Ok(o.into())
}
#[allow(clippy::wrong_self_convention)]
pub(crate) fn to_string(
this: &JsValue,
_: &[JsValue],
context: &mut Context,
) -> JsResult<JsValue> {
let o = if let Some(o) = this.as_object() {
o
} else {
return context.throw_type_error("'this' is not an Object");
};
let name = o.get("name", context)?;
let name = if name.is_undefined() {
JsString::new("Error")
} else {
name.to_string(context)?
};
let msg = o.get("message", context)?;
let msg = if msg.is_undefined() {
JsString::empty()
} else {
msg.to_string(context)?
};
if name.is_empty() {
return Ok(msg.into());
}
if msg.is_empty() {
return Ok(name.into());
}
Ok(format!("{name}: {msg}").into())
}
}