diff --git a/__tests__/IterableSeq.ts b/__tests__/IterableSeq.ts
deleted file mode 100644
index fe3b8ff146..0000000000
--- a/__tests__/IterableSeq.ts
+++ /dev/null
@@ -1,200 +0,0 @@
-/**
- * Copyright (c) 2014-present, Facebook, Inc.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- */
-
-///
-
-declare var Symbol: any;
-import { Seq } from '../';
-
-describe('Sequence', () => {
- it('creates a sequence from an iterable', () => {
- const i = new SimpleIterable();
- const s = Seq(i);
- expect(s.take(5).toArray()).toEqual([0, 1, 2, 3, 4]);
- });
-
- it('is stable', () => {
- const i = new SimpleIterable();
- const s = Seq(i);
- expect(s.take(5).toArray()).toEqual([0, 1, 2, 3, 4]);
- expect(s.take(5).toArray()).toEqual([0, 1, 2, 3, 4]);
- expect(
- s
- .take(5)
- .take(Infinity)
- .toArray()
- ).toEqual([0, 1, 2, 3, 4]);
- expect(s.take(5).toArray()).toEqual([0, 1, 2, 3, 4]);
- });
-
- it('counts iterations', () => {
- const i = new SimpleIterable(10);
- const s = Seq(i);
- expect(s.forEach(x => x)).toEqual(10);
- expect(s.take(5).forEach(x => x)).toEqual(5);
- expect(s.forEach(x => x < 3)).toEqual(4);
- });
-
- it('creates a new iterator on every operations', () => {
- const mockFn = jest.genMockFunction();
- const i = new SimpleIterable(3, mockFn);
- const s = Seq(i);
- expect(s.toArray()).toEqual([0, 1, 2]);
- expect(mockFn.mock.calls).toEqual([[0], [1], [2]]);
- // The iterator is recreated for the second time.
- expect(s.toArray()).toEqual([0, 1, 2]);
- expect(mockFn.mock.calls).toEqual([[0], [1], [2], [0], [1], [2]]);
- });
-
- it('can be iterated', () => {
- const mockFn = jest.genMockFunction();
- const i = new SimpleIterable(3, mockFn);
- const seq = Seq(i);
- let entries = seq.entries();
- expect(entries.next()).toEqual({ value: [0, 0], done: false });
- // The iteration is lazy
- expect(mockFn.mock.calls).toEqual([[0]]);
- expect(entries.next()).toEqual({ value: [1, 1], done: false });
- expect(entries.next()).toEqual({ value: [2, 2], done: false });
- expect(entries.next()).toEqual({ value: undefined, done: true });
- expect(mockFn.mock.calls).toEqual([[0], [1], [2]]);
- // The iterator is recreated for the second time.
- entries = seq.entries();
- expect(entries.next()).toEqual({ value: [0, 0], done: false });
- expect(entries.next()).toEqual({ value: [1, 1], done: false });
- expect(entries.next()).toEqual({ value: [2, 2], done: false });
- expect(entries.next()).toEqual({ value: undefined, done: true });
- expect(mockFn.mock.calls).toEqual([[0], [1], [2], [0], [1], [2]]);
- });
-
- it('can be mapped and filtered', () => {
- const mockFn = jest.genMockFunction();
- const i = new SimpleIterable(undefined, mockFn); // infinite
- const seq = Seq(i)
- .filter(x => x % 2 === 1)
- .map(x => x * x);
- const entries = seq.entries();
- expect(entries.next()).toEqual({ value: [0, 1], done: false });
- expect(entries.next()).toEqual({ value: [1, 9], done: false });
- expect(entries.next()).toEqual({ value: [2, 25], done: false });
- expect(mockFn.mock.calls).toEqual([[0], [1], [2], [3], [4], [5]]);
- });
-
- it('can be updated', () => {
- function sum(seq) {
- return seq.reduce((s, v) => s + v, 0);
- }
- const total = Seq([1, 2, 3])
- .filter(x => x % 2 === 1)
- .map(x => x * x)
- .update(sum);
- expect(total).toBe(10);
- });
-
- describe('IteratorSequence', () => {
- it('creates a sequence from a raw iterable', () => {
- const i = new SimpleIterable(10);
- const s = Seq(i[ITERATOR_SYMBOL]());
- expect(s.take(5).toArray()).toEqual([0, 1, 2, 3, 4]);
- });
-
- it('is stable', () => {
- const i = new SimpleIterable(10);
- const s = Seq(i[ITERATOR_SYMBOL]());
- expect(s.take(5).toArray()).toEqual([0, 1, 2, 3, 4]);
- expect(s.take(5).toArray()).toEqual([0, 1, 2, 3, 4]);
- expect(s.take(5).toArray()).toEqual([0, 1, 2, 3, 4]);
- });
-
- it('counts iterations', () => {
- const i = new SimpleIterable(10);
- const s = Seq(i[ITERATOR_SYMBOL]());
- expect(s.forEach(x => x)).toEqual(10);
- expect(s.take(5).forEach(x => x)).toEqual(5);
- expect(s.forEach(x => x < 3)).toEqual(4);
- });
-
- it('memoizes the iterator', () => {
- const mockFn = jest.genMockFunction();
- const i = new SimpleIterable(10, mockFn);
- const s = Seq(i[ITERATOR_SYMBOL]());
- expect(s.take(3).toArray()).toEqual([0, 1, 2]);
- expect(mockFn.mock.calls).toEqual([[0], [1], [2]]);
-
- // Second call uses memoized values
- expect(s.take(3).toArray()).toEqual([0, 1, 2]);
- expect(mockFn.mock.calls).toEqual([[0], [1], [2]]);
-
- // Further ahead in the iterator yields more results.
- expect(s.take(5).toArray()).toEqual([0, 1, 2, 3, 4]);
- expect(mockFn.mock.calls).toEqual([[0], [1], [2], [3], [4]]);
- });
-
- it('can be iterated', () => {
- const mockFn = jest.genMockFunction();
- const i = new SimpleIterable(3, mockFn);
- const seq = Seq(i[ITERATOR_SYMBOL]());
- let entries = seq.entries();
- expect(entries.next()).toEqual({ value: [0, 0], done: false });
- // The iteration is lazy
- expect(mockFn.mock.calls).toEqual([[0]]);
- expect(entries.next()).toEqual({ value: [1, 1], done: false });
- expect(entries.next()).toEqual({ value: [2, 2], done: false });
- expect(entries.next()).toEqual({ value: undefined, done: true });
- expect(mockFn.mock.calls).toEqual([[0], [1], [2]]);
- // The iterator has been memoized for the second time.
- entries = seq.entries();
- expect(entries.next()).toEqual({ value: [0, 0], done: false });
- expect(entries.next()).toEqual({ value: [1, 1], done: false });
- expect(entries.next()).toEqual({ value: [2, 2], done: false });
- expect(entries.next()).toEqual({ value: undefined, done: true });
- expect(mockFn.mock.calls).toEqual([[0], [1], [2]]);
- });
-
- it('can iterate an skipped seq based on an iterator', () => {
- const i = new SimpleIterable(4);
- const seq = Seq(i[ITERATOR_SYMBOL]());
- expect(seq.size).toBe(undefined);
- const skipped = seq.skip(2);
- expect(skipped.size).toBe(undefined);
- const iter = skipped[ITERATOR_SYMBOL]();
- // The first two were skipped
- expect(iter.next()).toEqual({ value: 2, done: false });
- expect(iter.next()).toEqual({ value: 3, done: false });
- expect(iter.next()).toEqual({ value: undefined, done: true });
- });
- });
-});
-
-// Helper for this test
-const ITERATOR_SYMBOL =
- (typeof Symbol === 'function' && Symbol.iterator) || '@@iterator';
-
-function SimpleIterable(max?: number, watcher?: any) {
- this.max = max;
- this.watcher = watcher;
-}
-SimpleIterable.prototype[ITERATOR_SYMBOL] = function() {
- return new SimpleIterator(this);
-};
-
-function SimpleIterator(iterable) {
- this.iterable = iterable;
- this.value = 0;
-}
-SimpleIterator.prototype.next = function() {
- if (this.value >= this.iterable.max) {
- return { value: undefined, done: true };
- }
- if (this.iterable.watcher) {
- this.iterable.watcher(this.value);
- }
- return { value: this.value++, done: false };
-};
-SimpleIterator.prototype[ITERATOR_SYMBOL] = function() {
- return this;
-};
diff --git a/__tests__/Seq.ts b/__tests__/Seq.ts
index 52ec342989..549c83b622 100644
--- a/__tests__/Seq.ts
+++ b/__tests__/Seq.ts
@@ -22,6 +22,10 @@ describe('Seq', () => {
expect(Seq({ a: 1, b: 2, c: 3 }).size).toBe(3);
});
+ it('accepts an object with a next property', () => {
+ expect(Seq({ a: 1, b: 2, next: _ => _ }).size).toBe(3);
+ });
+
it('accepts a collection string', () => {
expect(Seq('foo').size).toBe(3);
});
diff --git a/src/Seq.js b/src/Seq.js
index f70c19fc60..22ec1bd75a 100644
--- a/src/Seq.js
+++ b/src/Seq.js
@@ -288,55 +288,6 @@ class CollectionSeq extends IndexedSeq {
}
}
-class IteratorSeq extends IndexedSeq {
- constructor(iterator) {
- this._iterator = iterator;
- this._iteratorCache = [];
- }
-
- __iterateUncached(fn, reverse) {
- if (reverse) {
- return this.cacheResult().__iterate(fn, reverse);
- }
- const iterator = this._iterator;
- const cache = this._iteratorCache;
- let iterations = 0;
- while (iterations < cache.length) {
- if (fn(cache[iterations], iterations++, this) === false) {
- return iterations;
- }
- }
- let step;
- while (!(step = iterator.next()).done) {
- const val = step.value;
- cache[iterations] = val;
- if (fn(val, iterations++, this) === false) {
- break;
- }
- }
- return iterations;
- }
-
- __iteratorUncached(type, reverse) {
- if (reverse) {
- return this.cacheResult().__iterator(type, reverse);
- }
- const iterator = this._iterator;
- const cache = this._iteratorCache;
- let iterations = 0;
- return new Iterator(() => {
- if (iterations >= cache.length) {
- const step = iterator.next();
- if (step.done) {
- return step;
- }
- cache[iterations] = step.value;
- }
- return iteratorValue(type, iterations, cache[iterations++]);
- });
- }
-}
-
// # pragma Helper functions
export function isSeq(maybeSeq) {
@@ -352,11 +303,9 @@ function emptySequence() {
export function keyedSeqFromValue(value) {
const seq = Array.isArray(value)
? new ArraySeq(value)
- : isIterator(value)
- ? new IteratorSeq(value)
- : hasIterator(value)
- ? new CollectionSeq(value)
- : undefined;
+ : hasIterator(value)
+ ? new CollectionSeq(value)
+ : undefined;
if (seq) {
return seq.fromEntrySeq();
}
@@ -395,9 +344,7 @@ function seqFromValue(value) {
function maybeIndexedSeqFromValue(value) {
return isArrayLike(value)
? new ArraySeq(value)
- : isIterator(value)
- ? new IteratorSeq(value)
- : hasIterator(value)
- ? new CollectionSeq(value)
- : undefined;
+ : hasIterator(value)
+ ? new CollectionSeq(value)
+ : undefined;
}
diff --git a/type-definitions/Immutable.d.ts b/type-definitions/Immutable.d.ts
index e493a78ba1..47e00c7e7a 100644
--- a/type-definitions/Immutable.d.ts
+++ b/type-definitions/Immutable.d.ts
@@ -3008,10 +3008,13 @@ declare module Immutable {
* * If a `Seq`, that same `Seq`.
* * If an `Collection`, a `Seq` of the same kind (Keyed, Indexed, or Set).
* * If an Array-like, an `Seq.Indexed`.
- * * If an Object with an Iterator, an `Seq.Indexed`.
- * * If an Iterator, an `Seq.Indexed`.
+ * * If an Iterable Object, an `Seq.Indexed`.
* * If an Object, a `Seq.Keyed`.
*
+ * Note: An Iterator itself will be treated as an object, becoming a `Seq.Keyed`,
+ * which is usually not what you want. You should turn your Iterator Object into
+ * an iterable object by defining a Symbol.iterator (or @@iterator) method which
+ * returns `this`.
*/
export function Seq>(seq: S): S;
export function Seq(collection: Collection.Keyed): Seq.Keyed;
@@ -3723,13 +3726,17 @@ declare module Immutable {
*
* * If an `Collection`, that same `Collection`.
* * If an Array-like, an `Collection.Indexed`.
- * * If an Object with an Iterator, an `Collection.Indexed`.
- * * If an Iterator, an `Collection.Indexed`.
+ * * If an Object with an Iterator defined, an `Collection.Indexed`.
* * If an Object, an `Collection.Keyed`.
*
* This methods forces the conversion of Objects and Strings to Collections.
* If you want to ensure that a Collection of one item is returned, use
* `Seq.of`.
+ *
+ * Note: An Iterator itself will be treated as an object, becoming a `Seq.Keyed`,
+ * which is usually not what you want. You should turn your Iterator Object into
+ * an iterable object by defining a Symbol.iterator (or @@iterator) method which
+ * returns `this`.
*/
export function Collection>(collection: I): I;
export function Collection(collection: Iterable): Collection.Indexed;