@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.
Files changed (114) hide show
  1. package/LICENSE +384 -0
  2. package/dist/actions.d.ts +430 -0
  3. package/dist/actions.js +724 -0
  4. package/dist/background.d.ts +153 -0
  5. package/dist/background.js +557 -0
  6. package/dist/board-hit.d.ts +137 -0
  7. package/dist/board-hit.js +191 -0
  8. package/dist/commands-manifest.d.ts +19 -0
  9. package/dist/commands-manifest.js +571 -0
  10. package/dist/commands.d.ts +4 -0
  11. package/dist/commands.js +983 -0
  12. package/dist/component.d.ts +521 -0
  13. package/dist/component.js +708 -0
  14. package/dist/consts.d.ts +365 -0
  15. package/dist/consts.js +463 -0
  16. package/dist/descriptor.d.ts +12 -0
  17. package/dist/descriptor.js +10 -0
  18. package/dist/drawio-decode.d.ts +32 -0
  19. package/dist/drawio-decode.js +96 -0
  20. package/dist/drawio-import.d.ts +133 -0
  21. package/dist/drawio-import.js +885 -0
  22. package/dist/edge-morph.d.ts +154 -0
  23. package/dist/edge-morph.js +153 -0
  24. package/dist/edge-styles.d.ts +78 -0
  25. package/dist/edge-styles.js +210 -0
  26. package/dist/effects.d.ts +9 -0
  27. package/dist/effects.js +6 -0
  28. package/dist/element-renderer.d.ts +64 -0
  29. package/dist/element-renderer.js +114 -0
  30. package/dist/element-view.d.ts +234 -0
  31. package/dist/element-view.js +430 -0
  32. package/dist/export.d.ts +61 -0
  33. package/dist/export.js +41 -0
  34. package/dist/filename.d.ts +17 -0
  35. package/dist/filename.js +26 -0
  36. package/dist/frame-tag.d.ts +70 -0
  37. package/dist/frame-tag.js +78 -0
  38. package/dist/grammar.d.ts +695 -0
  39. package/dist/grammar.js +1436 -0
  40. package/dist/import.d.ts +306 -0
  41. package/dist/import.js +1270 -0
  42. package/dist/index.d.ts +47 -0
  43. package/dist/index.js +67 -0
  44. package/dist/interchange.d.ts +125 -0
  45. package/dist/interchange.js +372 -0
  46. package/dist/keywords.d.ts +204 -0
  47. package/dist/keywords.js +361 -0
  48. package/dist/kinds.d.ts +73 -0
  49. package/dist/kinds.js +91 -0
  50. package/dist/legend.d.ts +30 -0
  51. package/dist/legend.js +255 -0
  52. package/dist/model.d.ts +862 -0
  53. package/dist/model.js +1316 -0
  54. package/dist/morph.d.ts +178 -0
  55. package/dist/morph.js +496 -0
  56. package/dist/node/act-glyphs.d.ts +30 -0
  57. package/dist/node/act-glyphs.js +142 -0
  58. package/dist/node/compartment-watcher.d.ts +107 -0
  59. package/dist/node/compartment-watcher.js +163 -0
  60. package/dist/node/fit.d.ts +85 -0
  61. package/dist/node/fit.js +129 -0
  62. package/dist/node/node-renderer.d.ts +49 -0
  63. package/dist/node/node-renderer.js +611 -0
  64. package/dist/node/node-view.d.ts +51 -0
  65. package/dist/node/node-view.js +89 -0
  66. package/dist/node/paint.d.ts +84 -0
  67. package/dist/node/paint.js +143 -0
  68. package/dist/node/sd-glyphs.d.ts +36 -0
  69. package/dist/node/sd-glyphs.js +79 -0
  70. package/dist/node/stm-glyphs.d.ts +22 -0
  71. package/dist/node/stm-glyphs.js +111 -0
  72. package/dist/node/tier-metrics.d.ts +38 -0
  73. package/dist/node/tier-metrics.js +45 -0
  74. package/dist/operators.d.ts +45 -0
  75. package/dist/operators.js +75 -0
  76. package/dist/plantuml-import.d.ts +113 -0
  77. package/dist/plantuml-import.js +1723 -0
  78. package/dist/plantuml.d.ts +94 -0
  79. package/dist/plantuml.js +985 -0
  80. package/dist/presets.d.ts +149 -0
  81. package/dist/presets.js +302 -0
  82. package/dist/profiles.d.ts +2 -0
  83. package/dist/profiles.js +358 -0
  84. package/dist/reading.d.ts +160 -0
  85. package/dist/reading.js +648 -0
  86. package/dist/roles.d.ts +257 -0
  87. package/dist/roles.js +997 -0
  88. package/dist/rules.d.ts +267 -0
  89. package/dist/rules.js +3090 -0
  90. package/dist/templates.d.ts +2 -0
  91. package/dist/templates.js +197 -0
  92. package/dist/toolbar/config.d.ts +228 -0
  93. package/dist/toolbar/config.js +833 -0
  94. package/dist/toolbar/icons.d.ts +440 -0
  95. package/dist/toolbar/icons.js +711 -0
  96. package/dist/toolbar/senior-tool.d.ts +11 -0
  97. package/dist/toolbar/senior-tool.js +21 -0
  98. package/dist/toolbar/uml-menu.d.ts +17 -0
  99. package/dist/toolbar/uml-menu.js +20 -0
  100. package/dist/toolbar/uml-senior-button.d.ts +18 -0
  101. package/dist/toolbar/uml-senior-button.js +22 -0
  102. package/dist/translations.d.ts +27 -0
  103. package/dist/translations.js +117 -0
  104. package/dist/view.d.ts +33 -0
  105. package/dist/view.js +236 -0
  106. package/dist/xmi-import.d.ts +174 -0
  107. package/dist/xmi-import.js +2268 -0
  108. package/dist/xmi.d.ts +61 -0
  109. package/dist/xmi.js +1860 -0
  110. package/dist/xml-reader.d.ts +157 -0
  111. package/dist/xml-reader.js +430 -0
  112. package/dist/xml.d.ts +72 -0
  113. package/dist/xml.js +96 -0
  114. 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;
@@ -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
+ }
@@ -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
+ };