Demo refresh

This commit is contained in:
SheetJS 2025-03-26 22:49:13 -04:00
parent f9e5e70cef
commit 55c1649e47
8 changed files with 239 additions and 187 deletions

@ -34,7 +34,7 @@
</Style>
</Styles>
<Worksheet ss:Name="Frameworks">
<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"/>
@ -125,6 +125,17 @@
<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/mobile/lynx"><Data ss:Type="String">Lynx</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"><Data ss:Type="String">✔</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"><Data ss:Type="String"></Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String">✘</Data></Cell>
<Cell ss:StyleID="s16"><Data ss:Type="String"> </Data></Cell>
</Row>
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>

@ -35,13 +35,14 @@ This demo was tested in the following configurations:
| Platform | Architecture | Date |
|:------------------------------------------------------------------|:-------------|:-----------|
| NVIDIA RTX 4090 (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | 2025-01-08 |
| NVIDIA RTX 4090 (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | 2025-03-06 |
| NVIDIA RTX 4090 (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `linux-x64` | 2025-01-28 |
| AMD RX 7900 XTX (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `win11-x64` | 2025-01-12 |
| AMD RX 7900 XTX (24 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `linux-x64` | 2025-01-29 |
| Intel Arc B580 (12 GB VRAM) + Ryzen Z1 Extreme (24 GB RAM) | `win11-x64` | 2025-01-24 |
| Intel Arc B580 (12 GB VRAM) + Ryzen Z1 Extreme (16 GB RAM) | `linux-x64` | 2025-02-08 |
| Apple M2 Max 12-Core CPU + 30-Core GPU (32 GB unified memory) | `darwin-arm` | 2024-11-04 |
| Apple M4 Max 16-Core CPU + 40-Core GPU (48 GB unified memory) | `darwin-arm` | 2025-03-06 |
| Apple M2 Max 12-Core CPU + 30-Core GPU (32 GB unified memory) | `darwin-arm` | 2025-03-25 |
SheetJS users have verified this demo in other configurations:
@ -856,7 +857,7 @@ npm i --save https://sheet.lol/balls/xlsx-${current}.tgz`}
4) Install dependencies:
```bash
npm i --save @langchain/community@0.3.22 @langchain/core@0.3.27 langchain@0.3.10 peggy@3.0.2
npm i --save @langchain/core@0.3.42 langchain@0.3.19 @langchain/ollama@0.2.0 peggy@3.0.2
```
:::note pass
@ -865,7 +866,7 @@ In some test runs, there were error messages relating to dependency and peer
dependency versions. The `--force` flag will suppress version mismatch errors:
```bash
npm i --save @langchain/community@0.3.22 @langchain/core@0.3.27 langchain@0.3.10 peggy@3.0.2 --force
npm i --save @langchain/core@0.3.42 langchain@0.3.19 @langchain/ollama@0.2.0 peggy@3.0.2 --force
```
:::
@ -912,7 +913,7 @@ ollama pull nomic-embed-text:latest
B) Edit `query.mjs` to use the embedding model:
```js title="query.mjs (edit highlighted line)"
const model = new ChatOllama({ baseUrl: "http://127.0.0.1:11434", model: modelName });
const llm = new ChatOllama({ baseUrl: "http://127.0.0.1:11434", model });
// highlight-next-line
const embeddings = new OllamaEmbeddings({ baseUrl: "http://127.0.0.1:11434", model: "nomic-embed-text:latest"});
```

@ -97,7 +97,7 @@ _Complete State_
The complete state is initialized with the following snippet:
```js
```js title="State variables"
const [data, setData] = useState([
"SheetJS".split(""),
[5,4,3,3,7,9,5],
@ -112,7 +112,7 @@ const [widths, setWidths] = useState(Array.from({length:7}, () => 20));
Starting from a SheetJS worksheet object, `sheet_to_json`[^3] with the `header`
option can generate an array of arrays:
```js
```js title="Updating state from a workbook"
/* assuming `wb` is a SheetJS workbook */
function update_state(wb) {
/* convert first worksheet to AOA */
@ -133,7 +133,7 @@ _Calculating Column Widths_
Column widths can be calculated by walking each column and calculating the max
data width. Using the array of arrays:
```js
```js title="Calculating column widths"
/* this function takes an array of arrays and generates widths */
function make_width(aoa) {
/* walk each row */
@ -154,7 +154,7 @@ function make_width(aoa) {
`aoa_to_sheet`[^4] builds a SheetJS worksheet object from the array of arrays:
```js
```js title="Exporting state data to a workbook"
/* generate a SheetJS workbook from the state */
function export_state() {
/* convert AOA back to worksheet */
@ -170,13 +170,19 @@ function export_state() {
### Displaying Data
The demos uses `react-native-table-component` to display the first worksheet.
React Native does not ship with a component for displaying tabular data.
`react-native-table-component` is a simple UI component designed for legacy
versions of React Native.
[`react-native-tabeller`](https://git.sheetjs.com/asadbek064/react-native-tabeller)
uses a similar API and follows modern React Native design patterns.
The demos use components similar to the example below:
```jsx
```jsx title="Example JSX for displaying data"
import { ScrollView } from 'react-native';
import { Table, Row, Rows, TableWrapper } from 'react-native-table-component';
import { Table, Row, Rows, TableWrapper } from 'react-native-tabeller';
(
{/* Horizontal scroll */}
@ -226,8 +232,8 @@ This demo was tested in the following environments:
| OS | Device | RN | Date |
|:-----------|:------------------|:---------|:-----------|
| iOS 15.6 | iPhone 13 Pro Max | `0.76.5` | 2025-01-05 |
| Android 34 | NVIDIA Shield | `0.76.5` | 2025-01-05 |
| iOS 15.6 | iPhone 13 Pro Max | `0.76.8` | 2025-03-26 |
| Android 34 | NVIDIA Shield | `0.76.8` | 2025-03-26 |
**Simulators**
@ -235,8 +241,8 @@ This demo was tested in the following environments:
|:-----------|:--------------------|:---------|:-------------|:-----------|
| Android 34 | Pixel 3a | `0.76.5` | `darwin-x64` | 2024-12-31 |
| iOS 18.2 | iPhone 16 Pro | `0.76.5` | `darwin-x64` | 2024-12-31 |
| Android 34 | Pixel 3a | `0.76.5` | `darwin-arm` | 2025-01-05 |
| iOS 18.3 | iPhone 16 Pro | `0.76.5` | `darwin-arm` | 2025-03-08 |
| Android 34 | Pixel 3a | `0.76.8` | `darwin-arm` | 2025-03-26 |
| iOS 18.3 | iPhone 16 Pro | `0.76.8` | `darwin-arm` | 2025-03-26 |
| Android 35 | Pixel 9 | `0.76.5` | `win11-x64` | 2024-12-22 |
| Android 35 | Pixel 9 | `0.76.5` | `linux-x64` | 2025-01-02 |
@ -244,8 +250,9 @@ This demo was tested in the following environments:
:::caution
First install React Native by following the CLI Guide![^1]. Make sure you can run a basic test app on your
phone/simulator before continuing!
**Before testing this demo, follow the official React Native CLI Guide!**[^1]
Make sure you can run a basic test app on your phone/simulator before continuing!
:::
@ -284,14 +291,15 @@ export JAVA_HOME=/usr/lib/jvm/java-17-openjdk
1) Create project:
```bash
npx -y @react-native-community/cli@15 init SheetJSRNFetch --version="0.76.5"
npx -y @react-native-community/cli@15 init SheetJSRNFetch --version="0.76.8"
```
On macOS, if prompted to install `CocoaPods`, press <kbd>Y</kbd>
:::info pass
If you were prompted to install CocoaPods, verify it worked by opening a new terminal and running:
If you were prompted to install CocoaPods, verify it worked by opening a new
terminal and running:
```bash
pod --version
@ -303,7 +311,9 @@ If you see "command not found", install it via `brew`:
brew install cocoapods
```
---
:::
:::note pass
Older versions of this demo used the `react-native` package. The `init` command
was officially deprecated.
@ -319,10 +329,10 @@ scheme is fundamentally different from `react-native`.[^6]
cd SheetJSRNFetch
curl -LO https://docs.sheetjs.com/logo.png
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz
npm i -S https://git.sheetjs.com/asadbek064/react-native-tabeller/raw/branch/main/react-native-tabeller-0.1.0.tgz`}
npm i -S https://cdn.sheetjs.com/react-native-tabeller-0.1.0/react-native-tabeller-0.1.0.tgz`}
</CodeBlock>
3) Download [`App.tsx`](pathname:///reactnative/App.tsx) and replace:
3) Download and replace [`App.tsx`](pathname:///reactnative/App.tsx):
```bash
curl -LO https://docs.sheetjs.com/reactnative/App.tsx
@ -555,8 +565,23 @@ brew install ios-deploy
npx react-native run-ios
```
:::note pass
If the device is not detected, the terminal will print
```
info No booted devices or simulators found. Launching first available simulator...
```
This may happen if the device goes to sleep while connected. Disconnect and
reconnect the device before trying again.
:::
:::info pass
In some test runs, the app requested for local network access:
> "SheetJSRNFetch" would like to find and connect to devices on your local network.
Local network access is not required for the demo. Select "Don't Allow".

@ -6,7 +6,7 @@ pagination_prev: demos/static/index
pagination_next: demos/desktop/index
sidebar_position: 7
sidebar_custom_props:
summary: Lynx + Native Rendering
summary: React + Native Rendering
---
import current from '/version.js';
@ -19,21 +19,23 @@ export const g = {style: {color:"green"}};
export const y = {style: {color:"gold"}};
export const gr = {style: {color:"gray"}};
[Lynx](https://lynxjs.org/) is a modern cross-platform framework. It builds iOS, Android
and Web apps that use JavaScript for describing layouts and events.
[Lynx](https://lynxjs.org/) is a modern cross-platform framework. It builds iOS,
Android and Web apps that use JavaScript for describing layouts and events.
[SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing
data from spreadsheets.
:::caution Lynx support is considered experimental.
Lynx is a great, fast, open-source alternative to React Native. Any issues should be reported to the Lynx project for
further diagnosis.
Lynx is relatively new and does not currently have a deep community.
Any issues should be reported to the Lynx project for further diagnosis.
:::
This demo uses [ReactLynx](https://lynxjs.org/react) and SheetJS to process and generate
spreadsheets. We'll explore how to load SheetJS in ReactLynx app in a few ways:
This demo uses React (using [ReactLynx](https://lynxjs.org/react)) and SheetJS
to process and generate spreadsheets. We'll explore how to load SheetJS in Lynx
apps in the following scenarios:
- ["Fetching Remote Data"](#fetching-remote-data) uses the built-in `fetch` to download
and parse remote workbook files.
@ -54,6 +56,7 @@ The "Fetching Remote Data" example creates an app that looks like the screenshot
</td></tr></tbody></table>
:::caution pass
**Before testing this demo, follow the official React Lynx Guide!**[^1]
Follow the instructions for iOS (requires macOS) and for Android. They will
@ -62,8 +65,15 @@ a sample app in the Android and the iOS (if applicable) simulators.
:::
:::danger pass
## Integration Detail
**Lynx development requires an Apple Silicon-powered Macintosh!**
[X64 is currently unsupported.](https://github.com/lynx-family/lynx/issues/219)
:::
## Integration Details
The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be
imported from any component or script in the app.
@ -99,12 +109,12 @@ Each array represents a row in the table.
This demo also keeps track of the column widths as a single array of numbers.
The widths are used by the display component.
```tsx
```ts title="State variables"
const [data, setData] = useState<any[]>([
"SheetJS".split(""),
[5, 4, 3, 3, 7, 9, 5],
[8, 6, 7, 5, 3, 0, 9]
]);
"SheetJS".split(""),
[5, 4, 3, 3, 7, 9, 5],
[8, 6, 7, 5, 3, 0, 9]
]);
const [widths, setWidths] = useState<number[]>(Array.from({ length: 7 }, () => 20));
```
@ -113,7 +123,7 @@ const [widths, setWidths] = useState<number[]>(Array.from({ length: 7 }, () => 2
Starting from a SheetJS worksheet object, `sheet_to_json`[^3] with the `header`
option can generate an array of arrays:
```js
```js title="Updating state from a workbook"
/* assuming `wb` is a SheetJS workbook */
function update_state(wb) {
/* convert first worksheet to AOA */
@ -134,7 +144,7 @@ _Calculating Column Widths_
Column widths can be calculated by walking each column and calculating the max
data width. Using the array of arrays:
```js
```js title="Calculating column widths"
/* this function takes an array of arrays and generates widths */
function make_width(aoa) {
/* walk each row */
@ -153,28 +163,28 @@ function make_width(aoa) {
### Displaying Data
The demo uses Lynx builtin element `<view/>` and `<text/>` to display the first worksheet.
Lynx does not ship with a component for displaying tabular data.
The demo uses components similar to the example below:
The demo uses Lynx `<view/>` and `<text/>` elements to display tabular data:
```tsx
```tsx title="Example JSX for displaying data"
{/* Table container */}
<view className='Table'>
{/* Map through each row in the data array */}
{data.map((row, rowIndex) => (
<view key={`row-${rowIndex}`} className="Row">
{/* Map through each cell in the current row */}
{Array.isArray(row) && row.map((cell, cellIndex) => (
{/* Cell with dynamic width based on content */}
<view
key={`cell-${rowIndex}-${cellIndex}`} className="Cell"
style={{ width: `${widths[cellIndex]}px` }}>
{/* Display cell content as text */}
<text>{String(cell)}</text>
</view>
))}
</view>
))}
{/* Map through each row in the data array */}
{data.map((row, rowIndex) => (
<view key={`row-${rowIndex}`} className="Row">
{/* Map through each cell in the current row */}
{Array.isArray(row) && row.map((cell, cellIndex) => (
{/* Cell with dynamic width based on content */}
<view
key={`cell-${rowIndex}-${cellIndex}`} className="Cell"
style={{ width: `${widths[cellIndex]}px` }}>
{/* Display cell content as text */}
<text>{String(cell)}</text>
</view>
))}
</view>
))}
</view>
```
@ -182,16 +192,13 @@ The demo uses components similar to the example below:
This snippet downloads and parses https://docs.sheetjs.com/pres.xlsx:
```tsx
```js
/* fetch data into an ArrayBuffer */
const ab = await (await fetch("https://docs.sheetjs.com/pres.xlsx")).arrayBuffer();
/* parse data */
const wb = XLSX.read(ab);
```
The `data.map()` approach allows direct rendering of the worksheet data in a tabular format, with each cell
width dynamically calculated based on content.
### Fetch Demo
:::note Tested Deployments
@ -202,21 +209,23 @@ This demo was tested in the following environments:
| OS | Device | Lynx | LynxExplorer | Dev Platform | Date |
|:-----------|:--------------------|:---------|:-------------|:-------------|:-----------|
| Android 35 | Pixel 3a | `0.8.3` | `3.2.0-rc.0` | `darwin-arm` | 2025-03-11 |
| iOS 18.3 | iPhone 16 Pro | `0.8.3` | `3.2.0-rc.0` | `darwin-arm` | 2025-03-11 |
| Android 35 | Pixel 3a | `0.8.6` | `3.2.0-rc.1` | `darwin-arm` | 2025-03-26 |
| iOS 18.3 | iPhone 16 Pro | `0.8.6` | `3.2.0-rc.1` | `darwin-arm` | 2025-03-26 |
:::
:::danger Real Devices
As of `2025-03-11`, there is no simple, standalone guide on how to build your Lynx app for real devices.
When this demo was last tested, there was no simple standalone guide for running
Lynx apps on real devices.
:::
:::caution
:::caution pass
First install Lynx by following the Guide![^1]. Make sure you can run a basic test app on your
simulator before continuing!
First install Lynx by following the Guide![^1].
Make sure you can run a basic test app on your simulator before continuing!
:::
@ -225,7 +234,7 @@ simulator before continuing!
1) Create project:
```bash
pnpm create rspeedy@0.8.3 -d SheetJSLynxFetch -t react-ts --tools biome
npm create rspeedy@0.8.6 -- -d SheetJSLynxFetch -t react-ts --tools biome
```
2) Install shared dependencies:
@ -233,40 +242,45 @@ pnpm create rspeedy@0.8.3 -d SheetJSLynxFetch -t react-ts --tools biome
<CodeBlock language="bash">{`\
cd SheetJSLynxFetch
curl -o ./src/assets/SheetJS-logo.png https://docs.sheetjs.com/logo.png
pnpm install
pnpm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
npm i
npm i -S https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
</CodeBlock>
3) Download [`App.tsx`](pathname:///lynx/App.tsx) and replace:
3) Download [`App.tsx`](pathname:///lynx/App.tsx) into the `src` folder:
```bash
curl -o ./src/App.tsx https://docs.sheetjs.com/lynx/App.tsx
```
4) Download [`App.css`](pathname://lynx/App.css) and replace:
4) Download [`App.css`](pathname:///lynx/App.css) into the `src` folder:
```bash
curl -o ./src/App.css https://docs.sheetjs.com/lynx/App.css
```
<a id="step5"></a>
5) Start the development server, run:
5) Start the development server:
```bash
pnpm run dev
npm run dev
```
Keep the window open.
#### Android
6) Start the Android emulator:
<details open>
<summary><b>Details</b> (click to hide)</summary>
**Android Studio**
<Tabs>
<TabItem name="Android Studio" value="Android Studio">
In Android Studio, click "More actions" > "Virtual Device Manager". Look for the
emulated device in the list and click the ▶ button to play.
**Command Line**
List the available emulators with `emulator -list-avds`
</TabItem>
<TabItem name="Android Studio" value="Command Line">
List the available emulators with `emulator -list-avds`:
```
shjs@sheetjs SheetJSLynxFetch % emulator -list-avds
@ -274,8 +288,8 @@ Medium_Phone_API_35
^^^^^^^^^^^^^^^^^^^--- emulator name
```
Emulator name should be passed to `emulator -avd`. In a previous test, the name was
`Medium_Phone_API_35` and the launch command was:
The emulator name should be passed to `emulator -avd`. In a previous test, the
name was `Medium_Phone_API_35` and the launch command was:
```bash
emulator -avd Medium_Phone_API_35
@ -293,28 +307,27 @@ emulator -avd Medium_Phone_API_35
:::
</details>
7) While the Android emulator is open, download LynxExplorer[^4] - (Is a sandbox for trying out Lynx quickly)
<Tabs groupId="lang">
<TabItem name="Android" value="Android">
1. Download the pre-build app from the [GitHub Release](https://github.com/lynx-family/lynx/releases/tag/3.2.0-rc.0) and
select the APK `LynxExplorer-noasan-release.apk`.
2. Drag and drop the APK `LynxExplorer-noasan-release.apk` in to your Android simulator.
</TabItem>
</Tabs>
---
8) From [step 5](#step5), you will see a QR code appear in the terminal with a hyperlink like this. Copy the HTTP link.
7) Download the LynxExplorer[^4] APK.
The latest test used [`LynxExplorer-noasan-release.apk` for version `3.2.0-rc.1`](https://github.com/lynx-family/lynx/releases/download/3.2.0-rc.1/LynxExplorer-noasan-release.apk).
8) Drag and drop the APK into the Android emulator window.
The emulator will install LynxExplorer.
9) In the terminal window from [step 5](#step5), copy the HTTP link. It will be
printed below the QR code, as shown in the following screenshot:
![lynx live server link](pathname:///lynx/lynx_live_server_link.png)
9) In the simulator, open the _LynxExplorer_ app. In the input field labeled **Enter Card URL**, paste the link and
click **Go**.
10) In the emulator, open the "LynxExplorer" app.
10) When opened, the app should look like the "Before" screenshot below. After tapping "Import data from a spreadsheet",
verify that the app shows new data:
11) In the **Enter Card URL** input field, paste the link. Tap **Go**.
The view will refresh. The app should look like the "Before" screenshot:
<table><thead><tr>
<th>Before</th>
@ -329,6 +342,9 @@ verify that the app shows new data:
</td></tr></tbody></table>
12) Tap "Import data from a spreadsheet" and verify that the app shows new data.
The app should look like the "After" screenshot.
**iOS Testing**
@ -340,33 +356,29 @@ Xcode and iOS simulators are not available on Windows or Linux.
:::
<Tabs groupId="lang">
<TabItem name="iOS Simulator" value="iOS Simulator">
1. Install Xcode open up the Mac App Store, search for [Xcode](https://apps.apple.com/us/app/xcode/id497799835), and
click Install (or Update if you have it already).
2. Download [`LynxExplorer-arm64.app.tar.gz`](https://github.com/lynx-family/lynx/releases/latest/download/LynxExplorer-arm64.app.tar.gz).
3. Then, extract the downloaded archive:
13) Download the LynxExplorer[^4] app tarball.
```bash
mkdir -p LynxExplorer-arm64.app/
tar -zxf LynxExplorer-arm64.app.tar.gz -C LynxExplorer-arm64.app/
```
The latest test used [`LynxExplorer-arm64.app.tar.gz` for version `3.2.0-rc.1`](https://github.com/lynx-family/lynx/releases/download/3.2.0-rc.1/LynxExplorer-arm64.app.tar.gz).
4. Install LynxExplorer[^4] on simulator open Xcode, and choose Open Developer Tool from the Xcode menu. Click the
Simulator to launch one. Drag "LynxExplorer-arm64.app" into it.
14) Open `LynxExplorer-arm64.app.tar.gz` using Finder.
</TabItem>
</Tabs>
The tarball contains an app named `LynxExplorer-arm64` .
11) From [step 5](#step5), you will see a QR code appear in the terminal with a hyperlink like this. Copy the HTTP link.
15) Launch the iOS Simulator.
16) Click and drag `LynxExplorer-arm64` into the Simulator window.
The simulator will install the "LynxExplorer" app.
17) Copy the HTTP link from the terminal window in [step 5](#step5).
![lynx live server link](pathname:///lynx/lynx_live_server_link.png)
12) In the simulator, open the _LynxExplorer_ app. In the input field labeled **Enter Card URL**, paste the link and
click **Go**.
18) Tap the "LynxExplorer" icon in the simulator to launch the app.
13) When opened, the app should look like the "Before" screenshot below. After tapping "Import data from a spreadsheet",
verify that the app shows new data:
19) Tap the **Enter Card URL** input field and paste the link. Tap **Go**.
The view will refresh. The app should look like the "Before" screenshot:
<table><thead><tr>
<th>Before</th>
@ -381,8 +393,10 @@ Xcode and iOS simulators are not available on Windows or Linux.
</td></tr></tbody></table>
[^1]: Follow the ["Quick Start guide](https://lynxjs.org/guide/start/quick-start.html) and select the appropriate
"Lynx Explorer sandbox"
20) Tap "Import data from a spreadsheet" and verify that the app shows new data. The app should look like the "After" screenshot.
[^1]: Follow ["Quick Start"](https://lynxjs.org/guide/start/quick-start.html) in
the Lynx documentation and select the appropriate "Lynx Explorer sandbox"
[^2]: See ["Array of Arrays" in the API reference](/docs/api/utilities/array#array-of-arrays)
[^3]: See ["Array Output" in "Utility Functions"](/docs/api/utilities/array#array-output)
[^4]: See ["LynxExplorer sandbox"](https://github.com/lynx-family/lynx/releases/tag/3.2.0-rc.0/)
[^4]: See ["LynxExplorer sandbox"](https://github.com/lynx-family/lynx/releases/latest/)

@ -4,7 +4,7 @@ sidebar_label: Ghidra
pagination_prev: demos/cloud/index
pagination_next: demos/bigdata/index
sidebar_custom_props:
summary: Generate spreadsheets from Ghidra-generated bitfield tables
summary: Generate spreadsheets from bitfield tables extracted from programs
---
import current from '/version.js';
@ -154,7 +154,17 @@ handles the plugin and file extension details.
`ghidra.app.decompiler.DecompInterface` is the primary Java interface to the
decompiler. In Ghidra.js, `JavaHelper.getClass` will load the class.
_Java_
```js title="Launch decompiler process in Ghidra.js"
const DecompInterface = JavaHelper.getClass('ghidra.app.decompiler.DecompInterface');
const decompiler = new DecompInterface();
decompiler.openProgram(currentProgram);
```
<details>
<summary><b>Equivalent Java Code</b> (click to show)</summary>
The Ghidra.js snippet approximates the following Java code:
```java title="Launch decompiler process in Java (snippet)"
import ghidra.app.script.GhidraScript;
@ -170,20 +180,14 @@ public class SheetZilla extends GhidraScript {
}
```
_Ghidra.js_
```js title="Launch decompiler process in Ghidra.js"
const DecompInterface = JavaHelper.getClass('ghidra.app.decompiler.DecompInterface');
const decompiler = new DecompInterface();
decompiler.openProgram(currentProgram);
```
</details>
#### Identifying a Function
The `getGlobalSymbols` method of a symbol table instance will return an array of
symbols matching the given name:
```js
```js title="Find one symbol matching a given name"
/* name of function to find */
const fname = 'MyMethod';
@ -198,7 +202,7 @@ const fsymb = fsymbs[0];
The `getFunctionAt` method of a function manager instance will take an address
and return a reference to a function:
```js
```js title="Fetch details about a function identified by a symbol"
/* get address */
const faddr = fsymb.getAddress();
@ -209,17 +213,15 @@ const fn = currentProgram.getFunctionManager().getFunctionAt(faddr);
#### Decompiling a Function
The `decompileFunction` method attempts to decompile the referenced function:
The `decompileFunction` method attempts to decompile the referenced function.
Once decompiled, the `getC` method retrieves the decompiled C code:
```js
```js title="Decompile a function identified by a reference"
/* decompile function */
// highlight-next-line
const decomp = decompiler.decompileFunction(fn, 10000, null);
```
Once decompiled, it is possible to retrieve the decompiled C code:
```js
/* get generated C code */
const src = decomp.getDecompiledFunction().getC();
```
@ -293,7 +295,8 @@ sudo npm install -g ghidra.js
3) Create a temporary folder to hold the Ghidra project:
```bash
mkdir -p /tmp/sheetjs-ghidra; cd /tmp/sheetjs-ghidra;
mkdir -p /tmp/sheetjs-ghidra
cd /tmp/sheetjs-ghidra
```
4) Copy the `TSTables` framework to the current directory:
@ -322,7 +325,9 @@ $(dirname $(realpath `which ghidraRun`))/support/analyzeHeadless /tmp/sheetjs-gh
```
<details>
<summary><b>Above Command Execution Notes</b> (click to show)</summary>
<summary><b>Troubleshooting</b> (click to show)</summary>
**JDK Settings**
On macOS, you may see the prompt:
@ -334,41 +339,47 @@ Enter path to JDK home directory:
```
When this appears, enter the path to your JDK installation. The default path is typically:
If prompted, enter the path to the JDK installation. On macOS, JDK installations
are typically stored in `/Library/Java/JavaVirtualMachines`. The required path
is the `/Contents/Home/` folder within the specific JDK installation.
```
/Library/Java/JavaVirtualMachines/jdk-[version].jdk//Contents/Home/
```
or similar, depending on your installed Java version.
Make sure it's version 21 or greater. If you don't have it installed, you can install it via brew:
When this demo was last tested, Zulu JDK 21 was installed with Homebrew:
```bash
brew install --cask zulu@21
```
If you get a message saying "decompile Not opened", don't worry - this is just macOS Gatekeeper preventing the
app from running.
The path to the JDK home directory was:
```
/Library/Java/JavaVirtualMachines/zulu-21.jdk/Contents/Home/
```
---
**Gatekeeper**
macOS Gatekeeper may prevent Ghidra from launching helper programs. When this
happens, macOS will show a message stating that a program was "Not opened":
![macOS apple silicon, decompile not opened notice](pathname:///ghidra/macos_apple_silicon/decompile_not_opened_notice.png)
To resolve adjust Gatekeeper settings:
An administrator account must explicitly allow the supporting programs to run:
1. Open up "System Settings"
2. Find the "Privacy & security" tab on the left side and click on it.
3. Scroll down to "Security" section and look for "Allow application from".
4. Choose the option saying "App Store & Known Developers
5. Click "Allow Anyway" for "decompile" was blocked to protect your Mac.
1. Open "System Settings" from the Apple menu
2. In the left sidebar, scroll down and select the "Privacy & Security" tab.
3. In the main area, scroll down to the "Security" section
4. In the "Allow applications from" box, select "App Store & Known Developers"
5. Next to '"decompile" was blocked to protect your Mac', click "Allow Anyway".
![macOS apple silicon, privacy security allow application and allow decompile](pathname:///ghidra/macos_apple_silicon/privacy_security_allow_application_and_allow_decompile.png)
6. If you get another pop up modal `Open "decompile"` click "Open Anyway"
6. If macOS shows another `Open "decompile"` popup, click "Open Anyway".
![macOS apple silicon, Open "decompile" modal pop up](pathname:///ghidra/macos_apple_silicon/open_decompile_open_anyway.png)
7. After you will get another pop up modal "Privacy & Security" click "Use Password..."
7. If macOS shows a "Privacy & Security" popup, authenticate with a password by
clicking "Use Password..." and entering the password in the next popup.
![macOS apple silicon, "Privacy & Security" modal pop up](pathname:///ghidra/macos_apple_silicon/privacy_and_security_use_password.png)
@ -401,7 +412,7 @@ npm i --save https://cdn.sheetjs.com/xlsx-${current}/xlsx-${current}.tgz`}
$(dirname $(realpath `which ghidraRun`))/support/analyzeHeadless /tmp/sheetjs-ghidra Numbers -process TSTables.macho -noanalysis -scriptPath `pwd` -postScript sheetjs-ghidra.js
```
10) Open the generated `SheetJSGhidraTSTCell.xlsx` spreadsheet.
10) Open the generated `SheetJSGhidraTSTCell.xlsx` spreadsheet with Numbers:
```bash
open -a "Numbers" SheetJSGhidraTSTCell.xlsx

@ -406,7 +406,7 @@ This demo was tested in the following deployments:
| Architecture | Version | PHP | Date |
|:-------------|:--------|:---------|:-----------|
| `darwin-x64` | `2.7.0` | `8.4.2` | 2024-12-31 |
| `darwin-arm` | `2.7.0` | `8.3.8` | 2024-06-30 |
| `darwin-arm` | `2.7.0` | `8.4.4` | 2025-02-25 |
| `linux-x64` | `2.7.0` | `8.3.3` | 2024-12-31 |
| `linux-arm` | `2.7.0` | `8.2.26` | 2025-02-15 |

@ -230,7 +230,7 @@ sudo apt-get install -y make
```
</TabItem>
<TabItem value="osx" label="MacOS">
<TabItem value="osx" label="MacOS" default>
A) Open a terminal window and run `git`:
@ -287,15 +287,15 @@ browser.
![NodeJS macOS Installation](pathname:///contributing/nodejs_macos_installation.png)
Select the following dropdown options as follows:
*In the `"Get Node.js®"` section:*
1. "Get Node.js®": Select the LTS version (currently `"v22.14.0 (LTS)"`)
1. Select the LTS version (currently `"v22.14.0 (LTS)"`) in the first dropdown
Then scroll down to `"Or get a prebuilt Node.js® for"` section and:
*In the `"Or get a prebuilt Node.js® for"` section:*
2. Select `"macOS"` from the first dropdown
2. Select `"macOS"` from the first dropdown.
3. Select `"ARM64"` for Apple Silicon Macs or `"x64"` for Intel Macs from the second dropdown
3. Select `"ARM64"` for Apple Silicon Macs or `"x64"` for Intel Macs in the second dropdown
4. Click the green <span style={{backgroundColor: '#417E38', padding: '0.4rem 0.4rem', borderRadius:
'0.25rem', color: 'white'}}>macOS Installer (.pkg)</span> button to download the installer

@ -1,20 +1,20 @@
/* NOTE: hnswlib-node@3.0.0 does not install on a fresh Windows 11 setup */
// import { existsSync } from 'fs';
import { ChatOllama } from "@langchain/community/chat_models/ollama";
import { OllamaEmbeddings } from "@langchain/community/embeddings/ollama"
// import { HNSWLib } from "@langchain/community/vectorstores/hnswlib";
import { ChatOllama, OllamaEmbeddings } from "@langchain/ollama";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { SelfQueryRetriever } from "langchain/retrievers/self_query";
import { FunctionalTranslator } from "@langchain/core/structured_query";
import LoadOfSheet from "./loadofsheet.mjs";
const modelName = "llama3-chatqa:8b-v1.5-q8_0";
let s = 0, spin = ['\\', '|', '/', '-'];
setInterval(() => { process.stderr.write(spin[s = ++s % spin.length] + '\u001b[0G'); }, 100).unref();
process.on('exit', function() { process.stderr.write('\u001b[2K'); });
console.log(`Using model ${modelName}`);
const model = "llama3-chatqa:8b-v1.5-q8_0";
const model = new ChatOllama({ baseUrl: "http://localhost:11434", model: modelName });
const embeddings = new OllamaEmbeddings({model: modelName});
console.log(`Using model ${model}`);
const llm = new ChatOllama({ baseUrl: "http://127.0.0.1:11434", model });
const embeddings = new OllamaEmbeddings({model});
console.time("load of sheet");
const loader = new LoadOfSheet("./cd.xls");
@ -22,23 +22,13 @@ const docs = await loader.load();
console.timeEnd("load of sheet");
console.time("vector store");
const vectorstore = await MemoryVectorStore.fromDocuments(docs, embeddings);
/*
const vectorstore = await (async() => {
if(!existsSync("store/hnswlib.index")) {
const vectorstore = await HNSWLib.fromDocuments(docs, embeddings);
await vectorstore.save("store");
return vectorstore;
}
return await HNSWLib.load("store", embeddings);
})();
*/
const vectorStore = await MemoryVectorStore.fromDocuments(docs, embeddings);
console.timeEnd("vector store");
console.time("query");
const selfQueryRetriever = SelfQueryRetriever.fromLLM({
llm: model,
vectorStore: vectorstore,
llm,
vectorStore,
documentContents: "Data rows from a worksheet",
attributeInfo: loader.attributes,
structuredQueryTranslator: new FunctionalTranslator(),