zombie-mermaid 5.0.1 → 5.2.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 +30 -7
- package/THIRD_PARTY_NOTICES.md +14 -0
- package/dist/cli.js +276 -218
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -2
- package/package.json +20 -8
package/README.md
CHANGED
|
@@ -73,7 +73,7 @@ the SVG renderer at all (see [ASCII Output](#ascii-output)).
|
|
|
73
73
|
|
|
74
74
|
## Features
|
|
75
75
|
|
|
76
|
-
- **
|
|
76
|
+
- **8 diagram types** — Flowcharts (including State), Sequence, Class, ER, XY Charts (bar, line, combined), Architecture, C4, and Pie
|
|
77
77
|
- **Dual output** — SVG for rich UIs, ASCII/Unicode for terminals
|
|
78
78
|
- **Synchronous rendering** — No async, no flash. Works with React `useMemo()`
|
|
79
79
|
- **15 built-in themes** — And dead simple to add your own
|
|
@@ -86,6 +86,8 @@ the SVG renderer at all (see [ASCII Output](#ascii-output)).
|
|
|
86
86
|
|
|
87
87
|
## Installation
|
|
88
88
|
|
|
89
|
+
Requires Node.js 24 or newer (`engines` in `package.json`).
|
|
90
|
+
|
|
89
91
|
```bash
|
|
90
92
|
npm install zombie-mermaid
|
|
91
93
|
# or
|
|
@@ -94,9 +96,16 @@ bun add zombie-mermaid
|
|
|
94
96
|
pnpm add zombie-mermaid
|
|
95
97
|
```
|
|
96
98
|
|
|
97
|
-
>
|
|
98
|
-
|
|
99
|
-
>
|
|
99
|
+
> Not sure this is the right package? See [Which package do I install?](docs/guides/choosing-a-package.md).
|
|
100
|
+
|
|
101
|
+
> **Upgrading from 4.x?** Node.js 24 or newer is now required. `elkjs` is now an
|
|
102
|
+
> optional peer dependency: browser and bundler apps must call `registerElk(ELK)`
|
|
103
|
+
> once (see the [migration guide](docs/guides/elkjs-optional-peer.md)). The
|
|
104
|
+
> package no longer ships `src/` (see [#1538](https://github.com/dfadler/zombie-mermaid/issues/1538)).
|
|
105
|
+
|
|
106
|
+
> **`elkjs` in the umbrella package:** the sub-packages (`@zombie-mermaid/svg-renderer`) treat `elkjs` as an
|
|
107
|
+
> optional peer, but `zombie-mermaid` itself lists it as a regular dependency so the CLI and MCP server work
|
|
108
|
+
> out of the box. See [what happens if you remove it](docs/guides/elkjs-optional-peer.md#removing-elkjs-from-zombie-mermaid).
|
|
100
109
|
|
|
101
110
|
Only need one output format? `@zombie-mermaid/ascii-renderer` and `@zombie-mermaid/svg-renderer` are published standalone — see [Packages](#packages) below.
|
|
102
111
|
|
|
@@ -129,10 +138,23 @@ import { registerElk } from 'zombie-mermaid'
|
|
|
129
138
|
registerElk(ELK)
|
|
130
139
|
```
|
|
131
140
|
|
|
141
|
+
Architecture diagrams (`architecture-beta`, see [Supported Diagrams](docs/diagrams.md#architecture-diagrams)) are laid out by `elkjs` too.
|
|
132
142
|
Sequence, pie, xychart and C4 diagrams, and all ASCII output, need no `elkjs`
|
|
133
143
|
and no registration. Rendering a graph diagram with no `elkjs` available throws an
|
|
134
144
|
`ElkNotRegisteredError` that says how to fix it.
|
|
135
145
|
|
|
146
|
+
**Flowcharts without `elkjs`.** Pass `layout: 'simple'` to lay a flowchart out with a
|
|
147
|
+
small built-in layered layout instead of ELK. It needs no `elkjs`, adds about 3.5 KB
|
|
148
|
+
gzipped, and is opt-in: the default output never changes. It is a rougher match for
|
|
149
|
+
ELK on edge routing, and a subgraph's own `direction` is ignored. State, class, ER
|
|
150
|
+
and architecture diagrams still need `elkjs`. See
|
|
151
|
+
[the decision record](docs/decisions/simple-layout-1685.md) for the measured quality
|
|
152
|
+
gap.
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
const svg = renderMermaidSVG('graph TD\n A --> B', { layout: 'simple' }) // no registerElk()
|
|
156
|
+
```
|
|
157
|
+
|
|
136
158
|
Need async? Use `renderMermaidSVGAsync()` — same output, returns a `Promise<string>`.
|
|
137
159
|
|
|
138
160
|
### ASCII Output
|
|
@@ -201,7 +223,7 @@ hyperlinks — off by default, since terminal and pager support varies (see
|
|
|
201
223
|
|
|
202
224
|
> 🧪 **Experimental — shipped to gauge interest, not a finished or best-effort implementation.** This is a first cut covering the common case; the tool surface may change based on feedback. Try it and [open an issue](https://github.com/dfadler/zombie-mermaid/issues/new) with what you'd want from it.
|
|
203
225
|
|
|
204
|
-
`zombie-mermaid mcp` starts a [Model Context Protocol](https://modelcontextprotocol.io/) server on stdio, exposing the library's rendering as
|
|
226
|
+
`zombie-mermaid mcp` starts a [Model Context Protocol](https://modelcontextprotocol.io/) server on stdio, exposing the library's rendering as seven tools: `render_mermaid_svg`, `render_mermaid_ascii`, `validate_mermaid`, `check_mermaid_sequence_activations`, `fix_mermaid_sequence_activations`, `list_themes`, and `list_diagram_types`. `render_mermaid_svg` also takes optional `bg`/`fg` hex color overrides (applied on top of `theme`) and an optional `outputPath` that writes the SVG to disk and returns `{ saved, size }` instead of the SVG text. `outputPath` must end in `.svg` and resolve inside the server's working directory (the directory your MCP client launched it from); its parent directory must already exist, symlinks and non-regular files are refused, and an existing `.svg` file at that path is overwritten. Per-tool arguments and return shapes are in the [MCP tool reference](docs/mcp-tools.md). Point an MCP client (Claude Desktop, Claude Code, or anything else that speaks MCP) at it to render Mermaid diagrams directly in a conversation, without shelling out to the CLI or importing the library.
|
|
205
227
|
|
|
206
228
|
Example Claude Desktop / Claude Code MCP server config:
|
|
207
229
|
|
|
@@ -216,7 +238,7 @@ Example Claude Desktop / Claude Code MCP server config:
|
|
|
216
238
|
}
|
|
217
239
|
```
|
|
218
240
|
|
|
219
|
-
|
|
241
|
+
The five diagram tools (including `validate_mermaid`, parse-only) accept a `diagram` string (`list_themes` and `list_diagram_types` take no arguments). The two render tools also take a handful of rendering options (`theme`, `transparent`, `font` for SVG; `useAscii`, `paddingX`/`paddingY`/`boxBorderPadding` for ASCII) — see each tool's `inputSchema` for the full, current list. Invalid Mermaid syntax comes back as a normal tool error (`isError: true`) rather than crashing the connection; `validate_mermaid` is the exception and reports it as a normal `{ valid: false, diagnostics }` result.
|
|
220
242
|
|
|
221
243
|
`check_mermaid_sequence_activations` is a mechanical, deterministic check — no LLM judgment involved — for a specific gap in existing Mermaid validators: every `activate X` (or `+` arrow shorthand) in a `sequenceDiagram` must be closed by a matching `deactivate X` (`-` shorthand) before the diagram ends. It returns a JSON report (`{ ok, issues }`) rather than rendering anything, and errors (`isError: true`) if given a non-sequence diagram.
|
|
222
244
|
|
|
@@ -266,12 +288,13 @@ See [docs/decisions/monorepo-conversion.md](docs/decisions/monorepo-conversion.m
|
|
|
266
288
|
|
|
267
289
|
## Docs
|
|
268
290
|
|
|
269
|
-
- [Guides](docs/guides/) — task-oriented walkthroughs: [browsing the samples](docs/guides/samples.md), [choosing a theme](docs/guides/theming.md), [using the HTML viewer](docs/guides/html-viewer.md)
|
|
291
|
+
- [Guides](docs/guides/) — task-oriented walkthroughs: [browsing the samples](docs/guides/samples.md), [choosing a theme](docs/guides/theming.md), [using the HTML viewer](docs/guides/html-viewer.md), [upgrading from 2.x to 5.x](docs/guides/upgrading-2x-to-5x.md)
|
|
270
292
|
- [Accessibility](docs/accessibility.md) — conformance statement: what's guaranteed (and CI-enforced), what's implemented but unverified by automation, and what isn't covered
|
|
271
293
|
- [Theming](docs/theming.md) — the two-color foundation, enriched mode, built-in themes, custom themes, Shiki compatibility
|
|
272
294
|
- [Supported Diagrams](docs/diagrams.md) — syntax for every diagram type, XY chart styling, and ASCII rendering options
|
|
273
295
|
- [React Integration](docs/react-integration.md) — zero-flash rendering with `useMemo()`
|
|
274
296
|
- [API Reference](docs/api-reference.md) — full function and options reference
|
|
297
|
+
- [Versioning and deprecation policy](docs/decisions/versioning-and-deprecation-policy-1568.md) — what counts as a breaking change, and how old majors are supported and deprecated
|
|
275
298
|
- [Migrating from `beautiful-mermaid`](docs/migrating-from-beautiful-mermaid.md) — what's drop-in, which fixes change rendered output, and how to audit your own diagrams before upgrading
|
|
276
299
|
|
|
277
300
|
More design write-ups and reference material live in [docs/](docs/).
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
This repository includes material from the projects below. Each published
|
|
4
|
+
package ships only the notices that apply to it (see its own
|
|
5
|
+
`THIRD_PARTY_NOTICES.md`).
|
|
6
|
+
|
|
7
|
+
- ASCII renderer: based on [mermaid-ascii](https://github.com/AlexanderGrooff/mermaid-ascii), MIT,
|
|
8
|
+
Copyright (c) 2023 Alexander Grooff
|
|
9
|
+
(`packages/ascii-renderer/THIRD_PARTY_NOTICES.md`).
|
|
10
|
+
- JetBrains Mono NL font subset: SIL OFL 1.1, Copyright 2020 The JetBrains Mono
|
|
11
|
+
Project Authors (`packages/svg-renderer/THIRD_PARTY_NOTICES.md`,
|
|
12
|
+
`third_party/fonts/`).
|
|
13
|
+
- Forked from [beautiful-mermaid](https://github.com/lukilabs/beautiful-mermaid),
|
|
14
|
+
MIT, Copyright (c) 2026 Craft Docs (see `LICENSE`).
|
package/dist/cli.js
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createRequire as
|
|
3
|
-
import { extname as
|
|
4
|
-
import { THEMES as B, escapeXml as
|
|
5
|
-
import { access as
|
|
2
|
+
import { createRequire as V } from "node:module";
|
|
3
|
+
import { extname as H, format as q, parse as D } from "node:path";
|
|
4
|
+
import { THEMES as B, escapeXml as j, isDirection as K, isWideChar as J } from "@zombie-mermaid/core";
|
|
5
|
+
import { access as Z, readFile as F, writeFile as Q } from "node:fs/promises";
|
|
6
6
|
import { diagramColorsToAsciiTheme as ee, renderMermaidASCII as O } from "@zombie-mermaid/ascii-renderer";
|
|
7
7
|
import "@zombie-mermaid/mermaid-parser";
|
|
8
|
-
import { registerElk as te, renderMermaidSVG as
|
|
9
|
-
import { createServer as
|
|
10
|
-
import { StdioServerTransport as
|
|
11
|
-
import { createMcpServer as
|
|
12
|
-
import
|
|
13
|
-
var
|
|
14
|
-
var
|
|
8
|
+
import { registerElk as te, renderMermaidSVG as M, validateMermaid as ne } from "@zombie-mermaid/svg-renderer";
|
|
9
|
+
import { createServer as re } from "node:http";
|
|
10
|
+
import { StdioServerTransport as oe } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
|
+
import { createMcpServer as ie } from "@zombie-mermaid/mcp";
|
|
12
|
+
import ae from "elkjs/lib/elk.bundled.js";
|
|
13
|
+
var se = 3e3;
|
|
14
|
+
var G = {
|
|
15
15
|
".svg": "svg",
|
|
16
16
|
".txt": "ascii",
|
|
17
17
|
".html": "html",
|
|
18
18
|
".htm": "html",
|
|
19
19
|
".png": "png"
|
|
20
20
|
};
|
|
21
|
-
function
|
|
21
|
+
function de(e) {
|
|
22
22
|
if (!(e === void 0 || e === "-"))
|
|
23
|
-
return
|
|
23
|
+
return G[H(e).toLowerCase()];
|
|
24
24
|
}
|
|
25
|
-
var
|
|
25
|
+
var w = {
|
|
26
26
|
svg: {
|
|
27
27
|
flag: "--svg",
|
|
28
28
|
ext: ".svg",
|
|
@@ -44,49 +44,57 @@ var v = {
|
|
|
44
44
|
display: "PNG",
|
|
45
45
|
label: "the PNG rasterization"
|
|
46
46
|
}
|
|
47
|
-
},
|
|
48
|
-
function
|
|
49
|
-
const t =
|
|
50
|
-
return
|
|
47
|
+
}, T = Object.keys(w);
|
|
48
|
+
function ce(e, n) {
|
|
49
|
+
const t = D(e);
|
|
50
|
+
return q({
|
|
51
51
|
dir: t.dir,
|
|
52
52
|
name: t.name,
|
|
53
53
|
ext: n
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
|
-
function
|
|
56
|
+
function le(e) {
|
|
57
57
|
const [n, ...t] = e;
|
|
58
58
|
if (n === void 0) return { command: "help" };
|
|
59
59
|
if (n === "--help" || n === "-h") return { command: "help" };
|
|
60
60
|
if (n === "--version" || n === "-v") return { command: "version" };
|
|
61
61
|
if (n === "themes") return { command: "themes" };
|
|
62
|
-
if (n === "render") return
|
|
63
|
-
if (n === "
|
|
62
|
+
if (n === "render") return pe(t);
|
|
63
|
+
if (n === "validate") {
|
|
64
|
+
const r = t.find((a, c) => c > 0 || a.startsWith("-"));
|
|
65
|
+
if (r !== void 0) throw new Error(`Unexpected argument: ${r}`);
|
|
66
|
+
return {
|
|
67
|
+
command: "validate",
|
|
68
|
+
input: t[0]
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (n === "web") return fe(t);
|
|
64
72
|
if (n === "mcp") return { command: "mcp" };
|
|
65
73
|
throw new Error(`Unknown command: ${n}`);
|
|
66
74
|
}
|
|
67
|
-
function
|
|
75
|
+
function z(e, n, t) {
|
|
68
76
|
const r = e[n + 1];
|
|
69
77
|
if (n + 1 >= e.length || r === void 0) throw new Error(`${t} requires a numeric value`);
|
|
70
78
|
if (!/^\d+$/.test(r)) throw new Error(`${t} requires a non-negative integer, got: "${r}"`);
|
|
71
79
|
return Number(r);
|
|
72
80
|
}
|
|
73
|
-
function
|
|
81
|
+
function me(e, n, t) {
|
|
74
82
|
const r = e[n + 1];
|
|
75
83
|
if (n + 1 >= e.length || r === void 0) throw new Error(`${t} requires a value ("auto" or a positive integer)`);
|
|
76
84
|
if (r === "auto") return "auto";
|
|
77
|
-
const
|
|
78
|
-
if (!/^\d+$/.test(r) ||
|
|
79
|
-
return
|
|
85
|
+
const a = Number(r);
|
|
86
|
+
if (!/^\d+$/.test(r) || a === 0 || !Number.isSafeInteger(a)) throw new Error(`${t} requires "auto" or a positive integer, got: "${r}"`);
|
|
87
|
+
return a;
|
|
80
88
|
}
|
|
81
|
-
function
|
|
89
|
+
function ue(e, n, t) {
|
|
82
90
|
const r = e[n + 1];
|
|
83
91
|
if (n + 1 >= e.length || r === void 0) throw new Error(`${t} requires a value (one of TD, TB, BT, LR, RL)`);
|
|
84
|
-
const
|
|
85
|
-
if (!
|
|
86
|
-
return
|
|
92
|
+
const a = r.toUpperCase();
|
|
93
|
+
if (!K(a)) throw new Error(`${t} requires one of TD, TB, BT, LR, RL, got: "${r}"`);
|
|
94
|
+
return a;
|
|
87
95
|
}
|
|
88
|
-
function
|
|
89
|
-
let n, t = !1, r = !1,
|
|
96
|
+
function pe(e) {
|
|
97
|
+
let n, t = !1, r = !1, a = !1, c = !1, l = !1, m, g = !1, E, S, k, s, u = !1, p = !1, h, b, i = 0;
|
|
90
98
|
for (; i < e.length; ) {
|
|
91
99
|
const o = e[i];
|
|
92
100
|
if (o === void 0) throw new Error(`parseArgs: index ${i} out of range while parsing arguments`);
|
|
@@ -95,115 +103,115 @@ function ue(e) {
|
|
|
95
103
|
else if (o === "--svg")
|
|
96
104
|
r = !0, i++;
|
|
97
105
|
else if (o === "--resolve-colors")
|
|
98
|
-
|
|
106
|
+
a = !0, i++;
|
|
99
107
|
else if (o === "--html")
|
|
100
|
-
m = !0, i++;
|
|
101
|
-
else if (o === "--png")
|
|
102
108
|
c = !0, i++;
|
|
109
|
+
else if (o === "--png")
|
|
110
|
+
l = !0, i++;
|
|
103
111
|
else if (o === "-o" || o === "--output") {
|
|
104
112
|
if (i + 1 >= e.length) throw new Error("-o requires a file path (or - for stdout)");
|
|
105
|
-
|
|
113
|
+
m = e[i + 1], i += 2;
|
|
106
114
|
} else if (o === "-f" || o === "--force")
|
|
107
|
-
|
|
115
|
+
g = !0, i++;
|
|
108
116
|
else if (o === "--theme") {
|
|
109
117
|
if (i + 1 >= e.length) throw new Error("--theme requires a theme name");
|
|
110
|
-
|
|
118
|
+
E = e[i + 1], i += 2;
|
|
111
119
|
} else if (o === "-x" || o === "--paddingX")
|
|
112
|
-
|
|
120
|
+
S = z(e, i, o), i += 2;
|
|
113
121
|
else if (o === "-y" || o === "--paddingY")
|
|
114
|
-
|
|
122
|
+
k = z(e, i, o), i += 2;
|
|
115
123
|
else if (o === "-p" || o === "--borderPadding")
|
|
116
|
-
|
|
124
|
+
s = z(e, i, o), i += 2;
|
|
117
125
|
else if (o === "--coords")
|
|
118
|
-
|
|
126
|
+
u = !0, i++;
|
|
119
127
|
else if (o === "--hyperlinks")
|
|
120
|
-
|
|
128
|
+
p = !0, i++;
|
|
121
129
|
else if (o === "-w" || o === "--max-width")
|
|
122
|
-
|
|
130
|
+
h = me(e, i, o), i += 2;
|
|
123
131
|
else if (o === "--direction")
|
|
124
|
-
|
|
132
|
+
b = ue(e, i, o), i += 2;
|
|
125
133
|
else if (!o.startsWith("-") || o === "-") {
|
|
126
134
|
if (o === "-") throw new Error("Unexpected argument: - (use -o - to write output to stdout; omit the input file to read stdin)");
|
|
127
135
|
if (n !== void 0) throw new Error(`Unexpected argument: ${o} (input file already set to "${n}")`);
|
|
128
136
|
n = o, i++;
|
|
129
137
|
} else throw new Error(`Unknown flag: ${o}`);
|
|
130
138
|
}
|
|
131
|
-
const
|
|
139
|
+
const v = {
|
|
132
140
|
svg: r,
|
|
133
|
-
html:
|
|
134
|
-
png:
|
|
135
|
-
},
|
|
136
|
-
if (
|
|
137
|
-
const [o,
|
|
138
|
-
throw new Error(`${
|
|
141
|
+
html: c,
|
|
142
|
+
png: l
|
|
143
|
+
}, y = T.filter((o) => v[o]);
|
|
144
|
+
if (y.length > 1) {
|
|
145
|
+
const [o, d] = y;
|
|
146
|
+
throw new Error(`${w[o].flag} and ${w[d].flag} cannot both be set — they would write different content to the same output path. Run the command twice with different -o paths for each.`);
|
|
139
147
|
}
|
|
140
|
-
const
|
|
141
|
-
if (
|
|
142
|
-
const o =
|
|
148
|
+
const f = de(m);
|
|
149
|
+
if (f !== void 0 && f !== "ascii") {
|
|
150
|
+
const o = T.find((d) => d !== f && v[d]);
|
|
143
151
|
if (o !== void 0) {
|
|
144
|
-
const
|
|
145
|
-
throw new Error(`-o ${
|
|
152
|
+
const d = w[f], $ = w[o];
|
|
153
|
+
throw new Error(`-o ${m} has ${d.article} ${d.ext} extension, but ${$.flag} output would be written to it. Use a ${$.ext} path (or -o - for stdout) for ${$.label}.`);
|
|
146
154
|
}
|
|
147
|
-
|
|
148
|
-
} else if (
|
|
149
|
-
const o =
|
|
155
|
+
f === "svg" ? r = !0 : f === "html" ? c = !0 : l = !0;
|
|
156
|
+
} else if (f === "ascii") {
|
|
157
|
+
const o = T.find((d) => v[d]);
|
|
150
158
|
if (o !== void 0) {
|
|
151
|
-
const
|
|
152
|
-
throw new Error(`-o ${
|
|
159
|
+
const d = w[o];
|
|
160
|
+
throw new Error(`-o ${m} has a .txt extension, but ${d.flag} output would be written to it. Use a ${d.ext} path (or -o - for stdout) instead.`);
|
|
153
161
|
}
|
|
154
162
|
t = !0;
|
|
155
163
|
}
|
|
156
|
-
if (!t && !r && !
|
|
157
|
-
if (
|
|
158
|
-
const o = Object.keys(
|
|
159
|
-
throw new Error(`Cannot infer an output format from "${
|
|
164
|
+
if (!t && !r && !c && !l) {
|
|
165
|
+
if (m !== void 0 && m !== "-") {
|
|
166
|
+
const o = Object.keys(G).join(", ");
|
|
167
|
+
throw new Error(`Cannot infer an output format from "${m}" — pass --ascii, --svg, --html, or --png, or use a recognised extension (${o})`);
|
|
160
168
|
}
|
|
161
169
|
throw new Error("Specify --ascii, --svg, --html, and/or --png (or -o <path> with a .svg/.txt/.html/.png extension)");
|
|
162
170
|
}
|
|
163
|
-
const
|
|
171
|
+
const C = {
|
|
164
172
|
svg: r,
|
|
165
|
-
html:
|
|
166
|
-
png:
|
|
167
|
-
},
|
|
168
|
-
if (
|
|
169
|
-
const o =
|
|
173
|
+
html: c,
|
|
174
|
+
png: l
|
|
175
|
+
}, x = T.find((o) => C[o]);
|
|
176
|
+
if (m === "-" && t && x !== void 0) {
|
|
177
|
+
const o = w[x].display;
|
|
170
178
|
throw new Error(`-o - would send both ASCII and ${o} to stdout; drop --ascii, or write the ${o} to a file path`);
|
|
171
179
|
}
|
|
172
|
-
if (
|
|
173
|
-
const { flag: o, ext:
|
|
180
|
+
if (x !== void 0 && m === void 0) {
|
|
181
|
+
const { flag: o, ext: d } = w[x];
|
|
174
182
|
if (n === void 0) throw new Error(`${o} needs -o <path> (or -o - for stdout) when reading from stdin — there is no input file name to derive an output name from`);
|
|
175
|
-
|
|
183
|
+
m = ce(n, d);
|
|
176
184
|
}
|
|
177
|
-
if (
|
|
178
|
-
if (
|
|
179
|
-
if (
|
|
185
|
+
if (h !== void 0 && !t) throw new Error("-w/--max-width requires --ascii");
|
|
186
|
+
if (p && !t) throw new Error("--hyperlinks requires --ascii");
|
|
187
|
+
if (a && !r) throw new Error("--resolve-colors requires --svg");
|
|
180
188
|
return {
|
|
181
189
|
command: "render",
|
|
182
190
|
input: n,
|
|
183
191
|
ascii: t,
|
|
184
192
|
svg: r,
|
|
185
|
-
resolveColors:
|
|
186
|
-
html:
|
|
187
|
-
png:
|
|
188
|
-
output:
|
|
189
|
-
force:
|
|
190
|
-
theme:
|
|
191
|
-
paddingX:
|
|
192
|
-
paddingY:
|
|
193
|
-
borderPadding:
|
|
194
|
-
coords:
|
|
195
|
-
hyperlinks:
|
|
196
|
-
maxWidth:
|
|
197
|
-
direction:
|
|
193
|
+
resolveColors: a,
|
|
194
|
+
html: c,
|
|
195
|
+
png: l,
|
|
196
|
+
output: m,
|
|
197
|
+
force: g,
|
|
198
|
+
theme: E,
|
|
199
|
+
paddingX: S,
|
|
200
|
+
paddingY: k,
|
|
201
|
+
borderPadding: s,
|
|
202
|
+
coords: u,
|
|
203
|
+
hyperlinks: p,
|
|
204
|
+
maxWidth: h,
|
|
205
|
+
direction: b
|
|
198
206
|
};
|
|
199
207
|
}
|
|
200
|
-
function
|
|
201
|
-
let n =
|
|
208
|
+
function fe(e) {
|
|
209
|
+
let n = se, t = 0;
|
|
202
210
|
for (; t < e.length; ) {
|
|
203
211
|
const r = e[t];
|
|
204
212
|
if (r === void 0) throw new Error(`parseArgs: index ${t} out of range while parsing arguments`);
|
|
205
213
|
if (r === "--port")
|
|
206
|
-
n =
|
|
214
|
+
n = z(e, t, r), t += 2;
|
|
207
215
|
else throw new Error(`Unknown flag: ${r}`);
|
|
208
216
|
}
|
|
209
217
|
return {
|
|
@@ -212,33 +220,51 @@ function pe(e) {
|
|
|
212
220
|
};
|
|
213
221
|
}
|
|
214
222
|
var he = /\p{Mn}|\p{Me}/u;
|
|
215
|
-
function
|
|
223
|
+
function ge(e) {
|
|
216
224
|
return he.test(e);
|
|
217
225
|
}
|
|
218
|
-
var
|
|
219
|
-
function
|
|
226
|
+
var ve = new Intl.Segmenter(void 0, { granularity: "grapheme" }), we = "️";
|
|
227
|
+
function be(e) {
|
|
220
228
|
if (/^[\x20-\x7e]*$/.test(e)) return e.split("");
|
|
221
229
|
const n = [];
|
|
222
|
-
for (const { segment: t } of
|
|
230
|
+
for (const { segment: t } of ve.segment(e)) n.push(t);
|
|
223
231
|
return n;
|
|
224
232
|
}
|
|
225
|
-
function
|
|
226
|
-
if (e.includes(
|
|
233
|
+
function ye(e) {
|
|
234
|
+
if (e.includes(we)) return 2;
|
|
227
235
|
let n = !1, t = !1;
|
|
228
236
|
for (const r of e)
|
|
229
|
-
|
|
237
|
+
J(r) && (n = !0), ge(r) || (t = !0);
|
|
230
238
|
return n ? 2 : t ? 1 : 0;
|
|
231
239
|
}
|
|
232
|
-
function
|
|
240
|
+
function xe(e) {
|
|
233
241
|
let n = 0;
|
|
234
|
-
for (const t of
|
|
242
|
+
for (const t of be(e)) n += ye(t);
|
|
235
243
|
return n;
|
|
236
244
|
}
|
|
237
|
-
var
|
|
238
|
-
function
|
|
239
|
-
return e.replace(
|
|
245
|
+
var Ee = /\x1b\]8;[^\x07\x1b]*(?:\x1b\\|\x07)/g;
|
|
246
|
+
function Se(e) {
|
|
247
|
+
return e.replace(Ee, "");
|
|
240
248
|
}
|
|
241
|
-
var
|
|
249
|
+
var ke = /^Line (\d+): ([\s\S]*)$/;
|
|
250
|
+
function Ce(e, n) {
|
|
251
|
+
const t = ke.exec(e);
|
|
252
|
+
if (t === null) return;
|
|
253
|
+
const r = Number(t[1]), a = n.split(/\r?\n/)[r - 1];
|
|
254
|
+
if (!(!Number.isSafeInteger(r) || r < 1 || a === void 0))
|
|
255
|
+
return {
|
|
256
|
+
line: r,
|
|
257
|
+
sourceLine: a,
|
|
258
|
+
message: t[2] ?? ""
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function W(e, n) {
|
|
262
|
+
if (!(e instanceof Error)) return e;
|
|
263
|
+
const t = Ce(e.message, n);
|
|
264
|
+
return t === void 0 ? e : /* @__PURE__ */ new Error(`${e.message}
|
|
265
|
+
${t.line} | ${t.sourceLine}`);
|
|
266
|
+
}
|
|
267
|
+
var Te = `// @ts-check
|
|
242
268
|
/// <reference lib="dom" />
|
|
243
269
|
// ============================================================================
|
|
244
270
|
// Client script for the CLI's self-contained HTML viewer (\`render --html\`).
|
|
@@ -530,7 +556,7 @@ var Se = `// @ts-check
|
|
|
530
556
|
fit()
|
|
531
557
|
stage.focus({ preventScroll: true })
|
|
532
558
|
})()
|
|
533
|
-
`,
|
|
559
|
+
`, Ae = `
|
|
534
560
|
:root {
|
|
535
561
|
color-scheme: light dark;
|
|
536
562
|
--bg: #f4f4f5;
|
|
@@ -637,16 +663,16 @@ var Se = `// @ts-check
|
|
|
637
663
|
#diagram { position: static; transform: none !important; }
|
|
638
664
|
}
|
|
639
665
|
`.trim();
|
|
640
|
-
function
|
|
666
|
+
function Ie(e) {
|
|
641
667
|
const n = e.title?.trim() || "Mermaid diagram";
|
|
642
668
|
return `<!doctype html>
|
|
643
669
|
<html lang="en">
|
|
644
670
|
<head>
|
|
645
671
|
<meta charset="utf-8" />
|
|
646
672
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
647
|
-
<title>${
|
|
673
|
+
<title>${j(n)}</title>
|
|
648
674
|
<style>
|
|
649
|
-
${
|
|
675
|
+
${Ae}
|
|
650
676
|
</style>
|
|
651
677
|
</head>
|
|
652
678
|
<body>
|
|
@@ -664,13 +690,13 @@ ${e.svg}
|
|
|
664
690
|
<button id="theme" type="button" aria-pressed="false" aria-label="Switch to dark mode (T)">Dark</button>
|
|
665
691
|
</div>
|
|
666
692
|
<script>
|
|
667
|
-
${
|
|
693
|
+
${Te}
|
|
668
694
|
<\/script>
|
|
669
695
|
</body>
|
|
670
696
|
</html>
|
|
671
697
|
`;
|
|
672
698
|
}
|
|
673
|
-
async function
|
|
699
|
+
async function Me(e) {
|
|
674
700
|
let n;
|
|
675
701
|
try {
|
|
676
702
|
n = await import("@resvg/resvg-js");
|
|
@@ -681,123 +707,130 @@ ${r}`);
|
|
|
681
707
|
}
|
|
682
708
|
return (await n.renderAsync(e)).asPng();
|
|
683
709
|
}
|
|
684
|
-
var
|
|
685
|
-
function
|
|
710
|
+
var ze = 80, P = 1, L = 1, R = 0, $e = /\x1b\[[0-9;]*m/g;
|
|
711
|
+
function _(e) {
|
|
686
712
|
return e.split(`
|
|
687
|
-
`).reduce((n, t) => Math.max(n,
|
|
713
|
+
`).reduce((n, t) => Math.max(n, xe(Se(t.replace($e, "")))), 0);
|
|
688
714
|
}
|
|
689
|
-
function
|
|
690
|
-
return e !== "auto" ? e : process.stdout.columns ??
|
|
715
|
+
function Pe(e) {
|
|
716
|
+
return e !== "auto" ? e : process.stdout.columns ?? ze;
|
|
691
717
|
}
|
|
692
|
-
async function
|
|
693
|
-
const
|
|
694
|
-
let
|
|
695
|
-
if (e.input !== void 0)
|
|
696
|
-
else if (t !== void 0)
|
|
718
|
+
async function Le(e, n, t, r) {
|
|
719
|
+
const a = n ?? process.stdout, c = r ?? process.stderr;
|
|
720
|
+
let l;
|
|
721
|
+
if (e.input !== void 0) l = await F(e.input, "utf-8");
|
|
722
|
+
else if (t !== void 0) l = t;
|
|
697
723
|
else {
|
|
698
724
|
if (process.stdin.isTTY) throw new Error("No input file specified and stdin is a terminal. Pipe a diagram or pass a file path.");
|
|
699
|
-
|
|
725
|
+
l = await Y();
|
|
700
726
|
}
|
|
701
|
-
if (
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
throw
|
|
727
|
+
if (l.trim().length === 0) throw new Error("Empty input — provide a Mermaid diagram via file or stdin");
|
|
728
|
+
try {
|
|
729
|
+
await Re(e, l, a, c);
|
|
730
|
+
} catch (m) {
|
|
731
|
+
throw W(m, l);
|
|
706
732
|
}
|
|
707
|
-
|
|
708
|
-
|
|
733
|
+
}
|
|
734
|
+
async function Re(e, n, t, r) {
|
|
735
|
+
let a;
|
|
736
|
+
if (e.theme !== void 0 && (a = B[e.theme], a === void 0)) {
|
|
737
|
+
const s = Object.keys(B).join(", ");
|
|
738
|
+
throw new Error(`Unknown theme: "${e.theme}". Available themes: ${s}`);
|
|
739
|
+
}
|
|
740
|
+
const c = e.svg && e.output === "-", l = e.html && e.output === "-", m = e.png && e.output === "-", g = e.ascii && !e.svg && !e.html && !e.png && e.output !== void 0 && e.output !== "-" ? e.output : void 0, E = e.svg && !c ? e.output : void 0, S = e.html && !l ? e.output : void 0, k = e.png && !m ? e.output : void 0;
|
|
741
|
+
for (const s of [
|
|
709
742
|
g,
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
])
|
|
743
|
+
E,
|
|
744
|
+
S,
|
|
745
|
+
k
|
|
746
|
+
]) s !== void 0 && await Be(s, e.force);
|
|
714
747
|
if (e.ascii) {
|
|
715
|
-
const
|
|
748
|
+
const s = a && g === void 0 ? {
|
|
716
749
|
colorMode: "auto",
|
|
717
|
-
theme: ee(
|
|
750
|
+
theme: ee(a)
|
|
718
751
|
} : { colorMode: "none" };
|
|
719
|
-
e.paddingX !== void 0 && (
|
|
720
|
-
let u = O(
|
|
752
|
+
e.paddingX !== void 0 && (s.paddingX = e.paddingX), e.paddingY !== void 0 && (s.paddingY = e.paddingY), e.borderPadding !== void 0 && (s.boxBorderPadding = e.borderPadding), e.coords && (s.showCoords = !0), e.direction !== void 0 && (s.direction = e.direction), e.hyperlinks && g === void 0 && (s.hyperlinks = !0);
|
|
753
|
+
let u = O(n, s);
|
|
721
754
|
if (e.maxWidth !== void 0) {
|
|
722
|
-
const
|
|
723
|
-
let h =
|
|
724
|
-
if (h >
|
|
725
|
-
const
|
|
726
|
-
if (
|
|
727
|
-
const
|
|
728
|
-
...
|
|
729
|
-
paddingX:
|
|
730
|
-
paddingY:
|
|
755
|
+
const p = Pe(e.maxWidth);
|
|
756
|
+
let h = _(u), b = !1;
|
|
757
|
+
if (h > p) {
|
|
758
|
+
const i = s.paddingX ?? 5, v = s.paddingY ?? 5, y = s.boxBorderPadding ?? 1, f = Math.min(i, P), C = Math.min(v, L), x = Math.min(y, R);
|
|
759
|
+
if (f < i || C < v || x < y) {
|
|
760
|
+
const o = O(n, {
|
|
761
|
+
...s,
|
|
762
|
+
paddingX: f,
|
|
763
|
+
paddingY: C,
|
|
731
764
|
boxBorderPadding: x
|
|
732
|
-
}),
|
|
733
|
-
|
|
765
|
+
}), d = _(o);
|
|
766
|
+
d < h && (u = o, h = d, b = !0);
|
|
734
767
|
}
|
|
735
768
|
}
|
|
736
|
-
if (h >
|
|
737
|
-
const
|
|
738
|
-
|
|
769
|
+
if (h > p) {
|
|
770
|
+
const i = e.maxWidth === "auto" ? "detected terminal width" : "--max-width", v = b ? `Compact spacing (-x ${P} -y ${L} -p ${R}) was already applied automatically. ` : "", y = b ? "Try a narrower direction (LR vs TD), shorter labels, or widen your terminal." : "Try -x/-y/-p for tighter spacing, a narrower direction (LR vs TD), or widen your terminal.";
|
|
771
|
+
r.write(`Warning: ASCII output is ${h} columns wide, exceeding ${i} of ${p}. ${v}zombie-mermaid does not reflow diagram structure to fit (no label wrapping or direction-flip cascade — see https://github.com/dfadler/zombie-mermaid/issues/335). ${y}
|
|
739
772
|
`);
|
|
740
|
-
} else
|
|
773
|
+
} else b && r.write(`Note: ASCII output exceeded ${p} columns at the requested spacing; applied compact spacing automatically (-x ${P} -y ${L} -p ${R}) to fit.
|
|
741
774
|
`);
|
|
742
775
|
}
|
|
743
|
-
await
|
|
744
|
-
`,
|
|
776
|
+
await I(A(g === void 0, g), u + `
|
|
777
|
+
`, t, e.force);
|
|
745
778
|
}
|
|
746
779
|
if (e.svg) {
|
|
747
|
-
const
|
|
748
|
-
...
|
|
780
|
+
const s = {
|
|
781
|
+
...a,
|
|
749
782
|
resolveColors: e.resolveColors
|
|
750
783
|
};
|
|
751
|
-
e.direction !== void 0 && (
|
|
752
|
-
const u =
|
|
753
|
-
await
|
|
784
|
+
e.direction !== void 0 && (s.direction = e.direction);
|
|
785
|
+
const u = M(n, s);
|
|
786
|
+
await I(A(c, E), u, t, e.force);
|
|
754
787
|
}
|
|
755
788
|
if (e.html) {
|
|
756
|
-
const
|
|
757
|
-
svg:
|
|
789
|
+
const s = M(n, a ?? {}), u = e.input ? D(e.input).name : void 0, p = Ie({
|
|
790
|
+
svg: s,
|
|
758
791
|
title: u
|
|
759
792
|
});
|
|
760
|
-
await
|
|
793
|
+
await I(A(l, S), p, t, e.force);
|
|
761
794
|
}
|
|
762
795
|
if (e.png) {
|
|
763
|
-
const
|
|
764
|
-
...
|
|
796
|
+
const s = {
|
|
797
|
+
...a,
|
|
765
798
|
resolveColors: !0
|
|
766
799
|
};
|
|
767
|
-
e.direction !== void 0 && (
|
|
768
|
-
const u =
|
|
769
|
-
await
|
|
800
|
+
e.direction !== void 0 && (s.direction = e.direction);
|
|
801
|
+
const u = M(n, s), p = await Me(u);
|
|
802
|
+
await I(A(m, k), p, t, e.force);
|
|
770
803
|
}
|
|
771
804
|
}
|
|
772
|
-
function
|
|
805
|
+
function A(e, n) {
|
|
773
806
|
return e ? { kind: "stdout" } : n !== void 0 ? {
|
|
774
807
|
kind: "file",
|
|
775
808
|
path: n
|
|
776
809
|
} : { kind: "skip" };
|
|
777
810
|
}
|
|
778
|
-
async function
|
|
811
|
+
async function I(e, n, t, r) {
|
|
779
812
|
switch (e.kind) {
|
|
780
813
|
case "stdout":
|
|
781
814
|
t.write(n);
|
|
782
815
|
break;
|
|
783
816
|
case "file":
|
|
784
|
-
await
|
|
817
|
+
await Oe(e.path, n, r);
|
|
785
818
|
}
|
|
786
819
|
}
|
|
787
820
|
function X(e) {
|
|
788
821
|
return /* @__PURE__ */ new Error(`Refusing to overwrite existing file "${e}" — pass --force to replace it`);
|
|
789
822
|
}
|
|
790
|
-
async function
|
|
823
|
+
async function Be(e, n) {
|
|
791
824
|
if (n) return;
|
|
792
825
|
let t = !0;
|
|
793
826
|
try {
|
|
794
|
-
await
|
|
827
|
+
await Z(e);
|
|
795
828
|
} catch {
|
|
796
829
|
t = !1;
|
|
797
830
|
}
|
|
798
831
|
if (t) throw X(e);
|
|
799
832
|
}
|
|
800
|
-
async function
|
|
833
|
+
async function Oe(e, n, t) {
|
|
801
834
|
try {
|
|
802
835
|
await Q(e, n, {
|
|
803
836
|
encoding: "utf-8",
|
|
@@ -807,37 +840,54 @@ async function Pe(e, n, t) {
|
|
|
807
840
|
throw !t && r instanceof Error && "code" in r && r.code === "EEXIST" ? X(e) : r;
|
|
808
841
|
}
|
|
809
842
|
}
|
|
810
|
-
async function
|
|
843
|
+
async function Y() {
|
|
811
844
|
const e = [], n = process.stdin;
|
|
812
845
|
return n.setEncoding("utf-8"), new Promise((t, r) => {
|
|
813
|
-
n.on("data", (
|
|
846
|
+
n.on("data", (a) => e.push(a)), n.on("end", () => t(e.join(""))), n.on("error", r);
|
|
814
847
|
});
|
|
815
848
|
}
|
|
816
|
-
|
|
817
|
-
|
|
849
|
+
async function _e(e, n) {
|
|
850
|
+
let t;
|
|
851
|
+
if (e.input !== void 0) t = await F(e.input, "utf-8");
|
|
852
|
+
else if (n !== void 0) t = n;
|
|
853
|
+
else {
|
|
854
|
+
if (process.stdin.isTTY) throw new Error("No input file specified and stdin is a terminal. Pipe a diagram or pass a file path.");
|
|
855
|
+
t = await Y();
|
|
856
|
+
}
|
|
857
|
+
const r = t;
|
|
858
|
+
if (r.trim().length === 0) throw new Error("Empty input — provide a Mermaid diagram via file or stdin");
|
|
859
|
+
try {
|
|
860
|
+
ne(r);
|
|
861
|
+
} catch (a) {
|
|
862
|
+
throw W(a, r);
|
|
863
|
+
}
|
|
864
|
+
console.log("valid");
|
|
865
|
+
}
|
|
866
|
+
var Ne = 1e6;
|
|
867
|
+
function De(e) {
|
|
818
868
|
return new Promise((n, t) => {
|
|
819
869
|
const r = [];
|
|
820
|
-
let
|
|
821
|
-
e.on("data", (
|
|
822
|
-
if (
|
|
870
|
+
let a = 0;
|
|
871
|
+
e.on("data", (c) => {
|
|
872
|
+
if (a += c.length, a > Ne) {
|
|
823
873
|
t(/* @__PURE__ */ new Error("Request body too large")), e.destroy();
|
|
824
874
|
return;
|
|
825
875
|
}
|
|
826
|
-
r.push(
|
|
876
|
+
r.push(c);
|
|
827
877
|
}), e.on("end", () => n(Buffer.concat(r).toString("utf-8"))), e.on("error", t);
|
|
828
878
|
});
|
|
829
879
|
}
|
|
830
|
-
function
|
|
880
|
+
function U(e) {
|
|
831
881
|
return typeof e == "object" && e !== null;
|
|
832
882
|
}
|
|
833
|
-
function
|
|
883
|
+
function Fe(e) {
|
|
834
884
|
let n;
|
|
835
885
|
try {
|
|
836
886
|
n = JSON.parse(e);
|
|
837
887
|
} catch {
|
|
838
888
|
throw new Error("Invalid JSON in request body");
|
|
839
889
|
}
|
|
840
|
-
if (!
|
|
890
|
+
if (!U(n)) throw new Error("Request body must be a JSON object");
|
|
841
891
|
const t = n.source;
|
|
842
892
|
if (typeof t != "string" || t.trim().length === 0) throw new Error('Provide Mermaid source as a non-empty "source" string');
|
|
843
893
|
return {
|
|
@@ -845,25 +895,25 @@ function Oe(e) {
|
|
|
845
895
|
format: n.format === "svg" ? "svg" : "ascii"
|
|
846
896
|
};
|
|
847
897
|
}
|
|
848
|
-
function
|
|
898
|
+
function N(e, n, t) {
|
|
849
899
|
const r = JSON.stringify(t);
|
|
850
900
|
e.writeHead(n, {
|
|
851
901
|
"Content-Type": "application/json; charset=utf-8",
|
|
852
902
|
"Content-Length": Buffer.byteLength(r)
|
|
853
903
|
}), e.end(r);
|
|
854
904
|
}
|
|
855
|
-
async function
|
|
905
|
+
async function Ge(e, n) {
|
|
856
906
|
try {
|
|
857
|
-
const { source: t, format: r } =
|
|
858
|
-
|
|
859
|
-
output: r === "svg" ?
|
|
907
|
+
const { source: t, format: r } = Fe(await De(e));
|
|
908
|
+
N(n, 200, {
|
|
909
|
+
output: r === "svg" ? M(t) : O(t),
|
|
860
910
|
format: r
|
|
861
911
|
});
|
|
862
912
|
} catch (t) {
|
|
863
|
-
|
|
913
|
+
N(n, 400, { error: t instanceof Error ? t.message : String(t) });
|
|
864
914
|
}
|
|
865
915
|
}
|
|
866
|
-
var
|
|
916
|
+
var We = `<!doctype html>
|
|
867
917
|
<html lang="en">
|
|
868
918
|
<head>
|
|
869
919
|
<meta charset="utf-8" />
|
|
@@ -929,56 +979,56 @@ var Ne = `<!doctype html>
|
|
|
929
979
|
</body>
|
|
930
980
|
</html>
|
|
931
981
|
`;
|
|
932
|
-
function
|
|
933
|
-
return
|
|
982
|
+
function Xe() {
|
|
983
|
+
return re((e, n) => {
|
|
934
984
|
const t = (e.url ?? "/").split("?")[0];
|
|
935
985
|
if (e.method === "GET" && (t === "/" || t === "")) {
|
|
936
|
-
n.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }), n.end(
|
|
986
|
+
n.writeHead(200, { "Content-Type": "text/html; charset=utf-8" }), n.end(We);
|
|
937
987
|
return;
|
|
938
988
|
}
|
|
939
989
|
if (e.method === "POST" && t === "/render") {
|
|
940
|
-
|
|
990
|
+
Ge(e, n);
|
|
941
991
|
return;
|
|
942
992
|
}
|
|
943
993
|
n.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" }), n.end("Not found");
|
|
944
994
|
});
|
|
945
995
|
}
|
|
946
|
-
function
|
|
996
|
+
function Ye(e) {
|
|
947
997
|
return new Promise((n, t) => {
|
|
948
|
-
const r =
|
|
998
|
+
const r = Xe();
|
|
949
999
|
r.once("error", t), r.listen(e, "127.0.0.1", () => {
|
|
950
1000
|
r.removeListener("error", t), n(r);
|
|
951
1001
|
});
|
|
952
1002
|
});
|
|
953
1003
|
}
|
|
954
|
-
async function
|
|
955
|
-
const t = await
|
|
956
|
-
return n(`zombie-mermaid web running at http://localhost:${
|
|
1004
|
+
async function Ue(e, n = console.log) {
|
|
1005
|
+
const t = await Ye(e.port), r = t.address();
|
|
1006
|
+
return n(`zombie-mermaid web running at http://localhost:${U(r) && typeof r.port == "number" ? r.port : e.port}`), t;
|
|
957
1007
|
}
|
|
958
|
-
async function
|
|
959
|
-
const n =
|
|
1008
|
+
async function Ve(e = (n) => console.error(n)) {
|
|
1009
|
+
const n = ie(), t = new oe();
|
|
960
1010
|
return await n.connect(t), e("zombie-mermaid MCP server running on stdio (experimental — feedback welcome: https://github.com/dfadler/zombie-mermaid/issues)"), n;
|
|
961
1011
|
}
|
|
962
|
-
function
|
|
963
|
-
const e =
|
|
1012
|
+
function He() {
|
|
1013
|
+
const e = V(import.meta.url)("../package.json");
|
|
964
1014
|
return typeof e == "object" && e !== null && "version" in e && typeof e.version == "string" ? e.version : "unknown";
|
|
965
1015
|
}
|
|
966
|
-
te(
|
|
967
|
-
var
|
|
968
|
-
async function
|
|
1016
|
+
te(ae);
|
|
1017
|
+
var qe = He();
|
|
1018
|
+
async function je() {
|
|
969
1019
|
const e = process.argv.slice(2);
|
|
970
1020
|
let n;
|
|
971
1021
|
try {
|
|
972
|
-
n =
|
|
1022
|
+
n = le(e);
|
|
973
1023
|
} catch (t) {
|
|
974
1024
|
console.error(`Error: ${t instanceof Error ? t.message : String(t)}`), process.exit(1);
|
|
975
1025
|
}
|
|
976
1026
|
switch (n.command) {
|
|
977
1027
|
case "help":
|
|
978
|
-
|
|
1028
|
+
Ke();
|
|
979
1029
|
break;
|
|
980
1030
|
case "version":
|
|
981
|
-
console.log(`zombie-mermaid ${
|
|
1031
|
+
console.log(`zombie-mermaid ${qe}`);
|
|
982
1032
|
break;
|
|
983
1033
|
case "themes":
|
|
984
1034
|
console.log(`Available themes:
|
|
@@ -987,27 +1037,34 @@ async function Ue() {
|
|
|
987
1037
|
break;
|
|
988
1038
|
case "render":
|
|
989
1039
|
try {
|
|
990
|
-
await
|
|
1040
|
+
await Le(n);
|
|
1041
|
+
} catch (t) {
|
|
1042
|
+
console.error(`Error: ${t instanceof Error ? t.message : String(t)}`), process.exit(1);
|
|
1043
|
+
}
|
|
1044
|
+
break;
|
|
1045
|
+
case "validate":
|
|
1046
|
+
try {
|
|
1047
|
+
await _e(n);
|
|
991
1048
|
} catch (t) {
|
|
992
1049
|
console.error(`Error: ${t instanceof Error ? t.message : String(t)}`), process.exit(1);
|
|
993
1050
|
}
|
|
994
1051
|
break;
|
|
995
1052
|
case "web":
|
|
996
1053
|
try {
|
|
997
|
-
await
|
|
1054
|
+
await Ue(n);
|
|
998
1055
|
} catch (t) {
|
|
999
1056
|
console.error(`Error: ${t instanceof Error ? t.message : String(t)}`), process.exit(1);
|
|
1000
1057
|
}
|
|
1001
1058
|
break;
|
|
1002
1059
|
case "mcp":
|
|
1003
1060
|
try {
|
|
1004
|
-
await
|
|
1061
|
+
await Ve();
|
|
1005
1062
|
} catch (t) {
|
|
1006
1063
|
console.error(`Error: ${t instanceof Error ? t.message : String(t)}`), process.exit(1);
|
|
1007
1064
|
}
|
|
1008
1065
|
}
|
|
1009
1066
|
}
|
|
1010
|
-
function
|
|
1067
|
+
function Ke() {
|
|
1011
1068
|
console.log(`
|
|
1012
1069
|
zombie-mermaid — render Mermaid diagrams from the command line
|
|
1013
1070
|
|
|
@@ -1021,6 +1078,7 @@ Usage:
|
|
|
1021
1078
|
zombie-mermaid render <file> --html Self-contained pan/zoom HTML viewer
|
|
1022
1079
|
zombie-mermaid render <file> --png Rasterize to <file stem>.png
|
|
1023
1080
|
cat file.mmd | zombie-mermaid render --ascii Read from stdin
|
|
1081
|
+
zombie-mermaid validate [file] Parse only; exit 1 with line diagnostics if invalid
|
|
1024
1082
|
zombie-mermaid themes List available themes
|
|
1025
1083
|
zombie-mermaid web [--port <n>] Start a local web UI (default port: 3000)
|
|
1026
1084
|
zombie-mermaid mcp Start an MCP server on stdio (render tools)
|
|
@@ -1081,7 +1139,7 @@ Options:
|
|
|
1081
1139
|
-v, --version Show version
|
|
1082
1140
|
`.trim());
|
|
1083
1141
|
}
|
|
1084
|
-
|
|
1142
|
+
je();
|
|
1085
1143
|
export {
|
|
1086
|
-
|
|
1144
|
+
je as main
|
|
1087
1145
|
};
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@zombie-mermaid/core"),t=require("@zombie-mermaid/mermaid-parser"),n=require("@zombie-mermaid/ascii-renderer"),r=require("@zombie-mermaid/svg-renderer");Object.defineProperty(exports,"DEFAULTS",{enumerable:!0,get:function(){return e.DEFAULTS}}),Object.defineProperty(exports,"ElkNotRegisteredError",{enumerable:!0,get:function(){return r.ElkNotRegisteredError}}),Object.defineProperty(exports,"THEMES",{enumerable:!0,get:function(){return e.THEMES}}),Object.defineProperty(exports,"createLayoutCache",{enumerable:!0,get:function(){return r.createLayoutCache}}),Object.defineProperty(exports,"fromShikiTheme",{enumerable:!0,get:function(){return e.fromShikiTheme}}),Object.defineProperty(exports,"parseMermaid",{enumerable:!0,get:function(){return t.parseMermaid}}),Object.defineProperty(exports,"registerElk",{enumerable:!0,get:function(){return r.registerElk}}),Object.defineProperty(exports,"renderMermaid",{enumerable:!0,get:function(){return r.renderMermaid}}),Object.defineProperty(exports,"renderMermaidASCII",{enumerable:!0,get:function(){return n.renderMermaidASCII}}),Object.defineProperty(exports,"renderMermaidAscii",{enumerable:!0,get:function(){return n.renderMermaidAscii}}),Object.defineProperty(exports,"renderMermaidSVG",{enumerable:!0,get:function(){return r.renderMermaidSVG}}),Object.defineProperty(exports,"renderMermaidSVGAsync",{enumerable:!0,get:function(){return r.renderMermaidSVGAsync}}),Object.defineProperty(exports,"renderMermaidSync",{enumerable:!0,get:function(){return r.renderMermaidSync}}),Object.defineProperty(exports,"themeCssVariables",{enumerable:!0,get:function(){return r.themeCssVariables}});
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@zombie-mermaid/core"),t=require("@zombie-mermaid/mermaid-parser"),n=require("@zombie-mermaid/ascii-renderer"),r=require("@zombie-mermaid/svg-renderer");Object.defineProperty(exports,"DEFAULTS",{enumerable:!0,get:function(){return e.DEFAULTS}}),Object.defineProperty(exports,"ElkNotRegisteredError",{enumerable:!0,get:function(){return r.ElkNotRegisteredError}}),Object.defineProperty(exports,"THEMES",{enumerable:!0,get:function(){return e.THEMES}}),Object.defineProperty(exports,"createLayoutCache",{enumerable:!0,get:function(){return r.createLayoutCache}}),Object.defineProperty(exports,"fromShikiTheme",{enumerable:!0,get:function(){return e.fromShikiTheme}}),Object.defineProperty(exports,"parseMermaid",{enumerable:!0,get:function(){return t.parseMermaid}}),Object.defineProperty(exports,"registerElk",{enumerable:!0,get:function(){return r.registerElk}}),Object.defineProperty(exports,"renderMermaid",{enumerable:!0,get:function(){return r.renderMermaid}}),Object.defineProperty(exports,"renderMermaidASCII",{enumerable:!0,get:function(){return n.renderMermaidASCII}}),Object.defineProperty(exports,"renderMermaidAscii",{enumerable:!0,get:function(){return n.renderMermaidAscii}}),Object.defineProperty(exports,"renderMermaidSVG",{enumerable:!0,get:function(){return r.renderMermaidSVG}}),Object.defineProperty(exports,"renderMermaidSVGAsync",{enumerable:!0,get:function(){return r.renderMermaidSVGAsync}}),Object.defineProperty(exports,"renderMermaidSync",{enumerable:!0,get:function(){return r.renderMermaidSync}}),Object.defineProperty(exports,"themeCssVariables",{enumerable:!0,get:function(){return r.themeCssVariables}}),Object.defineProperty(exports,"validateMermaid",{enumerable:!0,get:function(){return r.validateMermaid}});
|
package/dist/index.d.cts
CHANGED
|
@@ -27,6 +27,7 @@ import { SequenceRenderOptions } from '@zombie-mermaid/core';
|
|
|
27
27
|
import { themeCssVariables } from '@zombie-mermaid/svg-renderer';
|
|
28
28
|
import { ThemeName } from '@zombie-mermaid/core';
|
|
29
29
|
import { THEMES } from '@zombie-mermaid/core';
|
|
30
|
+
import { validateMermaid } from '@zombie-mermaid/svg-renderer';
|
|
30
31
|
import { XyChartRenderOptions } from '@zombie-mermaid/core';
|
|
31
32
|
|
|
32
33
|
export { AsciiRenderOptions }
|
|
@@ -87,6 +88,8 @@ export { ThemeName }
|
|
|
87
88
|
|
|
88
89
|
export { THEMES }
|
|
89
90
|
|
|
91
|
+
export { validateMermaid }
|
|
92
|
+
|
|
90
93
|
export { XyChartRenderOptions }
|
|
91
94
|
|
|
92
95
|
export { }
|
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,7 @@ import { SequenceRenderOptions } from '@zombie-mermaid/core';
|
|
|
27
27
|
import { themeCssVariables } from '@zombie-mermaid/svg-renderer';
|
|
28
28
|
import { ThemeName } from '@zombie-mermaid/core';
|
|
29
29
|
import { THEMES } from '@zombie-mermaid/core';
|
|
30
|
+
import { validateMermaid } from '@zombie-mermaid/svg-renderer';
|
|
30
31
|
import { XyChartRenderOptions } from '@zombie-mermaid/core';
|
|
31
32
|
|
|
32
33
|
export { AsciiRenderOptions }
|
|
@@ -87,6 +88,8 @@ export { ThemeName }
|
|
|
87
88
|
|
|
88
89
|
export { THEMES }
|
|
89
90
|
|
|
91
|
+
export { validateMermaid }
|
|
92
|
+
|
|
90
93
|
export { XyChartRenderOptions }
|
|
91
94
|
|
|
92
95
|
export { }
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DEFAULTS as e, THEMES as t, fromShikiTheme as n } from "@zombie-mermaid/core";
|
|
2
2
|
import { parseMermaid as r } from "@zombie-mermaid/mermaid-parser";
|
|
3
3
|
import { renderMermaidASCII as i, renderMermaidAscii as a } from "@zombie-mermaid/ascii-renderer";
|
|
4
|
-
import { ElkNotRegisteredError as o, createLayoutCache as s, registerElk as c, renderMermaid as l, renderMermaidSVG as u, renderMermaidSVGAsync as d, renderMermaidSync as f, themeCssVariables as p } from "@zombie-mermaid/svg-renderer";
|
|
5
|
-
export { e as DEFAULTS, o as ElkNotRegisteredError, t as THEMES, s as createLayoutCache, n as fromShikiTheme, r as parseMermaid, c as registerElk, l as renderMermaid, i as renderMermaidASCII, a as renderMermaidAscii, u as renderMermaidSVG, d as renderMermaidSVGAsync, f as renderMermaidSync, p as themeCssVariables };
|
|
4
|
+
import { ElkNotRegisteredError as o, createLayoutCache as s, registerElk as c, renderMermaid as l, renderMermaidSVG as u, renderMermaidSVGAsync as d, renderMermaidSync as f, themeCssVariables as p, validateMermaid as m } from "@zombie-mermaid/svg-renderer";
|
|
5
|
+
export { e as DEFAULTS, o as ElkNotRegisteredError, t as THEMES, s as createLayoutCache, n as fromShikiTheme, r as parseMermaid, c as registerElk, l as renderMermaid, i as renderMermaidASCII, a as renderMermaidAscii, u as renderMermaidSVG, d as renderMermaidSVGAsync, f as renderMermaidSync, p as themeCssVariables, m as validateMermaid };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zombie-mermaid",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.2.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Render Mermaid diagrams as beautiful SVGs or ASCII art. Ultra-fast, fully themeable, zero DOM dependencies. Maintained fork of beautiful-mermaid.",
|
|
6
6
|
"type": "module",
|
|
@@ -80,6 +80,7 @@
|
|
|
80
80
|
"files": [
|
|
81
81
|
"dist/",
|
|
82
82
|
"LICENSE",
|
|
83
|
+
"THIRD_PARTY_NOTICES.md",
|
|
83
84
|
"README.md"
|
|
84
85
|
],
|
|
85
86
|
"engines": {
|
|
@@ -89,13 +90,14 @@
|
|
|
89
90
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
90
91
|
"elkjs": "^0.11.0",
|
|
91
92
|
"entities": "^7.0.1",
|
|
92
|
-
"@zombie-mermaid/ascii-renderer": "5.0
|
|
93
|
-
"@zombie-mermaid/
|
|
94
|
-
"@zombie-mermaid/
|
|
95
|
-
"@zombie-mermaid/svg-renderer": "5.0
|
|
96
|
-
"@zombie-mermaid/mermaid-parser": "5.0
|
|
93
|
+
"@zombie-mermaid/ascii-renderer": "5.2.0",
|
|
94
|
+
"@zombie-mermaid/core": "5.2.0",
|
|
95
|
+
"@zombie-mermaid/mcp": "5.2.0",
|
|
96
|
+
"@zombie-mermaid/svg-renderer": "5.2.0",
|
|
97
|
+
"@zombie-mermaid/mermaid-parser": "5.2.0"
|
|
97
98
|
},
|
|
98
99
|
"devDependencies": {
|
|
100
|
+
"@axe-core/playwright": "^4.13.0",
|
|
99
101
|
"@changesets/changelog-github": "^1.0.0",
|
|
100
102
|
"@changesets/cli": "^3.0.1",
|
|
101
103
|
"@microsoft/api-extractor": "^7.59.0",
|
|
@@ -116,7 +118,7 @@
|
|
|
116
118
|
"jsdom": "^30.0.1",
|
|
117
119
|
"lightningcss": "^1.33.0",
|
|
118
120
|
"marked": "^18.0.11",
|
|
119
|
-
"mermaid": "
|
|
121
|
+
"mermaid": "12.1.0",
|
|
120
122
|
"prettier": "^3.9.6",
|
|
121
123
|
"react": "^19.2.8",
|
|
122
124
|
"react-dom": "^19.2.8",
|
|
@@ -138,7 +140,9 @@
|
|
|
138
140
|
"test:watch": "vitest -c config/vitest.config.ts",
|
|
139
141
|
"test:coverage": "vitest run -c config/vitest.config.ts --coverage",
|
|
140
142
|
"test:visual": "playwright test",
|
|
143
|
+
"test:a11y": "playwright test -c playwright.a11y.config.ts",
|
|
141
144
|
"test:visual:watch": "playwright test --ui",
|
|
145
|
+
"test:ascii-text:update": "vitest run -c config/vitest.config.ts __tests__/ascii-text-snapshots.test.ts -u",
|
|
142
146
|
"test:visual:update": "playwright test --update-snapshots",
|
|
143
147
|
"coverage:diff": "tsx scripts/check-diff-coverage.ts",
|
|
144
148
|
"samples": "scripts/tsx-css.sh packages/site/index.ts",
|
|
@@ -156,8 +160,12 @@
|
|
|
156
160
|
"bench:ascii-renderer": "tsx scripts/bench-ascii-renderer.ts",
|
|
157
161
|
"bench:package-compare": "tsx scripts/bench-package-compare.ts",
|
|
158
162
|
"bench:history:append": "tsx scripts/bench-history-append.ts",
|
|
163
|
+
"metrics:history:append": "tsx scripts/metrics-history-append.ts",
|
|
159
164
|
"bench:trend": "tsx scripts/bench-trend.ts",
|
|
160
165
|
"bench:mcp": "tsx scripts/bench-mcp.ts",
|
|
166
|
+
"check:changesets": "tsx scripts/check-changesets.ts",
|
|
167
|
+
"check:docs": "tsx scripts/check-docs.ts",
|
|
168
|
+
"smoke:packed": "node scripts/smoke-test-packed.mjs",
|
|
161
169
|
"check:bundle-size": "tsx scripts/check-bundle-size.ts",
|
|
162
170
|
"generate:hero": "tsx scripts/generate-hero.ts",
|
|
163
171
|
"build:mono-font": "tsx scripts/build-mono-font-subset.ts && prettier --write demo/components/generated/mono-font-subset.ts demo/styles.css packages/svg-renderer/src/generated/mono-font-subset.ts",
|
|
@@ -170,6 +178,7 @@
|
|
|
170
178
|
"form-facts": "tsx scripts/form-facts.ts",
|
|
171
179
|
"form-judge-prepare": "tsx scripts/form-judge-prepare.ts",
|
|
172
180
|
"form-judge-finalize-cache": "tsx scripts/form-judge-finalize-cache.ts",
|
|
181
|
+
"form-judge-calibrate": "tsx scripts/form-judge-calibrate.ts",
|
|
173
182
|
"build": "pnpm run build:packages && vite build --app --config config/vite.config.lib.ts",
|
|
174
183
|
"build:packages": "vite build --app --config packages/core/vite.config.ts && vite build --app --config packages/mermaid-parser/vite.config.ts && vite build --app --config packages/svg-renderer/vite.config.ts && vite build --app --config packages/ascii-renderer/vite.config.ts && vite build --app --config packages/mcp/vite.config.ts",
|
|
175
184
|
"build:site": "rm -rf site && mkdir -p site && SITE_OUT_DIR=site scripts/tsx-css.sh packages/site/index.ts && SITE_OUT_DIR=site scripts/tsx-css.sh packages/site/editor.ts && SITE_OUT_DIR=site scripts/tsx-css.sh packages/site/fork-fixes.ts && SITE_OUT_DIR=site scripts/tsx-css.sh packages/site/pages.ts && SITE_OUT_DIR=site scripts/tsx-css.sh packages/site/blog.ts && SITE_OUT_DIR=site scripts/tsx-css.sh packages/site/dashboard.ts && cp -r public/* site/",
|
|
@@ -183,6 +192,9 @@
|
|
|
183
192
|
"upstream:pr-candidates": "tsx scripts/list-upstream-pr-rescue-candidates.ts",
|
|
184
193
|
"audit:responsive": "tsx scripts/audit-responsive.ts",
|
|
185
194
|
"layout:oracle": "tsx scripts/layout-oracle.ts",
|
|
186
|
-
"
|
|
195
|
+
"layout:scorecard": "tsx scripts/layout-oracle.ts --history=layout-fidelity-history.jsonl --scorecard=docs/layout-fidelity-scorecard.md && prettier --write docs/layout-fidelity-scorecard.md",
|
|
196
|
+
"label:oracle": "tsx scripts/label-position-oracle.ts",
|
|
197
|
+
"verify": "scripts/verify.sh",
|
|
198
|
+
"doctor": "scripts/doctor.sh"
|
|
187
199
|
}
|
|
188
200
|
}
|