forked from sheetjs/docs.sheetjs.com
		
	hermes
This commit is contained in:
		
							parent
							
								
									820cbdfada
								
							
						
					
					
						commit
						686b5c55af
					
				@ -16,8 +16,8 @@ using platform-specific APIs.
 | 
			
		||||
 | 
			
		||||
## Dense Mode
 | 
			
		||||
 | 
			
		||||
The `dense` option (supported in `read`, `readFile` and `aoa_to_sheet`) creates
 | 
			
		||||
worksheet objects that use arrays of arrays under the hood:
 | 
			
		||||
`read`, `readFile` and `aoa_to_sheet` accept the `dense` option. When enabled,
 | 
			
		||||
the methods create worksheet objects that store cells in arrays of arrays:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var dense_wb = XLSX.read(ab, {dense: true});
 | 
			
		||||
@ -55,7 +55,9 @@ take the same arguments as the normal write functions:
 | 
			
		||||
 | 
			
		||||
<details><summary><b>Historical Note</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
NodeJS push streams were introduced in 2012.
 | 
			
		||||
NodeJS push streams were introduced in 2012. The text streaming methods `to_csv`
 | 
			
		||||
and `to_html` are supported in NodeJS v0.10 and later while the object streaming
 | 
			
		||||
method `to_json` is supported in NodeJS v0.12 and later.
 | 
			
		||||
 | 
			
		||||
The first streaming write function, `to_csv`, was introduced in April 2017.  It
 | 
			
		||||
used and still uses the same NodeJS streaming API.
 | 
			
		||||
@ -68,14 +70,14 @@ For maximal compatibility, the library uses NodeJS push streams.
 | 
			
		||||
 | 
			
		||||
### NodeJS
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
In a CommonJS context, NodeJS Streams and `fs` immediately work with SheetJS:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
const XLSX = require("xlsx"); // "just works"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::warning ECMAScript Module Machinations
 | 
			
		||||
 | 
			
		||||
In NodeJS ESM, the dependency must be loaded manually:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
@ -98,44 +100,214 @@ XLSX.set_fs(fs); // manually load fs helpers
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
**`XLSX.stream.to_csv`**
 | 
			
		||||
 | 
			
		||||
This example reads a worksheet passed as an argument to the script, pulls the
 | 
			
		||||
first worksheet, converts to CSV and writes to `out.csv`:
 | 
			
		||||
first worksheet, converts to CSV and writes to `SheetJSNodeJStream.csv`:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
var XLSX = require("xlsx");
 | 
			
		||||
var workbook = XLSX.readFile(process.argv[2]);
 | 
			
		||||
var worksheet = workbook.Sheets[workbook.SheetNames[0]];
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
var stream = XLSX.stream.to_csv(worksheet);
 | 
			
		||||
var XLSX = require("xlsx"), fs = require("fs");
 | 
			
		||||
 | 
			
		||||
var wb = XLSX.readFile(process.argv[2]);
 | 
			
		||||
var ws = wb.Sheets[wb.SheetNames[0]];
 | 
			
		||||
var ostream = fs.createWriteStream("SheetJSNodeJStream.csv");
 | 
			
		||||
 | 
			
		||||
var output_file_name = "out.csv";
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
stream.pipe(fs.createWriteStream(output_file_name));
 | 
			
		||||
XLSX.stream.to_csv(ws).pipe(ostream);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**`XLSX.stream.to_json`**
 | 
			
		||||
 | 
			
		||||
`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
 | 
			
		||||
var XLSX = require("xlsx");
 | 
			
		||||
var workbook = XLSX.readFile(process.argv[2], {dense: true});
 | 
			
		||||
var worksheet = workbook.Sheets[workbook.SheetNames[0]];
 | 
			
		||||
/* to_json returns an object-mode stream */
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
var stream = XLSX.stream.to_json(worksheet, {raw:true});
 | 
			
		||||
var XLSX = require("xlsx"), Transform = require("stream").Transform;
 | 
			
		||||
var wb = XLSX.readFile(process.argv[2], {dense: true});
 | 
			
		||||
var ws = wb.Sheets[wb.SheetNames[0]];
 | 
			
		||||
 | 
			
		||||
/* this Transform stream converts JS objects to text and prints to screen */
 | 
			
		||||
/* this Transform stream converts JS objects to text */
 | 
			
		||||
var conv = new Transform({writableObjectMode:true});
 | 
			
		||||
conv._transform = function(obj, e, cb){ cb(null, JSON.stringify(obj) + "\n"); };
 | 
			
		||||
conv.pipe(process.stdout);
 | 
			
		||||
 | 
			
		||||
/* pipe `to_json` -> transformer -> standard output */
 | 
			
		||||
// highlight-next-line
 | 
			
		||||
stream.pipe(conv);
 | 
			
		||||
XLSX.stream.to_json(ws, {raw: true}).pipe(conv).pipe(process.stdout);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
**Demo**
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
This demo was last tested in the following deployments:
 | 
			
		||||
 | 
			
		||||
| Node Version | Date       | Node Status when tested |
 | 
			
		||||
|:-------------|:-----------|:------------------------|
 | 
			
		||||
| `0.12.18`    | 2023-05-30 | End-of-Life             |
 | 
			
		||||
| `4.9.1`      | 2023-05-30 | End-of-Life             |
 | 
			
		||||
| `6.17.1`     | 2023-05-30 | End-of-Life             |
 | 
			
		||||
| `8.17.0`     | 2023-05-30 | End-of-Life             |
 | 
			
		||||
| `10.24.1`    | 2023-05-30 | End-of-Life             |
 | 
			
		||||
| `12.22.12`   | 2023-05-30 | End-of-Life             |
 | 
			
		||||
| `14.21.3`    | 2023-05-30 | End-of-Life             |
 | 
			
		||||
| `16.20.0`    | 2023-05-30 | Maintenance LTS         |
 | 
			
		||||
| `18.16.0`    | 2023-05-30 | Active LTS              |
 | 
			
		||||
| `20.2.0`     | 2023-05-30 | Current                 |
 | 
			
		||||
 | 
			
		||||
While streaming methods work in End-of-Life versions of NodeJS, production
 | 
			
		||||
deployments should upgrade to a Current or LTS version of NodeJS.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
1) Install the [NodeJS module](/docs/getting-started/installation/nodejs)
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
2) Download [`SheetJSNodeJStream.js`](pathname:///stream/SheetJSNodeJStream.js):
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://docs.sheetjs.com/stream/SheetJSNodeJStream.js
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
3) Download [the test file](https://sheetjs.com/pres.xlsx):
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://sheetjs.com/pres.xlsx
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
4) Run the script:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
node SheetJSNodeJStream.js pres.xlsx
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
<details><summary><b>Expected Output</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
The console will display a list of objects:
 | 
			
		||||
 | 
			
		||||
```json
 | 
			
		||||
{"Name":"Bill Clinton","Index":42}
 | 
			
		||||
{"Name":"GeorgeW Bush","Index":43}
 | 
			
		||||
{"Name":"Barack Obama","Index":44}
 | 
			
		||||
{"Name":"Donald Trump","Index":45}
 | 
			
		||||
{"Name":"Joseph Biden","Index":46}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The script will also generate `SheetJSNodeJStream.csv`:
 | 
			
		||||
 | 
			
		||||
