@diagrammo/dgmo 0.46.0 → 0.47.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 (232) hide show
  1. package/dist/advanced.d.cts +3 -855
  2. package/dist/advanced.d.ts +3 -855
  3. package/dist/advanced.js +541 -70107
  4. package/dist/analyzer-UYKBXAKR.js +15 -0
  5. package/dist/auto.cjs +1 -1
  6. package/dist/auto.js +1 -1
  7. package/dist/auto.mjs +1 -1
  8. package/dist/block.js +83 -69417
  9. package/dist/calculator-LDYQCDDY.js +11 -0
  10. package/dist/charts-d3-QOZHKTCT.js +25 -0
  11. package/dist/chunk-2DXMZRWJ.js +800 -0
  12. package/dist/chunk-2LACINWN.js +786 -0
  13. package/dist/chunk-33LCUH4H.js +893 -0
  14. package/dist/chunk-3CIOJ5YJ.js +35 -0
  15. package/dist/chunk-3HDBAXF5.js +86 -0
  16. package/dist/chunk-3JLKYGBQ.js +290 -0
  17. package/dist/chunk-3MQQNXPD.js +415 -0
  18. package/dist/chunk-3R5POCTZ.js +967 -0
  19. package/dist/chunk-3SMGIJDD.js +112 -0
  20. package/dist/chunk-44CM72SQ.js +409 -0
  21. package/dist/chunk-4GRI7MEB.js +1604 -0
  22. package/dist/chunk-4OHACBGX.js +606 -0
  23. package/dist/chunk-5DH3KYFH.js +21 -0
  24. package/dist/chunk-5MLYVTYM.js +76 -0
  25. package/dist/chunk-5QXL4NYS.js +553 -0
  26. package/dist/chunk-5WRI5ZAA.js +31 -0
  27. package/dist/chunk-6EK55ART.js +117 -0
  28. package/dist/chunk-6FZYCKXB.js +2065 -0
  29. package/dist/chunk-6HO5ZTXK.js +277 -0
  30. package/dist/chunk-6KFWC4CO.js +7 -0
  31. package/dist/chunk-6MTWIQVO.js +121 -0
  32. package/dist/chunk-6NYWYNBI.js +329 -0
  33. package/dist/chunk-6SM5NJQH.js +620 -0
  34. package/dist/chunk-725LDASD.js +422 -0
  35. package/dist/chunk-76OWZ3BA.js +130 -0
  36. package/dist/chunk-7JEGTRLD.js +338 -0
  37. package/dist/chunk-A44USUV7.js +923 -0
  38. package/dist/chunk-A4GOY3PE.js +25 -0
  39. package/dist/chunk-A4VFQH5G.js +251 -0
  40. package/dist/chunk-AELOBFW5.js +375 -0
  41. package/dist/chunk-AN2MOO5T.js +522 -0
  42. package/dist/chunk-BMR4CIEO.js +41 -0
  43. package/dist/chunk-BS7SV7C3.js +51 -0
  44. package/dist/chunk-BUPDIHML.js +613 -0
  45. package/dist/chunk-BUVJFRPY.js +887 -0
  46. package/dist/chunk-C3Z4DX3V.js +112 -0
  47. package/dist/chunk-CI2G3OEB.js +1818 -0
  48. package/dist/chunk-CKNVO24D.js +54 -0
  49. package/dist/chunk-CUVHQHZ7.js +391 -0
  50. package/dist/chunk-CXK4DZH3.js +114 -0
  51. package/dist/chunk-DKEPS5LH.js +315 -0
  52. package/dist/chunk-DU7W62N5.js +487 -0
  53. package/dist/chunk-DZAQBW35.js +751 -0
  54. package/dist/chunk-EB6FPQUP.js +316 -0
  55. package/dist/chunk-EMS2SK26.js +376 -0
  56. package/dist/chunk-ERLBPDGU.js +510 -0
  57. package/dist/chunk-EVCVDTXE.js +732 -0
  58. package/dist/chunk-FCIIHT24.js +384 -0
  59. package/dist/chunk-FFUN5D66.js +97 -0
  60. package/dist/chunk-FITOLXSX.js +714 -0
  61. package/dist/chunk-FMDSF3OV.js +68 -0
  62. package/dist/chunk-FNB3PNGF.js +410 -0
  63. package/dist/chunk-G2H74XJZ.js +2104 -0
  64. package/dist/chunk-GMR5MFHJ.js +339 -0
  65. package/dist/chunk-H6PI3KJT.js +305 -0
  66. package/dist/chunk-I46X5VUA.js +59 -0
  67. package/dist/chunk-I5IGB56C.js +255 -0
  68. package/dist/chunk-IH6ZMVQ5.js +3950 -0
  69. package/dist/chunk-IJZFN3HM.js +463 -0
  70. package/dist/chunk-IPWPWM6R.js +3079 -0
  71. package/dist/chunk-IYULMRBE.js +23 -0
  72. package/dist/chunk-IZMRON6C.js +167 -0
  73. package/dist/chunk-J5FIXQRT.js +813 -0
  74. package/dist/chunk-JED6ZDEE.js +73 -0
  75. package/dist/chunk-JEUJOX5X.js +136 -0
  76. package/dist/chunk-JM4LEPY3.js +436 -0
  77. package/dist/chunk-L3UHP6TD.js +101 -0
  78. package/dist/chunk-L66GEFB6.js +524 -0
  79. package/dist/chunk-LIOHW36Z.js +469 -0
  80. package/dist/chunk-LP7EC4MI.js +16 -0
  81. package/dist/chunk-MITI6NOL.js +548 -0
  82. package/dist/chunk-MO5YHHMQ.js +168 -0
  83. package/dist/chunk-MZSBFAPJ.js +885 -0
  84. package/dist/chunk-NNAAJVBU.js +9 -0
  85. package/dist/chunk-NOTA6TEI.js +47 -0
  86. package/dist/chunk-NURGB5Z4.js +335 -0
  87. package/dist/chunk-NX4EQS3U.js +1062 -0
  88. package/dist/chunk-NXMESY4J.js +1 -0
  89. package/dist/chunk-OJR3MQYV.js +1458 -0
  90. package/dist/chunk-OURHMODR.js +454 -0
  91. package/dist/chunk-P235SVAH.js +1057 -0
  92. package/dist/chunk-P4RH4OSP.js +1038 -0
  93. package/dist/chunk-P6T66CCZ.js +226 -0
  94. package/dist/chunk-PBAHEPLQ.js +223 -0
  95. package/dist/chunk-PBHE5UG6.js +1530 -0
  96. package/dist/chunk-PDKUANDZ.js +35 -0
  97. package/dist/chunk-PWIHZ6NJ.js +296 -0
  98. package/dist/chunk-QEBUY5NY.js +1685 -0
  99. package/dist/chunk-QLCCJEJI.js +253 -0
  100. package/dist/chunk-QOOUC2J5.js +52 -0
  101. package/dist/chunk-QYTPPDAO.js +402 -0
  102. package/dist/chunk-R3XI2VC7.js +801 -0
  103. package/dist/chunk-RCERWOJR.js +154 -0
  104. package/dist/chunk-RJE5JTVK.js +362 -0
  105. package/dist/chunk-RTLBSQ3G.js +1155 -0
  106. package/dist/chunk-RUNNI6VE.js +448 -0
  107. package/dist/chunk-RVMRZAPB.js +354 -0
  108. package/dist/chunk-RYEGFMUO.js +955 -0
  109. package/dist/chunk-RZCF2VVM.js +528 -0
  110. package/dist/chunk-SML67VPV.js +1025 -0
  111. package/dist/chunk-SQ7IY53Q.js +44 -0
  112. package/dist/chunk-SQAG3UXH.js +161 -0
  113. package/dist/chunk-SRTU6HMQ.js +1851 -0
  114. package/dist/chunk-T2OE3YQB.js +550 -0
  115. package/dist/chunk-T3UBLACL.js +299 -0
  116. package/dist/chunk-TLVIHFRO.js +296 -0
  117. package/dist/chunk-TYS6CSS5.js +52 -0
  118. package/dist/chunk-U6EQI3U6.js +130 -0
  119. package/dist/chunk-UJ4FJLBF.js +86 -0
  120. package/dist/chunk-ULOEATBZ.js +347 -0
  121. package/dist/chunk-UNCCZ3NU.js +127 -0
  122. package/dist/chunk-USZW2HHU.js +197 -0
  123. package/dist/chunk-UWN33VNX.js +1610 -0
  124. package/dist/chunk-UZ7EZW3B.js +40 -0
  125. package/dist/chunk-VOKGH627.js +37 -0
  126. package/dist/chunk-WBRZJOEC.js +204 -0
  127. package/dist/chunk-WCSOJFU3.js +380 -0
  128. package/dist/chunk-WCT3NYCV.js +160 -0
  129. package/dist/chunk-WVAJFAIA.js +529 -0
  130. package/dist/chunk-X5LCYCL5.js +394 -0
  131. package/dist/chunk-XAKEUMEJ.js +1256 -0
  132. package/dist/chunk-Y2ZE3MSG.js +590 -0
  133. package/dist/chunk-Y3J7VR52.js +646 -0
  134. package/dist/chunk-Y5QGVTVC.js +33 -0
  135. package/dist/chunk-YAA6IID3.js +548 -0
  136. package/dist/chunk-YGJTDXVR.js +692 -0
  137. package/dist/chunk-YRYKTYMQ.js +186 -0
  138. package/dist/chunk-YYVTBZZC.js +61 -0
  139. package/dist/chunk-Z5CGSFJB.js +647 -0
  140. package/dist/chunk-Z72XRXD4.js +787 -0
  141. package/dist/chunk-ZGR7ULFJ.js +978 -0
  142. package/dist/chunk-ZJEL4H2R.js +851 -0
  143. package/dist/chunk-ZO27FGJS.js +554 -0
  144. package/dist/collapse-CLPJD2RL.js +11 -0
  145. package/dist/collapse-SLINJQW6.js +9 -0
  146. package/dist/collapse-ZWUFFCK2.js +9 -0
  147. package/dist/compute-G55RG53N.js +8 -0
  148. package/dist/dgmo-router-DZCIDUO5.js +73 -0
  149. package/dist/dimensions-J3FHIMJ6.js +22 -0
  150. package/dist/element.cjs +1 -1
  151. package/dist/element.js +1 -1
  152. package/dist/element.mjs +1 -1
  153. package/dist/flowchart-parser-ZNSKIBVR.js +21 -0
  154. package/dist/flowchart-renderer-ZAEOL4DX.js +35 -0
  155. package/dist/index.cjs +3 -3
  156. package/dist/index.d.cts +3 -469
  157. package/dist/index.d.ts +3 -469
  158. package/dist/index.js +137 -69685
  159. package/dist/layout-46N4JJYK.js +17 -0
  160. package/dist/layout-5RA6QWR6.js +26 -0
  161. package/dist/layout-5T6RH5M6.js +14 -0
  162. package/dist/layout-7QXCNOVS.js +13 -0
  163. package/dist/layout-EE6GE46Y.js +17 -0
  164. package/dist/layout-G23F7LDH.js +9 -0
  165. package/dist/layout-HRBZPFCN.js +23 -0
  166. package/dist/layout-HWDSRX5E.js +20 -0
  167. package/dist/layout-HYZPWAK5.js +18 -0
  168. package/dist/layout-N76NR4ZO.js +19 -0
  169. package/dist/layout-OB3RI63S.js +14 -0
  170. package/dist/layout-S2QBYSK2.js +15 -0
  171. package/dist/layout-UM5F4DJB.js +15 -0
  172. package/dist/layout-search-OYV77HHS.js +1655 -0
  173. package/dist/load-data-EHDDZ5ZS.js +8 -0
  174. package/dist/palettes-PRJ2RI6D.js +56 -0
  175. package/dist/parser-2MFP2H2E.js +11 -0
  176. package/dist/parser-3STE62GB.js +21 -0
  177. package/dist/parser-4FL2CMDG.js +18 -0
  178. package/dist/parser-4OGOBJJ4.js +13 -0
  179. package/dist/parser-6BTRLKRZ.js +15 -0
  180. package/dist/parser-AQETEVRW.js +21 -0
  181. package/dist/parser-CFZD5IBL.js +12 -0
  182. package/dist/parser-FUSKFGZN.js +16 -0
  183. package/dist/parser-I6KXEYFK.js +13 -0
  184. package/dist/parser-IXSZZQHY.js +18 -0
  185. package/dist/parser-JAL2HD4I.js +13 -0
  186. package/dist/parser-KNSQSKQO.js +20 -0
  187. package/dist/parser-N5O4IHUN.js +13 -0
  188. package/dist/parser-NGU3ETO6.js +16 -0
  189. package/dist/parser-NRAI6O25.js +19 -0
  190. package/dist/parser-O5J4VBII.js +11 -0
  191. package/dist/parser-OV7NOBW6.js +21 -0
  192. package/dist/parser-PQ3POX45.js +23 -0
  193. package/dist/parser-TFZFBVWN.js +11 -0
  194. package/dist/parser-TRTHDFPP.js +18 -0
  195. package/dist/parser-VQP2UJ6W.js +11 -0
  196. package/dist/parser-XDVELHRK.js +13 -0
  197. package/dist/parser-XKRP7QKP.js +11 -0
  198. package/dist/parser-Y6WTBU76.js +14 -0
  199. package/dist/parser-ZSDPZYQP.js +12 -0
  200. package/dist/renderer-2XQQQ6QR.js +28 -0
  201. package/dist/renderer-5NDVNDAZ.js +26 -0
  202. package/dist/renderer-6EEZHMH4.js +26 -0
  203. package/dist/renderer-6W5462RB.js +43 -0
  204. package/dist/renderer-7MVLWWQD.js +22 -0
  205. package/dist/renderer-AWWAF6XD.js +33 -0
  206. package/dist/renderer-BYCNMBF7.js +34 -0
  207. package/dist/renderer-CLJHQPBJ.js +29 -0
  208. package/dist/renderer-GHPZMFU2.js +15 -0
  209. package/dist/renderer-JGBKUCZD.js +16 -0
  210. package/dist/renderer-KQB7UGDS.js +19 -0
  211. package/dist/renderer-PGX2TKVS.js +24 -0
  212. package/dist/renderer-QIWVHWZO.js +15 -0
  213. package/dist/renderer-RPOA5YPZ.js +35 -0
  214. package/dist/renderer-SMIBCRVB.js +24 -0
  215. package/dist/renderer-T7YKC5VP.js +28 -0
  216. package/dist/renderer-TOCOVLHS.js +37 -0
  217. package/dist/renderer-UWA5XS74.js +39 -0
  218. package/dist/renderer-VACVQYML.js +25 -0
  219. package/dist/renderer-W4M6QLIJ.js +37 -0
  220. package/dist/renderer-WZRREQ2P.js +23 -0
  221. package/dist/renderer-YY2OSF6E.js +27 -0
  222. package/dist/renderer-Z7I3W2PP.js +24 -0
  223. package/dist/renderer-ZGNTUWC4.js +22 -0
  224. package/dist/renderer-ZTR3DER3.js +19 -0
  225. package/dist/renderer-radial-C32GPJQ7.js +21 -0
  226. package/dist/resolver-NOAA7ID7.js +13 -0
  227. package/dist/state-collapse-HCGD6IVJ.js +8 -0
  228. package/dist/state-parser-Z2V23ATR.js +18 -0
  229. package/dist/state-renderer-RFYHSP4K.js +34 -0
  230. package/dist/themes-1-CuKpeH.d.cts +908 -0
  231. package/dist/themes-1-CuKpeH.d.ts +908 -0
  232. package/package.json +1 -1
