This commit is contained in:
SheetJS 2023-11-04 01:05:26 -04:00
parent 5e3369edda
commit e455737c33
14 changed files with 212 additions and 51 deletions

@ -89,9 +89,9 @@ XLSX.set_cptable(cpexcel);
For server-side scripts, `bun build` can pre-optimize dependencies. The Bun
builder requires a proper `package.json` that includes the SheetJS dependency.
:::note
:::note Tested Deployments
This example was last tested on 2023 October 21 against BunJS 1.0.6.
This example was last tested on 2023 November 05 against BunJS 1.0.8.
:::
@ -124,10 +124,14 @@ const url = "https://sheetjs.com/data/executive.json";
const raw_data = await (await fetch(url)).json();
/* filter for the Presidents */
const prez = raw_data.filter((row) => row.terms.some((term) => term.type === "prez"));
const prez = raw_data.filter(row => row.terms.some(term => term.type === "prez"));
/* sort by first presidential term */
prez.forEach(row => row.start = row.terms.find(term => term.type === "prez").start);
prez.sort((l,r) => l.start.localeCompare(r.start));
/* flatten objects */
const rows = prez.map((row) => ({
const rows = prez.map(row => ({
name: row.name.first + " " + row.name.last,
birthday: row.bio.birthday
}));

@ -7,10 +7,10 @@ pagination_next: demos/net/index
import current from '/version.js';
import CodeBlock from '@theme/CodeBlock';
:::note
:::note Tested Deployments
This demo was tested against `vue3-table-lite 1.2.4`, VueJS `3.3.4`, ViteJS
4.4.7, and `@vitejs/plugin-vue` 4.2.3 on 2023 July 27
This demo was tested against `vue3-table-lite 1.3.9`, VueJS `3.3.7` and ViteJS
`4.5.0` on 2023 November 03.
:::
@ -132,4 +132,4 @@ npm run dev
5) Load the displayed URL (typically `http://localhost:5173`) in a web browser.
When the page loads, it will try to fetch <https://sheetjs.com/pres.numbers>
and display the data
and display the data. Click "Export" to generate a workbook.

@ -185,7 +185,7 @@ export class SheetjsController {
npx @nestjs/cli start
```
:::note
:::note pass
In the most recent test, the process failed with a message referencing Multer:

@ -440,9 +440,20 @@ When this demo was last tested, Google Chrome did not add an entry to the
:::
:::note
:::note Tested Deployments
This demo was last tested on 2023 August 30 in Google Chrome.
This browser demo was tested in the following environments:
| Browser | Date |
|:------------|:-----------|
| Chrome 119 | 2023-11-04 |
Some lesser-used browsers do not support File System Access API:
| Browser | Date |
|:------------|:-----------|
| Safari 17.0 | 2023-11-04 |
| Firefox 119 | 2023-11-04 |
:::

@ -7,6 +7,8 @@ pagination_next: demos/bigdata/index
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import CodeBlock from '@theme/CodeBlock';
[Mathematica](https://mathematica.com) is a software system for mathematics and
@ -19,9 +21,9 @@ This demo uses SheetJS to pull data from a spreadsheet for further analysis
within Mathematica. We'll explore how to run an external tool to generate CSV
data from opaque spreadsheets and parse the data from Mathematica.
:::note
:::note Tested Deployments
This demo was last tested by SheetJS users on 2023 August 21 in Mathematica 13.
This demo was last tested by SheetJS users on 2023 November 04 in Mathematica 13.
:::
@ -74,6 +76,35 @@ _Complete Function_
The following function reads a file, parses the first worksheet and returns a
Dataset object assuming one header row.
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
```mathematica title="Complete Function"
(* Import file stored in the Documents folder (e.g. C:\Users\Me\Documents) *)
SheetJSImportFileEE[filename_]:=Module[{csv}, (
(* This was required in local testing *)
RegisterExternalEvaluator["NodeJS","/usr/local/bin/node"];
(* Generate CSV from first sheet *)
csv:=ExternalEvaluate["NodeJS", StringJoin[
(* module installed in home directory *)
"var XLSX = require('xlsx');",
(* read specified filename *)
"var wb = XLSX.readFile('",filename,"');",
(* grab first worksheet *)
"var ws = wb.Sheets[wb.SheetNames[0]];",
(* convert to CSV *)
"XLSX.utils.sheet_to_csv(ws)"
]];
(* Parse CSV into a dataset *)
Return[ImportString[csv, "Dataset", "HeaderLines"->1]];
)]
```
</TabItem>
<TabItem value="win" label="Windows">
```mathematica title="Complete Function"
(* Import file stored in the Documents folder (e.g. C:\Users\Me\Documents) *)
SheetJSImportFileEE[filename_]:=Module[{csv}, (
@ -93,19 +124,22 @@ SheetJSImportFileEE[filename_]:=Module[{csv}, (
]];
(* Parse CSV into a dataset *)
ImportString[csv, "Dataset", "HeaderLines"->1];
Return[ImportString[csv, "Dataset", "HeaderLines"->1]];
)]
```
</TabItem>
</Tabs>
<details open><summary><b>How to run the example</b> (click to hide)</summary>
:::note
:::note Tested Deployments
This example was last tested on 2023 September 13 with Mathematica 13.3.
This example was last tested on 2023 November 04 with Mathematica 13.3.
:::
0) Install NodeJS. When the demo was tested, version `18.14.1` was installed.
0) Install NodeJS. When the demo was tested, version `20.9.0` was installed.
1) Install dependencies in the Home folder (`~` or `$HOME` or `%HOMEPATH%`):
@ -116,11 +150,25 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz zeromq@
2) Open a new Mathematica Notebook and register NodeJS. When the example was
tested in Windows, the commands were:
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
```mathematica
RegisterExternalEvaluator["NodeJS","/usr/local/bin/node"]
FindExternalEvaluators["NodeJS"]
```
</TabItem>
<TabItem value="win" label="Windows">
```mathematica
RegisterExternalEvaluator["NodeJS","C:\\Program Files\\nodejs\\node.exe"]
FindExternalEvaluators["NodeJS"]
```
</TabItem>
</Tabs>
The second argument to `RegisterExternalEvaluator` should be the path to the
`node` or `node.exe` binary.
@ -143,6 +191,8 @@ to the base folder as shown in the previous step.
SheetJSImportFileEE["pres.numbers"]
```
![SheetJSImportFileEE result](pathname:///mathematica/SheetJSImportFileEE.png)
</details>
### Command-Line Tools
@ -183,21 +233,17 @@ flowchart LR
## Complete Demo
:::info pass
This demo was tested in macOS. The path names will differ in other platforms.
:::
1) Create the standalone `xlsx-cli` binary[^14]:
<CodeBlock language="bash">{`\
cd /tmp
npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz exit-on-epipe commander@2
curl -LO https://docs.sheetjs.com/cli/xlsx-cli.js
npx nexe -t 14.15.3 xlsx-cli.js`}
</CodeBlock>
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
2) Move the generated `xlsx-cli` to a fixed location in `/usr/local/bin`:
```bash
@ -205,6 +251,20 @@ mkdir -p /usr/local/bin
mv xlsx-cli /usr/local/bin/
```
</TabItem>
<TabItem value="win" label="Windows">
2) Find the current directory:
```bash
cd
```
The generated binary will be `xlsx-cli.exe` in the displayed path.
</TabItem>
</Tabs>
### Reading a Local File
3) In a new Mathematica notebook, run the following snippet:
@ -212,10 +272,34 @@ mv xlsx-cli /usr/local/bin/
```mathematica
SheetJSImportFile[x_] := ImportString[Block[{Print}, ExternalEvaluate[
"Shell" -> "StandardOutput",
// highlight-next-line
"/usr/local/bin/xlsx-cli " <> x
]], "Dataset", "HeaderLines" -> 1]
```
<Tabs groupId="os">
<TabItem value="unix" label="Linux/MacOS">
</TabItem>
<TabItem value="win" label="Windows">
Change `/usr/local/bin/xlsx-cli` in the string to the path to the generated
`xlsx-cli.exe` binary. For example, if the path in step 2 was
`C:\Users\Me\Documents\`, then the code should be:
```mathematica
SheetJSImportFile[x_] := ImportString[Block[{Print}, ExternalEvaluate[
"Shell" -> "StandardOutput",
// highlight-next-line
"C:\\Users\\Me\\Documents\\xlsx-cli.exe " <> x
]], "Dataset", "HeaderLines" -> 1]
```
The `\` characters must be doubled.
</TabItem>
</Tabs>
4) Download <https://sheetjs.com/pres.numbers> and save to Downloads folder:
```bash
@ -232,6 +316,8 @@ data = SheetJSImportFile["~/Downloads/pres.numbers"]
The result should be displayed in a concise table.
![SheetJSImportFile result](pathname:///mathematica/SheetJSImportFile.png)
### Reading from a URL
`FetchURL`[^15] downloads a file from a specified URL and returns a path to the
@ -253,6 +339,8 @@ SheetJSImportURL[x_] := Module[{path},(
data = SheetJSImportURL["https://sheetjs.com/pres.numbers"]
```
![SheetJSImportURL result](pathname:///mathematica/SheetJSImportURL.png)
[^1]: See [the `ExternalEvaluate` Node.js example](https://reference.wolfram.com/language/ref/ExternalEvaluate.html#:~:text=Evaluate%20a%20basic%20math%20function%20in%20JavaScript%20using%20Node.js%3A) in the Mathematica documentation.
[^2]: See [`RegisterExternalEvaluator`](https://reference.wolfram.com/language/ref/RegisterExternalEvaluator.html) in the Mathematica documentation.
[^3]: See [`ExternalEvaluate`](https://reference.wolfram.com/language/ref/ExternalEvaluate.html) in the Mathematica documentation.

@ -229,7 +229,7 @@ curl -LO https://docs.sheetjs.com/duk/sheetjs.duk.c
gcc -std=c99 -Wall -osheetjs.duk sheetjs.duk.c duktape.c -lm
```
:::note
:::note pass
GCC may generate a warning:

@ -356,7 +356,7 @@ while the "CLI Test" demonstrates other concepts using the `hermes` CLI tool.
### Integration Example
:::note
:::note Tested Deployments
This demo was tested in the following deployments:
@ -374,6 +374,8 @@ fork, which powers React Native for Windows, does have built-in support[^5]
|:-------------|:-----------|:-----------|
| `win10-x64` | `930456b` | 2023-10-28 |
The ["Windows Example"](#windows-example) covers `hermes-windows`.
:::
0) Install [dependencies](https://hermesengine.dev/docs/building-and-running/#dependencies)
@ -627,18 +629,56 @@ contents of the first sheet as CSV rows.
### CLI Test
:::note
:::note Tested Deployments
This demo was last tested on 2023 August 27 against Hermes version `0.11.0`.
This demo was last tested on 2023 November 04 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
#### Install CLI
1) Download the SheetJS Standalone script and the test file. Save both files in
0) Install the Hermes command line tools:
```bash
npx jsvu install hermes@0.11.0
```
When prompted, select the appropriate operating system.
1) Inspect the output of the installer. Look for "Installing binary" lines:
```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…
```
The first "Installing binary" line mentions the path to the `hermes` tool.
#### Setup Project
2) Create a new project folder:
```bash
mkdir sheetjs-hermes-cli
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 .
```
#### Create Script
4) Download the SheetJS Standalone script and the test file. Save both files in
the project directory:
<ul>
@ -651,13 +691,13 @@ 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`:
5) 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:
6) Create support scripts:
- `global.js` creates a `global` variable and defines a fake `console`:
@ -673,19 +713,21 @@ 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`:
7) Create the amalgamation `sheetjs.hermes.js`:
```bash
cat global.js xlsx.full.min.js payload.js hermes.js > xlsx.hermes.js
cat global.js xlsx.full.min.js payload.js hermes.js > sheetjs.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:
#### Testing
8) Run the script using the Hermes standalone binary:
```bash
hermes xlsx.hermes.js
./hermes-0.11.0 sheetjs.hermes.js
```
If successful, the script will print CSV data from the test file.

@ -1,5 +1,7 @@
---
title: C++ + ChakraCore
title: Sheets in ChakraCore
sidebar_label: C++ + ChakraCore
description: Process structured data in C++ programs. Seamlessly integrate spreadsheets into your program by pairing ChakraCore and SheetJS. Handle the most complex files without breaking a sweat.
pagination_prev: demos/bigdata/index
pagination_next: solutions/input
---
@ -11,12 +13,19 @@ import CodeBlock from '@theme/CodeBlock';
ChakraCore is an embeddable JS engine written in C++.
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
can be parsed and evaluated in a ChakraCore context.
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
This demo uses Hermes and SheetJS to pull data from a spreadsheet and print CSV
rows. We'll explore how to load SheetJS in a ChakraCore context and process
spreadsheets from a C++ program.
The ["Integration Example"](#integration-example) section includes a complete
command-line tool for reading data from files.
## Integration Details
_Initialize ChakraCore_
### Initialize ChakraCore
ChakraCore provides a `global` object through `JsGetGlobalObject`:
@ -47,7 +56,10 @@ example shows structured validation and controlled memory usage.
:::
_Load SheetJS Scripts_
### Load SheetJS Scripts
[SheetJS Standalone scripts](/docs/getting-started/installation/standalone) can
be parsed and evaluated in a ChakraCore context.
The main library can be loaded by reading the script from the file system and
evaluating in the ChakraCore context:
@ -114,13 +126,13 @@ while the "CLI Test" demonstrates other concepts using the `ch` CLI tool.
### Integration Example
:::note
:::note Tested Deployments
This demo was tested in the following deployments:
| Architecture | Git Commit | Date |
|:-------------|:-----------|:-----------|
| `darwin-x64` | `c3ead3f` | 2023-08-26 |
| `darwin-x64` | `c3ead3f` | 2023-11-04 |
| `darwin-arm` | `c3ead3f` | 2023-10-19 |
| `win10-x64` | `c3ead3f` | 2023-10-28 |
| `linux-x64` | `c3ead3f` | 2023-10-11 |
@ -164,7 +176,7 @@ All commands in this demo should be run in a "Native Tools Command Prompt".
1) Download ChakraCore:
```bash
git clone https://github.com/Microsoft/ChakraCore.git
git clone https://github.com/chakra-core/ChakraCore.git
cd ChakraCore
git checkout c3ead3f
cd ..
@ -364,7 +376,7 @@ If successful, the program will print the contents of the first sheet as CSV.
### CLI Test
:::note
:::note Tested Deployments
This demo was last tested on 2023-10-28 against `ch` commit `c3ead3f`.

