Something went wrong. Try again.
Browser extension: detect and subscribe to standard.site publications on ATProto
Something went wrong. Try again.
3.3 kB · 80 lines
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081// The sanitizer is the whole reason the diagram can be inlined at all: the// site's CSP has no 'unsafe-inline' and a bare `style-src 'self'`, so anything// Mermaid emits as CSS is dead on arrival in production and would take the// picture with it. These cover the shapes Mermaid actually produces.
import assert from "node:assert/strict";import { readFileSync } from "node:fs";import { join } from "node:path";import { fileURLToPath } from "node:url";import { describe, it } from "node:test";
import { sanitize } from "./render-diagram.mjs";
const webRoot = join(fileURLToPath(import.meta.url), "../..");const svgPath = join(webRoot, "src/diagrams/architecture.svg");
const wrap = (inner, attrs = 'viewBox="0 0 10 10"') => `<svg ${attrs}>${inner}</svg>`;
describe("sanitize", () => { it("drops the stylesheet Mermaid inlines", () => { const out = sanitize(wrap("<style>#a{fill:#000}</style><rect/>"), "t"); assert.ok(!out.includes("<style")); assert.ok(out.includes("<rect/>")); });
it("drops style attributes but keeps font-style and other presentation attributes", () => { const out = sanitize( wrap('<text style="fill:#333" font-style="normal" fill="red">x</text>'), "t", ); assert.ok(!/(^|[\s"'])style\s*=/.test(out)); assert.ok(out.includes('font-style="normal"')); assert.ok(out.includes('fill="red"')); });
it("drops the fixed pixel size so CSS can scale the figure", () => { const out = sanitize(wrap("<rect/>", 'width="900" height="500" viewBox="0 0 900 500"'), "t"); assert.ok(!/<svg[^>]*\swidth=/.test(out)); assert.ok(!/<svg[^>]*\sheight=/.test(out)); assert.ok(out.includes('viewBox="0 0 900 500"')); });
it("refuses an SVG with no viewBox, which would have nothing to scale by", () => { assert.throws(() => sanitize('<svg width="10"><rect/></svg>', "t"), /viewBox/); });
it("refuses a script, whatever a future Mermaid decides to emit", () => { assert.throws(() => sanitize(wrap("<script>alert(1)</script>"), "t"), /script/); });});
describe("the committed architecture.svg", () => { const svg = readFileSync(svgPath, "utf8");
it("carries nothing the site CSP would drop", () => { assert.ok(!/<style[\s>]/i.test(svg)); assert.ok(!/(^|[\s"'])style\s*=/i.test(svg)); assert.ok(!/<script/i.test(svg)); });
it("scales from a viewBox rather than a fixed width", () => { assert.match(svg, /<svg[^>]*\sviewBox="/); assert.ok(!/<svg[^>]*\swidth=/.test(svg)); });
// `outsideNode` is deliberately not in this list. It used to give the // services outside the browser a dashed border, but the diagram now draws // that boundary with subgraphs instead and applies no such class. The rule // survives in global.css so re-adding `class … outsideNode` to the source // starts working again without a second change. it("keeps the class hooks global.css styles it through", () => { for (const cls of ["node", "cluster", "flowchart-link", "arrowMarkerPath"]) { assert.ok(svg.includes(cls), `architecture.svg has no ${cls} to style`); } });
it("has the ids a stable render produces, so rebuilds do not churn", () => { assert.ok(svg.includes('id="diagram-architecture"')); });});