@zombie-mermaid/svg-renderer 4.2.2 → 5.0.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.
Files changed (72) hide show
  1. package/README.md +15 -1
  2. package/dist/index.cjs +52 -52
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +23 -4
  5. package/dist/index.d.ts +23 -4
  6. package/dist/index.js +897 -849
  7. package/dist/index.js.map +1 -1
  8. package/package.json +14 -5
  9. package/src/__tests__/c4-label-clearance-1290.test.ts +0 -112
  10. package/src/__tests__/c4-line-ends-1208.test.ts +0 -52
  11. package/src/__tests__/c4-mermaid-reference.test.ts +0 -124
  12. package/src/__tests__/c4-svg.test.ts +0 -337
  13. package/src/__tests__/c4-text-width-1210.test.ts +0 -43
  14. package/src/__tests__/class-component-order-1249.test.ts +0 -40
  15. package/src/__tests__/class-diamond-markers-1232.test.ts +0 -59
  16. package/src/__tests__/class-member-right-padding-1238.test.ts +0 -43
  17. package/src/__tests__/class-namespace-1196.test.ts +0 -165
  18. package/src/__tests__/class-namespace-sparse-elk-1196.test.ts +0 -96
  19. package/src/__tests__/class-visibility-markers-1237.test.ts +0 -27
  20. package/src/__tests__/edge-jog-straightening-1388.test.ts +0 -57
  21. package/src/__tests__/elk-adapter-utils.test.ts +0 -166
  22. package/src/__tests__/er-attribute-right-padding-1262.test.ts +0 -47
  23. package/src/__tests__/er-cardinality-markers-1233.test.ts +0 -35
  24. package/src/__tests__/er-default-direction-1250.test.ts +0 -69
  25. package/src/__tests__/er-edge-label-contrast-1244.test.ts +0 -58
  26. package/src/__tests__/fixtures/c4-mermaid-reference.json +0 -626
  27. package/src/__tests__/flowchart-parallel-edge-lanes-1308.test.ts +0 -168
  28. package/src/__tests__/pie-layout.test.ts +0 -215
  29. package/src/__tests__/pie-svg.test.ts +0 -194
  30. package/src/__tests__/render-mermaid-svg.test.ts +0 -64
  31. package/src/__tests__/sequence-label-clearance-1242.test.ts +0 -162
  32. package/src/__tests__/sequence-nested-activation-1241.test.ts +0 -37
  33. package/src/__tests__/svg-edge-to-own-cluster-1310.test.ts +0 -32
  34. package/src/__tests__/xychart-smooth-curve.test.ts +0 -42
  35. package/src/__tests__/xychart-x-label-overlap-1243.test.ts +0 -62
  36. package/src/c4/arial-widths.ts +0 -59
  37. package/src/c4/layout.ts +0 -680
  38. package/src/c4/metrics.ts +0 -261
  39. package/src/c4/renderer.ts +0 -366
  40. package/src/class/layout.ts +0 -525
  41. package/src/class/renderer.ts +0 -669
  42. package/src/edge-curves.ts +0 -205
  43. package/src/elk-instance.ts +0 -292
  44. package/src/er/layout.ts +0 -216
  45. package/src/er/renderer.ts +0 -516
  46. package/src/generated/mono-font-subset.ts +0 -32
  47. package/src/index.ts +0 -277
  48. package/src/layout-engine/back-edges.ts +0 -73
  49. package/src/layout-engine/compound-flat.ts +0 -916
  50. package/src/layout-engine/constants.ts +0 -19
  51. package/src/layout-engine/edge-bundling.ts +0 -458
  52. package/src/layout-engine/elk-adapter-utils.ts +0 -81
  53. package/src/layout-engine/elk-graph-builder.ts +0 -245
  54. package/src/layout-engine/from-elk.ts +0 -767
  55. package/src/layout-engine/inner-edges.ts +0 -329
  56. package/src/layout-engine/jog-straightening.ts +0 -52
  57. package/src/layout-engine/layer-alignment.ts +0 -174
  58. package/src/layout-engine/layout-hints.ts +0 -27
  59. package/src/layout-engine/to-elk.ts +0 -855
  60. package/src/layout-engine.ts +0 -115
  61. package/src/pie/layout.ts +0 -234
  62. package/src/pie/renderer.ts +0 -161
  63. package/src/registry.ts +0 -441
  64. package/src/renderer.ts +0 -1510
  65. package/src/resolve-colors.ts +0 -339
  66. package/src/sequence/layout.ts +0 -766
  67. package/src/sequence/renderer.ts +0 -687
  68. package/src/shape-clipping.ts +0 -197
  69. package/src/styles.ts +0 -145
  70. package/src/title-gaps.ts +0 -161
  71. package/src/xychart/layout.ts +0 -727
  72. package/src/xychart/renderer.ts +0 -676
