zombie-mermaid 2.2.3 → 2.2.6

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 (321) hide show
  1. package/README.md +4 -4
  2. package/dist/ascii.cjs +1 -11
  3. package/dist/ascii.d.cts +1 -167
  4. package/dist/ascii.d.ts +1 -167
  5. package/dist/ascii.js +1 -6591
  6. package/dist/cli.js +836 -10946
  7. package/dist/index.cjs +2 -81
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.d.cts +42 -680
  10. package/dist/index.d.ts +42 -680
  11. package/dist/index.js +408 -10002
  12. package/dist/index.js.map +1 -1
  13. package/dist/mcp.cjs +1 -17909
  14. package/dist/mcp.d.cts +1 -11
  15. package/dist/mcp.d.ts +1 -11
  16. package/dist/mcp.js +1 -17884
  17. package/package.json +29 -29
  18. package/src/__tests__/workspace-package-boundaries.test.ts +15 -16
  19. package/src/__tests__/xychart-parser-categories.test.ts +78 -0
  20. package/src/ascii-entry.ts +14 -0
  21. package/src/cli/html-viewer.ts +5 -0
  22. package/src/mcp-entry.ts +21 -0
  23. package/dist/ascii.cjs.map +0 -1
  24. package/dist/ascii.js.map +0 -1
  25. package/dist/mcp.cjs.map +0 -1
  26. package/dist/mcp.js.map +0 -1
  27. package/packages/ascii-renderer/LICENSE +0 -22
  28. package/packages/ascii-renderer/src/ansi.ts +0 -490
  29. package/packages/ascii-renderer/src/canvas.ts +0 -658
  30. package/packages/ascii-renderer/src/class-diagram.ts +0 -2001
  31. package/packages/ascii-renderer/src/converter.ts +0 -446
  32. package/packages/ascii-renderer/src/coords.ts +0 -58
  33. package/packages/ascii-renderer/src/display-width.ts +0 -151
  34. package/packages/ascii-renderer/src/draw-arrows.ts +0 -549
  35. package/packages/ascii-renderer/src/draw-boxes.ts +0 -267
  36. package/packages/ascii-renderer/src/draw-bundles.ts +0 -611
  37. package/packages/ascii-renderer/src/draw-lines.ts +0 -174
  38. package/packages/ascii-renderer/src/draw-subgraphs.ts +0 -108
  39. package/packages/ascii-renderer/src/draw.ts +0 -337
  40. package/packages/ascii-renderer/src/edge-bundling.ts +0 -435
  41. package/packages/ascii-renderer/src/edge-cell-styles.ts +0 -81
  42. package/packages/ascii-renderer/src/edge-routing.ts +0 -1049
  43. package/packages/ascii-renderer/src/er-diagram.ts +0 -1488
  44. package/packages/ascii-renderer/src/flowchart.ts +0 -94
  45. package/packages/ascii-renderer/src/grid-occupancy.ts +0 -234
  46. package/packages/ascii-renderer/src/grid.ts +0 -1267
  47. package/packages/ascii-renderer/src/hyperlinks.ts +0 -248
  48. package/packages/ascii-renderer/src/index.ts +0 -163
  49. package/packages/ascii-renderer/src/lane-search.ts +0 -68
  50. package/packages/ascii-renderer/src/multiline-utils.ts +0 -82
  51. package/packages/ascii-renderer/src/pathfinder.ts +0 -448
  52. package/packages/ascii-renderer/src/registry.ts +0 -88
  53. package/packages/ascii-renderer/src/sequence.ts +0 -1318
  54. package/packages/ascii-renderer/src/shapes/circle.ts +0 -31
  55. package/packages/ascii-renderer/src/shapes/corners.ts +0 -273
  56. package/packages/ascii-renderer/src/shapes/diamond.ts +0 -31
  57. package/packages/ascii-renderer/src/shapes/hexagon.ts +0 -31
  58. package/packages/ascii-renderer/src/shapes/index.ts +0 -123
  59. package/packages/ascii-renderer/src/shapes/rectangle.ts +0 -199
  60. package/packages/ascii-renderer/src/shapes/rounded.ts +0 -31
  61. package/packages/ascii-renderer/src/shapes/special.ts +0 -352
  62. package/packages/ascii-renderer/src/shapes/stadium.ts +0 -122
  63. package/packages/ascii-renderer/src/shapes/state.ts +0 -204
  64. package/packages/ascii-renderer/src/shapes/types.ts +0 -78
  65. package/packages/ascii-renderer/src/territory.ts +0 -136
  66. package/packages/ascii-renderer/src/types.ts +0 -454
  67. package/packages/ascii-renderer/src/validate.ts +0 -189
  68. package/packages/ascii-renderer/src/xychart.ts +0 -1085
  69. package/packages/core/LICENSE +0 -22
  70. package/packages/core/src/click-directive.ts +0 -106
  71. package/packages/core/src/color-utils.ts +0 -205
  72. package/packages/core/src/diagram-type.ts +0 -35
  73. package/packages/core/src/direction-override.ts +0 -46
  74. package/packages/core/src/direction.ts +0 -56
  75. package/packages/core/src/index.ts +0 -34
  76. package/packages/core/src/init-directive.ts +0 -248
  77. package/packages/core/src/multiline-utils.ts +0 -275
  78. package/packages/core/src/statements.ts +0 -197
  79. package/packages/core/src/style-directives.ts +0 -214
  80. package/packages/core/src/text-metrics.ts +0 -498
  81. package/packages/core/src/theme.ts +0 -696
  82. package/packages/core/src/types.ts +0 -670
  83. package/packages/mcp/LICENSE +0 -22
  84. package/packages/mcp/src/index.ts +0 -17
  85. package/packages/mcp/src/server.ts +0 -135
  86. package/packages/mcp/src/tools/check-sequence-activations.ts +0 -91
  87. package/packages/mcp/src/tools/fix-sequence-activations.ts +0 -77
  88. package/packages/mcp/src/tools/render-ascii.ts +0 -99
  89. package/packages/mcp/src/tools/render-svg.ts +0 -95
  90. package/packages/mermaid-parser/LICENSE +0 -22
  91. package/packages/mermaid-parser/src/class/format.ts +0 -15
  92. package/packages/mermaid-parser/src/class/parser.ts +0 -593
  93. package/packages/mermaid-parser/src/class/types.ts +0 -166
  94. package/packages/mermaid-parser/src/er/parser.ts +0 -286
  95. package/packages/mermaid-parser/src/er/types.ts +0 -99
  96. package/packages/mermaid-parser/src/expanded-shapes.ts +0 -376
  97. package/packages/mermaid-parser/src/index.ts +0 -48
  98. package/packages/mermaid-parser/src/sequence/activation-check.ts +0 -149
  99. package/packages/mermaid-parser/src/sequence/activation-fix.ts +0 -112
  100. package/packages/mermaid-parser/src/sequence/box-color.ts +0 -85
  101. package/packages/mermaid-parser/src/sequence/parser.ts +0 -613
  102. package/packages/mermaid-parser/src/sequence/types.ts +0 -242
  103. package/packages/mermaid-parser/src/xychart/colors.ts +0 -177
  104. package/packages/mermaid-parser/src/xychart/parser.ts +0 -203
  105. package/packages/mermaid-parser/src/xychart/types.ts +0 -150
  106. package/packages/svg-renderer/LICENSE +0 -22
  107. package/packages/svg-renderer/src/class/layout.ts +0 -360
  108. package/packages/svg-renderer/src/class/renderer.ts +0 -636
  109. package/packages/svg-renderer/src/edge-curves.ts +0 -204
  110. package/packages/svg-renderer/src/elk-instance.ts +0 -292
  111. package/packages/svg-renderer/src/er/layout.ts +0 -200
  112. package/packages/svg-renderer/src/er/renderer.ts +0 -493
  113. package/packages/svg-renderer/src/index.ts +0 -58
  114. package/packages/svg-renderer/src/layout-engine/constants.ts +0 -19
  115. package/packages/svg-renderer/src/layout-engine/edge-bundling.ts +0 -379
  116. package/packages/svg-renderer/src/layout-engine/elk-adapter-utils.ts +0 -81
  117. package/packages/svg-renderer/src/layout-engine/elk-graph-builder.ts +0 -240
  118. package/packages/svg-renderer/src/layout-engine/from-elk.ts +0 -685
  119. package/packages/svg-renderer/src/layout-engine/layer-alignment.ts +0 -174
  120. package/packages/svg-renderer/src/layout-engine/to-elk.ts +0 -695
  121. package/packages/svg-renderer/src/layout-engine.ts +0 -74
  122. package/packages/svg-renderer/src/layout.ts +0 -8
  123. package/packages/svg-renderer/src/renderer.ts +0 -1485
  124. package/packages/svg-renderer/src/resolve-colors.ts +0 -339
  125. package/packages/svg-renderer/src/sequence/layout.ts +0 -698
  126. package/packages/svg-renderer/src/sequence/renderer.ts +0 -546
  127. package/packages/svg-renderer/src/shape-clipping.ts +0 -197
  128. package/packages/svg-renderer/src/styles.ts +0 -118
  129. package/packages/svg-renderer/src/xychart/layout.ts +0 -682
  130. package/packages/svg-renderer/src/xychart/renderer.ts +0 -684
  131. package/src/__tests__/ascii-canvas-write.test.ts +0 -137
  132. package/src/__tests__/ascii-charset-border-junctions.test.ts +0 -63
  133. package/src/__tests__/ascii-cjk-width.test.ts +0 -150
  134. package/src/__tests__/ascii-class-box-occupancy.test.ts +0 -462
  135. package/src/__tests__/ascii-class-column-width-488-489.test.ts +0 -639
  136. package/src/__tests__/ascii-class-cross-level-jog-corruption.test.ts +0 -187
  137. package/src/__tests__/ascii-class-detour-label-routing-487.test.ts +0 -114
  138. package/src/__tests__/ascii-class-diagram-compartments.test.ts +0 -70
  139. package/src/__tests__/ascii-class-label-box-collision.test.ts +0 -60
  140. package/src/__tests__/ascii-class-label-row-collision-531.test.ts +0 -135
  141. package/src/__tests__/ascii-class-label-territory-row-awareness.test.ts +0 -57
  142. package/src/__tests__/ascii-class-padding.test.ts +0 -104
  143. package/src/__tests__/ascii-class-parent-alignment-971.test.ts +0 -139
  144. package/src/__tests__/ascii-class-parent-alignment-972.test.ts +0 -208
  145. package/src/__tests__/ascii-class-reciprocal-relationships-448.test.ts +0 -169
  146. package/src/__tests__/ascii-combining-mark-width.test.ts +0 -70
  147. package/src/__tests__/ascii-coords-overlay.test.ts +0 -64
  148. package/src/__tests__/ascii-decision-lr-box-start.test.ts +0 -106
  149. package/src/__tests__/ascii-display-width-unit.test.ts +0 -154
  150. package/src/__tests__/ascii-draw-arrows-coverage.test.ts +0 -171
  151. package/src/__tests__/ascii-draw-arrows-single-point-path.test.ts +0 -112
  152. package/src/__tests__/ascii-edge-bundling-rank-violation-454.test.ts +0 -72
  153. package/src/__tests__/ascii-edge-ending-glyphs.test.ts +0 -206
  154. package/src/__tests__/ascii-edge-label-diagonal-fallback-418.test.ts +0 -95
  155. package/src/__tests__/ascii-edge-routing-fixes.test.ts +0 -178
  156. package/src/__tests__/ascii-edge-routing-single-point-path.test.ts +0 -107
  157. package/src/__tests__/ascii-edge-styles.test.ts +0 -149
  158. package/src/__tests__/ascii-emoji-cluster-width.test.ts +0 -101
  159. package/src/__tests__/ascii-er-box-occupancy.test.ts +0 -251
  160. package/src/__tests__/ascii-er-cardinality.test.ts +0 -40
  161. package/src/__tests__/ascii-er-corner-glyphs.test.ts +0 -249
  162. package/src/__tests__/ascii-er-jog-stray-line.test.ts +0 -111
  163. package/src/__tests__/ascii-er-label-padding.test.ts +0 -118
  164. package/src/__tests__/ascii-er-padding.test.ts +0 -114
  165. package/src/__tests__/ascii-er-relationship-label-corruption-350.test.ts +0 -458
  166. package/src/__tests__/ascii-er-relationship-overwrite.test.ts +0 -325
  167. package/src/__tests__/ascii-er-stray-connectors.test.ts +0 -347
  168. package/src/__tests__/ascii-er-unrelated-stem-separation-411.test.ts +0 -98
  169. package/src/__tests__/ascii-er-vertical-one-marker.test.ts +0 -110
  170. package/src/__tests__/ascii-label-line-terminal-fallback.test.ts +0 -172
  171. package/src/__tests__/ascii-lane-search.test.ts +0 -207
  172. package/src/__tests__/ascii-multibox-cjk-width.test.ts +0 -184
  173. package/src/__tests__/ascii-multiline.test.ts +0 -291
  174. package/src/__tests__/ascii-padding-edge-cases.test.ts +0 -154
  175. package/src/__tests__/ascii-pathfinder-route-edge.test.ts +0 -194
  176. package/src/__tests__/ascii-sequence-alt-else-label.test.ts +0 -236
  177. package/src/__tests__/ascii-sequence-block-wall-clearance.test.ts +0 -217
  178. package/src/__tests__/ascii-sequence-box-group.test.ts +0 -159
  179. package/src/__tests__/ascii-sequence-cjk-width.test.ts +0 -235
  180. package/src/__tests__/ascii-sequence-create-destroy.test.ts +0 -114
  181. package/src/__tests__/ascii-sequence-form-invariants.test.ts +0 -432
  182. package/src/__tests__/ascii-sequence-mermaid-parity.test.ts +0 -219
  183. package/src/__tests__/ascii-sequence-notes.test.ts +0 -61
  184. package/src/__tests__/ascii-sequence-padding.test.ts +0 -119
  185. package/src/__tests__/ascii-sequence-self-arrow.test.ts +0 -206
  186. package/src/__tests__/ascii-shape-diamond.test.ts +0 -38
  187. package/src/__tests__/ascii-shape-rectangle.test.ts +0 -258
  188. package/src/__tests__/ascii-shape-rounded.test.ts +0 -36
  189. package/src/__tests__/ascii-shapes-circle.test.ts +0 -41
  190. package/src/__tests__/ascii-shapes-hexagon.test.ts +0 -42
  191. package/src/__tests__/ascii-shapes-special.test.ts +0 -349
  192. package/src/__tests__/ascii-shapes-stadium.test.ts +0 -217
  193. package/src/__tests__/ascii-shapes-state.test.ts +0 -234
  194. package/src/__tests__/ascii-state-bidirectional-label-swap-530.test.ts +0 -130
  195. package/src/__tests__/ascii-subgraph-direction-honored-445.test.ts +0 -90
  196. package/src/__tests__/ascii-subgraph-label-border-clip.test.ts +0 -152
  197. package/src/__tests__/ascii-subgraph-title-padding.test.ts +0 -77
  198. package/src/__tests__/ascii-territory-unit.test.ts +0 -219
  199. package/src/__tests__/ascii-validate.test.ts +0 -220
  200. package/src/__tests__/ascii.test.ts +0 -328
  201. package/src/__tests__/box-color.test.ts +0 -80
  202. package/src/__tests__/class-arrow-directions.test.ts +0 -505
  203. package/src/__tests__/click-directive.test.ts +0 -63
  204. package/src/__tests__/color-utils.test.ts +0 -186
  205. package/src/__tests__/diagram-type.test.ts +0 -28
  206. package/src/__tests__/draw-lines.test.ts +0 -93
  207. package/src/__tests__/edge-cell-styles.test.ts +0 -180
  208. package/src/__tests__/elk-adapter-utils.test.ts +0 -166
  209. package/src/__tests__/grid-occupancy.test.ts +0 -240
  210. package/src/__tests__/helpers/ascii-form.ts +0 -142
  211. package/src/__tests__/helpers/terminal-display-width.ts +0 -74
  212. package/src/__tests__/mcp-check-sequence-activations-tool.test.ts +0 -85
  213. package/src/__tests__/mcp-fix-sequence-activations-tool.test.ts +0 -134
  214. package/src/__tests__/mcp-server.test.ts +0 -163
  215. package/src/__tests__/pathfinder.test.ts +0 -246
  216. package/src/__tests__/sequence-activation-fix.test.ts +0 -91
  217. package/src/__tests__/testdata/ascii/ampersand_lhs.txt +0 -18
  218. package/src/__tests__/testdata/ascii/ampersand_lhs_and_rhs.txt +0 -18
  219. package/src/__tests__/testdata/ascii/ampersand_rhs.txt +0 -18
  220. package/src/__tests__/testdata/ascii/ampersand_td_fanin.txt +0 -18
  221. package/src/__tests__/testdata/ascii/ampersand_td_fanout.txt +0 -18
  222. package/src/__tests__/testdata/ascii/ampersand_without_edge.txt +0 -18
  223. package/src/__tests__/testdata/ascii/back_reference_from_child.txt +0 -10
  224. package/src/__tests__/testdata/ascii/backlink_from_bottom.txt +0 -22
  225. package/src/__tests__/testdata/ascii/backlink_from_top.txt +0 -22
  226. package/src/__tests__/testdata/ascii/backlink_with_short_y_padding.txt +0 -20
  227. package/src/__tests__/testdata/ascii/cls_all_relationships.txt +0 -19
  228. package/src/__tests__/testdata/ascii/cls_annotation.txt +0 -29
  229. package/src/__tests__/testdata/ascii/cls_association.txt +0 -14
  230. package/src/__tests__/testdata/ascii/cls_basic.txt +0 -15
  231. package/src/__tests__/testdata/ascii/cls_dependency.txt +0 -14
  232. package/src/__tests__/testdata/ascii/cls_inheritance.txt +0 -20
  233. package/src/__tests__/testdata/ascii/cls_methods.txt +0 -21
  234. package/src/__tests__/testdata/ascii/comments.txt +0 -23
  235. package/src/__tests__/testdata/ascii/custom_padding.txt +0 -10
  236. package/src/__tests__/testdata/ascii/duplicate_labels.txt +0 -19
  237. package/src/__tests__/testdata/ascii/er_attributes.txt +0 -21
  238. package/src/__tests__/testdata/ascii/er_basic.txt +0 -8
  239. package/src/__tests__/testdata/ascii/er_identifying.txt +0 -18
  240. package/src/__tests__/testdata/ascii/flowchart_tb_simple.txt +0 -29
  241. package/src/__tests__/testdata/ascii/graph_bt_direction.txt +0 -28
  242. package/src/__tests__/testdata/ascii/graph_tb_direction.txt +0 -26
  243. package/src/__tests__/testdata/ascii/nested_subgraphs_with_labels.txt +0 -36
  244. package/src/__tests__/testdata/ascii/preserve_order_of_definition.txt +0 -23
  245. package/src/__tests__/testdata/ascii/self_reference.txt +0 -10
  246. package/src/__tests__/testdata/ascii/self_reference_with_edge.txt +0 -10
  247. package/src/__tests__/testdata/ascii/seq_basic.txt +0 -17
  248. package/src/__tests__/testdata/ascii/seq_multiple_messages.txt +0 -25
  249. package/src/__tests__/testdata/ascii/seq_self_message.txt +0 -18
  250. package/src/__tests__/testdata/ascii/single_node.txt +0 -8
  251. package/src/__tests__/testdata/ascii/single_node_longer_name.txt +0 -8
  252. package/src/__tests__/testdata/ascii/subgraph_complex_mixed.txt +0 -38
  253. package/src/__tests__/testdata/ascii/subgraph_complex_nested.txt +0 -49
  254. package/src/__tests__/testdata/ascii/subgraph_direction_override.txt +0 -47
  255. package/src/__tests__/testdata/ascii/subgraph_empty.txt +0 -10
  256. package/src/__tests__/testdata/ascii/subgraph_mixed_nodes.txt +0 -20
  257. package/src/__tests__/testdata/ascii/subgraph_mixed_nodes_td.txt +0 -48
  258. package/src/__tests__/testdata/ascii/subgraph_multiple_edges.txt +0 -32
  259. package/src/__tests__/testdata/ascii/subgraph_multiple_nodes.txt +0 -16
  260. package/src/__tests__/testdata/ascii/subgraph_nested.txt +0 -24
  261. package/src/__tests__/testdata/ascii/subgraph_nested_with_external.txt +0 -30
  262. package/src/__tests__/testdata/ascii/subgraph_node_outside_lr.txt +0 -17
  263. package/src/__tests__/testdata/ascii/subgraph_single_node.txt +0 -16
  264. package/src/__tests__/testdata/ascii/subgraph_td_direction.txt +0 -26
  265. package/src/__tests__/testdata/ascii/subgraph_td_multiple.txt +0 -44
  266. package/src/__tests__/testdata/ascii/subgraph_td_multiple_paddingy.txt +0 -42
  267. package/src/__tests__/testdata/ascii/subgraph_three_levels_nested.txt +0 -32
  268. package/src/__tests__/testdata/ascii/subgraph_three_separate.txt +0 -24
  269. package/src/__tests__/testdata/ascii/subgraph_two_separate.txt +0 -20
  270. package/src/__tests__/testdata/ascii/subgraph_with_labels.txt +0 -20
  271. package/src/__tests__/testdata/ascii/three_nodes.txt +0 -9
  272. package/src/__tests__/testdata/ascii/three_nodes_single_line.txt +0 -8
  273. package/src/__tests__/testdata/ascii/two_layer_single_graph.txt +0 -19
  274. package/src/__tests__/testdata/ascii/two_layer_single_graph_longer_names.txt +0 -19
  275. package/src/__tests__/testdata/ascii/two_nodes_linked.txt +0 -8
  276. package/src/__tests__/testdata/ascii/two_nodes_longer_names.txt +0 -8
  277. package/src/__tests__/testdata/ascii/two_root_nodes.txt +0 -19
  278. package/src/__tests__/testdata/ascii/two_root_nodes_longer_names.txt +0 -19
  279. package/src/__tests__/testdata/ascii/two_single_root_nodes.txt +0 -19
  280. package/src/__tests__/testdata/unicode/ampersand_lhs.txt +0 -18
  281. package/src/__tests__/testdata/unicode/ampersand_lhs_and_rhs.txt +0 -18
  282. package/src/__tests__/testdata/unicode/ampersand_rhs.txt +0 -18
  283. package/src/__tests__/testdata/unicode/ampersand_without_edge.txt +0 -18
  284. package/src/__tests__/testdata/unicode/back_reference_from_child.txt +0 -10
  285. package/src/__tests__/testdata/unicode/backlink_from_bottom.txt +0 -22
  286. package/src/__tests__/testdata/unicode/backlink_from_top.txt +0 -22
  287. package/src/__tests__/testdata/unicode/cls_all_relationships.txt +0 -19
  288. package/src/__tests__/testdata/unicode/cls_annotation.txt +0 -29
  289. package/src/__tests__/testdata/unicode/cls_association.txt +0 -14
  290. package/src/__tests__/testdata/unicode/cls_basic.txt +0 -15
  291. package/src/__tests__/testdata/unicode/cls_dependency.txt +0 -14
  292. package/src/__tests__/testdata/unicode/cls_inheritance.txt +0 -20
  293. package/src/__tests__/testdata/unicode/cls_methods.txt +0 -21
  294. package/src/__tests__/testdata/unicode/comments.txt +0 -23
  295. package/src/__tests__/testdata/unicode/duplicate_labels.txt +0 -19
  296. package/src/__tests__/testdata/unicode/er_attributes.txt +0 -21
  297. package/src/__tests__/testdata/unicode/er_basic.txt +0 -8
  298. package/src/__tests__/testdata/unicode/er_identifying.txt +0 -18
  299. package/src/__tests__/testdata/unicode/graph_bt_direction.txt +0 -28
  300. package/src/__tests__/testdata/unicode/preserve_order_of_definition.txt +0 -23
  301. package/src/__tests__/testdata/unicode/self_reference.txt +0 -10
  302. package/src/__tests__/testdata/unicode/self_reference_with_edge.txt +0 -10
  303. package/src/__tests__/testdata/unicode/seq_basic.txt +0 -17
  304. package/src/__tests__/testdata/unicode/seq_multiple_messages.txt +0 -25
  305. package/src/__tests__/testdata/unicode/seq_self_message.txt +0 -18
  306. package/src/__tests__/testdata/unicode/single_node.txt +0 -8
  307. package/src/__tests__/testdata/unicode/single_node_longer_name.txt +0 -8
  308. package/src/__tests__/testdata/unicode/three_nodes.txt +0 -9
  309. package/src/__tests__/testdata/unicode/three_nodes_single_line.txt +0 -8
  310. package/src/__tests__/testdata/unicode/two_layer_single_graph.txt +0 -19
  311. package/src/__tests__/testdata/unicode/two_layer_single_graph_longer_names.txt +0 -19
  312. package/src/__tests__/testdata/unicode/two_nodes_linked.txt +0 -8
  313. package/src/__tests__/testdata/unicode/two_nodes_longer_names.txt +0 -8
  314. package/src/__tests__/testdata/unicode/two_root_nodes.txt +0 -19
  315. package/src/__tests__/testdata/unicode/two_root_nodes_longer_names.txt +0 -19
  316. package/src/__tests__/testdata/unicode/two_single_root_nodes.txt +0 -19
  317. package/src/__tests__/text-metrics.test.ts +0 -473
  318. package/src/__tests__/theme-palette-contrast.test.ts +0 -84
  319. package/src/__tests__/theme.test.ts +0 -132
  320. package/src/__tests__/xychart-ascii.test.ts +0 -376
  321. package/src/__tests__/xychart-colors.test.ts +0 -149
