forked from sheetjs/docs.sheetjs.com
		
	quick
This commit is contained in:
		
							parent
							
								
									efc57df123
								
							
						
					
					
						commit
						edaa2e6b5e
					
				| @ -33,3 +33,6 @@ Specific pages can load scripts using the `head` component: | ||||
| </head> | ||||
| ``` | ||||
| 
 | ||||
| ## Other Notes | ||||
| 
 | ||||
| `src/theme/Admonition` was swizzled from 2.4.1 to address Docusaurus issue 8568 | ||||
| @ -22,10 +22,25 @@ Most scenarios involving spreadsheets and data can be divided into 5 parts: | ||||
|    locally.  Data can be presented to users in an HTML TABLE or data grid. | ||||
| 
 | ||||
| A common problem involves generating a valid spreadsheet export from data stored | ||||
| in an HTML table.  In this example, an HTML TABLE on the page will be scraped, | ||||
| a row will be added to the bottom with the date of the report, and a new file | ||||
| will be generated and downloaded locally. `XLSX.writeFile` takes care of | ||||
| packaging the data and attempting a local download: | ||||
| in an HTML table. | ||||
| 
 | ||||
| ```mermaid | ||||
| flowchart LR | ||||
|   server[(Backend\nServer)] | ||||
|   html{{HTML\nTABLE}} | ||||
|   wb(((SheetJS\nWorkbook))) | ||||
|   wb2(((Modified\nWorkbook))) | ||||
|   file[(workbook\nfile)] | ||||
|   server --> |"Get Table (1)\n."| html | ||||
|   html --> |"Parse Table (2)\n`table_to_book`"| wb | ||||
|   wb --> |"Add data (3)\n`sheet_add_aoa`"| wb2 | ||||
|   wb2 --> |"Export file (4,5)\n`writeFile`"| file | ||||
| ``` | ||||
| 
 | ||||
| In this example, an HTML TABLE on the page will be scraped, a row will be added | ||||
| to the bottom with the date of the report, and a new file will be generated and | ||||
| downloaded locally. `XLSX.writeFile` takes care of packaging the data and | ||||
| attempting a local download: | ||||
| 
 | ||||
| ```js | ||||
| // Acquire Data (reference to the HTML table) | ||||
| @ -54,6 +69,9 @@ Utility functions help with step 3. | ||||
| 
 | ||||
| ## Highlights | ||||
| 
 | ||||
| ["Demos"](/docs/demos) describes special deployments using SheetJS in tandem with | ||||
| other tools and libraries. | ||||
| 
 | ||||
| ["Data Import"](/docs/solutions/input) describes solutions for common data import | ||||
| scenarios. | ||||
| 
 | ||||
