@diagrammo/dgmo 0.48.2 → 0.50.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 (244) hide show
  1. package/.cursorrules +12 -3
  2. package/.github/copilot-instructions.md +12 -3
  3. package/.windsurfrules +12 -3
  4. package/SKILL.md +12 -3
  5. package/dist/advanced.d.ts +851 -1
  6. package/dist/advanced.js +601 -177
  7. package/dist/auto.css +63 -0
  8. package/dist/auto.js +220 -110
  9. package/dist/auto.mjs +45920 -33167
  10. package/dist/block.css +63 -0
  11. package/dist/block.d.ts +13 -5
  12. package/dist/block.js +239 -62
  13. package/dist/{charts-d3-QOZHKTCT.js → charts-d3-DKUD7MQE.js} +9 -8
  14. package/dist/{chunk-3MQQNXPD.js → chunk-2C56LEML.js} +3 -3
  15. package/dist/{chunk-L66GEFB6.js → chunk-2JJ2KNPI.js} +4 -4
  16. package/dist/{chunk-6SM5NJQH.js → chunk-2QYTMIRR.js} +4 -4
  17. package/dist/{chunk-RJE5JTVK.js → chunk-3G6TMNVF.js} +7 -7
  18. package/dist/{chunk-MO5YHHMQ.js → chunk-3LKM6FMW.js} +2 -2
  19. package/dist/{chunk-76OWZ3BA.js → chunk-3P2DKJCG.js} +2 -2
  20. package/dist/chunk-3TDRHT4J.js +1043 -0
  21. package/dist/chunk-3XPUDB7B.js +420 -0
  22. package/dist/{chunk-2LACINWN.js → chunk-3ZPC476N.js} +7 -7
  23. package/dist/{chunk-G2H74XJZ.js → chunk-4BMJQFNK.js} +8 -8
  24. package/dist/{chunk-THXCFRTU.js → chunk-4S723I74.js} +9 -9
  25. package/dist/{chunk-6NYWYNBI.js → chunk-4XK3FLFB.js} +3 -3
  26. package/dist/chunk-5JSWBPZZ.js +607 -0
  27. package/dist/{chunk-WCT3NYCV.js → chunk-5LWQH6QV.js} +1 -1
  28. package/dist/{chunk-7DTWEFUE.js → chunk-5Z736BSU.js} +8 -8
  29. package/dist/{chunk-ERLBPDGU.js → chunk-6BFZKBGD.js} +2 -2
  30. package/dist/{chunk-6HO5ZTXK.js → chunk-6IAA2QQ2.js} +2 -2
  31. package/dist/{chunk-H6PI3KJT.js → chunk-6IUAK7RZ.js} +2 -2
  32. package/dist/{chunk-RTLBSQ3G.js → chunk-6M5PJFQG.js} +3 -3
  33. package/dist/{chunk-Z5CGSFJB.js → chunk-6X4AKWLF.js} +4 -4
  34. package/dist/{chunk-OJR3MQYV.js → chunk-6ZT4U37Q.js} +291 -52
  35. package/dist/{chunk-5QXL4NYS.js → chunk-7G2ER4CY.js} +10 -5
  36. package/dist/chunk-7PQYTZMA.js +681 -0
  37. package/dist/{chunk-OURHMODR.js → chunk-7RB5Q6MB.js} +11 -11
  38. package/dist/{chunk-YAA6IID3.js → chunk-7UEMZREK.js} +2 -2
  39. package/dist/{chunk-AN2MOO5T.js → chunk-A3WQVFBS.js} +3 -3
  40. package/dist/{chunk-VOKGH627.js → chunk-AHGF2YYA.js} +13 -3
  41. package/dist/{chunk-CI2G3OEB.js → chunk-ASS5YYIZ.js} +12 -12
  42. package/dist/{chunk-TYS6CSS5.js → chunk-BCYVE3N5.js} +2 -2
  43. package/dist/chunk-BDXC7MDK.js +2395 -0
  44. package/dist/chunk-BTUTZMPT.js +482 -0
  45. package/dist/{chunk-YGJTDXVR.js → chunk-C4GQDB5L.js} +2 -2
  46. package/dist/{chunk-Y2ZE3MSG.js → chunk-C63UWAKM.js} +2 -2
  47. package/dist/{chunk-725LDASD.js → chunk-CLD2OKV7.js} +2 -2
  48. package/dist/{chunk-WBRZJOEC.js → chunk-CMCR5WBW.js} +3 -3
  49. package/dist/{chunk-IZMRON6C.js → chunk-CVV36CWI.js} +2 -2
  50. package/dist/chunk-DMJJ3CEQ.js +254 -0
  51. package/dist/{chunk-MZSBFAPJ.js → chunk-EJTKV7CY.js} +9 -9
  52. package/dist/{chunk-FITOLXSX.js → chunk-EOFPYPAU.js} +26 -2
  53. package/dist/{chunk-X5LCYCL5.js → chunk-ER5SCQWQ.js} +5 -5
  54. package/dist/{chunk-4OHACBGX.js → chunk-F2L5GCQ4.js} +2 -2
  55. package/dist/{chunk-FCIIHT24.js → chunk-F5UDBSJY.js} +7 -7
  56. package/dist/{chunk-3JLKYGBQ.js → chunk-F7BFXWNQ.js} +2 -2
  57. package/dist/{chunk-FANX6UJR.js → chunk-FAL7NOK3.js} +11 -11
  58. package/dist/{chunk-BUPDIHML.js → chunk-FB2WHOEQ.js} +4 -4
  59. package/dist/chunk-FL4IOQ37.js +379 -0
  60. package/dist/{chunk-LIOHW36Z.js → chunk-GBE54KY6.js} +6 -5
  61. package/dist/{chunk-RUNNI6VE.js → chunk-GL5UZ6NY.js} +3 -3
  62. package/dist/{chunk-4GRI7MEB.js → chunk-GPWHQ5FJ.js} +6 -6
  63. package/dist/chunk-GROQGHCT.js +960 -0
  64. package/dist/{chunk-SGZYXELT.js → chunk-H73FP42Q.js} +9 -6
  65. package/dist/{chunk-PBAHEPLQ.js → chunk-HGN652MU.js} +7 -6
  66. package/dist/{chunk-3SMGIJDD.js → chunk-HHXOONLX.js} +13 -1
  67. package/dist/{chunk-QOOUC2J5.js → chunk-HQCHYB5F.js} +2 -2
  68. package/dist/{chunk-AELOBFW5.js → chunk-I4IFRCUB.js} +3 -3
  69. package/dist/{chunk-GMR5MFHJ.js → chunk-I7F2A35O.js} +2 -2
  70. package/dist/{chunk-T2OE3YQB.js → chunk-IA3FJYWR.js} +3 -3
  71. package/dist/chunk-IAEC4KLA.js +492 -0
  72. package/dist/chunk-IVKC4GID.js +32 -0
  73. package/dist/{chunk-HSH73DP6.js → chunk-JFYIP7XU.js} +139 -39
  74. package/dist/{chunk-CKNVO24D.js → chunk-JZNMXEIV.js} +2 -2
  75. package/dist/chunk-KJXIHOVL.js +940 -0
  76. package/dist/chunk-L2ZTFHAY.js +331 -0
  77. package/dist/{chunk-B7JUCQUA.js → chunk-M5RXSRO2.js} +4 -4
  78. package/dist/{chunk-ULOEATBZ.js → chunk-NFFIKVNO.js} +106 -29
  79. package/dist/{chunk-PZMETGLY.js → chunk-NISQC5KW.js} +358 -122
  80. package/dist/chunk-O4VUFXIH.js +574 -0
  81. package/dist/{chunk-RVMRZAPB.js → chunk-O76UD6VJ.js} +3 -3
  82. package/dist/{chunk-JM4LEPY3.js → chunk-O7NUCTFU.js} +2 -2
  83. package/dist/{chunk-JED6ZDEE.js → chunk-O7WP4ZD4.js} +2 -2
  84. package/dist/{chunk-EVCVDTXE.js → chunk-OHQEMBLI.js} +3 -3
  85. package/dist/{chunk-ZBWMSD5N.js → chunk-ONA5KPV3.js} +4 -4
  86. package/dist/{chunk-Y3J7VR52.js → chunk-OTAL43EH.js} +34 -2
  87. package/dist/{chunk-WCSOJFU3.js → chunk-OTP5KVLO.js} +3 -3
  88. package/dist/{chunk-RYEGFMUO.js → chunk-PGEGPSCZ.js} +2 -2
  89. package/dist/{chunk-ZO27FGJS.js → chunk-PH5X4GIP.js} +2 -2
  90. package/dist/{chunk-ZJEL4H2R.js → chunk-PJUGRJHJ.js} +9 -9
  91. package/dist/{chunk-ZGR7ULFJ.js → chunk-PLZI6KPM.js} +26 -14
  92. package/dist/{chunk-3R5POCTZ.js → chunk-PMN3Q7RJ.js} +6 -6
  93. package/dist/{chunk-YGJZWZTY.js → chunk-PZFVK3IH.js} +2 -2
  94. package/dist/chunk-Q4V4XQWV.js +158 -0
  95. package/dist/chunk-QDFNCATJ.js +325 -0
  96. package/dist/{chunk-QEBUY5NY.js → chunk-QFQ35BTO.js} +4 -4
  97. package/dist/chunk-QQJUTGQH.js +135 -0
  98. package/dist/{chunk-PWIHZ6NJ.js → chunk-QUJGFNFN.js} +4 -4
  99. package/dist/{chunk-J5FIXQRT.js → chunk-R56LASIN.js} +4 -4
  100. package/dist/{chunk-SRTU6HMQ.js → chunk-RV26LTUU.js} +8 -8
  101. package/dist/chunk-RV6A2B5S.js +354 -0
  102. package/dist/{chunk-EB6FPQUP.js → chunk-S5GRONXL.js} +3 -3
  103. package/dist/{chunk-5MLYVTYM.js → chunk-SCHXJTZL.js} +2 -2
  104. package/dist/{chunk-T3UBLACL.js → chunk-SCQ5VPUF.js} +19 -5
  105. package/dist/{chunk-PBHE5UG6.js → chunk-SGFZZAUO.js} +46 -12
  106. package/dist/{chunk-BUVJFRPY.js → chunk-SU2VBK4L.js} +4 -4
  107. package/dist/{chunk-SML67VPV.js → chunk-T4BRO3Z6.js} +3 -3
  108. package/dist/{chunk-NURGB5Z4.js → chunk-TSA237IM.js} +2 -2
  109. package/dist/chunk-TWCLK2GA.js +273 -0
  110. package/dist/{chunk-IJZFN3HM.js → chunk-TWQUYVP3.js} +4 -4
  111. package/dist/{chunk-DKEPS5LH.js → chunk-U2HGPLZS.js} +36 -2
  112. package/dist/{chunk-B65G5DNL.js → chunk-URSQLCTR.js} +3 -3
  113. package/dist/{chunk-ILKORZ3H.js → chunk-UUS2GIJZ.js} +7 -7
  114. package/dist/{chunk-XAKEUMEJ.js → chunk-UXOSVCLJ.js} +4 -4
  115. package/dist/{chunk-QLCCJEJI.js → chunk-WCUHAQKB.js} +2 -2
  116. package/dist/{chunk-WVAJFAIA.js → chunk-WWN566I7.js} +257 -101
  117. package/dist/{chunk-IPWPWM6R.js → chunk-X2NMFTG3.js} +111 -10
  118. package/dist/{chunk-UWN33VNX.js → chunk-XCLHOZAM.js} +10 -10
  119. package/dist/{chunk-P235SVAH.js → chunk-XDXNDSKO.js} +2 -2
  120. package/dist/chunk-XHVV4NVW.js +51 -0
  121. package/dist/{chunk-33LCUH4H.js → chunk-XMVQ5F4M.js} +4 -4
  122. package/dist/{chunk-MITI6NOL.js → chunk-YA7D2N2O.js} +11 -11
  123. package/dist/{chunk-7JEGTRLD.js → chunk-YB3FW24O.js} +3 -3
  124. package/dist/chunk-YNRDWYZP.js +295 -0
  125. package/dist/{chunk-44CM72SQ.js → chunk-YZLMKW4T.js} +3 -3
  126. package/dist/chunk-Z6XJQ6KO.js +452 -0
  127. package/dist/cli.cjs +179 -133
  128. package/dist/clock.d.ts +10 -0
  129. package/dist/clock.js +235 -0
  130. package/dist/countdown.d.ts +12 -0
  131. package/dist/countdown.js +450 -0
  132. package/dist/dgmo-router-QOMFCOOV.js +84 -0
  133. package/dist/dimensions-P5FSX2QN.js +22 -0
  134. package/dist/editor.js +43 -2
  135. package/dist/element.js +220 -110
  136. package/dist/element.mjs +45920 -33167
  137. package/dist/{flowchart-parser-ZNSKIBVR.js → flowchart-parser-OE4WHLTF.js} +4 -4
  138. package/dist/{flowchart-renderer-SNDSII4D.js → flowchart-renderer-GPCSMTOR.js} +8 -8
  139. package/dist/highlight.d.ts +17 -1
  140. package/dist/highlight.js +163 -6
  141. package/dist/index.d.ts +5 -1
  142. package/dist/index.js +199 -233
  143. package/dist/{layout-HRBZPFCN.js → layout-34CLNICW.js} +5 -5
  144. package/dist/layout-46366KBT.js +10 -0
  145. package/dist/{layout-HWDSRX5E.js → layout-5BG6DFCU.js} +6 -6
  146. package/dist/layout-6RDJHS6E.js +9 -0
  147. package/dist/{layout-7QXCNOVS.js → layout-7H4H46CS.js} +3 -3
  148. package/dist/{layout-46N4JJYK.js → layout-7SKMFYHL.js} +5 -5
  149. package/dist/{layout-EE6GE46Y.js → layout-DC4TVXER.js} +5 -5
  150. package/dist/layout-FGQWRYYW.js +14 -0
  151. package/dist/{layout-S2QBYSK2.js → layout-NXG63LWH.js} +3 -3
  152. package/dist/{layout-N76NR4ZO.js → layout-PUQCB6AN.js} +7 -7
  153. package/dist/{layout-HYZPWAK5.js → layout-QNUQLEHU.js} +3 -3
  154. package/dist/{layout-UM5F4DJB.js → layout-T3OZU5QW.js} +5 -5
  155. package/dist/layout-TJIWF7EM.js +14 -0
  156. package/dist/layout-VYELEAW7.js +14 -0
  157. package/dist/{layout-5RA6QWR6.js → layout-WZHNDT2O.js} +6 -6
  158. package/dist/{layout-search-OYV77HHS.js → layout-search-QS44PI5R.js} +6 -6
  159. package/dist/{parser-6BTRLKRZ.js → parser-45DENHFZ.js} +4 -4
  160. package/dist/{parser-TFZFBVWN.js → parser-4AI5ZN5F.js} +3 -3
  161. package/dist/{parser-XDVELHRK.js → parser-4P36TUVD.js} +4 -4
  162. package/dist/{parser-ZSDPZYQP.js → parser-5AURY4A6.js} +4 -4
  163. package/dist/{parser-N5O4IHUN.js → parser-A2BEFMGK.js} +4 -4
  164. package/dist/parser-B5FVS7O6.js +11 -0
  165. package/dist/{parser-NGU3ETO6.js → parser-C2HF2C2E.js} +4 -4
  166. package/dist/parser-CSFUN3CT.js +14 -0
  167. package/dist/{parser-TRTHDFPP.js → parser-D3QT6GWN.js} +5 -5
  168. package/dist/parser-D5637H5H.js +15 -0
  169. package/dist/{parser-VQP2UJ6W.js → parser-DFFEDKHH.js} +3 -3
  170. package/dist/parser-DOKMZXVZ.js +13 -0
  171. package/dist/parser-FMPCVFRK.js +15 -0
  172. package/dist/{parser-Y6WTBU76.js → parser-HYRTF3DO.js} +3 -3
  173. package/dist/{parser-I6KXEYFK.js → parser-I2UIJKVQ.js} +4 -4
  174. package/dist/{parser-O5J4VBII.js → parser-IBWNAPY4.js} +3 -3
  175. package/dist/{parser-PQ3POX45.js → parser-KUQWRPIT.js} +4 -4
  176. package/dist/{parser-2MFP2H2E.js → parser-LWKKBNSA.js} +3 -3
  177. package/dist/{parser-OV7NOBW6.js → parser-O4QFCUW7.js} +5 -5
  178. package/dist/{parser-IXSZZQHY.js → parser-PGMQDD4G.js} +4 -4
  179. package/dist/{parser-3STE62GB.js → parser-Q4QKCIWQ.js} +4 -4
  180. package/dist/parser-QTOB4KFL.js +14 -0
  181. package/dist/{parser-2EWECDSA.js → parser-QYYM4QVW.js} +4 -4
  182. package/dist/{parser-4OGOBJJ4.js → parser-RZMQP7MM.js} +4 -4
  183. package/dist/parser-RZPVAQVX.js +11 -0
  184. package/dist/parser-SOUJOEYI.js +13 -0
  185. package/dist/{parser-4FL2CMDG.js → parser-UQE5OWZI.js} +5 -5
  186. package/dist/{parser-NRAI6O25.js → parser-WAV5JRPT.js} +4 -4
  187. package/dist/{parser-KNSQSKQO.js → parser-YLKYBRIT.js} +5 -5
  188. package/dist/{parser-XKRP7QKP.js → parser-YS7TOS2K.js} +3 -3
  189. package/dist/{parser-AQETEVRW.js → parser-ZSOWUBML.js} +5 -5
  190. package/dist/{parser-CFZD5IBL.js → parser-ZTBATMLX.js} +4 -4
  191. package/dist/{renderer-VACVQYML.js → renderer-35HSIDMZ.js} +8 -8
  192. package/dist/{renderer-5MYBMBYO.js → renderer-4ITCHBT7.js} +5 -5
  193. package/dist/{renderer-CLJHQPBJ.js → renderer-67NPCBIS.js} +11 -11
  194. package/dist/{renderer-5NDVNDAZ.js → renderer-6GHYK7DX.js} +9 -9
  195. package/dist/{renderer-Z7I3W2PP.js → renderer-6RNGHC5Z.js} +8 -8
  196. package/dist/renderer-72LGR2YF.js +14 -0
  197. package/dist/{renderer-KQB7UGDS.js → renderer-7RH2SI3B.js} +3 -3
  198. package/dist/renderer-7SWMIFMM.js +21 -0
  199. package/dist/renderer-BBCEFILK.js +24 -0
  200. package/dist/{renderer-JGBKUCZD.js → renderer-BSW7SRIZ.js} +4 -4
  201. package/dist/{renderer-BYCNMBF7.js → renderer-BY533UWU.js} +11 -11
  202. package/dist/{renderer-6W5462RB.js → renderer-BZSBPTZJ.js} +9 -9
  203. package/dist/{renderer-7MVLWWQD.js → renderer-CXUC4KAD.js} +9 -9
  204. package/dist/{renderer-QIWVHWZO.js → renderer-DAXMXIKD.js} +3 -3
  205. package/dist/renderer-FZUKFUNZ.js +23 -0
  206. package/dist/renderer-G2NLGNKF.js +17 -0
  207. package/dist/renderer-GO3FE3RA.js +24 -0
  208. package/dist/{renderer-ZGNTUWC4.js → renderer-HPGR6USK.js} +8 -8
  209. package/dist/{renderer-UV6MI64M.js → renderer-HVCU2C3Z.js} +3 -3
  210. package/dist/renderer-ICJN2SA2.js +24 -0
  211. package/dist/{renderer-AWWAF6XD.js → renderer-INEXO7B6.js} +10 -10
  212. package/dist/{renderer-YY2OSF6E.js → renderer-KDYCFRBX.js} +8 -8
  213. package/dist/renderer-KY4KQBTF.js +19 -0
  214. package/dist/{renderer-B2OMQIQG.js → renderer-LBN65V45.js} +13 -13
  215. package/dist/{renderer-N43WR5GV.js → renderer-MGBWOCXG.js} +10 -10
  216. package/dist/{renderer-PGX2TKVS.js → renderer-O4JKUGKO.js} +8 -8
  217. package/dist/{renderer-4JHRUBE6.js → renderer-OOGFODWP.js} +10 -10
  218. package/dist/{renderer-6EEZHMH4.js → renderer-Q6ZKPLS6.js} +9 -9
  219. package/dist/{renderer-RPOA5YPZ.js → renderer-SZQ326M5.js} +12 -12
  220. package/dist/{renderer-ZRNG54CW.js → renderer-TKG6LS4U.js} +11 -11
  221. package/dist/{renderer-W4M6QLIJ.js → renderer-TQMZGDAX.js} +13 -13
  222. package/dist/renderer-radial-JELMHQ24.js +21 -0
  223. package/dist/{resolver-NOAA7ID7.js → resolver-FHBCO3PL.js} +3 -3
  224. package/dist/{state-parser-Z2V23ATR.js → state-parser-3REXRK3R.js} +4 -4
  225. package/dist/{state-renderer-B4DQBM6M.js → state-renderer-XYLNRWXR.js} +8 -8
  226. package/docs/ai-integration.md +12 -3
  227. package/docs/language-reference.md +429 -24
  228. package/gallery/fixtures/body.dgmo +17 -0
  229. package/gallery/fixtures/bracket.dgmo +30 -0
  230. package/gallery/fixtures/clock.dgmo +8 -0
  231. package/gallery/fixtures/countdown.dgmo +3 -0
  232. package/gallery/fixtures/family.dgmo +23 -0
  233. package/gallery/fixtures/goal.dgmo +4 -0
  234. package/gallery/fixtures/sketch.dgmo +22 -0
  235. package/package.json +12 -4
  236. package/dist/chunk-ODZVHU3R.js +0 -153
  237. package/dist/dgmo-router-X35VLZLM.js +0 -73
  238. package/dist/dimensions-J3FHIMJ6.js +0 -22
  239. package/dist/layout-5T6RH5M6.js +0 -14
  240. package/dist/layout-G23F7LDH.js +0 -9
  241. package/dist/layout-OB3RI63S.js +0 -14
  242. package/dist/parser-JAL2HD4I.js +0 -13
  243. package/dist/renderer-SMIBCRVB.js +0 -24
  244. package/dist/renderer-radial-C32GPJQ7.js +0 -21
