zombie-mermaid 2.2.1 → 2.2.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.
Files changed (251) hide show
  1. package/LICENSE +1 -0
  2. package/README.md +7 -2
  3. package/dist/ascii.cjs +9 -9
  4. package/dist/ascii.cjs.map +1 -1
  5. package/dist/ascii.js +4069 -3969
  6. package/dist/ascii.js.map +1 -1
  7. package/dist/cli.js +7605 -7381
  8. package/dist/index.cjs +52 -52
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.js +7613 -7459
  11. package/dist/index.js.map +1 -1
  12. package/dist/mcp.cjs +14142 -13717
  13. package/dist/mcp.cjs.map +1 -1
  14. package/dist/mcp.js +14142 -13717
  15. package/dist/mcp.js.map +1 -1
  16. package/package.json +27 -5
  17. package/packages/ascii-renderer/LICENSE +22 -0
  18. package/{src/ascii → packages/ascii-renderer/src}/class-diagram.ts +277 -57
  19. package/{src/ascii → packages/ascii-renderer/src}/er-diagram.ts +2 -2
  20. package/packages/ascii-renderer/src/flowchart.ts +94 -0
  21. package/{src/ascii → packages/ascii-renderer/src}/grid.ts +23 -0
  22. package/{src/ascii → packages/ascii-renderer/src}/index.ts +13 -84
  23. package/{src/ascii → packages/ascii-renderer/src}/registry.ts +23 -12
  24. package/{src/ascii → packages/ascii-renderer/src}/sequence.ts +55 -8
  25. package/{src/ascii → packages/ascii-renderer/src}/xychart.ts +6 -3
  26. package/packages/core/LICENSE +22 -0
  27. package/packages/core/src/click-directive.ts +106 -0
  28. package/packages/core/src/color-utils.ts +205 -0
  29. package/packages/core/src/diagram-type.ts +35 -0
  30. package/packages/core/src/direction-override.ts +46 -0
  31. package/packages/core/src/direction.ts +56 -0
  32. package/packages/core/src/index.ts +34 -0
  33. package/packages/core/src/init-directive.ts +248 -0
  34. package/packages/core/src/multiline-utils.ts +275 -0
  35. package/packages/core/src/statements.ts +197 -0
  36. package/packages/core/src/style-directives.ts +214 -0
  37. package/packages/core/src/text-metrics.ts +498 -0
  38. package/packages/core/src/theme.ts +696 -0
  39. package/packages/core/src/types.ts +670 -0
  40. package/packages/mcp/LICENSE +22 -0
  41. package/{src/mcp → packages/mcp/src}/server.ts +34 -2
  42. package/{src/mcp → packages/mcp/src}/tools/check-sequence-activations.ts +8 -5
  43. package/packages/mcp/src/tools/fix-sequence-activations.ts +77 -0
  44. package/{src/mcp → packages/mcp/src}/tools/render-ascii.ts +2 -2
  45. package/{src/mcp → packages/mcp/src}/tools/render-svg.ts +1 -1
  46. package/packages/mermaid-parser/LICENSE +22 -0
  47. package/{src → packages/mermaid-parser/src}/class/parser.ts +86 -8
  48. package/{src → packages/mermaid-parser/src}/er/parser.ts +59 -26
  49. package/packages/mermaid-parser/src/index.ts +48 -0
  50. package/{src → packages/mermaid-parser/src}/sequence/activation-check.ts +4 -3
  51. package/packages/mermaid-parser/src/sequence/activation-fix.ts +112 -0
  52. package/{src → packages/mermaid-parser/src}/sequence/parser.ts +74 -16
  53. package/{src → packages/mermaid-parser/src}/xychart/parser.ts +84 -6
  54. package/packages/svg-renderer/LICENSE +22 -0
  55. package/{src → packages/svg-renderer/src}/class/layout.ts +8 -4
  56. package/{src → packages/svg-renderer/src}/class/renderer.ts +7 -6
  57. package/packages/svg-renderer/src/edge-curves.ts +204 -0
  58. package/packages/svg-renderer/src/elk-instance.ts +292 -0
  59. package/{src → packages/svg-renderer/src}/er/layout.ts +6 -4
  60. package/{src → packages/svg-renderer/src}/er/renderer.ts +4 -4
  61. package/packages/svg-renderer/src/index.ts +58 -0
  62. package/packages/svg-renderer/src/layout-engine/constants.ts +19 -0
  63. package/packages/svg-renderer/src/layout-engine/edge-bundling.ts +379 -0
  64. package/packages/svg-renderer/src/layout-engine/elk-adapter-utils.ts +81 -0
  65. package/packages/svg-renderer/src/layout-engine/elk-graph-builder.ts +240 -0
  66. package/packages/svg-renderer/src/layout-engine/from-elk.ts +685 -0
  67. package/packages/svg-renderer/src/layout-engine/layer-alignment.ts +174 -0
  68. package/packages/svg-renderer/src/layout-engine/to-elk.ts +695 -0
  69. package/packages/svg-renderer/src/layout-engine.ts +74 -0
  70. package/packages/svg-renderer/src/layout.ts +8 -0
  71. package/packages/svg-renderer/src/renderer.ts +1485 -0
  72. package/packages/svg-renderer/src/resolve-colors.ts +339 -0
  73. package/{src → packages/svg-renderer/src}/sequence/layout.ts +2 -6
  74. package/{src → packages/svg-renderer/src}/sequence/renderer.ts +4 -4
  75. package/packages/svg-renderer/src/shape-clipping.ts +197 -0
  76. package/packages/svg-renderer/src/styles.ts +118 -0
  77. package/{src → packages/svg-renderer/src}/xychart/layout.ts +2 -2
  78. package/{src → packages/svg-renderer/src}/xychart/renderer.ts +6 -6
  79. package/src/__tests__/ascii-ansi.test.ts +6 -2
  80. package/src/__tests__/ascii-canvas-write.test.ts +2 -2
  81. package/src/__tests__/ascii-charset-border-junctions.test.ts +1 -1
  82. package/src/__tests__/ascii-cjk-width.test.ts +1 -1
  83. package/src/__tests__/ascii-class-box-occupancy.test.ts +147 -45
  84. package/src/__tests__/ascii-class-column-width-488-489.test.ts +1 -1
  85. package/src/__tests__/ascii-class-cross-level-jog-corruption.test.ts +187 -0
  86. package/src/__tests__/ascii-class-detour-label-routing-487.test.ts +1 -1
  87. package/src/__tests__/ascii-class-diagram-compartments.test.ts +1 -1
  88. package/src/__tests__/ascii-class-label-box-collision.test.ts +1 -1
  89. package/src/__tests__/ascii-class-label-row-collision-531.test.ts +1 -1
  90. package/src/__tests__/ascii-class-label-territory-row-awareness.test.ts +1 -1
  91. package/src/__tests__/ascii-class-padding.test.ts +1 -1
  92. package/src/__tests__/ascii-class-reciprocal-relationships-448.test.ts +86 -1
  93. package/src/__tests__/ascii-combining-mark-width.test.ts +2 -2
  94. package/src/__tests__/ascii-coords-overlay.test.ts +2 -2
  95. package/src/__tests__/ascii-decision-lr-box-start.test.ts +2 -2
  96. package/src/__tests__/ascii-display-width-unit.test.ts +1 -1
  97. package/src/__tests__/ascii-draw-arrows-coverage.test.ts +1 -1
  98. package/src/__tests__/ascii-draw-arrows-single-point-path.test.ts +12 -5
  99. package/src/__tests__/ascii-draw-bundles.test.ts +5 -5
  100. package/src/__tests__/ascii-edge-bundling-rank-violation-454.test.ts +1 -1
  101. package/src/__tests__/ascii-edge-bundling-routing.test.ts +9 -5
  102. package/src/__tests__/ascii-edge-cross-style-overlap.test.ts +10 -6
  103. package/src/__tests__/ascii-edge-ending-glyphs.test.ts +1 -1
  104. package/src/__tests__/ascii-edge-label-diagonal-fallback-418.test.ts +2 -2
  105. package/src/__tests__/ascii-edge-routing-fixes.test.ts +1 -1
  106. package/src/__tests__/ascii-edge-routing-single-point-path.test.ts +8 -4
  107. package/src/__tests__/ascii-edge-styles.test.ts +1 -1
  108. package/src/__tests__/ascii-emoji-cluster-width.test.ts +2 -2
  109. package/src/__tests__/ascii-er-box-occupancy.test.ts +1 -1
  110. package/src/__tests__/ascii-er-cardinality.test.ts +1 -1
  111. package/src/__tests__/ascii-er-corner-glyphs.test.ts +1 -1
  112. package/src/__tests__/ascii-er-jog-stray-line.test.ts +1 -1
  113. package/src/__tests__/ascii-er-label-padding.test.ts +1 -1
  114. package/src/__tests__/ascii-er-padding.test.ts +1 -1
  115. package/src/__tests__/ascii-er-relationship-label-corruption-350.test.ts +1 -1
  116. package/src/__tests__/ascii-er-relationship-overwrite.test.ts +1 -1
  117. package/src/__tests__/ascii-er-stray-connectors.test.ts +7 -4
  118. package/src/__tests__/ascii-er-unrelated-stem-separation-411.test.ts +1 -1
  119. package/src/__tests__/ascii-er-vertical-one-marker.test.ts +1 -1
  120. package/src/__tests__/ascii-grid-deep-chain.test.ts +4 -4
  121. package/src/__tests__/ascii-hyperlinks.test.ts +9 -6
  122. package/src/__tests__/ascii-label-line-terminal-fallback.test.ts +8 -4
  123. package/src/__tests__/ascii-lane-search.test.ts +1 -1
  124. package/src/__tests__/ascii-multibox-cjk-width.test.ts +1 -1
  125. package/src/__tests__/ascii-multiline.test.ts +6 -3
  126. package/src/__tests__/ascii-nested-subgraph-sibling-order-444.test.ts +8 -5
  127. package/src/__tests__/ascii-package-boundary.test.ts +47 -37
  128. package/src/__tests__/ascii-padding-edge-cases.test.ts +1 -1
  129. package/src/__tests__/ascii-parallel-edges-329.test.ts +8 -5
  130. package/src/__tests__/ascii-pathfinder-route-edge.test.ts +14 -4
  131. package/src/__tests__/ascii-reverse-direction-edges-629.test.ts +9 -5
  132. package/src/__tests__/ascii-sequence-alt-else-label.test.ts +1 -1
  133. package/src/__tests__/ascii-sequence-block-wall-clearance.test.ts +1 -1
  134. package/src/__tests__/ascii-sequence-box-group.test.ts +1 -1
  135. package/src/__tests__/ascii-sequence-cjk-width.test.ts +1 -1
  136. package/src/__tests__/ascii-sequence-create-destroy.test.ts +1 -1
  137. package/src/__tests__/ascii-sequence-form-invariants.test.ts +48 -50
  138. package/src/__tests__/ascii-sequence-mermaid-parity.test.ts +1 -1
  139. package/src/__tests__/ascii-sequence-notes.test.ts +1 -1
  140. package/src/__tests__/ascii-sequence-padding.test.ts +1 -1
  141. package/src/__tests__/ascii-sequence-self-arrow.test.ts +1 -1
  142. package/src/__tests__/ascii-shape-diamond.test.ts +3 -3
  143. package/src/__tests__/ascii-shape-rectangle.test.ts +5 -5
  144. package/src/__tests__/ascii-shape-rounded.test.ts +3 -3
  145. package/src/__tests__/ascii-shapes-circle.test.ts +3 -3
  146. package/src/__tests__/ascii-shapes-hexagon.test.ts +3 -3
  147. package/src/__tests__/ascii-shapes-special.test.ts +10 -5
  148. package/src/__tests__/ascii-shapes-stadium.test.ts +3 -3
  149. package/src/__tests__/ascii-shapes-state.test.ts +15 -5
  150. package/src/__tests__/ascii-state-bidirectional-label-swap-530.test.ts +1 -1
  151. package/src/__tests__/ascii-subgraph-bbox.test.ts +8 -4
  152. package/src/__tests__/ascii-subgraph-direction-honored-445.test.ts +1 -1
  153. package/src/__tests__/ascii-subgraph-label-border-clip.test.ts +88 -25
  154. package/src/__tests__/ascii-subgraph-later-edgeless-301.test.ts +8 -4
  155. package/src/__tests__/ascii-subgraph-title-padding.test.ts +1 -1
  156. package/src/__tests__/ascii-territory-unit.test.ts +2 -2
  157. package/src/__tests__/ascii-validate.test.ts +1 -1
  158. package/src/__tests__/ascii.test.ts +5 -2
  159. package/src/__tests__/box-color.test.ts +1 -1
  160. package/src/__tests__/class-arrow-directions.test.ts +1 -1
  161. package/src/__tests__/class-click-interactions.test.ts +3 -6
  162. package/src/__tests__/class-integration.test.ts +1 -1
  163. package/src/__tests__/class-notes.test.ts +3 -3
  164. package/src/__tests__/class-parser-error-messages.test.ts +162 -0
  165. package/src/__tests__/class-parser.test.ts +6 -6
  166. package/src/__tests__/class-styling.test.ts +2 -2
  167. package/src/__tests__/cli-render.test.ts +16 -1
  168. package/src/__tests__/direction-override.test.ts +1 -1
  169. package/src/__tests__/draw-lines.test.ts +2 -2
  170. package/src/__tests__/edge-cell-styles.test.ts +5 -2
  171. package/src/__tests__/elk-layout-cache.test.ts +6 -4
  172. package/src/__tests__/er-click-unsupported.test.ts +5 -8
  173. package/src/__tests__/er-parser-error-messages.test.ts +82 -0
  174. package/src/__tests__/er-parser.test.ts +3 -6
  175. package/src/__tests__/expanded-shapes.test.ts +1 -1
  176. package/src/__tests__/grid-occupancy.test.ts +1 -1
  177. package/src/__tests__/mcp-check-sequence-activations-tool.test.ts +1 -1
  178. package/src/__tests__/mcp-fix-sequence-activations-tool.test.ts +134 -0
  179. package/src/__tests__/mcp-render-ascii-tool.test.ts +5 -4
  180. package/src/__tests__/mcp-render-svg-theme-guard.test.ts +3 -3
  181. package/src/__tests__/mcp-render-svg-tool.test.ts +1 -1
  182. package/src/__tests__/mcp-server.test.ts +30 -1
  183. package/src/__tests__/multiline-labels.test.ts +29 -18
  184. package/src/__tests__/parser.test.ts +117 -5
  185. package/src/__tests__/pathfinder.test.ts +11 -4
  186. package/src/__tests__/render-options-overrides.test.ts +28 -21
  187. package/src/__tests__/render-options-per-type.test.ts +13 -9
  188. package/src/__tests__/resolve-colors.test.ts +1 -1
  189. package/src/__tests__/self-loop-edges.test.ts +112 -0
  190. package/src/__tests__/sequence-activation-check.test.ts +7 -8
  191. package/src/__tests__/sequence-activation-fix.test.ts +91 -0
  192. package/src/__tests__/sequence-layout.test.ts +4 -7
  193. package/src/__tests__/sequence-parser-syntax-errors.test.ts +179 -0
  194. package/src/__tests__/sequence-parser.test.ts +3 -6
  195. package/src/__tests__/statements.test.ts +53 -35
  196. package/src/__tests__/testdata/ascii/subgraph_direction_override.txt +21 -21
  197. package/src/__tests__/theme-palette-contrast.test.ts +84 -0
  198. package/src/__tests__/workspace-package-boundaries.test.ts +199 -25
  199. package/src/__tests__/xychart-ascii.test.ts +1 -1
  200. package/src/__tests__/xychart-colors.test.ts +3 -2
  201. package/src/__tests__/xychart-layout.test.ts +1 -1
  202. package/src/__tests__/xychart-parser-errors.test.ts +95 -0
  203. package/src/browser.ts +8 -2
  204. package/src/cli/mcp.ts +1 -1
  205. package/src/cli/render.ts +59 -25
  206. package/src/cli/web.ts +1 -1
  207. package/src/diagram-registry.ts +190 -25
  208. package/src/index.ts +34 -131
  209. package/src/parser.ts +102 -40
  210. /package/{src/ascii → packages/ascii-renderer/src}/ansi.ts +0 -0
  211. /package/{src/ascii → packages/ascii-renderer/src}/canvas.ts +0 -0
  212. /package/{src/ascii → packages/ascii-renderer/src}/converter.ts +0 -0
  213. /package/{src/ascii → packages/ascii-renderer/src}/coords.ts +0 -0
  214. /package/{src/ascii → packages/ascii-renderer/src}/display-width.ts +0 -0
  215. /package/{src/ascii → packages/ascii-renderer/src}/draw-arrows.ts +0 -0
  216. /package/{src/ascii → packages/ascii-renderer/src}/draw-boxes.ts +0 -0
  217. /package/{src/ascii → packages/ascii-renderer/src}/draw-bundles.ts +0 -0
  218. /package/{src/ascii → packages/ascii-renderer/src}/draw-lines.ts +0 -0
  219. /package/{src/ascii → packages/ascii-renderer/src}/draw-subgraphs.ts +0 -0
  220. /package/{src/ascii → packages/ascii-renderer/src}/draw.ts +0 -0
  221. /package/{src/ascii → packages/ascii-renderer/src}/edge-bundling.ts +0 -0
  222. /package/{src/ascii → packages/ascii-renderer/src}/edge-cell-styles.ts +0 -0
  223. /package/{src/ascii → packages/ascii-renderer/src}/edge-routing.ts +0 -0
  224. /package/{src/ascii → packages/ascii-renderer/src}/grid-occupancy.ts +0 -0
  225. /package/{src/ascii → packages/ascii-renderer/src}/hyperlinks.ts +0 -0
  226. /package/{src/ascii → packages/ascii-renderer/src}/lane-search.ts +0 -0
  227. /package/{src/ascii → packages/ascii-renderer/src}/multiline-utils.ts +0 -0
  228. /package/{src/ascii → packages/ascii-renderer/src}/pathfinder.ts +0 -0
  229. /package/{src/ascii → packages/ascii-renderer/src}/shapes/circle.ts +0 -0
  230. /package/{src/ascii → packages/ascii-renderer/src}/shapes/corners.ts +0 -0
  231. /package/{src/ascii → packages/ascii-renderer/src}/shapes/diamond.ts +0 -0
  232. /package/{src/ascii → packages/ascii-renderer/src}/shapes/hexagon.ts +0 -0
  233. /package/{src/ascii → packages/ascii-renderer/src}/shapes/index.ts +0 -0
  234. /package/{src/ascii → packages/ascii-renderer/src}/shapes/rectangle.ts +0 -0
  235. /package/{src/ascii → packages/ascii-renderer/src}/shapes/rounded.ts +0 -0
  236. /package/{src/ascii → packages/ascii-renderer/src}/shapes/special.ts +0 -0
  237. /package/{src/ascii → packages/ascii-renderer/src}/shapes/stadium.ts +0 -0
  238. /package/{src/ascii → packages/ascii-renderer/src}/shapes/state.ts +0 -0
  239. /package/{src/ascii → packages/ascii-renderer/src}/shapes/types.ts +0 -0
  240. /package/{src/ascii → packages/ascii-renderer/src}/territory.ts +0 -0
  241. /package/{src/ascii → packages/ascii-renderer/src}/types.ts +0 -0
  242. /package/{src/ascii → packages/ascii-renderer/src}/validate.ts +0 -0
  243. /package/{src/mcp → packages/mcp/src}/index.ts +0 -0
  244. /package/{src → packages/mermaid-parser/src}/class/format.ts +0 -0
  245. /package/{src → packages/mermaid-parser/src}/class/types.ts +0 -0
  246. /package/{src → packages/mermaid-parser/src}/er/types.ts +0 -0
  247. /package/{src → packages/mermaid-parser/src}/expanded-shapes.ts +0 -0
  248. /package/{src → packages/mermaid-parser/src}/sequence/box-color.ts +0 -0
  249. /package/{src → packages/mermaid-parser/src}/sequence/types.ts +0 -0
  250. /package/{src → packages/mermaid-parser/src}/xychart/colors.ts +0 -0
  251. /package/{src → packages/mermaid-parser/src}/xychart/types.ts +0 -0
