Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion src/drift/checkers/broken-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ export function checkBrokenLinks(
}

const fileDir = dirname(filePath);
const lines = content.split("\n");
// Strip complete HTML comments before line processing. Unclosed <!-- stays
// as plain text (matches checkIndexSync behavior).
const lines = content.replace(/<!--[\s\S]*?-->/g, (m) => "\n".repeat(m.split("\n").length - 1)).split("\n");
let inFence = false;

for (let i = 0; i < lines.length; i++) {
Expand Down
72 changes: 72 additions & 0 deletions test/checkers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<!-- Example: [foo.md](foo.md) -->\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[foo.md](foo.md)\n[bar.md](bar.md)\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 <!-- stays as plain text; link after it should still be checked
writeFileSync(
file,
"# Guide\n\n<!-- this comment never closes\n\nSee [missing](./context/nowhere.md).\n",
);
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", () => {
mkdirSync(join(tmpDir, "context"), { recursive: true });
writeFileSync(join(tmpDir, "context/target.md"), "# Target\n");
const file = join(tmpDir, "guide.md");
// Link before comment should be scanned; link inside comment should not
writeFileSync(
file,
"[real](./context/target.md) <!-- [fake](./missing.md) -->\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<!--\ncomment body\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<!-- some note -->\n\n[broken](./context/nowhere.md)\n",
);
const issues = checkBrokenLinks([file], tmpDir, tmpDir);
expect(issues).toHaveLength(1);
expect(issues[0].line).toBe(5);
});
});
Loading