@@ -0,0 +1,482 @@
1
+ import {
2
+ monthIndex,
3
+ resolveNext,
4
+ weekdayIndex
5
+ } from "./chunk-YNRDWYZP.js";
6
+ import {
7
+ extractColor,
8
+ measureIndent,
9
+ parseFirstLine
10
+ } from "./chunk-OTAL43EH.js";
11
+ import {
12
+ makeDgmoError,
13
+ makeFail
14
+ } from "./chunk-CXK4DZH3.js";
15
+
16
+ // src/countdown/parser.ts
17
+ var DATE_ONLY_RE = /^\d{4}-\d{2}-\d{2}$/;
18
+ var TIME_24H_RE = /^(\d{1,2}):(\d{2})$/;
19
+ var AMPM_RE = /^(\d{1,2})(?::(\d{2}))?\s*([ap]m)$/i;
20
+ function targetToMs(target) {
21
+ const s = target.trim();
22
+ if (DATE_ONLY_RE.test(s)) {
23
+ const [y, m, d] = s.split("-").map(Number);
24
+ return new Date(y, m - 1, d).getTime();
25
+ }
26
+ const t = new Date(s).getTime();
27
+ return Number.isFinite(t) ? t : null;
28
+ }
29
+ function ordinalToken(tok) {
30
+ const t = tok.toLowerCase();
31
+ if (t === "last") return -1;
32
+ const m = t.match(/^(\d+)(?:st|nd|rd|th)?$/);
33
+ if (m) {
34
+ const n = Number(m[1]);
35
+ return n >= 1 && n <= 5 ? n : null;
36
+ }
37
+ return null;
38
+ }
39
+ function parse24h(tok) {
40
+ const m = tok.match(TIME_24H_RE);
41
+ if (!m) return null;
42
+ const hour = Number(m[1]);
43
+ const minute = Number(m[2]);
44
+ if (hour > 23 || minute > 59) return null;
45
+ return { hour, minute };
46
+ }
47
+ function parseAt(rest, lineNum, softError) {
48
+ const t = parse24h(rest.trim());
49
+ if (t) return t;
50
+ const fixed = ampmTo24h(rest.trim());
51
+ softError(
52
+ lineNum,
53
+ fixed ? `"at ${rest}": use 24h time (${fixed}).` : `"at" needs a 24h time like 18:00 (got "${rest}").`
54
+ );
55
+ return null;
56
+ }
57
+ function ampmTo24h(tok) {
58
+ const m = tok.match(AMPM_RE);
59
+ if (!m) return null;
60
+ let hour = Number(m[1]) % 12;
61
+ if (/pm/i.test(m[3])) hour += 12;
62
+ return `${String(hour).padStart(2, "0")}:${m[2] ?? "00"}`;
63
+ }
64
+ function parseCountdown(content, palette) {
65
+ const result = {
66
+ type: "countdown",
67
+ title: null,
68
+ titleLineNumber: null,
69
+ target: null,
70
+ targetMs: null,
71
+ rule: null,
72
+ resolvedMs: null,
73
+ hasTime: false,
74
+ since: null,
75
+ sinceLabel: null,
76
+ units: "human",
77
+ round: "up",
78
+ fields: ["d", "h", "m", "s"],
79
+ lang: "en",
80
+ onDay: null,
81
+ expired: null,
82
+ note: null,
83
+ noVisual: false,
84
+ diagnostics: [],
85
+ error: null
86
+ };
87
+ const fail = makeFail(result);
88
+ const warn = (line, message) => {
89
+ result.diagnostics.push(makeDgmoError(line, message, "warning"));
90
+ };
91
+ const softError = (line, message) => {
92
+ result.diagnostics.push(makeDgmoError(line, message, "error"));
93
+ };
94
+ if (!content?.trim()) return fail(0, "No content provided");
95
+ const lines = content.split("\n");
96
+ let headerParsed = false;
97
+ let cadence = null;
98
+ let intervalN = 1;
99
+ let intervalUnit = "day";
100
+ let onSpec = null;
101
+ let atTime = null;
102
+ let anchorMs = null;
103
+ let targetMs = null;
104
+ let hasTargetLine = false;
105
+ let hasEvery = false;
106
+ const noteBody = [];
107
+ let inNote = false;
108
+ for (let i = 0; i < lines.length; i++) {
109
+ const lineNum = i + 1;
110
+ const raw = lines[i];
111
+ const trimmed = raw.trim();
112
+ if (!trimmed || trimmed.startsWith("//")) continue;
113
+ if (!headerParsed) {
114
+ const first = parseFirstLine(trimmed);
115
+ if (first?.chartType !== "countdown") {
116
+ return fail(lineNum, 'Expected "countdown [Title]" as the first line.');
117
+ }
118
+ if (first.title) {
119
+ const { label, color } = extractColor(
120
+ first.title,
121
+ palette,
122
+ result.diagnostics,
123
+ lineNum
124
+ );
125
+ result.title = label || null;
126
+ if (color !== void 0) result.color = color;
127
+ }
128
+ result.titleLineNumber = lineNum;
129
+ headerParsed = true;
130
+ continue;
131
+ }
132
+ if (measureIndent(raw) > 0) {
133
+ if (inNote) noteBody.push(trimmed);
134
+ else
135
+ warn(
136
+ lineNum,
137
+ `Indented content "${trimmed}" ignored \u2014 countdown is a single value.`
138
+ );
139
+ continue;
140
+ }
141
+ const [keyword, ...restTokens] = trimmed.split(/\s+/);
142
+ const key = keyword.toLowerCase();
143
+ const rest = restTokens.join(" ").trim();
144
+ if (key !== "note") inNote = false;
145
+ switch (key) {
146
+ // ── One-shot target ──
147
+ case "target": {
148
+ hasTargetLine = true;
149
+ if (/^now$/i.test(rest)) {
150
+ targetMs = Date.now();
151
+ result.target = new Date(targetMs).toISOString();
152
+ result.hasTime = true;
153
+ } else {
154
+ const ms = targetToMs(rest);
155
+ if (ms === null) {
156
+ softError(
157
+ lineNum,
158
+ `"target" needs an ISO date/datetime or "now" (got "${rest}").`
159
+ );
160
+ } else {
161
+ result.target = rest;
162
+ targetMs = ms;
163
+ if (rest.includes("T")) result.hasTime = true;
164
+ }
165
+ }
166
+ break;
167
+ }
168
+ // ── Recurrence — the canonical single-line form:
169
+ // every <cadence> [on <instant>] [at <time>] [from <date>]
170
+ // (each slot may also appear on its own line — handled below.)
171
+ case "every": {
172
+ hasEvery = true;
173
+ const seg = {
174
+ cadence: [],
175
+ on: [],
176
+ at: [],
177
+ from: []
178
+ };
179
+ let cur = "cadence";
180
+ for (const tok of rest.split(/\s+/).filter(Boolean)) {
181
+ const low = tok.toLowerCase();
182
+ if (low === "on" || low === "at" || low === "from") cur = low;
183
+ else seg[cur].push(tok);
184
+ }
185
+ const head = (seg.cadence[0] ?? "").toLowerCase();
186
+ const bareInterval = (head === "day" || head === "week" || head === "month") && seg.from.length > 0 && seg.on.length === 0;
187
+ if (bareInterval) {
188
+ cadence = "interval";
189
+ intervalN = 1;
190
+ intervalUnit = head;
191
+ } else if (head === "year" || head === "month" || head === "week") {
192
+ cadence = head;
193
+ } else if (head === "day") {
194
+ softError(
195
+ lineNum,
196
+ "`every day` needs `from <date>` (an interval anchor)."
197
+ );
198
+ break;
199
+ } else if (/^\d+$/.test(head) && seg.cadence[1]) {
200
+ const unit = seg.cadence[1].toLowerCase().replace(/s$/, "");
201
+ if (unit === "day" || unit === "week" || unit === "month") {
202
+ cadence = "interval";
203
+ intervalN = Number(head);
204
+ intervalUnit = unit;
205
+ } else {
206
+ softError(
207
+ lineNum,
208
+ `every ${head} <days|weeks|months> \u2014 unknown unit "${seg.cadence[1]}".`
209
+ );
210
+ }
211
+ } else {
212
+ emitFreeProseError(lineNum, rest, softError);
213
+ break;
214
+ }
215
+ if (seg.on.length)
216
+ onSpec = parseOn(seg.on.join(" "), lineNum, softError);
217
+ if (seg.at.length)
218
+ atTime = parseAt(seg.at.join(" "), lineNum, softError);
219
+ if (seg.from.length) {
220
+ const ms = targetToMs(seg.from.join(" "));
221
+ if (ms === null) {
222
+ softError(
223
+ lineNum,
224
+ `"from" needs an anchor date (got "${seg.from.join(" ")}").`
225
+ );
226
+ } else {
227
+ anchorMs = ms;
228
+ }
229
+ }
230
+ break;
231
+ }
232
+ // Standalone slot lines (lenient multi-line form).
233
+ case "on": {
234
+ onSpec = parseOn(rest, lineNum, softError);
235
+ break;
236
+ }
237
+ case "at": {
238
+ const t = parseAt(rest, lineNum, softError);
239
+ if (t) atTime = t;
240
+ break;
241
+ }
242
+ case "from": {
243
+ const ms = targetToMs(rest);
244
+ if (ms === null) {
245
+ softError(lineNum, `"from" needs an anchor date (got "${rest}").`);
246
+ } else {
247
+ anchorMs = ms;
248
+ }
249
+ break;
250
+ }
251
+ // ── Ordinal / since — numbers a yearly occurrence (resolvedYear − since) ──
252
+ case "since": {
253
+ const y = Number(rest);
254
+ if (Number.isInteger(y) && y > 0) result.since = y;
255
+ else softError(lineNum, `"since" needs a year (got "${rest}").`);
256
+ break;
257
+ }
258
+ // The eyebrow template: `Nth` → ordinal word, `N` → the number.
259
+ case "since-label":
260
+ result.sinceLabel = rest || null;
261
+ break;
262
+ // ── Display ──
263
+ case "units": {
264
+ const v = rest.toLowerCase();
265
+ if (v === "human" || v === "days" || v === "full" || v === "clock" || v === "weeks" || v === "words" || v === "compound") {
266
+ result.units = v;
267
+ } else {
268
+ warn(
269
+ lineNum,
270
+ `Unknown units "${rest}" \u2014 use human|days|full|clock|weeks|words.`
271
+ );
272
+ }
273
+ break;
274
+ }
275
+ case "round": {
276
+ const v = rest.toLowerCase();
277
+ if (v === "up" || v === "down" || v === "nearest") {
278
+ result.round = v;
279
+ } else {
280
+ warn(lineNum, `Unknown round "${rest}" \u2014 use up|down|nearest.`);
281
+ }
282
+ break;
283
+ }
284
+ case "fields": {
285
+ const set = rest.split(/[,\s]+/).map((f) => f.toLowerCase()).filter((f) => ["d", "h", "m", "s"].includes(f));
286
+ if (set.length) result.fields = set;
287
+ else
288
+ warn(lineNum, `"fields" needs a subset of d,h,m,s (got "${rest}").`);
289
+ break;
290
+ }
291
+ case "lang":
292
+ result.lang = rest.toLowerCase() || "en";
293
+ break;
294
+ case "on-day":
295
+ result.onDay = rest || null;
296
+ break;
297
+ case "expired":
298
+ result.expired = rest;
299
+ break;
300
+ // ── `no-visual` — suppress the default-on calendar band (§36.6). ──
301
+ case "no-visual":
302
+ result.noVisual = true;
303
+ break;
304
+ // ── `note` — markdown caption; inline value or indented body block. ──
305
+ case "note":
306
+ inNote = true;
307
+ if (rest) noteBody.push(rest);
308
+ break;
309
+ default:
310
+ warn(lineNum, `Unrecognized line "${trimmed}".`);
311
+ }
312
+ }
313
+ if (noteBody.length) result.note = noteBody.join("\n");
314
+ if (hasEvery && hasTargetLine) {
315
+ softError(
316
+ result.titleLineNumber ?? 1,
317
+ "A countdown has either `target` (one-shot) or `every` (recurring), not both."
318
+ );
319
+ }
320
+ if (result.expired !== null && hasEvery) {
321
+ warn(
322
+ result.titleLineNumber ?? 1,
323
+ "`expired` applies only to one-shot `target` blocks; recurring blocks roll forward."
324
+ );
325
+ }
326
+ if (hasEvery && cadence) {
327
+ const rule = assembleRule(
328
+ cadence,
329
+ { intervalN, intervalUnit, anchorMs },
330
+ onSpec,
331
+ atTime,
332
+ result.titleLineNumber ?? 1,
333
+ softError
334
+ );
335
+ if (rule) {
336
+ result.rule = rule;
337
+ result.resolvedMs = resolveNext(rule, Date.now());
338
+ if (atTime) result.hasTime = true;
339
+ }
340
+ } else if (targetMs !== null) {
341
+ result.targetMs = targetMs;
342
+ result.resolvedMs = targetMs;
343
+ }
344
+ if (result.resolvedMs === null && result.error === null) {
345
+ if (!hasEvery && !hasTargetLine) {
346
+ softError(
347
+ result.titleLineNumber ?? 1,
348
+ "Missing `target` or `every` \u2014 a countdown needs one."
349
+ );
350
+ }
351
+ }
352
+ return result;
353
+ }
354
+ function parseOn(rest, lineNum, softError) {
355
+ const toks = rest.split(/\s+/).filter(Boolean);
356
+ if (toks.length === 0) {
357
+ softError(
358
+ lineNum,
359
+ '"on" needs a target (e.g. "Aug 21", "3rd Tuesday", "Friday").'
360
+ );
361
+ return null;
362
+ }
363
+ const ord = ordinalToken(toks[0]);
364
+ if (ord !== null && toks[1]) {
365
+ const wd2 = weekdayIndex(toks[1]);
366
+ if (wd2 === null) {
367
+ softError(lineNum, `"${toks[1]}" is not a weekday.`);
368
+ return null;
369
+ }
370
+ return { nth: ord, weekday: wd2 };
371
+ }
372
+ const mo = monthIndex(toks[0]);
373
+ if (mo !== null && toks[1]) {
374
+ const day = Number(toks[1].replace(/(st|nd|rd|th)$/i, ""));
375
+ if (!Number.isInteger(day) || day < 1 || day > 31) {
376
+ softError(lineNum, `"${toks[1]}" is not a valid day of month.`);
377
+ return null;
378
+ }
379
+ return { month: mo, day };
380
+ }
381
+ const wd = weekdayIndex(toks[0]);
382
+ if (wd !== null) return { weekday: wd };
383
+ softError(
384
+ lineNum,
385
+ `"on ${rest}" \u2014 use "Aug 21", "3rd Tuesday", "last Friday", or a weekday.`
386
+ );
387
+ return null;
388
+ }
389
+ function assembleRule(cadence, interval, onSpec, atTime, lineNum, softError) {
390
+ const hour = atTime?.hour ?? 0;
391
+ const minute = atTime?.minute ?? 0;
392
+ const allDay = atTime === null;
393
+ if (cadence === "interval") {
394
+ return {
395
+ kind: "interval",
396
+ intervalN: interval.intervalN,
397
+ intervalUnit: interval.intervalUnit,
398
+ anchorMs: interval.anchorMs ?? void 0,
399
+ hour,
400
+ minute,
401
+ allDay
402
+ };
403
+ }
404
+ if (cadence === "year") {
405
+ if (onSpec?.month === void 0 || onSpec.day === void 0) {
406
+ softError(
407
+ lineNum,
408
+ "`every year` needs `on <Month> <Day>` (e.g. on Aug 21)."
409
+ );
410
+ return null;
411
+ }
412
+ return {
413
+ kind: "month-day",
414
+ month: onSpec.month,
415
+ day: onSpec.day,
416
+ hour,
417
+ minute,
418
+ allDay
419
+ };
420
+ }
421
+ if (cadence === "month") {
422
+ if (onSpec?.nth === void 0 || onSpec.weekday === void 0) {
423
+ softError(
424
+ lineNum,
425
+ "`every month` needs `on <nth> <weekday>`, `on last <weekday>`, or `from <date>`."
426
+ );
427
+ return null;
428
+ }
429
+ return onSpec.nth < 0 ? { kind: "last-weekday", weekday: onSpec.weekday, hour, minute, allDay } : {
430
+ kind: "nth-weekday",
431
+ nth: onSpec.nth,
432
+ weekday: onSpec.weekday,
433
+ hour,
434
+ minute,
435
+ allDay
436
+ };
437
+ }
438
+ if (onSpec?.weekday === void 0 || onSpec.nth !== void 0) {
439
+ softError(lineNum, "`every week` needs `on <weekday>` (e.g. on Friday).");
440
+ return null;
441
+ }
442
+ return { kind: "weekly", weekday: onSpec.weekday, hour, minute, allDay };
443
+ }
444
+ function emitFreeProseError(lineNum, rest, softError) {
445
+ const toks = rest.split(/\s+/).filter(Boolean);
446
+ const problems = [];
447
+ let onPart = "";
448
+ let atPart = "";
449
+ for (let i = 0; i < toks.length; i++) {
450
+ const tok = toks[i];
451
+ const fixed = ampmTo24h(tok);
452
+ if (fixed) {
453
+ problems.push(`"${tok}": use 24h time (${fixed})`);
454
+ atPart = ` at ${fixed}`;
455
+ continue;
456
+ }
457
+ const wd = weekdayIndex(tok);
458
+ if (wd !== null) onPart = `week on ${tok}`;
459
+ const mo = monthIndex(tok);
460
+ if (mo !== null && toks[i + 1] && /^\d/.test(toks[i + 1])) {
461
+ onPart = `year on ${tok} ${toks[i + 1]}`;
462
+ }
463
+ }
464
+ if (!onPart && !atPart) {
465
+ problems.push(
466
+ "bare cadence \u2014 use year | month | week | N days|weeks|months"
467
+ );
468
+ } else if (onPart.startsWith("week")) {
469
+ problems.push("bare weekday needs a cadence");
470
+ }
471
+ const suggestion = onPart ? `every ${onPart}${atPart}` : `every week \u2026${atPart}`;
472
+ softError(
473
+ lineNum,
474
+ `Free-form recurrence rejected. ${problems.join("; ")}. Try: ${suggestion}`
475
+ );
476
+ }
477
+
478
+ export {
479
+ targetToMs,
480
+ parseCountdown
481
+ };
482
+ //# sourceMappingURL=chunk-BTUTZMPT.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  NODE_HEIGHT,
3
3
  NODE_WIDTH
