@ai-gui/plugin-mermaid 0.6.0 → 0.6.2

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/dist/index.cjs CHANGED
@@ -1,6 +1,21 @@
1
1
  "use strict";
2
2
 
3
3
  //#region src/index.ts
4
+ /** The themes Mermaid ships with. Anything else it is handed is not a theme it can find. */
5
+ const MERMAID_THEMES = new Set([
6
+ "default",
7
+ "base",
8
+ "dark",
9
+ "forest",
10
+ "neutral",
11
+ "neo",
12
+ "neo-dark",
13
+ "redux",
14
+ "redux-dark",
15
+ "redux-color",
16
+ "redux-dark-color",
17
+ "null"
18
+ ]);
4
19
  let nextId = 0;
5
20
  let mermaidPromise = null;
6
21
  let initializedTheme;
@@ -14,6 +29,18 @@ function enqueue(work) {
14
29
  function escapeHtml(s) {
15
30
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
16
31
  }
32
+ /**
33
+ * Remove the container Mermaid rendered into.
34
+ *
35
+ * Mermaid appends a host element id'd `d<id>` to the document and removes it itself on success. A
36
+ * parse error aborts before that, leaving its own error graphic in the page — outside the renderer,
37
+ * so nothing that owns the answer can clean it up.
38
+ */
39
+ function discardMermaidHost(id) {
40
+ if (typeof document === "undefined") return;
41
+ document.getElementById(`d${id}`)?.remove();
42
+ document.getElementById(id)?.remove();
43
+ }
17
44
  function errorHtml() {
18
45
  return {
19
46
  kind: "html",
@@ -33,7 +60,8 @@ function mermaid(opts = {}) {
33
60
  if (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0) throw new TypeError("maxSourceBytes must be a positive safe integer");
34
61
  const outputs = new WeakMap();
35
62
  const render = (node, context) => {
36
- const wanted = context?.theme ?? theme;
63
+ const scheme = context?.theme;
64
+ const wanted = scheme === "dark" ? "dark" : scheme && MERMAID_THEMES.has(scheme) ? scheme : theme;
37
65
  const cached = outputs.get(node);
38
66
  if (cached && cached.theme === wanted) return cached.output;
39
67
  const output = enqueue(async () => {
@@ -49,12 +77,16 @@ function mermaid(opts = {}) {
49
77
  initializedTheme = wanted;
50
78
  }
51
79
  const id = `aigui-mermaid-${nextId++}`;
52
- const { svg } = await m.render(id, node.content ?? "");
53
- return {
54
- kind: "html",
55
- html: svg,
56
- trusted: true
57
- };
80
+ try {
81
+ const { svg } = await m.render(id, node.content ?? "");
82
+ return {
83
+ kind: "html",
84
+ html: svg,
85
+ trusted: true
86
+ };
87
+ } finally {
88
+ discardMermaidHost(id);
89
+ }
58
90
  } catch {
59
91
  return errorHtml();
60
92
  }
package/dist/index.js CHANGED
@@ -1,4 +1,19 @@
1
1
  //#region src/index.ts
2
+ /** The themes Mermaid ships with. Anything else it is handed is not a theme it can find. */
3
+ const MERMAID_THEMES = new Set([
4
+ "default",
5
+ "base",
6
+ "dark",
7
+ "forest",
8
+ "neutral",
9
+ "neo",
10
+ "neo-dark",
11
+ "redux",
12
+ "redux-dark",
13
+ "redux-color",
14
+ "redux-dark-color",
15
+ "null"
16
+ ]);
2
17
  let nextId = 0;
3
18
  let mermaidPromise = null;
4
19
  let initializedTheme;
@@ -12,6 +27,18 @@ function enqueue(work) {
12
27
  function escapeHtml(s) {
13
28
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
14
29
  }
30
+ /**
31
+ * Remove the container Mermaid rendered into.
32
+ *
33
+ * Mermaid appends a host element id'd `d<id>` to the document and removes it itself on success. A
34
+ * parse error aborts before that, leaving its own error graphic in the page — outside the renderer,
35
+ * so nothing that owns the answer can clean it up.
36
+ */
37
+ function discardMermaidHost(id) {
38
+ if (typeof document === "undefined") return;
39
+ document.getElementById(`d${id}`)?.remove();
40
+ document.getElementById(id)?.remove();
41
+ }
15
42
  function errorHtml() {
16
43
  return {
17
44
  kind: "html",
@@ -31,7 +58,8 @@ function mermaid(opts = {}) {
31
58
  if (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0) throw new TypeError("maxSourceBytes must be a positive safe integer");
32
59
  const outputs = new WeakMap();
33
60
  const render = (node, context) => {
34
- const wanted = context?.theme ?? theme;
61
+ const scheme = context?.theme;
62
+ const wanted = scheme === "dark" ? "dark" : scheme && MERMAID_THEMES.has(scheme) ? scheme : theme;
35
63
  const cached = outputs.get(node);
36
64
  if (cached && cached.theme === wanted) return cached.output;
37
65
  const output = enqueue(async () => {
@@ -47,12 +75,16 @@ function mermaid(opts = {}) {
47
75
  initializedTheme = wanted;
48
76
  }
49
77
  const id = `aigui-mermaid-${nextId++}`;
50
- const { svg } = await m.render(id, node.content ?? "");
51
- return {
52
- kind: "html",
53
- html: svg,
54
- trusted: true
55
- };
78
+ try {
79
+ const { svg } = await m.render(id, node.content ?? "");
80
+ return {
81
+ kind: "html",
82
+ html: svg,
83
+ trusted: true
84
+ };
85
+ } finally {
86
+ discardMermaidHost(id);
87
+ }
56
88
  } catch {
57
89
  return errorHtml();
58
90
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-gui/plugin-mermaid",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Mermaid diagram plugin for AIGUI.",
5
5
  "keywords": [
6
6
  "llm",
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "mermaid": "^11.4.0",
55
- "@ai-gui/core": "0.6.0"
55
+ "@ai-gui/core": "0.6.2"
56
56
  },
57
57
  "scripts": {
58
58
  "build": "tsdown",