schematex 0.1.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 (181) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +379 -0
  3. package/dist/chunk-2MQWZ2XY.cjs +453 -0
  4. package/dist/chunk-2MQWZ2XY.cjs.map +1 -0
  5. package/dist/chunk-2UKC6ZCY.cjs +1803 -0
  6. package/dist/chunk-2UKC6ZCY.cjs.map +1 -0
  7. package/dist/chunk-34X3ZJ6E.cjs +783 -0
  8. package/dist/chunk-34X3ZJ6E.cjs.map +1 -0
  9. package/dist/chunk-3FTUWAXK.cjs +1220 -0
  10. package/dist/chunk-3FTUWAXK.cjs.map +1 -0
  11. package/dist/chunk-3J7TFUOC.js +745 -0
  12. package/dist/chunk-3J7TFUOC.js.map +1 -0
  13. package/dist/chunk-47ZC6EMJ.js +1009 -0
  14. package/dist/chunk-47ZC6EMJ.js.map +1 -0
  15. package/dist/chunk-4DBRNOPA.cjs +750 -0
  16. package/dist/chunk-4DBRNOPA.cjs.map +1 -0
  17. package/dist/chunk-4G7ZIBHN.js +778 -0
  18. package/dist/chunk-4G7ZIBHN.js.map +1 -0
  19. package/dist/chunk-5C7DPDHQ.js +1321 -0
  20. package/dist/chunk-5C7DPDHQ.js.map +1 -0
  21. package/dist/chunk-ADOXGKAK.js +1251 -0
  22. package/dist/chunk-ADOXGKAK.js.map +1 -0
  23. package/dist/chunk-BE5HNDA5.cjs +874 -0
  24. package/dist/chunk-BE5HNDA5.cjs.map +1 -0
  25. package/dist/chunk-CZRM7LT7.js +889 -0
  26. package/dist/chunk-CZRM7LT7.js.map +1 -0
  27. package/dist/chunk-D4JTSPOL.js +1795 -0
  28. package/dist/chunk-D4JTSPOL.js.map +1 -0
  29. package/dist/chunk-DS47NTWZ.cjs +1034 -0
  30. package/dist/chunk-DS47NTWZ.cjs.map +1 -0
  31. package/dist/chunk-FDLZEKEB.js +449 -0
  32. package/dist/chunk-FDLZEKEB.js.map +1 -0
  33. package/dist/chunk-FGPTCDUT.cjs +1851 -0
  34. package/dist/chunk-FGPTCDUT.cjs.map +1 -0
  35. package/dist/chunk-HDKDQAEQ.cjs +86 -0
  36. package/dist/chunk-HDKDQAEQ.cjs.map +1 -0
  37. package/dist/chunk-IX554O5K.js +346 -0
  38. package/dist/chunk-IX554O5K.js.map +1 -0
  39. package/dist/chunk-KLJEK547.js +71 -0
  40. package/dist/chunk-KLJEK547.js.map +1 -0
  41. package/dist/chunk-LMFSHK45.js +1028 -0
  42. package/dist/chunk-LMFSHK45.js.map +1 -0
  43. package/dist/chunk-MDICUK6F.cjs +1258 -0
  44. package/dist/chunk-MDICUK6F.cjs.map +1 -0
  45. package/dist/chunk-N7KOXOMX.cjs +363 -0
  46. package/dist/chunk-N7KOXOMX.cjs.map +1 -0
  47. package/dist/chunk-NYCIK4SU.cjs +775 -0
  48. package/dist/chunk-NYCIK4SU.cjs.map +1 -0
  49. package/dist/chunk-PDPHRZZT.js +770 -0
  50. package/dist/chunk-PDPHRZZT.js.map +1 -0
  51. package/dist/chunk-ROFLJ74T.js +1212 -0
  52. package/dist/chunk-ROFLJ74T.js.map +1 -0
  53. package/dist/chunk-S6BK5DB6.cjs +845 -0
  54. package/dist/chunk-S6BK5DB6.cjs.map +1 -0
  55. package/dist/chunk-U4I37IBN.js +874 -0
  56. package/dist/chunk-U4I37IBN.js.map +1 -0
  57. package/dist/chunk-U5GGE6PJ.js +839 -0
  58. package/dist/chunk-U5GGE6PJ.js.map +1 -0
  59. package/dist/chunk-UHLYS3W5.cjs +1015 -0
  60. package/dist/chunk-UHLYS3W5.cjs.map +1 -0
  61. package/dist/chunk-URSKIHSY.cjs +881 -0
  62. package/dist/chunk-URSKIHSY.cjs.map +1 -0
  63. package/dist/chunk-V6WO7RK7.cjs +1056 -0
  64. package/dist/chunk-V6WO7RK7.cjs.map +1 -0
  65. package/dist/chunk-VFQCTXOX.js +869 -0
  66. package/dist/chunk-VFQCTXOX.js.map +1 -0
  67. package/dist/chunk-XQ52ICHU.cjs +895 -0
  68. package/dist/chunk-XQ52ICHU.cjs.map +1 -0
  69. package/dist/chunk-XX4BKS7Y.js +1051 -0
  70. package/dist/chunk-XX4BKS7Y.js.map +1 -0
  71. package/dist/chunk-XXU36667.js +1844 -0
  72. package/dist/chunk-XXU36667.js.map +1 -0
  73. package/dist/chunk-ZX7QKZK2.cjs +1326 -0
  74. package/dist/chunk-ZX7QKZK2.cjs.map +1 -0
  75. package/dist/diagrams/blockdiagram/index.cjs +25 -0
  76. package/dist/diagrams/blockdiagram/index.cjs.map +1 -0
  77. package/dist/diagrams/blockdiagram/index.d.cts +67 -0
  78. package/dist/diagrams/blockdiagram/index.d.ts +67 -0
  79. package/dist/diagrams/blockdiagram/index.js +4 -0
  80. package/dist/diagrams/blockdiagram/index.js.map +1 -0
  81. package/dist/diagrams/circuit/index.cjs +34 -0
  82. package/dist/diagrams/circuit/index.cjs.map +1 -0
  83. package/dist/diagrams/circuit/index.d.cts +138 -0
  84. package/dist/diagrams/circuit/index.d.ts +138 -0
  85. package/dist/diagrams/circuit/index.js +5 -0
  86. package/dist/diagrams/circuit/index.js.map +1 -0
  87. package/dist/diagrams/ecomap/index.cjs +30 -0
  88. package/dist/diagrams/ecomap/index.cjs.map +1 -0
  89. package/dist/diagrams/ecomap/index.d.cts +15 -0
  90. package/dist/diagrams/ecomap/index.d.ts +15 -0
  91. package/dist/diagrams/ecomap/index.js +5 -0
  92. package/dist/diagrams/ecomap/index.js.map +1 -0
  93. package/dist/diagrams/entity/index.cjs +26 -0
  94. package/dist/diagrams/entity/index.cjs.map +1 -0
  95. package/dist/diagrams/entity/index.d.cts +54 -0
  96. package/dist/diagrams/entity/index.d.ts +54 -0
  97. package/dist/diagrams/entity/index.js +5 -0
  98. package/dist/diagrams/entity/index.js.map +1 -0
  99. package/dist/diagrams/fishbone/index.cjs +34 -0
  100. package/dist/diagrams/fishbone/index.cjs.map +1 -0
  101. package/dist/diagrams/fishbone/index.d.cts +185 -0
  102. package/dist/diagrams/fishbone/index.d.ts +185 -0
  103. package/dist/diagrams/fishbone/index.js +5 -0
  104. package/dist/diagrams/fishbone/index.js.map +1 -0
  105. package/dist/diagrams/flowchart/index.cjs +34 -0
  106. package/dist/diagrams/flowchart/index.cjs.map +1 -0
  107. package/dist/diagrams/flowchart/index.d.cts +2 -0
  108. package/dist/diagrams/flowchart/index.d.ts +2 -0
  109. package/dist/diagrams/flowchart/index.js +5 -0
  110. package/dist/diagrams/flowchart/index.js.map +1 -0
  111. package/dist/diagrams/genogram/index.cjs +38 -0
  112. package/dist/diagrams/genogram/index.cjs.map +1 -0
  113. package/dist/diagrams/genogram/index.d.cts +20 -0
  114. package/dist/diagrams/genogram/index.d.ts +20 -0
  115. package/dist/diagrams/genogram/index.js +5 -0
  116. package/dist/diagrams/genogram/index.js.map +1 -0
  117. package/dist/diagrams/ladder/index.cjs +26 -0
  118. package/dist/diagrams/ladder/index.cjs.map +1 -0
  119. package/dist/diagrams/ladder/index.d.cts +49 -0
  120. package/dist/diagrams/ladder/index.d.ts +49 -0
  121. package/dist/diagrams/ladder/index.js +5 -0
  122. package/dist/diagrams/ladder/index.js.map +1 -0
  123. package/dist/diagrams/logic/index.cjs +26 -0
  124. package/dist/diagrams/logic/index.cjs.map +1 -0
  125. package/dist/diagrams/logic/index.d.cts +73 -0
  126. package/dist/diagrams/logic/index.d.ts +73 -0
  127. package/dist/diagrams/logic/index.js +5 -0
  128. package/dist/diagrams/logic/index.js.map +1 -0
  129. package/dist/diagrams/orgchart/index.cjs +30 -0
  130. package/dist/diagrams/orgchart/index.cjs.map +1 -0
  131. package/dist/diagrams/orgchart/index.d.cts +100 -0
  132. package/dist/diagrams/orgchart/index.d.ts +100 -0
  133. package/dist/diagrams/orgchart/index.js +5 -0
  134. package/dist/diagrams/orgchart/index.js.map +1 -0
  135. package/dist/diagrams/pedigree/index.cjs +30 -0
  136. package/dist/diagrams/pedigree/index.cjs.map +1 -0
  137. package/dist/diagrams/pedigree/index.d.cts +15 -0
  138. package/dist/diagrams/pedigree/index.d.ts +15 -0
  139. package/dist/diagrams/pedigree/index.js +5 -0
  140. package/dist/diagrams/pedigree/index.js.map +1 -0
  141. package/dist/diagrams/phylo/index.cjs +30 -0
  142. package/dist/diagrams/phylo/index.cjs.map +1 -0
  143. package/dist/diagrams/phylo/index.d.cts +32 -0
  144. package/dist/diagrams/phylo/index.d.ts +32 -0
  145. package/dist/diagrams/phylo/index.js +5 -0
  146. package/dist/diagrams/phylo/index.js.map +1 -0
  147. package/dist/diagrams/sld/index.cjs +26 -0
  148. package/dist/diagrams/sld/index.cjs.map +1 -0
  149. package/dist/diagrams/sld/index.d.cts +58 -0
  150. package/dist/diagrams/sld/index.d.ts +58 -0
  151. package/dist/diagrams/sld/index.js +5 -0
  152. package/dist/diagrams/sld/index.js.map +1 -0
  153. package/dist/diagrams/sociogram/index.cjs +26 -0
  154. package/dist/diagrams/sociogram/index.cjs.map +1 -0
  155. package/dist/diagrams/sociogram/index.d.cts +76 -0
  156. package/dist/diagrams/sociogram/index.d.ts +76 -0
  157. package/dist/diagrams/sociogram/index.js +5 -0
  158. package/dist/diagrams/sociogram/index.js.map +1 -0
  159. package/dist/diagrams/timing/index.cjs +21 -0
  160. package/dist/diagrams/timing/index.cjs.map +1 -0
  161. package/dist/diagrams/timing/index.d.cts +9 -0
  162. package/dist/diagrams/timing/index.d.ts +9 -0
  163. package/dist/diagrams/timing/index.js +4 -0
  164. package/dist/diagrams/timing/index.js.map +1 -0
  165. package/dist/diagrams/venn/index.cjs +38 -0
  166. package/dist/diagrams/venn/index.cjs.map +1 -0
  167. package/dist/diagrams/venn/index.d.cts +69 -0
  168. package/dist/diagrams/venn/index.d.ts +69 -0
  169. package/dist/diagrams/venn/index.js +5 -0
  170. package/dist/diagrams/venn/index.js.map +1 -0
  171. package/dist/index-BSlza1YY.d.ts +150 -0
  172. package/dist/index-BXefHVce.d.cts +150 -0
  173. package/dist/index.cjs +2033 -0
  174. package/dist/index.cjs.map +1 -0
  175. package/dist/index.d.cts +29 -0
  176. package/dist/index.d.ts +29 -0
  177. package/dist/index.js +1944 -0
  178. package/dist/index.js.map +1 -0
  179. package/dist/types-DqfcYkcY.d.cts +741 -0
  180. package/dist/types-DqfcYkcY.d.ts +741 -0
  181. package/package.json +163 -0
