From 8d29c2a85e1a0947b5fc81a6ec1a25e8794bd40c Mon Sep 17 00:00:00 2001 From: Denis Pushkarev Date: Thu, 15 Sep 2022 06:21:41 +0700 Subject: [PATCH 1/2] early exit on broken `.next` in missed cases of `{ Iterator, AsyncIterator }.from` https://github.com/tc39/proposal-iterator-helpers/pull/232 --- CHANGELOG.md | 1 + packages/core-js/internals/array-from-async.js | 3 ++- .../core-js/internals/async-from-sync-iterator.js | 9 +++------ packages/core-js/internals/get-async-iterator.js | 3 ++- .../core-js/modules/esnext.async-iterator.from.js | 14 ++++++++------ packages/core-js/modules/esnext.iterator.from.js | 10 +++++----- .../core-js/modules/esnext.iterator.to-async.js | 2 +- 7 files changed, 22 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9283f973ff4c..d34110ae649b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - [`Array.fromAsync` proposal](https://github.com/tc39/proposal-array-from-async): - Moved to Stage 3, [September TC39 meeting](https://github.com/babel/proposals/issues/83#issuecomment-1246218703) - Avoid observable side effects of `%Array.prototype.values%` usage in array-like branch, [proposal-array-from-async/30](https://github.com/tc39/proposal-array-from-async/pull/30) +- 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) - Added `inverse` option to `core-js-compat`, [#1119](https://github.com/zloirock/core-js/issues/1119) - Added `format` option to `core-js-builder`, [#1120](https://github.com/zloirock/core-js/issues/1120) diff --git a/packages/core-js/internals/array-from-async.js b/packages/core-js/internals/array-from-async.js index dc8a4dfb2d4c..683f7b6166b5 100644 --- a/packages/core-js/internals/array-from-async.js +++ b/packages/core-js/internals/array-from-async.js @@ -5,6 +5,7 @@ var toObject = require('../internals/to-object'); var isConstructor = require('../internals/is-constructor'); var getAsyncIterator = require('../internals/get-async-iterator'); var getIterator = require('../internals/get-iterator'); +var getIteratorDirect = require('../internals/get-iterator-direct'); var getIteratorMethod = require('../internals/get-iterator-method'); var getMethod = require('../internals/get-method'); var getVirtual = require('../internals/entry-virtual'); @@ -44,7 +45,7 @@ module.exports = function fromAsync(asyncItems /* , mapfn = undefined, thisArg = var A = isConstructor(C) ? new C() : []; var iterator = usingAsyncIterator ? getAsyncIterator(O, usingAsyncIterator) - : new AsyncFromSyncIterator(getIterator(O, usingSyncIterator)); + : new AsyncFromSyncIterator(getIteratorDirect(getIterator(O, usingSyncIterator))); resolve(toArray(iterator, mapfn, A)); }); }; diff --git a/packages/core-js/internals/async-from-sync-iterator.js b/packages/core-js/internals/async-from-sync-iterator.js index 78c3bafdabc6..b4ab0179da73 100644 --- a/packages/core-js/internals/async-from-sync-iterator.js +++ b/packages/core-js/internals/async-from-sync-iterator.js @@ -22,12 +22,9 @@ var asyncFromSyncIteratorContinuation = function (result, resolve, reject) { }, reject); }; -var AsyncFromSyncIterator = function AsyncIterator(iterator) { - setInternalState(this, { - type: ASYNC_FROM_SYNC_ITERATOR, - iterator: anObject(iterator), - next: iterator.next - }); +var AsyncFromSyncIterator = function AsyncIterator(iteratorRecord) { + iteratorRecord.type = ASYNC_FROM_SYNC_ITERATOR; + setInternalState(this, iteratorRecord); }; AsyncFromSyncIterator.prototype = defineBuiltIns(create(AsyncIteratorPrototype), { diff --git a/packages/core-js/internals/get-async-iterator.js b/packages/core-js/internals/get-async-iterator.js index 20e941ca92da..6491f89538b4 100644 --- a/packages/core-js/internals/get-async-iterator.js +++ b/packages/core-js/internals/get-async-iterator.js @@ -2,6 +2,7 @@ var call = require('../internals/function-call'); var AsyncFromSyncIterator = require('../internals/async-from-sync-iterator'); var anObject = require('../internals/an-object'); var getIterator = require('../internals/get-iterator'); +var getIteratorDirect = require('../internals/get-iterator-direct'); var getMethod = require('../internals/get-method'); var wellKnownSymbol = require('../internals/well-known-symbol'); @@ -9,5 +10,5 @@ var ASYNC_ITERATOR = wellKnownSymbol('asyncIterator'); module.exports = function (it, usingIterator) { var method = arguments.length < 2 ? getMethod(it, ASYNC_ITERATOR) : usingIterator; - return method ? anObject(call(method, it)) : new AsyncFromSyncIterator(getIterator(it)); + return method ? anObject(call(method, it)) : new AsyncFromSyncIterator(getIteratorDirect(getIterator(it))); }; diff --git a/packages/core-js/modules/esnext.async-iterator.from.js b/packages/core-js/modules/esnext.async-iterator.from.js index bea7c28619d5..75a0acb361ca 100644 --- a/packages/core-js/modules/esnext.async-iterator.from.js +++ b/packages/core-js/modules/esnext.async-iterator.from.js @@ -18,15 +18,17 @@ $({ target: 'AsyncIterator', stat: true, forced: true }, { from: function from(O) { var object = toObject(O); var usingIterator = getMethod(object, ASYNC_ITERATOR); - var iterator; + var iteratorRecord; if (usingIterator) { - iterator = getAsyncIterator(object, usingIterator); - if (isPrototypeOf(AsyncIteratorPrototype, iterator)) return iterator; + iteratorRecord = getIteratorDirect(getAsyncIterator(object, usingIterator)); + if (isPrototypeOf(AsyncIteratorPrototype, iteratorRecord.iterator)) return iteratorRecord.iterator; } - if (iterator === undefined) { + if (iteratorRecord === undefined) { usingIterator = getIteratorMethod(object); - if (usingIterator) iterator = new AsyncFromSyncIterator(getIterator(object, usingIterator)); + if (usingIterator) iteratorRecord = getIteratorDirect(new AsyncFromSyncIterator( + getIteratorDirect(getIterator(object, usingIterator)) + )); } - return new WrapAsyncIterator(getIteratorDirect(iterator !== undefined ? iterator : object)); + return new WrapAsyncIterator(iteratorRecord !== undefined ? iteratorRecord : getIteratorDirect(object)); } }); diff --git a/packages/core-js/modules/esnext.iterator.from.js b/packages/core-js/modules/esnext.iterator.from.js index 17a25ab1ec84..2d7bdf622448 100644 --- a/packages/core-js/modules/esnext.iterator.from.js +++ b/packages/core-js/modules/esnext.iterator.from.js @@ -17,12 +17,12 @@ $({ target: 'Iterator', stat: true, forced: true }, { from: function from(O) { var object = toObject(O); var usingIterator = getIteratorMethod(object); - var iterator; + var iteratorRecord; if (usingIterator) { - iterator = getIterator(object, usingIterator); - if (isPrototypeOf(IteratorPrototype, iterator)) return iterator; + iteratorRecord = getIteratorDirect(getIterator(object, usingIterator)); + if (isPrototypeOf(IteratorPrototype, iteratorRecord.iterator)) return iteratorRecord.iterator; } else { - iterator = object; - } return new IteratorProxy(getIteratorDirect(iterator)); + iteratorRecord = getIteratorDirect(object); + } return new IteratorProxy(iteratorRecord); } }); diff --git a/packages/core-js/modules/esnext.iterator.to-async.js b/packages/core-js/modules/esnext.iterator.to-async.js index d3ccdcf396b2..55982c466f79 100644 --- a/packages/core-js/modules/esnext.iterator.to-async.js +++ b/packages/core-js/modules/esnext.iterator.to-async.js @@ -7,6 +7,6 @@ var getIteratorDirect = require('../internals/get-iterator-direct'); $({ target: 'Iterator', proto: true, real: true, forced: true }, { toAsync: function toAsync() { - return new WrapAsyncIterator(getIteratorDirect(new AsyncFromSyncIterator(this))); + return new WrapAsyncIterator(getIteratorDirect(new AsyncFromSyncIterator(getIteratorDirect(this)))); } }); From b16bb7805a1de47ec4234edf1ea32e289ce567d2 Mon Sep 17 00:00:00 2001 From: Denis Pushkarev Date: Thu, 15 Sep 2022 06:50:15 +0700 Subject: [PATCH 2/2] add some tests --- tests/pure/esnext.async-iterator.from.js | 3 ++- tests/pure/esnext.iterator.from.js | 2 ++ tests/tests/esnext.async-iterator.from.js | 7 +++++-- tests/tests/esnext.iterator.from.js | 3 +++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/pure/esnext.async-iterator.from.js b/tests/pure/esnext.async-iterator.from.js index 14456d6f104f..e4ee63248b1d 100644 --- a/tests/pure/esnext.async-iterator.from.js +++ b/tests/pure/esnext.async-iterator.from.js @@ -4,7 +4,7 @@ import values from 'core-js-pure/es/array/values'; import AsyncIterator from 'core-js-pure/full/async-iterator'; QUnit.test('AsyncIterator.from', assert => { - assert.expect(9); + assert.expect(10); const async = assert.async(); const { from } = AsyncIterator; @@ -29,4 +29,5 @@ QUnit.test('AsyncIterator.from', assert => { assert.throws(() => from(undefined), TypeError); assert.throws(() => from(null), TypeError); assert.throws(() => from({}), TypeError); + assert.throws(() => from(assign(new AsyncIterator(), { next: 42 })), TypeError); }); diff --git a/tests/pure/esnext.iterator.from.js b/tests/pure/esnext.iterator.from.js index 95ee908ee280..3c363077baf9 100644 --- a/tests/pure/esnext.iterator.from.js +++ b/tests/pure/esnext.iterator.from.js @@ -1,6 +1,7 @@ import { createIterable, createIterator } from '../helpers/helpers'; import Iterator from 'core-js-pure/full/iterator'; +import assign from 'core-js-pure/es/object/assign'; QUnit.test('Iterator.from', assert => { const { from } = Iterator; @@ -17,4 +18,5 @@ QUnit.test('Iterator.from', assert => { assert.throws(() => from(undefined), TypeError); assert.throws(() => from(null), TypeError); assert.throws(() => from({}), TypeError); + assert.throws(() => from(assign(new Iterator(), { next: 42 })), TypeError); }); diff --git a/tests/tests/esnext.async-iterator.from.js b/tests/tests/esnext.async-iterator.from.js index 49e6e193eee5..62c97222f4c7 100644 --- a/tests/tests/esnext.async-iterator.from.js +++ b/tests/tests/esnext.async-iterator.from.js @@ -1,5 +1,7 @@ +const { assign } = Object; + QUnit.test('AsyncIterator.from', assert => { - assert.expect(12); + assert.expect(13); const async = assert.async(); const { from } = AsyncIterator; @@ -18,7 +20,7 @@ QUnit.test('AsyncIterator.from', assert => { async(); }); - const asyncIterator = Object.assign(new AsyncIterator(), { + const asyncIterator = assign(new AsyncIterator(), { next: () => { /* empty */ }, }); @@ -27,4 +29,5 @@ QUnit.test('AsyncIterator.from', assert => { assert.throws(() => from(undefined), TypeError); assert.throws(() => from(null), TypeError); assert.throws(() => from({}), TypeError); + assert.throws(() => from(assign(new AsyncIterator(), { next: 42 })), TypeError); }); diff --git a/tests/tests/esnext.iterator.from.js b/tests/tests/esnext.iterator.from.js index 4e3acff0e4a3..965e12165f9d 100644 --- a/tests/tests/esnext.iterator.from.js +++ b/tests/tests/esnext.iterator.from.js @@ -1,5 +1,7 @@ import { createIterable, createIterator } from '../helpers/helpers'; +const { assign } = Object; + QUnit.test('Iterator.from', assert => { const { from } = Iterator; @@ -18,4 +20,5 @@ QUnit.test('Iterator.from', assert => { assert.throws(() => from(undefined), TypeError); assert.throws(() => from(null), TypeError); assert.throws(() => from({}), TypeError); + assert.throws(() => from(assign(new Iterator(), { next: 42 })), TypeError); });