schematex 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/README.md +130 -15
  2. package/dist/api-bQZ98gkJ.d.cts +22 -0
  3. package/dist/api-bQZ98gkJ.d.ts +22 -0
  4. package/dist/browser.cjs +46 -0
  5. package/dist/browser.cjs.map +1 -0
  6. package/dist/browser.d.cts +27 -0
  7. package/dist/browser.d.ts +27 -0
  8. package/dist/browser.js +40 -0
  9. package/dist/browser.js.map +1 -0
  10. package/dist/{chunk-XXU36667.js → chunk-2OIW3MAE.js} +4 -3
  11. package/dist/chunk-2OIW3MAE.js.map +1 -0
  12. package/dist/{chunk-3FTUWAXK.cjs → chunk-3M7QWADF.cjs} +5 -4
  13. package/dist/chunk-3M7QWADF.cjs.map +1 -0
  14. package/dist/{chunk-BE5HNDA5.cjs → chunk-4HPT4BOI.cjs} +5 -4
  15. package/dist/{chunk-BE5HNDA5.cjs.map → chunk-4HPT4BOI.cjs.map} +1 -1
  16. package/dist/{chunk-CZRM7LT7.js → chunk-4TS5NB7L.js} +4 -3
  17. package/dist/chunk-4TS5NB7L.js.map +1 -0
  18. package/dist/{chunk-4G7ZIBHN.js → chunk-5SH5NUDW.js} +3 -2
  19. package/dist/{chunk-4G7ZIBHN.js.map → chunk-5SH5NUDW.js.map} +1 -1
  20. package/dist/{chunk-47ZC6EMJ.js → chunk-7WXAAVR3.js} +4 -3
  21. package/dist/{chunk-47ZC6EMJ.js.map → chunk-7WXAAVR3.js.map} +1 -1
  22. package/dist/{chunk-5C7DPDHQ.js → chunk-A74ZCP5I.js} +4 -3
  23. package/dist/{chunk-5C7DPDHQ.js.map → chunk-A74ZCP5I.js.map} +1 -1
  24. package/dist/{chunk-DS47NTWZ.cjs → chunk-AMP2FFES.cjs} +11 -10
  25. package/dist/chunk-AMP2FFES.cjs.map +1 -0
  26. package/dist/{chunk-2UKC6ZCY.cjs → chunk-CEV3GZA3.cjs} +12 -11
  27. package/dist/chunk-CEV3GZA3.cjs.map +1 -0
  28. package/dist/{chunk-NYCIK4SU.cjs → chunk-DTMCQXXC.cjs} +13 -12
  29. package/dist/chunk-DTMCQXXC.cjs.map +1 -0
  30. package/dist/{chunk-FDLZEKEB.js → chunk-GEPBET4L.js} +3 -2
  31. package/dist/chunk-GEPBET4L.js.map +1 -0
  32. package/dist/chunk-HAIBAF6J.cjs +1880 -0
  33. package/dist/chunk-HAIBAF6J.cjs.map +1 -0
  34. package/dist/{chunk-FGPTCDUT.cjs → chunk-HKRYKEOV.cjs} +5 -4
  35. package/dist/chunk-HKRYKEOV.cjs.map +1 -0
  36. package/dist/{chunk-D4JTSPOL.js → chunk-HLYA4QBB.js} +4 -3
  37. package/dist/chunk-HLYA4QBB.js.map +1 -0
  38. package/dist/{chunk-7FZSPKX3.cjs → chunk-IMHR3S5H.cjs} +6 -5
  39. package/dist/chunk-IMHR3S5H.cjs.map +1 -0
  40. package/dist/{chunk-HGHWCB6K.js → chunk-IQIJ6WW6.js} +4 -3
  41. package/dist/chunk-IQIJ6WW6.js.map +1 -0
  42. package/dist/{chunk-UHLYS3W5.cjs → chunk-IY52OWPG.cjs} +5 -4
  43. package/dist/{chunk-UHLYS3W5.cjs.map → chunk-IY52OWPG.cjs.map} +1 -1
  44. package/dist/chunk-JZGFSRVT.js +1873 -0
  45. package/dist/chunk-JZGFSRVT.js.map +1 -0
  46. package/dist/{chunk-3J7TFUOC.js → chunk-L6IHSTPP.js} +4 -3
  47. package/dist/{chunk-3J7TFUOC.js.map → chunk-L6IHSTPP.js.map} +1 -1
  48. package/dist/{chunk-4DBRNOPA.cjs → chunk-LKHWBDWZ.cjs} +5 -4
  49. package/dist/{chunk-4DBRNOPA.cjs.map → chunk-LKHWBDWZ.cjs.map} +1 -1
  50. package/dist/{chunk-34X3ZJ6E.cjs → chunk-LXNFVHDT.cjs} +3 -2
  51. package/dist/{chunk-34X3ZJ6E.cjs.map → chunk-LXNFVHDT.cjs.map} +1 -1
  52. package/dist/chunk-M6AMNXQ7.js +4539 -0
  53. package/dist/chunk-M6AMNXQ7.js.map +1 -0
  54. package/dist/{chunk-XX4BKS7Y.js → chunk-MRGS54WN.js} +4 -3
  55. package/dist/chunk-MRGS54WN.js.map +1 -0
  56. package/dist/{chunk-ROFLJ74T.js → chunk-MXJ6FHSY.js} +4 -3
  57. package/dist/chunk-MXJ6FHSY.js.map +1 -0
  58. package/dist/{chunk-V6WO7RK7.cjs → chunk-PIQG2Z5N.cjs} +5 -4
  59. package/dist/chunk-PIQG2Z5N.cjs.map +1 -0
  60. package/dist/{chunk-U5GGE6PJ.js → chunk-RQX53J6M.js} +4 -3
  61. package/dist/chunk-RQX53J6M.js.map +1 -0
  62. package/dist/{chunk-N7KOXOMX.cjs → chunk-S6VPECM3.cjs} +72 -2
  63. package/dist/chunk-S6VPECM3.cjs.map +1 -0
  64. package/dist/{chunk-VFQCTXOX.js → chunk-SPIW4VWP.js} +4 -3
  65. package/dist/chunk-SPIW4VWP.js.map +1 -0
  66. package/dist/{chunk-IX554O5K.js → chunk-TIGP2OEJ.js} +72 -3
  67. package/dist/chunk-TIGP2OEJ.js.map +1 -0
  68. package/dist/{chunk-LMFSHK45.js → chunk-TPA36ULU.js} +4 -3
  69. package/dist/{chunk-LMFSHK45.js.map → chunk-TPA36ULU.js.map} +1 -1
  70. package/dist/{chunk-ZX7QKZK2.cjs → chunk-ULERCTGS.cjs} +5 -4
  71. package/dist/{chunk-ZX7QKZK2.cjs.map → chunk-ULERCTGS.cjs.map} +1 -1
  72. package/dist/chunk-VP54YPOX.cjs +4544 -0
  73. package/dist/chunk-VP54YPOX.cjs.map +1 -0
  74. package/dist/{chunk-XQ52ICHU.cjs → chunk-YKO7DY2F.cjs} +14 -13
  75. package/dist/chunk-YKO7DY2F.cjs.map +1 -0
  76. package/dist/{chunk-PDPHRZZT.js → chunk-YO4GU6JX.js} +4 -3
  77. package/dist/chunk-YO4GU6JX.js.map +1 -0
  78. package/dist/{chunk-S6BK5DB6.cjs → chunk-ZGKEFVJQ.cjs} +13 -12
  79. package/dist/chunk-ZGKEFVJQ.cjs.map +1 -0
  80. package/dist/{chunk-2MQWZ2XY.cjs → chunk-ZO77FHBF.cjs} +3 -2
  81. package/dist/chunk-ZO77FHBF.cjs.map +1 -0
  82. package/dist/diagrams/blockdiagram/index.cjs +5 -5
  83. package/dist/diagrams/blockdiagram/index.d.cts +1 -1
  84. package/dist/diagrams/blockdiagram/index.d.ts +1 -1
  85. package/dist/diagrams/blockdiagram/index.js +1 -1
  86. package/dist/diagrams/circuit/index.cjs +8 -8
  87. package/dist/diagrams/circuit/index.d.cts +1 -1
  88. package/dist/diagrams/circuit/index.d.ts +1 -1
  89. package/dist/diagrams/circuit/index.js +2 -2
  90. package/dist/diagrams/ecomap/index.cjs +7 -7
  91. package/dist/diagrams/ecomap/index.d.cts +1 -1
  92. package/dist/diagrams/ecomap/index.d.ts +1 -1
  93. package/dist/diagrams/ecomap/index.js +2 -2
  94. package/dist/diagrams/entity/index.cjs +6 -6
  95. package/dist/diagrams/entity/index.d.cts +1 -1
  96. package/dist/diagrams/entity/index.d.ts +1 -1
  97. package/dist/diagrams/entity/index.js +2 -2
  98. package/dist/diagrams/fishbone/index.cjs +8 -8
  99. package/dist/diagrams/fishbone/index.d.cts +1 -1
  100. package/dist/diagrams/fishbone/index.d.ts +1 -1
  101. package/dist/diagrams/fishbone/index.js +2 -2
  102. package/dist/diagrams/flowchart/index.cjs +8 -8
  103. package/dist/diagrams/flowchart/index.d.cts +2 -2
  104. package/dist/diagrams/flowchart/index.d.ts +2 -2
  105. package/dist/diagrams/flowchart/index.js +2 -2
  106. package/dist/diagrams/genogram/index.cjs +9 -9
  107. package/dist/diagrams/genogram/index.d.cts +1 -1
  108. package/dist/diagrams/genogram/index.d.ts +1 -1
  109. package/dist/diagrams/genogram/index.js +2 -2
  110. package/dist/diagrams/ladder/index.cjs +6 -6
  111. package/dist/diagrams/ladder/index.d.cts +1 -1
  112. package/dist/diagrams/ladder/index.d.ts +1 -1
  113. package/dist/diagrams/ladder/index.js +2 -2
  114. package/dist/diagrams/logic/index.cjs +6 -6
  115. package/dist/diagrams/logic/index.d.cts +1 -1
  116. package/dist/diagrams/logic/index.d.ts +1 -1
  117. package/dist/diagrams/logic/index.js +2 -2
  118. package/dist/diagrams/orgchart/index.cjs +7 -7
  119. package/dist/diagrams/orgchart/index.d.cts +1 -1
  120. package/dist/diagrams/orgchart/index.d.ts +1 -1
  121. package/dist/diagrams/orgchart/index.js +2 -2
  122. package/dist/diagrams/pedigree/index.cjs +7 -7
  123. package/dist/diagrams/pedigree/index.d.cts +1 -1
  124. package/dist/diagrams/pedigree/index.d.ts +1 -1
  125. package/dist/diagrams/pedigree/index.js +2 -2
  126. package/dist/diagrams/phylo/index.cjs +7 -7
  127. package/dist/diagrams/phylo/index.d.cts +1 -1
  128. package/dist/diagrams/phylo/index.d.ts +1 -1
  129. package/dist/diagrams/phylo/index.js +2 -2
  130. package/dist/diagrams/sld/index.cjs +6 -6
  131. package/dist/diagrams/sld/index.d.cts +1 -1
  132. package/dist/diagrams/sld/index.d.ts +1 -1
  133. package/dist/diagrams/sld/index.js +2 -2
  134. package/dist/diagrams/sociogram/index.cjs +6 -6
  135. package/dist/diagrams/sociogram/index.d.cts +1 -1
  136. package/dist/diagrams/sociogram/index.d.ts +1 -1
  137. package/dist/diagrams/sociogram/index.js +2 -2
  138. package/dist/diagrams/timing/index.cjs +4 -4
  139. package/dist/diagrams/timing/index.d.cts +1 -1
  140. package/dist/diagrams/timing/index.d.ts +1 -1
  141. package/dist/diagrams/timing/index.js +1 -1
  142. package/dist/diagrams/venn/index.cjs +9 -9
  143. package/dist/diagrams/venn/index.d.cts +1 -1
  144. package/dist/diagrams/venn/index.d.ts +1 -1
  145. package/dist/diagrams/venn/index.js +2 -2
  146. package/dist/export.cjs +87 -0
  147. package/dist/export.cjs.map +1 -0
  148. package/dist/export.d.cts +38 -0
  149. package/dist/export.d.ts +38 -0
  150. package/dist/export.js +83 -0
  151. package/dist/export.js.map +1 -0
  152. package/dist/{index-BXefHVce.d.cts → index-SSGpCggE.d.cts} +52 -3
  153. package/dist/{index-BSlza1YY.d.ts → index-ga04CTBI.d.ts} +52 -3
  154. package/dist/index.cjs +65 -1948
  155. package/dist/index.cjs.map +1 -1
  156. package/dist/index.d.cts +7 -12
  157. package/dist/index.d.ts +7 -12
  158. package/dist/index.js +19 -1942
  159. package/dist/index.js.map +1 -1
  160. package/dist/react.cjs +56 -0
  161. package/dist/react.cjs.map +1 -0
  162. package/dist/react.d.cts +24 -0
  163. package/dist/react.d.ts +24 -0
  164. package/dist/react.js +54 -0
  165. package/dist/react.js.map +1 -0
  166. package/dist/{types-DqfcYkcY.d.ts → types-BcPhMdHd.d.cts} +6 -2
  167. package/dist/{types-DqfcYkcY.d.cts → types-BcPhMdHd.d.ts} +6 -2
  168. package/package.json +31 -2
  169. package/dist/chunk-2MQWZ2XY.cjs.map +0 -1
  170. package/dist/chunk-2UKC6ZCY.cjs.map +0 -1
  171. package/dist/chunk-3FTUWAXK.cjs.map +0 -1
  172. package/dist/chunk-7FZSPKX3.cjs.map +0 -1
  173. package/dist/chunk-ADOXGKAK.js +0 -1251
  174. package/dist/chunk-ADOXGKAK.js.map +0 -1
  175. package/dist/chunk-CZRM7LT7.js.map +0 -1
  176. package/dist/chunk-D4JTSPOL.js.map +0 -1
  177. package/dist/chunk-DS47NTWZ.cjs.map +0 -1
  178. package/dist/chunk-FDLZEKEB.js.map +0 -1
  179. package/dist/chunk-FGPTCDUT.cjs.map +0 -1
  180. package/dist/chunk-HGHWCB6K.js.map +0 -1
  181. package/dist/chunk-IX554O5K.js.map +0 -1
  182. package/dist/chunk-MDICUK6F.cjs +0 -1258
  183. package/dist/chunk-MDICUK6F.cjs.map +0 -1
  184. package/dist/chunk-N7KOXOMX.cjs.map +0 -1
  185. package/dist/chunk-NYCIK4SU.cjs.map +0 -1
  186. package/dist/chunk-PDPHRZZT.js.map +0 -1
  187. package/dist/chunk-ROFLJ74T.js.map +0 -1
  188. package/dist/chunk-S6BK5DB6.cjs.map +0 -1
  189. package/dist/chunk-U5GGE6PJ.js.map +0 -1
  190. package/dist/chunk-V6WO7RK7.cjs.map +0 -1
  191. package/dist/chunk-VFQCTXOX.js.map +0 -1
  192. package/dist/chunk-XQ52ICHU.cjs.map +0 -1
  193. package/dist/chunk-XX4BKS7Y.js.map +0 -1
  194. package/dist/chunk-XXU36667.js.map +0 -1
