google-spreadsheet 5.0.3 → 5.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/dist/index.js CHANGED
@@ -43,6 +43,12 @@ var GoogleSpreadsheetRow = class {
43
43
  this._worksheet = _worksheet;
44
44
  this._rowNumber = _rowNumber;
45
45
  this._rawData = _rawData;
46
+ this._padRawData();
47
+ }
48
+ /** pad _rawData with empty strings so it always matches header length */
49
+ _padRawData() {
50
+ const headerLength = this._worksheet.headerValues.length;
51
+ while (this._rawData.length < headerLength) this._rawData.push("");
46
52
  }
47
53
  _deleted = false;
48
54
  get deleted() {
@@ -60,6 +66,14 @@ var GoogleSpreadsheetRow = class {
60
66
  _updateRowNumber(newRowNumber) {
61
67
  this._rowNumber = newRowNumber;
62
68
  }
69
+ /**
70
+ * @internal
71
+ * Used internally to mark row as deleted.
72
+ * Should not be called directly.
73
+ */
74
+ _markDeleted() {
75
+ this._deleted = true;
76
+ }
63
77
  get a1Range() {
64
78
  return [
65
79
  this._worksheet.a1SheetName,
@@ -106,7 +120,8 @@ var GoogleSpreadsheetRow = class {
106
120
  majorDimension: "ROWS",
107
121
  values: [this._rawData]
108
122
  }
109
- })).json()).updatedData.values[0];
123
+ })).json()).updatedData.values?.[0] || [];
124
+ this._padRawData();
110
125
  }
111
126
  /** delete this row */
