UNPKG

@scalar/code-highlight

Version:

Central methods and themes for code highlighting in Scalar projects

113 lines (112 loc) 3.4 kB
import rehypeExternalLinks from "rehype-external-links"; import rehypeFormat from "rehype-format"; import rehypeRaw from "rehype-raw"; import rehypeSanitize, { defaultSchema } from "rehype-sanitize"; import rehypeStringify from "rehype-stringify"; import remarkGfm from "remark-gfm"; import remarkParse from "remark-parse"; import remarkRehype from "remark-rehype"; import remarkStringify from "remark-stringify"; import { unified } from "unified"; import { SKIP, visit } from "unist-util-visit"; import { standardLanguages } from "../languages/index.js"; import { rehypeAlert } from "../rehype-alert/index.js"; import { rehypeHighlight } from "../rehype-highlight/index.js"; const transformNodes = (options, ..._ignored) => (tree) => { if (!options?.transform || !options?.type) { return; } visit(tree, options?.type, (node) => { options?.transform ? options?.transform(node) : node; return SKIP; }); return; }; function htmlFromMarkdown(markdown, options) { const removeTags = options?.removeTags ?? []; const tagNames = [...defaultSchema.tagNames ?? [], ...options?.allowTags ?? []].filter( (t) => !removeTags.includes(t) ); const html = unified().use(remarkParse).use(remarkGfm).use(transformNodes, { transform: options?.transform, type: options?.transformType }).use(remarkRehype, { allowDangerousHtml: true }).use(rehypeAlert).use(rehypeRaw).use(rehypeSanitize, { ...defaultSchema, // Don't prefix the heading ids clobberPrefix: "", // Makes it even more strict tagNames, attributes: { ...defaultSchema.attributes, abbr: ["title"], // Allow alert classes div: ["class", ["className", /^markdown-alert(-.*)?$/]] } }).use(rehypeHighlight, { languages: standardLanguages, // Enable auto detection detect: true }).use(rehypeExternalLinks, { target: "_blank" }).use(rehypeFormat).use(rehypeStringify).processSync(markdown); return html.toString(); } function getMarkdownAst(markdown) { return unified().use(remarkParse).use(remarkGfm).parse(markdown); } function getHeadings(markdown, depth = 1) { const tree = getMarkdownAst(markdown); const nodes = []; visit(tree, "heading", (node) => { const text = findTextInHeading(node); if (text) { nodes.push({ depth: node.depth ?? depth, value: text.value }); } }); return nodes; } function findTextInHeading(node) { if (node.type === "text") { return node; } if ("children" in node && node.children) { for (const child of node.children) { const text = findTextInHeading(child); if (text) { return text; } } } return null; } function splitContent(markdown) { const tree = getMarkdownAst(markdown); const sections = []; let nodes = []; tree.children?.forEach((node) => { if (node.type === "heading") { if (nodes.length) { sections.push(nodes); } sections.push([node]); nodes = []; } else { nodes.push(node); } }); if (nodes.length) { sections.push(nodes); } return sections.map((section) => createDocument(section)); } function createDocument(nodes) { const markdown = unified().use(remarkStringify).use(remarkGfm).stringify({ type: "root", children: nodes }); return markdown.trim(); } export { getHeadings, htmlFromMarkdown, splitContent }; //# sourceMappingURL=markdown.js.map