@transitrix/diagrams 1.0.0 → 1.1.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/LICENSE +21 -21
- package/README.md +47 -47
- package/dist/__tests__/edge-path.test.js +8 -0
- package/dist/activities/cpm.js +11 -2
- package/dist/activities/gantt.js +6 -3
- package/dist/activities/types.d.ts +1 -0
- package/dist/activities/validate.js +3 -3
- 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 +161 -7
- 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 +115 -28
- 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 +509 -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 +78 -81
- package/dist/compliance/impact.d.ts +100 -16
- package/dist/compliance/impact.js +272 -28
- 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 +75 -46
- package/dist/factor/index.d.ts +3 -2
- package/dist/factor/index.js +1 -1
- package/dist/factor/types.d.ts +5 -8
- 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__/chain-table.test.js +2 -2
- package/dist/fgca/__tests__/layout.test.js +11 -11
- package/dist/fgca/__tests__/preview-layout.test.js +7 -7
- package/dist/fgca/__tests__/resolver.test.js +185 -0
- package/dist/fgca/chain-table.d.ts +1 -1
- package/dist/fgca/chain-table.js +4 -4
- package/dist/fgca/index.d.ts +4 -2
- package/dist/fgca/index.js +2 -1
- package/dist/fgca/layout.d.ts +2 -2
- package/dist/fgca/layout.js +9 -9
- package/dist/fgca/nodeTypes.d.ts +1 -1
- package/dist/fgca/nodeTypes.js +2 -2
- package/dist/fgca/nodes/FGCAFactorNode.d.ts +3 -3
- package/dist/fgca/nodes/FGCAFactorNode.js +5 -5
- package/dist/fgca/parse-canonical.js +15 -10
- package/dist/fgca/preview-layout.d.ts +1 -1
- package/dist/fgca/preview-layout.js +4 -4
- package/dist/fgca/resolver.d.ts +49 -0
- package/dist/fgca/resolver.js +126 -0
- package/dist/fgca/types.d.ts +11 -11
- package/dist/fgca/types.js +2 -2
- package/dist/fgca/validate.d.ts +2 -2
- package/dist/fgca/validate.js +17 -14
- 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/index.d.ts +1 -1
- package/dist/process-blueprint/layout.js +66 -35
- package/dist/process-blueprint/types.d.ts +36 -1
- package/dist/scenarios/index.d.ts +1 -1
- package/dist/scenarios/types.d.ts +4 -4
- 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 +71 -69
- package/dist/theme/tokens.d.ts +7 -1
- package/dist/theme/tokens.js +3 -1
- package/dist/webview/__tests__/entry-notations.test.js +2 -0
- package/dist/webview/__tests__/entry.test.js +11 -11
- package/dist/webview/__tests__/render-process.test.js +463 -0
- package/dist/webview/__tests__/render-util.test.d.ts +1 -0
- package/dist/webview/__tests__/render-util.test.js +54 -0
- package/dist/webview/entry.d.ts +1 -1
- package/dist/webview/entry.js +9 -5
- package/dist/webview/render-activities.d.ts +24 -2
- package/dist/webview/render-activities.js +92 -57
- package/dist/webview/render-activity-card.d.ts +11 -1
- package/dist/webview/render-activity-card.js +115 -79
- package/dist/webview/render-blocks.d.ts +24 -1
- package/dist/webview/render-blocks.js +58 -24
- package/dist/webview/render-fgca.d.ts +31 -0
- package/dist/webview/render-fgca.js +30 -19
- package/dist/webview/render-goals.d.ts +27 -1
- package/dist/webview/render-goals.js +42 -32
- package/dist/webview/render-process-blueprint.d.ts +11 -1
- package/dist/webview/render-process-blueprint.js +118 -53
- package/dist/webview/render-process.d.ts +95 -0
- package/dist/webview/render-process.js +392 -0
- package/dist/webview/render-scenarios.js +2 -2
- package/dist/webview/render-util.d.ts +19 -6
- package/dist/webview/render-util.js +23 -15
- package/package.json +54 -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 +107 -95
- package/src/activities/gantt.ts +277 -276
- package/src/activities/index.ts +28 -28
- package/src/activities/layout.ts +112 -112
- package/src/activities/types.ts +149 -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 +330 -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 +422 -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 +1059 -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 +291 -295
- package/src/compliance/impact.ts +979 -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 +81 -46
- package/src/factor/index.ts +3 -7
- package/src/factor/types.ts +15 -19
- 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 +405 -400
- package/src/fgca/preview-layout.ts +217 -217
- package/src/fgca/resolver.ts +159 -0
- package/src/fgca/types.ts +50 -50
- package/src/fgca/validate.ts +129 -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 +32 -31
- package/src/process-blueprint/layout.ts +564 -531
- package/src/process-blueprint/types.ts +278 -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 +239 -237
- package/src/theme/tokens.ts +135 -133
- package/src/typed-id.ts +56 -56
- package/src/validation-types.ts +36 -36
- package/src/webview/__tests__/entry-notations.test.ts +79 -77
- package/src/webview/__tests__/entry.test.ts +64 -64
- package/src/webview/__tests__/render-goals.test.ts +72 -72
- package/src/webview/__tests__/render-process.test.ts +538 -0
- package/src/webview/__tests__/render-util.test.ts +66 -0
- package/src/webview/entry.ts +298 -292
- package/src/webview/render-activities.ts +111 -69
- package/src/webview/render-activity-card.ts +275 -234
- package/src/webview/render-blocks.ts +78 -28
- package/src/webview/render-fgca.ts +53 -28
- package/src/webview/render-goals.ts +133 -110
- package/src/webview/render-process-blueprint.ts +281 -207
- package/src/webview/render-process.ts +507 -0
- package/src/webview/render-scenarios.ts +3 -3
- package/src/webview/render-util.ts +27 -14
- 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.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/dist/{issues/__tests__/validate.test.d.ts → webview/__tests__/render-process.test.d.ts} +0 -0
|
@@ -1,234 +1,275 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Host-neutral SVG renderer for the Activity Card notation.
|
|
3
|
-
*
|
|
4
|
-
* Step 4 of the IntelliJ epic (ADR 0001): the webview bundle must turn a
|
|
5
|
-
* validated Activity Card document into renderable SVG so JCEF can drop it into
|
|
6
|
-
* the preview panel. The VS Code path lives in
|
|
7
|
-
* `extension/src/activity-card-preview.ts` and pulls in VS Code-specific
|
|
8
|
-
* concerns (themes, title block, save dialogs, sibling-document discovery on
|
|
9
|
-
* the filesystem); this module is the host-neutral subset — pure layout → SVG
|
|
10
|
-
* with no VS Code APIs, no `node:fs`, no `node:path`.
|
|
11
|
-
*
|
|
12
|
-
* CROSS-DOCUMENT RESOLUTION CAVEAT
|
|
13
|
-
* The Activity Card is the only MULTI-DOCUMENT Studio notation: the card YAML
|
|
14
|
-
* names a project Activity, and the project's name, dates, motivation chain
|
|
15
|
-
* (
|
|
16
|
-
* the canonical element + relation store (`canon/elements/**`,
|
|
17
|
-
* `canon/relations/**`; see `../activity-card/resolver.ts`). That resolution
|
|
18
|
-
* requires reading those files from disk, which is NOT available inside the
|
|
19
|
-
* JCEF host. We therefore resolve from the single in-memory card document
|
|
20
|
-
* ONLY: we synthesise
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
} from '../
|
|
35
|
-
import {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
parts.push(
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
parts.push(
|
|
124
|
-
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
</
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Host-neutral SVG renderer for the Activity Card notation.
|
|
3
|
+
*
|
|
4
|
+
* Step 4 of the IntelliJ epic (ADR 0001): the webview bundle must turn a
|
|
5
|
+
* validated Activity Card document into renderable SVG so JCEF can drop it into
|
|
6
|
+
* the preview panel. The VS Code path lives in
|
|
7
|
+
* `extension/src/activity-card-preview.ts` and pulls in VS Code-specific
|
|
8
|
+
* concerns (themes, title block, save dialogs, sibling-document discovery on
|
|
9
|
+
* the filesystem); this module is the host-neutral subset — pure layout → SVG
|
|
10
|
+
* with no VS Code APIs, no `node:fs`, no `node:path`.
|
|
11
|
+
*
|
|
12
|
+
* CROSS-DOCUMENT RESOLUTION CAVEAT
|
|
13
|
+
* The Activity Card is the only MULTI-DOCUMENT Studio notation: the card YAML
|
|
14
|
+
* names a project Activity, and the project's name, dates, motivation chain
|
|
15
|
+
* (Drivers → Assessments → Goals → Changes) and child activities are pulled BY
|
|
16
|
+
* REFERENCE from the canonical element + relation store (`canon/elements/**`,
|
|
17
|
+
* `canon/relations/**`; see `../activity-card/resolver.ts`). That resolution
|
|
18
|
+
* requires reading those files from disk, which is NOT available inside the
|
|
19
|
+
* JCEF host. We therefore resolve from the single in-memory card document
|
|
20
|
+
* ONLY: we synthesise a minimal `ResolvedActivityCard` whose project carries
|
|
21
|
+
* just the referenced project id (no resolved name/dates), whose milestones
|
|
22
|
+
* come straight from the card's own `milestones[]`, and whose chain sections
|
|
23
|
+
* and child activities are empty. The SVG layout is shared with the VS Code
|
|
24
|
+
* path via `layoutActivityCard`, so a single-document card still renders its
|
|
25
|
+
* title, dates band and milestone section.
|
|
26
|
+
*/
|
|
27
|
+
import { layoutActivityCard, ARCHIMATE_CLASS } from '../activity-card/layout.js';
|
|
28
|
+
import type {
|
|
29
|
+
ActivityCardDoc,
|
|
30
|
+
ActivityCardLayout,
|
|
31
|
+
ResolvedActivityCard,
|
|
32
|
+
ResolvedMilestone,
|
|
33
|
+
} from '../activity-card/types.js';
|
|
34
|
+
import { generateSvgEmbedCss } from '../theme/index.js';
|
|
35
|
+
import { escXml } from './render-util.js';
|
|
36
|
+
|
|
37
|
+
const PAD = 24;
|
|
38
|
+
const EMPTY_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" viewBox="0 0 0 0"></svg>`;
|
|
39
|
+
|
|
40
|
+
export interface RenderActivityCardOptions {
|
|
41
|
+
title?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function truncate(text: string, maxChars: number): string {
|
|
45
|
+
if (text.length <= maxChars) return text;
|
|
46
|
+
return text.slice(0, Math.max(0, maxChars - 1)) + '…';
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function resolveSingleDoc(doc: ActivityCardDoc): ResolvedActivityCard {
|
|
50
|
+
const card = doc.activity_card;
|
|
51
|
+
const rawMilestones = Array.isArray(card?.milestones) ? card.milestones : [];
|
|
52
|
+
|
|
53
|
+
const milestones: ResolvedMilestone[] = rawMilestones
|
|
54
|
+
.filter((m): m is NonNullable<typeof m> => !!m && typeof m === 'object')
|
|
55
|
+
.map((m) => ({
|
|
56
|
+
id: m.id,
|
|
57
|
+
name: m.name,
|
|
58
|
+
date: m.date,
|
|
59
|
+
description: m.description,
|
|
60
|
+
deliversChanges: Array.isArray(m.delivers_changes) ? m.delivers_changes : [],
|
|
61
|
+
}))
|
|
62
|
+
.sort((a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0));
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
cardId: card?.id ?? '',
|
|
66
|
+
cardDescription: card?.description,
|
|
67
|
+
// No sibling docs in the host-neutral path: the project resolves to its id
|
|
68
|
+
// only. The layout falls back to '—' for the unknown date fields.
|
|
69
|
+
project: { id: card?.project ?? '', name: card?.project ?? '' },
|
|
70
|
+
milestones,
|
|
71
|
+
motivation: { drivers: [], goals: [], changes: [] },
|
|
72
|
+
assessments: [],
|
|
73
|
+
childActivities: [],
|
|
74
|
+
notes: card?.notes,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* The single Activity Card SVG body emitter shared by every host. Takes an
|
|
80
|
+
* already-laid-out {@link ActivityCardLayout} plus the canvas offset and emits
|
|
81
|
+
* the body elements (card, header, badges, dates, chain sections, milestones,
|
|
82
|
+
* child activities, footer) — everything except the host chrome (`<defs>`
|
|
83
|
+
* marker, title, embedded CSS, `<svg>` wrapper). The VS Code preview and the
|
|
84
|
+
* host-neutral {@link renderActivityCardSvg} both build their own chrome around
|
|
85
|
+
* this single source of truth.
|
|
86
|
+
*/
|
|
87
|
+
export function renderActivityCardBody(layout: ActivityCardLayout, ox: number, oy: number): string {
|
|
88
|
+
const parts: string[] = [];
|
|
89
|
+
|
|
90
|
+
// Outer card.
|
|
91
|
+
parts.push(
|
|
92
|
+
`<rect class="diagram-node level-0" x="${ox}" y="${oy}" width="${layout.bounds.width}" height="${layout.bounds.height}" rx="8"/>`,
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// Title row.
|
|
96
|
+
parts.push(
|
|
97
|
+
`<text class="text-header" x="${layout.titleRow.x + ox}" y="${layout.titleRow.y + oy}" style="dominant-baseline:central" font-size="18">${escXml(truncate(layout.titleRow.name, 60))}</text>`,
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
// Activity type badge.
|
|
101
|
+
if (layout.activityTypeBadge) {
|
|
102
|
+
const b = layout.activityTypeBadge;
|
|
103
|
+
parts.push(`<rect class="diagram-node level-2" x="${b.x + ox}" y="${b.y + oy}" width="${b.width}" height="${b.height}" rx="4"/>`);
|
|
104
|
+
parts.push(`<text class="text-secondary" style="dominant-baseline:central;text-anchor:middle" x="${b.x + ox + b.width / 2}" y="${b.y + oy + b.height / 2}">${escXml(b.label)}</text>`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Status badge.
|
|
108
|
+
if (layout.statusBadge) {
|
|
109
|
+
const b = layout.statusBadge;
|
|
110
|
+
parts.push(`<rect class="diagram-node level-3" x="${b.x + ox}" y="${b.y + oy}" width="${b.width}" height="${b.height}" rx="4"/>`);
|
|
111
|
+
parts.push(`<text class="text-secondary" style="dominant-baseline:central;text-anchor:middle" x="${b.x + ox + b.width / 2}" y="${b.y + oy + b.height / 2}">${escXml(b.label)}</text>`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Date fields.
|
|
115
|
+
for (const d of layout.dateFields) {
|
|
116
|
+
parts.push(`<rect class="diagram-node level-2" x="${d.x + ox}" y="${d.y + oy}" width="${d.width}" height="${d.height}" rx="6"/>`);
|
|
117
|
+
parts.push(`<text class="text-secondary" x="${d.x + ox + 12}" y="${d.y + oy + 18}" style="dominant-baseline:central">${escXml(d.label)}</text>`);
|
|
118
|
+
parts.push(`<text class="text-primary" x="${d.x + ox + 12}" y="${d.y + oy + 40}" style="dominant-baseline:central">${escXml(d.value)}</text>`);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Stakeholder role slots (2-column grid).
|
|
122
|
+
for (const s of layout.stakeholderRoleSlots) {
|
|
123
|
+
parts.push(`<rect class="diagram-node level-2" x="${s.x + ox}" y="${s.y + oy}" width="${s.width}" height="${s.height}" rx="6"/>`);
|
|
124
|
+
parts.push(`<text class="text-secondary" x="${s.x + ox + 10}" y="${s.y + oy + 16}" style="dominant-baseline:central">${escXml(s.role)}</text>`);
|
|
125
|
+
parts.push(`<text class="text-primary" x="${s.x + ox + 10}" y="${s.y + oy + 36}" style="dominant-baseline:central">${escXml(truncate(s.name, 40))}</text>`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Description row.
|
|
129
|
+
if (layout.descriptionRow) {
|
|
130
|
+
const r = layout.descriptionRow;
|
|
131
|
+
parts.push(`<rect class="diagram-node level-2" x="${r.x + ox}" y="${r.y + oy}" width="${r.width}" height="${r.height}" rx="6"/>`);
|
|
132
|
+
parts.push(`<text class="text-secondary" x="${r.x + ox + 12}" y="${r.y + oy + 22}" style="dominant-baseline:central">${escXml(r.label)}</text>`);
|
|
133
|
+
r.valueLines.forEach((line, i) => {
|
|
134
|
+
parts.push(`<text class="text-primary" x="${r.x + ox + 12}" y="${r.y + oy + 44 + i * 18}" style="dominant-baseline:central">${escXml(line)}</text>`);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Chain sections (Drivers → Assessments → Goals → Changes).
|
|
139
|
+
const SECTION_LEVEL: Record<string, number> = {
|
|
140
|
+
drivers: 4,
|
|
141
|
+
assessments: 5,
|
|
142
|
+
goals: 5,
|
|
143
|
+
changes: 6,
|
|
144
|
+
};
|
|
145
|
+
for (let si = 0; si < layout.chainSections.length; si++) {
|
|
146
|
+
const section = layout.chainSections[si];
|
|
147
|
+
const level = SECTION_LEVEL[section.type] ?? 5;
|
|
148
|
+
|
|
149
|
+
// Section outer box.
|
|
150
|
+
parts.push(
|
|
151
|
+
`<rect class="diagram-node level-1" x="${section.x + ox}" y="${section.y + oy}" width="${section.width}" height="${section.height}" rx="6"/>`,
|
|
152
|
+
);
|
|
153
|
+
// Section header label + subtitle.
|
|
154
|
+
parts.push(
|
|
155
|
+
`<text class="text-header" x="${section.x + ox + 12}" y="${section.y + oy + 14}" style="dominant-baseline:central">${escXml(section.label)}<tspan class="text-secondary" font-size="11"> (${escXml(section.subtitle)})</tspan></text>`,
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
if (section.isEmpty) {
|
|
159
|
+
// Gap indicator.
|
|
160
|
+
parts.push(
|
|
161
|
+
`<text class="text-secondary" x="${section.x + ox + 12}" y="${section.y + oy + 24 + 8 + 16}" style="dominant-baseline:central">— not on file</text>`,
|
|
162
|
+
);
|
|
163
|
+
} else {
|
|
164
|
+
for (const n of section.nodes) {
|
|
165
|
+
parts.push(
|
|
166
|
+
`<rect class="diagram-node level-${level}" x="${n.x + ox}" y="${n.y + oy}" width="${n.width}" height="${n.height}" rx="4"/>`,
|
|
167
|
+
);
|
|
168
|
+
parts.push(
|
|
169
|
+
`<text class="text-primary" x="${n.x + ox + 10}" y="${n.y + oy + (n.meta ? 16 : n.height / 2)}" style="dominant-baseline:central">${escXml(truncate(n.name, 80))}</text>`,
|
|
170
|
+
);
|
|
171
|
+
if (n.meta) {
|
|
172
|
+
parts.push(
|
|
173
|
+
`<text class="text-secondary" x="${n.x + ox + 10}" y="${n.y + oy + 30}" style="dominant-baseline:central">${escXml(n.meta)}</text>`,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Connector arrow to next section.
|
|
180
|
+
if (si < layout.chainSections.length - 1) {
|
|
181
|
+
const nextSection = layout.chainSections[si + 1];
|
|
182
|
+
const arrowX = section.x + ox + section.width / 2;
|
|
183
|
+
const arrowTopY = section.y + oy + section.height;
|
|
184
|
+
const arrowBotY = nextSection.y + oy;
|
|
185
|
+
const midY = (arrowTopY + arrowBotY) / 2;
|
|
186
|
+
parts.push(
|
|
187
|
+
`<path class="diagram-edge" d="M${arrowX},${arrowTopY} L${arrowX},${arrowBotY}" fill="none" marker-end="url(#ac-arrow)"/>`,
|
|
188
|
+
);
|
|
189
|
+
void midY; // midpoint available for future label placement
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// Milestones.
|
|
194
|
+
for (const m of layout.milestones) {
|
|
195
|
+
parts.push(
|
|
196
|
+
`<rect class="diagram-node level-3" x="${m.x + ox}" y="${m.y + oy}" width="${m.width}" height="${m.height}" rx="6"/>`,
|
|
197
|
+
);
|
|
198
|
+
parts.push(
|
|
199
|
+
`<text class="text-secondary" x="${m.x + ox + 10}" y="${m.y + oy + 16}" style="dominant-baseline:central">${escXml(m.date)}</text>`,
|
|
200
|
+
);
|
|
201
|
+
parts.push(
|
|
202
|
+
`<text class="text-primary" x="${m.x + ox + 10}" y="${m.y + oy + 36}" style="dominant-baseline:central">${escXml(truncate(m.name, 22))}</text>`,
|
|
203
|
+
);
|
|
204
|
+
parts.push(
|
|
205
|
+
`<text class="text-secondary" x="${m.x + ox + 10}" y="${m.y + oy + 52}" style="dominant-baseline:central">(${escXml(m.archimateClass)})</text>`,
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Child activities.
|
|
210
|
+
for (const a of layout.childActivities) {
|
|
211
|
+
parts.push(
|
|
212
|
+
`<rect class="diagram-node level-1" x="${a.x + ox}" y="${a.y + oy}" width="${a.width}" height="${a.height}" rx="6"/>`,
|
|
213
|
+
);
|
|
214
|
+
parts.push(
|
|
215
|
+
`<text class="text-primary" x="${a.x + ox + 12}" y="${a.y + oy + a.height / 2}" style="dominant-baseline:central">${escXml(truncate(a.name, 48))} <tspan class="text-secondary">(${escXml(a.archimateClass)})</tspan></text>`,
|
|
216
|
+
);
|
|
217
|
+
if (a.meta) {
|
|
218
|
+
parts.push(
|
|
219
|
+
`<text class="text-secondary" x="${a.x + a.width + ox - 12}" y="${a.y + oy + a.height / 2}" style="dominant-baseline:central;text-anchor:end">${escXml(truncate(a.meta, 40))}</text>`,
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Footer — notes.
|
|
225
|
+
if (layout.footerRow) {
|
|
226
|
+
const r = layout.footerRow;
|
|
227
|
+
parts.push(`<rect class="diagram-node level-2" x="${r.x + ox}" y="${r.y + oy}" width="${r.width}" height="${r.height}" rx="6"/>`);
|
|
228
|
+
parts.push(`<text class="text-secondary" x="${r.x + ox + 12}" y="${r.y + oy + 22}" style="dominant-baseline:central">${escXml(r.label)}</text>`);
|
|
229
|
+
r.valueLines.forEach((line, i) => {
|
|
230
|
+
parts.push(`<text class="text-primary" x="${r.x + ox + 12}" y="${r.y + oy + 44 + i * 18}" style="dominant-baseline:central">${escXml(line)}</text>`);
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return parts.join('\n');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export function renderActivityCardSvg(
|
|
238
|
+
doc: ActivityCardDoc,
|
|
239
|
+
options: RenderActivityCardOptions = {},
|
|
240
|
+
): string {
|
|
241
|
+
// `ARCHIMATE_CLASS` is referenced so the host-neutral module pins the same
|
|
242
|
+
// §5.1 class convention the layout applies; keeps the import meaningful.
|
|
243
|
+
void ARCHIMATE_CLASS;
|
|
244
|
+
|
|
245
|
+
const { title = '' } = options;
|
|
246
|
+
const resolved = resolveSingleDoc(doc);
|
|
247
|
+
const layout = layoutActivityCard(resolved);
|
|
248
|
+
|
|
249
|
+
if (layout.bounds.width <= 0 || layout.bounds.height <= 0) return EMPTY_SVG;
|
|
250
|
+
|
|
251
|
+
const titleH = title ? 28 : 0;
|
|
252
|
+
const w = layout.bounds.width + PAD * 2;
|
|
253
|
+
const h = layout.bounds.height + PAD * 2 + titleH;
|
|
254
|
+
const ox = PAD;
|
|
255
|
+
const oy = PAD + titleH;
|
|
256
|
+
|
|
257
|
+
const body = renderActivityCardBody(layout, ox, oy);
|
|
258
|
+
|
|
259
|
+
const titleSvg = title
|
|
260
|
+
? `<text class="text-header" x="${PAD}" y="${PAD + 14}">${escXml(`Activity Card — ${title}`)}</text>`
|
|
261
|
+
: '';
|
|
262
|
+
|
|
263
|
+
const embedCss = generateSvgEmbedCss('transitrix');
|
|
264
|
+
|
|
265
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${w}" height="${h}" viewBox="0 0 ${w} ${h}">
|
|
266
|
+
<style>${embedCss}</style>
|
|
267
|
+
<defs>
|
|
268
|
+
<marker id="ac-arrow" markerWidth="8" markerHeight="8" refX="8" refY="3" orient="auto">
|
|
269
|
+
<path d="M0,0 L0,6 L8,3 z" class="arrow-fill"/>
|
|
270
|
+
</marker>
|
|
271
|
+
</defs>
|
|
272
|
+
${titleSvg}
|
|
273
|
+
${body}
|
|
274
|
+
</svg>`;
|
|
275
|
+
}
|