This commit is contained in:
SheetJS 2024-01-28 22:29:45 -05:00
parent 6e3b91f9e5
commit 4258609879
23 changed files with 922 additions and 150 deletions

21
docz/data/engines.js Normal file

@ -0,0 +1,21 @@
import { read, utils } from 'xlsx';
import url from './engines.xls';
import React, { useEffect, useState } from 'react';
const EngineData = () => {
const [engines, setEngines] = useState("");
const [binding, setBinding] = useState("");
useEffect(() => { (async() => {
const wb = read(await (await fetch(url)).arrayBuffer(), { dense: true });
setEngines(utils.sheet_to_html(wb.Sheets["Engines"]));
setBinding(utils.sheet_to_html(wb.Sheets["Bindings"]));
})(); }, []);
return ( <>
<p>The following engines have been tested in their native languages:</p>
<div dangerouslySetInnerHTML={{__html: engines}}/>
<p>The following bindings have been tested:</p>
<div dangerouslySetInnerHTML={{__html: binding}}/>
</> );
};
export default EngineData;

321
docz/data/engines.xls Normal file

@ -0,0 +1,321 @@
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowHeight>10620</WindowHeight>
<WindowWidth>11020</WindowWidth>
<WindowTopX>2260</WindowTopX>
<WindowTopY>19600</WindowTopY>
<ActiveSheet>1</ActiveSheet>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom"/>
<Borders/>
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000"/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
<Style ss:ID="s16">
<Font ss:FontName="Arial" x:Family="Swiss" ss:Size="12" ss:Color="#1C1E21"/>
</Style>
<Style ss:ID="s17">
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000"
ss:Bold="1"/>
</Style>
<Style ss:ID="s19">
<Alignment ss:Horizontal="Center" ss:Vertical="Bottom"/>
<Font ss:FontName="Calibri" x:Family="Swiss" ss:Size="12" ss:Color="#000000"
ss:Bold="1"/>
</Style>
</Styles>
<Worksheet ss:Name="Engines">
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="14" x:FullColumns="1"
x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
<Column ss:Index="3" ss:Width="24"/>
<Column ss:Width="31"/>
<Column ss:Width="24"/>
<Column ss:Width="31"/>
<Column ss:Width="24"/>
<Column ss:Width="31"/>
<Row>
<Cell ss:MergeAcross="1" ss:StyleID="s17"><Data ss:Type="String"></Data></Cell>
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">MacOS</Data></Cell>
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">Windows</Data></Cell>
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">Linux</Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="s17"><Data ss:Type="String">Engine</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">Lang</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">Duktape</Data></Cell>
<Cell><Data ss:Type="String">C</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">V8</Data></Cell>
<Cell><Data ss:Type="String">C++</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"/>
</Row>
<Row>
<Cell><Data ss:Type="String">Rhino</Data></Cell>
<Cell><Data ss:Type="String">Java</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"/>
</Row>
<Row>
<Cell><Data ss:Type="String">Jint</Data></Cell>
<Cell><Data ss:Type="String">C#</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">Goja</Data></Cell>
<Cell><Data ss:Type="String">Go</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">Nashorn</Data></Cell>
<Cell><Data ss:Type="String">Java</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"/>
</Row>
<Row>
<Cell><Data ss:Type="String">QuickJS</Data></Cell>
<Cell><Data ss:Type="String">C</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">Hermes</Data></Cell>
<Cell><Data ss:Type="String">C++</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">ChakraCore</Data></Cell>
<Cell><Data ss:Type="String">C++</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">Boa</Data></Cell>
<Cell><Data ss:Type="String">Rust</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">JE</Data></Cell>
<Cell><Data ss:Type="String">Perl</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"/>
</Row>
<Row>
<Cell><Data ss:Type="String">JerryScript</Data></Cell>
<Cell><Data ss:Type="String">C</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
<FreezePanes/>
<FrozenNoSplit/>
<SplitHorizontal>2</SplitHorizontal>
<TopRowBottomPane>2</TopRowBottomPane>
<ActivePane>2</ActivePane>
<Panes>
<Pane>
<Number>3</Number>
</Pane>
<Pane>
<Number>2</Number>
<ActiveRow>12</ActiveRow>
<ActiveCol>5</ActiveCol>
</Pane>
</Panes>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Bindings">
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="7" x:FullColumns="1"
x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
<Column ss:Index="3" ss:Width="24"/>
<Column ss:Width="31"/>
<Column ss:Width="24"/>
<Column ss:Width="31"/>
<Column ss:Width="24"/>
<Column ss:Width="31"/>
<Row>
<Cell ss:MergeAcross="1" ss:StyleID="s17"><Data ss:Type="String"></Data></Cell>
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">MacOS</Data></Cell>
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">Windows</Data></Cell>
<Cell ss:MergeAcross="1" ss:StyleID="s19"><Data ss:Type="String">Linux</Data></Cell>
</Row>
<Row>
<Cell ss:StyleID="s17"><Data ss:Type="String">Engine</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">Binding</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">x64</Data></Cell>
<Cell ss:StyleID="s17"><Data ss:Type="String">ARM</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">Duktape</Data></Cell>
<Cell><Data ss:Type="String">Perl</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"/>
</Row>
<Row>
<Cell><Data ss:Type="String">Duktape</Data></Cell>
<Cell><Data ss:Type="String">PHP</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
</Row>
<Row>
<Cell><Data ss:Type="String">V8</Data></Cell>
<Cell><Data ss:Type="String">Rust</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:Index="7" ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
<Row>
<Cell><Data ss:Type="String">V8</Data></Cell>
<Cell><Data ss:Type="String">Python</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
</Row>
<Row>
<Cell><Data ss:Type="String">JSC</Data></Cell>
<Cell><Data ss:Type="String">Swift</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
<Cell ss:StyleID="s16"/>
</Row>
<Row>
<Cell><Data ss:Type="String">ExecJS</Data></Cell>
<Cell><Data ss:Type="String">Ruby</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
</Row>
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
<Selected/>
<FreezePanes/>
<FrozenNoSplit/>
<SplitHorizontal>2</SplitHorizontal>
<TopRowBottomPane>2</TopRowBottomPane>
<ActivePane>2</ActivePane>
<Panes>
<Pane>
<Number>3</Number>
</Pane>
<Pane>
<Number>2</Number>
<ActiveRow>3</ActiveRow>
<ActiveCol>1</ActiveCol>
</Pane>
</Panes>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
</Workbook>

