┌─ TS ───────────────────────────────────────────────────────────────────────┐
│ import { describe, expect, it } from "vitest"; │
│ import { mermaidToAscii, normalizeArt, parseMermaid } from "./mermaid"; │
│ import { checkGrid } from "./ascii"; │
│ │
│ describe("parseMermaid", () => { │
│ it("parses the flowchart subset with labels and edge text", () => { │
│ const p = parseMermaid("graph LR\nmd[markdown] -->|transforms| rh[rehype]\nrh │
│ --> fr\n")!; │
│ expect(p.direction).toBe("LR"); │
│ expect(p.graph.labels.get("md")).toBe("markdown"); │
│ expect(p.graph.edges).toEqual([ │
│ { from: "md", to: "rh", label: "transforms" }, │
│ { from: "rh", to: "fr", label: "" }, │
│ ]); │
│ }); │
│ │
│ it("parses multiple arrows on one line", () => { │
│ const p = parseMermaid("graph LR\na --> b --> c\n")!; │
│ expect(p.graph.edges.map((e) => e.from + e.to)).toEqual(["ab", "bc"]); │
│ }); │
│ │
│ it("ignores %% comments", () => { │
│ expect(parseMermaid("%% note\ngraph TD\na --> b\n")!.direction).toBe("TD"); │
│ }); │
│ │
│ it("returns null for syntax beyond the subset", () => { │
│ expect(parseMermaid("sequenceDiagram\nAlice->>Bob: hi")).toBeNull(); │
│ expect(parseMermaid("graph LR\nsubgraph one\na --> b\nend")).toBeNull(); │
│ expect(parseMermaid("graph RL\na --> b")).toBeNull(); │
│ }); │
│ }); │
│ │
│ describe("normalizeArt", () => { │
│ it("swaps off-grid arrowheads and strips trailing space", () => { │
│ expect(normalizeArt("─? \n?\n?─")).toBe("─>\n↓\n<─"); │
│ }); │
│ }); │
│ │
│ describe("mermaidToAscii", () => { │
│ it("renders LR chains through the house layout", () => { │
│ const art = mermaidToAscii("graph LR\na -->|go| b", 40); │
│ expect(art).toBe( │
│ [ │
│ " go", │
│ "┌───┐ ┌───┐", │
│ "│ a │───>│ b │", │
│ "└───┘ └───┘", │
│ ].join("\n"), │
│ ); │
│ }); │
│ │
│ it("renders TD chains vertically", () => { │
│ const art = mermaidToAscii("graph TD\na -->|go| b", 80); │
│ expect(art).toContain("↓"); │
│ }); │
│ │
│ it("delegates branching graphs to mermaid-ascii and stays on-grid", () => { │
│ const art = mermaidToAscii("graph TD\na --> b\na --> c", 86); │
│ expect(art).toContain("┌"); │
│ expect(() => checkGrid(art, 86, "t")).not.toThrow(); │
│ }); │
│ }); │
└────────────────────────────────────────────────────────────────────────────────────┘
┌─ TS ─────────────────────────────────┐
│ import { describe, expect, it } from "vitest │
│ "; │
│ import { mermaidToAscii, normalizeArt, parse │
│ Mermaid } from "./mermaid"; │
│ import { checkGrid } from "./ascii"; │
│ │
│ describe("parseMermaid", () => { │
│ it("parses the flowchart subset with label │
│ s and edge text", () => { │
│ const p = parseMermaid("graph LR\nmd[mar │
│ kdown] -->|transforms| rh[rehype]\nrh --> fr │
│ \n")!; │
│ expect(p.direction).toBe("LR"); │
│ expect(p.graph.labels.get("md")).toBe("m │
│ arkdown"); │
│ expect(p.graph.edges).toEqual([ │
│ { from: "md", to: "rh", label: "transf │
│ orms" }, │
│ { from: "rh", to: "fr", label: "" }, │
│ ]); │
│ }); │
│ │
│ it("parses multiple arrows on one line", ( │
│ ) => { │
│ const p = parseMermaid("graph LR\na --> │
│ b --> c\n")!; │
│ expect(p.graph.edges.map((e) => e.from + │
│ e.to)).toEqual(["ab", "bc"]); │
│ }); │
│ │
│ it("ignores %% comments", () => { │
│ expect(parseMermaid("%% note\ngraph TD\n │
│ a --> b\n")!.direction).toBe("TD"); │
│ }); │
│ │
│ it("returns null for syntax beyond the sub │
│ set", () => { │
│ expect(parseMermaid("sequenceDiagram\nAl │
│ ice->>Bob: hi")).toBeNull(); │
│ expect(parseMermaid("graph LR\nsubgraph │
│ one\na --> b\nend")).toBeNull(); │
│ expect(parseMermaid("graph RL\na --> b") │
│ ).toBeNull(); │
│ }); │
│ }); │
│ │
│ describe("normalizeArt", () => { │
│ it("swaps off-grid arrowheads and strips t │
│ railing space", () => { │
│ expect(normalizeArt("─? \n?\n?─")).toBe │
│ ("─>\n↓\n<─"); │
│ }); │
│ }); │
│ │
│ describe("mermaidToAscii", () => { │
│ it("renders LR chains through the house la │
│ yout", () => { │
│ const art = mermaidToAscii("graph LR\na │
│ -->|go| b", 40); │
│ expect(art).toBe( │
│ [ │
│ " go", │
│ "┌───┐ ┌───┐", │
│ "│ a │───>│ b │", │
│ "└───┘ └───┘", │
│ ].join("\n"), │
│ ); │
│ }); │
│ │
│ it("renders TD chains vertically", () => { │
│ const art = mermaidToAscii("graph TD\na │
│ -->|go| b", 80); │
│ expect(art).toContain("↓"); │
│ }); │
│ │
│ it("delegates branching graphs to mermaid- │
│ ascii and stays on-grid", () => { │
│ const art = mermaidToAscii("graph TD\na │
│ --> b\na --> c", 86); │
│ expect(art).toContain("┌"); │
│ expect(() => checkGrid(art, 86, "t")).no │
│ t.toThrow(); │
│ }); │
│ }); │
└──────────────────────────────────────────────┘