@chengchenccc/tui 0.1.1-rc.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 (226) hide show
  1. package/dist/autocomplete.d.ts +56 -0
  2. package/dist/autocomplete.d.ts.map +1 -0
  3. package/dist/autocomplete.js +647 -0
  4. package/dist/components/box.d.ts +22 -0
  5. package/dist/components/box.d.ts.map +1 -0
  6. package/dist/components/box.js +103 -0
  7. package/dist/components/card.d.ts +33 -0
  8. package/dist/components/card.d.ts.map +1 -0
  9. package/dist/components/card.js +49 -0
  10. package/dist/components/editor.d.ts +257 -0
  11. package/dist/components/editor.d.ts.map +1 -0
  12. package/dist/components/editor.js +1980 -0
  13. package/dist/components/input.d.ts +37 -0
  14. package/dist/components/input.d.ts.map +1 -0
  15. package/dist/components/input.js +389 -0
  16. package/dist/components/loader.d.ts +33 -0
  17. package/dist/components/loader.d.ts.map +1 -0
  18. package/dist/components/loader.js +100 -0
  19. package/dist/components/markdown.d.ts +108 -0
  20. package/dist/components/markdown.d.ts.map +1 -0
  21. package/dist/components/markdown.js +847 -0
  22. package/dist/components/markdown.test.d.ts +2 -0
  23. package/dist/components/markdown.test.d.ts.map +1 -0
  24. package/dist/components/markdown.test.js +81 -0
  25. package/dist/components/output-block.d.ts +44 -0
  26. package/dist/components/output-block.d.ts.map +1 -0
  27. package/dist/components/output-block.js +131 -0
  28. package/dist/components/select-list.d.ts +50 -0
  29. package/dist/components/select-list.d.ts.map +1 -0
  30. package/dist/components/select-list.js +166 -0
  31. package/dist/components/spacer.d.ts +12 -0
  32. package/dist/components/spacer.d.ts.map +1 -0
  33. package/dist/components/spacer.js +22 -0
  34. package/dist/components/statusline.d.ts +30 -0
  35. package/dist/components/statusline.d.ts.map +1 -0
  36. package/dist/components/statusline.js +46 -0
  37. package/dist/components/text.d.ts +19 -0
  38. package/dist/components/text.d.ts.map +1 -0
  39. package/dist/components/text.js +90 -0
  40. package/dist/components/truncated-text.d.ts +13 -0
  41. package/dist/components/truncated-text.d.ts.map +1 -0
  42. package/dist/components/truncated-text.js +50 -0
  43. package/dist/editor-component.d.ts +39 -0
  44. package/dist/editor-component.d.ts.map +1 -0
  45. package/dist/editor-component.js +1 -0
  46. package/dist/fuzzy.d.ts +16 -0
  47. package/dist/fuzzy.d.ts.map +1 -0
  48. package/dist/fuzzy.js +109 -0
  49. package/dist/index.d.ts +25 -0
  50. package/dist/index.d.ts.map +1 -0
  51. package/dist/index.js +36 -0
  52. package/dist/keybindings.d.ts +193 -0
  53. package/dist/keybindings.d.ts.map +1 -0
  54. package/dist/keybindings.js +191 -0
  55. package/dist/keys.d.ts +184 -0
  56. package/dist/keys.d.ts.map +1 -0
  57. package/dist/keys.js +1191 -0
  58. package/dist/kill-ring.d.ts +28 -0
  59. package/dist/kill-ring.d.ts.map +1 -0
  60. package/dist/kill-ring.js +43 -0
  61. package/dist/mermaid.d.ts +23 -0
  62. package/dist/mermaid.d.ts.map +1 -0
  63. package/dist/mermaid.js +77 -0
  64. package/dist/mouse.d.ts +40 -0
  65. package/dist/mouse.d.ts.map +1 -0
  66. package/dist/mouse.js +39 -0
  67. package/dist/mouse.test.d.ts +2 -0
  68. package/dist/mouse.test.d.ts.map +1 -0
  69. package/dist/mouse.test.js +36 -0
  70. package/dist/native-modifiers.d.ts +3 -0
  71. package/dist/native-modifiers.d.ts.map +1 -0
  72. package/dist/native-modifiers.js +52 -0
  73. package/dist/stdin-buffer.d.ts +50 -0
  74. package/dist/stdin-buffer.d.ts.map +1 -0
  75. package/dist/stdin-buffer.js +360 -0
  76. package/dist/terminal-colors.d.ts +10 -0
  77. package/dist/terminal-colors.d.ts.map +1 -0
  78. package/dist/terminal-colors.js +58 -0
  79. package/dist/terminal-image.d.ts +90 -0
  80. package/dist/terminal-image.d.ts.map +1 -0
  81. package/dist/terminal-image.js +375 -0
  82. package/dist/terminal.d.ts +110 -0
  83. package/dist/terminal.d.ts.map +1 -0
  84. package/dist/terminal.js +432 -0
  85. package/dist/tui-scrollback.test.d.ts +2 -0
  86. package/dist/tui-scrollback.test.d.ts.map +1 -0
  87. package/dist/tui-scrollback.test.js +51 -0
  88. package/dist/tui.d.ts +330 -0
  89. package/dist/tui.d.ts.map +1 -0
  90. package/dist/tui.js +1568 -0
  91. package/dist/undo-stack.d.ts +17 -0
  92. package/dist/undo-stack.d.ts.map +1 -0
  93. package/dist/undo-stack.js +24 -0
  94. package/dist/utils.d.ts +85 -0
  95. package/dist/utils.d.ts.map +1 -0
  96. package/dist/utils.js +1066 -0
  97. package/dist/vendor/mermaid-ascii/ascii/ansi.d.ts +42 -0
  98. package/dist/vendor/mermaid-ascii/ascii/ansi.d.ts.map +1 -0
  99. package/dist/vendor/mermaid-ascii/ascii/ansi.js +361 -0
  100. package/dist/vendor/mermaid-ascii/ascii/canvas.d.ts +90 -0
  101. package/dist/vendor/mermaid-ascii/ascii/canvas.d.ts.map +1 -0
  102. package/dist/vendor/mermaid-ascii/ascii/canvas.js +414 -0
  103. package/dist/vendor/mermaid-ascii/ascii/class-diagram.d.ts +8 -0
  104. package/dist/vendor/mermaid-ascii/ascii/class-diagram.d.ts.map +1 -0
  105. package/dist/vendor/mermaid-ascii/ascii/class-diagram.js +623 -0
  106. package/dist/vendor/mermaid-ascii/ascii/converter.d.ts +13 -0
  107. package/dist/vendor/mermaid-ascii/ascii/converter.d.ts.map +1 -0
  108. package/dist/vendor/mermaid-ascii/ascii/converter.js +233 -0
  109. package/dist/vendor/mermaid-ascii/ascii/draw.d.ts +67 -0
  110. package/dist/vendor/mermaid-ascii/ascii/draw.d.ts.map +1 -0
  111. package/dist/vendor/mermaid-ascii/ascii/draw.js +1313 -0
  112. package/dist/vendor/mermaid-ascii/ascii/edge-bundling.d.ts +49 -0
  113. package/dist/vendor/mermaid-ascii/ascii/edge-bundling.d.ts.map +1 -0
  114. package/dist/vendor/mermaid-ascii/ascii/edge-bundling.js +289 -0
  115. package/dist/vendor/mermaid-ascii/ascii/edge-routing.d.ts +44 -0
  116. package/dist/vendor/mermaid-ascii/ascii/edge-routing.d.ts.map +1 -0
  117. package/dist/vendor/mermaid-ascii/ascii/edge-routing.js +302 -0
  118. package/dist/vendor/mermaid-ascii/ascii/er-diagram.d.ts +8 -0
  119. package/dist/vendor/mermaid-ascii/ascii/er-diagram.d.ts.map +1 -0
  120. package/dist/vendor/mermaid-ascii/ascii/er-diagram.js +380 -0
  121. package/dist/vendor/mermaid-ascii/ascii/grid.d.ts +57 -0
  122. package/dist/vendor/mermaid-ascii/ascii/grid.d.ts.map +1 -0
  123. package/dist/vendor/mermaid-ascii/ascii/grid.js +516 -0
  124. package/dist/vendor/mermaid-ascii/ascii/index.d.ts +66 -0
  125. package/dist/vendor/mermaid-ascii/ascii/index.d.ts.map +1 -0
  126. package/dist/vendor/mermaid-ascii/ascii/index.js +133 -0
  127. package/dist/vendor/mermaid-ascii/ascii/multiline-utils.d.ts +28 -0
  128. package/dist/vendor/mermaid-ascii/ascii/multiline-utils.d.ts.map +1 -0
  129. package/dist/vendor/mermaid-ascii/ascii/multiline-utils.js +60 -0
  130. package/dist/vendor/mermaid-ascii/ascii/pathfinder.d.ts +18 -0
  131. package/dist/vendor/mermaid-ascii/ascii/pathfinder.d.ts.map +1 -0
  132. package/dist/vendor/mermaid-ascii/ascii/pathfinder.js +224 -0
  133. package/dist/vendor/mermaid-ascii/ascii/sequence.d.ts +8 -0
  134. package/dist/vendor/mermaid-ascii/ascii/sequence.d.ts.map +1 -0
  135. package/dist/vendor/mermaid-ascii/ascii/sequence.js +416 -0
  136. package/dist/vendor/mermaid-ascii/ascii/shapes/circle.d.ts +12 -0
  137. package/dist/vendor/mermaid-ascii/ascii/shapes/circle.d.ts.map +1 -0
  138. package/dist/vendor/mermaid-ascii/ascii/shapes/circle.js +22 -0
  139. package/dist/vendor/mermaid-ascii/ascii/shapes/corners.d.ts +35 -0
  140. package/dist/vendor/mermaid-ascii/ascii/shapes/corners.d.ts.map +1 -0
  141. package/dist/vendor/mermaid-ascii/ascii/shapes/corners.js +91 -0
  142. package/dist/vendor/mermaid-ascii/ascii/shapes/diamond.d.ts +12 -0
  143. package/dist/vendor/mermaid-ascii/ascii/shapes/diamond.d.ts.map +1 -0
  144. package/dist/vendor/mermaid-ascii/ascii/shapes/diamond.js +22 -0
  145. package/dist/vendor/mermaid-ascii/ascii/shapes/hexagon.d.ts +12 -0
  146. package/dist/vendor/mermaid-ascii/ascii/shapes/hexagon.d.ts.map +1 -0
  147. package/dist/vendor/mermaid-ascii/ascii/shapes/hexagon.js +22 -0
  148. package/dist/vendor/mermaid-ascii/ascii/shapes/index.d.ts +27 -0
  149. package/dist/vendor/mermaid-ascii/ascii/shapes/index.d.ts.map +1 -0
  150. package/dist/vendor/mermaid-ascii/ascii/shapes/index.js +66 -0
  151. package/dist/vendor/mermaid-ascii/ascii/shapes/rectangle.d.ts +32 -0
  152. package/dist/vendor/mermaid-ascii/ascii/shapes/rectangle.d.ts.map +1 -0
  153. package/dist/vendor/mermaid-ascii/ascii/shapes/rectangle.js +149 -0
  154. package/dist/vendor/mermaid-ascii/ascii/shapes/rounded.d.ts +12 -0
  155. package/dist/vendor/mermaid-ascii/ascii/shapes/rounded.d.ts.map +1 -0
  156. package/dist/vendor/mermaid-ascii/ascii/shapes/rounded.js +22 -0
  157. package/dist/vendor/mermaid-ascii/ascii/shapes/special.d.ts +60 -0
  158. package/dist/vendor/mermaid-ascii/ascii/shapes/special.d.ts.map +1 -0
  159. package/dist/vendor/mermaid-ascii/ascii/shapes/special.js +253 -0
  160. package/dist/vendor/mermaid-ascii/ascii/shapes/stadium.d.ts +18 -0
  161. package/dist/vendor/mermaid-ascii/ascii/shapes/stadium.d.ts.map +1 -0
  162. package/dist/vendor/mermaid-ascii/ascii/shapes/stadium.js +103 -0
  163. package/dist/vendor/mermaid-ascii/ascii/shapes/state.d.ts +31 -0
  164. package/dist/vendor/mermaid-ascii/ascii/shapes/state.d.ts.map +1 -0
  165. package/dist/vendor/mermaid-ascii/ascii/shapes/state.js +167 -0
  166. package/dist/vendor/mermaid-ascii/ascii/shapes/types.d.ts +56 -0
  167. package/dist/vendor/mermaid-ascii/ascii/shapes/types.d.ts.map +1 -0
  168. package/dist/vendor/mermaid-ascii/ascii/shapes/types.js +4 -0
  169. package/dist/vendor/mermaid-ascii/ascii/types.d.ts +207 -0
  170. package/dist/vendor/mermaid-ascii/ascii/types.d.ts.map +1 -0
  171. package/dist/vendor/mermaid-ascii/ascii/types.js +39 -0
  172. package/dist/vendor/mermaid-ascii/ascii/validate.d.ts +52 -0
  173. package/dist/vendor/mermaid-ascii/ascii/validate.d.ts.map +1 -0
  174. package/dist/vendor/mermaid-ascii/ascii/validate.js +97 -0
  175. package/dist/vendor/mermaid-ascii/ascii/xychart.d.ts +3 -0
  176. package/dist/vendor/mermaid-ascii/ascii/xychart.d.ts.map +1 -0
  177. package/dist/vendor/mermaid-ascii/ascii/xychart.js +719 -0
  178. package/dist/vendor/mermaid-ascii/class/parser.d.ts +7 -0
  179. package/dist/vendor/mermaid-ascii/class/parser.d.ts.map +1 -0
  180. package/dist/vendor/mermaid-ascii/class/parser.js +265 -0
  181. package/dist/vendor/mermaid-ascii/class/types.d.ts +103 -0
  182. package/dist/vendor/mermaid-ascii/class/types.d.ts.map +1 -0
  183. package/dist/vendor/mermaid-ascii/class/types.js +7 -0
  184. package/dist/vendor/mermaid-ascii/er/parser.d.ts +7 -0
  185. package/dist/vendor/mermaid-ascii/er/parser.d.ts.map +1 -0
  186. package/dist/vendor/mermaid-ascii/er/parser.js +162 -0
  187. package/dist/vendor/mermaid-ascii/er/types.d.ts +77 -0
  188. package/dist/vendor/mermaid-ascii/er/types.d.ts.map +1 -0
  189. package/dist/vendor/mermaid-ascii/er/types.js +7 -0
  190. package/dist/vendor/mermaid-ascii/index.d.ts +2 -0
  191. package/dist/vendor/mermaid-ascii/index.d.ts.map +1 -0
  192. package/dist/vendor/mermaid-ascii/index.js +13 -0
  193. package/dist/vendor/mermaid-ascii/multiline-utils.d.ts +10 -0
  194. package/dist/vendor/mermaid-ascii/multiline-utils.d.ts.map +1 -0
  195. package/dist/vendor/mermaid-ascii/multiline-utils.js +29 -0
  196. package/dist/vendor/mermaid-ascii/parser.d.ts +8 -0
  197. package/dist/vendor/mermaid-ascii/parser.d.ts.map +1 -0
  198. package/dist/vendor/mermaid-ascii/parser.js +558 -0
  199. package/dist/vendor/mermaid-ascii/sequence/parser.d.ts +7 -0
  200. package/dist/vendor/mermaid-ascii/sequence/parser.d.ts.map +1 -0
  201. package/dist/vendor/mermaid-ascii/sequence/parser.js +182 -0
  202. package/dist/vendor/mermaid-ascii/sequence/types.d.ts +131 -0
  203. package/dist/vendor/mermaid-ascii/sequence/types.d.ts.map +1 -0
  204. package/dist/vendor/mermaid-ascii/sequence/types.js +7 -0
  205. package/dist/vendor/mermaid-ascii/text-metrics.d.ts +24 -0
  206. package/dist/vendor/mermaid-ascii/text-metrics.d.ts.map +1 -0
  207. package/dist/vendor/mermaid-ascii/text-metrics.js +69 -0
  208. package/dist/vendor/mermaid-ascii/types.d.ts +115 -0
  209. package/dist/vendor/mermaid-ascii/types.d.ts.map +1 -0
  210. package/dist/vendor/mermaid-ascii/types.js +4 -0
  211. package/dist/vendor/mermaid-ascii/xychart/colors.d.ts +26 -0
  212. package/dist/vendor/mermaid-ascii/xychart/colors.d.ts.map +1 -0
  213. package/dist/vendor/mermaid-ascii/xychart/colors.js +145 -0
  214. package/dist/vendor/mermaid-ascii/xychart/parser.d.ts +7 -0
  215. package/dist/vendor/mermaid-ascii/xychart/parser.d.ts.map +1 -0
  216. package/dist/vendor/mermaid-ascii/xychart/parser.js +105 -0
  217. package/dist/vendor/mermaid-ascii/xychart/types.d.ts +146 -0
  218. package/dist/vendor/mermaid-ascii/xychart/types.d.ts.map +1 -0
  219. package/dist/vendor/mermaid-ascii/xychart/types.js +8 -0
  220. package/dist/virtual-terminal.d.ts +80 -0
  221. package/dist/virtual-terminal.d.ts.map +1 -0
  222. package/dist/virtual-terminal.js +284 -0
  223. package/dist/word-navigation.d.ts +25 -0
  224. package/dist/word-navigation.d.ts.map +1 -0
  225. package/dist/word-navigation.js +97 -0
  226. package/package.json +38 -0
