sysml-diagram 0.25.0 → 0.26.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
@@ -162649,7 +162649,12 @@ function keywordFor(node) {
162649
162649
  JoinNode: "join",
162650
162650
  TerminateNode: "terminate",
162651
162651
  PerformStmt: "perform action",
162652
- EventDecl: "event occurrence"
162652
+ EventDecl: "event occurrence",
162653
+ // REQ-198, issue #113: a state sub-action drawn as a state-transition
162654
+ // node keeps the keyword that says WHEN it runs (OMG 8.2.2.18.1).
162655
+ EntryAction: "entry action",
162656
+ DoAction: "do action",
162657
+ ExitAction: "exit action"
162653
162658
  };
162654
162659
  if (t === "ActionDecl" && n2.inlineBody?.$type === "AcceptNode") {
162655
162660
  return "accept action";
@@ -167625,7 +167630,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167625
167630
  const def = this.resolveType(holder, index2);
167626
167631
  return def && def !== holder && def.isDef === true ? def : void 0;
167627
167632
  };
167628
- const ownStates = (holder) => membersOf(holder).filter((member) => isStateDecl(member) && nameOf2(member) !== void 0);
167633
+ const ownStates = (holder) => membersOf(holder).map((member) => this.thenActionMemberNode(member) ?? member).filter((member) => isStateDecl(member) && nameOf2(member) !== void 0);
167629
167634
  const nestedStates = (holder) => {
167630
167635
  const out = ownStates(holder);
167631
167636
  const def = definitionOf(holder);
@@ -167664,9 +167669,28 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167664
167669
  drawnStates.push({ node: anchor, id: anchorFrameId });
167665
167670
  idByState.set(anchor, anchorFrameId);
167666
167671
  }
167672
+ const drawnRowKeys = /* @__PURE__ */ new Set();
167673
+ const rowKey = (source) => source ? `${source.uri} ${source.range.start.line} ${source.range.start.character}` : void 0;
167674
+ const registerDrawn = (member) => {
167675
+ const key = rowKey(sourceOf2(member, uri));
167676
+ if (key)
167677
+ drawnRowKeys.add(key);
167678
+ };
167679
+ const namesByFrame = /* @__PURE__ */ new Map();
167680
+ const namesIn = (frameId) => {
167681
+ const key = frameId ?? "";
167682
+ const existing = namesByFrame.get(key);
167683
+ if (existing)
167684
+ return existing;
167685
+ const created = /* @__PURE__ */ new Map();
167686
+ namesByFrame.set(key, created);
167687
+ return created;
167688
+ };
167667
167689
  const renderState = (s, parentFrame, depth, seen) => {
167668
167690
  const id2 = qnameOf(s) || nameOf2(s);
167669
167691
  byName.set(nameOf2(s), id2);
167692
+ namesIn(parentFrame).set(nameOf2(s), id2);
167693
+ registerDrawn(s);
167670
167694
  drawnStates.push({ node: s, id: id2 });
167671
167695
  idByState.set(s, id2);
167672
167696
  const def = s.isDef === true ? void 0 : this.resolveType(s, index2);
@@ -167704,6 +167728,75 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167704
167728
  };
167705
167729
  for (const s of topStates)
167706
167730
  renderState(s, anchorFrameId, 0, /* @__PURE__ */ new Set());
