@diagrammo/dgmo 0.49.0 → 0.50.1

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 (198) hide show
  1. package/.cursorrules +6 -2
  2. package/.github/copilot-instructions.md +6 -2
  3. package/.windsurfrules +6 -2
  4. package/SKILL.md +6 -2
  5. package/dist/advanced.js +557 -195
  6. package/dist/auto.js +129 -119
  7. package/dist/auto.mjs +19496 -12761
  8. package/dist/block.js +145 -48
  9. package/dist/{charts-d3-EW3YQTEA.js → charts-d3-LR6D3D7A.js} +5 -5
  10. package/dist/{chunk-5FGDJIJX.js → chunk-2C56LEML.js} +3 -3
  11. package/dist/{chunk-XJ7J6WOO.js → chunk-2KGXHFYK.js} +4 -4
  12. package/dist/{chunk-T7IKPCMI.js → chunk-3LH5CLP4.js} +3 -3
  13. package/dist/{chunk-ZDUQGL3N.js → chunk-3LKM6FMW.js} +2 -2
  14. package/dist/{chunk-4FIV4K4Z.js → chunk-3NODSS6A.js} +7 -7
  15. package/dist/{chunk-4BD7EVPK.js → chunk-3P2DKJCG.js} +2 -2
  16. package/dist/{chunk-TC3YWBFO.js → chunk-3UIKSPFB.js} +35 -9
  17. package/dist/{chunk-SJEGO2QL.js → chunk-3XGZF2QJ.js} +4 -4
  18. package/dist/chunk-3XPUDB7B.js +420 -0
  19. package/dist/{chunk-O5MQPK7E.js → chunk-3Y2DRD7S.js} +3 -3
  20. package/dist/chunk-3YPY3OXD.js +354 -0
  21. package/dist/{chunk-N4J5KGWG.js → chunk-4MJ7M6YL.js} +8 -8
  22. package/dist/{chunk-JFPY3UJ7.js → chunk-4S52SK6G.js} +8 -8
  23. package/dist/{chunk-ALRHIR6I.js → chunk-5GJYGP5Z.js} +4 -4
  24. package/dist/{chunk-SQDFK5ZQ.js → chunk-5OWVC2A6.js} +3 -3
  25. package/dist/{chunk-7VLUGEMJ.js → chunk-66NVRO4K.js} +4 -4
  26. package/dist/{chunk-ZREZOIGS.js → chunk-66RUL3XF.js} +6 -6
  27. package/dist/{chunk-MJCG5K2O.js → chunk-6BFZKBGD.js} +2 -2
  28. package/dist/{chunk-2WMBWZY2.js → chunk-6HJBFVLO.js} +3 -3
  29. package/dist/{chunk-XCC2RENT.js → chunk-6IAA2QQ2.js} +2 -2
  30. package/dist/{chunk-B57V3DWN.js → chunk-7L3R6I3U.js} +3 -3
  31. package/dist/chunk-7PQYTZMA.js +681 -0
  32. package/dist/{chunk-6SA7FJE4.js → chunk-7QKLIMRZ.js} +10 -10
  33. package/dist/{chunk-YTN572Q2.js → chunk-7TV5Y53Y.js} +2 -2
  34. package/dist/{chunk-6CLKNXVP.js → chunk-BBGDM4NQ.js} +457 -78
  35. package/dist/{chunk-3NFJWFNP.js → chunk-BDXC7MDK.js} +1045 -124
  36. package/dist/{chunk-D5AVQCDN.js → chunk-BH3UYK36.js} +3 -3
  37. package/dist/chunk-BTUTZMPT.js +482 -0
  38. package/dist/{chunk-LVHPTBO3.js → chunk-C2CVAM3U.js} +4 -4
  39. package/dist/{chunk-BCT5G2VN.js → chunk-DFTFPYUD.js} +5 -5
  40. package/dist/{chunk-KV6Y2HE6.js → chunk-DSWVNQVS.js} +4 -4
  41. package/dist/{chunk-4YNP6O47.js → chunk-DZXYF2F5.js} +13 -3
  42. package/dist/{chunk-FUCAB3KQ.js → chunk-EAMEADTV.js} +3 -3
  43. package/dist/chunk-FA6K3FWM.js +940 -0
  44. package/dist/{chunk-HBVD67XG.js → chunk-FJUNPCYI.js} +2 -2
  45. package/dist/{chunk-6VE3VLWM.js → chunk-GBE54KY6.js} +6 -5
  46. package/dist/{chunk-YRVLP7UU.js → chunk-GKC3HILQ.js} +4 -4
  47. package/dist/{chunk-ZXL6MB4R.js → chunk-GL5UZ6NY.js} +3 -3
  48. package/dist/{chunk-GB3YZTAM.js → chunk-H73FP42Q.js} +5 -5
  49. package/dist/{chunk-4UDKKGHH.js → chunk-HEVYAHLW.js} +2 -2
  50. package/dist/{chunk-DDTJ5N7Q.js → chunk-HLJVEAOF.js} +6 -6
  51. package/dist/{chunk-CLR4A2N2.js → chunk-HTMN2Z6U.js} +4 -4
  52. package/dist/{chunk-TLKMTQYL.js → chunk-I2WKW7C7.js} +3 -3
  53. package/dist/{chunk-IUK7AGD4.js → chunk-I7F2A35O.js} +2 -2
  54. package/dist/{chunk-IBC35BTK.js → chunk-IUMPEA64.js} +2 -2
  55. package/dist/{chunk-5XCM7UUW.js → chunk-J6K7RP6P.js} +100 -36
  56. package/dist/{chunk-AJ2PEY7J.js → chunk-JJUOHGX2.js} +2 -2
  57. package/dist/{chunk-CEHZOPGM.js → chunk-KFZYNWWO.js} +2 -2
  58. package/dist/{chunk-4NQ3IKUM.js → chunk-KHEYDLMT.js} +5 -5
  59. package/dist/{chunk-YM2BSPYW.js → chunk-LE4MYMLI.js} +2 -2
  60. package/dist/{chunk-PU3AUQPA.js → chunk-M5RXSRO2.js} +2 -2
  61. package/dist/{chunk-XKTN7CZF.js → chunk-MCZ5LBZD.js} +4 -4
  62. package/dist/{chunk-35BBZDFE.js → chunk-NU3XLTGP.js} +4 -4
  63. package/dist/{chunk-BPIJLRYE.js → chunk-NWED7CYO.js} +3 -3
  64. package/dist/{chunk-YYX3SU6H.js → chunk-OMNGQPEZ.js} +257 -101
  65. package/dist/{chunk-BGJV5ATD.js → chunk-ONA5KPV3.js} +2 -2
  66. package/dist/{chunk-ZNQX6QWH.js → chunk-OTAL43EH.js} +6 -2
  67. package/dist/{chunk-F743CM2N.js → chunk-OTQKUHRS.js} +3 -3
  68. package/dist/{chunk-KUBBJ2CD.js → chunk-P7CE7LXL.js} +6 -6
  69. package/dist/{chunk-UVCXZEGU.js → chunk-PFHVU7UA.js} +2 -2
  70. package/dist/{chunk-5ZZLLBFK.js → chunk-PGEGPSCZ.js} +2 -2
  71. package/dist/chunk-Q4V4XQWV.js +158 -0
  72. package/dist/{chunk-IHLSHCPZ.js → chunk-QJP6PG7F.js} +5 -5
  73. package/dist/{chunk-EYN7VFKL.js → chunk-QROYX7TT.js} +3 -3
  74. package/dist/chunk-QXKWYZNR.js +379 -0
  75. package/dist/{chunk-VC3TR4NL.js → chunk-RZ6YKEUJ.js} +3 -3
  76. package/dist/{chunk-K6HNAY5V.js → chunk-SCHXJTZL.js} +2 -2
  77. package/dist/{chunk-7OVSJI2V.js → chunk-SQLNBA64.js} +3 -3
  78. package/dist/{chunk-65RTDUZH.js → chunk-SXRTRMEE.js} +3 -3
  79. package/dist/{chunk-3BIAFYD2.js → chunk-T4VOVZT5.js} +2 -2
  80. package/dist/{chunk-UWDO3O52.js → chunk-TN35C5KM.js} +2 -2
  81. package/dist/{chunk-IFK3GIUW.js → chunk-TSA237IM.js} +2 -2
  82. package/dist/{chunk-DKEPS5LH.js → chunk-U2HGPLZS.js} +36 -2
  83. package/dist/{chunk-4HVNZ7WF.js → chunk-VBYSIOOY.js} +3 -3
  84. package/dist/{chunk-ZTLWVRNS.js → chunk-VDOOQZUD.js} +2 -2
  85. package/dist/{chunk-RTERS6S5.js → chunk-VUJGMJE6.js} +4 -4
  86. package/dist/{chunk-X2CH42BN.js → chunk-VVW3F3MD.js} +7 -7
  87. package/dist/{chunk-RI4NIMFP.js → chunk-VVZRV54S.js} +75 -35
  88. package/dist/{chunk-LG4TWW4U.js → chunk-WW32K72E.js} +8 -8
  89. package/dist/{chunk-NVT6C2VE.js → chunk-X6EZPSW6.js} +4 -4
  90. package/dist/{chunk-KQAEKMIX.js → chunk-XDXNDSKO.js} +2 -2
  91. package/dist/{chunk-FMKTYMP4.js → chunk-XJLKLU4D.js} +3 -3
  92. package/dist/chunk-Y4RNXEAO.js +952 -0
  93. package/dist/{chunk-26RVGM44.js → chunk-YIA4LEX4.js} +15 -7
  94. package/dist/chunk-YNRDWYZP.js +295 -0
  95. package/dist/{chunk-SGHSY3LU.js → chunk-Z6XJQ6KO.js} +81 -6
  96. package/dist/{chunk-SVDWQGX2.js → chunk-ZAD4HV2G.js} +139 -78
  97. package/dist/cli.cjs +153 -144
  98. package/dist/clock.d.ts +10 -0
  99. package/dist/clock.js +235 -0
  100. package/dist/countdown.d.ts +12 -0
  101. package/dist/countdown.js +450 -0
  102. package/dist/dgmo-router-YTU3ENAX.js +84 -0
  103. package/dist/{dimensions-WSIJXT5Q.js → dimensions-OTBKC5M6.js} +5 -5
  104. package/dist/editor.js +39 -1
  105. package/dist/element.js +131 -121
  106. package/dist/element.mjs +19496 -12761
  107. package/dist/{flowchart-parser-IVZN7CQN.js → flowchart-parser-OE4WHLTF.js} +4 -4
  108. package/dist/{flowchart-renderer-GMI2U3DD.js → flowchart-renderer-GPCSMTOR.js} +6 -6
  109. package/dist/highlight.d.ts +17 -1
  110. package/dist/highlight.js +156 -5
  111. package/dist/index.js +50 -45
  112. package/dist/{layout-HQMBPJVS.js → layout-46366KBT.js} +2 -2
  113. package/dist/{layout-D42XE4RE.js → layout-5BG6DFCU.js} +3 -3
  114. package/dist/{layout-K2ZN3Q42.js → layout-7MZ5NF2N.js} +4 -4
  115. package/dist/{layout-4Z5JM7PT.js → layout-FWODLIMP.js} +4 -4
  116. package/dist/{layout-GZ2CWONU.js → layout-J36454XU.js} +4 -4
  117. package/dist/{layout-S3EK4IYO.js → layout-LD6XTLD6.js} +4 -4
  118. package/dist/{parser-CLMFZWCC.js → parser-36HVKU5U.js} +5 -5
  119. package/dist/{parser-MCJWF5G3.js → parser-4AI5ZN5F.js} +3 -3
  120. package/dist/{parser-DERPY5KC.js → parser-4NO6VZ6S.js} +4 -4
  121. package/dist/parser-4WQQQXCG.js +13 -0
  122. package/dist/{parser-4ROBKVUR.js → parser-5OXGPNBF.js} +5 -5
  123. package/dist/{parser-XWUDFJ7P.js → parser-AGVYTQXV.js} +4 -4
  124. package/dist/{parser-TITK4YW6.js → parser-AXKBDGNO.js} +5 -5
  125. package/dist/parser-B5FVS7O6.js +11 -0
  126. package/dist/parser-CSFUN3CT.js +14 -0
  127. package/dist/parser-CVMEDULU.js +15 -0
  128. package/dist/{parser-KPMN5KKE.js → parser-D5VILGN2.js} +4 -4
  129. package/dist/{parser-IKZFTLOJ.js → parser-DFFEDKHH.js} +3 -3
  130. package/dist/{parser-JD7OQ2E6.js → parser-H3XEPFPV.js} +4 -4
  131. package/dist/{parser-UBGPTIZD.js → parser-HYRTF3DO.js} +3 -3
  132. package/dist/{parser-K647FRI4.js → parser-IBWNAPY4.js} +3 -3
  133. package/dist/{parser-4BKIFG2C.js → parser-IJBMRXMC.js} +5 -5
  134. package/dist/{parser-MBJSBTL5.js → parser-JJR52VAT.js} +5 -5
  135. package/dist/{parser-SMBJO3XN.js → parser-K3XXLMUW.js} +4 -4
  136. package/dist/{parser-OBQG655V.js → parser-KCR2WS3V.js} +4 -4
  137. package/dist/{parser-HVJFTOXL.js → parser-LWKKBNSA.js} +3 -3
  138. package/dist/{parser-ZYC3XGNS.js → parser-MPCE5JBG.js} +4 -4
  139. package/dist/{parser-QJYS7KQQ.js → parser-MTOMTWTD.js} +4 -4
  140. package/dist/{parser-GFSOPDB7.js → parser-O4HIUN6G.js} +4 -4
  141. package/dist/{parser-BL7Z72EY.js → parser-PSA4UBSP.js} +4 -4
  142. package/dist/{parser-TNYX5S7E.js → parser-RV4M6AS2.js} +4 -4
  143. package/dist/parser-RZPVAQVX.js +11 -0
  144. package/dist/{parser-UGA23PYK.js → parser-TGQZJ5OT.js} +4 -4
  145. package/dist/parser-TXND652E.js +13 -0
  146. package/dist/{parser-WISPH7LW.js → parser-VKOJM7KS.js} +4 -4
  147. package/dist/{parser-ZKF5K2H2.js → parser-W4PQUGX3.js} +4 -4
  148. package/dist/{parser-MRBPXXIV.js → parser-WAV5JRPT.js} +4 -4
  149. package/dist/{parser-D6ONJQFR.js → parser-YS7TOS2K.js} +3 -3
  150. package/dist/pert.d.ts +8 -0
  151. package/dist/{renderer-VFUVRNLK.js → renderer-2AZ5HJFK.js} +4 -4
  152. package/dist/{renderer-V3JEMWMM.js → renderer-2QPMJ2DA.js} +6 -6
  153. package/dist/renderer-45PSOL3E.js +19 -0
  154. package/dist/{renderer-BB5PREMY.js → renderer-4ITCHBT7.js} +4 -4
  155. package/dist/{renderer-XEKIRPI6.js → renderer-5DSEWF74.js} +5 -5
  156. package/dist/{renderer-QNHUXCRL.js → renderer-6OKF44KS.js} +9 -9
  157. package/dist/renderer-72LGR2YF.js +14 -0
  158. package/dist/{renderer-YHXPN3GF.js → renderer-7SD6MSBS.js} +7 -7
  159. package/dist/renderer-A5VE5BCI.js +24 -0
  160. package/dist/{renderer-A5VFZQQK.js → renderer-AUW2BE6G.js} +6 -6
  161. package/dist/{renderer-LWGJFT3D.js → renderer-B5TBNZJE.js} +5 -5
  162. package/dist/{renderer-4IUPINAE.js → renderer-BSR2O2H6.js} +7 -7
  163. package/dist/{renderer-DKESNMU5.js → renderer-CYB4LK3G.js} +6 -6
  164. package/dist/{renderer-MFJ7HY2H.js → renderer-FF24KZCI.js} +5 -5
  165. package/dist/{renderer-CGW7QPNA.js → renderer-FPE3J5VZ.js} +7 -7
  166. package/dist/{renderer-6T3KK4S3.js → renderer-FYSVXL7M.js} +7 -7
  167. package/dist/{renderer-THD6V5TL.js → renderer-HDCCZURL.js} +9 -7
  168. package/dist/{renderer-TPIBXNOS.js → renderer-JCCHNECZ.js} +6 -6
  169. package/dist/{renderer-QL5KO6SK.js → renderer-KS7YZJE2.js} +7 -7
  170. package/dist/{renderer-SQ3JUAI7.js → renderer-NGXZTRK6.js} +6 -6
  171. package/dist/{renderer-MJDDU27W.js → renderer-ODUUOPVT.js} +10 -10
  172. package/dist/renderer-PJM35LJN.js +17 -0
  173. package/dist/{renderer-TYXRHMRI.js → renderer-PPIHO5FI.js} +9 -9
  174. package/dist/{renderer-W5RMOURB.js → renderer-PSMMZCKH.js} +6 -6
  175. package/dist/{renderer-UZF3JROD.js → renderer-QAOBLRXV.js} +8 -8
  176. package/dist/{renderer-ROV756WT.js → renderer-R2WNIC2C.js} +5 -5
  177. package/dist/{renderer-VICQ4WNY.js → renderer-SBS3YWU5.js} +5 -5
  178. package/dist/{renderer-6L3NBEY5.js → renderer-UYMQQCJK.js} +6 -6
  179. package/dist/{renderer-radial-MHO2VDXN.js → renderer-radial-F7X5F2VU.js} +6 -6
  180. package/dist/{state-parser-RX3GXOIB.js → state-parser-3REXRK3R.js} +4 -4
  181. package/dist/{state-renderer-AJUKGNWU.js → state-renderer-XYLNRWXR.js} +6 -6
  182. package/docs/ai-integration.md +6 -2
  183. package/docs/language-reference.md +253 -22
  184. package/gallery/fixtures/body.dgmo +17 -0
  185. package/gallery/fixtures/bracket.dgmo +30 -0
  186. package/gallery/fixtures/clock.dgmo +8 -0
  187. package/gallery/fixtures/countdown.dgmo +3 -0
  188. package/gallery/fixtures/goal.dgmo +4 -0
  189. package/package.json +12 -4
  190. package/dist/advanced.d.ts +0 -6162
  191. package/dist/auto.d.ts +0 -54
  192. package/dist/block.d.ts +0 -123
  193. package/dist/dgmo-router-ODKPEJ3P.js +0 -79
  194. package/dist/element.d.ts +0 -62
  195. package/dist/index.d.ts +0 -166
  196. package/dist/parser-667RGSUW.js +0 -13
  197. package/dist/parser-J3P2D6IP.js +0 -13
  198. package/dist/themes-1-CuKpeH.d.ts +0 -908
