434 lines · 16.3 KB · TypeScript
RawDownload
import { describe, expect, it } from "vite-plus/test";import { createElement } from "react";import { renderToStaticMarkup } from "react-dom/server";import ReactMarkdown from "react-markdown"; import {  extractMarkdownLinkHrefs,  resolveInlineCodeFileLinkMeta,  resolveMarkdownFileLinkMeta,  resolveMarkdownFileLinkTarget,  rewriteMarkdownFileUriHref,  shouldOpenMarkdownFileLinkInBrowserByDefault,  shouldOpenMarkdownFileLinkInEditor,} from "./markdown-links"; function renderMarkdownLinkHref(markdown: string): string | undefined {  let renderedHref: string | undefined;  renderToStaticMarkup(    createElement(      ReactMarkdown,      {        components: {          a({ href }) {            renderedHref = href;            return createElement("a", { href });          },        },      },      markdown,    ),  );  return renderedHref;} describe("extractMarkdownLinkHrefs", () => {  it("extracts angle-bracketed paths containing spaces", () => {    expect(      extractMarkdownLinkHrefs(        "[Open the Bike Receipts folder](</Users/dara/Downloads/Lime Ride Artifacts/Bike Receipts>)",      ),    ).toEqual(["/Users/dara/Downloads/Lime Ride Artifacts/Bike Receipts"]);  });   it("preserves ordinary destinations and ignores link titles", () => {    expect(      extractMarkdownLinkHrefs(        '[source](apps/web/src/markdown-links.ts "implementation") and [docs](https://example.com)',      ),    ).toEqual(["apps/web/src/markdown-links.ts", "https://example.com"]);  });}); describe("shouldOpenMarkdownFileLinkInEditor", () => {  it("uses command-click on macOS", () => {    expect(shouldOpenMarkdownFileLinkInEditor({ metaKey: true, ctrlKey: false }, "MacIntel")).toBe(      true,    );    expect(shouldOpenMarkdownFileLinkInEditor({ metaKey: false, ctrlKey: true }, "MacIntel")).toBe(      false,    );  });   it("uses control-click on other platforms", () => {    expect(      shouldOpenMarkdownFileLinkInEditor({ metaKey: false, ctrlKey: true }, "Linux x86_64"),    ).toBe(true);    expect(      shouldOpenMarkdownFileLinkInEditor({ metaKey: true, ctrlKey: false }, "Linux x86_64"),    ).toBe(false);  });}); describe("shouldOpenMarkdownFileLinkInBrowserByDefault", () => {  it("keeps PDFs browser-first while source files open in the file viewer", () => {    expect(shouldOpenMarkdownFileLinkInBrowserByDefault("report.pdf")).toBe(true);    expect(shouldOpenMarkdownFileLinkInBrowserByDefault("report.PDF?download=1")).toBe(true);    expect(shouldOpenMarkdownFileLinkInBrowserByDefault("report.html")).toBe(false);    expect(shouldOpenMarkdownFileLinkInBrowserByDefault("report.xml")).toBe(false);  });}); describe("rewriteMarkdownFileUriHref", () => {  it("rewrites file uri hrefs into direct path hrefs", () => {    expect(rewriteMarkdownFileUriHref("file:///Users/julius/project/src/main.ts#L42")).toBe(      "/Users/julius/project/src/main.ts#L42",    );  });   it("preserves encoded octets so file paths are decoded only once later", () => {    expect(rewriteMarkdownFileUriHref("file:///Users/julius/project/file%2520name.md")).toBe(      "/Users/julius/project/file%2520name.md",    );  });   it("normalizes file uri hrefs for windows drive paths", () => {    expect(      rewriteMarkdownFileUriHref(        "file:///D:/Programme/t3code/apps/web/src/components/chat/OpenInPicker.tsx#L69",      ),    ).toBe("D:/Programme/t3code/apps/web/src/components/chat/OpenInPicker.tsx#L69");  });   it("preserves file uri authorities as windows UNC paths", () => {    expect(rewriteMarkdownFileUriHref("file://server/share/workspace-image.svg")).toBe(      "\\\\server\\share\\workspace-image.svg",    );  });   it("treats a localhost file uri as a local path", () => {    expect(rewriteMarkdownFileUriHref("file://localhost/home/me/notes.md")).toBe(      "/home/me/notes.md",    );  });   it("unwraps angle-bracketed file uri hrefs", () => {    expect(      rewriteMarkdownFileUriHref(" <file:///D:/Programme/t3code/apps/web/src/markdown-links.ts> "),    ).toBe("D:/Programme/t3code/apps/web/src/markdown-links.ts");  });}); describe("resolveMarkdownFileLinkTarget", () => {  it("resolves absolute posix file paths", () => {    expect(resolveMarkdownFileLinkTarget("/Users/julius/project/AGENTS.md")).toBe(      "/Users/julius/project/AGENTS.md",    );  });   it("resolves relative file paths against cwd", () => {    expect(resolveMarkdownFileLinkTarget("src/processRunner.ts:71", "/Users/julius/project")).toBe(      "/Users/julius/project/src/processRunner.ts:71",    );  });   it("does not treat filename line references as external schemes", () => {    expect(resolveMarkdownFileLinkTarget("script.ts:10", "/Users/julius/project")).toBe(      "/Users/julius/project/script.ts:10",    );  });   it("resolves bare file names against cwd", () => {    expect(resolveMarkdownFileLinkTarget("AGENTS.md", "/Users/julius/project")).toBe(      "/Users/julius/project/AGENTS.md",    );  });   it("maps #L line anchors to editor line suffixes", () => {    expect(resolveMarkdownFileLinkTarget("/Users/julius/project/src/main.ts#L42C7")).toBe(      "/Users/julius/project/src/main.ts:42:7",    );  });   it("ignores external urls", () => {    expect(resolveMarkdownFileLinkTarget("https://example.com/docs")).toBeNull();  });   it("does not double-decode file URLs", () => {    expect(resolveMarkdownFileLinkTarget("file:///Users/julius/project/file%2520name.md")).toBe(      "/Users/julius/project/file%20name.md",    );  });   it("resolves file uri authorities as windows UNC paths", () => {    expect(resolveMarkdownFileLinkTarget("file://server/share/workspace-image.svg")).toBe(      "\\\\server\\share\\workspace-image.svg",    );  });   it("resolves a localhost file uri as a local path", () => {    expect(resolveMarkdownFileLinkTarget("file://localhost/home/me/notes.md")).toBe(      "/home/me/notes.md",    );  });   it("formats tooltip display paths relative to the cwd when possible", () => {    expect(      resolveMarkdownFileLinkMeta(        "file:///C:/Users/mike/dev-stuff/t3code/apps/web/src/session-logic.ts#L501",        "C:/Users/mike/dev-stuff/t3code",      ),    ).toMatchObject({      displayPath: "t3code/apps/web/src/session-logic.ts:501",      workspaceRelativePath: "apps/web/src/session-logic.ts",    });  });   it("resolves the encoded spaces emitted by the markdown renderer", () => {    expect(      resolveMarkdownFileLinkMeta(        "/Users/dara/Downloads/Lime%20Ride%20Artifacts/Bike%20Receipts",        "/Users/dara/Downloads/Lime Ride Artifacts",      ),    ).toMatchObject({      targetPath: "/Users/dara/Downloads/Lime Ride Artifacts/Bike Receipts",      workspaceRelativePath: "Bike Receipts",      basename: "Bike Receipts",    });  });   it("resolves relative spaced folders from the markdown renderer", () => {    const href = renderMarkdownLinkHref("[folder](<docs/My Folder>)");     expect(href).toBe("docs/My%20Folder");    expect(resolveMarkdownFileLinkMeta(href, "/repo/project")).toMatchObject({      targetPath: "/repo/project/docs/My Folder",      workspaceRelativePath: "docs/My Folder",      basename: "My Folder",    });  });   it.each(["md", "html", "xml"])(    "resolves a bare spaced .%s filename from the markdown renderer",    (extension) => {      const href = renderMarkdownLinkHref(`[checklist](<Updated cutover checklist.${extension}>)`);       expect(href).toBe(`Updated%20cutover%20checklist.${extension}`);      expect(resolveMarkdownFileLinkMeta(href, "/repo/project")).toMatchObject({        targetPath: `/repo/project/Updated cutover checklist.${extension}`,        workspaceRelativePath: `Updated cutover checklist.${extension}`,        basename: `Updated cutover checklist.${extension}`,      });    },  );   it("formats tooltip display paths relative to the cwd for slash-prefixed windows paths", () => {    expect(      resolveMarkdownFileLinkMeta(        "/C:/Users/mike/dev-stuff/t3code/apps/web/src/components/chat/MessagesTimeline.virtualization.browser.tsx",        "C:/Users/mike/dev-stuff/t3code",      ),    ).toMatchObject({      displayPath:        "t3code/apps/web/src/components/chat/MessagesTimeline.virtualization.browser.tsx",      workspaceRelativePath:        "apps/web/src/components/chat/MessagesTimeline.virtualization.browser.tsx",    });  });   it("does not create a preview path for files outside the workspace", () => {    expect(resolveMarkdownFileLinkMeta("/tmp/report.ts", "/repo/project")).toMatchObject({      workspaceRelativePath: null,    });  });   it("normalizes slash-prefixed windows drive paths before resolving", () => {    expect(      resolveMarkdownFileLinkTarget(        "/D:/Programme/t3code/apps/web/src/components/chat/OpenInPicker.tsx#L69",      ),    ).toBe("D:/Programme/t3code/apps/web/src/components/chat/OpenInPicker.tsx:69");  });   it("resolves angle-bracketed windows drive paths", () => {    expect(      resolveMarkdownFileLinkTarget(        "</D:/Programme/t3code/apps/web/src/components/ChatMarkdown.tsx:1>",      ),    ).toBe("D:/Programme/t3code/apps/web/src/components/ChatMarkdown.tsx:1");  });   it("does not treat app routes as file links", () => {    expect(resolveMarkdownFileLinkTarget("/chat/settings")).toBeNull();  });}); describe("resolveInlineCodeFileLinkMeta", () => {  it("links relative paths with file extensions", () => {    expect(      resolveInlineCodeFileLinkMeta("docs/internals/workspace-layout.md", "/Users/julius/project"),    ).toMatchObject({      targetPath: "/Users/julius/project/docs/internals/workspace-layout.md",      basename: "workspace-layout.md",    });  });   it("links absolute posix paths", () => {    expect(resolveInlineCodeFileLinkMeta("/Users/julius/project/AGENTS.md")).toMatchObject({      targetPath: "/Users/julius/project/AGENTS.md",    });    expect(resolveInlineCodeFileLinkMeta("/usr/local/bin/tool")).toMatchObject({      targetPath: "/usr/local/bin/tool",    });    expect(resolveInlineCodeFileLinkMeta("/workspace/Makefile")).toMatchObject({      basename: "Makefile",    });    expect(resolveInlineCodeFileLinkMeta("/chat/settings")).toBeNull();  });   it("links windows drive paths", () => {    expect(resolveInlineCodeFileLinkMeta("C:\\Users\\mike\\project\\src\\main.ts")).toMatchObject({      basename: "main.ts",    });  });   it("links relative paths with line positions", () => {    expect(      resolveInlineCodeFileLinkMeta("src/processRunner.ts:71", "/Users/julius/project"),    ).toMatchObject({      targetPath: "/Users/julius/project/src/processRunner.ts:71",      line: 71,    });  });   it("links bare filenames only when a line suffix marks them as file references", () => {    expect(resolveInlineCodeFileLinkMeta("script.ts:10", "/Users/julius/project")).toMatchObject({      targetPath: "/Users/julius/project/script.ts:10",      line: 10,    });    expect(resolveInlineCodeFileLinkMeta("AGENTS.md", "/Users/julius/project")).toBeNull();  });   it("links extensionless bare filenames with a line suffix", () => {    expect(resolveInlineCodeFileLinkMeta("Makefile:12", "/Users/julius/project")).toMatchObject({      targetPath: "/Users/julius/project/Makefile:12",      basename: "Makefile",      line: 12,    });    expect(resolveInlineCodeFileLinkMeta("Dockerfile:8:2", "/Users/julius/project")).toMatchObject({      line: 8,      column: 2,    });    expect(resolveInlineCodeFileLinkMeta("Makefile:12")).toBeNull();  });   it("does not treat arbitrary name:digits shapes as files", () => {    expect(resolveInlineCodeFileLinkMeta("error:1", "/Users/julius/project")).toBeNull();    expect(resolveInlineCodeFileLinkMeta("TODO:12", "/Users/julius/project")).toBeNull();    expect(resolveInlineCodeFileLinkMeta("exit:0", "/Users/julius/project")).toBeNull();    expect(resolveInlineCodeFileLinkMeta("port:3000", "/Users/julius/project")).toBeNull();    expect(resolveInlineCodeFileLinkMeta("http:80", "/Users/julius/project")).toBeNull();  });   it("links dot-prefixed relative paths without extensions", () => {    expect(      resolveInlineCodeFileLinkMeta("./scripts/deploy", "/Users/julius/project"),    ).toMatchObject({      basename: "deploy",    });  });   it("links relative windows-style paths by normalizing backslashes", () => {    expect(resolveInlineCodeFileLinkMeta("src\\main.ts", "/Users/julius/project")).toMatchObject({      targetPath: "/Users/julius/project/src/main.ts",      basename: "main.ts",    });    expect(      resolveInlineCodeFileLinkMeta(".\\scripts\\deploy", "/Users/julius/project"),    ).toMatchObject({      basename: "deploy",    });  });   it("ignores hosts, ports, and versions", () => {    expect(resolveInlineCodeFileLinkMeta("127.0.0.1:3000", "/Users/julius/project")).toBeNull();    expect(resolveInlineCodeFileLinkMeta("localhost:3000", "/Users/julius/project")).toBeNull();    expect(      resolveInlineCodeFileLinkMeta("example.com/index.html", "/Users/julius/project"),    ).toBeNull();    expect(resolveInlineCodeFileLinkMeta("example.com:8080", "/Users/julius/project")).toBeNull();    expect(resolveInlineCodeFileLinkMeta("10.0.0.1:80:1", "/Users/julius/project")).toBeNull();    expect(      resolveInlineCodeFileLinkMeta("localhost/index.html", "/Users/julius/project"),    ).toBeNull();    expect(      resolveInlineCodeFileLinkMeta("example.uk/index.html", "/Users/julius/project"),    ).toBeNull();  });   it("still links files whose extension merely resembles a tld", () => {    expect(resolveInlineCodeFileLinkMeta("script.ts:10", "/Users/julius/project")).not.toBeNull();    expect(resolveInlineCodeFileLinkMeta("src/setup.sh:3", "/Users/julius/project")).not.toBeNull();    expect(resolveInlineCodeFileLinkMeta("Makefile.in:12", "/Users/julius/project")).not.toBeNull();    expect(      resolveInlineCodeFileLinkMeta("conf.d/nginx.conf", "/Users/julius/project"),    ).not.toBeNull();  });   it("prefers file over country-code host when a line suffix is present", () => {    expect(resolveInlineCodeFileLinkMeta("script.pl:10", "/Users/julius/project")).toMatchObject({      targetPath: "/Users/julius/project/script.pl:10",      line: 10,    });    expect(resolveInlineCodeFileLinkMeta("model.pt:3", "/Users/julius/project")).not.toBeNull();    expect(      resolveInlineCodeFileLinkMeta("example.pl/index.html", "/Users/julius/project"),    ).toBeNull();    expect(resolveInlineCodeFileLinkMeta("example.com:8080", "/Users/julius/project")).toBeNull();  });   it("ignores commands, flags, and expressions", () => {    expect(resolveInlineCodeFileLinkMeta("git worktree list --porcelain")).toBeNull();    expect(resolveInlineCodeFileLinkMeta("node.meta", "/Users/julius/project")).toBeNull();    expect(resolveInlineCodeFileLinkMeta("pnpm install", "/Users/julius/project")).toBeNull();    expect(resolveInlineCodeFileLinkMeta("src/**/*.ts", "/Users/julius/project")).toBeNull();  });   it("ignores extension-less relative segments like git refs and directories", () => {    expect(resolveInlineCodeFileLinkMeta("origin/main", "/Users/julius/project")).toBeNull();    expect(resolveInlineCodeFileLinkMeta("apps/web", "/Users/julius/project")).toBeNull();  });   it("ignores external urls", () => {    expect(resolveInlineCodeFileLinkMeta("https://example.com/docs.html")).toBeNull();  });   it("ignores relative paths without a cwd to resolve against", () => {    expect(resolveInlineCodeFileLinkMeta("docs/internals/workspace-layout.md")).toBeNull();  });}); describe("directory paths with a trailing separator", () => {  it("keeps the final segment for a POSIX directory path", () => {    expect(resolveMarkdownFileLinkMeta("/tmp/favicons/", "/repo/project")).toMatchObject({      basename: "favicons",    });  });   it("keeps the final segment for a Windows directory path", () => {    expect(      resolveMarkdownFileLinkMeta("C:\\Users\\kelchm\\.claude\\", "/repo/project"),    ).toMatchObject({ basename: ".claude" });  });   it("matches the label of the same path without a trailing separator", () => {    const withSlash = resolveMarkdownFileLinkMeta("/tmp/favicons/", "/repo/project");    const withoutSlash = resolveMarkdownFileLinkMeta("/tmp/favicons", "/repo/project");    expect(withSlash?.basename).toBe(withoutSlash?.basename);  });   it("does not produce an empty label for the filesystem root", () => {    const meta = resolveMarkdownFileLinkMeta("/tmp/", "/repo/project");    expect(meta?.basename).not.toBe("");  });});