167731
+ const endpointName = (path10) => typeof path10 === "string" ? path10.split(/::|\./).pop() || void 0 : void 0;
167732
+ const controlNodeInfo = (m) => {
167733
+ switch (m.$type) {
167734
+ case "ActionDecl":
167735
+ return m.isDef === true || !nameOf2(m) ? void 0 : { shape: "action", label: nameOf2(m) };
167736
+ // A `perform` names the action it performs, which for a feature
167737
+ // chain (`perform machine.selfTest;`) is the LAST segment.
167738
+ case "PerformStmt": {
167739
+ const segments = [nameOf2(m), ...m.chainSegs ?? []].filter((segment) => !!segment);
167740
+ return { shape: "action", label: segments.at(-1) ?? typeText(m) ?? "perform" };
167741
+ }
167742
+ // User direction 2026-08-30: fork and join only. They express
167743
+ // concurrency, which a transition cannot say: nothing about a
167744
+ // guard or a trigger splits control into parallel regions or
167745
+ // gathers it again. `decide` and `merge` are dropped because a
167746
+ // branch between states IS a guarded transition, which this
167747
+ // view already draws and labels, so a diamond would say the
167748
+ // same thing a second time in the action-flow idiom.
167749
+ // `terminate` is dropped with them: the node carries no name,
167750
+ // so no succession can reach it and it could only ever stand
167751
+ // alone. All three remain in the OMG 8.2.3.18 node set.
167752
+ case "JoinNode":
167753
+ return { shape: "join", label: nameOf2(m) ?? "" };
167754
+ case "ForkNode":
167755
+ return { shape: "fork", label: nameOf2(m) ?? "" };
167756
+ default:
167757
+ return void 0;
167758
+ }
167759
+ };
167760
+ const isInitialMarker = (member) => {
167761
+ const entry = member;
167762
+ return !!entry && entry.$type === "EntryAction" && !entry.name && !entry.actionKw && !entry.send && !entry.accept && !entry.assign;
167763
+ };
167764
+ const machineNodeIds = /* @__PURE__ */ new Map();
167765
+ const machineNodeMembers = [];
167766
+ let anonymousNodes = 0;
167767
+ const emitMachineNodes = (holder, frameId) => {
167768
+ const members = membersOf(holder);
167769
+ const drawnHere = namesIn(frameId);
167770
+ for (const raw of members) {
167771
+ const member = this.thenActionMemberNode(raw) ?? raw;
167772
+ const info = controlNodeInfo(member);
167773
+ if (!info)
167774
+ continue;
167775
+ const name = nameOf2(member);
167776
+ if (name && drawnHere.has(name))
167777
+ continue;
167778
+ const id2 = name ? qnameOf(member) || `${frameId}::${name}` : `${frameId}::__stv_${member.$type}_${anonymousNodes++}__`;
167779
+ if (nodes.some((n2) => n2.id === id2) || frames.some((f) => f.id === id2))
167780
+ continue;
167781
+ if (name) {
167782
+ drawnHere.set(name, id2);
167783
+ if (!byName.has(name))
167784
+ byName.set(name, id2);
167785
+ }
167786
+ machineNodeIds.set(member, id2);
167787
+ machineNodeMembers.push({ member, id: id2 });
167788
+ nodes.push({
167789
+ id: id2,
167790
+ name: info.label,
167791
+ keyword: keywordFor(member),
167792
+ isDef: false,
167793
+ shape: info.shape,
167794
+ compartments: this.compartmentsFor(member, uri, index2),
167795
+ frame: frameId,
167796
+ source: sourceOf2(member, uri)
167797
+ });
167798
+ }
167799
+ };
167707
167800
  const edges = [];
167708
167801
  let e = 0;
167709
167802
  const resolveState = (nm) => {
@@ -167719,53 +167812,201 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167719
167812
  }
167720
167813
  return void 0;
167721
167814
  };