@@ -8,7 +8,7 @@ import {
8
8
  stripDefaultModifier,
9
9
  validateTagGroupNames,
10
10
  validateTagValues
11
- } from "./chunk-HBVD67XG.js";
11
+ } from "./chunk-FJUNPCYI.js";
12
12
  import {
13
13
  parseArrow,
14
14
  parseInArrowLabel
@@ -26,7 +26,7 @@ import {
26
26
  splitNameAndMeta,
27
27
  warnUnknownMetaKeys,
28
28
  withTagAliases
29
- } from "./chunk-ZNQX6QWH.js";
29
+ } from "./chunk-OTAL43EH.js";
30
30
  import {
31
31
  NAME_DIAGNOSTIC_CODES,
32
32
  formatDgmoError,
@@ -1022,4 +1022,4 @@ export {
1022
1022
  parseSequenceDgmo,
1023
1023
  looksLikeSequence
1024
1024
  };
1025
- //# sourceMappingURL=chunk-D5AVQCDN.js.map
1025
+ //# sourceMappingURL=chunk-BH3UYK36.js.map
@@ -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
  GANTT_BOOLEAN_SET,
3
3
  GANTT_OPTION_SET
4
- } from "./chunk-DKEPS5LH.js";
4
+ } from "./chunk-U2HGPLZS.js";
5
5
  import {
6
6
  parseDuration,
7
7
  parseOffset,
@@ -15,7 +15,7 @@ import {
15
15
  stripDefaultModifier,
16
16
  tagAttrKey,
17
17
  validateTagGroupNames
18
- } from "./chunk-HBVD67XG.js";
18
+ } from "./chunk-FJUNPCYI.js";
19
19
  import {
20
20
  normalizeName
21
21
  } from "./chunk-NOTA6TEI.js";