@ -76,8 +76,8 @@ the automation context is more efficient and strongly recommended.
## Puppeteer
Puppeteer enables headless Chromium automation for NodeJS. Releases ship with
an installer script that prepares a compatible browser version.
[Puppeteer](https://pptr.dev/) enables headless Chromium automation for NodeJS.
Releases ship with an installer script that installs a headless browser.
<Tabs>
<TabItem value="nodejs" label="NodeJS">
@ -127,16 +127,16 @@ const puppeteer = require('puppeteer');
**Demo**
:::note
:::note Tested Deployments
This demo was last tested on 2023 September 14 against Puppeteer 21.2.1.
This demo was last tested on 2024 January 27 against Puppeteer 21.9.0.
:::
1) Install SheetJS and Puppeteer:
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz puppeteer@21.2.1`}
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz puppeteer@21.9.0`}
</CodeBlock>
2) Save the `SheetJSPuppeteer.js` code snippet to `SheetJSPuppeteer.js`.
@ -202,9 +202,9 @@ await browser.close();`}
**Demo**
:::note
:::note Tested Deployments
This demo was last tested on 2023 September 14 against deno-puppeteer 16.2.0.
This demo was last tested on 2024 January 27 against deno-puppeteer 16.2.0.
:::
@ -242,9 +242,9 @@ This file can be opened with Excel.
## Playwright
Playwright presents a unified scripting framework for Chromium, WebKit, and
other browsers. It draws inspiration from Puppeteer. In fact, the example
code is almost identical!
[Playwright](https://playwright.dev/) presents a unified scripting framework for
Chromium, WebKit, and other browsers. It draws inspiration from Puppeteer. In
fact, the example code is almost identical!
Differences from the Puppeteer example are highlighted below:
@ -290,16 +290,16 @@ const { webkit } = require('playwright'); // import desired browser
**Demo**
:::note
:::note Tested Deployments
This demo was last tested on 2023 September 14 against Playwright 1.38.0.
This demo was last tested on 2024 January 27 against Playwright 1.41.1.
:::
1) Install SheetJS and Playwright:
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz playwright@1.33.0`}
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz playwright@1.41.1`}
</CodeBlock>
2) Save the `SheetJSPlaywright.js` code snippet to `SheetJSPlaywright.js`.
@ -315,7 +315,7 @@ This file can be opened with Excel.
:::caution pass
In the latest Windows 10 test, the commmand failed with a clear error message:
The commmand may fail with a message such as:
```
╔═════════════════════════════════════════════════════════════════════════╗
@ -328,13 +328,13 @@ In the latest Windows 10 test, the commmand failed with a clear error message:
╚═════════════════════════════════════════════════════════════════════════╝
```
As recommended, the command
Running the recommended command will download and install browser engines:
```bash
npx playwright install
```
will download and install the browsers.
After installing engines, re-run the script.
:::
@ -398,13 +398,13 @@ strongly recommended to add verbose logging and to lint scripts before use.
**Demo**
:::note
:::note Tested Deployments
This demo was last tested on 2023 September 14 against PhantomJS 2.1.1
:::
1) Download and unzip the PhantomJS release from the official website[^1].
1) [Download and extract PhantomJS](https://phantomjs.org/download.html)
2) Save the `SheetJSPhantom.js` code snippet to `SheetJSPhantom.js`.
@ -421,5 +421,3 @@ When the script finishes, the file `SheetJSPhantomJS.xlsb` will be created.
This file can be opened with Excel.
</details>
[^1]: Downloads available at <https://phantomjs.org/download.html>

@ -30,6 +30,27 @@ web browser. ["Browser Automation"](/docs/demos/net/headless) includes demos.
## Integration Details
Synthetic DOM implementations typically provide a function that accept a HTML
string and return an object that represents `document`. An API method such as
`getElementsByTagName` or `querySelector` can pull TABLE elements.
```mermaid
flowchart LR
subgraph Synthetic DOM Operations
html(HTML\nstring)
doc{{`document`\nDOM Object}}
end
subgraph SheetJS Operations
table{{DOM\nTable}}
wb(((SheetJS\nWorkbook)))
file(workbook\nfile)
end
html --> |Library\n\n| doc
doc --> |DOM\nAPI| table
table --> |`table_to_book`\n\n| wb
wb --> |`writeFile`\n\n| file
```
SheetJS methods use features that may be missing from some DOM implementations.
### Table rows
@ -37,8 +58,8 @@ SheetJS methods use features that may be missing from some DOM implementations.
The `rows` property of TABLE elements is a list of TR row children. This list
automatically updates when rows are added and deleted.
SheetJS does not mutate `rows`. Assuming there are no nested tables, the `rows`
property can be created using `getElementsByTagName`:
SheetJS methods do not mutate `rows`. Assuming there are no nested tables, the
`rows` property can be created using `getElementsByTagName`:
```js
tbl.rows = Array.from(tbl.getElementsByTagName("tr"));
@ -49,7 +70,7 @@ tbl.rows = Array.from(tbl.getElementsByTagName("tr"));
The `cells` property of TR elements is a list of TD cell children. This list
automatically updates when cells are added and deleted.
SheetJS does not mutate `cells`. Assuming there are no nested tables, the
SheetJS methods do not mutate `cells`. Assuming there are no nested tables, the
`cells` property can be created using `getElementsByTagName`:
```js
@ -89,14 +110,14 @@ XLSX.writeFile(workbook, "SheetJSDOM.xlsx");
:::note Tested Deployments
This demo was last tested on 2023 September 10 against JSDOM `22.1.0`
This demo was last tested on 2024 January 27 against JSDOM `24.0.0`
:::
1) Install SheetJS and JSDOM libraries:
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz jsdom@22.0.0`}
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz jsdom@24.0.0`}
</CodeBlock>
2) Save the previous codeblock to `SheetJSDOM.js`.
@ -119,7 +140,7 @@ The script will create a file `SheetJSDOM.xlsx` that can be opened.
### HappyDOM
HappyDOM provides a DOM framework for NodeJS. For the tested version (`11.0.2`),
HappyDOM provides a DOM framework for NodeJS. For the tested version (`13.3.1`),
the following patches were needed:
- TABLE `rows` property (explained above)
@ -129,14 +150,14 @@ the following patches were needed:
:::note Tested Deployments
This demo was last tested on 2023 September 10 against HappyDOM `11.0.2`
This demo was last tested on 2024 January 27 against HappyDOM `13.3.1`
:::
1) Install SheetJS and HappyDOM libraries:
<CodeBlock language="bash">{`\
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz happy-dom@11.0.2`}
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz happy-dom@13.3.1`}
</CodeBlock>
2) Download [the sample script `SheetJSHappyDOM.js`](pathname:///dom/SheetJSHappyDOM.js):
@ -145,7 +166,13 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz happy-d
curl -LO https://docs.sheetjs.com/dom/SheetJSHappyDOM.js
```
3) Run the script:
3) Download [the sample `SheetJSTable.html`](pathname:///dom/SheetJSTable.html):
```bash
curl -LO https://docs.sheetjs.com/dom/SheetJSTable.html
```
4) Run the script:
```bash
node SheetJSHappyDOM.js
@ -256,7 +283,7 @@ The script will create a file `SheetJSCheerio.xlsx` that can be opened.
### DenoDOM
[DenoDOM](https://deno.land/x/deno_dom) provides a DOM framework for Deno. For
the tested version (`0.1.38`), the following patches were needed:
the tested version (`0.1.43`), the following patches were needed:
- TABLE `rows` property (explained above)
- TR `cells` property (explained above)
@ -267,7 +294,7 @@ This example fetches [a sample table](pathname:///dom/SheetJSTable.html):
// @deno-types="https://cdn.sheetjs.com/xlsx-${current}/package/types/index.d.ts"
import * as XLSX from 'https://cdn.sheetjs.com/xlsx-${current}/package/xlsx.mjs';
\n\
import { DOMParser } from 'https://deno.land/x/deno_dom@v0.1.38/deno-dom-wasm.ts';
import { DOMParser } from 'https://deno.land/x/deno_dom@v0.1.43/deno-dom-wasm.ts';
\n\
const doc = new DOMParser().parseFromString(
await (await fetch('https://docs.sheetjs.com/dom/SheetJSTable.html')).text(),
@ -290,7 +317,7 @@ XLSX.writeFile(workbook, "SheetJSDenoDOM.xlsx");`}
:::note Tested Deployments
This demo was last tested on 2023 September 10 against DenoDOM `0.1.38`
This demo was last tested on 2024 January 27 against DenoDOM `0.1.43`
:::

@ -123,7 +123,7 @@ async function importFile() {
:::note pass
In older versions of Electron, `showOpenDialog` returned the path directly:
`showOpenDialog` originally returned an array of paths:
```js
var dialog = require('electron').remote.dialog;
@ -134,6 +134,8 @@ function importFile(workbook) {
}
```
This method was renamed to `showOpenDialogSync` in Electron 6.
:::
### Writing Files
@ -163,7 +165,7 @@ async function exportFile(workbook) {
:::note pass
In older versions of Electron, `showSaveDialog` returned the path directly:
`showSaveDialog` originally returned the selected path:
```js
var dialog = require('electron').remote.dialog;
@ -174,6 +176,8 @@ function exportFile(workbook) {
}
```
This method was renamed to `showSaveDialogSync` in Electron 6.
:::
## Complete Example
@ -188,7 +192,7 @@ This demo was tested in the following environments:
| macOS 14.1.2 | `darwin-arm` | `27.1.3` | 2023-12-01 |
| Windows 10 | `win10-x64` | `27.1.3` | 2023-12-09 |
| Windows 11 | `win11-arm` | `27.1.3` | 2023-12-01 |
| Linux (HoloOS) | `linux-x64` | `27.1.3` | 2023-12-09 |
| Linux (HoloOS) | `linux-x64` | `28.2.0` | 2024-01-26 |
| Linux (Debian) | `linux-arm` | `27.1.3` | 2023-12-01 |
:::
@ -315,25 +319,30 @@ and select `pres.numbers`.
## Electron Breaking Changes
The first version of this demo used Electron 1.7.5. The current demo includes
the required changes for Electron 27.1.3.
the required changes for Electron 28.2.0.
There are no Electron-specific workarounds in the library, but Electron broke
backwards compatibility multiple times. A summary of changes is noted below.
:::caution pass
Electron 6.x changed the `dialog` API. Methods like `showSaveDialog` originally
returned an array of strings, but now returns a `Promise`. This change was not
documented.
Electron 6 changed the return types of `dialog` API methods. The old `dialog`
methods have been renamed:
Electron 9.0.0 and later require the preference `nodeIntegration: true` in order
to `require('xlsx')` in the renderer process.
| Electron 1 - 5 | Electron 6 |
|:-----------------|:---------------------|
| `showOpenDialog` | `showOpenDialogSync` |
| `showSaveDialog` | `showSaveDialogSync` |
**This change was not properly documented!**
Electron 12.0.0 and later also require `worldSafeExecuteJavascript: true` and
Electron 9 and later require the preference `nodeIntegration: true` in order to
`require('xlsx')` in the renderer process.
Electron 12 and later also require `worldSafeExecuteJavascript: true` and
`contextIsolation: true`.
Electron 14+ must use `@electron/remote` instead of `remote`. An `initialize`
call is required to enable Developer Tools in the window.
Electron 14 and later must use `@electron/remote` instead of `remote`. An
`initialize` call is required to enable Developer Tools in the window.
:::

@ -117,7 +117,7 @@ This demo was tested in the following environments:
| macOS 14.1.2 | `darwin-arm` | `0.82.0` | 2023-12-01 |
| Windows 10 | `win10-x64` | `0.82.0` | 2023-12-09 |
| Windows 11 | `win11-arm` | `0.82.0` | 2023-12-01 |
| Linux (HoloOS) | `linux-x64` | `0.82.0` | 2023-12-07 |
| Linux (HoloOS) | `linux-x64` | `0.83.0` | 2024-01-26 |
There is no official Linux ARM64 release. The community release[^1] was tested
and verified on 2023-09-27.
@ -140,7 +140,7 @@ cd sheetjs-nwjs
"version": "0.0.0",
"main": "index.html",
"dependencies": {
"nw": "0.82.0",
"nw": "0.83.0",
"xlsx": "https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz"
}
}`}
@ -179,7 +179,7 @@ the file input element to select a spreadsheet and clicking the export button.
5) To build a standalone app, run the builder:
```bash
npx -p nw-builder nwbuild --mode=build --version=0.82.0 --glob=false --outDir=../out ./
npx -p nw-builder nwbuild --mode=build --version=0.83.0 --glob=false --outDir=../out ./
```
This will generate the standalone app in the `..\out\` folder.

@ -196,7 +196,7 @@ This demo was tested in the following environments:
| macOS 14.0 | `darwin-arm` | `v4.14.1` | `v3.12.0` | 2023-10-18 |
| Windows 10 | `win10-x64` | `v4.14.1` | `v3.12.0` | 2023-12-09 |
| Windows 11 | `win11-arm` | `v4.14.1` | `v3.12.0` | 2023-12-01 |
| Linux (HoloOS) | `linux-x64` | `v4.14.1` | `v3.12.0` | 2023-12-09 |
| Linux (HoloOS) | `linux-x64` | `v4.14.1` | `v3.12.0` | 2024-01-26 |
| Linux (Debian) | `linux-arm` | `v4.14.1` | `v3.12.0` | 2023-12-01 |
:::
@ -238,7 +238,7 @@ curl -L -o resources/js/xlsx.full.min.js https://cdn.sheetjs.com/xlsx-${current}
3) Add the highlighted line to `neutralino.config.json` in `nativeAllowList`:
```json title="neutralino.config.json"
```json title="neutralino.config.json (add highlighted line)"
"nativeAllowList": [
"app.*",
"os.*",

@ -49,37 +49,37 @@ This demo was tested in the following deployments:
<Tabs groupId="njs">
<TabItem value="nexe" label="Nexe">
| Architecture | Version | Node Target | Date |
|:-------------|:-------------|:------------|:-----------|
| `darwin-x64` | `4.0.0-rc.2` | `14.15.3` | 2023-10-10 |
| `darwin-arm` | `4.0.0-rc.2` | `18.18.0` | 2023-12-01 |
| `win10-x64` | `4.0.0-rc.2` | `14.15.3` | 2023-10-09 |
| `win11-arm` | `4.0.0-rc.2` | `20.10.0` | 2023-12-01 |
| `linux-x64` | `4.0.0-rc.2` | `14.15.3` | 2023-12-07 |
| `linux-arm` | `4.0.0-rc.2` | `20.10.0` | 2023-12-01 |
| Architecture | Version | NodeJS | Source | Date |
|:-------------|:-------------|:----------|:----------|:-----------|
| `darwin-x64` | `4.0.0-rc.2` | `14.15.3` | Pre-built | 2023-10-10 |
| `darwin-arm` | `4.0.0-rc.2` | `18.18.0` | Compiled | 2023-12-01 |
| `win10-x64` | `4.0.0-rc.2` | `14.15.3` | Pre-built | 2023-10-09 |
| `win11-arm` | `4.0.0-rc.2` | `20.10.0` | Compiled | 2023-12-01 |
| `linux-x64` | `4.0.0-rc.4` | `14.15.3` | Pre-built | 2024-01-26 |
| `linux-arm` | `4.0.0-rc.2` | `20.10.0` | Compiled | 2023-12-01 |
</TabItem>
<TabItem value="pkg" label="pkg">
| Architecture | Version | Node Target | Date |
|:-------------|:--------|:------------|:-----------|
| `darwin-x64` | `5.8.1` | `18.5.0` | 2023-10-11 |
| `darwin-arm` | `5.8.1` | `18.5.0` | 2023-12-01 |
| `win10-x64` | `5.8.1` | `18.5.0` | 2023-10-09 |
| `win11-arm` | `5.8.1` | `18.5.0` | 2023-12-01 |
| `linux-x64` | `5.8.1` | `18.5.0` | 2023-12-07 |
| `linux-arm` | `5.8.1` | `18.5.0` | 2023-12-01 |
| Architecture | Version | NodeJS | Date |
|:-------------|:--------|:---------|:-----------|
| `darwin-x64` | `5.8.1` | `18.5.0` | 2023-10-11 |
| `darwin-arm` | `5.8.1` | `18.5.0` | 2023-12-01 |
| `win10-x64` | `5.8.1` | `18.5.0` | 2023-10-09 |
| `win11-arm` | `5.8.1` | `18.5.0` | 2023-12-01 |
| `linux-x64` | `5.8.1` | `18.5.0` | 2024-01-26 |
| `linux-arm` | `5.8.1` | `18.5.0` | 2023-12-01 |
</TabItem>
<TabItem value="boxednode" label="boxednode">
| Architecture | Version | Node Target | Date |
|:-------------|:--------|:------------|:-----------|
| `darwin-x64` | `2.1.2` | `20.8.0` | 2023-10-12 |
| `darwin-arm` | `2.3.0` | `21.3.0` | 2023-12-01 |
| `win10-x64` | `2.1.2` | `16.20.2` | 2023-10-09 |
| `linux-x64` | `2.3.0` | `21.4.0` | 2023-12-07 |
| `linux-arm` | `2.3.0` | `21.3.0` | 2023-12-01 |
| Architecture | Version | NodeJS | Date |
|:-------------|:--------|:----------|:-----------|
| `darwin-x64` | `2.1.2` | `20.8.0` | 2023-10-12 |
| `darwin-arm` | `2.3.0` | `21.3.0` | 2023-12-01 |
| `win10-x64` | `2.1.2` | `16.20.2` | 2023-10-09 |
| `linux-x64` | `2.3.0` | `21.6.1` | 2024-01-26 |
| `linux-arm` | `2.3.0` | `21.3.0` | 2023-12-01 |
</TabItem>
</Tabs>
@ -309,7 +309,7 @@ This demo was last tested in the following deployments:
| `darwin-arm` | `11.8.172.13` | `0.79.2` | 2023-10-18 |
| `win10-x64` | `11.8.172.13` | `0.79.2` | 2023-10-09 |
| `win11-x64` | `11.8.172.13` | `0.79.2` | 2023-10-14 |
| `linux-x64` | `11.8.172.13` | `0.79.2` | 2023-10-11 |
| `linux-x64` | `12.0.267.8` | `0.83.1` | 2024-01-26 |
| `linux-arm` | `12.0.267.8` | `0.82.0` | 2023-12-01 |
:::

@ -26,11 +26,18 @@ This demo was verified by NetSuite consultants in the following deployments:
|:----------------|:---------------|:-----------|
| ScheduledScript | 2.1 | 2023-12-13 |
| Restlet | 2.1 | 2023-10-05 |
| Suitelet | 2.1 | 2024-01-17 |
| Suitelet | 2.1 | 2024-01-26 |
| MapReduceScript | 2.1 | 2023-12-07 |
:::
:::info pass
[See issue #3058](https://git.sheetjs.com/sheetjs/sheetjs/issues/3058) in the
issue tracker for more examples submitted by NetSuite consultants.
:::
## Installation
In SuiteScript parlance, third-party scripts are "Custom Modules"[^2].
@ -126,6 +133,19 @@ define(
### Reading Files
```mermaid
flowchart LR
subgraph NetSuite Operations
cab[(File\nCabinet)]
file(File)
base64{{Base64\nString}}
end
wb(((SheetJS\nWorkbook)))
cab --> |`load`\nN/file| file
file --> |`getContents`\nFile method| base64
base64 --> |`read`\nSheetJS| wb
```
There are three steps to reading files:
1) Pull files from the file cabinet using `file.load`[^7]. The method returns a
@ -156,6 +176,19 @@ workbook object.
### Writing Files
```mermaid
flowchart LR
wb(((SheetJS\nWorkbook)))
subgraph NetSuite Operations
base64{{Base64\nString}}
file(File)
cab[(File\nCabinet)]
end
wb --> |`write`\nSheetJS| base64
base64 --> |`create`\nN/file| file
file --> |`save`\nFile method| cab
```
There are three steps to writing files:
1) Write the data with the SheetJS `write` method[^11]. Using the `base64` output
@ -171,7 +204,7 @@ There are three steps to writing files:
var out = XLSX.write(workbook, { bookType: "xlsx", type: "base64" });
/* create file */
var newfile = file.create({
name: 'test.xlsx', // replace with desired name
name: 'SheetJSCabinetExport.xlsx', // replace with desired name
fileType: file.Type.EXCEL,
contents: out
});
@ -179,6 +212,137 @@ var newfile = file.create({
newfile.save();
```
## Sheets in Suitelet Requests
Suitelets are driven by an exported `onRequest` method[^15].
The `request` property of the argument is a `ServerRequest` object[^16]. The
`files` property of the request[^17] is an object whose values are `file` objects.
The `response` property of the argument is a `ServerResponse` object[^18]. The
`writeFile` method[^19] of the response can respond with a `file` object.
For the examples in this section, the argument will be named `context`:
```js
/**
* @NApiVersion 2.1
* @NAmdConfig ./JsLibraryConfig.json
* @NScriptType Suitelet
*/
define(['N/file', 'xlsx'], function (file, XLSX) {
function onRequest(context) {
/* ServerRequest object */
var request = context.request;
/* ServerResponse object */
var response = context.response;
// ... do work here ...
}
return { onRequest: onRequest };
});
```
### Importing Sheet Data
```mermaid
flowchart LR
subgraph NetSuite Operations
req((Suitelet\nRequest))
file(File)
base64{{Base64\nString}}
end
wb(((SheetJS\nWorkbook)))
req --> |`files`\nrequest data| file
file --> |`getContents`\nFile method| base64
base64 --> |`read`\nSheetJS| wb
```
There are three steps to importing data from Suitelet requests:
1) Pull files from the `request.files` object.[^20]. Each value in the object is
a `file.File` object which represents the file metadata.
2) Read raw data from the file using `File#getContents`[^21]. The method returns
the data as a Base64-encoded string.
3) Parse the data with the SheetJS `read` method[^22]. This method returns a
SheetJS workbook object.
```js
/* form element ID or field name */
var id_of_file = "uploaded_file"
/* get file from request */
var f = context.request.files[id_of_file];
/* read file */
var b64 = f.getContents();
/* parse */
var workbook = XLSX.read(b64, { type: "base64" });
```
At this point, standard SheetJS utility functions[^23] can extract data from the
workbook object.
:::note pass
When programmatically creating a form with `N/ui/serverWidget`, the keys of the
`files` object are determined by the `id` properties of the field.
```js
var form = serverWidget.createForm({ title: "Upload Spreadsheet" });
var field = form.addField({
// highlight-next-line
id: "uploaded_file",
label: "Choose Spreadsheet",
type: serverWidget.FieldType.FILE
});
```
Since the `id` of the file field is `uploaded_file`, the request handler can
access the file at at `context.request.files["uploaded_file"]`
:::
### Exporting Files
```mermaid
flowchart LR
wb(((SheetJS\nWorkbook)))
subgraph NetSuite Operations
base64{{Base64\nString}}
file(File)
res[(Suitelet\nResponse)]
end
wb --> |`write`\nSheetJS| base64
base64 --> |`create`\nN/file| file
file --> |`writeFile`\nResponse method| res
```
There are three steps to generating downloadable files:
1) Write the data with the SheetJS `write` method[^24]. Using the `base64` output
type[^25], the method will return a Base64 string.
2) Create a new file using `file.create`[^26]. The recommended file type is
`file.Type.EXCEL`. The method returns a `file.File` object.
3) Initiate download with `response.writeFile`[^27].
```js
/* write XLSX workbook as Base64 string */
var out = XLSX.write(workbook, { bookType: "xlsx", type: "base64" });
/* create file */
var newfile = file.create({
name: 'SheetJSSuiteletExport.xlsx', // replace with desired name
fileType: file.Type.EXCEL,
contents: out
});
/* initiate download */
context.response.writeFile(newfile);
```
[^1]: See ["SuiteScript 2.x API Introduction"](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/chapter_4387172221.html) in the NetSuite documentation.
[^2]: See ["SuiteScript 2.x Custom Modules"](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/chapter_4704097697.html) in the NetSuite documentation.
[^3]: See ["Java + Rhino" demo](/docs/demos/engines/rhino)
@ -191,5 +355,18 @@ newfile.save();
[^10]: See ["Utility Functions"](/docs/api/utilities/)
[^11]: See [`write` in "Writing Files"](/docs/api/write-options)
[^12]: See ["Supported Output Formats"](/docs/api/write-options#supported-output-formats)
[^13]: See [`file.create`](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4223861820.html) in the NetSuite documentation.
[^14]: See [`File.save()`](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4229271179.html) in the NetSuite documentation.
[^13]: See [`file.create(options)`](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4223861820.html) in the NetSuite documentation.
[^14]: See [`File.save()`](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4229271179.html) in the NetSuite documentation.
[^15]: See [`onRequest(params)`](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4407987288.html) in the NetSuite documentation.
[^16]: See [`http.ServerRequest`](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4314608702.html) in the NetSuite documentation.
[^17]: See [`ServerRequest.files`](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4314805947.html) in the NetSuite documentation.
[^18]: See [`http.ServerResponse`](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4314609319.html) in the NetSuite documentation.
[^19]: See [`ServerResponse.writeFile(options)`](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4426015540.html) in the NetSuite documentation.
[^20]: See [`ServerRequest.files`](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4314805947.html) in the NetSuite documentation.
[^21]: See [`File.getContents()`](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4229269811.html) in the NetSuite documentation.
[^22]: See [`read` in "Reading Files"](/docs/api/parse-options)
[^23]: See ["Utility Functions"](/docs/api/utilities/)
[^24]: See [`write` in "Writing Files"](/docs/api/write-options)
[^25]: See ["Supported Output Formats"](/docs/api/write-options#supported-output-formats)
[^26]: See [`file.create(options)`](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4223861820.html) in the NetSuite documentation.
[^27]: See [`ServerResponse.writeFile(options)`](https://docs.oracle.com/en/cloud/saas/netsuite/ns-online-help/section_4426015540.html) in the NetSuite documentation.

@ -134,7 +134,7 @@ This demo was tested in the following deployments:
| `darwin-arm` | `2.7.0` | 2023-10-18 |
| `win10-x64` | `2.7.0` | 2023-10-27 |
| `win11-arm` | `2.7.0` | 2023-12-01 |
| `linux-x64` | `2.7.0` | 2023-12-07 |
| `linux-x64` | `2.7.0` | 2024-01-26 |
| `linux-arm` | `2.7.0` | 2023-12-01 |
:::
@ -347,9 +347,75 @@ sequenceDiagram
Bindings exist for many languages. As these bindings require "native" code, they
may not work on every platform.
### PHP
There is no official PHP binding to the Duktape library. Instead, this demo uses
the raw `FFI` interface[^1] to the Duktape shared library.
#### PHP Demo
:::note Tested Deployments
This demo was tested in the following deployments:
| Architecture | Version | PHP Version | Date |
|:-------------|:--------|:------------|:-----------|
| `darwin-x64` | `2.7.0` | `8.3.2` | 2024-01-26 |
:::
0) Ensure `php` is installed and available on the system path.
1) Build the Duktape shared library:
```bash
curl -LO https://duktape.org/duktape-2.7.0.tar.xz
tar -xJf duktape-2.7.0.tar.xz
cd duktape-2.7.0
make -f Makefile.sharedlibrary
cd ..
```
2) Copy the shared library to the current folder. When the demo was last tested,
the file name was `libduktape.207.20700.so`:
```bash
cp duktape-*/libduktape.*.so .
```
3) Download the SheetJS Standalone script, shim script and test file. Move all
three files to the project directory:
<ul>
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js`}>shim.min.js</a></li>
<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/shim.min.js
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
curl -LO https://sheetjs.com/pres.numbers`}
</CodeBlock>
4) Download [`SheetJSDuk.php`](pathname:///duk/SheetJSDuk.php):
```bash
curl -LO https://docs.sheetjs.com/duk/SheetJSDuk.php
```
5) Run the script:
```bash
php SheetJSDuk.php pres.numbers
```
If the program succeeded, the CSV contents will be printed to console and the
file `sheetjsw.xlsb` will be created. That file can be opened with Excel.
### Perl
The Perl binding for Duktape is available as `JavaScript::Duktape` on CPAN.
The Perl binding for Duktape is available as `JavaScript::Duktape::XS` on CPAN.
The Perl binding does not have raw `Buffer` ops, so Base64 strings are used.
@ -361,17 +427,17 @@ This demo was tested in the following deployments:
| Architecture | Version | Date |
|:-------------|:--------|:-----------|
| `darwin-x64` | `2.5.0` | 2023-10-26 |
| `linux-arm` | `2.5.0` | 2023-12-01 |
| `darwin-x64` | `2.2.0` | 2024-01-26 |
| `linux-x64` | `2.2.0` | 2024-01-26 |
:::
0) Ensure `perl` and `cpan` are installed and available on the system path.
1) Install the `JavaScript::Duktape` library:
1) Install the `JavaScript::Duktape::XS` library:
```bash
cpan install JavaScript::Duktape
cpan install JavaScript::Duktape::XS
```
:::note pass
@ -379,7 +445,7 @@ cpan install JavaScript::Duktape
On some systems, the command must be run as the root user:
```bash
sudo cpan install JavaScript::Duktape
sudo cpan install JavaScript::Duktape::XS
```
:::
@ -388,12 +454,12 @@ sudo cpan install JavaScript::Duktape
```perl title="SheetJSDuk.pl"
# usage: perl SheetJSDuk.pl path/to/file
use JavaScript::Duktape;
use JavaScript::Duktape::XS;
use File::Slurp;
use MIME::Base64 qw( encode_base64 decode_base64 );
# Initialize
my $js = JavaScript::Duktape->new( max_memory => 256 * 1024 * 1024 );
my $js = JavaScript::Duktape::XS->new({ max_memory_bytes => 256 * 1024 * 1024 });
$js->eval("var global = (function(){ return this; }).call(null);");
# Load the ExtendScript build
@ -452,4 +518,6 @@ The fix is to install `File::Slurp` with `cpan`:
sudo cpan install File::Slurp
```
:::
:::
[^1]: See [Foreign Function Interface](https://www.php.net/manual/en/book.ffi.php) in the PHP documentation.

@ -30,7 +30,7 @@ covers V8 engine bindings for other programming languages.
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
can be parsed and evaluated in a V8 context.
_Initialize V8_
### Initialize V8
The official V8 `hello-world` example covers initialization and cleanup. For the
purposes of this demo, the key variables are noted below:
@ -50,7 +50,7 @@ v8::Local<v8::Value> eval_code(v8::Isolate *isolate, v8::Local<v8::Context> cont
}
```
_Load SheetJS Scripts_
### Load SheetJS Scripts
The main library can be loaded by reading the scripts from the file system and
evaluating in the V8 context:
@ -127,7 +127,7 @@ This demo was tested in the following deployments:
| `12.1.131` | `darwin-x64` | macOS 14.1 | `clang 15.0.0` | 2023-11-15 |
| `12.1.283` | `darwin-arm` | macOS 14.1.2 | `clang 15.0.0` | 2023-12-01 |
| `12.0.265` | `win10-x64` | Windows 10 | `CL 19.37.32822` | 2023-10-28 |
| `12.1.222` | `linux-x64` | HoloOS 3.5.7 | `gcc 13.1.1` | 2023-11-27 |
| `12.3.50` | `linux-x64` | HoloOS 3.5.7 | `gcc 13.1.1` | 2024-01-26 |
| `11.8.82` | `linux-arm` | Debian 12 | `gcc 12.2.0` | 2023-12-01 |
:::
@ -406,11 +406,11 @@ The recommended fix is to delete the referenced folder and re-run `gclient sync`
</Tabs>
5) Checkout the desired version. The following command pulls `12.1.283`:
5) Checkout the desired version. The following command pulls `12.3.50`:
```bash
git checkout tags/12.1.283 -b sample
git checkout tags/12.3.50 -b sample
```
:::caution pass
@ -418,14 +418,14 @@ git checkout tags/12.1.283 -b sample
The official documentation recommends:
```bash
git checkout refs/tags/12.1.283 -b sample -t
git checkout refs/tags/12.3.50 -b sample -t
```
This command failed in local testing:
```
E:\v8\v8>git checkout refs/tags/12.1.283 -b sample -t
fatal: cannot set up tracking information; starting point 'refs/tags/12.1.283' is not a branch
E:\v8\v8>git checkout refs/tags/12.3.50 -b sample -t
fatal: cannot set up tracking information; starting point 'refs/tags/12.3.50' is not a branch
```
:::
@ -473,7 +473,8 @@ warnings. The error messages included the tag `-Werror`:
1 error generated.
```
This was resolved by manually editing `out.gn/x64.release.sample/args.gn`:
This was resolved by manually editing `out.gn/x64.release.sample/args.gn`. The
option `treat_warnings_as_errors` should be set to `false`:
```ninja title="out.gn/x64.release.sample/args.gn (add to file)"
treat_warnings_as_errors = false
@ -815,7 +816,7 @@ This demo was last tested in the following deployments:
| `darwin-x64` | `0.81.0` | 2023-11-14 |
| `darwin-arm` | `0.82.0` | 2023-12-01 |
| `win10-x64` | `0.81.0` | 2023-11-14 |
| `linux-x64` | `0.81.0` | 2023-11-27 |
| `linux-x64` | `0.83.1` | 2024-01-26 |
| `linux-arm` | `0.82.0` | 2023-12-01 |
:::

@ -98,7 +98,7 @@ This demo was tested in the following deployments:
| `darwin-arm` | `873a149` | `1.21.3` | 2023-10-18 |
| `win10-x64` | `b396bb4` | `1.21.3` | 2023-10-28 |
| `win11-arm` | `b396bb4` | `1.21.1` | 2023-12-01 |
| `linux-x64` | `fc55792` | `1.21.3` | 2023-10-11 |
| `linux-x64` | `b396bb4` | `1.21.6` | 2024-01-26 |
| `linux-arm` | `b396bb4` | `1.21.4` | 2023-12-01 |
At the time of writing, Goja did not have proper version numbers. Versions are

@ -7,6 +7,8 @@ pagination_next: solutions/input
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
[Hermes](https://hermesengine.dev/) is an embeddable JS engine written in C++.
@ -26,7 +28,7 @@ command-line tool for reading data from files.
:::info pass
Many Hermes functions are not documented. The explanation was verified against
commit `49e1930`.
commit `90e2b47`.
:::
@ -106,7 +108,7 @@ be parsed and evaluated in a Hermes context.
The main library can be loaded by reading the script from the file system and
evaluating in the Hermes context.
:::tip pass
:::note pass
There are nonstandard tricks to embed the entire script in the binary. There are
language proposals such as `#embed` (mirroring the same feature in C23).
@ -364,7 +366,7 @@ This demo was tested in the following deployments:
|:-------------|:-----------|:-----------|
| `darwin-x64` | `84732b3` | 2023-11-14 |
| `darwin-arm` | `2b4f949` | 2023-10-18 |
| `linux-x64` | `2b4f949` | 2023-10-11 |
| `linux-x64` | `90e2b47` | 2024-01-26 |
| `linux-arm` | `84732b3` | 2023-12-01 |
The main Hermes source tree does not have Windows support. The `hermes-windows`
@ -480,7 +482,28 @@ curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
curl -LO https://sheetjs.com/pres.numbers`}
</CodeBlock>
7) Run the application:
7) Copy the `libhermes` and `libjsi` libraries into the current folder:
<Tabs groupId="os">
<TabItem value="linux" label="Linux">
```bash
cp ./build_release/API/hermes/libhermes.so .
cp ./build_release/jsi/libjsi.so .
```
</TabItem>
<TabItem value="darwin" label="MacOS">
```bash
cp ./build_release/API/hermes/libhermes.dylib .
cp ./build_release/jsi/libjsi.dylib .
```
</TabItem>
</Tabs>
8) Run the application:
```bash
./sheetjs-hermes pres.numbers
@ -663,7 +686,7 @@ contents of the first sheet as CSV rows.
:::note Tested Deployments
This demo was last tested on 2023 November 04 against Hermes version `0.11.0`.
This demo was last tested on 2023 November 04 against Hermes version `0.12.0`.
:::
@ -675,7 +698,7 @@ as a Base64 string and directly add it to an amalgamated script.
0) Install the Hermes command line tools:
```bash
npx jsvu install hermes@0.11.0
npx jsvu hermes@0.12.0
```
When prompted, select the appropriate operating system.
@ -685,10 +708,10 @@ When prompted, select the appropriate operating system.
```text pass
Extracting…
// highlight-next-line
Installing binary to ~/.jsvu/engines/hermes-0.11.0/hermes-0.11.0…
Installing symlink at ~/.jsvu/bin/hermes-0.11.0 pointing to ~/.jsvu/engines/hermes-0.11.0/hermes-0.11.0…
Installing binary to ~/.jsvu/engines/hermes-0.11.0/hermes-0.11.0-compiler…
Installing symlink at ~/.jsvu/bin/hermes-0.11.0-compiler pointing to ~/.jsvu/engines/hermes-0.11.0/hermes-0.11.0-compiler…
Installing binary to ~/.jsvu/engines/hermes-0.12.0/hermes-0.12.0…
Installing symlink at ~/.jsvu/bin/hermes-0.12.0 pointing to ~/.jsvu/engines/hermes-0.12.0/hermes-0.12.0…
Installing binary to ~/.jsvu/engines/hermes-0.12.0/hermes-0.12.0-compiler…
Installing symlink at ~/.jsvu/bin/hermes-0.12.0-compiler pointing to ~/.jsvu/engines/hermes-0.12.0/hermes-0.12.0-compiler…
```
The first "Installing binary" line mentions the path to the `hermes` tool.
@ -705,7 +728,7 @@ cd sheetjs-hermes-cli
3) Copy the binary from Step 1 into the current folder. For example, on macOS:
```bash
cp ~/.jsvu/engines/hermes-0.11.0/hermes-0.11.0 .
cp ~/.jsvu/engines/hermes-0.12.0/hermes-0.12.0 .
```
#### Create Script
@ -759,7 +782,7 @@ ready, it will read the bundled test data and print the contents as CSV.
8) Run the script using the Hermes standalone binary:
```bash
./hermes-0.11.0 sheetjs.hermes.js
./hermes-0.12.0 sheetjs.hermes.js
```
If successful, the script will print CSV data from the test file.

@ -74,7 +74,7 @@ This demo was tested in the following deployments:
| `darwin-arm` | `2.6.10` | `2.9.1` | 2023-12-01 |
| `win10-x64` | `3.2.2` | `2.9.1` | 2023-10-28 |
| `win11-arm` | `3.0.2` | `2.9.1` | 2023-12-01 |
| `linux-x64` | `3.0.4` | `2.9.1` | 2023-10-11 |
| `linux-x64` | `3.0.5` | `2.9.1` | 2024-01-26 |
| `linux-arm` | `2.7.4` | `2.9.1` | 2023-12-01 |
**Note: The Windows 11 ARM64 test used the Ruby version that ships with WSL.**

@ -135,7 +135,7 @@ This demo was tested in the following deployments:
| `darwin-x64` | `c3ead3f` | 2023-11-04 |
| `darwin-arm` | `c3ead3f` | 2023-10-19 |
| `win10-x64` | `c3ead3f` | 2023-10-28 |
| `linux-x64` | `c3ead3f` | 2023-12-09 |
| `linux-x64` | `c3ead3f` | 2024-01-26 |
:::

@ -124,7 +124,7 @@ This demo was tested in the following deployments:
| `darwin-arm` | 2023-10-20 |
| `win10-x64` | 2023-10-28 |
| `win11-arm` | 2023-12-01 |
| `linux-x64` | 2023-12-07 |
| `linux-x64` | 2024-01-26 |
| `linux-arm` | 2023-12-01 |
:::

@ -40,13 +40,11 @@ This demo was tested in the following environments:
| `darwin-arm` | `ef4cb2b` | 2023-12-08 |
| `win11-x64` | `ef4cb2b` | 2023-12-08 |
| `win11-arm` | `ef4cb2b` | 2023-12-08 |
| `linux-x64` | `ef4cb2b` | 2023-12-08 |
| `linux-x64` | `514fa67` | 2024-01-26 |
| `linux-arm` | `ef4cb2b` | 2023-12-08 |
The Windows tests were run in WSL.
Debian and WSL require the `cmake`, `python3` and `python-is-python3` packages.
:::
## Integration Details
@ -343,6 +341,14 @@ while the "CLI Test" demonstrates other concepts using the `jerry` CLI tool.
### Integration Example
<details><summary><b>Build Dependencies</b> (click to show)</summary>
The JerryScript build system requires `cmake`.
Debian and WSL additionally require `python3` and `python-is-python3` packages.
</details>
1) Create a project folder:
```bash
@ -384,7 +390,7 @@ curl -LO https://docs.sheetjs.com/jerryscript/sheetjs.jerry.c
5) Build the sample application:
```bash
gcc -o sheetjs.jerry -Ijerryscript/jerry-ext/include -Ijerryscript/jerry-math/include -Ijerryscript/jerry-core/include -ljerry-ext -ljerry-port -ljerry-core -Ljerryscript/build/lib sheetjs.jerry.c -Wno-pointer-sign
gcc -o sheetjs.jerry -Ijerryscript/jerry-ext/include -Ijerryscript/jerry-math/include -Ijerryscript/jerry-core/include sheetjs.jerry.c -ljerry-core -ljerry-ext -ljerry-port -lm -Ljerryscript/build/lib -Wno-pointer-sign
```
6) Run the test program: