61 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			61 lines
		
	
	
		
			1.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import {callbackify} from 'node:util';
 | |
| 
 | |
| // Applies a series of generator functions asynchronously
 | |
| export const pushChunks = callbackify(async (getChunks, state, getChunksArguments, transformStream) => {
 | |
| 	state.currentIterable = getChunks(...getChunksArguments);
 | |
| 
 | |
| 	try {
 | |
| 		for await (const chunk of state.currentIterable) {
 | |
| 			transformStream.push(chunk);
 | |
| 		}
 | |
| 	} finally {
 | |
| 		delete state.currentIterable;
 | |
| 	}
 | |
| });
 | |
| 
 | |
| // For each new chunk, apply each `transform()` method
 | |
| export const transformChunk = async function * (chunk, generators, index) {
 | |
| 	if (index === generators.length) {
 | |
| 		yield chunk;
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	const {transform = identityGenerator} = generators[index];
 | |
| 	for await (const transformedChunk of transform(chunk)) {
 | |
| 		yield * transformChunk(transformedChunk, generators, index + 1);
 | |
| 	}
 | |
| };
 | |
| 
 | |
| // At the end, apply each `final()` method, followed by the `transform()` method of the next transforms
 | |
| export const finalChunks = async function * (generators) {
 | |
| 	for (const [index, {final}] of Object.entries(generators)) {
 | |
| 		yield * generatorFinalChunks(final, Number(index), generators);
 | |
| 	}
 | |
| };
 | |
| 
 | |
| const generatorFinalChunks = async function * (final, index, generators) {
 | |
| 	if (final === undefined) {
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	for await (const finalChunk of final()) {
 | |
| 		yield * transformChunk(finalChunk, generators, index + 1);
 | |
| 	}
 | |
| };
 | |
| 
 | |
| // Cancel any ongoing async generator when the Transform is destroyed, e.g. when the subprocess errors
 | |
| export const destroyTransform = callbackify(async ({currentIterable}, error) => {
 | |
| 	if (currentIterable !== undefined) {
 | |
| 		await (error ? currentIterable.throw(error) : currentIterable.return());
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if (error) {
 | |
| 		throw error;
 | |
| 	}
 | |
| });
 | |
| 
 | |
| const identityGenerator = function * (chunk) {
 | |
| 	yield chunk;
 | |
| };
 |