4
- } from "./chunk-IJZFN3HM.js";
4
+ } from "./chunk-TWQUYVP3.js";
5
5
 
6
6
  // src/boxes-and-lines/layout-grouped.ts
7
7
  var NODESEP = 50;
@@ -689,4 +689,4 @@ export {
689
689
  acyclicOrient,
690
690
  groupedTierCandidates
691
691
  };
692
- //# sourceMappingURL=chunk-YGJTDXVR.js.map
692
+ //# sourceMappingURL=chunk-C4GQDB5L.js.map
@@ -2,7 +2,7 @@ import {
2
2
  CHAR_WIDTH_RATIO,
3
3
  measureText,
4
4
  truncateText
5
- } from "./chunk-WCT3NYCV.js";
5
+ } from "./chunk-5LWQH6QV.js";
6
6
 
7
7
  // src/infra/layout.ts
8
8
  import dagre from "@dagrejs/dagre";
@@ -587,4 +587,4 @@ export {
587
587
  fixEdgeWaypoints,
588
588
  layoutInfra
589
589
  };
590
- //# sourceMappingURL=chunk-Y2ZE3MSG.js.map
590
+ //# sourceMappingURL=chunk-C63UWAKM.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  acyclicOrient
3
- } from "./chunk-YGJTDXVR.js";
3
+ } from "./chunk-C4GQDB5L.js";
4
4
 
