Jurassic Engine demo
This commit is contained in:
parent
5c895ea38b
commit
a768b7ce8c
@ -34,7 +34,7 @@
|
||||
</Style>
|
||||
</Styles>
|
||||
<Worksheet ss:Name="Engines">
|
||||
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="17" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
|
||||
<Table ss:ExpandedColumnCount="8" ss:ExpandedRowCount="18" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="65" ss:DefaultRowHeight="16">
|
||||
<Column ss:Index="3" ss:Width="24"/>
|
||||
<Column ss:Width="31"/>
|
||||
<Column ss:Width="24"/>
|
||||
@ -207,6 +207,16 @@
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
</Row>
|
||||
<Row>
|
||||
<Cell ss:StyleID="s20" ss:HRef="/docs/demos/engines/jurassic#integration-example"><Data ss:Type="String">Jurassic.NET</Data></Cell>
|
||||
<Cell><Data ss:Type="String">C#</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"><Data ss:Type="String">✔</Data></Cell>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
<Cell ss:StyleID="s16"/>
|
||||
</Row>
|
||||
</Table>
|
||||
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
|
||||
<PageSetup>
|
||||
|
373
docz/docs/03-demos/42-engines/26-jurassic.md
Normal file
373
docz/docs/03-demos/42-engines/26-jurassic.md
Normal file
@ -0,0 +1,373 @@
|
||||
---
|
||||
title: Sheets in .NET with Jurassic
|
||||
sidebar_label: C# + Jurassic
|
||||
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';
|
||||
|
||||
Jurassic[^1] is a JavaScript compiler for .NET, In contrast to other engines,
|
||||
Jurassic generates .NET bytecode.
|
||||
|
||||
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
|
||||
data from spreadsheets.
|
||||
|
||||
This demo uses Jurassic and SheetJS to read and write spreadsheets. We'll
|
||||
explore how to load SheetJS in the Jurassic 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 ODS
|
||||
(OpenDocument Spreadsheet) workbooks.
|
||||
|
||||
:::danger Telemetry
|
||||
|
||||
**The `dotnet` command embeds telemetry.**
|
||||
|
||||
The `DOTNET_CLI_TELEMETRY_OPTOUT` environment variable should be set to `1`.
|
||||
|
||||
["Platform Configuration"](#platform-configuration) includes instructions for
|
||||
setting the environment variable on supported platforms.
|
||||
|
||||
:::
|
||||
|
||||
## Integration Details
|
||||
|
||||
The [SheetJS "mini" script](/docs/getting-started/installation/standalone) can
|
||||
be parsed and evaluated in a Jurassic engine instance.
|
||||
|
||||
:::warning pass
|
||||
|
||||
Jurassic throws errors when processing the "full" script (`xlsx.full.min.js`):
|
||||
|
||||
```
|
||||
Unhandled exception. Jurassic.JavaScriptException: Error: Maximum number of named properties reached.
|
||||
```
|
||||
|
||||
**The `xlsx.mini.min.js` script must be used!**
|
||||
|
||||
The mini build has a number of limitations, as noted in the installation guide.
|
||||
|
||||
:::
|
||||
|
||||
It is recommended to pass Base64 strings between C# code and the script engine.
|
||||
|
||||
### Initialize Jurassic
|
||||
|
||||
A `Jurassic.ScriptEngine` object can be created in one line:
|
||||
|
||||
```csharp
|
||||
var engine = new Jurassic.ScriptEngine();
|
||||
```
|
||||
|
||||
Jurassic does not expose the NodeJS `global`. It can be synthesized:
|
||||
|
||||
:::note pass
|
||||
|
||||
The goal is to run the following JavaScript code:
|
||||
|
||||
```js
|
||||
var global = (function(){ return this; }).call(null);
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
```csharp
|
||||
engine.Evaluate("var global = (function(){ return this; }).call(null);");
|
||||
```
|
||||
|
||||
### Load SheetJS Scripts
|
||||
|
||||
Jurassic engine objects support the `ExecuteFile` method for evaluating scripts:
|
||||
|
||||
```csharp
|
||||
/* read and evaluate the shim script */
|
||||
engine.ExecuteFile("shim.min.js");
|
||||
/* read and evaluate the main library */
|
||||
engine.ExecuteFile("xlsx.mini.min.js");
|
||||
```
|
||||
|
||||
To confirm the library is loaded, `XLSX.version` can be inspected:
|
||||
|
||||
```csharp
|
||||
Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version"));
|
||||
```
|
||||
|
||||
### 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);
|
||||
```
|
||||
|
||||
The bytes cannot be directly passed to Jurassic. Base64 strings are supported.
|
||||
An encoded Base64 string can be created with `System.Convert.ToBase64String`:
|
||||
|
||||
```csharp
|
||||
string b64 = System.Convert.ToBase64String(buf);
|
||||
```
|
||||
|
||||
`Jurassic.ScriptEngine#SetGlobalValue` will assign the C# String to a global:
|
||||
|
||||
```csharp
|
||||
engine.SetGlobalValue("buf", b64);
|
||||
```
|
||||
|
||||
The `buf` variable can be parsed from JS with the SheetJS `read` method[^2]:
|
||||
|
||||
:::note pass
|
||||
|
||||
The following script will be evaluated:
|
||||
|
||||
```js
|
||||
var wb = XLSX.read(buf, {type:'base64'});
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
```csharp
|
||||
engine.Evaluate("var wb = XLSX.read(buf, {type:'base64'});");
|
||||
```
|
||||
|
||||
`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: "base64"`
|
||||
instructs the library to generate Base64 strings. The `bookType` option[^4]
|
||||
controls the output file format.
|
||||
|
||||
:::note pass
|
||||
|
||||
The following expression will be evaluated:
|
||||
|
||||
```js
|
||||
XLSX.write(wb, {bookType: 'ods', type: 'base64'})
|
||||
```
|
||||
|
||||
The result will be passed back to C# code.
|
||||
|
||||
:::
|
||||
|
||||
```csharp
|
||||
string ods = engine.Evaluate("XLSX.write(wb, {bookType: 'ods', type: 'base64'})") as string;
|
||||
```
|
||||
|
||||
`ods` is a Base64 string. `System.Convert.FromBase64String` can decode the
|
||||
string into a `byte[]` which can be written to file:
|
||||
|
||||
```csharp
|
||||
File.WriteAllBytes("SheetJSJurassic.ods", System.Convert.FromBase64String(ods));
|
||||
```
|
||||
|
||||
## Integration Example
|
||||
|
||||
:::note Tested Deployments
|
||||
|
||||
This demo was tested in the following deployments:
|
||||
|
||||
| Architecture | Jurassic | Date |
|
||||
|:-------------|:---------|:-----------|
|
||||
| `darwin-x64` | `3.2.7` | 2024-06-15 |
|
||||
| `darwin-arm` | `3.2.7` | 2024-06-15 |
|
||||
|
||||
:::
|
||||
|
||||
### Platform Configuration
|
||||
|
||||
0) Set the `DOTNET_CLI_TELEMETRY_OPTOUT` environment variable to `1`.
|
||||
|
||||
<details open>
|
||||
<summary><b>How to disable telemetry</b> (click to hide)</summary>
|
||||
|
||||
<Tabs groupId="os">
|
||||
<TabItem value="unix" label="Linux/MacOS">
|
||||
|
||||
Add the following line to `.profile`, `.bashrc` and `.zshrc`:
|
||||
|
||||
```bash title="(add to .profile , .bashrc , and .zshrc)"
|
||||
export DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
```
|
||||
|
||||
Close and restart the Terminal to load the changes.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="win" label="Windows">
|
||||
|
||||
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.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
</details>
|
||||
|
||||
1) Install .NET
|
||||
|
||||
<details>
|
||||
<summary><b>Installation Notes</b> (click to show)</summary>
|
||||
|
||||
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`:
|
||||
|
||||
```bash
|
||||
sudo pacman -Syu dotnet-sdk dotnet-runtime
|
||||
```
|
||||
|
||||
https://dotnet.microsoft.com/en-us/download/dotnet/6.0 is the official source
|
||||
for Windows and ARM64 Linux versions.
|
||||
|
||||
</details>
|
||||
|
||||
2) Open a new Terminal window in macOS or PowerShell window in Windows.
|
||||
|
||||
### Base Project
|
||||
|
||||
3) Create a new folder `SheetJSJurassic` and a new `dotnet` project:
|
||||
|
||||
```bash
|
||||
mkdir SheetJSJurassic
|
||||
cd SheetJSJurassic
|
||||
dotnet new console
|
||||
dotnet run
|
||||
```
|
||||
|
||||
4) Add Jurassic using the NuGet tool:
|
||||
|
||||
```bash
|
||||
dotnet add package Jurassic --version 3.2.7
|
||||
```
|
||||
|
||||
To verify Jurassic is installed, replace `Program.cs` with the following:
|
||||
|
||||
```csharp title="Program.cs"
|
||||
var engine = new Jurassic.ScriptEngine();
|
||||
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 SheetJS mini script, shim script and test file. Move all three
|
||||
files to the project directory:
|
||||
|
||||
<ul>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.mini.min.js`}>xlsx.mini.min.js</a></li>
|
||||
<li><a href={`https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js`}>shim.min.js</a></li>
|
||||
<li><a href="https://docs.sheetjs.com/pres.xlsx">pres.xlsx</a></li>
|
||||
</ul>
|
||||
|
||||
<CodeBlock language="bash">{`\
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/shim.min.js
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-${current}/package/dist/xlsx.mini.min.js
|
||||
curl -LO https://docs.sheetjs.com/pres.xlsx`}
|
||||
</CodeBlock>
|
||||
|
||||
6) Replace `Program.cs` with the following:
|
||||
|
||||
```csharp title="Program.cs"
|
||||
var engine = new Jurassic.ScriptEngine();
|
||||
engine.Evaluate("var global = (function(){ return this; }).call(null);");
|
||||
engine.Evaluate(File.ReadAllText("shim.min.js"));
|
||||
engine.Evaluate(File.ReadAllText("xlsx.mini.min.js"));
|
||||
Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version"));
|
||||
```
|
||||
|
||||
After saving, run the program:
|
||||
|
||||
```bash
|
||||
dotnet run
|
||||
```
|
||||
|
||||
<p>The terminal should display <code>SheetJS version {current}</code></p>
|
||||
|
||||
### Read and Write Files
|
||||
|
||||
7) Replace `Program.cs` with the following:
|
||||
|
||||
```csharp title="Program.cs"
|
||||
var engine = new Jurassic.ScriptEngine();
|
||||
|
||||
/* Initialize Jurassic */
|
||||
engine.Evaluate("var global = (function(){ return this; }).call(null);");
|
||||
|
||||
/* Load SheetJS Scripts */
|
||||
engine.ExecuteFile("shim.min.js");
|
||||
engine.ExecuteFile("xlsx.mini.min.js");
|
||||
Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version"));
|
||||
|
||||
/* Read and Parse File */
|
||||
byte[] filedata = File.ReadAllBytes(args[0]);
|
||||
string b64 = System.Convert.ToBase64String(filedata);
|
||||
engine.SetGlobalValue("buf", b64);
|
||||
engine.Evaluate("var wb = XLSX.read(buf, {type:'base64'});");
|
||||
|
||||
/* Print CSV of first worksheet*/
|
||||
engine.Evaluate("var ws = wb.Sheets[wb.SheetNames[0]];");
|
||||
object csv = engine.Evaluate("XLSX.utils.sheet_to_csv(ws)");
|
||||
Console.Write(csv);
|
||||
|
||||
/* Generate XLSB file and save to SheetJSJurassic.ods */
|
||||
string ods = engine.Evaluate("XLSX.write(wb, {bookType: 'ods', type: 'base64'})") as string;
|
||||
File.WriteAllBytes("SheetJSJurassic.ods", System.Convert.FromBase64String(ods));
|
||||
```
|
||||
|
||||
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 `SheetJSJurassic.ods`, an OpenDocument spreadsheet
|
||||
that can be opened in Excel or another spreadsheet editor.
|
||||
|
||||
:::info pass
|
||||
|
||||
Running `dotnet run` without the filename argument will show an error:
|
||||
|
||||
```
|
||||
Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array.
|
||||
at Program.<Main>$(String[] args) in C:\Users\Me\SheetJSJurassic\Program.cs:line 15
|
||||
```
|
||||
|
||||
The command must be run with an argument specifying the name of the workbook:
|
||||
|
||||
```bash
|
||||
dotnet run pres.xlsx
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
[^1]: The project does not have a website. The library is hosted on [NuGet](https://www.nuget.org/packages/Jurassic/).
|
||||
[^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`
|
47
tests/engines-jurassic.sh
Executable file
47
tests/engines-jurassic.sh
Executable file
@ -0,0 +1,47 @@
|
||||
#!/bin/bash
|
||||
# https://docs.sheetjs.com/docs/demos/engines/jurassic
|
||||
|
||||
cd /tmp
|
||||
rm -rf SheetJSJurassic
|
||||
mkdir SheetJSJurassic
|
||||
cd SheetJSJurassic
|
||||
|
||||
dotnet new console
|
||||
dotnet run
|
||||
|
||||
dotnet add package Jurassic --version 3.2.7
|
||||
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-0.20.2/package/dist/shim.min.js
|
||||
curl -LO https://cdn.sheetjs.com/xlsx-0.20.2/package/dist/xlsx.mini.min.js
|
||||
curl -LO https://docs.sheetjs.com/pres.xlsx
|
||||
|
||||
cat >Program.cs <<EOF
|
||||
/* sheetjs (C) 2013-present SheetJS -- https://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
var engine = new Jurassic.ScriptEngine();
|
||||
|
||||
/* Initialize Jurassic */
|
||||
engine.Evaluate("var global = (function(){ return this; }).call(null);");
|
||||
|
||||
/* Load SheetJS Scripts */
|
||||
engine.ExecuteFile("shim.min.js");
|
||||
engine.ExecuteFile("xlsx.mini.min.js");
|
||||
Console.WriteLine("SheetJS version {0}", engine.Evaluate("XLSX.version"));
|
||||
|
||||
/* Read and Parse File */
|
||||
byte[] filedata = File.ReadAllBytes(args[0]);
|
||||
string b64 = System.Convert.ToBase64String(filedata);
|
||||
engine.SetGlobalValue("buf", b64);
|
||||
engine.Evaluate("var wb = XLSX.read(buf, {type:'base64'});");
|
||||
|
||||
/* Print CSV of first worksheet*/
|
||||
engine.Evaluate("var ws = wb.Sheets[wb.SheetNames[0]];");
|
||||
object csv = engine.Evaluate("XLSX.utils.sheet_to_csv(ws)");
|
||||
Console.Write(csv);
|
||||
|
||||
/* Generate XLSB file and save to SheetJSJurassic.ods */
|
||||
string ods = engine.Evaluate("XLSX.write(wb, {bookType: 'ods', type: 'base64'})") as string;
|
||||
File.WriteAllBytes("SheetJSJurassic.ods", System.Convert.FromBase64String(ods));
|
||||
EOF
|
||||
|
||||
dotnet run pres.xlsx
|
Loading…
Reference in New Issue
Block a user