🚀 Socket Launch Week Day 4:Socket MCP Adds Org Alerts, Threat Feed Review, and Package Inspection.Learn more
Sign In

@cerios/csv-nested-json

Package Overview
Dependencies
Maintainers
2
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cerios/csv-nested-json - npm Package Compare versions

Comparing version
1.1.0
to
1.2.0
+324
-1
dist/index.d.mts

@@ -0,1 +1,2 @@

import * as node_stream from 'node:stream';
import { Readable, TransformOptions, Transform, TransformCallback } from 'node:stream';

@@ -98,2 +99,47 @@

/**
* Strategy for handling duplicate column headers in CSV files.
* - `'error'`: Throw a CsvDuplicateHeaderError (default)
* - `'rename'`: Rename duplicates to 'name_1', 'name_2', etc.
* - `'combine'`: Combine duplicate values into comma-separated string
* - `'first'`: Keep only the first value for duplicate columns
* - `'last'`: Keep only the last value for duplicate columns
*/
type DuplicateHeaderStrategy = "error" | "rename" | "combine" | "first" | "last";
/**
* Information about parsing progress, passed to progress callbacks.
*/
interface ProgressInfo {
/**
* Total number of bytes processed so far.
*/
bytesProcessed: number;
/**
* Number of records emitted so far.
*/
recordsEmitted: number;
/**
* Whether the header row has been processed.
*/
headersProcessed: boolean;
/**
* Time elapsed since parsing started, in milliseconds.
*/
elapsedMs: number;
}
/**
* Callback function for progress updates during streaming parsing.
* Can be synchronous or asynchronous. Async callbacks are fire-and-forget
* (parsing does not wait for them to complete).
*
* @param info - Current progress information
*
* @example
* ```typescript
* const callback: ProgressCallback = (info) => {
* console.log(`Parsed ${info.recordsEmitted} records in ${info.elapsedMs}ms`);
* };
* ```
*/
type ProgressCallback = (info: ProgressInfo) => void | Promise<void>;
/**
* Configuration options for CSV parsing and conversion.

@@ -311,2 +357,72 @@ *

nullRepresentation?: NullRepresentation;
/**
* Maximum number of records to parse.
* Parsing stops after this limit is reached.
* Useful for previewing large files or pagination.
*
* @example
* ```typescript
* // Only parse first 100 records
* CsvParser.parseString(csv, { limit: 100 });
* ```
*/
limit?: number;
/**
* List of column names to include in the output.
* Only these columns will be present in parsed records.
* Cannot be used together with excludeColumns.
*
* @example
* ```typescript
* CsvParser.parseString(csv, {
* includeColumns: ['id', 'name', 'email']
* });
* ```
*/
includeColumns?: string[];
/**
* List of column names to exclude from the output.
* All columns except these will be present in parsed records.
* Cannot be used together with includeColumns.
*
* @example
* ```typescript
* CsvParser.parseString(csv, {
* excludeColumns: ['password', 'secret']
* });
* ```
*/
excludeColumns?: string[];
/**
* Strategy for handling duplicate column headers.
* - `'error'`: Throw a CsvDuplicateHeaderError (default)
* - `'rename'`: Rename duplicates to 'name_1', 'name_2', etc.
* - `'combine'`: Combine duplicate values into comma-separated string
* - `'first'`: Keep only the first value for duplicate columns
* - `'last'`: Keep only the last value for duplicate columns
* @default 'error'
*
* @example
* ```typescript
* CsvParser.parseString(csv, {
* duplicateHeaders: 'rename'
* });
* ```
*/
duplicateHeaders?: DuplicateHeaderStrategy;
/**
* Column to use as the identifier for grouping continuation rows.
* By default, the first column is used to identify new records.
* When this column has an empty value, the row is treated as a continuation
* of the previous record.
*
* @example
* ```typescript
* // Use 'productId' instead of first column to group rows
* CsvParser.parseString(csv, {
* identifierColumn: 'productId'
* });
* ```
*/
identifierColumn?: string;
}

@@ -597,2 +713,23 @@

