From: Ardis Lu Date: Thu, 30 Oct 2025 06:46:01 +0000 (-0700) Subject: Add `.from` static method X-Git-Tag: v0.1.9~3 X-Git-Url: https://git.ardis.lu/?a=commitdiff_plain;h=1feec4e2cb1013a88606e2246215dcd2e5aef0e4;p=csvio Add `.from` static method This method is intended to be the inverse of the `.toObject` method. It is useful to have such a method as a functional (i.e., non-mutating) alternative to `.toFieldMap` to transform rows in a transformation function. --- diff --git a/src/normalization.js b/src/normalization.js index 7c1efee..04cff95 100644 --- a/src/normalization.js +++ b/src/normalization.js @@ -410,6 +410,19 @@ export class CSVNormalizer extends TransformStream { } }); } + + /** + * Create a new array of `CSVNormalizerField` from an object. + * @param {Object} obj An object to convert. + * @returns {Array} An array of `CSVNormalizerField`. + */ + static from(obj) { + const arr = []; + for (const [name, value] of Object.entries(obj)) { + arr.push({ name, value }); + } + return arr; + } } /** diff --git a/test/normalization.test.js b/test/normalization.test.js index e6a92f4..846eeea 100644 --- a/test/normalization.test.js +++ b/test/normalization.test.js @@ -207,6 +207,14 @@ suite('CSVNormalizer.toObject', { concurrency: true }, () => { const obj = CSVNormalizer.toObject(row); deepStrictEqual(obj.a.b[0], 1n); }); + test('is the inverse of .from', { concurrency: true }, async () => { + const obj = { + 'a': '1', + 'b': '2', + 'c': '3' + }; + deepStrictEqual(CSVNormalizer.toObject(CSVNormalizer.from(obj)), obj); + }); }); suite('CSVNormalizer.toFieldMap', { concurrency: true }, () => { @@ -269,6 +277,40 @@ suite('CSVNormalizer.toFieldMap', { concurrency: true }, () => { }); }); +suite('CSVNormalizer.from', { concurrency: true }, () => { + test('converts a simple object', { concurrency: true }, async () => { + deepStrictEqual(CSVNormalizer.from({ + 'columnA': 'valueA', + 'columnB': 'valueB' + }), [ + { name: 'columnA', value: 'valueA' }, + { name: 'columnB', value: 'valueB' }, + ]); + }); + test('converts an empty object', { concurrency: true }, async () => { + deepStrictEqual(CSVNormalizer.from({}), []); + }); + test('preserves complex value types', { concurrency: true }, async () => { + deepStrictEqual(CSVNormalizer.from({ + 'a': 123n, + 'b': { 'b-1': 'b-2' }, + 'c': ['c', 2, 3n] + }), [ + { name: 'a', value: 123n }, + { name: 'b', value: { 'b-1': 'b-2' } }, + { name: 'c', value: ['c', 2, 3n] }, + ]); + }); + test('is the inverse of .toObject', { concurrency: true }, async () => { + const row = [ + { name: 'a', value: '1' }, + { name: 'b', value: '2' }, + { name: 'c', value: '3' }, + ]; + deepStrictEqual(CSVNormalizer.from(CSVNormalizer.toObject(row)), row); + }); +}); + suite('CSVNormalizer', { concurrency: true }, () => { test('accepts string shorthand to set headers', { concurrency: true }, async () => { await createCSVMockStream([