From bb14d172a68f2a4f232d57c3222c153dae501ca3 Mon Sep 17 00:00:00 2001 From: Ardis Lu Date: Thu, 9 Jan 2025 22:11:13 -0800 Subject: [PATCH] Allow transformation function to return multiple rows --- src/core.js | 10 +++++++--- test/core.test.js | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/core.js b/src/core.js index 48f327f..e49389b 100644 --- a/src/core.js +++ b/src/core.js @@ -118,13 +118,14 @@ export function createCSVReadableStream(path) { /** * Create a new [TransformStream](https://developer.mozilla.org/en-US/docs/Web/API/TransformStream) to process CSV data. * - * @param {function(Array|string):Array|string|null} fn A function to process a row of CSV data from `createCSVReadableStream`. + * @param {function(Array|string):Array>|Array|string|null} fn A function to process a row of CSV data from `createCSVReadableStream`. * * If `options.rawInput` is `false` (default), the input will be a `Array` representing the CSV row. If `options.rawInput` is `true`, * the input will be a JSON `string` representing the CSV row. * - * If `options.rawOutput` is `false` (default), the expected output is a `Array` which will be serialized with `JSON.stringify()`. If - * `options.rawOutput` is `true`, the raw output will be sent the next stream unmodified. + * If `options.rawOutput` is `false` (default), the expected output is a `Array` which will be serialized with `JSON.stringify()` and enqueued, + * or a `Array>` which will have each of its sub-arrays serialized and enqueued separately. If `options.rawOutput` is `true`, the raw + * output will be sent the next stream unmodified. * * Return `null` to consume an input row without emitting an output row. * @param {createCSVTransformStreamOptions} options Object containing flags to configure the stream logic. @@ -155,6 +156,9 @@ export function createCSVTransformStream(fn, options = {}) { if (options.rawOutput || typeof out === 'string') { controller.enqueue(out); } + else if (Array.isArray(out) && Array.isArray(out[0])) { // Multiple rows returned, enqueue each row separately + out.forEach(row => controller.enqueue(JSON.stringify(row))); + } else { controller.enqueue(JSON.stringify(out)); } diff --git a/test/core.test.js b/test/core.test.js index 9fbb8e2..436e5e1 100644 --- a/test/core.test.js +++ b/test/core.test.js @@ -202,6 +202,20 @@ suite('createCSVTransformStream', { concurrency: true }, () => { ['a', 'b'], ])); }); + test('enqueues multiple rows when Array> is returned', { concurrency: true }, async () => { + await createCSVMockStream([ + ['columnA', 'columnB'], + ['a', 'b'] + ]) + .pipeThrough(createCSVTransformStream(r => ([r, r, r, r]))) + .pipeTo(csvStreamEqualWritable([ + ['columnA', 'columnB'], + ['a', 'b'], + ['a', 'b'], + ['a', 'b'], + ['a', 'b'] + ])); + }); }); suite('createCSVWritableStream', { concurrency: true }, () => { -- 2.47.3