( track: string, tableStart: number, )
| 288 | |
| 289 | /** Character index in `track` immediately after the first balanced </table>, or -1. */ |
| 290 | export function firstCompleteTableEnd( |
| 291 | track: string, |
| 292 | tableStart: number, |
| 293 | ): number { |
| 294 | if (tableStart < 0 || tableStart >= track.length) { |
| 295 | return -1; |
| 296 | } |
| 297 | |
| 298 | const openMatch = track.slice(tableStart).match(/^<table\b[^>]*>/i); |
| 299 | if (!openMatch) { |
| 300 | return -1; |
| 301 | } |
| 302 | |
| 303 | let depth = 1; |
| 304 | let i = tableStart + openMatch[0]!.length; |
| 305 | |
| 306 | while (i < track.length && depth > 0) { |
| 307 | if (track[i] === "<") { |
| 308 | const rest = track.slice(i); |
| 309 | const closeMatch = rest.match(/^<\/table\s*>/i); |
| 310 | if (closeMatch) { |
| 311 | depth--; |
| 312 | i += closeMatch[0]!.length; |
| 313 | if (depth === 0) { |
| 314 | return i; |
| 315 | } |
| 316 | continue; |
| 317 | } |
| 318 | |
| 319 | const nestedOpen = rest.match(/^<table\b[^>]*>/i); |
| 320 | if (nestedOpen) { |
| 321 | depth++; |
| 322 | i += nestedOpen[0]!.length; |
| 323 | continue; |
| 324 | } |
| 325 | } |
| 326 | i++; |
| 327 | } |
| 328 | |
| 329 | return -1; |
| 330 | } |
| 331 | |
| 332 | function assembleTableSectionHtml(tableSection: string): string { |
| 333 | const parts = splitTableStream(tableSection); |
no outgoing calls
no test coverage detected