Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions packages/utilities/src/streams_utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,35 @@ export async function readStreamToString(stream: Readable | PassThrough, encodin
const buffer = await concatStreamToBuffer(stream);
return buffer.toString(encoding);
}

function isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {
return typeof value === 'object' && !!value && Symbol.asyncIterator in value;
}

async function asyncIterableToArray<T>(iterable: AsyncIterable<T>): Promise<T[]> {
const out: T[] = [];
for await (const item of iterable) {
out.push(item);
}

return out;
}
Comment on lines +34 to +41
Copy link
Copy Markdown
Member

@B4nan B4nan May 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the same as Array.fromAsync(), no?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:O Did not know about that one. This was my use case mainly, closing the PR. Thanks


export function iterableToArray<T>(iterable: AsyncIterable<T>): Promise<T[]>;
export function iterableToArray<T>(iterable: Iterable<T>): T[];

/**
* Collect items from an iterable object or an async iterable into an array.
*/
export function iterableToArray<T>(iterable: AsyncIterable<T> | Iterable<T>) {
if (isAsyncIterable(iterable)) {
return asyncIterableToArray(iterable);
}

const out: T[] = [];
for (const item of iterable) {
out.push(item);
}

return out;
}
32 changes: 32 additions & 0 deletions test/streams_utilities.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { describe, expect, it } from 'vitest';

import { iterableToArray } from '@apify/utilities';

describe('iterableToArray', () => {
it('collects a synchronous iterable into an array', () => {
const result = iterableToArray(new Set([1, 2, 3]));

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

it('collects an async iterable into an array', async () => {
async function* gen() {
yield 'a';
yield 'b';
yield 'c';
}

const result = await iterableToArray(gen());

expect(result).toEqual(['a', 'b', 'c']);
});

it('propagates errors thrown by an async iterable', async () => {
async function* gen() {
yield 1;
throw new Error('boom');
}

await expect(iterableToArray(gen())).rejects.toThrow('boom');
});
});
Loading