| 202 | } |
| 203 | |
| 204 | export function trimTrailingEmptyRowsAndColumns(matrix: ExcelCellValue[][]): ExcelCellValue[][] { |
| 205 | if (!Array.isArray(matrix) || matrix.length === 0) return [] |
| 206 | |
| 207 | const isEmptyValue = (v: ExcelCellValue) => v === null || v === '' |
| 208 | |
| 209 | // Determine last non-empty row |
| 210 | let lastNonEmptyRowIndex = -1 |
| 211 | for (let r = 0; r < matrix.length; r++) { |
| 212 | const row = matrix[r] || [] |
| 213 | const hasData = row.some((cell: ExcelCellValue) => !isEmptyValue(cell)) |
| 214 | if (hasData) lastNonEmptyRowIndex = r |
| 215 | } |
| 216 | |
| 217 | if (lastNonEmptyRowIndex === -1) return [] |
| 218 | |
| 219 | const trimmedRows = matrix.slice(0, lastNonEmptyRowIndex + 1) |
| 220 | |
| 221 | // Determine last non-empty column across trimmed rows |
| 222 | let lastNonEmptyColIndex = -1 |
| 223 | for (let r = 0; r < trimmedRows.length; r++) { |
| 224 | const row = trimmedRows[r] || [] |
| 225 | for (let c = 0; c < row.length; c++) { |
| 226 | if (!isEmptyValue(row[c])) { |
| 227 | if (c > lastNonEmptyColIndex) lastNonEmptyColIndex = c |
| 228 | } |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | if (lastNonEmptyColIndex === -1) return [] |
| 233 | |
| 234 | return trimmedRows.map((row) => (row || []).slice(0, lastNonEmptyColIndex + 1)) |
| 235 | } |
| 236 | |
| 237 | /** |
| 238 | * Fetches the browser-accessible web URL for an Excel spreadsheet. |