package/src/index.ts CHANGED
@@ -37,17 +37,17 @@ export { fromShikiTheme, THEMES, DEFAULTS } from '@zombie-mermaid/core'
37
37
  export { parseMermaid } from './parser.ts'
38
38
  import {
39
39
  resolveCssColors,
40
- layoutGraphSync,
41
- renderSvg,
42
40
  resolveFontSizes,
43
41
  } from '@zombie-mermaid/svg-renderer'
44
- export { renderMermaidASCII, renderMermaidAscii } from './ascii/index.ts'
45
- export type { AsciiRenderOptions } from './ascii/index.ts'
42
+ export {
43
+ renderMermaidASCII,
44
+ renderMermaidAscii,
45
+ } from '@zombie-mermaid/ascii-renderer'
46
+ export type { AsciiRenderOptions } from '@zombie-mermaid/ascii-renderer'
46
47
  export { createLayoutCache } from '@zombie-mermaid/svg-renderer'
47
48
  export type { LayoutCache } from '@zombie-mermaid/svg-renderer'
48
49
 
49
50
  import { decodeXML } from 'entities'
50
- import { parseMermaid } from './parser.ts'
51
51
  import type {
52
52
  RenderOptions,
53
53
  DiagramColors,
@@ -60,17 +60,9 @@ import {
60
60
  isMonospaceFont,
61
61
  setMonospaceMetrics,
62
62
  detectDiagramType,
63
- applyInitConfig,
64
- withDirectionOverride,
65
63
  splitStatements,
66
64
  } from '@zombie-mermaid/core'
67
65
 
68
- import { parseSequenceDiagram } from './sequence/parser.ts'
69
- import { layoutSequenceDiagram } from './sequence/layout.ts'
70
- import { renderSequenceSvg } from './sequence/renderer.ts'
71
- import { parseClassDiagram } from './class/parser.ts'
72
- import { layoutClassDiagramSync } from './class/layout.ts'
73
- import { renderClassSvg } from './class/renderer.ts'
74
66
  import { diagramRegistry } from './diagram-registry.ts'
75
67
  import type { SvgRenderContext } from './diagram-registry.ts'
76
68
 
@@ -133,42 +125,15 @@ function resolveSvgEmit(options: RenderOptions): SvgEmitOptions {
133
125
  }
134
126
  }
