@formicoidea/labre-framework-uml 0.42.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 +384 -0
- package/dist/actions.d.ts +430 -0
- package/dist/actions.js +724 -0
- package/dist/background.d.ts +153 -0
- package/dist/background.js +557 -0
- package/dist/board-hit.d.ts +137 -0
- package/dist/board-hit.js +191 -0
- package/dist/commands-manifest.d.ts +19 -0
- package/dist/commands-manifest.js +571 -0
- package/dist/commands.d.ts +4 -0
- package/dist/commands.js +983 -0
- package/dist/component.d.ts +521 -0
- package/dist/component.js +708 -0
- package/dist/consts.d.ts +365 -0
- package/dist/consts.js +463 -0
- package/dist/descriptor.d.ts +12 -0
- package/dist/descriptor.js +10 -0
- package/dist/drawio-decode.d.ts +32 -0
- package/dist/drawio-decode.js +96 -0
- package/dist/drawio-import.d.ts +133 -0
- package/dist/drawio-import.js +885 -0
- package/dist/edge-morph.d.ts +154 -0
- package/dist/edge-morph.js +153 -0
- package/dist/edge-styles.d.ts +78 -0
- package/dist/edge-styles.js +210 -0
- package/dist/effects.d.ts +9 -0
- package/dist/effects.js +6 -0
- package/dist/element-renderer.d.ts +64 -0
- package/dist/element-renderer.js +114 -0
- package/dist/element-view.d.ts +234 -0
- package/dist/element-view.js +430 -0
- package/dist/export.d.ts +61 -0
- package/dist/export.js +41 -0
- package/dist/filename.d.ts +17 -0
- package/dist/filename.js +26 -0
- package/dist/frame-tag.d.ts +70 -0
- package/dist/frame-tag.js +78 -0
- package/dist/grammar.d.ts +695 -0
- package/dist/grammar.js +1436 -0
- package/dist/import.d.ts +306 -0
- package/dist/import.js +1270 -0
- package/dist/index.d.ts +47 -0
- package/dist/index.js +67 -0
- package/dist/interchange.d.ts +125 -0
- package/dist/interchange.js +372 -0
- package/dist/keywords.d.ts +204 -0
- package/dist/keywords.js +361 -0
- package/dist/kinds.d.ts +73 -0
- package/dist/kinds.js +91 -0
- package/dist/legend.d.ts +30 -0
- package/dist/legend.js +255 -0
- package/dist/model.d.ts +862 -0
- package/dist/model.js +1316 -0
- package/dist/morph.d.ts +178 -0
- package/dist/morph.js +496 -0
- package/dist/node/act-glyphs.d.ts +30 -0
- package/dist/node/act-glyphs.js +142 -0
- package/dist/node/compartment-watcher.d.ts +107 -0
- package/dist/node/compartment-watcher.js +163 -0
- package/dist/node/fit.d.ts +85 -0
- package/dist/node/fit.js +129 -0
- package/dist/node/node-renderer.d.ts +49 -0
- package/dist/node/node-renderer.js +611 -0
- package/dist/node/node-view.d.ts +51 -0
- package/dist/node/node-view.js +89 -0
- package/dist/node/paint.d.ts +84 -0
- package/dist/node/paint.js +143 -0
- package/dist/node/sd-glyphs.d.ts +36 -0
- package/dist/node/sd-glyphs.js +79 -0
- package/dist/node/stm-glyphs.d.ts +22 -0
- package/dist/node/stm-glyphs.js +111 -0
- package/dist/node/tier-metrics.d.ts +38 -0
- package/dist/node/tier-metrics.js +45 -0
- package/dist/operators.d.ts +45 -0
- package/dist/operators.js +75 -0
- package/dist/plantuml-import.d.ts +113 -0
- package/dist/plantuml-import.js +1723 -0
- package/dist/plantuml.d.ts +94 -0
- package/dist/plantuml.js +985 -0
- package/dist/presets.d.ts +149 -0
- package/dist/presets.js +302 -0
- package/dist/profiles.d.ts +2 -0
- package/dist/profiles.js +358 -0
- package/dist/reading.d.ts +160 -0
- package/dist/reading.js +648 -0
- package/dist/roles.d.ts +257 -0
- package/dist/roles.js +997 -0
- package/dist/rules.d.ts +267 -0
- package/dist/rules.js +3090 -0
- package/dist/templates.d.ts +2 -0
- package/dist/templates.js +197 -0
- package/dist/toolbar/config.d.ts +228 -0
- package/dist/toolbar/config.js +833 -0
- package/dist/toolbar/icons.d.ts +440 -0
- package/dist/toolbar/icons.js +711 -0
- package/dist/toolbar/senior-tool.d.ts +11 -0
- package/dist/toolbar/senior-tool.js +21 -0
- package/dist/toolbar/uml-menu.d.ts +17 -0
- package/dist/toolbar/uml-menu.js +20 -0
- package/dist/toolbar/uml-senior-button.d.ts +18 -0
- package/dist/toolbar/uml-senior-button.js +22 -0
- package/dist/translations.d.ts +27 -0
- package/dist/translations.js +117 -0
- package/dist/view.d.ts +33 -0
- package/dist/view.js +236 -0
- package/dist/xmi-import.d.ts +174 -0
- package/dist/xmi-import.js +2268 -0
- package/dist/xmi.d.ts +61 -0
- package/dist/xmi.js +1860 -0
- package/dist/xml-reader.d.ts +157 -0
- package/dist/xml-reader.js +430 -0
- package/dist/xml.d.ts +72 -0
- package/dist/xml.js +96 -0
- package/package.json +38 -0
package/dist/roles.js
ADDED
|
@@ -0,0 +1,997 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Role ids, keyed by their own name.
|
|
3
|
+
*
|
|
4
|
+
* Keyed by the ROLE and not by the `kind`: UML has thirty-eight node kinds and
|
|
5
|
+
* forty-one node roles, because `uml:classifier`, `uml:control-node` and
|
|
6
|
+
* `uml:pseudostate` are parents nothing is ever drawn as. ({@link
|
|
7
|
+
* UML_ROLE.node} is a parent too, and IS drawn — §19.4 makes a Node
|
|
8
|
+
* instantiable — so it does not add a role of its own.)
|
|
9
|
+
* {@link UML_ROLE_OF_KIND} is the bridge, and it is the only place the two
|
|
10
|
+
* vocabularies meet.
|
|
11
|
+
*/
|
|
12
|
+
export const UML_ROLE = {
|
|
13
|
+
classifier: 'uml:classifier',
|
|
14
|
+
class: 'uml:class',
|
|
15
|
+
interface: 'uml:interface',
|
|
16
|
+
enumeration: 'uml:enumeration',
|
|
17
|
+
object: 'uml:object',
|
|
18
|
+
package: 'uml:package',
|
|
19
|
+
note: 'uml:note',
|
|
20
|
+
actor: 'uml:actor',
|
|
21
|
+
'use-case': 'uml:use-case',
|
|
22
|
+
component: 'uml:component',
|
|
23
|
+
port: 'uml:port',
|
|
24
|
+
'provided-interface': 'uml:provided-interface',
|
|
25
|
+
'required-interface': 'uml:required-interface',
|
|
26
|
+
artifact: 'uml:artifact',
|
|
27
|
+
node: 'uml:node',
|
|
28
|
+
device: 'uml:device',
|
|
29
|
+
'execution-environment': 'uml:execution-environment',
|
|
30
|
+
'control-node': 'uml:control-node',
|
|
31
|
+
action: 'uml:action',
|
|
32
|
+
initial: 'uml:initial',
|
|
33
|
+
'activity-final': 'uml:activity-final',
|
|
34
|
+
'flow-final': 'uml:flow-final',
|
|
35
|
+
decision: 'uml:decision',
|
|
36
|
+
fork: 'uml:fork',
|
|
37
|
+
'object-node': 'uml:object-node',
|
|
38
|
+
'send-signal': 'uml:send-signal',
|
|
39
|
+
'accept-event': 'uml:accept-event',
|
|
40
|
+
'time-event': 'uml:time-event',
|
|
41
|
+
state: 'uml:state',
|
|
42
|
+
'final-state': 'uml:final-state',
|
|
43
|
+
pseudostate: 'uml:pseudostate',
|
|
44
|
+
choice: 'uml:choice',
|
|
45
|
+
junction: 'uml:junction',
|
|
46
|
+
'shallow-history': 'uml:shallow-history',
|
|
47
|
+
'deep-history': 'uml:deep-history',
|
|
48
|
+
'entry-point': 'uml:entry-point',
|
|
49
|
+
'exit-point': 'uml:exit-point',
|
|
50
|
+
terminate: 'uml:terminate',
|
|
51
|
+
lifeline: 'uml:lifeline',
|
|
52
|
+
execution: 'uml:execution',
|
|
53
|
+
destruction: 'uml:destruction',
|
|
54
|
+
name: 'uml:name',
|
|
55
|
+
attributes: 'uml:attributes',
|
|
56
|
+
operations: 'uml:operations',
|
|
57
|
+
label: 'uml:label',
|
|
58
|
+
'lifeline-ident': 'uml:lifeline-ident',
|
|
59
|
+
diagram: 'uml:diagram',
|
|
60
|
+
subject: 'uml:subject',
|
|
61
|
+
partition: 'uml:partition',
|
|
62
|
+
region: 'uml:region',
|
|
63
|
+
fragment: 'uml:fragment',
|
|
64
|
+
operand: 'uml:operand',
|
|
65
|
+
association: 'uml:association',
|
|
66
|
+
aggregation: 'uml:aggregation',
|
|
67
|
+
composition: 'uml:composition',
|
|
68
|
+
generalization: 'uml:generalization',
|
|
69
|
+
realization: 'uml:realization',
|
|
70
|
+
dependency: 'uml:dependency',
|
|
71
|
+
anchor: 'uml:anchor',
|
|
72
|
+
include: 'uml:include',
|
|
73
|
+
extend: 'uml:extend',
|
|
74
|
+
deploy: 'uml:deploy',
|
|
75
|
+
manifest: 'uml:manifest',
|
|
76
|
+
'communication-path': 'uml:communication-path',
|
|
77
|
+
'control-flow': 'uml:control-flow',
|
|
78
|
+
'object-flow': 'uml:object-flow',
|
|
79
|
+
transition: 'uml:transition',
|
|
80
|
+
message: 'uml:message',
|
|
81
|
+
'message-sync': 'uml:message-sync',
|
|
82
|
+
'message-async': 'uml:message-async',
|
|
83
|
+
'message-reply': 'uml:message-reply',
|
|
84
|
+
'message-create': 'uml:message-create',
|
|
85
|
+
'message-delete': 'uml:message-delete',
|
|
86
|
+
};
|
|
87
|
+
const _everyRoleIsMapped = true;
|
|
88
|
+
void _everyRoleIsMapped;
|
|
89
|
+
/**
|
|
90
|
+
* i18n key stem of a role id: `uml:class` → `com.labre.uml.role.class`.
|
|
91
|
+
*
|
|
92
|
+
* Exported because the creation sites seed an artefact's NAME from the same key
|
|
93
|
+
* a role labels itself with (a diagram drawn in a French host should not be
|
|
94
|
+
* called "Diagram"): one key for the role and for the seed, because they are the
|
|
95
|
+
* same noun and a host must not be asked to word it twice.
|
|
96
|
+
*/
|
|
97
|
+
export const umlRoleKey = (local) => `com.labre.uml.role.${local}`;
|
|
98
|
+
/** The same, from a full role id. */
|
|
99
|
+
const roleKey = (id) => umlRoleKey(id.slice('uml:'.length));
|
|
100
|
+
/** The diagram frame's own key, read by `createUmlDiagram` to seed its name. */
|
|
101
|
+
export const umlDiagramRoleKey = roleKey(UML_ROLE.diagram);
|
|
102
|
+
/** The subject's own key, read by `createUmlSubject` to seed its name. */
|
|
103
|
+
export const umlSubjectRoleKey = roleKey(UML_ROLE.subject);
|
|
104
|
+
/** The partition's own key, read by `createUmlPartition` to seed its name. */
|
|
105
|
+
export const umlPartitionRoleKey = roleKey(UML_ROLE.partition);
|
|
106
|
+
/** The composite state's own key, read by `createUmlRegion` to seed its name. */
|
|
107
|
+
export const umlRegionRoleKey = roleKey(UML_ROLE.region);
|
|
108
|
+
/**
|
|
109
|
+
* The combined fragment's own key.
|
|
110
|
+
*
|
|
111
|
+
* Unlike the four above it seeds NO name — §17.6.4 writes a guard only where
|
|
112
|
+
* there is one, so `UmlFragmentElementModel.name` starts empty — and the key is
|
|
113
|
+
* exported for the toolbar and the templates, which still have to call the
|
|
114
|
+
* thing something in the user's language.
|
|
115
|
+
*/
|
|
116
|
+
export const umlFragmentRoleKey = roleKey(UML_ROLE.fragment);
|
|
117
|
+
/**
|
|
118
|
+
* The classifiers (§9.2, §11.4.4) — the compartmented rectangle, and the three
|
|
119
|
+
* keywords that tell its flavours apart — plus every artefact that is not a
|
|
120
|
+
* classifier and is drawn as something else entirely: the four of phase 1, and
|
|
121
|
+
* the eight components and deployment artefacts phase 2 appended.
|
|
122
|
+
*
|
|
123
|
+
* `uml:classifier` is declared but never stamped on an element: it is the
|
|
124
|
+
* ancestor a rule about naming, about visibility or about features is written
|
|
125
|
+
* on, so that the same sentence reaches a class, an interface and an enumeration
|
|
126
|
+
* without being restated three times.
|
|
127
|
+
*/
|
|
128
|
+
const ELEMENT_DEFS = [
|
|
129
|
+
{
|
|
130
|
+
id: UML_ROLE.classifier,
|
|
131
|
+
kind: 'node',
|
|
132
|
+
labelKey: roleKey(UML_ROLE.classifier),
|
|
133
|
+
labelFallback: 'Classifier',
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
id: UML_ROLE.class,
|
|
137
|
+
parent: UML_ROLE.classifier,
|
|
138
|
+
kind: 'node',
|
|
139
|
+
labelKey: roleKey(UML_ROLE.class),
|
|
140
|
+
labelFallback: 'Class',
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
id: UML_ROLE.interface,
|
|
144
|
+
parent: UML_ROLE.classifier,
|
|
145
|
+
kind: 'node',
|
|
146
|
+
labelKey: roleKey(UML_ROLE.interface),
|
|
147
|
+
labelFallback: 'Interface',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
id: UML_ROLE.enumeration,
|
|
151
|
+
parent: UML_ROLE.classifier,
|
|
152
|
+
kind: 'node',
|
|
153
|
+
labelKey: roleKey(UML_ROLE.enumeration),
|
|
154
|
+
labelFallback: 'Enumeration',
|
|
155
|
+
},
|
|
156
|
+
// An INSTANCE of a classifier (§9.8), not a kind of one — see the note at the
|
|
157
|
+
// top of this file on why it stays out of the chain above.
|
|
158
|
+
{
|
|
159
|
+
id: UML_ROLE.object,
|
|
160
|
+
kind: 'node',
|
|
161
|
+
labelKey: roleKey(UML_ROLE.object),
|
|
162
|
+
labelFallback: 'Object',
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: UML_ROLE.package,
|
|
166
|
+
kind: 'node',
|
|
167
|
+
labelKey: roleKey(UML_ROLE.package),
|
|
168
|
+
labelFallback: 'Package',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
id: UML_ROLE.note,
|
|
172
|
+
kind: 'node',
|
|
173
|
+
labelKey: roleKey(UML_ROLE.note),
|
|
174
|
+
labelFallback: 'Note',
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
id: UML_ROLE.actor,
|
|
178
|
+
kind: 'node',
|
|
179
|
+
labelKey: roleKey(UML_ROLE.actor),
|
|
180
|
+
labelFallback: 'Actor',
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
id: UML_ROLE['use-case'],
|
|
184
|
+
kind: 'node',
|
|
185
|
+
labelKey: roleKey(UML_ROLE['use-case']),
|
|
186
|
+
labelFallback: 'Use case',
|
|
187
|
+
},
|
|
188
|
+
// ── The component artefacts (phase 2) ───────────────────────────────────
|
|
189
|
+
// §11.6.4: a Component is drawn as a rectangle with the two-tabbed icon in
|
|
190
|
+
// its top-right corner. Flat, and not under `uml:classifier`: see the header.
|
|
191
|
+
{
|
|
192
|
+
id: UML_ROLE.component,
|
|
193
|
+
kind: 'node',
|
|
194
|
+
labelKey: roleKey(UML_ROLE.component),
|
|
195
|
+
labelFallback: 'Component',
|
|
196
|
+
},
|
|
197
|
+
// §11.3.4: a Port is a small square ON the border of the component that owns
|
|
198
|
+
// it — a part of that component, never a specialisation of it.
|
|
199
|
+
{
|
|
200
|
+
id: UML_ROLE.port,
|
|
201
|
+
kind: 'node',
|
|
202
|
+
labelKey: roleKey(UML_ROLE.port),
|
|
203
|
+
labelFallback: 'Port',
|
|
204
|
+
},
|
|
205
|
+
// §10.4.4: the ball-and-socket pair. Two roles rather than one `uml:interface
|
|
206
|
+
// -point` with a flag, because they are two STATEMENTS — one says a component
|
|
207
|
+
// offers a service, the other that it needs one — and a rule about a required
|
|
208
|
+
// interface left dangling must not fall on every lollipop on the sheet.
|
|
209
|
+
{
|
|
210
|
+
id: UML_ROLE['provided-interface'],
|
|
211
|
+
kind: 'node',
|
|
212
|
+
labelKey: roleKey(UML_ROLE['provided-interface']),
|
|
213
|
+
labelFallback: 'Provided interface',
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
id: UML_ROLE['required-interface'],
|
|
217
|
+
kind: 'node',
|
|
218
|
+
labelKey: roleKey(UML_ROLE['required-interface']),
|
|
219
|
+
labelFallback: 'Required interface',
|
|
220
|
+
},
|
|
221
|
+
// ── The deployment artefacts (phase 2) ──────────────────────────────────
|
|
222
|
+
// §19.3.4: an Artifact is a physical file — drawn as a rectangle with the
|
|
223
|
+
// document icon, and named `«artifact»` over its own file name.
|
|
224
|
+
{
|
|
225
|
+
id: UML_ROLE.artifact,
|
|
226
|
+
kind: 'node',
|
|
227
|
+
labelKey: roleKey(UML_ROLE.artifact),
|
|
228
|
+
labelFallback: 'Artifact',
|
|
229
|
+
},
|
|
230
|
+
// §19.4: the cube, and the two things the spec derives from it. The parent is
|
|
231
|
+
// itself drawn — a Node is instantiable — which is what makes this chain
|
|
232
|
+
// different from `uml:classifier`.
|
|
233
|
+
{
|
|
234
|
+
id: UML_ROLE.node,
|
|
235
|
+
kind: 'node',
|
|
236
|
+
labelKey: roleKey(UML_ROLE.node),
|
|
237
|
+
labelFallback: 'Node',
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
id: UML_ROLE.device,
|
|
241
|
+
parent: UML_ROLE.node,
|
|
242
|
+
kind: 'node',
|
|
243
|
+
labelKey: roleKey(UML_ROLE.device),
|
|
244
|
+
labelFallback: 'Device',
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
id: UML_ROLE['execution-environment'],
|
|
248
|
+
parent: UML_ROLE.node,
|
|
249
|
+
kind: 'node',
|
|
250
|
+
labelKey: roleKey(UML_ROLE['execution-environment']),
|
|
251
|
+
labelFallback: 'Execution environment',
|
|
252
|
+
},
|
|
253
|
+
// ── The activity artefacts (phase 2) ────────────────────────────────────
|
|
254
|
+
// §15.3.4: an Action is the round-cornered rectangle work is written in. Flat
|
|
255
|
+
// — it is the only thing on an activity diagram that DOES anything, and the
|
|
256
|
+
// control nodes below route between actions rather than specialise them.
|
|
257
|
+
{
|
|
258
|
+
id: UML_ROLE.action,
|
|
259
|
+
kind: 'node',
|
|
260
|
+
labelKey: roleKey(UML_ROLE.action),
|
|
261
|
+
labelFallback: 'Action',
|
|
262
|
+
},
|
|
263
|
+
// §15.3.4: the ControlNodes. An abstract parent, stamped on nothing, for the
|
|
264
|
+
// reason `uml:classifier` is one: "a control node carries no name" and "a
|
|
265
|
+
// control flow may end on a control node" are sentences about the five of
|
|
266
|
+
// them at once, and restating each five times is how four of them stay right.
|
|
267
|
+
{
|
|
268
|
+
id: UML_ROLE['control-node'],
|
|
269
|
+
kind: 'node',
|
|
270
|
+
labelKey: roleKey(UML_ROLE['control-node']),
|
|
271
|
+
labelFallback: 'Control node',
|
|
272
|
+
},
|
|
273
|
+
// The filled disc where a flow begins. Filed under the control node because
|
|
274
|
+
// §15.3.4 puts it there — and USED on state machines too, where §14.2.4 draws
|
|
275
|
+
// the identical disc and means the identical thing (one per region, no
|
|
276
|
+
// incoming edge). That cross-family reading is deliberate and recorded here:
|
|
277
|
+
// a rule written on `uml:initial` fires on both diagrams, which is what the
|
|
278
|
+
// two specifications between them say.
|
|
279
|
+
{
|
|
280
|
+
id: UML_ROLE.initial,
|
|
281
|
+
parent: UML_ROLE['control-node'],
|
|
282
|
+
kind: 'node',
|
|
283
|
+
labelKey: roleKey(UML_ROLE.initial),
|
|
284
|
+
labelFallback: 'Initial node',
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
id: UML_ROLE['activity-final'],
|
|
288
|
+
parent: UML_ROLE['control-node'],
|
|
289
|
+
kind: 'node',
|
|
290
|
+
labelKey: roleKey(UML_ROLE['activity-final']),
|
|
291
|
+
labelFallback: 'Activity final',
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
id: UML_ROLE['flow-final'],
|
|
295
|
+
parent: UML_ROLE['control-node'],
|
|
296
|
+
kind: 'node',
|
|
297
|
+
labelKey: roleKey(UML_ROLE['flow-final']),
|
|
298
|
+
labelFallback: 'Flow final',
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
id: UML_ROLE.decision,
|
|
302
|
+
parent: UML_ROLE['control-node'],
|
|
303
|
+
kind: 'node',
|
|
304
|
+
labelKey: roleKey(UML_ROLE.decision),
|
|
305
|
+
labelFallback: 'Decision',
|
|
306
|
+
},
|
|
307
|
+
// §15.3.4 draws a fork and a join as the SAME bar and tells them apart by how
|
|
308
|
+
// many edges run in and out. One role, therefore: two would be this
|
|
309
|
+
// vocabulary claiming a distinction the picture does not carry, and a rule
|
|
310
|
+
// that wants it can count the edges.
|
|
311
|
+
{
|
|
312
|
+
id: UML_ROLE.fork,
|
|
313
|
+
parent: UML_ROLE['control-node'],
|
|
314
|
+
kind: 'node',
|
|
315
|
+
labelKey: roleKey(UML_ROLE.fork),
|
|
316
|
+
labelFallback: 'Fork / join',
|
|
317
|
+
},
|
|
318
|
+
// §15.4.4: an ObjectNode is the DATA that flows between actions, drawn as a
|
|
319
|
+
// plain rectangle. NOT a control node — it is what moves, not what routes —
|
|
320
|
+
// and not an `uml:object` either: an object diagram's instance specification
|
|
321
|
+
// and an activity's object node are different metaclasses that happen to
|
|
322
|
+
// share a rectangle, which is exactly the trap this vocabulary avoids.
|
|
323
|
+
{
|
|
324
|
+
id: UML_ROLE['object-node'],
|
|
325
|
+
kind: 'node',
|
|
326
|
+
labelKey: roleKey(UML_ROLE['object-node']),
|
|
327
|
+
labelFallback: 'Object node',
|
|
328
|
+
},
|
|
329
|
+
// §16.3.4: the two invocation shapes, drawn as the convex and the concave
|
|
330
|
+
// pentagon. Flat and separate, because they are two statements — one sends,
|
|
331
|
+
// the other waits — and the notation gives each its own silhouette.
|
|
332
|
+
{
|
|
333
|
+
id: UML_ROLE['send-signal'],
|
|
334
|
+
kind: 'node',
|
|
335
|
+
labelKey: roleKey(UML_ROLE['send-signal']),
|
|
336
|
+
labelFallback: 'Send signal',
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
id: UML_ROLE['accept-event'],
|
|
340
|
+
kind: 'node',
|
|
341
|
+
labelKey: roleKey(UML_ROLE['accept-event']),
|
|
342
|
+
labelFallback: 'Accept event',
|
|
343
|
+
},
|
|
344
|
+
// §16.10.4: the hourglass — an AcceptEventAction whose trigger is a
|
|
345
|
+
// TimeEvent. A role of its own rather than a flag on `uml:accept-event`,
|
|
346
|
+
// because the notation draws a different picture for it and a reader tells
|
|
347
|
+
// "waits for an order" from "waits two days" by that picture alone.
|
|
348
|
+
{
|
|
349
|
+
id: UML_ROLE['time-event'],
|
|
350
|
+
kind: 'node',
|
|
351
|
+
labelKey: roleKey(UML_ROLE['time-event']),
|
|
352
|
+
labelFallback: 'Time event',
|
|
353
|
+
},
|
|
354
|
+
// ── The state machine artefacts (phase 2) ───────────────────────────────
|
|
355
|
+
// §14.2.4: a State is the round-cornered rectangle a machine rests in. Flat,
|
|
356
|
+
// and emphatically not under `uml:action`: an action is work that happens, a
|
|
357
|
+
// state is a condition that holds, and the two share a silhouette and
|
|
358
|
+
// nothing else.
|
|
359
|
+
{
|
|
360
|
+
id: UML_ROLE.state,
|
|
361
|
+
kind: 'node',
|
|
362
|
+
labelKey: roleKey(UML_ROLE.state),
|
|
363
|
+
labelFallback: 'State',
|
|
364
|
+
},
|
|
365
|
+
// The bullseye. Drawn identically to `uml:activity-final` and kept a separate
|
|
366
|
+
// role all the same, because the two are different metaclasses on different
|
|
367
|
+
// diagrams: a FinalState is a vertex a transition lands on, an
|
|
368
|
+
// ActivityFinalNode stops every flow in the activity. A rule about one must
|
|
369
|
+
// not be handed the other.
|
|
370
|
+
{
|
|
371
|
+
id: UML_ROLE['final-state'],
|
|
372
|
+
kind: 'node',
|
|
373
|
+
labelKey: roleKey(UML_ROLE['final-state']),
|
|
374
|
+
labelFallback: 'Final state',
|
|
375
|
+
},
|
|
376
|
+
// §14.2.4: the Pseudostates. The state machine's own abstract parent, the
|
|
377
|
+
// counterpart of `uml:control-node` and stamped on nothing for the same
|
|
378
|
+
// reason: "a pseudostate carries no name" and "a pseudostate is never where a
|
|
379
|
+
// machine rests" are sentences about all seven at once.
|
|
380
|
+
{
|
|
381
|
+
id: UML_ROLE.pseudostate,
|
|
382
|
+
kind: 'node',
|
|
383
|
+
labelKey: roleKey(UML_ROLE.pseudostate),
|
|
384
|
+
labelFallback: 'Pseudostate',
|
|
385
|
+
},
|
|
386
|
+
{
|
|
387
|
+
id: UML_ROLE.choice,
|
|
388
|
+
parent: UML_ROLE.pseudostate,
|
|
389
|
+
kind: 'node',
|
|
390
|
+
labelKey: roleKey(UML_ROLE.choice),
|
|
391
|
+
labelFallback: 'Choice',
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
id: UML_ROLE.junction,
|
|
395
|
+
parent: UML_ROLE.pseudostate,
|
|
396
|
+
kind: 'node',
|
|
397
|
+
labelKey: roleKey(UML_ROLE.junction),
|
|
398
|
+
labelFallback: 'Junction',
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
id: UML_ROLE['shallow-history'],
|
|
402
|
+
parent: UML_ROLE.pseudostate,
|
|
403
|
+
kind: 'node',
|
|
404
|
+
labelKey: roleKey(UML_ROLE['shallow-history']),
|
|
405
|
+
labelFallback: 'Shallow history',
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
id: UML_ROLE['deep-history'],
|
|
409
|
+
parent: UML_ROLE.pseudostate,
|
|
410
|
+
kind: 'node',
|
|
411
|
+
labelKey: roleKey(UML_ROLE['deep-history']),
|
|
412
|
+
labelFallback: 'Deep history',
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
id: UML_ROLE['entry-point'],
|
|
416
|
+
parent: UML_ROLE.pseudostate,
|
|
417
|
+
kind: 'node',
|
|
418
|
+
labelKey: roleKey(UML_ROLE['entry-point']),
|
|
419
|
+
labelFallback: 'Entry point',
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
id: UML_ROLE['exit-point'],
|
|
423
|
+
parent: UML_ROLE.pseudostate,
|
|
424
|
+
kind: 'node',
|
|
425
|
+
labelKey: roleKey(UML_ROLE['exit-point']),
|
|
426
|
+
labelFallback: 'Exit point',
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
id: UML_ROLE.terminate,
|
|
430
|
+
parent: UML_ROLE.pseudostate,
|
|
431
|
+
kind: 'node',
|
|
432
|
+
labelKey: roleKey(UML_ROLE.terminate),
|
|
433
|
+
labelFallback: 'Terminate',
|
|
434
|
+
},
|
|
435
|
+
// ── The interaction artefacts (phase 3) ─────────────────────────────────
|
|
436
|
+
// §17.3.4: the participant column — a named head over a dashed spine. FLAT
|
|
437
|
+
// under nothing, and pointedly not a child of `uml:object` although its name
|
|
438
|
+
// is written with the same `name : Type` grammar (§17.3.4 reuses §9.8.4's
|
|
439
|
+
// ident): an instance specification is a thing that exists, a lifeline is a
|
|
440
|
+
// thing that TAKES PART, and the rules that police the two share nothing.
|
|
441
|
+
{
|
|
442
|
+
id: UML_ROLE.lifeline,
|
|
443
|
+
kind: 'node',
|
|
444
|
+
labelKey: roleKey(UML_ROLE.lifeline),
|
|
445
|
+
labelFallback: 'Lifeline',
|
|
446
|
+
},
|
|
447
|
+
// §17.2.4's ExecutionSpecification: the thin bar drawn ON a spine saying the
|
|
448
|
+
// participant is busy for that stretch of the conversation. A node of its
|
|
449
|
+
// own rather than a decoration of the lifeline, because a lifeline may carry
|
|
450
|
+
// several and they nest — and because the author positions each one by hand.
|
|
451
|
+
{
|
|
452
|
+
id: UML_ROLE.execution,
|
|
453
|
+
kind: 'node',
|
|
454
|
+
labelKey: roleKey(UML_ROLE.execution),
|
|
455
|
+
labelFallback: 'Execution',
|
|
456
|
+
},
|
|
457
|
+
// §17.2.4's DestructionOccurrenceSpecification: the X that ends a lifeline.
|
|
458
|
+
// Flat, and not a child of `uml:terminate` although both are drawn as a bare
|
|
459
|
+
// cross: a terminate pseudostate kills a state MACHINE, a destruction ends
|
|
460
|
+
// one PARTICIPANT's life in one interaction.
|
|
461
|
+
{
|
|
462
|
+
id: UML_ROLE.destruction,
|
|
463
|
+
kind: 'node',
|
|
464
|
+
labelKey: roleKey(UML_ROLE.destruction),
|
|
465
|
+
labelFallback: 'Destruction',
|
|
466
|
+
},
|
|
467
|
+
];
|
|
468
|
+
/**
|
|
469
|
+
* The written tiers of an artefact's label, as roles on the canvas TEXT
|
|
470
|
+
* elements that carry them.
|
|
471
|
+
*
|
|
472
|
+
* A UML node is a GROUP — the shape plus its words — for the reason C4's
|
|
473
|
+
* component is one (PO recette, 28/08/2026): an architect writes ON the picture,
|
|
474
|
+
* in place, with the ordinary text toolbar, and a field would have been a second
|
|
475
|
+
* place to write the same sentence reachable only through a form. Which leaves
|
|
476
|
+
* one question — given a group of a box and three texts, WHICH text is the
|
|
477
|
+
* attribute compartment? — and the role is the answer that survives a child
|
|
478
|
+
* reordered inside its group, a group ungrouped and regrouped, a tier copied to
|
|
479
|
+
* another node, a tier deleted and redrawn.
|
|
480
|
+
*
|
|
481
|
+
* `uml:name` is the name compartment of every kind that HAS compartments, plus
|
|
482
|
+
* the package's and the note's single line. `uml:label` is the one word written
|
|
483
|
+
* against an actor or inside a use case: the same tier, named differently
|
|
484
|
+
* because it is not a compartment — there is no rectangle for it to be a
|
|
485
|
+
* compartment OF — and a reading profile has to know which of the two to ask for
|
|
486
|
+
* (see `reading.ts`).
|
|
487
|
+
*
|
|
488
|
+
* `kind: 'text'`, as `c4:title` and `wardley:label` are: the BOX of a text
|
|
489
|
+
* element is a creation-time default and not a statement about anything, so a
|
|
490
|
+
* rule measuring one must measure its ink.
|
|
491
|
+
*
|
|
492
|
+
* The GROUP itself is deliberately role-less: a role makes an element count as
|
|
493
|
+
* an artefact for every rule written against roles, and the wrapper round a box
|
|
494
|
+
* is not a second box.
|
|
495
|
+
*/
|
|
496
|
+
const TIER_DEFS = [
|
|
497
|
+
{
|
|
498
|
+
id: UML_ROLE.name,
|
|
499
|
+
kind: 'text',
|
|
500
|
+
labelKey: roleKey(UML_ROLE.name),
|
|
501
|
+
labelFallback: 'Name',
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
id: UML_ROLE.attributes,
|
|
505
|
+
kind: 'text',
|
|
506
|
+
labelKey: roleKey(UML_ROLE.attributes),
|
|
507
|
+
labelFallback: 'Attributes',
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
id: UML_ROLE.operations,
|
|
511
|
+
kind: 'text',
|
|
512
|
+
labelKey: roleKey(UML_ROLE.operations),
|
|
513
|
+
labelFallback: 'Operations',
|
|
514
|
+
},
|
|
515
|
+
{
|
|
516
|
+
id: UML_ROLE.label,
|
|
517
|
+
kind: 'text',
|
|
518
|
+
labelKey: roleKey(UML_ROLE.label),
|
|
519
|
+
labelFallback: 'Label',
|
|
520
|
+
},
|
|
521
|
+
// §17.3.4's LIFELINE HEAD, and the reason it is a fourth tier rather than a
|
|
522
|
+
// fourth user of `uml:label`.
|
|
523
|
+
//
|
|
524
|
+
// What is written in a lifeline's head is not a name: it is a
|
|
525
|
+
// `<lifelineident>` — `order : Order`, `self`, `customers[i] : Customer` — a
|
|
526
|
+
// production the clause prints a BNF for and `parseLifelineIdent` reads back.
|
|
527
|
+
// An actor's word and a use case's phrase are prose, and the clause that
|
|
528
|
+
// draws them prints no grammar at all. Filing all three under `uml:label`
|
|
529
|
+
// would mean the two questions a tier can be asked — "is anything written
|
|
530
|
+
// here" and "does what is written parse" — could only ever be asked of the
|
|
531
|
+
// three together: the spelling rule would indict `Place an order (fast)` on
|
|
532
|
+
// an ellipse, and the naming rule would tell an author of a sequence diagram
|
|
533
|
+
// that their lifeline is an unnamed use case.
|
|
534
|
+
//
|
|
535
|
+
// FLAT, with no `parent: UML_ROLE.label`, and that is the same statement made
|
|
536
|
+
// once more: `roleIsA` would put every rule written on the label tier back on
|
|
537
|
+
// the head, which is precisely what splitting the tier was for. Hierarchy in
|
|
538
|
+
// this vocabulary is only ever the specification's own, and §17.3.4 makes a
|
|
539
|
+
// lifeline ident a kind of nothing.
|
|
540
|
+
{
|
|
541
|
+
id: UML_ROLE['lifeline-ident'],
|
|
542
|
+
kind: 'text',
|
|
543
|
+
labelKey: roleKey(UML_ROLE['lifeline-ident']),
|
|
544
|
+
labelFallback: 'Lifeline identifier',
|
|
545
|
+
},
|
|
546
|
+
];
|
|
547
|
+
/**
|
|
548
|
+
* The frames: the sheet the diagram is drawn on (Annex A) and the rectangle a
|
|
549
|
+
* use case diagram draws round the system's own use cases (§18.1.4).
|
|
550
|
+
*
|
|
551
|
+
* Parent-less, and unrelated to each other: a diagram frame is WHERE the drawing
|
|
552
|
+
* lives, a subject is a statement made INSIDE it about which use cases the
|
|
553
|
+
* system offers. Neither is an element of the model, so a rule about classes,
|
|
554
|
+
* packages, actors or use cases must fall on neither.
|
|
555
|
+
*
|
|
556
|
+
* The subject has no children, unlike `c4:boundary`: §18.1.4 draws one rectangle
|
|
557
|
+
* with one name — no variants, no keyword line, no second tier — so there is
|
|
558
|
+
* nothing here for a specialisation to specialise.
|
|
559
|
+
*/
|
|
560
|
+
const FRAME_DEFS = [
|
|
561
|
+
{
|
|
562
|
+
id: UML_ROLE.diagram,
|
|
563
|
+
kind: 'node',
|
|
564
|
+
labelKey: roleKey(UML_ROLE.diagram),
|
|
565
|
+
labelFallback: 'UML diagram',
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
id: UML_ROLE.subject,
|
|
569
|
+
kind: 'node',
|
|
570
|
+
labelKey: roleKey(UML_ROLE.subject),
|
|
571
|
+
labelFallback: 'Subject',
|
|
572
|
+
},
|
|
573
|
+
// §15.6.4: the swimlane. A frame and not an artefact, for the reason the
|
|
574
|
+
// subject is one — it says who is responsible for the actions drawn in it,
|
|
575
|
+
// and a rule written about actions must not fall on the lane holding them.
|
|
576
|
+
// Membership is geometry at read time (R11), never a stored list.
|
|
577
|
+
{
|
|
578
|
+
id: UML_ROLE.partition,
|
|
579
|
+
kind: 'node',
|
|
580
|
+
labelKey: roleKey(UML_ROLE.partition),
|
|
581
|
+
labelFallback: 'Partition',
|
|
582
|
+
},
|
|
583
|
+
// §14.2.4: the composite state. A frame, although it IS a state — the one
|
|
584
|
+
// place this vocabulary files a model element as furniture, and it does so
|
|
585
|
+
// because the picture is furniture: a rectangle drawn round a sub-machine,
|
|
586
|
+
// with the sub-states inside it by geometry. A rule about states is written
|
|
587
|
+
// on `uml:state`, which this is deliberately not a child of.
|
|
588
|
+
{
|
|
589
|
+
id: UML_ROLE.region,
|
|
590
|
+
kind: 'node',
|
|
591
|
+
labelKey: roleKey(UML_ROLE.region),
|
|
592
|
+
labelFallback: 'Composite state',
|
|
593
|
+
},
|
|
594
|
+
// §17.6.4: the COMBINED FRAGMENT — the rectangle drawn round part of a
|
|
595
|
+
// conversation with `alt`, `loop` or `opt` in its corner — and, under the
|
|
596
|
+
// `ref` operator, §17.7.4's InteractionUse. A frame for the reason the
|
|
597
|
+
// partition is one: it says something ABOUT the messages inside it, and a
|
|
598
|
+
// rule written on messages must not fall on the box round them. What it
|
|
599
|
+
// holds is geometry at read time (R11), never a stored list.
|
|
600
|
+
{
|
|
601
|
+
id: UML_ROLE.fragment,
|
|
602
|
+
kind: 'node',
|
|
603
|
+
labelKey: roleKey(UML_ROLE.fragment),
|
|
604
|
+
labelFallback: 'Combined fragment',
|
|
605
|
+
},
|
|
606
|
+
// One OPERAND of that fragment — the band between two dashed separators, with
|
|
607
|
+
// its own guard. Declared and never stamped on an element, exactly as
|
|
608
|
+
// `uml:classifier` is: an operand is an INSTANCE ZONE of the fragment's own
|
|
609
|
+
// plot (the mechanism the BPMN pool's lanes use), so the only thing that
|
|
610
|
+
// carries this id is a reported zone. It is here so a rule about what may sit
|
|
611
|
+
// in an operand has a name to be written against.
|
|
612
|
+
{
|
|
613
|
+
id: UML_ROLE.operand,
|
|
614
|
+
kind: 'node',
|
|
615
|
+
labelKey: roleKey(UML_ROLE.operand),
|
|
616
|
+
labelFallback: 'Operand',
|
|
617
|
+
},
|
|
618
|
+
];
|
|
619
|
+
/**
|
|
620
|
+
* The relationships — nine typed edges under `docs/adr/0010`.
|
|
621
|
+
*
|
|
622
|
+
* Tier 1 of that ADR is generic — `source` is the subject of the role's verb,
|
|
623
|
+
* `target` its object. Tier 2 is the `direction` block, and UML is the framework
|
|
624
|
+
* that needs it most: the notation's whole grammar is in WHICH END carries the
|
|
625
|
+
* decoration, and an architect who draws a generalization the wrong way round
|
|
626
|
+
* has drawn the opposite statement. So every relationship that HAS a reading
|
|
627
|
+
* declares its verb and the gesture that produces it.
|
|
628
|
+
*
|
|
629
|
+
* Two declare none, and that is a statement too:
|
|
630
|
+
*
|
|
631
|
+
* - `uml:association` is UNDIRECTED (§11.5.4): a plain line between two
|
|
632
|
+
* classifiers says they are related and nothing about which way. Giving it a
|
|
633
|
+
* default verb would put words in the diagram's mouth every time somebody
|
|
634
|
+
* dragged a line and moved on — and, worse, would make the reveal claim a
|
|
635
|
+
* direction the notation explicitly declines to draw.
|
|
636
|
+
* - `uml:anchor` is the dotted line from a note to what it annotates. It has no
|
|
637
|
+
* verb because a comment is not a relationship between two model elements; it
|
|
638
|
+
* is a piece of paper pinned to one.
|
|
639
|
+
*
|
|
640
|
+
* ## The diamond ends, and where the source is
|
|
641
|
+
*
|
|
642
|
+
* For `uml:aggregation` and `uml:composition` the source is the WHOLE — the end
|
|
643
|
+
* that carries the diamond, which `actions.ts` arms as the connector's FRONT
|
|
644
|
+
* endpoint. That is the one asymmetry a user can get backwards without noticing,
|
|
645
|
+
* because both ends of the line look alike until the diamond lands, so the
|
|
646
|
+
* gesture hint says it in as many words.
|
|
647
|
+
*/
|
|
648
|
+
const RELATIONSHIP_DEFS = [
|
|
649
|
+
{
|
|
650
|
+
id: UML_ROLE.association,
|
|
651
|
+
kind: 'edge',
|
|
652
|
+
labelKey: roleKey(UML_ROLE.association),
|
|
653
|
+
labelFallback: 'Association',
|
|
654
|
+
},
|
|
655
|
+
{
|
|
656
|
+
id: UML_ROLE.aggregation,
|
|
657
|
+
parent: UML_ROLE.association,
|
|
658
|
+
kind: 'edge',
|
|
659
|
+
labelKey: roleKey(UML_ROLE.aggregation),
|
|
660
|
+
labelFallback: 'Aggregation',
|
|
661
|
+
direction: {
|
|
662
|
+
verbKey: `${roleKey(UML_ROLE.aggregation)}.verb`,
|
|
663
|
+
verbFallback: 'is composed of',
|
|
664
|
+
gestureHintKey: `${roleKey(UML_ROLE.aggregation)}.gesture`,
|
|
665
|
+
gestureHintFallback: 'Drag from the whole to the part — the diamond lands on the whole.',
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
id: UML_ROLE.composition,
|
|
670
|
+
parent: UML_ROLE.association,
|
|
671
|
+
kind: 'edge',
|
|
672
|
+
labelKey: roleKey(UML_ROLE.composition),
|
|
673
|
+
labelFallback: 'Composition',
|
|
674
|
+
direction: {
|
|
675
|
+
verbKey: `${roleKey(UML_ROLE.composition)}.verb`,
|
|
676
|
+
verbFallback: 'is composed of',
|
|
677
|
+
gestureHintKey: `${roleKey(UML_ROLE.composition)}.gesture`,
|
|
678
|
+
gestureHintFallback: 'Drag from the whole to the part — the diamond lands on the whole.',
|
|
679
|
+
},
|
|
680
|
+
},
|
|
681
|
+
{
|
|
682
|
+
id: UML_ROLE.generalization,
|
|
683
|
+
kind: 'edge',
|
|
684
|
+
labelKey: roleKey(UML_ROLE.generalization),
|
|
685
|
+
labelFallback: 'Generalization',
|
|
686
|
+
direction: {
|
|
687
|
+
verbKey: `${roleKey(UML_ROLE.generalization)}.verb`,
|
|
688
|
+
verbFallback: 'is a',
|
|
689
|
+
gestureHintKey: `${roleKey(UML_ROLE.generalization)}.gesture`,
|
|
690
|
+
gestureHintFallback: 'Drag from the specific classifier to the general one — the hollow ' +
|
|
691
|
+
'triangle lands on the general.',
|
|
692
|
+
},
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
id: UML_ROLE.realization,
|
|
696
|
+
kind: 'edge',
|
|
697
|
+
labelKey: roleKey(UML_ROLE.realization),
|
|
698
|
+
labelFallback: 'Realization',
|
|
699
|
+
direction: {
|
|
700
|
+
verbKey: `${roleKey(UML_ROLE.realization)}.verb`,
|
|
701
|
+
verbFallback: 'realizes',
|
|
702
|
+
gestureHintKey: `${roleKey(UML_ROLE.realization)}.gesture`,
|
|
703
|
+
gestureHintFallback: 'Drag from the class to the interface it implements.',
|
|
704
|
+
},
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
id: UML_ROLE.dependency,
|
|
708
|
+
kind: 'edge',
|
|
709
|
+
labelKey: roleKey(UML_ROLE.dependency),
|
|
710
|
+
labelFallback: 'Dependency',
|
|
711
|
+
direction: {
|
|
712
|
+
verbKey: `${roleKey(UML_ROLE.dependency)}.verb`,
|
|
713
|
+
verbFallback: 'depends on',
|
|
714
|
+
gestureHintKey: `${roleKey(UML_ROLE.dependency)}.gesture`,
|
|
715
|
+
gestureHintFallback: 'Drag from the element that needs the other to the one it needs.',
|
|
716
|
+
},
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
id: UML_ROLE.anchor,
|
|
720
|
+
kind: 'edge',
|
|
721
|
+
labelKey: roleKey(UML_ROLE.anchor),
|
|
722
|
+
labelFallback: 'Anchor',
|
|
723
|
+
},
|
|
724
|
+
{
|
|
725
|
+
id: UML_ROLE.include,
|
|
726
|
+
kind: 'edge',
|
|
727
|
+
labelKey: roleKey(UML_ROLE.include),
|
|
728
|
+
labelFallback: 'Include',
|
|
729
|
+
direction: {
|
|
730
|
+
verbKey: `${roleKey(UML_ROLE.include)}.verb`,
|
|
731
|
+
verbFallback: 'includes',
|
|
732
|
+
gestureHintKey: `${roleKey(UML_ROLE.include)}.gesture`,
|
|
733
|
+
gestureHintFallback: 'Drag from the base use case to the one it always includes.',
|
|
734
|
+
},
|
|
735
|
+
},
|
|
736
|
+
{
|
|
737
|
+
id: UML_ROLE.extend,
|
|
738
|
+
kind: 'edge',
|
|
739
|
+
labelKey: roleKey(UML_ROLE.extend),
|
|
740
|
+
labelFallback: 'Extend',
|
|
741
|
+
direction: {
|
|
742
|
+
verbKey: `${roleKey(UML_ROLE.extend)}.verb`,
|
|
743
|
+
verbFallback: 'extends',
|
|
744
|
+
gestureHintKey: `${roleKey(UML_ROLE.extend)}.gesture`,
|
|
745
|
+
gestureHintFallback: 'Drag from the extending use case to the base one it may extend.',
|
|
746
|
+
},
|
|
747
|
+
},
|
|
748
|
+
// ── The deployment relationships (phase 2) ──────────────────────────────
|
|
749
|
+
// §19.2.4: a Deployment is drawn as a dashed arrow keyworded `«deploy»`, from
|
|
750
|
+
// the artifact TO the node it runs on. The source is the artifact because the
|
|
751
|
+
// artifact is the subject of the sentence: `order.jar is deployed on
|
|
752
|
+
// :AppServer`, never the other way round.
|
|
753
|
+
{
|
|
754
|
+
id: UML_ROLE.deploy,
|
|
755
|
+
kind: 'edge',
|
|
756
|
+
labelKey: roleKey(UML_ROLE.deploy),
|
|
757
|
+
labelFallback: 'Deploy',
|
|
758
|
+
direction: {
|
|
759
|
+
verbKey: `${roleKey(UML_ROLE.deploy)}.verb`,
|
|
760
|
+
verbFallback: 'is deployed on',
|
|
761
|
+
gestureHintKey: `${roleKey(UML_ROLE.deploy)}.gesture`,
|
|
762
|
+
gestureHintFallback: 'Drag from the artifact to the node it runs on — the arrow lands on the node.',
|
|
763
|
+
},
|
|
764
|
+
},
|
|
765
|
+
// §19.3.4: a Manifestation is the other dashed arrow off an artifact, and it
|
|
766
|
+
// says what the file IS a physical embodiment of. Same source for the same
|
|
767
|
+
// reason: `order.jar manifests Ordering`.
|
|
768
|
+
{
|
|
769
|
+
id: UML_ROLE.manifest,
|
|
770
|
+
kind: 'edge',
|
|
771
|
+
labelKey: roleKey(UML_ROLE.manifest),
|
|
772
|
+
labelFallback: 'Manifest',
|
|
773
|
+
direction: {
|
|
774
|
+
verbKey: `${roleKey(UML_ROLE.manifest)}.verb`,
|
|
775
|
+
verbFallback: 'manifests',
|
|
776
|
+
gestureHintKey: `${roleKey(UML_ROLE.manifest)}.gesture`,
|
|
777
|
+
gestureHintFallback: 'Drag from the artifact to the component it is a physical copy of.',
|
|
778
|
+
},
|
|
779
|
+
},
|
|
780
|
+
// §19.4.4: a CommunicationPath is a plain solid line between two nodes saying
|
|
781
|
+
// they can exchange messages. UNDIRECTED, and verbless for the reason
|
|
782
|
+
// `uml:association` is: the notation draws no arrow, so claiming a direction
|
|
783
|
+
// would put words in the diagram's mouth. Flat under nothing — see the header
|
|
784
|
+
// on the one place this file departs from the metamodel.
|
|
785
|
+
{
|
|
786
|
+
id: UML_ROLE['communication-path'],
|
|
787
|
+
kind: 'edge',
|
|
788
|
+
labelKey: roleKey(UML_ROLE['communication-path']),
|
|
789
|
+
labelFallback: 'Communication path',
|
|
790
|
+
},
|
|
791
|
+
// ── The behaviour relationships (phase 2) ───────────────────────────────
|
|
792
|
+
// §15.2.4: the two ActivityEdges. Both are a solid line with an open arrow,
|
|
793
|
+
// and both read "flows to" — what tells them apart is what is AT THE ENDS: a
|
|
794
|
+
// control flow sequences two actions, an object flow carries a value into or
|
|
795
|
+
// out of one. Two roles rather than one with a flag, because "an object flow
|
|
796
|
+
// must touch an object node" is a sentence that has to reach one of them and
|
|
797
|
+
// not the other.
|
|
798
|
+
{
|
|
799
|
+
id: UML_ROLE['control-flow'],
|
|
800
|
+
kind: 'edge',
|
|
801
|
+
labelKey: roleKey(UML_ROLE['control-flow']),
|
|
802
|
+
labelFallback: 'Control flow',
|
|
803
|
+
direction: {
|
|
804
|
+
verbKey: `${roleKey(UML_ROLE['control-flow'])}.verb`,
|
|
805
|
+
verbFallback: 'flows to',
|
|
806
|
+
gestureHintKey: `${roleKey(UML_ROLE['control-flow'])}.gesture`,
|
|
807
|
+
gestureHintFallback: 'Drag from the action that finishes to the one that starts next — the arrow lands on the next.',
|
|
808
|
+
},
|
|
809
|
+
},
|
|
810
|
+
{
|
|
811
|
+
id: UML_ROLE['object-flow'],
|
|
812
|
+
kind: 'edge',
|
|
813
|
+
labelKey: roleKey(UML_ROLE['object-flow']),
|
|
814
|
+
labelFallback: 'Object flow',
|
|
815
|
+
direction: {
|
|
816
|
+
verbKey: `${roleKey(UML_ROLE['object-flow'])}.verb`,
|
|
817
|
+
verbFallback: 'flows to',
|
|
818
|
+
gestureHintKey: `${roleKey(UML_ROLE['object-flow'])}.gesture`,
|
|
819
|
+
gestureHintFallback: 'Drag from where the value comes from to where it is consumed.',
|
|
820
|
+
},
|
|
821
|
+
},
|
|
822
|
+
// §14.2.4.8: a Transition — the arrow between two vertices of a state
|
|
823
|
+
// machine, labelled `trigger [guard] / effect`. FLAT under nothing and not a
|
|
824
|
+
// sibling of the two flows above: an activity edge carries a token between
|
|
825
|
+
// actions, a transition fires a machine from one state into another, and the
|
|
826
|
+
// rules that police the two have different endpoint tables.
|
|
827
|
+
{
|
|
828
|
+
id: UML_ROLE.transition,
|
|
829
|
+
kind: 'edge',
|
|
830
|
+
labelKey: roleKey(UML_ROLE.transition),
|
|
831
|
+
labelFallback: 'Transition',
|
|
832
|
+
direction: {
|
|
833
|
+
verbKey: `${roleKey(UML_ROLE.transition)}.verb`,
|
|
834
|
+
verbFallback: 'transitions to',
|
|
835
|
+
gestureHintKey: `${roleKey(UML_ROLE.transition)}.gesture`,
|
|
836
|
+
gestureHintFallback: 'Drag from the state the machine leaves to the state it enters.',
|
|
837
|
+
},
|
|
838
|
+
},
|
|
839
|
+
// ── The interaction relationships (phase 3) ─────────────────────────────
|
|
840
|
+
// §17.4.4: a Message. The PARENT is verbless, exactly as `uml:association`
|
|
841
|
+
// is, and for a sharper version of the same reason — the five children below
|
|
842
|
+
// say five different things ("calls", "sends", "replies to", "creates",
|
|
843
|
+
// "destroys") and a default verb on the parent would be a sixth, claimed by
|
|
844
|
+
// whichever of them a rule happened to reach through it.
|
|
845
|
+
//
|
|
846
|
+
// The SOURCE is the sender on all five, without exception. That is the one
|
|
847
|
+
// thing a reader of a sequence diagram may never have to guess: the arrow
|
|
848
|
+
// points at the receiver, the line's height is when it happens, and a
|
|
849
|
+
// message drawn the wrong way round is the opposite exchange.
|
|
850
|
+
{
|
|
851
|
+
id: UML_ROLE.message,
|
|
852
|
+
kind: 'edge',
|
|
853
|
+
labelKey: roleKey(UML_ROLE.message),
|
|
854
|
+
labelFallback: 'Message',
|
|
855
|
+
},
|
|
856
|
+
{
|
|
857
|
+
id: UML_ROLE['message-sync'],
|
|
858
|
+
parent: UML_ROLE.message,
|
|
859
|
+
kind: 'edge',
|
|
860
|
+
labelKey: roleKey(UML_ROLE['message-sync']),
|
|
861
|
+
labelFallback: 'Synchronous message',
|
|
862
|
+
direction: {
|
|
863
|
+
verbKey: `${roleKey(UML_ROLE['message-sync'])}.verb`,
|
|
864
|
+
verbFallback: 'calls',
|
|
865
|
+
gestureHintKey: `${roleKey(UML_ROLE['message-sync'])}.gesture`,
|
|
866
|
+
gestureHintFallback: 'Drag from the sender to the receiver — the filled arrowhead lands on the receiver.',
|
|
867
|
+
},
|
|
868
|
+
},
|
|
869
|
+
{
|
|
870
|
+
id: UML_ROLE['message-async'],
|
|
871
|
+
parent: UML_ROLE.message,
|
|
872
|
+
kind: 'edge',
|
|
873
|
+
labelKey: roleKey(UML_ROLE['message-async']),
|
|
874
|
+
labelFallback: 'Asynchronous message',
|
|
875
|
+
direction: {
|
|
876
|
+
verbKey: `${roleKey(UML_ROLE['message-async'])}.verb`,
|
|
877
|
+
verbFallback: 'sends',
|
|
878
|
+
gestureHintKey: `${roleKey(UML_ROLE['message-async'])}.gesture`,
|
|
879
|
+
gestureHintFallback: 'Drag from the sender to the receiver — the open arrowhead says the sender does not wait.',
|
|
880
|
+
},
|
|
881
|
+
},
|
|
882
|
+
// The dashed line back. Its source is still the SENDER — the participant the
|
|
883
|
+
// reply comes FROM, which is the one that was called — so an author draws
|
|
884
|
+
// every message the same way round and the notation sorts itself out.
|
|
885
|
+
{
|
|
886
|
+
id: UML_ROLE['message-reply'],
|
|
887
|
+
parent: UML_ROLE.message,
|
|
888
|
+
kind: 'edge',
|
|
889
|
+
labelKey: roleKey(UML_ROLE['message-reply']),
|
|
890
|
+
labelFallback: 'Reply message',
|
|
891
|
+
direction: {
|
|
892
|
+
verbKey: `${roleKey(UML_ROLE['message-reply'])}.verb`,
|
|
893
|
+
verbFallback: 'replies to',
|
|
894
|
+
gestureHintKey: `${roleKey(UML_ROLE['message-reply'])}.gesture`,
|
|
895
|
+
gestureHintFallback: 'Drag from the participant that was called back to the one that called it.',
|
|
896
|
+
},
|
|
897
|
+
},
|
|
898
|
+
// §17.4.4's createMessage: the dashed arrow that lands on a lifeline's HEAD,
|
|
899
|
+
// drawn at the height the participant comes into existence.
|
|
900
|
+
{
|
|
901
|
+
id: UML_ROLE['message-create'],
|
|
902
|
+
parent: UML_ROLE.message,
|
|
903
|
+
kind: 'edge',
|
|
904
|
+
labelKey: roleKey(UML_ROLE['message-create']),
|
|
905
|
+
labelFallback: 'Create message',
|
|
906
|
+
direction: {
|
|
907
|
+
verbKey: `${roleKey(UML_ROLE['message-create'])}.verb`,
|
|
908
|
+
verbFallback: 'creates',
|
|
909
|
+
gestureHintKey: `${roleKey(UML_ROLE['message-create'])}.gesture`,
|
|
910
|
+
gestureHintFallback: 'Drag from the sender to the head of the lifeline it brings into existence.',
|
|
911
|
+
},
|
|
912
|
+
},
|
|
913
|
+
// …and its opposite: the message whose arrival ends a life, drawn to the X.
|
|
914
|
+
{
|
|
915
|
+
id: UML_ROLE['message-delete'],
|
|
916
|
+
parent: UML_ROLE.message,
|
|
917
|
+
kind: 'edge',
|
|
918
|
+
labelKey: roleKey(UML_ROLE['message-delete']),
|
|
919
|
+
labelFallback: 'Delete message',
|
|
920
|
+
direction: {
|
|
921
|
+
verbKey: `${roleKey(UML_ROLE['message-delete'])}.verb`,
|
|
922
|
+
verbFallback: 'destroys',
|
|
923
|
+
gestureHintKey: `${roleKey(UML_ROLE['message-delete'])}.gesture`,
|
|
924
|
+
gestureHintFallback: 'Drag from the sender to the destruction mark that ends the receiver.',
|
|
925
|
+
},
|
|
926
|
+
},
|
|
927
|
+
];
|
|
928
|
+
const DEFS = [
|
|
929
|
+
...ELEMENT_DEFS,
|
|
930
|
+
...TIER_DEFS,
|
|
931
|
+
...FRAME_DEFS,
|
|
932
|
+
...RELATIONSHIP_DEFS,
|
|
933
|
+
];
|
|
934
|
+
// Null prototype: this is a lookup table keyed by ids that may one day come
|
|
935
|
+
// from host-supplied packs, so `defs['toString']` must not resolve.
|
|
936
|
+
export const UML_ROLES = Object.assign(Object.create(null), Object.fromEntries(DEFS.map(def => [def.id, def])));
|
|
937
|
+
/**
|
|
938
|
+
* The `kind` discriminant → the role it means.
|
|
939
|
+
*
|
|
940
|
+
* `kind` drives the renderer and is what the palette writes; the ROLE is the
|
|
941
|
+
* semantic authority. The two are posted side by side at every creation site,
|
|
942
|
+
* the way C4, BPMN and Wardley already do it, and this table is the single place
|
|
943
|
+
* that says which kind means which role. Total over {@link UmlNodeKind} by its
|
|
944
|
+
* type, so a new kind cannot land without being given a meaning.
|
|
945
|
+
*
|
|
946
|
+
* One kind, one role, with none collapsed — unlike C4, where four kinds are a
|
|
947
|
+
* second DRAWING of a level. Here the thirty-eight kinds are thirty-eight
|
|
948
|
+
* different artefacts of the specification, and the three roles with no kind of
|
|
949
|
+
* their own — `uml:classifier`, `uml:control-node`, `uml:pseudostate` — are
|
|
950
|
+
* ancestors rather than any of them.
|
|
951
|
+
*/
|
|
952
|
+
export const UML_ROLE_OF_KIND = {
|
|
953
|
+
class: UML_ROLE.class,
|
|
954
|
+
interface: UML_ROLE.interface,
|
|
955
|
+
enumeration: UML_ROLE.enumeration,
|
|
956
|
+
object: UML_ROLE.object,
|
|
957
|
+
package: UML_ROLE.package,
|
|
958
|
+
note: UML_ROLE.note,
|
|
959
|
+
actor: UML_ROLE.actor,
|
|
960
|
+
'use-case': UML_ROLE['use-case'],
|
|
961
|
+
component: UML_ROLE.component,
|
|
962
|
+
port: UML_ROLE.port,
|
|
963
|
+
'provided-interface': UML_ROLE['provided-interface'],
|
|
964
|
+
'required-interface': UML_ROLE['required-interface'],
|
|
965
|
+
artifact: UML_ROLE.artifact,
|
|
966
|
+
// The one role that is BOTH a parent and a drawing: §19.4 makes Node
|
|
967
|
+
// instantiable and derives Device and ExecutionEnvironment from it.
|
|
968
|
+
node: UML_ROLE.node,
|
|
969
|
+
device: UML_ROLE.device,
|
|
970
|
+
'execution-environment': UML_ROLE['execution-environment'],
|
|
971
|
+
// ── The activity artefacts (phase 2) ────────────────────────────────────
|
|
972
|
+
action: UML_ROLE.action,
|
|
973
|
+
// Shared by `act` and `stm`: the same disc, the same meaning. See the def.
|
|
974
|
+
initial: UML_ROLE.initial,
|
|
975
|
+
'activity-final': UML_ROLE['activity-final'],
|
|
976
|
+
'flow-final': UML_ROLE['flow-final'],
|
|
977
|
+
decision: UML_ROLE.decision,
|
|
978
|
+
fork: UML_ROLE.fork,
|
|
979
|
+
'object-node': UML_ROLE['object-node'],
|
|
980
|
+
'send-signal': UML_ROLE['send-signal'],
|
|
981
|
+
'accept-event': UML_ROLE['accept-event'],
|
|
982
|
+
'time-event': UML_ROLE['time-event'],
|
|
983
|
+
// ── The state machine artefacts (phase 2) ───────────────────────────────
|
|
984
|
+
state: UML_ROLE.state,
|
|
985
|
+
'final-state': UML_ROLE['final-state'],
|
|
986
|
+
choice: UML_ROLE.choice,
|
|
987
|
+
junction: UML_ROLE.junction,
|
|
988
|
+
'shallow-history': UML_ROLE['shallow-history'],
|
|
989
|
+
'deep-history': UML_ROLE['deep-history'],
|
|
990
|
+
'entry-point': UML_ROLE['entry-point'],
|
|
991
|
+
'exit-point': UML_ROLE['exit-point'],
|
|
992
|
+
terminate: UML_ROLE.terminate,
|
|
993
|
+
// ── The interaction artefacts (phase 3) ─────────────────────────────────
|
|
994
|
+
lifeline: UML_ROLE.lifeline,
|
|
995
|
+
execution: UML_ROLE.execution,
|
|
996
|
+
destruction: UML_ROLE.destruction,
|
|
997
|
+
};
|