@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,154 @@
1
+ import { type MorphSpec } from '@formicoidea/labre-core/blocks/surface';
2
+ import type { RoleId } from '@formicoidea/labre-core/std/gfx';
3
+ import { type UmlEdgeRole } from './edge-styles.js';
4
+ /**
5
+ * What a UML RELATIONSHIP may become — the same dropdown as the node morph, on a
6
+ * selected connector.
7
+ *
8
+ * ## Why an edge needs this more than a node does
9
+ *
10
+ * Because an edge is the thing a modeller gets wrong most often, and redrawing
11
+ * it is the most expensive to undo. A node morph saves a box and three lines of
12
+ * words; an edge morph saves the two ENDPOINTS — which element each end is
13
+ * attached to, and where on its perimeter — and those are precisely what a
14
+ * delete-and-redraw destroys. "This is really a composition, not an
15
+ * association", discovered halfway through a class diagram, is modelling
16
+ * (§11.5.3 is a whole clause about when it is which), and today the only way
17
+ * through it is to delete the line, re-drag it between the same two boxes and
18
+ * hope both ends reattach where they were.
19
+ *
20
+ * ## The four families, and why they are four
21
+ *
22
+ * Grouped by what the relationship IS, which is also what the specification
23
+ * groups them by:
24
+ *
25
+ * - **association, aggregation, composition, communication path** — §11.5 and
26
+ * §19.4.4: one metaclass (Association), and the difference between the first
27
+ * three is `aggregation` = none / shared / composite. These are literally the
28
+ * same model element with one property changed, which is as close to "the
29
+ * same thing said more precisely" as UML gets. A CommunicationPath joins them
30
+ * rather than standing alone because §19.4.4 defines it AS an Association
31
+ * between nodes and draws it as one — a plain solid line — so a line an
32
+ * author drew between two servers and one they drew between two classes are
33
+ * the same drawing, and the swap is the correction a reader of a deployment
34
+ * diagram actually needs;
35
+ * - **generalization, realization** — §9.9.7 and §10.4.3: both say "this one
36
+ * conforms to that one", both are drawn with the hollow triangle, and the
37
+ * dashed line is the whole visual difference. A designer who drew a
38
+ * generalization to an interface meant a realization often enough that the
39
+ * swap is the point;
40
+ * - **dependency, include, extend** — §7.8 and §18.1.4: all three are
41
+ * dependencies drawn identically and told apart by their keyword alone, which
42
+ * is exactly the case where a picture cannot show a mistake and a dropdown
43
+ * can fix one;
44
+ * - **deploy, manifest** — §19.2.4 and §19.3.4: both are dependencies FROM an
45
+ * artifact drawn as that same dashed arrow, and what separates them is which
46
+ * end it lands on — a node (this artifact runs there) or a component (this
47
+ * artifact IS that component, in the flesh). They are their own family rather
48
+ * than three more members of the one above precisely because the confusion is
49
+ * between the two of them: an author who dropped a `.war` on a diagram and
50
+ * arrowed it at the wrong neighbour has made the one mistake this dropdown
51
+ * fixes, and offering them `«include»` alongside would be offering a use-case
52
+ * relationship on a deployment diagram.
53
+ *
54
+ * - **control flow, object flow** — §15.2.4: one drawing (a solid open arrow),
55
+ * told apart by what the line runs BETWEEN rather than by anything on it.
56
+ *
57
+ * - **synchronous, asynchronous and reply messages** — §17.4.4: one line, told
58
+ * apart by a filled head, an open head and a dash. See the declaration.
59
+ *
60
+ * ## The anchor, the transition and the two placed messages are in no family
61
+ *
62
+ * Deliberately, and the anchor is the edge equivalent of C4's `component`: an
63
+ * anchor joins a note to what it comments on (Annex A). It is not a
64
+ * relationship between classifiers at all, it carries no semantics, and
65
+ * offering to turn one into a composition would invite a diagram claiming that
66
+ * a comment owns a class. A kind in no family never offers the menu, so an
67
+ * anchor's toolbar is the plain connector's.
68
+ *
69
+ * A TRANSITION is alone for the opposite reason: it is drawn exactly like the
70
+ * two activity edges beside it (§14.2.4.8 and §15.2.4 are the same solid open
71
+ * arrow), and it is still not one of them, because it lives on the other
72
+ * diagram. A state machine's arrow joins two STATES and carries
73
+ * `trigger [guard] / effect`; an activity's joins two ACTIONS and carries a
74
+ * guard. Offering the swap would put an activity edge on a state machine, which
75
+ * is what the per-frame admissibility lists exist to refuse — a dropdown must
76
+ * not hand a user the error the audit is about to report.
77
+ *
78
+ * A CREATE and a DELETE message are alone for a third reason, and it is about
79
+ * WHERE THE LINE LANDS rather than about what it looks like. §17.4.4 draws a
80
+ * create message exactly like a reply and a delete message exactly like a
81
+ * synchronous call, and what makes each of them what it is, is its far end: a
82
+ * create arrives on the HEAD of the lifeline it brings into existence, and a
83
+ * delete arrives at a destruction cross. Offering them in the family above
84
+ * would let one click retype an ordinary call as a creation whose target is a
85
+ * spine — a line the drawing cannot show as wrong and `uml.message-endpoints`
86
+ * is about to report. The swap a modeller actually wants there is to move the
87
+ * end, which the canvas already does.
88
+ */
89
+ export type UmlEdgeKind = UmlEdgeRole;
90
+ /**
91
+ * Every edge kind the pack draws — derived from the style table, which is the
92
+ * one place they are enumerated.
93
+ */
94
+ export declare const UML_EDGE_KINDS: UmlEdgeKind[];
95
+ /** See the module docblock: four families, and the anchor in none of them. */
96
+ export declare const UML_EDGE_FAMILIES: readonly (readonly UmlEdgeKind[])[];
97
+ /**
98
+ * Which UML edge a connector's ROLE says it is — `undefined` for every connector
99
+ * that is not one of ours.
100
+ *
101
+ * `Partial` is the honest type rather than a defensive one: this question is
102
+ * asked of EVERY connector a user selects, and most of them are plain lines, a
103
+ * BPMN sequence flow or a C4 relationship. A total `Record<RoleId, …>` would
104
+ * type that answer away and leave `kindOf` promising a kind for a role it has
105
+ * never heard of.
106
+ *
107
+ * Derived from {@link UML_ROLE}, so a relationship renamed in the vocabulary is
108
+ * renamed here in the same edit.
109
+ */
110
+ export declare const UML_EDGE_KIND_OF_ROLE: Readonly<Partial<Record<RoleId, UmlEdgeKind>>>;
111
+ /**
112
+ * The WHOLE patch one relationship kind is worth — the same six props
113
+ * `activateUmlEdge` arms a fresh connector with, read off the same table.
114
+ *
115
+ * ## Why all six and not just the role
116
+ *
117
+ * Because on this table it is visibly not enough: a composition and an
118
+ * association differ ONLY in the filled diamond on the front end, a realization
119
+ * and a generalization ONLY in the dashes. A `{role}` patch would write the
120
+ * meaning and leave the picture stating the previous one — a line the exporter
121
+ * calls a composition and a reader calls an association, which is the single
122
+ * worst outcome a notation pack can produce.
123
+ *
124
+ * The ink and the weight ride along for the reason the node morph's whole preset
125
+ * does: a morphed edge and one freshly drawn from the toolbox must be the same
126
+ * element, and an edge somebody restyled by hand is an edge whose style this
127
+ * gesture is explicitly resetting.
128
+ *
129
+ * ## The one prop that is NOT here
130
+ *
131
+ * `mode`. The router is a LAYOUT decision — straight, orthogonal, curved — and a
132
+ * user who dragged a line into an elbow to get it round a box did that to the
133
+ * drawing, not to the relationship. It is the geometry of the edge in the sense
134
+ * `xywh` is the geometry of a node, and the morph's contract is that geometry is
135
+ * the user's. The omission is inert on today's table anyway, since all nine are
136
+ * armed straight; it is stated so that it stays inert on purpose.
137
+ */
138
+ export declare function umlEdgeProps(kind: UmlEdgeKind): Record<string, unknown>;
139
+ /**
140
+ * UML's edge morph declaration, handed to the generic `morphToolbarConfig`.
141
+ *
142
+ * `modelType` is `ConnectorElementModel` and there is NO `resolveTarget`: unlike
143
+ * a classifier, a relationship is one element — what the user selects, what
144
+ * carries the role and what the patch lands on are the same object. The gate is
145
+ * therefore entirely in {@link kindOf}: a plain connector, a BPMN sequence flow
146
+ * and a C4 relationship all carry a role this table does not know (or none at
147
+ * all), so they answer `undefined` and are never offered the menu.
148
+ *
149
+ * `clearOf` is empty, and hard-coded rather than derived: every kind writes the
150
+ * same six keys, because they all come from one table with no conditional
151
+ * spread in it. The day a row grows a key the others lack, this is where the
152
+ * deletion goes.
153
+ */
154
+ export declare const UML_EDGE_MORPH_SPEC: MorphSpec<UmlEdgeKind>;
@@ -0,0 +1,153 @@
1
+ import { morphLabel, } from '@formicoidea/labre-core/blocks/surface';
2
+ import { ConnectorElementModel } from '@formicoidea/labre-core/model';
3
+ import { umlCommandIcons, umlCommands } from './commands.js';
4
+ import { UML_EDGE_WIDTH, UML_INK } from './consts.js';
5
+ import { UML_EDGE_STYLE } from './edge-styles.js';
6
+ import { UML_ROLE } from './roles.js';
7
+ /**
8
+ * Every edge kind the pack draws — derived from the style table, which is the
9
+ * one place they are enumerated.
10
+ */
11
+ export const UML_EDGE_KINDS = Object.keys(UML_EDGE_STYLE);
12
+ /** See the module docblock: four families, and the anchor in none of them. */
13
+ export const UML_EDGE_FAMILIES = [
14
+ // Declaration order is menu order, and each family opens on its PLAIN member:
15
+ // the undecorated relationship is the honest first draft and the decorated one
16
+ // is the refinement — the same call the node morph and the sub-menu make.
17
+ // `communication-path` sits here because it is DRAWN as an association
18
+ // (§19.4.4) — while `roles.ts` files `uml:communication-path` flat, outside
19
+ // `uml:association`, so that association rules and readings never reach a
20
+ // deployment sheet. Two answers, two questions (drawing vs rule reach).
21
+ ['association', 'aggregation', 'composition', 'communication-path'],
22
+ ['generalization', 'realization'],
23
+ ['dependency', 'include', 'extend'],
24
+ // APPENDED, never inserted: the three families above keep their index, which
25
+ // is what lets the suite go on naming the dependency family by position.
26
+ ['deploy', 'manifest'],
27
+ // §15.2.4 — the two ACTIVITY edges, and the fifth family. Both are the same
28
+ // solid open arrow and the specification tells them apart by what the line
29
+ // runs BETWEEN: a flow that touches an object node is an object flow, every
30
+ // other one is a control flow. That is precisely the mistake a modeller makes
31
+ // — drawing the arrow through a data object and leaving it typed as control —
32
+ // and it is invisible on the canvas, which is the case a dropdown exists for.
33
+ ['control-flow', 'object-flow'],
34
+ // §17.4.4 — the three MESSAGES an interaction is mostly made of, and the
35
+ // sixth family. This is the case the edge morph exists for, more clearly than
36
+ // any family above it: the three are one line told apart by a FILLED head, an
37
+ // open head and a dash, the distinction is the whole semantics of a sequence
38
+ // diagram — does the caller wait, or not — and it is exactly what a modeller
39
+ // gets backwards while laying out a conversation. Redrawing the line would
40
+ // cost both ends, which on a sequence diagram is the HEIGHT the message
41
+ // happens at as well as which participants it runs between.
42
+ //
43
+ // `message-sync` opens it, as every family above opens on its plain member:
44
+ // a call whose caller waits is what `a -> b` means everywhere, and the other
45
+ // two are the refinements.
46
+ ['message-sync', 'message-async', 'message-reply'],
47
+ ];
48
+ /**
49
+ * Which UML edge a connector's ROLE says it is — `undefined` for every connector
50
+ * that is not one of ours.
51
+ *
52
+ * `Partial` is the honest type rather than a defensive one: this question is
53
+ * asked of EVERY connector a user selects, and most of them are plain lines, a
54
+ * BPMN sequence flow or a C4 relationship. A total `Record<RoleId, …>` would
55
+ * type that answer away and leave `kindOf` promising a kind for a role it has
56
+ * never heard of.
57
+ *
58
+ * Derived from {@link UML_ROLE}, so a relationship renamed in the vocabulary is
59
+ * renamed here in the same edit.
60
+ */
61
+ export const UML_EDGE_KIND_OF_ROLE = Object.fromEntries(UML_EDGE_KINDS.map(kind => [UML_ROLE[kind], kind]));
62
+ /**
63
+ * The creation command that arms each edge, keyed BY its kind.
64
+ *
65
+ * Derived from `telemetry.element` (`connector:composition`) exactly as the node
66
+ * morph derives its own from `node:interface`: the kind is already written down
67
+ * there, and a second table of labels and icons would drift from the sub-menu's.
68
+ */
69
+ const EDGE_COMMANDS = new Map(umlCommands.flatMap(command => {
70
+ const element = command.telemetry?.element;
71
+ return element?.startsWith('connector:')
72
+ ? [[element.slice('connector:'.length), command]]
73
+ : [];
74
+ }));
75
+ /** A kind's wording: the tool command's own key and English. */
76
+ function labelOf(kind) {
77
+ const command = EDGE_COMMANDS.get(kind);
78
+ return {
79
+ key: command?.labelKey,
80
+ fallback: command?.labelFallback ?? kind,
81
+ };
82
+ }
83
+ /** A kind's icon: the tool command's own, reused rather than redrawn. */
84
+ function iconOf(kind) {
85
+ const iconKey = EDGE_COMMANDS.get(kind)?.iconKey;
86
+ return ((iconKey && umlCommandIcons[iconKey]) || umlCommandIcons['uml.association']);
87
+ }
88
+ /**
89
+ * The WHOLE patch one relationship kind is worth — the same six props
90
+ * `activateUmlEdge` arms a fresh connector with, read off the same table.
91
+ *
92
+ * ## Why all six and not just the role
93
+ *
94
+ * Because on this table it is visibly not enough: a composition and an
95
+ * association differ ONLY in the filled diamond on the front end, a realization
96
+ * and a generalization ONLY in the dashes. A `{role}` patch would write the
97
+ * meaning and leave the picture stating the previous one — a line the exporter
98
+ * calls a composition and a reader calls an association, which is the single
99
+ * worst outcome a notation pack can produce.
100
+ *
101
+ * The ink and the weight ride along for the reason the node morph's whole preset
102
+ * does: a morphed edge and one freshly drawn from the toolbox must be the same
103
+ * element, and an edge somebody restyled by hand is an edge whose style this
104
+ * gesture is explicitly resetting.
105
+ *
106
+ * ## The one prop that is NOT here
107
+ *
108
+ * `mode`. The router is a LAYOUT decision — straight, orthogonal, curved — and a
109
+ * user who dragged a line into an elbow to get it round a box did that to the
110
+ * drawing, not to the relationship. It is the geometry of the edge in the sense
111
+ * `xywh` is the geometry of a node, and the morph's contract is that geometry is
112
+ * the user's. The omission is inert on today's table anyway, since all nine are
113
+ * armed straight; it is stated so that it stays inert on purpose.
114
+ */
115
+ export function umlEdgeProps(kind) {
116
+ return {
117
+ role: UML_ROLE[kind],
118
+ stroke: UML_INK,
119
+ strokeWidth: UML_EDGE_WIDTH,
120
+ ...UML_EDGE_STYLE[kind],
121
+ };
122
+ }
123
+ /**
124
+ * UML's edge morph declaration, handed to the generic `morphToolbarConfig`.
125
+ *
126
+ * `modelType` is `ConnectorElementModel` and there is NO `resolveTarget`: unlike
127
+ * a classifier, a relationship is one element — what the user selects, what
128
+ * carries the role and what the patch lands on are the same object. The gate is
129
+ * therefore entirely in {@link kindOf}: a plain connector, a BPMN sequence flow
130
+ * and a C4 relationship all carry a role this table does not know (or none at
131
+ * all), so they answer `undefined` and are never offered the menu.
132
+ *
133
+ * `clearOf` is empty, and hard-coded rather than derived: every kind writes the
134
+ * same six keys, because they all come from one table with no conditional
135
+ * spread in it. The day a row grows a key the others lack, this is where the
136
+ * deletion goes.
137
+ */
138
+ export const UML_EDGE_MORPH_SPEC = {
139
+ framework: 'uml',
140
+ families: UML_EDGE_FAMILIES,
141
+ modelType: ConnectorElementModel,
142
+ kindOf: (model) => model.role === undefined ? undefined : UML_EDGE_KIND_OF_ROLE[model.role],
143
+ // A relationship's kind IS its role, one for one — there is no collapsing to
144
+ // do here, unlike the node table where two C4 kinds share one role.
145
+ roleOf: kind => UML_ROLE[kind],
146
+ propsOf: umlEdgeProps,
147
+ clearOf: () => [],
148
+ labelOf,
149
+ iconOf,
150
+ // The same wording as the node dropdown, and the same key: a user meets one
151
+ // affordance called one thing, whether what they selected is a box or a line.
152
+ label: morphLabel('com.labre.morph.toolbar.label', 'Change type'),
153
+ };
@@ -0,0 +1,78 @@
1
+ import { PointStyle, StrokeStyle } from '@formicoidea/labre-core/model';
2
+ /**
3
+ * The UML line notation, as data — read by the TOOL that arms a fresh connector
4
+ * (`actions.ts`) and by the MORPH that retypes one already drawn
5
+ * (`edge-morph.ts`).
6
+ *
7
+ * It lives in a module of its own for exactly that reason. A relationship drawn
8
+ * from the toolbox and one an author changed his mind about must be the same
9
+ * element down to the last endpoint, and the only way to guarantee that is for
10
+ * the two sites to read one table rather than to agree about two. The file also
11
+ * keeps the morph — pure data, no editor — free of `actions.ts`, which pulls in
12
+ * the std scope, the gfx controller and the surface.
13
+ */
14
+ /**
15
+ * The edges the toolbox arms, by their role's local name.
16
+ *
17
+ * APPEND-ONLY, and the three at the bottom are phase 2's: a deployment diagram
18
+ * is drawn with lines of its own (§19.2.4, §19.3.4, §19.4.4) and they are added
19
+ * after the nine rather than filed among them, so a union somebody reads top to
20
+ * bottom still tells the story of how the pack grew.
21
+ */
22
+ export type UmlEdgeRole = 'association' | 'aggregation' | 'composition' | 'generalization' | 'realization' | 'dependency' | 'anchor' | 'include' | 'extend' | 'deploy' | 'manifest' | 'communication-path' | 'control-flow' | 'object-flow' | 'transition' | 'message-sync' | 'message-async' | 'message-reply' | 'message-create' | 'message-delete';
23
+ /** The three style props an edge kind actually differs on. */
24
+ export interface UmlEdgeStyle {
25
+ strokeStyle: StrokeStyle;
26
+ frontEndpointStyle: PointStyle;
27
+ rearEndpointStyle: PointStyle;
28
+ }
29
+ /**
30
+ * The whole UML line notation, in one table — §11.5.4 (association, aggregation
31
+ * and composition), §9.2.4 (generalization), §10.4.4 (interface realization),
32
+ * §7.8.4 (dependency and anchor), §18.1.4 (include, extend) and, since phase 2,
33
+ * §19.2.4 (deployment), §19.3.4 (manifestation) and §19.4.4 (communication
34
+ * path).
35
+ *
36
+ * ## Three props, and never a fourth
37
+ *
38
+ * UML tells its relationships apart by TWO things and only two: whether the line
39
+ * is solid or dashed, and what is drawn on its ends. Never by colour — the
40
+ * specification has none — and never by thickness, which is why `UML_EDGE_WIDTH`
41
+ * is one constant rather than a column here. A pack that distinguished an
42
+ * association from a dependency by making one heavier would be inventing a
43
+ * notation on top of the one it claims to implement.
44
+ *
45
+ * ## Which end carries the mark
46
+ *
47
+ * `front` is the SOURCE end, `rear` the target end, and the difference is the
48
+ * whole semantics of four of these nine:
49
+ *
50
+ * - **aggregation / composition** put their diamond on the FRONT, because the
51
+ * source of these roles is the WHOLE (`roles.ts`: "is composed of"). Hollow
52
+ * for shared aggregation, filled for composite — §11.5.4's one visual
53
+ * difference, and the one everybody misdraws;
54
+ * - **generalization / realization** put a hollow triangle on the REAR, because
55
+ * their source is the SPECIFIC one ("is a", "realizes") and the triangle
56
+ * points at the general. Solid for generalization, dashed for realization:
57
+ * §10.4.4 draws a realization as the generalization arrow on a broken line,
58
+ * and that is the only thing that separates them.
59
+ *
60
+ * ## The five that share a look
61
+ *
62
+ * A dependency, an include, an extend, a deployment and a manifestation are all
63
+ * a dashed line with an open arrowhead, and the specification is explicit that
64
+ * they are told apart by the KEYWORD written on them («use», «include»,
65
+ * «extend», «deploy», «manifest» — §7.8.4, §18.1.4, §19.2.4, §19.3.4), not by
66
+ * their drawing: all five ARE Dependencies. So they share a row here and differ
67
+ * only by the ROLE, which is what the export writes the keyword from. Nothing on
68
+ * the canvas is lost: the role is what the audit, the reading profile and the
69
+ * exporter all read.
70
+ *
71
+ * ## The anchor
72
+ *
73
+ * Dashed with nothing on either end (Annex A): an anchor joins a note to what it
74
+ * comments on and claims no direction, so an arrowhead would be the picture
75
+ * making a statement the role explicitly refuses to make — the same argument
76
+ * BPMN's association makes for the same absence.
77
+ */
78
+ export declare const UML_EDGE_STYLE: Record<UmlEdgeRole, UmlEdgeStyle>;
@@ -0,0 +1,210 @@
1
+ import { PointStyle, StrokeStyle } from '@formicoidea/labre-core/model';
2
+ /**
3
+ * The whole UML line notation, in one table — §11.5.4 (association, aggregation
4
+ * and composition), §9.2.4 (generalization), §10.4.4 (interface realization),
5
+ * §7.8.4 (dependency and anchor), §18.1.4 (include, extend) and, since phase 2,
6
+ * §19.2.4 (deployment), §19.3.4 (manifestation) and §19.4.4 (communication
7
+ * path).
8
+ *
9
+ * ## Three props, and never a fourth
10
+ *
11
+ * UML tells its relationships apart by TWO things and only two: whether the line
12
+ * is solid or dashed, and what is drawn on its ends. Never by colour — the
13
+ * specification has none — and never by thickness, which is why `UML_EDGE_WIDTH`
14
+ * is one constant rather than a column here. A pack that distinguished an
15
+ * association from a dependency by making one heavier would be inventing a
16
+ * notation on top of the one it claims to implement.
17
+ *
18
+ * ## Which end carries the mark
19
+ *
20
+ * `front` is the SOURCE end, `rear` the target end, and the difference is the
21
+ * whole semantics of four of these nine:
22
+ *
23
+ * - **aggregation / composition** put their diamond on the FRONT, because the
24
+ * source of these roles is the WHOLE (`roles.ts`: "is composed of"). Hollow
25
+ * for shared aggregation, filled for composite — §11.5.4's one visual
26
+ * difference, and the one everybody misdraws;
27
+ * - **generalization / realization** put a hollow triangle on the REAR, because
28
+ * their source is the SPECIFIC one ("is a", "realizes") and the triangle
29
+ * points at the general. Solid for generalization, dashed for realization:
30
+ * §10.4.4 draws a realization as the generalization arrow on a broken line,
31
+ * and that is the only thing that separates them.
32
+ *
33
+ * ## The five that share a look
34
+ *
35
+ * A dependency, an include, an extend, a deployment and a manifestation are all
36
+ * a dashed line with an open arrowhead, and the specification is explicit that
37
+ * they are told apart by the KEYWORD written on them («use», «include»,
38
+ * «extend», «deploy», «manifest» — §7.8.4, §18.1.4, §19.2.4, §19.3.4), not by
39
+ * their drawing: all five ARE Dependencies. So they share a row here and differ
40
+ * only by the ROLE, which is what the export writes the keyword from. Nothing on
41
+ * the canvas is lost: the role is what the audit, the reading profile and the
42
+ * exporter all read.
43
+ *
44
+ * ## The anchor
45
+ *
46
+ * Dashed with nothing on either end (Annex A): an anchor joins a note to what it
47
+ * comments on and claims no direction, so an arrowhead would be the picture
48
+ * making a statement the role explicitly refuses to make — the same argument
49
+ * BPMN's association makes for the same absence.
50
+ */
51
+ export const UML_EDGE_STYLE = {
52
+ association: {
53
+ strokeStyle: StrokeStyle.Solid,
54
+ frontEndpointStyle: PointStyle.None,
55
+ rearEndpointStyle: PointStyle.None,
56
+ },
57
+ aggregation: {
58
+ strokeStyle: StrokeStyle.Solid,
59
+ frontEndpointStyle: PointStyle.DiamondHollow,
60
+ rearEndpointStyle: PointStyle.None,
61
+ },
62
+ composition: {
63
+ strokeStyle: StrokeStyle.Solid,
64
+ frontEndpointStyle: PointStyle.Diamond,
65
+ rearEndpointStyle: PointStyle.None,
66
+ },
67
+ generalization: {
68
+ strokeStyle: StrokeStyle.Solid,
69
+ frontEndpointStyle: PointStyle.None,
70
+ rearEndpointStyle: PointStyle.TriangleHollow,
71
+ },
72
+ realization: {
73
+ strokeStyle: StrokeStyle.Dash,
74
+ frontEndpointStyle: PointStyle.None,
75
+ rearEndpointStyle: PointStyle.TriangleHollow,
76
+ },
77
+ dependency: {
78
+ strokeStyle: StrokeStyle.Dash,
79
+ frontEndpointStyle: PointStyle.None,
80
+ rearEndpointStyle: PointStyle.Arrow,
81
+ },
82
+ include: {
83
+ strokeStyle: StrokeStyle.Dash,
84
+ frontEndpointStyle: PointStyle.None,
85
+ rearEndpointStyle: PointStyle.Arrow,
86
+ },
87
+ extend: {
88
+ strokeStyle: StrokeStyle.Dash,
89
+ frontEndpointStyle: PointStyle.None,
90
+ rearEndpointStyle: PointStyle.Arrow,
91
+ },
92
+ anchor: {
93
+ strokeStyle: StrokeStyle.Dash,
94
+ frontEndpointStyle: PointStyle.None,
95
+ rearEndpointStyle: PointStyle.None,
96
+ },
97
+ // A Deployment is a Dependency (§19.2.4): the artifact is the client, the node
98
+ // the supplier, and the picture is the dashed open arrow every dependency
99
+ // wears — told apart, as always, by the keyword the export writes from the
100
+ // role rather than by a drawing of its own.
101
+ deploy: {
102
+ strokeStyle: StrokeStyle.Dash,
103
+ frontEndpointStyle: PointStyle.None,
104
+ rearEndpointStyle: PointStyle.Arrow,
105
+ },
106
+ // A Manifestation is an Abstraction, and therefore a Dependency too (§19.3.4)
107
+ // — same line, from the artifact to the component it is the physical form of.
108
+ manifest: {
109
+ strokeStyle: StrokeStyle.Dash,
110
+ frontEndpointStyle: PointStyle.None,
111
+ rearEndpointStyle: PointStyle.Arrow,
112
+ },
113
+ // A CommunicationPath is an Association between two nodes (§19.4.4), so it is
114
+ // drawn exactly as one: a plain solid line, and nothing on either end. The
115
+ // absence of arrowheads is the statement — a network link between two servers
116
+ // has no client and no supplier, and a head would invent one.
117
+ 'communication-path': {
118
+ strokeStyle: StrokeStyle.Solid,
119
+ frontEndpointStyle: PointStyle.None,
120
+ rearEndpointStyle: PointStyle.None,
121
+ },
122
+ // ── Behaviour: the third drawing this table has ever needed ────────────────
123
+ //
124
+ // §15.2.4 draws an ActivityEdge as a SOLID line with an OPEN ARROWHEAD, and
125
+ // §14.2.4.8 draws a Transition as exactly the same line. That is a look no
126
+ // structural relationship wears: an association is solid with nothing on it,
127
+ // a dependency is the arrowhead on a DASHED line. The distinction matters and
128
+ // is the specification's own — a behaviour diagram states an ORDER of things
129
+ // and therefore always points, where a class diagram states a relationship
130
+ // and mostly does not.
131
+ //
132
+ // Control flow and object flow share the row, as the five dependencies above
133
+ // share theirs and for the same reason: §15.2.4 tells them apart by what sits
134
+ // at the ENDS of the line — an object node at one end makes it an object flow
135
+ // — not by a decoration on the line, and the ROLE is what the audit and the
136
+ // exporter read that from. (An object flow drawn between two pins can be
137
+ // shown with the pins collapsed into a rectangle on the line; that is a
138
+ // §15.4.4 shorthand for the NODES, not a second line style, so it does not
139
+ // belong here.)
140
+ 'control-flow': {
141
+ strokeStyle: StrokeStyle.Solid,
142
+ frontEndpointStyle: PointStyle.None,
143
+ rearEndpointStyle: PointStyle.Arrow,
144
+ },
145
+ 'object-flow': {
146
+ strokeStyle: StrokeStyle.Solid,
147
+ frontEndpointStyle: PointStyle.None,
148
+ rearEndpointStyle: PointStyle.Arrow,
149
+ },
150
+ // A Transition (§14.2.4.8) is the same arrow, and the `trigger [guard] /
151
+ // effect` it carries is written on the line as its centre label rather than
152
+ // drawn into it — which is why this row is a copy of the two above and the
153
+ // grammar, not the style table, is where that syntax lives.
154
+ transition: {
155
+ strokeStyle: StrokeStyle.Solid,
156
+ frontEndpointStyle: PointStyle.None,
157
+ rearEndpointStyle: PointStyle.Arrow,
158
+ },
159
+ // ── Phase 3: the MESSAGES of a sequence diagram (§17.4.4) ─────────────────
160
+ //
161
+ // The one place in this table where the DRAWING carries the meaning rather
162
+ // than merely accompanying it. §17.4.4 is explicit, and the three shapes are
163
+ // the whole vocabulary of an interaction:
164
+ //
165
+ // - a SYNCHRONOUS call is a solid line with a FILLED arrowhead — the caller
166
+ // waits, and the black triangle is what says so;
167
+ // - an ASYNCHRONOUS message is a solid line with an OPEN (stick) arrowhead —
168
+ // the caller does not wait, and the open head is the difference;
169
+ // - a REPLY is a DASHED line with an open arrowhead, travelling back.
170
+ //
171
+ // `Triangle` and `Arrow` are the library's filled triangle and its open
172
+ // stick head, which is exactly the pair §17.4.4 draws. Getting them the wrong
173
+ // way round would make every call on the diagram say the opposite of what the
174
+ // author meant — the one notation mistake in this pack that a reader cannot
175
+ // recover from, because nothing else on the line says which it is.
176
+ 'message-sync': {
177
+ strokeStyle: StrokeStyle.Solid,
178
+ frontEndpointStyle: PointStyle.None,
179
+ rearEndpointStyle: PointStyle.Triangle,
180
+ },
181
+ 'message-async': {
182
+ strokeStyle: StrokeStyle.Solid,
183
+ frontEndpointStyle: PointStyle.None,
184
+ rearEndpointStyle: PointStyle.Arrow,
185
+ },
186
+ 'message-reply': {
187
+ strokeStyle: StrokeStyle.Dash,
188
+ frontEndpointStyle: PointStyle.None,
189
+ rearEndpointStyle: PointStyle.Arrow,
190
+ },
191
+ // A CREATE message (§17.4.4) is drawn as a dashed line with an open arrowhead
192
+ // landing on the HEAD of the lifeline it brings into existence — the same
193
+ // drawing as a reply, and told apart by the role and by where it lands, which
194
+ // is `rules.ts`'s business rather than this table's.
195
+ 'message-create': {
196
+ strokeStyle: StrokeStyle.Dash,
197
+ frontEndpointStyle: PointStyle.None,
198
+ rearEndpointStyle: PointStyle.Arrow,
199
+ },
200
+ // A DELETE message is an ordinary call that happens to end at the X of a
201
+ // destruction occurrence (§17.4.4): the line is the synchronous one, and the
202
+ // cross at its end is a separate mark the author drops on the spine. So it
203
+ // shares the sync row rather than inventing a drawing the specification does
204
+ // not have.
205
+ 'message-delete': {
206
+ strokeStyle: StrokeStyle.Solid,
207
+ frontEndpointStyle: PointStyle.None,
208
+ rearEndpointStyle: PointStyle.Triangle,
209
+ },
210
+ };
@@ -0,0 +1,9 @@
1
+ import { EdgelessUmlMenu } from './toolbar/uml-menu.js';
2
+ import { EdgelessUmlSeniorButton } from './toolbar/uml-senior-button.js';
3
+ export declare function effects(): void;
4
+ declare global {
5
+ interface HTMLElementTagNameMap {
6
+ 'edgeless-uml-menu': EdgelessUmlMenu;
7
+ 'edgeless-uml-senior-button': EdgelessUmlSeniorButton;
8
+ }
9
+ }
@@ -0,0 +1,6 @@
1
+ import { EdgelessUmlMenu } from './toolbar/uml-menu.js';
2
+ import { EdgelessUmlSeniorButton } from './toolbar/uml-senior-button.js';
3
+ export function effects() {
4
+ customElements.define('edgeless-uml-menu', EdgelessUmlMenu);
5
+ customElements.define('edgeless-uml-senior-button', EdgelessUmlSeniorButton);
6
+ }