1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 05:07:34 +00:00

LibJS+WebContent+js: Reimplement console.log() and friends to spec

This implements the Logger and Printer abstract operations defined in
the console spec, and stubs out the Formatter AO. These are then used
for the "output a categorized log message" functions.
This commit is contained in:
Sam Atkins 2021-12-10 12:26:25 +00:00 committed by Andreas Kling
parent fd7163b125
commit 260836135a
5 changed files with 211 additions and 125 deletions

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2020, Emanuele Torre <torreemanuele6@gmail.com>
* Copyright (c) 2020-2021, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -20,53 +21,58 @@ VM& Console::vm()
return m_global_object.vm();
}
Value Console::debug()
// 1.1.3. debug(...data), https://console.spec.whatwg.org/#debug
ThrowCompletionOr<Value> Console::debug()
{
#ifdef __serenity__
dbgln("\033[32;1m(js debug)\033[0m {}", vm().join_arguments());
#endif
if (m_client)
return m_client->debug();
// 1. Perform Logger("debug", data).
if (m_client) {
auto data = vm_arguments();
return m_client->logger(LogLevel::Debug, data);
}
return js_undefined();
}
Value Console::error()
// 1.1.4. error(...data), https://console.spec.whatwg.org/#error
ThrowCompletionOr<Value> Console::error()
{
#ifdef __serenity__
dbgln("\033[32;1m(js error)\033[0m {}", vm().join_arguments());
#endif
if (m_client)
return m_client->error();
// 1. Perform Logger("error", data).
if (m_client) {
auto data = vm_arguments();
return m_client->logger(LogLevel::Error, data);
}
return js_undefined();
}
Value Console::info()
// 1.1.5. info(...data), https://console.spec.whatwg.org/#info
ThrowCompletionOr<Value> Console::info()
{
#ifdef __serenity__
dbgln("\033[32;1m(js info)\033[0m {}", vm().join_arguments());
#endif
if (m_client)
return m_client->info();
// 1. Perform Logger("info", data).
if (m_client) {
auto data = vm_arguments();
return m_client->logger(LogLevel::Info, data);
}
return js_undefined();
}
Value Console::log()
// 1.1.6. log(...data), https://console.spec.whatwg.org/#log
ThrowCompletionOr<Value> Console::log()
{
#ifdef __serenity__
dbgln("\033[32;1m(js log)\033[0m {}", vm().join_arguments());
#endif
if (m_client)
return m_client->log();
// 1. Perform Logger("log", data).
if (m_client) {
auto data = vm_arguments();
return m_client->logger(LogLevel::Log, data);
}
return js_undefined();
}
Value Console::warn()
// 1.1.9. warn(...data), https://console.spec.whatwg.org/#warn
ThrowCompletionOr<Value> Console::warn()
{
#ifdef __serenity__
dbgln("\033[32;1m(js warn)\033[0m {}", vm().join_arguments());
#endif
if (m_client)
return m_client->warn();
// 1. Perform Logger("warn", data).
if (m_client) {
auto data = vm_arguments();
return m_client->logger(LogLevel::Warn, data);
}
return js_undefined();
}
@ -127,6 +133,42 @@ bool Console::counter_reset(String label)
return true;
}
Vector<Value> Console::vm_arguments()
{
Vector<Value> arguments;
arguments.ensure_capacity(vm().argument_count());
for (size_t i = 0; i < vm().argument_count(); ++i) {
arguments.append(vm().argument(i));
}
return arguments;
}
void Console::output_debug_message([[maybe_unused]] LogLevel log_level, [[maybe_unused]] String output) const
{
#ifdef __serenity__
switch (log_level) {
case JS::Console::LogLevel::Debug:
dbgln("\033[32;1m(js debug)\033[0m {}", output);
break;
case JS::Console::LogLevel::Error:
dbgln("\033[32;1m(js error)\033[0m {}", output);
break;
case JS::Console::LogLevel::Info:
dbgln("\033[32;1m(js info)\033[0m {}", output);
break;
case JS::Console::LogLevel::Log:
dbgln("\033[32;1m(js log)\033[0m {}", output);
break;
case JS::Console::LogLevel::Warn:
dbgln("\033[32;1m(js warn)\033[0m {}", output);
break;
default:
dbgln("\033[32;1m(js)\033[0m {}", output);
break;
}
#endif
}
VM& ConsoleClient::vm()
{
return global_object().vm();
@ -142,4 +184,45 @@ Vector<String> ConsoleClient::get_trace() const
return trace;
}
// 2.1. Logger(logLevel, args), https://console.spec.whatwg.org/#logger
ThrowCompletionOr<Value> ConsoleClient::logger(Console::LogLevel log_level, Vector<Value>& args)
{
auto& global_object = this->global_object();
// 1. If args is empty, return.
if (args.is_empty())
return js_undefined();
// 2. Let first be args[0].
auto first = args[0];
// 3. Let rest be all elements following first in args.
size_t rest_size = args.size() - 1;
// 4. If rest is empty, perform Printer(logLevel, « first ») and return.
if (rest_size == 0) {
auto first_as_vector = Vector { first };
return printer(log_level, first_as_vector);
}
// 5. If first does not contain any format specifiers, perform Printer(logLevel, args).
if (!TRY(first.to_string(global_object)).contains('%')) {
TRY(printer(log_level, args));
} else {
// 6. Otherwise, perform Printer(logLevel, Formatter(args)).
auto formatted = TRY(formatter(args));
TRY(printer(log_level, formatted));
}
// 7. Return undefined.
return js_undefined();
}
// 2.2. Formatter(args), https://console.spec.whatwg.org/#formatter
ThrowCompletionOr<Vector<Value>> ConsoleClient::formatter(Vector<Value>& args)
{
// TODO: Actually implement formatting
return args;
}
}