@formicoidea/labre-framework-bpmn 0.32.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 +202 -6
- package/dist/actions.js +421 -43
- package/dist/background.d.ts +2 -0
- package/dist/background.js +158 -0
- package/dist/commands.js +496 -5
- package/dist/consts.d.ts +157 -3
- package/dist/consts.js +192 -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 +12 -0
- package/dist/index.js +44 -0
- 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-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 +3 -1
- package/dist/translations.js +8 -3
- package/dist/view.d.ts +6 -2
- package/dist/view.js +68 -5
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,14 @@
|
|
|
1
|
+
export { BPMN_POOL_BACKGROUND } from './background.js';
|
|
2
|
+
export { bpmnBoardOf } from './actions.js';
|
|
3
|
+
export { materializeBpmnImport, reportBpmnImport } from './actions.js';
|
|
1
4
|
export { bpmnCommandIcons, bpmnCommands } from './commands.js';
|
|
5
|
+
export { BPMN_FORMAT_ID, BPMN_NS, BPMN_XML_OF_KIND, type BpmnExportBoard, type BpmnExportOptions, type BpmnExportOutcome, type BpmnXmlMapping, exportBpmnXml, exportBpmnXmlWithWarnings, isNcName, toNcName, } from './export.js';
|
|
6
|
+
export { BPMN_KIND_OF_XML, BPMN_QUARANTINE_REASON, importBpmnXml, } from './import.js';
|
|
7
|
+
export { bpmnMorphClears, bpmnMorphProps, bpmnNodeProps, type BpmnNodePreset, NODE_PRESETS, } from './presets.js';
|
|
8
|
+
export { BPMN_MORPH_FAMILIES, BPMN_MORPH_SPEC } from './morph.js';
|
|
9
|
+
export { BPMN_INTERCHANGE, BPMN_SVG_FORMAT, BPMN_SVG_IMPORT, BPMN_XML_EXPORT, BPMN_XML_EXTENSION, BPMN_XML_IMPORT, BPMN_XML_FORMAT, BPMN_XML_MIME, bpmnBoardFrom, bpmnSafeFilename, } from './interchange.js';
|
|
10
|
+
export { bpmnLaneOf, bpmnPoolOf } from './facts.js';
|
|
11
|
+
export { BPMN_PROFILES } from './profiles.js';
|
|
12
|
+
export { BPMN_ROLE, BPMN_ROLE_OF_KIND, BPMN_ROLES, type BpmnRole, type BpmnRoleId, } from './roles.js';
|
|
13
|
+
export { BPMN_RULES, BPMN_SEQUENCE_MATRIX } from './rules.js';
|
|
2
14
|
export { bpmnTranslationEntries } from './translations.js';
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,46 @@
|
|
|
1
|
+
// The declaration IS the pool: what it looks like, where its plot is and how
|
|
2
|
+
// its lanes divide that plot are all read off this one value (`docs/adr/0009`
|
|
3
|
+
// on why a framework declares rather than draws). Exported so a host — and the
|
|
4
|
+
// audit's own consumers — can answer those questions without a canvas.
|
|
5
|
+
export { BPMN_POOL_BACKGROUND } from './background.js';
|
|
6
|
+
// Everything on the surface the exporter speaks about, in document order — the
|
|
7
|
+
// half of the export that needs an editor, kept apart from the half that does
|
|
8
|
+
// not so a host can substitute either.
|
|
9
|
+
export { bpmnBoardOf } from './actions.js';
|
|
10
|
+
// …and the mirror half of the import: the reader is pure, and THIS is the one
|
|
11
|
+
// thing its caller owes it — the surface mints ids, so a connector's endpoints
|
|
12
|
+
// arrive naming the source file's and are rewritten from the map the returned
|
|
13
|
+
// array already carries (`docs/adr/0012`, D3). Exported so the command, the
|
|
14
|
+
// chromium round trip and a host embedding the reader all write a board the
|
|
15
|
+
// same way.
|
|
16
|
+
export { materializeBpmnImport, reportBpmnImport } from './actions.js';
|
|
1
17
|
export { bpmnCommandIcons, bpmnCommands } from './commands.js';
|
|
18
|
+
// The board as a BPMN 2.0 interchange document. A pure function — element
|
|
19
|
+
// models in, XML out — so a host can export a board it never rendered, and the
|
|
20
|
+
// kind → element table it is built on is readable without running it.
|
|
21
|
+
export { BPMN_FORMAT_ID, BPMN_NS, BPMN_XML_OF_KIND, exportBpmnXml, exportBpmnXmlWithWarnings, isNcName, toNcName, } from './export.js';
|
|
22
|
+
// …and the same file, back as a board. A pure function too — text in, element
|
|
23
|
+
// PROPS out, never live models — so labre-mcp reads a `.bpmn` through the one
|
|
24
|
+
// implementation the editor reads it through (`docs/adr/0012`, P3).
|
|
25
|
+
export { BPMN_KIND_OF_XML, BPMN_QUARANTINE_REASON, importBpmnXml, } from './import.js';
|
|
26
|
+
// What an artefact is BORN as, shared by the palette and the importer so a task
|
|
27
|
+
// read out of a file and a task drawn by hand are one element in the document —
|
|
28
|
+
// and, since the morph, by the toolbar that says one artefact more precisely.
|
|
29
|
+
export { bpmnMorphClears, bpmnMorphProps, bpmnNodeProps, NODE_PRESETS, } from './presets.js';
|
|
30
|
+
// What an artefact may BECOME: the declared families, and the spec the generic
|
|
31
|
+
// morph module is registered with. Data a host can read without an editor.
|
|
32
|
+
export { BPMN_MORPH_FAMILIES, BPMN_MORPH_SPEC } from './morph.js';
|
|
33
|
+
// BPMN's entries in the interchange registry (`docs/adr/0012`) — `.bpmn` out,
|
|
34
|
+
// `.bpmn` in, and the visual-tier SVG fallback. Exported whole so a host can
|
|
35
|
+
// ask what BPMN can read and write without mounting an editor, and call it
|
|
36
|
+
// without one either.
|
|
37
|
+
export { BPMN_INTERCHANGE, BPMN_SVG_FORMAT, BPMN_SVG_IMPORT, BPMN_XML_EXPORT, BPMN_XML_EXTENSION, BPMN_XML_IMPORT, BPMN_XML_FORMAT, BPMN_XML_MIME, bpmnBoardFrom, bpmnSafeFilename, } from './interchange.js';
|
|
38
|
+
// Where an artefact sits, without a `BlockStdScope`: the same pool and lane
|
|
39
|
+
// attribution the audit computes, answerable by a rule, a host or a test.
|
|
40
|
+
export { bpmnLaneOf, bpmnPoolOf } from './facts.js';
|
|
41
|
+
// The levels of requirement, and the rules they arbitrate: DATA a host can read,
|
|
42
|
+
// ship and reason about without an editor.
|
|
43
|
+
export { BPMN_PROFILES } from './profiles.js';
|
|
44
|
+
export { BPMN_ROLE, BPMN_ROLE_OF_KIND, BPMN_ROLES, } from './roles.js';
|
|
45
|
+
export { BPMN_RULES, BPMN_SEQUENCE_MATRIX } from './rules.js';
|
|
2
46
|
export { bpmnTranslationEntries } from './translations.js';
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import type { InterchangeCapability, InterchangeExportCapability, InterchangeFormat, InterchangeImportCapability } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import type { GfxPrimitiveElementModel } from '@formicoidea/labre-core/std/gfx';
|
|
3
|
+
import { type BpmnExportBoard } from './export.js';
|
|
4
|
+
/**
|
|
5
|
+
* BPMN's entries in the interchange registry (`docs/adr/0012`, P1).
|
|
6
|
+
*
|
|
7
|
+
* Both directions of one format, declared as two capabilities and not as one
|
|
8
|
+
* symmetric thing: `.bpmn` OUT shipped in #149, `.bpmn` IN is the worked
|
|
9
|
+
* example D1–D6 specifies, and each makes its own promises. The registry says
|
|
10
|
+
* so in the only way it can — a row per triple.
|
|
11
|
+
*
|
|
12
|
+
* They share the FORMAT object, deliberately. `bpmn` is the id under which
|
|
13
|
+
* foreign matter rides on an element (D2), so a reader and a writer that
|
|
14
|
+
* disagreed about it would write payloads the other could not find; there is
|
|
15
|
+
* one `BPMN_XML_FORMAT` and both point at it.
|
|
16
|
+
*
|
|
17
|
+
* Everything here is pure. Neither serializer nor parser has ever had a `std`
|
|
18
|
+
* in sight, and this file adds no editor to either: it picks the artefacts the
|
|
19
|
+
* writer speaks about out of a surface's elements, and hands the reader's
|
|
20
|
+
* output straight back to whoever asked for it.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* BPMN 2.0 XML. **Semantic** — the file carries a model, not a picture, so it
|
|
24
|
+
* takes the whole preservation contract the day an importer is written.
|
|
25
|
+
*
|
|
26
|
+
* `application/xml` and not `text/xml`: the file is not meant to be read as
|
|
27
|
+
* text by whatever opens it, and `.bpmn` is the extension every BPMN tool
|
|
28
|
+
* watches for.
|
|
29
|
+
*
|
|
30
|
+
* `.xml` rides along BEHIND it, and the order is the whole of the difference:
|
|
31
|
+
* the first extension is the one a download is given, so Labre still writes
|
|
32
|
+
* `.bpmn`, and the rest are what a picker offers and what an auto-detecting
|
|
33
|
+
* host indexes on. Half the tools in the wild write the same bytes under the
|
|
34
|
+
* generic extension, and a filter that refused them would refuse a valid
|
|
35
|
+
* process for the sake of a filename — the same argument the shared `FileTypes`
|
|
36
|
+
* table made when this filter lived there, kept now that the filter is built
|
|
37
|
+
* from the format itself. What the file actually IS is decided by the reader,
|
|
38
|
+
* which throws on anything that is not a BPMN `<definitions>`.
|
|
39
|
+
*/
|
|
40
|
+
export declare const BPMN_XML_EXTENSION = ".bpmn";
|
|
41
|
+
export declare const BPMN_XML_MIME = "application/xml";
|
|
42
|
+
export declare const BPMN_XML_FORMAT: InterchangeFormat;
|
|
43
|
+
/**
|
|
44
|
+
* The artefacts the exporter speaks about, picked out of a surface's elements
|
|
45
|
+
* and kept in the order they were given.
|
|
46
|
+
*
|
|
47
|
+
* Document order matters twice and both times for the same reason: `bpmnPoolOf`
|
|
48
|
+
* gives a centre inside two overlapping pools to the FIRST one, and the audit's
|
|
49
|
+
* `attribute()` does the same. Sorting here would make the export disagree with
|
|
50
|
+
* the badge the user can see.
|
|
51
|
+
*/
|
|
52
|
+
export declare function bpmnBoardFrom(elements: readonly GfxPrimitiveElementModel[]): BpmnExportBoard;
|
|
53
|
+
/**
|
|
54
|
+
* A name a file system will accept, minus the extension.
|
|
55
|
+
*
|
|
56
|
+
* Every character a file system reserves becomes `-`, whitespace runs collapse,
|
|
57
|
+
* and the result is capped: `process` is a better download than one a browser
|
|
58
|
+
* silently refuses.
|
|
59
|
+
*
|
|
60
|
+
* The trailing `[. ]` trim is the Windows tail case and it is not decorative: a
|
|
61
|
+
* board called "Order to cash." would otherwise download as
|
|
62
|
+
* `Order to cash..bpmn`, and Windows strips trailing dots and spaces from a
|
|
63
|
+
* name anyway — so the extension is what would get eaten. Trimmed AFTER the
|
|
64
|
+
* cap, because the cap can create one.
|
|
65
|
+
*/
|
|
66
|
+
export declare function bpmnSafeFilename(raw: string | undefined): string;
|
|
67
|
+
/** `bpmn:bpmn:export` — the registry's first capability. */
|
|
68
|
+
export declare const BPMN_XML_EXPORT: InterchangeExportCapability;
|
|
69
|
+
/**
|
|
70
|
+
* `bpmn:bpmn:import` — a `.bpmn` file as a board.
|
|
71
|
+
*
|
|
72
|
+
* A thin adapter over {@link importBpmnXml} and nothing else, which is the
|
|
73
|
+
* whole of what a capability is: the parser is a pure function of a string, so
|
|
74
|
+
* the registry entry has nothing to add to it and deliberately adds nothing.
|
|
75
|
+
* A reader that threw its arms around a surface here would be a reader
|
|
76
|
+
* labre-mcp could not call.
|
|
77
|
+
*/
|
|
78
|
+
export declare const BPMN_XML_IMPORT: InterchangeImportCapability;
|
|
79
|
+
/**
|
|
80
|
+
* SVG. **Visual** — the file carries a rendering, not a model.
|
|
81
|
+
*
|
|
82
|
+
* A separate format object from `BPMN_XML_FORMAT` and deliberately not a shared
|
|
83
|
+
* singleton with Wardley's: ADR 0012's unit is the TRIPLE, and the ADR
|
|
84
|
+
* explicitly rejects "one capability per format, with the framework inferred
|
|
85
|
+
* from the file" — a `.svg` is read by several frameworks and the inference is
|
|
86
|
+
* exactly the guess the ADR forbids everywhere else. The three constants come
|
|
87
|
+
* from the parser's own package so the two declarations cannot drift into
|
|
88
|
+
* disagreeing about the extension or the mime a picker filters on.
|
|
89
|
+
*/
|
|
90
|
+
export declare const BPMN_SVG_FORMAT: InterchangeFormat;
|
|
91
|
+
/**
|
|
92
|
+
* `bpmn:svg:import` — an SVG as a sketch, best effort.
|
|
93
|
+
*
|
|
94
|
+
* **The heuristics statement and the known failure modes this capability owes
|
|
95
|
+
* (ADR 0012, open question 2) are the module documentation of
|
|
96
|
+
* `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** They are
|
|
97
|
+
* written once, there, because BPMN and Wardley wrap the SAME parser and
|
|
98
|
+
* therefore make the same guesses; a framework that ever wants narrower or
|
|
99
|
+
* wider recognition writes its own parser and its own paragraph beside it.
|
|
100
|
+
*
|
|
101
|
+
* What lands is a level-1 sketch (ADR 0007) — plain shapes, brush strokes and
|
|
102
|
+
* editable free text — that the author then PROMOTES into BPMN artefacts.
|
|
103
|
+
* Nothing here decides that a rounded rectangle in somebody's picture was a
|
|
104
|
+
* task, and no `interchange` payload is written, because a visual round-trip
|
|
105
|
+
* would be a re-render (P2).
|
|
106
|
+
*/
|
|
107
|
+
export declare const BPMN_SVG_IMPORT: InterchangeImportCapability;
|
|
108
|
+
/** Everything BPMN registers, in one list the view extension can hand over. */
|
|
109
|
+
export declare const BPMN_INTERCHANGE: readonly InterchangeCapability[];
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { interchangeCapabilityId, parseSvgSketch, SVG_SKETCH_EXTENSION, SVG_SKETCH_FORMAT_ID, SVG_SKETCH_MIME, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { BpmnNodeElementModel, BpmnPoolElementModel, ConnectorElementModel, } from '@formicoidea/labre-core/model';
|
|
3
|
+
import { BPMN_FORMAT_ID, exportBpmnXmlWithWarnings, } from './export.js';
|
|
4
|
+
import { importBpmnXml } from './import.js';
|
|
5
|
+
/**
|
|
6
|
+
* BPMN's entries in the interchange registry (`docs/adr/0012`, P1).
|
|
7
|
+
*
|
|
8
|
+
* Both directions of one format, declared as two capabilities and not as one
|
|
9
|
+
* symmetric thing: `.bpmn` OUT shipped in #149, `.bpmn` IN is the worked
|
|
10
|
+
* example D1–D6 specifies, and each makes its own promises. The registry says
|
|
11
|
+
* so in the only way it can — a row per triple.
|
|
12
|
+
*
|
|
13
|
+
* They share the FORMAT object, deliberately. `bpmn` is the id under which
|
|
14
|
+
* foreign matter rides on an element (D2), so a reader and a writer that
|
|
15
|
+
* disagreed about it would write payloads the other could not find; there is
|
|
16
|
+
* one `BPMN_XML_FORMAT` and both point at it.
|
|
17
|
+
*
|
|
18
|
+
* Everything here is pure. Neither serializer nor parser has ever had a `std`
|
|
19
|
+
* in sight, and this file adds no editor to either: it picks the artefacts the
|
|
20
|
+
* writer speaks about out of a surface's elements, and hands the reader's
|
|
21
|
+
* output straight back to whoever asked for it.
|
|
22
|
+
*/
|
|
23
|
+
/* ── The format ───────────────────────────────────────────────────────── */
|
|
24
|
+
/**
|
|
25
|
+
* BPMN 2.0 XML. **Semantic** — the file carries a model, not a picture, so it
|
|
26
|
+
* takes the whole preservation contract the day an importer is written.
|
|
27
|
+
*
|
|
28
|
+
* `application/xml` and not `text/xml`: the file is not meant to be read as
|
|
29
|
+
* text by whatever opens it, and `.bpmn` is the extension every BPMN tool
|
|
30
|
+
* watches for.
|
|
31
|
+
*
|
|
32
|
+
* `.xml` rides along BEHIND it, and the order is the whole of the difference:
|
|
33
|
+
* the first extension is the one a download is given, so Labre still writes
|
|
34
|
+
* `.bpmn`, and the rest are what a picker offers and what an auto-detecting
|
|
35
|
+
* host indexes on. Half the tools in the wild write the same bytes under the
|
|
36
|
+
* generic extension, and a filter that refused them would refuse a valid
|
|
37
|
+
* process for the sake of a filename — the same argument the shared `FileTypes`
|
|
38
|
+
* table made when this filter lived there, kept now that the filter is built
|
|
39
|
+
* from the format itself. What the file actually IS is decided by the reader,
|
|
40
|
+
* which throws on anything that is not a BPMN `<definitions>`.
|
|
41
|
+
*/
|
|
42
|
+
export const BPMN_XML_EXTENSION = '.bpmn';
|
|
43
|
+
export const BPMN_XML_MIME = 'application/xml';
|
|
44
|
+
export const BPMN_XML_FORMAT = {
|
|
45
|
+
id: BPMN_FORMAT_ID,
|
|
46
|
+
tier: 'semantic',
|
|
47
|
+
extensions: [BPMN_XML_EXTENSION, '.xml'],
|
|
48
|
+
mime: BPMN_XML_MIME,
|
|
49
|
+
};
|
|
50
|
+
/* ── Pure board helpers ───────────────────────────────────────────────── */
|
|
51
|
+
/**
|
|
52
|
+
* The artefacts the exporter speaks about, picked out of a surface's elements
|
|
53
|
+
* and kept in the order they were given.
|
|
54
|
+
*
|
|
55
|
+
* Document order matters twice and both times for the same reason: `bpmnPoolOf`
|
|
56
|
+
* gives a centre inside two overlapping pools to the FIRST one, and the audit's
|
|
57
|
+
* `attribute()` does the same. Sorting here would make the export disagree with
|
|
58
|
+
* the badge the user can see.
|
|
59
|
+
*/
|
|
60
|
+
export function bpmnBoardFrom(elements) {
|
|
61
|
+
const pools = [];
|
|
62
|
+
const nodes = [];
|
|
63
|
+
const connectors = [];
|
|
64
|
+
for (const element of elements) {
|
|
65
|
+
if (element instanceof BpmnPoolElementModel)
|
|
66
|
+
pools.push(element);
|
|
67
|
+
else if (element instanceof BpmnNodeElementModel)
|
|
68
|
+
nodes.push(element);
|
|
69
|
+
else if (element instanceof ConnectorElementModel)
|
|
70
|
+
connectors.push(element);
|
|
71
|
+
}
|
|
72
|
+
return { pools, nodes, connectors };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A name a file system will accept, minus the extension.
|
|
76
|
+
*
|
|
77
|
+
* Every character a file system reserves becomes `-`, whitespace runs collapse,
|
|
78
|
+
* and the result is capped: `process` is a better download than one a browser
|
|
79
|
+
* silently refuses.
|
|
80
|
+
*
|
|
81
|
+
* The trailing `[. ]` trim is the Windows tail case and it is not decorative: a
|
|
82
|
+
* board called "Order to cash." would otherwise download as
|
|
83
|
+
* `Order to cash..bpmn`, and Windows strips trailing dots and spaces from a
|
|
84
|
+
* name anyway — so the extension is what would get eaten. Trimmed AFTER the
|
|
85
|
+
* cap, because the cap can create one.
|
|
86
|
+
*/
|
|
87
|
+
export function bpmnSafeFilename(raw) {
|
|
88
|
+
const safe = (raw ?? '')
|
|
89
|
+
.trim()
|
|
90
|
+
.replaceAll(/[\\/:*?"<>|]/g, '-')
|
|
91
|
+
.replaceAll(/\s+/g, ' ')
|
|
92
|
+
.trim()
|
|
93
|
+
.slice(0, 120)
|
|
94
|
+
.replace(/[. ]+$/, '');
|
|
95
|
+
return safe || 'process';
|
|
96
|
+
}
|
|
97
|
+
/* ── The capability ───────────────────────────────────────────────────── */
|
|
98
|
+
/**
|
|
99
|
+
* The board as a BPMN 2.0 interchange document.
|
|
100
|
+
*
|
|
101
|
+
* A thin adapter and nothing else: it splits the surface into the three lists
|
|
102
|
+
* {@link exportBpmnXmlWithWarnings} takes, names the file, and passes the
|
|
103
|
+
* writer's losses straight through. There is no second door — `bpmn.exportXml`
|
|
104
|
+
* calls THIS, so the command and the registry cannot produce different bytes,
|
|
105
|
+
* different filenames or different warnings: there is nowhere for them to
|
|
106
|
+
* differ.
|
|
107
|
+
*
|
|
108
|
+
* `warnings` is omitted rather than empty when the board came out whole, so a
|
|
109
|
+
* caller can ask `if (result.warnings)` and mean it.
|
|
110
|
+
*/
|
|
111
|
+
const runBpmnXmlExport = (elements, context) => {
|
|
112
|
+
const name = bpmnSafeFilename(context.name);
|
|
113
|
+
const { text, warnings } = exportBpmnXmlWithWarnings(bpmnBoardFrom(elements), { name });
|
|
114
|
+
return {
|
|
115
|
+
text,
|
|
116
|
+
filename: `${name}${BPMN_XML_EXTENSION}`,
|
|
117
|
+
mime: BPMN_XML_MIME,
|
|
118
|
+
...(warnings.length > 0 ? { warnings } : {}),
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
/** `bpmn:bpmn:export` — the registry's first capability. */
|
|
122
|
+
export const BPMN_XML_EXPORT = {
|
|
123
|
+
id: interchangeCapabilityId('bpmn', BPMN_XML_FORMAT.id, 'export'),
|
|
124
|
+
framework: 'bpmn',
|
|
125
|
+
format: BPMN_XML_FORMAT,
|
|
126
|
+
direction: 'export',
|
|
127
|
+
run: runBpmnXmlExport,
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* `bpmn:bpmn:import` — a `.bpmn` file as a board.
|
|
131
|
+
*
|
|
132
|
+
* A thin adapter over {@link importBpmnXml} and nothing else, which is the
|
|
133
|
+
* whole of what a capability is: the parser is a pure function of a string, so
|
|
134
|
+
* the registry entry has nothing to add to it and deliberately adds nothing.
|
|
135
|
+
* A reader that threw its arms around a surface here would be a reader
|
|
136
|
+
* labre-mcp could not call.
|
|
137
|
+
*/
|
|
138
|
+
export const BPMN_XML_IMPORT = {
|
|
139
|
+
id: interchangeCapabilityId('bpmn', BPMN_XML_FORMAT.id, 'import'),
|
|
140
|
+
framework: 'bpmn',
|
|
141
|
+
format: BPMN_XML_FORMAT,
|
|
142
|
+
direction: 'import',
|
|
143
|
+
run: importBpmnXml,
|
|
144
|
+
};
|
|
145
|
+
/* ── The visual tier ──────────────────────────────────────────────────── */
|
|
146
|
+
/**
|
|
147
|
+
* SVG. **Visual** — the file carries a rendering, not a model.
|
|
148
|
+
*
|
|
149
|
+
* A separate format object from `BPMN_XML_FORMAT` and deliberately not a shared
|
|
150
|
+
* singleton with Wardley's: ADR 0012's unit is the TRIPLE, and the ADR
|
|
151
|
+
* explicitly rejects "one capability per format, with the framework inferred
|
|
152
|
+
* from the file" — a `.svg` is read by several frameworks and the inference is
|
|
153
|
+
* exactly the guess the ADR forbids everywhere else. The three constants come
|
|
154
|
+
* from the parser's own package so the two declarations cannot drift into
|
|
155
|
+
* disagreeing about the extension or the mime a picker filters on.
|
|
156
|
+
*/
|
|
157
|
+
export const BPMN_SVG_FORMAT = {
|
|
158
|
+
id: SVG_SKETCH_FORMAT_ID,
|
|
159
|
+
tier: 'visual',
|
|
160
|
+
extensions: [SVG_SKETCH_EXTENSION],
|
|
161
|
+
mime: SVG_SKETCH_MIME,
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* `bpmn:svg:import` — an SVG as a sketch, best effort.
|
|
165
|
+
*
|
|
166
|
+
* **The heuristics statement and the known failure modes this capability owes
|
|
167
|
+
* (ADR 0012, open question 2) are the module documentation of
|
|
168
|
+
* `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** They are
|
|
169
|
+
* written once, there, because BPMN and Wardley wrap the SAME parser and
|
|
170
|
+
* therefore make the same guesses; a framework that ever wants narrower or
|
|
171
|
+
* wider recognition writes its own parser and its own paragraph beside it.
|
|
172
|
+
*
|
|
173
|
+
* What lands is a level-1 sketch (ADR 0007) — plain shapes, brush strokes and
|
|
174
|
+
* editable free text — that the author then PROMOTES into BPMN artefacts.
|
|
175
|
+
* Nothing here decides that a rounded rectangle in somebody's picture was a
|
|
176
|
+
* task, and no `interchange` payload is written, because a visual round-trip
|
|
177
|
+
* would be a re-render (P2).
|
|
178
|
+
*/
|
|
179
|
+
export const BPMN_SVG_IMPORT = {
|
|
180
|
+
id: interchangeCapabilityId('bpmn', BPMN_SVG_FORMAT.id, 'import'),
|
|
181
|
+
framework: 'bpmn',
|
|
182
|
+
format: BPMN_SVG_FORMAT,
|
|
183
|
+
direction: 'import',
|
|
184
|
+
run: parseSvgSketch,
|
|
185
|
+
};
|
|
186
|
+
/** Everything BPMN registers, in one list the view extension can hand over. */
|
|
187
|
+
export const BPMN_INTERCHANGE = [
|
|
188
|
+
BPMN_XML_EXPORT,
|
|
189
|
+
BPMN_XML_IMPORT,
|
|
190
|
+
BPMN_SVG_IMPORT,
|
|
191
|
+
];
|
package/dist/morph.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type MorphSpec } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { type BpmnNodeKind } from '@formicoidea/labre-core/model';
|
|
3
|
+
/**
|
|
4
|
+
* What a BPMN artefact may BECOME — the declaration behind the "Change type"
|
|
5
|
+
* dropdown on a selected node's contextual toolbar.
|
|
6
|
+
*
|
|
7
|
+
* ## Families, and why they are a table
|
|
8
|
+
*
|
|
9
|
+
* A user task IS a task, said more precisely; a timer start IS a start event
|
|
10
|
+
* that names its trigger. Realising halfway through a draft that the rectangle
|
|
11
|
+
* should have been a user task is modelling, not a mistake — but the only way
|
|
12
|
+
* through it today is delete, re-draw, re-connect and re-type the label, which
|
|
13
|
+
* loses every sequence flow attached to the node.
|
|
14
|
+
*
|
|
15
|
+
* The six families below are DATA and nothing derives them. The role tree would
|
|
16
|
+
* have been the obvious source and it is the wrong one: `roleIsA` makes
|
|
17
|
+
* `bpmn:task` and `bpmn:sub-process` both `bpmn:activity`, so a derivation
|
|
18
|
+
* would offer "turn this task into a sub-process" — a swap between an atomic
|
|
19
|
+
* unit of work and a stand-in for a whole process, which is not the same
|
|
20
|
+
* artefact said more precisely but a different claim about the process. A
|
|
21
|
+
* reader has to accept the pair, and only a human knows which pairs a reader
|
|
22
|
+
* accepts.
|
|
23
|
+
*
|
|
24
|
+
* Each family is closed under "the same thing, more or less specific":
|
|
25
|
+
*
|
|
26
|
+
* - the three tasks — plain, and the two that say WHO performs the work;
|
|
27
|
+
* - the three starts and the three ends — plain, and the variants that say what
|
|
28
|
+
* triggers the one and what the other does on the way out;
|
|
29
|
+
* - the two gateways — the same diamond, and the marker is the whole difference;
|
|
30
|
+
* - the two data artefacts — a data object dies with the process instance, a
|
|
31
|
+
* data store outlives it, and both are the paperwork rather than the work;
|
|
32
|
+
* - the sub-process and the call activity — the two ways of standing for a
|
|
33
|
+
* whole process, one defined inline and one defined elsewhere. They are each
|
|
34
|
+
* other's neighbour and neither is a task.
|
|
35
|
+
*
|
|
36
|
+
* ## The two kinds with no family, deliberately
|
|
37
|
+
*
|
|
38
|
+
* `textAnnotation` and `group` are what the author drew ON the picture rather
|
|
39
|
+
* than IN it (BPMN 2.0.2 §10.4), and there is nothing either of them could
|
|
40
|
+
* become without ceasing to be commentary. They are in no family, so a
|
|
41
|
+
* selection holding one offers no menu at all — which is the same isolation
|
|
42
|
+
* `roles.ts` already gives them in the role tree.
|
|
43
|
+
*/
|
|
44
|
+
export declare const BPMN_MORPH_FAMILIES: readonly (readonly BpmnNodeKind[])[];
|
|
45
|
+
/**
|
|
46
|
+
* BPMN's morph declaration, handed to the generic `morphToolbarConfig`.
|
|
47
|
+
*
|
|
48
|
+
* `propsOf` is the shipped creation builder minus `type` / `xywh` / `text`
|
|
49
|
+
* ({@link bpmnMorphProps}) and `clearOf` the keys the target does not write
|
|
50
|
+
* ({@link bpmnMorphClears}) — both live in `presets.ts`, beside the one
|
|
51
|
+
* description of what a BPMN node IS, precisely so that a morph and a creation
|
|
52
|
+
* can never disagree about what a `callActivity` looks like.
|
|
53
|
+
*
|
|
54
|
+
* That pair is the one place the FULL preset earns its keep on today's table:
|
|
55
|
+
* `subProcess` and `callActivity` differ only in `strokeWidth` (2 ⇄ 4), and the
|
|
56
|
+
* thick border is the whole distinction. Every other family here shares one
|
|
57
|
+
* preset across its members, so the rest of the patch is inert — kept anyway,
|
|
58
|
+
* because a family grows by DECLARATION and nobody would be prompted to check
|
|
59
|
+
* the presets on the day one gains a member that styles itself differently.
|
|
60
|
+
*/
|
|
61
|
+
export declare const BPMN_MORPH_SPEC: MorphSpec<BpmnNodeKind>;
|
package/dist/morph.js
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { morphLabel, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
|
+
import { BpmnNodeElementModel } from '@formicoidea/labre-core/model';
|
|
3
|
+
import { bpmnCommandIcons, bpmnCommands } from './commands.js';
|
|
4
|
+
import { bpmnMorphClears, bpmnMorphProps } from './presets.js';
|
|
5
|
+
import { BPMN_ROLE_OF_KIND } from './roles.js';
|
|
6
|
+
/**
|
|
7
|
+
* What a BPMN artefact may BECOME — the declaration behind the "Change type"
|
|
8
|
+
* dropdown on a selected node's contextual toolbar.
|
|
9
|
+
*
|
|
10
|
+
* ## Families, and why they are a table
|
|
11
|
+
*
|
|
12
|
+
* A user task IS a task, said more precisely; a timer start IS a start event
|
|
13
|
+
* that names its trigger. Realising halfway through a draft that the rectangle
|
|
14
|
+
* should have been a user task is modelling, not a mistake — but the only way
|
|
15
|
+
* through it today is delete, re-draw, re-connect and re-type the label, which
|
|
16
|
+
* loses every sequence flow attached to the node.
|
|
17
|
+
*
|
|
18
|
+
* The six families below are DATA and nothing derives them. The role tree would
|
|
19
|
+
* have been the obvious source and it is the wrong one: `roleIsA` makes
|
|
20
|
+
* `bpmn:task` and `bpmn:sub-process` both `bpmn:activity`, so a derivation
|
|
21
|
+
* would offer "turn this task into a sub-process" — a swap between an atomic
|
|
22
|
+
* unit of work and a stand-in for a whole process, which is not the same
|
|
23
|
+
* artefact said more precisely but a different claim about the process. A
|
|
24
|
+
* reader has to accept the pair, and only a human knows which pairs a reader
|
|
25
|
+
* accepts.
|
|
26
|
+
*
|
|
27
|
+
* Each family is closed under "the same thing, more or less specific":
|
|
28
|
+
*
|
|
29
|
+
* - the three tasks — plain, and the two that say WHO performs the work;
|
|
30
|
+
* - the three starts and the three ends — plain, and the variants that say what
|
|
31
|
+
* triggers the one and what the other does on the way out;
|
|
32
|
+
* - the two gateways — the same diamond, and the marker is the whole difference;
|
|
33
|
+
* - the two data artefacts — a data object dies with the process instance, a
|
|
34
|
+
* data store outlives it, and both are the paperwork rather than the work;
|
|
35
|
+
* - the sub-process and the call activity — the two ways of standing for a
|
|
36
|
+
* whole process, one defined inline and one defined elsewhere. They are each
|
|
37
|
+
* other's neighbour and neither is a task.
|
|
38
|
+
*
|
|
39
|
+
* ## The two kinds with no family, deliberately
|
|
40
|
+
*
|
|
41
|
+
* `textAnnotation` and `group` are what the author drew ON the picture rather
|
|
42
|
+
* than IN it (BPMN 2.0.2 §10.4), and there is nothing either of them could
|
|
43
|
+
* become without ceasing to be commentary. They are in no family, so a
|
|
44
|
+
* selection holding one offers no menu at all — which is the same isolation
|
|
45
|
+
* `roles.ts` already gives them in the role tree.
|
|
46
|
+
*/
|
|
47
|
+
export const BPMN_MORPH_FAMILIES = [
|
|
48
|
+
// Declaration order is menu order, and it opens on the plain member of each
|
|
49
|
+
// family: the undecorated artefact is the honest first draft, and the variant
|
|
50
|
+
// is the refinement — the same call `commands.ts` makes about the senior row.
|
|
51
|
+
['task', 'taskUser', 'taskService'],
|
|
52
|
+
['startEvent', 'startEventMessage', 'startEventTimer'],
|
|
53
|
+
['endEvent', 'endEventMessage', 'endEventTerminate'],
|
|
54
|
+
['gatewayExclusive', 'gatewayParallel'],
|
|
55
|
+
['dataObject', 'dataStore'],
|
|
56
|
+
['subProcess', 'callActivity'],
|
|
57
|
+
];
|
|
58
|
+
/**
|
|
59
|
+
* The creation command that draws each kind, keyed BY that kind.
|
|
60
|
+
*
|
|
61
|
+
* Derived from `telemetry.element`, which is where the kind is already written
|
|
62
|
+
* down (`node:taskUser`) and is documented as a historical value that must not
|
|
63
|
+
* be renamed. Deriving rather than restating is what stops a second table of
|
|
64
|
+
* labels and icons drifting from the one the palette and the catalogue read: a
|
|
65
|
+
* kind whose command is renamed, re-iconed or re-worded changes here for free,
|
|
66
|
+
* and a kind with no creation command at all simply falls back to its own name.
|
|
67
|
+
*/
|
|
68
|
+
const NODE_COMMANDS = new Map(bpmnCommands.flatMap(command => {
|
|
69
|
+
const element = command.telemetry?.element;
|
|
70
|
+
return element?.startsWith('node:')
|
|
71
|
+
? [[element.slice('node:'.length), command]]
|
|
72
|
+
: [];
|
|
73
|
+
}));
|
|
74
|
+
/**
|
|
75
|
+
* A kind's wording: the creation command's own key and English, so the dropdown
|
|
76
|
+
* says "User task" in whatever the host's catalogue says it in, and says
|
|
77
|
+
* exactly what the palette entry that draws one says.
|
|
78
|
+
*/
|
|
79
|
+
function labelOf(kind) {
|
|
80
|
+
const command = NODE_COMMANDS.get(kind);
|
|
81
|
+
return {
|
|
82
|
+
key: command?.labelKey,
|
|
83
|
+
fallback: command?.labelFallback ?? kind,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** A kind's icon: the creation command's own, reused rather than redrawn. */
|
|
87
|
+
function iconOf(kind) {
|
|
88
|
+
const iconKey = NODE_COMMANDS.get(kind)?.iconKey;
|
|
89
|
+
return ((iconKey && bpmnCommandIcons[iconKey]) || bpmnCommandIcons['bpmn.task']);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* BPMN's morph declaration, handed to the generic `morphToolbarConfig`.
|
|
93
|
+
*
|
|
94
|
+
* `propsOf` is the shipped creation builder minus `type` / `xywh` / `text`
|
|
95
|
+
* ({@link bpmnMorphProps}) and `clearOf` the keys the target does not write
|
|
96
|
+
* ({@link bpmnMorphClears}) — both live in `presets.ts`, beside the one
|
|
97
|
+
* description of what a BPMN node IS, precisely so that a morph and a creation
|
|
98
|
+
* can never disagree about what a `callActivity` looks like.
|
|
99
|
+
*
|
|
100
|
+
* That pair is the one place the FULL preset earns its keep on today's table:
|
|
101
|
+
* `subProcess` and `callActivity` differ only in `strokeWidth` (2 ⇄ 4), and the
|
|
102
|
+
* thick border is the whole distinction. Every other family here shares one
|
|
103
|
+
* preset across its members, so the rest of the patch is inert — kept anyway,
|
|
104
|
+
* because a family grows by DECLARATION and nobody would be prompted to check
|
|
105
|
+
* the presets on the day one gains a member that styles itself differently.
|
|
106
|
+
*/
|
|
107
|
+
export const BPMN_MORPH_SPEC = {
|
|
108
|
+
framework: 'bpmn',
|
|
109
|
+
families: BPMN_MORPH_FAMILIES,
|
|
110
|
+
modelType: BpmnNodeElementModel,
|
|
111
|
+
kindOf: (model) => model instanceof BpmnNodeElementModel ? model.kind : undefined,
|
|
112
|
+
roleOf: kind => BPMN_ROLE_OF_KIND[kind],
|
|
113
|
+
propsOf: bpmnMorphProps,
|
|
114
|
+
clearOf: bpmnMorphClears,
|
|
115
|
+
labelOf,
|
|
116
|
+
iconOf,
|
|
117
|
+
label: morphLabel('com.labre.morph.toolbar.label', 'Change type'),
|
|
118
|
+
};
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import { type ElementRenderer } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import { type BpmnNodeElementModel } from '@formicoidea/labre-core/model';
|
|
3
|
-
/**
|
|
4
|
-
* Renderer for a BPMN flow-object node. The shape body (ellipse / rounded rect
|
|
5
|
-
* / diamond) is drawn by REUSING the native shape renderer — so stroke width,
|
|
6
|
-
* colors, inner text and theme behave exactly like a native shape. Only
|
|
7
|
-
* `gatewayExclusive` is decorated: an X drawn on top in the node's (editable)
|
|
8
|
-
* stroke color. Events and task are plain native shapes.
|
|
9
|
-
*
|
|
10
|
-
* Mirrors the EDGY node renderer.
|
|
11
|
-
*/
|
|
12
3
|
export declare const bpmnNode: ElementRenderer<BpmnNodeElementModel>;
|
|
13
4
|
export declare const BpmnNodeRendererExtension: import("@formicoidea/labre-core/store").ExtensionType & {
|
|
14
5
|
identifier: import("@formicoidea/labre-core/_pkgs/global/di").ServiceIdentifier<ElementRenderer<BpmnNodeElementModel>>;
|