```csv
 | 
			
		||||
Name,Index
 | 
			
		||||
Bill Clinton,42
 | 
			
		||||
GeorgeW Bush,43
 | 
			
		||||
Barack Obama,44
 | 
			
		||||
Donald Trump,45
 | 
			
		||||
Joseph Biden,46
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
### Browser
 | 
			
		||||
 | 
			
		||||
<details><summary><b>Live Demo</b> (click to show)</summary>
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
The live demo was last tested on 2023 May 30 in Chromium 113.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
NodeJS streaming APIs are not available in the browser.  The following function
 | 
			
		||||
supplies a pseudo stream object compatible with the `to_csv` function:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
function sheet_to_csv_cb(ws, cb, opts, batch = 1000) {
 | 
			
		||||
  XLSX.stream.set_readable(() => ({
 | 
			
		||||
    __done: false,
 | 
			
		||||
    // this function will be assigned by the SheetJS stream methods
 | 
			
		||||
    _read: function() { this.__done = true; },
 | 
			
		||||
    // this function is called by the stream methods
 | 
			
		||||
    push: function(d) { if(!this.__done) cb(d); if(d == null) this.__done = true; },
 | 
			
		||||
    resume: function pump() { for(var i = 0; i < batch && !this.__done; ++i) this._read(); if(!this.__done) setTimeout(pump.bind(this), 0); }
 | 
			
		||||
  }));
 | 
			
		||||
  return XLSX.stream.to_csv(ws, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// assuming `workbook` is a workbook, stream the first sheet
 | 
			
		||||
const ws = workbook.Sheets[workbook.SheetNames[0]];
 | 
			
		||||
const strm = sheet_to_csv_cb(ws, (csv)=>{ if(csv != null) console.log(csv); });
 | 
			
		||||
strm.resume();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Web Workers
 | 
			
		||||
 | 
			
		||||
For processing large files in the browser, it is strongly encouraged to use Web
 | 
			
		||||
Workers. The [Worker demo](/docs/demos/bigdata/worker#streaming-write) includes
 | 
			
		||||
examples using the File System Access API.
 | 
			
		||||
 | 
			
		||||
<details><summary><b>Web Worker Details</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
Typically, the file and stream processing occurs in the Web Worker.  CSV rows
 | 
			
		||||
can be sent back to the main thread in the callback:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="js" title="worker.js">{`\
 | 
			
		||||
/* load standalone script from CDN */
 | 
			
		||||
importScripts("https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js");
 | 
			
		||||
\n\
 | 
			
		||||
function sheet_to_csv_cb(ws, cb, opts, batch = 1000) {
 | 
			
		||||
  XLSX.stream.set_readable(() => ({
 | 
			
		||||
    __done: false,
 | 
			
		||||
    // this function will be assigned by the SheetJS stream methods
 | 
			
		||||
    _read: function() { this.__done = true; },
 | 
			
		||||
    // this function is called by the stream methods
 | 
			
		||||
    push: function(d) { if(!this.__done) cb(d); if(d == null) this.__done = true; },
 | 
			
		||||
    resume: function pump() { for(var i = 0; i < batch && !this.__done; ++i) this._read(); if(!this.__done) setTimeout(pump.bind(this), 0); }
 | 
			
		||||
  }));
 | 
			
		||||
  return XLSX.stream.to_csv(ws, opts);
 | 
			
		||||
}
 | 
			
		||||
\n\
 | 
			
		||||
/* this callback will run once the main context sends a message */
 | 
			
		||||
self.addEventListener('message', async(e) => {
 | 
			
		||||
  try {
 | 
			
		||||
    postMessage({state: "fetching " + e.data.url});
 | 
			
		||||
    /* Fetch file */
 | 
			
		||||
    const res = await fetch(e.data.url);
 | 
			
		||||
    const ab = await res.arrayBuffer();
 | 
			
		||||
\n\
 | 
			
		||||
    /* Parse file */
 | 
			
		||||
    postMessage({state: "parsing"});
 | 
			
		||||
    const wb = XLSX.read(ab, {dense: true});
 | 
			
		||||
    const ws = wb.Sheets[wb.SheetNames[0]];
 | 
			
		||||
\n\
 | 
			
		||||
    /* Generate CSV rows */
 | 
			
		||||
    postMessage({state: "csv"});
 | 
			
		||||
    const strm = sheet_to_csv_cb(ws, (csv) => {
 | 
			
		||||
      if(csv != null) postMessage({csv});
 | 
			
		||||
      else postMessage({state: "done"});
 | 
			
		||||
    });
 | 
			
		||||
    strm.resume();
 | 
			
		||||
  } catch(e) {
 | 
			
		||||
    /* Pass the error message back */
 | 
			
		||||
    postMessage({error: String(e.message || e) });
 | 
			
		||||
  }
 | 
			
		||||
}, false);`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
The main thread will receive messages with CSV rows for further processing:
 | 
			
		||||
 | 
			
		||||
```js title="main.js"
 | 
			
		||||
