ladybird/Libraries/LibWeb/HTML/ErrorInformation.cpp
Andreas Kling 88d4d1b1a6 LibWeb: Use VM helpers for execution context access
Inline JS-to-JS frames no longer live in the raw execution context
vector, so LibWeb callers that need to inspect or pop contexts now go
through VM helpers instead of peeking into that storage directly.

This keeps the execution context bookkeeping encapsulated while
preserving existing microtask and realm-entry checks.
2026-04-13 18:29:43 +02:00

67 lines
2.6 KiB
C++

/*
* Copyright (c) 2025, Shannon Booth <shannon@serenityos.org>
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/VM.h>
#include <LibWeb/HTML/ErrorInformation.h>
namespace Web::HTML {
// https://html.spec.whatwg.org/multipage/webappapis.html#extract-error
ErrorInformation extract_error_information(JS::VM& vm, JS::Value exception)
{
// 1. Let attributes be an empty map keyed by IDL attributes.
ErrorInformation attributes;
// 2. Set attributes[error] to exception.
attributes.error = exception;
// 3. Set attributes[message], attributes[filename], attributes[lineno], and attributes[colno] to
// implementation-defined values derived from exception.
attributes.message = [&] {
if (auto object = exception.as_if<JS::Object>()) {
if (MUST(object->has_own_property(vm.names.message))) {
auto message = object->get_without_side_effects(vm.names.message);
return message.to_string_without_side_effects();
}
}
return MUST(String::formatted("Uncaught exception: {}", exception));
}();
// FIXME: This offset is relative to the javascript source. Other browsers appear to do it relative
// to the entire source document! Calculate that somehow.
// NB: If we got an Error object, then try and extract the information from the location the object was made.
if (auto object = exception.as_if<JS::Object>(); object && object->error_data()) {
for (auto const& frame : object->error_data()->traceback()) {
auto source_range = frame.source_range();
if (source_range.start.line != 0 || source_range.start.column != 0) {
attributes.filename = MUST(String::from_byte_string(source_range.filename()));
attributes.lineno = source_range.start.line;
attributes.colno = source_range.start.column;
break;
}
}
}
// NB: Otherwise, we fall back to try and find the location of the invocation of the function itself.
else {
for (auto const& frame : vm.stack_trace()) {
if (frame.source_range.has_value()) {
auto const& source_range = *frame.source_range;
attributes.filename = MUST(String::from_byte_string(source_range.filename()));
attributes.lineno = source_range.start.line;
attributes.colno = source_range.start.column;
break;
}
}
}
// 4. Return attributes.
return attributes;
}
}