@formicoidea/labre-framework-bpmn 0.31.0 → 0.33.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions.d.ts +213 -0
- package/dist/actions.js +467 -0
- package/dist/background.d.ts +2 -0
- package/dist/background.js +158 -0
- package/dist/commands.d.ts +4 -0
- package/dist/commands.js +567 -0
- package/dist/consts.d.ts +157 -3
- package/dist/consts.js +192 -3
- package/dist/descriptor.d.ts +8 -3
- package/dist/descriptor.js +6 -3
- package/dist/element-renderer.d.ts +10 -4
- package/dist/element-renderer.js +14 -55
- package/dist/element-view.d.ts +100 -8
- package/dist/element-view.js +249 -30
- package/dist/export.d.ts +277 -0
- package/dist/export.js +1802 -0
- package/dist/facts.d.ts +48 -0
- package/dist/facts.js +127 -0
- package/dist/import.d.ts +44 -0
- package/dist/import.js +1440 -0
- package/dist/index.d.ts +14 -1
- package/dist/index.js +46 -1
- package/dist/interchange.d.ts +109 -0
- package/dist/interchange.js +191 -0
- package/dist/morph.d.ts +61 -0
- package/dist/morph.js +118 -0
- package/dist/node/node-renderer.d.ts +0 -9
- package/dist/node/node-renderer.js +294 -17
- package/dist/pool-hit.d.ts +98 -0
- package/dist/pool-hit.js +130 -0
- package/dist/presets.d.ts +114 -0
- package/dist/presets.js +232 -0
- package/dist/profiles.d.ts +2 -0
- package/dist/profiles.js +189 -0
- package/dist/roles.d.ts +96 -0
- package/dist/roles.js +410 -0
- package/dist/rules.d.ts +199 -0
- package/dist/rules.js +1539 -0
- package/dist/templates/index.js +116 -9
- package/dist/toolbar/bpmn-menu.d.ts +6 -21
- package/dist/toolbar/bpmn-menu.js +6 -173
- package/dist/toolbar/bpmn-senior-button.js +8 -2
- package/dist/toolbar/config.d.ts +27 -2
- package/dist/toolbar/config.js +86 -2
- package/dist/toolbar/icons.d.ts +67 -0
- package/dist/toolbar/icons.js +141 -0
- package/dist/toolbar/senior-tool.js +1 -0
- package/dist/translations.d.ts +16 -0
- package/dist/translations.js +20 -0
- package/dist/view.d.ts +18 -0
- package/dist/view.js +95 -7
- package/package.json +2 -2
package/dist/presets.js
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { FontFamily, ShapeStyle, StrokeStyle, TextAlign, TextFitMode, TextVerticalAlign, } from '@formicoidea/labre-core/model';
|
|
2
|
+
import { CALL_ACTIVITY_WIDTH, END_WIDTH, EVENT_END, EVENT_START, GROUP_RADIUS, GROUP_STROKE, INNER_FONT_SIZE, NEUTRAL_STROKE, NODE_FILL, NODE_STROKE_WIDTH, START_WIDTH, TASK_RADIUS, } from './consts.js';
|
|
3
|
+
import { BPMN_ROLE_OF_KIND } from './roles.js';
|
|
4
|
+
/** Per-kind native shape + accent presets (style C). */
|
|
5
|
+
export const NODE_PRESETS = {
|
|
6
|
+
// Events: one ellipse, and the ring weight says start or end. The message and
|
|
7
|
+
// timer variants keep their family's ring exactly — a message START is a thin
|
|
8
|
+
// green ring with an envelope in it, and a message END the thick red one.
|
|
9
|
+
startEvent: { shapeType: 'ellipse', stroke: EVENT_START, width: START_WIDTH },
|
|
10
|
+
startEventMessage: {
|
|
11
|
+
shapeType: 'ellipse',
|
|
12
|
+
stroke: EVENT_START,
|
|
13
|
+
width: START_WIDTH,
|
|
14
|
+
},
|
|
15
|
+
startEventTimer: {
|
|
16
|
+
shapeType: 'ellipse',
|
|
17
|
+
stroke: EVENT_START,
|
|
18
|
+
width: START_WIDTH,
|
|
19
|
+
},
|
|
20
|
+
endEvent: { shapeType: 'ellipse', stroke: EVENT_END, width: END_WIDTH },
|
|
21
|
+
endEventMessage: {
|
|
22
|
+
shapeType: 'ellipse',
|
|
23
|
+
stroke: EVENT_END,
|
|
24
|
+
width: END_WIDTH,
|
|
25
|
+
},
|
|
26
|
+
endEventTerminate: {
|
|
27
|
+
shapeType: 'ellipse',
|
|
28
|
+
stroke: EVENT_END,
|
|
29
|
+
width: END_WIDTH,
|
|
30
|
+
},
|
|
31
|
+
// Activities: the same rounded rectangle, and a marker tells them apart —
|
|
32
|
+
// except the call activity, whose thick border IS the distinction (it carries
|
|
33
|
+
// the same `+` as the sub-process).
|
|
34
|
+
task: {
|
|
35
|
+
shapeType: 'rect',
|
|
36
|
+
stroke: NEUTRAL_STROKE,
|
|
37
|
+
width: NODE_STROKE_WIDTH,
|
|
38
|
+
radius: TASK_RADIUS,
|
|
39
|
+
},
|
|
40
|
+
taskUser: {
|
|
41
|
+
shapeType: 'rect',
|
|
42
|
+
stroke: NEUTRAL_STROKE,
|
|
43
|
+
width: NODE_STROKE_WIDTH,
|
|
44
|
+
radius: TASK_RADIUS,
|
|
45
|
+
},
|
|
46
|
+
taskService: {
|
|
47
|
+
shapeType: 'rect',
|
|
48
|
+
stroke: NEUTRAL_STROKE,
|
|
49
|
+
width: NODE_STROKE_WIDTH,
|
|
50
|
+
radius: TASK_RADIUS,
|
|
51
|
+
},
|
|
52
|
+
subProcess: {
|
|
53
|
+
shapeType: 'rect',
|
|
54
|
+
stroke: NEUTRAL_STROKE,
|
|
55
|
+
width: NODE_STROKE_WIDTH,
|
|
56
|
+
radius: TASK_RADIUS,
|
|
57
|
+
},
|
|
58
|
+
callActivity: {
|
|
59
|
+
shapeType: 'rect',
|
|
60
|
+
stroke: NEUTRAL_STROKE,
|
|
61
|
+
width: CALL_ACTIVITY_WIDTH,
|
|
62
|
+
radius: TASK_RADIUS,
|
|
63
|
+
},
|
|
64
|
+
// Gateways: one diamond, one marker each.
|
|
65
|
+
gatewayExclusive: {
|
|
66
|
+
shapeType: 'diamond',
|
|
67
|
+
stroke: NEUTRAL_STROKE,
|
|
68
|
+
width: NODE_STROKE_WIDTH,
|
|
69
|
+
},
|
|
70
|
+
gatewayParallel: {
|
|
71
|
+
shapeType: 'diamond',
|
|
72
|
+
stroke: NEUTRAL_STROKE,
|
|
73
|
+
width: NODE_STROKE_WIDTH,
|
|
74
|
+
},
|
|
75
|
+
// Data and artifacts: body drawn by the glyph (see {@link BpmnNodePreset}).
|
|
76
|
+
dataObject: {
|
|
77
|
+
shapeType: 'rect',
|
|
78
|
+
stroke: NEUTRAL_STROKE,
|
|
79
|
+
width: NODE_STROKE_WIDTH,
|
|
80
|
+
glyphBody: true,
|
|
81
|
+
},
|
|
82
|
+
dataStore: {
|
|
83
|
+
shapeType: 'rect',
|
|
84
|
+
stroke: NEUTRAL_STROKE,
|
|
85
|
+
width: NODE_STROKE_WIDTH,
|
|
86
|
+
glyphBody: true,
|
|
87
|
+
},
|
|
88
|
+
textAnnotation: {
|
|
89
|
+
shapeType: 'rect',
|
|
90
|
+
stroke: NEUTRAL_STROKE,
|
|
91
|
+
width: NODE_STROKE_WIDTH,
|
|
92
|
+
glyphBody: true,
|
|
93
|
+
},
|
|
94
|
+
// The group: a dashed grey outline round part of the picture. Entirely a
|
|
95
|
+
// native shape — no glyph, nothing for the renderer to do — because the
|
|
96
|
+
// notation asks for exactly what `strokeStyle: dash` already draws.
|
|
97
|
+
group: {
|
|
98
|
+
shapeType: 'rect',
|
|
99
|
+
stroke: GROUP_STROKE,
|
|
100
|
+
width: NODE_STROKE_WIDTH,
|
|
101
|
+
radius: GROUP_RADIUS,
|
|
102
|
+
strokeStyle: StrokeStyle.Dash,
|
|
103
|
+
hollow: true,
|
|
104
|
+
textAlign: TextAlign.Left,
|
|
105
|
+
textVerticalAlign: TextVerticalAlign.Top,
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* One BPMN node, as the props `surface.addElement` takes.
|
|
110
|
+
*
|
|
111
|
+
* The single description of what a `bpmnNode` IS in a document: the palette
|
|
112
|
+
* hands it a box centred on the viewport, the importer hands it the box the
|
|
113
|
+
* file's `dc:Bounds` gave, and the element that lands is the same either way.
|
|
114
|
+
*
|
|
115
|
+
* `text` is passed through unchanged, `undefined` included — an artefact whose
|
|
116
|
+
* label the source left empty gets no `text` key at all rather than an empty
|
|
117
|
+
* one, which is what keeps an imported node byte-comparable with a drawn one
|
|
118
|
+
* that was never typed into.
|
|
119
|
+
*/
|
|
120
|
+
export function bpmnNodeProps(kind, box) {
|
|
121
|
+
const preset = NODE_PRESETS[kind];
|
|
122
|
+
return {
|
|
123
|
+
type: 'bpmnNode',
|
|
124
|
+
kind,
|
|
125
|
+
// Semantic identity (B1): posted next to `kind`, which stays untouched and
|
|
126
|
+
// keeps driving the rendering. The role is the authority on what the node
|
|
127
|
+
// MEANS — see the table in `./roles.ts`.
|
|
128
|
+
role: BPMN_ROLE_OF_KIND[kind],
|
|
129
|
+
shapeType: preset.shapeType,
|
|
130
|
+
// A glyph-bodied artefact paints nothing natively: the folded page, the
|
|
131
|
+
// cylinder and the bracket are drawn by the renderer, which reads
|
|
132
|
+
// `fillColor` / `strokeColor` off this same model — so both stay editable
|
|
133
|
+
// from the shape toolbar exactly like every other node's. A `hollow` one
|
|
134
|
+
// paints natively and simply has no body: the group is an outline.
|
|
135
|
+
filled: !preset.glyphBody && !preset.hollow,
|
|
136
|
+
fillColor: NODE_FILL,
|
|
137
|
+
strokeColor: preset.stroke,
|
|
138
|
+
strokeWidth: preset.width,
|
|
139
|
+
strokeStyle: preset.glyphBody
|
|
140
|
+
? StrokeStyle.None
|
|
141
|
+
: (preset.strokeStyle ?? StrokeStyle.Solid),
|
|
142
|
+
shapeStyle: ShapeStyle.General,
|
|
143
|
+
roughness: 0,
|
|
144
|
+
radius: preset.radius ?? 0,
|
|
145
|
+
text: box.text,
|
|
146
|
+
color: NEUTRAL_STROKE,
|
|
147
|
+
fontFamily: FontFamily.Inter,
|
|
148
|
+
fontSize: INNER_FONT_SIZE,
|
|
149
|
+
textAlign: preset.textAlign ?? TextAlign.Center,
|
|
150
|
+
// Spread, never a defaulted key: the model's own default is already
|
|
151
|
+
// `Center`, so writing it here would put a new key in the Y.Map of every
|
|
152
|
+
// artefact that does not ask for one — the same avoidable payload change
|
|
153
|
+
// review caught on `strokeStyle`.
|
|
154
|
+
...(preset.textVerticalAlign
|
|
155
|
+
? { textVerticalAlign: preset.textVerticalAlign }
|
|
156
|
+
: {}),
|
|
157
|
+
// BPMN symbols have normative sizes: a long label overflows rather
|
|
158
|
+
// than deforming the node
|
|
159
|
+
textFitMode: TextFitMode.Overflow,
|
|
160
|
+
xywh: box.xywh,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The box {@link bpmnMorphProps} hands {@link bpmnNodeProps} and then throws
|
|
165
|
+
* away. Never written to a document: a morph keeps the geometry the element
|
|
166
|
+
* already has, and this exists only because the one builder takes a box.
|
|
167
|
+
*/
|
|
168
|
+
const DISCARDED_BOX = '[0,0,0,0]';
|
|
169
|
+
/** What a morph must never rewrite: identity, geometry, and the user's words. */
|
|
170
|
+
const NOT_A_MORPH = ['type', 'xywh', 'text'];
|
|
171
|
+
/**
|
|
172
|
+
* What a node's kind is worth to an element that ALREADY EXISTS — the same
|
|
173
|
+
* description as {@link bpmnNodeProps}, minus the three things a morph has no
|
|
174
|
+
* business touching.
|
|
175
|
+
*
|
|
176
|
+
* Derived from the creation builder rather than restated beside it, and that is
|
|
177
|
+
* the whole point of the function.
|
|
178
|
+
*
|
|
179
|
+
* ## Why a `{kind, role}` patch is not enough
|
|
180
|
+
*
|
|
181
|
+
* Because the appearance of a BPMN artefact lives in props the CREATING kind's
|
|
182
|
+
* preset wrote, and nothing else ever rewrites them. One shipped morph pair
|
|
183
|
+
* shows it today: `subProcess` and `callActivity` are the same rounded
|
|
184
|
+
* rectangle and differ only in `strokeWidth` — 2 against 4 — and that thick
|
|
185
|
+
* border IS how a reader tells "this box stands for a process defined
|
|
186
|
+
* elsewhere" from "this box stands for one defined inline". Morph between them
|
|
187
|
+
* with two keys and the call activity arrives wearing the sub-process's thin
|
|
188
|
+
* border, which is a drawing that says the wrong thing.
|
|
189
|
+
*
|
|
190
|
+
* Every other family declared in `./morph.ts` currently shares one preset
|
|
191
|
+
* across its members, so for those the full patch changes nothing — and that is
|
|
192
|
+
* the second reason to write it this way rather than to trim it. A family is
|
|
193
|
+
* DATA (`BPMN_MORPH_FAMILIES`) and grows by declaration, with no code change to
|
|
194
|
+
* prompt anyone to ask whether the presets still agree; deriving the patch from
|
|
195
|
+
* the creation builder means the answer is right in advance. It is also what
|
|
196
|
+
* guarantees that a morphed artefact and one drawn fresh from the palette are
|
|
197
|
+
* the same element — two builders would agree the day they were written and
|
|
198
|
+
* drift on the first restyle, which is the argument this file already makes for
|
|
199
|
+
* having one creation builder at all.
|
|
200
|
+
*/
|
|
201
|
+
export function bpmnMorphProps(kind) {
|
|
202
|
+
// Widened to the plain record on the way in: `type` is required on what the
|
|
203
|
+
// creation builder returns, and `delete` may only take an optional key.
|
|
204
|
+
const props = {
|
|
205
|
+
...bpmnNodeProps(kind, { xywh: DISCARDED_BOX }),
|
|
206
|
+
};
|
|
207
|
+
for (const key of NOT_A_MORPH)
|
|
208
|
+
delete props[key];
|
|
209
|
+
return props;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Every key ANY kind's props may carry — the union over the whole pack.
|
|
213
|
+
*
|
|
214
|
+
* Computed rather than listed, so a preset that starts spreading a second
|
|
215
|
+
* conditional key is covered on the day it is added rather than on the day
|
|
216
|
+
* somebody notices.
|
|
217
|
+
*/
|
|
218
|
+
const EVERY_MORPH_KEY = new Set(Object.keys(NODE_PRESETS).flatMap(kind => Object.keys(bpmnMorphProps(kind))));
|
|
219
|
+
/**
|
|
220
|
+
* The fields to DELETE from an element after morphing it to `kind` — the keys
|
|
221
|
+
* some other kind writes and this one does not.
|
|
222
|
+
*
|
|
223
|
+
* A patch cannot express absence. `textVerticalAlign` is spread conditionally
|
|
224
|
+
* (see {@link bpmnNodeProps}), so morphing away from the group would leave
|
|
225
|
+
* `Top` sitting in the Y.Map and silently in force over a preset that means
|
|
226
|
+
* "centred". `clearField` removes the key, which is the same call `writeLanes`
|
|
227
|
+
* makes when a pool loses its last lane.
|
|
228
|
+
*/
|
|
229
|
+
export function bpmnMorphClears(kind) {
|
|
230
|
+
const present = new Set(Object.keys(bpmnMorphProps(kind)));
|
|
231
|
+
return [...EVERY_MORPH_KEY].filter(key => !present.has(key));
|
|
232
|
+
}
|
package/dist/profiles.js
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BPMN validation profiles (backlog item B6 — not the rule of that number; see
|
|
3
|
+
* the numbering note in `rules.ts`).
|
|
4
|
+
*
|
|
5
|
+
* DATA owned by the framework, like its rules and its roles. A profile is chosen
|
|
6
|
+
* per POOL — the framework's root instance — and the choice rides on the pool
|
|
7
|
+
* element itself, so two participants at two levels of requirement coexist on one
|
|
8
|
+
* canvas: the pool somebody is still sketching stays a sketch while the one
|
|
9
|
+
* that is being handed over is held to the norm.
|
|
10
|
+
*
|
|
11
|
+
* Registered from the flag-gated `BpmnViewExtension`, beside the rules:
|
|
12
|
+
* switching the `bpmn` flag off takes the choice away with the rest of the
|
|
13
|
+
* tooling, and a pool already set to `descriptive` simply stops being checked
|
|
14
|
+
* until it comes back — the id stays written, untouched.
|
|
15
|
+
*
|
|
16
|
+
* ## Two today, and the two that are future DATA
|
|
17
|
+
*
|
|
18
|
+
* BPMN 2.0 defines three conformance sub-classes, each a superset of the last:
|
|
19
|
+
* DESCRIPTIVE (the visual subset a business reader can follow — the one this
|
|
20
|
+
* pack draws), ANALYTIC (every event type, every gateway, the full flow
|
|
21
|
+
* semantics) and COMMON EXECUTABLE (what an engine can run: data mappings,
|
|
22
|
+
* expressions, message correlation). Only the first is meaningful against the
|
|
23
|
+
* twenty-two rules that exist, because the other two are levels of requirement
|
|
24
|
+
* about artefacts this pack does not yet draw.
|
|
25
|
+
*
|
|
26
|
+
* They arrive as PROFILES and not as engine work when they arrive: a level of
|
|
27
|
+
* requirement is a table of severities per rule id, so `bpmn.analytic` is an
|
|
28
|
+
* entry in the array at the bottom of this file plus whatever new rules the new
|
|
29
|
+
* artefacts bring. Nothing in the pipework has to learn a third word.
|
|
30
|
+
*
|
|
31
|
+
* ## Both tables spell out all TWENTY-TWO ids
|
|
32
|
+
*
|
|
33
|
+
* Every severity a user can get is either the one its rule declares or one of
|
|
34
|
+
* these lines — nothing is raised implicitly (PF9.4). Spelling them all out is
|
|
35
|
+
* also what let eight of these rules wait a review cycle for the engine fields
|
|
36
|
+
* they needed and then arrive already governed, rather than arriving and
|
|
37
|
+
* quietly keeping their own severity at a level nobody had chosen.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Sketch: every rule demoted to `audit`. Findings still reach `violations$` —
|
|
41
|
+
* a host panel and a conformance report see them — and the canvas says nothing.
|
|
42
|
+
*
|
|
43
|
+
* The DEFAULT, and deliberately so (PRD principle 3). A process is drawn in a
|
|
44
|
+
* workshop, at speed, with the steps going down before anybody decides where the
|
|
45
|
+
* pools are: for the first minutes of that, EVERY task is a dead end, no pool has
|
|
46
|
+
* a start event, and half the links are still plain connectors somebody
|
|
47
|
+
* quick-dragged. A tool arguing with that hand is a tool switched off within the
|
|
48
|
+
* hour, and it would be arguing about a diagram the author already knows is
|
|
49
|
+
* unfinished.
|
|
50
|
+
*
|
|
51
|
+
* The sketch PRIMES: the findings are computed, collected and available the
|
|
52
|
+
* moment the author asks — through the panel, through a check-up, through the
|
|
53
|
+
* profile switch — so nothing has to be re-derived when they decide the drawing
|
|
54
|
+
* is a deliverable. Being the default also means it WRITES NOTHING: a pool on
|
|
55
|
+
* `sketch` carries no profile key, so every process ever drawn is on it, with no
|
|
56
|
+
* migration and no backfill.
|
|
57
|
+
*/
|
|
58
|
+
const sketch = {
|
|
59
|
+
id: 'bpmn.sketch',
|
|
60
|
+
framework: 'bpmn',
|
|
61
|
+
labelKey: 'com.labre.bpmn.profile.sketch',
|
|
62
|
+
fallback: 'Sketch',
|
|
63
|
+
isDefault: true,
|
|
64
|
+
rules: {
|
|
65
|
+
'bpmn.sequence-flow-endpoints': 'audit',
|
|
66
|
+
'bpmn.sequence-flow-self-loop': 'audit',
|
|
67
|
+
'bpmn.message-flow-endpoints': 'audit',
|
|
68
|
+
'bpmn.association-endpoints': 'audit',
|
|
69
|
+
'bpmn.untyped-flow': 'audit',
|
|
70
|
+
'bpmn.duplicate-sequence-flow': 'audit',
|
|
71
|
+
'bpmn.start-event-no-inflow': 'audit',
|
|
72
|
+
'bpmn.start-event-must-exit': 'audit',
|
|
73
|
+
'bpmn.end-event-no-outflow': 'audit',
|
|
74
|
+
'bpmn.end-event-must-be-reached': 'audit',
|
|
75
|
+
'bpmn.activity-dead-end': 'audit',
|
|
76
|
+
'bpmn.sequence-flow-stays-home': 'audit',
|
|
77
|
+
'bpmn.message-flow-crosses-pools': 'audit',
|
|
78
|
+
'bpmn.unreachable-step': 'audit',
|
|
79
|
+
'bpmn.pool-end-without-start': 'audit',
|
|
80
|
+
'bpmn.pool-start-without-end': 'audit',
|
|
81
|
+
'bpmn.single-blank-start': 'audit',
|
|
82
|
+
'bpmn.gateway-must-branch': 'audit',
|
|
83
|
+
'bpmn.gateway-join-and-fork': 'audit',
|
|
84
|
+
'bpmn.fake-join': 'audit',
|
|
85
|
+
'bpmn.implicit-split': 'audit',
|
|
86
|
+
'bpmn.unlabeled-step': 'audit',
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Descriptive: the BPMN 2.0 DESCRIPTIVE conformance posture — a diagram a
|
|
91
|
+
* business reader can be handed and will read correctly.
|
|
92
|
+
*
|
|
93
|
+
* Every rule at the severity its own declaration carries, spelled out rather
|
|
94
|
+
* than left absent, so the answer is readable in one place. That is the point of
|
|
95
|
+
* a profile table: a reviewer asking "what does this level actually require"
|
|
96
|
+
* reads twenty-two lines instead of twenty-two files, and a rule added later
|
|
97
|
+
* cannot join
|
|
98
|
+
* a level silently — it arrives with its own severity until somebody writes it
|
|
99
|
+
* down here.
|
|
100
|
+
*
|
|
101
|
+
* ## Nothing is `blocking-overridable`, and one line each is what changes that
|
|
102
|
+
*
|
|
103
|
+
* Nothing in this library implements refusal — no gesture is declined anywhere —
|
|
104
|
+
* so declaring the level would be data claiming an effect that does not exist
|
|
105
|
+
* (the `wardley/rules.ts:30` promise, kept). FOUR rules would sit there the day
|
|
106
|
+
* a gesture refusal lands, and each moves in one line, here:
|
|
107
|
+
*
|
|
108
|
+
* - `bpmn.start-event-no-inflow` and `bpmn.end-event-no-outflow` (p.244 / p.248)
|
|
109
|
+
* — both say the process runs backwards, and neither has a reading in which
|
|
110
|
+
* the author is right;
|
|
111
|
+
* - `bpmn.pool-end-without-start` and `bpmn.pool-start-without-end` — verbatim
|
|
112
|
+
* normative MUSTs, guard included: "If there is an End Event, then there MUST
|
|
113
|
+
* be at least one Start Event" (p.238) and its mirror (p.246). The pack argued
|
|
114
|
+
* the pairing into existence before somebody read the pages; the specification
|
|
115
|
+
* simply states it.
|
|
116
|
+
*
|
|
117
|
+
* ## The five that do not move
|
|
118
|
+
*
|
|
119
|
+
* `bpmn.activity-dead-end`, `bpmn.fake-join`, `bpmn.implicit-split`,
|
|
120
|
+
* `bpmn.single-blank-start` and `bpmn.unlabeled-step` stay `audit` HERE TOO, and
|
|
121
|
+
* they are the reason a profile spells everything out.
|
|
122
|
+
*
|
|
123
|
+
* The first three report shapes the specification explicitly SANCTIONS: an
|
|
124
|
+
* activity with no outgoing sequence flow is a way to end a path (BPMN 2.0.2,
|
|
125
|
+
* p.151), and an activity with several incoming or several outgoing flows has
|
|
126
|
+
* defined token semantics on the same page. A warning would be the tool arguing
|
|
127
|
+
* with a house style the standard allows. They stay in the pack because on a
|
|
128
|
+
* diagram meant to be READ each of them is a question the drawing no longer asks
|
|
129
|
+
* out loud — which is a remark for the conformance panel, at every level of
|
|
130
|
+
* requirement. Every one of them is quieter than bpmnlint's own level for the
|
|
131
|
+
* same shape, deliberately.
|
|
132
|
+
*
|
|
133
|
+
* The last two report a diagram that is UNFINISHED rather than wrong — two
|
|
134
|
+
* indistinguishable blank starts, a step nobody has named — and "not done" is
|
|
135
|
+
* what a panel is for.
|
|
136
|
+
*
|
|
137
|
+
* The exact `context-map.acl-on-customer-supplier` shape, one layer over: a
|
|
138
|
+
* judgement the diagram cannot make on the author's behalf, so it is collected
|
|
139
|
+
* and never interrupts.
|
|
140
|
+
*
|
|
141
|
+
* ## Which line is which, now that a rule says so itself
|
|
142
|
+
*
|
|
143
|
+
* Every rule declares {@link ValidationRule.provenance}, so the question this
|
|
144
|
+
* table used to answer only in prose — is this a conformance defect or a
|
|
145
|
+
* suggestion — is readable off the rule. Twelve of them read a normative
|
|
146
|
+
* sentence of the standard, and those are not judgement calls: a message flow
|
|
147
|
+
* inside one pool is a sentence BPMN does not have. The other ten are a linter's
|
|
148
|
+
* rule, a reading nudge, or our own house style, and the bubble now says which
|
|
149
|
+
* before the user decides how much to care.
|
|
150
|
+
*/
|
|
151
|
+
const descriptive = {
|
|
152
|
+
id: 'bpmn.descriptive',
|
|
153
|
+
framework: 'bpmn',
|
|
154
|
+
labelKey: 'com.labre.bpmn.profile.descriptive',
|
|
155
|
+
fallback: 'Descriptive',
|
|
156
|
+
rules: {
|
|
157
|
+
'bpmn.sequence-flow-endpoints': 'warning',
|
|
158
|
+
// A LABRE convention (see B1a), and the one line of this table where that
|
|
159
|
+
// is worth knowing: an organisation that does not share the house style
|
|
160
|
+
// switches it off here without touching p.95, which is the whole point of
|
|
161
|
+
// having split it out of the endpoints rule.
|
|
162
|
+
'bpmn.sequence-flow-self-loop': 'warning',
|
|
163
|
+
'bpmn.message-flow-endpoints': 'warning',
|
|
164
|
+
'bpmn.association-endpoints': 'warning',
|
|
165
|
+
'bpmn.untyped-flow': 'warning',
|
|
166
|
+
'bpmn.duplicate-sequence-flow': 'warning',
|
|
167
|
+
'bpmn.start-event-no-inflow': 'warning',
|
|
168
|
+
'bpmn.start-event-must-exit': 'warning',
|
|
169
|
+
'bpmn.end-event-no-outflow': 'warning',
|
|
170
|
+
'bpmn.end-event-must-be-reached': 'warning',
|
|
171
|
+
// The five that do not move — see the header.
|
|
172
|
+
'bpmn.activity-dead-end': 'audit',
|
|
173
|
+
'bpmn.sequence-flow-stays-home': 'warning',
|
|
174
|
+
'bpmn.message-flow-crosses-pools': 'warning',
|
|
175
|
+
'bpmn.unreachable-step': 'warning',
|
|
176
|
+
'bpmn.pool-end-without-start': 'warning',
|
|
177
|
+
'bpmn.pool-start-without-end': 'warning',
|
|
178
|
+
'bpmn.single-blank-start': 'audit',
|
|
179
|
+
'bpmn.gateway-must-branch': 'warning',
|
|
180
|
+
'bpmn.gateway-join-and-fork': 'warning',
|
|
181
|
+
'bpmn.fake-join': 'audit',
|
|
182
|
+
'bpmn.implicit-split': 'audit',
|
|
183
|
+
'bpmn.unlabeled-step': 'audit',
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
export const BPMN_PROFILES = [
|
|
187
|
+
sketch,
|
|
188
|
+
descriptive,
|
|
189
|
+
];
|
package/dist/roles.d.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { BpmnNodeKind } from '@formicoidea/labre-core/model';
|
|
2
|
+
import type { RoleDefs, RoleId } from '@formicoidea/labre-core/std/gfx';
|
|
3
|
+
/**
|
|
4
|
+
* BPMN role vocabulary (B1).
|
|
5
|
+
*
|
|
6
|
+
* A role is the semantic identity of a BPMN artefact — no rule will ever look at
|
|
7
|
+
* a shape type, and none ever could here: the whole notation is drawn with three
|
|
8
|
+
* native shapes, and an ellipse is a start event, an end event or somebody's
|
|
9
|
+
* doodle depending entirely on what the author meant. The `kind` discriminant
|
|
10
|
+
* the pack already carries answers a different question (which glyph to paint);
|
|
11
|
+
* the role answers what the glyph MEANS.
|
|
12
|
+
*
|
|
13
|
+
* Hierarchy is DATA (`parent`), never TS inheritance: `bpmn:start-event` and
|
|
14
|
+
* `bpmn:end-event` specialise `bpmn:event`, so a rule written on the parent
|
|
15
|
+
* applies to both for free (see `roleIsA`). The three families were declared
|
|
16
|
+
* while the lean pack still shipped one or two children each, precisely so that
|
|
17
|
+
* the descriptive profile could land underneath them without a reshuffle — and
|
|
18
|
+
* that is what happened: the message and timer starts, the message and terminate
|
|
19
|
+
* ends, the user and service tasks, the sub-process, the call activity and the
|
|
20
|
+
* parallel gateway all arrived as LEAVES, and everything already written about
|
|
21
|
+
* "an event" or "an activity" stayed written.
|
|
22
|
+
*
|
|
23
|
+
* The tree is FOUR levels deep on two branches — `bpmn:message-start-event` is a
|
|
24
|
+
* `bpmn:start-event` is a `bpmn:event` is a `bpmn:flow-object`, and
|
|
25
|
+
* `bpmn:user-task` is a `bpmn:task` is a `bpmn:activity` is a
|
|
26
|
+
* `bpmn:flow-object` — which `roleIsA` walks for free.
|
|
27
|
+
*
|
|
28
|
+
* `bpmn:flow-object` arrived with the rules, for the reason its own block gives:
|
|
29
|
+
* a sequence flow chains flow objects and a step must be reachable from the
|
|
30
|
+
* start, and both sentences are about events, activities and gateways at once.
|
|
31
|
+
* It is the one word BPMN itself uses, so the rules say it once instead of
|
|
32
|
+
* enumerating three families and forgetting the fourth.
|
|
33
|
+
*
|
|
34
|
+
* The **pool** is parent-less on purpose, the same call `wardley:map` makes: it
|
|
35
|
+
* is the FRAME the flow objects are drawn in, and a rule written on the artefacts
|
|
36
|
+
* must never fall on the lane they sit in — nor, therefore, under
|
|
37
|
+
* `bpmn:flow-object`. `bpmn:data` is a family of its own for
|
|
38
|
+
* the same reason inverted: a data object is not a flow object, it is never
|
|
39
|
+
* executed, and a rule about the WORK must not fall on the paperwork. And the
|
|
40
|
+
* two artifacts — `bpmn:text-annotation` and `bpmn:group` — are parent-less AND
|
|
41
|
+
* childless, because they are what the author drew ON the picture rather than
|
|
42
|
+
* IN it: a note and a lasso, neither of which says anything the process does.
|
|
43
|
+
* The group's isolation is the spec's own (BPMN 2.0.2 §10.4 exempts it from
|
|
44
|
+
* every connection and containment constraint there is), and the tree is where
|
|
45
|
+
* that exemption is written down.
|
|
46
|
+
*
|
|
47
|
+
* ## Compatibility
|
|
48
|
+
*
|
|
49
|
+
* Nothing is backfilled. A process drawn before today carries nodes, pools and
|
|
50
|
+
* connectors with no role, so it is never evaluated and never says a word — the
|
|
51
|
+
* same promise every role in this library has made (PRD principle 8).
|
|
52
|
+
*/
|
|
53
|
+
/** Every role this framework declares. */
|
|
54
|
+
export type BpmnRole = 'flow-object' | 'event' | 'start-event' | 'message-start-event' | 'timer-start-event' | 'end-event' | 'message-end-event' | 'terminate-end-event' | 'activity' | 'task' | 'user-task' | 'service-task' | 'sub-process' | 'call-activity' | 'gateway' | 'gateway-exclusive' | 'parallel-gateway' | 'data' | 'data-object' | 'data-store' | 'text-annotation' | 'group' | 'pool' | 'sequence-flow' | 'message-flow' | 'association';
|
|
55
|
+
export type BpmnRoleId = `bpmn:${BpmnRole}`;
|
|
56
|
+
/** Role ids, keyed by the `kind` used at the creation sites. */
|
|
57
|
+
export declare const BPMN_ROLE: {
|
|
58
|
+
readonly flowObject: "bpmn:flow-object";
|
|
59
|
+
readonly event: "bpmn:event";
|
|
60
|
+
readonly startEvent: "bpmn:start-event";
|
|
61
|
+
readonly startEventMessage: "bpmn:message-start-event";
|
|
62
|
+
readonly startEventTimer: "bpmn:timer-start-event";
|
|
63
|
+
readonly endEvent: "bpmn:end-event";
|
|
64
|
+
readonly endEventMessage: "bpmn:message-end-event";
|
|
65
|
+
readonly endEventTerminate: "bpmn:terminate-end-event";
|
|
66
|
+
readonly activity: "bpmn:activity";
|
|
67
|
+
readonly task: "bpmn:task";
|
|
68
|
+
readonly taskUser: "bpmn:user-task";
|
|
69
|
+
readonly taskService: "bpmn:service-task";
|
|
70
|
+
readonly subProcess: "bpmn:sub-process";
|
|
71
|
+
readonly callActivity: "bpmn:call-activity";
|
|
72
|
+
readonly gateway: "bpmn:gateway";
|
|
73
|
+
readonly gatewayExclusive: "bpmn:gateway-exclusive";
|
|
74
|
+
readonly gatewayParallel: "bpmn:parallel-gateway";
|
|
75
|
+
readonly data: "bpmn:data";
|
|
76
|
+
readonly dataObject: "bpmn:data-object";
|
|
77
|
+
readonly dataStore: "bpmn:data-store";
|
|
78
|
+
readonly textAnnotation: "bpmn:text-annotation";
|
|
79
|
+
readonly group: "bpmn:group";
|
|
80
|
+
readonly pool: "bpmn:pool";
|
|
81
|
+
readonly sequenceFlow: "bpmn:sequence-flow";
|
|
82
|
+
readonly messageFlow: "bpmn:message-flow";
|
|
83
|
+
readonly association: "bpmn:association";
|
|
84
|
+
};
|
|
85
|
+
export declare const BPMN_ROLES: RoleDefs;
|
|
86
|
+
/**
|
|
87
|
+
* The legacy `kind` discriminant → the role it means.
|
|
88
|
+
*
|
|
89
|
+
* `kind` STAYS: it is persisted, it drives the renderer and it is what the
|
|
90
|
+
* palette writes. What it is not, from today, is the semantic authority — the
|
|
91
|
+
* ROLE is. The two are posted side by side at every creation site, the way
|
|
92
|
+
* Wardley already does it, and this table is the single place that says which
|
|
93
|
+
* kind means which role. Total over {@link BpmnNodeKind} by its type, so a new
|
|
94
|
+
* kind cannot land without being given a meaning.
|
|
95
|
+
*/
|
|
96
|
+
export declare const BPMN_ROLE_OF_KIND: Record<BpmnNodeKind, RoleId>;
|