@@ -0,0 +1,548 @@
1
+ import {
2
+ layoutERDiagram
3
+ } from "./chunk-6NYWYNBI.js";
4
+ import {
5
+ NOTE_BADGE_RADIUS,
6
+ noteConnectorPoints,
7
+ renderNoteBadge,
8
+ renderNoteBox,
9
+ renderNoteConnector
10
+ } from "./chunk-JEUJOX5X.js";
11
+ import {
12
+ EDGE_STROKE_WIDTH,
13
+ NODE_STROKE_WIDTH
14
+ } from "./chunk-3CIOJ5YJ.js";
15
+ import {
16
+ renderIntegratedLegend
17
+ } from "./chunk-PWIHZ6NJ.js";
18
+ import {
19
+ ScaleContext
20
+ } from "./chunk-YYVTBZZC.js";
21
+ import {
22
+ TITLE_FONT_SIZE,
23
+ TITLE_FONT_WEIGHT,
24
+ TITLE_Y
25
+ } from "./chunk-A4GOY3PE.js";
26
+ import {
27
+ FONT_FAMILY
28
+ } from "./chunk-6KFWC4CO.js";
29
+ import {
30
+ LEGEND_HEIGHT
31
+ } from "./chunk-QOOUC2J5.js";
32
+ import {
33
+ measureText
34
+ } from "./chunk-WCT3NYCV.js";
35
+ import {
36
+ parseERDiagram
37
+ } from "./chunk-L66GEFB6.js";
38
+ import {
39
+ contrastText,
40
+ getSeriesColors,
41
+ shapeFill
42
+ } from "./chunk-P6T66CCZ.js";
43
+ import {
44
+ resolveTagColor,
45
+ tagAttrKey
46
+ } from "./chunk-QLCCJEJI.js";
47
+
48
+ // src/er/renderer.ts
49
+ import * as d3Selection from "d3-selection";
50
+ import * as d3Shape from "d3-shape";
51
+
52
+ // src/er/classify.ts
53
+ var ROLE_COLORS = {
54
+ core: "green",
55
+ dependent: "blue",
56
+ junction: "red",
57
+ ambiguous: "purple",
58
+ lookup: "yellow",
59
+ hub: "orange",
60
+ "self-referential": "teal",
61
+ unclassified: "gray"
62
+ };
63
+ var ROLE_LABELS = {
64
+ core: "Core entity",
65
+ dependent: "Dependent",
66
+ junction: "Junction / M:M",
67
+ ambiguous: "Bridge",
68
+ lookup: "Lookup / Reference",
69
+ hub: "Hub",
70
+ "self-referential": "Self-referential",
71
+ unclassified: "Unclassified"
72
+ };
73
+ var ROLE_ORDER = [
74
+ "core",
75
+ "dependent",
76
+ "junction",
77
+ "ambiguous",
78
+ "lookup",
79
+ "hub",
80
+ "self-referential",
81
+ "unclassified"
82
+ ];
83
+ var LOOKUP_NAME_SUFFIXES = ["_type", "_status", "_code", "_category"];
84
+ function classifyEREntities(tables, relationships) {
85
+ const result = /* @__PURE__ */ new Map();
86
+ if (tables.length === 0) return result;
87
+ const indegreeMap = {};
88
+ for (const t of tables) indegreeMap[t.id] = 0;
89
+ for (const rel of relationships) {
90
+ if (rel.source === rel.target) continue;
91
+ if (rel.cardinality.from === "1" && rel.cardinality.to !== "1") {
92
+ indegreeMap[rel.source] = (indegreeMap[rel.source] ?? 0) + 1;
93
+ }
94
+ if (rel.cardinality.to === "1" && rel.cardinality.from !== "1") {
95
+ indegreeMap[rel.target] = (indegreeMap[rel.target] ?? 0) + 1;
96
+ }
97
+ }
98
+ const tableStarNeighbors = /* @__PURE__ */ new Map();
99
+ for (const rel of relationships) {
100
+ if (rel.source === rel.target) continue;
101
+ if (rel.cardinality.from === "*") {
102
+ if (!tableStarNeighbors.has(rel.source))
103
+ tableStarNeighbors.set(rel.source, /* @__PURE__ */ new Set());
104
+ tableStarNeighbors.get(rel.source).add(rel.target);
105
+ }
106
+ if (rel.cardinality.to === "*") {
107
+ if (!tableStarNeighbors.has(rel.target))
108
+ tableStarNeighbors.set(rel.target, /* @__PURE__ */ new Set());
109
+ tableStarNeighbors.get(rel.target).add(rel.source);
110
+ }
111
+ }
112
+ const mmParticipants = /* @__PURE__ */ new Set();
113
+ for (const [id, neighbors] of tableStarNeighbors) {
114
+ if (neighbors.size >= 2) mmParticipants.add(id);
115
+ }
116
+ const indegreeValues = Object.values(indegreeMap);
117
+ const mean = indegreeValues.reduce((a, b) => a + b, 0) / indegreeValues.length;
118
+ const variance = indegreeValues.reduce((a, b) => a + (b - mean) ** 2, 0) / indegreeValues.length;
119
+ const stddev = Math.sqrt(variance);
120
+ const sorted = [...indegreeValues].sort((a, b) => a - b);
121
+ const median = sorted.length % 2 === 0 ? (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2 : sorted[Math.floor(sorted.length / 2)];
122
+ for (const table of tables) {
123
+ const id = table.id;
124
+ const cols = table.columns;
125
+ const fkCols = cols.filter((c) => c.constraints.includes("fk"));
126
+ const pkFkCols = cols.filter(
127
+ (c) => c.constraints.includes("pk") && c.constraints.includes("fk")
128
+ );
129
+ const fkCount = fkCols.length;
130
+ const fkRatio = cols.length === 0 ? 0 : fkCount / cols.length;
131
+ const indegree = indegreeMap[id] ?? 0;
132
+ const nameLower = table.name.toLowerCase();
133
+ const externalRels = relationships.filter(
134
+ (r) => (r.source === id || r.target === id) && r.source !== r.target
135
+ );
136
+ const hasSelfRef = relationships.some(
137
+ (r) => r.source === id && r.target === id
138
+ );
139
+ const externalTargets = /* @__PURE__ */ new Set();
140
+ for (const rel of externalRels) {
141
+ externalTargets.add(rel.source === id ? rel.target : rel.source);
142
+ }
143
+ if (hasSelfRef && externalRels.length === 0) {
144
+ result.set(id, "self-referential");
145
+ continue;
146
+ }
147
+ const isInheritancePattern = pkFkCols.length >= 2 && externalTargets.size === 1;
148
+ const junctionByRatio = fkRatio >= 0.6 && !isInheritancePattern;
149
+ const junctionByCompositePk = pkFkCols.length >= 2 && externalTargets.size >= 2;
150
+ const junctionByMm = mmParticipants.has(id);
151
+ if (junctionByRatio || junctionByCompositePk || junctionByMm) {
152
+ result.set(id, "junction");
153
+ continue;
154
+ }
155
+ if (fkRatio >= 0.4 && fkRatio < 0.6 && pkFkCols.length < 2 && !mmParticipants.has(id)) {
156
+ result.set(id, "ambiguous");
157
+ continue;
158
+ }
159
+ const nameMatchesLookup = LOOKUP_NAME_SUFFIXES.some(
160
+ (s) => nameLower.endsWith(s)
161
+ );
162
+ if (nameMatchesLookup && cols.length <= 6 && fkCount <= 1 && indegree > median) {
163
+ result.set(id, "lookup");
164
+ continue;
165
+ }
166
+ if (tables.length >= 6 && indegree > 0 && indegree > mean + 1.5 * stddev && indegree >= 2 * mean) {
167
+ result.set(id, "hub");
168
+ continue;
169
+ }
170
+ if (fkCount > 0) {
171
+ result.set(id, "dependent");
172
+ continue;
173
+ }
174
+ result.set(id, "core");
175
+ }
176
+ return result;
177
+ }
178
+
179
+ // src/er/renderer.ts
180
+ var DIAGRAM_PADDING = 20;
181
+ var MAX_SCALE = 3;
182
+ var TABLE_FONT_SIZE = 13;
183
+ var COLUMN_FONT_SIZE = 11;
184
+ var EDGE_LABEL_FONT_SIZE = 11;
185
+ var MEMBER_LINE_HEIGHT = 18;
186
+ var COMPARTMENT_PADDING_Y = 8;
187
+ var MEMBER_PADDING_X = 10;
188
+ function constraintIcon(constraint) {
189
+ switch (constraint) {
190
+ case "pk":
191
+ return "\u2666";
192
+ // ♦
193
+ case "fk":
194
+ return "\u2192";
195
+ // →
196
+ case "unique":
197
+ return "\u25C6";
198
+ // ◆
199
+ case "nullable":
200
+ return "\u25CB";
201
+ }
202
+ }
203
+ var lineGenerator = d3Shape.line().x((d) => d.x).y((d) => d.y).curve(d3Shape.curveBasis);
204
+ function drawCardinality(g, point, prevPoint, cardinality, color, useLabels, edgeLabelFontSize = EDGE_LABEL_FONT_SIZE, edgeStrokeWidth = EDGE_STROKE_WIDTH) {
205
+ const dx = point.x - prevPoint.x;
206
+ const dy = point.y - prevPoint.y;
207
+ const len = Math.sqrt(dx * dx + dy * dy);
208
+ if (len === 0) return;
209
+ const ux = dx / len;
210
+ const uy = dy / len;
211
+ const px = -uy;
212
+ const py = ux;
213
+ const sw = edgeStrokeWidth + 0.5;
214
+ if (useLabels) {
215
+ const offset = 15;
216
+ const bx = point.x - ux * offset;
217
+ const by = point.y - uy * offset;
218
+ const labelText = cardinality === "1" ? "1" : cardinality === "*" ? "*" : "0..1";
219
+ g.append("text").attr("x", bx + px * 12).attr("y", by + py * 12).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", color).attr("font-size", edgeLabelFontSize).text(labelText);
220
+ return;
221
+ }
222
+ const barOffset = 14;
223
+ const spread = 9;
224
+ if (cardinality === "1") {
225
+ const bx = point.x - ux * barOffset;
226
+ const by = point.y - uy * barOffset;
227
+ g.append("line").attr("x1", bx + px * spread).attr("y1", by + py * spread).attr("x2", bx - px * spread).attr("y2", by - py * spread).attr("stroke", color).attr("stroke-width", sw);
228
+ } else if (cardinality === "*") {
229
+ const forkOrigin = 18;
230
+ const forkEnd = 5;
231
+ const ox = point.x - ux * forkOrigin;
232
+ const oy = point.y - uy * forkOrigin;
233
+ const ex = point.x - ux * forkEnd;
234
+ const ey = point.y - uy * forkEnd;
235
+ g.append("line").attr("x1", ox).attr("y1", oy).attr("x2", ex + px * spread).attr("y2", ey + py * spread).attr("stroke", color).attr("stroke-width", sw);
236
+ g.append("line").attr("x1", ox).attr("y1", oy).attr("x2", ex - px * spread).attr("y2", ey - py * spread).attr("stroke", color).attr("stroke-width", sw);
237
+ g.append("line").attr("x1", ox).attr("y1", oy).attr("x2", ex).attr("y2", ey).attr("stroke", color).attr("stroke-width", sw);
238
+ } else if (cardinality === "?") {
239
+ const circleR = 5;
240
+ const circleCenter = barOffset + circleR * 2 + 2;
241
+ const cx = point.x - ux * circleCenter;
242
+ const cy = point.y - uy * circleCenter;
243
+ g.append("circle").attr("cx", cx).attr("cy", cy).attr("r", circleR).attr("fill", "none").attr("stroke", color).attr("stroke-width", sw);
244
+ const bx = point.x - ux * barOffset;
245
+ const by = point.y - uy * barOffset;
246
+ g.append("line").attr("x1", bx + px * spread).attr("y1", by + py * spread).attr("x2", bx - px * spread).attr("y2", by - py * spread).attr("stroke", color).attr("stroke-width", sw);
247
+ }
248
+ }
249
+ function renderERDiagram(container, parsed, layout, palette, isDark, onClickItem, exportDims, activeTagGroup, semanticColorsActive, exportMode) {
250
+ d3Selection.select(container).selectAll(":not([data-d3-tooltip])").remove();
251
+ const useSemanticColors = parsed.tagGroups.length === 0 && layout.nodes.every((n) => !n.color);
252
+ const LEGEND_FIXED_GAP = 8;
253
+ const hasTagLegend = parsed.tagGroups.length > 0;
254
+ const legendReserveH = useSemanticColors ? LEGEND_HEIGHT + LEGEND_FIXED_GAP : hasTagLegend ? LEGEND_HEIGHT + LEGEND_FIXED_GAP : 0;
255
+ const showTitle = !!parsed.title && parsed.options["no-title"] !== "on";
256
+ const titleHeight = showTitle ? 40 : 0;
257
+ const diagramW = layout.width;
258
+ const diagramH = layout.height;
259
+ const ctx = ScaleContext.identity();
260
+ const sDiagramPadding = ctx.aesthetic(DIAGRAM_PADDING);
261
+ const sTableFontSize = ctx.text(TABLE_FONT_SIZE);
262
+ const sColumnFontSize = ctx.text(COLUMN_FONT_SIZE);
263
+ const sEdgeLabelFontSize = ctx.text(EDGE_LABEL_FONT_SIZE);
264
+ const sEdgeStrokeWidth = ctx.structural(EDGE_STROKE_WIDTH);
265
+ const sNodeStrokeWidth = ctx.structural(NODE_STROKE_WIDTH);
266
+ const sMemberLineHeight = ctx.structural(MEMBER_LINE_HEIGHT);
267
+ const sCompartmentPaddingY = ctx.structural(COMPARTMENT_PADDING_Y);
268
+ const sMemberPaddingX = ctx.structural(MEMBER_PADDING_X);
269
+ const sTitleFontSize = ctx.text(TITLE_FONT_SIZE);
270
+ const sTitleY = ctx.structural(TITLE_Y);
271
+ const naturalW = diagramW + sDiagramPadding * 2;
272
+ const naturalH = diagramH + titleHeight + legendReserveH + sDiagramPadding * 2;
273
+ let viewW;
274
+ let viewH;
275
+ let scale;
276
+ let offsetX;
277
+ let offsetY;
278
+ if (exportDims) {
279
+ viewW = exportDims.width ?? naturalW;
280
+ viewH = exportDims.height ?? naturalH;
281
+ const availH = viewH - titleHeight - legendReserveH;
282
+ const scaleX = (viewW - sDiagramPadding * 2) / diagramW;
283
+ const scaleY = (availH - sDiagramPadding * 2) / diagramH;
284
+ scale = Math.min(MAX_SCALE, scaleX, scaleY);
285
+ const scaledW = diagramW * scale;
286
+ offsetX = (viewW - scaledW) / 2;
287
+ offsetY = titleHeight + legendReserveH + sDiagramPadding;
288
+ } else {
289
+ viewW = naturalW;
290
+ viewH = naturalH;
291
+ scale = 1;
292
+ offsetX = sDiagramPadding;
293
+ offsetY = titleHeight + legendReserveH + sDiagramPadding;
294
+ }
295
+ if (viewW <= 0 || viewH <= 0) return;
296
+ const svg = d3Selection.select(container).append("svg").attr("width", exportDims ? viewW : "100%").attr("height", exportDims ? viewH : "100%").attr("viewBox", `0 0 ${viewW} ${viewH}`).attr("preserveAspectRatio", "xMidYMid meet").style("font-family", FONT_FAMILY);
297
+ if (showTitle) {
298
+ const titleEl = svg.append("text").attr("class", "chart-title").attr("x", viewW / 2).attr("y", sTitleY).attr("text-anchor", "middle").attr("fill", palette.text).attr("font-size", sTitleFontSize).attr("font-weight", TITLE_FONT_WEIGHT).style(
299
+ "cursor",
300
+ onClickItem && parsed.titleLineNumber ? "pointer" : "default"
301
+ ).text(parsed.title);
302
+ if (parsed.titleLineNumber) {
303
+ titleEl.attr("data-line-number", parsed.titleLineNumber);
304
+ if (onClickItem) {
305
+ titleEl.on("click", () => onClickItem(parsed.titleLineNumber)).on("mouseenter", function() {
306
+ d3Selection.select(this).attr("opacity", 0.7);
307
+ }).on("mouseleave", function() {
308
+ d3Selection.select(this).attr("opacity", 1);
309
+ });
310
+ }
311
+ }
312
+ }
313
+ const contentG = svg.append("g").attr("transform", `translate(${offsetX}, ${offsetY}) scale(${scale})`);
314
+ const seriesColors = getSeriesColors(palette);
315
+ const semanticRoles = useSemanticColors ? classifyEREntities([...parsed.tables], [...parsed.relationships]) : null;
316
+ const semanticActive = semanticRoles !== null && (semanticColorsActive ?? true);
317
+ const useLabels = parsed.options["notation"] === "labels";
318
+ for (const edge of layout.edges) {
319
+ if (edge.points.length < 2) continue;
320
+ const edgeG = contentG.append("g").attr("class", "er-edge-group").attr("data-line-number", String(edge.lineNumber)).attr("data-source", edge.source).attr("data-target", edge.target);
321
+ const edgeColor = palette.textMuted;
322
+ const pathD = lineGenerator(edge.points);
323
+ if (pathD) {
324
+ edgeG.append("path").attr("d", pathD).attr("fill", "none").attr("stroke", edgeColor).attr("stroke-width", sEdgeStrokeWidth).attr("class", "er-edge");
325
+ }
326
+ const pts = edge.points;
327
+ drawCardinality(
328
+ edgeG,
329
+ pts[0],
330
+ pts[1],
331
+ edge.cardinality.from,
332
+ edgeColor,
333
+ useLabels,
334
+ sEdgeLabelFontSize,
335
+ sEdgeStrokeWidth
336
+ );
337
+ drawCardinality(
338
+ edgeG,
339
+ pts[pts.length - 1],
340
+ pts[pts.length - 2],
341
+ edge.cardinality.to,
342
+ edgeColor,
343
+ useLabels,
344
+ sEdgeLabelFontSize,
345
+ sEdgeStrokeWidth
346
+ );
347
+ if (edge.label) {
348
+ const midIdx = Math.floor(pts.length / 2);
349
+ const midPt = pts[midIdx];
350
+ const bgW = measureText(edge.label, sEdgeLabelFontSize) + 8;
351
+ const bgH = 16;
352
+ edgeG.append("rect").attr("x", midPt.x - bgW / 2).attr("y", midPt.y - bgH / 2 - 1).attr("width", bgW).attr("height", bgH).attr("rx", 3).attr("fill", palette.bg).attr("opacity", 0.85).attr("class", "er-edge-label-bg");
353
+ edgeG.append("text").attr("x", midPt.x).attr("y", midPt.y + 4).attr("text-anchor", "middle").attr("fill", edgeColor).attr("font-size", sEdgeLabelFontSize).attr("class", "er-edge-label").text(edge.label);
354
+ }
355
+ }
356
+ for (let ni = 0; ni < layout.nodes.length; ni++) {
357
+ const node = layout.nodes[ni];
358
+ const tagColor = resolveTagColor(
359
+ node.metadata,
360
+ [...parsed.tagGroups],
361
+ activeTagGroup ?? null
362
+ );
363
+ const semanticColor = semanticActive ? palette.colors[ROLE_COLORS[semanticRoles.get(node.id) ?? "unclassified"]] : semanticRoles ? palette.primary : void 0;
364
+ const nodeColor = node.color ?? tagColor ?? semanticColor ?? // In-bounds by modulo: seriesColors is non-empty from the palette.
365
+ seriesColors[ni % seriesColors.length];
366
+ const nodeG = contentG.append("g").attr("transform", `translate(${node.x}, ${node.y})`).attr("class", "er-table").attr("data-line-number", String(node.lineNumber)).attr("data-node-id", node.id);
367
+ if (activeTagGroup) {
368
+ const tagKey = tagAttrKey(activeTagGroup);
369
+ const tagValue = node.metadata[tagKey];
370
+ if (tagValue) {
371
+ nodeG.attr(`data-tag-${tagKey}`, tagValue.toLowerCase());
372
+ }
373
+ }
374
+ if (semanticRoles) {
375
+ const role = semanticRoles.get(node.id);
376
+ if (role) nodeG.attr("data-er-role", role);
377
+ }
378
+ if (onClickItem) {
379
+ nodeG.style("cursor", "pointer").on("click", () => {
380
+ onClickItem(node.lineNumber);
381
+ });
382
+ }
383
+ const w = node.width;
384
+ const h = node.height;
385
+ const fill = shapeFill(palette, nodeColor, isDark, {
386
+ solid: parsed.options["solid-fill"] === "on"
387
+ });
388
+ const stroke = nodeColor;
389
+ const onFillText = contrastText(
390
+ fill,
391
+ palette.textOnFillLight,
392
+ palette.textOnFillDark
393
+ );
394
+ nodeG.append("rect").attr("x", -w / 2).attr("y", -h / 2).attr("width", w).attr("height", h).attr("rx", 3).attr("ry", 3).attr("fill", fill).attr("stroke", stroke).attr("stroke-width", sNodeStrokeWidth);
395
+ let yPos = -h / 2;
396
+ const headerCenterY = yPos + node.headerHeight / 2;
397
+ nodeG.append("text").attr("x", 0).attr("y", headerCenterY).attr("text-anchor", "middle").attr("dominant-baseline", "central").attr("fill", onFillText).attr("font-size", sTableFontSize).attr("font-weight", "bold").text(node.name);
398
+ yPos += node.headerHeight;
399
+ if (node.columns.length > 0) {
400
+ nodeG.append("line").attr("x1", -w / 2).attr("y1", yPos).attr("x2", w / 2).attr("y2", yPos).attr("stroke", stroke).attr("stroke-width", 0.5).attr("stroke-opacity", 0.5);
401
+ let memberY = yPos + sCompartmentPaddingY;
402
+ for (const col of node.columns) {
403
+ const iconX = -w / 2 + sMemberPaddingX;
404
+ const primaryConstraint = col.constraints[0];
405
+ if (primaryConstraint) {
406
+ nodeG.append("text").attr("x", iconX).attr("y", memberY + sMemberLineHeight / 2).attr("dominant-baseline", "central").attr("fill", onFillText).attr("font-size", sColumnFontSize).text(constraintIcon(primaryConstraint));
407
+ }
408
+ const textX = -w / 2 + sMemberPaddingX + (primaryConstraint ? 16 : 0);
409
+ let colText = col.name;
410
+ if (col.type) colText += `: ${col.type}`;
411
+ nodeG.append("text").attr("x", textX).attr("y", memberY + sMemberLineHeight / 2).attr("dominant-baseline", "central").attr("fill", onFillText).attr("font-size", sColumnFontSize).text(colText);
412
+ memberY += sMemberLineHeight;
413
+ }
414
+ }
415
+ if (node.note) {
416
+ if (node.note.collapsed) {
417
+ renderNoteBadge(
418
+ nodeG,
419
+ {
420
+ x: w / 2 - NOTE_BADGE_RADIUS - 3,
421
+ y: -h / 2 + NOTE_BADGE_RADIUS + 3
422
+ },
423
+ palette,
424
+ {
425
+ isDark,
426
+ ...node.note.color && { color: node.note.color },
427
+ lineNumber: node.note.lineNumber,
428
+ endLineNumber: node.note.endLineNumber
429
+ }
430
+ );
431
+ } else {
432
+ const [cx1, cy1, cx2, cy2] = noteConnectorPoints(
433
+ { width: w, height: h },
434
+ node.note
435
+ );
436
+ renderNoteConnector(nodeG, cx1, cy1, cx2, cy2, palette);
437
+ renderNoteBox(
438
+ nodeG,
439
+ {
440
+ x: node.note.x,
441
+ y: node.note.y,
442
+ width: node.note.width,
443
+ height: node.note.height
444
+ },
445
+ node.note.lines,
446
+ palette,
447
+ {
448
+ isDark,
449
+ ...node.note.color && { color: node.note.color },
450
+ lineNumber: node.note.lineNumber,
451
+ endLineNumber: node.note.endLineNumber,
452
+ interactive: true
453
+ }
454
+ );
455
+ }
456
+ }
457
+ }
458
+ if (parsed.tagGroups.length > 0) {
459
+ const legendY = sDiagramPadding + titleHeight;
460
+ const legendG = svg.append("g").attr("class", "er-tag-legend").attr("transform", `translate(0,${legendY})`);
461
+ renderIntegratedLegend(legendG, {
462
+ groups: parsed.tagGroups,
463
+ activeGroup: activeTagGroup ?? null,
464
+ mode: exportMode ? "export" : "preview",
465
+ palette,
466
+ isDark,
467
+ width: viewW
468
+ });
469
+ legendG.selectAll("[data-legend-group]").classed("er-legend-group", true);
470
+ }
471
+ if (semanticRoles) {
472
+ const presentRoles = ROLE_ORDER.filter((role) => {
473
+ for (const r of semanticRoles.values()) {
474
+ if (r === role) return true;
475
+ }
476
+ return false;
477
+ });
478
+ if (presentRoles.length > 0) {
479
+ const legendY = sDiagramPadding + titleHeight;
480
+ const semanticGroups = [
481
+ {
482
+ name: "Role",
483
+ entries: presentRoles.map((role) => ({
484
+ value: ROLE_LABELS[role],
485
+ color: palette.colors[ROLE_COLORS[role]]
486
+ }))
487
+ }
488
+ ];
489
+ const legendG = svg.append("g").attr("class", "er-semantic-legend").attr("transform", `translate(0,${legendY})`);
490
+ renderIntegratedLegend(legendG, {
491
+ groups: semanticGroups,
492
+ activeGroup: semanticActive ? "Role" : null,
493
+ mode: exportMode ? "export" : "preview",
494
+ palette,
495
+ isDark,
496
+ width: viewW
497
+ });
498
+ legendG.selectAll("[data-legend-group]").classed("er-legend-group", true);
499
+ }
500
+ }
501
+ }
502
+ function renderERDiagramForExport(content, theme, palette) {
503
+ const parsed = parseERDiagram(content, palette);
504
+ if (parsed.error || parsed.tables.length === 0) return "";
505
+ const layout = layoutERDiagram(parsed);
506
+ const isDark = theme === "dark";
507
+ const container = document.createElement("div");
508
+ const exportWidth = layout.width + DIAGRAM_PADDING * 2;
509
+ const exportHeight = layout.height + DIAGRAM_PADDING * 2 + (parsed.title && parsed.options["no-title"] !== "on" ? 40 : 0);
510
+ container.style.width = `${exportWidth}px`;
511
+ container.style.height = `${exportHeight}px`;
512
+ container.style.position = "absolute";
513
+ container.style.left = "-9999px";
514
+ document.body.appendChild(container);
515
+ try {
516
+ renderERDiagram(
517
+ container,
518
+ parsed,
519
+ layout,
520
+ palette,
521
+ isDark,
522
+ void 0,
523
+ {
524
+ width: exportWidth,
525
+ height: exportHeight
526
+ },
527
+ void 0,
528
+ void 0,
529
+ true
530
+ );
531
+ const svgEl = container.querySelector("svg");
532
+ if (!svgEl) return "";
533
+ if (theme === "transparent") {
534
+ svgEl.style.background = "none";
535
+ }
536
+ svgEl.setAttribute("xmlns", "http://www.w3.org/2000/svg");
537
+ svgEl.style.fontFamily = FONT_FAMILY;
538
+ return svgEl.outerHTML;
539
+ } finally {
540
+ document.body.removeChild(container);
541
+ }
542
+ }
543
+
544
+ export {
545
+ renderERDiagram,
546
+ renderERDiagramForExport
547
+ };
548
+ //# sourceMappingURL=chunk-MITI6NOL.js.map