google-spreadsheet 3.0.12 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +1 -0
- package/Changelog.md +10 -0
- package/README.md +153 -0
- package/TODO +73 -0
- package/lib/GoogleSpreadsheet.js +32 -5
- package/lib/GoogleSpreadsheetCell.js +0 -1
- package/lib/GoogleSpreadsheetWorksheet.js +61 -12
- package/package.json +6 -5
package/.eslintrc.js
CHANGED
package/Changelog.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
TODO: set this up to be automated and pulled from git commits... for now just going to leave some notes manually!
|
|
4
|
+
|
|
5
|
+
### 3.2.0 (2021-11-07)
|
|
6
|
+
|
|
7
|
+
- Added `insertDimension` functionality
|
|
8
|
+
- Added custom header row index for row-based API
|
|
9
|
+
- Bumped dependency versions
|
|
10
|
+
- Readme/docs cleanup
|
package/README.md
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# google-spreadsheet
|
|
2
|
+
> The most popular [Google Sheets API](https://developers.google.com/sheets/api/reference/rest) wrapper for javascript
|
|
3
|
+
|
|
4
|
+
[](https://www.npmjs.com/package/google-spreadsheet)
|
|
5
|
+
[](https://circleci.com/gh/theoephraim/node-google-spreadsheet)
|
|
6
|
+
[](https://snyk.io/test/github/theoephraim/node-google-spreadsheet?targetFile=package.json)
|
|
7
|
+
[](https://www.npmtrends.com/google-spreadsheet)
|
|
8
|
+
|
|
9
|
+
- multiple auth options - service account (w/ optional impersonation), OAuth 2.0, API key (read-only)
|
|
10
|
+
- cell-based API - read, write, bulk-updates, formatting
|
|
11
|
+
- row-based API - read, update, delete (based on the old v3 row-based calls)
|
|
12
|
+
- managing worksheets - add, remove, resize, change title, formatting
|
|
13
|
+
|
|
14
|
+
**Docs site -**
|
|
15
|
+
Full docs available at [https://theoephraim.github.io/node-google-spreadsheet](https://theoephraim.github.io/node-google-spreadsheet)
|
|
16
|
+
|
|
17
|
+
> **🚨 Google Deprecation Warning - affects older version (v2) of this module 🚨**
|
|
18
|
+
>
|
|
19
|
+
> Google is [phasing out their old v3 api](https://cloud.google.com/blog/products/g-suite/migrate-your-apps-use-latest-sheets-api), which the older version of this module used. Originally they were going to shut it down on March 3rd 2020, but have pushed that date back to June 2021.
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
**Regardless, please upgrade to the latest version of this module (v3) which uses the newer sheets v4 API**
|
|
23
|
+
|
|
24
|
+
-------------
|
|
25
|
+
|
|
26
|
+
> 🌈 **Installation** - `npm i google-spreadsheet --save` or `yarn add google-spreadsheet`
|
|
27
|
+
|
|
28
|
+
## Examples
|
|
29
|
+
_the following examples are meant to give you an idea of just some of the things you can do_
|
|
30
|
+
|
|
31
|
+
> **IMPORTANT NOTE** - To keep the examples concise, I'm calling await [at the top level](https://v8.dev/features/top-level-await) which is not allowed by default in most versions of node. If you need to call await in a script at the root level, you must instead wrap it in an async function like so:
|
|
32
|
+
|
|
33
|
+
```javascript
|
|
34
|
+
(async function() {
|
|
35
|
+
await someAsyncFunction();
|
|
36
|
+
}());
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
### The Basics
|
|
41
|
+
```javascript
|
|
42
|
+
const { GoogleSpreadsheet } = require('google-spreadsheet');
|
|
43
|
+
|
|
44
|
+
// Initialize the sheet - doc ID is the long id in the sheets URL
|
|
45
|
+
const doc = new GoogleSpreadsheet('<the sheet ID from the url>');
|
|
46
|
+
|
|
47
|
+
// Initialize Auth - see https://theoephraim.github.io/node-google-spreadsheet/#/getting-started/authentication
|
|
48
|
+
await doc.useServiceAccountAuth({
|
|
49
|
+
// env var values are copied from service account credentials generated by google
|
|
50
|
+
// see "Authentication" section in docs for more info
|
|
51
|
+
client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
|
|
52
|
+
private_key: process.env.GOOGLE_PRIVATE_KEY,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
await doc.loadInfo(); // loads document properties and worksheets
|
|
56
|
+
console.log(doc.title);
|
|
57
|
+
await doc.updateProperties({ title: 'renamed doc' });
|
|
58
|
+
|
|
59
|
+
const sheet = doc.sheetsByIndex[0]; // or use doc.sheetsById[id] or doc.sheetsByTitle[title]
|
|
60
|
+
console.log(sheet.title);
|
|
61
|
+
console.log(sheet.rowCount);
|
|
62
|
+
|
|
63
|
+
// adding / removing sheets
|
|
64
|
+
const newSheet = await doc.addSheet({ title: 'hot new sheet!' });
|
|
65
|
+
await newSheet.delete();
|
|
66
|
+
```
|
|
67
|
+
More info:
|
|
68
|
+
- [GoogleSpreadsheet](https://theoephraim.github.io/node-google-spreadsheet/#/classes/google-spreadsheet)
|
|
69
|
+
- [GoogleSpreadsheetWorksheet](https://theoephraim.github.io/node-google-spreadsheet/#/classes/google-spreadsheet-worksheet)
|
|
70
|
+
- [Authentication](https://theoephraim.github.io/node-google-spreadsheet/#/getting-started/authentication)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
### Working with rows
|
|
75
|
+
```javascript
|
|
76
|
+
// create a sheet and set the header row
|
|
77
|
+
const sheet = await doc.addSheet({ headerValues: ['name', 'email'] });
|
|
78
|
+
|
|
79
|
+
// append rows
|
|
80
|
+
const larryRow = await sheet.addRow({ name: 'Larry Page', email: 'larry@google.com' });
|
|
81
|
+
const moreRows = await sheet.addRows([
|
|
82
|
+
{ name: 'Sergey Brin', email: 'sergey@google.com' },
|
|
83
|
+
{ name: 'Eric Schmidt', email: 'eric@google.com' },
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
// read rows
|
|
87
|
+
const rows = await sheet.getRows(); // can pass in { limit, offset }
|
|
88
|
+
|
|
89
|
+
// read/write row values
|
|
90
|
+
console.log(rows[0].name); // 'Larry Page'
|
|
91
|
+
rows[1].email = 'sergey@abc.xyz'; // update a value
|
|
92
|
+
await rows[1].save(); // save updates
|
|
93
|
+
await rows[1].delete(); // delete a row
|
|
94
|
+
```
|
|
95
|
+
More info:
|
|
96
|
+
- [GoogleSpreadsheetWorksheet > Working With Rows](https://theoephraim.github.io/node-google-spreadsheet/#/classes/google-spreadsheet-worksheet#working-with-rows)
|
|
97
|
+
- [GoogleSpreadsheetRow](https://theoephraim.github.io/node-google-spreadsheet/#/classes/google-spreadsheet-row)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
### Working with cells
|
|
102
|
+
```javascript
|
|
103
|
+
await sheet.loadCells('A1:E10'); // loads a range of cells
|
|
104
|
+
console.log(sheet.cellStats); // total cells, loaded, how many non-empty
|
|
105
|
+
const a1 = sheet.getCell(0, 0); // access cells using a zero-based index
|
|
106
|
+
const c6 = sheet.getCellByA1('C6'); // or A1 style notation
|
|
107
|
+
// access everything about the cell
|
|
108
|
+
console.log(a1.value);
|
|
109
|
+
console.log(a1.formula);
|
|
110
|
+
console.log(a1.formattedValue);
|
|
111
|
+
// update the cell contents and formatting
|
|
112
|
+
a1.value = 123.456;
|
|
113
|
+
c6.formula = '=A1';
|
|
114
|
+
a1.textFormat = { bold: true };
|
|
115
|
+
c6.note = 'This is a note!';
|
|
116
|
+
await sheet.saveUpdatedCells(); // save all updates in one call
|
|
117
|
+
```
|
|
118
|
+
More info:
|
|
119
|
+
- [GoogleSpreadsheetWorksheet > Working With Cells](https://theoephraim.github.io/node-google-spreadsheet/#/classes/google-spreadsheet-worksheet#working-with-cells)
|
|
120
|
+
- [GoogleSpreadsheetCell](https://theoephraim.github.io/node-google-spreadsheet/#/classes/google-spreadsheet-cell)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
## Why?
|
|
125
|
+
> **This module provides an intuitive wrapper around Google's API to simplify common interactions**
|
|
126
|
+
|
|
127
|
+
While Google's v4 sheets api is much easier to use than v3 was, the official [googleapis npm module](https://www.npmjs.com/package/googleapis) is a giant meta-tool that handles _every Google product_. The module and the API itself are awkward and the docs are pretty terrible, at least to get started.
|
|
128
|
+
|
|
129
|
+
**In what situation should you use Google's API directly?**<br>
|
|
130
|
+
This module makes trade-offs for simplicity of the interface.
|
|
131
|
+
Google's API provides a mechanism to make many requests in parallel, so if speed and efficiency is extremely important to your use case, you may want to use their API directly. There are also several features of their API that are not implemented here yet.
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
## Support & Contributions
|
|
135
|
+
|
|
136
|
+
This module was written and is actively maintained by [Theo Ephraim](https://theoephraim.com).
|
|
137
|
+
|
|
138
|
+
**Are you actively using this module for a commercial project? Want to help support it?**<br>
|
|
139
|
+
[Buy Theo a beer](https://paypal.me/theoephraim)
|
|
140
|
+
|
|
141
|
+
#### Sponsors
|
|
142
|
+
|
|
143
|
+
None yet - get in touch!
|
|
144
|
+
|
|
145
|
+
#### Contributing
|
|
146
|
+
|
|
147
|
+
Contributions are welcome, but please follow the existing conventions, use the linter, add relevant tests, add relevant documentation.
|
|
148
|
+
|
|
149
|
+
The docs site is generated using [docsify](https://docsify.js.org). To preview and run locally so you can make edits, run `npm run docs:preview` and head to http://localhost:3000
|
|
150
|
+
The content lives in markdown files in the docs folder.
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
This is free and unencumbered public domain software. For more info, see https://unlicense.org.
|
package/TODO
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
- support more cell functionality
|
|
2
|
+
- data validation rules - https://github.com/theoephraim/node-google-spreadsheet/issues/487
|
|
3
|
+
|
|
4
|
+
- dont explode if sheet contains charts - https://github.com/theoephraim/node-google-spreadsheet/issues/444
|
|
5
|
+
- add row.toJSON()
|
|
6
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/247
|
|
7
|
+
- google auth - Application Default Creds
|
|
8
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/215
|
|
9
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/345
|
|
10
|
+
|
|
11
|
+
- escape issues for strings starting with = `'=not a formula`
|
|
12
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/323
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
- browser/react native, older ES support
|
|
17
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/339
|
|
18
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/382
|
|
19
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/406
|
|
20
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/404
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
- nice tips here - https://github.com/mikro-orm/mikro-orm/issues/12
|
|
24
|
+
- start using semantic release? or similar https://semantic-release.gitbook.io/semantic-release/
|
|
25
|
+
- better commit messages to autogenerate changelog
|
|
26
|
+
- commitizen - https://github.com/commitizen/cz-cli
|
|
27
|
+
- https://gist.github.com/brianclements/841ea7bffdb01346392c
|
|
28
|
+
- commitlint checks - https://github.com/conventional-changelog/commitlint
|
|
29
|
+
- https://github.com/conventional-changelog/conventional-changelog
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
BUGS
|
|
36
|
+
- fetching single row via GRO has issues
|
|
37
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/347
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
MISSING FUNCTIONS
|
|
41
|
+
|
|
42
|
+
- support batchGet
|
|
43
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/326
|
|
44
|
+
|
|
45
|
+
- update filters
|
|
46
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/328
|
|
47
|
+
- insertDimension
|
|
48
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/366
|
|
49
|
+
- conditional formatting
|
|
50
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/410
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
OTHER
|
|
54
|
+
- row to cell interface
|
|
55
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/343
|
|
56
|
+
- reading from draftValue
|
|
57
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/350
|
|
58
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/402
|
|
59
|
+
- heroku config docs
|
|
60
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/354
|
|
61
|
+
- document metadata from drive api
|
|
62
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/364
|
|
63
|
+
- date formatting, escaping issues
|
|
64
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/367
|
|
65
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/363
|
|
66
|
+
- release notes
|
|
67
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/384
|
|
68
|
+
- delete rows from google forms
|
|
69
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/393
|
|
70
|
+
- better handling of merged cells
|
|
71
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/400
|
|
72
|
+
- specify header row
|
|
73
|
+
https://github.com/theoephraim/node-google-spreadsheet/issues/407
|
package/lib/GoogleSpreadsheet.js
CHANGED
|
@@ -20,6 +20,7 @@ const AUTH_MODES = {
|
|
|
20
20
|
JWT: 'JWT',
|
|
21
21
|
API_KEY: 'API_KEY',
|
|
22
22
|
RAW_ACCESS_TOKEN: 'RAW_ACCESS_TOKEN',
|
|
23
|
+
OAUTH: 'OAUTH',
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
class GoogleSpreadsheet {
|
|
@@ -31,7 +32,7 @@ class GoogleSpreadsheet {
|
|
|
31
32
|
|
|
32
33
|
// create an axios instance with sheet root URL and interceptors to handle auth
|
|
33
34
|
this.axios = Axios.create({
|
|
34
|
-
baseURL: `https://sheets.googleapis.com/v4/spreadsheets/${sheetId}`,
|
|
35
|
+
baseURL: `https://sheets.googleapis.com/v4/spreadsheets/${sheetId || ''}`,
|
|
35
36
|
// send arrays in params with duplicate keys - ie `?thing=1&thing=2` vs `?thing[]=1...`
|
|
36
37
|
// solution taken from https://github.com/axios/axios/issues/604
|
|
37
38
|
paramsSerializer(params) {
|
|
@@ -59,6 +60,23 @@ class GoogleSpreadsheet {
|
|
|
59
60
|
return this;
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
// CREATE NEW DOC ////////////////////////////////////////////////////////////////////////////////
|
|
64
|
+
async createNewSpreadsheetDocument(properties) {
|
|
65
|
+
// see updateProperties for more info about available properties
|
|
66
|
+
|
|
67
|
+
if (this.spreadsheetId) {
|
|
68
|
+
throw new Error('Only call `createNewSpreadsheetDocument()` on a GoogleSpreadsheet object that has no spreadsheetId set');
|
|
69
|
+
}
|
|
70
|
+
const response = await this.axios.post(this.url, {
|
|
71
|
+
properties,
|
|
72
|
+
});
|
|
73
|
+
this.spreadsheetId = response.data.spreadsheetId;
|
|
74
|
+
this.axios.defaults.baseURL += this.spreadsheetId;
|
|
75
|
+
|
|
76
|
+
this._rawProperties = response.data.properties;
|
|
77
|
+
_.each(response.data.sheets, (s) => this._updateOrCreateSheet(s));
|
|
78
|
+
}
|
|
79
|
+
|
|
62
80
|
// AUTH RELATED FUNCTIONS ////////////////////////////////////////////////////////////////////////
|
|
63
81
|
async useApiKey(key) {
|
|
64
82
|
this.authMode = AUTH_MODES.API_KEY;
|
|
@@ -71,6 +89,11 @@ class GoogleSpreadsheet {
|
|
|
71
89
|
this.accessToken = token;
|
|
72
90
|
}
|
|
73
91
|
|
|
92
|
+
async useOAuth2Client(oAuth2Client) {
|
|
93
|
+
this.authMode = AUTH_MODES.OAUTH;
|
|
94
|
+
this.oAuth2Client = oAuth2Client;
|
|
95
|
+
}
|
|
96
|
+
|
|
74
97
|
// creds should be an object obtained by loading the json file google gives you
|
|
75
98
|
// impersonateAs is an email of any user in the G Suite domain
|
|
76
99
|
// (only works if service account has domain-wide delegation enabled)
|
|
@@ -116,6 +139,9 @@ class GoogleSpreadsheet {
|
|
|
116
139
|
if (!this.apiKey) throw new Error('Please set API key');
|
|
117
140
|
config.params = config.params || {};
|
|
118
141
|
config.params.key = this.apiKey;
|
|
142
|
+
} else if (this.authMode === AUTH_MODES.OAUTH) {
|
|
143
|
+
const credentials = await this.oAuth2Client.getAccessToken();
|
|
144
|
+
config.headers.Authorization = `Bearer ${credentials.token}`;
|
|
119
145
|
} else {
|
|
120
146
|
throw new Error('You must initialize some kind of auth before making any requests');
|
|
121
147
|
}
|
|
@@ -172,7 +198,7 @@ class GoogleSpreadsheet {
|
|
|
172
198
|
}
|
|
173
199
|
|
|
174
200
|
_ensureInfoLoaded() {
|
|
175
|
-
if (!this._rawProperties) throw new Error('You must call `
|
|
201
|
+
if (!this._rawProperties) throw new Error('You must call `doc.loadInfo()` before accessing this property');
|
|
176
202
|
}
|
|
177
203
|
|
|
178
204
|
_updateRawProperties(newProperties) { this._rawProperties = newProperties; }
|
|
@@ -273,15 +299,16 @@ class GoogleSpreadsheet {
|
|
|
273
299
|
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddSheetRequest
|
|
274
300
|
|
|
275
301
|
const response = await this._makeSingleUpdateRequest('addSheet', {
|
|
276
|
-
properties: _.omit(properties, 'headers', 'headerValues'),
|
|
302
|
+
properties: _.omit(properties, 'headers', 'headerValues', 'headerRowIndex'),
|
|
277
303
|
});
|
|
278
304
|
// _makeSingleUpdateRequest already adds the sheet
|
|
279
305
|
const newSheetId = response.properties.sheetId;
|
|
280
306
|
const newSheet = this.sheetsById[newSheetId];
|
|
281
307
|
|
|
282
308
|
// allow it to work with `.headers` but `.headerValues` is the real prop
|
|
283
|
-
|
|
284
|
-
|
|
309
|
+
const headers = properties.headerValues || properties.headers;
|
|
310
|
+
if (headers) {
|
|
311
|
+
await newSheet.setHeaderRow(headers, properties.headerRowIndex);
|
|
285
312
|
}
|
|
286
313
|
|
|
287
314
|
return newSheet;
|
|
@@ -20,6 +20,8 @@ class GoogleSpreadsheetWorksheet {
|
|
|
20
20
|
constructor(parentSpreadsheet, { properties, data }) {
|
|
21
21
|
this._spreadsheet = parentSpreadsheet; // the parent GoogleSpreadsheet instance
|
|
22
22
|
|
|
23
|
+
this._headerRowIndex = 1; // assume "header row" (for row-based calls) is in first row
|
|
24
|
+
|
|
23
25
|
// basic properties
|
|
24
26
|
this._rawProperties = properties;
|
|
25
27
|
|
|
@@ -51,6 +53,7 @@ class GoogleSpreadsheetWorksheet {
|
|
|
51
53
|
resetLocalCache(dataOnly) {
|
|
52
54
|
if (!dataOnly) this._rawProperties = null;
|
|
53
55
|
this.headerValues = null;
|
|
56
|
+
this._headerRowIndex = 1;
|
|
54
57
|
this._cells = [];
|
|
55
58
|
}
|
|
56
59
|
|
|
@@ -174,7 +177,6 @@ class GoogleSpreadsheetWorksheet {
|
|
|
174
177
|
return this._cells[rowIndex][columnIndex];
|
|
175
178
|
}
|
|
176
179
|
|
|
177
|
-
|
|
178
180
|
async loadCells(sheetFilters) {
|
|
179
181
|
// load the whole sheet
|
|
180
182
|
if (!sheetFilters) return this._spreadsheet.loadCells(this.a1SheetName);
|
|
@@ -283,11 +285,11 @@ class GoogleSpreadsheetWorksheet {
|
|
|
283
285
|
// });
|
|
284
286
|
// }
|
|
285
287
|
|
|
286
|
-
|
|
287
288
|
// ROW BASED FUNCTIONS ///////////////////////////////////////////////////////////////////////////
|
|
288
289
|
|
|
289
|
-
async loadHeaderRow() {
|
|
290
|
-
|
|
290
|
+
async loadHeaderRow(headerRowIndex) {
|
|
291
|
+
if (headerRowIndex !== undefined) this._headerRowIndex = headerRowIndex;
|
|
292
|
+
const rows = await this.getCellsInRange(`A${this._headerRowIndex}:${this.lastColumnLetter}${this._headerRowIndex}`);
|
|
291
293
|
if (!rows) {
|
|
292
294
|
throw new Error('No values in the header row - fill the first row with header values before trying to interact with rows');
|
|
293
295
|
}
|
|
@@ -298,7 +300,7 @@ class GoogleSpreadsheetWorksheet {
|
|
|
298
300
|
checkForDuplicateHeaders(this.headerValues);
|
|
299
301
|
}
|
|
300
302
|
|
|
301
|
-
async setHeaderRow(headerValues) {
|
|
303
|
+
async setHeaderRow(headerValues, headerRowIndex) {
|
|
302
304
|
if (!headerValues) return;
|
|
303
305
|
if (headerValues.length > this.columnCount) {
|
|
304
306
|
throw new Error(`Sheet is not large enough to fit ${headerValues.length} columns. Resize the sheet first.`);
|
|
@@ -310,15 +312,17 @@ class GoogleSpreadsheetWorksheet {
|
|
|
310
312
|
throw new Error('All your header cells are blank -');
|
|
311
313
|
}
|
|
312
314
|
|
|
315
|
+
if (headerRowIndex) this._headerRowIndex = headerRowIndex;
|
|
316
|
+
|
|
313
317
|
const response = await this._spreadsheet.axios.request({
|
|
314
318
|
method: 'put',
|
|
315
|
-
url: `/values/${this.encodedA1SheetName}
|
|
319
|
+
url: `/values/${this.encodedA1SheetName}!${this._headerRowIndex}:${this._headerRowIndex}`,
|
|
316
320
|
params: {
|
|
317
321
|
valueInputOption: 'USER_ENTERED', // other option is RAW
|
|
318
322
|
includeValuesInResponse: true,
|
|
319
323
|
},
|
|
320
324
|
data: {
|
|
321
|
-
range: `${this.a1SheetName}
|
|
325
|
+
range: `${this.a1SheetName}!${this._headerRowIndex}:${this._headerRowIndex}`,
|
|
322
326
|
majorDimension: 'ROWS',
|
|
323
327
|
values: [[
|
|
324
328
|
...trimmedHeaderValues,
|
|
@@ -369,7 +373,7 @@ class GoogleSpreadsheetWorksheet {
|
|
|
369
373
|
|
|
370
374
|
const response = await this._spreadsheet.axios.request({
|
|
371
375
|
method: 'post',
|
|
372
|
-
url: `/values/${this.encodedA1SheetName}!
|
|
376
|
+
url: `/values/${this.encodedA1SheetName}!A${this._headerRowIndex}:append`,
|
|
373
377
|
params: {
|
|
374
378
|
valueInputOption: options.raw ? 'RAW' : 'USER_ENTERED',
|
|
375
379
|
insertDataOption: options.insert ? 'INSERT_ROWS' : 'OVERWRITE',
|
|
@@ -423,7 +427,7 @@ class GoogleSpreadsheetWorksheet {
|
|
|
423
427
|
|
|
424
428
|
if (!this.headerValues) await this.loadHeaderRow();
|
|
425
429
|
|
|
426
|
-
const firstRow =
|
|
430
|
+
const firstRow = 1 + this._headerRowIndex + options.offset;
|
|
427
431
|
const lastRow = firstRow + options.limit - 1; // inclusive so we subtract 1
|
|
428
432
|
const lastColumn = columnToLetter(this.headerValues.length);
|
|
429
433
|
const rawRows = await this.getCellsInRange(
|
|
@@ -553,14 +557,33 @@ class GoogleSpreadsheetWorksheet {
|
|
|
553
557
|
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CopyPasteRequest
|
|
554
558
|
}
|
|
555
559
|
|
|
556
|
-
async mergeCells() {
|
|
560
|
+
async mergeCells(range, mergeType = 'MERGE_ALL') {
|
|
557
561
|
// Request type = `mergeCells`
|
|
558
562
|
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#MergeCellsRequest
|
|
563
|
+
if (range.sheetId && range.sheetId !== this.sheetId) {
|
|
564
|
+
throw new Error('Leave sheet ID blank or set to matching ID of this sheet');
|
|
565
|
+
}
|
|
566
|
+
await this._makeSingleUpdateRequest('mergeCells', {
|
|
567
|
+
mergeType,
|
|
568
|
+
range: {
|
|
569
|
+
...range,
|
|
570
|
+
sheetId: this.sheetId,
|
|
571
|
+
},
|
|
572
|
+
});
|
|
559
573
|
}
|
|
560
574
|
|
|
561
|
-
async unmergeCells() {
|
|
575
|
+
async unmergeCells(range) {
|
|
562
576
|
// Request type = `unmergeCells`
|
|
563
577
|
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UnmergeCellsRequest
|
|
578
|
+
if (range.sheetId && range.sheetId !== this.sheetId) {
|
|
579
|
+
throw new Error('Leave sheet ID blank or set to matching ID of this sheet');
|
|
580
|
+
}
|
|
581
|
+
await this._makeSingleUpdateRequest('unmergeCells', {
|
|
582
|
+
range: {
|
|
583
|
+
...range,
|
|
584
|
+
sheetId: this.sheetId,
|
|
585
|
+
},
|
|
586
|
+
});
|
|
564
587
|
}
|
|
565
588
|
|
|
566
589
|
async updateBorders() {
|
|
@@ -613,9 +636,35 @@ class GoogleSpreadsheetWorksheet {
|
|
|
613
636
|
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#FindReplaceRequest
|
|
614
637
|
}
|
|
615
638
|
|
|
616
|
-
async insertDimension() {
|
|
639
|
+
async insertDimension(columnsOrRows, range, inheritFromBefore = null) {
|
|
617
640
|
// Request type = `insertDimension`
|
|
618
641
|
// https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#InsertDimensionRequest
|
|
642
|
+
|
|
643
|
+
if (!columnsOrRows) throw new Error('You need to specify a dimension. i.e. COLUMNS|ROWS');
|
|
644
|
+
if (!_.isObject(range)) throw new Error('`range` must be an object containing `startIndex` and `endIndex`');
|
|
645
|
+
if (!_.isInteger(range.startIndex) || range.startIndex < 0) throw new Error('range.startIndex must be an integer >=0');
|
|
646
|
+
if (!_.isInteger(range.endIndex) || range.endIndex < 0) throw new Error('range.endIndex must be an integer >=0');
|
|
647
|
+
if (range.endIndex <= range.startIndex) throw new Error('range.endIndex must be greater than range.startIndex');
|
|
648
|
+
|
|
649
|
+
// default inheritFromBefore to true - unless inserting in the first row/column
|
|
650
|
+
if (inheritFromBefore === null) {
|
|
651
|
+
inheritFromBefore = range.startIndex > 0;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// do not allow inheritFromBefore if inserting at first row/column
|
|
655
|
+
if (inheritFromBefore && range.startIndex === 0) {
|
|
656
|
+
throw new Error('Cannot set inheritFromBefore to true if inserting in first row/column');
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
return this._makeSingleUpdateRequest('insertDimension', {
|
|
660
|
+
range: {
|
|
661
|
+
sheetId: this.sheetId,
|
|
662
|
+
dimension: columnsOrRows,
|
|
663
|
+
startIndex: range.startIndex,
|
|
664
|
+
endIndex: range.endIndex,
|
|
665
|
+
},
|
|
666
|
+
inheritFromBefore,
|
|
667
|
+
});
|
|
619
668
|
}
|
|
620
669
|
|
|
621
670
|
async insertRange() {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"author": "Theo Ephraim <theozero@gmail.com> (https://theoephraim.com)",
|
|
3
3
|
"name": "google-spreadsheet",
|
|
4
4
|
"description": "Google Sheets API (v4) -- simple interface to read/write data and manage sheets",
|
|
5
|
-
"version": "3.0
|
|
5
|
+
"version": "3.2.0",
|
|
6
6
|
"license": "Unlicense",
|
|
7
7
|
"keywords": [
|
|
8
8
|
"google spreadsheets",
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"node": ">=0.8.0"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"axios": "^0.
|
|
30
|
-
"google-auth-library": "^6.
|
|
31
|
-
"lodash": "^4.17.
|
|
29
|
+
"axios": "^0.21.4",
|
|
30
|
+
"google-auth-library": "^6.1.3",
|
|
31
|
+
"lodash": "^4.17.21"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"delay": "^4.3.0",
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
"test": "jest --runInBand",
|
|
47
47
|
"lint": "eslint ./",
|
|
48
48
|
"lint:fix": "eslint ./ --fix",
|
|
49
|
-
"docs:preview": "docsify serve docs"
|
|
49
|
+
"docs:preview": "docsify serve docs",
|
|
50
|
+
"readme:copy": "echo \"<!-- DO NOT EDIT THIS FILE, EDIT MAIN README.md AND RUN \\`npm readme:copy\\` instead -->\n\n_Welcome to the docs site for_\n\" | cat - README.md > docs/README.md"
|
|
50
51
|
},
|
|
51
52
|
"husky": {
|
|
52
53
|
"hooks": {
|