@zombie-mermaid/ascii-renderer 2.2.1

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 (232) hide show
  1. package/LICENSE +22 -0
  2. package/dist/index.cjs +8 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.cts +146 -0
  5. package/dist/index.d.ts +146 -0
  6. package/dist/index.js +5392 -0
  7. package/dist/index.js.map +1 -0
  8. package/package.json +36 -0
  9. package/src/__tests__/ascii-arrowhead-direction-1083.test.ts +51 -0
  10. package/src/__tests__/ascii-canvas-first-claim-wins-1093.test.ts +89 -0
  11. package/src/__tests__/ascii-canvas-size-offset-1093.test.ts +95 -0
  12. package/src/__tests__/ascii-canvas-write.test.ts +132 -0
  13. package/src/__tests__/ascii-chain-edge-overlap-1067.test.ts +100 -0
  14. package/src/__tests__/ascii-charset-border-junctions.test.ts +63 -0
  15. package/src/__tests__/ascii-cjk-width.test.ts +150 -0
  16. package/src/__tests__/ascii-class-box-occupancy.test.ts +462 -0
  17. package/src/__tests__/ascii-class-column-width-488-489.test.ts +639 -0
  18. package/src/__tests__/ascii-class-cross-level-jog-corruption.test.ts +187 -0
  19. package/src/__tests__/ascii-class-detour-label-routing-487.test.ts +114 -0
  20. package/src/__tests__/ascii-class-diagram-compartments.test.ts +70 -0
  21. package/src/__tests__/ascii-class-label-box-collision.test.ts +60 -0
  22. package/src/__tests__/ascii-class-label-row-collision-531.test.ts +135 -0
  23. package/src/__tests__/ascii-class-label-territory-row-awareness.test.ts +57 -0
  24. package/src/__tests__/ascii-class-padding.test.ts +104 -0
  25. package/src/__tests__/ascii-class-parent-alignment-971.test.ts +139 -0
  26. package/src/__tests__/ascii-class-parent-alignment-972.test.ts +208 -0
  27. package/src/__tests__/ascii-class-reciprocal-relationships-448.test.ts +169 -0
  28. package/src/__tests__/ascii-combining-mark-width.test.ts +70 -0
  29. package/src/__tests__/ascii-coords-overlay.test.ts +64 -0
  30. package/src/__tests__/ascii-decision-lr-box-start.test.ts +106 -0
  31. package/src/__tests__/ascii-display-width-unit.test.ts +154 -0
  32. package/src/__tests__/ascii-draw-arrows-coverage.test.ts +224 -0
  33. package/src/__tests__/ascii-draw-arrows-single-point-path.test.ts +105 -0
  34. package/src/__tests__/ascii-edge-bundling-rank-violation-454.test.ts +72 -0
  35. package/src/__tests__/ascii-edge-ending-glyphs.test.ts +206 -0
  36. package/src/__tests__/ascii-edge-label-diagonal-fallback-418.test.ts +95 -0
  37. package/src/__tests__/ascii-edge-routing-fixes.test.ts +178 -0
  38. package/src/__tests__/ascii-edge-routing-single-point-path.test.ts +103 -0
  39. package/src/__tests__/ascii-edge-style-consistency-1067.test.ts +89 -0
  40. package/src/__tests__/ascii-edge-styles.test.ts +149 -0
  41. package/src/__tests__/ascii-emoji-cluster-width.test.ts +101 -0
  42. package/src/__tests__/ascii-er-box-occupancy.test.ts +251 -0
  43. package/src/__tests__/ascii-er-cardinality.test.ts +40 -0
  44. package/src/__tests__/ascii-er-corner-glyphs.test.ts +249 -0
  45. package/src/__tests__/ascii-er-jog-stray-line.test.ts +111 -0
  46. package/src/__tests__/ascii-er-label-padding.test.ts +118 -0
  47. package/src/__tests__/ascii-er-padding.test.ts +114 -0
  48. package/src/__tests__/ascii-er-relationship-label-corruption-350.test.ts +458 -0
  49. package/src/__tests__/ascii-er-relationship-overwrite.test.ts +325 -0
  50. package/src/__tests__/ascii-er-stray-connectors.test.ts +344 -0
  51. package/src/__tests__/ascii-er-unrelated-stem-separation-411.test.ts +98 -0
  52. package/src/__tests__/ascii-er-vertical-one-marker.test.ts +110 -0
  53. package/src/__tests__/ascii-label-line-terminal-fallback.test.ts +168 -0
  54. package/src/__tests__/ascii-lane-search.test.ts +207 -0
  55. package/src/__tests__/ascii-multibox-cjk-width.test.ts +184 -0
  56. package/src/__tests__/ascii-multiline.test.ts +288 -0
  57. package/src/__tests__/ascii-padding-edge-cases.test.ts +154 -0
  58. package/src/__tests__/ascii-pathfinder-route-edge.test.ts +184 -0
  59. package/src/__tests__/ascii-sequence-alt-else-label.test.ts +236 -0
  60. package/src/__tests__/ascii-sequence-block-wall-clearance.test.ts +217 -0
  61. package/src/__tests__/ascii-sequence-box-group.test.ts +159 -0
  62. package/src/__tests__/ascii-sequence-cjk-width.test.ts +235 -0
  63. package/src/__tests__/ascii-sequence-create-destroy.test.ts +114 -0
  64. package/src/__tests__/ascii-sequence-form-invariants.test.ts +432 -0
  65. package/src/__tests__/ascii-sequence-mermaid-parity.test.ts +219 -0
  66. package/src/__tests__/ascii-sequence-notes.test.ts +61 -0
  67. package/src/__tests__/ascii-sequence-padding.test.ts +119 -0
  68. package/src/__tests__/ascii-sequence-self-arrow.test.ts +206 -0
  69. package/src/__tests__/ascii-shape-diamond.test.ts +38 -0
  70. package/src/__tests__/ascii-shape-rectangle.test.ts +258 -0
  71. package/src/__tests__/ascii-shape-rounded.test.ts +36 -0
  72. package/src/__tests__/ascii-shapes-circle.test.ts +41 -0
  73. package/src/__tests__/ascii-shapes-hexagon.test.ts +42 -0
  74. package/src/__tests__/ascii-shapes-special.test.ts +344 -0
  75. package/src/__tests__/ascii-shapes-stadium.test.ts +217 -0
  76. package/src/__tests__/ascii-shapes-state.test.ts +224 -0
  77. package/src/__tests__/ascii-state-bidirectional-label-swap-530.test.ts +130 -0
  78. package/src/__tests__/ascii-subgraph-direction-honored-445.test.ts +90 -0
  79. package/src/__tests__/ascii-subgraph-label-border-clip.test.ts +152 -0
  80. package/src/__tests__/ascii-subgraph-title-padding.test.ts +77 -0
  81. package/src/__tests__/ascii-territory-unit.test.ts +219 -0
  82. package/src/__tests__/ascii-validate.test.ts +220 -0
  83. package/src/__tests__/ascii.test.ts +325 -0
  84. package/src/__tests__/class-arrow-directions.test.ts +505 -0
  85. package/src/__tests__/draw-lines.test.ts +93 -0
  86. package/src/__tests__/edge-cell-styles.test.ts +278 -0
  87. package/src/__tests__/grid-occupancy.test.ts +240 -0
  88. package/src/__tests__/helpers/ascii-form.ts +142 -0
  89. package/src/__tests__/helpers/terminal-display-width.ts +74 -0
  90. package/src/__tests__/pathfinder.test.ts +239 -0
  91. package/src/__tests__/testdata/ascii/ampersand_lhs.txt +18 -0
  92. package/src/__tests__/testdata/ascii/ampersand_lhs_and_rhs.txt +18 -0
  93. package/src/__tests__/testdata/ascii/ampersand_rhs.txt +18 -0
  94. package/src/__tests__/testdata/ascii/ampersand_td_fanin.txt +18 -0
  95. package/src/__tests__/testdata/ascii/ampersand_td_fanout.txt +18 -0
  96. package/src/__tests__/testdata/ascii/ampersand_without_edge.txt +18 -0
  97. package/src/__tests__/testdata/ascii/back_reference_from_child.txt +10 -0
  98. package/src/__tests__/testdata/ascii/backlink_from_bottom.txt +22 -0
  99. package/src/__tests__/testdata/ascii/backlink_from_top.txt +22 -0
  100. package/src/__tests__/testdata/ascii/backlink_with_short_y_padding.txt +20 -0
  101. package/src/__tests__/testdata/ascii/cls_all_relationships.txt +19 -0
  102. package/src/__tests__/testdata/ascii/cls_annotation.txt +29 -0
  103. package/src/__tests__/testdata/ascii/cls_association.txt +14 -0
  104. package/src/__tests__/testdata/ascii/cls_basic.txt +15 -0
  105. package/src/__tests__/testdata/ascii/cls_dependency.txt +14 -0
  106. package/src/__tests__/testdata/ascii/cls_inheritance.txt +20 -0
  107. package/src/__tests__/testdata/ascii/cls_methods.txt +21 -0
  108. package/src/__tests__/testdata/ascii/comments.txt +23 -0
  109. package/src/__tests__/testdata/ascii/custom_padding.txt +10 -0
  110. package/src/__tests__/testdata/ascii/duplicate_labels.txt +19 -0
  111. package/src/__tests__/testdata/ascii/er_attributes.txt +21 -0
  112. package/src/__tests__/testdata/ascii/er_basic.txt +8 -0
  113. package/src/__tests__/testdata/ascii/er_identifying.txt +18 -0
  114. package/src/__tests__/testdata/ascii/flowchart_tb_simple.txt +29 -0
  115. package/src/__tests__/testdata/ascii/graph_bt_direction.txt +28 -0
  116. package/src/__tests__/testdata/ascii/graph_tb_direction.txt +26 -0
  117. package/src/__tests__/testdata/ascii/nested_subgraphs_with_labels.txt +36 -0
  118. package/src/__tests__/testdata/ascii/preserve_order_of_definition.txt +23 -0
  119. package/src/__tests__/testdata/ascii/self_reference.txt +10 -0
  120. package/src/__tests__/testdata/ascii/self_reference_with_edge.txt +10 -0
  121. package/src/__tests__/testdata/ascii/seq_basic.txt +17 -0
  122. package/src/__tests__/testdata/ascii/seq_multiple_messages.txt +25 -0
  123. package/src/__tests__/testdata/ascii/seq_self_message.txt +18 -0
  124. package/src/__tests__/testdata/ascii/single_node.txt +8 -0
  125. package/src/__tests__/testdata/ascii/single_node_longer_name.txt +8 -0
  126. package/src/__tests__/testdata/ascii/subgraph_complex_mixed.txt +38 -0
  127. package/src/__tests__/testdata/ascii/subgraph_complex_nested.txt +49 -0
  128. package/src/__tests__/testdata/ascii/subgraph_direction_override.txt +47 -0
  129. package/src/__tests__/testdata/ascii/subgraph_empty.txt +10 -0
  130. package/src/__tests__/testdata/ascii/subgraph_mixed_nodes.txt +20 -0
  131. package/src/__tests__/testdata/ascii/subgraph_mixed_nodes_td.txt +48 -0
  132. package/src/__tests__/testdata/ascii/subgraph_multiple_edges.txt +32 -0
  133. package/src/__tests__/testdata/ascii/subgraph_multiple_nodes.txt +16 -0
  134. package/src/__tests__/testdata/ascii/subgraph_nested.txt +24 -0
  135. package/src/__tests__/testdata/ascii/subgraph_nested_with_external.txt +30 -0
  136. package/src/__tests__/testdata/ascii/subgraph_node_outside_lr.txt +17 -0
  137. package/src/__tests__/testdata/ascii/subgraph_single_node.txt +16 -0
  138. package/src/__tests__/testdata/ascii/subgraph_td_direction.txt +26 -0
  139. package/src/__tests__/testdata/ascii/subgraph_td_multiple.txt +44 -0
  140. package/src/__tests__/testdata/ascii/subgraph_td_multiple_paddingy.txt +42 -0
  141. package/src/__tests__/testdata/ascii/subgraph_three_levels_nested.txt +32 -0
  142. package/src/__tests__/testdata/ascii/subgraph_three_separate.txt +24 -0
  143. package/src/__tests__/testdata/ascii/subgraph_two_separate.txt +20 -0
  144. package/src/__tests__/testdata/ascii/subgraph_with_labels.txt +20 -0
  145. package/src/__tests__/testdata/ascii/three_nodes.txt +9 -0
  146. package/src/__tests__/testdata/ascii/three_nodes_single_line.txt +8 -0
  147. package/src/__tests__/testdata/ascii/two_layer_single_graph.txt +19 -0
  148. package/src/__tests__/testdata/ascii/two_layer_single_graph_longer_names.txt +19 -0
  149. package/src/__tests__/testdata/ascii/two_nodes_linked.txt +8 -0
  150. package/src/__tests__/testdata/ascii/two_nodes_longer_names.txt +8 -0
  151. package/src/__tests__/testdata/ascii/two_root_nodes.txt +19 -0
  152. package/src/__tests__/testdata/ascii/two_root_nodes_longer_names.txt +19 -0
  153. package/src/__tests__/testdata/ascii/two_single_root_nodes.txt +19 -0
  154. package/src/__tests__/testdata/unicode/ampersand_lhs.txt +18 -0
  155. package/src/__tests__/testdata/unicode/ampersand_lhs_and_rhs.txt +18 -0
  156. package/src/__tests__/testdata/unicode/ampersand_rhs.txt +18 -0
  157. package/src/__tests__/testdata/unicode/ampersand_without_edge.txt +18 -0
  158. package/src/__tests__/testdata/unicode/back_reference_from_child.txt +10 -0
  159. package/src/__tests__/testdata/unicode/backlink_from_bottom.txt +22 -0
  160. package/src/__tests__/testdata/unicode/backlink_from_top.txt +22 -0
  161. package/src/__tests__/testdata/unicode/cls_all_relationships.txt +19 -0
  162. package/src/__tests__/testdata/unicode/cls_annotation.txt +29 -0
  163. package/src/__tests__/testdata/unicode/cls_association.txt +14 -0
  164. package/src/__tests__/testdata/unicode/cls_basic.txt +15 -0
  165. package/src/__tests__/testdata/unicode/cls_dependency.txt +14 -0
  166. package/src/__tests__/testdata/unicode/cls_inheritance.txt +20 -0
  167. package/src/__tests__/testdata/unicode/cls_methods.txt +21 -0
  168. package/src/__tests__/testdata/unicode/comments.txt +23 -0
  169. package/src/__tests__/testdata/unicode/duplicate_labels.txt +19 -0
  170. package/src/__tests__/testdata/unicode/er_attributes.txt +21 -0
  171. package/src/__tests__/testdata/unicode/er_basic.txt +8 -0
  172. package/src/__tests__/testdata/unicode/er_identifying.txt +18 -0
  173. package/src/__tests__/testdata/unicode/graph_bt_direction.txt +28 -0
  174. package/src/__tests__/testdata/unicode/preserve_order_of_definition.txt +23 -0
  175. package/src/__tests__/testdata/unicode/self_reference.txt +10 -0
  176. package/src/__tests__/testdata/unicode/self_reference_with_edge.txt +10 -0
  177. package/src/__tests__/testdata/unicode/seq_basic.txt +17 -0
  178. package/src/__tests__/testdata/unicode/seq_multiple_messages.txt +25 -0
  179. package/src/__tests__/testdata/unicode/seq_self_message.txt +18 -0
  180. package/src/__tests__/testdata/unicode/single_node.txt +8 -0
  181. package/src/__tests__/testdata/unicode/single_node_longer_name.txt +8 -0
  182. package/src/__tests__/testdata/unicode/three_nodes.txt +9 -0
  183. package/src/__tests__/testdata/unicode/three_nodes_single_line.txt +8 -0
  184. package/src/__tests__/testdata/unicode/two_layer_single_graph.txt +19 -0
  185. package/src/__tests__/testdata/unicode/two_layer_single_graph_longer_names.txt +19 -0
  186. package/src/__tests__/testdata/unicode/two_nodes_linked.txt +8 -0
  187. package/src/__tests__/testdata/unicode/two_nodes_longer_names.txt +8 -0
  188. package/src/__tests__/testdata/unicode/two_root_nodes.txt +19 -0
  189. package/src/__tests__/testdata/unicode/two_root_nodes_longer_names.txt +19 -0
  190. package/src/__tests__/testdata/unicode/two_single_root_nodes.txt +19 -0
  191. package/src/__tests__/xychart-ascii.test.ts +376 -0
  192. package/src/ansi.ts +490 -0
  193. package/src/canvas.ts +757 -0
  194. package/src/class-diagram.ts +2001 -0
  195. package/src/converter.ts +446 -0
  196. package/src/coords.ts +58 -0
  197. package/src/display-width.ts +151 -0
  198. package/src/draw-arrows.ts +593 -0
  199. package/src/draw-boxes.ts +267 -0
  200. package/src/draw-bundles.ts +611 -0
  201. package/src/draw-lines.ts +174 -0
  202. package/src/draw-subgraphs.ts +108 -0
  203. package/src/draw.ts +350 -0
  204. package/src/edge-bundling.ts +435 -0
  205. package/src/edge-cell-styles.ts +209 -0
  206. package/src/edge-routing.ts +1070 -0
  207. package/src/er-diagram.ts +1488 -0
  208. package/src/flowchart.ts +94 -0
  209. package/src/grid-occupancy.ts +234 -0
  210. package/src/grid.ts +1309 -0
  211. package/src/hyperlinks.ts +248 -0
  212. package/src/index.ts +163 -0
  213. package/src/lane-search.ts +68 -0
  214. package/src/multiline-utils.ts +82 -0
  215. package/src/pathfinder.ts +448 -0
  216. package/src/registry.ts +88 -0
  217. package/src/sequence.ts +1318 -0
  218. package/src/shapes/circle.ts +31 -0
  219. package/src/shapes/corners.ts +273 -0
  220. package/src/shapes/diamond.ts +31 -0
  221. package/src/shapes/hexagon.ts +35 -0
  222. package/src/shapes/index.ts +123 -0
  223. package/src/shapes/rectangle.ts +199 -0
  224. package/src/shapes/rounded.ts +31 -0
  225. package/src/shapes/special.ts +360 -0
  226. package/src/shapes/stadium.ts +122 -0
  227. package/src/shapes/state.ts +204 -0
  228. package/src/shapes/types.ts +78 -0
  229. package/src/territory.ts +136 -0
  230. package/src/types.ts +454 -0
  231. package/src/validate.ts +189 -0
  232. package/src/xychart.ts +1085 -0
