Skip to content

Commit

Permalink
add Array#groupByMap
Browse files Browse the repository at this point in the history
  • Loading branch information
zloirock committed Oct 28, 2021
1 parent 2e3dc01 commit b3863d1
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/core-js-compat/src/data.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1449,6 +1449,8 @@ export const data = {
},
'esnext.array.group-by': {
},
'esnext.array.group-by-map': {
},
'esnext.array.is-template-object': {
},
// TODO: Remove from `core-js@4`
Expand Down
3 changes: 3 additions & 0 deletions packages/core-js-compat/src/modules-by-versions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,7 @@ export default {
'esnext.array.from-async',
'esnext.typed-array.from-async',
],
'3.20': [
'esnext.array.group-by-map',
],
};
5 changes: 5 additions & 0 deletions packages/core-js/features/array/group-by-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require('../../modules/es.map');
require('../../modules/esnext.array.group-by-map');
var entryUnbind = require('../../internals/entry-unbind');

module.exports = entryUnbind('Array', 'groupByMap');
1 change: 1 addition & 0 deletions packages/core-js/features/array/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require('../../modules/esnext.array.filter-reject');
require('../../modules/esnext.array.find-last');
require('../../modules/esnext.array.find-last-index');
require('../../modules/esnext.array.group-by');
require('../../modules/esnext.array.group-by-map');
require('../../modules/esnext.array.is-template-object');
require('../../modules/esnext.array.last-item');
require('../../modules/esnext.array.last-index');
Expand Down
5 changes: 5 additions & 0 deletions packages/core-js/features/array/virtual/group-by-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
require('../../../modules/es.map');
require('../../../modules/esnext.array.group-by-map');
var entryVirtual = require('../../../internals/entry-virtual');

module.exports = entryVirtual('Array').groupByMap;
1 change: 1 addition & 0 deletions packages/core-js/features/array/virtual/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require('../../../modules/esnext.array.filter-reject');
require('../../../modules/esnext.array.find-last');
require('../../../modules/esnext.array.find-last-index');
require('../../../modules/esnext.array.group-by');
require('../../../modules/esnext.array.group-by-map');
require('../../../modules/esnext.array.unique-by');

module.exports = parent;
38 changes: 38 additions & 0 deletions packages/core-js/modules/esnext.array.group-by-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
'use strict';
var $ = require('../internals/export');
var getBuiltIn = require('../internals/get-built-in');
var bind = require('../internals/function-bind-context');
var uncurryThis = require('../internals/function-uncurry-this');
var IndexedObject = require('../internals/indexed-object');
var toObject = require('../internals/to-object');
var lengthOfArrayLike = require('../internals/length-of-array-like');
var addToUnscopables = require('../internals/add-to-unscopables');

var Map = getBuiltIn('Map');
var MapPrototype = Map.prototype;
var mapGet = uncurryThis(MapPrototype.get);
var mapHas = uncurryThis(MapPrototype.has);
var mapSet = uncurryThis(MapPrototype.set);
var push = uncurryThis([].push);

// `Array.prototype.groupByMap` method
// https://github.com/tc39/proposal-array-grouping
$({ target: 'Array', proto: true }, {
groupByMap: function groupByMap(callbackfn /* , thisArg */) {
var O = toObject(this);
var self = IndexedObject(O);
var boundFunction = bind(callbackfn, arguments.length > 1 ? arguments[1] : undefined);
var map = new Map();
var length = lengthOfArrayLike(self);
var index = 0;
var key, value;
for (;length > index; index++) {
value = self[index];
key = boundFunction(value, index, O);
if (mapHas(map, key)) push(mapGet(map, key), value);
else mapSet(map, key, [value]);
} return map;
}
});

addToUnscopables('groupByMap');
1 change: 1 addition & 0 deletions packages/core-js/proposals/array-grouping.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// https://github.com/tc39/proposal-array-grouping
require('../modules/esnext.array.group-by');
require('../modules/esnext.array.group-by-map');
// TODO: Remove from `core-js@4`
require('../modules/esnext.typed-array.group-by');
2 changes: 2 additions & 0 deletions scripts/check-compat-tests.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ const ignore = new Set([
'esnext.string.at',
'esnext.symbol.pattern-match',
'esnext.symbol.replace-all',
'esnext.typed-array.from-async',
'esnext.typed-array.filter-out',
'esnext.typed-array.group-by',
'esnext.weak-map.upsert',
]);

