Skip to content

Commit cf6aa2c

Browse files
slowcheetahzloirock
authored andcommitted
Iterator#windows implementation
1 parent de73131 commit cf6aa2c

File tree

14 files changed

+148
-9
lines changed

14 files changed

+148
-9
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@
3737
- Added built-ins:
3838
- `Iterator.zip`
3939
- `Iterator.zipKeyed`
40-
- [`Iterator` chunking stage 2 proposal](https://github.com/tc39/proposal-iterator-chunking):
40+
- Added [`Iterator` chunking stage 2 proposal](https://github.com/tc39/proposal-iterator-chunking):
4141
- Added built-ins:
4242
- `Iterator.prototype.chunks`
43+
- `Iterator.prototype.windows`
4344
- [`Number.prototype.clamp` proposal](https://github.com/tc39/proposal-math-clamp):
4445
- Built-ins:
4546
- `Number.prototype.clamp`

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3060,22 +3060,26 @@ core-js(-pure)/full/symbol/custom-matcher
30603060
```
30613061

30623062
##### [`Iterator` chunking](https://github.com/tc39/proposal-iterator-chunking)[⬆](#index)
3063-
Modules [`esnext.iterator.chunks`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.iterator.chunks.js)
3063+
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)
30643064
```ts
30653065
class Iterator {
30663066
chunks(chunkSize: number): Iterator<any>;
3067+
windows(windowSize: number): Iterator<any>;
30673068
}
30683069
```
30693070
[*CommonJS entry points:*](#commonjs-api)
30703071
```
30713072
core-js/proposals/iterator-chunking
30723073
core-js(-pure)/full/iterator/chunks
3074+
core-js(-pure)/full/iterator/windows
30733075
```
3074-
[*Examples*](http://es6.zloirock.ru/#const%20digits%20%3D%20()%20%3D%3E%20%5B0%2C%201%2C%202%2C%203%2C%204%2C%205%2C%206%2C%207%2C%208%2C%209%5D.values()%3B%0A%0Alet%20chunksOf2%20%3D%20Array.from(digits().chunks(2))%3B%0A%0Alog(chunksOf2)%3B)
3076+
[*Examples*](https://tinyurl.com/ypmzafjc)
30753077
```js
30763078
const digits = () => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].values();
30773079
30783080
let chunksOf2 = Array.from(digits().chunks(2)); // [ [0, 1], [2, 3], [4, 5], [6, 7], [8, 9] ]
3081+
3082+
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] ]
30793083
```
30803084

30813085
#### Stage 1 proposals[⬆](#index)

packages/core-js-compat/src/data.mjs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2488,6 +2488,8 @@ export const data = {
24882488
'esnext.iterator.to-array': null,
24892489
'esnext.iterator.to-async': {
24902490
},
2491+
'esnext.iterator.windows': {
2492+
},
24912493
'esnext.iterator.zip': {
24922494
},
24932495
'esnext.iterator.zip-keyed': {
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
'use strict';
2+
require('../../modules/es.object.to-string');
3+
require('../../modules/es.iterator.constructor');
24
require('../../modules/esnext.iterator.chunks');
3-
var path = require('../../internals/path');
45

5-
module.exports = path.Iterator.chunks;
6+
var entryUnbind = require('../../internals/entry-unbind');
7+
8+
module.exports = entryUnbind('Iterator', 'chunks');

packages/core-js/full/iterator/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ var parent = require('../../actual/iterator');
33
require('../../modules/esnext.iterator.chunks');
44
require('../../modules/esnext.iterator.concat');
55
require('../../modules/esnext.iterator.range');
6+
require('../../modules/esnext.iterator.windows');
67
require('../../modules/esnext.iterator.zip');
78
require('../../modules/esnext.iterator.zip-keyed');
89
// TODO: Remove from `core-js@4`
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
'use strict';
2+
require('../../modules/es.object.to-string');
3+
require('../../modules/es.iterator.constructor');
4+
require('../../modules/esnext.iterator.windows');
5+
6+
var entryUnbind = require('../../internals/entry-unbind');
7+
8+
module.exports = entryUnbind('Iterator', 'windows');

packages/core-js/modules/esnext.iterator.chunks.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ var push = uncurryThis([].push);
1212
var IteratorProxy = createIteratorProxy(function () {
1313
var iterator = this.iterator;
1414
var next = this.next;
15-
var result, done;
15+
var chunkSize = this.chunkSize;
1616
var buffer = [];
17+
var result, done;
1718
while (true) {
1819
result = anObject(call(next, iterator));
1920
done = !!result.done;
@@ -23,7 +24,7 @@ var IteratorProxy = createIteratorProxy(function () {
2324
return;
2425
}
2526
push(buffer, result.value);
26-
if (buffer.length === this.chunkSize) return buffer;
27+
if (buffer.length === chunkSize) return buffer;
2728
}
2829
});
2930

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
'use strict';
2+
var $ = require('../internals/export');
3+
var anObject = require('../internals/an-object');
4+
var call = require('../internals/function-call');
5+
var createIteratorProxy = require('../internals/iterator-create-proxy');
6+
var getIteratorDirect = require('../internals/get-iterator-direct');
7+
var uncurryThis = require('../internals/function-uncurry-this');
8+
9+
var $RangeError = RangeError;
10+
var push = uncurryThis([].push);
11+
var slice = uncurryThis([].slice);
12+
13+
var IteratorProxy = createIteratorProxy(function () {
14+
var iterator = this.iterator;
15+
var next = this.next;
16+
var buffer = this.buffer;
17+
var windowSize = this.windowSize;
18+
var result, done;
19+
while (true) {
20+
result = anObject(call(next, iterator));
21+
done = this.done = !!result.done;
22+
if (done) return;
23+
24+
push(buffer, result.value);
25+
if (buffer.length === windowSize) {
26+
this.buffer = slice(buffer, 1);
27+
return buffer;
28+
}
29+
}
30+
});
31+
32+
// `Iterator.prototype.windows` method
33+
// https://github.com/tc39/proposal-iterator-chunking
34+
$({ target: 'Iterator', proto: true, real: true, forced: true }, {
35+
windows: function windows(windowSize) {
36+
var O = anObject(this);
37+
if (!windowSize || windowSize >>> 0 !== windowSize) {
38+
throw $RangeError('windowSize must be integer in [1, 2^32-1]');
39+
}
40+
return new IteratorProxy(getIteratorDirect(O), {
41+
windowSize: windowSize,
42+
buffer: []
43+
});
44+
}
45+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
'use strict';
22
// https://github.com/tc39/proposal-iterator-chunking
33
require('../modules/esnext.iterator.chunks');
4+
require('../modules/esnext.iterator.windows');

tests/compat/tests.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1836,7 +1836,6 @@ GLOBAL.tests = {
18361836
return Function.prototype[Symbol.metadata] === null;
18371837
},
18381838
'esnext.iterator.chunks': function () {
1839-
// eslint-disable-next-line es/no-nonstandard-iterator-prototype-properties -- required for detection
18401839
return Iterator.prototype.chunks;
18411840
},
18421841
'esnext.iterator.concat': function () {
@@ -1848,6 +1847,9 @@ GLOBAL.tests = {
18481847
'esnext.iterator.to-async': function () {
18491848
return Iterator.prototype.toAsync;
18501849
},
1850+
'esnext.iterator.windows': function () {
1851+
return Iterator.prototype.windows;
1852+
},
18511853
'esnext.iterator.zip': function () {
18521854
return Iterator.zip;
18531855
},

tests/entries/unit.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,8 @@ for (PATH of ['core-js-pure', 'core-js']) {
773773
ok(typeof load(NS, 'iterator/indexed') == 'function');
774774
ok(load(NS, 'iterator/concat')([2]).next().value === 2);
775775
ok(load(NS, 'iterator/range')(1, 2).next().value === 1);
776+
ok(typeof load(NS, 'iterator/chunks') == 'function');
777+
ok(typeof load(NS, 'iterator/windows') == 'function');
776778
ok(typeof load(NS, 'iterator/zip') == 'function');
777779
ok(typeof load(NS, 'iterator/zip-keyed') == 'function');
778780
ok(load(NS, 'map/delete-all')(new Map(), 1, 2) === false);
@@ -1104,7 +1106,6 @@ for (const NS of ['full', 'features']) {
11041106
load(NS, 'typed-array/filter-reject');
11051107
load(NS, 'typed-array/group-by');
11061108
load(NS, 'typed-array/unique-by');
1107-
load(NS, 'iterator/chunks');
11081109
}
11091110

11101111
load('modules/esnext.string.at-alternative');

tests/eslint/eslint.config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,7 @@ const forbidCompletelyNonExistentBuiltIns = {
12561256
'asIndexedPairs',
12571257
'indexed',
12581258
'chunks',
1259+
'windows',
12591260
] }],
12601261
'es/no-nonstandard-json-properties': [ERROR, { allow: [
12611262
'isRawJSON',
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { createIterator } from '../helpers/helpers.js';
2+
3+
const { from } = Array;
4+
5+
QUnit.test('Iterator#windows', assert => {
6+
const { windows } = Iterator.prototype;
7+
8+
assert.isFunction(windows);
9+
assert.arity(windows, 1);
10+
assert.name(windows, 'windows');
11+
assert.looksNative(windows);
12+
assert.nonEnumerable(Iterator.prototype, 'windows');
13+
14+
assert.arrayEqual(from(windows.call(createIterator([1, 2, 3]), 2)), [[1, 2], [2, 3]], 'basic functionality #1');
15+
assert.arrayEqual(from(windows.call(createIterator([1, 2, 3, 4]), 2)), [[1, 2], [2, 3], [3, 4]], 'basic functionality #2');
16+
assert.arrayEqual(from(windows.call(createIterator([]), 2)), [], 'basic functionality on empty iterable');
17+
18+
const it = createIterator([1, 2, 3]);
19+
const result = windows.call(it, 3);
20+
assert.isIterable(result, 'returns iterable');
21+
assert.isIterator(result, 'returns iterator');
22+
assert.true(result instanceof Iterator, 'returns iterator');
23+
assert.deepEqual(result.next(), { done: false, value: [1, 2, 3] }, '.next with active inner iterator result');
24+
assert.deepEqual(result.return(), { done: true, value: undefined }, '.return with active inner iterator result');
25+
assert.deepEqual(result.next(), { done: true, value: undefined }, '.return with active inner iterator result on closed iterator');
26+
27+
assert.throws(() => windows.call('', 1), TypeError, 'iterable non-object this');
28+
assert.throws(() => windows.call(undefined, 1), TypeError, 'non-iterable-object this #1');
29+
assert.throws(() => windows.call(null, 1), TypeError, 'non-iterable-object this #2');
30+
assert.throws(() => windows.call(5, 1), TypeError, 'non-iterable-object this #3');
31+
32+
assert.throws(() => windows.call(it), RangeError, 'throws on empty argument');
33+
assert.throws(() => windows.call(it, -1), RangeError, 'throws on negative argument');
34+
assert.throws(() => windows.call(it, 0x100000000), RangeError, 'throws on argument more then 2^32 - 1');
35+
});
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { createIterator } from '../helpers/helpers.js';
2+
3+
import Iterator from 'core-js-pure/full/iterator/index';
4+
import from from 'core-js-pure/es/array/from';
5+
6+
QUnit.test('Iterator#windows', assert => {
7+
const { windows } = Iterator.prototype;
8+
assert.isFunction(windows);
9+
assert.arity(windows, 1);
10+
assert.name(windows, 'windows');
11+
assert.nonEnumerable(Iterator.prototype, 'windows');
12+
13+
assert.arrayEqual(from(windows.call(createIterator([1, 2, 3]), 2)), [[1, 2], [2, 3]], 'basic functionality #1');
14+
assert.arrayEqual(from(windows.call(createIterator([1, 2, 3, 4]), 2)), [[1, 2], [2, 3], [3, 4]], 'basic functionality #2');
15+
assert.arrayEqual(from(windows.call(createIterator([]), 2)), [], 'basic functionality on empty iterable');
16+
17+
const it = createIterator([1, 2, 3]);
18+
const result = windows.call(it, 3);
19+
assert.isIterable(result, 'returns iterable');
20+
assert.isIterator(result, 'returns iterator');
21+
assert.true(result instanceof Iterator, 'returns iterator');
22+
assert.deepEqual(result.next(), { done: false, value: [1, 2, 3] }, '.next with active inner iterator result');
23+
assert.deepEqual(result.return(), { done: true, value: undefined }, '.return with active inner iterator result');
24+
assert.deepEqual(result.next(), { done: true, value: undefined }, '.return with active inner iterator result on closed iterator');
25+
26+
assert.throws(() => windows.call('', 1), TypeError, 'iterable non-object this');
27+
assert.throws(() => windows.call(undefined, 1), TypeError, 'non-iterable-object this #1');
28+
assert.throws(() => windows.call(null, 1), TypeError, 'non-iterable-object this #2');
29+
assert.throws(() => windows.call(5, 1), TypeError, 'non-iterable-object this #3');
30+
31+
assert.throws(() => windows.call(it), RangeError, 'throws on empty argument');
32+
assert.throws(() => windows.call(it, -1), RangeError, 'throws on negative argument');
33+
assert.throws(() => windows.call(it, 0x100000000), RangeError, 'throws on argument more then 2^32 - 1');
34+
});

0 commit comments

Comments
 (0)