From 4438bd86cd47463fad64d1668b735d51c47680a5 Mon Sep 17 00:00:00 2001 From: SheetJS Date: Sun, 17 Sep 2023 00:57:06 -0400 Subject: [PATCH] jint --- .../01-installation/02-frameworks.md | 3 +- .../01-installation/03-nodejs.md | 3 +- .../01-installation/06-deno.md | 3 +- .../01-installation/07-bun.md | 74 +++- docz/docs/03-demos/02-grid/14-gdg.md | 2 +- docz/docs/03-demos/32-extensions/04-gsheet.md | 26 +- docz/docs/03-demos/42-engines/05-jint.md | 414 ++++++++++++++++++ .../42-engines/{05-pandas.md => 14-pandas.md} | 0 docz/docs/03-demos/42-engines/index.md | 6 + 9 files changed, 504 insertions(+), 27 deletions(-) create mode 100644 docz/docs/03-demos/42-engines/05-jint.md rename docz/docs/03-demos/42-engines/{05-pandas.md => 14-pandas.md} (100%) diff --git a/docz/docs/02-getting-started/01-installation/02-frameworks.md b/docz/docs/02-getting-started/01-installation/02-frameworks.md index 96b2c22..3c3a15f 100644 --- a/docz/docs/02-getting-started/01-installation/02-frameworks.md +++ b/docz/docs/02-getting-started/01-installation/02-frameworks.md @@ -64,7 +64,8 @@ but the registry is out of date. The latest version on that registry is 0.18.5 This is a known registry bug - is the authoritative source for SheetJS scripts. +**The SheetJS CDN** **is the authoritative source** +**for SheetJS modules.** For existing projects, the easiest approach is to uninstall and reinstall: 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 a5cf746..4f33673 100644 --- a/docz/docs/02-getting-started/01-installation/03-nodejs.md +++ b/docz/docs/02-getting-started/01-installation/03-nodejs.md @@ -56,7 +56,8 @@ but the registry is out of date. The latest version on that registry is 0.18.5 This is a known registry bug - is the authoritative source for SheetJS scripts. +**The SheetJS CDN** **is the authoritative source** +**for SheetJS modules.** For existing projects, the easiest approach is to uninstall and reinstall: diff --git a/docz/docs/02-getting-started/01-installation/06-deno.md b/docz/docs/02-getting-started/01-installation/06-deno.md index 7ad2b35..44c68fe 100644 --- a/docz/docs/02-getting-started/01-installation/06-deno.md +++ b/docz/docs/02-getting-started/01-installation/06-deno.md @@ -72,7 +72,8 @@ and the types URLs should be updated at the same time: The official Deno registry is out of date. This is a registry bug. - is the authoritative source for SheetJS scripts. +**The SheetJS CDN** **is the authoritative source** +**for SheetJS modules.** ::: diff --git a/docz/docs/02-getting-started/01-installation/07-bun.md b/docz/docs/02-getting-started/01-installation/07-bun.md index 7e6783c..a9ced6d 100644 --- a/docz/docs/02-getting-started/01-installation/07-bun.md +++ b/docz/docs/02-getting-started/01-installation/07-bun.md @@ -3,24 +3,17 @@ pagination_prev: getting-started/index pagination_next: getting-started/examples/index sidebar_position: 7 sidebar_custom_props: - summary: Download and Import ECMAScript Modules + summary: Load NodeJS-style modules using CommonJS or ESM --- import current from '/version.js'; +import CodeBlock from '@theme/CodeBlock'; # Bun -Module scripts are available at . +Tarballs are available on . -

https://cdn.sheetjs.com/xlsx-{current}/package/xlsx.mjs is the URL for {current}

- -After downloading the script, it can be directly imported: - -```js -import * as XLSX from './xlsx.mjs'; -import * as fs from 'fs'; -XLSX.set_fs(fs); -``` +

https://cdn.sheetjs.com/xlsx-{current}/xlsx-{current}.tgz is the URL for version {current}

