From abd24a42b84e22670b2f75d380438e8feee5fa14 Mon Sep 17 00:00:00 2001 From: Ardis Lu Date: Wed, 9 Jul 2025 21:33:12 -0700 Subject: [PATCH] Fall back on `name` if `displayName` is undefined This behavior is useful when passing rows to `CSVDenormalizer` after a transformation *other* than `CSVNormalizer` (which automatically creates `displayName`). --- src/normalization.js | 2 +- test/normalization.test.js | 27 +++++++++++++++++++++++++++ test/utils.js | 4 ++-- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/normalization.js b/src/normalization.js index 7f2fd3d..45a864a 100644 --- a/src/normalization.js +++ b/src/normalization.js @@ -308,7 +308,7 @@ export class CSVDenormalizer extends TransformStream { const row = JSON.parse(chunk); if (firstRow) { firstRow = false; - controller.enqueue(JSON.stringify(row.map(f => f.displayName))); + controller.enqueue(JSON.stringify(row.map(f => f?.displayName ?? f.name))); } controller.enqueue(JSON.stringify(row.map(f => f.value))); } diff --git a/test/normalization.test.js b/test/normalization.test.js index 1d355c1..c12577c 100644 --- a/test/normalization.test.js +++ b/test/normalization.test.js @@ -352,6 +352,33 @@ suite('CSVNormalizer', { concurrency: true }, () => { }); }); +suite('CSVDenormalizer', { concurrency: true }, () => { + test('can process normalized rows', { concurrency: true }, async () => { + await createCSVMockStream([ + [{ displayName: 'Column A', value: 'a1' }, { displayName: 'Column B', value: 'b1' }], + [{ displayName: 'Column A', value: 'a2' }, { displayName: 'Column B', value: 'b2' }] + ]) + .pipeThrough(new CSVDenormalizer()) + .pipeTo(csvStreamEqualWritable([ + ['Column A', 'Column B'], + ['a1', 'b1'], + ['a2', 'b2'] + ])); + }); + test('falls back on name if displayName is undefined', { concurrency: true }, async () => { + await createCSVMockStream([ + [{ name: 'Column A', value: 'a1' }, { displayName: 'Column B', value: 'b1' }], + [{ displayName: 'Column A', value: 'a2' }, { name: 'Column B', value: 'b2' }] + ]) + .pipeThrough(new CSVDenormalizer()) + .pipeTo(csvStreamEqualWritable([ + ['Column A', 'Column B'], + ['a1', 'b1'], + ['a2', 'b2'] + ])); + }); +}); + suite('CSVNormalizer and CSVDenormalizer end-to-end', { concurrency: true }, () => { test('can normalize', { concurrency: true }, async () => { const headers = [ diff --git a/test/utils.js b/test/utils.js index a56f739..b14a1c4 100644 --- a/test/utils.js +++ b/test/utils.js @@ -132,8 +132,8 @@ export function assertSleep(context, expected) { /** * Simulate a stream of CSV data for test mocking purposes. * - * @param {Array>} data A 2-D array representing the CSV file to mock, where each inner array - * is a row of the CSV. + * @param {Array>|Array>} data A 2-D array representing the CSV file to mock, where + * each inner array is a row of the CSV. * @returns {ReadableStream} A `ReadableStream` where each row is emitted as a separate chunk. */ export function createCSVMockStream(data) { -- 2.47.3