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