sysml-diagram 0.23.0 → 0.24.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/out/main.js CHANGED
@@ -162474,6 +162474,35 @@ function connectionEndMultiplicity(node) {
162474
162474
  return void 0;
162475
162475
  return hi == null || hi === lo ? `[${lo}]` : `[${lo}..${hi}]`;
162476
162476
  }
162477
+ function isEmptyPrefixFlow(node) {
162478
+ const fm = node;
162479
+ return node.$type === "FlowStmt" && fm.target !== void 0 && fm.source === void 0;
162480
+ }
162481
+ function flowStmtName(node) {
162482
+ return isEmptyPrefixFlow(node) ? void 0 : effectiveNameOf(node);
162483
+ }
162484
+ function flowKeyword(fm) {
162485
+ return `${fm.succession === true ? "succession " : ""}${fm.flowKind === "message" ? "message" : "flow"}`;
162486
+ }
162487
+ function flowTransferredFeature(ends) {
162488
+ const sourceFeature = ends.source ? lastSeg(ends.source) : void 0;
162489
+ const targetFeature = ends.target ? lastSeg(ends.target) : void 0;
162490
+ return sourceFeature === targetFeature ? sourceFeature : sourceFeature ?? targetFeature;
162491
+ }
162492
+ function flowDecorationMeta(carried) {
162493
+ const drawn = carried.filter((flow) => !flow.message);
162494
+ if (!drawn.length)
162495
+ return {};
162496
+ return {
162497
+ flowDecorations: drawn.map(({ keyword, label, name, reversed, row }) => ({
162498
+ keyword,
162499
+ ...label ? { label } : {},
162500
+ ...name ? { name } : {},
162501
+ reversed,
162502
+ ...row.source ? { source: row.source } : {}
162503
+ }))
162504
+ };
162505
+ }
162477
162506
  var END_PROPERTY_ADORNMENTS = /* @__PURE__ */ new Set(["abstract", "derived", "readonly", "ordered", "nonunique"]);
162478
162507
  var uniqueStrings = (values2) => [...new Set([...values2].filter((value) => !!value))];
162479
162508
  function formatConnectionEndAdornment(notation) {
@@ -164919,6 +164948,27 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164919
164948
  }
164920
164949
  return { source: void 0, target: fm.target ? String(fm.target) : void 0 };
164921
164950
  }
164951
+ // REQ-401 — the `flows-compartment` row of one flow or message usage (OMG
164952
+ // SysML 8.2.3.16). Rebuilt from the declaration instead of copied from the
164953
+ // source text, because a flow may carry a BODY (`flow a.x to b.y { doc ... }`)
164954
+ // whose whole text would otherwise be inlined into one compartment row.
164955
+ // `ends` overrides the declared endpoints with the concrete ones a relationship
164956
+ // usage rebinds them to (REQ-402).
164957
+ // REQ-401 — Flow notation: on-connection decoration, port docking, and the flow usage node
164958
+ flowRowText(flow, ends) {
164959
+ const fm = flow;
164960
+ const declared = ends ?? this.flowStmtEnds(fm);
164961
+ const type = typeText(flow);
164962
+ const payload = this.flowPayloadText(fm);
164963
+ return [
164964
+ flowKeyword(fm),
164965
+ flowStmtName(flow),
164966
+ type ? `: ${type}` : void 0,
164967
+ payload ? `of ${payload}` : void 0,
164968
+ declared.source ? `from ${declared.source}` : void 0,
164969
+ declared.target ? `to ${declared.target}` : void 0
164970
+ ].filter(Boolean).join(" ");
164971
+ }
164922
164972
  // Payload text of a flow/message (`of Fuel` / `of f : Fuel`) per OMG SysML
164923
164973
  // 8.2.2.16 PayloadFeature.
164924
164974
  flowPayloadText(fm) {
@@ -164928,6 +164978,87 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164928
164978
  const typeRef = p.type?.$refText ?? p.typing?.type?.$refText;
164929
164979
  return typeRef ? lastSeg(typeRef) : p.name;
164930
164980
  }
