diff --git a/spec.emu b/spec.emu
index 554ab7b..d475853 100644
--- a/spec.emu
+++ b/spec.emu
@@ -25,7 +25,20 @@ copyright: false
1. Else,
1. Let _completion_ be Completion(Yield(_innerValue_)).
1. If _completion_ is an abrupt completion, then
- 1. Return ? IteratorClose(_iteratorRecord_, _completion_).
+ 1. Set _completion_ to Completion(IteratorClose(_iteratorRecord_, _completion_)).
+ 1. Repeat, while _items_ is not empty,
+ 1. Let _trailingIter_ be the first element of _items_.
+ 1. Remove the first element from _items_.
+ 1. If _trailingIter_ is an Object, then
+ 1. Let _nextMethod_ be Completion(Get(_trailingIter_, "next")).
+ 1. If _nextMethod_ is an abrupt completion, then
+ 1. If _completion_ is not a throw completion, set _completion_ to _nextMethod_.
+ 1. Else,
+ 1. Set _nextMethod_ to ! _nextMethod_.
+ 1. If IsCallable(_nextMethod_), then
+ 1. Let _record_ be the Iterator Record { [[Iterator]]: _iter_, [[NextMethod]]: _nextMethod_, [[Done]]: true }.
+ 1. Set _completion_ to Completion(IteratorClose(_iteratorRecord_, _completion_)).
+ 1. Return ? _completion_.
1. Return CreateIteratorFromClosure(_closure_, *"Iterator Helper"*, %IteratorHelperPrototype%, « »).
diff --git a/src/index.ts b/src/index.ts
index a033c65..88b7679 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -40,8 +40,31 @@ function concatImpl(iteratorA: IteratorOrIterable, iteratorB: Ite
function concatImpl(iteratorA: IteratorOrIterable, iteratorB: IteratorOrIterable, iteratorC: IteratorOrIterable, iteratorD: IteratorOrIterable, iteratorE: IteratorOrIterable): Generator
function concatImpl(...iterators: Array>): Generator
function* concatImpl(...iterators: Array): Generator {
- for (const iter of iterators) {
- yield* liftIterator(getIteratorFlattenable(iter, 'iterate-strings'));
+ let i = 0;
+ try {
+ for (; i < iterators.length; ++i) {
+ let iter = iterators[i];
+ yield* liftIterator(getIteratorFlattenable(iter, 'iterate-strings'));
+ }
+ } finally {
+ let err = null, hasErr = false;;
+ for (++i; i < iterators.length; ++i) {
+ try {
+ let obj = iterators[i];
+ if (obj != null && (typeof obj === 'object' || typeof obj === 'function')) {
+ let iter = obj as Iterator;
+ if (typeof iter.next === 'function') {
+ iter.return?.();
+ }
+ }
+ } catch (e) {
+ if (!hasErr) {
+ hasErr = true;
+ err = e;
+ }
+ }
+ }
+ if (hasErr) throw err;
}
}
diff --git a/test/index.mjs b/test/index.mjs
index 0ab53f7..71917d7 100644
--- a/test/index.mjs
+++ b/test/index.mjs
@@ -56,3 +56,90 @@ test('concat bare iterators', async t => {
[0, 1, 2, 3, 4, 5],
);
});
+
+test('closes later iterators', async t => {
+ await t.test('stopped between iterators', () => {
+ let returned = [];
+ let concatted = Iterator.concat(
+ [0, 1],
+ [2, 3],
+ {
+ next() {
+ return { done: false, value: 'a' };
+ },
+ return() {
+ returned.push('a');
+ return { done: true, value: undefined };
+ },
+ },
+ {
+ next() {
+ return { done: false, value: 'b' };
+ },
+ return() {
+ returned.push('b');
+ return { done: true, value: undefined };
+ },
+ },
+ {
+ next() {
+ return { done: false, value: 'c' };
+ },
+ return() {
+ returned.push('c');
+ return { done: true, value: undefined };
+ },
+ },
+ );
+ assert.equal(concatted.next().value, 0);
+ assert.equal(concatted.next().value, 1);
+ assert.equal(concatted.next().value, 2);
+ assert.equal(concatted.next().value, 3);
+ assert.deepEqual(returned, []);
+ concatted.return();
+ assert.deepEqual(returned, ['a', 'b', 'c']);
+ });
+
+ await t.test('stopped during iteration', () => {
+ let returned = [];
+ let concatted = Iterator.concat(
+ [0, 1],
+ [2, 3],
+ {
+ next() {
+ return { done: false, value: 4 };
+ },
+ return() {
+ returned.push('a');
+ return { done: true, value: undefined };
+ },
+ },
+ {
+ next() {
+ return { done: false, value: 'b' };
+ },
+ return() {
+ returned.push('b');
+ return { done: true, value: undefined };
+ },
+ },
+ {
+ next() {
+ return { done: false, value: 'c' };
+ },
+ return() {
+ returned.push('c');
+ return { done: true, value: undefined };
+ },
+ },
+ );
+ assert.equal(concatted.next().value, 0);
+ assert.equal(concatted.next().value, 1);
+ assert.equal(concatted.next().value, 2);
+ assert.equal(concatted.next().value, 3);
+ assert.equal(concatted.next().value, 4);
+ assert.deepEqual(returned, []);
+ concatted.return();
+ assert.deepEqual(returned, ['a', 'b', 'c']);
+ });
+});
\ No newline at end of file