google-spreadsheet 3.0.14 → 3.3.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 CHANGED
@@ -33,6 +33,7 @@ module.exports = {
33
33
  exports: 'always-multiline',
34
34
  functions: 'never', // this breaks
35
35
  }],
36
+ 'no-multiple-empty-lines': 0, // sometimes helpful to break up sections of code
36
37
  },
37
38
  overrides: [
38
39
  { // extra jest related rules for tests
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 CHANGED
@@ -6,7 +6,7 @@
6
6
  [![Known Vulnerabilities](https://snyk.io/test/github/theoephraim/node-google-spreadsheet/badge.svg?targetFile=package.json)](https://snyk.io/test/github/theoephraim/node-google-spreadsheet?targetFile=package.json)
7
7
  [![NPM](https://img.shields.io/npm/dw/google-spreadsheet)](https://www.npmtrends.com/google-spreadsheet)
8
8
 
9
- - multiple auth options - API key, service account, oauth
9
+ - multiple auth options - service account (w/ optional impersonation), OAuth 2.0, API key (read-only)
10
10
  - cell-based API - read, write, bulk-updates, formatting
11
11
  - row-based API - read, update, delete (based on the old v3 row-based calls)
12
12
  - managing worksheets - add, remove, resize, change title, formatting
@@ -16,7 +16,7 @@ Full docs available at [https://theoephraim.github.io/node-google-spreadsheet](h
16
16
 
17
17
  > **🚨 Google Deprecation Warning - affects older version (v2) of this module 🚨**
18
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 to use. Originally they were going to shut it down on March 3rd 2020, but have pushed that date back to January 2021.
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
20
 
21
21
 
22
22
  **Regardless, please upgrade to the latest version of this module (v3) which uses the newer sheets v4 API**
@@ -28,7 +28,7 @@ Full docs available at [https://theoephraim.github.io/node-google-spreadsheet](h
28
28
  ## Examples
29
29
  _the following examples are meant to give you an idea of just some of the things you can do_
30
30
 
31
- !> NOTE - To keep the examples more 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:
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
32
 
33
33
  ```javascript
34
34
  (async function() {
@@ -41,20 +41,16 @@ _the following examples are meant to give you an idea of just some of the things
41
41
  ```javascript
42
42
  const { GoogleSpreadsheet } = require('google-spreadsheet');
43
43
 
44
- // spreadsheet key is the long id in the sheets URL
44
+ // Initialize the sheet - doc ID is the long id in the sheets URL
45
45
  const doc = new GoogleSpreadsheet('<the sheet ID from the url>');
46
46
 
47
- // use service account creds
47
+ // Initialize Auth - see https://theoephraim.github.io/node-google-spreadsheet/#/getting-started/authentication
48
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
49
51
  client_email: process.env.GOOGLE_SERVICE_ACCOUNT_EMAIL,
50
52
  private_key: process.env.GOOGLE_PRIVATE_KEY,
51
53
  });
52
- // OR load directly from json file if not in secure environment
53
- await doc.useServiceAccountAuth(require('./creds-from-google.json'));
54
- // OR use service account to impersonate a user (see https://developers.google.com/identity/protocols/oauth2/service-account#delegatingauthority)
55
- await doc.useServiceAccountAuth(require('./creds-from-google.json'), 'some-user@my-domain.com');
56
- // OR use API key -- only for read-only access to public sheets
57
- doc.useApiKey('YOUR-API-KEY');
58
54
 
59
55
  await doc.loadInfo(); // loads document properties and worksheets
60
56
  console.log(doc.title);
@@ -104,7 +100,7 @@ More info:
104
100
 
105
101
  ### Working with cells
106
102
  ```javascript
107
- await sheet.loadCells('A1:E10'); // loads a range of cells
103
+ await sheet.loadCells('A1:E10'); // loads range of cells into local cache - DOES NOT RETURN THE CELLS
108
104
  console.log(sheet.cellStats); // total cells, loaded, how many non-empty
109
105
  const a1 = sheet.getCell(0, 0); // access cells using a zero-based index
110
106
  const c6 = sheet.getCellByA1('C6'); // or A1 style notation
@@ -150,7 +146,7 @@ None yet - get in touch!
150
146
 
151
147
  Contributions are welcome, but please follow the existing conventions, use the linter, add relevant tests, add relevant documentation.
152
148
 
153
- These docs are 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
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
154
150
  The content lives in markdown files in the docs folder.
155
151
 
156
152
  ## License
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
@@ -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 {
@@ -28,6 +29,7 @@ class GoogleSpreadsheet {
28
29
  this.authMode = null;
29
30
  this._rawSheets = {};
30
31
  this._rawProperties = null;
32
+ this._spreadsheetUrl = null;
31
33
 
32
34
  // create an axios instance with sheet root URL and interceptors to handle auth
33
35
  this.axios = Axios.create({
@@ -88,6 +90,11 @@ class GoogleSpreadsheet {
88
90
  this.accessToken = token;
89
91
  }
90
92
 
93
+ async useOAuth2Client(oAuth2Client) {
94
+ this.authMode = AUTH_MODES.OAUTH;
95
+ this.oAuth2Client = oAuth2Client;
96
+ }
97
+
91
98
  // creds should be an object obtained by loading the json file google gives you
92
99
  // impersonateAs is an email of any user in the G Suite domain
93
100
  // (only works if service account has domain-wide delegation enabled)
@@ -133,6 +140,9 @@ class GoogleSpreadsheet {
133
140
  if (!this.apiKey) throw new Error('Please set API key');
134
141
  config.params = config.params || {};
135
142
  config.params.key = this.apiKey;
143
+ } else if (this.authMode === AUTH_MODES.OAUTH) {
144
+ const credentials = await this.oAuth2Client.getAccessToken();
145
+ config.headers.Authorization = `Bearer ${credentials.token}`;
136
146
  } else {
137
147
  throw new Error('You must initialize some kind of auth before making any requests');
138
148
  }
@@ -254,6 +264,7 @@ class GoogleSpreadsheet {
254
264
  ...includeCells && { includeGridData: true },
255
265
  },
256
266
  });
267
+ this._spreadsheetUrl = response.data.spreadsheetUrl;
257
268
  this._rawProperties = response.data.properties;
258
269
  _.each(response.data.sheets, (s) => this._updateOrCreateSheet(s));
259
270
  }
@@ -290,15 +301,16 @@ class GoogleSpreadsheet {
290
301
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddSheetRequest
291
302
 
292
303
  const response = await this._makeSingleUpdateRequest('addSheet', {
293
- properties: _.omit(properties, 'headers', 'headerValues'),
304
+ properties: _.omit(properties, 'headers', 'headerValues', 'headerRowIndex'),
294
305
  });
295
306
  // _makeSingleUpdateRequest already adds the sheet
296
307
  const newSheetId = response.properties.sheetId;
297
308
  const newSheet = this.sheetsById[newSheetId];
298
309
 
299
310
  // allow it to work with `.headers` but `.headerValues` is the real prop
300
- if (properties.headerValues || properties.headers) {
301
- await newSheet.setHeaderRow(properties.headerValues || properties.headers);
311
+ const headers = properties.headerValues || properties.headers;
312
+ if (headers) {
313
+ await newSheet.setHeaderRow(headers, properties.headerRowIndex);
302
314
  }
303
315
 
304
316
  return newSheet;
@@ -372,6 +384,43 @@ class GoogleSpreadsheet {
372
384
  const { sheets } = result.data;
373
385
  _.each(sheets, (sheet) => { this._updateOrCreateSheet(sheet); });
374
386
  }
387
+
388
+ // EXPORTING /////////////////////////////////////////////////////////////
389
+ async _downloadAs(fileType, worksheetId, returnStreamInsteadOfBuffer) {
390
+ // see https://stackoverflow.com/questions/11619805/using-the-google-drive-api-to-download-a-spreadsheet-in-csv-format/51235960#51235960
391
+
392
+ if (['html', 'xlsx', 'ods'].includes(fileType)) {
393
+ if (worksheetId) throw new Error(`Cannot specify worksheetId when exporting as ${fileType}`);
394
+ } else if (['csv', 'tsv', 'pdf'].includes(fileType)) {
395
+ if (worksheetId === undefined) throw new Error(`Must specify worksheetId when exporting as ${fileType}`);
396
+ } else {
397
+ throw new Error(`unsupported export fileType - ${fileType}`);
398
+ }
399
+
400
+ // google UI shows "html" but passes through "zip"
401
+ if (fileType === 'html') fileType = 'zip';
402
+
403
+ const exportUrl = this._spreadsheetUrl.replace('/edit', '/export');
404
+ const response = await this.axios.get(exportUrl, {
405
+ baseUrl: '', // unset baseUrl since we're not hitting the normal sheets API
406
+ params: {
407
+ id: this.spreadsheetId,
408
+ format: fileType,
409
+ ...worksheetId && { gid: worksheetId },
410
+ },
411
+ responseType: returnStreamInsteadOfBuffer ? 'stream' : 'arraybuffer',
412
+ });
413
+ return response.data;
414
+ }
415
+ async downloadAsHTML(returnStreamInsteadOfBuffer = false) {
416
+ return this._downloadAs('html', null, returnStreamInsteadOfBuffer);
417
+ }
418
+ async downloadAsXLSX(returnStreamInsteadOfBuffer = false) {
419
+ return this._downloadAs('xlsx', null, returnStreamInsteadOfBuffer);
420
+ }
421
+ async downloadAsODS(returnStreamInsteadOfBuffer = false) {
422
+ return this._downloadAs('ods', null, returnStreamInsteadOfBuffer);
423
+ }
375
424
  }
376
425
 
377
426
  module.exports = GoogleSpreadsheet;
@@ -202,7 +202,6 @@ class GoogleSpreadsheetCell {
202
202
  delete (format.backgroundColorStyle);
203
203
  }
204
204
 
205
-
206
205
  return {
207
206
  updateCells: {
208
207
  rows: [{
@@ -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
- const rows = await this.getCellsInRange(`A1:${this.lastColumnLetter}1`);
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}!1:1`,
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}!1:1`,
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}!A1:append`,
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 = 2 + options.offset; // skip first row AND not zero indexed
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(
@@ -440,6 +444,13 @@ class GoogleSpreadsheetWorksheet {
440
444
  return rows;
441
445
  }
442
446
 
447
+ async clearRows(options = {}) {
448
+ // default to first row after header
449
+ const startRowIndex = options.start || this._headerRowIndex + 1;
450
+ const endRowIndex = options.end || this.rowCount;
451
+ await this._spreadsheet.axios.post(`/values/${this.encodedA1SheetName}!${startRowIndex}:${endRowIndex}:clear`);
452
+ }
453
+
443
454
  // BASIC PROPS ///////////////////////////////////////////////////////////////////////////////////
444
455
  async updateProperties(properties) {
445
456
  // Request type = `updateSheetProperties`
@@ -622,9 +633,17 @@ class GoogleSpreadsheetWorksheet {
622
633
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DuplicateFilterViewRequest
623
634
  }
624
635
 
625
- async duplicateSheet() {
636
+ async duplicate(options = {}) {
626
637
  // Request type = `duplicateSheet`
627
638
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DuplicateSheetRequest
639
+ const response = await this._makeSingleUpdateRequest('duplicateSheet', {
640
+ sourceSheetId: this.sheetId,
641
+ ...options.index !== undefined && { insertSheetIndex: options.index },
642
+ ...options.id && { newSheetId: options.id },
643
+ ...options.title && { newSheetName: options.title },
644
+ });
645
+ const newSheetId = response.properties.sheetId;
646
+ return this._spreadsheet.sheetsById[newSheetId];
628
647
  }
629
648
 
630
649
  async findReplace() {
@@ -632,9 +651,35 @@ class GoogleSpreadsheetWorksheet {
632
651
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#FindReplaceRequest
633
652
  }
634
653
 
635
- async insertDimension() {
654
+ async insertDimension(columnsOrRows, range, inheritFromBefore = null) {
636
655
  // Request type = `insertDimension`
637
656
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#InsertDimensionRequest
657
+
658
+ if (!columnsOrRows) throw new Error('You need to specify a dimension. i.e. COLUMNS|ROWS');
659
+ if (!_.isObject(range)) throw new Error('`range` must be an object containing `startIndex` and `endIndex`');
660
+ if (!_.isInteger(range.startIndex) || range.startIndex < 0) throw new Error('range.startIndex must be an integer >=0');
661
+ if (!_.isInteger(range.endIndex) || range.endIndex < 0) throw new Error('range.endIndex must be an integer >=0');
662
+ if (range.endIndex <= range.startIndex) throw new Error('range.endIndex must be greater than range.startIndex');
663
+
664
+ // default inheritFromBefore to true - unless inserting in the first row/column
665
+ if (inheritFromBefore === null) {
666
+ inheritFromBefore = range.startIndex > 0;
667
+ }
668
+
669
+ // do not allow inheritFromBefore if inserting at first row/column
670
+ if (inheritFromBefore && range.startIndex === 0) {
671
+ throw new Error('Cannot set inheritFromBefore to true if inserting in first row/column');
672
+ }
673
+
674
+ return this._makeSingleUpdateRequest('insertDimension', {
675
+ range: {
676
+ sheetId: this.sheetId,
677
+ dimension: columnsOrRows,
678
+ startIndex: range.startIndex,
679
+ endIndex: range.endIndex,
680
+ },
681
+ inheritFromBefore,
682
+ });
638
683
  }
639
684
 
640
685
  async insertRange() {
@@ -820,12 +865,22 @@ class GoogleSpreadsheetWorksheet {
820
865
  });
821
866
  }
822
867
 
823
- async clear() {
824
- // clears all the data in the sheet
868
+ async clear(a1Range) {
869
+ // clears data in the sheet - defaults to entire sheet
870
+ const range = a1Range ? `!${a1Range}` : '';
825
871
  // sheet name without ie 'sheet1' rather than 'sheet1'!A1:B5 is all cells
826
- await this._spreadsheet.axios.post(`/values/${this.encodedA1SheetName}:clear`);
872
+ await this._spreadsheet.axios.post(`/values/${this.encodedA1SheetName}${range}:clear`);
827
873
  this.resetLocalCache(true);
828
874
  }
875
+ async downloadAsCSV(returnStreamInsteadOfBuffer = false) {
876
+ return this._spreadsheet._downloadAs('csv', this.sheetId, returnStreamInsteadOfBuffer);
877
+ }
878
+ async downloadAsTSV(returnStreamInsteadOfBuffer = false) {
879
+ return this._spreadsheet._downloadAs('tsv', this.sheetId, returnStreamInsteadOfBuffer);
880
+ }
881
+ async downloadAsPDF(returnStreamInsteadOfBuffer = false) {
882
+ return this._spreadsheet._downloadAs('pdf', this.sheetId, returnStreamInsteadOfBuffer);
883
+ }
829
884
  }
830
885
 
831
886
  module.exports = GoogleSpreadsheetWorksheet;
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.14",
5
+ "version": "3.3.0",
6
6
  "license": "Unlicense",
7
7
  "keywords": [
8
8
  "google spreadsheets",
@@ -16,7 +16,7 @@
16
16
  "api",
17
17
  "googleapis"
18
18
  ],
19
- "homepage": "https://github.com/theoephraim/node-google-spreadsheet",
19
+ "homepage": "https://theoephraim.github.io/node-google-spreadsheet",
20
20
  "repository": {
21
21
  "type": "git",
22
22
  "url": "git://github.com/theoephraim/node-google-spreadsheet.git"
@@ -26,13 +26,13 @@
26
26
  "node": ">=0.8.0"
27
27
  },
28
28
  "dependencies": {
29
- "axios": "^0.19.2",
29
+ "axios": "^0.21.4",
30
30
  "google-auth-library": "^6.1.3",
31
- "lodash": "^4.17.20"
31
+ "lodash": "^4.17.21"
32
32
  },
33
33
  "devDependencies": {
34
34
  "delay": "^4.3.0",
35
- "docsify-cli": "^4.4.0",
35
+ "docsify-cli": "^4.4.3",
36
36
  "eslint": "^6.8.0",
37
37
  "eslint-config-airbnb-base": "^14.0.0",
38
38
  "eslint-plugin-async-await": "0.0.0",
@@ -47,7 +47,7 @@
47
47
  "lint": "eslint ./",
48
48
  "lint:fix": "eslint ./ --fix",
49
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\" | cat - README.md > docs/README.md"
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"
51
51
  },
52
52
  "husky": {
53
53
  "hooks": {