164981
+ // REQ-402 — the flows a connection or interface usage CARRIES. A flow declared
164982
+ // in a `connection def` / `interface def` body (OMG SysML 8.2.3.16, and the
164983
+ // `Flow Interface Example` of the training corpus) is transported by every
164984
+ // usage of that definition; it is not a transfer of its own between two
164985
+ // unrelated features. Each end path is rebound through the usage's own end
164986
+ // bindings, so the definition-local `supplierPort.fuelSupply` reads as the
164987
+ // concrete `tankAssy.fuelTankPort.fuelSupply` this usage connects, and the
164988
+ // transfer direction is expressed relative to the usage's own end ordinals so
164989
+ // it survives whichever notation the relationship is drawn in.
164990
+ // REQ-402 — Flows carried by a connection or interface usage
164991
+ carriedFlowsOf(usage, ends, index2, uri) {
164992
+ const ordinalByRole = /* @__PURE__ */ new Map();
164993
+ const pathByRole = /* @__PURE__ */ new Map();
164994
+ for (const end of ends) {
164995
+ const role = end.notation.role;
164996
+ if (!role)
164997
+ continue;
164998
+ if (!ordinalByRole.has(role))
164999
+ ordinalByRole.set(role, end.ordinal);
165000
+ if (end.path && !pathByRole.has(role))
165001
+ pathByRole.set(role, end.path);
165002
+ }
165003
+ const rebind = (path10) => {
165004
+ if (!path10)
165005
+ return void 0;
165006
+ const segs = path10.split(".");
165007
+ const bound = pathByRole.get(segs[0]);
165008
+ return bound ? [bound, ...segs.slice(1)].join(".") : path10;
165009
+ };
165010
+ const carried = [];
165011
+ const seen = /* @__PURE__ */ new Set();
165012
+ for (const source of [usage, ...this.inheritedFeatureOwnersOf(usage, index2)]) {
165013
+ for (const member of membersOf(source)) {
165014
+ if (member.$type !== "FlowStmt" || member.isDef === true)
165015
+ continue;
165016
+ const fm = member;
165017
+ const flowEnds = this.flowStmtEnds(fm);
165018
+ const name = flowStmtName(member);
165019
+ const payload = this.flowPayloadText(fm);
165020
+ const key = name ?? `\0${flowEnds.source ?? ""}\0${flowEnds.target ?? ""}\0${payload ?? typeText(member) ?? ""}`;
165021
+ if (seen.has(key))
165022
+ continue;
165023
+ seen.add(key);
165024
+ const fromOrdinal = flowEnds.source ? ordinalByRole.get(flowEnds.source.split(".")[0]) : void 0;
165025
+ const from = rebind(flowEnds.source);
165026
+ const to = rebind(flowEnds.target);
165027
+ carried.push({
165028
+ flow: member,
165029
+ keyword: flowKeyword(fm),
165030
+ label: payload ?? typeText(member) ?? flowTransferredFeature(flowEnds),
165031
+ name,
165032
+ // The decoration rides the relationship, whose drawn direction
165033
+ // runs from its first end to its second.
165034
+ reversed: fromOrdinal !== void 0 && fromOrdinal > 0,
165035
+ inherited: source !== usage,
165036
+ message: fm.flowKind === "message",
165037
+ row: {
165038
+ text: this.flowRowText(member, { source: from, target: to }),
165039
+ source: sourceOf2(member, uri)
165040
+ }
165041
+ });
165042
+ }
165043
+ }
165044
+ return carried;
165045
+ }
165046
+ // REQ-402 — merge the transfers a relationship usage carries from its
165047
+ // definitions into the `flows` compartment its own body already contributes,
165048
+ // so one heading holds every transfer the usage transports.
165049
+ // REQ-402 — Flows carried by a connection or interface usage
165050
+ withCarriedFlowRows(compartments, carried) {
165051
+ const rows = carried.filter((flow) => flow.inherited).map((flow) => flow.row);
165052
+ if (!rows.length)
165053
+ return compartments;
165054
+ const out = [...compartments ?? []];
165055
+ const existing = out.findIndex((compartment) => compartment.title === "flows");
165056
+ if (existing >= 0)
165057
+ out[existing] = { ...out[existing], items: [...out[existing].items, ...rows] };
165058
+ else
165059
+ out.push({ title: "flows", items: rows });
165060
+ return out;
165061
+ }
164931
165062
  // REQ-192/360/363 — the ONE recursive Interconnection View renderer. Given the
164932
165063
  // top-level `roots` to draw, it renders each part instance and nests its
