diff --git a/docz/data/engines.xls b/docz/data/engines.xls
index 26d5428..26f7687 100644
--- a/docz/data/engines.xls
+++ b/docz/data/engines.xls
@@ -1,417 +1,417 @@
-
-
-
-
- 10620
- 11020
- 2260
- 19600
- 1
- False
- False
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- |
- MacOS |
- Windows |
- Linux |
-
-
- | Engine |
- Lang |
- x64 |
- ARM |
- x64 |
- ARM |
- x64 |
- ARM |
-
-
- | Duktape |
- C |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
-
-
- | V8 |
- C++ |
- ✔ |
- ✔ |
- ✔ |
- |
- ✔ |
- ✔ |
-
-
- | Rhino |
- Java |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
-
-
- | JSC |
- C++ |
- ✔ |
- ✔ |
- |
- |
- ✔ |
- ✔ |
-
-
- | Jint |
- C# |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
-
-
- | Goja |
- Go |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
-
-
- | Nashorn |
- Java |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
-
-
- | QuickJS |
- C |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
-
-
- | Hermes |
- C++ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
-
-
- | ChakraCore |
- C++ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
-
-
- | Boa |
- Rust |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
-
-
- | JE |
- Perl |
- ✔ |
- ✔ |
- ✱ |
- ✱ |
- ✔ |
- ✔ |
-
-
- | JerryScript |
- C |
- ✔ |
- ✔ |
- ✱ |
- ✱ |
- ✔ |
- ✔ |
-
-
- | GraalJS |
- Java |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
-
-
- | MuJS |
- C |
- ✔ |
- ✔ |
- ✱ |
- ✱ |
- ✔ |
- ✔ |
-
-
- | Jurassic.NET |
- C# |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
-
-
-
-
-
-
-
-
-
-
- 2
- 2
- 2
-
-
- 3
-
-
- 2
- 12
- 5
-
-
- False
- False
-
-
-
-
-
-
-
-
-
-
-
- |
- MacOS |
- Windows |
- Linux |
-
-
- | Engine |
- Lang |
- x64 |
- ARM |
- x64 |
- ARM |
- x64 |
- ARM |
-
-
- | Duktape |
- Perl |
- ✔ |
- ✔ |
- |
- |
- ✔ |
- ✔ |
-
-
- | Duktape |
- PHP |
- ✔ |
- ✔ |
- |
- |
- ✔ |
- ✔ |
-
-
- | Duktape |
- Python |
- ✔ |
- ✔ |
- |
- |
- ✔ |
- ✔ |
-
-
- | Duktape |
- Rust |
- ✔ |
- ✔ |
- ✔ |
- ✘ |
- ✔ |
- ✔ |
-
-
- | Duktape |
- Zig |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
-
-
- | V8 |
- Rust |
- ✔ |
- ✔ |
- ✔ |
- |
- ✔ |
- ✔ |
-
-
- | V8 |
- Java |
- ✔ |
- ✔ |
- ✔ |
- |
- ✔ |
- ✔ |
-
-
- | V8 |
- C# |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
- ✔ |
-
-
- | V8 |
- Python |
- ✔ |
- ✔ |
- ✔ |
- |
- ✔ |
- |
-
-
- | JSC |
- Swift |
- ✔ |
- ✔ |
- |
- |
- ✔ |
- ✔ |
-
-
- | JSC |
- Rust |
- ✔ |
- ✔ |
- |
- |
- |
- |
-
-
- | ExecJS |
- Ruby |
- ✔ |
- ✔ |
- ✔ |
- ✱ |
- ✔ |
- ✔ |
-
-
-
-
-
-
-
-
-
-
-
- 2
- 2
- 2
-
-
- 3
-
-
- 2
- 3
- 1
-
-
- False
- False
-
-
-
+
+
+
+
+ 10620
+ 11020
+ 2260
+ 19600
+ 1
+ False
+ False
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+ MacOS |
+ Windows |
+ Linux |
+
+
+ | Engine |
+ Lang |
+ x64 |
+ ARM |
+ x64 |
+ ARM |
+ x64 |
+ ARM |
+
+
+ | Duktape |
+ C |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | V8 |
+ C++ |
+ ✔ |
+ ✔ |
+ ✔ |
+ |
+ ✔ |
+ ✔ |
+
+
+ | Rhino |
+ Java |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | JSC |
+ C++ |
+ ✔ |
+ ✔ |
+ |
+ |
+ ✔ |
+ ✔ |
+
+
+ | Jint |
+ C# |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | Goja |
+ Go |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | Nashorn |
+ Java |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | QuickJS |
+ C |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | Hermes |
+ C++ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | ChakraCore |
+ C++ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | Boa |
+ Rust |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | JE |
+ Perl |
+ ✔ |
+ ✔ |
+ ✱ |
+ ✱ |
+ ✔ |
+ ✔ |
+
+
+ | JerryScript |
+ C |
+ ✔ |
+ ✔ |
+ ✱ |
+ ✱ |
+ ✔ |
+ ✔ |
+
+
+ | GraalJS |
+ Java |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | MuJS |
+ C |
+ ✔ |
+ ✔ |
+ ✱ |
+ ✱ |
+ ✔ |
+ ✔ |
+
+
+ | Jurassic.NET |
+ C# |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+
+
+
+
+
+
+
+
+ 2
+ 2
+ 2
+
+
+ 3
+
+
+ 2
+ 12
+ 5
+
+
+ False
+ False
+
+
+
+
+
+
+
+
+
+
+
+ |
+ MacOS |
+ Windows |
+ Linux |
+
+
+ | Engine |
+ Lang |
+ x64 |
+ ARM |
+ x64 |
+ ARM |
+ x64 |
+ ARM |
+
+
+ | Duktape |
+ Perl |
+ ✔ |
+ ✔ |
+ |
+ |
+ ✔ |
+ ✔ |
+
+
+ | Duktape |
+ PHP |
+ ✔ |
+ ✔ |
+ |
+ |
+ ✔ |
+ ✔ |
+
+
+ | Duktape |
+ Python |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | Duktape |
+ Rust |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✘ |
+ ✔ |
+ ✔ |
+
+
+ | Duktape |
+ Zig |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | V8 |
+ Rust |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | V8 |
+ Java |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✘ |
+ ✔ |
+ ✔ |
+
+
+ | V8 |
+ C# |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | V8 |
+ Python |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✔ |
+
+
+ | JSC |
+ Swift |
+ ✔ |
+ ✔ |
+ |
+ |
+ ✔ |
+ ✔ |
+
+
+ | JSC |
+ Rust |
+ ✔ |
+ ✔ |
+ |
+ |
+ ✔ |
+ ✔ |
+
+
+ | ExecJS |
+ Ruby |
+ ✔ |
+ ✔ |
+ ✔ |
+ ✱ |
+ ✔ |
+ ✔ |
+
+
+
+
+
+
+
+
+
+
+
+ 2
+ 2
+ 2
+
+
+ 3
+
+
+ 2
+ 3
+ 1
+
+
+ False
+ False
+
+
+
diff --git a/docz/docs/03-demos/42-engines/01-duktape.md b/docz/docs/03-demos/42-engines/01-duktape.md
index b3b1386..5caafc9 100644
--- a/docz/docs/03-demos/42-engines/01-duktape.md
+++ b/docz/docs/03-demos/42-engines/01-duktape.md
@@ -550,7 +550,8 @@ This demo was tested in the following deployments:
|:-------------|:--------|:---------|:-----------|
| `darwin-x64` | `2.7.0` | `3.13.7` | 2026-01-21 |
| `darwin-arm` | `2.7.0` | `3.12.3` | 2026-01-23 |
-| `win11-x64` | `2.7.0` | `3.11.9` | 2026-01-28 |
+| `win11-x64` | `2.7.0` | `3.11.9` | 2026-02-02 |
+| `win11-arm` | `2.7.0` | `3.11.9` | 2026-02-02 |
| `linux-x64` | `2.7.0` | `3.12.3` | 2025-04-21 |
| `linux-arm` | `2.7.0` | `3.11.2` | 2025-02-15 |
@@ -560,6 +561,9 @@ This demo was tested in the following deployments:
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
@@ -568,18 +572,92 @@ make -f Makefile.sharedlibrary
cd ..
```
+
+
+
+```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 ..
+```
+
+
+
+
+- Download and extract the source tarball:
+
+```bash
+curl -LO https://duktape.org/duktape-2.7.0.tar.xz
+tar -xJf duktape-2.7.0.tar.xz
+```
+
+- Enter the source folder:
+
+```bash
+cd duktape-2.7.0
+```
+
+- Edit `src\duk_config.h` and add the highlighted lines to the end of the file:
+
+```c title="src\duk_config.h (add highlighted lines to end of file)"
+#endif /* DUK_CONFIG_H_INCLUDED */
+
+// highlight-start
+#define DUK_EXTERNAL_DECL extern __declspec(dllexport)
+#define DUK_EXTERNAL __declspec(dllexport)
+// highlight-end
+```
+
+- Build the Duktape DLL:
+
+```cmd
+cl /O2 /W3 /Isrc /LD /DDUK_SINGLE_FILE /DDUK_F_DLL_BUILD /DDUK_F_WINDOWS /DDUK_COMPILING_DUKTAPE src\\duktape.c
+```
+
+- Move up to the parent directory:
+
+```bash
+cd ..
+```
+
+
+
+
2) Copy the shared library to the current folder. When the demo was last tested,
the shared library file name differed by platform:
-| OS | name |
-|:-------|:--------------------------|
-| Darwin | `libduktape.207.20700.so` |
-| Linux | `libduktape.so.207.20700` |
+| OS | name |
+|:--------|:--------------------------|
+| Darwin | `libduktape.207.20700.so` |
+| Linux | `libduktape.so.207.20700` |
+| Windows | `duktape.dll` |
+
+
+
```bash
cp duktape-*/libduktape.* .
```
+
+
+
+```bash
+cp duktape-*/libduktape.* .
+```
+
+
+
+
+```cmd
+copy duktape-2.7.0\duktape.dll .
+```
+
+
+
+
3) Download the SheetJS Standalone script, shim script and test file. Move all
three files to the project directory:
@@ -632,6 +710,38 @@ The name of the library is `libduktape.so.207.20700`:
lib = "libduktape.so.207.20700"
```
+
+
+
+The name of the library is `duktape.dll`:
+
+```python title="SheetJSDuk.py (change highlighted line)"
+# highlight-next-line
+lib = ".\\duktape.dll"
+```
+
+In addition, the following changes must be made:
+
+- `str_to_c` must be defined as follows:
+
+```python title="SheetJSDuk.py (replace str_to_c function)"
+def str_to_c(s):
+ if type(s) == bytes:
+ b = s
+ else:
+ b = s.encode("utf8")
+ return [c_char_p(b), len(b)]
+```
+
+- `eval_file` must `open` with mode `rb`:
+
+```python title="SheetJSDuk.py (edit highlighted line)"
+def eval_file(ctx, path):
+ # highlight-next-line
+ with open(path, "rb") as f:
+ code = f.read()
+```
+
@@ -672,6 +782,16 @@ The name of the library is `libduktape.so.207.20700`:
```python title="SheetJSDuk.py (change highlighted line)"
# highlight-next-line
lib = "./libduktape.so.207.20700"
+```
+
+
+
+
+The name of the library is `duktape.dll`:
+
+```python title="SheetJSDuk.py (change highlighted line)"
+# highlight-next-line
+lib = ".\\duktape.dll"
```
diff --git a/docz/docs/03-demos/42-engines/02-v8.md b/docz/docs/03-demos/42-engines/02-v8.md
index 90d9e44..7f64237 100644
--- a/docz/docs/03-demos/42-engines/02-v8.md
+++ b/docz/docs/03-demos/42-engines/02-v8.md
@@ -489,7 +489,7 @@ ninja -C out.gn/x64.release.sample v8_monolith
**This may not work in newer Python releases due to a breaking change!**
-Python 3.13 removed the `pipes` module from the standard library[^9]. `v8gen.py`
+Python 3.13 removed the `pipes` module from the standard library[^7]. `v8gen.py`
will fail on newer Python releases with the following traceback:
```
@@ -1099,6 +1099,7 @@ This demo was last tested in the following deployments:
| `darwin-x64` | `136.0.0` | 2025-04-21 |
| `darwin-arm` | `134.3.0` | 2025-02-13 |
| `win11-x64` | `137.1.0` | 2025-05-11 |
+| `win11-arm` | `145.0.0` | 2026-02-02 |
| `linux-x64` | `142.2.0` | 2026-01-08 |
| `linux-arm` | `134.4.0` | 2025-02-15 |
@@ -1212,10 +1213,29 @@ This demo was last tested in the following deployments:
| Architecture | V8 Version | Javet | Java | Date |
|:-------------|:--------------|:--------|:----------|:-----------|
| `darwin-x64` | `13.2.152.16` | `4.1.1` | `24.0.1` | 2025-04-21 |
-| `darwin-arm` | `13.2.152.16` | `4.1.1` | `17.0.14` | 2025-03-30 |
-| `win11-x64` | `13.2.152.16` | `4.1.1` | `17.0.13` | 2025-05-11 |
-| `linux-x64` | `13.2.152.16` | `4.1.1` | `21.0.6` | 2025-04-21 |
-| `linux-arm` | `13.2.152.16` | `4.1.1` | `17.0.14` | 2025-02-16 |
+| `darwin-arm` | `13.2.152.16` | `4.1.1` | `17.0.14` | 2026-03-04 |
+| `win11-x64` | `13.2.152.16` | `4.1.1` | `17.0.12` | 2026-03-04 |
+| `win11-arm` | `13.2.152.16` | `4.1.1` | `25.0.2` | 2026-03-04 |
+| `linux-x64` | `13.2.152.16` | `4.1.1` | `21.0.10` | 2026-02-04 |
+| `linux-arm` | `13.2.152.16` | `4.1.1` | `17.0.18` | 2026-02-04 |
+
+:::
+
+:::caution pass
+
+Javet does not provide a pre-built JAR for Windows on ARM. This demo was tested
+using the X64 compatibility layer.
+
+
+ Windows on ARM steps (click to show)
+
+Windows on ARM defaults to ARM64 JRE/JDK. A proper x64 JDK must be installed and
+`JAVA_HOME` must point to the x64 version.
+
+[Direct downloads are available at `adoptium.net`](https://adoptium.net/temurin/releases/).
+The Windows x64 JDK release should be downloaded and installed.
+
+
:::
@@ -1578,16 +1598,15 @@ 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.
+The [`mini-racer`](https://bpcreech.com/PyMiniRacer/) V8 wrapper package has
+precompiled wheels for all major platforms.
:::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.
+This is a known issue. The current recommendation is Base64 strings.
:::
@@ -1598,25 +1617,26 @@ 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:
+The file data can be read in Python and encoded as Base64. The `set_object_item`
+method on the internal context can assign to properties of the global object.
+
+`mini-racer` does not expose a dedicated API to reference the global object.
+The standard approach is to evaluate `this` in the JavaScript engine:
```py
from base64 import b64encode;
-from STPyV8 import JSContext, JSClass;
+from py_mini_racer import MiniRacer;
-# 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();
+with open("sheetjs.xlsx", "rb") as f:
+ file_data = b64encode(f.read()).decode("ascii");
-# 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
+# Create context and obtain a handle to `this`
+ctx = MiniRacer();
+global_scope = ctx.eval("this");
+
+# assign to the `fileData` global property and parse
+ctx._ctx.set_object_item(global_scope, "fileData", file_data);
+ctx.eval("var wb = XLSX.read(fileData, {type:'base64'});");
```
_Writing Files_
@@ -1626,14 +1646,14 @@ decoded and written to file from Python:
```py
from base64 import b64decode;
-from STPyV8 import JSContext;
+from py_mini_racer import MiniRacer;
-# 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));
+ctx = MiniRacer();
+# ... initialization and workbook creation ...
+xlsb = ctx.eval("XLSX.write(wb, {type: 'base64', bookType: 'xlsb'})");
+with open("SheetJSMiniRacer.xlsb", "wb") as f:
+ f.write(b64decode(xlsb));
+ctx.close();
```
#### Python Demo
@@ -1644,46 +1664,28 @@ This demo was last tested in the following deployments:
| Architecture | V8 Version | Python | Date |
|:-------------|:--------------|:---------|:-----------|
-| `darwin-x64` | `13.1.201.22` | `3.13.1` | 2025-03-31 |
-| `darwin-arm` | `13.1.201.22` | `3.13.2` | 2025-04-24 |
-| `win11-x64` | `13.1.201.22` | `3.11.9` | 2025-04-28 |
-| `linux-x64` | `13.1.201.22` | `3.12.3` | 2025-06-16 |
+| `darwin-x64` | `14.4` | `3.13.7` | 2026-03-04 |
+| `darwin-arm` | `14.4` | `3.14.3` | 2026-03-04 |
+| `win11-x64` | `14.4` | `3.11.9` | 2026-02-04 |
+| `win11-arm` | `14.4` | `3.11.9` | 2026-02-04 |
+| `linux-x64` | `14.4` | `3.13.9` | 2026-03-04 |
+| `linux-arm` | `14.4` | `3.13.5` | 2026-03-04 |
:::
0) Make a new folder for the project:
```bash
-mkdir sheetjs-stpyv8
-cd sheetjs-stpyv8
+mkdir sheetjs-miniracer
+cd sheetjs-miniracer
```
-1) Install `stpyv8`:
+1) Install `mini-racer`:
```bash
-pip install stpyv8
+pip install mini-racer
```
-:::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.1.201.22/stpyv8-13.1.201.22-cp313-cp313-macosx_14_0_arm64.whl
-sudo python -m pip install --break-system-packages --upgrade stpyv8-13.1.201.22-cp313-cp313-macosx_14_0_arm64.whl
-```
-
-:::
-
2) Download the SheetJS standalone script and test file. Move both files to the
project directory:
@@ -1697,40 +1699,20 @@ 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):
+3) Download [`sheetjs-mini-racer.py`](pathname:///v8/sheetjs-mini-racer.py):
```bash
-curl -LO https://docs.sheetjs.com/v8/sheetjs-stpyv8.py
+curl -LO https://docs.sheetjs.com/v8/sheetjs-mini-racer.py
```
4) Run the script and pass `pres.xlsx` as the first argument:
```bash
-python sheetjs-stpyv8.py pres.xlsx
+python sheetjs-mini-racer.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.
-
-:::caution pass
-
-On Windows, this may fail with a `charmap` error:
-
-```
- return codecs.charmap_decode(input,self.errors,decoding_table)[0]
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-UnicodeDecodeError: 'charmap' codec can't decode byte 0x90 in position 380: character maps to
-```
-
-`sheetjs-stpyv8.py` must be altered to read `xlsx.full.min.js` with mode `rb`:
-
-```python title="sheetjs-stpyv8.py (edit highlighted line)"
-# Read xlsx.full.min.js
-# highlight-next-line
-with open("xlsx.full.min.js", "rb") as f:
-```
-
-:::
+`SheetJSMiniRacer.xlsb`, a workbook that can be opened with a spreadsheet editor.
## Snapshots
@@ -1859,6 +1841,4 @@ mv target/release/sheet2csv.exe .
[^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)
-[^9]: `pipes` and other modules were removed from the standard library in Python 3.13 as part of ["PEP 594"](https://docs.python.org/3/whatsnew/3.13.html#whatsnew313-pep594).
\ No newline at end of file
+[^7]: `pipes` and other modules were removed from the standard library in Python 3.13 as part of ["PEP 594"](https://docs.python.org/3/whatsnew/3.13.html#whatsnew313-pep594).
\ 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 d1f5ba1..91d552d 100644
--- a/docz/docs/03-demos/42-engines/04-jsc.md
+++ b/docz/docs/03-demos/42-engines/04-jsc.md
@@ -32,28 +32,28 @@ Swift on MacOS supports JavaScriptCore without additional dependencies.
| Architecture | Swift | Date |
|:-------------|:--------|:-----------|
-| `darwin-x64` | `6.1` | 2025-04-21 |
-| `darwin-arm` | `6.1` | 2025-04-21 |
+| `darwin-x64` | `6.1.2` | 2026-03-04 |
+| `darwin-arm` | `6.0.3` | 2026-03-04 |
[**C / C++ Compiled from Source**](#c)
JavaScriptCore can be built from source and linked in C / C++ programs.
-| Architecture | Version | Date |
-|:-------------|:-----------------|:-----------|
-| `darwin-x64` | `7620.2.4.111.7` | 2025-04-21 |
-| `darwin-arm` | `7620.2.4.111.7` | 2025-04-21 |
-| `linux-x64` | `7620.2.4.111.7` | 2025-04-21 |
-| `linux-arm` | `7620.2.4.111.7` | 2025-04-21 |
+| Architecture | Version | Date |
+|:-------------|:------------------|:-----------|
+| `darwin-x64` | `7623.1.14.14.11` | 2026-03-04 |
+| `darwin-arm` | `7623.1.14.14.11` | 2026-03-04 |
+| `linux-x64` | `7623.1.14.14.11` | 2026-03-04 |
+| `linux-arm` | `7623.1.14.14.11` | 2026-03-04 |
[**Swift Compiled from Source**](#swift-c)
Swift compiler can link against libraries built from the JavaScriptCore source.
-| Architecture | Version | Date |
-|:-------------|:-----------------|:-----------|
-| `linux-x64` | `7620.2.4.111.7` | 2025-04-21 |
-| `linux-arm` | `7620.2.4.111.7` | 2025-04-21 |
+| Architecture | Version | Date |
+|:-------------|:------------------|:-----------|
+| `linux-x64` | `7623.1.14.14.11` | 2026-03-04 |
+| `linux-arm` | `7623.1.14.14.11` | 2026-03-04 |
:::
@@ -445,7 +445,7 @@ sudo pacman -Syu base-devel cmake ruby icu glibc linux-api-headers
On Debian and Ubuntu, dependencies should be installed with `apt`:
```bash
-sudo apt-get install build-essential cmake ruby
+sudo apt-get install build-essential cmake ruby libicu-dev
```
@@ -457,12 +457,12 @@ mkdir sheetjs-jsc
cd sheetjs-jsc
```
-2) Clone the WebKit repository and switch to the `WebKit-7620.2.4.111.7` tag:
+2) Clone the WebKit repository and switch to the `WebKit-7623.1.14.14.11` tag:
```bash
git clone https://github.com/WebKit/WebKit.git WebKit
cd WebKit
-git checkout WebKit-7620.2.4.111.7
+git checkout WebKit-7623.1.14.14.11
cd ..
```
@@ -473,19 +473,36 @@ cd ..
```bash
cd WebKit
-env CFLAGS="-Wno-error=all -Wno-deprecated-declarations" CXXFLAGS="-Wno-error=all -Wno-deprecated-declarations" LDFLAGS="-framework Foundation" Tools/Scripts/build-webkit --jsc-only --cmakeargs="-Wno-error=all -DENABLE_STATIC_JSC=ON -DCMAKE_C_FLAGS=\"-Wno-error=all -Wno-deprecated-declarations\" -DCMAKE_CXX_FLAGS=\"-Wno-error=all -Wno-deprecated-declarations\"" --make-args="-Wno-error=all -Wno-deprecated-declarations"
+env CFLAGS="-Wno-error=all -Wno-deprecated-declarations" CXXFLAGS="-Wno-error=all -Wno-deprecated-declarations" LDFLAGS="-framework Foundation" Tools/Scripts/build-webkit --jsc-only --cmakeargs="-Wno-error=all -DENABLE_STATIC_JSC=ON -DCMAKE_C_FLAGS=\"-Wno-error=all -Wno-deprecated-declarations\" -DCMAKE_CXX_FLAGS=\"-Wno-error=all -Wno-deprecated-declarations\"" --make-args="-Wno-error=all -Wno-deprecated-declarations" --no-jit --no-webassembly
cd ..
```
-:::note pass
+:::caution pass
-In some test runs on ARM64 macOS, JIT elicited runtime errors and WebAssembly
-elicited compile-time errors. WebAssembly and JIT should be disabled:
+In some test runs, there were test compile errors:
+
+```
+WebKit/Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp:42:10: fatal error: 'wtf/darwin/DispatchExtras.h' file not found
+ 42 | #include
+ | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+1 error generated.
+```
+
+The referenced file must be patched to assume `MACH_EXCEPTIONS` is not defined.
+There are a number of pre-processor directives:
+
+```c
+#if HAVE(MACH_EXCEPTIONS)
+#include
+#endif
+```
+
+Each pre-processor block must be removed.
+
+This can be automated with a simple Perl command:
```bash
-cd WebKit
-env CFLAGS="-Wno-error=all -Wno-deprecated-declarations" CXXFLAGS="-Wno-error=all -Wno-deprecated-declarations" LDFLAGS="-framework Foundation" Tools/Scripts/build-webkit --jsc-only --cmakeargs="-Wno-error=all -DENABLE_STATIC_JSC=ON -DCMAKE_C_FLAGS=\"-Wno-error=all -Wno-deprecated-declarations\" -DCMAKE_CXX_FLAGS=\"-Wno-error=all -Wno-deprecated-declarations\"" --make-args="-Wno-error=all -Wno-deprecated-declarations" --no-jit --no-webassembly
-cd ..
+perl -0777 -i -pe 's/#if HAVE\(MACH_EXCEPTIONS\).*?#endif\n*/\n/gs' "Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp"
```
:::
@@ -545,7 +562,7 @@ The `#include` should be changed to a relative directive:
```bash
cd WebKit
-env CFLAGS="-Wno-error=all -Wno-error=volatile-register-var -Wno-dangling-reference" CXXFLAGS="-Wno-error=all -Wno-error=volatile-register-var -Wno-dangling-reference" Tools/Scripts/build-webkit --jsc-only --cmakeargs="-Wno-error=all -Wno-error=volatile-register-var -DENABLE_STATIC_JSC=ON -DUSE_THIN_ARCHIVES=OFF -DCMAKE_C_FLAGS=\"-Wno-error=all -Wno-error=volatile-register-var -Wno-dangling-reference\" -DCMAKE_CXX_FLAGS=\"-Wno-error=all -Wno-error=volatile-register-var \"" --make-args="-j1 -Wno-error=all -Wno-error=volatile-register-var " -j1
+env CFLAGS="-Wno-error=all -Wno-error=volatile-register-var -Wno-dangling-reference" CXXFLAGS="-Wno-error=all -Wno-error=volatile-register-var -Wno-dangling-reference" Tools/Scripts/build-webkit --jsc-only --cmakeargs="-Wno-error=all -Wno-error=volatile-register-var -DENABLE_STATIC_JSC=ON -DUSE_THIN_ARCHIVES=OFF" --make-args="-j1 -Wno-error=all -Wno-error=volatile-register-var" -j1 --no-jit --no-webassembly
cd ..
```
@@ -585,17 +602,10 @@ The error can be suppressed with preprocessor directives around the definition:
T* prev() const { return static_cast(PtrTraits::unwrap(m_prev)); }
```
-After patching the header, JSC must be built without WebAssembly or JIT support:
-
-```bash
-cd WebKit
-env CFLAGS="-Wno-error=all -Wno-error=volatile-register-var -Wno-dangling-reference" CXXFLAGS="-Wno-error=all -Wno-error=volatile-register-var -Wno-dangling-reference" Tools/Scripts/build-webkit --jsc-only --cmakeargs="-Wno-error=all -Wno-error=volatile-register-var -DENABLE_STATIC_JSC=ON -DUSE_THIN_ARCHIVES=OFF -DCMAKE_C_FLAGS=\"-Wno-error=all -Wno-error=volatile-register-var -Wno-dangling-reference\" -DCMAKE_CXX_FLAGS=\"-Wno-error=all -Wno-error=volatile-register-var \"" --make-args="-j1 -Wno-error=all -Wno-error=volatile-register-var " -j1 --no-jit --no-webassembly
-cd ..
-```
:::
-:::caution pass
+:::note pass
In some test runs, there was a register error:
@@ -884,7 +894,7 @@ pub struct JSString {
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
// highlight-next-line
-type JSStringRef = *mut JSContext;
+type JSStringRef = *mut JSString;
```
**Function Declaration**
@@ -898,9 +908,10 @@ JSStringRef JSStringCreateWithUTF8CString(const char * string);
The equivalent Rust declaration must be defined in an `extern "C"` block:
```rust title="JSStringCreateWithUTF8CString Rust declaration"
+use libc::c_char;
unsafe extern "C" {
// JSStringRef JSStringCreateWithUTF8CString(const char * string);
- pub unsafe fn JSStringCreateWithUTF8CString(string: *const u8) -> JSStringRef;
+ pub unsafe fn JSStringCreateWithUTF8CString(string: *const c_char) -> JSStringRef;
}
```
@@ -940,8 +951,10 @@ The demo makes a safe wrapper to perform the unsafe waltz in one line:
pub struct JSC;
impl JSC {
pub fn JSStringCreateWithUTF8CString(str: &str) -> JSStringRef { unsafe {
- // highlight-next-line
- JSStringCreateWithUTF8CString(std::ffi::CString::new(str.as_bytes()).unwrap().as_ptr() as *const u8)
+ // highlight-start
+ let cstr = std::ffi::CString::new(str).unwrap();
+ JSStringCreateWithUTF8CString(cstr.as_ptr())
+ // highlight-end
} }
}
```
@@ -954,11 +967,24 @@ This demo was last tested in the following deployments:
| Architecture | Date |
|:-------------|:-----------|
-| `darwin-x64` | 2025-03-31 |
-| `darwin-arm` | 2025-03-30 |
+| `darwin-x64` | 2026-03-04 |
+| `darwin-arm` | 2026-03-04 |
+| `linux-x64` | 2026-03-04 |
+| `linux-arm` | 2026-03-04 |
:::
+
+
+
+
+
+
+0) Follow the entire ["C" demo](#c). The library will be used in Rust.
+
+
+
+
1) Create a new project:
```bash
@@ -999,7 +1025,13 @@ curl -L -o src/main.rs https://docs.sheetjs.com/jsc/main.rs
curl -LO https://docs.sheetjs.com/jsc/build.rs
```
-6) Build and run the app:
+6) Install the `libc` crate:
+
+```bash
+cargo add libc
+```
+
+7) Build and run the app:
```bash
cargo run pres.numbers
diff --git a/docz/static/jsc/build.rs b/docz/static/jsc/build.rs
index 74a61ed..6bd1983 100644
--- a/docz/static/jsc/build.rs
+++ b/docz/static/jsc/build.rs
@@ -2,3 +2,25 @@
fn main() {
println!("cargo::rustc-link-lib=framework=JavaScriptCore");
}
+
+#[cfg(target_os = "linux")]
+fn main() {
+ // Link against JavaScriptCore libraries built from WebKit source
+ // Libraries are static archives (.a files)
+ println!("cargo::rustc-link-lib=static=JavaScriptCore");
+ println!("cargo::rustc-link-lib=static=WTF");
+ println!("cargo::rustc-link-lib=static=bmalloc");
+ println!("cargo::rustc-link-lib=icui18n");
+ println!("cargo::rustc-link-lib=icuuc");
+ println!("cargo::rustc-link-lib=atomic");
+
+ // Required system libraries for the C++ runtime dependencies
+ println!("cargo::rustc-link-lib=stdc++");
+ println!("cargo::rustc-link-lib=pthread");
+ println!("cargo::rustc-link-lib=m");
+ println!("cargo::rustc-link-lib=dl");
+ println!("cargo::rustc-link-lib=c");
+
+ // Search path to the pre-built JavaScriptCore libraries
+ println!("cargo::rustc-link-search=native=/tmp/sheetjs-jsc/Release/lib");
+}
\ No newline at end of file
diff --git a/docz/static/jsc/main.rs b/docz/static/jsc/main.rs
index c5431e3..99302d1 100644
--- a/docz/static/jsc/main.rs
+++ b/docz/static/jsc/main.rs
@@ -1,6 +1,8 @@
/* See https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs */
#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)]
+use libc::{c_char, size_t};
+
#[repr(C)]
pub struct JSContext {
_data: [u8; 0],
@@ -37,21 +39,21 @@ pub struct JSString {
_data: [u8; 0],
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
-type JSStringRef = *mut JSContext;
+type JSStringRef = *mut JSString;
#[repr(C)]
pub struct BytesDeallocator {
_data: [u8; 0],
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
-type JSTypedArrayBytesDeallocator = *mut BytesDeallocator;
+type JSTypedArrayBytesDeallocator = Option;
#[repr(C)]
pub struct BytesDeallocatorContext {
_data: [u8; 0],
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
-type JSTypedArrayBytesDeallocatorContext = *mut BytesDeallocatorContext;
+type JSTypedArrayBytesDeallocatorContext = *mut BytesDeallocatorContext;
/* NOTE: this is technically an enum */
type JSTypedArrayType = u32;
@@ -66,36 +68,59 @@ unsafe extern "C" {
pub unsafe fn JSGlobalContextCreate(string: JSClassRef) -> JSGlobalContextRef;
pub unsafe fn JSGlobalContextRelease(ctx: JSGlobalContextRef);
- pub unsafe fn JSStringCreateWithUTF8CString(string: *const u8) -> JSStringRef;
- pub unsafe fn JSStringGetUTF8CString(string: JSStringRef, buffer: *const u8, bufferSize: usize) -> usize;
- pub unsafe fn JSStringGetMaximumUTF8CStringSize(string: JSStringRef) -> usize;
+ pub unsafe fn JSStringCreateWithUTF8CString(string: *const c_char) -> JSStringRef;
+ pub unsafe fn JSStringGetUTF8CString(string: JSStringRef, buffer: *mut c_char, bufferSize: size_t) -> size_t;
+ pub unsafe fn JSStringGetMaximumUTF8CStringSize(string: JSStringRef) -> size_t;
pub unsafe fn JSStringRelease(string: JSStringRef);
pub unsafe fn JSValueIsString(ctx: JSContextRef, value: JSValueRef) -> bool;
pub unsafe fn JSValueToStringCopy(ctx: JSContextRef, value: JSValueRef, exception: JSValueRefRef) -> JSStringRef;
pub unsafe fn JSValueToObject(ctx: JSContextRef, value: JSValueRef, exception: JSValueRefRef) -> JSObjectRef;
- pub unsafe fn JSObjectGetTypedArrayLength(ctx: JSContextRef, object: JSObjectRef, exception: JSValueRefRef) -> usize;
+ pub unsafe fn JSObjectGetTypedArrayLength(ctx: JSContextRef, object: JSObjectRef, exception: JSValueRefRef) -> size_t;
pub unsafe fn JSObjectGetTypedArrayBytesPtr(ctx: JSContextRef, object: JSObjectRef, exception: JSValueRefRef) -> *const u8;
pub unsafe fn JSObjectSetProperty(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef, value: JSValueRef, attributes: JSPropertyAttributes, exception: JSValueRefRef);
- pub unsafe fn JSObjectMakeTypedArrayWithBytesNoCopy(ctx: JSContextRef, arrayType: JSTypedArrayType, bytes: *const u8, byteLength: usize, bytesDeallocator: JSTypedArrayBytesDeallocator, deallocatorContext: JSTypedArrayBytesDeallocatorContext, exception: JSValueRefRef) -> JSObjectRef;
+ pub unsafe fn JSObjectMakeTypedArrayWithBytesNoCopy(ctx: JSContextRef, arrayType: JSTypedArrayType, bytes: *const u8, byteLength: size_t, bytesDeallocator: JSTypedArrayBytesDeallocator, deallocatorContext: JSTypedArrayBytesDeallocatorContext, exception: JSValueRefRef) -> JSObjectRef;
pub unsafe fn JSContextGetGlobalObject(ctx: JSContextRef) -> JSObjectRef;
}
macro_rules! NULL { () => { std::ptr::null_mut() }; }
+unsafe fn read_file(filename: &str) -> (*mut u8, size_t) {
+ use std::fs::File;
+ use std::io::Read;
+
+ let mut file = File::open(filename).expect("Failed to open file");
+ let mut buffer = Vec::new();
+ file.read_to_end(&mut buffer).expect("Failed to read file");
+
+ let len = buffer.len();
+
+ unsafe {
+ let ptr = libc::malloc(len) as *mut u8;
+ if ptr.is_null() { panic!("malloc failed"); }
+
+ std::ptr::copy(buffer.as_ptr(), ptr, len);
+ std::mem::forget(buffer);
+
+ (ptr, len)
+ }
+}
+
+unsafe fn free_file(ptr: *mut u8) {
+ if !ptr.is_null() { unsafe { libc::free(ptr as *mut libc::c_void); } }
+}
+
pub struct JSC;
impl JSC {
pub fn JSEval(ctx: JSContextRef, script: &str) -> JSValueRef { unsafe {
- let script: JSStringRef = JSStringCreateWithUTF8CString(std::ffi::CString::new(script.as_bytes()).unwrap().as_ptr() as *const u8);
+ let cstr = std::ffi::CString::new(script).unwrap();
+ let script: JSStringRef = JSStringCreateWithUTF8CString(cstr.as_ptr());
let result: JSValueRef = JSEvaluateScript(ctx, script, NULL!(), NULL!(), 0, NULL!());
JSStringRelease(script);
result
} }
- pub fn JSEvaluateScript(ctx: JSContextRef, script: JSStringRef, thisObject: JSObjectRef, sourceURL: JSStringRef, startingLineNumber: i32, exception: JSValueRefRef) -> JSValueRef { unsafe {
- JSEvaluateScript(ctx, script, thisObject, sourceURL, startingLineNumber, exception)
- } }
pub fn JSGlobalContextCreate(globalObjectClass: JSClassRef) -> JSGlobalContextRef { unsafe {
JSGlobalContextCreate(globalObjectClass)
@@ -105,7 +130,8 @@ impl JSC {
} }
pub fn JSStringCreateWithUTF8CString(str: &str) -> JSStringRef { unsafe {
- JSStringCreateWithUTF8CString(std::ffi::CString::new(str.as_bytes()).unwrap().as_ptr() as *const u8)
+ let cstr = std::ffi::CString::new(str).unwrap();
+ JSStringCreateWithUTF8CString(cstr.as_ptr())
} }
pub fn JSStringRelease(string: JSStringRef) { unsafe {
JSStringRelease(string)
@@ -113,17 +139,18 @@ impl JSC {
pub fn JSCastStr(ctx: JSContextRef, value: JSValueRef) -> Result { unsafe {
match JSValueIsString(ctx, value) {
true => {
- /* TODO: this leaks memory -- `buf` must be freed and `str` must be JSStringRelease-d */
let str: JSStringRef = JSValueToStringCopy(ctx, value, NULL!());
- let sz: usize = JSStringGetMaximumUTF8CStringSize(str);
- let layout = std::alloc::Layout::array::(sz).unwrap();
- let buf = std::alloc::alloc(layout) as *mut u8;
+ let sz: size_t = JSStringGetMaximumUTF8CStringSize(str);
+ let buf = libc::malloc(sz) as *mut c_char;
match buf.is_null() {
true => Err(format!("Unable to allocate {} bytes", sz)),
false => {
let size = JSStringGetUTF8CString(str, buf, sz);
- let slice = std::slice::from_raw_parts(buf, size);
- String::from_utf8(slice.to_vec()).map_err(|e| format!("from_utf8 error {}", e))
+ let slice = std::slice::from_raw_parts(buf as *const u8, size);
+ let result = String::from_utf8(slice.to_vec()).map_err(|e| format!("from_utf8 error {}", e));
+ libc::free(buf as *mut libc::c_void);
+ JSStringRelease(str);
+ result
}
}
},
@@ -134,9 +161,6 @@ impl JSC {
pub fn JSObjectSetProperty(ctx: JSContextRef, object: JSObjectRef, propertyName: JSStringRef, value: JSValueRef, attributes: JSPropertyAttributes, exception: JSValueRefRef) { unsafe {
JSObjectSetProperty(ctx, object, propertyName, value, attributes, exception)
} }
- pub fn JSObjectMakeUint8Array(ctx: JSContextRef, data: Vec) -> JSObjectRef { unsafe {
- JSObjectMakeTypedArrayWithBytesNoCopy(ctx, kJSTypedArrayTypeUint8Array, data.as_ptr(), data.len(), NULL!(), NULL!(), NULL!())
- } }
pub fn JSContextGetGlobalObject(ctx: JSContextRef) -> JSObjectRef { unsafe {
JSContextGetGlobalObject(ctx)
@@ -155,7 +179,7 @@ impl JSC {
/* pull Uint8Array data back to Rust */
let u8: JSObjectRef = JSValueToObject(ctx, result, NULL!());
- let sz: usize = JSObjectGetTypedArrayLength(ctx, u8, NULL!());
+ let sz: size_t = JSObjectGetTypedArrayLength(ctx, u8, NULL!());
let buf: *const u8 = JSObjectGetTypedArrayBytesPtr(ctx, u8, NULL!());
std::slice::from_raw_parts(buf, sz).to_vec()
@@ -168,6 +192,8 @@ impl JSC {
fn main() {
+ let mut file_buf: *mut u8 = std::ptr::null_mut();
+ let mut file_len: size_t = 0;
/* initialize */
let ctx: JSGlobalContextRef = JSC::JSGlobalContextCreate(NULL!());
@@ -193,13 +219,15 @@ fn main() {
let mut iter = std::env::args();
let path: String = iter.nth(1).expect("must specify a file name");
- let file: Vec = std::fs::read(path.clone()).unwrap();
+ unsafe { (file_buf, file_len) = read_file(&path); }
/* push data to JSC */
- let u8: JSObjectRef = JSC::JSObjectMakeUint8Array(ctx, file);
+ unsafe {
+ let u8: JSObjectRef = JSObjectMakeTypedArrayWithBytesNoCopy(ctx, kJSTypedArrayTypeUint8Array, file_buf, file_len, None, std::ptr::null_mut(), NULL!());
- /* assign to `global.buf` */
- JSC::JSContextSetGlobalProperty(ctx, "buf", JSC::JSCastObjectToValue(u8));
+ /* assign to `global.buf` */
+ JSC::JSContextSetGlobalProperty(ctx, "buf", JSC::JSCastObjectToValue(u8));
+ }
}
/* parse workbook and print CSV */
@@ -225,4 +253,5 @@ fn main() {
}
JSC::JSGlobalContextRelease(ctx);
+ unsafe { free_file(file_buf); }
}
diff --git a/docz/static/v8/sheetjs-mini-racer.py b/docz/static/v8/sheetjs-mini-racer.py
new file mode 100644
index 0000000..1e58a6c
--- /dev/null
+++ b/docz/static/v8/sheetjs-mini-racer.py
@@ -0,0 +1,29 @@
+from sys import stderr, argv;
+from base64 import b64encode, b64decode;
+from py_mini_racer import MiniRacer;
+
+with open("xlsx.full.min.js", "rb") as f:
+ sheetjs = f.read().decode("utf-8");
+
+with open(argv[1], "rb") as f:
+ file_data = b64encode(f.read()).decode("ascii");
+
+ctx = MiniRacer();
+
+global_scope = ctx.eval("this");
+
+ctx.eval(sheetjs);
+version = ctx.eval("XLSX.version");
+print(f"SheetJS Version: {version}", file=stderr);
+
+ctx._ctx.set_object_item(global_scope, "fileData", file_data);
+ctx.eval("var wb = XLSX.read(fileData, {type:'base64'});");
+
+csv = ctx.eval("XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);");
+print(csv);
+
+xlsb = ctx.eval("XLSX.write(wb, {type: 'base64', bookType: 'xlsb'})");
+with open("SheetJSMiniRacer.xlsb", "wb") as f:
+ f.write(b64decode(xlsb));
+
+ctx.close();
\ No newline at end of file
diff --git a/tests/engines/javet.ps1 b/tests/engines/javet.ps1
new file mode 100644
index 0000000..4be5a18
--- /dev/null
+++ b/tests/engines/javet.ps1
@@ -0,0 +1,41 @@
+#!/usr/bin/env pwsh
+# https://docs.sheetjs.com/docs/demos/engines/v8#java
+
+$oldDir = Get-Location
+$tempDir = Join-Path -Path $env:TEMP -ChildPath "sheetjs-javet"
+if (Test-Path -Path $tempDir) { Remove-Item -Path $tempDir -Recurse -Force }
+New-Item -ItemType Directory -Path $tempDir | Out-Null
+Set-Location -Path $tempDir
+
+$javetVersion = "4.1.1"
+$javetBaseUrl = "https://repo1.maven.org/maven2/com/caoccao/javet"
+$osArtifact = "windows"
+$archArtifact = "x86_64"
+
+# Javet only provides x64 Windows builds. On ARM64 Windows, x64 Java
+# runs via Prism emulation. Ensure we have x64 Java in PATH.
+$javaInfo = Get-Command java -ErrorAction SilentlyContinue
+if (-not $javaInfo) { throw "Java not found in PATH" }
+$javaExe = $javaInfo.Source
+
+$javacInfo = Get-Command javac -ErrorAction SilentlyContinue
+if (-not $javacInfo) { throw "javac not found in PATH" }
+$javacExe = $javacInfo.Source
+
+Invoke-WebRequest -Uri "$javetBaseUrl/javet/$javetVersion/javet-$javetVersion.jar" -OutFile "javet-$javetVersion.jar"
+Invoke-WebRequest -Uri "$javetBaseUrl/javet-v8-$osArtifact-$archArtifact/$javetVersion/javet-v8-$osArtifact-$archArtifact-$javetVersion.jar" -OutFile "javet-v8-$osArtifact-$archArtifact-$javetVersion.jar"
+
+$version = "0.20.3"
+Invoke-WebRequest -Uri "https://cdn.sheetjs.com/xlsx-$version/package/dist/xlsx.full.min.js" -OutFile "xlsx.full.min.js"
+Invoke-WebRequest -Uri "https://docs.sheetjs.com/pres.xlsx" -OutFile "pres.xlsx"
+
+Invoke-WebRequest -Uri "https://docs.sheetjs.com/v8/SheetJSJavet.java" -OutFile "SheetJSJavet.java"
+
+& $javacExe -cp ".;javet-$javetVersion.jar;javet-v8-$osArtifact-$archArtifact-$javetVersion.jar" SheetJSJavet.java
+if ($LASTEXITCODE -ne 0) { throw "Compilation failed" }
+
+& $javaExe -cp ".;javet-$javetVersion.jar;javet-v8-$osArtifact-$archArtifact-$javetVersion.jar" SheetJSJavet pres.xlsx
+if ($LASTEXITCODE -ne 0) { throw "Java execution failed" }
+
+Set-Location $oldDir
+Remove-Item -Path $tempDir -Recurse -Force
\ No newline at end of file
diff --git a/tests/engines/javet.sh b/tests/engines/javet.sh
new file mode 100755
index 0000000..e8dc5b1
--- /dev/null
+++ b/tests/engines/javet.sh
@@ -0,0 +1,38 @@
+#!/bin/bash
+# https://docs.sheetjs.com/docs/demos/engines/v8#java
+
+cd /tmp
+rm -rf sheetjs-javet
+mkdir sheetjs-javet
+cd sheetjs-javet
+
+OS="$(uname -s)"
+ARCH="$(uname -m)"
+
+case "$OS" in
+ Darwin) OS_ARTIFACT="macos" ;;
+ Linux) OS_ARTIFACT="linux" ;;
+ *) echo "Unsupported OS: $OS" ; exit 1 ;;
+esac
+
+case "$ARCH" in
+ x86_64) ARCH_ARTIFACT="x86_64" ;;
+ aarch64|arm64) ARCH_ARTIFACT="arm64" ;;
+ *) echo "Unsupported architecture: $ARCH"; exit 1 ;;
+esac
+
+echo "Downloading Javet for $OS ($ARCH_ARTIFACT)..."
+
+JAVET_VERSION="4.1.1"
+JAVET_BASE_URL="https://repo1.maven.org/maven2/com/caoccao/javet"
+
+curl -LO "$JAVET_BASE_URL/javet/$JAVET_VERSION/javet-$JAVET_VERSION.jar"
+curl -LO "$JAVET_BASE_URL/javet-v8-$OS_ARTIFACT-$ARCH_ARTIFACT/$JAVET_VERSION/javet-v8-$OS_ARTIFACT-$ARCH_ARTIFACT-$JAVET_VERSION.jar"
+
+curl -LO "https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"
+curl -LO "https://docs.sheetjs.com/pres.xlsx"
+
+curl -LO "https://docs.sheetjs.com/v8/SheetJSJavet.java"
+
+javac -cp ".:javet-$JAVET_VERSION.jar:javet-v8-$OS_ARTIFACT-$ARCH_ARTIFACT-$JAVET_VERSION.jar" SheetJSJavet.java
+java -cp ".:javet-$JAVET_VERSION.jar:javet-v8-$OS_ARTIFACT-$ARCH_ARTIFACT-$JAVET_VERSION.jar" SheetJSJavet pres.xlsx
diff --git a/tests/engines/jsc-cpp.sh b/tests/engines/jsc-cpp.sh
new file mode 100755
index 0000000..da52ea1
--- /dev/null
+++ b/tests/engines/jsc-cpp.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+# https://docs.sheetjs.com/docs/demos/engines/jsc#c
+
+OS="$(uname -s)"
+ARCH="$(uname -m)"
+
+case "$OS" in
+ Darwin|Linux) ;;
+ *) echo "unsupported OS: $OS"; exit 1 ;;
+esac
+
+cd /tmp
+# rm -rf sheetjs-jsc
+mkdir -p sheetjs-jsc
+cd sheetjs-jsc
+
+if [[ ! -d "WebKit" ]]; then git clone https://github.com/WebKit/WebKit.git WebKit; fi
+
+cd WebKit
+git checkout "WebKit-7623.1.14.14.11"
+cd ..
+
+cd WebKit
+
+case "$OS" in
+ Darwin)
+ # NOTE: this was needed in WebKit-7623.1.14.14.11
+ perl -0777 -i -pe 's/#if HAVE\(MACH_EXCEPTIONS\).*?#endif\n*/\n/gs' "Source/JavaScriptCore/API/tests/ExecutionTimeLimitTest.cpp"
+
+ env CFLAGS="-Wno-error=all -Wno-deprecated-declarations -Wno-unused-parameter" \
+ CXXFLAGS="-Wno-error=all -Wno-deprecated-declarations -Wno-unused-parameter" \
+ LDFLAGS="-framework Foundation" \
+ Tools/Scripts/build-webkit --jsc-only \
+ --cmakeargs="-Wno-error=all -DENABLE_STATIC_JSC=ON -DCMAKE_C_FLAGS=\"-Wno-error=all -Wno-deprecated-declarations -Wno-unused-parameter\" -DCMAKE_CXX_FLAGS=\"-Wno-error=all -Wno-deprecated-declarations -Wno-unused-parameter\"" \
+ --make-args="-Wno-error=all -Wno-deprecated-declarations -Wno-unused-parameter" \
+ --no-jit \
+ --no-webassembly
+ ;;
+ Linux)
+ env CFLAGS="-Wno-error=all -Wno-error=volatile-register-var -Wno-dangling-reference" \
+ CXXFLAGS="-Wno-error=all -Wno-error=volatile-register-var -Wno-dangling-reference" \
+ Tools/Scripts/build-webkit --jsc-only \
+ --cmakeargs="-Wno-error=all -Wno-error=volatile-register-var -DENABLE_STATIC_JSC=ON -DUSE_THIN_ARCHIVES=OFF" \
+ --make-args="-j1 -Wno-error=all -Wno-error=volatile-register-var" \
+ -j1 \
+ --no-jit \
+ --no-webassembly
+ ;;
+esac
+
+cd ..
+
+ln -sfn WebKit/WebKitBuild/JSCOnly/Release Release
+
+curl -LO https://docs.sheetjs.com/jsc/sheetjs-jsc.c
+
+curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js
+curl -LO https://docs.sheetjs.com/pres.numbers
+
+case "$OS" in
+ Darwin) g++ -o sheetjs-jsc sheetjs-jsc.c -IRelease/JavaScriptCore/Headers -LRelease/lib -lbmalloc -licucore -lWTF -lJavaScriptCore -IRelease/JavaScriptCore/Headers -framework Foundation ;;
+ Linux) g++ -o sheetjs-jsc sheetjs-jsc.c -IRelease/JavaScriptCore/Headers -LRelease/lib -lJavaScriptCore -lWTF -lbmalloc -licui18n -licuuc -latomic -IRelease/JavaScriptCore/Headers ;;
+esac
+
+./sheetjs-jsc pres.numbers
+npx -y xlsx-cli sheetjsw.xlsb
diff --git a/tests/engines/jsc-rust.sh b/tests/engines/jsc-rust.sh
new file mode 100755
index 0000000..8bab96e
--- /dev/null
+++ b/tests/engines/jsc-rust.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+# https://docs.sheetjs.com/docs/demos/engines/jsc#rust-example
+
+set -e
+
+OS="$(uname -s)"
+ARCH="$(uname -m)"
+
+case "$OS" in
+ Darwin) PLATFORM="macos" ;;
+ Linux) PLATFORM="linux" ;;
+ *) echo "Unsupported OS: $OS" ; exit 1 ;;
+esac
+
+echo "Detected platform: $PLATFORM ($ARCH)"
+
+case "$PLATFORM" in
+ linux)
+ # This test requires the WebKit build from the C demo
+ cd /tmp
+ if [[ ! -d "sheetjs-jsc" ]]; then
+ echo "Please run the C demo from https://docs.sheetjs.com/docs/demos/engines/jsc#c"
+ exit 1
+ fi
+
+ cd sheetjs-jsc
+ if [[ ! -d "Release" ]]; then
+ echo "Please run the C demo from https://docs.sheetjs.com/docs/demos/engines/jsc#c"
+ exit 1
+ fi
+
+ cd /tmp
+ rm -rf sheetjs-jsc-rust
+ mkdir -p sheetjs-jsc-rust
+ cd sheetjs-jsc-rust
+
+ cargo new sheetjs-jsc-rust
+ cd sheetjs-jsc-rust
+ ;;
+
+ macos)
+ cd /tmp
+ rm -rf sheetjs-jsc-rust
+ mkdir -p sheetjs-jsc-rust
+ cd sheetjs-jsc-rust
+
+ cargo new sheetjs-jsc-rust
+ cd sheetjs-jsc-rust
+ ;;
+esac
+
+curl -L -o src/xlsx.full.min.js https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js
+curl -LO https://docs.sheetjs.com/pres.numbers
+curl -L -o src/main.rs https://docs.sheetjs.com/jsc/main.rs
+curl -L -o build.rs https://docs.sheetjs.com/jsc/build.rs
+
+cargo add libc
+cargo run --release -- pres.numbers
+npx -y xlsx-cli sheetjsw.xlsb
diff --git a/tests/engines/jsc-swift.sh b/tests/engines/jsc-swift.sh
new file mode 100755
index 0000000..d8de02f
--- /dev/null
+++ b/tests/engines/jsc-swift.sh
@@ -0,0 +1,88 @@
+#!/bin/bash
+# https://docs.sheetjs.com/docs/demos/engines/jsc#swift
+
+set -e
+
+OS="$(uname -s)"
+ARCH="$(uname -m)"
+
+if ! command -v swiftc &>/dev/null; then
+ echo "Error: Swift is not installed. Install from https://swift.org/download/"
+ exit 1
+fi
+echo "Swift version: $(swiftc --version)"
+
+case "$OS" in
+ Darwin)
+ cd /tmp
+ rm -rf sheetjswift
+ mkdir -p sheetjswift
+ cd sheetjswift
+
+ curl -sLO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js
+ curl -sLO https://docs.sheetjs.com/pres.numbers
+ curl -sLO https://docs.sheetjs.com/swift/SheetJSCore.swift
+ curl -sLO https://docs.sheetjs.com/swift/main.swift
+
+ swiftc SheetJSCore.swift main.swift -o SheetJSwift
+ ./SheetJSwift pres.numbers
+ npx -y xlsx-cli SheetJSwift.xlsx
+ ;;
+
+ Linux)
+ # This test requires the WebKit build from the C demo
+ cd /tmp
+ if [ ! -d "sheetjs-jsc" ]; then
+ echo "Please run the C demo from https://docs.sheetjs.com/docs/demos/engines/jsc#c"
+ exit 1
+ fi
+
+ cd sheetjs-jsc
+ if [ ! -d "Release" ]; then
+ echo "Please run the C demo from https://docs.sheetjs.com/docs/demos/engines/jsc#c"
+ exit 1
+ fi
+
+ rm -rf sheetjswift
+ mkdir -p sheetjswift
+ cd sheetjswift
+
+ curl -sLO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js
+ curl -sLO https://docs.sheetjs.com/pres.numbers
+
+ find ../WebKit/WebKitBuild/JSCOnly/Release/JavaScriptCore/Headers/ -name "*.h" -exec cp {} . \;
+
+ for f in *.h; do sed -i 's/ JavaScriptCore-Bridging-Header.h << EOF
+#import "${PWD_DIR}/JavaScript.h"
+EOF
+
+ cat > module.modulemap << EOF
+module JavaScriptCore {
+ header "./JavaScript.h"
+ link "JavaScriptCore"
+}
+EOF
+
+ curl -sLO https://docs.sheetjs.com/swift/SheetJSCRaw.swift
+
+ swiftc -Xcc -I$(pwd) \
+ -Xlinker -L../WebKit/WebKitBuild/JSCOnly/Release/lib/ \
+ -Xlinker -lJavaScriptCore \
+ -Xlinker -lWTF \
+ -Xlinker -lbmalloc \
+ -Xlinker -lstdc++ \
+ -Xlinker -latomic \
+ -Xlinker -licuuc \
+ -Xlinker -licui18n \
+ -import-objc-header JavaScriptCore-Bridging-Header.h \
+ SheetJSCRaw.swift -o SheetJSwift
+
+ ./SheetJSwift pres.numbers
+ npx -y xlsx-cli SheetJSwift.xlsx
+ ;;
+
+ *) echo "Unsupported OS: $OS"; exit 1 ;;
+esac
diff --git a/tests/engines/miniracer.ps1 b/tests/engines/miniracer.ps1
new file mode 100644
index 0000000..725dcb8
--- /dev/null
+++ b/tests/engines/miniracer.ps1
@@ -0,0 +1,27 @@
+#!/usr/bin/env pwsh
+# https://docs.sheetjs.com/docs/demos/engines/v8#python
+
+$oldDir = Get-Location
+$tempDir = Join-Path -Path $env:TEMP -ChildPath "sheetjs-miniracer"
+if (Test-Path -Path $tempDir) { Remove-Item -Path $tempDir -Recurse -Force }
+New-Item -ItemType Directory -Path $tempDir | Out-Null
+Set-Location -Path $tempDir
+
+pip install mini-racer 2>&1 | Out-Null
+if ($LASTEXITCODE -ne 0) {
+ python -m pip install mini-racer
+}
+
+Invoke-WebRequest -Uri "https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js" -OutFile "xlsx.full.min.js"
+Invoke-WebRequest -Uri "https://docs.sheetjs.com/pres.xlsx" -OutFile "pres.xlsx"
+Invoke-WebRequest -Uri "https://docs.sheetjs.com/v8/sheetjs-mini-racer.py" -OutFile "sheetjs-mini-racer.py"
+
+python sheetjs-mini-racer.py pres.xlsx
+if ($LASTEXITCODE -ne 0) { throw "Python script failed" }
+
+npm init -y
+npm i --save xlsx-cli
+.\node_modules\.bin\xlsx-cli SheetJSMiniRacer.xlsb
+
+Set-Location $oldDir
+Remove-Item -Path $tempDir -Recurse -Force
\ No newline at end of file
diff --git a/tests/engines/miniracer.sh b/tests/engines/miniracer.sh
new file mode 100755
index 0000000..dbcf643
--- /dev/null
+++ b/tests/engines/miniracer.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+# https://docs.sheetjs.com/docs/demos/engines/v8#python
+
+cd /tmp
+rm -rf sheetjs-miniracer
+mkdir sheetjs-miniracer
+cd sheetjs-miniracer
+
+python3 -m venv .
+source ./bin/activate
+pip3 install mini-racer 2>/dev/null || python3 -m pip install mini-racer
+
+curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js
+curl -LO https://docs.sheetjs.com/pres.xlsx
+
+curl -LO https://docs.sheetjs.com/v8/sheetjs-mini-racer.py
+
+python3 sheetjs-mini-racer.py pres.xlsx; echo $?
+
+npx -y xlsx-cli SheetJSMiniRacer.xlsb
\ No newline at end of file