sysml-diagram 0.36.0 → 0.38.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,125 @@ 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 constraintReferenceOf(node) {
161064
+ const kind = REFERENCE_KEYWORDS[node.$type];
161065
+ if (!kind)
161066
+ return void 0;
161067
+ const shape = node;
161068
+ if (shape.constraintKw)
161069
+ return void 0;
161070
+ const negated = shape.isNegated === true;
161071
+ if (kind === "assert") {
161072
+ if (!shape.name)
161073
+ return void 0;
161074
+ const links = [shape.name, ...shape.chainSegs ?? []];
161075
+ return { kind, negated, path: links.join("::"), simpleName: links[links.length - 1] };
161076
+ }
161077
+ const target = shape.target;
161078
+ if (typeof target !== "string" || target.length === 0)
161079
+ return void 0;
161080
+ return {
161081
+ kind,
161082
+ negated,
161083
+ property: "target",
161084
+ path: target,
161085
+ simpleName: lastLink(target)
161086
+ };
161087
+ }
161088
+ function lastLink(path10) {
161089
+ return path10.split(/::|\./u).filter(Boolean).pop() ?? path10;
161090
+ }
161091
+ var NON_CONSTRAINT_DECL_TYPES = /* @__PURE__ */ new Set([
161092
+ "Package",
161093
+ "NamespaceDecl",
161094
+ "Document",
161095
+ "Import",
161096
+ "PartDecl",
161097
+ "ItemDecl",
161098
+ "AttributeDecl",
161099
+ "PortDecl",
161100
+ "OccurrenceDecl",
161101
+ "InterfaceDecl",
161102
+ "ConnectionDecl",
161103
+ "AllocationDecl",
161104
+ "ConnectorDecl",
161105
+ "EnumDecl",
161106
+ "EnumValueDecl",
161107
+ "MetadataDecl",
161108
+ "MultiplicityDecl",
161109
+ "ActionDecl",
161110
+ "StateDecl",
161111
+ "CalcDecl",
161112
+ "CaseDecl",
161113
+ "UseCaseDecl",
161114
+ "AnalysisCaseDecl",
161115
+ "VerificationCaseDecl",
161116
+ "ViewDecl",
161117
+ "ViewpointDecl",
161118
+ "RenderingDecl",
161119
+ "ActorDecl",
161120
+ "StakeholderDecl",
161121
+ "StructDecl",
161122
+ "ClassDecl",
161123
+ "DatatypeDecl",
161124
+ "AssociationDecl",
161125
+ "MetaclassDecl",
161126
+ "BehaviorDecl",
161127
+ "FunctionDecl",
161128
+ "InteractionDecl"
161129
+ ]);
161130
+ var NON_CONSTRAINT_LABELS = {
161131
+ Package: "a package",
161132
+ NamespaceDecl: "a namespace",
161133
+ Document: "a file root namespace",
161134
+ Import: "an import",
161135
+ PartDecl: "a part",
161136
+ ItemDecl: "an item",
161137
+ AttributeDecl: "an attribute",
161138
+ PortDecl: "a port",
161139
+ OccurrenceDecl: "an occurrence",
161140
+ InterfaceDecl: "an interface",
161141
+ ConnectionDecl: "a connection",
161142
+ AllocationDecl: "an allocation",
161143
+ ConnectorDecl: "a connector",
161144
+ EnumDecl: "an enumeration",
161145
+ EnumValueDecl: "an enumeration value",
161146
+ MetadataDecl: "a metadata usage",
161147
+ MultiplicityDecl: "a multiplicity",
161148
+ ActionDecl: "an action",
161149
+ StateDecl: "a state",
161150
+ CalcDecl: "a calculation",
161151
+ CaseDecl: "a case",
161152
+ UseCaseDecl: "a use case",
161153
+ AnalysisCaseDecl: "an analysis case",
161154
+ VerificationCaseDecl: "a verification case",
161155
+ ViewDecl: "a view",
161156
+ ViewpointDecl: "a viewpoint",
161157
+ RenderingDecl: "a rendering",
161158
+ ActorDecl: "an actor",
161159
+ StakeholderDecl: "a stakeholder",
161160
+ StructDecl: "a structure",
161161
+ ClassDecl: "a class",
161162
+ DatatypeDecl: "a datatype",
161163
+ AssociationDecl: "an association",
161164
+ MetaclassDecl: "a metaclass",
161165
+ BehaviorDecl: "a behavior",
161166
+ FunctionDecl: "a function",
161167
+ InteractionDecl: "an interaction"
161168
+ };
161169
+ function isWrongKindConstraintTarget(node) {
161170
+ return NON_CONSTRAINT_DECL_TYPES.has(node.$type);
161171
+ }
161172
+ function wrongKindLabel(node) {
161173
+ return NON_CONSTRAINT_LABELS[node.$type] ?? "not a constraint";
161174
+ }
161175
+
161057
161176
  // ../language-server/out/src/services/requirement-semantics.js
161058
161177
  var DEFAULT_SUBJECT_TYPE = "Anything";
161059
161178
  var MAX_INHERITANCE_DEPTH = 16;
@@ -161071,6 +161190,16 @@ var REQUIREMENT_SHAPED = /* @__PURE__ */ new Set([
161071
161190
  "ObjectiveDecl",
161072
161191
  "ViewpointDecl"
161073
161192
  ]);
