import { describe, expect, it } from "vitest"; import { citationDomainLabel, closeUnterminatedFence, isExternalMarkdownUrl, parseCitationBadgeLabel, parseHexColorToken, sanitizeMarkdownUrl, } from "./markdown"; describe("sanitizeMarkdownUrl", () => { it("allows normal external links and optionally allows local links", () => { expect(sanitizeMarkdownUrl("https://example.com/docs")).toBe("https://example.com/docs"); expect(sanitizeMarkdownUrl("mailto:hello@example.com")).toBe("mailto:hello@example.com"); expect(sanitizeMarkdownUrl("/docs", true)).toBe("/docs"); expect(sanitizeMarkdownUrl("#section", true)).toBe("#section"); }); it("rejects executable and embedded-data URLs", () => { expect(sanitizeMarkdownUrl("javascript:alert(1)", true)).toBeUndefined(); expect(sanitizeMarkdownUrl("data:text/html,", true)).toBeUndefined(); expect(sanitizeMarkdownUrl("/docs")).toBeUndefined(); }); }); describe("isExternalMarkdownUrl", () => { it("identifies outbound links while excluding local paths and fragments", () => { expect(isExternalMarkdownUrl("https://example.com/docs")).toBe(true); expect(isExternalMarkdownUrl("http://85.215.232.220:8080/gudrun-review/")).toBe(true); expect(isExternalMarkdownUrl("mailto:hello@example.com")).toBe(true); expect(isExternalMarkdownUrl("/docs")).toBe(false); expect(isExternalMarkdownUrl("#section")).toBe(false); expect(isExternalMarkdownUrl(undefined)).toBe(false); }); }); describe("parseHexColorToken", () => { it("parses valid 3, 6, and 8 digit hex color tokens and rejects other strings", () => { expect(parseHexColorToken("#6B4226")).toBe("#6B4226"); expect(parseHexColorToken(" #e8722a ")).toBe("#e8722a"); expect(parseHexColorToken("#fff")).toBe("#fff"); expect(parseHexColorToken("#FAF6F0FF")).toBe("#FAF6F0FF"); expect(parseHexColorToken("#12345")).toBeUndefined(); expect(parseHexColorToken("npm run dev")).toBeUndefined(); }); }); describe("closeUnterminatedFence", () => { it("temporarily closes a partial streaming code fence", () => { expect(closeUnterminatedFence("Before\n```ts\nconst value = 1;")).toBe( "Before\n```ts\nconst value = 1;\n```", ); }); it("leaves complete markdown unchanged", () => { const markdown = "```ts\nconst value = 1;\n```\n\nDone"; expect(closeUnterminatedFence(markdown)).toBe(markdown); }); }); describe("parseCitationBadgeLabel and citationDomainLabel", () => { it("recognizes numeric inline citation links and extracts domain labels", () => { expect(parseCitationBadgeLabel("1", "https://arxiv.org/abs/2401.00001")).toBe("1"); expect(parseCitationBadgeLabel("[12]", "https://www.example.com/article")).toBe("12"); expect(parseCitationBadgeLabel("Read more", "https://example.com/article")).toBeUndefined(); expect(parseCitationBadgeLabel("1", "/relative/path")).toBeUndefined(); expect(citationDomainLabel("https://www.arxiv.org/abs/2401.00001")).toBe("arxiv.org"); expect(citationDomainLabel("invalid-url")).toBeUndefined(); }); });