import MarkdownIt from "markdown-it";
import type { MarkdownIt as MarkdownRenderer, StateCore } from "markdown-it";
import { highlight } from "sugar-high";
import { FilterXSS, safeAttrValue } from "xss";
import { linkTextReferences } from "./references";
import { camoUrl } from "./camo-sign";
export type MarkdownContext = {
owner: string;
repo: string;
ref: string;
/** Directory of the document inside the repo, used to resolve relative links. */
basePath: string;
};
const ATTACHMENT_PREFIX = "/attachments/";
const ABSOLUTE_URL = /^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i;
/** GitHub's prefix for user-supplied ids/anchors, so content cannot clobber `window.<id>` or app anchors. */
const USER_CONTENT_PREFIX = "user-content-";
const EXTERNAL_URL = /^(?:https?:)?\/\//i;
const DATA_IMAGE = /^data:image\/(png|gif|jpe?g|webp);/i;
/** External images go through the signed same-origin proxy; relative, data: and attachment URLs stay as they are. */
function imageSource(url: string): string {
if (!EXTERNAL_URL.test(url)) return url;
return camoUrl(url.startsWith("//") ? `https:${url}` : url) ?? "";
}
function userContentId(value: string): string {
const cleaned = value.trim();
return cleaned.length === 0 || cleaned.startsWith(USER_CONTENT_PREFIX) ? cleaned : `${USER_CONTENT_PREFIX}${cleaned}`;
}
/** Same-document anchors must point at the prefixed ids this renderer emits. */
function anchorHref(url: string): string {
if (!url.startsWith("#") || url.length === 1) return url;
return `#${userContentId(url.slice(1))}`;
}
function createRenderer(): MarkdownRenderer {