--- /dev/null
+// ## 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
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';
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 });
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);