sysml-diagram 0.36.0 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/out/main.js CHANGED
@@ -161054,6 +161054,128 @@ var ANCHOR_KEYWORD = {
161054
161054
  bv: "package"
161055
161055
  };
161056
161056
 
161057
+ // ../language-server/out/src/services/constraint-reference.js
161058
+ var REFERENCE_KEYWORDS = {
161059
+ AssertConstraintStmt: "assert",
161060
+ RequireConstraintStmt: "require",
161061
+ AssumeConstraintStmt: "assume"
161062
+ };
161063
+ function isInlineConstraintClaim(node) {
161064
+ return REFERENCE_KEYWORDS[node.$type] !== void 0 && node.constraintKw === true;
161065
+ }
161066
+ function constraintReferenceOf(node) {
161067
+ const kind = REFERENCE_KEYWORDS[node.$type];
161068
+ if (!kind)
161069
+ return void 0;
161070
+ const shape = node;
161071
+ if (shape.constraintKw)
161072
+ return void 0;
161073
+ const negated = shape.isNegated === true;
161074
+ if (kind === "assert") {
161075
+ if (!shape.name)
161076
+ return void 0;
161077
+ const links = [shape.name, ...shape.chainSegs ?? []];
161078
+ return { kind, negated, path: links.join("::"), simpleName: links[links.length - 1] };
161079
+ }
161080
+ const target = shape.target;
161081
+ if (typeof target !== "string" || target.length === 0)
161082
+ return void 0;
161083
+ return {
161084
+ kind,
161085
+ negated,
161086
+ property: "target",
161087
+ path: target,
161088
+ simpleName: lastLink(target)
161089
+ };
161090
+ }
161091
+ function lastLink(path10) {
161092
+ return path10.split(/::|\./u).filter(Boolean).pop() ?? path10;
161093
+ }
161094
+ var NON_CONSTRAINT_DECL_TYPES = /* @__PURE__ */ new Set([
161095
+ "Package",
161096
+ "NamespaceDecl",
161097
+ "Document",
161098
+ "Import",
161099
+ "PartDecl",
161100
+ "ItemDecl",
161101
+ "AttributeDecl",
161102
+ "PortDecl",
161103
+ "OccurrenceDecl",
161104
+ "InterfaceDecl",
161105
+ "ConnectionDecl",
161106
+ "AllocationDecl",
161107
+ "ConnectorDecl",
161108
+ "EnumDecl",
161109
+ "EnumValueDecl",
161110
+ "MetadataDecl",
161111
+ "MultiplicityDecl",
161112
+ "ActionDecl",
161113
+ "StateDecl",
161114
+ "CalcDecl",
161115
+ "CaseDecl",
161116
+ "UseCaseDecl",
161117
+ "AnalysisCaseDecl",
161118
+ "VerificationCaseDecl",
161119
+ "ViewDecl",
161120
+ "ViewpointDecl",
161121
+ "RenderingDecl",
161122
+ "ActorDecl",
161123
+ "StakeholderDecl",
161124
+ "StructDecl",
161125
+ "ClassDecl",
161126
+ "DatatypeDecl",
161127
+ "AssociationDecl",
161128
+ "MetaclassDecl",
161129
+ "BehaviorDecl",
161130
+ "FunctionDecl",
161131
+ "InteractionDecl"
161132
+ ]);
161133
+ var NON_CONSTRAINT_LABELS = {
161134
+ Package: "a package",
161135
+ NamespaceDecl: "a namespace",
161136
+ Document: "a file root namespace",
161137
+ Import: "an import",
161138
+ PartDecl: "a part",
161139
+ ItemDecl: "an item",
161140
+ AttributeDecl: "an attribute",
161141
+ PortDecl: "a port",
161142
+ OccurrenceDecl: "an occurrence",
161143
+ InterfaceDecl: "an interface",
161144
+ ConnectionDecl: "a connection",
161145
+ AllocationDecl: "an allocation",
161146
+ ConnectorDecl: "a connector",
161147
+ EnumDecl: "an enumeration",
161148
+ EnumValueDecl: "an enumeration value",
161149
+ MetadataDecl: "a metadata usage",
161150
+ MultiplicityDecl: "a multiplicity",
161151
+ ActionDecl: "an action",
161152
+ StateDecl: "a state",
161153
+ CalcDecl: "a calculation",
161154
+ CaseDecl: "a case",
161155
+ UseCaseDecl: "a use case",
161156
+ AnalysisCaseDecl: "an analysis case",
161157
+ VerificationCaseDecl: "a verification case",
161158
+ ViewDecl: "a view",
161159
+ ViewpointDecl: "a viewpoint",
161160
+ RenderingDecl: "a rendering",
161161
+ ActorDecl: "an actor",
161162
+ StakeholderDecl: "a stakeholder",
161163
+ StructDecl: "a structure",
161164
+ ClassDecl: "a class",
161165
+ DatatypeDecl: "a datatype",
161166
+ AssociationDecl: "an association",
161167
+ MetaclassDecl: "a metaclass",
161168
+ BehaviorDecl: "a behavior",
161169
+ FunctionDecl: "a function",
161170
+ InteractionDecl: "an interaction"
161171
+ };
161172
+ function isWrongKindConstraintTarget(node) {
161173
+ return NON_CONSTRAINT_DECL_TYPES.has(node.$type);
161174
+ }
161175
+ function wrongKindLabel(node) {
161176
+ return NON_CONSTRAINT_LABELS[node.$type] ?? "not a constraint";
161177
+ }
161178
+
161057
161179
  // ../language-server/out/src/services/requirement-semantics.js
161058
161180
  var DEFAULT_SUBJECT_TYPE = "Anything";
161059
161181
  var MAX_INHERITANCE_DEPTH = 16;
@@ -161071,6 +161193,16 @@ var REQUIREMENT_SHAPED = /* @__PURE__ */ new Set([
161071
161193
  "ObjectiveDecl",
161072
161194
  "ViewpointDecl"
161073
161195
  ]);
