-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
JSLib, WebContent: Implement console.table
- Expose table from console object - Add new Table log level - Create a JS object that represents table rows and columns - Print table as HTML using WebContentConsoleClient
- Loading branch information
1 parent
dd8c693
commit b74a281
Showing
7 changed files
with
288 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
* Copyright (c) 2020, Emanuele Torre <[email protected]> | ||
* Copyright (c) 2020-2023, Linus Groh <[email protected]> | ||
* Copyright (c) 2021-2022, Sam Atkins <[email protected]> | ||
* Copyright (c) 2024, Gasim Gasimzada <[email protected]> | ||
* | ||
* SPDX-License-Identifier: BSD-2-Clause | ||
*/ | ||
|
@@ -11,6 +12,7 @@ | |
#include <LibJS/Console.h> | ||
#include <LibJS/Print.h> | ||
#include <LibJS/Runtime/AbstractOperations.h> | ||
#include <LibJS/Runtime/Array.h> | ||
#include <LibJS/Runtime/Completion.h> | ||
#include <LibJS/Runtime/StringConstructor.h> | ||
#include <LibJS/Runtime/Temporal/Duration.h> | ||
|
@@ -140,6 +142,145 @@ ThrowCompletionOr<Value> Console::log() | |
return js_undefined(); | ||
} | ||
|
||
static ThrowCompletionOr<NonnullGCPtr<Object>> create_table_row(Realm& realm, Value index, Value value, Vector<Value>& columns, HashMap<PropertyKey, bool>& visited_columns, HashMap<PropertyKey, bool>& input_columns) | ||
{ | ||
auto& vm = realm.vm(); | ||
|
||
auto item = Object::create(realm, nullptr); | ||
|
||
auto add_column = [&](PropertyKey column_name) -> Optional<Completion> { | ||
if (!visited_columns.contains(column_name)) { | ||
visited_columns.set(column_name, true); | ||
|
||
if (column_name.is_string()) { | ||
columns.append(PrimitiveString::create(vm, column_name.as_string())); | ||
} else if (column_name.is_symbol()) { | ||
columns.append(column_name.as_symbol()); | ||
} else if (column_name.is_number()) { | ||
columns.append(Value(column_name.as_number())); | ||
} | ||
} | ||
|
||
return {}; | ||
}; | ||
|
||
// "(index)" column that that shows array indices | ||
// or object keys | ||
{ | ||
auto key = PropertyKey("(index)"); | ||
TRY(item->set(key, index, Object::ShouldThrowExceptions::No)); | ||
|
||
add_column(key); | ||
} | ||
|
||
if (TRY(value.is_array(vm))) { | ||
auto& array = value.as_array(); | ||
for (auto const& prop : array.indexed_properties()) { | ||
PropertyKey key(prop.index()); | ||
|
||
// If `properties` array is passed and the current index does | ||
// not exist in it, do not add this column to the row. | ||
if (input_columns.size() > 0 && !input_columns.contains(key)) { | ||
continue; | ||
} | ||
|
||
TRY(item->set(key, TRY(array.get(key)), Object::ShouldThrowExceptions::No)); | ||
add_column(key); | ||
} | ||
} else if (value.is_object()) { | ||
auto& object = value.as_object(); | ||
object.enumerate_object_properties([&](Value key_v) -> Optional<Completion> { | ||
auto key = TRY(PropertyKey::from_value(vm, key_v)); | ||
|
||
// If `properties` array is passed and the current key does | ||
// not exist in it, do not add this column to the row. | ||
if (input_columns.size() > 0 && !input_columns.contains(key)) { | ||
return {}; | ||
} | ||
|
||
TRY(item->set(key, TRY(object.get(key)), Object::ShouldThrowExceptions::No)); | ||
add_column(key); | ||
|
||
return {}; | ||
}); | ||
} else { | ||
// The "Value" column | ||
PropertyKey key("Value"); | ||
TRY(item->set(key, value, Object::ShouldThrowExceptions::No)); | ||
|
||
add_column(key); | ||
} | ||
|
||
return item; | ||
} | ||
|
||
// 1.1.7. table(tabularData, properties), https://console.spec.whatwg.org/#table | ||
ThrowCompletionOr<Value> Console::table() | ||
{ | ||
if (!m_client) { | ||
return js_undefined(); | ||
} | ||
|
||
auto& vm = realm().vm(); | ||
|
||
if (vm.argument_count() > 0) { | ||
auto tabular_data = vm.argument(0); | ||
auto properties = vm.argument(1); | ||
|
||
HashMap<PropertyKey, bool> input_columns; | ||
|
||
if (TRY(properties.is_array(vm))) { | ||
auto& properties_array = properties.as_array().indexed_properties(); | ||
auto properties_storage = properties_array.storage(); | ||
for (auto const& col : properties_array) { | ||
auto col_name = properties_storage->get(col.index()).value().value; | ||
input_columns.set(TRY(PropertyKey::from_value(vm, col_name)), true); | ||
} | ||
} | ||
|
||
Vector<Value> rows; | ||
Vector<Value> columns; | ||
HashMap<PropertyKey, bool> visited_columns; | ||
if (TRY(tabular_data.is_array(vm))) { | ||
auto& array = tabular_data.as_array(); | ||
for (auto const& prop : array.indexed_properties()) { | ||
PropertyKey key(prop.index()); | ||
Value value = TRY(array.get(key)); | ||
|
||
auto item = TRY(create_table_row(realm(), Value(key.as_number()), value, columns, visited_columns, input_columns)); | ||
rows.append(item); | ||
} | ||
|
||
} else if (tabular_data.is_object()) { | ||
auto& object = tabular_data.as_object(); | ||
object.enumerate_object_properties([&](Value key) -> Optional<Completion> { | ||
auto index = TRY(PropertyKey::from_value(vm, key)); | ||
auto value = TRY(object.get(index)); | ||
|
||
auto item = TRY(create_table_row(realm(), key, value, columns, visited_columns, input_columns)); | ||
rows.append(item); | ||
|
||
return {}; | ||
}); | ||
} | ||
|
||
if (rows.size() > 0) { | ||
auto table_rows = Array::create_from(realm(), rows); | ||
auto table_cols = Array::create_from(realm(), columns); | ||
auto table = Object::create(realm(), nullptr); | ||
|
||
TRY(table->set(PropertyKey("rows"), table_rows, Object::ShouldThrowExceptions::No)); | ||
TRY(table->set(PropertyKey("columns"), table_cols, Object::ShouldThrowExceptions::No)); | ||
|
||
MarkedVector<Value> args(vm.heap()); | ||
args.append(Value(table)); | ||
return m_client->logger(LogLevel::Table, args); | ||
} | ||
} | ||
|
||
return m_client->logger(LogLevel::Log, vm_arguments()); | ||
} | ||
|
||
// 1.1.8. trace(...data), https://console.spec.whatwg.org/#trace | ||
ThrowCompletionOr<Value> Console::trace() | ||
{ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters