@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
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import type { UmlNodeKind } from '@formicoidea/labre-core/model';
|
|
2
|
+
/**
|
|
3
|
+
* UML keywords, the guillemets they are written in, and the words a fresh
|
|
4
|
+
* artefact arrives carrying.
|
|
5
|
+
*
|
|
6
|
+
* ## Why keywords are a module and not a string literal
|
|
7
|
+
*
|
|
8
|
+
* A keyword is not decoration: UML 2.5.1 Annex C (normative) makes it the thing
|
|
9
|
+
* that tells two artefacts apart when the notation draws them the same way. A
|
|
10
|
+
* compartmented rectangle is a Class; the SAME rectangle with `«interface»` in
|
|
11
|
+
* its header box is an Interface. So the keyword carries the author's statement,
|
|
12
|
+
* the exporters read it back out of the name compartment
|
|
13
|
+
* ({@link stereotypesOf}), and the seeds below are what puts it there in the
|
|
14
|
+
* first place.
|
|
15
|
+
*
|
|
16
|
+
* Annex C is also explicit about the punctuation: keywords are "always enclosed
|
|
17
|
+
* in guillemets", and the note under the table warns that `<<` and `>>` are a
|
|
18
|
+
* fallback for character sets that lack `«»`, not a spelling. Labre writes the
|
|
19
|
+
* real characters ({@link guillemets}) and READS both, because a diagram pasted
|
|
20
|
+
* in from a tool that only had ASCII still means what it says.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* A keyword as it is written on a diagram — `interface` → `«interface»`.
|
|
24
|
+
*
|
|
25
|
+
* The real guillemets, per the Annex C note. Nothing is validated: Annex C's
|
|
26
|
+
* table is the list of keywords UML defines, not the list of labels an author
|
|
27
|
+
* may write between guillemets — a stereotype name goes in the same brackets
|
|
28
|
+
* (Annex C, "Not all words appearing between guillemets are necessarily
|
|
29
|
+
* keywords"), and refusing one here would be this module inventing a rule the
|
|
30
|
+
* spec declines to make.
|
|
31
|
+
*/
|
|
32
|
+
export declare function guillemets(keyword: string): string;
|
|
33
|
+
/** The opening and closing guillemet, named so no call site types a raw glyph. */
|
|
34
|
+
export declare const GUILLEMET_OPEN = "\u00AB";
|
|
35
|
+
export declare const GUILLEMET_CLOSE = "\u00BB";
|
|
36
|
+
/**
|
|
37
|
+
* The places Annex C says a keyword may appear, verbatim from its own legend
|
|
38
|
+
* (the eight conventions listed under "Notation Placement").
|
|
39
|
+
*
|
|
40
|
+
* Phase 1 only ever writes in three of them, and the union carries the rest
|
|
41
|
+
* anyway because it is a transcription of a normative list: narrowing it to
|
|
42
|
+
* what we happen to draw today would turn a quotation into an opinion.
|
|
43
|
+
*/
|
|
44
|
+
export type UmlKeywordPlacement = 'box header' | 'dashed-line label' | 'line label' | 'inline label' | 'swimlane header' | 'note label' | 'top left corner' | 'after name';
|
|
45
|
+
/**
|
|
46
|
+
* The Annex C keywords phase 1 can draw, each with the placement Table C.1
|
|
47
|
+
* gives it.
|
|
48
|
+
*
|
|
49
|
+
* A SUBSET, declared as one: UML defines some eighty keywords and phase 1 draws
|
|
50
|
+
* four structural diagram families, so the table below is the eighteen words that
|
|
51
|
+
* can honestly appear on a class, package, object or use case diagram. Phase 2
|
|
52
|
+
* appends to it; nothing here is rewritten.
|
|
53
|
+
*
|
|
54
|
+
* Read the placements straight off Table C.1 (pp. 746-748):
|
|
55
|
+
*
|
|
56
|
+
* - `interface`, `enumeration`, `dataType` — **box header**: they sit in the
|
|
57
|
+
* name compartment of a classifier rectangle, which is what makes the same
|
|
58
|
+
* rectangle mean three different metaclasses;
|
|
59
|
+
* - `use`, `call`, `create` — **dashed-line label**: a Usage is a Dependency,
|
|
60
|
+
* and every Dependency is one dashed arrow among many, so the keyword is the
|
|
61
|
+
* only thing on the picture that says which one it is;
|
|
62
|
+
* - `import`, `access` — **dashed-line label**: the same PackageImport drawn
|
|
63
|
+
* twice, public and private (Table C.1 keys them on `visibility`);
|
|
64
|
+
* - `merge` — **dashed-line label**, a PackageMerge;
|
|
65
|
+
* - `include`, `extend` — **dashed-line label**, the two relationships between
|
|
66
|
+
* UseCases (§18.1.4).
|
|
67
|
+
*
|
|
68
|
+
* `abstract` is the one entry that is NOT in Table C.1, and it is here because
|
|
69
|
+
* the parser has to recognise it: §9.2.4 writes an abstract Classifier's name in
|
|
70
|
+
* italics, and a canvas with no italic name compartment writes the alternative
|
|
71
|
+
* the same clause allows — `{abstract}` after the name. It is a MODIFIER, not a
|
|
72
|
+
* keyword, so it takes no guillemets, and {@link stereotypesOf} reports it in
|
|
73
|
+
* its own field rather than in the keyword list.
|
|
74
|
+
*
|
|
75
|
+
* `create` appears TWICE in Table C.1 — as a dashed-line label on a Usage and as
|
|
76
|
+
* an inline label on a constructor BehavioralFeature. The dependency reading is
|
|
77
|
+
* the one phase 1 draws, and it is the one recorded.
|
|
78
|
+
*/
|
|
79
|
+
export declare const UML_KEYWORD_PLACEMENT: Readonly<Record<string, UmlKeywordPlacement>>;
|
|
80
|
+
/**
|
|
81
|
+
* The text a node arrives with in its NAME compartment, per kind.
|
|
82
|
+
*
|
|
83
|
+
* Every seed is a true statement about the box that carries it — which is the
|
|
84
|
+
* rule the C4 pack settled on and the reason its title seed is `Container`
|
|
85
|
+
* rather than a bracketed prompt: an unnamed class IS a class, and exporting
|
|
86
|
+
* `Class` says something, where exporting an invented placeholder would say
|
|
87
|
+
* something false. So a diagram the author has not typed on yet still exports,
|
|
88
|
+
* still round-trips, and still reads.
|
|
89
|
+
*
|
|
90
|
+
* Three of them carry more than a word, and each is the notation asking for it:
|
|
91
|
+
*
|
|
92
|
+
* - `interface` and `enumeration` open with their Annex C keyword above the
|
|
93
|
+
* name — that keyword is what distinguishes the metaclass, so a fresh
|
|
94
|
+
* interface that did not carry it would be a class;
|
|
95
|
+
* - `object` seeds `object : Class`, the underlined `name : Type` of §11.6. The
|
|
96
|
+
* UNDERLINE is drawn by the renderer and is not in the text: it is notation,
|
|
97
|
+
* not a character, and an author who retyped the line would otherwise have to
|
|
98
|
+
* reproduce it.
|
|
99
|
+
*
|
|
100
|
+
* ## The empty ones
|
|
101
|
+
*
|
|
102
|
+
* Thirteen kinds seed the EMPTY STRING, and that is a statement rather than a
|
|
103
|
+
* gap: the control nodes of §15.3.4 and the pseudostates of §14.2.4 are marks
|
|
104
|
+
* with no words in them — a disc, a bar, a bullseye, a cross — so the true
|
|
105
|
+
* statement about them is silence. {@link UML_UNLABELLED_KINDS} is that fact as
|
|
106
|
+
* a set, and it is what the creation site and the audit both read.
|
|
107
|
+
*/
|
|
108
|
+
export declare const UML_NAME_SEED: Record<UmlNodeKind, string>;
|
|
109
|
+
/**
|
|
110
|
+
* The kinds a fresh artefact arrives with NO label text at all.
|
|
111
|
+
*
|
|
112
|
+
* Derived from {@link UML_NAME_SEED} rather than listed beside it, because the
|
|
113
|
+
* two would otherwise be one fact written twice: a kind whose seed is empty IS
|
|
114
|
+
* a kind with nothing to write, and a hand-kept list is how one of them comes to
|
|
115
|
+
* say otherwise.
|
|
116
|
+
*
|
|
117
|
+
* ## What a caller does with it
|
|
118
|
+
*
|
|
119
|
+
* The creation site (`actions.ts`) reads it to decide whether to write a `text`
|
|
120
|
+
* element into the group at all — a control node or a pseudostate is the SHAPE
|
|
121
|
+
* and nothing else, and a group holding a 24-unit disc and an empty text box is
|
|
122
|
+
* a group with an invisible member an author can select by accident.
|
|
123
|
+
*
|
|
124
|
+
* The audit reads it too, and that is the more important half: a `label-presence`
|
|
125
|
+
* rule fires on an artefact that should be named and is not, and firing it on
|
|
126
|
+
* every decision diamond on the sheet would be the audit reporting the notation
|
|
127
|
+
* as a defect (`rules.ts`, `uml.unnamed-action` / `uml.unnamed-state`, whose
|
|
128
|
+
* `appliesTo` is the complement of this set).
|
|
129
|
+
*/
|
|
130
|
+
export declare const UML_UNLABELLED_KINDS: ReadonlySet<UmlNodeKind>;
|
|
131
|
+
/**
|
|
132
|
+
* The i18n key {@link UML_NAME_SEED} is the English default of — the same
|
|
133
|
+
* derivation BPMN's and C4's `nodeLabelKey` are, one package over: resolved AT
|
|
134
|
+
* PLACEMENT (`createUmlNode`, `createUmlClassifier`) and never afterwards,
|
|
135
|
+
* since what a gesture writes into the document is content the author owns
|
|
136
|
+
* from that moment on, and a renderer that re-translated it on every paint
|
|
137
|
+
* would silently overwrite a name somebody typed.
|
|
138
|
+
*
|
|
139
|
+
* The kinds seeded with nothing ({@link UML_UNLABELLED_KINDS}) ask for no key:
|
|
140
|
+
* there is no word to translate, and the notation draws them as marks.
|
|
141
|
+
*/
|
|
142
|
+
export declare const umlSeedKey: (kind: UmlNodeKind) => string;
|
|
143
|
+
/**
|
|
144
|
+
* The attribute compartment of a fresh classifier — one property in the §9.5.4
|
|
145
|
+
* syntax the parser reads back.
|
|
146
|
+
*
|
|
147
|
+
* A worked example rather than a prompt: it parses, it exports, and an author
|
|
148
|
+
* editing it has the grammar in front of them instead of in a manual.
|
|
149
|
+
*/
|
|
150
|
+
export declare const UML_ATTRIBUTES_SEED = "+ attribute : Type";
|
|
151
|
+
/** The key the line above is the English default of, resolved at placement. */
|
|
152
|
+
export declare const UML_ATTRIBUTES_SEED_KEY = "com.labre.uml.seed.attributes";
|
|
153
|
+
/** The operation compartment of a fresh classifier — §9.6.4, same argument. */
|
|
154
|
+
export declare const UML_OPERATIONS_SEED = "+ operation() : Type";
|
|
155
|
+
/** Its own key, resolved at placement like the one above. */
|
|
156
|
+
export declare const UML_OPERATIONS_SEED_KEY = "com.labre.uml.seed.operations";
|
|
157
|
+
/**
|
|
158
|
+
* The one written tier of a fresh object — a SLOT, not a property.
|
|
159
|
+
*
|
|
160
|
+
* An InstanceSpecification's compartment holds `name = value` (§11.6.4): no
|
|
161
|
+
* visibility, no type, no multiplicity, because an instance does not redeclare
|
|
162
|
+
* its classifier's features, it gives them values.
|
|
163
|
+
*/
|
|
164
|
+
export declare const UML_SLOTS_SEED = "attribute = value";
|
|
165
|
+
/** Its own key, resolved at placement like the two above. */
|
|
166
|
+
export declare const UML_SLOTS_SEED_KEY = "com.labre.uml.seed.slots";
|
|
167
|
+
/** What a name compartment states, once its notation has been read off it. */
|
|
168
|
+
export interface UmlStereotypes {
|
|
169
|
+
/**
|
|
170
|
+
* The labels between guillemets, in the order they were written, commas
|
|
171
|
+
* inside one pair split into separate entries per Annex C's
|
|
172
|
+
* `"«" <label> ["," <label>]* "»"`.
|
|
173
|
+
*/
|
|
174
|
+
keywords: string[];
|
|
175
|
+
/** Everything else, lines joined by `\n` and trimmed. */
|
|
176
|
+
name: string;
|
|
177
|
+
/** Whether `{abstract}` was written on it (§9.2.4). */
|
|
178
|
+
isAbstract: boolean;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* A name compartment, split into what the notation says and what the author
|
|
182
|
+
* named the thing.
|
|
183
|
+
*
|
|
184
|
+
* ## Why this is one function and not three
|
|
185
|
+
*
|
|
186
|
+
* The three facts live in the same string and are read by the same pass: a
|
|
187
|
+
* classifier's header box is `«keyword»` lines, then the name, with `{abstract}`
|
|
188
|
+
* anywhere on it. Reading them separately would mean three scans that can
|
|
189
|
+
* disagree about where the name starts.
|
|
190
|
+
*
|
|
191
|
+
* ## Guillemets above the name, and beside it
|
|
192
|
+
*
|
|
193
|
+
* §9.2.4 draws the keyword on its own line above the name, which is what the
|
|
194
|
+
* seeds write. Tools routinely write it INLINE — `«interface» Payable` — and
|
|
195
|
+
* both are accepted here: a group is lifted out wherever it appears, and a line
|
|
196
|
+
* that held nothing else disappears with it. What is left, in order, is the
|
|
197
|
+
* name. Nothing is re-ordered and nothing is folded: a two-line name stays two
|
|
198
|
+
* lines, because a name compartment that wraps is a name that wraps.
|
|
199
|
+
*
|
|
200
|
+
* A compartment with no guillemets and no marker comes back as
|
|
201
|
+
* `{ keywords: [], name: <the text>, isAbstract: false }` — the common case, and
|
|
202
|
+
* it costs the caller no special handling.
|
|
203
|
+
*/
|
|
204
|
+
export declare function stereotypesOf(text: string | undefined | null): UmlStereotypes;
|
package/dist/keywords.js
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UML keywords, the guillemets they are written in, and the words a fresh
|
|
3
|
+
* artefact arrives carrying.
|
|
4
|
+
*
|
|
5
|
+
* ## Why keywords are a module and not a string literal
|
|
6
|
+
*
|
|
7
|
+
* A keyword is not decoration: UML 2.5.1 Annex C (normative) makes it the thing
|
|
8
|
+
* that tells two artefacts apart when the notation draws them the same way. A
|
|
9
|
+
* compartmented rectangle is a Class; the SAME rectangle with `«interface»` in
|
|
10
|
+
* its header box is an Interface. So the keyword carries the author's statement,
|
|
11
|
+
* the exporters read it back out of the name compartment
|
|
12
|
+
* ({@link stereotypesOf}), and the seeds below are what puts it there in the
|
|
13
|
+
* first place.
|
|
14
|
+
*
|
|
15
|
+
* Annex C is also explicit about the punctuation: keywords are "always enclosed
|
|
16
|
+
* in guillemets", and the note under the table warns that `<<` and `>>` are a
|
|
17
|
+
* fallback for character sets that lack `«»`, not a spelling. Labre writes the
|
|
18
|
+
* real characters ({@link guillemets}) and READS both, because a diagram pasted
|
|
19
|
+
* in from a tool that only had ASCII still means what it says.
|
|
20
|
+
*/
|
|
21
|
+
/* ── Writing one ──────────────────────────────────────────────────────── */
|
|
22
|
+
/**
|
|
23
|
+
* A keyword as it is written on a diagram — `interface` → `«interface»`.
|
|
24
|
+
*
|
|
25
|
+
* The real guillemets, per the Annex C note. Nothing is validated: Annex C's
|
|
26
|
+
* table is the list of keywords UML defines, not the list of labels an author
|
|
27
|
+
* may write between guillemets — a stereotype name goes in the same brackets
|
|
28
|
+
* (Annex C, "Not all words appearing between guillemets are necessarily
|
|
29
|
+
* keywords"), and refusing one here would be this module inventing a rule the
|
|
30
|
+
* spec declines to make.
|
|
31
|
+
*/
|
|
32
|
+
export function guillemets(keyword) {
|
|
33
|
+
return `«${keyword}»`;
|
|
34
|
+
}
|
|
35
|
+
/** The opening and closing guillemet, named so no call site types a raw glyph. */
|
|
36
|
+
export const GUILLEMET_OPEN = '«';
|
|
37
|
+
export const GUILLEMET_CLOSE = '»';
|
|
38
|
+
/**
|
|
39
|
+
* The Annex C keywords phase 1 can draw, each with the placement Table C.1
|
|
40
|
+
* gives it.
|
|
41
|
+
*
|
|
42
|
+
* A SUBSET, declared as one: UML defines some eighty keywords and phase 1 draws
|
|
43
|
+
* four structural diagram families, so the table below is the eighteen words that
|
|
44
|
+
* can honestly appear on a class, package, object or use case diagram. Phase 2
|
|
45
|
+
* appends to it; nothing here is rewritten.
|
|
46
|
+
*
|
|
47
|
+
* Read the placements straight off Table C.1 (pp. 746-748):
|
|
48
|
+
*
|
|
49
|
+
* - `interface`, `enumeration`, `dataType` — **box header**: they sit in the
|
|
50
|
+
* name compartment of a classifier rectangle, which is what makes the same
|
|
51
|
+
* rectangle mean three different metaclasses;
|
|
52
|
+
* - `use`, `call`, `create` — **dashed-line label**: a Usage is a Dependency,
|
|
53
|
+
* and every Dependency is one dashed arrow among many, so the keyword is the
|
|
54
|
+
* only thing on the picture that says which one it is;
|
|
55
|
+
* - `import`, `access` — **dashed-line label**: the same PackageImport drawn
|
|
56
|
+
* twice, public and private (Table C.1 keys them on `visibility`);
|
|
57
|
+
* - `merge` — **dashed-line label**, a PackageMerge;
|
|
58
|
+
* - `include`, `extend` — **dashed-line label**, the two relationships between
|
|
59
|
+
* UseCases (§18.1.4).
|
|
60
|
+
*
|
|
61
|
+
* `abstract` is the one entry that is NOT in Table C.1, and it is here because
|
|
62
|
+
* the parser has to recognise it: §9.2.4 writes an abstract Classifier's name in
|
|
63
|
+
* italics, and a canvas with no italic name compartment writes the alternative
|
|
64
|
+
* the same clause allows — `{abstract}` after the name. It is a MODIFIER, not a
|
|
65
|
+
* keyword, so it takes no guillemets, and {@link stereotypesOf} reports it in
|
|
66
|
+
* its own field rather than in the keyword list.
|
|
67
|
+
*
|
|
68
|
+
* `create` appears TWICE in Table C.1 — as a dashed-line label on a Usage and as
|
|
69
|
+
* an inline label on a constructor BehavioralFeature. The dependency reading is
|
|
70
|
+
* the one phase 1 draws, and it is the one recorded.
|
|
71
|
+
*/
|
|
72
|
+
export const UML_KEYWORD_PLACEMENT = {
|
|
73
|
+
interface: 'box header',
|
|
74
|
+
enumeration: 'box header',
|
|
75
|
+
dataType: 'box header',
|
|
76
|
+
use: 'dashed-line label',
|
|
77
|
+
create: 'dashed-line label',
|
|
78
|
+
call: 'dashed-line label',
|
|
79
|
+
import: 'dashed-line label',
|
|
80
|
+
access: 'dashed-line label',
|
|
81
|
+
merge: 'dashed-line label',
|
|
82
|
+
include: 'dashed-line label',
|
|
83
|
+
extend: 'dashed-line label',
|
|
84
|
+
// Not Annex C: the `{abstract}` modifier of §9.2.4. See the docblock.
|
|
85
|
+
abstract: 'after name',
|
|
86
|
+
// ── Appended by phase 2 (components and deployments) ──────────────────
|
|
87
|
+
// Table C.1, all six, with the placements it gives them:
|
|
88
|
+
// - `component`, `artifact`, `device` and `executionEnvironment` are **box
|
|
89
|
+
// header** keywords — the word written above the name of the rectangle or
|
|
90
|
+
// the cube, which is what makes one cube a Device and the next a plain Node
|
|
91
|
+
// (§19.4.4). `component` is the one of the four an author may drop: §11.6.4
|
|
92
|
+
// lets the corner ICON stand in for the keyword, and this pack draws the
|
|
93
|
+
// icon — so the seed does not write it, and the parser still reads it off a
|
|
94
|
+
// component pasted in from a tool that does;
|
|
95
|
+
// - `deploy` and `manifest` are **dashed-line labels**, the keyword being the
|
|
96
|
+
// only thing on the picture that says which dependency a dashed arrow is
|
|
97
|
+
// (§19.2.4, §19.3.4).
|
|
98
|
+
component: 'box header',
|
|
99
|
+
artifact: 'box header',
|
|
100
|
+
device: 'box header',
|
|
101
|
+
executionEnvironment: 'box header',
|
|
102
|
+
deploy: 'dashed-line label',
|
|
103
|
+
manifest: 'dashed-line label',
|
|
104
|
+
};
|
|
105
|
+
/* ── What a fresh artefact says ───────────────────────────────────────── */
|
|
106
|
+
/**
|
|
107
|
+
* The text a node arrives with in its NAME compartment, per kind.
|
|
108
|
+
*
|
|
109
|
+
* Every seed is a true statement about the box that carries it — which is the
|
|
110
|
+
* rule the C4 pack settled on and the reason its title seed is `Container`
|
|
111
|
+
* rather than a bracketed prompt: an unnamed class IS a class, and exporting
|
|
112
|
+
* `Class` says something, where exporting an invented placeholder would say
|
|
113
|
+
* something false. So a diagram the author has not typed on yet still exports,
|
|
114
|
+
* still round-trips, and still reads.
|
|
115
|
+
*
|
|
116
|
+
* Three of them carry more than a word, and each is the notation asking for it:
|
|
117
|
+
*
|
|
118
|
+
* - `interface` and `enumeration` open with their Annex C keyword above the
|
|
119
|
+
* name — that keyword is what distinguishes the metaclass, so a fresh
|
|
120
|
+
* interface that did not carry it would be a class;
|
|
121
|
+
* - `object` seeds `object : Class`, the underlined `name : Type` of §11.6. The
|
|
122
|
+
* UNDERLINE is drawn by the renderer and is not in the text: it is notation,
|
|
123
|
+
* not a character, and an author who retyped the line would otherwise have to
|
|
124
|
+
* reproduce it.
|
|
125
|
+
*
|
|
126
|
+
* ## The empty ones
|
|
127
|
+
*
|
|
128
|
+
* Thirteen kinds seed the EMPTY STRING, and that is a statement rather than a
|
|
129
|
+
* gap: the control nodes of §15.3.4 and the pseudostates of §14.2.4 are marks
|
|
130
|
+
* with no words in them — a disc, a bar, a bullseye, a cross — so the true
|
|
131
|
+
* statement about them is silence. {@link UML_UNLABELLED_KINDS} is that fact as
|
|
132
|
+
* a set, and it is what the creation site and the audit both read.
|
|
133
|
+
*/
|
|
134
|
+
export const UML_NAME_SEED = {
|
|
135
|
+
class: 'Class',
|
|
136
|
+
interface: `${guillemets('interface')}\nInterface`,
|
|
137
|
+
enumeration: `${guillemets('enumeration')}\nEnumeration`,
|
|
138
|
+
object: 'object : Class',
|
|
139
|
+
package: 'Package',
|
|
140
|
+
note: 'Note',
|
|
141
|
+
actor: 'Actor',
|
|
142
|
+
'use-case': 'Use case',
|
|
143
|
+
// ── Phase 2 ──────────────────────────────────────────────────────────────
|
|
144
|
+
// A component carries NO keyword: §11.6.4 offers the corner icon or the word
|
|
145
|
+
// `«component»`, and this pack draws the icon, so writing both would say the
|
|
146
|
+
// same thing twice on one box.
|
|
147
|
+
component: 'Component',
|
|
148
|
+
// Lower case, and that is §11.3.4: a port is named like the property it is —
|
|
149
|
+
// `port`, not `Port` — and the name is written BESIDE the little square,
|
|
150
|
+
// which is the only place it fits.
|
|
151
|
+
port: 'port',
|
|
152
|
+
// §10.4.4 names an interface point after the interface it stands for, and the
|
|
153
|
+
// `I` prefix is what every tool and every architect writes. Two different
|
|
154
|
+
// seeds because the two glyphs make two different statements: one offers a
|
|
155
|
+
// service, the other needs one.
|
|
156
|
+
'provided-interface': 'IProvided',
|
|
157
|
+
'required-interface': 'IRequired',
|
|
158
|
+
// §19.3.4: an artifact is a FILE, so its seed is a file name — the keyword
|
|
159
|
+
// above it is what the notation puts there, and the extension is what tells a
|
|
160
|
+
// reader this box is a deployable thing rather than a design one.
|
|
161
|
+
artifact: `${guillemets('artifact')}\nartifact.jar`,
|
|
162
|
+
// §19.4.4 names deployment targets as INSTANCES — `:AppServer`, the colon
|
|
163
|
+
// saying "an unnamed instance of". The cubes are the one place in the pack
|
|
164
|
+
// that convention applies, and a seed that read `Node` would teach the wrong
|
|
165
|
+
// one.
|
|
166
|
+
node: ':Node',
|
|
167
|
+
device: `${guillemets('device')}\n:Device`,
|
|
168
|
+
'execution-environment': `${guillemets('executionEnvironment')}\n:Runtime`,
|
|
169
|
+
// ── Phase 2, the behaviour artefacts ─────────────────────────────────────
|
|
170
|
+
// §15.3.4 names an action with a VERB PHRASE, so the seed is the noun the
|
|
171
|
+
// library uses everywhere for "a thing that happens" — true of the box that
|
|
172
|
+
// carries it, and replaced by the author's own verb the moment they type.
|
|
173
|
+
action: 'Action',
|
|
174
|
+
// §15.4.4: an object node is named after the VALUE that flows through it, and
|
|
175
|
+
// may carry a `[state]` in brackets after it. The seed is the noun alone —
|
|
176
|
+
// the bracket is grammar the author reaches for, not a placeholder to delete.
|
|
177
|
+
'object-node': 'Object',
|
|
178
|
+
// §16.3.4: the pentagons are named after the signal sent and the event
|
|
179
|
+
// awaited. Two different words, because they are two different statements.
|
|
180
|
+
'send-signal': 'Signal',
|
|
181
|
+
'accept-event': 'Event',
|
|
182
|
+
// §16.10.4: a time event is written as a time EXPRESSION, and `after (…)` is
|
|
183
|
+
// the form the specification's own figures use. The ellipsis is part of the
|
|
184
|
+
// grammar being shown, not a prompt: an author replaces what is inside the
|
|
185
|
+
// brackets and the sentence stays a sentence.
|
|
186
|
+
'time-event': 'after (…)',
|
|
187
|
+
// §14.2.4: a state is named after the CONDITION that holds while the machine
|
|
188
|
+
// is in it. Same argument as `action`, and the same word the role uses.
|
|
189
|
+
state: 'State',
|
|
190
|
+
// ── Phase 3, the sequence diagram ────────────────────────────────────────
|
|
191
|
+
// §17.3.4 writes a lifeline's head as `<name> [: <Type>]` — the participant's
|
|
192
|
+
// own name, then the classifier it is an instance of. The seed is the
|
|
193
|
+
// OBJECT's, word for word, and that is the specification's doing rather than
|
|
194
|
+
// a copy: a lifeline IS an instance of a classifier taking part in an
|
|
195
|
+
// interaction, and §9.8.4's `object : Class` is the same grammar. An author
|
|
196
|
+
// who has met one has met the other, and `parseLifelineIdent` reads exactly
|
|
197
|
+
// this line back.
|
|
198
|
+
//
|
|
199
|
+
// NOT underlined, unlike §9.8.4's instance specification: §17.3.4 draws the
|
|
200
|
+
// head plain, and a rule that underlined it would be this pack applying one
|
|
201
|
+
// clause's notation to another's.
|
|
202
|
+
lifeline: 'lifeline : Class',
|
|
203
|
+
// ── The unlabelled ones ─────────────────────────────────────────────────
|
|
204
|
+
// Thirteen empty strings, and every one of them is the notation's own answer:
|
|
205
|
+
// §15.3.4 and §14.2.4 draw these as MARKS, not as boxes with words in them.
|
|
206
|
+
// A disc has no name, a bar has no name, a bullseye has no name — and the one
|
|
207
|
+
// thing that would be wrong here is a seed, because a seed is text the author
|
|
208
|
+
// then has to find and delete off a 24-unit dot.
|
|
209
|
+
//
|
|
210
|
+
// {@link UML_UNLABELLED_KINDS} is the list stated as a set, so a creation site
|
|
211
|
+
// can ask the question instead of testing a string for emptiness.
|
|
212
|
+
initial: '',
|
|
213
|
+
'activity-final': '',
|
|
214
|
+
'flow-final': '',
|
|
215
|
+
decision: '',
|
|
216
|
+
fork: '',
|
|
217
|
+
'final-state': '',
|
|
218
|
+
choice: '',
|
|
219
|
+
junction: '',
|
|
220
|
+
'shallow-history': '',
|
|
221
|
+
'deep-history': '',
|
|
222
|
+
'entry-point': '',
|
|
223
|
+
'exit-point': '',
|
|
224
|
+
terminate: '',
|
|
225
|
+
// …and phase 3 adds two more, for the same reason and out of the same clause:
|
|
226
|
+
// §17.2.4 draws an ExecutionSpecification as a thin BAR on a lifeline's spine
|
|
227
|
+
// and a DestructionOccurrence as a CROSS on it. Neither is named — what the
|
|
228
|
+
// reader learns from them is "this participant is busy here" and "this
|
|
229
|
+
// participant ends here", and both facts are the mark's position on the
|
|
230
|
+
// spine. A seed under either would be a word to delete off a 12-unit bar.
|
|
231
|
+
execution: '',
|
|
232
|
+
destruction: '',
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* The kinds a fresh artefact arrives with NO label text at all.
|
|
236
|
+
*
|
|
237
|
+
* Derived from {@link UML_NAME_SEED} rather than listed beside it, because the
|
|
238
|
+
* two would otherwise be one fact written twice: a kind whose seed is empty IS
|
|
239
|
+
* a kind with nothing to write, and a hand-kept list is how one of them comes to
|
|
240
|
+
* say otherwise.
|
|
241
|
+
*
|
|
242
|
+
* ## What a caller does with it
|
|
243
|
+
*
|
|
244
|
+
* The creation site (`actions.ts`) reads it to decide whether to write a `text`
|
|
245
|
+
* element into the group at all — a control node or a pseudostate is the SHAPE
|
|
246
|
+
* and nothing else, and a group holding a 24-unit disc and an empty text box is
|
|
247
|
+
* a group with an invisible member an author can select by accident.
|
|
248
|
+
*
|
|
249
|
+
* The audit reads it too, and that is the more important half: a `label-presence`
|
|
250
|
+
* rule fires on an artefact that should be named and is not, and firing it on
|
|
251
|
+
* every decision diamond on the sheet would be the audit reporting the notation
|
|
252
|
+
* as a defect (`rules.ts`, `uml.unnamed-action` / `uml.unnamed-state`, whose
|
|
253
|
+
* `appliesTo` is the complement of this set).
|
|
254
|
+
*/
|
|
255
|
+
export const UML_UNLABELLED_KINDS = new Set(Object.keys(UML_NAME_SEED).filter(kind => UML_NAME_SEED[kind] === ''));
|
|
256
|
+
/**
|
|
257
|
+
* The i18n key {@link UML_NAME_SEED} is the English default of — the same
|
|
258
|
+
* derivation BPMN's and C4's `nodeLabelKey` are, one package over: resolved AT
|
|
259
|
+
* PLACEMENT (`createUmlNode`, `createUmlClassifier`) and never afterwards,
|
|
260
|
+
* since what a gesture writes into the document is content the author owns
|
|
261
|
+
* from that moment on, and a renderer that re-translated it on every paint
|
|
262
|
+
* would silently overwrite a name somebody typed.
|
|
263
|
+
*
|
|
264
|
+
* The kinds seeded with nothing ({@link UML_UNLABELLED_KINDS}) ask for no key:
|
|
265
|
+
* there is no word to translate, and the notation draws them as marks.
|
|
266
|
+
*/
|
|
267
|
+
export const umlSeedKey = (kind) => `com.labre.uml.seed.${kind}`;
|
|
268
|
+
/**
|
|
269
|
+
* The attribute compartment of a fresh classifier — one property in the §9.5.4
|
|
270
|
+
* syntax the parser reads back.
|
|
271
|
+
*
|
|
272
|
+
* A worked example rather than a prompt: it parses, it exports, and an author
|
|
273
|
+
* editing it has the grammar in front of them instead of in a manual.
|
|
274
|
+
*/
|
|
275
|
+
export const UML_ATTRIBUTES_SEED = '+ attribute : Type';
|
|
276
|
+
/** The key the line above is the English default of, resolved at placement. */
|
|
277
|
+
export const UML_ATTRIBUTES_SEED_KEY = 'com.labre.uml.seed.attributes';
|
|
278
|
+
/** The operation compartment of a fresh classifier — §9.6.4, same argument. */
|
|
279
|
+
export const UML_OPERATIONS_SEED = '+ operation() : Type';
|
|
280
|
+
/** Its own key, resolved at placement like the one above. */
|
|
281
|
+
export const UML_OPERATIONS_SEED_KEY = 'com.labre.uml.seed.operations';
|
|
282
|
+
/**
|
|
283
|
+
* The one written tier of a fresh object — a SLOT, not a property.
|
|
284
|
+
*
|
|
285
|
+
* An InstanceSpecification's compartment holds `name = value` (§11.6.4): no
|
|
286
|
+
* visibility, no type, no multiplicity, because an instance does not redeclare
|
|
287
|
+
* its classifier's features, it gives them values.
|
|
288
|
+
*/
|
|
289
|
+
export const UML_SLOTS_SEED = 'attribute = value';
|
|
290
|
+
/** Its own key, resolved at placement like the two above. */
|
|
291
|
+
export const UML_SLOTS_SEED_KEY = 'com.labre.uml.seed.slots';
|
|
292
|
+
/**
|
|
293
|
+
* Both spellings of a guillemet pair — the real characters and the ASCII
|
|
294
|
+
* fallback Annex C's note tolerates.
|
|
295
|
+
*
|
|
296
|
+
* Reading both is not symmetry for its own sake: `<<interface>>` is what every
|
|
297
|
+
* tool that predates a unicode-safe pipeline writes, and a class pasted in from
|
|
298
|
+
* one would otherwise export as a class named `<<interface>> Foo`.
|
|
299
|
+
*/
|
|
300
|
+
const GUILLEMET_GROUP = /«([^»]*)»|<<([^>]*)>>/g;
|
|
301
|
+
/** `{abstract}`, with whatever spacing and case the author used (§9.2.4). */
|
|
302
|
+
const ABSTRACT_MARKER = /\{\s*abstract\s*\}/i;
|
|
303
|
+
/**
|
|
304
|
+
* A name compartment, split into what the notation says and what the author
|
|
305
|
+
* named the thing.
|
|
306
|
+
*
|
|
307
|
+
* ## Why this is one function and not three
|
|
308
|
+
*
|
|
309
|
+
* The three facts live in the same string and are read by the same pass: a
|
|
310
|
+
* classifier's header box is `«keyword»` lines, then the name, with `{abstract}`
|
|
311
|
+
* anywhere on it. Reading them separately would mean three scans that can
|
|
312
|
+
* disagree about where the name starts.
|
|
313
|
+
*
|
|
314
|
+
* ## Guillemets above the name, and beside it
|
|
315
|
+
*
|
|
316
|
+
* §9.2.4 draws the keyword on its own line above the name, which is what the
|
|
317
|
+
* seeds write. Tools routinely write it INLINE — `«interface» Payable` — and
|
|
318
|
+
* both are accepted here: a group is lifted out wherever it appears, and a line
|
|
319
|
+
* that held nothing else disappears with it. What is left, in order, is the
|
|
320
|
+
* name. Nothing is re-ordered and nothing is folded: a two-line name stays two
|
|
321
|
+
* lines, because a name compartment that wraps is a name that wraps.
|
|
322
|
+
*
|
|
323
|
+
* A compartment with no guillemets and no marker comes back as
|
|
324
|
+
* `{ keywords: [], name: <the text>, isAbstract: false }` — the common case, and
|
|
325
|
+
* it costs the caller no special handling.
|
|
326
|
+
*/
|
|
327
|
+
export function stereotypesOf(text) {
|
|
328
|
+
const raw = text === null || text === undefined ? '' : String(text);
|
|
329
|
+
const keywords = [];
|
|
330
|
+
const kept = [];
|
|
331
|
+
for (const line of raw.split('\n')) {
|
|
332
|
+
const remainder = line
|
|
333
|
+
.replaceAll(GUILLEMET_GROUP, (_match, spelled, ascii) => {
|
|
334
|
+
const labels = String(spelled ?? ascii ?? '');
|
|
335
|
+
for (const label of labels.split(',')) {
|
|
336
|
+
const trimmed = label.trim();
|
|
337
|
+
if (trimmed)
|
|
338
|
+
keywords.push(trimmed);
|
|
339
|
+
}
|
|
340
|
+
return ' ';
|
|
341
|
+
})
|
|
342
|
+
.trim();
|
|
343
|
+
// A line that held keywords ALONE is notation, not a name: dropping it is
|
|
344
|
+
// what makes `«interface»\nInterface` read as the interface `Interface`.
|
|
345
|
+
if (remainder)
|
|
346
|
+
kept.push(remainder);
|
|
347
|
+
}
|
|
348
|
+
let name = kept.join('\n');
|
|
349
|
+
const isAbstract = ABSTRACT_MARKER.test(name);
|
|
350
|
+
if (isAbstract)
|
|
351
|
+
name = name.replace(ABSTRACT_MARKER, ' ');
|
|
352
|
+
return {
|
|
353
|
+
keywords,
|
|
354
|
+
name: name
|
|
355
|
+
.split('\n')
|
|
356
|
+
.map(line => line.replaceAll(/\s+/g, ' ').trim())
|
|
357
|
+
.filter(line => line.length > 0)
|
|
358
|
+
.join('\n'),
|
|
359
|
+
isAbstract,
|
|
360
|
+
};
|
|
361
|
+
}
|
package/dist/kinds.d.ts
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { UmlDiagramKind } from '@formicoidea/labre-core/model';
|
|
2
|
+
/**
|
|
3
|
+
* The combined fragment's OPERATOR picker, re-exported.
|
|
4
|
+
*
|
|
5
|
+
* It lives in `operators.ts` — a fragment's operator is a different field on a
|
|
6
|
+
* different element, and thirteen entries beside the diagram kinds would make
|
|
7
|
+
* this file two tables under one name. It is re-exported here all the same,
|
|
8
|
+
* because a reader looking for "the pickers this framework declares" looks
|
|
9
|
+
* first at the file named after one of them, and because both spellings were
|
|
10
|
+
* already in use by the time the second picker landed.
|
|
11
|
+
*/
|
|
12
|
+
export { UML_FRAGMENT_OPERATOR_MENU, type UmlFragmentOperatorOption, } from './operators.js';
|
|
13
|
+
/**
|
|
14
|
+
* The KIND a diagram frame declares, as the picker offers it — DATA, like
|
|
15
|
+
* everything else this framework contributes.
|
|
16
|
+
*
|
|
17
|
+
* A UML diagram is one kind of diagram, and Annex A writes which in the frame's
|
|
18
|
+
* own heading: `class Orders`, `uc Checkout`. So the kind is not a label on the
|
|
19
|
+
* side of the sheet the way a C4 board's level is — it is HALF THE HEADING, and
|
|
20
|
+
* picking one changes what the frame says about itself.
|
|
21
|
+
*
|
|
22
|
+
* ## The name stays the author's
|
|
23
|
+
*
|
|
24
|
+
* Choosing a kind RENAMES NOTHING. The heading is derived
|
|
25
|
+
* (`UmlDiagramElementModel.heading`) from the kind and the name together, and
|
|
26
|
+
* the picker writes one field: a use case diagram of the checkout flow is still
|
|
27
|
+
* called whatever its author called it, and the tag simply reads `uc` in front
|
|
28
|
+
* of it.
|
|
29
|
+
*
|
|
30
|
+
* ## Why there is no "none", unlike C4's Free sketch
|
|
31
|
+
*
|
|
32
|
+
* A C4 board's level is a CLAIM about the model that an author may decline to
|
|
33
|
+
* make, so its absence means "a working surface". A UML frame's kind is part of
|
|
34
|
+
* its NOTATION: Annex A's heading is `<kind> <name>`, and a frame with no kind
|
|
35
|
+
* has no heading to draw. The model makes it required with `class` as the
|
|
36
|
+
* default — the diagram an architect reaches for first, and the one kind Annex A
|
|
37
|
+
* gives no abbreviation for — so every option here writes a value and none of
|
|
38
|
+
* them clears the field.
|
|
39
|
+
*
|
|
40
|
+
* ## Eight now, more later, and nothing to migrate
|
|
41
|
+
*
|
|
42
|
+
* Phase 1 offered four structural diagrams; phase 2 appended `cmp` and `dep`,
|
|
43
|
+
* then the two behaviour frames `act` and `stm`; phase 3 appends `sd`. Each arrives as a new
|
|
44
|
+
* option over a new VALUE of the same string field (ADR 0017). A frame carrying
|
|
45
|
+
* a kind this
|
|
46
|
+
* build has never heard of still paints its own heading, verbatim — see
|
|
47
|
+
* {@link UmlDiagramElementModel.heading} — and the picker below simply shows no
|
|
48
|
+
* current option rather than silently rewriting it to `class`.
|
|
49
|
+
*/
|
|
50
|
+
export interface UmlDiagramKindOption {
|
|
51
|
+
/** What gets written on the frame. Never `undefined`: see the header. */
|
|
52
|
+
kind: UmlDiagramKind;
|
|
53
|
+
/** i18n key of the entry's words; resolved by the host. */
|
|
54
|
+
labelKey: string;
|
|
55
|
+
/** The framework's own wording, for a host that ships no catalogue. */
|
|
56
|
+
labelFallback: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The picker, whole: its own heading and its entries, in the order UML itself
|
|
60
|
+
* teaches them — the classifiers first, then what groups them, then their
|
|
61
|
+
* instances, then what the system is for, then what it is built of and where it
|
|
62
|
+
* runs.
|
|
63
|
+
*
|
|
64
|
+
* One object rather than a loose array plus a stray heading constant, because
|
|
65
|
+
* the manifest walks DECLARATIONS: `umlTranslationEntries` hands this value to
|
|
66
|
+
* `collectTranslationKeys` and every key below reaches a host's catalogue with
|
|
67
|
+
* nothing restated anywhere.
|
|
68
|
+
*/
|
|
69
|
+
export declare const UML_DIAGRAM_KIND_MENU: {
|
|
70
|
+
labelKey: string;
|
|
71
|
+
labelFallback: string;
|
|
72
|
+
options: readonly UmlDiagramKindOption[];
|
|
73
|
+
};
|