From 01d7333f4425b326dbe4b4f96ad119f823081ffa Mon Sep 17 00:00:00 2001 From: SheetJS Date: Sun, 12 Mar 2023 01:25:57 -0500 Subject: [PATCH] quick --- .../01-installation/03-nodejs.md | 6 +- docz/docs/03-demos/01-frontend/04-svelte.md | 66 ++++++ docz/docs/03-demos/02-grid/01-xs.md | 4 +- docz/docs/03-demos/02-grid/02-cdg.md | 137 ++++++++++++ docz/docs/03-demos/02-grid/index.md | 95 +------- docz/docs/03-demos/07-data/01-websql.md | 9 + docz/docs/03-demos/12-engines/08_quickjs.md | 211 ++++++++++++++++++ docz/docs/03-demos/12-engines/index.md | 52 +---- docz/docs/03-demos/index.md | 2 +- docz/docs/06-solutions/05-output.md | 5 +- docz/static/quickjs/SheetJSQuick.js | 25 +++ docz/static/quickjs/sheetjs.quick.c | 120 ++++++++++ 12 files changed, 582 insertions(+), 150 deletions(-) create mode 100644 docz/docs/03-demos/02-grid/02-cdg.md create mode 100644 docz/docs/03-demos/12-engines/08_quickjs.md create mode 100644 docz/static/quickjs/SheetJSQuick.js create mode 100644 docz/static/quickjs/sheetjs.quick.c diff --git a/docz/docs/02-getting-started/01-installation/03-nodejs.md b/docz/docs/02-getting-started/01-installation/03-nodejs.md index 6fd6756..a7a7fec 100644 --- a/docz/docs/02-getting-started/01-installation/03-nodejs.md +++ b/docz/docs/02-getting-started/01-installation/03-nodejs.md @@ -55,19 +55,19 @@ For existing projects, the easiest approach is to uninstall and reinstall:
{`\
 npm rm --save xlsx
-npm i --save file:vendor/xlsx-${current}.tgz`}
+npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
 
{`\
 pnpm rm xlsx
-pnpm install file:vendor/xlsx-${current}.tgz`}
+pnpm install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
 
{`\
 yarn remove xlsx
-yarn add file:vendor/xlsx-${current}.tgz`}
+yarn add https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
 
