Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Changes from October 2021 TC39 meeting #1001

Merged
merged 4 commits into from
Dec 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## Changelog
##### Unreleased
- [`Array` grouping proposal](https://github.com/tc39/proposal-array-grouping):
- Moved to the stage 2
- Added `Array.prototype.groupByMap` method
- Removed `@@species` support
- Added [change `Array` by copy stage 2 proposal](https://github.com/tc39/proposal-change-array-by-copy):
- `Array.prototype.toReversed`
- `Array.prototype.toSorted`
Expand Down
24 changes: 9 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ Promise.resolve(32).then(x => console.log(x)); // => 32
- [`Iterator` helpers](#iterator-helpers)
- [New `Set` methods](#new-set-methods)
- [`Map.prototype.emplace`](#mapprototypeemplace)
- [`Array` grouping](#array-grouping)
- [Change `Array` by copy](#change-array-by-copy)
- [`Array.isTemplateObject`](#arrayistemplateobject)
- [`Symbol.{ asyncDispose, dispose }` for `using` statement](#symbol-asyncdispose-dispose--for-using-statement)
Expand All @@ -112,7 +113,6 @@ Promise.resolve(32).then(x => console.log(x)); // => 32
- [`compositeKey` and `compositeSymbol`](#compositekey-and-compositesymbol)
- [`Array.fromAsync`](#arrayfromasync)
- [`Array` filtering](#array-filtering)
- [`Array` grouping](#array-grouping)
- [`Array` deduplication](#array-deduplication)
- [Getting last item from `Array`](#getting-last-item-from-array)
- [`Number.range`](#numberrange)
Expand Down Expand Up @@ -2353,21 +2353,16 @@ console.log(compositeSymbol(1, a, 2, b) === compositeSymbol(1, a, 2, b)); // =>
console.log(compositeSymbol(a, a) === compositeSymbol(a, a)); // => true
```
##### [`Array.fromAsync`](https://github.com/tc39/proposal-array-from-async)[⬆](#index)
Modules [`esnext.array.from-async`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.from-async.js) and [`esnext.typed-array.from-async`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.typed-array.from-async.js)
Modules [`esnext.array.from-async`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.from-async.js).
```js
class Array {
static fromAsync(asyncItems: AsyncIterable | Iterable | ArrayLike, mapfn?: (value: any, index: number) => any, thisArg?: any): Array;
}

class %TypedArray% {
static fromAsync(asyncItems: AsyncIterable | Iterable | ArrayLike, mapfn?: (value: number, index: number, target) => number, thisArg?: any): %TypedArray%;
}
```
[*CommonJS entry points:*](#commonjs-api)
```js
core-js/proposals/array-from-async
core-js(-pure)/features/array/from-async
core-js/features/typed-array/from-async
```
[*Example*](https://goo.gl/Jt7SsD):
```js
Expand Down Expand Up @@ -2395,26 +2390,25 @@ core-js/features/typed-array/filter-reject
[1, 2, 3, 4, 5].filterReject(it => it % 2); // => [2, 4]
````
##### [`Array` grouping](#https://github.com/tc39/proposal-array-grouping)[⬆](#index)
Modules [`esnext.array.group-by`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.group-by.js) and [`esnext.typed-array.group-by`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.typed-array.group-by.js).
Modules [`esnext.array.group-by`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.group-by.js), [`esnext.array.group-by-map`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.group-by-map.js).
```js
class Array {
groupBy(callbackfn: (value: any, index: number, target: any) => key, thisArg?: any): { [key]: Array<mixed> };
groupByMap(callbackfn: (value: any, index: number, target: any) => key, thisArg?: any): Map<key, Array<mixed>>;
}

class %TypedArray% {
groupBy(callbackfn: (value: number, index: number, target: %TypedArray%) => key, thisArg?: any): { [key]: %TypedArray% };
}
```
[*CommonJS entry points:*](#commonjs-api)
```
core-js/proposals/array-grouping
core-js(-pure)/features/array(/virtual)/group-by
core-js/features/typed-array/group-by
core-js(-pure)/features/array(/virtual)/group-by-map
```
[*Examples*](t.ly/VggI):
[*Examples*](t.ly/xEqc):
```js
[1, 2, 3, 4, 5].groupBy(it => it % 2); // => { 1: [1, 3, 5], 0: [2, 4] }
const map = [1, 2, 3, 4, 5].groupByMap(it => it % 2);
map.get(1); // => [1, 3, 5]
map.get(0); // => [2, 4]
````
##### [Array deduplication](https://github.com/tc39/proposal-array-unique)[⬆](#index)
Modules [`esnext.array.unique-by`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.unique-by.js) and [`esnext.typed-array.unique-by`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.typed-array.unique-by.js)
Expand Down Expand Up @@ -3086,4 +3080,4 @@ console.log(getIteratorMethod({})); // undefined
- ES `Proxy` can't be polyfilled, you can try to use [`proxy-polyfill`](https://github.com/GoogleChrome/proxy-polyfill) which provides a very little subset of features.
- ES `String#normalize` is not a very useful feature, but this polyfill will be very large. If you need it, you can use [unorm](https://github.com/walling/unorm/).
- ECMA-402 `Intl` is missed because of the size. You can use [those polyfills](https://formatjs.io/docs/polyfills).
- `window.fetch` is not a cross-platform feature, in some environments, it makes no sense. For this reason, I don't think it should be in `core-js`. Looking at a large number of requests it *might be* added in the future. Now you can use, for example, [this polyfill](https://github.com/github/fetch).
- `window.fetch` is not a cross-platform feature, in some environments, it makes no sense. For this reason, I don't think it should be in `core-js`. Looking at a large number of requests it *might be* added in the future. Now you can use, for example, [this polyfill](https://github.com/github/fetch).
4 changes: 4 additions & 0 deletions packages/core-js-compat/src/data.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1451,6 +1451,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 Expand Up @@ -1728,6 +1730,7 @@ export const data = {
// TODO: Remove from `core-js@4`
'esnext.symbol.replace-all': {
},
// TODO: Remove from `core-js@4`
'esnext.typed-array.from-async': {
},
// TODO: Remove from `core-js@4`
Expand All @@ -1745,6 +1748,7 @@ export const data = {
chrome: '97',
safari: '15.4',
},
// TODO: Remove from `core-js@4`
'esnext.typed-array.group-by': {
},
'esnext.typed-array.to-reversed': {
Expand Down
1 change: 1 addition & 0 deletions packages/core-js-compat/src/modules-by-versions.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export default {
'esnext.typed-array.from-async',
],
'3.20': [
'esnext.array.group-by-map',
'esnext.array.to-reversed',
'esnext.array.to-sorted',
'esnext.array.to-spliced',
Expand Down
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.to-reversed');
require('../../../modules/esnext.array.to-sorted');
require('../../../modules/esnext.array.to-spliced');
Expand Down
1 change: 1 addition & 0 deletions packages/core-js/internals/array-group-by.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ module.exports = function ($this, callbackfn, that, specificConstructor) {
if (key in target) push(target[key], value);
else target[key] = [value];
}
// TODO: Remove this block from `core-js@4`
if (specificConstructor) {
Constructor = specificConstructor(O);
if (Constructor !== Array) {
Expand Down
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');
3 changes: 1 addition & 2 deletions packages/core-js/modules/esnext.array.group-by.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
'use strict';
var $ = require('../internals/export');
var $groupBy = require('../internals/array-group-by');
var arraySpeciesConstructor = require('../internals/array-species-constructor');
var addToUnscopables = require('../internals/add-to-unscopables');

// `Array.prototype.groupBy` method
// https://github.com/tc39/proposal-array-grouping
$({ target: 'Array', proto: true }, {
groupBy: function groupBy(callbackfn /* , thisArg */) {
var thisArg = arguments.length > 1 ? arguments[1] : undefined;
return $groupBy(this, callbackfn, thisArg, arraySpeciesConstructor);
return $groupBy(this, callbackfn, thisArg);
}
});

Expand Down
1 change: 1 addition & 0 deletions packages/core-js/modules/esnext.typed-array.from-async.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
'use strict';
// TODO: Remove from `core-js@4`
var getBuiltIn = require('../internals/get-built-in');
var aConstructor = require('../internals/a-constructor');
var arrayFromAsync = require('../internals/array-from-async');
Expand Down
1 change: 1 addition & 0 deletions packages/core-js/modules/esnext.typed-array.group-by.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
'use strict';
// TODO: Remove from `core-js@4`
var ArrayBufferViewCore = require('../internals/array-buffer-view-core');
var $groupBy = require('../internals/array-group-by');
var typedArraySpeciesConstructor = require('../internals/typed-array-species-constructor');
Expand Down
1 change: 1 addition & 0 deletions packages/core-js/proposals/array-from-async.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// https://github.com/tc39/proposal-array-from-async
require('../modules/esnext.array.from-async');
// TODO: Remove from `core-js@4`
require('../modules/esnext.typed-array.from-async');
2 changes: 2 additions & 0 deletions packages/core-js/proposals/array-grouping.js
Original file line number Diff line number Diff line change
@@ -1,3 +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');
1 change: 0 additions & 1 deletion packages/core-js/stage/1.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
require('../proposals/array-filtering');
require('../proposals/array-from-async');
require('../proposals/array-grouping');
require('../proposals/array-last');
require('../proposals/array-unique');
require('../proposals/collection-methods');
Expand Down
1 change: 1 addition & 0 deletions packages/core-js/stage/2.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
require('../proposals/array-grouping');
require('../proposals/array-is-template-object');
require('../proposals/change-array-by-copy');
require('../proposals/decorators');
Expand Down
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 @@ -580,6 +581,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(load(NS, 'array/virtual/with').call([1, 2, 3], 1, 4));
ok(load(NS, 'array/virtual/to-reversed').call([1, 2, 3])[0] === 3);
Expand Down
6 changes: 0 additions & 6 deletions tests/compat/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1514,9 +1514,6 @@ GLOBAL.tests = {
'esnext.symbol.observable': function () {
return Symbol.observable;
},
'esnext.typed-array.from-async': function () {
return Int8Array.fromAsync;
},
'esnext.typed-array.filter-reject': function () {
return Int8Array.prototype.filterReject;
},
Expand All @@ -1526,9 +1523,6 @@ GLOBAL.tests = {
'esnext.typed-array.find-last-index': function () {
return Int8Array.prototype.findLastIndex;
},
'esnext.typed-array.group-by': function () {
return Int8Array.prototype.groupBy;
},
'esnext.typed-array.to-reversed': function () {
return Int8Array.prototype.toReversed;
},
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.true(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');
});
2 changes: 1 addition & 1 deletion tests/pure/esnext.array.group-by.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,5 @@ QUnit.test('Array#groupBy', assert => {
array.constructor = { [Symbol.species]: function () {
return { foo: 1 };
} };
assert.same(groupBy(array, Boolean).true.foo, 1, '@@species');
assert.same(groupBy(array, Boolean).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.true([].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');
});
2 changes: 1 addition & 1 deletion tests/tests/esnext.array.group-by.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,5 @@ QUnit.test('Array#groupBy', assert => {
array.constructor = { [Symbol.species]: function () {
return { foo: 1 };
} };
assert.same(array.groupBy(Boolean).true.foo, 1, '@@species');
assert.same(array.groupBy(Boolean).true.foo, undefined, 'no @@species');
});