1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 14:57:35 +00:00

WebContent+LibWeb+LibJS: Report exceptions to the JS console

Print exceptions passed to `HTML::report_exception` in the JS console

Refactored `ExceptionReporter`: in order to report exception now
you need to pass the relevant realm in it. For passed `JS::Value`
we now create `JS::Error` object to print value as the error message.
This commit is contained in:
Pavel 2022-10-08 19:38:32 +04:00 committed by Linus Groh
parent 2eb6dbd4f0
commit 40aad77ab1
14 changed files with 86 additions and 58 deletions

View file

@ -453,6 +453,12 @@ void Console::output_debug_message([[maybe_unused]] LogLevel log_level, [[maybe_
#endif
}
void Console::report_exception(JS::Error const& exception, bool in_promise) const
{
if (m_client)
m_client->report_exception(exception, in_promise);
}
ThrowCompletionOr<String> Console::value_vector_to_string(MarkedVector<Value> const& values)
{
auto& vm = realm().vm();

View file

@ -82,6 +82,7 @@ public:
ThrowCompletionOr<Value> time_end();
void output_debug_message(LogLevel log_level, String output) const;
void report_exception(JS::Error const&, bool) const;
private:
ThrowCompletionOr<String> value_vector_to_string(MarkedVector<Value> const&);
@ -108,7 +109,8 @@ public:
ThrowCompletionOr<MarkedVector<Value>> formatter(MarkedVector<Value> const& args);
virtual ThrowCompletionOr<Value> printer(Console::LogLevel log_level, PrinterArguments) = 0;
virtual void add_css_style_to_current_message(StringView) {};
virtual void add_css_style_to_current_message(StringView) { }
virtual void report_exception(JS::Error const&, bool) { }
virtual void clear() = 0;
virtual void end_group() = 0;

View file

@ -36,11 +36,10 @@ String MarkupGenerator::html_from_value(Value value)
return output_html.to_string();
}
String MarkupGenerator::html_from_error(Object& object)
String MarkupGenerator::html_from_error(Error const& object, bool in_promise)
{
StringBuilder output_html;
HashTable<Object*> seen_objects;
error_to_html(object, output_html, seen_objects);
error_to_html(object, output_html, in_promise);
return output_html.to_string();
}
@ -70,8 +69,6 @@ void MarkupGenerator::value_to_html(Value value, StringBuilder& output_html, Has
return function_to_html(object, output_html, seen_objects);
if (is<Date>(object))
return date_to_html(object, output_html, seen_objects);
if (is<Error>(object))
return error_to_html(object, output_html, seen_objects);
return object_to_html(object, output_html, seen_objects);
}
@ -145,19 +142,35 @@ void MarkupGenerator::date_to_html(Object const& date, StringBuilder& html_outpu
html_output.appendff("Date {}", to_date_string(static_cast<Date const&>(date).date_value()));
}
void MarkupGenerator::error_to_html(Object const& object, StringBuilder& html_output, HashTable<Object*>&)
void MarkupGenerator::trace_to_html(TracebackFrame const& traceback_frame, StringBuilder& html_output)
{
auto& vm = object.vm();
auto name = object.get_without_side_effects(vm.names.name).value_or(js_undefined());
auto message = object.get_without_side_effects(vm.names.message).value_or(js_undefined());
if (name.is_accessor() || message.is_accessor()) {
html_output.append(wrap_string_in_style(Value(&object).to_string_without_side_effects(), StyleType::Invalid));
} else {
auto name_string = name.to_string_without_side_effects();
auto message_string = message.to_string_without_side_effects();
html_output.append(wrap_string_in_style(String::formatted("[{}]", name_string), StyleType::Invalid));
if (!message_string.is_empty())
html_output.appendff(": {}", escape_html_entities(message_string));
auto function_name = escape_html_entities(traceback_frame.function_name);
auto [line, column, _] = traceback_frame.source_range.start;
auto get_filename_from_path = [&](StringView filename) -> StringView {
auto last_slash_index = filename.find_last('/');
return last_slash_index.has_value() ? filename.substring_view(*last_slash_index + 1) : filename;
};
auto filename = escape_html_entities(get_filename_from_path(traceback_frame.source_range.filename));
auto trace = String::formatted("at {} ({}:{}:{})", function_name, filename, line, column);
html_output.appendff("&nbsp;&nbsp;{}<br>", trace);
}
void MarkupGenerator::error_to_html(Error const& error, StringBuilder& html_output, bool in_promise)
{
auto& vm = error.vm();
auto name = error.get_without_side_effects(vm.names.name).value_or(js_undefined());
auto message = error.get_without_side_effects(vm.names.message).value_or(js_undefined());
auto name_string = name.to_string_without_side_effects();
auto message_string = message.to_string_without_side_effects();
auto uncaught_message = String::formatted("Uncaught {}[{}]: ", in_promise ? "(in promise) " : "", name_string);
html_output.append(wrap_string_in_style(uncaught_message, StyleType::Invalid));
html_output.appendff("{}<br>", message_string.is_empty() ? "\"\"" : escape_html_entities(message_string));
for (size_t i = 0; i < error.traceback().size() - min(error.traceback().size(), 3); i++) {
auto& traceback_frame = error.traceback().at(i);
trace_to_html(traceback_frame, html_output);
}
}

View file

@ -9,6 +9,7 @@
#include <AK/HashTable.h>
#include <AK/String.h>
#include <LibJS/Forward.h>
#include <LibJS/Runtime/Error.h>
namespace JS {
@ -16,7 +17,7 @@ class MarkupGenerator {
public:
static String html_from_source(StringView);
static String html_from_value(Value);
static String html_from_error(Object&);
static String html_from_error(Error const&, bool);
private:
enum class StyleType {
@ -37,7 +38,8 @@ private:
static void object_to_html(Object const&, StringBuilder& output_html, HashTable<Object*>&);
static void function_to_html(Object const&, StringBuilder& output_html, HashTable<Object*>&);
static void date_to_html(Object const&, StringBuilder& output_html, HashTable<Object*>&);
static void error_to_html(Object const&, StringBuilder& output_html, HashTable<Object*>&);
static void error_to_html(Error const&, StringBuilder& output_html, bool in_promise);
static void trace_to_html(TracebackFrame const&, StringBuilder& output_html);
static String style_from_style_type(StyleType);
static StyleType style_type_for_token(Token);