135
127
 
136
- /**
137
- * Resolve the effective interactivity level, defaulting unset to `'static'`.
138
- * See `RenderOptions.interactivity` for what each level means.
139
- */
140
- function resolveInteractivity(
141
- options: RenderOptions,
142
- ): 'none' | 'static' | 'full' {
143
- return options.interactivity ?? 'static'
144
- }
145
-
146
- /**
147
- * Whether flowchart/state-diagram edge animation (`e1@{ animate: true }`)
148
- * should render. Gated to `'full'` only — CSS animation is tier-2 *motion*
149
- * (see docs/decisions/no-script-interactivity.md), so the default
150
- * (`'static'`, tier 1 + tier 2 minus motion) and `'none'` both render the
151
- * edge as a still line.
152
- */
153
- function resolveAnimationEnabled(options: RenderOptions): boolean {
154
- return resolveInteractivity(options) === 'full'
155
- }
156
-
157
- /**
158
- * Whether flowchart `click`-based links (`<a href>`) and `<title>` tooltips
159
- * should render. Gated behind `interactivity !== 'none'` — `'none'` is meant
160
- * for print/rasterized output, where a link is meaningless, so it strips
161
- * both; `'static'` and `'full'` both keep them.
162
- */
163
- function resolveLinksEnabled(options: RenderOptions): boolean {
164
- return resolveInteractivity(options) !== 'none'
165
- }
166
-
167
- // Whether xychart hover tooltips should render (`interactivity` wins over
168
- // the deprecated `interactive` boolean when both are set) now lives next to
169
- // the xychart registry entry in src/diagram-registry.ts, since xychart's
170
- // SVG dispatch is fully handled by the registry lookup below — there is no
171
- // remaining switch case here for it to serve.
128
+ // Interactivity-derived render gates — whether xychart hover tooltips
129
+ // render, whether flowchart/state edge animation (`e1@{ animate: true }`)
130
+ // plays, and whether `click`-based links/`<title>` tooltips render — all
131
+ // now live next to their diagram type's registry entry in
132
+ // src/diagram-registry.ts (`resolveAnimationEnabled`/`resolveLinksEnabled`
133
+ // there, duplicated rather than imported since that module is imported BY
134
+ // this file — see those functions' own comments for why), since every
135
+ // diagram type's SVG dispatch is fully handled by the registry lookup
136
+ // below and there is no remaining switch case here for them to serve.
172
137
 
