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";
/**
* 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.
*/
export function Markdown({
children,
context,
}: {
children: string;
context?: { base: string; gitRef: string; dir: string };
}) {
return (
<div className="markdown">
<ReactMarkdown
remarkPlugins={[remarkGfm]}
rehypePlugins={[rehypeRaw, rehypeSanitize]}
urlTransform={(url, key) => {
const safe = defaultUrlTransform(url);
if (!context || !safe || /^([a-z][a-z0-9+.-]*:|\/\/|#|\/)/i.test(safe)) return safe;
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>
);
}