Skip to content

Commit f5f7df5

Browse files
committed
{ Iterator, AsyncIterator }.prototype.flatMap supports returning both - iterables and iterators
tc39/proposal-iterator-helpers#233
1 parent 43cfb4e commit f5f7df5

9 files changed

+68
-70
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
- Recent updates of the [iterator helpers proposal](https://github.com/tc39/proposal-iterator-helpers):
1010
- Added a counter parameter to helpers, [proposal-iterator-helpers/211](https://github.com/tc39/proposal-iterator-helpers/pull/211)
1111
- Don't await non-objects returned from functions passed to `AsyncIterator` helpers, [proposal-iterator-helpers/239](https://github.com/tc39/proposal-iterator-helpers/pull/239)
12+
- `{ Iterator, AsyncIterator }.prototype.flatMap` supports returning both - iterables and iterators, [proposal-iterator-helpers/233](https://github.com/tc39/proposal-iterator-helpers/pull/233)
1213
- Early exit on broken `.next` in missed cases of `{ Iterator, AsyncIterator }.from`, [proposal-iterator-helpers/232](https://github.com/tc39/proposal-iterator-helpers/pull/232)
1314
- Added `inverse` option to `core-js-compat`, [#1119](https://github.com/zloirock/core-js/issues/1119)
1415
- Added `format` option to `core-js-builder`, [#1120](https://github.com/zloirock/core-js/issues/1120)

packages/core-js/internals/async-iterator-create-proxy.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,10 @@ var createAsyncIteratorProxyPrototype = function (IS_ITERATOR) {
7979
return exit ? state : enqueue(state, function () {
8080
state.done = true;
8181
var iterator = state.iterator;
82-
var innerIterator = state.innerIterator;
8382
var returnMethod, result;
8483
var completion = perform(function () {
85-
if (innerIterator) try {
86-
iteratorClose(innerIterator, 'return');
84+
if (state.inner) try {
85+
iteratorClose(state.inner.iterator, 'return');
8786
} catch (error) {
8887
return iteratorClose(iterator, 'throw', error);
8988
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
var call = require('../internals/function-call');
2+
var isCallable = require('../internals/is-callable');
3+
var toObject = require('../internals/to-object');
4+
var getIteratorDirect = require('../internals/get-iterator-direct');
5+
var getIteratorMethod = require('../internals/get-iterator-method');
6+
var getMethod = require('../internals/get-method');
7+
var wellKnownSymbol = require('../internals/well-known-symbol');
8+
var AsyncFromSyncIterator = require('../internals/async-from-sync-iterator');
9+
10+
var ASYNC_ITERATOR = wellKnownSymbol('asyncIterator');
11+
12+
module.exports = function from(obj) {
13+
var object = toObject(obj);
14+
var alreadyAsync = true;
15+
var method = getMethod(object, ASYNC_ITERATOR);
16+
var iterator;
17+
if (!isCallable(method)) {
18+
method = getIteratorMethod(object);
19+
alreadyAsync = false;
20+
}
21+
if (isCallable(method)) {
22+
iterator = call(method, object);
23+
} else {
24+
iterator = object;
25+
alreadyAsync = true;
26+
}
27+
return getIteratorDirect(alreadyAsync ? iterator : new AsyncFromSyncIterator(getIteratorDirect(iterator)));
28+
};
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
var call = require('../internals/function-call');
2+
var isCallable = require('../internals/is-callable');
3+
var toObject = require('../internals/to-object');
4+
var getIteratorDirect = require('../internals/get-iterator-direct');
5+
var getIteratorMethod = require('../internals/get-iterator-method');
6+
7+
module.exports = function (obj) {
8+
var object = toObject(obj);
9+
var method = getIteratorMethod(object);
10+
return getIteratorDirect(isCallable(method) ? call(method, object) : object);
11+
};

packages/core-js/internals/iterator-create-proxy.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,8 @@ var createIteratorProxyPrototype = function (IS_ITERATOR) {
4444
var returnMethod = getMethod(iterator, 'return');
4545
return returnMethod ? call(returnMethod, iterator) : createIterResultObject(undefined, true);
4646
}
47-
var innerIterator = state.innerIterator;
48-
if (innerIterator) try {
49-
iteratorClose(innerIterator, 'return');
47+
if (state.inner) try {
48+
iteratorClose(state.inner.iterator, 'return');
5049
} catch (error) {
5150
return iteratorClose(iterator, 'throw', error);
5251
}

packages/core-js/modules/esnext.async-iterator.flat-map.js

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@ var isObject = require('../internals/is-object');
88
var getIteratorDirect = require('../internals/get-iterator-direct');
99
var createAsyncIteratorProxy = require('../internals/async-iterator-create-proxy');
1010
var createIterResultObject = require('../internals/create-iter-result-object');
11-
var getAsyncIterator = require('../internals/get-async-iterator');
11+
var getAsyncIteratorFlattenable = require('../internals/get-async-iterator-flattenable');
1212
var closeAsyncIteration = require('../internals/async-iterator-close');
1313

1414
var AsyncIteratorProxy = createAsyncIteratorProxy(function (Promise) {
1515
var state = this;
1616
var iterator = state.iterator;
1717
var mapper = state.mapper;
18-
var innerIterator;
1918

2019
return new Promise(function (resolve, reject) {
2120
var doneAndReject = function (error) {
@@ -41,8 +40,7 @@ var AsyncIteratorProxy = createAsyncIteratorProxy(function (Promise) {
4140

4241
var handler = function (mapped) {
4342
try {
44-
state.innerIterator = innerIterator = getAsyncIterator(mapped);
45-
state.innerNext = aCallable(innerIterator.next);
43+
state.inner = getAsyncIteratorFlattenable(mapped);
4644
innerLoop();
4745
} catch (error4) { ifAbruptCloseAsyncIterator(error4); }
4846
};
@@ -57,12 +55,13 @@ var AsyncIteratorProxy = createAsyncIteratorProxy(function (Promise) {
5755
};
5856

5957
var innerLoop = function () {
60-
if (innerIterator = state.innerIterator) {
58+
var inner = state.inner;
59+
if (inner) {
6160
try {
62-
Promise.resolve(anObject(call(state.innerNext, innerIterator))).then(function (result) {
61+
Promise.resolve(anObject(call(inner.next, inner.iterator))).then(function (result) {
6362
try {
6463
if (anObject(result).done) {
65-
state.innerIterator = state.innerNext = null;
64+
state.inner = null;
6665
outerLoop();
6766
} else resolve(createIterResultObject(result.value, false));
6867
} catch (error1) { ifAbruptCloseAsyncIterator(error1); }
@@ -79,8 +78,7 @@ $({ target: 'AsyncIterator', proto: true, real: true, forced: true }, {
7978
flatMap: function flatMap(mapper) {
8079
return new AsyncIteratorProxy(getIteratorDirect(this), {
8180
mapper: aCallable(mapper),
82-
innerIterator: null,
83-
innerNext: null
81+
inner: null
8482
});
8583
}
8684
});
Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,15 @@
11
// https://github.com/tc39/proposal-iterator-helpers
22
var $ = require('../internals/export');
3-
var toObject = require('../internals/to-object');
43
var isPrototypeOf = require('../internals/object-is-prototype-of');
4+
var getAsyncIteratorFlattenable = require('../internals/get-async-iterator-flattenable');
55
var AsyncIteratorPrototype = require('../internals/async-iterator-prototype');
6-
var getAsyncIterator = require('../internals/get-async-iterator');
7-
var getIterator = require('../internals/get-iterator');
8-
var getIteratorDirect = require('../internals/get-iterator-direct');
9-
var getIteratorMethod = require('../internals/get-iterator-method');
10-
var getMethod = require('../internals/get-method');
11-
var wellKnownSymbol = require('../internals/well-known-symbol');
12-
var AsyncFromSyncIterator = require('../internals/async-from-sync-iterator');
136
var WrapAsyncIterator = require('../internals/async-iterator-wrap');
147

15-
var ASYNC_ITERATOR = wellKnownSymbol('asyncIterator');
16-
178
$({ target: 'AsyncIterator', stat: true, forced: true }, {
189
from: function from(O) {
19-
var object = toObject(O);
20-
var usingIterator = getMethod(object, ASYNC_ITERATOR);
21-
var iteratorRecord;
22-
if (usingIterator) {
23-
iteratorRecord = getIteratorDirect(getAsyncIterator(object, usingIterator));
24-
if (isPrototypeOf(AsyncIteratorPrototype, iteratorRecord.iterator)) return iteratorRecord.iterator;
25-
}
26-
if (iteratorRecord === undefined) {
27-
usingIterator = getIteratorMethod(object);
28-
if (usingIterator) iteratorRecord = getIteratorDirect(new AsyncFromSyncIterator(
29-
getIteratorDirect(getIterator(object, usingIterator))
30-
));
31-
}
32-
return new WrapAsyncIterator(iteratorRecord !== undefined ? iteratorRecord : getIteratorDirect(object));
10+
var iteratorRecord = getAsyncIteratorFlattenable(O);
11+
return isPrototypeOf(AsyncIteratorPrototype, iteratorRecord.iterator)
12+
? iteratorRecord.iterator
13+
: new WrapAsyncIterator(iteratorRecord);
3314
}
3415
});

packages/core-js/modules/esnext.iterator.flat-map.js

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,38 +5,28 @@ var call = require('../internals/function-call');
55
var aCallable = require('../internals/a-callable');
66
var anObject = require('../internals/an-object');
77
var getIteratorDirect = require('../internals/get-iterator-direct');
8-
var getIteratorMethod = require('../internals/get-iterator-method');
8+
var getIteratorFlattenable = require('../internals/get-iterator-flattenable');
99
var createIteratorProxy = require('../internals/iterator-create-proxy');
1010
var iteratorClose = require('../internals/iterator-close');
1111

12-
var $TypeError = TypeError;
13-
1412
var IteratorProxy = createIteratorProxy(function () {
1513
var iterator = this.iterator;
1614
var mapper = this.mapper;
17-
var result, mapped, iteratorMethod, innerIterator;
15+
var result, inner;
1816

1917
while (true) {
20-
if (innerIterator = this.innerIterator) try {
21-
result = anObject(call(this.innerNext, innerIterator));
18+
if (inner = this.inner) try {
19+
result = anObject(call(inner.next, inner.iterator));
2220
if (!result.done) return result.value;
23-
this.innerIterator = this.innerNext = null;
21+
this.inner = null;
2422
} catch (error) { iteratorClose(iterator, 'throw', error); }
2523

2624
result = anObject(call(this.next, iterator));
2725

2826
if (this.done = !!result.done) return;
2927

3028
try {
31-
mapped = mapper(result.value, this.counter++);
32-
iteratorMethod = getIteratorMethod(mapped);
33-
34-
if (!iteratorMethod) {
35-
throw $TypeError('.flatMap callback should return an iterable object');
36-
}
37-
38-
this.innerIterator = innerIterator = anObject(call(iteratorMethod, mapped));
39-
this.innerNext = aCallable(innerIterator.next);
29+
this.inner = getIteratorFlattenable(mapper(result.value, this.counter++));
4030
} catch (error) { iteratorClose(iterator, 'throw', error); }
4131
}
4232
});
@@ -45,8 +35,7 @@ $({ target: 'Iterator', proto: true, real: true, forced: true }, {
4535
flatMap: function flatMap(mapper) {
4636
return new IteratorProxy(getIteratorDirect(this), {
4737
mapper: aCallable(mapper),
48-
innerIterator: null,
49-
innerNext: null
38+
inner: null
5039
});
5140
}
5241
});
Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,20 @@
11
// https://github.com/tc39/proposal-iterator-helpers
22
var $ = require('../internals/export');
33
var call = require('../internals/function-call');
4-
var toObject = require('../internals/to-object');
54
var isPrototypeOf = require('../internals/object-is-prototype-of');
65
var IteratorPrototype = require('../internals/iterators-core').IteratorPrototype;
76
var createIteratorProxy = require('../internals/iterator-create-proxy');
8-
var getIterator = require('../internals/get-iterator');
9-
var getIteratorDirect = require('../internals/get-iterator-direct');
10-
var getIteratorMethod = require('../internals/get-iterator-method');
7+
var getIteratorFlattenable = require('../internals/get-iterator-flattenable');
118

129
var IteratorProxy = createIteratorProxy(function () {
1310
return call(this.next, this.iterator);
1411
}, true);
1512

1613
$({ target: 'Iterator', stat: true, forced: true }, {
1714
from: function from(O) {
18-
var object = toObject(O);
19-
var usingIterator = getIteratorMethod(object);
20-
var iteratorRecord;
21-
if (usingIterator) {
22-
iteratorRecord = getIteratorDirect(getIterator(object, usingIterator));
23-
if (isPrototypeOf(IteratorPrototype, iteratorRecord.iterator)) return iteratorRecord.iterator;
24-
} else {
25-
iteratorRecord = getIteratorDirect(object);
26-
} return new IteratorProxy(iteratorRecord);
15+
var iteratorRecord = getIteratorFlattenable(O);
16+
return isPrototypeOf(IteratorPrototype, iteratorRecord.iterator)
17+
? iteratorRecord.iterator
18+
: new IteratorProxy(iteratorRecord);
2719
}
2820
});

0 commit comments

Comments
 (0)