@@ -0,0 +1,49 @@
1
+ import type { AsciiGraph, EdgeBundle, GridCoord } from './types.ts';
2
+ /**
3
+ * Analyze graph edges and create bundles for parallel links.
4
+ *
5
+ * Groups edges by:
6
+ * - Fan-in: Multiple edges sharing the same target (A & B --> C)
7
+ * - Fan-out: Multiple edges sharing the same source (A --> B & C)
8
+ *
9
+ * Only creates bundles when:
10
+ * - Graph direction is TD (top-down) - LR routing handles merging naturally
11
+ * - 2+ edges share the endpoint
12
+ * - All edges have the same style (solid/dotted/thick)
13
+ * - None of the edges have labels (labels would overlap at junction)
14
+ * - Edges are not self-loops
15
+ *
16
+ * @returns Array of bundles. Each edge can belong to at most one bundle.
17
+ */
18
+ export declare function analyzeEdgeBundles(graph: AsciiGraph): EdgeBundle[];
19
+ /**
20
+ * Calculate the optimal junction point for a bundle.
21
+ *
22
+ * For fan-in (A & B --> C):
23
+ * - Junction is placed between the sources and the target
24
+ * - In TD: above the target, horizontally centered between sources
25
+ * - In LR: left of the target, vertically centered between sources
26
+ *
27
+ * For fan-out (A --> B & C):
28
+ * - Junction is placed between the source and the targets
29
+ * - In TD: below the source, horizontally centered between targets
30
+ * - In LR: right of the source, vertically centered between targets
31
+ */
32
+ export declare function calculateJunctionPoint(graph: AsciiGraph, bundle: EdgeBundle): GridCoord;
33
+ /**
34
+ * Route all edges in a bundle through the junction point.
35
+ *
36
+ * For fan-in bundles:
37
+ * 1. Route each source → junction (stored in edge.pathToJunction)
38
+ * 2. Route junction → target (stored in bundle.sharedPath)
39
+ *
40
+ * For fan-out bundles:
41
+ * 1. Route source → junction (stored in bundle.sharedPath)
42
+ * 2. Route junction → each target (stored in edge.pathToJunction)
43
+ */
44
+ export declare function routeBundledEdges(graph: AsciiGraph, bundle: EdgeBundle): void;
45
+ /**
46
+ * Process all bundles in a graph: calculate junction points and route edges.
47
+ */
48
+ export declare function processBundles(graph: AsciiGraph): void;
49
+ //# sourceMappingURL=edge-bundling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge-bundling.d.ts","sourceRoot":"","sources":["../../../../src/vendor/mermaid-ascii/ascii/edge-bundling.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,UAAU,EAAwB,UAAU,EAAE,SAAS,EACxD,MAAM,YAAY,CAAA;AASnB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,EAAE,CAqFlE;AAuCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,UAAU,GACjB,SAAS,CAkDX;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAuE7E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAItD"}
@@ -0,0 +1,289 @@
1
+ // ============================================================================
2
+ // ASCII renderer — edge bundling for parallel links
3
+ //
4
+ // Analyzes edges to find parallel links (A & B --> C or A --> B & C) and
5
+ // groups them into bundles. Bundled edges share a visual junction point
6
+ // where they merge/split, creating cleaner diagrams.
7
+ //
8
+ // This module provides:
9
+ // - analyzeEdgeBundles(): Finds and creates bundles from graph edges
10
+ // - calculateJunctionPoint(): Computes optimal merge/split locations
11
+ // - routeBundledEdges(): Routes edges through junction points
12
+ // ============================================================================
13
+ import { Up, Down, Left, Right, Middle } from "./types.js";
14
+ import { getPath, mergePath } from "./pathfinder.js";
15
+ import { getNodeSubgraph } from "./grid.js";
16
+ // ============================================================================
17
+ // Bundle analysis
18
+ // ============================================================================
19
+ /**
20
+ * Analyze graph edges and create bundles for parallel links.
21
+ *
22
+ * Groups edges by:
23
+ * - Fan-in: Multiple edges sharing the same target (A & B --> C)
24
+ * - Fan-out: Multiple edges sharing the same source (A --> B & C)
25
+ *
26
+ * Only creates bundles when:
27
+ * - Graph direction is TD (top-down) - LR routing handles merging naturally
28
+ * - 2+ edges share the endpoint
29
+ * - All edges have the same style (solid/dotted/thick)
30
+ * - None of the edges have labels (labels would overlap at junction)
31
+ * - Edges are not self-loops
32
+ *
33
+ * @returns Array of bundles. Each edge can belong to at most one bundle.
34
+ */
35
+ export function analyzeEdgeBundles(graph) {
36
+ // Only bundle in TD direction - LR routing handles merging naturally at corners
37
+ if (graph.config.graphDirection !== 'TD') {
38
+ return [];
39
+ }
40
+ const bundles = [];
41
+ const bundledEdges = new Set();
42
+ // Group edges by target (fan-in candidates)
43
+ const edgesByTarget = new Map();
44
+ for (const edge of graph.edges) {
45
+ // Skip self-loops
46
+ if (edge.from === edge.to)
47
+ continue;
48
+ const existing = edgesByTarget.get(edge.to) ?? [];
49
+ existing.push(edge);
50
+ edgesByTarget.set(edge.to, existing);
51
+ }
52
+ // Create fan-in bundles
53
+ for (const [target, edges] of edgesByTarget) {
54
+ if (edges.length < 2)
55
+ continue;
56
+ if (!canBundle(edges, graph))
57
+ continue;
58
+ // Check if all edges are already bundled
59
+ if (edges.some(e => bundledEdges.has(e)))
60
+ continue;
61
+ const bundle = {
62
+ type: 'fan-in',
63
+ edges: [...edges],
64
+ sharedNode: target,
65
+ otherNodes: edges.map(e => e.from),
66
+ junctionPoint: null,
67
+ sharedPath: [],
68
+ junctionDir: Middle,
69
+ sharedNodeDir: Middle,
70
+ };
71
+ // Mark edges as bundled
72
+ for (const edge of edges) {
73
+ edge.bundle = bundle;
74
+ bundledEdges.add(edge);
75
+ }
76
+ bundles.push(bundle);
77
+ }
78
+ // Group edges by source (fan-out candidates)
79
+ const edgesBySource = new Map();
80
+ for (const edge of graph.edges) {
81
+ // Skip self-loops and already bundled edges
82
+ if (edge.from === edge.to)
83
+ continue;
84
+ if (bundledEdges.has(edge))
85
+ continue;
86
+ const existing = edgesBySource.get(edge.from) ?? [];
87
+ existing.push(edge);
88
+ edgesBySource.set(edge.from, existing);
89
+ }
90
+ // Create fan-out bundles
91
+ for (const [source, edges] of edgesBySource) {
92
+ if (edges.length < 2)
93
+ continue;
94
+ if (!canBundle(edges, graph))
95
+ continue;
96
+ const bundle = {
97
+ type: 'fan-out',
98
+ edges: [...edges],
99
+ sharedNode: source,
100
+ otherNodes: edges.map(e => e.to),
101
+ junctionPoint: null,
102
+ sharedPath: [],
103
+ junctionDir: Middle,
104
+ sharedNodeDir: Middle,
105
+ };
106
+ // Mark edges as bundled
107
+ for (const edge of edges) {
108
+ edge.bundle = bundle;
109
+ bundledEdges.add(edge);
110
+ }
111
+ bundles.push(bundle);
112
+ }
113
+ return bundles;
114
+ }
115
+ /**
116
+ * Check if a group of edges can be bundled together.
117
+ * Returns false if edges have different styles, any have labels,
118
+ * or if the edges span subgraph boundaries (which creates complex routing).
119
+ */
120
+ function canBundle(edges, graph) {
121
+ if (edges.length < 2)
122
+ return false;
123
+ const firstStyle = edges[0].style;
124
+ const firstFromSg = getNodeSubgraph(graph, edges[0].from);
125
+ const firstToSg = getNodeSubgraph(graph, edges[0].to);
126
+ for (const edge of edges) {
127
+ // Different styles can't be bundled (would look confusing)
128
+ if (edge.style !== firstStyle)
129
+ return false;
130
+ // Edges with labels can't be bundled (labels would overlap at junction)
131
+ if (edge.text.length > 0)
132
+ return false;
133
+ // Don't bundle if edges span different subgraph boundaries
134
+ // (creates complex routing that doesn't look good)
135
+ const fromSg = getNodeSubgraph(graph, edge.from);
136
+ const toSg = getNodeSubgraph(graph, edge.to);
137
+ if (fromSg !== firstFromSg || toSg !== firstToSg)
138
+ return false;
139
+ // Don't bundle if source and target are in different subgraphs
140
+ // (cross-boundary edges have special routing needs)
141
+ if (fromSg !== toSg)
142
+ return false;
143
+ }
144
+ return true;
145
+ }
146
+ // ============================================================================
147
+ // Junction point calculation
148
+ // ============================================================================
149
+ /**
150
+ * Calculate the optimal junction point for a bundle.
151
+ *
152
+ * For fan-in (A & B --> C):
153
+ * - Junction is placed between the sources and the target
154
+ * - In TD: above the target, horizontally centered between sources
155
+ * - In LR: left of the target, vertically centered between sources
156
+ *
157
+ * For fan-out (A --> B & C):
158
+ * - Junction is placed between the source and the targets
159
+ * - In TD: below the source, horizontally centered between targets
160
+ * - In LR: right of the source, vertically centered between targets
161
+ */
162
+ export function calculateJunctionPoint(graph, bundle) {
163
+ const dir = graph.config.graphDirection;
164
+ const sharedCoord = bundle.sharedNode.gridCoord;
165
+ const otherCoords = bundle.otherNodes.map(n => n.gridCoord);
166
+ if (bundle.type === 'fan-in') {
167
+ // Junction is BEFORE the shared target
168
+ // Calculate center of sources
169
+ const minX = Math.min(...otherCoords.map(c => c.x));
170
+ const maxX = Math.max(...otherCoords.map(c => c.x));
171
+ const minY = Math.min(...otherCoords.map(c => c.y));
172
+ const maxY = Math.max(...otherCoords.map(c => c.y));
173
+ if (dir === 'TD') {
174
+ // Junction above target, centered between sources
175
+ // Place it one row above the target's entry point
176
+ const junctionY = sharedCoord.y - 1;
177
+ // X is centered between sources, but clamped to shared node's X for alignment
178
+ const centerX = Math.floor((minX + maxX) / 2) + 1; // +1 for center of 3x3 block
179
+ const junctionX = sharedCoord.x + 1; // Align with target's center
180
+ return { x: junctionX, y: junctionY };
181
+ }
182
+ else {
183
+ // LR: Junction left of target, centered between sources
184
+ const junctionX = sharedCoord.x - 1;
185
+ const junctionY = sharedCoord.y + 1; // Align with target's center
186
+ return { x: junctionX, y: junctionY };
187
+ }
188
+ }
189
+ else {
190
+ // fan-out: Junction is AFTER the shared source
191
+ const minX = Math.min(...otherCoords.map(c => c.x));
192
+ const maxX = Math.max(...otherCoords.map(c => c.x));
193
+ const minY = Math.min(...otherCoords.map(c => c.y));
194
+ const maxY = Math.max(...otherCoords.map(c => c.y));
195
+ if (dir === 'TD') {
196
+ // Junction below source, will then split to targets
197
+ const junctionY = sharedCoord.y + 3; // Just below source's 3x3 block
198
+ const junctionX = sharedCoord.x + 1; // Align with source's center
199
+ return { x: junctionX, y: junctionY };
200
+ }
201
+ else {
202
+ // LR: Junction right of source
203
+ const junctionX = sharedCoord.x + 3;
204
+ const junctionY = sharedCoord.y + 1;
205
+ return { x: junctionX, y: junctionY };
206
+ }
207
+ }
208
+ }
209
+ // ============================================================================
210
+ // Bundled edge routing
211
+ // ============================================================================
212
+ /**
213
+ * Route all edges in a bundle through the junction point.
214
+ *
215
+ * For fan-in bundles:
216
+ * 1. Route each source → junction (stored in edge.pathToJunction)
217
+ * 2. Route junction → target (stored in bundle.sharedPath)
218
+ *
219
+ * For fan-out bundles:
220
+ * 1. Route source → junction (stored in bundle.sharedPath)
221
+ * 2. Route junction → each target (stored in edge.pathToJunction)
222
+ */
223
+ export function routeBundledEdges(graph, bundle) {
224
+ const dir = graph.config.graphDirection;
225
+ // Calculate and store junction point
226
+ bundle.junctionPoint = calculateJunctionPoint(graph, bundle);
227
+ const junction = bundle.junctionPoint;
228
+ // Determine directions based on graph direction and bundle type
229
+ if (bundle.type === 'fan-in') {
230
+ // Sources converge to junction, then junction to target
231
+ bundle.junctionDir = dir === 'TD' ? Up : Left;
232
+ bundle.sharedNodeDir = dir === 'TD' ? Down : Right;
233
+ // Route junction → target (shared path)
234
+ const targetCoord = bundle.sharedNode.gridCoord;
235
+ const targetEntry = dir === 'TD'
236
+ ? { x: targetCoord.x + 1, y: targetCoord.y } // Top center of target
237
+ : { x: targetCoord.x, y: targetCoord.y + 1 }; // Left center of target
238
+ const sharedPath = getPath(graph.grid, junction, targetEntry);
239
+ bundle.sharedPath = sharedPath ? mergePath(sharedPath) : [junction, targetEntry];
240
+ // Route each source → junction
241
+ for (const edge of bundle.edges) {
242
+ const sourceCoord = edge.from.gridCoord;
243
+ const sourceExit = dir === 'TD'
244
+ ? { x: sourceCoord.x + 1, y: sourceCoord.y + 2 } // Bottom center of source
245
+ : { x: sourceCoord.x + 2, y: sourceCoord.y + 1 }; // Right center of source
246
+ const pathToJunction = getPath(graph.grid, sourceExit, junction);
247
+ edge.pathToJunction = pathToJunction ? mergePath(pathToJunction) : [sourceExit, junction];
248
+ // Set edge directions for proper drawing
249
+ edge.startDir = dir === 'TD' ? Down : Right;
250
+ edge.endDir = dir === 'TD' ? Up : Left;
251
+ // Build full path for grid size calculation: source → junction → target
252
+ edge.path = [...edge.pathToJunction, ...bundle.sharedPath.slice(1)];
253
+ }
254
+ }
255
+ else {
256
+ // fan-out: Source to junction, then junction splits to targets
257
+ bundle.junctionDir = dir === 'TD' ? Down : Right;
258
+ bundle.sharedNodeDir = dir === 'TD' ? Up : Left;
259
+ // Route source → junction (shared path)
260
+ const sourceCoord = bundle.sharedNode.gridCoord;
261
+ const sourceExit = dir === 'TD'
262
+ ? { x: sourceCoord.x + 1, y: sourceCoord.y + 2 } // Bottom center of source
263
+ : { x: sourceCoord.x + 2, y: sourceCoord.y + 1 }; // Right center of source
264
+ const sharedPath = getPath(graph.grid, sourceExit, junction);
265
+ bundle.sharedPath = sharedPath ? mergePath(sharedPath) : [sourceExit, junction];
266
+ // Route junction → each target
267
+ for (const edge of bundle.edges) {
268
+ const targetCoord = edge.to.gridCoord;
269
+ const targetEntry = dir === 'TD'
270
+ ? { x: targetCoord.x + 1, y: targetCoord.y } // Top center of target
271
+ : { x: targetCoord.x, y: targetCoord.y + 1 }; // Left center of target
272
+ const pathToJunction = getPath(graph.grid, junction, targetEntry);
273
+ edge.pathToJunction = pathToJunction ? mergePath(pathToJunction) : [junction, targetEntry];
274
+ // Set edge directions
275
+ edge.startDir = dir === 'TD' ? Down : Right;
276
+ edge.endDir = dir === 'TD' ? Up : Left;
277
+ // Build full path for grid size calculation: source → junction → target
278
+ edge.path = [...bundle.sharedPath, ...edge.pathToJunction.slice(1)];
279
+ }
280
+ }
281
+ }
282
+ /**
283
+ * Process all bundles in a graph: calculate junction points and route edges.
284
+ */
285
+ export function processBundles(graph) {
286
+ for (const bundle of graph.bundles) {
287
+ routeBundledEdges(graph, bundle);
288
+ }
289
+ }
@@ -0,0 +1,44 @@
1
+ import type { Direction, AsciiEdge, AsciiGraph } from './types.ts';
2
+ export declare function getOpposite(d: Direction): Direction;
3
+ /** Compare directions by value (not reference). */
4
+ export declare function dirEquals(a: Direction, b: Direction): boolean;
5
+ /**
6
+ * Determine 8-way direction from one coordinate to another.
7
+ * Uses the coordinate difference to pick one of 8 cardinal/ordinal directions.
8
+ */
9
+ export declare function determineDirection(from: {
10
+ x: number;
11
+ y: number;
12
+ }, to: {
13
+ x: number;
14
+ y: number;
15
+ }): Direction;
16
+ /**
17
+ * Determine preferred and alternative start/end directions for an edge.
18
+ * Returns [preferredStart, preferredEnd, alternativeStart, alternativeEnd].
19
+ *
20
+ * The edge routing tries both pairs and picks the shorter path.
21
+ * Direction selection depends on relative node positions and graph direction (LR vs TD).
22
+ */
23
+ export declare function determineStartAndEndDir(edge: AsciiEdge, graphDirection: string): [Direction, Direction, Direction, Direction];
24
+ /**
25
+ * Determine the path for an edge by trying two candidate routes (preferred + alternative)
26
+ * and picking the shorter one. Sets edge.path, edge.startDir, edge.endDir.
27
+ *
28
+ * When both A* paths fail (common for edges crossing subgraph boundaries), falls back
29
+ * to a direct path using the start/end points. This ensures edges always have a path
30
+ * for arrowhead rendering.
31
+ *
32
+ * Uses the effective direction for edge routing, respecting subgraph direction overrides
33
+ * when both source and target are in the same subgraph.
34
+ */
35
+ export declare function determinePath(graph: AsciiGraph, edge: AsciiEdge): void;
36
+ /**
37
+ * Find the best line segment in an edge's path to place a label on.
38
+ * Prefers vertical segments for TD/BT graphs and horizontal for LR/RL to avoid
39
+ * label collisions when multiple edges share initial segments.
40
+ * Falls back to the widest segment if none are suitable.
41
+ * Also increases the column width at the label position to fit the text.
42
+ */
43
+ export declare function determineLabelLine(graph: AsciiGraph, edge: AsciiEdge): void;
44
+ //# sourceMappingURL=edge-routing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge-routing.d.ts","sourceRoot":"","sources":["../../../../src/vendor/mermaid-ascii/ascii/edge-routing.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAa,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAa7E,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,GAAG,SAAS,CAUnD;AAED,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,OAAO,CAE7D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAU1G;AAYD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,SAAS,EACf,cAAc,EAAE,MAAM,GACrB,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAgE9C;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CA+DtE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CA0D3E"}