diff options
Diffstat (limited to 'core/error.rs')
-rw-r--r-- | core/error.rs | 67 |
1 files changed, 52 insertions, 15 deletions
diff --git a/core/error.rs b/core/error.rs index dc50b4d73..4ee3b9315 100644 --- a/core/error.rs +++ b/core/error.rs @@ -326,6 +326,7 @@ impl JsError { } if is_instance_of_error(scope, exception) { + let v8_exception = exception; // The exception is a JS Error object. let exception: v8::Local<v8::Object> = exception.try_into().unwrap(); let cause = get_property(scope, exception, "cause"); @@ -444,24 +445,25 @@ impl JsError { } } - // Read an array of stored errors, this is only defined for `AggregateError` - let aggregated_errors = get_property(scope, exception, "errors"); - let aggregated_errors: Option<v8::Local<v8::Array>> = - aggregated_errors.and_then(|a| a.try_into().ok()); - let mut aggregated: Option<Vec<JsError>> = None; - - if let Some(errors) = aggregated_errors { - if errors.length() > 0 { - let mut agg = vec![]; - for i in 0..errors.length() { - let error = errors.get_index(scope, i).unwrap(); - let js_error = Self::from_v8_exception(scope, error); - agg.push(js_error); + if is_aggregate_error(scope, v8_exception) { + // Read an array of stored errors, this is only defined for `AggregateError` + let aggregated_errors = get_property(scope, exception, "errors"); + let aggregated_errors: Option<v8::Local<v8::Array>> = + aggregated_errors.and_then(|a| a.try_into().ok()); + + if let Some(errors) = aggregated_errors { + if errors.length() > 0 { + let mut agg = vec![]; + for i in 0..errors.length() { + let error = errors.get_index(scope, i).unwrap(); + let js_error = Self::from_v8_exception(scope, error); + agg.push(js_error); + } + aggregated = Some(agg); } - aggregated = Some(agg); } - } + }; Self { name: e.name, @@ -575,6 +577,41 @@ pub(crate) fn is_instance_of_error<'s>( false } +/// Implements `value instanceof primordials.AggregateError` in JS, +/// by walking the prototype chain, and comparing each links constructor `name` property. +/// +/// NOTE: There is currently no way to detect `AggregateError` via `rusty_v8`, +/// as v8 itself doesn't expose `v8__Exception__AggregateError`, +/// and we cannot create bindings for it. This forces us to rely on `name` inference. +pub(crate) fn is_aggregate_error<'s>( + scope: &mut v8::HandleScope<'s>, + value: v8::Local<v8::Value>, +) -> bool { + let mut maybe_prototype = Some(value); + while let Some(prototype) = maybe_prototype { + if !prototype.is_object() { + return false; + } + + let prototype = prototype.to_object(scope).unwrap(); + let prototype_name = match get_property(scope, prototype, "constructor") { + Some(constructor) => { + let ctor = constructor.to_object(scope).unwrap(); + get_property(scope, ctor, "name").map(|v| v.to_rust_string_lossy(scope)) + } + None => return false, + }; + + if prototype_name == Some(String::from("AggregateError")) { + return true; + } + + maybe_prototype = prototype.get_prototype(scope); + } + + false +} + const DATA_URL_ABBREV_THRESHOLD: usize = 150; pub fn format_file_name(file_name: &str) -> String { |