Expand Down
2 changes: 2 additions & 0 deletions tests/commonjs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ for (PATH of ['core-js-pure', 'core-js']) {
ok(load(NS, 'array/find-last')([1, 2, 3], it => it % 2) === 3);
ok(load(NS, 'array/find-last-index')([1, 2, 3], it => it % 2) === 2);
ok(typeof load(NS, 'array/group-by') == 'function');
ok(typeof load(NS, 'array/group-by-map') == 'function');
ok(typeof load(NS, 'array/is-template-object') == 'function');
load(NS, 'array/last-item');
load(NS, 'array/last-index');
Expand All @@ -576,6 +577,7 @@ for (PATH of ['core-js-pure', 'core-js']) {
ok(load(NS, 'array/virtual/find-last').call([1, 2, 3], it => it % 2) === 3);
ok(load(NS, 'array/virtual/find-last-index').call([1, 2, 3], it => it % 2) === 2);
ok(typeof load(NS, 'array/virtual/group-by') == 'function');
ok(typeof load(NS, 'array/virtual/group-by-map') == 'function');
ok(typeof load(NS, 'array/virtual/unique-by') == 'function');
ok(typeof load(NS, 'async-iterator') == 'function');
ok(typeof load(NS, 'async-iterator/as-indexed-pairs') == 'function');
Expand Down
3 changes: 3 additions & 0 deletions tests/compat/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1221,6 +1221,9 @@ GLOBAL.tests = {
'esnext.array.group-by': function () {
return [].groupBy;
},
'esnext.array.group-by-map': function () {
return [].groupByMap;
},
'esnext.array.is-template-object': function () {
return Array.isTemplateObject;
},
Expand Down
37 changes: 37 additions & 0 deletions tests/pure/esnext.array.group-by-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { STRICT } from '../helpers/constants';

import Map from 'core-js-pure/es/map';
import Symbol from 'core-js-pure/es/symbol';
import from from 'core-js-pure/es/array/from';
import groupByMap from 'core-js-pure/features/array/group-by-map';

QUnit.test('Array#groupByMap', assert => {
assert.isFunction(groupByMap);
let array = [1];
const context = {};
groupByMap(array, function (value, key, that) {
assert.same(arguments.length, 3, 'correct number of callback arguments');
assert.same(value, 1, 'correct value in callback');
assert.same(key, 0, 'correct index in callback');
assert.same(that, array, 'correct link to array in callback');
assert.same(this, context, 'correct callback context');
}, context);
assert.ok(groupByMap([], it => it) instanceof Map, 'returns Map');
assert.deepEqual(from(groupByMap([1, 2, 3], it => it % 2)), [[1, [1, 3]], [0, [2]]], '#1');
assert.deepEqual(
from(groupByMap([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], it => `i${ it % 5 }`)),
[['i1', [1, 6, 11]], ['i2', [2, 7, 12]], ['i3', [3, 8]], ['i4', [4, 9]], ['i0', [5, 10]]],
'#2',
);
assert.deepEqual(from(groupByMap(Array(3), it => it)), [[undefined, [undefined, undefined, undefined]]], '#3');
if (STRICT) {
assert.throws(() => groupByMap(null, () => { /* empty */ }), TypeError);
assert.throws(() => groupByMap(undefined, () => { /* empty */ }), TypeError);
}
array = [1];
// eslint-disable-next-line object-shorthand -- constructor
array.constructor = { [Symbol.species]: function () {
return { foo: 1 };
} };
assert.same(groupByMap(array, Boolean).get(true).foo, undefined, 'no @@species');
});
39 changes: 39 additions & 0 deletions tests/tests/esnext.array.group-by-map.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { STRICT } from '../helpers/constants';

const { from } = Array;

QUnit.test('Array#groupByMap', assert => {
const { groupByMap } = Array.prototype;
assert.isFunction(groupByMap);
assert.arity(groupByMap, 1);
assert.name(groupByMap, 'groupByMap');
assert.looksNative(groupByMap);
assert.nonEnumerable(Array.prototype, 'groupByMap');
let array = [1];
const context = {};
array.groupByMap(function (value, key, that) {
assert.same(arguments.length, 3, 'correct number of callback arguments');
assert.same(value, 1, 'correct value in callback');
assert.same(key, 0, 'correct index in callback');
assert.same(that, array, 'correct link to array in callback');
assert.same(this, context, 'correct callback context');
}, context);
assert.ok([].groupByMap(it => it) instanceof Map, 'returns Map');
assert.deepEqual(from([1, 2, 3].groupByMap(it => it % 2)), [[1, [1, 3]], [0, [2]]], '#1');
assert.deepEqual(
from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].groupByMap(it => `i${ it % 5 }`)),
[['i1', [1, 6, 11]], ['i2', [2, 7, 12]], ['i3', [3, 8]], ['i4', [4, 9]], ['i0', [5, 10]]],
'#2',
);
assert.deepEqual(from(Array(3).groupByMap(it => it)), [[undefined, [undefined, undefined, undefined]]], '#3');
if (STRICT) {
assert.throws(() => groupByMap.call(null, () => { /* empty */ }), TypeError);
assert.throws(() => groupByMap.call(undefined, () => { /* empty */ }), TypeError);
}
array = [1];
// eslint-disable-next-line object-shorthand -- constructor
array.constructor = { [Symbol.species]: function () {
return { foo: 1 };
} };
assert.same(array.groupByMap(Boolean).get(true).foo, undefined, 'no @@species');
});

0 comments on commit b3863d1

Please sign in to comment.