Skip to content

Commit

Permalink
handle xhtml void elements in mermaid diagrams (#2103)
Browse files Browse the repository at this point in the history
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
  • Loading branch information
bollwyvl and pre-commit-ci[bot] committed Feb 6, 2024
1 parent f840772 commit b953703
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1483,6 +1483,7 @@ raw template
{%- endblock in_prompt -%}
"""


exporter_attr = AttrExporter()
output_attr, _ = exporter_attr.from_notebook_node(nb)
assert "raw template" in output_attr
Expand Down
35 changes: 34 additions & 1 deletion share/templates/lab/mermaidjs.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ url="https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.7.0/mermaid.esm.min.mjs"
let results = null;
let output = null;
try {
const { svg } = await mermaid.render(id, raw, el);
let { svg } = await mermaid.render(id, raw, el);
svg = cleanMermaidSvg(svg);
results = makeMermaidImage(svg);
output = document.createElement("figure");
results.map(output.appendChild, output);
Expand All @@ -99,6 +100,38 @@ url="https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.7.0/mermaid.esm.min.mjs"
parent.appendChild(output);
}
/**
* Post-process to ensure mermaid diagrams contain only valid SVG and XHTML.
*/
function cleanMermaidSvg(svg) {
return svg.replace(RE_VOID_ELEMENT, replaceVoidElement);
}
/**
* A regular expression for all void elements, which may include attributes and
* a slash.
*
* @see https://developer.mozilla.org/en-US/docs/Glossary/Void_element
*
* Of these, only `<br>` is generated by Mermaid in place of `\n`,
* but _any_ "malformed" tag will break the SVG rendering entirely.
*/
const RE_VOID_ELEMENT =
/<\s*(area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)\s*([^>]*?)\s*>/gi;
/**
* Ensure a void element is closed with a slash, preserving any attributes.
*/
function replaceVoidElement(match, tag, rest) {
rest = rest.trim();
if (!rest.endsWith('/')) {
rest = `${rest} /`;
}
return `<${tag} ${rest}>`;
}
void Promise.all([...diagrams].map(renderOneMarmaid));
});
</script>
Expand Down

0 comments on commit b953703

Please sign in to comment.