@transitrix/diagrams 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +47 -47
- package/dist/__tests__/edge-path.test.js +8 -0
- package/dist/activity-card/__tests__/example.test.js +20 -1
- package/dist/activity-card/__tests__/layout.test.js +102 -11
- package/dist/activity-card/__tests__/resolver.test.js +139 -6
- package/dist/activity-card/index.d.ts +1 -1
- package/dist/activity-card/layout.d.ts +1 -1
- package/dist/activity-card/layout.js +220 -103
- package/dist/activity-card/resolver.js +107 -26
- package/dist/activity-card/types.d.ts +150 -27
- package/dist/activity-card/validate.js +3 -0
- package/dist/actor/__tests__/validate.test.js +63 -31
- package/dist/actor/index.d.ts +1 -1
- package/dist/actor/index.js +1 -1
- package/dist/actor/types.d.ts +7 -3
- package/dist/actor/types.js +17 -3
- package/dist/actor/validate.js +55 -26
- package/dist/assertion/types.d.ts +3 -1
- package/dist/assertion/types.js +1 -1
- package/dist/change/__tests__/validate.test.js +40 -34
- package/dist/change/index.d.ts +1 -0
- package/dist/change/types.d.ts +1 -1
- package/dist/change/types.js +2 -2
- package/dist/change/validate.d.ts +6 -1
- package/dist/change/validate.js +68 -41
- package/dist/compliance/__tests__/classify.test.js +34 -0
- package/dist/compliance/__tests__/coverage-metric.test.js +146 -46
- package/dist/compliance/__tests__/html.test.js +2 -2
- package/dist/compliance/__tests__/impact.test.js +311 -6
- package/dist/compliance/classify.d.ts +6 -0
- package/dist/compliance/classify.js +9 -1
- package/dist/compliance/coverage-metric.d.ts +31 -11
- package/dist/compliance/coverage-metric.js +149 -39
- package/dist/compliance/html.js +77 -74
- package/dist/compliance/impact.d.ts +77 -16
- package/dist/compliance/impact.js +193 -25
- package/dist/compliance/index.d.ts +2 -2
- package/dist/compliance/index.js +1 -1
- package/dist/compliance/markdown.js +1 -0
- package/dist/compliance/types.d.ts +25 -6
- package/dist/edge-path.d.ts +8 -4
- package/dist/edge-path.js +11 -6
- package/dist/factor/__tests__/validate.test.js +74 -45
- package/dist/factor/index.d.ts +3 -2
- package/dist/factor/index.js +1 -1
- package/dist/factor/types.d.ts +4 -7
- package/dist/factor/types.js +10 -5
- package/dist/factor/validate.d.ts +6 -1
- package/dist/factor/validate.js +68 -50
- package/dist/fgca/__tests__/resolver.test.js +185 -0
- package/dist/fgca/index.d.ts +2 -0
- package/dist/fgca/index.js +1 -0
- package/dist/fgca/resolver.d.ts +49 -0
- package/dist/fgca/resolver.js +124 -0
- package/dist/goals/index.d.ts +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/process-blueprint/__tests__/layout.test.js +37 -0
- package/dist/process-blueprint/layout.js +5 -1
- package/dist/process-blueprint/types.d.ts +22 -1
- package/dist/stakeholder/__tests__/validate.test.js +49 -47
- package/dist/stakeholder/index.d.ts +1 -0
- package/dist/stakeholder/types.d.ts +3 -4
- package/dist/stakeholder/types.js +2 -3
- package/dist/stakeholder/validate.d.ts +6 -1
- package/dist/stakeholder/validate.js +71 -50
- package/dist/target-state/__tests__/validate.test.js +43 -27
- package/dist/target-state/index.d.ts +2 -0
- package/dist/target-state/index.js +1 -0
- package/dist/target-state/types.d.ts +6 -1
- package/dist/target-state/types.js +8 -7
- package/dist/target-state/validate.d.ts +6 -1
- package/dist/target-state/validate.js +69 -45
- package/dist/theme/themes.js +69 -69
- package/dist/webview/__tests__/entry.test.js +11 -11
- package/dist/webview/render-activities.d.ts +3 -1
- package/dist/webview/render-activities.js +2 -2
- package/dist/webview/render-activity-card.js +104 -77
- package/dist/webview/render-fgca.d.ts +4 -0
- package/dist/webview/render-fgca.js +2 -5
- package/dist/webview/render-goals.d.ts +1 -0
- package/dist/webview/render-goals.js +15 -15
- package/dist/webview/render-process-blueprint.js +10 -10
- package/package.json +40 -40
- package/src/__tests__/edge-path.test.ts +58 -46
- package/src/__tests__/scope.test.ts +27 -27
- package/src/__tests__/yaml-normalize.test.ts +158 -158
- package/src/activities/__tests__/cpm.test.ts +164 -164
- package/src/activities/__tests__/gantt.test.ts +245 -245
- package/src/activities/__tests__/layout.test.ts +112 -112
- package/src/activities/__tests__/validate.test.ts +409 -409
- package/src/activities/cpm.ts +95 -95
- package/src/activities/gantt.ts +276 -276
- package/src/activities/index.ts +28 -28
- package/src/activities/layout.ts +112 -112
- package/src/activities/types.ts +148 -148
- package/src/activities/validate.ts +357 -357
- package/src/activity-card/__tests__/example.test.ts +85 -66
- package/src/activity-card/__tests__/layout.test.ts +169 -63
- package/src/activity-card/__tests__/resolver.test.ts +307 -161
- package/src/activity-card/__tests__/validate.test.ts +131 -131
- package/src/activity-card/index.ts +38 -32
- package/src/activity-card/layout.ts +324 -194
- package/src/activity-card/resolver.ts +415 -337
- package/src/activity-card/types.ts +376 -237
- package/src/activity-card/validate.ts +162 -158
- package/src/actor/__tests__/validate.test.ts +70 -31
- package/src/actor/index.ts +1 -1
- package/src/actor/types.ts +21 -7
- package/src/actor/validate.ts +59 -27
- package/src/applications/__tests__/validate.test.ts +256 -256
- package/src/applications/index.ts +11 -11
- package/src/applications/types.ts +43 -43
- package/src/applications/validate.ts +131 -131
- package/src/assertion/__tests__/example.test.ts +37 -37
- package/src/assertion/__tests__/validate.test.ts +142 -142
- package/src/assertion/index.ts +12 -12
- package/src/assertion/types.ts +60 -58
- package/src/assertion/validate.ts +145 -145
- package/src/blocks/__tests__/layout.test.ts +169 -169
- package/src/blocks/__tests__/validate.test.ts +260 -260
- package/src/blocks/index.ts +17 -17
- package/src/blocks/layout.ts +186 -186
- package/src/blocks/types.ts +62 -62
- package/src/blocks/validate.ts +206 -206
- package/src/capability-map/__tests__/validate.test.ts +238 -238
- package/src/capability-map/index.ts +8 -8
- package/src/capability-map/types.ts +29 -29
- package/src/capability-map/validate.ts +127 -127
- package/src/change/__tests__/validate.test.ts +43 -34
- package/src/change/index.ts +1 -0
- package/src/change/types.ts +5 -3
- package/src/change/validate.ts +75 -43
- package/src/compliance/__tests__/classify.test.ts +64 -27
- package/src/compliance/__tests__/confidence.test.ts +98 -98
- package/src/compliance/__tests__/coverage-metric.test.ts +300 -188
- package/src/compliance/__tests__/demo-scenario.test.ts +273 -273
- package/src/compliance/__tests__/example.test.ts +57 -57
- package/src/compliance/__tests__/gap-report.test.ts +128 -128
- package/src/compliance/__tests__/html.test.ts +141 -141
- package/src/compliance/__tests__/impact.test.ts +840 -481
- package/src/compliance/__tests__/markdown.test.ts +94 -94
- package/src/compliance/__tests__/views.test.ts +64 -64
- package/src/compliance/classify.ts +100 -84
- package/src/compliance/confidence.ts +69 -69
- package/src/compliance/coverage-metric.ts +404 -263
- package/src/compliance/gap-report.ts +94 -94
- package/src/compliance/html.ts +298 -295
- package/src/compliance/impact.ts +861 -677
- package/src/compliance/index.ts +57 -56
- package/src/compliance/markdown.ts +136 -135
- package/src/compliance/reverse-index.ts +33 -33
- package/src/compliance/types.ts +136 -120
- package/src/compliance/views.ts +46 -46
- package/src/compliance-matrix/__tests__/build.test.ts +200 -200
- package/src/compliance-matrix/__tests__/example.test.ts +57 -57
- package/src/compliance-matrix/index.ts +11 -11
- package/src/compliance-matrix/types.ts +102 -102
- package/src/edge-path.ts +50 -44
- package/src/factor/__tests__/validate.test.ts +80 -45
- package/src/factor/index.ts +3 -7
- package/src/factor/types.ts +14 -18
- package/src/factor/validate.ts +77 -51
- package/src/fgca/__tests__/chain-table.test.ts +172 -172
- package/src/fgca/__tests__/layout.test.ts +179 -179
- package/src/fgca/__tests__/parse-canonical.test.ts +248 -248
- package/src/fgca/__tests__/preview-layout.test.ts +124 -124
- package/src/fgca/__tests__/resolver.test.ts +209 -0
- package/src/fgca/__tests__/validate.test.ts +142 -142
- package/src/fgca/chain-table.ts +225 -225
- package/src/fgca/index.ts +47 -45
- package/src/fgca/layout.ts +204 -204
- package/src/fgca/nodeTypes.ts +11 -11
- package/src/fgca/nodes/FGCAActivityNode.tsx +65 -65
- package/src/fgca/nodes/FGCAChangeNode.tsx +64 -64
- package/src/fgca/nodes/FGCAFactorNode.tsx +64 -64
- package/src/fgca/nodes/FGCAGoalNode.tsx +72 -72
- package/src/fgca/parse-canonical.ts +400 -400
- package/src/fgca/preview-layout.ts +217 -217
- package/src/fgca/resolver.ts +157 -0
- package/src/fgca/types.ts +50 -50
- package/src/fgca/validate.ts +126 -126
- package/src/geometry.ts +9 -9
- package/src/goals/__tests__/layout.test.ts +175 -175
- package/src/goals/__tests__/mutations.test.ts +111 -111
- package/src/goals/__tests__/parse-canonical.test.ts +145 -145
- package/src/goals/__tests__/validate.test.ts +202 -202
- package/src/goals/index.ts +20 -21
- package/src/goals/layout.ts +172 -172
- package/src/goals/mutations.ts +123 -123
- package/src/goals/parse-canonical.ts +286 -286
- package/src/goals/types.ts +85 -85
- package/src/goals/validate.ts +136 -136
- package/src/index.ts +28 -23
- package/src/process-blueprint/__tests__/compliance-lane.test.ts +320 -320
- package/src/process-blueprint/__tests__/layout.test.ts +240 -195
- package/src/process-blueprint/__tests__/validate.test.ts +310 -310
- package/src/process-blueprint/index.ts +31 -31
- package/src/process-blueprint/layout.ts +535 -531
- package/src/process-blueprint/types.ts +263 -242
- package/src/process-blueprint/validate.ts +181 -181
- package/src/process-map/__tests__/validate.test.ts +223 -223
- package/src/process-map/index.ts +10 -10
- package/src/process-map/types.ts +36 -36
- package/src/process-map/validate.ts +135 -135
- package/src/products/__tests__/validate.test.ts +239 -239
- package/src/products/index.ts +9 -9
- package/src/products/types.ts +31 -31
- package/src/products/validate.ts +112 -112
- package/src/repo-validate/__tests__/validate-repo.test.ts +149 -149
- package/src/repo-validate/index.ts +2 -2
- package/src/repo-validate/types.ts +50 -50
- package/src/repo-validate/validate-repo.ts +196 -196
- package/src/requirement/__tests__/example.test.ts +24 -24
- package/src/requirement/__tests__/validate.test.ts +96 -96
- package/src/requirement/index.ts +4 -4
- package/src/requirement/types.ts +35 -35
- package/src/requirement/validate.ts +92 -92
- package/src/scenarios/__tests__/validate.test.ts +209 -209
- package/src/scenarios/index.ts +15 -15
- package/src/scenarios/types.ts +37 -37
- package/src/scenarios/validate.ts +122 -122
- package/src/schema-version.ts +16 -16
- package/src/scope.ts +46 -46
- package/src/stakeholder/__tests__/validate.test.ts +51 -47
- package/src/stakeholder/index.ts +1 -0
- package/src/stakeholder/types.ts +7 -7
- package/src/stakeholder/validate.ts +79 -52
- package/src/target-state/__tests__/validate.test.ts +48 -27
- package/src/target-state/index.ts +2 -0
- package/src/target-state/types.ts +11 -7
- package/src/target-state/validate.ts +76 -46
- package/src/theme/index.ts +4 -4
- package/src/theme/themes.ts +237 -237
- package/src/theme/tokens.ts +133 -133
- package/src/typed-id.ts +56 -56
- package/src/validation-types.ts +36 -36
- package/src/webview/__tests__/entry-notations.test.ts +77 -77
- package/src/webview/__tests__/entry.test.ts +64 -64
- package/src/webview/__tests__/render-goals.test.ts +72 -72
- package/src/webview/entry.ts +292 -292
- package/src/webview/render-activities.ts +5 -3
- package/src/webview/render-activity-card.ts +266 -234
- package/src/webview/render-fgca.ts +6 -5
- package/src/webview/render-goals.ts +111 -110
- package/src/webview/render-process-blueprint.ts +207 -207
- package/src/webview/styles.css +322 -323
- package/src/yaml-normalize.ts +56 -56
- package/dist/element-envelope.d.ts +0 -15
- package/dist/element-envelope.js +0 -55
- package/dist/issues/__tests__/layout.test.js +0 -62
- package/dist/issues/__tests__/validate.test.d.ts +0 -1
- package/dist/issues/__tests__/validate.test.js +0 -82
- package/dist/issues/index.d.ts +0 -4
- package/dist/issues/index.js +0 -2
- package/dist/issues/layout.d.ts +0 -10
- package/dist/issues/layout.js +0 -82
- package/dist/issues/types.d.ts +0 -61
- package/dist/issues/types.js +0 -6
- package/dist/issues/validate.d.ts +0 -3
- package/dist/issues/validate.js +0 -143
- package/dist/webview/transitrix-render.css +0 -323
- package/dist/webview/transitrix-render.js +0 -6452
- package/dist/webview/transitrix-render.js.map +0 -7
- package/src/element-envelope.ts +0 -76
- /package/dist/{issues/__tests__/layout.test.d.ts → fgca/__tests__/resolver.test.d.ts} +0 -0
package/src/activities/cpm.ts
CHANGED
|
@@ -1,95 +1,95 @@
|
|
|
1
|
-
import type { Activity, CpmResult, CpmValues } from './types.js';
|
|
2
|
-
|
|
3
|
-
export function computeCpm(activities: Activity[]): CpmResult {
|
|
4
|
-
const result: CpmResult = new Map();
|
|
5
|
-
|
|
6
|
-
if (activities.length === 0) return result;
|
|
7
|
-
|
|
8
|
-
// Build successor map and in-degree for topological sort
|
|
9
|
-
const successors = new Map<string, string[]>();
|
|
10
|
-
const predecessors = new Map<string, string[]>();
|
|
11
|
-
for (const a of activities) {
|
|
12
|
-
successors.set(a.id, []);
|
|
13
|
-
predecessors.set(a.id, a.predecessors?.filter(p => p !== a.id) ?? []);
|
|
14
|
-
}
|
|
15
|
-
for (const a of activities) {
|
|
16
|
-
for (const pred of (predecessors.get(a.id) ?? [])) {
|
|
17
|
-
successors.get(pred)?.push(a.id);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Topological sort (Kahn's)
|
|
22
|
-
const inDegree = new Map<string, number>();
|
|
23
|
-
for (const a of activities) {
|
|
24
|
-
inDegree.set(a.id, (predecessors.get(a.id) ?? []).length);
|
|
25
|
-
}
|
|
26
|
-
const queue: string[] = [];
|
|
27
|
-
for (const a of activities) {
|
|
28
|
-
if ((inDegree.get(a.id) ?? 0) === 0) queue.push(a.id);
|
|
29
|
-
}
|
|
30
|
-
const topoOrder: string[] = [];
|
|
31
|
-
while (queue.length > 0) {
|
|
32
|
-
const id = queue.shift()!;
|
|
33
|
-
topoOrder.push(id);
|
|
34
|
-
for (const succ of (successors.get(id) ?? [])) {
|
|
35
|
-
const newDeg = (inDegree.get(succ) ?? 1) - 1;
|
|
36
|
-
inDegree.set(succ, newDeg);
|
|
37
|
-
if (newDeg === 0) queue.push(succ);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const actById = new Map(activities.map(a => [a.id, a]));
|
|
42
|
-
|
|
43
|
-
// Forward pass
|
|
44
|
-
const es = new Map<string, number>();
|
|
45
|
-
const ef = new Map<string, number>();
|
|
46
|
-
for (const id of topoOrder) {
|
|
47
|
-
const a = actById.get(id)!;
|
|
48
|
-
const dur = a.duration ?? 0;
|
|
49
|
-
const maxPredEf = Math.max(0, ...(predecessors.get(id) ?? []).map(p => ef.get(p) ?? 0));
|
|
50
|
-
es.set(id, maxPredEf);
|
|
51
|
-
ef.set(id, maxPredEf + dur);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Project finish
|
|
55
|
-
const projectFinish = Math.max(0, ...[...ef.values()]);
|
|
56
|
-
|
|
57
|
-
// Backward pass
|
|
58
|
-
const ls = new Map<string, number>();
|
|
59
|
-
const lf = new Map<string, number>();
|
|
60
|
-
for (const id of [...topoOrder].reverse()) {
|
|
61
|
-
const a = actById.get(id)!;
|
|
62
|
-
const dur = a.duration ?? 0;
|
|
63
|
-
const succs = successors.get(id) ?? [];
|
|
64
|
-
const minSuccLs = succs.length === 0 ? projectFinish : Math.min(...succs.map(s => ls.get(s) ?? projectFinish));
|
|
65
|
-
lf.set(id, minSuccLs);
|
|
66
|
-
ls.set(id, minSuccLs - dur);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Assemble result
|
|
70
|
-
for (const id of topoOrder) {
|
|
71
|
-
const esV = es.get(id) ?? 0;
|
|
72
|
-
const efV = ef.get(id) ?? 0;
|
|
73
|
-
const lsV = ls.get(id) ?? 0;
|
|
74
|
-
const lfV = lf.get(id) ?? 0;
|
|
75
|
-
const slack = lsV - esV;
|
|
76
|
-
result.set(id, { es: esV, ef: efV, ls: lsV, lf: lfV, slack, isCritical: slack <= 0 });
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Cycle defence: Kahn's topo-order silently omits any activity that's part
|
|
80
|
-
// of a cycle (its in-degree never reaches zero), and the forward/backward
|
|
81
|
-
// passes above skip those nodes. The validator's ACT-006 is the
|
|
82
|
-
// authoritative cycle error — but layoutActivities is reachable without
|
|
83
|
-
// validation, so fill the omitted nodes with neutral CPM values so
|
|
84
|
-
// downstream consumers don't see `undefined` entries. Cyclic activities
|
|
85
|
-
// simply render without critical-path highlighting.
|
|
86
|
-
if (topoOrder.length < activities.length) {
|
|
87
|
-
for (const a of activities) {
|
|
88
|
-
if (!result.has(a.id)) {
|
|
89
|
-
result.set(a.id, { es: 0, ef: 0, ls: 0, lf: 0, slack: 0, isCritical: false });
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
return result;
|
|
95
|
-
}
|
|
1
|
+
import type { Activity, CpmResult, CpmValues } from './types.js';
|
|
2
|
+
|
|
3
|
+
export function computeCpm(activities: Activity[]): CpmResult {
|
|
4
|
+
const result: CpmResult = new Map();
|
|
5
|
+
|
|
6
|
+
if (activities.length === 0) return result;
|
|
7
|
+
|
|
8
|
+
// Build successor map and in-degree for topological sort
|
|
9
|
+
const successors = new Map<string, string[]>();
|
|
10
|
+
const predecessors = new Map<string, string[]>();
|
|
11
|
+
for (const a of activities) {
|
|
12
|
+
successors.set(a.id, []);
|
|
13
|
+
predecessors.set(a.id, a.predecessors?.filter(p => p !== a.id) ?? []);
|
|
14
|
+
}
|
|
15
|
+
for (const a of activities) {
|
|
16
|
+
for (const pred of (predecessors.get(a.id) ?? [])) {
|
|
17
|
+
successors.get(pred)?.push(a.id);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Topological sort (Kahn's)
|
|
22
|
+
const inDegree = new Map<string, number>();
|
|
23
|
+
for (const a of activities) {
|
|
24
|
+
inDegree.set(a.id, (predecessors.get(a.id) ?? []).length);
|
|
25
|
+
}
|
|
26
|
+
const queue: string[] = [];
|
|
27
|
+
for (const a of activities) {
|
|
28
|
+
if ((inDegree.get(a.id) ?? 0) === 0) queue.push(a.id);
|
|
29
|
+
}
|
|
30
|
+
const topoOrder: string[] = [];
|
|
31
|
+
while (queue.length > 0) {
|
|
32
|
+
const id = queue.shift()!;
|
|
33
|
+
topoOrder.push(id);
|
|
34
|
+
for (const succ of (successors.get(id) ?? [])) {
|
|
35
|
+
const newDeg = (inDegree.get(succ) ?? 1) - 1;
|
|
36
|
+
inDegree.set(succ, newDeg);
|
|
37
|
+
if (newDeg === 0) queue.push(succ);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const actById = new Map(activities.map(a => [a.id, a]));
|
|
42
|
+
|
|
43
|
+
// Forward pass
|
|
44
|
+
const es = new Map<string, number>();
|
|
45
|
+
const ef = new Map<string, number>();
|
|
46
|
+
for (const id of topoOrder) {
|
|
47
|
+
const a = actById.get(id)!;
|
|
48
|
+
const dur = a.duration ?? 0;
|
|
49
|
+
const maxPredEf = Math.max(0, ...(predecessors.get(id) ?? []).map(p => ef.get(p) ?? 0));
|
|
50
|
+
es.set(id, maxPredEf);
|
|
51
|
+
ef.set(id, maxPredEf + dur);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Project finish
|
|
55
|
+
const projectFinish = Math.max(0, ...[...ef.values()]);
|
|
56
|
+
|
|
57
|
+
// Backward pass
|
|
58
|
+
const ls = new Map<string, number>();
|
|
59
|
+
const lf = new Map<string, number>();
|
|
60
|
+
for (const id of [...topoOrder].reverse()) {
|
|
61
|
+
const a = actById.get(id)!;
|
|
62
|
+
const dur = a.duration ?? 0;
|
|
63
|
+
const succs = successors.get(id) ?? [];
|
|
64
|
+
const minSuccLs = succs.length === 0 ? projectFinish : Math.min(...succs.map(s => ls.get(s) ?? projectFinish));
|
|
65
|
+
lf.set(id, minSuccLs);
|
|
66
|
+
ls.set(id, minSuccLs - dur);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Assemble result
|
|
70
|
+
for (const id of topoOrder) {
|
|
71
|
+
const esV = es.get(id) ?? 0;
|
|
72
|
+
const efV = ef.get(id) ?? 0;
|
|
73
|
+
const lsV = ls.get(id) ?? 0;
|
|
74
|
+
const lfV = lf.get(id) ?? 0;
|
|
75
|
+
const slack = lsV - esV;
|
|
76
|
+
result.set(id, { es: esV, ef: efV, ls: lsV, lf: lfV, slack, isCritical: slack <= 0 });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Cycle defence: Kahn's topo-order silently omits any activity that's part
|
|
80
|
+
// of a cycle (its in-degree never reaches zero), and the forward/backward
|
|
81
|
+
// passes above skip those nodes. The validator's ACT-006 is the
|
|
82
|
+
// authoritative cycle error — but layoutActivities is reachable without
|
|
83
|
+
// validation, so fill the omitted nodes with neutral CPM values so
|
|
84
|
+
// downstream consumers don't see `undefined` entries. Cyclic activities
|
|
85
|
+
// simply render without critical-path highlighting.
|
|
86
|
+
if (topoOrder.length < activities.length) {
|
|
87
|
+
for (const a of activities) {
|
|
88
|
+
if (!result.has(a.id)) {
|
|
89
|
+
result.set(a.id, { es: 0, ef: 0, ls: 0, lf: 0, slack: 0, isCritical: false });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return result;
|
|
95
|
+
}
|