@@ -0,0 +1,1258 @@
1
+ 'use strict';
2
+
3
+ var chunkN7KOXOMX_cjs = require('./chunk-N7KOXOMX.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, line, col) {
9
+ super(`[line ${line}:${col}] ${message}`);
10
+ this.line = line;
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(line, pos) {
19
+ const ch = line[pos];
20
+ if (ch === void 0) return null;
21
+ if (ch === "(" && line[pos + 1] === "[") {
22
+ const end = line.indexOf("])", pos + 2);
23
+ if (end < 0) return null;
24
+ return {
25
+ shape: "stadium",
26
+ label: line.slice(pos + 2, end).trim(),
27
+ end: end + 2
28
+ };
29
+ }
30
+ if (ch === "(" && line[pos + 1] === "(") {
31
+ const end = line.indexOf("))", pos + 2);
32
+ if (end < 0) return null;
33
+ return {
34
+ shape: "circle",
35
+ label: line.slice(pos + 2, end).trim(),
36
+ end: end + 2
37
+ };
38
+ }
39
+ if (ch === "[" && line[pos + 1] === "[") {
40
+ const end = line.indexOf("]]", pos + 2);
41
+ if (end < 0) return null;
42
+ return {
43
+ shape: "subroutine",
44
+ label: line.slice(pos + 2, end).trim(),
45
+ end: end + 2
46
+ };
47
+ }
48
+ if (ch === "[" && line[pos + 1] === "(") {
49
+ const end = line.indexOf(")]", pos + 2);
50
+ if (end < 0) return null;
51
+ return {
52
+ shape: "cylinder",
53
+ label: line.slice(pos + 2, end).trim(),
54
+ end: end + 2
55
+ };
56
+ }
57
+ if (ch === "{" && line[pos + 1] === "{") {
58
+ const end = line.indexOf("}}", pos + 2);
59
+ if (end < 0) return null;
60
+ return {
61
+ shape: "hexagon",
62
+ label: line.slice(pos + 2, end).trim(),
63
+ end: end + 2
64
+ };
65
+ }
66
+ if (ch === "[" && line[pos + 1] === "/") {
67
+ const end = line.indexOf("/]", pos + 2);
68
+ if (end < 0) return null;
69
+ return {
70
+ shape: "parallelogram",
71
+ label: line.slice(pos + 2, end).trim(),
72
+ end: end + 2
73
+ };
74
+ }
75
+ if (ch === "[" && line[pos + 1] === "\\") {
76
+ const end = line.indexOf("\\]", pos + 2);
77
+ if (end < 0) return null;
78
+ return {
79
+ shape: "parallelogram-alt",
80
+ label: line.slice(pos + 2, end).trim(),
81
+ end: end + 2
82
+ };
83
+ }
84
+ if (ch === "[") {
85
+ const end = line.indexOf("]", pos + 1);
86
+ if (end < 0) return null;
87
+ return {
88
+ shape: "rect",
89
+ label: line.slice(pos + 1, end).trim(),
90
+ end: end + 1
91
+ };
92
+ }
93
+ if (ch === "(") {
94
+ const end = line.indexOf(")", pos + 1);
95
+ if (end < 0) return null;
96
+ return {
97
+ shape: "round",
98
+ label: line.slice(pos + 1, end).trim(),
99
+ end: end + 1
100
+ };
101
+ }
102
+ if (ch === "{") {
103
+ const end = line.indexOf("}", pos + 1);
104
+ if (end < 0) return null;
105
+ return {
106
+ shape: "diamond",
107
+ label: line.slice(pos + 1, end).trim(),
108
+ end: end + 1
109
+ };
110
+ }
111
+ return null;
112
+ }
113
+ var ID_CHAR = /[A-Za-z0-9_-]/;
114
+ function parseEdgeOp(line, pos) {
115
+ while (pos < line.length && line[pos] === " ") pos++;
116
+ const rest = line.slice(pos);
117
+ const bi = rest.startsWith("<");
118
+ const i = bi ? 1 : 0;
119
+ if (rest[i] === "=") {
120
+ const m = /^(=+)(?:([^=<>]*)(=+))?(>)?/.exec(rest.slice(i));
121
+ if (!m) return null;
122
+ const full = m[0];
123
+ const inlineLabel = m[2]?.trim();
124
+ const hasArrow = m[4] === ">";
125
+ return {
126
+ kind: "thick",
127
+ bidirectional: bi && hasArrow,
128
+ end: pos + i + full.length,
129
+ inlineLabel: inlineLabel && inlineLabel.length > 0 ? inlineLabel : void 0
130
+ };
131
+ }
132
+ if (rest[i] === "-") {
133
+ const dm = /^-\.+/.exec(rest.slice(i));
134
+ if (dm) {
135
+ const mWithLabel = /^(-\.+)([^.\-<>]+)(\.+->|\.+-)/.exec(rest.slice(i));
136
+ if (mWithLabel) {
137
+ const full = mWithLabel[0];
138
+ const label = mWithLabel[2]?.trim();
139
+ const hasArrow = mWithLabel[3].endsWith(">");
140
+ return {
141
+ kind: "dotted",
142
+ bidirectional: bi && hasArrow,
143
+ end: pos + i + full.length,
144
+ inlineLabel: label && label.length > 0 ? label : void 0
145
+ };
146
+ }
147
+ const mPlain2 = /^(-\.+)(->|-)?/.exec(rest.slice(i));
148
+ if (mPlain2) {
149
+ const full = mPlain2[0];
150
+ const hasArrow = mPlain2[2] === "->";
151
+ return {
152
+ kind: "dotted",
153
+ bidirectional: bi && hasArrow,
154
+ end: pos + i + full.length
155
+ };
156
+ }
157
+ return null;
158
+ }
159
+ const mLabeled = /^(-{2,})([^-<>|=][^-<>|=]*?)(-{2,})(>|x|o)?/.exec(rest.slice(i));
160
+ if (mLabeled) {
161
+ const full = mLabeled[0];
162
+ const label = mLabeled[2]?.trim();
163
+ const endCh = mLabeled[4];
164
+ const kind = endCh === "x" ? "crossed" : endCh === "o" ? "round-end" : endCh === ">" ? "solid" : "none";
165
+ return {
166
+ kind,
167
+ bidirectional: bi && endCh === ">",
168
+ end: pos + i + full.length,
169
+ inlineLabel: label && label.length > 0 ? label : void 0
170
+ };
171
+ }
172
+ const mPlain = /^(-{2,})(>|x|o)?/.exec(rest.slice(i));
173
+ if (mPlain) {
174
+ const full = mPlain[0];
175
+ const endCh = mPlain[2];
176
+ const kind = endCh === "x" ? "crossed" : endCh === "o" ? "round-end" : endCh === ">" ? "solid" : "none";
177
+ return {
178
+ kind,
179
+ bidirectional: bi && endCh === ">",
180
+ end: pos + i + full.length
181
+ };
182
+ }
183
+ }
184
+ return null;
185
+ }
186
+ function parseNodeRef(line, pos) {
187
+ let i = pos;
188
+ while (i < line.length && ID_CHAR.test(line[i])) i++;
189
+ if (i === pos) return null;
190
+ const id = line.slice(pos, i);
191
+ const shape = parseShapeSuffix(line, i);
192
+ if (shape) {
193
+ return {
194
+ ref: { id, shape: shape.shape, label: shape.label },
195
+ end: shape.end
196
+ };
197
+ }
198
+ return { ref: { id }, end: i };
199
+ }
200
+ function parsePipeLabel(line, pos) {
201
+ if (line[pos] !== "|") return null;
202
+ const end = line.indexOf("|", pos + 1);
203
+ if (end < 0) return null;
204
+ return { label: line.slice(pos + 1, end).trim(), end: end + 1 };
205
+ }
206
+ function skipSpaces(line, pos) {
207
+ while (pos < line.length && (line[pos] === " " || line[pos] === " ")) pos++;
208
+ return pos;
209
+ }
210
+ function parseChainStatement(line, lineNo) {
211
+ const nodes = [];
212
+ const edges = [];
213
+ let pos = skipSpaces(line, 0);
214
+ const first = parseNodeRef(line, pos);
215
+ if (!first) {
216
+ throw new FlowchartParseError(
217
+ `expected node identifier, got ${JSON.stringify(line.slice(pos, pos + 10))}`,
218
+ lineNo,
219
+ pos + 1
220
+ );
221
+ }
222
+ if (first.ref.shape && first.ref.label !== void 0) {
223
+ nodes.push({ id: first.ref.id, shape: first.ref.shape, label: first.ref.label });
224
+ } else {
225
+ nodes.push({ id: first.ref.id, shape: "rect", label: first.ref.id });
226
+ }
227
+ let prev = first.ref;
228
+ pos = first.end;
229
+ while (pos < line.length) {
230
+ pos = skipSpaces(line, pos);
231
+ if (pos >= line.length) break;
232
+ const op = parseEdgeOp(line, pos);
233
+ if (!op) {
234
+ throw new FlowchartParseError(
235
+ `expected edge operator, got ${JSON.stringify(line.slice(pos, pos + 10))}`,
236
+ lineNo,
237
+ pos + 1
238
+ );
239
+ }
240
+ pos = op.end;
241
+ pos = skipSpaces(line, pos);
242
+ let label = op.inlineLabel;
243
+ const pipe = parsePipeLabel(line, pos);
244
+ if (pipe) {
245
+ label = pipe.label;
246
+ pos = pipe.end;
247
+ }
248
+ pos = skipSpaces(line, pos);
249
+ const target = parseNodeRef(line, pos);
250
+ if (!target) {
251
+ throw new FlowchartParseError(
252
+ `expected target node after edge, got ${JSON.stringify(line.slice(pos, pos + 10))}`,
253
+ lineNo,
254
+ pos + 1
255
+ );
256
+ }
257
+ if (target.ref.shape && target.ref.label !== void 0) {
258
+ nodes.push({
259
+ id: target.ref.id,
260
+ shape: target.ref.shape,
261
+ label: target.ref.label
262
+ });
263
+ } else {
264
+ nodes.push({ id: target.ref.id, shape: "rect", label: target.ref.id });
265
+ }
266
+ edges.push({
267
+ from: prev.id,
268
+ to: target.ref.id,
269
+ kind: op.kind,
270
+ label,
271
+ bidirectional: op.bidirectional
272
+ });
273
+ prev = target.ref;
274
+ pos = target.end;
275
+ }
276
+ return { nodes, edges };
277
+ }
278
+ function normalizeDirection(dir) {
279
+ const up = dir.toUpperCase();
280
+ if (up === "TD") return "TB";
281
+ if (up === "TB" || up === "BT" || up === "LR" || up === "RL") return up;
282
+ return "TB";
283
+ }
284
+ function parseFlowchart(source) {
285
+ const lines = source.replace(/\r\n/g, "\n").split("\n");
286
+ const ast = {
287
+ type: "flowchart",
288
+ direction: "TB",
289
+ nodes: [],
290
+ edges: [],
291
+ subgraphs: [],
292
+ classDefs: [],
293
+ linkStyles: /* @__PURE__ */ new Map()
294
+ };
295
+ const nodeMap = /* @__PURE__ */ new Map();
296
+ let headerIdx = -1;
297
+ for (let i = 0; i < lines.length; i++) {
298
+ const t = lines[i].trim();
299
+ if (t.length === 0 || t.startsWith("%%")) continue;
300
+ headerIdx = i;
301
+ break;
302
+ }
303
+ if (headerIdx < 0) {
304
+ throw new FlowchartParseError("empty flowchart source", 1, 1);
305
+ }
306
+ const header = lines[headerIdx].trim();
307
+ const headerMatch = /^(flowchart|graph)(?:\s+(\w+))?(?:\s+(.*))?$/i.exec(header);
308
+ if (!headerMatch) {
309
+ throw new FlowchartParseError(
310
+ `expected 'flowchart' or 'graph' header, got ${JSON.stringify(header)}`,
311
+ headerIdx + 1,
312
+ 1
313
+ );
314
+ }
315
+ const dirTok = headerMatch[2];
316
+ if (dirTok) {
317
+ if (!DIRECTIONS.has(dirTok.toUpperCase())) {
318
+ throw new FlowchartParseError(
319
+ `unknown direction ${JSON.stringify(dirTok)}`,
320
+ headerIdx + 1,
321
+ 1
322
+ );
323
+ }
324
+ ast.direction = normalizeDirection(dirTok);
325
+ }
326
+ const extra = headerMatch[3]?.trim();
327
+ if (extra) {
328
+ const mQuoted = /^"([^"]*)"$/.exec(extra);
329
+ ast.title = mQuoted ? mQuoted[1] : extra;
330
+ }
331
+ for (let i = headerIdx + 1; i < lines.length; i++) {
332
+ const raw = lines[i];
333
+ const trimmed = raw.trim();
334
+ if (trimmed.length === 0) continue;
335
+ if (trimmed.startsWith("%%")) continue;
336
+ const classMatch = /^class\s+([\w,\s]+?)\s+(\w[\w-]*)\s*$/.exec(trimmed);
337
+ if (classMatch) {
338
+ const idList = classMatch[1].split(/[,\s]+/).map((s) => s.trim()).filter((s) => s.length > 0);
339
+ const className = classMatch[2];
340
+ for (const nid of idList) {
341
+ const existing = nodeMap.get(nid);
342
+ if (!existing) {
343
+ const node = { id: nid, shape: "rect", label: nid, classes: [className] };
344
+ nodeMap.set(nid, node);
345
+ ast.nodes.push(node);
346
+ } else {
347
+ existing.classes = [...existing.classes ?? [], className];
348
+ }
349
+ }
350
+ continue;
351
+ }
352
+ const parsed = parseChainStatement(trimmed, i + 1);
353
+ for (const ndef of parsed.nodes) {
354
+ const existing = nodeMap.get(ndef.id);
355
+ if (!existing) {
356
+ const node = {
357
+ id: ndef.id,
358
+ shape: ndef.shape,
359
+ label: ndef.label
360
+ };
361
+ nodeMap.set(ndef.id, node);
362
+ ast.nodes.push(node);
363
+ } else {
364
+ if (ndef.label !== ndef.id) {
365
+ existing.label = ndef.label;
366
+ }
367
+ if (ndef.shape !== "rect") {
368
+ existing.shape = ndef.shape;
369
+ }
370
+ }
371
+ }
372
+ for (const e of parsed.edges) {
373
+ const edge = {
374
+ from: e.from,
375
+ to: e.to,
376
+ kind: e.kind,
377
+ label: e.label,
378
+ arrowEnd: e.kind === "solid" || e.kind === "thick" || e.kind === "dotted" || e.kind === "bidirectional" ? "arrow" : e.kind === "crossed" ? "cross" : e.kind === "round-end" ? "circle" : "none",
379
+ arrowStart: e.bidirectional ? "arrow" : "none"
380
+ };
381
+ ast.edges.push(edge);
382
+ }
383
+ }
384
+ return ast;
385
+ }
386
+
387
+ // src/diagrams/flowchart/layout.ts
388
+ var FC_CONST = {
389
+ nodeWidth: 120,
390
+ nodeHeight: 44,
391
+ nodeSpacingX: 32,
392
+ // cross-flow gap between nodes in same layer
393
+ layerSpacingY: 56,
394
+ // flow-direction gap between layers
395
+ dummyWidth: 1,
396
+ padding: 24,
397
+ charWidth: 6.8,
398
+ // approx font-size 12 proportional width
399
+ labelHPad: 16,
400
+ minNodeWidth: 72,
401
+ maxLabelWidth: 220,
402
+ crossingSweepIters: 24
403
+ };
404
+ function greedyFAS(nodeIds, edges) {
405
+ const outAdj = /* @__PURE__ */ new Map();
406
+ const inAdj = /* @__PURE__ */ new Map();
407
+ for (const id of nodeIds) {
408
+ outAdj.set(id, /* @__PURE__ */ new Set());
409
+ inAdj.set(id, /* @__PURE__ */ new Set());
410
+ }
411
+ for (const e of edges) {
412
+ if (e.from === e.to) continue;
413
+ outAdj.get(e.from)?.add(e.to);
414
+ inAdj.get(e.to)?.add(e.from);
415
+ }
416
+ const s1 = [];
417
+ const s2 = [];
418
+ const remaining = new Set(nodeIds);
419
+ while (remaining.size > 0) {
420
+ let changed = true;
421
+ while (changed) {
422
+ changed = false;
423
+ for (const v of Array.from(remaining)) {
424
+ if ((outAdj.get(v)?.size ?? 0) === 0) {
425
+ s2.unshift(v);
426
+ removeVertex(v, remaining, outAdj, inAdj);
427
+ changed = true;
428
+ }
429
+ }
430
+ }
431
+ changed = true;
432
+ while (changed) {
433
+ changed = false;
434
+ for (const v of Array.from(remaining)) {
435
+ if ((inAdj.get(v)?.size ?? 0) === 0) {
436
+ s1.push(v);
437
+ removeVertex(v, remaining, outAdj, inAdj);
438
+ changed = true;
439
+ }
440
+ }
441
+ }
442
+ if (remaining.size === 0) break;
443
+ let best = null;
444
+ let bestScore = -Infinity;
445
+ for (const v of remaining) {
446
+ const score = (outAdj.get(v)?.size ?? 0) - (inAdj.get(v)?.size ?? 0);
447
+ if (score > bestScore) {
448
+ bestScore = score;
449
+ best = v;
450
+ }
451
+ }
452
+ if (best !== null) {
453
+ s1.push(best);
454
+ removeVertex(best, remaining, outAdj, inAdj);
455
+ }
456
+ }
457
+ const ordering = [...s1, ...s2];
458
+ const rank = /* @__PURE__ */ new Map();
459
+ ordering.forEach((id, i) => rank.set(id, i));
460
+ const feedback = /* @__PURE__ */ new Set();
461
+ edges.forEach((e, i) => {
462
+ if (e.from === e.to) {
463
+ feedback.add(i);
464
+ return;
465
+ }
466
+ const ru = rank.get(e.from);
467
+ const rv = rank.get(e.to);
468
+ if (ru !== void 0 && rv !== void 0 && ru > rv) {
469
+ feedback.add(i);
470
+ }
471
+ });
472
+ return feedback;
473
+ }
474
+ function removeVertex(v, remaining, outAdj, inAdj) {
475
+ remaining.delete(v);
476
+ const outs = outAdj.get(v);
477
+ if (outs) {
478
+ for (const w of outs) inAdj.get(w)?.delete(v);
479
+ }
480
+ const ins = inAdj.get(v);
481
+ if (ins) {
482
+ for (const u of ins) outAdj.get(u)?.delete(v);
483
+ }
484
+ outAdj.delete(v);
485
+ inAdj.delete(v);
486
+ }
487
+ function longestPathLayers(nodeIds, edges) {
488
+ const layer = /* @__PURE__ */ new Map();
489
+ for (const id of nodeIds) layer.set(id, 0);
490
+ const outAdj = /* @__PURE__ */ new Map();
491
+ const inDeg = /* @__PURE__ */ new Map();
492
+ for (const id of nodeIds) {
493
+ outAdj.set(id, []);
494
+ inDeg.set(id, 0);
495
+ }
496
+ for (const e of edges) {
497
+ if (e.from === e.to) continue;
498
+ outAdj.get(e.from)?.push(e.to);
499
+ inDeg.set(e.to, (inDeg.get(e.to) ?? 0) + 1);
500
+ }
501
+ const queue = [];
502
+ for (const id of nodeIds) {
503
+ if ((inDeg.get(id) ?? 0) === 0) queue.push(id);
504
+ }
505
+ const order = [];
506
+ const remIn = new Map(inDeg);
507
+ while (queue.length > 0) {
508
+ const v = queue.shift();
509
+ order.push(v);
510
+ for (const w of outAdj.get(v) ?? []) {
511
+ const d = (remIn.get(w) ?? 0) - 1;
512
+ remIn.set(w, d);
513
+ if (d === 0) queue.push(w);
514
+ }
515
+ }
516
+ if (order.length !== nodeIds.length) {
517
+ for (const id of nodeIds) {
518
+ if (!order.includes(id)) order.push(id);
519
+ }
520
+ }
521
+ for (const v of order) {
522
+ for (const w of outAdj.get(v) ?? []) {
523
+ const lv = layer.get(v) ?? 0;
524
+ const lw = layer.get(w) ?? 0;
525
+ if (lw < lv + 1) layer.set(w, lv + 1);
526
+ }
527
+ }
528
+ return layer;
529
+ }
530
+ function insertDummies(ledges, layerMap, genDummyId) {
531
+ const dummyIds = [];
532
+ const updated = [];
533
+ for (const e of ledges) {
534
+ if (e.from === e.to) {
535
+ updated.push(e);
536
+ continue;
537
+ }
538
+ const lu = layerMap.get(e.from) ?? 0;
539
+ const lv = layerMap.get(e.to) ?? 0;
540
+ const diff = Math.abs(lv - lu);
541
+ if (diff <= 1) {
542
+ e.chain = [e.from, e.to];
543
+ updated.push(e);
544
+ continue;
545
+ }
546
+ const step = lv > lu ? 1 : -1;
547
+ const chain = [e.from];
548
+ let curLayer = lu + step;
549
+ while (curLayer !== lv) {
550
+ const d = genDummyId();
551
+ layerMap.set(d, curLayer);
552
+ dummyIds.push(d);
553
+ chain.push(d);
554
+ curLayer += step;
555
+ }
556
+ chain.push(e.to);
557
+ e.chain = chain;
558
+ updated.push(e);
559
+ }
560
+ return { dummyIds, updatedEdges: updated };
561
+ }
562
+ function medianOrder(layers, segments) {
563
+ const succ = /* @__PURE__ */ new Map();
564
+ const pred = /* @__PURE__ */ new Map();
565
+ for (const layer of layers) for (const id of layer) {
566
+ succ.set(id, []);
567
+ pred.set(id, []);
568
+ }
569
+ for (const [u, v] of segments) {
570
+ succ.get(u)?.push(v);
571
+ pred.get(v)?.push(u);
572
+ }
573
+ const indexOf = (layer, id) => layer.indexOf(id);
574
+ const reorderByMedian = (layer, fixed, useSucc) => {
575
+ const fixedIdx = /* @__PURE__ */ new Map();
576
+ fixed.forEach((id, i) => fixedIdx.set(id, i));
577
+ const scored = layer.map((id, i) => {
578
+ const neighbors = useSucc ? succ.get(id) ?? [] : pred.get(id) ?? [];
579
+ const positions = neighbors.map((n) => fixedIdx.get(n)).filter((p) => p !== void 0).sort((a, b) => a - b);
580
+ if (positions.length === 0) return { id, score: i, orig: i };
581
+ const m = positions.length;
582
+ const mid = positions[Math.floor(m / 2)];
583
+ const score = m % 2 === 1 ? mid : (positions[m / 2 - 1] + positions[m / 2]) / 2;
584
+ return { id, score, orig: i };
585
+ });
586
+ scored.sort((a, b) => a.score - b.score || a.orig - b.orig);
587
+ return scored.map((s) => s.id);
588
+ };
589
+ const result = layers.map((l) => l.slice());
590
+ let bestCrossings = countCrossings(result, segments, indexOf);
591
+ let best = result.map((l) => l.slice());
592
+ for (let iter = 0; iter < FC_CONST.crossingSweepIters; iter++) {
593
+ const down = iter % 2 === 0;
594
+ if (down) {
595
+ for (let i = 1; i < result.length; i++) {
596
+ result[i] = reorderByMedian(result[i], result[i - 1], false);
597
+ }
598
+ } else {
599
+ for (let i = result.length - 2; i >= 0; i--) {
600
+ result[i] = reorderByMedian(result[i], result[i + 1], true);
601
+ }
602
+ }
603
+ const c = countCrossings(result, segments, indexOf);
604
+ if (c < bestCrossings) {
605
+ bestCrossings = c;
606
+ best = result.map((l) => l.slice());
607
+ }
608
+ }
609
+ return best;
610
+ }
611
+ function countCrossings(layers, segments, indexOf) {
612
+ let total = 0;
613
+ for (let i = 0; i < layers.length - 1; i++) {
614
+ const upper = layers[i];
615
+ const lower = layers[i + 1];
616
+ const pairs = [];
617
+ for (const [u, v] of segments) {
618
+ const iu = indexOf(upper, u);
619
+ const iv = indexOf(lower, v);
620
+ if (iu >= 0 && iv >= 0) pairs.push([iu, iv]);
621
+ }
622
+ pairs.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
623
+ for (let a = 0; a < pairs.length; a++) {
624
+ for (let b = a + 1; b < pairs.length; b++) {
625
+ if (pairs[a][1] > pairs[b][1]) total++;
626
+ }
627
+ }
628
+ }
629
+ return total;
630
+ }
631
+ function assignXCoords(layers, nodeSpacingX) {
632
+ const x = /* @__PURE__ */ new Map();
633
+ const layerWidths = [];
634
+ for (const layer of layers) {
635
+ let w = 0;
636
+ for (let i = 0; i < layer.length; i++) {
637
+ w += layer[i].width;
638
+ if (i < layer.length - 1) w += nodeSpacingX;
639
+ }
640
+ layerWidths.push(w);
641
+ }
642
+ const maxWidth = Math.max(...layerWidths, 1);
643
+ for (let li = 0; li < layers.length; li++) {
644
+ const layer = layers[li];
645
+ const layerW = layerWidths[li];
646
+ let cursor = (maxWidth - layerW) / 2;
647
+ for (const n of layer) {
648
+ x.set(n.id, cursor + n.width / 2);
649
+ cursor += n.width + nodeSpacingX;
650
+ }
651
+ }
652
+ return x;
653
+ }
654
+ function layoutFlowchart(ast) {
655
+ const dir = ast.direction;
656
+ const isHorizontalDir = dir === "LR" || dir === "RL";
657
+ const sizeOf = (n) => {
658
+ const labelW = Math.min(
659
+ FC_CONST.maxLabelWidth,
660
+ Math.ceil(n.label.length * FC_CONST.charWidth) + FC_CONST.labelHPad * 2
661
+ );
662
+ let shapeW = Math.max(FC_CONST.minNodeWidth, labelW);
663
+ let shapeH = FC_CONST.nodeHeight;
664
+ if (n.shape === "diamond") {
665
+ shapeW = Math.max(shapeW, labelW * 1.25);
666
+ shapeH = Math.max(shapeH, 52);
667
+ }
668
+ if (n.shape === "parallelogram" || n.shape === "parallelogram-alt") {
669
+ shapeW += 20;
670
+ }
671
+ if (n.shape === "stadium" || n.shape === "round") {
672
+ shapeW = Math.max(shapeW, shapeH + 20);
673
+ }
674
+ return isHorizontalDir ? { w: shapeH, h: shapeW } : { w: shapeW, h: shapeH };
675
+ };
676
+ const nodeMap = /* @__PURE__ */ new Map();
677
+ for (const n of ast.nodes) nodeMap.set(n.id, n);
678
+ for (const e of ast.edges) {
679
+ for (const id of [e.from, e.to]) {
680
+ if (!nodeMap.has(id)) {
681
+ const implicit = { id, label: id, shape: "rect" };
682
+ nodeMap.set(id, implicit);
683
+ ast.nodes.push(implicit);
684
+ }
685
+ }
686
+ }
687
+ const allIds = Array.from(nodeMap.keys());
688
+ const feedbackIdx = greedyFAS(allIds, ast.edges);
689
+ const ledges = ast.edges.map((e, i) => {
690
+ const reversed = feedbackIdx.has(i) && e.from !== e.to;
691
+ return {
692
+ from: reversed ? e.to : e.from,
693
+ to: reversed ? e.from : e.to,
694
+ original: e,
695
+ isReversed: reversed,
696
+ chain: []
697
+ };
698
+ });
699
+ const layerMap = longestPathLayers(allIds, ledges);
700
+ let dummyCounter = 0;
701
+ const dummies = [];
702
+ const { updatedEdges } = insertDummies(ledges, layerMap, () => {
703
+ const id = `__dummy_${dummyCounter++}`;
704
+ dummies.push(id);
705
+ return id;
706
+ });
707
+ const lnodes = /* @__PURE__ */ new Map();
708
+ for (const id of allIds) {
709
+ const n = nodeMap.get(id);
710
+ const { w, h } = sizeOf(n);
711
+ lnodes.set(id, {
712
+ id,
713
+ node: n,
714
+ layer: layerMap.get(id) ?? 0,
715
+ order: 0,
716
+ width: w,
717
+ height: h,
718
+ isDummy: false
719
+ });
720
+ }
721
+ for (const id of dummies) {
722
+ lnodes.set(id, {
723
+ id,
724
+ layer: layerMap.get(id) ?? 0,
725
+ order: 0,
726
+ width: FC_CONST.dummyWidth,
727
+ height: 0,
728
+ isDummy: true
729
+ });
730
+ }
731
+ const maxLayer = Math.max(0, ...Array.from(layerMap.values()));
732
+ const layers = [];
733
+ for (let i = 0; i <= maxLayer; i++) layers.push([]);
734
+ for (const [id, layer] of layerMap) {
735
+ layers[layer].push(id);
736
+ }
737
+ const segments = [];
738
+ for (const e of updatedEdges) {
739
+ if (e.chain.length >= 2) {
740
+ for (let i = 0; i < e.chain.length - 1; i++) {
741
+ segments.push([e.chain[i], e.chain[i + 1]]);
742
+ }
743
+ }
744
+ }
745
+ const ordered = medianOrder(layers, segments);
746
+ for (let li = 0; li < ordered.length; li++) {
747
+ const layer = ordered[li];
748
+ for (let oi = 0; oi < layer.length; oi++) {
749
+ const n = lnodes.get(layer[oi]);
750
+ if (n) n.order = oi;
751
+ }
752
+ }
753
+ const layerNodes = ordered.map(
754
+ (layer) => layer.map((id) => lnodes.get(id))
755
+ );
756
+ const xMap = assignXCoords(layerNodes, FC_CONST.nodeSpacingX);
757
+ for (let pass = 0; pass < 4; pass++) {
758
+ for (let li = 0; li < layerNodes.length; li++) {
759
+ const layer = layerNodes[li];
760
+ const pullList = layer.map((n) => {
761
+ const neighbors = [];
762
+ for (const [u, v] of segments) {
763
+ if (v === n.id) {
764
+ const ux = xMap.get(u);
765
+ if (ux !== void 0) neighbors.push(ux);
766
+ }
767
+ if (u === n.id) {
768
+ const vx = xMap.get(v);
769
+ if (vx !== void 0) neighbors.push(vx);
770
+ }
771
+ }
772
+ if (neighbors.length === 0) return xMap.get(n.id) ?? 0;
773
+ neighbors.sort((a, b) => a - b);
774
+ return neighbors[Math.floor(neighbors.length / 2)];
775
+ });
776
+ let cursor = -Infinity;
777
+ for (let oi = 0; oi < layer.length; oi++) {
778
+ const n = layer[oi];
779
+ const desired = pullList[oi];
780
+ const minX2 = cursor + FC_CONST.nodeSpacingX + n.width / 2;
781
+ const newX = Math.max(desired, oi === 0 ? desired : minX2);
782
+ xMap.set(n.id, newX);
783
+ cursor = newX + n.width / 2;
784
+ }
785
+ }
786
+ }
787
+ const isHorizontal = dir === "LR" || dir === "RL";
788
+ const layerGap = FC_CONST.layerSpacingY;
789
+ const layerHeights = layerNodes.map((layer) => {
790
+ let maxH = 0;
791
+ for (const n of layer) {
792
+ if (n.isDummy) continue;
793
+ if (n.height > maxH) maxH = n.height;
794
+ }
795
+ return maxH > 0 ? maxH : FC_CONST.nodeHeight;
796
+ });
797
+ const layerCenterY = [];
798
+ {
799
+ let y = FC_CONST.padding;
800
+ for (let li = 0; li < layerHeights.length; li++) {
801
+ y += layerHeights[li] / 2;
802
+ layerCenterY.push(y);
803
+ y += layerHeights[li] / 2 + layerGap;
804
+ }
805
+ }
806
+ let minX = Infinity;
807
+ let maxX = -Infinity;
808
+ for (const [id, x] of xMap) {
809
+ const n = lnodes.get(id);
810
+ if (n.isDummy) continue;
811
+ minX = Math.min(minX, x - n.width / 2);
812
+ maxX = Math.max(maxX, x + n.width / 2);
813
+ }
814
+ if (!isFinite(minX)) {
815
+ minX = 0;
816
+ maxX = 100;
817
+ }
818
+ const padding = FC_CONST.padding;
819
+ const shiftX = padding - minX;
820
+ const placed = [];
821
+ for (let li = 0; li < layerNodes.length; li++) {
822
+ const y = layerCenterY[li];
823
+ for (const n of layerNodes[li]) {
824
+ if (n.isDummy) continue;
825
+ const cx = (xMap.get(n.id) ?? 0) + shiftX;
826
+ placed.push({
827
+ id: n.id,
828
+ x: cx - n.width / 2,
829
+ y: y - n.height / 2,
830
+ width: n.width,
831
+ height: n.height,
832
+ layer: li,
833
+ order: n.order
834
+ });
835
+ }
836
+ }
837
+ const dummyPos = /* @__PURE__ */ new Map();
838
+ for (let li = 0; li < layerNodes.length; li++) {
839
+ const y = layerCenterY[li];
840
+ for (const n of layerNodes[li]) {
841
+ if (!n.isDummy) continue;
842
+ dummyPos.set(n.id, {
843
+ x: (xMap.get(n.id) ?? 0) + shiftX,
844
+ y
845
+ });
846
+ }
847
+ }
848
+ const canvasW = maxX - minX + 2 * padding;
849
+ const lastLayer = layerCenterY.length - 1;
850
+ const canvasH = lastLayer >= 0 ? layerCenterY[lastLayer] + layerHeights[lastLayer] / 2 + padding : 2 * padding;
851
+ const outNodes = placed.map((p) => {
852
+ const base = lnodes.get(p.id).node;
853
+ if (!isHorizontal) {
854
+ return {
855
+ node: base,
856
+ x: p.x,
857
+ y: p.y,
858
+ width: p.width,
859
+ height: p.height,
860
+ layer: p.layer,
861
+ order: p.order
862
+ };
863
+ }
864
+ return {
865
+ node: base,
866
+ x: p.y,
867
+ y: p.x,
868
+ width: p.height,
869
+ height: p.width,
870
+ layer: p.layer,
871
+ order: p.order
872
+ };
873
+ });
874
+ const outWidth = isHorizontal ? canvasH : canvasW;
875
+ const outHeight = isHorizontal ? canvasW : canvasH;
876
+ const nodeCenter = /* @__PURE__ */ new Map();
877
+ for (const ln of outNodes) {
878
+ nodeCenter.set(ln.node.id, {
879
+ x: ln.x + ln.width / 2,
880
+ y: ln.y + ln.height / 2,
881
+ w: ln.width,
882
+ h: ln.height
883
+ });
884
+ }
885
+ const dummyCenter = /* @__PURE__ */ new Map();
886
+ for (const [id, p] of dummyPos) {
887
+ if (!isHorizontal) dummyCenter.set(id, p);
888
+ else dummyCenter.set(id, { x: p.y, y: p.x });
889
+ }
890
+ const outEdges = updatedEdges.map((le) => {
891
+ const chain = le.chain.length > 0 ? le.chain : [le.from, le.to];
892
+ const points = [];
893
+ for (let i = 0; i < chain.length; i++) {
894
+ const id = chain[i];
895
+ const nc = nodeCenter.get(id);
896
+ const dc = dummyCenter.get(id);
897
+ if (nc) {
898
+ points.push({ x: nc.x, y: nc.y });
899
+ } else if (dc) {
900
+ points.push({ x: dc.x, y: dc.y });
901
+ }
902
+ }
903
+ if (points.length < 2) {
904
+ return { edge: le.original, path: "" };
905
+ }
906
+ const startNode = nodeCenter.get(chain[0]);
907
+ const endNode = nodeCenter.get(chain[chain.length - 1]);
908
+ if (startNode) {
909
+ points[0] = clipToBox(points[0], points[1], startNode, dir);
910
+ }
911
+ if (endNode) {
912
+ points[points.length - 1] = clipToBox(
913
+ points[points.length - 1],
914
+ points[points.length - 2],
915
+ endNode,
916
+ dir);
917
+ }
918
+ const d = buildManhattanPath(points, dir);
919
+ let labelAnchor;
920
+ if (le.original.label) {
921
+ labelAnchor = edgeLabelAnchor(points, dir);
922
+ }
923
+ return {
924
+ edge: {
925
+ ...le.original,
926
+ isReversed: le.isReversed
927
+ },
928
+ path: d,
929
+ labelAnchor
930
+ };
931
+ });
932
+ return {
933
+ width: outWidth,
934
+ height: outHeight,
935
+ direction: dir,
936
+ nodes: outNodes,
937
+ edges: outEdges,
938
+ clusters: []
939
+ };
940
+ }
941
+ function clipToBox(from, toward, box, dir, isStart) {
942
+ const cx = box.x;
943
+ const cy = box.y;
944
+ if (dir === "TB" || dir === "BT") {
945
+ const goingDown = toward.y >= from.y;
946
+ return { x: cx, y: cy + (goingDown ? box.h / 2 : -box.h / 2) };
947
+ }
948
+ const goingRight = toward.x >= from.x;
949
+ return { x: cx + (goingRight ? box.w / 2 : -box.w / 2), y: cy };
950
+ }
951
+ function buildManhattanPath(pts, dir) {
952
+ if (pts.length === 0) return "";
953
+ const parts = [`M ${fmt(pts[0].x)} ${fmt(pts[0].y)}`];
954
+ const isHorizontal = dir === "LR" || dir === "RL";
955
+ for (let i = 1; i < pts.length; i++) {
956
+ const a = pts[i - 1];
957
+ const b = pts[i];
958
+ if (isHorizontal) {
959
+ const midX = (a.x + b.x) / 2;
960
+ parts.push(`L ${fmt(midX)} ${fmt(a.y)}`);
961
+ parts.push(`L ${fmt(midX)} ${fmt(b.y)}`);
962
+ parts.push(`L ${fmt(b.x)} ${fmt(b.y)}`);
963
+ } else {
964
+ const midY = (a.y + b.y) / 2;
965
+ parts.push(`L ${fmt(a.x)} ${fmt(midY)}`);
966
+ parts.push(`L ${fmt(b.x)} ${fmt(midY)}`);
967
+ parts.push(`L ${fmt(b.x)} ${fmt(b.y)}`);
968
+ }
969
+ }
970
+ return parts.join(" ");
971
+ }
972
+ function fmt(n) {
973
+ return (Math.round(n * 100) / 100).toString();
974
+ }
975
+ function edgeLabelAnchor(pts, dir) {
976
+ if (pts.length < 2) return pts[0] ?? { x: 0, y: 0 };
977
+ const a = pts[0];
978
+ const b = pts[1];
979
+ const isHorizontal = dir === "LR" || dir === "RL";
980
+ if (isHorizontal) {
981
+ const midX = (a.x + b.x) / 2;
982
+ const bends2 = Math.abs(a.y - b.y) > 1;
983
+ if (bends2) {
984
+ const midY2 = (a.y + b.y) / 2;
985
+ return { x: midX + 6, y: midY2, textAnchor: "start" };
986
+ }
987
+ return { x: midX, y: a.y - 8, textAnchor: "middle" };
988
+ }
989
+ const midY = (a.y + b.y) / 2;
990
+ const bends = Math.abs(a.x - b.x) > 1;
991
+ if (bends) {
992
+ const midX = (a.x + b.x) / 2;
993
+ return { x: midX, y: midY - 8, textAnchor: "middle" };
994
+ }
995
+ return { x: a.x + 6, y: midY, textAnchor: "start" };
996
+ }
997
+
998
+ // src/diagrams/flowchart/shapes.ts
999
+ function shapeSVG(shape, w, h) {
1000
+ switch (shape) {
1001
+ case "rect":
1002
+ return chunkHDKDQAEQ_cjs.rect({ x: 0, y: 0, width: w, height: h, rx: 14, ry: 14, class: "sx-fc-node" });
1003
+ case "round":
1004
+ return chunkHDKDQAEQ_cjs.rect({ x: 0, y: 0, width: w, height: h, rx: 20, ry: 20, class: "sx-fc-node sx-fc-node-round" });
1005
+ case "stadium": {
1006
+ const r = Math.min(h / 2, 24);
1007
+ return chunkHDKDQAEQ_cjs.rect({ x: 0, y: 0, width: w, height: h, rx: r, ry: r, class: "sx-fc-node sx-fc-node-stadium" });
1008
+ }
1009
+ case "diamond": {
1010
+ const points = `${w / 2},0 ${w},${h / 2} ${w / 2},${h} 0,${h / 2}`;
1011
+ return chunkHDKDQAEQ_cjs.polygon({ points, class: "sx-fc-node sx-fc-node-diamond" });
1012
+ }
1013
+ case "parallelogram": {
1014
+ const slant = 20;
1015
+ const points = `${slant},0 ${w},0 ${w - slant},${h} 0,${h}`;
1016
+ return chunkHDKDQAEQ_cjs.polygon({ points, class: "sx-fc-node" });
1017
+ }
1018
+ case "parallelogram-alt": {
1019
+ const slant = 20;
1020
+ const points = `0,0 ${w - slant},0 ${w},${h} ${slant},${h}`;
1021
+ return chunkHDKDQAEQ_cjs.polygon({ points, class: "sx-fc-node" });
1022
+ }
1023
+ default:
1024
+ return chunkHDKDQAEQ_cjs.rect({ x: 0, y: 0, width: w, height: h, rx: 6, ry: 6, class: "sx-fc-node" });
1025
+ }
1026
+ }
1027
+
1028
+ // src/diagrams/flowchart/renderer.ts
1029
+ var CSS_TEMPLATE = (themeName) => {
1030
+ const t = chunkN7KOXOMX_cjs.resolveFlowchartTheme(themeName);
1031
+ const c = t.classes;
1032
+ return `
1033
+ .sx-fc { background: ${t.bg}; font-family: system-ui, -apple-system, "Segoe UI", sans-serif; }
1034
+ .sx-fc-node { fill: ${t.fillMuted}; stroke: ${t.stroke}; stroke-width: 1.5; stroke-linejoin: round; }
1035
+ .sx-fc-node-stadium { fill: ${t.stadiumFill}; stroke: ${t.stroke}; }
1036
+ .sx-fc-node-diamond { fill: ${t.diamondFill}; stroke: ${t.stroke}; }
1037
+ .sx-fc-node-round { fill: ${t.roundFill}; stroke: ${t.stroke}; }
1038
+ .sx-fc-node-text { fill: ${t.text}; font: 12px system-ui, -apple-system, "Segoe UI", sans-serif; }
1039
+ /* Semantic class presets (applied via 'class A start') \u2014 override shape fills */
1040
+ .sx-fc-class-start > .sx-fc-node { fill: ${c.start.fill}; stroke: ${c.start.stroke}; }
1041
+ .sx-fc-class-start > .sx-fc-node-text { fill: ${c.start.text}; font-weight: 600; }
1042
+ .sx-fc-class-process > .sx-fc-node { fill: ${c.process.fill}; stroke: ${c.process.stroke}; }
1043
+ .sx-fc-class-process > .sx-fc-node-text { fill: ${c.process.text}; font-weight: 600; }
1044
+ .sx-fc-class-decision > .sx-fc-node { fill: ${c.decision.fill}; stroke: ${c.decision.stroke}; }
1045
+ .sx-fc-class-decision > .sx-fc-node-text { fill: ${c.decision.text}; font-weight: 600; }
1046
+ .sx-fc-class-success > .sx-fc-node { fill: ${c.success.fill}; stroke: ${c.success.stroke}; }
1047
+ .sx-fc-class-success > .sx-fc-node-text { fill: ${c.success.text}; font-weight: 600; }
1048
+ .sx-fc-class-danger > .sx-fc-node { fill: ${c.danger.fill}; stroke: ${c.danger.stroke}; }
1049
+ .sx-fc-class-danger > .sx-fc-node-text { fill: ${c.danger.text}; font-weight: 600; }
1050
+ .sx-fc-class-neutral > .sx-fc-node { fill: ${c.neutral.fill}; stroke: ${c.neutral.stroke}; }
1051
+ .sx-fc-class-neutral > .sx-fc-node-text { fill: ${c.neutral.text}; font-weight: 600; }
1052
+ .sx-fc-edge { fill: none; stroke: ${t.neutral}; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
1053
+ .sx-fc-edge-thick { stroke: ${t.stroke}; stroke-width: 2.4; }
1054
+ .sx-fc-edge-dashed { stroke-dasharray: 5 3; }
1055
+ .sx-fc-edge-dotted { stroke-dasharray: 1.5 3; }
1056
+ .sx-fc-edge-label { fill: ${t.textMuted}; font: 11px system-ui, -apple-system, "Segoe UI", sans-serif; }
1057
+ .sx-fc-edge-label-bg { fill: ${t.bg}; fill-opacity: 0.96; stroke: ${t.neutral}; stroke-width: 0.5; }
1058
+ .sx-fc-title { fill: ${t.text}; font: 600 14px system-ui, -apple-system, "Segoe UI", sans-serif; }
1059
+ `.trim();
1060
+ };
1061
+ var ARROW_MARKER = `
1062
+ <marker id="sx-fc-arrow" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto-start-reverse" markerUnits="userSpaceOnUse">
1063
+ <path d="M0,0 L8,4 L0,8 L2,4 Z" fill="context-stroke"/>
1064
+ </marker>
1065
+ <marker id="sx-fc-arrow-o" markerWidth="8" markerHeight="8" refX="7" refY="4" orient="auto" markerUnits="userSpaceOnUse">
1066
+ <circle cx="4" cy="4" r="3" fill="none" stroke="context-stroke" stroke-width="1"/>
1067
+ </marker>
1068
+ <marker id="sx-fc-arrow-x" markerWidth="8" markerHeight="8" refX="4" refY="4" orient="auto" markerUnits="userSpaceOnUse">
1069
+ <path d="M1,1 L7,7 M1,7 L7,1" stroke="context-stroke" stroke-width="1.2"/>
1070
+ </marker>
1071
+ `.trim();
1072
+ function edgeCssClass(edge) {
1073
+ const classes = ["sx-fc-edge"];
1074
+ if (edge.kind === "thick") classes.push("sx-fc-edge-thick");
1075
+ if (edge.kind === "dotted") classes.push("sx-fc-edge-dotted");
1076
+ return classes.join(" ");
1077
+ }
1078
+ function markerEndFor(edge) {
1079
+ switch (edge.arrowEnd) {
1080
+ case "arrow":
1081
+ return "url(#sx-fc-arrow)";
1082
+ case "circle":
1083
+ return "url(#sx-fc-arrow-o)";
1084
+ case "cross":
1085
+ return "url(#sx-fc-arrow-x)";
1086
+ default:
1087
+ return void 0;
1088
+ }
1089
+ }
1090
+ function markerStartFor(edge) {
1091
+ return edge.arrowStart === "arrow" ? "url(#sx-fc-arrow)" : void 0;
1092
+ }
1093
+ function renderNode(ln) {
1094
+ const n = ln.node;
1095
+ const shapeEl = shapeSVG(n.shape, ln.width, ln.height);
1096
+ const label = chunkHDKDQAEQ_cjs.text(
1097
+ {
1098
+ x: ln.width / 2,
1099
+ y: ln.height / 2,
1100
+ class: "sx-fc-node-text",
1101
+ "text-anchor": "middle",
1102
+ "dominant-baseline": "central"
1103
+ },
1104
+ n.label
1105
+ );
1106
+ const nodeTitle = chunkHDKDQAEQ_cjs.title(n.label);
1107
+ const classAttr = ["sx-fc-node-g", ...(n.classes ?? []).map((c) => `sx-fc-class-${c}`)].join(" ");
1108
+ return chunkHDKDQAEQ_cjs.group(
1109
+ {
1110
+ "data-node-id": n.id,
1111
+ "data-shape": n.shape,
1112
+ "data-layer": ln.layer,
1113
+ "data-classes": n.classes?.join(" "),
1114
+ class: classAttr,
1115
+ transform: `translate(${fmt2(ln.x)} ${fmt2(ln.y)})`
1116
+ },
1117
+ [shapeEl, label, nodeTitle]
1118
+ );
1119
+ }
1120
+ function renderEdge(le) {
1121
+ const e = le.edge;
1122
+ const attrs = {
1123
+ d: le.path,
1124
+ class: edgeCssClass(e)
1125
+ };
1126
+ const me = markerEndFor(e);
1127
+ const ms = markerStartFor(e);
1128
+ if (me) attrs["marker-end"] = me;
1129
+ if (ms) attrs["marker-start"] = ms;
1130
+ const p = chunkHDKDQAEQ_cjs.path(attrs);
1131
+ const labelEl = e.label && le.labelAnchor ? renderEdgeLabel(
1132
+ e.label,
1133
+ le.labelAnchor.x,
1134
+ le.labelAnchor.y,
1135
+ le.labelAnchor.textAnchor ?? "middle"
1136
+ ) : "";
1137
+ const edgeTitle = chunkHDKDQAEQ_cjs.title(
1138
+ e.label ? `${e.from} \u2192 ${e.to}: ${e.label}` : `${e.from} \u2192 ${e.to}`
1139
+ );
1140
+ return chunkHDKDQAEQ_cjs.group(
1141
+ {
1142
+ "data-edge-id": e.id ?? `${e.from}->${e.to}`,
1143
+ "data-kind": e.kind,
1144
+ "data-from": e.from,
1145
+ "data-to": e.to
1146
+ },
1147
+ [p, edgeTitle, labelEl].filter((s) => s.length > 0)
1148
+ );
1149
+ }
1150
+ function renderEdgeLabel(label, cx, cy, textAnchor) {
1151
+ const w = Math.max(20, label.length * 6.5 + 10);
1152
+ const h = 16;
1153
+ const rx = cx - (textAnchor === "start" ? 0 : textAnchor === "end" ? w : w / 2);
1154
+ const ry = cy - h / 2;
1155
+ const bg = chunkHDKDQAEQ_cjs.rect({
1156
+ x: rx,
1157
+ y: ry,
1158
+ width: w,
1159
+ height: h,
1160
+ rx: 3,
1161
+ class: "sx-fc-edge-label-bg"
1162
+ });
1163
+ const t = chunkHDKDQAEQ_cjs.text(
1164
+ {
1165
+ x: cx,
1166
+ y: cy,
1167
+ class: "sx-fc-edge-label",
1168
+ "text-anchor": textAnchor,
1169
+ "dominant-baseline": "central"
1170
+ },
1171
+ label
1172
+ );
1173
+ return chunkHDKDQAEQ_cjs.group({ class: "sx-fc-edge-label-g" }, [bg, t]);
1174
+ }
1175
+ function fmt2(n) {
1176
+ return (Math.round(n * 100) / 100).toString();
1177
+ }
1178
+ function renderFlowchartAST(ast, themeName = "default") {
1179
+ const layout = layoutFlowchart(ast);
1180
+ const nodeSvg = layout.nodes.map(renderNode);
1181
+ const edgeSvg = layout.edges.map(renderEdge);
1182
+ const titleBlock = ast.title ? chunkHDKDQAEQ_cjs.text(
1183
+ {
1184
+ x: layout.width / 2,
1185
+ y: 16,
1186
+ class: "sx-fc-title",
1187
+ "text-anchor": "middle"
1188
+ },
1189
+ ast.title
1190
+ ) : "";
1191
+ const inner = [
1192
+ chunkHDKDQAEQ_cjs.title(ast.title ? `${ast.title} \u2014 Flowchart` : "Flowchart"),
1193
+ chunkHDKDQAEQ_cjs.desc(
1194
+ `Flowchart with ${ast.nodes.length} node${ast.nodes.length === 1 ? "" : "s"} and ${ast.edges.length} edge${ast.edges.length === 1 ? "" : "s"}.`
1195
+ ),
1196
+ chunkHDKDQAEQ_cjs.el("style", {}, CSS_TEMPLATE(themeName)),
1197
+ chunkHDKDQAEQ_cjs.defs([ARROW_MARKER])
1198
+ ];
1199
+ if (titleBlock) inner.push(titleBlock);
1200
+ inner.push(chunkHDKDQAEQ_cjs.group({ class: "sx-fc-edges" }, edgeSvg));
1201
+ inner.push(chunkHDKDQAEQ_cjs.group({ class: "sx-fc-nodes" }, nodeSvg));
1202
+ const topPad = ast.title ? 24 : 0;
1203
+ const totalH = layout.height + topPad;
1204
+ return chunkHDKDQAEQ_cjs.svgRoot(
1205
+ {
1206
+ viewBox: `0 0 ${fmt2(layout.width)} ${fmt2(totalH)}`,
1207
+ width: fmt2(layout.width),
1208
+ height: fmt2(totalH),
1209
+ class: "sx-fc",
1210
+ "data-diagram-type": "flowchart",
1211
+ "data-direction": layout.direction,
1212
+ role: "graphics-document"
1213
+ },
1214
+ [
1215
+ ...inner.slice(0, 4),
1216
+ ...titleBlock ? [titleBlock] : [],
1217
+ chunkHDKDQAEQ_cjs.group(
1218
+ { transform: topPad > 0 ? `translate(0 ${topPad})` : "translate(0 0)" },
1219
+ [
1220
+ chunkHDKDQAEQ_cjs.group({ class: "sx-fc-edges" }, edgeSvg),
1221
+ chunkHDKDQAEQ_cjs.group({ class: "sx-fc-nodes" }, nodeSvg)
1222
+ ]
1223
+ )
1224
+ ]
1225
+ );
1226
+ }
1227
+ function renderFlowchart(text2, themeName = "default") {
1228
+ const ast = parseFlowchart(text2);
1229
+ return renderFlowchartAST(ast, themeName);
1230
+ }
1231
+
1232
+ // src/diagrams/flowchart/index.ts
1233
+ var flowchart = {
1234
+ type: "flowchart",
1235
+ detect(text2) {
1236
+ for (const raw of text2.split(/\r?\n/)) {
1237
+ const t = raw.trim();
1238
+ if (t.length === 0) continue;
1239
+ if (t.startsWith("%%")) continue;
1240
+ const first = t.split(/\s+/)[0]?.toLowerCase() ?? "";
1241
+ return first === "flowchart" || first === "graph";
1242
+ }
1243
+ return false;
1244
+ },
1245
+ render(text2, config) {
1246
+ const themeName = config?.theme ?? "default";
1247
+ return renderFlowchart(text2, themeName);
1248
+ }
1249
+ };
1250
+
1251
+ exports.FC_CONST = FC_CONST;
1252
+ exports.flowchart = flowchart;
1253
+ exports.layoutFlowchart = layoutFlowchart;
1254
+ exports.parseFlowchart = parseFlowchart;
1255
+ exports.renderFlowchart = renderFlowchart;
1256
+ exports.renderFlowchartAST = renderFlowchartAST;
1257
+ //# sourceMappingURL=chunk-MDICUK6F.cjs.map
1258
+ //# sourceMappingURL=chunk-MDICUK6F.cjs.map