]> git.ardis.lu - csvio/commitdiff
Allow passing an array to `placeholder`
authorArdis Lu <ardisglu@gmail.com>
Thu, 18 Sep 2025 06:47:10 +0000 (23:47 -0700)
committerArdis Lu <ardisglu@gmail.com>
Thu, 18 Sep 2025 06:47:10 +0000 (23:47 -0700)
This functionality is helpful to indicate different and more useful placeholders for each column.

It also allows setting a completely blank row (without any commas) on error, which may be desirable to make output CSV row counts match input CSV row counts without clutter.

src/errorStrategies.js
test/errorStrategies.test.js

index f2b76e67f4c8956792c24bcec9e80a9f95939a5d..1a1fe2bdfe9ab76f92889fee0a4e9cfb661bc9aa 100644 (file)
@@ -26,14 +26,20 @@ function skip() {
 
 /**
  * Create a `TransformationErrorFunction` that handles errors by filling the output row with a given placeholder value.
+ * To set a blank row without any commas, pass an empty array `[]`. To set a blank row with commas to match the number
+ * of columns in the rest of the CSV, pass an empty string `''`.
  * 
- * @param {string} value The placeholder value to fill the row with. This value will be used for each field in the row.
+ * @param {Array<string>|string} value The placeholder value to fill the row with. If an `Array<string>` is passed, `value`
+ * will be used as the literal row. If a `string` is passed, `value` will be used to fill each field in the row.
  * @returns {TransformationErrorFunction} A `TransformationErrorFunction` that may be passed to a `CSVTransformer`'s
  * `onError` option.
  */
 function placeholder(value) {
   return (row) => {
-    if (row.length === 0) {
+    if (Array.isArray(value)) {
+      return value;
+    }
+    else if (row.length === 0) {
       return [value];
     }
     else {
@@ -46,7 +52,7 @@ function placeholder(value) {
  * @typedef {Object} RetryOptions
  * @property {number} [interval] The duration (in milliseconds) to wait in between each retry. The default value is `0`
  * (retry immediately).
- * @property {string} [placeholder] A placeholder value to set if the function still errors after the final iteration.
+ * @property {Array<string>|string} [placeholder] A placeholder value to set if the function still errors after the final iteration.
  * If unset, the final error thrown by the function is re-thrown.
  */
 
@@ -79,7 +85,7 @@ function retry(iterations, options = {}) {
  * @property {number} [maxExponent] If provided, the maximum exponent used to calculate the retry duration. In other words,
  * the `iterations` number at which the retry duration stops increasing. If `maxExponent` is unset, the retry duration
  * is unbounded and will increase after each retry.
- * @property {string} [placeholder] A placeholder value to set if the function still errors after the final iteration.
+ * @property {Array<string>|string} [placeholder] A placeholder value to set if the function still errors after the final iteration.
  * If unset, the final error thrown by the function is re-thrown.
  */
 
index 124446e12209dbae9a2cc272f0772c849db631eb..07f456c5c909baa5a2538aabe741409415c7ad0f 100644 (file)
@@ -54,6 +54,45 @@ suite('ErrorStrategies.skip', { concurrency: true }, () => {
 });
 
 suite('ErrorStrategies.placeholder', { concurrency: true }, () => {
+  test('sets exact placeholder row if an array is passed', async () => {
+    await createCSVMockStream([
+      ['header', 'header', 'header'],
+      ['1', '1', '1'],
+      ['1', '1', '1']
+    ])
+      .pipeThrough(new CSVTransformer(() => { throw new Error(); }, { onError: placeholder(['n/a 1', 'n/a 2', 'n/a 3']) }))
+      .pipeTo(csvStreamEqualWritable([
+        ['header', 'header', 'header'],
+        ['n/a 1', 'n/a 2', 'n/a 3'],
+        ['n/a 1', 'n/a 2', 'n/a 3']
+      ]));
+  });
+  test('sets empty row if an empty array is passed', async () => {
+    await createCSVMockStream([
+      ['header', 'header', 'header'],
+      ['1', '1', '1'],
+      ['1', '1', '1']
+    ])
+      .pipeThrough(new CSVTransformer(() => { throw new Error(); }, { onError: placeholder([]) }))
+      .pipeTo(csvStreamEqualWritable([
+        ['header', 'header', 'header'],
+        [],
+        []
+      ]));
+  });
+  test('sets empty row matching column count if an empty string is passed', async () => {
+    await createCSVMockStream([
+      ['header', 'header', 'header'],
+      ['1', '1', '1'],
+      ['1', '1', '1']
+    ])
+      .pipeThrough(new CSVTransformer(() => { throw new Error(); }, { onError: placeholder('') }))
+      .pipeTo(csvStreamEqualWritable([
+        ['header', 'header', 'header'],
+        ['', '', ''],
+        ['', '', '']
+      ]));
+  });
   test('sets placeholders on all fields in a row', async () => {
     await createCSVMockStream([
       ['header', 'header', 'header'],
This page took 0.037771 seconds and 4 git commands to generate.