static parseLine(line: string, delimiter?: string, quote?: string): string[];
/**
* Detect duplicate headers and process them according to the strategy.
* Returns the processed headers and a set of indices that are duplicates.
*
* @param headers - The parsed header names
* @param strategy - The duplicate handling strategy
* @param headerRow - The 1-based row number for error reporting
* @returns Object with processed headers and duplicate indices
* @throws {CsvDuplicateHeaderError} If strategy is 'error' and duplicates found
*/
private static detectAndProcessDuplicateHeaders;
/**
* Filter columns based on includeColumns and excludeColumns options.
* Returns the filtered headers and an array mapping filtered indices to original indices.
*
* @param headers - The parsed header names (after transformations)
* @param options - Parser options containing includeColumns/excludeColumns
* @param validationMode - How to handle warnings about missing columns
* @returns Object with filtered headers and index mapping array
*/
private static filterColumns;
}

@@ -612,2 +749,43 @@

nested?: boolean;
/**
* Callback function called periodically to report parsing progress.
* Can be synchronous or asynchronous.
*
* @example
* ```typescript
* const parser = new CsvStreamParser({
* progressCallback: (info) => {
* console.log(`Parsed ${info.recordsEmitted} records`);
* }
* });
* ```
*/
progressCallback?: ProgressCallback;
/**
* How often to call the progress callback, in number of records.
* The callback is invoked every N records emitted.
* @default 100
*/
progressInterval?: number;
/**
* Number of records to batch together before emitting.
* When set to a value greater than 1, the stream emits arrays of records
* instead of individual records.
*
* Note: When using batchSize > 1, each 'data' event receives an array.
* The static parseStream() method always returns a flat array regardless
* of this setting.
*
* @default 1
*
* @example
* ```typescript
* const parser = new CsvStreamParser({ batchSize: 100 });
* for await (const batch of stream.pipe(parser)) {
* // batch is an array of up to 100 records
* console.log(`Received ${batch.length} records`);
* }
* ```
*/
batchSize?: number;
}

@@ -669,2 +847,13 @@ /**

private nullSet;
private duplicateStrategy;
private duplicateIndices;
private includedIndices;
private bytesProcessed;
private recordsEmitted;
private startTime;
private progressInterval;
private limit;
private limitReached;
private batchSize;
private recordBatch;
/**

@@ -687,2 +876,34 @@ * Creates a new streaming CSV parser.

/**
* Parse a readable stream and return all records as a Promise.
* This is a convenience method that collects all streamed records into an array.
*
* For true streaming with backpressure handling, use the pipe-based API instead.
*
* @typeParam T - The expected type of each record in the result array
* @param stream - Readable stream containing CSV data
* @param options - Parser options
* @returns Promise resolving to array of parsed records
*
* @example
* ```typescript
* import { createReadStream } from 'node:fs';
* import { CsvStreamParser } from '@cerios/csv-nested-json';
*
* const stream = createReadStream('data.csv');
* const records = await CsvStreamParser.parseStream(stream, {
* delimiter: ',',
* autoParseNumbers: true
* });
* ```
*
* @example
* ```typescript
* // Get flat records instead of nested
* const flatRecords = await CsvStreamParser.parseStream(stream, {
* nested: false
* });
* ```
*/
static parseStream<T = NestedObject>(stream: node_stream.Readable, options?: CsvStreamParserOptions): Promise<T[]>;
/**
* Transform implementation - processes incoming chunks.

@@ -698,2 +919,7 @@ * @internal

/**
* Destroy implementation - cleans up resources.
* @internal
*/
_destroy(error: Error | null, callback: (error: Error | null) => void): void;
/**
* Strip BOM from the beginning of a string.

@@ -743,2 +969,10 @@ */

private unflatten;
/**
* Detect duplicate headers and process them according to the strategy.
*/
private detectAndProcessDuplicateHeaders;
/**
* Filter columns based on includeColumns and excludeColumns options.
*/
private filterColumns;
}

@@ -844,2 +1078,28 @@

}
/**
* Error thrown when duplicate headers are detected and the strategy is 'error'.
* Contains the list of duplicate header names and the row number where they were found.
*
* @example
* ```typescript
* try {
* CsvParser.parseString('id,name,id\n1,Alice,2');
* } catch (error) {
* if (error instanceof CsvDuplicateHeaderError) {
* console.log(`Duplicate headers: ${error.duplicateHeaders.join(', ')}`);
* // Output: "Duplicate headers: id"
* }
* }
* ```
*/
declare class CsvDuplicateHeaderError extends CsvParseError {
readonly duplicateHeaders: string[];
readonly headerRow: number;
/**
* Creates a new duplicate header error
* @param duplicateHeaders - Array of header names that appear more than once
* @param headerRow - The 1-based row number where the headers are located
*/
constructor(duplicateHeaders: string[], headerRow?: number);
}