:::caution Bun support is considered experimental. @@ -29,6 +22,14 @@ be reported to the Bun project for further diagnosis. ::: +## Installation + +Tarballs can be directly installed with `bun install`[^1]: + +{`\ +bun install https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`} + + :::tip pass [Watch the repo](https://git.sheetjs.com/SheetJS/sheetjs) or subscribe to the @@ -37,15 +38,52 @@ new versions are released! ::: -## Encoding support +:::warning pass -If Encoding support is required, `cpexcel.full.mjs` must be manually imported. +At the time of writing `bun install` does not support vendored tarballs[^2]. -

https://cdn.sheetjs.com/xlsx-{current}/package/dist/cpexcel.full.mjs is the URL for {current}

+::: +## Usage -```ts -/* load the codepage support library for extended support with older formats */ -import * as cptable from './cpexcel.full.mjs'; -XLSX.set_cptable(cptable); +Bun supports both "CommonJS" and "ESM" modules. + +:::info pass + +It is strongly recommended to use CommonJS in Bun. + +::: + +#### CommonJS `require` + +By default, the module supports `require` and it will automatically add support +for streams and file system access: + +```js +const { readFile } = require("xlsx"); +const wb = readFile("pres.numbers"); // works! ``` + +#### ESM `import` + +When importing the library using ESM `import` statements, the native NodeJS +modules are not loaded. They must be added manually: + +```js +import * as XLSX from 'xlsx'; + +/* load 'fs' for readFile and writeFile support */ +import * as fs from 'fs'; +XLSX.set_fs(fs); + +/* load 'stream' for stream support */ +import { Readable } from 'stream'; +XLSX.stream.set_readable(Readable); + +/* load the codepage support library for extended support with older formats */ +import * as cpexcel from 'xlsx/dist/cpexcel.full.mjs'; +XLSX.set_cptable(cpexcel); +``` + +[^1]: Bun releases before the official 1.0.0 release did not support tarball dependencies. If a pre-1.0.0 release must be used, the module can be installed with a package manager like Yarn or the ESM script can be vendored. +[^2]: See [the relevant issue in the Bun issue tracker](https://github.com/oven-sh/bun/issues/101) \ No newline at end of file diff --git a/docz/docs/03-demos/02-grid/14-gdg.md b/docz/docs/03-demos/02-grid/14-gdg.md index 7572da6..5a34b4a 100644 --- a/docz/docs/03-demos/02-grid/14-gdg.md +++ b/docz/docs/03-demos/02-grid/14-gdg.md @@ -394,7 +394,7 @@ Open the generated file and verify the contents match the grid. should update with the data in the file. [^1]: See ["Array of Objects" in the ReactJS demo](/docs/demos/frontend/react#array-of-objects) -[^2]: The "Story" section of the ["Getting Started" page in the Glide Data Grid Storybook](https://quicktype.github.io/glide-data-grid/?path=/story/glide-data-grid-docs--getting-started) stores an Array of Objects outside of the component. +[^2]: The "Story" section of the ["Getting Started" page in the Glide Data Grid Storybook](https://glideapps.github.io/glide-data-grid/?path=/story/glide-data-grid-docs--getting-started) stores an Array of Objects outside of the component. [^3]: See [the "Data" section in `DataEditorProps`](https://grid.glideapps.com/docs/interfaces/DataEditorProps.html#columns:~:text=default-,Data,-Readonly) in the Glide Data Grid API documentation. [^4]: See [`read` in "Reading Files"](/docs/api/parse-options) [^5]: See ["SheetJS Data Model"](/docs/csf) diff --git a/docz/docs/03-demos/32-extensions/04-gsheet.md b/docz/docs/03-demos/32-extensions/04-gsheet.md index 1adf10b..f0a65c7 100644 --- a/docz/docs/03-demos/32-extensions/04-gsheet.md +++ b/docz/docs/03-demos/32-extensions/04-gsheet.md @@ -29,7 +29,7 @@ remote file, parses the contents, and writes data to the sheet: :::note -This demo was last tested on 2023 April 17. +This demo was last tested on 2023 September 16. ::: @@ -152,12 +152,28 @@ npx @google/clasp push :::caution -If the push command fails with an error message like +If the Google Apps Script API is not enabled, the command will display an object +with `code: 403` and an error message about the Apps Script API: -> User has not enabled the Apps Script API +```js +{ // ... + code: 403, + errors: [ + { + message: 'User has not enabled the Apps Script API. Enable it by ...', + domain: 'global', + reason: 'forbidden' + } + ] +} +``` The message includes a URL (`https://script.google.com/home/usersettings` when -the demo was last tested). Visit that URL and enable the Google Apps Script API. +the demo was last tested). Visit that URL. + +If the Google Apps Script API is "Off", click on "Google Apps Script API" and +click on the slider to enable the API. + After enabling the API, run `npx @google/clasp push` again. ::: @@ -190,7 +206,7 @@ function SHEETJS(url) { } ``` -Click the "Save Project" icon to save the project. +Click the "Save Project" icon (💾) to save the project. 11) In the Google Sheets window, select cell A1 and enter the formula diff --git a/docz/docs/03-demos/42-engines/05-jint.md b/docz/docs/03-demos/42-engines/05-jint.md new file mode 100644 index 0000000..7f8e516 --- /dev/null +++ b/docz/docs/03-demos/42-engines/05-jint.md @@ -0,0 +1,414 @@ +--- +title: Sheets in .NET with Jint +sidebar_label: C# + Jint +description: Process structured data in C#. Seamlessly integrate spreadsheets into your program by pairing Jint and SheetJS. Handle the most complex Excel files without breaking a sweat. +pagination_prev: demos/bigdata/index +pagination_next: solutions/input +--- + +import current from '/version.js'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import CodeBlock from '@theme/CodeBlock'; + +Jint[^1] is a JavaScript interpreter for .NET Standard and .NET Core. It has +built-in support for binary data with .NET `byte[]` and ES6 `Uint8Array`. + +[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing +data from spreadsheets. + +This demo uses Jint and SheetJS to read and write spreadsheets. We'll explore +how to load SheetJS in the Jint engine, exchange binary data with a C# program, +and process spreadsheets and structured data. + +The ["Integration Example"](#integration-example) section includes a complete +command-line tool for reading arbitrary workbooks and writing data to XLSB +(Excel 2007+ Binary Format) workbooks. + +## Integration Details + +:::note pass + +Most of the integration functions are not documented. This explanation is based +on version `3.0.0-beta-2051`. + +::: + +The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone) +can be parsed and evaluated in a Jint engine instance. + +### Initialize Jint + +A `Jint.Engine` object can be created in one line: + +```csharp +var engine = new Jint.Engine(); +``` + +Jint does not expose the NodeJS `global` but does provide `globalThis`. Using +`Jint.Engine#Evaluate`, a `global` global variable can be created: + +>The JS code is +```js +global = globalThis; +``` + +```csharp +engine.Evaluate("global = globalThis"); +``` + +### Load SheetJS Scripts + +The main library can be loaded by reading the scripts from the file system with +`System.IO.File.ReadAllText` and evaluating in the Jint engine instance: + +```csharp +/* read and evaluate the shim script */ +string src = System.IO.File.ReadAllText("shim.min.js"); +engine.Evaluate(src); +/* read and evaluate the main library */ +engine.Evaluate(System.IO.File.ReadAllText("xlsx.full.min.js")); +``` + +To confirm the library is loaded, `XLSX.version` can be inspected: + +```csharp +Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version")); +``` + +:::info pass + +The Jint `Evaluate` method returns a generic `Jint.Native.JsValue` object. + +When the JS expression returns a string, the `JsValue` object is an instance of +`Jint.Native.JsString`. C# `ToString` will return the underlying `string` value. + +::: + +### Reading Files + +In C#, `System.IO.File.ReadAllBytes` reads file data into a `byte[]` byte array: + +```csharp +string filename = "pres.xlsx"; +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.Engine#SetValue` will assign the `Uint8Array` to a scope variable in JS: + +```csharp +engine.SetValue("buf", u8); +``` + +The `buf` variable can be parsed from JS with the SheetJS `read` method[^2]: + +>The JS code is +```js +var wb = XLSX.read(buf); +``` + +```csharp +engine.Evaluate("var wb = XLSX.read(buf);"); +``` + +`wb` is a SheetJS workbook object. The ["SheetJS Data Model"](/docs/csf) section +describes the object structure and the ["API Reference"](/docs/api) section +describes various helper functions. + +### Writing Files + +The SheetJS `write` method[^3] can write workbooks. The option `type: "buffer"` +instructs the library to generate `Uint8Array` objects. + +> The JS code for exporting to the XLSB format is: +```js +var u8 = XLSX.write(wb, {bookType: 'xlsb', type: 'buffer'}); +``` +The file format can be changed with the `bookType` option[^4] + +```csharp +Jint.Native.JsValue xlsb = engine.Evaluate("XLSX.write(wb, {bookType: 'xlsb', type: 'buffer'})"); +``` + +`xlsb` represents a `Uint8Array`. `xlsb.AsUint8Array()` returns the bytes as a +`byte[]` array which can be exported with `System.IO.File.WriteAllBytes`: + +```csharp +byte[] outfile = xlsb.AsUint8Array(); +System.IO.File.WriteAllBytes("SheetJSJint.xlsb", outfile); +``` + +## Integration Example + +:::note + +This demo was tested in the following deployments: + +| Architecture | Jint Version | Date | +|:-------------|:------------------|:-----------| +| `darwin-x64` | `3.0.0-beta-2051` | 2023-09-16 | +| `win10-x64` | `3.0.0-beta-2051` | 2023-09-16 | + +::: + +0) Install .NET[^5] + +### Platform Configuration + +1) Set the `DOTNET_CLI_TELEMETRY_OPTOUT` environment variable to `1`. + +
How to disable telemetry (click to hide) + + + + +Add the following line to `.profile`, `.bashrc` and `.zshrc`: + +```bash +export DOTNET_CLI_TELEMETRY_OPTOUT=1 +``` + +Close and restart the Terminal to load the changes. + + + + +Type `env` in the search bar and select "Edit the system environment variables". + +In the new window, click the "Environment Variables..." button. + +In the new window, look for the "System variables" section and click "New..." + +Set the "Variable name" to `DOTNET_CLI_TELEMETRY_OPTOUT` and the value to `1`. + +Click "OK" in each window (3 windows) and restart your computer. + + + + +
+ +2) Open a new Terminal window in macOS or PowerShell window in Windows. + +### Base Project + +3) Create a new folder `SheetJSJint` and a new project using the `dotnet` tool: + +```bash +rm -rf SheetJSJint +mkdir SheetJSJint +cd SheetJSJint +dotnet new console --framework net6.0 +dotnet run +``` + +4) Add Jint using the NuGet tool: + +```bash +dotnet nuget add source https://www.myget.org/F/jint/api/v3/index.json +dotnet add package Jint --version 3.0.0-beta-2051 +``` + +To verify Jint is installed, replace `Program.cs` with the following: + +```csharp title="Program.cs" +var engine = new Jint.Engine(); +Console.WriteLine("Hello {0}", engine.Evaluate("'Sheet' + 'JS'")); +``` + +After saving, run the program: + +```bash +dotnet run +``` + +The terminal should display `Hello SheetJS` + +### Add SheetJS + +5) Download the standalone script, shim and test file: + + + +{`\ +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`} + + +6) Replace `Program.cs` with the following: + +```csharp title="Program.cs" +var engine = new Jint.Engine(); +engine.Evaluate("global = globalThis;"); +engine.Evaluate(File.ReadAllText("shim.min.js")); +engine.Evaluate(File.ReadAllText("xlsx.full.min.js")); +Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version")); +``` + +After saving, run the program: + +```bash +dotnet run +``` + +

