diff --git a/assets/js/cell/markdown.js b/assets/js/cell/markdown.js
index 7e79008b4..80dbe4a69 100644
--- a/assets/js/cell/markdown.js
+++ b/assets/js/cell/markdown.js
@@ -17,6 +17,7 @@ import { removePosition } from "unist-util-remove-position";
import { highlight } from "./live_editor/monaco";
import { renderMermaid } from "./markdown/mermaid";
+import { escapeHtml } from "../lib/utils";
/**
* Renders markdown content in the given container.
@@ -163,7 +164,7 @@ function remarkPrepareMermaid(options) {
visit(ast, "code", (node, index, parent) => {
if (node.lang === "mermaid") {
node.type = "html";
- node.value = `
${node.value}
`;
+ node.value = `${escapeHtml(node.value)}
`;
}
});
};
diff --git a/assets/js/cell/markdown/mermaid.js b/assets/js/cell/markdown/mermaid.js
index 81f145b8f..4dd107d32 100644
--- a/assets/js/cell/markdown/mermaid.js
+++ b/assets/js/cell/markdown/mermaid.js
@@ -34,13 +34,13 @@ const maybeInjectFontAwesome = (value) => {
export function renderMermaid(value) {
return importMermaid().then((mermaid) => {
- try {
- // Inject font-awesome when fa: prefix is used
- maybeInjectFontAwesome(value);
+ // Inject font-awesome when fa: prefix is used
+ maybeInjectFontAwesome(value);
+ try {
return mermaid.render(getId(), value);
} catch (e) {
- return `${e.message}
`;
+ return `Mermaid\n${e.message}
`;
}
});
}
diff --git a/assets/js/lib/utils.js b/assets/js/lib/utils.js
index da9648696..dae2f6ae5 100644
--- a/assets/js/lib/utils.js
+++ b/assets/js/lib/utils.js
@@ -144,3 +144,18 @@ export function cancelEvent(event) {
// Stop event propagation (e.g. so it doesn't reach the editor).
event.stopPropagation();
}
+
+const htmlEscapes = {
+ "&": "&",
+ "<": "<",
+ ">": ">",
+ '"': """,
+ "'": "'",
+};
+
+/**
+ * Transforms the given string to a HTML-safe value.
+ */
+export function escapeHtml(string) {
+ return (string || "").replace(/[&<>"']/g, (char) => htmlEscapes[char]);
+}