diff --git a/docz/docs/03-demos/01-math/index.md b/docz/docs/03-demos/01-math/index.md index bb097fb..92ecd3e 100644 --- a/docz/docs/03-demos/01-math/index.md +++ b/docz/docs/03-demos/01-math/index.md @@ -38,11 +38,10 @@ Under the hood, `ArrayBuffer` objects represent raw binary data. "Typed arrays" such as `Float64Array` and `Float32Array` are objects designed for efficient interpretation and mutation of `ArrayBuffer` data. - :::note pass -`ArrayBuffer` are roughly analogous to heap-allocated memory. Typed arrays -behave like typed pointers. +`ArrayBuffer` objects are roughly analogous to heap-allocated memory. Typed +arrays behave like typed pointers. **JavaScript** @@ -262,7 +261,7 @@ arrays of arrays. A single typed array can be converted to a pure JS array with `Array.from`: ```js -const arr = Array.from(column); +const arr = Array.from(row); ``` An array of arrays can be created from the array: diff --git a/docz/docs/03-demos/03-net/01-network/index.mdx b/docz/docs/03-demos/03-net/01-network/index.mdx index 7fc0380..a4184ec 100644 --- a/docz/docs/03-demos/03-net/01-network/index.mdx +++ b/docz/docs/03-demos/03-net/01-network/index.mdx @@ -386,7 +386,7 @@ https.get('https://sheetjs.com/pres.numbers', function(res) {
Complete Example (click to show) -:::note +:::note Tested Environments This demo was last tested on 2024 January 15 against NodeJS `20.11.0` @@ -433,7 +433,7 @@ async function parse_from_url(url) {
Complete Example (click to show) -:::note +:::note Tested Environments This demo was last tested on 2024 January 15 against NodeJS `20.11.0` @@ -512,7 +512,7 @@ request(url, {encoding: null}, function(err, res, data) {
Complete Example (click to show) -:::note +:::note Tested Environments This demo was last tested on 2024 January 15 against request `2.88.2` @@ -554,7 +554,7 @@ async function workbook_dl_axios(url) {
Complete Example (click to show) -:::note +:::note Tested Environments This demo was last tested on 2024 January 15 against Axios `1.6.5` diff --git a/docz/docs/03-demos/19-desktop/03-wails.md b/docz/docs/03-demos/19-desktop/03-wails.md index 2275757..c4bb330 100644 --- a/docz/docs/03-demos/19-desktop/03-wails.md +++ b/docz/docs/03-demos/19-desktop/03-wails.md @@ -301,7 +301,7 @@ This demo was tested in the following environments: | macOS 14.1.2 | `darwin-arm` | `v2.6.0` | 2023-12-01 | | Windows 10 | `win10-x64` | `v2.6.0` | 2023-12-09 | | Windows 11 | `win11-arm` | `v2.6.0` | 2023-12-01 | -| Linux (HoloOS) | `linux-x64` | `v2.6.0` | 2023-10-11 | +| Linux (HoloOS) | `linux-x64` | `v2.7.1` | 2024-01-22 | | Linux (Debian) | `linux-arm` | `v2.6.0` | 2023-12-01 | ::: diff --git a/docz/docs/03-demos/19-desktop/04-tauri.md b/docz/docs/03-demos/19-desktop/04-tauri.md index dd1b6e9..79ca192 100644 --- a/docz/docs/03-demos/19-desktop/04-tauri.md +++ b/docz/docs/03-demos/19-desktop/04-tauri.md @@ -261,7 +261,7 @@ This demo was tested in the following environments: | macOS 14.0 | `darwin-arm` | `v1.5.2` | 2023-10-18 | | Windows 10 | `win10-x64` | `v1.5.0` | 2023-10-01 | | Windows 11 | `win11-arm` | `v1.5.7` | 2023-12-01 | -| Linux (HoloOS) | `linux-x64` | `v1.5.2` | 2023-10-11 | +| Linux (HoloOS) | `linux-x64` | `v1.5.9` | 2024-01-23 | | Linux (Debian) | `linux-arm` | `v1.5.7` | 2023-12-01 | ::: diff --git a/docz/docs/03-demos/19-desktop/09-cli.md b/docz/docs/03-demos/19-desktop/09-cli.md index 57aea31..8560591 100644 --- a/docz/docs/03-demos/19-desktop/09-cli.md +++ b/docz/docs/03-demos/19-desktop/09-cli.md @@ -421,7 +421,7 @@ This demo was last tested in the following deployments: | `win10-x64` | `1.37.1` | 2023-10-09 | | `win11-x64` | `1.37.2` | 2023-10-14 | | `win11-arm` | `1.38.4` | 2023-12-01 | -| `linux-x64` | `1.37.1` | 2023-10-11 | +| `linux-x64` | `1.39.4` | 2024-01-22 | | `linux-arm` | `1.38.4` | 2023-12-01 | ::: diff --git a/docz/docs/03-demos/42-engines/05-jint.md b/docz/docs/03-demos/42-engines/05-jint.md index a9056f2..c1cc5b1 100644 --- a/docz/docs/03-demos/42-engines/05-jint.md +++ b/docz/docs/03-demos/42-engines/05-jint.md @@ -41,7 +41,7 @@ setting the environment variable on supported platforms. :::note pass Most of the integration functions are not documented. This explanation is based -on version `3.0.0-beta-2056`. +on version `3.0.0`. ::: @@ -108,7 +108,7 @@ byte[] buf = File.ReadAllBytes(filename); Jint natively supports `Uint8Array` construction from the byte array: ```csharp -Jint.Native.JsValue u8 = engine.Realm.Intrinsics.Uint8Array.Construct(buf); +Jint.Native.JsValue u8 = engine.Intrinsics.Uint8Array.Construct(buf); ``` `Jint.Engine#SetValue` will assign the `Uint8Array` to a scope variable in JS: @@ -163,11 +163,11 @@ This demo was tested in the following deployments: | Architecture | Jint Version | Date | |:-------------|:------------------|:-----------| -| `darwin-x64` | `3.0.0-beta-2055` | 2023-11-14 | +| `darwin-x64` | `3.0.0` | 2024-01-22 | | `darwin-arm` | `3.0.0-beta-2056` | 2023-12-01 | | `win10-x64` | `3.0.0-beta-2053` | 2023-10-28 | | `win11-arm` | `3.0.0-beta-2056` | 2023-12-01 | -| `linux-x64` | `3.0.0-beta-2052` | 2023-10-11 | +| `linux-x64` | `3.0.0` | 2024-01-22 | | `linux-arm` | `3.0.0-beta-2056` | 2023-12-01 | ::: @@ -211,10 +211,18 @@ Click "OK" in each window (3 windows) and restart your computer.
Installation Notes (click to show) -For macOS x64 and ARM64, install with Homebrew: `brew install dotnet@6` +For macOS x64 and ARM64, install the `dotnet-sdk` Cask with Homebrew: + +```bash +brew install --cask dotnet-sdk +``` For Steam Deck Holo and other Arch Linux x64 distributions, the `dotnet-sdk` and -`dotnet-runtime` packages should be installed using `pacman`. +`dotnet-runtime` packages should be installed using `pacman`: + +```bash +sudo pacman -Syu dotnet-sdk dotnet-runtime +``` is the official source for Windows and ARM64 Linux versions. @@ -230,7 +238,7 @@ for Windows and ARM64 Linux versions. ```bash mkdir SheetJSJint cd SheetJSJint -dotnet new console --framework net6.0 +dotnet new console dotnet run ``` @@ -238,7 +246,7 @@ dotnet run ```bash dotnet nuget add source https://www.myget.org/F/jint/api/v3/index.json -dotnet add package Jint --version 3.0.0-beta-2056 +dotnet add package Jint --version 3.0.0 ``` To verify Jint is installed, replace `Program.cs` with the following: @@ -309,7 +317,7 @@ Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version")); /* Read and Parse File */ byte[] filedata = File.ReadAllBytes(args[0]); -Jint.Native.JsValue u8 = engine.Realm.Intrinsics.Uint8Array.Construct(filedata); +Jint.Native.JsValue u8 = engine.Intrinsics.Uint8Array.Construct(filedata); engine.SetValue("buf", u8); engine.Evaluate("var wb = XLSX.read(buf);"); diff --git a/docz/docs/03-demos/42-engines/08-quickjs.md b/docz/docs/03-demos/42-engines/08-quickjs.md index b20635d..632324b 100644 --- a/docz/docs/03-demos/42-engines/08-quickjs.md +++ b/docz/docs/03-demos/42-engines/08-quickjs.md @@ -27,7 +27,7 @@ command-line tool for reading data from files. :::note pass Many QuickJS functions are not documented. The explanation was verified against -the latest release (commit `daa35bc`). +the latest release (commit `9e561d5`). ::: @@ -266,10 +266,10 @@ This demo was tested in the following deployments: | `darwin-arm` | `2788d71` | 2023-10-18 | | `win10-x64` | `daa35bc` | 2023-12-09 | | `win11-arm` | `03cc5ec` | 2023-12-01 | -| `linux-x64` | `03cc5ec` | 2023-12-07 | +| `linux-x64` | `9e561d5` | 2024-01-22 | | `linux-arm` | `03cc5ec` | 2023-12-01 | -When the demo was tested, commit `daa35bc` corresponded to the latest release. +When the demo was tested, commit `9e561d5` corresponded to the latest release. ::: @@ -285,7 +285,7 @@ tests were run entirely within Windows Subsystem for Linux. ```bash git clone https://github.com/bellard/quickjs cd quickjs -git checkout daa35bc +git checkout 9e561d5 make cd .. ``` @@ -342,10 +342,9 @@ This demo was tested in the following environments: | Git Commit | Date | |:-----------|:-----------| -| `daa35bc` | 2023-12-09 | -| `2788d71` | 2023-12-09 | +| `9e561d5` | 2024-01-22 | -When the demo was tested, commit `daa35bc` corresponded to the latest release. +When the demo was tested, commit `9e561d5` corresponded to the latest release. ::: @@ -354,7 +353,7 @@ When the demo was tested, commit `daa35bc` corresponded to the latest release. ```bash git clone https://github.com/bellard/quickjs cd quickjs -git checkout daa35bc +git checkout 9e561d5 make cd .. cp quickjs/qjs . diff --git a/docz/docs/03-demos/42-engines/20-chakra.md b/docz/docs/03-demos/42-engines/20-chakra.md index e51312a..902c635 100644 --- a/docz/docs/03-demos/42-engines/20-chakra.md +++ b/docz/docs/03-demos/42-engines/20-chakra.md @@ -16,8 +16,8 @@ ChakraCore is an embeddable JS engine written in C++. [SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing data from spreadsheets. -This demo uses Hermes and SheetJS to pull data from a spreadsheet and print CSV -rows. We'll explore how to load SheetJS in a ChakraCore context and process +This demo uses ChakraCore and SheetJS to pull data from a spreadsheet and print +CSV rows. We'll explore how to load SheetJS in a ChakraCore context and process spreadsheets from a C++ program. The ["Integration Example"](#integration-example) section includes a complete diff --git a/docz/docs/03-demos/42-engines/23-jerryscript.md b/docz/docs/03-demos/42-engines/23-jerryscript.md new file mode 100644 index 0000000..ba7aa3d --- /dev/null +++ b/docz/docs/03-demos/42-engines/23-jerryscript.md @@ -0,0 +1,473 @@ +--- +title: C + JerryScript +pagination_prev: demos/bigdata/index +pagination_next: solutions/input +--- + +import current from '/version.js'; +import CodeBlock from '@theme/CodeBlock'; + +[JerryScript](https://jerryscript.net/) is a lightweight JavaScript engine. It +is designed for microcontrollers and similar environments. + +[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing +data from spreadsheets. + +This demo uses JerryScript and SheetJS to pull data from a spreadsheet and print +CSV rows. We'll explore how to load SheetJS in a JerryScript realm and process +spreadsheets from C programs. + +The ["Integration Example"](#integration-example) section includes a complete +command-line tool for reading data from files. + +:::caution pass + +This demo requires a much larger heap size than is normally used in JerryScript +deployments! In local testing, the following sizes were needed: + +- 8192 (8M) for +- 65536 (64M) for + +::: + +:::note Tested Environments + +This demo was tested in the following environments: + +| Architecture | Commit | Date | +|:-------------|:----------|:-----------| +| `darwin-x64` | `514fa67` | 2024-01-22 | +| `darwin-arm` | `ef4cb2b` | 2023-12-08 | +| `win11-x64` | `ef4cb2b` | 2023-12-08 | +| `win11-arm` | `ef4cb2b` | 2023-12-08 | +| `linux-x64` | `ef4cb2b` | 2023-12-08 | +| `linux-arm` | `ef4cb2b` | 2023-12-08 | + +The Windows tests were run in WSL. + +Debian and WSL require the `cmake`, `python3` and `python-is-python3` packages. + +::: + +## Integration Details + +:::info pass + +The official JerryScript documentation and examples are out of date. This +explanation was verified against the latest release (commit `514fa67`). + +::: + +### Initialize JerryScript + +The global engine instance can be initialized with `jerry_init` and cleaned up +with `jerry_cleanup`: + +```c +#include "jerryscript.h" + +int main (int argc, char **argv) { + /* Initialize engine */ +/* highlight-next-line */ + jerry_init(JERRY_INIT_EMPTY); + + // ... use engine methods ... + + /* cleanup before exiting */ +/* highlight-next-line */ + jerry_cleanup(); + return 0; +} +``` + +API methods use `jerry_value_t` values to represent JS values and miscellany. +Values representing errors can be distinguished using `jerry_value_is_error`. +`jerry_value_t` values can be freed with `jerry_value_free`. + +### Evaluate Code + +Evaluating code involves two steps: + +- `jerry_parse` will parse the script +- `jerry_run` will run the parsed script object + +:::note pass + +The return value of `jerry_parse` is a `jerry_value_t` value that can be safely +freed after `jerry_run`. + +::: + +The following `eval_str` function parses and executes scripts. If parsing fails, +the function will return the parsing error. If parsing succeeds, the function +will return the result of executing the code. + +```c +jerry_value_t eval_str(const char *code, size_t sz) { + /* try to parse code */ + jerry_value_t parsed = jerry_parse(code, sz, NULL); + /* return the parse error if parsing failed */ + if(jerry_value_is_error(parsed)) return parsed; + + /* run the code */ + jerry_value_t out = jerry_run(parsed); + /* free the parsed representation */ + jerry_value_free(parsed); + + /* return the result */ + return out; +} +``` + +### Load SheetJS Scripts + +[SheetJS Standalone scripts](/docs/getting-started/installation/standalone) can +be parsed and run in JerryScript. + +Scripts can be read from the filesystem using standard C functions: + +```c +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) - 1; + fclose(f); + return buf; +} +``` + +The shim script must be evaluated before the main library. In both cases, after +reading the script file, the previous `eval_str` function can run the code: + +```c + /* evaluate shim.min.js */ + { + size_t sz; const jerry_char_t *script = (jerry_char_t *)read_file("shim.min.js", &sz); + jerry_value_t result = eval_str(script, sz); + if(jerry_value_is_error(result)) { // failed to parse / execute + fprintf(stderr, "Failed to evaluate shim.min.js"); return 1; + } + jerry_value_free(result); + } + + /* evaluate xlsx.full.min.js */ + { + size_t sz; const jerry_char_t *script = (jerry_char_t *)read_file("xlsx.full.min.js", &sz); + jerry_value_t result = eval_str(script, sz); + if(jerry_value_is_error(result)) { // failed to parse / execute + fprintf(stderr, "Failed to evaluate xlsx.full.min.js"); return 1; + } + jerry_value_free(result); + } +``` + +### Reading Files + +Binary file data can be passed from C to JerryScript with `ArrayBuffer` objects. + +#### Creating ArrayBuffers + +`jerry_arraybuffer` will generate an `ArrayBuffer` object of specified length. +After creating the array, `jerry_arraybuffer_write` will copy data. + +The following `load_file` function reads a file from the filesystem and loads +the data into an `ArrayBuffer`: + +```c +static jerry_value_t load_file(const char *filename) { + /* read file */ + size_t len; char *buf = read_file(filename, &len); + if(!buf) return 0; + + /* create ArrayBuffer */ + jerry_value_t out = jerry_arraybuffer(len); + /* copy file data into ArrayBuffer */ + jerry_arraybuffer_write(out, 0, (const uint8_t*)buf, len); + return out; +} +``` + +The process may fail. The result should be tested with `jerry_value_is_error`: + +```c + jerry_value_t ab = load_file("pres.xlsx"); + if(!ab || jerry_value_is_error(ab)) { // failed to create ArrayBuffer + fprintf(stderr, "Failed to read pres.xlsx"); return 1; + } +``` + +#### Creating Global Variable + +The `ArrayBuffer` object must be bound to a variable before it can be used. + +:::note pass + +The goal is to bind the `ArrayBuffer` to the `buf` property in global scope. + +::: + +1) Get the global `this` variable (using `jerry_current_realm`): + +```c + /* get the global variable */ + jerry_value_t this = jerry_current_realm(); + if(jerry_value_is_error(this)) { // failed to get global object + fprintf(stderr, "Failed to get global object"); return 1; + } +``` + +2) Create a JerryScript string (`"buf"`) for the property: + +```c + /* create a string "buf" for the property access */ + jerry_value_t prop = jerry_string_sz("buf"); + if(jerry_value_is_error(this)) { // failed to create "buf" + fprintf(stderr, "Failed to create string"); return 1; + } +``` + +3) Assign the property using `jerry_object_set`: + +```c + /* set global["buf"] to the ArrayBuffer */ + jerry_value_t set = jerry_object_set(this, prop, ab); + if(jerry_value_is_error(set)) { // failed to set property + fprintf(stderr, "Failed to assign ArrayBuffer"); return 1; + } +``` + +#### Parsing Data + +:::note pass + +The goal is to run the equivalent of the following JavaScript code: + +```js +/* `buf` is the `ArrayBuffer` from the previous step */ +var wb = XLSX.read(buf); +``` + +::: + +The `ArrayBuffer` from the previous step is available in the `buf` variable. +That `ArrayBuffer` can be passed to the SheetJS `read` method[^1], which will +parse the raw data and return a SheetJS workbook object[^2]. + +`var wb = XLSX.read(buf)` can be stored in a byte array and evaluated directly: + +```c + /* run `var wb = XLSX.read(buf)` */ + { + const jerry_char_t code[] = "var wb = XLSX.read(buf);"; + jerry_value_t result = eval_str(code, sizeof(code) - 1); + if(jerry_value_is_error(result)) { + fprintf(stderr, "Failed to parse file"); return 1; + } + jerry_value_free(result); + } +``` + +#### Generating CSV + +:::note pass + +The goal is to run the equivalent of the following JavaScript code: + +```js +/* `wb` is the workbook from the previous step */ +XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]) +``` + +::: + +A SheetJS workbook object can contain multiple sheet objects[^3]. The `Sheets` +property is an object whose keys are sheet names and whose values are sheet +objects. The `SheetNames` property is an array of worksheet names. + +The first sheet name can be found at `wb.SheetNames[0]`. The first sheet object +can be found at `wb.Sheets[wb.SheetNames[0]]`. + +The SheetJS `sheet_to_csv` utility function[^4] accepts a sheet object and +generates a JS string. + +Combining everything, `XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])` +generates a CSV string based on the first worksheet in the workbook `wb`: + +```c + const jerry_char_t code[] = "XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])"; + jerry_value_t csv = eval_str(code, sizeof(code) - 1); + if(jerry_value_is_error(result)) { // CSV generation failed + fprintf(stderr, "Failed to generate csv"); return 1; + } +``` + +#### Pulling Strings + +JerryScript exposes encoding-aware methods to pull JS strings into C. The +`JERRY_ENCODING_UTF8` encoding forces UTF8 interpretations. + +The `jerry_string_size` function returns the number of bytes required to store +the string. After allocating memory, `jerry_string_to_buffer` will copy data. +The following `pull_str` function uses `malloc`: + +```js +char *pull_str(jerry_value_t str, size_t *sz) { + /* determine string size in bytes */ + jerry_size_t str_sz = jerry_string_size(str, JERRY_ENCODING_UTF8); + + /* allocate memory */ + jerry_char_t *buf = (jerry_char_t *)malloc(str_sz + 1); + + /* copy from JS string to C byte array */ + jerry_string_to_buffer(str, JERRY_ENCODING_UTF8, buf, str_sz + 1); + + /* pass back size and return the pointer */ + *sz = str_sz; + return (char *)buf; +} +``` + +This function can be used to pull the `csv` value from the previous section: + +```c + size_t sz; char *buf = pull_str(result, &sz); + printf("%s\n", buf); +``` + +## Complete Example + +The "Integration Example" covers a traditional integration in a C application, +while the "CLI Test" demonstrates other concepts using the `jerry` CLI tool. + +### Integration Example + +1) Create a project folder: + +```bash +mkdir SheetJSJerry +cd SheetJSJerry +``` + +2) Clone the repository and build the library with required options: + +```bash +git clone --depth=1 https://github.com/jerryscript-project/jerryscript.git +cd jerryscript +python tools/build.py --error-messages=ON --logging=ON --mem-heap=8192 --cpointer-32bit=ON +cd .. +``` + +3) Download the SheetJS Standalone script, shim script and test file. Move all +three files to the `SheetJSJerry` directory: + + + +{`\ +curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js +curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js +curl -LO https://sheetjs.com/pres.xlsx`} + + +4) Download [`sheetjs.jerry.c`](pathname:///jerryscript/sheetjs.jerry.c) into +the same folder: + +```bash +curl -LO https://docs.sheetjs.com/jerryscript/sheetjs.jerry.c +``` + +5) Build the sample application: + +```bash +gcc -o sheetjs.jerry -Ijerryscript/jerry-ext/include -Ijerryscript/jerry-math/include -Ijerryscript/jerry-core/include -ljerry-ext -ljerry-port -ljerry-core -Ljerryscript/build/lib sheetjs.jerry.c -Wno-pointer-sign +``` + +6) Run the test program: + +```bash +./sheetjs.jerry pres.xlsx +``` + +If successful, the program will print contents of the first sheet as CSV rows. + +### CLI Test + +:::note pass + +Due to limitations of the standalone binary, this demo will encode a test file +as a Base64 string and directly add it to an amalgamated script. + +::: + +0) Build the library and command line tool with required options: + +```bash +git clone --depth=1 https://github.com/jerryscript-project/jerryscript.git +cd jerryscript +python tools/build.py --error-messages=ON --logging=ON --mem-heap=8192 --cpointer-32bit=ON +``` + +1) Download the SheetJS Standalone script, shim script and test file. Move all +three files to the `jerryscript` cloned repo directory: + + + +{`\ +curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js +curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js +curl -LO https://sheetjs.com/pres.xlsx`} + + +2) Bundle the test file and create `payload.js`: + +```bash +node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.xlsx').toString('base64') + '\";')" +``` + +3) Create support scripts: + +- `global.js` creates a `global` variable and defines a fake `console`: + +```js title="global.js" +var global = (function(){ return this; }).call(null); +var console = { log: function(x) { print(x); } }; +``` + +- `jerry.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`: + +```js title="jerry.js" +var wb = XLSX.read(payload, {type:'base64'}); +console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])); +``` + +4) Create the amalgamation `xlsx.jerry.js`: + +```bash +cat global.js xlsx.full.min.js payload.js jerry.js > xlsx.jerry.js +``` + +The final script defines `global` before loading the standalone library. Once +ready, it will read the bundled test data and print the contents as CSV. + +5) Run the script using the `jerry` standalone binary: + +```bash +build/bin/jerry xlsx.jerry.js; echo $? +``` + +If successful, the contents of the test file will be displayed in CSV rows. The +status code `0` will be printed after the rows. + +[^1]: See [`read` in "Reading Files"](/docs/api/parse-options) +[^2]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) +[^3]: See ["Sheet Objects"](/docs/csf/sheet) +[^4]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output) diff --git a/docz/docs/03-demos/42-engines/index.md b/docz/docs/03-demos/42-engines/index.md index d99d67e..96b736a 100644 --- a/docz/docs/03-demos/42-engines/index.md +++ b/docz/docs/03-demos/42-engines/index.md @@ -26,7 +26,7 @@ This demo showcases a number of JS engines and language bindings. Common browser and NodeJS APIs are often missing from light-weight JS engines. -**Global** +#### Global Some engines do not provide `globalThis` or `global` or `window`. A `global` variable can be exposed in one line that should be run in the JS engine: @@ -35,16 +35,17 @@ variable can be exposed in one line that should be run in the JS engine: var global = (function(){ return this; }).call(null); ``` -**Console** +#### Console -Some engines do not provide a `console` object. `console.log` can be shimmed -using the engine functionality. For example, `hermes`[^1] provides `print()`: +Some engines do not provide a `console` object but offer other ways to print to +standard output. For example, Hermes[^1] provides `print()`. A `console` object +should be created using the engine print function: ```js var console = { log: function(x) { print(x); } }; ``` -**Binary Data** +#### Binary Data Some engines do not provide easy ways to exchange binary data. For example, it is common to pass null-terminated arrays, which would truncate XLSX, XLS, and @@ -53,7 +54,7 @@ other exports. APIs that accept pointers without length should be avoided. 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`. -**Byte Conventions** +#### Byte Conventions Java has no native concept of unsigned bytes. Values in a `byte[]` are limited to the range `-128 .. 127`. They need to be fixed within the JS engine. @@ -116,123 +117,12 @@ Swift and Objective-C. This demo has been moved [to a dedicated page](/docs/demos/engines/jsc). - ### JerryScript JerryScript is a lightweight JavaScript engine designed for use in low-memory -environments like microcontrollers. As part of the build suite, the project -generates a C library and a standalone CLI tool. +environments including microcontrollers. -The simplest way to interact with the engine is to pass Base64 strings. - -:::note Tested Environments - -This demo was tested in the following environments: - -| Architecture | Commit | Date | -|:-------------|:----------|:-----------| -| `darwin-x64` | `ef4cb2b` | 2023-12-08 | -| `darwin-arm` | `ef4cb2b` | 2023-12-08 | -| `win11-x64` | `ef4cb2b` | 2023-12-08 | -| `win11-arm` | `ef4cb2b` | 2023-12-08 | -| `linux-x64` | `ef4cb2b` | 2023-12-08 | -| `linux-arm` | `ef4cb2b` | 2023-12-08 | - -The Windows tests were run in WSL. - -Debian and WSL require the `cmake`, `python3` and `python-is-python3` packages. - -::: - -:::note pass - -While applications should link against the official libraries, the standalone tool -is useful for verifying functionality. - -::: - -:::caution pass - -This demo requires a much larger heap size than is normally used in JerryScript -deployments! In local testing, the following sizes were needed: - -- 8192 (8M) for -- 65536 (64M) for - -This works on a Raspberry Pi. - -::: - -
Complete Example (click to show) - -Due to limitations of the standalone binary, this demo will encode a test file -as a Base64 string and directly add it to an amalgamated script. - -0) Build the library and command line tool with required options: - -```bash -git clone --depth=1 https://github.com/jerryscript-project/jerryscript.git -cd jerryscript -python tools/build.py --error-messages=ON --logging=ON --mem-heap=8192 --cpointer-32bit=ON -``` - -1) Download the SheetJS Standalone script, shim script and test file. Move all -three files to the `jerryscript` cloned repo directory: - - - -{`\ -curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js -curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.full.min.js -curl -LO https://sheetjs.com/pres.xlsx`} - - -2) Bundle the test file and create `payload.js`: - -```bash -node -e "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('pres.xlsx').toString('base64') + '\";')" -``` - -3) Create support scripts: - -- `global.js` creates a `global` variable and defines a fake `console`: - -```js title="global.js" -var global = (function(){ return this; }).call(null); -var console = { log: function(x) { print(x); } }; -``` - -- `jerry.js` will call `XLSX.read` and `XLSX.utils.sheet_to_csv`: - -```js title="jerry.js" -/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */ -var wb = XLSX.read(payload, {type:'base64'}); -console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])); -``` - -4) Create the amalgamation `xlsx.jerry.js`: - -```bash -cat global.js xlsx.full.min.js payload.js jerry.js > xlsx.jerry.js -``` - -The final script defines `global` before loading the standalone library. Once -ready, it will read the bundled test data and print the contents as CSV. - -5) Run the script using the `jerry` standalone binary: - -```bash -build/bin/jerry xlsx.jerry.js; echo $? -``` - -If successful, the contents of the test file will be displayed in CSV rows. The -status code `0` will be printed after the rows. - -
+This demo has been moved [to a dedicated page](/docs/demos/engines/jerryscript). ### Jint @@ -240,14 +130,12 @@ Jint is an embeddable JS engine for .NET written in C#. This demo has been moved [to a dedicated page](/docs/demos/engines/jint). - ### Nashorn Nashorn shipped with some versions of Java. It is now a standalone library. This demo has been moved [to a dedicated page](/docs/demos/engines/nashorn). - ### QuickJS QuickJS is an embeddable JS engine written in C. It provides a separate set of @@ -256,14 +144,12 @@ the standalone browser scripts. This demo has been moved [to a dedicated page](/docs/demos/engines/quickjs). - ### Rhino Rhino is an ES3+ engine in Java. This demo has been moved [to a dedicated page](/docs/demos/engines/rhino). - ### V8 V8 is an embeddable JS engine written in C++. It powers Chromium and Chrome, diff --git a/docz/static/jerryscript/sheetjs.jerry.c b/docz/static/jerryscript/sheetjs.jerry.c new file mode 100644 index 0000000..242a4f7 --- /dev/null +++ b/docz/static/jerryscript/sheetjs.jerry.c @@ -0,0 +1,143 @@ +#include +#include + +#include "jerryscript.h" + +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) - 1; + fclose(f); + return buf; +} + +jerry_value_t eval_str(const char *code, size_t sz) { + jerry_value_t parsed = jerry_parse(code, sz, NULL); + if(jerry_value_is_error(parsed)) return parsed; + + jerry_value_t out = jerry_run(parsed); + jerry_value_free(parsed); + + return out; +} + +static jerry_value_t load_file(const char *filename) { + size_t len; char *buf = read_file(filename, &len); + if(!buf) return 0; + + jerry_value_t out = jerry_arraybuffer(len); + jerry_arraybuffer_write(out, 0, (const uint8_t*)buf, len); + return out; +} + +char *pull_str(jerry_value_t str, size_t *sz) { + jerry_size_t str_sz = jerry_string_size(str, JERRY_ENCODING_UTF8); + jerry_char_t *buf = (jerry_char_t *)malloc(str_sz + 1); + jerry_string_to_buffer(str, JERRY_ENCODING_UTF8, buf, str_sz + 1); + *sz = str_sz; + return (char *)buf; +} + +int main (int argc, char **argv) { + int res = 0; + + /* Initialize engine */ + jerry_init(JERRY_INIT_EMPTY); + + /* evaluate shim.min.js */ + { + size_t sz; const jerry_char_t *script = (jerry_char_t *)read_file("shim.min.js", &sz); + jerry_value_t result = eval_str(script, sz); + if(jerry_value_is_error(result)) { + fprintf(stderr, "Failed to evaluate shim.min.js"); + res = 1; + goto cleanup; + } + + jerry_value_free(result); + } + + /* evaluate xlsx.full.min.js */ + { + size_t sz; const jerry_char_t *script = read_file("xlsx.full.min.js", &sz); + jerry_value_t result = eval_str(script, sz); + if(jerry_value_is_error(result)) { + fprintf(stderr, "Failed to evaluate xlsx.full.min.js"); + res = 2; + goto cleanup; + } + + jerry_value_free(result); + } + + /* load spreadsheet */ + jerry_value_t ab = load_file(argv[1]); + if(!ab || jerry_value_is_error(ab)) { + fprintf(stderr, "Failed to read %s", argv[1]); + res = 3; + goto exeunt; + } + + /* assign to `buf` in the global scope */ + { + /* get `this` */ + jerry_value_t this = jerry_current_realm(); + if(jerry_value_is_error(this)) { + fprintf(stderr, "Failed to get global object"); + res = 4; + goto exeunt; + } + + /* create "buf" str */ + jerry_value_t prop = jerry_string_sz("buf"); + if(jerry_value_is_error(this)) { + fprintf(stderr, "Failed to create string"); + res = 5; + goto exeunt; + } + + /* equivalent of `this["buf"] = buf` */ + jerry_value_t set = jerry_object_set(this, prop, ab); + if(jerry_value_is_error(set)) { + fprintf(stderr, "Failed to assign ArrayBuffer"); + res = 6; + goto exeunt; + } + } + + /* run `var wb = XLSX.read(buf)` */ + { + const jerry_char_t code[] = "var wb = XLSX.read(buf);"; + jerry_value_t result = eval_str(code, sizeof(code) - 1); + if(jerry_value_is_error(result)) { + fprintf(stderr, "Failed to parse file"); + res = 7; + goto exeunt; + } + jerry_value_free(result); + } + + /* run `XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])` and print result */ + { + const jerry_char_t code[] = "XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]])"; + jerry_value_t result = eval_str(code, sizeof(code) - 1); + if(jerry_value_is_error(result)) { + fprintf(stderr, "Failed to generate csv"); + res = 8; + } else { + size_t sz; char *buf = pull_str(result, &sz); + printf("%s\n", buf); + } + jerry_value_free(result); + } + +exeunt: + jerry_value_free(ab); + +cleanup: + /* Cleanup engine */ + jerry_cleanup(); + return res; +} diff --git a/docz/static/tauri/linux.png b/docz/static/tauri/linux.png index 0823c60..ca1a922 100644 Binary files a/docz/static/tauri/linux.png and b/docz/static/tauri/linux.png differ diff --git a/docz/static/wails/linux.png b/docz/static/wails/linux.png index a5b7a9a..4d4c13c 100644 Binary files a/docz/static/wails/linux.png and b/docz/static/wails/linux.png differ