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

Update Set methods proposal #1150

Merged
merged 11 commits into from Dec 11, 2022
18 changes: 18 additions & 0 deletions CHANGELOG.md
Expand Up @@ -35,6 +35,24 @@
- Added `/actual/` entries, unconditional forced replacement disabled for features that survived to Stage 3
- `.from` accept strings, `.flatMap` throws on strings returned from the callback, [proposal-iterator-helpers/244](https://github.com/tc39/proposal-iterator-helpers/pull/244), [proposal-iterator-helpers/250](https://github.com/tc39/proposal-iterator-helpers/pull/250)
- `.from` and `.flatMap` throws on non-object *iterators*, [proposal-iterator-helpers/253](https://github.com/tc39/proposal-iterator-helpers/pull/253)
- [`Set` methods proposal](https://github.com/tc39/proposal-set-methods):
- Methods:
- `Set.prototype.intersection`
- `Set.prototype.union`
- `Set.prototype.difference`
- `Set.prototype.symmetricDifference`
- `Set.prototype.isSubsetOf`
- `Set.prototype.isSupersetOf`
- `Set.prototype.isDisjointFrom`
- Moved to Stage 3, [November 2022 TC39 meeting](https://github.com/babel/proposals/issues/85#issuecomment-1332175557)
- Reimplemented with [new semantics](https://tc39.es/proposal-set-methods/):
- Optimized performance (iteration over lowest set)
- Accepted only `Set`-like objects as an argument, not all iterables
- Accepted only `Set`s as `this`, no `@@species` support, and other minor changes
- Added `/actual/` entries, unconditional forced replacement changed to feature detection
- For avoiding breaking changes:
- New versions of methods are implemented as new modules and available in new entries or entries where old versions of methods were not available before (like `/actual/` namespace)
- In entries where they were available before (like `/full/` namespace), those methods are available with fallbacks to old semantics (in addition to `Set`-like, they accept iterable objects). This behavior will be removed from the next major release
- [Well-Formed Unicode Strings](https://github.com/tc39/proposal-is-usv-string) proposal:
- Methods:
- `String.prototype.isWellFormed`
Expand Down
71 changes: 35 additions & 36 deletions README.md
Expand Up @@ -129,9 +129,9 @@ queueMicrotask(() => console.log('called as microtask'));
- [`Array.fromAsync`](#arrayfromasync)
- [`Array` grouping](#array-grouping)
- [Change `Array` by copy](#change-array-by-copy)
- [New `Set` methods](#new-set-methods)
- [Well-formed unicode strings](#well-formed-unicode-strings)
- [Stage 2 proposals](#stage-2-proposals)
- [New `Set` methods](#new-set-methods)
- [`Map.prototype.emplace`](#mapprototypeemplace)
- [`Array.isTemplateObject`](#arrayistemplateobject)
- [`Symbol.{ asyncDispose, dispose }` for `using` statement](#symbol-asyncdispose-dispose--for-using-statement)
Expand Down Expand Up @@ -2277,6 +2277,40 @@ const correctionNeeded = [1, 1, 3];
correctionNeeded.with(1, 2); // => [1, 2, 3]
correctionNeeded; // => [1, 1, 3]
````
##### [New `Set` methods](https://github.com/tc39/proposal-set-methods)[⬆](#index)
Modules [`esnext.set.difference.v2`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.difference.v2.js), [`esnext.set.intersection.v2`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.intersection.v2.js), [`esnext.set.is-disjoint-from.v2`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.is-disjoint-from.v2.js), [`esnext.set.is-subset-of.v2`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.is-subset-of.v2.js), [`esnext.set.is-superset-of.v2`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.is-superset-of.v2.js), [`esnext.set.symmetric-difference.v2`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.symmetric-difference.v2.js), [`esnext.set.union.v2`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.union.v2.js)
```js
class Set {
difference(other: SetLike<mixed>): Set;
intersection(other: SetLike<mixed>): Set;
isDisjointFrom(other: SetLike<mixed>): boolean;
isSubsetOf(other: SetLike<mixed>): boolean;
isSupersetOf(other: SetLike<mixed>): boolean;
symmetricDifference(other: SetLike<mixed>): Set;
union(other: SetLike<mixed>): Set;
}
```
[*CommonJS entry points:*](#commonjs-api)
```js
core-js/proposals/set-methods-v2
core-js(-pure)/actual|full/set/difference
core-js(-pure)/actual|full/set/intersection
core-js(-pure)/actual|full/set/is-disjoint-from
core-js(-pure)/actual|full/set/is-subset-of
core-js(-pure)/actual|full/set/is-superset-of
core-js(-pure)/actual|full/set/symmetric-difference
core-js(-pure)/actual|full/set/union
```
[*Examples*](https://tinyurl.com/2henaoac):
```js
new Set([1, 2, 3]).union(new Set([3, 4, 5])); // => Set {1, 2, 3, 4, 5}
new Set([1, 2, 3]).intersection(new Set([3, 4, 5])); // => Set {3}
new Set([1, 2, 3]).difference(new Set([3, 4, 5])); // => Set {1, 2}
new Set([1, 2, 3]).symmetricDifference(new Set([3, 4, 5])); // => Set {1, 2, 4, 5}
new Set([1, 2, 3]).isDisjointFrom(new Set([4, 5, 6])); // => true
new Set([1, 2, 3]).isSubsetOf(new Set([5, 4, 3, 2, 1])); // => true
new Set([5, 4, 3, 2, 1]).isSupersetOf(new Set([1, 2, 3])); // => true
```
##### [Well-formed unicode strings](https://github.com/tc39/proposal-is-usv-string)[⬆](#index)
Modules [`esnext.string.is-well-formed`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.string.is-well-formed.js) and [`esnext.string.to-well-formed`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.string.to-well-formed.js)
```js
Expand Down Expand Up @@ -2305,41 +2339,6 @@ core-js(-pure)/actual|full/string(/virtual)/to-well-formed
```
core-js(-pure)/stage/2
```
##### [New `Set` methods](https://github.com/tc39/proposal-set-methods)[⬆](#index)
Modules [`esnext.set.difference`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.difference.js), [`esnext.set.intersection`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.intersection.js), [`esnext.set.is-disjoint-from`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.is-disjoint-from.js), [`esnext.set.is-subset-of`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.is-subset-of.js), [`esnext.set.is-superset-of`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.is-superset-of.js), [`esnext.set.symmetric-difference`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.symmetric-difference.js), [`esnext.set.union`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.set.union.js)
```js
class Set {
difference(iterable: SetLike<mixed>): Set;
intersection(iterable: SetLike<mixed>): Set;
isDisjointFrom(iterable: SetLike<mixed>): boolean;
isSubsetOf(iterable: SetLike<mixed>): boolean;
isSupersetOf(iterable: SetLike<mixed>): boolean;
symmetricDifference(iterable: SetLike<mixed>): Set;
union(iterable: SetLike<mixed>): Set;
}
```
[*CommonJS entry points:*](#commonjs-api)
```js
core-js/proposals/set-methods
core-js(-pure)/full/set/difference
core-js(-pure)/full/set/intersection
core-js(-pure)/full/set/is-disjoint-from
core-js(-pure)/full/set/is-subset-of
core-js(-pure)/full/set/is-superset-of
core-js(-pure)/full/set/symmetric-difference
core-js(-pure)/full/set/union
```
[*Examples*](https://tinyurl.com/2henaoac):
```js
new Set([1, 2, 3]).union(new Set([3, 4, 5])); // => Set {1, 2, 3, 4, 5}
new Set([1, 2, 3]).intersection(new Set([3, 4, 5])); // => Set {3}
new Set([1, 2, 3]).difference(new Set([3, 4, 5])); // => Set {1, 2}
new Set([1, 2, 3]).symmetricDifference(new Set([3, 4, 5])); // => Set {1, 2, 4, 5}

new Set([1, 2, 3]).isDisjointFrom(new Set([4, 5, 6])); // => true
new Set([1, 2, 3]).isSubsetOf(new Set([5, 4, 3, 2, 1])); // => true
new Set([5, 4, 3, 2, 1]).isSupersetOf(new Set([1, 2, 3])); // => true
```
##### [`Map.prototype.emplace`](https://github.com/thumbsupep/proposal-upsert)[⬆](#index)
Modules [`esnext.map.emplace`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.map.emplace.js) and [`esnext.weak-map.emplace`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.weak-map.emplace.js)
```js
Expand Down
21 changes: 21 additions & 0 deletions packages/core-js-compat/src/data.mjs
Expand Up @@ -2071,6 +2071,9 @@ export const data = {
},
'esnext.set.delete-all': {
},
'esnext.set.difference.v2': {
},
// TODO: Remove from `core-js@4`
'esnext.set.difference': {
},
'esnext.set.every': {
Expand All @@ -2081,12 +2084,24 @@ export const data = {
},
'esnext.set.from': {
},
'esnext.set.intersection.v2': {
},
// TODO: Remove from `core-js@4`
'esnext.set.intersection': {
},
'esnext.set.is-disjoint-from.v2': {
},
// TODO: Remove from `core-js@4`
'esnext.set.is-disjoint-from': {
},
'esnext.set.is-subset-of.v2': {
},
// TODO: Remove from `core-js@4`
'esnext.set.is-subset-of': {
},
'esnext.set.is-superset-of.v2': {
},
// TODO: Remove from `core-js@4`
'esnext.set.is-superset-of': {
},
'esnext.set.join': {
Expand All @@ -2099,8 +2114,14 @@ export const data = {
},
'esnext.set.some': {
},
'esnext.set.symmetric-difference.v2': {
},
// TODO: Remove from `core-js@4`
'esnext.set.symmetric-difference': {
},
'esnext.set.union.v2': {
},
// TODO: Remove from `core-js@4`
'esnext.set.union': {
},
// TODO: Remove from `core-js@4`
Expand Down
9 changes: 9 additions & 0 deletions packages/core-js-compat/src/modules-by-versions.mjs
Expand Up @@ -162,4 +162,13 @@ export default {
'esnext.string.to-well-formed',
'web.self',
],
3.27: [
'esnext.set.difference.v2',
'esnext.set.intersection.v2',
'esnext.set.is-disjoint-from.v2',
'esnext.set.is-subset-of.v2',
'esnext.set.is-superset-of.v2',
'esnext.set.symmetric-difference.v2',
'esnext.set.union.v2',
],
};
61 changes: 61 additions & 0 deletions packages/core-js-pure/override/internals/set-helpers.js
@@ -0,0 +1,61 @@
var getBuiltIn = require('../internals/get-built-in');
var anObject = require('../internals/an-object');
var tryToString = require('../internals/try-to-string');
var iterateSimple = require('../internals/iterate-simple');

var Set = getBuiltIn('Set');
var SetPrototype = Set.prototype;
var $TypeError = TypeError;

var aSet = function (it) {
anObject(it);
if ('size' in it && 'has' in it && 'add' in it && 'delete' in it && 'keys' in it) return it;
throw $TypeError(tryToString(it) + ' is not a set');
};

var add = function (set, it) {
return set.add(it);
};

var remove = function (set, it) {
return set['delete'](it);
};

var forEach = function (set, fn) {
set.forEach(fn);
};

var has = function (set, it) {
return set.has(it);
};

var size = function (set) {
return set.size;
};

var clone = function (set) {
var result = new Set();
forEach(set, function (it) {
add(result, it);
});
return result;
};

var iterate = function (set, fn) {
var iterator = set.keys();
return iterateSimple(iterator, fn, iterator.next);
};

module.exports = {
Set: Set,
aSet: aSet,
add: add,
remove: remove,
forEach: forEach,
has: has,
size: size,
clone: clone,
iterate: iterate,
$has: SetPrototype.has,
$keys: SetPrototype.keys
};
@@ -0,0 +1,3 @@
module.exports = function () {
return false;
};
5 changes: 5 additions & 0 deletions packages/core-js/actual/set/difference.js
@@ -0,0 +1,5 @@
require('../../modules/es.set');
require('../../modules/esnext.set.difference.v2');
var entryUnbind = require('../../internals/entry-unbind');

module.exports = entryUnbind('Set', 'difference');
7 changes: 7 additions & 0 deletions packages/core-js/actual/set/index.js
@@ -1,3 +1,10 @@
var parent = require('../../stable/set');
require('../../modules/esnext.set.difference.v2');
require('../../modules/esnext.set.intersection.v2');
require('../../modules/esnext.set.is-disjoint-from.v2');
require('../../modules/esnext.set.is-subset-of.v2');
require('../../modules/esnext.set.is-superset-of.v2');
require('../../modules/esnext.set.symmetric-difference.v2');
require('../../modules/esnext.set.union.v2');

module.exports = parent;
5 changes: 5 additions & 0 deletions packages/core-js/actual/set/intersection.js
@@ -0,0 +1,5 @@
require('../../modules/es.set');
require('../../modules/esnext.set.intersection.v2');
var entryUnbind = require('../../internals/entry-unbind');

module.exports = entryUnbind('Set', 'intersection');
5 changes: 5 additions & 0 deletions packages/core-js/actual/set/is-disjoint-from.js
@@ -0,0 +1,5 @@
require('../../modules/es.set');
require('../../modules/esnext.set.is-disjoint-from.v2');
var entryUnbind = require('../../internals/entry-unbind');

module.exports = entryUnbind('Set', 'isDisjointFrom');
5 changes: 5 additions & 0 deletions packages/core-js/actual/set/is-subset-of.js
@@ -0,0 +1,5 @@
require('../../modules/es.set');
require('../../modules/esnext.set.is-subset-of.v2');
var entryUnbind = require('../../internals/entry-unbind');

module.exports = entryUnbind('Set', 'isSubsetOf');
5 changes: 5 additions & 0 deletions packages/core-js/actual/set/is-superset-of.js
@@ -0,0 +1,5 @@
require('../../modules/es.set');
require('../../modules/esnext.set.is-superset-of.v2');
var entryUnbind = require('../../internals/entry-unbind');

module.exports = entryUnbind('Set', 'isSupersetOf');
5 changes: 5 additions & 0 deletions packages/core-js/actual/set/symmetric-difference.js
@@ -0,0 +1,5 @@
require('../../modules/es.set');
require('../../modules/esnext.set.symmetric-difference.v2');
var entryUnbind = require('../../internals/entry-unbind');

module.exports = entryUnbind('Set', 'symmetricDifference');
5 changes: 5 additions & 0 deletions packages/core-js/actual/set/union.js
@@ -0,0 +1,5 @@
require('../../modules/es.set');
require('../../modules/esnext.set.union.v2');
var entryUnbind = require('../../internals/entry-unbind');

module.exports = entryUnbind('Set', 'union');
2 changes: 1 addition & 1 deletion packages/core-js/full/set/difference.js
@@ -1,5 +1,5 @@
require('../../actual/set/difference');
require('../../modules/es.array.iterator');
require('../../modules/es.set');
require('../../modules/es.string.iterator');
require('../../modules/esnext.set.difference');
require('../../modules/web.dom-collections.iterator');
Expand Down
2 changes: 1 addition & 1 deletion packages/core-js/full/set/intersection.js
@@ -1,5 +1,5 @@
require('../../actual/set/intersection');
require('../../modules/es.array.iterator');
require('../../modules/es.set');
require('../../modules/es.string.iterator');
require('../../modules/esnext.set.intersection');
require('../../modules/web.dom-collections.iterator');
Expand Down
2 changes: 1 addition & 1 deletion packages/core-js/full/set/is-disjoint-from.js
@@ -1,5 +1,5 @@
require('../../actual/set/is-disjoint-from');
require('../../modules/es.array.iterator');
require('../../modules/es.set');
require('../../modules/es.string.iterator');
require('../../modules/esnext.set.is-disjoint-from');
require('../../modules/web.dom-collections.iterator');
Expand Down
2 changes: 1 addition & 1 deletion packages/core-js/full/set/is-subset-of.js
@@ -1,5 +1,5 @@
require('../../actual/set/is-subset-of');
require('../../modules/es.array.iterator');
require('../../modules/es.set');
require('../../modules/es.string.iterator');
require('../../modules/esnext.set.is-subset-of');
require('../../modules/web.dom-collections.iterator');
Expand Down
2 changes: 1 addition & 1 deletion packages/core-js/full/set/is-superset-of.js
@@ -1,5 +1,5 @@
require('../../actual/set/is-superset-of');
require('../../modules/es.array.iterator');
require('../../modules/es.set');
require('../../modules/es.string.iterator');
require('../../modules/esnext.set.is-superset-of');
require('../../modules/web.dom-collections.iterator');
Expand Down
2 changes: 1 addition & 1 deletion packages/core-js/full/set/symmetric-difference.js
@@ -1,5 +1,5 @@
require('../../actual/set/symmetric-difference');
require('../../modules/es.array.iterator');
require('../../modules/es.set');
require('../../modules/es.string.iterator');
require('../../modules/esnext.set.symmetric-difference');
require('../../modules/web.dom-collections.iterator');
Expand Down
2 changes: 1 addition & 1 deletion packages/core-js/full/set/union.js
@@ -1,5 +1,5 @@
require('../../actual/set/union');
require('../../modules/es.array.iterator');
require('../../modules/es.set');
require('../../modules/es.string.iterator');
require('../../modules/esnext.set.union');
require('../../modules/web.dom-collections.iterator');
Expand Down
38 changes: 38 additions & 0 deletions packages/core-js/internals/get-set-record.js
@@ -0,0 +1,38 @@
var aCallable = require('../internals/a-callable');
var anObject = require('../internals/an-object');
var call = require('../internals/function-call');
var toIntegerOrInfinity = require('../internals/to-integer-or-infinity');

var $TypeError = TypeError;

var SetRecord = function (set, size, has, keys) {
this.set = set;
this.size = size;
this.has = has;
this.keys = keys;
};

SetRecord.prototype = {
getIterator: function () {
return anObject(call(this.keys, this.set));
},
includes: function (it) {
return call(this.has, this.set, it);
}
};

// `GetSetRecord` abstract operation
// https://tc39.es/proposal-set-methods/#sec-getsetrecord
module.exports = function (obj) {
anObject(obj);
var numSize = +obj.size;
// NOTE: If size is undefined, then numSize will be NaN
// eslint-disable-next-line no-self-compare -- NaN check
if (numSize != numSize) throw $TypeError('Invalid size');
return new SetRecord(
obj,
toIntegerOrInfinity(numSize),
aCallable(obj.has),
aCallable(obj.keys)
);
};