5
5
  // src/swimlane/layout.ts
6
6
  var MARGIN = 30;
@@ -419,4 +419,4 @@ function layoutSwimlane(parsed) {
419
419
  export {
420
420
  layoutSwimlane
421
421
  };
422
- //# sourceMappingURL=chunk-725LDASD.js.map
422
+ //# sourceMappingURL=chunk-CLD2OKV7.js.map
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  buildPlacedNotes
3
- } from "./chunk-JED6ZDEE.js";
3
+ } from "./chunk-O7WP4ZD4.js";
4
4
  import {
5
5
  noteCanvasShift
6
6
  } from "./chunk-6EK55ART.js";
7
7
  import {
8
8
  measureText
9
- } from "./chunk-WCT3NYCV.js";
9
+ } from "./chunk-5LWQH6QV.js";
10
10
  import {
11
11
  resolveNotes
12
12
  } from "./chunk-FMDSF3OV.js";
@@ -201,4 +201,4 @@ function layoutClassDiagram(parsed, options) {
201
201
  export {
202
202
  layoutClassDiagram
203
203
  };
204
- //# sourceMappingURL=chunk-WBRZJOEC.js.map
204
+ //# sourceMappingURL=chunk-CMCR5WBW.js.map
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  resolveTagColor,
6
6
  tagAttrKey
7
- } from "./chunk-QLCCJEJI.js";
7
+ } from "./chunk-WCUHAQKB.js";
8
8
  import {
9
9
  resolveColor
10
10
  } from "./chunk-TLVIHFRO.js";
@@ -164,4 +164,4 @@ export {
164
164
  formatPct,
165
165
  buildLegend
166
166
  };
167
- //# sourceMappingURL=chunk-IZMRON6C.js.map
167
+ //# sourceMappingURL=chunk-CVV36CWI.js.map