@@ -1049,2 +1309,65 @@ /**

private static processGroup;
/**
* Build hierarchy structure for forced array fields.
* This enables context-aware merging of continuation rows.
*/
private static buildForcedArrayHierarchy;
/**
* Analyze a row to determine merge behavior based on which fields have values.
*/
private static analyzeRowContext;
/**
* Process a group of rows using hierarchy-aware merging.
* This handles nested forced arrays correctly by distinguishing between
* "create new parent item" vs "append to nested array in existing item".
*/
private static processGroupWithHierarchy;
/**
* Deep merge with tracking of last items in forced arrays.
* Used for the first row to establish the base structure.
*/
private static deepMergeWithTracking;
/**
* Track last items in nested forced arrays.
*/
private static trackLastItems;
/**
* Context-aware merge for continuation rows.
* Decides whether to create new array items or append to existing nested arrays.
*/
private static contextAwareMerge;
/**
* Check if the only data under this path is in child forced array fields.
* Returns false if there are no child forced arrays.
*/
private static hasOnlyChildArrayData;
/**
* Check if there's any data under a given path in the flat row.
*/
private static hasDataUnderPath;
/**
* Apply the context-aware merge decisions.
*/
private static applyContextAwareMerge;
/**
* Merge fields that are not part of forced arrays.
* Uses deepMerge for proper collision detection and auto-array creation.
*/
private static mergeNonArrayFields;
/**
* Filter out paths that are under forced array fields.
*/
private static filterForcedArrayPaths;
/**
* Get value at a dot-separated path in a nested object.
*/
private static getValueAtPath;
/**
* Ensure an array exists at the given path, creating intermediate objects as needed.
*/
private static ensureArrayAtPath;
/**
* Ensure an array exists at the given relative path within an object.
*/
private static ensureArrayAtPathRelative;
private static unflatten;

@@ -1058,2 +1381,2 @@ private static deepMerge;

export { type ArrayMode, CsvEncodingError, CsvFileNotFoundError, CsvFileReader, CsvParseError, CsvParser, type CsvParserOptions, CsvReader, type CsvRecord, CsvStreamParser, type CsvStreamParserOptions, CsvValidationError, type EmptyArrayBehavior, type HeaderTransformer, JsonToCsv, type JsonToCsvOptions, NestedJsonConverter, type NestedObject, type NestedValue, type NullRepresentation, type RowFilter, type ValidationMode, type ValueTransformer };
export { type ArrayMode, CsvDuplicateHeaderError, CsvEncodingError, CsvFileNotFoundError, CsvFileReader, CsvParseError, CsvParser, type CsvParserOptions, CsvReader, type CsvRecord, CsvStreamParser, type CsvStreamParserOptions, CsvValidationError, type DuplicateHeaderStrategy, type EmptyArrayBehavior, type HeaderTransformer, JsonToCsv, type JsonToCsvOptions, NestedJsonConverter, type NestedObject, type NestedValue, type NullRepresentation, type ProgressCallback, type ProgressInfo, type RowFilter, type ValidationMode, type ValueTransformer };

@@ -0,1 +1,2 @@

import * as node_stream from 'node:stream';
import { Readable, TransformOptions, Transform, TransformCallback } from 'node:stream';

@@ -98,2 +99,47 @@

