Skip to content

Commit 84a4b4a

Browse files
committed
added mergeFn
1 parent 987e44e commit 84a4b4a

1 file changed

Lines changed: 47 additions & 2 deletions

File tree

src/headers.ts

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ export function createHeaderMapFns<To extends Record<string, any>, RowArr extend
170170
* @param data - Array of arrays or objects to transform
171171
* @param headerMap - Mapping between array indices or header names and object properties
172172
* @param headerRow - Optional header row for object input (if headerMap uses header names)
173+
* @param mergeFn - Optional function to customize how values are merged into the target object
173174
* @returns Array of structured objects
174175
* @example
175176
* ```typescript
@@ -188,12 +189,26 @@ export function createHeaderMapFns<To extends Record<string, any>, RowArr extend
188189
* csvData.slice(1), // Skip header row
189190
* { 0: 'id', 1: 'details.name', 2: 'details.price' }
190191
* );
192+
*
193+
* // With custom merge function to convert price to number
194+
* const productsWithPriceAsNumber = arrayToObjArray<Product>(
195+
* csvData.slice(1),
196+
* { 0: 'id', 1: 'details.name', 2: 'details.price' },
197+
* undefined,
198+
* (obj, key, value) => {
199+
* if (key === 'details.price') {
200+
* return parseFloat(value);
201+
* }
202+
* return value;
203+
* }
204+
* );
191205
* ```
192206
*/
193207
export function arrayToObjArray<T extends Record<string, any>>(
194208
data: any[],
195209
headerMap: HeaderMap<T>,
196-
headerRow?: string[]
210+
headerRow?: string[],
211+
mergeFn?: (obj: Partial<T>, key: string, value: any) => any
197212
): T[] {
198213
if (!Array.isArray(data)) {
199214
throw new CSVError('Data must be an array');
@@ -213,7 +228,37 @@ export function arrayToObjArray<T extends Record<string, any>>(
213228
if (isArrayData && hasStringKeys && !headerRow) {
214229
throw new CSVError('Header row is required for string-keyed header map with array data');
215230
}
216-
231+
232+
if (mergeFn) {
233+
return data.map(row => {
234+
// Convert row to an object if working with arrays and string header maps
235+
let objRow: Record<string, any> = {};
236+
if (isArrayData && hasStringKeys && headerRow) {
237+
for (let i = 0; i < row.length && i < headerRow.length; i++) {
238+
objRow[headerRow[i]] = row[i];
239+
}
240+
} else if (isArrayData) {
241+
// For array data with numeric indices
242+
objRow = [...row];
243+
} else {
244+
// For object data
245+
objRow = {...row};
246+
}
247+
248+
// Apply mappings with custom merge function
249+
const result = {} as T;
250+
for (const [sourceKey, targetPath] of Object.entries(headerMap)) {
251+
const key = isArrayData && !hasStringKeys ? parseInt(sourceKey) : sourceKey;
252+
const value = isArrayData ? row[key as number] : objRow[key as string];
253+
if (value !== undefined) {
254+
const processedValue = mergeFn(result, targetPath as string, value);
255+
setPath(result, targetPath as string, processedValue);
256+
}
257+
}
258+
return result;
259+
});
260+
}
261+
217262
return data.map(row => {
218263
// If working with arrays and string header maps, convert to object first
219264
if (isArrayData && hasStringKeys && headerRow) {

0 commit comments

Comments
 (0)