|  | ||||
| @ -94,14 +94,22 @@ export default defineConfig({ | ||||
| ``` | ||||
| 
 | ||||
| In frontend code, the loader will look for all modules with a `?sheetjs` | ||||
| query string. The default export is an array of row objects: | ||||
| query string. The default export is an array of row objects. | ||||
| 
 | ||||
| The following example script displays the data in a table: | ||||
| 
 | ||||
| ```js title="main.js" | ||||
| import data from './data.xlsx?sheetjs'; | ||||
| import data from './data/pres.xlsx?sheetjs'; | ||||
| 
 | ||||
| document.querySelector('#app').innerHTML = `<div><pre> | ||||
|   ${data.map(row => JSON.stringify(row)).join("\n")} | ||||
| </pre></div>`; | ||||
| document.querySelector('#app').innerHTML = `<table> | ||||
|   <thead><tr><th>Name</th><th>Index</th></tr></thead> | ||||
|   <tbody> | ||||
|     ${data.map(row => `<tr> | ||||
|       <td>${row.Name}</td> | ||||
|       <td>${row.Index}</td> | ||||
|     </tr>`).join("\n")} | ||||
|   </tbody> | ||||
| </table>`; | ||||
| ``` | ||||
| 
 | ||||
| ### Base64 Plugin | ||||
| @ -155,17 +163,23 @@ When importing using the `b64` query, the raw Base64 string will be exposed. | ||||
| ```js title="main.js" | ||||
| import { read, utils } from "xlsx"; | ||||
| 
 | ||||
| /* reference workbook */ | ||||
| /* import workbook data */ | ||||
| import b64 from './data.xlsx?b64'; | ||||
| /* parse workbook and export first sheet to CSV */ | ||||
| 
 | ||||
| /* parse workbook and pull data from the first worksheet */ | ||||
| const wb = read(b64, { type: "base64" }); | ||||
| const wsname = wb.SheetNames[0]; | ||||
| const csv = utils.sheet_to_csv(wb.Sheets[wsname]); | ||||
| const data = utils.sheet_to_json(wb.Sheets[wsname]); | ||||
| 
 | ||||
| document.querySelector('#app').innerHTML = `<div><pre> | ||||
| <b>${wsname}</b> | ||||
| ${csv} | ||||
| </pre></div>`; | ||||
| document.querySelector('#app').innerHTML = `<table> | ||||
|   <thead><tr><th>Name</th><th>Index</th></tr></thead> | ||||
|   <tbody> | ||||
|     ${data.map(row => `<tr> | ||||
|       <td>${row.Name}</td> | ||||
|       <td>${row.Index}</td> | ||||
|     </tr>`).join("\n")} | ||||
|   </tbody> | ||||
| </table>`; | ||||
| ``` | ||||
| 
 | ||||
| ## Complete Demo | ||||
| @ -278,7 +292,7 @@ source.  The code will reference some script like `/assets/index-HASH.js`. | ||||
| Open that script.  Searching for `Bill Clinton` reveals the following: | ||||
| 
 | ||||
| ``` | ||||
| JSON.parse('[{"Name":"Bill Clinton","Index":42} | ||||
| {"Name":"Bill Clinton","Index":42} | ||||
| ``` | ||||
| 
 | ||||
| Searching for `BESSELJ` should reveal no results.  The SheetJS scripts are not | ||||
| @ -350,9 +364,9 @@ The SheetJS library is embedded in the final site. | ||||
| 
 | ||||
| [^1]: See ["Using Plugins"](https://vitejs.dev/guide/using-plugins.html) in the ViteJS documentation. | ||||
| [^2]: See ["Static Asset Handling"](https://vitejs.dev/guide/assets.html) in the ViteJS documentation. | ||||
| [^3]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/#array-output) | ||||
| [^4]: See [`read` in "Parsing Options"](/docs/api/parse-options) | ||||
| [^5]: See [`read` in "Parsing Options"](/docs/api/parse-options) | ||||
| [^6]: See [the "base64" type in "Parsing Options"](/docs/api/parse-options#input-type) | ||||
| [^3]: See [`read` in "Reading Files"](/docs/api/parse-options) | ||||
| [^4]: See [`sheet_to_json` in "Utilities"](/docs/api/utilities/array#array-output) | ||||
| [^5]: See [`read` in "Reading Files"](/docs/api/parse-options) | ||||
| [^6]: See [the "base64" type in "Reading Files"](/docs/api/parse-options#input-type) | ||||
| [^7]: See [`SheetJS/sheetjs-vite`](https://git.sheetjs.com/sheetjs/sheetjs-vite/) on the SheetJS git server. | ||||
| [^8]: See ["Server-Side Rendering"](https://vitejs.dev/guide/ssr.html) in the ViteJS documentation. | ||||
| @ -1,5 +1,7 @@ | ||||
| --- | ||||
| title: Wails | ||||
| sidebar_label: Wails | ||||
| description: Build data-intensive desktop apps using Wails. Seamlessly integrate spreadsheets into your app using SheetJS. Modernize Excel-powered business processes with confidence. | ||||
| pagination_prev: demos/mobile/index | ||||
| pagination_next: demos/data/index | ||||
| sidebar_position: 3 | ||||
| @ -7,18 +9,28 @@ sidebar_custom_props: | ||||
|   summary: Webview + Go Backend | ||||
| --- | ||||
| 
 | ||||
| # Spreadsheet-Powered Wails Apps | ||||
| 
 | ||||
| import current from '/version.js'; | ||||
| import Tabs from '@theme/Tabs'; | ||||
| import TabItem from '@theme/TabItem'; | ||||
| import CodeBlock from '@theme/CodeBlock'; | ||||
| 
 | ||||
| The [NodeJS Module](/docs/getting-started/installation/nodejs) can be imported | ||||
| from JavaScript code. | ||||
| [Wails](https://wails.io/) is a modern toolkit for building desktop apps. Wails | ||||
| apps pair a Go-powered backend with a JavaScript-powered frontend[^1]. | ||||
| 
 | ||||
| The "Complete Example" creates an app that looks like the screenshot: | ||||
| [SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing | ||||
| data from spreadsheets. | ||||
| 
 | ||||
| This demo uses Wails and SheetJS to pull data from a spreadsheet and display the | ||||
| data in the app. We'll explore how to load SheetJS in a Wails app and exchange | ||||
| file data between the JavaScript frontend and Go backend. | ||||
| 
 | ||||
| The ["Complete Example"](#complete-example) section covers a complete desktop | ||||
| app to read and write workbooks. The app will look like the screenshots below: | ||||
| 
 | ||||
| <table><thead><tr> | ||||
|   <th><a href="#complete-example">Win10</a></th> | ||||
|   <th><a href="#complete-example">Windows</a></th> | ||||
|   <th><a href="#complete-example">macOS</a></th> | ||||
|   <th><a href="#complete-example">Linux</a></th> | ||||
| </tr></thead><tbody><tr><td> | ||||
| @ -35,49 +47,71 @@ The "Complete Example" creates an app that looks like the screenshot: | ||||
| 
 | ||||
| </td></tr></tbody></table> | ||||
| 
 | ||||
| ## Integration Details | ||||
| :::info | ||||
| 
 | ||||
| All operations must be run from Go code.  This example passes Base64 strings. | ||||
| 
 | ||||
| :::caution | ||||
| 
 | ||||
| Wails currently does not provide the equivalent of NodeJS `fs` module.  All raw | ||||
| file operations must be performed in Go code. | ||||
| 
 | ||||
| The HTML File Input Element does not show a file picker.  This is a known bug. | ||||
| The demo works around the issue by showing pickers in Go code. | ||||
| This demo assumes some familiarity with JavaScript and with Go. If you would | ||||
| prefer a pure JavaScript solution, the [Electron](/docs/demos/desktop/electron) | ||||
| platform provides many native features out of the box. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ## Integration Details | ||||
| 
 | ||||
| The [SheetJS NodeJS Module](/docs/getting-started/installation/nodejs) can be | ||||
| installed in the `frontend` folder and imported in frontend scripts. | ||||
| 
 | ||||
| :::caution | ||||
| 
 | ||||
| Wails currently does not provide the equivalent of NodeJS `fs` module. | ||||
| 
 | ||||
| Reading and writing raw file data must be implemented in native Go code. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| This demo includes native Go code for showing dialogs and reading and writing | ||||
| files. When sending data between Go and JavaScript code, the raw files are | ||||
| encoded as Base64 strings. | ||||
| 
 | ||||
| ### Reading Files | ||||
| 
 | ||||
| The file picker and reading operations can be combined in one Go function. | ||||
| When the user clicks the "Import File" button, the frontend tells the Go backend | ||||
| to read data. The user will be presented with a file picker to select a file to | ||||
| read. The Go backend will read the data, encode as a Base64 string, and send the | ||||
| result to the frontend. | ||||
| 
 | ||||
| The frontend will parse the data using the SheetJS `read` method[^2], generate | ||||
| HTML tables with `sheet_to_html`[^3], and display the tables on the frontend. | ||||
| 
 | ||||
| The following diagram summarizes the steps: | ||||
| 
 | ||||
| ```mermaid | ||||
| sequenceDiagram | ||||
|   autonumber | ||||
|   actor User | ||||
|   participant JS | ||||
|   participant Go | ||||
|   participant JS as Frontend (JS) | ||||
|   participant Go as Backend (Go) | ||||
|   User->>JS: click button | ||||
|   JS->>Go: ask for data | ||||
|   Note over Go: Show Open Dialog | ||||
|   Note over Go: Read File Bytes | ||||
|   Note over Go: Generate Base64 | ||||
|   Go->>JS: return data | ||||
|   Note over JS: Parse data | ||||
|   Note over JS: Display Table | ||||
|   Note over JS: Parse Data<br/>`read` | ||||
|   Note over JS: Display Table<br/>`sheet_to_html` | ||||
|   JS->>User: app shows data | ||||
| ``` | ||||
| 
 | ||||
| #### Go | ||||
| 
 | ||||
| The Wails runtime provides the cross-platform `OpenFileDialog` function[^4] to | ||||
| show a file picker. The Go standard library provides methods for reading data | ||||
| from the selected file[^5] and encoding in a Base64 string[^6] | ||||
| 
 | ||||
| ```go | ||||
| import ( | ||||
|   "context" | ||||
| // highlight-start | ||||
|   "encoding/base64" | ||||
|   "io/ioutil" | ||||
|   "os" | ||||
|   "github.com/wailsapp/wails/v2/pkg/runtime" | ||||
| // highlight-end | ||||
| ) | ||||
| @ -98,7 +132,7 @@ func (a *App) ReadFile() string { | ||||
|   }) | ||||
|   if err != nil { return "" } // The demo app shows an error message | ||||
|   // highlight-next-line | ||||
|   data, err := ioutil.ReadFile(selection) | ||||
|   data, err := os.ReadFile(selection) | ||||
|   if err != nil { return "" } // The demo app shows an error message | ||||
|   // highlight-next-line | ||||
|   return base64.StdEncoding.EncodeToString(data) | ||||
| @ -107,7 +141,8 @@ func (a *App) ReadFile() string { | ||||
| 
 | ||||
| #### JS | ||||
| 
 | ||||
| Wails will automatically create bindings for use in JS: | ||||
| Wails will automatically create bindings for use in JS. The `App` binding module | ||||
| will export the function `ReadFile`. | ||||
| 
 | ||||
| ```js title="frontend/src/App.svelte" | ||||
| import { read, utils } from 'xlsx'; | ||||
| @ -115,38 +150,53 @@ import { ReadFile } from '../wailsjs/go/main/App'; | ||||
| 
 | ||||
| async function importFile(evt) { | ||||
| // highlight-start | ||||
|   /* call the native Go function and receive a base64 string */ | ||||
|   const b64 = await ReadFile(); | ||||
|   /* parse the base64 string with SheetJS */ | ||||
|   const wb = read(b64, { type: "base64" }); | ||||
| // highlight-end | ||||
| 
 | ||||
|   const ws = wb.Sheets[wb.SheetNames[0]]; // get the first worksheet | ||||
|   html = utils.sheet_to_html(ws); // generate HTML and update state | ||||
|   return utils.sheet_to_html(ws); // generate HTML table | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ### Writing Files | ||||
| 
 | ||||
| There is a multi-part dance since the library needs the file extension. | ||||
| :::info | ||||
| 
 | ||||
| 1) Show the save file picker in Go, pass back to JS | ||||
| The SheetJS `write` method[^7] can write spreadsheets in a number of formats[^8] | ||||
| including XLSX, XLSB, XLS, and NUMBERS. It expects a `bookType` option. This | ||||
| means the frontend needs to know the output file name before creating the file. | ||||
| 
 | ||||
| 2) Generate the file data in JS, pass the data back to Go | ||||
| ::: | ||||
| 
 | ||||
| 3) Write to file in Go | ||||
| When the user clicks the "Export File" button, the frontend asks the Go backend | ||||
| for the output filename and path. The user will be presented with a file picker | ||||
| to select the output folder and workbook type. The backend will send the name | ||||
| to the frontend. | ||||
| 
 | ||||
| The frontend will generate a workbook object from the table using the SheetJS | ||||
| `table_to_book` method[^9]. The SheetJS `write` method[^10] will generate a | ||||
| Base64 string from the data. | ||||
| 
 | ||||
| The frontend will send the Base64 string to the backend. The backend will write | ||||
| the data to a file in the selected folder. | ||||
| 
 | ||||
| ```mermaid | ||||
| sequenceDiagram | ||||
|   autonumber | ||||
|   actor User | ||||
|   participant JS | ||||
|   participant Go | ||||
|   participant JS as Frontend (JS) | ||||
|   participant Go as Backend (Go) | ||||
|   User->>JS: click button | ||||
|   JS->>Go: ask for path | ||||
|   Note over Go: Show Save Dialog | ||||
|   Go->>JS: path to save file | ||||
|   Note over JS: write workbook | ||||
|   Note over JS: Read from Table<br/>`table_to_book` | ||||
|   Note over JS: Write Workbook<br/>`write` | ||||
|   JS->>Go: base64-encoded bytes | ||||
|   Note over Go: decode data | ||||
|   Note over Go: write to file | ||||
|   Note over Go: Decode Data | ||||
|   Note over Go: Write to File | ||||
|   Go->>JS: write finished | ||||
|   JS->>User: alert | ||||
| ``` | ||||
| @ -155,7 +205,8 @@ sequenceDiagram | ||||
| 
 | ||||
| Two Go functions will be exposed. | ||||
| 
 | ||||
| - `SaveFile` will show the file picker and return the path: | ||||
| - `SaveFile` will show the file picker and return the path. It will use the | ||||
|   cross-platform `SaveFileDialog` function[^11]. | ||||
| 
 | ||||
| ```go | ||||
| import ( | ||||
| @ -183,14 +234,16 @@ func (a *App) SaveFile() string { | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| - `WriteFile` performs the file write given a Base64 string and file path: | ||||
| - `WriteFile` performs the file write given a Base64 string and file path. The | ||||
|   Go standard library provides methods for decoding Base64 strings[^12] and | ||||
|   writing data to the filesystem[^13] | ||||
| 
 | ||||
| ```go | ||||
| import ( | ||||
|   "context" | ||||
| // highlight-start | ||||
|   "encoding/base64" | ||||
|   "io/ioutil" | ||||
|   "os" | ||||
| // highlight-end | ||||
| ) | ||||
| 
 | ||||
| @ -201,29 +254,32 @@ type App struct { | ||||
| func (a *App) WriteFile(b64 string, path string) { | ||||
|   // highlight-start | ||||
|   buf, _ := base64.StdEncoding.DecodeString(b64); | ||||
|   _ = ioutil.WriteFile(path, buf, 0644); | ||||
|   _ = os.WriteFile(path, buf, 0644); | ||||
|   // highlight-end | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| #### JS | ||||
| 
 | ||||
| Wails will automatically create bindings for use in JS: | ||||
| Wails will automatically create bindings for use in JS. The `App` binding module | ||||
| will export the functions `SaveFile` and `WriteFile`: | ||||
| 
 | ||||
| ```js | ||||
| ```js title="frontend/src/App.svelte" | ||||
| import { utils, write } from 'xlsx'; | ||||
| import { SaveFile, WriteFile } from '../wailsjs/go/main/App'; | ||||
| 
 | ||||
| async function exportFile(wb) { | ||||
| async function exportFile(table_element) { | ||||
|   /* generate workbook */ | ||||
|   const elt = tbl.getElementsByTagName("TABLE")[0]; | ||||
|   const wb = utils.table_to_book(elt); | ||||
|   const wb = utils.table_to_book(table_element); | ||||
| 
 | ||||
|   /* show save picker and get path */ | ||||
|   const path = await SaveFile(); | ||||
| 
 | ||||
|   /* generate base64 string based on the path */ | ||||
|   const b64 = write(wb, { bookType: path.slice(path.lastIndexOf(".")+1), type: "base64" }); | ||||
|   /* get the file extension -> bookType */ | ||||
|   const bookType = path.slice(path.lastIndexOf(".")+1); | ||||
| 
 | ||||
|   /* generate base64 string */ | ||||
|   const b64 = write(wb, { bookType: bookType, type: "base64" }); | ||||
| 
 | ||||
|   /* write to file */ | ||||
|   await WriteFile(b64, path); | ||||
| @ -239,7 +295,44 @@ the Svelte TypeScript starter. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 0) [Read Wails "Getting Started" guide and install dependencies.](https://wails.io/docs/gettingstarted/installation) | ||||
| 0) Read the Wails "Getting Started" guide[^14] and install dependencies. | ||||
| 
 | ||||
| <details><summary><b>Installation Notes</b> (click to show)</summary> | ||||
| 
 | ||||
| Wails will require: | ||||
| 
 | ||||
| - A recent version of [Go](https://go.dev/doc/install). | ||||
| - The "LTS" version of [NodeJS](https://nodejs.org/en/download). | ||||
| 
 | ||||
| After installing both, run the following command to install Wails: | ||||
| 
 | ||||
| ```bash | ||||
| go install github.com/wailsapp/wails/v2/cmd/wails@latest | ||||
| ``` | ||||
| 
 | ||||
| Once that finishes, run the following command in a new terminal window: | ||||
| 
 | ||||
| ```bash | ||||
| wails doctor | ||||
| ``` | ||||
| 
 | ||||
| The output will include a `# Diagnosis` section. It should display: | ||||
| 
 | ||||
| ``` | ||||
| # Diagnosis | ||||
| 
 | ||||
| Your system is ready for Wails development! | ||||
| ``` | ||||
| 
 | ||||
| If a required dependency is missing, it will be displayed. | ||||
| 
 | ||||
| :::note | ||||
| 
 | ||||
| None of the optional packages are required for building and running this demo. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| 1) Create a new Wails app: | ||||
| 
 | ||||
| @ -280,3 +373,18 @@ wails build | ||||
| ``` | ||||
| 
 | ||||
| At the end, it will print the path to the generated program. Run the program! | ||||
| 
 | ||||
| [^1]: See ["How does it Work?"](https://wails.io/docs/howdoesitwork) in the Wails documentation. | ||||
| [^2]: See [`read` in "Parsing Options"](/docs/api/parse-options) | ||||
| [^3]: See [`sheet_to_html` in "Utilities"](/docs/api/utilities/html#html-table-output) | ||||
| [^4]: See [`OpenFileDialog`](https://wails.io/docs/reference/runtime/dialog#openfiledialog) in the Wails documentation. | ||||
| [^5]: See [`ReadFile`](https://pkg.go.dev/os#ReadFile) in the Go documentation | ||||
| [^6]: See [`EncodeToString`](https://pkg.go.dev/encoding/base64#Encoding.EncodeToString) in the Go documentation | ||||
| [^7]: See [`write` in "Writing Files"](/docs/api/write-options) | ||||
| [^8]: See ["Supported Output Formats" type in "Writing Files"](/docs/api/write-options#supported-output-formats) | ||||
| [^9]: See ["HTML Table Input" in "Utilities"](/docs/api/utilities/html#create-new-sheet) | ||||
| [^10]: See [`write` in "Writing Files"](/docs/api/write-options) | ||||
| [^11]: See [`SaveFileDialog`](https://wails.io/docs/reference/runtime/dialog#savefiledialog) in the Wails documentation. | ||||
| [^12]: See [`DecodeString`](https://pkg.go.dev/encoding/base64#Encoding.DecodeString) in the Go documentation | ||||
| [^13]: See [`WriteFile`](https://pkg.go.dev/os#WriteFile) in the Go documentation | ||||
| [^14]: See ["Installation"](https://wails.io/docs/gettingstarted/installation) in the Wails documentation. | ||||
| @ -1,36 +1,66 @@ | ||||
| --- | ||||
| title: C + QuickJS | ||||
| sidebar_label: C + QuickJS | ||||
| description: Process structured data in C programs. Seamlessly integrate spreadsheets into your program by pairing QuickJS and SheetJS. Supercharge programs with modern data tools. | ||||
| pagination_prev: demos/bigdata/index | ||||
| pagination_next: solutions/input | ||||
| --- | ||||
| 
 | ||||
| # Data Processing with QuickJS | ||||
| 
 | ||||
| import current from '/version.js'; | ||||
| import CodeBlock from '@theme/CodeBlock'; | ||||
| 
 | ||||
| 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. | ||||
| [QuickJS](https://bellard.org/quickjs/) is an embeddable JS engine written in C. | ||||
| It has built-in support for reading and writing file data stored in memory. | ||||
| 
 | ||||
| The [Standalone scripts](/docs/getting-started/installation/standalone) can be | ||||
| parsed and evaluated in a QuickJS context. | ||||
| [SheetJS](https://sheetjs.com) is a JavaScript library for reading and writing | ||||
| data from spreadsheets. | ||||
| 
 | ||||
| This demo uses QuickJS and SheetJS to pull data from a spreadsheet and print CSV | ||||
| rows. We'll explore how to load SheetJS in a QuickJS context and process | ||||
| spreadsheets from C programs. | ||||
| 
 | ||||
| The ["Integration Example"](#integration-example) section includes a complete | ||||
| command-line tool for reading data from files. | ||||
| 
 | ||||
| ## Integration Details | ||||
| 
 | ||||
| _Initialize QuickJS_ | ||||
| :::note | ||||
| 
 | ||||
| Many QuickJS functions are not documented. The explanation was verified against | ||||
| the latest release (version `2021-03-27`, commit `2788d71`). | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| ### Initialize QuickJS | ||||
| 
 | ||||
| Most QuickJS API functions interact with a `JSContext` object[^1], which is | ||||
| normally created with `JS_NewRuntime` and `JS_NewContext`: | ||||
| 
 | ||||
| ```c | ||||
| #include "quickjs.h" | ||||
| 
 | ||||
| /* initialize context */ | ||||
| JSRuntime *rt = JS_NewRuntime(); | ||||
| JSContext *ctx = JS_NewContext(rt); | ||||
| ``` | ||||
| 
 | ||||
| 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 */ | ||||
| <details><summary><b>Cleanup</b> (click to show)</summary> | ||||
| 
 | ||||
| /* free after use */ | ||||
| Once finished, programs are expected to cleanup by using `JS_FreeValue` to free | ||||
| values, `JS_FreeContext` to free the context pointer, and `JS_FreeRuntime` to | ||||
| free the runtime: | ||||
| 
 | ||||
| ```c | ||||
| /* global is a JSValue */ | ||||
| JS_FreeValue(ctx, global); | ||||
| 
 | ||||
| /* cleanup */ | ||||
| @ -38,27 +68,23 @@ JS_FreeContext(ctx); | ||||
| JS_FreeRuntime(rt); | ||||
| ``` | ||||
| 
 | ||||
| :::warning | ||||
| The [Integration Example](#integration-example) frees JS values after use. | ||||
| 
 | ||||
| All values must be freed with `JS_FreeValue` before calling `JS_FreeContext`! | ||||
| </details> | ||||
| 
 | ||||
| `JS_IsException` should be used for validation. | ||||
| ### Load SheetJS Scripts | ||||
| 
 | ||||
| Cleanup and validation code is omitted from the discussion.  The integration | ||||
| example shows structured validation and controlled memory usage. | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| _Load SheetJS Scripts_ | ||||
| [SheetJS Standalone scripts](/docs/getting-started/installation/standalone) can | ||||
| be loaded and executed in QuickJS. | ||||
| 
 | ||||
| The main library can be loaded by reading the script from the file system and | ||||
| evaluating in the QuickJS context: | ||||
| evaluating in the QuickJS context using `JS_Eval`: | ||||
| 
 | ||||
| ```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); } | ||||
|   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); | ||||
| @ -66,22 +92,37 @@ static char *read_file(const char *filename, size_t *sz) { | ||||
| } | ||||
| 
 | ||||
| // ... | ||||
|   /* load library */ | ||||
|   { | ||||
|     /* Read `xlsx.full.min.js` from the filesystem */ | ||||
|     size_t len; char *buf = read_file("xlsx.full.min.js", &len); | ||||
|     /* evaluate from the QuickJS context */ | ||||
|     JS_Eval(ctx, buf, len, "<input>", 0); | ||||
|     /* Free the file buffer */ | ||||
|     free(buf); | ||||
|   } | ||||
| ``` | ||||
| 
 | ||||
| To confirm the library is loaded, `XLSX.version` can be inspected: | ||||
| If the library is loaded, `XLSX.version` will be a string. This string can be | ||||
| pulled into the main C program. | ||||
| 
 | ||||
| 1) Get the `XLSX` property of the global object using `JS_GetPropertyStr`: | ||||
| 
 | ||||
| ```c | ||||
| /* obtain reference to the XLSX object */ | ||||
| JSValue XLSX = JS_GetPropertyStr(ctx, global, "XLSX"); | ||||
| ``` | ||||
| 
 | ||||
| /* print version */ | ||||
| 2) Get the `version` property of the `XLSX` object using `JS_GetPropertyStr`: | ||||
| 
 | ||||
| ```c | ||||
| /* obtain reference to `XLSX.version` */ | ||||
| JSValue version = JS_GetPropertyStr(ctx, XLSX, "version"); | ||||
| ``` | ||||
| 
 | ||||
| 3) Pull the string into C code with `JS_ToCStringLen`: | ||||
| 
 | ||||
| ```c | ||||
| /* pull the version string into C */ | ||||
| size_t vlen; const char *vers = JS_ToCStringLen(ctx, &vlen, version); | ||||
| printf("Version: %s\n", vers); | ||||
| ``` | ||||
| @ -97,16 +138,119 @@ 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 */ | ||||
| The `ArrayBuffer` will be parsed with the SheetJS `read` method[^2]. The CSV row | ||||
| data will be generated with `sheet_to_csv`[^3]. | ||||
| 
 | ||||
| #### Parse the ArrayBuffer | ||||
| 
 | ||||
| :::note pass | ||||
| 
 | ||||
| The goal is to run the equivalent of the following JavaScript code: | ||||
| 
 | ||||
| ```js | ||||
| /* `ab` is the `ArrayBuffer` from the previous step */ | ||||
| var wb = XLSX.read(ab); | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 1) Get the `XLSX` property of the global object and the `read` property of `XLSX`: | ||||
| 
 | ||||
