google-spreadsheet 5.0.2 → 5.1.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.
@@ -13,6 +13,9 @@ import {
13
13
  RowIndex, ColumnIndex, DataFilterWithoutWorksheetId, DataFilter, GetValuesRequestOptions, WorksheetGridProperties,
14
14
  WorksheetDimensionProperties, CellDataRange, AddRowOptions, GridRangeWithOptionalWorksheetId,
15
15
  DataValidationRule,
16
+ ProtectedRange, Integer, GridCoordinateWithOptionalWorksheetId, PasteType, DelimiterType, PasteOrientation,
17
+ SortSpec, SourceAndDestination, DimensionRange,
18
+ FilterView, ConditionalFormatRule, BandedRange, DeveloperMetadata, DataFilterObject,
16
19
  } from './types/sheets-types';
17
20
 
18
21
 
@@ -29,6 +32,7 @@ export class GoogleSpreadsheetWorksheet {
29
32
  private _cells: GoogleSpreadsheetCell[][] = [];
30
33
  private _rowMetadata: any[] = [];
31
34
  private _columnMetadata: any[] = [];
35
+ private _protectedRanges: ProtectedRange[] | null = null;
32
36
 
33
37
  private _headerValues: string[] | undefined;
34
38
  get headerValues() {
@@ -42,7 +46,8 @@ export class GoogleSpreadsheetWorksheet {
42
46
  /** parent GoogleSpreadsheet instance */
43
47
  readonly _spreadsheet: GoogleSpreadsheet,
44
48
  rawProperties: WorksheetProperties,
45
- rawCellData?: CellDataRange[]
49
+ rawCellData?: CellDataRange[],
50
+ protectedRanges?: ProtectedRange[]
46
51
  ) {
47
52
  this._headerRowIndex = 1;
48
53
 
@@ -53,15 +58,17 @@ export class GoogleSpreadsheetWorksheet {
53
58
 
54
59
  this._rowMetadata = []; // 1d sparse array
55
60
  this._columnMetadata = [];
61
+ if (protectedRanges) this._protectedRanges = protectedRanges;
56
62
 
57
63
  if (rawCellData) this._fillCellData(rawCellData);
58
64
  }
59
65
 
60
66
  // INTERNAL UTILITY FUNCTIONS ////////////////////////////////////////////////////////////////////
61
67
 
62
- updateRawData(properties: WorksheetProperties, rawCellData: CellDataRange[]) {
68
+ updateRawData(properties: WorksheetProperties, rawCellData: CellDataRange[], protectedRanges?: ProtectedRange[]) {
63
69
  this._rawProperties = properties;
64
70
  this._fillCellData(rawCellData);
71
+ if (protectedRanges) this._protectedRanges = protectedRanges;
65
72
  }
66
73
 
67
74
  async _makeSingleUpdateRequest(requestType: string, requestParams: any) {
@@ -77,7 +84,9 @@ export class GoogleSpreadsheetWorksheet {
77
84
  }
78
85
  }
79
86
 
80
- /** clear local cache of sheet data/properties */
87
+ /**
88
+ * clear local cache of sheet data/properties
89
+ */
81
90
  resetLocalCache(
82
91
  /** set to true to clear data only, leaving sheet metadata/propeties intact */
83
92
  dataOnly?: boolean
@@ -166,6 +175,7 @@ export class GoogleSpreadsheetWorksheet {
166
175
  get hidden() { return this._getProp('hidden'); }
167
176
  get tabColor() { return this._getProp('tabColor'); }
168
177
  get rightToLeft() { return this._getProp('rightToLeft'); }
178
+ get protectedRanges() { return this._protectedRanges; }
169
179
  private get _headerRange() {
170
180
  return `A${this._headerRowIndex}:${this.lastColumnLetter}${this._headerRowIndex}`;
171
181
  }
@@ -474,8 +484,13 @@ export class GoogleSpreadsheetWorksheet {
474
484
  });
475
485
  }
476
486
 
477
- /** add a single row - see addRows for more info */
478
- async addRow(rowValues: RawRowData, options?: AddRowOptions) {
487
+ /**
488
+ * add a single row - see addRows for more info
489
+ */
490
+ async addRow(
491
+ rowValues: RawRowData,
492
+ options?: AddRowOptions
493
+ ) {
479
494
  const rows = await this.addRows([rowValues], options);
480
495
  return rows[0];
481
496
  }
@@ -542,6 +557,111 @@ export class GoogleSpreadsheetWorksheet {
542
557
  });
543
558
  }
544
559
 
560
+ /**
561
+ * @internal
562
+ * Used internally to update row numbers after deleting multiple rows.
563
+ * Should not be called directly.
564
+ * */
565
+ _shiftRowCacheBulk(startIndex: number, endIndex: number) {
566
+ const numDeleted = endIndex - startIndex;
567
+ // Convert from 0-based indices to 1-based row numbers
568
+ const startRow = startIndex + 1;
569
+ const endRow = endIndex;
570
+
571
+ // Mark rows in the deleted range as deleted, then remove from cache
572
+ for (let rowNum = startRow; rowNum <= endRow; rowNum++) {
573
+ const row = this._rowCache[rowNum];
574
+ if (row) {
575
+ row._markDeleted(); // Mark as deleted
576
+ }
577
+ delete this._rowCache[rowNum];
578
+ }
579
+
580
+ // Shift rows after the deleted range
581
+ this._rowCache.forEach((row) => {
582
+ if (row.rowNumber > endRow) {
583
+ row._updateRowNumber(row.rowNumber - numDeleted);
584
+ }
585
+ });
586
+ }
587
+
588
+ /**
589
+ * @internal
590
+ * Used internally to shift cell cache after deleting rows.
591
+ * Should not be called directly.
592
+ * */
593
+ _shiftCellCacheRows(startIndex: number, endIndex: number) {
594
+ const numDeleted = endIndex - startIndex;
595
+
596
+ // Mark cells in the deleted row range as deleted, then remove from cache
597
+ for (let rowIndex = startIndex; rowIndex < endIndex; rowIndex++) {
598
+ const row = this._cells[rowIndex];
599
+ if (row) {
600
+ row.forEach((cell) => {
601
+ if (cell) cell._markDeleted();
602
+ });
603
+ }
604
+ delete this._cells[rowIndex];
605
+ }
606
+
607
+ // Collect rows that need to be shifted
608
+ const rowsToShift: Array<{ oldRowIndex: number, cells: any[] }> = [];
609
+ for (let rowIndex = endIndex; rowIndex < this._cells.length; rowIndex++) {
610
+ if (this._cells[rowIndex]) {
611
+ rowsToShift.push({ oldRowIndex: rowIndex, cells: this._cells[rowIndex] });
612
+ }
613
+ }
614
+
615
+ // Clear old positions and update to new positions
616
+ rowsToShift.forEach(({ oldRowIndex, cells }) => {
617
+ delete this._cells[oldRowIndex];
618
+ const newRowIndex = oldRowIndex - numDeleted;
619
+ this._cells[newRowIndex] = cells;
620
+ // Update each cell's internal row index
621
+ cells.forEach((cell, colIndex) => {
622
+ if (cell) cell._updateIndices(newRowIndex, colIndex);
623
+ });
624
+ });
625
+ }
626
+
627
+ /**
628
+ * @internal
629
+ * Used internally to shift cell cache after deleting columns.
630
+ * Should not be called directly.
631
+ * */
632
+ _shiftCellCacheColumns(startIndex: number, endIndex: number) {
633
+ const numDeleted = endIndex - startIndex;
634
+
635
+ // For each row, delete cells in the deleted column range and shift remaining
636
+ this._cells.forEach((row, rowIndex) => {
637
+ if (!row) return;
638
+
639
+ // Mark cells in the deleted column range as deleted, then remove from cache
640
+ for (let colIndex = startIndex; colIndex < endIndex; colIndex++) {
641
+ const cell = row[colIndex];
642
+ if (cell) cell._markDeleted();
643
+ delete row[colIndex];
644
+ }
645
+
646
+ // Collect cells that need to be shifted
647
+ const cellsToShift: Array<{ oldColIndex: number, cell: any }> = [];
648
+ for (let colIndex = endIndex; colIndex < row.length; colIndex++) {
649
+ if (row[colIndex]) {
650
+ cellsToShift.push({ oldColIndex: colIndex, cell: row[colIndex] });
651
+ }
652
+ }
653
+
654
+ // Clear old positions and update to new positions
655
+ cellsToShift.forEach(({ oldColIndex, cell }) => {
656
+ delete row[oldColIndex];
657
+ const newColIndex = oldColIndex - numDeleted;
658
+ row[newColIndex] = cell;
659
+ // Update cell's internal column index
660
+ cell._updateIndices(rowIndex, newColIndex);
661
+ });
662
+ });
663
+ }
664
+
545
665
  async clearRows(
546
666
  options?: {
547
667
  start?: number,
@@ -574,17 +694,22 @@ export class GoogleSpreadsheetWorksheet {
574
694
  /**
575
695
  * passes through the call to updateProperties to update only the gridProperties object
576
696
  */
577
- async updateGridProperties(gridProperties: WorksheetGridProperties) {
578
- return this.updateProperties({ gridProperties });
697
+ async updateGridProperties(
698
+ gridProperties: Partial<WorksheetGridProperties>
699
+ ) {
700
+ return this.updateProperties({ gridProperties: gridProperties as WorksheetGridProperties });
579
701
  }
580
702
 
581
- /** resize, internally just calls updateGridProperties */
582
- async resize(gridProperties: Pick<WorksheetGridProperties, 'rowCount' | 'columnCount'>) {
703
+ /**
704
+ * resize, internally just calls updateGridProperties
705
+ */
706
+ async resize(
707
+ gridProperties: Pick<WorksheetGridProperties, 'rowCount' | 'columnCount'>
708
+ ) {
583
709
  return this.updateGridProperties(gridProperties);
584
710
  }
585
711
 
586
712
  /**
587
- *
588
713
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#updatedimensionpropertiesrequest
589
714
  */
590
715
  async updateDimensionProperties(
@@ -628,48 +753,166 @@ export class GoogleSpreadsheetWorksheet {
628
753
  return data.valueRanges.map((r: any) => r.values);
629
754
  }
630
755
 
631
- async updateNamedRange() {
632
- // Request type = `updateNamedRange`
633
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateNamedRangeRequest
756
+ /**
757
+ * Updates an existing named range
758
+ *
759
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateNamedRangeRequest
760
+ */
761
+ async updateNamedRange(
762
+ /** ID of the named range to update */
763
+ namedRangeId: string,
764
+ /** The named range properties to update */
765
+ namedRange: Partial<{ name: string, range: GridRangeWithOptionalWorksheetId }>,
766
+ /** Field mask specifying which properties to update */
767
+ fields: string
768
+ ) {
769
+ return this._makeSingleUpdateRequest('updateNamedRange', {
770
+ namedRange: {
771
+ namedRangeId,
772
+ ...namedRange.name && { name: namedRange.name },
773
+ ...namedRange.range && { range: this._addSheetIdToRange(namedRange.range) },
774
+ },
775
+ fields,
776
+ });
634
777
  }
635
778
 
636
- async addNamedRange() {
637
- // Request type = `addNamedRange`
638
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddNamedRangeRequest
779
+ /**
780
+ * Creates a new named range in this worksheet (convenience method that auto-fills sheetId)
781
+ *
782
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddNamedRangeRequest
783
+ */
784
+ async addNamedRange(
785
+ /** Name of the new named range */
786
+ name: string,
787
+ /** GridRange describing the range (sheetId optional, will be auto-filled) */
788
+ range: GridRangeWithOptionalWorksheetId,
789
+ /** Optional ID for the named range */
790
+ namedRangeId?: string
791
+ ) {
792
+ return this._spreadsheet.addNamedRange(
793
+ name,
794
+ this._addSheetIdToRange(range),
795
+ namedRangeId
796
+ );
639
797
  }
640
798
 
641
- async deleteNamedRange() {
642
- // Request type = `deleteNamedRange`
643
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteNamedRangeRequest
799
+ /**
800
+ * Deletes a named range (convenience wrapper)
801
+ *
802
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteNamedRangeRequest
803
+ */
804
+ async deleteNamedRange(
805
+ /** ID of the named range to delete */
806
+ namedRangeId: string
807
+ ) {
808
+ return this._spreadsheet.deleteNamedRange(namedRangeId);
644
809
  }
645
810
 
646
- async repeatCell() {
647
- // Request type = `repeatCell`
648
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#RepeatCellRequest
811
+ /**
812
+ * Updates all cells in a range with the same cell data
813
+ *
814
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#RepeatCellRequest
815
+ */
816
+ async repeatCell(
817
+ /** The range to update (sheetId optional) */
818
+ range: GridRangeWithOptionalWorksheetId,
819
+ /** The cell data to repeat across the range */
820
+ cell: any,
821
+ /** Which fields to update (use "*" for all fields) */
822
+ fields: string
823
+ ) {
824
+ await this._makeSingleUpdateRequest('repeatCell', {
825
+ range: this._addSheetIdToRange(range),
826
+ cell,
827
+ fields,
828
+ });
649
829
  }
650
830
 
651
- async autoFill() {
652
- // Request type = `autoFill`
653
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AutoFillRequest
831
+ /**
832
+ * Auto-fills cells with data following a pattern (like dragging the fill handle)
833
+ *
834
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AutoFillRequest
835
+ */
836
+ async autoFill(
837
+ /** The range to autofill (detects source location automatically, sheetId optional) or explicit source and destination specification */
838
+ rangeOrSource: GridRangeWithOptionalWorksheetId | SourceAndDestination,
839
+ /** Whether to generate data with the alternate series */
840
+ useAlternateSeries?: boolean
841
+ ) {
842
+ // Check if it's a SourceAndDestination by looking for the 'dimension' property
843
+ const isSourceAndDestination = 'dimension' in rangeOrSource;
844
+
845
+ await this._makeSingleUpdateRequest('autoFill', {
846
+ ...isSourceAndDestination
847
+ ? {
848
+ sourceAndDestination: {
849
+ ...rangeOrSource,
850
+ source: this._addSheetIdToRange((rangeOrSource as SourceAndDestination).source),
851
+ },
852
+ }
853
+ : { range: this._addSheetIdToRange(rangeOrSource as GridRangeWithOptionalWorksheetId) },
854
+ ...useAlternateSeries !== undefined && { useAlternateSeries },
855
+ });
654
856
  }
655
857
 
656
- async cutPaste() {
657
- // Request type = `cutPaste`
658
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CutPasteRequest
858
+ /**
859
+ * Cuts data from a source range and pastes it to a destination coordinate
860
+ *
861
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CutPasteRequest
862
+ */
863
+ async cutPaste(
864
+ /** The source range to cut from (sheetId optional) */
865
+ source: GridRangeWithOptionalWorksheetId,
866
+ /** The top-left coordinate where data should be pasted (sheetId optional) */
867
+ destination: GridCoordinateWithOptionalWorksheetId,
868
+ /** What kind of data to paste (defaults to PASTE_NORMAL) */
869
+ pasteType: PasteType = 'PASTE_NORMAL'
870
+ ) {
871
+ await this._makeSingleUpdateRequest('cutPaste', {
872
+ source: this._addSheetIdToRange(source),
873
+ destination: {
874
+ sheetId: this.sheetId,
875
+ rowIndex: destination.rowIndex,
876
+ columnIndex: destination.columnIndex,
877
+ },
878
+ pasteType,
879
+ });
659
880
  }
660
881
 
661
- async copyPaste() {
662
- // Request type = `copyPaste`
663
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CopyPasteRequest
882
+ /**
883
+ * Copies data from a source range and pastes it to a destination range
884
+ *
885
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CopyPasteRequest
886
+ */
887
+ async copyPaste(
888
+ /** The source range to copy from (sheetId optional) */
889
+ source: GridRangeWithOptionalWorksheetId,
890
+ /** The destination range to paste to (sheetId optional) */
891
+ destination: GridRangeWithOptionalWorksheetId,
892
+ /** What kind of data to paste (defaults to PASTE_NORMAL) */
893
+ pasteType: PasteType = 'PASTE_NORMAL',
894
+ /** How data should be oriented (defaults to NORMAL) */
895
+ pasteOrientation: PasteOrientation = 'NORMAL'
896
+ ) {
897
+ await this._makeSingleUpdateRequest('copyPaste', {
898
+ source: this._addSheetIdToRange(source),
899
+ destination: this._addSheetIdToRange(destination),
900
+ pasteType,
901
+ pasteOrientation,
902
+ });
664
903
  }
665
904
 
666
905
  // TODO: check types on these ranges
667
906
 
668
907
  /**
669
908
  * Merges all cells in the range
909
+ *
670
910
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#MergeCellsRequest
671
911
  */
672
- async mergeCells(range: GridRangeWithOptionalWorksheetId, mergeType = 'MERGE_ALL') {
912
+ async mergeCells(
913
+ range: GridRangeWithOptionalWorksheetId,
914
+ mergeType = 'MERGE_ALL'
915
+ ) {
673
916
  await this._makeSingleUpdateRequest('mergeCells', {
674
917
  mergeType,
675
918
  range: this._addSheetIdToRange(range),
@@ -678,56 +921,180 @@ export class GoogleSpreadsheetWorksheet {
678
921
 
679
922
  /**
680
923
  * Unmerges cells in the given range
924
+ *
681
925
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UnmergeCellsRequest
682
926
  */
683
- async unmergeCells(range: GridRangeWithOptionalWorksheetId) {
927
+ async unmergeCells(
928
+ range: GridRangeWithOptionalWorksheetId
929
+ ) {
684
930
  await this._makeSingleUpdateRequest('unmergeCells', {
685
931
  range: this._addSheetIdToRange(range),
686
932
  });
687
933
  }
688
934
 
689
- async updateBorders() {
690
- // Request type = `updateBorders`
691
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateBordersRequest
935
+ /**
936
+ * Updates borders for a range
937
+ *
938
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateBordersRequest
939
+ */
940
+ async updateBorders(
941
+ /** The range whose borders should be updated (sheetId optional) */
942
+ range: GridRangeWithOptionalWorksheetId,
943
+ /** Border styles for top, bottom, left, right, innerHorizontal, innerVertical */
944
+ borders: {
945
+ top?: any,
946
+ bottom?: any,
947
+ left?: any,
948
+ right?: any,
949
+ innerHorizontal?: any,
950
+ innerVertical?: any
951
+ }
952
+ ) {
953
+ await this._makeSingleUpdateRequest('updateBorders', {
954
+ range: this._addSheetIdToRange(range),
955
+ ...borders,
956
+ });
692
957
  }
693
958
 
694
- async addFilterView() {
695
- // Request type = `addFilterView`
696
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddFilterViewRequest
959
+ /**
960
+ * Adds a filter view to the sheet
961
+ *
962
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddFilterViewRequest
963
+ */
964
+ async addFilterView(
965
+ /** The filter view to add (filterViewId is optional and will be auto-generated if not provided) */
966
+ filter: FilterView
967
+ ) {
968
+ return this._makeSingleUpdateRequest('addFilterView', {
969
+ filter,
970
+ });
697
971
  }
698
972
 
699
- async appendCells() {
700
- // Request type = `appendCells`
701
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AppendCellsRequest
973
+ /**
974
+ * Appends cells after the last row with data in a sheet
975
+ *
976
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AppendCellsRequest
977
+ */
978
+ async appendCells(
979
+ /** The row data to append */
980
+ rows: any[],
981
+ /** Which fields to update (use "*" for all fields) */
982
+ fields: string
983
+ ) {
984
+ await this._makeSingleUpdateRequest('appendCells', {
985
+ sheetId: this.sheetId,
986
+ rows,
987
+ fields,
988
+ });
702
989
  }
703
990
 
991
+ /**
992
+ * Clears the basic filter on this sheet
993
+ *
994
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#ClearBasicFilterRequest
995
+ */
704
996
  async clearBasicFilter() {
705
- // Request type = `clearBasicFilter`
706
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#ClearBasicFilterRequest
997
+ await this._makeSingleUpdateRequest('clearBasicFilter', {
998
+ sheetId: this.sheetId,
999
+ });
1000
+ }
1001
+
1002
+ /**
1003
+ * Delete rows or columns in a given range
1004
+ *
1005
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDimensionRequest
1006
+ */
1007
+ async deleteDimension(
1008
+ columnsOrRows: WorksheetDimension,
1009
+ rangeIndexes: DimensionRangeIndexes
1010
+ ) {
1011
+ if (!columnsOrRows) throw new Error('You need to specify a dimension. i.e. COLUMNS|ROWS');
1012
+ if (!_.isObject(rangeIndexes)) throw new Error('`range` must be an object containing `startIndex` and `endIndex`');
1013
+ if (!_.isInteger(rangeIndexes.startIndex) || rangeIndexes.startIndex < 0) throw new Error('range.startIndex must be an integer >=0');
1014
+ if (!_.isInteger(rangeIndexes.endIndex) || rangeIndexes.endIndex < 0) throw new Error('range.endIndex must be an integer >=0');
1015
+ if (rangeIndexes.endIndex <= rangeIndexes.startIndex) throw new Error('range.endIndex must be greater than range.startIndex');
1016
+
1017
+ const result = await this._makeSingleUpdateRequest('deleteDimension', {
1018
+ range: {
1019
+ sheetId: this.sheetId,
1020
+ dimension: columnsOrRows,
1021
+ startIndex: rangeIndexes.startIndex,
1022
+ endIndex: rangeIndexes.endIndex,
1023
+ },
1024
+ });
1025
+
1026
+ // Update cached rows and cells
1027
+ if (columnsOrRows === 'ROWS') {
1028
+ this._shiftRowCacheBulk(rangeIndexes.startIndex, rangeIndexes.endIndex);
1029
+ this._shiftCellCacheRows(rangeIndexes.startIndex, rangeIndexes.endIndex);
1030
+ } else {
1031
+ this._shiftCellCacheColumns(rangeIndexes.startIndex, rangeIndexes.endIndex);
1032
+ }
1033
+
1034
+ return result;
707
1035
  }
708
1036
 
709
- async deleteDimension() {
710
- // Request type = `deleteDimension`
711
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDimensionRequest
1037
+ /**
1038
+ * Delete rows by index
1039
+ */
1040
+ async deleteRows(
1041
+ /** the start row index (inclusive, 0-based) */
1042
+ startIndex: number,
1043
+ /** the end row index (exclusive) */
1044
+ endIndex: number
1045
+ ) {
1046
+ return this.deleteDimension('ROWS', { startIndex, endIndex });
1047
+ }
1048
+
1049
+ /**
1050
+ * Delete columns by index
1051
+ */
1052
+ async deleteColumns(
1053
+ /** the start column index (inclusive, 0-based) */
1054
+ startIndex: number,
1055
+ /** the end column index (exclusive) */
1056
+ endIndex: number
1057
+ ) {
1058
+ return this.deleteDimension('COLUMNS', { startIndex, endIndex });
712
1059
  }
713
1060
 
714
1061
  async deleteEmbeddedObject() {
715
1062
  // Request type = `deleteEmbeddedObject`
716
1063
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteEmbeddedObjectRequest
1064
+ throw new Error('Not implemented yet');
717
1065
  }
718
1066
 
719
- async deleteFilterView() {
720
- // Request type = `deleteFilterView`
721
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteFilterViewRequest
1067
+ /**
1068
+ * Deletes a filter view from the sheet
1069
+ *
1070
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteFilterViewRequest
1071
+ */
1072
+ async deleteFilterView(
1073
+ /** The ID of the filter view to delete */
1074
+ filterId: Integer
1075
+ ) {
1076
+ await this._makeSingleUpdateRequest('deleteFilterView', {
1077
+ filterId,
1078
+ });
722
1079
  }
723
1080
 
724
- async duplicateFilterView() {
725
- // Request type = `duplicateFilterView`
726
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DuplicateFilterViewRequest
1081
+ /**
1082
+ * Duplicates a filter view
1083
+ *
1084
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DuplicateFilterViewRequest
1085
+ */
1086
+ async duplicateFilterView(
1087
+ /** The ID of the filter view to duplicate */
1088
+ filterId: Integer
1089
+ ) {
1090
+ await this._makeSingleUpdateRequest('duplicateFilterView', {
1091
+ filterId,
1092
+ });
727
1093
  }
728
1094
 
729
1095
  /**
730
1096
  * Duplicate worksheet within the document
1097
+ *
731
1098
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DuplicateSheetRequest
732
1099
  */
733
1100
  async duplicate(
@@ -747,13 +1114,39 @@ export class GoogleSpreadsheetWorksheet {
747
1114
  return this._spreadsheet.sheetsById[newSheetId];
748
1115
  }
749
1116
 
750
- async findReplace() {
751
- // Request type = `findReplace`
752
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#FindReplaceRequest
1117
+ /**
1118
+ * Finds and replaces text in cells
1119
+ *
1120
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#FindReplaceRequest
1121
+ */
1122
+ async findReplace(
1123
+ /** The value to search for */
1124
+ find: string,
1125
+ /** The value to use as replacement */
1126
+ replacement: string,
1127
+ /** Search options (matchCase, matchEntireCell, searchByRegex, includeFormulas) */
1128
+ options?: {
1129
+ matchCase?: boolean,
1130
+ matchEntireCell?: boolean,
1131
+ searchByRegex?: boolean,
1132
+ includeFormulas?: boolean
1133
+ },
1134
+ /** Optional range to search in (defaults to entire sheet, sheetId optional) */
1135
+ range?: GridRangeWithOptionalWorksheetId
1136
+ ) {
1137
+ await this._makeSingleUpdateRequest('findReplace', {
1138
+ find,
1139
+ replacement,
1140
+ ...options,
1141
+ ...range
1142
+ ? { range: this._addSheetIdToRange(range) }
1143
+ : { sheetId: this.sheetId },
1144
+ });
753
1145
  }
754
1146
 
755
1147
  /**
756
1148
  * Inserts rows or columns at a particular index
1149
+ *
757
1150
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#InsertDimensionRequest
758
1151
  */
759
1152
  async insertDimension(
@@ -788,68 +1181,229 @@ export class GoogleSpreadsheetWorksheet {
788
1181
  });
789
1182
  }
790
1183
 
791
- async insertRange() {
792
- // Request type = `insertRange`
793
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#InsertRangeRequest
1184
+ /**
1185
+ * insert empty cells in a range, shifting existing cells in the specified direction
1186
+ *
1187
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#InsertRangeRequest
1188
+ */
1189
+ async insertRange(
1190
+ /** the range to insert new cells into */
1191
+ range: GridRangeWithOptionalWorksheetId,
1192
+ /** which direction to shift existing cells - ROWS (shift down) or COLUMNS (shift right) */
1193
+ shiftDimension: WorksheetDimension
1194
+ ) {
1195
+ await this._makeSingleUpdateRequest('insertRange', {
1196
+ range: this._addSheetIdToRange(range),
1197
+ shiftDimension,
1198
+ });
794
1199
  }
795
1200
 
796
- async moveDimension() {
797
- // Request type = `moveDimension`
798
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#MoveDimensionRequest
1201
+ /**
1202
+ * Moves rows or columns to a different position within the sheet
1203
+ *
1204
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#MoveDimensionRequest
1205
+ */
1206
+ async moveDimension(
1207
+ /** Whether to move rows or columns */
1208
+ dimension: WorksheetDimension,
1209
+ /** The indexes of rows/columns to move */
1210
+ source: DimensionRangeIndexes,
1211
+ /** Where to move them (calculated before removal) */
1212
+ destinationIndex: number
1213
+ ) {
1214
+ await this._makeSingleUpdateRequest('moveDimension', {
1215
+ source: {
1216
+ sheetId: this.sheetId,
1217
+ dimension,
1218
+ startIndex: source.startIndex,
1219
+ endIndex: source.endIndex,
1220
+ },
1221
+ destinationIndex,
1222
+ });
799
1223
  }
800
1224
 
801
1225
  async updateEmbeddedObjectPosition() {
802
1226
  // Request type = `updateEmbeddedObjectPosition`
803
1227
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateEmbeddedObjectPositionRequest
1228
+ throw new Error('Not implemented yet');
804
1229
  }
805
1230
 
806
- async pasteData() {
807
- // Request type = `pasteData`
808
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#PasteDataRequest
1231
+ /**
1232
+ * Inserts data into the spreadsheet starting at the specified coordinate
1233
+ *
1234
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#PasteDataRequest
1235
+ */
1236
+ async pasteData(
1237
+ /** The coordinate at which the data should start being inserted (sheetId optional) */
1238
+ coordinate: GridCoordinateWithOptionalWorksheetId,
1239
+ /** The data to insert */
1240
+ data: string,
1241
+ /** The delimiter in the data */
1242
+ delimiter: string,
1243
+ /** How the data should be pasted (defaults to PASTE_NORMAL) */
1244
+ type: PasteType = 'PASTE_NORMAL'
1245
+ ) {
1246
+ await this._makeSingleUpdateRequest('pasteData', {
1247
+ coordinate: {
1248
+ sheetId: this.sheetId,
1249
+ rowIndex: coordinate.rowIndex,
1250
+ columnIndex: coordinate.columnIndex,
1251
+ },
1252
+ data,
1253
+ delimiter,
1254
+ type,
1255
+ });
809
1256
  }
810
1257
 
811
- async textToColumns() {
812
- // Request type = `textToColumns`
813
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#TextToColumnsRequest
1258
+ /**
1259
+ * Splits a column of text into multiple columns based on a delimiter
1260
+ *
1261
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#TextToColumnsRequest
1262
+ */
1263
+ async textToColumns(
1264
+ /** The column to split (must span exactly one column) */
1265
+ source: GridRangeWithOptionalWorksheetId,
1266
+ /** Type of delimiter to use */
1267
+ delimiterType: DelimiterType,
1268
+ /** Custom delimiter character (only used when delimiterType is CUSTOM) */
1269
+ delimiter?: string
1270
+ ) {
1271
+ await this._makeSingleUpdateRequest('textToColumns', {
1272
+ source: this._addSheetIdToRange(source),
1273
+ delimiterType,
1274
+ ...delimiter && { delimiter },
1275
+ });
814
1276
  }
815
1277
 
816
- async updateFilterView() {
817
- // Request type = `updateFilterView`
818
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateFilterViewRequest
1278
+ /**
1279
+ * Updates properties of a filter view
1280
+ *
1281
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateFilterViewRequest
1282
+ */
1283
+ async updateFilterView(
1284
+ /** The new properties of the filter view */
1285
+ filter: FilterView,
1286
+ /** The fields that should be updated (use "*" to update all fields) */
1287
+ fields: string
1288
+ ) {
1289
+ await this._makeSingleUpdateRequest('updateFilterView', {
1290
+ filter,
1291
+ fields,
1292
+ });
819
1293
  }
820
1294
 
821
- async deleteRange() {
822
- // Request type = `deleteRange`
823
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteRangeRequest
1295
+ /**
1296
+ * Deletes a range of cells and shifts remaining cells
1297
+ *
1298
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteRangeRequest
1299
+ */
1300
+ async deleteRange(
1301
+ /** The range of cells to delete (sheetId optional) */
1302
+ range: GridRangeWithOptionalWorksheetId,
1303
+ /** How remaining cells should shift (ROWS = up, COLUMNS = left) */
1304
+ shiftDimension: WorksheetDimension
1305
+ ) {
1306
+ await this._makeSingleUpdateRequest('deleteRange', {
1307
+ range: this._addSheetIdToRange(range),
1308
+ shiftDimension,
1309
+ });
824
1310
  }
825
1311
 
826
- async appendDimension() {
827
- // Request type = `appendDimension`
828
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AppendDimensionRequest
1312
+ /**
1313
+ * Appends rows or columns to the end of a sheet
1314
+ *
1315
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AppendDimensionRequest
1316
+ */
1317
+ async appendDimension(
1318
+ /** Whether rows or columns should be appended */
1319
+ dimension: WorksheetDimension,
1320
+ /** The number of rows or columns to append */
1321
+ length: number
1322
+ ) {
1323
+ await this._makeSingleUpdateRequest('appendDimension', {
1324
+ sheetId: this.sheetId,
1325
+ dimension,
1326
+ length,
1327
+ });
829
1328
  }
830
1329
 
831
- async addConditionalFormatRule() {
832
- // Request type = `addConditionalFormatRule`
833
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddConditionalFormatRuleRequest
1330
+ /**
1331
+ * Adds a new conditional formatting rule at the given index
1332
+ * All subsequent rules' indexes are incremented
1333
+ *
1334
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddConditionalFormatRuleRequest
1335
+ */
1336
+ async addConditionalFormatRule(
1337
+ /** The rule to add */
1338
+ rule: ConditionalFormatRule,
1339
+ /** The zero-based index where the rule should be inserted */
1340
+ index: Integer
1341
+ ) {
1342
+ await this._makeSingleUpdateRequest('addConditionalFormatRule', {
1343
+ rule,
1344
+ index,
1345
+ });
834
1346
  }
835
1347
 
836
- async updateConditionalFormatRule() {
837
- // Request type = `updateConditionalFormatRule`
838
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateConditionalFormatRuleRequest
1348
+ /**
1349
+ * Updates a conditional format rule at the given index, or moves a conditional format rule to another index
1350
+ *
1351
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateConditionalFormatRuleRequest
1352
+ */
1353
+ async updateConditionalFormatRule(
1354
+ /** Either provide `rule` to replace the rule, or `newIndex` and `sheetId` to move it */
1355
+ options: {
1356
+ /** The zero-based index of the rule */
1357
+ index: Integer;
1358
+ /** The rule that should replace the rule at the given index (mutually exclusive with newIndex) */
1359
+ rule?: ConditionalFormatRule;
1360
+ /** The zero-based new index the rule should end up at (mutually exclusive with rule, requires sheetId) */
1361
+ newIndex?: Integer;
1362
+ /** The sheet of the rule to move (required if newIndex is set) */
1363
+ sheetId?: WorksheetId;
1364
+ }
1365
+ ) {
1366
+ await this._makeSingleUpdateRequest('updateConditionalFormatRule', options);
839
1367
  }
840
1368
 
841
- async deleteConditionalFormatRule() {
842
- // Request type = `deleteConditionalFormatRule`
843
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteConditionalFormatRuleRequest
1369
+ /**
1370
+ * Deletes a conditional format rule at the given index
1371
+ * All subsequent rules' indexes are decremented
1372
+ *
1373
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteConditionalFormatRuleRequest
1374
+ */
1375
+ async deleteConditionalFormatRule(
1376
+ /** The zero-based index of the rule to be deleted */
1377
+ index: Integer,
1378
+ /** The sheet the rule is being deleted from (defaults to this sheet) */
1379
+ sheetId?: WorksheetId
1380
+ ) {
1381
+ await this._makeSingleUpdateRequest('deleteConditionalFormatRule', {
1382
+ index,
1383
+ sheetId: sheetId ?? this.sheetId,
1384
+ });
844
1385
  }
845
1386
 
846
- async sortRange() {
847
- // Request type = `sortRange`
848
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SortRangeRequest
1387
+ /**
1388
+ * Sorts data in rows based on sort order per column
1389
+ *
1390
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SortRangeRequest
1391
+ */
1392
+ async sortRange(
1393
+ /** The range to sort (sheetId optional) */
1394
+ range: GridRangeWithOptionalWorksheetId,
1395
+ /** Array of sort specifications (later specs used when values are equal) */
1396
+ sortSpecs: SortSpec[]
1397
+ ) {
1398
+ await this._makeSingleUpdateRequest('sortRange', {
1399
+ range: this._addSheetIdToRange(range),
1400
+ sortSpecs,
1401
+ });
849
1402
  }
850
1403
 
851
1404
  /**
852
1405
  * Sets (or unsets) a data validation rule to every cell in the range
1406
+ *
853
1407
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SetDataValidationRequest
854
1408
  */
855
1409
  async setDataValidation(
@@ -866,121 +1420,286 @@ export class GoogleSpreadsheetWorksheet {
866
1420
  });
867
1421
  }
868
1422
 
869
- async setBasicFilter() {
870
- // Request type = `setBasicFilter`
871
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SetBasicFilterRequest
1423
+ /**
1424
+ * Sets the basic filter on this sheet
1425
+ *
1426
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SetBasicFilterRequest
1427
+ */
1428
+ async setBasicFilter(
1429
+ /** The basic filter configuration (range will auto-fill sheetId if not provided) */
1430
+ filter: {
1431
+ range?: GridRangeWithOptionalWorksheetId,
1432
+ sortSpecs?: SortSpec[],
1433
+ filterSpecs?: any[]
1434
+ }
1435
+ ) {
1436
+ await this._makeSingleUpdateRequest('setBasicFilter', {
1437
+ filter: {
1438
+ ...filter,
1439
+ ...filter.range && { range: this._addSheetIdToRange(filter.range) },
1440
+ },
1441
+ });
872
1442
  }
873
1443
 
874
- async addProtectedRange() {
875
- // Request type = `addProtectedRange`
876
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddProtectedRangeRequest
1444
+ /**
1445
+ * add a new protected range to the sheet
1446
+ *
1447
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddProtectedRangeRequest
1448
+ */
1449
+ async addProtectedRange(
1450
+ protectedRange: ProtectedRange
1451
+ ) {
1452
+ if (!protectedRange.range && !protectedRange.namedRangeId) {
1453
+ throw new Error('No range specified: either range or namedRangeId is required');
1454
+ }
1455
+ return this._makeSingleUpdateRequest('addProtectedRange', {
1456
+ protectedRange,
1457
+ });
877
1458
  }
878
1459
 
879
- async updateProtectedRange() {
880
- // Request type = `updateProtectedRange`
881
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateProtectedRangeRequest
1460
+ /**
1461
+ * update an existing protected range
1462
+ *
1463
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateProtectedRangeRequest
1464
+ */
1465
+ async updateProtectedRange(
1466
+ protectedRangeId: Integer,
1467
+ protectedRange: Partial<ProtectedRange>
1468
+ ) {
1469
+ return this._makeSingleUpdateRequest('updateProtectedRange', {
1470
+ protectedRange: { protectedRangeId, ...protectedRange },
1471
+ fields: getFieldMask(protectedRange as Record<string, unknown>),
1472
+ });
882
1473
  }
883
1474
 
884
- async deleteProtectedRange() {
885
- // Request type = `deleteProtectedRange`
886
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteProtectedRangeRequest
1475
+ /**
1476
+ * delete a protected range by ID
1477
+ *
1478
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteProtectedRangeRequest
1479
+ */
1480
+ async deleteProtectedRange(
1481
+ protectedRangeId: Integer
1482
+ ) {
1483
+ return this._makeSingleUpdateRequest('deleteProtectedRange', {
1484
+ protectedRangeId,
1485
+ });
887
1486
  }
888
1487
 
889
- async autoResizeDimensions() {
890
- // Request type = `autoResizeDimensions`
891
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AutoResizeDimensionsRequest
1488
+ /**
1489
+ * auto-resize rows or columns to fit their contents
1490
+ *
1491
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AutoResizeDimensionsRequest
1492
+ */
1493
+ async autoResizeDimensions(
1494
+ /** which dimension to auto-resize */
1495
+ columnsOrRows: WorksheetDimension,
1496
+ /** start and end indexes (optional, defaults to all) */
1497
+ rangeIndexes?: DimensionRangeIndexes
1498
+ ) {
1499
+ return this._makeSingleUpdateRequest('autoResizeDimensions', {
1500
+ dimensions: {
1501
+ sheetId: this.sheetId,
1502
+ dimension: columnsOrRows,
1503
+ ...rangeIndexes,
1504
+ },
1505
+ });
892
1506
  }
893
1507
 
894
1508
  async addChart() {
895
1509
  // Request type = `addChart`
896
1510
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddChartRequest
1511
+ throw new Error('Not implemented yet');
897
1512
  }
898
1513
 
899
1514
  async updateChartSpec() {
900
1515
  // Request type = `updateChartSpec`
901
1516
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateChartSpecRequest
1517
+ throw new Error('Not implemented yet');
902
1518
  }
903
1519
 
904
- async updateBanding() {
905
- // Request type = `updateBanding`
906
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateBandingRequest
1520
+ /**
1521
+ * Updates properties of a banded range
1522
+ *
1523
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateBandingRequest
1524
+ */
1525
+ async updateBanding(
1526
+ /** The banded range to update with the new properties */
1527
+ bandedRange: BandedRange,
1528
+ /** The fields that should be updated (use "*" to update all fields) */
1529
+ fields: string
1530
+ ) {
1531
+ await this._makeSingleUpdateRequest('updateBanding', {
1532
+ bandedRange,
1533
+ fields,
1534
+ });
907
1535
  }
908
1536
 
909
- async addBanding() {
910
- // Request type = `addBanding`
911
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddBandingRequest
1537
+ /**
1538
+ * Adds a new banded range to the sheet
1539
+ *
1540
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddBandingRequest
1541
+ */
1542
+ async addBanding(
1543
+ /** The banded range to add (bandedRangeId is optional and will be auto-generated if not provided) */
1544
+ bandedRange: BandedRange
1545
+ ) {
1546
+ return this._makeSingleUpdateRequest('addBanding', {
1547
+ bandedRange,
1548
+ });
912
1549
  }
913
1550
 
914
- async deleteBanding() {
915
- // Request type = `deleteBanding`
916
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteBandingRequest
1551
+ /**
1552
+ * Deletes a banded range from the sheet
1553
+ *
1554
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteBandingRequest
1555
+ */
1556
+ async deleteBanding(
1557
+ /** The ID of the banded range to delete */
1558
+ bandedRangeId: Integer
1559
+ ) {
1560
+ await this._makeSingleUpdateRequest('deleteBanding', {
1561
+ bandedRangeId,
1562
+ });
917
1563
  }
918
1564
 
919
- async createDeveloperMetadata() {
920
- // Request type = `createDeveloperMetadata`
921
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CreateDeveloperMetadataRequest
1565
+ /**
1566
+ * Creates developer metadata
1567
+ *
1568
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CreateDeveloperMetadataRequest
1569
+ */
1570
+ async createDeveloperMetadata(
1571
+ /** The developer metadata to create */
1572
+ developerMetadata: DeveloperMetadata
1573
+ ) {
1574
+ return this._makeSingleUpdateRequest('createDeveloperMetadata', {
1575
+ developerMetadata,
1576
+ });
922
1577
  }
923
1578
 
924
- async updateDeveloperMetadata() {
925
- // Request type = `updateDeveloperMetadata`
926
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateDeveloperMetadataRequest
1579
+ /**
1580
+ * Updates developer metadata that matches the specified filters
1581
+ *
1582
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateDeveloperMetadataRequest
1583
+ */
1584
+ async updateDeveloperMetadata(
1585
+ /** The filters matching the developer metadata entries to update */
1586
+ dataFilters: DataFilterObject[],
1587
+ /** The value that all metadata matched by the filters will be updated to */
1588
+ developerMetadata: DeveloperMetadata,
1589
+ /** The fields that should be updated (use "*" to update all fields) */
1590
+ fields: string
1591
+ ) {
1592
+ await this._makeSingleUpdateRequest('updateDeveloperMetadata', {
1593
+ dataFilters,
1594
+ developerMetadata,
1595
+ fields,
1596
+ });
927
1597
  }
928
1598
 
929
- async deleteDeveloperMetadata() {
930
- // Request type = `deleteDeveloperMetadata`
931
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDeveloperMetadataRequest
1599
+ /**
1600
+ * Deletes developer metadata that matches the specified filter
1601
+ *
1602
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDeveloperMetadataRequest
1603
+ */
1604
+ async deleteDeveloperMetadata(
1605
+ /** The filter describing the criteria used to select which developer metadata to delete */
1606
+ dataFilter: DataFilterObject
1607
+ ) {
1608
+ await this._makeSingleUpdateRequest('deleteDeveloperMetadata', {
1609
+ dataFilter,
1610
+ });
932
1611
  }
933
1612
 
934
- async randomizeRange() {
935
- // Request type = `randomizeRange`
936
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#RandomizeRangeRequest
1613
+ /**
1614
+ * Randomizes the order of rows in a range
1615
+ *
1616
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#RandomizeRangeRequest
1617
+ */
1618
+ async randomizeRange(
1619
+ /** The range to randomize (sheetId optional) */
1620
+ range: GridRangeWithOptionalWorksheetId
1621
+ ) {
1622
+ await this._makeSingleUpdateRequest('randomizeRange', {
1623
+ range: this._addSheetIdToRange(range),
1624
+ });
937
1625
  }
938
1626
 
939
1627
  async addDimensionGroup() {
940
1628
  // Request type = `addDimensionGroup`
941
1629
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddDimensionGroupRequest
1630
+ throw new Error('Not implemented yet');
942
1631
  }
943
1632
 
944
1633
  async deleteDimensionGroup() {
945
1634
  // Request type = `deleteDimensionGroup`
946
1635
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDimensionGroupRequest
1636
+ throw new Error('Not implemented yet');
947
1637
  }
948
1638
 
949
1639
  async updateDimensionGroup() {
950
1640
  // Request type = `updateDimensionGroup`
951
1641
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateDimensionGroupRequest
1642
+ throw new Error('Not implemented yet');
952
1643
  }
953
1644
 
954
- async trimWhitespace() {
955
- // Request type = `trimWhitespace`
956
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#TrimWhitespaceRequest
1645
+ /**
1646
+ * Trims whitespace from the start and end of each cell's text
1647
+ *
1648
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#TrimWhitespaceRequest
1649
+ */
1650
+ async trimWhitespace(
1651
+ /** The range whose cells to trim (sheetId optional) */
1652
+ range: GridRangeWithOptionalWorksheetId
1653
+ ) {
1654
+ await this._makeSingleUpdateRequest('trimWhitespace', {
1655
+ range: this._addSheetIdToRange(range),
1656
+ });
957
1657
  }
958
1658
 
959
- async deleteDuplicates() {
960
- // Request type = `deleteDuplicates`
961
- // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDuplicatesRequest
1659
+ /**
1660
+ * Removes duplicate rows from a range based on specified columns
1661
+ *
1662
+ * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDuplicatesRequest
1663
+ */
1664
+ async deleteDuplicates(
1665
+ /** The range to remove duplicates from (sheetId optional) */
1666
+ range: GridRangeWithOptionalWorksheetId,
1667
+ /** Columns to check for duplicates (if empty, all columns are used) */
1668
+ comparisonColumns?: DimensionRange[]
1669
+ ) {
1670
+ await this._makeSingleUpdateRequest('deleteDuplicates', {
1671
+ range: this._addSheetIdToRange(range),
1672
+ ...comparisonColumns && { comparisonColumns },
1673
+ });
962
1674
  }
963
1675
 
964
1676
  async addSlicer() {
965
1677
  // Request type = `addSlicer`
966
1678
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddSlicerRequest
1679
+ throw new Error('Not implemented yet');
967
1680
  }
968
1681
 
969
1682
  async updateSlicerSpec() {
970
1683
  // Request type = `updateSlicerSpec`
971
1684
  // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateSlicerSpecRequest
1685
+ throw new Error('Not implemented yet');
972
1686
  }
973
1687
 
974
- /** delete this worksheet */
1688
+ /**
1689
+ * delete this worksheet
1690
+ */
975
1691
  async delete() {
976
1692
  return this._spreadsheet.deleteSheet(this.sheetId);
977
1693
  }
978
1694
 
979
1695
  /**
980
1696
  * copies this worksheet into another document/spreadsheet
1697
+ *
981
1698
  * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.sheets/copyTo
982
- * */
983
- async copyToSpreadsheet(destinationSpreadsheetId: SpreadsheetId) {
1699
+ */
1700
+ async copyToSpreadsheet(
1701
+ destinationSpreadsheetId: SpreadsheetId
1702
+ ) {
984
1703
  const req = this._spreadsheet.sheetsApi.post(`sheets/${this.sheetId}:copyTo`, {
985
1704
  json: {
986
1705
  destinationSpreadsheetId,
@@ -990,7 +1709,9 @@ export class GoogleSpreadsheetWorksheet {
990
1709
  return data;
991
1710
  }
992
1711
 
993
- /** clear data in the sheet - either the entire sheet or a specific range */
1712
+ /**
1713
+ * clear data in the sheet - either the entire sheet or a specific range
1714
+ */
994
1715
  async clear(
995
1716
  /** optional A1 range to clear - defaults to entire sheet */
996
1717
  a1Range?: A1Range
@@ -1001,21 +1722,27 @@ export class GoogleSpreadsheetWorksheet {
1001
1722
  this.resetLocalCache(true);
1002
1723
  }
1003
1724
 
1004
- /** exports worksheet as CSV file (comma-separated values) */
1725
+ /**
1726
+ * exports worksheet as CSV file (comma-separated values)
1727
+ */
1005
1728
  async downloadAsCSV(): Promise<ArrayBuffer>;
1006
1729
  async downloadAsCSV(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;
1007
1730
  async downloadAsCSV(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;
1008
1731
  async downloadAsCSV(returnStreamInsteadOfBuffer = false) {
1009
1732
  return this._spreadsheet._downloadAs('csv', this.sheetId, returnStreamInsteadOfBuffer);
1010
1733
  }
1011
- /** exports worksheet as TSC file (tab-separated values) */
1734
+ /**
1735
+ * exports worksheet as TSC file (tab-separated values)
1736
+ */
1012
1737
  async downloadAsTSV(): Promise<ArrayBuffer>;
1013
1738
  async downloadAsTSV(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;
1014
1739
  async downloadAsTSV(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;
1015
1740
  async downloadAsTSV(returnStreamInsteadOfBuffer = false) {
1016
1741
  return this._spreadsheet._downloadAs('tsv', this.sheetId, returnStreamInsteadOfBuffer);
1017
1742
  }
1018
- /** exports worksheet as PDF */
1743
+ /**
1744
+ * exports worksheet as PDF
1745
+ */
1019
1746
  async downloadAsPDF(): Promise<ArrayBuffer>;
1020
1747
  async downloadAsPDF(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;
1021
1748
  async downloadAsPDF(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;