worker.onmessage = function(e) {
 | 
			
		||||
  if(e.data.error) { console.error(e.data.error); /* show an error message */ }
 | 
			
		||||
  else if(e.data.state) { console.info(e.data.state); /* current state */ }
 | 
			
		||||
  else {
 | 
			
		||||
    /* e.data.csv is the row generated by the stream */
 | 
			
		||||
    console.log(e.data.csv);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
### Live Demo
 | 
			
		||||
 | 
			
		||||
The following live demo fetches and parses a file in a Web Worker.  The `to_csv`
 | 
			
		||||
streaming function is used to generate CSV rows and pass back to the main thread
 | 
			
		||||
@ -231,117 +403,13 @@ self.addEventListener('message', async(e) => {
 | 
			
		||||
}`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
NodeJS streaming APIs are not available in the browser.  The following function
 | 
			
		||||
supplies a pseudo stream object compatible with the `to_csv` function:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
function sheet_to_csv_cb(ws, cb, opts, batch = 1000) {
 | 
			
		||||
  XLSX.stream.set_readable(() => ({
 | 
			
		||||
    __done: false,
 | 
			
		||||
    // this function will be assigned by the SheetJS stream methods
 | 
			
		||||
    _read: function() { this.__done = true; },
 | 
			
		||||
    // this function is called by the stream methods
 | 
			
		||||
    push: function(d) { if(!this.__done) cb(d); if(d == null) this.__done = true; },
 | 
			
		||||
    resume: function pump() { for(var i = 0; i < batch && !this.__done; ++i) this._read(); if(!this.__done) setTimeout(pump.bind(this), 0); }
 | 
			
		||||
  }));
 | 
			
		||||
  return XLSX.stream.to_csv(ws, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// assuming `workbook` is a workbook, stream the first sheet
 | 
			
		||||
const ws = workbook.Sheets[workbook.SheetNames[0]];
 | 
			
		||||
const strm = sheet_to_csv_cb(ws, (csv)=>{ if(csv != null) console.log(csv); });
 | 
			
		||||
strm.resume();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Web Workers
 | 
			
		||||
 | 
			
		||||
For processing large files in the browser, it is strongly encouraged to use Web
 | 
			
		||||
Workers. The [Worker demo](/docs/demos/bigdata/worker#streaming-write) includes
 | 
			
		||||
examples using the File System Access API.
 | 
			
		||||
 | 
			
		||||
Typically, the file and stream processing occurs in the Web Worker.  CSV rows
 | 
			
		||||
can be sent back to the main thread in the callback:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="js" title="worker.js">{`\
 | 
			
		||||
/* load standalone script from CDN */
 | 
			
		||||
importScripts("https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js");
 | 
			
		||||
\n\
 | 
			
		||||
function sheet_to_csv_cb(ws, cb, opts, batch = 1000) {
 | 
			
		||||
  XLSX.stream.set_readable(() => ({
 | 
			
		||||
    __done: false,
 | 
			
		||||
    // this function will be assigned by the SheetJS stream methods
 | 
			
		||||
    _read: function() { this.__done = true; },
 | 
			
		||||
    // this function is called by the stream methods
 | 
			
		||||
    push: function(d) { if(!this.__done) cb(d); if(d == null) this.__done = true; },
 | 
			
		||||
    resume: function pump() { for(var i = 0; i < batch && !this.__done; ++i) this._read(); if(!this.__done) setTimeout(pump.bind(this), 0); }
 | 
			
		||||
  }));
 | 
			
		||||
  return XLSX.stream.to_csv(ws, opts);
 | 
			
		||||
}
 | 
			
		||||
\n\
 | 
			
		||||
/* this callback will run once the main context sends a message */
 | 
			
		||||
self.addEventListener('message', async(e) => {
 | 
			
		||||
  try {
 | 
			
		||||
    postMessage({state: "fetching " + e.data.url});
 | 
			
		||||
    /* Fetch file */
 | 
			
		||||
    const res = await fetch(e.data.url);
 | 
			
		||||
    const ab = await res.arrayBuffer();
 | 
			
		||||
\n\
 | 
			
		||||
    /* Parse file */
 | 
			
		||||
    postMessage({state: "parsing"});
 | 
			
		||||
    const wb = XLSX.read(ab, {dense: true});
 | 
			
		||||
    const ws = wb.Sheets[wb.SheetNames[0]];
 | 
			
		||||
\n\
 | 
			
		||||
    /* Generate CSV rows */
 | 
			
		||||
    postMessage({state: "csv"});
 | 
			
		||||
    const strm = sheet_to_csv_cb(ws, (csv) => {
 | 
			
		||||
      if(csv != null) postMessage({csv});
 | 
			
		||||
      else postMessage({state: "done"});
 | 
			
		||||
    });
 | 
			
		||||
    strm.resume();
 | 
			
		||||
  } catch(e) {
 | 
			
		||||
    /* Pass the error message back */
 | 
			
		||||
    postMessage({error: String(e.message || e) });
 | 
			
		||||
  }
 | 
			
		||||
}, false);`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
The main thread will receive messages with CSV rows for further processing:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
worker.onmessage = function(e) {
 | 
			
		||||
  if(e.data.error) { console.error(e.data.error); /* show an error message */ }
 | 
			
		||||
  else if(e.data.state) { console.info(e.data.state); /* current state */ }
 | 
			
		||||
  else {
 | 
			
		||||
    /* e.data.csv is the row generated by the stream */
 | 
			
		||||
    console.log(e.data.csv);
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Deno
 | 
			
		||||
 | 
			
		||||
Deno does not support NodeJS streams in normal execution, so a wrapper is used.
 | 
			
		||||
This example fetches <https://sheetjs.com/pres.numbers> and prints CSV rows:
 | 
			
		||||
Deno does not support NodeJS streams in normal execution, so a wrapper is used:
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="ts" title="sheet2csv.ts">{`\
 | 
			
		||||
<CodeBlock language="ts">{`\
 | 
			
		||||
// @deno-types="https://cdn.sheetjs.com/xlsx-${current}/package/types/index.d.ts"
 | 
			
		||||
import { stream, Sheet2CSVOpts, WorkSheet } from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs';
 | 
			
		||||
\n\
 | 
			
		||||
interface Resumable { resume:()=>void; };
 | 
			
		||||
/* Generate row strings from a worksheet */
 | 
			
		||||
function sheet_to_csv_cb(ws: WorkSheet, cb:(d:string|null)=>void, opts: Sheet2CSVOpts = {}, batch = 1000): Resumable {
 | 
			
		||||
  stream.set_readable(() => ({
 | 
			
		||||
    __done: false,
 | 
			
		||||
    // this function will be assigned by the SheetJS stream methods
 | 
			
		||||
    _read: function() { this.__done = true; },
 | 
			
		||||
    // this function is called by the stream methods
 | 
			
		||||
    push: function(d: any) { if(!this.__done) cb(d); if(d == null) this.__done = true; },
 | 
			
		||||
    resume: function pump() { for(var i = 0; i < batch && !this.__done; ++i) this._read(); if(!this.__done) setTimeout(pump.bind(this), 0); }
 | 
			
		||||
  }));
 | 
			
		||||
  return stream.to_csv(ws, opts) as Resumable;
 | 
			
		||||
}
 | 
			
		||||
import { stream } from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs';
 | 
			
		||||
\n\
 | 
			
		||||
/* Callback invoked on each row (string) and at the end (null) */
 | 
			
		||||
const csv_cb = (d:string|null) => {
 | 
			
		||||
@ -350,12 +418,37 @@ const csv_cb = (d:string|null) => {
 | 
			
		||||
  Deno.stdout.write(new TextEncoder().encode(d));
 | 
			
		||||
};
 | 
			
		||||
\n\
 | 
			
		||||
/* Fetch https://sheetjs.com/pres.numbers, parse, and get first worksheet */
 | 
			
		||||
import { read } from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs';
 | 
			
		||||
const ab = await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer();
 | 
			
		||||
const wb = read(ab, { dense: true });
 | 
			
		||||
const ws = wb.Sheets[wb.SheetNames[0]];
 | 
			
		||||
/* Prepare \`Readable\` function */
 | 
			
		||||
const Readable = () => ({
 | 
			
		||||
  __done: false,
 | 
			
		||||
  // this function will be assigned by the SheetJS stream methods
 | 
			
		||||
  _read: function() { this.__done = true; },
 | 
			
		||||
  // this function is called by the stream methods
 | 
			
		||||
  push: function(d: any) {
 | 
			
		||||
    if(!this.__done) csv_cb(d);
 | 
			
		||||
    if(d == null) this.__done = true;
 | 
			
		||||
  },
 | 
			
		||||
  resume: function pump() {
 | 
			
		||||
    for(var i = 0; i < 1000 && !this.__done; ++i) this._read();
 | 
			
		||||
    if(!this.__done) setTimeout(pump.bind(this), 0);
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
/* Wire up */
 | 
			
		||||
stream.set_readable(Readable);
 | 
			
		||||
\n\
 | 
			
		||||
/* Create and start CSV stream */
 | 
			
		||||
sheet_to_csv_cb(ws, csv_cb).resume();`}
 | 
			
		||||
/* assuming \`workbook\` is a workbook, stream the first sheet */
 | 
			
		||||
const ws = workbook.Sheets[workbook.SheetNames[0]];
 | 
			
		||||
stream.to_csv(wb.Sheets[wb.SheetNames[0]]).resume();`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
This demo was last tested on 2023 May 30
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
[`SheetJSDenoStream.ts`](pathname:///stream/SheetJSDenoStream.ts) is a small
 | 
			
		||||
example script that downloads <https://sheetjs.com/pres.numbers> and prints
 | 
			
		||||
CSV row objects.
 | 
			
		||||
 | 
			
		||||
1) Run `deno run -A https://docs.sheetjs.com/stream/SheetJSDenoStream.ts`
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										283
									
								
								docz/docs/03-demos/12-engines/09_hermes.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										283
									
								
								docz/docs/03-demos/12-engines/09_hermes.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,283 @@
 | 
			
		||||
---
 | 
			
		||||
title: C++ + Hermes
 | 
			
		||||
pagination_prev: demos/bigdata/index
 | 
			
		||||
pagination_next: solutions/input
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
import current from '/version.js';
 | 
			
		||||
import CodeBlock from '@theme/CodeBlock';
 | 
			
		||||
 | 
			
		||||
Hermes is an embeddable JS engine written in C++. With some light shims, it can
 | 
			
		||||
run the standalone browser scripts.
 | 
			
		||||
 | 
			
		||||
The [Standalone scripts](/docs/getting-started/installation/standalone) can be
 | 
			
		||||
parsed and evaluated in a Hermes context.
 | 
			
		||||
 | 
			
		||||
:::caution Here be Dragons
 | 
			
		||||
 | 
			
		||||
The main target for Hermes is React Native.  At the time of writing, there was
 | 
			
		||||
no official documentation for embedding the Hermes engine in C++ programs.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
## Integration Details
 | 
			
		||||
 | 
			
		||||
_Initialize Hermes_
 | 
			
		||||
 | 
			
		||||
The runtime can be initialized in one line:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
std::unique_ptr<facebook::jsi::Runtime> rt(facebook::hermes::makeHermesRuntime());
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Hermes does not expose a `console` or `global` variable, but those can be
 | 
			
		||||
synthesized from JS code in the runtime:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
auto src = std::make_shared<facebook::jsi::StringBuffer>(
 | 
			
		||||
  /* create global object */
 | 
			
		||||
  "var global = (function(){ return this; }).call(null);"
 | 
			
		||||
  /* create a fake `console` from the hermes `print` builtin */
 | 
			
		||||
  "var console = { log: function(x) { print(x); } };"
 | 
			
		||||
);
 | 
			
		||||
auto js = rt->prepareJavaScript(src, std::string("<eval>"));
 | 
			
		||||
rt->evaluatePreparedJavaScript(js);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
_Load SheetJS Scripts_
 | 
			
		||||
 | 
			
		||||
The main library can be loaded by reading the script from the file system and
 | 
			
		||||
evaluating in the Hermes context:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
static char *read_file(const char *filename, size_t *sz) {
 | 
			
		||||
  FILE *f = fopen(filename, "rb");
 | 
			
		||||
  if(!f) return NULL;
 | 
			
		||||
  long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); }
 | 
			
		||||
  char *buf = (char *)malloc(fsize * sizeof(char));
 | 
			
		||||
  *sz = fread((void *) buf, 1, fsize, f);
 | 
			
		||||
  fclose(f);
 | 
			
		||||
  return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Unfortunately the library provides no C-friendly Buffer classes */
 | 
			
		||||
class CBuffer : public facebook::jsi::Buffer {
 | 
			
		||||
  public:
 | 
			
		||||
    CBuffer(const uint8_t *data, size_t size) : buf(data), sz(size) {}
 | 
			
		||||
    size_t size() const override { return sz; }
 | 
			
		||||
    const uint8_t *data() const override { return buf; }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    const uint8_t *buf;
 | 
			
		||||
    size_t sz;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// ...
 | 
			
		||||
  /* load SheetJS library */
 | 
			
		||||
  size_t sz; char *xlsx_full_min_js = read_file("xlsx.full.min.js", &sz);
 | 
			
		||||
  auto src = std::make_shared<CBuffer>(CBuffer((uint8_t *)xlsx_full_min_js, sz));
 | 
			
		||||
  auto js = rt->prepareJavaScript(src, std::string("xlsx.full.min.js"));
 | 
			
		||||
  rt->evaluatePreparedJavaScript(js);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To confirm the library is loaded, `XLSX.version` can be printed to the console:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
auto src = std::make_shared<facebook::jsi::StringBuffer>(
 | 
			
		||||
  "console.log('SheetJS Library Version: ' + XLSX.version)"
 | 
			
		||||
);
 | 
			
		||||
auto js = rt->prepareJavaScript(src, std::string("<eval>"));
 | 
			
		||||
rt->evaluatePreparedJavaScript(js);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Reading Files
 | 
			
		||||
 | 
			
		||||
Hermes supports `ArrayBuffer` but has no simple helper to read raw memory.
 | 
			
		||||
Libraries are expected to implement `MutableBuffer`:
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
/* ArrayBuffer constructor expects MutableBuffer*/
 | 
			
		||||
class CMutableBuffer : public facebook::jsi::MutableBuffer {
 | 
			
		||||
  public:
 | 
			
		||||
    CMutableBuffer(uint8_t *data, size_t size) : buf(data), sz(size) {}
 | 
			
		||||
    size_t size() const override { return sz; }
 | 
			
		||||
    uint8_t *data() override { return buf; }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    uint8_t *buf;
 | 
			
		||||
    size_t sz;
 | 
			
		||||
};
 | 
			
		||||
// ...
 | 
			
		||||
  /* load payload as ArrayBuffer */
 | 
			
		||||
  size_t sz; char *data = read_file(argv[1], &sz);
 | 
			
		||||
  auto payload = std::make_shared<CMutableBuffer>(CMutableBuffer((uint8_t *)data, sz));
 | 
			
		||||
  auto ab = facebook::jsi::ArrayBuffer(*rt, payload);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
It is strongly recommended to create a stub function to perform the entire
 | 
			
		||||
workflow in JS code and pass the final result back to C++.
 | 
			
		||||
 | 
			
		||||
> _JS Stub function_
 | 
			
		||||
>
 | 
			
		||||
```js
 | 
			
		||||
function(buf) {
 | 
			
		||||
  /* `buf` will be an ArrayBuffer */
 | 
			
		||||
  var wb = XLSX.read(buf);
 | 
			
		||||
  return XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
_C++ integration code_
 | 
			
		||||
 | 
			
		||||
```cpp
 | 
			
		||||
  /* define stub function to read and convert first sheet to CSV */
 | 
			
		||||
  auto src = std::make_shared<facebook::jsi::StringBuffer>(
 | 
			
		||||
    "(function(buf) {"
 | 
			
		||||
      "var wb = XLSX.read(buf);"
 | 
			
		||||
      "return XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);"
 | 
			
		||||
    "})"
 | 
			
		||||
  );
 | 
			
		||||
  auto js = rt->prepareJavaScript(src, std::string("<eval>"));
 | 
			
		||||
  auto func = rt->evaluatePreparedJavaScript(js);
 | 
			
		||||
 | 
			
		||||
  /* call stub function and capture result */
 | 
			
		||||
  auto csv = func.asObject(*rt).asFunction(*rt).call(*rt, ab);
 | 
			
		||||
 | 
			
		||||
  /* interpret as utf8 and print to stdout */
 | 
			
		||||
  std::string str = csv.getString(*rt).utf8(*rt);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## Complete Example
 | 
			
		||||
 | 
			
		||||
The "Integration Example" covers a traditional integration in a C++ application,
 | 
			
		||||
while the "CLI Test" demonstrates other concepts using the `hermes` CLI tool.
 | 
			
		||||
 | 
			
		||||
### Integration Example
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
This demo was last tested on 2023 May 30 against Hermes commit `869312f` on
 | 
			
		||||
a Intel Mac. `llvm-g++ -v` printed:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
Apple clang version 14.0.0 (clang-1400.0.29.202)
 | 
			
		||||
Target: x86_64-apple-darwin21.6.0
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
0) Make a project directory:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
mkdir sheetjs-hermes
 | 
			
		||||
cd sheetjs-hermes
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
1) Download the [`Makefile`](pathname:///hermes/Makefile):
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://docs.sheetjs.com/hermes/Makefile
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
2) Download [`sheetjs-hermes.cpp`](pathname:///hermes/sheetjs-hermes.cpp):
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
curl -LO https://docs.sheetjs.com/hermes/sheetjs-hermes.cpp
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
3) Build the library (this is the `init` target):
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
make init
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
4) Build the application:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
make sheetjs-hermes
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
5) Download the standalone script and test file:
 | 
			
		||||
 | 
			
		||||
