diff options
author | Nayeem Rahman <nayeemrmn99@gmail.com> | 2023-04-12 12:45:36 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-12 13:45:36 +0200 |
commit | 806671af3345f403d122911d8a3f09a2994bb8c0 (patch) | |
tree | 28520c1d8017b85444317959de8dab96ee5bee04 /core/bindings.rs | |
parent | 18e0ee368c6a77b476f3fec7574415465f9052b9 (diff) |
fix(core): preserve syntax error locations in dynamic imports (#18664)
Fixes #6259.
Adds the location for v8 syntax errors to the message (`message += " at
{location}"`) when rethrowing them for dynamic imports.
Discussing with @bartlomieju on discord I proposed just preserving v8's
error and not reconstructing it, allowing the standard stack trace to
just point to the syntax error instead of the dynamic import. But on
further thought this way has parity with SWC's syntax errors + has the
advantage of showing both the syntax error and dynamic import location.
```ts
// temp.js
await import("./temp2.js");
// temp2.js
function foo() {
await Promise.resolve();
}
// Before:
// error: Uncaught (in promise) SyntaxError: Unexpected reserved word
// await import("./temp2.js");
// ^
// at async file:///.../temp.js:1:1
// After:
// error: Uncaught (in promise) SyntaxError: Unexpected reserved word at file:///.../temp2.js:2:3
// await import("./temp2.js");
// ^
// at async file:///.../temp.js:1:1
```
Diffstat (limited to 'core/bindings.rs')
-rw-r--r-- | core/bindings.rs | 31 |
1 files changed, 16 insertions, 15 deletions
diff --git a/core/bindings.rs b/core/bindings.rs index 8e701c903..5650b78f3 100644 --- a/core/bindings.rs +++ b/core/bindings.rs @@ -7,6 +7,7 @@ use log::debug; use v8::MapFnTo; use crate::error::is_instance_of_error; +use crate::error::JsStackFrame; use crate::modules::get_asserted_module_type_from_assertions; use crate::modules::parse_import_assertions; use crate::modules::resolve_helper; @@ -436,26 +437,26 @@ fn catch_dynamic_import_promise_error( if is_instance_of_error(scope, arg) { let e: crate::error::NativeJsError = serde_v8::from_v8(scope, arg).unwrap(); let name = e.name.unwrap_or_else(|| "Error".to_string()); - let message = v8::Exception::create_message(scope, arg); - if message.get_stack_trace(scope).unwrap().get_frame_count() == 0 { + let msg = v8::Exception::create_message(scope, arg); + if msg.get_stack_trace(scope).unwrap().get_frame_count() == 0 { let arg: v8::Local<v8::Object> = arg.try_into().unwrap(); let message_key = v8::String::new_external_onebyte_static(scope, b"message").unwrap(); let message = arg.get(scope, message_key.into()).unwrap(); - let exception = match name.as_str() { - "RangeError" => { - v8::Exception::range_error(scope, message.try_into().unwrap()) - } - "TypeError" => { - v8::Exception::type_error(scope, message.try_into().unwrap()) - } - "SyntaxError" => { - v8::Exception::syntax_error(scope, message.try_into().unwrap()) + let mut message: v8::Local<v8::String> = message.try_into().unwrap(); + if let Some(stack_frame) = JsStackFrame::from_v8_message(scope, msg) { + if let Some(location) = stack_frame.maybe_format_location() { + let str = + format!("{} at {location}", message.to_rust_string_lossy(scope)); + message = v8::String::new(scope, &str).unwrap(); } - "ReferenceError" => { - v8::Exception::reference_error(scope, message.try_into().unwrap()) - } - _ => v8::Exception::error(scope, message.try_into().unwrap()), + } + let exception = match name.as_str() { + "RangeError" => v8::Exception::range_error(scope, message), + "TypeError" => v8::Exception::type_error(scope, message), + "SyntaxError" => v8::Exception::syntax_error(scope, message), + "ReferenceError" => v8::Exception::reference_error(scope, message), + _ => v8::Exception::error(scope, message), }; let code_key = v8::String::new_external_onebyte_static(scope, b"code").unwrap(); |