/**
* Strategy for handling duplicate column headers in CSV files.
* - `'error'`: Throw a CsvDuplicateHeaderError (default)
* - `'rename'`: Rename duplicates to 'name_1', 'name_2', etc.
* - `'combine'`: Combine duplicate values into comma-separated string
* - `'first'`: Keep only the first value for duplicate columns
* - `'last'`: Keep only the last value for duplicate columns
*/
type DuplicateHeaderStrategy = "error" | "rename" | "combine" | "first" | "last";
/**
* Information about parsing progress, passed to progress callbacks.
*/
interface ProgressInfo {
/**
* Total number of bytes processed so far.
*/
bytesProcessed: number;
/**
* Number of records emitted so far.
*/
recordsEmitted: number;
/**
* Whether the header row has been processed.
*/
headersProcessed: boolean;
/**
* Time elapsed since parsing started, in milliseconds.
*/
elapsedMs: number;
}
/**
* Callback function for progress updates during streaming parsing.
* Can be synchronous or asynchronous. Async callbacks are fire-and-forget
* (parsing does not wait for them to complete).
*
* @param info - Current progress information
*
* @example
* ```typescript
* const callback: ProgressCallback = (info) => {
* console.log(`Parsed ${info.recordsEmitted} records in ${info.elapsedMs}ms`);
* };
* ```
*/
type ProgressCallback = (info: ProgressInfo) => void | Promise<void>;
/**
* Configuration options for CSV parsing and conversion.

@@ -311,2 +357,72 @@ *

nullRepresentation?: NullRepresentation;
/**
* Maximum number of records to parse.
* Parsing stops after this limit is reached.
* Useful for previewing large files or pagination.
*
* @example
* ```typescript
* // Only parse first 100 records
* CsvParser.parseString(csv, { limit: 100 });
* ```
*/
limit?: number;
/**
* List of column names to include in the output.
* Only these columns will be present in parsed records.
* Cannot be used together with excludeColumns.
*
* @example
* ```typescript
* CsvParser.parseString(csv, {
* includeColumns: ['id', 'name', 'email']
* });
* ```
*/
includeColumns?: string[];
/**
* List of column names to exclude from the output.
* All columns except these will be present in parsed records.
* Cannot be used together with includeColumns.
*
* @example
* ```typescript
* CsvParser.parseString(csv, {
* excludeColumns: ['password', 'secret']
* });
* ```
*/
excludeColumns?: string[];
/**
* Strategy for handling duplicate column headers.
* - `'error'`: Throw a CsvDuplicateHeaderError (default)
* - `'rename'`: Rename duplicates to 'name_1', 'name_2', etc.
* - `'combine'`: Combine duplicate values into comma-separated string
* - `'first'`: Keep only the first value for duplicate columns
* - `'last'`: Keep only the last value for duplicate columns
* @default 'error'
*
* @example
* ```typescript
* CsvParser.parseString(csv, {
* duplicateHeaders: 'rename'
* });
* ```
*/
duplicateHeaders?: DuplicateHeaderStrategy;
/**
* Column to use as the identifier for grouping continuation rows.
* By default, the first column is used to identify new records.
* When this column has an empty value, the row is treated as a continuation
* of the previous record.
*
* @example
* ```typescript
* // Use 'productId' instead of first column to group rows
* CsvParser.parseString(csv, {
* identifierColumn: 'productId'
* });
* ```
*/
identifierColumn?: string;
}

@@ -597,2 +713,23 @@

static parseLine(line: string, delimiter?: string, quote?: string): string[];
/**
* Detect duplicate headers and process them according to the strategy.
* Returns the processed headers and a set of indices that are duplicates.
*
* @param headers - The parsed header names
* @param strategy - The duplicate handling strategy
* @param headerRow - The 1-based row number for error reporting
* @returns Object with processed headers and duplicate indices
* @throws {CsvDuplicateHeaderError} If strategy is 'error' and duplicates found
*/
private static detectAndProcessDuplicateHeaders;
/**
* Filter columns based on includeColumns and excludeColumns options.
* Returns the filtered headers and an array mapping filtered indices to original indices.
*
* @param headers - The parsed header names (after transformations)
* @param options - Parser options containing includeColumns/excludeColumns
* @param validationMode - How to handle warnings about missing columns
* @returns Object with filtered headers and index mapping array
*/
private static filterColumns;
}

@@ -612,2 +749,43 @@

nested?: boolean;
/**
* Callback function called periodically to report parsing progress.
* Can be synchronous or asynchronous.
*
* @example
* ```typescript
* const parser = new CsvStreamParser({
* progressCallback: (info) => {
* console.log(`Parsed ${info.recordsEmitted} records`);
* }
* });
* ```
*/
progressCallback?: ProgressCallback;
/**
* How often to call the progress callback, in number of records.
* The callback is invoked every N records emitted.
* @default 100
*/
progressInterval?: number;
/**
* Number of records to batch together before emitting.
* When set to a value greater than 1, the stream emits arrays of records
* instead of individual records.
*
* Note: When using batchSize > 1, each 'data' event receives an array.
* The static parseStream() method always returns a flat array regardless
* of this setting.
*
* @default 1
*
* @example
* ```typescript
* const parser = new CsvStreamParser({ batchSize: 100 });
* for await (const batch of stream.pipe(parser)) {
* // batch is an array of up to 100 records
* console.log(`Received ${batch.length} records`);
* }
* ```
*/
batchSize?: number;
}

