From 0fd0ef01408c9b1f11e4203c0ece11f3933f544d Mon Sep 17 00:00:00 2001 From: Ardis Lu Date: Sat, 1 Nov 2025 22:05:52 -0700 Subject: [PATCH] Add `.source` property for `FieldMap` This property is useful when there is no other variable set to access the underlying row (e.g., `.toFieldMap` was called with a literal object). --- src/normalization.js | 21 ++++++++++++++++----- test/normalization.test.js | 9 +++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/normalization.js b/src/normalization.js index 04cff95..e22c411 100644 --- a/src/normalization.js +++ b/src/normalization.js @@ -339,6 +339,12 @@ export class CSVNormalizer extends TransformStream { return object; } + /** + * @typedef {Object} FieldMapExtensions + * @property {Array} source The original CSV row object that was passed to `.toFieldMap` to + * create the `FieldMap` object. + */ + /** * Create a subset of the `Map` interface to get and set the `value` of a field using its `name`. * @@ -354,14 +360,16 @@ export class CSVNormalizer extends TransformStream { * - `.clear()` * - `.size` * - * All other methods are unsupported. For more advanced usage, use the underlying `row` object directly. + * All other `Map` methods are unsupported. * - * The `displayName` and `emptyField` values of a field cannot be accessed from the `Map`. + * The `displayName` and `emptyField` values of a field cannot be accessed from the `Map`. Calling `.set()` with a + * `name` that is not in the row will push a new field to the row. * - * Calling `.set()` with a `name` that is not in the row will push a new field to the row. + * For more advanced usage, use the underlying `row` object directly. You can access the underlying `row` object by + * calling the `.source` property. * @param {Array} row A normalized CSV row. - * @returns {Pick,'get'|'set'|'has'|'delete'|'clear'|'size'>} A `Proxy` over a `Map` object with keys - * set to the `name` of each field in the row. + * @returns {Pick,'get'|'set'|'has'|'delete'|'clear'|'size'>&FieldMapExtensions}} A `Proxy` + * over a `Map` object with keys set to the `name` of each field in the row. */ static toFieldMap(row) { const map = new Map(); @@ -407,6 +415,9 @@ export class CSVNormalizer extends TransformStream { target.clear(); } } + if (prop === 'source') { + return row; + } } }); } diff --git a/test/normalization.test.js b/test/normalization.test.js index 846eeea..268b52e 100644 --- a/test/normalization.test.js +++ b/test/normalization.test.js @@ -275,6 +275,15 @@ suite('CSVNormalizer.toFieldMap', { concurrency: true }, () => { const map = CSVNormalizer.toFieldMap(row); deepStrictEqual(map.size, 1); }); + test('has a .source property to access the underlying row', { concurrency: true }, async () => { + const row = [{ name: 'a', value: 1 }]; + const map = CSVNormalizer.toFieldMap(row); + ok(map.source === row); // Intentionally comparing by reference, do not use deepStrictEqual + row.push({ name: 'b', value: 2 }); + ok(map.source === row); + map.source.push({ name: 'c', value: 3 }); + ok(map.source === row); + }); }); suite('CSVNormalizer.from', { concurrency: true }, () => { -- 2.47.3