| ```c | ||||
| /* obtain reference to XLSX.read */ | ||||
| JSValue XLSX = JS_GetPropertyStr(ctx, global, "XLSX"); | ||||
| 
 | ||||
| /* call XLSX.read(ab) */ | ||||
| JSValue XLSX_read = JS_GetPropertyStr(ctx, XLSX, "read"); | ||||
| ``` | ||||
| 
 | ||||
| 2) Create an array of arguments to pass to the function. In this case, the | ||||
| `read` function will be called with one argument (`ArrayBuffer` data): | ||||
| 
 | ||||
| ```c | ||||
| /* prepare arguments */ | ||||
| JSValue args[] = { ab }; | ||||
| ``` | ||||
| 
 | ||||
| 3) Use `JS_Call` to call the function with the arguments: | ||||
| 
 | ||||
| ```c | ||||
| /* call XLSX.read(ab) */ | ||||
| JSValue wb = JS_Call(ctx, XLSX_read, XLSX, 1, args); | ||||
| ``` | ||||
| 
 | ||||
| #### Get First Worksheet | ||||
| 
 | ||||
| :::note pass | ||||
| 
 | ||||
| The goal is to get the first worksheet. In JavaScript, the `SheetNames` property | ||||
| of the workbook is an array of strings and the `Sheets` property holds worksheet | ||||
| objects[^4]. The desired action looks like: | ||||
| 
 | ||||
