From 76f7ae64cfb657de66f6f12f04d2f6a03b99c3e2 Mon Sep 17 00:00:00 2001 From: Rolf Martin Glomsrud Date: Mon, 10 Jan 2022 15:24:49 +0000 Subject: [PATCH] Bug 1739648 - implement groupBy r=arai Depends on D133870 Differential Revision: https://phabricator.services.mozilla.com/D133881 --- js/src/builtin/Array.cpp | 1 + js/src/builtin/Array.js | 82 +++++++++++++++++-- js/xpconnect/tests/chrome/test_xrayToJS.xhtml | 2 +- 3 files changed, 75 insertions(+), 10 deletions(-) diff --git a/js/src/builtin/Array.cpp b/js/src/builtin/Array.cpp index 7a9ecb6797cd..710f7da03c7b 100644 --- a/js/src/builtin/Array.cpp +++ b/js/src/builtin/Array.cpp @@ -3839,6 +3839,7 @@ static const JSFunctionSpec array_methods[] = { JS_SELF_HOSTED_FN("forEach", "ArrayForEach", 1, 0), JS_SELF_HOSTED_FN("map", "ArrayMap", 1, 0), JS_SELF_HOSTED_FN("filter", "ArrayFilter", 1, 0), + JS_SELF_HOSTED_FN("groupBy", "ArrayGroupBy", 1, 0), JS_SELF_HOSTED_FN("groupByToMap", "ArrayGroupByToMap", 1, 0), JS_SELF_HOSTED_FN("reduce", "ArrayReduce", 1, 0), JS_SELF_HOSTED_FN("reduceRight", "ArrayReduceRight", 1, 0), diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js index 7d2b7f4f61d8..f34ca7b89795 100644 --- a/js/src/builtin/Array.js +++ b/js/src/builtin/Array.js @@ -307,6 +307,70 @@ function ArrayFilter(callbackfn/*, thisArg*/) { return A; } +// Array Grouping proposal +// +// Array.prototype.groupBy +// https://tc39.es/proposal-array-grouping/#sec-array.prototype.groupby +function ArrayGroupBy(callbackfn/*, thisArg*/) { + /* Step 1. Let O be ? ToObject(this value). */ + var O = ToObject(this); + + /* Step 2. Let len be ? LengthOfArrayLike(O). */ + var len = ToLength(O.length); + + /* Step 3. If IsCallable(callbackfn) is false, throw a TypeError exception. */ + if (!IsCallable(callbackfn)) { + ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, callbackfn)); + } + + /* Step 5. Let groups be a new empty List. */ + var groups = new_List(); + + var T = arguments.length > 1 ? arguments[1] : void 0; + + /* Steps 4, 6. */ + for (var k = 0; k < len; k++) { + + /* Skip Step 6.a. Let Pk be ! ToString(๐”ฝ(k)). + * + * k is coerced into a string through the property access. */ + + /* Step 6.b. Let kValue be ? Get(O, Pk). */ + var kValue = O[k]; + + /* Step 6.c. + * Let propertyKey be ? ToPropertyKey( + * ? Call(callbackfn, thisArg, ยซ kValue, ๐”ฝ(k), O ยป)). + */ + var propertyKey = TO_PROPERTY_KEY( + callContentFunction(callbackfn, T, kValue, k, O) + ); + + /* Step 6.d. Perform ! AddValueToKeyedGroup(groups, propertyKey, kValue). */ + if (!groups[propertyKey]) { + var elements = [ kValue ]; + DefineDataProperty(groups, propertyKey, elements); + } else { + var lenElements = groups[propertyKey].length; + DefineDataProperty(groups[propertyKey], lenElements, kValue); + } + } + + /* Step 7. Let obj be ! OrdinaryObjectCreate(null). */ + var object = {}; + + /* Step 8. For each Record { [[Key]], [[Elements]] } g of groups, do + * a. Let elements be ! CreateArrayFromList(g.[[Elements]]). + * b. Perform ! CreateDataPropertyOrThrow(obj, g.[[Key]], elements). + */ + for (var propertyKey in groups) { + DefineDataProperty(object, propertyKey, groups[propertyKey]) + } + + /* Step 9. Return obj. */ + return object; +} + // Array Grouping proposal // // Array.prototype.groupByToMap @@ -338,39 +402,39 @@ function ArrayGroupByToMap(callbackfn/*, thisArg*/) { var T = arguments.length > 1 ? arguments[1] : void 0; - /* Combined Step 6. and Step 8. + /* Combine Step 6. and Step 8. * * We have direct access to the map constructor and set/get methods. * We can treat these two loops as one, as there isn't a risk that user * polyfilling will impact the implementation. */ - for(var k = 0; k