From 6fe3135e4ec781bfb4a90eb8d62e4a6f84d71436 Mon Sep 17 00:00:00 2001 From: Mike Wheway Date: Wed, 17 Jun 2026 13:25:14 -0400 Subject: [PATCH 1/2] fix: skip HTML comments in checkBrokenLinks checkBrokenLinks was scanning links inside HTML comments and flagging them as broken. Template examples in patterns/INDEX.md (which live in comment blocks) were producing false BROKEN_LINK warnings. Strips complete spans from content before line processing using the same regex approach as checkIndexSync. Unclosed `), both single-line and multi-line. Previously, template examples in comments (e.g., in `patterns/INDEX.md`) were flagged as broken links. + ## [0.6.1] - 2026-06-14 ### Added diff --git a/src/drift/checkers/broken-link.ts b/src/drift/checkers/broken-link.ts index ed85394..354b72e 100644 --- a/src/drift/checkers/broken-link.ts +++ b/src/drift/checkers/broken-link.ts @@ -22,7 +22,9 @@ export function checkBrokenLinks( } const fileDir = dirname(filePath); - const lines = content.split("\n"); + // Strip complete HTML comments before line processing. Unclosed /g, "").split("\n"); let inFence = false; for (let i = 0; i < lines.length; i++) { diff --git a/test/checkers.test.ts b/test/checkers.test.ts index 720cdd5..578e665 100644 --- a/test/checkers.test.ts +++ b/test/checkers.test.ts @@ -595,4 +595,50 @@ describe("checkBrokenLinks", () => { expect(issues).toHaveLength(1); expect(issues[0].severity).toBe("warning"); }); + + it("ignores links inside HTML comments", () => { + const file = join(tmpDir, "INDEX.md"); + writeFileSync( + file, + "# Index\n\n\n\n| Pattern | Use |\n|---|---|\n", + ); + const issues = checkBrokenLinks([file], tmpDir, tmpDir); + expect(issues).toHaveLength(0); + }); + + it("ignores links inside multi-line HTML comments", () => { + const file = join(tmpDir, "INDEX.md"); + writeFileSync( + file, + "# Index\n\n\n\nReal content.\n", + ); + const issues = checkBrokenLinks([file], tmpDir, tmpDir); + expect(issues).toHaveLength(0); + }); + + it("scans links after an unclosed HTML comment as plain text", () => { + mkdirSync(join(tmpDir, "context"), { recursive: true }); + const file = join(tmpDir, "guide.md"); + // Unclosed \n", + ); + const issues = checkBrokenLinks([file], tmpDir, tmpDir); + expect(issues).toHaveLength(0); + }); }); From b53b84a37c4755e187b378a4bfb6c4581eca4ee9 Mon Sep 17 00:00:00 2001 From: Mike Wheway Date: Thu, 18 Jun 2026 14:00:05 -0400 Subject: [PATCH 2/2] fix: preserve line numbers when stripping HTML comments in checkBrokenLinks Replace empty-string comment removal with newline-preserving padding so the line array stays the same length as the original file. Adds line number assertions to existing tests and two regression tests covering broken links after single-line and multi-line HTML comments. --- src/drift/checkers/broken-link.ts | 2 +- test/checkers.test.ts | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/drift/checkers/broken-link.ts b/src/drift/checkers/broken-link.ts index 354b72e..e2c63fe 100644 --- a/src/drift/checkers/broken-link.ts +++ b/src/drift/checkers/broken-link.ts @@ -24,7 +24,7 @@ export function checkBrokenLinks( const fileDir = dirname(filePath); // Strip complete HTML comments before line processing. Unclosed /g, "").split("\n"); + const lines = content.replace(//g, (m) => "\n".repeat(m.split("\n").length - 1)).split("\n"); let inFence = false; for (let i = 0; i < lines.length; i++) { diff --git a/test/checkers.test.ts b/test/checkers.test.ts index 578e665..223b765 100644 --- a/test/checkers.test.ts +++ b/test/checkers.test.ts @@ -594,6 +594,7 @@ describe("checkBrokenLinks", () => { const issues = checkBrokenLinks([file], tmpDir, tmpDir); expect(issues).toHaveLength(1); expect(issues[0].severity).toBe("warning"); + expect(issues[0].line).toBe(1); }); it("ignores links inside HTML comments", () => { @@ -627,6 +628,7 @@ describe("checkBrokenLinks", () => { const issues = checkBrokenLinks([file], tmpDir, tmpDir); expect(issues).toHaveLength(1); expect(issues[0].message).toContain("nowhere.md"); + expect(issues[0].line).toBe(5); }); it("scans links on lines with inline HTML comments", () => { @@ -641,4 +643,28 @@ describe("checkBrokenLinks", () => { const issues = checkBrokenLinks([file], tmpDir, tmpDir); expect(issues).toHaveLength(0); }); + + it("reports correct line numbers for broken links after multi-line HTML comments", () => { + mkdirSync(join(tmpDir, "context"), { recursive: true }); + const file = join(tmpDir, "guide.md"); + writeFileSync( + file, + "# Doc\n\n\n\n[broken](./context/nowhere.md)\n", + ); + const issues = checkBrokenLinks([file], tmpDir, tmpDir); + expect(issues).toHaveLength(1); + expect(issues[0].line).toBe(7); + }); + + it("reports correct line numbers for broken links after single-line HTML comments", () => { + mkdirSync(join(tmpDir, "context"), { recursive: true }); + const file = join(tmpDir, "guide.md"); + writeFileSync( + file, + "# Doc\n\n\n\n[broken](./context/nowhere.md)\n", + ); + const issues = checkBrokenLinks([file], tmpDir, tmpDir); + expect(issues).toHaveLength(1); + expect(issues[0].line).toBe(5); + }); });