Skip to content
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Fixed some cases of `Set.prototype.{ symmetricDifference, union }` detection
- Added missing dependencies to some entries of static `Iterator` methods
- Added missing `/full/{ instance, number/virtual }/clamp` entries
- Added `sliding` method to `Iterator` chunking stage 2 proposal
- Compat data improvements:
- Added Electron 38 compat data mapping
- `Iterator` helpers marked as fixed and updated following the latest spec changes in Safari 26.0
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3059,25 +3059,30 @@ core-js(-pure)/full/symbol/custom-matcher
```

##### [`Iterator` chunking](https://github.com/tc39/proposal-iterator-chunking)[⬆](#index)
Modules [`esnext.iterator.chunks`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.iterator.chunks.js) and [`esnext.iterator.windows`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.iterator.windows.js)
Modules [`esnext.iterator.chunks`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.iterator.chunks.js), [`esnext.iterator.sliding`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.iterator.sliding.js)
and [`esnext.iterator.windows`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.iterator.windows.js)
```ts
class Iterator {
chunks(chunkSize: number): Iterator<any>;
sliding(windowSize: number): Iterator<any>;
windows(windowSize: number): Iterator<any>;
}
```
[*CommonJS entry points:*](#commonjs-api)
```
core-js/proposals/iterator-chunking
core-js(-pure)/full/iterator/chunks
core-js(-pure)/full/iterator/sliding
core-js(-pure)/full/iterator/windows
```
[*Examples*](https://tinyurl.com/ypmzafjc)
[*Examples*](https://tinyurl.com/24xnkcnn)
```js
const digits = () => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].values();

let chunksOf2 = Array.from(digits().chunks(2)); // [ [0, 1], [2, 3], [4, 5], [6, 7], [8, 9] ]

let slidingOf2 = Array.from(digits().sliding(2)); // [ [0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9] ]

