@diagrammo/dgmo 0.8.17 → 0.8.19
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/cli.cjs +103 -103
- package/dist/editor.cjs +1 -1
- package/dist/editor.cjs.map +1 -1
- package/dist/editor.js +1 -1
- package/dist/editor.js.map +1 -1
- package/dist/highlight.cjs +1 -1
- package/dist/highlight.cjs.map +1 -1
- package/dist/highlight.js +1 -1
- package/dist/highlight.js.map +1 -1
- package/dist/index.cjs +1306 -146
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +120 -15
- package/dist/index.d.ts +120 -15
- package/dist/index.js +1325 -151
- package/dist/index.js.map +1 -1
- package/docs/guide/how-dgmo-thinks.md +277 -0
- package/docs/guide/registry.json +1 -0
- package/gallery/fixtures/gantt-sprints.dgmo +20 -0
- package/package.json +1 -1
- package/src/colors.ts +1 -1
- package/src/editor/dgmo.grammar +1 -1
- package/src/editor/dgmo.grammar.js +1 -1
- package/src/gantt/calculator.ts +120 -7
- package/src/gantt/parser.ts +98 -3
- package/src/gantt/renderer.ts +410 -95
- package/src/gantt/types.ts +23 -2
- package/src/index.ts +10 -2
- package/src/sequence/collapse.ts +169 -0
- package/src/sequence/parser.ts +14 -2
- package/src/sequence/renderer.ts +186 -49
- package/src/sharing.ts +86 -49
- package/src/utils/duration.ts +16 -2
- package/src/utils/legend-constants.ts +11 -0
- package/src/utils/legend-d3.ts +171 -0
- package/src/utils/legend-layout.ts +148 -17
- package/src/utils/legend-types.ts +45 -0
package/src/gantt/parser.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
MULTIPLE_PIPE_ERROR,
|
|
18
18
|
parseFirstLine,
|
|
19
19
|
} from '../utils/parsing';
|
|
20
|
-
import { parseOffset } from '../utils/duration';
|
|
20
|
+
import { parseOffset, parseDuration } from '../utils/duration';
|
|
21
21
|
import type { PaletteColors } from '../palettes';
|
|
22
22
|
import { getSeriesColors } from '../palettes';
|
|
23
23
|
import type {
|
|
@@ -35,14 +35,14 @@ import type {
|
|
|
35
35
|
// ── Regexes ─────────────────────────────────────────────────
|
|
36
36
|
|
|
37
37
|
/** Duration task: `30d Label`, `1.5w Label`, `10bd? Label`, `2h Label`, `90min Label` */
|
|
38
|
-
const DURATION_RE = /^(\d+(?:\.\d+)?)(min|bd|d|w|m|q|y|h)(\?)?\s+(.+)$/;
|
|
38
|
+
const DURATION_RE = /^(\d+(?:\.\d+)?)(min|bd|d|w|m|q|y|h|s)(\?)?\s+(.+)$/;
|
|
39
39
|
|
|
40
40
|
/** Explicit date task: `2024-01-15 Label` or `2024-01-15 14:30 Label` */
|
|
41
41
|
const EXPLICIT_DATE_RE = /^(\d{4}-\d{2}-\d{2}(?: \d{2}:\d{2})?)\s+(.+)$/;
|
|
42
42
|
|
|
43
43
|
/** Timeline migration syntax: `2024-01-15 -> 30d Label` or `2024-01-15 14:30 -> 2h Label` */
|
|
44
44
|
const TIMELINE_DURATION_RE =
|
|
45
|
-
/^(\d{4}-\d{2}-\d{2}(?: \d{2}:\d{2})?)\s*(?:->|\u2013>)\s*(\d+(?:\.\d+)?)(min|bd|d|w|m|q|y|h)(\?)?\s+(.+)$/;
|
|
45
|
+
/^(\d{4}-\d{2}-\d{2}(?: \d{2}:\d{2})?)\s*(?:->|\u2013>)\s*(\d+(?:\.\d+)?)(min|bd|d|w|m|q|y|h|s)(\?)?\s+(.+)$/;
|
|
46
46
|
|
|
47
47
|
/** Group container: `[GroupName]` with optional pipe metadata */
|
|
48
48
|
const GROUP_RE = /^\[(.+?)\]\s*(.*)$/;
|
|
@@ -138,6 +138,10 @@ export function parseGantt(
|
|
|
138
138
|
activeTag: null,
|
|
139
139
|
optionLineNumbers: {},
|
|
140
140
|
holidaysLineNumber: null,
|
|
141
|
+
sprintLength: null,
|
|
142
|
+
sprintNumber: null,
|
|
143
|
+
sprintStart: null,
|
|
144
|
+
sprintMode: null,
|
|
141
145
|
},
|
|
142
146
|
diagnostics,
|
|
143
147
|
error: null,
|
|
@@ -650,6 +654,57 @@ export function parseGantt(
|
|
|
650
654
|
case 'active-tag':
|
|
651
655
|
result.options.activeTag = value;
|
|
652
656
|
break;
|
|
657
|
+
case 'sprint-length': {
|
|
658
|
+
const dur = parseDuration(value);
|
|
659
|
+
if (!dur) {
|
|
660
|
+
warn(
|
|
661
|
+
lineNumber,
|
|
662
|
+
`Invalid sprint-length value: "${value}". Expected a duration like "2w" or "10d".`
|
|
663
|
+
);
|
|
664
|
+
} else if (dur.unit !== 'd' && dur.unit !== 'w') {
|
|
665
|
+
warn(
|
|
666
|
+
lineNumber,
|
|
667
|
+
`sprint-length only accepts "d" or "w" units, got "${dur.unit}".`
|
|
668
|
+
);
|
|
669
|
+
} else if (dur.amount <= 0) {
|
|
670
|
+
warn(lineNumber, `sprint-length must be greater than 0.`);
|
|
671
|
+
} else if (
|
|
672
|
+
!Number.isInteger(dur.amount * (dur.unit === 'w' ? 7 : 1))
|
|
673
|
+
) {
|
|
674
|
+
warn(
|
|
675
|
+
lineNumber,
|
|
676
|
+
`sprint-length must resolve to a whole number of days.`
|
|
677
|
+
);
|
|
678
|
+
} else {
|
|
679
|
+
result.options.sprintLength = dur;
|
|
680
|
+
}
|
|
681
|
+
break;
|
|
682
|
+
}
|
|
683
|
+
case 'sprint-number': {
|
|
684
|
+
const n = Number(value);
|
|
685
|
+
if (!Number.isFinite(n) || !Number.isInteger(n) || n <= 0) {
|
|
686
|
+
warn(
|
|
687
|
+
lineNumber,
|
|
688
|
+
`sprint-number must be a positive integer, got "${value}".`
|
|
689
|
+
);
|
|
690
|
+
} else {
|
|
691
|
+
result.options.sprintNumber = n;
|
|
692
|
+
}
|
|
693
|
+
break;
|
|
694
|
+
}
|
|
695
|
+
case 'sprint-start': {
|
|
696
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) {
|
|
697
|
+
warn(
|
|
698
|
+
lineNumber,
|
|
699
|
+
`sprint-start requires a full date (YYYY-MM-DD), got "${value}".`
|
|
700
|
+
);
|
|
701
|
+
} else if (Number.isNaN(new Date(value + 'T00:00:00').getTime())) {
|
|
702
|
+
warn(lineNumber, `sprint-start is not a valid date: "${value}".`);
|
|
703
|
+
} else {
|
|
704
|
+
result.options.sprintStart = value;
|
|
705
|
+
}
|
|
706
|
+
break;
|
|
707
|
+
}
|
|
653
708
|
}
|
|
654
709
|
continue;
|
|
655
710
|
}
|
|
@@ -879,6 +934,31 @@ export function parseGantt(
|
|
|
879
934
|
|
|
880
935
|
validateTagGroupNames(result.tagGroups, warn);
|
|
881
936
|
|
|
937
|
+
// ── Sprint mode detection ──────────────────────────────
|
|
938
|
+
const hasSprintOption =
|
|
939
|
+
result.options.sprintLength !== null ||
|
|
940
|
+
result.options.sprintNumber !== null ||
|
|
941
|
+
result.options.sprintStart !== null;
|
|
942
|
+
|
|
943
|
+
const hasSprintUnit = hasSprintDurationUnit(result.nodes);
|
|
944
|
+
|
|
945
|
+
if (hasSprintOption) {
|
|
946
|
+
result.options.sprintMode = 'explicit';
|
|
947
|
+
} else if (hasSprintUnit) {
|
|
948
|
+
result.options.sprintMode = 'auto';
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// Apply defaults when sprint mode is active
|
|
952
|
+
if (result.options.sprintMode) {
|
|
953
|
+
if (!result.options.sprintLength) {
|
|
954
|
+
result.options.sprintLength = { amount: 2, unit: 'w' };
|
|
955
|
+
}
|
|
956
|
+
if (result.options.sprintNumber === null) {
|
|
957
|
+
result.options.sprintNumber = 1;
|
|
958
|
+
}
|
|
959
|
+
// sprintStart defaults to chart start or today — handled in calculator
|
|
960
|
+
}
|
|
961
|
+
|
|
882
962
|
return result;
|
|
883
963
|
|
|
884
964
|
// ── Helper: create a task ───────────────────────────────
|
|
@@ -1041,6 +1121,9 @@ const KNOWN_OPTIONS = new Set([
|
|
|
1041
1121
|
'chart',
|
|
1042
1122
|
'sort',
|
|
1043
1123
|
'active-tag',
|
|
1124
|
+
'sprint-length',
|
|
1125
|
+
'sprint-number',
|
|
1126
|
+
'sprint-start',
|
|
1044
1127
|
]);
|
|
1045
1128
|
|
|
1046
1129
|
/** Boolean options that can appear as bare keywords or with `no-` prefix. */
|
|
@@ -1053,3 +1136,15 @@ const KNOWN_BOOLEANS = new Set([
|
|
|
1053
1136
|
function isKnownOption(key: string): boolean {
|
|
1054
1137
|
return KNOWN_OPTIONS.has(key);
|
|
1055
1138
|
}
|
|
1139
|
+
|
|
1140
|
+
/** Check if any task in the tree uses the `s` (sprint) duration unit. */
|
|
1141
|
+
function hasSprintDurationUnit(nodes: GanttNode[]): boolean {
|
|
1142
|
+
for (const node of nodes) {
|
|
1143
|
+
if (node.kind === 'task') {
|
|
1144
|
+
if (node.duration?.unit === 's') return true;
|
|
1145
|
+
} else if (node.kind === 'group' || node.kind === 'parallel') {
|
|
1146
|
+
if (hasSprintDurationUnit(node.children)) return true;
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
return false;
|
|
1150
|
+
}
|