@@ -669,2 +847,13 @@ /**

private nullSet;
private duplicateStrategy;
private duplicateIndices;
private includedIndices;
private bytesProcessed;
private recordsEmitted;
private startTime;
private progressInterval;
private limit;
private limitReached;
private batchSize;
private recordBatch;
/**

@@ -687,2 +876,34 @@ * Creates a new streaming CSV parser.

/**
* Parse a readable stream and return all records as a Promise.
* This is a convenience method that collects all streamed records into an array.
*
* For true streaming with backpressure handling, use the pipe-based API instead.
*
* @typeParam T - The expected type of each record in the result array
* @param stream - Readable stream containing CSV data
* @param options - Parser options
* @returns Promise resolving to array of parsed records
*
* @example
* ```typescript
* import { createReadStream } from 'node:fs';
* import { CsvStreamParser } from '@cerios/csv-nested-json';
*
* const stream = createReadStream('data.csv');
* const records = await CsvStreamParser.parseStream(stream, {
* delimiter: ',',
* autoParseNumbers: true
* });
* ```
*
* @example
* ```typescript
* // Get flat records instead of nested
* const flatRecords = await CsvStreamParser.parseStream(stream, {
* nested: false
* });
* ```
*/
static parseStream<T = NestedObject>(stream: node_stream.Readable, options?: CsvStreamParserOptions): Promise<T[]>;
/**
* Transform implementation - processes incoming chunks.

@@ -698,2 +919,7 @@ * @internal

/**
* Destroy implementation - cleans up resources.
* @internal
*/
_destroy(error: Error | null, callback: (error: Error | null) => void): void;
/**
* Strip BOM from the beginning of a string.

@@ -743,2 +969,10 @@ */

private unflatten;
/**
* Detect duplicate headers and process them according to the strategy.
*/
private detectAndProcessDuplicateHeaders;
/**
* Filter columns based on includeColumns and excludeColumns options.
*/
private filterColumns;
}

@@ -844,2 +1078,28 @@

}
/**
* Error thrown when duplicate headers are detected and the strategy is 'error'.
* Contains the list of duplicate header names and the row number where they were found.
*
* @example
* ```typescript
* try {
* CsvParser.parseString('id,name,id\n1,Alice,2');
* } catch (error) {
* if (error instanceof CsvDuplicateHeaderError) {
* console.log(`Duplicate headers: ${error.duplicateHeaders.join(', ')}`);
* // Output: "Duplicate headers: id"
* }
* }
* ```
*/
declare class CsvDuplicateHeaderError extends CsvParseError {
readonly duplicateHeaders: string[];
readonly headerRow: number;
/**
* Creates a new duplicate header error
* @param duplicateHeaders - Array of header names that appear more than once
* @param headerRow - The 1-based row number where the headers are located
*/
constructor(duplicateHeaders: string[], headerRow?: number);
}

@@ -1049,2 +1309,65 @@ /**

private static processGroup;
/**
* Build hierarchy structure for forced array fields.
* This enables context-aware merging of continuation rows.
*/
private static buildForcedArrayHierarchy;
/**
* Analyze a row to determine merge behavior based on which fields have values.
*/
private static analyzeRowContext;
/**
* Process a group of rows using hierarchy-aware merging.
* This handles nested forced arrays correctly by distinguishing between
* "create new parent item" vs "append to nested array in existing item".
*/
private static processGroupWithHierarchy;
/**
* Deep merge with tracking of last items in forced arrays.
* Used for the first row to establish the base structure.
*/
private static deepMergeWithTracking;
/**
* Track last items in nested forced arrays.
*/
private static trackLastItems;
/**
* Context-aware merge for continuation rows.
* Decides whether to create new array items or append to existing nested arrays.
*/
private static contextAwareMerge;
/**
* Check if the only data under this path is in child forced array fields.
* Returns false if there are no child forced arrays.
*/
private static hasOnlyChildArrayData;
/**
* Check if there's any data under a given path in the flat row.
*/
private static hasDataUnderPath;
/**
* Apply the context-aware merge decisions.
*/
private static applyContextAwareMerge;
/**
* Merge fields that are not part of forced arrays.
* Uses deepMerge for proper collision detection and auto-array creation.
*/
private static mergeNonArrayFields;
/**
* Filter out paths that are under forced array fields.
*/
private static filterForcedArrayPaths;
/**
* Get value at a dot-separated path in a nested object.
*/
private static getValueAtPath;
/**
* Ensure an array exists at the given path, creating intermediate objects as needed.
*/
private static ensureArrayAtPath;
/**
* Ensure an array exists at the given relative path within an object.
*/
private static ensureArrayAtPathRelative;
private static unflatten;