@@ -0,0 +1,325 @@
1
+ /**
2
+ * Golden-file tests for the ASCII/Unicode renderer.
3
+ *
4
+ * Ported from AlexanderGrooff/mermaid-ascii cmd/graph_test.go.
5
+ * Each .txt file contains mermaid input above a `---` separator
6
+ * and the expected ASCII/Unicode output below it.
7
+ *
8
+ * Test data: 44 ASCII files + 22 Unicode files = 66 total.
9
+ */
10
+ import { describe, it, expect } from 'vitest'
11
+ import { renderMermaidASCII } from '@zombie-mermaid/ascii-renderer'
12
+ import { hasDiagonalLines, DIAGONAL_CHARS } from '../validate.ts'
13
+ import { readdirSync, readFileSync } from 'node:fs'
14
+ import { join, dirname } from 'node:path'
15
+ import { fileURLToPath } from 'node:url'
16
+
17
+ // ============================================================================
18
+ // Test case parser — matches Go's testutil.ReadTestCase format
19
+ // ============================================================================
20
+
21
+ interface TestCase {
22
+ mermaid: string
23
+ expected: string
24
+ paddingX: number
25
+ paddingY: number
26
+ }
27
+
28
+ /**
29
+ * Parse a golden test file into its components.
30
+ * Format:
31
+ * [paddingX=N] (optional)
32
+ * [paddingY=N] (optional)
33
+ * <mermaid code>
34
+ * ---
35
+ * <expected output>
36
+ */
37
+ function parseTestCase(content: string): TestCase {
38
+ const tc: TestCase = { mermaid: '', expected: '', paddingX: 5, paddingY: 5 }
39
+ const lines = content.split('\n')
40
+ const paddingRegex = /^(?:padding([xy]))\s*=\s*(\d+)\s*$/i
41
+
42
+ let inMermaid = true
43
+ let mermaidStarted = false
44
+ const mermaidLines: string[] = []
45
+ const expectedLines: string[] = []
46
+
47
+ for (const line of lines) {
48
+ if (line === '---') {
49
+ inMermaid = false
50
+ continue
51
+ }
52
+
53
+ if (inMermaid) {
54
+ const trimmed = line.trim()
55
+
56
+ // Before mermaid code starts, parse padding directives and skip blanks
57
+ if (!mermaidStarted) {
58
+ if (trimmed === '') continue
59
+ const match = trimmed.match(paddingRegex)
60
+ if (match) {
61
+ const value = parseInt(match[2]!, 10)
62
+ if (match[1]!.toLowerCase() === 'x') {
63
+ tc.paddingX = value
64
+ } else {
65
+ tc.paddingY = value
66
+ }
67
+ continue
68
+ }
69
+ }
70
+
71
+ mermaidStarted = true
72
+ mermaidLines.push(line)
73
+ } else {
74
+ expectedLines.push(line)
75
+ }
76
+ }
77
+
78
+ tc.mermaid = mermaidLines.join('\n') + '\n'
79
+
80
+ // Strip final trailing newline (matches Go's strings.TrimSuffix(expected, "\n"))
81
+ let expected = expectedLines.join('\n')
82
+ if (expected.endsWith('\n')) {
83
+ expected = expected.slice(0, -1)
84
+ }
85
+ tc.expected = expected
86
+
87
+ return tc
88
+ }
89
+
90
+ // ============================================================================
91
+ // Whitespace normalization — matches Go's testutil.NormalizeWhitespace
92
+ // ============================================================================
93
+
94
+ /**
95
+ * Normalize whitespace for comparison:
96
+ * - Trim trailing spaces from each line
97
+ * - Remove leading/trailing blank lines
98
+ */
99
+ function normalizeWhitespace(s: string): string {
100
+ const lines = s.split('\n')
101
+ const normalized = lines.map((l) => l.trimEnd())
102
+
103
+ // Remove leading blank lines
104
+ while (normalized.length > 0 && normalized[0] === '') {
105
+ normalized.shift()
106
+ }
107
+ // Remove trailing blank lines
108
+ while (normalized.length > 0 && normalized[normalized.length - 1] === '') {
109
+ normalized.pop()
110
+ }
111
+
112
+ return normalized.join('\n')
113
+ }
114
+
115
+ /** Replace spaces with middle dots for clearer diff output. */
116
+ function visualizeWhitespace(s: string): string {
117
+ return s.replaceAll(' ', '·')
118
+ }
119
+
120
+ // ============================================================================
121
+ // Test runner — dynamically loads all golden files from testdata directories
122
+ // ============================================================================
123
+
124
+ function runGoldenTests(dir: string, useAscii: boolean): void {
125
+ const files = readdirSync(dir)
126
+ .filter((f) => f.endsWith('.txt'))
127
+ .sort()
128
+
129
+ for (const file of files) {
130
+ const testName = file.replace('.txt', '')
131
+
132
+ it(testName, () => {
133
+ const content = readFileSync(join(dir, file), 'utf-8')
134
+ const tc = parseTestCase(content)
135
+
136
+ const actual = renderMermaidASCII(tc.mermaid, {
137
+ useAscii,
138
+ paddingX: tc.paddingX,
139
+ paddingY: tc.paddingY,
140
+ })
141
+
142
+ const normalizedExpected = normalizeWhitespace(tc.expected)
143
+ const normalizedActual = normalizeWhitespace(actual)
144
+
145
+ if (normalizedExpected !== normalizedActual) {
146
+ const expectedVis = visualizeWhitespace(normalizedExpected)
147
+ const actualVis = visualizeWhitespace(normalizedActual)
148
+ expect(actualVis).toBe(expectedVis)
149
+ }
150
+ })
151
+ }
152
+ }
153
+
154
+ // ============================================================================
155
+ // Test suites
156
+ // ============================================================================
157
+
158
+ const testdataDir = join(dirname(fileURLToPath(import.meta.url)), 'testdata')
159
+
160
+ describe('ASCII rendering', () => {
161
+ runGoldenTests(join(testdataDir, 'ascii'), true)
162
+ })
163
+
164
+ describe('Unicode rendering', () => {
165
+ runGoldenTests(join(testdataDir, 'unicode'), false)
166
+ })
167
+
168
+ // ============================================================================
169
+ // Config behavior tests — ported from Go's TestGraphUseAsciiConfig
170
+ // ============================================================================
171
+
172
+ describe('Config behavior', () => {
173
+ const mermaidInput = 'graph LR\nA --> B'
174
+
175
+ it('ASCII and Unicode outputs should differ', () => {
176
+ const asciiOutput = renderMermaidASCII(mermaidInput, { useAscii: true })
177
+ const unicodeOutput = renderMermaidASCII(mermaidInput, { useAscii: false })
178
+ expect(asciiOutput).not.toBe(unicodeOutput)
179
+ })
180
+
181
+ it('ASCII output should not contain Unicode box-drawing characters', () => {
182
+ const output = renderMermaidASCII(mermaidInput, { useAscii: true })
183
+ expect(output).not.toContain('┌')
184
+ expect(output).not.toContain('─')
185
+ expect(output).not.toContain('│')
186
+ })
187
+
188
+ it('Unicode output should contain Unicode box-drawing characters', () => {
189
+ const output = renderMermaidASCII(mermaidInput, { useAscii: false })
190
+ const hasUnicode =
191
+ output.includes('┌') || output.includes('─') || output.includes('│')
192
+ expect(hasUnicode).toBe(true)
193
+ })
194
+ })
195
+
196
+ // ============================================================================
197
+ // Diagonal validation — ensures all edges use orthogonal Manhattan routing
198
+ // ============================================================================
199
+
200
+ describe('Diagonal validation', () => {
201
+ const asciiDir = join(testdataDir, 'ascii')
202
+ const unicodeDir = join(testdataDir, 'unicode')
203
+
204
+ it('ASCII output should never contain diagonal characters', () => {
205
+ // Test all ASCII golden files
206
+ const files = readdirSync(asciiDir).filter((f) => f.endsWith('.txt'))
207
+ for (const file of files) {
208
+ const content = readFileSync(join(asciiDir, file), 'utf-8')
209
+ const { mermaid, paddingX, paddingY } = parseTestCase(content)
210
+ const output = renderMermaidASCII(mermaid, {
211
+ useAscii: true,
212
+ boxBorderPadding: paddingX,
213
+ paddingY: paddingY,
214
+ })
215
+
216
+ // Check for diagonal characters
217
+ for (const char of DIAGONAL_CHARS.ascii) {
218
+ expect(output).not.toContain(char)
219
+ }
220
+ }
221
+ })
222
+
223
+ it('Unicode output should never contain diagonal characters', () => {
224
+ // Test all Unicode golden files
225
+ const files = readdirSync(unicodeDir).filter((f) => f.endsWith('.txt'))
226
+ for (const file of files) {
227
+ const content = readFileSync(join(unicodeDir, file), 'utf-8')
228
+ const { mermaid, paddingX, paddingY } = parseTestCase(content)
229
+ const output = renderMermaidASCII(mermaid, {
230
+ useAscii: false,
231
+ boxBorderPadding: paddingX,
232
+ paddingY: paddingY,
233
+ })
234
+
235
+ // Check for diagonal characters
236
+ for (const char of DIAGONAL_CHARS.unicode) {
237
+ expect(output).not.toContain(char)
238
+ }
239
+ }
240
+ })
241
+
242
+ it('hasDiagonalLines utility correctly detects diagonal characters', () => {
243
+ // Should detect ASCII diagonals
244
+ expect(hasDiagonalLines('A / B')).toBe(true)
245
+ expect(hasDiagonalLines('A \\ B')).toBe(true)
246
+
247
+ // Should detect Unicode diagonals
248
+ expect(hasDiagonalLines('A ╱ B')).toBe(true)
249
+ expect(hasDiagonalLines('A ╲ B')).toBe(true)
250
+
251
+ // Should not flag clean output
252
+ expect(hasDiagonalLines('┌───┐\n│ A │\n└───┘')).toBe(false)
253
+ expect(hasDiagonalLines('+---+\n| A |\n+---+')).toBe(false)
254
+ })
255
+ })
256
+
257
+ // ============================================================================
258
+ // Issue #65 regressions
259
+ // ============================================================================
260
+
261
+ describe('Issue #65 – --o/--x edges no longer drop the target node', () => {
262
+ it('renders both nodes and a connector for A --o B', () => {
263
+ const output = renderMermaidASCII('graph LR\n A --o B')
264
+ expect(output).toContain('A')
265
+ expect(output).toContain('B')
266
+ // The connecting line/arrow should be present, not just two bare boxes.
267
+ expect(output).toMatch(/[─▼►]/)
268
+ })
269
+
270
+ it('renders both nodes and a connector for A --x B', () => {
271
+ const output = renderMermaidASCII('graph LR\n A --x B')
272
+ expect(output).toContain('A')
273
+ expect(output).toContain('B')
274
+ expect(output).toMatch(/[─▼►]/)
275
+ })
276
+ })
277
+
278
+ describe('Issue #65 – edges to a subgraph id no longer create phantom nodes', () => {
279
+ const mermaid = `flowchart TD
280
+ subgraph ONE["First"]
281
+ A1["a"] --> A2["b"]
282
+ end
283
+ subgraph TWO["Second"]
284
+ B1["c"] --> B2["d"]
285
+ end
286
+ ONE --> TWO`
287
+
288
+ it('does not render a standalone "ONE" or "TWO" box disconnected from the subgraphs', () => {
289
+ const output = renderMermaidASCII(mermaid)
290
+ // The subgraph titles ("First"/"Second") should render; the raw
291
+ // subgraph ids should not appear as their own node labels.
292
+ expect(output).toContain('First')
293
+ expect(output).toContain('Second')
294
+ expect(output).not.toMatch(/│\s*ONE\s*│/)
295
+ expect(output).not.toMatch(/│\s*TWO\s*│/)
296
+ })
297
+
298
+ it('draws a real connector between the two subgraph frames', () => {
299
+ const output = renderMermaidASCII(mermaid)
300
+ // A vertical connector should cross between the two subgraph boxes.
301
+ expect(output).toMatch(/[│▼]/)
302
+ })
303
+ })
304
+
305
+ describe('Issue #65 – inline <i>/<b>/<em>/<strong> tags are stripped', () => {
306
+ it('strips inline formatting tags from a node label', () => {
307
+ const output = renderMermaidASCII(
308
+ 'flowchart TD\n A["italic <i>word</i> and bold <b>x</b>"]',
309
+ )
310
+ expect(output).toContain('italic word and bold x')
311
+ expect(output).not.toContain('<i>')
312
+ expect(output).not.toContain('</i>')
313
+ expect(output).not.toContain('<b>')
314
+ expect(output).not.toContain('</b>')
315
+ })
316
+
317
+ it('strips <em>/<strong> as well', () => {
318
+ const output = renderMermaidASCII(
319
+ 'flowchart TD\n A["<em>emphasis</em> and <strong>strong</strong>"]',
320
+ )
321
+ expect(output).toContain('emphasis and strong')
322
+ expect(output).not.toContain('<em>')
323
+ expect(output).not.toContain('<strong>')
324
+ })
325
+ })