The terminal should display SheetJS version {current}

+ +### Read and Write Files + +7) Replace `Program.cs` with the following: + +```csharp title="Program.cs" +using Jint; + +/* Initialize Jint */ +var engine = new Jint.Engine(); +engine.Evaluate("global = globalThis;"); + +/* Load SheetJS Scripts */ +engine.Evaluate(File.ReadAllText("shim.min.js")); +engine.Evaluate(File.ReadAllText("xlsx.full.min.js")); +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); +engine.SetValue("buf", u8); +engine.Evaluate("var wb = XLSX.read(buf);"); + +/* Print CSV of first worksheet*/ +engine.Evaluate("var ws = wb.Sheets[wb.SheetNames[0]];"); +Jint.Native.JsValue csv = engine.Evaluate("XLSX.utils.sheet_to_csv(ws)"); +Console.Write(csv); + +/* Generate XLSB file and save to SheetJSJint.xlsb */ +Jint.Native.JsValue xlsb = engine.Evaluate("XLSX.write(wb, {bookType: 'xlsb', type: 'buffer'})"); +File.WriteAllBytes("SheetJSJint.xlsb", xlsb.AsUint8Array()); +``` + +After saving, run the program and pass the test file name as an argument: + +```bash +dotnet run pres.xlsx +``` + +If successful, the program will print the contents of the first sheet as CSV +rows. It will also create `SheetJSJint.xlsb` which can be opened in Excel or +another spreadsheet editor. + +:::caution pass + +If the `using Jint;` directive is omitted, the build will fail: + +``` +'JsValue' does not contain a definition for 'AsUint8Array' and no accessible extension method 'AsUint8Array' accepting a first argument of type 'JsValue' could be found +``` + +::: + +### Standalone Application + +8) Find the runtime identifier (RID) for your platform[^6]. The RID values for +tested platforms are listed below: + +| Platform | RID | +|:-----------------|:------------| +| Intel Mac | `osx-x64` | +| Windows 10 (x64) | `win10-x64` | + +9) Build the standalone application. Replace `$RID` with the real value in: + +```bash +dotnet publish -c Release -r $RID --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true +``` + +
Tested platforms (click to hide) + + + + +For Intel Mac, the RID is `osx-x64` and the command is + +```bash +dotnet publish -c Release -r osx-x64 --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true +``` + + + + +For Windows 10 x64, the RID is `win10-x64` and the command is: + +```powershell +dotnet publish -c Release -r win10-x64 --self-contained true -p:PublishSingleFile=true -p:PublishTrimmed=true +``` + + + + +
+ +10) Copy the generated executable to the project directory. + +The build from step 9 is placed in `bin\Release\net6.0\$RID\publish` and the +binary name will be `SheetJSJint` or `SheetJSJint.exe` depending on OS. + +
Tested platforms (click to hide) + + + + +For Intel Mac, the RID is `osx-x64` and the command is: + +```bash +cp bin/Release/net6.0/osx-x64/publish/SheetJSJint . +``` + + + + +For Windows 10 x64, the RID is `win10-x64` and the command is: + +```powershell +copy .\bin\Release\net6.0\win10-x64\publish\SheetJSJint.exe . +``` + + + + +
+ +11) Run the generated command. + + + + +```bash +./SheetJSJint pres.xlsx +``` + + + + +```powershell +.\SheetJSJint pres.xlsx +``` + + + + +[^1]: The Jint project recommends the ["MyGet" service](https://www.myget.org/feed/jint/package/nuget/Jint). According to the developers, the ["NuGet" package](https://www.nuget.org/packages/jint) is "occasionally published". +[^2]: See [`read` in "Reading Files"](/docs/api/parse-options) +[^3]: See [`write` in "Writing Files"](/docs/api/write-options) +[^4]: See ["Supported Output Formats" in "Writing Files"](/docs/api/write-options#supported-output-formats) for details on `bookType` +[^5]: At the time of writing, is the official endpoint. +[^6]: See [".NET RID Catalog"](https://learn.microsoft.com/en-us/dotnet/core/rid-catalog) in the .NET documentation \ No newline at end of file diff --git a/docz/docs/03-demos/42-engines/05-pandas.md b/docz/docs/03-demos/42-engines/14-pandas.md similarity index 100% rename from docz/docs/03-demos/42-engines/05-pandas.md rename to docz/docs/03-demos/42-engines/14-pandas.md diff --git a/docz/docs/03-demos/42-engines/index.md b/docz/docs/03-demos/42-engines/index.md index 23fab23..efeb376 100644 --- a/docz/docs/03-demos/42-engines/index.md +++ b/docz/docs/03-demos/42-engines/index.md @@ -204,6 +204,12 @@ build/bin/jerry xlsx.jerry.js; echo $? +### Jint + +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