The following engines have been tested in their native languages:
-
-
The following bindings have been tested:
-
-
Asterisks (✱) in the Windows columns mark tests that were run in Windows Subsystem for Linux (WSL)
- > );
+ return ( );
};
export default EngineData;
\ No newline at end of file
diff --git a/docz/data/engines.xls b/docz/data/engines.xls
index 3fe2df7..4727094 100644
--- a/docz/data/engines.xls
+++ b/docz/data/engines.xls
@@ -244,7 +244,7 @@
-
+
@@ -337,6 +337,16 @@
✔✔
+
+ V8
+ Python
+
+ ✔
+
+
+
+
+ JSCSwift
diff --git a/docz/docs/02-getting-started/01-installation/04-amd.md b/docz/docs/02-getting-started/01-installation/04-amd.md
index 4fc5e93..44c77c3 100644
--- a/docz/docs/02-getting-started/01-installation/04-amd.md
+++ b/docz/docs/02-getting-started/01-installation/04-amd.md
@@ -134,9 +134,31 @@ sap.ui.define([
"path/to/xlsx.full.min"
], function(/* ... variables for the other libraries ... */, XLSX) {
// use XLSX here
-})
+});
```
+:::caution pass
+
+In some deployments, the function argument was `undefined`.
+
+The standalone scripts add `window.XLSX`, so it is recommended to use `_XLSX`
+in the function arguments and access the library with `XLSX` in the callback:
+
+```js
+sap.ui.define([
+ /* ... other libraries ... */
+ "path/to/xlsx.full.min"
+], function(
+ /* ... variables for the other libraries ... */,
+ _XLSX // !! NOTE: this is not XLSX! A different variable name must be used
+) {
+ // highlight-next-line
+ alert(XLSX.version); // use XLSX in the callback
+});
+```
+
+:::
+
:::danger pass
**Copy and pasting code does not work** for SheetJS scripts as they contain
diff --git a/docz/docs/03-demos/02-frontend/09-blazor.md b/docz/docs/03-demos/02-frontend/09-blazor.md
index c5b1a30..10f9701 100644
--- a/docz/docs/03-demos/02-frontend/09-blazor.md
+++ b/docz/docs/03-demos/02-frontend/09-blazor.md
@@ -59,7 +59,7 @@ can be loaded in the root HTML page (typically `wwwroot/index.html`):
#### ECMAScript Module
The SheetJS ECMAScript module script can be dynamically imported from functions.
-This ensures the library is only loaded when necessary. The following example
+This ensures the library is only loaded when necessary. The following JS example
loads the library and returns a Promise that resolves to the version string:
{`\
@@ -75,6 +75,22 @@ async function sheetjs_version(id) {
### Calling JS from C#
+Callbacks for events in Razor elements invoke C# methods. The C# methods can use
+Blazor APIs to invoke JS methods that are visible in the browser global scope.
+
+```mermaid
+sequenceDiagram
+ actor U as User
+ participant P as Browser
+ participant A as Blazor
+ U-->>P: click button
+ P-->>A: click event
+ Note over A: C#35; callback
InvokeVoidAsync
+ A->>P: call JS function
+ Note over P: global method
SheetJS logic
+ P->>U: download workbook
+```
+
#### Setup
The primary mechanism for invoking JS functions from Blazor is `IJSRuntime`[^1].
@@ -88,7 +104,9 @@ It should be injected at the top of relevant Razor component scripts:
When exporting a file with the SheetJS `writeFile` method[^2], browser APIs do
not provide success or error feedback. As a result, this demo invokes functions
-using the `InvokeVoidAsync` static method[^3]:
+using the `InvokeVoidAsync` static method[^3].
+
+The following C# method will invoke the `export_method` method in the browser:
```csharp title="Invoking JS functions from C#"
private async Task ExportDataset() {
@@ -96,7 +114,54 @@ private async Task ExportDataset() {
}
```
-Methods are commonly bound to buttons in the Razor template using `@onclick`:
+:::caution pass
+
+**The JS methods must be defined in the global scope!**
+
+In this demo, the script is added to the `HEAD` block of the root HTML file:
+
+```html title="wwwroot/index.html"
+
+
+
+
+
+
+
+
+
+```
+
+When using `
+```
+
+:::
+
+#### Blazor Callbacks
+
+Methods are commonly bound to buttons in the Razor template using `@onclick`.
+When the following button is clicked, Blazor will invoke `ExportDataset`:
```html title="Binding callback to a HTML button"
diff --git a/docz/docs/03-demos/42-engines/02-v8.md b/docz/docs/03-demos/42-engines/02-v8.md
index 431801b..ca63d1b 100644
--- a/docz/docs/03-demos/42-engines/02-v8.md
+++ b/docz/docs/03-demos/42-engines/02-v8.md
@@ -32,10 +32,10 @@ can be parsed and evaluated in a V8 context.
:::note pass
-This section describes a flow where the script is parsed and evaluated every
-time the program is run.
+This section describes a flow where the script is parsed and evaluated each time
+the program is run.
-Using V8 snapshots, SheetJS libraries can be parsed and evaluated beforehand.
+Using V8 snapshots, SheetJS libraries can be parsed and evaluated at build time.
This greatly improves program startup time.
The ["Snapshots"](#snapshots) section includes a complete example.
@@ -96,30 +96,40 @@ To confirm the library is loaded, `XLSX.version` can be inspected:
### Reading Files
V8 supports `ArrayBuffer` natively. Assuming `buf` is a C byte array, with
-length `len`, this snippet stores the data as an `ArrayBuffer` in global scope:
+length `len`, the following code stores the data in a global `ArrayBuffer`:
-```cpp
+```cpp title="Loading data into an ArrayBuffer in the V8 engine"
/* load C char array and save to an ArrayBuffer */
std::unique_ptr back = v8::ArrayBuffer::NewBackingStore(isolate, len);
memcpy(back->Data(), buf, len);
v8::Local ab = v8::ArrayBuffer::New(isolate, std::move(back));
v8::Maybe res = context->Global()->Set(context, v8::String::NewFromUtf8Literal(isolate, "buf"), ab);
+```
+Once the raw data is pulled into the engine, the SheetJS `read` method[^1] can
+parse the data. It is recommended to attach the result to a global variable:
+
+```cpp
/* parse with SheetJS */
v8::Local result = eval_code(isolate, context, "globalThis.wb = XLSX.read(buf)");
```
-`wb` will be a variable in the JS environment that can be inspected using the
-various SheetJS API functions.
+`wb`, a SheetJS workbook object[^2], will be a variable in the JS environment
+that can be inspected using the various SheetJS API functions[^3].
### Writing Files
-The underlying memory from an `ArrayBuffer` can be recovered:
+The SheetJS `write` method[^4] generates file bytes from workbook objects. The
+`array` type[^5] instructs the library to generate `ArrayBuffer` objects:
-```c
+```cpp
/* write with SheetJS using type: "array" */
v8::Local result = eval_code(isolate, context, "XLSX.write(wb, {type:'array', bookType:'xlsb'})");
+```
+The underlying memory from an `ArrayBuffer` can be pulled from the engine:
+
+```cpp title="Pulling raw bytes from an ArrayBuffer"
/* pull result back to C++ */
v8::Local ab = v8::Local::Cast(result);
size_t sz = ab->ByteLength();
@@ -150,13 +160,13 @@ generates an XLSB file and writes to the filesystem.
:::caution pass
When the demo was last tested, there were errors in the official V8 embed guide.
-The correct instructions are included below.
+Corrected instructions are included below.
:::
-:::caution pass
+:::danger pass
-The build process is long and will test your patience.
+**The build process is long and will test your patience.**
:::
@@ -894,7 +904,7 @@ may not work on every platform.
### Rust
-The `v8` crate provides binary builds and straightforward bindings. The Rust
+The `v8` crate[^6] provides binary builds and straightforward bindings. The Rust
code is similar to the C++ code.
Pulling data from an `ArrayBuffer` back into Rust involves an unsafe operation:
@@ -1125,7 +1135,8 @@ If the program succeeded, the CSV contents will be printed to console.
### C#
-ClearScript provides a .NET interface to the V8 engine.
+[ClearScript](https://microsoft.github.io/ClearScript/) is a .NET interface to
+the V8 engine.
C# byte arrays (`byte[]`) must be explicitly converted to arrays of bytes:
@@ -1231,8 +1242,8 @@ dotnet run
dotnet add package Microsoft.ClearScript.Complete --version 7.4.5
```
-5) Download the SheetJS standalone script and test file. Move all three files to
-the project directory:
+5) Download the SheetJS standalone script and test file. Move both files to the
+project directory:
@@ -1282,6 +1293,139 @@ If successful, the program will print the contents of the first sheet as CSV
rows. It will also create `SheetJSClearScript.xlsb`, a workbook that can be
opened in a spreadsheet editor.
+### Python
+
+[`pyv8`](https://code.google.com/archive/p/pyv8/) is a Python wrapper for V8.
+
+The `stpyv8` package[^7] is an actively-maintained fork with binary wheels.
+
+:::caution pass
+
+When this demo was last tested, there was no direct conversion between Python
+`bytes` and JavaScript `ArrayBuffer` data.
+
+This is a known issue[^8]. The current recommendation is Base64 strings.
+
+:::
+
+#### Python Base64 Strings
+
+The SheetJS `read`[^1] and `write`[^4] methods support Base64 strings through
+the `base64` type[^5].
+
+_Reading Files_
+
+It is recommended to create a global context with a special method that handles
+file reading from Python. The `read_file` helper in the following snippet will
+read bytes from `sheetjs.xlsx` and generate a Base64 string:
+
+```py
+from base64 import b64encode;
+from STPyV8 import JSContext, JSClass;
+
+# Create context with methods for file i/o
+class Base64Context(JSClass):
+ def read_file(self, path):
+ with open(path, "rb") as f:
+ data = f.read();
+ return b64encode(data).decode("ascii");
+globals = Base64Context();
+
+# The JSContext starts and cleans up the V8 engine
+with JSContext(globals) as ctxt:
+ print(ctxt.eval("read_file('sheetjs.xlsx')")); # read base64 data and print
+```
+
+_Writing Files_
+
+Since the SheetJS `write` method returns a Base64 string, the result can be
+decoded and written to file from Python:
+
+```py
+from base64 import b64decode;
+from STPyV8 import JSContext;
+
+# The JSContext starts and cleans up the V8 engine
+with JSContext() as ctxt:
+ # ... initialization and workbook creation ...
+ xlsb = ctxt.eval("XLSX.write(wb, {type: 'base64', bookType: 'xlsb'})");
+ with open("SheetJSSTPyV8.xlsb", "wb") as f:
+ f.write(b64decode(xlsb));
+```
+
+#### Python Demo
+
+:::note Tested Deployments
+
+This demo was last tested in the following deployments:
+
+| Architecture | V8 Version | Python | Date |
+|:-------------|:--------------|:---------|:-----------|
+| `darwin-arm` | `13.0.245.16` | `3.13.0` | 2024-10-20 |
+
+:::
+
+0) Make a new folder for the project:
+
+```bash
+mkdir sheetjs-stpyv8
+cd sheetjs-stpyv8
+```
+
+1) Install `stpyv8`:
+
+```bash
+pip install stpyv8
+```
+
+:::caution pass
+
+The install may fail with a `externally-managed-environment` error:
+
+```
+error: externally-managed-environment
+
+× This environment is externally managed
+```
+
+The wheel can be downloaded and forcefully installed. The following commands
+download and install version `13.0.245.16` for Python `3.13` on `darwin-arm`:
+
+```bash
+curl -LO https://github.com/cloudflare/stpyv8/releases/download/v13.0.245.16/stpyv8-13.0.245.16-cp313-cp313-macosx_14_0_arm64.whl
+sudo python -m pip install --upgrade stpyv8-13.0.245.16-cp313-cp313-macosx_14_0_arm64.whl --break-system-packages
+```
+
+:::
+
+2) Download the SheetJS standalone script and test file. Move both files to the
+project directory:
+
+
+
+{`\
+curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js
+curl -LO https://docs.sheetjs.com/pres.xlsx`}
+
+
+3) Download [`sheetjs-stpyv8.py`](pathname:///v8/sheetjs-stpyv8.py):
+
+```bash
+curl -LO https://docs.sheetjs.com/v8/sheetjs-stpyv8.py
+```
+
+4) Run the script and pass `pres.xlsx` as the first argument:
+
+```bash
+python sheetjs-stpyv8.py pres.xlsx
+```
+
+The script will display CSV rows from the first worksheet. It will also create
+`SheetJSSTPyV8.xlsb`, a workbook that can be opened with a spreadsheet editor.
+
## Snapshots
At a high level, V8 snapshots are raw dumps of the V8 engine state. It is much
@@ -1403,3 +1547,12 @@ mv target/release/sheet2csv.exe .
+
+[^1]: See [`read` in "Reading Files"](/docs/api/parse-options)
+[^2]: See ["SheetJS Data Model"](/docs/csf) for more details on the object representation.
+[^3]: See ["API Reference"](/docs/api) for a list of functions that ship with the library. ["Spreadsheet Features"](/docs/csf/features) covers workbook and worksheet features that can be modified directly.
+[^4]: See [`write` in "Writing Files"](/docs/api/write-options)
+[^5]: See ["Supported Output Formats" type in "Writing Files"](/docs/api/write-options#supported-output-formats)
+[^6]: The project does not have an official website. The [official Rust crate](https://crates.io/crates/v8) is hosted on `crates.io`.
+[^7]: The project does not have a separate website. The source repository is hosted on [GitHub](https://github.com/cloudflare/stpyv8)
+[^8]: According to a maintainer, [typed arrays were not supported in the original `pyv8` project](https://github.com/cloudflare/stpyv8/issues/104#issuecomment-2059125389)
\ No newline at end of file
diff --git a/docz/docs/03-demos/42-engines/04-jsc.md b/docz/docs/03-demos/42-engines/04-jsc.md
index 5ea8604..2fdf86d 100644
--- a/docz/docs/03-demos/42-engines/04-jsc.md
+++ b/docz/docs/03-demos/42-engines/04-jsc.md
@@ -22,6 +22,41 @@ This demo uses JSC and SheetJS to read and write spreadsheets. We'll explore how
to load SheetJS in a JSC context and process spreadsheets and structured data
from C++ and Swift programs.
+:::note pass
+
+This demo was tested in the following environments:
+
+[**Swift Built-in**](#swift)
+
+Swift on MacOS supports JavaScriptCore without additional dependencies.
+
+| Architecture | Swift | Date |
+|:-------------|:--------|:-----------|
+| `darwin-x64` | `5.10` | 2024-04-04 |
+| `darwin-arm` | `5.10` | 2024-06-30 |
+
+[**C / C++ Compiled from Source**](#c)
+
+JavaScriptCore can be built from source and linked in C / C++ programs.
+
+| Architecture | Version | Date |
+|:-------------|:-----------------|:-----------|
+| `darwin-x64` | `7618.1.15.14.7` | 2024-04-24 |
+| `darwin-arm` | `7618.2.12.11.7` | 2024-05-24 |
+| `linux-x64` | `7618.2.12.11.7` | 2024-06-22 |
+| `linux-arm` | `7618.2.12.11.7` | 2024-06-22 |
+
+[**Swift Compiled from Source**](#swift-c)
+
+Swift compiler can link against libraries built from the JavaScriptCore source.
+
+| Architecture | Version | Date |
+|:-------------|:-----------------|:-----------|
+| `linux-x64` | `7618.2.12.11.7` | 2024-06-22 |
+| `linux-arm` | `7618.2.12.11.7` | 2024-06-22 |
+
+:::
+
## Integration Details
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
@@ -308,31 +343,6 @@ FILE *f = fopen("sheetjsw.xlsb", "wb"); fwrite(buf, 1, sz, f); fclose(f);
### Swift
-:::note pass
-
-This demo was tested in the following environments:
-
-**Built-in**
-
-Swift on MacOS supports JavaScriptCore without additional dependencies.
-
-| Architecture | Swift | Date |
-|:-------------|:--------|:-----------|
-| `darwin-x64` | `5.10` | 2024-04-04 |
-| `darwin-arm` | `5.10` | 2024-06-30 |
-
-**Compiled**
-
-The ["Swift C"](#swift-c) section starts from the static libraries built in the
-["C++"](#c) section and builds Swift bindings.
-
-| Architecture | Version | Date |
-|:-------------|:-----------------|:-----------|
-| `linux-x64` | `7618.2.12.11.7` | 2024-06-22 |
-| `linux-arm` | `7618.2.12.11.7` | 2024-06-22 |
-
-:::
-
The demo includes a sample `SheetJSCore` Wrapper class to simplify operations.
:::caution This demo only runs on MacOS
@@ -399,19 +409,6 @@ to `SheetJSwift.xlsx`. That file can be verified by opening in Excel / Numbers.
### C++
-:::note pass
-
-This demo was tested in the following environments:
-
-| Architecture | Version | Date |
-|:-------------|:-----------------|:-----------|
-| `darwin-x64` | `7618.1.15.14.7` | 2024-04-24 |
-| `darwin-arm` | `7618.2.12.11.7` | 2024-05-24 |
-| `linux-x64` | `7618.2.12.11.7` | 2024-06-22 |
-| `linux-arm` | `7618.2.12.11.7` | 2024-06-22 |
-
-:::
-
0) Install dependencies
diff --git a/docz/docs/03-demos/42-engines/15-rb.md b/docz/docs/03-demos/42-engines/15-rb.md
index 747d193..51c65c2 100644
--- a/docz/docs/03-demos/42-engines/15-rb.md
+++ b/docz/docs/03-demos/42-engines/15-rb.md
@@ -95,8 +95,7 @@ This demo was tested in the following deployments:
| `linux-arm` | `3.1.2` | `2.9.1` | 2024-05-25 |
When the demo was last tested, there was no official Ruby release for Windows
-on ARM. The `win11-arm` test was run in WSL. The `win10-x64` test used the
-official Ruby for Windows x64 release.
+on ARM. The `win11-arm` test was run in WSL.
:::
diff --git a/docz/docs/03-demos/42-engines/index.md b/docz/docs/03-demos/42-engines/index.md
index 384bb29..aa45d91 100644
--- a/docz/docs/03-demos/42-engines/index.md
+++ b/docz/docs/03-demos/42-engines/index.md
@@ -5,6 +5,7 @@ pagination_next: solutions/input
---
import EngineData from '/data/engines.js'
+import BindingData from '/data/bindings.js'
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
@@ -85,8 +86,27 @@ across multiple architectures (x64 and ARM64).
:::
+The following engines have been tested in their native languages:
+
+The following bindings have been tested:
+
+
+
+:::note pass
+
+Asterisks (✱) in the Windows columns mark tests that were run in Windows
+Subsystem for Linux (WSL). In some cases, community efforts have produced forks
+with native Windows support.
+
+Blank cells mark untested or unsupported configurations. With cross-compilation,
+V8 can run natively in Windows on ARM. The `win11-arm` platform is not tested
+since the official build infrastructure does not support Windows on ARM and the
+V8 project does not distribute shared or static libraries for Windows on ARM.
+
+:::
+
#### Boa
Boa is an embeddable JS engine written in Rust.
@@ -165,9 +185,7 @@ V8 is an embeddable JS engine written in C++. It powers Chromium and Chrome,
NodeJS and Deno, Adobe UXP and other platforms.
This demo has been moved [to a dedicated page](/docs/demos/engines/v8).
-The demo includes examples in C++ and Rust.
-
-The ["Python + Pandas" demo](/docs/demos/math/pandas) uses V8 with Python.
+The demo includes examples in C++, C#, Python, and Rust.
[^1]: See ["Initialize Hermes"](/docs/demos/engines/hermes#initialize-hermes) in the Hermes demo.
[^2]: See [`read` in "Reading Files"](/docs/api/parse-options)
diff --git a/docz/static/v8/sheetjs-stpyv8.py b/docz/static/v8/sheetjs-stpyv8.py
new file mode 100644
index 0000000..5ca9835
--- /dev/null
+++ b/docz/static/v8/sheetjs-stpyv8.py
@@ -0,0 +1,36 @@
+from sys import stderr, argv;
+from base64 import b64encode, b64decode;
+from STPyV8 import JSContext, JSClass;
+
+# Create context with methods for file i/o
+class Base64Context(JSClass):
+ def read_file(self, path):
+ with open(path, "rb") as f:
+ data = f.read();
+ return b64encode(data).decode("ascii");
+ def write_file(self, data, path):
+ with open(path, "wb") as f:
+ f.write(b64decode(data));
+globals = Base64Context();
+
+# Read xlsx.full.min.js
+with open("xlsx.full.min.js", "r") as f:
+ sheetjs = f.read();
+
+# The JSContext starts and cleans up the V8 engine
+with JSContext(globals) as ctxt:
+ # Load SheetJS library and display version number
+ ctxt.eval(sheetjs);
+ version = ctxt.eval("XLSX.version");
+ print(f"SheetJS Version: {version}", file=stderr);
+
+ # Parse workbook
+ ctxt.eval(f"globalThis.wb = XLSX.read(read_file('{argv[1]}'), {{type:'base64'}}); void 0;");
+
+ # Print CSV from first worksheet
+ csv = ctxt.eval("XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);");
+ print(csv);
+
+ # Generate XLSB
+ xlsb = ctxt.eval("XLSX.write(wb, {type: 'base64', bookType: 'xlsb'})");
+ globals.write_file(xlsb,"SheetJSSTPyV8.xlsb");