161193
+ var CASE_SHAPED = /* @__PURE__ */ new Set([
161194
+ "CaseDecl",
161195
+ "AnalysisCaseDecl",
161196
+ "VerificationCaseDecl",
161197
+ "UseCaseDecl"
161198
+ ]);
161199
+ var SUBJECT_SHAPED = /* @__PURE__ */ new Set([
161200
+ ...REQUIREMENT_SHAPED,
161201
+ ...CASE_SHAPED
161202
+ ]);
161074
161203
  var CONSTRAINT_SHAPED = /* @__PURE__ */ new Set([
161075
161204
  "ConstraintDecl",
161076
161205
  "InvShorthand",
@@ -161178,9 +161307,10 @@ function referencePathOf(member) {
161178
161307
  return target.trim() || void 0;
161179
161308
  if (target && typeof target === "object") {
161180
161309
  const text = target.$refText?.trim();
161181
- return text || void 0;
161310
+ if (text)
161311
+ return text;
161182
161312
  }
161183
- return void 0;
161313
+ return constraintReferenceOf(member)?.path;
161184
161314
  }
161185
161315
  function referenceTargetOf(member, resolve8) {
161186
161316
  const target = member.target;
@@ -161361,7 +161491,7 @@ function inheritedSubject(node, resolve8, depth, seen) {
161361
161491
  return void 0;
161362
161492
  seen.add(node);
161363
161493
  for (const supertype of supertypesOf(node, resolve8)) {
161364
- if (!REQUIREMENT_SHAPED.has(supertype.$type))
161494
+ if (!SUBJECT_SHAPED.has(supertype.$type))
161365
161495
  continue;
161366
161496
  const own = ownSubject(supertype);
161367
161497
  if (own)
@@ -161685,7 +161815,7 @@ function memberNamed(node, name, seen = /* @__PURE__ */ new Set()) {
161685
161815
  const typeRef = node.typing?.type?.ref;
161686
161816
  return typeRef ? memberNamed(typeRef, name, seen) : void 0;
161687
161817
  }
161688
- function resolveFeatureValue(root4, segments) {
161818
+ function resolveFeatureValue(root4, segments, ext) {
161689
161819
  let cur = root4;
161690
161820
  for (const seg of segments) {
161691
161821
  cur = memberNamed(cur, seg);
@@ -161693,7 +161823,7 @@ function resolveFeatureValue(root4, segments) {
161693
161823
  return UNRESOLVED;
161694
161824
  }
161695
161825
  if (cur.value)
161696
- return evaluateExpr(cur.value, () => INCONCLUSIVE);
161826
+ return evaluateExpr(cur.value, () => INCONCLUSIVE, ext);
161697
161827
  return INCONCLUSIVE;
161698
161828
  }
161699
161829
  function subjectScope(subjectName, subjectBinding) {
@@ -161788,6 +161918,83 @@ function evaluateSatisfy(stmt, resolveRequirement, resolvePart, resolve8) {
161788
161918
  const status = result.status === "pass" ? "fail" : result.status === "fail" ? "pass" : result.status;
161789
161919
  return { status, requirement, satisfier };
161790
161920
  }
161921
+ var CONSTRAINT_SHAPED_TYPES = /* @__PURE__ */ new Set([
161922
+ "ConstraintDecl",
161923
+ "InvShorthand",
161924
+ "RequirementDecl",
161925
+ "ConcernDecl",
161926
+ "PredicateDecl",
161927
+ "AssertConstraintStmt",
161928
+ "RequireConstraintStmt",
161929
+ "AssumeConstraintStmt"
161930
+ ]);
161931
+ function exprText2(node) {
161932
+ return node?.$cstNode?.text?.trim() ?? "";
161933
+ }
161934
+ function rootOf2(node) {
161935
+ let current2 = node;
161936
+ while (current2.$container)
161937
+ current2 = current2.$container;
161938
+ return current2;
161939
+ }
161940
+ function* walkMembers(node) {
161941
+ for (const member of [...node.elements ?? [], ...node.members ?? []]) {
161942
+ yield member;
161943
+ yield* walkMembers(member);
161944
+ }
161945
+ }
161946
+ function documentConstraintResolver() {
161947
+ return (reference, member) => {
161948
+ for (const candidate of walkMembers(rootOf2(member))) {
161949
+ if (candidate.name === reference.simpleName && CONSTRAINT_SHAPED_TYPES.has(candidate.$type)) {
161950
+ return candidate;
161951
+ }
161952
+ }
161953
+ return void 0;
161954
+ };
161955
+ }
161956
+ var assertionExpression = (node) => {
161957
+ const expr = node;
161958
+ return (expr.$type === "NumericPrimary" || expr.$type === "PostfixOp") && expr.unit ? INCONCLUSIVE : void 0;
161959
+ };
161960
+ function evaluateAssertion(node, resolveConstraint = documentConstraintResolver()) {
161961
+ const member = node;
161962
+ if (member.$type !== "AssertConstraintStmt")
161963
+ return void 0;
161964
+ const reference = constraintReferenceOf(member);
161965
+ const negated = reference?.negated ?? member.isNegated === true;
161966
+ let body;
161967
+ let text;
161968
+ let target;
161969
+ if (reference) {
161970
+ text = `${reference.kind}${reference.negated ? " not" : ""} ${reference.path}`;
161971
+ target = resolveConstraint(reference, member);
161972
+ if (!target)
161973
+ return { status: "unresolved", text };
161974
+ body = member.body ?? constraintBodyOf(target, documentResolver(member));
161975
+ } else {
161976
+ body = member.body;
161977
+ text = exprText2(member.body);
161978
+ }
161979
+ if (!body)
161980
+ return { status: "inconclusive", text };
161981
+ const scope = (segments) => {
161982
+ for (const owner of [member, target]) {
161983
+ if (!owner)
161984
+ continue;
161985
+ if (memberNamed(owner, segments[0])) {
161986
+ return resolveFeatureValue(owner, segments, assertionExpression);
161987
+ }
161988
+ }
161989
+ return INCONCLUSIVE;
161990
+ };
161991
+ const value = negate2(evaluateExpr(body, scope, assertionExpression), negated);
161992
+ if (value.kind === "unresolved")
161993
+ return { status: "unresolved", text };
161994
+ if (value.kind !== "boolean")
161995
+ return { status: "inconclusive", text };
161996
+ return { status: value.value ? "pass" : "fail", text };
161997
+ }
161791
161998
  function bindingName(by) {
161792
161999
  const n2 = by;
161793
162000
  if (n2?.$type !== "PathExpr")
@@ -163036,6 +163243,21 @@ function unwrap(node) {
163036
163243
  }
163037
163244
  var namedChildrenByNode = /* @__PURE__ */ new WeakMap();
163038
163245
  var childrenByName = /* @__PURE__ */ new WeakMap();
163246
+ var REFERENCE_FORM_DECLARATIONS = {
163247
+ PerformStmt: "actionKw",
163248
+ EntryAction: "actionKw",
163249
+ DoAction: "actionKw",
163250
+ ExitAction: "actionKw",
163251
+ ExhibitStateDecl: "stateKw",
163252
+ AssertConstraintStmt: "constraintKw",
163253
+ EventDecl: "isOccurrence"
163254
+ };
163255
+ function isReferenceFormDeclaration(node) {
163256
+ const keyword = REFERENCE_FORM_DECLARATIONS[node.$type];
163257
+ if (!keyword)
163258
+ return false;
163259
+ return node[keyword] !== true;
163260
+ }
163039
163261
  function directNamedChildren(node) {
163040
163262
  const cached = namedChildrenByNode.get(node);
163041
163263
  if (cached)
@@ -163044,6 +163266,8 @@ function directNamedChildren(node) {
163044
163266
  const seen = /* @__PURE__ */ new Set();
163045
163267
  for (const raw of ast_utils_exports.streamContents(node)) {
163046
163268
  const child = unwrap(raw);
163269
+ if (isReferenceFormDeclaration(child))
163270
+ continue;
163047
163271
  if (!nameOf(child) || seen.has(child))
163048
163272
  continue;
163049
163273
  seen.add(child);
@@ -163525,7 +163749,7 @@ var FeaturePathResolver = class {
163525
163749
  }
163526
163750
  for (let owner = node.$container; owner; owner = owner.$container) {
163527
163751
  const declaredName3 = owner.name;
163528
- if (typeof declaredName3 === "string" && canonicalEscapedName(declaredName3) === name && !isSelfReference(owner, node)) {
163752
+ if (typeof declaredName3 === "string" && canonicalEscapedName(declaredName3) === name && !isReferenceFormDeclaration(owner) && !isSelfReference(owner, node)) {
163529
163753
  return this.targetForNode(owner, this.memberInventoryKnown(owner, snapshot));
163530
163754
  }
163531
163755
  if (boundVariableName(owner) === name) {
@@ -166341,6 +166565,16 @@ var directionOf = (node) => {
166341
166565
  return void 0;
166342
166566
  return mods.find((m) => m === "in" || m === "out" || m === "inout");
166343
166567
  };
166568
+ function parameterKeyword(node) {
166569
+ const direction = directionOf(node);
166570
+ if (!direction)
166571
+ return void 0;
166572
+ let owner = node.$container;
166573
+ while (owner?.$type === "PrefixMetadataMember" || owner?.$type === "MemberPrefixDecl") {
166574
+ owner = owner.$container;
166575
+ }
166576
+ return owner && (isConstraintDecl(owner) || isCalcDecl(owner)) ? `${direction} parameter` : void 0;
166577
+ }
166344
166578
  function keywordFor(node) {
166345
166579
  const n2 = node;
166346
166580
  if (node.$type === "VariantReference")
@@ -166402,6 +166636,9 @@ function keywordFor(node) {
166402
166636
  DoAction: "do action",
166403
166637
  ExitAction: "exit action"
166404
166638
  };
166639
+ const parameter = parameterKeyword(node);
166640
+ if (parameter)
166641
+ return parameter;
166405
166642
  if (t === "ActionDecl" && n2.inlineBody?.$type === "AcceptNode") {
166406
166643
  return "accept action";
166407
166644
  }
@@ -167879,6 +168116,19 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167879
168116
  const all = [...ast_utils_exports.streamAllContents(scope)];
167880
168117
  const annotationNodes = all.filter(isGvAnnotationNode);
167881
168118
  const annotationNodeSet = new Set(annotationNodes);
168119
+ const declaredOwnerOf = (node) => {
168120
+ let owner = node.$container;
168121
+ while (owner?.$type === "PrefixMetadataMember" || owner?.$type === "MemberPrefixDecl") {
168122
+ owner = owner.$container;
168123
+ }
168124
+ return owner;
168125
+ };
168126
+ const isDefinitionParameter = (node) => {
168127
+ if (directionOf(node) === void 0)
168128
+ return false;
168129
+ const owner = declaredOwnerOf(node);
168130
+ return !!owner && owner.isDef === true && (isConstraintDecl(owner) || isCalcDecl(owner));
168131
+ };
167882
168132
  const usageNodes = all.filter(isGvExplicitUsage);
167883
168133
  const usageNodeSet = new Set(usageNodes);
167884
168134
  const usageDefinitions = new Map(usageNodes.map((node) => [
@@ -167917,7 +168167,20 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167917
168167
  semanticOwners.set(member, found);
167918
168168
  return found;
167919
168169
  };
168170
+ const readsAsAttribute = (node) => isAttributeDecl(node) || isAttributeDecl(this.resolveType(node, index2));
168171
+ const implicitlyRedefined = (node) => {
168172
+ const name = nameOf2(node);
168173
+ const owner = semanticOwner(node);
168174
+ if (!name || !owner || owner.isDef === true)
168175
+ return void 0;
168176
+ const definition = usageDefinitions.get(owner);
168177
+ if (!definition)
168178
+ return void 0;
168179
+ return membersOf(definition).find((member) => nameOf2(member) === name);
168180
+ };
167920
168181
  const attributeUsages = new Set(usageNodes.filter((node) => {
168182
+ if (isDefinitionParameter(node))
168183
+ return false;
167921
168184
  if (isAttributeDecl(node))
167922
168185
  return true;
167923
168186
  const owner = semanticOwner(node);
@@ -167928,12 +168191,23 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167928
168191
  const definition = usageDefinitions.get(node);
167929
168192
  if (definition && isAttributeDecl(definition))
167930
168193
  return true;
167931
- return redefinitionTargetsOf(node).some((target) => {
168194
+ if (redefinitionTargetsOf(node).some((target) => {
167932
168195
  const inherited = this.resolveFeatureInheritanceTarget(node, target, index2, /* @__PURE__ */ new Set());
167933
168196
  return inherited && isAttributeDecl(inherited);
167934
- });
168197
+ }))
168198
+ return true;
168199
+ const implicit = implicitlyRedefined(node);
168200
+ return !!implicit && readsAsAttribute(implicit);
167935
168201
  }));
167936
168202
  const attributeValue = (node) => valueTextOf(node) ?? node.default?.value?.$cstNode?.text ?? "";
168203
+ const returnMemberOf = (node) => membersOf(node).find((m) => m.$type === "ReturnDecl");
168204
+ const expressionBody = (node) => {
168205
+ const ret = isCalcDecl(node) ? returnMemberOf(node) : void 0;
168206
+ const text = ret ? valueTextOf(ret) ?? "" : node.body?.$cstNode?.text ?? "";
168207
+ return text.replace(/\s+/g, " ").trim();
168208
+ };
168209
+ const declaresExpression = (node) => node.body !== void 0 || isCalcDecl(node) && valueTextOf(returnMemberOf(node)) !== void 0;
168210
+ const showsExpressionField = (node) => (isConstraintDecl(node) || isCalcDecl(node)) && (node.isDef === true || declaresExpression(node));
167937
168211
  const ids = /* @__PURE__ */ new Map();
167938
168212
  const unnamedOrdinals = /* @__PURE__ */ new Map();
167939
168213
  const semanticId = (node) => {
@@ -167989,6 +168263,8 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
167989
168263
  multiplicity: this.multText(n2),
167990
168264
  type: typeText(n2) ?? (usageDefinitions.get(n2) ? nameOf2(usageDefinitions.get(n2)) : void 0),
167991
168265
  ...attributeUsages.has(n2) ? { value: attributeValue(n2) } : {},
168266
+ // REQ-208/209 — the constraint or calculation expression field.
168267
+ ...showsExpressionField(n2) ? { value: expressionBody(n2) } : {},
167992
168268
  compartments: extra?.compartments ?? this.compartmentsFor(n2, uri, index2, shape === "box"),
167993
168269
  ...packageOf2(n2),
167994
168270
  source: sourceOf2(n2, uri),
@@ -168003,9 +168279,60 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
168003
168279
  for (const usage of usageNodes) {
168004
168280
  pushNode(usage, "box", false, {
168005
168281
  compartments: this.compartmentsFor(usage, uri, index2, true, false),
168006
- ...attributeUsages.has(usage) ? { keyword: "attribute" } : {}
168282
+ // REQ-376 a parameter keeps its own banner; only an ordinary
168283
+ // attribute usage is relabelled by its value-carrying role.
168284
+ ...attributeUsages.has(usage) && !parameterKeyword(usage) ? { keyword: "attribute" } : {}
168007
168285
  });
168008
168286
  }
168287
+ for (const usage of usageNodes) {
168288
+ if (!isConstraintDecl(usage) || usage.isDef === true)
168289
+ continue;
168290
+ const definition = usageDefinitions.get(usage);
168291
+ if (!definition || !isConstraintDecl(definition))
168292
+ continue;
168293
+ const usageId = semanticId(usage);
168294
+ const local = new Set(membersOf(usage).flatMap((member) => [nameOf2(member), ...redefinitionTargetsOf(member)]).filter((name) => !!name));
168295
+ for (const member of membersOf(definition)) {
168296
+ const name = nameOf2(member);
168297
+ if (!name || local.has(name))
168298
+ continue;
168299
+ if (directionOf(member) === void 0 && !isAttributeDecl(member))
168300
+ continue;
168301
+ const id2 = `${usageId}::${name}`;
168302
+ if (nodes.some((existing) => existing.id === id2))
168303
+ continue;
168304
+ nodes.push({
168305
+ id: id2,
168306
+ name: effectiveNameOf(member) ?? name,
168307
+ keyword: "attribute",
168308
+ isDef: false,
168309
+ shape: "box",
168310
+ multiplicity: this.multText(member),
168311
+ type: typeText(member),
168312
+ value: attributeValue(member),
168313
+ compartments: [],
168314
+ parent: usageId,
168315
+ // Navigation lands on the declaration the member comes from.
168316
+ source: sourceOf2(member, uri),
168317
+ meta: {
168318
+ gvUsage: true,
168319
+ gvOwnerId: usageId,
168320
+ gvExplicit: true,
168321
+ gvDeclaredName: name,
168322
+ gvDeclaredType: typeText(member) ?? "",
168323
+ // REQ-364 — the concrete usage that owns a local edit, plus
168324
+ // the relative redefinition path to write inside it.
168325
+ localUsageId: usageId,
168326
+ localUsageName: nameOf2(usage),
168327
+ localUsageSource: sourceOf2(usage, uri),
168328
+ localUsagePath: [name],
168329
+ expandedFromDefinition: true,
168330
+ declarationId: qnameOf(member),
168331
+ declarationSource: sourceOf2(member, uri)
168332
+ }
168333
+ });
168334
+ }
168335
+ }
168009
168336
  for (const p of packageNodes) {
168010
168337
  const pn = p;
168011
168338
  pushNode(p, "package", false, {
@@ -168322,6 +168649,28 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
168322
168649
  }
168323
168650
  }
168324
168651
  }
168652
+ const CLAIM_EDGE_KINDS = {
168653
+ AssertConstraintStmt: "assert",
168654
+ AssumeConstraintStmt: "assume",
168655
+ RequireConstraintStmt: "require"
168656
+ };
168657
+ for (const owner of [...defNodes, ...usageNodes]) {
168658
+ for (const m of membersOf(owner)) {
168659
+ const claim = CLAIM_EDGE_KINDS[m.$type];
168660
+ if (!claim)
168661
+ continue;
168662
+ const negated = m.isNegated === true;
168663
+ const label = `\xAB${claim}${negated ? " not" : ""}\xBB`;
168664
+ const reference = constraintReferenceOf(m);
168665
+ if (reference) {
168666
+ linkByName(claim, owner, reference.path, label, m);
168667
+ continue;
168668
+ }
168669
+ const typed = typeText(m);
168670
+ if (typed)
168671
+ linkByName(claim, owner, typed, label, m);
168672
+ }
168673
+ }
168325
168674
  const allocPairs = [
168326
168675
  ...all.filter((m) => m.$type === "AllocateStmt").map((a2) => ({
168327
168676
  from: String(a2.source ?? ""),
@@ -172388,7 +172737,12 @@ ${node.id}`;
172388
172737
  idOf.set(n2, id2);
172389
172738
  nodes.push({
172390
172739
  id: id2,
172391
- name: nameOf2(n2) ?? lastSeg(typeText(n2) ?? "subject"),
172740
+ // REQ-404 — a redeclaration (`actor :>> driver = …`) writes no name
172741
+ // of its own; the name it is KNOWN BY is the one it redefines, which
172742
+ // is the same derivation the rest of the model is labelled by. The
172743
+ // last-resort fallback is the SHAPE, never the literal 'subject':
172744
+ // that string labelled every unnamed actor "subject" on the card.
172745
+ name: effectiveNameOf(n2) ?? lastSeg(typeText(n2) ?? shape),
172392
172746
  keyword: keywordFor(n2),
172393
172747
  isDef: n2.isDef === true,
172394
172748
  shape,
@@ -172432,14 +172786,15 @@ ${node.id}`;
172432
172786
  const declarationKey = (subject) => {
172433
172787
  const type = this.resolveType(subject, index2);
172434
172788
  const typeKey = (type ? qnameOf(type) : void 0) || typeText(subject) || "";
172435
- const name = nameOf2(subject) ?? "";
172789
+ const name = effectiveNameOf(subject) ?? "";
172436
172790
  return name || typeKey ? `subject:${name}|${typeKey}` : "";
172437
172791
  };
172438
172792
  const declarationText = (subject) => {
172439
172793
  const value = subjectValuePath(subject);
172440
172794
  const type = typeText(subject);
172441
- return [nameOf2(subject), type ? `: ${type}` : void 0, value ? `= ${value}` : void 0].filter((part) => !!part).join(" ");
172795
+ return [effectiveNameOf(subject), type ? `: ${type}` : void 0, value ? `= ${value}` : void 0].filter((part) => !!part).join(" ");
172442
172796
  };
172797
+ const boundKeysOfDeclaration = /* @__PURE__ */ new Map();
172443
172798
  const subjectKey = (subject, seen = /* @__PURE__ */ new Set()) => {
172444
172799
  const canonical = canonicalSubjectTarget(subject);
172445
172800
  if (canonical && isSubjectDecl(canonical) && canonical !== subject && !seen.has(canonical)) {
@@ -172448,7 +172803,14 @@ ${node.id}`;
172448
172803
  }
172449
172804
  const canonicalQName = canonical && !isSubjectDecl(canonical) ? qnameOf(canonical) : "";
172450
172805
  const value = subjectValuePath(subject);
172451
- return canonicalQName ? `target:${canonicalQName}` : value ? `value:${value}` : declarationKey(subject) || `decl:${qnameOf(subject) || `${subject.$cstNode?.offset ?? 0}:subject`}`;
172806
+ if (canonicalQName)
172807
+ return `target:${canonicalQName}`;
172808
+ if (value)
172809
+ return `value:${value}`;
172810
+ const adopted = boundKeysOfDeclaration.get(subject);
172811
+ if (adopted?.size === 1)
172812
+ return [...adopted][0];
172813
+ return declarationKey(subject) || `decl:${qnameOf(subject) || `${subject.$cstNode?.offset ?? 0}:subject`}`;
172452
172814
  };
172453
172815
  const subjectIdByKey = /* @__PURE__ */ new Map();
172454
172816
  const subjectOfCase = /* @__PURE__ */ new Map();
@@ -172459,7 +172821,7 @@ ${node.id}`;
172459
172821
  const key2 = subjectKey(subject);
172460
172822
  let sid = subjectIdByKey.get(key2);
172461
172823
  if (!sid) {
172462
- const label = nameOf2(identity6) ?? lastSeg(value || typeText(identity6) || "subject");
172824
+ const label = effectiveNameOf(identity6) ?? lastSeg(value || typeText(identity6) || "subject");
172463
172825
  add(identity6, "subject", {
172464
172826
  id: `${scopeId}::__cv_subject__::${key2}`,
172465
172827
  name: label,
@@ -172471,6 +172833,26 @@ ${node.id}`;
172471
172833
  idOf.set(subject, sid);
172472
172834
  return sid;
172473
172835
  };
172836
+ for (const c of displayedCases) {
172837
+ const declared = declaredMembers(c).filter(isSubjectDecl);
172838
+ for (const bound of declared) {
172839
+ if (!subjectValuePath(bound))
172840
+ continue;
172841
+ const name = effectiveNameOf(bound);
172842
+ if (!name)
172843
+ continue;
172844
+ for (const target of declared) {
172845
+ if (target === bound || subjectValuePath(target))
172846
+ continue;
172847
+ if (effectiveNameOf(target) !== name)
172848
+ continue;
172849
+ let keys3 = boundKeysOfDeclaration.get(target);
172850
+ if (!keys3)
172851
+ boundKeysOfDeclaration.set(target, keys3 = /* @__PURE__ */ new Set());
172852
+ keys3.add(subjectKey(bound));
172853
+ }
172854
+ }
172855
+ }
172474
172856
  const denotesSubject = (s) => !!(nameOf2(s) || typeText(s) || subjectValuePath(s));
172475
172857
  for (const c of displayedCases) {
172476
172858
  const declared = declaredMembers(c).filter(isSubjectDecl);
@@ -172513,16 +172895,47 @@ ${node.id}`;
172513
172895
  };
172514
172896
  const actorOfCase = [];
172515
172897
  const actorCasePairs = /* @__PURE__ */ new Set();
172516
- const anonymousActorId = (actor) => nameOf2(actor) ? void 0 : `${scopeId}::__cv_actor__::${qnameOf(actor)}:${actor.$cstNode?.offset ?? 0}`;
172898
+ const actorTypeKey = (actor) => {
172899
+ const type = this.resolveType(actor, index2);
172900
+ return (type ? qnameOf(type) : void 0) || typeText(actor) || "";
172901
+ };
172902
+ const actorTypeSource = (actor, siblings) => {
172903
+ if (actorTypeKey(actor))
172904
+ return actor;
172905
+ const name = effectiveNameOf(actor);
172906
+ if (!name)
172907
+ return void 0;
172908
+ return siblings.find((sibling) => sibling !== actor && effectiveNameOf(sibling) === name && !!actorTypeKey(sibling));
172909
+ };
172910
+ const actorDeclarationKey = (actor, siblings) => {
172911
+ const name = effectiveNameOf(actor) ?? "";
172912
+ const typeKey = actorTypeKey(actorTypeSource(actor, siblings) ?? actor);
172913
+ return name || typeKey ? `actor:${name}|${typeKey}` : "";
172914
+ };
172915
+ const actorKey = (actor, siblings) => actorDeclarationKey(actor, siblings) || `decl:${qnameOf(actor) || ""}:${actor.$cstNode?.offset ?? 0}`;
172916
+ const actorIdByKey = /* @__PURE__ */ new Map();
172917
+ const addActor = (actor, siblings) => {
172918
+ const canonical = actorCanonical(actor);
172919
+ const key2 = actorKey(canonical, siblings);
172920
+ let aid = actorIdByKey.get(key2);
172921
+ if (aid === void 0) {
172922
+ const typeSource = actorTypeSource(canonical, siblings);
172923
+ add(canonical, "actor", {
172924
+ id: `${scopeId}::__cv_actor__::${key2}`,
172925
+ ...typeSource && typeSource !== canonical ? { type: typeText(typeSource) } : {},
172926
+ meta: { cvAuxiliary: true }
172927
+ });
172928
+ aid = idOf.get(canonical);
172929
+ actorIdByKey.set(key2, aid);
172930
+ }
172931
+ idOf.set(actor, aid);
172932
+ return aid;
172933
+ };
172517
172934
  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);
172935
+ const siblings = declaredMembers(c).filter(isActorDecl);
172936
+ const typeSources = siblings.some((a2) => !actorTypeKey(a2)) ? [...siblings, ...this.inheritedTypesOf(c, index2).flatMap((t) => membersOf(t).filter(isActorDecl))] : siblings;
172937
+ for (const a2 of siblings) {
172938
+ const actorId = addActor(a2, typeSources);
172526
172939
  const pair = `${actorId}\0${qnameOf(c) ?? nameOf2(c) ?? ""}`;
172527
172940
  if (!actorCasePairs.has(pair)) {
172528
172941
  actorCasePairs.add(pair);
@@ -174271,7 +174684,7 @@ ${node.id}`;
174271
174684
  const inherited = includeInherited ? this.inheritedItems(node, index2, uri) : [];
174272
174685
  const inheritedRows = (predicate, text = (member) => this.featureText(member)) => inherited.filter(({ member }) => predicate(member)).map(({ member, source }) => ({ text: `^${text(member)}`, source }));
174273
174686
  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();
174687
+ const exprText4 = (m) => (m.body?.$cstNode?.text ?? "").replace(/\s+/g, " ").trim();
174275
174688
  const statementText = (m) => (m.$cstNode?.text ?? this.featureText(m)).replace(/\s+/g, " ").replace(/;$/, "").trim();
174276
174689
  const canonicalFeatureText = (m) => m.$type === "FeatureShorthand" || m.$type === "FeatureRedefinitionShorthand" ? statementText(m) : this.featureText(m);
174277
174690
  const out = [];
@@ -174323,8 +174736,8 @@ ${node.id}`;
174323
174736
  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
174737
  add("calcs", undirected(isCalcDecl).map((m) => item(m)));
174325
174738
  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())));
174739
+ add("assume constraints", members.filter((m) => m.$type === "AssumeConstraintStmt").map((m) => item(m, exprText4(m) || "assume constraint")));
174740
+ add("require constraints", members.filter((m) => m.$type === "RequireConstraintStmt").map((m) => item(m, exprText4(m) || `require ${this.featurePath(m.target) ?? ""}`.trim())));
174328
174741
  add("actors", members.filter(isActorDecl).filter(isNonVariantMember).map((m) => item(m)));
174329
174742
  add("stakeholders", members.filter(isStakeholderDecl).filter(isNonVariantMember).map((m) => item(m)));
174330
174743
  add("frames", members.filter((m) => m.$type === "FrameMember").map((m) => item(m, this.refText(m.target) ?? "concern")));
@@ -174353,7 +174766,7 @@ ${node.id}`;
174353
174766
  ]);
174354
174767
  add("result", members.filter((m) => m.$type === "ReturnDecl").map((m) => item(m, `return${nameOf2(m) ? ` ${nameOf2(m)}` : ""}${typeText(m) ? ` : ${typeText(m)}` : ""}`)));
174355
174768
  if (isConstraintDecl(node))
174356
- add("expression", exprText3(node) ? [{ text: exprText3(node), source: sourceOf2(node, uri) }] : []);
174769
+ add("expression", exprText4(node) ? [{ text: exprText4(node), source: sourceOf2(node, uri) }] : []);
174357
174770
  const enumValueMembers = isEnumDecl(node) ? members.filter(isOwnedEnumerationValue) : members.filter((m) => isNonVariantMember(m) && m.$type === "EnumValueDecl" && !m.typing);
174358
174771
  add("enums", enumValueMembers.map((m) => {
174359
174772
  const nm = nameOf2(m);
@@ -174382,11 +174795,11 @@ ${node.id}`;
174382
174795
  add("state transition", members.filter((m) => m.$type === "TransitionDecl").map((m) => item(m, `${m.from ?? ""} \u2192 ${m.to ?? ""}`)));
174383
174796
  const successionText = (m) => (m.$cstNode?.text ?? "").replace(/\s+/g, " ").replace(/;$/, "").trim();
174384
174797
  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")));
174798
+ add("assert constraints", members.filter((m) => m.$type === "AssertConstraintStmt").map((m) => item(m, exprText4(m) || nameOf2(m) || "assert constraint")));
174386
174799
  add("invariants", members.filter((m) => m.$type === "InvShorthand").map((m) => {
174387
174800
  const inv = m;
174388
174801
  const head2 = `inv${inv.isNegated ? " false" : ""}${nameOf2(m) ? ` ${nameOf2(m)}` : ""}`;
174389
- const expr = exprText3(m);
174802
+ const expr = exprText4(m);
174390
174803
  return item(m, `${head2} { ${expr} }`.replace(/\s+/g, " ").trim());
174391
174804
  }));
174392
174805
  add("actions", usages(isActionDecl).map((m) => item(m)));
@@ -174643,8 +175056,12 @@ function projectGvCompartments(input) {
174643
175056
  continue;
174644
175057
  visible.add(node.id);
174645
175058
  const key2 = gvElementKey(node);
174646
- const open = gvElementIsExpanded(node, expanded2);
174647
- expandable.add(key2);
175059
+ const children2 = (index2.children.get(node.id) ?? []).filter(
175060
+ (child) => child.meta?.gvDerived !== true && child.meta?.connectionDefinitionHub !== true
175061
+ );
175062
+ const canExpand = children2.length > 0;
175063
+ const open = canExpand && gvElementIsExpanded(node, expanded2);
175064
+ if (canExpand) expandable.add(key2);
174648
175065
  nodes.push({
174649
175066
  ...node,
174650
175067
  parent,
@@ -174663,7 +175080,7 @@ function projectGvCompartments(input) {
174663
175080
  ...node.meta,
174664
175081
  gvMode: "group",
174665
175082
  gvExpansionKey: key2,
174666
- gvCanExpand: true,
175083
+ gvCanExpand: canExpand,
174667
175084
  gvExpanded: open,
174668
175085
  gvOpenContainer: open,
174669
175086
  internalsHidden: !open,
@@ -174671,7 +175088,7 @@ function projectGvCompartments(input) {
174671
175088
  }
174672
175089
  });
174673
175090
  if (open) {
174674
- for (const child of index2.children.get(node.id) ?? []) {
175091
+ for (const child of children2) {
174675
175092
  queue.push({ node: child, parent: node.id });
174676
175093
  }
174677
175094
  }
@@ -174707,10 +175124,10 @@ function projectGvTree(input) {
174707
175124
  visible.add(node.id);
174708
175125
  const isPackage2 = node.shape === "package";
174709
175126
  const children2 = (index2.children.get(node.id) ?? []).filter(
174710
- (child) => isPackage2 || isGvPartUsage(child)
175127
+ (child) => child.meta?.gvTreeExcluded !== true && !isDerivedHub(child) && (isPackage2 || isGvPartUsage(child))
174711
175128
  );
174712
175129
  const key2 = gvElementKey(node);
174713
- const canExpand = isPackage2 || children2.length > 0 || /\bpart\b/.test(node.keyword);
175130
+ const canExpand = children2.length > 0;
174714
175131
  const open = canExpand && gvElementIsExpanded(node, expanded2, true);
174715
175132
  if (canExpand) expandable.add(key2);
174716
175133
  nodes.push({
@@ -175761,6 +176178,283 @@ function resolveEffectiveSubject(node) {
175761
176178
  return void 0;
175762
176179
  }
175763
176180
 
176181
+ // ../language-server/out/src/services/case-semantics.js
176182
+ var CASE_KIND_BY_TYPE = /* @__PURE__ */ new Map([
176183
+ ["CaseDecl", "case"],
176184
+ ["AnalysisCaseDecl", "analysis"],
176185
+ ["VerificationCaseDecl", "verification"],
176186
+ ["UseCaseDecl", "use-case"]
176187
+ ]);
176188
+ var MAX_INHERITANCE_DEPTH2 = 16;
176189
+ function caseKindOf(node) {
176190
+ return node ? CASE_KIND_BY_TYPE.get(node.$type) : void 0;
176191
+ }
176192
+ function enclosingCase(node) {
176193
+ let current2 = node;
176194
+ while (current2) {
176195
+ if (CASE_SHAPED.has(current2.$type))
176196
+ return current2;
176197
+ current2 = current2.$container;
176198
+ }
176199
+ return void 0;
176200
+ }
176201
+ function writtenTypes(node, resolve8) {
176202
+ const out = [];
176203
+ for (const typing of [node.typing, ...node.moreTypings ?? []]) {
176204
+ if (!typing)
176205
+ continue;
176206
+ for (const ref of [typing.type, ...typing.moreTypes ?? []]) {
176207
+ if (!ref)
176208
+ continue;
176209
+ const name = ref.$refText?.trim() ?? ref.ref?.name;
176210
+ if (!name)
176211
+ continue;
176212
+ out.push({ name, node: ref.ref ?? resolve8(name) });
176213
+ }
176214
+ }
176215
+ return out;
176216
+ }
176217
+ function effectiveCaseDefinition(node, resolve8) {
176218
+ const kind = caseKindOf(node);
176219
+ if (!kind)
176220
+ return void 0;
176221
+ const decl = node;
176222
+ const resolver = resolve8 ?? documentResolver(node);
176223
+ const definitions = writtenTypes(decl, resolver).filter((type) => type.node === void 0 || CASE_SHAPED.has(type.node.$type));
176224
+ return {
176225
+ kind,
176226
+ isDefinition: decl.isDef === true,
176227
+ definitions,
176228
+ sole: definitions.length === 1 ? definitions[0] : void 0
176229
+ };
176230
+ }
176231
+ function hasAmbiguousDefinition(node, resolve8) {
176232
+ const effective = effectiveCaseDefinition(node, resolve8);
176233
+ if (!effective || effective.isDefinition)
176234
+ return false;
176235
+ return effective.definitions.filter((type) => type.node !== void 0).length > 1;
176236
+ }
176237
+ function isDecidedSubject(subject) {
176238
+ if (!subject)
176239
+ return false;
176240
+ return subject.origin !== "default" && subject.origin !== "ambiguous" && subject.typeName !== DEFAULT_SUBJECT_TYPE;
176241
+ }
176242
+ function effectiveCaseSubject(node, resolve8) {
176243
+ const resolver = resolve8 ?? documentResolver(node);
176244
+ if (hasAmbiguousDefinition(node, resolver)) {
176245
+ const own = ownSubject(node);
176246
+ return own ? subjectInfo(own, node, "own") : { typeName: DEFAULT_SUBJECT_TYPE, origin: "ambiguous" };
176247
+ }
176248
+ return effectiveSubject(node, resolver);
176249
+ }
176250
+ function ownActors(node) {
176251
+ return (node.members ?? []).filter((member) => member.$type === "ActorDecl");
176252
+ }
176253
+ function effectiveActors(node, resolve8) {
176254
+ const resolver = resolve8 ?? documentResolver(node);
176255
+ const ambiguous = hasAmbiguousDefinition(node, resolver);
176256
+ const out = [];
176257
+ const seenNodes = /* @__PURE__ */ new Set();
176258
+ const seenNames = /* @__PURE__ */ new Set();
176259
+ const walk = (current2, origin, depth) => {
176260
+ if (depth > MAX_INHERITANCE_DEPTH2 || seenNodes.has(current2))
176261
+ return;
176262
+ seenNodes.add(current2);
176263
+ for (const actor of ownActors(current2)) {
176264
+ if (actor.name && seenNames.has(actor.name))
176265
+ continue;
176266
+ if (actor.name)
176267
+ seenNames.add(actor.name);
176268
+ out.push({
176269
+ declaration: actor,
176270
+ name: actor.name,
176271
+ typeName: subjectTypeName(actor),
176272
+ origin,
176273
+ owner: current2
176274
+ });
176275
+ }
176276
+ if (ambiguous)
176277
+ return;
176278
+ for (const supertype of supertypesOf(current2, resolver)) {
176279
+ if (!CASE_SHAPED.has(supertype.$type))
176280
+ continue;
176281
+ walk(supertype, "inherited", depth + 1);
176282
+ }
176283
+ };
176284
+ walk(node, "own", 0);
176285
+ return out;
176286
+ }
176287
+ function caseResult(node, resolve8) {
176288
+ const resolver = resolve8 ?? documentResolver(node);
176289
+ const ambiguous = hasAmbiguousDefinition(node, resolver);
176290
+ const seen = /* @__PURE__ */ new Set();
176291
+ const walk = (current2, origin, depth) => {
176292
+ if (depth > MAX_INHERITANCE_DEPTH2 || seen.has(current2))
176293
+ return void 0;
176294
+ seen.add(current2);
176295
+ const own = (current2.members ?? []).find((member) => member.$type === "ReturnDecl");
176296
+ if (own) {
176297
+ return {
176298
+ declaration: own,
176299
+ name: own.name,
176300
+ typeName: subjectTypeName(own),
176301
+ origin,
176302
+ owner: current2
176303
+ };
176304
+ }
176305
+ if (ambiguous)
176306
+ return void 0;
176307
+ for (const supertype of supertypesOf(current2, resolver)) {
176308
+ if (!CASE_SHAPED.has(supertype.$type))
176309
+ continue;
176310
+ const inherited = walk(supertype, "inherited", depth + 1);
176311
+ if (inherited)
176312
+ return inherited;
176313
+ }
176314
+ return void 0;
176315
+ };
176316
+ return walk(node, "own", 0);
176317
+ }
176318
+ function objectiveBindingOf(objective, resolve8) {
176319
+ if (objective.$type !== "ObjectiveDecl")
176320
+ return void 0;
176321
+ const caseNode = enclosingCase(objective.$container);
176322
+ const caseKind = caseKindOf(caseNode);
176323
+ if (!caseNode || !caseKind)
176324
+ return void 0;
176325
+ const resolver = resolve8 ?? documentResolver(objective);
176326
+ const own = ownSubject(objective);
176327
+ const bindsSubject = caseKind === "verification" || caseKind === "use-case";
176328
+ if (bindsSubject) {
176329
+ const subject = effectiveCaseSubject(caseNode, resolver);
176330
+ return {
176331
+ objective,
176332
+ caseNode,
176333
+ caseKind,
176334
+ target: "case-subject",
176335
+ strength: "bind",
176336
+ boundTo: subject.declaration,
176337
+ // An undecided subject names no type: the case still binds its
176338
+ // objective to whatever its subject is, but neither hover nor
176339
+ // `SSM046` may say what that is.
176340
+ typeName: isDecidedSubject(subject) ? subject.typeName : void 0,
176341
+ own
176342
+ };
176343
+ }
176344
+ const result = caseResult(caseNode, resolver);
176345
+ return {
176346
+ objective,
176347
+ caseNode,
176348
+ caseKind,
176349
+ target: "case-result",
176350
+ strength: "default",
176351
+ boundTo: result?.declaration,
176352
+ typeName: result?.typeName,
176353
+ own
176354
+ };
176355
+ }
176356
+ function effectiveObjectiveSubject(objective, resolve8) {
176357
+ const resolver = resolve8 ?? documentResolver(objective);
176358
+ const binding = objectiveBindingOf(objective, resolver);
176359
+ const own = ownSubject(objective);
176360
+ if (!binding) {
176361
+ return own ? { declaration: own, name: own.name, typeName: subjectTypeName(own) ?? DEFAULT_SUBJECT_TYPE, origin: "own", owner: objective } : { typeName: DEFAULT_SUBJECT_TYPE, origin: "default" };
176362
+ }
176363
+ if (own && binding.strength === "default") {
176364
+ return {
176365
+ declaration: own,
176366
+ name: own.name,
176367
+ typeName: subjectTypeName(own) ?? DEFAULT_SUBJECT_TYPE,
176368
+ origin: "own",
176369
+ owner: objective
176370
+ };
176371
+ }
176372
+ return {
176373
+ declaration: binding.boundTo,
176374
+ typeName: binding.typeName ?? DEFAULT_SUBJECT_TYPE,
176375
+ origin: "enclosing",
176376
+ owner: binding.caseNode
176377
+ };
176378
+ }
176379
+ function objectiveSubrequirements(objective, resolve8) {
176380
+ if (objective.$type !== "ObjectiveDecl")
176381
+ return [];
176382
+ const resolver = resolve8 ?? documentResolver(objective);
176383
+ const subjectTypeName2 = effectiveObjectiveSubject(objective, resolver).typeName;
176384
+ const out = [];
176385
+ for (const member of objective.members ?? []) {
176386
+ if (member.$type === "VerifyStmt") {
176387
+ const path10 = referencePathOf(member);
176388
+ out.push({
176389
+ declaration: member,
176390
+ kind: "verify",
176391
+ path: path10,
176392
+ target: referenceTargetOf(member, resolver),
176393
+ subjectTypeName: subjectTypeName2
176394
+ });
176395
+ } else if (member.$type === "RequirementDecl") {
176396
+ out.push({ declaration: member, kind: "requirement", subjectTypeName: subjectTypeName2 });
176397
+ }
176398
+ }
176399
+ return out;
176400
+ }
176401
+ function valueSimpleName(value) {
176402
+ const node = value;
176403
+ if (!node)
176404
+ return void 0;
176405
+ if (node.$type === "ParenExpr") {
176406
+ const items = node.items ?? [];
176407
+ return items.length === 1 ? valueSimpleName(items[0]) : void 0;
176408
+ }
176409
+ if (node.$type !== "PathExpr")
176410
+ return void 0;
176411
+ return node.path ? simpleName(node.path) : void 0;
176412
+ }
176413
+ function includeBindingOf(stmt, resolve8) {
176414
+ if (stmt.$type !== "IncludeStmt")
176415
+ return void 0;
176416
+ const node = stmt;
176417
+ const resolver = resolve8 ?? documentResolver(stmt);
176418
+ const isUseCase = (candidate) => candidate !== void 0 && candidate.$type === "UseCaseDecl";
176419
+ const typed = writtenTypes(node, resolver).find((type) => type.node === void 0 || isUseCase(type.node));
176420
+ const path10 = referencePathOf(node);
176421
+ const named2 = typed?.node ?? (typed ? void 0 : referenceTargetOf(node, resolver));
176422
+ const target = isUseCase(named2) ? named2 : void 0;
176423
+ const form = node.useCaseKw === true || typed !== void 0 ? "declaration" : "reference";
176424
+ const containing = enclosingCase(node.$container);
176425
+ const parameters = target ? effectiveActors(target, resolver) : [];
176426
+ const actors = [];
176427
+ for (const member of node.members ?? []) {
176428
+ if (member.$type !== "ActorDecl")
176429
+ continue;
176430
+ const name = member.name;
176431
+ actors.push({
176432
+ declaration: member,
176433
+ name,
176434
+ valueName: valueSimpleName(member.value),
176435
+ typeName: subjectTypeName(member),
176436
+ parameter: name ? parameters.find((parameter) => parameter.name === name) : void 0
176437
+ });
176438
+ }
176439
+ const containingSubject = containing ? effectiveCaseSubject(containing, resolver) : void 0;
176440
+ const includedSubject = target ? effectiveCaseSubject(target, resolver) : void 0;
176441
+ const subjectOrigin = isDecidedSubject(includedSubject) ? "included" : isDecidedSubject(containingSubject) ? "containing" : "default";
176442
+ const subjectTypeName2 = subjectOrigin === "included" ? includedSubject.typeName : subjectOrigin === "containing" ? containingSubject.typeName : DEFAULT_SUBJECT_TYPE;
176443
+ return {
176444
+ statement: stmt,
176445
+ form,
176446
+ path: typed ? typed.name : path10,
176447
+ target,
176448
+ containing,
176449
+ containingSubject,
176450
+ includedSubject,
176451
+ subjectOrigin,
176452
+ subjectTypeName: subjectTypeName2,
176453
+ parameters,
176454
+ actors
176455
+ };
176456
+ }
176457
+
175764
176458
  // ../language-server/out/src/services/implicit-specialization.js
175765
176459
  var EXPLICIT_SPECIALIZATION_KINDS = /* @__PURE__ */ new Set([
175766
176460
  ":>",
@@ -176530,11 +177224,64 @@ var DIAGNOSTIC_MESSAGES = {
176530
177224
  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
177225
  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
177226
  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.`,
177227
+ // REQ-415 — issue #164. `assert c`, `require c` and `assume c` all reach their
177228
+ // constraint through the same OwnedReferenceSubsetting, so one message covers
177229
+ // the three. The kind is named because the fix depends on it: a part or an
177230
+ // action is not something that can be true or false.
177231
+ 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.`,
177232
+ // REQ-415 — the reference resolves and its constraint evaluates to a definite
177233
+ // false, so the model states something against itself. A warning, never an
177234
+ // error: the text is well formed, and only a closed constant expression is
177235
+ // decided at all - anything that depends on a binding stays silent.
177236
+ SEM014_ASSERTION_VIOLATED: (text) => `Asserted constraint '${text}' evaluates to false, so this model is inconsistent as written.`,
177237
+ // REQ-131 — a constraint is a predicate: `BooleanEvaluation` returns
177238
+ // `Boolean[1]` (Kernel Semantic Library, `Performances.kerml`). A body that is
177239
+ // demonstrably some other type can never be true or false. Only a body the
177240
+ // checker can PROVE is not Boolean is reported, so an expression whose type it
177241
+ // cannot settle stays silent.
177242
+ 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.`,
177243
+ // REQ-209 — a usage inherits its definition's expression. Replacing it hides
177244
+ // what the definition says while every other usage still reads the original.
177245
+ // Advisory: the language permits the redefinition, the modelling idiom does not
177246
+ // use it, and no model in the OMG corpus does.
177247
+ 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.`,
177248
+ /* REQ-376 — a parameter of a constraint or a calculation is an INPUT.
177249
+ *
177250
+ * A constraint is a predicate: its one output is its Boolean result, which
177251
+ * comes from the body, never from a parameter. A calculation produces its
177252
+ * value through `return`. Neither has anything to send back out through a
177253
+ * parameter, and the OMG corpus bears that out: 40 `in` parameters on
177254
+ * constraints and 44 on calculations, and not one `out` or `inout` on either.
177255
+ *
177256
+ * A constraint is also ACAUSAL — `StraightLineDynamicsEquations` declares even
177257
+ * the quantities it would be solved for (`x_f`, `v_f`, `a`) as `in`, because
177258
+ * which parameter is the unknown is the binding's business, not the
177259
+ * constraint's. Fixing a direction would bake in one solving order. */
177260
+ 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.`,
177261
+ // REQ-376 — a directed parameter is an input to be bound by a usage, not a
177262
+ // value slot. OMG declares parameters bare on a definition and puts values on
177263
+ // `attribute` members (`StraightLineDynamicsEquations`).
177264
+ 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
177265
  // issue #165 — a satisfaction binds a thing to the subject a requirement
176534
177266
  // constrains, so the thing has to BE one of those (OMG SysML v2 Part 1
176535
177267
  // §7.21.2). The message names both types because the fix is either to bind a
176536
177268
  // different satisfier or to widen the requirement's subject.
176537
177269
  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.`,
177270
+ // issue #166 — a case usage performs ONE case (OMG SysML v2 Part 1 §7.22.2),
177271
+ // and every effective binding this extension derives reads through that one:
177272
+ // the subject, the actor parameters and the objective. Two definitions leave
177273
+ // all three undecided, so the message names them and asks for one.
177274
+ 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.`,
177275
+ // issue #166 — an `objective` written inside a verification case or a use
177276
+ // case has its subject BOUND to the case's subject, so a `subject` of an
177277
+ // unrelated type on the objective states something the case has already
177278
+ // decided otherwise.
177279
+ 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.`,
177280
+ // issue #166 — an `include` investigates the included use case on the
177281
+ // including case's subject (§7.25), and an `actor` written inside the
177282
+ // include binds one of the included use case's actor parameters.
177283
+ 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.`,
177284
+ SSM048_INCLUDE_ACTOR_BINDING: (actor, included, known2) => `'${actor}' is not an actor parameter of the included use case '${included}'. It declares ${known2}.`,
176538
177285
  // REQ-392 — a `sysml-format` comment the formatter cannot act on. Advisory:
176539
177286
  // the directive is inert, and saying so beats leaving the author to wonder
176540
177287
  // why their layout was reformatted anyway.
@@ -176997,7 +177744,7 @@ function nearestAncestor(node, types) {
176997
177744
  }
176998
177745
  return void 0;
176999
177746
  }
177000
- function exprText2(node) {
177747
+ function exprText3(node) {
177001
177748
  return node?.$cstNode?.text?.trim().replace(/\s+/gu, " ") ?? "";
177002
177749
  }
177003
177750
  function conditionTypeLabel(node) {
@@ -177008,7 +177755,7 @@ function conditionTypeLabel(node) {
177008
177755
  if (["AndExpr", "OrExpr", "XorExpr", "NotExpr", "CompareExpr", "ClassifyOp"].includes(node.$type)) {
177009
177756
  return "Boolean";
177010
177757
  }
177011
- const text = exprText2(node);
177758
+ const text = exprText3(node);
177012
177759
  return /\b(true|false)\b|[=!<>]=?|(?:\band\b|\bor\b|\bnot\b|\bxor\b)/u.test(text) ? "Boolean" : "Boolean (expected)";
177013
177760
  }
177014
177761
  function buildConditionalHover(node) {
@@ -177022,7 +177769,7 @@ function buildConditionalHover(node) {
177022
177769
  "",
177023
177770
  "Canonical form: `if condition ? thenExpression else elseExpression`",
177024
177771
  `Then marker: ${usesQuestion ? "canonical `?`" : "non-canonical `then`; use `?`"}`,
177025
- `Condition: \`${exprText2(n2.cond)}\``,
177772
+ `Condition: \`${exprText3(n2.cond)}\``,
177026
177773
  `Condition type: ${conditionTypeLabel(n2.cond)}`,
177027
177774
  "",
177028
177775
  sourceFooter(nodeSource(node))
@@ -177194,6 +177941,8 @@ ${headerLines.join("\n")}
177194
177941
  const subject = subjectInheritanceSection(node);
177195
177942
  if (subject)
177196
177943
  parts.push(subject);
177944
+ for (const section of caseBindingSections(node))
177945
+ parts.push(section);
177197
177946
  if (relationshipDetails)
177198
177947
  parts.push(relationshipDetails);
177199
177948
  const flip = conjugationFlipSection(node);
@@ -177230,6 +177979,62 @@ function subjectInheritanceSection(node) {
177230
177979
  const ownerName = effective.owner.name ?? "(anonymous requirement)";
177231
177980
  return `*Subject inherited from \`${ownerName}\`:* \`${subjectText}\``;
177232
177981
  }
177982
+ var CASE_KIND_LABELS = {
177983
+ "case": "Case",
177984
+ "analysis": "Analysis case",
177985
+ "verification": "Verification case",
177986
+ "use-case": "Use case"
177987
+ };
177988
+ function caseBindingSections(node) {
177989
+ const out = [];
177990
+ const kind = caseKindOf(node);
177991
+ if (kind) {
177992
+ const effective = effectiveCaseDefinition(node);
177993
+ if (effective && !effective.isDefinition && effective.sole) {
177994
+ out.push(`*${CASE_KIND_LABELS[kind]} performs:* \`${effective.sole.name}\``);
177995
+ }
177996
+ const subject = effectiveCaseSubject(node);
177997
+ if (subject.origin === "inherited") {
177998
+ const owner = subject.owner?.name;
177999
+ out.push(`*Subject inherited${owner ? ` from \`${owner}\`` : ""}:* \`${subject.name ?? "subject"} : ${subject.typeName}\``);
178000
+ } else if (subject.origin === "default") {
178001
+ out.push("*Subject:* none declared, so this case investigates `Anything`.");
178002
+ }
178003
+ const inherited = effectiveActors(node).filter((actor) => actor.origin === "inherited");
178004
+ if (inherited.length > 0) {
178005
+ const list = inherited.map((actor) => `\`${actor.name ?? "actor"}${actor.typeName ? ` : ${actor.typeName}` : ""}\``).join(", ");
178006
+ out.push(`*Actors inherited:* ${list}`);
178007
+ }
178008
+ }
178009
+ if (node.$type === "ObjectiveDecl") {
178010
+ const binding = objectiveBindingOf(node);
178011
+ if (binding) {
178012
+ const what = binding.target === "case-subject" ? "subject" : "result";
178013
+ const verb = binding.strength === "bind" ? "is bound to" : "defaults to";
178014
+ const type = binding.typeName ? ` (\`${binding.typeName}\`)` : "";
178015
+ const caseName = binding.caseNode.name;
178016
+ out.push(`*Objective subject ${verb}* the ${what} of ${caseName ? `\`${caseName}\`` : "the enclosing case"}${type}.`);
178017
+ }
178018
+ const subrequirements = objectiveSubrequirements(node);
178019
+ if (subrequirements.length > 0) {
178020
+ const list = subrequirements.map((sub) => `\`${sub.path ?? sub.declaration.name ?? "requirement"}\``).join(", ");
178021
+ out.push(`*Required subrequirements:* ${list} \u2014 each is checked on this objective's subject.`);
178022
+ }
178023
+ }
178024
+ if (node.$type === "IncludeStmt") {
178025
+ const binding = includeBindingOf(node);
178026
+ if (binding?.target) {
178027
+ const name = binding.path ? `\`${binding.path}\`` : "the included use case";
178028
+ out.push(`*Includes:* ${name}, a reference to a use case performed elsewhere. It keeps its own identity and is not copied here.`);
178029
+ if (binding.subjectOrigin === "containing") {
178030
+ out.push(`*Investigated on:* the including case's subject (\`${binding.subjectTypeName}\`).`);
178031
+ } else if (binding.subjectOrigin === "included") {
178032
+ out.push(`*Investigated on:* its own subject (\`${binding.subjectTypeName}\`).`);
178033
+ }
178034
+ }
178035
+ }
178036
+ return out;
178037
+ }
177233
178038
  function flipDirection(direction) {
177234
178039
  return direction === "in" ? "out" : direction === "out" ? "in" : direction;
177235
178040
  }
@@ -178204,6 +179009,13 @@ var TYPE_CONTEXTS = {
178204
179009
  calc: ["CalcDecl", "FunctionDecl"],
178205
179010
  constraint: ["ConstraintDecl", "PredicateDecl"]
178206
179011
  };
179012
+ var CONSTRAINT_REFERENCE_TYPES = [
179013
+ "ConstraintDecl",
179014
+ "InvShorthand",
179015
+ "PredicateDecl",
179016
+ "RequirementDecl",
179017
+ "ConcernDecl"
179018
+ ];
178207
179019
  var ALL_DEFINITION_TYPES = [
178208
179020
  "PartDecl",
178209
179021
  "PortDecl",
@@ -178389,6 +179201,10 @@ var SysmlCompletionProvider = class extends DefaultCompletionProvider {
178389
179201
  allowedLabels.add("requirement");
178390
179202
  allowedLabels.add("by");
178391
179203
  }
179204
+ if (context.kind === "constraint-reference") {
179205
+ allowedLabels.add("constraint");
179206
+ allowedLabels.add("not");
179207
+ }
178392
179208
  if (context.kind === "specialization") {
178393
179209
  allowedLabels.add("specializes");
178394
179210
  allowedLabels.add("subsets");
@@ -178463,6 +179279,14 @@ var SysmlCompletionProvider = class extends DefaultCompletionProvider {
178463
179279
  addUnique(items, this.visibleSymbolItems(["RequirementDecl"], { document: document2, offset: offset2 }));
178464
179280
  return;
178465
179281
  }
179282
+ // REQ-415 — a reference shorthand names a CONSTRAINT, so the slot
179283
+ // offers constraint usages and definitions rather than every symbol.
179284
+ // A requirement and a concern are constraints too (OMG SysML v2
179285
+ // Part 1 §7.20.2, §7.21.2), so both belong in the list.
179286
+ case "constraint-reference": {
179287
+ addUnique(items, this.visibleSymbolItems(CONSTRAINT_REFERENCE_TYPES, { document: document2, offset: offset2 }));
179288
+ return;
179289
+ }
178466
179290
  case "connect": {
178467
179291
  addUnique(items, this.connectPortItems(document2, offset2));
178468
179292
  return;
@@ -178484,6 +179308,8 @@ var SysmlCompletionProvider = class extends DefaultCompletionProvider {
178484
179308
  symbolTypesForContext(context) {
178485
179309
  if (context.kind === "verify" || context.kind === "satisfy")
178486
179310
  return ["RequirementDecl"];
179311
+ if (context.kind === "constraint-reference")
179312
+ return CONSTRAINT_REFERENCE_TYPES;
178487
179313
  const keyword = context.typingKeyword;
178488
179314
  if (!keyword)
178489
179315
  return ALL_DEFINITION_TYPES;
@@ -178687,6 +179513,9 @@ function detectCompletionContext(text, offset2) {
178687
179513
  if (/\bconnect\s+(?:[\p{L}_:'.]+(?:\.[\p{L}_:']+)*\s+to\s*)?[\p{L}_:'.]*$/u.test(statement)) {
178688
179514
  return { kind: "connect", statement };
178689
179515
  }
179516
+ if (/\b(?:assert|require|assume)\s+(?:not\s+)?[\p{L}_:'.]*$/u.test(statement)) {
179517
+ return { kind: "constraint-reference", statement };
179518
+ }
178690
179519
  if (/(?:^|[^\w:])(?::>|:>>|specializes|subsets|redefines)\s*~?[\p{L}_:'.]*$/u.test(statement)) {
178691
179520
  return { kind: "specialization", statement, typingKeyword: keyword };
178692
179521
  }
@@ -180197,6 +181026,60 @@ var CONSTRAINT_SIDE_EFFECT_TYPES = /* @__PURE__ */ new Set([
180197
181026
  "DoAction",
180198
181027
  "ExitAction"
180199
181028
  ]);
181029
+ var BOOLEAN_OPERATORS = /* @__PURE__ */ new Set([
181030
+ "or",
181031
+ "|",
181032
+ "implies",
181033
+ "xor",
181034
+ "and",
181035
+ "&",
181036
+ ">=",
181037
+ "<=",
181038
+ "===",
181039
+ "!==",
181040
+ "==",
181041
+ "!=",
181042
+ ">",
181043
+ "<",
181044
+ "hastype",
181045
+ "istype",
181046
+ "@",
181047
+ "@@"
181048
+ ]);
181049
+ var ARITHMETIC_OPERATORS = /* @__PURE__ */ new Set(["+", "-", "*", "/", "%", "**", "^", ".."]);
181050
+ function nonBooleanExpressionKind(expr) {
181051
+ const node = expr;
181052
+ switch (expr.$type) {
181053
+ case "NumericPrimary":
181054
+ return node.unit ? "a quantity" : "a number";
181055
+ case "LiteralStr":
181056
+ return "a string";
181057
+ case "UnaryMinusExpr":
181058
+ case "UnaryPlusExpr":
181059
+ return "a number";
181060
+ case "ParenExpr": {
181061
+ const items = Array.isArray(node.items) ? node.items : [];
181062
+ return items.length === 1 ? nonBooleanExpressionKind(items[0]) : void 0;
181063
+ }
181064
+ case "BinExpr": {
181065
+ const op = typeof node.op === "string" ? node.op : void 0;
181066
+ if (op && BOOLEAN_OPERATORS.has(op))
181067
+ return void 0;
181068
+ if (op && ARITHMETIC_OPERATORS.has(op)) {
181069
+ return op === ".." ? "a range" : "an arithmetic expression";
181070
+ }
181071
+ return void 0;
181072
+ }
181073
+ default:
181074
+ return void 0;
181075
+ }
181076
+ }
181077
+ function directionOfModifiers(node) {
181078
+ const modifiers2 = node.modifiers;
181079
+ if (!Array.isArray(modifiers2))
181080
+ return void 0;
181081
+ return modifiers2.find((modifier) => modifier === "in" || modifier === "out" || modifier === "inout");
181082
+ }
180200
181083
  var ACTION_BODY_TYPES = /* @__PURE__ */ new Set([
180201
181084
  "ActionDecl",
180202
181085
  "PerformStmt",
@@ -180497,7 +181380,122 @@ var SysmlValidator = class _SysmlValidator {
180497
181380
  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
181381
  }
180499
181382
  }
181383
+ const notBoolean = node.body ? nonBooleanExpressionKind(node.body) : void 0;
181384
+ if (node.body?.$cstNode && notBoolean) {
181385
+ 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" });
181386
+ }
181387
+ if (!node.isDef && node.body) {
181388
+ const definition = this.constraintTypeOf(node);
181389
+ if (definition?.body && definition.name) {
181390
+ accept(severity("STYL012", "hint"), DIAGNOSTIC_MESSAGES.STYL012_CONSTRAINT_BODY_OVERRIDES_DEFINITION(node.name ?? "(anonymous)", definition.name), { node, property: "body", code: "STYL012" });
181391
+ }
181392
+ }
181393
+ }
181394
+ /** REQ-209 — the constraint definition a usage is typed by, when the link
181395
+ * resolved. Only a direct typing is followed: a deeper specialization chain
181396
+ * is not what "replaces its definition's expression" is about. */
181397
+ constraintTypeOf(node) {
181398
+ const target = node.typing?.type?.ref;
181399
+ return target?.$type === "ConstraintDecl" ? target : void 0;
181400
+ }
181401
+ /* REQ-376 (user direction 2026-09-07) — STYL014: a parameter of a constraint
181402
+ * or a calculation is an INPUT. A constraint's one output is its Boolean
181403
+ * result and a calculation's is its `return`; neither sends anything back
181404
+ * through a parameter, and no model in the OMG corpus declares one `out` or
181405
+ * `inout`.
181406
+ *
181407
+ * Reported where the parameter is DECLARED: on a definition, and on a usage
181408
+ * that declares its own (an untyped `constraint c { out x : T; … }`). A TYPED
181409
+ * usage inherits its parameters, so a direction written there is a
181410
+ * redefinition of one, and `SSM025` already reports that as an error - saying
181411
+ * it twice, once as an error and once as an advisory, helps nobody. */
181412
+ checkParameterDirection(node, accept) {
181413
+ const decl = node;
181414
+ const typed = node.typing?.type?.ref;
181415
+ if (decl.isDef !== true && typed)
181416
+ return;
181417
+ const kind = node.$type === "ConstraintDecl" ? "constraint" : "calculation";
181418
+ const owner = typeof decl.name === "string" && decl.name ? decl.name : "(anonymous)";
181419
+ for (const member of decl.members ?? []) {
181420
+ const direction = directionOfModifiers(member);
181421
+ if (direction !== "out" && direction !== "inout")
181422
+ continue;
181423
+ const name = member.name;
181424
+ if (typeof name !== "string" || !name)
181425
+ continue;
181426
+ accept(severity("STYL014", "hint"), DIAGNOSTIC_MESSAGES.STYL014_PARAMETER_DIRECTION(name, direction, kind, owner), { node: member, code: "STYL014" });
181427
+ }
180500
181428
  }
181429
+ // REQ-376 — STYL013: a directed parameter is an input a usage binds, not a
181430
+ // value slot. OMG declares them bare on a definition and puts values on
181431
+ // `attribute` members. Only a DEFINITION is flagged: `in x = expr;` on a usage
181432
+ // is the canonical binding form.
181433
+ checkParameterDefaultOnDefinition(node, accept) {
181434
+ const decl = node;
181435
+ if (decl.isDef !== true || typeof decl.name !== "string" || !decl.name)
181436
+ return;
181437
+ for (const member of decl.members ?? []) {
181438
+ const name = member.name;
181439
+ const value = member.value;
181440
+ if (!value || typeof name !== "string" || !name)
181441
+ continue;
181442
+ if (directionOfModifiers(member) === void 0)
181443
+ continue;
181444
+ accept(severity("STYL013", "hint"), DIAGNOSTIC_MESSAGES.STYL013_PARAMETER_DEFAULT_ON_DEFINITION(name, decl.name), { node: member, code: "STYL013" });
181445
+ }
181446
+ }
181447
+ // REQ-415 — issue #164. `assert c;`, `assert not c;`, `require c;` and
181448
+ // `assume c;` name a constraint declared elsewhere (OMG SysML v2 Part 1
181449
+ // §7.20.3, §7.21.2). Three things can go wrong with that name, and all three
181450
+ // were silent: it may resolve to nothing, it may resolve to something that is
181451
+ // not a constraint, and the constraint it resolves to may be decidably false.
181452
+ //
181453
+ // The ROOT link is judged here rather than in `checkWrittenPaths`, which
181454
+ // deliberately leaves a root alone: a root is reported absent only when the
181455
+ // resolver could enumerate the whole surrounding inventory, and that is
181456
+ // exactly the guarantee `unresolvedIndex === 0` carries. It is the same rule
181457
+ // `checkRelationshipTargets` applies to a redefinition target.
181458
+ checkConstraintReference(node, accept) {
181459
+ const reference = constraintReferenceOf(node);
181460
+ if (!reference)
181461
+ return;
181462
+ const resolution = reference.property ? this.featurePaths.resolvePropertyPath(node, reference.property) : this.featurePaths.resolveDeclarationPath(node);
181463
+ if (resolution.segments.length === 0)
181464
+ return;
181465
+ if (resolution.unresolvedIndex === 0) {
181466
+ const invalid = resolution.segments[0];
181467
+ 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 } });
181468
+ return;
181469
+ }
181470
+ if (resolution.unresolvedIndex !== void 0 || resolution.indeterminateIndex !== void 0)
181471
+ return;
181472
+ const last2 = resolution.segments[resolution.segments.length - 1];
181473
+ const target = last2.target;
181474
+ if (target && isWrongKindConstraintTarget(target)) {
181475
+ accept(severity("SSM043", "error"), DIAGNOSTIC_MESSAGES.SSM043_CONSTRAINT_REFERENCE_KIND(reference.kind, reference.path, wrongKindLabel(target)), { node, range: last2.cst.range, code: "SSM043" });
181476
+ }
181477
+ }
181478
+ // REQ-415 — SEM014. An assertion the model can DECIDE and that comes out
181479
+ // false is an inconsistency the author wrote against themselves. Only a
181480
+ // closed constant expression is decided: every feature reference is
181481
+ // inconclusive here, so an assertion that depends on a binding, on time, or
181482
+ // on anything this evaluator does not model stays silent rather than passing
181483
+ // quietly or being reported on a guess.
181484
+ checkAssertionConsistency(node, accept) {
181485
+ if (node.$type !== "AssertConstraintStmt")
181486
+ return;
181487
+ const result = evaluateAssertion(node, this.constraintResolver);
181488
+ if (result?.status !== "fail")
181489
+ return;
181490
+ accept(severity("SEM014", "warning"), DIAGNOSTIC_MESSAGES.SEM014_ASSERTION_VIOLATED(result.text), { node, code: "SEM014" });
181491
+ }
181492
+ // REQ-415 — Resolve a reference shorthand through the shared path resolver,
181493
+ // so a target in another file or in the standard library is evaluated exactly
181494
+ // as a same-file one is.
181495
+ constraintResolver = (reference, member) => {
181496
+ const resolution = reference.property ? this.featurePaths.resolvePropertyPath(member, reference.property) : this.featurePaths.resolveDeclarationPath(member);
181497
+ return resolution.segments[resolution.segments.length - 1]?.target;
181498
+ };
180501
181499
  // REQ-410 — SEM013. A `ref` feature is NON-composite: it names a feature that
180502
181500
  // is owned somewhere else. An unbound one therefore names nothing at all, and
180503
181501
  // the General View cannot draw it as anything: a box would claim the owner
@@ -181996,6 +182994,7 @@ ${baseIndent}}`;
181996
182994
  const decls = [];
181997
182995
  const verifyStmts = [];
181998
182996
  const satisfyStmts = [];
182997
+ const includeStmts = [];
181999
182998
  const aliasMap = /* @__PURE__ */ new Map();
182000
182999
  for (const child of ast_utils_exports.streamAllContents(node)) {
182001
183000
  if (isImport(child)) {
@@ -182019,6 +183018,8 @@ ${baseIndent}}`;
182019
183018
  if (a2.name && a2.target)
182020
183019
  aliasMap.set(a2.name, a2.target);
182021
183020
  }
183021
+ if (child.$type === "IncludeStmt")
183022
+ includeStmts.push(child);
182022
183023
  }
182023
183024
  this.checkAmbiguousReferences(node, imports, index2, accept);
182024
183025
  this.checkPrivateImports(imports, index2, accept);
@@ -182054,7 +183055,7 @@ ${baseIndent}}`;
182054
183055
  this.checkInverseOfTargets(decl, index2, accept);
182055
183056
  this.checkTypeComposition(decl, index2, accept);
182056
183057
  }
182057
- this.checkTypeConformance(decls, satisfyStmts, index2, accept);
183058
+ this.checkTypeConformance(decls, satisfyStmts, includeStmts, index2, accept);
182058
183059
  }
182059
183060
  // ══════════════════════════════════════════════════════════════════════
182060
183061
  // REQ-390 — SSM017-SSM021: whole-model type conformance (issue #104)
@@ -182064,7 +183065,7 @@ ${baseIndent}}`;
182064
183065
  // the walk, so a type rooted in the unparsed standard library yields
182065
183066
  // `unknown` and no diagnostic. That is what keeps the OMG corpus clean while
182066
183067
  // still catching the workspace-local mistakes these codes exist for.
182067
- checkTypeConformance(decls, satisfyStmts, index2, accept) {
183068
+ checkTypeConformance(decls, satisfyStmts, includeStmts, index2, accept) {
182068
183069
  const model = new ConformanceModel((name) => this.resolveUnique(name, index2), (node) => this.implicit?.closureOf(node) ?? { names: /* @__PURE__ */ new Set(), complete: true });
182069
183070
  for (const decl of decls) {
182070
183071
  this.checkRedefinitionTypeConformance(decl, model, index2, accept);
@@ -182079,9 +183080,78 @@ ${baseIndent}}`;
182079
183080
  this.checkRedefinitionDirection(decl, index2, accept);
182080
183081
  this.checkInterfaceEndTypes(decl, model, index2, accept);
182081
183082
  this.checkIndividualDefinitions(decl, model, accept);
183083
+ this.checkCaseDefinitionCount(decl, index2, accept);
183084
+ this.checkObjectiveSubject(decl, model, index2, accept);
182082
183085
  }
182083
183086
  for (const stmt of satisfyStmts)
182084
183087
  this.checkSatisfierSubjectType(stmt, model, index2, accept);
183088
+ for (const stmt of includeStmts)
183089
+ this.checkIncludeBindings(stmt, model, index2, accept);
183090
+ }
183091
+ // ══════════════════════════════════════════════════════════════════════
183092
+ // REQ-417 — SSM045-SSM048: the bindings a case makes (issue #166)
183093
+ // ══════════════════════════════════════════════════════════════════════
183094
+ // SSM045 — OMG SysML v2 Part 1 §7.22.2: a CaseUsage has exactly one
183095
+ // CaseDefinition. Everything this extension derives about a case usage reads
183096
+ // through that one — its subject, its actor parameters, its objective — so
183097
+ // two leave all three undecided rather than merged. A type this validator
183098
+ // could not read is NOT counted: an unread type is not a wrong one, the same
183099
+ // three-valued rule the rest of this family follows.
183100
+ checkCaseDefinitionCount(decl, index2, accept) {
183101
+ const effective = effectiveCaseDefinition(decl, (name) => this.resolveUnique(name, index2));
183102
+ if (!effective || effective.isDefinition)
183103
+ return;
183104
+ const read = effective.definitions.filter((type) => type.node !== void 0);
183105
+ if (read.length < 2)
183106
+ return;
183107
+ accept(severity("SSM045", "error"), DIAGNOSTIC_MESSAGES.SSM045_CASE_MULTIPLE_DEFINITIONS(decl.name ?? "this case", read[0].name, read[1].name), { node: decl, code: "SSM045" });
183108
+ }
183109
+ // SSM046 — a `verification case` and a `use case` BIND their objective's
183110
+ // subject to their own (`objective obj { subject subj = VerificationCase::subj; }`
183111
+ // in `VerificationCases.sysml`), so a `subject` written on the objective with
183112
+ // an unrelated type states something the case has already decided otherwise.
183113
+ // A generic `case` and an `analysis case` only DEFAULT the objective's subject
183114
+ // to their result, which the model may override, so neither is judged here.
183115
+ checkObjectiveSubject(decl, model, index2, accept) {
183116
+ if (decl.$type !== "ObjectiveDecl")
183117
+ return;
183118
+ const binding = objectiveBindingOf(decl, (name) => this.resolveUnique(name, index2));
183119
+ if (!binding || binding.strength !== "bind" || !binding.own)
183120
+ return;
183121
+ const written = binding.own.typing?.type?.$refText?.trim();
183122
+ if (!written)
183123
+ return;
183124
+ const bound = binding.typeName;
183125
+ if (!bound || bound === DEFAULT_SUBJECT_TYPE)
183126
+ return;
183127
+ if (model.compatible(written, bound) !== "unrelated")
183128
+ return;
183129
+ const caseName = binding.caseNode.name ?? "this case";
183130
+ accept(severity("SSM046", "warning"), DIAGNOSTIC_MESSAGES.SSM046_OBJECTIVE_SUBJECT_TYPE(caseName, written, bound), { node: binding.own, code: "SSM046" });
183131
+ }
183132
+ // SSM047 / SSM048 — OMG SysML v2 Part 1 §7.25 / §8.2.2.25 IncludeUseCaseUsage.
183133
+ // An include is a REFERENCE to a use case performed elsewhere: it keeps that
183134
+ // use case's identity, is investigated on the including case's subject, and
183135
+ // binds that use case's own actor parameters. Both checks stay silent unless
183136
+ // the included use case was actually read.
183137
+ checkIncludeBindings(stmt, model, index2, accept) {
183138
+ const binding = includeBindingOf(stmt, (name) => this.resolveUnique(name, index2));
183139
+ if (!binding?.target)
183140
+ return;
183141
+ const included = binding.path ?? "the included use case";
183142
+ const includedSubject = binding.includedSubject;
183143
+ const containingSubject = binding.containingSubject;
183144
+ if (isDecidedSubject(includedSubject) && isDecidedSubject(containingSubject) && model.compatible(includedSubject.typeName, containingSubject.typeName) === "unrelated") {
183145
+ accept(severity("SSM047", "warning"), DIAGNOSTIC_MESSAGES.SSM047_INCLUDE_SUBJECT_TYPE(included, includedSubject.typeName, containingSubject.typeName), { node: stmt, code: "SSM047" });
183146
+ }
183147
+ if (binding.parameters.length === 0)
183148
+ return;
183149
+ const known2 = binding.parameters.map((parameter) => `'${parameter.name ?? "(anonymous)"}'`).join(", ");
183150
+ for (const actor of binding.actors) {
183151
+ if (!actor.name || actor.parameter)
183152
+ continue;
183153
+ accept(severity("SSM048", "warning"), DIAGNOSTIC_MESSAGES.SSM048_INCLUDE_ACTOR_BINDING(actor.name, included, known2), { node: actor.declaration, code: "SSM048" });
183154
+ }
182085
183155
  }
182086
183156
  // REQ-416 — SSM044: `satisfy MassReq by engine;` claims that `engine` is one
182087
183157
  // of the things `MassReq` constrains, so `engine`'s type has to conform to
@@ -183346,7 +184416,16 @@ ${baseIndent}}`;
183346
184416
  // issue #215 — the rest of the reference-form declarations. They share
183347
184417
  // `ReferenceFormPath` with `perform`/`exhibit`, so they can spell the
183348
184418
  // same defect and are judged by the same rule.
183349
- AssertConstraintStmt: this.checkChainSeparators.bind(this),
184419
+ // REQ-415 — issue #164: the constraint reference shorthands. `assert`
184420
+ // shares its `ReferenceFormPath` with the other reference forms, so it
184421
+ // also carries the RES019 separator rule above.
184422
+ AssertConstraintStmt: [
184423
+ this.checkChainSeparators.bind(this),
184424
+ this.checkConstraintReference.bind(this),
184425
+ this.checkAssertionConsistency.bind(this)
184426
+ ],
184427
+ RequireConstraintStmt: this.checkConstraintReference.bind(this),
184428
+ AssumeConstraintStmt: this.checkConstraintReference.bind(this),
183350
184429
  EntryAction: this.checkChainSeparators.bind(this),
183351
184430
  DoAction: this.checkChainSeparators.bind(this),
183352
184431
  ExitAction: this.checkChainSeparators.bind(this),
@@ -183354,7 +184433,17 @@ ${baseIndent}}`;
183354
184433
  ConnectorEnd: this.checkConnectorEndSeparators.bind(this),
183355
184434
  RequirementDecl: this.checkRequirementDecl.bind(this),
183356
184435
  AttributeDecl: this.checkAttributeDecl.bind(this),
183357
- ConstraintDecl: this.checkConstraintDecl.bind(this),
184436
+ // REQ-376 — STYL013 applies to both behavioral definitions that take
184437
+ // parameters, so the constraint check runs beside it here.
184438
+ ConstraintDecl: [
184439
+ this.checkConstraintDecl.bind(this),
184440
+ this.checkParameterDefaultOnDefinition.bind(this),
184441
+ this.checkParameterDirection.bind(this)
184442
+ ],
184443
+ CalcDecl: [
184444
+ this.checkParameterDefaultOnDefinition.bind(this),
184445
+ this.checkParameterDirection.bind(this)
184446
+ ],
183358
184447
  VerificationCaseDecl: this.checkVerificationCaseDecl.bind(this),
183359
184448
  AnalysisCaseDecl: this.checkAnalysisCaseDecl.bind(this),
183360
184449
  ViewDecl: this.checkViewDecl.bind(this),
@@ -184077,6 +185166,9 @@ var STYLE_ADVISORY_CODES = /* @__PURE__ */ new Set([
184077
185166
  "STYL009",
184078
185167
  "STYL010",
184079
185168
  "STYL011",
185169
+ "STYL012",
185170
+ "STYL013",
185171
+ "STYL014",
184080
185172
  "LEX009",
184081
185173
  // trailing whitespace
184082
185174
  "SYN024",
@@ -184399,6 +185491,8 @@ var SysmlScopeComputation = class extends DefaultScopeComputation {
184399
185491
  break;
184400
185492
  if (node.$type === "ShortName" || node.$type === "ImportSeg")
184401
185493
  continue;
185494
+ if (isReferenceFormDeclaration(node))
185495
+ continue;
184402
185496
  const aliases = this.nameAliasesOf(node);
184403
185497
  if (aliases.length === 0)
184404
185498
  continue;
@@ -190059,7 +191153,9 @@ function nodeSize(node, direction) {
190059
191153
  const portRunHeight = connectionUsage ? portRows ? portRows * 18 + 6 : 0 : portRows ? compactContainer ? portRows * 24 + 8 : 40 + portRows * 24 + 8 : 0;
190060
191154
  const bodyH = Math.max(
190061
191155
  connectionUsage ? 42 : BOX_H,
190062
- node.value !== void 0 ? 88 : 0,
191156
+ // REQ-209/375 - The value field sits at the bottom of the card, under
191157
+ // whatever compartments it carries, so both have to fit.
191158
+ node.value !== void 0 ? Math.max(88, NODE_COMPARTMENT_TOP + compartmentHeight(node) + 36) : 0,
190063
191159
  featureH === 0 ? NODE_COMPARTMENT_TOP + compartmentHeight(node) : 0,
190064
191160
  portRunHeight,
190065
191161
  portedSideLength(ph, "left"),
@@ -190730,7 +191826,7 @@ function collapseIvModel(model, hiddenInternals) {
190730
191826
  const frames = model.frames ?? [];
190731
191827
  if (!frames.length) return model;
190732
191828
  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));
191829
+ const requested = new Set(frames.filter((frame2) => (frame2.meta?.internalsExpandable === false || framePresentationEnabled(hiddenInternals, frame2, true)) && isCollapsibleFrame("iv", frame2)).map((frame2) => frame2.id));
190734
191830
  if (requested.size === 0) return model;
190735
191831
  const hasRequestedAncestor = (id2) => {
190736
191832
  let p = frameById.get(id2)?.parent;
@@ -190793,12 +191889,11 @@ function collapseIvModel(model, hiddenInternals) {
190793
191889
  const toRoot = containerRootOf(e.to);
190794
191890
  if (fromRoot !== void 0 && fromRoot === toRoot) return false;
190795
191891
  return !(hidden.has(e.from) && fromRoot === void 0) && !(hidden.has(e.to) && toRoot === void 0);
190796
- }).map((e) => {
191892
+ }).filter((e) => e.from === e.to || (bodyDock.get(e.from) ?? e.from) !== (bodyDock.get(e.to) ?? e.to)).map((e) => {
190797
191893
  const from = bodyDock.get(e.from) ?? e.from;
190798
191894
  const to = bodyDock.get(e.to) ?? e.to;
190799
191895
  return from === e.from && to === e.to ? e : { ...e, from, to };
190800
191896
  }).filter((e) => {
190801
- if (e.from === e.to) return false;
190802
191897
  const key2 = `${e.from}\0${e.to}\0${e.kind}\0${e.label ?? ""}`;
190803
191898
  if (seenEdge.has(`${key2}:${e.id}`)) return false;
190804
191899
  seenEdge.add(`${key2}:${e.id}`);
@@ -190876,17 +191971,30 @@ function isFeatureCompartmentNode(kind, node) {
190876
191971
  if (kind === "stv") return node.shape === "state";
190877
191972
  return false;
190878
191973
  }
191974
+ function graphicalChildOwners(model) {
191975
+ const owners = /* @__PURE__ */ new Set();
191976
+ for (const node of model.nodes) {
191977
+ const owner = node.frame ?? node.parent;
191978
+ if (owner && owner !== node.id) owners.add(owner);
191979
+ }
191980
+ for (const frame2 of model.frames ?? []) {
191981
+ if (frame2.parent && frame2.parent !== frame2.id) owners.add(frame2.parent);
191982
+ }
191983
+ return owners;
191984
+ }
190879
191985
  function applyFeatureCompartmentVisibility(model, visibleFeatureCompartments, hiddenInternals = {}) {
190880
191986
  if (!CONTAINER_PRESENTATION_KINDS.has(model.kind)) return model;
190881
191987
  const legacy = model.kind === "iv";
191988
+ const owners = graphicalChildOwners(model);
190882
191989
  let changed = false;
190883
191990
  const project = (host, leaf) => {
191991
+ const internalsExpandable = owners.has(host.id);
190884
191992
  const alwaysVisible = host.meta?.alwaysVisibleCompartments === true;
190885
191993
  const defaultVisible = leaf || model.kind === "afv" && !leaf;
190886
191994
  const visible = alwaysVisible || framePresentationEnabled(visibleFeatureCompartments, host, legacy, defaultVisible);
190887
191995
  const compartments = visible ? host.compartments : void 0;
190888
191996
  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;
191997
+ if (compartments === host.compartments && host.meta?.containerControls === true && host.meta?.internalsExpandable === internalsExpandable && host.meta?.featureCompartmentsVisible === visible && (!leaf || host.meta?.internalsHidden === internalsHidden)) return host;
190890
191998
  changed = true;
190891
191999
  return {
190892
192000
  ...host,
@@ -190894,6 +192002,7 @@ function applyFeatureCompartmentVisibility(model, visibleFeatureCompartments, hi
190894
192002
  meta: {
190895
192003
  ...host.meta,
190896
192004
  containerControls: true,
192005
+ internalsExpandable,
190897
192006
  featureCompartmentsVisible: visible,
190898
192007
  ...leaf ? { internalsHidden } : {}
190899
192008
  }
@@ -190909,10 +192018,10 @@ function collapseActionFrames(model, hiddenInternals, isHost = isCollapsibleActi
190909
192018
  if (!frames.length) return model;
190910
192019
  const frameById = new Map(frames.map((f) => [f.id, f]));
190911
192020
  const requested = new Set(
190912
- frames.filter((f) => framePresentationEnabled(hiddenInternals, f) && isHost(f)).map((f) => f.id)
192021
+ frames.filter((f) => (f.meta?.internalsExpandable === false || framePresentationEnabled(hiddenInternals, f)) && isHost(f)).map((f) => f.id)
190913
192022
  );
190914
192023
  if (requested.size === 0) return model;
190915
- const rootOf2 = (id2) => {
192024
+ const rootOf3 = (id2) => {
190916
192025
  let root4;
190917
192026
  const seen = /* @__PURE__ */ new Set();
190918
192027
  for (let cur = id2; cur !== void 0 && !seen.has(cur); cur = frameById.get(cur)?.parent) {
@@ -190921,13 +192030,13 @@ function collapseActionFrames(model, hiddenInternals, isHost = isCollapsibleActi
190921
192030
  }
190922
192031
  return root4;
190923
192032
  };
190924
- const roots = new Set([...requested].filter((id2) => rootOf2(frameById.get(id2)?.parent) === void 0));
192033
+ const roots = new Set([...requested].filter((id2) => rootOf3(frameById.get(id2)?.parent) === void 0));
190925
192034
  const dockOf = /* @__PURE__ */ new Map();
190926
192035
  const proxyHost = /* @__PURE__ */ new Map();
190927
192036
  const ownerOfHiddenPort = /* @__PURE__ */ new Map();
190928
192037
  const hiddenFrameIds = /* @__PURE__ */ new Set();
190929
192038
  for (const f of frames) {
190930
- const root4 = roots.has(f.id) ? rootOf2(f.parent) : rootOf2(f.id);
192039
+ const root4 = roots.has(f.id) ? rootOf3(f.parent) : rootOf3(f.id);
190931
192040
  if (root4 === void 0) continue;
190932
192041
  hiddenFrameIds.add(f.id);
190933
192042
  dockOf.set(f.id, root4);
@@ -190938,7 +192047,7 @@ function collapseActionFrames(model, hiddenInternals, isHost = isCollapsibleActi
190938
192047
  }
190939
192048
  const hiddenNodeIds = /* @__PURE__ */ new Set();
190940
192049
  for (const n2 of model.nodes) {
190941
- const root4 = rootOf2(n2.frame);
192050
+ const root4 = rootOf3(n2.frame);
190942
192051
  if (root4 === void 0) continue;
190943
192052
  hiddenNodeIds.add(n2.id);
190944
192053
  dockOf.set(n2.id, root4);
@@ -190967,12 +192076,11 @@ function collapseActionFrames(model, hiddenInternals, isHost = isCollapsibleActi
190967
192076
  const edges = model.edges.filter((e) => {
190968
192077
  const fromRoot = containerRootOf(e.from);
190969
192078
  return fromRoot === void 0 || fromRoot !== containerRootOf(e.to);
190970
- }).map((e) => {
192079
+ }).filter((e) => e.from === e.to || (dockOf.get(e.from) ?? e.from) !== (dockOf.get(e.to) ?? e.to)).map((e) => {
190971
192080
  const from = dockOf.get(e.from) ?? e.from;
190972
192081
  const to = dockOf.get(e.to) ?? e.to;
190973
192082
  return from === e.from && to === e.to ? e : { ...e, from, to };
190974
192083
  }).filter((e) => {
190975
- if (e.from === e.to) return false;
190976
192084
  const key2 = `${e.from}\0${e.to}\0${e.kind}\0${e.label ?? ""}`;
190977
192085
  if (seenEdge.has(`${key2}:${e.id}`)) return false;
190978
192086
  seenEdge.add(`${key2}:${e.id}`);
@@ -205385,6 +206493,10 @@ function markersFor(kind) {
205385
206493
  // REQ-199
205386
206494
  case "derive":
205387
206495
  // REQ-188
206496
+ case "assert":
206497
+ // REQ-131/REQ-415 — the constraint claims
206498
+ case "assume":
206499
+ case "require":
205388
206500
  case "causation":
205389
206501
  // REQ-189
205390
206502
  case "import":
@@ -205761,7 +206873,7 @@ var KIN_MARKER_DEFS_SVG = [
205761
206873
 
205762
206874
  // ../extension/src/webview/diagram/element-colors.ts
205763
206875
  var ELEMENT_CLOSED_OPACITY = 1;
205764
- var ELEMENT_OPEN_OPACITY = 0.2;
206876
+ var ELEMENT_OPEN_OPACITY = 0.3;
205765
206877
  var DIAGRAM_ELEMENT_COLORS = {
205766
206878
  default: {
205767
206879
  outline: { light: "#3a3a3a", dark: "#a1a1a1" },
@@ -205894,7 +207006,22 @@ var DIAGRAM_LINE_COLORS = {
205894
207006
  },
205895
207007
  dependency: {
205896
207008
  color: { light: "#6b46c1", dark: "#b08cf0" },
205897
- kinds: ["satisfy", "verify", "include", "dependency", "allocate", "frame", "derive", "causation", "import", "expose"],
207009
+ kinds: [
207010
+ "satisfy",
207011
+ "verify",
207012
+ "include",
207013
+ "dependency",
207014
+ "allocate",
207015
+ "frame",
207016
+ "derive",
207017
+ "causation",
207018
+ "import",
207019
+ "expose",
207020
+ // REQ-131/REQ-415 — the constraint claims read as the same family.
207021
+ "assert",
207022
+ "assume",
207023
+ "require"
207024
+ ],
205898
207025
  colorLabels: true
205899
207026
  },
205900
207027
  binding: {
@@ -206321,6 +207448,8 @@ body {
206321
207448
  .dlink.satisfy, .dlink.verify, .dlink.include, .dlink.dependency { stroke-dasharray: 4 3; }
206322
207449
  /* REQ-186/188/189/199/206/210 \u2014 the dashed labelled families */
206323
207450
  .dlink.allocate, .dlink.frame, .dlink.derive, .dlink.causation, .dlink.import, .dlink.expose { stroke-dasharray: 4 3; }
207451
+ /* REQ-131/REQ-415 \u2014 the three constraint claims */
207452
+ .dlink.assert, .dlink.assume, .dlink.require { stroke-dasharray: 4 3; }
206324
207453
  .dlink.annotation { stroke-dasharray: 2 3; }
206325
207454
  .dlink.elaboration { stroke-dasharray: 2 3; pointer-events: none; }
206326
207455
  .dlink.reply { stroke-dasharray: 4 3; } /* REQ-202 \u2014 sequence reply arrows */
@@ -207812,7 +208941,15 @@ var TOOLBOX = {
207812
208941
  rel("verify", "verify", "\u2713", "click the verification case, then the requirement"),
207813
208942
  rel("frame", "frame", "\u274F", "click the requirement/view, then the framed concern"),
207814
208943
  rel("exhibit", "exhibit", "\u25C9", "click the part, then the exhibited state"),
207815
- rel("perform", "perform", "\u25B7", "click the part, then the performed action")
208944
+ rel("perform", "perform", "\u25B7", "click the part, then the performed action"),
208945
+ // REQ-131/REQ-415 (user direction 2026-09-08 — "how do we add assert
208946
+ // constraint from the diagram") — the three constraint CLAIMS. The
208947
+ // diagram drew them in its compartments but could not create one, so
208948
+ // `assert constraint …` could only be typed. Each writes into the
208949
+ // claiming element, exactly as satisfy/verify/frame do.
208950
+ rel("assert", "assert", "\u22A8", "click the element that asserts, then the constraint"),
208951
+ rel("assume", "assume", "\u2283", "click the requirement/concern, then the assumed constraint"),
208952
+ rel("require", "require", "\u22A2", "click the requirement/concern, then the required constraint")
207816
208953
  ]
207817
208954
  },
207818
208955
  // The Interconnection View depicts parts, ports, and the compartment rows of
@@ -207843,7 +208980,12 @@ var TOOLBOX = {
207843
208980
  rel("flow", "flow", "\u2192", "click the source port/feature, then the target"),
207844
208981
  // issue #115 — an item flow that also sequences its ends.
207845
208982
  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")
208983
+ rel("allocate", "allocate", "\u290F", "click the source part/feature, then the target"),
208984
+ // REQ-131 — the view draws a part's constraints, and OMG's own
208985
+ // parametric picture is a part asserting one and binding its
208986
+ // parameters (ConstraintTest.sysml). `bind` was already here; the
208987
+ // claim that gives it something to bind was not.
208988
+ rel("assert", "assert", "\u22A8", "click the part, then the constraint it asserts")
207847
208989
  ]
207848
208990
  },
207849
208991
  // Action Flow depicts actions (a new `action def` becomes its own tile in a
@@ -208025,7 +209167,10 @@ var CHILD_KINDS = {
208025
209167
  "event occurrence": [],
208026
209168
  requirement: ["requirement", "constraint", "attribute", "part", "actor"],
208027
209169
  concern: ["requirement", "constraint", "attribute", "actor"],
208028
- constraint: ["attribute", "constraint"],
209170
+ // REQ-376 — a constraint and a calculation take INPUTS, and there was no way
209171
+ // to add one from the diagram. Only `in`: an `out` or `inout` parameter on
209172
+ // either is STYL014, so offering one would contradict the check.
209173
+ constraint: ["in parameter", "attribute", "constraint"],
208029
209174
  "use case": CASE_CHILDREN,
208030
209175
  "analysis case": CASE_CHILDREN,
208031
209176
  "verification case": CASE_CHILDREN,
@@ -208037,7 +209182,7 @@ var CHILD_KINDS = {
208037
209182
  // issue (GRV on enum def): an enum def owns enumeration VALUES — nested enum
208038
209183
  // usages — never requirements/parts; the old fallback offered the view list.
208039
209184
  enum: ["enum"],
208040
- calc: ["attribute", "calc"],
209185
+ calc: ["in parameter", "attribute", "calc"],
208041
209186
  connection: ["attribute", "item", "part"],
208042
209187
  connector: ["attribute", "item", "part"],
208043
209188
  interface: ["port", "attribute", "item"],
@@ -208052,6 +209197,10 @@ var CHILD_KINDS = {
208052
209197
  control: [],
208053
209198
  terminate: [],
208054
209199
  pin: [],
209200
+ // REQ-376 — the banner of a constraint/calc parameter card.
209201
+ "in parameter": [],
209202
+ "out parameter": [],
209203
+ "inout parameter": [],
208055
209204
  // REQ-196 — a «performer» swimlane (OMG SysML v2 Part 1 §8.2.3.17, p.90). Its
208056
209205
  // members are the actions that part performs; the edit writes the action into
208057
209206
  // the OWNING action's body and a `perform` for it into the part.
@@ -208164,12 +209313,33 @@ function relationToolsForNode(keyword, viewKind, shape) {
208164
209313
  case "exhibit":
208165
209314
  case "perform":
208166
209315
  return base === "part";
209316
+ // REQ-131 — the OMG corpus asserts inside a part or a package
209317
+ // (ConstraintTest.sysml, MassConstraintExample.sysml); a case and
209318
+ // a requirement own constraints of their own.
209319
+ case "assert":
209320
+ return [
209321
+ "part",
209322
+ "item",
209323
+ "package",
209324
+ "requirement",
209325
+ "concern",
209326
+ "use case",
209327
+ "analysis case",
209328
+ "verification case",
209329
+ "case"
209330
+ ].includes(base);
209331
+ // REQ-131 — OMG SysML 8.2.2.21.1: a RequirementConstraintMembership
209332
+ // belongs to a requirement or a concern.
209333
+ case "assume":
209334
+ case "require":
209335
+ return ["requirement", "concern"].includes(base);
208167
209336
  default:
208168
209337
  return true;
208169
209338
  }
208170
209339
  }
208171
209340
  if (viewKind === "iv") {
208172
209341
  if (!["part", "port", "attribute", "item", "connection"].includes(base)) return false;
209342
+ if (tool.kind === "assert") return base === "part" || base === "item";
208173
209343
  return tool.kind === "interface" ? base === "port" : true;
208174
209344
  }
208175
209345
  if (viewKind === "afv") {
@@ -208604,7 +209774,7 @@ function GvDisclosure({ element, svgWidth }) {
208604
209774
  }
208605
209775
  );
208606
209776
  }
208607
- function AttributeValueEditor({ id: id2, name, value, top }) {
209777
+ function AttributeValueEditor({ id: id2, name, value, top, label = "Value", placeholder = "Add value" }) {
208608
209778
  const { onSetElementValue } = useDiagram();
208609
209779
  const [draft, setDraft] = (0, import_react9.useState)(value);
208610
209780
  if (!onSetElementValue) return null;
@@ -208614,8 +209784,8 @@ function AttributeValueEditor({ id: id2, name, value, top }) {
208614
209784
  type: "text",
208615
209785
  className: "dattribute-value nodrag nopan nowheel",
208616
209786
  style: { top },
208617
- "aria-label": "Value of " + name,
208618
- placeholder: "Add value",
209787
+ "aria-label": label + " of " + name,
209788
+ placeholder,
208619
209789
  value: draft,
208620
209790
  onPointerDown: (event) => event.stopPropagation(),
208621
209791
  onClick: (event) => event.stopPropagation(),
@@ -209026,12 +210196,17 @@ function titleNameLine(name, type, mult, alias, availPx) {
209026
210196
  const shown = fitText(full, availPx, 11);
209027
210197
  return { full, shown, clipped: shown !== full };
209028
210198
  }
209029
- function AttributeValueShape({ value, w, top }) {
209030
- const shown = fitText(value || "Add value", Math.max(16, w - 32), 11);
210199
+ function valueFieldRole(keyword) {
210200
+ if (keyword.startsWith("constraint")) return { label: "Constraint", placeholder: "Add constraint" };
210201
+ if (keyword.startsWith("calc")) return { label: "Expression", placeholder: "Add expression" };
210202
+ return { label: "Value", placeholder: "Add value" };
210203
+ }
210204
+ function AttributeValueShape({ value, w, top, placeholder = "Add value" }) {
210205
+ const shown = fitText(value || placeholder, Math.max(16, w - 32), 11);
209031
210206
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("g", { className: "dattribute-value-shape", children: [
209032
210207
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x: 8, y: top, width: Math.max(1, w - 16), height: 28, rx: 3 }),
209033
210208
  /* @__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" }),
210209
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("title", { children: value || placeholder }),
209035
210210
  shown
209036
210211
  ] })
209037
210212
  ] });
@@ -209078,7 +210253,15 @@ function BoxBody({ node, w, h, showMult }) {
209078
210253
  ] })
209079
210254
  ] }),
209080
210255
  /* @__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
210256
+ node.value !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
210257
+ AttributeValueShape,
210258
+ {
210259
+ value: node.value,
210260
+ w,
210261
+ top: h - 36,
210262
+ placeholder: valueFieldRole(node.keyword).placeholder
210263
+ }
210264
+ ) : null
209082
210265
  ] });
209083
210266
  }
209084
210267
  function RoundedBody({ node, w, h, cls, showMult }) {
@@ -209262,7 +210445,7 @@ function SendAcceptBody({ node, w, h, accept }) {
209262
210445
  }
209263
210446
  function PackageBody({ node, w, h }) {
209264
210447
  if (node.meta?.gvMode !== void 0) {
209265
- const title = fitText(node.name, Math.max(24, w - 42), 11);
210448
+ const title = fitText(node.name, Math.max(24, w - (node.meta?.gvCanExpand === true ? 42 : 20)), 11);
209266
210449
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("g", { children: [
209267
210450
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { className: "dnode-rect package", d: packageFramePath(w, h) }),
209268
210451
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("text", { className: "dnode-kind", x: 10, y: 12, children: "\xABpackage\xBB" }),
@@ -210032,7 +211215,7 @@ function SysmlNode({ id: id2, data, draggable, selected: selected2, width, heigh
210032
211215
  internalsVisible: !hiddenContainer,
210033
211216
  featureCompartmentsVisible,
210034
211217
  cornerRadius: nodeCornerRadius(node.shape, node.isDef, h, (node.compartments?.length ?? 0) > 0),
210035
- onToggleInternals: ctx.onToggleInternals,
211218
+ onToggleInternals: node.meta?.internalsExpandable === true ? ctx.onToggleInternals : void 0,
210036
211219
  onToggleFeatureCompartments: ctx.onToggleFeatureCompartments
210037
211220
  }
210038
211221
  ) : null,
@@ -210042,7 +211225,8 @@ function SysmlNode({ id: id2, data, draggable, selected: selected2, width, heigh
210042
211225
  id: id2,
210043
211226
  name: node.name,
210044
211227
  value: node.value,
210045
- top: h - 36
211228
+ top: h - 36,
211229
+ ...valueFieldRole(node.keyword)
210046
211230
  },
210047
211231
  id2 + ":" + node.value
210048
211232
  ) : null,
@@ -210289,7 +211473,15 @@ function FrameNode({ id: id2, data, selected: selected2, width, height }) {
210289
211473
  strokeWidth: 0.8
210290
211474
  }
210291
211475
  ) : null,
210292
- frame2.value !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(AttributeValueShape, { value: frame2.value, w, top: frameHeaderHeight - 34 }) : null,
211476
+ frame2.value !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
211477
+ AttributeValueShape,
211478
+ {
211479
+ value: frame2.value,
211480
+ w,
211481
+ top: frameHeaderHeight - 34,
211482
+ placeholder: valueFieldRole(frame2.keyword).placeholder
211483
+ }
211484
+ ) : null,
210293
211485
  isStructuredControl ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("g", { className: "dstructured-condition-compartment", children: [
210294
211486
  isNamedStructuredAction ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
210295
211487
  "line",
@@ -210555,7 +211747,7 @@ function FrameNode({ id: id2, data, selected: selected2, width, height }) {
210555
211747
  internalsVisible: true,
210556
211748
  featureCompartmentsVisible,
210557
211749
  cornerRadius: frame2.isDef === true ? 0 : FRAME_USAGE_CORNER_RADIUS,
210558
- onToggleInternals: ctx.onToggleInternals,
211750
+ onToggleInternals: frame2.meta?.internalsExpandable === true ? ctx.onToggleInternals : void 0,
210559
211751
  onToggleFeatureCompartments: ctx.onToggleFeatureCompartments
210560
211752
  }
210561
211753
  ) : null,
@@ -210565,7 +211757,8 @@ function FrameNode({ id: id2, data, selected: selected2, width, height }) {
210565
211757
  id: id2,
210566
211758
  name: frame2.label,
210567
211759
  value: frame2.value,
210568
- top: frameHeaderHeight - 34
211760
+ top: frameHeaderHeight - 34,
211761
+ ...valueFieldRole(frame2.keyword)
210569
211762
  },
210570
211763
  id2 + ":" + frame2.value
210571
211764
  ) : null,
@@ -211260,7 +212453,7 @@ async function runExport(command) {
211260
212453
  }
211261
212454
 
211262
212455
  // src/main.ts
211263
- var VERSION2 = true ? "0.36.0" : "dev";
212456
+ var VERSION2 = true ? "0.38.0" : "dev";
211264
212457
  function display(file) {
211265
212458
  const rel2 = path9.relative(process.cwd(), file);
211266
212459
  return rel2 && !rel2.startsWith("..") ? rel2.split(path9.sep).join("/") : file;