167722
- const transitionScope = [anchor, ...definitionOf(anchor) ? [definitionOf(anchor)] : []];
167723
- for (const t of transitionScope.flatMap((holder) => [...ast_utils_exports.streamAllContents(holder)])) {
167724
- if (t.$type !== "TransitionDecl")
167725
- continue;
167726
- const tn = t;
167727
- const from = resolveState(tn.from);
167728
- const to = resolveState(tn.to);
167815
+ const drawnEdges = /* @__PURE__ */ new Set();
167816
+ const stateLike = /* @__PURE__ */ new Set(["state", "initial", "final"]);
167817
+ const isStateEndpoint = (id2) => {
167818
+ const node = nodes.find((n2) => n2.id === id2);
167819
+ return node ? stateLike.has(node.shape) : frames.some((f) => f.id === id2);
167820
+ };
167821
+ const link = (from, to, label, src) => {
167729
167822
  if (!from || !to)
167730
- continue;
167823
+ return;
167824
+ const kind = isStateEndpoint(from) && isStateEndpoint(to) ? "transition" : "succession";
167825
+ const key = `${from}\0${to}\0${label ?? ""}`;
167826
+ if (drawnEdges.has(key))
167827
+ return;
167828
+ drawnEdges.add(key);
167829
+ if (src)
167830
+ registerDrawn(src);
167731
167831
  edges.push({
167732
167832
  id: `e${e++}`,
167733
167833
  from,
167734
167834
  to,
167735
- kind: "transition",
167736
- label: this.transitionLabel(t),
167737
- source: sourceOf2(t, uri)
167835
+ kind,
167836
+ label,
167837
+ source: src ? sourceOf2(src, uri) : void 0
167738
167838
  });
167839
+ };
167840
+ const guardText = (guard) => {
167841
+ const text = guard?.$cstNode?.text?.replace(/\s+/g, " ").trim();
167842
+ return text ? `[${text}]` : void 0;
167843
+ };
167844
+ const resolveEndpoint = (path10, initialId, frameId) => {
167845
+ if (typeof path10 !== "string")
167846
+ return void 0;
167847
+ const short = endpointName(path10);
167848
+ const local = namesByFrame.get(frameId ?? "");
167849
+ return (short ? local?.get(short) : void 0) ?? resolveState(path10) ?? resolveState(short) ?? (short === "start" ? initialId : void 0);
167850
+ };
167851
+ const transitionScope = [anchor, ...definitionOf(anchor) ? [definitionOf(anchor)] : []];
167852
+ for (const t of transitionScope.flatMap((holder) => [...ast_utils_exports.streamAllContents(holder)])) {
167853
+ if (t.$type !== "TransitionDecl")
167854
+ continue;
167855
+ const tn = t;
167856
+ link(resolveState(tn.from), resolveState(tn.to), this.transitionLabel(t), t);
167739
167857
  }
167740
- const designatedInitial = (owner) => {
167858
+ const designatedInitial = (owner, frameId) => {
167741
167859
  const members = owner.members;
167742
167860
  if (!Array.isArray(members))
167743
167861
  return void 0;
167744
- for (let i = 0; i < members.length - 1; i++) {
167745
- const entry = members[i];
167746
- if (entry.$type !== "EntryAction" || entry.name || entry.actionKw || entry.send || entry.accept || entry.assign)
167862
+ for (let i = 0; i < members.length; i++) {
167863
+ const member = members[i];
167864
+ if (member.$type === "FirstThenChain") {
167865
+ const chain = member;
167866
+ if (endpointName(chain.head) !== "start")
167867
+ continue;
167868
+ const target2 = resolveEndpoint((chain.steps ?? [])[0], void 0, frameId);
167869
+ if (target2) {
167870
+ registerDrawn(member);
167871
+ return target2;
167872
+ }
167873
+ continue;
167874
+ }
167875
+ if (!isInitialMarker(member))
167747
167876
  continue;
167748
167877
  const then = members[i + 1];
167749
167878
  if (then?.$type !== "ThenActionMember" || typeof then.target !== "string")
167750
167879
  continue;
167751
167880
  const target = resolveState(lastSeg(then.target));
167752
- if (target)
167881
+ if (target) {
167882
+ registerDrawn(then);
167753
167883
  return target;
167884
+ }
167754
167885
  }
167755
167886
  return void 0;
167756
167887
  };
167757
- const anchorDefinition = definitionOf(anchor);
167758
- const firstStateId = designatedInitial(anchor) ?? (anchorDefinition ? designatedInitial(anchorDefinition) : void 0) ?? (topStates.length ? byName.get(nameOf2(topStates[0])) : void 0);
167759
- if (firstStateId) {
167760
- edges.push({ id: `e${e++}`, from: "__initial__", to: firstStateId, kind: "transition" });
167888
+ const machineScope = (holder) => {
167889
+ const def = definitionOf(holder);
167890
+ return def ? [holder, def] : [holder];
167891
+ };
167892
+ if (anchorFrameId) {
167893
+ for (const holder of machineScope(anchor))
167894
+ emitMachineNodes(holder, anchorFrameId);
167761
167895
  }
167762
167896
  for (const { state, frameId } of compositeFrames) {
167763
- const target = designatedInitial(state);
167897
+ for (const holder of machineScope(state))
167898
+ emitMachineNodes(holder, frameId);
167899
+ }
167900
+ const anchorDefinition = definitionOf(anchor);
167901
+ const firstStateId = designatedInitial(anchor, anchorFrameId) ?? (anchorDefinition ? designatedInitial(anchorDefinition, anchorFrameId) : void 0) ?? (topStates.length ? byName.get(nameOf2(topStates[0])) : void 0);
167902
+ if (firstStateId)
167903
+ link("__initial__", firstStateId, void 0, void 0);
167904
+ const compositeInitial = /* @__PURE__ */ new Map();
167905
+ for (const { state, frameId } of compositeFrames) {
167906
+ const target = designatedInitial(state, frameId);
167764
167907
  if (!target)
167765
167908
  continue;
167766
167909
  const id2 = `__initial__${frameId}`;
167767
167910
  nodes.push({ id: id2, name: "", keyword: "initial", isDef: false, shape: "initial", frame: frameId });
167768
- edges.push({ id: `e${e++}`, from: id2, to: target, kind: "transition" });
167911
+ compositeInitial.set(state, id2);
167912
+ link(id2, target, void 0, void 0);
167913
+ }
167914
+ const sequentialTransitions = (holder, initialId, frameId) => {
167915
+ let cursor;
167916
+ const idOf = (member) => machineNodeIds.get(member) ?? idByState.get(member) ?? (nameOf2(member) ? resolveEndpoint(nameOf2(member), void 0, frameId) : void 0);
167917
+ const endpoint = (path10) => resolveEndpoint(path10, initialId, frameId);
167918
+ for (const member of membersOf(holder)) {
167919
+ switch (member.$type) {
167920
+ case "StateDecl": {
167921
+ cursor = idOf(member) ?? cursor;
167922
+ break;
167923
+ }
167924
+ // `entry;` IS the start pseudostate, so the succession written
167925
+ // after it leaves that pseudostate rather than the last state.
167926
+ case "EntryAction": {
167927
+ if (isInitialMarker(member)) {
167928
+ cursor = initialId;
167929
+ break;
167930
+ }
167931
+ cursor = machineNodeIds.get(member) ?? cursor;
167932
+ break;
167933
+ }
167934
+ // OMG 8.2.3.18 names this edge `st-succession`, so the
167935
+ // keyworded form is a first-class state-transition edge,
167936
+ // not action-language sugar the state view may skip.
167937
+ // Its ends are ConnectorEnds, not bare paths.
167938
+ case "SuccessionStmt": {
167939
+ const succession = member;
167940
+ let previous = endpoint(this.connectorEndPath(succession.first));
167941
+ let firstHop = true;
167942
+ for (const step of succession.steps ?? []) {
167943
+ const to = endpoint(this.connectorEndPath(step));
167944
+ link(previous, to, firstHop ? guardText(succession.guard) : void 0, member);
167945
+ previous = to;
167946
+ firstHop = false;
167947
+ }
167948
+ if (previous)
167949
+ cursor = previous;
167950
+ break;
167951
+ }
167952
+ case "FirstThenChain": {
167953
+ const chain = member;
167954
+ let previous = endpoint(chain.head);
167955
+ let firstHop = true;
167956
+ for (const step of chain.steps ?? []) {
167957
+ const to = endpoint(step);
167958
+ link(previous, to, firstHop ? guardText(chain.guard) : void 0, member);
167959
+ previous = to;
167960
+ firstHop = false;
167961
+ }
167962
+ if (previous)
167963
+ cursor = previous;
167964
+ break;
167965
+ }
167966
+ case "AcceptNode": {
167967
+ const accept = member;
167968
+ if (typeof accept.thenTarget !== "string")
167969
+ break;
167970
+ link(cursor, endpoint(accept.thenTarget), this.acceptShorthandLabel(member), member);
167971
+ break;
167972
+ }
167973
+ case "ThenActionMember": {
167974
+ const then = member;
167975
+ const declared = this.thenActionMemberNode(member);
167976
+ const to = (declared ? idOf(declared) : void 0) ?? endpoint(then.target);
167977
+ link(cursor, to, void 0, member);
167978
+ if (to)
167979
+ cursor = to;
167980
+ break;
167981
+ }
167982
+ // issue #113: a guarded or default target succession fans out
167983
+ // of the SAME source (a decision node, normally), so neither
167984
+ // branch may advance the cursor past its siblings.
167985
+ case "IfActionNode": {
167986
+ const branch = member;
167987
+ if (typeof branch.thenTarget !== "string")
167988
+ break;
167989
+ link(cursor, endpoint(branch.thenTarget), guardText(branch.cond), member);
167990
+ break;
167991
+ }
167992
+ case "ElseSuccessionMember": {
167993
+ link(cursor, endpoint(member.target), "else", member);
167994
+ break;
167995
+ }
167996
+ default: {
167997
+ cursor = machineNodeIds.get(member) ?? cursor;
167998
+ break;
167999
+ }
168000
+ }
168001
+ }
168002
+ };
168003
+ for (const holder of machineScope(anchor)) {
168004
+ sequentialTransitions(holder, hostsStateMachine ? "__initial__" : void 0, anchorFrameId);
168005
+ }
168006
+ for (const { state, frameId } of compositeFrames) {
168007
+ for (const holder of machineScope(state)) {
168008
+ sequentialTransitions(holder, compositeInitial.get(state), frameId);
168009
+ }
167769
168010
  }
167770
168011
  const exhibitorsByState = /* @__PURE__ */ new Map();
167771
168012
  const exhibitScope = this.packageScopeOf(anchor);
@@ -167847,6 +168088,37 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167847
168088
  edges.push({ id: `e${e++}`, from, to, kind: "causation", label: "\xABcausation\xBB", source: sourceOf2(c, uri) });
167848
168089
  }
167849
168090
  }
168091
+ const wired = /* @__PURE__ */ new Set();
168092
+ for (const edge of edges) {
168093
+ wired.add(edge.from);
168094
+ wired.add(edge.to);
168095
+ }
168096
+ const stranded = new Set(machineNodeMembers.filter(({ id: id2 }) => !wired.has(id2)).map(({ id: id2 }) => id2));
168097
+ if (stranded.size) {
168098
+ for (let at = nodes.length - 1; at >= 0; at--) {
168099
+ if (stranded.has(nodes[at].id))
168100
+ nodes.splice(at, 1);
168101
+ }
168102
+ }
168103
+ for (const { member, id: id2 } of machineNodeMembers) {
168104
+ if (!stranded.has(id2))
168105
+ registerDrawn(member);
168106
+ }
168107
+ for (const frame2 of frames) {
168108
+ const full = frame2.compartments;
168109
+ if (!full?.length)
168110
+ continue;
168111
+ const kept = full.map((compartment) => ({
168112
+ title: compartment.title,
168113
+ items: compartment.items.filter((row) => {
168114
+ const key = rowKey(row.source);
168115
+ return !key || !drawnRowKeys.has(key);
168116
+ })
168117
+ })).filter((compartment) => compartment.items.length > 0);
168118
+ if (kept.length === full.length && kept.every((c, at) => c.items.length === full[at].items.length))
168119
+ continue;
168120
+ frame2.compartments = kept.length ? kept : void 0;
168121
+ }
167850
168122
  const model = this.model("stv", anchor, nodes, edges);
167851
168123
  if (frames.length) {
167852
168124
  model.frames = frames;
@@ -170032,9 +170304,25 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
170032
170304
  return item(m, val ? `= ${val}` : "(value)");
170033
170305
  }));
