mirror of
https://github.com/hanzoai/core-js.git
synced 2026-09-24 16:58:15 +00:00
backport Iterator.prototype.includes
This commit is contained in:
@@ -12,6 +12,9 @@
|
||||
- `Iterator.prototype.windows`
|
||||
- Moved to stage 3, [May 2026 TC39 meeting](https://github.com/tc39/proposals/commit/7226f0af93443025010efcad219115cec7dc8b2a)
|
||||
- Added `/actual/` namespaces entries, unconditional forced replacement changed to feature detection
|
||||
- [`Iterator` includes stage 3 proposal](https://github.com/tc39/proposal-iterator-includes):
|
||||
- Added built-in:
|
||||
- `Iterator.prototype.includes`
|
||||
- Ensure opaque paths always roundtrip in URL polyfill (still without adding to feature detection), [whatwg/url#844](https://github.com/whatwg/url/pull/844)
|
||||
- Fixed possible crash on some keys in `Symbol.for`
|
||||
- Some `get-iterator` / `get-iterator-method` fixes
|
||||
|
||||
@@ -173,6 +173,7 @@ structuredClone(new Set([1, 2, 3])); // => new Set([1, 2, 3])
|
||||
- [`Math.sumPrecise`](#mathsumprecise)
|
||||
- [Stage 3 proposals](#stage-3-proposals)
|
||||
- [`Iterator` chunking](#iterator-chunking)
|
||||
- [`Iterator` includes](#iterator-includes)
|
||||
- [Stage 2.7 proposals](#stage-27-proposals)
|
||||
- [`Symbol.metadata` for decorators metadata proposal](#symbolmetadata-for-decorators-metadata-proposal)
|
||||
- [Stage 2 proposals](#stage-2-proposals)
|
||||
@@ -2901,6 +2902,26 @@ let windowsPartial = Array.from([0, 1].values().windows(3, 'allow-partial')); /
|
||||
let windowsFull = Array.from([0, 1].values().windows(3)); // []
|
||||
```
|
||||
|
||||
##### [`Iterator` includes](https://github.com/tc39/proposal-iterator-includes)[⬆](#index)
|
||||
Module [`esnext.iterator.includes`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.iterator.includes.js)
|
||||
```ts
|
||||
class Iterator {
|
||||
includes(searchElement: any, skippedElements?: number): boolean;
|
||||
}
|
||||
```
|
||||
[*CommonJS entry points:*](#commonjs-api)
|
||||
```
|
||||
core-js/proposals/iterator-includes
|
||||
core-js(-pure)/actual|full/iterator/includes
|
||||
```
|
||||
```js
|
||||
[1, 2, 3].values().includes(2); // => true
|
||||
[1, 2, 3].values().includes(4); // => false
|
||||
[NaN].values().includes(NaN); // => true
|
||||
[1, 2, 3].values().includes(3, 2); // => true
|
||||
[1, 2, 3].values().includes(1, 1); // => false
|
||||
```
|
||||
|
||||
#### Stage 2.7 proposals[⬆](#index)
|
||||
[*CommonJS entry points:*](#commonjs-api)
|
||||
```
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# Iterator includes
|
||||
[Specification](https://tc39.es/proposal-iterator-includes/)\
|
||||
[Proposal repo](https://github.com/tc39/proposal-iterator-includes)
|
||||
|
||||
## Modules
|
||||
[`esnext.iterator.includes`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.iterator.includes.js)
|
||||
|
||||
## Built-ins signatures
|
||||
```ts
|
||||
class Iterator {
|
||||
includes(searchElement: any, skippedElements?: number): boolean;
|
||||
}
|
||||
```
|
||||
|
||||
## [Entry points]({docs-version}/docs/usage#h-entry-points)
|
||||
```plaintext
|
||||
core-js/proposals/iterator-includes
|
||||
core-js(-pure)/actual|full/iterator/includes
|
||||
```
|
||||
|
||||
## Examples
|
||||
```js
|
||||
[1, 2, 3].values().includes(2); // => true
|
||||
[1, 2, 3].values().includes(4); // => false
|
||||
[NaN].values().includes(NaN); // => true
|
||||
[1, 2, 3].values().includes(3, 2); // => true
|
||||
[1, 2, 3].values().includes(1, 1); // => false
|
||||
```
|
||||
@@ -257,6 +257,10 @@
|
||||
{
|
||||
"title": "Iterator chunking",
|
||||
"url": "{docs-version}/docs/features/proposals/iterator-chunking"
|
||||
},
|
||||
{
|
||||
"title": "Iterator includes",
|
||||
"url": "{docs-version}/docs/features/proposals/iterator-includes"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -2632,6 +2632,8 @@ export const data = {
|
||||
'esnext.iterator.for-each': null,
|
||||
// TODO: Remove from `core-js@4`
|
||||
'esnext.iterator.from': null,
|
||||
'esnext.iterator.includes': {
|
||||
},
|
||||
'esnext.iterator.indexed': {
|
||||
},
|
||||
// TODO: Remove from `core-js@4`
|
||||
|
||||
@@ -326,5 +326,6 @@ export default {
|
||||
'3.50': [
|
||||
'es.iterator.zip',
|
||||
'es.iterator.zip-keyed',
|
||||
'esnext.iterator.includes',
|
||||
],
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
var parent = require('../../stable/iterator/concat');
|
||||
require('../../modules/esnext.iterator.chunks');
|
||||
require('../../modules/esnext.iterator.concat');
|
||||
require('../../modules/esnext.iterator.includes');
|
||||
require('../../modules/esnext.iterator.windows');
|
||||
|
||||
module.exports = parent;
|
||||
|
||||
@@ -11,6 +11,7 @@ require('../../modules/esnext.iterator.find');
|
||||
require('../../modules/esnext.iterator.flat-map');
|
||||
require('../../modules/esnext.iterator.for-each');
|
||||
require('../../modules/esnext.iterator.from');
|
||||
require('../../modules/esnext.iterator.includes');
|
||||
require('../../modules/esnext.iterator.map');
|
||||
require('../../modules/esnext.iterator.reduce');
|
||||
require('../../modules/esnext.iterator.some');
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
'use strict';
|
||||
require('../../modules/es.object.to-string');
|
||||
require('../../modules/es.iterator.constructor');
|
||||
require('../../modules/esnext.iterator.includes');
|
||||
|
||||
var entryUnbind = require('../../internals/entry-unbind');
|
||||
|
||||
module.exports = entryUnbind('Iterator', 'includes');
|
||||
@@ -13,6 +13,7 @@ require('../../modules/esnext.iterator.find');
|
||||
require('../../modules/esnext.iterator.flat-map');
|
||||
require('../../modules/esnext.iterator.for-each');
|
||||
require('../../modules/esnext.iterator.from');
|
||||
require('../../modules/esnext.iterator.includes');
|
||||
require('../../modules/esnext.iterator.map');
|
||||
require('../../modules/esnext.iterator.reduce');
|
||||
require('../../modules/esnext.iterator.some');
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
var parent = require('../../stable/iterator/zip');
|
||||
require('../../modules/esnext.iterator.chunks');
|
||||
require('../../modules/esnext.iterator.includes');
|
||||
require('../../modules/esnext.iterator.windows');
|
||||
require('../../modules/esnext.iterator.zip-keyed');
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
'use strict';
|
||||
var parent = require('../../stable/iterator/zip');
|
||||
require('../../modules/esnext.iterator.chunks');
|
||||
require('../../modules/esnext.iterator.includes');
|
||||
require('../../modules/esnext.iterator.windows');
|
||||
require('../../modules/esnext.iterator.zip');
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
'use strict';
|
||||
var parent = require('../../actual/iterator/includes');
|
||||
|
||||
module.exports = parent;
|
||||
@@ -17,6 +17,7 @@ require('../../modules/es.iterator.to-array');
|
||||
// TODO: drop from core-js@4
|
||||
require('../../modules/esnext.iterator.constructor');
|
||||
require('../../modules/esnext.iterator.chunks');
|
||||
require('../../modules/esnext.iterator.includes');
|
||||
require('../../modules/esnext.iterator.range');
|
||||
require('../../modules/esnext.iterator.sliding');
|
||||
require('../../modules/esnext.iterator.windows');
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
'use strict';
|
||||
var $ = require('../internals/export');
|
||||
var anObject = require('../internals/an-object');
|
||||
var isIntegralNumber = require('../internals/is-integral-number');
|
||||
var iterate = require('../internals/iterate');
|
||||
var iteratorClose = require('../internals/iterator-close');
|
||||
var sameValueZero = require('../internals/same-value-zero');
|
||||
var IS_PURE = require('../internals/is-pure');
|
||||
|
||||
var $RangeError = RangeError;
|
||||
var $TypeError = TypeError;
|
||||
var $Infinity = Infinity;
|
||||
|
||||
var INVALID_SKIPPED_ELEMENTS = 'skippedElements should be a positive integer or Infinity';
|
||||
|
||||
// `Iterator.prototype.includes` method
|
||||
// https://github.com/tc39/proposal-iterator-includes
|
||||
$({ target: 'Iterator', proto: true, real: true, forced: IS_PURE }, {
|
||||
includes: function includes(searchElement /* , skippedElements */) {
|
||||
anObject(this);
|
||||
var skippedElements = arguments.length > 1 ? arguments[1] : undefined;
|
||||
var skipped = 0;
|
||||
var toSkip;
|
||||
try {
|
||||
if (skippedElements === undefined) {
|
||||
toSkip = 0;
|
||||
} else if (skippedElements === $Infinity || skippedElements === -$Infinity || isIntegralNumber(skippedElements)) {
|
||||
toSkip = skippedElements;
|
||||
} else {
|
||||
throw new $TypeError(INVALID_SKIPPED_ELEMENTS);
|
||||
}
|
||||
if (toSkip < 0) throw new $RangeError(INVALID_SKIPPED_ELEMENTS);
|
||||
} catch (error) {
|
||||
iteratorClose(this, 'throw', error);
|
||||
}
|
||||
|
||||
return iterate(this, function (value, stop) {
|
||||
if (skipped < toSkip) skipped++;
|
||||
else if (sameValueZero(value, searchElement)) return stop();
|
||||
}, { IS_ITERATOR: true, INTERRUPTED: true }).stopped;
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
'use strict';
|
||||
// https://github.com/tc39/proposal-iterator-includes
|
||||
require('../modules/esnext.iterator.includes');
|
||||
@@ -2,6 +2,7 @@
|
||||
var parent = require('./4');
|
||||
|
||||
require('../proposals/decorator-metadata-v2');
|
||||
require('../proposals/iterator-includes');
|
||||
require('../proposals/joint-iteration');
|
||||
// TODO: Obsolete versions, remove from `core-js@4`
|
||||
require('../proposals/array-grouping-stage-3');
|
||||
|
||||
@@ -1955,6 +1955,9 @@ GLOBAL.tests = {
|
||||
'esnext.iterator.chunks': function () {
|
||||
return Iterator.prototype.chunks;
|
||||
},
|
||||
'esnext.iterator.includes': function () {
|
||||
return Iterator.prototype.includes;
|
||||
},
|
||||
'esnext.iterator.range': function () {
|
||||
return Iterator.range;
|
||||
},
|
||||
|
||||
@@ -721,6 +721,7 @@ for (PATH of ['core-js-pure', 'core-js']) {
|
||||
ok(typeof load(NS, 'async-iterator/to-array') == 'function');
|
||||
ok(load(NS, 'function/metadata') === null);
|
||||
ok(typeof load(NS, 'iterator/chunks') == 'function');
|
||||
ok(load(NS, 'iterator/includes')([1, 2].values(), 2) === true);
|
||||
ok(typeof load(NS, 'iterator/to-async') == 'function');
|
||||
ok(typeof load(NS, 'iterator/windows') == 'function');
|
||||
ok(load(NS, 'symbol/metadata'));
|
||||
@@ -956,6 +957,7 @@ for (PATH of ['core-js-pure', 'core-js']) {
|
||||
load('proposals/iterator-sequencing');
|
||||
load('proposals/iterator-chunking');
|
||||
load('proposals/iterator-chunking-v2');
|
||||
load('proposals/iterator-includes');
|
||||
load('proposals/joint-iteration');
|
||||
load('proposals/json-parse-with-source');
|
||||
load('proposals/keys-composition');
|
||||
|
||||
@@ -1300,6 +1300,7 @@ const forbidCompletelyNonExistentBuiltIns = {
|
||||
] }],
|
||||
'es/no-nonstandard-iterator-prototype-properties': [ERROR, { allow: [
|
||||
'chunks',
|
||||
'includes',
|
||||
'sliding',
|
||||
'toAsync',
|
||||
'windows',
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import { STRICT } from '../helpers/constants.js';
|
||||
import { createIterator } from '../helpers/helpers.js';
|
||||
|
||||
QUnit.test('Iterator#includes', assert => {
|
||||
const { includes } = Iterator.prototype;
|
||||
|
||||
assert.isFunction(includes);
|
||||
assert.arity(includes, 1);
|
||||
assert.name(includes, 'includes');
|
||||
assert.looksNative(includes);
|
||||
assert.nonEnumerable(Iterator.prototype, 'includes');
|
||||
|
||||
assert.true(includes.call(createIterator([1, 2, 3]), 2), 'basic functionality #1');
|
||||
assert.false(includes.call(createIterator([1, 2, 3]), 4), 'basic functionality #2');
|
||||
assert.true(includes.call(createIterator([1, 'foo', 3]), 'foo'), 'basic functionality #3');
|
||||
assert.false(includes.call(createIterator([]), 1), 'empty iterator');
|
||||
|
||||
// SameValueZero semantics
|
||||
assert.true(includes.call(createIterator([NaN]), NaN), 'NaN is found');
|
||||
assert.true(includes.call(createIterator([0]), -0), '+0 and -0 are equal #1');
|
||||
assert.true(includes.call(createIterator([-0]), 0), '+0 and -0 are equal #2');
|
||||
assert.false(includes.call(createIterator([undefined]), null), 'undefined is not null');
|
||||
|
||||
// skippedElements parameter - valid values
|
||||
assert.true(includes.call(createIterator([1, 2, 3]), 3, 2), 'skippedElements #1');
|
||||
assert.false(includes.call(createIterator([1, 2, 3]), 1, 1), 'skippedElements #2');
|
||||
assert.true(includes.call(createIterator([1, 2, 3]), 1, 0), 'skippedElements 0');
|
||||
assert.true(includes.call(createIterator([1, 2, 3]), 1, -0), 'skippedElements -0');
|
||||
assert.true(includes.call(createIterator([1, 2, 3]), 1, undefined), 'skippedElements undefined');
|
||||
assert.false(includes.call(createIterator([1, 2, 3]), 1, Infinity), 'skippedElements Infinity');
|
||||
assert.true(includes.call(createIterator([1, 2, 3, 2]), 2, 2), 'skippedElements finds later occurrence');
|
||||
assert.false(includes.call(createIterator([1, 2, 3]), 2, 3), 'skippedElements skips all');
|
||||
|
||||
// skippedElements parameter - invalid values (must be integral Number, +Infinity, or -Infinity)
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, 1.5), TypeError, 'non-integer number');
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, NaN), TypeError, 'NaN');
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, '1'), TypeError, 'string');
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, true), TypeError, 'boolean');
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, null), TypeError, 'null');
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, {}), TypeError, 'object');
|
||||
|
||||
// skippedElements - negative values
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, -1), RangeError, 'negative integer');
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, -Infinity), RangeError, 'negative Infinity');
|
||||
|
||||
// iterator closing on match
|
||||
const it1 = createIterator([1, 2, 3], {
|
||||
return() {
|
||||
this.closed = true;
|
||||
return { done: true, value: undefined };
|
||||
},
|
||||
});
|
||||
assert.true(includes.call(it1, 2), 'found element');
|
||||
assert.true(it1.closed, 'iterator closes on match');
|
||||
|
||||
// iterator closing on skippedElements validation error
|
||||
const it2 = createIterator([1, 2, 3], { return() { this.closed = true; } });
|
||||
assert.throws(() => includes.call(it2, 1, -1), RangeError, 'negative skippedElements');
|
||||
assert.true(it2.closed, 'iterator closes on negative skippedElements');
|
||||
|
||||
const it3 = createIterator([1, 2, 3], { return() { this.closed = true; } });
|
||||
assert.throws(() => includes.call(it3, 1, 1.5), TypeError, 'non-integer skippedElements');
|
||||
assert.true(it3.closed, 'iterator closes on non-integer skippedElements');
|
||||
|
||||
if (STRICT) {
|
||||
assert.throws(() => includes.call(undefined, 1), TypeError, 'non-object this #1');
|
||||
assert.throws(() => includes.call(null, 1), TypeError, 'non-object this #2');
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,70 @@
|
||||
import { STRICT } from '../helpers/constants.js';
|
||||
import { createIterator } from '../helpers/helpers.js';
|
||||
|
||||
import Iterator from 'core-js-pure/full/iterator';
|
||||
|
||||
QUnit.test('Iterator#includes', assert => {
|
||||
const { includes } = Iterator.prototype;
|
||||
|
||||
assert.isFunction(includes);
|
||||
assert.arity(includes, 1);
|
||||
assert.name(includes, 'includes');
|
||||
assert.nonEnumerable(Iterator.prototype, 'includes');
|
||||
|
||||
assert.true(includes.call(createIterator([1, 2, 3]), 2), 'basic functionality #1');
|
||||
assert.false(includes.call(createIterator([1, 2, 3]), 4), 'basic functionality #2');
|
||||
assert.true(includes.call(createIterator([1, 'foo', 3]), 'foo'), 'basic functionality #3');
|
||||
assert.false(includes.call(createIterator([]), 1), 'empty iterator');
|
||||
|
||||
// SameValueZero semantics
|
||||
assert.true(includes.call(createIterator([NaN]), NaN), 'NaN is found');
|
||||
assert.true(includes.call(createIterator([0]), -0), '+0 and -0 are equal #1');
|
||||
assert.true(includes.call(createIterator([-0]), 0), '+0 and -0 are equal #2');
|
||||
assert.false(includes.call(createIterator([undefined]), null), 'undefined is not null');
|
||||
|
||||
// skippedElements parameter - valid values
|
||||
assert.true(includes.call(createIterator([1, 2, 3]), 3, 2), 'skippedElements #1');
|
||||
assert.false(includes.call(createIterator([1, 2, 3]), 1, 1), 'skippedElements #2');
|
||||
assert.true(includes.call(createIterator([1, 2, 3]), 1, 0), 'skippedElements 0');
|
||||
assert.true(includes.call(createIterator([1, 2, 3]), 1, -0), 'skippedElements -0');
|
||||
assert.true(includes.call(createIterator([1, 2, 3]), 1, undefined), 'skippedElements undefined');
|
||||
assert.false(includes.call(createIterator([1, 2, 3]), 1, Infinity), 'skippedElements Infinity');
|
||||
assert.true(includes.call(createIterator([1, 2, 3, 2]), 2, 2), 'skippedElements finds later occurrence');
|
||||
assert.false(includes.call(createIterator([1, 2, 3]), 2, 3), 'skippedElements skips all');
|
||||
|
||||
// skippedElements parameter - invalid values (must be integral Number, +Infinity, or -Infinity)
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, 1.5), TypeError, 'non-integer number');
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, NaN), TypeError, 'NaN');
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, '1'), TypeError, 'string');
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, true), TypeError, 'boolean');
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, null), TypeError, 'null');
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, {}), TypeError, 'object');
|
||||
|
||||
// skippedElements - negative values
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, -1), RangeError, 'negative integer');
|
||||
assert.throws(() => includes.call(createIterator([1]), 1, -Infinity), RangeError, 'negative Infinity');
|
||||
|
||||
// iterator closing on match
|
||||
const it1 = createIterator([1, 2, 3], {
|
||||
return() {
|
||||
this.closed = true;
|
||||
return { done: true, value: undefined };
|
||||
},
|
||||
});
|
||||
assert.true(includes.call(it1, 2), 'found element');
|
||||
assert.true(it1.closed, 'iterator closes on match');
|
||||
|
||||
// iterator closing on skippedElements validation error
|
||||
const it2 = createIterator([1, 2, 3], { return() { this.closed = true; } });
|
||||
assert.throws(() => includes.call(it2, 1, -1), RangeError, 'negative skippedElements');
|
||||
assert.true(it2.closed, 'iterator closes on negative skippedElements');
|
||||
|
||||
const it3 = createIterator([1, 2, 3], { return() { this.closed = true; } });
|
||||
assert.throws(() => includes.call(it3, 1, 1.5), TypeError, 'non-integer skippedElements');
|
||||
assert.true(it3.closed, 'iterator closes on non-integer skippedElements');
|
||||
|
||||
if (STRICT) {
|
||||
assert.throws(() => includes.call(undefined, 1), TypeError, 'non-object this #1');
|
||||
assert.throws(() => includes.call(null, 1), TypeError, 'non-object this #2');
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user