| ```js | ||||
| /* `wb` is the workbook from the previous step */ | ||||
| var wsname = wb.SheetNames[0]; | ||||
| var ws = wb.Sheets[wsname]; | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 4) Pull `wb.SheetNames[0]` into a C string using `JS_GetPropertyStr`: | ||||
| 
 | ||||
| ```c | ||||
| /* get `wb.SheetNames[0]` */ | ||||
| JSValue SheetNames = JS_GetPropertyStr(ctx, wb, "SheetNames"); | ||||
| JSValue Sheet1 = JS_GetPropertyStr(ctx, SheetNames, "0"); | ||||
| 
 | ||||
| /* pull first sheet name into C code */ | ||||
| size_t wslen; const char *wsname = JS_ToCStringLen(ctx, &wslen, Sheet1); | ||||
| ``` | ||||
| 
 | ||||
| 5) Get the worksheet object: | ||||
| 
 | ||||
| ```c | ||||
| /* get wb.Sheets[wsname] */ | ||||
| JSValue Sheets = JS_GetPropertyStr(ctx, wb, "Sheets"); | ||||
| JSValue ws = JS_GetPropertyStr(ctx, Sheets, wsname); | ||||
| ``` | ||||
| 
 | ||||
| #### Convert to CSV | ||||
| 
 | ||||
| :::note pass | ||||
| 
 | ||||
| The goal is to call `sheet_to_csv`[^5] and pull the result into C code: | ||||
| 
 | ||||
| ```js | ||||
| /* `ws` is the worksheet from the previous step */ | ||||
| var csv = XLSX.utils.sheet_to_csv(ws); | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 6) Create a references to `XLSX.utils` and `XLSX.utils.sheet_to_csv`: | ||||
| 
 | ||||
