]> git.ardis.lu - csvio/commitdiff
Fix bug where `defaultValue` was not set if row is uneven
authorArdis Lu <ardisglu@gmail.com>
Thu, 10 Jul 2025 06:11:45 +0000 (23:11 -0700)
committerArdis Lu <ardisglu@gmail.com>
Thu, 10 Jul 2025 06:11:45 +0000 (23:11 -0700)
src/normalization.js
test/normalization.test.js

index 45a864ae72dda01cf7e92adff238ced15a41ee92..bc43d0b9930a8b406d26db0f788cb2dd92f9c8cb 100644 (file)
@@ -73,7 +73,7 @@ export function expandScientificNotation(str, truncate = false) {
  * @property {'string'|'number'|'bigint'|'date'} [type='string'] The JavaScript data type to attempt to cast this column to. If
  * the data cannot be unmangled, the data passes through as a `string`. The default value is `'string'`.
  * @property {string} [displayName=name] Optional `string` value to indicate the desired header name in the output CSV.
- * @property {string} [defaultValue] Optional `string` value to use to fill empty CSV fields. If no value is provided, the
+ * @property {string} [defaultValue=''] Optional `string` value to use to fill empty CSV fields. If no value is provided, the
  * field value will be `''` (empty string) in the output CSV.
  */
 
@@ -122,7 +122,7 @@ export class CSVNormalizer extends TransformStream {
     this.#passthroughEmptyRows = options.passthroughEmptyRows ?? false;
     this.#typeCastOnly = options.typeCastOnly ?? false;
 
-    for (const { name, type, displayName = name, defaultValue = null } of headers) {
+    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.`);
@@ -162,7 +162,7 @@ export class CSVNormalizer extends TransformStream {
     /** @type {Array<CSVNormalizerRow>} */
     const out = [];
     for (const { name, type, displayName, defaultValue, index } of this.#columns) {
-      let value = row[index];
+      let value = row[index] ?? '';
       const emptyField = value === '' ? true : false;
       switch (type) {
         case 'string': break;
@@ -170,7 +170,7 @@ export class CSVNormalizer extends TransformStream {
         case 'bigint': value = this.#typeCastOnly ? BigInt(value).toString() : CSVNormalizer.fixExcelBigInt(value); break;
         case 'date': value = this.#typeCastOnly ? new Date(value).toISOString() : CSVNormalizer.fixExcelDate(value); break;
       }
-      if (emptyField && defaultValue !== null) {
+      if (emptyField) {
         value = defaultValue;
       }
       out.push({ name, displayName, value, emptyField });
index a2e2466fd274e927ddf9796461bccdd903bfcfa1..fd7ef7a7b735e8d877ac88db99daa883a4684ce9 100644 (file)
@@ -293,6 +293,29 @@ suite('CSVNormalizer', { concurrency: true }, () => {
         ['', '', 's3']
       ]));
   });
+  test('handles uneven CSV', { concurrency: true }, async () => {
+    await createCSVMockStream([
+      ['common', 'maybe1', 'maybe2', 'maybe3'],
+      ['c'],
+      ['c', 'm'],
+      ['c', 'm', 'm'],
+      ['c', 'm', 'm', 'm']
+    ])
+      .pipeThrough(new CSVNormalizer([
+        { name: 'common', type: 'string' },
+        { name: 'maybe1', type: 'string' },
+        { name: 'maybe2', type: 'string' },
+        { name: 'maybe3', type: 'string' },
+      ]))
+      .pipeThrough(new CSVDenormalizer())
+      .pipeTo(csvStreamEqualWritable([
+        ['common', 'maybe1', 'maybe2', 'maybe3'],
+        ['c', '', '', ''],
+        ['c', 'm', '', ''],
+        ['c', 'm', 'm', ''],
+        ['c', 'm', 'm', 'm'],
+      ]));
+  });
   test('defaults to "string" type', { concurrency: true }, async () => {
     await createCSVMockStream([
       ['columnA', 'columnB'],
This page took 0.054224 seconds and 4 git commands to generate.