170034
170306
  add("states", usages(isStateDecl).map((m) => item(m)));
170035
- const stateActions = members.map((m) => ({ m, kind: { EntryAction: "entry", DoAction: "do", ExitAction: "exit" }[m.$type] })).filter((x) => !!x.kind);
170036
- add("state actions", stateActions.map(({ m, kind }) => item(m, `${kind} ${nameOf2(m) ?? ""}`.trim())));
170307
+ const isInitialStateMarker = (m, at) => {
170308
+ const entry = m;
170309
+ if (m.$type !== "EntryAction" || entry.name || entry.actionKw || entry.send || entry.accept || entry.assign)
170310
+ return false;
170311
+ const next = members[at + 1];
170312
+ return next?.$type === "ThenActionMember" || next?.$type === "FirstThenChain";
170313
+ };
170314
+ const stateActionTitle = {
170315
+ EntryAction: "entry",
170316
+ DoAction: "during",
170317
+ ExitAction: "exit"
170318
+ };
170319
+ const stateActionText = (m) => nameOf2(m) ?? (m.$cstNode?.text ?? "").replace(/\s+/g, " ").replace(/;$/, "").replace(/^(entry|do|exit)\s+(action\s+)?/, "").trim();
170320
+ for (const title of ["entry", "during", "exit"]) {
170321
+ add(title, members.filter((m, at) => stateActionTitle[m.$type] === title && !isInitialStateMarker(m, at)).map((m) => item(m, stateActionText(m))).filter((row) => !!row.text));
170322
+ }
170037
170323
  add("state transition", members.filter((m) => m.$type === "TransitionDecl").map((m) => item(m, `${m.from ?? ""} \u2192 ${m.to ?? ""}`)));