@@ -28,7 +28,7 @@ import {
28
28
  splitNameAndMeta,
29
29
  warnUnknownMetaKeys,
30
30
  withTagAliases
31
- } from "./chunk-ZNQX6QWH.js";
31
+ } from "./chunk-OTAL43EH.js";
32
32
  import {
33
33
  formatDgmoError,
34
34
  makeDgmoError
@@ -1253,4 +1253,4 @@ export {
1253
1253
  GANTT_KNOWN_OPTIONS,
1254
1254
  GANTT_KNOWN_BOOLEANS
1255
1255
  };
1256
- //# sourceMappingURL=chunk-LVHPTBO3.js.map
1256
+ //# sourceMappingURL=chunk-C2CVAM3U.js.map
@@ -4,7 +4,7 @@ import {
4
4
  layoutC4Containers,
5
5
  layoutC4Context,
6
6
  layoutC4Deployment
7
- } from "./chunk-CEHZOPGM.js";
7
+ } from "./chunk-KFZYNWWO.js";
8
8
  import {
9
9
  renderInlineText
10
10
  } from "./chunk-3HDBAXF5.js";
@@ -17,7 +17,7 @@ import {
17
17
  } from "./chunk-3CIOJ5YJ.js";
18
18
  import {
19
19
  renderIntegratedLegend
20
- } from "./chunk-4UDKKGHH.js";
20
+ } from "./chunk-HEVYAHLW.js";
21
21
  import {
22
22
  TITLE_FONT_SIZE,
23
23
  TITLE_FONT_WEIGHT
@@ -34,7 +34,7 @@ import {
34
34
  } from "./chunk-5LWQH6QV.js";
35
35
  import {
36
36
  parseC4
37
- } from "./chunk-EYN7VFKL.js";
37
+ } from "./chunk-QROYX7TT.js";
38
38
  import {
39
39
  preprocessDescriptionLine
40
40
  } from "./chunk-IYULMRBE.js";