package/src/index.ts DELETED
@@ -1,277 +0,0 @@
1
- // ============================================================================
2
- // @zombie-mermaid/svg-renderer — SVG emission and ELK-backed layout
3
- //
4
- // Every file re-exported below was grep-verified (zombie-mermaid#625,
5
- // umbrella #620) as unreachable from `src/ascii/index.ts` except through
6
- // the SVG-side modules the umbrella still owns — so nothing here can put
7
- // `elkjs` on the ASCII renderer's dependency path once #623 extracts it.
8
- //
9
- // This package depends on `@zombie-mermaid/core` and, since #624, on
10
- // `@zombie-mermaid/mermaid-parser` too — an ordinary, acyclic dependency
11
- // (both `svg-renderer` and the future `ascii-renderer` depend on
12
- // `mermaid-parser` directly, per the scoping doc's finding 2), not a cycle:
13
- // every per-type `layout.ts`/`renderer.ts` below needs the positioned-
14
- // diagram types `mermaid-parser`'s `types.ts` halves own, and
15
- // `class/layout.ts` needs `formatClassMember` from `mermaid-parser`'s
16
- // `class/format.ts`. It deliberately does NOT re-export the internal
17
- // `layout-engine/` modules the umbrella never imports
18
- // (`constants.ts` — whose `DEFAULTS` would collide with `core`'s theme
19
- // `DEFAULTS` anyway — plus `edge-bundling.ts`, `from-elk.ts`,
20
- // `layer-alignment.ts` and `to-elk.ts`): they are `layoutGraphSync()`'s
21
- // implementation, not its API. `elk-graph-builder.ts` is the exception:
22
- // `class/layout.ts` and `er/layout.ts` (moved into this package under
23
- // #624) call its primitives directly (zombie-mermaid#616), so it is part
24
- // of the public API alongside `elk-adapter-utils.ts`.
25
- //
26
- // `layout.ts` used to be a thin re-export of `layoutGraphSync` from
27
- // `layout-engine.ts`; it was folded into `layout-engine.ts` directly
28
- // (#1109), so `layoutGraphSync` now comes from the one star-export below.
29
- //
30
- // `class/`, `er/`, `sequence/`, `xychart/` hold each diagram type's
31
- // renderer half (`layout.ts` + `renderer.ts`) — the other half
32
- // (`parser.ts`/`types.ts`, plus `class/format.ts`, `sequence/box-color.ts`,
33
- // `sequence/activation-check.ts`, `xychart/colors.ts`) moved to
34
- // `@zombie-mermaid/mermaid-parser` under the same issue (#624), per the
35
- // scoping doc's finding 1: each per-type directory used to mix both halves
36
- // in one place, and the split point already existed at the file level.
37
- //
38
- // `renderMermaidSVG` (below) is the single "Mermaid text in, SVG out" front
39
- // door — moved here from the umbrella's `src/index.ts` under issue #1111,
40
- // for parity with `@zombie-mermaid/ascii-renderer`'s `renderMermaidASCII`.
41
- // `./registry.ts` (not re-exported — same as ascii-renderer's own
42
- // `registry.ts` — it's this front door's internal dispatch table, not part
43
- // of the public API) drives per-diagram-type dispatch; see that file's
44
- // header for why it's a separate module from the ASCII side's table.
45
- // ============================================================================
46
-
47
- export * from './edge-curves.ts'
48
- export * from './elk-instance.ts'
49
- export * from './layout-engine.ts'
50
- export * from './layout-engine/elk-adapter-utils.ts'
51
- export * from './layout-engine/elk-graph-builder.ts'
52
- export * from './renderer.ts'
53
- export * from './resolve-colors.ts'
54
- export * from './shape-clipping.ts'
55
- export * from './styles.ts'
56
-
57
- export * from './class/layout.ts'
58
- export * from './class/renderer.ts'
59
- export * from './er/layout.ts'
60
- export * from './er/renderer.ts'
61
- export * from './sequence/layout.ts'
62
- export * from './sequence/renderer.ts'
63
- export * from './xychart/layout.ts'
64
- export * from './xychart/renderer.ts'
65
- export * from './pie/layout.ts'
66
- export * from './pie/renderer.ts'
67
-
68
- import { decodeXML } from 'entities'
69
- import type {
70
- RenderOptions,
71
- DiagramColors,
72
- SvgEmitOptions,
73
- DiagramType,
74
- } from '@zombie-mermaid/core'
75
- import {
76
- DEFAULTS,
77
- themeStyleDeclarations,
78
- isMonospaceFont,
79
- setMonospaceMetrics,
80
- detectDiagramType,
81
- splitStatements,
82
- } from '@zombie-mermaid/core'
83
- import { resolveCssColors } from './resolve-colors.ts'
84
- import { resolveFontSizes } from './styles.ts'
85
- import { diagramRegistry } from './registry.ts'
86
- import type { SvgRenderContext } from './registry.ts'
87
-
88
- /**
89
- * Build a DiagramColors object from render options.
90
- * Uses DEFAULTS for bg/fg when not provided, and passes through
91
- * optional enrichment colors (line, accent, muted, surface, border).
92
- */
93
- function buildColors(options: RenderOptions): DiagramColors {
94
- return {
95
- bg: options.bg ?? DEFAULTS.bg,
96
- fg: options.fg ?? DEFAULTS.fg,
97
- line: options.line,
98
- accent: options.accent,
99
- muted: options.muted,
100
- surface: options.surface,
101
- border: options.border,
102
- }
103
- }
104
-
105
- /**
106
- * The exact CSS declaration list the root `<svg style="…">` attribute would
107
- * carry for these options — `--bg`, `--fg`, whichever enrichment colours
108
- * were given, and (unless `transparent`) `background: var(--bg)`.
109
- *
110
- * For hosts with a strict `Content-Security-Policy`: a `style=` attribute
111
- * can't be nonced, so a `style-src` without `'unsafe-inline'` drops it and
112
- * the diagram loses its colours. Render with `styleAttribute: false` and
113
- * put this string in your own stylesheet on the SVG (or any ancestor —
114
- * custom properties inherit) instead. Pass the same options object to both
115
- * calls so the declarations match what the render expects. See
116
- * `RenderOptions.styleAttribute` / `RenderOptions.nonce` and issue #216.
117
- *
118
- * Built by the same function that fills the attribute in normal renders,
119
- * so there is one variable list to keep in sync. The string is compact
120
- * (`--bg:#fff;--fg:#000;background:var(--bg)`) — valid inside any rule
121
- * block — and the colour values are yours, unescaped, exactly as the
122
- * attribute has always carried them.
123
- *
124
- * @example
125
- * ```ts
126
- * const opts = { bg: '#1a1b26', fg: '#a9b1d6', nonce, styleAttribute: false }
127
- * const svg = renderMermaidSVG('graph TD\n A --> B', opts)
128
- * const css = `.diagram svg { ${themeCssVariables(opts)} }`
129
- * ```
130
- */
131
- export function themeCssVariables(options: RenderOptions = {}): string {
132
- return themeStyleDeclarations(buildColors(options), options.transparent)
133
- }
134
-
135
- /**
136
- * Resolve the effective strict-CSP emission controls from the public
137
- * options. Kept as one object so every renderer takes it as a single
138
- * trailing parameter — see `SvgEmitOptions` in packages/core/src/theme.ts.
139
- */
140
- function resolveSvgEmit(options: RenderOptions): SvgEmitOptions {
141
- return {
142
- nonce: options.nonce,
143
- styleAttribute: options.styleAttribute,
144
- }
145
- }
146
-
147
- // Interactivity-derived render gates — whether xychart hover tooltips
148
- // render, whether flowchart/state edge animation (`e1@{ animate: true }`)
149
- // plays, and whether `click`-based links/`<title>` tooltips render — all
150
- // now live next to their diagram type's registry entry in ./registry.ts
151
- // (`resolveAnimationEnabled`/`resolveLinksEnabled` there, duplicated rather
152
- // than imported since that module is imported BY this file — see those
153
- // functions' own comments for why), since every diagram type's SVG dispatch
154
- // is fully handled by the registry lookup below and there is no remaining
155
- // switch case here for them to serve.
156
-
157
- /**
158
- * Render Mermaid diagram text to an SVG string — synchronously.
159
- *
160
- * Uses elk.bundled.js with a direct FakeWorker bypass (no setTimeout(0) delay).
161
- * The ELK singleton is created lazily on first use and cached forever.
162
- *
163
- * Use this in React components with useMemo() to avoid flash:
164
- * const svg = useMemo(() => renderMermaidSVG(code, opts), [code])
165
- *
166
- * @param text - Mermaid source text
167
- * @param options - Rendering options (colors, font, spacing)
168
- * @returns A self-contained SVG string
169
- *
170
- * @example
171
- * ```ts
172
- * const svg = renderMermaidSVG('graph TD\n A --> B')
173
- *
174
- * // With theme
175
- * const svg = renderMermaidSVG('graph TD\n A --> B', {
176
- * bg: '#1a1b26', fg: '#a9b1d6'
177
- * })
178
- *
179
- * // With CSS variables (for live theme switching)
180
- * const svg = renderMermaidSVG('graph TD\n A --> B', {
181
- * bg: 'var(--background)', fg: 'var(--foreground)', transparent: true
182
- * })
183
- *
184
- * // With the original source stamped onto the root <svg> as data-src —
185
- * // handy for a "copy source" button or an "open in Mermaid Live" link
186
- * // without re-attaching it via string surgery on the output.
187
- * const svg = renderMermaidSVG('graph TD\n A --> B', { embedSource: true })
188
- *
189
- * // With an accessible name — role="img" + aria-labelledby pointing at a
190
- * // <title> child, so assistive tech announces the diagram instead of
191
- * // reading every node label individually (see issue #215).
192
- * const svg = renderMermaidSVG('graph TD\n A --> B', {
193
- * title: 'Flowchart: Build → Test → Ship'
194
- * })
195
- *
196
- * // Decorative diagram — already described in surrounding prose, so it's
197
- * // hidden from assistive tech (aria-hidden="true") instead of named.
198
- * const svg = renderMermaidSVG('graph TD\n A --> B', { decorative: true })
199
- * ```
200
- */
201
- export function renderMermaidSVG(
202
- text: string,
203
- options: RenderOptions = {},
204
- ): string {
205
- const svg = renderMermaidSVGRaw(text, options)
206
- return options.resolveColors
207
- ? resolveCssColors(svg, buildColors(options))
208
- : svg
209
- }
210
-
211
- /** The renderer proper — `renderMermaidSVG` minus the optional `resolveColors` post-pass. */
212
- function renderMermaidSVGRaw(text: string, options: RenderOptions): string {
213
- // Decode XML entities that may leak from markdown parsers (e.g. rehype-raw).
214
- // Without this, escapeXml() double-encodes them: &lt; → &amp;lt; → literal "&lt;" in SVG.
215
- // `text` itself is left untouched so `embedSource` below stamps the exact
216
- // string the caller passed in, not this entity-decoded copy used
217
- // internally for parsing.
218
- const decoded = decodeXML(text)
219
-
220
- const colors = buildColors(options)
221
- const font = options.font ?? 'Inter'
222
- // Box sizing depends on the metrics model, so pick it before any layout runs.
223
- setMonospaceMetrics(isMonospaceFont(font))
224
- const transparent = options.transparent ?? false
225
- const fontSizes = resolveFontSizes(options.fontSizes)
226
- const diagramType: DiagramType = detectDiagramType(decoded)
227
- const embedSource = options.embedSource ? text : undefined
228
- const title = options.title
229
- const decorative = options.decorative
230
- const emit = resolveSvgEmit(options)
231
-
232
- const lines = splitStatements(decoded)
233
-
234
- // Registry dispatch (see ./registry.ts): every diagram type, including
235
- // 'flowchart' (and the 'state' pipeline it shares), is registered there.
236
- // `parse` takes both `lines` (what every already-registered type's parser
237
- // wants) and `decoded` (the raw text flowchart/state's parser needs
238
- // instead — see the `parse` doc comment on `DiagramModule` in
239
- // ./registry.ts).
240
- const registered = diagramRegistry[diagramType]
241
- const diagram = registered.parse(lines, decoded)
242
- const positioned = registered.layoutForSvg(diagram, options)
243
- const ctx: SvgRenderContext = {
244
- colors,
245
- font,
246
- transparent,
247
- fontSizes,
248
- embedSource,
249
- title,
250
- decorative,
251
- emit,
252
- }
253
- return registered.renderSvg(positioned, ctx, options)
254
- }
255
-
256
- /**
257
- * Render Mermaid diagram text to an SVG string — async.
258
- *
259
- * Same result as renderMermaidSVG() but returns a Promise.
260
- * Useful in async contexts (server handlers, data loaders, etc.)
261
- */
262
- export async function renderMermaidSVGAsync(
263
- text: string,
264
- options: RenderOptions = {},
265
- ): Promise<string> {
266
- return renderMermaidSVG(text, options)
267
- }
268
-
269
- // ---------------------------------------------------------------------------
270
- // Backward-compatible aliases
271
- // ---------------------------------------------------------------------------
272
-
273
- /** @deprecated Use `renderMermaidSVG` */
274
- export const renderMermaidSync = renderMermaidSVG
275
-
276
- /** @deprecated Use `renderMermaidSVGAsync` */
277
- export const renderMermaid = renderMermaidSVGAsync
@@ -1,73 +0,0 @@
1
- /**
2
- * Which edges of a flowchart are "back edges", found the way mermaid.js finds
3
- * them.
4
- *
5
- * mermaid lays a flowchart out with dagre, which makes the graph acyclic by a
6
- * depth-first walk: starting from each node in order and following out-edges
7
- * in source order, an edge that points at a node still on the walk's stack is
8
- * reversed. Which edge of a cycle gets reversed decides the whole layout. In
9
- * the CI/CD sample `D -.-> A` closes the cycle `A -> B -> D -> A`, and walking
10
- * `A -> B -> C -> E -> F` reaches `D` through `F --> D` first, so `D -.-> A` is
11
- * the back edge and `D` ("Fix & Retry") sits after `F`.
12
- *
13
- * ELK's own cycle breaking picks a different edge (`F --> D`), puts `D` early,
14
- * and draws the long way round. It also treats a subgraph's contents
15
- * separately from the rest of the graph, so no ELK setting reproduces the
16
- * dagre result (#1239). Handing ELK these edges already reversed means it never
17
- * has a cycle to break.
18
- */
19
-
20
- import type { MermaidGraph } from '@zombie-mermaid/core'
21
-
22
- /**
23
- * Indices into `graph.edges` of the edges a depth-first walk reverses.
24
- * Self-loops are never back edges here; layout handles them on their own.
25
- *
26
- * `walkOrder` is the order the walk starts from; it defaults to the graph's
27
- * node order, which is mermaid's (first appearance in the source).
28
- */
29
- export function findBackEdgeIndexes(
30
- graph: MermaidGraph,
31
- walkOrder?: Iterable<string>,
32
- ): Set<number> {
33
- const outEdges = new Map<string, number[]>()
34
- graph.edges.forEach((edge, index) => {
35
- if (edge.source === edge.target) return
36
- const list = outEdges.get(edge.source)
37
- if (list) list.push(index)
38
- else outEdges.set(edge.source, [index])
39
- })
40
-
41
- const back = new Set<number>()
42
- const visited = new Set<string>()
43
- const onStack = new Set<string>()
44
-
45
- // Iterative, so a long chain can't overflow the call stack.
46
- for (const root of walkOrder ?? graph.nodes.keys()) {
47
- if (visited.has(root)) continue
48
- const stack: Array<{ node: string; next: number }> = [
49
- { node: root, next: 0 },
50
- ]
51
- visited.add(root)
52
- onStack.add(root)
53
- while (stack.length > 0) {
54
- const frame = stack[stack.length - 1]!
55
- const edges = outEdges.get(frame.node) ?? []
56
- if (frame.next >= edges.length) {
57
- onStack.delete(frame.node)
58
- stack.pop()
59
- continue
60
- }
61
- const index = edges[frame.next++]!
62
- const target = graph.edges[index]!.target
63
- if (onStack.has(target)) {
64
- back.add(index)
65
- } else if (!visited.has(target)) {
66
- visited.add(target)
67
- onStack.add(target)
68
- stack.push({ node: target, next: 0 })
69
- }
70
- }
71
- }
72
- return back
73
- }