1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 21:58:12 +00:00

LibJS+WebContent+Browser+js: Implement console.group() methods

This implements:
- console.group()
- console.groupCollapsed()
- console.groupEnd()

In the Browser, we use `<details>` for the groups, which is not actually
implemented yet, so groups are always open.

In the REPL, groups are non-interactive, but still indent any output.
This looks weird since the console prompt and return values remain on
the far left, but this matches what Node does so it's probably fine. :^)
I expect `console.group()` is not used much outside of browsers.
This commit is contained in:
Sam Atkins 2021-12-22 12:32:15 +00:00 committed by Andreas Kling
parent ff5e07d718
commit d702678d16
10 changed files with 281 additions and 25 deletions

View file

@ -79,7 +79,8 @@ ThrowCompletionOr<Value> Console::warn()
// 1.1.2. clear(), https://console.spec.whatwg.org/#clear
Value Console::clear()
{
// 1. TODO: Empty the appropriate group stack.
// 1. Empty the appropriate group stack.
m_group_stack.clear();
// 2. If possible for the environment, clear the console. (Otherwise, do nothing.)
if (m_client)
@ -107,12 +108,7 @@ ThrowCompletionOr<Value> Console::trace()
StringBuilder builder;
auto data = vm_arguments();
auto formatted_data = TRY(m_client->formatter(data));
for (auto const& item : formatted_data) {
if (!builder.is_empty())
builder.append(' ');
builder.append(TRY(item.to_string(global_object())));
}
trace.label = builder.to_string();
trace.label = TRY(value_vector_to_string(formatted_data));
}
// 3. Perform Printer("trace", « trace »).
@ -221,6 +217,88 @@ ThrowCompletionOr<Value> Console::assert_()
return js_undefined();
}
// 1.3.1. group(...data), https://console.spec.whatwg.org/#group
ThrowCompletionOr<Value> Console::group()
{
// 1. Let group be a new group.
Group group;
// 2. If data is not empty, let groupLabel be the result of Formatter(data).
String group_label;
auto data = vm_arguments();
if (!data.is_empty()) {
auto formatted_data = TRY(m_client->formatter(data));
group_label = TRY(value_vector_to_string(formatted_data));
}
// ... Otherwise, let groupLabel be an implementation-chosen label representing a group.
else {
group_label = "Group";
}
// 3. Incorporate groupLabel as a label for group.
group.label = group_label;
// 4. Optionally, if the environment supports interactive groups, group should be expanded by default.
// NOTE: This is handled in Printer.
// 5. Perform Printer("group", « group »).
if (m_client)
TRY(m_client->printer(LogLevel::Group, group));
// 6. Push group onto the appropriate group stack.
m_group_stack.append(group);
return js_undefined();
}
// 1.3.2. groupCollapsed(...data), https://console.spec.whatwg.org/#groupcollapsed
ThrowCompletionOr<Value> Console::group_collapsed()
{
// 1. Let group be a new group.
Group group;
// 2. If data is not empty, let groupLabel be the result of Formatter(data).
String group_label;
auto data = vm_arguments();
if (!data.is_empty()) {
auto formatted_data = TRY(m_client->formatter(data));
group_label = TRY(value_vector_to_string(formatted_data));
}
// ... Otherwise, let groupLabel be an implementation-chosen label representing a group.
else {
group_label = "Group";
}
// 3. Incorporate groupLabel as a label for group.
group.label = group_label;
// 4. Optionally, if the environment supports interactive groups, group should be collapsed by default.
// NOTE: This is handled in Printer.
// 5. Perform Printer("groupCollapsed", « group »).
if (m_client)
TRY(m_client->printer(LogLevel::GroupCollapsed, group));
// 6. Push group onto the appropriate group stack.
m_group_stack.append(group);
return js_undefined();
}
// 1.3.3. groupEnd(), https://console.spec.whatwg.org/#groupend
ThrowCompletionOr<Value> Console::group_end()
{
if (m_group_stack.is_empty())
return js_undefined();
// 1. Pop the last group from the group stack.
m_group_stack.take_last();
if (m_client)
m_client->end_group();
return js_undefined();
}
Vector<Value> Console::vm_arguments()
{
Vector<Value> arguments;
@ -257,6 +335,17 @@ void Console::output_debug_message([[maybe_unused]] LogLevel log_level, [[maybe_
#endif
}
ThrowCompletionOr<String> Console::value_vector_to_string(Vector<Value>& values)
{
StringBuilder builder;
for (auto const& item : values) {
if (!builder.is_empty())
builder.append(' ');
builder.append(TRY(item.to_string(global_object())));
}
return builder.to_string();
}
VM& ConsoleClient::vm()
{
return global_object().vm();