@nowline/export-mermaid 0.8.6 → 0.9.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/README.md +14 -2
- package/dist/duration.d.ts +3 -4
- package/dist/duration.d.ts.map +1 -1
- package/dist/duration.js +11 -41
- package/dist/duration.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +220 -57
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/src/duration.ts +11 -42
- package/src/index.ts +287 -59
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ nowline roadmap.nowline -o roadmap.md # extension-inferred
|
|
|
47
47
|
gantt
|
|
48
48
|
title <title>
|
|
49
49
|
dateFormat YYYY-MM-DD
|
|
50
|
-
|
|
50
|
+
excludes saturday, sunday
|
|
51
51
|
section <swimlane>
|
|
52
52
|
Item one : done, item-one, 2026-01-06, 5d
|
|
53
53
|
Item two : active, item-two, after item-one, 10d
|
|
@@ -57,7 +57,19 @@ gantt
|
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
The first line of the Markdown is the roadmap title. The fenced
|
|
60
|
-
```` ```mermaid ```` block contains a valid `gantt` diagram
|
|
60
|
+
```` ```mermaid ```` block contains a valid `gantt` diagram. Under
|
|
61
|
+
`calendar:business` (the default) `excludes saturday, sunday` follows
|
|
62
|
+
`dateFormat`, so Mermaid counts each `Nd` in working days like the chart;
|
|
63
|
+
`calendar:full` and `calendar:custom` have no days off and emit no
|
|
64
|
+
`excludes` line, unless the file declares days off: each day of a
|
|
65
|
+
`non-working` closure follows the weekday names as an ISO date
|
|
66
|
+
(`excludes saturday, sunday, 2026-11-26, 2026-11-27`). A `working`
|
|
67
|
+
exception can't be written, so its days are counted as `working-day` in the
|
|
68
|
+
`%%` comment. Durations are the chart's own day count for the item
|
|
69
|
+
(sizes, `q` and `capacity:` included), written as `Nd` with up to two
|
|
70
|
+
decimals (`10d`, `7.5d`), so a `full` `4w` is `28d`. The roadmap start and
|
|
71
|
+
wave-end milestones fall on working days; anchor and milestone dates are
|
|
72
|
+
written as declared. The trailing
|
|
61
73
|
`%%` comment line lists Nowline features that don't have a Mermaid
|
|
62
74
|
equivalent and have been dropped.
|
|
63
75
|
|
package/dist/duration.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Returns `undefined`
|
|
4
|
-
* and Mermaid uses its default 1d.
|
|
2
|
+
* `Nd` with up to two decimals, trailing zeros trimmed (`7.5d`, `7.33d`).
|
|
3
|
+
* Returns `undefined` for no duration; the caller falls back to `1d`.
|
|
5
4
|
*/
|
|
6
|
-
export declare function
|
|
5
|
+
export declare function daysToMermaid(days: number | undefined): string | undefined;
|
|
7
6
|
//# sourceMappingURL=duration.d.ts.map
|
package/dist/duration.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duration.d.ts","sourceRoot":"","sources":["../src/duration.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"duration.d.ts","sourceRoot":"","sources":["../src/duration.ts"],"names":[],"mappings":"AASA;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAI1E"}
|
package/dist/duration.js
CHANGED
|
@@ -1,49 +1,19 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
1
|
+
// Mermaid task durations. The day count is engine C's `ScheduledItem.days`
|
|
2
|
+
// under the file's calendar (specs/working-calendar.md §8), so sizes,
|
|
3
|
+
// `capacity:` and every unit match the chart. It is always written as `Nd`:
|
|
4
|
+
// with the business `excludes` Mermaid counts those in working days, and a
|
|
5
|
+
// full-calendar `4w` becomes `28d`, the same span.
|
|
3
6
|
//
|
|
4
7
|
// Spec: specs/handoffs/m2c.md § 6 + the bridge rules in
|
|
5
8
|
// specs/rendering.md § Markdown+Mermaid Bridge.
|
|
6
|
-
const SIZE_BUCKET_DAYS = {
|
|
7
|
-
xs: 1,
|
|
8
|
-
sm: 3,
|
|
9
|
-
s: 3,
|
|
10
|
-
md: 5,
|
|
11
|
-
m: 5,
|
|
12
|
-
lg: 10,
|
|
13
|
-
l: 10,
|
|
14
|
-
xl: 15,
|
|
15
|
-
};
|
|
16
|
-
const NUMERIC_RE = /^(\d+(?:\.\d+)?)\s*(d|w|m|y)?$/i;
|
|
17
9
|
/**
|
|
18
|
-
*
|
|
19
|
-
* Returns `undefined`
|
|
20
|
-
* and Mermaid uses its default 1d.
|
|
10
|
+
* `Nd` with up to two decimals, trailing zeros trimmed (`7.5d`, `7.33d`).
|
|
11
|
+
* Returns `undefined` for no duration; the caller falls back to `1d`.
|
|
21
12
|
*/
|
|
22
|
-
export function
|
|
23
|
-
if (!
|
|
13
|
+
export function daysToMermaid(days) {
|
|
14
|
+
if (days === undefined || !(days > 0))
|
|
24
15
|
return undefined;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return undefined;
|
|
28
|
-
// Size buckets resolve to working-day counts.
|
|
29
|
-
if (trimmed in SIZE_BUCKET_DAYS) {
|
|
30
|
-
return `${SIZE_BUCKET_DAYS[trimmed]}d`;
|
|
31
|
-
}
|
|
32
|
-
const match = NUMERIC_RE.exec(trimmed);
|
|
33
|
-
if (!match)
|
|
34
|
-
return undefined;
|
|
35
|
-
const value = match[1];
|
|
36
|
-
const unit = (match[2] ?? 'd').toLowerCase();
|
|
37
|
-
if (unit === 'd' || unit === 'w')
|
|
38
|
-
return `${value}${unit}`;
|
|
39
|
-
if (unit === 'm') {
|
|
40
|
-
const days = Math.round(Number(value) * 22);
|
|
41
|
-
return `${days}d`;
|
|
42
|
-
}
|
|
43
|
-
if (unit === 'y') {
|
|
44
|
-
const days = Math.round(Number(value) * 252);
|
|
45
|
-
return `${days}d`;
|
|
46
|
-
}
|
|
47
|
-
return undefined;
|
|
16
|
+
// parseFloat strips trailing zeros: `7.50` → `7.5`.
|
|
17
|
+
return `${parseFloat(days.toFixed(2))}d`;
|
|
48
18
|
}
|
|
49
19
|
//# sourceMappingURL=duration.js.map
|
package/dist/duration.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duration.js","sourceRoot":"","sources":["../src/duration.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"duration.js","sourceRoot":"","sources":["../src/duration.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,sEAAsE;AACtE,4EAA4E;AAC5E,2EAA2E;AAC3E,mDAAmD;AACnD,EAAE;AACF,wDAAwD;AACxD,gDAAgD;AAEhD;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,IAAwB;IAClD,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACxD,oDAAoD;IACpD,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAC7C,CAAC"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAYzD,MAAM,WAAW,cAAc;IAC3B,gEAAgE;IAChE,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAiED,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,GAAE,cAAmB,GAAG,MAAM,CA6ExF"}
|
package/dist/index.js
CHANGED
|
@@ -16,13 +16,23 @@
|
|
|
16
16
|
// gantt
|
|
17
17
|
// title <title>
|
|
18
18
|
// dateFormat YYYY-MM-DD
|
|
19
|
-
//
|
|
19
|
+
// excludes saturday, sunday (only when the open week has days off)
|
|
20
20
|
// section <swimlane>
|
|
21
21
|
// <Task name>: <status>, <id>, <after-or-date>, <duration>
|
|
22
22
|
// ```
|
|
23
23
|
//
|
|
24
24
|
// <%% lossy comment %%>
|
|
25
25
|
//
|
|
26
|
+
// Calendar (specs/working-calendar.md §8): the file's calendar comes from
|
|
27
|
+
// engine C (`scheduleRoadmap`, built once per export). `excludes` lists the
|
|
28
|
+
// open week's non-working days, Monday first, so Mermaid counts `Nd` in
|
|
29
|
+
// working days; every duration is engine C's `days` written as `Nd` (a
|
|
30
|
+
// full-calendar `4w` is `28d`). Mermaid never checks a task's explicit start
|
|
31
|
+
// against `excludes`, so the dates this exporter derives are working days:
|
|
32
|
+
// the roadmap start is snapped to its first working day, and a wave-end
|
|
33
|
+
// milestone is the first working day at or after the wave's exclusive end.
|
|
34
|
+
// Declared anchor and milestone dates are written as given.
|
|
35
|
+
//
|
|
26
36
|
// Every emitted task carries an explicit start token (`after <id>` or an
|
|
27
37
|
// absolute `YYYY-MM-DD` date). Mermaid's positional task parser strips a
|
|
28
38
|
// leading status keyword (`done`/`active`/`crit`/`milestone`) and then reads
|
|
@@ -31,13 +41,22 @@
|
|
|
31
41
|
// start (`:done, my-id, 2w`) collapses to two fields after the status strip,
|
|
32
42
|
// so Mermaid mis-reads the id as a start date and throws `Invalid date: my-id`
|
|
33
43
|
// at render time. To keep an explicit id we therefore MUST emit a start token:
|
|
34
|
-
// - declared `after:` deps
|
|
35
|
-
//
|
|
36
|
-
//
|
|
44
|
+
// - `after <ids>`: the declared `after:` deps (a group or parallel id
|
|
45
|
+
// expanded to the tasks that end it; neither is a Mermaid task), then the
|
|
46
|
+
// lane chain: the previous item in the lane, or every track end when it
|
|
47
|
+
// follows a parallel; a first child also gets its group's or parallel's
|
|
48
|
+
// own `after:`. Engine C starts an item at `max(prevEnd, ...after)`.
|
|
49
|
+
// - with none of those, a lane/track leader -> the roadmap start date
|
|
50
|
+
// - a member of wave k >= 2 also gets `after <wave k-1 id>`: appended to
|
|
51
|
+
// its `after` token, or replacing a lane/track leader's start date
|
|
52
|
+
// (specs/waves.md §10)
|
|
37
53
|
// This mirrors Nowline's default "each item starts after the preceding item in
|
|
38
54
|
// its lane" semantics (specs/rendering.md § Item Bars).
|
|
55
|
+
import { isGroupBlock, isParallelBlock } from '@nowline/core';
|
|
56
|
+
import { parseIsoDate, trackChildren, trackNodes } from '@nowline/core/internal';
|
|
39
57
|
import { displayLabel, getProp, getProps, hasProp, roadmapTitle } from '@nowline/export-core';
|
|
40
|
-
import {
|
|
58
|
+
import { calendarExceptions, scheduleRoadmap, } from '@nowline/layout';
|
|
59
|
+
import { daysToMermaid } from './duration.js';
|
|
41
60
|
function emptyCounts() {
|
|
42
61
|
return {
|
|
43
62
|
labels: 0,
|
|
@@ -50,12 +69,16 @@ function emptyCounts() {
|
|
|
50
69
|
nestedSwimlanes: 0,
|
|
51
70
|
description: 0,
|
|
52
71
|
style: 0,
|
|
72
|
+
waveFloor: 0,
|
|
73
|
+
workingDay: 0,
|
|
53
74
|
};
|
|
54
75
|
}
|
|
55
76
|
export function exportMermaid(inputs, options = {}) {
|
|
56
77
|
const ast = inputs.ast;
|
|
57
78
|
const title = roadmapTitle(ast.roadmapDecl ?? undefined);
|
|
58
|
-
const
|
|
79
|
+
const schedule = inputs.schedule ?? scheduleRoadmap(ast, inputs.resolved, { today: inputs.today });
|
|
80
|
+
const { working } = schedule.calendar;
|
|
81
|
+
const startDate = formatIsoDate(working.dateAtWorkingIndex(resolveStartDate(inputs), 0));
|
|
59
82
|
const drops = emptyCounts();
|
|
60
83
|
const out = [];
|
|
61
84
|
out.push(`# ${title}`);
|
|
@@ -64,6 +87,11 @@ export function exportMermaid(inputs, options = {}) {
|
|
|
64
87
|
out.push('gantt');
|
|
65
88
|
out.push(` title ${escapeMermaidText(title)}`);
|
|
66
89
|
out.push(' dateFormat YYYY-MM-DD');
|
|
90
|
+
const exceptions = calendarExceptions(working, inputs.model.timeline.startDate, inputs.model.timeline.endDate);
|
|
91
|
+
const excludes = [...excludedWeekdays(working), ...excludedDates(exceptions)];
|
|
92
|
+
if (excludes.length > 0)
|
|
93
|
+
out.push(` excludes ${excludes.join(', ')}`);
|
|
94
|
+
drops.workingDay += workingDayCount(exceptions);
|
|
67
95
|
// Footnotes are file-level; counted once.
|
|
68
96
|
drops.footnote += ast.roadmapEntries.filter((e) => e.$type === 'FootnoteDeclaration').length;
|
|
69
97
|
// Anchors → milestone entries (Mermaid doesn't support standalone anchors).
|
|
@@ -78,17 +106,20 @@ export function exportMermaid(inputs, options = {}) {
|
|
|
78
106
|
out.push(` ${escapeTaskName(displayLabel(anchor))} :milestone, ${id}, ${date}, 0d`);
|
|
79
107
|
}
|
|
80
108
|
}
|
|
109
|
+
// Waves → one end milestone per wave, dated from the day schedule.
|
|
110
|
+
const waves = emitWaves(schedule, drops, out, startDate);
|
|
81
111
|
// Swimlanes → sections; their items become tasks.
|
|
82
112
|
const swimlanes = ast.roadmapEntries.filter((e) => e.$type === 'SwimlaneDeclaration');
|
|
113
|
+
const ctx = { startDate, schedule, waves, containers: namedContainers(swimlanes) };
|
|
83
114
|
for (const lane of swimlanes) {
|
|
84
|
-
emitSwimlane(lane, [lane.name ?? slugify(displayLabel(lane))], drops, out,
|
|
115
|
+
emitSwimlane(lane, [lane.name ?? slugify(displayLabel(lane))], drops, out, ctx);
|
|
85
116
|
}
|
|
86
117
|
// Top-level milestones.
|
|
87
118
|
const milestones = ast.roadmapEntries.filter((e) => e.$type === 'MilestoneDeclaration');
|
|
88
119
|
if (milestones.length > 0) {
|
|
89
120
|
out.push(' section Milestones');
|
|
90
121
|
for (const m of milestones) {
|
|
91
|
-
emitMilestone(m, drops, out,
|
|
122
|
+
emitMilestone(m, drops, out, ctx);
|
|
92
123
|
}
|
|
93
124
|
}
|
|
94
125
|
out.push('```');
|
|
@@ -101,33 +132,59 @@ export function exportMermaid(inputs, options = {}) {
|
|
|
101
132
|
}
|
|
102
133
|
return out.join('\n');
|
|
103
134
|
}
|
|
104
|
-
|
|
135
|
+
/**
|
|
136
|
+
* `section Waves` (specs/waves.md §10): `{title} (wave end) :milestone, {id},
|
|
137
|
+
* {date}, 0d` per wave, in declaration order. The date is the first working
|
|
138
|
+
* day at or after `E_k`, the wave's exclusive end from the day schedule: the
|
|
139
|
+
* instant Mermaid starts a task `after` the milestone, so `after:build` and
|
|
140
|
+
* the barrier tokens both open on the barrier, and on a working day, since
|
|
141
|
+
* Mermaid never moves an explicit date off an excluded day. Start floors
|
|
142
|
+
* cannot be expressed and are counted as drops. Returns undefined, emitting
|
|
143
|
+
* nothing, when the roadmap has no waves.
|
|
144
|
+
*/
|
|
145
|
+
function emitWaves(schedule, drops, out, startDate) {
|
|
146
|
+
const plan = schedule.plan;
|
|
147
|
+
if (!plan)
|
|
148
|
+
return undefined;
|
|
149
|
+
const { working } = schedule.calendar;
|
|
150
|
+
const ids = plan.waves.map((w) => w.name);
|
|
151
|
+
out.push(' section Waves');
|
|
152
|
+
plan.waves.forEach((w, i) => {
|
|
153
|
+
const end = schedule.waves?.get(ids[i])?.end;
|
|
154
|
+
const date = end ? formatIsoDate(working.dateAtWorkingIndex(end, 0)) : startDate;
|
|
155
|
+
out.push(` ${escapeTaskName(displayLabel(w))} (wave end) :milestone, ${ids[i]}, ${date}, 0d`);
|
|
156
|
+
if (getProps(w, 'after').length > 0)
|
|
157
|
+
drops.waveFloor += 1;
|
|
158
|
+
});
|
|
159
|
+
return { plan, ids };
|
|
160
|
+
}
|
|
161
|
+
function emitSwimlane(lane, breadcrumb, drops, out, ctx) {
|
|
105
162
|
const sectionLabel = breadcrumb.join('.');
|
|
106
163
|
out.push(` section ${escapeMermaidText(sectionLabel)}`);
|
|
107
164
|
// Each lane starts its own sequential chain; the first non-`after` item
|
|
108
165
|
// anchors at the roadmap start date.
|
|
109
|
-
const chain = {
|
|
166
|
+
const chain = { prevIds: [] };
|
|
110
167
|
for (const child of lane.content) {
|
|
111
|
-
emitSwimlaneChild(child, breadcrumb, drops, out, chain,
|
|
168
|
+
emitSwimlaneChild(child, breadcrumb, drops, out, chain, ctx);
|
|
112
169
|
}
|
|
113
170
|
// Nested swimlanes — count for the lossy report.
|
|
114
171
|
// SwimlaneContent doesn't include nested swimlanes per the grammar, so
|
|
115
172
|
// there's nothing to recurse into here. If `nested` lives on the
|
|
116
173
|
// roadmap-level layout model, that's a separate count tracked elsewhere.
|
|
117
174
|
}
|
|
118
|
-
function emitSwimlaneChild(child, breadcrumb, drops, out, chain,
|
|
175
|
+
function emitSwimlaneChild(child, breadcrumb, drops, out, chain, ctx) {
|
|
119
176
|
if (child.$type === 'ItemDeclaration') {
|
|
120
|
-
emitItem(child, drops, out, chain,
|
|
177
|
+
emitItem(child, drops, out, chain, ctx);
|
|
121
178
|
return;
|
|
122
179
|
}
|
|
123
180
|
if (child.$type === 'GroupBlock') {
|
|
124
181
|
drops.group += 1;
|
|
125
|
-
emitGroup(child, breadcrumb, drops, out, chain,
|
|
182
|
+
emitGroup(child, breadcrumb, drops, out, chain, ctx);
|
|
126
183
|
return;
|
|
127
184
|
}
|
|
128
185
|
if (child.$type === 'ParallelBlock') {
|
|
129
186
|
drops.parallel += 1;
|
|
130
|
-
emitParallel(child, breadcrumb, drops, out, chain,
|
|
187
|
+
emitParallel(child, breadcrumb, drops, out, chain, ctx);
|
|
131
188
|
return;
|
|
132
189
|
}
|
|
133
190
|
if (child.$type === 'DescriptionDirective') {
|
|
@@ -135,67 +192,76 @@ function emitSwimlaneChild(child, breadcrumb, drops, out, chain, startDate) {
|
|
|
135
192
|
return;
|
|
136
193
|
}
|
|
137
194
|
}
|
|
138
|
-
function emitGroup(group, breadcrumb, drops, out, chain,
|
|
195
|
+
function emitGroup(group, breadcrumb, drops, out, chain, ctx) {
|
|
139
196
|
// A group is a visual container within a lane — its items continue the
|
|
140
|
-
// lane's sequential chain.
|
|
197
|
+
// lane's sequential chain, which its own `after:` joins for the first child.
|
|
198
|
+
joinContainerAfter(group, chain, ctx);
|
|
141
199
|
for (const child of group.content) {
|
|
142
200
|
if (child.$type === 'ItemDeclaration') {
|
|
143
|
-
emitItem(child, drops, out, chain,
|
|
201
|
+
emitItem(child, drops, out, chain, ctx);
|
|
144
202
|
}
|
|
145
203
|
else if (child.$type === 'GroupBlock') {
|
|
146
204
|
drops.group += 1;
|
|
147
|
-
emitGroup(child, breadcrumb, drops, out, chain,
|
|
205
|
+
emitGroup(child, breadcrumb, drops, out, chain, ctx);
|
|
148
206
|
}
|
|
149
207
|
else if (child.$type === 'ParallelBlock') {
|
|
150
208
|
drops.parallel += 1;
|
|
151
|
-
emitParallel(child, breadcrumb, drops, out, chain,
|
|
209
|
+
emitParallel(child, breadcrumb, drops, out, chain, ctx);
|
|
152
210
|
}
|
|
153
211
|
else if (child.$type === 'DescriptionDirective') {
|
|
154
212
|
drops.description += 1;
|
|
155
213
|
}
|
|
156
214
|
}
|
|
157
215
|
}
|
|
158
|
-
function emitParallel(parallel, breadcrumb, drops, out, chain,
|
|
216
|
+
function emitParallel(parallel, breadcrumb, drops, out, chain, ctx) {
|
|
159
217
|
// Tracks run concurrently: each starts from the parallel's entry point
|
|
160
|
-
// (the lane cursor as it was on entry
|
|
161
|
-
|
|
162
|
-
|
|
218
|
+
// (the lane cursor as it was on entry, joined by the parallel's own
|
|
219
|
+
// `after:`), not after the previous track.
|
|
220
|
+
joinContainerAfter(parallel, chain, ctx);
|
|
221
|
+
const entryIds = chain.prevIds;
|
|
163
222
|
for (const child of parallel.content) {
|
|
164
223
|
if (child.$type === 'ItemDeclaration') {
|
|
165
|
-
|
|
166
|
-
emitItem(child, drops, out, trackChain, startDate);
|
|
167
|
-
lastTrackEnd = trackChain.prevId;
|
|
224
|
+
emitItem(child, drops, out, { prevIds: entryIds }, ctx);
|
|
168
225
|
}
|
|
169
226
|
else if (child.$type === 'GroupBlock') {
|
|
170
227
|
drops.group += 1;
|
|
171
|
-
|
|
172
|
-
emitGroup(child, breadcrumb, drops, out, trackChain, startDate);
|
|
173
|
-
lastTrackEnd = trackChain.prevId;
|
|
228
|
+
emitGroup(child, breadcrumb, drops, out, { prevIds: entryIds }, ctx);
|
|
174
229
|
}
|
|
175
230
|
else if (child.$type === 'DescriptionDirective') {
|
|
176
231
|
drops.description += 1;
|
|
177
232
|
}
|
|
178
233
|
}
|
|
179
|
-
// After the block, the lane continues
|
|
180
|
-
//
|
|
181
|
-
chain.
|
|
234
|
+
// After the block, the lane continues after every track's end: Mermaid's
|
|
235
|
+
// `after a b` starts at the latest of them, where engine C ends a parallel.
|
|
236
|
+
chain.prevIds = endTaskIds(parallel);
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Adds a group's or parallel's own `after:` ids to the chain its first children
|
|
240
|
+
* start from. Engine C starts a container at `max(prevEnd, ...after)`, and
|
|
241
|
+
* neither container is a Mermaid task, so its first children carry both. An
|
|
242
|
+
* inline date stays dropped: as an id it would name no task, and a leader with
|
|
243
|
+
* no other id would start on the day the chart renders.
|
|
244
|
+
*/
|
|
245
|
+
function joinContainerAfter(container, chain, ctx) {
|
|
246
|
+
const refs = getProps(container, 'after').filter((raw) => !parseIsoDate(raw));
|
|
247
|
+
chain.prevIds = union(chain.prevIds, expandAfter(refs, ctx.containers));
|
|
182
248
|
}
|
|
183
|
-
function emitItem(item, drops, out, chain,
|
|
249
|
+
function emitItem(item, drops, out, chain, ctx) {
|
|
184
250
|
countDrops(item, drops);
|
|
185
|
-
const id =
|
|
251
|
+
const id = taskIdOf(item);
|
|
186
252
|
const status = mapStatus(getProp(item, 'status'));
|
|
187
|
-
const after = getProps(item, 'after');
|
|
188
|
-
const duration =
|
|
189
|
-
const start = startTokenFor(after, chain, startDate);
|
|
253
|
+
const after = expandAfter(getProps(item, 'after'), ctx.containers);
|
|
254
|
+
const duration = daysToMermaid(ctx.schedule.byNode.get(item)?.days) ?? '1d';
|
|
255
|
+
const start = startTokenFor(after, chain, ctx.startDate, previousWaveOf(item, ctx.waves));
|
|
190
256
|
const meta = [status, id, start, duration].filter((s) => s !== '').join(', ');
|
|
191
257
|
out.push(` ${escapeTaskName(displayLabel(item))} :${meta}`);
|
|
192
258
|
// Advance the lane cursor so the next sequential item chains after this one.
|
|
193
|
-
chain.
|
|
259
|
+
chain.prevIds = [id];
|
|
194
260
|
}
|
|
195
|
-
function emitMilestone(milestone, drops, out,
|
|
261
|
+
function emitMilestone(milestone, drops, out, ctx) {
|
|
196
262
|
const id = milestone.name ?? slugify(displayLabel(milestone));
|
|
197
263
|
const date = getProp(milestone, 'date');
|
|
198
|
-
const after = getProps(milestone, 'after');
|
|
264
|
+
const after = expandAfter(getProps(milestone, 'after'), ctx.containers);
|
|
199
265
|
let start;
|
|
200
266
|
if (date) {
|
|
201
267
|
start = date;
|
|
@@ -206,36 +272,127 @@ function emitMilestone(milestone, drops, out, startDate) {
|
|
|
206
272
|
else {
|
|
207
273
|
// A milestone with neither a date nor predecessors still needs a start
|
|
208
274
|
// token; anchor it at the roadmap start so Mermaid renders it.
|
|
209
|
-
start = startDate;
|
|
275
|
+
start = ctx.startDate;
|
|
210
276
|
}
|
|
211
277
|
out.push(` ${escapeTaskName(displayLabel(milestone))} :milestone, ${id}, ${start}, 0d`);
|
|
212
278
|
if (hasProp(milestone, 'style'))
|
|
213
279
|
drops.style += 1;
|
|
214
280
|
}
|
|
215
281
|
/**
|
|
216
|
-
* Start token for a task: declared `after:` deps
|
|
217
|
-
* previous item
|
|
282
|
+
* Start token for a task: `after` its declared `after:` deps and the lane chain
|
|
283
|
+
* (the previous item, every track end after a parallel), deduplicated, as
|
|
284
|
+
* engine C starts it at `max(prevEnd, ...after)`. A member of wave k >= 2 also
|
|
285
|
+
* waits for wave k-1's end milestone (`barrier`). Mermaid's `after a b` starts
|
|
286
|
+
* at the latest of them. With none, a lane or track leader anchors at the
|
|
218
287
|
* roadmap start date. Always non-empty so Mermaid never mis-reads the task id
|
|
219
|
-
* as a start date
|
|
288
|
+
* as a start date; a leader's start date gives way to the barrier, which is
|
|
289
|
+
* never earlier.
|
|
290
|
+
*/
|
|
291
|
+
function startTokenFor(after, chain, startDate, barrier) {
|
|
292
|
+
const deps = union(union(after, chain.prevIds), barrier ? [barrier] : []);
|
|
293
|
+
return deps.length > 0 ? `after ${deps.join(' ')}` : startDate;
|
|
294
|
+
}
|
|
295
|
+
/** `a` then the ids of `b` it lacks, in order. */
|
|
296
|
+
function union(a, b) {
|
|
297
|
+
return [...a, ...b.filter((id) => !a.includes(id))];
|
|
298
|
+
}
|
|
299
|
+
/** An item's Mermaid task id: its own id, else a slug of its title. */
|
|
300
|
+
function taskIdOf(item) {
|
|
301
|
+
return item.name ?? slugify(displayLabel(item));
|
|
302
|
+
}
|
|
303
|
+
/** Every named group and parallel under `lanes`, by id. */
|
|
304
|
+
function namedContainers(lanes) {
|
|
305
|
+
const out = new Map();
|
|
306
|
+
for (const node of trackNodes(lanes)) {
|
|
307
|
+
if ((isGroupBlock(node) || isParallelBlock(node)) && node.name)
|
|
308
|
+
out.set(node.name, node);
|
|
309
|
+
}
|
|
310
|
+
return out;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* `after:` ids with each group and parallel replaced by the tasks that end it,
|
|
314
|
+
* without duplicates. Neither container is a Mermaid task, and Mermaid starts
|
|
315
|
+
* a task with an unknown `after` id on the day it renders. Engine C ends a
|
|
316
|
+
* group at its last child's end and a parallel at its latest track end;
|
|
317
|
+
* Mermaid's `after a b` starts at the latest end of the tasks it names, so the
|
|
318
|
+
* expansion lands on the same day.
|
|
220
319
|
*/
|
|
221
|
-
function
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
320
|
+
function expandAfter(after, containers) {
|
|
321
|
+
const out = [];
|
|
322
|
+
for (const ref of after) {
|
|
323
|
+
const container = containers.get(ref);
|
|
324
|
+
for (const id of container ? endTaskIds(container) : [ref]) {
|
|
325
|
+
if (!out.includes(id))
|
|
326
|
+
out.push(id);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return out;
|
|
330
|
+
}
|
|
331
|
+
/** The task ids that end a track node: an item, a group's last child, or every parallel track. */
|
|
332
|
+
function endTaskIds(node) {
|
|
333
|
+
if (isGroupBlock(node)) {
|
|
334
|
+
const last = trackChildren(node).at(-1);
|
|
335
|
+
return last ? endTaskIds(last) : [];
|
|
336
|
+
}
|
|
337
|
+
if (isParallelBlock(node))
|
|
338
|
+
return trackChildren(node).flatMap(endTaskIds);
|
|
339
|
+
return [taskIdOf(node)];
|
|
340
|
+
}
|
|
341
|
+
/** The previous wave's id for a member of wave k >= 2; undefined otherwise. */
|
|
342
|
+
function previousWaveOf(item, waves) {
|
|
343
|
+
if (!waves)
|
|
344
|
+
return undefined;
|
|
345
|
+
const k = waves.plan.memberWave(item);
|
|
346
|
+
return k !== undefined && k >= 2 ? waves.ids[k - 2] : undefined;
|
|
227
347
|
}
|
|
228
348
|
/**
|
|
229
|
-
* Absolute anchor date
|
|
230
|
-
*
|
|
231
|
-
* present) so the export renders even when the source omits `start:`.
|
|
349
|
+
* Absolute anchor date for lane leaders. Prefers the roadmap's declared
|
|
350
|
+
* `start:`, falling back to the layout-computed timeline start (always
|
|
351
|
+
* present) so the export renders even when the source omits `start:`. An
|
|
352
|
+
* impossible `start:` (`2026-02-30`, NL.E0405) falls back the same way,
|
|
353
|
+
* as layout treats it, rather than rolling over to March 2.
|
|
232
354
|
*/
|
|
233
355
|
function resolveStartDate(inputs) {
|
|
234
356
|
const decl = inputs.ast.roadmapDecl;
|
|
235
357
|
const declared = decl ? getProp(decl, 'start') : undefined;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
358
|
+
return parseIsoDate(declared?.trim()) ?? inputs.model.timeline.startDate;
|
|
359
|
+
}
|
|
360
|
+
/** Monday first, as Mermaid's docs write `excludes`. */
|
|
361
|
+
const WEEKDAY_NAMES_MONDAY_FIRST = [
|
|
362
|
+
[1, 'monday'],
|
|
363
|
+
[2, 'tuesday'],
|
|
364
|
+
[3, 'wednesday'],
|
|
365
|
+
[4, 'thursday'],
|
|
366
|
+
[5, 'friday'],
|
|
367
|
+
[6, 'saturday'],
|
|
368
|
+
[0, 'sunday'],
|
|
369
|
+
];
|
|
370
|
+
/** The open week's non-working days, as Mermaid `excludes` names. */
|
|
371
|
+
function excludedWeekdays(working) {
|
|
372
|
+
return WEEKDAY_NAMES_MONDAY_FIRST.filter(([weekday]) => !working.workingWeekdays.has(weekday)).map(([, name]) => name);
|
|
373
|
+
}
|
|
374
|
+
const DAY_MS = 86_400_000;
|
|
375
|
+
/** The ISO date of every day in every non-working exception, ascending. */
|
|
376
|
+
function excludedDates(exceptions) {
|
|
377
|
+
const dates = [];
|
|
378
|
+
for (const exception of exceptions) {
|
|
379
|
+
if (exception.working)
|
|
380
|
+
continue;
|
|
381
|
+
for (let t = exception.from.getTime(); t <= exception.through.getTime(); t += DAY_MS) {
|
|
382
|
+
dates.push(formatIsoDate(new Date(t)));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return dates;
|
|
386
|
+
}
|
|
387
|
+
/** Days across the working exceptions. */
|
|
388
|
+
function workingDayCount(exceptions) {
|
|
389
|
+
let days = 0;
|
|
390
|
+
for (const exception of exceptions) {
|
|
391
|
+
if (!exception.working)
|
|
392
|
+
continue;
|
|
393
|
+
days += Math.round((exception.through.getTime() - exception.from.getTime()) / DAY_MS) + 1;
|
|
394
|
+
}
|
|
395
|
+
return days;
|
|
239
396
|
}
|
|
240
397
|
function formatIsoDate(d) {
|
|
241
398
|
const y = d.getUTCFullYear();
|
|
@@ -295,6 +452,8 @@ function formatDrops(drops) {
|
|
|
295
452
|
'nestedSwimlanes',
|
|
296
453
|
'description',
|
|
297
454
|
'style',
|
|
455
|
+
'waveFloor',
|
|
456
|
+
'workingDay',
|
|
298
457
|
];
|
|
299
458
|
const parts = order
|
|
300
459
|
.filter((key) => drops[key] > 0)
|
|
@@ -309,6 +468,10 @@ function formatDrops(drops) {
|
|
|
309
468
|
function formatDropKey(key) {
|
|
310
469
|
if (key === 'nestedSwimlanes')
|
|
311
470
|
return 'nested-swimlanes';
|
|
471
|
+
if (key === 'waveFloor')
|
|
472
|
+
return 'wave-floor';
|
|
473
|
+
if (key === 'workingDay')
|
|
474
|
+
return 'working-day';
|
|
312
475
|
return key;
|
|
313
476
|
}
|
|
314
477
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nowline/export-mermaid",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Exports a Nowline roadmap as a Mermaid Gantt chart in Markdown.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"engines": {
|
|
@@ -21,15 +21,15 @@
|
|
|
21
21
|
"src/"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@nowline/core": "0.
|
|
25
|
-
"@nowline/export-core": "0.
|
|
26
|
-
"@nowline/layout": "0.
|
|
24
|
+
"@nowline/core": "0.9.0",
|
|
25
|
+
"@nowline/export-core": "0.9.0",
|
|
26
|
+
"@nowline/layout": "0.9.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@types/node": "^26.6.
|
|
29
|
+
"@types/node": "^26.6.5",
|
|
30
30
|
"langium": "~4.4.0",
|
|
31
31
|
"typescript": "^7.0.2",
|
|
32
|
-
"vitest": "^5.0.
|
|
32
|
+
"vitest": "^5.0.5"
|
|
33
33
|
},
|
|
34
34
|
"scripts": {
|
|
35
35
|
"build": "tsc -b tsconfig.json",
|
package/src/duration.ts
CHANGED
|
@@ -1,49 +1,18 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
1
|
+
// Mermaid task durations. The day count is engine C's `ScheduledItem.days`
|
|
2
|
+
// under the file's calendar (specs/working-calendar.md §8), so sizes,
|
|
3
|
+
// `capacity:` and every unit match the chart. It is always written as `Nd`:
|
|
4
|
+
// with the business `excludes` Mermaid counts those in working days, and a
|
|
5
|
+
// full-calendar `4w` becomes `28d`, the same span.
|
|
3
6
|
//
|
|
4
7
|
// Spec: specs/handoffs/m2c.md § 6 + the bridge rules in
|
|
5
8
|
// specs/rendering.md § Markdown+Mermaid Bridge.
|
|
6
9
|
|
|
7
|
-
const SIZE_BUCKET_DAYS: Readonly<Record<string, number>> = {
|
|
8
|
-
xs: 1,
|
|
9
|
-
sm: 3,
|
|
10
|
-
s: 3,
|
|
11
|
-
md: 5,
|
|
12
|
-
m: 5,
|
|
13
|
-
lg: 10,
|
|
14
|
-
l: 10,
|
|
15
|
-
xl: 15,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
const NUMERIC_RE = /^(\d+(?:\.\d+)?)\s*(d|w|m|y)?$/i;
|
|
19
|
-
|
|
20
10
|
/**
|
|
21
|
-
*
|
|
22
|
-
* Returns `undefined`
|
|
23
|
-
* and Mermaid uses its default 1d.
|
|
11
|
+
* `Nd` with up to two decimals, trailing zeros trimmed (`7.5d`, `7.33d`).
|
|
12
|
+
* Returns `undefined` for no duration; the caller falls back to `1d`.
|
|
24
13
|
*/
|
|
25
|
-
export function
|
|
26
|
-
if (!
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
// Size buckets resolve to working-day counts.
|
|
31
|
-
if (trimmed in SIZE_BUCKET_DAYS) {
|
|
32
|
-
return `${SIZE_BUCKET_DAYS[trimmed]}d`;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const match = NUMERIC_RE.exec(trimmed);
|
|
36
|
-
if (!match) return undefined;
|
|
37
|
-
const value = match[1];
|
|
38
|
-
const unit = (match[2] ?? 'd').toLowerCase();
|
|
39
|
-
if (unit === 'd' || unit === 'w') return `${value}${unit}`;
|
|
40
|
-
if (unit === 'm') {
|
|
41
|
-
const days = Math.round(Number(value) * 22);
|
|
42
|
-
return `${days}d`;
|
|
43
|
-
}
|
|
44
|
-
if (unit === 'y') {
|
|
45
|
-
const days = Math.round(Number(value) * 252);
|
|
46
|
-
return `${days}d`;
|
|
47
|
-
}
|
|
48
|
-
return undefined;
|
|
14
|
+
export function daysToMermaid(days: number | undefined): string | undefined {
|
|
15
|
+
if (days === undefined || !(days > 0)) return undefined;
|
|
16
|
+
// parseFloat strips trailing zeros: `7.50` → `7.5`.
|
|
17
|
+
return `${parseFloat(days.toFixed(2))}d`;
|
|
49
18
|
}
|
package/src/index.ts
CHANGED
|
@@ -16,13 +16,23 @@
|
|
|
16
16
|
// gantt
|
|
17
17
|
// title <title>
|
|
18
18
|
// dateFormat YYYY-MM-DD
|
|
19
|
-
//
|
|
19
|
+
// excludes saturday, sunday (only when the open week has days off)
|
|
20
20
|
// section <swimlane>
|
|
21
21
|
// <Task name>: <status>, <id>, <after-or-date>, <duration>
|
|
22
22
|
// ```
|
|
23
23
|
//
|
|
24
24
|
// <%% lossy comment %%>
|
|
25
25
|
//
|
|
26
|
+
// Calendar (specs/working-calendar.md §8): the file's calendar comes from
|
|
27
|
+
// engine C (`scheduleRoadmap`, built once per export). `excludes` lists the
|
|
28
|
+
// open week's non-working days, Monday first, so Mermaid counts `Nd` in
|
|
29
|
+
// working days; every duration is engine C's `days` written as `Nd` (a
|
|
30
|
+
// full-calendar `4w` is `28d`). Mermaid never checks a task's explicit start
|
|
31
|
+
// against `excludes`, so the dates this exporter derives are working days:
|
|
32
|
+
// the roadmap start is snapped to its first working day, and a wave-end
|
|
33
|
+
// milestone is the first working day at or after the wave's exclusive end.
|
|
34
|
+
// Declared anchor and milestone dates are written as given.
|
|
35
|
+
//
|
|
26
36
|
// Every emitted task carries an explicit start token (`after <id>` or an
|
|
27
37
|
// absolute `YYYY-MM-DD` date). Mermaid's positional task parser strips a
|
|
28
38
|
// leading status keyword (`done`/`active`/`crit`/`milestone`) and then reads
|
|
@@ -31,9 +41,15 @@
|
|
|
31
41
|
// start (`:done, my-id, 2w`) collapses to two fields after the status strip,
|
|
32
42
|
// so Mermaid mis-reads the id as a start date and throws `Invalid date: my-id`
|
|
33
43
|
// at render time. To keep an explicit id we therefore MUST emit a start token:
|
|
34
|
-
// - declared `after:` deps
|
|
35
|
-
//
|
|
36
|
-
//
|
|
44
|
+
// - `after <ids>`: the declared `after:` deps (a group or parallel id
|
|
45
|
+
// expanded to the tasks that end it; neither is a Mermaid task), then the
|
|
46
|
+
// lane chain: the previous item in the lane, or every track end when it
|
|
47
|
+
// follows a parallel; a first child also gets its group's or parallel's
|
|
48
|
+
// own `after:`. Engine C starts an item at `max(prevEnd, ...after)`.
|
|
49
|
+
// - with none of those, a lane/track leader -> the roadmap start date
|
|
50
|
+
// - a member of wave k >= 2 also gets `after <wave k-1 id>`: appended to
|
|
51
|
+
// its `after` token, or replacing a lane/track leader's start date
|
|
52
|
+
// (specs/waves.md §10)
|
|
37
53
|
// This mirrors Nowline's default "each item starts after the preceding item in
|
|
38
54
|
// its lane" semantics (specs/rendering.md § Item Bars).
|
|
39
55
|
|
|
@@ -46,11 +62,21 @@ import type {
|
|
|
46
62
|
ParallelBlock,
|
|
47
63
|
SwimlaneContent,
|
|
48
64
|
SwimlaneDeclaration,
|
|
65
|
+
WavePlan,
|
|
49
66
|
} from '@nowline/core';
|
|
67
|
+
import { isGroupBlock, isParallelBlock } from '@nowline/core';
|
|
68
|
+
import { parseIsoDate, type TrackNode, trackChildren, trackNodes } from '@nowline/core/internal';
|
|
50
69
|
import type { ExportInputs } from '@nowline/export-core';
|
|
51
70
|
import { displayLabel, getProp, getProps, hasProp, roadmapTitle } from '@nowline/export-core';
|
|
71
|
+
import {
|
|
72
|
+
type CalendarException,
|
|
73
|
+
calendarExceptions,
|
|
74
|
+
type RoadmapSchedule,
|
|
75
|
+
scheduleRoadmap,
|
|
76
|
+
type WorkingCalendar,
|
|
77
|
+
} from '@nowline/layout';
|
|
52
78
|
|
|
53
|
-
import {
|
|
79
|
+
import { daysToMermaid } from './duration.js';
|
|
54
80
|
|
|
55
81
|
export interface MermaidOptions {
|
|
56
82
|
/** Append the trailing `%%` lossy comment. Defaults to true. */
|
|
@@ -68,6 +94,10 @@ interface DropCounts {
|
|
|
68
94
|
nestedSwimlanes: number;
|
|
69
95
|
description: number;
|
|
70
96
|
style: number;
|
|
97
|
+
/** Wave start floors (a wave's `after:`); Mermaid has no "no earlier than". */
|
|
98
|
+
waveFloor: number;
|
|
99
|
+
/** Days a `working` exception opens inside a closed week; Mermaid has no `includes`. */
|
|
100
|
+
workingDay: number;
|
|
71
101
|
}
|
|
72
102
|
|
|
73
103
|
function emptyCounts(): DropCounts {
|
|
@@ -82,22 +112,47 @@ function emptyCounts(): DropCounts {
|
|
|
82
112
|
nestedSwimlanes: 0,
|
|
83
113
|
description: 0,
|
|
84
114
|
style: 0,
|
|
115
|
+
waveFloor: 0,
|
|
116
|
+
workingDay: 0,
|
|
85
117
|
};
|
|
86
118
|
}
|
|
87
119
|
|
|
88
120
|
/**
|
|
89
|
-
* Mutable per-lane chaining cursor. `
|
|
90
|
-
* task should start after
|
|
91
|
-
* (lane / parallel-track leader).
|
|
121
|
+
* Mutable per-lane chaining cursor. `prevIds` are the ids the NEXT sequential
|
|
122
|
+
* task should start after: one item, or every track end after a parallel.
|
|
123
|
+
* Empty means "anchor at the roadmap start date" (lane / parallel-track leader).
|
|
92
124
|
*/
|
|
93
125
|
interface Chain {
|
|
94
|
-
|
|
126
|
+
prevIds: string[];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Wave barrier context (specs/waves.md §10): the plan, for membership, and
|
|
131
|
+
* each wave's end milestone id by 1-based index. Undefined without waves.
|
|
132
|
+
*/
|
|
133
|
+
interface WaveCtx {
|
|
134
|
+
plan: WavePlan;
|
|
135
|
+
/** `ids[k - 1]` is wave k's id, which is also its end milestone's id. */
|
|
136
|
+
ids: readonly string[];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** What every item line reads besides its own lane chain. */
|
|
140
|
+
interface EmitCtx {
|
|
141
|
+
/** The roadmap start, on a working day (`YYYY-MM-DD`). */
|
|
142
|
+
startDate: string;
|
|
143
|
+
schedule: RoadmapSchedule;
|
|
144
|
+
waves: WaveCtx | undefined;
|
|
145
|
+
/** Each named group and parallel, which `after:` expands to its end tasks. */
|
|
146
|
+
containers: ReadonlyMap<string, GroupBlock | ParallelBlock>;
|
|
95
147
|
}
|
|
96
148
|
|
|
97
149
|
export function exportMermaid(inputs: ExportInputs, options: MermaidOptions = {}): string {
|
|
98
150
|
const ast = inputs.ast;
|
|
99
151
|
const title = roadmapTitle(ast.roadmapDecl ?? undefined);
|
|
100
|
-
const
|
|
152
|
+
const schedule =
|
|
153
|
+
inputs.schedule ?? scheduleRoadmap(ast, inputs.resolved, { today: inputs.today });
|
|
154
|
+
const { working } = schedule.calendar;
|
|
155
|
+
const startDate = formatIsoDate(working.dateAtWorkingIndex(resolveStartDate(inputs), 0));
|
|
101
156
|
const drops = emptyCounts();
|
|
102
157
|
|
|
103
158
|
const out: string[] = [];
|
|
@@ -107,6 +162,14 @@ export function exportMermaid(inputs: ExportInputs, options: MermaidOptions = {}
|
|
|
107
162
|
out.push('gantt');
|
|
108
163
|
out.push(` title ${escapeMermaidText(title)}`);
|
|
109
164
|
out.push(' dateFormat YYYY-MM-DD');
|
|
165
|
+
const exceptions = calendarExceptions(
|
|
166
|
+
working,
|
|
167
|
+
inputs.model.timeline.startDate,
|
|
168
|
+
inputs.model.timeline.endDate,
|
|
169
|
+
);
|
|
170
|
+
const excludes = [...excludedWeekdays(working), ...excludedDates(exceptions)];
|
|
171
|
+
if (excludes.length > 0) out.push(` excludes ${excludes.join(', ')}`);
|
|
172
|
+
drops.workingDay += workingDayCount(exceptions);
|
|
110
173
|
|
|
111
174
|
// Footnotes are file-level; counted once.
|
|
112
175
|
drops.footnote += ast.roadmapEntries.filter((e) => e.$type === 'FootnoteDeclaration').length;
|
|
@@ -126,12 +189,16 @@ export function exportMermaid(inputs: ExportInputs, options: MermaidOptions = {}
|
|
|
126
189
|
}
|
|
127
190
|
}
|
|
128
191
|
|
|
192
|
+
// Waves → one end milestone per wave, dated from the day schedule.
|
|
193
|
+
const waves = emitWaves(schedule, drops, out, startDate);
|
|
194
|
+
|
|
129
195
|
// Swimlanes → sections; their items become tasks.
|
|
130
196
|
const swimlanes = ast.roadmapEntries.filter(
|
|
131
197
|
(e): e is SwimlaneDeclaration => e.$type === 'SwimlaneDeclaration',
|
|
132
198
|
);
|
|
199
|
+
const ctx: EmitCtx = { startDate, schedule, waves, containers: namedContainers(swimlanes) };
|
|
133
200
|
for (const lane of swimlanes) {
|
|
134
|
-
emitSwimlane(lane, [lane.name ?? slugify(displayLabel(lane))], drops, out,
|
|
201
|
+
emitSwimlane(lane, [lane.name ?? slugify(displayLabel(lane))], drops, out, ctx);
|
|
135
202
|
}
|
|
136
203
|
|
|
137
204
|
// Top-level milestones.
|
|
@@ -141,7 +208,7 @@ export function exportMermaid(inputs: ExportInputs, options: MermaidOptions = {}
|
|
|
141
208
|
if (milestones.length > 0) {
|
|
142
209
|
out.push(' section Milestones');
|
|
143
210
|
for (const m of milestones) {
|
|
144
|
-
emitMilestone(m, drops, out,
|
|
211
|
+
emitMilestone(m, drops, out, ctx);
|
|
145
212
|
}
|
|
146
213
|
}
|
|
147
214
|
|
|
@@ -158,20 +225,52 @@ export function exportMermaid(inputs: ExportInputs, options: MermaidOptions = {}
|
|
|
158
225
|
return out.join('\n');
|
|
159
226
|
}
|
|
160
227
|
|
|
228
|
+
/**
|
|
229
|
+
* `section Waves` (specs/waves.md §10): `{title} (wave end) :milestone, {id},
|
|
230
|
+
* {date}, 0d` per wave, in declaration order. The date is the first working
|
|
231
|
+
* day at or after `E_k`, the wave's exclusive end from the day schedule: the
|
|
232
|
+
* instant Mermaid starts a task `after` the milestone, so `after:build` and
|
|
233
|
+
* the barrier tokens both open on the barrier, and on a working day, since
|
|
234
|
+
* Mermaid never moves an explicit date off an excluded day. Start floors
|
|
235
|
+
* cannot be expressed and are counted as drops. Returns undefined, emitting
|
|
236
|
+
* nothing, when the roadmap has no waves.
|
|
237
|
+
*/
|
|
238
|
+
function emitWaves(
|
|
239
|
+
schedule: RoadmapSchedule,
|
|
240
|
+
drops: DropCounts,
|
|
241
|
+
out: string[],
|
|
242
|
+
startDate: string,
|
|
243
|
+
): WaveCtx | undefined {
|
|
244
|
+
const plan = schedule.plan;
|
|
245
|
+
if (!plan) return undefined;
|
|
246
|
+
const { working } = schedule.calendar;
|
|
247
|
+
const ids = plan.waves.map((w) => w.name as string);
|
|
248
|
+
out.push(' section Waves');
|
|
249
|
+
plan.waves.forEach((w, i) => {
|
|
250
|
+
const end = schedule.waves?.get(ids[i]!)?.end;
|
|
251
|
+
const date = end ? formatIsoDate(working.dateAtWorkingIndex(end, 0)) : startDate;
|
|
252
|
+
out.push(
|
|
253
|
+
` ${escapeTaskName(displayLabel(w))} (wave end) :milestone, ${ids[i]}, ${date}, 0d`,
|
|
254
|
+
);
|
|
255
|
+
if (getProps(w, 'after').length > 0) drops.waveFloor += 1;
|
|
256
|
+
});
|
|
257
|
+
return { plan, ids };
|
|
258
|
+
}
|
|
259
|
+
|
|
161
260
|
function emitSwimlane(
|
|
162
261
|
lane: SwimlaneDeclaration,
|
|
163
262
|
breadcrumb: readonly string[],
|
|
164
263
|
drops: DropCounts,
|
|
165
264
|
out: string[],
|
|
166
|
-
|
|
265
|
+
ctx: EmitCtx,
|
|
167
266
|
): void {
|
|
168
267
|
const sectionLabel = breadcrumb.join('.');
|
|
169
268
|
out.push(` section ${escapeMermaidText(sectionLabel)}`);
|
|
170
269
|
// Each lane starts its own sequential chain; the first non-`after` item
|
|
171
270
|
// anchors at the roadmap start date.
|
|
172
|
-
const chain: Chain = {
|
|
271
|
+
const chain: Chain = { prevIds: [] };
|
|
173
272
|
for (const child of lane.content) {
|
|
174
|
-
emitSwimlaneChild(child, breadcrumb, drops, out, chain,
|
|
273
|
+
emitSwimlaneChild(child, breadcrumb, drops, out, chain, ctx);
|
|
175
274
|
}
|
|
176
275
|
// Nested swimlanes — count for the lossy report.
|
|
177
276
|
// SwimlaneContent doesn't include nested swimlanes per the grammar, so
|
|
@@ -185,20 +284,20 @@ function emitSwimlaneChild(
|
|
|
185
284
|
drops: DropCounts,
|
|
186
285
|
out: string[],
|
|
187
286
|
chain: Chain,
|
|
188
|
-
|
|
287
|
+
ctx: EmitCtx,
|
|
189
288
|
): void {
|
|
190
289
|
if (child.$type === 'ItemDeclaration') {
|
|
191
|
-
emitItem(child, drops, out, chain,
|
|
290
|
+
emitItem(child, drops, out, chain, ctx);
|
|
192
291
|
return;
|
|
193
292
|
}
|
|
194
293
|
if (child.$type === 'GroupBlock') {
|
|
195
294
|
drops.group += 1;
|
|
196
|
-
emitGroup(child, breadcrumb, drops, out, chain,
|
|
295
|
+
emitGroup(child, breadcrumb, drops, out, chain, ctx);
|
|
197
296
|
return;
|
|
198
297
|
}
|
|
199
298
|
if (child.$type === 'ParallelBlock') {
|
|
200
299
|
drops.parallel += 1;
|
|
201
|
-
emitParallel(child, breadcrumb, drops, out, chain,
|
|
300
|
+
emitParallel(child, breadcrumb, drops, out, chain, ctx);
|
|
202
301
|
return;
|
|
203
302
|
}
|
|
204
303
|
if (child.$type === 'DescriptionDirective') {
|
|
@@ -213,19 +312,20 @@ function emitGroup(
|
|
|
213
312
|
drops: DropCounts,
|
|
214
313
|
out: string[],
|
|
215
314
|
chain: Chain,
|
|
216
|
-
|
|
315
|
+
ctx: EmitCtx,
|
|
217
316
|
): void {
|
|
218
317
|
// A group is a visual container within a lane — its items continue the
|
|
219
|
-
// lane's sequential chain.
|
|
318
|
+
// lane's sequential chain, which its own `after:` joins for the first child.
|
|
319
|
+
joinContainerAfter(group, chain, ctx);
|
|
220
320
|
for (const child of group.content as GroupContent[]) {
|
|
221
321
|
if (child.$type === 'ItemDeclaration') {
|
|
222
|
-
emitItem(child, drops, out, chain,
|
|
322
|
+
emitItem(child, drops, out, chain, ctx);
|
|
223
323
|
} else if (child.$type === 'GroupBlock') {
|
|
224
324
|
drops.group += 1;
|
|
225
|
-
emitGroup(child, breadcrumb, drops, out, chain,
|
|
325
|
+
emitGroup(child, breadcrumb, drops, out, chain, ctx);
|
|
226
326
|
} else if (child.$type === 'ParallelBlock') {
|
|
227
327
|
drops.parallel += 1;
|
|
228
|
-
emitParallel(child, breadcrumb, drops, out, chain,
|
|
328
|
+
emitParallel(child, breadcrumb, drops, out, chain, ctx);
|
|
229
329
|
} else if (child.$type === 'DescriptionDirective') {
|
|
230
330
|
drops.description += 1;
|
|
231
331
|
}
|
|
@@ -238,29 +338,42 @@ function emitParallel(
|
|
|
238
338
|
drops: DropCounts,
|
|
239
339
|
out: string[],
|
|
240
340
|
chain: Chain,
|
|
241
|
-
|
|
341
|
+
ctx: EmitCtx,
|
|
242
342
|
): void {
|
|
243
343
|
// Tracks run concurrently: each starts from the parallel's entry point
|
|
244
|
-
// (the lane cursor as it was on entry
|
|
245
|
-
|
|
246
|
-
|
|
344
|
+
// (the lane cursor as it was on entry, joined by the parallel's own
|
|
345
|
+
// `after:`), not after the previous track.
|
|
346
|
+
joinContainerAfter(parallel, chain, ctx);
|
|
347
|
+
const entryIds = chain.prevIds;
|
|
247
348
|
for (const child of parallel.content) {
|
|
248
349
|
if (child.$type === 'ItemDeclaration') {
|
|
249
|
-
|
|
250
|
-
emitItem(child, drops, out, trackChain, startDate);
|
|
251
|
-
lastTrackEnd = trackChain.prevId;
|
|
350
|
+
emitItem(child, drops, out, { prevIds: entryIds }, ctx);
|
|
252
351
|
} else if (child.$type === 'GroupBlock') {
|
|
253
352
|
drops.group += 1;
|
|
254
|
-
|
|
255
|
-
emitGroup(child, breadcrumb, drops, out, trackChain, startDate);
|
|
256
|
-
lastTrackEnd = trackChain.prevId;
|
|
353
|
+
emitGroup(child, breadcrumb, drops, out, { prevIds: entryIds }, ctx);
|
|
257
354
|
} else if (child.$type === 'DescriptionDirective') {
|
|
258
355
|
drops.description += 1;
|
|
259
356
|
}
|
|
260
357
|
}
|
|
261
|
-
// After the block, the lane continues
|
|
262
|
-
//
|
|
263
|
-
chain.
|
|
358
|
+
// After the block, the lane continues after every track's end: Mermaid's
|
|
359
|
+
// `after a b` starts at the latest of them, where engine C ends a parallel.
|
|
360
|
+
chain.prevIds = endTaskIds(parallel);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Adds a group's or parallel's own `after:` ids to the chain its first children
|
|
365
|
+
* start from. Engine C starts a container at `max(prevEnd, ...after)`, and
|
|
366
|
+
* neither container is a Mermaid task, so its first children carry both. An
|
|
367
|
+
* inline date stays dropped: as an id it would name no task, and a leader with
|
|
368
|
+
* no other id would start on the day the chart renders.
|
|
369
|
+
*/
|
|
370
|
+
function joinContainerAfter(
|
|
371
|
+
container: GroupBlock | ParallelBlock,
|
|
372
|
+
chain: Chain,
|
|
373
|
+
ctx: EmitCtx,
|
|
374
|
+
): void {
|
|
375
|
+
const refs = getProps(container, 'after').filter((raw) => !parseIsoDate(raw));
|
|
376
|
+
chain.prevIds = union(chain.prevIds, expandAfter(refs, ctx.containers));
|
|
264
377
|
}
|
|
265
378
|
|
|
266
379
|
function emitItem(
|
|
@@ -268,30 +381,30 @@ function emitItem(
|
|
|
268
381
|
drops: DropCounts,
|
|
269
382
|
out: string[],
|
|
270
383
|
chain: Chain,
|
|
271
|
-
|
|
384
|
+
ctx: EmitCtx,
|
|
272
385
|
): void {
|
|
273
386
|
countDrops(item, drops);
|
|
274
|
-
const id =
|
|
387
|
+
const id = taskIdOf(item);
|
|
275
388
|
const status = mapStatus(getProp(item, 'status'));
|
|
276
|
-
const after = getProps(item, 'after');
|
|
277
|
-
const duration =
|
|
278
|
-
const start = startTokenFor(after, chain, startDate);
|
|
389
|
+
const after = expandAfter(getProps(item, 'after'), ctx.containers);
|
|
390
|
+
const duration = daysToMermaid(ctx.schedule.byNode.get(item)?.days) ?? '1d';
|
|
391
|
+
const start = startTokenFor(after, chain, ctx.startDate, previousWaveOf(item, ctx.waves));
|
|
279
392
|
|
|
280
393
|
const meta = [status, id, start, duration].filter((s) => s !== '').join(', ');
|
|
281
394
|
out.push(` ${escapeTaskName(displayLabel(item))} :${meta}`);
|
|
282
395
|
// Advance the lane cursor so the next sequential item chains after this one.
|
|
283
|
-
chain.
|
|
396
|
+
chain.prevIds = [id];
|
|
284
397
|
}
|
|
285
398
|
|
|
286
399
|
function emitMilestone(
|
|
287
400
|
milestone: MilestoneDeclaration,
|
|
288
401
|
drops: DropCounts,
|
|
289
402
|
out: string[],
|
|
290
|
-
|
|
403
|
+
ctx: EmitCtx,
|
|
291
404
|
): void {
|
|
292
405
|
const id = milestone.name ?? slugify(displayLabel(milestone));
|
|
293
406
|
const date = getProp(milestone, 'date');
|
|
294
|
-
const after = getProps(milestone, 'after');
|
|
407
|
+
const after = expandAfter(getProps(milestone, 'after'), ctx.containers);
|
|
295
408
|
let start: string;
|
|
296
409
|
if (date) {
|
|
297
410
|
start = date;
|
|
@@ -300,34 +413,145 @@ function emitMilestone(
|
|
|
300
413
|
} else {
|
|
301
414
|
// A milestone with neither a date nor predecessors still needs a start
|
|
302
415
|
// token; anchor it at the roadmap start so Mermaid renders it.
|
|
303
|
-
start = startDate;
|
|
416
|
+
start = ctx.startDate;
|
|
304
417
|
}
|
|
305
418
|
out.push(` ${escapeTaskName(displayLabel(milestone))} :milestone, ${id}, ${start}, 0d`);
|
|
306
419
|
if (hasProp(milestone, 'style')) drops.style += 1;
|
|
307
420
|
}
|
|
308
421
|
|
|
309
422
|
/**
|
|
310
|
-
* Start token for a task: declared `after:` deps
|
|
311
|
-
* previous item
|
|
423
|
+
* Start token for a task: `after` its declared `after:` deps and the lane chain
|
|
424
|
+
* (the previous item, every track end after a parallel), deduplicated, as
|
|
425
|
+
* engine C starts it at `max(prevEnd, ...after)`. A member of wave k >= 2 also
|
|
426
|
+
* waits for wave k-1's end milestone (`barrier`). Mermaid's `after a b` starts
|
|
427
|
+
* at the latest of them. With none, a lane or track leader anchors at the
|
|
312
428
|
* roadmap start date. Always non-empty so Mermaid never mis-reads the task id
|
|
313
|
-
* as a start date
|
|
429
|
+
* as a start date; a leader's start date gives way to the barrier, which is
|
|
430
|
+
* never earlier.
|
|
314
431
|
*/
|
|
315
|
-
function startTokenFor(
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
432
|
+
function startTokenFor(
|
|
433
|
+
after: readonly string[],
|
|
434
|
+
chain: Chain,
|
|
435
|
+
startDate: string,
|
|
436
|
+
barrier?: string,
|
|
437
|
+
): string {
|
|
438
|
+
const deps = union(union(after, chain.prevIds), barrier ? [barrier] : []);
|
|
439
|
+
return deps.length > 0 ? `after ${deps.join(' ')}` : startDate;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/** `a` then the ids of `b` it lacks, in order. */
|
|
443
|
+
function union(a: readonly string[], b: readonly string[]): string[] {
|
|
444
|
+
return [...a, ...b.filter((id) => !a.includes(id))];
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/** An item's Mermaid task id: its own id, else a slug of its title. */
|
|
448
|
+
function taskIdOf(item: ItemDeclaration): string {
|
|
449
|
+
return item.name ?? slugify(displayLabel(item));
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/** Every named group and parallel under `lanes`, by id. */
|
|
453
|
+
function namedContainers(
|
|
454
|
+
lanes: readonly SwimlaneDeclaration[],
|
|
455
|
+
): Map<string, GroupBlock | ParallelBlock> {
|
|
456
|
+
const out = new Map<string, GroupBlock | ParallelBlock>();
|
|
457
|
+
for (const node of trackNodes(lanes)) {
|
|
458
|
+
if ((isGroupBlock(node) || isParallelBlock(node)) && node.name) out.set(node.name, node);
|
|
459
|
+
}
|
|
460
|
+
return out;
|
|
319
461
|
}
|
|
320
462
|
|
|
321
463
|
/**
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
464
|
+
* `after:` ids with each group and parallel replaced by the tasks that end it,
|
|
465
|
+
* without duplicates. Neither container is a Mermaid task, and Mermaid starts
|
|
466
|
+
* a task with an unknown `after` id on the day it renders. Engine C ends a
|
|
467
|
+
* group at its last child's end and a parallel at its latest track end;
|
|
468
|
+
* Mermaid's `after a b` starts at the latest end of the tasks it names, so the
|
|
469
|
+
* expansion lands on the same day.
|
|
325
470
|
*/
|
|
326
|
-
function
|
|
471
|
+
function expandAfter(
|
|
472
|
+
after: readonly string[],
|
|
473
|
+
containers: ReadonlyMap<string, GroupBlock | ParallelBlock>,
|
|
474
|
+
): string[] {
|
|
475
|
+
const out: string[] = [];
|
|
476
|
+
for (const ref of after) {
|
|
477
|
+
const container = containers.get(ref);
|
|
478
|
+
for (const id of container ? endTaskIds(container) : [ref]) {
|
|
479
|
+
if (!out.includes(id)) out.push(id);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return out;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/** The task ids that end a track node: an item, a group's last child, or every parallel track. */
|
|
486
|
+
function endTaskIds(node: TrackNode): string[] {
|
|
487
|
+
if (isGroupBlock(node)) {
|
|
488
|
+
const last = trackChildren(node).at(-1);
|
|
489
|
+
return last ? endTaskIds(last) : [];
|
|
490
|
+
}
|
|
491
|
+
if (isParallelBlock(node)) return trackChildren(node).flatMap(endTaskIds);
|
|
492
|
+
return [taskIdOf(node)];
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/** The previous wave's id for a member of wave k >= 2; undefined otherwise. */
|
|
496
|
+
function previousWaveOf(item: ItemDeclaration, waves: WaveCtx | undefined): string | undefined {
|
|
497
|
+
if (!waves) return undefined;
|
|
498
|
+
const k = waves.plan.memberWave(item);
|
|
499
|
+
return k !== undefined && k >= 2 ? waves.ids[k - 2] : undefined;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Absolute anchor date for lane leaders. Prefers the roadmap's declared
|
|
504
|
+
* `start:`, falling back to the layout-computed timeline start (always
|
|
505
|
+
* present) so the export renders even when the source omits `start:`. An
|
|
506
|
+
* impossible `start:` (`2026-02-30`, NL.E0405) falls back the same way,
|
|
507
|
+
* as layout treats it, rather than rolling over to March 2.
|
|
508
|
+
*/
|
|
509
|
+
function resolveStartDate(inputs: ExportInputs): Date {
|
|
327
510
|
const decl = inputs.ast.roadmapDecl;
|
|
328
511
|
const declared = decl ? getProp(decl, 'start') : undefined;
|
|
329
|
-
|
|
330
|
-
|
|
512
|
+
return parseIsoDate(declared?.trim()) ?? inputs.model.timeline.startDate;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/** Monday first, as Mermaid's docs write `excludes`. */
|
|
516
|
+
const WEEKDAY_NAMES_MONDAY_FIRST: ReadonlyArray<[number, string]> = [
|
|
517
|
+
[1, 'monday'],
|
|
518
|
+
[2, 'tuesday'],
|
|
519
|
+
[3, 'wednesday'],
|
|
520
|
+
[4, 'thursday'],
|
|
521
|
+
[5, 'friday'],
|
|
522
|
+
[6, 'saturday'],
|
|
523
|
+
[0, 'sunday'],
|
|
524
|
+
];
|
|
525
|
+
|
|
526
|
+
/** The open week's non-working days, as Mermaid `excludes` names. */
|
|
527
|
+
function excludedWeekdays(working: WorkingCalendar): string[] {
|
|
528
|
+
return WEEKDAY_NAMES_MONDAY_FIRST.filter(
|
|
529
|
+
([weekday]) => !working.workingWeekdays.has(weekday),
|
|
530
|
+
).map(([, name]) => name);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const DAY_MS = 86_400_000;
|
|
534
|
+
|
|
535
|
+
/** The ISO date of every day in every non-working exception, ascending. */
|
|
536
|
+
function excludedDates(exceptions: readonly CalendarException[]): string[] {
|
|
537
|
+
const dates: string[] = [];
|
|
538
|
+
for (const exception of exceptions) {
|
|
539
|
+
if (exception.working) continue;
|
|
540
|
+
for (let t = exception.from.getTime(); t <= exception.through.getTime(); t += DAY_MS) {
|
|
541
|
+
dates.push(formatIsoDate(new Date(t)));
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return dates;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/** Days across the working exceptions. */
|
|
548
|
+
function workingDayCount(exceptions: readonly CalendarException[]): number {
|
|
549
|
+
let days = 0;
|
|
550
|
+
for (const exception of exceptions) {
|
|
551
|
+
if (!exception.working) continue;
|
|
552
|
+
days += Math.round((exception.through.getTime() - exception.from.getTime()) / DAY_MS) + 1;
|
|
553
|
+
}
|
|
554
|
+
return days;
|
|
331
555
|
}
|
|
332
556
|
|
|
333
557
|
function formatIsoDate(d: Date): string {
|
|
@@ -390,6 +614,8 @@ function formatDrops(drops: DropCounts): string | null {
|
|
|
390
614
|
'nestedSwimlanes',
|
|
391
615
|
'description',
|
|
392
616
|
'style',
|
|
617
|
+
'waveFloor',
|
|
618
|
+
'workingDay',
|
|
393
619
|
];
|
|
394
620
|
const parts = order
|
|
395
621
|
.filter((key) => drops[key] > 0)
|
|
@@ -403,5 +629,7 @@ function formatDrops(drops: DropCounts): string | null {
|
|
|
403
629
|
|
|
404
630
|
function formatDropKey(key: keyof DropCounts): string {
|
|
405
631
|
if (key === 'nestedSwimlanes') return 'nested-swimlanes';
|
|
632
|
+
if (key === 'waveFloor') return 'wave-floor';
|
|
633
|
+
if (key === 'workingDay') return 'working-day';
|
|
406
634
|
return key;
|
|
407
635
|
}
|