@diagrammo/dgmo 0.45.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 (250) hide show
  1. package/dist/advanced.cjs +31 -25
  2. package/dist/advanced.d.cts +3 -855
  3. package/dist/advanced.d.ts +3 -855
  4. package/dist/advanced.js +541 -70101
  5. package/dist/analyzer-UYKBXAKR.js +15 -0
  6. package/dist/auto.cjs +500 -341
  7. package/dist/auto.css +342 -159
  8. package/dist/auto.d.cts +10 -8
  9. package/dist/auto.d.ts +10 -8
  10. package/dist/auto.js +373 -265
  11. package/dist/auto.mjs +500 -341
  12. package/dist/block.cjs +31 -25
  13. package/dist/block.js +83 -69411
  14. package/dist/calculator-LDYQCDDY.js +11 -0
  15. package/dist/charts-d3-QOZHKTCT.js +25 -0
  16. package/dist/chunk-2DXMZRWJ.js +800 -0
  17. package/dist/chunk-2LACINWN.js +786 -0
  18. package/dist/chunk-33LCUH4H.js +893 -0
  19. package/dist/chunk-3CIOJ5YJ.js +35 -0
  20. package/dist/chunk-3HDBAXF5.js +86 -0
  21. package/dist/chunk-3JLKYGBQ.js +290 -0
  22. package/dist/chunk-3MQQNXPD.js +415 -0
  23. package/dist/chunk-3R5POCTZ.js +967 -0
  24. package/dist/chunk-3SMGIJDD.js +112 -0
  25. package/dist/chunk-44CM72SQ.js +409 -0
  26. package/dist/chunk-4GRI7MEB.js +1604 -0
  27. package/dist/chunk-4OHACBGX.js +606 -0
  28. package/dist/chunk-5DH3KYFH.js +21 -0
  29. package/dist/chunk-5MLYVTYM.js +76 -0
  30. package/dist/chunk-5QXL4NYS.js +553 -0
  31. package/dist/chunk-5WRI5ZAA.js +31 -0
  32. package/dist/chunk-6EK55ART.js +117 -0
  33. package/dist/chunk-6FZYCKXB.js +2065 -0
  34. package/dist/chunk-6HO5ZTXK.js +277 -0
  35. package/dist/chunk-6KFWC4CO.js +7 -0
  36. package/dist/chunk-6MTWIQVO.js +121 -0
  37. package/dist/chunk-6NYWYNBI.js +329 -0
  38. package/dist/chunk-6SM5NJQH.js +620 -0
  39. package/dist/chunk-725LDASD.js +422 -0
  40. package/dist/chunk-76OWZ3BA.js +130 -0
  41. package/dist/chunk-7JEGTRLD.js +338 -0
  42. package/dist/chunk-A44USUV7.js +923 -0
  43. package/dist/chunk-A4GOY3PE.js +25 -0
  44. package/dist/chunk-A4VFQH5G.js +251 -0
  45. package/dist/chunk-AELOBFW5.js +375 -0
  46. package/dist/chunk-AN2MOO5T.js +522 -0
  47. package/dist/chunk-BMR4CIEO.js +41 -0
  48. package/dist/chunk-BS7SV7C3.js +51 -0
  49. package/dist/chunk-BUPDIHML.js +613 -0
  50. package/dist/chunk-BUVJFRPY.js +887 -0
  51. package/dist/chunk-C3Z4DX3V.js +112 -0
  52. package/dist/chunk-CI2G3OEB.js +1818 -0
  53. package/dist/chunk-CKNVO24D.js +54 -0
  54. package/dist/chunk-CUVHQHZ7.js +391 -0
  55. package/dist/chunk-CXK4DZH3.js +114 -0
  56. package/dist/chunk-DKEPS5LH.js +315 -0
  57. package/dist/chunk-DU7W62N5.js +487 -0
  58. package/dist/chunk-DZAQBW35.js +751 -0
  59. package/dist/chunk-EB6FPQUP.js +316 -0
  60. package/dist/chunk-EMS2SK26.js +376 -0
  61. package/dist/chunk-ERLBPDGU.js +510 -0
  62. package/dist/chunk-EVCVDTXE.js +732 -0
  63. package/dist/chunk-FCIIHT24.js +384 -0
  64. package/dist/chunk-FFUN5D66.js +97 -0
  65. package/dist/chunk-FITOLXSX.js +714 -0
  66. package/dist/chunk-FMDSF3OV.js +68 -0
  67. package/dist/chunk-FNB3PNGF.js +410 -0
  68. package/dist/chunk-G2H74XJZ.js +2104 -0
  69. package/dist/chunk-GMR5MFHJ.js +339 -0
  70. package/dist/chunk-H6PI3KJT.js +305 -0
  71. package/dist/chunk-I46X5VUA.js +59 -0
  72. package/dist/chunk-I5IGB56C.js +255 -0
  73. package/dist/chunk-IH6ZMVQ5.js +3950 -0
  74. package/dist/chunk-IJZFN3HM.js +463 -0
  75. package/dist/chunk-IPWPWM6R.js +3079 -0
  76. package/dist/chunk-IYULMRBE.js +23 -0
  77. package/dist/chunk-IZMRON6C.js +167 -0
  78. package/dist/chunk-J5FIXQRT.js +813 -0
  79. package/dist/chunk-JED6ZDEE.js +73 -0
  80. package/dist/chunk-JEUJOX5X.js +136 -0
  81. package/dist/chunk-JM4LEPY3.js +436 -0
  82. package/dist/chunk-L3UHP6TD.js +101 -0
  83. package/dist/chunk-L66GEFB6.js +524 -0
  84. package/dist/chunk-LIOHW36Z.js +469 -0
  85. package/dist/chunk-LP7EC4MI.js +16 -0
  86. package/dist/chunk-MITI6NOL.js +548 -0
  87. package/dist/chunk-MO5YHHMQ.js +168 -0
  88. package/dist/chunk-MZSBFAPJ.js +885 -0
  89. package/dist/chunk-NNAAJVBU.js +9 -0
  90. package/dist/chunk-NOTA6TEI.js +47 -0
  91. package/dist/chunk-NURGB5Z4.js +335 -0
  92. package/dist/chunk-NX4EQS3U.js +1062 -0
  93. package/dist/chunk-NXMESY4J.js +1 -0
  94. package/dist/chunk-OJR3MQYV.js +1458 -0
  95. package/dist/chunk-OURHMODR.js +454 -0
  96. package/dist/chunk-P235SVAH.js +1057 -0
  97. package/dist/chunk-P4RH4OSP.js +1038 -0
  98. package/dist/chunk-P6T66CCZ.js +226 -0
  99. package/dist/chunk-PBAHEPLQ.js +223 -0
  100. package/dist/chunk-PBHE5UG6.js +1530 -0
  101. package/dist/chunk-PDKUANDZ.js +35 -0
  102. package/dist/chunk-PWIHZ6NJ.js +296 -0
  103. package/dist/chunk-QEBUY5NY.js +1685 -0
  104. package/dist/chunk-QLCCJEJI.js +253 -0
  105. package/dist/chunk-QOOUC2J5.js +52 -0
  106. package/dist/chunk-QYTPPDAO.js +402 -0
  107. package/dist/chunk-R3XI2VC7.js +801 -0
  108. package/dist/chunk-RCERWOJR.js +154 -0
  109. package/dist/chunk-RJE5JTVK.js +362 -0
  110. package/dist/chunk-RTLBSQ3G.js +1155 -0
  111. package/dist/chunk-RUNNI6VE.js +448 -0
  112. package/dist/chunk-RVMRZAPB.js +354 -0
  113. package/dist/chunk-RYEGFMUO.js +955 -0
  114. package/dist/chunk-RZCF2VVM.js +528 -0
  115. package/dist/chunk-SML67VPV.js +1025 -0
  116. package/dist/chunk-SQ7IY53Q.js +44 -0
  117. package/dist/chunk-SQAG3UXH.js +161 -0
  118. package/dist/chunk-SRTU6HMQ.js +1851 -0
  119. package/dist/chunk-T2OE3YQB.js +550 -0
  120. package/dist/chunk-T3UBLACL.js +299 -0
  121. package/dist/chunk-TLVIHFRO.js +296 -0
  122. package/dist/chunk-TYS6CSS5.js +52 -0
  123. package/dist/chunk-U6EQI3U6.js +130 -0
  124. package/dist/chunk-UJ4FJLBF.js +86 -0
  125. package/dist/chunk-ULOEATBZ.js +347 -0
  126. package/dist/chunk-UNCCZ3NU.js +127 -0
  127. package/dist/chunk-USZW2HHU.js +197 -0
  128. package/dist/chunk-UWN33VNX.js +1610 -0
  129. package/dist/chunk-UZ7EZW3B.js +40 -0
  130. package/dist/chunk-VOKGH627.js +37 -0
  131. package/dist/chunk-WBRZJOEC.js +204 -0
  132. package/dist/chunk-WCSOJFU3.js +380 -0
  133. package/dist/chunk-WCT3NYCV.js +160 -0
  134. package/dist/chunk-WVAJFAIA.js +529 -0
  135. package/dist/chunk-X5LCYCL5.js +394 -0
  136. package/dist/chunk-XAKEUMEJ.js +1256 -0
  137. package/dist/chunk-Y2ZE3MSG.js +590 -0
  138. package/dist/chunk-Y3J7VR52.js +646 -0
  139. package/dist/chunk-Y5QGVTVC.js +33 -0
  140. package/dist/chunk-YAA6IID3.js +548 -0
  141. package/dist/chunk-YGJTDXVR.js +692 -0
  142. package/dist/chunk-YRYKTYMQ.js +186 -0
  143. package/dist/chunk-YYVTBZZC.js +61 -0
  144. package/dist/chunk-Z5CGSFJB.js +647 -0
  145. package/dist/chunk-Z72XRXD4.js +787 -0
  146. package/dist/chunk-ZGR7ULFJ.js +978 -0
  147. package/dist/chunk-ZJEL4H2R.js +851 -0
  148. package/dist/chunk-ZO27FGJS.js +554 -0
  149. package/dist/cli.cjs +112 -112
  150. package/dist/collapse-CLPJD2RL.js +11 -0
  151. package/dist/collapse-SLINJQW6.js +9 -0
  152. package/dist/collapse-ZWUFFCK2.js +9 -0
  153. package/dist/compute-G55RG53N.js +8 -0
  154. package/dist/dgmo-router-DZCIDUO5.js +73 -0
  155. package/dist/dimensions-J3FHIMJ6.js +22 -0
  156. package/dist/element.cjs +492 -325
  157. package/dist/element.js +367 -259
  158. package/dist/element.mjs +492 -325
  159. package/dist/flowchart-parser-ZNSKIBVR.js +21 -0
  160. package/dist/flowchart-renderer-ZAEOL4DX.js +35 -0
  161. package/dist/index.cjs +34 -28
  162. package/dist/index.d.cts +3 -469
  163. package/dist/index.d.ts +3 -469
  164. package/dist/index.js +137 -69679
  165. package/dist/layout-46N4JJYK.js +17 -0
  166. package/dist/layout-5RA6QWR6.js +26 -0
  167. package/dist/layout-5T6RH5M6.js +14 -0
  168. package/dist/layout-7QXCNOVS.js +13 -0
  169. package/dist/layout-EE6GE46Y.js +17 -0
  170. package/dist/layout-G23F7LDH.js +9 -0
  171. package/dist/layout-HRBZPFCN.js +23 -0
  172. package/dist/layout-HWDSRX5E.js +20 -0
  173. package/dist/layout-HYZPWAK5.js +18 -0
  174. package/dist/layout-N76NR4ZO.js +19 -0
  175. package/dist/layout-OB3RI63S.js +14 -0
  176. package/dist/layout-S2QBYSK2.js +15 -0
  177. package/dist/layout-UM5F4DJB.js +15 -0
  178. package/dist/layout-search-OYV77HHS.js +1655 -0
  179. package/dist/load-data-EHDDZ5ZS.js +8 -0
  180. package/dist/palettes-PRJ2RI6D.js +56 -0
  181. package/dist/parser-2MFP2H2E.js +11 -0
  182. package/dist/parser-3STE62GB.js +21 -0
  183. package/dist/parser-4FL2CMDG.js +18 -0
  184. package/dist/parser-4OGOBJJ4.js +13 -0
  185. package/dist/parser-6BTRLKRZ.js +15 -0
  186. package/dist/parser-AQETEVRW.js +21 -0
  187. package/dist/parser-CFZD5IBL.js +12 -0
  188. package/dist/parser-FUSKFGZN.js +16 -0
  189. package/dist/parser-I6KXEYFK.js +13 -0
  190. package/dist/parser-IXSZZQHY.js +18 -0
  191. package/dist/parser-JAL2HD4I.js +13 -0
  192. package/dist/parser-KNSQSKQO.js +20 -0
  193. package/dist/parser-N5O4IHUN.js +13 -0
  194. package/dist/parser-NGU3ETO6.js +16 -0
  195. package/dist/parser-NRAI6O25.js +19 -0
  196. package/dist/parser-O5J4VBII.js +11 -0
  197. package/dist/parser-OV7NOBW6.js +21 -0
  198. package/dist/parser-PQ3POX45.js +23 -0
  199. package/dist/parser-TFZFBVWN.js +11 -0
  200. package/dist/parser-TRTHDFPP.js +18 -0
  201. package/dist/parser-VQP2UJ6W.js +11 -0
  202. package/dist/parser-XDVELHRK.js +13 -0
  203. package/dist/parser-XKRP7QKP.js +11 -0
  204. package/dist/parser-Y6WTBU76.js +14 -0
  205. package/dist/parser-ZSDPZYQP.js +12 -0
  206. package/dist/renderer-2XQQQ6QR.js +28 -0
  207. package/dist/renderer-5NDVNDAZ.js +26 -0
  208. package/dist/renderer-6EEZHMH4.js +26 -0
  209. package/dist/renderer-6W5462RB.js +43 -0
  210. package/dist/renderer-7MVLWWQD.js +22 -0
  211. package/dist/renderer-AWWAF6XD.js +33 -0
  212. package/dist/renderer-BYCNMBF7.js +34 -0
  213. package/dist/renderer-CLJHQPBJ.js +29 -0
  214. package/dist/renderer-GHPZMFU2.js +15 -0
  215. package/dist/renderer-JGBKUCZD.js +16 -0
  216. package/dist/renderer-KQB7UGDS.js +19 -0
  217. package/dist/renderer-PGX2TKVS.js +24 -0
  218. package/dist/renderer-QIWVHWZO.js +15 -0
  219. package/dist/renderer-RPOA5YPZ.js +35 -0
  220. package/dist/renderer-SMIBCRVB.js +24 -0
  221. package/dist/renderer-T7YKC5VP.js +28 -0
  222. package/dist/renderer-TOCOVLHS.js +37 -0
  223. package/dist/renderer-UWA5XS74.js +39 -0
  224. package/dist/renderer-VACVQYML.js +25 -0
  225. package/dist/renderer-W4M6QLIJ.js +37 -0
  226. package/dist/renderer-WZRREQ2P.js +23 -0
  227. package/dist/renderer-YY2OSF6E.js +27 -0
  228. package/dist/renderer-Z7I3W2PP.js +24 -0
  229. package/dist/renderer-ZGNTUWC4.js +22 -0
  230. package/dist/renderer-ZTR3DER3.js +19 -0
  231. package/dist/renderer-radial-C32GPJQ7.js +21 -0
  232. package/dist/resolver-NOAA7ID7.js +13 -0
  233. package/dist/state-collapse-HCGD6IVJ.js +8 -0
  234. package/dist/state-parser-Z2V23ATR.js +18 -0
  235. package/dist/state-renderer-RFYHSP4K.js +34 -0
  236. package/dist/themes-1-CuKpeH.d.cts +908 -0
  237. package/dist/themes-1-CuKpeH.d.ts +908 -0
  238. package/package.json +1 -1
  239. package/src/auto/index.ts +55 -57
  240. package/src/auto/shared.ts +142 -142
  241. package/src/auto/styles.ts +44 -199
  242. package/src/c4/renderer.ts +2 -2
  243. package/src/element/index.ts +29 -21
  244. package/src/infra/renderer.ts +1 -1
  245. package/src/render.ts +34 -14
  246. package/src/sitemap/renderer.ts +1 -1
  247. package/src/timeline/renderer.ts +1 -1
  248. package/src/utils/hover-styles.ts +6 -1
  249. package/src/utils/legend-d3.ts +1 -4
  250. package/src/utils/legend-svg.ts +1 -1
@@ -0,0 +1,1155 @@
1
+ import {
2
+ formatLocalISODate,
3
+ parseLocalISODate
4
+ } from "./chunk-L3UHP6TD.js";
5
+ import {
6
+ parseDuration
7
+ } from "./chunk-USZW2HHU.js";
8
+ import {
9
+ AUTO_TAG_COLOR_SENTINEL,
10
+ finalizeAutoTagColors,
11
+ injectDefaultTagMetadata,
12
+ matchTagBlockHeading,
13
+ stripDefaultModifier,
14
+ tagAttrKey,
15
+ validateTagGroupNames,
16
+ validateTagValues
17
+ } from "./chunk-QLCCJEJI.js";
18
+ import {
19
+ normalizeName
20
+ } from "./chunk-NOTA6TEI.js";
21
+ import {
22
+ PERT_REGISTRY,
23
+ extractColor,
24
+ measureIndent,
25
+ splitNameAndMeta,
26
+ warnUnknownMetaKeys,
27
+ withTagAliases
28
+ } from "./chunk-Y3J7VR52.js";
29
+ import {
30
+ emit,
31
+ makeDgmoError,
32
+ suggest
33
+ } from "./chunk-CXK4DZH3.js";
34
+
35
+ // src/pert/diagnostics.ts
36
+ var PERT_DX = {
37
+ BOTH_ANCHORS: {
38
+ code: "E_PERT_BOTH_ANCHORS",
39
+ severity: "error",
40
+ // Runtime: error() @ parser.ts ~1508
41
+ chartType: "pert",
42
+ title: "Both start-date and end-date set",
43
+ // Message interpolates an optional `priorRef` suffix referencing the
44
+ // first anchor's kind + line. Builder tolerates `{}` (suffix omitted).
45
+ message: (p) => {
46
+ const kind = p.firstAnchorKey;
47
+ const line = p.firstAnchorLine;
48
+ const priorRef = kind && line ? ` Conflicts with \`${String(kind)}\` declared on line ${String(line)}.` : "";
49
+ return `Specify \`start-date\` or \`end-date\`, not both. Use one anchor \u2014 both directives are discarded; re-author one to recover.${priorRef}`;
50
+ },
51
+ hint: "Pick a single anchor: either `start-date` (forward) or `end-date` (backward).",
52
+ example: "pert\nstart-date 2026-06-01\nend-date 2026-09-15\nA 1 2 3\n"
53
+ },
54
+ END_DATE_NOW: {
55
+ code: "E_PERT_END_DATE_NOW",
56
+ severity: "error",
57
+ // Runtime: error() @ parser.ts ~1530
58
+ chartType: "pert",
59
+ title: "`end-date now` not allowed",
60
+ message: "`end-date` requires an explicit YYYY-MM-DD; `now` is only valid for `start-date`.",
61
+ hint: "Give `end-date` a literal date, or use `start-date now` if you want today.",
62
+ example: "pert\nend-date now\nA 1 2 3\n"
63
+ },
64
+ INVALID_DATE: {
65
+ code: "E_PERT_INVALID_DATE",
66
+ severity: "error",
67
+ // Runtime: error() @ parser.ts ~1519 and ~1545
68
+ chartType: "pert",
69
+ title: "Invalid anchor date",
70
+ // Emitted from TWO sites with different wording:
71
+ // (a) empty value @ ~1519: "`${key}` requires a full date (YYYY-MM-DD), got '${value}'."
72
+ // (b) unparseable @ ~1545: "Invalid date '${trimmed}' for ${key}. Expected YYYY-MM-DD."
73
+ // The builder reproduces BOTH: pass `empty: true` + `value`/`key` for
74
+ // variant (a); pass `trimmed`/`key` for variant (b). The `{}` default
75
+ // shows variant (b)'s representative wording.
76
+ message: (p) => {
77
+ const key = p.key ?? "start-date";
78
+ if (p.empty) {
79
+ return `\`${String(key)}\` requires a full date (YYYY-MM-DD), got '${String(p.value ?? "")}'.`;
80
+ }
81
+ const date = p.trimmed ?? p.value;
82
+ return date ? `Invalid date '${String(date)}' for ${String(key)}. Expected YYYY-MM-DD.` : `Invalid date for ${String(key)}. Expected YYYY-MM-DD.`;
83
+ },
84
+ hint: "Use a calendar-valid ISO date, e.g. `2026-06-01` (dashes, not slashes).",
85
+ example: "pert\nstart-date 2026-13-99\nA 1 2 3\n"
86
+ },
87
+ NEAR_DIRECTIVE: {
88
+ code: "E_PERT_NEAR_DIRECTIVE",
89
+ severity: "error",
90
+ // Runtime: error() @ parser.ts ~938
91
+ chartType: "pert",
92
+ title: "Near-miss directive typo",
93
+ // Interpolates the mistyped head + the suggested canonical directive.
94
+ message: (p) => {
95
+ const head = p.head ?? "start";
96
+ const canonical = p.canonical ?? "start-date";
97
+ return `Unknown directive '${String(head)}'. Did you mean '${String(canonical)}'?`;
98
+ },
99
+ hint: "Use the full directive name (`start-date`, `end-date`, `default-confidence`, `time-unit`).",
100
+ example: "pert\nstart 2026-06-01\nA 1 2 3\n"
101
+ },
102
+ BD_WITH_ANCHOR: {
103
+ code: "W_PERT_BD_WITH_ANCHOR",
104
+ severity: "warning",
105
+ // Runtime: warn() @ parser.ts ~1024
106
+ chartType: "pert",
107
+ title: "Business days with date anchor",
108
+ message: "`bd` (business days) is treated as calendar days when `start-date`/`end-date` is set. For business-day scheduling with weekend/holiday awareness, use Gantt.",
109
+ hint: "Drop the date anchor, or switch to Gantt for weekend/holiday-aware scheduling.",
110
+ example: "pert\ntime-unit bd\nstart-date 2026-06-01\nA 1 2 3\n"
111
+ },
112
+ SUBDAY_WITH_ANCHOR: {
113
+ code: "W_PERT_SUBDAY_WITH_ANCHOR",
114
+ severity: "warning",
115
+ // Runtime: warn() @ parser.ts ~1030
116
+ chartType: "pert",
117
+ title: "Sub-day time-unit with date anchor",
118
+ message: "Date display rounds to whole days; sub-day `time-unit` ('h'/'min') will lose precision when `start-date`/`end-date` is set. For honest output use `time-unit d`.",
119
+ hint: "Use `time-unit d` when anchoring to dates, or remove the anchor.",
120
+ example: "pert\ntime-unit h\nstart-date 2026-06-01\nA 1 2 3\n"
121
+ }
122
+ };
123
+ var PERT_DIAGNOSTICS = Object.values(PERT_DX);
124
+
125
+ // src/pert/parser.ts
126
+ var DIRECTIVE_KEYS = /* @__PURE__ */ new Set([
127
+ "time-unit",
128
+ "default-confidence",
129
+ "direction",
130
+ "node-detail",
131
+ "no-analysis",
132
+ "trials",
133
+ "seed",
134
+ "scrubber-trials",
135
+ "start-date",
136
+ "end-date",
137
+ "no-title",
138
+ "solid-fill",
139
+ "sprint-length",
140
+ "sprint-number",
141
+ "sprint-start",
142
+ "active-tag"
143
+ ]);
144
+ var RESERVED_PIPE_KEYS = /* @__PURE__ */ new Set([
145
+ "confidence",
146
+ "collapsed"
147
+ ]);
148
+ var NEAR_DIRECTIVE_HINTS = [
149
+ {
150
+ stem: "confidence",
151
+ canonical: "default-confidence",
152
+ matches: /^(low|medium|high)$/i
153
+ },
154
+ {
155
+ stem: "start",
156
+ canonical: "start-date",
157
+ matches: /^(\d{4}-\d{2}-\d{2}|now)$/i
158
+ },
159
+ {
160
+ stem: "end",
161
+ canonical: "end-date",
162
+ matches: /^\d{4}-\d{2}-\d{2}$/
163
+ },
164
+ {
165
+ stem: "time",
166
+ canonical: "time-unit",
167
+ matches: /^(d|w|m|q|y|h|min|bd|s)$/i
168
+ }
169
+ ];
170
+ var GROUP_HEADER_RE = /^\[([^\]]+)\]\s*(.*)$/;
171
+ var ARROW_RE = /^->\s*(.+?)\s*$/;
172
+ var INDENTED_META_RE = /^([A-Za-z][\w-]*)\s*:\s*(.+)$/;
173
+ var LABELED_ARROW_RE = /^-(.+?)->\s*(.+?)\s*$/;
174
+ function parseEdgeLabel(label, defaultUnit) {
175
+ const trimmed = label.trim();
176
+ if (trimmed === "") return null;
177
+ const m = trimmed.match(/^(fs|ss|ff|sf)?([+-]?\d+(?:\.\d+)?)?\s*([a-z]+)?$/i);
178
+ if (!m) return null;
179
+ const typeRaw = m[1];
180
+ const numRaw = m[2];
181
+ const unitRaw = m[3];
182
+ if (!typeRaw && !numRaw) return null;
183
+ if (unitRaw && !numRaw) return null;
184
+ const type = typeRaw ? typeRaw.toUpperCase() : "FS";
185
+ let lag = null;
186
+ if (numRaw) {
187
+ const amount = parseFloat(numRaw);
188
+ if (amount !== 0) {
189
+ const unit = unitRaw ? unitRaw.toLowerCase() : defaultUnit;
190
+ if (!isValidDurationUnit(unit)) return null;
191
+ lag = { amount, unit };
192
+ }
193
+ }
194
+ return { type, lag };
195
+ }
196
+ var VALID_DURATION_UNITS = /* @__PURE__ */ new Set([
197
+ "min",
198
+ "h",
199
+ "d",
200
+ "bd",
201
+ "w",
202
+ "m",
203
+ "q",
204
+ "y",
205
+ "s"
206
+ ]);
207
+ function isValidDurationUnit(u) {
208
+ return VALID_DURATION_UNITS.has(u);
209
+ }
210
+ var ALIAS_SUFFIX_RE = /\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*$/;
211
+ var ESTIMATE_TOKEN_RE = /^(\d+(?:\.\d+)?)(min|bd|d|w|m|q|y|h|s)?$/;
212
+ var DEFAULT_OPTIONS = {
213
+ timeUnit: "d",
214
+ direction: "LR",
215
+ nodeDetail: "compact",
216
+ confidence: "medium",
217
+ trials: -1,
218
+ seed: -1,
219
+ scrubberTrials: 300,
220
+ anchor: null,
221
+ sprintLength: null,
222
+ sprintNumber: null,
223
+ sprintStart: null,
224
+ sprintMode: null,
225
+ today: ""
226
+ };
227
+ function deriveTrials(activityCount) {
228
+ const t = Math.round(1e3 * Math.sqrt(Math.max(activityCount, 1)));
229
+ return Math.max(5e3, Math.min(2e4, t));
230
+ }
231
+ function deriveSeed(s) {
232
+ let h = 2166136261;
233
+ for (let i = 0; i < s.length; i++) {
234
+ h ^= s.charCodeAt(i);
235
+ h = Math.imul(h, 16777619);
236
+ }
237
+ return h >>> 1;
238
+ }
239
+ function stripTrailingComment(line) {
240
+ const m = line.match(/^(.*?)\s+#.*$/);
241
+ return (m ? m[1] : line).trimEnd();
242
+ }
243
+ function peelAlias(text) {
244
+ const trimmed = text.trim();
245
+ const m = trimmed.match(ALIAS_SUFFIX_RE);
246
+ if (!m) return { head: trimmed };
247
+ const alias = m[1];
248
+ return {
249
+ head: trimmed.slice(0, m.index).trim(),
250
+ ...alias !== void 0 && { alias }
251
+ };
252
+ }
253
+ function tokenizeActivityLine(line, diagnostics, lineNumber, metaAliasMap) {
254
+ let body = line;
255
+ let pipeMetadata;
256
+ if (metaAliasMap !== void 0) {
257
+ const registry = withTagAliases(
258
+ PERT_REGISTRY,
259
+ new Set(metaAliasMap.keys())
260
+ );
261
+ const split = splitNameAndMeta(
262
+ body,
263
+ registry,
264
+ metaAliasMap,
265
+ void 0,
266
+ diagnostics,
267
+ lineNumber
268
+ );
269
+ if (diagnostics && lineNumber != null) {
270
+ warnUnknownMetaKeys(
271
+ split.meta,
272
+ registry,
273
+ (msg) => diagnostics.push(makeDgmoError(lineNumber, msg, "warning")),
274
+ split.name
275
+ );
276
+ }
277
+ if (Object.keys(split.meta).length > 0) {
278
+ let restored = split.name;
279
+ if (split.color) restored = `${restored} ${split.color}`;
280
+ if (split.alias) restored = `${restored} as ${split.alias}`;
281
+ body = restored;
282
+ const merged = Object.entries(split.meta).map(([k, v]) => `${k}: ${v}`).join(", ");
283
+ pipeMetadata = pipeMetadata ? `${pipeMetadata}, ${merged}` : merged;
284
+ }
285
+ }
286
+ const peeled = peelAlias(body);
287
+ const rawTokens = peeled.head.split(/[,\s]+/).map((t) => t.trim()).filter(Boolean);
288
+ let firstNumIdx = -1;
289
+ for (let i = 0; i < rawTokens.length; i++) {
290
+ if (ESTIMATE_TOKEN_RE.test(rawTokens[i])) {
291
+ firstNumIdx = i;
292
+ break;
293
+ }
294
+ }
295
+ let name;
296
+ let durationTokens;
297
+ if (firstNumIdx === -1) {
298
+ name = peeled.head;
299
+ durationTokens = [];
300
+ } else {
301
+ name = rawTokens.slice(0, firstNumIdx).join(" ").trim();
302
+ durationTokens = rawTokens.slice(firstNumIdx);
303
+ }
304
+ return {
305
+ name,
306
+ durationTokens,
307
+ ...peeled.alias !== void 0 && { alias: peeled.alias },
308
+ ...pipeMetadata !== void 0 && { pipeMetadata }
309
+ };
310
+ }
311
+ function parseEstimateToken(token, defaultUnit) {
312
+ const m = token.match(ESTIMATE_TOKEN_RE);
313
+ if (!m) return null;
314
+ const amount = parseFloat(m[1]);
315
+ if (!Number.isFinite(amount)) return null;
316
+ const unit = m[2] ?? defaultUnit;
317
+ if (unit === "s") {
318
+ return { amount, unit: defaultUnit };
319
+ }
320
+ const round = parseDuration(`${amount}${unit}`);
321
+ return round ?? { amount, unit };
322
+ }
323
+ function buildEstimate(tokens, defaultUnit, diagnose) {
324
+ if (tokens.length === 0) return null;
325
+ if (tokens.length === 2) {
326
+ diagnose(
327
+ `Expected 1 (M) or 3 (O M P) durations; got 2 (${tokens.join(" ")}). Did you mean '${tokens[0]} ${(parseFloat(tokens[0]) + parseFloat(tokens[1])) / 2} ${tokens[1]}'?`
328
+ );
329
+ return null;
330
+ }
331
+ if (tokens.length !== 1 && tokens.length !== 3) {
332
+ diagnose(
333
+ `Expected 1 (M) or 3 (O M P) durations; got ${tokens.length} (${tokens.join(" ")}).`
334
+ );
335
+ return null;
336
+ }
337
+ const parsed = [];
338
+ for (const t of tokens) {
339
+ const dur = parseEstimateToken(t, defaultUnit);
340
+ if (!dur) {
341
+ diagnose(`Invalid duration token '${t}'.`);
342
+ return null;
343
+ }
344
+ if (dur.amount < 0) {
345
+ diagnose(`Duration must be \u2265 0; got '${t}'.`);
346
+ return null;
347
+ }
348
+ parsed.push(dur);
349
+ }
350
+ if (parsed.length === 1) {
351
+ return { o: parsed[0], m: parsed[0], p: parsed[0], mOnly: true };
352
+ }
353
+ const [o, m, p] = parsed;
354
+ const sameUnit = o.unit === m.unit && m.unit === p.unit;
355
+ if (sameUnit && !(o.amount <= m.amount && m.amount <= p.amount)) {
356
+ diagnose(
357
+ `Invalid estimate (${tokens.join(" ")}): expected O \u2264 M \u2264 P. Did you mean (${[o.amount, m.amount, p.amount].sort((a, b) => a - b).join(" ")})?`
358
+ );
359
+ return null;
360
+ }
361
+ return { o, m, p, mOnly: false };
362
+ }
363
+ function parsePipeMetadata(raw, aliasMap = /* @__PURE__ */ new Map()) {
364
+ const out = {};
365
+ for (const part of raw.split(",")) {
366
+ const trimmed = part.trim();
367
+ if (!trimmed) continue;
368
+ const idx = trimmed.indexOf(":");
369
+ if (idx <= 0) continue;
370
+ const rawKey = trimmed.slice(0, idx).trim().toLowerCase();
371
+ const key = aliasMap.get(rawKey) ?? rawKey;
372
+ const value = trimmed.slice(idx + 1).trim();
373
+ out[key] = value;
374
+ }
375
+ return out;
376
+ }
377
+ function parsePert(content, parseOpts = {}) {
378
+ const lines = content.split("\n");
379
+ const diagnostics = [];
380
+ const error = (line, msg, code) => {
381
+ diagnostics.push(makeDgmoError(line, msg, "error", code));
382
+ };
383
+ const warn = (line, msg, code) => {
384
+ diagnostics.push(makeDgmoError(line, msg, "warning", code));
385
+ };
386
+ const today = formatLocalISODate(parseOpts.now ?? /* @__PURE__ */ new Date());
387
+ const options = { ...DEFAULT_OPTIONS, today };
388
+ let title = null;
389
+ let firstAnchorLine = null;
390
+ let firstAnchorKey = null;
391
+ const declarationsByName = /* @__PURE__ */ new Map();
392
+ const declarationsByAlias = /* @__PURE__ */ new Map();
393
+ const allDeclarations = [];
394
+ const sitesByName = /* @__PURE__ */ new Map();
395
+ const references = [];
396
+ const groups = [];
397
+ const tagGroups = [];
398
+ let currentTagGroup = null;
399
+ let contentStarted = false;
400
+ const metaAliasMap = /* @__PURE__ */ new Map();
401
+ const groupStack = [];
402
+ const currentGroupId = () => groupStack.length > 0 ? (
403
+ // In-bounds by length check.
404
+ groupStack[groupStack.length - 1].groupId
405
+ ) : void 0;
406
+ let currentSourceName = null;
407
+ let currentSourceIndent = -1;
408
+ let currentSourceSite = null;
409
+ let pastFirstLine = false;
410
+ for (let i = 0; i < lines.length; i++) {
411
+ const rawLine = lines[i];
412
+ const lineNumber = i + 1;
413
+ const trimmed = stripTrailingComment(rawLine).trim();
414
+ if (!trimmed) continue;
415
+ if (trimmed.startsWith("#") || trimmed.startsWith("//")) continue;
416
+ const indent = measureIndent(rawLine);
417
+ while (groupStack.length > 0) {
418
+ const top = groupStack[groupStack.length - 1];
419
+ if (indent <= top.indent) groupStack.pop();
420
+ else break;
421
+ }
422
+ if (currentSourceIndent >= 0 && indent <= currentSourceIndent && !trimmed.startsWith("-")) {
423
+ currentSourceName = null;
424
+ currentSourceIndent = -1;
425
+ currentSourceSite = null;
426
+ }
427
+ if (!pastFirstLine) {
428
+ pastFirstLine = true;
429
+ const tokens = trimmed.split(/\s+/);
430
+ const head = tokens[0].toLowerCase();
431
+ if (head === "pert") {
432
+ if (tokens.length > 1) title = tokens.slice(1).join(" ");
433
+ continue;
434
+ }
435
+ }
436
+ if (!contentStarted) {
437
+ const tagBlockMatch = matchTagBlockHeading(trimmed);
438
+ if (tagBlockMatch) {
439
+ currentTagGroup = {
440
+ name: tagBlockMatch.name,
441
+ ...tagBlockMatch.alias !== void 0 && {
442
+ alias: tagBlockMatch.alias
443
+ },
444
+ entries: [],
445
+ lineNumber
446
+ };
447
+ if (tagBlockMatch.alias) {
448
+ metaAliasMap.set(
449
+ tagBlockMatch.alias.toLowerCase(),
450
+ tagAttrKey(tagBlockMatch.name)
451
+ );
452
+ }
453
+ metaAliasMap.set(
454
+ normalizeName(tagBlockMatch.name),
455
+ tagAttrKey(tagBlockMatch.name)
456
+ );
457
+ tagGroups.push(currentTagGroup);
458
+ if (tagBlockMatch.inlineValues) {
459
+ for (const raw of tagBlockMatch.inlineValues) {
460
+ const { text, isDefault } = stripDefaultModifier(raw);
461
+ const { label, color } = extractColor(
462
+ text,
463
+ parseOpts.palette,
464
+ diagnostics,
465
+ lineNumber
466
+ );
467
+ if (isDefault || currentTagGroup.entries.length === 0) {
468
+ currentTagGroup.defaultValue = label;
469
+ }
470
+ currentTagGroup.entries.push({
471
+ value: label,
472
+ color: color ?? AUTO_TAG_COLOR_SENTINEL,
473
+ lineNumber
474
+ });
475
+ }
476
+ }
477
+ continue;
478
+ }
479
+ if (currentTagGroup && indent > 0) {
480
+ const { text, isDefault } = stripDefaultModifier(trimmed);
481
+ const { label, color } = extractColor(
482
+ text,
483
+ parseOpts.palette,
484
+ diagnostics,
485
+ lineNumber
486
+ );
487
+ if (isDefault || currentTagGroup.entries.length === 0) {
488
+ currentTagGroup.defaultValue = label;
489
+ }
490
+ currentTagGroup.entries.push({
491
+ value: label,
492
+ color: color ?? AUTO_TAG_COLOR_SENTINEL,
493
+ lineNumber
494
+ });
495
+ continue;
496
+ }
497
+ currentTagGroup = null;
498
+ } else if (matchTagBlockHeading(trimmed)) {
499
+ error(
500
+ lineNumber,
501
+ `'tag' declarations must appear before activities and groups.`
502
+ );
503
+ continue;
504
+ }
505
+ const groupMatch = trimmed.match(GROUP_HEADER_RE);
506
+ if (groupMatch) {
507
+ contentStarted = true;
508
+ currentTagGroup = null;
509
+ const name = groupMatch[1].trim();
510
+ const tail = (groupMatch[2] ?? "").trim();
511
+ const meta = tail ? parsePipeMetadata(tail, metaAliasMap) : {};
512
+ const id = `[${normalizeName(name)}]`;
513
+ const tags = {};
514
+ for (const [k, v] of Object.entries(meta)) {
515
+ if (!RESERVED_PIPE_KEYS.has(k)) tags[k] = v;
516
+ }
517
+ groups.push({
518
+ id,
519
+ name,
520
+ activityIds: [],
521
+ collapsed: meta["collapsed"] === "true",
522
+ lineNumber,
523
+ ...Object.keys(tags).length > 0 && { tags }
524
+ });
525
+ groupStack.push({ groupId: id, indent });
526
+ currentSourceName = null;
527
+ currentSourceIndent = -1;
528
+ currentSourceSite = null;
529
+ continue;
530
+ }
531
+ if (trimmed.startsWith("-")) {
532
+ contentStarted = true;
533
+ currentTagGroup = null;
534
+ let arrowTargetText;
535
+ let edgeType = "FS";
536
+ let edgeLag = null;
537
+ const bareMatch = trimmed.match(ARROW_RE);
538
+ if (bareMatch) {
539
+ arrowTargetText = bareMatch[1];
540
+ } else {
541
+ const labeledMatch = trimmed.match(LABELED_ARROW_RE);
542
+ if (!labeledMatch) {
543
+ error(lineNumber, `Malformed arrow line: '${trimmed}'.`);
544
+ continue;
545
+ }
546
+ const parsedLabel = parseEdgeLabel(labeledMatch[1], options.timeUnit);
547
+ if (!parsedLabel) {
548
+ error(
549
+ lineNumber,
550
+ `Invalid edge label '${labeledMatch[1]}' in '${trimmed}'. Expected a dependency type (FS/SS/FF/SF) and/or lag (e.g. '+2d', '-1d').`
551
+ );
552
+ continue;
553
+ }
554
+ arrowTargetText = labeledMatch[2];
555
+ edgeType = parsedLabel.type;
556
+ edgeLag = parsedLabel.lag;
557
+ }
558
+ if (!currentSourceName) {
559
+ error(
560
+ lineNumber,
561
+ `'-> ${arrowTargetText}' has no source \u2014 declare an activity above on a non-indented line.`
562
+ );
563
+ continue;
564
+ }
565
+ const tok = tokenizeActivityLine(
566
+ arrowTargetText,
567
+ diagnostics,
568
+ lineNumber,
569
+ metaAliasMap
570
+ );
571
+ const targetName = tok.name;
572
+ if (!targetName) {
573
+ error(lineNumber, `'-> \u2026' is missing a target name.`);
574
+ continue;
575
+ }
576
+ if (tok.durationTokens.length > 0 || tok.alias !== void 0 || tok.pipeMetadata !== void 0) {
577
+ const extras = [];
578
+ if (tok.durationTokens.length > 0) {
579
+ extras.push(`'${tok.durationTokens.join(" ")}'`);
580
+ }
581
+ if (tok.alias !== void 0) extras.push(`'as ${tok.alias}'`);
582
+ if (tok.pipeMetadata !== void 0) {
583
+ extras.push(`'${tok.pipeMetadata}'`);
584
+ }
585
+ const durHint = tok.durationTokens.length > 0 ? ` ${tok.durationTokens.join(" ")}` : "";
586
+ error(
587
+ lineNumber,
588
+ `Inline forward-declaration not allowed on '-> ${arrowTargetText}' (${extras.join(", ")}). Move attributes to a source-line: '${targetName}${durHint}' then '-> ${targetName}'.`
589
+ );
590
+ continue;
591
+ }
592
+ references.push({
593
+ sourceName: currentSourceName,
594
+ sourceLineNumber: -1,
595
+ // resolved in Pass 2 from declarations
596
+ targetName,
597
+ targetLineNumber: lineNumber,
598
+ type: edgeType,
599
+ lag: edgeLag
600
+ });
601
+ continue;
602
+ }
603
+ if (currentSourceSite) {
604
+ const metaMatch = trimmed.match(INDENTED_META_RE);
605
+ if (metaMatch) {
606
+ const rawKey = metaMatch[1];
607
+ const key = rawKey.toLowerCase();
608
+ const resolvedKey = metaAliasMap.get(key) ?? key;
609
+ if (RESERVED_PIPE_KEYS.has(resolvedKey) || metaAliasMap.has(key)) {
610
+ contentStarted = true;
611
+ currentTagGroup = null;
612
+ const entry = `${rawKey}: ${metaMatch[2].trim()}`;
613
+ currentSourceSite.pipeMetadata = currentSourceSite.pipeMetadata ? `${currentSourceSite.pipeMetadata}, ${entry}` : entry;
614
+ continue;
615
+ }
616
+ }
617
+ }
618
+ {
619
+ const firstSpace = trimmed.indexOf(" ");
620
+ const head = firstSpace === -1 ? trimmed.toLowerCase() : trimmed.slice(0, firstSpace).toLowerCase();
621
+ if (DIRECTIVE_KEYS.has(head)) {
622
+ const value = firstSpace === -1 ? "" : trimmed.slice(firstSpace + 1).trim();
623
+ if (head === "start-date" || head === "end-date") {
624
+ const hadAnchor = options.anchor !== null;
625
+ applyAnchorDirective(
626
+ head,
627
+ value,
628
+ lineNumber,
629
+ options,
630
+ diagnostics,
631
+ firstAnchorLine,
632
+ firstAnchorKey
633
+ );
634
+ if (!hadAnchor && options.anchor !== null) {
635
+ firstAnchorLine = lineNumber;
636
+ firstAnchorKey = head;
637
+ } else if (hadAnchor && options.anchor === null) {
638
+ firstAnchorLine = null;
639
+ firstAnchorKey = null;
640
+ }
641
+ continue;
642
+ }
643
+ applyDirective(head, value, lineNumber, options, error, warn);
644
+ continue;
645
+ }
646
+ }
647
+ {
648
+ const firstSpace = trimmed.indexOf(" ");
649
+ if (firstSpace > 0) {
650
+ const head = trimmed.slice(0, firstSpace).toLowerCase();
651
+ const value = trimmed.slice(firstSpace + 1).trim();
652
+ const hint = NEAR_DIRECTIVE_HINTS.find((h) => h.stem === head);
653
+ if (hint?.matches.test(value)) {
654
+ diagnostics.push(
655
+ emit(PERT_DX.NEAR_DIRECTIVE, lineNumber, {
656
+ head,
657
+ canonical: hint.canonical
658
+ })
659
+ );
660
+ continue;
661
+ }
662
+ }
663
+ }
664
+ if (/^milestone(\s|$)/i.test(trimmed)) {
665
+ error(lineNumber, `Unknown keyword 'milestone'.`);
666
+ continue;
667
+ }
668
+ {
669
+ const tok = tokenizeActivityLine(
670
+ trimmed,
671
+ diagnostics,
672
+ lineNumber,
673
+ metaAliasMap
674
+ );
675
+ if (!tok.name) {
676
+ error(lineNumber, `Empty activity name: '${trimmed}'.`);
677
+ continue;
678
+ }
679
+ contentStarted = true;
680
+ currentTagGroup = null;
681
+ const isBareSource = tok.durationTokens.length === 0 && tok.alias === void 0 && tok.pipeMetadata === void 0;
682
+ if (isBareSource && declarationsByAlias.has(tok.name)) {
683
+ const existing = declarationsByAlias.get(tok.name);
684
+ currentSourceName = existing.name;
685
+ currentSourceIndent = indent;
686
+ currentSourceSite = existing;
687
+ continue;
688
+ }
689
+ const groupHint = currentGroupId();
690
+ const site = {
691
+ name: tok.name,
692
+ ...tok.alias !== void 0 && { alias: tok.alias },
693
+ durationTokens: tok.durationTokens,
694
+ ...tok.pipeMetadata !== void 0 && {
695
+ pipeMetadata: tok.pipeMetadata
696
+ },
697
+ lineNumber,
698
+ ...groupHint !== void 0 && { groupHint }
699
+ };
700
+ registerSite(site);
701
+ currentSourceName = tok.name;
702
+ currentSourceIndent = indent;
703
+ currentSourceSite = site;
704
+ continue;
705
+ }
706
+ }
707
+ function registerSite(site) {
708
+ allDeclarations.push(site);
709
+ const key = normalizeName(site.name);
710
+ const bucket = sitesByName.get(key);
711
+ if (bucket) bucket.push(site);
712
+ else sitesByName.set(key, [site]);
713
+ if (!declarationsByName.has(key)) {
714
+ declarationsByName.set(key, site);
715
+ }
716
+ if (site.alias && !declarationsByAlias.has(site.alias)) {
717
+ declarationsByAlias.set(site.alias, site);
718
+ }
719
+ }
720
+ if (options.anchor !== null) {
721
+ if (options.timeUnit === "bd") {
722
+ diagnostics.push(emit(PERT_DX.BD_WITH_ANCHOR, 0));
723
+ } else if (options.timeUnit === "min" || options.timeUnit === "h") {
724
+ diagnostics.push(emit(PERT_DX.SUBDAY_WITH_ANCHOR, 0));
725
+ }
726
+ }
727
+ for (const [key, sites] of sitesByName) {
728
+ if (sites.length < 2) continue;
729
+ const explicit = sites.filter((s) => s.durationTokens.length > 0);
730
+ if (explicit.length < 2) continue;
731
+ const fingerprints = new Set(
732
+ explicit.map((s) => s.durationTokens.join(" "))
733
+ );
734
+ if (fingerprints.size > 1) {
735
+ const lineList = explicit.map((s) => `line ${s.lineNumber} (${s.durationTokens.join(" ")})`).join(" and ");
736
+ error(
737
+ explicit[0].lineNumber,
738
+ `Conflicting estimates for "${declarationsByName.get(key).name}" on ${lineList}. Keep one declaration site.`
739
+ );
740
+ }
741
+ }
742
+ const idMap = {};
743
+ for (const [, decl] of declarationsByName) {
744
+ const id = canonicalIdFromDeclaration(decl);
745
+ idMap[normalizeName(decl.name)] = id;
746
+ idMap[decl.name.toLowerCase()] = id;
747
+ }
748
+ for (const [aliasLiteral, decl] of declarationsByAlias) {
749
+ idMap[aliasLiteral] = canonicalIdFromDeclaration(decl);
750
+ }
751
+ function canonicalIdFromDeclaration(decl) {
752
+ return normalizeName(decl.name);
753
+ }
754
+ function resolveTargetId(token, lineNumber) {
755
+ const trimmed = token.trim();
756
+ if (declarationsByAlias.has(trimmed)) {
757
+ return canonicalIdFromDeclaration(declarationsByAlias.get(trimmed));
758
+ }
759
+ const norm = normalizeName(trimmed);
760
+ if (declarationsByName.has(norm)) {
761
+ return canonicalIdFromDeclaration(declarationsByName.get(norm));
762
+ }
763
+ const candidates = [
764
+ ...declarationsByAlias.keys(),
765
+ ...[...declarationsByName.values()].map((d) => d.name)
766
+ ];
767
+ const hint = suggest(trimmed, candidates);
768
+ error(
769
+ lineNumber,
770
+ `Unknown activity '${trimmed}'.${hint ? ` ${hint}` : ""}`
771
+ );
772
+ return null;
773
+ }
774
+ const bestDeclByName = /* @__PURE__ */ new Map();
775
+ for (const decl of allDeclarations) {
776
+ const key = normalizeName(decl.name);
777
+ const existing = bestDeclByName.get(key);
778
+ if (!existing) {
779
+ bestDeclByName.set(key, decl);
780
+ continue;
781
+ }
782
+ const existingHasInfo = existing.durationTokens.length > 0 || existing.alias !== void 0;
783
+ const incomingHasInfo = decl.durationTokens.length > 0 || decl.alias !== void 0;
784
+ if (!existingHasInfo && incomingHasInfo) {
785
+ bestDeclByName.set(key, decl);
786
+ }
787
+ }
788
+ const activitiesById = /* @__PURE__ */ new Map();
789
+ for (const [id, decl] of bestDeclByName) {
790
+ const estimate = buildEstimate(
791
+ decl.durationTokens,
792
+ options.timeUnit,
793
+ (msg) => error(decl.lineNumber, msg)
794
+ );
795
+ const meta = decl.pipeMetadata ? parsePipeMetadata(decl.pipeMetadata, metaAliasMap) : {};
796
+ const tags = {};
797
+ for (const [k, v] of Object.entries(meta)) {
798
+ if (!RESERVED_PIPE_KEYS.has(k)) tags[k] = v;
799
+ }
800
+ const isMilestone = estimate !== null && estimate.o.amount === 0 && estimate.m.amount === 0 && estimate.p.amount === 0;
801
+ activitiesById.set(id, {
802
+ id,
803
+ name: decl.name,
804
+ ...decl.alias !== void 0 && { alias: decl.alias },
805
+ duration: estimate,
806
+ ...meta["confidence"] && { confidence: meta["confidence"] },
807
+ ...decl.groupHint !== void 0 && { groupId: decl.groupHint },
808
+ lineNumber: decl.lineNumber,
809
+ isMilestone,
810
+ ...Object.keys(tags).length > 0 && { tags }
811
+ });
812
+ }
813
+ const edges = [];
814
+ for (const ref of references) {
815
+ const sourceId = resolveTargetId(ref.sourceName, ref.targetLineNumber);
816
+ const targetId = resolveTargetId(ref.targetName, ref.targetLineNumber);
817
+ if (!sourceId || !targetId) continue;
818
+ edges.push({
819
+ source: sourceId,
820
+ target: targetId,
821
+ lineNumber: ref.targetLineNumber,
822
+ type: ref.type,
823
+ lag: ref.lag
824
+ });
825
+ }
826
+ for (const group of groups) {
827
+ group.activityIds = [...activitiesById.values()].filter((a) => a.groupId === group.id).map((a) => a.id);
828
+ group.classification = classifyGroup(group, edges);
829
+ }
830
+ const seen = /* @__PURE__ */ new Set();
831
+ const activities = [];
832
+ for (const decl of allDeclarations) {
833
+ const id = canonicalIdFromDeclaration(decl);
834
+ if (seen.has(id)) continue;
835
+ seen.add(id);
836
+ const a = activitiesById.get(id);
837
+ if (a) activities.push(a);
838
+ }
839
+ if (options.trials === -1) {
840
+ options.trials = deriveTrials(activities.length);
841
+ }
842
+ if (options.seed === -1) {
843
+ const seedSource = title || activities.map((a) => a.name).sort().join("\n") || "pert";
844
+ options.seed = deriveSeed(seedSource);
845
+ }
846
+ const hasSprintOption = options.sprintLength !== null || options.sprintNumber !== null || options.sprintStart !== null;
847
+ const hasSprintUnit = options.timeUnit === "s" || activities.some(
848
+ (a) => a.duration !== null && (a.duration.o.unit === "s" || a.duration.m.unit === "s" || a.duration.p.unit === "s")
849
+ );
850
+ if (hasSprintOption) {
851
+ options.sprintMode = "explicit";
852
+ } else if (hasSprintUnit) {
853
+ options.sprintMode = "auto";
854
+ }
855
+ if (options.sprintMode) {
856
+ if (!options.sprintLength) {
857
+ options.sprintLength = { amount: 2, unit: "w" };
858
+ }
859
+ if (options.sprintNumber === null) {
860
+ options.sprintNumber = 1;
861
+ }
862
+ }
863
+ finalizeAutoTagColors(tagGroups, parseOpts.palette);
864
+ if (tagGroups.length > 0) {
865
+ validateTagGroupNames(
866
+ tagGroups.map((g) => ({
867
+ name: g.name,
868
+ alias: g.alias ?? null,
869
+ lineNumber: g.lineNumber
870
+ })),
871
+ warn,
872
+ error
873
+ );
874
+ const ensureTags = (entity) => {
875
+ if (!entity.tags) entity.tags = {};
876
+ return {
877
+ metadata: entity.tags,
878
+ lineNumber: entity.lineNumber
879
+ };
880
+ };
881
+ const activityShells = activities.map(ensureTags);
882
+ const groupShells = groups.map(ensureTags);
883
+ validateTagValues(
884
+ [...activityShells, ...groupShells],
885
+ tagGroups,
886
+ warn,
887
+ suggest
888
+ );
889
+ injectDefaultTagMetadata(activityShells, tagGroups);
890
+ for (const a of activities) {
891
+ if (a.tags && Object.keys(a.tags).length === 0) delete a.tags;
892
+ }
893
+ for (const g of groups) {
894
+ if (g.tags && Object.keys(g.tags).length === 0) delete g.tags;
895
+ }
896
+ }
897
+ const firstFatal = diagnostics.find((d) => d.severity === "error");
898
+ return {
899
+ title,
900
+ options,
901
+ activities,
902
+ edges,
903
+ groups,
904
+ tagGroups,
905
+ idMap,
906
+ diagnostics,
907
+ error: firstFatal ? firstFatal.message : null
908
+ };
909
+ }
910
+ function applyDirective(key, value, lineNumber, options, error, warn) {
911
+ switch (key) {
912
+ case "time-unit": {
913
+ const valid = [
914
+ "min",
915
+ "h",
916
+ "d",
917
+ "bd",
918
+ "w",
919
+ "m",
920
+ "q",
921
+ "y",
922
+ "s"
923
+ ];
924
+ if (!valid.includes(value)) {
925
+ error(
926
+ lineNumber,
927
+ `Unknown time-unit '${value}'. Expected one of ${valid.join(", ")}.`
928
+ );
929
+ return;
930
+ }
931
+ options.timeUnit = value;
932
+ return;
933
+ }
934
+ case "default-confidence": {
935
+ options.confidence = value || "medium";
936
+ return;
937
+ }
938
+ case "no-title": {
939
+ options.noTitle = true;
940
+ return;
941
+ }
942
+ case "solid-fill": {
943
+ options.solidFill = true;
944
+ return;
945
+ }
946
+ case "active-tag": {
947
+ options.activeTag = value;
948
+ return;
949
+ }
950
+ case "sprint-length": {
951
+ const dur = parseDuration(value);
952
+ if (!dur) {
953
+ warn(
954
+ lineNumber,
955
+ `Invalid sprint-length value: "${value}". Expected a duration like "2w" or "10d".`
956
+ );
957
+ } else if (dur.unit !== "d" && dur.unit !== "w") {
958
+ warn(
959
+ lineNumber,
960
+ `sprint-length only accepts "d" or "w" units, got "${dur.unit}".`
961
+ );
962
+ } else if (dur.amount <= 0) {
963
+ warn(lineNumber, `sprint-length must be greater than 0.`);
964
+ } else if (!Number.isInteger(dur.amount * (dur.unit === "w" ? 7 : 1))) {
965
+ warn(
966
+ lineNumber,
967
+ `sprint-length must resolve to a whole number of days.`
968
+ );
969
+ } else {
970
+ options.sprintLength = dur;
971
+ }
972
+ return;
973
+ }
974
+ case "sprint-number": {
975
+ const n = Number(value);
976
+ if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
977
+ warn(
978
+ lineNumber,
979
+ `sprint-number must be a positive integer, got "${value}".`
980
+ );
981
+ } else {
982
+ options.sprintNumber = n;
983
+ }
984
+ return;
985
+ }
986
+ case "sprint-start": {
987
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
988
+ warn(
989
+ lineNumber,
990
+ `sprint-start requires a full date (YYYY-MM-DD), got "${value}".`
991
+ );
992
+ } else if (Number.isNaN((/* @__PURE__ */ new Date(value + "T00:00:00")).getTime())) {
993
+ warn(lineNumber, `sprint-start is not a valid date: "${value}".`);
994
+ } else {
995
+ options.sprintStart = value;
996
+ }
997
+ return;
998
+ }
999
+ case "direction": {
1000
+ const upper = value.toUpperCase();
1001
+ if (upper !== "LR" && upper !== "TB") {
1002
+ error(lineNumber, `Unknown direction '${value}'. Expected LR or TB.`);
1003
+ return;
1004
+ }
1005
+ options.direction = upper;
1006
+ return;
1007
+ }
1008
+ case "node-detail": {
1009
+ if (value !== "compact" && value !== "full") {
1010
+ error(
1011
+ lineNumber,
1012
+ `Unknown node-detail '${value}'. Expected compact or full.`
1013
+ );
1014
+ return;
1015
+ }
1016
+ options.nodeDetail = value;
1017
+ return;
1018
+ }
1019
+ case "no-analysis": {
1020
+ options.noAnalysis = true;
1021
+ return;
1022
+ }
1023
+ case "trials": {
1024
+ const n = parseInt(value, 10);
1025
+ if (!Number.isFinite(n) || n < 1) {
1026
+ error(
1027
+ lineNumber,
1028
+ `'trials' expects a positive integer; got '${value}'.`
1029
+ );
1030
+ return;
1031
+ }
1032
+ options.trials = n;
1033
+ return;
1034
+ }
1035
+ case "seed": {
1036
+ const n = parseInt(value, 10);
1037
+ if (!Number.isFinite(n)) {
1038
+ error(lineNumber, `'seed' expects an integer; got '${value}'.`);
1039
+ return;
1040
+ }
1041
+ options.seed = n;
1042
+ return;
1043
+ }
1044
+ case "scrubber-trials": {
1045
+ const n = parseInt(value, 10);
1046
+ if (!Number.isFinite(n) || n < 1) {
1047
+ error(
1048
+ lineNumber,
1049
+ `'scrubber-trials' expects a positive integer; got '${value}'.`
1050
+ );
1051
+ return;
1052
+ }
1053
+ if (n < 100) {
1054
+ warn(
1055
+ lineNumber,
1056
+ `'scrubber-trials ${n}' is below the floor of 100; analyzer will still degrade if needed.`
1057
+ );
1058
+ }
1059
+ options.scrubberTrials = n;
1060
+ return;
1061
+ }
1062
+ case "start-date":
1063
+ case "end-date": {
1064
+ error(
1065
+ lineNumber,
1066
+ `internal error: anchor directive '${key}' reached generic dispatch`
1067
+ );
1068
+ return;
1069
+ }
1070
+ }
1071
+ }
1072
+ function applyAnchorDirective(key, value, lineNumber, options, diagnostics, firstAnchorLine, firstAnchorKey) {
1073
+ if (options.anchor !== null) {
1074
+ diagnostics.push(
1075
+ emit(PERT_DX.BOTH_ANCHORS, lineNumber, {
1076
+ firstAnchorKey,
1077
+ firstAnchorLine
1078
+ })
1079
+ );
1080
+ options.anchor = null;
1081
+ return;
1082
+ }
1083
+ const trimmed = value.trim();
1084
+ if (trimmed.length === 0) {
1085
+ diagnostics.push(
1086
+ emit(PERT_DX.INVALID_DATE, lineNumber, { empty: true, key, value })
1087
+ );
1088
+ return;
1089
+ }
1090
+ if (trimmed.toLowerCase() === "now") {
1091
+ if (key === "end-date") {
1092
+ diagnostics.push(emit(PERT_DX.END_DATE_NOW, lineNumber));
1093
+ return;
1094
+ }
1095
+ options.anchor = { kind: "forward", date: options.today };
1096
+ return;
1097
+ }
1098
+ const parsed = parseLocalISODate(trimmed);
1099
+ if (!parsed) {
1100
+ diagnostics.push(emit(PERT_DX.INVALID_DATE, lineNumber, { trimmed, key }));
1101
+ return;
1102
+ }
1103
+ options.anchor = key === "start-date" ? { kind: "forward", date: trimmed } : { kind: "backward", date: trimmed };
1104
+ }
1105
+ function classifyGroup(group, edges) {
1106
+ const members = new Set(group.activityIds);
1107
+ if (members.size === 0) return "cluster";
1108
+ const entries = /* @__PURE__ */ new Set();
1109
+ const exits = /* @__PURE__ */ new Set();
1110
+ for (const id of members) {
1111
+ const incoming = edges.filter((e) => e.target === id);
1112
+ const outgoing = edges.filter((e) => e.source === id);
1113
+ const hasInsideIn = incoming.some((e) => members.has(e.source));
1114
+ const hasOutsideIn = incoming.some((e) => !members.has(e.source));
1115
+ const hasInsideOut = outgoing.some((e) => members.has(e.target));
1116
+ const hasOutsideOut = outgoing.some((e) => !members.has(e.target));
1117
+ if (hasOutsideIn || !hasInsideIn && incoming.length === 0)
1118
+ entries.add(id);
1119
+ if (hasOutsideOut || !hasInsideOut && outgoing.length === 0)
1120
+ exits.add(id);
1121
+ }
1122
+ return entries.size === 1 && exits.size === 1 ? "hammock" : "cluster";
1123
+ }
1124
+ function extractPertSymbols(docText) {
1125
+ const parsed = parsePert(docText);
1126
+ const entities = [];
1127
+ for (const a of parsed.activities) {
1128
+ if (!entities.includes(a.name)) entities.push(a.name);
1129
+ if (a.alias && !entities.includes(a.alias)) entities.push(a.alias);
1130
+ }
1131
+ for (const g of parsed.groups) {
1132
+ if (!entities.includes(g.name)) entities.push(g.name);
1133
+ }
1134
+ return {
1135
+ kind: "pert",
1136
+ entities
1137
+ };
1138
+ }
1139
+ function looksLikePert(content) {
1140
+ for (const raw of content.split("\n")) {
1141
+ const line = raw.trim();
1142
+ if (!line || line.startsWith("//") || line.startsWith("#")) continue;
1143
+ if (/^analysis\s+monte-carlo\b/i.test(line)) return true;
1144
+ }
1145
+ return false;
1146
+ }
1147
+
1148
+ export {
1149
+ PERT_DIAGNOSTICS,
1150
+ parseEdgeLabel,
1151
+ parsePert,
1152
+ extractPertSymbols,
1153
+ looksLikePert
1154
+ };
1155
+ //# sourceMappingURL=chunk-RTLBSQ3G.js.map