@@ -45,7 +45,7 @@ import {
45
45
  } from "./chunk-P6T66CCZ.js";
46
46
  import {
47
47
  tagAttrKey
48
- } from "./chunk-HBVD67XG.js";
48
+ } from "./chunk-FJUNPCYI.js";
49
49
 
50
50
  // src/c4/renderer.ts
51
51
  import * as d3Selection from "d3-selection";
@@ -1035,4 +1035,4 @@ export {
1035
1035
  renderC4Deployment,
1036
1036
  renderC4DeploymentForExport
1037
1037
  };
1038
- //# sourceMappingURL=chunk-BCT5G2VN.js.map
1038
+ //# sourceMappingURL=chunk-DFTFPYUD.js.map
@@ -7,10 +7,10 @@ import {
7
7
  tagAttrKey,
8
8
  validateTagGroupNames,
9
9
  validateTagValues
10
- } from "./chunk-HBVD67XG.js";
10
+ } from "./chunk-FJUNPCYI.js";
11
11
  import {
12
12
  tryCollectNote
13
- } from "./chunk-K6HNAY5V.js";
13
+ } from "./chunk-SCHXJTZL.js";
14
14
  import {
15
15
  resolveNotes
16
16
  } from "./chunk-FMDSF3OV.js";
@@ -30,7 +30,7 @@ import {
30
30
  tryParseSharedOption,
31
31
  warnUnknownMetaKeys,
32
32
  withTagAliases
33
- } from "./chunk-ZNQX6QWH.js";
33
+ } from "./chunk-OTAL43EH.js";
34
34
  import {
35
35
  makeDgmoError,
36
36
  suggest
@@ -884,4 +884,4 @@ export {
884
884
  looksLikeBoxesAndLines,
885
885
  parseBoxesAndLines
886
886
  };
887
- //# sourceMappingURL=chunk-KV6Y2HE6.js.map
887
+ //# sourceMappingURL=chunk-DSWVNQVS.js.map
@@ -10,7 +10,7 @@ import {
10
10
  tagAttrKey,
11
11
  validateTagGroupNames,
12
12
  validateTagValues
13
- } from "./chunk-HBVD67XG.js";
13
+ } from "./chunk-FJUNPCYI.js";
14
14
  import {
15
15
  parseInArrowLabel
16
16
  } from "./chunk-FFUN5D66.js";