@ -120,7 +120,7 @@ This demo was tested in the following deployments:
| Architecture | Date |
|:-------------|:-----------|
| `darwin-x64` | 2023-08-31 |
| `darwin-x64` | 2023-11-03 |
| `darwin-arm` | 2023-10-20 |
| `win10-x64` | 2023-10-28 |
| `win11-arm` | 2023-09-26 |

@ -369,4 +369,4 @@ the `w` text if available. When programmatically changing values, the `w` text
should be deleted before attempting to export. Utilities will regenerate the `w`
text from the number format (`cell.z`) and the raw value if possible.
[^1]: On 2023 September 14, [the "Review guidelines for customizing a number format" page](https://support.microsoft.com/en-us/office/review-guidelines-for-customizing-a-number-format-c0a1d1fa-d3f4-4018-96b7-9c9354dd99f5) in the Excel documentation covered custom number format minutiae.
[^1]: On 2023 November 04, [the "Review guidelines for customizing a number format" page](https://support.microsoft.com/en-us/office/review-guidelines-for-customizing-a-number-format-c0a1d1fa-d3f4-4018-96b7-9c9354dd99f5) in the Excel documentation covered custom number format minutiae.

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

@ -16,6 +16,8 @@ const sheets = ref<string[]>([]);
const workBook = ref<DataSet>({} as DataSet);
const rows = ref<Row[]>([]);
const columns = ref<Column[]>([]);
const loading = ref<boolean>(true);
const paging = ref<boolean>(true);
const exportTypes: string[] = ["xlsx", "xlsb", "csv", "html"];
@ -60,12 +62,14 @@ const makeDisplay = (col: number): RowCB => (row: Row) => `<span
};
async function importAB(ab: ArrayBuffer, name: string): Promise<void> {
loading.value = true;
const data = read(ab);
currFileName.value = name;
currSheet.value = data.SheetNames?.[0];
sheets.value = data.SheetNames;
workBook.value = data.Sheets;
loading.value = false;
selectSheet(currSheet.value);
}
@ -91,9 +95,10 @@ function selectSheet(sheet: string): void {
resetCell();
rows.value = newRows;
columns.value = newCols;
currSheet.value = sheet;
columns.value = newCols;
rows.value = newRows;
paging.value = newRows.length > 50
}
/* Download from https://sheetjs.com/pres.numbers */
@ -129,7 +134,7 @@ onMounted(async() => {
{{ sheet }}
</span>
</div>
<vue-table-lite :is-static-mode="true" :page-size="50" :columns="columns" :rows="rows"></vue-table-lite>
<vue-table-lite :is-loading="loading" :page-size="50" :columns="columns" :is-hide-paging="paging" :rows="rows"></vue-table-lite>
</template>
<style>
@ -216,4 +221,3 @@ onMounted(async() => {
color: white;
}
</style>