@@ -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 */
193207export 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