]> git.ardis.lu - csvio/commitdiff
Make column matching case insensitive by default
authorArdis Lu <ardisglu@gmail.com>
Thu, 25 Sep 2025 06:33:37 +0000 (23:33 -0700)
committerArdis Lu <ardisglu@gmail.com>
Thu, 25 Sep 2025 06:33:37 +0000 (23:33 -0700)
Before: `datetime` and `dateTime` are considered different columns.

After: `datetime` and `dateTime` are considered the same column (last column prevails).

Note the output column name will still use the same casing passed in `CSVNormalizerHeader`.

`CSVNormalizer` already significantly modifies column names by normalizing to camelCase, so it is surprising the column matching is still case sensitive. It is likely that in the case a user wants `column A` and `columnA` to be the same column, that they'd also want `columna` to be the same as well.

src/normalization.js
test/normalization.test.js

index ee04dc0f8f88bece3fc57c13a680525878096bba..eeb0c823591978be2dda56437389215ce03fc6f2 100644 (file)
@@ -151,7 +151,9 @@ export class CSVNormalizer extends TransformStream {
       const normalizedRow = this.#useLiteralNames ? chunk : chunk.map(f => toCamelCase(f));
       let i = 0;
       for (const header of normalizedRow) {
-        const col = this.#columns.find(c => c.name === header);
+        const col = this.#useLiteralNames
+          ? this.#columns.find(c => c.name === header)
+          : this.#columns.find(c => c.name.toLocaleLowerCase() === header.toLocaleLowerCase());
         if (col !== undefined) { // Drop columns provided in the CSV but not the headers input
           col.index = i;
         }
index d4a182163100ecf64bdbbc46304dd0ef71129143..d4e15b44bf0f68d4f0b90cfe5d3fee61adf91795 100644 (file)
@@ -248,8 +248,8 @@ suite('CSVNormalizer', { concurrency: true }, () => {
   });
   test('removes columns that have the same normalized name (last column prevails)', { concurrency: true }, async () => {
     await createCSVMockStream([
-      ['columnA', 'column A', 'column-A'],
-      ['a1', 'a2', 'a3']
+      ['columnA', 'column A', 'column-A', 'columna'],
+      ['a1', 'a2', 'a3', 'a4']
     ])
       .pipeThrough(new CSVNormalizer([
         { name: 'columnA' }
@@ -257,23 +257,52 @@ suite('CSVNormalizer', { concurrency: true }, () => {
       .pipeThrough(new CSVDenormalizer())
       .pipeTo(csvStreamEqualWritable([
         ['columnA'],
-        ['a3']
+        ['a4']
       ]));
   });
   test('can match by literal column names', { concurrency: true }, async () => {
     await createCSVMockStream([
-      ['columnA', 'column A', 'column-A'],
-      ['a1', 'a2', 'a3']
+      ['columnA', 'column A', 'column-A', 'columna'],
+      ['a1', 'a2', 'a3', 'a4']
     ])
       .pipeThrough(new CSVNormalizer([
         { name: 'columnA' },
         { name: 'column A' },
-        { name: 'column-A' }
+        { name: 'column-A' },
+        { name: 'columna' }
+      ], { useLiteralNames: true }))
+      .pipeThrough(new CSVDenormalizer())
+      .pipeTo(csvStreamEqualWritable([
+        ['columnA', 'column A', 'column-A', 'columna'],
+        ['a1', 'a2', 'a3', 'a4']
+      ]));
+  });
+  test('is NOT case sensitive on column names', { concurrency: true }, async () => {
+    await createCSVMockStream([
+      ['datetime', 'dateTime'],
+      ['a1', 'a2']
+    ])
+      .pipeThrough(new CSVNormalizer([
+        { name: 'datetime' }
+      ]))
+      .pipeThrough(new CSVDenormalizer())
+      .pipeTo(csvStreamEqualWritable([
+        ['datetime'],
+        ['a2']
+      ]));
+  });
+  test('is case sensitive on column names when `useLiteralNames: true`', { concurrency: true }, async () => {
+    await createCSVMockStream([
+      ['datetime', 'dateTime'],
+      ['a1', 'a2']
+    ])
+      .pipeThrough(new CSVNormalizer([
+        { name: 'datetime' }
       ], { useLiteralNames: true }))
       .pipeThrough(new CSVDenormalizer())
       .pipeTo(csvStreamEqualWritable([
-        ['columnA', 'column A', 'column-A'],
-        ['a1', 'a2', 'a3']
+        ['datetime'],
+        ['a1']
       ]));
   });
   test('removes columns that have the same literal name (last column prevails)', { concurrency: true }, async () => {
This page took 0.038557 seconds and 4 git commands to generate.