Headers make the examples easier to skim. Using minor numberings is also useful to later add more examples without having to renumber existing groupings each time.
## Example
-Assume `./examples/data/ex1-in.csv` looks like:
+Assume `./examples/data/ex1_1-in.csv` looks like:
```plaintext
columnA,columnB
return [Number(row[0]) * 2, Number(row[1]) * 2];
}
-await new CSVReader('./examples/data/ex1-in.csv')
+await new CSVReader('./examples/data/ex1_1-in.csv')
.pipeThrough(new CSVTransformer(timesTwo))
- .pipeTo(new CSVWriter('./examples/data/ex1-out.csv'));
+ .pipeTo(new CSVWriter('./examples/data/ex1_1-out.csv'));
```
-A new `./examples/data/ex1-out.csv` file will be created:
+A new `./examples/data/ex1_1-out.csv` file will be created:
```plaintext
columnA,columnB
```javascript
import { CSVReader } from './src/index.js';
-const readableStream = new CSVReader('./examples/data/ex1-in.csv');
+const readableStream = new CSVReader('./examples/data/ex1_1-in.csv');
for await (const row of readableStream) {
console.log(row);
All examples can be run directly without additional setup using `node`. E.g.:
```
-node ./examples/ex1.js
+node ./examples/ex1_1.js
```
## Table of contents
-[Example 1: Basic usage](./ex1.js)
+### Section 1: Common usage
-[Example 2: Updating headers in the output](./ex2.js)
+These examples demonstrate the most common, expected usage.
-[Example 3: Chaining multiple transformations](./ex3.js)
+[Example 1.1: Basic usage](./ex1_1.js)
-[Example 4: Using `CSVNormalizer` and `CSVDenormalizer`](./ex4.js)
+[Example 1.2: Updating headers in the output](./ex1_2.js)
-[Example 5: Handling an irregularly-shaped CSV file](./ex5.js)
+[Example 1.3: Chaining multiple transformations](./ex1_3.js)
-[Example 6: Handling a flaky transformation (basic retry strategy)](./ex6.js)
+[Example 1.4: Handling an irregularly-shaped CSV file](./ex1_4.js)
-[Example 7: Processing rows in batches (multi-row input)](./ex7.js)
+### Section 2: Error strategies
-[Example 8: Processing rows concurrently (async)](./ex8.js)
+These examples demonstrate using the `onError` option to handle transformations that may throw errors.
-[Example 9: Handling a flaky transformation (graceful failure)](./ex9.js)
\ No newline at end of file
+[Example 2.1: Basic retry strategy](./ex2_1.js)
+
+[Example 2.2: Graceful failure (placeholder value)](./ex2_2.js)
+
+### Section 3: Batch and concurrent processing
+
+These examples demonstrate using the `maxBatchSize` and `maxConcurrent` options to process more than one CSV row at a time.
+
+[Example 3.1: Batch processing (multi-row input) using `maxBatchSize`](./ex3_1.js)
+
+[Example 3.2: Concurrent processing (async) using `maxConcurrent`](./ex3_2.js)
+
+### Section 4: Extended API
+
+These examples demonstrate the extended API.
+
+[Example 4.1: Using `CSVNormalizer` and `CSVDenormalizer`](./ex4_1.js)
-// ## Example 1: Basic usage
+// ## Example 1.1: Basic usage
//
// Minimal example of a user-defined function to transform a CSV.
//
return [Number(row[0]) * 2, Number(row[1]) * 2];
}
-await new CSVReader(new URL('./data/ex1-in.csv', import.meta.url))
+await new CSVReader(new URL('./data/ex1_1-in.csv', import.meta.url))
.pipeThrough(new CSVTransformer(timesTwo))
- .pipeTo(new CSVWriter(new URL('./data/ex1-out.csv', import.meta.url)));
\ No newline at end of file
+ .pipeTo(new CSVWriter(new URL('./data/ex1_1-out.csv', import.meta.url)));
\ No newline at end of file
-// ## Example 2: Updating headers in the output
+// ## Example 1.2: Updating headers in the output
//
// Set `includeHeaders: true` to manually handle the header row (first row).
//
return [...row, Number(row[0]) + Number(row[1])];
}
-await new CSVReader(new URL('./data/ex2-in.csv', import.meta.url))
+await new CSVReader(new URL('./data/ex1_2-in.csv', import.meta.url))
.pipeThrough(new CSVTransformer(sum, { includeHeaders: true }))
- .pipeTo(new CSVWriter(new URL('./data/ex2-out.csv', import.meta.url)));
\ No newline at end of file
+ .pipeTo(new CSVWriter(new URL('./data/ex1_2-out.csv', import.meta.url)));
\ No newline at end of file
-// ## Example 3: Chaining multiple transformations
+// ## Example 1.3: Chaining multiple transformations
//
// Set `rawInput: true` and/or `rawOutput: true` to skip JSON deserialization (`rawInput`) and/or JSON serialization
// (`rawOutput`) when handling the transformation function input/output. These options are intended for advanced
return [name, paddedId];
}
-await new CSVReader(new URL('./data/ex3-in.csv', import.meta.url))
+await new CSVReader(new URL('./data/ex1_3-in.csv', import.meta.url))
.pipeThrough(new CSVTransformer(parse, { includeHeaders: true, rawOutput: true }))
.pipeThrough(new CSVTransformer(calculate, { includeHeaders: true, rawInput: true }))
- .pipeTo(new CSVWriter(new URL('./data/ex3-out.csv', import.meta.url)));
\ No newline at end of file
+ .pipeTo(new CSVWriter(new URL('./data/ex1_3-out.csv', import.meta.url)));
\ No newline at end of file
-// ## Example 5: Handling an irregularly-shaped CSV file
+// ## Example 1.4: Handling an irregularly-shaped CSV file
//
// `CSVReader` can parse CSVs that have rows with a mismatching number of columns, for example CSVs
// with informational file headers. This information can be handled as required in the transformation function.
return [report, id, date, ...row];
}
-await new CSVReader(new URL('./data/ex5-in.csv', import.meta.url))
+await new CSVReader(new URL('./data/ex1_4-in.csv', import.meta.url))
.pipeThrough(new CSVTransformer(parse, { includeHeaders: true }))
- .pipeTo(new CSVWriter(new URL('./data/ex5-out.csv', import.meta.url)));
\ No newline at end of file
+ .pipeTo(new CSVWriter(new URL('./data/ex1_4-out.csv', import.meta.url)));
\ No newline at end of file
-// ## Example 6: Handling a flaky transformation (basic retry strategy)
+// ## Example 2.1: Basic retry strategy
//
// Pass a function to the `onError` option of `CSVTransformer` to catch errors thrown by the transformation
// function.
return [`${v}: pass`];
}
-await new CSVReader(new URL('./data/ex6-in.csv', import.meta.url))
+await new CSVReader(new URL('./data/ex2_1-in.csv', import.meta.url))
.pipeThrough(new CSVTransformer(flaky, { onError: (row, e, fn) => retry(row, fn, 1000) }))
- .pipeTo(new CSVWriter(new URL('./data/ex6-out.csv', import.meta.url)));
\ No newline at end of file
+ .pipeTo(new CSVWriter(new URL('./data/ex2_1-out.csv', import.meta.url)));
\ No newline at end of file
-// ## Example 9: Handling a flaky transformation (graceful failure)
+// ## Example 2.2: Graceful failure (placeholder value)
import { CSVReader, CSVTransformer, CSVWriter } from '../src/index.js';
return row;
}
-await new CSVReader(new URL('./data/ex9-in.csv', import.meta.url))
+await new CSVReader(new URL('./data/ex2_2-in.csv', import.meta.url))
.pipeThrough(new CSVTransformer(flaky, { onError: row => graceful(row) }))
- .pipeTo(new CSVWriter(new URL('./data/ex9-out.csv', import.meta.url)));
\ No newline at end of file
+ .pipeTo(new CSVWriter(new URL('./data/ex2_2-out.csv', import.meta.url)));
\ No newline at end of file
-// ## Example 7: Processing rows in batches (multi-row input)
+// ## Example 3.1: Batch processing (multi-row input) using `maxBatchSize`
//
// Set the `maxBatchSize` option to a number greater than `1` to collect rows into batches before passing the whole
// batch to the transformation function.
return batch.map(row => [batchNumber, sum, ...row]);
}
-await new CSVReader(new URL('./data/ex7-in.csv', import.meta.url))
+await new CSVReader(new URL('./data/ex3_1-in.csv', import.meta.url))
.pipeThrough(new CSVTransformer(process, { includeHeaders: true, maxBatchSize: 5 }))
- .pipeTo(new CSVWriter(new URL('./data/ex7-out.csv', import.meta.url)));
\ No newline at end of file
+ .pipeTo(new CSVWriter(new URL('./data/ex3_1-out.csv', import.meta.url)));
\ No newline at end of file
-// ## Example 8: Processing rows concurrently (async)
+// ## Example 3.2: Concurrent processing (async) using `maxConcurrent`
//
// Set the `maxConcurrent` option to a number greater than `1` to process rows concurrently. The transformation function
// will be automatically turned into a promise if it isn't already async.
return [tick(), ...row];
}
-await new CSVReader(new URL('./data/ex8-in.csv', import.meta.url))
+await new CSVReader(new URL('./data/ex3_2-in.csv', import.meta.url))
.pipeThrough(new CSVTransformer(concurrent, { includeHeaders: true, maxConcurrent: 5 }))
- .pipeTo(new CSVWriter(new URL('./data/ex8-out.csv', import.meta.url)));
\ No newline at end of file
+ .pipeTo(new CSVWriter(new URL('./data/ex3_2-out.csv', import.meta.url)));
\ No newline at end of file
-// ## Example 4: Using `CSVNormalizer` and `CSVDenormalizer`
+// ## Example 4.1: Using `CSVNormalizer` and `CSVDenormalizer`
//
-// These functions fix common CSV data mangling caused by Excel. In `ex4-in.csv`:
+// These functions fix common CSV data mangling caused by Excel. In `ex4_1-in.csv`:
// - The "Index" column has been mangled into Excel's "Accounting" format
// - The "Phone Number" column has been mangled into scientific notation
// - The "Join Timestamp" column has been mangled into a number
}
];
-await new CSVReader(new URL('./data/ex4-in.csv', import.meta.url))
+await new CSVReader(new URL('./data/ex4_1-in.csv', import.meta.url))
.pipeThrough(new CSVNormalizer(headers))
.pipeThrough(new CSVDenormalizer())
- .pipeTo(new CSVWriter(new URL('./data/ex4-out.csv', import.meta.url)));
\ No newline at end of file
+ .pipeTo(new CSVWriter(new URL('./data/ex4_1-out.csv', import.meta.url)));
\ No newline at end of file
const tests = [];
const files = await opendir(tempExamples, { recursive: true });
for await (const file of files) {
- const { name } = /(?<name>ex\d+).js/.exec(file.name)?.groups ?? { name: null }; // Assuming naming convention "ex*.js"
+ const { name } = /(?<name>ex\d+_\d+).js/.exec(file.name)?.groups ?? { name: null }; // Assuming naming convention "ex*_*.js"
if (name === null) { continue; }
tests.push({
name,