<ul>
 | 
			
		||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
 | 
			
		||||
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
 | 
			
		||||
</ul>
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
 | 
			
		||||
curl -LO https://sheetjs.com/pres.numbers`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
6) Run the application:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
./sheetjs-hermes pres.numbers
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If successful, the program will print the library version number and the
 | 
			
		||||
contents of the first sheet as CSV rows.
 | 
			
		||||
 | 
			
		||||
### CLI Test
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
This demo was last tested on 2023 May 30 against Hermes version `0.11.0`.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
Due to limitations of the standalone binary, this demo will encode a test file
 | 
			
		||||
as a Base64 string and directly add it to an amalgamated script.
 | 
			
		||||
 | 
			
		||||
0) Install the `hermes` command line tool
 | 
			
		||||
 | 
			
		||||
1) Download the standalone script and test file:
 | 
			
		||||
 | 
			
		||||
<ul>
 | 
			
		||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
 | 
			
		||||
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
 | 
			
		||||
</ul>
 | 
			
		||||
 | 
			
		||||
<CodeBlock language="bash">{`\
 | 
			
		||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
 | 
			
		||||
curl -LO https://sheetjs.com/pres.numbers`}
 | 
			
		||||
</CodeBlock>
 | 
			
		||||
 | 
			
		||||