164933
165064
  // internals recursively, drilling into a usage's type DEFINITION (+
@@ -164976,7 +165107,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164976
165107
  for (const source of [part, ...this.inheritedFeatureOwnersOf(part, index2)]) {
164977
165108
  for (const member of membersOf(source)) {
164978
165109
  const relationship = member;
164979
- const emptyPrefixFlow = member.$type === "FlowStmt" && relationship.target !== void 0 && relationship.source === void 0;
165110
+ const emptyPrefixFlow = isEmptyPrefixFlow(member);
164980
165111
  const emptyPrefixInterface = isInterfaceDecl(member) && relationship.target !== void 0 && relationship.connect === void 0;
164981
165112
  const namedRelationship = isConnectorDecl(member) || isConnectionDecl(member) || isInterfaceDecl(member) && !emptyPrefixInterface || member.$type === "BindingDecl" || member.$type === "FlowStmt" && !emptyPrefixFlow;
164982
165113
  if (namedRelationship) {
@@ -165334,6 +165465,8 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
165334
165465
  // synthetic n-ary dot with that container's frame id).
165335
165466
  emitInterconnectEdges(members, resolveEnd, parts, index2, uri, nodes, edges, eRef, frameId, actionPinIds = /* @__PURE__ */ new Set(), structuralPortIds = /* @__PURE__ */ new Set(), memberOwner, memberOwnerInherited = false, endpointProvenance = /* @__PURE__ */ new Map()) {
165336
165467
  const memberList2 = [...members];
165468
+ const pendingFlows = [];
165469
+ const firstEdge = edges.length;
165337
165470
  const relationshipFields = (source) => {
165338
165471
  let directMember = source;
165339
165472
  while (directMember.$container && directMember.$container !== memberOwner) {
@@ -165488,22 +165621,8 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
165488
165621
  }
165489
165622
  }
165490
165623
  } else if (m.$type === "FlowStmt") {
165491
- const fm = m;
165492
- if (fm.flowKind === "message")
165493
- continue;
165494
- const { source, target } = this.flowStmtEnds(fm);
165495
- const from = resolveEnd(source ?? "");
165496
- const to = resolveEnd(target ?? "");
165497
- if (from && to && supportsEndpoints("flow", [from, to])) {
165498
- edges.push({
165499
- id: `e${eRef.n++}`,
165500
- from,
165501
- to,
165502
- kind: "flow",
165503
- label: this.flowPayloadText(fm) ?? typeText(m) ?? nameOf2(m),
165504
- ...relationshipFields(m)
165505
- });
165506
- }
165624
+ if (m.isDef !== true)
165625
+ pendingFlows.push(m);
165507
165626
  } else if (m.$type === "BindStmt" || m.$type === "BindingConnectorStmt" || m.$type === "BindingDecl") {
165508
165627
  const bn = m;
165509
165628
  const leftEnd = bn.left ?? bn.source;
@@ -165591,6 +165710,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
165591
165710
  }
165592
165711
  };
165593
165712
  });
165713
+ const carriedFlows = this.carriedFlowsOf(m, usageEnds, index2, uri);
165594
165714
  nodes.push({
165595
165715
  id: usageId,
165596
165716
  name: name ?? ANONYMOUS_INTERFACE_NAME,
@@ -165601,12 +165721,13 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
165601
165721
  multiplicity: multText(m),
165602
165722
  ports,
165603
165723
  ...usageFrame ? { frame: usageFrame } : {},
165604
- compartments: this.compartmentsFor(m, uri, index2),
165724
+ compartments: this.withCarriedFlowRows(this.compartmentsFor(m, uri, index2), carriedFlows),
165605
165725
  source: usageSource,
165606
165726
  meta: {
165607
165727
  ...relationship.meta ?? {},
165608
165728
  interfaceUsage: true,
165609
- ...name ? { explicitRelationshipName: name } : {}
165729
+ ...name ? { explicitRelationshipName: name } : {},
165730
+ ...flowDecorationMeta(carriedFlows)
165610
165731
  }
165611
165732
  });
165612
165733
  for (const { end, ordinal, targetId } of visibleUsageEnds) {
@@ -165675,6 +165796,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
165675
165796
  }
165676
165797
  };
165677
165798
  });
165799
+ const carriedFlows = this.carriedFlowsOf(m, usageEnds, index2, uri);
165678
165800
  nodes.push({
165679
165801
  id: usageId,
165680
165802
  name: name ?? "connection",
@@ -165684,12 +165806,13 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
165684
165806
  type,
165685
165807
  ports,
165686
165808
  ...usageFrame ? { frame: usageFrame } : {},
165687
- compartments: this.compartmentsFor(m, uri, index2),
165809
+ compartments: this.withCarriedFlowRows(this.compartmentsFor(m, uri, index2), carriedFlows),
165688
165810
  source: usageSource,
165689
165811
  meta: {
165690
165812
  ...relationship.meta ?? {},
165691
165813
  connectionUsage: true,
165692
- ...name ? { explicitRelationshipName: name } : {}
165814
+ ...name ? { explicitRelationshipName: name } : {},
165815
+ ...flowDecorationMeta(carriedFlows)
165693
165816
  }
165694
165817
  });
165695
165818
  for (const { end, ordinal, targetId } of visibleUsageEnds) {
@@ -165717,6 +165840,92 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
165717
165840
  }
165718
165841
  }
165719
165842
  }
165843
+ const resolveFlowEnd = (pathText) => {
165844
+ const direct = resolveEnd(pathText);
165845
+ if (direct)
165846
+ return { id: direct, docked: false };
165847
+ const parts2 = pathText.split(/(::|\.)/u).filter((part) => part.length > 0);
165848
+ for (let length2 = parts2.length - 2; length2 >= 1; length2 -= 2) {
165849
+ const carrier = resolveEnd(parts2.slice(0, length2).join(""));
165850
+ if (carrier)
165851
+ return { id: carrier, docked: true };
165852
+ }
165853
+ return void 0;
165854
+ };
165855
+ const transportFor = (from, to) => edges.slice(firstEdge).find((edge) => (edge.kind === "connect" || edge.kind === "interface") && (edge.from === from && edge.to === to || edge.from === to && edge.to === from));
165856
+ const flowUsageNodeId = (flow) => {
165857
+ const src = sourceOf2(flow, uri);
165858
+ const ownerId = frameId ?? (qnameOf(memberOwner ?? flow) || "iv");
165859
+ const suffix = (frameId ? flowStmtName(flow) : qnameOf(flow)) ?? (src ? `${src.range.start.line}_${src.range.start.character}` : `${eRef.n}`);
165860
+ return `${ownerId}::__flow_${suffix}`;
165861
+ };
165862
+ for (const m of pendingFlows) {
165863
+ const fm = m;
165864
+ const message = fm.flowKind === "message";
165865
+ const keyword = flowKeyword(fm);
165866
+ const { source, target } = this.flowStmtEnds(fm);
165867
+ const flowName = flowStmtName(m);
165868
+ const sourceEnd = message ? void 0 : resolveFlowEnd(source ?? "");
165869
+ const targetEnd = message ? void 0 : resolveFlowEnd(target ?? "");
165870
+ const selfDock = sourceEnd !== void 0 && sourceEnd.id === targetEnd?.id && (sourceEnd.docked || targetEnd.docked);
165871
+ const from = selfDock ? void 0 : sourceEnd?.id;
165872
+ const to = selfDock ? void 0 : targetEnd?.id;
165873
+ const transferred = flowTransferredFeature({ source, target });
165874
+ const label = this.flowPayloadText(fm) ?? typeText(m) ?? transferred ?? flowName;
165875
+ if (from && to && supportsEndpoints("flow", [from, to])) {
165876
+ const transport = transportFor(from, to);
165877
+ if (transport) {
165878
+ const decorations = Array.isArray(transport.meta?.flowDecorations) ? transport.meta.flowDecorations : [];
165879
+ transport.meta = {
165880
+ ...transport.meta ?? {},
165881
+ flowDecorations: [...decorations, {
165882
+ keyword,
165883
+ label,
165884
+ ...flowName ? { name: flowName } : {},
165885
+ reversed: transport.from === to,
165886
+ source: sourceOf2(m, uri)
165887
+ }]
165888
+ };
165889
+ continue;
165890
+ }
165891
+ edges.push({
165892
+ id: `e${eRef.n++}`,
165893
+ from,
165894
+ to,
165895
+ kind: "flow",
165896
+ label,
165897
+ ...relationshipFields(m)
165898
+ });
165899
+ continue;
165900
+ }
165901
+ if (message || !flowName)
165902
+ continue;
165903
+ const ownerNode = frameId ? nodes.find((node) => node.id === frameId) : void 0;
165904
+ const ends = [
165905
+ ...source ? [{ text: `from ${source}` }] : [],
165906
+ ...target ? [{ text: `to ${target}` }] : []
165907
+ ];
165908
+ nodes.push({
165909
+ id: flowUsageNodeId(m),
165910
+ name: flowName,
165911
+ keyword,
165912
+ isDef: false,
165913
+ shape: "box",
165914
+ type: typeText(m),
165915
+ multiplicity: multText(m),
165916
+ ...ownerNode ? { frame: ownerNode.frame } : frameId ? { frame: frameId } : {},
165917
+ compartments: [
165918
+ ...label ? [{ title: "payload", items: [{ text: label }] }] : [],
165919
+ ...ends.length ? [{ title: "ends", items: ends }] : []
165920
+ ],
165921
+ source: sourceOf2(m, uri),
165922
+ meta: {
165923
+ ...relationshipFields(m).meta ?? {},
165924
+ flowUsage: true,
165925
+ explicitRelationshipName: flowName
165926
+ }
165927
+ });
165928
+ }
165720
165929
  }