let windowsOf2 = Array.from(digits().windows(2)); // [ [0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9] ]
```

Expand Down
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 @@ -2484,6 +2484,8 @@ export const data = {
},
// TODO: Remove from `core-js@4`
'esnext.iterator.reduce': null,
'esnext.iterator.sliding': {
},
// TODO: Remove from `core-js@4`
'esnext.iterator.some': null,
// 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 @@ -299,4 +299,7 @@ export default {
'esnext.iterator.zip-keyed',
'esnext.number.clamp',
],
3.44: [
'esnext.iterator.sliding',
],
};
1 change: 1 addition & 0 deletions packages/core-js/full/iterator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var parent = require('../../actual/iterator');
require('../../modules/esnext.iterator.chunks');
require('../../modules/esnext.iterator.concat');
require('../../modules/esnext.iterator.range');
require('../../modules/esnext.iterator.sliding');
require('../../modules/esnext.iterator.windows');
require('../../modules/esnext.iterator.zip');
require('../../modules/esnext.iterator.zip-keyed');
Expand Down
8 changes: 8 additions & 0 deletions packages/core-js/full/iterator/sliding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict';
require('../../modules/es.object.to-string');
require('../../modules/es.iterator.constructor');
require('../../modules/esnext.iterator.sliding');

var entryUnbind = require('../../internals/entry-unbind');

module.exports = entryUnbind('Iterator', 'sliding');
45 changes: 45 additions & 0 deletions packages/core-js/internals/iterator-window.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
'use strict';
var anObject = require('../internals/an-object');
var call = require('../internals/function-call');
var createIteratorProxy = require('../internals/iterator-create-proxy');
var createIterResultObject = require('../internals/create-iter-result-object');
var getIteratorDirect = require('../internals/get-iterator-direct');
var iteratorClose = require('../internals/iterator-close');
var uncurryThis = require('../internals/function-uncurry-this');

var $RangeError = RangeError;
var push = uncurryThis([].push);
var slice = uncurryThis([].slice);

var IteratorProxy = createIteratorProxy(function () {
var iterator = this.iterator;
var next = this.next;
var buffer = this.buffer;
var windowSize = this.windowSize;
var sliding = this.sliding;
var result, done;
while (true) {
result = anObject(call(next, iterator));
done = this.done = !!result.done;
if (sliding && done && buffer.length && buffer.length < windowSize) return createIterResultObject(buffer, false);
if (done) return createIterResultObject(undefined, true);

if (buffer.length === windowSize) this.buffer = buffer = slice(buffer, 1);
push(buffer, result.value);
if (buffer.length === windowSize) return createIterResultObject(buffer, false);
}
}, false, true);

// `Iterator.prototype.sliding` and `Iterator.prototype.windows` methods
// https://github.com/tc39/proposal-iterator-chunking
module.exports = function (O, windowSize, sliding) {
anObject(O);
if (typeof windowSize != 'number' || !windowSize || windowSize >>> 0 !== windowSize) {
return iteratorClose(O, 'throw', new $RangeError('windowSize must be integer in [1, 2^32-1]'));
}
return new IteratorProxy(getIteratorDirect(O), {
windowSize: windowSize,
buffer: [],
sliding: sliding
});
};
11 changes: 11 additions & 0 deletions packages/core-js/modules/esnext.iterator.sliding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use strict';
var $ = require('../internals/export');
var iteratorWindow = require('../internals/iterator-window');

// `Iterator.prototype.sliding` method
// https://github.com/tc39/proposal-iterator-chunking
$({ target: 'Iterator', proto: true, real: true, forced: true }, {
sliding: function sliding(windowSize) {
return iteratorWindow(this, windowSize, true);
}
});
37 changes: 2 additions & 35 deletions packages/core-js/modules/esnext.iterator.windows.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,11 @@
'use strict';
var $ = require('../internals/export');
var anObject = require('../internals/an-object');
var call = require('../internals/function-call');
var createIteratorProxy = require('../internals/iterator-create-proxy');
var getIteratorDirect = require('../internals/get-iterator-direct');
var iteratorClose = require('../internals/iterator-close');
var uncurryThis = require('../internals/function-uncurry-this');

var $RangeError = RangeError;
var push = uncurryThis([].push);
var slice = uncurryThis([].slice);

var IteratorProxy = createIteratorProxy(function () {
var iterator = this.iterator;
var next = this.next;
var buffer = this.buffer;
var windowSize = this.windowSize;
var result, done;
while (true) {
result = anObject(call(next, iterator));
done = this.done = !!result.done;
if (done) return;

if (buffer.length === windowSize) this.buffer = buffer = slice(buffer, 1);
push(buffer, result.value);
if (buffer.length === windowSize) return buffer;
}
});
var iteratorWindow = require('../internals/iterator-window');

// `Iterator.prototype.windows` method
// https://github.com/tc39/proposal-iterator-chunking
$({ target: 'Iterator', proto: true, real: true, forced: true }, {
windows: function windows(windowSize) {
var O = anObject(this);
if (typeof windowSize != 'number' || !windowSize || windowSize >>> 0 !== windowSize) {
return iteratorClose(O, 'throw', new $RangeError('windowSize must be integer in [1, 2^32-1]'));
}
return new IteratorProxy(getIteratorDirect(O), {
windowSize: windowSize,
buffer: []
});
return iteratorWindow(this, windowSize, false);
}
});
1 change: 1 addition & 0 deletions packages/core-js/proposals/iterator-chunking.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
// https://github.com/tc39/proposal-iterator-chunking
require('../modules/esnext.iterator.chunks');
require('../modules/esnext.iterator.windows');
require('../modules/esnext.iterator.sliding');
3 changes: 3 additions & 0 deletions tests/compat/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1844,6 +1844,9 @@ GLOBAL.tests = {
'esnext.iterator.range': function () {
return Iterator.range;
},
'esnext.iterator.sliding': function () {
return Iterator.prototype.sliding;
},
'esnext.iterator.to-async': function () {
return Iterator.prototype.toAsync;
},
Expand Down
1 change: 1 addition & 0 deletions tests/entries/unit.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,7 @@ for (PATH of ['core-js-pure', 'core-js']) {
ok(load(NS, 'iterator/concat')([2]).next().value === 2);
ok(load(NS, 'iterator/range')(1, 2).next().value === 1);
ok(typeof load(NS, 'iterator/chunks') == 'function');
ok(typeof load(NS, 'iterator/sliding') == 'function');
ok(typeof load(NS, 'iterator/windows') == 'function');
ok(typeof load(NS, 'iterator/zip') == 'function');
ok(typeof load(NS, 'iterator/zip-keyed') == 'function');
Expand Down
1 change: 1 addition & 0 deletions tests/eslint/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,7 @@ const forbidCompletelyNonExistentBuiltIns = {
] }],
'es/no-nonstandard-iterator-prototype-properties': [ERROR, { allow: [
'chunks',
'sliding',
'toAsync',
'windows',
// TODO: drop from `core-js@4`
Expand Down
48 changes: 48 additions & 0 deletions tests/unit-global/esnext.iterator.sliding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { STRICT } from '../helpers/constants.js';
import { createIterator } from '../helpers/helpers.js';

const { from } = Array;

QUnit.test('Iterator#sliding', assert => {
const { sliding } = Iterator.prototype;

assert.isFunction(sliding);
assert.arity(sliding, 1);
assert.name(sliding, 'sliding');
assert.looksNative(sliding);
assert.nonEnumerable(Iterator.prototype, 'sliding');

assert.arrayEqual(from(sliding.call(createIterator([1, 2, 3]), 2)), [[1, 2], [2, 3]], 'basic functionality #1');
assert.arrayEqual(from(sliding.call(createIterator([1, 2, 3, 4]), 2)), [[1, 2], [2, 3], [3, 4]], 'basic functionality #2');
assert.arrayEqual(from(sliding.call(createIterator([1, 2]), 3)), [[1, 2]], 'basic functionality #3');
assert.arrayEqual(from(sliding.call(createIterator([]), 2)), [], 'basic functionality on empty iterable');

const it = createIterator([1, 2, 3]);
const result = sliding.call(it, 3);
assert.isIterable(result, 'returns iterable');
assert.isIterator(result, 'returns iterator');
assert.true(result instanceof Iterator, 'returns iterator');
assert.deepEqual(result.next(), { done: false, value: [1, 2, 3] }, '.next with active inner iterator result');
assert.deepEqual(result.return(), { done: true, value: undefined }, '.return with active inner iterator result');
assert.deepEqual(result.next(), { done: true, value: undefined }, '.return with active inner iterator result on closed iterator');

if (STRICT) {
assert.throws(() => sliding.call('', 1), TypeError, 'iterable non-object this');
assert.throws(() => sliding.call(undefined, 1), TypeError, 'non-iterable-object this #1');
assert.throws(() => sliding.call(null, 1), TypeError, 'non-iterable-object this #2');
assert.throws(() => sliding.call(5, 1), TypeError, 'non-iterable-object this #3');
}

assert.throws(() => sliding.call(it), RangeError, 'throws on empty argument');
assert.throws(() => sliding.call(it, -1), RangeError, 'throws on negative argument');

const observableReturn = {
return() {
this.called = true;
return { done: true, value: undefined };
},
};
const itObservable = createIterator([1, 2, 3], observableReturn);
assert.throws(() => sliding.call(itObservable, 0x100000000), RangeError, 'throws on argument more then 2^32 - 1');
assert.true(itObservable.called, 'iterator closed on argument validation error');
});
1 change: 1 addition & 0 deletions tests/unit-global/esnext.iterator.windows.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ QUnit.test('Iterator#windows', assert => {

assert.arrayEqual(from(windows.call(createIterator([1, 2, 3]), 2)), [[1, 2], [2, 3]], 'basic functionality #1');
assert.arrayEqual(from(windows.call(createIterator([1, 2, 3, 4]), 2)), [[1, 2], [2, 3], [3, 4]], 'basic functionality #2');
assert.arrayEqual(from(windows.call(createIterator([1, 2]), 3)), [], 'basic functionality #3');
assert.arrayEqual(from(windows.call(createIterator([]), 2)), [], 'basic functionality on empty iterable');

const it = createIterator([1, 2, 3]);
Expand Down
47 changes: 47 additions & 0 deletions tests/unit-pure/esnext.iterator.sliding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { STRICT } from '../helpers/constants.js';
import { createIterator } from '../helpers/helpers.js';

import Iterator from 'core-js-pure/full/iterator/index';
import from from 'core-js-pure/es/array/from';

QUnit.test('Iterator#sliding', assert => {
const { sliding } = Iterator.prototype;
assert.isFunction(sliding);
assert.arity(sliding, 1);
assert.name(sliding, 'sliding');
assert.nonEnumerable(Iterator.prototype, 'sliding');

assert.arrayEqual(from(sliding.call(createIterator([1, 2, 3]), 2)), [[1, 2], [2, 3]], 'basic functionality #1');
assert.arrayEqual(from(sliding.call(createIterator([1, 2, 3, 4]), 2)), [[1, 2], [2, 3], [3, 4]], 'basic functionality #2');
assert.arrayEqual(from(sliding.call(createIterator([1, 2]), 3)), [[1, 2]], 'basic functionality #3');
assert.arrayEqual(from(sliding.call(createIterator([]), 2)), [], 'basic functionality on empty iterable');

const it = createIterator([1, 2, 3]);
const result = sliding.call(it, 3);
assert.isIterable(result, 'returns iterable');
assert.isIterator(result, 'returns iterator');
assert.true(result instanceof Iterator, 'returns iterator');
assert.deepEqual(result.next(), { done: false, value: [1, 2, 3] }, '.next with active inner iterator result');
assert.deepEqual(result.return(), { done: true, value: undefined }, '.return with active inner iterator result');
assert.deepEqual(result.next(), { done: true, value: undefined }, '.return with active inner iterator result on closed iterator');

if (STRICT) {
assert.throws(() => sliding.call('', 1), TypeError, 'iterable non-object this');
assert.throws(() => sliding.call(undefined, 1), TypeError, 'non-iterable-object this #1');
assert.throws(() => sliding.call(null, 1), TypeError, 'non-iterable-object this #2');
assert.throws(() => sliding.call(5, 1), TypeError, 'non-iterable-object this #3');
}

assert.throws(() => sliding.call(it), RangeError, 'throws on empty argument');
assert.throws(() => sliding.call(it, -1), RangeError, 'throws on negative argument');

const observableReturn = {
return() {
this.called = true;
return { done: true, value: undefined };
},
};
const itObservable = createIterator([1, 2, 3], observableReturn);
assert.throws(() => sliding.call(itObservable, 0x100000000), RangeError, 'throws on argument more then 2^32 - 1');
assert.true(itObservable.called, 'iterator closed on argument validation error');
});
1 change: 1 addition & 0 deletions tests/unit-pure/esnext.iterator.windows.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ QUnit.test('Iterator#windows', assert => {

assert.arrayEqual(from(windows.call(createIterator([1, 2, 3]), 2)), [[1, 2], [2, 3]], 'basic functionality #1');
assert.arrayEqual(from(windows.call(createIterator([1, 2, 3, 4]), 2)), [[1, 2], [2, 3], [3, 4]], 'basic functionality #2');
assert.arrayEqual(from(windows.call(createIterator([1, 2]), 3)), [], 'basic functionality #3');
assert.arrayEqual(from(windows.call(createIterator([]), 2)), [], 'basic functionality on empty iterable');

const it = createIterator([1, 2, 3]);
Expand Down