173
138
  /**
174
139
  * Render Mermaid diagram text to an SVG string — synchronously.
@@ -247,90 +212,28 @@ function renderMermaidSVGRaw(text: string, options: RenderOptions): string {
247
212
 
248
213
  const lines = splitStatements(decoded)
249
214
 
250
- // Registry lookup first (see src/diagram-registry.ts — issue #533):
251
- // 'xychart' and 'er' are registered there and handled identically to how
252
- // their switch cases below used to read, just via the shared adapter
253
- // shape instead. Anything not registered (currently 'sequence', 'class',
254
- // 'flowchart') falls through to the switch, unchanged.
215
+ // Registry dispatch (see src/diagram-registry.ts — issue #533 / #745):
216
+ // every diagram type, including 'flowchart' (and the 'state' pipeline it
217
+ // shares), is registered there and handled identically to how each
218
+ // type's original switch case (or, for 'flowchart', its inline fallback)
219
+ // used to read, just via the shared adapter shape instead. `parse` takes
220
+ // both `lines` (what every already-registered type's parser wants) and
221
+ // `decoded` (the raw text flowchart/state's parser needs instead — see
222
+ // the `parse` doc comment on `DiagramModule`).
255
223
  const registered = diagramRegistry[diagramType]
256
- if (registered) {
257
- const diagram = registered.parse(lines)
258
- const positioned = registered.layoutForSvg(diagram, options)
259
- const ctx: SvgRenderContext = {
260
- colors,
261
- font,
262
- transparent,
263
- fontSizes,
264
- embedSource,
265
- title,
266
- decorative,
267
- emit,
268
- }
269
- return registered.renderSvg(positioned, ctx, options)
270
- }
271
-
272
- switch (diagramType) {
273
- case 'sequence': {
274
- const diagram = parseSequenceDiagram(lines)
275
- const positioned = layoutSequenceDiagram(diagram, options)
276
- return renderSequenceSvg(
277
- positioned,
278
- colors,
279
- font,
280
- transparent,
281
- fontSizes,
282
- embedSource,
283
- title,
284
- decorative,
285
- emit,
286
- )
287
- }
288
- case 'class': {
289
- const diagram = parseClassDiagram(lines)
290
- const positioned = layoutClassDiagramSync(diagram, options)
291
- return renderClassSvg(
292
- positioned,
293
- colors,
294
- font,
295
- transparent,
296
- fontSizes,
297
- embedSource,
298
- title,
299
- decorative,
300
- resolveLinksEnabled(options),
301
- emit,
302
- )
303
- }
304
- case 'flowchart':
305
- default: {
306
- const parsed = parseMermaid(decoded)
307
- // A diagram's own `%%{init: ...}%%` supplies defaults; an explicit
308
- // render option always wins. See packages/core/src/init-directive.ts.
309
- const effective = parsed.initConfig
310
- ? applyInitConfig(options, parsed.initConfig)
311
- : options
312
- // `direction` replaces the header's (or a state diagram's top-level
313
- // `direction` line's) direction before layout; nested subgraph /
314
- // composite-state directions live on the subgraph objects and still
315
- // apply on top of it. See packages/core/src/direction-override.ts.
316
- const graph = withDirectionOverride(parsed, effective.direction)
317
- const positioned = layoutGraphSync(graph, effective)
318
- return renderSvg(
319
- positioned,
320
- colors,
321
- font,
322
- transparent,
323
- fontSizes,
324
- effective.curve ?? 'linear',
325
- embedSource,
326
- resolveAnimationEnabled(options),
327
- resolveLinksEnabled(options),
328
- title,
329
- decorative,
330
- emit,
331
- )
332
- }
224
+ const diagram = registered.parse(lines, decoded)
225
+ const positioned = registered.layoutForSvg(diagram, options)
226
+ const ctx: SvgRenderContext = {
227
+ colors,
228
+ font,
229
+ transparent,
230
+ fontSizes,
231
+ embedSource,
232
+ title,
233
+ decorative,
234
+ emit,
333
235
  }
236
+ return registered.renderSvg(positioned, ctx, options)
334
237
  }
335
238
 
336
239
  /**
package/src/parser.ts CHANGED
@@ -2,14 +2,14 @@ import type {
2
2
  MermaidGraph,
3
3
  MermaidNode,
4
4
  MermaidSubgraph,
5
- Direction,
6
5
  NodeShape,
7
6
  EdgeStyle,
7
+ Statement,
8
8
  } from '@zombie-mermaid/core'
9
9
  import {
10
- isDirection,
10
+ toDirection,
11
11
  normalizeBrTags,
12
- splitStatements,
12
+ splitStatementsByLine,
13
13
  extractInitConfig,
14
14
  applyClickStatement as applyClickStatementShared,
15
15
  parseStyleProps,
@@ -22,8 +22,8 @@ import {
22
22
  matchExpandedBlock,
23
23
  parseExpandedMeta,
24
24
  resolveShapeName,
25
- } from './expanded-shapes.ts'
26
- import type { ExpandedNodeMeta } from './expanded-shapes.ts'
25
+ } from '@zombie-mermaid/mermaid-parser'
26
+ import type { ExpandedNodeMeta } from '@zombie-mermaid/mermaid-parser'
27
27
  /** Remove a single layer of matching wrapping quotes (`"…"` or `'…'`). */