2) Bundle the test file and create `payload.js`:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.numbers').toString('base64') + '\";')"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
3) Create support scripts:
 | 
			
		||||
 | 
			
		||||
- `global.js` creates a `global` variable and defines a fake `console`:
 | 
			
		||||
 | 
			
		||||
```js title="global.js"
 | 
			
		||||
var global = (function(){ return this; }).call(null);
 | 
			
		||||
var console = { log: function(x) { print(x); } };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- `hermes.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`:
 | 
			
		||||
 | 
			
		||||
```js title="hermes.js"
 | 
			
		||||
var wb = XLSX.read(payload, {type:'base64'});
 | 
			
		||||
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
4) Create the amalgamation `xlsx.hermes.js`:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
cat global.js xlsx.full.min.js payload.js hermes.js > xlsx.hermes.js
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The final script defines `global` before loading the standalone library.  Once
 | 
			
		||||
ready, it will read the bundled test data and print the contents as CSV.
 | 
			
		||||
 | 
			
		||||
5) Run the script using the Hermes standalone binary:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
hermes xlsx.hermes.js
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If successful, the script will print CSV data from the test file
 | 
			
		||||
@ -104,75 +104,9 @@ This demo has been moved [to a dedicated page](/docs/demos/engines/goja).
 | 
			
		||||
 | 
			
		||||
