@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/model.d.ts
ADDED
|
@@ -0,0 +1,862 @@
|
|
|
1
|
+
import { type UmlDiagramKind, type UmlFragmentOperand, type UmlFragmentOperator, type UmlNodeKind } from '@formicoidea/labre-core/model';
|
|
2
|
+
import { type UmlBox, type UmlComponent, type UmlComponentElement, type UmlComponentGroup } from './component.js';
|
|
3
|
+
import { type UmlAssociationEnd, type UmlOperation, type UmlProperty } from './grammar.js';
|
|
4
|
+
/**
|
|
5
|
+
* The neutral intermediate representation one UML diagram exports through.
|
|
6
|
+
*
|
|
7
|
+
* ## Why there is an IR at all
|
|
8
|
+
*
|
|
9
|
+
* Two writers — PlantUML and XMI — and one canvas. Without a model in between,
|
|
10
|
+
* each writer would have to know that a class's name lives in a grouped text
|
|
11
|
+
* element with the role `uml:name`, that its attributes are a second one, that a
|
|
12
|
+
* connector's ends may land on the group rather than on the shape, and that a
|
|
13
|
+
* package contains what its box contains. Two copies of that reading is two
|
|
14
|
+
* copies that drift, and the drift shows up as two files that disagree about the
|
|
15
|
+
* same drawing.
|
|
16
|
+
*
|
|
17
|
+
* So the canvas is read ONCE, here, and the writers take records. It is also
|
|
18
|
+
* what makes them testable with literals: a golden XMI test needs a model, not a
|
|
19
|
+
* surface.
|
|
20
|
+
*
|
|
21
|
+
* ## Pure
|
|
22
|
+
*
|
|
23
|
+
* Elements in, records out. No `std`, no DOM, no clock, no randomness — the
|
|
24
|
+
* discipline `docs/adr/0012` P3 sets for every interchange function, and the
|
|
25
|
+
* reason {@link umlModelFrom} takes plain structural records
|
|
26
|
+
* ({@link UmlSourceElement}) rather than element models: the same function runs
|
|
27
|
+
* against a live surface and against six object literals in a spec.
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* The shape of an element as this module reads it.
|
|
31
|
+
*
|
|
32
|
+
* Structural, and deliberately so: every field is one a real
|
|
33
|
+
* `GfxPrimitiveElementModel` carries, and every field is optional, so a test can
|
|
34
|
+
* hand over `{ id, type, kind, xywh }` and get the same answer a surface does.
|
|
35
|
+
* `text` and `name` are `unknown` because on a live element they are a `Y.Text`
|
|
36
|
+
* and in a spec they are a string, and nothing here has any business knowing
|
|
37
|
+
* which — both go through `umlTierText`, which stringifies whatever it is given.
|
|
38
|
+
* That is also what keeps this file free of a Yjs import.
|
|
39
|
+
*/
|
|
40
|
+
export interface UmlSourceElement extends UmlComponentElement {
|
|
41
|
+
/** `'umlDiagram'`, `'umlNode'`, `'umlSubject'`, `'connector'`, `'text'`, … */
|
|
42
|
+
type?: string;
|
|
43
|
+
/** `UmlNodeKind` on a node, `UmlDiagramKind` on a frame. */
|
|
44
|
+
kind?: string;
|
|
45
|
+
name?: unknown;
|
|
46
|
+
heading?: unknown;
|
|
47
|
+
/** Which way a `umlPartition`'s band runs (§15.6.4). */
|
|
48
|
+
orientation?: string;
|
|
49
|
+
xywh?: string;
|
|
50
|
+
deserializedXYWH?: readonly number[];
|
|
51
|
+
elementBound?: {
|
|
52
|
+
x: number;
|
|
53
|
+
y: number;
|
|
54
|
+
w: number;
|
|
55
|
+
h: number;
|
|
56
|
+
};
|
|
57
|
+
/** A group's members. */
|
|
58
|
+
childIds?: readonly string[];
|
|
59
|
+
/**
|
|
60
|
+
* A connector's ends.
|
|
61
|
+
*
|
|
62
|
+
* `position` is the RELATIVE point the end is anchored at on the element it
|
|
63
|
+
* touches — `[0.5, 0.5]` for a centre anchor, `[0, 0.35]` for a message
|
|
64
|
+
* attached a third of the way down a lifeline's left edge. Read for one thing
|
|
65
|
+
* only, and it is the thing a sequence diagram is made of: §17.4.4 says the
|
|
66
|
+
* HEIGHT an arrow is drawn at is WHEN it happens, and that height is stored
|
|
67
|
+
* here rather than derived — a connector's own bound is computed by the router
|
|
68
|
+
* and reads `[0,0,0,0]` on a freshly loaded document.
|
|
69
|
+
*/
|
|
70
|
+
source?: {
|
|
71
|
+
id?: string;
|
|
72
|
+
position?: readonly number[];
|
|
73
|
+
} | null;
|
|
74
|
+
target?: {
|
|
75
|
+
id?: string;
|
|
76
|
+
position?: readonly number[];
|
|
77
|
+
} | null;
|
|
78
|
+
/** A `umlFragment`'s interaction operator (§17.6.4). */
|
|
79
|
+
operator?: string;
|
|
80
|
+
/** A `umlFragment`'s operand bands, top to bottom (§17.6.4). */
|
|
81
|
+
operands?: readonly UmlFragmentOperand[];
|
|
82
|
+
/**
|
|
83
|
+
* The two PER-END labels of a connector (ADR 0020), beside `text`.
|
|
84
|
+
*
|
|
85
|
+
* `unknown` for the reason {@link UmlSourceElement.name} is: a live connector
|
|
86
|
+
* holds a `Y.Text` and a spec hands over a string, and both go through
|
|
87
|
+
* `umlTierText`.
|
|
88
|
+
*/
|
|
89
|
+
sourceLabel?: unknown;
|
|
90
|
+
targetLabel?: unknown;
|
|
91
|
+
}
|
|
92
|
+
/** A slot of an InstanceSpecification — `attribute = value` (§11.6.4). */
|
|
93
|
+
export interface UmlSlot {
|
|
94
|
+
name: string;
|
|
95
|
+
/** Absent when the author named a feature and gave it no value. */
|
|
96
|
+
value?: string;
|
|
97
|
+
}
|
|
98
|
+
/** What every drawn artefact states, whatever kind it is. */
|
|
99
|
+
export interface UmlNodeBase {
|
|
100
|
+
/** The surface element's id — what a relation's ends resolve to. */
|
|
101
|
+
id: string;
|
|
102
|
+
name: string;
|
|
103
|
+
/** Annex C labels read off the name compartment, in order. */
|
|
104
|
+
keywords: string[];
|
|
105
|
+
/** `{abstract}` was written on it (§9.2.4). */
|
|
106
|
+
isAbstract: boolean;
|
|
107
|
+
/** Where it is drawn — what package and subject nesting is decided by. */
|
|
108
|
+
bounds?: UmlBox;
|
|
109
|
+
}
|
|
110
|
+
/** A Class, an Interface, an Enumeration or an InstanceSpecification. */
|
|
111
|
+
export interface UmlClassifier extends UmlNodeBase {
|
|
112
|
+
kind: Extract<UmlNodeKind, 'class' | 'interface' | 'enumeration' | 'object'>;
|
|
113
|
+
/** The attribute compartment, parsed. Empty for an object. */
|
|
114
|
+
attributes: UmlProperty[];
|
|
115
|
+
/** The operation compartment, parsed. Empty for an object. */
|
|
116
|
+
operations: UmlOperation[];
|
|
117
|
+
/** The value compartment of an object. Empty for the other three. */
|
|
118
|
+
slots: UmlSlot[];
|
|
119
|
+
/**
|
|
120
|
+
* The compartments as the author TYPED them — trimmed, blanks and elision
|
|
121
|
+
* markers dropped, and otherwise untouched.
|
|
122
|
+
*
|
|
123
|
+
* Carried beside the parsed forms because one of the two writers wants each.
|
|
124
|
+
* XMI needs the structure: it has a slot for a visibility, a type and a
|
|
125
|
+
* multiplicity and nothing to do with a line. PlantUML's member syntax IS
|
|
126
|
+
* §9.5.4's own notation, so re-spelling a parsed property for it could only
|
|
127
|
+
* lose what the parser did not model — a constraint, an unusual modifier, a
|
|
128
|
+
* qualified redefinition. Both readings of the same compartment, stated once
|
|
129
|
+
* here rather than re-derived in two files.
|
|
130
|
+
*/
|
|
131
|
+
lines: {
|
|
132
|
+
attributes: string[];
|
|
133
|
+
operations: string[];
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* The Classifier an object is an instance OF — the `Class` of
|
|
137
|
+
* `object : Class` (§11.6.4). Objects only, and absent when the author wrote
|
|
138
|
+
* a bare instance name.
|
|
139
|
+
*/
|
|
140
|
+
instanceOf?: string;
|
|
141
|
+
}
|
|
142
|
+
/** A Package (§12.2), an Actor or a UseCase (§18.1) — a named box. */
|
|
143
|
+
export type UmlPackageNode = UmlNodeBase;
|
|
144
|
+
export type UmlActorNode = UmlNodeBase;
|
|
145
|
+
export type UmlUseCaseNode = UmlNodeBase;
|
|
146
|
+
/**
|
|
147
|
+
* A Port (§11.3) — the small square on an EncapsulatedClassifier's boundary.
|
|
148
|
+
*
|
|
149
|
+
* `ownerId` is the surface id of the component (or the node) the square is drawn
|
|
150
|
+
* ON, and it is GEOMETRY rather than a stored link: §11.3.4 says the symbol "may
|
|
151
|
+
* be placed either overlapping the boundary of the rectangle symbol denoting
|
|
152
|
+
* that EncapsulatedClassifier or it may be shown inside the rectangle symbol",
|
|
153
|
+
* and a canvas has no other statement to read. See {@link umlHostOf} for the
|
|
154
|
+
* reading and for its tolerance.
|
|
155
|
+
*
|
|
156
|
+
* Absent when the author has drawn a port beside every box, which is a port
|
|
157
|
+
* belonging to nothing — the file writes it nowhere rather than guessing an
|
|
158
|
+
* owner, and the drawing keeps it.
|
|
159
|
+
*/
|
|
160
|
+
export interface UmlPort extends UmlNodeBase {
|
|
161
|
+
ownerId?: string;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* A Component (§11.6) — the classifier rectangle with the two-tab icon.
|
|
165
|
+
*
|
|
166
|
+
* `provided` and `required` are the NAMES read off the lollipops and sockets
|
|
167
|
+
* drawn against it, not references: §10.4.4 draws a provided Interface as a
|
|
168
|
+
* circle "labeled with the name of the Interface, attached by a solid line to
|
|
169
|
+
* the BehavioredClassifier that realizes this Interface", and on this canvas the
|
|
170
|
+
* glyph carries its own `uml:label` and nothing else. The names are what both
|
|
171
|
+
* writers need — XMI mints a `uml:Interface` per name, PlantUML declares one —
|
|
172
|
+
* and what neither can get from an id, because the glyph IS the interface as far
|
|
173
|
+
* as the drawing is concerned.
|
|
174
|
+
*
|
|
175
|
+
* `ports` are the squares on its border, resolved the same geometric way.
|
|
176
|
+
*/
|
|
177
|
+
export interface UmlComponentNode extends UmlNodeBase {
|
|
178
|
+
ports: UmlPort[];
|
|
179
|
+
/** Interface names read off the lollipops touching this component. */
|
|
180
|
+
provided: string[];
|
|
181
|
+
/** Interface names read off the sockets touching this component. */
|
|
182
|
+
required: string[];
|
|
183
|
+
}
|
|
184
|
+
/** An Artifact (§19.3) — the `«artifact»` rectangle with the document icon. */
|
|
185
|
+
export type UmlArtifactNode = UmlNodeBase;
|
|
186
|
+
/**
|
|
187
|
+
* A Node, a Device or an ExecutionEnvironment (§19.4) — the perspective cube.
|
|
188
|
+
*
|
|
189
|
+
* ONE record with a `kind` discriminant rather than three lists, because §19.4.2
|
|
190
|
+
* makes Device and ExecutionEnvironment specializations of Node and §19.4.4
|
|
191
|
+
* draws all three as the same cube: the keyword is the difference, and both
|
|
192
|
+
* writers need exactly that — an `xmi:type` and a PlantUML stereotype.
|
|
193
|
+
*/
|
|
194
|
+
export interface UmlDeploymentNode extends UmlNodeBase {
|
|
195
|
+
kind: Extract<UmlNodeKind, 'node' | 'device' | 'execution-environment'>;
|
|
196
|
+
}
|
|
197
|
+
/** The subject of a use case diagram — the rectangle the cases sit in. */
|
|
198
|
+
export type UmlSubjectBox = UmlNodeBase;
|
|
199
|
+
/** A Comment (Annex A) — prose, kept whole. */
|
|
200
|
+
export interface UmlNote extends UmlNodeBase {
|
|
201
|
+
/** The note's text, verbatim: a note is prose, not a name compartment. */
|
|
202
|
+
body: string;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* The relationships phase 1 draws — the local half of each `uml:…` edge role.
|
|
206
|
+
*
|
|
207
|
+
* A closed union rather than an open string, because every writer maps it
|
|
208
|
+
* TOTALLY: a `Record<UmlRelationKind, …>` in `plantuml.ts` and an exhaustive
|
|
209
|
+
* `switch` in `xmi.ts` both fail the build the day a tenth relationship is drawn
|
|
210
|
+
* with nothing to write it as. That failure is cheap here and expensive in a
|
|
211
|
+
* file somebody exported.
|
|
212
|
+
*/
|
|
213
|
+
export type UmlRelationKind = 'association' | 'aggregation' | 'composition' | 'generalization' | 'realization' | 'dependency' | 'anchor' | 'include' | 'extend' | 'deploy' | 'manifest' | 'communication-path' | 'control-flow' | 'object-flow' | 'transition' | 'message-sync' | 'message-async' | 'message-reply' | 'message-create' | 'message-delete';
|
|
214
|
+
/** One connector, once both of its ends are known artefacts of this diagram. */
|
|
215
|
+
export interface UmlRelation {
|
|
216
|
+
kind: UmlRelationKind;
|
|
217
|
+
/**
|
|
218
|
+
* The SUBJECT of the sentence the edge's direction states (the role table in
|
|
219
|
+
* `roles.ts`): the specific classifier of a generalization, the WHOLE of an
|
|
220
|
+
* aggregation, the base UseCase of an include, the extending UseCase of an
|
|
221
|
+
* extend.
|
|
222
|
+
*/
|
|
223
|
+
sourceId: string;
|
|
224
|
+
targetId: string;
|
|
225
|
+
/** The connector's own centre text, when it carries one. */
|
|
226
|
+
label?: string;
|
|
227
|
+
/**
|
|
228
|
+
* What is written beside the SOURCE end of the line — §11.5.4's adornments.
|
|
229
|
+
*
|
|
230
|
+
* Present whenever the connector carries an end label at all, whatever the
|
|
231
|
+
* relationship is. On the four kinds §11.5.4 governs
|
|
232
|
+
* ({@link ADORNED_RELATION_KINDS}) it is PARSED — a multiplicity, a role name,
|
|
233
|
+
* a visibility glyph; on every other kind only
|
|
234
|
+
* {@link UmlAssociationEnd.raw} is filled, because a multiplicity beside a
|
|
235
|
+
* generalization is not a multiplicity of anything and writing one into a file
|
|
236
|
+
* would state a fact the metamodel has nowhere to hold. Carrying the raw text
|
|
237
|
+
* regardless is what keeps the round trip lossless: the author's words come
|
|
238
|
+
* back on the board even where no writer can spell them.
|
|
239
|
+
*/
|
|
240
|
+
sourceEnd?: UmlAssociationEnd;
|
|
241
|
+
/** What is written beside the TARGET end — see {@link sourceEnd}. */
|
|
242
|
+
targetEnd?: UmlAssociationEnd;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* The relationships whose end labels §11.5.4 gives a MEANING to.
|
|
246
|
+
*
|
|
247
|
+
* An Association and its two aggregation flavours, plus the CommunicationPath
|
|
248
|
+
* §19.4.3 defines as "an Association between two DeploymentTargets" — which is
|
|
249
|
+
* why it is in the set: it is an Association, so its ends are Properties and
|
|
250
|
+
* take a multiplicity like any other.
|
|
251
|
+
*/
|
|
252
|
+
export declare const ADORNED_RELATION_KINDS: ReadonlySet<UmlRelationKind>;
|
|
253
|
+
/** The ten glyphs an `act` sheet draws — §15.3.4, §15.4.4, §16.3.4, §16.10.4. */
|
|
254
|
+
export type UmlActivityNodeKind = Extract<UmlNodeKind, 'action' | 'initial' | 'activity-final' | 'flow-final' | 'decision' | 'fork' | 'object-node' | 'send-signal' | 'accept-event' | 'time-event'>;
|
|
255
|
+
/**
|
|
256
|
+
* One node of an Activity — the glyph, its words, and the lane it is drawn in.
|
|
257
|
+
*
|
|
258
|
+
* ONE record with a `kind` discriminant rather than ten lists, for the reason
|
|
259
|
+
* {@link UmlDeploymentNode} gives: §15.7 makes all ten ActivityNodes and both
|
|
260
|
+
* writers need exactly the discriminant — an `xmi:type` and a PlantUML
|
|
261
|
+
* stereotype. A list per glyph would be ten fields the writers would have to
|
|
262
|
+
* concatenate back into one traversal order.
|
|
263
|
+
*/
|
|
264
|
+
export interface UmlActivityNode extends UmlNodeBase {
|
|
265
|
+
kind: UmlActivityNodeKind;
|
|
266
|
+
/**
|
|
267
|
+
* The surface id of the `umlPartition` whose box holds this node's centre —
|
|
268
|
+
* §15.6.4's swimlane, read at EXPORT time from geometry and never stored.
|
|
269
|
+
*
|
|
270
|
+
* The same reading {@link UmlPort.ownerId} gets, and for the same reason: a
|
|
271
|
+
* partition is a band drawn across the sheet, membership is which band a glyph
|
|
272
|
+
* sits in, and a canvas holds no second statement about it. Absent for a node
|
|
273
|
+
* drawn between the lanes, or on a sheet with no lanes at all — which is most
|
|
274
|
+
* of them.
|
|
275
|
+
*/
|
|
276
|
+
partitionId?: string;
|
|
277
|
+
}
|
|
278
|
+
/** One ActivityEdge — the arrow, and the three things §15.2.4 writes on it. */
|
|
279
|
+
export interface UmlActivityEdge {
|
|
280
|
+
/** §15.7.9 / §15.7.11 — which of the two kinds of token travels. */
|
|
281
|
+
kind: Extract<UmlRelationKind, 'control-flow' | 'object-flow'>;
|
|
282
|
+
sourceId: string;
|
|
283
|
+
targetId: string;
|
|
284
|
+
/** The edge's own name, "notated near the arrow". */
|
|
285
|
+
name?: string;
|
|
286
|
+
/** The `[…]` guard, without its brackets — §15.2.4's own notation. */
|
|
287
|
+
guard?: string;
|
|
288
|
+
/** `{weight = …}`'s value, as written — see {@link UmlActivityEdgeLabel}. */
|
|
289
|
+
weight?: string;
|
|
290
|
+
}
|
|
291
|
+
/** An ActivityPartition (§15.6) — the swimlane, and what is drawn in it. */
|
|
292
|
+
export interface UmlPartition extends UmlNodeBase {
|
|
293
|
+
/** Which way the band runs. A column unless the author turned it. */
|
|
294
|
+
orientation: 'vertical' | 'horizontal';
|
|
295
|
+
/**
|
|
296
|
+
* The activity nodes whose centres it holds, in document order.
|
|
297
|
+
*
|
|
298
|
+
* Listed on the partition AS WELL AS named by each node's
|
|
299
|
+
* {@link UmlActivityNode.partitionId}, and the duplication is the one
|
|
300
|
+
* {@link UmlModel.ports} already explains: the XMI writer walks the lane (an
|
|
301
|
+
* `ActivityPartition` carries `node` idrefs, so it needs the list) while a
|
|
302
|
+
* reader asking which lane one action is in must not have to scan every lane
|
|
303
|
+
* to find out. Both readings are built from one pass, so they cannot disagree.
|
|
304
|
+
*/
|
|
305
|
+
nodeIds: string[];
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* One Activity — the whole of what an `act` sheet says.
|
|
309
|
+
*
|
|
310
|
+
* A frame is ONE Activity: §15.2.4 draws the border and the name in the upper
|
|
311
|
+
* left corner, Annex A replaces that border with the diagram frame, and that is
|
|
312
|
+
* exactly the frame this model was read off. So the id and the name are the
|
|
313
|
+
* sheet's own, and a second activity on one canvas is a second frame — the same
|
|
314
|
+
* reading ADR 0017 makes about every other UML sheet.
|
|
315
|
+
*/
|
|
316
|
+
export interface UmlActivity {
|
|
317
|
+
/** The diagram frame's surface id — the Activity IS the sheet. */
|
|
318
|
+
id: string;
|
|
319
|
+
name: string;
|
|
320
|
+
nodes: UmlActivityNode[];
|
|
321
|
+
edges: UmlActivityEdge[];
|
|
322
|
+
partitions: UmlPartition[];
|
|
323
|
+
}
|
|
324
|
+
/** The nine glyphs §14.2.4 routes transitions through. */
|
|
325
|
+
export type UmlPseudostateKind = Extract<UmlNodeKind, 'initial' | 'choice' | 'junction' | 'shallow-history' | 'deep-history' | 'entry-point' | 'exit-point' | 'terminate' | 'fork'>;
|
|
326
|
+
/** A Region (§14.2.4) — the composite state, drawn as a box round its parts. */
|
|
327
|
+
export interface UmlRegion extends UmlNodeBase {
|
|
328
|
+
/**
|
|
329
|
+
* The region this one is drawn inside — §14.2.4's nested composite state.
|
|
330
|
+
*
|
|
331
|
+
* Geometry, most-nested first, exactly as a package inside a package is read
|
|
332
|
+
* (`xmi.ts`'s `containerOf`). Absent for a region at the top level of the
|
|
333
|
+
* sheet, which is where most of them are.
|
|
334
|
+
*/
|
|
335
|
+
parentId?: string;
|
|
336
|
+
}
|
|
337
|
+
/** A State (§14.2.4.4) — the rounded box and its internal activities. */
|
|
338
|
+
export interface UmlState extends UmlNodeBase {
|
|
339
|
+
/** `entry / …` lines, in order, as the expressions alone. */
|
|
340
|
+
entry: string[];
|
|
341
|
+
/** `do / …` lines — the metamodel's `doActivity`. */
|
|
342
|
+
doActivity: string[];
|
|
343
|
+
/** `exit / …` lines. */
|
|
344
|
+
exit: string[];
|
|
345
|
+
/**
|
|
346
|
+
* Every line of the compartment that is NONE of the three — an internal
|
|
347
|
+
* transition (§14.2.4.4's second compartment), a constraint, a note to self.
|
|
348
|
+
*
|
|
349
|
+
* Carried rather than dropped for the reason {@link UmlClassifier.lines}
|
|
350
|
+
* exists: the author typed it, so something has to be able to write it back,
|
|
351
|
+
* and a writer that silently lost a compartment would be the worst kind of
|
|
352
|
+
* lossy export. Neither writer has a metamodel slot for it today; PlantUML
|
|
353
|
+
* prints it as a state line.
|
|
354
|
+
*/
|
|
355
|
+
lines: string[];
|
|
356
|
+
/** The composite state whose box holds its centre — {@link UmlRegion}. */
|
|
357
|
+
regionId?: string;
|
|
358
|
+
}
|
|
359
|
+
/** A FinalState (§14.2.4.5) — the bullseye a machine stops at. */
|
|
360
|
+
export interface UmlFinalState extends UmlNodeBase {
|
|
361
|
+
regionId?: string;
|
|
362
|
+
}
|
|
363
|
+
/** A Pseudostate (§14.2.4.6) — a vertex that routes rather than one that is. */
|
|
364
|
+
export interface UmlPseudostate extends UmlNodeBase {
|
|
365
|
+
kind: UmlPseudostateKind;
|
|
366
|
+
regionId?: string;
|
|
367
|
+
}
|
|
368
|
+
/** One Transition (§14.2.4.8) — its two ends and its label, parsed. */
|
|
369
|
+
export interface UmlTransition {
|
|
370
|
+
sourceId: string;
|
|
371
|
+
targetId: string;
|
|
372
|
+
/** `<trigger> [',' <trigger>]*`, verbatim and in order. */
|
|
373
|
+
triggers: string[];
|
|
374
|
+
/** The `[…]` guard, without its brackets. */
|
|
375
|
+
guard?: string;
|
|
376
|
+
/** The `/ <behavior-expression>` effect, as written. */
|
|
377
|
+
effect?: string;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* One StateMachine — the whole of what an `stm` sheet says.
|
|
381
|
+
*
|
|
382
|
+
* {@link UmlActivity}'s twin, and it carries its vertices in FOUR lists rather
|
|
383
|
+
* than one discriminated list because the metamodel does: a State owns
|
|
384
|
+
* behaviours and regions, a FinalState owns neither and forbids both
|
|
385
|
+
* (§14.5.11.4), and a Pseudostate is a `kind` attribute on one metaclass. Three
|
|
386
|
+
* different `xmi:type`s with three different shapes is three lists; ten
|
|
387
|
+
* identically shaped ActivityNodes is one.
|
|
388
|
+
*/
|
|
389
|
+
export interface UmlStateMachine {
|
|
390
|
+
/** The diagram frame's surface id — the StateMachine IS the sheet. */
|
|
391
|
+
id: string;
|
|
392
|
+
name: string;
|
|
393
|
+
/** The composite states, outermost and nested alike. */
|
|
394
|
+
regions: UmlRegion[];
|
|
395
|
+
states: UmlState[];
|
|
396
|
+
finalStates: UmlFinalState[];
|
|
397
|
+
pseudostates: UmlPseudostate[];
|
|
398
|
+
transitions: UmlTransition[];
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* §17.4.3's `messageSort`, as the five arrows an `sd` sheet is drawn with.
|
|
402
|
+
*
|
|
403
|
+
* A projection of {@link UmlRelationKind} rather than a union of its own, for
|
|
404
|
+
* the reason {@link UmlActivityEdge.kind} is one: a message IS a connector on
|
|
405
|
+
* the canvas, read off the same role table in the same pass, and two spellings
|
|
406
|
+
* of the same five words would be two things to keep in step.
|
|
407
|
+
*/
|
|
408
|
+
export type UmlMessageKind = Extract<UmlRelationKind, 'message-sync' | 'message-async' | 'message-reply' | 'message-create' | 'message-delete'>;
|
|
409
|
+
/**
|
|
410
|
+
* A Lifeline (§17.3) — the participant column: a named head over a dashed
|
|
411
|
+
* spine.
|
|
412
|
+
*
|
|
413
|
+
* `name` and `type` are the two halves of §17.3.4's `<name> : <Type>`, split by
|
|
414
|
+
* `parseLifelineIdent` — the same grammar `keywords.ts` seeds a fresh head
|
|
415
|
+
* with. `type` is absent when the author wrote a bare participant name, which
|
|
416
|
+
* is most of them.
|
|
417
|
+
*/
|
|
418
|
+
export interface UmlLifeline extends UmlNodeBase {
|
|
419
|
+
/** The Classifier this participant is an instance of (§17.3.4). */
|
|
420
|
+
type?: string;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* One Message (§17.4) — its two ends, its label, and WHEN it happens.
|
|
424
|
+
*
|
|
425
|
+
* ## Why `y` is on the record and the list is sorted by it
|
|
426
|
+
*
|
|
427
|
+
* Because on a sequence diagram the vertical axis IS time (§17.4.4: "every line
|
|
428
|
+
* fragment is either horizontal or downwards"), and every writer needs the
|
|
429
|
+
* order rather than the height: XMI serializes a pair of
|
|
430
|
+
* `MessageOccurrenceSpecification`s per message and an Interaction's `fragment`
|
|
431
|
+
* list is READ IN ORDER, PlantUML's whole syntax is one message per line top to
|
|
432
|
+
* bottom. So the canvas's one statement about sequence — the height an arrow was
|
|
433
|
+
* drawn at — is turned into an order here, once, and the writers take a list.
|
|
434
|
+
*
|
|
435
|
+
* `sourceId` and `targetId` are the ids the connector actually resolves to,
|
|
436
|
+
* which is a LIFELINE or an EXECUTION ({@link UmlExecution}): §17.4.4 draws an
|
|
437
|
+
* arrow onto the bar as readily as onto the spine, and a reading that snapped
|
|
438
|
+
* every end to a lifeline would lose which activation the author aimed at.
|
|
439
|
+
* A writer that needs the covering lifeline resolves it through
|
|
440
|
+
* {@link UmlExecution.lifelineId}.
|
|
441
|
+
*/
|
|
442
|
+
export interface UmlMessage {
|
|
443
|
+
/** The connector's own surface id — what a report names it by. */
|
|
444
|
+
id: string;
|
|
445
|
+
kind: UmlMessageKind;
|
|
446
|
+
sourceId: string;
|
|
447
|
+
targetId: string;
|
|
448
|
+
/** The connector's centre text: §17.4.4's message label, as written. */
|
|
449
|
+
label?: string;
|
|
450
|
+
/** The height it is drawn at — see the docblock. */
|
|
451
|
+
y: number;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* One InteractionOperand (§17.6.4) — a horizontal band of a combined fragment,
|
|
455
|
+
* separated from the next by a dashed line.
|
|
456
|
+
*
|
|
457
|
+
* `guard` is §17.6.4's `[…]` InteractionConstraint WITHOUT its brackets, the
|
|
458
|
+
* same way {@link UmlActivityEdge.guard} and {@link UmlTransition.guard} carry
|
|
459
|
+
* theirs: the brackets are the notation's delimiter, and a writer that had to
|
|
460
|
+
* strip them would be parsing its own model. The canvas keeps them — they are
|
|
461
|
+
* what the author typed and what the renderer paints — and
|
|
462
|
+
* {@link umlGuardText} takes exactly one pair off on the way in here.
|
|
463
|
+
*
|
|
464
|
+
* `y0` and `y1` are the band's own top and bottom in canvas units, because that
|
|
465
|
+
* is what decides which messages are inside WHICH operand — an `alt`'s two
|
|
466
|
+
* branches are told apart by nothing else.
|
|
467
|
+
*/
|
|
468
|
+
export interface UmlInteractionOperand {
|
|
469
|
+
guard?: string;
|
|
470
|
+
y0: number;
|
|
471
|
+
y1: number;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* A CombinedFragment (§17.6) — the rectangle with an operator in its corner —
|
|
475
|
+
* and, under the `ref` operator, §17.7's InteractionUse.
|
|
476
|
+
*
|
|
477
|
+
* ONE record for both, because the canvas draws one element for both
|
|
478
|
+
* (`UmlFragmentElementModel`): §17.7.4's InteractionUse is the same rectangle
|
|
479
|
+
* with the same pentagon, and every tool offers it from the same menu. The
|
|
480
|
+
* writers branch on `operator === 'ref'`, which is one line each.
|
|
481
|
+
*
|
|
482
|
+
* `name` is the fragment's own word — the first operand's guard on an `alt`,
|
|
483
|
+
* the referenced interaction's name on a `ref`.
|
|
484
|
+
*
|
|
485
|
+
* `coveredLifelineIds` is GEOMETRY, like every other membership in this file:
|
|
486
|
+
* a fragment covers the lifelines whose spine runs through it, because that is
|
|
487
|
+
* what §17.6.4 draws and a canvas holds no second statement about it.
|
|
488
|
+
*/
|
|
489
|
+
export interface UmlCombinedFragment extends UmlNodeBase {
|
|
490
|
+
operator: UmlFragmentOperator;
|
|
491
|
+
operands: UmlInteractionOperand[];
|
|
492
|
+
coveredLifelineIds: string[];
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* An ExecutionSpecification (§17.2.4) — the thin bar saying the participant is
|
|
496
|
+
* busy between two occurrences.
|
|
497
|
+
*
|
|
498
|
+
* `lifelineId` is the spine the bar sits ON, resolved by measuring
|
|
499
|
+
* ({@link umlLifelineAt}): a bar is a plain node and the canvas holds no
|
|
500
|
+
* parent link, exactly as a port's owner and a lollipop's component are read by
|
|
501
|
+
* measuring. Absent for a bar drawn off every spine — which is on the drawing
|
|
502
|
+
* and in no file.
|
|
503
|
+
*/
|
|
504
|
+
export interface UmlExecution extends UmlNodeBase {
|
|
505
|
+
lifelineId?: string;
|
|
506
|
+
/** The occurrence it starts at. */
|
|
507
|
+
y0: number;
|
|
508
|
+
/** The occurrence it finishes at. */
|
|
509
|
+
y1: number;
|
|
510
|
+
}
|
|
511
|
+
/** A DestructionOccurrenceSpecification (§17.2.4) — the X a lifeline ends at. */
|
|
512
|
+
export interface UmlDestruction extends UmlNodeBase {
|
|
513
|
+
lifelineId?: string;
|
|
514
|
+
y: number;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* One Interaction — the whole of what an `sd` sheet says.
|
|
518
|
+
*
|
|
519
|
+
* {@link UmlActivity}'s and {@link UmlStateMachine}'s twin, down to the reading
|
|
520
|
+
* that the FRAME IS THE INTERACTION: §17.2.4 draws the interaction as a
|
|
521
|
+
* rectangle with `sd <name>` in its corner, which is Annex A's frame, which is
|
|
522
|
+
* the frame this model was read off.
|
|
523
|
+
*/
|
|
524
|
+
export interface UmlInteraction {
|
|
525
|
+
/** The diagram frame's surface id — the Interaction IS the sheet. */
|
|
526
|
+
id: string;
|
|
527
|
+
name: string;
|
|
528
|
+
lifelines: UmlLifeline[];
|
|
529
|
+
/** ORDERED by `y`: top to bottom is earlier to later (§17.4.4). */
|
|
530
|
+
messages: UmlMessage[];
|
|
531
|
+
fragments: UmlCombinedFragment[];
|
|
532
|
+
executions: UmlExecution[];
|
|
533
|
+
destructions: UmlDestruction[];
|
|
534
|
+
}
|
|
535
|
+
/** One diagram, as everything the writers need and nothing else. */
|
|
536
|
+
export interface UmlModel {
|
|
537
|
+
diagram: {
|
|
538
|
+
id: string;
|
|
539
|
+
kind: UmlDiagramKind;
|
|
540
|
+
name: string;
|
|
541
|
+
/** `<kind> <name>` — Annex A's frame heading. */
|
|
542
|
+
heading: string;
|
|
543
|
+
bounds?: UmlBox;
|
|
544
|
+
};
|
|
545
|
+
classifiers: UmlClassifier[];
|
|
546
|
+
packages: UmlPackageNode[];
|
|
547
|
+
actors: UmlActorNode[];
|
|
548
|
+
useCases: UmlUseCaseNode[];
|
|
549
|
+
subjects: UmlSubjectBox[];
|
|
550
|
+
notes: UmlNote[];
|
|
551
|
+
/** §11.6 — the component boxes, each carrying its ports and its interfaces. */
|
|
552
|
+
components: UmlComponentNode[];
|
|
553
|
+
/**
|
|
554
|
+
* §11.3 — every port on the sheet, whether or not it found a host.
|
|
555
|
+
*
|
|
556
|
+
* Listed here AS WELL AS under its component, and the duplication is on
|
|
557
|
+
* purpose: the XMI writer walks the components (a `uml:Port` is an
|
|
558
|
+
* `ownedAttribute`, so it has nowhere else to go) while a reader asking "how
|
|
559
|
+
* many ports are on this sheet" — a check, a count, a later rule — must not
|
|
560
|
+
* have to know that a hostless one is invisible from every component. The two
|
|
561
|
+
* readings hold the SAME record, so they cannot disagree.
|
|
562
|
+
*/
|
|
563
|
+
ports: UmlPort[];
|
|
564
|
+
/** §19.3 — the artefacts. */
|
|
565
|
+
artifacts: UmlArtifactNode[];
|
|
566
|
+
/** §19.4 — the nodes, devices and execution environments. */
|
|
567
|
+
nodes: UmlDeploymentNode[];
|
|
568
|
+
/**
|
|
569
|
+
* §15.2 — the Activity this sheet draws, or nothing.
|
|
570
|
+
*
|
|
571
|
+
* A LIST holding zero or one entry rather than an optional field, and the
|
|
572
|
+
* shape is what makes both writers a loop instead of a branch: every other
|
|
573
|
+
* artefact on this model is a list, `for (const activity of model.activities)`
|
|
574
|
+
* reads identically to `for (const component of model.components)`, and a
|
|
575
|
+
* sheet that draws no flow contributes nothing without either writer testing
|
|
576
|
+
* for it. Populated when the sheet holds an activity NODE or an activity EDGE
|
|
577
|
+
* — a lone arrow is still something the author drew.
|
|
578
|
+
*/
|
|
579
|
+
activities: UmlActivity[];
|
|
580
|
+
/** §14.2 — the StateMachine this sheet draws, or nothing. The same shape. */
|
|
581
|
+
stateMachines: UmlStateMachine[];
|
|
582
|
+
/** §17.2 — the Interaction this sheet draws, or nothing. The same shape. */
|
|
583
|
+
interactions: UmlInteraction[];
|
|
584
|
+
relations: UmlRelation[];
|
|
585
|
+
/**
|
|
586
|
+
* What the READING could not make sense of, one line each, in the user's
|
|
587
|
+
* words (`InterchangeExportResult.warnings`).
|
|
588
|
+
*
|
|
589
|
+
* Never an error and never noise: the two cases below are both a connector
|
|
590
|
+
* the author DREW that no file can carry, which is the one thing a user who
|
|
591
|
+
* clicked Export is entitled to be told about. A shape with no role, a
|
|
592
|
+
* neutral connector between two neutral shapes, a type name that names
|
|
593
|
+
* nothing on this sheet — none of those is warned about, because none of them
|
|
594
|
+
* is a statement the author made and lost (`docs/adr/0010`).
|
|
595
|
+
*/
|
|
596
|
+
warnings: string[];
|
|
597
|
+
}
|
|
598
|
+
/**
|
|
599
|
+
* An element's box, from whichever of the three spellings it carries.
|
|
600
|
+
*
|
|
601
|
+
* `deserializedXYWH` first because that is what a live element answers with;
|
|
602
|
+
* `elementBound` because that is what the shared canvas fixtures build; the
|
|
603
|
+
* serialized `xywh` last, for a record that carries only what the store holds.
|
|
604
|
+
*/
|
|
605
|
+
export declare function umlBoundsOf(element: UmlSourceElement): UmlBox | undefined;
|
|
606
|
+
/** Inclusive containment of a box's CENTRE in another box. */
|
|
607
|
+
export declare function umlCentreInside(inner: UmlBox, outer: UmlBox): boolean;
|
|
608
|
+
/**
|
|
609
|
+
* How near a glyph has to be drawn to count as attached to a box, in model
|
|
610
|
+
* units.
|
|
611
|
+
*
|
|
612
|
+
* The one number this file invents, and the reason it is small: §10.4.4 and
|
|
613
|
+
* §11.3.4 both describe a symbol TOUCHING a rectangle — a lollipop "attached by
|
|
614
|
+
* a solid line" to the classifier that realizes it, a port "overlapping the
|
|
615
|
+
* boundary" of the box it is on. Touching is a gap of zero, and a hand drawing
|
|
616
|
+
* on a canvas misses by a few units, so the tolerance is a couple of grid steps
|
|
617
|
+
* and not a neighbourhood: an interface glyph parked halfway across the sheet is
|
|
618
|
+
* not this component's, and a reading that guessed would put an interface in the
|
|
619
|
+
* file that nobody drew.
|
|
620
|
+
*
|
|
621
|
+
* Read by {@link umlHostOf} and by {@link umlBoxGap}'s callers alike, so the
|
|
622
|
+
* port's owner and the interface's component are decided by the same distance.
|
|
623
|
+
*/
|
|
624
|
+
export declare const UML_ATTACH_TOLERANCE = 24;
|
|
625
|
+
/**
|
|
626
|
+
* The GAP between two boxes — zero when they touch or overlap, otherwise the
|
|
627
|
+
* shortest distance from edge to edge.
|
|
628
|
+
*
|
|
629
|
+
* Edges, never centres: a lollipop is thirty units across and a component two
|
|
630
|
+
* hundred, so "nearest centre" would hand a glyph to whichever box happens to be
|
|
631
|
+
* squattest rather than to the one it is drawn against. The same argument
|
|
632
|
+
* `gapSquared` makes in the validation engine, one package over.
|
|
633
|
+
*/
|
|
634
|
+
export declare function umlBoxGap(a: UmlBox, b: UmlBox): number;
|
|
635
|
+
/**
|
|
636
|
+
* The DRAWING area of a diagram frame — the frame minus its heading band.
|
|
637
|
+
*
|
|
638
|
+
* The same carve-out `c4/export.ts` makes with `backgroundPlot`, arrived at from
|
|
639
|
+
* the MODEL's own constant so this module owes the framework declaration
|
|
640
|
+
* nothing: the top margin is where the frame writes its own heading
|
|
641
|
+
* (`UmlDiagramElementModel`), and an element laid over the heading is on the
|
|
642
|
+
* sheet's chrome rather than on its drawing area.
|
|
643
|
+
*/
|
|
644
|
+
export declare function umlSheetOf(frame: UmlBox): UmlBox;
|
|
645
|
+
/** The little {@link umlHostOf} needs to know about a candidate host. */
|
|
646
|
+
export interface UmlHostCandidate {
|
|
647
|
+
id: string;
|
|
648
|
+
bounds?: UmlBox;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* Which box a glyph is drawn AGAINST — the one reading that gives a port its
|
|
652
|
+
* owner and a lollipop its component.
|
|
653
|
+
*
|
|
654
|
+
* The nearest host within {@link UML_ATTACH_TOLERANCE}, and `undefined` when
|
|
655
|
+
* nothing is that near: a port drawn in the middle of the sheet belongs to
|
|
656
|
+
* nothing, and inventing an owner for it would put a `uml:Port` on a component
|
|
657
|
+
* the author never drew it on.
|
|
658
|
+
*
|
|
659
|
+
* ## The tie-breaks, and why there are two of them
|
|
660
|
+
*
|
|
661
|
+
* A component nested inside another (§11.6.4's white-box view) puts a port on
|
|
662
|
+
* the boundary of BOTH, at a gap of zero from each. The smaller box wins,
|
|
663
|
+
* because the most-nested container is the one the author was aiming at — the
|
|
664
|
+
* same reading `containerOf` makes in the two writers. And an exact tie on both
|
|
665
|
+
* gap and area is broken by the smaller id, never by the order the surface
|
|
666
|
+
* happened to be walked in: this decides what a FILE says, and a Y.Map rebuilt
|
|
667
|
+
* on every load does not promise an order.
|
|
668
|
+
*/
|
|
669
|
+
export declare function umlHostOf<T extends UmlHostCandidate>(glyph: UmlBox | undefined, hosts: readonly T[], tolerance?: number): T | undefined;
|
|
670
|
+
/**
|
|
671
|
+
* The x of a lifeline's SPINE — the dashed line everything on a sequence sheet
|
|
672
|
+
* is measured against.
|
|
673
|
+
*
|
|
674
|
+
* The centre of the element's own box, which is the column and not the head:
|
|
675
|
+
* `UmlNodeElementModel` makes a lifeline a narrow tall column so that the
|
|
676
|
+
* connector layer's native anchors land on the spine, and paints the 160-wide
|
|
677
|
+
* head over the top of it. So the spine is the column's own centre line, and
|
|
678
|
+
* this function exists so that the four readers below cannot each decide that
|
|
679
|
+
* differently.
|
|
680
|
+
*/
|
|
681
|
+
export declare function umlSpineX(lifeline: UmlBox): number;
|
|
682
|
+
/**
|
|
683
|
+
* How far off a spine a bar or a cross may be drawn and still be ON it.
|
|
684
|
+
*
|
|
685
|
+
* Half the HEAD's width, and it is the notation's own number rather than a
|
|
686
|
+
* guess: §17.2.4 draws an ExecutionSpecification as a bar centred on the spine
|
|
687
|
+
* and a destruction as a cross centred on it, so the honest tolerance is "nearer
|
|
688
|
+
* to this spine than to any other", and lifelines laid out at the 200-unit
|
|
689
|
+
* spacing of an invented sequence layout are 200 apart. 80 is inside that by a
|
|
690
|
+
* comfortable margin, so a bar dropped a little off centre finds its own
|
|
691
|
+
* lifeline and a bar dropped between two finds neither.
|
|
692
|
+
*/
|
|
693
|
+
export declare const UML_SPINE_TOLERANCE: number;
|
|
694
|
+
/**
|
|
695
|
+
* Which lifeline a bar or a cross is drawn ON — {@link umlHostOf}'s twin for
|
|
696
|
+
* §17.2.4's two glyphs.
|
|
697
|
+
*
|
|
698
|
+
* A different reading from `umlHostOf` and deliberately so: a port is attached
|
|
699
|
+
* to a box by TOUCHING it, and a bar is attached to a spine by SITTING ON it —
|
|
700
|
+
* one is an edge-to-edge gap, the other a distance from one vertical line. The
|
|
701
|
+
* nearest spine within {@link UML_SPINE_TOLERANCE} wins; an exact tie is broken
|
|
702
|
+
* by the smaller id, never by the order the surface happened to be walked in,
|
|
703
|
+
* for the reason `umlHostOf` gives: this decides what a FILE says.
|
|
704
|
+
*
|
|
705
|
+
* `undefined` when nothing is that near — a bar drawn between two spines belongs
|
|
706
|
+
* to neither, and inventing an owner for it would put an execution on a
|
|
707
|
+
* participant the author never drew it on.
|
|
708
|
+
*/
|
|
709
|
+
export declare function umlLifelineAt<T extends UmlHostCandidate>(glyph: UmlBox | undefined, lifelines: readonly T[]): T | undefined;
|
|
710
|
+
/**
|
|
711
|
+
* The operand bands of a combined fragment, as boxes — §17.6.4's horizontal
|
|
712
|
+
* slices, separated by dashed lines.
|
|
713
|
+
*
|
|
714
|
+
* The operator BAND is carved off the top first (`UML_FRAGMENT_BAND`), exactly
|
|
715
|
+
* as `umlSheetOf` carves the frame's heading off: the pentagon is the
|
|
716
|
+
* fragment's own chrome, and a guard written over it is on the furniture rather
|
|
717
|
+
* than in an operand.
|
|
718
|
+
*
|
|
719
|
+
* `size` is a relative WEIGHT (`UmlFragmentOperand`), so the bands are the body
|
|
720
|
+
* divided in proportion — a fragment dragged taller keeps its operands' shares.
|
|
721
|
+
* A fragment that declares no operands is ONE operand, which is what every
|
|
722
|
+
* `opt`, every `loop` and every `ref` is, and its guard is the fragment's own
|
|
723
|
+
* `name`.
|
|
724
|
+
*/
|
|
725
|
+
/**
|
|
726
|
+
* A guard as the IR spells it — §17.6.4's condition with ONE surrounding pair
|
|
727
|
+
* of brackets taken off.
|
|
728
|
+
*
|
|
729
|
+
* The canvas text is exactly what the author types, and §17.6.4.4 prints the
|
|
730
|
+
* condition **in brackets**: `[x > 0]`, `[else]`. So the brackets are stored,
|
|
731
|
+
* the renderer paints them verbatim, and the delimiter is stripped HERE, once,
|
|
732
|
+
* for both writers — PlantUML writes its own `[…]` back round the condition and
|
|
733
|
+
* XMI writes a bare `LiteralString`, and neither should have to parse the
|
|
734
|
+
* model it is given.
|
|
735
|
+
*
|
|
736
|
+
* Tolerant in both directions, because a guard is free text an author types:
|
|
737
|
+
* `x > 0` typed without brackets is the same condition and exports identically,
|
|
738
|
+
* and `[[x > 0]]` gives up exactly one pair. Only a pair that actually
|
|
739
|
+
* SURROUNDS the condition is taken — `[a] or [b]` opens and closes twice, and
|
|
740
|
+
* dropping its outer characters would turn a sentence inside out.
|
|
741
|
+
*/
|
|
742
|
+
export declare function umlGuardText(written: string | undefined): string;
|
|
743
|
+
export declare function umlOperandBands(box: UmlBox, operands: readonly UmlFragmentOperand[] | undefined, name: string): UmlInteractionOperand[];
|
|
744
|
+
export interface UmlModelOptions {
|
|
745
|
+
/**
|
|
746
|
+
* Which words belong to which shape — `component.ts`'s
|
|
747
|
+
* {@link umlComponentSiblings}, injectable.
|
|
748
|
+
*
|
|
749
|
+
* Injectable rather than only imported so a caller can resolve a component
|
|
750
|
+
* some other way (a test with a hand-built resolution, a host that already
|
|
751
|
+
* holds the answer) without this module growing a second reading of a group.
|
|
752
|
+
* The default IS `umlComponentSiblings`, so nothing has two behaviours.
|
|
753
|
+
*/
|
|
754
|
+
siblingsOf?: (group: UmlComponentGroup, elements: readonly UmlComponentElement[]) => UmlComponent;
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* One diagram, read off a flat element list.
|
|
758
|
+
*
|
|
759
|
+
* ## What belongs to it
|
|
760
|
+
*
|
|
761
|
+
* Geometry, exactly as every other framework in this library attributes: an
|
|
762
|
+
* element is on this sheet when its CENTRE is inside the frame's drawing area.
|
|
763
|
+
* Selecting a frame therefore selects what is drawn on it, and a second frame
|
|
764
|
+
* beside it is a second diagram — the reading `c4/export.ts` argues for at
|
|
765
|
+
* length, and the reason UML ships four diagram kinds on one canvas (ADR 0017).
|
|
766
|
+
*
|
|
767
|
+
* ## How an end finds its artefact
|
|
768
|
+
*
|
|
769
|
+
* A UML node is drawn as a GROUP — a shape plus its written tiers — and every
|
|
770
|
+
* part of that group is connectable. An arrow dragged onto a class records the
|
|
771
|
+
* id of the group, of the name tier or of the attribute tier about as often as
|
|
772
|
+
* the shape's, and all four look identical to the person drawing it. So each
|
|
773
|
+
* part answers for its shape, and only where the group holds exactly ONE UML
|
|
774
|
+
* node: a lasso somebody drew round two classes points at neither in
|
|
775
|
+
* particular, and guessing there would put a relationship in the file that
|
|
776
|
+
* nobody drew.
|
|
777
|
+
*
|
|
778
|
+
* ## Two things geometry decides, and nothing else does
|
|
779
|
+
*
|
|
780
|
+
* Phase 2 added the only readings in this file that measure one element against
|
|
781
|
+
* ANOTHER element: which component a PORT sits on (§11.3.4) and which component
|
|
782
|
+
* a lollipop or a socket is drawn against (§10.4.4, §11.6.4). Both are the
|
|
783
|
+
* notation's own statement — the specification describes a small symbol placed
|
|
784
|
+
* on or touching a rectangle, and a whiteboard holds no second link to read — so
|
|
785
|
+
* the reading is {@link umlHostOf} and the tolerance is
|
|
786
|
+
* {@link UML_ATTACH_TOLERANCE}. A glyph that touches nothing is kept on the
|
|
787
|
+
* drawing and written into no file, which is the same call the rest of this
|
|
788
|
+
* module makes about anything it cannot attribute.
|
|
789
|
+
*
|
|
790
|
+
* ## What is warned about
|
|
791
|
+
*
|
|
792
|
+
* Two things, and both are a line the author DREW that the file cannot carry: a
|
|
793
|
+
* typed relationship with an end this diagram cannot resolve, and a connector
|
|
794
|
+
* between two UML nodes carrying no role at all. The second is not an error —
|
|
795
|
+
* `docs/adr/0010` is explicit that the role IS the statement, so a bare
|
|
796
|
+
* connector relates nothing — but a user who drew a line between two classes
|
|
797
|
+
* and gets a file without it is owed the sentence.
|
|
798
|
+
*
|
|
799
|
+
* Neither is said about a connector that is not this sheet's. A line belongs to
|
|
800
|
+
* this diagram when at least one of its ends resolves to an artefact of it, or —
|
|
801
|
+
* for a line attached to nothing — when its own centre is inside the sheet.
|
|
802
|
+
* Anything else is another frame's drawing, and warning about it would mean
|
|
803
|
+
* every export of a two-frame board complaining about lines that are perfectly
|
|
804
|
+
* drawn next door.
|
|
805
|
+
*/
|
|
806
|
+
export declare function umlModelFrom(diagram: UmlSourceElement, elements: readonly UmlSourceElement[], options?: UmlModelOptions): UmlModel;
|
|
807
|
+
/**
|
|
808
|
+
* One thing that happens on a sequence sheet, at the height it happens at.
|
|
809
|
+
*
|
|
810
|
+
* A discriminated union over the five, and a TREE rather than a list: a combined
|
|
811
|
+
* fragment carries the entries drawn inside each of its operands, which is what
|
|
812
|
+
* §17.6.4 makes it — an `InteractionOperand` OWNS the fragments in its band, and
|
|
813
|
+
* PlantUML's `alt … else … end` is the same nesting spelled with keywords.
|
|
814
|
+
*/
|
|
815
|
+
export type UmlTimelineEntry = {
|
|
816
|
+
at: 'message';
|
|
817
|
+
y: number;
|
|
818
|
+
message: UmlMessage;
|
|
819
|
+
} | {
|
|
820
|
+
at: 'execution-start';
|
|
821
|
+
y: number;
|
|
822
|
+
execution: UmlExecution;
|
|
823
|
+
} | {
|
|
824
|
+
at: 'execution-finish';
|
|
825
|
+
y: number;
|
|
826
|
+
execution: UmlExecution;
|
|
827
|
+
} | {
|
|
828
|
+
at: 'destruction';
|
|
829
|
+
y: number;
|
|
830
|
+
destruction: UmlDestruction;
|
|
831
|
+
} | {
|
|
832
|
+
at: 'fragment';
|
|
833
|
+
y: number;
|
|
834
|
+
fragment: UmlCombinedFragment;
|
|
835
|
+
operands: UmlTimelineOperand[];
|
|
836
|
+
};
|
|
837
|
+
/** One operand's band and what is drawn in it. */
|
|
838
|
+
export interface UmlTimelineOperand {
|
|
839
|
+
operand: UmlInteractionOperand;
|
|
840
|
+
entries: UmlTimelineEntry[];
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* One Interaction as the ordered, nested account of what happens on it — the
|
|
844
|
+
* reading BOTH writers take, so that a `.puml` and an XMI file can never
|
|
845
|
+
* disagree about the order of a conversation.
|
|
846
|
+
*
|
|
847
|
+
* ## What decides that something is INSIDE a fragment
|
|
848
|
+
*
|
|
849
|
+
* Two things, and both are what §17.6.4 draws: the moment falls inside the
|
|
850
|
+
* fragment's box VERTICALLY, and the fragment COVERS the lifeline it happens on
|
|
851
|
+
* ({@link UmlCombinedFragment.coveredLifelineIds}). The second is what stops an
|
|
852
|
+
* `alt` drawn over two of five participants from swallowing a message exchanged
|
|
853
|
+
* between the other three at the same height — which a y-only test would, and
|
|
854
|
+
* which would put an arrow in a branch nobody drew it in.
|
|
855
|
+
*
|
|
856
|
+
* The innermost matching fragment wins, measured by AREA, exactly as `umlHostOf`
|
|
857
|
+
* and `containerOf` decide every other containment in this framework.
|
|
858
|
+
*
|
|
859
|
+
* Pure and total: every message, bar and cross of the interaction comes back
|
|
860
|
+
* exactly once, whether it landed in a fragment or at the top level.
|
|
861
|
+
*/
|
|
862
|
+
export declare function umlInteractionTimeline(interaction: UmlInteraction): UmlTimelineEntry[];
|