@formicoidea/labre-framework-bpmn 0.50.0 → 0.52.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/consts.d.ts +2 -2
- package/dist/consts.js +3 -3
- package/dist/export.js +1 -1
- package/dist/facts.js +1 -1
- package/dist/import.d.ts +1 -1
- package/dist/import.js +122 -89
- package/dist/interchange-headless.d.ts +74 -0
- package/dist/interchange-headless.js +100 -0
- package/dist/interchange.d.ts +2 -79
- package/dist/interchange.js +4 -87
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/package.json +6 -2
package/dist/consts.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BpmnNodeKind } from '@formicoidea/labre-core/model';
|
|
2
|
-
import { PointStyle, StrokeStyle } from '@formicoidea/labre-core/model';
|
|
2
|
+
import { PointStyle, StrokeStyle } from '@formicoidea/labre-core/model/headless';
|
|
3
3
|
/**
|
|
4
4
|
* Visual constants for the BPMN basics. Style "C" (hybrid): spec-accurate
|
|
5
5
|
* shapes and line weights, with accent colour only on the event rings — the
|
|
@@ -240,7 +240,7 @@ export declare const POOL_LANE_NAME_FONT_SIZE = 13;
|
|
|
240
240
|
* so this file stays the one place a reader looks for a pool's metrics, and so
|
|
241
241
|
* the declaration keeps reading them from where it always did.
|
|
242
242
|
*/
|
|
243
|
-
export { POOL_BAND_WIDTH, POOL_LANE_BAND_WIDTH } from '@formicoidea/labre-core/model';
|
|
243
|
+
export { POOL_BAND_WIDTH, POOL_LANE_BAND_WIDTH, } from '@formicoidea/labre-core/model/headless';
|
|
244
244
|
/**
|
|
245
245
|
* How close to an internal lane boundary a pointer has to be, in MODEL units,
|
|
246
246
|
* for the gesture to be a separator drag rather than a click on the pool.
|
package/dist/consts.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PointStyle, StrokeStyle } from '@formicoidea/labre-core/model';
|
|
2
|
-
import { NOTATION_NEUTRALS } from '@formicoidea/labre-core/shared/
|
|
1
|
+
import { PointStyle, StrokeStyle } from '@formicoidea/labre-core/model/headless';
|
|
2
|
+
import { NOTATION_NEUTRALS } from '@formicoidea/labre-core/shared/headless';
|
|
3
3
|
/**
|
|
4
4
|
* Visual constants for the BPMN basics. Style "C" (hybrid): spec-accurate
|
|
5
5
|
* shapes and line weights, with accent colour only on the event rings — the
|
|
@@ -296,7 +296,7 @@ export const POOL_LANE_NAME_FONT_SIZE = 13;
|
|
|
296
296
|
* so this file stays the one place a reader looks for a pool's metrics, and so
|
|
297
297
|
* the declaration keeps reading them from where it always did.
|
|
298
298
|
*/
|
|
299
|
-
export { POOL_BAND_WIDTH, POOL_LANE_BAND_WIDTH } from '@formicoidea/labre-core/model';
|
|
299
|
+
export { POOL_BAND_WIDTH, POOL_LANE_BAND_WIDTH, } from '@formicoidea/labre-core/model/headless';
|
|
300
300
|
/**
|
|
301
301
|
* How close to an internal lane boundary a pointer has to be, in MODEL units,
|
|
302
302
|
* for the gesture to be a separator drag rather than a click on the pool.
|
package/dist/export.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { backgroundInstanceZones, backgroundPlot, } from '@formicoidea/labre-core/
|
|
1
|
+
import { backgroundInstanceZones, backgroundPlot, } from '@formicoidea/labre-core/interchange';
|
|
2
2
|
import { BPMN_POOL_BACKGROUND } from './background.js';
|
|
3
3
|
import { bpmnLaneOf, bpmnPoolOf } from './facts.js';
|
|
4
4
|
import { BPMN_ROLE } from './roles.js';
|
package/dist/facts.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { backgroundInstanceZones, backgroundPlot, containingFrame, } from '@formicoidea/labre-core/
|
|
1
|
+
import { backgroundInstanceZones, backgroundPlot, containingFrame, } from '@formicoidea/labre-core/interchange';
|
|
2
2
|
import { BPMN_POOL_BACKGROUND } from './background.js';
|
|
3
3
|
/**
|
|
4
4
|
* Where a BPMN artefact SITS — the facts, answerable without a `BlockStdScope`.
|
package/dist/import.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { InterchangeImportContext, InterchangeImportResult } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import type { BpmnNodeKind } from '@formicoidea/labre-core/model';
|
|
3
3
|
/**
|
|
4
4
|
* The remarks whose wording is FIXED, as `[key, English]` pairs — one entry
|
package/dist/import.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { InterchangeImportError, } from '@formicoidea/labre-core/
|
|
2
|
-
import { ConnectorMode, PointStyle, StrokeStyle } from '@formicoidea/labre-core/model';
|
|
1
|
+
import { InterchangeImportError, readXmlElement, } from '@formicoidea/labre-core/interchange';
|
|
2
|
+
import { ConnectorMode, PointStyle, StrokeStyle, } from '@formicoidea/labre-core/model/headless';
|
|
3
3
|
import { Bound } from '@formicoidea/labre-core/global/gfx';
|
|
4
4
|
import { ASSOCIATION_STROKE, ASSOCIATION_WIDTH, bpmnLabelMode, MESSAGE_STROKE, MESSAGE_WIDTH, NODE_SIZE, POOL_BAND_WIDTH, POOL_REF_HEIGHT, POOL_REF_WIDTH, SEQUENCE_STROKE, SEQUENCE_WIDTH, } from './consts.js';
|
|
5
5
|
import { BPMN_FORMAT_ID, BPMN_NS, BPMN_OWN_DECLARATIONS, BPMN_SCOPE, BPMN_XML_OF_KIND, escapeAttr, escapeText, } from './export.js';
|
|
@@ -191,15 +191,13 @@ export const BPMN_IMPORT_ERRORS = {
|
|
|
191
191
|
*
|
|
192
192
|
* ## Reading XML by hand, and why
|
|
193
193
|
*
|
|
194
|
-
* The
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
*
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
* spec. Both traps are `export.unit.spec.ts`'s findings, inherited rather than
|
|
202
|
-
* rediscovered.
|
|
194
|
+
* The file is read by the platform's `readXml` and walked through its
|
|
195
|
+
* DOM-shaped view (`xml-element.ts` in the surface package), child by child,
|
|
196
|
+
* namespaces resolved. Not `DOMParser`: the P0 import spike measured this
|
|
197
|
+
* reader on a server, where it needed a DOM installed (jsdom) and grew
|
|
198
|
+
* quadratically with the file — 5.1 s of CPU at 2 000 tasks. Without a DOM it
|
|
199
|
+
* runs in a server function, in labre-mcp and in a unit test alike (ADR 0012,
|
|
200
|
+
* P3 as amended 2026-10-14), in time linear in the file.
|
|
203
201
|
*
|
|
204
202
|
* ## Failure is an exception, not a report
|
|
205
203
|
*
|
|
@@ -293,11 +291,13 @@ export const BPMN_KIND_OF_XML = new Map(Object.entries(BPMN_XML_OF_KIND).map(([k
|
|
|
293
291
|
* there is no such thing in BPMN, where every connecting object is one of
|
|
294
292
|
* these three.
|
|
295
293
|
*/
|
|
296
|
-
|
|
294
|
+
// No prototype: it is read by a name the file chose, and `<constructor>` is
|
|
295
|
+
// one (security review, 2026-10-14).
|
|
296
|
+
const EDGE_ROLE_OF_ELEMENT = Object.assign(Object.create(null), {
|
|
297
297
|
sequenceFlow: BPMN_ROLE.sequenceFlow,
|
|
298
298
|
messageFlow: BPMN_ROLE.messageFlow,
|
|
299
299
|
association: BPMN_ROLE.association,
|
|
300
|
-
};
|
|
300
|
+
});
|
|
301
301
|
/**
|
|
302
302
|
* The colour extensions D5 quarantines (case 1), by namespace and by prefix.
|
|
303
303
|
*
|
|
@@ -368,20 +368,14 @@ const NOT_A_BODY = new Set([
|
|
|
368
368
|
'multiInstanceLoopCharacteristics',
|
|
369
369
|
'standardLoopCharacteristics',
|
|
370
370
|
]);
|
|
371
|
-
/* ── Reading the
|
|
372
|
-
/** The `Node.nodeType`s a fragment can be made of, spelled rather than numbered. */
|
|
373
|
-
const ELEMENT_NODE = 1;
|
|
374
|
-
const TEXT_NODE = 3;
|
|
375
|
-
const CDATA_NODE = 4;
|
|
376
|
-
const PI_NODE = 7;
|
|
377
|
-
const COMMENT_NODE = 8;
|
|
371
|
+
/* ── Reading the tree by hand ─────────────────────────────────────────── */
|
|
378
372
|
/** The element children of `node`, in document order. */
|
|
379
373
|
function childrenOf(node) {
|
|
380
|
-
return
|
|
374
|
+
return node.children;
|
|
381
375
|
}
|
|
382
376
|
/** Every element under `node`, at any depth, in document order. */
|
|
383
377
|
function descendantsOf(node) {
|
|
384
|
-
return
|
|
378
|
+
return node.descendants();
|
|
385
379
|
}
|
|
386
380
|
/** Is this element in the BPMN MODEL namespace, whatever prefix it wears? */
|
|
387
381
|
function isModel(element) {
|
|
@@ -428,53 +422,71 @@ function isColourAttr(attr) {
|
|
|
428
422
|
* (XML 1.0 §3.3.3 — only a character reference survives normalization).
|
|
429
423
|
*/
|
|
430
424
|
function fragmentOf(element) {
|
|
431
|
-
const
|
|
432
|
-
.map(
|
|
433
|
-
.join('')
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
425
|
+
const head = (node) => `<${node.name}${Object.entries(node.attrs)
|
|
426
|
+
.map(([name, value]) => ` ${name}="${escapeAttr(value)}"`)
|
|
427
|
+
.join('')}`;
|
|
428
|
+
// An explicit stack: a quarantined fragment is as deep as the file made it.
|
|
429
|
+
const stack = [
|
|
430
|
+
{ node: element.node, parts: [], next: 0 },
|
|
431
|
+
];
|
|
432
|
+
let written = '';
|
|
433
|
+
while (stack.length > 0) {
|
|
434
|
+
const frame = stack[stack.length - 1];
|
|
435
|
+
const content = frame.node.content ?? frame.node.children;
|
|
436
|
+
if (frame.next < content.length) {
|
|
437
|
+
const entry = content[frame.next];
|
|
438
|
+
frame.next += 1;
|
|
439
|
+
if (!('kind' in entry)) {
|
|
440
|
+
stack.push({ node: entry, parts: [], next: 0 });
|
|
441
|
+
}
|
|
442
|
+
else if (entry.kind === 'text') {
|
|
443
|
+
frame.parts.push(escapeText(entry.value));
|
|
444
|
+
}
|
|
445
|
+
else if (entry.kind === 'comment') {
|
|
446
|
+
// A comment inside a vendor extension is documentation somebody wrote
|
|
447
|
+
// by hand, and dropping it while promising the fragment back
|
|
448
|
+
// "character for character" would make that promise false in the one
|
|
449
|
+
// place a human would notice.
|
|
450
|
+
frame.parts.push(`<!--${entry.value}-->`);
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
frame.parts.push(`<?${entry.target} ${entry.data}?>`);
|
|
454
|
+
}
|
|
455
|
+
continue;
|
|
452
456
|
}
|
|
457
|
+
stack.pop();
|
|
458
|
+
const { node, parts } = frame;
|
|
459
|
+
const text = parts.length === 0
|
|
460
|
+
? `${head(node)} />`
|
|
461
|
+
: `${head(node)}>${parts.join('')}</${node.name}>`;
|
|
462
|
+
const parent = stack[stack.length - 1];
|
|
463
|
+
if (parent)
|
|
464
|
+
parent.parts.push(text);
|
|
465
|
+
else
|
|
466
|
+
written = text;
|
|
453
467
|
}
|
|
454
|
-
|
|
455
|
-
if (parts.length === 0)
|
|
456
|
-
return `<${name}${attrs} />`;
|
|
457
|
-
return `<${name}${attrs}>${parts.join('')}</${name}>`;
|
|
468
|
+
return written;
|
|
458
469
|
}
|
|
459
470
|
/**
|
|
460
471
|
* The document, or an exception naming what is wrong with it.
|
|
461
472
|
*
|
|
462
|
-
* `
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
*
|
|
473
|
+
* `readXml` never throws: it reads what it can and says what it had to
|
|
474
|
+
* recover from. Anything it recovered from is refused here, with its first
|
|
475
|
+
* remark as the detail, as `DOMParser` refused it before. A `DOCTYPE` is not
|
|
476
|
+
* an error: it is skipped, and no entity it declares is ever expanded, so a
|
|
477
|
+
* `&name;` it declares stays those characters (the spike's billion-laughs and
|
|
478
|
+
* XXE files, `__tests__/import-hostile.unit.spec.ts`).
|
|
466
479
|
*/
|
|
467
480
|
function parseDefinitions(source) {
|
|
468
|
-
const
|
|
469
|
-
const
|
|
470
|
-
if (
|
|
471
|
-
const detail =
|
|
481
|
+
const { document, root } = readXmlElement(source, { conformant: true });
|
|
482
|
+
const [complaint] = document.notes;
|
|
483
|
+
if (complaint !== undefined) {
|
|
484
|
+
const detail = complaint.slice(0, 200);
|
|
472
485
|
throw new InterchangeImportError(`This file is not well-formed XML, so no BPMN can be read out of it: ${detail}`, {
|
|
473
486
|
messageKey: BPMN_IMPORT_ERRORS.malformedXml[0],
|
|
474
487
|
messageParams: { detail },
|
|
475
488
|
});
|
|
476
489
|
}
|
|
477
|
-
const root = doc.documentElement;
|
|
478
490
|
if (!root || root.localName !== 'definitions') {
|
|
479
491
|
const tag = root?.localName ?? 'nothing';
|
|
480
492
|
throw new InterchangeImportError(`A BPMN file opens on <definitions>; this one opens on <${tag}>.`, {
|
|
@@ -581,8 +593,16 @@ function diagramIndex(definitions) {
|
|
|
581
593
|
* everywhere in this format, and everything else on an element Labre draws is
|
|
582
594
|
* something Labre does not model and must not lose.
|
|
583
595
|
*/
|
|
584
|
-
|
|
585
|
-
|
|
596
|
+
// No prototype, like `EDGE_ROLE_OF_ELEMENT`: `READ_ATTRS.constructor` was a
|
|
597
|
+
// function, and `.includes` on it the untyped TypeError the review found.
|
|
598
|
+
const READ_ATTRS = Object.assign(Object.create(null), {
|
|
599
|
+
definitions: [
|
|
600
|
+
'id',
|
|
601
|
+
'name',
|
|
602
|
+
'targetNamespace',
|
|
603
|
+
'exporter',
|
|
604
|
+
'exporterVersion',
|
|
605
|
+
],
|
|
586
606
|
participant: ['id', 'name', 'processRef'],
|
|
587
607
|
process: ['id', 'name', 'isExecutable'],
|
|
588
608
|
lane: ['id', 'name'],
|
|
@@ -594,9 +614,15 @@ const READ_ATTRS = {
|
|
|
594
614
|
messageFlow: ['id', 'name', 'sourceRef', 'targetRef'],
|
|
595
615
|
// `associationDirection` is read only when it says what the exporter would
|
|
596
616
|
// write anyway; see the edge reader for the other values.
|
|
597
|
-
association: [
|
|
617
|
+
association: [
|
|
618
|
+
'id',
|
|
619
|
+
'name',
|
|
620
|
+
'sourceRef',
|
|
621
|
+
'targetRef',
|
|
622
|
+
'associationDirection',
|
|
623
|
+
],
|
|
598
624
|
'': ['id', 'name'],
|
|
599
|
-
};
|
|
625
|
+
});
|
|
600
626
|
/** What a `BPMNShape` says that the drawing already carries. */
|
|
601
627
|
const READ_SHAPE_ATTRS = [
|
|
602
628
|
'id',
|
|
@@ -685,8 +711,14 @@ function layOutTheUndrawn(drafts, minted) {
|
|
|
685
711
|
draft.kind !== 'edge' &&
|
|
686
712
|
draft.kind !== 'group');
|
|
687
713
|
const boxes = placed.map(boundOf);
|
|
688
|
-
const maxX = boxes.length > 0
|
|
689
|
-
|
|
714
|
+
const maxX = boxes.length > 0
|
|
715
|
+
? boxes
|
|
716
|
+
.map(box => box.x + box.w)
|
|
717
|
+
.reduce((a, b) => Math.max(a, b), -Infinity)
|
|
718
|
+
: 0;
|
|
719
|
+
const minY = boxes.length > 0
|
|
720
|
+
? boxes.map(box => box.y).reduce((a, b) => Math.min(a, b), Infinity)
|
|
721
|
+
: 0;
|
|
690
722
|
let seat = 0;
|
|
691
723
|
for (const draft of drafts) {
|
|
692
724
|
if (!draft.needsLayout)
|
|
@@ -718,10 +750,16 @@ function layOutTheUndrawn(drafts, minted) {
|
|
|
718
750
|
.map(boundOf);
|
|
719
751
|
if (inside.length === 0)
|
|
720
752
|
return;
|
|
721
|
-
const left =
|
|
722
|
-
|
|
723
|
-
const
|
|
724
|
-
|
|
753
|
+
const left = inside.map(box => box.x).reduce((a, b) => Math.min(a, b), Infinity) -
|
|
754
|
+
MINTED_POOL_PADDING;
|
|
755
|
+
const top = inside.map(box => box.y).reduce((a, b) => Math.min(a, b), Infinity) -
|
|
756
|
+
MINTED_POOL_PADDING;
|
|
757
|
+
const right = inside
|
|
758
|
+
.map(box => box.x + box.w)
|
|
759
|
+
.reduce((a, b) => Math.max(a, b), -Infinity) + MINTED_POOL_PADDING;
|
|
760
|
+
const bottom = inside
|
|
761
|
+
.map(box => box.y + box.h)
|
|
762
|
+
.reduce((a, b) => Math.max(a, b), -Infinity) + MINTED_POOL_PADDING;
|
|
725
763
|
minted.props.xywh = new Bound(
|
|
726
764
|
// The name band is drawn INSIDE the frame and is not part of the plot, so
|
|
727
765
|
// the frame starts a band's width further left than the work does.
|
|
@@ -814,12 +852,17 @@ export function importBpmnXml(source, context = {}) {
|
|
|
814
852
|
}
|
|
815
853
|
seenSourceIds.add(sourceId);
|
|
816
854
|
};
|
|
855
|
+
/*
|
|
856
|
+
* The four keep-helpers fill their bags IN PLACE: a copy of the bag per entry
|
|
857
|
+
* made 20 000 carried children 7.4 s and 20 000 unknown attributes over a
|
|
858
|
+
* minute (security review, 2026-10-14). The bags have no prototype, because
|
|
859
|
+
* their keys are names and ids the file chose (`__proto__` among them).
|
|
860
|
+
*/
|
|
817
861
|
/** One attribute, kept under the scope of the element that carried it. */
|
|
818
862
|
const carryAttr = (payload, scope, name, value) => {
|
|
819
|
-
payload.attrs
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
};
|
|
863
|
+
const attrs = (payload.attrs ??= Object.create(null));
|
|
864
|
+
(attrs[scope] ??= Object.create(null))[name] =
|
|
865
|
+
value;
|
|
823
866
|
carried++;
|
|
824
867
|
};
|
|
825
868
|
/**
|
|
@@ -830,10 +873,8 @@ export function importBpmnXml(source, context = {}) {
|
|
|
830
873
|
* one flow, one of them generic, is a worse report than one that is precise.
|
|
831
874
|
*/
|
|
832
875
|
const carryChild = (payload, scope, child, sourceId, announce = true) => {
|
|
833
|
-
payload.children
|
|
834
|
-
|
|
835
|
-
[scope]: [...(payload.children?.[scope] ?? []), fragmentOf(child)],
|
|
836
|
-
};
|
|
876
|
+
const children = (payload.children ??= Object.create(null));
|
|
877
|
+
(children[scope] ??= []).push(fragmentOf(child));
|
|
837
878
|
carried++;
|
|
838
879
|
if (!announce)
|
|
839
880
|
return;
|
|
@@ -848,10 +889,8 @@ export function importBpmnXml(source, context = {}) {
|
|
|
848
889
|
};
|
|
849
890
|
/** One diagram fragment, kept under the scope of what it DRAWS. */
|
|
850
891
|
const carryDi = (payload, scope, fragment) => {
|
|
851
|
-
payload.di
|
|
852
|
-
|
|
853
|
-
[scope]: [...(payload.di?.[scope] ?? []), fragment],
|
|
854
|
-
};
|
|
892
|
+
const di = (payload.di ??= Object.create(null));
|
|
893
|
+
(di[scope] ??= []).push(fragment);
|
|
855
894
|
carried++;
|
|
856
895
|
};
|
|
857
896
|
const quarantine = (payload, fragment, reason, entry,
|
|
@@ -860,10 +899,7 @@ export function importBpmnXml(source, context = {}) {
|
|
|
860
899
|
// `payload.quarantined[].reason` (data, never translated); only the
|
|
861
900
|
// REPORT note below carries the key.
|
|
862
901
|
reasonKey) => {
|
|
863
|
-
payload.quarantined
|
|
864
|
-
...(payload.quarantined ?? []),
|
|
865
|
-
{ fragment, reason },
|
|
866
|
-
];
|
|
902
|
+
(payload.quarantined ??= []).push({ fragment, reason });
|
|
867
903
|
quarantined++;
|
|
868
904
|
note({
|
|
869
905
|
kind: 'quarantined',
|
|
@@ -1298,13 +1334,10 @@ export function importBpmnXml(source, context = {}) {
|
|
|
1298
1334
|
const drawn = shapes.get(inner)?.element ?? diEdges.get(inner)?.element;
|
|
1299
1335
|
if (!drawn)
|
|
1300
1336
|
continue;
|
|
1301
|
-
payload.quarantined
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
reason: BPMN_QUARANTINE_REASON.expanded,
|
|
1306
|
-
},
|
|
1307
|
-
];
|
|
1337
|
+
(payload.quarantined ??= []).push({
|
|
1338
|
+
fragment: fragmentOf(drawn),
|
|
1339
|
+
reason: BPMN_QUARANTINE_REASON.expanded,
|
|
1340
|
+
});
|
|
1308
1341
|
}
|
|
1309
1342
|
continue;
|
|
1310
1343
|
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { InterchangeFormat, InterchangeImportCapability } from '@formicoidea/labre-core/interchange';
|
|
2
|
+
/**
|
|
3
|
+
* `@labre/affine-gfx-bpmn/interchange` — BPMN's formats and its two READERS,
|
|
4
|
+
* with no editor behind them (ADR 0012, P3 as amended 2026-10-14).
|
|
5
|
+
*
|
|
6
|
+
* What a server needs to read a `.bpmn` or an `.svg` as a BPMN board: the
|
|
7
|
+
* format declarations and the import capabilities, whose `run` is a pure
|
|
8
|
+
* function of text. The EXPORT capability is not here and cannot be: it picks
|
|
9
|
+
* the artefacts out of live element models (`bpmnBoardFrom`, by `instanceof`),
|
|
10
|
+
* which is the editor graph this entry exists to leave out. It stays in
|
|
11
|
+
* `interchange.ts`, which re-exports everything below.
|
|
12
|
+
*
|
|
13
|
+
* Held by `interchange-headless.unit.spec.ts` in `packages/affine/all`.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* BPMN 2.0 XML. **Semantic** — the file carries a model, not a picture, so it
|
|
17
|
+
* takes the whole preservation contract the day an importer is written.
|
|
18
|
+
*
|
|
19
|
+
* `application/xml` and not `text/xml`: the file is not meant to be read as
|
|
20
|
+
* text by whatever opens it, and `.bpmn` is the extension every BPMN tool
|
|
21
|
+
* watches for.
|
|
22
|
+
*
|
|
23
|
+
* `.xml` rides along BEHIND it, and the order is the whole of the difference:
|
|
24
|
+
* the first extension is the one a download is given, so Labre still writes
|
|
25
|
+
* `.bpmn`, and the rest are what a picker offers and what an auto-detecting
|
|
26
|
+
* host indexes on. Half the tools in the wild write the same bytes under the
|
|
27
|
+
* generic extension, and a filter that refused them would refuse a valid
|
|
28
|
+
* process for the sake of a filename — the same argument the shared `FileTypes`
|
|
29
|
+
* table made when this filter lived there, kept now that the filter is built
|
|
30
|
+
* from the format itself. What the file actually IS is decided by the reader,
|
|
31
|
+
* which throws on anything that is not a BPMN `<definitions>`.
|
|
32
|
+
*/
|
|
33
|
+
export declare const BPMN_XML_EXTENSION = ".bpmn";
|
|
34
|
+
export declare const BPMN_XML_MIME = "application/xml";
|
|
35
|
+
export declare const BPMN_XML_FORMAT: InterchangeFormat;
|
|
36
|
+
/**
|
|
37
|
+
* `bpmn:bpmn:import` — a `.bpmn` file as a board.
|
|
38
|
+
*
|
|
39
|
+
* A thin adapter over {@link importBpmnXml} and nothing else, which is the
|
|
40
|
+
* whole of what a capability is: the parser is a pure function of a string, so
|
|
41
|
+
* the registry entry has nothing to add to it and deliberately adds nothing.
|
|
42
|
+
* A reader that threw its arms around a surface here would be a reader
|
|
43
|
+
* labre-mcp could not call.
|
|
44
|
+
*/
|
|
45
|
+
export declare const BPMN_XML_IMPORT: InterchangeImportCapability;
|
|
46
|
+
/**
|
|
47
|
+
* SVG. **Visual** — the file carries a rendering, not a model.
|
|
48
|
+
*
|
|
49
|
+
* A separate format object from `BPMN_XML_FORMAT` and deliberately not a shared
|
|
50
|
+
* singleton with Wardley's: ADR 0012's unit is the TRIPLE, and the ADR
|
|
51
|
+
* explicitly rejects "one capability per format, with the framework inferred
|
|
52
|
+
* from the file" — a `.svg` is read by several frameworks and the inference is
|
|
53
|
+
* exactly the guess the ADR forbids everywhere else. The three constants come
|
|
54
|
+
* from the parser's own package so the two declarations cannot drift into
|
|
55
|
+
* disagreeing about the extension or the mime a picker filters on.
|
|
56
|
+
*/
|
|
57
|
+
export declare const BPMN_SVG_FORMAT: InterchangeFormat;
|
|
58
|
+
/**
|
|
59
|
+
* `bpmn:svg:import` — an SVG as a sketch, best effort.
|
|
60
|
+
*
|
|
61
|
+
* **The heuristics statement and the known failure modes this capability owes
|
|
62
|
+
* (ADR 0012, open question 2) are the module documentation of
|
|
63
|
+
* `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** They are
|
|
64
|
+
* written once, there, because BPMN and Wardley wrap the SAME parser and
|
|
65
|
+
* therefore make the same guesses; a framework that ever wants narrower or
|
|
66
|
+
* wider recognition writes its own parser and its own paragraph beside it.
|
|
67
|
+
*
|
|
68
|
+
* What lands is a level-1 sketch (ADR 0007) — plain shapes, brush strokes and
|
|
69
|
+
* editable free text — that the author then PROMOTES into BPMN artefacts.
|
|
70
|
+
* Nothing here decides that a rounded rectangle in somebody's picture was a
|
|
71
|
+
* task, and no `interchange` payload is written, because a visual round-trip
|
|
72
|
+
* would be a re-render (P2).
|
|
73
|
+
*/
|
|
74
|
+
export declare const BPMN_SVG_IMPORT: InterchangeImportCapability;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { interchangeCapabilityId, parseSvgSketch, SVG_SKETCH_EXTENSION, SVG_SKETCH_FORMAT_ID, SVG_SKETCH_MIME, } from '@formicoidea/labre-core/interchange';
|
|
2
|
+
import { BPMN_FORMAT_ID } from './export.js';
|
|
3
|
+
import { importBpmnXml } from './import.js';
|
|
4
|
+
/**
|
|
5
|
+
* `@labre/affine-gfx-bpmn/interchange` — BPMN's formats and its two READERS,
|
|
6
|
+
* with no editor behind them (ADR 0012, P3 as amended 2026-10-14).
|
|
7
|
+
*
|
|
8
|
+
* What a server needs to read a `.bpmn` or an `.svg` as a BPMN board: the
|
|
9
|
+
* format declarations and the import capabilities, whose `run` is a pure
|
|
10
|
+
* function of text. The EXPORT capability is not here and cannot be: it picks
|
|
11
|
+
* the artefacts out of live element models (`bpmnBoardFrom`, by `instanceof`),
|
|
12
|
+
* which is the editor graph this entry exists to leave out. It stays in
|
|
13
|
+
* `interchange.ts`, which re-exports everything below.
|
|
14
|
+
*
|
|
15
|
+
* Held by `interchange-headless.unit.spec.ts` in `packages/affine/all`.
|
|
16
|
+
*/
|
|
17
|
+
/* ── The format ───────────────────────────────────────────────────────── */
|
|
18
|
+
/**
|
|
19
|
+
* BPMN 2.0 XML. **Semantic** — the file carries a model, not a picture, so it
|
|
20
|
+
* takes the whole preservation contract the day an importer is written.
|
|
21
|
+
*
|
|
22
|
+
* `application/xml` and not `text/xml`: the file is not meant to be read as
|
|
23
|
+
* text by whatever opens it, and `.bpmn` is the extension every BPMN tool
|
|
24
|
+
* watches for.
|
|
25
|
+
*
|
|
26
|
+
* `.xml` rides along BEHIND it, and the order is the whole of the difference:
|
|
27
|
+
* the first extension is the one a download is given, so Labre still writes
|
|
28
|
+
* `.bpmn`, and the rest are what a picker offers and what an auto-detecting
|
|
29
|
+
* host indexes on. Half the tools in the wild write the same bytes under the
|
|
30
|
+
* generic extension, and a filter that refused them would refuse a valid
|
|
31
|
+
* process for the sake of a filename — the same argument the shared `FileTypes`
|
|
32
|
+
* table made when this filter lived there, kept now that the filter is built
|
|
33
|
+
* from the format itself. What the file actually IS is decided by the reader,
|
|
34
|
+
* which throws on anything that is not a BPMN `<definitions>`.
|
|
35
|
+
*/
|
|
36
|
+
export const BPMN_XML_EXTENSION = '.bpmn';
|
|
37
|
+
export const BPMN_XML_MIME = 'application/xml';
|
|
38
|
+
export const BPMN_XML_FORMAT = {
|
|
39
|
+
id: BPMN_FORMAT_ID,
|
|
40
|
+
tier: 'semantic',
|
|
41
|
+
extensions: [BPMN_XML_EXTENSION, '.xml'],
|
|
42
|
+
mime: BPMN_XML_MIME,
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* `bpmn:bpmn:import` — a `.bpmn` file as a board.
|
|
46
|
+
*
|
|
47
|
+
* A thin adapter over {@link importBpmnXml} and nothing else, which is the
|
|
48
|
+
* whole of what a capability is: the parser is a pure function of a string, so
|
|
49
|
+
* the registry entry has nothing to add to it and deliberately adds nothing.
|
|
50
|
+
* A reader that threw its arms around a surface here would be a reader
|
|
51
|
+
* labre-mcp could not call.
|
|
52
|
+
*/
|
|
53
|
+
export const BPMN_XML_IMPORT = {
|
|
54
|
+
id: interchangeCapabilityId('bpmn', BPMN_XML_FORMAT.id, 'import'),
|
|
55
|
+
framework: 'bpmn',
|
|
56
|
+
format: BPMN_XML_FORMAT,
|
|
57
|
+
direction: 'import',
|
|
58
|
+
run: importBpmnXml,
|
|
59
|
+
};
|
|
60
|
+
/* ── The visual tier ──────────────────────────────────────────────────── */
|
|
61
|
+
/**
|
|
62
|
+
* SVG. **Visual** — the file carries a rendering, not a model.
|
|
63
|
+
*
|
|
64
|
+
* A separate format object from `BPMN_XML_FORMAT` and deliberately not a shared
|
|
65
|
+
* singleton with Wardley's: ADR 0012's unit is the TRIPLE, and the ADR
|
|
66
|
+
* explicitly rejects "one capability per format, with the framework inferred
|
|
67
|
+
* from the file" — a `.svg` is read by several frameworks and the inference is
|
|
68
|
+
* exactly the guess the ADR forbids everywhere else. The three constants come
|
|
69
|
+
* from the parser's own package so the two declarations cannot drift into
|
|
70
|
+
* disagreeing about the extension or the mime a picker filters on.
|
|
71
|
+
*/
|
|
72
|
+
export const BPMN_SVG_FORMAT = {
|
|
73
|
+
id: SVG_SKETCH_FORMAT_ID,
|
|
74
|
+
tier: 'visual',
|
|
75
|
+
extensions: [SVG_SKETCH_EXTENSION],
|
|
76
|
+
mime: SVG_SKETCH_MIME,
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* `bpmn:svg:import` — an SVG as a sketch, best effort.
|
|
80
|
+
*
|
|
81
|
+
* **The heuristics statement and the known failure modes this capability owes
|
|
82
|
+
* (ADR 0012, open question 2) are the module documentation of
|
|
83
|
+
* `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** They are
|
|
84
|
+
* written once, there, because BPMN and Wardley wrap the SAME parser and
|
|
85
|
+
* therefore make the same guesses; a framework that ever wants narrower or
|
|
86
|
+
* wider recognition writes its own parser and its own paragraph beside it.
|
|
87
|
+
*
|
|
88
|
+
* What lands is a level-1 sketch (ADR 0007) — plain shapes, brush strokes and
|
|
89
|
+
* editable free text — that the author then PROMOTES into BPMN artefacts.
|
|
90
|
+
* Nothing here decides that a rounded rectangle in somebody's picture was a
|
|
91
|
+
* task, and no `interchange` payload is written, because a visual round-trip
|
|
92
|
+
* would be a re-render (P2).
|
|
93
|
+
*/
|
|
94
|
+
export const BPMN_SVG_IMPORT = {
|
|
95
|
+
id: interchangeCapabilityId('bpmn', BPMN_SVG_FORMAT.id, 'import'),
|
|
96
|
+
framework: 'bpmn',
|
|
97
|
+
format: BPMN_SVG_FORMAT,
|
|
98
|
+
direction: 'import',
|
|
99
|
+
run: parseSvgSketch,
|
|
100
|
+
};
|
package/dist/interchange.d.ts
CHANGED
|
@@ -1,45 +1,7 @@
|
|
|
1
|
-
import type { InterchangeCapability, InterchangeExportCapability
|
|
1
|
+
import type { InterchangeCapability, InterchangeExportCapability } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import type { GfxPrimitiveElementModel } from '@formicoidea/labre-core/std/gfx';
|
|
3
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;
|
|
4
|
+
export { BPMN_SVG_FORMAT, BPMN_SVG_IMPORT, BPMN_XML_EXTENSION, BPMN_XML_FORMAT, BPMN_XML_IMPORT, BPMN_XML_MIME, } from './interchange-headless.js';
|
|
43
5
|
/**
|
|
44
6
|
* The artefacts the exporter speaks about, picked out of a surface's elements
|
|
45
7
|
* and kept in the order they were given.
|
|
@@ -95,44 +57,5 @@ export declare function bpmnBoardFrom(elements: readonly GfxPrimitiveElementMode
|
|
|
95
57
|
export declare function bpmnSafeFilename(raw: string | undefined): string;
|
|
96
58
|
/** `bpmn:bpmn:export` — the registry's first capability. */
|
|
97
59
|
export declare const BPMN_XML_EXPORT: InterchangeExportCapability;
|
|
98
|
-
/**
|
|
99
|
-
* `bpmn:bpmn:import` — a `.bpmn` file as a board.
|
|
100
|
-
*
|
|
101
|
-
* A thin adapter over {@link importBpmnXml} and nothing else, which is the
|
|
102
|
-
* whole of what a capability is: the parser is a pure function of a string, so
|
|
103
|
-
* the registry entry has nothing to add to it and deliberately adds nothing.
|
|
104
|
-
* A reader that threw its arms around a surface here would be a reader
|
|
105
|
-
* labre-mcp could not call.
|
|
106
|
-
*/
|
|
107
|
-
export declare const BPMN_XML_IMPORT: InterchangeImportCapability;
|
|
108
|
-
/**
|
|
109
|
-
* SVG. **Visual** — the file carries a rendering, not a model.
|
|
110
|
-
*
|
|
111
|
-
* A separate format object from `BPMN_XML_FORMAT` and deliberately not a shared
|
|
112
|
-
* singleton with Wardley's: ADR 0012's unit is the TRIPLE, and the ADR
|
|
113
|
-
* explicitly rejects "one capability per format, with the framework inferred
|
|
114
|
-
* from the file" — a `.svg` is read by several frameworks and the inference is
|
|
115
|
-
* exactly the guess the ADR forbids everywhere else. The three constants come
|
|
116
|
-
* from the parser's own package so the two declarations cannot drift into
|
|
117
|
-
* disagreeing about the extension or the mime a picker filters on.
|
|
118
|
-
*/
|
|
119
|
-
export declare const BPMN_SVG_FORMAT: InterchangeFormat;
|
|
120
|
-
/**
|
|
121
|
-
* `bpmn:svg:import` — an SVG as a sketch, best effort.
|
|
122
|
-
*
|
|
123
|
-
* **The heuristics statement and the known failure modes this capability owes
|
|
124
|
-
* (ADR 0012, open question 2) are the module documentation of
|
|
125
|
-
* `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** They are
|
|
126
|
-
* written once, there, because BPMN and Wardley wrap the SAME parser and
|
|
127
|
-
* therefore make the same guesses; a framework that ever wants narrower or
|
|
128
|
-
* wider recognition writes its own parser and its own paragraph beside it.
|
|
129
|
-
*
|
|
130
|
-
* What lands is a level-1 sketch (ADR 0007) — plain shapes, brush strokes and
|
|
131
|
-
* editable free text — that the author then PROMOTES into BPMN artefacts.
|
|
132
|
-
* Nothing here decides that a rounded rectangle in somebody's picture was a
|
|
133
|
-
* task, and no `interchange` payload is written, because a visual round-trip
|
|
134
|
-
* would be a re-render (P2).
|
|
135
|
-
*/
|
|
136
|
-
export declare const BPMN_SVG_IMPORT: InterchangeImportCapability;
|
|
137
60
|
/** Everything BPMN registers, in one list the view extension can hand over. */
|
|
138
61
|
export declare const BPMN_INTERCHANGE: readonly InterchangeCapability[];
|
package/dist/interchange.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { interchangeCapabilityId, LEGEND_ROLE,
|
|
1
|
+
import { interchangeCapabilityId, LEGEND_ROLE, } from '@formicoidea/labre-core/blocks/surface';
|
|
2
2
|
import { BpmnNodeElementModel, BpmnPoolElementModel, ConnectorElementModel, GroupElementModel, TextElementModel, } from '@formicoidea/labre-core/model';
|
|
3
3
|
import { fillPlaceholders } from '@formicoidea/labre-core/shared/services';
|
|
4
4
|
import { safeFilename } from '@formicoidea/labre-core/shared/utils';
|
|
5
|
-
import {
|
|
5
|
+
import { exportBpmnXmlWithWarnings } from './export.js';
|
|
6
6
|
import { bpmnPoolOf } from './facts.js';
|
|
7
|
-
import {
|
|
7
|
+
import { BPMN_SVG_IMPORT, BPMN_XML_EXTENSION, BPMN_XML_FORMAT, BPMN_XML_IMPORT, BPMN_XML_MIME, } from './interchange-headless.js';
|
|
8
8
|
import { BPMN_ROLE, BPMN_ROLE_OF_KIND } from './roles.js';
|
|
9
|
+
export { BPMN_SVG_FORMAT, BPMN_SVG_IMPORT, BPMN_XML_EXTENSION, BPMN_XML_FORMAT, BPMN_XML_IMPORT, BPMN_XML_MIME, } from './interchange-headless.js';
|
|
9
10
|
/**
|
|
10
11
|
* BPMN's entries in the interchange registry (`docs/adr/0012`, P1).
|
|
11
12
|
*
|
|
@@ -24,33 +25,6 @@ import { BPMN_ROLE, BPMN_ROLE_OF_KIND } from './roles.js';
|
|
|
24
25
|
* writer speaks about out of a surface's elements, and hands the reader's
|
|
25
26
|
* output straight back to whoever asked for it.
|
|
26
27
|
*/
|
|
27
|
-
/* ── The format ───────────────────────────────────────────────────────── */
|
|
28
|
-
/**
|
|
29
|
-
* BPMN 2.0 XML. **Semantic** — the file carries a model, not a picture, so it
|
|
30
|
-
* takes the whole preservation contract the day an importer is written.
|
|
31
|
-
*
|
|
32
|
-
* `application/xml` and not `text/xml`: the file is not meant to be read as
|
|
33
|
-
* text by whatever opens it, and `.bpmn` is the extension every BPMN tool
|
|
34
|
-
* watches for.
|
|
35
|
-
*
|
|
36
|
-
* `.xml` rides along BEHIND it, and the order is the whole of the difference:
|
|
37
|
-
* the first extension is the one a download is given, so Labre still writes
|
|
38
|
-
* `.bpmn`, and the rest are what a picker offers and what an auto-detecting
|
|
39
|
-
* host indexes on. Half the tools in the wild write the same bytes under the
|
|
40
|
-
* generic extension, and a filter that refused them would refuse a valid
|
|
41
|
-
* process for the sake of a filename — the same argument the shared `FileTypes`
|
|
42
|
-
* table made when this filter lived there, kept now that the filter is built
|
|
43
|
-
* from the format itself. What the file actually IS is decided by the reader,
|
|
44
|
-
* which throws on anything that is not a BPMN `<definitions>`.
|
|
45
|
-
*/
|
|
46
|
-
export const BPMN_XML_EXTENSION = '.bpmn';
|
|
47
|
-
export const BPMN_XML_MIME = 'application/xml';
|
|
48
|
-
export const BPMN_XML_FORMAT = {
|
|
49
|
-
id: BPMN_FORMAT_ID,
|
|
50
|
-
tier: 'semantic',
|
|
51
|
-
extensions: [BPMN_XML_EXTENSION, '.xml'],
|
|
52
|
-
mime: BPMN_XML_MIME,
|
|
53
|
-
};
|
|
54
28
|
/* ── Pure board helpers ───────────────────────────────────────────────── */
|
|
55
29
|
/**
|
|
56
30
|
* Everything a generated legend is made of: the group the legend gesture stamps
|
|
@@ -269,63 +243,6 @@ export const BPMN_XML_EXPORT = {
|
|
|
269
243
|
direction: 'export',
|
|
270
244
|
run: runBpmnXmlExport,
|
|
271
245
|
};
|
|
272
|
-
/**
|
|
273
|
-
* `bpmn:bpmn:import` — a `.bpmn` file as a board.
|
|
274
|
-
*
|
|
275
|
-
* A thin adapter over {@link importBpmnXml} and nothing else, which is the
|
|
276
|
-
* whole of what a capability is: the parser is a pure function of a string, so
|
|
277
|
-
* the registry entry has nothing to add to it and deliberately adds nothing.
|
|
278
|
-
* A reader that threw its arms around a surface here would be a reader
|
|
279
|
-
* labre-mcp could not call.
|
|
280
|
-
*/
|
|
281
|
-
export const BPMN_XML_IMPORT = {
|
|
282
|
-
id: interchangeCapabilityId('bpmn', BPMN_XML_FORMAT.id, 'import'),
|
|
283
|
-
framework: 'bpmn',
|
|
284
|
-
format: BPMN_XML_FORMAT,
|
|
285
|
-
direction: 'import',
|
|
286
|
-
run: importBpmnXml,
|
|
287
|
-
};
|
|
288
|
-
/* ── The visual tier ──────────────────────────────────────────────────── */
|
|
289
|
-
/**
|
|
290
|
-
* SVG. **Visual** — the file carries a rendering, not a model.
|
|
291
|
-
*
|
|
292
|
-
* A separate format object from `BPMN_XML_FORMAT` and deliberately not a shared
|
|
293
|
-
* singleton with Wardley's: ADR 0012's unit is the TRIPLE, and the ADR
|
|
294
|
-
* explicitly rejects "one capability per format, with the framework inferred
|
|
295
|
-
* from the file" — a `.svg` is read by several frameworks and the inference is
|
|
296
|
-
* exactly the guess the ADR forbids everywhere else. The three constants come
|
|
297
|
-
* from the parser's own package so the two declarations cannot drift into
|
|
298
|
-
* disagreeing about the extension or the mime a picker filters on.
|
|
299
|
-
*/
|
|
300
|
-
export const BPMN_SVG_FORMAT = {
|
|
301
|
-
id: SVG_SKETCH_FORMAT_ID,
|
|
302
|
-
tier: 'visual',
|
|
303
|
-
extensions: [SVG_SKETCH_EXTENSION],
|
|
304
|
-
mime: SVG_SKETCH_MIME,
|
|
305
|
-
};
|
|
306
|
-
/**
|
|
307
|
-
* `bpmn:svg:import` — an SVG as a sketch, best effort.
|
|
308
|
-
*
|
|
309
|
-
* **The heuristics statement and the known failure modes this capability owes
|
|
310
|
-
* (ADR 0012, open question 2) are the module documentation of
|
|
311
|
-
* `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** They are
|
|
312
|
-
* written once, there, because BPMN and Wardley wrap the SAME parser and
|
|
313
|
-
* therefore make the same guesses; a framework that ever wants narrower or
|
|
314
|
-
* wider recognition writes its own parser and its own paragraph beside it.
|
|
315
|
-
*
|
|
316
|
-
* What lands is a level-1 sketch (ADR 0007) — plain shapes, brush strokes and
|
|
317
|
-
* editable free text — that the author then PROMOTES into BPMN artefacts.
|
|
318
|
-
* Nothing here decides that a rounded rectangle in somebody's picture was a
|
|
319
|
-
* task, and no `interchange` payload is written, because a visual round-trip
|
|
320
|
-
* would be a re-render (P2).
|
|
321
|
-
*/
|
|
322
|
-
export const BPMN_SVG_IMPORT = {
|
|
323
|
-
id: interchangeCapabilityId('bpmn', BPMN_SVG_FORMAT.id, 'import'),
|
|
324
|
-
framework: 'bpmn',
|
|
325
|
-
format: BPMN_SVG_FORMAT,
|
|
326
|
-
direction: 'import',
|
|
327
|
-
run: parseSvgSketch,
|
|
328
|
-
};
|
|
329
246
|
/** Everything BPMN registers, in one list the view extension can hand over. */
|
|
330
247
|
export const BPMN_INTERCHANGE = [
|
|
331
248
|
BPMN_XML_EXPORT,
|
package/dist/presets.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BpmnNodeKind } from '@formicoidea/labre-core/model';
|
|
2
|
-
import { StrokeStyle, TextAlign, TextFitMode, TextVerticalAlign } from '@formicoidea/labre-core/model';
|
|
2
|
+
import { StrokeStyle, TextAlign, TextFitMode, TextVerticalAlign } from '@formicoidea/labre-core/model/headless';
|
|
3
3
|
/**
|
|
4
4
|
* What a BPMN artefact is BORN as — the one description of a node's props, read
|
|
5
5
|
* by every site that creates one.
|
package/dist/presets.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FontFamily, SHAPE_TEXT_PADDING, SHAPE_TEXT_VERTICAL_PADDING, ShapeStyle, StrokeStyle, TextAlign, TextFitMode, TextVerticalAlign, } from '@formicoidea/labre-core/model';
|
|
1
|
+
import { FontFamily, SHAPE_TEXT_PADDING, SHAPE_TEXT_VERTICAL_PADDING, ShapeStyle, StrokeStyle, TextAlign, TextFitMode, TextVerticalAlign, } from '@formicoidea/labre-core/model/headless';
|
|
2
2
|
import { Bound } from '@formicoidea/labre-core/global/gfx';
|
|
3
3
|
import { ACTIVITY_FIT_REF, BPMN_LABEL_GAP, BPMN_LABEL_H, BPMN_LABEL_W, CALL_ACTIVITY_WIDTH, END_WIDTH, EVENT_END, EVENT_START, GROUP_RADIUS, GROUP_STROKE, INNER_FONT_SIZE, isBpmnActivityKind, LABEL_FONT_SIZE, LABEL_INSET_RATIO, LABEL_MIN_FONT_SIZE, NEUTRAL_STROKE, NODE_FILL, NODE_SIZE, NODE_STROKE_WIDTH, START_WIDTH, TASK_RADIUS, } from './consts.js';
|
|
4
4
|
import { BPMN_ROLE, BPMN_ROLE_OF_KIND } from './roles.js';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@formicoidea/labre-framework-bpmn",
|
|
3
3
|
"description": "Labre bpmn framework for @formicoidea/labre-core.",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.52.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"author": "lajola",
|
|
@@ -25,13 +25,17 @@
|
|
|
25
25
|
"./commands-manifest": {
|
|
26
26
|
"types": "./dist/commands-manifest.d.ts",
|
|
27
27
|
"import": "./dist/commands-manifest.js"
|
|
28
|
+
},
|
|
29
|
+
"./interchange": {
|
|
30
|
+
"types": "./dist/interchange-headless.d.ts",
|
|
31
|
+
"import": "./dist/interchange-headless.js"
|
|
28
32
|
}
|
|
29
33
|
},
|
|
30
34
|
"files": [
|
|
31
35
|
"dist"
|
|
32
36
|
],
|
|
33
37
|
"dependencies": {
|
|
34
|
-
"@formicoidea/labre-core": "0.
|
|
38
|
+
"@formicoidea/labre-core": "0.52.0",
|
|
35
39
|
"lit": "^3.2.0"
|
|
36
40
|
}
|
|
37
41
|
}
|