diff --git a/.spelling b/.spelling
index a328cad..2a16e2d 100644
--- a/.spelling
+++ b/.spelling
@@ -153,6 +153,7 @@ Fastify
FileReader
GBK
GatsbyJS
+GitLab
Goja
HTML
HTML5
diff --git a/docz/docs/03-demos/25-gsheet.md b/docz/docs/03-demos/25-gsheet.md
index 9754356..0a746eb 100644
--- a/docz/docs/03-demos/25-gsheet.md
+++ b/docz/docs/03-demos/25-gsheet.md
@@ -8,8 +8,12 @@ import TabItem from '@theme/TabItem';
This demo uses [`node-google-spreadsheet`](https://theoephraim.github.io/node-google-spreadsheet)
to interact with Google Sheets v4 API.
-Code that does not directly relate to SheetJS APIs are tucked away. Click on
-the "click to show" blocks to see the code snippets.
+:::caution
+
+Google Sheets deprecates APIs quickly and there is no guarantee that the
+referenced API version will be available in the future.
+
+:::
## Initial Configuration
@@ -46,97 +50,10 @@ module.exports = async(ID) => {
-## Exporting Document Data to a File
+## Export Document Data
The goal is to create an XLSB export from a Google Sheet. Google Sheets does
-not natively support the XLSB format. SheetJS fills the gap. [The last subsection](#how-to-run-export-example) includes detailed instructions for running locally.
-
-### Connecting to the Document
-
-This uses the `common.js` helper from above:
-
-Code (click to show)
-
-```js
-/* Connect to Google Sheet */
-const ID = "";
-const doc = await require("./common")(ID);
-```
-
-
-
-### Creating a New Workbook
-
-`XLSX.utils.book_new()` creates an empty workbook with no worksheets:
-
-```js
-/* create a blank workbook */
-const wb = XLSX.utils.book_new();
-```
-
-### Looping across the Document
-
-
-`doc.sheetsByIndex` is an array of worksheets in the Google Sheet Document.
-
-Code (click to show)
-
-```js
-/* Loop across the Document sheets */
-for(let i = 0; i < doc.sheetsByIndex.length; ++i) {
- const sheet = doc.sheetsByIndex[i];
- /* Get the worksheet name */
- const name = sheet.title;
- /* ... */
-}
-```
-
-
-
-### Convert a Google Sheets sheet to a SheetJS Worksheet
-
-The idea is to extract the raw data from the Google Sheet headers and combine
-with the raw data rows to produce a large array of arrays.
-
-Code (click to show)
-
-```js
- /* get the header and data rows */
- await sheet.loadHeaderRow();
- const header = sheet.headerValues;
- const rows = await sheet.getRows();
-
- /* construct the array of arrays */
- const aoa = [header].concat(rows.map(r => r._rawData));
-```
-
-
-
-This can be converted to a SheetJS worksheet using `XLSX.utils.aoa_to_sheet`:
-
-
-```js
- /* generate a SheetJS Worksheet */
- const ws = XLSX.utils.aoa_to_sheet(aoa);
-```
-
-`XLSX.utils.book_append_sheet` will add the worksheet to the workbook:
-
-```js
- /* add to workbook */
- XLSX.utils.book_append_sheet(wb, ws, name);
-```
-
-### Generating an XLSB file
-
-`XLSX.writeFile` will write a file in the file system:
-
-```js
-/* write to SheetJS.xlsb */
-XLSX.writeFile(wb, "SheetJS.xlsb");
-```
-
-### How to Run Export Example
+not natively support the XLSB format. SheetJS fills the gap.
How to run locally (click to show)
@@ -225,151 +142,56 @@ const ID = "";
-## Updating a Document from a Local File
+### Convert a Single Sheet
-The goal is to refresh a Google Sheet based on a local file. The problem can
-be broken down into a few steps. [The last subsection](#how-to-run-update-example)
-includes detailed instructions for running locally.
-
-### Reading the Workbook File
-
-`XLSX.readFile` can read files from the file system. The following line reads
-`sheetjs.xlsx` from the current directory:
+The idea is to extract the raw data from the Google Sheet headers and combine
+with the raw data rows to produce a large array of arrays.
```js
-const XLSX = require("xlsx");
-const wb = XLSX.readFile("sheetjs.xlsx");
+async function wb_append_sheet(sheet, name, wb) {
+ /* get the header and data rows */
+ await sheet.loadHeaderRow();
+ const header = sheet.headerValues;
+ const rows = await sheet.getRows();
+
+ /* construct the array of arrays */
+ const aoa = [header].concat(rows.map(r => r._rawData));
+
+ /* generate a SheetJS Worksheet */
+ const ws = XLSX.utils.aoa_to_sheet(aoa);
+
+ /* add to workbook */
+ XLSX.utils.book_append_sheet(wb, ws, name);
+}
```
-### Connecting to the Document
+### Convert a Workbook
-This uses the `common.js` helper from above:
-
-Code (click to show)
+`doc.sheetsByIndex` is an array of worksheets in the Google Sheet Document. By
+looping across the sheets, the entire workbook can be written:
```js
-/* Connect to Google Sheet */
-const ID = "";
-const doc = await require("./common")(ID);
-```
+async function doc_to_wb(doc) {
+ /* Create a new workbook object */
+ const wb = XLSX.utils.book_new();
-
+ /* Loop across the Document sheets */
+ for(let i = 0; i < doc.sheetsByIndex.length; ++i) {
+ const sheet = doc.sheetsByIndex[i];
+ /* Get the worksheet name */
+ const name = sheet.title;
-### Clearing the Document
-
-Google Sheets does not allow users to delete every worksheet. The snippet
-deletes every worksheet after the first, then clears the first worksheet.
-
-Code (click to show)
-
-```js
-/* clear workbook */
-{
- /* delete all sheets after the first sheet */
- const old_sheets = doc.sheetsByIndex;
- for(let i = 1; i < old_sheets.length; ++i) {
- await old_sheets[i].delete();
+ /* Add sheet to workbook */
+ await add_sheet_to_wb(sheet, name, wb);
}
- /* clear first worksheet */
- old_sheets[0].clear();
+
+ return wb;
}
```
-
+## Update Document Data
-### Update First Worksheet
-
-In the SheetJS workbook object, worksheet names are stored in the `SheetNames`
-property. The first worksheet name is `wb.SheetNames[0]`:
-
-```js
-const name = wb.SheetNames[0];
-```
-
-The `Sheets` property is an object whose keys are sheet names and whose values
-are worksheet objects.
-
-```js
-const ws = wb.Sheets[name];
-```
-
-In the Google Sheet, `doc.sheetsByIndex[0]` is a reference to the first sheet:
-
-```js
-const sheet = doc.sheetsByIndex[0];
-```
-
-#### Update Sheet Name
-
-The worksheet name is assigned by using the `updateProperties` method. The
-desired sheet name is the name of the first worksheet from the file.
-
-```js
-/* update worksheet name */
-await sheet.updateProperties({title: name});
-```
-
-#### Update Worksheet Data
-
-`sheet.addRows` reads an Array of Arrays of values. `XLSX.utils.sheet_to_json`
-can generate this exact shape with the option `header: 1`. Unfortunately
-Google Sheets requires at least one "Header Row". This can be implemented by
-converting the entire worksheet to an Array of Arrays and setting the header
-row to the first row of the result:
-
-```js
-/* generate array of arrays from the first worksheet */
-const aoa = XLSX.utils.sheet_to_json(ws, {header: 1});
-
-/* set document header row to first row of the AOA */
-await sheet.setHeaderRow(aoa[0]);
-
-/* add the remaining rows */
-await sheet.addRows(aoa.slice(1));
-```
-
-### Add the Other Worksheets
-
-Each name in the SheetJS Workbook `SheetNames` array maps to a worksheet. The
-loop over the remaining worksheet names looks like
-
-```js
-for(let i = 1; i < wb.SheetNames.length; ++i) {
- /* wb.SheetNames[i] is the sheet name */
- const name = wb.SheetNames[i];
- /* wb.Sheets[name] is the worksheet object */
- const ws = wb.Sheets[name];
- /* ... */
-}
-```
-
-#### Appending a Worksheet to the Document
-
-`doc.addSheet` accepts a properties object that includes the worksheet name:
-
-```js
- const sheet = await doc.addSheet({title: name});
-```
-
-This creates a new worksheet, sets the tab name, and returns a reference to the
-created worksheet.
-
-#### Update Worksheet Data
-
-This is identical to the first worksheet code:
-
-```js
- /* generate array of arrays from the first worksheet */
- const aoa = XLSX.utils.sheet_to_json(ws, {header: 1});
-
- /* set document header row to first row of the AOA */
- await sheet.setHeaderRow(aoa[0]);
-
- /* add the remaining rows */
- await sheet.addRows(aoa.slice(1));
-```
-
-### How to Run Update Example
+The goal is to refresh a Google Sheet based on a local file.
How to run locally (click to show)
@@ -485,15 +307,132 @@ const ID = "";
-## Using the Raw File Exports
+### Clear the Document
+
+Google Sheets does not allow users to delete every worksheet. This function
+deletes every worksheet after the first, then clears the first worksheet:
+
+```js
+/* clear google sheets doc */
+async function doc_clear(doc) {
+ /* delete all sheets after the first sheet */
+ const old_sheets = doc.sheetsByIndex;
+ for(let i = 1; i < old_sheets.length; ++i) await old_sheets[i].delete();
+
+ /* clear first worksheet */
+ old_sheets[0].clear();
+}
+```
+
+### Update First Sheet
+
+There are two steps: "update worksheet name" and "update worksheet data":
+
+#### Update Sheet Name
+
+The worksheet name is assigned by using the `updateProperties` method. The
+desired sheet name is the name of the first worksheet from the file.
+
+```js
+async function doc_update_first_sheet_name(doc, wb) {
+ /* get first worksheet name */
+ const wsname = wb.SheetNames[0];
+
+ /* get first gsheet */
+ const sheet = doc.sheetsByIndex[0];
+
+ /* update worksheet name */
+ await sheet.updateProperties({title: wsname});
+}
+```
+
+#### Update Sheet Data
+
+`sheet.addRows` reads an Array of Arrays of values. `XLSX.utils.sheet_to_json`
+can generate this exact shape with the option `header: 1`. Unfortunately
+Google Sheets requires at least one "Header Row". This can be implemented by
+converting the entire worksheet to an Array of Arrays and setting the header
+row to the first row of the result:
+
+```js
+async function doc_update_first_sheet_data(doc, wb) {
+ /* get first worksheet */
+ const ws = wb.Sheets[wb.SheetNames[0]];
+ /* generate array of arrays from the first worksheet */
+ const aoa = XLSX.utils.sheet_to_json(ws, {header: 1});
+
+ /* get first gsheet */
+ const sheet = doc.sheetsByIndex[0];
+ /* set document header row to first row of the AOA */
+ await sheet.setHeaderRow(aoa[0]);
+
+ /* add the remaining rows */
+ await sheet.addRows(aoa.slice(1));
+}
+```
+
+### Append Remaining Worksheets
+
+Each name in the SheetJS Workbook `SheetNames` array maps to a worksheet. The
+list of names not including the first sheet is `wb.SheetNames.slice(1)`.
+
+There are two steps for each sheet: "create new sheet" and "load data".
+
+Due to JavaScript `async` idiosyncrasies, a plain `for` loop must be used:
+
+```js
+async function doc_append_remaining_sheets(doc, wb) {
+ const names = wb.SheetNames.slice(1);
+
+ /* loop across names */
+ for(let i = 0; i < names.length; ++i) {
+ /* wb.SheetNames[i] is the sheet name */
+ const name = wb.SheetNames[i];
+ /* wb.Sheets[name] is the worksheet object */
+ const ws = wb.Sheets[name];
+
+ /* create new google sheet */
+ const sheet = await doc_add_new_sheet(doc, name);
+ /* load sheet with data */
+ await sheet_load_from_ws(sheet, ws);
+ }
+}
+```
+
+#### Add a New Worksheet
+
+`doc.addSheet` accepts a properties object that includes the worksheet name:
+
+```js
+async function doc_add_new_sheet(doc, name) {
+ return await doc.addSheet({title: name});
+}
+```
+
+This creates a new worksheet, sets the tab name, and returns a reference to the
+created worksheet.
+
+#### Update Worksheet Data
+
+```js
+async function sheet_load_from_ws(sheet, ws) {
+ /* generate array of arrays from the first worksheet */
+ const aoa = XLSX.utils.sheet_to_json(ws, {header: 1});
+
+ /* set document header row to first row of the AOA */
+ await sheet.setHeaderRow(aoa[0]);
+
+ /* add the remaining rows */
+ await sheet.addRows(aoa.slice(1));
+}
+```
+
+## Raw File Exports
`node-google-spreadsheet` can download the XLSX or ODS export of the document.
The functions return NodeJS `Buffer` data that can be parsed using SheetJS.
-Sample Code (click to show)
-
-SheetJS can read data from XLSX files and ODS files. This example prints the
-worksheet names and CSV exports of each sheet.
+This example prints the worksheet names and CSV exports of each sheet.
@@ -501,27 +440,30 @@ worksheet names and CSV exports of each sheet.
```js
const XLSX = require("xlsx");
-/* Connect to Google Sheet */
-const ID = "";
-const doc = await require("./common")(ID);
+(async() => {
+ /* Connect to Google Sheet */
+ const ID = "";
+ const doc = await require("./common")(ID);
-/* Get XLSX export */
-const buf = await doc.downloadAsXLSX();
+ /* Get file export */
+ // highlight-next-line
+ const buf = await doc.downloadAsXLSX();
-/* Parse with SheetJS */
-const wb = XLSX.read(buf);
+ /* Parse with SheetJS */
+ const wb = XLSX.read(buf);
-/* Loop over the worksheet names */
-wb.SheetNames.forEach(name => {
- /* Print the name to the console */
- console.log(name);
+ /* Loop over the worksheet names */
+ wb.SheetNames.forEach(name => {
+ /* Print the name to the console */
+ console.log(name);
- /* Get the corresponding worksheet object */
- const sheet = wb.Sheets[name];
+ /* Get the corresponding worksheet object */
+ const sheet = wb.Sheets[name];
- /* Print a CSV export of the worksheet */
- console.log(XLSX.utils.sheet_to_csv(sheet));
-});
+ /* Print a CSV export of the worksheet */
+ console.log(XLSX.utils.sheet_to_csv(sheet));
+ });
+})();
```
@@ -531,30 +473,31 @@ wb.SheetNames.forEach(name => {
```js
const XLSX = require("xlsx");
-/* Connect to Google Sheet */
-const ID = "";
-const doc = await require("./common")(ID);
+(async() => {
+ /* Connect to Google Sheet */
+ const ID = "";
+ const doc = await require("./common")(ID);
-/* Get XLSX export */
-const buf = await doc.downloadAsODS();
+ /* Get file export */
+ // highlight-next-line
+ const buf = await doc.downloadAsODS();
-/* Parse with SheetJS */
-const wb = XLSX.read(buf);
+ /* Parse with SheetJS */
+ const wb = XLSX.read(buf);
-/* Loop over the worksheet names */
-wb.SheetNames.forEach(name => {
- /* Print the name to the console */
- console.log(name);
+ /* Loop over the worksheet names */
+ wb.SheetNames.forEach(name => {
+ /* Print the name to the console */
+ console.log(name);
- /* Get the corresponding worksheet object */
- const sheet = wb.Sheets[name];
+ /* Get the corresponding worksheet object */
+ const sheet = wb.Sheets[name];
- /* Print a CSV export of the worksheet */
- console.log(XLSX.utils.sheet_to_csv(sheet));
-});
+ /* Print a CSV export of the worksheet */
+ console.log(XLSX.utils.sheet_to_csv(sheet));
+ });
+})();
```
-
-
-
\ No newline at end of file
+
\ No newline at end of file