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/README.md +2 -0
- package/dist/index.cjs +596 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +654 -61
- package/dist/index.d.ts +654 -61
- package/dist/index.js +596 -58
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/lib/GoogleSpreadsheet.ts +47 -11
- package/src/lib/GoogleSpreadsheetCell.ts +26 -4
- package/src/lib/GoogleSpreadsheetRow.ts +20 -1
- package/src/lib/GoogleSpreadsheetWorksheet.ts +808 -128
- package/src/lib/types/sheets-types.ts +257 -10
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/lib/utils.ts","../src/lib/GoogleSpreadsheetRow.ts","../src/lib/GoogleSpreadsheetCellErrorValue.ts","../src/lib/GoogleSpreadsheetCell.ts","../src/lib/GoogleSpreadsheetWorksheet.ts","../src/lib/types/auth-types.ts","../src/lib/GoogleSpreadsheet.ts"],"sourcesContent":["import * as _ from './toolkit';\n\nexport function getFieldMask(obj: Record<string, unknown>) {\n let fromGrid = '';\n const fromRoot = Object.keys(obj).filter((key) => key !== 'gridProperties').join(',');\n\n if (obj.gridProperties) {\n fromGrid = Object.keys(obj.gridProperties).map((key) => `gridProperties.${key}`).join(',');\n if (fromGrid.length && fromRoot.length) {\n fromGrid = `${fromGrid},`;\n }\n }\n return fromGrid + fromRoot;\n}\n\nexport function columnToLetter(column: number) {\n let temp;\n let letter = '';\n let col = column;\n while (col > 0) {\n temp = (col - 1) % 26;\n letter = String.fromCharCode(temp + 65) + letter;\n col = (col - temp - 1) / 26;\n }\n return letter;\n}\n\nexport function letterToColumn(letter: string) {\n let column = 0;\n const { length } = letter;\n for (let i = 0; i < length; i++) {\n column += (letter.charCodeAt(i) - 64) * 26 ** (length - i - 1);\n }\n return column;\n}\n\nexport function checkForDuplicateHeaders(headers: string[]) {\n // check for duplicate headers\n const checkForDupes = _.groupBy(headers); // { c1: ['c1'], c2: ['c2', 'c2' ]}\n _.each(checkForDupes, (grouped, header) => {\n if (!header) return; // empty columns are skipped, so multiple is ok\n if (grouped.length > 1) {\n throw new Error(`Duplicate header detected: \"${header}\". Please make sure all non-empty headers are unique`);\n }\n });\n}\n\n","import { GoogleSpreadsheetWorksheet } from './GoogleSpreadsheetWorksheet';\nimport { columnToLetter } from './utils';\n\n\n// TODO: add type for possible row values (currently any)\n\nexport class GoogleSpreadsheetRow<T extends Record<string, any> = Record<string, any>> {\n constructor(\n /** parent GoogleSpreadsheetWorksheet instance */\n readonly _worksheet: GoogleSpreadsheetWorksheet,\n /** the A1 row (1-indexed) */\n private _rowNumber: number,\n /** raw underlying data for row */\n private _rawData: any[]\n ) {\n\n }\n\n private _deleted = false;\n get deleted() { return this._deleted; }\n\n /** row number (matches A1 notation, ie first row is 1) */\n get rowNumber() { return this._rowNumber; }\n /**\n * @internal\n * Used internally to update row numbers after deleting rows.\n * Should not be called directly.\n */\n _updateRowNumber(newRowNumber: number) {\n this._rowNumber = newRowNumber;\n }\n get a1Range() {\n return [\n this._worksheet.a1SheetName,\n '!',\n `A${this._rowNumber}`,\n ':',\n `${columnToLetter(this._worksheet.headerValues.length)}${this._rowNumber}`,\n ].join('');\n }\n\n /** get row's value of specific cell (by header key) */\n get(key: keyof T) {\n const index = this._worksheet.headerValues.indexOf(key as string);\n return this._rawData[index];\n }\n /** set row's value of specific cell (by header key) */\n set<K extends keyof T>(key: K, val: T[K]) {\n const index = this._worksheet.headerValues.indexOf(key as string);\n this._rawData[index] = val;\n }\n /** set multiple values in the row at once from an object */\n assign(obj: Partial<T>) {\n // eslint-disable-next-line no-restricted-syntax, guard-for-in\n for (const key in obj) this.set(key, obj[key] as any);\n }\n\n /** return raw object of row data */\n toObject() {\n const o: Partial<T> = {};\n for (let i = 0; i < this._worksheet.headerValues.length; i++) {\n const key: keyof T = this._worksheet.headerValues[i];\n if (!key) continue;\n o[key] = this._rawData[i];\n }\n return o;\n }\n\n /** save row values */\n async save(options?: { raw?: boolean }) {\n if (this._deleted) throw new Error('This row has been deleted - call getRows again before making updates.');\n\n const response = await this._worksheet._spreadsheet.sheetsApi.put(`values/${encodeURIComponent(this.a1Range)}`, {\n searchParams: {\n valueInputOption: options?.raw ? 'RAW' : 'USER_ENTERED',\n includeValuesInResponse: true,\n },\n json: {\n range: this.a1Range,\n majorDimension: 'ROWS',\n values: [this._rawData],\n },\n });\n const data = await response.json<any>();\n this._rawData = data.updatedData.values[0];\n }\n\n /** delete this row */\n async delete() {\n if (this._deleted) throw new Error('This row has been deleted - call getRows again before making updates.');\n\n const result = await this._worksheet._makeSingleUpdateRequest('deleteRange', {\n range: {\n sheetId: this._worksheet.sheetId,\n startRowIndex: this._rowNumber - 1, // this format is zero indexed, because of course...\n endRowIndex: this._rowNumber,\n },\n shiftDimension: 'ROWS',\n });\n this._deleted = true;\n this._worksheet._shiftRowCache(this.rowNumber);\n\n return result;\n }\n\n /**\n * @internal\n * Used internally to clear row data after calling sheet.clearRows\n * Should not be called directly.\n */\n _clearRowData() {\n for (let i = 0; i < this._rawData.length; i++) {\n this._rawData[i] = '';\n }\n }\n}\n","import { CellValueErrorType, ErrorValue } from './types/sheets-types';\n\n/**\n * Cell error\n *\n * not a js \"error\" that gets thrown, but a value that holds an error code and message for a cell\n * it's useful to use a class so we can check `instanceof`\n\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#ErrorType\n */\nexport class GoogleSpreadsheetCellErrorValue {\n /**\n * type of the error\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#ErrorType\n * */\n readonly type: CellValueErrorType;\n\n /** A message with more information about the error (in the spreadsheet's locale) */\n readonly message: string;\n\n constructor(rawError: ErrorValue) {\n this.type = rawError.type;\n this.message = rawError.message;\n }\n}\n","/* eslint-disable max-classes-per-file */\nimport * as _ from './toolkit';\n\nimport { columnToLetter } from './utils';\n\nimport { GoogleSpreadsheetWorksheet } from './GoogleSpreadsheetWorksheet';\nimport { GoogleSpreadsheetCellErrorValue } from './GoogleSpreadsheetCellErrorValue';\n\nimport {\n CellData,\n CellFormat, CellValueType, ColumnIndex, RowIndex,\n} from './types/sheets-types';\n\nexport class GoogleSpreadsheetCell {\n private _rawData?: CellData;\n private _draftData: any = {};\n private _error?: GoogleSpreadsheetCellErrorValue;\n\n constructor(\n readonly _sheet: GoogleSpreadsheetWorksheet,\n private _rowIndex: RowIndex,\n private _columnIndex: ColumnIndex,\n rawCellData: CellData\n ) {\n this._updateRawData(rawCellData);\n this._rawData = rawCellData; // so TS does not complain\n }\n\n // TODO: figure out how to deal with empty rawData\n // newData can be undefined/null if the cell is totally empty and unformatted\n /**\n * update cell using raw CellData coming back from sheets API\n * @internal\n */\n _updateRawData(newData: CellData) {\n this._rawData = newData;\n this._draftData = {};\n if (this._rawData?.effectiveValue && 'errorValue' in this._rawData.effectiveValue) {\n this._error = new GoogleSpreadsheetCellErrorValue(this._rawData.effectiveValue.errorValue);\n } else {\n this._error = undefined;\n }\n }\n\n // CELL LOCATION/ADDRESS /////////////////////////////////////////////////////////////////////////\n get rowIndex() { return this._rowIndex; }\n get columnIndex() { return this._columnIndex; }\n get a1Column() { return columnToLetter(this._columnIndex + 1); }\n get a1Row() { return this._rowIndex + 1; } // a1 row numbers start at 1 instead of 0\n get a1Address() { return `${this.a1Column}${this.a1Row}`; }\n\n // CELL CONTENTS - VALUE/FORMULA/NOTES ///////////////////////////////////////////////////////////\n get value(): number | boolean | string | null | GoogleSpreadsheetCellErrorValue {\n // const typeKey = _.keys(this._rawData.effectiveValue)[0];\n if (this._draftData.value !== undefined) throw new Error('Value has been changed');\n if (this._error) return this._error;\n if (!this._rawData?.effectiveValue) return null;\n return _.values(this._rawData.effectiveValue)[0];\n }\n\n\n set value(newValue: number | boolean | Date | string | null | undefined | GoogleSpreadsheetCellErrorValue) {\n // had to include the GoogleSpreadsheetCellErrorValue in the type to make TS happy\n if (newValue instanceof GoogleSpreadsheetCellErrorValue) {\n throw new Error(\"You can't manually set a value to an error\");\n }\n\n if (_.isBoolean(newValue)) {\n this._draftData.valueType = 'boolValue';\n } else if (_.isString(newValue)) {\n if (newValue.substring(0, 1) === '=') this._draftData.valueType = 'formulaValue';\n else this._draftData.valueType = 'stringValue';\n } else if (_.isFinite(newValue)) {\n this._draftData.valueType = 'numberValue';\n } else if (_.isNil(newValue)) {\n // null or undefined\n this._draftData.valueType = 'stringValue';\n newValue = '';\n } else {\n throw new Error('Set value to boolean, string, or number');\n }\n this._draftData.value = newValue;\n }\n\n get valueType(): CellValueType | null {\n // an error only happens with a formula (as far as I know)\n if (this._error) return 'errorValue';\n if (!this._rawData?.effectiveValue) return null;\n return _.keys(this._rawData.effectiveValue)[0] as CellValueType;\n }\n\n /** The formatted value of the cell - this is the value as it's shown to the user */\n get formattedValue(): string | null { return this._rawData?.formattedValue || null; }\n\n get formula() { return _.get(this._rawData, 'userEnteredValue.formulaValue', null); }\n set formula(newValue: string | null) {\n if (!newValue) throw new Error('To clear a formula, set `cell.value = null`');\n if (newValue.substring(0, 1) !== '=') throw new Error('formula must begin with \"=\"');\n this.value = newValue; // use existing value setter\n }\n /**\n * @deprecated use `cell.errorValue` instead\n */\n get formulaError() { return this._error; }\n /**\n * error contained in the cell, which can happen with a bad formula (maybe some other weird cases?)\n */\n get errorValue() { return this._error; }\n\n get numberValue(): number | undefined {\n if (this.valueType !== 'numberValue') return undefined;\n return this.value as number;\n }\n set numberValue(val: number | undefined) {\n this.value = val;\n }\n\n get boolValue(): boolean | undefined {\n if (this.valueType !== 'boolValue') return undefined;\n return this.value as boolean;\n }\n set boolValue(val: boolean | undefined) {\n this.value = val;\n }\n\n get stringValue(): string | undefined {\n if (this.valueType !== 'stringValue') return undefined;\n return this.value as string;\n }\n set stringValue(val: string | undefined) {\n if (val?.startsWith('=')) {\n throw new Error('Use cell.formula to set formula values');\n }\n this.value = val;\n }\n\n /**\n * Hyperlink contained within the cell.\n *\n * To modify, do not set directly. Instead set cell.formula, for example `cell.formula = \\'=HYPERLINK(\"http://google.com\", \"Google\")\\'`\n */\n get hyperlink() {\n if (this._draftData.value) throw new Error('Save cell to be able to read hyperlink');\n return this._rawData?.hyperlink;\n }\n\n /** a note attached to the cell */\n get note(): string {\n return this._draftData.note !== undefined ? this._draftData.note : this._rawData?.note || '';\n }\n set note(newVal: string | null | undefined | false) {\n if (newVal === null || newVal === undefined || newVal === false) newVal = '';\n if (!_.isString(newVal)) throw new Error('Note must be a string');\n if (newVal === this._rawData?.note) delete this._draftData.note;\n else this._draftData.note = newVal;\n }\n\n // CELL FORMATTING ///////////////////////////////////////////////////////////////////////////////\n get userEnteredFormat() { return Object.freeze(this._rawData?.userEnteredFormat); }\n get effectiveFormat() { return Object.freeze(this._rawData?.effectiveFormat); }\n\n private _getFormatParam<T extends keyof CellFormat>(param: T): Readonly<CellFormat[T]> {\n // we freeze the object so users don't change nested props accidentally\n // TODO: figure out something that would throw an error if you try to update it?\n if (_.get(this._draftData, `userEnteredFormat.${param}`)) {\n throw new Error('User format is unsaved - save the cell to be able to read it again');\n }\n // TODO: figure out how to deal with possible empty rawData\n // if (!this._rawData?.userEnteredFormat?.[param]) {\n // return undefined;\n // }\n return Object.freeze(this._rawData!.userEnteredFormat[param]);\n }\n\n private _setFormatParam<T extends keyof CellFormat>(param: T, newVal: CellFormat[T]) {\n if (_.isEqual(newVal, _.get(this._rawData, `userEnteredFormat.${param}`))) {\n _.unset(this._draftData, `userEnteredFormat.${param}`);\n } else {\n _.set(this._draftData, `userEnteredFormat.${param}`, newVal);\n this._draftData.clearFormat = false;\n }\n }\n\n // format getters\n get numberFormat() { return this._getFormatParam('numberFormat'); }\n get backgroundColor() { return this._getFormatParam('backgroundColor'); }\n get backgroundColorStyle() { return this._getFormatParam('backgroundColorStyle'); }\n get borders() { return this._getFormatParam('borders'); }\n get padding() { return this._getFormatParam('padding'); }\n get horizontalAlignment() { return this._getFormatParam('horizontalAlignment'); }\n get verticalAlignment() { return this._getFormatParam('verticalAlignment'); }\n get wrapStrategy() { return this._getFormatParam('wrapStrategy'); }\n get textDirection() { return this._getFormatParam('textDirection'); }\n get textFormat() { return this._getFormatParam('textFormat'); }\n get hyperlinkDisplayType() { return this._getFormatParam('hyperlinkDisplayType'); }\n get textRotation() { return this._getFormatParam('textRotation'); }\n\n // format setters\n set numberFormat(newVal: CellFormat['numberFormat']) { this._setFormatParam('numberFormat', newVal); }\n set backgroundColor(newVal: CellFormat['backgroundColor']) { this._setFormatParam('backgroundColor', newVal); }\n set backgroundColorStyle(newVal: CellFormat['backgroundColorStyle']) { this._setFormatParam('backgroundColorStyle', newVal); }\n set borders(newVal: CellFormat['borders']) { this._setFormatParam('borders', newVal); }\n set padding(newVal: CellFormat['padding']) { this._setFormatParam('padding', newVal); }\n set horizontalAlignment(newVal: CellFormat['horizontalAlignment']) { this._setFormatParam('horizontalAlignment', newVal); }\n set verticalAlignment(newVal: CellFormat['verticalAlignment']) { this._setFormatParam('verticalAlignment', newVal); }\n set wrapStrategy(newVal: CellFormat['wrapStrategy']) { this._setFormatParam('wrapStrategy', newVal); }\n set textDirection(newVal: CellFormat['textDirection']) { this._setFormatParam('textDirection', newVal); }\n set textFormat(newVal: CellFormat['textFormat']) { this._setFormatParam('textFormat', newVal); }\n set hyperlinkDisplayType(newVal: CellFormat['hyperlinkDisplayType']) { this._setFormatParam('hyperlinkDisplayType', newVal); }\n set textRotation(newVal: CellFormat['textRotation']) { this._setFormatParam('textRotation', newVal); }\n\n clearAllFormatting() {\n // need to track this separately since by setting/unsetting things, we may end up with\n // this._draftData.userEnteredFormat as an empty object, but not an intent to clear it\n this._draftData.clearFormat = true;\n delete this._draftData.userEnteredFormat;\n }\n\n // SAVING + UTILS ////////////////////////////////////////////////////////////////////////////////\n\n // returns true if there are any updates that have not been saved yet\n get _isDirty() {\n // have to be careful about checking undefined rather than falsy\n // in case a new value is empty string or 0 or false\n if (this._draftData.note !== undefined) return true;\n if (_.keys(this._draftData.userEnteredFormat).length) return true;\n if (this._draftData.clearFormat) return true;\n if (this._draftData.value !== undefined) return true;\n return false;\n }\n\n discardUnsavedChanges() {\n this._draftData = {};\n }\n\n /**\n * saves updates for single cell\n * usually it's better to make changes and call sheet.saveUpdatedCells\n * */\n async save() {\n await this._sheet.saveCells([this]);\n }\n\n /**\n * used by worksheet when saving cells\n * returns an individual batchUpdate request to update the cell\n * @internal\n */\n _getUpdateRequest() {\n // this logic should match the _isDirty logic above\n // but we need it broken up to build the request below\n const isValueUpdated = this._draftData.value !== undefined;\n const isNoteUpdated = this._draftData.note !== undefined;\n const isFormatUpdated = !!_.keys(this._draftData.userEnteredFormat || {}).length;\n const isFormatCleared = this._draftData.clearFormat;\n\n // if no updates, we return null, which we can filter out later before sending requests\n if (!_.some([isValueUpdated, isNoteUpdated, isFormatUpdated, isFormatCleared])) {\n return null;\n }\n\n // build up the formatting object, which has some quirks...\n const format = {\n // have to pass the whole object or it will clear existing properties\n ...this._rawData?.userEnteredFormat,\n ...this._draftData.userEnteredFormat,\n };\n // if background color already set, cell has backgroundColor and backgroundColorStyle\n // but backgroundColorStyle takes precendence so we must remove to set the color\n // see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/cells#CellFormat\n if (_.get(this._draftData, 'userEnteredFormat.backgroundColor')) {\n delete (format.backgroundColorStyle);\n }\n\n return {\n updateCells: {\n rows: [{\n values: [{\n ...isValueUpdated && {\n userEnteredValue: { [this._draftData.valueType]: this._draftData.value },\n },\n ...isNoteUpdated && {\n note: this._draftData.note,\n },\n ...isFormatUpdated && {\n userEnteredFormat: format,\n },\n ...isFormatCleared && {\n userEnteredFormat: {},\n },\n }],\n }],\n // turns into a string of which fields to update ex \"note,userEnteredFormat\"\n fields: _.keys(_.pickBy({\n userEnteredValue: isValueUpdated,\n note: isNoteUpdated,\n userEnteredFormat: isFormatUpdated || isFormatCleared,\n })).join(','),\n start: {\n sheetId: this._sheet.sheetId,\n rowIndex: this.rowIndex,\n columnIndex: this.columnIndex,\n },\n },\n };\n }\n}\n","import { type ReadableStream } from 'stream/web';\nimport * as _ from './toolkit';\n\nimport { GoogleSpreadsheetRow } from './GoogleSpreadsheetRow';\nimport { GoogleSpreadsheetCell } from './GoogleSpreadsheetCell';\n\nimport {\n getFieldMask, columnToLetter, letterToColumn, checkForDuplicateHeaders,\n} from './utils';\nimport { GoogleSpreadsheet } from './GoogleSpreadsheet';\nimport {\n A1Range, SpreadsheetId, DimensionRangeIndexes, WorksheetDimension, WorksheetId, WorksheetProperties, A1Address,\n RowIndex, ColumnIndex, DataFilterWithoutWorksheetId, DataFilter, GetValuesRequestOptions, WorksheetGridProperties,\n WorksheetDimensionProperties, CellDataRange, AddRowOptions, GridRangeWithOptionalWorksheetId,\n DataValidationRule,\n ProtectedRange, Integer,\n} from './types/sheets-types';\n\n\n// types of cell data accepted when using row based api\ntype RowCellData = string | number | boolean | Date;\n// raw row data can be passed in as an array or an object using header values as keys\ntype RawRowData = RowCellData[] | Record<string, RowCellData>;\n\nexport class GoogleSpreadsheetWorksheet {\n // assume \"header row\" (for row-based calls) is in first row, can be adjusted later\n private _headerRowIndex = 1;\n\n private _rawProperties: WorksheetProperties | null = null;\n private _cells: GoogleSpreadsheetCell[][] = [];\n private _rowMetadata: any[] = [];\n private _columnMetadata: any[] = [];\n private _protectedRanges: ProtectedRange[] | null = null;\n\n private _headerValues: string[] | undefined;\n get headerValues() {\n if (!this._headerValues) {\n throw new Error('Header values are not yet loaded');\n }\n return this._headerValues!;\n }\n\n constructor(\n /** parent GoogleSpreadsheet instance */\n readonly _spreadsheet: GoogleSpreadsheet,\n rawProperties: WorksheetProperties,\n rawCellData?: CellDataRange[],\n protectedRanges?: ProtectedRange[]\n ) {\n this._headerRowIndex = 1;\n\n // basic properties\n this._rawProperties = rawProperties;\n\n this._cells = []; // we will use a 2d sparse array to store cells;\n\n this._rowMetadata = []; // 1d sparse array\n this._columnMetadata = [];\n if (protectedRanges) this._protectedRanges = protectedRanges;\n\n if (rawCellData) this._fillCellData(rawCellData);\n }\n\n // INTERNAL UTILITY FUNCTIONS ////////////////////////////////////////////////////////////////////\n\n updateRawData(properties: WorksheetProperties, rawCellData: CellDataRange[], protectedRanges?: ProtectedRange[]) {\n this._rawProperties = properties;\n this._fillCellData(rawCellData);\n if (protectedRanges) this._protectedRanges = protectedRanges;\n }\n\n async _makeSingleUpdateRequest(requestType: string, requestParams: any) {\n // pass the call up to the parent\n return this._spreadsheet._makeSingleUpdateRequest(requestType, {\n ...requestParams,\n });\n }\n\n private _ensureInfoLoaded() {\n if (!this._rawProperties) {\n throw new Error('You must call `doc.loadInfo()` again before accessing this property');\n }\n }\n\n /** clear local cache of sheet data/properties */\n resetLocalCache(\n /** set to true to clear data only, leaving sheet metadata/propeties intact */\n dataOnly?: boolean\n ) {\n if (!dataOnly) this._rawProperties = null;\n this._headerValues = undefined;\n this._headerRowIndex = 1;\n this._cells = [];\n }\n\n private _fillCellData(\n dataRanges: CellDataRange[]\n ) {\n _.each(dataRanges, (range) => {\n const startRow = range.startRow || 0;\n const startColumn = range.startColumn || 0;\n const numRows = range.rowMetadata.length;\n const numColumns = range.columnMetadata.length;\n\n // update cell data for entire range\n for (let i = 0; i < numRows; i++) {\n const actualRow = startRow + i;\n for (let j = 0; j < numColumns; j++) {\n const actualColumn = startColumn + j;\n\n // if the row has not been initialized yet, do it\n if (!this._cells[actualRow]) this._cells[actualRow] = [];\n\n // see if the response includes some info for the cell\n const cellData = _.get(range, `rowData[${i}].values[${j}]`);\n\n // update the cell object or create it\n if (this._cells[actualRow][actualColumn]) {\n this._cells[actualRow][actualColumn]._updateRawData(cellData);\n } else {\n this._cells[actualRow][actualColumn] = new GoogleSpreadsheetCell(\n this,\n actualRow,\n actualColumn,\n cellData\n );\n }\n }\n }\n\n // update row metadata\n for (let i = 0; i < range.rowMetadata.length; i++) {\n this._rowMetadata[startRow + i] = range.rowMetadata[i];\n }\n // update column metadata\n for (let i = 0; i < range.columnMetadata.length; i++) {\n this._columnMetadata[startColumn + i] = range.columnMetadata[i];\n }\n });\n }\n\n // TODO: make this handle A1 ranges as well?\n private _addSheetIdToRange(range: GridRangeWithOptionalWorksheetId) {\n if (range.sheetId && range.sheetId !== this.sheetId) {\n throw new Error('Leave sheet ID blank or set to matching ID of this sheet');\n }\n return {\n ...range,\n sheetId: this.sheetId,\n };\n }\n\n\n // PROPERTY GETTERS //////////////////////////////////////////////////////////////////////////////\n\n private _getProp<T extends keyof WorksheetProperties>(param: T): WorksheetProperties[T] {\n this._ensureInfoLoaded();\n // see note about asserting info loaded on GoogleSpreasheet\n return this._rawProperties![param];\n }\n // eslint-disable-line no-unused-vars\n private _setProp<T extends keyof WorksheetProperties>(_param: T, _newVal: WorksheetProperties[T]) {\n throw new Error('Do not update directly - use `updateProperties()`');\n }\n\n get sheetId() { return this._getProp('sheetId'); }\n get title() { return this._getProp('title'); }\n get index() { return this._getProp('index'); }\n get sheetType() { return this._getProp('sheetType'); }\n get gridProperties() { return this._getProp('gridProperties'); }\n get hidden() { return this._getProp('hidden'); }\n get tabColor() { return this._getProp('tabColor'); }\n get rightToLeft() { return this._getProp('rightToLeft'); }\n get protectedRanges() { return this._protectedRanges; }\n private get _headerRange() {\n return `A${this._headerRowIndex}:${this.lastColumnLetter}${this._headerRowIndex}`;\n }\n\n set sheetId(newVal: WorksheetProperties['sheetId']) { this._setProp('sheetId', newVal); }\n set title(newVal: WorksheetProperties['title']) { this._setProp('title', newVal); }\n set index(newVal: WorksheetProperties['index']) { this._setProp('index', newVal); }\n set sheetType(newVal: WorksheetProperties['sheetType']) { this._setProp('sheetType', newVal); }\n set gridProperties(newVal: WorksheetProperties['gridProperties']) { this._setProp('gridProperties', newVal); }\n set hidden(newVal: WorksheetProperties['hidden']) { this._setProp('hidden', newVal); }\n set tabColor(newVal: WorksheetProperties['tabColor']) { this._setProp('tabColor', newVal); }\n set rightToLeft(newVal: WorksheetProperties['rightToLeft']) { this._setProp('rightToLeft', newVal); }\n\n get rowCount() {\n this._ensureInfoLoaded();\n return this.gridProperties.rowCount;\n }\n get columnCount() {\n this._ensureInfoLoaded();\n return this.gridProperties.columnCount;\n }\n\n get a1SheetName() { return `'${this.title.replace(/'/g, \"''\")}'`; }\n get encodedA1SheetName() { return encodeURIComponent(this.a1SheetName); }\n get lastColumnLetter() {\n // TODO: double check behaviour if data not loaded\n return this.columnCount ? columnToLetter(this.columnCount) : '';\n }\n\n\n // CELLS-BASED INTERACTIONS //////////////////////////////////////////////////////////////////////\n\n get cellStats() {\n let allCells = _.flatten(this._cells);\n allCells = _.compact(allCells);\n return {\n nonEmpty: _.filter(allCells, (c) => c.value).length,\n loaded: allCells.length,\n total: this.rowCount * this.columnCount,\n };\n }\n\n getCellByA1(a1Address: A1Address) {\n const split = a1Address.match(/([A-Z]+)([0-9]+)/);\n if (!split) throw new Error(`Cell address \"${a1Address}\" not valid`);\n const columnIndex = letterToColumn(split[1]);\n const rowIndex = parseInt(split[2]);\n return this.getCell(rowIndex - 1, columnIndex - 1);\n }\n\n getCell(rowIndex: RowIndex, columnIndex: ColumnIndex) {\n if (rowIndex < 0 || columnIndex < 0) throw new Error('Min coordinate is 0, 0');\n if (rowIndex >= this.rowCount || columnIndex >= this.columnCount) {\n throw new Error(`Out of bounds, sheet is ${this.rowCount} by ${this.columnCount}`);\n }\n\n if (!_.get(this._cells, `[${rowIndex}][${columnIndex}]`)) {\n throw new Error('This cell has not been loaded yet');\n }\n return this._cells[rowIndex][columnIndex];\n }\n\n async loadCells(sheetFilters?: DataFilterWithoutWorksheetId | DataFilterWithoutWorksheetId[]) {\n // load the whole sheet\n if (!sheetFilters) return this._spreadsheet.loadCells(this.a1SheetName);\n\n const filtersArray = _.isArray(sheetFilters) ? sheetFilters : [sheetFilters];\n const filtersArrayWithSheetId: DataFilter[] = _.map(filtersArray, (filter) => {\n // add sheet name to A1 ranges\n if (_.isString(filter)) {\n if (filter.startsWith(this.a1SheetName)) return filter;\n return `${this.a1SheetName}!${filter}`;\n }\n if (_.isObject(filter)) {\n // TODO: detect and support DeveloperMetadata filters\n\n // check if the user passed in a sheet id\n const filterAny = filter as any;\n if (filterAny.sheetId && filterAny.sheetId !== this.sheetId) {\n throw new Error('Leave sheet ID blank or set to matching ID of this sheet');\n }\n\n return { sheetId: this.sheetId, ...filter };\n }\n throw new Error('Each filter must be a A1 range string or gridrange object');\n });\n return this._spreadsheet.loadCells(filtersArrayWithSheetId);\n }\n\n async saveUpdatedCells() {\n const cellsToSave = _.filter(_.flatten(this._cells), { _isDirty: true });\n if (cellsToSave.length) {\n await this.saveCells(cellsToSave);\n }\n // TODO: do we want to return stats? or the cells that got updated?\n }\n\n async saveCells(cellsToUpdate: GoogleSpreadsheetCell[]) {\n // we send an individual \"updateCells\" request for each cell\n // because the fields that are udpated for each group are the same\n // and we dont want to accidentally overwrite something\n const requests = _.map(cellsToUpdate, (cell) => cell._getUpdateRequest());\n const responseRanges = _.map(cellsToUpdate, (c) => `${this.a1SheetName}!${c.a1Address}`);\n\n // if nothing is being updated the request returned is just `null`\n // so we make sure at least 1 request is valid - otherwise google throws a 400\n if (!_.compact(requests).length) {\n throw new Error('At least one cell must have something to update');\n }\n\n await this._spreadsheet._makeBatchUpdateRequest(requests, responseRanges);\n }\n\n // SAVING THIS FOR FUTURE USE\n // puts the cells that need updating into batches\n // async updateCellsByBatches() {\n // // saving this code, but it's problematic because each group must have the same update fields\n // const cellsByRow = _.groupBy(cellsToUpdate, 'rowIndex');\n // const groupsToSave = [];\n // _.each(cellsByRow, (cells, rowIndex) => {\n // let cellGroup = [];\n // _.each(cells, (c) => {\n // if (!cellGroup.length) {\n // cellGroup.push(c);\n // } else if (\n // cellGroup[cellGroup.length - 1].columnIndex ===\n // c.columnIndex - 1\n // ) {\n // cellGroup.push(c);\n // } else {\n // groupsToSave.push(cellGroup);\n // cellGroup = [];\n // }\n // });\n // groupsToSave.push(cellGroup);\n // });\n // const requests = _.map(groupsToSave, (cellGroup) => ({\n // updateCells: {\n // rows: [\n // {\n // values: _.map(cellGroup, (cell) => ({\n // ...cell._draftData.value && {\n // userEnteredValue: { [cell._draftData.valueType]: cell._draftData.value },\n // },\n // ...cell._draftData.note !== undefined && {\n // note: cell._draftData.note ,\n // },\n // ...cell._draftData.userEnteredFormat && {\n // userEnteredValue: cell._draftData.userEnteredFormat,\n // },\n // })),\n // },\n // ],\n // fields: 'userEnteredValue,note,userEnteredFormat',\n // start: {\n // sheetId: this.sheetId,\n // rowIndex: cellGroup[0].rowIndex,\n // columnIndex: cellGroup[0].columnIndex,\n // },\n // },\n // }));\n // const responseRanges = _.map(groupsToSave, (cellGroup) => {\n // let a1Range = cellGroup[0].a1Address;\n // if (cellGroup.length > 1)\n // a1Range += `:${cellGroup[cellGroup.length - 1].a1Address}`;\n // return `${cellGroup[0]._sheet.a1SheetName}!${a1Range}`;\n // });\n // }\n\n // ROW BASED FUNCTIONS ///////////////////////////////////////////////////////////////////////////\n\n async _ensureHeaderRowLoaded() {\n if (!this._headerValues) {\n await this.loadHeaderRow();\n }\n }\n\n async loadHeaderRow(headerRowIndex?: number) {\n if (headerRowIndex !== undefined) this._headerRowIndex = headerRowIndex;\n const rows = await this.getCellsInRange(this._headerRange);\n this._processHeaderRow(rows);\n }\n\n private _processHeaderRow(rows: any[]) {\n if (!rows) {\n throw new Error('No values in the header row - fill the first row with header values before trying to interact with rows');\n }\n this._headerValues = _.map(rows[0], (header) => header?.trim());\n if (!_.compact(this.headerValues).length) {\n throw new Error('All your header cells are blank - fill the first row with header values before trying to interact with rows');\n }\n checkForDuplicateHeaders(this.headerValues);\n }\n\n async setHeaderRow(headerValues: string[], headerRowIndex?: number) {\n if (!headerValues) return;\n if (headerValues.length > this.columnCount) {\n throw new Error(`Sheet is not large enough to fit ${headerValues.length} columns. Resize the sheet first.`);\n }\n const trimmedHeaderValues = _.map(headerValues, (h) => h?.trim());\n checkForDuplicateHeaders(trimmedHeaderValues);\n\n if (!_.compact(trimmedHeaderValues).length) {\n throw new Error('All your header cells are blank -');\n }\n\n if (headerRowIndex) this._headerRowIndex = headerRowIndex;\n\n const response = await this._spreadsheet.sheetsApi.put(\n `values/${this.encodedA1SheetName}!${this._headerRowIndex}:${this._headerRowIndex}`,\n {\n searchParams: {\n valueInputOption: 'USER_ENTERED', // other option is RAW\n includeValuesInResponse: true,\n },\n json: {\n range: `${this.a1SheetName}!${this._headerRowIndex}:${this._headerRowIndex}`,\n majorDimension: 'ROWS',\n values: [[\n ...trimmedHeaderValues,\n // pad the rest of the row with empty values to clear them all out\n ..._.times(this.columnCount - trimmedHeaderValues.length, () => ''),\n ]],\n },\n }\n );\n const data = await response.json<any>();\n this._headerValues = data.updatedData.values[0];\n }\n\n // TODO: look at these types\n async addRows(\n rows: RawRowData[],\n options: AddRowOptions = {}\n ) {\n // adds multiple rows in one API interaction using the append endpoint\n\n // each row can be an array or object\n // an array is just cells\n // ex: ['column 1', 'column 2', 'column 3']\n // an object must use the header row values as keys\n // ex: { col1: 'column 1', col2: 'column 2', col3: 'column 3' }\n\n // google bug that does not handle colons in sheet names\n // see https://issuetracker.google.com/issues/150373119\n if (this.title.includes(':')) {\n throw new Error('Please remove the \":\" from your sheet title. There is a bug with the google API which breaks appending rows if any colons are in the sheet title.');\n }\n\n if (!_.isArray(rows)) throw new Error('You must pass in an array of row values to append');\n\n await this._ensureHeaderRowLoaded();\n\n // convert each row into an array of cell values rather than the key/value object\n const rowsAsArrays: RawRowData[] = [];\n _.each(rows, (row) => {\n let rowAsArray;\n if (_.isArray(row)) {\n rowAsArray = row;\n } else if (_.isObject(row)) {\n rowAsArray = [];\n for (let i = 0; i < this.headerValues.length; i++) {\n const propName = this.headerValues[i];\n rowAsArray[i] = row[propName];\n }\n } else {\n throw new Error('Each row must be an object or an array');\n }\n rowsAsArrays.push(rowAsArray);\n });\n\n const response = await this._spreadsheet.sheetsApi.post(\n `values/${this.encodedA1SheetName}!A${this._headerRowIndex}:append`,\n {\n searchParams: {\n valueInputOption: options.raw ? 'RAW' : 'USER_ENTERED',\n insertDataOption: options.insert ? 'INSERT_ROWS' : 'OVERWRITE',\n includeValuesInResponse: true,\n },\n json: {\n values: rowsAsArrays,\n },\n }\n );\n\n // extract the new row number from the A1-notation data range in the response\n // ex: in \"'Sheet8!A2:C2\" -- we want the `2`\n const data = await response.json<any>();\n const { updatedRange } = data.updates;\n let rowNumber = updatedRange.match(/![A-Z]+([0-9]+):?/)[1];\n rowNumber = parseInt(rowNumber);\n\n\n this._ensureInfoLoaded();\n // if new rows were added, we need update sheet.rowRount\n if (options.insert) {\n this._rawProperties!.gridProperties.rowCount += rows.length;\n } else if (rowNumber + rows.length > this.rowCount) {\n // have to subtract 1 since one row was inserted at rowNumber\n this._rawProperties!.gridProperties.rowCount = rowNumber + rows.length - 1;\n }\n\n return _.map(data.updates.updatedData.values, (rowValues) => {\n const row = new GoogleSpreadsheetRow(this, rowNumber++, rowValues);\n return row;\n });\n }\n\n /** add a single row - see addRows for more info */\n async addRow(rowValues: RawRowData, options?: AddRowOptions) {\n const rows = await this.addRows([rowValues], options);\n return rows[0];\n }\n\n\n private _rowCache: GoogleSpreadsheetRow[] = [];\n async getRows<T extends Record<string, any>>(\n options?: {\n /** skip first N rows */\n offset?: number,\n /** limit number of rows fetched */\n limit?: number,\n }\n ) {\n // https://developers.google.com/sheets/api/guides/migration\n // v4 API does not have equivalents for the row-order query parameters provided\n // Reverse-order is trivial; simply process the returned values array in reverse order.\n // Order by column is not supported for reads, but it is possible to sort the data then read\n\n // v4 API does not currently have a direct equivalent for the Sheets API v3 structured queries\n // However, you can retrieve the relevant data and sort through it as needed in your application\n const offset = options?.offset || 0;\n const limit = options?.limit || this.rowCount - 1;\n\n const firstRow = 1 + this._headerRowIndex + offset;\n const lastRow = firstRow + limit - 1; // inclusive so we subtract 1\n\n let rawRows;\n if (this._headerValues) {\n const lastColumn = columnToLetter(this.headerValues.length);\n rawRows = await this.getCellsInRange(\n `A${firstRow}:${lastColumn}${lastRow}`\n );\n } else {\n const result = await this.batchGetCellsInRange([this._headerRange,\n `A${firstRow}:${this.lastColumnLetter}${lastRow}`]);\n this._processHeaderRow(result[0]);\n rawRows = result[1];\n }\n\n if (!rawRows) return [];\n\n const rows = [];\n let rowNum = firstRow;\n for (let i = 0; i < rawRows.length; i++) {\n const row = new GoogleSpreadsheetRow<T>(this, rowNum++, rawRows[i]);\n this._rowCache[row.rowNumber] = row;\n rows.push(row);\n }\n return rows;\n }\n\n /**\n * @internal\n * Used internally to update row numbers after deleting rows.\n * Should not be called directly.\n * */\n _shiftRowCache(deletedRowNumber: number) {\n delete this._rowCache[deletedRowNumber];\n this._rowCache.forEach((row) => {\n if (row.rowNumber > deletedRowNumber) {\n row._updateRowNumber(row.rowNumber - 1);\n }\n });\n }\n\n async clearRows(\n options?: {\n start?: number,\n end?: number,\n }\n ) {\n // default to first row after header\n const startRowIndex = options?.start || this._headerRowIndex + 1;\n const endRowIndex = options?.end || this.rowCount;\n await this._spreadsheet.sheetsApi.post(`values/${this.encodedA1SheetName}!${startRowIndex}:${endRowIndex}:clear`);\n this._rowCache.forEach((row) => {\n if (row.rowNumber >= startRowIndex && row.rowNumber <= endRowIndex) row._clearRowData();\n });\n }\n\n // BASIC PROPS ///////////////////////////////////////////////////////////////////////////////////\n /** @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateSheetPropertiesRequest */\n async updateProperties(properties: Partial<Omit<WorksheetProperties, 'sheetId'>>) {\n // Request type = `updateSheetProperties`\n\n return this._makeSingleUpdateRequest('updateSheetProperties', {\n properties: {\n sheetId: this.sheetId,\n ...properties,\n },\n fields: getFieldMask(properties),\n });\n }\n\n /**\n * passes through the call to updateProperties to update only the gridProperties object\n */\n async updateGridProperties(gridProperties: WorksheetGridProperties) {\n return this.updateProperties({ gridProperties });\n }\n\n /** resize, internally just calls updateGridProperties */\n async resize(gridProperties: Pick<WorksheetGridProperties, 'rowCount' | 'columnCount'>) {\n return this.updateGridProperties(gridProperties);\n }\n\n /**\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#updatedimensionpropertiesrequest\n */\n async updateDimensionProperties(\n columnsOrRows: WorksheetDimension,\n properties: WorksheetDimensionProperties,\n bounds: Partial<DimensionRangeIndexes>\n ) {\n // Request type = `updateDimensionProperties`\n\n Object.keys(properties);\n\n return this._makeSingleUpdateRequest('updateDimensionProperties', {\n range: {\n sheetId: this.sheetId,\n dimension: columnsOrRows,\n ...bounds,\n },\n properties,\n fields: getFieldMask(properties as any),\n });\n }\n\n // OTHER /////////////////////////////////////////////////////////////////////////////////////////\n\n // this uses the \"values\" getter and does not give all the info about the cell contents\n // it is used internally when loading header cells\n async getCellsInRange(a1Range: A1Range, options?: GetValuesRequestOptions) {\n const response = await this._spreadsheet.sheetsApi.get(`values/${this.encodedA1SheetName}!${a1Range}`, {\n searchParams: options,\n });\n const data = await response.json<any>();\n return data.values;\n }\n\n async batchGetCellsInRange(a1Ranges: A1Range[], options?: GetValuesRequestOptions) {\n const ranges = a1Ranges.map((r) => `ranges=${this.encodedA1SheetName}!${r}`).join('&');\n const response = await this._spreadsheet.sheetsApi.get(`values:batchGet?${ranges}`, {\n searchParams: options,\n });\n const data = await response.json<any>();\n return data.valueRanges.map((r: any) => r.values);\n }\n\n async updateNamedRange() {\n // Request type = `updateNamedRange`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateNamedRangeRequest\n }\n\n async addNamedRange() {\n // Request type = `addNamedRange`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddNamedRangeRequest\n }\n\n async deleteNamedRange() {\n // Request type = `deleteNamedRange`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteNamedRangeRequest\n }\n\n async repeatCell() {\n // Request type = `repeatCell`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#RepeatCellRequest\n }\n\n async autoFill() {\n // Request type = `autoFill`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AutoFillRequest\n }\n\n async cutPaste() {\n // Request type = `cutPaste`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CutPasteRequest\n }\n\n async copyPaste() {\n // Request type = `copyPaste`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CopyPasteRequest\n }\n\n // TODO: check types on these ranges\n\n /**\n * Merges all cells in the range\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#MergeCellsRequest\n */\n async mergeCells(range: GridRangeWithOptionalWorksheetId, mergeType = 'MERGE_ALL') {\n await this._makeSingleUpdateRequest('mergeCells', {\n mergeType,\n range: this._addSheetIdToRange(range),\n });\n }\n\n /**\n * Unmerges cells in the given range\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UnmergeCellsRequest\n */\n async unmergeCells(range: GridRangeWithOptionalWorksheetId) {\n await this._makeSingleUpdateRequest('unmergeCells', {\n range: this._addSheetIdToRange(range),\n });\n }\n\n async updateBorders() {\n // Request type = `updateBorders`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateBordersRequest\n }\n\n async addFilterView() {\n // Request type = `addFilterView`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddFilterViewRequest\n }\n\n async appendCells() {\n // Request type = `appendCells`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AppendCellsRequest\n }\n\n async clearBasicFilter() {\n // Request type = `clearBasicFilter`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#ClearBasicFilterRequest\n }\n\n async deleteDimension() {\n // Request type = `deleteDimension`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDimensionRequest\n }\n\n async deleteEmbeddedObject() {\n // Request type = `deleteEmbeddedObject`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteEmbeddedObjectRequest\n }\n\n async deleteFilterView() {\n // Request type = `deleteFilterView`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteFilterViewRequest\n }\n\n async duplicateFilterView() {\n // Request type = `duplicateFilterView`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DuplicateFilterViewRequest\n }\n\n /**\n * Duplicate worksheet within the document\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DuplicateSheetRequest\n */\n async duplicate(\n options?: {\n id?: WorksheetId,\n title?: string,\n index?: number,\n }\n ) {\n const response = await this._makeSingleUpdateRequest('duplicateSheet', {\n sourceSheetId: this.sheetId,\n ...options?.index !== undefined && { insertSheetIndex: options.index },\n ...options?.id && { newSheetId: options.id },\n ...options?.title && { newSheetName: options.title },\n });\n const newSheetId = response.properties.sheetId;\n return this._spreadsheet.sheetsById[newSheetId];\n }\n\n async findReplace() {\n // Request type = `findReplace`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#FindReplaceRequest\n }\n\n /**\n * Inserts rows or columns at a particular index\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#InsertDimensionRequest\n */\n async insertDimension(\n columnsOrRows: WorksheetDimension,\n rangeIndexes: DimensionRangeIndexes,\n inheritFromBefore?: boolean\n ) {\n if (!columnsOrRows) throw new Error('You need to specify a dimension. i.e. COLUMNS|ROWS');\n if (!_.isObject(rangeIndexes)) throw new Error('`range` must be an object containing `startIndex` and `endIndex`');\n if (!_.isInteger(rangeIndexes.startIndex) || rangeIndexes.startIndex < 0) throw new Error('range.startIndex must be an integer >=0');\n if (!_.isInteger(rangeIndexes.endIndex) || rangeIndexes.endIndex < 0) throw new Error('range.endIndex must be an integer >=0');\n if (rangeIndexes.endIndex <= rangeIndexes.startIndex) throw new Error('range.endIndex must be greater than range.startIndex');\n\n // default inheritFromBefore to true - unless inserting in the first row/column\n if (inheritFromBefore === undefined) {\n inheritFromBefore = rangeIndexes.startIndex > 0;\n }\n\n // do not allow inheritFromBefore if inserting at first row/column\n if (inheritFromBefore && rangeIndexes.startIndex === 0) {\n throw new Error('Cannot set inheritFromBefore to true if inserting in first row/column');\n }\n\n return this._makeSingleUpdateRequest('insertDimension', {\n range: {\n sheetId: this.sheetId,\n dimension: columnsOrRows,\n startIndex: rangeIndexes.startIndex,\n endIndex: rangeIndexes.endIndex,\n },\n inheritFromBefore,\n });\n }\n\n /**\n * insert empty cells in a range, shifting existing cells in the specified direction\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#InsertRangeRequest\n */\n async insertRange(\n /** the range to insert new cells into */\n range: GridRangeWithOptionalWorksheetId,\n /** which direction to shift existing cells - ROWS (shift down) or COLUMNS (shift right) */\n shiftDimension: WorksheetDimension\n ) {\n return this._makeSingleUpdateRequest('insertRange', {\n range: this._addSheetIdToRange(range),\n shiftDimension,\n });\n }\n\n async moveDimension() {\n // Request type = `moveDimension`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#MoveDimensionRequest\n }\n\n async updateEmbeddedObjectPosition() {\n // Request type = `updateEmbeddedObjectPosition`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateEmbeddedObjectPositionRequest\n }\n\n async pasteData() {\n // Request type = `pasteData`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#PasteDataRequest\n }\n\n async textToColumns() {\n // Request type = `textToColumns`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#TextToColumnsRequest\n }\n\n async updateFilterView() {\n // Request type = `updateFilterView`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateFilterViewRequest\n }\n\n async deleteRange() {\n // Request type = `deleteRange`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteRangeRequest\n }\n\n async appendDimension() {\n // Request type = `appendDimension`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AppendDimensionRequest\n }\n\n async addConditionalFormatRule() {\n // Request type = `addConditionalFormatRule`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddConditionalFormatRuleRequest\n }\n\n async updateConditionalFormatRule() {\n // Request type = `updateConditionalFormatRule`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateConditionalFormatRuleRequest\n }\n\n async deleteConditionalFormatRule() {\n // Request type = `deleteConditionalFormatRule`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteConditionalFormatRuleRequest\n }\n\n async sortRange() {\n // Request type = `sortRange`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SortRangeRequest\n }\n\n /**\n * Sets (or unsets) a data validation rule to every cell in the range\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SetDataValidationRequest\n */\n async setDataValidation(\n range: GridRangeWithOptionalWorksheetId,\n /** data validation rule object, or set to false to clear an existing rule */\n rule: DataValidationRule | false\n ) {\n return this._makeSingleUpdateRequest('setDataValidation', {\n range: {\n sheetId: this.sheetId,\n ...range,\n },\n ...rule && { rule },\n });\n }\n\n async setBasicFilter() {\n // Request type = `setBasicFilter`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SetBasicFilterRequest\n }\n\n /**\n * add a new protected range to the sheet\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddProtectedRangeRequest\n */\n async addProtectedRange(protectedRange: ProtectedRange) {\n if (!protectedRange.range && !protectedRange.namedRangeId) {\n throw new Error('No range specified: either range or namedRangeId is required');\n }\n return this._makeSingleUpdateRequest('addProtectedRange', {\n protectedRange,\n });\n }\n\n /**\n * update an existing protected range\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateProtectedRangeRequest\n */\n async updateProtectedRange(protectedRangeId: Integer, protectedRange: Partial<ProtectedRange>) {\n return this._makeSingleUpdateRequest('updateProtectedRange', {\n protectedRange: { protectedRangeId, ...protectedRange },\n fields: getFieldMask(protectedRange as Record<string, unknown>),\n });\n }\n\n /**\n * delete a protected range by ID\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteProtectedRangeRequest\n */\n async deleteProtectedRange(protectedRangeId: Integer) {\n return this._makeSingleUpdateRequest('deleteProtectedRange', {\n protectedRangeId,\n });\n }\n\n /**\n * auto-resize rows or columns to fit their contents\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AutoResizeDimensionsRequest\n */\n async autoResizeDimensions(\n /** which dimension to auto-resize */\n columnsOrRows: WorksheetDimension,\n /** start and end indexes (optional, defaults to all) */\n rangeIndexes?: DimensionRangeIndexes\n ) {\n return this._makeSingleUpdateRequest('autoResizeDimensions', {\n dimensions: {\n sheetId: this.sheetId,\n dimension: columnsOrRows,\n ...rangeIndexes,\n },\n });\n }\n\n async addChart() {\n // Request type = `addChart`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddChartRequest\n }\n\n async updateChartSpec() {\n // Request type = `updateChartSpec`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateChartSpecRequest\n }\n\n async updateBanding() {\n // Request type = `updateBanding`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateBandingRequest\n }\n\n async addBanding() {\n // Request type = `addBanding`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddBandingRequest\n }\n\n async deleteBanding() {\n // Request type = `deleteBanding`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteBandingRequest\n }\n\n async createDeveloperMetadata() {\n // Request type = `createDeveloperMetadata`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CreateDeveloperMetadataRequest\n }\n\n async updateDeveloperMetadata() {\n // Request type = `updateDeveloperMetadata`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateDeveloperMetadataRequest\n }\n\n async deleteDeveloperMetadata() {\n // Request type = `deleteDeveloperMetadata`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDeveloperMetadataRequest\n }\n\n async randomizeRange() {\n // Request type = `randomizeRange`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#RandomizeRangeRequest\n }\n\n async addDimensionGroup() {\n // Request type = `addDimensionGroup`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddDimensionGroupRequest\n }\n\n async deleteDimensionGroup() {\n // Request type = `deleteDimensionGroup`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDimensionGroupRequest\n }\n\n async updateDimensionGroup() {\n // Request type = `updateDimensionGroup`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateDimensionGroupRequest\n }\n\n async trimWhitespace() {\n // Request type = `trimWhitespace`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#TrimWhitespaceRequest\n }\n\n async deleteDuplicates() {\n // Request type = `deleteDuplicates`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDuplicatesRequest\n }\n\n async addSlicer() {\n // Request type = `addSlicer`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddSlicerRequest\n }\n\n async updateSlicerSpec() {\n // Request type = `updateSlicerSpec`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateSlicerSpecRequest\n }\n\n /** delete this worksheet */\n async delete() {\n return this._spreadsheet.deleteSheet(this.sheetId);\n }\n\n /**\n * copies this worksheet into another document/spreadsheet\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.sheets/copyTo\n * */\n async copyToSpreadsheet(destinationSpreadsheetId: SpreadsheetId) {\n const req = this._spreadsheet.sheetsApi.post(`sheets/${this.sheetId}:copyTo`, {\n json: {\n destinationSpreadsheetId,\n },\n });\n const data = await req.json<any>();\n return data;\n }\n\n /** clear data in the sheet - either the entire sheet or a specific range */\n async clear(\n /** optional A1 range to clear - defaults to entire sheet */\n a1Range?: A1Range\n ) {\n const range = a1Range ? `!${a1Range}` : '';\n // sheet name without ie 'sheet1' rather than 'sheet1'!A1:B5 is all cells\n await this._spreadsheet.sheetsApi.post(`values/${this.encodedA1SheetName}${range}:clear`);\n this.resetLocalCache(true);\n }\n\n /** exports worksheet as CSV file (comma-separated values) */\n async downloadAsCSV(): Promise<ArrayBuffer>;\n async downloadAsCSV(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;\n async downloadAsCSV(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;\n async downloadAsCSV(returnStreamInsteadOfBuffer = false) {\n return this._spreadsheet._downloadAs('csv', this.sheetId, returnStreamInsteadOfBuffer);\n }\n /** exports worksheet as TSC file (tab-separated values) */\n async downloadAsTSV(): Promise<ArrayBuffer>;\n async downloadAsTSV(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;\n async downloadAsTSV(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;\n async downloadAsTSV(returnStreamInsteadOfBuffer = false) {\n return this._spreadsheet._downloadAs('tsv', this.sheetId, returnStreamInsteadOfBuffer);\n }\n /** exports worksheet as PDF */\n async downloadAsPDF(): Promise<ArrayBuffer>;\n async downloadAsPDF(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;\n async downloadAsPDF(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;\n async downloadAsPDF(returnStreamInsteadOfBuffer = false) {\n return this._spreadsheet._downloadAs('pdf', this.sheetId, returnStreamInsteadOfBuffer);\n }\n}\n","/** single type to handle all valid auth types */\nexport type GoogleApiAuth =\n // this simple interface should cover all google-auth-library auth methods\n | { getRequestHeaders: () => Promise<any> }\n // used to pass in an API key only\n | { apiKey: string }\n // used to pass in a raw token\n | { token: string };\n\nexport enum AUTH_MODES {\n GOOGLE_AUTH_CLIENT = 'google_auth',\n RAW_ACCESS_TOKEN = 'raw_access_token',\n API_KEY = 'api_key'\n}\n","import ky, { HTTPError, KyInstance } from 'ky'; // eslint-disable-line import/no-extraneous-dependencies\nimport * as _ from './toolkit';\nimport { GoogleSpreadsheetWorksheet } from './GoogleSpreadsheetWorksheet';\nimport { getFieldMask } from './utils';\nimport {\n DataFilter, GridRange, NamedRangeId, ProtectedRange,\n SpreadsheetId, SpreadsheetProperties, WorksheetId, WorksheetProperties,\n} from './types/sheets-types';\nimport { PermissionRoles, PermissionsList, PublicPermissionRoles } from './types/drive-types';\nimport { RecursivePartial } from './types/util-types';\nimport { AUTH_MODES, GoogleApiAuth } from './types/auth-types';\n\n\nconst SHEETS_API_BASE_URL = 'https://sheets.googleapis.com/v4/spreadsheets';\nconst DRIVE_API_BASE_URL = 'https://www.googleapis.com/drive/v3/files';\n\nconst EXPORT_CONFIG: Record<string, { singleWorksheet?: boolean }> = {\n html: {},\n zip: {},\n xlsx: {},\n ods: {},\n csv: { singleWorksheet: true },\n tsv: { singleWorksheet: true },\n pdf: { singleWorksheet: true },\n};\ntype ExportFileTypes = keyof typeof EXPORT_CONFIG;\n\n\n\n\nfunction getAuthMode(auth: GoogleApiAuth) {\n if ('getRequestHeaders' in auth) return AUTH_MODES.GOOGLE_AUTH_CLIENT;\n if ('token' in auth && auth.token) return AUTH_MODES.RAW_ACCESS_TOKEN;\n // google-auth-library now has an empty `apiKey` property\n if ('apiKey' in auth && auth.apiKey) return AUTH_MODES.API_KEY;\n throw new Error('Invalid auth');\n}\n\nasync function getRequestAuthConfig(auth: GoogleApiAuth): Promise<{\n headers?: Record<string, string>;\n searchParams?: Record<string, string>\n}> {\n // google-auth-libary methods all can call this method to get the right headers\n // JWT | OAuth2Client | GoogleAuth | Impersonate | AuthClient\n if ('getRequestHeaders' in auth) {\n const headers = await auth.getRequestHeaders();\n\n // google-auth-library v10 uses a Headers object rather than a plain object\n if ('entries' in headers) {\n return { headers: Object.fromEntries(headers.entries()) };\n } if (_.isObject(headers)) {\n return { headers: headers as Record<string, string> };\n }\n throw new Error('unexpected headers returned from getRequestHeaders');\n }\n\n // API key only access passes through the api key as a query param\n // (note this can only provide read-only access)\n if ('apiKey' in auth && auth.apiKey) {\n return { searchParams: { key: auth.apiKey } };\n }\n\n // RAW ACCESS TOKEN\n if ('token' in auth && auth.token) {\n return { headers: { Authorization: `Bearer ${auth.token}` } };\n }\n\n throw new Error('Invalid auth');\n}\n\n/**\n * Google Sheets document\n *\n * @description\n * **This class represents an entire google spreadsheet document**\n * Provides methods to interact with document metadata/settings, formatting, manage sheets, and acts as the main gateway to interacting with sheets and data that the document contains.q\n *\n */\nexport class GoogleSpreadsheet {\n readonly spreadsheetId: string;\n\n public auth: GoogleApiAuth;\n get authMode() {\n return getAuthMode(this.auth);\n }\n\n private _rawSheets: any;\n private _rawProperties = null as SpreadsheetProperties | null;\n private _spreadsheetUrl = null as string | null;\n private _deleted = false;\n\n /**\n * Sheets API [ky](https://github.com/sindresorhus/ky?tab=readme-ov-file#kycreatedefaultoptions) instance\n * authentication is automatically attached\n * can be used if unsupported sheets calls need to be made\n * @see https://developers.google.com/sheets/api/reference/rest\n * */\n readonly sheetsApi: KyInstance;\n\n /**\n * Drive API [ky](https://github.com/sindresorhus/ky?tab=readme-ov-file#kycreatedefaultoptions) instance\n * authentication automatically attached\n * can be used if unsupported drive calls need to be made\n * @topic permissions\n * @see https://developers.google.com/drive/api/v3/reference\n * */\n readonly driveApi: KyInstance;\n\n\n /**\n * initialize new GoogleSpreadsheet\n * @category Initialization\n * */\n constructor(\n /** id of google spreadsheet doc */\n spreadsheetId: SpreadsheetId,\n /** authentication to use with Google Sheets API */\n auth: GoogleApiAuth\n ) {\n this.spreadsheetId = spreadsheetId;\n this.auth = auth;\n\n this._rawSheets = {};\n this._spreadsheetUrl = null;\n\n // create a ky instance with sheet root URL and hooks to handle auth\n this.sheetsApi = ky.create({\n prefixUrl: `${SHEETS_API_BASE_URL}/${spreadsheetId}`,\n timeout: 180_000,\n hooks: {\n beforeRequest: [(r) => this._setAuthRequestHook(r)],\n beforeError: [(e) => this._errorHook(e)],\n },\n });\n this.driveApi = ky.create({\n prefixUrl: `${DRIVE_API_BASE_URL}/${spreadsheetId}`,\n hooks: {\n beforeRequest: [(r) => this._setAuthRequestHook(r)],\n beforeError: [(e) => this._errorHook(e)],\n },\n });\n }\n\n\n // INTERNAL UTILITY FUNCTIONS ////////////////////////////////////////////////////////////////////\n\n /** @internal */\n async _setAuthRequestHook(req: Request): Promise<Request> {\n const authConfig = await getRequestAuthConfig(this.auth);\n if (authConfig.headers) {\n Object.entries(authConfig.headers).forEach(([key, val]) => {\n req.headers.set(key, String(val));\n });\n }\n\n if (authConfig.searchParams) {\n const url = new URL(req.url);\n Object.entries(authConfig.searchParams).forEach(([key, val]) => {\n url.searchParams.set(key, String(val));\n });\n // cannot change the URL with ky, so have to return a new request\n return new Request(url, req);\n }\n\n return req;\n }\n\n /** @internal */\n async _errorHook(error: HTTPError) {\n const { response } = error;\n const errorDataText = await response?.text();\n let errorData;\n try {\n errorData = JSON.parse(errorDataText);\n } catch (e) {\n // console.log('parsing json failed', errorDataText);\n }\n\n if (errorData) {\n // usually the error has a code and message, but occasionally not\n if (!errorData.error) return error;\n\n const { code, message } = errorData.error;\n error.message = `Google API error - [${code}] ${message}`;\n return error;\n }\n\n if (_.get(error, 'response.status') === 403) {\n if ('apiKey' in this.auth) {\n throw new Error('Sheet is private. Use authentication or make public. (see https://github.com/theoephraim/node-google-spreadsheet#a-note-on-authentication for details)');\n }\n }\n return error;\n }\n\n /** @internal */\n async _makeSingleUpdateRequest(requestType: string, requestParams: any) {\n const response = await this.sheetsApi.post(':batchUpdate', {\n json: {\n requests: [{ [requestType]: requestParams }],\n includeSpreadsheetInResponse: true,\n // responseRanges: [string]\n // responseIncludeGridData: true\n },\n });\n const data = await response.json<any>();\n\n this._updateRawProperties(data.updatedSpreadsheet.properties);\n _.each(data.updatedSpreadsheet.sheets, (s: any) => this._updateOrCreateSheet(s));\n // console.log('API RESPONSE', response.data.replies[0][requestType]);\n return data.replies[0][requestType];\n }\n\n // TODO: review these types\n // currently only used in batching cell updates\n /** @internal */\n async _makeBatchUpdateRequest(requests: any[], responseRanges?: string | string[]) {\n // this is used for updating batches of cells\n const response = await this.sheetsApi.post(':batchUpdate', {\n json: {\n requests,\n includeSpreadsheetInResponse: true,\n ...responseRanges && {\n responseIncludeGridData: true,\n ...responseRanges !== '*' && { responseRanges },\n },\n },\n });\n\n const data = await response.json<any>();\n this._updateRawProperties(data.updatedSpreadsheet.properties);\n _.each(data.updatedSpreadsheet.sheets, (s: any) => this._updateOrCreateSheet(s));\n }\n\n /** @internal */\n _ensureInfoLoaded() {\n if (!this._rawProperties) throw new Error('You must call `doc.loadInfo()` before accessing this property');\n }\n\n /** @internal */\n _updateRawProperties(newProperties: SpreadsheetProperties) { this._rawProperties = newProperties; }\n\n /** @internal */\n _updateOrCreateSheet(sheetInfo: { properties: WorksheetProperties, data: any, protectedRanges?: ProtectedRange[] }) {\n const { properties, data, protectedRanges } = sheetInfo;\n const { sheetId } = properties;\n if (!this._rawSheets[sheetId]) {\n this._rawSheets[sheetId] = new GoogleSpreadsheetWorksheet(this, properties, data, protectedRanges);\n } else {\n this._rawSheets[sheetId].updateRawData(properties, data, protectedRanges);\n }\n }\n\n // BASIC PROPS //////////////////////////////////////////////////////////////////////////////\n _getProp(param: keyof SpreadsheetProperties) {\n this._ensureInfoLoaded();\n // ideally ensureInfoLoaded would assert that _rawProperties is in fact loaded\n // but this is not currently possible in TS - see https://github.com/microsoft/TypeScript/issues/49709\n return this._rawProperties![param];\n }\n\n get title(): SpreadsheetProperties['title'] { return this._getProp('title'); }\n get locale(): SpreadsheetProperties['locale'] { return this._getProp('locale'); }\n get timeZone(): SpreadsheetProperties['timeZone'] { return this._getProp('timeZone'); }\n get autoRecalc(): SpreadsheetProperties['autoRecalc'] { return this._getProp('autoRecalc'); }\n get defaultFormat(): SpreadsheetProperties['defaultFormat'] { return this._getProp('defaultFormat'); }\n get spreadsheetTheme(): SpreadsheetProperties['spreadsheetTheme'] { return this._getProp('spreadsheetTheme'); }\n get iterativeCalculationSettings(): SpreadsheetProperties['iterativeCalculationSettings'] { return this._getProp('iterativeCalculationSettings'); }\n\n /**\n * update spreadsheet properties\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets#SpreadsheetProperties\n * */\n async updateProperties(properties: Partial<SpreadsheetProperties>) {\n await this._makeSingleUpdateRequest('updateSpreadsheetProperties', {\n properties,\n fields: getFieldMask(properties),\n });\n }\n\n // BASIC INFO ////////////////////////////////////////////////////////////////////////////////////\n async loadInfo(includeCells = false) {\n const response = await this.sheetsApi.get('', {\n searchParams: {\n ...includeCells && { includeGridData: true },\n },\n });\n const data = await response.json<any>();\n this._spreadsheetUrl = data.spreadsheetUrl;\n this._rawProperties = data.properties;\n data.sheets?.forEach((s: any) => this._updateOrCreateSheet(s));\n }\n\n resetLocalCache() {\n this._rawProperties = null;\n this._rawSheets = {};\n }\n\n // WORKSHEETS ////////////////////////////////////////////////////////////////////////////////////\n get sheetCount() {\n this._ensureInfoLoaded();\n return _.values(this._rawSheets).length;\n }\n\n get sheetsById(): Record<WorksheetId, GoogleSpreadsheetWorksheet> {\n this._ensureInfoLoaded();\n return this._rawSheets;\n }\n\n get sheetsByIndex(): GoogleSpreadsheetWorksheet[] {\n this._ensureInfoLoaded();\n return _.sortBy(this._rawSheets, 'index');\n }\n\n get sheetsByTitle(): Record<string, GoogleSpreadsheetWorksheet> {\n this._ensureInfoLoaded();\n return _.keyBy(this._rawSheets, 'title');\n }\n\n /**\n * Add new worksheet to document\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddSheetRequest\n * */\n async addSheet(\n properties: Partial<\n RecursivePartial<WorksheetProperties>\n & {\n headerValues: string[],\n headerRowIndex: number\n }\n > = {}\n ) {\n const response = await this._makeSingleUpdateRequest('addSheet', {\n properties: _.omit(properties, 'headerValues', 'headerRowIndex'),\n });\n // _makeSingleUpdateRequest already adds the sheet\n const newSheetId = response.properties.sheetId;\n const newSheet = this.sheetsById[newSheetId];\n\n if (properties.headerValues) {\n await newSheet.setHeaderRow(properties.headerValues, properties.headerRowIndex);\n }\n\n return newSheet;\n }\n\n /**\n * delete a worksheet\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteSheetRequest\n * */\n async deleteSheet(sheetId: WorksheetId) {\n await this._makeSingleUpdateRequest('deleteSheet', { sheetId });\n delete this._rawSheets[sheetId];\n }\n\n // NAMED RANGES //////////////////////////////////////////////////////////////////////////////////\n\n /**\n * create a new named range\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddNamedRangeRequest\n */\n async addNamedRange(\n /** name of new named range */\n name: string,\n /** GridRange object describing range */\n range: GridRange,\n /** id for named range (optional) */\n namedRangeId?: string\n ) {\n // TODO: add named range to local cache\n return this._makeSingleUpdateRequest('addNamedRange', {\n namedRange: {\n name,\n namedRangeId,\n range,\n },\n });\n }\n\n /**\n * delete a named range\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteNamedRangeRequest\n * */\n async deleteNamedRange(\n /** id of named range to delete */\n namedRangeId: NamedRangeId\n ) {\n // TODO: remove named range from local cache\n return this._makeSingleUpdateRequest('deleteNamedRange', { namedRangeId });\n }\n\n // LOADING CELLS /////////////////////////////////////////////////////////////////////////////////\n\n /** fetch cell data into local cache */\n async loadCells(\n /**\n * single filter or array of filters\n * strings are treated as A1 ranges, objects are treated as GridRange objects\n * pass nothing to fetch all cells\n * */\n filters?: DataFilter | DataFilter[]\n ) {\n // TODO: make it support DeveloperMetadataLookup objects\n\n\n\n // TODO: switch to this mode if using a read-only auth token?\n const readOnlyMode = this.authMode === AUTH_MODES.API_KEY;\n\n const filtersArray = _.isArray(filters) ? filters : [filters];\n const dataFilters = _.map(filtersArray, (filter) => {\n if (_.isString(filter)) {\n return readOnlyMode ? filter : { a1Range: filter };\n }\n if (_.isObject(filter)) {\n if (readOnlyMode) {\n throw new Error('Only A1 ranges are supported when fetching cells with read-only access (using only an API key)');\n }\n // TODO: make this support Developer Metadata filters\n return { gridRange: filter };\n }\n throw new Error('Each filter must be an A1 range string or a gridrange object');\n });\n\n let result;\n // when using an API key only, we must use the regular get endpoint\n // because :getByDataFilter requires higher access\n if (this.authMode === AUTH_MODES.API_KEY) {\n const params = new URLSearchParams();\n params.append('includeGridData', 'true');\n dataFilters.forEach((singleFilter) => {\n if (!_.isString(singleFilter)) {\n throw new Error('Only A1 ranges are supported when fetching cells with read-only access (using only an API key)');\n }\n params.append('ranges', singleFilter);\n });\n result = await this.sheetsApi.get('', {\n searchParams: params,\n });\n // otherwise we use the getByDataFilter endpoint because it is more flexible\n } else {\n result = await this.sheetsApi.post(':getByDataFilter', {\n json: {\n includeGridData: true,\n dataFilters,\n },\n });\n }\n\n const data = await result?.json<any>();\n _.each(data.sheets, (sheet: any) => { this._updateOrCreateSheet(sheet); });\n }\n\n // EXPORTING /////////////////////////////////////////////////////////////\n\n /**\n * export/download helper, not meant to be called directly (use downloadAsX methods on spreadsheet and worksheet instead)\n * @internal\n */\n async _downloadAs(\n fileType: ExportFileTypes,\n worksheetId: WorksheetId | undefined,\n returnStreamInsteadOfBuffer?: boolean\n ) {\n // see https://stackoverflow.com/questions/11619805/using-the-google-drive-api-to-download-a-spreadsheet-in-csv-format/51235960#51235960\n\n if (!EXPORT_CONFIG[fileType]) throw new Error(`unsupported export fileType - ${fileType}`);\n if (EXPORT_CONFIG[fileType].singleWorksheet) {\n if (worksheetId === undefined) throw new Error(`Must specify worksheetId when exporting as ${fileType}`);\n } else if (worksheetId) throw new Error(`Cannot specify worksheetId when exporting as ${fileType}`);\n\n // google UI shows \"html\" but passes through \"zip\"\n if (fileType === 'html') fileType = 'zip';\n\n if (!this._spreadsheetUrl) throw new Error('Cannot export sheet that is not fully loaded');\n\n const exportUrl = this._spreadsheetUrl.replace('edit', 'export');\n const response = await this.sheetsApi.get(exportUrl, {\n prefixUrl: '', // unset baseUrl since we're not hitting the normal sheets API\n searchParams: {\n id: this.spreadsheetId,\n format: fileType,\n // worksheetId can be 0\n ...worksheetId !== undefined && { gid: worksheetId },\n },\n });\n if (returnStreamInsteadOfBuffer) {\n return response.body;\n }\n return response.arrayBuffer();\n }\n\n /**\n * exports entire document as html file (zipped)\n * @topic export\n * */\n async downloadAsZippedHTML(): Promise<ArrayBuffer>;\n async downloadAsZippedHTML(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;\n async downloadAsZippedHTML(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;\n async downloadAsZippedHTML(returnStreamInsteadOfBuffer?: boolean) {\n return this._downloadAs('html', undefined, returnStreamInsteadOfBuffer);\n }\n\n /**\n * @deprecated\n * use `doc.downloadAsZippedHTML()` instead\n * */\n async downloadAsHTML(returnStreamInsteadOfBuffer?: boolean) {\n return this._downloadAs('html', undefined, returnStreamInsteadOfBuffer);\n }\n\n /**\n * exports entire document as xlsx spreadsheet (Microsoft Office Excel)\n * @topic export\n * */\n async downloadAsXLSX(): Promise<ArrayBuffer>;\n async downloadAsXLSX(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;\n async downloadAsXLSX(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;\n async downloadAsXLSX(returnStreamInsteadOfBuffer = false) {\n return this._downloadAs('xlsx', undefined, returnStreamInsteadOfBuffer);\n }\n /**\n * exports entire document as ods spreadsheet (Open Office)\n * @topic export\n */\n async downloadAsODS(): Promise<ArrayBuffer>;\n async downloadAsODS(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;\n async downloadAsODS(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;\n async downloadAsODS(returnStreamInsteadOfBuffer = false) {\n return this._downloadAs('ods', undefined, returnStreamInsteadOfBuffer);\n }\n\n\n async delete() {\n await this.driveApi.delete('');\n this._deleted = true;\n // endpoint returns nothing when successful\n }\n\n // PERMISSIONS ///////////////////////////////////////////////////////////////////////////////////\n\n /**\n * list all permissions entries for doc\n */\n async listPermissions(): Promise<PermissionsList> {\n const listReq = await this.driveApi.get('permissions', {\n searchParams: {\n fields: 'permissions(id,type,emailAddress,domain,role,displayName,photoLink,deleted)',\n },\n });\n const data = await listReq.json<{ permissions: PermissionsList }>();\n return data.permissions;\n }\n\n async setPublicAccessLevel(role: PublicPermissionRoles | false) {\n const permissions = await this.listPermissions();\n const existingPublicPermission = _.find(permissions, (p) => p.type === 'anyone');\n\n if (role === false) {\n if (!existingPublicPermission) {\n // doc is already not public... could throw an error or just do nothing\n return;\n }\n await this.driveApi.delete(`permissions/${existingPublicPermission.id}`);\n } else {\n const _shareReq = await this.driveApi.post('permissions', {\n json: {\n role: role || 'viewer',\n type: 'anyone',\n },\n });\n }\n }\n\n /** share document to email or domain */\n async share(emailAddressOrDomain: string, opts?: {\n /** set role level, defaults to owner */\n role?: PermissionRoles,\n\n /** set to true if email is for a group */\n isGroup?: boolean,\n\n /** set to string to include a custom message, set to false to skip sending a notification altogether */\n emailMessage?: string | false,\n\n // moveToNewOwnersRoot?: string,\n // /** send a notification email (default = true) */\n // sendNotificationEmail?: boolean,\n // /** support My Drives and shared drives (default = false) */\n // supportsAllDrives?: boolean,\n\n // /** Issue the request as a domain administrator */\n // useDomainAdminAccess?: boolean,\n }) {\n let emailAddress: string | undefined;\n let domain: string | undefined;\n if (emailAddressOrDomain.includes('@')) {\n emailAddress = emailAddressOrDomain;\n } else {\n domain = emailAddressOrDomain;\n }\n\n\n const shareReq = await this.driveApi.post('permissions', {\n searchParams: {\n ...opts?.emailMessage === false && { sendNotificationEmail: false },\n ..._.isString(opts?.emailMessage) && { emailMessage: opts?.emailMessage },\n ...opts?.role === 'owner' && { transferOwnership: true },\n },\n json: {\n role: opts?.role || 'writer',\n ...emailAddress && {\n type: opts?.isGroup ? 'group' : 'user',\n emailAddress,\n },\n ...domain && {\n type: 'domain',\n domain,\n },\n },\n });\n\n return shareReq.json();\n }\n\n /**\n * delete a permission by its ID\n * @see https://developers.google.com/drive/api/v3/reference/permissions/delete\n */\n async deletePermission(permissionId: string) {\n await this.driveApi.delete(`permissions/${permissionId}`);\n }\n\n //\n // CREATE NEW DOC ////////////////////////////////////////////////////////////////////////////////\n static async createNewSpreadsheetDocument(auth: GoogleApiAuth, properties?: Partial<SpreadsheetProperties>) {\n // see updateProperties for more info about available properties\n\n if (getAuthMode(auth) === AUTH_MODES.API_KEY) {\n throw new Error('Cannot use api key only to create a new spreadsheet - it is only usable for read-only access of public docs');\n }\n\n // TODO: handle injecting default credentials if running on google infra\n\n const authConfig = await getRequestAuthConfig(auth);\n\n const response = await ky.post(SHEETS_API_BASE_URL, {\n ...authConfig, // has the auth header\n json: {\n properties,\n },\n });\n\n const data = await response.json<any>();\n const newSpreadsheet = new GoogleSpreadsheet(data.spreadsheetId, auth);\n\n // TODO ideally these things aren't public, might want to refactor anyway\n newSpreadsheet._spreadsheetUrl = data.spreadsheetUrl;\n newSpreadsheet._rawProperties = data.properties;\n _.each(data.sheets, (s: any) => newSpreadsheet._updateOrCreateSheet(s));\n\n return newSpreadsheet;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,SAAgB,aAAa,KAA8B;CACzD,IAAI,WAAW;CACf,MAAM,WAAW,OAAO,KAAK,IAAI,CAAC,QAAQ,QAAQ,QAAQ,iBAAiB,CAAC,KAAK,IAAI;AAErF,KAAI,IAAI,gBAAgB;AACtB,aAAW,OAAO,KAAK,IAAI,eAAe,CAAC,KAAK,QAAQ,kBAAkB,MAAM,CAAC,KAAK,IAAI;AAC1F,MAAI,SAAS,UAAU,SAAS,OAC9B,YAAW,GAAG,SAAS;;AAG3B,QAAO,WAAW;;AAGpB,SAAgB,eAAe,QAAgB;CAC7C,IAAI;CACJ,IAAI,SAAS;CACb,IAAI,MAAM;AACV,QAAO,MAAM,GAAG;AACd,UAAQ,MAAM,KAAK;AACnB,WAAS,OAAO,aAAa,OAAO,GAAG,GAAG;AAC1C,SAAO,MAAM,OAAO,KAAK;;AAE3B,QAAO;;AAGT,SAAgB,eAAe,QAAgB;CAC7C,IAAI,SAAS;CACb,MAAM,EAAE,WAAW;AACnB,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,IAC1B,YAAW,OAAO,WAAW,EAAE,GAAG,MAAM,OAAO,SAAS,IAAI;AAE9D,QAAO;;AAGT,SAAgB,yBAAyB,SAAmB;CAE1D,MAAM,0CAA0B,QAAQ;AACxC,wBAAO,gBAAgB,SAAS,WAAW;AACzC,MAAI,CAAC,OAAQ;AACb,MAAI,QAAQ,SAAS,EACnB,OAAM,IAAI,MAAM,+BAA+B,OAAO,sDAAsD;GAE9G;;;;;ACtCJ,IAAa,uBAAb,MAAuF;CACrF,YAEE,AAAS,YAET,AAAQ,YAER,AAAQ,UACR;EALS;EAED;EAEA;;CAKV,AAAQ,WAAW;CACnB,IAAI,UAAU;AAAE,SAAO,KAAK;;;CAG5B,IAAI,YAAY;AAAE,SAAO,KAAK;;;;;;;CAM9B,iBAAiB,cAAsB;AACrC,OAAK,aAAa;;CAEpB,IAAI,UAAU;AACZ,SAAO;GACL,KAAK,WAAW;GAChB;GACA,IAAI,KAAK;GACT;GACA,GAAG,eAAe,KAAK,WAAW,aAAa,OAAO,GAAG,KAAK;GAC/D,CAAC,KAAK,GAAG;;;CAIZ,IAAI,KAAc;EAChB,MAAM,QAAQ,KAAK,WAAW,aAAa,QAAQ,IAAc;AACjE,SAAO,KAAK,SAAS;;;CAGvB,IAAuB,KAAQ,KAAW;EACxC,MAAM,QAAQ,KAAK,WAAW,aAAa,QAAQ,IAAc;AACjE,OAAK,SAAS,SAAS;;;CAGzB,OAAO,KAAiB;AAEtB,OAAK,MAAM,OAAO,IAAK,MAAK,IAAI,KAAK,IAAI,KAAY;;;CAIvD,WAAW;EACT,MAAM,IAAgB,EAAE;AACxB,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,WAAW,aAAa,QAAQ,KAAK;GAC5D,MAAM,MAAe,KAAK,WAAW,aAAa;AAClD,OAAI,CAAC,IAAK;AACV,KAAE,OAAO,KAAK,SAAS;;AAEzB,SAAO;;;CAIT,MAAM,KAAK,SAA6B;AACtC,MAAI,KAAK,SAAU,OAAM,IAAI,MAAM,wEAAwE;AAc3G,OAAK,YADQ,OAXI,MAAM,KAAK,WAAW,aAAa,UAAU,IAAI,UAAU,mBAAmB,KAAK,QAAQ,IAAI;GAC9G,cAAc;IACZ,kBAAkB,SAAS,MAAM,QAAQ;IACzC,yBAAyB;IAC1B;GACD,MAAM;IACJ,OAAO,KAAK;IACZ,gBAAgB;IAChB,QAAQ,CAAC,KAAK,SAAS;IACxB;GACF,CAAC,EAC0B,MAAW,EAClB,YAAY,OAAO;;;CAI1C,MAAM,SAAS;AACb,MAAI,KAAK,SAAU,OAAM,IAAI,MAAM,wEAAwE;EAE3G,MAAM,SAAS,MAAM,KAAK,WAAW,yBAAyB,eAAe;GAC3E,OAAO;IACL,SAAS,KAAK,WAAW;IACzB,eAAe,KAAK,aAAa;IACjC,aAAa,KAAK;IACnB;GACD,gBAAgB;GACjB,CAAC;AACF,OAAK,WAAW;AAChB,OAAK,WAAW,eAAe,KAAK,UAAU;AAE9C,SAAO;;;;;;;CAQT,gBAAgB;AACd,OAAK,IAAI,IAAI,GAAG,IAAI,KAAK,SAAS,QAAQ,IACxC,MAAK,SAAS,KAAK;;;;;;;;;;;;;;ACtGzB,IAAa,kCAAb,MAA6C;;;;;CAK3C,AAAS;;CAGT,AAAS;CAET,YAAY,UAAsB;AAChC,OAAK,OAAO,SAAS;AACrB,OAAK,UAAU,SAAS;;;;;;ACT5B,IAAa,wBAAb,MAAmC;CACjC,AAAQ;CACR,AAAQ,aAAkB,EAAE;CAC5B,AAAQ;CAER,YACE,AAAS,QACT,AAAQ,WACR,AAAQ,cACR,aACA;EAJS;EACD;EACA;AAGR,OAAK,eAAe,YAAY;AAChC,OAAK,WAAW;;;;;;CASlB,eAAe,SAAmB;AAChC,OAAK,WAAW;AAChB,OAAK,aAAa,EAAE;AACpB,MAAI,KAAK,UAAU,kBAAkB,gBAAgB,KAAK,SAAS,eACjE,MAAK,SAAS,IAAI,gCAAgC,KAAK,SAAS,eAAe,WAAW;MAE1F,MAAK,SAAS;;CAKlB,IAAI,WAAW;AAAE,SAAO,KAAK;;CAC7B,IAAI,cAAc;AAAE,SAAO,KAAK;;CAChC,IAAI,WAAW;AAAE,SAAO,eAAe,KAAK,eAAe,EAAE;;CAC7D,IAAI,QAAQ;AAAE,SAAO,KAAK,YAAY;;CACtC,IAAI,YAAY;AAAE,SAAO,GAAG,KAAK,WAAW,KAAK;;CAGjD,IAAI,QAA4E;AAE9E,MAAI,KAAK,WAAW,UAAU,OAAW,OAAM,IAAI,MAAM,yBAAyB;AAClF,MAAI,KAAK,OAAQ,QAAO,KAAK;AAC7B,MAAI,CAAC,KAAK,UAAU,eAAgB,QAAO;AAC3C,kCAAgB,KAAK,SAAS,eAAe,CAAC;;CAIhD,IAAI,MAAM,UAAiG;AAEzG,MAAI,oBAAoB,gCACtB,OAAM,IAAI,MAAM,6CAA6C;AAG/D,kCAAgB,SAAS,CACvB,MAAK,WAAW,YAAY;sCACR,SAAS,CAC7B,KAAI,SAAS,UAAU,GAAG,EAAE,KAAK,IAAK,MAAK,WAAW,YAAY;MAC7D,MAAK,WAAW,YAAY;sCACb,SAAS,CAC7B,MAAK,WAAW,YAAY;mCACX,SAAS,EAAE;AAE5B,QAAK,WAAW,YAAY;AAC5B,cAAW;QAEX,OAAM,IAAI,MAAM,0CAA0C;AAE5D,OAAK,WAAW,QAAQ;;CAG1B,IAAI,YAAkC;AAEpC,MAAI,KAAK,OAAQ,QAAO;AACxB,MAAI,CAAC,KAAK,UAAU,eAAgB,QAAO;AAC3C,gCAAc,KAAK,SAAS,eAAe,CAAC;;;CAI9C,IAAI,iBAAgC;AAAE,SAAO,KAAK,UAAU,kBAAkB;;CAE9E,IAAI,UAAU;AAAE,+BAAa,KAAK,UAAU,iCAAiC,KAAK;;CAClF,IAAI,QAAQ,UAAyB;AACnC,MAAI,CAAC,SAAU,OAAM,IAAI,MAAM,8CAA8C;AAC7E,MAAI,SAAS,UAAU,GAAG,EAAE,KAAK,IAAK,OAAM,IAAI,MAAM,gCAA8B;AACpF,OAAK,QAAQ;;;;;CAKf,IAAI,eAAe;AAAE,SAAO,KAAK;;;;;CAIjC,IAAI,aAAa;AAAE,SAAO,KAAK;;CAE/B,IAAI,cAAkC;AACpC,MAAI,KAAK,cAAc,cAAe,QAAO;AAC7C,SAAO,KAAK;;CAEd,IAAI,YAAY,KAAyB;AACvC,OAAK,QAAQ;;CAGf,IAAI,YAAiC;AACnC,MAAI,KAAK,cAAc,YAAa,QAAO;AAC3C,SAAO,KAAK;;CAEd,IAAI,UAAU,KAA0B;AACtC,OAAK,QAAQ;;CAGf,IAAI,cAAkC;AACpC,MAAI,KAAK,cAAc,cAAe,QAAO;AAC7C,SAAO,KAAK;;CAEd,IAAI,YAAY,KAAyB;AACvC,MAAI,KAAK,WAAW,IAAI,CACtB,OAAM,IAAI,MAAM,yCAAyC;AAE3D,OAAK,QAAQ;;;;;;;CAQf,IAAI,YAAY;AACd,MAAI,KAAK,WAAW,MAAO,OAAM,IAAI,MAAM,yCAAyC;AACpF,SAAO,KAAK,UAAU;;;CAIxB,IAAI,OAAe;AACjB,SAAO,KAAK,WAAW,SAAS,SAAY,KAAK,WAAW,OAAO,KAAK,UAAU,QAAQ;;CAE5F,IAAI,KAAK,QAA2C;AAClD,MAAI,WAAW,QAAQ,WAAW,UAAa,WAAW,MAAO,UAAS;AAC1E,MAAI,4BAAY,OAAO,CAAE,OAAM,IAAI,MAAM,wBAAwB;AACjE,MAAI,WAAW,KAAK,UAAU,KAAM,QAAO,KAAK,WAAW;MACtD,MAAK,WAAW,OAAO;;CAI9B,IAAI,oBAAoB;AAAE,SAAO,OAAO,OAAO,KAAK,UAAU,kBAAkB;;CAChF,IAAI,kBAAkB;AAAE,SAAO,OAAO,OAAO,KAAK,UAAU,gBAAgB;;CAE5E,AAAQ,gBAA4C,OAAmC;AAGrF,4BAAU,KAAK,YAAY,qBAAqB,QAAQ,CACtD,OAAM,IAAI,MAAM,qEAAqE;AAMvF,SAAO,OAAO,OAAO,KAAK,SAAU,kBAAkB,OAAO;;CAG/D,AAAQ,gBAA4C,OAAU,QAAuB;AACnF,gCAAc,8BAAc,KAAK,UAAU,qBAAqB,QAAQ,CAAC,CACvE,yBAAQ,KAAK,YAAY,qBAAqB,QAAQ;OACjD;AACL,yBAAM,KAAK,YAAY,qBAAqB,SAAS,OAAO;AAC5D,QAAK,WAAW,cAAc;;;CAKlC,IAAI,eAAe;AAAE,SAAO,KAAK,gBAAgB,eAAe;;CAChE,IAAI,kBAAkB;AAAE,SAAO,KAAK,gBAAgB,kBAAkB;;CACtE,IAAI,uBAAuB;AAAE,SAAO,KAAK,gBAAgB,uBAAuB;;CAChF,IAAI,UAAU;AAAE,SAAO,KAAK,gBAAgB,UAAU;;CACtD,IAAI,UAAU;AAAE,SAAO,KAAK,gBAAgB,UAAU;;CACtD,IAAI,sBAAsB;AAAE,SAAO,KAAK,gBAAgB,sBAAsB;;CAC9E,IAAI,oBAAoB;AAAE,SAAO,KAAK,gBAAgB,oBAAoB;;CAC1E,IAAI,eAAe;AAAE,SAAO,KAAK,gBAAgB,eAAe;;CAChE,IAAI,gBAAgB;AAAE,SAAO,KAAK,gBAAgB,gBAAgB;;CAClE,IAAI,aAAa;AAAE,SAAO,KAAK,gBAAgB,aAAa;;CAC5D,IAAI,uBAAuB;AAAE,SAAO,KAAK,gBAAgB,uBAAuB;;CAChF,IAAI,eAAe;AAAE,SAAO,KAAK,gBAAgB,eAAe;;CAGhE,IAAI,aAAa,QAAoC;AAAE,OAAK,gBAAgB,gBAAgB,OAAO;;CACnG,IAAI,gBAAgB,QAAuC;AAAE,OAAK,gBAAgB,mBAAmB,OAAO;;CAC5G,IAAI,qBAAqB,QAA4C;AAAE,OAAK,gBAAgB,wBAAwB,OAAO;;CAC3H,IAAI,QAAQ,QAA+B;AAAE,OAAK,gBAAgB,WAAW,OAAO;;CACpF,IAAI,QAAQ,QAA+B;AAAE,OAAK,gBAAgB,WAAW,OAAO;;CACpF,IAAI,oBAAoB,QAA2C;AAAE,OAAK,gBAAgB,uBAAuB,OAAO;;CACxH,IAAI,kBAAkB,QAAyC;AAAE,OAAK,gBAAgB,qBAAqB,OAAO;;CAClH,IAAI,aAAa,QAAoC;AAAE,OAAK,gBAAgB,gBAAgB,OAAO;;CACnG,IAAI,cAAc,QAAqC;AAAE,OAAK,gBAAgB,iBAAiB,OAAO;;CACtG,IAAI,WAAW,QAAkC;AAAE,OAAK,gBAAgB,cAAc,OAAO;;CAC7F,IAAI,qBAAqB,QAA4C;AAAE,OAAK,gBAAgB,wBAAwB,OAAO;;CAC3H,IAAI,aAAa,QAAoC;AAAE,OAAK,gBAAgB,gBAAgB,OAAO;;CAEnG,qBAAqB;AAGnB,OAAK,WAAW,cAAc;AAC9B,SAAO,KAAK,WAAW;;CAMzB,IAAI,WAAW;AAGb,MAAI,KAAK,WAAW,SAAS,OAAW,QAAO;AAC/C,6BAAW,KAAK,WAAW,kBAAkB,CAAC,OAAQ,QAAO;AAC7D,MAAI,KAAK,WAAW,YAAa,QAAO;AACxC,MAAI,KAAK,WAAW,UAAU,OAAW,QAAO;AAChD,SAAO;;CAGT,wBAAwB;AACtB,OAAK,aAAa,EAAE;;;;;;CAOtB,MAAM,OAAO;AACX,QAAM,KAAK,OAAO,UAAU,CAAC,KAAK,CAAC;;;;;;;CAQrC,oBAAoB;EAGlB,MAAM,iBAAiB,KAAK,WAAW,UAAU;EACjD,MAAM,gBAAgB,KAAK,WAAW,SAAS;EAC/C,MAAM,kBAAkB,CAAC,wBAAQ,KAAK,WAAW,qBAAqB,EAAE,CAAC,CAAC;EAC1E,MAAM,kBAAkB,KAAK,WAAW;AAGxC,MAAI,wBAAQ;GAAC;GAAgB;GAAe;GAAiB;GAAgB,CAAC,CAC5E,QAAO;EAIT,MAAM,SAAS;GAEb,GAAG,KAAK,UAAU;GAClB,GAAG,KAAK,WAAW;GACpB;AAID,4BAAU,KAAK,YAAY,oCAAoC,CAC7D,QAAQ,OAAO;AAGjB,SAAO,EACL,aAAa;GACX,MAAM,CAAC,EACL,QAAQ,CAAC;IACP,GAAG,kBAAkB,EACnB,kBAAkB,GAAG,KAAK,WAAW,YAAY,KAAK,WAAW,OAAO,EACzE;IACD,GAAG,iBAAiB,EAClB,MAAM,KAAK,WAAW,MACvB;IACD,GAAG,mBAAmB,EACpB,mBAAmB,QACpB;IACD,GAAG,mBAAmB,EACpB,mBAAmB,EAAE,EACtB;IACF,CAAC,EACH,CAAC;GAEF,wDAAwB;IACtB,kBAAkB;IAClB,MAAM;IACN,mBAAmB,mBAAmB;IACvC,CAAC,CAAC,CAAC,KAAK,IAAI;GACb,OAAO;IACL,SAAS,KAAK,OAAO;IACrB,UAAU,KAAK;IACf,aAAa,KAAK;IACnB;GACF,EACF;;;;;;ACxRL,IAAa,6BAAb,MAAwC;CAEtC,AAAQ,kBAAkB;CAE1B,AAAQ,iBAA6C;CACrD,AAAQ,SAAoC,EAAE;CAC9C,AAAQ,eAAsB,EAAE;CAChC,AAAQ,kBAAyB,EAAE;CACnC,AAAQ,mBAA4C;CAEpD,AAAQ;CACR,IAAI,eAAe;AACjB,MAAI,CAAC,KAAK,cACR,OAAM,IAAI,MAAM,mCAAmC;AAErD,SAAO,KAAK;;CAGd,YAEE,AAAS,cACT,eACA,aACA,iBACA;EAJS;AAKT,OAAK,kBAAkB;AAGvB,OAAK,iBAAiB;AAEtB,OAAK,SAAS,EAAE;AAEhB,OAAK,eAAe,EAAE;AACtB,OAAK,kBAAkB,EAAE;AACzB,MAAI,gBAAiB,MAAK,mBAAmB;AAE7C,MAAI,YAAa,MAAK,cAAc,YAAY;;CAKlD,cAAc,YAAiC,aAA8B,iBAAoC;AAC/G,OAAK,iBAAiB;AACtB,OAAK,cAAc,YAAY;AAC/B,MAAI,gBAAiB,MAAK,mBAAmB;;CAG/C,MAAM,yBAAyB,aAAqB,eAAoB;AAEtE,SAAO,KAAK,aAAa,yBAAyB,aAAa,EAC7D,GAAG,eACJ,CAAC;;CAGJ,AAAQ,oBAAoB;AAC1B,MAAI,CAAC,KAAK,eACR,OAAM,IAAI,MAAM,sEAAsE;;;CAK1F,gBAEE,UACA;AACA,MAAI,CAAC,SAAU,MAAK,iBAAiB;AACrC,OAAK,gBAAgB;AACrB,OAAK,kBAAkB;AACvB,OAAK,SAAS,EAAE;;CAGlB,AAAQ,cACN,YACA;AACA,yBAAO,aAAa,UAAU;GAC5B,MAAM,WAAW,MAAM,YAAY;GACnC,MAAM,cAAc,MAAM,eAAe;GACzC,MAAM,UAAU,MAAM,YAAY;GAClC,MAAM,aAAa,MAAM,eAAe;AAGxC,QAAK,IAAI,IAAI,GAAG,IAAI,SAAS,KAAK;IAChC,MAAM,YAAY,WAAW;AAC7B,SAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;KACnC,MAAM,eAAe,cAAc;AAGnC,SAAI,CAAC,KAAK,OAAO,WAAY,MAAK,OAAO,aAAa,EAAE;KAGxD,MAAM,iCAAiB,OAAO,WAAW,EAAE,WAAW,EAAE,GAAG;AAG3D,SAAI,KAAK,OAAO,WAAW,cACzB,MAAK,OAAO,WAAW,cAAc,eAAe,SAAS;SAE7D,MAAK,OAAO,WAAW,gBAAgB,IAAI,sBACzC,MACA,WACA,cACA,SACD;;;AAMP,QAAK,IAAI,IAAI,GAAG,IAAI,MAAM,YAAY,QAAQ,IAC5C,MAAK,aAAa,WAAW,KAAK,MAAM,YAAY;AAGtD,QAAK,IAAI,IAAI,GAAG,IAAI,MAAM,eAAe,QAAQ,IAC/C,MAAK,gBAAgB,cAAc,KAAK,MAAM,eAAe;IAE/D;;CAIJ,AAAQ,mBAAmB,OAAyC;AAClE,MAAI,MAAM,WAAW,MAAM,YAAY,KAAK,QAC1C,OAAM,IAAI,MAAM,2DAA2D;AAE7E,SAAO;GACL,GAAG;GACH,SAAS,KAAK;GACf;;CAMH,AAAQ,SAA8C,OAAkC;AACtF,OAAK,mBAAmB;AAExB,SAAO,KAAK,eAAgB;;CAG9B,AAAQ,SAA8C,QAAW,SAAiC;AAChG,QAAM,IAAI,MAAM,oDAAoD;;CAGtE,IAAI,UAAU;AAAE,SAAO,KAAK,SAAS,UAAU;;CAC/C,IAAI,QAAQ;AAAE,SAAO,KAAK,SAAS,QAAQ;;CAC3C,IAAI,QAAQ;AAAE,SAAO,KAAK,SAAS,QAAQ;;CAC3C,IAAI,YAAY;AAAE,SAAO,KAAK,SAAS,YAAY;;CACnD,IAAI,iBAAiB;AAAE,SAAO,KAAK,SAAS,iBAAiB;;CAC7D,IAAI,SAAS;AAAE,SAAO,KAAK,SAAS,SAAS;;CAC7C,IAAI,WAAW;AAAE,SAAO,KAAK,SAAS,WAAW;;CACjD,IAAI,cAAc;AAAE,SAAO,KAAK,SAAS,cAAc;;CACvD,IAAI,kBAAkB;AAAE,SAAO,KAAK;;CACpC,IAAY,eAAe;AACzB,SAAO,IAAI,KAAK,gBAAgB,GAAG,KAAK,mBAAmB,KAAK;;CAGlE,IAAI,QAAQ,QAAwC;AAAE,OAAK,SAAS,WAAW,OAAO;;CACtF,IAAI,MAAM,QAAsC;AAAE,OAAK,SAAS,SAAS,OAAO;;CAChF,IAAI,MAAM,QAAsC;AAAE,OAAK,SAAS,SAAS,OAAO;;CAChF,IAAI,UAAU,QAA0C;AAAE,OAAK,SAAS,aAAa,OAAO;;CAC5F,IAAI,eAAe,QAA+C;AAAE,OAAK,SAAS,kBAAkB,OAAO;;CAC3G,IAAI,OAAO,QAAuC;AAAE,OAAK,SAAS,UAAU,OAAO;;CACnF,IAAI,SAAS,QAAyC;AAAE,OAAK,SAAS,YAAY,OAAO;;CACzF,IAAI,YAAY,QAA4C;AAAE,OAAK,SAAS,eAAe,OAAO;;CAElG,IAAI,WAAW;AACb,OAAK,mBAAmB;AACxB,SAAO,KAAK,eAAe;;CAE7B,IAAI,cAAc;AAChB,OAAK,mBAAmB;AACxB,SAAO,KAAK,eAAe;;CAG7B,IAAI,cAAc;AAAE,SAAO,IAAI,KAAK,MAAM,QAAQ,MAAM,KAAK,CAAC;;CAC9D,IAAI,qBAAqB;AAAE,SAAO,mBAAmB,KAAK,YAAY;;CACtE,IAAI,mBAAmB;AAErB,SAAO,KAAK,cAAc,eAAe,KAAK,YAAY,GAAG;;CAM/D,IAAI,YAAY;EACd,IAAI,qCAAqB,KAAK,OAAO;AACrC,uCAAqB,SAAS;AAC9B,SAAO;GACL,mCAAmB,WAAW,MAAM,EAAE,MAAM,CAAC;GAC7C,QAAQ,SAAS;GACjB,OAAO,KAAK,WAAW,KAAK;GAC7B;;CAGH,YAAY,WAAsB;EAChC,MAAM,QAAQ,UAAU,MAAM,mBAAmB;AACjD,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,iBAAiB,UAAU,aAAa;EACpE,MAAM,cAAc,eAAe,MAAM,GAAG;EAC5C,MAAM,WAAW,SAAS,MAAM,GAAG;AACnC,SAAO,KAAK,QAAQ,WAAW,GAAG,cAAc,EAAE;;CAGpD,QAAQ,UAAoB,aAA0B;AACpD,MAAI,WAAW,KAAK,cAAc,EAAG,OAAM,IAAI,MAAM,yBAAyB;AAC9E,MAAI,YAAY,KAAK,YAAY,eAAe,KAAK,YACnD,OAAM,IAAI,MAAM,2BAA2B,KAAK,SAAS,MAAM,KAAK,cAAc;AAGpF,MAAI,uBAAO,KAAK,QAAQ,IAAI,SAAS,IAAI,YAAY,GAAG,CACtD,OAAM,IAAI,MAAM,oCAAoC;AAEtD,SAAO,KAAK,OAAO,UAAU;;CAG/B,MAAM,UAAU,cAA8E;AAE5F,MAAI,CAAC,aAAc,QAAO,KAAK,aAAa,UAAU,KAAK,YAAY;EAEvE,MAAM,yCAAyB,aAAa,GAAG,eAAe,CAAC,aAAa;EAC5E,MAAM,gDAA8C,eAAe,WAAW;AAE5E,kCAAe,OAAO,EAAE;AACtB,QAAI,OAAO,WAAW,KAAK,YAAY,CAAE,QAAO;AAChD,WAAO,GAAG,KAAK,YAAY,GAAG;;AAEhC,kCAAe,OAAO,EAAE;IAItB,MAAM,YAAY;AAClB,QAAI,UAAU,WAAW,UAAU,YAAY,KAAK,QAClD,OAAM,IAAI,MAAM,2DAA2D;AAG7E,WAAO;KAAE,SAAS,KAAK;KAAS,GAAG;KAAQ;;AAE7C,SAAM,IAAI,MAAM,4DAA4D;IAC5E;AACF,SAAO,KAAK,aAAa,UAAU,wBAAwB;;CAG7D,MAAM,mBAAmB;EACvB,MAAM,iEAAiC,KAAK,OAAO,EAAE,EAAE,UAAU,MAAM,CAAC;AACxE,MAAI,YAAY,OACd,OAAM,KAAK,UAAU,YAAY;;CAKrC,MAAM,UAAU,eAAwC;EAItD,MAAM,iCAAiB,gBAAgB,SAAS,KAAK,mBAAmB,CAAC;EACzE,MAAM,uCAAuB,gBAAgB,MAAM,GAAG,KAAK,YAAY,GAAG,EAAE,YAAY;AAIxF,MAAI,2BAAW,SAAS,CAAC,OACvB,OAAM,IAAI,MAAM,kDAAkD;AAGpE,QAAM,KAAK,aAAa,wBAAwB,UAAU,eAAe;;CA6D3E,MAAM,yBAAyB;AAC7B,MAAI,CAAC,KAAK,cACR,OAAM,KAAK,eAAe;;CAI9B,MAAM,cAAc,gBAAyB;AAC3C,MAAI,mBAAmB,OAAW,MAAK,kBAAkB;EACzD,MAAM,OAAO,MAAM,KAAK,gBAAgB,KAAK,aAAa;AAC1D,OAAK,kBAAkB,KAAK;;CAG9B,AAAQ,kBAAkB,MAAa;AACrC,MAAI,CAAC,KACH,OAAM,IAAI,MAAM,0GAA0G;AAE5H,OAAK,sCAAsB,KAAK,KAAK,WAAW,QAAQ,MAAM,CAAC;AAC/D,MAAI,2BAAW,KAAK,aAAa,CAAC,OAChC,OAAM,IAAI,MAAM,8GAA8G;AAEhI,2BAAyB,KAAK,aAAa;;CAG7C,MAAM,aAAa,cAAwB,gBAAyB;AAClE,MAAI,CAAC,aAAc;AACnB,MAAI,aAAa,SAAS,KAAK,YAC7B,OAAM,IAAI,MAAM,oCAAoC,aAAa,OAAO,mCAAmC;EAE7G,MAAM,4CAA4B,eAAe,MAAM,GAAG,MAAM,CAAC;AACjE,2BAAyB,oBAAoB;AAE7C,MAAI,2BAAW,oBAAoB,CAAC,OAClC,OAAM,IAAI,MAAM,oCAAoC;AAGtD,MAAI,eAAgB,MAAK,kBAAkB;AAqB3C,OAAK,iBADQ,OAlBI,MAAM,KAAK,aAAa,UAAU,IACjD,UAAU,KAAK,mBAAmB,GAAG,KAAK,gBAAgB,GAAG,KAAK,mBAClE;GACE,cAAc;IACZ,kBAAkB;IAClB,yBAAyB;IAC1B;GACD,MAAM;IACJ,OAAO,GAAG,KAAK,YAAY,GAAG,KAAK,gBAAgB,GAAG,KAAK;IAC3D,gBAAgB;IAChB,QAAQ,CAAC,CACP,GAAG,qBAEH,2BAAW,KAAK,cAAc,oBAAoB,cAAc,GAAG,CACpE,CAAC;IACH;GACF,CACF,EAC2B,MAAW,EACb,YAAY,OAAO;;CAI/C,MAAM,QACJ,MACA,UAAyB,EAAE,EAC3B;AAWA,MAAI,KAAK,MAAM,SAAS,IAAI,CAC1B,OAAM,IAAI,MAAM,sJAAoJ;AAGtK,MAAI,2BAAW,KAAK,CAAE,OAAM,IAAI,MAAM,oDAAoD;AAE1F,QAAM,KAAK,wBAAwB;EAGnC,MAAM,eAA6B,EAAE;AACrC,yBAAO,OAAO,QAAQ;GACpB,IAAI;AACJ,iCAAc,IAAI,CAChB,cAAa;uCACO,IAAI,EAAE;AAC1B,iBAAa,EAAE;AACf,SAAK,IAAI,IAAI,GAAG,IAAI,KAAK,aAAa,QAAQ,KAAK;KACjD,MAAM,WAAW,KAAK,aAAa;AACnC,gBAAW,KAAK,IAAI;;SAGtB,OAAM,IAAI,MAAM,yCAAyC;AAE3D,gBAAa,KAAK,WAAW;IAC7B;EAkBF,MAAM,OAAO,OAhBI,MAAM,KAAK,aAAa,UAAU,KACjD,UAAU,KAAK,mBAAmB,IAAI,KAAK,gBAAgB,UAC3D;GACE,cAAc;IACZ,kBAAkB,QAAQ,MAAM,QAAQ;IACxC,kBAAkB,QAAQ,SAAS,gBAAgB;IACnD,yBAAyB;IAC1B;GACD,MAAM,EACJ,QAAQ,cACT;GACF,CACF,EAI2B,MAAW;EACvC,MAAM,EAAE,iBAAiB,KAAK;EAC9B,IAAI,YAAY,aAAa,MAAM,oBAAoB,CAAC;AACxD,cAAY,SAAS,UAAU;AAG/B,OAAK,mBAAmB;AAExB,MAAI,QAAQ,OACV,MAAK,eAAgB,eAAe,YAAY,KAAK;WAC5C,YAAY,KAAK,SAAS,KAAK,SAExC,MAAK,eAAgB,eAAe,WAAW,YAAY,KAAK,SAAS;AAG3E,+BAAa,KAAK,QAAQ,YAAY,SAAS,cAAc;AAE3D,UADY,IAAI,qBAAqB,MAAM,aAAa,UAAU;IAElE;;;CAIJ,MAAM,OAAO,WAAuB,SAAyB;AAE3D,UADa,MAAM,KAAK,QAAQ,CAAC,UAAU,EAAE,QAAQ,EACzC;;CAId,AAAQ,YAAoC,EAAE;CAC9C,MAAM,QACJ,SAMA;EAQA,MAAM,SAAS,SAAS,UAAU;EAClC,MAAM,QAAQ,SAAS,SAAS,KAAK,WAAW;EAEhD,MAAM,WAAW,IAAI,KAAK,kBAAkB;EAC5C,MAAM,UAAU,WAAW,QAAQ;EAEnC,IAAI;AACJ,MAAI,KAAK,eAAe;GACtB,MAAM,aAAa,eAAe,KAAK,aAAa,OAAO;AAC3D,aAAU,MAAM,KAAK,gBACnB,IAAI,SAAS,GAAG,aAAa,UAC9B;SACI;GACL,MAAM,SAAS,MAAM,KAAK,qBAAqB,CAAC,KAAK,cACnD,IAAI,SAAS,GAAG,KAAK,mBAAmB,UAAU,CAAC;AACrD,QAAK,kBAAkB,OAAO,GAAG;AACjC,aAAU,OAAO;;AAGnB,MAAI,CAAC,QAAS,QAAO,EAAE;EAEvB,MAAM,OAAO,EAAE;EACf,IAAI,SAAS;AACb,OAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;GACvC,MAAM,MAAM,IAAI,qBAAwB,MAAM,UAAU,QAAQ,GAAG;AACnE,QAAK,UAAU,IAAI,aAAa;AAChC,QAAK,KAAK,IAAI;;AAEhB,SAAO;;;;;;;CAQT,eAAe,kBAA0B;AACvC,SAAO,KAAK,UAAU;AACtB,OAAK,UAAU,SAAS,QAAQ;AAC9B,OAAI,IAAI,YAAY,iBAClB,KAAI,iBAAiB,IAAI,YAAY,EAAE;IAEzC;;CAGJ,MAAM,UACJ,SAIA;EAEA,MAAM,gBAAgB,SAAS,SAAS,KAAK,kBAAkB;EAC/D,MAAM,cAAc,SAAS,OAAO,KAAK;AACzC,QAAM,KAAK,aAAa,UAAU,KAAK,UAAU,KAAK,mBAAmB,GAAG,cAAc,GAAG,YAAY,QAAQ;AACjH,OAAK,UAAU,SAAS,QAAQ;AAC9B,OAAI,IAAI,aAAa,iBAAiB,IAAI,aAAa,YAAa,KAAI,eAAe;IACvF;;;CAKJ,MAAM,iBAAiB,YAA2D;AAGhF,SAAO,KAAK,yBAAyB,yBAAyB;GAC5D,YAAY;IACV,SAAS,KAAK;IACd,GAAG;IACJ;GACD,QAAQ,aAAa,WAAW;GACjC,CAAC;;;;;CAMJ,MAAM,qBAAqB,gBAAyC;AAClE,SAAO,KAAK,iBAAiB,EAAE,gBAAgB,CAAC;;;CAIlD,MAAM,OAAO,gBAA2E;AACtF,SAAO,KAAK,qBAAqB,eAAe;;;;;;CAOlD,MAAM,0BACJ,eACA,YACA,QACA;AAKA,SAAO,KAAK,yBAAyB,6BAA6B;GAChE,OAAO;IACL,SAAS,KAAK;IACd,WAAW;IACX,GAAG;IACJ;GACD;GACA,QAAQ,aAAa,WAAkB;GACxC,CAAC;;CAOJ,MAAM,gBAAgB,SAAkB,SAAmC;AAKzE,UADa,OAHI,MAAM,KAAK,aAAa,UAAU,IAAI,UAAU,KAAK,mBAAmB,GAAG,WAAW,EACrG,cAAc,SACf,CAAC,EAC0B,MAAW,EAC3B;;CAGd,MAAM,qBAAqB,UAAqB,SAAmC;EACjF,MAAM,SAAS,SAAS,KAAK,MAAM,UAAU,KAAK,mBAAmB,GAAG,IAAI,CAAC,KAAK,IAAI;AAKtF,UADa,OAHI,MAAM,KAAK,aAAa,UAAU,IAAI,mBAAmB,UAAU,EAClF,cAAc,SACf,CAAC,EAC0B,MAAW,EAC3B,YAAY,KAAK,MAAW,EAAE,OAAO;;CAGnD,MAAM,mBAAmB;CAKzB,MAAM,gBAAgB;CAKtB,MAAM,mBAAmB;CAKzB,MAAM,aAAa;CAKnB,MAAM,WAAW;CAKjB,MAAM,WAAW;CAKjB,MAAM,YAAY;;;;;CAWlB,MAAM,WAAW,OAAyC,YAAY,aAAa;AACjF,QAAM,KAAK,yBAAyB,cAAc;GAChD;GACA,OAAO,KAAK,mBAAmB,MAAM;GACtC,CAAC;;;;;;CAOJ,MAAM,aAAa,OAAyC;AAC1D,QAAM,KAAK,yBAAyB,gBAAgB,EAClD,OAAO,KAAK,mBAAmB,MAAM,EACtC,CAAC;;CAGJ,MAAM,gBAAgB;CAKtB,MAAM,gBAAgB;CAKtB,MAAM,cAAc;CAKpB,MAAM,mBAAmB;CAKzB,MAAM,kBAAkB;CAKxB,MAAM,uBAAuB;CAK7B,MAAM,mBAAmB;CAKzB,MAAM,sBAAsB;;;;;CAS5B,MAAM,UACJ,SAKA;EAOA,MAAM,cANW,MAAM,KAAK,yBAAyB,kBAAkB;GACrE,eAAe,KAAK;GACpB,GAAG,SAAS,UAAU,UAAa,EAAE,kBAAkB,QAAQ,OAAO;GACtE,GAAG,SAAS,MAAM,EAAE,YAAY,QAAQ,IAAI;GAC5C,GAAG,SAAS,SAAS,EAAE,cAAc,QAAQ,OAAO;GACrD,CAAC,EAC0B,WAAW;AACvC,SAAO,KAAK,aAAa,WAAW;;CAGtC,MAAM,cAAc;;;;;CASpB,MAAM,gBACJ,eACA,cACA,mBACA;AACA,MAAI,CAAC,cAAe,OAAM,IAAI,MAAM,qDAAqD;AACzF,MAAI,4BAAY,aAAa,CAAE,OAAM,IAAI,MAAM,mEAAmE;AAClH,MAAI,6BAAa,aAAa,WAAW,IAAI,aAAa,aAAa,EAAG,OAAM,IAAI,MAAM,0CAA0C;AACpI,MAAI,6BAAa,aAAa,SAAS,IAAI,aAAa,WAAW,EAAG,OAAM,IAAI,MAAM,wCAAwC;AAC9H,MAAI,aAAa,YAAY,aAAa,WAAY,OAAM,IAAI,MAAM,uDAAuD;AAG7H,MAAI,sBAAsB,OACxB,qBAAoB,aAAa,aAAa;AAIhD,MAAI,qBAAqB,aAAa,eAAe,EACnD,OAAM,IAAI,MAAM,wEAAwE;AAG1F,SAAO,KAAK,yBAAyB,mBAAmB;GACtD,OAAO;IACL,SAAS,KAAK;IACd,WAAW;IACX,YAAY,aAAa;IACzB,UAAU,aAAa;IACxB;GACD;GACD,CAAC;;;;;;CAOJ,MAAM,YAEJ,OAEA,gBACA;AACA,SAAO,KAAK,yBAAyB,eAAe;GAClD,OAAO,KAAK,mBAAmB,MAAM;GACrC;GACD,CAAC;;CAGJ,MAAM,gBAAgB;CAKtB,MAAM,+BAA+B;CAKrC,MAAM,YAAY;CAKlB,MAAM,gBAAgB;CAKtB,MAAM,mBAAmB;CAKzB,MAAM,cAAc;CAKpB,MAAM,kBAAkB;CAKxB,MAAM,2BAA2B;CAKjC,MAAM,8BAA8B;CAKpC,MAAM,8BAA8B;CAKpC,MAAM,YAAY;;;;;CASlB,MAAM,kBACJ,OAEA,MACA;AACA,SAAO,KAAK,yBAAyB,qBAAqB;GACxD,OAAO;IACL,SAAS,KAAK;IACd,GAAG;IACJ;GACD,GAAG,QAAQ,EAAE,MAAM;GACpB,CAAC;;CAGJ,MAAM,iBAAiB;;;;;CASvB,MAAM,kBAAkB,gBAAgC;AACtD,MAAI,CAAC,eAAe,SAAS,CAAC,eAAe,aAC3C,OAAM,IAAI,MAAM,+DAA+D;AAEjF,SAAO,KAAK,yBAAyB,qBAAqB,EACxD,gBACD,CAAC;;;;;;CAOJ,MAAM,qBAAqB,kBAA2B,gBAAyC;AAC7F,SAAO,KAAK,yBAAyB,wBAAwB;GAC3D,gBAAgB;IAAE;IAAkB,GAAG;IAAgB;GACvD,QAAQ,aAAa,eAA0C;GAChE,CAAC;;;;;;CAOJ,MAAM,qBAAqB,kBAA2B;AACpD,SAAO,KAAK,yBAAyB,wBAAwB,EAC3D,kBACD,CAAC;;;;;;CAOJ,MAAM,qBAEJ,eAEA,cACA;AACA,SAAO,KAAK,yBAAyB,wBAAwB,EAC3D,YAAY;GACV,SAAS,KAAK;GACd,WAAW;GACX,GAAG;GACJ,EACF,CAAC;;CAGJ,MAAM,WAAW;CAKjB,MAAM,kBAAkB;CAKxB,MAAM,gBAAgB;CAKtB,MAAM,aAAa;CAKnB,MAAM,gBAAgB;CAKtB,MAAM,0BAA0B;CAKhC,MAAM,0BAA0B;CAKhC,MAAM,0BAA0B;CAKhC,MAAM,iBAAiB;CAKvB,MAAM,oBAAoB;CAK1B,MAAM,uBAAuB;CAK7B,MAAM,uBAAuB;CAK7B,MAAM,iBAAiB;CAKvB,MAAM,mBAAmB;CAKzB,MAAM,YAAY;CAKlB,MAAM,mBAAmB;;CAMzB,MAAM,SAAS;AACb,SAAO,KAAK,aAAa,YAAY,KAAK,QAAQ;;;;;;CAOpD,MAAM,kBAAkB,0BAAyC;AAO/D,SADa,MALD,KAAK,aAAa,UAAU,KAAK,UAAU,KAAK,QAAQ,UAAU,EAC5E,MAAM,EACJ,0BACD,EACF,CAAC,CACqB,MAAW;;;CAKpC,MAAM,MAEJ,SACA;EACA,MAAM,QAAQ,UAAU,IAAI,YAAY;AAExC,QAAM,KAAK,aAAa,UAAU,KAAK,UAAU,KAAK,qBAAqB,MAAM,QAAQ;AACzF,OAAK,gBAAgB,KAAK;;CAO5B,MAAM,cAAc,8BAA8B,OAAO;AACvD,SAAO,KAAK,aAAa,YAAY,OAAO,KAAK,SAAS,4BAA4B;;CAMxF,MAAM,cAAc,8BAA8B,OAAO;AACvD,SAAO,KAAK,aAAa,YAAY,OAAO,KAAK,SAAS,4BAA4B;;CAMxF,MAAM,cAAc,8BAA8B,OAAO;AACvD,SAAO,KAAK,aAAa,YAAY,OAAO,KAAK,SAAS,4BAA4B;;;;;;ACviC1F,IAAY,kDAAL;AACL;AACA;AACA;;;;;;ACCF,MAAM,sBAAsB;AAC5B,MAAM,qBAAqB;AAE3B,MAAM,gBAA+D;CACnE,MAAM,EAAE;CACR,KAAK,EAAE;CACP,MAAM,EAAE;CACR,KAAK,EAAE;CACP,KAAK,EAAE,iBAAiB,MAAM;CAC9B,KAAK,EAAE,iBAAiB,MAAM;CAC9B,KAAK,EAAE,iBAAiB,MAAM;CAC/B;AAMD,SAAS,YAAY,MAAqB;AACxC,KAAI,uBAAuB,KAAM,QAAO,WAAW;AACnD,KAAI,WAAW,QAAQ,KAAK,MAAO,QAAO,WAAW;AAErD,KAAI,YAAY,QAAQ,KAAK,OAAQ,QAAO,WAAW;AACvD,OAAM,IAAI,MAAM,eAAe;;AAGjC,eAAe,qBAAqB,MAGjC;AAGD,KAAI,uBAAuB,MAAM;EAC/B,MAAM,UAAU,MAAM,KAAK,mBAAmB;AAG9C,MAAI,aAAa,QACf,QAAO,EAAE,SAAS,OAAO,YAAY,QAAQ,SAAS,CAAC,EAAE;AACzD,iCAAe,QAAQ,CACvB,QAAO,EAAW,SAAmC;AAEvD,QAAM,IAAI,MAAM,qDAAqD;;AAKvE,KAAI,YAAY,QAAQ,KAAK,OAC3B,QAAO,EAAE,cAAc,EAAE,KAAK,KAAK,QAAQ,EAAE;AAI/C,KAAI,WAAW,QAAQ,KAAK,MAC1B,QAAO,EAAE,SAAS,EAAE,eAAe,UAAU,KAAK,SAAS,EAAE;AAG/D,OAAM,IAAI,MAAM,eAAe;;;;;;;;;;AAWjC,IAAa,oBAAb,MAAa,kBAAkB;CAC7B,AAAS;CAET,AAAO;CACP,IAAI,WAAW;AACb,SAAO,YAAY,KAAK,KAAK;;CAG/B,AAAQ;CACR,AAAQ,iBAAiB;CACzB,AAAQ,kBAAkB;CAC1B,AAAQ,WAAW;;;;;;;CAQnB,AAAS;;;;;;;;CAST,AAAS;;;;;CAOT,YAEE,eAEA,MACA;AACA,OAAK,gBAAgB;AACrB,OAAK,OAAO;AAEZ,OAAK,aAAa,EAAE;AACpB,OAAK,kBAAkB;AAGvB,OAAK,YAAY,WAAG,OAAO;GACzB,WAAW,GAAG,oBAAoB,GAAG;GACrC,SAAS;GACT,OAAO;IACL,eAAe,EAAE,MAAM,KAAK,oBAAoB,EAAE,CAAC;IACnD,aAAa,EAAE,MAAM,KAAK,WAAW,EAAE,CAAC;IACzC;GACF,CAAC;AACF,OAAK,WAAW,WAAG,OAAO;GACxB,WAAW,GAAG,mBAAmB,GAAG;GACpC,OAAO;IACL,eAAe,EAAE,MAAM,KAAK,oBAAoB,EAAE,CAAC;IACnD,aAAa,EAAE,MAAM,KAAK,WAAW,EAAE,CAAC;IACzC;GACF,CAAC;;;CAOJ,MAAM,oBAAoB,KAAgC;EACxD,MAAM,aAAa,MAAM,qBAAqB,KAAK,KAAK;AACxD,MAAI,WAAW,QACb,QAAO,QAAQ,WAAW,QAAQ,CAAC,SAAS,CAAC,KAAK,SAAS;AACzD,OAAI,QAAQ,IAAI,KAAK,OAAO,IAAI,CAAC;IACjC;AAGJ,MAAI,WAAW,cAAc;GAC3B,MAAM,MAAM,IAAI,IAAI,IAAI,IAAI;AAC5B,UAAO,QAAQ,WAAW,aAAa,CAAC,SAAS,CAAC,KAAK,SAAS;AAC9D,QAAI,aAAa,IAAI,KAAK,OAAO,IAAI,CAAC;KACtC;AAEF,UAAO,IAAI,QAAQ,KAAK,IAAI;;AAG9B,SAAO;;;CAIT,MAAM,WAAW,OAAkB;EACjC,MAAM,EAAE,aAAa;EACrB,MAAM,gBAAgB,MAAM,UAAU,MAAM;EAC5C,IAAI;AACJ,MAAI;AACF,eAAY,KAAK,MAAM,cAAc;WAC9B,GAAG;AAIZ,MAAI,WAAW;AAEb,OAAI,CAAC,UAAU,MAAO,QAAO;GAE7B,MAAM,EAAE,MAAM,YAAY,UAAU;AACpC,SAAM,UAAU,uBAAuB,KAAK,IAAI;AAChD,UAAO;;AAGT,4BAAU,OAAO,kBAAkB,KAAK,KACtC;OAAI,YAAY,KAAK,KACnB,OAAM,IAAI,MAAM,yJAAyJ;;AAG7K,SAAO;;;CAIT,MAAM,yBAAyB,aAAqB,eAAoB;EAStE,MAAM,OAAO,OARI,MAAM,KAAK,UAAU,KAAK,gBAAgB,EACzD,MAAM;GACJ,UAAU,CAAC,GAAG,cAAc,eAAe,CAAC;GAC5C,8BAA8B;GAG/B,EACF,CAAC,EAC0B,MAAW;AAEvC,OAAK,qBAAqB,KAAK,mBAAmB,WAAW;AAC7D,yBAAO,KAAK,mBAAmB,SAAS,MAAW,KAAK,qBAAqB,EAAE,CAAC;AAEhF,SAAO,KAAK,QAAQ,GAAG;;;CAMzB,MAAM,wBAAwB,UAAiB,gBAAoC;EAajF,MAAM,OAAO,OAXI,MAAM,KAAK,UAAU,KAAK,gBAAgB,EACzD,MAAM;GACJ;GACA,8BAA8B;GAC9B,GAAG,kBAAkB;IACnB,yBAAyB;IACzB,GAAG,mBAAmB,OAAO,EAAE,gBAAgB;IAChD;GACF,EACF,CAAC,EAE0B,MAAW;AACvC,OAAK,qBAAqB,KAAK,mBAAmB,WAAW;AAC7D,yBAAO,KAAK,mBAAmB,SAAS,MAAW,KAAK,qBAAqB,EAAE,CAAC;;;CAIlF,oBAAoB;AAClB,MAAI,CAAC,KAAK,eAAgB,OAAM,IAAI,MAAM,gEAAgE;;;CAI5G,qBAAqB,eAAsC;AAAE,OAAK,iBAAiB;;;CAGnF,qBAAqB,WAA+F;EAClH,MAAM,EAAE,YAAY,MAAM,oBAAoB;EAC9C,MAAM,EAAE,YAAY;AACpB,MAAI,CAAC,KAAK,WAAW,SACnB,MAAK,WAAW,WAAW,IAAI,2BAA2B,MAAM,YAAY,MAAM,gBAAgB;MAElG,MAAK,WAAW,SAAS,cAAc,YAAY,MAAM,gBAAgB;;CAK7E,SAAS,OAAoC;AAC3C,OAAK,mBAAmB;AAGxB,SAAO,KAAK,eAAgB;;CAG9B,IAAI,QAAwC;AAAE,SAAO,KAAK,SAAS,QAAQ;;CAC3E,IAAI,SAA0C;AAAE,SAAO,KAAK,SAAS,SAAS;;CAC9E,IAAI,WAA8C;AAAE,SAAO,KAAK,SAAS,WAAW;;CACpF,IAAI,aAAkD;AAAE,SAAO,KAAK,SAAS,aAAa;;CAC1F,IAAI,gBAAwD;AAAE,SAAO,KAAK,SAAS,gBAAgB;;CACnG,IAAI,mBAA8D;AAAE,SAAO,KAAK,SAAS,mBAAmB;;CAC5G,IAAI,+BAAsF;AAAE,SAAO,KAAK,SAAS,+BAA+B;;;;;;CAMhJ,MAAM,iBAAiB,YAA4C;AACjE,QAAM,KAAK,yBAAyB,+BAA+B;GACjE;GACA,QAAQ,aAAa,WAAW;GACjC,CAAC;;CAIJ,MAAM,SAAS,eAAe,OAAO;EAMnC,MAAM,OAAO,OALI,MAAM,KAAK,UAAU,IAAI,IAAI,EAC5C,cAAc,EACZ,GAAG,gBAAgB,EAAE,iBAAiB,MAAM,EAC7C,EACF,CAAC,EAC0B,MAAW;AACvC,OAAK,kBAAkB,KAAK;AAC5B,OAAK,iBAAiB,KAAK;AAC3B,OAAK,QAAQ,SAAS,MAAW,KAAK,qBAAqB,EAAE,CAAC;;CAGhE,kBAAkB;AAChB,OAAK,iBAAiB;AACtB,OAAK,aAAa,EAAE;;CAItB,IAAI,aAAa;AACf,OAAK,mBAAmB;AACxB,kCAAgB,KAAK,WAAW,CAAC;;CAGnC,IAAI,aAA8D;AAChE,OAAK,mBAAmB;AACxB,SAAO,KAAK;;CAGd,IAAI,gBAA8C;AAChD,OAAK,mBAAmB;AACxB,kCAAgB,KAAK,YAAY,QAAQ;;CAG3C,IAAI,gBAA4D;AAC9D,OAAK,mBAAmB;AACxB,iCAAe,KAAK,YAAY,QAAQ;;;;;;CAO1C,MAAM,SACJ,aAMI,EAAE,EACN;EAKA,MAAM,cAJW,MAAM,KAAK,yBAAyB,YAAY,EAC/D,mCAAmB,YAAY,gBAAgB,iBAAiB,EACjE,CAAC,EAE0B,WAAW;EACvC,MAAM,WAAW,KAAK,WAAW;AAEjC,MAAI,WAAW,aACb,OAAM,SAAS,aAAa,WAAW,cAAc,WAAW,eAAe;AAGjF,SAAO;;;;;;CAOT,MAAM,YAAY,SAAsB;AACtC,QAAM,KAAK,yBAAyB,eAAe,EAAE,SAAS,CAAC;AAC/D,SAAO,KAAK,WAAW;;;;;;CASzB,MAAM,cAEJ,MAEA,OAEA,cACA;AAEA,SAAO,KAAK,yBAAyB,iBAAiB,EACpD,YAAY;GACV;GACA;GACA;GACD,EACF,CAAC;;;;;;CAOJ,MAAM,iBAEJ,cACA;AAEA,SAAO,KAAK,yBAAyB,oBAAoB,EAAE,cAAc,CAAC;;;CAM5E,MAAM,UAMJ,SACA;EAMA,MAAM,eAAe,KAAK,aAAa,WAAW;EAElD,MAAM,yCAAyB,QAAQ,GAAG,UAAU,CAAC,QAAQ;EAC7D,MAAM,oCAAoB,eAAe,WAAW;AAClD,kCAAe,OAAO,CACpB,QAAO,eAAe,SAAS,EAAE,SAAS,QAAQ;AAEpD,kCAAe,OAAO,EAAE;AACtB,QAAI,aACF,OAAM,IAAI,MAAM,iGAAiG;AAGnH,WAAO,EAAE,WAAW,QAAQ;;AAE9B,SAAM,IAAI,MAAM,+DAA+D;IAC/E;EAEF,IAAI;AAGJ,MAAI,KAAK,aAAa,WAAW,SAAS;GACxC,MAAM,SAAS,IAAI,iBAAiB;AACpC,UAAO,OAAO,mBAAmB,OAAO;AACxC,eAAY,SAAS,iBAAiB;AACpC,QAAI,4BAAY,aAAa,CAC3B,OAAM,IAAI,MAAM,iGAAiG;AAEnH,WAAO,OAAO,UAAU,aAAa;KACrC;AACF,YAAS,MAAM,KAAK,UAAU,IAAI,IAAI,EACpC,cAAc,QACf,CAAC;QAGF,UAAS,MAAM,KAAK,UAAU,KAAK,oBAAoB,EACrD,MAAM;GACJ,iBAAiB;GACjB;GACD,EACF,CAAC;EAGJ,MAAM,OAAO,MAAM,QAAQ,MAAW;AACtC,yBAAO,KAAK,SAAS,UAAe;AAAE,QAAK,qBAAqB,MAAM;IAAI;;;;;;CAS5E,MAAM,YACJ,UACA,aACA,6BACA;AAGA,MAAI,CAAC,cAAc,UAAW,OAAM,IAAI,MAAM,iCAAiC,WAAW;AAC1F,MAAI,cAAc,UAAU,iBAC1B;OAAI,gBAAgB,OAAW,OAAM,IAAI,MAAM,8CAA8C,WAAW;aAC/F,YAAa,OAAM,IAAI,MAAM,gDAAgD,WAAW;AAGnG,MAAI,aAAa,OAAQ,YAAW;AAEpC,MAAI,CAAC,KAAK,gBAAiB,OAAM,IAAI,MAAM,+CAA+C;EAE1F,MAAM,YAAY,KAAK,gBAAgB,QAAQ,QAAQ,SAAS;EAChE,MAAM,WAAW,MAAM,KAAK,UAAU,IAAI,WAAW;GACnD,WAAW;GACX,cAAc;IACZ,IAAI,KAAK;IACT,QAAQ;IAER,GAAG,gBAAgB,UAAa,EAAE,KAAK,aAAa;IACrD;GACF,CAAC;AACF,MAAI,4BACF,QAAO,SAAS;AAElB,SAAO,SAAS,aAAa;;CAU/B,MAAM,qBAAqB,6BAAuC;AAChE,SAAO,KAAK,YAAY,QAAQ,QAAW,4BAA4B;;;;;;CAOzE,MAAM,eAAe,6BAAuC;AAC1D,SAAO,KAAK,YAAY,QAAQ,QAAW,4BAA4B;;CAUzE,MAAM,eAAe,8BAA8B,OAAO;AACxD,SAAO,KAAK,YAAY,QAAQ,QAAW,4BAA4B;;CASzE,MAAM,cAAc,8BAA8B,OAAO;AACvD,SAAO,KAAK,YAAY,OAAO,QAAW,4BAA4B;;CAIxE,MAAM,SAAS;AACb,QAAM,KAAK,SAAS,OAAO,GAAG;AAC9B,OAAK,WAAW;;;;;CASlB,MAAM,kBAA4C;AAOhD,UADa,OALG,MAAM,KAAK,SAAS,IAAI,eAAe,EACrD,cAAc,EACZ,QAAQ,+EACT,EACF,CAAC,EACyB,MAAwC,EACvD;;CAGd,MAAM,qBAAqB,MAAqC;EAC9D,MAAM,cAAc,MAAM,KAAK,iBAAiB;EAChD,MAAM,kDAAkC,cAAc,MAAM,EAAE,SAAS,SAAS;AAEhF,MAAI,SAAS,OAAO;AAClB,OAAI,CAAC,yBAEH;AAEF,SAAM,KAAK,SAAS,OAAO,eAAe,yBAAyB,KAAK;QAEtD,OAAM,KAAK,SAAS,KAAK,eAAe,EACxD,MAAM;GACJ,MAAM,QAAQ;GACd,MAAM;GACP,EACF,CAAC;;;CAKN,MAAM,MAAM,sBAA8B,MAkBvC;EACD,IAAI;EACJ,IAAI;AACJ,MAAI,qBAAqB,SAAS,IAAI,CACpC,gBAAe;MAEf,UAAS;AAuBX,UAnBiB,MAAM,KAAK,SAAS,KAAK,eAAe;GACvD,cAAc;IACZ,GAAG,MAAM,iBAAiB,SAAS,EAAE,uBAAuB,OAAO;IACnE,8BAAc,MAAM,aAAa,IAAI,EAAE,cAAc,MAAM,cAAc;IACzE,GAAG,MAAM,SAAS,WAAW,EAAE,mBAAmB,MAAM;IACzD;GACD,MAAM;IACJ,MAAM,MAAM,QAAQ;IACpB,GAAG,gBAAgB;KACjB,MAAM,MAAM,UAAU,UAAU;KAChC;KACD;IACD,GAAG,UAAU;KACX,MAAM;KACN;KACD;IACF;GACF,CAAC,EAEc,MAAM;;;;;;CAOxB,MAAM,iBAAiB,cAAsB;AAC3C,QAAM,KAAK,SAAS,OAAO,eAAe,eAAe;;CAK3D,aAAa,6BAA6B,MAAqB,YAA6C;AAG1G,MAAI,YAAY,KAAK,KAAK,WAAW,QACnC,OAAM,IAAI,MAAM,8GAA8G;EAKhI,MAAM,aAAa,MAAM,qBAAqB,KAAK;EASnD,MAAM,OAAO,OAPI,MAAM,WAAG,KAAK,qBAAqB;GAClD,GAAG;GACH,MAAM,EACJ,YACD;GACF,CAAC,EAE0B,MAAW;EACvC,MAAM,iBAAiB,IAAI,kBAAkB,KAAK,eAAe,KAAK;AAGtE,iBAAe,kBAAkB,KAAK;AACtC,iBAAe,iBAAiB,KAAK;AACrC,yBAAO,KAAK,SAAS,MAAW,eAAe,qBAAqB,EAAE,CAAC;AAEvE,SAAO"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/lib/utils.ts","../src/lib/GoogleSpreadsheetRow.ts","../src/lib/GoogleSpreadsheetCellErrorValue.ts","../src/lib/GoogleSpreadsheetCell.ts","../src/lib/GoogleSpreadsheetWorksheet.ts","../src/lib/types/auth-types.ts","../src/lib/GoogleSpreadsheet.ts"],"sourcesContent":["import * as _ from './toolkit';\n\nexport function getFieldMask(obj: Record<string, unknown>) {\n let fromGrid = '';\n const fromRoot = Object.keys(obj).filter((key) => key !== 'gridProperties').join(',');\n\n if (obj.gridProperties) {\n fromGrid = Object.keys(obj.gridProperties).map((key) => `gridProperties.${key}`).join(',');\n if (fromGrid.length && fromRoot.length) {\n fromGrid = `${fromGrid},`;\n }\n }\n return fromGrid + fromRoot;\n}\n\nexport function columnToLetter(column: number) {\n let temp;\n let letter = '';\n let col = column;\n while (col > 0) {\n temp = (col - 1) % 26;\n letter = String.fromCharCode(temp + 65) + letter;\n col = (col - temp - 1) / 26;\n }\n return letter;\n}\n\nexport function letterToColumn(letter: string) {\n let column = 0;\n const { length } = letter;\n for (let i = 0; i < length; i++) {\n column += (letter.charCodeAt(i) - 64) * 26 ** (length - i - 1);\n }\n return column;\n}\n\nexport function checkForDuplicateHeaders(headers: string[]) {\n // check for duplicate headers\n const checkForDupes = _.groupBy(headers); // { c1: ['c1'], c2: ['c2', 'c2' ]}\n _.each(checkForDupes, (grouped, header) => {\n if (!header) return; // empty columns are skipped, so multiple is ok\n if (grouped.length > 1) {\n throw new Error(`Duplicate header detected: \"${header}\". Please make sure all non-empty headers are unique`);\n }\n });\n}\n\n","import { GoogleSpreadsheetWorksheet } from './GoogleSpreadsheetWorksheet';\nimport { columnToLetter } from './utils';\n\n\n// TODO: add type for possible row values (currently any)\n\nexport class GoogleSpreadsheetRow<T extends Record<string, any> = Record<string, any>> {\n constructor(\n /** parent GoogleSpreadsheetWorksheet instance */\n readonly _worksheet: GoogleSpreadsheetWorksheet,\n /** the A1 row (1-indexed) */\n private _rowNumber: number,\n /** raw underlying data for row */\n private _rawData: any[]\n ) {\n this._padRawData();\n }\n\n /** pad _rawData with empty strings so it always matches header length */\n private _padRawData() {\n const headerLength = this._worksheet.headerValues.length;\n while (this._rawData.length < headerLength) {\n this._rawData.push('');\n }\n }\n\n private _deleted = false;\n get deleted() { return this._deleted; }\n\n /** row number (matches A1 notation, ie first row is 1) */\n get rowNumber() { return this._rowNumber; }\n /**\n * @internal\n * Used internally to update row numbers after deleting rows.\n * Should not be called directly.\n */\n _updateRowNumber(newRowNumber: number) {\n this._rowNumber = newRowNumber;\n }\n\n /**\n * @internal\n * Used internally to mark row as deleted.\n * Should not be called directly.\n */\n _markDeleted() {\n this._deleted = true;\n }\n\n get a1Range() {\n return [\n this._worksheet.a1SheetName,\n '!',\n `A${this._rowNumber}`,\n ':',\n `${columnToLetter(this._worksheet.headerValues.length)}${this._rowNumber}`,\n ].join('');\n }\n\n /** get row's value of specific cell (by header key) */\n get(key: keyof T) {\n const index = this._worksheet.headerValues.indexOf(key as string);\n return this._rawData[index];\n }\n /** set row's value of specific cell (by header key) */\n set<K extends keyof T>(key: K, val: T[K]) {\n const index = this._worksheet.headerValues.indexOf(key as string);\n this._rawData[index] = val;\n }\n /** set multiple values in the row at once from an object */\n assign(obj: Partial<T>) {\n // eslint-disable-next-line no-restricted-syntax, guard-for-in\n for (const key in obj) this.set(key, obj[key] as any);\n }\n\n /** return raw object of row data */\n toObject() {\n const o: Partial<T> = {};\n for (let i = 0; i < this._worksheet.headerValues.length; i++) {\n const key: keyof T = this._worksheet.headerValues[i];\n if (!key) continue;\n o[key] = this._rawData[i];\n }\n return o;\n }\n\n /** save row values */\n async save(options?: { raw?: boolean }) {\n if (this._deleted) throw new Error('This row has been deleted - call getRows again before making updates.');\n\n const response = await this._worksheet._spreadsheet.sheetsApi.put(`values/${encodeURIComponent(this.a1Range)}`, {\n searchParams: {\n valueInputOption: options?.raw ? 'RAW' : 'USER_ENTERED',\n includeValuesInResponse: true,\n },\n json: {\n range: this.a1Range,\n majorDimension: 'ROWS',\n values: [this._rawData],\n },\n });\n const data = await response.json<any>();\n this._rawData = data.updatedData.values?.[0] || [];\n this._padRawData();\n }\n\n /** delete this row */\n async delete() {\n if (this._deleted) throw new Error('This row has been deleted - call getRows again before making updates.');\n\n const result = await this._worksheet._makeSingleUpdateRequest('deleteRange', {\n range: {\n sheetId: this._worksheet.sheetId,\n startRowIndex: this._rowNumber - 1, // this format is zero indexed, because of course...\n endRowIndex: this._rowNumber,\n },\n shiftDimension: 'ROWS',\n });\n this._deleted = true;\n this._worksheet._shiftRowCache(this.rowNumber);\n\n return result;\n }\n\n /**\n * @internal\n * Used internally to clear row data after calling sheet.clearRows\n * Should not be called directly.\n */\n _clearRowData() {\n for (let i = 0; i < this._rawData.length; i++) {\n this._rawData[i] = '';\n }\n }\n}\n","import { CellValueErrorType, ErrorValue } from './types/sheets-types';\n\n/**\n * Cell error\n *\n * not a js \"error\" that gets thrown, but a value that holds an error code and message for a cell\n * it's useful to use a class so we can check `instanceof`\n\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#ErrorType\n */\nexport class GoogleSpreadsheetCellErrorValue {\n /**\n * type of the error\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/other#ErrorType\n * */\n readonly type: CellValueErrorType;\n\n /** A message with more information about the error (in the spreadsheet's locale) */\n readonly message: string;\n\n constructor(rawError: ErrorValue) {\n this.type = rawError.type;\n this.message = rawError.message;\n }\n}\n","/* eslint-disable max-classes-per-file */\nimport * as _ from './toolkit';\n\nimport { columnToLetter } from './utils';\n\nimport { GoogleSpreadsheetWorksheet } from './GoogleSpreadsheetWorksheet';\nimport { GoogleSpreadsheetCellErrorValue } from './GoogleSpreadsheetCellErrorValue';\n\nimport {\n CellData,\n CellFormat, CellValueType, ColumnIndex, RowIndex,\n} from './types/sheets-types';\n\nexport class GoogleSpreadsheetCell {\n private _rawData?: CellData;\n private _draftData: any = {};\n private _error?: GoogleSpreadsheetCellErrorValue;\n private _deleted = false;\n\n constructor(\n readonly _sheet: GoogleSpreadsheetWorksheet,\n private _rowIndex: RowIndex,\n private _columnIndex: ColumnIndex,\n rawCellData: CellData\n ) {\n this._updateRawData(rawCellData);\n this._rawData = rawCellData; // so TS does not complain\n }\n\n get deleted() { return this._deleted; }\n\n // TODO: figure out how to deal with empty rawData\n // newData can be undefined/null if the cell is totally empty and unformatted\n /**\n * update cell using raw CellData coming back from sheets API\n * @internal\n */\n _updateRawData(newData: CellData) {\n this._rawData = newData;\n this._draftData = {};\n if (this._rawData?.effectiveValue && 'errorValue' in this._rawData.effectiveValue) {\n this._error = new GoogleSpreadsheetCellErrorValue(this._rawData.effectiveValue.errorValue);\n } else {\n this._error = undefined;\n }\n }\n\n // CELL LOCATION/ADDRESS /////////////////////////////////////////////////////////////////////////\n get rowIndex() { return this._rowIndex; }\n get columnIndex() { return this._columnIndex; }\n get a1Column() { return columnToLetter(this._columnIndex + 1); }\n get a1Row() { return this._rowIndex + 1; } // a1 row numbers start at 1 instead of 0\n get a1Address() { return `${this.a1Column}${this.a1Row}`; }\n\n /**\n * @internal\n * Used internally to update cell indices after deleting rows/columns.\n * Should not be called directly.\n */\n _updateIndices(rowIndex: RowIndex, columnIndex: ColumnIndex) {\n this._rowIndex = rowIndex;\n this._columnIndex = columnIndex;\n }\n\n /**\n * @internal\n * Used internally to mark cell as deleted.\n * Should not be called directly.\n */\n _markDeleted() {\n this._deleted = true;\n }\n\n // CELL CONTENTS - VALUE/FORMULA/NOTES ///////////////////////////////////////////////////////////\n get value(): number | boolean | string | null | GoogleSpreadsheetCellErrorValue {\n // const typeKey = _.keys(this._rawData.effectiveValue)[0];\n if (this._draftData.value !== undefined) throw new Error('Value has been changed');\n if (this._error) return this._error;\n if (!this._rawData?.effectiveValue) return null;\n return _.values(this._rawData.effectiveValue)[0];\n }\n\n\n set value(newValue: number | boolean | Date | string | null | undefined | GoogleSpreadsheetCellErrorValue) {\n if (this._deleted) throw new Error('This cell has been deleted - reload cells before making updates.');\n\n // had to include the GoogleSpreadsheetCellErrorValue in the type to make TS happy\n if (newValue instanceof GoogleSpreadsheetCellErrorValue) {\n throw new Error(\"You can't manually set a value to an error\");\n }\n\n if (_.isBoolean(newValue)) {\n this._draftData.valueType = 'boolValue';\n } else if (_.isString(newValue)) {\n if (newValue.substring(0, 1) === '=') this._draftData.valueType = 'formulaValue';\n else this._draftData.valueType = 'stringValue';\n } else if (_.isFinite(newValue)) {\n this._draftData.valueType = 'numberValue';\n } else if (_.isNil(newValue)) {\n // null or undefined\n this._draftData.valueType = 'stringValue';\n newValue = '';\n } else {\n throw new Error('Set value to boolean, string, or number');\n }\n this._draftData.value = newValue;\n }\n\n get valueType(): CellValueType | null {\n // an error only happens with a formula (as far as I know)\n if (this._error) return 'errorValue';\n if (!this._rawData?.effectiveValue) return null;\n return _.keys(this._rawData.effectiveValue)[0] as CellValueType;\n }\n\n /** The formatted value of the cell - this is the value as it's shown to the user */\n get formattedValue(): string | null { return this._rawData?.formattedValue || null; }\n\n get formula() { return _.get(this._rawData, 'userEnteredValue.formulaValue', null); }\n set formula(newValue: string | null) {\n if (!newValue) throw new Error('To clear a formula, set `cell.value = null`');\n if (newValue.substring(0, 1) !== '=') throw new Error('formula must begin with \"=\"');\n this.value = newValue; // use existing value setter\n }\n /**\n * @deprecated use `cell.errorValue` instead\n */\n get formulaError() { return this._error; }\n /**\n * error contained in the cell, which can happen with a bad formula (maybe some other weird cases?)\n */\n get errorValue() { return this._error; }\n\n get numberValue(): number | undefined {\n if (this.valueType !== 'numberValue') return undefined;\n return this.value as number;\n }\n set numberValue(val: number | undefined) {\n this.value = val;\n }\n\n get boolValue(): boolean | undefined {\n if (this.valueType !== 'boolValue') return undefined;\n return this.value as boolean;\n }\n set boolValue(val: boolean | undefined) {\n this.value = val;\n }\n\n get stringValue(): string | undefined {\n if (this.valueType !== 'stringValue') return undefined;\n return this.value as string;\n }\n set stringValue(val: string | undefined) {\n this._draftData.valueType = 'stringValue';\n this._draftData.value = val || '';\n }\n\n /**\n * Hyperlink contained within the cell.\n *\n * To modify, do not set directly. Instead set cell.formula, for example `cell.formula = \\'=HYPERLINK(\"http://google.com\", \"Google\")\\'`\n */\n get hyperlink() {\n if (this._draftData.value) throw new Error('Save cell to be able to read hyperlink');\n return this._rawData?.hyperlink;\n }\n\n /** a note attached to the cell */\n get note(): string {\n return this._draftData.note !== undefined ? this._draftData.note : this._rawData?.note || '';\n }\n set note(newVal: string | null | undefined | false) {\n if (newVal === null || newVal === undefined || newVal === false) newVal = '';\n if (!_.isString(newVal)) throw new Error('Note must be a string');\n if (newVal === this._rawData?.note) delete this._draftData.note;\n else this._draftData.note = newVal;\n }\n\n // CELL FORMATTING ///////////////////////////////////////////////////////////////////////////////\n get userEnteredFormat() { return Object.freeze(this._rawData?.userEnteredFormat); }\n get effectiveFormat() { return Object.freeze(this._rawData?.effectiveFormat); }\n\n private _getFormatParam<T extends keyof CellFormat>(param: T): Readonly<CellFormat[T]> {\n // we freeze the object so users don't change nested props accidentally\n // TODO: figure out something that would throw an error if you try to update it?\n if (_.get(this._draftData, `userEnteredFormat.${param}`)) {\n throw new Error('User format is unsaved - save the cell to be able to read it again');\n }\n // TODO: figure out how to deal with possible empty rawData\n // if (!this._rawData?.userEnteredFormat?.[param]) {\n // return undefined;\n // }\n return Object.freeze(this._rawData!.userEnteredFormat[param]);\n }\n\n private _setFormatParam<T extends keyof CellFormat>(param: T, newVal: CellFormat[T]) {\n if (_.isEqual(newVal, _.get(this._rawData, `userEnteredFormat.${param}`))) {\n _.unset(this._draftData, `userEnteredFormat.${param}`);\n } else {\n _.set(this._draftData, `userEnteredFormat.${param}`, newVal);\n this._draftData.clearFormat = false;\n }\n }\n\n // format getters\n get numberFormat() { return this._getFormatParam('numberFormat'); }\n get backgroundColor() { return this._getFormatParam('backgroundColor'); }\n get backgroundColorStyle() { return this._getFormatParam('backgroundColorStyle'); }\n get borders() { return this._getFormatParam('borders'); }\n get padding() { return this._getFormatParam('padding'); }\n get horizontalAlignment() { return this._getFormatParam('horizontalAlignment'); }\n get verticalAlignment() { return this._getFormatParam('verticalAlignment'); }\n get wrapStrategy() { return this._getFormatParam('wrapStrategy'); }\n get textDirection() { return this._getFormatParam('textDirection'); }\n get textFormat() { return this._getFormatParam('textFormat'); }\n get hyperlinkDisplayType() { return this._getFormatParam('hyperlinkDisplayType'); }\n get textRotation() { return this._getFormatParam('textRotation'); }\n\n // format setters\n set numberFormat(newVal: CellFormat['numberFormat']) { this._setFormatParam('numberFormat', newVal); }\n set backgroundColor(newVal: CellFormat['backgroundColor']) { this._setFormatParam('backgroundColor', newVal); }\n set backgroundColorStyle(newVal: CellFormat['backgroundColorStyle']) { this._setFormatParam('backgroundColorStyle', newVal); }\n set borders(newVal: CellFormat['borders']) { this._setFormatParam('borders', newVal); }\n set padding(newVal: CellFormat['padding']) { this._setFormatParam('padding', newVal); }\n set horizontalAlignment(newVal: CellFormat['horizontalAlignment']) { this._setFormatParam('horizontalAlignment', newVal); }\n set verticalAlignment(newVal: CellFormat['verticalAlignment']) { this._setFormatParam('verticalAlignment', newVal); }\n set wrapStrategy(newVal: CellFormat['wrapStrategy']) { this._setFormatParam('wrapStrategy', newVal); }\n set textDirection(newVal: CellFormat['textDirection']) { this._setFormatParam('textDirection', newVal); }\n set textFormat(newVal: CellFormat['textFormat']) { this._setFormatParam('textFormat', newVal); }\n set hyperlinkDisplayType(newVal: CellFormat['hyperlinkDisplayType']) { this._setFormatParam('hyperlinkDisplayType', newVal); }\n set textRotation(newVal: CellFormat['textRotation']) { this._setFormatParam('textRotation', newVal); }\n\n clearAllFormatting() {\n // need to track this separately since by setting/unsetting things, we may end up with\n // this._draftData.userEnteredFormat as an empty object, but not an intent to clear it\n this._draftData.clearFormat = true;\n delete this._draftData.userEnteredFormat;\n }\n\n // SAVING + UTILS ////////////////////////////////////////////////////////////////////////////////\n\n // returns true if there are any updates that have not been saved yet\n get _isDirty() {\n // have to be careful about checking undefined rather than falsy\n // in case a new value is empty string or 0 or false\n if (this._draftData.note !== undefined) return true;\n if (_.keys(this._draftData.userEnteredFormat).length) return true;\n if (this._draftData.clearFormat) return true;\n if (this._draftData.value !== undefined) return true;\n return false;\n }\n\n discardUnsavedChanges() {\n this._draftData = {};\n }\n\n /**\n * saves updates for single cell\n * usually it's better to make changes and call sheet.saveUpdatedCells\n * */\n async save() {\n await this._sheet.saveCells([this]);\n }\n\n /**\n * used by worksheet when saving cells\n * returns an individual batchUpdate request to update the cell\n * @internal\n */\n _getUpdateRequest() {\n // this logic should match the _isDirty logic above\n // but we need it broken up to build the request below\n const isValueUpdated = this._draftData.value !== undefined;\n const isNoteUpdated = this._draftData.note !== undefined;\n const isFormatUpdated = !!_.keys(this._draftData.userEnteredFormat || {}).length;\n const isFormatCleared = this._draftData.clearFormat;\n\n // if no updates, we return null, which we can filter out later before sending requests\n if (!_.some([isValueUpdated, isNoteUpdated, isFormatUpdated, isFormatCleared])) {\n return null;\n }\n\n // build up the formatting object, which has some quirks...\n const format = {\n // have to pass the whole object or it will clear existing properties\n ...this._rawData?.userEnteredFormat,\n ...this._draftData.userEnteredFormat,\n };\n // if background color already set, cell has backgroundColor and backgroundColorStyle\n // but backgroundColorStyle takes precendence so we must remove to set the color\n // see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/cells#CellFormat\n if (_.get(this._draftData, 'userEnteredFormat.backgroundColor')) {\n delete (format.backgroundColorStyle);\n }\n\n return {\n updateCells: {\n rows: [{\n values: [{\n ...isValueUpdated && {\n userEnteredValue: { [this._draftData.valueType]: this._draftData.value },\n },\n ...isNoteUpdated && {\n note: this._draftData.note,\n },\n ...isFormatUpdated && {\n userEnteredFormat: format,\n },\n ...isFormatCleared && {\n userEnteredFormat: {},\n },\n }],\n }],\n // turns into a string of which fields to update ex \"note,userEnteredFormat\"\n fields: _.keys(_.pickBy({\n userEnteredValue: isValueUpdated,\n note: isNoteUpdated,\n userEnteredFormat: isFormatUpdated || isFormatCleared,\n })).join(','),\n start: {\n sheetId: this._sheet.sheetId,\n rowIndex: this.rowIndex,\n columnIndex: this.columnIndex,\n },\n },\n };\n }\n}\n","import { type ReadableStream } from 'stream/web';\nimport * as _ from './toolkit';\n\nimport { GoogleSpreadsheetRow } from './GoogleSpreadsheetRow';\nimport { GoogleSpreadsheetCell } from './GoogleSpreadsheetCell';\n\nimport {\n getFieldMask, columnToLetter, letterToColumn, checkForDuplicateHeaders,\n} from './utils';\nimport { GoogleSpreadsheet } from './GoogleSpreadsheet';\nimport {\n A1Range, SpreadsheetId, DimensionRangeIndexes, WorksheetDimension, WorksheetId, WorksheetProperties, A1Address,\n RowIndex, ColumnIndex, DataFilterWithoutWorksheetId, DataFilter, GetValuesRequestOptions, WorksheetGridProperties,\n WorksheetDimensionProperties, CellDataRange, AddRowOptions, GridRangeWithOptionalWorksheetId,\n DataValidationRule,\n ProtectedRange, Integer, GridCoordinateWithOptionalWorksheetId, PasteType, DelimiterType, PasteOrientation,\n SortSpec, SourceAndDestination, DimensionRange,\n FilterView, ConditionalFormatRule, BandedRange, DeveloperMetadata, DataFilterObject,\n} from './types/sheets-types';\n\n\n// types of cell data accepted when using row based api\ntype RowCellData = string | number | boolean | Date;\n// raw row data can be passed in as an array or an object using header values as keys\ntype RawRowData = RowCellData[] | Record<string, RowCellData>;\n\nexport class GoogleSpreadsheetWorksheet {\n // assume \"header row\" (for row-based calls) is in first row, can be adjusted later\n private _headerRowIndex = 1;\n\n private _rawProperties: WorksheetProperties | null = null;\n private _cells: GoogleSpreadsheetCell[][] = [];\n private _rowMetadata: any[] = [];\n private _columnMetadata: any[] = [];\n private _protectedRanges: ProtectedRange[] | null = null;\n\n private _headerValues: string[] | undefined;\n get headerValues() {\n if (!this._headerValues) {\n throw new Error('Header values are not yet loaded');\n }\n return this._headerValues!;\n }\n\n constructor(\n /** parent GoogleSpreadsheet instance */\n readonly _spreadsheet: GoogleSpreadsheet,\n rawProperties: WorksheetProperties,\n rawCellData?: CellDataRange[],\n protectedRanges?: ProtectedRange[]\n ) {\n this._headerRowIndex = 1;\n\n // basic properties\n this._rawProperties = rawProperties;\n\n this._cells = []; // we will use a 2d sparse array to store cells;\n\n this._rowMetadata = []; // 1d sparse array\n this._columnMetadata = [];\n if (protectedRanges) this._protectedRanges = protectedRanges;\n\n if (rawCellData) this._fillCellData(rawCellData);\n }\n\n // INTERNAL UTILITY FUNCTIONS ////////////////////////////////////////////////////////////////////\n\n updateRawData(properties: WorksheetProperties, rawCellData: CellDataRange[], protectedRanges?: ProtectedRange[]) {\n this._rawProperties = properties;\n this._fillCellData(rawCellData);\n if (protectedRanges) this._protectedRanges = protectedRanges;\n }\n\n async _makeSingleUpdateRequest(requestType: string, requestParams: any) {\n // pass the call up to the parent\n return this._spreadsheet._makeSingleUpdateRequest(requestType, {\n ...requestParams,\n });\n }\n\n private _ensureInfoLoaded() {\n if (!this._rawProperties) {\n throw new Error('You must call `doc.loadInfo()` again before accessing this property');\n }\n }\n\n /**\n * clear local cache of sheet data/properties\n */\n resetLocalCache(\n /** set to true to clear data only, leaving sheet metadata/propeties intact */\n dataOnly?: boolean\n ) {\n if (!dataOnly) this._rawProperties = null;\n this._headerValues = undefined;\n this._headerRowIndex = 1;\n this._cells = [];\n }\n\n private _fillCellData(\n dataRanges: CellDataRange[]\n ) {\n _.each(dataRanges, (range) => {\n const startRow = range.startRow || 0;\n const startColumn = range.startColumn || 0;\n const numRows = range.rowMetadata.length;\n const numColumns = range.columnMetadata.length;\n\n // update cell data for entire range\n for (let i = 0; i < numRows; i++) {\n const actualRow = startRow + i;\n for (let j = 0; j < numColumns; j++) {\n const actualColumn = startColumn + j;\n\n // if the row has not been initialized yet, do it\n if (!this._cells[actualRow]) this._cells[actualRow] = [];\n\n // see if the response includes some info for the cell\n const cellData = _.get(range, `rowData[${i}].values[${j}]`);\n\n // update the cell object or create it\n if (this._cells[actualRow][actualColumn]) {\n this._cells[actualRow][actualColumn]._updateRawData(cellData);\n } else {\n this._cells[actualRow][actualColumn] = new GoogleSpreadsheetCell(\n this,\n actualRow,\n actualColumn,\n cellData\n );\n }\n }\n }\n\n // update row metadata\n for (let i = 0; i < range.rowMetadata.length; i++) {\n this._rowMetadata[startRow + i] = range.rowMetadata[i];\n }\n // update column metadata\n for (let i = 0; i < range.columnMetadata.length; i++) {\n this._columnMetadata[startColumn + i] = range.columnMetadata[i];\n }\n });\n }\n\n // TODO: make this handle A1 ranges as well?\n private _addSheetIdToRange(range: GridRangeWithOptionalWorksheetId) {\n if (range.sheetId && range.sheetId !== this.sheetId) {\n throw new Error('Leave sheet ID blank or set to matching ID of this sheet');\n }\n return {\n ...range,\n sheetId: this.sheetId,\n };\n }\n\n\n // PROPERTY GETTERS //////////////////////////////////////////////////////////////////////////////\n\n private _getProp<T extends keyof WorksheetProperties>(param: T): WorksheetProperties[T] {\n this._ensureInfoLoaded();\n // see note about asserting info loaded on GoogleSpreasheet\n return this._rawProperties![param];\n }\n // eslint-disable-line no-unused-vars\n private _setProp<T extends keyof WorksheetProperties>(_param: T, _newVal: WorksheetProperties[T]) {\n throw new Error('Do not update directly - use `updateProperties()`');\n }\n\n get sheetId() { return this._getProp('sheetId'); }\n get title() { return this._getProp('title'); }\n get index() { return this._getProp('index'); }\n get sheetType() { return this._getProp('sheetType'); }\n get gridProperties() { return this._getProp('gridProperties'); }\n get hidden() { return this._getProp('hidden'); }\n get tabColor() { return this._getProp('tabColor'); }\n get rightToLeft() { return this._getProp('rightToLeft'); }\n get protectedRanges() { return this._protectedRanges; }\n private get _headerRange() {\n return `A${this._headerRowIndex}:${this.lastColumnLetter}${this._headerRowIndex}`;\n }\n\n set sheetId(newVal: WorksheetProperties['sheetId']) { this._setProp('sheetId', newVal); }\n set title(newVal: WorksheetProperties['title']) { this._setProp('title', newVal); }\n set index(newVal: WorksheetProperties['index']) { this._setProp('index', newVal); }\n set sheetType(newVal: WorksheetProperties['sheetType']) { this._setProp('sheetType', newVal); }\n set gridProperties(newVal: WorksheetProperties['gridProperties']) { this._setProp('gridProperties', newVal); }\n set hidden(newVal: WorksheetProperties['hidden']) { this._setProp('hidden', newVal); }\n set tabColor(newVal: WorksheetProperties['tabColor']) { this._setProp('tabColor', newVal); }\n set rightToLeft(newVal: WorksheetProperties['rightToLeft']) { this._setProp('rightToLeft', newVal); }\n\n get rowCount() {\n this._ensureInfoLoaded();\n return this.gridProperties.rowCount;\n }\n get columnCount() {\n this._ensureInfoLoaded();\n return this.gridProperties.columnCount;\n }\n\n get a1SheetName() { return `'${this.title.replace(/'/g, \"''\")}'`; }\n get encodedA1SheetName() { return encodeURIComponent(this.a1SheetName); }\n get lastColumnLetter() {\n // TODO: double check behaviour if data not loaded\n return this.columnCount ? columnToLetter(this.columnCount) : '';\n }\n\n\n // CELLS-BASED INTERACTIONS //////////////////////////////////////////////////////////////////////\n\n get cellStats() {\n let allCells = _.flatten(this._cells);\n allCells = _.compact(allCells);\n return {\n nonEmpty: _.filter(allCells, (c) => c.value).length,\n loaded: allCells.length,\n total: this.rowCount * this.columnCount,\n };\n }\n\n getCellByA1(a1Address: A1Address) {\n const split = a1Address.match(/([A-Z]+)([0-9]+)/);\n if (!split) throw new Error(`Cell address \"${a1Address}\" not valid`);\n const columnIndex = letterToColumn(split[1]);\n const rowIndex = parseInt(split[2]);\n return this.getCell(rowIndex - 1, columnIndex - 1);\n }\n\n getCell(rowIndex: RowIndex, columnIndex: ColumnIndex) {\n if (rowIndex < 0 || columnIndex < 0) throw new Error('Min coordinate is 0, 0');\n if (rowIndex >= this.rowCount || columnIndex >= this.columnCount) {\n throw new Error(`Out of bounds, sheet is ${this.rowCount} by ${this.columnCount}`);\n }\n\n if (!_.get(this._cells, `[${rowIndex}][${columnIndex}]`)) {\n throw new Error('This cell has not been loaded yet');\n }\n return this._cells[rowIndex][columnIndex];\n }\n\n async loadCells(sheetFilters?: DataFilterWithoutWorksheetId | DataFilterWithoutWorksheetId[]) {\n // load the whole sheet\n if (!sheetFilters) return this._spreadsheet.loadCells(this.a1SheetName);\n\n const filtersArray = _.isArray(sheetFilters) ? sheetFilters : [sheetFilters];\n const filtersArrayWithSheetId: DataFilter[] = _.map(filtersArray, (filter) => {\n // add sheet name to A1 ranges\n if (_.isString(filter)) {\n if (filter.startsWith(this.a1SheetName)) return filter;\n return `${this.a1SheetName}!${filter}`;\n }\n if (_.isObject(filter)) {\n // pass through developer metadata filters without adding sheetId\n if ('developerMetadataLookup' in filter) {\n return filter;\n }\n\n // check if the user passed in a sheet id\n const filterAny = filter as any;\n if (filterAny.sheetId && filterAny.sheetId !== this.sheetId) {\n throw new Error('Leave sheet ID blank or set to matching ID of this sheet');\n }\n\n return { sheetId: this.sheetId, ...filter };\n }\n throw new Error('Each filter must be a A1 range string or gridrange object');\n });\n return this._spreadsheet.loadCells(filtersArrayWithSheetId);\n }\n\n async saveUpdatedCells() {\n const cellsToSave = _.filter(_.flatten(this._cells), { _isDirty: true });\n if (cellsToSave.length) {\n await this.saveCells(cellsToSave);\n }\n // TODO: do we want to return stats? or the cells that got updated?\n }\n\n async saveCells(cellsToUpdate: GoogleSpreadsheetCell[]) {\n // we send an individual \"updateCells\" request for each cell\n // because the fields that are udpated for each group are the same\n // and we dont want to accidentally overwrite something\n const requests = _.map(cellsToUpdate, (cell) => cell._getUpdateRequest());\n const responseRanges = _.map(cellsToUpdate, (c) => `${this.a1SheetName}!${c.a1Address}`);\n\n // if nothing is being updated the request returned is just `null`\n // so we make sure at least 1 request is valid - otherwise google throws a 400\n if (!_.compact(requests).length) {\n throw new Error('At least one cell must have something to update');\n }\n\n await this._spreadsheet._makeBatchUpdateRequest(requests, responseRanges);\n }\n\n // SAVING THIS FOR FUTURE USE\n // puts the cells that need updating into batches\n // async updateCellsByBatches() {\n // // saving this code, but it's problematic because each group must have the same update fields\n // const cellsByRow = _.groupBy(cellsToUpdate, 'rowIndex');\n // const groupsToSave = [];\n // _.each(cellsByRow, (cells, rowIndex) => {\n // let cellGroup = [];\n // _.each(cells, (c) => {\n // if (!cellGroup.length) {\n // cellGroup.push(c);\n // } else if (\n // cellGroup[cellGroup.length - 1].columnIndex ===\n // c.columnIndex - 1\n // ) {\n // cellGroup.push(c);\n // } else {\n // groupsToSave.push(cellGroup);\n // cellGroup = [];\n // }\n // });\n // groupsToSave.push(cellGroup);\n // });\n // const requests = _.map(groupsToSave, (cellGroup) => ({\n // updateCells: {\n // rows: [\n // {\n // values: _.map(cellGroup, (cell) => ({\n // ...cell._draftData.value && {\n // userEnteredValue: { [cell._draftData.valueType]: cell._draftData.value },\n // },\n // ...cell._draftData.note !== undefined && {\n // note: cell._draftData.note ,\n // },\n // ...cell._draftData.userEnteredFormat && {\n // userEnteredValue: cell._draftData.userEnteredFormat,\n // },\n // })),\n // },\n // ],\n // fields: 'userEnteredValue,note,userEnteredFormat',\n // start: {\n // sheetId: this.sheetId,\n // rowIndex: cellGroup[0].rowIndex,\n // columnIndex: cellGroup[0].columnIndex,\n // },\n // },\n // }));\n // const responseRanges = _.map(groupsToSave, (cellGroup) => {\n // let a1Range = cellGroup[0].a1Address;\n // if (cellGroup.length > 1)\n // a1Range += `:${cellGroup[cellGroup.length - 1].a1Address}`;\n // return `${cellGroup[0]._sheet.a1SheetName}!${a1Range}`;\n // });\n // }\n\n // ROW BASED FUNCTIONS ///////////////////////////////////////////////////////////////////////////\n\n async _ensureHeaderRowLoaded() {\n if (!this._headerValues) {\n await this.loadHeaderRow();\n }\n }\n\n async loadHeaderRow(headerRowIndex?: number) {\n if (headerRowIndex !== undefined) this._headerRowIndex = headerRowIndex;\n const rows = await this.getCellsInRange(this._headerRange);\n this._processHeaderRow(rows);\n }\n\n private _processHeaderRow(rows: any[]) {\n if (!rows) {\n throw new Error('No values in the header row - fill the first row with header values before trying to interact with rows');\n }\n this._headerValues = _.map(rows[0], (header) => header?.trim());\n if (!_.compact(this.headerValues).length) {\n throw new Error('All your header cells are blank - fill the first row with header values before trying to interact with rows');\n }\n checkForDuplicateHeaders(this.headerValues);\n }\n\n async setHeaderRow(headerValues: string[], headerRowIndex?: number) {\n if (!headerValues) return;\n if (headerValues.length > this.columnCount) {\n throw new Error(`Sheet is not large enough to fit ${headerValues.length} columns. Resize the sheet first.`);\n }\n const trimmedHeaderValues = _.map(headerValues, (h) => h?.trim());\n checkForDuplicateHeaders(trimmedHeaderValues);\n\n if (!_.compact(trimmedHeaderValues).length) {\n throw new Error('All your header cells are blank -');\n }\n\n if (headerRowIndex) this._headerRowIndex = headerRowIndex;\n\n const response = await this._spreadsheet.sheetsApi.put(\n `values/${this.encodedA1SheetName}!${this._headerRowIndex}:${this._headerRowIndex}`,\n {\n searchParams: {\n valueInputOption: 'USER_ENTERED', // other option is RAW\n includeValuesInResponse: true,\n },\n json: {\n range: `${this.a1SheetName}!${this._headerRowIndex}:${this._headerRowIndex}`,\n majorDimension: 'ROWS',\n values: [[\n ...trimmedHeaderValues,\n // pad the rest of the row with empty values to clear them all out\n ..._.times(this.columnCount - trimmedHeaderValues.length, () => ''),\n ]],\n },\n }\n );\n const data = await response.json<any>();\n this._headerValues = data.updatedData.values[0];\n }\n\n // TODO: look at these types\n async addRows(\n rows: RawRowData[],\n options: AddRowOptions = {}\n ) {\n // adds multiple rows in one API interaction using the append endpoint\n\n // each row can be an array or object\n // an array is just cells\n // ex: ['column 1', 'column 2', 'column 3']\n // an object must use the header row values as keys\n // ex: { col1: 'column 1', col2: 'column 2', col3: 'column 3' }\n\n // google bug that does not handle colons in sheet names\n // see https://issuetracker.google.com/issues/150373119\n if (this.title.includes(':')) {\n throw new Error('Please remove the \":\" from your sheet title. There is a bug with the google API which breaks appending rows if any colons are in the sheet title.');\n }\n\n if (!_.isArray(rows)) throw new Error('You must pass in an array of row values to append');\n\n await this._ensureHeaderRowLoaded();\n\n // convert each row into an array of cell values rather than the key/value object\n const rowsAsArrays: RawRowData[] = [];\n _.each(rows, (row) => {\n let rowAsArray;\n if (_.isArray(row)) {\n rowAsArray = row;\n } else if (_.isObject(row)) {\n rowAsArray = [];\n for (let i = 0; i < this.headerValues.length; i++) {\n const propName = this.headerValues[i];\n rowAsArray[i] = row[propName];\n }\n } else {\n throw new Error('Each row must be an object or an array');\n }\n rowsAsArrays.push(rowAsArray);\n });\n\n const response = await this._spreadsheet.sheetsApi.post(\n `values/${this.encodedA1SheetName}!A${this._headerRowIndex}:append`,\n {\n searchParams: {\n valueInputOption: options.raw ? 'RAW' : 'USER_ENTERED',\n insertDataOption: options.insert ? 'INSERT_ROWS' : 'OVERWRITE',\n includeValuesInResponse: true,\n },\n json: {\n values: rowsAsArrays,\n },\n }\n );\n\n // extract the new row number from the A1-notation data range in the response\n // ex: in \"'Sheet8!A2:C2\" -- we want the `2`\n const data = await response.json<any>();\n const { updatedRange } = data.updates;\n let rowNumber = updatedRange.match(/![A-Z]+([0-9]+):?/)[1];\n rowNumber = parseInt(rowNumber);\n\n\n this._ensureInfoLoaded();\n // if new rows were added, we need update sheet.rowRount\n if (options.insert) {\n this._rawProperties!.gridProperties.rowCount += rows.length;\n } else if (rowNumber + rows.length > this.rowCount) {\n // have to subtract 1 since one row was inserted at rowNumber\n this._rawProperties!.gridProperties.rowCount = rowNumber + rows.length - 1;\n }\n\n return _.map(data.updates.updatedData.values, (rowValues) => {\n const row = new GoogleSpreadsheetRow(this, rowNumber++, rowValues);\n return row;\n });\n }\n\n /**\n * add a single row - see addRows for more info\n */\n async addRow(\n rowValues: RawRowData,\n options?: AddRowOptions\n ) {\n const rows = await this.addRows([rowValues], options);\n return rows[0];\n }\n\n\n private _rowCache: GoogleSpreadsheetRow[] = [];\n async getRows<T extends Record<string, any>>(\n options?: {\n /** skip first N rows */\n offset?: number,\n /** limit number of rows fetched */\n limit?: number,\n }\n ) {\n // https://developers.google.com/sheets/api/guides/migration\n // v4 API does not have equivalents for the row-order query parameters provided\n // Reverse-order is trivial; simply process the returned values array in reverse order.\n // Order by column is not supported for reads, but it is possible to sort the data then read\n\n // v4 API does not currently have a direct equivalent for the Sheets API v3 structured queries\n // However, you can retrieve the relevant data and sort through it as needed in your application\n const offset = options?.offset || 0;\n const limit = options?.limit || this.rowCount - 1;\n\n const firstRow = 1 + this._headerRowIndex + offset;\n const lastRow = firstRow + limit - 1; // inclusive so we subtract 1\n\n let rawRows;\n if (this._headerValues) {\n const lastColumn = columnToLetter(this.headerValues.length);\n rawRows = await this.getCellsInRange(\n `A${firstRow}:${lastColumn}${lastRow}`\n );\n } else {\n const result = await this.batchGetCellsInRange([this._headerRange,\n `A${firstRow}:${this.lastColumnLetter}${lastRow}`]);\n this._processHeaderRow(result[0]);\n rawRows = result[1];\n }\n\n if (!rawRows) return [];\n\n const rows = [];\n let rowNum = firstRow;\n for (let i = 0; i < rawRows.length; i++) {\n const row = new GoogleSpreadsheetRow<T>(this, rowNum++, rawRows[i]);\n this._rowCache[row.rowNumber] = row;\n rows.push(row);\n }\n return rows;\n }\n\n /**\n * @internal\n * Used internally to update row numbers after deleting rows.\n * Should not be called directly.\n * */\n _shiftRowCache(deletedRowNumber: number) {\n delete this._rowCache[deletedRowNumber];\n this._rowCache.forEach((row) => {\n if (row.rowNumber > deletedRowNumber) {\n row._updateRowNumber(row.rowNumber - 1);\n }\n });\n }\n\n /**\n * @internal\n * Used internally to update row numbers after deleting multiple rows.\n * Should not be called directly.\n * */\n _shiftRowCacheBulk(startIndex: number, endIndex: number) {\n const numDeleted = endIndex - startIndex;\n // Convert from 0-based indices to 1-based row numbers\n const startRow = startIndex + 1;\n const endRow = endIndex;\n\n // Mark rows in the deleted range as deleted, then remove from cache\n for (let rowNum = startRow; rowNum <= endRow; rowNum++) {\n const row = this._rowCache[rowNum];\n if (row) {\n row._markDeleted(); // Mark as deleted\n }\n delete this._rowCache[rowNum];\n }\n\n // Shift rows after the deleted range\n this._rowCache.forEach((row) => {\n if (row.rowNumber > endRow) {\n row._updateRowNumber(row.rowNumber - numDeleted);\n }\n });\n }\n\n /**\n * @internal\n * Used internally to shift cell cache after deleting rows.\n * Should not be called directly.\n * */\n _shiftCellCacheRows(startIndex: number, endIndex: number) {\n const numDeleted = endIndex - startIndex;\n\n // Mark cells in the deleted row range as deleted, then remove from cache\n for (let rowIndex = startIndex; rowIndex < endIndex; rowIndex++) {\n const row = this._cells[rowIndex];\n if (row) {\n row.forEach((cell) => {\n if (cell) cell._markDeleted();\n });\n }\n delete this._cells[rowIndex];\n }\n\n // Collect rows that need to be shifted\n const rowsToShift: Array<{ oldRowIndex: number, cells: any[] }> = [];\n for (let rowIndex = endIndex; rowIndex < this._cells.length; rowIndex++) {\n if (this._cells[rowIndex]) {\n rowsToShift.push({ oldRowIndex: rowIndex, cells: this._cells[rowIndex] });\n }\n }\n\n // Clear old positions and update to new positions\n rowsToShift.forEach(({ oldRowIndex, cells }) => {\n delete this._cells[oldRowIndex];\n const newRowIndex = oldRowIndex - numDeleted;\n this._cells[newRowIndex] = cells;\n // Update each cell's internal row index\n cells.forEach((cell, colIndex) => {\n if (cell) cell._updateIndices(newRowIndex, colIndex);\n });\n });\n }\n\n /**\n * @internal\n * Used internally to shift cell cache after deleting columns.\n * Should not be called directly.\n * */\n _shiftCellCacheColumns(startIndex: number, endIndex: number) {\n const numDeleted = endIndex - startIndex;\n\n // For each row, delete cells in the deleted column range and shift remaining\n this._cells.forEach((row, rowIndex) => {\n if (!row) return;\n\n // Mark cells in the deleted column range as deleted, then remove from cache\n for (let colIndex = startIndex; colIndex < endIndex; colIndex++) {\n const cell = row[colIndex];\n if (cell) cell._markDeleted();\n delete row[colIndex];\n }\n\n // Collect cells that need to be shifted\n const cellsToShift: Array<{ oldColIndex: number, cell: any }> = [];\n for (let colIndex = endIndex; colIndex < row.length; colIndex++) {\n if (row[colIndex]) {\n cellsToShift.push({ oldColIndex: colIndex, cell: row[colIndex] });\n }\n }\n\n // Clear old positions and update to new positions\n cellsToShift.forEach(({ oldColIndex, cell }) => {\n delete row[oldColIndex];\n const newColIndex = oldColIndex - numDeleted;\n row[newColIndex] = cell;\n // Update cell's internal column index\n cell._updateIndices(rowIndex, newColIndex);\n });\n });\n }\n\n async clearRows(\n options?: {\n start?: number,\n end?: number,\n }\n ) {\n // default to first row after header\n const startRowIndex = options?.start || this._headerRowIndex + 1;\n const endRowIndex = options?.end || this.rowCount;\n await this._spreadsheet.sheetsApi.post(`values/${this.encodedA1SheetName}!${startRowIndex}:${endRowIndex}:clear`);\n this._rowCache.forEach((row) => {\n if (row.rowNumber >= startRowIndex && row.rowNumber <= endRowIndex) row._clearRowData();\n });\n }\n\n // BASIC PROPS ///////////////////////////////////////////////////////////////////////////////////\n /** @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateSheetPropertiesRequest */\n async updateProperties(properties: Partial<Omit<WorksheetProperties, 'sheetId'>>) {\n // Request type = `updateSheetProperties`\n\n return this._makeSingleUpdateRequest('updateSheetProperties', {\n properties: {\n sheetId: this.sheetId,\n ...properties,\n },\n fields: getFieldMask(properties),\n });\n }\n\n /**\n * passes through the call to updateProperties to update only the gridProperties object\n */\n async updateGridProperties(\n gridProperties: Partial<WorksheetGridProperties>\n ) {\n return this.updateProperties({ gridProperties: gridProperties as WorksheetGridProperties });\n }\n\n /**\n * resize, internally just calls updateGridProperties\n */\n async resize(\n gridProperties: Pick<WorksheetGridProperties, 'rowCount' | 'columnCount'>\n ) {\n return this.updateGridProperties(gridProperties);\n }\n\n /**\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#updatedimensionpropertiesrequest\n */\n async updateDimensionProperties(\n columnsOrRows: WorksheetDimension,\n properties: Partial<WorksheetDimensionProperties>,\n bounds: Partial<DimensionRangeIndexes>\n ) {\n // Request type = `updateDimensionProperties`\n\n Object.keys(properties);\n\n return this._makeSingleUpdateRequest('updateDimensionProperties', {\n range: {\n sheetId: this.sheetId,\n dimension: columnsOrRows,\n ...bounds,\n },\n properties,\n fields: getFieldMask(properties as any),\n });\n }\n\n // OTHER /////////////////////////////////////////////////////////////////////////////////////////\n\n // this uses the \"values\" getter and does not give all the info about the cell contents\n // it is used internally when loading header cells\n async getCellsInRange(a1Range: A1Range, options?: GetValuesRequestOptions) {\n const response = await this._spreadsheet.sheetsApi.get(`values/${this.encodedA1SheetName}!${a1Range}`, {\n searchParams: options,\n });\n const data = await response.json<any>();\n return data.values;\n }\n\n async batchGetCellsInRange(a1Ranges: A1Range[], options?: GetValuesRequestOptions) {\n const ranges = a1Ranges.map((r) => `ranges=${this.encodedA1SheetName}!${r}`).join('&');\n const response = await this._spreadsheet.sheetsApi.get(`values:batchGet?${ranges}`, {\n searchParams: options,\n });\n const data = await response.json<any>();\n return data.valueRanges.map((r: any) => r.values);\n }\n\n /**\n * Updates an existing named range\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateNamedRangeRequest\n */\n async updateNamedRange(\n /** ID of the named range to update */\n namedRangeId: string,\n /** The named range properties to update */\n namedRange: Partial<{ name: string, range: GridRangeWithOptionalWorksheetId }>,\n /** Field mask specifying which properties to update */\n fields: string\n ) {\n return this._makeSingleUpdateRequest('updateNamedRange', {\n namedRange: {\n namedRangeId,\n ...namedRange.name && { name: namedRange.name },\n ...namedRange.range && { range: this._addSheetIdToRange(namedRange.range) },\n },\n fields,\n });\n }\n\n /**\n * Creates a new named range in this worksheet (convenience method that auto-fills sheetId)\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddNamedRangeRequest\n */\n async addNamedRange(\n /** Name of the new named range */\n name: string,\n /** GridRange describing the range (sheetId optional, will be auto-filled) */\n range: GridRangeWithOptionalWorksheetId,\n /** Optional ID for the named range */\n namedRangeId?: string\n ) {\n return this._spreadsheet.addNamedRange(\n name,\n this._addSheetIdToRange(range),\n namedRangeId\n );\n }\n\n /**\n * Deletes a named range (convenience wrapper)\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteNamedRangeRequest\n */\n async deleteNamedRange(\n /** ID of the named range to delete */\n namedRangeId: string\n ) {\n return this._spreadsheet.deleteNamedRange(namedRangeId);\n }\n\n /**\n * Updates all cells in a range with the same cell data\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#RepeatCellRequest\n */\n async repeatCell(\n /** The range to update (sheetId optional) */\n range: GridRangeWithOptionalWorksheetId,\n /** The cell data to repeat across the range */\n cell: any,\n /** Which fields to update (use \"*\" for all fields) */\n fields: string\n ) {\n await this._makeSingleUpdateRequest('repeatCell', {\n range: this._addSheetIdToRange(range),\n cell,\n fields,\n });\n }\n\n /**\n * Auto-fills cells with data following a pattern (like dragging the fill handle)\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AutoFillRequest\n */\n async autoFill(\n /** The range to autofill (detects source location automatically, sheetId optional) or explicit source and destination specification */\n rangeOrSource: GridRangeWithOptionalWorksheetId | SourceAndDestination,\n /** Whether to generate data with the alternate series */\n useAlternateSeries?: boolean\n ) {\n // Check if it's a SourceAndDestination by looking for the 'dimension' property\n const isSourceAndDestination = 'dimension' in rangeOrSource;\n\n await this._makeSingleUpdateRequest('autoFill', {\n ...isSourceAndDestination\n ? {\n sourceAndDestination: {\n ...rangeOrSource,\n source: this._addSheetIdToRange((rangeOrSource as SourceAndDestination).source),\n },\n }\n : { range: this._addSheetIdToRange(rangeOrSource as GridRangeWithOptionalWorksheetId) },\n ...useAlternateSeries !== undefined && { useAlternateSeries },\n });\n }\n\n /**\n * Cuts data from a source range and pastes it to a destination coordinate\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CutPasteRequest\n */\n async cutPaste(\n /** The source range to cut from (sheetId optional) */\n source: GridRangeWithOptionalWorksheetId,\n /** The top-left coordinate where data should be pasted (sheetId optional) */\n destination: GridCoordinateWithOptionalWorksheetId,\n /** What kind of data to paste (defaults to PASTE_NORMAL) */\n pasteType: PasteType = 'PASTE_NORMAL'\n ) {\n await this._makeSingleUpdateRequest('cutPaste', {\n source: this._addSheetIdToRange(source),\n destination: {\n sheetId: this.sheetId,\n rowIndex: destination.rowIndex,\n columnIndex: destination.columnIndex,\n },\n pasteType,\n });\n }\n\n /**\n * Copies data from a source range and pastes it to a destination range\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CopyPasteRequest\n */\n async copyPaste(\n /** The source range to copy from (sheetId optional) */\n source: GridRangeWithOptionalWorksheetId,\n /** The destination range to paste to (sheetId optional) */\n destination: GridRangeWithOptionalWorksheetId,\n /** What kind of data to paste (defaults to PASTE_NORMAL) */\n pasteType: PasteType = 'PASTE_NORMAL',\n /** How data should be oriented (defaults to NORMAL) */\n pasteOrientation: PasteOrientation = 'NORMAL'\n ) {\n await this._makeSingleUpdateRequest('copyPaste', {\n source: this._addSheetIdToRange(source),\n destination: this._addSheetIdToRange(destination),\n pasteType,\n pasteOrientation,\n });\n }\n\n // TODO: check types on these ranges\n\n /**\n * Merges all cells in the range\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#MergeCellsRequest\n */\n async mergeCells(\n range: GridRangeWithOptionalWorksheetId,\n mergeType = 'MERGE_ALL'\n ) {\n await this._makeSingleUpdateRequest('mergeCells', {\n mergeType,\n range: this._addSheetIdToRange(range),\n });\n }\n\n /**\n * Unmerges cells in the given range\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UnmergeCellsRequest\n */\n async unmergeCells(\n range: GridRangeWithOptionalWorksheetId\n ) {\n await this._makeSingleUpdateRequest('unmergeCells', {\n range: this._addSheetIdToRange(range),\n });\n }\n\n /**\n * Updates borders for a range\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateBordersRequest\n */\n async updateBorders(\n /** The range whose borders should be updated (sheetId optional) */\n range: GridRangeWithOptionalWorksheetId,\n /** Border styles for top, bottom, left, right, innerHorizontal, innerVertical */\n borders: {\n top?: any,\n bottom?: any,\n left?: any,\n right?: any,\n innerHorizontal?: any,\n innerVertical?: any\n }\n ) {\n await this._makeSingleUpdateRequest('updateBorders', {\n range: this._addSheetIdToRange(range),\n ...borders,\n });\n }\n\n /**\n * Adds a filter view to the sheet\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddFilterViewRequest\n */\n async addFilterView(\n /** The filter view to add (filterViewId is optional and will be auto-generated if not provided) */\n filter: FilterView\n ) {\n return this._makeSingleUpdateRequest('addFilterView', {\n filter,\n });\n }\n\n /**\n * Appends cells after the last row with data in a sheet\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AppendCellsRequest\n */\n async appendCells(\n /** The row data to append */\n rows: any[],\n /** Which fields to update (use \"*\" for all fields) */\n fields: string\n ) {\n await this._makeSingleUpdateRequest('appendCells', {\n sheetId: this.sheetId,\n rows,\n fields,\n });\n }\n\n /**\n * Clears the basic filter on this sheet\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#ClearBasicFilterRequest\n */\n async clearBasicFilter() {\n await this._makeSingleUpdateRequest('clearBasicFilter', {\n sheetId: this.sheetId,\n });\n }\n\n /**\n * Delete rows or columns in a given range\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDimensionRequest\n */\n async deleteDimension(\n columnsOrRows: WorksheetDimension,\n rangeIndexes: DimensionRangeIndexes\n ) {\n if (!columnsOrRows) throw new Error('You need to specify a dimension. i.e. COLUMNS|ROWS');\n if (!_.isObject(rangeIndexes)) throw new Error('`range` must be an object containing `startIndex` and `endIndex`');\n if (!_.isInteger(rangeIndexes.startIndex) || rangeIndexes.startIndex < 0) throw new Error('range.startIndex must be an integer >=0');\n if (!_.isInteger(rangeIndexes.endIndex) || rangeIndexes.endIndex < 0) throw new Error('range.endIndex must be an integer >=0');\n if (rangeIndexes.endIndex <= rangeIndexes.startIndex) throw new Error('range.endIndex must be greater than range.startIndex');\n\n const result = await this._makeSingleUpdateRequest('deleteDimension', {\n range: {\n sheetId: this.sheetId,\n dimension: columnsOrRows,\n startIndex: rangeIndexes.startIndex,\n endIndex: rangeIndexes.endIndex,\n },\n });\n\n // Update cached rows and cells\n if (columnsOrRows === 'ROWS') {\n this._shiftRowCacheBulk(rangeIndexes.startIndex, rangeIndexes.endIndex);\n this._shiftCellCacheRows(rangeIndexes.startIndex, rangeIndexes.endIndex);\n } else {\n this._shiftCellCacheColumns(rangeIndexes.startIndex, rangeIndexes.endIndex);\n }\n\n return result;\n }\n\n /**\n * Delete rows by index\n */\n async deleteRows(\n /** the start row index (inclusive, 0-based) */\n startIndex: number,\n /** the end row index (exclusive) */\n endIndex: number\n ) {\n return this.deleteDimension('ROWS', { startIndex, endIndex });\n }\n\n /**\n * Delete columns by index\n */\n async deleteColumns(\n /** the start column index (inclusive, 0-based) */\n startIndex: number,\n /** the end column index (exclusive) */\n endIndex: number\n ) {\n return this.deleteDimension('COLUMNS', { startIndex, endIndex });\n }\n\n async deleteEmbeddedObject() {\n // Request type = `deleteEmbeddedObject`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteEmbeddedObjectRequest\n throw new Error('Not implemented yet');\n }\n\n /**\n * Deletes a filter view from the sheet\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteFilterViewRequest\n */\n async deleteFilterView(\n /** The ID of the filter view to delete */\n filterId: Integer\n ) {\n await this._makeSingleUpdateRequest('deleteFilterView', {\n filterId,\n });\n }\n\n /**\n * Duplicates a filter view\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DuplicateFilterViewRequest\n */\n async duplicateFilterView(\n /** The ID of the filter view to duplicate */\n filterId: Integer\n ) {\n await this._makeSingleUpdateRequest('duplicateFilterView', {\n filterId,\n });\n }\n\n /**\n * Duplicate worksheet within the document\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DuplicateSheetRequest\n */\n async duplicate(\n options?: {\n id?: WorksheetId,\n title?: string,\n index?: number,\n }\n ) {\n const response = await this._makeSingleUpdateRequest('duplicateSheet', {\n sourceSheetId: this.sheetId,\n ...options?.index !== undefined && { insertSheetIndex: options.index },\n ...options?.id && { newSheetId: options.id },\n ...options?.title && { newSheetName: options.title },\n });\n const newSheetId = response.properties.sheetId;\n return this._spreadsheet.sheetsById[newSheetId];\n }\n\n /**\n * Finds and replaces text in cells\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#FindReplaceRequest\n */\n async findReplace(\n /** The value to search for */\n find: string,\n /** The value to use as replacement */\n replacement: string,\n /** Search options (matchCase, matchEntireCell, searchByRegex, includeFormulas) */\n options?: {\n matchCase?: boolean,\n matchEntireCell?: boolean,\n searchByRegex?: boolean,\n includeFormulas?: boolean\n },\n /** Optional range to search in (defaults to entire sheet, sheetId optional) */\n range?: GridRangeWithOptionalWorksheetId\n ) {\n await this._makeSingleUpdateRequest('findReplace', {\n find,\n replacement,\n ...options,\n ...range\n ? { range: this._addSheetIdToRange(range) }\n : { sheetId: this.sheetId },\n });\n }\n\n /**\n * Inserts rows or columns at a particular index\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#InsertDimensionRequest\n */\n async insertDimension(\n columnsOrRows: WorksheetDimension,\n rangeIndexes: DimensionRangeIndexes,\n inheritFromBefore?: boolean\n ) {\n if (!columnsOrRows) throw new Error('You need to specify a dimension. i.e. COLUMNS|ROWS');\n if (!_.isObject(rangeIndexes)) throw new Error('`range` must be an object containing `startIndex` and `endIndex`');\n if (!_.isInteger(rangeIndexes.startIndex) || rangeIndexes.startIndex < 0) throw new Error('range.startIndex must be an integer >=0');\n if (!_.isInteger(rangeIndexes.endIndex) || rangeIndexes.endIndex < 0) throw new Error('range.endIndex must be an integer >=0');\n if (rangeIndexes.endIndex <= rangeIndexes.startIndex) throw new Error('range.endIndex must be greater than range.startIndex');\n\n // default inheritFromBefore to true - unless inserting in the first row/column\n if (inheritFromBefore === undefined) {\n inheritFromBefore = rangeIndexes.startIndex > 0;\n }\n\n // do not allow inheritFromBefore if inserting at first row/column\n if (inheritFromBefore && rangeIndexes.startIndex === 0) {\n throw new Error('Cannot set inheritFromBefore to true if inserting in first row/column');\n }\n\n return this._makeSingleUpdateRequest('insertDimension', {\n range: {\n sheetId: this.sheetId,\n dimension: columnsOrRows,\n startIndex: rangeIndexes.startIndex,\n endIndex: rangeIndexes.endIndex,\n },\n inheritFromBefore,\n });\n }\n\n /**\n * insert empty cells in a range, shifting existing cells in the specified direction\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#InsertRangeRequest\n */\n async insertRange(\n /** the range to insert new cells into */\n range: GridRangeWithOptionalWorksheetId,\n /** which direction to shift existing cells - ROWS (shift down) or COLUMNS (shift right) */\n shiftDimension: WorksheetDimension\n ) {\n await this._makeSingleUpdateRequest('insertRange', {\n range: this._addSheetIdToRange(range),\n shiftDimension,\n });\n }\n\n /**\n * Moves rows or columns to a different position within the sheet\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#MoveDimensionRequest\n */\n async moveDimension(\n /** Whether to move rows or columns */\n dimension: WorksheetDimension,\n /** The indexes of rows/columns to move */\n source: DimensionRangeIndexes,\n /** Where to move them (calculated before removal) */\n destinationIndex: number\n ) {\n await this._makeSingleUpdateRequest('moveDimension', {\n source: {\n sheetId: this.sheetId,\n dimension,\n startIndex: source.startIndex,\n endIndex: source.endIndex,\n },\n destinationIndex,\n });\n }\n\n async updateEmbeddedObjectPosition() {\n // Request type = `updateEmbeddedObjectPosition`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateEmbeddedObjectPositionRequest\n throw new Error('Not implemented yet');\n }\n\n /**\n * Inserts data into the spreadsheet starting at the specified coordinate\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#PasteDataRequest\n */\n async pasteData(\n /** The coordinate at which the data should start being inserted (sheetId optional) */\n coordinate: GridCoordinateWithOptionalWorksheetId,\n /** The data to insert */\n data: string,\n /** The delimiter in the data */\n delimiter: string,\n /** How the data should be pasted (defaults to PASTE_NORMAL) */\n type: PasteType = 'PASTE_NORMAL'\n ) {\n await this._makeSingleUpdateRequest('pasteData', {\n coordinate: {\n sheetId: this.sheetId,\n rowIndex: coordinate.rowIndex,\n columnIndex: coordinate.columnIndex,\n },\n data,\n delimiter,\n type,\n });\n }\n\n /**\n * Splits a column of text into multiple columns based on a delimiter\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#TextToColumnsRequest\n */\n async textToColumns(\n /** The column to split (must span exactly one column) */\n source: GridRangeWithOptionalWorksheetId,\n /** Type of delimiter to use */\n delimiterType: DelimiterType,\n /** Custom delimiter character (only used when delimiterType is CUSTOM) */\n delimiter?: string\n ) {\n await this._makeSingleUpdateRequest('textToColumns', {\n source: this._addSheetIdToRange(source),\n delimiterType,\n ...delimiter && { delimiter },\n });\n }\n\n /**\n * Updates properties of a filter view\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateFilterViewRequest\n */\n async updateFilterView(\n /** The new properties of the filter view */\n filter: FilterView,\n /** The fields that should be updated (use \"*\" to update all fields) */\n fields: string\n ) {\n await this._makeSingleUpdateRequest('updateFilterView', {\n filter,\n fields,\n });\n }\n\n /**\n * Deletes a range of cells and shifts remaining cells\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteRangeRequest\n */\n async deleteRange(\n /** The range of cells to delete (sheetId optional) */\n range: GridRangeWithOptionalWorksheetId,\n /** How remaining cells should shift (ROWS = up, COLUMNS = left) */\n shiftDimension: WorksheetDimension\n ) {\n await this._makeSingleUpdateRequest('deleteRange', {\n range: this._addSheetIdToRange(range),\n shiftDimension,\n });\n }\n\n /**\n * Appends rows or columns to the end of a sheet\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AppendDimensionRequest\n */\n async appendDimension(\n /** Whether rows or columns should be appended */\n dimension: WorksheetDimension,\n /** The number of rows or columns to append */\n length: number\n ) {\n await this._makeSingleUpdateRequest('appendDimension', {\n sheetId: this.sheetId,\n dimension,\n length,\n });\n }\n\n /**\n * Adds a new conditional formatting rule at the given index\n * All subsequent rules' indexes are incremented\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddConditionalFormatRuleRequest\n */\n async addConditionalFormatRule(\n /** The rule to add */\n rule: ConditionalFormatRule,\n /** The zero-based index where the rule should be inserted */\n index: Integer\n ) {\n await this._makeSingleUpdateRequest('addConditionalFormatRule', {\n rule,\n index,\n });\n }\n\n /**\n * Updates a conditional format rule at the given index, or moves a conditional format rule to another index\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateConditionalFormatRuleRequest\n */\n async updateConditionalFormatRule(\n /** Either provide `rule` to replace the rule, or `newIndex` and `sheetId` to move it */\n options: {\n /** The zero-based index of the rule */\n index: Integer;\n /** The rule that should replace the rule at the given index (mutually exclusive with newIndex) */\n rule?: ConditionalFormatRule;\n /** The zero-based new index the rule should end up at (mutually exclusive with rule, requires sheetId) */\n newIndex?: Integer;\n /** The sheet of the rule to move (required if newIndex is set) */\n sheetId?: WorksheetId;\n }\n ) {\n await this._makeSingleUpdateRequest('updateConditionalFormatRule', options);\n }\n\n /**\n * Deletes a conditional format rule at the given index\n * All subsequent rules' indexes are decremented\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteConditionalFormatRuleRequest\n */\n async deleteConditionalFormatRule(\n /** The zero-based index of the rule to be deleted */\n index: Integer,\n /** The sheet the rule is being deleted from (defaults to this sheet) */\n sheetId?: WorksheetId\n ) {\n await this._makeSingleUpdateRequest('deleteConditionalFormatRule', {\n index,\n sheetId: sheetId ?? this.sheetId,\n });\n }\n\n /**\n * Sorts data in rows based on sort order per column\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SortRangeRequest\n */\n async sortRange(\n /** The range to sort (sheetId optional) */\n range: GridRangeWithOptionalWorksheetId,\n /** Array of sort specifications (later specs used when values are equal) */\n sortSpecs: SortSpec[]\n ) {\n await this._makeSingleUpdateRequest('sortRange', {\n range: this._addSheetIdToRange(range),\n sortSpecs,\n });\n }\n\n /**\n * Sets (or unsets) a data validation rule to every cell in the range\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SetDataValidationRequest\n */\n async setDataValidation(\n range: GridRangeWithOptionalWorksheetId,\n /** data validation rule object, or set to false to clear an existing rule */\n rule: DataValidationRule | false\n ) {\n return this._makeSingleUpdateRequest('setDataValidation', {\n range: {\n sheetId: this.sheetId,\n ...range,\n },\n ...rule && { rule },\n });\n }\n\n /**\n * Sets the basic filter on this sheet\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#SetBasicFilterRequest\n */\n async setBasicFilter(\n /** The basic filter configuration (range will auto-fill sheetId if not provided) */\n filter: {\n range?: GridRangeWithOptionalWorksheetId,\n sortSpecs?: SortSpec[],\n filterSpecs?: any[]\n }\n ) {\n await this._makeSingleUpdateRequest('setBasicFilter', {\n filter: {\n ...filter,\n ...filter.range && { range: this._addSheetIdToRange(filter.range) },\n },\n });\n }\n\n /**\n * add a new protected range to the sheet\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddProtectedRangeRequest\n */\n async addProtectedRange(\n protectedRange: ProtectedRange\n ) {\n if (!protectedRange.range && !protectedRange.namedRangeId) {\n throw new Error('No range specified: either range or namedRangeId is required');\n }\n return this._makeSingleUpdateRequest('addProtectedRange', {\n protectedRange,\n });\n }\n\n /**\n * update an existing protected range\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateProtectedRangeRequest\n */\n async updateProtectedRange(\n protectedRangeId: Integer,\n protectedRange: Partial<ProtectedRange>\n ) {\n return this._makeSingleUpdateRequest('updateProtectedRange', {\n protectedRange: { protectedRangeId, ...protectedRange },\n fields: getFieldMask(protectedRange as Record<string, unknown>),\n });\n }\n\n /**\n * delete a protected range by ID\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteProtectedRangeRequest\n */\n async deleteProtectedRange(\n protectedRangeId: Integer\n ) {\n return this._makeSingleUpdateRequest('deleteProtectedRange', {\n protectedRangeId,\n });\n }\n\n /**\n * auto-resize rows or columns to fit their contents\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AutoResizeDimensionsRequest\n */\n async autoResizeDimensions(\n /** which dimension to auto-resize */\n columnsOrRows: WorksheetDimension,\n /** start and end indexes (optional, defaults to all) */\n rangeIndexes?: DimensionRangeIndexes\n ) {\n return this._makeSingleUpdateRequest('autoResizeDimensions', {\n dimensions: {\n sheetId: this.sheetId,\n dimension: columnsOrRows,\n ...rangeIndexes,\n },\n });\n }\n\n async addChart() {\n // Request type = `addChart`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddChartRequest\n throw new Error('Not implemented yet');\n }\n\n async updateChartSpec() {\n // Request type = `updateChartSpec`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateChartSpecRequest\n throw new Error('Not implemented yet');\n }\n\n /**\n * Updates properties of a banded range\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateBandingRequest\n */\n async updateBanding(\n /** The banded range to update with the new properties */\n bandedRange: BandedRange,\n /** The fields that should be updated (use \"*\" to update all fields) */\n fields: string\n ) {\n await this._makeSingleUpdateRequest('updateBanding', {\n bandedRange,\n fields,\n });\n }\n\n /**\n * Adds a new banded range to the sheet\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddBandingRequest\n */\n async addBanding(\n /** The banded range to add (bandedRangeId is optional and will be auto-generated if not provided) */\n bandedRange: BandedRange\n ) {\n return this._makeSingleUpdateRequest('addBanding', {\n bandedRange,\n });\n }\n\n /**\n * Deletes a banded range from the sheet\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteBandingRequest\n */\n async deleteBanding(\n /** The ID of the banded range to delete */\n bandedRangeId: Integer\n ) {\n await this._makeSingleUpdateRequest('deleteBanding', {\n bandedRangeId,\n });\n }\n\n /**\n * Creates developer metadata\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#CreateDeveloperMetadataRequest\n */\n async createDeveloperMetadata(\n /** The developer metadata to create */\n developerMetadata: DeveloperMetadata\n ) {\n return this._makeSingleUpdateRequest('createDeveloperMetadata', {\n developerMetadata,\n });\n }\n\n /**\n * Updates developer metadata that matches the specified filters\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateDeveloperMetadataRequest\n */\n async updateDeveloperMetadata(\n /** The filters matching the developer metadata entries to update */\n dataFilters: DataFilterObject[],\n /** The value that all metadata matched by the filters will be updated to */\n developerMetadata: DeveloperMetadata,\n /** The fields that should be updated (use \"*\" to update all fields) */\n fields: string\n ) {\n await this._makeSingleUpdateRequest('updateDeveloperMetadata', {\n dataFilters,\n developerMetadata,\n fields,\n });\n }\n\n /**\n * Deletes developer metadata that matches the specified filter\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDeveloperMetadataRequest\n */\n async deleteDeveloperMetadata(\n /** The filter describing the criteria used to select which developer metadata to delete */\n dataFilter: DataFilterObject\n ) {\n await this._makeSingleUpdateRequest('deleteDeveloperMetadata', {\n dataFilter,\n });\n }\n\n /**\n * Randomizes the order of rows in a range\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#RandomizeRangeRequest\n */\n async randomizeRange(\n /** The range to randomize (sheetId optional) */\n range: GridRangeWithOptionalWorksheetId\n ) {\n await this._makeSingleUpdateRequest('randomizeRange', {\n range: this._addSheetIdToRange(range),\n });\n }\n\n async addDimensionGroup() {\n // Request type = `addDimensionGroup`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddDimensionGroupRequest\n throw new Error('Not implemented yet');\n }\n\n async deleteDimensionGroup() {\n // Request type = `deleteDimensionGroup`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDimensionGroupRequest\n throw new Error('Not implemented yet');\n }\n\n async updateDimensionGroup() {\n // Request type = `updateDimensionGroup`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateDimensionGroupRequest\n throw new Error('Not implemented yet');\n }\n\n /**\n * Trims whitespace from the start and end of each cell's text\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#TrimWhitespaceRequest\n */\n async trimWhitespace(\n /** The range whose cells to trim (sheetId optional) */\n range: GridRangeWithOptionalWorksheetId\n ) {\n await this._makeSingleUpdateRequest('trimWhitespace', {\n range: this._addSheetIdToRange(range),\n });\n }\n\n /**\n * Removes duplicate rows from a range based on specified columns\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteDuplicatesRequest\n */\n async deleteDuplicates(\n /** The range to remove duplicates from (sheetId optional) */\n range: GridRangeWithOptionalWorksheetId,\n /** Columns to check for duplicates (if empty, all columns are used) */\n comparisonColumns?: DimensionRange[]\n ) {\n await this._makeSingleUpdateRequest('deleteDuplicates', {\n range: this._addSheetIdToRange(range),\n ...comparisonColumns && { comparisonColumns },\n });\n }\n\n async addSlicer() {\n // Request type = `addSlicer`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddSlicerRequest\n throw new Error('Not implemented yet');\n }\n\n async updateSlicerSpec() {\n // Request type = `updateSlicerSpec`\n // https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#UpdateSlicerSpecRequest\n throw new Error('Not implemented yet');\n }\n\n /**\n * delete this worksheet\n */\n async delete() {\n return this._spreadsheet.deleteSheet(this.sheetId);\n }\n\n /**\n * copies this worksheet into another document/spreadsheet\n *\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.sheets/copyTo\n */\n async copyToSpreadsheet(\n destinationSpreadsheetId: SpreadsheetId\n ) {\n const req = this._spreadsheet.sheetsApi.post(`sheets/${this.sheetId}:copyTo`, {\n json: {\n destinationSpreadsheetId,\n },\n });\n const data = await req.json<any>();\n return data;\n }\n\n /**\n * clear data in the sheet - either the entire sheet or a specific range\n */\n async clear(\n /** optional A1 range to clear - defaults to entire sheet */\n a1Range?: A1Range\n ) {\n const range = a1Range ? `!${a1Range}` : '';\n // sheet name without ie 'sheet1' rather than 'sheet1'!A1:B5 is all cells\n await this._spreadsheet.sheetsApi.post(`values/${this.encodedA1SheetName}${range}:clear`);\n this.resetLocalCache(true);\n }\n\n /**\n * exports worksheet as CSV file (comma-separated values)\n */\n async downloadAsCSV(): Promise<ArrayBuffer>;\n async downloadAsCSV(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;\n async downloadAsCSV(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;\n async downloadAsCSV(returnStreamInsteadOfBuffer = false) {\n return this._spreadsheet._downloadAs('csv', this.sheetId, returnStreamInsteadOfBuffer);\n }\n /**\n * exports worksheet as TSC file (tab-separated values)\n */\n async downloadAsTSV(): Promise<ArrayBuffer>;\n async downloadAsTSV(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;\n async downloadAsTSV(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;\n async downloadAsTSV(returnStreamInsteadOfBuffer = false) {\n return this._spreadsheet._downloadAs('tsv', this.sheetId, returnStreamInsteadOfBuffer);\n }\n /**\n * exports worksheet as PDF\n */\n async downloadAsPDF(): Promise<ArrayBuffer>;\n async downloadAsPDF(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;\n async downloadAsPDF(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;\n async downloadAsPDF(returnStreamInsteadOfBuffer = false) {\n return this._spreadsheet._downloadAs('pdf', this.sheetId, returnStreamInsteadOfBuffer);\n }\n}\n","/** single type to handle all valid auth types */\nexport type GoogleApiAuth =\n // this simple interface should cover all google-auth-library auth methods\n | { getRequestHeaders: () => Promise<any> }\n // used to pass in an API key only\n | { apiKey: string }\n // used to pass in a raw token\n | { token: string };\n\nexport enum AUTH_MODES {\n GOOGLE_AUTH_CLIENT = 'google_auth',\n RAW_ACCESS_TOKEN = 'raw_access_token',\n API_KEY = 'api_key'\n}\n","import ky, { HTTPError, KyInstance, RetryOptions } from 'ky'; // eslint-disable-line import/no-extraneous-dependencies\nimport * as _ from './toolkit';\nimport { GoogleSpreadsheetWorksheet } from './GoogleSpreadsheetWorksheet';\nimport { getFieldMask } from './utils';\nimport {\n DataFilter,\n DataFilterObject,\n DeveloperMetadata,\n GridRange,\n NamedRangeId,\n ProtectedRange,\n SpreadsheetId,\n SpreadsheetProperties,\n WorksheetId,\n WorksheetProperties,\n} from './types/sheets-types';\nimport { PermissionRoles, PermissionsList, PublicPermissionRoles } from './types/drive-types';\nimport { RecursivePartial } from './types/util-types';\nimport { AUTH_MODES, GoogleApiAuth } from './types/auth-types';\n\n\nconst SHEETS_API_BASE_URL = 'https://sheets.googleapis.com/v4/spreadsheets';\nconst DRIVE_API_BASE_URL = 'https://www.googleapis.com/drive/v3/files';\n\nconst EXPORT_CONFIG: Record<string, { singleWorksheet?: boolean }> = {\n html: {},\n zip: {},\n xlsx: {},\n ods: {},\n csv: { singleWorksheet: true },\n tsv: { singleWorksheet: true },\n pdf: { singleWorksheet: true },\n};\ntype ExportFileTypes = keyof typeof EXPORT_CONFIG;\n\n\n\n\nfunction getAuthMode(auth: GoogleApiAuth) {\n if ('getRequestHeaders' in auth) return AUTH_MODES.GOOGLE_AUTH_CLIENT;\n if ('token' in auth && auth.token) return AUTH_MODES.RAW_ACCESS_TOKEN;\n // google-auth-library now has an empty `apiKey` property\n if ('apiKey' in auth && auth.apiKey) return AUTH_MODES.API_KEY;\n throw new Error('Invalid auth');\n}\n\nasync function getRequestAuthConfig(auth: GoogleApiAuth): Promise<{\n headers?: Record<string, string>;\n searchParams?: Record<string, string>\n}> {\n // google-auth-libary methods all can call this method to get the right headers\n // JWT | OAuth2Client | GoogleAuth | Impersonate | AuthClient\n if ('getRequestHeaders' in auth) {\n const headers = await auth.getRequestHeaders();\n\n // google-auth-library v10 uses a Headers object rather than a plain object\n if ('entries' in headers) {\n return { headers: Object.fromEntries(headers.entries()) };\n } if (_.isObject(headers)) {\n return { headers: headers as Record<string, string> };\n }\n throw new Error('unexpected headers returned from getRequestHeaders');\n }\n\n // API key only access passes through the api key as a query param\n // (note this can only provide read-only access)\n if ('apiKey' in auth && auth.apiKey) {\n return { searchParams: { key: auth.apiKey } };\n }\n\n // RAW ACCESS TOKEN\n if ('token' in auth && auth.token) {\n return { headers: { Authorization: `Bearer ${auth.token}` } };\n }\n\n throw new Error('Invalid auth');\n}\n\n/**\n * Google Sheets document\n *\n * @description\n * **This class represents an entire google spreadsheet document**\n * Provides methods to interact with document metadata/settings, formatting, manage sheets, and acts as the main gateway to interacting with sheets and data that the document contains.q\n *\n */\nexport class GoogleSpreadsheet {\n readonly spreadsheetId: string;\n\n public auth: GoogleApiAuth;\n get authMode() {\n return getAuthMode(this.auth);\n }\n\n private _rawSheets: any;\n private _rawProperties = null as SpreadsheetProperties | null;\n private _spreadsheetUrl = null as string | null;\n private _deleted = false;\n\n /**\n * Sheets API [ky](https://github.com/sindresorhus/ky?tab=readme-ov-file#kycreatedefaultoptions) instance\n * authentication is automatically attached\n * can be used if unsupported sheets calls need to be made\n * @see https://developers.google.com/sheets/api/reference/rest\n * */\n readonly sheetsApi: KyInstance;\n\n /**\n * Drive API [ky](https://github.com/sindresorhus/ky?tab=readme-ov-file#kycreatedefaultoptions) instance\n * authentication automatically attached\n * can be used if unsupported drive calls need to be made\n * @topic permissions\n * @see https://developers.google.com/drive/api/v3/reference\n * */\n readonly driveApi: KyInstance;\n\n\n /**\n * initialize new GoogleSpreadsheet\n * @category Initialization\n * */\n constructor(\n /** id of Google spreadsheet doc */\n spreadsheetId: SpreadsheetId,\n /** authentication to use with Google Sheets API */\n auth: GoogleApiAuth,\n /** Additional options */\n options?: {\n /**\n * customize retry behavior --\n * see the [ky documentation](https://github.com/sindresorhus/ky#retry) for details of the available options and defaults.\n * */\n retryConfig?: RetryOptions | number\n }\n ) {\n const { retryConfig } = options || {};\n this.spreadsheetId = spreadsheetId;\n this.auth = auth;\n\n this._rawSheets = {};\n this._spreadsheetUrl = null;\n\n // create a ky instance with sheet root URL and hooks to handle auth\n this.sheetsApi = ky.create({\n prefixUrl: `${SHEETS_API_BASE_URL}/${spreadsheetId}`,\n timeout: 180_000,\n hooks: {\n beforeRequest: [(r) => this._setAuthRequestHook(r)],\n beforeError: [(e) => this._errorHook(e)],\n },\n retry: retryConfig,\n });\n this.driveApi = ky.create({\n prefixUrl: `${DRIVE_API_BASE_URL}/${spreadsheetId}`,\n hooks: {\n beforeRequest: [(r) => this._setAuthRequestHook(r)],\n beforeError: [(e) => this._errorHook(e)],\n },\n retry: retryConfig,\n });\n }\n\n\n // INTERNAL UTILITY FUNCTIONS ////////////////////////////////////////////////////////////////////\n\n /** @internal */\n async _setAuthRequestHook(req: Request): Promise<Request> {\n const authConfig = await getRequestAuthConfig(this.auth);\n if (authConfig.headers) {\n Object.entries(authConfig.headers).forEach(([key, val]) => {\n req.headers.set(key, String(val));\n });\n }\n\n if (authConfig.searchParams) {\n const url = new URL(req.url);\n Object.entries(authConfig.searchParams).forEach(([key, val]) => {\n url.searchParams.set(key, String(val));\n });\n // cannot change the URL with ky, so have to return a new request\n return new Request(url, req);\n }\n\n return req;\n }\n\n /** @internal */\n async _errorHook(error: HTTPError) {\n const { response } = error;\n const errorDataText = await response?.text();\n let errorData;\n try {\n errorData = JSON.parse(errorDataText);\n } catch (e) {\n // console.log('parsing json failed', errorDataText);\n }\n\n if (errorData) {\n // usually the error has a code and message, but occasionally not\n if (!errorData.error) return error;\n\n const { code, message } = errorData.error;\n error.message = `Google API error - [${code}] ${message}`;\n return error;\n }\n\n if (_.get(error, 'response.status') === 403) {\n if ('apiKey' in this.auth) {\n throw new Error('Sheet is private. Use authentication or make public. (see https://github.com/theoephraim/node-google-spreadsheet#a-note-on-authentication for details)');\n }\n }\n return error;\n }\n\n /** @internal */\n async _makeSingleUpdateRequest(requestType: string, requestParams: any) {\n const response = await this.sheetsApi.post(':batchUpdate', {\n json: {\n requests: [{ [requestType]: requestParams }],\n includeSpreadsheetInResponse: true,\n // responseRanges: [string]\n // responseIncludeGridData: true\n },\n });\n const data = await response.json<any>();\n\n this._updateRawProperties(data.updatedSpreadsheet.properties);\n _.each(data.updatedSpreadsheet.sheets, (s: any) => this._updateOrCreateSheet(s));\n // console.log('API RESPONSE', response.data.replies[0][requestType]);\n return data.replies[0][requestType];\n }\n\n // TODO: review these types\n // currently only used in batching cell updates\n /** @internal */\n async _makeBatchUpdateRequest(requests: any[], responseRanges?: string | string[]) {\n // this is used for updating batches of cells\n const response = await this.sheetsApi.post(':batchUpdate', {\n json: {\n requests,\n includeSpreadsheetInResponse: true,\n ...responseRanges && {\n responseIncludeGridData: true,\n ...responseRanges !== '*' && { responseRanges },\n },\n },\n });\n\n const data = await response.json<any>();\n this._updateRawProperties(data.updatedSpreadsheet.properties);\n _.each(data.updatedSpreadsheet.sheets, (s: any) => this._updateOrCreateSheet(s));\n }\n\n /** @internal */\n _ensureInfoLoaded() {\n if (!this._rawProperties) throw new Error('You must call `doc.loadInfo()` before accessing this property');\n }\n\n /** @internal */\n _updateRawProperties(newProperties: SpreadsheetProperties) { this._rawProperties = newProperties; }\n\n /** @internal */\n _updateOrCreateSheet(sheetInfo: { properties: WorksheetProperties, data: any, protectedRanges?: ProtectedRange[] }) {\n const { properties, data, protectedRanges } = sheetInfo;\n const { sheetId } = properties;\n if (!this._rawSheets[sheetId]) {\n this._rawSheets[sheetId] = new GoogleSpreadsheetWorksheet(this, properties, data, protectedRanges);\n } else {\n this._rawSheets[sheetId].updateRawData(properties, data, protectedRanges);\n }\n }\n\n // BASIC PROPS //////////////////////////////////////////////////////////////////////////////\n _getProp(param: keyof SpreadsheetProperties) {\n this._ensureInfoLoaded();\n // ideally ensureInfoLoaded would assert that _rawProperties is in fact loaded\n // but this is not currently possible in TS - see https://github.com/microsoft/TypeScript/issues/49709\n return this._rawProperties![param];\n }\n\n get title(): SpreadsheetProperties['title'] { return this._getProp('title'); }\n get locale(): SpreadsheetProperties['locale'] { return this._getProp('locale'); }\n get timeZone(): SpreadsheetProperties['timeZone'] { return this._getProp('timeZone'); }\n get autoRecalc(): SpreadsheetProperties['autoRecalc'] { return this._getProp('autoRecalc'); }\n get defaultFormat(): SpreadsheetProperties['defaultFormat'] { return this._getProp('defaultFormat'); }\n get spreadsheetTheme(): SpreadsheetProperties['spreadsheetTheme'] { return this._getProp('spreadsheetTheme'); }\n get iterativeCalculationSettings(): SpreadsheetProperties['iterativeCalculationSettings'] { return this._getProp('iterativeCalculationSettings'); }\n\n /**\n * update spreadsheet properties\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets#SpreadsheetProperties\n * */\n async updateProperties(properties: Partial<SpreadsheetProperties>) {\n await this._makeSingleUpdateRequest('updateSpreadsheetProperties', {\n properties,\n fields: getFieldMask(properties),\n });\n }\n\n // BASIC INFO ////////////////////////////////////////////////////////////////////////////////////\n async loadInfo(includeCells = false) {\n const response = await this.sheetsApi.get('', {\n searchParams: {\n ...includeCells && { includeGridData: true },\n },\n });\n const data = await response.json<any>();\n this._spreadsheetUrl = data.spreadsheetUrl;\n this._rawProperties = data.properties;\n data.sheets?.forEach((s: any) => this._updateOrCreateSheet(s));\n }\n\n resetLocalCache() {\n this._rawProperties = null;\n this._rawSheets = {};\n }\n\n // WORKSHEETS ////////////////////////////////////////////////////////////////////////////////////\n get sheetCount() {\n this._ensureInfoLoaded();\n return _.values(this._rawSheets).length;\n }\n\n get sheetsById(): Record<WorksheetId, GoogleSpreadsheetWorksheet> {\n this._ensureInfoLoaded();\n return this._rawSheets;\n }\n\n get sheetsByIndex(): GoogleSpreadsheetWorksheet[] {\n this._ensureInfoLoaded();\n return _.sortBy(this._rawSheets, 'index');\n }\n\n get sheetsByTitle(): Record<string, GoogleSpreadsheetWorksheet> {\n this._ensureInfoLoaded();\n return _.keyBy(this._rawSheets, 'title');\n }\n\n /**\n * Add new worksheet to document\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddSheetRequest\n * */\n async addSheet(\n properties: Partial<\n RecursivePartial<WorksheetProperties>\n & {\n headerValues: string[],\n headerRowIndex: number\n }\n > = {}\n ) {\n const response = await this._makeSingleUpdateRequest('addSheet', {\n properties: _.omit(properties, 'headerValues', 'headerRowIndex'),\n });\n // _makeSingleUpdateRequest already adds the sheet\n const newSheetId = response.properties.sheetId;\n const newSheet = this.sheetsById[newSheetId];\n\n if (properties.headerValues) {\n await newSheet.setHeaderRow(properties.headerValues, properties.headerRowIndex);\n }\n\n return newSheet;\n }\n\n /**\n * delete a worksheet\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteSheetRequest\n * */\n async deleteSheet(sheetId: WorksheetId) {\n await this._makeSingleUpdateRequest('deleteSheet', { sheetId });\n delete this._rawSheets[sheetId];\n }\n\n // NAMED RANGES //////////////////////////////////////////////////////////////////////////////////\n\n /**\n * create a new named range\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#AddNamedRangeRequest\n */\n async addNamedRange(\n /** name of new named range */\n name: string,\n /** GridRange object describing range */\n range: GridRange,\n /** id for named range (optional) */\n namedRangeId?: string\n ) {\n // TODO: add named range to local cache\n return this._makeSingleUpdateRequest('addNamedRange', {\n namedRange: {\n name,\n namedRangeId,\n range,\n },\n });\n }\n\n /**\n * delete a named range\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#DeleteNamedRangeRequest\n * */\n async deleteNamedRange(\n /** id of named range to delete */\n namedRangeId: NamedRangeId\n ) {\n // TODO: remove named range from local cache\n return this._makeSingleUpdateRequest('deleteNamedRange', { namedRangeId });\n }\n\n // LOADING CELLS /////////////////////////////////////////////////////////////////////////////////\n\n /** fetch cell data into local cache */\n async loadCells(\n /**\n * single filter or array of filters\n * strings are treated as A1 ranges, objects are treated as GridRange objects,\n * objects with a `developerMetadataLookup` key are treated as DeveloperMetadataLookup filters\n * pass nothing to fetch all cells\n * */\n filters?: DataFilter | DataFilter[]\n ) {\n // TODO: switch to this mode if using a read-only auth token?\n const readOnlyMode = this.authMode === AUTH_MODES.API_KEY;\n\n const filtersArray = _.isArray(filters) ? filters : [filters];\n const dataFilters = _.map(filtersArray, (filter) => {\n if (_.isString(filter)) {\n return readOnlyMode ? filter : { a1Range: filter };\n }\n if (_.isObject(filter)) {\n if (readOnlyMode) {\n throw new Error('Only A1 ranges are supported when fetching cells with read-only access (using only an API key)');\n }\n if ('developerMetadataLookup' in filter) {\n return { developerMetadataLookup: filter.developerMetadataLookup };\n }\n return { gridRange: filter };\n }\n throw new Error('Each filter must be an A1 range string or a gridrange object');\n });\n\n let result;\n // when using an API key only, we must use the regular get endpoint\n // because :getByDataFilter requires higher access\n if (this.authMode === AUTH_MODES.API_KEY) {\n const params = new URLSearchParams();\n params.append('includeGridData', 'true');\n dataFilters.forEach((singleFilter) => {\n if (!_.isString(singleFilter)) {\n throw new Error('Only A1 ranges are supported when fetching cells with read-only access (using only an API key)');\n }\n params.append('ranges', singleFilter);\n });\n result = await this.sheetsApi.get('', {\n searchParams: params,\n });\n // otherwise we use the getByDataFilter endpoint because it is more flexible\n } else {\n result = await this.sheetsApi.post(':getByDataFilter', {\n json: {\n includeGridData: true,\n dataFilters,\n },\n });\n }\n\n const data = await result?.json<any>();\n _.each(data.sheets, (sheet: any) => { this._updateOrCreateSheet(sheet); });\n }\n\n // EXPORTING /////////////////////////////////////////////////////////////\n\n /**\n * export/download helper, not meant to be called directly (use downloadAsX methods on spreadsheet and worksheet instead)\n * @internal\n */\n async _downloadAs(\n fileType: ExportFileTypes,\n worksheetId: WorksheetId | undefined,\n returnStreamInsteadOfBuffer?: boolean\n ) {\n // see https://stackoverflow.com/questions/11619805/using-the-google-drive-api-to-download-a-spreadsheet-in-csv-format/51235960#51235960\n\n if (!EXPORT_CONFIG[fileType]) throw new Error(`unsupported export fileType - ${fileType}`);\n if (EXPORT_CONFIG[fileType].singleWorksheet) {\n if (worksheetId === undefined) throw new Error(`Must specify worksheetId when exporting as ${fileType}`);\n } else if (worksheetId) throw new Error(`Cannot specify worksheetId when exporting as ${fileType}`);\n\n // google UI shows \"html\" but passes through \"zip\"\n if (fileType === 'html') fileType = 'zip';\n\n if (!this._spreadsheetUrl) throw new Error('Cannot export sheet that is not fully loaded');\n\n const exportUrl = this._spreadsheetUrl.replace('edit', 'export');\n const response = await this.sheetsApi.get(exportUrl, {\n prefixUrl: '', // unset baseUrl since we're not hitting the normal sheets API\n searchParams: {\n id: this.spreadsheetId,\n format: fileType,\n // worksheetId can be 0\n ...worksheetId !== undefined && { gid: worksheetId },\n },\n });\n if (returnStreamInsteadOfBuffer) {\n return response.body;\n }\n return response.arrayBuffer();\n }\n\n /**\n * exports entire document as html file (zipped)\n * @topic export\n * */\n async downloadAsZippedHTML(): Promise<ArrayBuffer>;\n async downloadAsZippedHTML(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;\n async downloadAsZippedHTML(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;\n async downloadAsZippedHTML(returnStreamInsteadOfBuffer?: boolean) {\n return this._downloadAs('html', undefined, returnStreamInsteadOfBuffer);\n }\n\n /**\n * @deprecated\n * use `doc.downloadAsZippedHTML()` instead\n * */\n async downloadAsHTML(returnStreamInsteadOfBuffer?: boolean) {\n return this._downloadAs('html', undefined, returnStreamInsteadOfBuffer);\n }\n\n /**\n * exports entire document as xlsx spreadsheet (Microsoft Office Excel)\n * @topic export\n * */\n async downloadAsXLSX(): Promise<ArrayBuffer>;\n async downloadAsXLSX(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;\n async downloadAsXLSX(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;\n async downloadAsXLSX(returnStreamInsteadOfBuffer = false) {\n return this._downloadAs('xlsx', undefined, returnStreamInsteadOfBuffer);\n }\n /**\n * exports entire document as ods spreadsheet (Open Office)\n * @topic export\n */\n async downloadAsODS(): Promise<ArrayBuffer>;\n async downloadAsODS(returnStreamInsteadOfBuffer: false): Promise<ArrayBuffer>;\n async downloadAsODS(returnStreamInsteadOfBuffer: true): Promise<ReadableStream>;\n async downloadAsODS(returnStreamInsteadOfBuffer = false) {\n return this._downloadAs('ods', undefined, returnStreamInsteadOfBuffer);\n }\n\n\n async delete() {\n await this.driveApi.delete('');\n this._deleted = true;\n // endpoint returns nothing when successful\n }\n\n // PERMISSIONS ///////////////////////////////////////////////////////////////////////////////////\n\n /**\n * list all permissions entries for doc\n */\n async listPermissions(): Promise<PermissionsList> {\n const listReq = await this.driveApi.get('permissions', {\n searchParams: {\n fields: 'permissions(id,type,emailAddress,domain,role,displayName,photoLink,deleted)',\n },\n });\n const data = await listReq.json<{ permissions: PermissionsList }>();\n return data.permissions;\n }\n\n async setPublicAccessLevel(role: PublicPermissionRoles | false) {\n const permissions = await this.listPermissions();\n const existingPublicPermission = _.find(permissions, (p) => p.type === 'anyone');\n\n if (role === false) {\n if (!existingPublicPermission) {\n // doc is already not public... could throw an error or just do nothing\n return;\n }\n await this.driveApi.delete(`permissions/${existingPublicPermission.id}`);\n } else {\n const _shareReq = await this.driveApi.post('permissions', {\n json: {\n role: role || 'viewer',\n type: 'anyone',\n },\n });\n }\n }\n\n /** share document to email or domain */\n async share(emailAddressOrDomain: string, opts?: {\n /** set role level, defaults to owner */\n role?: PermissionRoles,\n\n /** set to true if email is for a group */\n isGroup?: boolean,\n\n /** set to string to include a custom message, set to false to skip sending a notification altogether */\n emailMessage?: string | false,\n\n // moveToNewOwnersRoot?: string,\n // /** send a notification email (default = true) */\n // sendNotificationEmail?: boolean,\n // /** support My Drives and shared drives (default = false) */\n // supportsAllDrives?: boolean,\n\n // /** Issue the request as a domain administrator */\n // useDomainAdminAccess?: boolean,\n }) {\n let emailAddress: string | undefined;\n let domain: string | undefined;\n if (emailAddressOrDomain.includes('@')) {\n emailAddress = emailAddressOrDomain;\n } else {\n domain = emailAddressOrDomain;\n }\n\n\n const shareReq = await this.driveApi.post('permissions', {\n searchParams: {\n ...opts?.emailMessage === false && { sendNotificationEmail: false },\n ..._.isString(opts?.emailMessage) && { emailMessage: opts?.emailMessage },\n ...opts?.role === 'owner' && { transferOwnership: true },\n },\n json: {\n role: opts?.role || 'writer',\n ...emailAddress && {\n type: opts?.isGroup ? 'group' : 'user',\n emailAddress,\n },\n ...domain && {\n type: 'domain',\n domain,\n },\n },\n });\n\n return shareReq.json();\n }\n\n /**\n * delete a permission by its ID\n * @see https://developers.google.com/drive/api/v3/reference/permissions/delete\n */\n async deletePermission(permissionId: string) {\n await this.driveApi.delete(`permissions/${permissionId}`);\n }\n\n // DEVELOPER METADATA ///////////////////////////////////////////////////////////////////////////\n\n /**\n * search for developer metadata entries matching the given filters\n * @see https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.developerMetadata/search\n */\n async searchDeveloperMetadata(\n /** array of DataFilter objects to match against */\n filters: DataFilterObject[]\n ): Promise<DeveloperMetadata[]> {\n const response = await this.sheetsApi.post('developerMetadata:search', {\n json: { dataFilters: filters },\n });\n const data = await response.json<any>();\n if (!data.matchedDeveloperMetadata) return [];\n return data.matchedDeveloperMetadata.map((m: any) => m.developerMetadata);\n }\n\n //\n // CREATE NEW DOC ////////////////////////////////////////////////////////////////////////////////\n static async createNewSpreadsheetDocument(auth: GoogleApiAuth, properties?: Partial<SpreadsheetProperties>) {\n // see updateProperties for more info about available properties\n\n if (getAuthMode(auth) === AUTH_MODES.API_KEY) {\n throw new Error('Cannot use api key only to create a new spreadsheet - it is only usable for read-only access of public docs');\n }\n\n // TODO: handle injecting default credentials if running on google infra\n\n const authConfig = await getRequestAuthConfig(auth);\n\n const response = await ky.post(SHEETS_API_BASE_URL, {\n ...authConfig, // has the auth header\n json: {\n properties,\n },\n });\n\n const data = await response.json<any>();\n const newSpreadsheet = new GoogleSpreadsheet(data.spreadsheetId, auth);\n\n // TODO ideally these things aren't public, might want to refactor anyway\n newSpreadsheet._spreadsheetUrl = data.spreadsheetUrl;\n newSpreadsheet._rawProperties = data.properties;\n _.each(data.sheets, (s: any) => newSpreadsheet._updateOrCreateSheet(s));\n\n return newSpreadsheet;\n }\n}\n"],"mappings":"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"}
|