* Regenerates the Table of Contents in the root CHANGELOG.md. * Uses GitHub's heading anchor algorithm with duplicate tracking.
()
| 276 | * Uses GitHub's heading anchor algorithm with duplicate tracking. |
| 277 | */ |
| 278 | function updateTableOfContents() { |
| 279 | let changelogPath = path.join(getRootDir(), "CHANGELOG.md"); |
| 280 | |
| 281 | if (preview) { |
| 282 | console.log(" • Would update Table of Contents"); |
| 283 | return; |
| 284 | } |
| 285 | |
| 286 | let content = readFile(changelogPath); |
| 287 | |
| 288 | // Strip the existing <details> block before parsing headings so that |
| 289 | // links inside the TOC don't skew the duplicate-anchor counters |
| 290 | let contentWithoutDetails = content.replace( |
| 291 | /<details>[\s\S]*?<\/details>/, |
| 292 | "", |
| 293 | ); |
| 294 | |
| 295 | // Build TOC: include h1, h2 (versions), and h4+ items nested under |
| 296 | // "What's Changed" h3 sections (shown at h3 indent level). |
| 297 | let tocLines: string[] = []; |
| 298 | let inWhatsChanged = false; |
| 299 | |
| 300 | for (let line of contentWithoutDetails.split("\n")) { |
| 301 | let match = line.match(/^(#{1,6})\s+(.+)$/); |
| 302 | if (!match) continue; |
| 303 | |
| 304 | let level = match[1].length; |
| 305 | let text = match[2].trim(); |
| 306 | let anchor = text |
| 307 | .toLowerCase() |
| 308 | .replace(/[^\w\s-]/g, "") |
| 309 | .trim() |
| 310 | .replace(/\s+/g, "-"); |
| 311 | |
| 312 | if (level <= 2) { |
| 313 | inWhatsChanged = false; |
| 314 | tocLines.push(`${" ".repeat(level - 1)}- [${text}](#${anchor})`); |
| 315 | } else if (level === 3) { |
| 316 | inWhatsChanged = text.toLowerCase() === "what's changed"; |
| 317 | } else if (inWhatsChanged) { |
| 318 | // Render at indent level 2 (child of version, same depth h3 used to occupy) |
| 319 | tocLines.push(` - [${text}](#${anchor})`); |
| 320 | } |
| 321 | } |
| 322 | |
| 323 | let newDetails = |
| 324 | `<details>\n <summary>Table of Contents</summary>\n\n` + |
| 325 | tocLines.join("\n") + |
| 326 | `\n\n</details>`; |
| 327 | |
| 328 | let updated = content.replace(/<details>[\s\S]*?<\/details>/, newDetails); |
| 329 | writeFile(changelogPath, updated); |
| 330 | console.log(" ✓ Updated Table of Contents"); |
| 331 | } |
| 332 | |
| 333 | /** |
| 334 | * Stages and commits changes, or prints the commit message in preview mode |
no test coverage detected
searching dependent graphs…