1919#include < LibJS/Runtime/Error.h>
2020#include < LibJS/Runtime/FunctionObject.h>
2121#include < LibJS/Runtime/GlobalObject.h>
22+ #include < LibJS/Runtime/Map.h>
2223#include < LibJS/Runtime/ObjectPrototype.h>
2324#include < LibJS/Runtime/Realm.h>
2425#include < LibJS/Runtime/Value.h>
@@ -73,6 +74,7 @@ void ArrayPrototype::initialize(GlobalObject& global_object)
7374 define_native_function (vm.names .entries , entries, 0 , attr);
7475 define_native_function (vm.names .copyWithin , copy_within, 2 , attr);
7576 define_native_function (vm.names .groupBy , group_by, 1 , attr);
77+ define_native_function (vm.names .groupByToMap , group_by_to_map, 1 , attr);
7678
7779 // Use define_direct_property here instead of define_native_function so that
7880 // Object.is(Array.prototype[Symbol.iterator], Array.prototype.values)
@@ -95,6 +97,7 @@ void ArrayPrototype::initialize(GlobalObject& global_object)
9597 MUST (unscopable_list->create_data_property_or_throw (vm.names .flat , Value (true )));
9698 MUST (unscopable_list->create_data_property_or_throw (vm.names .flatMap , Value (true )));
9799 MUST (unscopable_list->create_data_property_or_throw (vm.names .groupBy , Value (true )));
100+ MUST (unscopable_list->create_data_property_or_throw (vm.names .groupByToMap , Value (true )));
98101 MUST (unscopable_list->create_data_property_or_throw (vm.names .includes , Value (true )));
99102 MUST (unscopable_list->create_data_property_or_throw (vm.names .keys , Value (true )));
100103 MUST (unscopable_list->create_data_property_or_throw (vm.names .values , Value (true )));
@@ -1750,4 +1753,75 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::group_by)
17501753 return object;
17511754}
17521755
1756+ // 2.2 Array.prototype.groupByToMap ( callbackfn [ , thisArg ] ), https://tc39.es/proposal-array-grouping/#sec-array.prototype.groupbymap
1757+ JS_DEFINE_NATIVE_FUNCTION (ArrayPrototype::group_by_to_map)
1758+ {
1759+ auto callback_function = vm.argument (0 );
1760+ auto this_arg = vm.argument (1 );
1761+
1762+ // 1. Let O be ? ToObject(this value).
1763+ auto * this_object = TRY (vm.this_value (global_object).to_object (global_object));
1764+
1765+ // 2. Let len be ? LengthOfArrayLike(O).
1766+ auto length = TRY (length_of_array_like (global_object, *this_object));
1767+
1768+ // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
1769+ if (!callback_function.is_function ())
1770+ return vm.throw_completion <TypeError>(global_object, ErrorType::NotAFunction, callback_function.to_string_without_side_effects ());
1771+
1772+ struct KeyedGroupTraits : public Traits <Handle<Value>> {
1773+ static unsigned hash (Handle<Value> const & value_handle)
1774+ {
1775+ return ValueTraits::hash (value_handle.value ());
1776+ }
1777+
1778+ static bool equals (Handle<Value> const & a, Handle<Value> const & b)
1779+ {
1780+ // AddValueToKeyedGroup uses SameValue on the keys on Step 1.a.
1781+ return same_value (a.value (), b.value ());
1782+ }
1783+ };
1784+
1785+ // 5. Let groups be a new empty List.
1786+ OrderedHashMap<Handle<Value>, MarkedValueList, KeyedGroupTraits> groups;
1787+
1788+ // 4. Let k be 0.
1789+ // 6. Repeat, while k < len
1790+ for (size_t index = 0 ; index < length; ++index) {
1791+ // a. Let Pk be ! ToString(𝔽(k)).
1792+ auto index_property = PropertyKey { index };
1793+
1794+ // b. Let kValue be ? Get(O, Pk).
1795+ auto k_value = TRY (this_object->get (index_property));
1796+
1797+ // c. Let key be ? Call(callbackfn, thisArg, « kValue, 𝔽(k), O »).
1798+ auto key = TRY (vm.call (callback_function.as_function (), this_arg, k_value, Value (index), this_object));
1799+
1800+ // d. If key is -0𝔽, set key to +0𝔽.
1801+ if (key.is_negative_zero ())
1802+ key = Value (0 );
1803+
1804+ // e. Perform ! AddValueToKeyedGroup(groups, key, kValue).
1805+ add_value_to_keyed_group (global_object, groups, make_handle (key), k_value);
1806+
1807+ // f. Set k to k + 1.
1808+ }
1809+
1810+ // 7. Let map be ! Construct(%Map%).
1811+ auto * map = Map::create (global_object);
1812+
1813+ // 8. For each Record { [[Key]], [[Elements]] } g of groups, do
1814+ for (auto & group : groups) {
1815+ // a. Let elements be ! CreateArrayFromList(g.[[Elements]]).
1816+ auto * elements = Array::create_from (global_object, group.value );
1817+
1818+ // b. Let entry be the Record { [[Key]]: g.[[Key]], [[Value]]: elements }.
1819+ // c. Append entry as the last element of map.[[MapData]].
1820+ map->entries ().set (group.key .value (), elements);
1821+ }
1822+
1823+ // 9. Return map.
1824+ return map;
1825+ }
1826+
17531827}
0 commit comments