165721
165930
  // ── iv overview (REQ-360) — recursive nested Interconnection View over a
165722
165931
  // package. The hierarchy follows COMPOSITION, not text layout: the roots are
@@ -167077,9 +167286,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167077
167286
  const to = resolvePin(ends.target, occurrenceContext);
167078
167287
  if (from && to) {
167079
167288
  const kind = fm.succession === true ? "successionFlow" : "flow";
167080
- const sourceFeature = ends.source ? lastSeg(ends.source) : void 0;
167081
- const targetFeature = ends.target ? lastSeg(ends.target) : void 0;
167082
- const transferredFeature = sourceFeature === targetFeature ? sourceFeature : sourceFeature ?? targetFeature;
167289
+ const transferredFeature = flowTransferredFeature(ends);
167083
167290
  edges.push({
167084
167291
  id: `e${e++}`,
167085
167292
  from,
@@ -169777,6 +169984,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
169777
169984
  }
169778
169985
  add("connections", members.filter((member) => isConnectionDecl(member) && member.isDef !== true && isOrdinaryMember(member)).map((member) => item(member, this.featureText(member) || "(anonymous connection)")));
169779
169986
  add("interfaces", members.filter((m) => isInterfaceDecl(m) && m.isDef !== true && isOrdinaryMember(m)).map((m) => item(m, this.interfaceRowText(m))));
169987
+ add("flows", members.filter((m) => m.$type === "FlowStmt" && m.isDef !== true && isOrdinaryMember(m)).map((m) => item(m, this.flowRowText(m))));
169780
169988
  add("features", members.filter((m) => m.$type === "FeatureShorthand" || m.$type === "FeatureRedefinitionShorthand").filter(isOrdinaryMember).filter((m) => !isOccurrenceModified(m)).map((m) => item(m, canonicalFeatureText(m))));
169781
169989
  const undirected = (guard) => usages(guard);
169782
169990
  add("items", undirected(isItemDecl).filter(notPortion).map((m) => item(m)));
@@ -183835,7 +184043,7 @@ function compartmentWidth(node) {
183835
184043
  }
183836
184044
  function nodeForCanvas(node) {
183837
184045
  if (node.meta?.connectionUsage === true || node.meta?.interfaceUsage === true) {
183838
- const compartments2 = node.compartments?.filter((compartment) => compartment.title === "doc");
184046
+ const compartments2 = node.compartments?.filter((compartment) => compartment.title === "doc" || compartment.title === "flows");
183839
184047
  return {
183840
184048
  ...node,
183841
184049
  compartments: compartments2?.length ? compartments2 : void 0
@@ -184367,7 +184575,8 @@ function hideExplicitRelationshipBoxes(model, relationship) {
184367
184575
  bindings: explicitRelationshipBindings(usage, model),
184368
184576
  endCount: usage.ports?.length ?? 0
184369
184577
  }));
184370
- const retainedIds = new Set(projections.filter(({ usage, bindings, endCount }) => (nodeForCanvas(usage).compartments?.length ?? 0) > 0 || annotatedUsageIds.has(usage.id) || endCount < 2 || bindings.length !== endCount).map(({ usage }) => usage.id));
184578
+ const blocksCompaction = ({ usage, endCount }) => (nodeForCanvas(usage).compartments ?? []).some((compartment) => endCount !== 2 || compartment.title !== "flows");
184579
+ const retainedIds = new Set(projections.filter((projection2) => blocksCompaction(projection2) || annotatedUsageIds.has(projection2.usage.id) || projection2.endCount < 2 || projection2.bindings.length !== projection2.endCount).map(({ usage }) => usage.id));
184371
184580
  const hiddenIds = /* @__PURE__ */ new Set();
184372
184581
  for (const { usage } of projections) {
184373
184582
  if (retainedIds.has(usage.id)) continue;
@@ -184424,6 +184633,8 @@ function hideExplicitRelationshipBoxes(model, relationship) {
184424
184633
  });
184425
184634
  continue;
184426
184635
  }
184636
+ const hubMeta = { ...baseMeta };
184637
+ delete hubMeta.flowDecorations;
184427
184638
  const hubId = `${usage.id}::__compact_hub`;
184428
184639
  compactNodes.push({
184429
184640
  id: hubId,
@@ -184434,7 +184645,7 @@ function hideExplicitRelationshipBoxes(model, relationship) {
184434
184645
  ...usage.frame ? { frame: usage.frame } : {},
184435
184646
  source: usage.source,
184436
184647
  meta: {
184437
- ...baseMeta,
184648
+ ...hubMeta,
184438
184649
  naryConnectionHub: true,
184439
184650
  ...relationship === "connection" ? { compactConnectionUsageHub: true } : { compactInterfaceUsageHub: true }
184440
184651
  }
@@ -184454,7 +184665,7 @@ function hideExplicitRelationshipBoxes(model, relationship) {
184454
184665
  endAdornmentTo: binding.adornment,
184455
184666
  source: usage.source ?? binding.edge.source,
184456
184667
  meta: {
184457
- ...baseMeta,
184668
+ ...hubMeta,
184458
184669
  ...relationship === "connection" ? { compactConnectionUsageEnd: true } : { compactInterfaceUsageEnd: true },
184459
184670
  connectionEndOrdinal: binding.ordinal,
184460
184671
  ...binding.role ? { connectionEndRole: binding.role } : {}
@@ -198165,6 +198376,45 @@ function successionFlowLabelPoint(centre, mark) {
198165
198376
  y: markCoordinate(centre.y - mark.normal.y * 16)
198166
198377
  };
198167
198378
  }
198379
+ function flowDecorationsOf(edge) {
198380
+ const raw = edge.meta?.flowDecorations;
198381
+ if (!Array.isArray(raw)) return [];
198382
+ return raw.flatMap((entry) => {
198383
+ if (!entry || typeof entry !== "object") return [];
198384
+ const decoration = entry;
198385
+ return [{
198386
+ keyword: typeof decoration.keyword === "string" ? decoration.keyword : "flow",
198387
+ label: typeof decoration.label === "string" ? decoration.label : void 0,
198388
+ name: typeof decoration.name === "string" ? decoration.name : void 0,
198389
+ reversed: decoration.reversed === true
198390
+ }];
198391
+ });
198392
+ }
198393
+ var FLOW_DECORATION_STEP = 26;
198394
+ function flowDecorationGeometry(centre, points, source, target, index2, count, reversed) {
198395
+ const raw = midpointTangent(points?.length ? points : [source, target]) ?? { x: target.x - source.x, y: target.y - source.y };
198396
+ const length2 = Math.hypot(raw.x, raw.y);
198397
+ if (length2 <= 0) return void 0;
198398
+ const tangent = { x: raw.x / length2, y: raw.y / length2 };
198399
+ const normal = { x: -tangent.y, y: tangent.x };
198400
+ const shift = (index2 - (count - 1) / 2) * FLOW_DECORATION_STEP;
198401
+ const at = { x: centre.x + tangent.x * shift, y: centre.y + tangent.y * shift };
198402
+ const sign = reversed ? -1 : 1;
198403
+ const tip = { x: at.x + tangent.x * 5 * sign, y: at.y + tangent.y * 5 * sign };
198404
+ const back = { x: at.x - tangent.x * 4 * sign, y: at.y - tangent.y * 4 * sign };
198405
+ const corner = (side) => ({
198406
+ x: back.x + normal.x * 4 * side,
198407
+ y: back.y + normal.y * 4 * side
198408
+ });
198409
+ const wing = [corner(1), corner(-1)];
198410
+ return {
198411
+ chevron: [tip, wing[0], wing[1]].map((point) => `${markCoordinate(point.x)},${markCoordinate(point.y)}`).join(" "),
198412
+ label: {
198413
+ x: markCoordinate(at.x + normal.x * 13),
198414
+ y: markCoordinate(at.y + normal.y * 13)
198415
+ }
198416
+ };
198417
+ }
198168
198418
  function routePointNearSource(points, source, target, distance2) {
198169
198419
  const route = [source, ...points ?? [], target].filter((point, index2, all) => index2 === 0 || point.x !== all[index2 - 1].x || point.y !== all[index2 - 1].y);
198170
198420
  let remaining = distance2;
@@ -199194,6 +199444,13 @@ body {
199194
199444
  .dlink { stroke: var(--diagram-line-structural); stroke-width: 1.2; fill: none; }
199195
199445
  .dlink.successionFlow { stroke-width: 2; }
199196
199446
  .dsuccession-flow-mark { pointer-events: none; stroke-linecap: butt; }
199447
+ /* REQ-401 \u2014 OMG 8.2.3.16 flow-on-connection: the payload chevron rides the
199448
+ connector that transports it, in the item-flow hue, and never takes pointer
199449
+ events away from the connector it decorates. */
199450
+ .dflow-decoration {
199451
+ pointer-events: none; stroke: none;
199452
+ fill: var(--diagram-line-connection, #6cd1d9);
199453
+ }
199197
199454
  /* REQ-196: AFV control transitions (IR succession) use a dotted route so
199198
199455
  they remain visually distinct from continuous item and succession flows. */
199199
199456
  .dlink.succession { stroke-dasharray: 1 3; stroke-linecap: round; }
@@ -200373,6 +200630,24 @@ function buildDiagramSvg(options) {
200373
200630
  extendPoint(sequencingMark.x1, sequencingMark.y1, 2);
200374
200631
  extendPoint(sequencingMark.x2, sequencingMark.y2, 2);
200375
200632
  }
200633
+ const decorations = semantic ? flowDecorationsOf(semantic) : [];
200634
+ decorations.forEach((decoration, index2) => {
200635
+ const placement = flowDecorationGeometry(
200636
+ geometry.label,
200637
+ geometry.points ?? geometry.anchors,
200638
+ geometry.source,
200639
+ geometry.target,
200640
+ index2,
200641
+ decorations.length,
200642
+ decoration.reversed === true
200643
+ );
200644
+ if (!placement) return;
200645
+ edgeParts.push(`<polygon class="dflow-decoration ${decoration.keyword.replace(/\s+/gu, "-")}" points="${placement.chevron}"/>`);
200646
+ const text = [decoration.name, decoration.label].filter(Boolean).join(" : ");
200647
+ if (!text) return;
200648
+ labelParts.push(labelSvg(text, placement.label.x, placement.label.y, "elabel flow"));
200649
+ extendLabel(text, placement.label.x, placement.label.y);
200650
+ });
200376
200651
  extendPoint(geometry.source.x, geometry.source.y, MARKER_ALLOWANCE);
200377
200652
  extendPoint(geometry.target.x, geometry.target.y, MARKER_ALLOWANCE);
200378
200653
  for (const point of geometry.points ?? geometry.anchors) extendPoint(point.x, point.y, MARKER_ALLOWANCE);
@@ -203682,7 +203957,7 @@ async function runExport(command) {
203682
203957
  }
203683
203958
 
203684
203959
  // src/main.ts
203685
- var VERSION2 = true ? "0.23.0" : "dev";
203960
+ var VERSION2 = true ? "0.24.0" : "dev";
203686
203961
  function display(file) {
203687
203962
  const rel2 = path9.relative(process.cwd(), file);
203688
203963
  return rel2 && !rel2.startsWith("..") ? rel2.split(path9.sep).join("/") : file;