| ```c | ||||
| /* obtain reference to XLSX.utils.sheet_to_csv */ | ||||
| JSValue utils = JS_GetPropertyStr(ctx, XLSX, "utils"); | ||||
| JSValue sheet_to_csv = JS_GetPropertyStr(ctx, utils, "sheet_to_csv"); | ||||
| ``` | ||||
| 
 | ||||
| 7) Create arguments array: | ||||
| 
 | ||||
| ```c | ||||
| /* prepare arguments */ | ||||
| JSValue args[] = { ws }; | ||||
| ``` | ||||
| 
 | ||||
| 8) Use `JS_Call` to call the function and use `JS_ToCStringLen` to pull the CSV: | ||||
| 
 | ||||
| ```c | ||||
| JSValue csv = JS_Call(ctx, sheet_to_csv, utils, 1, args); | ||||
| size_t csvlen; const char *csvstr = JS_ToCStringLen(ctx, &csvlen, csv); | ||||
| ``` | ||||
| 
 | ||||
| At this point, `csvstr` is a C string that can be printed to standard output. | ||||
| 
 | ||||
| ## Complete Example | ||||
| 
 | ||||
| The "Integration Example" covers a traditional integration in a C application, | ||||
| @ -124,6 +268,8 @@ This demo was tested in the following deployments: | ||||
| | `darwin-arm` | `2788d71`  | 2023-06-05 | | ||||
| | `linux-x64`  | `2788d71`  | 2023-06-02 | | ||||
| 
 | ||||
| Git commit `2788d71` corresponds to the latest release (`2021-03-27`) | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| 0) Build `libquickjs.a`: | ||||
| @ -171,7 +317,7 @@ curl -LO https://sheetjs.com/pres.numbers`} | ||||
| 
 | ||||
| 5) Run the test program: | ||||
| 
 | ||||
| ``` | ||||
| ```bash | ||||
| ./sheetjs.quick pres.numbers | ||||
| ``` | ||||
| 
 | ||||
| @ -215,3 +361,9 @@ quickjs SheetJSQuick.js | ||||
| 
 | ||||
| If successful, the script will generate `SheetJSQuick.xlsx`. | ||||
| 
 | ||||
| 
 | ||||
| [^1]: See ["Runtime and Contexts"](https://bellard.org/quickjs/quickjs.html#Runtime-and-contexts) in the QuickJS documentation | ||||
| [^2]: See [`read` in "Reading Files"](/docs/api/parse-options) | ||||
| [^3]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output) | ||||
| [^4]: See ["Workbook Object" in "SheetJS Data Model"](/docs/csf/book) | ||||
| [^5]: See [`sheet_to_csv` in "CSV and Text"](/docs/api/utilities/csv#delimiter-separated-output) | ||||
|  | ||||
| @ -31,7 +31,22 @@ std::unique_ptr<facebook::jsi::Runtime> rt(facebook::hermes::makeHermesRuntime() | ||||
| ``` | ||||
| 
 | ||||
| Hermes does not expose a `console` or `global` variable, but those can be | ||||
| synthesized from JS code in the runtime: | ||||
| synthesized from JS code in the runtime. | ||||
| 
 | ||||
| :::note pass | ||||
| 
 | ||||
| The JavaScript code is shown below: | ||||
| 
 | ||||
