sysml-diagram 0.23.0 → 0.25.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 +1082 -57
- 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
|
@@ -162474,6 +162474,35 @@ function connectionEndMultiplicity(node) {
|
|
|
162474
162474
|
return void 0;
|
|
162475
162475
|
return hi == null || hi === lo ? `[${lo}]` : `[${lo}..${hi}]`;
|
|
162476
162476
|
}
|
|
162477
|
+
function isEmptyPrefixFlow(node) {
|
|
162478
|
+
const fm = node;
|
|
162479
|
+
return node.$type === "FlowStmt" && fm.target !== void 0 && fm.source === void 0;
|
|
162480
|
+
}
|
|
162481
|
+
function flowStmtName(node) {
|
|
162482
|
+
return isEmptyPrefixFlow(node) ? void 0 : effectiveNameOf(node);
|
|
162483
|
+
}
|
|
162484
|
+
function flowKeyword(fm) {
|
|
162485
|
+
return `${fm.succession === true ? "succession " : ""}${fm.flowKind === "message" ? "message" : "flow"}`;
|
|
162486
|
+
}
|
|
162487
|
+
function flowTransferredFeature(ends) {
|
|
162488
|
+
const sourceFeature = ends.source ? lastSeg(ends.source) : void 0;
|
|
162489
|
+
const targetFeature = ends.target ? lastSeg(ends.target) : void 0;
|
|
162490
|
+
return sourceFeature === targetFeature ? sourceFeature : sourceFeature ?? targetFeature;
|
|
162491
|
+
}
|
|
162492
|
+
function flowDecorationMeta(carried) {
|
|
162493
|
+
const drawn = carried.filter((flow) => !flow.message);
|
|
162494
|
+
if (!drawn.length)
|
|
162495
|
+
return {};
|
|
162496
|
+
return {
|
|
162497
|
+
flowDecorations: drawn.map(({ keyword, label, name, reversed, row }) => ({
|
|
162498
|
+
keyword,
|
|
162499
|
+
...label ? { label } : {},
|
|
162500
|
+
...name ? { name } : {},
|
|
162501
|
+
reversed,
|
|
162502
|
+
...row.source ? { source: row.source } : {}
|
|
162503
|
+
}))
|
|
162504
|
+
};
|
|
162505
|
+
}
|
|
162477
162506
|
var END_PROPERTY_ADORNMENTS = /* @__PURE__ */ new Set(["abstract", "derived", "readonly", "ordered", "nonunique"]);
|
|
162478
162507
|
var uniqueStrings = (values2) => [...new Set([...values2].filter((value) => !!value))];
|
|
162479
162508
|
function formatConnectionEndAdornment(notation) {
|
|
@@ -164919,6 +164948,27 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
164919
164948
|
}
|
|
164920
164949
|
return { source: void 0, target: fm.target ? String(fm.target) : void 0 };
|
|
164921
164950
|
}
|
|
164951
|
+
// REQ-401 — the `flows-compartment` row of one flow or message usage (OMG
|
|
164952
|
+
// SysML 8.2.3.16). Rebuilt from the declaration instead of copied from the
|
|
164953
|
+
// source text, because a flow may carry a BODY (`flow a.x to b.y { doc ... }`)
|
|
164954
|
+
// whose whole text would otherwise be inlined into one compartment row.
|
|
164955
|
+
// `ends` overrides the declared endpoints with the concrete ones a relationship
|
|
164956
|
+
// usage rebinds them to (REQ-402).
|
|
164957
|
+
// REQ-401 — Flow notation: on-connection decoration, port docking, and the flow usage node
|
|
164958
|
+
flowRowText(flow, ends) {
|
|
164959
|
+
const fm = flow;
|
|
164960
|
+
const declared = ends ?? this.flowStmtEnds(fm);
|
|
164961
|
+
const type = typeText(flow);
|
|
164962
|
+
const payload = this.flowPayloadText(fm);
|
|
164963
|
+
return [
|
|
164964
|
+
flowKeyword(fm),
|
|
164965
|
+
flowStmtName(flow),
|
|
164966
|
+
type ? `: ${type}` : void 0,
|
|
164967
|
+
payload ? `of ${payload}` : void 0,
|
|
164968
|
+
declared.source ? `from ${declared.source}` : void 0,
|
|
164969
|
+
declared.target ? `to ${declared.target}` : void 0
|
|
164970
|
+
].filter(Boolean).join(" ");
|
|
164971
|
+
}
|
|
164922
164972
|
// Payload text of a flow/message (`of Fuel` / `of f : Fuel`) per OMG SysML
|
|
164923
164973
|
// 8.2.2.16 PayloadFeature.
|
|
164924
164974
|
flowPayloadText(fm) {
|
|
@@ -164928,6 +164978,87 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
164928
164978
|
const typeRef = p.type?.$refText ?? p.typing?.type?.$refText;
|
|
164929
164979
|
return typeRef ? lastSeg(typeRef) : p.name;
|
|
164930
164980
|
}
|
|
164981
|
+
// REQ-402 — the flows a connection or interface usage CARRIES. A flow declared
|
|
164982
|
+
// in a `connection def` / `interface def` body (OMG SysML 8.2.3.16, and the
|
|
164983
|
+
// `Flow Interface Example` of the training corpus) is transported by every
|
|
164984
|
+
// usage of that definition; it is not a transfer of its own between two
|
|
164985
|
+
// unrelated features. Each end path is rebound through the usage's own end
|
|
164986
|
+
// bindings, so the definition-local `supplierPort.fuelSupply` reads as the
|
|
164987
|
+
// concrete `tankAssy.fuelTankPort.fuelSupply` this usage connects, and the
|
|
164988
|
+
// transfer direction is expressed relative to the usage's own end ordinals so
|
|
164989
|
+
// it survives whichever notation the relationship is drawn in.
|
|
164990
|
+
// REQ-402 — Flows carried by a connection or interface usage
|
|
164991
|
+
carriedFlowsOf(usage, ends, index2, uri) {
|
|
164992
|
+
const ordinalByRole = /* @__PURE__ */ new Map();
|
|
164993
|
+
const pathByRole = /* @__PURE__ */ new Map();
|
|
164994
|
+
for (const end of ends) {
|
|
164995
|
+
const role = end.notation.role;
|
|
164996
|
+
if (!role)
|
|
164997
|
+
continue;
|
|
164998
|
+
if (!ordinalByRole.has(role))
|
|
164999
|
+
ordinalByRole.set(role, end.ordinal);
|
|
165000
|
+
if (end.path && !pathByRole.has(role))
|
|
165001
|
+
pathByRole.set(role, end.path);
|
|
165002
|
+
}
|
|
165003
|
+
const rebind = (path10) => {
|
|
165004
|
+
if (!path10)
|
|
165005
|
+
return void 0;
|
|
165006
|
+
const segs = path10.split(".");
|
|
165007
|
+
const bound = pathByRole.get(segs[0]);
|
|
165008
|
+
return bound ? [bound, ...segs.slice(1)].join(".") : path10;
|
|
165009
|
+
};
|
|
165010
|
+
const carried = [];
|
|
165011
|
+
const seen = /* @__PURE__ */ new Set();
|
|
165012
|
+
for (const source of [usage, ...this.inheritedFeatureOwnersOf(usage, index2)]) {
|
|
165013
|
+
for (const member of membersOf(source)) {
|
|
165014
|
+
if (member.$type !== "FlowStmt" || member.isDef === true)
|
|
165015
|
+
continue;
|
|
165016
|
+
const fm = member;
|
|
165017
|
+
const flowEnds = this.flowStmtEnds(fm);
|
|
165018
|
+
const name = flowStmtName(member);
|
|
165019
|
+
const payload = this.flowPayloadText(fm);
|
|
165020
|
+
const key = name ?? `\0${flowEnds.source ?? ""}\0${flowEnds.target ?? ""}\0${payload ?? typeText(member) ?? ""}`;
|
|
165021
|
+
if (seen.has(key))
|
|
165022
|
+
continue;
|
|
165023
|
+
seen.add(key);
|
|
165024
|
+
const fromOrdinal = flowEnds.source ? ordinalByRole.get(flowEnds.source.split(".")[0]) : void 0;
|
|
165025
|
+
const from = rebind(flowEnds.source);
|
|
165026
|
+
const to = rebind(flowEnds.target);
|
|
165027
|
+
carried.push({
|
|
165028
|
+
flow: member,
|
|
165029
|
+
keyword: flowKeyword(fm),
|
|
165030
|
+
label: payload ?? typeText(member) ?? flowTransferredFeature(flowEnds),
|
|
165031
|
+
name,
|
|
165032
|
+
// The decoration rides the relationship, whose drawn direction
|
|
165033
|
+
// runs from its first end to its second.
|
|
165034
|
+
reversed: fromOrdinal !== void 0 && fromOrdinal > 0,
|
|
165035
|
+
inherited: source !== usage,
|
|
165036
|
+
message: fm.flowKind === "message",
|
|
165037
|
+
row: {
|
|
165038
|
+
text: this.flowRowText(member, { source: from, target: to }),
|
|
165039
|
+
source: sourceOf2(member, uri)
|
|
165040
|
+
}
|
|
165041
|
+
});
|
|
165042
|
+
}
|
|
165043
|
+
}
|
|
165044
|
+
return carried;
|
|
165045
|
+
}
|
|
165046
|
+
// REQ-402 — merge the transfers a relationship usage carries from its
|
|
165047
|
+
// definitions into the `flows` compartment its own body already contributes,
|
|
165048
|
+
// so one heading holds every transfer the usage transports.
|
|
165049
|
+
// REQ-402 — Flows carried by a connection or interface usage
|
|
165050
|
+
withCarriedFlowRows(compartments, carried) {
|
|
165051
|
+
const rows = carried.filter((flow) => flow.inherited).map((flow) => flow.row);
|
|
165052
|
+
if (!rows.length)
|
|
165053
|
+
return compartments;
|
|
165054
|
+
const out = [...compartments ?? []];
|
|
165055
|
+
const existing = out.findIndex((compartment) => compartment.title === "flows");
|
|
165056
|
+
if (existing >= 0)
|
|
165057
|
+
out[existing] = { ...out[existing], items: [...out[existing].items, ...rows] };
|
|
165058
|
+
else
|
|
165059
|
+
out.push({ title: "flows", items: rows });
|
|
165060
|
+
return out;
|
|
165061
|
+
}
|
|
164931
165062
|
// REQ-192/360/363 — the ONE recursive Interconnection View renderer. Given the
|
|
164932
165063
|
// top-level `roots` to draw, it renders each part instance and nests its
|
|
164933
165064
|
// internals recursively, drilling into a usage's type DEFINITION (+
|
|
@@ -164976,7 +165107,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
164976
165107
|
for (const source of [part, ...this.inheritedFeatureOwnersOf(part, index2)]) {
|
|
164977
165108
|
for (const member of membersOf(source)) {
|
|
164978
165109
|
const relationship = member;
|
|
164979
|
-
const emptyPrefixFlow = member
|
|
165110
|
+
const emptyPrefixFlow = isEmptyPrefixFlow(member);
|
|
164980
165111
|
const emptyPrefixInterface = isInterfaceDecl(member) && relationship.target !== void 0 && relationship.connect === void 0;
|
|
164981
165112
|
const namedRelationship = isConnectorDecl(member) || isConnectionDecl(member) || isInterfaceDecl(member) && !emptyPrefixInterface || member.$type === "BindingDecl" || member.$type === "FlowStmt" && !emptyPrefixFlow;
|
|
164982
165113
|
if (namedRelationship) {
|
|
@@ -165133,16 +165264,16 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
165133
165264
|
};
|
|
165134
165265
|
const performedActions = depth < 8 && !(typeQ !== void 0 && seenTypes.has(typeQ)) ? effectiveMembersOf(part).filter((m) => m.$type === "PerformStmt" && !!nameOf2(m)).map((act) => {
|
|
165135
165266
|
const pinSource = this.performTargetOf(act, index2) ?? act;
|
|
165136
|
-
const
|
|
165267
|
+
const pathSegments2 = this.isAnonymousBehaviorReference(act) ? this.featurePaths.resolveDeclarationPath(act).segments.map((segment) => segment.text) : [nameOf2(act)];
|
|
165137
165268
|
return {
|
|
165138
165269
|
act,
|
|
165139
165270
|
pinSource,
|
|
165140
|
-
pathSegments,
|
|
165141
|
-
name:
|
|
165271
|
+
pathSegments: pathSegments2,
|
|
165272
|
+
name: pathSegments2.at(-1) ?? nameOf2(act),
|
|
165142
165273
|
key: concretePerformPath(act, pinSource)
|
|
165143
165274
|
};
|
|
165144
165275
|
}).filter((entry, i, list) => list.findIndex((other) => other.key === entry.key) === i) : [];
|
|
165145
|
-
const performedActionInfos = performedActions.map(({ act, pinSource, pathSegments, name, key }) => {
|
|
165276
|
+
const performedActionInfos = performedActions.map(({ act, pinSource, pathSegments: pathSegments2, name, key }) => {
|
|
165146
165277
|
const id2 = `${instanceId}::__perform_${key}`;
|
|
165147
165278
|
const inheritedFromDefinition = !!localUsage && !isAstDescendantOrSelf(act, localUsage);
|
|
165148
165279
|
const syncDeclaration2 = this.synchronizationDeclarationOf(act, index2);
|
|
@@ -165150,7 +165281,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
165150
165281
|
act,
|
|
165151
165282
|
name,
|
|
165152
165283
|
id: id2,
|
|
165153
|
-
pathSegments,
|
|
165284
|
+
pathSegments: pathSegments2,
|
|
165154
165285
|
pins: this.actionPinPorts(pinSource, id2, index2, uri),
|
|
165155
165286
|
meta: {
|
|
165156
165287
|
...ivEditMeta(act, id2, void 0, localUsage, [...localPath, name], uri),
|
|
@@ -165334,6 +165465,8 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
165334
165465
|
// synthetic n-ary dot with that container's frame id).
|
|
165335
165466
|
emitInterconnectEdges(members, resolveEnd, parts, index2, uri, nodes, edges, eRef, frameId, actionPinIds = /* @__PURE__ */ new Set(), structuralPortIds = /* @__PURE__ */ new Set(), memberOwner, memberOwnerInherited = false, endpointProvenance = /* @__PURE__ */ new Map()) {
|
|
165336
165467
|
const memberList2 = [...members];
|
|
165468
|
+
const pendingFlows = [];
|
|
165469
|
+
const firstEdge = edges.length;
|
|
165337
165470
|
const relationshipFields = (source) => {
|
|
165338
165471
|
let directMember = source;
|
|
165339
165472
|
while (directMember.$container && directMember.$container !== memberOwner) {
|
|
@@ -165488,22 +165621,8 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
165488
165621
|
}
|
|
165489
165622
|
}
|
|
165490
165623
|
} else if (m.$type === "FlowStmt") {
|
|
165491
|
-
|
|
165492
|
-
|
|
165493
|
-
continue;
|
|
165494
|
-
const { source, target } = this.flowStmtEnds(fm);
|
|
165495
|
-
const from = resolveEnd(source ?? "");
|
|
165496
|
-
const to = resolveEnd(target ?? "");
|
|
165497
|
-
if (from && to && supportsEndpoints("flow", [from, to])) {
|
|
165498
|
-
edges.push({
|
|
165499
|
-
id: `e${eRef.n++}`,
|
|
165500
|
-
from,
|
|
165501
|
-
to,
|
|
165502
|
-
kind: "flow",
|
|
165503
|
-
label: this.flowPayloadText(fm) ?? typeText(m) ?? nameOf2(m),
|
|
165504
|
-
...relationshipFields(m)
|
|
165505
|
-
});
|
|
165506
|
-
}
|
|
165624
|
+
if (m.isDef !== true)
|
|
165625
|
+
pendingFlows.push(m);
|
|
165507
165626
|
} else if (m.$type === "BindStmt" || m.$type === "BindingConnectorStmt" || m.$type === "BindingDecl") {
|
|
165508
165627
|
const bn = m;
|
|
165509
165628
|
const leftEnd = bn.left ?? bn.source;
|
|
@@ -165591,6 +165710,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
165591
165710
|
}
|
|
165592
165711
|
};
|
|
165593
165712
|
});
|
|
165713
|
+
const carriedFlows = this.carriedFlowsOf(m, usageEnds, index2, uri);
|
|
165594
165714
|
nodes.push({
|
|
165595
165715
|
id: usageId,
|
|
165596
165716
|
name: name ?? ANONYMOUS_INTERFACE_NAME,
|
|
@@ -165601,12 +165721,13 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
165601
165721
|
multiplicity: multText(m),
|
|
165602
165722
|
ports,
|
|
165603
165723
|
...usageFrame ? { frame: usageFrame } : {},
|
|
165604
|
-
compartments: this.compartmentsFor(m, uri, index2),
|
|
165724
|
+
compartments: this.withCarriedFlowRows(this.compartmentsFor(m, uri, index2), carriedFlows),
|
|
165605
165725
|
source: usageSource,
|
|
165606
165726
|
meta: {
|
|
165607
165727
|
...relationship.meta ?? {},
|
|
165608
165728
|
interfaceUsage: true,
|
|
165609
|
-
...name ? { explicitRelationshipName: name } : {}
|
|
165729
|
+
...name ? { explicitRelationshipName: name } : {},
|
|
165730
|
+
...flowDecorationMeta(carriedFlows)
|
|
165610
165731
|
}
|
|
165611
165732
|
});
|
|
165612
165733
|
for (const { end, ordinal, targetId } of visibleUsageEnds) {
|
|
@@ -165675,6 +165796,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
165675
165796
|
}
|
|
165676
165797
|
};
|
|
165677
165798
|
});
|
|
165799
|
+
const carriedFlows = this.carriedFlowsOf(m, usageEnds, index2, uri);
|
|
165678
165800
|
nodes.push({
|
|
165679
165801
|
id: usageId,
|
|
165680
165802
|
name: name ?? "connection",
|
|
@@ -165684,12 +165806,13 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
165684
165806
|
type,
|
|
165685
165807
|
ports,
|
|
165686
165808
|
...usageFrame ? { frame: usageFrame } : {},
|
|
165687
|
-
compartments: this.compartmentsFor(m, uri, index2),
|
|
165809
|
+
compartments: this.withCarriedFlowRows(this.compartmentsFor(m, uri, index2), carriedFlows),
|
|
165688
165810
|
source: usageSource,
|
|
165689
165811
|
meta: {
|
|
165690
165812
|
...relationship.meta ?? {},
|
|
165691
165813
|
connectionUsage: true,
|
|
165692
|
-
...name ? { explicitRelationshipName: name } : {}
|
|
165814
|
+
...name ? { explicitRelationshipName: name } : {},
|
|
165815
|
+
...flowDecorationMeta(carriedFlows)
|
|
165693
165816
|
}
|
|
165694
165817
|
});
|
|
165695
165818
|
for (const { end, ordinal, targetId } of visibleUsageEnds) {
|
|
@@ -165717,6 +165840,92 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
165717
165840
|
}
|
|
165718
165841
|
}
|
|
165719
165842
|
}
|
|
165843
|
+
const resolveFlowEnd = (pathText) => {
|
|
165844
|
+
const direct = resolveEnd(pathText);
|
|
165845
|
+
if (direct)
|
|
165846
|
+
return { id: direct, docked: false };
|
|
165847
|
+
const parts2 = pathText.split(/(::|\.)/u).filter((part) => part.length > 0);
|
|
165848
|
+
for (let length2 = parts2.length - 2; length2 >= 1; length2 -= 2) {
|
|
165849
|
+
const carrier = resolveEnd(parts2.slice(0, length2).join(""));
|
|
165850
|
+
if (carrier)
|
|
165851
|
+
return { id: carrier, docked: true };
|
|
165852
|
+
}
|
|
165853
|
+
return void 0;
|
|
165854
|
+
};
|
|
165855
|
+
const transportFor = (from, to) => edges.slice(firstEdge).find((edge) => (edge.kind === "connect" || edge.kind === "interface") && (edge.from === from && edge.to === to || edge.from === to && edge.to === from));
|
|
165856
|
+
const flowUsageNodeId = (flow) => {
|
|
165857
|
+
const src = sourceOf2(flow, uri);
|
|
165858
|
+
const ownerId = frameId ?? (qnameOf(memberOwner ?? flow) || "iv");
|
|
165859
|
+
const suffix = (frameId ? flowStmtName(flow) : qnameOf(flow)) ?? (src ? `${src.range.start.line}_${src.range.start.character}` : `${eRef.n}`);
|
|
165860
|
+
return `${ownerId}::__flow_${suffix}`;
|
|
165861
|
+
};
|
|
165862
|
+
for (const m of pendingFlows) {
|
|
165863
|
+
const fm = m;
|
|
165864
|
+
const message = fm.flowKind === "message";
|
|
165865
|
+
const keyword = flowKeyword(fm);
|
|
165866
|
+
const { source, target } = this.flowStmtEnds(fm);
|
|
165867
|
+
const flowName = flowStmtName(m);
|
|
165868
|
+
const sourceEnd = message ? void 0 : resolveFlowEnd(source ?? "");
|
|
165869
|
+
const targetEnd = message ? void 0 : resolveFlowEnd(target ?? "");
|
|
165870
|
+
const selfDock = sourceEnd !== void 0 && sourceEnd.id === targetEnd?.id && (sourceEnd.docked || targetEnd.docked);
|
|
165871
|
+
const from = selfDock ? void 0 : sourceEnd?.id;
|
|
165872
|
+
const to = selfDock ? void 0 : targetEnd?.id;
|
|
165873
|
+
const transferred = flowTransferredFeature({ source, target });
|
|
165874
|
+
const label = this.flowPayloadText(fm) ?? typeText(m) ?? transferred ?? flowName;
|
|
165875
|
+
if (from && to && supportsEndpoints("flow", [from, to])) {
|
|
165876
|
+
const transport = transportFor(from, to);
|
|
165877
|
+
if (transport) {
|
|
165878
|
+
const decorations = Array.isArray(transport.meta?.flowDecorations) ? transport.meta.flowDecorations : [];
|
|
165879
|
+
transport.meta = {
|
|
165880
|
+
...transport.meta ?? {},
|
|
165881
|
+
flowDecorations: [...decorations, {
|
|
165882
|
+
keyword,
|
|
165883
|
+
label,
|
|
165884
|
+
...flowName ? { name: flowName } : {},
|
|
165885
|
+
reversed: transport.from === to,
|
|
165886
|
+
source: sourceOf2(m, uri)
|
|
165887
|
+
}]
|
|
165888
|
+
};
|
|
165889
|
+
continue;
|
|
165890
|
+
}
|
|
165891
|
+
edges.push({
|
|
165892
|
+
id: `e${eRef.n++}`,
|
|
165893
|
+
from,
|
|
165894
|
+
to,
|
|
165895
|
+
kind: "flow",
|
|
165896
|
+
label,
|
|
165897
|
+
...relationshipFields(m)
|
|
165898
|
+
});
|
|
165899
|
+
continue;
|
|
165900
|
+
}
|
|
165901
|
+
if (message || !flowName)
|
|
165902
|
+
continue;
|
|
165903
|
+
const ownerNode = frameId ? nodes.find((node) => node.id === frameId) : void 0;
|
|
165904
|
+
const ends = [
|
|
165905
|
+
...source ? [{ text: `from ${source}` }] : [],
|
|
165906
|
+
...target ? [{ text: `to ${target}` }] : []
|
|
165907
|
+
];
|
|
165908
|
+
nodes.push({
|
|
165909
|
+
id: flowUsageNodeId(m),
|
|
165910
|
+
name: flowName,
|
|
165911
|
+
keyword,
|
|
165912
|
+
isDef: false,
|
|
165913
|
+
shape: "box",
|
|
165914
|
+
type: typeText(m),
|
|
165915
|
+
multiplicity: multText(m),
|
|
165916
|
+
...ownerNode ? { frame: ownerNode.frame } : frameId ? { frame: frameId } : {},
|
|
165917
|
+
compartments: [
|
|
165918
|
+
...label ? [{ title: "payload", items: [{ text: label }] }] : [],
|
|
165919
|
+
...ends.length ? [{ title: "ends", items: ends }] : []
|
|
165920
|
+
],
|
|
165921
|
+
source: sourceOf2(m, uri),
|
|
165922
|
+
meta: {
|
|
165923
|
+
...relationshipFields(m).meta ?? {},
|
|
165924
|
+
flowUsage: true,
|
|
165925
|
+
explicitRelationshipName: flowName
|
|
165926
|
+
}
|
|
165927
|
+
});
|
|
165928
|
+
}
|
|
165720
165929
|
}
|
|
165721
165930
|
// ── iv overview (REQ-360) — recursive nested Interconnection View over a
|
|
165722
165931
|
// package. The hierarchy follows COMPOSITION, not text layout: the roots are
|
|
@@ -167077,9 +167286,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
167077
167286
|
const to = resolvePin(ends.target, occurrenceContext);
|
|
167078
167287
|
if (from && to) {
|
|
167079
167288
|
const kind = fm.succession === true ? "successionFlow" : "flow";
|
|
167080
|
-
const
|
|
167081
|
-
const targetFeature = ends.target ? lastSeg(ends.target) : void 0;
|
|
167082
|
-
const transferredFeature = sourceFeature === targetFeature ? sourceFeature : sourceFeature ?? targetFeature;
|
|
167289
|
+
const transferredFeature = flowTransferredFeature(ends);
|
|
167083
167290
|
edges.push({
|
|
167084
167291
|
id: `e${e++}`,
|
|
167085
167292
|
from,
|
|
@@ -169777,6 +169984,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
|
|
|
169777
169984
|
}
|
|
169778
169985
|
add("connections", members.filter((member) => isConnectionDecl(member) && member.isDef !== true && isOrdinaryMember(member)).map((member) => item(member, this.featureText(member) || "(anonymous connection)")));
|
|
169779
169986
|
add("interfaces", members.filter((m) => isInterfaceDecl(m) && m.isDef !== true && isOrdinaryMember(m)).map((m) => item(m, this.interfaceRowText(m))));
|
|
169987
|
+
add("flows", members.filter((m) => m.$type === "FlowStmt" && m.isDef !== true && isOrdinaryMember(m)).map((m) => item(m, this.flowRowText(m))));
|
|
169780
169988
|
add("features", members.filter((m) => m.$type === "FeatureShorthand" || m.$type === "FeatureRedefinitionShorthand").filter(isOrdinaryMember).filter((m) => !isOccurrenceModified(m)).map((m) => item(m, canonicalFeatureText(m))));
|
|
169781
169989
|
const undirected = (guard) => usages(guard);
|
|
169782
169990
|
add("items", undirected(isItemDecl).filter(notPortion).map((m) => item(m)));
|
|
@@ -170210,7 +170418,9 @@ var sysmlInlayHintSettings = {
|
|
|
170210
170418
|
modifiers: false,
|
|
170211
170419
|
specialization: false,
|
|
170212
170420
|
redefinition: false,
|
|
170213
|
-
effectiveNames: false
|
|
170421
|
+
effectiveNames: false,
|
|
170422
|
+
importedNames: false,
|
|
170423
|
+
parameterNames: false
|
|
170214
170424
|
};
|
|
170215
170425
|
|
|
170216
170426
|
// ../language-server/out/src/services/category-taxonomy.js
|
|
@@ -180911,6 +181121,329 @@ var SysmlSemanticTokenProvider = class extends AbstractSemanticTokenProvider {
|
|
|
180911
181121
|
|
|
180912
181122
|
// ../language-server/out/src/services/inlay-hint-provider.js
|
|
180913
181123
|
var import_vscode_languageserver20 = __toESM(require_main4(), 1);
|
|
181124
|
+
|
|
181125
|
+
// ../language-server/out/src/services/name-lookup.js
|
|
181126
|
+
function unquoteName3(name) {
|
|
181127
|
+
return name.replace(/^'(.*)'$/u, "$1");
|
|
181128
|
+
}
|
|
181129
|
+
function pathSegments(path10) {
|
|
181130
|
+
const segments = [];
|
|
181131
|
+
let current2 = "";
|
|
181132
|
+
let quoted = false;
|
|
181133
|
+
for (let index2 = 0; index2 < path10.length; index2++) {
|
|
181134
|
+
const char = path10[index2];
|
|
181135
|
+
if (char === "'") {
|
|
181136
|
+
quoted = !quoted;
|
|
181137
|
+
current2 += char;
|
|
181138
|
+
continue;
|
|
181139
|
+
}
|
|
181140
|
+
if (!quoted && char === ":" && path10[index2 + 1] === ":") {
|
|
181141
|
+
segments.push(current2);
|
|
181142
|
+
current2 = "";
|
|
181143
|
+
index2++;
|
|
181144
|
+
continue;
|
|
181145
|
+
}
|
|
181146
|
+
if (!quoted && char === ".") {
|
|
181147
|
+
segments.push(current2);
|
|
181148
|
+
current2 = "";
|
|
181149
|
+
continue;
|
|
181150
|
+
}
|
|
181151
|
+
current2 += char;
|
|
181152
|
+
}
|
|
181153
|
+
segments.push(current2);
|
|
181154
|
+
return segments;
|
|
181155
|
+
}
|
|
181156
|
+
function simpleNameOf2(name) {
|
|
181157
|
+
return pathSegments(name).at(-1) ?? name;
|
|
181158
|
+
}
|
|
181159
|
+
var ELEMENT_SEPARATOR = "\0";
|
|
181160
|
+
function elementKey2(description) {
|
|
181161
|
+
return `${description.documentUri.toString()}${ELEMENT_SEPARATOR}${description.path}`;
|
|
181162
|
+
}
|
|
181163
|
+
function isDeclaredSpelling(description) {
|
|
181164
|
+
const kind = description.derivedKind;
|
|
181165
|
+
if (kind === "reexport" || kind === "inherited")
|
|
181166
|
+
return false;
|
|
181167
|
+
return pathSegments(description.name).length === 1;
|
|
181168
|
+
}
|
|
181169
|
+
var SysmlNameLookup = class {
|
|
181170
|
+
shared;
|
|
181171
|
+
byName;
|
|
181172
|
+
/** Element key → the declared spellings the index holds for that element. */
|
|
181173
|
+
spellings;
|
|
181174
|
+
constructor(shared) {
|
|
181175
|
+
this.shared = shared;
|
|
181176
|
+
this.shared.workspace.DocumentBuilder.onBuildPhase(DocumentState.IndexedContent, () => {
|
|
181177
|
+
this.byName = void 0;
|
|
181178
|
+
this.spellings = void 0;
|
|
181179
|
+
});
|
|
181180
|
+
}
|
|
181181
|
+
/** Every description indexed under `name`, in either spelling of an escaped name. */
|
|
181182
|
+
descriptions(name) {
|
|
181183
|
+
return this.index().get(name) ?? [];
|
|
181184
|
+
}
|
|
181185
|
+
/**
|
|
181186
|
+
* The ONE element `name` names, or `undefined` when the answer is not
|
|
181187
|
+
* certain: no element, or more than one. `accept` narrows the candidates
|
|
181188
|
+
* before ambiguity is judged, so "the only CALLABLE called `f`" is a
|
|
181189
|
+
* decidable question even where a part shares the name.
|
|
181190
|
+
*/
|
|
181191
|
+
unique(name, accept) {
|
|
181192
|
+
const candidates = this.descriptions(name).filter((candidate) => !accept || accept(candidate));
|
|
181193
|
+
let found;
|
|
181194
|
+
let key;
|
|
181195
|
+
for (const candidate of candidates) {
|
|
181196
|
+
const candidateKey = elementKey2(candidate);
|
|
181197
|
+
if (found === void 0) {
|
|
181198
|
+
found = candidate;
|
|
181199
|
+
key = candidateKey;
|
|
181200
|
+
continue;
|
|
181201
|
+
}
|
|
181202
|
+
if (candidateKey !== key)
|
|
181203
|
+
return void 0;
|
|
181204
|
+
}
|
|
181205
|
+
return found;
|
|
181206
|
+
}
|
|
181207
|
+
/**
|
|
181208
|
+
* Resolve a written path: the spelling the index holds verbatim first, then
|
|
181209
|
+
* its final segment. Both readings must name exactly one element.
|
|
181210
|
+
*/
|
|
181211
|
+
uniqueForPath(path10, accept) {
|
|
181212
|
+
return this.unique(path10, accept) ?? this.unique(simpleNameOf2(path10), accept);
|
|
181213
|
+
}
|
|
181214
|
+
/**
|
|
181215
|
+
* The declared spellings of the element `description` names — its regular
|
|
181216
|
+
* name and its `<short>` name — minus `written`.
|
|
181217
|
+
*/
|
|
181218
|
+
otherNames(description, written) {
|
|
181219
|
+
const all = this.spellingIndex().get(elementKey2(description)) ?? [];
|
|
181220
|
+
const seen = unquoteName3(written);
|
|
181221
|
+
return all.filter((name) => unquoteName3(name) !== seen);
|
|
181222
|
+
}
|
|
181223
|
+
index() {
|
|
181224
|
+
if (!this.byName)
|
|
181225
|
+
this.build();
|
|
181226
|
+
return this.byName;
|
|
181227
|
+
}
|
|
181228
|
+
spellingIndex() {
|
|
181229
|
+
if (!this.spellings)
|
|
181230
|
+
this.build();
|
|
181231
|
+
return this.spellings;
|
|
181232
|
+
}
|
|
181233
|
+
/** One pass over the index feeds both maps; neither is worth a second. */
|
|
181234
|
+
build() {
|
|
181235
|
+
const byName = /* @__PURE__ */ new Map();
|
|
181236
|
+
const spellings = /* @__PURE__ */ new Map();
|
|
181237
|
+
const add = (key, description) => {
|
|
181238
|
+
const bucket = byName.get(key);
|
|
181239
|
+
if (bucket)
|
|
181240
|
+
bucket.push(description);
|
|
181241
|
+
else
|
|
181242
|
+
byName.set(key, [description]);
|
|
181243
|
+
};
|
|
181244
|
+
for (const description of this.shared.workspace.IndexManager.allElements()) {
|
|
181245
|
+
add(description.name, description);
|
|
181246
|
+
const unquoted = unquoteName3(description.name);
|
|
181247
|
+
if (unquoted !== description.name)
|
|
181248
|
+
add(unquoted, description);
|
|
181249
|
+
if (!isDeclaredSpelling(description))
|
|
181250
|
+
continue;
|
|
181251
|
+
const key = elementKey2(description);
|
|
181252
|
+
const names = spellings.get(key);
|
|
181253
|
+
if (names) {
|
|
181254
|
+
if (!names.includes(description.name))
|
|
181255
|
+
names.push(description.name);
|
|
181256
|
+
} else {
|
|
181257
|
+
spellings.set(key, [description.name]);
|
|
181258
|
+
}
|
|
181259
|
+
}
|
|
181260
|
+
this.byName = byName;
|
|
181261
|
+
this.spellings = spellings;
|
|
181262
|
+
}
|
|
181263
|
+
};
|
|
181264
|
+
var lookups = /* @__PURE__ */ new WeakMap();
|
|
181265
|
+
function nameLookupFor(shared) {
|
|
181266
|
+
if (!shared)
|
|
181267
|
+
return void 0;
|
|
181268
|
+
const existing = lookups.get(shared);
|
|
181269
|
+
if (existing)
|
|
181270
|
+
return existing;
|
|
181271
|
+
const created = new SysmlNameLookup(shared);
|
|
181272
|
+
lookups.set(shared, created);
|
|
181273
|
+
return created;
|
|
181274
|
+
}
|
|
181275
|
+
|
|
181276
|
+
// ../language-server/out/src/services/callable-resolver.js
|
|
181277
|
+
var CALLABLE_TYPES = /* @__PURE__ */ new Set([
|
|
181278
|
+
"CalcDecl",
|
|
181279
|
+
"ActionDecl",
|
|
181280
|
+
"ConstraintDecl",
|
|
181281
|
+
"FunctionDecl",
|
|
181282
|
+
"PredicateDecl",
|
|
181283
|
+
"BehaviorDecl",
|
|
181284
|
+
"InteractionDecl"
|
|
181285
|
+
]);
|
|
181286
|
+
var CallableResolver = class {
|
|
181287
|
+
services;
|
|
181288
|
+
lookup;
|
|
181289
|
+
linker;
|
|
181290
|
+
constructor(services) {
|
|
181291
|
+
this.services = services;
|
|
181292
|
+
this.lookup = nameLookupFor(services?.shared);
|
|
181293
|
+
this.linker = services?.references.Linker;
|
|
181294
|
+
}
|
|
181295
|
+
/**
|
|
181296
|
+
* Every indexed callable that answers to `name`, so a caller can decide what
|
|
181297
|
+
* ambiguity costs it. Signature help is transient and follows the cursor, so
|
|
181298
|
+
* it takes the first; an inlay hint is a permanent annotation, so it takes a
|
|
181299
|
+
* candidate only when it is the ONLY element with that name.
|
|
181300
|
+
*/
|
|
181301
|
+
candidates(name) {
|
|
181302
|
+
const simple = simpleNameOf2(name);
|
|
181303
|
+
return (this.lookup?.descriptions(simple) ?? []).filter((description) => CALLABLE_TYPES.has(description.type));
|
|
181304
|
+
}
|
|
181305
|
+
/**
|
|
181306
|
+
* The one callable `name` unambiguously names in the index, if any: the
|
|
181307
|
+
* written spelling first, then its final segment, and either reading must
|
|
181308
|
+
* name exactly one element.
|
|
181309
|
+
*/
|
|
181310
|
+
uniqueCandidate(name) {
|
|
181311
|
+
return this.lookup?.uniqueForPath(name, (description) => CALLABLE_TYPES.has(description.type));
|
|
181312
|
+
}
|
|
181313
|
+
/** The callable declaration `name` invokes in `document`, resolved locally. */
|
|
181314
|
+
findLocal(document2, name) {
|
|
181315
|
+
const root4 = document2.parseResult?.value;
|
|
181316
|
+
if (!root4)
|
|
181317
|
+
return void 0;
|
|
181318
|
+
return collectCallables([root4, ...ast_utils_exports.streamAllContents(root4).toArray()]).get(unquoteName3(simpleNameOf2(name)));
|
|
181319
|
+
}
|
|
181320
|
+
/**
|
|
181321
|
+
* SYNCHRONOUS resolution: a qualified spelling the index holds verbatim,
|
|
181322
|
+
* then the document's own tree, then an unambiguous indexed callable —
|
|
181323
|
+
* resolved through the linker's off-to-the-side library parse. Nothing here
|
|
181324
|
+
* grows `LangiumDocuments`, and nothing here awaits, so it is safe on a
|
|
181325
|
+
* request VS Code re-issues on every scroll.
|
|
181326
|
+
*/
|
|
181327
|
+
resolve(document2, name, local) {
|
|
181328
|
+
if (name.includes("::") || name.includes(".")) {
|
|
181329
|
+
const exact = this.lookup?.unique(name, (description) => CALLABLE_TYPES.has(description.type));
|
|
181330
|
+
const node = exact ? this.nodeOf(exact) : void 0;
|
|
181331
|
+
if (node)
|
|
181332
|
+
return node;
|
|
181333
|
+
}
|
|
181334
|
+
const found = local ? local(unquoteName3(simpleNameOf2(name))) : this.findLocal(document2, name);
|
|
181335
|
+
if (found)
|
|
181336
|
+
return found;
|
|
181337
|
+
const candidate = this.uniqueCandidate(name);
|
|
181338
|
+
return candidate ? this.nodeOf(candidate) : void 0;
|
|
181339
|
+
}
|
|
181340
|
+
/** An indexed description as a node, through the linker's lazy library parse. */
|
|
181341
|
+
nodeOf(description) {
|
|
181342
|
+
return this.linker?.resolveIndexedNode?.(description) ?? description.node;
|
|
181343
|
+
}
|
|
181344
|
+
/**
|
|
181345
|
+
* Resolution that may load a workspace document. Signature help uses it: it
|
|
181346
|
+
* runs on an explicit editor gesture, not on every scroll, and a callable in
|
|
181347
|
+
* a workspace file the user has not opened yet still deserves a signature.
|
|
181348
|
+
*/
|
|
181349
|
+
// REQ-263 — Signature help on `(` / `,` / `->`
|
|
181350
|
+
async resolveAsync(document2, name) {
|
|
181351
|
+
const direct = this.resolve(document2, name);
|
|
181352
|
+
if (direct)
|
|
181353
|
+
return direct;
|
|
181354
|
+
const candidate = this.candidates(name).at(0);
|
|
181355
|
+
if (!candidate)
|
|
181356
|
+
return void 0;
|
|
181357
|
+
if (candidate.node)
|
|
181358
|
+
return candidate.node;
|
|
181359
|
+
const documents = this.services?.shared.workspace.LangiumDocuments;
|
|
181360
|
+
const locator = this.services?.workspace.AstNodeLocator;
|
|
181361
|
+
if (!documents || !locator)
|
|
181362
|
+
return void 0;
|
|
181363
|
+
const doc = documents.getDocument(candidate.documentUri) ?? await documents.getOrCreateDocument(candidate.documentUri);
|
|
181364
|
+
const root4 = doc?.parseResult?.value;
|
|
181365
|
+
return root4 ? locator.getAstNode(root4, candidate.path) : void 0;
|
|
181366
|
+
}
|
|
181367
|
+
/** {@link callableParameters} — the parameters, in written order. */
|
|
181368
|
+
parameters(node) {
|
|
181369
|
+
return callableParameters(node);
|
|
181370
|
+
}
|
|
181371
|
+
/**
|
|
181372
|
+
* The parameters a positional argument list binds to: the INPUTS, in written
|
|
181373
|
+
* order. An `out` parameter and the result are not written at the call site
|
|
181374
|
+
* (OMG KerML v1.0 binds an `InvocationExpression`'s arguments to the
|
|
181375
|
+
* invoked type's input features).
|
|
181376
|
+
*/
|
|
181377
|
+
inputParameters(node) {
|
|
181378
|
+
return this.parameters(node).filter((parameter) => !parameter.isReturn && parameter.direction !== "out");
|
|
181379
|
+
}
|
|
181380
|
+
};
|
|
181381
|
+
function callableParameters(node) {
|
|
181382
|
+
const directed = new Map(directedParameters(node).map((entry) => [entry.node, entry.direction]));
|
|
181383
|
+
const result = [];
|
|
181384
|
+
for (const member of membersOf2(node)) {
|
|
181385
|
+
const direction = directed.get(member);
|
|
181386
|
+
const isReturn = member.$type === "ReturnDecl";
|
|
181387
|
+
if (!direction && !isReturn)
|
|
181388
|
+
continue;
|
|
181389
|
+
const name = nodeName2(member);
|
|
181390
|
+
if (!name && !direction)
|
|
181391
|
+
continue;
|
|
181392
|
+
result.push({
|
|
181393
|
+
node: member,
|
|
181394
|
+
direction: direction ?? "return",
|
|
181395
|
+
name,
|
|
181396
|
+
type: typingText(member),
|
|
181397
|
+
multiplicity: multiplicityText2(member),
|
|
181398
|
+
isReturn
|
|
181399
|
+
});
|
|
181400
|
+
}
|
|
181401
|
+
return result;
|
|
181402
|
+
}
|
|
181403
|
+
function collectCallables(nodes) {
|
|
181404
|
+
const callables = /* @__PURE__ */ new Map();
|
|
181405
|
+
const byDefinition = /* @__PURE__ */ new Set();
|
|
181406
|
+
for (const node of nodes) {
|
|
181407
|
+
if (!CALLABLE_TYPES.has(node.$type) && callableParameters(node).length === 0)
|
|
181408
|
+
continue;
|
|
181409
|
+
const isDefinition = node.isDef === true;
|
|
181410
|
+
for (const name of [nodeName2(node), shortNameOf2(node)]) {
|
|
181411
|
+
if (!name)
|
|
181412
|
+
continue;
|
|
181413
|
+
if (callables.has(name) && !(isDefinition && !byDefinition.has(name)))
|
|
181414
|
+
continue;
|
|
181415
|
+
callables.set(name, node);
|
|
181416
|
+
if (isDefinition)
|
|
181417
|
+
byDefinition.add(name);
|
|
181418
|
+
}
|
|
181419
|
+
}
|
|
181420
|
+
return callables;
|
|
181421
|
+
}
|
|
181422
|
+
function membersOf2(node) {
|
|
181423
|
+
const members = node?.members;
|
|
181424
|
+
return Array.isArray(members) ? members.filter(isAstNode3) : [];
|
|
181425
|
+
}
|
|
181426
|
+
function isAstNode3(value) {
|
|
181427
|
+
return typeof value === "object" && value !== null && typeof value.$type === "string";
|
|
181428
|
+
}
|
|
181429
|
+
function nodeName2(node) {
|
|
181430
|
+
const value = node?.name;
|
|
181431
|
+
return typeof value === "string" && value.length > 0 ? unquoteName3(value) : void 0;
|
|
181432
|
+
}
|
|
181433
|
+
function shortNameOf2(node) {
|
|
181434
|
+
const value = node?.shortName?.name;
|
|
181435
|
+
return typeof value === "string" && value.length > 0 ? unquoteName3(value) : void 0;
|
|
181436
|
+
}
|
|
181437
|
+
function typingText(node) {
|
|
181438
|
+
const text = node?.typing?.type?.$refText;
|
|
181439
|
+
return typeof text === "string" && text.length > 0 ? text : void 0;
|
|
181440
|
+
}
|
|
181441
|
+
function multiplicityText2(node) {
|
|
181442
|
+
const text = node?.multiplicity?.$cstNode?.text;
|
|
181443
|
+
return typeof text === "string" && text.length > 0 ? text.trim() : void 0;
|
|
181444
|
+
}
|
|
181445
|
+
|
|
181446
|
+
// ../language-server/out/src/services/inlay-hint-provider.js
|
|
180914
181447
|
function multiplicityAnchor(node) {
|
|
180915
181448
|
const leaves = cst_utils_exports.flattenCst(node).toArray();
|
|
180916
181449
|
const bodyStart = leaves.find((leaf) => leaf.text === "{");
|
|
@@ -180969,6 +181502,50 @@ var EXPLICIT_SPECIALIZATION_KINDS = /* @__PURE__ */ new Set([
|
|
|
180969
181502
|
"conjugates"
|
|
180970
181503
|
]);
|
|
180971
181504
|
var REDEFINITION_KINDS2 = /* @__PURE__ */ new Set([":>>", "redefines"]);
|
|
181505
|
+
var CONSTANT_CARRYING_KINDS = /* @__PURE__ */ new Set([
|
|
181506
|
+
":>",
|
|
181507
|
+
"subsets",
|
|
181508
|
+
":>>",
|
|
181509
|
+
"redefines",
|
|
181510
|
+
"::>",
|
|
181511
|
+
"references",
|
|
181512
|
+
"=>",
|
|
181513
|
+
"crosses"
|
|
181514
|
+
]);
|
|
181515
|
+
var CONSTANT_MODIFIERS = /* @__PURE__ */ new Set(["constant", "const"]);
|
|
181516
|
+
function constantKeyword(languageId) {
|
|
181517
|
+
return languageId === "kerml" ? "const" : "constant";
|
|
181518
|
+
}
|
|
181519
|
+
var PREFIXES_BEFORE_CONSTANT = /* @__PURE__ */ new Set([
|
|
181520
|
+
"public",
|
|
181521
|
+
"private",
|
|
181522
|
+
"protected",
|
|
181523
|
+
"in",
|
|
181524
|
+
"out",
|
|
181525
|
+
"inout",
|
|
181526
|
+
"abstract",
|
|
181527
|
+
"variation",
|
|
181528
|
+
"variant",
|
|
181529
|
+
"derived",
|
|
181530
|
+
"readonly",
|
|
181531
|
+
"composite",
|
|
181532
|
+
"portion",
|
|
181533
|
+
"ordered",
|
|
181534
|
+
"nonunique",
|
|
181535
|
+
"parallel"
|
|
181536
|
+
]);
|
|
181537
|
+
var PORTION_MODIFIERS = /* @__PURE__ */ new Set(["portion", "snapshot", "timeslice"]);
|
|
181538
|
+
var ACTION_KIND_USAGES = /* @__PURE__ */ new Set([
|
|
181539
|
+
"ActionDecl",
|
|
181540
|
+
"StateDecl",
|
|
181541
|
+
"CalcDecl",
|
|
181542
|
+
"CaseDecl",
|
|
181543
|
+
"UseCaseDecl",
|
|
181544
|
+
"AnalysisCaseDecl",
|
|
181545
|
+
"VerificationCaseDecl"
|
|
181546
|
+
]);
|
|
181547
|
+
var KERML_FEATURE_DECLS = /* @__PURE__ */ new Set(["FeatureDecl", "StepDecl", "ExpressionDecl"]);
|
|
181548
|
+
var REFERENCE_MODIFIERS = /* @__PURE__ */ new Set(["ref", "in", "out", "inout"]);
|
|
180972
181549
|
var IMPLICIT_BASES = Object.freeze({
|
|
180973
181550
|
PartDecl: { def: "Parts::Part", usage: "Parts::parts" },
|
|
180974
181551
|
ItemDecl: { def: "Items::Item", usage: "Items::items" },
|
|
@@ -180993,6 +181570,37 @@ var IMPLICIT_BASES = Object.freeze({
|
|
|
180993
181570
|
OccurrenceDecl: { def: "Occurrences::Occurrence", usage: "Occurrences::occurrences" },
|
|
180994
181571
|
MetadataDecl: { def: "Metadata::MetadataItem", usage: "Metadata::metadataItems" }
|
|
180995
181572
|
});
|
|
181573
|
+
var OCCURRENCE_KIND_OWNERS = /* @__PURE__ */ new Set([
|
|
181574
|
+
...Object.keys(IMPLICIT_BASES).filter((kind) => kind !== "AttributeDecl"),
|
|
181575
|
+
// KerML fixes a library base per classifier kind too, in the same way and in
|
|
181576
|
+
// the same normative place: `Class` specializes `Occurrences::Occurrence`,
|
|
181577
|
+
// `Structure` specializes `Objects::Object`, `Metaclass` specializes
|
|
181578
|
+
// `Metaobjects::Metaobject`, `Behavior` specializes
|
|
181579
|
+
// `Performances::Performance`, `Function` and `Interaction` are Behaviors,
|
|
181580
|
+
// `Predicate` is a Function, `Step` specializes `Performances::performances`
|
|
181581
|
+
// and `Expression` is a Step. All of them reach `Occurrence`.
|
|
181582
|
+
"ClassDecl",
|
|
181583
|
+
"StructDecl",
|
|
181584
|
+
"MetaclassDecl",
|
|
181585
|
+
"BehaviorDecl",
|
|
181586
|
+
"InteractionDecl",
|
|
181587
|
+
"FunctionDecl",
|
|
181588
|
+
"PredicateDecl",
|
|
181589
|
+
"StepDecl",
|
|
181590
|
+
"ExpressionDecl"
|
|
181591
|
+
// Left out because their base is NOT an occurrence: `DatatypeDecl`
|
|
181592
|
+
// (`Base::DataValue`, declared disjoint from `Occurrence`) and plain
|
|
181593
|
+
// `AssociationDecl` (`Links::Link`, which specializes `Base::Anything`) —
|
|
181594
|
+
// `assoc struct` is handled separately, since it is a `LinkObject`.
|
|
181595
|
+
// Left out because their base is WRITTEN rather than fixed by the kind:
|
|
181596
|
+
// `TypeDecl`, `ClassifierDecl`, `FeatureDecl`.
|
|
181597
|
+
]);
|
|
181598
|
+
function isOccurrenceKindOwner(owner) {
|
|
181599
|
+
if (owner.$type === "AssociationDecl")
|
|
181600
|
+
return owner.isStruct === true;
|
|
181601
|
+
return OCCURRENCE_KIND_OWNERS.has(owner.$type);
|
|
181602
|
+
}
|
|
181603
|
+
var NON_VARYING_LIBRARY_TYPES = /* @__PURE__ */ new Set(["SelfLink", "HappensLink"]);
|
|
180996
181604
|
function markdown(value) {
|
|
180997
181605
|
return { kind: import_vscode_languageserver20.MarkupKind.Markdown, value };
|
|
180998
181606
|
}
|
|
@@ -181014,19 +181622,130 @@ function descriptionRange(description) {
|
|
|
181014
181622
|
const segment = description.nameSegment ?? description.selectionSegment;
|
|
181015
181623
|
return segment?.range ?? { start: { line: 0, character: 0 }, end: { line: 0, character: 0 } };
|
|
181016
181624
|
}
|
|
181625
|
+
function descriptionLocation(description) {
|
|
181626
|
+
return { uri: description.documentUri.toString(), range: descriptionRange(description) };
|
|
181627
|
+
}
|
|
181628
|
+
function nodeLocation(node) {
|
|
181629
|
+
const range = node.$cstNode?.range;
|
|
181630
|
+
if (!range)
|
|
181631
|
+
return void 0;
|
|
181632
|
+
return { uri: ast_utils_exports.getDocument(node).uri.toString(), range };
|
|
181633
|
+
}
|
|
181634
|
+
function specializesNonVaryingLibraryType(node) {
|
|
181635
|
+
const typing = node.typing?.type?.$refText;
|
|
181636
|
+
if (typing && NON_VARYING_LIBRARY_TYPES.has(lastSegment3(typing)))
|
|
181637
|
+
return true;
|
|
181638
|
+
return allRelationships2(node).flatMap((rel2) => rel2.targets ?? []).some((target) => NON_VARYING_LIBRARY_TYPES.has(lastSegment3(target)));
|
|
181639
|
+
}
|
|
181640
|
+
function constantAnchor(node) {
|
|
181641
|
+
const cst = node.$cstNode;
|
|
181642
|
+
if (!cst)
|
|
181643
|
+
return void 0;
|
|
181644
|
+
for (const leaf of cst_utils_exports.flattenCst(cst)) {
|
|
181645
|
+
if (leaf.hidden)
|
|
181646
|
+
continue;
|
|
181647
|
+
if (PREFIXES_BEFORE_CONSTANT.has(leaf.text))
|
|
181648
|
+
continue;
|
|
181649
|
+
return /^[a-z]+$/u.test(leaf.text) ? leaf : void 0;
|
|
181650
|
+
}
|
|
181651
|
+
return void 0;
|
|
181652
|
+
}
|
|
181653
|
+
function membershipImportPath(node) {
|
|
181654
|
+
if (isImport(node) && node.alias)
|
|
181655
|
+
return void 0;
|
|
181656
|
+
if (isExposePath(node) && node.dotSegs.length > 0)
|
|
181657
|
+
return void 0;
|
|
181658
|
+
if (node.segs.some((seg) => seg.star || seg.recursive || !seg.name))
|
|
181659
|
+
return void 0;
|
|
181660
|
+
const last2 = node.segs.at(-1);
|
|
181661
|
+
const written = last2?.name ?? node.head;
|
|
181662
|
+
const anchor = last2 ? grammar_utils_exports.findNodeForProperty(last2.$cstNode, "name") : grammar_utils_exports.findNodeForProperty(node.$cstNode, "head");
|
|
181663
|
+
if (!anchor)
|
|
181664
|
+
return void 0;
|
|
181665
|
+
return { path: [node.head, ...node.segs.map((seg) => seg.name)].join("::"), written, anchor };
|
|
181666
|
+
}
|
|
181667
|
+
function publicFeatures(type) {
|
|
181668
|
+
const members = type.members;
|
|
181669
|
+
if (!Array.isArray(members))
|
|
181670
|
+
return [];
|
|
181671
|
+
return members.filter((member) => {
|
|
181672
|
+
if (typeof member?.$type !== "string")
|
|
181673
|
+
return false;
|
|
181674
|
+
const decl = member;
|
|
181675
|
+
if (decl.isDef !== false && decl.$type !== "FeatureDecl")
|
|
181676
|
+
return false;
|
|
181677
|
+
return decl.visibility === void 0 || decl.visibility === "public";
|
|
181678
|
+
});
|
|
181679
|
+
}
|
|
181680
|
+
function calleeName(node) {
|
|
181681
|
+
if (node.call) {
|
|
181682
|
+
if (isPathExpr(node.target))
|
|
181683
|
+
return node.target.path;
|
|
181684
|
+
const target = node.target;
|
|
181685
|
+
if (isPostfixOp(target) && target.dot && target.field)
|
|
181686
|
+
return target.field;
|
|
181687
|
+
return void 0;
|
|
181688
|
+
}
|
|
181689
|
+
if (node.arrow && node.invoke)
|
|
181690
|
+
return node.invoke;
|
|
181691
|
+
return void 0;
|
|
181692
|
+
}
|
|
181693
|
+
function callArguments(node) {
|
|
181694
|
+
if (node.call)
|
|
181695
|
+
return { args: node.callArgs, firstParameter: 0 };
|
|
181696
|
+
if (node.arrow && node.invoke)
|
|
181697
|
+
return { args: node.args, firstParameter: 1 };
|
|
181698
|
+
return void 0;
|
|
181699
|
+
}
|
|
181017
181700
|
var SysmlInlayHintProvider = class {
|
|
181018
181701
|
services;
|
|
181019
181702
|
/**
|
|
181020
181703
|
* Resolved implicit bases, keyed by the qualified name in
|
|
181021
|
-
* {@link IMPLICIT_BASES}.
|
|
181022
|
-
*
|
|
181023
|
-
*
|
|
181024
|
-
*
|
|
181025
|
-
*
|
|
181704
|
+
* {@link IMPLICIT_BASES}. A base the index does not hold is NOT cached — the
|
|
181705
|
+
* library may still be loading — and issue #240 made that miss cheap: two
|
|
181706
|
+
* lookups in the shared name index rather than the full index scan it used
|
|
181707
|
+
* to be, on a request VS Code re-issues on every scroll. A HIT is cached
|
|
181708
|
+
* until the index is rebuilt, so the description a label links to always
|
|
181709
|
+
* carries the ranges of the generation it was read from.
|
|
181026
181710
|
*/
|
|
181027
181711
|
baseCache = /* @__PURE__ */ new Map();
|
|
181712
|
+
/**
|
|
181713
|
+
* REQ-395 — issue #240: the shared name lookup, built once per index
|
|
181714
|
+
* generation. Every category that resolves a WRITTEN name goes through it,
|
|
181715
|
+
* so no request puts an index scan on the hint path.
|
|
181716
|
+
*/
|
|
181717
|
+
lookup;
|
|
181718
|
+
/** REQ-395 — issue #240: the callee resolution signature help also uses. */
|
|
181719
|
+
callables;
|
|
181720
|
+
/** REQ-395 — issue #240: the linker's lazy standard-library parse. */
|
|
181721
|
+
linker;
|
|
181722
|
+
/**
|
|
181723
|
+
* REQ-395 — issue #240: "does this element declare `constant`?", memoized by
|
|
181724
|
+
* element identity, because answering it may cost one lazily parsed library
|
|
181725
|
+
* file. Editing away the `constant` on the SUBSETTED feature changes the
|
|
181726
|
+
* answer without changing the key, so this is dropped whenever the index is
|
|
181727
|
+
* rebuilt, exactly like the shared name lookup.
|
|
181728
|
+
*/
|
|
181729
|
+
constantCache = /* @__PURE__ */ new Map();
|
|
181730
|
+
/**
|
|
181731
|
+
* REQ-395 — issue #240: an element's own written names, memoized by element
|
|
181732
|
+
* identity. Reading them tells a `<short>` name from a regular one, which is
|
|
181733
|
+
* what lets the imported-name hint print the notation the source would have
|
|
181734
|
+
* written. It costs at most one lazily parsed library file, only for an
|
|
181735
|
+
* element that actually has two names, and it is dropped with the rest when
|
|
181736
|
+
* the index is rebuilt.
|
|
181737
|
+
*/
|
|
181738
|
+
declaredNameCache = /* @__PURE__ */ new Map();
|
|
181028
181739
|
constructor(services) {
|
|
181029
181740
|
this.services = services;
|
|
181741
|
+
this.lookup = nameLookupFor(services?.shared);
|
|
181742
|
+
this.callables = new CallableResolver(services);
|
|
181743
|
+
this.linker = services?.references.Linker;
|
|
181744
|
+
services?.shared.workspace.DocumentBuilder.onBuildPhase(DocumentState.IndexedContent, () => {
|
|
181745
|
+
this.baseCache.clear();
|
|
181746
|
+
this.constantCache.clear();
|
|
181747
|
+
this.declaredNameCache.clear();
|
|
181748
|
+
});
|
|
181030
181749
|
}
|
|
181031
181750
|
getInlayHints(document2, _params) {
|
|
181032
181751
|
const root4 = document2.parseResult?.value;
|
|
@@ -181034,7 +181753,14 @@ var SysmlInlayHintProvider = class {
|
|
|
181034
181753
|
return void 0;
|
|
181035
181754
|
const settings = sysmlInlayHintSettings;
|
|
181036
181755
|
const hints = [];
|
|
181037
|
-
|
|
181756
|
+
const nodes = allAstNodes(root4);
|
|
181757
|
+
let localCallables;
|
|
181758
|
+
const localCallable = (simple) => {
|
|
181759
|
+
localCallables ??= collectCallables(nodes);
|
|
181760
|
+
return localCallables.get(simple);
|
|
181761
|
+
};
|
|
181762
|
+
const callees = /* @__PURE__ */ new Map();
|
|
181763
|
+
for (const node of nodes) {
|
|
181038
181764
|
const decl = node;
|
|
181039
181765
|
if (settings.multiplicity && (isPartDecl(node) || isPortDecl(node) || isAttributeDecl(node)) && !decl.isDef && !decl.multiplicity && node.$cstNode && decl.name) {
|
|
181040
181766
|
hints.push({
|
|
@@ -181061,6 +181787,11 @@ var SysmlInlayHintProvider = class {
|
|
|
181061
181787
|
});
|
|
181062
181788
|
}
|
|
181063
181789
|
}
|
|
181790
|
+
if (settings.modifiers) {
|
|
181791
|
+
const constant2 = this.implicitConstantHint(decl);
|
|
181792
|
+
if (constant2)
|
|
181793
|
+
hints.push(constant2);
|
|
181794
|
+
}
|
|
181064
181795
|
if (settings.modifiers && isAttributeDecl(node) && !decl.isDef && !(decl.modifiers ?? []).includes("ref")) {
|
|
181065
181796
|
const keyword = keywordLeaf(node, "attribute");
|
|
181066
181797
|
if (keyword) {
|
|
@@ -181102,6 +181833,17 @@ var SysmlInlayHintProvider = class {
|
|
|
181102
181833
|
if (effective)
|
|
181103
181834
|
hints.push(effective);
|
|
181104
181835
|
}
|
|
181836
|
+
if (settings.importedNames && (isImport(node) || isExposePath(node))) {
|
|
181837
|
+
const imported = this.importedNameHint(node);
|
|
181838
|
+
if (imported)
|
|
181839
|
+
hints.push(imported);
|
|
181840
|
+
}
|
|
181841
|
+
if (settings.parameterNames && isPostfixOp(node)) {
|
|
181842
|
+
hints.push(...this.argumentNameHints(node, document2, callees, localCallable));
|
|
181843
|
+
}
|
|
181844
|
+
if (settings.parameterNames && isNewExpr(node)) {
|
|
181845
|
+
hints.push(...this.constructorArgumentHints(node));
|
|
181846
|
+
}
|
|
181105
181847
|
if (!settings.dimension)
|
|
181106
181848
|
continue;
|
|
181107
181849
|
if (isNumericPrimary(node)) {
|
|
@@ -181171,6 +181913,228 @@ var SysmlInlayHintProvider = class {
|
|
|
181171
181913
|
}
|
|
181172
181914
|
return hints;
|
|
181173
181915
|
}
|
|
181916
|
+
/**
|
|
181917
|
+
* REQ-395 — issue #240: the other name a membership `import` brings in.
|
|
181918
|
+
*
|
|
181919
|
+
* An element may declare both a regular name and a `<short>` name, and an
|
|
181920
|
+
* import brings in BOTH — the one the path does not write is invisible in
|
|
181921
|
+
* the source, which is exactly what the hint is for. The written path is a
|
|
181922
|
+
* datatype string, not a cross-reference, so the element is found through
|
|
181923
|
+
* the shared name lookup: the spelling the index holds verbatim first, then
|
|
181924
|
+
* the final segment, and either reading must name exactly ONE element. A
|
|
181925
|
+
* name two packages both declare yields nothing rather than whichever the
|
|
181926
|
+
* index lists first.
|
|
181927
|
+
*/
|
|
181928
|
+
importedNameHint(node) {
|
|
181929
|
+
const written = membershipImportPath(node);
|
|
181930
|
+
if (!written || !this.lookup)
|
|
181931
|
+
return void 0;
|
|
181932
|
+
const description = this.lookup.uniqueForPath(written.path);
|
|
181933
|
+
if (!description)
|
|
181934
|
+
return void 0;
|
|
181935
|
+
const others = this.lookup.otherNames(description, written.written);
|
|
181936
|
+
if (others.length === 0)
|
|
181937
|
+
return void 0;
|
|
181938
|
+
const declared = this.declaredNames(description);
|
|
181939
|
+
const shown = others.map((name) => declared?.shortName === name ? `<${name}>` : name);
|
|
181940
|
+
const kind = isImport(node) ? "import" : "expose";
|
|
181941
|
+
return {
|
|
181942
|
+
position: written.anchor.range.end,
|
|
181943
|
+
label: [{
|
|
181944
|
+
value: ` also ${shown.join(", ")}`,
|
|
181945
|
+
location: descriptionLocation(description)
|
|
181946
|
+
}],
|
|
181947
|
+
kind: import_vscode_languageserver20.InlayHintKind.Parameter,
|
|
181948
|
+
paddingLeft: true,
|
|
181949
|
+
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.`)
|
|
181950
|
+
};
|
|
181951
|
+
}
|
|
181952
|
+
/**
|
|
181953
|
+
* REQ-395 — issue #240: the names an indexed element declares for itself.
|
|
181954
|
+
*
|
|
181955
|
+
* The index records the spellings but not which of them is the `<short>`
|
|
181956
|
+
* one, so the declaration is resolved through the linker's off-to-the-side
|
|
181957
|
+
* library parse — the budget REQ-251 sets, spent only for an element that
|
|
181958
|
+
* has more than one name, and memoized until the index is rebuilt.
|
|
181959
|
+
*/
|
|
181960
|
+
declaredNames(description) {
|
|
181961
|
+
const key = elementKey2(description);
|
|
181962
|
+
const cached = this.declaredNameCache.get(key);
|
|
181963
|
+
if (cached)
|
|
181964
|
+
return cached;
|
|
181965
|
+
const node = this.linker?.resolveIndexedNode?.(description) ?? description.node;
|
|
181966
|
+
if (!node)
|
|
181967
|
+
return void 0;
|
|
181968
|
+
const decl = node;
|
|
181969
|
+
const names = { name: decl.name, shortName: decl.shortName?.name };
|
|
181970
|
+
this.declaredNameCache.set(key, names);
|
|
181971
|
+
return names;
|
|
181972
|
+
}
|
|
181973
|
+
/**
|
|
181974
|
+
* REQ-395 — issue #240: the feature each `new Type(…)` argument binds to.
|
|
181975
|
+
*
|
|
181976
|
+
* A `ConstructorExpression` binds its arguments to the PUBLIC features of
|
|
181977
|
+
* the instantiated type, in order (OMG KerML v1.0, `ConstructorExpression`)
|
|
181978
|
+
* — not to input parameters, which is what an `InvocationExpression` binds.
|
|
181979
|
+
* The instantiated type IS a cross-reference here, so there is nothing to
|
|
181980
|
+
* resolve by name: an unresolved one simply yields no hints.
|
|
181981
|
+
*/
|
|
181982
|
+
constructorArgumentHints(node) {
|
|
181983
|
+
if (node.args.length === 0)
|
|
181984
|
+
return [];
|
|
181985
|
+
if (node.args.every((argument) => argument.name !== void 0))
|
|
181986
|
+
return [];
|
|
181987
|
+
const instantiated = node.type?.ref;
|
|
181988
|
+
if (!instantiated)
|
|
181989
|
+
return [];
|
|
181990
|
+
const features = publicFeatures(instantiated);
|
|
181991
|
+
if (features.length === 0)
|
|
181992
|
+
return [];
|
|
181993
|
+
const hints = [];
|
|
181994
|
+
for (let index2 = 0; index2 < node.args.length; index2++) {
|
|
181995
|
+
const argument = node.args[index2];
|
|
181996
|
+
if (argument.name || !argument.$cstNode)
|
|
181997
|
+
continue;
|
|
181998
|
+
const feature = features[index2];
|
|
181999
|
+
const name = feature?.name;
|
|
182000
|
+
if (!feature || !name)
|
|
182001
|
+
continue;
|
|
182002
|
+
const location = nodeLocation(feature);
|
|
182003
|
+
hints.push({
|
|
182004
|
+
position: argument.$cstNode.range.start,
|
|
182005
|
+
label: [{ value: `${name} =`, ...location ? { location } : {} }],
|
|
182006
|
+
kind: import_vscode_languageserver20.InlayHintKind.Parameter,
|
|
182007
|
+
paddingRight: true,
|
|
182008
|
+
tooltip: markdown(`Argument ${index2 + 1} binds to \`${name}\` of \`${node.type.$refText}\`.`)
|
|
182009
|
+
});
|
|
182010
|
+
}
|
|
182011
|
+
return hints;
|
|
182012
|
+
}
|
|
182013
|
+
/**
|
|
182014
|
+
* REQ-395 — issue #240: the parameter a POSITIONAL invocation argument binds
|
|
182015
|
+
* to.
|
|
182016
|
+
*
|
|
182017
|
+
* The callee of a call is an expression rather than a cross-reference, so
|
|
182018
|
+
* the name is resolved through the shared {@link CallableResolver} — the
|
|
182019
|
+
* same one signature help uses, which is why naming these arguments does not
|
|
182020
|
+
* add a second resolution path. An argument that writes its own name has
|
|
182021
|
+
* stated the correspondence, so it gets no hint.
|
|
182022
|
+
*/
|
|
182023
|
+
argumentNameHints(node, document2, callees, localCallable) {
|
|
182024
|
+
const call = callArguments(node);
|
|
182025
|
+
const callee = calleeName(node);
|
|
182026
|
+
if (!call || !callee || call.args.length === 0)
|
|
182027
|
+
return [];
|
|
182028
|
+
if (call.args.every((argument) => argument.argName !== void 0))
|
|
182029
|
+
return [];
|
|
182030
|
+
let callable = callees.get(callee);
|
|
182031
|
+
if (callable === void 0 && !callees.has(callee)) {
|
|
182032
|
+
callable = this.callables.resolve(document2, callee, localCallable);
|
|
182033
|
+
callees.set(callee, callable);
|
|
182034
|
+
}
|
|
182035
|
+
if (!callable)
|
|
182036
|
+
return [];
|
|
182037
|
+
const parameters = this.callables.inputParameters(callable);
|
|
182038
|
+
if (parameters.length === 0)
|
|
182039
|
+
return [];
|
|
182040
|
+
const hints = [];
|
|
182041
|
+
for (let index2 = 0; index2 < call.args.length; index2++) {
|
|
182042
|
+
const argument = call.args[index2];
|
|
182043
|
+
if (argument.argName || !argument.$cstNode)
|
|
182044
|
+
continue;
|
|
182045
|
+
const parameter = parameters[index2 + call.firstParameter];
|
|
182046
|
+
if (!parameter?.name)
|
|
182047
|
+
continue;
|
|
182048
|
+
const location = nodeLocation(parameter.node);
|
|
182049
|
+
hints.push({
|
|
182050
|
+
position: argument.$cstNode.range.start,
|
|
182051
|
+
label: [{ value: `${parameter.name} =`, ...location ? { location } : {} }],
|
|
182052
|
+
kind: import_vscode_languageserver20.InlayHintKind.Parameter,
|
|
182053
|
+
paddingRight: true,
|
|
182054
|
+
tooltip: markdown(`Argument ${index2 + 1} binds to \`${parameter.direction} ${parameter.name}\` of \`${callee}\`.`)
|
|
182055
|
+
});
|
|
182056
|
+
}
|
|
182057
|
+
return hints;
|
|
182058
|
+
}
|
|
182059
|
+
/**
|
|
182060
|
+
* REQ-395 — issue #240: implicit `constant`.
|
|
182061
|
+
*
|
|
182062
|
+
* OMG KerML v1.0 constrains `Subsetting`: `subsettedFeature.isConstant and
|
|
182063
|
+
* subsettingFeature.isVariable implies subsettingFeature.isConstant`. So a
|
|
182064
|
+
* usage that subsets or redefines a feature declared `constant` IS constant,
|
|
182065
|
+
* without writing it — provided it can vary at all, because `Feature` also
|
|
182066
|
+
* constrains `isConstant implies isVariable`.
|
|
182067
|
+
*
|
|
182068
|
+
* Whether it can vary is `Usage::mayTimeVary`, which OMG SysML v2 Part 1
|
|
182069
|
+
* derives as "owned by a type that specializes `Occurrences::Occurrence`,
|
|
182070
|
+
* and not a portion, a self/happens link, or a composite action". All four
|
|
182071
|
+
* are decided here from the declaration kinds and what the source writes
|
|
182072
|
+
* ({@link isOccurrenceKindOwner}, {@link PORTION_MODIFIERS},
|
|
182073
|
+
* {@link ACTION_KIND_USAGES} with {@link REFERENCE_MODIFIERS}, and
|
|
182074
|
+
* {@link specializesNonVaryingLibraryType}); an owner whose base is written
|
|
182075
|
+
* rather than fixed by its kind leaves the category quiet, as an
|
|
182076
|
+
* undecidable model must.
|
|
182077
|
+
*/
|
|
182078
|
+
implicitConstantHint(node) {
|
|
182079
|
+
const isFeature = node.isDef === false || KERML_FEATURE_DECLS.has(node.$type);
|
|
182080
|
+
if (!isFeature)
|
|
182081
|
+
return void 0;
|
|
182082
|
+
const modifiers2 = node.modifiers ?? [];
|
|
182083
|
+
if (modifiers2.some((modifier) => CONSTANT_MODIFIERS.has(modifier)))
|
|
182084
|
+
return void 0;
|
|
182085
|
+
if (modifiers2.some((modifier) => PORTION_MODIFIERS.has(modifier)))
|
|
182086
|
+
return void 0;
|
|
182087
|
+
if (ACTION_KIND_USAGES.has(node.$type) && !modifiers2.some((modifier) => REFERENCE_MODIFIERS.has(modifier)))
|
|
182088
|
+
return void 0;
|
|
182089
|
+
const owner = node.$container;
|
|
182090
|
+
if (!owner || !isOccurrenceKindOwner(owner))
|
|
182091
|
+
return void 0;
|
|
182092
|
+
if (specializesNonVaryingLibraryType(node))
|
|
182093
|
+
return void 0;
|
|
182094
|
+
const carrier = allRelationships2(node).filter((rel2) => rel2.kind && CONSTANT_CARRYING_KINDS.has(rel2.kind)).flatMap((rel2) => rel2.targets ?? []).find((target) => this.isConstantFeature(target));
|
|
182095
|
+
if (!carrier)
|
|
182096
|
+
return void 0;
|
|
182097
|
+
const anchor = constantAnchor(node);
|
|
182098
|
+
const at = anchor?.range.start ?? node.$cstNode?.range.start;
|
|
182099
|
+
if (!at)
|
|
182100
|
+
return void 0;
|
|
182101
|
+
const keyword = constantKeyword(this.services?.LanguageMetaData.languageId);
|
|
182102
|
+
return {
|
|
182103
|
+
position: at,
|
|
182104
|
+
label: keyword,
|
|
182105
|
+
kind: import_vscode_languageserver20.InlayHintKind.Type,
|
|
182106
|
+
paddingRight: true,
|
|
182107
|
+
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.`),
|
|
182108
|
+
// Writing the modifier is mechanically safe — it is a leading
|
|
182109
|
+
// declaration prefix, and OMG puts it exactly here, before `ref`
|
|
182110
|
+
// and the kind keyword.
|
|
182111
|
+
...anchor ? { textEdits: [{ range: { start: at, end: at }, newText: `${keyword} ` }] } : {}
|
|
182112
|
+
};
|
|
182113
|
+
}
|
|
182114
|
+
/**
|
|
182115
|
+
* REQ-395 — issue #240: does the feature this path names declare `constant`?
|
|
182116
|
+
*
|
|
182117
|
+
* The path must name exactly one element, and that element is resolved
|
|
182118
|
+
* through the linker's off-to-the-side library parse — one lazily parsed
|
|
182119
|
+
* indexed target, the budget REQ-251 sets, and never a document added to the
|
|
182120
|
+
* workspace. The answer is memoized, so a scroll does not repeat it.
|
|
182121
|
+
*/
|
|
182122
|
+
isConstantFeature(target) {
|
|
182123
|
+
if (!this.lookup)
|
|
182124
|
+
return false;
|
|
182125
|
+
const description = this.lookup.uniqueForPath(target);
|
|
182126
|
+
if (!description)
|
|
182127
|
+
return false;
|
|
182128
|
+
const key = elementKey2(description);
|
|
182129
|
+
const cached = this.constantCache.get(key);
|
|
182130
|
+
if (cached !== void 0)
|
|
182131
|
+
return cached;
|
|
182132
|
+
const node = this.linker?.resolveIndexedNode?.(description) ?? description.node;
|
|
182133
|
+
const modifiers2 = node?.modifiers ?? [];
|
|
182134
|
+
const answer = modifiers2.some((modifier) => CONSTANT_MODIFIERS.has(modifier));
|
|
182135
|
+
this.constantCache.set(key, answer);
|
|
182136
|
+
return answer;
|
|
182137
|
+
}
|
|
181174
182138
|
/**
|
|
181175
182139
|
* REQ-395 — Find one implicit base in the index.
|
|
181176
182140
|
*
|
|
@@ -181184,25 +182148,19 @@ var SysmlInlayHintProvider = class {
|
|
|
181184
182148
|
const cached = this.baseCache.get(qualified);
|
|
181185
182149
|
if (cached)
|
|
181186
182150
|
return cached;
|
|
181187
|
-
|
|
181188
|
-
if (!index2)
|
|
182151
|
+
if (!this.lookup)
|
|
181189
182152
|
return void 0;
|
|
181190
|
-
const
|
|
181191
|
-
|
|
181192
|
-
|
|
181193
|
-
|
|
181194
|
-
|
|
181195
|
-
|
|
181196
|
-
}
|
|
181197
|
-
if (fallback || description.name !== simple)
|
|
181198
|
-
continue;
|
|
182153
|
+
const exact = this.lookup.descriptions(qualified).at(0);
|
|
182154
|
+
if (exact) {
|
|
182155
|
+
this.baseCache.set(qualified, exact);
|
|
182156
|
+
return exact;
|
|
182157
|
+
}
|
|
182158
|
+
const fallback = this.lookup.descriptions(lastSegment3(qualified)).find((description) => {
|
|
181199
182159
|
const uri = description.documentUri instanceof URI2 ? description.documentUri : URI2.parse(String(description.documentUri));
|
|
181200
182160
|
if (!isStandardLibraryUri(uri))
|
|
181201
|
-
|
|
181202
|
-
|
|
181203
|
-
|
|
181204
|
-
fallback = description;
|
|
181205
|
-
}
|
|
182161
|
+
return false;
|
|
182162
|
+
return description.isUsage === true === wantUsage;
|
|
182163
|
+
});
|
|
181206
182164
|
if (fallback)
|
|
181207
182165
|
this.baseCache.set(qualified, fallback);
|
|
181208
182166
|
return fallback;
|
|
@@ -183835,7 +184793,7 @@ function compartmentWidth(node) {
|
|
|
183835
184793
|
}
|
|
183836
184794
|
function nodeForCanvas(node) {
|
|
183837
184795
|
if (node.meta?.connectionUsage === true || node.meta?.interfaceUsage === true) {
|
|
183838
|
-
const compartments2 = node.compartments?.filter((compartment) => compartment.title === "doc");
|
|
184796
|
+
const compartments2 = node.compartments?.filter((compartment) => compartment.title === "doc" || compartment.title === "flows");
|
|
183839
184797
|
return {
|
|
183840
184798
|
...node,
|
|
183841
184799
|
compartments: compartments2?.length ? compartments2 : void 0
|
|
@@ -184367,7 +185325,8 @@ function hideExplicitRelationshipBoxes(model, relationship) {
|
|
|
184367
185325
|
bindings: explicitRelationshipBindings(usage, model),
|
|
184368
185326
|
endCount: usage.ports?.length ?? 0
|
|
184369
185327
|
}));
|
|
184370
|
-
const
|
|
185328
|
+
const blocksCompaction = ({ usage, endCount }) => (nodeForCanvas(usage).compartments ?? []).some((compartment) => endCount !== 2 || compartment.title !== "flows");
|
|
185329
|
+
const retainedIds = new Set(projections.filter((projection2) => blocksCompaction(projection2) || annotatedUsageIds.has(projection2.usage.id) || projection2.endCount < 2 || projection2.bindings.length !== projection2.endCount).map(({ usage }) => usage.id));
|
|
184371
185330
|
const hiddenIds = /* @__PURE__ */ new Set();
|
|
184372
185331
|
for (const { usage } of projections) {
|
|
184373
185332
|
if (retainedIds.has(usage.id)) continue;
|
|
@@ -184424,6 +185383,8 @@ function hideExplicitRelationshipBoxes(model, relationship) {
|
|
|
184424
185383
|
});
|
|
184425
185384
|
continue;
|
|
184426
185385
|
}
|
|
185386
|
+
const hubMeta = { ...baseMeta };
|
|
185387
|
+
delete hubMeta.flowDecorations;
|
|
184427
185388
|
const hubId = `${usage.id}::__compact_hub`;
|
|
184428
185389
|
compactNodes.push({
|
|
184429
185390
|
id: hubId,
|
|
@@ -184434,7 +185395,7 @@ function hideExplicitRelationshipBoxes(model, relationship) {
|
|
|
184434
185395
|
...usage.frame ? { frame: usage.frame } : {},
|
|
184435
185396
|
source: usage.source,
|
|
184436
185397
|
meta: {
|
|
184437
|
-
...
|
|
185398
|
+
...hubMeta,
|
|
184438
185399
|
naryConnectionHub: true,
|
|
184439
185400
|
...relationship === "connection" ? { compactConnectionUsageHub: true } : { compactInterfaceUsageHub: true }
|
|
184440
185401
|
}
|
|
@@ -184454,7 +185415,7 @@ function hideExplicitRelationshipBoxes(model, relationship) {
|
|
|
184454
185415
|
endAdornmentTo: binding.adornment,
|
|
184455
185416
|
source: usage.source ?? binding.edge.source,
|
|
184456
185417
|
meta: {
|
|
184457
|
-
...
|
|
185418
|
+
...hubMeta,
|
|
184458
185419
|
...relationship === "connection" ? { compactConnectionUsageEnd: true } : { compactInterfaceUsageEnd: true },
|
|
184459
185420
|
connectionEndOrdinal: binding.ordinal,
|
|
184460
185421
|
...binding.role ? { connectionEndRole: binding.role } : {}
|
|
@@ -198165,6 +199126,45 @@ function successionFlowLabelPoint(centre, mark) {
|
|
|
198165
199126
|
y: markCoordinate(centre.y - mark.normal.y * 16)
|
|
198166
199127
|
};
|
|
198167
199128
|
}
|
|
199129
|
+
function flowDecorationsOf(edge) {
|
|
199130
|
+
const raw = edge.meta?.flowDecorations;
|
|
199131
|
+
if (!Array.isArray(raw)) return [];
|
|
199132
|
+
return raw.flatMap((entry) => {
|
|
199133
|
+
if (!entry || typeof entry !== "object") return [];
|
|
199134
|
+
const decoration = entry;
|
|
199135
|
+
return [{
|
|
199136
|
+
keyword: typeof decoration.keyword === "string" ? decoration.keyword : "flow",
|
|
199137
|
+
label: typeof decoration.label === "string" ? decoration.label : void 0,
|
|
199138
|
+
name: typeof decoration.name === "string" ? decoration.name : void 0,
|
|
199139
|
+
reversed: decoration.reversed === true
|
|
199140
|
+
}];
|
|
199141
|
+
});
|
|
199142
|
+
}
|
|
199143
|
+
var FLOW_DECORATION_STEP = 26;
|
|
199144
|
+
function flowDecorationGeometry(centre, points, source, target, index2, count, reversed) {
|
|
199145
|
+
const raw = midpointTangent(points?.length ? points : [source, target]) ?? { x: target.x - source.x, y: target.y - source.y };
|
|
199146
|
+
const length2 = Math.hypot(raw.x, raw.y);
|
|
199147
|
+
if (length2 <= 0) return void 0;
|
|
199148
|
+
const tangent = { x: raw.x / length2, y: raw.y / length2 };
|
|
199149
|
+
const normal = { x: -tangent.y, y: tangent.x };
|
|
199150
|
+
const shift = (index2 - (count - 1) / 2) * FLOW_DECORATION_STEP;
|
|
199151
|
+
const at = { x: centre.x + tangent.x * shift, y: centre.y + tangent.y * shift };
|
|
199152
|
+
const sign = reversed ? -1 : 1;
|
|
199153
|
+
const tip = { x: at.x + tangent.x * 5 * sign, y: at.y + tangent.y * 5 * sign };
|
|
199154
|
+
const back = { x: at.x - tangent.x * 4 * sign, y: at.y - tangent.y * 4 * sign };
|
|
199155
|
+
const corner = (side) => ({
|
|
199156
|
+
x: back.x + normal.x * 4 * side,
|
|
199157
|
+
y: back.y + normal.y * 4 * side
|
|
199158
|
+
});
|
|
199159
|
+
const wing = [corner(1), corner(-1)];
|
|
199160
|
+
return {
|
|
199161
|
+
chevron: [tip, wing[0], wing[1]].map((point) => `${markCoordinate(point.x)},${markCoordinate(point.y)}`).join(" "),
|
|
199162
|
+
label: {
|
|
199163
|
+
x: markCoordinate(at.x + normal.x * 13),
|
|
199164
|
+
y: markCoordinate(at.y + normal.y * 13)
|
|
199165
|
+
}
|
|
199166
|
+
};
|
|
199167
|
+
}
|
|
198168
199168
|
function routePointNearSource(points, source, target, distance2) {
|
|
198169
199169
|
const route = [source, ...points ?? [], target].filter((point, index2, all) => index2 === 0 || point.x !== all[index2 - 1].x || point.y !== all[index2 - 1].y);
|
|
198170
199170
|
let remaining = distance2;
|
|
@@ -199194,6 +200194,13 @@ body {
|
|
|
199194
200194
|
.dlink { stroke: var(--diagram-line-structural); stroke-width: 1.2; fill: none; }
|
|
199195
200195
|
.dlink.successionFlow { stroke-width: 2; }
|
|
199196
200196
|
.dsuccession-flow-mark { pointer-events: none; stroke-linecap: butt; }
|
|
200197
|
+
/* REQ-401 \u2014 OMG 8.2.3.16 flow-on-connection: the payload chevron rides the
|
|
200198
|
+
connector that transports it, in the item-flow hue, and never takes pointer
|
|
200199
|
+
events away from the connector it decorates. */
|
|
200200
|
+
.dflow-decoration {
|
|
200201
|
+
pointer-events: none; stroke: none;
|
|
200202
|
+
fill: var(--diagram-line-connection, #6cd1d9);
|
|
200203
|
+
}
|
|
199197
200204
|
/* REQ-196: AFV control transitions (IR succession) use a dotted route so
|
|
199198
200205
|
they remain visually distinct from continuous item and succession flows. */
|
|
199199
200206
|
.dlink.succession { stroke-dasharray: 1 3; stroke-linecap: round; }
|
|
@@ -200373,6 +201380,24 @@ function buildDiagramSvg(options) {
|
|
|
200373
201380
|
extendPoint(sequencingMark.x1, sequencingMark.y1, 2);
|
|
200374
201381
|
extendPoint(sequencingMark.x2, sequencingMark.y2, 2);
|
|
200375
201382
|
}
|
|
201383
|
+
const decorations = semantic ? flowDecorationsOf(semantic) : [];
|
|
201384
|
+
decorations.forEach((decoration, index2) => {
|
|
201385
|
+
const placement = flowDecorationGeometry(
|
|
201386
|
+
geometry.label,
|
|
201387
|
+
geometry.points ?? geometry.anchors,
|
|
201388
|
+
geometry.source,
|
|
201389
|
+
geometry.target,
|
|
201390
|
+
index2,
|
|
201391
|
+
decorations.length,
|
|
201392
|
+
decoration.reversed === true
|
|
201393
|
+
);
|
|
201394
|
+
if (!placement) return;
|
|
201395
|
+
edgeParts.push(`<polygon class="dflow-decoration ${decoration.keyword.replace(/\s+/gu, "-")}" points="${placement.chevron}"/>`);
|
|
201396
|
+
const text = [decoration.name, decoration.label].filter(Boolean).join(" : ");
|
|
201397
|
+
if (!text) return;
|
|
201398
|
+
labelParts.push(labelSvg(text, placement.label.x, placement.label.y, "elabel flow"));
|
|
201399
|
+
extendLabel(text, placement.label.x, placement.label.y);
|
|
201400
|
+
});
|
|
200376
201401
|
extendPoint(geometry.source.x, geometry.source.y, MARKER_ALLOWANCE);
|
|
200377
201402
|
extendPoint(geometry.target.x, geometry.target.y, MARKER_ALLOWANCE);
|
|
200378
201403
|
for (const point of geometry.points ?? geometry.anchors) extendPoint(point.x, point.y, MARKER_ALLOWANCE);
|
|
@@ -203682,7 +204707,7 @@ async function runExport(command) {
|
|
|
203682
204707
|
}
|
|
203683
204708
|
|
|
203684
204709
|
// src/main.ts
|
|
203685
|
-
var VERSION2 = true ? "0.
|
|
204710
|
+
var VERSION2 = true ? "0.25.0" : "dev";
|
|
203686
204711
|
function display(file) {
|
|
203687
204712
|
const rel2 = path9.relative(process.cwd(), file);
|
|
203688
204713
|
return rel2 && !rel2.startsWith("..") ? rel2.split(path9.sep).join("/") : file;
|