@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.
- package/dist/advanced.cjs +31 -25
- package/dist/advanced.d.cts +3 -855
- package/dist/advanced.d.ts +3 -855
- package/dist/advanced.js +541 -70101
- package/dist/analyzer-UYKBXAKR.js +15 -0
- package/dist/auto.cjs +500 -341
- package/dist/auto.css +342 -159
- package/dist/auto.d.cts +10 -8
- package/dist/auto.d.ts +10 -8
- package/dist/auto.js +373 -265
- package/dist/auto.mjs +500 -341
- package/dist/block.cjs +31 -25
- package/dist/block.js +83 -69411
- package/dist/calculator-LDYQCDDY.js +11 -0
- package/dist/charts-d3-QOZHKTCT.js +25 -0
- package/dist/chunk-2DXMZRWJ.js +800 -0
- package/dist/chunk-2LACINWN.js +786 -0
- package/dist/chunk-33LCUH4H.js +893 -0
- package/dist/chunk-3CIOJ5YJ.js +35 -0
- package/dist/chunk-3HDBAXF5.js +86 -0
- package/dist/chunk-3JLKYGBQ.js +290 -0
- package/dist/chunk-3MQQNXPD.js +415 -0
- package/dist/chunk-3R5POCTZ.js +967 -0
- package/dist/chunk-3SMGIJDD.js +112 -0
- package/dist/chunk-44CM72SQ.js +409 -0
- package/dist/chunk-4GRI7MEB.js +1604 -0
- package/dist/chunk-4OHACBGX.js +606 -0
- package/dist/chunk-5DH3KYFH.js +21 -0
- package/dist/chunk-5MLYVTYM.js +76 -0
- package/dist/chunk-5QXL4NYS.js +553 -0
- package/dist/chunk-5WRI5ZAA.js +31 -0
- package/dist/chunk-6EK55ART.js +117 -0
- package/dist/chunk-6FZYCKXB.js +2065 -0
- package/dist/chunk-6HO5ZTXK.js +277 -0
- package/dist/chunk-6KFWC4CO.js +7 -0
- package/dist/chunk-6MTWIQVO.js +121 -0
- package/dist/chunk-6NYWYNBI.js +329 -0
- package/dist/chunk-6SM5NJQH.js +620 -0
- package/dist/chunk-725LDASD.js +422 -0
- package/dist/chunk-76OWZ3BA.js +130 -0
- package/dist/chunk-7JEGTRLD.js +338 -0
- package/dist/chunk-A44USUV7.js +923 -0
- package/dist/chunk-A4GOY3PE.js +25 -0
- package/dist/chunk-A4VFQH5G.js +251 -0
- package/dist/chunk-AELOBFW5.js +375 -0
- package/dist/chunk-AN2MOO5T.js +522 -0
- package/dist/chunk-BMR4CIEO.js +41 -0
- package/dist/chunk-BS7SV7C3.js +51 -0
- package/dist/chunk-BUPDIHML.js +613 -0
- package/dist/chunk-BUVJFRPY.js +887 -0
- package/dist/chunk-C3Z4DX3V.js +112 -0
- package/dist/chunk-CI2G3OEB.js +1818 -0
- package/dist/chunk-CKNVO24D.js +54 -0
- package/dist/chunk-CUVHQHZ7.js +391 -0
- package/dist/chunk-CXK4DZH3.js +114 -0
- package/dist/chunk-DKEPS5LH.js +315 -0
- package/dist/chunk-DU7W62N5.js +487 -0
- package/dist/chunk-DZAQBW35.js +751 -0
- package/dist/chunk-EB6FPQUP.js +316 -0
- package/dist/chunk-EMS2SK26.js +376 -0
- package/dist/chunk-ERLBPDGU.js +510 -0
- package/dist/chunk-EVCVDTXE.js +732 -0
- package/dist/chunk-FCIIHT24.js +384 -0
- package/dist/chunk-FFUN5D66.js +97 -0
- package/dist/chunk-FITOLXSX.js +714 -0
- package/dist/chunk-FMDSF3OV.js +68 -0
- package/dist/chunk-FNB3PNGF.js +410 -0
- package/dist/chunk-G2H74XJZ.js +2104 -0
- package/dist/chunk-GMR5MFHJ.js +339 -0
- package/dist/chunk-H6PI3KJT.js +305 -0
- package/dist/chunk-I46X5VUA.js +59 -0
- package/dist/chunk-I5IGB56C.js +255 -0
- package/dist/chunk-IH6ZMVQ5.js +3950 -0
- package/dist/chunk-IJZFN3HM.js +463 -0
- package/dist/chunk-IPWPWM6R.js +3079 -0
- package/dist/chunk-IYULMRBE.js +23 -0
- package/dist/chunk-IZMRON6C.js +167 -0
- package/dist/chunk-J5FIXQRT.js +813 -0
- package/dist/chunk-JED6ZDEE.js +73 -0
- package/dist/chunk-JEUJOX5X.js +136 -0
- package/dist/chunk-JM4LEPY3.js +436 -0
- package/dist/chunk-L3UHP6TD.js +101 -0
- package/dist/chunk-L66GEFB6.js +524 -0
- package/dist/chunk-LIOHW36Z.js +469 -0
- package/dist/chunk-LP7EC4MI.js +16 -0
- package/dist/chunk-MITI6NOL.js +548 -0
- package/dist/chunk-MO5YHHMQ.js +168 -0
- package/dist/chunk-MZSBFAPJ.js +885 -0
- package/dist/chunk-NNAAJVBU.js +9 -0
- package/dist/chunk-NOTA6TEI.js +47 -0
- package/dist/chunk-NURGB5Z4.js +335 -0
- package/dist/chunk-NX4EQS3U.js +1062 -0
- package/dist/chunk-NXMESY4J.js +1 -0
- package/dist/chunk-OJR3MQYV.js +1458 -0
- package/dist/chunk-OURHMODR.js +454 -0
- package/dist/chunk-P235SVAH.js +1057 -0
- package/dist/chunk-P4RH4OSP.js +1038 -0
- package/dist/chunk-P6T66CCZ.js +226 -0
- package/dist/chunk-PBAHEPLQ.js +223 -0
- package/dist/chunk-PBHE5UG6.js +1530 -0
- package/dist/chunk-PDKUANDZ.js +35 -0
- package/dist/chunk-PWIHZ6NJ.js +296 -0
- package/dist/chunk-QEBUY5NY.js +1685 -0
- package/dist/chunk-QLCCJEJI.js +253 -0
- package/dist/chunk-QOOUC2J5.js +52 -0
- package/dist/chunk-QYTPPDAO.js +402 -0
- package/dist/chunk-R3XI2VC7.js +801 -0
- package/dist/chunk-RCERWOJR.js +154 -0
- package/dist/chunk-RJE5JTVK.js +362 -0
- package/dist/chunk-RTLBSQ3G.js +1155 -0
- package/dist/chunk-RUNNI6VE.js +448 -0
- package/dist/chunk-RVMRZAPB.js +354 -0
- package/dist/chunk-RYEGFMUO.js +955 -0
- package/dist/chunk-RZCF2VVM.js +528 -0
- package/dist/chunk-SML67VPV.js +1025 -0
- package/dist/chunk-SQ7IY53Q.js +44 -0
- package/dist/chunk-SQAG3UXH.js +161 -0
- package/dist/chunk-SRTU6HMQ.js +1851 -0
- package/dist/chunk-T2OE3YQB.js +550 -0
- package/dist/chunk-T3UBLACL.js +299 -0
- package/dist/chunk-TLVIHFRO.js +296 -0
- package/dist/chunk-TYS6CSS5.js +52 -0
- package/dist/chunk-U6EQI3U6.js +130 -0
- package/dist/chunk-UJ4FJLBF.js +86 -0
- package/dist/chunk-ULOEATBZ.js +347 -0
- package/dist/chunk-UNCCZ3NU.js +127 -0
- package/dist/chunk-USZW2HHU.js +197 -0
- package/dist/chunk-UWN33VNX.js +1610 -0
- package/dist/chunk-UZ7EZW3B.js +40 -0
- package/dist/chunk-VOKGH627.js +37 -0
- package/dist/chunk-WBRZJOEC.js +204 -0
- package/dist/chunk-WCSOJFU3.js +380 -0
- package/dist/chunk-WCT3NYCV.js +160 -0
- package/dist/chunk-WVAJFAIA.js +529 -0
- package/dist/chunk-X5LCYCL5.js +394 -0
- package/dist/chunk-XAKEUMEJ.js +1256 -0
- package/dist/chunk-Y2ZE3MSG.js +590 -0
- package/dist/chunk-Y3J7VR52.js +646 -0
- package/dist/chunk-Y5QGVTVC.js +33 -0
- package/dist/chunk-YAA6IID3.js +548 -0
- package/dist/chunk-YGJTDXVR.js +692 -0
- package/dist/chunk-YRYKTYMQ.js +186 -0
- package/dist/chunk-YYVTBZZC.js +61 -0
- package/dist/chunk-Z5CGSFJB.js +647 -0
- package/dist/chunk-Z72XRXD4.js +787 -0
- package/dist/chunk-ZGR7ULFJ.js +978 -0
- package/dist/chunk-ZJEL4H2R.js +851 -0
- package/dist/chunk-ZO27FGJS.js +554 -0
- package/dist/cli.cjs +112 -112
- package/dist/collapse-CLPJD2RL.js +11 -0
- package/dist/collapse-SLINJQW6.js +9 -0
- package/dist/collapse-ZWUFFCK2.js +9 -0
- package/dist/compute-G55RG53N.js +8 -0
- package/dist/dgmo-router-DZCIDUO5.js +73 -0
- package/dist/dimensions-J3FHIMJ6.js +22 -0
- package/dist/element.cjs +492 -325
- package/dist/element.js +367 -259
- package/dist/element.mjs +492 -325
- package/dist/flowchart-parser-ZNSKIBVR.js +21 -0
- package/dist/flowchart-renderer-ZAEOL4DX.js +35 -0
- package/dist/index.cjs +34 -28
- package/dist/index.d.cts +3 -469
- package/dist/index.d.ts +3 -469
- package/dist/index.js +137 -69679
- package/dist/layout-46N4JJYK.js +17 -0
- package/dist/layout-5RA6QWR6.js +26 -0
- package/dist/layout-5T6RH5M6.js +14 -0
- package/dist/layout-7QXCNOVS.js +13 -0
- package/dist/layout-EE6GE46Y.js +17 -0
- package/dist/layout-G23F7LDH.js +9 -0
- package/dist/layout-HRBZPFCN.js +23 -0
- package/dist/layout-HWDSRX5E.js +20 -0
- package/dist/layout-HYZPWAK5.js +18 -0
- package/dist/layout-N76NR4ZO.js +19 -0
- package/dist/layout-OB3RI63S.js +14 -0
- package/dist/layout-S2QBYSK2.js +15 -0
- package/dist/layout-UM5F4DJB.js +15 -0
- package/dist/layout-search-OYV77HHS.js +1655 -0
- package/dist/load-data-EHDDZ5ZS.js +8 -0
- package/dist/palettes-PRJ2RI6D.js +56 -0
- package/dist/parser-2MFP2H2E.js +11 -0
- package/dist/parser-3STE62GB.js +21 -0
- package/dist/parser-4FL2CMDG.js +18 -0
- package/dist/parser-4OGOBJJ4.js +13 -0
- package/dist/parser-6BTRLKRZ.js +15 -0
- package/dist/parser-AQETEVRW.js +21 -0
- package/dist/parser-CFZD5IBL.js +12 -0
- package/dist/parser-FUSKFGZN.js +16 -0
- package/dist/parser-I6KXEYFK.js +13 -0
- package/dist/parser-IXSZZQHY.js +18 -0
- package/dist/parser-JAL2HD4I.js +13 -0
- package/dist/parser-KNSQSKQO.js +20 -0
- package/dist/parser-N5O4IHUN.js +13 -0
- package/dist/parser-NGU3ETO6.js +16 -0
- package/dist/parser-NRAI6O25.js +19 -0
- package/dist/parser-O5J4VBII.js +11 -0
- package/dist/parser-OV7NOBW6.js +21 -0
- package/dist/parser-PQ3POX45.js +23 -0
- package/dist/parser-TFZFBVWN.js +11 -0
- package/dist/parser-TRTHDFPP.js +18 -0
- package/dist/parser-VQP2UJ6W.js +11 -0
- package/dist/parser-XDVELHRK.js +13 -0
- package/dist/parser-XKRP7QKP.js +11 -0
- package/dist/parser-Y6WTBU76.js +14 -0
- package/dist/parser-ZSDPZYQP.js +12 -0
- package/dist/renderer-2XQQQ6QR.js +28 -0
- package/dist/renderer-5NDVNDAZ.js +26 -0
- package/dist/renderer-6EEZHMH4.js +26 -0
- package/dist/renderer-6W5462RB.js +43 -0
- package/dist/renderer-7MVLWWQD.js +22 -0
- package/dist/renderer-AWWAF6XD.js +33 -0
- package/dist/renderer-BYCNMBF7.js +34 -0
- package/dist/renderer-CLJHQPBJ.js +29 -0
- package/dist/renderer-GHPZMFU2.js +15 -0
- package/dist/renderer-JGBKUCZD.js +16 -0
- package/dist/renderer-KQB7UGDS.js +19 -0
- package/dist/renderer-PGX2TKVS.js +24 -0
- package/dist/renderer-QIWVHWZO.js +15 -0
- package/dist/renderer-RPOA5YPZ.js +35 -0
- package/dist/renderer-SMIBCRVB.js +24 -0
- package/dist/renderer-T7YKC5VP.js +28 -0
- package/dist/renderer-TOCOVLHS.js +37 -0
- package/dist/renderer-UWA5XS74.js +39 -0
- package/dist/renderer-VACVQYML.js +25 -0
- package/dist/renderer-W4M6QLIJ.js +37 -0
- package/dist/renderer-WZRREQ2P.js +23 -0
- package/dist/renderer-YY2OSF6E.js +27 -0
- package/dist/renderer-Z7I3W2PP.js +24 -0
- package/dist/renderer-ZGNTUWC4.js +22 -0
- package/dist/renderer-ZTR3DER3.js +19 -0
- package/dist/renderer-radial-C32GPJQ7.js +21 -0
- package/dist/resolver-NOAA7ID7.js +13 -0
- package/dist/state-collapse-HCGD6IVJ.js +8 -0
- package/dist/state-parser-Z2V23ATR.js +18 -0
- package/dist/state-renderer-RFYHSP4K.js +34 -0
- package/dist/themes-1-CuKpeH.d.cts +908 -0
- package/dist/themes-1-CuKpeH.d.ts +908 -0
- package/package.json +1 -1
- package/src/auto/index.ts +55 -57
- package/src/auto/shared.ts +142 -142
- package/src/auto/styles.ts +44 -199
- package/src/c4/renderer.ts +2 -2
- package/src/element/index.ts +29 -21
- package/src/infra/renderer.ts +1 -1
- package/src/render.ts +34 -14
- package/src/sitemap/renderer.ts +1 -1
- package/src/timeline/renderer.ts +1 -1
- package/src/utils/hover-styles.ts +6 -1
- package/src/utils/legend-d3.ts +1 -4
- 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
|