112
127
  async delete() {
@@ -163,6 +178,7 @@ var GoogleSpreadsheetCell = class {
163
178
  _rawData;
164
179
  _draftData = {};
165
180
  _error;
181
+ _deleted = false;
166
182
  constructor(_sheet, _rowIndex, _columnIndex, rawCellData) {
167
183
  this._sheet = _sheet;
168
184
  this._rowIndex = _rowIndex;
@@ -170,6 +186,9 @@ var GoogleSpreadsheetCell = class {
170
186
  this._updateRawData(rawCellData);
171
187
  this._rawData = rawCellData;
172
188
  }
189
+ get deleted() {
190
+ return this._deleted;
191
+ }
173
192
  /**
174
193
  * update cell using raw CellData coming back from sheets API
175
194
  * @internal
@@ -195,6 +214,23 @@ var GoogleSpreadsheetCell = class {
195
214
  get a1Address() {
196
215
  return `${this.a1Column}${this.a1Row}`;
197
216
  }
217
+ /**
218
+ * @internal
219
+ * Used internally to update cell indices after deleting rows/columns.
220
+ * Should not be called directly.
221
+ */
222
+ _updateIndices(rowIndex, columnIndex) {
223
+ this._rowIndex = rowIndex;
224
+ this._columnIndex = columnIndex;
225
+ }
226
+ /**
227
+ * @internal
228
+ * Used internally to mark cell as deleted.
229
+ * Should not be called directly.
230
+ */
231
+ _markDeleted() {
232
+ this._deleted = true;
233
+ }
198
234
  get value() {
199
235
  if (this._draftData.value !== void 0) throw new Error("Value has been changed");
200
236
  if (this._error) return this._error;
@@ -202,6 +238,7 @@ var GoogleSpreadsheetCell = class {
202
238
  return values(this._rawData.effectiveValue)[0];
203
239
  }
204
240
  set value(newValue) {
241
+ if (this._deleted) throw new Error("This cell has been deleted - reload cells before making updates.");
205
242
  if (newValue instanceof GoogleSpreadsheetCellErrorValue) throw new Error("You can't manually set a value to an error");
206
243
  if (isBoolean(newValue)) this._draftData.valueType = "boolValue";
207
244
  else if (isString(newValue)) if (newValue.substring(0, 1) === "=") this._draftData.valueType = "formulaValue";
@@ -261,8 +298,8 @@ var GoogleSpreadsheetCell = class {
261
298
  return this.value;
262
299
  }
263
300
  set stringValue(val) {
264
- if (val?.startsWith("=")) throw new Error("Use cell.formula to set formula values");
265
- this.value = val;
301
+ this._draftData.valueType = "stringValue";
302
+ this._draftData.value = val || "";
266
303
  }
267
304
  /**
268
305
  * Hyperlink contained within the cell.
@@ -470,7 +507,9 @@ var GoogleSpreadsheetWorksheet = class {
470
507
  _ensureInfoLoaded() {
471
508
  if (!this._rawProperties) throw new Error("You must call `doc.loadInfo()` again before accessing this property");
472
509
  }
473
- /** clear local cache of sheet data/properties */
510
+ /**
511
+ * clear local cache of sheet data/properties
512
+ */
474
513
  resetLocalCache(dataOnly) {
475
514
  if (!dataOnly) this._rawProperties = null;
476
515
  this._headerValues = void 0;
@@ -613,6 +652,7 @@ var GoogleSpreadsheetWorksheet = class {
613
652
  return `${this.a1SheetName}!${filter}`;
614
653
  }
615
654
  if (isObject(filter)) {
655
+ if ("developerMetadataLookup" in filter) return filter;
616
656
  const filterAny = filter;
617
657
  if (filterAny.sheetId && filterAny.sheetId !== this.sheetId) throw new Error("Leave sheet ID blank or set to matching ID of this sheet");
618
658
  return {
@@ -702,7 +742,9 @@ var GoogleSpreadsheetWorksheet = class {
702
742
  return new GoogleSpreadsheetRow(this, rowNumber++, rowValues);
703
743
  });
704
744
  }
705
- /** add a single row - see addRows for more info */
745
+ /**
746
+ * add a single row - see addRows for more info
747
+ */
706
748
  async addRow(rowValues, options) {
707
749
  return (await this.addRows([rowValues], options))[0];
708
750
  }
@@ -742,6 +784,79 @@ var GoogleSpreadsheetWorksheet = class {
742
784
  if (row.rowNumber > deletedRowNumber) row._updateRowNumber(row.rowNumber - 1);
743
785
  });
744
786
  }
787
+ /**
788
+ * @internal
789
+ * Used internally to update row numbers after deleting multiple rows.
790
+ * Should not be called directly.
791
+ * */
792
+ _shiftRowCacheBulk(startIndex, endIndex) {
793
+ const numDeleted = endIndex - startIndex;
794
+ const startRow = startIndex + 1;
795
+ const endRow = endIndex;
796
+ for (let rowNum = startRow; rowNum <= endRow; rowNum++) {
797
+ const row = this._rowCache[rowNum];
798
+ if (row) row._markDeleted();
799
+ delete this._rowCache[rowNum];
800
+ }
801
+ this._rowCache.forEach((row) => {
802
+ if (row.rowNumber > endRow) row._updateRowNumber(row.rowNumber - numDeleted);
803
+ });
804
+ }
805
+ /**
806
+ * @internal
807
+ * Used internally to shift cell cache after deleting rows.
808
+ * Should not be called directly.
809
+ * */
810
+ _shiftCellCacheRows(startIndex, endIndex) {
811
+ const numDeleted = endIndex - startIndex;
812
+ for (let rowIndex = startIndex; rowIndex < endIndex; rowIndex++) {
813
+ const row = this._cells[rowIndex];
814
+ if (row) row.forEach((cell) => {
815
+ if (cell) cell._markDeleted();
816
+ });
817
+ delete this._cells[rowIndex];
818
+ }
819
+ const rowsToShift = [];
820
+ for (let rowIndex = endIndex; rowIndex < this._cells.length; rowIndex++) if (this._cells[rowIndex]) rowsToShift.push({
821
+ oldRowIndex: rowIndex,
822
+ cells: this._cells[rowIndex]
823
+ });
824
+ rowsToShift.forEach(({ oldRowIndex, cells }) => {
825
+ delete this._cells[oldRowIndex];
826
+ const newRowIndex = oldRowIndex - numDeleted;
827
+ this._cells[newRowIndex] = cells;
828
+ cells.forEach((cell, colIndex) => {
829
+ if (cell) cell._updateIndices(newRowIndex, colIndex);
830
+ });
831
+ });
832
+ }
833
+ /**
834
+ * @internal
835
+ * Used internally to shift cell cache after deleting columns.
836
+ * Should not be called directly.
837
+ * */
838
+ _shiftCellCacheColumns(startIndex, endIndex) {
839
+ const numDeleted = endIndex - startIndex;
840
+ this._cells.forEach((row, rowIndex) => {
841
+ if (!row) return;
842
+ for (let colIndex = startIndex; colIndex < endIndex; colIndex++) {
843
+ const cell = row[colIndex];
844
+ if (cell) cell._markDeleted();
845
+ delete row[colIndex];
846
+ }
847
+ const cellsToShift = [];
848
+ for (let colIndex = endIndex; colIndex < row.length; colIndex++) if (row[colIndex]) cellsToShift.push({
849
+ oldColIndex: colIndex,
850
+ cell: row[colIndex]
851
+ });
852
+ cellsToShift.forEach(({ oldColIndex, cell }) => {
853
+ delete row[oldColIndex];
854
+ const newColIndex = oldColIndex - numDeleted;
855
+ row[newColIndex] = cell;
856
+ cell._updateIndices(rowIndex, newColIndex);
857
+ });
858
+ });
859
+ }
745
860
  async clearRows(options) {
746
861
  const startRowIndex = options?.start || this._headerRowIndex + 1;
747
862
  const endRowIndex = options?.end || this.rowCount;
@@ -766,12 +881,13 @@ var GoogleSpreadsheetWorksheet = class {
766
881
  async updateGridProperties(gridProperties) {
767
882
  return this.updateProperties({ gridProperties });
768
883
  }
769
- /** resize, internally just calls updateGridProperties */
884
+ /**
885
+ * resize, internally just calls updateGridProperties
886
+ */
770
887
  async resize(gridProperties) {
771
888
  return this.updateGridProperties(gridProperties);
772
889
  }
773
890
  /**
774
- *
775
891
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#updatedimensionpropertiesrequest
776
892
  */
777
893
  async updateDimensionProperties(columnsOrRows, properties, bounds) {
@@ -792,15 +908,96 @@ var GoogleSpreadsheetWorksheet = class {
792
908
  const ranges = a1Ranges.map((r) => `ranges=${this.encodedA1SheetName}!${r}`).join("&");
793
909
  return (await (await this._spreadsheet.sheetsApi.get(`values:batchGet?${ranges}`, { searchParams: options })).json()).valueRanges.map((r) => r.values);
794
910
  }
795
- async updateNamedRange() {}
796
- async addNamedRange() {}
797
- async deleteNamedRange() {}
798
- async repeatCell() {}
799
- async autoFill() {}
800
- async cutPaste() {}
801
- async copyPaste() {}
911
+ /**
912
+ * Updates an existing named range
913
+ *
914
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateNamedRangeRequest
915
+ */
916
+ async updateNamedRange(namedRangeId, namedRange, fields) {
917
+ return this._makeSingleUpdateRequest("updateNamedRange", {
918
+ namedRange: {
919
+ namedRangeId,
920
+ ...namedRange.name && { name: namedRange.name },
921
+ ...namedRange.range && { range: this._addSheetIdToRange(namedRange.range) }
922
+ },
923
+ fields
924
+ });
925
+ }
926
+ /**
927
+ * Creates a new named range in this worksheet (convenience method that auto-fills sheetId)
928
+ *
929
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddNamedRangeRequest
930
+ */
931
+ async addNamedRange(name, range, namedRangeId) {
932
+ return this._spreadsheet.addNamedRange(name, this._addSheetIdToRange(range), namedRangeId);
933
+ }
934
+ /**
935
+ * Deletes a named range (convenience wrapper)
936
+ *
937
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteNamedRangeRequest
938
+ */
939
+ async deleteNamedRange(namedRangeId) {
940
+ return this._spreadsheet.deleteNamedRange(namedRangeId);
941
+ }
942
+ /**
943
+ * Updates all cells in a range with the same cell data
944
+ *
945
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#RepeatCellRequest
946
+ */
947
+ async repeatCell(range, cell, fields) {
948
+ await this._makeSingleUpdateRequest("repeatCell", {
949
+ range: this._addSheetIdToRange(range),
950
+ cell,
951
+ fields
952
+ });
953
+ }
954
+ /**
955
+ * Auto-fills cells with data following a pattern (like dragging the fill handle)
956
+ *
957
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AutoFillRequest
958
+ */
959
+ async autoFill(rangeOrSource, useAlternateSeries) {
960
+ const isSourceAndDestination = "dimension" in rangeOrSource;
961
+ await this._makeSingleUpdateRequest("autoFill", {
962
+ ...isSourceAndDestination ? { sourceAndDestination: {
963
+ ...rangeOrSource,
964
+ source: this._addSheetIdToRange(rangeOrSource.source)
965
+ } } : { range: this._addSheetIdToRange(rangeOrSource) },
966
+ ...useAlternateSeries !== void 0 && { useAlternateSeries }
967
+ });
968
+ }
969
+ /**
970
+ * Cuts data from a source range and pastes it to a destination coordinate
971
+ *
972
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CutPasteRequest
973
+ */
974
+ async cutPaste(source, destination, pasteType = "PASTE_NORMAL") {
975
+ await this._makeSingleUpdateRequest("cutPaste", {
976
+ source: this._addSheetIdToRange(source),
977
+ destination: {
978
+ sheetId: this.sheetId,
979
+ rowIndex: destination.rowIndex,
980
+ columnIndex: destination.columnIndex
981
+ },
982
+ pasteType
983
+ });
984
+ }
985
+ /**
986
+ * Copies data from a source range and pastes it to a destination range
987
+ *
988
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CopyPasteRequest
989
+ */
990
+ async copyPaste(source, destination, pasteType = "PASTE_NORMAL", pasteOrientation = "NORMAL") {
991
+ await this._makeSingleUpdateRequest("copyPaste", {
992
+ source: this._addSheetIdToRange(source),
993
+ destination: this._addSheetIdToRange(destination),
994
+ pasteType,
995
+ pasteOrientation
996
+ });
997
+ }
802
998
  /**
803
999
  * Merges all cells in the range
1000
+ *
804
1001
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#MergeCellsRequest
805
1002
  */
806
1003
  async mergeCells(range, mergeType = "MERGE_ALL") {
@@ -811,21 +1008,114 @@ var GoogleSpreadsheetWorksheet = class {
811
1008
  }
812
1009
  /**
813
1010
  * Unmerges cells in the given range
1011
+ *
814
1012
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UnmergeCellsRequest
815
1013
  */
816
1014
  async unmergeCells(range) {
817
1015
  await this._makeSingleUpdateRequest("unmergeCells", { range: this._addSheetIdToRange(range) });
818
1016
  }
819
- async updateBorders() {}
820
- async addFilterView() {}
821
- async appendCells() {}
822
- async clearBasicFilter() {}
823
- async deleteDimension() {}
824
- async deleteEmbeddedObject() {}
825
- async deleteFilterView() {}
826
- async duplicateFilterView() {}
1017
+ /**
1018
+ * Updates borders for a range
1019
+ *
1020
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateBordersRequest
1021
+ */
1022
+ async updateBorders(range, borders) {
1023
+ await this._makeSingleUpdateRequest("updateBorders", {
1024
+ range: this._addSheetIdToRange(range),
1025
+ ...borders
1026
+ });
1027
+ }
1028
+ /**
1029
+ * Adds a filter view to the sheet
1030
+ *
1031
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddFilterViewRequest
1032
+ */
1033
+ async addFilterView(filter) {
1034
+ return this._makeSingleUpdateRequest("addFilterView", { filter });
1035
+ }
1036
+ /**
1037
+ * Appends cells after the last row with data in a sheet
1038
+ *
1039
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AppendCellsRequest
1040
+ */
1041
+ async appendCells(rows, fields) {
1042
+ await this._makeSingleUpdateRequest("appendCells", {
1043
+ sheetId: this.sheetId,
1044
+ rows,
1045
+ fields
1046
+ });
1047
+ }
1048
+ /**
1049
+ * Clears the basic filter on this sheet
1050
+ *
1051
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#ClearBasicFilterRequest
1052
+ */
1053
+ async clearBasicFilter() {
1054
+ await this._makeSingleUpdateRequest("clearBasicFilter", { sheetId: this.sheetId });
1055
+ }
1056
+ /**
1057
+ * Delete rows or columns in a given range
1058
+ *
1059
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDimensionRequest
1060
+ */
1061
+ async deleteDimension(columnsOrRows, rangeIndexes) {
1062
+ if (!columnsOrRows) throw new Error("You need to specify a dimension. i.e. COLUMNS|ROWS");
1063
+ if (!isObject(rangeIndexes)) throw new Error("`range` must be an object containing `startIndex` and `endIndex`");
1064
+ if (!isInteger(rangeIndexes.startIndex) || rangeIndexes.startIndex < 0) throw new Error("range.startIndex must be an integer >=0");
1065
+ if (!isInteger(rangeIndexes.endIndex) || rangeIndexes.endIndex < 0) throw new Error("range.endIndex must be an integer >=0");
1066
+ if (rangeIndexes.endIndex <= rangeIndexes.startIndex) throw new Error("range.endIndex must be greater than range.startIndex");
1067
+ const result = await this._makeSingleUpdateRequest("deleteDimension", { range: {
1068
+ sheetId: this.sheetId,
1069
+ dimension: columnsOrRows,
1070
+ startIndex: rangeIndexes.startIndex,
1071
+ endIndex: rangeIndexes.endIndex
1072
+ } });
1073
+ if (columnsOrRows === "ROWS") {
1074
+ this._shiftRowCacheBulk(rangeIndexes.startIndex, rangeIndexes.endIndex);
1075
+ this._shiftCellCacheRows(rangeIndexes.startIndex, rangeIndexes.endIndex);
1076
+ } else this._shiftCellCacheColumns(rangeIndexes.startIndex, rangeIndexes.endIndex);
1077
+ return result;
1078
+ }
1079
+ /**
1080
+ * Delete rows by index
1081
+ */
1082
+ async deleteRows(startIndex, endIndex) {
1083
+ return this.deleteDimension("ROWS", {
1084
+ startIndex,
1085
+ endIndex
1086
+ });
1087
+ }
1088
+ /**
1089
+ * Delete columns by index
1090
+ */
1091
+ async deleteColumns(startIndex, endIndex) {
1092
+ return this.deleteDimension("COLUMNS", {
1093
+ startIndex,
1094
+ endIndex
1095
+ });
1096
+ }
1097
+ async deleteEmbeddedObject() {
1098
+ throw new Error("Not implemented yet");
1099
+ }
1100
+ /**
1101
+ * Deletes a filter view from the sheet
1102
+ *
1103
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteFilterViewRequest
1104
+ */
1105
+ async deleteFilterView(filterId) {
1106
+ await this._makeSingleUpdateRequest("deleteFilterView", { filterId });
1107
+ }
1108
+ /**
1109
+ * Duplicates a filter view
1110
+ *
1111
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DuplicateFilterViewRequest
1112
+ */
1113
+ async duplicateFilterView(filterId) {
1114
+ await this._makeSingleUpdateRequest("duplicateFilterView", { filterId });
1115
+ }
827
1116
  /**
828
1117
  * Duplicate worksheet within the document
1118
+ *
829
1119
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DuplicateSheetRequest
830
1120
  */
831
1121
  async duplicate(options) {
@@ -837,9 +1127,22 @@ var GoogleSpreadsheetWorksheet = class {
837
1127
  })).properties.sheetId;
838
1128
  return this._spreadsheet.sheetsById[newSheetId];
839
1129
  }
840
- async findReplace() {}
1130
+ /**
1131
+ * Finds and replaces text in cells
1132
+ *
1133
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#FindReplaceRequest
1134
+ */
1135
+ async findReplace(find, replacement, options, range) {
1136
+ await this._makeSingleUpdateRequest("findReplace", {
1137
+ find,
1138
+ replacement,
1139
+ ...options,
1140
+ ...range ? { range: this._addSheetIdToRange(range) } : { sheetId: this.sheetId }
1141
+ });
1142
+ }
841
1143
  /**
842
1144
  * Inserts rows or columns at a particular index
1145
+ *
843
1146
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#InsertDimensionRequest
844
1147
  */
845
1148
  async insertDimension(columnsOrRows, rangeIndexes, inheritFromBefore) {
@@ -862,27 +1165,143 @@ var GoogleSpreadsheetWorksheet = class {
862
1165
  }
863
1166
  /**
864
1167
  * insert empty cells in a range, shifting existing cells in the specified direction
1168
+ *
865
1169
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#InsertRangeRequest
866
1170
  */
867
1171
  async insertRange(range, shiftDimension) {
868
- return this._makeSingleUpdateRequest("insertRange", {
1172
+ await this._makeSingleUpdateRequest("insertRange", {
1173
+ range: this._addSheetIdToRange(range),
1174
+ shiftDimension
1175
+ });
1176
+ }
1177
+ /**
1178
+ * Moves rows or columns to a different position within the sheet
1179
+ *
1180
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#MoveDimensionRequest
1181
+ */
1182
+ async moveDimension(dimension, source, destinationIndex) {
1183
+ await this._makeSingleUpdateRequest("moveDimension", {
1184
+ source: {
1185
+ sheetId: this.sheetId,
1186
+ dimension,
1187
+ startIndex: source.startIndex,
1188
+ endIndex: source.endIndex
1189
+ },
1190
+ destinationIndex
1191
+ });
1192
+ }
1193
+ async updateEmbeddedObjectPosition() {
1194
+ throw new Error("Not implemented yet");
1195
+ }
1196
+ /**
1197
+ * Inserts data into the spreadsheet starting at the specified coordinate
1198
+ *
1199
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#PasteDataRequest
1200
+ */
1201
+ async pasteData(coordinate, data, delimiter, type = "PASTE_NORMAL") {
1202
+ await this._makeSingleUpdateRequest("pasteData", {
1203
+ coordinate: {
1204
+ sheetId: this.sheetId,
1205
+ rowIndex: coordinate.rowIndex,
1206
+ columnIndex: coordinate.columnIndex
1207
+ },
1208
+ data,
1209
+ delimiter,
1210
+ type
1211
+ });
1212
+ }
1213
+ /**
1214
+ * Splits a column of text into multiple columns based on a delimiter
1215
+ *
1216
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#TextToColumnsRequest
1217
+ */
1218
+ async textToColumns(source, delimiterType, delimiter) {
1219
+ await this._makeSingleUpdateRequest("textToColumns", {
1220
+ source: this._addSheetIdToRange(source),
1221
+ delimiterType,
1222
+ ...delimiter && { delimiter }
1223
+ });
1224
+ }
1225
+ /**
1226
+ * Updates properties of a filter view
1227
+ *
1228
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateFilterViewRequest
1229
+ */
1230
+ async updateFilterView(filter, fields) {
1231
+ await this._makeSingleUpdateRequest("updateFilterView", {
1232
+ filter,
1233
+ fields
1234
+ });
1235
+ }
1236
+ /**
1237
+ * Deletes a range of cells and shifts remaining cells
1238
+ *
1239
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteRangeRequest
1240
+ */
1241
+ async deleteRange(range, shiftDimension) {
1242
+ await this._makeSingleUpdateRequest("deleteRange", {
869
1243
  range: this._addSheetIdToRange(range),
870
1244
  shiftDimension
871
1245
  });
872
1246
  }
873
- async moveDimension() {}
874
- async updateEmbeddedObjectPosition() {}
875
- async pasteData() {}
876
- async textToColumns() {}
877
- async updateFilterView() {}
878
- async deleteRange() {}
879
- async appendDimension() {}
880
- async addConditionalFormatRule() {}
881
- async updateConditionalFormatRule() {}
882
- async deleteConditionalFormatRule() {}
883
- async sortRange() {}
1247
+ /**
1248
+ * Appends rows or columns to the end of a sheet
1249
+ *
1250
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AppendDimensionRequest
1251
+ */
1252
+ async appendDimension(dimension, length) {
1253
+ await this._makeSingleUpdateRequest("appendDimension", {
1254
+ sheetId: this.sheetId,
1255
+ dimension,
1256
+ length
1257
+ });
1258
+ }
1259
+ /**
1260
+ * Adds a new conditional formatting rule at the given index
1261
+ * All subsequent rules' indexes are incremented
1262
+ *
1263
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddConditionalFormatRuleRequest
1264
+ */
1265
+ async addConditionalFormatRule(rule, index) {
1266
+ await this._makeSingleUpdateRequest("addConditionalFormatRule", {
1267
+ rule,
1268
+ index
1269
+ });
1270
+ }
1271
+ /**
1272
+ * Updates a conditional format rule at the given index, or moves a conditional format rule to another index
1273
+ *
1274
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateConditionalFormatRuleRequest
1275
+ */
1276
+ async updateConditionalFormatRule(options) {
1277
+ await this._makeSingleUpdateRequest("updateConditionalFormatRule", options);
1278
+ }
1279
+ /**
1280
+ * Deletes a conditional format rule at the given index
1281
+ * All subsequent rules' indexes are decremented
1282
+ *
1283
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteConditionalFormatRuleRequest
1284
+ */
1285
+ async deleteConditionalFormatRule(index, sheetId) {
1286
+ await this._makeSingleUpdateRequest("deleteConditionalFormatRule", {
1287
+ index,
1288
+ sheetId: sheetId ?? this.sheetId
1289
+ });
1290
+ }
1291
+ /**
1292
+ * Sorts data in rows based on sort order per column
1293
+ *
1294
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SortRangeRequest
1295
+ */
1296
+ async sortRange(range, sortSpecs) {
1297
+ await this._makeSingleUpdateRequest("sortRange", {
1298
+ range: this._addSheetIdToRange(range),
1299
+ sortSpecs
1300
+ });
1301
+ }
884
1302
  /**
885
1303
  * Sets (or unsets) a data validation rule to every cell in the range
1304
+ *
886
1305
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SetDataValidationRequest
887
1306
  */
888
1307
  async setDataValidation(range, rule) {
@@ -894,9 +1313,20 @@ var GoogleSpreadsheetWorksheet = class {
894
1313
  ...rule && { rule }
895
1314
  });
896
1315
  }
897
- async setBasicFilter() {}
1316
+ /**
1317
+ * Sets the basic filter on this sheet
1318
+ *
1319
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SetBasicFilterRequest
1320
+ */
1321
+ async setBasicFilter(filter) {
1322
+ await this._makeSingleUpdateRequest("setBasicFilter", { filter: {
1323
+ ...filter,
1324
+ ...filter.range && { range: this._addSheetIdToRange(filter.range) }
1325
+ } });
1326
+ }
898
1327
  /**
899
1328
  * add a new protected range to the sheet
1329
+ *
900
1330
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddProtectedRangeRequest
901
1331
  */
902
1332
  async addProtectedRange(protectedRange) {
@@ -905,6 +1335,7 @@ var GoogleSpreadsheetWorksheet = class {
905
1335
  }
906
1336
  /**
907
1337
  * update an existing protected range
1338
+ *
908
1339
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateProtectedRangeRequest
909
1340
  */
910
1341
  async updateProtectedRange(protectedRangeId, protectedRange) {
@@ -918,6 +1349,7 @@ var GoogleSpreadsheetWorksheet = class {
918
1349
  }
919
1350
  /**
920
1351
  * delete a protected range by ID
1352
+ *
921
1353
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteProtectedRangeRequest
922
1354
  */
923
1355
  async deleteProtectedRange(protectedRangeId) {
@@ -925,6 +1357,7 @@ var GoogleSpreadsheetWorksheet = class {
925
1357
  }
926
1358
  /**
927
1359
  * auto-resize rows or columns to fit their contents
1360
+ *
928
1361
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AutoResizeDimensionsRequest
929
1362
  */
930
1363
  async autoResizeDimensions(columnsOrRows, rangeIndexes) {
@@ -934,34 +1367,126 @@ var GoogleSpreadsheetWorksheet = class {
934
1367
  ...rangeIndexes
935
1368
  } });
936
1369
  }
937
- async addChart() {}
938
- async updateChartSpec() {}
939
- async updateBanding() {}
940
- async addBanding() {}
941
- async deleteBanding() {}
942
- async createDeveloperMetadata() {}
943
- async updateDeveloperMetadata() {}
944
- async deleteDeveloperMetadata() {}
945
- async randomizeRange() {}
946
- async addDimensionGroup() {}
947
- async deleteDimensionGroup() {}
948
- async updateDimensionGroup() {}
949
- async trimWhitespace() {}
950
- async deleteDuplicates() {}
951
- async addSlicer() {}
952
- async updateSlicerSpec() {}
953
- /** delete this worksheet */
1370
+ async addChart() {
1371
+ throw new Error("Not implemented yet");
1372
+ }
1373
+ async updateChartSpec() {
1374
+ throw new Error("Not implemented yet");
1375
+ }
1376
+ /**
1377
+ * Updates properties of a banded range
1378
+ *
1379
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateBandingRequest
1380
+ */
1381
+ async updateBanding(bandedRange, fields) {
1382
+ await this._makeSingleUpdateRequest("updateBanding", {
1383
+ bandedRange,
1384
+ fields
1385
+ });
1386
+ }
1387
+ /**
1388
+ * Adds a new banded range to the sheet
1389
+ *
1390
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddBandingRequest
1391
+ */
1392
+ async addBanding(bandedRange) {
1393
+ return this._makeSingleUpdateRequest("addBanding", { bandedRange });
1394
+ }
1395
+ /**
1396
+ * Deletes a banded range from the sheet
1397
+ *
1398
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteBandingRequest
1399
+ */
1400
+ async deleteBanding(bandedRangeId) {
1401
+ await this._makeSingleUpdateRequest("deleteBanding", { bandedRangeId });
1402
+ }
1403
+ /**
1404
+ * Creates developer metadata
1405
+ *
1406
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CreateDeveloperMetadataRequest
1407
+ */
1408
+ async createDeveloperMetadata(developerMetadata) {
1409
+ return this._makeSingleUpdateRequest("createDeveloperMetadata", { developerMetadata });
1410
+ }
1411
+ /**
1412
+ * Updates developer metadata that matches the specified filters
1413
+ *
1414
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateDeveloperMetadataRequest
1415
+ */
1416
+ async updateDeveloperMetadata(dataFilters, developerMetadata, fields) {
1417
+ await this._makeSingleUpdateRequest("updateDeveloperMetadata", {
1418
+ dataFilters,
1419
+ developerMetadata,
1420
+ fields
1421
+ });
1422
+ }
1423
+ /**
1424
+ * Deletes developer metadata that matches the specified filter
1425
+ *
1426
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDeveloperMetadataRequest
1427
+ */
1428
+ async deleteDeveloperMetadata(dataFilter) {
1429
+ await this._makeSingleUpdateRequest("deleteDeveloperMetadata", { dataFilter });
1430
+ }
1431
+ /**
1432
+ * Randomizes the order of rows in a range
1433
+ *
1434
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#RandomizeRangeRequest
1435
+ */
1436
+ async randomizeRange(range) {
1437
+ await this._makeSingleUpdateRequest("randomizeRange", { range: this._addSheetIdToRange(range) });
1438
+ }
1439
+ async addDimensionGroup() {
1440
+ throw new Error("Not implemented yet");
1441
+ }
1442
+ async deleteDimensionGroup() {
1443
+ throw new Error("Not implemented yet");
1444
+ }
1445
+ async updateDimensionGroup() {
1446
+ throw new Error("Not implemented yet");
1447
+ }
1448
+ /**
1449
+ * Trims whitespace from the start and end of each cell's text
1450
+ *
1451
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#TrimWhitespaceRequest
1452
+ */
1453
+ async trimWhitespace(range) {
1454
+ await this._makeSingleUpdateRequest("trimWhitespace", { range: this._addSheetIdToRange(range) });
1455
+ }
1456
+ /**
1457
+ * Removes duplicate rows from a range based on specified columns
1458
+ *
1459
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDuplicatesRequest
1460
+ */
1461
+ async deleteDuplicates(range, comparisonColumns) {
1462
+ await this._makeSingleUpdateRequest("deleteDuplicates", {
1463
+ range: this._addSheetIdToRange(range),
1464
+ ...comparisonColumns && { comparisonColumns }
1465
+ });
1466
+ }
1467
+ async addSlicer() {
1468
+ throw new Error("Not implemented yet");
1469
+ }
1470
+ async updateSlicerSpec() {
1471
+ throw new Error("Not implemented yet");
1472
+ }
1473
+ /**
1474
+ * delete this worksheet
1475
+ */
954
1476
  async delete() {
955
1477
  return this._spreadsheet.deleteSheet(this.sheetId);
956
1478
  }
957
1479
  /**
958
1480
  * copies this worksheet into another document/spreadsheet
1481
+ *
959
1482
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.sheets/copyTo
960
- * */
1483
+ */
961
1484
  async copyToSpreadsheet(destinationSpreadsheetId) {
962
1485
  return await this._spreadsheet.sheetsApi.post(`sheets/${this.sheetId}:copyTo`, { json: { destinationSpreadsheetId } }).json();
963
1486
  }
964
- /** clear data in the sheet - either the entire sheet or a specific range */
1487
+ /**
1488
+ * clear data in the sheet - either the entire sheet or a specific range
1489
+ */
965
1490
  async clear(a1Range) {
966
1491
  const range = a1Range ? `!${a1Range}` : "";
967
1492
  await this._spreadsheet.sheetsApi.post(`values/${this.encodedA1SheetName}${range}:clear`);
@@ -1054,7 +1579,8 @@ var GoogleSpreadsheet = class GoogleSpreadsheet {
1054
1579
  * initialize new GoogleSpreadsheet
1055
1580
  * @category Initialization
1056
1581
  * */
1057
- constructor(spreadsheetId, auth) {
1582
+ constructor(spreadsheetId, auth, options) {
1583
+ const { retryConfig } = options || {};
1058
1584
  this.spreadsheetId = spreadsheetId;
1059
1585
  this.auth = auth;
1060
1586
  this._rawSheets = {};
@@ -1065,14 +1591,16 @@ var GoogleSpreadsheet = class GoogleSpreadsheet {
1065
1591
  hooks: {
1066
1592
  beforeRequest: [(r) => this._setAuthRequestHook(r)],
1067
1593
  beforeError: [(e) => this._errorHook(e)]
1068
- }
1594
+ },
1595
+ retry: retryConfig
1069
1596
  });
1070
1597
  this.driveApi = ky.create({
1071
1598
  prefixUrl: `${DRIVE_API_BASE_URL}/${spreadsheetId}`,
1072
1599
  hooks: {
1073
1600
  beforeRequest: [(r) => this._setAuthRequestHook(r)],
1074
1601
  beforeError: [(e) => this._errorHook(e)]
1075
- }
1602
+ },
1603
+ retry: retryConfig
1076
1604
  });
1077
1605
  }
1078
1606
  /** @internal */
@@ -1252,6 +1780,7 @@ var GoogleSpreadsheet = class GoogleSpreadsheet {
1252
1780
  if (isString(filter)) return readOnlyMode ? filter : { a1Range: filter };
1253
1781
  if (isObject(filter)) {
1254
1782
  if (readOnlyMode) throw new Error("Only A1 ranges are supported when fetching cells with read-only access (using only an API key)");
1783
+ if ("developerMetadataLookup" in filter) return { developerMetadataLookup: filter.developerMetadataLookup };
1255
1784
  return { gridRange: filter };
1256
1785
  }
1257
1786
  throw new Error("Each filter must be an A1 range string or a gridrange object");
@@ -1366,6 +1895,15 @@ var GoogleSpreadsheet = class GoogleSpreadsheet {
1366
1895
  async deletePermission(permissionId) {
1367
1896
  await this.driveApi.delete(`permissions/${permissionId}`);
1368
1897
  }
1898
+ /**
1899
+ * search for developer metadata entries matching the given filters
1900
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.developerMetadata/search
1901
+ */
1902
+ async searchDeveloperMetadata(filters) {
1903
+ const data = await (await this.sheetsApi.post("developerMetadata:search", { json: { dataFilters: filters } })).json();
1904
+ if (!data.matchedDeveloperMetadata) return [];
1905
+ return data.matchedDeveloperMetadata.map((m) => m.developerMetadata);
1906
+ }
1369
1907
  static async createNewSpreadsheetDocument(auth, properties) {
1370
1908
  if (getAuthMode(auth) === AUTH_MODES.API_KEY) throw new Error("Cannot use api key only to create a new spreadsheet - it is only usable for read-only access of public docs");
1371
1909
  const authConfig = await getRequestAuthConfig(auth);