]> git.ardis.lu - csvio/commitdiff
Add example for `stdin` and `stdout` usage
authorArdis Lu <ardisglu@gmail.com>
Fri, 22 Aug 2025 03:27:37 +0000 (20:27 -0700)
committerArdis Lu <ardisglu@gmail.com>
Fri, 22 Aug 2025 03:27:37 +0000 (20:27 -0700)
examples/README.md
examples/data/ex1_8-in.csv [new file with mode: 0644]
examples/data/ex1_8-out.csv [new file with mode: 0644]
examples/ex1_8.js [new file with mode: 0644]
test/examples.test.js

index a78fd6f92d29f49d61c29c4ecd465fe121c99a93..607878ae5ced960e5f1144dba07d1b8be6a3d31b 100644 (file)
@@ -28,6 +28,8 @@ These examples demonstrate the most common, expected usage.
 
 [Example 1.7: Abort a transformation](./ex1_7.js) ([input](./data/ex1_7-in.csv), [output](./data/ex1_7-out.csv))
 
+[Example 1.8: Read from `stdin` and write to `stdout`](./ex1_8.js) ([input](./data/ex1_8-in.csv), [output](./data/ex1_8-out.csv))
+
 ### Section 2: Error strategies
 
 These examples demonstrate using the `onError` option to handle transformations that may throw errors.
diff --git a/examples/data/ex1_8-in.csv b/examples/data/ex1_8-in.csv
new file mode 100644 (file)
index 0000000..4bd7c6a
--- /dev/null
@@ -0,0 +1,6 @@
+columnA,columnB\r
+1,1\r
+100,100\r
+223423,455947\r
+348553,692708\r
+536368,676147
\ No newline at end of file
diff --git a/examples/data/ex1_8-out.csv b/examples/data/ex1_8-out.csv
new file mode 100644 (file)
index 0000000..3b79d13
--- /dev/null
@@ -0,0 +1,6 @@
+columnA,columnB\r
+2,2\r
+101,101\r
+223424,455948\r
+348554,692709\r
+536369,676148\r
diff --git a/examples/ex1_8.js b/examples/ex1_8.js
new file mode 100644 (file)
index 0000000..9d3490e
--- /dev/null
@@ -0,0 +1,20 @@
+// ## Example 1.8: Read from `stdin` and write to `stdout`
+// 
+// Wrap Node.js's `process.stdin` and `process.stdout` to handle the `stdin` and `stdout` streams.
+// This usage is helpful for integrating csvio within complex shell scripts.
+
+import { stdin, stdout } from 'node:process';
+import { Readable, Writable } from 'node:stream';
+import { TextDecoderStream } from 'node:stream/web';
+import { CSVReader, CSVTransformer, CSVWriter } from '../src/index.js';
+
+// Do not `await`, the pipe just runs indefinitely. The shell script will close this process.
+Readable.toWeb(stdin)
+  .pipeThrough(new TextDecoderStream()) // CSVReader expects text, bring your own text decoder.
+  .pipeThrough(new CSVReader())
+  .pipeThrough(new CSVTransformer(r => r.map(v => Number(v) + 1)))
+  .pipeThrough(new CSVWriter()) // No need to encode on this end, CSVWriter already outputs text.
+  .pipeTo(Writable.toWeb(stdout));
+
+// Basic usage example:
+// cat ./examples/data/ex1_8-in.csv | node ./examples/ex1_8.js > ./examples/data/ex1_8-out.csv
index a39e2f911b22b35638244a3bf38aceb518bb23b6..8e49070de30b150b13f75a3a2ca423c268ce0114 100644 (file)
@@ -1,7 +1,10 @@
 import { suite, after, test } from 'node:test';
 import { ok } from 'node:assert/strict';
+import { createReadStream, createWriteStream } from 'node:fs';
 import { mkdir, cp, opendir, readFile, rm } from 'node:fs/promises';
-import { pathToFileURL } from 'node:url';
+import { pathToFileURL, fileURLToPath } from 'node:url';
+import { spawn } from 'node:child_process';
+import { finished } from 'node:stream/promises';
 
 import { createTempFolder, assertConsole } from './utils.js';
 
@@ -28,13 +31,14 @@ for await (const file of files) {
   tests.push({
     name,
     code: new URL(`${name}.js`, tempExamples),
+    input: new URL(`./data/${name}-in.csv`, tempExamples),
     output: new URL(`./data/${name}-out.csv`, tempExamples)
   });
 }
 
 suite('examples', { concurrency: true }, () => {
   after(async () => await rm(dir, { recursive: true, force: true }));
-  for (const { name, code, output } of tests) {
+  for (const { name, code, input, output } of tests) {
     if (name === 'ex1_6') {
       test(name, { concurrency: true }, async (t) => {
         assertConsole(t, { log: 1 });
@@ -44,6 +48,16 @@ suite('examples', { concurrency: true }, () => {
         ok(actual.equals(expected));
       });
     }
+    else if (name === 'ex1_8') {
+      test(name, { concurrency: true }, async () => {
+        const expected = await readFile(output);
+        const child = spawn(process.execPath, [fileURLToPath(code)]);
+        createReadStream(input).pipe(child.stdin); // Equivalent to `cat ${input} | child`
+        await finished(child.stdout.pipe(createWriteStream(output))); // Equivalent to `child > ${output}`
+        const actual = await readFile(output);
+        ok(actual.equals(expected));
+      });
+    }
     else {
       test(name, { concurrency: true }, async () => {
         const expected = await readFile(output);
This page took 0.038962 seconds and 4 git commands to generate.