Skip to content

Commit

Permalink
Add asyncIteratorToAsyncIterable (#19)
Browse files Browse the repository at this point in the history
* Add `asyncIteratorToAsyncIterable`

* Typo
  • Loading branch information
compulim authored Jun 13, 2024
1 parent edf2470 commit 1dec735
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added `observableSubscribeAsReadable` in PR [#13](https://github.com/compulim/iter-fest/pull/13)
- Added `iterableGetReadable` in PR [#15](https://github.com/compulim/iter-fest/pull/15)
- Added `generatorWithLastValue`/`asyncGeneratorWithLastValue` in PR [#17](https://github.com/compulim/iter-fest/pull/17)
- Added `asyncIteratorToAsyncIterable` in PR [#18](https://github.com/compulim/iter-fest/pull/18)

### Changed

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ List of ported functions: [`at`](https://tc39.es/ecma262/#sec-array.prototype.at
| From | To | Function signature |
| ----------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Iterator` | `IterableIterator` | [`iteratorToIterable<T>(iterator: Iterator<T>): IterableIterator<T>`](#converting-an-iterator-to-iterable) |
| `AsyncIterator` | `AsyncIterableIterator` | [`asyncIteratorToAsyncIterable<T>(asyncIterator: AsyncIterator<T>): AsyncIterableIterator<T>`](#converting-an-iterator-to-iterable) |
| `Observable` | `ReadableStream` | [`observableSubscribeAsReadable<T>(observable: Observable<T>): ReadableStream<T>`](#converting-an-observable-to-readablestream) |
| `ReadableStreamDefaultReader` | `AsyncIterableIterator` | [`readerValues`<T>(reader: ReadableStreamDefaultReader<T>): AsyncIterableIterator<T>`](#iterating-readablestreamdefaultreader) |
| `AsyncIterable` | `Observable` | [`observableFromAsync<T>(iterable: AsyncIterable<T>): Observable<T>`](#converting-an-asynciterable-to-observable) |
Expand All @@ -47,7 +48,7 @@ To convert `Observable` to `AsyncIterableIterator`, [use `ReadableStream` as int

### Converting an iterator to iterable

`iteratorToIterable` enable a [pure iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator) to be iterable using a for-loop statement.
`iteratorToIterable` and `asyncIteratorToAsyncIterable` enable a [pure iterator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator) to be iterable using a for-loop statement.

```ts
const iterate = (): Iterator<number> => {
Expand Down
21 changes: 21 additions & 0 deletions packages/integration-test/importDefault.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
PushAsyncIterableIterator,
SymbolObservable,
asyncGeneratorWithLastValue,
asyncIteratorToAsyncIterable,
generatorWithLastValue,
iterableAt,
iterableConcat,
Expand Down Expand Up @@ -32,6 +33,26 @@ import {
readerValues
} from 'iter-fest';

test('asyncIteratorToIterable should work', async () => {
const iterable = asyncIteratorToAsyncIterable(
((): AsyncIterator<number> => {
let value = 0;

return {
next: () => Promise.resolve(++value <= 3 ? { done: false, value } : { done: true, value: undefined })
};
})()
);

const values: number[] = [];

for await (const value of iterable) {
values.push(value);
}

expect(values).toEqual([1, 2, 3]);
});

test('asyncGeneratorWithLastValue should work', async () => {
const asyncGenerator = asyncGeneratorWithLastValue(
(async function* () {
Expand Down
21 changes: 21 additions & 0 deletions packages/integration-test/importNamed.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import withResolvers from 'core-js-pure/full/promise/with-resolvers';
import { asyncGeneratorWithLastValue } from 'iter-fest/asyncGeneratorWithLastValue';
import { asyncIteratorToAsyncIterable } from 'iter-fest/asyncIteratorToAsyncIterable';
import { generatorWithLastValue } from 'iter-fest/generatorWithLastValue';
import { iterableAt } from 'iter-fest/iterableAt';
import { iterableConcat } from 'iter-fest/iterableConcat';
Expand Down Expand Up @@ -46,6 +47,26 @@ test('asyncGeneratorWithLastValue should work', async () => {
expect(asyncGenerator.lastValue()).toEqual('end');
});

test('asyncIteratorToIterable should work', async () => {
const iterable = asyncIteratorToAsyncIterable(
((): AsyncIterator<number> => {
let value = 0;

return {
next: () => Promise.resolve(++value <= 3 ? { done: false, value } : { done: true, value: undefined })
};
})()
);

const values: number[] = [];

for await (const value of iterable) {
values.push(value);
}

expect(values).toEqual([1, 2, 3]);
});

test('generatorWithLastValue should work', () => {
const generator = generatorWithLastValue(
(function* () {
Expand Down
21 changes: 21 additions & 0 deletions packages/integration-test/requireNamed.test.cjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const withResolvers = require('core-js-pure/full/promise/with-resolvers');

const { asyncGeneratorWithLastValue } = require('iter-fest/asyncGeneratorWithLastValue');
const { asyncIteratorToAsyncIterable } = require('iter-fest/asyncIteratorToAsyncIterable');
const { generatorWithLastValue } = require('iter-fest/generatorWithLastValue');
const { iterableAt } = require('iter-fest/iterableAt');
const { iterableConcat } = require('iter-fest/iterableConcat');
Expand Down Expand Up @@ -47,6 +48,26 @@ test('asyncGeneratorWithLastValue should work', async () => {
expect(asyncGenerator.lastValue()).toEqual('end');
});

test('asyncIteratorToIterable should work', async () => {
const iterable = asyncIteratorToAsyncIterable(
(() => {
let value = 0;

return {
next: () => Promise.resolve(++value <= 3 ? { done: false, value } : { done: true, value: undefined })
};
})()
);

const values = [];

for await (const value of iterable) {
values.push(value);
}

expect(values).toEqual([1, 2, 3]);
});

test('generatorWithLastValue should work', () => {
const generator = generatorWithLastValue(
(function* () {
Expand Down
21 changes: 21 additions & 0 deletions packages/integration-test/requiredDefault.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const withResolvers = require('core-js-pure/full/promise/with-resolvers');

const {
asyncGeneratorWithLastValue,
asyncIteratorToAsyncIterable,
generatorWithLastValue,
iterableAt,
iterableConcat,
Expand Down Expand Up @@ -49,6 +50,26 @@ test('asyncGeneratorWithLastValue should work', async () => {
expect(asyncGenerator.lastValue()).toEqual('end');
});

test('asyncIteratorToIterable should work', async () => {
const iterable = asyncIteratorToAsyncIterable(
(() => {
let value = 0;

return {
next: () => Promise.resolve(++value <= 3 ? { done: false, value } : { done: true, value: undefined })
};
})()
);

const values = [];

for await (const value of iterable) {
values.push(value);
}

expect(values).toEqual([1, 2, 3]);
});

test('generatorWithLastValue should work', () => {
const generator = generatorWithLastValue(
(function* () {
Expand Down
10 changes: 10 additions & 0 deletions packages/iter-fest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@
"default": "./dist/iter-fest.asyncGeneratorWithLastValue.js"
}
},
"./asyncIteratorToAsyncIterable": {
"import": {
"types": "./dist/iter-fest.asyncIteratorToAsyncIterable.d.mts",
"default": "./dist/iter-fest.asyncIteratorToAsyncIterable.mjs"
},
"require": {
"types": "./dist/iter-fest.asyncIteratorToAsyncIterable.d.ts",
"default": "./dist/iter-fest.asyncIteratorToAsyncIterable.js"
}
},
"./generatorWithLastValue": {
"import": {
"types": "./dist/iter-fest.generatorWithLastValue.d.mts",
Expand Down
28 changes: 28 additions & 0 deletions packages/iter-fest/src/asyncIteratorToAsyncIterable.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { asyncIteratorToAsyncIterable } from './asyncIteratorToAsyncIterable';

describe('passing an async iterator-compatible generator', () => {
let asyncIterable: AsyncIterableIterator<number>;

beforeEach(() => {
const iterate = (): AsyncIterator<number> => {
let value = 0;

return {
next: (): Promise<IteratorResult<number>> =>
Promise.resolve(++value <= 3 ? { done: false, value } : { done: true, value: undefined })
};
};

asyncIterable = asyncIteratorToAsyncIterable(iterate());
});

test('should be iterable', async () => {
const values: number[] = [];

for await (const value of asyncIterable) {
values.push(value);
}

expect(values).toEqual([1, 2, 3]);
});
});
10 changes: 10 additions & 0 deletions packages/iter-fest/src/asyncIteratorToAsyncIterable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export function asyncIteratorToAsyncIterable<T>(asyncIterator: AsyncIterator<T>): AsyncIterableIterator<T> {
const asyncIterableIterator: AsyncIterableIterator<T> = {
[Symbol.asyncIterator]: () => asyncIterableIterator,
next: asyncIterator.next.bind(asyncIterator),
...(asyncIterator.return ? { return: asyncIterator.return.bind(asyncIterator) } : {}),
...(asyncIterator.throw ? { throw: asyncIterator.throw.bind(asyncIterator) } : {})
};

return asyncIterableIterator;
}
1 change: 1 addition & 0 deletions packages/iter-fest/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './Observable';
export * from './PushAsyncIterableIterator';
export * from './SymbolObservable';
export * from './asyncGeneratorWithLastValue';
export * from './asyncIteratorToAsyncIterable';
export * from './generatorWithLastValue';
export * from './iterableAt';
export * from './iterableConcat';
Expand Down
1 change: 1 addition & 0 deletions packages/iter-fest/tsup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default defineConfig([
entry: {
'iter-fest': './src/index.ts',
'iter-fest.asyncGeneratorWithLastValue': './src/asyncGeneratorWithLastValue.ts',
'iter-fest.asyncIteratorToAsyncIterable': './src/asyncIteratorToAsyncIterable.ts',
'iter-fest.generatorWithLastValue': './src/generatorWithLastValue.ts',
'iter-fest.iterableAt': './src/iterableAt.ts',
'iter-fest.iterableConcat': './src/iterableConcat.ts',
Expand Down

0 comments on commit 1dec735

Please sign in to comment.