| ```js | ||||
| /* create global object */ | ||||
| var global = (function(){ return this; }).call(null); | ||||
| /* create a fake `console` from the hermes `print` builtin */ | ||||
| var console = { log: function(x) { print(x); } }; | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| The code can be stored in a C string and evaluated after creating a runtime: | ||||
| 
 | ||||
| ```cpp | ||||
| auto src = std::make_shared<facebook::jsi::StringBuffer>( | ||||
| @ -96,7 +111,7 @@ Hermes supports `ArrayBuffer` but has no simple helper to read raw memory. | ||||
| Libraries are expected to implement `MutableBuffer`: | ||||
| 
 | ||||
| ```cpp | ||||
| /* ArrayBuffer constructor expects MutableBuffer*/ | ||||
| /* ArrayBuffer constructor expects MutableBuffer */ | ||||
| class CMutableBuffer : public facebook::jsi::MutableBuffer { | ||||
|   public: | ||||
|     CMutableBuffer(uint8_t *data, size_t size) : buf(data), sz(size) {} | ||||
| @ -117,8 +132,10 @@ class CMutableBuffer : public facebook::jsi::MutableBuffer { | ||||
| It is strongly recommended to create a stub function to perform the entire | ||||
| workflow in JS code and pass the final result back to C++. | ||||
| 
 | ||||
| > _JS Stub function_ | ||||
| > | ||||
| :::note pass | ||||
| 
 | ||||
| The stub function will be passed an `ArrayBuffer` object: | ||||
| 
 | ||||
| ```js | ||||
| function(buf) { | ||||
|   /* `buf` will be an ArrayBuffer */ | ||||
| @ -127,6 +144,8 @@ function(buf) { | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| _C++ integration code_ | ||||
| 
 | ||||
| ```cpp | ||||
|  | ||||
| @ -3,19 +3,102 @@ sidebar_position: 1 | ||||
| title: Addresses and Ranges | ||||
| --- | ||||
| 
 | ||||
| export const g = {style: {backgroundColor:"green"}}; | ||||
| 
 | ||||
| Each cell in a worksheet has a unique address which specifies the row and the | ||||
| column that include the cell. | ||||
| 
 | ||||
| ## Basic Concepts | ||||
| 
 | ||||
| ### Rows | ||||
| 
 | ||||
| Spreadsheet applications typically display ordinal row numbers, where `1` is the | ||||
| first row, `2` is the second row, etc. The numbering starts at `1`. | ||||
| 
 | ||||
| SheetJS follows JavaScript counting conventions, where `0` is the first row, `1` | ||||
| is the second row, etc. The numbering starts at `0`. | ||||
| 
 | ||||
| The following table lists some example row labels: | ||||
| 
 | ||||
| | Ordinal   | Row Label |   SheetJS | | ||||
| |:----------|----------:|----------:| | ||||
| | First     |       `1` |       `0` | | ||||
| | Second    |       `2` |       `1` | | ||||
| | 26th      |      `26` |      `25` | | ||||
| | 420th     |     `420` |     `419` | | ||||
| | 7262nd    |    `7262` |    `7261` | | ||||
| | 1048576th | `1048576` | `1048575` | | ||||
| 
 | ||||
| ### Columns | ||||
| 
 | ||||
| Spreadsheet applications typically use letters to represent columns. | ||||
| 
 | ||||
| The first column is `A`, the second column is `B`, and the 26th column is `Z`. | ||||
| After `Z`, the next column is `AA` and counting continues through `AZ`.  After | ||||
| `AZ`, the count continues with `BA`. After `ZZ`, the count continues with `AAA`. | ||||
| 
 | ||||
| Some sample values, along with SheetJS column indices, are listed below: | ||||
| 
 | ||||
| | Ordinal | Column Label | SheetJS | | ||||
| |:--------|:-------------|--------:| | ||||
| | First   | `A`          |     `0` | | ||||
| | Second  | `B`          |     `1` | | ||||
| | 26th    | `Z`          |    `25` | | ||||
| | 27th    | `AA`         |    `26` | | ||||
| | 420th   | `PD`         |   `419` | | ||||
| | 702nd   | `ZZ`         |   `701` | | ||||
| | 703rd   | `AAA`        |   `702` | | ||||
| | 7262nd  | `JSH`        |  `7261` | | ||||
| | 16384th | `XFD`        | `16383` | | ||||
| 
 | ||||
| ## Cell Addresses | ||||
| 
 | ||||
| ### A1-Style | ||||
| 
 | ||||
| A1-Style is the default address style in Lotus 1-2-3 and Excel. | ||||
| 
 | ||||
| A cell address is the concatenation of column label and row label. | ||||
| 
 | ||||
| For example, the cell in the third column and fourth row is `C4`, concatenating | ||||
| the third column label (`C`) and the fourth row label (`4`) | ||||
| 
 | ||||
| ### SheetJS Cell Address | ||||
| 
 | ||||
| Cell address objects are stored as `{c:C, r:R}` where `C` and `R` are 0-indexed | ||||
| column and row numbers, respectively.  For example, the cell address `B5` is | ||||
| represented by the object `{c:1, r:4}`. | ||||
| 
 | ||||
| ## Cell Ranges | ||||
| 
 | ||||
| ### A1-Style | ||||
| 
 | ||||
| A cell range is represented as the top-left cell of the range, followed by `:`, | ||||
| followed by the bottom-right cell of the range. For example, the range `"C2:D4"` | ||||
| includes the 6 green cells in the following table: | ||||
| 
 | ||||
| <table><tbody> | ||||
|   <tr><th> </th><th>A</th><th>B</th><th>C</th><th>D</th><th>E</th></tr> | ||||
|   <tr><th>1</th><td> </td><td> </td><td> </td><td> </td><td> </td></tr> | ||||
|   <tr><th>2</th><td> </td><td> </td><td {...g}></td><td {...g}></td><td> </td></tr> | ||||
|   <tr><th>3</th><td> </td><td> </td><td {...g}></td><td {...g}></td><td> </td></tr> | ||||
|   <tr><th>4</th><td> </td><td> </td><td {...g}></td><td {...g}></td><td> </td></tr> | ||||
|   <tr><th>5</th><td> </td><td> </td><td> </td><td> </td><td> </td></tr> | ||||
| </tbody></table> | ||||
| 
 | ||||
| A column range is represented by the left-most column, followed by `:`, followed | ||||
| by the right-most column.  For example, the range `C:D` represents the third and | ||||
| fourth columns. | ||||
| 
 | ||||
| A row range is represented by the top-most row, followed by `:`, followed by the | ||||
| bottom-most column.  For example, `2:4` represents the second/third/fourth rows. | ||||
| 
 | ||||
| ### SheetJS Range | ||||
| 
 | ||||
| Cell range objects are stored as `{s:S, e:E}` where `S` is the first cell and | ||||
| `E` is the last cell in the range.  The ranges are inclusive.  For example, the | ||||
| range `A3:B7` is represented by the object `{s:{c:0, r:2}, e:{c:1, r:6}}`. | ||||
| 
 | ||||
| ### Column and Row Ranges | ||||
| #### Column and Row Ranges | ||||
| 
 | ||||
| A column range (spanning every row) is represented with the starting row `0` and | ||||
| the ending row `1048575`: | ||||
| @ -33,54 +116,9 @@ the ending col `16383`: | ||||
| { s: { c: 0, r: 1 }, e: { c: 16383, r: 2 } } // 2:3 | ||||
| ``` | ||||
| 
 | ||||
| # Common Spreadsheet Address Styles | ||||
| ## Utilities | ||||
| 
 | ||||
| ## A1-Style | ||||
| 
 | ||||
| A1-Style is the default address style in Lotus 1-2-3 and Excel. | ||||
| 
 | ||||
| Columns are specified with letters, counting from `A` to `Z`, then `AA` to `ZZ`, | ||||
| then `AAA`.  Some sample values, along with SheetJS column indices, are listed: | ||||
| 
 | ||||
| | Ordinal | `A1`    | SheetJS | | ||||
| |:--------|:--------|--------:| | ||||
| | First   | `A`     |     `0` | | ||||
| | Second  | `B`     |     `1` | | ||||
| | 26th    | `Z`     |    `25` | | ||||
| | 27th    | `AA`    |    `26` | | ||||
| | 702nd   | `ZZ`    |   `701` | | ||||
| | 703rd   | `AAA`   |   `702` | | ||||
| | 16384th | `XFD`   | `16383` | | ||||
| 
 | ||||
| Rows are specified with numbers, starting from `1` for the first row.  SheetJS | ||||
| APIs that take row indices start from `0` (ECMAScript convention). | ||||
| 
 | ||||
| A cell address is the concatenation of column text and row number.  For example, | ||||
| the cell in the third column and fourth row is "C4". | ||||
| 
 | ||||
| A cell range is represented as the top-left cell of the range, followed by `:`, | ||||
| followed by the bottom-right cell of the range. For example, the range `"C2:D4"` | ||||
| includes 6 cells marked with ▒ in the table below: | ||||
| 
 | ||||
| <table><tbody> | ||||
|   <tr><th> </th><th>A</th><th>B</th><th>C</th><th>D</th><th>E</th></tr> | ||||
|   <tr><th>1</th><td> </td><td> </td><td> </td><td> </td><td> </td></tr> | ||||
|   <tr><th>2</th><td> </td><td> </td><td>▒</td><td>▒</td><td> </td></tr> | ||||
|   <tr><th>3</th><td> </td><td> </td><td>▒</td><td>▒</td><td> </td></tr> | ||||
|   <tr><th>4</th><td> </td><td> </td><td>▒</td><td>▒</td><td> </td></tr> | ||||
|   <tr><th>5</th><td> </td><td> </td><td> </td><td> </td><td> </td></tr> | ||||
| </tbody></table> | ||||
| 
 | ||||
| A column range is represented by the left-most column, followed by `:`, followed | ||||
| by the right-most column.  For example, the range `C:D` represents the third and | ||||
| fourth columns. | ||||
| 
 | ||||
| A row range is represented by the top-most row, followed by `:`, followed by the | ||||
| bottom-most column.  For example, `2:4` represents the second/third/fourth rows. | ||||
| 
 | ||||
| ### Utilities | ||||
| 
 | ||||
| #### Column Names | ||||
| ### Column Names | ||||
| 
 | ||||
| _Get the SheetJS index from an A1-Style column_ | ||||
| 
 | ||||
| @ -98,7 +136,7 @@ var col_name = XLSX.utils.encode_col(3); | ||||
| 
 | ||||
| The argument is expected to be a SheetJS column (non-negative integer). | ||||
| 
 | ||||
| #### Row Names | ||||
| ### Row Names | ||||
| 
 | ||||
| _Get the SheetJS index from an A1-Style row_ | ||||
| 
 | ||||
| @ -116,7 +154,7 @@ var row_name = XLSX.utils.encode_row(3); | ||||
| 
 | ||||
| The argument is expected to be a SheetJS column (non-negative integer). | ||||
| 
 | ||||
| #### Cell Addresses | ||||
| ### Cell Addresses | ||||
| 
 | ||||
| _Generate a SheetJS cell address from an A1-Style address string_ | ||||
| 
 | ||||
| @ -134,7 +172,7 @@ var a1_addr = XLSX.utils.encode_cell({r:1, c:0}); | ||||
| 
 | ||||
| The argument is expected to be a SheetJS cell address | ||||
| 
 | ||||
| #### Cell Ranges | ||||
| ### Cell Ranges | ||||
| 
 | ||||
| _Generate a SheetJS cell range from an A1-Style range string_ | ||||
| 
 | ||||
|  | ||||
| @ -104,6 +104,7 @@ Read functions attempt to populate all three properties.  Write functions will | ||||
| try to cycle specified values to the desired type.  In order to avoid potential | ||||
| conflicts, manipulation should delete the other properties first.  For example, | ||||
| when changing the pixel width, delete the `wch` and `width` properties. | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| <details> | ||||
| @ -222,10 +223,6 @@ function Visibility(props) { | ||||
| 
 | ||||
|     </tr>))}</tbody></table>); | ||||
| } | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
|  | ||||
| @ -7,9 +7,12 @@ title: Common Spreadsheet Format | ||||
| import DocCardList from '@theme/DocCardList'; | ||||
| import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; | ||||
| 
 | ||||