@@ -26,7 +26,7 @@ import {
26
26
  stripQuotes,
27
27
  warnUnknownMetaKeys,
28
28
  withTagAliases
29
- } from "./chunk-ZNQX6QWH.js";
29
+ } from "./chunk-OTAL43EH.js";
30
30
  import {
31
31
  NAME_DIAGNOSTIC_CODES,
32
32
  formatDgmoError,
@@ -407,6 +407,11 @@ function parseSketch(content, palette) {
407
407
  currentTagGroup.entries.push({
408
408
  value: label,
409
409
  color: color ?? AUTO_TAG_COLOR_SENTINEL,
410
+ // When a color resolved, the recognized name is the entry's last
411
+ // token — keep it so a reparse can tell authored from auto.
412
+ ...color !== void 0 && {
413
+ authoredColor: cleanEntry.trim().split(/\s+/).pop()
414
+ },
410
415
  lineNumber
411
416
  });
412
417
  }
@@ -427,6 +432,11 @@ function parseSketch(content, palette) {
427
432
  currentTagGroup.entries.push({
428
433
  value: label,
429
434
  color: color ?? AUTO_TAG_COLOR_SENTINEL,
435
+ // When a color resolved, the recognized name is the entry's last token
436
+ // — keep it so a reparse can tell authored from auto.
437
+ ...color !== void 0 && {
438
+ authoredColor: cleanEntry.trim().split(/\s+/).pop()
439
+ },
430
440
  lineNumber
431
441
  });
432
442
  continue;
@@ -604,4 +614,4 @@ export {
604
614
  isSketchShapeKind,
605
615
  parseSketch
606
616
  };
607
- //# sourceMappingURL=chunk-4YNP6O47.js.map
617
+ //# sourceMappingURL=chunk-DZXYF2F5.js.map
@@ -14,7 +14,7 @@ import {
14
14
  tagAttrKey,
15
15
  validateTagGroupNames,
16
16
  validateTagValues
17
- } from "./chunk-HBVD67XG.js";
17
+ } from "./chunk-FJUNPCYI.js";
18
18
  import {
19
19
  normalizeName
20
20
  } from "./chunk-NOTA6TEI.js";
@@ -25,7 +25,7 @@ import {
25
25
  splitNameAndMeta,
26
26
  warnUnknownMetaKeys,
27
27
  withTagAliases
28
- } from "./chunk-ZNQX6QWH.js";
28
+ } from "./chunk-OTAL43EH.js";
29
29
  import {
30
30
  emit,
31
31
  makeDgmoError,
@@ -1152,4 +1152,4 @@ export {
1152
1152
  extractPertSymbols,
1153
1153
  looksLikePert
1154
1154
  };
1155
- //# sourceMappingURL=chunk-FUCAB3KQ.js.map
1155
+ //# sourceMappingURL=chunk-EAMEADTV.js.map