diff --git a/docz/docs/03-demos/01-frontend/04-svelte.md b/docz/docs/03-demos/01-frontend/04-svelte.md index 747294c..c183871 100644 --- a/docz/docs/03-demos/01-frontend/04-svelte.md +++ b/docz/docs/03-demos/01-frontend/04-svelte.md @@ -114,6 +114,39 @@ function exportFile() { ``` +
How to run the example (click to show) + +:::note + +This demo was last run on 2023 March 08 using `svelte@3.55.1`. When running +`npm create`, the package `create-vite@4.1.0` was installed. + +::: + +1) Run `npm create vite@latest sheetjs-svelte -- --template svelte-ts`. + +2) Install the SheetJS dependency and start the dev server: + +```bash +cd sheetjs-svelte +npm install +npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz +npm run dev +``` + +3) Open a web browser and access the displayed URL (`http://localhost:5173`) + +4) Replace `src/App.svelte` with the `src/SheetJSSvelteAoO.svelte` example. + +The page will refresh and show a table with an Export button. Click the button +and the page will attempt to download `SheetJSSvelteAoA.xlsx`. There may be a +delay since Vite will try to optimize the SheetJS library on the fly. + +5) Build the site with `npm run build`, then test with `npx http-server dist`. +Access `http://localhost:8080` with a web browser to test the bundled site. + +
+ ### HTML The main disadvantage of the Array of Objects approach is the specific nature @@ -158,3 +191,36 @@ function exportFile() { ``` + +
How to run the example (click to show) + +:::note + +This demo was last run on 2023 March 08 using `svelte@3.55.1`. When running +`npm create`, the package `create-vite@4.1.0` was installed. + +::: + +1) Run `npm create vite@latest sheetjs-svelte -- --template svelte-ts`. + +2) Install the SheetJS dependency and start the dev server: + +```bash +cd sheetjs-svelte +npm install +npm i --save https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz +npm run dev +``` + +3) Open a web browser and access the displayed URL (`http://localhost:5173`) + +4) Replace `src/App.svelte` with the `src/SheetJSSvelteHTML.svelte` example. + +The page will refresh and show a table with an Export button. Click the button +and the page will attempt to download `SheetJSSvelteHTML.xlsx`. There may be a +delay since Vite will try to optimize the SheetJS library on the fly. + +5) Build the site with `npm run build`, then test with `npx http-server dist`. +Access `http://localhost:8080` with a web browser to test the bundled site. + +
diff --git a/docz/docs/03-demos/02-grid/01-xs.md b/docz/docs/03-demos/02-grid/01-xs.md index 7faef86..64e0a31 100644 --- a/docz/docs/03-demos/02-grid/01-xs.md +++ b/docz/docs/03-demos/02-grid/01-xs.md @@ -29,7 +29,7 @@ features like scrolling may not work as expected. function SheetJSXSpread() { const [url, setUrl] = React.useState("https://sheetjs.com/pres.numbers"); const [done, setDone] = React.useState(false); - const ref = React.useRef(); + const ref = React.useRef(); // ref to DIV container const set_url = React.useCallback((evt) => setUrl(evt.target.value)); return ( <> @@ -43,7 +43,7 @@ function SheetJSXSpread() { x_spreadsheet(ref.current).loadData(stox(wb)); setDone(true); }}>Fetch! - )} + )} ); } ``` diff --git a/docz/docs/03-demos/02-grid/02-cdg.md b/docz/docs/03-demos/02-grid/02-cdg.md new file mode 100644 index 0000000..3b56768 --- /dev/null +++ b/docz/docs/03-demos/02-grid/02-cdg.md @@ -0,0 +1,137 @@ +--- +title: Canvas Datagrid +pagination_prev: demos/frontend/index +pagination_next: demos/net/index +--- + + + + + +After extensive testing, `canvas-datagrid` stood out as a high-performance grid +with a straightforward API. + +[Click here for a live standalone integration demo.](pathname:///cdg/) + +## Live Demo + +:::note + +Due to CSS conflicts between the data grid and the documentation generator, +features like scrolling may not work as expected. + +[The linked demo uses a simple HTML page.](pathname:///cdg/) + +::: + +```jsx live +function SheetJSCDG() { + const [url, setUrl] = React.useState("https://sheetjs.com/pres.numbers"); + const [done, setDone] = React.useState(false); + const ref = React.useRef(); // ref to DIV container + const set_url = React.useCallback((evt) => setUrl(evt.target.value)); + const [cdg, setCdg] = React.useState(null); // reference to grid object + + return ( <> +
+ {!done && ( <> + URL: +
+ )} + ); +} +``` + +## Integration Details + +#### Obtaining the Library + +The `canvas-datagrid` NodeJS packages include a minified script that can be +directly inserted as a script tag. The unpkg CDN also serves this script: + +```html + +``` + +#### Previewing Data + +The HTML document needs a container element: + +```html +
+``` + +Grid initialization is a one-liner: + +```js +var grid = canvasDatagrid({ + parentNode: document.getElementById('gridctr'), + data: [] +}); +``` + +For large data sets, it's necessary to constrain the size of the grid. + +```js +grid.style.height = '100%'; +grid.style.width = '100%'; +``` + +Once the workbook is read and the worksheet is selected, assigning the data +variable automatically updates the view: + +```js +grid.data = XLSX.utils.sheet_to_json(ws, {header:1}); +``` + +This demo previews the first worksheet. + +#### Editing + +`canvas-datagrid` handles the entire edit cycle. No intervention is necessary. + +#### Saving Data + +`grid.data` is immediately readable and can be converted back to a worksheet. +Some versions return an array-like object without the length, so a little bit of +preparation may be needed: + +```js +/* converts an array of array-like objects into an array of arrays */ +function prep(arr) { + var out = []; + for(var i = 0; i < arr.length; ++i) { + if(!arr[i]) continue; + if(Array.isArray(arr[i])) { out[i] = arr[i]; continue }; + var o = new Array(); + Object.keys(arr[i]).forEach(function(k) { o[+k] = arr[i][k] }); + out[i] = o; + } + return out; +} + +/* build worksheet from the grid data */ +var ws = XLSX.utils.aoa_to_sheet(prep(grid.data)); + +/* build up workbook */ +var wb = XLSX.utils.book_new(); +XLSX.utils.book_append_sheet(wb, ws, 'SheetJS'); + +/* generate download */ +XLSX.writeFile(wb, "SheetJS.xlsx"); +``` + +#### Additional Features + +This demo barely scratches the surface. The underlying grid component includes +many additional features that work with [SheetJS Pro](https://sheetjs.com/pro). diff --git a/docz/docs/03-demos/02-grid/index.md b/docz/docs/03-demos/02-grid/index.md index 6e2d6c3..80e9d65 100644 --- a/docz/docs/03-demos/02-grid/index.md +++ b/docz/docs/03-demos/02-grid/index.md @@ -34,101 +34,16 @@ With a familiar UI, `x-spreadsheet` is an excellent choice for a modern editor. [Click here for a live integration demo.](pathname:///xspreadsheet/) -[The exposition has been moved to a separate page.](/docs/demos/grid/xs) +**[The exposition has been moved to a separate page.](/docs/demos/grid/xs)** -### Canvas DataGrid +### Canvas Datagrid -After extensive testing, [`canvas-datagrid`](https://canvas-datagrid.js.org/demo.html) -stood out as a very high-performance grid with an incredibly simple API. +After extensive testing, `canvas-datagrid` stood out as a high-performance grid +with a straightforward API. [Click here for a live integration demo.](pathname:///cdg/index.html) -
Full Exposition (click to show) - -**Obtaining the Library** - -The `canvas-datagrid` NodeJS packages include a minified script that can be -directly inserted as a script tag. The unpkg CDN also serves this script: - -```html - -``` - -**Previewing Data** - -The HTML document needs a container element: - -```html -
-``` - -Grid initialization is a one-liner: - -```js -var grid = canvasDatagrid({ - parentNode: document.getElementById('gridctr'), - data: [] -}); -``` - -For large data sets, it's necessary to constrain the size of the grid. - -```js -grid.style.height = '100%'; -grid.style.width = '100%'; -``` - -Once the workbook is read and the worksheet is selected, assigning the data -variable automatically updates the view: - -```js -grid.data = XLSX.utils.sheet_to_json(ws, {header:1}); -``` - -This demo previews the first worksheet. - -**Editing** - -`canvas-datagrid` handles the entire edit cycle. No intervention is necessary. - -**Saving Data** - -`grid.data` is immediately readable and can be converted back to a worksheet. -Some versions return an array-like object without the length, so a little bit of -preparation may be needed: - -```js -/* converts an array of array-like objects into an array of arrays */ -function prep(arr) { - var out = []; - for(var i = 0; i < arr.length; ++i) { - if(!arr[i]) continue; - if(Array.isArray(arr[i])) { out[i] = arr[i]; continue }; - var o = new Array(); - Object.keys(arr[i]).forEach(function(k) { o[+k] = arr[i][k] }); - out[i] = o; - } - return out; -} - -/* build worksheet from the grid data */ -var ws = XLSX.utils.aoa_to_sheet(prep(grid.data)); - -/* build up workbook */ -var wb = XLSX.utils.book_new(); -XLSX.utils.book_append_sheet(wb, ws, 'SheetJS'); - -/* generate download */ -XLSX.writeFile(wb, "SheetJS.xlsx"); -``` - -**Additional Features** - -This demo barely scratches the surface. The underlying grid component includes -many additional features including massive data streaming, sorting and styling. - -
- +**[The exposition has been moved to a separate page.](/docs/demos/grid/cdg)** ### Tabulator diff --git a/docz/docs/03-demos/07-data/01-websql.md b/docz/docs/03-demos/07-data/01-websql.md index 9ef9ce5..a616b8d 100644 --- a/docz/docs/03-demos/07-data/01-websql.md +++ b/docz/docs/03-demos/07-data/01-websql.md @@ -13,6 +13,15 @@ work as-is in WebSQL. The public demo generates a database from workbook. +:::caution + +WebSQL is only supported in Chromium-based browsers including Chrome. + +Safari historically supported WebSQL but Safari 13 dropped support. Legacy +browsers including Internet Explorer and Firefox never added support. + +::: + ## WebSQL Details Importing data from spreadsheets is straightforward using the `generate_sql` diff --git a/docz/docs/03-demos/12-engines/08_quickjs.md b/docz/docs/03-demos/12-engines/08_quickjs.md new file mode 100644 index 0000000..327236d --- /dev/null +++ b/docz/docs/03-demos/12-engines/08_quickjs.md @@ -0,0 +1,211 @@ +--- +title: C + QuickJS +pagination_prev: demos/bigdata/index +pagination_next: solutions/input +--- + +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 +the standalone browser scripts. + +## Integration Details + +_Initialize QuickJS_ + +QuickJS provides a `global` object through `JS_GetGlobalObject`: + +```c +/* initialize */ +JSRuntime *rt = JS_NewRuntime(); +JSContext *ctx = JS_NewContext(rt); + +/* obtain reference to global object */ +JSValue global = JS_GetGlobalObject(ctx); + +/* DO WORK HERE */ + +/* free after use */ +JS_FreeValue(ctx, global); + +/* cleanup */ +JS_FreeContext(ctx); +JS_FreeRuntime(rt); +``` + +:::warning + +All values must be freed with `JS_FreeValue` before calling `JS_FreeContext`! + +`JS_IsException` should be used for validation. + +Cleanup and validation code is omitted from the discussion. The integration +example shows structured validation and controlled memory usage. + +::: + +_Load SheetJS Scripts_ + +The main library can be loaded by reading the script from the file system and +evaluating in the QuickJS context: + +```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); fsee (f, 0, SEEK_SET); } + char *buf = (char *)malloc(fsize * sizeof(char)); + *sz = fread((void *) buf, 1, fsize, f); + fclose(f); + return buf; +} + +// ... + /* load library */ + { + size_t len; char *buf = read_file("xlsx.full.min.js", &len); + JS_Eval(ctx, buf, len, "", 0); + free(buf); + } +``` + +To confirm the library is loaded, `XLSX.version` can be inspected: + +```c +/* obtain reference to the XLSX object */ +JSValue XLSX = JS_GetPropertyStr(ctx, global, "XLSX"); + +/* print version */ +JSValue version = JS_GetPropertyStr(ctx, XLSX, "version"); +size_t vlen; const char *vers = JS_ToCStringLen(ctx, &vlen, version); +printf("Version: %s\n", vers); +``` + +### Reading Files + +`JS_NewArrayBuffer` can generate an `ArrayBuffer` from a C byte array. The +function signature expects `uint8_t *` instead of `char *`: + +```c +/* read file */ +size_t dlen; uint8_t * dbuf = (uint8_t *)read_file("pres.numbers", &dlen); + +/* load data into array buffer */ +JSValue ab = JS_NewArrayBuffer(ctx, dbuf, dlen, NULL, NULL, 0); + +/* obtain reference to the XLSX object */ +JSValue XLSX = JS_GetPropertyStr(ctx, global, "XLSX"); + +/* call XLSX.read(ab) */ +JSValue XLSX_read = JS_GetPropertyStr(ctx, XLSX, "read"); +JSValue args[] = { ab }; +JSValue wb = JS_Call(ctx, XLSX_read, XLSX, 1, args); +``` + +## Complete Example + +The "Integration Example" covers a traditional integration in a C application, +while the "CLI Test" demonstrates other concepts using the `quickjs` CLI tool. + +### Integration Example + +:::note + +This demo was last tested on 2023 March 11 against QuickJS commit `2788d71` on +a Intel Mac. `gcc -v` printed: + +``` +Apple clang version 14.0.0 (clang-1400.0.29.202) +Target: x86_64-apple-darwin21.6.0 +``` + +::: + +0) Build `libquickjs.a`: + +```bash +git clone --depth=1 https://github.com/bellard/quickjs +cd quickjs +git checkout 2788d71 +make +cd .. +``` + +1) Copy `libquickjs.a` and `quickjs.h` into the working directory: + +```bash +cp quickjs/libquickjs.a . +cp quickjs/quickjs.h . +``` + +2) Download [`sheetjs.quick.c`](pathname:///quickjs/sheetjs.quick.c): + +```bash +curl -LO https://docs.sheetjs.com/quickjs/sheetjs.quick.c +``` + +3) Build the sample application: + +```bash +gcc -o sheetjs.quick -Wall -lm libquickjs.a sheetjs.quick.c +``` + +This program tries to parse the file specified by the first argument + +4) Download the standalone script and test file: + + + +```bash +curl -LO https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js +curl -LO https://sheetjs.com/pres.numbers +``` + +5) Run the test program: + +``` +./sheetjs.quick pres.numbers +``` + +If successful, the program will print the library version number, file size, +first worksheet name, and the contents of the first sheet as CSV rows. + + +### CLI Test + +:::note + +This demo was last tested on 2023 March 11 against QuickJS `2021-03-27`. + +::: + +0) Ensure `quickjs` command line utility is installed + +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 [`SheetJSQuick.js`](pathname:///quickjs/SheetJSQuick.js) + +```bash +curl -LO https://docs.sheetjs.com/quickjs/SheetJSQuick.js +``` + +3) Test the program: + +```bash +quickjs SheetJSQuick.js +``` + +If successful, the script will generate `SheetJSQuick.xlsx`. + diff --git a/docz/docs/03-demos/12-engines/index.md b/docz/docs/03-demos/12-engines/index.md index 034ae00..cc57493 100644 --- a/docz/docs/03-demos/12-engines/index.md +++ b/docz/docs/03-demos/12-engines/index.md @@ -246,57 +246,7 @@ 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 the standalone browser scripts. -
Complete Example (click to show) - -0) Ensure `quickjs` command line utility is installed - -1) Download the standalone script, the shim and the test file: - - - -2) Save the following script to `SheetJSQuick.js`: - -```js title="SheetJSQuick.js" -/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */ -/* load XLSX */ -import * as std from "std"; -globalThis.global = globalThis; -std.loadScript("xlsx.full.min.js"); - -/* read contents of file */ -var rh = std.open("pres.numbers", "rb"); -rh.seek(0, std.SEEK_END); -var sz = rh.tell(); -var ab = new ArrayBuffer(sz); -rh.seek(); -rh.read(ab, 0, sz); -rh.close(); - -/* parse file */ -var wb = XLSX.read(ab); - -/* write XLSX */ -var out = XLSX.write(wb, {bookType: "xlsx", type: "array"}); - -/* write contents to file */ -var wh = std.open("SheetJSQuick.xlsx", "wb"); -wh.write(out, 0, out.byteLength); -wh.close(); -``` - -3) Test the program: - -```bash -quickjs SheetJSQuick.js -``` - -If successful, the script will generate `SheetJSQuick.xlsx`. - -
+This demo has been moved [to a dedicated page](/docs/demos/engines/quickjs). ### Rhino diff --git a/docz/docs/03-demos/index.md b/docz/docs/03-demos/index.md index 41845b3..4531085 100644 --- a/docz/docs/03-demos/index.md +++ b/docz/docs/03-demos/index.md @@ -32,7 +32,7 @@ run in the web browser, demos will include interactive examples. ### Front-End UI Components -- [`canvas-datagrid`](/docs/demos/grid#canvas-datagrid) +- [`canvas-datagrid`](/docs/demos/grid/cdg) - [`x-spreadsheet`](/docs/demos/grid/xs) - [`react-data-grid`](/docs/demos/grid#react-data-grid) - [`glide-data-grid`](/docs/demos/grid#glide-data-grid) diff --git a/docz/docs/06-solutions/05-output.md b/docz/docs/06-solutions/05-output.md index cea7e3b..e0eac3d 100644 --- a/docz/docs/06-solutions/05-output.md +++ b/docz/docs/06-solutions/05-output.md @@ -737,9 +737,8 @@ function Tabeller(props) { /* fetch and update the workbook with an effect */ React.useEffect(() => { (async() => { /* fetch and parse workbook -- see the fetch example for details */ - const wb = XLSX.read(await (await fetch("sheetjs.xlsx")).arrayBuffer()); - setWorkbook(wb); - })(); }); + setWorkbook(XLSX.read(await (await fetch("sheetjs.xlsx")).arrayBuffer())); + })(); }, []); return workbook.SheetNames.map(name => ( <>