| The "Common Spreadsheet Format" is the object model used by SheetJS. This | ||||
| section covers the JS representation of workbooks, worksheets, cells, ranges, | ||||
| addresses and other features. | ||||
| The "Common Spreadsheet Format" is the object model used by SheetJS. The library | ||||
| [includes a number of API functions](/docs/api) for common operations, but some | ||||
| features are only accessible by inspecting and modifying the objects directly. | ||||
| 
 | ||||
| This section covers the JS representation of workbooks, worksheets, cells, | ||||
| ranges, addresses and other features. | ||||
| 
 | ||||
| ### Contents | ||||
| 
 | ||||
|  | ||||
| @ -4,15 +4,26 @@ sidebar_position: 5 | ||||
| title: API Reference | ||||
| --- | ||||
| 
 | ||||
| ## Interface Summary | ||||
| import current from '/version.js'; | ||||
| 
 | ||||
| `XLSX` is the exposed variable in the browser and the exported node variable | ||||
| This section lists the functions defined in the library. | ||||
| 
 | ||||
| `XLSX.version` is the version of the library (added by the build script). | ||||
| Using the ["Standalone" scripts](/docs/getting-started/installation/standalone), | ||||
| `XLSX` is added to the `window` or other `global` object. | ||||
| 
 | ||||
