Skip to content

Commit 817c4dd

Browse files
committed
1 parent f73a13f commit 817c4dd

22 files changed

+363
-11
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
## Changelog
22
##### Unreleased
3+
- Added [`Array.fromAsync` stage 1 proposal](https://github.com/tc39/proposal-array-from-async):
4+
- `Array.fromAsync`
5+
- `%TypedArray%.fromAsync`
36
- `.name` and `.toString()` on polyfilled functions improved in many different cases
47
- Improved internal `IsConstructor` and `IsCallable` checks
58
- Fixed some internal cases of `GetMethod` operation

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ Promise.resolve(32).then(x => console.log(x)); // => 32
109109
- [New collections methods](#new-collections-methods)
110110
- [`.of` and `.from` methods on collection constructors](#of-and-from-methods-on-collection-constructors)
111111
- [`compositeKey` and `compositeSymbol`](#compositekey-and-compositesymbol)
112+
- [`Array.fromAsync`](#arrayfromasync)
112113
- [`Array` filtering](#array-filtering)
113114
- [`Array` grouping](#array-grouping)
114115
- [`Array` deduplication](#array-deduplication)
@@ -2297,6 +2298,27 @@ console.log(compositeSymbol(1, a) === compositeSymbol(1, a)); // => true
22972298
console.log(compositeSymbol(1, a, 2, b) === compositeSymbol(1, a, 2, b)); // => true
22982299
console.log(compositeSymbol(a, a) === compositeSymbol(a, a)); // => true
22992300
```
2301+
##### [`Array.fromAsync`](https://github.com/tc39/proposal-array-from-async)[⬆](#index)
2302+
Modules [`esnext.array.from-async`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.from-async.js) and [`esnext.typed-array.from-async`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.typed-array.from-async.js)
2303+
```js
2304+
class Array {
2305+
static fromAsync(asyncItems: AsyncIterable | Iterable | ArrayLike, mapfn?: (value: any, index: number) => any, thisArg?: any): Array;
2306+
}
2307+
2308+
class %TypedArray% {
2309+
static fromAsync(asyncItems: AsyncIterable | Iterable | ArrayLike, mapfn?: (value: number, index: number, target) => number, thisArg?: any): %TypedArray%;
2310+
}
2311+
```
2312+
[*CommonJS entry points:*](#commonjs-api)
2313+
```js
2314+
core-js/proposals/array-from-async
2315+
core-js(-pure)/features/array/from-async
2316+
core-js/features/typed-array/from-async
2317+
```
2318+
[*Example*](https://goo.gl/Jt7SsD):
2319+
```js
2320+
await Array.fromAsync((async function * (){ yield * [1, 2, 3] })(), i => i * i); // => [1, 4, 9]
2321+
```
23002322
##### [Array filtering](https://github.com/tc39/proposal-array-filtering)[⬆](#index)
23012323
Modules [`esnext.array.filter-reject`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.array.filter-reject.js) and [`esnext.typed-array.filter-reject`](https://github.com/zloirock/core-js/blob/master/packages/core-js/modules/esnext.typed-array.filter-reject.js).
23022324
```js

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,6 +1428,8 @@ export const data = {
14281428
},
14291429
// TODO: Remove from `core-js@4`
14301430
'esnext.aggregate-error': null,
1431+
'esnext.array.from-async': {
1432+
},
14311433
// TODO: Remove from `core-js@4`
14321434
'esnext.array.at': null,
14331435
// TODO: Remove from `core-js@4`
@@ -1700,6 +1702,8 @@ export const data = {
17001702
// TODO: Remove from `core-js@4`
17011703
'esnext.symbol.replace-all': {
17021704
},
1705+
'esnext.typed-array.from-async': {
1706+
},
17031707
// TODO: Remove from `core-js@4`
17041708
'esnext.typed-array.at': null,
17051709
// TODO: Remove from `core-js@4`

packages/core-js-compat/src/modules-by-versions.mjs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,8 @@ export default {
107107
'es.string.at-alternative',
108108
'es.typed-array.at',
109109
],
110+
3.18: [
111+
'esnext.array.from-async',
112+
'esnext.typed-array.from-async',
113+
],
110114
};
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// empty
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
require('../../modules/es.array.iterator');
2+
require('../../modules/es.object.to-string');
3+
require('../../modules/es.promise');
4+
require('../../modules/es.string.iterator');
5+
require('../../modules/esnext.array.from-async');
6+
var path = require('../../internals/path');
7+
8+
module.exports = path.Array.fromAsync;

packages/core-js/features/array/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
var parent = require('../../stable/array');
22
require('../../modules/es.map');
3+
require('../../modules/es.promise');
4+
require('../../modules/esnext.array.from-async');
35
// TODO: Remove from `core-js@4`
46
require('../../modules/esnext.array.at');
57
// TODO: Remove from `core-js@4`
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require('../../modules/esnext.typed-array.from-async');

packages/core-js/features/typed-array/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
var parent = require('../../stable/typed-array');
22
require('../../modules/es.map');
3+
require('../../modules/es.promise');
4+
require('../../modules/esnext.typed-array.from-async');
35
// TODO: Remove from `core-js@4`
46
require('../../modules/esnext.typed-array.at');
57
// TODO: Remove from `core-js@4`
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
'use strict';
2+
var bind = require('../internals/function-bind-context');
3+
var toObject = require('../internals/to-object');
4+
var isConstructor = require('../internals/is-constructor');
5+
var getAsyncIterator = require('../internals/get-async-iterator');
6+
var getIterator = require('../internals/get-iterator');
7+
var getIteratorMethod = require('../internals/get-iterator-method');
8+
var getMethod = require('../internals/get-method');
9+
var getVirtual = require('../internals/entry-virtual');
10+
var wellKnownSymbol = require('../internals/well-known-symbol');
11+
var AsyncFromSyncIterator = require('../internals/async-from-sync-iterator');
12+
var toArray = require('../internals/async-iterator-iteration').toArray;
13+
14+
var ASYNC_ITERATOR = wellKnownSymbol('asyncIterator');
15+
var arrayIterator = getVirtual('Array').values;
16+
17+
// `Array.fromAsync` method implementation
18+
// https://github.com/tc39/proposal-array-from-async
19+
module.exports = function fromAsync(asyncItems /* , mapfn = undefined, thisArg = undefined */) {
20+
var O = toObject(asyncItems);
21+
var argumentsLength = arguments.length;
22+
var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
23+
if (mapfn !== undefined) mapfn = bind(mapfn, argumentsLength > 2 ? arguments[2] : undefined, 2);
24+
var usingAsyncIterator = getMethod(O, ASYNC_ITERATOR);
25+
var usingIterator;
26+
if (!usingAsyncIterator) usingIterator = getIteratorMethod(O);
27+
var A = isConstructor(this) ? new this() : [];
28+
var iterator = usingAsyncIterator
29+
? getAsyncIterator(O, usingAsyncIterator)
30+
: new AsyncFromSyncIterator(getIterator(O, usingIterator || arrayIterator));
31+
return toArray(iterator, mapfn, A);
32+
};

packages/core-js/internals/async-iterator-iteration.js

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,21 @@ var anObject = require('../internals/an-object');
55
var getBuiltIn = require('../internals/get-built-in');
66
var getMethod = require('../internals/get-method');
77

8-
var Promise = getBuiltIn('Promise');
8+
var MAX_SAFE_INTEGER = 9007199254740991;
99
var push = [].push;
1010

1111
var createMethod = function (TYPE) {
1212
var IS_TO_ARRAY = TYPE == 0;
1313
var IS_FOR_EACH = TYPE == 1;
1414
var IS_EVERY = TYPE == 2;
1515
var IS_SOME = TYPE == 3;
16-
return function (iterator, fn) {
16+
return function (iterator, fn, target) {
1717
anObject(iterator);
18+
var Promise = getBuiltIn('Promise');
1819
var next = aCallable(iterator.next);
19-
var array = IS_TO_ARRAY ? [] : undefined;
20-
if (!IS_TO_ARRAY) aCallable(fn);
20+
var counter = -1;
21+
var MAPPING = fn !== undefined;
22+
if (MAPPING || !IS_TO_ARRAY) aCallable(fn);
2123

2224
return new Promise(function (resolve, reject) {
2325
var closeIteration = function (method, argument) {
@@ -41,25 +43,34 @@ var createMethod = function (TYPE) {
4143

4244
var loop = function () {
4345
try {
46+
if (IS_TO_ARRAY && (++counter > MAX_SAFE_INTEGER) && MAPPING) {
47+
throw TypeError('The allowed number of iterations has been exceeded');
48+
}
4449
Promise.resolve(anObject(next.call(iterator))).then(function (step) {
4550
try {
4651
if (anObject(step).done) {
47-
resolve(IS_TO_ARRAY ? array : IS_SOME ? false : IS_EVERY || undefined);
52+
if (IS_TO_ARRAY) {
53+
target.length = counter;
54+
resolve(target);
55+
} else resolve(IS_SOME ? false : IS_EVERY || undefined);
4856
} else {
4957
var value = step.value;
50-
if (IS_TO_ARRAY) {
51-
push.call(array, value);
52-
loop();
53-
} else {
54-
Promise.resolve(fn(value)).then(function (result) {
58+
if (MAPPING) {
59+
Promise.resolve(IS_TO_ARRAY ? fn(value, counter) : fn(value)).then(function (result) {
5560
if (IS_FOR_EACH) {
5661
loop();
5762
} else if (IS_EVERY) {
5863
result ? loop() : closeIteration(resolve, false);
64+
} else if (IS_TO_ARRAY) {
65+
push.call(target, result);
66+
loop();
5967
} else {
6068
result ? closeIteration(resolve, IS_SOME || value) : loop();
6169
}
6270
}, onError);
71+
} else {
72+
push.call(target, value);
73+
loop();
6374
}
6475
}
6576
} catch (error) { onError(error); }
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
var $ = require('../internals/export');
2+
var fromAsync = require('../internals/array-from-async');
3+
4+
// `Array.fromAsync` method
5+
// https://github.com/tc39/proposal-array-from-async
6+
$({ target: 'Array', stat: true }, {
7+
fromAsync: fromAsync
8+
});

packages/core-js/modules/esnext.async-iterator.to-array.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ var $toArray = require('../internals/async-iterator-iteration').toArray;
55

66
$({ target: 'AsyncIterator', proto: true, real: true }, {
77
toArray: function toArray() {
8-
return $toArray(this);
8+
return $toArray(this, undefined, []);
99
}
1010
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
'use strict';
2+
var aConstructor = require('../internals/a-constructor');
3+
var arrayFromAsync = require('../internals/array-from-async');
4+
var TYPED_ARRAYS_CONSTRUCTORS_REQUIRES_WRAPPERS = require('../internals/typed-array-constructors-require-wrappers');
5+
var ArrayBufferViewCore = require('../internals/array-buffer-view-core');
6+
var arrayFromConstructorAndList = require('../internals/array-from-constructor-and-list');
7+
8+
var aTypedArrayConstructor = ArrayBufferViewCore.aTypedArrayConstructor;
9+
var exportTypedArrayStaticMethod = ArrayBufferViewCore.exportTypedArrayStaticMethod;
10+
11+
// `%TypedArray%.fromAsync` method
12+
// https://github.com/tc39/proposal-array-from-async
13+
// eslint-disable-next-line -- required for .length
14+
exportTypedArrayStaticMethod('fromAsync', function fromAsync(asyncItems /* , mapfn = undefined, thisArg = undefined */) {
15+
var C = aConstructor(this);
16+
return arrayFromAsync.apply(Array, arguments).then(function (list) {
17+
return arrayFromConstructorAndList(aTypedArrayConstructor(C), list);
18+
});
19+
}, TYPED_ARRAYS_CONSTRUCTORS_REQUIRES_WRAPPERS);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// https://github.com/tc39/proposal-array-from-async
2+
require('../modules/esnext.array.from-async');
3+
require('../modules/esnext.typed-array.from-async');

packages/core-js/stage/1.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
require('../proposals/array-filtering');
2+
require('../proposals/array-from-async');
23
require('../proposals/array-grouping');
34
require('../proposals/array-last');
45
require('../proposals/array-unique');

tests/commonjs.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,7 @@ for (PATH of ['core-js-pure', 'core-js']) {
561561
const Set = load(NS, 'set');
562562
const WeakMap = load(NS, 'weak-map');
563563
const WeakSet = load(NS, 'weak-set');
564+
ok(typeof load(NS, 'array/from-async') === 'function');
564565
ok(typeof load(NS, 'array/filter-out') === 'function');
565566
ok(typeof load(NS, 'array/filter-reject') === 'function');
566567
ok(load(NS, 'array/find-last')([1, 2, 3], it => it % 2) === 3);
@@ -741,6 +742,7 @@ for (PATH of ['core-js-pure', 'core-js']) {
741742
load('proposals/array-last');
742743
load('proposals/array-filtering');
743744
load('proposals/array-find-from-last');
745+
load('proposals/array-from-async');
744746
load('proposals/array-grouping');
745747
load('proposals/array-is-template-object');
746748
load('proposals/array-unique');
@@ -852,6 +854,7 @@ for (const NS of ['es', 'stable', 'features']) {
852854
{
853855
const NS = 'features';
854856

857+
load(NS, 'typed-array/from-async');
855858
load(NS, 'typed-array/filter-out');
856859
load(NS, 'typed-array/filter-reject');
857860
load(NS, 'typed-array/find-last');

tests/compat/tests.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1198,6 +1198,9 @@ GLOBAL.tests = {
11981198
&& set.add({}) == set
11991199
&& set[Symbol.toStringTag];
12001200
}],
1201+
'esnext.array.from-async': function () {
1202+
return Array.fromAsync;
1203+
},
12011204
'esnext.array.filter-reject': function () {
12021205
return [].filterReject;
12031206
},
@@ -1470,6 +1473,9 @@ GLOBAL.tests = {
14701473
'esnext.symbol.observable': function () {
14711474
return Symbol.observable;
14721475
},
1476+
'esnext.typed-array.from-async': function () {
1477+
return Int8Array.fromAsync;
1478+
},
14731479
'esnext.typed-array.filter-reject': function () {
14741480
return Int8Array.prototype.filterReject;
14751481
},

tests/helpers/helpers.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Promise from 'core-js-pure/es/promise';
22
import ITERATOR from 'core-js-pure/features/symbol/iterator';
3+
import ASYNC_ITERATOR from 'core-js-pure/features/symbol/async-iterator';
34

45
export function createIterator(elements, methods) {
56
let index = 0;
@@ -40,6 +41,29 @@ export function createIterable(elements, methods) {
4041
return iterable;
4142
}
4243

44+
export function createAsyncIterable(elements, methods) {
45+
const iterable = {
46+
called: false,
47+
received: false,
48+
[ASYNC_ITERATOR]() {
49+
iterable.received = true;
50+
let index = 0;
51+
const iterator = {
52+
next() {
53+
iterable.called = true;
54+
return Promise.resolve({
55+
value: elements[index++],
56+
done: index > elements.length,
57+
});
58+
},
59+
};
60+
if (methods) for (const key in methods) iterator[key] = methods[key];
61+
return iterator;
62+
},
63+
};
64+
return iterable;
65+
}
66+
4367
export function includes(target, wanted) {
4468
for (const element of target) if (wanted === element) return true;
4569
return false;

tests/pure/esnext.array.from-async.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { createAsyncIterable, createIterable } from '../helpers/helpers';
2+
import { STRICT_THIS } from '../helpers/constants';
3+
import Promise from 'core-js-pure/es/promise';
4+
import fromAsync from 'core-js-pure/features/array/from-async';
5+
6+
QUnit.test('Array.fromAsync', assert => {
7+
assert.expect(25);
8+
const async = assert.async();
9+
10+
assert.isFunction(fromAsync);
11+
assert.arity(fromAsync, 1);
12+
assert.name(fromAsync, 'fromAsync');
13+
14+
function C() { /* empty */ }
15+
16+
fromAsync(createAsyncIterable([1, 2, 3]), it => it ** 2).then(it => {
17+
assert.arrayEqual(it, [1, 4, 9], 'async iterable and mapfn');
18+
return fromAsync(createAsyncIterable([1]), function (arg, index) {
19+
assert.same(this, STRICT_THIS, 'this');
20+
assert.same(arguments.length, 2, 'arguments length');
21+
assert.same(arg, 1, 'argument');
22+
assert.same(index, 0, 'index');
23+
});
24+
}).then(() => {
25+
return fromAsync(createAsyncIterable([1, 2, 3]));
26+
}).then(it => {
27+
assert.arrayEqual(it, [1, 2, 3], 'async iterable without mapfn');
28+
return fromAsync(createIterable([1, 2, 3]), arg => arg ** 2);
29+
}).then(it => {
30+
assert.arrayEqual(it, [1, 4, 9], 'iterable and mapfn');
31+
return fromAsync(createIterable([1, 2, 3]), arg => Promise.resolve(arg ** 2));
32+
}).then(it => {
33+
assert.arrayEqual(it, [1, 4, 9], 'iterable and async mapfn');
34+
return fromAsync(createIterable([1]), function (arg, index) {
35+
assert.same(this, STRICT_THIS, 'this');
36+
assert.same(arguments.length, 2, 'arguments length');
37+
assert.same(arg, 1, 'argument');
38+
assert.same(index, 0, 'index');
39+
});
40+
}).then(() => {
41+
return fromAsync(createIterable([1, 2, 3]));
42+
}).then(it => {
43+
assert.arrayEqual(it, [1, 2, 3], 'iterable and without mapfn');
44+
return fromAsync([1, Promise.resolve(2), 3]);
45+
}).then(it => {
46+
assert.arrayEqual(it, [1, 2, 3], 'array');
47+
return fromAsync('123');
48+
}).then(it => {
49+
assert.arrayEqual(it, ['1', '2', '3'], 'string');
50+
return fromAsync.call(C, [1]);
51+
}).then(it => {
52+
assert.ok(it instanceof C, 'subclassable');
53+
return fromAsync({ length: 1, 0: 1 });
54+
}).then(it => {
55+
assert.arrayEqual(it, [1], 'non-iterable');
56+
return fromAsync(createIterable([1]), () => { throw 42; });
57+
}).catch(error => {
58+
assert.same(error, 42, 'rejection on a callback error');
59+
}).then(() => async());
60+
61+
assert.throws(() => fromAsync(undefined, () => { /* empty */ }), TypeError);
62+
assert.throws(() => fromAsync(null, () => { /* empty */ }), TypeError);
63+
assert.throws(() => fromAsync([1], null), TypeError);
64+
assert.throws(() => fromAsync([1], {}), TypeError);
65+
});

0 commit comments

Comments
 (0)