@@ -9,11 +9,17 @@ import { Sheets } from './sheets/sheets.js';
99// Google Sheets epoch (December 30, 1899)
1010const SHEETS_EPOCH = new Date ( 1899 , 11 , 30 ) . getTime ( ) ;
1111
12+ /**
13+ * Configuration for a single header column in a sheet table.
14+ */
1215export type HeaderCell = {
1316 readonly label : string ;
1417 readonly conditionalFormatRules ?: sheets_v4 . Schema$ConditionalFormatRule [ ] ;
1518} ;
1619
20+ /**
21+ * Options for creating a {@link SheetTable}.
22+ */
1723export type SheetTableOptions = {
1824 readonly bodyStartRow ?: number ;
1925 readonly frozen ?: {
@@ -22,16 +28,30 @@ export type SheetTableOptions = {
2228 } ;
2329} ;
2430
31+ /**
32+ * Header configuration that searches for existing header labels in the sheet.
33+ * @template T - Record type whose keys correspond to header labels in the sheet
34+ */
2535export type SearchTableHeaders < T > = {
2636 readonly headerRowNumber ?: number ;
2737 readonly search : readonly ( keyof T ) [ ] ;
2838} ;
2939
40+ /**
41+ * Header configuration that explicitly defines column headers and their labels.
42+ * @template T - Record type whose keys are used as header identifiers
43+ */
3044export type DefineHeader < T > = {
3145 readonly headerRowNumber ?: number ;
3246 readonly define : Record < keyof T , string | HeaderCell > ;
3347} ;
3448
49+ /**
50+ * Typed table interface for reading from and writing to a Google Sheets worksheet.
51+ *
52+ * Use the static {@link SheetTable.create} factory method to instantiate.
53+ * @template T - Record type representing a single row of data
54+ */
3555export class SheetTable < T > {
3656 readonly #auth: OAuth2Client ;
3757 readonly #bodyStartRow: number ;
@@ -67,6 +87,10 @@ export class SheetTable<T> {
6787 this . #bodyStartRow = options ?. bodyStartRow ?? 2 ;
6888 }
6989
90+ /**
91+ * Appends rows to the sheet.
92+ * @param records - Array of row data keyed by header identifiers
93+ */
7094 async addRecords ( records : ReadonlyArray < Record < keyof T , string | CellData > > ) {
7195 if ( ! this . #sheet) {
7296 throw new Error ( 'Sheet is not created' ) ;
@@ -84,6 +108,14 @@ export class SheetTable<T> {
84108 ) ;
85109 }
86110
111+ /**
112+ * Retrieves all data rows with header-mapped values and row visibility state.
113+ *
114+ * Each returned record includes:
115+ * - `hiddenByUser` (`boolean`): `true` if the row is manually hidden by a user
116+ * - `hiddenByFilter` (`boolean`): `true` if the row is hidden by a filter view
117+ * @returns Array of records typed as `T & { hiddenByUser: boolean; hiddenByFilter: boolean }`
118+ */
87119 async getData ( ) {
88120 if ( ! this . #sheet) {
89121 throw new Error ( 'Sheet is not created' ) ;
@@ -112,17 +144,21 @@ export class SheetTable<T> {
112144 typeMap . set ( firstColIndex + cellType . index , cellType . type ) ;
113145 }
114146
115- // Get all data
116- const data = await this . #sheet. getValues (
117- `${ headers . at ( 0 ) ?. row ?? 'A' } ${ this . #bodyStartRow} ` ,
118- headers . at ( - 1 ) ?. row ?? 'A' ,
119- ) ;
147+ // Get all data and row metadata in parallel
148+ const [ data , rowMetadata ] = await Promise . all ( [
149+ this . #sheet. getValues (
150+ `${ headers . at ( 0 ) ?. row ?? 'A' } ${ this . #bodyStartRow} ` ,
151+ headers . at ( - 1 ) ?. row ?? 'A' ,
152+ ) ,
153+ this . #sheet. getRowMetadata ( this . #bodyStartRow) ,
154+ ] ) ;
120155
121156 if ( data == null ) {
122157 return [ ] ;
123158 }
124159
125- const list = data . map ( ( _d ) => {
160+ const list = data . map ( ( _d , rowIndex ) => {
161+ const meta = rowMetadata [ rowIndex ] ;
126162 const _data : Partial < T > = { } ;
127163
128164 for ( const header of headers ) {
@@ -133,7 +169,11 @@ export class SheetTable<T> {
133169 _data [ header . key ] = convertValue ( rawValue , cellType ) as T [ keyof T ] ;
134170 }
135171
136- return _data as T ;
172+ return {
173+ ..._data ,
174+ hiddenByUser : meta ?. hiddenByUser ?? false ,
175+ hiddenByFilter : meta ?. hiddenByFilter ?? false ,
176+ } as T & { hiddenByUser : boolean ; hiddenByFilter : boolean } ;
137177 } ) ;
138178
139179 return list ;
@@ -177,6 +217,16 @@ export class SheetTable<T> {
177217 }
178218 }
179219
220+ /**
221+ * Creates and initializes a new {@link SheetTable} instance.
222+ * @template T - Record type representing a single row of data
223+ * @param sheetUrl - Full URL of the Google Spreadsheet
224+ * @param sheetName - Name of the worksheet tab to operate on
225+ * @param auth - Authenticated OAuth2 client for Google Sheets API access
226+ * @param header - Header configuration (define columns explicitly or search existing ones)
227+ * @param options - Additional table options such as frozen panes and body start row
228+ * @returns Initialized SheetTable instance ready for read/write operations
229+ */
180230 static async create < T > (
181231 sheetUrl : string ,
182232 sheetName : string ,
@@ -197,10 +247,11 @@ interface Header<T> {
197247}
198248
199249/**
200- *
201- * @param sheet
202- * @param headerRowNumber
203- * @param keys
250+ * Resolves header keys to their column positions by reading the header row from the sheet.
251+ * @param sheet - Sheet instance to read headers from
252+ * @param headerRowNumber - 1-based row number where headers are located
253+ * @param keys - Header keys to search for in the header row
254+ * @returns Resolved headers sorted by column index, excluding keys not found
204255 */
205256async function getHeaders < T > (
206257 sheet : Sheet ,
@@ -225,9 +276,9 @@ async function getHeaders<T>(
225276}
226277
227278/**
228- * Convert column number to alphabet column name.
229- * Example: 5 => "E", 100 => "CV"
230- * @param col
279+ * Converts a 1-based column number to an alphabetic column name (e.g. 5 → "E", 100 → "CV") .
280+ * @param col - 1-based column number
281+ * @returns Alphabetic column name
231282 */
232283function getClmName ( col : number ) : string {
233284 const COUNT_OF_ALPHABET = 26 ;
0 commit comments