diff --git a/docz/docs/03-demos/03-desktop/05-neutralino.md b/docz/docs/03-demos/03-desktop/05-neutralino.md
index 5f64237..06270b1 100644
--- a/docz/docs/03-demos/03-desktop/05-neutralino.md
+++ b/docz/docs/03-demos/03-desktop/05-neutralino.md
@@ -135,13 +135,13 @@ cd sheetjs-neu
curl -L -o resources/js/xlsx.full.min.js https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js
```
-3) Add the highlighted lines to `neutralino.conf.json` in `nativeAllowList`:
+3) Add the highlighted line to `neutralino.conf.json` in `nativeAllowList`:
```json title="neutralino.config.json"
"nativeAllowList": [
"app.*",
-// highlight-start
"os.*",
+// highlight-start
"filesystem.*",
// highlight-end
"debug.log"
diff --git a/docz/docs/03-demos/03-desktop/06-reactnative.md b/docz/docs/03-demos/03-desktop/06-reactnative.md
index 47313c0..c017562 100644
--- a/docz/docs/03-demos/03-desktop/06-reactnative.md
+++ b/docz/docs/03-demos/03-desktop/06-reactnative.md
@@ -1,5 +1,5 @@
---
-title: React Native for Desktop
+title: React Native
pagination_prev: demos/mobile/index
pagination_next: demos/cloud/index
sidebar_position: 6
diff --git a/docz/docs/03-demos/27-cli.md b/docz/docs/03-demos/27-cli.md
index aea7874..48daeed 100644
--- a/docz/docs/03-demos/27-cli.md
+++ b/docz/docs/03-demos/27-cli.md
@@ -1,5 +1,6 @@
---
title: Command-Line Tools
+pagination_next: demos/engines/index
---
import current from '/version.js';
diff --git a/docz/docs/03-demos/31-engines/01_duktape.md b/docz/docs/03-demos/31-engines/01_duktape.md
new file mode 100644
index 0000000..7d13dca
--- /dev/null
+++ b/docz/docs/03-demos/31-engines/01_duktape.md
@@ -0,0 +1,232 @@
+---
+title: C + Duktape
+pagination_prev: demos/cli
+pagination_next: demos/clipboard
+---
+
+Duktape is an embeddable JS engine written in C. It has been ported to a number
+of exotic architectures and operating systems.
+
+The [Standalone scripts](/docs/getting-started/installation/standalone) can be
+parsed and evaluated in a Duktape context.
+
+## Integration Details
+
+_Initialize Duktape_
+
+Duktape does not provide a `global` variable. It can be created in one line:
+
+```c
+/* initialize */
+duk_context *ctx = duk_create_heap_default();
+
+/* duktape does not expose a standard "global" by default */
+// highlight-next-line
+duk_eval_string_noresult(ctx, "var global = (function(){ return this; }).call(null);");
+```
+
+_Load SheetJS Scripts_
+
+The shim and main libraries can be loaded by reading the scripts from the file
+system and evaluating in the Duktape context:
+
+```c
+/* simple wrapper to read the entire script file */
+static duk_int_t eval_file(duk_context *ctx, const char *filename) {
+ size_t len;
+ /* read script from filesystem */
+ FILE *f = fopen(filename, "rb");
+ if(!f) { duk_push_undefined(ctx); perror("fopen"); return 1; }
+ long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); }
+ char *buf = (char *)malloc(fsize * sizeof(char));
+ len = fread((void *) buf, 1, fsize, f);
+ fclose(f);
+ if(!buf) { duk_push_undefined(ctx); perror("fread"); return 1; }
+
+ // highlight-start
+ /* load script into the context */
+ duk_push_lstring(ctx, (const char *)buf, (duk_size_t)len);
+ /* eval script */
+ duk_int_t retval = duk_peval(ctx);
+ /* cleanup */
+ duk_pop(ctx);
+ // highlight-end
+ return retval;
+}
+
+// ...
+ duk_int_t res = 0;
+
+ if((res = eval_file(ctx, "shim.min.js")) != 0) { /* error handler */ }
+ if((res = eval_file(ctx, "xlsx.full.min.js")) != 0) { /* error handler */ }
+```
+
+To confirm the library is loaded, `XLSX.version` can be inspected:
+
+```c
+ /* get version string */
+ duk_eval_string(ctx, "XLSX.version");
+ printf("SheetJS library version %s\n", duk_get_string(ctx, -1));
+ duk_pop(ctx);
+```
+
+### Reading Files
+
+Duktape supports `Buffer` natively but should be sliced before processing.
+Assuming `buf` is a C byte array, with length `len`, this snippet parses data:
+
+```c
+/* load C char array and save to a Buffer */
+duk_push_external_buffer(ctx);
+duk_config_buffer(ctx, -1, buf, len);
+duk_put_global_string(ctx, "buf");
+
+/* parse with SheetJS */
+duk_eval_string_noresult("workbook = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});");
+```
+
+`workbook` will be a variable in the JS environment that can be inspected using
+the various SheetJS API functions.
+
+### Writing Files
+
+`duk_get_buffer_data` can pull `Buffer` object data into the C code:
+
+```c
+/* write with SheetJS using type: "array" */
+duk_eval_string(ctx, "XLSX.write(workbook, {type:'array', bookType:'xlsx'})");
+
+/* pull result back to C */
+duk_size_t sz;
+char *buf = (char *)duk_get_buffer_data(ctx, -1, sz);
+
+/* discard result in duktape */
+duk_pop(ctx);
+```
+
+The resulting `buf` can be written to file with `fwrite`.
+
+## Complete Example
+
+:::note
+
+This demo was tested with Duktape `2.7.0` (`darwin-x64`) on 2023 February 12.
+
+:::
+
+This program parses a file and prints CSV data from the first worksheet. It also
+generates an XLSB file and writes to the filesystem.
+
+The [flow diagram is displayed after the example steps](#flow-diagram)
+
+0) Download and extract Duktape:
+
+```bash
+mkdir sheetjs-duk
+cd sheetjs-duk
+curl -LO https://duktape.org/duktape-2.7.0.tar.xz
+tar -xJf duktape-2.7.0.tar.xz
+mv duktape-2.7.0/src/*.{c,h} .
+```
+
+1) Download the standalone script, shim and test file:
+
+
+
+```bash
+curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/shim.min.js
+curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js
+curl -LO https://sheetjs.com/pres.numbers
+```
+
+2) Download [`sheetjs.duk.c`](pathname:///duk/sheetjs.duk.c):
+
+```bash
+curl -LO https://docs.sheetjs.com/duk/sheetjs.duk.c
+```
+
+3) Compile standalone `sheetjs.duk` binary
+
+```bash
+gcc -std=c99 -Wall -osheetjs.duk sheetjs.duk.c duktape.c -lm
+```
+
+4) Run the demo:
+
+```bash
+./sheetjs.duk 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.
+
+#### Flow Diagram
+
+```mermaid
+sequenceDiagram
+ participant F as Filesystem
+ participant C as C Code
+ participant D as Duktape
+ activate C
+ opt
+ Note over F,D: ~ Prepare Duktape ~
+ C->>+D: Initialize
+ deactivate C
+ D->>-C: Done
+ activate C
+ C->>F: Need SheetJS
+ F->>C: SheetJS Code
+ C->>+D: Load SheetJS Code
+ deactivate C
+ D->>-C: Loaded
+ activate C
+ C->>+D: Execute Code
+ deactivate C
+ Note over D: Eval SheetJS Code
+ D->>-C: Done
+ activate C
+ Note over D: XLSX
ready to rock
+ end
+ opt
+ Note over F,D: ~ Parse File ~
+ C->>F: Read Spreadsheet
+ F->>C: Spreadsheet File
+ C->>+D: Load Data
+ deactivate C
+ D->>-C: Loaded
+ activate C
+ C->>+D: eval `var workbook = XLSX.read(...)`
+ deactivate C
+ Note over D: Parse File
+ D->>-C: Done
+ activate C
+ Note over D: `workbook`
can be used later
+ end
+ opt
+ Note over F,D: ~ Print CSV to screen ~
+ C->>+D: eval `XLSX.utils.sheet_to_csv(...)`
+ deactivate C
+ Note over D: Generate CSV
+ D->>-C: CSV Data
+ activate C
+ Note over C: Print to standard output
+ end
+ opt
+ Note over F,D: ~ Write XLSB File ~
+ C->>+D: eval `XLSX.write(...)`
+ deactivate C
+ Note over D: Generate File
+ D->>-C: done
+ activate C
+ C->>+D: get file bytes
+ deactivate C
+ D->>-C: binary data
+ activate C
+ C->>F: Write File
+ end
+ deactivate C
+```
\ No newline at end of file
diff --git a/docz/docs/03-demos/31-engines/02_jsc.md b/docz/docs/03-demos/31-engines/02_jsc.md
new file mode 100644
index 0000000..097d6fa
--- /dev/null
+++ b/docz/docs/03-demos/31-engines/02_jsc.md
@@ -0,0 +1,163 @@
+---
+title: Swift + JavaScriptCore
+pagination_prev: demos/cli
+pagination_next: demos/clipboard
+---
+
+iOS and MacOS ship with the JavaScriptCore framework for running JS code from
+Swift and Objective-C. Hybrid function invocation is tricky, but explicit data
+passing is straightforward. The demo shows a standalone Swift sample for MacOS.
+
+The [Standalone scripts](/docs/getting-started/installation/standalone) can be
+parsed and evaluated in a JSC context.
+
+:::warning Platform Limitations
+
+JavaScriptCore is primarily deployed in MacOS and iOS applications. There is
+some experimental support through the Bun runtime, but production applications
+intending to support Windows / Linux / Android should try to embed V8.
+
+:::
+
+## Integration Details
+
+Binary strings can be passed back and forth using `String.Encoding.isoLatin1`.
+
+_Initialize JavaScriptCore_
+
+JSC does not provide a `global` variable. It can be created in one line:
+
+```swift
+var context: JSContext!
+do {
+ context = JSContext();
+ context.exceptionHandler = { _, X in if let e = X { print(e.toString()!); }; };
+ // highlight-next-line
+ context.evaluateScript("var global = (function(){ return this; }).call(null);");
+} catch { print(error.localizedDescription); }
+```
+
+_Load SheetJS Scripts_
+
+The main library can be loaded by reading the scripts from the file system and
+evaluating in the JSC context:
+
+```swift
+let src = try String(contentsOfFile: "xlsx.full.min.js");
+context.evaluateScript(src);
+```
+
+To confirm the library is loaded, `XLSX.version` can be inspected:
+
+```swift
+let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX");
+if let ver = XLSX.objectForKeyedSubscript("version") { print(ver.toString()); }
+```
+
+### Reading Files
+
+`String(contentsOf:encoding:)` reads from a path and returns an encoded string:
+
+```swift
+/* read sheetjs.xls as Base64 string */
+let file_path = shared_dir.appendingPathComponent("sheetjs.xls");
+let data: String! = try String(contentsOf: file_path, encoding: String.Encoding.isoLatin1);
+```
+
+This string can be loaded into the JS engine and processed:
+
+```swift
+/* load data in JSC */
+context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol));
+
+/* `payload` (the "forKeyedSubscript" parameter) is a binary string */
+context.evaluateScript("var wb = XLSX.read(payload, {type:'binary'});");
+```
+
+### Writing Files
+
+When writing to binary string in JavaScriptCore, the result should be stored in
+a variable and converted to string in Swift:
+
+```swift
+/* write to binary string */
+context.evaluateScript("var out = XLSX.write(wb, {type:'binary', bookType:'xlsx'})");
+
+/* `out` from the script is a binary string that can be stringified in Swift */
+let outvalue: JSValue! = context.objectForKeyedSubscript("out");
+var out: String! = outvalue.toString();
+```
+
+`String#write(to:atomically:encoding)` writes the string to the specified path:
+
+```swift
+/* write to sheetjsw.xlsx */
+let out_path = shared_dir.appendingPathComponent("sheetjsw.xlsx");
+try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLatin1);
+```
+
+## Complete Example
+
+:::note
+
+This demo was tested on 2023 February 12. `swift --version` printed:
+
+```
+swift-driver version: 1.62.15 Apple Swift version 5.7.2
+Target: x86_64-apple-macosx12.0
+```
+
+:::
+
+The demo includes a sample `SheetJSCore` Wrapper class to simplify operations.
+
+:::caution This demo only runs on MacOS
+
+This example requires MacOS + Swift and will not work on Windows or Linux!
+
+:::
+
+0) Ensure Xcode is installed. Create a folder for the project:
+
+```bash
+mkdir sheetjswift
+cd sheetjswift
+```
+
+1) Download the standalone script and the test file:
+
+
+
+```bash
+curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js
+curl -LO https://sheetjs.com/pres.numbers
+```
+
+2) Download the Swift scripts for the demo
+
+- [`SheetJSCore.swift`](pathname:///swift/SheetJSCore.swift) Wrapper library
+- [`main.swift`](pathname:///swift/main.swift) Command-line script
+
+```bash
+curl -LO https://docs.sheetjs.com/swift/SheetJSCore.swift
+curl -LO https://docs.sheetjs.com/swift/main.swift
+```
+
+
+3) Build the `SheetJSwift` binary:
+
+```bash
+swiftc SheetJSCore.swift main.swift -o SheetJSwift
+```
+
+4) Test the program:
+
+```bash
+./SheetJSwift pres.numbers
+```
+
+If successful, a CSV will be printed to console. The script also tries to write
+to `SheetJSwift.xlsx`. That file can be verified by opening in Excel / Numbers.
diff --git a/docz/docs/03-demos/31-engines/_category_.json b/docz/docs/03-demos/31-engines/_category_.json
new file mode 100644
index 0000000..f21164c
--- /dev/null
+++ b/docz/docs/03-demos/31-engines/_category_.json
@@ -0,0 +1,5 @@
+{
+ "label": "Other Languages",
+ "position": 31,
+ "collapsed": false
+}
\ No newline at end of file
diff --git a/docz/docs/03-demos/31-engines.md b/docz/docs/03-demos/31-engines/index.md
similarity index 69%
rename from docz/docs/03-demos/31-engines.md
rename to docz/docs/03-demos/31-engines/index.md
index 7a0e650..34a8b8e 100644
--- a/docz/docs/03-demos/31-engines.md
+++ b/docz/docs/03-demos/31-engines/index.md
@@ -1,11 +1,16 @@
---
title: JavaScript Engines
+pagination_prev: demos/cli
+pagination_next: demos/clipboard
---
import current from '/version.js';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
+Browser vendors and other organizations have built "JavaScript engines". They
+are independent software libraries that are capable of running JS scripts.
+
The most popular JavaScript engine is V8. Designed for embedding in software,
it powers Chrome, NodeJS, UXP, Deno and many other platforms.
@@ -14,6 +19,7 @@ for low-power or low-memory environments. Others aim for interoperability with
specific programming languages or environments. Typically they support ES3 and
are capable of running SheetJS code.
+This demo showcases a number of JS engines and language bindings.
## General Caveats
@@ -47,186 +53,19 @@ Base64 strings are safe for passing between JS and native code, but they should
only be used when there is no safe way to pass `ArrayBuffer` or `Uint8Array`.
-## Duktape
+## Engines
+
+This list is sorted in alphabetical order.
+
+### Duktape
Duktape is an embeddable JS engine written in C. It has been ported to a number
of exotic architectures and operating systems.
-**Reading data**
+This demo has been moved [to a dedicated page](/docs/demos/engines/duktape).
-Duktape supports `Buffer` natively but should be sliced before processing:
-```c
-/* parse a C char array as a workbook object */
-duk_push_external_buffer(ctx);
-duk_config_buffer(ctx, -1, buf, len);
-duk_put_global_string(ctx, "buf");
-duk_eval_string_noresult("workbook = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});");
-```
-
-**Writing data**
-
-`duk_get_buffer_data` can pull `Buffer` object data into the C code:
-
-```c
-/* write a workbook object to a C char array */
-duk_eval_string(ctx, "XLSX.write(workbook, {type:'array', bookType:'xlsx'})");
-duk_size_t sz;
-char *buf = (char *)duk_get_buffer_data(ctx, -1, sz);
-duk_pop(ctx);
-```
-
-Complete Example (click to show)
-
-:::note
-
-This demo was tested on Intel Mac (`darwin-x64`).
-
-:::
-
-0) Download and extract the latest release (2.7.0 at the time of writing)
-
-```bash
-curl -LO https://duktape.org/duktape-2.7.0.tar.xz
-tar -xJf duktape-2.7.0.tar.xz
-mv duktape-2.7.0/src/*.{c,h} .
-```
-
-1) Download the standalone script, shim and test file:
-
-
-
-2) Save the following script to `sheetjs.duk.c`:
-
-```c title="sheetjs.duk.c"
-/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
-#include
-#include
-#include
-#include "duktape.h"
-
-#define FAIL_LOAD { \
- duk_push_undefined(ctx); \
- perror("Error in load_file"); \
- return 1; \
-}
-
-static char *read_file(const char *filename, size_t *sz) {
- FILE *f = fopen(filename, "rb");
- if(!f) return NULL;
- long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); }
- char *buf = (char *)malloc(fsize * sizeof(char));
- *sz = fread((void *) buf, 1, fsize, f);
- fclose(f);
- return buf;
-}
-
-static duk_int_t eval_file(duk_context *ctx, const char *filename) {
- size_t len; char *buf = read_file(filename, &len);
- if(!buf) FAIL_LOAD
-
- duk_push_lstring(ctx, (const char *)buf, (duk_size_t)len);
- duk_int_t retval = duk_peval(ctx);
- duk_pop(ctx);
- return retval;
-}
-
-static duk_int_t load_file(duk_context *ctx, const char *filename, const char *var) {
- size_t len; char *buf = read_file(filename, &len);
- if(!buf) FAIL_LOAD
-
- duk_push_external_buffer(ctx);
- duk_config_buffer(ctx, -1, buf, len);
- duk_put_global_string(ctx, var);
- return 0;
-}
-
-static duk_int_t save_file(duk_context *ctx, const char *filename, const char *var) {
- duk_get_global_string(ctx, var);
- duk_size_t sz;
- char *buf = (char *)duk_get_buffer_data(ctx, -1, &sz);
-
- if(!buf) return 1;
- FILE *f = fopen(filename, "wb"); fwrite(buf, 1, sz, f); fclose(f);
- return 0;
-}
-
-#define FAIL(cmd) { \
- printf("error in %s: %s\n", cmd, duk_safe_to_string(ctx, -1)); \
- duk_destroy_heap(ctx); \
- return res; \
-}
-
-#define DOIT(cmd) duk_eval_string_noresult(ctx, cmd);
-int main(int argc, char *argv[]) {
- duk_int_t res = 0;
-
- /* initialize */
- duk_context *ctx = duk_create_heap_default();
- /* duktape does not expose a standard "global" by default */
- DOIT("var global = (function(){ return this; }).call(null);");
-
- /* load library */
- res = eval_file(ctx, "shim.min.js");
- if(res != 0) FAIL("shim load")
- res = eval_file(ctx, "xlsx.full.min.js");
- if(res != 0) FAIL("library load")
-
- /* get version string */
- duk_eval_string(ctx, "XLSX.version");
- printf("SheetJS library version %s\n", duk_get_string(ctx, -1));
- duk_pop(ctx);
-
- /* read file */
- res = load_file(ctx, argv[1], "buf");
- if(res != 0) FAIL("file load")
- printf("Loaded file %s\n", argv[1]);
-
- /* parse workbook */
- DOIT("wb = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});");
- DOIT("ws = wb.Sheets[wb.SheetNames[0]]");
-
- /* print CSV */
- duk_eval_string(ctx, "XLSX.utils.sheet_to_csv(ws)");
- printf("%s\n", duk_get_string(ctx, -1));
- duk_pop(ctx);
-
- /* write file */
-#define WRITE_TYPE(BOOKTYPE) \
- DOIT("newbuf = (XLSX.write(wb, {type:'array', bookType:'" BOOKTYPE "'}));");\
- res = save_file(ctx, "sheetjsw." BOOKTYPE, "newbuf");\
- if(res != 0) FAIL("save sheetjsw." BOOKTYPE)
-
- WRITE_TYPE("xlsb")
-
- /* cleanup */
- duk_destroy_heap(ctx);
- return res;
-}
-```
-
-3) Compile standalone `sheetjs.duk` binary
-
-```bash
-gcc -std=c99 -Wall -osheetjs.duk sheetjs.duk.c duktape.c -lm
-```
-
-4) Run the demo:
-
-```bash
-./sheetjs.duk 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.
-
-
-
-## Goja
+### Goja
Goja is a pure Go implementation of ECMAScript 5. It supports the standalone
scripts out of the box.
@@ -368,7 +207,7 @@ This will print the contents as a CSV to screen AND write to `sheetjsg.csv`
-## Hermes
+### Hermes
Hermes is an embeddable JS engine for React Native. The library and binary
distributions include a command-line tool `hermes` for running JS scripts.
@@ -439,107 +278,16 @@ hermes xlsx.hermes.js
-## JavaScriptCore
-:::warning Platform Limitations
-
-JavaScriptCore is primarily deployed in MacOS and iOS applications. There is
-some experimental support through the Bun runtime, but production applications
-intending to support Windows / Linux / Android should try to embed V8.
-
-:::
+### JavaScriptCore
iOS and MacOS ship with the JavaScriptCore framework for running JS code from
-Swift and Objective-C. Hybrid function invocation is tricky, but explicit data
-passing is straightforward. The demo shows a standalone Swift sample for MacOS.
+Swift and Objective-C.
-Binary strings can be passed back and forth using `String.Encoding.isoLatin1`.
+This demo has been moved [to a dedicated page](/docs/demos/engines/jsc).
-**Reading data**
-`String(contentsOf:encoding:)` reads from a path and returns an encoded string:
-
-```swift
-/* read sheetjs.xls as Base64 string */
-let file_path = shared_dir.appendingPathComponent("sheetjs.xls");
-let data: String! = try String(contentsOf: file_path, encoding: String.Encoding.isoLatin1);
-```
-
-This string can be loaded into the JS engine and processed:
-
-```swift
-/* load data in JSC */
-context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol));
-
-/* `payload` (the "forKeyedSubscript" parameter) is a binary string */
-context.evaluateScript("var wb = XLSX.read(payload, {type:'binary'});");
-```
-
-**Writing data**
-
-When writing to binary string in JavaScriptCore, the result should be stored in
-a variable and converted to string in Swift:
-
-```swift
-/* write to binary string */
-context.evaluateScript("var out = XLSX.write(wb, {type:'binary', bookType:'xlsx'})");
-
-/* `out` from the script is a binary string that can be stringified in Swift */
-let outvalue: JSValue! = context.objectForKeyedSubscript("out");
-var out: String! = outvalue.toString();
-```
-
-`String#write(to:atomically:encoding)` writes the string to the specified path:
-
-```swift
-/* write to sheetjsw.xlsx */
-let out_path = shared_dir.appendingPathComponent("sheetjsw.xlsx");
-try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLatin1);
-```
-
-The demo includes a sample `SheetJSCore` Wrapper class to simplify operations.
-
-Complete Example (click to show)
-
-:::caution This demo only runs on MacOS
-
-This example requires MacOS + Swift and will not work on Windows or Linux!
-
-:::
-
-0) Ensure Xcode is installed
-
-1) Download the standalone script, the shim and the test file:
-
-
-
-2) Download the Swift scripts for the demo
-
-- [`SheetJSCore.swift`](pathname:///swift/SheetJSCore.swift) Wrapper library
-- [`main.swift`](pathname:///swift/main.swift) Command-line script
-
-3) Build the `SheetJSwift` binary:
-
-```bash
-swiftc SheetJSCore.swift main.swift -o SheetJSwift
-```
-
-4) Test the program:
-
-```bash
-./SheetJSwift pres.numbers
-```
-
-If successful, a CSV will be printed to console. The script also tries to write
-to `SheetJSwift.xlsx`. That file can be verified by opening in Excel / Numbers.
-
-
-
-## JerryScript
+### JerryScript
JerryScript is a lightweight JavaScript engine designed for use in low-memory
environments like microcontrollers. As part of the build suite, the project
@@ -627,7 +375,8 @@ build/bin/jerry xlsx.jerry.js; echo $?
-## QuickJS
+
+### QuickJS
QuickJS is an embeddable JS engine written in C. It provides a separate set of
functions for interacting with the filesystem and the global object. It can run
@@ -686,7 +435,7 @@ If successful, the script will generate `SheetJSQuick.xlsx`.
-## Rhino
+### Rhino
Rhino is an ES3+ engine in Java. The `SheetJSRhino` class and `com.sheetjs`
package show a complete JAR deployment, including the full XLSX source.
diff --git a/docz/docs/03-demos/32-clipboard.md b/docz/docs/03-demos/32-clipboard.md
index 1210dbd..ae855da 100644
--- a/docz/docs/03-demos/32-clipboard.md
+++ b/docz/docs/03-demos/32-clipboard.md
@@ -1,5 +1,6 @@
---
title: Clipboard Data
+pagination_prev: demos/engines/index
---
Spreadsheet software like Excel typically support copying and pasting cells and
diff --git a/docz/docusaurus.config.js b/docz/docusaurus.config.js
index 9968cc2..c8749aa 100644
--- a/docz/docusaurus.config.js
+++ b/docz/docusaurus.config.js
@@ -173,6 +173,7 @@ const config = {
{ from: '/docs/getting-started/demos/excel', to: '/docs/demos/' },
{ from: '/docs/demos/content', to: '/docs/demos/static/' },
{ from: '/docs/demos/git', to: '/docs/demos/hosting/github/' },
+ { from: '/docs/demo/grid', to: '/docs/demos/grid/' },
/* frontend */
{ from: '/docs/demos/angular', to: '/docs/demos/frontend/angular/' },
{ from: '/docs/demos/react', to: '/docs/demos/frontend/react/' },
diff --git a/docz/static/duk/sheetjs.duk.c b/docz/static/duk/sheetjs.duk.c
new file mode 100644
index 0000000..14f89da
--- /dev/null
+++ b/docz/static/duk/sheetjs.duk.c
@@ -0,0 +1,104 @@
+/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
+#include
+#include
+#include
+#include "duktape.h"
+
+#define FAIL_LOAD { \
+ duk_push_undefined(ctx); \
+ perror("Error in load_file"); \
+ return 1; \
+}
+
+static char *read_file(const char *filename, size_t *sz) {
+ FILE *f = fopen(filename, "rb");
+ if(!f) return NULL;
+ long fsize; { fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); }
+ char *buf = (char *)malloc(fsize * sizeof(char));
+ *sz = fread((void *) buf, 1, fsize, f);
+ fclose(f);
+ return buf;
+}
+
+static duk_int_t eval_file(duk_context *ctx, const char *filename) {
+ size_t len; char *buf = read_file(filename, &len);
+ if(!buf) FAIL_LOAD
+
+ duk_push_lstring(ctx, (const char *)buf, (duk_size_t)len);
+ duk_int_t retval = duk_peval(ctx);
+ duk_pop(ctx);
+ return retval;
+}
+
+static duk_int_t load_file(duk_context *ctx, const char *filename, const char *var) {
+ size_t len; char *buf = read_file(filename, &len);
+ if(!buf) FAIL_LOAD
+
+ duk_push_external_buffer(ctx);
+ duk_config_buffer(ctx, -1, buf, len);
+ duk_put_global_string(ctx, var);
+ return 0;
+}
+
+static duk_int_t save_file(duk_context *ctx, const char *filename, const char *var) {
+ duk_get_global_string(ctx, var);
+ duk_size_t sz;
+ char *buf = (char *)duk_get_buffer_data(ctx, -1, &sz);
+
+ if(!buf) return 1;
+ FILE *f = fopen(filename, "wb"); fwrite(buf, 1, sz, f); fclose(f);
+ return 0;
+}
+
+#define FAIL(cmd) { \
+ printf("error in %s: %s\n", cmd, duk_safe_to_string(ctx, -1)); \
+ duk_destroy_heap(ctx); \
+ return res; \
+}
+
+#define DOIT(cmd) duk_eval_string_noresult(ctx, cmd);
+int main(int argc, char *argv[]) {
+ duk_int_t res = 0;
+
+ /* initialize */
+ duk_context *ctx = duk_create_heap_default();
+ /* duktape does not expose a standard "global" by default */
+ DOIT("var global = (function(){ return this; }).call(null);");
+
+ /* load library */
+ res = eval_file(ctx, "shim.min.js");
+ if(res != 0) FAIL("shim load")
+ res = eval_file(ctx, "xlsx.full.min.js");
+ if(res != 0) FAIL("library load")
+
+ /* get version string */
+ duk_eval_string(ctx, "XLSX.version");
+ printf("SheetJS library version %s\n", duk_get_string(ctx, -1));
+ duk_pop(ctx);
+
+ /* read file */
+ res = load_file(ctx, argv[1], "buf");
+ if(res != 0) FAIL("file load")
+ printf("Loaded file %s\n", argv[1]);
+
+ /* parse workbook */
+ DOIT("wb = XLSX.read(buf.slice(0, buf.length), {type:'buffer'});");
+ DOIT("ws = wb.Sheets[wb.SheetNames[0]]");
+
+ /* print CSV */
+ duk_eval_string(ctx, "XLSX.utils.sheet_to_csv(ws)");
+ printf("%s\n", duk_get_string(ctx, -1));
+ duk_pop(ctx);
+
+ /* write file */
+#define WRITE_TYPE(BOOKTYPE) \
+ DOIT("newbuf = (XLSX.write(wb, {type:'array', bookType:'" BOOKTYPE "'}));");\
+ res = save_file(ctx, "sheetjsw." BOOKTYPE, "newbuf");\
+ if(res != 0) FAIL("save sheetjsw." BOOKTYPE)
+
+ WRITE_TYPE("xlsb")
+
+ /* cleanup */
+ duk_destroy_heap(ctx);
+ return res;
+}