import path from "node:path/posix";
import ReactMarkdown, { defaultUrlTransform } from "react-markdown";
import rehypeRaw from "rehype-raw";
import rehypeSanitize from "rehype-sanitize";
import remarkGfm from "remark-gfm";
import { encodePath } from "@/lib/format";
import { remarkWikiLinks, wikiUrl } from "@/lib/wiki-links";
/**
* Renders GitHub-flavored markdown. Inline HTML is allowed but sanitized with
* GitHub's own allowlist, so untrusted READMEs and issue bodies are safe. When
* `context` is given, relative links and images resolve against the file's
* location in the repository. With `wiki` (the wiki's base URL) instead, they
* resolve to the wiki's pages and files, and [[Wiki Links]] work.
*/
export function Markdown({
children,
context,
wiki,
}: {
children: string;
context?: { base: string; gitRef: string; dir: string };
wiki?: string;
}) {
return (
<div className="markdown">
<ReactMarkdown
remarkPlugins={wiki ? [remarkGfm, [remarkWikiLinks, { base: wiki }]] : [remarkGfm]}
rehypePlugins={[rehypeRaw, rehypeSanitize]}
urlTransform={(url, key) => {
const safe = defaultUrlTransform(url);
if ((!context && !wiki) || !safe || /^([a-z][a-z0-9+.-]*:|\/\/|#|\/)/i.test(safe)) return safe;
if (wiki) return wikiUrl(wiki, safe, key);
const [target, hash] = safe.split("#");
const resolved = path.normalize(path.join(context!.dir, target)).replace(/^(\.\.\/)+/, "");
const kind = key === "src" ? "raw" : "blob";
return `${context!.base}/${kind}/${encodePath(context!.gitRef)}/${encodePath(resolved)}${hash ? `#${hash}` : ""}`;
}}
>
{children}
</ReactMarkdown>
</div>
);
}