diff --git a/docz/docs/04-getting-started/03-demos/13-cli.md b/docz/docs/04-getting-started/03-demos/13-cli.md
new file mode 100644
index 0000000..4934f8f
--- /dev/null
+++ b/docz/docs/04-getting-started/03-demos/13-cli.md
@@ -0,0 +1,60 @@
+---
+sidebar_position: 13
+title: Command-Line Tools
+---
+
+import current from '/version.js';
+
+With the availability of JS engines and the success of server-side runtimes, it
+is natural to want command-line tools for various workflows.
+
+This demo covers a number of strategies for building standalone processors. The
+goal is to generate CSV output from an arbitrary spreadsheet file.
+
+## Deno
+
+`deno compile` generates a standalone executable that includes the entire JS
+runtime as well as user JS code.
+
+When compiling, the `--allow-read` option must be specified to allow the script
+to read files from the filesystem with `Deno.readFileSync`.
+
+Complete Example (click to show)
+
+1) Save the following script to `sheet2csv.ts`:
+
+```ts title="sheet2csv.ts"
+/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
+// @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts"
+import * as XLSX from 'https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs';
+import * as cptable from 'https://cdn.sheetjs.com/xlsx-latest/package/dist/cpexcel.full.mjs';
+XLSX.set_cptable(cptable);
+
+/* Read and parse workbook */
+const filename = Deno.args[0];
+if(!filename) {
+ console.error("usage: sheet2csv [sheetname]");
+ Deno.exit(1);
+}
+const workbook = XLSX.readFile(filename);
+
+/* Find worksheet */
+const sheetname = Deno.args[1] || workbook.SheetNames[0];
+if(!workbook.Sheets[sheetname]) {
+ console.error(`error: workbook missing sheet ${sheetname}`);
+ Deno.exit(1);
+}
+
+/* Generate CSV and print to stdout */
+console.log(XLSX.utils.sheet_to_csv(workbook.Sheets[sheetname]));
+```
+
+2) Build `sheet2csv` with `deno compile`:
+
+```bash
+deno compile -r --allow-read sheet2csv.ts
+```
+
+`sheet2csv` is a generated executable that you can run.
+
+
\ No newline at end of file
diff --git a/docz/docs/04-getting-started/03-demos/index.md b/docz/docs/04-getting-started/03-demos/index.md
index 44b6460..54d04e6 100644
--- a/docz/docs/04-getting-started/03-demos/index.md
+++ b/docz/docs/04-getting-started/03-demos/index.md
@@ -34,8 +34,8 @@ The demo projects include small runnable examples and short explainers.
### Platforms and Integrations
+- [`Command-Line Tools`](./cli)
- [`NodeJS Server-Side Processing`](https://github.com/SheetJS/SheetJS/tree/master/demos/server/)
-- [`Deno`](https://github.com/SheetJS/SheetJS/tree/master/demos/deno/)
- [`Electron`](https://github.com/SheetJS/SheetJS/tree/master/demos/electron/)
- [`NW.js`](https://github.com/SheetJS/SheetJS/tree/master/demos/nwjs/)
- [`Chrome / Chromium Extension`](https://github.com/SheetJS/SheetJS/tree/master/demos/chrome/)
diff --git a/docz/docs/06-solutions/01-input.md b/docz/docs/06-solutions/01-input.md
index bf64f8a..a74bd66 100644
--- a/docz/docs/06-solutions/01-input.md
+++ b/docz/docs/06-solutions/01-input.md
@@ -173,9 +173,11 @@ import * as XLSX from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs'
const workbook = XLSX.readFile("test.xlsx");`}
+:::note
-Applications reading files must be invoked with the `--allow-read` flag. The
-[`deno` demo](https://github.com/SheetJS/SheetJS/tree/master/demos/deno/) has more examples
+Applications reading files must be invoked with the `--allow-read` flag.
+
+:::
diff --git a/docz/docs/06-solutions/05-output.md b/docz/docs/06-solutions/05-output.md
index 60b7348..02ed1b2 100644
--- a/docz/docs/06-solutions/05-output.md
+++ b/docz/docs/06-solutions/05-output.md
@@ -217,8 +217,11 @@ import * as XLSX from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs'
XLSX.writeFile(workbook, "test.xlsx");`}
-Applications writing files must be invoked with the `--allow-write` flag. The
-[`deno` demo](https://github.com/SheetJS/SheetJS/tree/master/demos/deno/) has more examples
+:::note
+
+Applications writing files must be invoked with the `--allow-write` flag.
+
+:::
@@ -832,31 +835,76 @@ Readable Stream.
- `XLSX.stream.to_html` is the streaming version of `XLSX.utils.sheet_to_html`.
- `XLSX.stream.to_json` is the streaming version of `XLSX.utils.sheet_to_json`.
-
- nodejs convert to CSV and write file (click to show)
+
+
+
+In a CommonJS context, NodeJS Streams immediately work with SheetJS. This
+example reads a worksheet passed as an argument to the script, pulls the first
+worksheet, converts to CSV and writes to `out.csv`:
```js
-var output_file_name = "out.csv";
-var stream = XLSX.stream.to_csv(worksheet);
+const XLSX = require("xlsx");
+
+const workbook = XLSX.readFile(process.argv[2]);
+const worksheet = workbook.Sheets[workbook.SheetNames[0]];
+// highlight-next-line
+const stream = XLSX.stream.to_csv(worksheet);
+
+const output_file_name = "out.csv";
+// highlight-next-line
stream.pipe(fs.createWriteStream(output_file_name));
```
-
-
-
- nodejs write JSON stream to screen (click to show)
+`stream.to_json` uses Object-mode streams. A `Transform` stream can be used to
+generate a normal stream for streaming to a file or the screen:
```js
/* to_json returns an object-mode stream */
+// highlight-next-line
var stream = XLSX.stream.to_json(worksheet, {raw:true});
-/* the following stream converts JS objects to text via JSON.stringify */
+/* this Transform stream converts JS objects to text and prints to screen */
var conv = new Transform({writableObjectMode:true});
conv._transform = function(obj, e, cb){ cb(null, JSON.stringify(obj) + "\n"); };
+conv.pipe(process.stdout);
-stream.pipe(conv); conv.pipe(process.stdout);
+// highlight-next-line
+stream.pipe(conv);
```
-
+
+
+
+Deno does not support NodeJS streams in normal execution, so a wrapper is used.
+This demo converts a worksheet to CSV and prints each row to the screen:
+
+```ts
+// @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts"
+import {utils, stream, set_cptable} from 'https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs';
+
+/* `Readable` will be compatible with how SheetJS uses `stream.Readable` */
+function NodeReadableCB(cb:(d:any)=>void) {
+ var rd = {
+ __done: false,
+ _read: function() {},
+ push: function(d: any) { if(!this.__done) cb(d); if(d == null) this.__done = true; },
+ resume: function pump() {for(var i = 0; i < 10000 && !this.__done; ++i) rd._read(); if(!rd.__done) setTimeout(pump, 0); }
+ };
+ return rd;
+}
+function NodeReadable(rd: any) { return function() { return rd; }; }
+/* The callback gets each CSV row. It will be `null` when the stream is drained */
+const rt = NodeReadableCB((d: any) => { if(d != null) console.log(d); });
+const Readable = NodeReadable(rt);
+stream.set_readable(Readable);
+
+/* wire up and start the stream */
+const rd = stream.to_csv(worksheet);
+rd.resume();
+```
+
+
+
+
pipes write streams to nodejs response.