@render-policy/mermaid 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 render-policy contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # @render-policy/mermaid
2
+
3
+ Strict Mermaid diagrams for [`@render-policy/core`](../core). Models emit ```mermaid blocks all
4
+ the time; rendering them is the one place where "sanitize the Markdown" is not enough, because
5
+ the diagram library itself produces markup from untrusted text.
6
+
7
+ ```ts
8
+ import { createRenderer } from '@render-policy/core';
9
+ import { createMermaidTransform } from '@render-policy/mermaid';
10
+ import mermaid from 'mermaid';
11
+
12
+ const renderer = createRenderer({
13
+ transforms: [createMermaidTransform({ mermaid, config: { theme: 'neutral' } })],
14
+ });
15
+ renderer.renderMarkdownInto(element, message.content);
16
+ ```
17
+
18
+ What the transform guarantees, whatever the diagram source says:
19
+
20
+ - mermaid runs with `securityLevel: 'strict'`, no HTML labels (so no `foreignObject`), no error
21
+ diagram injected into the page, nothing rendered on load; `config` cannot override these;
22
+ - the SVG mermaid produced goes through an SVG-only sanitizer: no `<a>`, `<script>`,
23
+ `<foreignObject>`, `<image>`, `<use>` or animations, no `href`, no `data-*`, no stylesheet or
24
+ inline style that imports, fetches an external `url()` or targets `:host`; the root `<svg>`
25
+ gets a fixed style;
26
+ - the result lives in a shadow root inside a `contain: paint` wrapper: the diagram's stylesheet
27
+ cannot reach the host page, the host page's CSS does not break the diagram, and nothing inside
28
+ can overlay the page;
29
+ - the original code block stays as the wrapper's light DOM, so streaming keeps a finished
30
+ diagram in place, and a block whose fence is still open is left as code until it closes;
31
+ - a diagram that fails to parse stays a code block, and the failure is journaled through
32
+ `onDecision`, with codes `diagram-render-failed`, `diagram-element-not-allowed`,
33
+ `diagram-attribute-not-allowed`, `diagram-style-escapes` and `diagram-root-not-svg`.
34
+
35
+ Renders are cached by source (`cacheSize`, default 50). Diagram languages other than
36
+ `mermaid` can be mapped with `languages`.
37
+
38
+ Bring your own mermaid (peer dependency, 11 or later) and load it lazily if bundle size
39
+ matters; the transform only needs `initialize` and `render`. The browser proof in
40
+ `e2e/run.mjs` runs the real mermaid in Chromium against click handlers, label injection,
41
+ `themeCSS` directives, positioning through `classDef`, invalid input and streaming.
42
+
43
+ Works with mermaid 11 and 12. Mermaid 12 lays diagrams out with ELK by default and recolours
44
+ them; pass `config: { layout: 'dagre', theme: 'default', look: 'classic' }` to keep the mermaid 11
45
+ look. The strict settings win over `config` either way.
@@ -0,0 +1,54 @@
1
+ import { type FragmentTransform, type RenderDecision, type RenderWindow } from '@render-policy/core';
2
+ /** The part of the mermaid API this package uses. Pass the real `mermaid` default export. */
3
+ export interface MermaidLike {
4
+ initialize(config: Record<string, unknown>): void;
5
+ render(id: string, text: string): Promise<{
6
+ readonly svg: string;
7
+ }>;
8
+ }
9
+ export interface MermaidTransformOptions {
10
+ /** The mermaid module (`import mermaid from 'mermaid'`). Loaded lazily by you, not by this package. */
11
+ readonly mermaid: MermaidLike;
12
+ /** The window to sanitize with. Defaults to the global window. */
13
+ readonly window?: RenderWindow;
14
+ /** Extra mermaid configuration (theme, fonts). The strict settings below always win. */
15
+ readonly config?: Record<string, unknown>;
16
+ /** Code block languages rendered as diagrams. Default ['mermaid']. */
17
+ readonly languages?: readonly string[];
18
+ /** Receives a decision for every diagram that failed to render or lost content to sanitization. */
19
+ readonly onDecision?: (decision: RenderDecision) => void;
20
+ /** Upper bound of the source -> SVG cache. Default 50. */
21
+ readonly cacheSize?: number;
22
+ }
23
+ /**
24
+ * Settings the diagram source cannot change: no HTML labels (so no foreignObject), no click
25
+ * handlers or links, no error diagram injected into the page, nothing rendered on load.
26
+ */
27
+ export declare const STRICT_MERMAID_CONFIG: Readonly<Record<string, unknown>>;
28
+ /** Class names of the wrapper and the shadow host, for styling. */
29
+ export declare const DIAGRAM_CLASS = "rp-diagram";
30
+ export declare const DIAGRAM_HOST_CLASS = "rp-diagram-host";
31
+ export interface DiagramSanitizeResult {
32
+ readonly fragment: DocumentFragment;
33
+ readonly decisions: readonly RenderDecision[];
34
+ }
35
+ /**
36
+ * Sanitize an SVG string produced by mermaid into a fragment that can only draw.
37
+ * Exported for tests and for hosts that render diagrams themselves.
38
+ */
39
+ export declare function createDiagramSanitizer(win: RenderWindow): (svg: string) => DiagramSanitizeResult;
40
+ /**
41
+ * A fragment transform for createRenderer({ transforms }) that turns
42
+ * ```mermaid code blocks into diagrams:
43
+ *
44
+ * - mermaid runs in `securityLevel: 'strict'` without HTML labels, whatever `config` says;
45
+ * - the SVG goes through an SVG-only sanitizer: no links, scripts, foreignObject, images,
46
+ * external references or animations, no stylesheet that imports, fetches or escapes;
47
+ * - the result lives in a shadow root inside a `contain: paint` wrapper, so the diagram's
48
+ * own styles cannot reach the host page and the host page's styles do not break the diagram;
49
+ * - the wrapper keeps the original code block as light DOM: streaming keeps a finished diagram
50
+ * in place, and a block whose fence is still open is left as code until it closes;
51
+ * - a diagram that fails to parse stays a code block; nothing is injected into <body>.
52
+ */
53
+ export declare function createMermaidTransform(options: MermaidTransformOptions): FragmentTransform;
54
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAiB,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEpH,6FAA6F;AAC7F,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAClD,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrE;AAED,MAAM,WAAW,uBAAuB;IACtC,uGAAuG;IACvG,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAC9B,kEAAkE;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,wFAAwF;IACxF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1C,sEAAsE;IACtE,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,mGAAmG;IACnG,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,CAAC;IACzD,0DAA0D;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASlE,CAAC;AAEH,mEAAmE;AACnE,eAAO,MAAM,aAAa,eAAe,CAAC;AAC1C,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AA2BpD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;CAC/C;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,YAAY,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,qBAAqB,CAwChG;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,uBAAuB,GAAG,iBAAiB,CA2E1F"}
package/dist/index.js ADDED
@@ -0,0 +1,196 @@
1
+ import createDOMPurify, {} from 'dompurify';
2
+ import { resolveWindow } from '@render-policy/core';
3
+ /**
4
+ * Settings the diagram source cannot change: no HTML labels (so no foreignObject), no click
5
+ * handlers or links, no error diagram injected into the page, nothing rendered on load.
6
+ */
7
+ export const STRICT_MERMAID_CONFIG = Object.freeze({
8
+ startOnLoad: false,
9
+ securityLevel: 'strict',
10
+ htmlLabels: false,
11
+ flowchart: Object.freeze({ htmlLabels: false }),
12
+ class: Object.freeze({ htmlLabels: false }),
13
+ state: Object.freeze({ htmlLabels: false }),
14
+ er: Object.freeze({ htmlLabels: false }),
15
+ suppressErrorRendering: true,
16
+ });
17
+ /** Class names of the wrapper and the shadow host, for styling. */
18
+ export const DIAGRAM_CLASS = 'rp-diagram';
19
+ export const DIAGRAM_HOST_CLASS = 'rp-diagram-host';
20
+ const SVG_CONFIG = {
21
+ USE_PROFILES: { svg: true, svgFilters: true },
22
+ ADD_TAGS: ['style'],
23
+ ADD_ATTR: ['role'], // accessibility: mermaid marks the root as a graphics document
24
+ // Links, embedded documents, external references and animations have no place in a diagram
25
+ // produced from untrusted text.
26
+ FORBID_TAGS: ['foreignObject', 'script', 'a', 'image', 'use', 'set', 'animate', 'animateMotion', 'animateTransform', 'feImage'],
27
+ FORBID_ATTR: ['href', 'xlink:href', 'ping', 'formaction'],
28
+ ALLOW_DATA_ATTR: false,
29
+ ALLOW_UNKNOWN_PROTOCOLS: false,
30
+ KEEP_CONTENT: false,
31
+ RETURN_DOM_FRAGMENT: true,
32
+ };
33
+ /** `url(#marker)` is a reference into the SVG itself; anything else in CSS is a fetch. */
34
+ const EXTERNAL_URL_RE = /url\((?!\s*['"]?#)/i;
35
+ /**
36
+ * CSS that could reach outside the diagram: imports and legacy script hooks, and `:host`,
37
+ * the one selector a shadow tree can aim at its host. Positioning is not on the list: SVG
38
+ * graphics ignore it, the root <svg> gets a fixed style below, and the wrapper's
39
+ * `contain: paint` confines whatever is left.
40
+ */
41
+ const DANGEROUS_CSS_RE = /@import|expression\(|:host|behavior\s*:|-moz-binding/i;
42
+ const ROOT_SVG_STYLE = 'display:block;max-width:100%;height:auto';
43
+ /**
44
+ * Sanitize an SVG string produced by mermaid into a fragment that can only draw.
45
+ * Exported for tests and for hosts that render diagrams themselves.
46
+ */
47
+ export function createDiagramSanitizer(win) {
48
+ const purify = createDOMPurify(win);
49
+ return (svg) => {
50
+ const decisions = [];
51
+ const fragment = purify.sanitize(svg, { ...SVG_CONFIG, RETURN_DOM_FRAGMENT: true });
52
+ // DOMPurify resets `removed` on every sanitize() call, so this is exactly this call's list.
53
+ for (const removed of purify.removed) {
54
+ if ('element' in removed && removed.element) {
55
+ const tag = (removed.element.nodeName ?? '').toLowerCase();
56
+ if (tag === 'body' || tag === 'html' || tag === 'head')
57
+ continue; // parser scaffolding, not content
58
+ decisions.push({ kind: 'blocked', subject: 'element', code: 'diagram-element-not-allowed', reason: 'element is not allowed in a diagram', tag });
59
+ }
60
+ else if ('attribute' in removed && removed.attribute) {
61
+ decisions.push({ kind: 'blocked', subject: 'attribute', code: 'diagram-attribute-not-allowed', reason: 'attribute is not allowed in a diagram', tag: (removed.from?.nodeName ?? '').toLowerCase(), attribute: removed.attribute.name, value: removed.attribute.value });
62
+ }
63
+ }
64
+ for (const style of Array.from(fragment.querySelectorAll('style'))) {
65
+ const css = style.textContent ?? '';
66
+ if (EXTERNAL_URL_RE.test(css) || DANGEROUS_CSS_RE.test(css)) {
67
+ style.remove();
68
+ decisions.push({ kind: 'blocked', subject: 'element', code: 'diagram-style-escapes', reason: 'diagram stylesheet references external resources or escapes the diagram', tag: 'style' });
69
+ }
70
+ }
71
+ for (const element of Array.from(fragment.querySelectorAll('[style]'))) {
72
+ const css = element.getAttribute('style') ?? '';
73
+ if (EXTERNAL_URL_RE.test(css) || DANGEROUS_CSS_RE.test(css)) {
74
+ element.removeAttribute('style');
75
+ decisions.push({ kind: 'blocked', subject: 'attribute', code: 'diagram-style-escapes', reason: 'inline style references external resources or escapes the diagram', tag: element.nodeName.toLowerCase(), attribute: 'style', value: css });
76
+ }
77
+ }
78
+ for (const root of Array.from(fragment.children)) {
79
+ if (root.nodeName.toLowerCase() === 'svg') {
80
+ root.setAttribute('style', ROOT_SVG_STYLE);
81
+ }
82
+ else {
83
+ root.remove();
84
+ decisions.push({ kind: 'blocked', subject: 'element', code: 'diagram-root-not-svg', reason: 'only an <svg> root is allowed in a diagram', tag: root.nodeName.toLowerCase() });
85
+ }
86
+ }
87
+ return { fragment, decisions };
88
+ };
89
+ }
90
+ /**
91
+ * A fragment transform for createRenderer({ transforms }) that turns
92
+ * ```mermaid code blocks into diagrams:
93
+ *
94
+ * - mermaid runs in `securityLevel: 'strict'` without HTML labels, whatever `config` says;
95
+ * - the SVG goes through an SVG-only sanitizer: no links, scripts, foreignObject, images,
96
+ * external references or animations, no stylesheet that imports, fetches or escapes;
97
+ * - the result lives in a shadow root inside a `contain: paint` wrapper, so the diagram's
98
+ * own styles cannot reach the host page and the host page's styles do not break the diagram;
99
+ * - the wrapper keeps the original code block as light DOM: streaming keeps a finished diagram
100
+ * in place, and a block whose fence is still open is left as code until it closes;
101
+ * - a diagram that fails to parse stays a code block; nothing is injected into <body>.
102
+ */
103
+ export function createMermaidTransform(options) {
104
+ const win = resolveWindow(options.window, '@render-policy/mermaid');
105
+ const sanitize = createDiagramSanitizer(win);
106
+ const languages = new Set(options.languages ?? ['mermaid']);
107
+ const cacheSize = options.cacheSize ?? 50;
108
+ const cache = new Map();
109
+ let initialized = false;
110
+ let counter = 0;
111
+ const emit = (decisions) => {
112
+ if (!options.onDecision)
113
+ return;
114
+ for (const decision of decisions)
115
+ options.onDecision(decision);
116
+ };
117
+ const ensureInitialized = () => {
118
+ if (initialized)
119
+ return;
120
+ options.mermaid.initialize({ ...(options.config ?? {}), ...STRICT_MERMAID_CONFIG });
121
+ initialized = true;
122
+ };
123
+ const renderSource = (source) => {
124
+ const cached = cache.get(source);
125
+ if (cached)
126
+ return cached;
127
+ counter += 1;
128
+ const promise = (async () => {
129
+ ensureInitialized();
130
+ let svg;
131
+ try {
132
+ svg = (await options.mermaid.render(`rp-mermaid-${counter}`, source)).svg;
133
+ }
134
+ catch (error) {
135
+ emit([{ kind: 'blocked', subject: 'markdown', code: 'diagram-render-failed', reason: `Mermaid could not render the diagram: ${error instanceof Error ? error.message.split('\n')[0] : String(error)}` }]);
136
+ return null;
137
+ }
138
+ const result = sanitize(svg);
139
+ emit(result.decisions);
140
+ return result;
141
+ })();
142
+ if (cache.size >= cacheSize) {
143
+ const oldest = cache.keys().next().value;
144
+ if (oldest !== undefined)
145
+ cache.delete(oldest);
146
+ }
147
+ cache.set(source, promise);
148
+ return promise;
149
+ };
150
+ return (fragment, context) => {
151
+ const blocks = Array.from(fragment.querySelectorAll('pre > code')).filter((code) => languages.has(languageOf(code)));
152
+ if (blocks.length === 0)
153
+ return;
154
+ const allPre = fragment.querySelectorAll('pre');
155
+ const lastPre = allPre[allPre.length - 1] ?? null;
156
+ const doc = context.document;
157
+ for (const code of blocks) {
158
+ const pre = code.parentElement;
159
+ if (!pre)
160
+ continue;
161
+ if (context.openFenceAtEnd && pre === lastPre)
162
+ continue; // still being typed
163
+ const source = code.textContent ?? '';
164
+ const wrapper = doc.createElement('div');
165
+ wrapper.className = DIAGRAM_CLASS;
166
+ wrapper.setAttribute('style', 'display:block;contain:paint');
167
+ const host = doc.createElement('div');
168
+ host.className = DIAGRAM_HOST_CLASS;
169
+ pre.replaceWith(wrapper);
170
+ wrapper.append(host);
171
+ host.append(pre); // light DOM: the source, hidden by the shadow root, compared by patchChildren
172
+ const shadow = host.attachShadow({ mode: 'open' });
173
+ shadow.append(fallback(doc, source));
174
+ void renderSource(source).then((result) => {
175
+ if (!result)
176
+ return;
177
+ shadow.replaceChildren(result.fragment.cloneNode(true));
178
+ });
179
+ }
180
+ };
181
+ }
182
+ function languageOf(code) {
183
+ for (const token of (code.getAttribute('class') ?? '').split(/\s+/)) {
184
+ if (token.startsWith('language-'))
185
+ return token.slice('language-'.length);
186
+ }
187
+ return '';
188
+ }
189
+ function fallback(doc, source) {
190
+ const pre = doc.createElement('pre');
191
+ const code = doc.createElement('code');
192
+ code.textContent = source;
193
+ pre.append(code);
194
+ return pre;
195
+ }
196
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,EAAE,EAAe,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,aAAa,EAAkE,MAAM,qBAAqB,CAAC;AAuBpH;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAsC,MAAM,CAAC,MAAM,CAAC;IACpF,WAAW,EAAE,KAAK;IAClB,aAAa,EAAE,QAAQ;IACvB,UAAU,EAAE,KAAK;IACjB,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IAC/C,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IAC3C,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IAC3C,EAAE,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACxC,sBAAsB,EAAE,IAAI;CAC7B,CAAC,CAAC;AAEH,mEAAmE;AACnE,MAAM,CAAC,MAAM,aAAa,GAAG,YAAY,CAAC;AAC1C,MAAM,CAAC,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAEpD,MAAM,UAAU,GAAW;IACzB,YAAY,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;IAC7C,QAAQ,EAAE,CAAC,OAAO,CAAC;IACnB,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,+DAA+D;IACnF,2FAA2F;IAC3F,gCAAgC;IAChC,WAAW,EAAE,CAAC,eAAe,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,eAAe,EAAE,kBAAkB,EAAE,SAAS,CAAC;IAC/H,WAAW,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,CAAC;IACzD,eAAe,EAAE,KAAK;IACtB,uBAAuB,EAAE,KAAK;IAC9B,YAAY,EAAE,KAAK;IACnB,mBAAmB,EAAE,IAAI;CAC1B,CAAC;AAEF,0FAA0F;AAC1F,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAC9C;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,uDAAuD,CAAC;AACjF,MAAM,cAAc,GAAG,0CAA0C,CAAC;AAOlE;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAiB;IACtD,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO,CAAC,GAAG,EAAE,EAAE;QACb,MAAM,SAAS,GAAqB,EAAE,CAAC;QACvC,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,GAAG,UAAU,EAAE,mBAAmB,EAAE,IAAI,EAAE,CAAC,CAAC;QACpF,4FAA4F;QAC5F,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACrC,IAAI,SAAS,IAAI,OAAO,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;gBAC5C,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;gBAC3D,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,MAAM;oBAAE,SAAS,CAAC,kCAAkC;gBACpG,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,6BAA6B,EAAE,MAAM,EAAE,qCAAqC,EAAE,GAAG,EAAE,CAAC,CAAC;YACnJ,CAAC;iBAAM,IAAI,WAAW,IAAI,OAAO,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;gBACvD,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,+BAA+B,EAAE,MAAM,EAAE,uCAAuC,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;YAC1Q,CAAC;QACH,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YACnE,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC;YACpC,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5D,KAAK,CAAC,MAAM,EAAE,CAAC;gBACf,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,uBAAuB,EAAE,MAAM,EAAE,yEAAyE,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;YAC1L,CAAC;QACH,CAAC;QACD,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;YACvE,MAAM,GAAG,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAChD,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC5D,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;gBACjC,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,uBAAuB,EAAE,MAAM,EAAE,mEAAmE,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;YAC7O,CAAC;QACH,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;YACjD,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,KAAK,KAAK,EAAE,CAAC;gBAC1C,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;YAC7C,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,MAAM,EAAE,CAAC;gBACd,SAAS,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,sBAAsB,EAAE,MAAM,EAAE,4CAA4C,EAAE,GAAG,EAAE,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;YAChL,CAAC;QACH,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IACjC,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAgC;IACrE,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,sBAAsB,CAAC,GAAG,CAAC,CAAC;IAC7C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC;IAC5D,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAiD,CAAC;IACvE,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,MAAM,IAAI,GAAG,CAAC,SAAoC,EAAQ,EAAE;QAC1D,IAAI,CAAC,OAAO,CAAC,UAAU;YAAE,OAAO;QAChC,KAAK,MAAM,QAAQ,IAAI,SAAS;YAAE,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IACjE,CAAC,CAAC;IAEF,MAAM,iBAAiB,GAAG,GAAS,EAAE;QACnC,IAAI,WAAW;YAAE,OAAO;QACxB,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,GAAG,qBAAqB,EAAE,CAAC,CAAC;QACpF,WAAW,GAAG,IAAI,CAAC;IACrB,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,CAAC,MAAc,EAAyC,EAAE;QAC7E,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjC,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;QAC1B,OAAO,IAAI,CAAC,CAAC;QACb,MAAM,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE;YAC1B,iBAAiB,EAAE,CAAC;YACpB,IAAI,GAAW,CAAC;YAChB,IAAI,CAAC;gBACH,GAAG,GAAG,CAAC,MAAM,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,cAAc,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC;YAC5E,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,uBAAuB,EAAE,MAAM,EAAE,yCAAyC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;gBAC1M,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC7B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YACvB,OAAO,MAAM,CAAC;QAChB,CAAC,CAAC,EAAE,CAAC;QACL,IAAI,KAAK,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC;YAC5B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YACzC,IAAI,MAAM,KAAK,SAAS;gBAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACjD,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC3B,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;IAEF,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE;QAC3B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAChC,MAAM,MAAM,GAAG,QAAQ,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC;QAClD,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC;QAE7B,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC;YAC/B,IAAI,CAAC,GAAG;gBAAE,SAAS;YACnB,IAAI,OAAO,CAAC,cAAc,IAAI,GAAG,KAAK,OAAO;gBAAE,SAAS,CAAC,oBAAoB;YAE7E,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC;YACtC,MAAM,OAAO,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YACzC,OAAO,CAAC,SAAS,GAAG,aAAa,CAAC;YAClC,OAAO,CAAC,YAAY,CAAC,OAAO,EAAE,6BAA6B,CAAC,CAAC;YAC7D,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YACtC,IAAI,CAAC,SAAS,GAAG,kBAAkB,CAAC;YACpC,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;YACzB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YACrB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,8EAA8E;YAChG,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;YACnD,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;YAErC,KAAK,YAAY,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE;gBACxC,IAAI,CAAC,MAAM;oBAAE,OAAO;gBACpB,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAC1D,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,IAAa;IAC/B,KAAK,MAAM,KAAK,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACpE,IAAI,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC;YAAE,OAAO,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAS,QAAQ,CAAC,GAAa,EAAE,MAAc;IAC7C,MAAM,GAAG,GAAG,GAAG,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC;IAC1B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACjB,OAAO,GAAG,CAAC;AACb,CAAC"}
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@render-policy/mermaid",
3
+ "version": "0.1.0",
4
+ "description": "Strict Mermaid diagrams for @render-policy/core: rendered in securityLevel strict without HTML labels, sanitized as SVG, isolated in a shadow root.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "sideEffects": false,
21
+ "scripts": {
22
+ "build": "tsc -p tsconfig.build.json",
23
+ "typecheck": "tsc -p tsconfig.json --noEmit",
24
+ "test": "vitest run"
25
+ },
26
+ "peerDependencies": {
27
+ "@render-policy/core": "^0.1.0",
28
+ "mermaid": ">=11.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@render-policy/core": "^0.1.0",
32
+ "mermaid": "^12.0.0"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "keywords": [
38
+ "mermaid",
39
+ "diagram",
40
+ "sanitize",
41
+ "xss",
42
+ "markdown",
43
+ "llm",
44
+ "agent",
45
+ "security"
46
+ ],
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git+https://github.com/shteynu/render-policy.git",
50
+ "directory": "packages/mermaid"
51
+ }
52
+ }