@@ -1,104 +0,0 @@
1
- // ============================================================================
2
- // ASCII class diagram padding tests (issue #343)
3
- //
4
- // `-x`/`-y`/`-p` (AsciiRenderOptions.paddingX/paddingY/boxBorderPadding)
5
- // previously only affected the flowchart/state grid layout — class diagrams
6
- // ignored them entirely (hGap/vGap were fixed constants, and drawMultiBox
7
- // was always called with its implicit default padding). This file verifies
8
- // the fix, and that a render with no explicit padding option still renders
9
- // byte-for-byte identical to before the fix (see the DEFAULT_PADDING_*
10
- // comment in src/ascii/types.ts for why that matters).
11
- // ============================================================================
12
-
13
- import { describe, it, expect } from 'vitest'
14
- import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
15
-
16
- // Two independent, same-level classes — exercises the horizontal gap.
17
- const SIDE_BY_SIDE = `classDiagram
18
- class Foo
19
- class Bar`
20
-
21
- // A parent/child pair — exercises the vertical gap between levels.
22
- const STACKED = `classDiagram
23
- class Animal
24
- class Dog
25
- Animal <|-- Dog`
26
-
27
- function colOf(ascii: string, lineIndex: number, needle: string): number {
28
- const line = ascii.split('\n')[lineIndex]
29
- if (line === undefined) throw new Error(`no line ${lineIndex}`)
30
- const idx = line.indexOf(needle)
31
- if (idx === -1) throw new Error(`"${needle}" not found on line ${lineIndex}`)
32
- return idx
33
- }
34
-
35
- function lineCount(ascii: string): number {
36
- return ascii.split('\n').filter((l) => l.length > 0).length
37
- }
38
-
39
- function borderWidth(ascii: string, lineIndex: number): number {
40
- const line = ascii.split('\n')[lineIndex]
41
- const match = line ? /\+-+\+/.exec(line) : null
42
- if (!match) throw new Error(`no border run on line ${lineIndex}: ${line}`)
43
- return match[0].length
44
- }
45
-
46
- describe('ASCII class diagrams — padding (issue #343)', () => {
47
- it('renders identically with no padding options and with explicit defaults', () => {
48
- const withoutOptions = renderMermaidASCII(SIDE_BY_SIDE, {
49
- useAscii: true,
50
- })
51
- const withDefaults = renderMermaidASCII(SIDE_BY_SIDE, {
52
- useAscii: true,
53
- paddingX: 5,
54
- paddingY: 5,
55
- boxBorderPadding: 1,
56
- })
57
- expect(withDefaults).toBe(withoutOptions)
58
- })
59
-
60
- it('paddingX widens the gap between same-level class boxes', () => {
61
- const base = renderMermaidASCII(SIDE_BY_SIDE, { useAscii: true })
62
- const wide = renderMermaidASCII(SIDE_BY_SIDE, {
63
- useAscii: true,
64
- paddingX: 25,
65
- })
66
- const baseCol = colOf(base, 1, '| Bar |')
67
- const wideCol = colOf(wide, 1, '| Bar |')
68
- expect(wideCol).toBeGreaterThan(baseCol)
69
- const mid = renderMermaidASCII(SIDE_BY_SIDE, {
70
- useAscii: true,
71
- paddingX: 15,
72
- })
73
- const midCol = colOf(mid, 1, '| Bar |')
74
- expect(midCol - baseCol).toBe(wideCol - midCol)
75
- })
76
-
77
- it('a very small paddingX tightens the gap below the default', () => {
78
- const base = renderMermaidASCII(SIDE_BY_SIDE, { useAscii: true })
79
- const tight = renderMermaidASCII(SIDE_BY_SIDE, {
80
- useAscii: true,
81
- paddingX: -10,
82
- })
83
- expect(colOf(tight, 1, '| Bar |')).toBeLessThan(colOf(base, 1, '| Bar |'))
84
- })
85
-
86
- it('paddingY widens the vertical gap between inheritance levels', () => {
87
- const base = renderMermaidASCII(STACKED, { useAscii: true })
88
- const tall = renderMermaidASCII(STACKED, { useAscii: true, paddingY: 25 })
89
- expect(lineCount(tall)).toBeGreaterThan(lineCount(base))
90
- const mid = renderMermaidASCII(STACKED, { useAscii: true, paddingY: 15 })
91
- expect(lineCount(mid) - lineCount(base)).toBe(
92
- lineCount(tall) - lineCount(mid),
93
- )
94
- })
95
-
96
- it('boxBorderPadding widens class boxes by exactly 2 columns per unit', () => {
97
- const base = renderMermaidASCII(SIDE_BY_SIDE, { useAscii: true })
98
- const padded = renderMermaidASCII(SIDE_BY_SIDE, {
99
- useAscii: true,
100
- boxBorderPadding: 4,
101
- })
102
- expect(borderWidth(padded, 0) - borderWidth(base, 0)).toBe(6)
103
- })
104
- })
@@ -1,139 +0,0 @@
1
- /**
2
- * Regression tests for issue #971 — "ASCII class-diagram layout: single-
3
- * parent x-alignment," the first implementation stage of #964's fix
4
- * (docs/decisions/ascii-class-diagram-x-coordinate-assignment-970.md).
5
- *
6
- * Before this fix, `class-diagram.ts` packed each level's classes strictly
7
- * left-to-right in declaration order, with no reference to any parent's
8
- * column — a level with exactly one occupant always landed at column 0,
9
- * even when its real parent sat far to the right. This fix aligns a
10
- * "singleton block" (no sibling at its level shares its exact parent-id
11
- * set) with exactly one qualifying (strictly-shallower) parent under that
12
- * parent's own box center instead. Every other shape (no parents, an
13
- * all-same-level/rootless-cycle parent set, or more than one class sharing
14
- * a parent set) is out of scope here — it keeps its pre-fix left-to-right
15
- * position, tracked separately by issue #972.
16
- */
17
-
18
- import { describe, it, expect } from 'vitest'
19
- import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
20
- import { findBoxRect } from './helpers/ascii-form.ts'
21
-
22
- describe('ASCII class diagram — single-parent x-alignment (issue #971)', () => {
23
- it("#964's exact repro: a lone child aligns under its real parent's center, not the leftmost column", () => {
24
- const src = `classDiagram
25
- class Left
26
- class TallMid {
27
- +String b0
28
- +String b1
29
- +String b2
30
- +String b3
31
- +String b4
32
- +String b5
33
- }
34
- class RightSrc
35
- class Kid
36
- RightSrc --> Kid`
37
- const ascii = renderMermaidASCII(src, { useAscii: true })
38
-
39
- const rightSrc = findBoxRect(ascii, 'RightSrc')
40
- const kid = findBoxRect(ascii, 'Kid')
41
- const rightSrcCenter =
42
- rightSrc.x0 + Math.floor((rightSrc.x1 - rightSrc.x0) / 2)
43
- const kidCenter = kid.x0 + Math.floor((kid.x1 - kid.x0) / 2)
44
-
45
- // Kid's box center lands on (or within 1 cell of, for odd-width
46
- // rounding) RightSrc's box center -- not at column 0, where every
47
- // sole-occupant level used to land regardless of its real parent.
48
- expect(Math.abs(kidCenter - rightSrcCenter)).toBeLessThanOrEqual(1)
49
- expect(kid.x0).toBeGreaterThan(0)
50
-
51
- // Left is the leftmost root and must stay exactly where declaration
52
- // order has always put it -- this fix only ever moves a class that has
53
- // a real single parent to align to.
54
- const left = findBoxRect(ascii, 'Left')
55
- expect(left.x0).toBe(0)
56
- })
57
-
58
- it('a root class with no parent at all is unaffected', () => {
59
- const src = `classDiagram
60
- class Lonely`
61
- const ascii = renderMermaidASCII(src, { useAscii: true })
62
- const lonely = findBoxRect(ascii, 'Lonely')
63
- expect(lonely.x0).toBe(0)
64
- })
65
-
66
- it('a class whose only parent edges are same-level (a rootless relationship cycle) is unaffected', () => {
67
- // A -> B -> C -> A has no external root: the level-BFS puts every
68
- // member at level 0 together, but the `parents` map still records
69
- // each one's in-cycle predecessor. That predecessor is same-level, not
70
- // strictly shallower, so it doesn't qualify -- every member keeps its
71
- // plain declaration-order position, same as before this fix.
72
- const src = `classDiagram
73
- class A
74
- class B
75
- class C
76
- A --> B
77
- B --> C
78
- C --> A`
79
- const ascii = renderMermaidASCII(src, { useAscii: true })
80
- const a = findBoxRect(ascii, 'A')
81
- const b = findBoxRect(ascii, 'B')
82
- const c = findBoxRect(ascii, 'C')
83
- expect(a.x0).toBe(0)
84
- expect(a.x0).toBeLessThan(b.x0)
85
- expect(b.x0).toBeLessThan(c.x0)
86
- })
87
-
88
- // Two children sharing the exact same single parent are a *multi-member*
89
- // block -- explicitly out of #971's scope (see #972) -- so this sample
90
- // must render byte-for-byte the way it always has. Chosen because
91
- // docs/decisions/ascii-class-diagram-x-coordinate-assignment-970.md
92
- // names this exact samples-data.ts sample ("Class: Inheritance (<|--)")
93
- // as one it verified stays unchanged.
94
- it('an existing catalog sample with a multi-child parent (Class: Inheritance) keeps its exact current positions', () => {
95
- const src = `classDiagram
96
- class Animal {
97
- +String name
98
- +eat() void
99
- }
100
- class Dog {
101
- +String breed
102
- +bark() void
103
- }
104
- class Cat {
105
- +bool isIndoor
106
- +meow() void
107
- }
108
- Animal <|-- Dog
109
- Animal <|-- Cat`
110
- const ascii = renderMermaidASCII(src, { useAscii: true })
111
- const animal = findBoxRect(ascii, 'Animal')
112
- const dog = findBoxRect(ascii, 'Dog')
113
- const cat = findBoxRect(ascii, 'Cat')
114
- expect(animal).toEqual({ x0: 0, x1: 17, y0: 0, y1: 6 })
115
- expect(dog).toEqual({ x0: 0, x1: 18, y0: 10, y1: 16 })
116
- expect(cat).toEqual({ x0: 23, x1: 42, y0: 10, y1: 16 })
117
- })
118
-
119
- it('two independent single-parent children at the same level both align, and compaction keeps them from overlapping', () => {
120
- // ParentA and ParentB are both roots; KidA is ParentA's only child,
121
- // KidB is ParentB's only child. Each is its own singleton block with
122
- // exactly one qualifying parent, so both get a real desired center --
123
- // this exercises the compaction pass itself (#971 must implement it
124
- // for every block shape, not just multi-parent ones): two different
125
- // singleton blocks can still want colliding desired positions.
126
- const src = `classDiagram
127
- class ParentA
128
- class ParentB
129
- class KidA
130
- class KidB
131
- ParentA --> KidA
132
- ParentB --> KidB`
133
- const ascii = renderMermaidASCII(src, { useAscii: true })
134
- const kidA = findBoxRect(ascii, 'KidA')
135
- const kidB = findBoxRect(ascii, 'KidB')
136
- // Declaration order is preserved -- KidA never lands right of KidB.
137
- expect(kidA.x1).toBeLessThan(kidB.x0)
138
- })
139
- })
@@ -1,208 +0,0 @@
1
- /**
2
- * Regression tests for issue #972 — "ASCII class-diagram layout:
3
- * multi-parent / overlap resolution," the second implementation stage of
4
- * #964's fix (docs/decisions/ascii-class-diagram-x-coordinate-assignment-970.md),
5
- * building on #971's single-parent alignment + universal compaction pass.
6
- *
7
- * #971 only computed a real desired position for a *singleton* block (no
8
- * sibling at its level shares its exact parent-id set) with exactly one
9
- * qualifying (strictly-shallower) parent. This fix adds the remaining
10
- * block shapes #970's decision named: a block of more than one class
11
- * sharing one qualifying-parent-set spreads evenly around that shared
12
- * center; a block with more than one qualifying parent centers on the
13
- * mean of their centers. Both reuse #971's exact compaction pass
14
- * unchanged, which already handles "an aligned position collides with a
15
- * sibling" — #972 does not add new nudging logic, only new
16
- * desired-position computations for `if (qualifying.length === 0)` this
17
- * pass now escapes into.
18
- */
19
-
20
- import { describe, it, expect } from 'vitest'
21
- import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
22
- import { findBoxRect, rectsOverlap } from './helpers/ascii-form.ts'
23
-
24
- function boxCenter(rect: { x0: number; x1: number }): number {
25
- return rect.x0 + Math.floor((rect.x1 - rect.x0 + 1) / 2)
26
- }
27
-
28
- describe('ASCII class diagram — multi-parent / overlap resolution (issue #972)', () => {
29
- it('two children of the same parent spread evenly around its center, not packed from column 0', () => {
30
- // WidePadding gives Animal real room on both sides -- proves genuine
31
- // symmetric spreading, not just an edge-of-canvas clamp coincidence.
32
- const src = `classDiagram
33
- class WidePadding {
34
- +String p0
35
- +String p1
36
- +String p2
37
- }
38
- class Animal
39
- class Dog
40
- class Cat
41
- Animal <|-- Dog
42
- Animal <|-- Cat`
43
- const ascii = renderMermaidASCII(src, { useAscii: true })
44
- const animal = findBoxRect(ascii, 'Animal')
45
- const dog = findBoxRect(ascii, 'Dog')
46
- const cat = findBoxRect(ascii, 'Cat')
47
-
48
- // Declaration order preserved: Dog left of Cat, neither overlapping.
49
- expect(dog.x1).toBeLessThan(cat.x0)
50
- // The pair's combined footprint centers on Animal's own center.
51
- const blockCenter = dog.x0 + Math.floor((cat.x1 - dog.x0 + 1) / 2)
52
- expect(Math.abs(blockCenter - boxCenter(animal))).toBeLessThanOrEqual(1)
53
- // Neither child sits at column 0 (the pre-#972 leftover artifact).
54
- expect(dog.x0).toBeGreaterThan(0)
55
- })
56
-
57
- it('a child with two parents at different levels centers on the mean of their centers', () => {
58
- // Controller (level 0) -> Model (level 1) -> View (level 2); View also
59
- // has a direct edge from Controller. View's qualifying parents are
60
- // both Controller and Model (both strictly shallower than View), so
61
- // its desired center is their mean -- not just Controller's alone.
62
- const src = `classDiagram
63
- class Controller {
64
- +handleInput() void
65
- }
66
- class Model {
67
- +getData() void
68
- }
69
- class View {
70
- +render() void
71
- }
72
- Controller --> Model
73
- Controller --> View
74
- Model ..> View`
75
- const ascii = renderMermaidASCII(src, { useAscii: true })
76
- const controller = findBoxRect(ascii, 'Controller')
77
- const model = findBoxRect(ascii, 'Model')
78
- const view = findBoxRect(ascii, 'View')
79
-
80
- const expectedCenter = Math.round(
81
- (boxCenter(controller) + boxCenter(model)) / 2,
82
- )
83
- expect(Math.abs(boxCenter(view) - expectedCenter)).toBeLessThanOrEqual(1)
84
- // Not simply parked back at column 0 the way an unresolved block used to be.
85
- expect(view.x0).toBeGreaterThan(0)
86
- })
87
-
88
- it('a multi-child block whose desired position collides with an earlier sibling is pushed right without overlapping it', () => {
89
- // Two parents both near the canvas's left edge: EarlyParent's own
90
- // child (EarlySibling) is placed first; WidePair's two children want
91
- // to center on WidePair, which sits close enough that their desired
92
- // block would otherwise land on top of EarlySibling. The universal
93
- // compaction pass (#971, reused unchanged by #972) must push the
94
- // whole block right of EarlySibling instead of overlapping it.
95
- const src = `classDiagram
96
- class EarlyParent
97
- class WidePair
98
- class EarlySibling
99
- class ChildA
100
- class ChildB
101
- EarlyParent --> EarlySibling
102
- WidePair --> ChildA
103
- WidePair --> ChildB`
104
- const ascii = renderMermaidASCII(src, { useAscii: true })
105
- const names = [
106
- 'EarlyParent',
107
- 'WidePair',
108
- 'EarlySibling',
109
- 'ChildA',
110
- 'ChildB',
111
- ]
112
- const rects = names.map((n) => ({ n, r: findBoxRect(ascii, n) }))
113
- for (let i = 0; i < rects.length; i++) {
114
- for (let j = i + 1; j < rects.length; j++) {
115
- expect(
116
- rectsOverlap(rects[i]!.r, rects[j]!.r),
117
- `${rects[i]!.n} and ${rects[j]!.n} boxes overlap`,
118
- ).toBe(false)
119
- }
120
- }
121
- // Declaration order preserved even after compaction pushes the block right.
122
- const earlySibling = findBoxRect(ascii, 'EarlySibling')
123
- const childA = findBoxRect(ascii, 'ChildA')
124
- expect(earlySibling.x1).toBeLessThan(childA.x0)
125
- })
126
-
127
- it('a block with no qualifying parents (a rootless cycle with two same-level "parent" edges) keeps its plain baseline position', () => {
128
- // A and B mutually reference each other with no external root: both
129
- // land at level 0, and neither's same-level "parent" edge qualifies --
130
- // #972 must not spread or converge this shape, only #971's untouched
131
- // no-resolvable-parents fallback applies.
132
- const src = `classDiagram
133
- class A
134
- class B
135
- A --> B
136
- B --> A`
137
- const ascii = renderMermaidASCII(src, { useAscii: true })
138
- const a = findBoxRect(ascii, 'A')
139
- const b = findBoxRect(ascii, 'B')
140
- expect(a.x0).toBe(0)
141
- expect(a.x1).toBeLessThan(b.x0)
142
- })
143
-
144
- // Regression for a CodeRabbit finding on #972's own PR (thread
145
- // PRRT_kwDOT5ndxc6hpu-C): two classes with no resolvable parents but the
146
- // exact same (non-qualifying) parent-id set used to be merged into one
147
- // joint placement unit the moment the *first* of them was reached in
148
- // declaration order -- silently pulling an unrelated class declared
149
- // *between* them ahead of its own position, since it hadn't been placed
150
- // yet when the merged pair's combined placement consumed the columns it
151
- // would have occupied.
152
- it('an unrelated class declared between two same-parent-set siblings with no qualifying parent keeps its own declaration-order position', () => {
153
- // Q and R share the exact same parent-id set ({P}), but P is at the
154
- // same level as Q/R (a 3-way mutual-reference cycle), so neither
155
- // qualifies -- both are "no resolvable parents" blocks on their own.
156
- // Interloper is a plain, unrelated root declared between Q and R.
157
- const src = `classDiagram
158
- class P
159
- class Q
160
- class Interloper
161
- class R
162
- P --> Q
163
- P --> R
164
- Q --> P
165
- R --> P`
166
- const ascii = renderMermaidASCII(src, { useAscii: true })
167
- const q = findBoxRect(ascii, 'Q')
168
- const interloper = findBoxRect(ascii, 'Interloper')
169
- const r = findBoxRect(ascii, 'R')
170
- // Declared order Q, Interloper, R must survive as rendered left-to-right order.
171
- expect(q.x1).toBeLessThan(interloper.x0)
172
- expect(interloper.x1).toBeLessThan(r.x0)
173
- })
174
-
175
- // Regression for a CodeRabbit finding on #972's own PR (thread
176
- // PRRT_kwDOT5ndxc6hpu-M): a multi-member block's desired left edge used
177
- // to be derived from centering the *padded slot* span (every member's
178
- // own reach padding, including the outermost edges with no neighbor to
179
- // separate from) on the shared parent center, rather than the *visible
180
- // box* span -- so a block whose first member has real reach padding
181
- // (e.g. its own outgoing relationship carries a long label) and whose
182
- // last member has none rendered visibly off-center from the parent it
183
- // was supposed to align under.
184
- it('a multi-child block with asymmetric reach padding on one child still visually centers on the shared parent', () => {
185
- const src = `classDiagram
186
- class Padding {
187
- +String p0
188
- +String p1
189
- +String p2
190
- +String p3
191
- }
192
- class Animal
193
- class Dog
194
- class Cat
195
- class SomewhereElse
196
- Animal <|-- Dog
197
- Animal <|-- Cat
198
- Dog --> SomewhereElse : a moderately long label`
199
- const ascii = renderMermaidASCII(src, { useAscii: true })
200
- const animal = findBoxRect(ascii, 'Animal')
201
- const dog = findBoxRect(ascii, 'Dog')
202
- const cat = findBoxRect(ascii, 'Cat')
203
- const visibleBlockCenter = dog.x0 + Math.floor((cat.x1 - dog.x0 + 1) / 2)
204
- expect(
205
- Math.abs(visibleBlockCenter - boxCenter(animal)),
206
- ).toBeLessThanOrEqual(1)
207
- })
208
- })
@@ -1,169 +0,0 @@
1
- /**
2
- * Regression test for #448 — "Class: MVC Architecture sample drops the
3
- * `View --> Model : reads` edge."
4
- *
5
- * Root cause: `renderClassAscii` connected every relationship's line/arrow/
6
- * label to its source and target boxes at a fixed box-center column, with
7
- * no awareness of other relationships. When two relationships connect the
8
- * same pair of classes in opposite directions (`View --> Model : reads`
9
- * alongside `Model ..> View : notifies`), both computed the identical
10
- * center column, so the later-drawn one silently overwrote the earlier
11
- * one's line, arrowhead, and label.
12
- *
13
- * The fix groups relationships by unordered class-pair and gives each
14
- * member of a multi-relationship group its own connection column. This
15
- * test exercises that grouping/column-offset logic directly — no prior
16
- * test in this repo did (verification for #448 was ad hoc/visual only via
17
- * a real-terminal capture, never committed as a vitest case), which is
18
- * exactly why this code path had gone completely uncovered.
19
- *
20
- * Uses the same source as the "Class: MVC Architecture" sample
21
- * (samples-data.ts) that the original issue was reported against — a
22
- * narrower repro with only short single-word labels and no other class
23
- * members hits an unrelated, tighter label/border collision (also
24
- * present, separately, in the pre-#448 code and out of scope here), so
25
- * this keeps the box widths the real sample has.
26
- */
27
-
28
- import { describe, it, expect } from 'vitest'
29
- import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
30
-
31
- const MVC_SOURCE = `classDiagram
32
- class Model {
33
- -data Map
34
- +getData() Map
35
- +setData(key, val) void
36
- +notify() void
37
- }
38
- class View {
39
- -model Model
40
- +render() void
41
- +update() void
42
- }
43
- class Controller {
44
- -model Model
45
- -view View
46
- +handleInput(event) void
47
- +updateModel(data) void
48
- }
49
- Controller --> Model : updates
50
- Controller --> View : refreshes
51
- View --> Model : reads
52
- Model ..> View : notifies`
53
-
54
- describe('ASCII class diagram — reciprocal relationships (issue #448)', () => {
55
- it('renders all four relationships, including both directions of the Model/View reciprocal pair', () => {
56
- const ascii = renderMermaidASCII(MVC_SOURCE, { colorMode: 'none' })
57
-
58
- for (const label of ['updates', 'refreshes', 'reads', 'notifies']) {
59
- expect(ascii).toContain(label)
60
- }
61
- })
62
-
63
- it('gives the reciprocal pair distinct connection columns instead of one overwriting the other', () => {
64
- const ascii = renderMermaidASCII(MVC_SOURCE, { colorMode: 'none' })
65
- const lines = ascii.split('\n')
66
-
67
- const readsCol = lines.find((l) => l.includes('reads'))!.indexOf('reads')
68
- const notifiesCol = lines
69
- .find((l) => l.includes('notifies'))!
70
- .indexOf('notifies')
71
- expect(readsCol).not.toBe(notifiesCol)
72
- })
73
-
74
- it('leaves a single (non-reciprocal) relationship at the plain center column', () => {
75
- const ascii = renderMermaidASCII(
76
- `classDiagram
77
- class A
78
- class B
79
- A --> B : uses`,
80
- { colorMode: 'none' },
81
- )
82
- expect(ascii).toContain('uses')
83
- })
84
- })
85
-
86
- /**
87
- * Regression test for issue #632 — a weekly form-judge audit comparing this
88
- * repo's ASCII output against real mermaid.js SVG flagged the "Class:
89
- * Relationship Labels" sample (samples-data.ts): `Teacher --> Course` and
90
- * `Student --> Course` are two *distinct* pairs (not a reciprocal pair
91
- * between the same two classes, which #448 above already covers) that both
92
- * terminate at the same target, `Course`.
93
- *
94
- * Root cause: `pairGroups` (the #448 fix, keyed by the unordered
95
- * `[from, to]` pair) only fans relationships between the exact same two
96
- * classes — it never grouped these, so both anchored at Course's identical
97
- * center column, collapsing their arrowheads onto the same cell. Since
98
- * both relationships' single horizontal jog then also landed on the exact
99
- * same row, the later-drawn label (in the separate label-drawing pass)
100
- * blotted out most of the visible line, so `Student --> Course` looked
101
- * like it terminated in blank space short of Course instead of reaching it.
102
- *
103
- * The fix (`relFromOffset`/`relToOffset` in `class-diagram.ts`) fans a
104
- * relationship at whichever single end it shares with another
105
- * relationship, even when the two relationships are between otherwise
106
- * unrelated classes — scoped to a direct, adjacent-level convergence (see
107
- * that code's comment for why a level-skipping relationship, which already
108
- * needs the separate box-collision detour routing, is excluded).
109
- */
110
- describe('ASCII class diagram — relationships converging on a shared target from different sources (issue #632)', () => {
111
- const STUDENT_COURSE_SOURCE = `classDiagram
112
- class Teacher {
113
- +String name
114
- }
115
- class Student {
116
- +String name
117
- }
118
- class Course {
119
- +String title
120
- }
121
- Teacher --> Course : teaches
122
- Student --> Course : enrolled in`
123
-
124
- it('renders both relationship labels', () => {
125
- const ascii = renderMermaidASCII(STUDENT_COURSE_SOURCE, {
126
- colorMode: 'none',
127
- })
128
- expect(ascii).toContain('teaches')
129
- expect(ascii).toContain('enrolled in')
130
- })
131
-
132
- it('draws two distinct arrowheads into Course instead of collapsing both onto one shared cell', () => {
133
- const ascii = renderMermaidASCII(STUDENT_COURSE_SOURCE, {
134
- colorMode: 'none',
135
- })
136
- // Before the fix, both relationships anchored at the exact same
137
- // column, so only a single '▼' was ever drawn for both of them
138
- // combined — the `Student --> Course` connector had no arrowhead of
139
- // its own at all.
140
- const arrowCount = (ascii.match(/▼/g) ?? []).length
141
- expect(arrowCount).toBe(2)
142
- })
143
-
144
- it('gives the two relationships distinct target columns, both landing on Course', () => {
145
- const ascii = renderMermaidASCII(STUDENT_COURSE_SOURCE, {
146
- colorMode: 'none',
147
- })
148
- const lines = ascii.split('\n')
149
- const arrowCols = lines.flatMap((line) =>
150
- [...line].map((ch, i) => (ch === '▼' ? i : -1)).filter((i) => i >= 0),
151
- )
152
- expect(arrowCols).toHaveLength(2)
153
- expect(arrowCols[0]).not.toBe(arrowCols[1])
154
-
155
- // Course's box must actually span both arrow columns — otherwise
156
- // they've merely moved apart without both still landing on the target.
157
- const courseRow = lines.findIndex((line) => line.includes('Course'))
158
- expect(courseRow).toBeGreaterThan(0)
159
- const boxRow = lines[courseRow - 1]!
160
- const boxLeft = boxRow.indexOf('┌')
161
- const boxRight = boxRow.indexOf('┐')
162
- expect(boxLeft).toBeGreaterThanOrEqual(0)
163
- expect(boxRight).toBeGreaterThan(boxLeft)
164
- for (const col of arrowCols) {
165
- expect(col).toBeGreaterThanOrEqual(boxLeft)
166
- expect(col).toBeLessThanOrEqual(boxRight)
167
- }
168
- })
169
- })