mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 15:27:35 +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:
parent
fd7163b125
commit
260836135a
5 changed files with 211 additions and 125 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Emanuele Torre <torreemanuele6@gmail.com>
|
||||
* Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -9,17 +10,39 @@
|
|||
#include <AK/Function.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/Noncopyable.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Runtime/Value.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
class ConsoleClient;
|
||||
|
||||
// https://console.spec.whatwg.org
|
||||
class Console {
|
||||
AK_MAKE_NONCOPYABLE(Console);
|
||||
AK_MAKE_NONMOVABLE(Console);
|
||||
|
||||
public:
|
||||
// These are not really levels, but that's the term used in the spec.
|
||||
enum class LogLevel {
|
||||
Assert,
|
||||
Count,
|
||||
CountReset,
|
||||
Debug,
|
||||
Dir,
|
||||
DirXML,
|
||||
Error,
|
||||
Group,
|
||||
GroupCollapsed,
|
||||
Info,
|
||||
Log,
|
||||
TimeEnd,
|
||||
TimeLog,
|
||||
Trace,
|
||||
Warn,
|
||||
};
|
||||
|
||||
explicit Console(GlobalObject&);
|
||||
|
||||
void set_client(ConsoleClient& client) { m_client = &client; }
|
||||
|
@ -28,15 +51,16 @@ public:
|
|||
const GlobalObject& global_object() const { return m_global_object; }
|
||||
|
||||
VM& vm();
|
||||
Vector<Value> vm_arguments();
|
||||
|
||||
HashMap<String, unsigned>& counters() { return m_counters; }
|
||||
const HashMap<String, unsigned>& counters() const { return m_counters; }
|
||||
|
||||
Value debug();
|
||||
Value error();
|
||||
Value info();
|
||||
Value log();
|
||||
Value warn();
|
||||
ThrowCompletionOr<Value> debug();
|
||||
ThrowCompletionOr<Value> error();
|
||||
ThrowCompletionOr<Value> info();
|
||||
ThrowCompletionOr<Value> log();
|
||||
ThrowCompletionOr<Value> warn();
|
||||
Value clear();
|
||||
Value trace();
|
||||
Value count();
|
||||
|
@ -46,6 +70,8 @@ public:
|
|||
unsigned counter_increment(String label);
|
||||
bool counter_reset(String label);
|
||||
|
||||
void output_debug_message(LogLevel log_level, String output) const;
|
||||
|
||||
private:
|
||||
GlobalObject& m_global_object;
|
||||
ConsoleClient* m_client { nullptr };
|
||||
|
@ -60,11 +86,10 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
virtual Value debug() = 0;
|
||||
virtual Value error() = 0;
|
||||
virtual Value info() = 0;
|
||||
virtual Value log() = 0;
|
||||
virtual Value warn() = 0;
|
||||
ThrowCompletionOr<Value> logger(Console::LogLevel log_level, Vector<Value>& args);
|
||||
ThrowCompletionOr<Vector<Value>> formatter(Vector<Value>& args);
|
||||
virtual ThrowCompletionOr<Value> printer(Console::LogLevel log_level, Vector<Value>&) = 0;
|
||||
|
||||
virtual Value clear() = 0;
|
||||
virtual Value trace() = 0;
|
||||
virtual Value count() = 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue