@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,1256 @@
1
+ import {
2
+ GANTT_BOOLEAN_SET,
3
+ GANTT_OPTION_SET
4
+ } from "./chunk-DKEPS5LH.js";
5
+ import {
6
+ parseDuration,
7
+ parseOffset,
8
+ parseOffsetPrefix
9
+ } from "./chunk-USZW2HHU.js";
10
+ import {
11
+ getSeriesColors
12
+ } from "./chunk-P6T66CCZ.js";
13
+ import {
14
+ matchTagBlockHeading,
15
+ stripDefaultModifier,
16
+ tagAttrKey,
17
+ validateTagGroupNames
18
+ } from "./chunk-QLCCJEJI.js";
19
+ import {
20
+ normalizeName
21
+ } from "./chunk-NOTA6TEI.js";
22
+ import {
23
+ GANTT_REGISTRY,
24
+ extractColor,
25
+ isReservedKey,
26
+ measureIndent,
27
+ parseFirstLine,
28
+ splitNameAndMeta,
29
+ warnUnknownMetaKeys,
30
+ withTagAliases
31
+ } from "./chunk-Y3J7VR52.js";
32
+ import {
33
+ formatDgmoError,
34
+ makeDgmoError
35
+ } from "./chunk-CXK4DZH3.js";
36
+
37
+ // src/gantt/parser.ts
38
+ var GROUP_RE = /^\[(.+?)\]\s*(.*)$/;
39
+ var DEPENDENCY_RE = /^(?:-(.+?))?->\s*(.+)$/;
40
+ var COMMENT_RE = /^\/\//;
41
+ var ERA_RE = /^era\s+(\d{4}(?:-\d{2}(?:-\d{2}(?: \d{2}:\d{2})?)?)?)\s*(?:->|\u2013>)\s*(\d{4}(?:-\d{2}(?:-\d{2}(?: \d{2}:\d{2})?)?)?)\s+(.+)$/i;
42
+ var MARKER_RE = /^marker\s+(\d{4}(?:-\d{2}(?:-\d{2}(?: \d{2}:\d{2})?)?)?)\s+(.+)$/i;
43
+ var HOLIDAY_DATE_RE = /^(\d{4}-\d{2}-\d{2})\s+(.+)$/;
44
+ var HOLIDAY_RANGE_RE = /^(\d{4}-\d{2}-\d{2})\s*(?:->|\u2013>)\s*(\d{4}-\d{2}-\d{2})\s+(.+)$/;
45
+ var WORKWEEK_RE = /^workweek\s+(.+)$/i;
46
+ var ERA_ENTRY_RE = /^(\d{4}(?:-\d{2}(?:-\d{2}(?: \d{2}:\d{2})?)?)?)\s*(?:->|\u2013>)\s*(\d{4}(?:-\d{2}(?:-\d{2}(?: \d{2}:\d{2})?)?)?)\s+(.+)$/;
47
+ var MARKER_ENTRY_RE = /^(\d{4}(?:-\d{2}(?:-\d{2}(?: \d{2}:\d{2})?)?)?)\s+(.+)$/;
48
+ var OFFSET_PREFIX_RE = /^\+(\d+(?:\.\d+)?(?:min|bd|d|w|m|q|y|h|s))\s+(.*)/;
49
+ var DURATION_TOKEN_RE = /^(\d+(?:\.\d+)?)(min|bd|d|w|m|q|y|h|s)(\?)?$/;
50
+ var LAG_ARROW_RE = /^-(\d+(?:\.\d+)?(?:min|bd|d|w|m|q|y|h|s))->\s*(.*)/;
51
+ var LEAD_ARROW_RE = /^--(\d+(?:\.\d+)?(?:min|bd|d|w|m|q|y|h|s))->\s*(.*)/;
52
+ var BASIC_ARROW_RE = /^->\s*(.*)/;
53
+ var ERA_OFFSET_RE = /^era\s+\+(\d+(?:\.\d+)?(?:min|bd|d|w|m|q|y|h|s))\s*(?:->|–>)\s*\+(\d+(?:\.\d+)?(?:min|bd|d|w|m|q|y|h|s))\s+(.+)$/i;
54
+ var MARKER_OFFSET_RE = /^marker\s+\+(\d+(?:\.\d+)?(?:min|bd|d|w|m|q|y|h|s))\s+(.+)$/i;
55
+ var WEEKDAY_MAP = {
56
+ mon: "mon",
57
+ tue: "tue",
58
+ wed: "wed",
59
+ thu: "thu",
60
+ fri: "fri",
61
+ sat: "sat",
62
+ sun: "sun",
63
+ monday: "mon",
64
+ tuesday: "tue",
65
+ wednesday: "wed",
66
+ thursday: "thu",
67
+ friday: "fri",
68
+ saturday: "sat",
69
+ sunday: "sun"
70
+ };
71
+ function parseGantt(content, palette) {
72
+ const lines = content.split("\n");
73
+ const diagnostics = [];
74
+ const holidays = {
75
+ dates: [],
76
+ ranges: [],
77
+ workweek: ["mon", "tue", "wed", "thu", "fri"]
78
+ };
79
+ const result = {
80
+ nodes: [],
81
+ holidays,
82
+ tagGroups: [],
83
+ eras: [],
84
+ markers: [],
85
+ options: {
86
+ start: null,
87
+ title: null,
88
+ titleLineNumber: null,
89
+ todayMarker: "off",
90
+ criticalPath: false,
91
+ dependencies: true,
92
+ sort: "default",
93
+ defaultSwimlaneGroup: null,
94
+ activeTag: null,
95
+ optionLineNumbers: {},
96
+ holidaysLineNumber: null,
97
+ sprintLength: null,
98
+ sprintNumber: null,
99
+ sprintStart: null,
100
+ sprintMode: null,
101
+ solidFill: false,
102
+ noTitle: false
103
+ },
104
+ diagnostics,
105
+ error: null,
106
+ syntaxMode: "new"
107
+ // always new-mode at 1.0
108
+ };
109
+ const fail = (line, message) => {
110
+ const diag = makeDgmoError(line, message);
111
+ diagnostics.push(diag);
112
+ result.error = formatDgmoError(diag);
113
+ return result;
114
+ };
115
+ const warn = (line, message) => {
116
+ diagnostics.push(makeDgmoError(line, message, "warning"));
117
+ };
118
+ const softError = (line, message) => {
119
+ diagnostics.push(makeDgmoError(line, message, "error"));
120
+ };
121
+ const metaAliasMap = /* @__PURE__ */ new Map();
122
+ const nameAliasMap = /* @__PURE__ */ new Map();
123
+ function peelAlias(label) {
124
+ const trimmed = label.trim();
125
+ const m = trimmed.match(/^(.*?)\s+as\s+([A-Za-z][A-Za-z0-9_]{0,11})\s*$/);
126
+ if (!m) return { label: trimmed };
127
+ return { label: m[1].trim(), alias: m[2] };
128
+ }
129
+ function resolveAliasTarget(token) {
130
+ return nameAliasMap.get(token.trim()) ?? token;
131
+ }
132
+ const blockStack = [];
133
+ const currentContainer = () => {
134
+ for (let k = blockStack.length - 1; k >= 0; k--) {
135
+ if (blockStack[k].containerType !== "task") {
136
+ return blockStack[k].node.children;
137
+ }
138
+ }
139
+ return result.nodes;
140
+ };
141
+ const currentGroupPath = () => {
142
+ const path = [];
143
+ for (const entry of blockStack) {
144
+ if (entry.containerType === "group") {
145
+ path.push(entry.node.name);
146
+ }
147
+ }
148
+ return path;
149
+ };
150
+ let seenChartType = false;
151
+ let inHolidaysBlock = false;
152
+ let holidaysBlockIndent = 0;
153
+ let inTagBlock = false;
154
+ let currentTagGroup = null;
155
+ let tagBlockIndent = 0;
156
+ let inEraBlock = false;
157
+ let eraBlockIndent = 0;
158
+ let inMarkerBlock = false;
159
+ let markerBlockIndent = 0;
160
+ let lastTaskNode = null;
161
+ let taskIdCounter = 0;
162
+ const seriesColors = palette ? getSeriesColors(palette) : [];
163
+ const syntaxMode = "new";
164
+ result.syntaxMode = syntaxMode;
165
+ for (let i = 0; i < lines.length; i++) {
166
+ const rawLine = lines[i];
167
+ const line = rawLine.trim();
168
+ const indent = measureIndent(rawLine);
169
+ const lineNumber = i + 1;
170
+ if (!line) {
171
+ if (inHolidaysBlock && indent <= holidaysBlockIndent) {
172
+ inHolidaysBlock = false;
173
+ }
174
+ if (inEraBlock && indent <= eraBlockIndent) {
175
+ inEraBlock = false;
176
+ }
177
+ if (inMarkerBlock && indent <= markerBlockIndent) {
178
+ inMarkerBlock = false;
179
+ }
180
+ if (inTagBlock && indent <= tagBlockIndent) {
181
+ inTagBlock = false;
182
+ if (currentTagGroup) {
183
+ result.tagGroups.push(currentTagGroup);
184
+ currentTagGroup = null;
185
+ }
186
+ }
187
+ continue;
188
+ }
189
+ if (!seenChartType) {
190
+ const firstLineResult = parseFirstLine(line);
191
+ if (firstLineResult) {
192
+ if (firstLineResult.chartType !== "gantt") {
193
+ return fail(
194
+ lineNumber,
195
+ `Expected chart type "gantt", got "${firstLineResult.chartType}"`
196
+ );
197
+ }
198
+ seenChartType = true;
199
+ if (firstLineResult.title) {
200
+ result.options.title = firstLineResult.title;
201
+ result.options.titleLineNumber = lineNumber;
202
+ }
203
+ continue;
204
+ }
205
+ }
206
+ if (inHolidaysBlock) {
207
+ if (indent <= holidaysBlockIndent) {
208
+ inHolidaysBlock = false;
209
+ } else {
210
+ const rangeMatch = line.match(HOLIDAY_RANGE_RE);
211
+ if (rangeMatch) {
212
+ holidays.ranges.push({
213
+ startDate: rangeMatch[1],
214
+ endDate: rangeMatch[2],
215
+ label: rangeMatch[3].trim(),
216
+ lineNumber
217
+ });
218
+ continue;
219
+ }
220
+ const dateMatch = line.match(HOLIDAY_DATE_RE);
221
+ if (dateMatch) {
222
+ holidays.dates.push({
223
+ date: dateMatch[1],
224
+ label: dateMatch[2].trim(),
225
+ lineNumber
226
+ });
227
+ continue;
228
+ }
229
+ const workweekMatch = line.match(WORKWEEK_RE);
230
+ if (workweekMatch) {
231
+ const days = parseWorkweek(workweekMatch[1].trim());
232
+ if (days) {
233
+ holidays.workweek = days;
234
+ } else {
235
+ warn(
236
+ lineNumber,
237
+ `Invalid workweek format: "${workweekMatch[1]}". Use day range like "sun-thu" or comma-separated days.`
238
+ );
239
+ }
240
+ continue;
241
+ }
242
+ if (COMMENT_RE.test(line)) continue;
243
+ warn(
244
+ lineNumber,
245
+ `Unrecognized holiday entry: "${line}". Use a date '2024-02-19 Presidents Day' or a range '2024-05-27 -> 2024-05-29 Memorial Weekend'. (\xA713.3)`
246
+ );
247
+ continue;
248
+ }
249
+ }
250
+ if (inEraBlock) {
251
+ if (indent <= eraBlockIndent) {
252
+ inEraBlock = false;
253
+ } else {
254
+ if (COMMENT_RE.test(line)) continue;
255
+ const eraEntryMatch = line.match(ERA_ENTRY_RE);
256
+ if (eraEntryMatch) {
257
+ const eraLabelRaw = eraEntryMatch[3].trim();
258
+ const eraExtracted = extractColor(
259
+ eraLabelRaw,
260
+ palette,
261
+ diagnostics,
262
+ lineNumber
263
+ );
264
+ result.eras.push({
265
+ startDate: eraEntryMatch[1],
266
+ endDate: eraEntryMatch[2],
267
+ label: eraExtracted.label,
268
+ color: eraExtracted.color || null,
269
+ lineNumber
270
+ });
271
+ } else {
272
+ warn(
273
+ lineNumber,
274
+ `Unrecognized era entry: "${line}". Use 'YYYY-MM-DD -> YYYY-MM-DD Label [color]' (e.g. '2026-04-06 -> 2026-04-10 Conference purple'). (\xA713.5)`
275
+ );
276
+ }
277
+ continue;
278
+ }
279
+ }
280
+ if (inMarkerBlock) {
281
+ if (indent <= markerBlockIndent) {
282
+ inMarkerBlock = false;
283
+ } else {
284
+ if (COMMENT_RE.test(line)) continue;
285
+ const markerEntryMatch = line.match(MARKER_ENTRY_RE);
286
+ if (markerEntryMatch) {
287
+ const markerLabelRaw = markerEntryMatch[2].trim();
288
+ const markerExtracted = extractColor(
289
+ markerLabelRaw,
290
+ palette,
291
+ diagnostics,
292
+ lineNumber
293
+ );
294
+ result.markers.push({
295
+ date: markerEntryMatch[1],
296
+ label: markerExtracted.label,
297
+ color: markerExtracted.color || null,
298
+ lineNumber
299
+ });
300
+ } else {
301
+ warn(
302
+ lineNumber,
303
+ `Unrecognized marker entry: "${line}". Use 'YYYY-MM-DD Label [color]' (e.g. '2026-03-27 Board Review' or '2026-06-15 Release green'). (\xA713.6)`
304
+ );
305
+ }
306
+ continue;
307
+ }
308
+ }
309
+ if (inTagBlock && currentTagGroup) {
310
+ if (indent <= tagBlockIndent) {
311
+ inTagBlock = false;
312
+ result.tagGroups.push(currentTagGroup);
313
+ currentTagGroup = null;
314
+ } else {
315
+ if (COMMENT_RE.test(line)) continue;
316
+ const { text: cleanEntry, isDefault } = stripDefaultModifier(line);
317
+ const extracted = extractColor(
318
+ cleanEntry,
319
+ palette,
320
+ diagnostics,
321
+ lineNumber
322
+ );
323
+ const color = extracted.color || seriesColors[currentTagGroup.entries.length % seriesColors.length] || "#888888";
324
+ const isFirstEntry = currentTagGroup.entries.length === 0;
325
+ currentTagGroup.entries.push({
326
+ value: extracted.label,
327
+ color,
328
+ lineNumber
329
+ });
330
+ if (isDefault) {
331
+ currentTagGroup.defaultValue = extracted.label;
332
+ } else if (isFirstEntry) {
333
+ currentTagGroup.defaultValue = extracted.label;
334
+ }
335
+ continue;
336
+ }
337
+ }
338
+ {
339
+ let hadDeeperPop = false;
340
+ let lastPoppedTaskRef = null;
341
+ while (blockStack.length > 0) {
342
+ const top = blockStack[blockStack.length - 1];
343
+ if (indent <= top.indent) {
344
+ if (top.indent > indent) hadDeeperPop = true;
345
+ if (top.containerType === "task" && top.taskRef) {
346
+ lastPoppedTaskRef = top.taskRef;
347
+ }
348
+ blockStack.pop();
349
+ } else {
350
+ break;
351
+ }
352
+ }
353
+ if (hadDeeperPop) {
354
+ for (let k = blockStack.length - 1; k >= 0; k--) {
355
+ if (blockStack[k].containerType === "task" && blockStack[k].taskRef) {
356
+ lastTaskNode = blockStack[k].taskRef;
357
+ break;
358
+ }
359
+ }
360
+ if (blockStack.length === 0 || !blockStack.some((e) => e.containerType === "task")) {
361
+ lastTaskNode = null;
362
+ }
363
+ } else if (lastPoppedTaskRef) {
364
+ lastTaskNode = lastPoppedTaskRef;
365
+ }
366
+ }
367
+ if (syntaxMode === "new") {
368
+ const arrowResult = matchArrowLine(line);
369
+ if (arrowResult) {
370
+ const content2 = parseNewTaskContent(arrowResult.rest, lineNumber);
371
+ if (content2.duration || content2.explicitStart) {
372
+ const task = makeTask(
373
+ content2.name,
374
+ content2.duration,
375
+ content2.uncertain,
376
+ lineNumber,
377
+ content2.explicitStart,
378
+ content2.preExtracted
379
+ );
380
+ const taskNode = { kind: "task", ...task };
381
+ if (lastTaskNode) {
382
+ lastTaskNode.dependencies.push({
383
+ targetName: content2.name,
384
+ ...arrowResult.label !== void 0 && {
385
+ label: arrowResult.label
386
+ },
387
+ ...arrowResult.lag !== void 0 && { offset: arrowResult.lag },
388
+ lineNumber
389
+ });
390
+ }
391
+ currentContainer().push(taskNode);
392
+ const writableTask = taskNode;
393
+ lastTaskNode = writableTask;
394
+ blockStack.push({
395
+ node: taskNode,
396
+ indent,
397
+ containerType: "task",
398
+ taskRef: writableTask
399
+ });
400
+ } else {
401
+ if (lastTaskNode) {
402
+ const depBody = arrowResult.rest;
403
+ let targetSegment;
404
+ let meta;
405
+ {
406
+ const depRegistry = withTagAliases(
407
+ GANTT_REGISTRY,
408
+ new Set(metaAliasMap.keys())
409
+ );
410
+ const split = splitNameAndMeta(
411
+ depBody.trim(),
412
+ depRegistry,
413
+ metaAliasMap
414
+ );
415
+ warnUnknownMetaKeys(
416
+ split.meta,
417
+ depRegistry,
418
+ (msg) => warn(lineNumber, msg),
419
+ split.name
420
+ );
421
+ targetSegment = split.name;
422
+ meta = split.meta;
423
+ }
424
+ const targetName = resolveAliasTarget(targetSegment);
425
+ let offset = arrowResult.lag;
426
+ if (meta["lag"] || meta["lead"]) {
427
+ const key = meta["lag"] ? "lag" : "lead";
428
+ softError(
429
+ lineNumber,
430
+ `"${key}" is no longer supported \u2014 use "offset: ${meta[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
431
+ );
432
+ }
433
+ if (meta["offset"]) {
434
+ const raw = meta["offset"];
435
+ if (raw.trim().startsWith("+")) {
436
+ warn(
437
+ lineNumber,
438
+ `Invalid offset: "${raw}". Explicit "+" is not supported \u2014 use "${raw.trim().slice(1)}" instead.`
439
+ );
440
+ } else {
441
+ offset = parseOffset(raw) ?? void 0;
442
+ if (!offset) {
443
+ warn(
444
+ lineNumber,
445
+ `Invalid offset: "${raw}". Expected format like "3bd", "-5d", or "0bd".`
446
+ );
447
+ }
448
+ }
449
+ }
450
+ lastTaskNode.dependencies.push({
451
+ targetName,
452
+ ...arrowResult.label !== void 0 && {
453
+ label: arrowResult.label
454
+ },
455
+ ...offset !== void 0 && { offset },
456
+ lineNumber
457
+ });
458
+ } else {
459
+ softError(
460
+ lineNumber,
461
+ `Arrow '-> ${content2.name}' has no source task \u2014 indent it under the task it follows (e.g. 'Design 5bd' then indented '-> ${content2.name} 3bd'). (\xA713)`
462
+ );
463
+ }
464
+ }
465
+ continue;
466
+ }
467
+ if (indent > 0 && lastTaskNode) {
468
+ const colonIdx = line.indexOf(":");
469
+ if (colonIdx > 0) {
470
+ const candidateKey = line.substring(0, colonIdx).trim().toLowerCase();
471
+ const registry = withTagAliases(
472
+ GANTT_REGISTRY,
473
+ new Set(metaAliasMap.keys())
474
+ );
475
+ const resolvedKey = metaAliasMap.get(normalizeName(candidateKey)) ?? candidateKey;
476
+ if (isReservedKey(registry, resolvedKey)) {
477
+ const value = line.substring(colonIdx + 1).trim();
478
+ const ownerTask = findOwningTask(blockStack, indent) ?? lastTaskNode;
479
+ if (ownerTask) {
480
+ const mutableMeta = ownerTask.metadata;
481
+ if (resolvedKey === "progress") {
482
+ const p = parseFloat(value);
483
+ if (!Number.isNaN(p)) {
484
+ ownerTask.progress = p;
485
+ }
486
+ } else if (resolvedKey === "offset") {
487
+ const off = parseOffsetPrefix(value) ?? parseOffset(value);
488
+ if (off) ownerTask.offset = off;
489
+ } else {
490
+ mutableMeta[resolvedKey] = value;
491
+ }
492
+ }
493
+ continue;
494
+ }
495
+ }
496
+ }
497
+ if (lastTaskNode && indent > 0 && COMMENT_RE.test(line)) {
498
+ const commentText = line.replace(/^\/\/\s?/, "");
499
+ lastTaskNode.comment = lastTaskNode.comment ? lastTaskNode.comment + "\n" + commentText : commentText;
500
+ continue;
501
+ }
502
+ if (COMMENT_RE.test(line)) continue;
503
+ const eraOffsetMatch = line.match(ERA_OFFSET_RE);
504
+ if (eraOffsetMatch) {
505
+ const startOff = parseOffsetPrefix("+" + eraOffsetMatch[1]);
506
+ const endOff = parseOffsetPrefix("+" + eraOffsetMatch[2]);
507
+ const eraLabelRaw = eraOffsetMatch[3].trim();
508
+ const eraExtracted = extractColor(
509
+ eraLabelRaw,
510
+ palette,
511
+ diagnostics,
512
+ lineNumber
513
+ );
514
+ result.eras.push({
515
+ startDate: "",
516
+ endDate: "",
517
+ label: eraExtracted.label,
518
+ color: eraExtracted.color || null,
519
+ lineNumber,
520
+ ...startOff && { offsetStart: startOff },
521
+ ...endOff && { offsetEnd: endOff }
522
+ });
523
+ continue;
524
+ }
525
+ const markerOffsetMatch = line.match(MARKER_OFFSET_RE);
526
+ if (markerOffsetMatch) {
527
+ const dateOff = parseOffsetPrefix("+" + markerOffsetMatch[1]);
528
+ const markerLabelRaw = markerOffsetMatch[2].trim();
529
+ const markerExtracted = extractColor(
530
+ markerLabelRaw,
531
+ palette,
532
+ diagnostics,
533
+ lineNumber
534
+ );
535
+ result.markers.push({
536
+ date: "",
537
+ label: markerExtracted.label,
538
+ color: markerExtracted.color || null,
539
+ lineNumber,
540
+ ...dateOff && { offsetDate: dateOff }
541
+ });
542
+ continue;
543
+ }
544
+ }
545
+ if (COMMENT_RE.test(line)) continue;
546
+ if (line.toLowerCase() === "holiday" || line.toLowerCase() === "holidays") {
547
+ inHolidaysBlock = true;
548
+ holidaysBlockIndent = indent;
549
+ result.options.holidaysLineNumber = lineNumber;
550
+ continue;
551
+ }
552
+ const holidayInlineMatch = line.match(
553
+ /^holiday\s+(\d{4}-\d{2}-\d{2})\s+(.+)$/i
554
+ );
555
+ if (holidayInlineMatch) {
556
+ holidays.dates.push({
557
+ date: holidayInlineMatch[1],
558
+ label: holidayInlineMatch[2].trim(),
559
+ lineNumber
560
+ });
561
+ result.options.holidaysLineNumber ??= lineNumber;
562
+ continue;
563
+ }
564
+ const tagMatch = matchTagBlockHeading(line);
565
+ if (tagMatch) {
566
+ inTagBlock = true;
567
+ tagBlockIndent = indent;
568
+ currentTagGroup = {
569
+ name: tagMatch.name,
570
+ ...tagMatch.alias !== void 0 && { alias: tagMatch.alias },
571
+ entries: [],
572
+ lineNumber
573
+ };
574
+ if (tagMatch.alias) {
575
+ metaAliasMap.set(
576
+ normalizeName(tagMatch.alias),
577
+ tagAttrKey(tagMatch.name)
578
+ );
579
+ }
580
+ metaAliasMap.set(normalizeName(tagMatch.name), tagAttrKey(tagMatch.name));
581
+ continue;
582
+ }
583
+ const topWorkweekMatch = line.match(WORKWEEK_RE);
584
+ if (topWorkweekMatch) {
585
+ const days = parseWorkweek(topWorkweekMatch[1].trim());
586
+ if (days) {
587
+ holidays.workweek = days;
588
+ } else {
589
+ warn(
590
+ lineNumber,
591
+ `Invalid workweek format: "${topWorkweekMatch[1]}". Use day range like "sun-thu" or comma-separated days.`
592
+ );
593
+ }
594
+ continue;
595
+ }
596
+ if (line.toLowerCase() === "era") {
597
+ inEraBlock = true;
598
+ eraBlockIndent = indent;
599
+ continue;
600
+ }
601
+ const eraMatch = line.match(ERA_RE);
602
+ if (eraMatch) {
603
+ const eraLabelRaw = eraMatch[3].trim();
604
+ const eraExtracted = extractColor(
605
+ eraLabelRaw,
606
+ palette,
607
+ diagnostics,
608
+ lineNumber
609
+ );
610
+ result.eras.push({
611
+ startDate: eraMatch[1],
612
+ endDate: eraMatch[2],
613
+ label: eraExtracted.label,
614
+ color: eraExtracted.color || null,
615
+ lineNumber
616
+ });
617
+ continue;
618
+ }
619
+ if (line.toLowerCase() === "marker") {
620
+ inMarkerBlock = true;
621
+ markerBlockIndent = indent;
622
+ continue;
623
+ }
624
+ const markerMatch = line.match(MARKER_RE);
625
+ if (markerMatch) {
626
+ const markerLabelRaw = markerMatch[2].trim();
627
+ const markerExtracted = extractColor(
628
+ markerLabelRaw,
629
+ palette,
630
+ diagnostics,
631
+ lineNumber
632
+ );
633
+ result.markers.push({
634
+ date: markerMatch[1],
635
+ label: markerExtracted.label,
636
+ color: markerExtracted.color || null,
637
+ lineNumber
638
+ });
639
+ continue;
640
+ }
641
+ {
642
+ const registry = withTagAliases(
643
+ GANTT_REGISTRY,
644
+ new Set(metaAliasMap.keys())
645
+ );
646
+ const split = splitNameAndMeta(
647
+ line,
648
+ registry,
649
+ metaAliasMap,
650
+ void 0,
651
+ diagnostics,
652
+ lineNumber
653
+ );
654
+ warnUnknownMetaKeys(
655
+ split.meta,
656
+ registry,
657
+ (msg) => warn(lineNumber, msg),
658
+ split.name
659
+ );
660
+ const rawDur = split.meta["duration"];
661
+ const rawStart = split.meta["start"];
662
+ if (rawDur !== void 0 || rawStart !== void 0) {
663
+ let duration = null;
664
+ let uncertain = false;
665
+ if (rawDur !== void 0) {
666
+ const uncertainMatch = rawDur.match(/^(.+)\?$/);
667
+ const durStr = uncertainMatch ? uncertainMatch[1] : rawDur;
668
+ if (uncertainMatch) uncertain = true;
669
+ duration = parseDuration(durStr);
670
+ if (!duration) {
671
+ softError(
672
+ lineNumber,
673
+ `Invalid duration: "${rawDur}". Expected format like "30bd", "5d", "1.5w".`
674
+ );
675
+ continue;
676
+ }
677
+ }
678
+ let explicitStart;
679
+ if (rawStart !== void 0) {
680
+ if (!/^\d{4}-\d{2}-\d{2}(?: \d{2}:\d{2})?$/.test(rawStart)) {
681
+ softError(
682
+ lineNumber,
683
+ `Invalid start date: "${rawStart}". Expected YYYY-MM-DD or YYYY-MM-DD HH:MM.`
684
+ );
685
+ continue;
686
+ }
687
+ explicitStart = rawStart;
688
+ }
689
+ const taskName = split.name.trim();
690
+ if (!taskName) {
691
+ softError(lineNumber, `Task name cannot be empty.`);
692
+ continue;
693
+ }
694
+ if (split.alias) nameAliasMap.set(split.alias, taskName);
695
+ const preExtracted = { ...split.meta };
696
+ delete preExtracted["duration"];
697
+ delete preExtracted["start"];
698
+ if (split.color) preExtracted["color"] = split.color;
699
+ const task = makeTask(
700
+ taskName,
701
+ duration,
702
+ uncertain,
703
+ lineNumber,
704
+ explicitStart,
705
+ preExtracted
706
+ );
707
+ const taskNode = { kind: "task", ...task };
708
+ currentContainer().push(taskNode);
709
+ const writableTaskN = taskNode;
710
+ lastTaskNode = writableTaskN;
711
+ blockStack.push({
712
+ node: taskNode,
713
+ indent,
714
+ containerType: "task",
715
+ taskRef: writableTaskN
716
+ });
717
+ continue;
718
+ }
719
+ }
720
+ const optNoColonMatch = line.match(/^([a-z][a-z0-9-]*)\s+(.+)$/i);
721
+ const bareKeyword = line.match(/^([a-z][a-z0-9-]*)$/i);
722
+ if (bareKeyword && KNOWN_BOOLEANS.has(bareKeyword[1].toLowerCase())) {
723
+ const key = bareKeyword[1].toLowerCase();
724
+ result.options.optionLineNumbers[key] = lineNumber;
725
+ switch (key) {
726
+ case "critical-path":
727
+ result.options.criticalPath = true;
728
+ break;
729
+ case "today-marker":
730
+ result.options.todayMarker = "on";
731
+ break;
732
+ case "solid-fill":
733
+ result.options.solidFill = true;
734
+ break;
735
+ case "no-title":
736
+ result.options.noTitle = true;
737
+ break;
738
+ }
739
+ continue;
740
+ }
741
+ if (bareKeyword && bareKeyword[1].toLowerCase().startsWith("no-")) {
742
+ const base = bareKeyword[1].toLowerCase().substring(3);
743
+ if (KNOWN_BOOLEANS.has(base)) {
744
+ result.options.optionLineNumbers[base] = lineNumber;
745
+ switch (base) {
746
+ case "dependencies":
747
+ result.options.dependencies = false;
748
+ break;
749
+ case "critical-path":
750
+ result.options.criticalPath = false;
751
+ break;
752
+ case "today-marker":
753
+ result.options.todayMarker = "off";
754
+ break;
755
+ }
756
+ continue;
757
+ }
758
+ }
759
+ if (optNoColonMatch && isKnownOption(optNoColonMatch[1].toLowerCase())) {
760
+ const key = optNoColonMatch[1].toLowerCase();
761
+ const value = optNoColonMatch[2].trim();
762
+ result.options.optionLineNumbers[key] = lineNumber;
763
+ switch (key) {
764
+ case "start":
765
+ result.options.start = value;
766
+ break;
767
+ case "title":
768
+ result.options.title = value;
769
+ result.options.titleLineNumber = lineNumber;
770
+ break;
771
+ case "today-marker":
772
+ if (/^\d{4}-\d{2}-\d{2}(?: \d{2}:\d{2})?$/.test(value)) {
773
+ result.options.todayMarker = value;
774
+ } else {
775
+ warn(
776
+ lineNumber,
777
+ `Invalid today-marker value: "${value}". Expected YYYY-MM-DD.`
778
+ );
779
+ }
780
+ break;
781
+ case "critical-path":
782
+ result.options.criticalPath = true;
783
+ break;
784
+ case "dependencies":
785
+ result.options.dependencies = true;
786
+ break;
787
+ case "sort":
788
+ if (value === "tag" || value.startsWith("tag:")) {
789
+ result.options.sort = "tag";
790
+ const colonIdx = value.indexOf(":");
791
+ if (colonIdx !== -1) {
792
+ result.options.defaultSwimlaneGroup = value.slice(colonIdx + 1).trim() || null;
793
+ }
794
+ } else {
795
+ warn(
796
+ lineNumber,
797
+ `Invalid sort value: "${value}". Expected "tag" or "tag:GroupName".`
798
+ );
799
+ }
800
+ break;
801
+ // `lane-by <group>`: the canonical swimlane-axis directive (view-state).
802
+ // Equivalent to `sort: tag:<group>` — enables tag swimlanes on the named
803
+ // group. `sort tag` remains a back-compat spelling.
804
+ case "lane-by":
805
+ result.options.sort = "tag";
806
+ result.options.defaultSwimlaneGroup = value.trim() || null;
807
+ break;
808
+ case "active-tag":
809
+ result.options.activeTag = value;
810
+ break;
811
+ case "sprint-length": {
812
+ const dur = parseDuration(value);
813
+ if (!dur) {
814
+ warn(
815
+ lineNumber,
816
+ `Invalid sprint-length value: "${value}". Expected a duration like "2w" or "10d".`
817
+ );
818
+ } else if (dur.unit !== "d" && dur.unit !== "w") {
819
+ warn(
820
+ lineNumber,
821
+ `sprint-length only accepts "d" or "w" units, got "${dur.unit}".`
822
+ );
823
+ } else if (dur.amount <= 0) {
824
+ warn(lineNumber, `sprint-length must be greater than 0.`);
825
+ } else if (!Number.isInteger(dur.amount * (dur.unit === "w" ? 7 : 1))) {
826
+ warn(
827
+ lineNumber,
828
+ `sprint-length must resolve to a whole number of days.`
829
+ );
830
+ } else {
831
+ result.options.sprintLength = dur;
832
+ }
833
+ break;
834
+ }
835
+ case "sprint-number": {
836
+ const n = Number(value);
837
+ if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
838
+ warn(
839
+ lineNumber,
840
+ `sprint-number must be a positive integer, got "${value}".`
841
+ );
842
+ } else {
843
+ result.options.sprintNumber = n;
844
+ }
845
+ break;
846
+ }
847
+ case "sprint-start": {
848
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
849
+ warn(
850
+ lineNumber,
851
+ `sprint-start requires a full date (YYYY-MM-DD), got "${value}".`
852
+ );
853
+ } else if (Number.isNaN((/* @__PURE__ */ new Date(value + "T00:00:00")).getTime())) {
854
+ warn(lineNumber, `sprint-start is not a valid date: "${value}".`);
855
+ } else {
856
+ result.options.sprintStart = value;
857
+ }
858
+ break;
859
+ }
860
+ }
861
+ continue;
862
+ }
863
+ if (syntaxMode === "new") {
864
+ let restAfterOffset = line;
865
+ let lineOffset;
866
+ const offMatch = line.match(OFFSET_PREFIX_RE);
867
+ if (offMatch) {
868
+ lineOffset = parseOffsetPrefix("+" + offMatch[1]) ?? void 0;
869
+ restAfterOffset = offMatch[2];
870
+ }
871
+ const gm = restAfterOffset.match(GROUP_RE);
872
+ if (gm) {
873
+ if (blockStack.length > 0 && blockStack[blockStack.length - 1].containerType === "task") {
874
+ softError(
875
+ lineNumber,
876
+ `Cannot nest a group inside a task. Groups must be inside other groups.`
877
+ );
878
+ continue;
879
+ }
880
+ const afterBrackets = gm[2].trim();
881
+ let metadata = {};
882
+ if (afterBrackets) {
883
+ const groupRegistry = withTagAliases(
884
+ GANTT_REGISTRY,
885
+ new Set(metaAliasMap.keys())
886
+ );
887
+ const split = splitNameAndMeta(
888
+ `_ ${afterBrackets}`,
889
+ groupRegistry,
890
+ metaAliasMap,
891
+ void 0,
892
+ result.diagnostics,
893
+ lineNumber
894
+ );
895
+ warnUnknownMetaKeys(
896
+ split.meta,
897
+ groupRegistry,
898
+ (msg) => warn(lineNumber, msg),
899
+ split.name
900
+ );
901
+ metadata = split.meta;
902
+ }
903
+ let collapsed = false;
904
+ if (metadata["collapsed"]?.toLowerCase() === "true") {
905
+ collapsed = true;
906
+ delete metadata["collapsed"];
907
+ }
908
+ const groupPeeled = peelAlias(gm[1]);
909
+ if (groupPeeled.alias)
910
+ nameAliasMap.set(groupPeeled.alias, groupPeeled.label);
911
+ const group = {
912
+ name: groupPeeled.label,
913
+ color: null,
914
+ metadata,
915
+ ...lineOffset && { offset: lineOffset },
916
+ ...collapsed && { collapsed: true },
917
+ lineNumber,
918
+ children: []
919
+ };
920
+ const groupNode = { kind: "group", ...group };
921
+ currentContainer().push(groupNode);
922
+ blockStack.push({
923
+ node: groupNode,
924
+ indent,
925
+ containerType: "group"
926
+ });
927
+ lastTaskNode = null;
928
+ continue;
929
+ }
930
+ {
931
+ const content2 = parseNewTaskContent(restAfterOffset, lineNumber);
932
+ if (content2.name && !content2.duration && !content2.explicitStart && !lineOffset) {
933
+ softError(
934
+ lineNumber,
935
+ `Expected task with duration/start (e.g., "${content2.name} 5d"), group brackets (e.g., "[Group]"), or keyword. Got: "${line}"`
936
+ );
937
+ continue;
938
+ }
939
+ if (content2.name || content2.duration || content2.explicitStart) {
940
+ const task = makeTask(
941
+ content2.name,
942
+ content2.duration,
943
+ content2.uncertain,
944
+ lineNumber,
945
+ content2.explicitStart,
946
+ content2.preExtracted
947
+ );
948
+ if (lineOffset) {
949
+ task.offset = lineOffset;
950
+ }
951
+ const taskNode = { kind: "task", ...task };
952
+ currentContainer().push(taskNode);
953
+ const writableTask = taskNode;
954
+ lastTaskNode = writableTask;
955
+ blockStack.push({
956
+ node: taskNode,
957
+ indent,
958
+ containerType: "task",
959
+ taskRef: writableTask
960
+ });
961
+ continue;
962
+ }
963
+ }
964
+ softError(
965
+ lineNumber,
966
+ `Expected task (e.g., "Task Name 5d"), arrow (e.g., "-> Task 3w"), group (e.g., "[Group]"), or directive. Got: "${line}"`
967
+ );
968
+ continue;
969
+ }
970
+ }
971
+ if (currentTagGroup) {
972
+ result.tagGroups.push(currentTagGroup);
973
+ }
974
+ if (result.options.sort === "tag" && result.tagGroups.length === 0) {
975
+ warn(0, "sort tag has no effect \u2014 no tag groups defined.");
976
+ result.options.sort = "default";
977
+ }
978
+ validateTagGroupNames(result.tagGroups, warn, (line, msg) => {
979
+ const diag = makeDgmoError(line, msg);
980
+ diagnostics.push(diag);
981
+ if (!result.error) result.error = formatDgmoError(diag);
982
+ });
983
+ const hasSprintOption = result.options.sprintLength !== null || result.options.sprintNumber !== null || result.options.sprintStart !== null;
984
+ const hasSprintUnit = hasSprintDurationUnit(result.nodes);
985
+ if (hasSprintOption) {
986
+ result.options.sprintMode = "explicit";
987
+ } else if (hasSprintUnit) {
988
+ result.options.sprintMode = "auto";
989
+ }
990
+ if (result.options.sprintMode) {
991
+ if (!result.options.sprintLength) {
992
+ result.options.sprintLength = { amount: 2, unit: "w" };
993
+ }
994
+ if (result.options.sprintNumber === null) {
995
+ result.options.sprintNumber = 1;
996
+ }
997
+ }
998
+ return result;
999
+ function matchArrowLine(trimmedLine) {
1000
+ const leadMatch = trimmedLine.match(LEAD_ARROW_RE);
1001
+ if (leadMatch) {
1002
+ const dur = parseDuration(leadMatch[1]);
1003
+ const match = { rest: leadMatch[2] };
1004
+ if (dur) match.lag = { duration: dur, direction: -1 };
1005
+ return match;
1006
+ }
1007
+ const lagMatch = trimmedLine.match(LAG_ARROW_RE);
1008
+ if (lagMatch) {
1009
+ const dur = parseDuration(lagMatch[1]);
1010
+ const match = { rest: lagMatch[2] };
1011
+ if (dur) match.lag = { duration: dur, direction: 1 };
1012
+ return match;
1013
+ }
1014
+ const basicMatch = trimmedLine.match(BASIC_ARROW_RE);
1015
+ if (basicMatch) {
1016
+ return { rest: basicMatch[1] };
1017
+ }
1018
+ const labeledMatch = trimmedLine.match(DEPENDENCY_RE);
1019
+ if (labeledMatch?.[1]) {
1020
+ return { rest: labeledMatch[2], label: labeledMatch[1].trim() };
1021
+ }
1022
+ return null;
1023
+ }
1024
+ function parseNewTaskContent(rawContent, ln) {
1025
+ const registry = withTagAliases(
1026
+ GANTT_REGISTRY,
1027
+ new Set(metaAliasMap.keys())
1028
+ );
1029
+ const split = splitNameAndMeta(
1030
+ rawContent,
1031
+ registry,
1032
+ metaAliasMap,
1033
+ void 0,
1034
+ diagnostics,
1035
+ ln
1036
+ );
1037
+ warnUnknownMetaKeys(
1038
+ split.meta,
1039
+ registry,
1040
+ (msg) => warn(ln, msg),
1041
+ split.name
1042
+ );
1043
+ let name = split.name;
1044
+ let duration = null;
1045
+ let uncertain = false;
1046
+ let explicitStart;
1047
+ const metadata = { ...split.meta };
1048
+ if (metadata["duration"]) {
1049
+ const durStr = metadata["duration"];
1050
+ const uncertainMatch = durStr.match(/^(.+)\?$/);
1051
+ const cleanDur = uncertainMatch ? uncertainMatch[1] : durStr;
1052
+ if (uncertainMatch) uncertain = true;
1053
+ duration = parseDuration(cleanDur);
1054
+ if (!duration) {
1055
+ softError(
1056
+ ln,
1057
+ `Invalid duration: "${durStr}". Expected format like "30bd", "5d", "1.5w".`
1058
+ );
1059
+ }
1060
+ delete metadata["duration"];
1061
+ }
1062
+ if (metadata["start"]) {
1063
+ const raw = metadata["start"];
1064
+ if (!/^\d{4}-\d{2}-\d{2}(?: \d{2}:\d{2})?$/.test(raw)) {
1065
+ softError(ln, `Invalid start date: "${raw}". Expected YYYY-MM-DD.`);
1066
+ } else {
1067
+ explicitStart = raw;
1068
+ }
1069
+ delete metadata["start"];
1070
+ }
1071
+ if (!duration && !explicitStart) {
1072
+ const tokens = name.split(/\s+/).filter(Boolean);
1073
+ for (let j = tokens.length - 1; j >= 0; j--) {
1074
+ const m = tokens[j].match(DURATION_TOKEN_RE);
1075
+ if (m) {
1076
+ duration = { amount: parseFloat(m[1]), unit: m[2] };
1077
+ uncertain = !!m[3];
1078
+ name = tokens.slice(0, j).join(" ");
1079
+ break;
1080
+ }
1081
+ }
1082
+ }
1083
+ const preExtracted = { ...metadata };
1084
+ if (split.color) preExtracted["color"] = split.color;
1085
+ return {
1086
+ name: name.trim(),
1087
+ duration,
1088
+ uncertain,
1089
+ explicitStart,
1090
+ preExtracted
1091
+ };
1092
+ }
1093
+ function findOwningTask(stack, metaIndent) {
1094
+ for (let k = stack.length - 1; k >= 0; k--) {
1095
+ const entry = stack[k];
1096
+ if (entry.containerType === "task" && entry.taskRef && entry.indent < metaIndent) {
1097
+ return entry.taskRef;
1098
+ }
1099
+ }
1100
+ return null;
1101
+ }
1102
+ function makeTask(labelRaw, duration, uncertain, ln, explicitStart, preExtractedMeta) {
1103
+ const peeled = peelAlias(labelRaw);
1104
+ let label = peeled.label;
1105
+ if (peeled.alias) nameAliasMap.set(peeled.alias, label);
1106
+ if (label.toLowerCase() === "parallel") {
1107
+ softError(
1108
+ ln,
1109
+ `"parallel" is a reserved keyword and cannot be used as a task name.`
1110
+ );
1111
+ }
1112
+ const metadata = {};
1113
+ {
1114
+ const registry = withTagAliases(
1115
+ GANTT_REGISTRY,
1116
+ new Set(metaAliasMap.keys())
1117
+ );
1118
+ const split = splitNameAndMeta(
1119
+ label,
1120
+ registry,
1121
+ metaAliasMap,
1122
+ void 0,
1123
+ result.diagnostics,
1124
+ ln
1125
+ );
1126
+ warnUnknownMetaKeys(
1127
+ split.meta,
1128
+ registry,
1129
+ (msg) => warn(ln, msg),
1130
+ split.name
1131
+ );
1132
+ if (Object.keys(split.meta).length > 0) {
1133
+ label = split.name;
1134
+ Object.assign(metadata, split.meta);
1135
+ }
1136
+ }
1137
+ if (preExtractedMeta) {
1138
+ Object.assign(metadata, preExtractedMeta);
1139
+ }
1140
+ let progress = null;
1141
+ if (metadata["progress"]) {
1142
+ progress = parseFloat(metadata["progress"]);
1143
+ delete metadata["progress"];
1144
+ }
1145
+ if (metadata["lag"] || metadata["lead"]) {
1146
+ const key = metadata["lag"] ? "lag" : "lead";
1147
+ softError(
1148
+ ln,
1149
+ `"${key}" is no longer supported \u2014 use "offset: ${metadata[key]}" instead.${key === "lead" ? ' Negate the value for lead behavior: "offset: -...".' : ""}`
1150
+ );
1151
+ }
1152
+ let taskOffset;
1153
+ if (metadata["offset"]) {
1154
+ const raw = metadata["offset"];
1155
+ if (raw.trim().startsWith("+")) {
1156
+ warn(
1157
+ ln,
1158
+ `Invalid offset: "${raw}". Explicit "+" is not supported \u2014 use "${raw.trim().slice(1)}" instead.`
1159
+ );
1160
+ } else {
1161
+ taskOffset = parseOffset(raw) ?? void 0;
1162
+ if (!taskOffset) {
1163
+ warn(
1164
+ ln,
1165
+ `Invalid offset: "${raw}". Expected format like "3bd", "-5d", or "0bd".`
1166
+ );
1167
+ }
1168
+ }
1169
+ delete metadata["offset"];
1170
+ }
1171
+ const groupPath = currentGroupPath();
1172
+ const inheritedMeta = {};
1173
+ for (const entry of blockStack) {
1174
+ if (entry.containerType === "group") {
1175
+ const groupNode = entry.node;
1176
+ Object.assign(inheritedMeta, groupNode.metadata);
1177
+ }
1178
+ }
1179
+ const effectiveMetadata = { ...inheritedMeta, ...metadata };
1180
+ const id = `task_${taskIdCounter++}`;
1181
+ return {
1182
+ id,
1183
+ label,
1184
+ duration,
1185
+ ...explicitStart !== void 0 && { explicitStart },
1186
+ uncertain,
1187
+ progress,
1188
+ ...taskOffset !== void 0 && { offset: taskOffset },
1189
+ isDefinition: duration !== null || explicitStart !== void 0,
1190
+ dependencies: [],
1191
+ metadata: effectiveMetadata,
1192
+ lineNumber: ln,
1193
+ groupPath
1194
+ };
1195
+ }
1196
+ }
1197
+ function parseWorkweek(s) {
1198
+ const rangeParts = s.toLowerCase().split("-");
1199
+ if (rangeParts.length === 2) {
1200
+ const start = WEEKDAY_MAP[rangeParts[0].trim()];
1201
+ const end = WEEKDAY_MAP[rangeParts[1].trim()];
1202
+ if (start && end) {
1203
+ const allDays = [
1204
+ "mon",
1205
+ "tue",
1206
+ "wed",
1207
+ "thu",
1208
+ "fri",
1209
+ "sat",
1210
+ "sun"
1211
+ ];
1212
+ const startIdx = allDays.indexOf(start);
1213
+ const endIdx = allDays.indexOf(end);
1214
+ const days2 = [];
1215
+ let idx = startIdx;
1216
+ while (true) {
1217
+ days2.push(allDays[idx]);
1218
+ if (idx === endIdx) break;
1219
+ idx = (idx + 1) % 7;
1220
+ }
1221
+ return days2;
1222
+ }
1223
+ }
1224
+ const parts = s.toLowerCase().split(",").map((p) => p.trim());
1225
+ const days = [];
1226
+ for (const part of parts) {
1227
+ const day = WEEKDAY_MAP[part];
1228
+ if (!day) return null;
1229
+ days.push(day);
1230
+ }
1231
+ return days.length > 0 ? days : null;
1232
+ }
1233
+ var GANTT_KNOWN_OPTIONS = GANTT_OPTION_SET;
1234
+ var KNOWN_OPTIONS = GANTT_KNOWN_OPTIONS;
1235
+ var GANTT_KNOWN_BOOLEANS = GANTT_BOOLEAN_SET;
1236
+ var KNOWN_BOOLEANS = GANTT_KNOWN_BOOLEANS;
1237
+ function isKnownOption(key) {
1238
+ return KNOWN_OPTIONS.has(key);
1239
+ }
1240
+ function hasSprintDurationUnit(nodes) {
1241
+ for (const node of nodes) {
1242
+ if (node.kind === "task") {
1243
+ if (node.duration?.unit === "s") return true;
1244
+ } else if (node.kind === "group" || node.kind === "parallel") {
1245
+ if (hasSprintDurationUnit(node.children)) return true;
1246
+ }
1247
+ }
1248
+ return false;
1249
+ }
1250
+
1251
+ export {
1252
+ parseGantt,
1253
+ GANTT_KNOWN_OPTIONS,
1254
+ GANTT_KNOWN_BOOLEANS
1255
+ };
1256
+ //# sourceMappingURL=chunk-XAKEUMEJ.js.map