import { describe, expect, test } from "bun:test"; import { stripHtmlComments, isMemoryFilePath, getLargeMemoryFiles, MAX_MEMORY_CHARACTER_COUNT, type MemoryFileInfo, } from "../claudemd"; function mockMemoryFile(overrides: Partial = {}): MemoryFileInfo { return { path: "/project/CLAUDE.md", type: "Project", content: "test content", ...overrides, }; } describe("stripHtmlComments", () => { test("strips block-level HTML comments (own line)", () => { // CommonMark type-2 HTML blocks: comment must start at beginning of line const result = stripHtmlComments("text\n\nmore"); expect(result.content).not.toContain("block comment"); expect(result.stripped).toBe(true); }); test("returns stripped: false when no comments", () => { const result = stripHtmlComments("no comments here"); expect(result.stripped).toBe(false); expect(result.content).toBe("no comments here"); }); test("returns stripped: true when block comments exist", () => { const result = stripHtmlComments("hello\n\nend"); expect(result.stripped).toBe(true); }); test("handles empty string", () => { const result = stripHtmlComments(""); expect(result.content).toBe(""); expect(result.stripped).toBe(false); }); test("handles multiple block comments", () => { const result = stripHtmlComments( "a\n\nb\n\nc" ); expect(result.content).not.toContain("c1"); expect(result.content).not.toContain("c2"); expect(result.stripped).toBe(true); }); test("preserves code block content", () => { const input = "text\n```html\n\n```\nmore"; const result = stripHtmlComments(input); expect(result.content).toContain(""); }); test("preserves inline comments within paragraphs", () => { // Inline comments are NOT stripped (CommonMark paragraph semantics) const result = stripHtmlComments("text more"); expect(result.content).toContain(""); expect(result.stripped).toBe(false); }); }); describe("isMemoryFilePath", () => { test("returns true for CLAUDE.md path", () => { expect(isMemoryFilePath("/project/CLAUDE.md")).toBe(true); }); test("returns true for CLAUDE.local.md path", () => { expect(isMemoryFilePath("/project/CLAUDE.local.md")).toBe(true); }); test("returns true for .claude/rules/ path", () => { expect(isMemoryFilePath("/project/.claude/rules/foo.md")).toBe(true); }); test("returns false for regular file", () => { expect(isMemoryFilePath("/project/src/main.ts")).toBe(false); }); test("returns false for unrelated .md file", () => { expect(isMemoryFilePath("/project/README.md")).toBe(false); }); test("returns false for .claude directory non-rules file", () => { expect(isMemoryFilePath("/project/.claude/settings.json")).toBe(false); }); }); describe("getLargeMemoryFiles", () => { test("returns files exceeding threshold", () => { const largeContent = "x".repeat(MAX_MEMORY_CHARACTER_COUNT + 1); const files = [ mockMemoryFile({ content: "small" }), mockMemoryFile({ content: largeContent, path: "/big.md" }), ]; const result = getLargeMemoryFiles(files); expect(result).toHaveLength(1); expect(result[0].path).toBe("/big.md"); }); test("returns empty array when all files are small", () => { const files = [ mockMemoryFile({ content: "small" }), mockMemoryFile({ content: "also small" }), ]; expect(getLargeMemoryFiles(files)).toEqual([]); }); test("correctly identifies threshold boundary", () => { const atThreshold = "x".repeat(MAX_MEMORY_CHARACTER_COUNT); const overThreshold = "x".repeat(MAX_MEMORY_CHARACTER_COUNT + 1); const files = [ mockMemoryFile({ content: atThreshold }), mockMemoryFile({ content: overThreshold }), ]; const result = getLargeMemoryFiles(files); expect(result).toHaveLength(1); }); });