28
28
  function stripWrappingQuotes(s: string): string {
29
29
  const t = s.trim()
@@ -48,26 +48,15 @@ function stripWrappingQuotes(s: string): string {
48
48
  // that we don't need a grammar generator or full parser combinator.
49
49
  // ============================================================================
50
50
 
51
- /**
52
- * Normalize a regex-captured direction token to a `Direction`.
53
- *
54
- * Accepts `string | undefined` because every call site passes a regex
55
- * capture group value (`match[1]`, typed as possibly-`undefined` under
56
- * `noUncheckedIndexedAccess`) straight through. Each call site's regex
57
- * guards the capture with the same `(TD|TB|LR|BT|RL)` alternation
58
- * (case-insensitively), so the group always participates in the match in
59
- * practice — but that's a regex-structure guarantee the type checker can't
60
- * see across the call site. Validating `undefined` here, instead of
61
- * asserting non-null at each call site, turns a hypothetical violation into
62
- * a clear, descriptive error rather than a raw `undefined` crash.
63
- */
64
- export function toDirection(raw: string | undefined): Direction {
65
- const upper = raw?.toUpperCase()
66
- if (upper === undefined || !isDirection(upper)) {
67
- throw new Error(`Invalid direction: "${raw}"`)
68
- }
69
- return upper
70
- }
51
+ // `toDirection` used to be defined here, with this file as its only caller.
52
+ // #624 gave it a second caller — `packages/mermaid-parser/src/er/parser.ts`,
53
+ // which cannot import this umbrella file without creating a cycle
54
+ // (mermaid-parser -> umbrella -> mermaid-parser) — so it moved to
55
+ // `packages/core/src/direction.ts` alongside `isDirection`, for the same
56
+ // reason that one moved under #625. Re-exported here so existing importers
57
+ // of `toDirection` from `./parser.ts` (this file's own tests included) keep
58
+ // working unchanged.
59
+ export { toDirection } from '@zombie-mermaid/core'
71
60
 
72
61
  /**
73
62
  * All diagram-type headers this library recognizes, for the "supported
@@ -103,6 +92,75 @@ function suggestedHeaderFor(header: string): string | undefined {
103
92
  return undefined
104
93
  }
105
94
 
95
+ /**
96
+ * Matches the start of a statement that continues the *previous* one's edge
97
+ * chain rather than beginning a new one: Mermaid lets a vertex-chain
98
+ * statement break across lines, with the link operator leading the next
99
+ * line — e.g.
100
+ *
101
+ * start([Start])
102
+ * ==> green([Change some code])
103
+ * ==> finish([Finish])
104
+ *
105
+ * is one chained statement (`start ==> green ==> finish`), identical to
106
+ * writing it on one line. `splitStatementsByLine` only knows about newlines
107
+ * and `;` as separators, so without this it hands `parseFlowchart` three
108
+ * unrelated-looking statements — the continuation lines start with a bare
109
+ * arrow and no node group, so `parseEdgeLine` can't find a source node and
110
+ * drops them entirely (see issue mermaid-js/mermaid#6049's repro, reported
111
+ * against this parser).
112
+ *
113
+ * Covers every arrow opener `parseEdgeLine` itself recognizes (ARROW_REGEX /
114
+ * TEXT_ARROW_REGEX below): a solid/thick run (`--`, `===`), a dotted run
115
+ * (`-.`, `-.-`), a `~~~` run, each optionally preceded by a `<` marker and/or
116
+ * an edge id (`e1@-->`).
117
+ *
118
+ * Deliberately excludes the `o`/`x` start markers ARROW_REGEX also accepts
119
+ * (`o--o`, `x--x`): unlike `<`, both are also valid bare node ids, so a
120
+ * first-body-line statement like `x-->Y` would otherwise be misread as an
121
+ * `x`-marked continuation of the header and merged into it, corrupting the
122
+ * header line (`flowchart TD x-->Y`) instead of parsing `x` as its own node.
123
+ * A genuine marked-start continuation line is rare enough that losing it is
124
+ * the safer tradeoff.
125
+ */
126
+ const CONTINUATION_START_REGEX = /^(?:[\w-]+@)?<?(?:-{2,}|={2,}|-\.+-?|~{3,})/
127
+
128
+ /**
129
+ * Rejoin a continuation statement onto the one it continues.
130
+ *
131
+ * `splitStatementsByLine` groups statements by their originating physical
132
+ * line, which is what makes this safe: only the *first* statement in a
133
+ * group is eligible to merge backward into the previous group's last
134
+ * statement (a genuine multi-line continuation, see
135
+ * `CONTINUATION_START_REGEX`). A later statement in the same group got
136
+ * there via an explicit `;` on that line (`A --> B; --> C`) — that boundary
137
+ * must stay a boundary, or `--> C` would wrongly become part of the chain
138
+ * instead of the source-less fragment it actually is.
139
+ */
140
+ function mergeContinuationLines(groups: Statement[][]): Statement[] {
141
+ const merged: Statement[] = []
142
+ for (const group of groups) {
143
+ group.forEach((statement, index) => {
144
+ if (
145
+ index === 0 &&
146
+ merged.length > 0 &&
147
+ CONTINUATION_START_REGEX.test(statement.text)
148
+ ) {
149
+ // Keep the *first* line's number: a merged statement is reported at
150
+ // the line its logical statement began, not the continuation line.
151
+ const prev = merged[merged.length - 1]!
152
+ merged[merged.length - 1] = {
153
+ text: `${prev.text} ${statement.text}`,
154
+ line: prev.line,
155
+ }
156
+ } else {
157
+ merged.push(statement)
158
+ }
159
+ })
160
+ }
161
+ return merged
162
+ }
163
+
106
164
  /**
107
165
  * Parse Mermaid text into a logical graph structure.
108
166
  * Auto-detects diagram type (flowchart or state diagram).
@@ -111,23 +169,23 @@ function suggestedHeaderFor(header: string): string | undefined {
111
169
  export function parseMermaid(text: string): MermaidGraph {
112
170
  /*
113
171
  * Init directives must be read from the raw lines: `%%{init: ...}%%` begins
114
- * with `%%`, so splitStatements — which treats `%%` as a comment and
172
+ * with `%%`, so splitStatementsByLine — which treats `%%` as a comment and
115
173
  * truncates the line there — would otherwise discard it along with real
116
174
  * comments before it could be seen.
117
175
  */
118
176
  const initConfig = extractInitConfig(text.split('\n').map((l) => l.trim()))
119
177
 
120
- const lines = splitStatements(text)
178
+ const lines = mergeContinuationLines(splitStatementsByLine(text))
121
179
 
122
180
  if (lines.length === 0) {
123
181
  throw new Error('Empty mermaid diagram')
124
182
  }
125
183
 
126
184
  // Detect diagram type from header
127
- const header = lines[0]!
185
+ const headerStmt = lines[0]!
128
186
 
129
187
  // State diagram: "stateDiagram-v2" or "stateDiagram"
130
- const graph = /^stateDiagram(-v2)?\s*$/i.test(header)
188
+ const graph = /^stateDiagram(-v2)?\s*$/i.test(headerStmt.text)
131
189
  ? parseStateDiagram(lines)
132
190
  : parseFlowchart(lines)
133
191
 
@@ -139,16 +197,17 @@ export function parseMermaid(text: string): MermaidGraph {
139
197
  // Flowchart parser
140
198
  // ============================================================================
141
199
 
142
- function parseFlowchart(lines: string[]): MermaidGraph {
200
+ function parseFlowchart(lines: Statement[]): MermaidGraph {
143
201
  // parseFlowchart is only ever invoked by parseMermaid, which has already
144
202
  // verified `lines` is non-empty — but that invariant isn't visible to the
145
203
  // type checker across the function boundary, so validate it here instead
146
204
  // of asserting past it.
147
- const header = lines[0]
148
- if (header === undefined) {
205
+ const headerStmt = lines[0]
206
+ if (headerStmt === undefined) {
149
207
  /* v8 ignore next */
150
208
  throw new Error('parseFlowchart called with no lines')
151
209
  }
210
+ const header = headerStmt.text
152
211
 
153
212
  const headerMatch = header.match(
154
213
  /^(?:graph|flowchart)\s+(TD|TB|LR|BT|RL)\s*$/i,
@@ -164,8 +223,8 @@ function parseFlowchart(lines: string[]): MermaidGraph {
164
223
  const rest = partialFlowchartMatch[1]!.trim()
165
224
  throw new Error(
166
225
  rest.length > 0
167
- ? `Invalid direction "${rest}" in header "${header}". Expected one of: TD, TB, LR, BT, RL.`
168
- : `Missing direction in header "${header}". Expected e.g. "graph TD" or "flowchart LR" — one of: TD, TB, LR, BT, RL.`,
226
+ ? `Line ${headerStmt.line}: Invalid direction "${rest}" in header "${header}". Expected one of: TD, TB, LR, BT, RL.`
227
+ : `Line ${headerStmt.line}: Missing direction in header "${header}". Expected e.g. "graph TD" or "flowchart LR" — one of: TD, TB, LR, BT, RL.`,
169
228
  )
170
229
  }
171
230
 
@@ -178,7 +237,7 @@ function parseFlowchart(lines: string[]): MermaidGraph {
178
237
  ? ` Did you mean "${suggestion}"?`
179
238
  : ''
180
239
  throw new Error(
181
- `Invalid mermaid header: "${header}".${hint} Supported headers: ${SUPPORTED_HEADERS}.`,
240
+ `Line ${headerStmt.line}: Invalid mermaid header: "${header}".${hint} Supported headers: ${SUPPORTED_HEADERS}.`,
182
241
  )
183
242
  }
184
243
 
@@ -200,7 +259,8 @@ function parseFlowchart(lines: string[]): MermaidGraph {
200
259
  const subgraphStack: MermaidSubgraph[] = []
201
260
 
202
261
  for (let i = 1; i < lines.length; i++) {
203
- const line = lines[i]!
262
+ const stmt = lines[i]!
263
+ const line = stmt.text
204
264
 
205
265
  // --- classDef / class assignment / style — shared with the class-diagram
206
266
  // parser, see packages/core/src/style-directives.ts ---
@@ -313,7 +373,7 @@ function parseFlowchart(lines: string[]): MermaidGraph {
313
373
  // }
314
374
  // ============================================================================
315
375
 
316
- function parseStateDiagram(lines: string[]): MermaidGraph {
376
+ function parseStateDiagram(lines: Statement[]): MermaidGraph {
317
377
  const graph: MermaidGraph = {
318
378
  direction: 'TD',
319
379
  nodes: new Map(),
@@ -335,7 +395,8 @@ function parseStateDiagram(lines: string[]): MermaidGraph {
335
395
  let endCount = 0
336
396
 
337
397
  for (let i = 1; i < lines.length; i++) {
338
- const line = lines[i]!
398
+ const stmt = lines[i]!
399
+ const line = stmt.text
339
400
 
340
401
  // --- direction override ---
341
402
  const dirMatch = line.match(/^direction\s+(TD|TB|LR|BT|RL)\s*$/i)
@@ -803,8 +864,9 @@ function expandedNodeLabel(id: string, meta: ExpandedNodeMeta): string {
803
864
  * browser without script.
804
865
  *
805
866
  * The actual grammar and href-safety rules live in packages/core/src/click-directive.ts,
806
- * shared with the class diagram parser (src/class/parser.ts) — this is a
807
- * thin wrapper binding it to this parser's `graph.interactions` map.
867
+ * shared with the class diagram parser
868
+ * (packages/mermaid-parser/src/class/parser.ts) — this is a thin wrapper
869
+ * binding it to this parser's `graph.interactions` map.
808
870
  */
809
871
  function applyClickStatement(line: string, graph: MermaidGraph): void {
810
872
  applyClickStatementShared(line, graph.interactions)
File without changes