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