sysml-diagram 0.24.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 +1122 -61
- package/out/main.js.map +4 -4
- package/package.json +1 -1
- package/resources/sysml.dimension-table.json +1 -1
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";
|
|
@@ -165264,16 +165269,16 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
165264
165269
|
};
|
|
165265
165270
|
const performedActions = depth < 8 && !(typeQ !== void 0 && seenTypes.has(typeQ)) ? effectiveMembersOf(part).filter((m) => m.$type === "PerformStmt" && !!nameOf2(m)).map((act) => {
|
|
165266
165271
|
const pinSource = this.performTargetOf(act, index2) ?? act;
|
|
165267
|
-
const
|
|
165272
|
+
const pathSegments2 = this.isAnonymousBehaviorReference(act) ? this.featurePaths.resolveDeclarationPath(act).segments.map((segment) => segment.text) : [nameOf2(act)];
|
|
165268
165273
|
return {
|
|
165269
165274
|
act,
|
|
165270
165275
|
pinSource,
|
|
165271
|
-
pathSegments,
|
|
165272
|
-
name:
|
|
165276
|
+
pathSegments: pathSegments2,
|
|
165277
|
+
name: pathSegments2.at(-1) ?? nameOf2(act),
|
|
165273
165278
|
key: concretePerformPath(act, pinSource)
|
|
165274
165279
|
};
|
|
165275
165280
|
}).filter((entry, i, list) => list.findIndex((other) => other.key === entry.key) === i) : [];
|
|
165276
|
-
const performedActionInfos = performedActions.map(({ act, pinSource, pathSegments, name, key }) => {
|
|
165281
|
+
const performedActionInfos = performedActions.map(({ act, pinSource, pathSegments: pathSegments2, name, key }) => {
|
|
165277
165282
|
const id2 = `${instanceId}::__perform_${key}`;
|
|
165278
165283
|
const inheritedFromDefinition = !!localUsage && !isAstDescendantOrSelf(act, localUsage);
|
|
165279
165284
|
const syncDeclaration2 = this.synchronizationDeclarationOf(act, index2);
|
|
@@ -165281,7 +165286,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
165281
165286
|
act,
|
|
165282
165287
|
name,
|
|
165283
165288
|
id: id2,
|
|
165284
|
-
pathSegments,
|
|
165289
|
+
pathSegments: pathSegments2,
|
|
165285
165290
|
pins: this.actionPinPorts(pinSource, id2, index2, uri),
|
|
165286
165291
|
meta: {
|
|
165287
165292
|
...ivEditMeta(act, id2, void 0, localUsage, [...localPath, name], uri),
|
|
@@ -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
|
|
167723
|
-
|
|
167724
|
-
|
|
167725
|
-
|
|
167726
|
-
|
|
167727
|
-
|
|
167728
|
-
|
|
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
|
-
|
|
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
|
|
167736
|
-
label
|
|
167737
|
-
source: sourceOf2(
|
|
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
|
|
167745
|
-
const
|
|
167746
|
-
if (
|
|
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
|
|
167758
|
-
|
|
167759
|
-
|
|
167760
|
-
|
|
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);
|
|
167895
|
+
}
|
|
167896
|
+
for (const { state, frameId } of compositeFrames) {
|
|
167897
|
+
for (const holder of machineScope(state))
|
|
167898
|
+
emitMachineNodes(holder, frameId);
|
|
167761
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();
|
|
167762
167905
|
for (const { state, frameId } of compositeFrames) {
|
|
167763
|
-
const target = designatedInitial(state);
|
|
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
|
-
|
|
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
|
|
170036
|
-
|
|
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
|
-
|
|
170129
|
-
|
|
170130
|
-
|
|
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));
|
|
@@ -170418,7 +170716,9 @@ var sysmlInlayHintSettings = {
|
|
|
170418
170716
|
modifiers: false,
|
|
170419
170717
|
specialization: false,
|
|
170420
170718
|
redefinition: false,
|
|
170421
|
-
effectiveNames: false
|
|
170719
|
+
effectiveNames: false,
|
|
170720
|
+
importedNames: false,
|
|
170721
|
+
parameterNames: false
|
|
170422
170722
|
};
|
|
170423
170723
|
|
|
170424
170724
|
// ../language-server/out/src/services/category-taxonomy.js
|
|
@@ -181119,6 +181419,329 @@ var SysmlSemanticTokenProvider = class extends AbstractSemanticTokenProvider {
|
|
|
181119
181419
|
|
|
181120
181420
|
// ../language-server/out/src/services/inlay-hint-provider.js
|
|
181121
181421
|
var import_vscode_languageserver20 = __toESM(require_main4(), 1);
|
|
181422
|
+
|
|
181423
|
+
// ../language-server/out/src/services/name-lookup.js
|
|
181424
|
+
function unquoteName3(name) {
|
|
181425
|
+
return name.replace(/^'(.*)'$/u, "$1");
|
|
181426
|
+
}
|
|
181427
|
+
function pathSegments(path10) {
|
|
181428
|
+
const segments = [];
|
|
181429
|
+
let current2 = "";
|
|
181430
|
+
let quoted = false;
|
|
181431
|
+
for (let index2 = 0; index2 < path10.length; index2++) {
|
|
181432
|
+
const char = path10[index2];
|
|
181433
|
+
if (char === "'") {
|
|
181434
|
+
quoted = !quoted;
|
|
181435
|
+
current2 += char;
|
|
181436
|
+
continue;
|
|
181437
|
+
}
|
|
181438
|
+
if (!quoted && char === ":" && path10[index2 + 1] === ":") {
|
|
181439
|
+
segments.push(current2);
|
|
181440
|
+
current2 = "";
|
|
181441
|
+
index2++;
|
|
181442
|
+
continue;
|
|
181443
|
+
}
|
|
181444
|
+
if (!quoted && char === ".") {
|
|
181445
|
+
segments.push(current2);
|
|
181446
|
+
current2 = "";
|
|
181447
|
+
continue;
|
|
181448
|
+
}
|
|
181449
|
+
current2 += char;
|
|
181450
|
+
}
|
|
181451
|
+
segments.push(current2);
|
|
181452
|
+
return segments;
|
|
181453
|
+
}
|
|
181454
|
+
function simpleNameOf2(name) {
|
|
181455
|
+
return pathSegments(name).at(-1) ?? name;
|
|
181456
|
+
}
|
|
181457
|
+
var ELEMENT_SEPARATOR = "\0";
|
|
181458
|
+
function elementKey2(description) {
|
|
181459
|
+
return `${description.documentUri.toString()}${ELEMENT_SEPARATOR}${description.path}`;
|
|
181460
|
+
}
|
|
181461
|
+
function isDeclaredSpelling(description) {
|
|
181462
|
+
const kind = description.derivedKind;
|
|
181463
|
+
if (kind === "reexport" || kind === "inherited")
|
|
181464
|
+
return false;
|
|
181465
|
+
return pathSegments(description.name).length === 1;
|
|
181466
|
+
}
|
|
181467
|
+
var SysmlNameLookup = class {
|
|
181468
|
+
shared;
|
|
181469
|
+
byName;
|
|
181470
|
+
/** Element key → the declared spellings the index holds for that element. */
|
|
181471
|
+
spellings;
|
|
181472
|
+
constructor(shared) {
|
|
181473
|
+
this.shared = shared;
|
|
181474
|
+
this.shared.workspace.DocumentBuilder.onBuildPhase(DocumentState.IndexedContent, () => {
|
|
181475
|
+
this.byName = void 0;
|
|
181476
|
+
this.spellings = void 0;
|
|
181477
|
+
});
|
|
181478
|
+
}
|
|
181479
|
+
/** Every description indexed under `name`, in either spelling of an escaped name. */
|
|
181480
|
+
descriptions(name) {
|
|
181481
|
+
return this.index().get(name) ?? [];
|
|
181482
|
+
}
|
|
181483
|
+
/**
|
|
181484
|
+
* The ONE element `name` names, or `undefined` when the answer is not
|
|
181485
|
+
* certain: no element, or more than one. `accept` narrows the candidates
|
|
181486
|
+
* before ambiguity is judged, so "the only CALLABLE called `f`" is a
|
|
181487
|
+
* decidable question even where a part shares the name.
|
|
181488
|
+
*/
|
|
181489
|
+
unique(name, accept) {
|
|
181490
|
+
const candidates = this.descriptions(name).filter((candidate) => !accept || accept(candidate));
|
|
181491
|
+
let found;
|
|
181492
|
+
let key;
|
|
181493
|
+
for (const candidate of candidates) {
|
|
181494
|
+
const candidateKey = elementKey2(candidate);
|
|
181495
|
+
if (found === void 0) {
|
|
181496
|
+
found = candidate;
|
|
181497
|
+
key = candidateKey;
|
|
181498
|
+
continue;
|
|
181499
|
+
}
|
|
181500
|
+
if (candidateKey !== key)
|
|
181501
|
+
return void 0;
|
|
181502
|
+
}
|
|
181503
|
+
return found;
|
|
181504
|
+
}
|
|
181505
|
+
/**
|
|
181506
|
+
* Resolve a written path: the spelling the index holds verbatim first, then
|
|
181507
|
+
* its final segment. Both readings must name exactly one element.
|
|
181508
|
+
*/
|
|
181509
|
+
uniqueForPath(path10, accept) {
|
|
181510
|
+
return this.unique(path10, accept) ?? this.unique(simpleNameOf2(path10), accept);
|
|
181511
|
+
}
|
|
181512
|
+
/**
|
|
181513
|
+
* The declared spellings of the element `description` names — its regular
|
|
181514
|
+
* name and its `<short>` name — minus `written`.
|
|
181515
|
+
*/
|
|
181516
|
+
otherNames(description, written) {
|
|
181517
|
+
const all = this.spellingIndex().get(elementKey2(description)) ?? [];
|
|
181518
|
+
const seen = unquoteName3(written);
|
|
181519
|
+
return all.filter((name) => unquoteName3(name) !== seen);
|
|
181520
|
+
}
|
|
181521
|
+
index() {
|
|
181522
|
+
if (!this.byName)
|
|
181523
|
+
this.build();
|
|
181524
|
+
return this.byName;
|
|
181525
|
+
}
|
|
181526
|
+
spellingIndex() {
|
|
181527
|
+
if (!this.spellings)
|
|
181528
|
+
this.build();
|
|
181529
|
+
return this.spellings;
|
|
181530
|
+
}
|
|
181531
|
+
/** One pass over the index feeds both maps; neither is worth a second. */
|
|
181532
|
+
build() {
|
|
181533
|
+
const byName = /* @__PURE__ */ new Map();
|
|
181534
|
+
const spellings = /* @__PURE__ */ new Map();
|
|
181535
|
+
const add = (key, description) => {
|
|
181536
|
+
const bucket = byName.get(key);
|
|
181537
|
+
if (bucket)
|
|
181538
|
+
bucket.push(description);
|
|
181539
|
+
else
|
|
181540
|
+
byName.set(key, [description]);
|
|
181541
|
+
};
|
|
181542
|
+
for (const description of this.shared.workspace.IndexManager.allElements()) {
|
|
181543
|
+
add(description.name, description);
|
|
181544
|
+
const unquoted = unquoteName3(description.name);
|
|
181545
|
+
if (unquoted !== description.name)
|
|
181546
|
+
add(unquoted, description);
|
|
181547
|
+
if (!isDeclaredSpelling(description))
|
|
181548
|
+
continue;
|
|
181549
|
+
const key = elementKey2(description);
|
|
181550
|
+
const names = spellings.get(key);
|
|
181551
|
+
if (names) {
|
|
181552
|
+
if (!names.includes(description.name))
|
|
181553
|
+
names.push(description.name);
|
|
181554
|
+
} else {
|
|
181555
|
+
spellings.set(key, [description.name]);
|
|
181556
|
+
}
|
|
181557
|
+
}
|
|
181558
|
+
this.byName = byName;
|
|
181559
|
+
this.spellings = spellings;
|
|
181560
|
+
}
|
|
181561
|
+
};
|
|
181562
|
+
var lookups = /* @__PURE__ */ new WeakMap();
|
|
181563
|
+
function nameLookupFor(shared) {
|
|
181564
|
+
if (!shared)
|
|
181565
|
+
return void 0;
|
|
181566
|
+
const existing = lookups.get(shared);
|
|
181567
|
+
if (existing)
|
|
181568
|
+
return existing;
|
|
181569
|
+
const created = new SysmlNameLookup(shared);
|
|
181570
|
+
lookups.set(shared, created);
|
|
181571
|
+
return created;
|
|
181572
|
+
}
|
|
181573
|
+
|
|
181574
|
+
// ../language-server/out/src/services/callable-resolver.js
|
|
181575
|
+
var CALLABLE_TYPES = /* @__PURE__ */ new Set([
|
|
181576
|
+
"CalcDecl",
|
|
181577
|
+
"ActionDecl",
|
|
181578
|
+
"ConstraintDecl",
|
|
181579
|
+
"FunctionDecl",
|
|
181580
|
+
"PredicateDecl",
|
|
181581
|
+
"BehaviorDecl",
|
|
181582
|
+
"InteractionDecl"
|
|
181583
|
+
]);
|
|
181584
|
+
var CallableResolver = class {
|
|
181585
|
+
services;
|
|
181586
|
+
lookup;
|
|
181587
|
+
linker;
|
|
181588
|
+
constructor(services) {
|
|
181589
|
+
this.services = services;
|
|
181590
|
+
this.lookup = nameLookupFor(services?.shared);
|
|
181591
|
+
this.linker = services?.references.Linker;
|
|
181592
|
+
}
|
|
181593
|
+
/**
|
|
181594
|
+
* Every indexed callable that answers to `name`, so a caller can decide what
|
|
181595
|
+
* ambiguity costs it. Signature help is transient and follows the cursor, so
|
|
181596
|
+
* it takes the first; an inlay hint is a permanent annotation, so it takes a
|
|
181597
|
+
* candidate only when it is the ONLY element with that name.
|
|
181598
|
+
*/
|
|
181599
|
+
candidates(name) {
|
|
181600
|
+
const simple = simpleNameOf2(name);
|
|
181601
|
+
return (this.lookup?.descriptions(simple) ?? []).filter((description) => CALLABLE_TYPES.has(description.type));
|
|
181602
|
+
}
|
|
181603
|
+
/**
|
|
181604
|
+
* The one callable `name` unambiguously names in the index, if any: the
|
|
181605
|
+
* written spelling first, then its final segment, and either reading must
|
|
181606
|
+
* name exactly one element.
|
|
181607
|
+
*/
|
|
181608
|
+
uniqueCandidate(name) {
|
|
181609
|
+
return this.lookup?.uniqueForPath(name, (description) => CALLABLE_TYPES.has(description.type));
|
|
181610
|
+
}
|
|
181611
|
+
/** The callable declaration `name` invokes in `document`, resolved locally. */
|
|
181612
|
+
findLocal(document2, name) {
|
|
181613
|
+
const root4 = document2.parseResult?.value;
|
|
181614
|
+
if (!root4)
|
|
181615
|
+
return void 0;
|
|
181616
|
+
return collectCallables([root4, ...ast_utils_exports.streamAllContents(root4).toArray()]).get(unquoteName3(simpleNameOf2(name)));
|
|
181617
|
+
}
|
|
181618
|
+
/**
|
|
181619
|
+
* SYNCHRONOUS resolution: a qualified spelling the index holds verbatim,
|
|
181620
|
+
* then the document's own tree, then an unambiguous indexed callable —
|
|
181621
|
+
* resolved through the linker's off-to-the-side library parse. Nothing here
|
|
181622
|
+
* grows `LangiumDocuments`, and nothing here awaits, so it is safe on a
|
|
181623
|
+
* request VS Code re-issues on every scroll.
|
|
181624
|
+
*/
|
|
181625
|
+
resolve(document2, name, local) {
|
|
181626
|
+
if (name.includes("::") || name.includes(".")) {
|
|
181627
|
+
const exact = this.lookup?.unique(name, (description) => CALLABLE_TYPES.has(description.type));
|
|
181628
|
+
const node = exact ? this.nodeOf(exact) : void 0;
|
|
181629
|
+
if (node)
|
|
181630
|
+
return node;
|
|
181631
|
+
}
|
|
181632
|
+
const found = local ? local(unquoteName3(simpleNameOf2(name))) : this.findLocal(document2, name);
|
|
181633
|
+
if (found)
|
|
181634
|
+
return found;
|
|
181635
|
+
const candidate = this.uniqueCandidate(name);
|
|
181636
|
+
return candidate ? this.nodeOf(candidate) : void 0;
|
|
181637
|
+
}
|
|
181638
|
+
/** An indexed description as a node, through the linker's lazy library parse. */
|
|
181639
|
+
nodeOf(description) {
|
|
181640
|
+
return this.linker?.resolveIndexedNode?.(description) ?? description.node;
|
|
181641
|
+
}
|
|
181642
|
+
/**
|
|
181643
|
+
* Resolution that may load a workspace document. Signature help uses it: it
|
|
181644
|
+
* runs on an explicit editor gesture, not on every scroll, and a callable in
|
|
181645
|
+
* a workspace file the user has not opened yet still deserves a signature.
|
|
181646
|
+
*/
|
|
181647
|
+
// REQ-263 — Signature help on `(` / `,` / `->`
|
|
181648
|
+
async resolveAsync(document2, name) {
|
|
181649
|
+
const direct = this.resolve(document2, name);
|
|
181650
|
+
if (direct)
|
|
181651
|
+
return direct;
|
|
181652
|
+
const candidate = this.candidates(name).at(0);
|
|
181653
|
+
if (!candidate)
|
|
181654
|
+
return void 0;
|
|
181655
|
+
if (candidate.node)
|
|
181656
|
+
return candidate.node;
|
|
181657
|
+
const documents = this.services?.shared.workspace.LangiumDocuments;
|
|
181658
|
+
const locator = this.services?.workspace.AstNodeLocator;
|
|
181659
|
+
if (!documents || !locator)
|
|
181660
|
+
return void 0;
|
|
181661
|
+
const doc = documents.getDocument(candidate.documentUri) ?? await documents.getOrCreateDocument(candidate.documentUri);
|
|
181662
|
+
const root4 = doc?.parseResult?.value;
|
|
181663
|
+
return root4 ? locator.getAstNode(root4, candidate.path) : void 0;
|
|
181664
|
+
}
|
|
181665
|
+
/** {@link callableParameters} — the parameters, in written order. */
|
|
181666
|
+
parameters(node) {
|
|
181667
|
+
return callableParameters(node);
|
|
181668
|
+
}
|
|
181669
|
+
/**
|
|
181670
|
+
* The parameters a positional argument list binds to: the INPUTS, in written
|
|
181671
|
+
* order. An `out` parameter and the result are not written at the call site
|
|
181672
|
+
* (OMG KerML v1.0 binds an `InvocationExpression`'s arguments to the
|
|
181673
|
+
* invoked type's input features).
|
|
181674
|
+
*/
|
|
181675
|
+
inputParameters(node) {
|
|
181676
|
+
return this.parameters(node).filter((parameter) => !parameter.isReturn && parameter.direction !== "out");
|
|
181677
|
+
}
|
|
181678
|
+
};
|
|
181679
|
+
function callableParameters(node) {
|
|
181680
|
+
const directed = new Map(directedParameters(node).map((entry) => [entry.node, entry.direction]));
|
|
181681
|
+
const result = [];
|
|
181682
|
+
for (const member of membersOf2(node)) {
|
|
181683
|
+
const direction = directed.get(member);
|
|
181684
|
+
const isReturn = member.$type === "ReturnDecl";
|
|
181685
|
+
if (!direction && !isReturn)
|
|
181686
|
+
continue;
|
|
181687
|
+
const name = nodeName2(member);
|
|
181688
|
+
if (!name && !direction)
|
|
181689
|
+
continue;
|
|
181690
|
+
result.push({
|
|
181691
|
+
node: member,
|
|
181692
|
+
direction: direction ?? "return",
|
|
181693
|
+
name,
|
|
181694
|
+
type: typingText(member),
|
|
181695
|
+
multiplicity: multiplicityText2(member),
|
|
181696
|
+
isReturn
|
|
181697
|
+
});
|
|
181698
|
+
}
|
|
181699
|
+
return result;
|
|
181700
|
+
}
|
|
181701
|
+
function collectCallables(nodes) {
|
|
181702
|
+
const callables = /* @__PURE__ */ new Map();
|
|
181703
|
+
const byDefinition = /* @__PURE__ */ new Set();
|
|
181704
|
+
for (const node of nodes) {
|
|
181705
|
+
if (!CALLABLE_TYPES.has(node.$type) && callableParameters(node).length === 0)
|
|
181706
|
+
continue;
|
|
181707
|
+
const isDefinition = node.isDef === true;
|
|
181708
|
+
for (const name of [nodeName2(node), shortNameOf2(node)]) {
|
|
181709
|
+
if (!name)
|
|
181710
|
+
continue;
|
|
181711
|
+
if (callables.has(name) && !(isDefinition && !byDefinition.has(name)))
|
|
181712
|
+
continue;
|
|
181713
|
+
callables.set(name, node);
|
|
181714
|
+
if (isDefinition)
|
|
181715
|
+
byDefinition.add(name);
|
|
181716
|
+
}
|
|
181717
|
+
}
|
|
181718
|
+
return callables;
|
|
181719
|
+
}
|
|
181720
|
+
function membersOf2(node) {
|
|
181721
|
+
const members = node?.members;
|
|
181722
|
+
return Array.isArray(members) ? members.filter(isAstNode3) : [];
|
|
181723
|
+
}
|
|
181724
|
+
function isAstNode3(value) {
|
|
181725
|
+
return typeof value === "object" && value !== null && typeof value.$type === "string";
|
|
181726
|
+
}
|
|
181727
|
+
function nodeName2(node) {
|
|
181728
|
+
const value = node?.name;
|
|
181729
|
+
return typeof value === "string" && value.length > 0 ? unquoteName3(value) : void 0;
|
|
181730
|
+
}
|
|
181731
|
+
function shortNameOf2(node) {
|
|
181732
|
+
const value = node?.shortName?.name;
|
|
181733
|
+
return typeof value === "string" && value.length > 0 ? unquoteName3(value) : void 0;
|
|
181734
|
+
}
|
|
181735
|
+
function typingText(node) {
|
|
181736
|
+
const text = node?.typing?.type?.$refText;
|
|
181737
|
+
return typeof text === "string" && text.length > 0 ? text : void 0;
|
|
181738
|
+
}
|
|
181739
|
+
function multiplicityText2(node) {
|
|
181740
|
+
const text = node?.multiplicity?.$cstNode?.text;
|
|
181741
|
+
return typeof text === "string" && text.length > 0 ? text.trim() : void 0;
|
|
181742
|
+
}
|
|
181743
|
+
|
|
181744
|
+
// ../language-server/out/src/services/inlay-hint-provider.js
|
|
181122
181745
|
function multiplicityAnchor(node) {
|
|
181123
181746
|
const leaves = cst_utils_exports.flattenCst(node).toArray();
|
|
181124
181747
|
const bodyStart = leaves.find((leaf) => leaf.text === "{");
|
|
@@ -181177,6 +181800,50 @@ var EXPLICIT_SPECIALIZATION_KINDS = /* @__PURE__ */ new Set([
|
|
|
181177
181800
|
"conjugates"
|
|
181178
181801
|
]);
|
|
181179
181802
|
var REDEFINITION_KINDS2 = /* @__PURE__ */ new Set([":>>", "redefines"]);
|
|
181803
|
+
var CONSTANT_CARRYING_KINDS = /* @__PURE__ */ new Set([
|
|
181804
|
+
":>",
|
|
181805
|
+
"subsets",
|
|
181806
|
+
":>>",
|
|
181807
|
+
"redefines",
|
|
181808
|
+
"::>",
|
|
181809
|
+
"references",
|
|
181810
|
+
"=>",
|
|
181811
|
+
"crosses"
|
|
181812
|
+
]);
|
|
181813
|
+
var CONSTANT_MODIFIERS = /* @__PURE__ */ new Set(["constant", "const"]);
|
|
181814
|
+
function constantKeyword(languageId) {
|
|
181815
|
+
return languageId === "kerml" ? "const" : "constant";
|
|
181816
|
+
}
|
|
181817
|
+
var PREFIXES_BEFORE_CONSTANT = /* @__PURE__ */ new Set([
|
|
181818
|
+
"public",
|
|
181819
|
+
"private",
|
|
181820
|
+
"protected",
|
|
181821
|
+
"in",
|
|
181822
|
+
"out",
|
|
181823
|
+
"inout",
|
|
181824
|
+
"abstract",
|
|
181825
|
+
"variation",
|
|
181826
|
+
"variant",
|
|
181827
|
+
"derived",
|
|
181828
|
+
"readonly",
|
|
181829
|
+
"composite",
|
|
181830
|
+
"portion",
|
|
181831
|
+
"ordered",
|
|
181832
|
+
"nonunique",
|
|
181833
|
+
"parallel"
|
|
181834
|
+
]);
|
|
181835
|
+
var PORTION_MODIFIERS = /* @__PURE__ */ new Set(["portion", "snapshot", "timeslice"]);
|
|
181836
|
+
var ACTION_KIND_USAGES = /* @__PURE__ */ new Set([
|
|
181837
|
+
"ActionDecl",
|
|
181838
|
+
"StateDecl",
|
|
181839
|
+
"CalcDecl",
|
|
181840
|
+
"CaseDecl",
|
|
181841
|
+
"UseCaseDecl",
|
|
181842
|
+
"AnalysisCaseDecl",
|
|
181843
|
+
"VerificationCaseDecl"
|
|
181844
|
+
]);
|
|
181845
|
+
var KERML_FEATURE_DECLS = /* @__PURE__ */ new Set(["FeatureDecl", "StepDecl", "ExpressionDecl"]);
|
|
181846
|
+
var REFERENCE_MODIFIERS = /* @__PURE__ */ new Set(["ref", "in", "out", "inout"]);
|
|
181180
181847
|
var IMPLICIT_BASES = Object.freeze({
|
|
181181
181848
|
PartDecl: { def: "Parts::Part", usage: "Parts::parts" },
|
|
181182
181849
|
ItemDecl: { def: "Items::Item", usage: "Items::items" },
|
|
@@ -181201,6 +181868,37 @@ var IMPLICIT_BASES = Object.freeze({
|
|
|
181201
181868
|
OccurrenceDecl: { def: "Occurrences::Occurrence", usage: "Occurrences::occurrences" },
|
|
181202
181869
|
MetadataDecl: { def: "Metadata::MetadataItem", usage: "Metadata::metadataItems" }
|
|
181203
181870
|
});
|
|
181871
|
+
var OCCURRENCE_KIND_OWNERS = /* @__PURE__ */ new Set([
|
|
181872
|
+
...Object.keys(IMPLICIT_BASES).filter((kind) => kind !== "AttributeDecl"),
|
|
181873
|
+
// KerML fixes a library base per classifier kind too, in the same way and in
|
|
181874
|
+
// the same normative place: `Class` specializes `Occurrences::Occurrence`,
|
|
181875
|
+
// `Structure` specializes `Objects::Object`, `Metaclass` specializes
|
|
181876
|
+
// `Metaobjects::Metaobject`, `Behavior` specializes
|
|
181877
|
+
// `Performances::Performance`, `Function` and `Interaction` are Behaviors,
|
|
181878
|
+
// `Predicate` is a Function, `Step` specializes `Performances::performances`
|
|
181879
|
+
// and `Expression` is a Step. All of them reach `Occurrence`.
|
|
181880
|
+
"ClassDecl",
|
|
181881
|
+
"StructDecl",
|
|
181882
|
+
"MetaclassDecl",
|
|
181883
|
+
"BehaviorDecl",
|
|
181884
|
+
"InteractionDecl",
|
|
181885
|
+
"FunctionDecl",
|
|
181886
|
+
"PredicateDecl",
|
|
181887
|
+
"StepDecl",
|
|
181888
|
+
"ExpressionDecl"
|
|
181889
|
+
// Left out because their base is NOT an occurrence: `DatatypeDecl`
|
|
181890
|
+
// (`Base::DataValue`, declared disjoint from `Occurrence`) and plain
|
|
181891
|
+
// `AssociationDecl` (`Links::Link`, which specializes `Base::Anything`) —
|
|
181892
|
+
// `assoc struct` is handled separately, since it is a `LinkObject`.
|
|
181893
|
+
// Left out because their base is WRITTEN rather than fixed by the kind:
|
|
181894
|
+
// `TypeDecl`, `ClassifierDecl`, `FeatureDecl`.
|
|
181895
|
+
]);
|
|
181896
|
+
function isOccurrenceKindOwner(owner) {
|
|
181897
|
+
if (owner.$type === "AssociationDecl")
|
|
181898
|
+
return owner.isStruct === true;
|
|
181899
|
+
return OCCURRENCE_KIND_OWNERS.has(owner.$type);
|
|
181900
|
+
}
|
|
181901
|
+
var NON_VARYING_LIBRARY_TYPES = /* @__PURE__ */ new Set(["SelfLink", "HappensLink"]);
|
|
181204
181902
|
function markdown(value) {
|
|
181205
181903
|
return { kind: import_vscode_languageserver20.MarkupKind.Markdown, value };
|
|
181206
181904
|
}
|
|
@@ -181222,19 +181920,130 @@ function descriptionRange(description) {
|
|
|
181222
181920
|
const segment = description.nameSegment ?? description.selectionSegment;
|
|
181223
181921
|
return segment?.range ?? { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } };
|
|
181224
181922
|
}
|
|
181923
|
+
function descriptionLocation(description) {
|
|
181924
|
+
return { uri: description.documentUri.toString(), range: descriptionRange(description) };
|
|
181925
|
+
}
|
|
181926
|
+
function nodeLocation(node) {
|
|
181927
|
+
const range = node.$cstNode?.range;
|
|
181928
|
+
if (!range)
|
|
181929
|
+
return void 0;
|
|
181930
|
+
return { uri: ast_utils_exports.getDocument(node).uri.toString(), range };
|
|
181931
|
+
}
|
|
181932
|
+
function specializesNonVaryingLibraryType(node) {
|
|
181933
|
+
const typing = node.typing?.type?.$refText;
|
|
181934
|
+
if (typing && NON_VARYING_LIBRARY_TYPES.has(lastSegment3(typing)))
|
|
181935
|
+
return true;
|
|
181936
|
+
return allRelationships2(node).flatMap((rel2) => rel2.targets ?? []).some((target) => NON_VARYING_LIBRARY_TYPES.has(lastSegment3(target)));
|
|
181937
|
+
}
|
|
181938
|
+
function constantAnchor(node) {
|
|
181939
|
+
const cst = node.$cstNode;
|
|
181940
|
+
if (!cst)
|
|
181941
|
+
return void 0;
|
|
181942
|
+
for (const leaf of cst_utils_exports.flattenCst(cst)) {
|
|
181943
|
+
if (leaf.hidden)
|
|
181944
|
+
continue;
|
|
181945
|
+
if (PREFIXES_BEFORE_CONSTANT.has(leaf.text))
|
|
181946
|
+
continue;
|
|
181947
|
+
return /^[a-z]+$/u.test(leaf.text) ? leaf : void 0;
|
|
181948
|
+
}
|
|
181949
|
+
return void 0;
|
|
181950
|
+
}
|
|
181951
|
+
function membershipImportPath(node) {
|
|
181952
|
+
if (isImport(node) && node.alias)
|
|
181953
|
+
return void 0;
|
|
181954
|
+
if (isExposePath(node) && node.dotSegs.length > 0)
|
|
181955
|
+
return void 0;
|
|
181956
|
+
if (node.segs.some((seg) => seg.star || seg.recursive || !seg.name))
|
|
181957
|
+
return void 0;
|
|
181958
|
+
const last2 = node.segs.at(-1);
|
|
181959
|
+
const written = last2?.name ?? node.head;
|
|
181960
|
+
const anchor = last2 ? grammar_utils_exports.findNodeForProperty(last2.$cstNode, "name") : grammar_utils_exports.findNodeForProperty(node.$cstNode, "head");
|
|
181961
|
+
if (!anchor)
|
|
181962
|
+
return void 0;
|
|
181963
|
+
return { path: [node.head, ...node.segs.map((seg) => seg.name)].join("::"), written, anchor };
|
|
181964
|
+
}
|
|
181965
|
+
function publicFeatures(type) {
|
|
181966
|
+
const members = type.members;
|
|
181967
|
+
if (!Array.isArray(members))
|
|
181968
|
+
return [];
|
|
181969
|
+
return members.filter((member) => {
|
|
181970
|
+
if (typeof member?.$type !== "string")
|
|
181971
|
+
return false;
|
|
181972
|
+
const decl = member;
|
|
181973
|
+
if (decl.isDef !== false && decl.$type !== "FeatureDecl")
|
|
181974
|
+
return false;
|
|
181975
|
+
return decl.visibility === void 0 || decl.visibility === "public";
|
|
181976
|
+
});
|
|
181977
|
+
}
|
|
181978
|
+
function calleeName(node) {
|
|
181979
|
+
if (node.call) {
|
|
181980
|
+
if (isPathExpr(node.target))
|
|
181981
|
+
return node.target.path;
|
|
181982
|
+
const target = node.target;
|
|
181983
|
+
if (isPostfixOp(target) && target.dot && target.field)
|
|
181984
|
+
return target.field;
|
|
181985
|
+
return void 0;
|
|
181986
|
+
}
|
|
181987
|
+
if (node.arrow && node.invoke)
|
|
181988
|
+
return node.invoke;
|
|
181989
|
+
return void 0;
|
|
181990
|
+
}
|
|
181991
|
+
function callArguments(node) {
|
|
181992
|
+
if (node.call)
|
|
181993
|
+
return { args: node.callArgs, firstParameter: 0 };
|
|
181994
|
+
if (node.arrow && node.invoke)
|
|
181995
|
+
return { args: node.args, firstParameter: 1 };
|
|
181996
|
+
return void 0;
|
|
181997
|
+
}
|
|
181225
181998
|
var SysmlInlayHintProvider = class {
|
|
181226
181999
|
services;
|
|
181227
182000
|
/**
|
|
181228
182001
|
* Resolved implicit bases, keyed by the qualified name in
|
|
181229
|
-
* {@link IMPLICIT_BASES}.
|
|
181230
|
-
*
|
|
181231
|
-
*
|
|
181232
|
-
*
|
|
181233
|
-
*
|
|
182002
|
+
* {@link IMPLICIT_BASES}. A base the index does not hold is NOT cached — the
|
|
182003
|
+
* library may still be loading — and issue #240 made that miss cheap: two
|
|
182004
|
+
* lookups in the shared name index rather than the full index scan it used
|
|
182005
|
+
* to be, on a request VS Code re-issues on every scroll. A HIT is cached
|
|
182006
|
+
* until the index is rebuilt, so the description a label links to always
|
|
182007
|
+
* carries the ranges of the generation it was read from.
|
|
181234
182008
|
*/
|
|
181235
182009
|
baseCache = /* @__PURE__ */ new Map();
|
|
182010
|
+
/**
|
|
182011
|
+
* REQ-395 — issue #240: the shared name lookup, built once per index
|
|
182012
|
+
* generation. Every category that resolves a WRITTEN name goes through it,
|
|
182013
|
+
* so no request puts an index scan on the hint path.
|
|
182014
|
+
*/
|
|
182015
|
+
lookup;
|
|
182016
|
+
/** REQ-395 — issue #240: the callee resolution signature help also uses. */
|
|
182017
|
+
callables;
|
|
182018
|
+
/** REQ-395 — issue #240: the linker's lazy standard-library parse. */
|
|
182019
|
+
linker;
|
|
182020
|
+
/**
|
|
182021
|
+
* REQ-395 — issue #240: "does this element declare `constant`?", memoized by
|
|
182022
|
+
* element identity, because answering it may cost one lazily parsed library
|
|
182023
|
+
* file. Editing away the `constant` on the SUBSETTED feature changes the
|
|
182024
|
+
* answer without changing the key, so this is dropped whenever the index is
|
|
182025
|
+
* rebuilt, exactly like the shared name lookup.
|
|
182026
|
+
*/
|
|
182027
|
+
constantCache = /* @__PURE__ */ new Map();
|
|
182028
|
+
/**
|
|
182029
|
+
* REQ-395 — issue #240: an element's own written names, memoized by element
|
|
182030
|
+
* identity. Reading them tells a `<short>` name from a regular one, which is
|
|
182031
|
+
* what lets the imported-name hint print the notation the source would have
|
|
182032
|
+
* written. It costs at most one lazily parsed library file, only for an
|
|
182033
|
+
* element that actually has two names, and it is dropped with the rest when
|
|
182034
|
+
* the index is rebuilt.
|
|
182035
|
+
*/
|
|
182036
|
+
declaredNameCache = /* @__PURE__ */ new Map();
|
|
181236
182037
|
constructor(services) {
|
|
181237
182038
|
this.services = services;
|
|
182039
|
+
this.lookup = nameLookupFor(services?.shared);
|
|
182040
|
+
this.callables = new CallableResolver(services);
|
|
182041
|
+
this.linker = services?.references.Linker;
|
|
182042
|
+
services?.shared.workspace.DocumentBuilder.onBuildPhase(DocumentState.IndexedContent, () => {
|
|
182043
|
+
this.baseCache.clear();
|
|
182044
|
+
this.constantCache.clear();
|
|
182045
|
+
this.declaredNameCache.clear();
|
|
182046
|
+
});
|
|
181238
182047
|
}
|
|
181239
182048
|
getInlayHints(document2, _params) {
|
|
181240
182049
|
const root4 = document2.parseResult?.value;
|
|
@@ -181242,7 +182051,14 @@ var SysmlInlayHintProvider = class {
|
|
|
181242
182051
|
return void 0;
|
|
181243
182052
|
const settings = sysmlInlayHintSettings;
|
|
181244
182053
|
const hints = [];
|
|
181245
|
-
|
|
182054
|
+
const nodes = allAstNodes(root4);
|
|
182055
|
+
let localCallables;
|
|
182056
|
+
const localCallable = (simple) => {
|
|
182057
|
+
localCallables ??= collectCallables(nodes);
|
|
182058
|
+
return localCallables.get(simple);
|
|
182059
|
+
};
|
|
182060
|
+
const callees = /* @__PURE__ */ new Map();
|
|
182061
|
+
for (const node of nodes) {
|
|
181246
182062
|
const decl = node;
|
|
181247
182063
|
if (settings.multiplicity && (isPartDecl(node) || isPortDecl(node) || isAttributeDecl(node)) && !decl.isDef && !decl.multiplicity && node.$cstNode && decl.name) {
|
|
181248
182064
|
hints.push({
|
|
@@ -181269,6 +182085,11 @@ var SysmlInlayHintProvider = class {
|
|
|
181269
182085
|
});
|
|
181270
182086
|
}
|
|
181271
182087
|
}
|
|
182088
|
+
if (settings.modifiers) {
|
|
182089
|
+
const constant2 = this.implicitConstantHint(decl);
|
|
182090
|
+
if (constant2)
|
|
182091
|
+
hints.push(constant2);
|
|
182092
|
+
}
|
|
181272
182093
|
if (settings.modifiers && isAttributeDecl(node) && !decl.isDef && !(decl.modifiers ?? []).includes("ref")) {
|
|
181273
182094
|
const keyword = keywordLeaf(node, "attribute");
|
|
181274
182095
|
if (keyword) {
|
|
@@ -181310,6 +182131,17 @@ var SysmlInlayHintProvider = class {
|
|
|
181310
182131
|
if (effective)
|
|
181311
182132
|
hints.push(effective);
|
|
181312
182133
|
}
|
|
182134
|
+
if (settings.importedNames && (isImport(node) || isExposePath(node))) {
|
|
182135
|
+
const imported = this.importedNameHint(node);
|
|
182136
|
+
if (imported)
|
|
182137
|
+
hints.push(imported);
|
|
182138
|
+
}
|
|
182139
|
+
if (settings.parameterNames && isPostfixOp(node)) {
|
|
182140
|
+
hints.push(...this.argumentNameHints(node, document2, callees, localCallable));
|
|
182141
|
+
}
|
|
182142
|
+
if (settings.parameterNames && isNewExpr(node)) {
|
|
182143
|
+
hints.push(...this.constructorArgumentHints(node));
|
|
182144
|
+
}
|
|
181313
182145
|
if (!settings.dimension)
|
|
181314
182146
|
continue;
|
|
181315
182147
|
if (isNumericPrimary(node)) {
|
|
@@ -181379,6 +182211,228 @@ var SysmlInlayHintProvider = class {
|
|
|
181379
182211
|
}
|
|
181380
182212
|
return hints;
|
|
181381
182213
|
}
|
|
182214
|
+
/**
|
|
182215
|
+
* REQ-395 — issue #240: the other name a membership `import` brings in.
|
|
182216
|
+
*
|
|
182217
|
+
* An element may declare both a regular name and a `<short>` name, and an
|
|
182218
|
+
* import brings in BOTH — the one the path does not write is invisible in
|
|
182219
|
+
* the source, which is exactly what the hint is for. The written path is a
|
|
182220
|
+
* datatype string, not a cross-reference, so the element is found through
|
|
182221
|
+
* the shared name lookup: the spelling the index holds verbatim first, then
|
|
182222
|
+
* the final segment, and either reading must name exactly ONE element. A
|
|
182223
|
+
* name two packages both declare yields nothing rather than whichever the
|
|
182224
|
+
* index lists first.
|
|
182225
|
+
*/
|
|
182226
|
+
importedNameHint(node) {
|
|
182227
|
+
const written = membershipImportPath(node);
|
|
182228
|
+
if (!written || !this.lookup)
|
|
182229
|
+
return void 0;
|
|
182230
|
+
const description = this.lookup.uniqueForPath(written.path);
|
|
182231
|
+
if (!description)
|
|
182232
|
+
return void 0;
|
|
182233
|
+
const others = this.lookup.otherNames(description, written.written);
|
|
182234
|
+
if (others.length === 0)
|
|
182235
|
+
return void 0;
|
|
182236
|
+
const declared = this.declaredNames(description);
|
|
182237
|
+
const shown = others.map((name) => declared?.shortName === name ? `<${name}>` : name);
|
|
182238
|
+
const kind = isImport(node) ? "import" : "expose";
|
|
182239
|
+
return {
|
|
182240
|
+
position: written.anchor.range.end,
|
|
182241
|
+
label: [{
|
|
182242
|
+
value: ` also ${shown.join(", ")}`,
|
|
182243
|
+
location: descriptionLocation(description)
|
|
182244
|
+
}],
|
|
182245
|
+
kind: import_vscode_languageserver20.InlayHintKind.Parameter,
|
|
182246
|
+
paddingLeft: true,
|
|
182247
|
+
tooltip: markdown(`This \`${kind}\` also brings \`${shown.join("`, `")}\` into scope: an element is addressable by its regular name and by its short name, and a membership import carries both.`)
|
|
182248
|
+
};
|
|
182249
|
+
}
|
|
182250
|
+
/**
|
|
182251
|
+
* REQ-395 — issue #240: the names an indexed element declares for itself.
|
|
182252
|
+
*
|
|
182253
|
+
* The index records the spellings but not which of them is the `<short>`
|
|
182254
|
+
* one, so the declaration is resolved through the linker's off-to-the-side
|
|
182255
|
+
* library parse — the budget REQ-251 sets, spent only for an element that
|
|
182256
|
+
* has more than one name, and memoized until the index is rebuilt.
|
|
182257
|
+
*/
|
|
182258
|
+
declaredNames(description) {
|
|
182259
|
+
const key = elementKey2(description);
|
|
182260
|
+
const cached = this.declaredNameCache.get(key);
|
|
182261
|
+
if (cached)
|
|
182262
|
+
return cached;
|
|
182263
|
+
const node = this.linker?.resolveIndexedNode?.(description) ?? description.node;
|
|
182264
|
+
if (!node)
|
|
182265
|
+
return void 0;
|
|
182266
|
+
const decl = node;
|
|
182267
|
+
const names = { name: decl.name, shortName: decl.shortName?.name };
|
|
182268
|
+
this.declaredNameCache.set(key, names);
|
|
182269
|
+
return names;
|
|
182270
|
+
}
|
|
182271
|
+
/**
|
|
182272
|
+
* REQ-395 — issue #240: the feature each `new Type(…)` argument binds to.
|
|
182273
|
+
*
|
|
182274
|
+
* A `ConstructorExpression` binds its arguments to the PUBLIC features of
|
|
182275
|
+
* the instantiated type, in order (OMG KerML v1.0, `ConstructorExpression`)
|
|
182276
|
+
* — not to input parameters, which is what an `InvocationExpression` binds.
|
|
182277
|
+
* The instantiated type IS a cross-reference here, so there is nothing to
|
|
182278
|
+
* resolve by name: an unresolved one simply yields no hints.
|
|
182279
|
+
*/
|
|
182280
|
+
constructorArgumentHints(node) {
|
|
182281
|
+
if (node.args.length === 0)
|
|
182282
|
+
return [];
|
|
182283
|
+
if (node.args.every((argument) => argument.name !== void 0))
|
|
182284
|
+
return [];
|
|
182285
|
+
const instantiated = node.type?.ref;
|
|
182286
|
+
if (!instantiated)
|
|
182287
|
+
return [];
|
|
182288
|
+
const features = publicFeatures(instantiated);
|
|
182289
|
+
if (features.length === 0)
|
|
182290
|
+
return [];
|
|
182291
|
+
const hints = [];
|
|
182292
|
+
for (let index2 = 0; index2 < node.args.length; index2++) {
|
|
182293
|
+
const argument = node.args[index2];
|
|
182294
|
+
if (argument.name || !argument.$cstNode)
|
|
182295
|
+
continue;
|
|
182296
|
+
const feature = features[index2];
|
|
182297
|
+
const name = feature?.name;
|
|
182298
|
+
if (!feature || !name)
|
|
182299
|
+
continue;
|
|
182300
|
+
const location = nodeLocation(feature);
|
|
182301
|
+
hints.push({
|
|
182302
|
+
position: argument.$cstNode.range.start,
|
|
182303
|
+
label: [{ value: `${name} =`, ...location ? { location } : {} }],
|
|
182304
|
+
kind: import_vscode_languageserver20.InlayHintKind.Parameter,
|
|
182305
|
+
paddingRight: true,
|
|
182306
|
+
tooltip: markdown(`Argument ${index2 + 1} binds to \`${name}\` of \`${node.type.$refText}\`.`)
|
|
182307
|
+
});
|
|
182308
|
+
}
|
|
182309
|
+
return hints;
|
|
182310
|
+
}
|
|
182311
|
+
/**
|
|
182312
|
+
* REQ-395 — issue #240: the parameter a POSITIONAL invocation argument binds
|
|
182313
|
+
* to.
|
|
182314
|
+
*
|
|
182315
|
+
* The callee of a call is an expression rather than a cross-reference, so
|
|
182316
|
+
* the name is resolved through the shared {@link CallableResolver} — the
|
|
182317
|
+
* same one signature help uses, which is why naming these arguments does not
|
|
182318
|
+
* add a second resolution path. An argument that writes its own name has
|
|
182319
|
+
* stated the correspondence, so it gets no hint.
|
|
182320
|
+
*/
|
|
182321
|
+
argumentNameHints(node, document2, callees, localCallable) {
|
|
182322
|
+
const call = callArguments(node);
|
|
182323
|
+
const callee = calleeName(node);
|
|
182324
|
+
if (!call || !callee || call.args.length === 0)
|
|
182325
|
+
return [];
|
|
182326
|
+
if (call.args.every((argument) => argument.argName !== void 0))
|
|
182327
|
+
return [];
|
|
182328
|
+
let callable = callees.get(callee);
|
|
182329
|
+
if (callable === void 0 && !callees.has(callee)) {
|
|
182330
|
+
callable = this.callables.resolve(document2, callee, localCallable);
|
|
182331
|
+
callees.set(callee, callable);
|
|
182332
|
+
}
|
|
182333
|
+
if (!callable)
|
|
182334
|
+
return [];
|
|
182335
|
+
const parameters = this.callables.inputParameters(callable);
|
|
182336
|
+
if (parameters.length === 0)
|
|
182337
|
+
return [];
|
|
182338
|
+
const hints = [];
|
|
182339
|
+
for (let index2 = 0; index2 < call.args.length; index2++) {
|
|
182340
|
+
const argument = call.args[index2];
|
|
182341
|
+
if (argument.argName || !argument.$cstNode)
|
|
182342
|
+
continue;
|
|
182343
|
+
const parameter = parameters[index2 + call.firstParameter];
|
|
182344
|
+
if (!parameter?.name)
|
|
182345
|
+
continue;
|
|
182346
|
+
const location = nodeLocation(parameter.node);
|
|
182347
|
+
hints.push({
|
|
182348
|
+
position: argument.$cstNode.range.start,
|
|
182349
|
+
label: [{ value: `${parameter.name} =`, ...location ? { location } : {} }],
|
|
182350
|
+
kind: import_vscode_languageserver20.InlayHintKind.Parameter,
|
|
182351
|
+
paddingRight: true,
|
|
182352
|
+
tooltip: markdown(`Argument ${index2 + 1} binds to \`${parameter.direction} ${parameter.name}\` of \`${callee}\`.`)
|
|
182353
|
+
});
|
|
182354
|
+
}
|
|
182355
|
+
return hints;
|
|
182356
|
+
}
|
|
182357
|
+
/**
|
|
182358
|
+
* REQ-395 — issue #240: implicit `constant`.
|
|
182359
|
+
*
|
|
182360
|
+
* OMG KerML v1.0 constrains `Subsetting`: `subsettedFeature.isConstant and
|
|
182361
|
+
* subsettingFeature.isVariable implies subsettingFeature.isConstant`. So a
|
|
182362
|
+
* usage that subsets or redefines a feature declared `constant` IS constant,
|
|
182363
|
+
* without writing it — provided it can vary at all, because `Feature` also
|
|
182364
|
+
* constrains `isConstant implies isVariable`.
|
|
182365
|
+
*
|
|
182366
|
+
* Whether it can vary is `Usage::mayTimeVary`, which OMG SysML v2 Part 1
|
|
182367
|
+
* derives as "owned by a type that specializes `Occurrences::Occurrence`,
|
|
182368
|
+
* and not a portion, a self/happens link, or a composite action". All four
|
|
182369
|
+
* are decided here from the declaration kinds and what the source writes
|
|
182370
|
+
* ({@link isOccurrenceKindOwner}, {@link PORTION_MODIFIERS},
|
|
182371
|
+
* {@link ACTION_KIND_USAGES} with {@link REFERENCE_MODIFIERS}, and
|
|
182372
|
+
* {@link specializesNonVaryingLibraryType}); an owner whose base is written
|
|
182373
|
+
* rather than fixed by its kind leaves the category quiet, as an
|
|
182374
|
+
* undecidable model must.
|
|
182375
|
+
*/
|
|
182376
|
+
implicitConstantHint(node) {
|
|
182377
|
+
const isFeature = node.isDef === false || KERML_FEATURE_DECLS.has(node.$type);
|
|
182378
|
+
if (!isFeature)
|
|
182379
|
+
return void 0;
|
|
182380
|
+
const modifiers2 = node.modifiers ?? [];
|
|
182381
|
+
if (modifiers2.some((modifier) => CONSTANT_MODIFIERS.has(modifier)))
|
|
182382
|
+
return void 0;
|
|
182383
|
+
if (modifiers2.some((modifier) => PORTION_MODIFIERS.has(modifier)))
|
|
182384
|
+
return void 0;
|
|
182385
|
+
if (ACTION_KIND_USAGES.has(node.$type) && !modifiers2.some((modifier) => REFERENCE_MODIFIERS.has(modifier)))
|
|
182386
|
+
return void 0;
|
|
182387
|
+
const owner = node.$container;
|
|
182388
|
+
if (!owner || !isOccurrenceKindOwner(owner))
|
|
182389
|
+
return void 0;
|
|
182390
|
+
if (specializesNonVaryingLibraryType(node))
|
|
182391
|
+
return void 0;
|
|
182392
|
+
const carrier = allRelationships2(node).filter((rel2) => rel2.kind && CONSTANT_CARRYING_KINDS.has(rel2.kind)).flatMap((rel2) => rel2.targets ?? []).find((target) => this.isConstantFeature(target));
|
|
182393
|
+
if (!carrier)
|
|
182394
|
+
return void 0;
|
|
182395
|
+
const anchor = constantAnchor(node);
|
|
182396
|
+
const at = anchor?.range.start ?? node.$cstNode?.range.start;
|
|
182397
|
+
if (!at)
|
|
182398
|
+
return void 0;
|
|
182399
|
+
const keyword = constantKeyword(this.services?.LanguageMetaData.languageId);
|
|
182400
|
+
return {
|
|
182401
|
+
position: at,
|
|
182402
|
+
label: keyword,
|
|
182403
|
+
kind: import_vscode_languageserver20.InlayHintKind.Type,
|
|
182404
|
+
paddingRight: true,
|
|
182405
|
+
tooltip: markdown(`Implicitly \`${keyword}\`: this feature subsets \`${lastSegment3(carrier)}\`, which is declared constant, and a subsetting feature that may vary takes the constancy of what it subsets.`),
|
|
182406
|
+
// Writing the modifier is mechanically safe — it is a leading
|
|
182407
|
+
// declaration prefix, and OMG puts it exactly here, before `ref`
|
|
182408
|
+
// and the kind keyword.
|
|
182409
|
+
...anchor ? { textEdits: [{ range: { start: at, end: at }, newText: `${keyword} ` }] } : {}
|
|
182410
|
+
};
|
|
182411
|
+
}
|
|
182412
|
+
/**
|
|
182413
|
+
* REQ-395 — issue #240: does the feature this path names declare `constant`?
|
|
182414
|
+
*
|
|
182415
|
+
* The path must name exactly one element, and that element is resolved
|
|
182416
|
+
* through the linker's off-to-the-side library parse — one lazily parsed
|
|
182417
|
+
* indexed target, the budget REQ-251 sets, and never a document added to the
|
|
182418
|
+
* workspace. The answer is memoized, so a scroll does not repeat it.
|
|
182419
|
+
*/
|
|
182420
|
+
isConstantFeature(target) {
|
|
182421
|
+
if (!this.lookup)
|
|
182422
|
+
return false;
|
|
182423
|
+
const description = this.lookup.uniqueForPath(target);
|
|
182424
|
+
if (!description)
|
|
182425
|
+
return false;
|
|
182426
|
+
const key = elementKey2(description);
|
|
182427
|
+
const cached = this.constantCache.get(key);
|
|
182428
|
+
if (cached !== void 0)
|
|
182429
|
+
return cached;
|
|
182430
|
+
const node = this.linker?.resolveIndexedNode?.(description) ?? description.node;
|
|
182431
|
+
const modifiers2 = node?.modifiers ?? [];
|
|
182432
|
+
const answer = modifiers2.some((modifier) => CONSTANT_MODIFIERS.has(modifier));
|
|
182433
|
+
this.constantCache.set(key, answer);
|
|
182434
|
+
return answer;
|
|
182435
|
+
}
|
|
181382
182436
|
/**
|
|
181383
182437
|
* REQ-395 — Find one implicit base in the index.
|
|
181384
182438
|
*
|
|
@@ -181392,25 +182446,19 @@ var SysmlInlayHintProvider = class {
|
|
|
181392
182446
|
const cached = this.baseCache.get(qualified);
|
|
181393
182447
|
if (cached)
|
|
181394
182448
|
return cached;
|
|
181395
|
-
|
|
181396
|
-
if (!index2)
|
|
182449
|
+
if (!this.lookup)
|
|
181397
182450
|
return void 0;
|
|
181398
|
-
const
|
|
181399
|
-
|
|
181400
|
-
|
|
181401
|
-
|
|
181402
|
-
|
|
181403
|
-
|
|
181404
|
-
}
|
|
181405
|
-
if (fallback || description.name !== simple)
|
|
181406
|
-
continue;
|
|
182451
|
+
const exact = this.lookup.descriptions(qualified).at(0);
|
|
182452
|
+
if (exact) {
|
|
182453
|
+
this.baseCache.set(qualified, exact);
|
|
182454
|
+
return exact;
|
|
182455
|
+
}
|
|
182456
|
+
const fallback = this.lookup.descriptions(lastSegment3(qualified)).find((description) => {
|
|
181407
182457
|
const uri = description.documentUri instanceof URI2 ? description.documentUri : URI2.parse(String(description.documentUri));
|
|
181408
182458
|
if (!isStandardLibraryUri(uri))
|
|
181409
|
-
|
|
181410
|
-
|
|
181411
|
-
|
|
181412
|
-
fallback = description;
|
|
181413
|
-
}
|
|
182459
|
+
return false;
|
|
182460
|
+
return description.isUsage === true === wantUsage;
|
|
182461
|
+
});
|
|
181414
182462
|
if (fallback)
|
|
181415
182463
|
this.baseCache.set(qualified, fallback);
|
|
181416
182464
|
return fallback;
|
|
@@ -196025,7 +197073,7 @@ var AFV_LAYOUT_EDGE_KINDS = /* @__PURE__ */ new Set([
|
|
|
196025
197073
|
"succession",
|
|
196026
197074
|
"successionFlow"
|
|
196027
197075
|
]);
|
|
196028
|
-
var STV_LAYOUT_EDGE_KINDS = /* @__PURE__ */ new Set(["transition"]);
|
|
197076
|
+
var STV_LAYOUT_EDGE_KINDS = /* @__PURE__ */ new Set(["transition", "succession"]);
|
|
196029
197077
|
function behaviorLayoutEdgeKinds(kind) {
|
|
196030
197078
|
return kind === "afv" ? AFV_LAYOUT_EDGE_KINDS : kind === "stv" ? STV_LAYOUT_EDGE_KINDS : void 0;
|
|
196031
197079
|
}
|
|
@@ -201234,6 +202282,10 @@ var TOOLBOX = {
|
|
|
201234
202282
|
],
|
|
201235
202283
|
relations: [
|
|
201236
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"),
|
|
201237
202289
|
// issue #115 — nothing could mark the initial state, so a state
|
|
201238
202290
|
// machine could not be STARTED from a blank canvas. The gesture runs
|
|
201239
202291
|
// from the always-drawn initial pseudostate to the first state.
|
|
@@ -201392,7 +202444,11 @@ function normalizedElementKeyword(keyword) {
|
|
|
201392
202444
|
"loop action",
|
|
201393
202445
|
"for-loop action",
|
|
201394
202446
|
"perform action",
|
|
201395
|
-
"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"
|
|
201396
202452
|
].includes(base)) {
|
|
201397
202453
|
base = "action";
|
|
201398
202454
|
} else if (["fork", "join", "merge", "decide", "decision"].includes(base)) {
|
|
@@ -201494,7 +202550,12 @@ function relationToolsForNode(keyword, viewKind, shape) {
|
|
|
201494
202550
|
if (base === "port") return false;
|
|
201495
202551
|
return base === "pin" && (tool.kind === "flow" || tool.kind === "successionFlow" || tool.kind === "bind");
|
|
201496
202552
|
}
|
|
201497
|
-
if (viewKind === "stv")
|
|
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
|
+
}
|
|
201498
202559
|
if (viewKind === "sv") return shape === "lifeline" && (base === "part" || base === "lifeline");
|
|
201499
202560
|
if (viewKind === "cv") {
|
|
201500
202561
|
if (base === "actor") return tool.kind === "actor";
|
|
@@ -203957,7 +205018,7 @@ async function runExport(command) {
|
|
|
203957
205018
|
}
|
|
203958
205019
|
|
|
203959
205020
|
// src/main.ts
|
|
203960
|
-
var VERSION2 = true ? "0.
|
|
205021
|
+
var VERSION2 = true ? "0.26.0" : "dev";
|
|
203961
205022
|
function display(file) {
|
|
203962
205023
|
const rel2 = path9.relative(process.cwd(), file);
|
|
203963
205024
|
return rel2 && !rel2.startsWith("..") ? rel2.split(path9.sep).join("/") : file;
|