@@ -0,0 +1,1880 @@
1
+ 'use strict';
2
+
3
+ var chunkS6VPECM3_cjs = require('./chunk-S6VPECM3.cjs');
4
+ var chunkHDKDQAEQ_cjs = require('./chunk-HDKDQAEQ.cjs');
5
+
6
+ // src/diagrams/flowchart/parser.ts
7
+ var FlowchartParseError = class extends Error {
8
+ constructor(message, line2, col) {
9
+ super(`[line ${line2}:${col}] ${message}`);
10
+ this.line = line2;
11
+ this.col = col;
12
+ this.name = "FlowchartParseError";
13
+ }
14
+ line;
15
+ col;
16
+ };
17
+ var DIRECTIONS = /* @__PURE__ */ new Set(["TB", "TD", "BT", "LR", "RL"]);
18
+ function parseShapeSuffix(line2, pos) {
19
+ const ch = line2[pos];
20
+ if (ch === void 0) return null;
21
+ if (ch === ">") {
22
+ const end = line2.indexOf("]", pos + 1);
23
+ if (end < 0) return null;
24
+ return { shape: "asymmetric", label: line2.slice(pos + 1, end).trim(), end: end + 1 };
25
+ }
26
+ if (ch === "(" && line2[pos + 1] === "(" && line2[pos + 2] === "(") {
27
+ const end = line2.indexOf(")))", pos + 3);
28
+ if (end < 0) return null;
29
+ return { shape: "double-circle", label: line2.slice(pos + 3, end).trim(), end: end + 3 };
30
+ }
31
+ if (ch === "(" && line2[pos + 1] === "[") {
32
+ const end = line2.indexOf("])", pos + 2);
33
+ if (end < 0) return null;
34
+ return { shape: "stadium", label: line2.slice(pos + 2, end).trim(), end: end + 2 };
35
+ }
36
+ if (ch === "(" && line2[pos + 1] === "(") {
37
+ const end = line2.indexOf("))", pos + 2);
38
+ if (end < 0) return null;
39
+ return { shape: "circle", label: line2.slice(pos + 2, end).trim(), end: end + 2 };
40
+ }
41
+ if (ch === "[" && line2[pos + 1] === "[") {
42
+ const end = line2.indexOf("]]", pos + 2);
43
+ if (end < 0) return null;
44
+ return { shape: "subroutine", label: line2.slice(pos + 2, end).trim(), end: end + 2 };
45
+ }
46
+ if (ch === "[" && line2[pos + 1] === "(") {
47
+ const end = line2.indexOf(")]", pos + 2);
48
+ if (end < 0) return null;
49
+ return { shape: "cylinder", label: line2.slice(pos + 2, end).trim(), end: end + 2 };
50
+ }
51
+ if (ch === "{" && line2[pos + 1] === "{") {
52
+ const end = line2.indexOf("}}", pos + 2);
53
+ if (end < 0) return null;
54
+ return { shape: "hexagon", label: line2.slice(pos + 2, end).trim(), end: end + 2 };
55
+ }
56
+ if (ch === "[" && line2[pos + 1] === "/") {
57
+ const endSlash = line2.indexOf("\\]", pos + 2);
58
+ if (endSlash >= 0) {
59
+ return { shape: "trapezoid", label: line2.slice(pos + 2, endSlash).trim(), end: endSlash + 2 };
60
+ }
61
+ const end = line2.indexOf("/]", pos + 2);
62
+ if (end < 0) return null;
63
+ return { shape: "parallelogram", label: line2.slice(pos + 2, end).trim(), end: end + 2 };
64
+ }
65
+ if (ch === "[" && line2[pos + 1] === "\\") {
66
+ const endFwd = line2.indexOf("/]", pos + 2);
67
+ if (endFwd >= 0) {
68
+ return { shape: "trapezoid-alt", label: line2.slice(pos + 2, endFwd).trim(), end: endFwd + 2 };
69
+ }
70
+ const end = line2.indexOf("\\]", pos + 2);
71
+ if (end < 0) return null;
72
+ return { shape: "parallelogram-alt", label: line2.slice(pos + 2, end).trim(), end: end + 2 };
73
+ }
74
+ if (ch === "[") {
75
+ const end = line2.indexOf("]", pos + 1);
76
+ if (end < 0) return null;
77
+ return { shape: "rect", label: line2.slice(pos + 1, end).trim(), end: end + 1 };
78
+ }
79
+ if (ch === "(") {
80
+ const end = line2.indexOf(")", pos + 1);
81
+ if (end < 0) return null;
82
+ return { shape: "round", label: line2.slice(pos + 1, end).trim(), end: end + 1 };
83
+ }
84
+ if (ch === "{") {
85
+ const end = line2.indexOf("}", pos + 1);
86
+ if (end < 0) return null;
87
+ return { shape: "diamond", label: line2.slice(pos + 1, end).trim(), end: end + 1 };
88
+ }
89
+ return null;
90
+ }
91
+ var ID_CHAR = /[A-Za-z0-9_-]/;
92
+ function parseEdgeOp(line2, pos) {
93
+ while (pos < line2.length && line2[pos] === " ") pos++;
94
+ const rest = line2.slice(pos);
95
+ const bi = rest.startsWith("<");
96
+ const i = bi ? 1 : 0;
97
+ if (rest[i] === "=") {
98
+ const m = /^(=+)(?:([^=<>]*)(=+))?(>)?/.exec(rest.slice(i));
99
+ if (!m) return null;
100
+ const full = m[0];
101
+ const inlineLabel = m[2]?.trim();
102
+ const hasArrow = m[4] === ">";
103
+ return {
104
+ kind: "thick",
105
+ bidirectional: bi && hasArrow,
106
+ end: pos + i + full.length,
107
+ inlineLabel: inlineLabel && inlineLabel.length > 0 ? inlineLabel : void 0
108
+ };
109
+ }
110
+ if (rest[i] === "-") {
111
+ const dm = /^-\.+/.exec(rest.slice(i));
112
+ if (dm) {
113
+ const mWithLabel = /^(-\.+)([^.\-<>]+)(\.+->|\.+-)/.exec(rest.slice(i));
114
+ if (mWithLabel) {
115
+ const full = mWithLabel[0];
116
+ const label = mWithLabel[2]?.trim();
117
+ const hasArrow = mWithLabel[3].endsWith(">");
118
+ return {
119
+ kind: "dotted",
120
+ bidirectional: bi && hasArrow,
121
+ end: pos + i + full.length,
122
+ inlineLabel: label && label.length > 0 ? label : void 0
123
+ };
124
+ }
125
+ const mPlain2 = /^(-\.+)(->|-)?/.exec(rest.slice(i));
126
+ if (mPlain2) {
127
+ const full = mPlain2[0];
128
+ const hasArrow = mPlain2[2] === "->";
129
+ return { kind: "dotted", bidirectional: bi && hasArrow, end: pos + i + full.length };
130
+ }
131
+ return null;
132
+ }
133
+ const mLabeled = /^(-{2,})([^-<>|=][^-<>|=]*?)(-{2,})(>|x|o)?/.exec(rest.slice(i));
134
+ if (mLabeled) {
135
+ const full = mLabeled[0];
136
+ const label = mLabeled[2]?.trim();
137
+ const endCh = mLabeled[4];
138
+ const kind = endCh === "x" ? "crossed" : endCh === "o" ? "round-end" : endCh === ">" ? "solid" : "none";
139
+ return {
140
+ kind,
141
+ bidirectional: bi && endCh === ">",
142
+ end: pos + i + full.length,
143
+ inlineLabel: label && label.length > 0 ? label : void 0
144
+ };
145
+ }
146
+ const mPlain = /^(-{2,})(>|x|o)?/.exec(rest.slice(i));
147
+ if (mPlain) {
148
+ const full = mPlain[0];
149
+ const endCh = mPlain[2];
150
+ const kind = endCh === "x" ? "crossed" : endCh === "o" ? "round-end" : endCh === ">" ? "solid" : "none";
151
+ return { kind, bidirectional: bi && endCh === ">", end: pos + i + full.length };
152
+ }
153
+ }
154
+ return null;
155
+ }
156
+ function parseNodeRef(line2, pos) {
157
+ let i = pos;
158
+ while (i < line2.length && ID_CHAR.test(line2[i])) i++;
159
+ if (i === pos) return null;
160
+ const id = line2.slice(pos, i);
161
+ const shape = parseShapeSuffix(line2, i);
162
+ if (shape) {
163
+ return { ref: { id, shape: shape.shape, label: shape.label }, end: shape.end };
164
+ }
165
+ return { ref: { id }, end: i };
166
+ }
167
+ function parsePipeLabel(line2, pos) {
168
+ if (line2[pos] !== "|") return null;
169
+ const end = line2.indexOf("|", pos + 1);
170
+ if (end < 0) return null;
171
+ return { label: line2.slice(pos + 1, end).trim(), end: end + 1 };
172
+ }
173
+ function skipSpaces(line2, pos) {
174
+ while (pos < line2.length && (line2[pos] === " " || line2[pos] === " ")) pos++;
175
+ return pos;
176
+ }
177
+ function registerNode(ref, nodes) {
178
+ if (ref.shape && ref.label !== void 0) {
179
+ nodes.push({ id: ref.id, shape: ref.shape, label: ref.label });
180
+ } else {
181
+ nodes.push({ id: ref.id, shape: "rect", label: ref.id });
182
+ }
183
+ }
184
+ function parseNodeGroup(line2, startPos, lineNo, nodes) {
185
+ let pos = skipSpaces(line2, startPos);
186
+ const first = parseNodeRef(line2, pos);
187
+ if (!first) {
188
+ throw new FlowchartParseError(
189
+ `expected node identifier, got ${JSON.stringify(line2.slice(pos, pos + 10))}`,
190
+ lineNo,
191
+ pos + 1
192
+ );
193
+ }
194
+ registerNode(first.ref, nodes);
195
+ const refs = [first.ref];
196
+ pos = first.end;
197
+ while (true) {
198
+ const p2 = skipSpaces(line2, pos);
199
+ if (line2[p2] !== "&") break;
200
+ const p3 = skipSpaces(line2, p2 + 1);
201
+ const next = parseNodeRef(line2, p3);
202
+ if (!next) break;
203
+ registerNode(next.ref, nodes);
204
+ refs.push(next.ref);
205
+ pos = next.end;
206
+ }
207
+ return { refs, end: pos };
208
+ }
209
+ function parseChainStatement(line2, lineNo) {
210
+ const nodes = [];
211
+ const edges = [];
212
+ let pos = skipSpaces(line2, 0);
213
+ const firstGroup = parseNodeGroup(line2, pos, lineNo, nodes);
214
+ let prevGroup = firstGroup.refs;
215
+ pos = firstGroup.end;
216
+ while (pos < line2.length) {
217
+ pos = skipSpaces(line2, pos);
218
+ if (pos >= line2.length) break;
219
+ const op = parseEdgeOp(line2, pos);
220
+ if (!op) {
221
+ const tail = line2.slice(pos).trim();
222
+ if (tail.length > 0) {
223
+ throw new FlowchartParseError(
224
+ `expected edge operator, got ${JSON.stringify(tail.slice(0, 10))}`,
225
+ lineNo,
226
+ pos + 1
227
+ );
228
+ }
229
+ break;
230
+ }
231
+ pos = op.end;
232
+ pos = skipSpaces(line2, pos);
233
+ let label = op.inlineLabel;
234
+ const pipe = parsePipeLabel(line2, pos);
235
+ if (pipe) {
236
+ label = pipe.label;
237
+ pos = pipe.end;
238
+ }
239
+ pos = skipSpaces(line2, pos);
240
+ const targetGroup = parseNodeGroup(line2, pos, lineNo, nodes);
241
+ pos = targetGroup.end;
242
+ for (const from of prevGroup) {
243
+ for (const to of targetGroup.refs) {
244
+ edges.push({
245
+ from: from.id,
246
+ to: to.id,
247
+ kind: op.kind,
248
+ label,
249
+ bidirectional: op.bidirectional
250
+ });
251
+ }
252
+ }
253
+ prevGroup = targetGroup.refs;
254
+ }
255
+ return { nodes, edges };
256
+ }
257
+ function parseSubgraphHeader(rest, idx) {
258
+ const defaultId = `sg_${idx}`;
259
+ const s = rest.trim();
260
+ if (!s) return { id: defaultId, label: defaultId, children: [], subgraphs: [] };
261
+ const idBracket = /^(\w[\w-]*)\s+\[([^\]]*)\]$/.exec(s);
262
+ if (idBracket) return { id: idBracket[1], label: idBracket[2], children: [], subgraphs: [] };
263
+ const idQuoted = /^(\w[\w-]*)\s+"([^"]*)"$/.exec(s);
264
+ if (idQuoted) return { id: idQuoted[1], label: idQuoted[2], children: [], subgraphs: [] };
265
+ const quotedOnly = /^"([^"]*)"$/.exec(s);
266
+ if (quotedOnly) return { id: defaultId, label: quotedOnly[1], children: [], subgraphs: [] };
267
+ const plainId = s.split(/\s/)[0];
268
+ return { id: plainId, label: plainId, children: [], subgraphs: [] };
269
+ }
270
+ function normalizeDirection(dir) {
271
+ const up = dir.toUpperCase();
272
+ if (up === "TD") return "TB";
273
+ if (up === "TB" || up === "BT" || up === "LR" || up === "RL") return up;
274
+ return "TB";
275
+ }
276
+ function parseCssProps(s) {
277
+ const props = {};
278
+ for (const part of s.split(",")) {
279
+ const colon = part.indexOf(":");
280
+ if (colon < 0) continue;
281
+ const key = part.slice(0, colon).trim();
282
+ const val = part.slice(colon + 1).trim();
283
+ if (key) props[key] = val;
284
+ }
285
+ return props;
286
+ }
287
+ function parseFlowchart(source) {
288
+ const lines = source.replace(/\r\n/g, "\n").split("\n");
289
+ const ast = {
290
+ type: "flowchart",
291
+ direction: "TB",
292
+ nodes: [],
293
+ edges: [],
294
+ subgraphs: [],
295
+ classDefs: [],
296
+ linkStyles: /* @__PURE__ */ new Map()
297
+ };
298
+ const nodeMap = /* @__PURE__ */ new Map();
299
+ let headerIdx = -1;
300
+ for (let i = 0; i < lines.length; i++) {
301
+ const t = lines[i].trim();
302
+ if (t.length === 0 || t.startsWith("%%")) continue;
303
+ headerIdx = i;
304
+ break;
305
+ }
306
+ if (headerIdx < 0) throw new FlowchartParseError("empty flowchart source", 1, 1);
307
+ const header = lines[headerIdx].trim();
308
+ const headerMatch = /^(flowchart|graph)(?:\s+(\w+))?(?:\s+(.*))?$/i.exec(header);
309
+ if (!headerMatch) {
310
+ throw new FlowchartParseError(
311
+ `expected 'flowchart' or 'graph' header, got ${JSON.stringify(header)}`,
312
+ headerIdx + 1,
313
+ 1
314
+ );
315
+ }
316
+ const dirTok = headerMatch[2];
317
+ if (dirTok) {
318
+ if (!DIRECTIONS.has(dirTok.toUpperCase())) {
319
+ throw new FlowchartParseError(`unknown direction ${JSON.stringify(dirTok)}`, headerIdx + 1, 1);
320
+ }
321
+ ast.direction = normalizeDirection(dirTok);
322
+ }
323
+ const extra = headerMatch[3]?.trim();
324
+ if (extra) {
325
+ const mQuoted = /^"([^"]*)"$/.exec(extra);
326
+ ast.title = mQuoted ? mQuoted[1] : extra;
327
+ }
328
+ const subgraphStack = [];
329
+ for (let i = headerIdx + 1; i < lines.length; i++) {
330
+ const raw = lines[i];
331
+ const trimmed = raw.trim();
332
+ if (trimmed.length === 0 || trimmed.startsWith("%%")) continue;
333
+ const sgMatch = /^subgraph(?:\s+(.*))?$/.exec(trimmed);
334
+ if (sgMatch) {
335
+ const sg = parseSubgraphHeader(sgMatch[1] ?? "", ast.subgraphs.length);
336
+ let finalId = sg.id;
337
+ let collision = 0;
338
+ while (ast.subgraphs.some((s) => s.id === finalId)) {
339
+ finalId = `${sg.id}_${++collision}`;
340
+ }
341
+ sg.id = finalId;
342
+ ast.subgraphs.push(sg);
343
+ if (subgraphStack.length > 0) {
344
+ const parent = subgraphStack[subgraphStack.length - 1];
345
+ if (!parent.subgraphs.includes(sg.id)) parent.subgraphs.push(sg.id);
346
+ }
347
+ subgraphStack.push(sg);
348
+ continue;
349
+ }
350
+ const dirMatch = /^direction\s+(TB|TD|BT|LR|RL)$/i.exec(trimmed);
351
+ if (dirMatch && subgraphStack.length > 0) {
352
+ subgraphStack[subgraphStack.length - 1].direction = normalizeDirection(dirMatch[1]);
353
+ continue;
354
+ }
355
+ if (trimmed === "end" && subgraphStack.length > 0) {
356
+ subgraphStack.pop();
357
+ continue;
358
+ }
359
+ const classMatch = /^class\s+([\w,\s]+?)\s+(\w[\w-]*)\s*$/.exec(trimmed);
360
+ if (classMatch) {
361
+ const idList = classMatch[1].split(/[,\s]+/).map((s) => s.trim()).filter((s) => s.length > 0);
362
+ const className = classMatch[2];
363
+ for (const nid of idList) {
364
+ const existing = nodeMap.get(nid);
365
+ if (!existing) {
366
+ const node = { id: nid, shape: "rect", label: nid, classes: [className] };
367
+ nodeMap.set(nid, node);
368
+ ast.nodes.push(node);
369
+ } else {
370
+ existing.classes = [...existing.classes ?? [], className];
371
+ }
372
+ }
373
+ continue;
374
+ }
375
+ const classDefMatch = /^classDef\s+(\w[\w-]*)\s+(.+)$/.exec(trimmed);
376
+ if (classDefMatch) {
377
+ const cdef = {
378
+ id: classDefMatch[1],
379
+ props: parseCssProps(classDefMatch[2])
380
+ };
381
+ const existIdx = ast.classDefs.findIndex((c) => c.id === cdef.id);
382
+ if (existIdx >= 0) ast.classDefs[existIdx] = cdef;
383
+ else ast.classDefs.push(cdef);
384
+ continue;
385
+ }
386
+ const styleMatch = /^style\s+(\w[\w-]*)\s+(.+)$/.exec(trimmed);
387
+ if (styleMatch) {
388
+ const nid = styleMatch[1];
389
+ const props = parseCssProps(styleMatch[2]);
390
+ const existing = nodeMap.get(nid);
391
+ if (existing) {
392
+ existing.style = { ...existing.style ?? {}, ...props };
393
+ } else {
394
+ const node = { id: nid, shape: "rect", label: nid, style: props };
395
+ nodeMap.set(nid, node);
396
+ ast.nodes.push(node);
397
+ }
398
+ continue;
399
+ }
400
+ if (/^linkStyle\s/.test(trimmed)) continue;
401
+ let parsed;
402
+ try {
403
+ parsed = parseChainStatement(trimmed, i + 1);
404
+ } catch (e) {
405
+ if (e instanceof FlowchartParseError) throw e;
406
+ continue;
407
+ }
408
+ const currentSg = subgraphStack.length > 0 ? subgraphStack[subgraphStack.length - 1] : null;
409
+ for (const ndef of parsed.nodes) {
410
+ const existing = nodeMap.get(ndef.id);
411
+ if (!existing) {
412
+ const node = {
413
+ id: ndef.id,
414
+ shape: ndef.shape,
415
+ label: ndef.label,
416
+ parent: currentSg?.id
417
+ };
418
+ nodeMap.set(ndef.id, node);
419
+ ast.nodes.push(node);
420
+ if (currentSg && !currentSg.children.includes(ndef.id)) {
421
+ currentSg.children.push(ndef.id);
422
+ }
423
+ } else {
424
+ if (ndef.label !== ndef.id) existing.label = ndef.label;
425
+ if (ndef.shape !== "rect") existing.shape = ndef.shape;
426
+ if (currentSg && !existing.parent) {
427
+ existing.parent = currentSg.id;
428
+ if (!currentSg.children.includes(existing.id)) currentSg.children.push(existing.id);
429
+ }
430
+ }
431
+ }
432
+ for (const e of parsed.edges) {
433
+ const edge = {
434
+ from: e.from,
435
+ to: e.to,
436
+ kind: e.kind,
437
+ label: e.label,
438
+ arrowEnd: e.kind === "solid" || e.kind === "thick" || e.kind === "dotted" || e.kind === "bidirectional" ? "arrow" : e.kind === "crossed" ? "cross" : e.kind === "round-end" ? "circle" : "none",
439
+ arrowStart: e.bidirectional ? "arrow" : "none"
440
+ };
441
+ ast.edges.push(edge);
442
+ }
443
+ }
444
+ return ast;
445
+ }
446
+
447
+ // src/core/layered/bk.ts
448
+ function bkXCoords(layers, segments, nodeSep) {
449
+ if (layers.length === 0) return /* @__PURE__ */ new Map();
450
+ const preds = /* @__PURE__ */ new Map();
451
+ const succs = /* @__PURE__ */ new Map();
452
+ const indexInLayer = /* @__PURE__ */ new Map();
453
+ const nodeById = /* @__PURE__ */ new Map();
454
+ for (const layer of layers) {
455
+ for (let i = 0; i < layer.length; i++) {
456
+ const n = layer[i];
457
+ indexInLayer.set(n.id, i);
458
+ nodeById.set(n.id, n);
459
+ preds.set(n.id, []);
460
+ succs.set(n.id, []);
461
+ }
462
+ }
463
+ for (const [u, v] of segments) {
464
+ if (!nodeById.has(u) || !nodeById.has(v)) continue;
465
+ succs.get(u).push(v);
466
+ preds.get(v).push(u);
467
+ }
468
+ const conflicts = findType1Conflicts(layers, preds, nodeById);
469
+ const xss = {};
470
+ for (const vertDir of ["u", "d"]) {
471
+ const adjNeighbors = vertDir === "u" ? (v) => preds.get(v) ?? [] : (v) => succs.get(v) ?? [];
472
+ const flippedV = vertDir === "u" ? layers : layers.slice().reverse();
473
+ for (const horizDir of ["l", "r"]) {
474
+ const flippedH = horizDir === "l" ? flippedV : flippedV.map((l) => l.slice().reverse());
475
+ const { root, align } = verticalAlignment(
476
+ flippedH,
477
+ conflicts,
478
+ adjNeighbors
479
+ );
480
+ let xs = horizontalCompaction(flippedH, root, align, nodeById, nodeSep);
481
+ if (horizDir === "r") {
482
+ const neg = /* @__PURE__ */ new Map();
483
+ for (const [k, v] of xs) neg.set(k, -v);
484
+ xs = neg;
485
+ }
486
+ xss[vertDir + horizDir] = xs;
487
+ }
488
+ }
489
+ alignCoordinates(xss, findSmallestWidthAlignment(xss, nodeById));
490
+ return balance(xss);
491
+ }
492
+ function findType1Conflicts(layers, preds, nodeById) {
493
+ const conflicts = /* @__PURE__ */ new Set();
494
+ if (layers.length < 2) return conflicts;
495
+ for (let li = 1; li < layers.length; li++) {
496
+ const prev = layers[li - 1];
497
+ const layer = layers[li];
498
+ const prevIdx = /* @__PURE__ */ new Map();
499
+ prev.forEach((n, i) => prevIdx.set(n.id, i));
500
+ let k0 = 0;
501
+ let scanPos = 0;
502
+ const lastIdx = layer.length - 1;
503
+ for (let i1 = 0; i1 < layer.length; i1++) {
504
+ const v = layer[i1];
505
+ let w = null;
506
+ if (v.isDummy) {
507
+ for (const p of preds.get(v.id) ?? []) {
508
+ if (nodeById.get(p)?.isDummy && prevIdx.has(p)) {
509
+ w = p;
510
+ break;
511
+ }
512
+ }
513
+ }
514
+ if (w !== null || i1 === lastIdx) {
515
+ const k1 = w !== null ? prevIdx.get(w) : prev.length - 1;
516
+ for (let i = scanPos; i <= i1; i++) {
517
+ const vv = layer[i];
518
+ for (const u of preds.get(vv.id) ?? []) {
519
+ const uPos = prevIdx.get(u);
520
+ if (uPos === void 0) continue;
521
+ if (uPos < k0 || uPos > k1) {
522
+ conflicts.add(conflictKey(u, vv.id));
523
+ }
524
+ }
525
+ }
526
+ scanPos = i1 + 1;
527
+ k0 = k1;
528
+ }
529
+ }
530
+ }
531
+ return conflicts;
532
+ }
533
+ function conflictKey(a, b) {
534
+ return a < b ? `${a}\0${b}` : `${b}\0${a}`;
535
+ }
536
+ function hasConflict(conflicts, a, b) {
537
+ return conflicts.has(conflictKey(a, b));
538
+ }
539
+ function verticalAlignment(layers, conflicts, neighborsOf) {
540
+ const root = /* @__PURE__ */ new Map();
541
+ const align = /* @__PURE__ */ new Map();
542
+ const pos = /* @__PURE__ */ new Map();
543
+ for (const layer of layers) {
544
+ for (let i = 0; i < layer.length; i++) {
545
+ const v = layer[i].id;
546
+ root.set(v, v);
547
+ align.set(v, v);
548
+ pos.set(v, i);
549
+ }
550
+ }
551
+ for (const layer of layers) {
552
+ let prevIdx = -1;
553
+ for (const vn of layer) {
554
+ const v = vn.id;
555
+ const ws = neighborsOf(v).slice();
556
+ if (ws.length === 0) continue;
557
+ ws.sort((a, b) => (pos.get(a) ?? 0) - (pos.get(b) ?? 0));
558
+ const mp = (ws.length - 1) / 2;
559
+ const mids = [Math.floor(mp), Math.ceil(mp)];
560
+ for (const mi of mids) {
561
+ if (align.get(v) !== v) continue;
562
+ const w = ws[mi];
563
+ if (hasConflict(conflicts, w, v)) continue;
564
+ const wPos = pos.get(w) ?? 0;
565
+ if (wPos <= prevIdx) continue;
566
+ align.set(w, v);
567
+ root.set(v, root.get(w));
568
+ align.set(v, root.get(v));
569
+ prevIdx = wPos;
570
+ }
571
+ }
572
+ }
573
+ return { root, align };
574
+ }
575
+ function horizontalCompaction(layers, root, align, nodeById, nodeSep) {
576
+ const xs = /* @__PURE__ */ new Map();
577
+ const sink = /* @__PURE__ */ new Map();
578
+ const shift = /* @__PURE__ */ new Map();
579
+ for (const layer of layers) {
580
+ for (const v of layer) {
581
+ sink.set(v.id, v.id);
582
+ shift.set(v.id, Number.POSITIVE_INFINITY);
583
+ }
584
+ }
585
+ const indexInLayer = /* @__PURE__ */ new Map();
586
+ const layerOf = /* @__PURE__ */ new Map();
587
+ for (let li = 0; li < layers.length; li++) {
588
+ for (let i = 0; i < layers[li].length; i++) {
589
+ const id = layers[li][i].id;
590
+ indexInLayer.set(id, i);
591
+ layerOf.set(id, li);
592
+ }
593
+ }
594
+ const sep = (uId, vId) => {
595
+ const u = nodeById.get(uId);
596
+ const v = nodeById.get(vId);
597
+ return u.width / 2 + nodeSep + v.width / 2;
598
+ };
599
+ const placeBlock = (v) => {
600
+ if (xs.has(v)) return;
601
+ xs.set(v, 0);
602
+ let w = v;
603
+ do {
604
+ const wi = indexInLayer.get(w);
605
+ const wLayer = layerOf.get(w);
606
+ if (wi > 0) {
607
+ const pred = layers[wLayer][wi - 1].id;
608
+ const u = root.get(pred);
609
+ placeBlock(u);
610
+ if (sink.get(v) === v) sink.set(v, sink.get(u));
611
+ if (sink.get(v) !== sink.get(u)) {
612
+ const candidate = xs.get(v) - xs.get(u) - sep(pred, w);
613
+ const cur = shift.get(sink.get(u)) ?? Number.POSITIVE_INFINITY;
614
+ shift.set(sink.get(u), Math.min(cur, candidate));
615
+ } else {
616
+ const candidate = xs.get(u) + sep(pred, w);
617
+ if (candidate > xs.get(v)) xs.set(v, candidate);
618
+ }
619
+ }
620
+ w = align.get(w);
621
+ } while (w !== v);
622
+ };
623
+ for (const layer of layers) {
624
+ for (const v of layer) {
625
+ if (root.get(v.id) === v.id) placeBlock(v.id);
626
+ }
627
+ }
628
+ const result = /* @__PURE__ */ new Map();
629
+ for (const layer of layers) {
630
+ for (const v of layer) {
631
+ const r = root.get(v.id);
632
+ const rx = xs.get(r) ?? 0;
633
+ const s = shift.get(sink.get(r));
634
+ const sx = s !== void 0 && s !== Number.POSITIVE_INFINITY ? s : 0;
635
+ result.set(v.id, rx + sx);
636
+ }
637
+ }
638
+ return result;
639
+ }
640
+ function findSmallestWidthAlignment(xss, nodeById, _nodeSep) {
641
+ let best = null;
642
+ let bestWidth = Number.POSITIVE_INFINITY;
643
+ for (const key of Object.keys(xss)) {
644
+ const xs = xss[key];
645
+ let minX = Number.POSITIVE_INFINITY;
646
+ let maxX = Number.NEGATIVE_INFINITY;
647
+ for (const [id, x] of xs) {
648
+ const n = nodeById.get(id);
649
+ if (!n) continue;
650
+ minX = Math.min(minX, x - n.width / 2);
651
+ maxX = Math.max(maxX, x + n.width / 2);
652
+ }
653
+ const w = maxX - minX;
654
+ if (w < bestWidth) {
655
+ bestWidth = w;
656
+ best = xs;
657
+ }
658
+ }
659
+ return best ?? /* @__PURE__ */ new Map();
660
+ }
661
+ function alignCoordinates(xss, ref) {
662
+ let refMin = Number.POSITIVE_INFINITY;
663
+ let refMax = Number.NEGATIVE_INFINITY;
664
+ for (const [, v] of ref) {
665
+ refMin = Math.min(refMin, v);
666
+ refMax = Math.max(refMax, v);
667
+ }
668
+ for (const key of Object.keys(xss)) {
669
+ const xs = xss[key];
670
+ if (xs === ref) continue;
671
+ let xMin = Number.POSITIVE_INFINITY;
672
+ let xMax = Number.NEGATIVE_INFINITY;
673
+ for (const [, v] of xs) {
674
+ xMin = Math.min(xMin, v);
675
+ xMax = Math.max(xMax, v);
676
+ }
677
+ const delta = key.endsWith("r") ? refMax - xMax : refMin - xMin;
678
+ if (delta === 0) continue;
679
+ for (const [k, v] of xs) xs.set(k, v + delta);
680
+ }
681
+ }
682
+ function balance(xss) {
683
+ const keys = Object.keys(xss);
684
+ const result = /* @__PURE__ */ new Map();
685
+ if (keys.length === 0) return result;
686
+ const ids = /* @__PURE__ */ new Set();
687
+ for (const k of keys) for (const id of xss[k].keys()) ids.add(id);
688
+ for (const id of ids) {
689
+ const vals = [];
690
+ for (const k of keys) {
691
+ const v = xss[k].get(id);
692
+ if (v !== void 0) vals.push(v);
693
+ }
694
+ vals.sort((a, b) => a - b);
695
+ const n = vals.length;
696
+ if (n === 0) continue;
697
+ if (n % 2 === 0) {
698
+ result.set(id, (vals[n / 2 - 1] + vals[n / 2]) / 2);
699
+ } else {
700
+ result.set(id, vals[(n - 1) / 2]);
701
+ }
702
+ }
703
+ return result;
704
+ }
705
+
706
+ // src/diagrams/flowchart/layout.ts
707
+ var FC_CONST = {
708
+ nodeWidth: 120,
709
+ nodeHeight: 44,
710
+ nodeSpacingX: 32,
711
+ // cross-flow gap between nodes in same layer
712
+ layerSpacingY: 56,
713
+ // flow-direction gap between layers
714
+ dummyWidth: 1,
715
+ padding: 24,
716
+ charWidth: 6.8,
717
+ // approx font-size 12 proportional width
718
+ labelHPad: 16,
719
+ minNodeWidth: 72,
720
+ maxLabelWidth: 220,
721
+ crossingSweepIters: 24
722
+ };
723
+ function greedyFAS(nodeIds, edges) {
724
+ const outAdj = /* @__PURE__ */ new Map();
725
+ const inAdj = /* @__PURE__ */ new Map();
726
+ for (const id of nodeIds) {
727
+ outAdj.set(id, /* @__PURE__ */ new Set());
728
+ inAdj.set(id, /* @__PURE__ */ new Set());
729
+ }
730
+ for (const e of edges) {
731
+ if (e.from === e.to) continue;
732
+ outAdj.get(e.from)?.add(e.to);
733
+ inAdj.get(e.to)?.add(e.from);
734
+ }
735
+ const s1 = [];
736
+ const s2 = [];
737
+ const remaining = new Set(nodeIds);
738
+ while (remaining.size > 0) {
739
+ let changed = true;
740
+ while (changed) {
741
+ changed = false;
742
+ for (const v of Array.from(remaining)) {
743
+ if ((outAdj.get(v)?.size ?? 0) === 0) {
744
+ s2.unshift(v);
745
+ removeVertex(v, remaining, outAdj, inAdj);
746
+ changed = true;
747
+ }
748
+ }
749
+ }
750
+ changed = true;
751
+ while (changed) {
752
+ changed = false;
753
+ for (const v of Array.from(remaining)) {
754
+ if ((inAdj.get(v)?.size ?? 0) === 0) {
755
+ s1.push(v);
756
+ removeVertex(v, remaining, outAdj, inAdj);
757
+ changed = true;
758
+ }
759
+ }
760
+ }
761
+ if (remaining.size === 0) break;
762
+ let best = null;
763
+ let bestScore = -Infinity;
764
+ for (const v of remaining) {
765
+ const score = (outAdj.get(v)?.size ?? 0) - (inAdj.get(v)?.size ?? 0);
766
+ if (score > bestScore) {
767
+ bestScore = score;
768
+ best = v;
769
+ }
770
+ }
771
+ if (best !== null) {
772
+ s1.push(best);
773
+ removeVertex(best, remaining, outAdj, inAdj);
774
+ }
775
+ }
776
+ const ordering = [...s1, ...s2];
777
+ const rank = /* @__PURE__ */ new Map();
778
+ ordering.forEach((id, i) => rank.set(id, i));
779
+ const feedback = /* @__PURE__ */ new Set();
780
+ edges.forEach((e, i) => {
781
+ if (e.from === e.to) {
782
+ feedback.add(i);
783
+ return;
784
+ }
785
+ const ru = rank.get(e.from);
786
+ const rv = rank.get(e.to);
787
+ if (ru !== void 0 && rv !== void 0 && ru > rv) {
788
+ feedback.add(i);
789
+ }
790
+ });
791
+ return feedback;
792
+ }
793
+ function removeVertex(v, remaining, outAdj, inAdj) {
794
+ remaining.delete(v);
795
+ const outs = outAdj.get(v);
796
+ if (outs) {
797
+ for (const w of outs) inAdj.get(w)?.delete(v);
798
+ }
799
+ const ins = inAdj.get(v);
800
+ if (ins) {
801
+ for (const u of ins) outAdj.get(u)?.delete(v);
802
+ }
803
+ outAdj.delete(v);
804
+ inAdj.delete(v);
805
+ }
806
+ function longestPathLayers(nodeIds, edges) {
807
+ const layer = /* @__PURE__ */ new Map();
808
+ for (const id of nodeIds) layer.set(id, 0);
809
+ const outAdj = /* @__PURE__ */ new Map();
810
+ const inDeg = /* @__PURE__ */ new Map();
811
+ for (const id of nodeIds) {
812
+ outAdj.set(id, []);
813
+ inDeg.set(id, 0);
814
+ }
815
+ for (const e of edges) {
816
+ if (e.from === e.to) continue;
817
+ outAdj.get(e.from)?.push(e.to);
818
+ inDeg.set(e.to, (inDeg.get(e.to) ?? 0) + 1);
819
+ }
820
+ const queue = [];
821
+ for (const id of nodeIds) {
822
+ if ((inDeg.get(id) ?? 0) === 0) queue.push(id);
823
+ }
824
+ const order = [];
825
+ const remIn = new Map(inDeg);
826
+ while (queue.length > 0) {
827
+ const v = queue.shift();
828
+ order.push(v);
829
+ for (const w of outAdj.get(v) ?? []) {
830
+ const d = (remIn.get(w) ?? 0) - 1;
831
+ remIn.set(w, d);
832
+ if (d === 0) queue.push(w);
833
+ }
834
+ }
835
+ if (order.length !== nodeIds.length) {
836
+ for (const id of nodeIds) {
837
+ if (!order.includes(id)) order.push(id);
838
+ }
839
+ }
840
+ for (const v of order) {
841
+ for (const w of outAdj.get(v) ?? []) {
842
+ const lv = layer.get(v) ?? 0;
843
+ const lw = layer.get(w) ?? 0;
844
+ if (lw < lv + 1) layer.set(w, lv + 1);
845
+ }
846
+ }
847
+ return layer;
848
+ }
849
+ function insertDummies(ledges, layerMap, genDummyId) {
850
+ const dummyIds = [];
851
+ const updated = [];
852
+ for (const e of ledges) {
853
+ if (e.from === e.to) {
854
+ updated.push(e);
855
+ continue;
856
+ }
857
+ const lu = layerMap.get(e.from) ?? 0;
858
+ const lv = layerMap.get(e.to) ?? 0;
859
+ const diff = Math.abs(lv - lu);
860
+ if (diff <= 1) {
861
+ e.chain = [e.from, e.to];
862
+ updated.push(e);
863
+ continue;
864
+ }
865
+ const step = lv > lu ? 1 : -1;
866
+ const chain = [e.from];
867
+ let curLayer = lu + step;
868
+ while (curLayer !== lv) {
869
+ const d = genDummyId();
870
+ layerMap.set(d, curLayer);
871
+ dummyIds.push(d);
872
+ chain.push(d);
873
+ curLayer += step;
874
+ }
875
+ chain.push(e.to);
876
+ e.chain = chain;
877
+ updated.push(e);
878
+ }
879
+ return { dummyIds, updatedEdges: updated };
880
+ }
881
+ function dfsInitOrder(layers, segments) {
882
+ const layerOf = /* @__PURE__ */ new Map();
883
+ layers.forEach((l, i) => l.forEach((id) => layerOf.set(id, i)));
884
+ const succ = /* @__PURE__ */ new Map();
885
+ for (const [u, v] of segments) {
886
+ if (!succ.has(u)) succ.set(u, []);
887
+ succ.get(u).push(v);
888
+ }
889
+ const order = layers.map(() => []);
890
+ const seen = /* @__PURE__ */ new Set();
891
+ const visit = (id) => {
892
+ if (seen.has(id)) return;
893
+ seen.add(id);
894
+ const l = layerOf.get(id);
895
+ if (l === void 0) return;
896
+ order[l].push(id);
897
+ for (const n of succ.get(id) ?? []) visit(n);
898
+ };
899
+ for (const id of layers[0] ?? []) visit(id);
900
+ for (const layer of layers) {
901
+ for (const id of layer) if (!seen.has(id)) {
902
+ seen.add(id);
903
+ const l = layerOf.get(id);
904
+ order[l].push(id);
905
+ }
906
+ }
907
+ return order;
908
+ }
909
+ function barycenterReorder(layer, fixed, neighborsOf, biasRight) {
910
+ const fixedIdx = /* @__PURE__ */ new Map();
911
+ fixed.forEach((id, i) => fixedIdx.set(id, i));
912
+ const scored = layer.map((id, i) => {
913
+ const neighbors = neighborsOf(id).map((n) => fixedIdx.get(n)).filter((p) => p !== void 0);
914
+ if (neighbors.length === 0) return { id, score: -1, orig: i, hasNeighbors: false };
915
+ const sum = neighbors.reduce((s, n) => s + n, 0);
916
+ return { id, score: sum / neighbors.length, orig: i, hasNeighbors: true };
917
+ });
918
+ const withNbrs = scored.filter((s) => s.hasNeighbors);
919
+ const withoutNbrs = scored.filter((s) => !s.hasNeighbors);
920
+ withNbrs.sort((a, b) => {
921
+ if (a.score !== b.score) return a.score - b.score;
922
+ return biasRight ? b.orig - a.orig : a.orig - b.orig;
923
+ });
924
+ const result = new Array(layer.length);
925
+ for (const s of withoutNbrs) result[s.orig] = s;
926
+ let k = 0;
927
+ for (let i = 0; i < result.length; i++) {
928
+ if (result[i] !== void 0) continue;
929
+ result[i] = withNbrs[k++];
930
+ }
931
+ return result.map((s) => s.id);
932
+ }
933
+ function orderLayers(layers, segments) {
934
+ const succ = /* @__PURE__ */ new Map();
935
+ const pred = /* @__PURE__ */ new Map();
936
+ for (const layer of layers) for (const id of layer) {
937
+ succ.set(id, []);
938
+ pred.set(id, []);
939
+ }
940
+ for (const [u, v] of segments) {
941
+ succ.get(u)?.push(v);
942
+ pred.get(v)?.push(u);
943
+ }
944
+ let result = dfsInitOrder(layers, segments);
945
+ let bestCrossings = countCrossings(result, segments);
946
+ let best = result.map((l) => l.slice());
947
+ const maxStale = 4;
948
+ let stale = 0;
949
+ for (let iter = 0; iter < FC_CONST.crossingSweepIters && stale < maxStale; iter++) {
950
+ const down = iter % 2 === 0;
951
+ const biasRight = iter % 4 >= 2;
952
+ const next = result.map((l) => l.slice());
953
+ if (down) {
954
+ for (let i = 1; i < next.length; i++) {
955
+ next[i] = barycenterReorder(
956
+ next[i],
957
+ next[i - 1],
958
+ (id) => pred.get(id) ?? [],
959
+ biasRight
960
+ );
961
+ }
962
+ } else {
963
+ for (let i = next.length - 2; i >= 0; i--) {
964
+ next[i] = barycenterReorder(
965
+ next[i],
966
+ next[i + 1],
967
+ (id) => succ.get(id) ?? [],
968
+ biasRight
969
+ );
970
+ }
971
+ }
972
+ const c = countCrossings(next, segments);
973
+ if (c < bestCrossings) {
974
+ bestCrossings = c;
975
+ best = next.map((l) => l.slice());
976
+ stale = 0;
977
+ } else {
978
+ stale++;
979
+ }
980
+ result = next;
981
+ }
982
+ return best;
983
+ }
984
+ function countCrossings(layers, segments) {
985
+ let total = 0;
986
+ const layerIdx = layers.map((l) => {
987
+ const m = /* @__PURE__ */ new Map();
988
+ l.forEach((id, i) => m.set(id, i));
989
+ return m;
990
+ });
991
+ for (let i = 0; i < layers.length - 1; i++) {
992
+ const upper = layerIdx[i];
993
+ const lower = layerIdx[i + 1];
994
+ const n = layers[i + 1].length;
995
+ if (n === 0) continue;
996
+ const edges = [];
997
+ for (const [u, v] of segments) {
998
+ const iu = upper.get(u);
999
+ const iv = lower.get(v);
1000
+ if (iu !== void 0 && iv !== void 0) edges.push([iu, iv]);
1001
+ }
1002
+ edges.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
1003
+ let firstIndex = 1;
1004
+ while (firstIndex < n) firstIndex <<= 1;
1005
+ const treeSize = 2 * firstIndex - 1;
1006
+ firstIndex -= 1;
1007
+ const tree = new Uint32Array(treeSize);
1008
+ for (const [, iv] of edges) {
1009
+ let idx = iv + firstIndex;
1010
+ tree[idx] += 1;
1011
+ let weightSum = 0;
1012
+ while (idx > 0) {
1013
+ if (idx % 2) weightSum += tree[idx + 1] ?? 0;
1014
+ idx = idx - 1 >> 1;
1015
+ tree[idx] += 1;
1016
+ }
1017
+ total += weightSum;
1018
+ }
1019
+ }
1020
+ return total;
1021
+ }
1022
+ function laneBasedXCoords(layerNodes, pathOf, nodeSpacingX, segments) {
1023
+ const INNER_PAD = 28;
1024
+ const LANE_GAP = 36;
1025
+ const laneOf = (id) => {
1026
+ const p = pathOf(id);
1027
+ return p.length > 0 ? p[0] : null;
1028
+ };
1029
+ const laneOrder = [];
1030
+ const laneSeen = /* @__PURE__ */ new Set();
1031
+ for (const layer of layerNodes) {
1032
+ for (const n of layer) {
1033
+ if (n.isDummy) continue;
1034
+ const lane = laneOf(n.id);
1035
+ if (!laneSeen.has(lane)) {
1036
+ laneSeen.add(lane);
1037
+ laneOrder.push(lane);
1038
+ }
1039
+ }
1040
+ }
1041
+ const lanesPerLayer = layerNodes.map(
1042
+ (layer) => {
1043
+ const m = /* @__PURE__ */ new Map();
1044
+ for (const n of layer) {
1045
+ if (n.isDummy) continue;
1046
+ const lane = laneOf(n.id);
1047
+ if (!m.has(lane)) m.set(lane, []);
1048
+ m.get(lane).push(n);
1049
+ }
1050
+ return m;
1051
+ }
1052
+ );
1053
+ const laneWidths = laneOrder.map((lane) => {
1054
+ let maxInner = 0;
1055
+ for (const layerLanes of lanesPerLayer) {
1056
+ const members = layerLanes.get(lane) ?? [];
1057
+ if (members.length === 0) continue;
1058
+ const inner = members.reduce((s, n) => s + n.width, 0) + (members.length - 1) * nodeSpacingX;
1059
+ if (inner > maxInner) maxInner = inner;
1060
+ }
1061
+ const pad = lane !== null ? 2 * INNER_PAD : 0;
1062
+ return maxInner + pad;
1063
+ });
1064
+ const laneStartX = [];
1065
+ {
1066
+ let x = 0;
1067
+ for (let i = 0; i < laneWidths.length; i++) {
1068
+ laneStartX.push(x);
1069
+ x += laneWidths[i];
1070
+ if (i < laneWidths.length - 1) x += LANE_GAP;
1071
+ }
1072
+ }
1073
+ const result = /* @__PURE__ */ new Map();
1074
+ for (let li = 0; li < lanesPerLayer.length; li++) {
1075
+ for (let laneIdx = 0; laneIdx < laneOrder.length; laneIdx++) {
1076
+ const lane = laneOrder[laneIdx];
1077
+ const members = lanesPerLayer[li].get(lane) ?? [];
1078
+ if (members.length === 0) continue;
1079
+ const laneW = laneWidths[laneIdx];
1080
+ const laneStart = laneStartX[laneIdx];
1081
+ const innerW = members.reduce((s, n) => s + n.width, 0) + (members.length - 1) * nodeSpacingX;
1082
+ let cursor = laneStart + (laneW - innerW) / 2;
1083
+ for (const n of members) {
1084
+ result.set(n.id, cursor + n.width / 2);
1085
+ cursor += n.width + nodeSpacingX;
1086
+ }
1087
+ }
1088
+ }
1089
+ for (let pass = 0; pass < 4; pass++) {
1090
+ for (const layer of layerNodes) {
1091
+ for (const n of layer) {
1092
+ if (!n.isDummy) continue;
1093
+ const neighbors = [];
1094
+ for (const [u, v] of segments) {
1095
+ if (v === n.id) {
1096
+ const ux = result.get(u);
1097
+ if (ux !== void 0) neighbors.push(ux);
1098
+ }
1099
+ if (u === n.id) {
1100
+ const vx = result.get(v);
1101
+ if (vx !== void 0) neighbors.push(vx);
1102
+ }
1103
+ }
1104
+ if (neighbors.length === 0) {
1105
+ if (!result.has(n.id)) result.set(n.id, 0);
1106
+ continue;
1107
+ }
1108
+ neighbors.sort((a, b) => a - b);
1109
+ result.set(n.id, neighbors[Math.floor(neighbors.length / 2)]);
1110
+ }
1111
+ }
1112
+ }
1113
+ return result;
1114
+ }
1115
+ function layoutFlowchart(ast) {
1116
+ const dir = ast.direction;
1117
+ const isHorizontalDir = dir === "LR" || dir === "RL";
1118
+ const sizeOf = (n) => {
1119
+ const labelW = Math.min(
1120
+ FC_CONST.maxLabelWidth,
1121
+ Math.ceil(n.label.length * FC_CONST.charWidth) + FC_CONST.labelHPad * 2
1122
+ );
1123
+ let shapeW = Math.max(FC_CONST.minNodeWidth, labelW);
1124
+ let shapeH = FC_CONST.nodeHeight;
1125
+ if (n.shape === "diamond") {
1126
+ shapeW = Math.max(shapeW, labelW * 1.25);
1127
+ shapeH = Math.max(shapeH, 52);
1128
+ }
1129
+ if (n.shape === "parallelogram" || n.shape === "parallelogram-alt" || n.shape === "trapezoid" || n.shape === "trapezoid-alt") {
1130
+ shapeW += 20;
1131
+ }
1132
+ if (n.shape === "stadium" || n.shape === "round") {
1133
+ shapeW = Math.max(shapeW, shapeH + 20);
1134
+ }
1135
+ if (n.shape === "circle" || n.shape === "double-circle") {
1136
+ const side = Math.max(shapeW, shapeH) + 8;
1137
+ shapeW = side;
1138
+ shapeH = side;
1139
+ }
1140
+ if (n.shape === "hexagon") {
1141
+ shapeW = Math.max(shapeW, labelW + 44);
1142
+ }
1143
+ if (n.shape === "cylinder") {
1144
+ shapeH = Math.max(shapeH, 52);
1145
+ }
1146
+ if (n.shape === "subroutine") {
1147
+ shapeW = Math.max(shapeW, labelW + 36);
1148
+ }
1149
+ return isHorizontalDir ? { w: shapeH, h: shapeW } : { w: shapeW, h: shapeH };
1150
+ };
1151
+ const nodeMap = /* @__PURE__ */ new Map();
1152
+ for (const n of ast.nodes) nodeMap.set(n.id, n);
1153
+ for (const e of ast.edges) {
1154
+ for (const id of [e.from, e.to]) {
1155
+ if (!nodeMap.has(id)) {
1156
+ const implicit = { id, label: id, shape: "rect" };
1157
+ nodeMap.set(id, implicit);
1158
+ ast.nodes.push(implicit);
1159
+ }
1160
+ }
1161
+ }
1162
+ const allIds = Array.from(nodeMap.keys());
1163
+ const feedbackIdx = greedyFAS(allIds, ast.edges);
1164
+ const ledges = ast.edges.map((e, i) => {
1165
+ const reversed = feedbackIdx.has(i) && e.from !== e.to;
1166
+ return {
1167
+ from: reversed ? e.to : e.from,
1168
+ to: reversed ? e.from : e.to,
1169
+ original: e,
1170
+ isReversed: reversed,
1171
+ chain: []
1172
+ };
1173
+ });
1174
+ const layerMap = longestPathLayers(allIds, ledges);
1175
+ let dummyCounter = 0;
1176
+ const dummies = [];
1177
+ const { updatedEdges } = insertDummies(ledges, layerMap, () => {
1178
+ const id = `__dummy_${dummyCounter++}`;
1179
+ dummies.push(id);
1180
+ return id;
1181
+ });
1182
+ const lnodes = /* @__PURE__ */ new Map();
1183
+ for (const id of allIds) {
1184
+ const n = nodeMap.get(id);
1185
+ const { w, h } = sizeOf(n);
1186
+ lnodes.set(id, {
1187
+ id,
1188
+ node: n,
1189
+ layer: layerMap.get(id) ?? 0,
1190
+ order: 0,
1191
+ width: w,
1192
+ height: h,
1193
+ isDummy: false
1194
+ });
1195
+ }
1196
+ for (const id of dummies) {
1197
+ lnodes.set(id, {
1198
+ id,
1199
+ layer: layerMap.get(id) ?? 0,
1200
+ order: 0,
1201
+ width: FC_CONST.dummyWidth,
1202
+ height: 0,
1203
+ isDummy: true
1204
+ });
1205
+ }
1206
+ const maxLayer = Math.max(0, ...Array.from(layerMap.values()));
1207
+ const layers = [];
1208
+ for (let i = 0; i <= maxLayer; i++) layers.push([]);
1209
+ for (const [id, layer] of layerMap) {
1210
+ layers[layer].push(id);
1211
+ }
1212
+ const segments = [];
1213
+ for (const e of updatedEdges) {
1214
+ if (e.chain.length >= 2) {
1215
+ for (let i = 0; i < e.chain.length - 1; i++) {
1216
+ segments.push([e.chain[i], e.chain[i + 1]]);
1217
+ }
1218
+ }
1219
+ }
1220
+ let ordered = orderLayers(layers, segments);
1221
+ const parentOf = /* @__PURE__ */ new Map();
1222
+ for (const n of ast.nodes) parentOf.set(n.id, n.parent);
1223
+ const sgParent = /* @__PURE__ */ new Map();
1224
+ for (const sg of ast.subgraphs) {
1225
+ for (const childSg of sg.subgraphs) sgParent.set(childSg, sg.id);
1226
+ if (!sgParent.has(sg.id)) sgParent.set(sg.id, void 0);
1227
+ }
1228
+ const ancestryPath = (id) => {
1229
+ const path2 = [];
1230
+ let cur = parentOf.get(id);
1231
+ while (cur !== void 0) {
1232
+ path2.unshift(cur);
1233
+ cur = sgParent.get(cur);
1234
+ }
1235
+ return path2;
1236
+ };
1237
+ const dummyAncestry = /* @__PURE__ */ new Map();
1238
+ for (const e of updatedEdges) {
1239
+ if (e.chain.length < 3) continue;
1240
+ const fromA = ancestryPath(e.chain[0]);
1241
+ const toA = ancestryPath(e.chain[e.chain.length - 1]);
1242
+ const common = [];
1243
+ for (let k = 0; k < Math.min(fromA.length, toA.length); k++) {
1244
+ if (fromA[k] === toA[k]) common.push(fromA[k]);
1245
+ else break;
1246
+ }
1247
+ for (let i = 1; i < e.chain.length - 1; i++) {
1248
+ dummyAncestry.set(e.chain[i], common);
1249
+ }
1250
+ }
1251
+ const pathOf = (id) => dummyAncestry.get(id) ?? ancestryPath(id);
1252
+ if (ast.subgraphs.length > 0) {
1253
+ ordered = ordered.map((layer) => {
1254
+ const keyed = layer.map((id, i) => ({ id, i, path: pathOf(id) }));
1255
+ keyed.sort((a, b) => {
1256
+ const la = a.path;
1257
+ const lb = b.path;
1258
+ const len = Math.min(la.length, lb.length);
1259
+ for (let k = 0; k < len; k++) {
1260
+ if (la[k] !== lb[k]) return la[k].localeCompare(lb[k]);
1261
+ }
1262
+ if (la.length !== lb.length) return la.length - lb.length;
1263
+ return a.i - b.i;
1264
+ });
1265
+ return keyed.map((k) => k.id);
1266
+ });
1267
+ }
1268
+ for (let li = 0; li < ordered.length; li++) {
1269
+ const layer = ordered[li];
1270
+ for (let oi = 0; oi < layer.length; oi++) {
1271
+ const n = lnodes.get(layer[oi]);
1272
+ if (n) n.order = oi;
1273
+ }
1274
+ }
1275
+ const layerNodes = ordered.map(
1276
+ (layer) => layer.map((id) => lnodes.get(id))
1277
+ );
1278
+ let xMap;
1279
+ if (ast.subgraphs.length > 0) {
1280
+ xMap = laneBasedXCoords(
1281
+ layerNodes,
1282
+ pathOf,
1283
+ FC_CONST.nodeSpacingX,
1284
+ segments
1285
+ );
1286
+ } else {
1287
+ const bkLayers = layerNodes.map(
1288
+ (layer) => layer.map((n) => ({ id: n.id, width: n.width, isDummy: n.isDummy }))
1289
+ );
1290
+ xMap = bkXCoords(bkLayers, segments, FC_CONST.nodeSpacingX);
1291
+ }
1292
+ const isHorizontal = dir === "LR" || dir === "RL";
1293
+ const layerGap = FC_CONST.layerSpacingY;
1294
+ const layerHeights = layerNodes.map((layer) => {
1295
+ let maxH = 0;
1296
+ for (const n of layer) {
1297
+ if (n.isDummy) continue;
1298
+ if (n.height > maxH) maxH = n.height;
1299
+ }
1300
+ return maxH > 0 ? maxH : FC_CONST.nodeHeight;
1301
+ });
1302
+ const hasClusters = ast.subgraphs.length > 0;
1303
+ const CLUSTER_OVERHEAD_TITLE = hasClusters ? 44 : 0;
1304
+ const CLUSTER_OVERHEAD_SIDE = hasClusters ? 24 : 0;
1305
+ const extraTopPad = isHorizontal ? CLUSTER_OVERHEAD_SIDE : CLUSTER_OVERHEAD_TITLE;
1306
+ const extraLeftPad = isHorizontal ? CLUSTER_OVERHEAD_TITLE : CLUSTER_OVERHEAD_SIDE;
1307
+ const layerCenterY = [];
1308
+ {
1309
+ let y = FC_CONST.padding + extraTopPad;
1310
+ for (let li = 0; li < layerHeights.length; li++) {
1311
+ y += layerHeights[li] / 2;
1312
+ layerCenterY.push(y);
1313
+ y += layerHeights[li] / 2 + layerGap;
1314
+ }
1315
+ }
1316
+ let minX = Infinity;
1317
+ let maxX = -Infinity;
1318
+ for (const [id, x] of xMap) {
1319
+ const n = lnodes.get(id);
1320
+ if (n.isDummy) continue;
1321
+ minX = Math.min(minX, x - n.width / 2);
1322
+ maxX = Math.max(maxX, x + n.width / 2);
1323
+ }
1324
+ if (!isFinite(minX)) {
1325
+ minX = 0;
1326
+ maxX = 100;
1327
+ }
1328
+ const padding = FC_CONST.padding;
1329
+ const shiftX = padding + extraLeftPad - minX;
1330
+ const placed = [];
1331
+ for (let li = 0; li < layerNodes.length; li++) {
1332
+ const y = layerCenterY[li];
1333
+ for (const n of layerNodes[li]) {
1334
+ if (n.isDummy) continue;
1335
+ const cx = (xMap.get(n.id) ?? 0) + shiftX;
1336
+ placed.push({
1337
+ id: n.id,
1338
+ x: cx - n.width / 2,
1339
+ y: y - n.height / 2,
1340
+ width: n.width,
1341
+ height: n.height,
1342
+ layer: li,
1343
+ order: n.order
1344
+ });
1345
+ }
1346
+ }
1347
+ const dummyPos = /* @__PURE__ */ new Map();
1348
+ for (let li = 0; li < layerNodes.length; li++) {
1349
+ const y = layerCenterY[li];
1350
+ for (const n of layerNodes[li]) {
1351
+ if (!n.isDummy) continue;
1352
+ dummyPos.set(n.id, {
1353
+ x: (xMap.get(n.id) ?? 0) + shiftX,
1354
+ y
1355
+ });
1356
+ }
1357
+ }
1358
+ const extraRightPad = isHorizontal ? CLUSTER_OVERHEAD_SIDE : CLUSTER_OVERHEAD_SIDE;
1359
+ const extraBottomPad = isHorizontal ? CLUSTER_OVERHEAD_SIDE : CLUSTER_OVERHEAD_SIDE;
1360
+ const canvasW = maxX - minX + 2 * padding + extraLeftPad + extraRightPad;
1361
+ const lastLayer = layerCenterY.length - 1;
1362
+ const canvasH = lastLayer >= 0 ? layerCenterY[lastLayer] + layerHeights[lastLayer] / 2 + padding + extraBottomPad : 2 * padding;
1363
+ const outNodes = placed.map((p) => {
1364
+ const base = lnodes.get(p.id).node;
1365
+ if (!isHorizontal) {
1366
+ return {
1367
+ node: base,
1368
+ x: p.x,
1369
+ y: p.y,
1370
+ width: p.width,
1371
+ height: p.height,
1372
+ layer: p.layer,
1373
+ order: p.order
1374
+ };
1375
+ }
1376
+ return {
1377
+ node: base,
1378
+ x: p.y,
1379
+ y: p.x,
1380
+ width: p.height,
1381
+ height: p.width,
1382
+ layer: p.layer,
1383
+ order: p.order
1384
+ };
1385
+ });
1386
+ const outWidth = isHorizontal ? canvasH : canvasW;
1387
+ const outHeight = isHorizontal ? canvasW : canvasH;
1388
+ const nodeCenter = /* @__PURE__ */ new Map();
1389
+ for (const ln of outNodes) {
1390
+ nodeCenter.set(ln.node.id, {
1391
+ x: ln.x + ln.width / 2,
1392
+ y: ln.y + ln.height / 2,
1393
+ w: ln.width,
1394
+ h: ln.height
1395
+ });
1396
+ }
1397
+ const dummyCenter = /* @__PURE__ */ new Map();
1398
+ for (const [id, p] of dummyPos) {
1399
+ if (!isHorizontal) dummyCenter.set(id, p);
1400
+ else dummyCenter.set(id, { x: p.y, y: p.x });
1401
+ }
1402
+ const outEdges = updatedEdges.map((le) => {
1403
+ const chain = le.chain.length > 0 ? le.chain : [le.from, le.to];
1404
+ const points = [];
1405
+ for (let i = 0; i < chain.length; i++) {
1406
+ const id = chain[i];
1407
+ const nc = nodeCenter.get(id);
1408
+ const dc = dummyCenter.get(id);
1409
+ if (nc) {
1410
+ points.push({ x: nc.x, y: nc.y });
1411
+ } else if (dc) {
1412
+ points.push({ x: dc.x, y: dc.y });
1413
+ }
1414
+ }
1415
+ if (points.length < 2) {
1416
+ return { edge: le.original, path: "" };
1417
+ }
1418
+ const startNode = nodeCenter.get(chain[0]);
1419
+ const endNode = nodeCenter.get(chain[chain.length - 1]);
1420
+ if (startNode) {
1421
+ points[0] = clipToBox(points[0], points[1], startNode, dir);
1422
+ }
1423
+ if (endNode) {
1424
+ points[points.length - 1] = clipToBox(
1425
+ points[points.length - 1],
1426
+ points[points.length - 2],
1427
+ endNode,
1428
+ dir);
1429
+ }
1430
+ const d = buildManhattanPath(points, dir);
1431
+ let labelAnchor;
1432
+ if (le.original.label) {
1433
+ labelAnchor = edgeLabelAnchor(points, dir);
1434
+ }
1435
+ return {
1436
+ edge: {
1437
+ ...le.original,
1438
+ isReversed: le.isReversed
1439
+ },
1440
+ path: d,
1441
+ labelAnchor
1442
+ };
1443
+ });
1444
+ function collectDescendantNodeIds(sgId) {
1445
+ const sg = ast.subgraphs.find((s) => s.id === sgId);
1446
+ if (!sg) return [];
1447
+ const ids = [...sg.children];
1448
+ for (const childSgId of sg.subgraphs) ids.push(...collectDescendantNodeIds(childSgId));
1449
+ return ids;
1450
+ }
1451
+ function computeDepth(sgId) {
1452
+ for (const s of ast.subgraphs) {
1453
+ if (s.subgraphs.includes(sgId)) return 1 + computeDepth(s.id);
1454
+ }
1455
+ return 0;
1456
+ }
1457
+ const CLUSTER_PAD = 24;
1458
+ const CLUSTER_TITLE_H = 20;
1459
+ const clusters = ast.subgraphs.map((sg) => {
1460
+ const memberIds = collectDescendantNodeIds(sg.id);
1461
+ const members = outNodes.filter((n) => memberIds.includes(n.node.id));
1462
+ if (members.length === 0) return null;
1463
+ const minX2 = Math.min(...members.map((n) => n.x)) - CLUSTER_PAD;
1464
+ const minY = Math.min(...members.map((n) => n.y)) - CLUSTER_PAD - CLUSTER_TITLE_H;
1465
+ const maxX2 = Math.max(...members.map((n) => n.x + n.width)) + CLUSTER_PAD;
1466
+ const maxY = Math.max(...members.map((n) => n.y + n.height)) + CLUSTER_PAD;
1467
+ return {
1468
+ subgraph: sg,
1469
+ x: minX2,
1470
+ y: minY,
1471
+ width: maxX2 - minX2,
1472
+ height: maxY - minY,
1473
+ depth: computeDepth(sg.id)
1474
+ };
1475
+ }).filter((c) => c !== null);
1476
+ return {
1477
+ width: outWidth,
1478
+ height: outHeight,
1479
+ direction: dir,
1480
+ nodes: outNodes,
1481
+ edges: outEdges,
1482
+ clusters
1483
+ };
1484
+ }
1485
+ function clipToBox(from, toward, box, dir, isStart) {
1486
+ const cx = box.x;
1487
+ const cy = box.y;
1488
+ if (dir === "TB" || dir === "BT") {
1489
+ const goingDown = toward.y >= from.y;
1490
+ return { x: cx, y: cy + (goingDown ? box.h / 2 : -box.h / 2) };
1491
+ }
1492
+ const goingRight = toward.x >= from.x;
1493
+ return { x: cx + (goingRight ? box.w / 2 : -box.w / 2), y: cy };
1494
+ }
1495
+ function buildManhattanPath(pts, dir) {
1496
+ if (pts.length === 0) return "";
1497
+ const parts = [`M ${fmt(pts[0].x)} ${fmt(pts[0].y)}`];
1498
+ const isHorizontal = dir === "LR" || dir === "RL";
1499
+ for (let i = 1; i < pts.length; i++) {
1500
+ const a = pts[i - 1];
1501
+ const b = pts[i];
1502
+ if (isHorizontal) {
1503
+ const midX = (a.x + b.x) / 2;
1504
+ parts.push(`L ${fmt(midX)} ${fmt(a.y)}`);
1505
+ parts.push(`L ${fmt(midX)} ${fmt(b.y)}`);
1506
+ parts.push(`L ${fmt(b.x)} ${fmt(b.y)}`);
1507
+ } else {
1508
+ const midY = (a.y + b.y) / 2;
1509
+ parts.push(`L ${fmt(a.x)} ${fmt(midY)}`);
1510
+ parts.push(`L ${fmt(b.x)} ${fmt(midY)}`);
1511
+ parts.push(`L ${fmt(b.x)} ${fmt(b.y)}`);
1512
+ }
1513
+ }
1514
+ return parts.join(" ");
1515
+ }
1516
+ function fmt(n) {
1517
+ return (Math.round(n * 100) / 100).toString();
1518
+ }
1519
+ function edgeLabelAnchor(pts, dir) {
1520
+ if (pts.length < 2) return pts[0] ?? { x: 0, y: 0 };
1521
+ const a = pts[0];
1522
+ const b = pts[1];
1523
+ const isHorizontal = dir === "LR" || dir === "RL";
1524
+ if (isHorizontal) {
1525
+ const midX = (a.x + b.x) / 2;
1526
+ const bends2 = Math.abs(a.y - b.y) > 1;
1527
+ if (bends2) {
1528
+ const midY2 = (a.y + b.y) / 2;
1529
+ return { x: midX + 6, y: midY2, textAnchor: "start" };
1530
+ }
1531
+ return { x: midX, y: a.y - 8, textAnchor: "middle" };
1532
+ }
1533
+ const midY = (a.y + b.y) / 2;
1534
+ const bends = Math.abs(a.x - b.x) > 1;
1535
+ if (bends) {
1536
+ const midX = (a.x + b.x) / 2;
1537
+ return { x: midX, y: midY - 8, textAnchor: "middle" };
1538
+ }
1539
+ return { x: a.x + 6, y: midY, textAnchor: "start" };
1540
+ }
1541
+
1542
+ // src/diagrams/flowchart/shapes.ts
1543
+ function shapeSVG(shape, w, h) {
1544
+ switch (shape) {
1545
+ // ── M1 core shapes ─────────────────────────────────────────
1546
+ case "rect":
1547
+ return chunkHDKDQAEQ_cjs.rect({ x: 0, y: 0, width: w, height: h, rx: 14, ry: 14, class: "sx-fc-node" });
1548
+ case "round":
1549
+ return chunkHDKDQAEQ_cjs.rect({ x: 0, y: 0, width: w, height: h, rx: 20, ry: 20, class: "sx-fc-node sx-fc-node-round" });
1550
+ case "stadium": {
1551
+ const r = Math.min(h / 2, 24);
1552
+ return chunkHDKDQAEQ_cjs.rect({ x: 0, y: 0, width: w, height: h, rx: r, ry: r, class: "sx-fc-node sx-fc-node-stadium" });
1553
+ }
1554
+ case "diamond": {
1555
+ const points = `${w / 2},0 ${w},${h / 2} ${w / 2},${h} 0,${h / 2}`;
1556
+ return chunkHDKDQAEQ_cjs.polygon({ points, class: "sx-fc-node sx-fc-node-diamond" });
1557
+ }
1558
+ case "parallelogram": {
1559
+ const slant = 20;
1560
+ const points = `${slant},0 ${w},0 ${w - slant},${h} 0,${h}`;
1561
+ return chunkHDKDQAEQ_cjs.polygon({ points, class: "sx-fc-node" });
1562
+ }
1563
+ // ── M2 additional shapes ────────────────────────────────────
1564
+ case "parallelogram-alt": {
1565
+ const slant = 20;
1566
+ const points = `0,0 ${w - slant},0 ${w},${h} ${slant},${h}`;
1567
+ return chunkHDKDQAEQ_cjs.polygon({ points, class: "sx-fc-node" });
1568
+ }
1569
+ case "trapezoid": {
1570
+ const slant = 16;
1571
+ const points = `0,0 ${w},0 ${w - slant},${h} ${slant},${h}`;
1572
+ return chunkHDKDQAEQ_cjs.polygon({ points, class: "sx-fc-node" });
1573
+ }
1574
+ case "trapezoid-alt": {
1575
+ const slant = 16;
1576
+ const points = `${slant},0 ${w - slant},0 ${w},${h} 0,${h}`;
1577
+ return chunkHDKDQAEQ_cjs.polygon({ points, class: "sx-fc-node" });
1578
+ }
1579
+ case "subroutine": {
1580
+ const barX = 10;
1581
+ const body = chunkHDKDQAEQ_cjs.rect({ x: 0, y: 0, width: w, height: h, rx: 2, class: "sx-fc-node" });
1582
+ const left = chunkHDKDQAEQ_cjs.line({ x1: barX, y1: 0, x2: barX, y2: h, class: "sx-fc-node-subline" });
1583
+ const right = chunkHDKDQAEQ_cjs.line({ x1: w - barX, y1: 0, x2: w - barX, y2: h, class: "sx-fc-node-subline" });
1584
+ return body + left + right;
1585
+ }
1586
+ case "cylinder": {
1587
+ const ry = Math.min(8, h / 4);
1588
+ const silhouette = chunkHDKDQAEQ_cjs.path({
1589
+ d: `M0,${ry} A${w / 2},${ry} 0 0,1 ${w},${ry} L${w},${h - ry} A${w / 2},${ry} 0 0,1 0,${h - ry} Z`,
1590
+ class: "sx-fc-node"
1591
+ });
1592
+ const topRim = chunkHDKDQAEQ_cjs.path({
1593
+ d: `M0,${ry} A${w / 2},${ry} 0 0,0 ${w},${ry}`,
1594
+ class: "sx-fc-node-arc"
1595
+ });
1596
+ return silhouette + topRim;
1597
+ }
1598
+ case "circle": {
1599
+ const r = Math.min(w, h) / 2 - 1;
1600
+ return chunkHDKDQAEQ_cjs.circle({ cx: w / 2, cy: h / 2, r, class: "sx-fc-node sx-fc-node-circle" });
1601
+ }
1602
+ case "double-circle": {
1603
+ const r1 = Math.min(w, h) / 2 - 1;
1604
+ const r2 = r1 - 5;
1605
+ const outer = chunkHDKDQAEQ_cjs.circle({ cx: w / 2, cy: h / 2, r: r1, class: "sx-fc-node" });
1606
+ const inner = chunkHDKDQAEQ_cjs.circle({ cx: w / 2, cy: h / 2, r: r2, class: "sx-fc-node-ring" });
1607
+ return outer + inner;
1608
+ }
1609
+ case "hexagon": {
1610
+ const cut = Math.min(20, w / 4);
1611
+ const points = `${cut},0 ${w - cut},0 ${w},${h / 2} ${w - cut},${h} ${cut},${h} 0,${h / 2}`;
1612
+ return chunkHDKDQAEQ_cjs.polygon({ points, class: "sx-fc-node sx-fc-node-hexagon" });
1613
+ }
1614
+ case "asymmetric": {
1615
+ const pts = `0,0 ${w - 15},0 ${w},${h / 2} ${w - 15},${h} 0,${h}`;
1616
+ return chunkHDKDQAEQ_cjs.polygon({ points: pts, class: "sx-fc-node" });
1617
+ }
1618
+ default:
1619
+ return chunkHDKDQAEQ_cjs.rect({ x: 0, y: 0, width: w, height: h, rx: 14, ry: 14, class: "sx-fc-node" });
1620
+ }
1621
+ }
1622
+
1623
+ // src/diagrams/flowchart/renderer.ts
1624
+ var CSS_TEMPLATE = (themeName) => {
1625
+ const t = chunkS6VPECM3_cjs.resolveFlowchartTheme(themeName);
1626
+ const c = t.classes;
1627
+ return `
1628
+ .sx-fc { background: ${t.bg}; font-family: system-ui, -apple-system, "Segoe UI", sans-serif; }
1629
+ .sx-fc-node { fill: ${t.fillMuted}; stroke: ${t.stroke}; stroke-width: 1.5; stroke-linejoin: round; }
1630
+ .sx-fc-node-stadium { fill: ${t.stadiumFill}; stroke: ${t.stroke}; }
1631
+ .sx-fc-node-diamond { fill: ${t.diamondFill}; stroke: ${t.stroke}; }
1632
+ .sx-fc-node-round { fill: ${t.roundFill}; stroke: ${t.stroke}; }
1633
+ .sx-fc-node-text { fill: ${t.text}; font: 12px system-ui, -apple-system, "Segoe UI", sans-serif; }
1634
+ /* Semantic class presets (applied via 'class A start') \u2014 override shape fills */
1635
+ .sx-fc-class-start > .sx-fc-node { fill: ${c.start.fill}; stroke: ${c.start.stroke}; }
1636
+ .sx-fc-class-start > .sx-fc-node-text { fill: ${c.start.text}; font-weight: 600; }
1637
+ .sx-fc-class-process > .sx-fc-node { fill: ${c.process.fill}; stroke: ${c.process.stroke}; }
1638
+ .sx-fc-class-process > .sx-fc-node-text { fill: ${c.process.text}; font-weight: 600; }
1639
+ .sx-fc-class-decision > .sx-fc-node { fill: ${c.decision.fill}; stroke: ${c.decision.stroke}; }
1640
+ .sx-fc-class-decision > .sx-fc-node-text { fill: ${c.decision.text}; font-weight: 600; }
1641
+ .sx-fc-class-success > .sx-fc-node { fill: ${c.success.fill}; stroke: ${c.success.stroke}; }
1642
+ .sx-fc-class-success > .sx-fc-node-text { fill: ${c.success.text}; font-weight: 600; }
1643
+ .sx-fc-class-danger > .sx-fc-node { fill: ${c.danger.fill}; stroke: ${c.danger.stroke}; }
1644
+ .sx-fc-class-danger > .sx-fc-node-text { fill: ${c.danger.text}; font-weight: 600; }
1645
+ .sx-fc-class-neutral > .sx-fc-node { fill: ${c.neutral.fill}; stroke: ${c.neutral.stroke}; }
1646
+ .sx-fc-class-neutral > .sx-fc-node-text { fill: ${c.neutral.text}; font-weight: 600; }
1647
+ .sx-fc-edge { fill: none; stroke: ${t.neutral}; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
1648
+ .sx-fc-edge-thick { stroke: ${t.stroke}; stroke-width: 2.4; }
1649
+ .sx-fc-edge-dashed { stroke-dasharray: 5 3; }
1650
+ .sx-fc-edge-dotted { stroke-dasharray: 1.5 3; }
1651
+ .sx-fc-edge-label { fill: ${t.textMuted}; font: 11px system-ui, -apple-system, "Segoe UI", sans-serif; }
1652
+ .sx-fc-edge-label-bg { fill: ${t.bg}; fill-opacity: 0.96; stroke: ${t.neutral}; stroke-width: 0.5; }
1653
+ .sx-fc-title { fill: ${t.text}; font: 600 14px system-ui, -apple-system, "Segoe UI", sans-serif; }
1654
+ /* Shape sub-elements */
1655
+ .sx-fc-node-subline { fill: none; stroke: ${t.stroke}; stroke-width: 1.5; }
1656
+ .sx-fc-node-arc { fill: none; stroke: ${t.stroke}; stroke-width: 1.5; }
1657
+ .sx-fc-node-ring { fill: none; stroke: ${t.stroke}; stroke-width: 1.8; }
1658
+ /* Cluster (subgraph) */
1659
+ .sx-fc-cluster { fill: ${t.fillMuted}; fill-opacity: 0.35; stroke: ${t.neutral}; stroke-width: 1.5; stroke-dasharray: 5,3; }
1660
+ .sx-fc-cluster-title { fill: ${t.textMuted}; font: 500 11px system-ui, -apple-system, "Segoe UI", sans-serif; }
1661
+ `.trim();
1662
+ };
1663
+ var ARROW_MARKER = `
1664
+ <marker id="sx-fc-arrow" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto-start-reverse" markerUnits="userSpaceOnUse">
1665
+ <path d="M0,0 L8,4 L0,8 L2,4 Z" fill="context-stroke"/>
1666
+ </marker>
1667
+ <marker id="sx-fc-arrow-o" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto" markerUnits="userSpaceOnUse">
1668
+ <circle cx="4" cy="4" r="3" fill="none" stroke="context-stroke" stroke-width="1"/>
1669
+ </marker>
1670
+ <marker id="sx-fc-arrow-x" markerWidth="8" markerHeight="8" refX="4" refY="4" orient="auto" markerUnits="userSpaceOnUse">
1671
+ <path d="M1,1 L7,7 M1,7 L7,1" stroke="context-stroke" stroke-width="1.2"/>
1672
+ </marker>
1673
+ `.trim();
1674
+ function edgeCssClass(edge) {
1675
+ const classes = ["sx-fc-edge"];
1676
+ if (edge.kind === "thick") classes.push("sx-fc-edge-thick");
1677
+ if (edge.kind === "dotted") classes.push("sx-fc-edge-dotted");
1678
+ return classes.join(" ");
1679
+ }
1680
+ function markerEndFor(edge) {
1681
+ switch (edge.arrowEnd) {
1682
+ case "arrow":
1683
+ return "url(#sx-fc-arrow)";
1684
+ case "circle":
1685
+ return "url(#sx-fc-arrow-o)";
1686
+ case "cross":
1687
+ return "url(#sx-fc-arrow-x)";
1688
+ default:
1689
+ return void 0;
1690
+ }
1691
+ }
1692
+ function markerStartFor(edge) {
1693
+ return edge.arrowStart === "arrow" ? "url(#sx-fc-arrow)" : void 0;
1694
+ }
1695
+ function renderCluster(lc) {
1696
+ const sg = lc.subgraph;
1697
+ const bg = chunkHDKDQAEQ_cjs.rect({ x: lc.x, y: lc.y, width: lc.width, height: lc.height, rx: 8, class: "sx-fc-cluster" });
1698
+ const label = chunkHDKDQAEQ_cjs.text(
1699
+ { x: lc.x + 12, y: lc.y + 15, class: "sx-fc-cluster-title" },
1700
+ sg.label
1701
+ );
1702
+ return chunkHDKDQAEQ_cjs.group(
1703
+ { "data-cluster-id": sg.id, "data-depth": lc.depth, class: "sx-fc-cluster-g" },
1704
+ [bg, label]
1705
+ );
1706
+ }
1707
+ function renderNode(ln) {
1708
+ const n = ln.node;
1709
+ const shapeEl = shapeSVG(n.shape, ln.width, ln.height);
1710
+ const label = chunkHDKDQAEQ_cjs.text(
1711
+ {
1712
+ x: ln.width / 2,
1713
+ y: ln.height / 2,
1714
+ class: "sx-fc-node-text",
1715
+ "text-anchor": "middle",
1716
+ "dominant-baseline": "central"
1717
+ },
1718
+ n.label
1719
+ );
1720
+ const nodeTitle = chunkHDKDQAEQ_cjs.title(n.label);
1721
+ const classAttr = ["sx-fc-node-g", ...(n.classes ?? []).map((c) => `sx-fc-class-${c}`)].join(" ");
1722
+ return chunkHDKDQAEQ_cjs.group(
1723
+ {
1724
+ "data-node-id": n.id,
1725
+ "data-shape": n.shape,
1726
+ "data-layer": ln.layer,
1727
+ "data-classes": n.classes?.join(" "),
1728
+ class: classAttr,
1729
+ transform: `translate(${fmt2(ln.x)} ${fmt2(ln.y)})`
1730
+ },
1731
+ [shapeEl, label, nodeTitle]
1732
+ );
1733
+ }
1734
+ function renderEdge(le) {
1735
+ const e = le.edge;
1736
+ const attrs = {
1737
+ d: le.path,
1738
+ class: edgeCssClass(e)
1739
+ };
1740
+ const me = markerEndFor(e);
1741
+ const ms = markerStartFor(e);
1742
+ if (me) attrs["marker-end"] = me;
1743
+ if (ms) attrs["marker-start"] = ms;
1744
+ const p = chunkHDKDQAEQ_cjs.path(attrs);
1745
+ const labelEl = e.label && le.labelAnchor ? renderEdgeLabel(
1746
+ e.label,
1747
+ le.labelAnchor.x,
1748
+ le.labelAnchor.y,
1749
+ le.labelAnchor.textAnchor ?? "middle"
1750
+ ) : "";
1751
+ const edgeTitle = chunkHDKDQAEQ_cjs.title(
1752
+ e.label ? `${e.from} \u2192 ${e.to}: ${e.label}` : `${e.from} \u2192 ${e.to}`
1753
+ );
1754
+ return chunkHDKDQAEQ_cjs.group(
1755
+ {
1756
+ "data-edge-id": e.id ?? `${e.from}->${e.to}`,
1757
+ "data-kind": e.kind,
1758
+ "data-from": e.from,
1759
+ "data-to": e.to
1760
+ },
1761
+ [p, edgeTitle, labelEl].filter((s) => s.length > 0)
1762
+ );
1763
+ }
1764
+ function renderEdgeLabel(label, cx, cy, textAnchor) {
1765
+ const w = Math.max(20, label.length * 6.5 + 10);
1766
+ const h = 16;
1767
+ const rx = cx - (textAnchor === "start" ? 0 : textAnchor === "end" ? w : w / 2);
1768
+ const ry = cy - h / 2;
1769
+ const bg = chunkHDKDQAEQ_cjs.rect({
1770
+ x: rx,
1771
+ y: ry,
1772
+ width: w,
1773
+ height: h,
1774
+ rx: 3,
1775
+ class: "sx-fc-edge-label-bg"
1776
+ });
1777
+ const t = chunkHDKDQAEQ_cjs.text(
1778
+ {
1779
+ x: cx,
1780
+ y: cy,
1781
+ class: "sx-fc-edge-label",
1782
+ "text-anchor": textAnchor,
1783
+ "dominant-baseline": "central"
1784
+ },
1785
+ label
1786
+ );
1787
+ return chunkHDKDQAEQ_cjs.group({ class: "sx-fc-edge-label-g" }, [bg, t]);
1788
+ }
1789
+ function fmt2(n) {
1790
+ return (Math.round(n * 100) / 100).toString();
1791
+ }
1792
+ function renderFlowchartAST(ast, themeName = "default") {
1793
+ const layout = layoutFlowchart(ast);
1794
+ const clusterSvg = layout.clusters.map(renderCluster);
1795
+ const nodeSvg = layout.nodes.map(renderNode);
1796
+ const edgeSvg = layout.edges.map(renderEdge);
1797
+ const nodeStyleOverrides = ast.nodes.filter((n) => n.style && Object.keys(n.style).length > 0).map((n) => {
1798
+ const props = Object.entries(n.style).map(([k, v]) => `${k}:${v}`).join(";");
1799
+ return `g[data-node-id="${n.id}"] .sx-fc-node { ${props} }`;
1800
+ }).join("\n");
1801
+ const classDefOverrides = ast.classDefs.map((cd) => {
1802
+ const props = Object.entries(cd.props).map(([k, v]) => `${k}:${v}`).join(";");
1803
+ return `.sx-fc-class-${cd.id} > .sx-fc-node { ${props} }`;
1804
+ }).join("\n");
1805
+ const titleBlock = ast.title ? chunkHDKDQAEQ_cjs.text(
1806
+ {
1807
+ x: layout.width / 2,
1808
+ y: 16,
1809
+ class: "sx-fc-title",
1810
+ "text-anchor": "middle"
1811
+ },
1812
+ ast.title
1813
+ ) : "";
1814
+ const cssOverrides = [nodeStyleOverrides, classDefOverrides].filter((s) => s.length > 0).join("\n");
1815
+ const headMeta = [
1816
+ chunkHDKDQAEQ_cjs.title(ast.title ? `${ast.title} \u2014 Flowchart` : "Flowchart"),
1817
+ chunkHDKDQAEQ_cjs.desc(
1818
+ `Flowchart with ${ast.nodes.length} node${ast.nodes.length === 1 ? "" : "s"} and ${ast.edges.length} edge${ast.edges.length === 1 ? "" : "s"}.`
1819
+ ),
1820
+ chunkHDKDQAEQ_cjs.el("style", {}, CSS_TEMPLATE(themeName) + (cssOverrides ? "\n" + cssOverrides : "")),
1821
+ chunkHDKDQAEQ_cjs.defs([ARROW_MARKER])
1822
+ ];
1823
+ const content = [];
1824
+ if (clusterSvg.length > 0) content.push(chunkHDKDQAEQ_cjs.group({ class: "sx-fc-clusters" }, clusterSvg));
1825
+ content.push(chunkHDKDQAEQ_cjs.group({ class: "sx-fc-edges" }, edgeSvg));
1826
+ content.push(chunkHDKDQAEQ_cjs.group({ class: "sx-fc-nodes" }, nodeSvg));
1827
+ const hasClusters = layout.clusters.length > 0;
1828
+ const topPad = ast.title ? hasClusters ? 56 : 24 : 0;
1829
+ const totalH = layout.height + topPad;
1830
+ const titleSvg = titleBlock;
1831
+ return chunkHDKDQAEQ_cjs.svgRoot(
1832
+ {
1833
+ viewBox: `0 0 ${fmt2(layout.width)} ${fmt2(totalH)}`,
1834
+ width: fmt2(layout.width),
1835
+ height: fmt2(totalH),
1836
+ class: "sx-fc",
1837
+ "data-diagram-type": "flowchart",
1838
+ "data-direction": layout.direction,
1839
+ role: "graphics-document"
1840
+ },
1841
+ topPad > 0 ? [
1842
+ ...headMeta,
1843
+ titleSvg,
1844
+ chunkHDKDQAEQ_cjs.group({ transform: `translate(0 ${topPad})` }, content)
1845
+ ] : [...headMeta, titleSvg, ...content]
1846
+ );
1847
+ }
1848
+ function renderFlowchart(text2, themeName = "default") {
1849
+ const ast = parseFlowchart(text2);
1850
+ return renderFlowchartAST(ast, themeName);
1851
+ }
1852
+
1853
+ // src/diagrams/flowchart/index.ts
1854
+ var flowchart = {
1855
+ type: "flowchart",
1856
+ detect(text2) {
1857
+ for (const raw of text2.split(/\r?\n/)) {
1858
+ const t = raw.trim();
1859
+ if (t.length === 0) continue;
1860
+ if (t.startsWith("%%")) continue;
1861
+ const first = t.split(/\s+/)[0]?.toLowerCase() ?? "";
1862
+ return first === "flowchart" || first === "graph";
1863
+ }
1864
+ return false;
1865
+ },
1866
+ parse: parseFlowchart,
1867
+ render(text2, config) {
1868
+ const themeName = config?.theme ?? "default";
1869
+ return renderFlowchart(text2, themeName);
1870
+ }
1871
+ };
1872
+
1873
+ exports.FC_CONST = FC_CONST;
1874
+ exports.flowchart = flowchart;
1875
+ exports.layoutFlowchart = layoutFlowchart;
1876
+ exports.parseFlowchart = parseFlowchart;
1877
+ exports.renderFlowchart = renderFlowchart;
1878
+ exports.renderFlowchartAST = renderFlowchartAST;
1879
+ //# sourceMappingURL=chunk-HAIBAF6J.cjs.map
1880
+ //# sourceMappingURL=chunk-HAIBAF6J.cjs.map