@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,306 @@
1
+ import type { InterchangeNote, SerializedElementProps } from '@formicoidea/labre-core/blocks/surface';
2
+ import { type UmlBox } from './component.js';
3
+ import { type UmlModel, type UmlNodeBase, type UmlRelation, type UmlRelationKind } from './model.js';
4
+ /**
5
+ * The **one materializer** every UML importer ends on — a model in, the
6
+ * serialized props of a board out (`docs/adr/0012`, P3).
7
+ *
8
+ * ## Why the pipeline forks at the PARSER and nowhere else
9
+ *
10
+ * Three formats read UML into Labre — PlantUML, XMI 2.5.1 and draw.io — and the
11
+ * only thing they disagree about is how a file spells a class. What a class IS
12
+ * on this canvas is five elements written in painting order, with three seeded
13
+ * compartments, one role per tier and a group over them (`actions.ts`), and that
14
+ * answer belongs to the pack rather than to any file format. Written three
15
+ * times it would be wrong in three different ways, and a class imported from a
16
+ * `.drawio` would not be the class the toolbox draws.
17
+ *
18
+ * So each parser produces a {@link UmlModel} — the same IR the two WRITERS
19
+ * already take — and this file turns it into elements. The pivot is the phase-1
20
+ * model and not a shape of its own, which is what makes the round trip
21
+ * checkable: read our own export, materialize it, read the board back with
22
+ * `umlModelFrom`, and the model is the one we started with.
23
+ *
24
+ * ## Never a size, never a colour, never a seed
25
+ *
26
+ * Every prop below comes out of {@link umlNodeProps}, {@link umlTextProps} and
27
+ * {@link umlCompartmentBoxes} — the very three functions the creation site calls
28
+ * (R17). Not one measurement is restated here, so an imported class and a drawn
29
+ * one are the same element down to the stroke width, and a restyle that moves
30
+ * the pack moves the import with it.
31
+ *
32
+ * ## The two names an element carries, and they are not the same name
33
+ *
34
+ * - `interchange[formatId].id` is the SOURCE file's id, verbatim: D3's fixed
35
+ * point, what an export prefers back, and what a support thread quotes.
36
+ * - `id` is this reader's OWN provisional name — `uml-import-<n>`, minted in
37
+ * document order. `surface.addElement` overwrites it with a nanoid and is
38
+ * documented to, so it reaches no document: it exists so that a connector can
39
+ * say which shape it runs to and a group can say which tiers it holds, before
40
+ * the surface has minted an id for either. `materializeInterchangeImport`
41
+ * resolves both.
42
+ *
43
+ * A source id is NOT usable for the second job: a tier and a group are elements
44
+ * Labre mints and no file ever named, two sheets may spell one class the same
45
+ * way, and PlantUML's own identifiers are aliases rather than ids. Minting is
46
+ * the only answer that is always available and always unique.
47
+ *
48
+ * ## Layout (D4)
49
+ *
50
+ * Geometry when the source carried some — `opts.layout.boxes` for a format that
51
+ * reads coordinates out of the file (draw.io's `mxGeometry`, XMI's `umldi`), or
52
+ * the `bounds` a parser already wrote onto the IR. Otherwise a layered layout is
53
+ * INVENTED, in rows by generalization depth, and the caller says so with an
54
+ * `invented-layout` note: D4 forbids claiming a position came from a file that
55
+ * never had one.
56
+ *
57
+ * ## Pure
58
+ *
59
+ * Models in, props out. No `std`, no surface, no DOM, no clock, no randomness —
60
+ * every id and every coordinate is a function of document order alone, so the
61
+ * same file always lands the same board.
62
+ */
63
+ /**
64
+ * One cell of the layered layout — the module a diagram nobody positioned is
65
+ * measured in.
66
+ *
67
+ * Wider and shallower than a class box (200 × 120) on purpose: the gap has to
68
+ * leave room for the name of the relationship drawn across it, and a row of
69
+ * boxes packed edge to edge reads as one band rather than as five classifiers.
70
+ */
71
+ export declare const UML_IMPORT_SLOT: {
72
+ readonly w: 240;
73
+ readonly h: 140;
74
+ };
75
+ /** The space between two slots, in both directions. */
76
+ export declare const UML_IMPORT_GUTTER = 60;
77
+ /** The margin between the drawing and the frame drawn round it. */
78
+ export declare const UML_IMPORT_MARGIN = 60;
79
+ /**
80
+ * The distance between two lifeline SPINES on a sheet nobody positioned.
81
+ *
82
+ * Wide enough that a 160-unit head has 40 units of air on either side of it, and
83
+ * that a message label written over the gap is legible. It is also comfortably
84
+ * more than twice {@link UML_SPINE_TOLERANCE}, which is what stops a bar dropped
85
+ * on one spine from being claimed by its neighbour.
86
+ */
87
+ export declare const UML_SD_COLUMN_GAP = 200;
88
+ /**
89
+ * The height of ONE SLOT — the vertical distance between two consecutive things
90
+ * that happen.
91
+ *
92
+ * A slot per EVENT and not per message, and that is the whole trick of the
93
+ * sequence importers: a `.puml` and an XMI fragment list state an ORDER and no
94
+ * heights, the canvas states heights and no order, and `model.ts` reads the
95
+ * order back off the heights. Giving every event — an arrow, the start of a bar,
96
+ * the end of one, an `alt`, an `else`, an `end` — a slot of its own is what makes
97
+ * that round trip exact: no two events tie, so nothing can come back reordered.
98
+ */
99
+ export declare const UML_SD_EVENT_STEP = 40;
100
+ /** Where the first event sits: one slot below the bottom of the heads. */
101
+ export declare const UML_SD_FIRST_EVENT: number;
102
+ /** How far outside the spines it covers a combined fragment is drawn. */
103
+ export declare const UML_SD_FRAGMENT_PADDING = 20;
104
+ /** The height of the nth slot of an invented sequence layout. */
105
+ export declare function umlSequenceSlot(index: number): number;
106
+ /**
107
+ * The COLUMN box of the nth lifeline — the narrow tall element, not the head.
108
+ *
109
+ * `UmlNodeElementModel` makes a lifeline the spine and paints the head across
110
+ * the top of it, so what is laid out here is the spine: its centre is the line
111
+ * the conversation is measured against, and the head overflows it on both sides
112
+ * by the same amount.
113
+ */
114
+ export declare function umlSequenceColumn(index: number, height: number): UmlBox;
115
+ /** The bar §17.2.4 draws on a spine between two occurrences. */
116
+ export declare function umlSequenceExecution(column: UmlBox, y0: number, y1: number): UmlBox;
117
+ /** The cross §17.2.4 ends a lifeline with, centred on the spine. */
118
+ export declare function umlSequenceDestruction(column: UmlBox, y: number): UmlBox;
119
+ /**
120
+ * The rectangle §17.6.4 draws round the spines a fragment covers.
121
+ *
122
+ * {@link UML_SD_FRAGMENT_PADDING} outside the outermost two, which is what makes
123
+ * the box cover the spines rather than end on them — `model.ts` reads coverage
124
+ * as "the spine runs through the box", and a rectangle whose edge lands exactly
125
+ * on a spine is a coin toss.
126
+ */
127
+ export declare function umlSequenceFragment(columns: readonly UmlBox[], y0: number, y1: number): UmlBox;
128
+ /** What one artefact asks the layout for. */
129
+ export interface UmlLayoutNode {
130
+ id: string;
131
+ /** Its own footprint, before anything it contains is measured. */
132
+ size: {
133
+ w: number;
134
+ h: number;
135
+ };
136
+ /** What is drawn INSIDE it, in document order. Containers only. */
137
+ children?: readonly string[];
138
+ }
139
+ /**
140
+ * A layered layout for a diagram that carried no geometry (D4).
141
+ *
142
+ * ## Rows by generalization depth
143
+ *
144
+ * Because that is the one ordering a class diagram has of its own: §9.2.4 draws
145
+ * the general classifier above the specific one, so a hierarchy read top to
146
+ * bottom is a hierarchy drawn top to bottom, and a sheet laid out this way is
147
+ * legible the moment it opens instead of being a grid somebody has to untangle.
148
+ * A classifier that specializes nothing is a root and sits in the first row;
149
+ * everything else sits one row below the deepest thing it specializes.
150
+ *
151
+ * Containers are laid out RECURSIVELY and sized to fit, because containment on
152
+ * this canvas IS geometry: a class is in a package when it is drawn inside it
153
+ * (`model.ts`, `plantuml.ts`, `xmi.ts` all read it that way), so a layout that
154
+ * placed a package's contents outside it would lose the nesting the file stated.
155
+ *
156
+ * Deterministic by construction: document order within a row, document order
157
+ * inside a container, and no measurement that depends on anything but the sizes
158
+ * handed in.
159
+ */
160
+ export declare function umlInventLayout(nodes: readonly UmlLayoutNode[], relations?: readonly UmlRelation[]): Map<string, UmlBox>;
161
+ /**
162
+ * A name compartment, written back the way the grammar reads it.
163
+ *
164
+ * The exact inverse of `stereotypesOf`: the Annex C keywords on their own line
165
+ * above the name — which is where §9.2.4 draws them and what the stencils seed —
166
+ * and §9.2.4's `{abstract}` modifier after it, which is the alternative that
167
+ * same clause allows a canvas with no italic name compartment. Read back, the
168
+ * three facts come out exactly as they went in.
169
+ */
170
+ export declare function umlNameTierText(node: UmlNodeBase): string;
171
+ /** One line on the board: its role, its two ends and its three labels. */
172
+ export interface UmlDrawnEdge {
173
+ kind: UmlRelationKind;
174
+ sourceId: string;
175
+ targetId: string;
176
+ label?: string;
177
+ /**
178
+ * §11.5.4's adornments beside the source end, already SPELLED.
179
+ *
180
+ * A string rather than the {@link UmlAssociationEnd} record, because what the
181
+ * connector holds is a label — one line of text an author goes on to edit by
182
+ * hand. The printing is `formatEndLabel`'s, which is the same one the PlantUML
183
+ * writer uses, so an association imported from XMI and one exported to a
184
+ * `.puml` spell their ends identically.
185
+ */
186
+ sourceEnd?: string;
187
+ /** The same, beside the target end. */
188
+ targetEnd?: string;
189
+ /**
190
+ * The HEIGHT a message is drawn at (§17.4.4), for the five kinds that have
191
+ * one.
192
+ *
193
+ * Present only for a message, and it is what makes a sequence diagram
194
+ * readable at all: every other UML line is anchored at the centre of the two
195
+ * boxes it joins, and a message anchored at the centre of a 600-unit spine
196
+ * would put the whole conversation on one horizontal line. See
197
+ * {@link messageAnchors}.
198
+ */
199
+ y?: number;
200
+ }
201
+ /**
202
+ * Every line one model draws — `relations`, plus the behaviour edges that live
203
+ * on the Activity and the StateMachine.
204
+ *
205
+ * ## Why there are two places to look, and neither can be dropped
206
+ *
207
+ * `umlModelFrom` reads a canvas and fills BOTH: a transition is a relation (one
208
+ * pass over the connectors resolves every end) and it is projected onto the
209
+ * machine, where the label grammar is parsed. The PlantUML reader mirrors that.
210
+ * The XMI reader cannot: `<edge>` and `<transition>` are children of the
211
+ * Activity and the StateMachine in the file, so it fills
212
+ * {@link UmlActivity.edges} and {@link UmlStateMachine.transitions} and leaves
213
+ * `relations` for the structural arrows. A materializer that walked only
214
+ * `relations` imported every XMI activity and every state machine with ZERO
215
+ * arrows on it — the defect this function exists to close.
216
+ *
217
+ * So: walk both, and DEDUPE, because a model may legitimately hold a line in
218
+ * each. The dedupe is a count per (kind, source, target) rather than a set, so
219
+ * two parallel transitions between one pair stay two — `relations` claims the
220
+ * first, the machine's second one is drawn, and nothing is drawn twice.
221
+ *
222
+ * The labels are printed with `grammar.ts`'s own printers, which is what the
223
+ * PlantUML writer uses: a guard imported from XMI and one exported to a `.puml`
224
+ * are then spelled identically, and `parseTransition` reads back exactly what
225
+ * was written.
226
+ */
227
+ export declare function umlDrawnEdges(model: UmlModel): UmlDrawnEdge[];
228
+ /** Where a source that carried coordinates says its artefacts are drawn. */
229
+ export interface UmlLayoutHints {
230
+ /**
231
+ * Boxes by SOURCE id, in model units and in one coordinate space.
232
+ *
233
+ * Whatever the file drew, translated as a block so its top-left corner lands
234
+ * at the frame's plot origin — the caller need not do the arithmetic, only
235
+ * agree with itself about which corner is which.
236
+ */
237
+ boxes?: Readonly<Record<string, UmlBox>>;
238
+ /**
239
+ * What the file says is drawn INSIDE what — child source id → container
240
+ * source id.
241
+ *
242
+ * For a format that states containment structurally and carries no geometry:
243
+ * XMI's `packagedElement` and `ownedUseCase` are the cases, and without this
244
+ * an imported package comes back empty and every class in it beside it. Read
245
+ * only where {@link boxes} gave no box — a file that drew the nesting has
246
+ * already said where everything is. See {@link containmentOf}.
247
+ */
248
+ containment?: Readonly<Record<string, string>>;
249
+ }
250
+ export interface UmlMaterializeOptions {
251
+ /**
252
+ * The interchange format whose payload key carries the source ids (D2) —
253
+ * `'plantuml'`, `'xmi'`, `'drawio'`. The same string the capability's
254
+ * {@link InterchangeFormat} declares, because
255
+ * `materializeInterchangeImport` looks the ids back up under it.
256
+ */
257
+ formatId: string;
258
+ layout?: UmlLayoutHints;
259
+ /**
260
+ * The top-left corner the first frame is drawn at. `(0, 0)` by default.
261
+ *
262
+ * An import is a NEW board beside whatever is already there, never a merge
263
+ * (`interchange-import.ts`) — and a materializer that always started at the
264
+ * origin made two imports into one heap. The caller knows what the surface
265
+ * already holds; this is where it says so.
266
+ *
267
+ * `materializeInterchangeImport` does the same thing one layer up, for every
268
+ * framework at once and out of the surface's own bounds, so a command need not
269
+ * pass this. It is here for the callers that have no surface to ask — a
270
+ * labre-mcp tool writing a document, a test — and so that the property is
271
+ * checkable without one.
272
+ */
273
+ origin?: {
274
+ x: number;
275
+ y: number;
276
+ };
277
+ }
278
+ export interface UmlMaterializeResult {
279
+ elements: SerializedElementProps[];
280
+ /** What the materializer had to invent — D4's `invented-layout`, and only it. */
281
+ notes: InterchangeNote[];
282
+ }
283
+ /**
284
+ * The MATERIALIZER's own two remarks, as `[key, English]` pairs — raised by
285
+ * {@link umlElementsFromModel} whichever reader produced the model, which is
286
+ * why they are declared here rather than in any one reader's table.
287
+ *
288
+ * Same shape and same reasons as `UML_PLANTUML_REMARKS`
289
+ * (`plantuml-import.ts`, where the contract is written out): one entry per
290
+ * SHAPE of sentence, the `{{count}}` / `{{heading}}` holes filled at the call
291
+ * site by `InterchangeNote.messageParams`, the English kept here as the
292
+ * fallback so a report drawn with no host catalogue reads exactly as before.
293
+ */
294
+ export declare const UML_LAYOUT_REMARKS: {
295
+ readonly allInvented: readonly ["com.labre.uml.import.layout.all-invented", "This source carries no coordinates, so the {{count}} artefacts of \"{{heading}}\" were laid out by Labre, in rows by generalization depth. The positions are ours, not the file's."];
296
+ readonly someInvented: readonly ["com.labre.uml.import.layout.some-invented", "{{count}} of the artefacts of \"{{heading}}\" were drawn nowhere in the source, so Labre laid them out below the rest. Their positions are ours, not the file's."];
297
+ };
298
+ /**
299
+ * Every model as the elements of a board — one `umlDiagram` frame per model,
300
+ * the artefacts drawn on it, and the connectors between them.
301
+ *
302
+ * The frames are stacked down the canvas rather than overlaid, because a UML
303
+ * document with four diagrams in it is four sheets (ADR 0017) and two frames
304
+ * sharing a box is two diagrams neither of which can be attributed.
305
+ */
306
+ export declare function umlElementsFromModel(models: readonly UmlModel[], options: UmlMaterializeOptions): UmlMaterializeResult;