From d9a45bbdba49446fa21bedb932653c9df2908006 Mon Sep 17 00:00:00 2001 From: Ardis Lu Date: Sat, 18 Oct 2025 21:17:43 -0700 Subject: [PATCH] Accept `string` as a shorthand for `{ name: string }` It is common to set headers using all the default values, so it is useful to have a shorthand for this situation. --- src/normalization.js | 41 +++++++++++++++++++++++++------------- test/normalization.test.js | 27 +++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/src/normalization.js b/src/normalization.js index bc3cd09..32a57f9 100644 --- a/src/normalization.js +++ b/src/normalization.js @@ -115,8 +115,8 @@ export class CSVNormalizer extends TransformStream { #typeCastOnly; /** - * @param {Array} headers An array of metadata objects to configure the data casting and - * cleanup transformations. + * @param {Array} headers An array of `CSVNormalizerHeader` or `string` to configure the + * data casting and cleanup transformations. Passing a plain `string` is the same as passing `{ name: string }`. * @param {CSVNormalizerOptions} options Object containing flags to configure the stream logic. */ constructor(headers, options = {}) { @@ -128,19 +128,32 @@ export class CSVNormalizer extends TransformStream { this.#passthroughEmptyRows = options.passthroughEmptyRows ?? false; this.#typeCastOnly = options.typeCastOnly ?? false; - for (const { name, type, displayName = name, defaultValue = '' } of headers) { - let normalizedType = type?.toLowerCase() ?? 'string'; - if (!['string', 'number', 'bigint', 'date'].includes(normalizedType)) { - console.warn(`Type "${normalizedType}" is not supported, defaulting to string.`); - normalizedType = 'string'; + for (const header of headers) { + if (typeof header === 'string') { + const name = this.#useLiteralNames ? header : toCamelCase(header); + this.#columns.push({ + name, + type: 'string', + displayName: name, + defaultValue: '', + index: null + }); + } + else { + const { name, type, displayName = name, defaultValue = '' } = header; + let normalizedType = type?.toLowerCase() ?? 'string'; + if (!['string', 'number', 'bigint', 'date'].includes(normalizedType)) { + console.warn(`Type "${normalizedType}" is not supported, defaulting to string.`); + normalizedType = 'string'; + } + this.#columns.push({ + name: this.#useLiteralNames ? name : toCamelCase(name), + type: normalizedType, + displayName, + defaultValue, + index: null + }); } - this.#columns.push({ - name: this.#useLiteralNames ? name : toCamelCase(name), - type: normalizedType, - displayName, - defaultValue, - index: null - }); } } diff --git a/test/normalization.test.js b/test/normalization.test.js index d71e0ae..d96e04b 100644 --- a/test/normalization.test.js +++ b/test/normalization.test.js @@ -252,6 +252,33 @@ suite('CSVNormalizer.toFieldMap', { concurrency: true }, () => { }); suite('CSVNormalizer', { concurrency: true }, () => { + test('accepts string shorthand to set headers', { concurrency: true }, async () => { + await createCSVMockStream([ + ['columnA', 'columnB'], + ['a', 'b'] + ]) + .pipeThrough(new CSVNormalizer(['columnA', 'columnB'])) + .pipeThrough(new CSVDenormalizer()) + .pipeTo(csvStreamEqualWritable([ + ['columnA', 'columnB'], + ['a', 'b'] + ])); + }); + test('accepts mixed string and CSVNormalizerHeader to set headers', { concurrency: true }, async () => { + await createCSVMockStream([ + ['columnA', 'columnB'], + ['a', 'b'] + ]) + .pipeThrough(new CSVNormalizer([ + 'columnA', + { name: 'columnB' } + ])) + .pipeThrough(new CSVDenormalizer()) + .pipeTo(csvStreamEqualWritable([ + ['columnA', 'columnB'], + ['a', 'b'] + ])); + }); test('can remove extra columns in CSV', { concurrency: true }, async () => { await createCSVMockStream([ ['extra1', 'columnA', 'extra2', 'extra3', 'columnB'], -- 2.47.3