import morphdom from "morphdom"; import { unified } from "unified"; import remarkParse from "remark-parse"; import remarkGfm from "remark-gfm"; import remarkMath from "remark-math"; import remarkRehype from "remark-rehype"; import rehypeRaw from "rehype-raw"; import rehypeKatex from "rehype-katex"; import rehypeParse from "rehype-parse"; import rehypeSanitize, { defaultSchema } from "rehype-sanitize"; import rehypeStringify from "rehype-stringify"; import "katex/contrib/copy-tex"; import { visit } from "unist-util-visit"; import { toText } from "hast-util-to-text"; import { removePosition } from "unist-util-remove-position"; import { highlight } from "../hooks/cell_editor/live_editor/monaco"; import { renderMermaid } from "./markdown/mermaid"; import { escapeHtml } from "../lib/utils"; /** * Renders markdown content in the given container. */ class Markdown { constructor( container, content, { baseUrl = null, emptyText = "", allowedUriSchemes = [] } = {} ) { this.container = container; this.content = content; this.baseUrl = baseUrl; this.emptyText = emptyText; this.allowedUriSchemes = allowedUriSchemes; this._render(); } setContent(content) { this.content = content; this._render(); } _render() { this._getHtml().then((html) => { // Wrap the HTML in another element, so that we // can use morphdom's childrenOnly option const wrappedHtml = `
${html}
`;
}
const result = options.highlight(node.value, node.lang);
if (result && typeof result.then === "function") {
const promise = Promise.resolve(result).then(updateNode);
promises.push(promise);
} else {
updateNode(result);
}
}
});
return Promise.all(promises).then(() => null);
};
}
// Expands relative URLs against the given base url
// and deals with ".." in URLs
function rehypeExpandUrls(options) {
return (ast) => {
if (options.baseUrl) {
visit(ast, "element", (node) => {
if (node.tagName === "a" && node.properties) {
const url = node.properties.href;
if (
url &&
!isAbsoluteUrl(url) &&
!isInternalUrl(url) &&
!isPageAnchor(url)
) {
node.properties.href = urlAppend(options.baseUrl, url);
}
}
if (node.tagName === "img" && node.properties) {
const url = node.properties.src;
if (url && !isAbsoluteUrl(url) && !isInternalUrl(url)) {
node.properties.src = urlAppend(options.baseUrl, url);
}
}
});
}
// Browser normalizes URLs with ".." so we use a "__parent__"
// modifier instead and handle it on the server
visit(ast, "element", (node) => {
if (node.tagName === "a" && node.properties && node.properties.href) {
node.properties.href = node.properties.href
.split("/")
.map((part) => (part === ".." ? "__parent__" : part))
.join("/");
}
});
};
}
const parseHtml = unified().use(rehypeParse, { fragment: true });
function remarkPrepareMermaid(options) {
return (ast) => {
visit(ast, "code", (node, index, parent) => {
if (node.lang === "mermaid") {
node.type = "html";
node.value = `