name

diff --git a/docz/static/quickjs/SheetJSQuick.js b/docz/static/quickjs/SheetJSQuick.js new file mode 100644 index 0000000..11407b7 --- /dev/null +++ b/docz/static/quickjs/SheetJSQuick.js @@ -0,0 +1,25 @@ +/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */ +/* load XLSX */ +import * as std from "std"; +globalThis.global = globalThis; +std.loadScript("xlsx.full.min.js"); + +/* read contents of file */ +var rh = std.open("pres.numbers", "rb"); +rh.seek(0, std.SEEK_END); +var sz = rh.tell(); +var ab = new ArrayBuffer(sz); +rh.seek(); +rh.read(ab, 0, sz); +rh.close(); + +/* parse file */ +var wb = XLSX.read(ab); + +/* write XLSX */ +var out = XLSX.write(wb, {bookType: "xlsx", type: "array"}); + +/* write contents to file */ +var wh = std.open("SheetJSQuick.xlsx", "wb"); +wh.write(out, 0, out.byteLength); +wh.close(); diff --git a/docz/static/quickjs/sheetjs.quick.c b/docz/static/quickjs/sheetjs.quick.c new file mode 100644 index 0000000..5b14193 --- /dev/null +++ b/docz/static/quickjs/sheetjs.quick.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include + +#include "quickjs.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); + fclose(f); + return buf; +} + +#define CLEANUP(v) { JS_FreeContext(ctx); JS_FreeRuntime(rt); return v; } +#define FREE(v) JS_FreeValue(ctx, v); +#define VALIDATE(v) { if(JS_IsException(v)) CLEANUP(1) } +#define VALINIT(xx,vv) \ + JSValue xx = vv;\ + VALIDATE(xx) +#define VALPROP(xx,vv,pp) VALINIT(xx, JS_GetPropertyStr(ctx, vv, pp)) + +int main(int argc, char *argv[]) { + JSRuntime *rt = JS_NewRuntime(); + JSContext *ctx = JS_NewContext(rt); + + /* load library */ + { + size_t len; char * buf = read_file("xlsx.full.min.js", &len); + VALIDATE(JS_Eval(ctx, buf, len, "", 0)) + free(buf); + } + + VALINIT(global, JS_GetGlobalObject(ctx)) + VALPROP(XLSX, global, "XLSX"); + FREE(global) + + /* print version */ + { + VALPROP(version, XLSX, "version") + size_t vlen; const char *vers = JS_ToCStringLen(ctx, &vlen, version); + printf("Version: %s\n", vers); + FREE(version) + } + + /* parse workbook */ + JSValue wb; + { + /* read file */ + size_t dlen; uint8_t * dbuf = (uint8_t *)read_file(argv[1], &dlen); + + /* load data into array buffer */ + JSValue ab = JS_NewArrayBuffer(ctx, dbuf, dlen, NULL, NULL, 0); + { + VALPROP(byteLen, ab, "byteLength") + uint32_t byteLength; JS_ToUint32(ctx, &byteLength, byteLen); + FREE(byteLen) + printf("Size: %d\n", byteLength); + } + + /* call XLSX.read(ab) */ + { + VALPROP(XLSX_read, XLSX, "read"); + JSValue args[] = { ab }; + wb = JS_Call(ctx, XLSX_read, XLSX, 1, args); + FREE(XLSX_read) + } + + /* cleanup */ + FREE(ab) + free(dbuf); + } + + /* print CSV of first worksheet */ + { + /* get first worksheet */ + JSValue ws; + { + /* get name of first sheet */ + const char *wsname; + { + JSValue SheetNames = JS_GetPropertyStr(ctx, wb, "SheetNames"); + JSValue Sheet1 = JS_GetPropertyStr(ctx, SheetNames, "0"); + size_t wslen; wsname = JS_ToCStringLen(ctx, &wslen, Sheet1); + FREE(Sheet1) + FREE(SheetNames) + } + printf("Worksheet Name: %s\n", wsname); + + /* get worksheet object */ + { + VALPROP(Sheets, wb, "Sheets"); + ws = JS_GetPropertyStr(ctx, Sheets, wsname); + FREE(Sheets) + } + } + + /* print CSV */ + { + VALPROP(utils, XLSX, "utils") + VALPROP(sheet_to_csv, utils, "sheet_to_csv") + JSValue args[] = { ws }; + JSValue csv = JS_Call(ctx, sheet_to_csv, utils, 1, args); + FREE(sheet_to_csv) + FREE(utils) + size_t csvlen; const char *csvstr = JS_ToCStringLen(ctx, &csvlen, csv); + printf("%s\n", csvstr); + FREE(csv) + } + + FREE(ws) + } + + FREE(wb) + FREE(XLSX) + CLEANUP(0) +}