161196
+ var CASE_SHAPED = /* @__PURE__ */ new Set([
161197
+ "CaseDecl",
161198
+ "AnalysisCaseDecl",
161199
+ "VerificationCaseDecl",
161200
+ "UseCaseDecl"
161201
+ ]);
161202
+ var SUBJECT_SHAPED = /* @__PURE__ */ new Set([
161203
+ ...REQUIREMENT_SHAPED,
161204
+ ...CASE_SHAPED
161205
+ ]);
161074
161206
  var CONSTRAINT_SHAPED = /* @__PURE__ */ new Set([
161075
161207
  "ConstraintDecl",
161076
161208
  "InvShorthand",
@@ -161178,9 +161310,10 @@ function referencePathOf(member) {
161178
161310
  return target.trim() || void 0;
161179
161311
  if (target && typeof target === "object") {
161180
161312
  const text = target.$refText?.trim();
161181
- return text || void 0;
161313
+ if (text)
161314
+ return text;
161182
161315
  }
161183
- return void 0;
161316
+ return constraintReferenceOf(member)?.path;
161184
161317
  }
161185
161318
  function referenceTargetOf(member, resolve8) {
161186
161319
  const target = member.target;
@@ -161361,7 +161494,7 @@ function inheritedSubject(node, resolve8, depth, seen) {
161361
161494
  return void 0;
161362
161495
  seen.add(node);
161363
161496
  for (const supertype of supertypesOf(node, resolve8)) {
161364
- if (!REQUIREMENT_SHAPED.has(supertype.$type))
161497
+ if (!SUBJECT_SHAPED.has(supertype.$type))
161365
161498
  continue;
161366
161499
  const own = ownSubject(supertype);
161367
161500
  if (own)
@@ -161685,7 +161818,7 @@ function memberNamed(node, name, seen = /* @__PURE__ */ new Set()) {
161685
161818
  const typeRef = node.typing?.type?.ref;
161686
161819
  return typeRef ? memberNamed(typeRef, name, seen) : void 0;
161687
161820
  }
161688
- function resolveFeatureValue(root4, segments) {
161821
+ function resolveFeatureValue(root4, segments, ext) {
161689
161822
  let cur = root4;
161690
161823
  for (const seg of segments) {
161691
161824
  cur = memberNamed(cur, seg);
@@ -161693,7 +161826,7 @@ function resolveFeatureValue(root4, segments) {
161693
161826
  return UNRESOLVED;
161694
161827
  }
161695
161828
  if (cur.value)
161696
- return evaluateExpr(cur.value, () => INCONCLUSIVE);
161829
+ return evaluateExpr(cur.value, () => INCONCLUSIVE, ext);
161697
161830
  return INCONCLUSIVE;
161698
161831
  }
161699
161832
  function subjectScope(subjectName, subjectBinding) {
@@ -161788,6 +161921,83 @@ function evaluateSatisfy(stmt, resolveRequirement, resolvePart, resolve8) {
161788
161921
  const status = result.status === "pass" ? "fail" : result.status === "fail" ? "pass" : result.status;
161789
161922
  return { status, requirement, satisfier };
161790
161923
  }
161924
+ var CONSTRAINT_SHAPED_TYPES = /* @__PURE__ */ new Set([
161925
+ "ConstraintDecl",
161926
+ "InvShorthand",
161927
+ "RequirementDecl",
161928
+ "ConcernDecl",
161929
+ "PredicateDecl",
161930
+ "AssertConstraintStmt",
161931
+ "RequireConstraintStmt",
161932
+ "AssumeConstraintStmt"
161933
+ ]);
161934
+ function exprText2(node) {
161935
+ return node?.$cstNode?.text?.trim() ?? "";
161936
+ }
161937
+ function rootOf2(node) {
161938
+ let current2 = node;
161939
+ while (current2.$container)
161940
+ current2 = current2.$container;
161941
+ return current2;
161942
+ }
161943
+ function* walkMembers(node) {
161944
+ for (const member of [...node.elements ?? [], ...node.members ?? []]) {
161945
+ yield member;
161946
+ yield* walkMembers(member);
161947
+ }
161948
+ }
161949
+ function documentConstraintResolver() {
161950
+ return (reference, member) => {
161951
+ for (const candidate of walkMembers(rootOf2(member))) {
161952
+ if (candidate.name === reference.simpleName && CONSTRAINT_SHAPED_TYPES.has(candidate.$type)) {
161953
+ return candidate;
161954
+ }
161955
+ }
161956
+ return void 0;
161957
+ };
161958
+ }
161959
+ var assertionExpression = (node) => {
161960
+ const expr = node;
161961
+ return (expr.$type === "NumericPrimary" || expr.$type === "PostfixOp") && expr.unit ? INCONCLUSIVE : void 0;
161962
+ };
161963
+ function evaluateAssertion(node, resolveConstraint = documentConstraintResolver()) {
161964
+ const member = node;
161965
+ if (member.$type !== "AssertConstraintStmt")
161966
+ return void 0;
161967
+ const reference = constraintReferenceOf(member);
161968
+ const negated = reference?.negated ?? member.isNegated === true;
161969
+ let body;
161970
+ let text;
161971
+ let target;
161972
+ if (reference) {
161973
+ text = `${reference.kind}${reference.negated ? " not" : ""} ${reference.path}`;
161974
+ target = resolveConstraint(reference, member);
161975
+ if (!target)
161976
+ return { status: "unresolved", text };
161977
+ body = member.body ?? constraintBodyOf(target, documentResolver(member));
161978
+ } else {
161979
+ body = member.body;
161980
+ text = exprText2(member.body);
161981
+ }
161982
+ if (!body)
161983
+ return { status: "inconclusive", text };
161984
+ const scope = (segments) => {
161985
+ for (const owner of [member, target]) {
161986
+ if (!owner)
161987
+ continue;
161988
+ if (memberNamed(owner, segments[0])) {
161989
+ return resolveFeatureValue(owner, segments, assertionExpression);
161990
+ }
161991
+ }
161992
+ return INCONCLUSIVE;
161993
+ };
161994
+ const value = negate2(evaluateExpr(body, scope, assertionExpression), negated);
161995
+ if (value.kind === "unresolved")
161996
+ return { status: "unresolved", text };
161997
+ if (value.kind !== "boolean")
161998
+ return { status: "inconclusive", text };
161999
+ return { status: value.value ? "pass" : "fail", text };
162000
+ }
161791
162001
  function bindingName(by) {
161792
162002
  const n2 = by;
161793
162003
  if (n2?.$type !== "PathExpr")
@@ -163036,6 +163246,21 @@ function unwrap(node) {
163036
163246
  }
163037
163247
  var namedChildrenByNode = /* @__PURE__ */ new WeakMap();
163038
163248
  var childrenByName = /* @__PURE__ */ new WeakMap();
163249
+ var REFERENCE_FORM_DECLARATIONS = {
163250
+ PerformStmt: "actionKw",
163251
+ EntryAction: "actionKw",
163252
+ DoAction: "actionKw",
163253
+ ExitAction: "actionKw",
163254
+ ExhibitStateDecl: "stateKw",
163255
+ AssertConstraintStmt: "constraintKw",
163256
+ EventDecl: "isOccurrence"
163257
+ };
163258
+ function isReferenceFormDeclaration(node) {
163259
+ const keyword = REFERENCE_FORM_DECLARATIONS[node.$type];
163260
+ if (!keyword)
163261
+ return false;
163262
+ return node[keyword] !== true;
163263
+ }
163039
163264
  function directNamedChildren(node) {
163040
163265
  const cached = namedChildrenByNode.get(node);
163041
163266
  if (cached)
@@ -163044,6 +163269,8 @@ function directNamedChildren(node) {
163044
163269
  const seen = /* @__PURE__ */ new Set();
163045
163270
  for (const raw of ast_utils_exports.streamContents(node)) {
163046
163271
  const child = unwrap(raw);
163272
+ if (isReferenceFormDeclaration(child))
163273
+ continue;
163047
163274
  if (!nameOf(child) || seen.has(child))
163048
163275
  continue;
163049
163276
  seen.add(child);
@@ -163525,7 +163752,7 @@ var FeaturePathResolver = class {
163525
163752
  }
163526
163753
  for (let owner = node.$container; owner; owner = owner.$container) {
163527
163754
  const declaredName3 = owner.name;
163528
- if (typeof declaredName3 === "string" && canonicalEscapedName(declaredName3) === name && !isSelfReference(owner, node)) {
163755
+ if (typeof declaredName3 === "string" && canonicalEscapedName(declaredName3) === name && !isReferenceFormDeclaration(owner) && !isSelfReference(owner, node)) {
163529
163756
  return this.targetForNode(owner, this.memberInventoryKnown(owner, snapshot));
163530
163757
  }
163531
163758
  if (boundVariableName(owner) === name) {
@@ -163877,6 +164104,28 @@ var FeaturePathResolver = class {
163877
164104
  }
163878
164105
  };
163879
164106
 
164107
+ // ../language-server/out/src/services/calculation-semantics.js
164108
+ function effectiveCalculationResult(node, resolve8) {
164109
+ const seen = /* @__PURE__ */ new Set();
164110
+ const walk = (current2, depth) => {
164111
+ if (depth > 32 || seen.has(current2))
164112
+ return void 0;
164113
+ seen.add(current2);
164114
+ const parameter = current2.members?.find((member) => member.$type === "ReturnDecl");
164115
+ if (parameter || current2.body)
164116
+ return {
164117
+ parameter,
164118
+ expression: parameter?.value ?? current2.body,
164119
+ inherited: current2 !== node
164120
+ };
164121
+ const parents = supertypesOf(current2, resolve8).filter((parent) => parent.$type === "CalcDecl");
164122
+ if (parents.length !== 1)
164123
+ return void 0;
164124
+ return walk(parents[0], depth + 1);
164125
+ };
164126
+ return walk(node, 0);
164127
+ }
164128
+
163880
164129
  // ../language-server/out/src/platform/platform.js
163881
164130
  var current;
163882
164131
  function setPlatform(platform) {
@@ -166341,6 +166590,16 @@ var directionOf = (node) => {
166341
166590
  return void 0;
166342
166591
  return mods.find((m) => m === "in" || m === "out" || m === "inout");
166343
166592
  };
166593
+ function parameterKeyword(node) {
166594
+ const direction = directionOf(node);
166595
+ if (!direction)
166596
+ return void 0;
166597
+ let owner = node.$container;
166598
+ while (owner?.$type === "PrefixMetadataMember" || owner?.$type === "MemberPrefixDecl") {
166599
+ owner = owner.$container;
166600
+ }
166601
+ return owner && (isConstraintDecl(owner) || isCalcDecl(owner)) ? `${direction} parameter` : void 0;
166602
+ }
166344
166603
  function keywordFor(node) {
166345
166604
  const n2 = node;
166346
166605
  if (node.$type === "VariantReference")
@@ -166402,6 +166661,9 @@ function keywordFor(node) {
166402
166661
  DoAction: "do action",
166403
166662
  ExitAction: "exit action"
166404
166663
  };
166664
+ const parameter = parameterKeyword(node);
166665
+ if (parameter)
166666
+ return parameter;
166405
166667
  if (t === "ActionDecl" && n2.inlineBody?.$type === "AcceptNode") {
166406
166668
  return "accept action";
166407
166669
  }
@@ -166434,6 +166696,7 @@ var isBareDefDecl = (node) => node.$type === "BareDefDecl";
166434
166696
  var isDefinitionNode = (node) => isDefinitionKind(node) && node.isDef === true || isBareDefDecl(node);
166435
166697
  var ACTION_FLOW_STEP_TYPES = /* @__PURE__ */ new Set([
166436
166698
  "ActionDecl",
166699
+ "CalcDecl",
166437
166700
  "PerformStmt",
166438
166701
  "AssignNode",
166439
166702
  "SendNode",
@@ -167348,8 +167611,8 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167348
167611
  case "iv":
167349
167612
  return firstContent(isPartDecl) ?? firstContent(isPackage) ?? firstThat(isPartDecl) ?? firstThat(isPackage) ?? root4;
167350
167613
  case "afv":
167351
- return firstContent((n2) => isActionDecl(n2) || this.isCaseLike(n2)) ?? firstContent(isPartDecl) ?? // REQ-196 — action flow over a part's performers
167352
- firstThat((n2) => isActionDecl(n2) || this.isCaseLike(n2)) ?? root4;
167614
+ return firstContent((n2) => isActionDecl(n2) || isCalcDecl(n2) || this.isCaseLike(n2)) ?? firstContent(isPartDecl) ?? // REQ-196 — action flow over a part's performers
167615
+ firstThat((n2) => isActionDecl(n2) || isCalcDecl(n2) || this.isCaseLike(n2)) ?? root4;
167353
167616
  case "stv":
167354
167617
  return firstContent((n2) => isExhibitStateDecl(n2) || isStateDecl(n2)) ?? firstThat((n2) => isExhibitStateDecl(n2) || isStateDecl(n2)) ?? root4;
167355
167618
  case "sv":
@@ -167399,7 +167662,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167399
167662
  case "iv":
167400
167663
  return isPartDecl(node);
167401
167664
  case "afv":
167402
- return isActionDecl(node) || isPartDecl(node) || this.isCaseLike(node);
167665
+ return isActionDecl(node) || isCalcDecl(node) || isPartDecl(node) || this.isCaseLike(node);
167403
167666
  case "stv":
167404
167667
  return isStateDecl(node) || isExhibitStateDecl(node) || isPartDecl(node);
167405
167668
  case "sv":
@@ -167422,7 +167685,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167422
167685
  // and `findAnchor` drills to them, so a view opened on the OWNER of an empty
167423
167686
  // action definition shows the same thing the package overview does.
167424
167687
  isAfvScaffoldAnchor(node) {
167425
- return isActionDecl(node) && !!nameOf2(node) && (node.isDef === true || this.isDirectPackageMember(node));
167688
+ return (isActionDecl(node) || isCalcDecl(node)) && !!nameOf2(node) && (node.isDef === true || this.isDirectPackageMember(node));
167426
167689
  }
167427
167690
  // REQ-196 — a member that is a STEP of the flow its holder runs: an action
167428
167691
  // usage, a send/accept/assign node, or a `perform`. An action DEFINITION is
@@ -167432,7 +167695,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167432
167695
  // `hasAnchorContent` and `hasAfvOverviewDescendant` both read, so what makes a
167433
167696
  // part an anchor and what makes it a scope cannot drift apart.
167434
167697
  isAfvFlowNode(member, index2) {
167435
- return !this.isSwimlaneClaim(member, index2) && (isActionDecl(member) && member.isDef !== true || ["SendNode", "AcceptNode", "AssignNode", "PerformStmt"].includes(member.$type));
167698
+ return !this.isSwimlaneClaim(member, index2) && ((isActionDecl(member) || isCalcDecl(member)) && member.isDef !== true || ["SendNode", "AcceptNode", "AssignNode", "PerformStmt"].includes(member.$type));
167436
167699
  }
167437
167700
  // REQ-196 — does this part's own subtree hold action flow anywhere? Counted
167438
167701
  // over the nested part usages of a flow-less part, this is what tells a shared
@@ -167558,20 +167821,29 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167558
167821
  * `accept` payload in on top) and the Interconnection View, where an action
167559
167822
  * drawn inside a part must expose the same pins a flow can dock on. */
167560
167823
  actionPinPorts(action, ownerId, index2, uri) {
167561
- const inheritedFrom = action.isDef === true ? void 0 : this.resolveType(action, index2);
167562
167824
  const directed = /* @__PURE__ */ new Map();
167563
- for (const member of inheritedFrom ? membersOf(inheritedFrom) : []) {
167564
- if (nameOf2(member) && directionOf(member))
167565
- directed.set(nameOf2(member), member);
167825
+ const inheritedTypes = /* @__PURE__ */ new Map();
167826
+ for (const owner of [...this.inheritedFeatureOwnersOf(action, index2)].reverse()) {
167827
+ for (const member of membersOf(owner)) {
167828
+ const targets = redefinitionTargetsOf(member).map(lastSeg);
167829
+ for (const target of targets)
167830
+ directed.delete(target);
167831
+ if (effectiveNameOf(member) && directionOf(member)) {
167832
+ directed.set(effectiveNameOf(member), member);
167833
+ inheritedTypes.set(effectiveNameOf(member), typeText(member) ?? inheritedTypes.get(targets[0] ?? effectiveNameOf(member)));
167834
+ }
167835
+ }
167566
167836
  }
167567
167837
  for (const member of membersOf(action)) {
167568
- if (nameOf2(member) && directionOf(member))
167569
- directed.set(nameOf2(member), member);
167838
+ for (const target of redefinitionTargetsOf(member))
167839
+ directed.delete(lastSeg(target));
167840
+ if (effectiveNameOf(member) && directionOf(member))
167841
+ directed.set(effectiveNameOf(member), member);
167570
167842
  }
167571
167843
  const pinOf = (member, id2, parentPort) => ({
167572
167844
  id: id2,
167573
- name: nameOf2(member),
167574
- type: typeText(member),
167845
+ name: effectiveNameOf(member),
167846
+ type: typeText(member) ?? inheritedTypes.get(lastSeg(redefinitionTargetsOf(member)[0] ?? effectiveNameOf(member))),
167575
167847
  direction: directionOf(member),
167576
167848
  conjugated: isConjugated(member) || void 0,
167577
167849
  // REQ-194/REQ-408 - see the port rule above: only a written `ref` dashes.
@@ -167584,7 +167856,8 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167584
167856
  // part does, so Properties inspects it the same way in the AFV as it
167585
167857
  // inspects a port in the IV.
167586
167858
  compartments: this.compartmentsFor(member, uri, index2, true),
167587
- source: sourceOf2(member, uri)
167859
+ source: sourceOf2(member, uri),
167860
+ meta: valueTextOf(member) !== void 0 ? { boundArgument: valueTextOf(member) } : void 0
167588
167861
  });
167589
167862
  const pins = [];
167590
167863
  const addNestedPins = (param, paramId, depth, seenTypes) => {
@@ -167610,12 +167883,38 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167610
167883
  }
167611
167884
  };
167612
167885
  for (const member of directed.values()) {
167613
- const id2 = `${ownerId}.${nameOf2(member)}`;
167886
+ const id2 = `${ownerId}.${effectiveNameOf(member)}`;
167614
167887
  pins.push(pinOf(member, id2));
167615
167888
  addNestedPins(member, id2, 1, /* @__PURE__ */ new Set());
167616
167889
  }
167890
+ if (isCalcDecl(action)) {
167891
+ const result = effectiveCalculationResult(action, (name) => index2.get(name));
167892
+ if (result) {
167893
+ const parameter = result.parameter;
167894
+ const name = parameter ? nameOf2(parameter) ?? "result" : "result";
167895
+ pins.push({
167896
+ id: `${ownerId}.${name}`,
167897
+ name,
167898
+ direction: "out",
167899
+ pin: true,
167900
+ isDef: false,
167901
+ type: parameter ? typeText(parameter) : void 0,
167902
+ source: sourceOf2(parameter ?? action, uri),
167903
+ meta: { calculationResult: true, inherited: result.inherited }
167904
+ });
167905
+ }
167906
+ }
167617
167907
  return pins;
167618
167908
  }
167909
+ // REQ-208 - Only a locally declared result expression is editable on a usage.
167910
+ calculationValue(node, index2) {
167911
+ if (!isCalcDecl(node))
167912
+ return {};
167913
+ const result = effectiveCalculationResult(node, (name) => index2.get(name));
167914
+ if (node.isDef !== true && (!result?.expression || result.inherited))
167915
+ return {};
167916
+ return { value: result?.expression?.$cstNode?.text.replace(/\s+/g, " ").trim() ?? "" };
167917
+ }
167619
167918
  /** REQ-196/198: one definition node per type used by a drawn usage.
167620
167919
  * The Defs filter controls these nodes. An existing definition tile is
167621
167920
  * reused. Typing links are omitted by user direction (2026-09-06).
@@ -167732,8 +168031,10 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167732
168031
  }
167733
168032
  return (isPackage(node) || isDocument(node)) && this.nestedUsages(node, isPartDecl).some((n2) => nameOf2(n2) !== void 0);
167734
168033
  case "afv": {
168034
+ if (isCalcDecl(node))
168035
+ return true;
167735
168036
  if (isActionDecl(node) || this.isCaseLike(node)) {
167736
- const actions = membersOf(node).map((member) => this.thenActionMemberNode(member) ?? member).filter(isActionDecl);
168037
+ const actions = membersOf(node).map((member) => this.thenActionMemberNode(member) ?? member).filter((n2) => isActionDecl(n2) || isCalcDecl(n2));
167737
168038
  if (actions.some((n2) => nameOf2(n2) !== void 0))
167738
168039
  return true;
167739
168040
  return node.inlineBody !== void 0;
@@ -167879,6 +168180,19 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167879
168180
  const all = [...ast_utils_exports.streamAllContents(scope)];
167880
168181
  const annotationNodes = all.filter(isGvAnnotationNode);
167881
168182
  const annotationNodeSet = new Set(annotationNodes);
168183
+ const declaredOwnerOf = (node) => {
168184
+ let owner = node.$container;
168185
+ while (owner?.$type === "PrefixMetadataMember" || owner?.$type === "MemberPrefixDecl") {
168186
+ owner = owner.$container;
168187
+ }
168188
+ return owner;
168189
+ };
168190
+ const isDefinitionParameter = (node) => {
168191
+ if (directionOf(node) === void 0)
168192
+ return false;
168193
+ const owner = declaredOwnerOf(node);
168194
+ return !!owner && owner.isDef === true && (isConstraintDecl(owner) || isCalcDecl(owner));
168195
+ };
167882
168196
  const usageNodes = all.filter(isGvExplicitUsage);
167883
168197
  const usageNodeSet = new Set(usageNodes);
167884
168198
  const usageDefinitions = new Map(usageNodes.map((node) => [
@@ -167917,7 +168231,20 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167917
168231
  semanticOwners.set(member, found);
167918
168232
  return found;
167919
168233
  };
168234
+ const readsAsAttribute = (node) => isAttributeDecl(node) || isAttributeDecl(this.resolveType(node, index2));
168235
+ const implicitlyRedefined = (node) => {
168236
+ const name = nameOf2(node);
168237
+ const owner = semanticOwner(node);
168238
+ if (!name || !owner || owner.isDef === true)
168239
+ return void 0;
168240
+ const definition = usageDefinitions.get(owner);
168241
+ if (!definition)
168242
+ return void 0;
168243
+ return membersOf(definition).find((member) => nameOf2(member) === name);
168244
+ };
167920
168245
  const attributeUsages = new Set(usageNodes.filter((node) => {
168246
+ if (isDefinitionParameter(node))
168247
+ return false;
167921
168248
  if (isAttributeDecl(node))
167922
168249
  return true;
167923
168250
  const owner = semanticOwner(node);
@@ -167928,12 +168255,23 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167928
168255
  const definition = usageDefinitions.get(node);
167929
168256
  if (definition && isAttributeDecl(definition))
167930
168257
  return true;
167931
- return redefinitionTargetsOf(node).some((target) => {
168258
+ if (redefinitionTargetsOf(node).some((target) => {
167932
168259
  const inherited = this.resolveFeatureInheritanceTarget(node, target, index2, /* @__PURE__ */ new Set());
167933
168260
  return inherited && isAttributeDecl(inherited);
167934
- });
168261
+ }))
168262
+ return true;
168263
+ const implicit = implicitlyRedefined(node);
168264
+ return !!implicit && readsAsAttribute(implicit);
167935
168265
  }));
167936
168266
  const attributeValue = (node) => valueTextOf(node) ?? node.default?.value?.$cstNode?.text ?? "";
168267
+ const returnMemberOf = (node) => membersOf(node).find((m) => m.$type === "ReturnDecl");
168268
+ const expressionBody = (node) => {
168269
+ const result = isCalcDecl(node) ? effectiveCalculationResult(node, (name) => index2.get(name)) : void 0;
168270
+ const text = isCalcDecl(node) ? result && !result.inherited ? result.expression?.$cstNode?.text ?? "" : "" : node.body?.$cstNode?.text ?? "";
168271
+ return text.replace(/\s+/g, " ").trim();
168272
+ };
168273
+ const declaresExpression = (node) => node.body !== void 0 || isCalcDecl(node) && valueTextOf(returnMemberOf(node)) !== void 0;
168274
+ const showsExpressionField = (node) => (isConstraintDecl(node) || isCalcDecl(node)) && (node.isDef === true || declaresExpression(node));
167937
168275
  const ids = /* @__PURE__ */ new Map();
167938
168276
  const unnamedOrdinals = /* @__PURE__ */ new Map();
167939
168277
  const semanticId = (node) => {
@@ -167989,6 +168327,8 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167989
168327
  multiplicity: this.multText(n2),
167990
168328
  type: typeText(n2) ?? (usageDefinitions.get(n2) ? nameOf2(usageDefinitions.get(n2)) : void 0),
167991
168329
  ...attributeUsages.has(n2) ? { value: attributeValue(n2) } : {},
168330
+ // REQ-208/209 — the constraint or calculation expression field.
168331
+ ...showsExpressionField(n2) ? { value: expressionBody(n2) } : {},
167992
168332
  compartments: extra?.compartments ?? this.compartmentsFor(n2, uri, index2, shape === "box"),
167993
168333
  ...packageOf2(n2),
167994
168334
  source: sourceOf2(n2, uri),
@@ -168003,9 +168343,60 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
168003
168343
  for (const usage of usageNodes) {
168004
168344
  pushNode(usage, "box", false, {
168005
168345
  compartments: this.compartmentsFor(usage, uri, index2, true, false),
168006
- ...attributeUsages.has(usage) ? { keyword: "attribute" } : {}
168346
+ // REQ-376 a parameter keeps its own banner; only an ordinary
168347
+ // attribute usage is relabelled by its value-carrying role.
168348
+ ...attributeUsages.has(usage) && !parameterKeyword(usage) ? { keyword: "attribute" } : {}
168007
168349
  });
168008
168350
  }
168351
+ for (const usage of usageNodes) {
168352
+ if (!isConstraintDecl(usage) || usage.isDef === true)
168353
+ continue;
168354
+ const definition = usageDefinitions.get(usage);
168355
+ if (!definition || !isConstraintDecl(definition))
168356
+ continue;
168357
+ const usageId = semanticId(usage);
168358
+ const local = new Set(membersOf(usage).flatMap((member) => [nameOf2(member), ...redefinitionTargetsOf(member)]).filter((name) => !!name));
168359
+ for (const member of membersOf(definition)) {
168360
+ const name = nameOf2(member);
168361
+ if (!name || local.has(name))
168362
+ continue;
168363
+ if (directionOf(member) === void 0 && !isAttributeDecl(member))
168364
+ continue;
168365
+ const id2 = `${usageId}::${name}`;
168366
+ if (nodes.some((existing) => existing.id === id2))
168367
+ continue;
168368
+ nodes.push({
168369
+ id: id2,
168370
+ name: effectiveNameOf(member) ?? name,
168371
+ keyword: "attribute",
168372
+ isDef: false,
168373
+ shape: "box",
168374
+ multiplicity: this.multText(member),
168375
+ type: typeText(member),
168376
+ value: attributeValue(member),
168377
+ compartments: [],
168378
+ parent: usageId,
168379
+ // Navigation lands on the declaration the member comes from.
168380
+ source: sourceOf2(member, uri),
168381
+ meta: {
168382
+ gvUsage: true,
168383
+ gvOwnerId: usageId,
168384
+ gvExplicit: true,
168385
+ gvDeclaredName: name,
168386
+ gvDeclaredType: typeText(member) ?? "",
168387
+ // REQ-364 — the concrete usage that owns a local edit, plus
168388
+ // the relative redefinition path to write inside it.
168389
+ localUsageId: usageId,
168390
+ localUsageName: nameOf2(usage),
168391
+ localUsageSource: sourceOf2(usage, uri),
168392
+ localUsagePath: [name],
168393
+ expandedFromDefinition: true,
168394
+ declarationId: qnameOf(member),
168395
+ declarationSource: sourceOf2(member, uri)
168396
+ }
168397
+ });
168398
+ }
168399
+ }
168009
168400
  for (const p of packageNodes) {
168010
168401
  const pn = p;
168011
168402
  pushNode(p, "package", false, {
@@ -168322,6 +168713,9 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
168322
168713
  }
168323
168714
  }
168324
168715
  }
168716
+ for (const owner of [...defNodes, ...usageNodes]) {
168717
+ this.emitConstraintGraphics(owner, semanticId(owner), membersOf(owner), nodes, edges, index2, uri, false);
168718
+ }
168325
168719
  const allocPairs = [
168326
168720
  ...all.filter((m) => m.$type === "AllocateStmt").map((a2) => ({
168327
168721
  from: String(a2.source ?? ""),
@@ -168957,6 +169351,89 @@ ${node.id}`;
168957
169351
  out.push({ title: "flows", items: rows });
168958
169352
  return out;
168959
169353
  }
169354
+ // REQ-209 - Claims preserve usage identity; references reuse their target.
169355
+ emitConstraintGraphics(owner, ownerId, members, nodes, edges, index2, uri, interconnection) {
169356
+ const kinds = {
169357
+ AssertConstraintStmt: "assert",
169358
+ AssumeConstraintStmt: "assume",
169359
+ RequireConstraintStmt: "require"
169360
+ };
169361
+ const ensureNode = (target, id2, keyword) => {
169362
+ let node = nodes.find((candidate) => candidate.id === id2);
169363
+ if (!node) {
169364
+ const body = target.body?.$cstNode?.text;
169365
+ node = {
169366
+ id: id2,
169367
+ name: effectiveNameOf(target) ?? keyword,
169368
+ keyword,
169369
+ shape: "box",
169370
+ isDef: target.isDef === true,
169371
+ type: typeText(target),
169372
+ multiplicity: this.multText(target),
169373
+ compartments: this.compartmentsFor(target, uri, index2),
169374
+ ...(isConstraintDecl(target) || isInlineConstraintClaim(target)) && (body !== void 0 || target.isDef) ? { value: (body ?? "").replace(/\s+/g, " ").trim() } : {},
169375
+ ...interconnection ? { ports: this.actionPinPorts(target, id2, index2, uri) } : {},
169376
+ source: sourceOf2(target, uri),
169377
+ ...interconnection ? {} : { parent: ownerId },
169378
+ meta: { constraintUsage: true, ...!interconnection ? { gvUsage: true } : {} }
169379
+ };
169380
+ nodes.push(node);
169381
+ }
169382
+ node.meta = { ...node.meta, constraintUsage: true };
169383
+ return node;
169384
+ };
169385
+ for (const member of members) {
169386
+ const kind = kinds[member.$type];
169387
+ if (!kind) {
169388
+ if (interconnection && isConstraintDecl(member) && !member.isDef) {
169389
+ ensureNode(member, `${ownerId}::${effectiveNameOf(member) ?? member.$cstNode?.offset}`, "constraint");
169390
+ }
169391
+ continue;
169392
+ }
169393
+ const reference = constraintReferenceOf(member);
169394
+ let target = member;
169395
+ let targetId = `${ownerId}::${effectiveNameOf(member) ?? `#${member.$type}:${members.filter((m) => m.$type === member.$type).indexOf(member) + 1}`}`;
169396
+ if (reference) {
169397
+ const resolved = this.featurePaths.resolveDeclarationPath(member);
169398
+ const localPath = reference.path === reference.simpleName || reference.path.replaceAll("::", ".") === `self.${reference.simpleName}`;
169399
+ const effective = interconnection && localPath ? members.find((candidate) => (isConstraintDecl(candidate) || isInlineConstraintClaim(candidate)) && [effectiveNameOf(candidate), ...redefinitionTargetsOf(candidate).map(lastSeg)].includes(reference.simpleName)) : void 0;
169400
+ const found = effective ?? resolved.segments.at(-1)?.target ?? membersOf(owner).find((candidate) => candidate !== member && nameOf2(candidate) === reference.path) ?? index2.get(reference.path) ?? index2.get(reference.simpleName);
169401
+ if (!found || found === member)
169402
+ continue;
169403
+ target = found;
169404
+ targetId = interconnection && members.includes(target) && effectiveNameOf(target) ? `${ownerId}::${effectiveNameOf(target)}` : qnameOf(target) || reference.path;
169405
+ }
169406
+ const negated = member.isNegated === true;
169407
+ ensureNode(target, targetId, reference ? keywordFor(target) : `${kind}${negated ? " not" : ""} constraint`);
169408
+ const id2 = `${ownerId}::__${kind}_${member.$cstNode?.offset ?? edges.length}`;
169409
+ if (!edges.some((edge) => edge.id === id2))
169410
+ edges.push({
169411
+ id: id2,
169412
+ from: ownerId,
169413
+ to: targetId,
169414
+ kind,
169415
+ label: `\xAB${kind}${negated ? " not" : ""}\xBB`,
169416
+ source: sourceOf2(member, uri),
169417
+ meta: { constraintReference: !!reference, negated }
169418
+ });
169419
+ if (!reference && !interconnection) {
169420
+ const definition = this.resolveType(member, index2);
169421
+ const definitionId = definition ? qnameOf(definition) : void 0;
169422
+ if (definitionId && nodes.some((node) => node.id === definitionId) && !edges.some((edge) => edge.kind === "definedBy" && edge.from === targetId)) {
169423
+ edges.push({
169424
+ id: `${id2}_type`,
169425
+ from: targetId,
169426
+ to: definitionId,
169427
+ kind: "definedBy",
169428
+ source: sourceOf2(member, uri)
169429
+ });
169430
+ }
169431
+ }
169432
+ }
169433
+ const drawnOwner = nodes.find((node) => node.id === ownerId);
169434
+ if (drawnOwner && interconnection)
169435
+ drawnOwner.compartments = withoutCompartments(drawnOwner.compartments, "assert constraints", "assume constraints", "require constraints");
169436
+ }
168960
169437
  // REQ-192/360/363 — the ONE recursive Interconnection View renderer. Given the
168961
169438
  // top-level `roots` to draw, it renders each part instance and nests its
168962
169439
  // internals recursively, drilling into a usage's type DEFINITION (+
@@ -169009,8 +169486,13 @@ ${node.id}`;
169009
169486
  const emptyPrefixFlow = isEmptyPrefixFlow(member);
169010
169487
  const emptyPrefixInterface = isInterfaceDecl(member) && relationship.target !== void 0 && relationship.connect === void 0;
169011
169488
  const namedRelationship = isConnectorDecl(member) || isConnectionDecl(member) || isInterfaceDecl(member) && !emptyPrefixInterface || member.$type === "BindingDecl" || member.$type === "FlowStmt" && !emptyPrefixFlow;
169012
- if (namedRelationship) {
169013
- const names = [nameOf2(member), redefinedNameOf(member)].filter((name) => name !== void 0);
169489
+ const constraint = isConstraintDecl(member) || isInlineConstraintClaim(member);
169490
+ if (namedRelationship || constraint) {
169491
+ const names = [
169492
+ nameOf2(member),
169493
+ redefinedNameOf(member),
169494
+ ...constraint ? redefinitionTargetsOf(member).map(lastSeg) : []
169495
+ ].filter((name) => name !== void 0);
169014
169496
  if (names.some((name) => claimedNames.has(name)))
169015
169497
  continue;
169016
169498
  for (const name of names)
@@ -169259,6 +169741,10 @@ ${node.id}`;
169259
169741
  const resolver = childResolver([], { usage: part, id: instanceId });
169260
169742
  this.emitInterconnectEdges(effectiveMembersOf(part), resolver.resolve, [], index2, uri, target.nodes, target.edges, eRef, instanceId, resolver.actionPinIds, resolver.structuralPortIds, part, occurrenceInherited, endpointProvenance);
169261
169743
  }
169744
+ this.emitConstraintGraphics(part, instanceId, effectiveMembersOf(part), target.nodes, target.edges, index2, uri, true);
169745
+ const claimFrame = target.frames.find((frame2) => frame2.id === instanceId);
169746
+ if (claimFrame)
169747
+ claimFrame.compartments = withoutCompartments(claimFrame.compartments, "assert constraints", "assume constraints", "require constraints");
169262
169748
  };
169263
169749
  const packageOfRoot = (root4) => enclosingPackage(root4) ?? scope;
169264
169750
  const rootBaseId = (root4) => qnameOf(root4) || nameOf2(root4) || `__root_${root4.$cstNode?.offset ?? 0}__`;
@@ -169350,8 +169836,35 @@ ${node.id}`;
169350
169836
  // single Interconnection View (called once over the anchor's whole subtree)
169351
169837
  // and the package overview (called once per container part, tagging any
169352
169838
  // synthetic n-ary dot with that container's frame id).
169353
- 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()) {
169839
+ emitInterconnectEdges(members, resolveStructuralEnd, parts, index2, uri, nodes, edges, eRef, frameId, actionPinIds = /* @__PURE__ */ new Set(), structuralPortIds = /* @__PURE__ */ new Set(), memberOwner, memberOwnerInherited = false, endpointProvenance = /* @__PURE__ */ new Map()) {
169354
169840
  const memberList2 = [...members];
169841
+ if (memberOwner && frameId)
169842
+ this.emitConstraintGraphics(memberOwner, frameId, memberList2, nodes, edges, index2, uri, true);
169843
+ const resolveEnd = (pathText) => {
169844
+ const structural = resolveStructuralEnd(pathText);
169845
+ if (structural)
169846
+ return structural;
169847
+ const path10 = pathText.replaceAll("::", ".");
169848
+ const candidates = nodes.filter((node) => node.meta?.constraintUsage === true && (!frameId || node.id.startsWith(`${frameId}::`) || edges.some((edge) => edge.from === frameId && edge.to === node.id))).flatMap((node) => (node.ports ?? []).filter((pin) => `${node.name}.${pin.name}` === path10 || pin.id.replaceAll("::", ".") === path10));
169849
+ if (candidates.length === 1)
169850
+ return candidates[0].id;
169851
+ const attribute = memberList2.find((member) => isAttributeDecl(member) && nameOf2(member) === path10);
169852
+ if (!attribute || !frameId)
169853
+ return void 0;
169854
+ const id2 = `${frameId}::${nameOf2(attribute)}`;
169855
+ if (!nodes.some((node) => node.id === id2))
169856
+ nodes.push({
169857
+ id: id2,
169858
+ name: nameOf2(attribute),
169859
+ keyword: "attribute",
169860
+ isDef: false,
169861
+ shape: "box",
169862
+ type: typeText(attribute),
169863
+ value: valueTextOf(attribute),
169864
+ source: sourceOf2(attribute, uri)
169865
+ });
169866
+ return id2;
169867
+ };
169355
169868
  const pendingFlows = [];
169356
169869
  const firstEdge = edges.length;
169357
169870
  const relationshipFields = (source) => {
@@ -169898,7 +170411,7 @@ ${node.id}`;
169898
170411
  while (cur && cur !== scope) {
169899
170412
  if (set3.has(cur)) {
169900
170413
  if (kind !== "stv" || !isPartDecl(n2)) {
169901
- if (kind === "afv" && isPartDecl(cur) && n2.isDef === true && isActionDecl(n2))
170414
+ if (kind === "afv" && isPartDecl(cur) && n2.isDef === true && (isActionDecl(n2) || isCalcDecl(n2)))
169902
170415
  break;
169903
170416
  return false;
169904
170417
  }
@@ -169952,12 +170465,12 @@ ${node.id}`;
169952
170465
  anchor: sub,
169953
170466
  diagramRoot: ctx.diagramRoot ?? ctx.anchor
169954
170467
  });
169955
- if (this.diagramElementCount(subModel) === 0 && !(kind === "afv" && isActionDecl(sub)) && !(kind === "stv" && (isStateDecl(sub) || isExhibitStateDecl(sub))))
170468
+ if (this.diagramElementCount(subModel) === 0 && !(kind === "afv" && (isActionDecl(sub) || isCalcDecl(sub))) && !(kind === "stv" && (isStateDecl(sub) || isExhibitStateDecl(sub))))
169956
170469
  continue;
169957
170470
  const frameId = `t${tile}`;
169958
170471
  const q = qnameOf(sub) || nameOf2(sub) || "";
169959
170472
  const rel2 = scopeQ && q.startsWith(`${scopeQ}::`) ? q.slice(scopeQ.length + 2) : nameOf2(sub) ?? q;
169960
- const tileMetaTag = kind === "afv" ? isPartDecl(sub) ? { afvPart: true } : isActionDecl(sub) && sub.isDef === true ? { behaviorDef: true } : void 0 : kind === "stv" && sub.isDef === true ? { behaviorDef: true } : void 0;
170473
+ const tileMetaTag = kind === "afv" ? isPartDecl(sub) ? { afvPart: true } : (isActionDecl(sub) || isCalcDecl(sub)) && sub.isDef === true ? { behaviorDef: true } : void 0 : kind === "stv" && sub.isDef === true ? { behaviorDef: true } : void 0;
169961
170474
  const tileIdentity = {
169962
170475
  declarationId: qnameOf(sub) || nameOf2(sub),
169963
170476
  declarationName: nameOf2(sub),
@@ -170178,7 +170691,7 @@ ${node.id}`;
170178
170691
  addStepAlias(alias, id2);
170179
170692
  };
170180
170693
  let anon = 0;
170181
- const anchorHostsFlow = isActionDecl(anchor) || this.isCaseLike(anchor);
170694
+ const anchorHostsFlow = isActionDecl(anchor) || isCalcDecl(anchor) || this.isCaseLike(anchor);
170182
170695
  const exprTextOf = (v) => (v?.$cstNode?.text ?? (typeof v === "string" ? v : "")).replace(/\s+/g, " ").trim();
170183
170696
  const performPathOf = (m) => [nameOf2(m), ...m.chainSegs ?? []].filter((segment) => !!segment);
170184
170697
  const performLabel = (m) => performPathOf(m).at(-1) ?? typeText(m) ?? "perform";
@@ -170187,6 +170700,9 @@ ${node.id}`;
170187
170700
  const flowNodeInfo = (m) => {
170188
170701
  const mm = m;
170189
170702
  switch (m.$type) {
170703
+ // REQ-208 - Calculations share action occurrence docking.
170704
+ case "CalcDecl":
170705
+ return { shape: "action", label: nameOf2(m) ?? "calc" };
170190
170706
  case "ActionDecl": {
170191
170707
  if (!nameOf2(m))
170192
170708
  return void 0;
@@ -170421,7 +170937,7 @@ ${node.id}`;
170421
170937
  pinByPath.set(alias, null);
170422
170938
  };
170423
170939
  const actionPinsOf = (action, ownerId) => {
170424
- if (!isActionDecl(action) && action.$type !== "PerformStmt")
170940
+ if (!isActionDecl(action) && !isCalcDecl(action) && action.$type !== "PerformStmt")
170425
170941
  return [];
170426
170942
  const pins = this.actionPinPorts(action, ownerId, index2, uri);
170427
170943
  const inline = action.inlineBody;
@@ -170606,7 +171122,7 @@ ${node.id}`;
170606
171122
  frameOfNode.set(holder, frameId);
170607
171123
  const framePorts = isPartDecl(holder) ? [...framePins, ...this.portsOf(holder, index2, uri, frameId).ports.filter((port) => !framePins.some((pin) => pin.name === port.name)).map((port) => ({ ...port, meta: { ...port.meta, afvPartPort: true } }))] : framePins;
170608
171124
  registerPins(holder, frameId, framePins, isAnchor);
170609
- const frameCompartments = isActionDecl(holder) ? actionFeatureCompartments(holder) : withoutCompartments(this.compartmentsFor(holder, uri, index2), ...graphicalAfvTitles);
171125
+ const frameCompartments = isActionDecl(holder) || isCalcDecl(holder) ? actionFeatureCompartments(holder) : withoutCompartments(this.compartmentsFor(holder, uri, index2), ...graphicalAfvTitles);
170610
171126
  frames.push({
170611
171127
  id: frameId,
170612
171128
  label: nameOf2(holder) ?? lastSeg(frameId),
@@ -170615,6 +171131,7 @@ ${node.id}`;
170615
171131
  isDef: holder.isDef === true,
170616
171132
  type: typeText(holder),
170617
171133
  multiplicity: this.multText(holder),
171134
+ ...this.calculationValue(holder, index2),
170618
171135
  compartments: frameCompartments?.length ? frameCompartments : void 0,
170619
171136
  ports: framePorts,
170620
171137
  source: sourceOf2(holder, uri),
@@ -170651,7 +171168,7 @@ ${node.id}`;
170651
171168
  this.featurePath(namedSendNode.via) ? `via ${this.featurePath(namedSendNode.via)}` : void 0,
170652
171169
  this.featurePath(namedSendNode.sendTarget) ? `to ${this.featurePath(namedSendNode.sendTarget)}` : void 0
170653
171170
  ].filter((value) => !!value).join(" ") : void 0;
170654
- const featureCompartments = m.$type === "ActionDecl" || m.$type === "PerformStmt" ? actionFeatureCompartments(m) : [];
171171
+ const featureCompartments = isCalcDecl(m) || m.$type === "ActionDecl" || m.$type === "PerformStmt" ? actionFeatureCompartments(m) : [];
170655
171172
  const detailCompartment = acceptTrigger || sendDetail ? [{
170656
171173
  title: acceptTrigger ? "accepts" : "sends",
170657
171174
  items: [{ text: acceptTrigger ?? sendDetail, source: sourceOf2(inlineAccept ?? m, uri) }]
@@ -170664,6 +171181,8 @@ ${node.id}`;
170664
171181
  keyword: info.keyword ?? keywordFor(m),
170665
171182
  isDef: m.isDef === true,
170666
171183
  shape: info.shape,
171184
+ ...isCalcDecl(m) ? { type: typeText(m), multiplicity: this.multText(m) } : {},
171185
+ ...this.calculationValue(m, index2),
170667
171186
  ports: pins,
170668
171187
  compartments: compartments.length ? compartments : void 0,
170669
171188
  frame: frameId,
@@ -170765,14 +171284,14 @@ ${node.id}`;
170765
171284
  }) || inline?.$type === "AssignNode" || definitionFlowMembersOf(node).length > 0;
170766
171285
  };
170767
171286
  const contentSourceOf = (node) => {
170768
- if (node.$type === "ActionDecl")
171287
+ if (isActionDecl(node) || isCalcDecl(node))
170769
171288
  return ownsFlow(node) ? node : void 0;
170770
171289
  if (node.$type !== "PerformStmt")
170771
171290
  return void 0;
170772
171291
  if (ownsFlow(node))
170773
171292
  return node;
170774
171293
  const target = performTarget(node);
170775
- return target && isActionDecl(target) && ownsFlow(target) ? target : void 0;
171294
+ return target && (isActionDecl(target) || isCalcDecl(target)) && ownsFlow(target) ? target : void 0;
170776
171295
  };
170777
171296
  const isCompositeAction = (node) => contentSourceOf(node) !== void 0;
170778
171297
  const openFrames = /* @__PURE__ */ new Set();
@@ -170807,6 +171326,7 @@ ${node.id}`;
170807
171326
  isDef: action.isDef === true,
170808
171327
  type: typeText(action),
170809
171328
  multiplicity: this.multText(action),
171329
+ ...this.calculationValue(action, index2),
170810
171330
  compartments: actionCompartments.length ? actionCompartments : void 0,
170811
171331
  ports: pins,
170812
171332
  source: sourceOf2(action, uri),
@@ -172388,7 +172908,12 @@ ${node.id}`;
172388
172908
  idOf.set(n2, id2);
172389
172909
  nodes.push({
172390
172910
  id: id2,
172391
- name: nameOf2(n2) ?? lastSeg(typeText(n2) ?? "subject"),
172911
+ // REQ-404 — a redeclaration (`actor :>> driver = …`) writes no name
172912
+ // of its own; the name it is KNOWN BY is the one it redefines, which
172913
+ // is the same derivation the rest of the model is labelled by. The
172914
+ // last-resort fallback is the SHAPE, never the literal 'subject':
172915
+ // that string labelled every unnamed actor "subject" on the card.
172916
+ name: effectiveNameOf(n2) ?? lastSeg(typeText(n2) ?? shape),
172392
172917
  keyword: keywordFor(n2),
172393
172918
  isDef: n2.isDef === true,
172394
172919
  shape,
@@ -172432,14 +172957,15 @@ ${node.id}`;
172432
172957
  const declarationKey = (subject) => {
172433
172958
  const type = this.resolveType(subject, index2);
172434
172959
  const typeKey = (type ? qnameOf(type) : void 0) || typeText(subject) || "";
172435
- const name = nameOf2(subject) ?? "";
172960
+ const name = effectiveNameOf(subject) ?? "";
172436
172961
  return name || typeKey ? `subject:${name}|${typeKey}` : "";
172437
172962
  };
172438
172963
  const declarationText = (subject) => {
172439
172964
  const value = subjectValuePath(subject);
172440
172965
  const type = typeText(subject);
172441
- return [nameOf2(subject), type ? `: ${type}` : void 0, value ? `= ${value}` : void 0].filter((part) => !!part).join(" ");
172966
+ return [effectiveNameOf(subject), type ? `: ${type}` : void 0, value ? `= ${value}` : void 0].filter((part) => !!part).join(" ");
172442
172967
  };
172968
+ const boundKeysOfDeclaration = /* @__PURE__ */ new Map();
172443
172969
  const subjectKey = (subject, seen = /* @__PURE__ */ new Set()) => {
172444
172970
  const canonical = canonicalSubjectTarget(subject);
172445
172971
  if (canonical && isSubjectDecl(canonical) && canonical !== subject && !seen.has(canonical)) {
@@ -172448,7 +172974,14 @@ ${node.id}`;
172448
172974
  }
172449
172975
  const canonicalQName = canonical && !isSubjectDecl(canonical) ? qnameOf(canonical) : "";
172450
172976
  const value = subjectValuePath(subject);
172451
- return canonicalQName ? `target:${canonicalQName}` : value ? `value:${value}` : declarationKey(subject) || `decl:${qnameOf(subject) || `${subject.$cstNode?.offset ?? 0}:subject`}`;
172977
+ if (canonicalQName)
172978
+ return `target:${canonicalQName}`;
172979
+ if (value)
172980
+ return `value:${value}`;
172981
+ const adopted = boundKeysOfDeclaration.get(subject);
172982
+ if (adopted?.size === 1)
172983
+ return [...adopted][0];
172984
+ return declarationKey(subject) || `decl:${qnameOf(subject) || `${subject.$cstNode?.offset ?? 0}:subject`}`;
172452
172985
  };
172453
172986
  const subjectIdByKey = /* @__PURE__ */ new Map();
172454
172987
  const subjectOfCase = /* @__PURE__ */ new Map();
@@ -172459,7 +172992,7 @@ ${node.id}`;
172459
172992
  const key2 = subjectKey(subject);
172460
172993
  let sid = subjectIdByKey.get(key2);
172461
172994
  if (!sid) {
172462
- const label = nameOf2(identity6) ?? lastSeg(value || typeText(identity6) || "subject");
172995
+ const label = effectiveNameOf(identity6) ?? lastSeg(value || typeText(identity6) || "subject");
172463
172996
  add(identity6, "subject", {
172464
172997
  id: `${scopeId}::__cv_subject__::${key2}`,
172465
172998
  name: label,
@@ -172471,6 +173004,26 @@ ${node.id}`;
172471
173004
  idOf.set(subject, sid);
172472
173005
  return sid;
172473
173006
  };
173007
+ for (const c of displayedCases) {
173008
+ const declared = declaredMembers(c).filter(isSubjectDecl);
173009
+ for (const bound of declared) {
173010
+ if (!subjectValuePath(bound))
173011
+ continue;
173012
+ const name = effectiveNameOf(bound);
173013
+ if (!name)
173014
+ continue;
173015
+ for (const target of declared) {
173016
+ if (target === bound || subjectValuePath(target))
173017
+ continue;
173018
+ if (effectiveNameOf(target) !== name)
173019
+ continue;
173020
+ let keys3 = boundKeysOfDeclaration.get(target);
173021
+ if (!keys3)
173022
+ boundKeysOfDeclaration.set(target, keys3 = /* @__PURE__ */ new Set());
173023
+ keys3.add(subjectKey(bound));
173024
+ }
173025
+ }
173026
+ }
172474
173027
  const denotesSubject = (s) => !!(nameOf2(s) || typeText(s) || subjectValuePath(s));
172475
173028
  for (const c of displayedCases) {
172476
173029
  const declared = declaredMembers(c).filter(isSubjectDecl);
@@ -172513,16 +173066,47 @@ ${node.id}`;
172513
173066
  };
172514
173067
  const actorOfCase = [];
172515
173068
  const actorCasePairs = /* @__PURE__ */ new Set();
172516
- const anonymousActorId = (actor) => nameOf2(actor) ? void 0 : `${scopeId}::__cv_actor__::${qnameOf(actor)}:${actor.$cstNode?.offset ?? 0}`;
173069
+ const actorTypeKey = (actor) => {
173070
+ const type = this.resolveType(actor, index2);
173071
+ return (type ? qnameOf(type) : void 0) || typeText(actor) || "";
173072
+ };
173073
+ const actorTypeSource = (actor, siblings) => {
173074
+ if (actorTypeKey(actor))
173075
+ return actor;
173076
+ const name = effectiveNameOf(actor);
173077
+ if (!name)
173078
+ return void 0;
173079
+ return siblings.find((sibling) => sibling !== actor && effectiveNameOf(sibling) === name && !!actorTypeKey(sibling));
173080
+ };
173081
+ const actorDeclarationKey = (actor, siblings) => {
173082
+ const name = effectiveNameOf(actor) ?? "";
173083
+ const typeKey = actorTypeKey(actorTypeSource(actor, siblings) ?? actor);
173084
+ return name || typeKey ? `actor:${name}|${typeKey}` : "";
173085
+ };
173086
+ const actorKey = (actor, siblings) => actorDeclarationKey(actor, siblings) || `decl:${qnameOf(actor) || ""}:${actor.$cstNode?.offset ?? 0}`;
173087
+ const actorIdByKey = /* @__PURE__ */ new Map();
173088
+ const addActor = (actor, siblings) => {
173089
+ const canonical = actorCanonical(actor);
173090
+ const key2 = actorKey(canonical, siblings);
173091
+ let aid = actorIdByKey.get(key2);
173092
+ if (aid === void 0) {
173093
+ const typeSource = actorTypeSource(canonical, siblings);
173094
+ add(canonical, "actor", {
173095
+ id: `${scopeId}::__cv_actor__::${key2}`,
173096
+ ...typeSource && typeSource !== canonical ? { type: typeText(typeSource) } : {},
173097
+ meta: { cvAuxiliary: true }
173098
+ });
173099
+ aid = idOf.get(canonical);
173100
+ actorIdByKey.set(key2, aid);
173101
+ }
173102
+ idOf.set(actor, aid);
173103
+ return aid;
173104
+ };
172517
173105
  for (const c of displayedCases) {
172518
- for (const a2 of declaredMembers(c)) {
172519
- if (!isActorDecl(a2))
172520
- continue;
172521
- const canonical = actorCanonical(a2);
172522
- if (!idOf.has(canonical))
172523
- add(canonical, "actor", { id: anonymousActorId(canonical), meta: { cvAuxiliary: true } });
172524
- const actorId = idOf.get(canonical);
172525
- idOf.set(a2, actorId);
173106
+ const siblings = declaredMembers(c).filter(isActorDecl);
173107
+ const typeSources = siblings.some((a2) => !actorTypeKey(a2)) ? [...siblings, ...this.inheritedTypesOf(c, index2).flatMap((t) => membersOf(t).filter(isActorDecl))] : siblings;
173108
+ for (const a2 of siblings) {
173109
+ const actorId = addActor(a2, typeSources);
172526
173110
  const pair = `${actorId}\0${qnameOf(c) ?? nameOf2(c) ?? ""}`;
172527
173111
  if (!actorCasePairs.has(pair)) {
172528
173112
  actorCasePairs.add(pair);
@@ -174271,7 +174855,7 @@ ${node.id}`;
174271
174855
  const inherited = includeInherited ? this.inheritedItems(node, index2, uri) : [];
174272
174856
  const inheritedRows = (predicate, text = (member) => this.featureText(member)) => inherited.filter(({ member }) => predicate(member)).map(({ member, source }) => ({ text: `^${text(member)}`, source }));
174273
174857
  const usages = (guard) => members.filter((m) => guard(m) && m.isDef !== true && nameOf2(m) && isOrdinaryMember(m));
174274
- const exprText3 = (m) => (m.body?.$cstNode?.text ?? "").replace(/\s+/g, " ").trim();
174858
+ const exprText4 = (m) => (m.body?.$cstNode?.text ?? "").replace(/\s+/g, " ").trim();
174275
174859
  const statementText = (m) => (m.$cstNode?.text ?? this.featureText(m)).replace(/\s+/g, " ").replace(/;$/, "").trim();
174276
174860
  const canonicalFeatureText = (m) => m.$type === "FeatureShorthand" || m.$type === "FeatureRedefinitionShorthand" ? statementText(m) : this.featureText(m);
174277
174861
  const out = [];
@@ -174323,8 +174907,8 @@ ${node.id}`;
174323
174907
  add("occurrences", members.map((m) => this.thenActionMemberNode(m) ?? m).filter(isNonVariantMember).filter((m) => isEventDecl(m) && m.isOccurrence === true && nameOf2(m)).map((m) => item(m)));
174324
174908
  add("calcs", undirected(isCalcDecl).map((m) => item(m)));
174325
174909
  add("constraints", undirected(isConstraintDecl).map((m) => item(m)));
174326
- add("assume constraints", members.filter((m) => m.$type === "AssumeConstraintStmt").map((m) => item(m, exprText3(m) || "assume constraint")));
174327
- add("require constraints", members.filter((m) => m.$type === "RequireConstraintStmt").map((m) => item(m, exprText3(m) || `require ${this.featurePath(m.target) ?? ""}`.trim())));
174910
+ add("assume constraints", members.filter((m) => m.$type === "AssumeConstraintStmt").map((m) => item(m, exprText4(m) || "assume constraint")));
174911
+ add("require constraints", members.filter((m) => m.$type === "RequireConstraintStmt").map((m) => item(m, exprText4(m) || `require ${this.featurePath(m.target) ?? ""}`.trim())));
174328
174912
  add("actors", members.filter(isActorDecl).filter(isNonVariantMember).map((m) => item(m)));
174329
174913
  add("stakeholders", members.filter(isStakeholderDecl).filter(isNonVariantMember).map((m) => item(m)));
174330
174914
  add("frames", members.filter((m) => m.$type === "FrameMember").map((m) => item(m, this.refText(m.target) ?? "concern")));
@@ -174332,7 +174916,7 @@ ${node.id}`;
174332
174916
  add("objective", members.filter(isObjectiveDecl).filter(isNonVariantMember).map((m) => item(m, nameOf2(m) ?? "objective")));
174333
174917
  add("verifies", members.filter((m) => m.$type === "VerifyStmt").map((m) => item(m, String(m.target ?? ""))));
174334
174918
  add("verification methods", members.filter((m) => isMetadataDecl(m) && (typeText(m) ?? "").includes("VerificationMethod")).map((m) => item(m, typeText(m) ?? "method")));
174335
- const behavioralParameterOwner = isActionDecl(node) || isCalcDecl(node) || isConstraintDecl(node) || isCaseDecl(node) || isAnalysisCaseDecl(node) || isVerificationCaseDecl(node) || isUseCaseDecl(node);
174919
+ const behavioralParameterOwner = ["AssertConstraintStmt", "AssumeConstraintStmt", "RequireConstraintStmt"].includes(node.$type) || isActionDecl(node) || isCalcDecl(node) || isConstraintDecl(node) || isCaseDecl(node) || isAnalysisCaseDecl(node) || isVerificationCaseDecl(node) || isUseCaseDecl(node);
174336
174920
  const enclosingBehavioralParameterOwner = (() => {
174337
174921
  if (isPartDecl(node) || isPortDecl(node) || directionOf(node) === void 0)
174338
174922
  return false;
@@ -174351,9 +174935,17 @@ ${node.id}`;
174351
174935
  ...members.filter((m) => directionOf(m) !== void 0 && nameOf2(m)).filter((m) => !isVariantMember(m) && !isVariantConfigMember(m)).map((m) => item(m, canonicalFeatureText(m))),
174352
174936
  ...inheritedRows((member) => directionOf(member) !== void 0 && isNonVariantMember(member))
174353
174937
  ]);
174354
- add("result", members.filter((m) => m.$type === "ReturnDecl").map((m) => item(m, `return${nameOf2(m) ? ` ${nameOf2(m)}` : ""}${typeText(m) ? ` : ${typeText(m)}` : ""}`)));
174355
- if (isConstraintDecl(node))
174356
- add("expression", exprText3(node) ? [{ text: exprText3(node), source: sourceOf2(node, uri) }] : []);
174938
+ const calculationResult = isCalcDecl(node) ? effectiveCalculationResult(node, (name) => index2?.get(name)) : void 0;
174939
+ const results = calculationResult?.parameter ? [calculationResult.parameter] : members.filter((m) => m.$type === "ReturnDecl");
174940
+ add("result", results.map((m) => item(m, `${calculationResult?.inherited ? "^" : ""}return${nameOf2(m) ? ` ${nameOf2(m)}` : ""}${typeText(m) ? ` : ${typeText(m)}` : ""}${valueTextOf(m) ? ` = ${valueTextOf(m)}` : ""}`)));
174941
+ if (calculationResult?.expression)
174942
+ add("expression", [{
174943
+ text: calculationResult.expression.$cstNode?.text ?? "",
174944
+ source: sourceOf2(calculationResult.expression, uri)
174945
+ }]);
174946
+ if (isConstraintDecl(node) || ["AssertConstraintStmt", "AssumeConstraintStmt", "RequireConstraintStmt"].includes(node.$type)) {
174947
+ add("expression", exprText4(node) ? [{ text: exprText4(node), source: sourceOf2(node, uri) }] : []);
174948
+ }
174357
174949
  const enumValueMembers = isEnumDecl(node) ? members.filter(isOwnedEnumerationValue) : members.filter((m) => isNonVariantMember(m) && m.$type === "EnumValueDecl" && !m.typing);
174358
174950
  add("enums", enumValueMembers.map((m) => {
174359
174951
  const nm = nameOf2(m);
@@ -174382,11 +174974,11 @@ ${node.id}`;
174382
174974
  add("state transition", members.filter((m) => m.$type === "TransitionDecl").map((m) => item(m, `${m.from ?? ""} \u2192 ${m.to ?? ""}`)));
174383
174975
  const successionText = (m) => (m.$cstNode?.text ?? "").replace(/\s+/g, " ").replace(/;$/, "").trim();
174384
174976
  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));
174385
- add("assert constraints", members.filter((m) => m.$type === "AssertConstraintStmt").map((m) => item(m, exprText3(m) || nameOf2(m) || "assert constraint")));
174977
+ add("assert constraints", members.filter((m) => m.$type === "AssertConstraintStmt").map((m) => item(m, exprText4(m) || nameOf2(m) || "assert constraint")));
174386
174978
  add("invariants", members.filter((m) => m.$type === "InvShorthand").map((m) => {
174387
174979
  const inv = m;
174388
174980
  const head2 = `inv${inv.isNegated ? " false" : ""}${nameOf2(m) ? ` ${nameOf2(m)}` : ""}`;
174389
- const expr = exprText3(m);
174981
+ const expr = exprText4(m);
174390
174982
  return item(m, `${head2} { ${expr} }`.replace(/\s+/g, " ").trim());
174391
174983
  }));
174392
174984
  add("actions", usages(isActionDecl).map((m) => item(m)));
@@ -174643,8 +175235,12 @@ function projectGvCompartments(input) {
174643
175235
  continue;
174644
175236
  visible.add(node.id);
174645
175237
  const key2 = gvElementKey(node);
174646
- const open = gvElementIsExpanded(node, expanded2);
174647
- expandable.add(key2);
175238
+ const children2 = (index2.children.get(node.id) ?? []).filter(
175239
+ (child) => child.meta?.gvDerived !== true && child.meta?.connectionDefinitionHub !== true
175240
+ );
175241
+ const canExpand = children2.length > 0;
175242
+ const open = canExpand && gvElementIsExpanded(node, expanded2);
175243
+ if (canExpand) expandable.add(key2);
174648
175244
  nodes.push({
174649
175245
  ...node,
174650
175246
  parent,
@@ -174663,7 +175259,7 @@ function projectGvCompartments(input) {
174663
175259
  ...node.meta,
174664
175260
  gvMode: "group",
174665
175261
  gvExpansionKey: key2,
174666
- gvCanExpand: true,
175262
+ gvCanExpand: canExpand,
174667
175263
  gvExpanded: open,
174668
175264
  gvOpenContainer: open,
174669
175265
  internalsHidden: !open,
@@ -174671,7 +175267,7 @@ function projectGvCompartments(input) {
174671
175267
  }
174672
175268
  });
174673
175269
  if (open) {
174674
- for (const child of index2.children.get(node.id) ?? []) {
175270
+ for (const child of children2) {
174675
175271
  queue.push({ node: child, parent: node.id });
174676
175272
  }
174677
175273
  }
@@ -174707,17 +175303,17 @@ function projectGvTree(input) {
174707
175303
  visible.add(node.id);
174708
175304
  const isPackage2 = node.shape === "package";
174709
175305
  const children2 = (index2.children.get(node.id) ?? []).filter(
174710
- (child) => isPackage2 || isGvPartUsage(child)
175306
+ (child) => child.meta?.gvTreeExcluded !== true && !isDerivedHub(child) && (isPackage2 || isGvPartUsage(child) || child.meta?.constraintUsage === true)
174711
175307
  );
174712
175308
  const key2 = gvElementKey(node);
174713
- const canExpand = isPackage2 || children2.length > 0 || /\bpart\b/.test(node.keyword);
175309
+ const canExpand = children2.length > 0;
174714
175310
  const open = canExpand && gvElementIsExpanded(node, expanded2, true);
174715
175311
  if (canExpand) expandable.add(key2);
174716
175312
  nodes.push({
174717
175313
  ...node,
174718
175314
  // Tree states membership with a line. It does not borrow canvas containment.
174719
175315
  parent: void 0,
174720
- compartments: (isPackage2 && open ? void 0 : gvPackageMemberCompartments(node, index2))?.filter((compartment) => !open || !isPackage2 && compartment.title !== "parts").map((compartment) => ({ ...compartment, expandable: false, expanded: false })),
175316
+ compartments: (isPackage2 && open ? void 0 : gvPackageMemberCompartments(node, index2))?.filter((compartment) => !open || !isPackage2 && !["parts", "assert constraints", "assume constraints", "require constraints"].includes(compartment.title)).map((compartment) => ({ ...compartment, expandable: false, expanded: false })),
174721
175317
  meta: {
174722
175318
  ...node.meta,
174723
175319
  gvMode: "tree",
@@ -175761,6 +176357,283 @@ function resolveEffectiveSubject(node) {
175761
176357
  return void 0;
175762
176358
  }
175763
176359
 
176360
+ // ../language-server/out/src/services/case-semantics.js
176361
+ var CASE_KIND_BY_TYPE = /* @__PURE__ */ new Map([
176362
+ ["CaseDecl", "case"],
176363
+ ["AnalysisCaseDecl", "analysis"],
176364
+ ["VerificationCaseDecl", "verification"],
176365
+ ["UseCaseDecl", "use-case"]
176366
+ ]);
176367
+ var MAX_INHERITANCE_DEPTH2 = 16;
176368
+ function caseKindOf(node) {
176369
+ return node ? CASE_KIND_BY_TYPE.get(node.$type) : void 0;
176370
+ }
176371
+ function enclosingCase(node) {
176372
+ let current2 = node;
176373
+ while (current2) {
176374
+ if (CASE_SHAPED.has(current2.$type))
176375
+ return current2;
176376
+ current2 = current2.$container;
176377
+ }
176378
+ return void 0;
176379
+ }
176380
+ function writtenTypes(node, resolve8) {
176381
+ const out = [];
176382
+ for (const typing of [node.typing, ...node.moreTypings ?? []]) {
176383
+ if (!typing)
176384
+ continue;
176385
+ for (const ref of [typing.type, ...typing.moreTypes ?? []]) {
176386
+ if (!ref)
176387
+ continue;
176388
+ const name = ref.$refText?.trim() ?? ref.ref?.name;
176389
+ if (!name)
176390
+ continue;
176391
+ out.push({ name, node: ref.ref ?? resolve8(name) });
176392
+ }
176393
+ }
176394
+ return out;
176395
+ }
176396
+ function effectiveCaseDefinition(node, resolve8) {
176397
+ const kind = caseKindOf(node);
176398
+ if (!kind)
176399
+ return void 0;
176400
+ const decl = node;
176401
+ const resolver = resolve8 ?? documentResolver(node);
176402
+ const definitions = writtenTypes(decl, resolver).filter((type) => type.node === void 0 || CASE_SHAPED.has(type.node.$type));
176403
+ return {
176404
+ kind,
176405
+ isDefinition: decl.isDef === true,
176406
+ definitions,
176407
+ sole: definitions.length === 1 ? definitions[0] : void 0
176408
+ };
176409
+ }
176410
+ function hasAmbiguousDefinition(node, resolve8) {
176411
+ const effective = effectiveCaseDefinition(node, resolve8);
176412
+ if (!effective || effective.isDefinition)
176413
+ return false;
176414
+ return effective.definitions.filter((type) => type.node !== void 0).length > 1;
176415
+ }
176416
+ function isDecidedSubject(subject) {
176417
+ if (!subject)
176418
+ return false;
176419
+ return subject.origin !== "default" && subject.origin !== "ambiguous" && subject.typeName !== DEFAULT_SUBJECT_TYPE;
176420
+ }
176421
+ function effectiveCaseSubject(node, resolve8) {
176422
+ const resolver = resolve8 ?? documentResolver(node);
176423
+ if (hasAmbiguousDefinition(node, resolver)) {
176424
+ const own = ownSubject(node);
176425
+ return own ? subjectInfo(own, node, "own") : { typeName: DEFAULT_SUBJECT_TYPE, origin: "ambiguous" };
176426
+ }
176427
+ return effectiveSubject(node, resolver);
176428
+ }
176429
+ function ownActors(node) {
176430
+ return (node.members ?? []).filter((member) => member.$type === "ActorDecl");
176431
+ }
176432
+ function effectiveActors(node, resolve8) {
176433
+ const resolver = resolve8 ?? documentResolver(node);
176434
+ const ambiguous = hasAmbiguousDefinition(node, resolver);
176435
+ const out = [];
176436
+ const seenNodes = /* @__PURE__ */ new Set();
176437
+ const seenNames = /* @__PURE__ */ new Set();
176438
+ const walk = (current2, origin, depth) => {
176439
+ if (depth > MAX_INHERITANCE_DEPTH2 || seenNodes.has(current2))
176440
+ return;
176441
+ seenNodes.add(current2);
176442
+ for (const actor of ownActors(current2)) {
176443
+ if (actor.name && seenNames.has(actor.name))
176444
+ continue;
176445
+ if (actor.name)
176446
+ seenNames.add(actor.name);
176447
+ out.push({
176448
+ declaration: actor,
176449
+ name: actor.name,
176450
+ typeName: subjectTypeName(actor),
176451
+ origin,
176452
+ owner: current2
176453
+ });
176454
+ }
176455
+ if (ambiguous)
176456
+ return;
176457
+ for (const supertype of supertypesOf(current2, resolver)) {
176458
+ if (!CASE_SHAPED.has(supertype.$type))
176459
+ continue;
176460
+ walk(supertype, "inherited", depth + 1);
176461
+ }
176462
+ };
176463
+ walk(node, "own", 0);
176464
+ return out;
176465
+ }
176466
+ function caseResult(node, resolve8) {
176467
+ const resolver = resolve8 ?? documentResolver(node);
176468
+ const ambiguous = hasAmbiguousDefinition(node, resolver);
176469
+ const seen = /* @__PURE__ */ new Set();
176470
+ const walk = (current2, origin, depth) => {
176471
+ if (depth > MAX_INHERITANCE_DEPTH2 || seen.has(current2))
176472
+ return void 0;
176473
+ seen.add(current2);
176474
+ const own = (current2.members ?? []).find((member) => member.$type === "ReturnDecl");
176475
+ if (own) {
176476
+ return {
176477
+ declaration: own,
176478
+ name: own.name,
176479
+ typeName: subjectTypeName(own),
176480
+ origin,
176481
+ owner: current2
176482
+ };
176483
+ }
176484
+ if (ambiguous)
176485
+ return void 0;
176486
+ for (const supertype of supertypesOf(current2, resolver)) {
176487
+ if (!CASE_SHAPED.has(supertype.$type))
176488
+ continue;
176489
+ const inherited = walk(supertype, "inherited", depth + 1);
176490
+ if (inherited)
176491
+ return inherited;
176492
+ }
176493
+ return void 0;
176494
+ };
176495
+ return walk(node, "own", 0);
176496
+ }
176497
+ function objectiveBindingOf(objective, resolve8) {
176498
+ if (objective.$type !== "ObjectiveDecl")
176499
+ return void 0;
176500
+ const caseNode = enclosingCase(objective.$container);
176501
+ const caseKind = caseKindOf(caseNode);
176502
+ if (!caseNode || !caseKind)
176503
+ return void 0;
176504
+ const resolver = resolve8 ?? documentResolver(objective);
176505
+ const own = ownSubject(objective);
176506
+ const bindsSubject = caseKind === "verification" || caseKind === "use-case";
176507
+ if (bindsSubject) {
176508
+ const subject = effectiveCaseSubject(caseNode, resolver);
176509
+ return {
176510
+ objective,
176511
+ caseNode,
176512
+ caseKind,
176513
+ target: "case-subject",
176514
+ strength: "bind",
176515
+ boundTo: subject.declaration,
176516
+ // An undecided subject names no type: the case still binds its
176517
+ // objective to whatever its subject is, but neither hover nor
176518
+ // `SSM046` may say what that is.
176519
+ typeName: isDecidedSubject(subject) ? subject.typeName : void 0,
176520
+ own
176521
+ };
176522
+ }
176523
+ const result = caseResult(caseNode, resolver);
176524
+ return {
176525
+ objective,
176526
+ caseNode,
176527
+ caseKind,
176528
+ target: "case-result",
176529
+ strength: "default",
176530
+ boundTo: result?.declaration,
176531
+ typeName: result?.typeName,
176532
+ own
176533
+ };
176534
+ }
176535
+ function effectiveObjectiveSubject(objective, resolve8) {
176536
+ const resolver = resolve8 ?? documentResolver(objective);
176537
+ const binding = objectiveBindingOf(objective, resolver);
176538
+ const own = ownSubject(objective);
176539
+ if (!binding) {
176540
+ return own ? { declaration: own, name: own.name, typeName: subjectTypeName(own) ?? DEFAULT_SUBJECT_TYPE, origin: "own", owner: objective } : { typeName: DEFAULT_SUBJECT_TYPE, origin: "default" };
176541
+ }
176542
+ if (own && binding.strength === "default") {
176543
+ return {
176544
+ declaration: own,
176545
+ name: own.name,
176546
+ typeName: subjectTypeName(own) ?? DEFAULT_SUBJECT_TYPE,
176547
+ origin: "own",
176548
+ owner: objective
176549
+ };
176550
+ }
176551
+ return {
176552
+ declaration: binding.boundTo,
176553
+ typeName: binding.typeName ?? DEFAULT_SUBJECT_TYPE,
176554
+ origin: "enclosing",
176555
+ owner: binding.caseNode
176556
+ };
176557
+ }
176558
+ function objectiveSubrequirements(objective, resolve8) {
176559
+ if (objective.$type !== "ObjectiveDecl")
176560
+ return [];
176561
+ const resolver = resolve8 ?? documentResolver(objective);
176562
+ const subjectTypeName2 = effectiveObjectiveSubject(objective, resolver).typeName;
176563
+ const out = [];
176564
+ for (const member of objective.members ?? []) {
176565
+ if (member.$type === "VerifyStmt") {
176566
+ const path10 = referencePathOf(member);
176567
+ out.push({
176568
+ declaration: member,
176569
+ kind: "verify",
176570
+ path: path10,
176571
+ target: referenceTargetOf(member, resolver),
176572
+ subjectTypeName: subjectTypeName2
176573
+ });
176574
+ } else if (member.$type === "RequirementDecl") {
176575
+ out.push({ declaration: member, kind: "requirement", subjectTypeName: subjectTypeName2 });
176576
+ }
176577
+ }
176578
+ return out;
176579
+ }
176580
+ function valueSimpleName(value) {
176581
+ const node = value;
176582
+ if (!node)
176583
+ return void 0;
176584
+ if (node.$type === "ParenExpr") {
176585
+ const items = node.items ?? [];
176586
+ return items.length === 1 ? valueSimpleName(items[0]) : void 0;
176587
+ }
176588
+ if (node.$type !== "PathExpr")
176589
+ return void 0;
176590
+ return node.path ? simpleName(node.path) : void 0;
176591
+ }
176592
+ function includeBindingOf(stmt, resolve8) {
176593
+ if (stmt.$type !== "IncludeStmt")
176594
+ return void 0;
176595
+ const node = stmt;
176596
+ const resolver = resolve8 ?? documentResolver(stmt);
176597
+ const isUseCase = (candidate) => candidate !== void 0 && candidate.$type === "UseCaseDecl";
176598
+ const typed = writtenTypes(node, resolver).find((type) => type.node === void 0 || isUseCase(type.node));
176599
+ const path10 = referencePathOf(node);
176600
+ const named2 = typed?.node ?? (typed ? void 0 : referenceTargetOf(node, resolver));
176601
+ const target = isUseCase(named2) ? named2 : void 0;
176602
+ const form = node.useCaseKw === true || typed !== void 0 ? "declaration" : "reference";
176603
+ const containing = enclosingCase(node.$container);
176604
+ const parameters = target ? effectiveActors(target, resolver) : [];
176605
+ const actors = [];
176606
+ for (const member of node.members ?? []) {
176607
+ if (member.$type !== "ActorDecl")
176608
+ continue;
176609
+ const name = member.name;
176610
+ actors.push({
176611
+ declaration: member,
176612
+ name,
176613
+ valueName: valueSimpleName(member.value),
176614
+ typeName: subjectTypeName(member),
176615
+ parameter: name ? parameters.find((parameter) => parameter.name === name) : void 0
176616
+ });
176617
+ }
176618
+ const containingSubject = containing ? effectiveCaseSubject(containing, resolver) : void 0;
176619
+ const includedSubject = target ? effectiveCaseSubject(target, resolver) : void 0;
176620
+ const subjectOrigin = isDecidedSubject(includedSubject) ? "included" : isDecidedSubject(containingSubject) ? "containing" : "default";
176621
+ const subjectTypeName2 = subjectOrigin === "included" ? includedSubject.typeName : subjectOrigin === "containing" ? containingSubject.typeName : DEFAULT_SUBJECT_TYPE;
176622
+ return {
176623
+ statement: stmt,
176624
+ form,
176625
+ path: typed ? typed.name : path10,
176626
+ target,
176627
+ containing,
176628
+ containingSubject,
176629
+ includedSubject,
176630
+ subjectOrigin,
176631
+ subjectTypeName: subjectTypeName2,
176632
+ parameters,
176633
+ actors
176634
+ };
176635
+ }
176636
+
175764
176637
  // ../language-server/out/src/services/implicit-specialization.js
175765
176638
  var EXPLICIT_SPECIALIZATION_KINDS = /* @__PURE__ */ new Set([
175766
176639
  ":>",
@@ -176530,11 +177403,64 @@ var DIAGNOSTIC_MESSAGES = {
176530
177403
  SSM040_INDIVIDUAL_NOT_OCCURRENCE: (name, kind) => `'individual' names one occurrence with an identity of its own, and ${name} is ${kind}, which has no life to identify. Remove 'individual', or move it to the occurrence this belongs to.`,
176531
177404
  SSM041_INDIVIDUAL_MULTIPLE_DEFINITIONS: (name, first2, second) => `${name} is typed by two individual definitions, '${first2}' and '${second}'. An individual usage names ONE life, so at most one of its types may be an 'individual def'.`,
176532
177405
  SSM042_INDIVIDUAL_WITHOUT_DEFINITION: (name) => `${name} is declared 'individual' but names no individual definition. An individual usage is typed by exactly one 'individual def' - the definition that carries the identity it names.`,
177406
+ // REQ-415 — issue #164. `assert c`, `require c` and `assume c` all reach their
177407
+ // constraint through the same OwnedReferenceSubsetting, so one message covers
177408
+ // the three. The kind is named because the fix depends on it: a part or an
177409
+ // action is not something that can be true or false.
177410
+ SSM043_CONSTRAINT_REFERENCE_KIND: (keyword, path10, kind) => `'${keyword} ${path10}' must name a constraint, but '${path10}' is ${kind}. The '${keyword}' shorthand asserts the referenced constraint's Boolean body, so write 'assert constraint { \u2026 }' to state a condition here instead.`,
177411
+ // REQ-415 — the reference resolves and its constraint evaluates to a definite
177412
+ // false, so the model states something against itself. A warning, never an
177413
+ // error: the text is well formed, and only a closed constant expression is
177414
+ // decided at all - anything that depends on a binding stays silent.
177415
+ SEM014_ASSERTION_VIOLATED: (text) => `Asserted constraint '${text}' evaluates to false, so this model is inconsistent as written.`,
177416
+ // REQ-131 — a constraint is a predicate: `BooleanEvaluation` returns
177417
+ // `Boolean[1]` (Kernel Semantic Library, `Performances.kerml`). A body that is
177418
+ // demonstrably some other type can never be true or false. Only a body the
177419
+ // checker can PROVE is not Boolean is reported, so an expression whose type it
177420
+ // cannot settle stays silent.
177421
+ SEM015_CONSTRAINT_BODY_NOT_BOOLEAN: (text, kind) => `A constraint body must be a Boolean expression, but '${text}' is ${kind}. A constraint is a predicate, so its body has to be able to come out true or false.`,
177422
+ // REQ-209 — a usage inherits its definition's expression. Replacing it hides
177423
+ // what the definition says while every other usage still reads the original.
177424
+ // Advisory: the language permits the redefinition, the modelling idiom does not
177425
+ // use it, and no model in the OMG corpus does.
177426
+ STYL012_CONSTRAINT_BODY_OVERRIDES_DEFINITION: (usage, definition) => `'${usage}' replaces the expression it inherits from '${definition}', so the definition's expression no longer applies here. Bind the parameters instead, or give this usage its own constraint definition.`,
177427
+ /* REQ-376 — a parameter of a constraint or a calculation is an INPUT.
177428
+ *
177429
+ * A constraint is a predicate: its one output is its Boolean result, which
177430
+ * comes from the body, never from a parameter. A calculation produces its
177431
+ * value through `return`. Neither has anything to send back out through a
177432
+ * parameter, and the OMG corpus bears that out: 40 `in` parameters on
177433
+ * constraints and 44 on calculations, and not one `out` or `inout` on either.
177434
+ *
177435
+ * A constraint is also ACAUSAL — `StraightLineDynamicsEquations` declares even
177436
+ * the quantities it would be solved for (`x_f`, `v_f`, `a`) as `in`, because
177437
+ * which parameter is the unknown is the binding's business, not the
177438
+ * constraint's. Fixing a direction would bake in one solving order. */
177439
+ STYL014_PARAMETER_DIRECTION: (parameter, direction, kind, owner) => kind === "constraint" ? `Parameter '${parameter}' is '${direction}' on constraint '${owner}'. A constraint's only output is true or false, so everything it relates is an input: declare the parameter 'in'. Which parameter is the unknown is decided where the constraint is bound.` : `Parameter '${parameter}' is '${direction}' on calculation '${owner}'. A calculation produces its value through 'return', so declare the parameter 'in' and return the result.`,
177440
+ // REQ-376 — a directed parameter is an input to be bound by a usage, not a
177441
+ // value slot. OMG declares parameters bare on a definition and puts values on
177442
+ // `attribute` members (`StraightLineDynamicsEquations`).
177443
+ STYL013_PARAMETER_DEFAULT_ON_DEFINITION: (parameter, owner) => `Parameter '${parameter}' carries a value on the definition '${owner}'. A parameter is an input a usage binds, so declare it without a value and put the value on an attribute, or bind it where the definition is used.`,
176533
177444
  // issue #165 — a satisfaction binds a thing to the subject a requirement
176534
177445
  // constrains, so the thing has to BE one of those (OMG SysML v2 Part 1
176535
177446
  // §7.21.2). The message names both types because the fix is either to bind a
176536
177447
  // different satisfier or to widen the requirement's subject.
176537
177448
  SSM044_SATISFIER_SUBJECT_TYPE: (satisfier, satisfierType, requirement, subjectType) => `'${satisfier}' is a '${satisfierType}', but '${requirement}' constrains a subject of type '${subjectType}'. A satisfying element must conform to the requirement's subject.`,
177449
+ // issue #166 — a case usage performs ONE case (OMG SysML v2 Part 1 §7.22.2),
177450
+ // and every effective binding this extension derives reads through that one:
177451
+ // the subject, the actor parameters and the objective. Two definitions leave
177452
+ // all three undecided, so the message names them and asks for one.
177453
+ SSM045_CASE_MULTIPLE_DEFINITIONS: (name, first2, second) => `Case '${name}' names more than one case definition ('${first2}' and '${second}'). A case usage performs exactly one case, so keep one and subset the other.`,
177454
+ // issue #166 — an `objective` written inside a verification case or a use
177455
+ // case has its subject BOUND to the case's subject, so a `subject` of an
177456
+ // unrelated type on the objective states something the case has already
177457
+ // decided otherwise.
177458
+ SSM046_OBJECTIVE_SUBJECT_TYPE: (caseName, objectiveType, subjectType) => `This objective declares a subject of type '${objectiveType}', but '${caseName}' binds its objective's subject to its own subject of type '${subjectType}'. Remove the subject or widen the case's.`,
177459
+ // issue #166 — an `include` investigates the included use case on the
177460
+ // including case's subject (§7.25), and an `actor` written inside the
177461
+ // include binds one of the included use case's actor parameters.
177462
+ SSM047_INCLUDE_SUBJECT_TYPE: (included, includedType, containerType) => `Included use case '${included}' has a subject of type '${includedType}', which does not conform to the including case's subject of type '${containerType}'. An included use case is investigated on the same subject.`,
177463
+ SSM048_INCLUDE_ACTOR_BINDING: (actor, included, known2) => `'${actor}' is not an actor parameter of the included use case '${included}'. It declares ${known2}.`,
176538
177464
  // REQ-392 — a `sysml-format` comment the formatter cannot act on. Advisory:
176539
177465
  // the directive is inert, and saying so beats leaving the author to wonder
176540
177466
  // why their layout was reformatted anyway.
@@ -176997,7 +177923,7 @@ function nearestAncestor(node, types) {
176997
177923
  }
176998
177924
  return void 0;
176999
177925
  }
177000
- function exprText2(node) {
177926
+ function exprText3(node) {
177001
177927
  return node?.$cstNode?.text?.trim().replace(/\s+/gu, " ") ?? "";
177002
177928
  }
177003
177929
  function conditionTypeLabel(node) {
@@ -177008,7 +177934,7 @@ function conditionTypeLabel(node) {
177008
177934
  if (["AndExpr", "OrExpr", "XorExpr", "NotExpr", "CompareExpr", "ClassifyOp"].includes(node.$type)) {
177009
177935
  return "Boolean";
177010
177936
  }
177011
- const text = exprText2(node);
177937
+ const text = exprText3(node);
177012
177938
  return /\b(true|false)\b|[=!<>]=?|(?:\band\b|\bor\b|\bnot\b|\bxor\b)/u.test(text) ? "Boolean" : "Boolean (expected)";
177013
177939
  }
177014
177940
  function buildConditionalHover(node) {
@@ -177022,7 +177948,7 @@ function buildConditionalHover(node) {
177022
177948
  "",
177023
177949
  "Canonical form: `if condition ? thenExpression else elseExpression`",
177024
177950
  `Then marker: ${usesQuestion ? "canonical `?`" : "non-canonical `then`; use `?`"}`,
177025
- `Condition: \`${exprText2(n2.cond)}\``,
177951
+ `Condition: \`${exprText3(n2.cond)}\``,
177026
177952
  `Condition type: ${conditionTypeLabel(n2.cond)}`,
177027
177953
  "",
177028
177954
  sourceFooter(nodeSource(node))
@@ -177194,6 +178120,8 @@ ${headerLines.join("\n")}
177194
178120
  const subject = subjectInheritanceSection(node);
177195
178121
  if (subject)
177196
178122
  parts.push(subject);
178123
+ for (const section of caseBindingSections(node))
178124
+ parts.push(section);
177197
178125
  if (relationshipDetails)
177198
178126
  parts.push(relationshipDetails);
177199
178127
  const flip = conjugationFlipSection(node);
@@ -177230,6 +178158,62 @@ function subjectInheritanceSection(node) {
177230
178158
  const ownerName = effective.owner.name ?? "(anonymous requirement)";
177231
178159
  return `*Subject inherited from \`${ownerName}\`:* \`${subjectText}\``;
177232
178160
  }
178161
+ var CASE_KIND_LABELS = {
178162
+ "case": "Case",
178163
+ "analysis": "Analysis case",
178164
+ "verification": "Verification case",
178165
+ "use-case": "Use case"
178166
+ };
178167
+ function caseBindingSections(node) {
178168
+ const out = [];
178169
+ const kind = caseKindOf(node);
178170
+ if (kind) {
178171
+ const effective = effectiveCaseDefinition(node);
178172
+ if (effective && !effective.isDefinition && effective.sole) {
178173
+ out.push(`*${CASE_KIND_LABELS[kind]} performs:* \`${effective.sole.name}\``);
178174
+ }
178175
+ const subject = effectiveCaseSubject(node);
178176
+ if (subject.origin === "inherited") {
178177
+ const owner = subject.owner?.name;
178178
+ out.push(`*Subject inherited${owner ? ` from \`${owner}\`` : ""}:* \`${subject.name ?? "subject"} : ${subject.typeName}\``);
178179
+ } else if (subject.origin === "default") {
178180
+ out.push("*Subject:* none declared, so this case investigates `Anything`.");
178181
+ }
178182
+ const inherited = effectiveActors(node).filter((actor) => actor.origin === "inherited");
178183
+ if (inherited.length > 0) {
178184
+ const list = inherited.map((actor) => `\`${actor.name ?? "actor"}${actor.typeName ? ` : ${actor.typeName}` : ""}\``).join(", ");
178185
+ out.push(`*Actors inherited:* ${list}`);
178186
+ }
178187
+ }
178188
+ if (node.$type === "ObjectiveDecl") {
178189
+ const binding = objectiveBindingOf(node);
178190
+ if (binding) {
178191
+ const what = binding.target === "case-subject" ? "subject" : "result";
178192
+ const verb = binding.strength === "bind" ? "is bound to" : "defaults to";
178193
+ const type = binding.typeName ? ` (\`${binding.typeName}\`)` : "";
178194
+ const caseName = binding.caseNode.name;
178195
+ out.push(`*Objective subject ${verb}* the ${what} of ${caseName ? `\`${caseName}\`` : "the enclosing case"}${type}.`);
178196
+ }
178197
+ const subrequirements = objectiveSubrequirements(node);
178198
+ if (subrequirements.length > 0) {
178199
+ const list = subrequirements.map((sub) => `\`${sub.path ?? sub.declaration.name ?? "requirement"}\``).join(", ");
178200
+ out.push(`*Required subrequirements:* ${list} \u2014 each is checked on this objective's subject.`);
178201
+ }
178202
+ }
178203
+ if (node.$type === "IncludeStmt") {
178204
+ const binding = includeBindingOf(node);
178205
+ if (binding?.target) {
178206
+ const name = binding.path ? `\`${binding.path}\`` : "the included use case";
178207
+ out.push(`*Includes:* ${name}, a reference to a use case performed elsewhere. It keeps its own identity and is not copied here.`);
178208
+ if (binding.subjectOrigin === "containing") {
178209
+ out.push(`*Investigated on:* the including case's subject (\`${binding.subjectTypeName}\`).`);
178210
+ } else if (binding.subjectOrigin === "included") {
178211
+ out.push(`*Investigated on:* its own subject (\`${binding.subjectTypeName}\`).`);
178212
+ }
178213
+ }
178214
+ }
178215
+ return out;
178216
+ }
177233
178217
  function flipDirection(direction) {
177234
178218
  return direction === "in" ? "out" : direction === "out" ? "in" : direction;
177235
178219
  }
@@ -178204,6 +179188,13 @@ var TYPE_CONTEXTS = {
178204
179188
  calc: ["CalcDecl", "FunctionDecl"],
178205
179189
  constraint: ["ConstraintDecl", "PredicateDecl"]
178206
179190
  };
179191
+ var CONSTRAINT_REFERENCE_TYPES = [
179192
+ "ConstraintDecl",
179193
+ "InvShorthand",
179194
+ "PredicateDecl",
179195
+ "RequirementDecl",
179196
+ "ConcernDecl"
179197
+ ];
178207
179198
  var ALL_DEFINITION_TYPES = [
178208
179199
  "PartDecl",
178209
179200
  "PortDecl",
@@ -178389,6 +179380,10 @@ var SysmlCompletionProvider = class extends DefaultCompletionProvider {
178389
179380
  allowedLabels.add("requirement");
178390
179381
  allowedLabels.add("by");
178391
179382
  }
179383
+ if (context.kind === "constraint-reference") {
179384
+ allowedLabels.add("constraint");
179385
+ allowedLabels.add("not");
179386
+ }
178392
179387
  if (context.kind === "specialization") {
178393
179388
  allowedLabels.add("specializes");
178394
179389
  allowedLabels.add("subsets");
@@ -178463,6 +179458,14 @@ var SysmlCompletionProvider = class extends DefaultCompletionProvider {
178463
179458
  addUnique(items, this.visibleSymbolItems(["RequirementDecl"], { document: document2, offset: offset2 }));
178464
179459
  return;
178465
179460
  }
179461
+ // REQ-415 — a reference shorthand names a CONSTRAINT, so the slot
179462
+ // offers constraint usages and definitions rather than every symbol.
179463
+ // A requirement and a concern are constraints too (OMG SysML v2
179464
+ // Part 1 §7.20.2, §7.21.2), so both belong in the list.
179465
+ case "constraint-reference": {
179466
+ addUnique(items, this.visibleSymbolItems(CONSTRAINT_REFERENCE_TYPES, { document: document2, offset: offset2 }));
179467
+ return;
179468
+ }
178466
179469
  case "connect": {
178467
179470
  addUnique(items, this.connectPortItems(document2, offset2));
178468
179471
  return;
@@ -178484,6 +179487,8 @@ var SysmlCompletionProvider = class extends DefaultCompletionProvider {
178484
179487
  symbolTypesForContext(context) {
178485
179488
  if (context.kind === "verify" || context.kind === "satisfy")
178486
179489
  return ["RequirementDecl"];
179490
+ if (context.kind === "constraint-reference")
179491
+ return CONSTRAINT_REFERENCE_TYPES;
178487
179492
  const keyword = context.typingKeyword;
178488
179493
  if (!keyword)
178489
179494
  return ALL_DEFINITION_TYPES;
@@ -178687,6 +179692,9 @@ function detectCompletionContext(text, offset2) {
178687
179692
  if (/\bconnect\s+(?:[\p{L}_:'.]+(?:\.[\p{L}_:']+)*\s+to\s*)?[\p{L}_:'.]*$/u.test(statement)) {
178688
179693
  return { kind: "connect", statement };
178689
179694
  }
179695
+ if (/\b(?:assert|require|assume)\s+(?:not\s+)?[\p{L}_:'.]*$/u.test(statement)) {
179696
+ return { kind: "constraint-reference", statement };
179697
+ }
178690
179698
  if (/(?:^|[^\w:])(?::>|:>>|specializes|subsets|redefines)\s*~?[\p{L}_:'.]*$/u.test(statement)) {
178691
179699
  return { kind: "specialization", statement, typingKeyword: keyword };
178692
179700
  }
@@ -180197,6 +181205,60 @@ var CONSTRAINT_SIDE_EFFECT_TYPES = /* @__PURE__ */ new Set([
180197
181205
  "DoAction",
180198
181206
  "ExitAction"
180199
181207
  ]);
181208
+ var BOOLEAN_OPERATORS = /* @__PURE__ */ new Set([
181209
+ "or",
181210
+ "|",
181211
+ "implies",
181212
+ "xor",
181213
+ "and",
181214
+ "&",
181215
+ ">=",
181216
+ "<=",
181217
+ "===",
181218
+ "!==",
181219
+ "==",
181220
+ "!=",
181221
+ ">",
181222
+ "<",
181223
+ "hastype",
181224
+ "istype",
181225
+ "@",
181226
+ "@@"
181227
+ ]);
181228
+ var ARITHMETIC_OPERATORS = /* @__PURE__ */ new Set(["+", "-", "*", "/", "%", "**", "^", ".."]);
181229
+ function nonBooleanExpressionKind(expr) {
181230
+ const node = expr;
181231
+ switch (expr.$type) {
181232
+ case "NumericPrimary":
181233
+ return node.unit ? "a quantity" : "a number";
181234
+ case "LiteralStr":
181235
+ return "a string";
181236
+ case "UnaryMinusExpr":
181237
+ case "UnaryPlusExpr":
181238
+ return "a number";
181239
+ case "ParenExpr": {
181240
+ const items = Array.isArray(node.items) ? node.items : [];
181241
+ return items.length === 1 ? nonBooleanExpressionKind(items[0]) : void 0;
181242
+ }
181243
+ case "BinExpr": {
181244
+ const op = typeof node.op === "string" ? node.op : void 0;
181245
+ if (op && BOOLEAN_OPERATORS.has(op))
181246
+ return void 0;
181247
+ if (op && ARITHMETIC_OPERATORS.has(op)) {
181248
+ return op === ".." ? "a range" : "an arithmetic expression";
181249
+ }
181250
+ return void 0;
181251
+ }
181252
+ default:
181253
+ return void 0;
181254
+ }
181255
+ }
181256
+ function directionOfModifiers(node) {
181257
+ const modifiers2 = node.modifiers;
181258
+ if (!Array.isArray(modifiers2))
181259
+ return void 0;
181260
+ return modifiers2.find((modifier) => modifier === "in" || modifier === "out" || modifier === "inout");
181261
+ }
180200
181262
  var ACTION_BODY_TYPES = /* @__PURE__ */ new Set([
180201
181263
  "ActionDecl",
180202
181264
  "PerformStmt",
@@ -180497,7 +181559,122 @@ var SysmlValidator = class _SysmlValidator {
180497
181559
  accept(severity("SEM010", "warning"), `Constraint '${node.name ?? "(anonymous)"}' must be a pure Boolean expression - '${member.$type}' is a statement with side effects and is not allowed in a constraint body.`, { node: member, code: "SEM010" });
180498
181560
  }
180499
181561
  }
181562
+ const notBoolean = node.body ? nonBooleanExpressionKind(node.body) : void 0;
181563
+ if (node.body?.$cstNode && notBoolean) {
181564
+ accept(severity("SEM015", "error"), DIAGNOSTIC_MESSAGES.SEM015_CONSTRAINT_BODY_NOT_BOOLEAN(node.body.$cstNode.text.replace(/\s+/g, " ").trim(), notBoolean), { node, property: "body", code: "SEM015" });
181565
+ }
181566
+ if (!node.isDef && node.body) {
181567
+ const definition = this.constraintTypeOf(node);
181568
+ if (definition?.body && definition.name) {
181569
+ accept(severity("STYL012", "hint"), DIAGNOSTIC_MESSAGES.STYL012_CONSTRAINT_BODY_OVERRIDES_DEFINITION(node.name ?? "(anonymous)", definition.name), { node, property: "body", code: "STYL012" });
181570
+ }
181571
+ }
181572
+ }
181573
+ /** REQ-209 — the constraint definition a usage is typed by, when the link
181574
+ * resolved. Only a direct typing is followed: a deeper specialization chain
181575
+ * is not what "replaces its definition's expression" is about. */
181576
+ constraintTypeOf(node) {
181577
+ const target = node.typing?.type?.ref;
181578
+ return target?.$type === "ConstraintDecl" ? target : void 0;
180500
181579
  }
181580
+ /* REQ-376 (user direction 2026-09-07) — STYL014: a parameter of a constraint
181581
+ * or a calculation is an INPUT. A constraint's one output is its Boolean
181582
+ * result and a calculation's is its `return`; neither sends anything back
181583
+ * through a parameter, and no model in the OMG corpus declares one `out` or
181584
+ * `inout`.
181585
+ *
181586
+ * Reported where the parameter is DECLARED: on a definition, and on a usage
181587
+ * that declares its own (an untyped `constraint c { out x : T; … }`). A TYPED
181588
+ * usage inherits its parameters, so a direction written there is a
181589
+ * redefinition of one, and `SSM025` already reports that as an error - saying
181590
+ * it twice, once as an error and once as an advisory, helps nobody. */
181591
+ checkParameterDirection(node, accept) {
181592
+ const decl = node;
181593
+ const typed = node.typing?.type?.ref;
181594
+ if (decl.isDef !== true && typed)
181595
+ return;
181596
+ const kind = node.$type === "ConstraintDecl" ? "constraint" : "calculation";
181597
+ const owner = typeof decl.name === "string" && decl.name ? decl.name : "(anonymous)";
181598
+ for (const member of decl.members ?? []) {
181599
+ const direction = directionOfModifiers(member);
181600
+ if (direction !== "out" && direction !== "inout")
181601
+ continue;
181602
+ const name = member.name;
181603
+ if (typeof name !== "string" || !name)
181604
+ continue;
181605
+ accept(severity("STYL014", "hint"), DIAGNOSTIC_MESSAGES.STYL014_PARAMETER_DIRECTION(name, direction, kind, owner), { node: member, code: "STYL014" });
181606
+ }
181607
+ }
181608
+ // REQ-376 — STYL013: a directed parameter is an input a usage binds, not a
181609
+ // value slot. OMG declares them bare on a definition and puts values on
181610
+ // `attribute` members. Only a DEFINITION is flagged: `in x = expr;` on a usage
181611
+ // is the canonical binding form.
181612
+ checkParameterDefaultOnDefinition(node, accept) {
181613
+ const decl = node;
181614
+ if (decl.isDef !== true || typeof decl.name !== "string" || !decl.name)
181615
+ return;
181616
+ for (const member of decl.members ?? []) {
181617
+ const name = member.name;
181618
+ const value = member.value;
181619
+ if (!value || typeof name !== "string" || !name)
181620
+ continue;
181621
+ if (directionOfModifiers(member) === void 0)
181622
+ continue;
181623
+ accept(severity("STYL013", "hint"), DIAGNOSTIC_MESSAGES.STYL013_PARAMETER_DEFAULT_ON_DEFINITION(name, decl.name), { node: member, code: "STYL013" });
181624
+ }
181625
+ }
181626
+ // REQ-415 — issue #164. `assert c;`, `assert not c;`, `require c;` and
181627
+ // `assume c;` name a constraint declared elsewhere (OMG SysML v2 Part 1
181628
+ // §7.20.3, §7.21.2). Three things can go wrong with that name, and all three
181629
+ // were silent: it may resolve to nothing, it may resolve to something that is
181630
+ // not a constraint, and the constraint it resolves to may be decidably false.
181631
+ //
181632
+ // The ROOT link is judged here rather than in `checkWrittenPaths`, which
181633
+ // deliberately leaves a root alone: a root is reported absent only when the
181634
+ // resolver could enumerate the whole surrounding inventory, and that is
181635
+ // exactly the guarantee `unresolvedIndex === 0` carries. It is the same rule
181636
+ // `checkRelationshipTargets` applies to a redefinition target.
181637
+ checkConstraintReference(node, accept) {
181638
+ const reference = constraintReferenceOf(node);
181639
+ if (!reference)
181640
+ return;
181641
+ const resolution = reference.property ? this.featurePaths.resolvePropertyPath(node, reference.property) : this.featurePaths.resolveDeclarationPath(node);
181642
+ if (resolution.segments.length === 0)
181643
+ return;
181644
+ if (resolution.unresolvedIndex === 0) {
181645
+ const invalid = resolution.segments[0];
181646
+ accept(severity("RES001", "error"), DIAGNOSTIC_MESSAGES.RES001_FEATURE_PATH_SEGMENT(invalid.text, "the current scope"), { node, range: invalid.cst.range, code: "RES001", data: { featurePathSegment: true } });
181647
+ return;
181648
+ }
181649
+ if (resolution.unresolvedIndex !== void 0 || resolution.indeterminateIndex !== void 0)
181650
+ return;
181651
+ const last2 = resolution.segments[resolution.segments.length - 1];
181652
+ const target = last2.target;
181653
+ if (target && isWrongKindConstraintTarget(target)) {
181654
+ accept(severity("SSM043", "error"), DIAGNOSTIC_MESSAGES.SSM043_CONSTRAINT_REFERENCE_KIND(reference.kind, reference.path, wrongKindLabel(target)), { node, range: last2.cst.range, code: "SSM043" });
181655
+ }
181656
+ }
181657
+ // REQ-415 — SEM014. An assertion the model can DECIDE and that comes out
181658
+ // false is an inconsistency the author wrote against themselves. Only a
181659
+ // closed constant expression is decided: every feature reference is
181660
+ // inconclusive here, so an assertion that depends on a binding, on time, or
181661
+ // on anything this evaluator does not model stays silent rather than passing
181662
+ // quietly or being reported on a guess.
181663
+ checkAssertionConsistency(node, accept) {
181664
+ if (node.$type !== "AssertConstraintStmt")
181665
+ return;
181666
+ const result = evaluateAssertion(node, this.constraintResolver);
181667
+ if (result?.status !== "fail")
181668
+ return;
181669
+ accept(severity("SEM014", "warning"), DIAGNOSTIC_MESSAGES.SEM014_ASSERTION_VIOLATED(result.text), { node, code: "SEM014" });
181670
+ }
181671
+ // REQ-415 — Resolve a reference shorthand through the shared path resolver,
181672
+ // so a target in another file or in the standard library is evaluated exactly
181673
+ // as a same-file one is.
181674
+ constraintResolver = (reference, member) => {
181675
+ const resolution = reference.property ? this.featurePaths.resolvePropertyPath(member, reference.property) : this.featurePaths.resolveDeclarationPath(member);
181676
+ return resolution.segments[resolution.segments.length - 1]?.target;
181677
+ };
180501
181678
  // REQ-410 — SEM013. A `ref` feature is NON-composite: it names a feature that
180502
181679
  // is owned somewhere else. An unbound one therefore names nothing at all, and
180503
181680
  // the General View cannot draw it as anything: a box would claim the owner
@@ -181996,6 +183173,7 @@ ${baseIndent}}`;
181996
183173
  const decls = [];
181997
183174
  const verifyStmts = [];
181998
183175
  const satisfyStmts = [];
183176
+ const includeStmts = [];
181999
183177
  const aliasMap = /* @__PURE__ */ new Map();
182000
183178
  for (const child of ast_utils_exports.streamAllContents(node)) {
182001
183179
  if (isImport(child)) {
@@ -182019,6 +183197,8 @@ ${baseIndent}}`;
182019
183197
  if (a2.name && a2.target)
182020
183198
  aliasMap.set(a2.name, a2.target);
182021
183199
  }
183200
+ if (child.$type === "IncludeStmt")
183201
+ includeStmts.push(child);
182022
183202
  }
182023
183203
  this.checkAmbiguousReferences(node, imports, index2, accept);
182024
183204
  this.checkPrivateImports(imports, index2, accept);
@@ -182054,7 +183234,7 @@ ${baseIndent}}`;
182054
183234
  this.checkInverseOfTargets(decl, index2, accept);
182055
183235
  this.checkTypeComposition(decl, index2, accept);
182056
183236
  }
182057
- this.checkTypeConformance(decls, satisfyStmts, index2, accept);
183237
+ this.checkTypeConformance(decls, satisfyStmts, includeStmts, index2, accept);
182058
183238
  }
182059
183239
  // ══════════════════════════════════════════════════════════════════════
182060
183240
  // REQ-390 — SSM017-SSM021: whole-model type conformance (issue #104)
@@ -182064,7 +183244,7 @@ ${baseIndent}}`;
182064
183244
  // the walk, so a type rooted in the unparsed standard library yields
182065
183245
  // `unknown` and no diagnostic. That is what keeps the OMG corpus clean while
182066
183246
  // still catching the workspace-local mistakes these codes exist for.
182067
- checkTypeConformance(decls, satisfyStmts, index2, accept) {
183247
+ checkTypeConformance(decls, satisfyStmts, includeStmts, index2, accept) {
182068
183248
  const model = new ConformanceModel((name) => this.resolveUnique(name, index2), (node) => this.implicit?.closureOf(node) ?? { names: /* @__PURE__ */ new Set(), complete: true });
182069
183249
  for (const decl of decls) {
182070
183250
  this.checkRedefinitionTypeConformance(decl, model, index2, accept);
@@ -182079,9 +183259,78 @@ ${baseIndent}}`;
182079
183259
  this.checkRedefinitionDirection(decl, index2, accept);
182080
183260
  this.checkInterfaceEndTypes(decl, model, index2, accept);
182081
183261
  this.checkIndividualDefinitions(decl, model, accept);
183262
+ this.checkCaseDefinitionCount(decl, index2, accept);
183263
+ this.checkObjectiveSubject(decl, model, index2, accept);
182082
183264
  }
182083
183265
  for (const stmt of satisfyStmts)
182084
183266
  this.checkSatisfierSubjectType(stmt, model, index2, accept);
183267
+ for (const stmt of includeStmts)
183268
+ this.checkIncludeBindings(stmt, model, index2, accept);
183269
+ }
183270
+ // ══════════════════════════════════════════════════════════════════════
183271
+ // REQ-417 — SSM045-SSM048: the bindings a case makes (issue #166)
183272
+ // ══════════════════════════════════════════════════════════════════════
183273
+ // SSM045 — OMG SysML v2 Part 1 §7.22.2: a CaseUsage has exactly one
183274
+ // CaseDefinition. Everything this extension derives about a case usage reads
183275
+ // through that one — its subject, its actor parameters, its objective — so
183276
+ // two leave all three undecided rather than merged. A type this validator
183277
+ // could not read is NOT counted: an unread type is not a wrong one, the same
183278
+ // three-valued rule the rest of this family follows.
183279
+ checkCaseDefinitionCount(decl, index2, accept) {
183280
+ const effective = effectiveCaseDefinition(decl, (name) => this.resolveUnique(name, index2));
183281
+ if (!effective || effective.isDefinition)
183282
+ return;
183283
+ const read = effective.definitions.filter((type) => type.node !== void 0);
183284
+ if (read.length < 2)
183285
+ return;
183286
+ accept(severity("SSM045", "error"), DIAGNOSTIC_MESSAGES.SSM045_CASE_MULTIPLE_DEFINITIONS(decl.name ?? "this case", read[0].name, read[1].name), { node: decl, code: "SSM045" });
183287
+ }
183288
+ // SSM046 — a `verification case` and a `use case` BIND their objective's
183289
+ // subject to their own (`objective obj { subject subj = VerificationCase::subj; }`
183290
+ // in `VerificationCases.sysml`), so a `subject` written on the objective with
183291
+ // an unrelated type states something the case has already decided otherwise.
183292
+ // A generic `case` and an `analysis case` only DEFAULT the objective's subject
183293
+ // to their result, which the model may override, so neither is judged here.
183294
+ checkObjectiveSubject(decl, model, index2, accept) {
183295
+ if (decl.$type !== "ObjectiveDecl")
183296
+ return;
183297
+ const binding = objectiveBindingOf(decl, (name) => this.resolveUnique(name, index2));
183298
+ if (!binding || binding.strength !== "bind" || !binding.own)
183299
+ return;
183300
+ const written = binding.own.typing?.type?.$refText?.trim();
183301
+ if (!written)
183302
+ return;
183303
+ const bound = binding.typeName;
183304
+ if (!bound || bound === DEFAULT_SUBJECT_TYPE)
183305
+ return;
183306
+ if (model.compatible(written, bound) !== "unrelated")
183307
+ return;
183308
+ const caseName = binding.caseNode.name ?? "this case";
183309
+ accept(severity("SSM046", "warning"), DIAGNOSTIC_MESSAGES.SSM046_OBJECTIVE_SUBJECT_TYPE(caseName, written, bound), { node: binding.own, code: "SSM046" });
183310
+ }
183311
+ // SSM047 / SSM048 — OMG SysML v2 Part 1 §7.25 / §8.2.2.25 IncludeUseCaseUsage.
183312
+ // An include is a REFERENCE to a use case performed elsewhere: it keeps that
183313
+ // use case's identity, is investigated on the including case's subject, and
183314
+ // binds that use case's own actor parameters. Both checks stay silent unless
183315
+ // the included use case was actually read.
183316
+ checkIncludeBindings(stmt, model, index2, accept) {
183317
+ const binding = includeBindingOf(stmt, (name) => this.resolveUnique(name, index2));
183318
+ if (!binding?.target)
183319
+ return;
183320
+ const included = binding.path ?? "the included use case";
183321
+ const includedSubject = binding.includedSubject;
183322
+ const containingSubject = binding.containingSubject;
183323
+ if (isDecidedSubject(includedSubject) && isDecidedSubject(containingSubject) && model.compatible(includedSubject.typeName, containingSubject.typeName) === "unrelated") {
183324
+ accept(severity("SSM047", "warning"), DIAGNOSTIC_MESSAGES.SSM047_INCLUDE_SUBJECT_TYPE(included, includedSubject.typeName, containingSubject.typeName), { node: stmt, code: "SSM047" });
183325
+ }
183326
+ if (binding.parameters.length === 0)
183327
+ return;
183328
+ const known2 = binding.parameters.map((parameter) => `'${parameter.name ?? "(anonymous)"}'`).join(", ");
183329
+ for (const actor of binding.actors) {
183330
+ if (!actor.name || actor.parameter)
183331
+ continue;
183332
+ accept(severity("SSM048", "warning"), DIAGNOSTIC_MESSAGES.SSM048_INCLUDE_ACTOR_BINDING(actor.name, included, known2), { node: actor.declaration, code: "SSM048" });
183333
+ }
182085
183334
  }
182086
183335
  // REQ-416 — SSM044: `satisfy MassReq by engine;` claims that `engine` is one
182087
183336
  // of the things `MassReq` constrains, so `engine`'s type has to conform to
@@ -183346,7 +184595,16 @@ ${baseIndent}}`;
183346
184595
  // issue #215 — the rest of the reference-form declarations. They share
183347
184596
  // `ReferenceFormPath` with `perform`/`exhibit`, so they can spell the
183348
184597
  // same defect and are judged by the same rule.
183349
- AssertConstraintStmt: this.checkChainSeparators.bind(this),
184598
+ // REQ-415 — issue #164: the constraint reference shorthands. `assert`
184599
+ // shares its `ReferenceFormPath` with the other reference forms, so it
184600
+ // also carries the RES019 separator rule above.
184601
+ AssertConstraintStmt: [
184602
+ this.checkChainSeparators.bind(this),
184603
+ this.checkConstraintReference.bind(this),
184604
+ this.checkAssertionConsistency.bind(this)
184605
+ ],
184606
+ RequireConstraintStmt: this.checkConstraintReference.bind(this),
184607
+ AssumeConstraintStmt: this.checkConstraintReference.bind(this),
183350
184608
  EntryAction: this.checkChainSeparators.bind(this),
183351
184609
  DoAction: this.checkChainSeparators.bind(this),
183352
184610
  ExitAction: this.checkChainSeparators.bind(this),
@@ -183354,7 +184612,17 @@ ${baseIndent}}`;
183354
184612
  ConnectorEnd: this.checkConnectorEndSeparators.bind(this),
183355
184613
  RequirementDecl: this.checkRequirementDecl.bind(this),
183356
184614
  AttributeDecl: this.checkAttributeDecl.bind(this),
183357
- ConstraintDecl: this.checkConstraintDecl.bind(this),
184615
+ // REQ-376 — STYL013 applies to both behavioral definitions that take
184616
+ // parameters, so the constraint check runs beside it here.
184617
+ ConstraintDecl: [
184618
+ this.checkConstraintDecl.bind(this),
184619
+ this.checkParameterDefaultOnDefinition.bind(this),
184620
+ this.checkParameterDirection.bind(this)
184621
+ ],
184622
+ CalcDecl: [
184623
+ this.checkParameterDefaultOnDefinition.bind(this),
184624
+ this.checkParameterDirection.bind(this)
184625
+ ],
183358
184626
  VerificationCaseDecl: this.checkVerificationCaseDecl.bind(this),
183359
184627
  AnalysisCaseDecl: this.checkAnalysisCaseDecl.bind(this),
183360
184628
  ViewDecl: this.checkViewDecl.bind(this),
@@ -184077,6 +185345,9 @@ var STYLE_ADVISORY_CODES = /* @__PURE__ */ new Set([
184077
185345
  "STYL009",
184078
185346
  "STYL010",
184079
185347
  "STYL011",
185348
+ "STYL012",
185349
+ "STYL013",
185350
+ "STYL014",
184080
185351
  "LEX009",
184081
185352
  // trailing whitespace
184082
185353
  "SYN024",
@@ -184399,6 +185670,8 @@ var SysmlScopeComputation = class extends DefaultScopeComputation {
184399
185670
  break;
184400
185671
  if (node.$type === "ShortName" || node.$type === "ImportSeg")
184401
185672
  continue;
185673
+ if (isReferenceFormDeclaration(node))
185674
+ continue;
184402
185675
  const aliases = this.nameAliasesOf(node);
184403
185676
  if (aliases.length === 0)
184404
185677
  continue;
@@ -189965,7 +191238,7 @@ function nodeBlockForCanvas(node) {
189965
191238
  compartments: compartments2?.length ? compartments2 : void 0
189966
191239
  };
189967
191240
  }
189968
- if (!/\bconstraint(?:\s+def)?$/u.test(node.keyword.trim().toLowerCase())) return node;
191241
+ if (!/\b(?:constraint|calc)(?:\s+def)?$/u.test(node.keyword.trim().toLowerCase())) return node;
189969
191242
  const compartments = node.compartments?.filter((compartment) => compartment.title !== "expression");
189970
191243
  return {
189971
191244
  ...node,
@@ -190059,7 +191332,9 @@ function nodeSize(node, direction) {
190059
191332
  const portRunHeight = connectionUsage ? portRows ? portRows * 18 + 6 : 0 : portRows ? compactContainer ? portRows * 24 + 8 : 40 + portRows * 24 + 8 : 0;
190060
191333
  const bodyH = Math.max(
190061
191334
  connectionUsage ? 42 : BOX_H,
190062
- node.value !== void 0 ? 88 : 0,
191335
+ // REQ-209/375 - The value field sits at the bottom of the card, under
191336
+ // whatever compartments it carries, so both have to fit.
191337
+ node.value !== void 0 ? Math.max(88, NODE_COMPARTMENT_TOP + compartmentHeight(node) + 36) : 0,
190063
191338
  featureH === 0 ? NODE_COMPARTMENT_TOP + compartmentHeight(node) : 0,
190064
191339
  portRunHeight,
190065
191340
  portedSideLength(ph, "left"),
@@ -190730,7 +192005,7 @@ function collapseIvModel(model, hiddenInternals) {
190730
192005
  const frames = model.frames ?? [];
190731
192006
  if (!frames.length) return model;
190732
192007
  const frameById = new Map(frames.map((f) => [f.id, f]));
190733
- const requested = new Set(frames.filter((frame2) => framePresentationEnabled(hiddenInternals, frame2, true) && isCollapsibleFrame("iv", frame2)).map((frame2) => frame2.id));
192008
+ const requested = new Set(frames.filter((frame2) => (frame2.meta?.internalsExpandable === false || framePresentationEnabled(hiddenInternals, frame2, true)) && isCollapsibleFrame("iv", frame2)).map((frame2) => frame2.id));
190734
192009
  if (requested.size === 0) return model;
190735
192010
  const hasRequestedAncestor = (id2) => {
190736
192011
  let p = frameById.get(id2)?.parent;
@@ -190793,12 +192068,11 @@ function collapseIvModel(model, hiddenInternals) {
190793
192068
  const toRoot = containerRootOf(e.to);
190794
192069
  if (fromRoot !== void 0 && fromRoot === toRoot) return false;
190795
192070
  return !(hidden.has(e.from) && fromRoot === void 0) && !(hidden.has(e.to) && toRoot === void 0);
190796
- }).map((e) => {
192071
+ }).filter((e) => e.from === e.to || (bodyDock.get(e.from) ?? e.from) !== (bodyDock.get(e.to) ?? e.to)).map((e) => {
190797
192072
  const from = bodyDock.get(e.from) ?? e.from;
190798
192073
  const to = bodyDock.get(e.to) ?? e.to;
190799
192074
  return from === e.from && to === e.to ? e : { ...e, from, to };
190800
192075
  }).filter((e) => {
190801
- if (e.from === e.to) return false;
190802
192076
  const key2 = `${e.from}\0${e.to}\0${e.kind}\0${e.label ?? ""}`;
190803
192077
  if (seenEdge.has(`${key2}:${e.id}`)) return false;
190804
192078
  seenEdge.add(`${key2}:${e.id}`);
@@ -190876,17 +192150,30 @@ function isFeatureCompartmentNode(kind, node) {
190876
192150
  if (kind === "stv") return node.shape === "state";
190877
192151
  return false;
190878
192152
  }
192153
+ function graphicalChildOwners(model) {
192154
+ const owners = /* @__PURE__ */ new Set();
192155
+ for (const node of model.nodes) {
192156
+ const owner = node.frame ?? node.parent;
192157
+ if (owner && owner !== node.id) owners.add(owner);
192158
+ }
192159
+ for (const frame2 of model.frames ?? []) {
192160
+ if (frame2.parent && frame2.parent !== frame2.id) owners.add(frame2.parent);
192161
+ }
192162
+ return owners;
192163
+ }
190879
192164
  function applyFeatureCompartmentVisibility(model, visibleFeatureCompartments, hiddenInternals = {}) {
190880
192165
  if (!CONTAINER_PRESENTATION_KINDS.has(model.kind)) return model;
190881
192166
  const legacy = model.kind === "iv";
192167
+ const owners = graphicalChildOwners(model);
190882
192168
  let changed = false;
190883
192169
  const project = (host, leaf) => {
192170
+ const internalsExpandable = owners.has(host.id);
190884
192171
  const alwaysVisible = host.meta?.alwaysVisibleCompartments === true;
190885
192172
  const defaultVisible = leaf || model.kind === "afv" && !leaf;
190886
192173
  const visible = alwaysVisible || framePresentationEnabled(visibleFeatureCompartments, host, legacy, defaultVisible);
190887
192174
  const compartments = visible ? host.compartments : void 0;
190888
192175
  const internalsHidden = leaf ? framePresentationEnabled(hiddenInternals, host, legacy) : host.meta?.internalsHidden === true;
190889
- if (compartments === host.compartments && host.meta?.containerControls === true && host.meta?.featureCompartmentsVisible === visible && (!leaf || host.meta?.internalsHidden === internalsHidden)) return host;
192176
+ if (compartments === host.compartments && host.meta?.containerControls === true && host.meta?.internalsExpandable === internalsExpandable && host.meta?.featureCompartmentsVisible === visible && (!leaf || host.meta?.internalsHidden === internalsHidden)) return host;
190890
192177
  changed = true;
190891
192178
  return {
190892
192179
  ...host,
@@ -190894,6 +192181,7 @@ function applyFeatureCompartmentVisibility(model, visibleFeatureCompartments, hi
190894
192181
  meta: {
190895
192182
  ...host.meta,
190896
192183
  containerControls: true,
192184
+ internalsExpandable,
190897
192185
  featureCompartmentsVisible: visible,
190898
192186
  ...leaf ? { internalsHidden } : {}
190899
192187
  }
@@ -190909,10 +192197,10 @@ function collapseActionFrames(model, hiddenInternals, isHost = isCollapsibleActi
190909
192197
  if (!frames.length) return model;
190910
192198
  const frameById = new Map(frames.map((f) => [f.id, f]));
190911
192199
  const requested = new Set(
190912
- frames.filter((f) => framePresentationEnabled(hiddenInternals, f) && isHost(f)).map((f) => f.id)
192200
+ frames.filter((f) => (f.meta?.internalsExpandable === false || framePresentationEnabled(hiddenInternals, f)) && isHost(f)).map((f) => f.id)
190913
192201
  );
190914
192202
  if (requested.size === 0) return model;
190915
- const rootOf2 = (id2) => {
192203
+ const rootOf3 = (id2) => {
190916
192204
  let root4;
190917
192205
  const seen = /* @__PURE__ */ new Set();
190918
192206
  for (let cur = id2; cur !== void 0 && !seen.has(cur); cur = frameById.get(cur)?.parent) {
@@ -190921,13 +192209,13 @@ function collapseActionFrames(model, hiddenInternals, isHost = isCollapsibleActi
190921
192209
  }
190922
192210
  return root4;
190923
192211
  };
190924
- const roots = new Set([...requested].filter((id2) => rootOf2(frameById.get(id2)?.parent) === void 0));
192212
+ const roots = new Set([...requested].filter((id2) => rootOf3(frameById.get(id2)?.parent) === void 0));
190925
192213
  const dockOf = /* @__PURE__ */ new Map();
190926
192214
  const proxyHost = /* @__PURE__ */ new Map();
190927
192215
  const ownerOfHiddenPort = /* @__PURE__ */ new Map();
190928
192216
  const hiddenFrameIds = /* @__PURE__ */ new Set();
190929
192217
  for (const f of frames) {
190930
- const root4 = roots.has(f.id) ? rootOf2(f.parent) : rootOf2(f.id);
192218
+ const root4 = roots.has(f.id) ? rootOf3(f.parent) : rootOf3(f.id);
190931
192219
  if (root4 === void 0) continue;
190932
192220
  hiddenFrameIds.add(f.id);
190933
192221
  dockOf.set(f.id, root4);
@@ -190938,7 +192226,7 @@ function collapseActionFrames(model, hiddenInternals, isHost = isCollapsibleActi
190938
192226
  }
190939
192227
  const hiddenNodeIds = /* @__PURE__ */ new Set();
190940
192228
  for (const n2 of model.nodes) {
190941
- const root4 = rootOf2(n2.frame);
192229
+ const root4 = rootOf3(n2.frame);
190942
192230
  if (root4 === void 0) continue;
190943
192231
  hiddenNodeIds.add(n2.id);
190944
192232
  dockOf.set(n2.id, root4);
@@ -190967,12 +192255,11 @@ function collapseActionFrames(model, hiddenInternals, isHost = isCollapsibleActi
190967
192255
  const edges = model.edges.filter((e) => {
190968
192256
  const fromRoot = containerRootOf(e.from);
190969
192257
  return fromRoot === void 0 || fromRoot !== containerRootOf(e.to);
190970
- }).map((e) => {
192258
+ }).filter((e) => e.from === e.to || (dockOf.get(e.from) ?? e.from) !== (dockOf.get(e.to) ?? e.to)).map((e) => {
190971
192259
  const from = dockOf.get(e.from) ?? e.from;
190972
192260
  const to = dockOf.get(e.to) ?? e.to;
190973
192261
  return from === e.from && to === e.to ? e : { ...e, from, to };
190974
192262
  }).filter((e) => {
190975
- if (e.from === e.to) return false;
190976
192263
  const key2 = `${e.from}\0${e.to}\0${e.kind}\0${e.label ?? ""}`;
190977
192264
  if (seenEdge.has(`${key2}:${e.id}`)) return false;
190978
192265
  seenEdge.add(`${key2}:${e.id}`);
@@ -191114,6 +192401,8 @@ function modelToFlow(model, opts) {
191114
192401
  nodes.push({
191115
192402
  id: f.id,
191116
192403
  type: "frame",
192404
+ // REQ-361 - Portless GV bounds include the complete painted frame.
192405
+ className: model.kind === "gv" && !f.ports?.length ? "rf-bounded-paint" : void 0,
191117
192406
  position: { x: 0, y: 0 },
191118
192407
  data: {
191119
192408
  kind: model.kind,
@@ -191229,6 +192518,8 @@ function modelToFlow(model, opts) {
191229
192518
  nodes.push({
191230
192519
  id: n2.id,
191231
192520
  type: isGeo ? "geo" : "sysml",
192521
+ // REQ-361 - Outside port labels must never enter paint containment.
192522
+ className: model.kind === "gv" && !n2.ports?.length ? "rf-bounded-paint" : void 0,
191232
192523
  position: { x: 0, y: 0 },
191233
192524
  data: {
191234
192525
  kind: model.kind,
@@ -205385,6 +206676,10 @@ function markersFor(kind) {
205385
206676
  // REQ-199
205386
206677
  case "derive":
205387
206678
  // REQ-188
206679
+ case "assert":
206680
+ // REQ-131/REQ-415 — the constraint claims
206681
+ case "assume":
206682
+ case "require":
205388
206683
  case "causation":
205389
206684
  // REQ-189
205390
206685
  case "import":
@@ -205761,7 +207056,7 @@ var KIN_MARKER_DEFS_SVG = [
205761
207056
 
205762
207057
  // ../extension/src/webview/diagram/element-colors.ts
205763
207058
  var ELEMENT_CLOSED_OPACITY = 1;
205764
- var ELEMENT_OPEN_OPACITY = 0.2;
207059
+ var ELEMENT_OPEN_OPACITY = 0.3;
205765
207060
  var DIAGRAM_ELEMENT_COLORS = {
205766
207061
  default: {
205767
207062
  outline: { light: "#3a3a3a", dark: "#a1a1a1" },
@@ -205894,7 +207189,22 @@ var DIAGRAM_LINE_COLORS = {
205894
207189
  },
205895
207190
  dependency: {
205896
207191
  color: { light: "#6b46c1", dark: "#b08cf0" },
205897
- kinds: ["satisfy", "verify", "include", "dependency", "allocate", "frame", "derive", "causation", "import", "expose"],
207192
+ kinds: [
207193
+ "satisfy",
207194
+ "verify",
207195
+ "include",
207196
+ "dependency",
207197
+ "allocate",
207198
+ "frame",
207199
+ "derive",
207200
+ "causation",
207201
+ "import",
207202
+ "expose",
207203
+ // REQ-131/REQ-415 — the constraint claims read as the same family.
207204
+ "assert",
207205
+ "assume",
207206
+ "require"
207207
+ ],
205898
207208
  colorLabels: true
205899
207209
  },
205900
207210
  binding: {
@@ -206321,6 +207631,8 @@ body {
206321
207631
  .dlink.satisfy, .dlink.verify, .dlink.include, .dlink.dependency { stroke-dasharray: 4 3; }
206322
207632
  /* REQ-186/188/189/199/206/210 \u2014 the dashed labelled families */
206323
207633
  .dlink.allocate, .dlink.frame, .dlink.derive, .dlink.causation, .dlink.import, .dlink.expose { stroke-dasharray: 4 3; }
207634
+ /* REQ-131/REQ-415 \u2014 the three constraint claims */
207635
+ .dlink.assert, .dlink.assume, .dlink.require { stroke-dasharray: 4 3; }
206324
207636
  .dlink.annotation { stroke-dasharray: 2 3; }
206325
207637
  .dlink.elaboration { stroke-dasharray: 2 3; pointer-events: none; }
206326
207638
  .dlink.reply { stroke-dasharray: 4 3; } /* REQ-202 \u2014 sequence reply arrows */
@@ -207035,6 +208347,15 @@ svg.react-flow__connectionline { z-index: 1; }
207035
208347
  .rf-ctl-zoom { width: auto; min-width: 42px; padding: 0 4px; text-align: center; font: 600 11px var(--font-mono); color: var(--fg-2); }
207036
208348
  .rf-ctl-sep { width: 1px; height: 16px; background: var(--line); margin: 0 3px; }
207037
208349
  .react-flow__node { font-family: var(--font-mono); font-size: 11px; color: var(--fg-0); }
208350
+ /* REQ-361 - Bound hit testing on portless GV cards. The margin retains border
208351
+ * strokes, package tabs and side handles. Port glyphs and their outside labels
208352
+ * remain unbounded. Editing and hover controls also retain their full overflow. */
208353
+ /* Keep every card mounted. Only ordinary Group cards defer off-screen contents.
208354
+ * Their explicit dimensions preserve geometry. Large frames and Tree retain
208355
+ * their regular rendering path; deferring their contents adds layout work. */
208356
+ .react-flow__node.rf-bounded-paint { contain: paint; overflow-clip-margin: 16px; }
208357
+ .rf-gv-group .react-flow__node-sysml.rf-bounded-paint { content-visibility: auto; }
208358
+ .react-flow__node.rf-bounded-paint:is(:hover, :focus-within, .selected) { contain: none; content-visibility: visible; }
207038
208359
  .react-flow__node-sysml, .react-flow__node-frame { background: transparent; border: none; padding: 0; border-radius: 0; box-shadow: none; }
207039
208360
  .rf-node, .rf-frame { position: relative; user-select: none; }
207040
208361
  /* Container frames: the interior is click-through so connectors drawn underneath
@@ -207812,7 +209133,15 @@ var TOOLBOX = {
207812
209133
  rel("verify", "verify", "\u2713", "click the verification case, then the requirement"),
207813
209134
  rel("frame", "frame", "\u274F", "click the requirement/view, then the framed concern"),
207814
209135
  rel("exhibit", "exhibit", "\u25C9", "click the part, then the exhibited state"),
207815
- rel("perform", "perform", "\u25B7", "click the part, then the performed action")
209136
+ rel("perform", "perform", "\u25B7", "click the part, then the performed action"),
209137
+ // REQ-131/REQ-415 (user direction 2026-09-08 — "how do we add assert
209138
+ // constraint from the diagram") — the three constraint CLAIMS. The
209139
+ // diagram drew them in its compartments but could not create one, so
209140
+ // `assert constraint …` could only be typed. Each writes into the
209141
+ // claiming element, exactly as satisfy/verify/frame do.
209142
+ rel("assert", "assert", "\u22A8", "click the element that asserts, then the constraint"),
209143
+ rel("assume", "assume", "\u2283", "click the requirement/concern, then the assumed constraint"),
209144
+ rel("require", "require", "\u22A2", "click the requirement/concern, then the required constraint")
207816
209145
  ]
207817
209146
  },
207818
209147
  // The Interconnection View depicts parts, ports, and the compartment rows of
@@ -207843,7 +209172,12 @@ var TOOLBOX = {
207843
209172
  rel("flow", "flow", "\u2192", "click the source port/feature, then the target"),
207844
209173
  // issue #115 — an item flow that also sequences its ends.
207845
209174
  rel("successionFlow", "succession flow", "\u21C9", "click the source port/feature, then the target"),
207846
- rel("allocate", "allocate", "\u290F", "click the source part/feature, then the target")
209175
+ rel("allocate", "allocate", "\u290F", "click the source part/feature, then the target"),
209176
+ // REQ-131 — the view draws a part's constraints, and OMG's own
209177
+ // parametric picture is a part asserting one and binding its
209178
+ // parameters (ConstraintTest.sysml). `bind` was already here; the
209179
+ // claim that gives it something to bind was not.
209180
+ rel("assert", "assert", "\u22A8", "click the part, then the constraint it asserts")
207847
209181
  ]
207848
209182
  },
207849
209183
  // Action Flow depicts actions (a new `action def` becomes its own tile in a
@@ -207857,6 +209191,8 @@ var TOOLBOX = {
207857
209191
  // they are the action's parameter pins.
207858
209192
  afv: {
207859
209193
  elements: [
209194
+ el("calc def", "calc def", "\u2211"),
209195
+ el("calc", "calc", "\u2211"),
207860
209196
  el("action def", "action def", "\u25B7"),
207861
209197
  el("action", "action", "\u25B7"),
207862
209198
  // issue #217 — a behaviour-root canvas writes into the action
@@ -208025,7 +209361,10 @@ var CHILD_KINDS = {
208025
209361
  "event occurrence": [],
208026
209362
  requirement: ["requirement", "constraint", "attribute", "part", "actor"],
208027
209363
  concern: ["requirement", "constraint", "attribute", "actor"],
208028
- constraint: ["attribute", "constraint"],
209364
+ // REQ-376 — a constraint and a calculation take INPUTS, and there was no way
209365
+ // to add one from the diagram. Only `in`: an `out` or `inout` parameter on
209366
+ // either is STYL014, so offering one would contradict the check.
209367
+ constraint: ["in parameter", "attribute", "constraint"],
208029
209368
  "use case": CASE_CHILDREN,
208030
209369
  "analysis case": CASE_CHILDREN,
208031
209370
  "verification case": CASE_CHILDREN,
@@ -208037,7 +209376,7 @@ var CHILD_KINDS = {
208037
209376
  // issue (GRV on enum def): an enum def owns enumeration VALUES — nested enum
208038
209377
  // usages — never requirements/parts; the old fallback offered the view list.
208039
209378
  enum: ["enum"],
208040
- calc: ["attribute", "calc"],
209379
+ calc: ["in parameter", "attribute", "calc"],
208041
209380
  connection: ["attribute", "item", "part"],
208042
209381
  connector: ["attribute", "item", "part"],
208043
209382
  interface: ["port", "attribute", "item"],
@@ -208052,6 +209391,10 @@ var CHILD_KINDS = {
208052
209391
  control: [],
208053
209392
  terminate: [],
208054
209393
  pin: [],
209394
+ // REQ-376 — the banner of a constraint/calc parameter card.
209395
+ "in parameter": [],
209396
+ "out parameter": [],
209397
+ "inout parameter": [],
208055
209398
  // REQ-196 — a «performer» swimlane (OMG SysML v2 Part 1 §8.2.3.17, p.90). Its
208056
209399
  // members are the actions that part performs; the edit writes the action into
208057
209400
  // the OWNING action's body and a `perform` for it into the part.
@@ -208063,6 +209406,7 @@ var CHILD_KINDS = {
208063
209406
  function normalizedElementKeyword(keyword) {
208064
209407
  const normalized = keyword.trim().toLowerCase();
208065
209408
  let base = normalized.replace(/\s*def$/u, "").replace(/^(?:(?:abstract|variation|variant|ref|derived|readonly|individual|timeslice|snapshot|parallel)\s+)+/u, "").trim();
209409
+ if (/^(assert(?: not)?|assume|require) constraint$/u.test(base)) base = "constraint";
208066
209410
  const isDecision = base === "decide" || base === "decision";
208067
209411
  if ([
208068
209412
  "send action",
@@ -208164,15 +209508,37 @@ function relationToolsForNode(keyword, viewKind, shape) {
208164
209508
  case "exhibit":
208165
209509
  case "perform":
208166
209510
  return base === "part";
209511
+ // REQ-131 — the OMG corpus asserts inside a part or a package
209512
+ // (ConstraintTest.sysml, MassConstraintExample.sysml); a case and
209513
+ // a requirement own constraints of their own.
209514
+ case "assert":
209515
+ return [
209516
+ "part",
209517
+ "item",
209518
+ "package",
209519
+ "requirement",
209520
+ "concern",
209521
+ "use case",
209522
+ "analysis case",
209523
+ "verification case",
209524
+ "case"
209525
+ ].includes(base);
209526
+ // REQ-131 — OMG SysML 8.2.2.21.1: a RequirementConstraintMembership
209527
+ // belongs to a requirement or a concern.
209528
+ case "assume":
209529
+ case "require":
209530
+ return ["requirement", "concern"].includes(base);
208167
209531
  default:
208168
209532
  return true;
208169
209533
  }
208170
209534
  }
208171
209535
  if (viewKind === "iv") {
208172
209536
  if (!["part", "port", "attribute", "item", "connection"].includes(base)) return false;
209537
+ if (tool.kind === "assert") return base === "part" || base === "item";
208173
209538
  return tool.kind === "interface" ? base === "port" : true;
208174
209539
  }
208175
209540
  if (viewKind === "afv") {
209541
+ if (base === "calc") return tool.kind === "succession" || tool.kind === "begin";
208176
209542
  if (base === "action") return tool.kind === "succession" || tool.kind === "begin" || tool.kind === "guard" || tool.kind === "terminate" || tool.kind === TERMINAL_RELATION;
208177
209543
  if (base === "control") return tool.kind === "succession" || tool.kind === "begin" || tool.kind === "guard" || isDecision && tool.kind === "else" || tool.kind === "terminate" || tool.kind === TERMINAL_RELATION;
208178
209544
  if (base === "port") return false;
@@ -208604,7 +209970,7 @@ function GvDisclosure({ element, svgWidth }) {
208604
209970
  }
208605
209971
  );
208606
209972
  }
208607
- function AttributeValueEditor({ id: id2, name, value, top }) {
209973
+ function AttributeValueEditor({ id: id2, name, value, top, label = "Value", placeholder = "Add value" }) {
208608
209974
  const { onSetElementValue } = useDiagram();
208609
209975
  const [draft, setDraft] = (0, import_react9.useState)(value);
208610
209976
  if (!onSetElementValue) return null;
@@ -208614,8 +209980,8 @@ function AttributeValueEditor({ id: id2, name, value, top }) {
208614
209980
  type: "text",
208615
209981
  className: "dattribute-value nodrag nopan nowheel",
208616
209982
  style: { top },
208617
- "aria-label": "Value of " + name,
208618
- placeholder: "Add value",
209983
+ "aria-label": label + " of " + name,
209984
+ placeholder,
208619
209985
  value: draft,
208620
209986
  onPointerDown: (event) => event.stopPropagation(),
208621
209987
  onClick: (event) => event.stopPropagation(),
@@ -209026,12 +210392,17 @@ function titleNameLine(name, type, mult, alias, availPx) {
209026
210392
  const shown = fitText(full, availPx, 11);
209027
210393
  return { full, shown, clipped: shown !== full };
209028
210394
  }
209029
- function AttributeValueShape({ value, w, top }) {
209030
- const shown = fitText(value || "Add value", Math.max(16, w - 32), 11);
210395
+ function valueFieldRole(keyword) {
210396
+ if (/\bconstraint(?:\s+def)?$/u.test(keyword)) return { label: "Constraint", placeholder: "Add constraint" };
210397
+ if (keyword.startsWith("calc")) return { label: "Expression", placeholder: "Add expression" };
210398
+ return { label: "Value", placeholder: "Add value" };
210399
+ }
210400
+ function AttributeValueShape({ value, w, top, placeholder = "Add value" }) {
210401
+ const shown = fitText(value || placeholder, Math.max(16, w - 32), 11);
209031
210402
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("g", { className: "dattribute-value-shape", children: [
209032
210403
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: 8, y: top, width: Math.max(1, w - 16), height: 28, rx: 3 }),
209033
210404
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("text", { x: 15, y: top + 18, className: "dnode-label", children: [
209034
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("title", { children: value || "Add value" }),
210405
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("title", { children: value || placeholder }),
209035
210406
  shown
209036
210407
  ] })
209037
210408
  ] });
@@ -209078,7 +210449,15 @@ function BoxBody({ node, w, h, showMult }) {
209078
210449
  ] })
209079
210450
  ] }),
209080
210451
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Compartments, { node, w, ruleClass }),
209081
- node.value !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AttributeValueShape, { value: node.value, w, top: h - 36 }) : null
210452
+ node.value !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
210453
+ AttributeValueShape,
210454
+ {
210455
+ value: node.value,
210456
+ w,
210457
+ top: h - 36,
210458
+ placeholder: valueFieldRole(node.keyword).placeholder
210459
+ }
210460
+ ) : null
209082
210461
  ] });
209083
210462
  }
209084
210463
  function RoundedBody({ node, w, h, cls, showMult }) {
@@ -209262,7 +210641,7 @@ function SendAcceptBody({ node, w, h, accept }) {
209262
210641
  }
209263
210642
  function PackageBody({ node, w, h }) {
209264
210643
  if (node.meta?.gvMode !== void 0) {
209265
- const title = fitText(node.name, Math.max(24, w - 42), 11);
210644
+ const title = fitText(node.name, Math.max(24, w - (node.meta?.gvCanExpand === true ? 42 : 20)), 11);
209266
210645
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("g", { children: [
209267
210646
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { className: "dnode-rect package", d: packageFramePath(w, h) }),
209268
210647
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("text", { className: "dnode-kind", x: 10, y: 12, children: "\xABpackage\xBB" }),
@@ -210032,7 +211411,7 @@ function SysmlNode({ id: id2, data, draggable, selected: selected2, width, heigh
210032
211411
  internalsVisible: !hiddenContainer,
210033
211412
  featureCompartmentsVisible,
210034
211413
  cornerRadius: nodeCornerRadius(node.shape, node.isDef, h, (node.compartments?.length ?? 0) > 0),
210035
- onToggleInternals: ctx.onToggleInternals,
211414
+ onToggleInternals: node.meta?.internalsExpandable === true ? ctx.onToggleInternals : void 0,
210036
211415
  onToggleFeatureCompartments: ctx.onToggleFeatureCompartments
210037
211416
  }
210038
211417
  ) : null,
@@ -210042,7 +211421,8 @@ function SysmlNode({ id: id2, data, draggable, selected: selected2, width, heigh
210042
211421
  id: id2,
210043
211422
  name: node.name,
210044
211423
  value: node.value,
210045
- top: h - 36
211424
+ top: h - 36,
211425
+ ...valueFieldRole(node.keyword)
210046
211426
  },
210047
211427
  id2 + ":" + node.value
210048
211428
  ) : null,
@@ -210289,7 +211669,15 @@ function FrameNode({ id: id2, data, selected: selected2, width, height }) {
210289
211669
  strokeWidth: 0.8
210290
211670
  }
210291
211671
  ) : null,
210292
- frame2.value !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AttributeValueShape, { value: frame2.value, w, top: frameHeaderHeight - 34 }) : null,
211672
+ frame2.value !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
211673
+ AttributeValueShape,
211674
+ {
211675
+ value: frame2.value,
211676
+ w,
211677
+ top: frameHeaderHeight - 34,
211678
+ placeholder: valueFieldRole(frame2.keyword).placeholder
211679
+ }
211680
+ ) : null,
210293
211681
  isStructuredControl ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("g", { className: "dstructured-condition-compartment", children: [
210294
211682
  isNamedStructuredAction ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
210295
211683
  "line",
@@ -210555,7 +211943,7 @@ function FrameNode({ id: id2, data, selected: selected2, width, height }) {
210555
211943
  internalsVisible: true,
210556
211944
  featureCompartmentsVisible,
210557
211945
  cornerRadius: frame2.isDef === true ? 0 : FRAME_USAGE_CORNER_RADIUS,
210558
- onToggleInternals: ctx.onToggleInternals,
211946
+ onToggleInternals: frame2.meta?.internalsExpandable === true ? ctx.onToggleInternals : void 0,
210559
211947
  onToggleFeatureCompartments: ctx.onToggleFeatureCompartments
210560
211948
  }
210561
211949
  ) : null,
@@ -210565,7 +211953,8 @@ function FrameNode({ id: id2, data, selected: selected2, width, height }) {
210565
211953
  id: id2,
210566
211954
  name: frame2.label,
210567
211955
  value: frame2.value,
210568
- top: frameHeaderHeight - 34
211956
+ top: frameHeaderHeight - 34,
211957
+ ...valueFieldRole(frame2.keyword)
210569
211958
  },
210570
211959
  id2 + ":" + frame2.value
210571
211960
  ) : null,
@@ -211260,7 +212649,7 @@ async function runExport(command) {
211260
212649
  }
211261
212650
 
211262
212651
  // src/main.ts
211263
- var VERSION2 = true ? "0.36.0" : "dev";
212652
+ var VERSION2 = true ? "0.39.0" : "dev";
211264
212653
  function display(file) {
211265
212654
  const rel2 = path9.relative(process.cwd(), file);
211266
212655
  return rel2 && !rel2.startsWith("..") ? rel2.split(path9.sep).join("/") : file;