170324
+ const successionText = (m) => (m.$cstNode?.text ?? "").replace(/\s+/g, " ").replace(/;$/, "").trim();
170325
+ add("successions", members.filter((m) => m.$type === "FirstThenChain" || m.$type === "SuccessionStmt" || m.$type === "ThenActionMember" && typeof m.target === "string" || m.$type === "ElseSuccessionMember" || (m.$type === "AcceptNode" || m.$type === "IfActionNode") && typeof m.thenTarget === "string").map((m) => item(m, successionText(m))).filter((row) => !!row.text));
170038
170326
  add("assert constraints", members.filter((m) => m.$type === "AssertConstraintStmt").map((m) => item(m, exprText3(m) || nameOf2(m) || "assert constraint")));
170039
170327
  add("invariants", members.filter((m) => m.$type === "InvShorthand").map((m) => {
170040
170328
  const inv = m;
@@ -170125,9 +170413,19 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
170125
170413
  // REQ-186/REQ-198 — transition label: `trigger [guard] / effect`.
170126
170414
  transitionLabel(t) {
170127
170415
  const tn = t;
170128
- const trigger = this.acceptTriggerLabel(tn.accept);
170129
- const guard = tn.guard?.$cstNode?.text?.replace(/\s+/g, " ").trim();
170130
- const effect = this.effectLabel(tn.effect);
170416
+ return this.transitionLabelOf(tn.accept, tn.guard, tn.effect);
170417
+ }
170418
+ // REQ-198: the label of a source-less transition shorthand (`accept Sig if g
170419
+ // do effect then t;`, OMG SysML 8.2.2.18.3). The accept node itself carries
170420
+ // the trigger, so it reads exactly like an explicit `transition`.
170421
+ acceptShorthandLabel(accept) {
170422
+ const node = accept;
170423
+ return this.transitionLabelOf(accept, node.guard, node.effect);
170424
+ }
170425
+ transitionLabelOf(accept, guardExpr, effectClause) {
170426
+ const trigger = this.acceptTriggerLabel(accept);
170427
+ const guard = guardExpr?.$cstNode?.text?.replace(/\s+/g, " ").trim();
170428
+ const effect = this.effectLabel(effectClause);
170131
170429
  const parts = [];
170132
170430
  if (trigger)
170133
170431
  parts.push(String(trigger));
@@ -196775,7 +197073,7 @@ var AFV_LAYOUT_EDGE_KINDS = /* @__PURE__ */ new Set([
196775
197073
  "succession",
196776
197074
  "successionFlow"
196777
197075
  ]);
196778
- var STV_LAYOUT_EDGE_KINDS = /* @__PURE__ */ new Set(["transition"]);
197076
+ var STV_LAYOUT_EDGE_KINDS = /* @__PURE__ */ new Set(["transition", "succession"]);
196779
197077
  function behaviorLayoutEdgeKinds(kind) {
196780
197078
  return kind === "afv" ? AFV_LAYOUT_EDGE_KINDS : kind === "stv" ? STV_LAYOUT_EDGE_KINDS : void 0;
196781
197079
  }
@@ -201984,6 +202282,10 @@ var TOOLBOX = {
201984
202282
  ],
201985
202283
  relations: [
201986
202284
  rel("transition", "transition", "\u2192", "click the source state, then the target state"),
202285
+ // issue #113 - a machine's action and control nodes are sequenced by
202286
+ // a succession, not by a transition: `transition` needs a state at
202287
+ // both ends (OMG SysML 8.2.2.18.3), while `first a then b` does not.
202288
+ rel("succession", "succession", "\u21E2", "click the source node, then the target node"),
201987
202289
  // issue #115 — nothing could mark the initial state, so a state
201988
202290
  // machine could not be STARTED from a blank canvas. The gesture runs
201989
202291
  // from the always-drawn initial pseudostate to the first state.
@@ -202142,7 +202444,11 @@ function normalizedElementKeyword(keyword) {
202142
202444
  "loop action",
202143
202445
  "for-loop action",
202144
202446
  "perform action",
202145
- "assign"
202447
+ "assign",
202448
+ // issue #113 — a state sub-action drawn as a node is an action node.
202449
+ "entry action",
202450
+ "do action",
202451
+ "exit action"
202146
202452
  ].includes(base)) {
202147
202453
  base = "action";
202148
202454
  } else if (["fork", "join", "merge", "decide", "decision"].includes(base)) {
@@ -202244,7 +202550,12 @@ function relationToolsForNode(keyword, viewKind, shape) {
202244
202550
  if (base === "port") return false;
202245
202551
  return base === "pin" && (tool.kind === "flow" || tool.kind === "successionFlow" || tool.kind === "bind");
202246
202552
  }
202247
- if (viewKind === "stv") return base === "state" && tool.kind !== "initial";
202553
+ if (viewKind === "stv") {
202554
+ if (base === "action" || base === "control") {
202555
+ return tool.kind === "succession" || tool.kind === TERMINAL_RELATION;
202556
+ }
202557
+ return base === "state" && tool.kind !== "initial";
202558
+ }
202248
202559
  if (viewKind === "sv") return shape === "lifeline" && (base === "part" || base === "lifeline");
202249
202560
  if (viewKind === "cv") {
202250
202561
  if (base === "actor") return tool.kind === "actor";
@@ -204707,7 +205018,7 @@ async function runExport(command) {
204707
205018
  }
204708
205019
 
204709
205020
  // src/main.ts
204710
- var VERSION2 = true ? "0.25.0" : "dev";
205021
+ var VERSION2 = true ? "0.26.0" : "dev";
204711
205022
  function display(file) {
204712
205023
  const rel2 = path9.relative(process.cwd(), file);
204713
205024
  return rel2 && !rel2.startsWith("..") ? rel2.split(path9.sep).join("/") : file;