| `XLSX.SSF` is an embedded version of the [format library](https://git.sheetjs.com/sheetjs/sheetjs/src/branch/master/packages/ssf). | ||||
| Using the ["NodeJS" module](/docs/getting-started/installation/nodejs), the | ||||
| `XLSX` variable refers to the CommonJS export: | ||||
| 
 | ||||
| `XLSX.CFB` is an embedded version of the [container library](https://git.sheetjs.com/sheetjs/js-cfb). | ||||
| ```js | ||||
| var XLSX = require("xlsx"); | ||||
| ``` | ||||
| 
 | ||||
| Using [a framework](/docs/getting-started/installation/frameworks), the `XLSX` | ||||
| variable refers to the glob import: | ||||
| 
 | ||||
| ```js | ||||
| import * as XLSX from "xlsx"; | ||||
| ``` | ||||
| 
 | ||||
| ## Parsing functions | ||||
| 
 | ||||
| @ -127,4 +138,20 @@ for different languages in XLS or text parsing. | ||||
| provides NodeJS ESM support for `XLSX.readFile` and `XLSX.writeFile`. | ||||
| 
 | ||||
| `XLSX.utils.set_readable` supplies a NodeJS `stream.Readable` constructor.  This | ||||
| provides NodeJS ESM support for the streaming operations. | ||||
| provides NodeJS ESM support for the streaming operations. | ||||
| 
 | ||||
| ESM helper functions are described in the ["NodeJS" Installation section](/docs/getting-started/installation/nodejs) | ||||
| 
 | ||||
| ## Miscellaneous | ||||
| 
 | ||||
| `XLSX.version` is the version of the library. | ||||
| 
 | ||||
| :::note pass | ||||
| 
 | ||||
| <p>The current version is <code>{current}</code></p> | ||||
| 
 | ||||
| ::: | ||||
| 
 | ||||
| `XLSX.SSF` is an embedded version of the [format library](https://git.sheetjs.com/sheetjs/sheetjs/src/branch/master/packages/ssf). | ||||
| 
 | ||||
| `XLSX.CFB` is an embedded version of the [container library](https://git.sheetjs.com/sheetjs/js-cfb). | ||||
|  | ||||
| @ -34,6 +34,7 @@ const config = { | ||||
|       ({ | ||||
|         docs: { | ||||
|           sidebarPath: require.resolve('./sidebars.js'), | ||||
|           showLastUpdateTime: true, | ||||
|           editUrl: 'https://git.sheetjs.com/sheetjs/docs.sheetjs.com/src/branch/master/docz', | ||||
|         }, | ||||
|         //blog: {
 | ||||
|  | ||||
							
								
								
									
										180
									
								
								docz/src/theme/Admonition/index.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										180
									
								
								docz/src/theme/Admonition/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,180 @@ | ||||
| import React from 'react'; | ||||
| import clsx from 'clsx'; | ||||
| import {ThemeClassNames} from '@docusaurus/theme-common'; | ||||
| import Translate from '@docusaurus/Translate'; | ||||
| import styles from './styles.module.css'; | ||||
| function NoteIcon() { | ||||
|   return ( | ||||
|     <svg viewBox="0 0 14 16"> | ||||
|       <path | ||||
|         fillRule="evenodd" | ||||
|         d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z" | ||||
|       /> | ||||
|     </svg> | ||||
|   ); | ||||
| } | ||||
| function TipIcon() { | ||||
|   return ( | ||||
|     <svg viewBox="0 0 12 16"> | ||||
|       <path | ||||
|         fillRule="evenodd" | ||||
|         d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z" | ||||
|       /> | ||||
|     </svg> | ||||
|   ); | ||||
| } | ||||
| function DangerIcon() { | ||||
|   return ( | ||||
|     <svg viewBox="0 0 12 16"> | ||||
|       <path | ||||
|         fillRule="evenodd" | ||||
|         d="M5.05.31c.81 2.17.41 3.38-.52 4.31C3.55 5.67 1.98 6.45.9 7.98c-1.45 2.05-1.7 6.53 3.53 7.7-2.2-1.16-2.67-4.52-.3-6.61-.61 2.03.53 3.33 1.94 2.86 1.39-.47 2.3.53 2.27 1.67-.02.78-.31 1.44-1.13 1.81 3.42-.59 4.78-3.42 4.78-5.56 0-2.84-2.53-3.22-1.25-5.61-1.52.13-2.03 1.13-1.89 2.75.09 1.08-1.02 1.8-1.86 1.33-.67-.41-.66-1.19-.06-1.78C8.18 5.31 8.68 2.45 5.05.32L5.03.3l.02.01z" | ||||
|       /> | ||||
|     </svg> | ||||
|   ); | ||||
| } | ||||
| function InfoIcon() { | ||||
|   return ( | ||||
|     <svg viewBox="0 0 14 16"> | ||||
|       <path | ||||
|         fillRule="evenodd" | ||||
|         d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z" | ||||
|       /> | ||||
|     </svg> | ||||
|   ); | ||||
| } | ||||
| function CautionIcon() { | ||||
|   return ( | ||||
|     <svg viewBox="0 0 16 16"> | ||||
|       <path | ||||
|         fillRule="evenodd" | ||||
|         d="M8.893 1.5c-.183-.31-.52-.5-.887-.5s-.703.19-.886.5L.138 13.499a.98.98 0 0 0 0 1.001c.193.31.53.501.886.501h13.964c.367 0 .704-.19.877-.5a1.03 1.03 0 0 0 .01-1.002L8.893 1.5zm.133 11.497H6.987v-2.003h2.039v2.003zm0-3.004H6.987V5.987h2.039v4.006z" | ||||
|       /> | ||||
|     </svg> | ||||
|   ); | ||||
| } | ||||
| // eslint-disable-next-line @typescript-eslint/consistent-indexed-object-style
 | ||||
| const AdmonitionConfigs = { | ||||
|   note: { | ||||
|     infimaClassName: 'secondary', | ||||
|     iconComponent: NoteIcon, | ||||
|     label: ( | ||||
|       <Translate | ||||
|         id="theme.admonition.note" | ||||
|         description="The default label used for the Note admonition (:::note)"> | ||||
|         note | ||||
|       </Translate> | ||||
|     ), | ||||
|   }, | ||||
|   tip: { | ||||
|     infimaClassName: 'success', | ||||
|     iconComponent: TipIcon, | ||||
|     label: ( | ||||
|       <Translate | ||||
|         id="theme.admonition.tip" | ||||
|         description="The default label used for the Tip admonition (:::tip)"> | ||||
|         tip | ||||
|       </Translate> | ||||
|     ), | ||||
|   }, | ||||
|   danger: { | ||||
|     infimaClassName: 'danger', | ||||
|     iconComponent: DangerIcon, | ||||
|     label: ( | ||||
|       <Translate | ||||
|         id="theme.admonition.danger" | ||||
|         description="The default label used for the Danger admonition (:::danger)"> | ||||
|         danger | ||||
|       </Translate> | ||||
|     ), | ||||
|   }, | ||||
|   info: { | ||||
|     infimaClassName: 'info', | ||||
|     iconComponent: InfoIcon, | ||||
|     label: ( | ||||
|       <Translate | ||||
|         id="theme.admonition.info" | ||||
|         description="The default label used for the Info admonition (:::info)"> | ||||
|         info | ||||
|       </Translate> | ||||
|     ), | ||||
|   }, | ||||
|   caution: { | ||||
|     infimaClassName: 'warning', | ||||
|     iconComponent: CautionIcon, | ||||
|     label: ( | ||||
|       <Translate | ||||
|         id="theme.admonition.caution" | ||||
|         description="The default label used for the Caution admonition (:::caution)"> | ||||
|         caution | ||||
|       </Translate> | ||||
|     ), | ||||
|   }, | ||||
| }; | ||||
| // Legacy aliases, undocumented but kept for retro-compatibility
 | ||||
| const aliases = { | ||||
|   secondary: 'note', | ||||
|   important: 'info', | ||||
|   success: 'tip', | ||||
|   warning: 'danger', | ||||
| }; | ||||
| function getAdmonitionConfig(unsafeType) { | ||||
|   const type = aliases[unsafeType] ?? unsafeType; | ||||
|   const config = AdmonitionConfigs[type]; | ||||
|   if (config) { | ||||
|     return config; | ||||
|   } | ||||
|   console.warn( | ||||
|     `No admonition config found for admonition type "${type}". Using Info as fallback.`, | ||||
|   ); | ||||
|   return AdmonitionConfigs.info; | ||||
| } | ||||
| // Workaround because it's difficult in MDX v1 to provide a MDX title as props
 | ||||
| // See https://github.com/facebook/docusaurus/pull/7152#issuecomment-1145779682
 | ||||
| function extractMDXAdmonitionTitle(children) { | ||||
|   const items = React.Children.toArray(children); | ||||
|   const mdxAdmonitionTitle = items.find( | ||||
|     (item) => | ||||
|       React.isValidElement(item) && | ||||
|       item.props?.mdxType === 'mdxAdmonitionTitle', | ||||
|   ); | ||||
|   const rest = <>{items.filter((item) => item !== mdxAdmonitionTitle)}</>; | ||||
|   return { | ||||
|     mdxAdmonitionTitle, | ||||
|     rest, | ||||
|   }; | ||||
| } | ||||
| function processAdmonitionProps(props) { | ||||
|   const {mdxAdmonitionTitle, rest} = extractMDXAdmonitionTitle(props.children); | ||||
|   return { | ||||
|     ...props, | ||||
|     title: props.title ?? mdxAdmonitionTitle, | ||||
|     children: rest, | ||||
|   }; | ||||
| } | ||||
| export default function Admonition(props) { | ||||
|   const {children, type, title, icon: iconProp} = processAdmonitionProps(props); | ||||
|   const typeConfig = getAdmonitionConfig(type); | ||||
|   const titleLabel = title ?? typeConfig.label; | ||||
|   const {iconComponent: IconComponent} = typeConfig; | ||||
|   const icon = iconProp ?? <IconComponent />; | ||||
|   return ( | ||||
|     <div | ||||
|       className={clsx( | ||||
|         ThemeClassNames.common.admonition, | ||||
|         ThemeClassNames.common.admonitionType(props.type), | ||||
|         'alert', | ||||
|         `alert--${typeConfig.infimaClassName}`, | ||||
|         styles.admonition, | ||||
|       )}> | ||||
|       {titleLabel == "pass" ? void 0 : ( | ||||
|         <div className={styles.admonitionHeading}> | ||||
|         <span className={styles.admonitionIcon}>{icon}</span> | ||||
|         {titleLabel} | ||||
|       </div> | ||||
|       )} | ||||
|       <div className={styles.admonitionContent}>{children}</div> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
| /* See docusaurus issue 8568 -- this was swizzled against 2.4.1 */ | ||||
							
								
								
									
										31
									
								
								docz/src/theme/Admonition/styles.module.css
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										31
									
								
								docz/src/theme/Admonition/styles.module.css
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| .admonition { | ||||
|   margin-bottom: 1em; | ||||
| } | ||||
| 
 | ||||
| .admonitionHeading { | ||||
|   font: var(--ifm-heading-font-weight) var(--ifm-h5-font-size) / | ||||
|     var(--ifm-heading-line-height) var(--ifm-heading-font-family); | ||||
|   text-transform: uppercase; | ||||
|   margin-bottom: 0.3rem; | ||||
| } | ||||
| 
 | ||||
| .admonitionHeading code { | ||||
|   text-transform: none; | ||||
| } | ||||
| 
 | ||||
| .admonitionIcon { | ||||
|   display: inline-block; | ||||
|   vertical-align: middle; | ||||
|   margin-right: 0.4em; | ||||
| } | ||||
| 
 | ||||
| .admonitionIcon svg { | ||||
|   display: inline-block; | ||||
|   height: 1.6em; | ||||
|   width: 1.6em; | ||||
|   fill: var(--ifm-alert-foreground-color); | ||||
| } | ||||
| 
 | ||||
| .admonitionContent > :last-child { | ||||
|   margin-bottom: 0; | ||||
| } | ||||
							
								
								
									
										
											BIN
										
									
								
								docz/static/vitejs/table.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								docz/static/vitejs/table.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 26 KiB | 
		Loading…
	
		Reference in New Issue
	
	Block a user