@@ -1058,2 +1381,2 @@ private static deepMerge;

export { type ArrayMode, CsvEncodingError, CsvFileNotFoundError, CsvFileReader, CsvParseError, CsvParser, type CsvParserOptions, CsvReader, type CsvRecord, CsvStreamParser, type CsvStreamParserOptions, CsvValidationError, type EmptyArrayBehavior, type HeaderTransformer, JsonToCsv, type JsonToCsvOptions, NestedJsonConverter, type NestedObject, type NestedValue, type NullRepresentation, type RowFilter, type ValidationMode, type ValueTransformer };
export { type ArrayMode, CsvDuplicateHeaderError, CsvEncodingError, CsvFileNotFoundError, CsvFileReader, CsvParseError, CsvParser, type CsvParserOptions, CsvReader, type CsvRecord, CsvStreamParser, type CsvStreamParserOptions, CsvValidationError, type DuplicateHeaderStrategy, type EmptyArrayBehavior, type HeaderTransformer, JsonToCsv, type JsonToCsvOptions, NestedJsonConverter, type NestedObject, type NestedValue, type NullRepresentation, type ProgressCallback, type ProgressInfo, type RowFilter, type ValidationMode, type ValueTransformer };
+1
-1
{
"name": "@cerios/csv-nested-json",
"version": "1.1.0",
"version": "1.2.0",
"author": "Ronald Veth - Cerios",

@@ -5,0 +5,0 @@ "description": "Parse CSV files into nested JSON objects with support for dot notation, arrays, and complex data structures",

+253
-6

@@ -14,2 +14,7 @@ # @cerios/csv-nested-json

- **Bidirectional Conversion** - Convert CSV to JSON and JSON back to CSV
- **Column Selection** - Include or exclude specific columns during parsing
- **Duplicate Header Handling** - Smart strategies for duplicate column names
- **Limit Records** - Stop parsing after N records for previews or pagination
- **Progress Monitoring** - Track parsing progress with callbacks for large files
- **Batch Processing** - Process records in configurable batches for memory efficiency
- **Value Transformations** - Auto-parse numbers, booleans, dates, or use custom transformers

@@ -153,2 +158,54 @@ - **Header Transformations** - Transform and map column names

### Progress Monitoring
Track parsing progress for large files:
```typescript
import { CsvStreamParser, ProgressInfo } from '@cerios/csv-nested-json';
import { createReadStream } from 'node:fs';
const parser = new CsvStreamParser({
progressCallback: (progress: ProgressInfo) => {
console.log(`Processed ${progress.recordsEmitted} records`);
console.log(`Bytes: ${progress.bytesProcessed}`);
console.log(`Elapsed: ${progress.elapsedMs}ms`);
},
progressInterval: 1000 // Call every 1000 records (default: 100)
});
for await (const record of createReadStream('./large.csv').pipe(parser)) {
// Process record
}
```
The `ProgressInfo` object contains:
- `bytesProcessed`: Total bytes read so far
- `recordsEmitted`: Number of records emitted
- `headersProcessed`: Whether headers have been parsed
- `elapsedMs`: Milliseconds since parsing started
### Batch Processing
Process records in batches for memory-efficient streaming:
```typescript
import { CsvStreamParser } from '@cerios/csv-nested-json';
import { createReadStream } from 'node:fs';
const parser = new CsvStreamParser({
batchSize: 100 // Emit arrays of 100 records
});
for await (const batch of createReadStream('./large.csv').pipe(parser)) {
// batch is an array of up to 100 records
await processBatch(batch);
}
// Note: parseStream() always returns a flat array regardless of batchSize
const allRecords = await CsvStreamParser.parseStream(
createReadStream('./data.csv'),
{ batchSize: 100 } // Batching used internally, result is flattened
);
```
### 6. Convert JSON to CSV

@@ -458,2 +515,82 @@

### Column Selection
Include or exclude specific columns during parsing:
```typescript
const csvContent = `id,name,email,password,role
1,Alice,alice@example.com,secret123,admin
2,Bob,bob@example.com,password456,user`;
// Include only specific columns
const result1 = CsvParser.parseString(csvContent, {
includeColumns: ['id', 'name', 'email']
});
// Result: [{ id: "1", name: "Alice", email: "alice@example.com" }, ...]
// Exclude sensitive columns
const result2 = CsvParser.parseString(csvContent, {
excludeColumns: ['password']
});
// Result: [{ id: "1", name: "Alice", email: "alice@example.com", role: "admin" }, ...]
```
### Duplicate Header Handling
Handle CSV files with duplicate column names:
```typescript
const csvContent = `id,name,value,value,value
1,Test,A,B,C`;
// Keep first occurrence (default)
const result1 = CsvParser.parseString(csvContent, {
duplicateHeaders: 'first'
});
// Result: [{ id: "1", name: "Test", value: "A" }]
// Keep last occurrence
const result2 = CsvParser.parseString(csvContent, {
duplicateHeaders: 'last'
});
// Result: [{ id: "1", name: "Test", value: "C" }]
// Combine into comma-separated string
const result3 = CsvParser.parseString(csvContent, {
duplicateHeaders: 'combine'
});
// Result: [{ id: "1", name: "Test", value: "A,B,C" }]
// Rename duplicates with suffix
const result4 = CsvParser.parseString(csvContent, {
duplicateHeaders: 'rename'
});
// Result: [{ id: "1", name: "Test", value: "A", value_1: "B", value_2: "C" }]
// Throw error on duplicates (default)
const result5 = CsvParser.parseString(csvContent, {
duplicateHeaders: 'error'
});
// Throws CsvDuplicateHeaderError
```
### Limit Records
Limit the number of records parsed (useful for previews or pagination):
```typescript
const csvContent = `id,name
1,Alice
2,Bob
3,Charlie
4,Diana
5,Eve`;
const result = CsvParser.parseString(csvContent, {
limit: 3
});
// Result: [{ id: "1", ... }, { id: "2", ... }, { id: "3", ... }]
// Parsing stops after 3 records - efficient for large files
```
### Skip Rows (Metadata Headers)

@@ -761,3 +898,11 @@

rowFilter?: (record, rowIndex) => boolean; // Filter rows during parsing
limit?: number; // Max records to parse
// Column selection
includeColumns?: string[]; // Include only these columns
excludeColumns?: string[]; // Exclude these columns
// Duplicate header handling
duplicateHeaders?: DuplicateHeaderStrategy; // Default: 'error'
// Value transformations

@@ -783,3 +928,14 @@ autoParseNumbers?: boolean; // Default: false

defaultValues?: Record<string, string>; // Default values for empty cells
// Row grouping
identifierColumn?: string; // Column for grouping continuation rows
}
// Streaming-specific options (CsvStreamParser)
interface CsvStreamParserOptions extends CsvParserOptions {
nested?: boolean; // Emit nested objects (default: true)
batchSize?: number; // Emit records in batches
progressCallback?: ProgressCallback; // Progress tracking callback
progressInterval?: number; // Records between callbacks (default: 100)
}
```

@@ -873,2 +1029,49 @@

#### `limit`
Maximum number of records to parse. Parsing stops after this limit is reached, which is efficient for large files when you only need a preview or first N records.
```typescript
limit: 100 // Stop after 100 records
```
#### `includeColumns`
Array of column names to include. Only these columns will be in the output.
```typescript
includeColumns: ['id', 'name', 'email'] // Only include these columns
```
#### `excludeColumns`
Array of column names to exclude. All other columns will be included.
```typescript
excludeColumns: ['password', 'secret'] // Exclude sensitive columns
```
#### `duplicateHeaders`
Strategy for handling duplicate column names in CSV headers. Default: `'error'`
```typescript
duplicateHeaders: 'rename' // 'error' | 'rename' | 'combine' | 'first' | 'last'
```
- `'error'` (default): Throw `CsvDuplicateHeaderError` on duplicates
- `'rename'`: Rename duplicates with suffix (e.g., `value`, `value_1`, `value_2`)
- `'combine'`: Combine values into comma-separated string
- `'first'`: Keep only the first occurrence of duplicate headers
- `'last'`: Keep only the last occurrence
#### `identifierColumn`
Column to use as the identifier for grouping continuation rows. By default, the first column is used to identify new records. When this column has an empty value, the row is treated as a continuation of the previous record.
```typescript
// Use 'productId' instead of first column to group rows
identifierColumn: 'productId'
```
#### `arraySuffixIndicator`

@@ -886,3 +1089,3 @@

Strings to interpret as null values. Default: `['null', 'NULL', 'nil', 'NIL']`
Strings to interpret as null values. Default: `['null', 'NULL', 'nil', 'NIL', '']`

@@ -921,3 +1124,10 @@ #### `nullRepresentation`

rowFilter: (record) => record.status !== 'deleted',
limit: 1000,
// Column selection
excludeColumns: ['password', 'secret'],
// Duplicate header handling
duplicateHeaders: 'rename',
// Value transformations

@@ -936,2 +1146,5 @@ autoParseNumbers: true,

// Row grouping
identifierColumn: 'id',
// Array handling

@@ -975,3 +1188,3 @@ arraySuffixIndicator: '[]',

```typescript
import { CsvStreamParser } from '@cerios/csv-nested-json';
import { CsvStreamParser, ProgressInfo } from '@cerios/csv-nested-json';

