Skip to main content
Glama
sheets-utils.ts4.98 kB
import { sheets_v4 } from 'googleapis'; /** * Utility functions for Google Sheets operations */ export class SheetsUtils { /** * Extract spreadsheet ID from URL or return as-is if already an ID */ static extractSpreadsheetId(input: string): string { // If it's already a valid ID format (alphanumeric string) if (/^[a-zA-Z0-9-_]+$/.test(input)) { return input; } // Extract from Google Sheets URL const urlPatterns = [ /\/spreadsheets\/d\/([a-zA-Z0-9-_]+)/, /\/d\/([a-zA-Z0-9-_]+)/, /id=([a-zA-Z0-9-_]+)/, ]; for (const pattern of urlPatterns) { const match = input.match(pattern); if (match && match[1]) { return match[1]; } } throw new Error(`Invalid spreadsheet ID or URL: ${input}`); } /** * Convert A1 notation to row and column numbers */ static a1ToRowCol(a1: string): { row: number; col: number } { const match = a1.match(/^([A-Z]+)([0-9]+)$/); if (!match || !match[1] || !match[2]) { throw new Error(`Invalid A1 notation: ${a1}`); } const colStr = match[1]; const rowStr = match[2]; // Convert column letters to number let col = 0; for (let i = 0; i < colStr.length; i++) { col = col * 26 + (colStr.charCodeAt(i) - 64); } return { row: parseInt(rowStr, 10), col, }; } /** * Convert row and column numbers to A1 notation */ static rowColToA1(row: number, col: number): string { let colStr = ''; while (col > 0) { col--; colStr = String.fromCharCode(65 + (col % 26)) + colStr; col = Math.floor(col / 26); } return `${colStr}${row}`; } /** * Parse range string (e.g., "A1:B10") to get start and end coordinates */ static parseRange(range: string): { startRow: number; endRow: number; startCol: number; endCol: number; } { const parts = range.split(':'); if (parts.length !== 2 || !parts[0] || !parts[1]) { throw new Error(`Invalid range format: ${range}`); } const start = this.a1ToRowCol(parts[0]); const end = this.a1ToRowCol(parts[1]); return { startRow: start.row, endRow: end.row, startCol: start.col, endCol: end.col, }; } /** * Expand range to include all data */ static expandRangeToData( range: string, data: any[][] ): string { if (!data || data.length === 0) { return range; } const parsed = this.parseRange(range); const actualRows = data.length; const actualCols = data[0]?.length || 0; const startCell = this.rowColToA1(parsed.startRow, parsed.startCol); const endCell = this.rowColToA1( parsed.startRow + actualRows - 1, parsed.startCol + actualCols - 1 ); return `${startCell}:${endCell}`; } /** * Validate range format */ static isValidRange(range: string): boolean { try { this.parseRange(range); return true; } catch { return false; } } /** * Get sheet by name from spreadsheet metadata */ static findSheetByName( sheets: sheets_v4.Schema$Sheet[], sheetName: string ): sheets_v4.Schema$Sheet | null { return sheets.find((sheet) => sheet.properties?.title === sheetName) || null; } /** * Get sheet by ID from spreadsheet metadata */ static findSheetById( sheets: sheets_v4.Schema$Sheet[], sheetId: number ): sheets_v4.Schema$Sheet | null { return sheets.find((sheet) => sheet.properties?.sheetId === sheetId) || null; } /** * Convert 2D array to Google Sheets format */ static arrayToSheetsFormat(values: any[][]): sheets_v4.Schema$ValueRange { return { values, majorDimension: 'ROWS', }; } /** * Convert Google Sheets format to 2D array */ static sheetsFormatToArray( valueRange: sheets_v4.Schema$ValueRange ): any[][] { return valueRange.values || []; } /** * Create a range string for a specific sheet */ static createSheetRange(sheetName: string, range?: string): string { if (range) { return `${sheetName}!${range}`; } return sheetName; } /** * Extract sheet name from range string */ static extractSheetName(range: string): string | null { const match = range.match(/^([^!]+)!/); return match?.[1] || null; } /** * Check if a value is empty (null, undefined, or empty string) */ static isEmpty(value: any): boolean { return value === null || value === undefined || value === ''; } /** * Flatten 2D array to 1D array */ static flattenArray<T>(array: T[][]): T[] { return array.reduce((acc, curr) => acc.concat(curr), []); } /** * Chunk array into smaller arrays */ static chunkArray<T>(array: T[], chunkSize: number): T[][] { const chunks: T[][] = []; for (let i = 0; i < array.length; i += chunkSize) { chunks.push(array.slice(i, i + chunkSize)); } return chunks; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ainetwork-ai/google-sheet-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server