### Hermes
 | 
			
		||||
 | 
			
		||||
Hermes is an embeddable JS engine for React Native.  The library and binary
 | 
			
		||||
distributions include a command-line tool `hermes` for running JS scripts.
 | 
			
		||||
 | 
			
		||||
The simplest way to interact with the engine is to pass Base64 strings. The make
 | 
			
		||||
target builds a very simple payload with the data.
 | 
			
		||||
 | 
			
		||||
:::note
 | 
			
		||||
 | 
			
		||||
The official release includes the `hermes` standalone tool.  While applications
 | 
			
		||||
should link against the official libraries, the standalone tool is useful for
 | 
			
		||||
verifying functionality.
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
<details><summary><b>Complete Example</b> (click to show)</summary>
 | 
			
		||||
 | 
			
		||||
Due to limitations of the standalone binary, this demo will encode a test file
 | 
			
		||||
as a Base64 string and directly add it to an amalgamated script.
 | 
			
		||||
 | 
			
		||||
0) Install the `hermes` command line tool
 | 
			
		||||
 | 
			
		||||
1) Download the standalone script, shim, and test file:
 | 
			
		||||
 | 
			
		||||
<ul>
 | 
			
		||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js`}>xlsx.full.min.js</a></li>
 | 
			
		||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js`}>shim.min.js</a></li>
 | 
			
		||||
<li><a href="https://sheetjs.com/pres.numbers">pres.numbers</a></li>
 | 
			
		||||
</ul>
 | 
			
		||||
 | 
			
		||||
2) Bundle the test file and create `payload.js`:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.numbers').toString('base64') + '\";')"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
3) Create support scripts:
 | 
			
		||||
 | 
			
		||||
- `global.js` creates a `global` variable and defines a fake `console`:
 | 
			
		||||
 | 
			
		||||
```js title="global.js"
 | 
			
		||||
var global = (function(){ return this; }).call(null);
 | 
			
		||||
var console = { log: function(x) { print(x); } };
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
- `hermes.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`:
 | 
			
		||||
 | 
			
		||||
```js title="hermes.js"
 | 
			
		||||
/* sheetjs (C) 2013-present  SheetJS -- https://sheetjs.com */
 | 
			
		||||
var wb = XLSX.read(payload, {type:'base64'});
 | 
			
		||||
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
4) Create the amalgamation `xlsx.hermes.js`:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
cat global.js xlsx.full.min.js payload.js hermes.js > xlsx.hermes.js
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The final script defines `global` before loading the standalone library.  Once
 | 
			
		||||
ready, it will read the bundled test data and print the contents as CSV.
 | 
			
		||||
 | 
			
		||||
5) Run the script using the Hermes standalone binary:
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
hermes xlsx.hermes.js
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
Hermes is an embeddable JS engine written in C++.
 | 
			
		||||
 | 
			
		||||
This demo has been moved [to a dedicated page](/docs/demos/engines/hermes).
 | 
			
		||||
 | 
			
		||||
### JavaScriptCore
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -111,6 +111,8 @@ _Miscellaneous_
 | 
			
		||||
- `to_html(sheet, opts)` streams an HTML table incrementally
 | 
			
		||||
- `to_json(sheet, opts)` streams JS objects (object-mode stream)
 | 
			
		||||
 | 
			
		||||
