@ai-gui/plugin-mermaid 0.3.0 → 0.4.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/README.md +21 -2
- package/dist/index.cjs +43 -23
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +42 -23
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -17,16 +17,35 @@ import { AIRenderer } from "@ai-gui/react"
|
|
|
17
17
|
<AIRenderer plugins={[mermaid({ theme: "default" })]} />
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
The model
|
|
20
|
+
The model can emit flowcharts, UML-style class/sequence/state diagrams, ER diagrams, journeys, Gantt charts, mind maps, timelines, Git graphs, and other Mermaid-supported diagram types.
|
|
21
|
+
|
|
22
|
+
Flowchart:
|
|
21
23
|
|
|
22
24
|
```mermaid
|
|
23
25
|
graph TD; A-->B; A-->C;
|
|
24
26
|
```
|
|
25
27
|
|
|
28
|
+
UML class diagram:
|
|
29
|
+
|
|
30
|
+
```mermaid
|
|
31
|
+
classDiagram
|
|
32
|
+
class Renderer { +push(chunk) +reset() }
|
|
33
|
+
Renderer --> AST : produces
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Sequence diagram:
|
|
37
|
+
|
|
38
|
+
```mermaid
|
|
39
|
+
sequenceDiagram
|
|
40
|
+
LLM->>AIGUI: streamed tokens
|
|
41
|
+
AIGUI-->>App: AST patches
|
|
42
|
+
```
|
|
43
|
+
|
|
26
44
|
## Options
|
|
27
45
|
|
|
28
46
|
- `theme?: string` — Mermaid theme. Mermaid has process-global configuration, so the theme of the first render wins across plugin instances; later instances share that initialization.
|
|
47
|
+
- `maxSourceBytes?: number` — maximum UTF-8 source size, default 64 KiB.
|
|
29
48
|
|
|
30
|
-
Renders are queued across instances because Mermaid mutates global state while rendering.
|
|
49
|
+
Renders use Mermaid `securityLevel: "strict"`, are complete-gated, and are queued across instances because Mermaid mutates global state while rendering. Errors use a generic non-reflective fallback and diagram IDs remain unique across concurrent renders.
|
|
31
50
|
|
|
32
51
|
See the [root README](../../README.md) for the full plugin list.
|
package/dist/index.cjs
CHANGED
|
@@ -14,39 +14,59 @@ function enqueue(work) {
|
|
|
14
14
|
function escapeHtml(s) {
|
|
15
15
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
16
16
|
}
|
|
17
|
-
function errorHtml(
|
|
17
|
+
function errorHtml() {
|
|
18
18
|
return {
|
|
19
19
|
kind: "html",
|
|
20
|
-
html: `<pre data-aigui-mermaid-error>${escapeHtml(
|
|
20
|
+
html: `<pre data-aigui-mermaid-error>${escapeHtml("Diagram could not be rendered.")}</pre>`
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
+
function mermaidPromptSpec() {
|
|
24
|
+
return [
|
|
25
|
+
"Diagrams (fenced): ```mermaid <Mermaid diagram syntax>```.",
|
|
26
|
+
"Supported examples include flowchart, sequenceDiagram, classDiagram (UML), stateDiagram-v2, erDiagram, journey, gantt, pie, mindmap, timeline, and gitGraph.",
|
|
27
|
+
"Use concise labels and valid Mermaid syntax. Never emit HTML, scripts, click handlers, URLs, initialization directives, remote resources, or credentials."
|
|
28
|
+
].join("\n");
|
|
29
|
+
}
|
|
23
30
|
function mermaid(opts = {}) {
|
|
24
31
|
const theme = opts.theme ?? "default";
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
const maxSourceBytes = opts.maxSourceBytes ?? 64 * 1024;
|
|
33
|
+
if (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0) throw new TypeError("maxSourceBytes must be a positive safe integer");
|
|
34
|
+
const outputs = new WeakMap();
|
|
35
|
+
const render = (node) => {
|
|
36
|
+
const cached = outputs.get(node);
|
|
37
|
+
if (cached) return cached;
|
|
38
|
+
const output = enqueue(async () => {
|
|
39
|
+
try {
|
|
40
|
+
if (new TextEncoder().encode(node.content ?? "").byteLength > maxSourceBytes) return errorHtml();
|
|
41
|
+
const m = await loadMermaid();
|
|
42
|
+
if (initializedTheme === void 0) {
|
|
43
|
+
m.initialize({
|
|
44
|
+
startOnLoad: false,
|
|
45
|
+
theme,
|
|
46
|
+
securityLevel: "strict"
|
|
47
|
+
});
|
|
48
|
+
initializedTheme = theme;
|
|
49
|
+
}
|
|
50
|
+
const id = `aigui-mermaid-${nextId++}`;
|
|
51
|
+
const { svg } = await m.render(id, node.content ?? "");
|
|
52
|
+
return {
|
|
53
|
+
kind: "html",
|
|
54
|
+
html: svg
|
|
55
|
+
};
|
|
56
|
+
} catch {
|
|
57
|
+
return errorHtml();
|
|
34
58
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
html: svg
|
|
40
|
-
};
|
|
41
|
-
} catch (e) {
|
|
42
|
-
return errorHtml(String(e?.message ?? e));
|
|
43
|
-
}
|
|
44
|
-
});
|
|
59
|
+
});
|
|
60
|
+
outputs.set(node, output);
|
|
61
|
+
return output;
|
|
62
|
+
};
|
|
45
63
|
return {
|
|
46
64
|
name: "mermaid",
|
|
47
|
-
nodeRenderers: { mermaid: render }
|
|
65
|
+
nodeRenderers: { mermaid: render },
|
|
66
|
+
promptSpec: mermaidPromptSpec()
|
|
48
67
|
};
|
|
49
68
|
}
|
|
50
69
|
|
|
51
70
|
//#endregion
|
|
52
|
-
exports.mermaid = mermaid
|
|
71
|
+
exports.mermaid = mermaid
|
|
72
|
+
exports.mermaidPromptSpec = mermaidPromptSpec
|
package/dist/index.d.cts
CHANGED
|
@@ -3,8 +3,10 @@ import { AIGuiPlugin } from "@ai-gui/core";
|
|
|
3
3
|
//#region src/index.d.ts
|
|
4
4
|
interface MermaidOptions {
|
|
5
5
|
theme?: string;
|
|
6
|
+
maxSourceBytes?: number;
|
|
6
7
|
}
|
|
8
|
+
declare function mermaidPromptSpec(): string;
|
|
7
9
|
declare function mermaid(opts?: MermaidOptions): AIGuiPlugin;
|
|
8
10
|
|
|
9
11
|
//#endregion
|
|
10
|
-
export { MermaidOptions, mermaid };
|
|
12
|
+
export { MermaidOptions, mermaid, mermaidPromptSpec };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,8 +3,10 @@ import { AIGuiPlugin } from "@ai-gui/core";
|
|
|
3
3
|
//#region src/index.d.ts
|
|
4
4
|
interface MermaidOptions {
|
|
5
5
|
theme?: string;
|
|
6
|
+
maxSourceBytes?: number;
|
|
6
7
|
}
|
|
8
|
+
declare function mermaidPromptSpec(): string;
|
|
7
9
|
declare function mermaid(opts?: MermaidOptions): AIGuiPlugin;
|
|
8
10
|
|
|
9
11
|
//#endregion
|
|
10
|
-
export { MermaidOptions, mermaid };
|
|
12
|
+
export { MermaidOptions, mermaid, mermaidPromptSpec };
|
package/dist/index.js
CHANGED
|
@@ -12,39 +12,58 @@ function enqueue(work) {
|
|
|
12
12
|
function escapeHtml(s) {
|
|
13
13
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
14
14
|
}
|
|
15
|
-
function errorHtml(
|
|
15
|
+
function errorHtml() {
|
|
16
16
|
return {
|
|
17
17
|
kind: "html",
|
|
18
|
-
html: `<pre data-aigui-mermaid-error>${escapeHtml(
|
|
18
|
+
html: `<pre data-aigui-mermaid-error>${escapeHtml("Diagram could not be rendered.")}</pre>`
|
|
19
19
|
};
|
|
20
20
|
}
|
|
21
|
+
function mermaidPromptSpec() {
|
|
22
|
+
return [
|
|
23
|
+
"Diagrams (fenced): ```mermaid <Mermaid diagram syntax>```.",
|
|
24
|
+
"Supported examples include flowchart, sequenceDiagram, classDiagram (UML), stateDiagram-v2, erDiagram, journey, gantt, pie, mindmap, timeline, and gitGraph.",
|
|
25
|
+
"Use concise labels and valid Mermaid syntax. Never emit HTML, scripts, click handlers, URLs, initialization directives, remote resources, or credentials."
|
|
26
|
+
].join("\n");
|
|
27
|
+
}
|
|
21
28
|
function mermaid(opts = {}) {
|
|
22
29
|
const theme = opts.theme ?? "default";
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
const maxSourceBytes = opts.maxSourceBytes ?? 64 * 1024;
|
|
31
|
+
if (!Number.isSafeInteger(maxSourceBytes) || maxSourceBytes <= 0) throw new TypeError("maxSourceBytes must be a positive safe integer");
|
|
32
|
+
const outputs = new WeakMap();
|
|
33
|
+
const render = (node) => {
|
|
34
|
+
const cached = outputs.get(node);
|
|
35
|
+
if (cached) return cached;
|
|
36
|
+
const output = enqueue(async () => {
|
|
37
|
+
try {
|
|
38
|
+
if (new TextEncoder().encode(node.content ?? "").byteLength > maxSourceBytes) return errorHtml();
|
|
39
|
+
const m = await loadMermaid();
|
|
40
|
+
if (initializedTheme === void 0) {
|
|
41
|
+
m.initialize({
|
|
42
|
+
startOnLoad: false,
|
|
43
|
+
theme,
|
|
44
|
+
securityLevel: "strict"
|
|
45
|
+
});
|
|
46
|
+
initializedTheme = theme;
|
|
47
|
+
}
|
|
48
|
+
const id = `aigui-mermaid-${nextId++}`;
|
|
49
|
+
const { svg } = await m.render(id, node.content ?? "");
|
|
50
|
+
return {
|
|
51
|
+
kind: "html",
|
|
52
|
+
html: svg
|
|
53
|
+
};
|
|
54
|
+
} catch {
|
|
55
|
+
return errorHtml();
|
|
32
56
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
html: svg
|
|
38
|
-
};
|
|
39
|
-
} catch (e) {
|
|
40
|
-
return errorHtml(String(e?.message ?? e));
|
|
41
|
-
}
|
|
42
|
-
});
|
|
57
|
+
});
|
|
58
|
+
outputs.set(node, output);
|
|
59
|
+
return output;
|
|
60
|
+
};
|
|
43
61
|
return {
|
|
44
62
|
name: "mermaid",
|
|
45
|
-
nodeRenderers: { mermaid: render }
|
|
63
|
+
nodeRenderers: { mermaid: render },
|
|
64
|
+
promptSpec: mermaidPromptSpec()
|
|
46
65
|
};
|
|
47
66
|
}
|
|
48
67
|
|
|
49
68
|
//#endregion
|
|
50
|
-
export { mermaid };
|
|
69
|
+
export { mermaid, mermaidPromptSpec };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-gui/plugin-mermaid",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
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.
|
|
55
|
+
"@ai-gui/core": "0.4.0"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "tsdown",
|