diff --git a/CHANGELOG.md b/CHANGELOG.md index 484d0be..ff0c639 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. ## [Unreleased] ### Fixed +- **checkBrokenLinks false positives from HTML comments** — `checkBrokenLinks` now skips links inside HTML comments (``), both single-line and multi-line. Previously, template examples in comments (e.g., in `patterns/INDEX.md`) were flagged as broken links. - **checkPaths false positives** — `checkPaths` now only validates inline code paths from `ROUTER.md`, not all scaffold files. Eliminates false `MISSING_PATH` errors from context docs, pattern files, and tool config files where backtick-wrapped strings are config values, IPs, annotation keys, or other non-path content. [#79](https://github.com/theDakshJaitly/mex/issues/79) ## [0.6.1] - 2026-06-14 diff --git a/src/drift/checkers/broken-link.ts b/src/drift/checkers/broken-link.ts index 86aef6f..e562e01 100644 --- a/src/drift/checkers/broken-link.ts +++ b/src/drift/checkers/broken-link.ts @@ -23,7 +23,9 @@ export function checkBrokenLinks( } const fileDir = dirname(filePath); - const lines = content.split("\n"); + // Strip complete HTML comments before line processing. Unclosed /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 720cdd5..223b765 100644 --- a/test/checkers.test.ts +++ b/test/checkers.test.ts @@ -594,5 +594,77 @@ 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", () => { + 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); + }); + + 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); }); });