Streaming write functions are described in the [Streaming Write demo](/docs/demos/bigdata/stream#streaming-write).
 | 
			
		||||
 | 
			
		||||
### ESM Helpers
 | 
			
		||||
 | 
			
		||||
Due to broad inconsistencies in ESM implementations, the `mjs` build does not
 | 
			
		||||
 | 
			
		||||
@ -34,7 +34,7 @@ const config = {
 | 
			
		||||
      ({
 | 
			
		||||
        docs: {
 | 
			
		||||
          sidebarPath: require.resolve('./sidebars.js'),
 | 
			
		||||
          // editUrl: 'https://git.sheetjs.com/sheetjs/docs.sheetjs.com/src/branch/master/docz',
 | 
			
		||||
          editUrl: 'https://git.sheetjs.com/sheetjs/docs.sheetjs.com/src/branch/master/docz',
 | 
			
		||||
        },
 | 
			
		||||
        //blog: {
 | 
			
		||||
        //  showReadingTime: true,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										57
									
								
								docz/static/hermes/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										57
									
								
								docz/static/hermes/Makefile
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,57 @@
 | 
			
		||||
# Note: The official Hermes documentation includes zero guidance on embedding.
 | 
			
		||||
# Tested against commit 869312f185b73a7d7678a28f5f3216052c667e90
 | 
			
		||||
 | 
			
		||||
.PHONY: doit
 | 
			
		||||
doit: sheetjs-hermes
 | 
			
		||||
	curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js
 | 
			
		||||
	curl -LO https://sheetjs.com/pres.numbers
 | 
			
		||||
	./sheetjs-hermes pres.numbers
 | 
			
		||||
 | 
			
		||||
.PHONY: clean
 | 
			
		||||
clean:
 | 
			
		||||
	rm -f sheetjs-hermes
 | 
			
		||||
 | 
			
		||||
.PHONY: clean-all
 | 
			
		||||
clean-all: clean
 | 
			
		||||
	rm -rf build_release hermes xlsx.full.min.js pres.numbers
 | 
			
		||||
 | 
			
		||||
# This sequence was cobbled together by linking against every artifact.
 | 
			
		||||
# Some of these lines are likely extraneous
 | 
			
		||||
sheetjs-hermes: sheetjs-hermes.cpp init
 | 
			
		||||
	llvm-g++ $< -o $@ -std=gnu++17  \
 | 
			
		||||
		-Ihermes/include/ -Ihermes/API/ -Ihermes/API/jsi -Ihermes/public \
 | 
			
		||||
		-Lbuild_release/API/hermes/ -lhermesapi -lcompileJS -lsynthTrace -lsynthTraceParser -ltimerStats -ltraceInterpreter \
 | 
			
		||||
		-Lbuild_release/external/dtoa/ -ldtoa \
 | 
			
		||||
		-Lbuild_release/external/llvh/lib/Demangle/ -lLLVHDemangle \
 | 
			
		||||
		-Lbuild_release/external/llvh/lib/Support/ -lLLVHSupport \
 | 
			
		||||
		-Lbuild_release/jsi/ -ljsi \
 | 
			
		||||
		-Lbuild_release/lib/ -lhermesFrontend \
 | 
			
		||||
		-Lbuild_release/lib/ -lhermesOptimizer \
 | 
			
		||||
		-Lbuild_release/lib/ADT -lhermesADT \
 | 
			
		||||
		-Lbuild_release/lib/AST/ -lhermesAST \
 | 
			
		||||
		-Lbuild_release/lib/AST2JS/ -lhermesAST2JS \
 | 
			
		||||
		-Lbuild_release/lib/BCGen/ -lhermesBackend \
 | 
			
		||||
		-Lbuild_release/lib/BCGen/HBC/ -lhermesHBCBackend \
 | 
			
		||||
		-Lbuild_release/lib/CompilerDriver/ -lhermesCompilerDriver \
 | 
			
		||||
		-Lbuild_release/lib/ConsoleHost/ -lhermesConsoleHost \
 | 
			
		||||
		-Lbuild_release/lib/DependencyExtractor/ -lhermesDependencyExtractor \
 | 
			
		||||
		-Lbuild_release/lib/FlowParser/ -lhermesFlowParser \
 | 
			
		||||
		-Lbuild_release/lib/FrontEndDefs/ -lhermesFrontEndDefs \
 | 
			
		||||
		-Lbuild_release/lib/Inst/ -lhermesInst \
 | 
			
		||||
		-Lbuild_release/lib/InternalBytecode/ -lhermesInternalBytecode \
 | 
			
		||||
		-Lbuild_release/lib/Parser/ -lhermesParser \
 | 
			
		||||
		-Lbuild_release/lib/Platform/ -lhermesPlatform \
 | 
			
		||||
		-Lbuild_release/lib/Platform/Intl/ -lhermesBCP47Parser \
 | 
			
		||||
		-Lbuild_release/lib/Platform/Unicode/ -lhermesPlatformUnicode \
 | 
			
		||||
		-Lbuild_release/lib/Regex/ -lhermesRegex \
 | 
			
		||||
		-Lbuild_release/lib/SourceMap/ -lhermesSourceMap \
 | 
			
		||||
		-Lbuild_release/lib/Support/ -lhermesSupport \
 | 
			
		||||
		-Lbuild_release/lib/VM/ -lhermesVMRuntime \
 | 
			
		||||
		-Lbuild_release/public/hermes/Public -lhermesPublic \
 | 
			
		||||
		-Lhermes/external/flowparser/ -lflowparser-mac \
 | 
			
		||||
		-framework CoreFoundation
 | 
			
		||||
 | 
			
		||||
.PHONY: init
 | 
			
		||||
init:
 | 
			
		||||
	if [ ! -e hermes ]; then git clone https://github.com/facebook/hermes.git; cd hermes; git checkout 869312f185b73a7d7678a28f5f3216052c667e90; cd ..; fi
 | 
			
		||||
	if [ ! -e build_release ]; then cmake -S hermes -B build_release -G Ninja -DCMAKE_BUILD_TYPE=Release; cmake --build ./build_release; fi
 | 
			
		||||
							
								
								
									
										105
									
								
								docz/static/hermes/sheetjs-hermes.cpp
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										105
									
								
								docz/static/hermes/sheetjs-hermes.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,105 @@
 | 
			
		||||
/* sheetjs-hermes.cpp Copyright (c) SheetJS LLC. */
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include "hermes/hermes.h"
 | 
			
		||||
 | 
			
		||||
static char *read_file(const char *filename, size_t *sz) {
 | 
			
		||||
  FILE *f = fopen(filename, "rb");
 | 
			
		||||
  if(!f) return NULL;
 | 
			
		||||
  long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); }
 | 
			
		||||
  char *buf = (char *)malloc(fsize * sizeof(char));
 | 
			
		||||
  *sz = fread((void *) buf, 1, fsize, f);
 | 
			
		||||
  fclose(f);
 | 
			
		||||
  return buf;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Unfortunately the library provides no C-friendly Buffer classes */
 | 
			
		||||
class CBuffer : public facebook::jsi::Buffer {
 | 
			
		||||
  public:
 | 
			
		||||
    CBuffer(const uint8_t *data, size_t size) : buf(data), sz(size) {}
 | 
			
		||||
    size_t size() const override { return sz; }
 | 
			
		||||
    const uint8_t *data() const override { return buf; }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    const uint8_t *buf;
 | 
			
		||||
    size_t sz;
 | 
			
		||||
};
 | 
			
		||||
/* ArrayBuffer constructor expects MutableBuffer*/
 | 
			
		||||
class CMutableBuffer : public facebook::jsi::MutableBuffer {
 | 
			
		||||
  public:
 | 
			
		||||
    CMutableBuffer(uint8_t *data, size_t size) : buf(data), sz(size) {}
 | 
			
		||||
    size_t size() const override { return sz; }
 | 
			
		||||
    uint8_t *data() override { return buf; }
 | 
			
		||||
 | 
			
		||||
  private:
 | 
			
		||||
    uint8_t *buf;
 | 
			
		||||
    size_t sz;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int main(int argc, char **argv) {
 | 
			
		||||
  std::unique_ptr<facebook::jsi::Runtime> rt(facebook::hermes::makeHermesRuntime());
 | 
			
		||||
 | 
			
		||||
  /* setup */
 | 
			
		||||
  try {
 | 
			
		||||
    auto src = std::make_shared<facebook::jsi::StringBuffer>(
 | 
			
		||||
      "var global = (function(){ return this; }).call(null);"
 | 
			
		||||
      "var console = { log: function(x) { print(x); } };"
 | 
			
		||||
    );
 | 
			
		||||
    auto js = rt->prepareJavaScript(src, std::string("<eval>"));
 | 
			
		||||
    rt->evaluatePreparedJavaScript(js);
 | 
			
		||||
  } catch (const facebook::jsi::JSIException &e) {
 | 
			
		||||
    std::cerr << "JavaScript terminated via uncaught exception: " << e.what() << '\n';
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* load SheetJS library */
 | 
			
		||||
  try {
 | 
			
		||||
    size_t sz; char *xlsx_full_min_js = read_file("xlsx.full.min.js", &sz);
 | 
			
		||||
    auto src = std::make_shared<CBuffer>(CBuffer((uint8_t *)xlsx_full_min_js, sz));
 | 
			
		||||
    auto js = rt->prepareJavaScript(src, std::string("xlsx.full.min.js"));
 | 
			
		||||
    rt->evaluatePreparedJavaScript(js);
 | 
			
		||||
  } catch (const facebook::jsi::JSIException &e) {
 | 
			
		||||
    std::cerr << "JavaScript terminated via uncaught exception: " << e.what() << '\n';
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /* print library version */
 | 
			
		||||
  try {
 | 
			
		||||
    auto src = std::make_shared<facebook::jsi::StringBuffer>(
 | 
			
		||||
      "console.log('SheetJS Library Version: ' + XLSX.version)"
 | 
			
		||||
    );
 | 
			
		||||
    auto js = rt->prepareJavaScript(src, std::string("<eval>"));
 | 
			
		||||
    rt->evaluatePreparedJavaScript(js);
 | 
			
		||||
  } catch (const facebook::jsi::JSIException &e) {
 | 
			
		||||
    std::cerr << "JavaScript terminated via uncaught exception: " << e.what() << '\n';
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    /* load payload as ArrayBuffer */
 | 
			
		||||
    size_t sz; char *data = read_file(argv[1], &sz);
 | 
			
		||||
    auto payload = std::make_shared<CMutableBuffer>(CMutableBuffer((uint8_t *)data, sz));
 | 
			
		||||
    auto ab = facebook::jsi::ArrayBuffer(*rt, payload);
 | 
			
		||||
 | 
			
		||||
    /* define stub function to read and convert first sheet to CSV */
 | 
			
		||||
    auto src = std::make_shared<facebook::jsi::StringBuffer>(
 | 
			
		||||
      "(function(buf) {"
 | 
			
		||||
        "var wb = XLSX.read(buf);"
 | 
			
		||||
        "return XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);"
 | 
			
		||||
      "})"
 | 
			
		||||
    );
 | 
			
		||||
    auto js = rt->prepareJavaScript(src, std::string("<eval>"));
 | 
			
		||||
    auto func = rt->evaluatePreparedJavaScript(js);
 | 
			
		||||
 | 
			
		||||
    /* call stub function and capture result */
 | 
			
		||||
    auto csv = func.asObject(*rt).asFunction(*rt).call(*rt, ab);
 | 
			
		||||
 | 
			
		||||
    /* interpret as utf8 and print to stdout */
 | 
			
		||||
    std::string str = csv.getString(*rt).utf8(*rt);
 | 
			
		||||
    std::cout << str << std::endl;
 | 
			
		||||
  } catch (const facebook::jsi::JSIException &e) {
 | 
			
		||||
    std::cerr << "JavaScript terminated via uncaught exception: " << e.what() << std::endl;
 | 
			
		||||
    return 1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return 0;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								docz/static/stream/SheetJSDenoStream.ts
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										38
									
								
								docz/static/stream/SheetJSDenoStream.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
#!/usr/bin/env -S deno run --allow-net
 | 
			
		||||
// @deno-types="https://cdn.sheetjs.com/xlsx-latest/package/types/index.d.ts"
 | 
			
		||||
import { read, stream, Sheet2CSVOpts, WorkSheet } from 'https://cdn.sheetjs.com/xlsx-latest/package/xlsx.mjs';
 | 
			
		||||
 | 
			
		||||
interface Resumable { resume:()=>void; };
 | 
			
		||||
/* Generate row strings from a worksheet */
 | 
			
		||||
function sheet_to_csv_cb(ws: WorkSheet, cb:(d:string|null)=>void, opts: Sheet2CSVOpts = {}, batch = 1000): Resumable {
 | 
			
		||||
  stream.set_readable(() => ({
 | 
			
		||||
    __done: false,
 | 
			
		||||
    // this function will be assigned by the SheetJS stream methods
 | 
			
		||||
    _read: function() { this.__done = true; },
 | 
			
		||||
    // this function is called by the stream methods
 | 
			
		||||
    push: function(d: string|null) {
 | 
			
		||||
      if(!this.__done) cb(d);
 | 
			
		||||
      if(d == null) this.__done = true;
 | 
			
		||||
    },
 | 
			
		||||
    resume: function pump() {
 | 
			
		||||
      for(var i = 0; i < batch && !this.__done; ++i) this._read();
 | 
			
		||||
      if(!this.__done) setTimeout(pump.bind(this), 0);
 | 
			
		||||
    }
 | 
			
		||||
  }));
 | 
			
		||||
  return stream.to_csv(ws, opts) as Resumable;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Callback invoked on each row (string) and at the end (null) */
 | 
			
		||||
const csv_cb = (d:string|null) => {
 | 
			
		||||
  if(d == null) return;
 | 
			
		||||
  /* The strings include line endings, so raw write ops should be used */
 | 
			
		||||
  Deno.stdout.write(new TextEncoder().encode(d));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Fetch https://sheetjs.com/pres.numbers, parse, and get first worksheet */
 | 
			
		||||
const ab = await (await fetch("https://sheetjs.com/pres.numbers")).arrayBuffer();
 | 
			
		||||
const wb = read(ab, { dense: true });
 | 
			
		||||
const ws = wb.Sheets[wb.SheetNames[0]];
 | 
			
		||||
 | 
			
		||||
/* Create and start CSV stream */
 | 
			
		||||
sheet_to_csv_cb(ws, csv_cb).resume();
 | 
			
		||||
							
								
								
									
										16
									
								
								docz/static/stream/SheetJSNodeJStream.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										16
									
								
								docz/static/stream/SheetJSNodeJStream.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
/* this script works in Node 0.12 (which predated ES6) so no modern syntax */
 | 
			
		||||
var XLSX = require("xlsx"), fs = require("fs"), stream = require("stream");
 | 
			
		||||
 | 
			
		||||
var wb = XLSX.readFile(process.argv[2]);
 | 
			
		||||
var ws = wb.Sheets[wb.SheetNames[0]];
 | 
			
		||||
 | 
			
		||||
/* this Transform stream converts JS objects to text */
 | 
			
		||||
var conv = new stream.Transform({writableObjectMode:true});
 | 
			
		||||
conv._transform = function(obj, e, cb){ cb(null, JSON.stringify(obj) + "\n"); };
 | 
			
		||||
 | 
			
		||||
/* to_json -> transformer -> standard output */
 | 
			
		||||
XLSX.stream.to_json(ws, {raw: true}).pipe(conv).pipe(process.stdout);
 | 
			
		||||
 | 
			
		||||
/* to_csv -> SheetJSNodeJStream.csv */
 | 
			
		||||
var ostream = fs.createWriteStream("SheetJSNodeJStream.csv");
 | 
			
		||||
XLSX.stream.to_csv(ws).pipe(ostream);
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user