@@ -981,2 +1194,8 @@ const parser = new CsvStreamParser({

autoParseNumbers: true,
limit: 1000, // Stop after 1000 records
batchSize: 100, // Emit in batches of 100
progressCallback: (info: ProgressInfo) => {
console.log(`Progress: ${info.recordsEmitted} records, ${info.elapsedMs}ms`);
},
progressInterval: 500, // Call progress every 500 records
// ... other CsvParserOptions

@@ -991,2 +1210,12 @@ });

#### Static Promise API
```typescript
// Parse stream and collect all records
const records = await CsvStreamParser.parseStream(
createReadStream('./data.csv'),
{ autoParseNumbers: true, limit: 100 }
);
```
### JsonToCsv Class

@@ -1029,3 +1258,4 @@

CsvValidationError,
CsvEncodingError
CsvEncodingError,
CsvDuplicateHeaderError
} from '@cerios/csv-nested-json';

@@ -1040,2 +1270,4 @@

console.error(`File not found: ${error.filePath}`);
} else if (error instanceof CsvDuplicateHeaderError) {
console.error(`Duplicate headers: ${error.duplicateHeaders.join(', ')}`);
} else if (error instanceof CsvValidationError) {

@@ -1056,3 +1288,3 @@ console.error(`Validation error at row ${error.row}`);

Records are grouped by the first column (identifier). When the first column is empty, the row is treated as a continuation of the previous group:
Records are grouped by the first column (identifier) by default, or by the column specified in `identifierColumn`. When this column is empty, the row is treated as a continuation of the previous group:

@@ -1218,5 +1450,9 @@ ```csv

CsvParserOptions,
CsvStreamParserOptions,
CsvParseError,
CsvValidationError,
NestedObject
NestedObject,
ProgressInfo,
ProgressCallback,
DuplicateHeaderOptions
} from '@cerios/csv-nested-json';

@@ -1250,2 +1486,3 @@

type ArrayMode = 'rows' | 'json';
type DuplicateHeaderStrategy = 'error' | 'rename' | 'combine' | 'first' | 'last';

@@ -1256,3 +1493,12 @@ // Function types

type RowFilter = (record: CsvRecord, rowIndex: number) => boolean;
type ProgressCallback = (info: ProgressInfo) => void | Promise<void>;
// Progress tracking
interface ProgressInfo {
bytesProcessed: number; // Total bytes read
recordsEmitted: number; // Records emitted so far
headersProcessed: boolean; // Whether headers have been parsed
elapsedMs: number; // Milliseconds since start
}
// Data types

@@ -1263,4 +1509,5 @@ type CsvRecord = Record<string, string>;

// Options interface
// Options interfaces
interface CsvParserOptions { /* ... */ }
interface CsvStreamParserOptions extends CsvParserOptions { /* ... */ }
```

@@ -1267,0 +1514,0 @@

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display