sysml-diagram 0.28.0 → 0.29.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
@@ -161786,6 +161786,14 @@ function directNamedChildren(node) {
161786
161786
  }
161787
161787
  return result;
161788
161788
  }
161789
+ function boundVariableName(node) {
161790
+ if (!node || node.$type !== "ForLoopNode" && node.$type !== "AcceptNode")
161791
+ return void 0;
161792
+ const binding = node;
161793
+ if (binding.varSegs?.length)
161794
+ return void 0;
161795
+ return typeof binding.varName === "string" && binding.varName.length > 0 ? canonicalEscapedName(binding.varName) : void 0;
161796
+ }
161789
161797
  function isAncestor(candidate, node) {
161790
161798
  if (!candidate)
161791
161799
  return false;
@@ -161798,7 +161806,25 @@ function isAncestor(candidate, node) {
161798
161806
  function isSelfReference(candidate, node) {
161799
161807
  if (!candidate || !isAncestor(candidate, node))
161800
161808
  return false;
161801
- return !isPackage(candidate) && candidate.$type !== "NamespaceDecl";
161809
+ if (candidate === node)
161810
+ return true;
161811
+ if (isPackage(candidate) || candidate.$type === "NamespaceDecl")
161812
+ return false;
161813
+ const initializer = candidate.value;
161814
+ if (initializer && isAncestor(initializer, node))
161815
+ return true;
161816
+ const header = candidate;
161817
+ if (typeof header.name === "string" && header.name.length > 0)
161818
+ return false;
161819
+ for (const part of [
161820
+ ...header.preRelationships ?? [],
161821
+ ...header.relationships ?? [],
161822
+ ...header.typing ? [header.typing] : []
161823
+ ]) {
161824
+ if (isAncestor(part, node))
161825
+ return true;
161826
+ }
161827
+ return false;
161802
161828
  }
161803
161829
  function lastSegment(path10) {
161804
161830
  return path10.split(/::|\./u).pop() ?? path10;
@@ -161872,7 +161898,8 @@ var FeaturePathResolver = class {
161872
161898
  let current2 = this.resolveRoot(node, segments[0].text, snapshot);
161873
161899
  this.applyTarget(segments[0], current2);
161874
161900
  if (!current2.node && !current2.description) {
161875
- return { segments, indeterminateIndex: 0 };
161901
+ const under = node.$type === "Relationship" || node.$type === "LeadingRelationship" ? node : void 0;
161902
+ return this.lexicalInventoryComplete(node, snapshot, under) ? { segments, unresolvedIndex: 0 } : { segments, indeterminateIndex: 0 };
161876
161903
  }
161877
161904
  for (let index2 = 1; index2 < segments.length; index2 += 1) {
161878
161905
  const segment = segments[index2];
@@ -162025,12 +162052,77 @@ var FeaturePathResolver = class {
162025
162052
  }
162026
162053
  }
162027
162054
  for (let owner = node.$container; owner; owner = owner.$container) {
162055
+ const declaredName3 = owner.name;
162056
+ if (typeof declaredName3 === "string" && canonicalEscapedName(declaredName3) === name && !isSelfReference(owner, node)) {
162057
+ return this.targetForNode(owner, this.memberInventoryKnown(owner, snapshot));
162058
+ }
162059
+ if (boundVariableName(owner) === name)
162060
+ return this.targetForNode(owner, true);
162028
162061
  const local = directNamedChildren(owner).find((candidate) => nameOf(candidate) === name && !isSelfReference(candidate, node));
162029
162062
  if (local)
162030
162063
  return this.targetForNode(local, this.memberInventoryKnown(local, snapshot));
162064
+ for (const inheritedOwner of this.typedAndSpecializedOwners(owner, snapshot)) {
162065
+ const inherited = directNamedChildren(inheritedOwner).find((candidate) => nameOf(candidate) === name && !isSelfReference(candidate, node));
162066
+ if (inherited) {
162067
+ return this.targetForNode(inherited, this.memberInventoryKnown(inherited, snapshot));
162068
+ }
162069
+ }
162031
162070
  }
162032
162071
  return this.targetFromDescriptions(snapshot.byName.get(name), node);
162033
162072
  }
162073
+ // REQ-317 — issue #259. Whether the scope chain around `node` has a member
162074
+ // inventory this resolver can enumerate COMPLETELY. A type or supertype it
162075
+ // could not resolve carries members it cannot list, so a name missing from
162076
+ // what it can see is then no proof the name is absent, and reporting it
162077
+ // would be a false positive rather than a diagnosis.
162078
+ //
162079
+ // `under` is the relationship whose own target is being resolved. It is the
162080
+ // claim under test, so it must not also count as evidence that the scope is
162081
+ // unknowable — otherwise every unresolved target would silence the very
162082
+ // check that should report it.
162083
+ lexicalInventoryComplete(node, snapshot, under) {
162084
+ for (let owner = node.$container; owner; owner = owner.$container) {
162085
+ if (this.inheritsImplicitly(owner, snapshot, under))
162086
+ return false;
162087
+ if (!this.declaredTypesResolve(owner, snapshot, under))
162088
+ return false;
162089
+ for (const inheritedOwner of this.typedAndSpecializedOwners(owner, snapshot)) {
162090
+ if (!this.declaredTypesResolve(inheritedOwner, snapshot, under))
162091
+ return false;
162092
+ }
162093
+ }
162094
+ return true;
162095
+ }
162096
+ // issue #259 — OMG SysML gives a case its single `objective` and `subject`,
162097
+ // so a usage of a typed case IMPLICITLY redefines the one its definition
162098
+ // declares, whatever either is named, and inherits that one's members
162099
+ // (`verify vehicleMassRequirement :>> massRequirement` reaches
162100
+ // `massRequirement` through exactly that). This resolver does not evaluate
162101
+ // implicit redefinition, so where one applies it cannot enumerate the scope
162102
+ // and must not call a name absent.
162103
+ inheritsImplicitly(node, snapshot, under) {
162104
+ if (node.$type !== "ObjectiveDecl" && node.$type !== "SubjectDecl")
162105
+ return false;
162106
+ if (this.typedAndSpecializedOwners(node, snapshot).length > 0)
162107
+ return false;
162108
+ const owner = node.$container;
162109
+ return !!owner && (this.typedAndSpecializedOwners(owner, snapshot).length > 0 || !this.declaredTypesResolve(owner, snapshot, under));
162110
+ }
162111
+ // Every type and specialization target this element WRITES resolves to a node
162112
+ // whose own members are readable. An unresolved one is an unknown inventory.
162113
+ declaredTypesResolve(node, snapshot, under) {
162114
+ const record = node;
162115
+ if (record.typing?.type?.$refText && !this.typingTarget(node, snapshot))
162116
+ return false;
162117
+ const declared = [
162118
+ ...record.preRelationships ?? [],
162119
+ ...record.relationships ?? []
162120
+ ].filter((relation) => relation !== under && relation.kind && SPECIALIZATION_KINDS.has(relation.kind));
162121
+ if (declared.length === 0)
162122
+ return true;
162123
+ const written = declared.reduce((total, relation) => total + (relation.targets?.length ?? 0), 0);
162124
+ return this.specializationTargets(node, snapshot).length >= written;
162125
+ }
162034
162126
  resolveChild(current2, name, segments, index2, snapshot) {
162035
162127
  const owner = this.followAlias(current2, snapshot);
162036
162128
  if (owner.node) {
@@ -162341,6 +162433,377 @@ function memberSeparator(owner) {
162341
162433
  return isDocument(owner) || isNamespaceOnlyDecl(owner) ? "::" : ".";
162342
162434
  }
162343
162435
 
162436
+ // ../language-server/out/src/services/name-lookup.js
162437
+ function unquoteName(name) {
162438
+ return name.replace(/^'(.*)'$/u, "$1");
162439
+ }
162440
+ function pathSegments(path10) {
162441
+ const segments = [];
162442
+ let current2 = "";
162443
+ let quoted = false;
162444
+ for (let index2 = 0; index2 < path10.length; index2++) {
162445
+ const char = path10[index2];
162446
+ if (char === "'") {
162447
+ quoted = !quoted;
162448
+ current2 += char;
162449
+ continue;
162450
+ }
162451
+ if (!quoted && char === ":" && path10[index2 + 1] === ":") {
162452
+ segments.push(current2);
162453
+ current2 = "";
162454
+ index2++;
162455
+ continue;
162456
+ }
162457
+ if (!quoted && char === ".") {
162458
+ segments.push(current2);
162459
+ current2 = "";
162460
+ continue;
162461
+ }
162462
+ current2 += char;
162463
+ }
162464
+ segments.push(current2);
162465
+ return segments;
162466
+ }
162467
+ function simpleNameOf(name) {
162468
+ return pathSegments(name).at(-1) ?? name;
162469
+ }
162470
+ var ELEMENT_SEPARATOR = "\0";
162471
+ function elementKey(description) {
162472
+ return `${description.documentUri.toString()}${ELEMENT_SEPARATOR}${description.path}`;
162473
+ }
162474
+ function isDeclaredSpelling(description) {
162475
+ const kind = description.derivedKind;
162476
+ if (kind === "reexport" || kind === "inherited")
162477
+ return false;
162478
+ return pathSegments(description.name).length === 1;
162479
+ }
162480
+ var SysmlNameLookup = class {
162481
+ shared;
162482
+ byName;
162483
+ /** Element key → the declared spellings the index holds for that element. */
162484
+ spellings;
162485
+ constructor(shared) {
162486
+ this.shared = shared;
162487
+ this.shared.workspace.DocumentBuilder.onBuildPhase(DocumentState.IndexedContent, () => {
162488
+ this.byName = void 0;
162489
+ this.spellings = void 0;
162490
+ });
162491
+ }
162492
+ /** Every description indexed under `name`, in either spelling of an escaped name. */
162493
+ descriptions(name) {
162494
+ return this.index().get(name) ?? [];
162495
+ }
162496
+ /**
162497
+ * The ONE element `name` names, or `undefined` when the answer is not
162498
+ * certain: no element, or more than one. `accept` narrows the candidates
162499
+ * before ambiguity is judged, so "the only CALLABLE called `f`" is a
162500
+ * decidable question even where a part shares the name.
162501
+ */
162502
+ unique(name, accept) {
162503
+ const candidates = this.descriptions(name).filter((candidate) => !accept || accept(candidate));
162504
+ let found;
162505
+ let key;
162506
+ for (const candidate of candidates) {
162507
+ const candidateKey = elementKey(candidate);
162508
+ if (found === void 0) {
162509
+ found = candidate;
162510
+ key = candidateKey;
162511
+ continue;
162512
+ }
162513
+ if (candidateKey !== key)
162514
+ return void 0;
162515
+ }
162516
+ return found;
162517
+ }
162518
+ /**
162519
+ * Resolve a written path: the spelling the index holds verbatim first, then
162520
+ * its final segment. Both readings must name exactly one element.
162521
+ */
162522
+ uniqueForPath(path10, accept) {
162523
+ return this.unique(path10, accept) ?? this.unique(simpleNameOf(path10), accept);
162524
+ }
162525
+ /**
162526
+ * The declared spellings of the element `description` names — its regular
162527
+ * name and its `<short>` name — minus `written`.
162528
+ */
162529
+ otherNames(description, written) {
162530
+ const all = this.spellingIndex().get(elementKey(description)) ?? [];
162531
+ const seen = unquoteName(written);
162532
+ return all.filter((name) => unquoteName(name) !== seen);
162533
+ }
162534
+ index() {
162535
+ if (!this.byName)
162536
+ this.build();
162537
+ return this.byName;
162538
+ }
162539
+ spellingIndex() {
162540
+ if (!this.spellings)
162541
+ this.build();
162542
+ return this.spellings;
162543
+ }
162544
+ /** One pass over the index feeds both maps; neither is worth a second. */
162545
+ build() {
162546
+ const byName = /* @__PURE__ */ new Map();
162547
+ const spellings = /* @__PURE__ */ new Map();
162548
+ const add = (key, description) => {
162549
+ const bucket = byName.get(key);
162550
+ if (bucket)
162551
+ bucket.push(description);
162552
+ else
162553
+ byName.set(key, [description]);
162554
+ };
162555
+ for (const description of this.shared.workspace.IndexManager.allElements()) {
162556
+ add(description.name, description);
162557
+ const unquoted = unquoteName(description.name);
162558
+ if (unquoted !== description.name)
162559
+ add(unquoted, description);
162560
+ if (!isDeclaredSpelling(description))
162561
+ continue;
162562
+ const key = elementKey(description);
162563
+ const names = spellings.get(key);
162564
+ if (names) {
162565
+ if (!names.includes(description.name))
162566
+ names.push(description.name);
162567
+ } else {
162568
+ spellings.set(key, [description.name]);
162569
+ }
162570
+ }
162571
+ this.byName = byName;
162572
+ this.spellings = spellings;
162573
+ }
162574
+ };
162575
+ var lookups = /* @__PURE__ */ new WeakMap();
162576
+ function nameLookupFor(shared) {
162577
+ if (!shared)
162578
+ return void 0;
162579
+ const existing = lookups.get(shared);
162580
+ if (existing)
162581
+ return existing;
162582
+ const created = new SysmlNameLookup(shared);
162583
+ lookups.set(shared, created);
162584
+ return created;
162585
+ }
162586
+
162587
+ // ../language-server/out/src/services/effective-name.js
162588
+ var REDEFINITION_KINDS = /* @__PURE__ */ new Set([":>>", "redefines"]);
162589
+ var NO_CANDIDATES = [];
162590
+ var NO_RESOLVER = () => NO_CANDIDATES;
162591
+ var nameable = /* @__PURE__ */ new Map();
162592
+ function canBeNamed(node) {
162593
+ const known2 = nameable.get(node.$type);
162594
+ if (known2 !== void 0)
162595
+ return known2;
162596
+ let answer = false;
162597
+ try {
162598
+ answer = reflection2.getTypeMetaData(node.$type).properties.some((property3) => property3.name === "name");
162599
+ } catch {
162600
+ answer = false;
162601
+ }
162602
+ nameable.set(node.$type, answer);
162603
+ return answer;
162604
+ }
162605
+ function declaredName(node) {
162606
+ const value = node.name;
162607
+ return typeof value === "string" && value.length > 0 ? value : void 0;
162608
+ }
162609
+ function declaredShortName(node) {
162610
+ const value = node.shortName?.name;
162611
+ return typeof value === "string" && value.length > 0 ? value : void 0;
162612
+ }
162613
+ function firstRedefinitionPath(node) {
162614
+ const decl = node;
162615
+ const groups = [decl.preRelationships, decl.relationships];
162616
+ for (const group of groups) {
162617
+ if (!Array.isArray(group))
162618
+ continue;
162619
+ for (const relationship of group) {
162620
+ if (typeof relationship?.kind !== "string")
162621
+ continue;
162622
+ if (!REDEFINITION_KINDS.has(relationship.kind))
162623
+ continue;
162624
+ const targets = relationship.targets;
162625
+ if (!Array.isArray(targets))
162626
+ continue;
162627
+ for (const target of targets) {
162628
+ if (typeof target === "string" && target.length > 0)
162629
+ return target;
162630
+ }
162631
+ }
162632
+ }
162633
+ return void 0;
162634
+ }
162635
+ function writtenNameOf(path10) {
162636
+ const segment = simpleNameOf(path10).replace(/\s*\[[^\]]*\]\s*$/u, "").trim();
162637
+ return segment.length > 0 ? segment : void 0;
162638
+ }
162639
+ var memos = /* @__PURE__ */ new WeakMap();
162640
+ function memoFor(resolver) {
162641
+ const existing = memos.get(resolver);
162642
+ if (existing)
162643
+ return existing;
162644
+ const created = /* @__PURE__ */ new WeakMap();
162645
+ memos.set(resolver, created);
162646
+ return created;
162647
+ }
162648
+ function effectiveNamesOf(node, resolver = NO_RESOLVER) {
162649
+ const memo3 = memoFor(resolver);
162650
+ const cached = memo3.get(node);
162651
+ if (cached)
162652
+ return cached;
162653
+ const computed = derive(node, resolver, /* @__PURE__ */ new Set());
162654
+ memo3.set(node, computed);
162655
+ return computed;
162656
+ }
162657
+ function derive(node, resolver, seen) {
162658
+ const name = declaredName(node);
162659
+ const shortName = declaredShortName(node);
162660
+ if (name !== void 0 || shortName !== void 0) {
162661
+ return { name, shortName, origin: "declared" };
162662
+ }
162663
+ const path10 = canBeNamed(node) ? firstRedefinitionPath(node) : void 0;
162664
+ if (path10 === void 0)
162665
+ return { origin: "none" };
162666
+ if (seen.has(node))
162667
+ return { origin: "none", redefines: path10, problem: "cycle" };
162668
+ seen.add(node);
162669
+ try {
162670
+ const inherited = resolveNames(path10, node, resolver, seen);
162671
+ if (inherited?.problem) {
162672
+ return { origin: "none", redefines: path10, problem: inherited.problem };
162673
+ }
162674
+ if (inherited?.name !== void 0 || inherited?.shortName !== void 0) {
162675
+ return {
162676
+ name: inherited.name,
162677
+ shortName: inherited.shortName,
162678
+ origin: "derived",
162679
+ redefines: path10
162680
+ };
162681
+ }
162682
+ const written = writtenNameOf(path10);
162683
+ return written === void 0 ? { origin: "none", redefines: path10 } : { name: written, origin: "written", redefines: path10 };
162684
+ } finally {
162685
+ seen.delete(node);
162686
+ }
162687
+ }
162688
+ function resolveNames(path10, from, resolver, seen) {
162689
+ const candidates = resolver(path10, from);
162690
+ if (candidates.length === 0)
162691
+ return void 0;
162692
+ let names;
162693
+ for (const candidate of candidates) {
162694
+ const resolved = candidate.node ? derive(candidate.node, resolver, seen) : { name: candidate.name, shortName: candidate.shortName, origin: "declared" };
162695
+ if (resolved.problem)
162696
+ return resolved;
162697
+ if (resolved.name === void 0 && resolved.shortName === void 0)
162698
+ continue;
162699
+ if (!names) {
162700
+ names = resolved;
162701
+ continue;
162702
+ }
162703
+ if (differ(names.name, resolved.name) || differ(names.shortName, resolved.shortName)) {
162704
+ return { origin: "none", problem: "ambiguous" };
162705
+ }
162706
+ names = {
162707
+ name: names.name ?? resolved.name,
162708
+ shortName: names.shortName ?? resolved.shortName,
162709
+ origin: names.origin
162710
+ };
162711
+ }
162712
+ return names;
162713
+ }
162714
+ function differ(left, right) {
162715
+ return left !== void 0 && right !== void 0 && left !== right;
162716
+ }
162717
+ var localResolvers = /* @__PURE__ */ new WeakMap();
162718
+ function documentLocalResolver(root4) {
162719
+ const existing = localResolvers.get(root4);
162720
+ if (existing)
162721
+ return existing;
162722
+ let index2;
162723
+ const resolver = (path10, from) => {
162724
+ index2 ??= buildLocalNameIndex(root4);
162725
+ const simple = writtenNameOf(path10) ?? path10;
162726
+ const declared = index2.declared.qualified.get(path10) ?? index2.declared.simple.get(simple);
162727
+ const found = declared?.filter((candidate) => candidate !== from) ?? [];
162728
+ if (found.length > 0)
162729
+ return found.map((node) => ({ node }));
162730
+ if (path10 === simple)
162731
+ return NO_CANDIDATES;
162732
+ const nested = index2.effective.qualified.get(path10)?.filter((candidate) => candidate !== from);
162733
+ return nested && nested.length > 0 ? nested.map((node) => ({ node })) : NO_CANDIDATES;
162734
+ };
162735
+ localResolvers.set(root4, resolver);
162736
+ return resolver;
162737
+ }
162738
+ function localResolverFor(node) {
162739
+ return documentLocalResolver(ast_utils_exports.findRootNode(node));
162740
+ }
162741
+ function emptyTier() {
162742
+ return { qualified: /* @__PURE__ */ new Map(), simple: /* @__PURE__ */ new Map() };
162743
+ }
162744
+ function buildLocalNameIndex(root4) {
162745
+ const index2 = { declared: emptyTier(), effective: emptyTier() };
162746
+ const add = (map3, key, node) => {
162747
+ const bucket = map3.get(key);
162748
+ if (bucket) {
162749
+ if (!bucket.includes(node))
162750
+ bucket.push(node);
162751
+ } else {
162752
+ map3.set(key, [node]);
162753
+ }
162754
+ };
162755
+ for (const node of ast_utils_exports.streamAllContents(root4)) {
162756
+ if (node.$type === "ShortName" || node.$type === "ImportSeg")
162757
+ continue;
162758
+ const declared = [declaredName(node), declaredShortName(node)].filter((value) => value !== void 0);
162759
+ const written = declared.length === 0 && canBeNamed(node) ? writtenNameOf(firstRedefinitionPath(node) ?? "") : void 0;
162760
+ const tier = declared.length > 0 ? index2.declared : index2.effective;
162761
+ for (const name of declared.length > 0 ? declared : [written].filter((v) => v !== void 0)) {
162762
+ add(tier.simple, name, node);
162763
+ for (const path10 of qualifiedPathsOf(node, name))
162764
+ add(tier.qualified, path10, node);
162765
+ }
162766
+ }
162767
+ return index2;
162768
+ }
162769
+ function qualifiedPathsOf(node, name) {
162770
+ const owners = [];
162771
+ for (let owner = node.$container; owner; owner = owner.$container) {
162772
+ const ownerName = declaredName(owner) ?? declaredShortName(owner);
162773
+ if (ownerName !== void 0)
162774
+ owners.unshift(ownerName);
162775
+ }
162776
+ const paths = [];
162777
+ for (let start2 = 0; start2 < owners.length; start2++) {
162778
+ paths.push([...owners.slice(start2), name].join("::"));
162779
+ }
162780
+ return paths;
162781
+ }
162782
+ function indexResolver(lookup, astNode) {
162783
+ if (!lookup)
162784
+ return void 0;
162785
+ return (path10) => {
162786
+ const description = lookup.uniqueForPath(path10);
162787
+ if (!description)
162788
+ return NO_CANDIDATES;
162789
+ const node = description.node ?? astNode?.(description);
162790
+ return node ? [{ node }] : NO_CANDIDATES;
162791
+ };
162792
+ }
162793
+ function chainResolvers(...resolvers) {
162794
+ const active = resolvers.filter((resolver) => !!resolver);
162795
+ if (active.length === 1)
162796
+ return active[0];
162797
+ return (path10, from) => {
162798
+ for (const resolver of active) {
162799
+ const found = resolver(path10, from);
162800
+ if (found.length > 0)
162801
+ return found;
162802
+ }
162803
+ return NO_CANDIDATES;
162804
+ };
162805
+ }
162806
+
162344
162807
  // ../language-server/out/src/services/diagram-model-provider.js
162345
162808
  var lastSeg = (name) => {
162346
162809
  const i = Math.max(name.lastIndexOf("::"), name.lastIndexOf("."));
@@ -162728,18 +163191,11 @@ var portionKindOf = (node) => modifiersOf(node).find((m) => m === "timeslice" ||
162728
163191
  var isIndividualOccurrence = (node) => modifiersOf(node).includes("individual");
162729
163192
  var isOccurrenceModified = (node) => portionKindOf(node) !== void 0 || isIndividualOccurrence(node);
162730
163193
  var redefinedNameOf = (node) => {
162731
- const n2 = node;
162732
- for (const rel2 of [...n2.preRelationships ?? [], ...n2.relationships ?? []]) {
162733
- if (rel2.kind === ":>>" || rel2.kind === "redefines") {
162734
- const target = (rel2.targets ?? [])[0];
162735
- if (target)
162736
- return lastSeg(target);
162737
- }
162738
- }
162739
- return void 0;
163194
+ const names = effectiveNamesOf(node, localResolverFor(node));
163195
+ return names.origin === "derived" || names.origin === "written" ? names.name ?? names.shortName : void 0;
162740
163196
  };
162741
163197
  var effectiveNameOf = (node) => nameOf2(node) ?? redefinedNameOf(node);
162742
- var portionLabelOf = (node) => nameOf2(node) ?? (isOccurrenceModified(node) ? redefinedNameOf(node) : void 0);
163198
+ var portionLabelOf = (node) => effectiveNameOf(node);
162743
163199
  function diagramNodeId(node) {
162744
163200
  const name = nameOf2(node);
162745
163201
  if (name)
@@ -165304,16 +165760,16 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
165304
165760
  };
165305
165761
  const performedActions = depth < 8 && !(typeQ !== void 0 && seenTypes.has(typeQ)) ? effectiveMembersOf(part).filter((m) => m.$type === "PerformStmt" && !!nameOf2(m)).map((act) => {
165306
165762
  const pinSource = this.performTargetOf(act, index2) ?? act;
165307
- const pathSegments2 = this.isAnonymousBehaviorReference(act) ? this.featurePaths.resolveDeclarationPath(act).segments.map((segment) => segment.text) : [nameOf2(act)];
165763
+ const pathSegments3 = this.isAnonymousBehaviorReference(act) ? this.featurePaths.resolveDeclarationPath(act).segments.map((segment) => segment.text) : [nameOf2(act)];
165308
165764
  return {
165309
165765
  act,
165310
165766
  pinSource,
165311
- pathSegments: pathSegments2,
165312
- name: pathSegments2.at(-1) ?? nameOf2(act),
165767
+ pathSegments: pathSegments3,
165768
+ name: pathSegments3.at(-1) ?? nameOf2(act),
165313
165769
  key: concretePerformPath(act, pinSource)
165314
165770
  };
165315
165771
  }).filter((entry, i, list) => list.findIndex((other) => other.key === entry.key) === i) : [];
165316
- const performedActionInfos = performedActions.map(({ act, pinSource, pathSegments: pathSegments2, name, key }) => {
165772
+ const performedActionInfos = performedActions.map(({ act, pinSource, pathSegments: pathSegments3, name, key }) => {
165317
165773
  const id2 = `${instanceId}::__perform_${key}`;
165318
165774
  const inheritedFromDefinition = !!localUsage && !isAstDescendantOrSelf(act, localUsage);
165319
165775
  const syncDeclaration2 = this.synchronizationDeclarationOf(act, index2);
@@ -165321,7 +165777,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
165321
165777
  act,
165322
165778
  name,
165323
165779
  id: id2,
165324
- pathSegments: pathSegments2,
165780
+ pathSegments: pathSegments3,
165325
165781
  pins: this.actionPinPorts(pinSource, id2, index2, uri),
165326
165782
  meta: {
165327
165783
  ...ivEditMeta(act, id2, void 0, localUsage, [...localPath, name], uri),
@@ -166786,10 +167242,10 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
166786
167242
  };
166787
167243
  const emitFlowNode = (m, frameId, executionContext, occurrence, laneParts) => {
166788
167244
  const info = flowNodeInfo(m);
166789
- const declaredName2 = localFlowName(m);
167245
+ const declaredName3 = localFlowName(m);
166790
167246
  const id2 = occurrence;
166791
167247
  idByNode.set(m, id2);
166792
- registerStep(occurrence, id2, [declaredName2]);
167248
+ registerStep(occurrence, id2, [declaredName3]);
166793
167249
  if (info.shape === "action" || info.shape === "send" || info.shape === "accept")
166794
167250
  actionCount++;
166795
167251
  const pins = actionPinsOf(m, id2);
@@ -166821,9 +167277,9 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
166821
167277
  source: sourceOf2(m, uri),
166822
167278
  meta: {
166823
167279
  ...occurrenceEditMeta(occurrence),
166824
- ...declaredName2 ? {
166825
- declarationId: qnameOf(m) || declaredName2,
166826
- declarationName: declaredName2,
167280
+ ...declaredName3 ? {
167281
+ declarationId: qnameOf(m) || declaredName3,
167282
+ declarationName: declaredName3,
166827
167283
  declarationSource: sourceOf2(m, uri)
166828
167284
  } : {},
166829
167285
  ...isPromotablePerform(m) ? { promotablePerform: true } : {},
@@ -166935,9 +167391,9 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
166935
167391
  return;
166936
167392
  }
166937
167393
  const id2 = occurrence;
166938
- const declaredName2 = localFlowName(action);
167394
+ const declaredName3 = localFlowName(action);
166939
167395
  idByNode.set(action, id2);
166940
- registerStep(occurrence, id2, [declaredName2]);
167396
+ registerStep(occurrence, id2, [declaredName3]);
166941
167397
  if (content !== action) {
166942
167398
  idByNode.set(content, id2);
166943
167399
  if (isPartDecl(this.declaringOwnerOf(action)) && nameOf2(content)) {
@@ -166952,7 +167408,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
166952
167408
  registerPins(action, id2, pins, false);
166953
167409
  frames.push({
166954
167410
  id: id2,
166955
- label: declaredName2 ?? (action.$type === "PerformStmt" ? performLabel(action) : lastSeg(id2)),
167411
+ label: declaredName3 ?? (action.$type === "PerformStmt" ? performLabel(action) : lastSeg(id2)),
166956
167412
  keyword: keywordFor(action),
166957
167413
  parent: parentFrameId,
166958
167414
  isDef: action.isDef === true,
@@ -166964,9 +167420,9 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
166964
167420
  meta: {
166965
167421
  compositeAction: true,
166966
167422
  ...isPromotablePerform(action) ? { promotablePerform: true } : {},
166967
- ...declaredName2 ? {
166968
- declarationId: qnameOf(action) || declaredName2,
166969
- declarationName: declaredName2,
167423
+ ...declaredName3 ? {
167424
+ declarationId: qnameOf(action) || declaredName3,
167425
+ declarationName: declaredName3,
166970
167426
  declarationSource: sourceOf2(action, uri)
166971
167427
  } : {},
166972
167428
  // REQ-196 — the body a lane added here writes its `perform` against.
@@ -171082,7 +171538,7 @@ function outlineGroupForType(astType) {
171082
171538
 
171083
171539
  // ../language-server/out/src/services/document-symbol-provider.js
171084
171540
  var SPECIALIZATION_KINDS2 = /* @__PURE__ */ new Set([":>", "specializes"]);
171085
- var REDEFINITION_KINDS = /* @__PURE__ */ new Set([":>>", "redefines"]);
171541
+ var REDEFINITION_KINDS2 = /* @__PURE__ */ new Set([":>>", "redefines"]);
171086
171542
  var INHERITABLE_FEATURE_TYPES = /* @__PURE__ */ new Set([
171087
171543
  "ActionDecl",
171088
171544
  "AttributeDecl",
@@ -171123,7 +171579,10 @@ function symbolNameFor(node) {
171123
171579
  return "rep";
171124
171580
  }
171125
171581
  const redefined = redefinitionTargets(node)[0];
171126
- return redefined ? `:>> ${lastNameSegment(redefined)}` : void 0;
171582
+ if (!redefined)
171583
+ return void 0;
171584
+ const effective = effectiveNamesOf(node, localResolverFor(node));
171585
+ return `:>> ${effective.name ?? effective.shortName ?? lastNameSegment(redefined)}`;
171127
171586
  }
171128
171587
  function isDefinitionNode2(node) {
171129
171588
  return node.isDef === true;
@@ -171159,7 +171618,7 @@ function redefinitionTargets(node) {
171159
171618
  const n2 = node;
171160
171619
  const out = [];
171161
171620
  for (const rel2 of [...n2.preRelationships ?? [], ...n2.relationships ?? []]) {
171162
- if (rel2.kind && REDEFINITION_KINDS.has(rel2.kind))
171621
+ if (rel2.kind && REDEFINITION_KINDS2.has(rel2.kind))
171163
171622
  out.push(...rel2.targets ?? []);
171164
171623
  }
171165
171624
  return out;
@@ -171251,6 +171710,11 @@ function locallyDeclaredOrRedefinedFeatureNames(node) {
171251
171710
  for (const target of redefinitionTargets(child)) {
171252
171711
  names.add(lastNameSegment(target));
171253
171712
  }
171713
+ const effective = effectiveNamesOf(child, localResolverFor(child));
171714
+ if (effective.name)
171715
+ names.add(effective.name);
171716
+ if (effective.shortName)
171717
+ names.add(effective.shortName);
171254
171718
  }
171255
171719
  return names;
171256
171720
  }
@@ -171433,7 +171897,6 @@ var SysmlFoldingRangeProvider = class extends DefaultFoldingRangeProvider {
171433
171897
  continue;
171434
171898
  }
171435
171899
  let groupStart = -1;
171436
- let groupEnd = -1;
171437
171900
  let startLine = -1;
171438
171901
  let endLine = -1;
171439
171902
  const flushGroup = () => {
@@ -171445,7 +171908,6 @@ var SysmlFoldingRangeProvider = class extends DefaultFoldingRangeProvider {
171445
171908
  });
171446
171909
  }
171447
171910
  groupStart = -1;
171448
- groupEnd = -1;
171449
171911
  startLine = -1;
171450
171912
  endLine = -1;
171451
171913
  };
@@ -171457,7 +171919,6 @@ var SysmlFoldingRangeProvider = class extends DefaultFoldingRangeProvider {
171457
171919
  groupStart = i;
171458
171920
  startLine = range.start.line;
171459
171921
  }
171460
- groupEnd = i;
171461
171922
  endLine = range.end.line;
171462
171923
  } else {
171463
171924
  flushGroup();
@@ -171471,11 +171932,22 @@ var SysmlFoldingRangeProvider = class extends DefaultFoldingRangeProvider {
171471
171932
  // ../language-server/out/src/services/name-provider.js
171472
171933
  var SysmlNameProvider = class extends DefaultNameProvider {
171473
171934
  getName(node) {
171474
- return super.getName(node) ?? this.shortNameOf(node);
171935
+ return super.getName(node) ?? this.shortNameOf(node) ?? this.effectiveNameOf(node);
171475
171936
  }
171937
+ /**
171938
+ * REQ-404 — deliberately NOT extended to the effective name. There is no
171939
+ * text to select, and a rename that reported one would offer to edit a name
171940
+ * the declaration never writes.
171941
+ */
171476
171942
  getNameNode(node) {
171477
171943
  return super.getNameNode(node) ?? this.shortNameNodeOf(node);
171478
171944
  }
171945
+ // REQ-404 — one shared derivation (effective-name.ts), resolved against this
171946
+ // document's declarations; the same answer scope computation indexes.
171947
+ effectiveNameOf(node) {
171948
+ const names = effectiveNamesOf(node, localResolverFor(node));
171949
+ return names.origin === "derived" || names.origin === "written" ? names.name ?? names.shortName : void 0;
171950
+ }
171479
171951
  shortNameOf(node) {
171480
171952
  const value = node.shortName?.name;
171481
171953
  return typeof value === "string" && value.length > 0 ? value : void 0;
@@ -171501,21 +171973,21 @@ function getDimensionTable() {
171501
171973
  function isDimensionTableLoaded() {
171502
171974
  return table !== void 0;
171503
171975
  }
171504
- function unquoteName(name) {
171976
+ function unquoteName2(name) {
171505
171977
  return name.replace(/^'(.*)'$/, "$1");
171506
171978
  }
171507
171979
  function lastSegment2(name) {
171508
171980
  const idx = name.lastIndexOf("::");
171509
- return unquoteName(idx >= 0 ? name.slice(idx + 2) : name);
171981
+ return unquoteName2(idx >= 0 ? name.slice(idx + 2) : name);
171510
171982
  }
171511
171983
  function directUnitDimension(symbol) {
171512
171984
  if (!table)
171513
171985
  return void 0;
171514
- const unquoted = unquoteName(symbol);
171986
+ const unquoted = unquoteName2(symbol);
171515
171987
  return table.unitDims[unquoted] ?? table.unitDims[lastSegment2(unquoted)];
171516
171988
  }
171517
171989
  function isDirectKnownUnit(symbol) {
171518
- const unquoted = unquoteName(symbol);
171990
+ const unquoted = unquoteName2(symbol);
171519
171991
  return unitSymbolSet.has(unquoted) || unitSymbolSet.has(lastSegment2(unquoted));
171520
171992
  }
171521
171993
  function unitDimension(symbol) {
@@ -171536,7 +172008,7 @@ function unitQuantityKind(symbol) {
171536
172008
  function unitQuantityKinds(symbol) {
171537
172009
  if (!table)
171538
172010
  return [];
171539
- const unquoted = unquoteName(symbol);
172011
+ const unquoted = unquoteName2(symbol);
171540
172012
  const kinds = table.unitKind[unquoted] ?? table.unitKind[lastSegment2(unquoted)];
171541
172013
  if (Array.isArray(kinds))
171542
172014
  return kinds;
@@ -171603,7 +172075,7 @@ function superscript(n2) {
171603
172075
  return String(n2).split("").map((c) => SUPERSCRIPT[c] ?? c).join("");
171604
172076
  }
171605
172077
  function compoundUnitDimension(symbol) {
171606
- const factors = splitUnitFactors(unquoteName(symbol));
172078
+ const factors = splitUnitFactors(unquoteName2(symbol));
171607
172079
  if (!factors)
171608
172080
  return void 0;
171609
172081
  const parsed = factors.map((factor) => ({ op: factor.op, factor: parseUnitFactor(factor.text) }));
@@ -171739,7 +172211,7 @@ function contextUnitDimension(symbol, ctx) {
171739
172211
  const directLocal = ctx.unitDim?.(lastSegment2(symbol));
171740
172212
  if (directLocal)
171741
172213
  return resultDimension(directLocal);
171742
- const factors = splitUnitFactors(unquoteName(symbol));
172214
+ const factors = splitUnitFactors(unquoteName2(symbol));
171743
172215
  if (!factors || factors.length === 0)
171744
172216
  return void 0;
171745
172217
  let result = {};
@@ -171760,7 +172232,7 @@ function contextUnitDimension(symbol, ctx) {
171760
172232
  function isKnownUnitInContext(symbol, ctx) {
171761
172233
  if (ctx.unitDim?.(lastSegment2(symbol)))
171762
172234
  return true;
171763
- const factors = splitUnitFactors(unquoteName(symbol));
172235
+ const factors = splitUnitFactors(unquoteName2(symbol));
171764
172236
  return !!factors && factors.length > 0 && factors.every((token) => {
171765
172237
  const factor = parseUnitFactor(token.text);
171766
172238
  return !!factor && (!!ctx.unitDim?.(lastSegment2(factor.name)) || isDirectKnownUnit(factor.name));
@@ -171972,7 +172444,7 @@ function isComparison(op) {
171972
172444
  return op === "==" || op === "!=" || op === "===" || op === "!==" || op === "<" || op === ">" || op === "<=" || op === ">=";
171973
172445
  }
171974
172446
  function reportUnknownUnit(node, property3, symbol, ctx) {
171975
- const display2 = unquoteName(symbol);
172447
+ const display2 = unquoteName2(symbol);
171976
172448
  const suggestions = nearestUnits(display2, 3);
171977
172449
  const hint = suggestions.length > 0 ? ` Did you mean ${suggestions.map((s) => `'${s}'`).join(", ")}?` : "";
171978
172450
  ctx.issues.push({
@@ -172219,6 +172691,16 @@ var DIAGNOSTIC_MESSAGES = {
172219
172691
  // there, and rewriting it is mechanical — the import keeps working exactly
172220
172692
  // as it did, since a root import was never re-exported to begin with.
172221
172693
  RES021_ROOT_IMPORT_VISIBILITY: (visibility) => `An import in a file's root namespace must be 'private' \u2014 nothing can import the root namespace, so '${visibility}' re-exports to no one.`,
172694
+ // REQ-404 — issue #155. OMG SysML v2 Part 1 §7.6.5 (Usage Names) derives the
172695
+ // names of an unnamed redefining usage from the feature it redefines. Two
172696
+ // things stop that derivation dead: a chain that comes back to the usage
172697
+ // itself, and a target answered by elements that do not agree on the name.
172698
+ // Neither may be settled by picking one, because the name decides what the
172699
+ // feature IS - what it shadows, what resolves to it, what the diagram draws.
172700
+ // The fix is in the source: give the usage a name of its own, or write the
172701
+ // redefinition target so it names one feature.
172702
+ RES022_EFFECTIVE_NAME_CYCLE: (target) => `This usage declares no name, and the redefinition of '${target}' leads back to it, so it has no name to take. Name the usage, or redefine a feature outside the cycle.`,
172703
+ RES022_EFFECTIVE_NAME_AMBIGUOUS: (target) => `This usage declares no name, and '${target}' is answered by elements with different names, so which name it takes is undecided. Name the usage, or qualify the redefinition target.`,
172222
172704
  // issue #153 — OMG SysML v2 Part 1 §7.5.4 (Filtered Packages) puts an element
172223
172705
  // filter in a package, where it restricts that package's imported memberships;
172224
172706
  // a view body is the one other place it is defined for (it restricts what the
@@ -172531,6 +173013,15 @@ function identificationLabel(node) {
172531
173013
  return `<${shortName}>`;
172532
173014
  return node.name;
172533
173015
  }
173016
+ function effectiveIdentificationLabel(node) {
173017
+ const names = effectiveNamesOf(node, localResolverFor(node));
173018
+ if (names.problem)
173019
+ return void 0;
173020
+ const name = names.name ?? names.shortName;
173021
+ if (!name)
173022
+ return void 0;
173023
+ return names.shortName && names.shortName !== name ? `<${names.shortName}> ${name}` : name;
173024
+ }
172534
173025
  function typingLabel(typing) {
172535
173026
  if (!typing)
172536
173027
  return "";
@@ -172606,7 +173097,7 @@ function declarationLine(node) {
172606
173097
  const named2 = node;
172607
173098
  const dir = directionLabel(node);
172608
173099
  const kind = kindLabel(node);
172609
- const name = identificationLabel(named2) ?? "(anonymous)";
173100
+ const name = identificationLabel(named2) ?? effectiveIdentificationLabel(named2) ?? "(anonymous)";
172610
173101
  const typing = typingLabel(named2.typing);
172611
173102
  const mult = multiplicityLabel(node);
172612
173103
  const rels = relationshipLabel(allRelationships(named2));
@@ -172863,7 +173354,7 @@ function buildHoverMarkdown(node, relationshipDetails, documentation) {
172863
173354
  const named2 = node;
172864
173355
  const dir = directionLabel(node);
172865
173356
  const kind = kindLabel(node);
172866
- const name = identificationLabel(named2) ?? "(anonymous)";
173357
+ const name = identificationLabel(named2) ?? effectiveIdentificationLabel(named2) ?? "(anonymous)";
172867
173358
  const typing = typingLabel(named2.typing);
172868
173359
  const mult = multiplicityLabel(node);
172869
173360
  const multHint = multiplicityPlainEnglish(node);
@@ -174206,7 +174697,7 @@ var SysmlCompletionProvider = class extends DefaultCompletionProvider {
174206
174697
  qualifiedNameFor(desc) {
174207
174698
  if (desc.name.includes("::"))
174208
174699
  return desc.name;
174209
- const candidates = this.qualifiedNamesByElement().get(elementKey(desc));
174700
+ const candidates = this.qualifiedNamesByElement().get(elementKey2(desc));
174210
174701
  return candidates?.find((name) => simpleName(name) === desc.name);
174211
174702
  }
174212
174703
  // REQ-245, REQ-268 — An element's qualified names, shortest first, keyed by
@@ -174222,7 +174713,7 @@ var SysmlCompletionProvider = class extends DefaultCompletionProvider {
174222
174713
  for (const desc of this.indexManager.allElements()) {
174223
174714
  if (!desc.name.includes("::"))
174224
174715
  continue;
174225
- const key = elementKey(desc);
174716
+ const key = elementKey2(desc);
174226
174717
  const names = byElement.get(key);
174227
174718
  if (names)
174228
174719
  names.push(desc.name);
@@ -174467,7 +174958,7 @@ function isPackageBody(prefix) {
174467
174958
  return true;
174468
174959
  return /\bpackage\s+(?:<[^>]+>\s*)?[\p{L}_'][^;{}]*$/u.test(prefix.slice(Math.max(0, open - 160), open));
174469
174960
  }
174470
- function elementKey(desc) {
174961
+ function elementKey2(desc) {
174471
174962
  return `${desc.documentUri.toString()}#${desc.path}#${desc.type}`;
174472
174963
  }
174473
174964
  function isArrowInvocableName(name) {
@@ -174525,7 +175016,7 @@ function isDefined(value) {
174525
175016
  }
174526
175017
  function nodeName(node) {
174527
175018
  const value = node?.name;
174528
- return typeof value === "string" && value.length > 0 ? unquoteName2(value) : void 0;
175019
+ return typeof value === "string" && value.length > 0 ? unquoteName3(value) : void 0;
174529
175020
  }
174530
175021
  function nodeMembers(node) {
174531
175022
  const members = node?.members;
@@ -174544,7 +175035,7 @@ function receiverSteps(receiver) {
174544
175035
  let match;
174545
175036
  while ((match = pattern.exec(receiver)) !== null) {
174546
175037
  steps.push({
174547
- text: unquoteName2(match[2]),
175038
+ text: unquoteName3(match[2]),
174548
175039
  separator: steps.length === 0 ? void 0 : match[1]
174549
175040
  });
174550
175041
  }
@@ -174601,7 +175092,7 @@ function simpleName(name) {
174601
175092
  if (!name)
174602
175093
  return void 0;
174603
175094
  const parts = name.split(/::|\./u);
174604
- return unquoteName2(parts.at(-1) ?? name);
175095
+ return unquoteName3(parts.at(-1) ?? name);
174605
175096
  }
174606
175097
  function importCovers(text, importPath) {
174607
175098
  const packagePath = importPath.split("::").slice(0, -1).join("::");
@@ -174716,7 +175207,7 @@ function importSortKey(line2) {
174716
175207
  function escapeRegExp3(value) {
174717
175208
  return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
174718
175209
  }
174719
- function unquoteName2(name) {
175210
+ function unquoteName3(name) {
174720
175211
  return name.replace(/^'(.*)'$/u, "$1");
174721
175212
  }
174722
175213
  function unitInsertText(symbol) {
@@ -174812,7 +175303,7 @@ function evaluateFilterCondition(condition, element, options) {
174812
175303
  return value.kind === "boolean" ? value.value : void 0;
174813
175304
  }
174814
175305
  function extensionFor(ctx) {
174815
- const ext = (node, evaluate2) => {
175306
+ const ext = (node, _evaluate) => {
174816
175307
  switch (node.$type) {
174817
175308
  case "SelfClassifyExpr":
174818
175309
  return classify(node, ctx);
@@ -175321,7 +175812,7 @@ function selectMemberships(path10, form, globalDescriptions) {
175321
175812
  const index2 = GlobalDescriptionIndex.from(globalDescriptions);
175322
175813
  const entries = [];
175323
175814
  if (form.includesSelf) {
175324
- const simple = simpleNameOf(path10);
175815
+ const simple = simpleNameOf2(path10);
175325
175816
  const self2 = index2.named(path10).find((desc) => form.importAll || !isPrivateDescription(desc));
175326
175817
  if (self2)
175327
175818
  entries.push({ name: simple, targetName: self2.name, description: self2 });
@@ -175340,7 +175831,7 @@ function selectMemberships(path10, form, globalDescriptions) {
175340
175831
  }
175341
175832
  return entries;
175342
175833
  }
175343
- function simpleNameOf(path10) {
175834
+ function simpleNameOf2(path10) {
175344
175835
  return path10.includes("::") ? path10.slice(path10.lastIndexOf("::") + 2) : path10;
175345
175836
  }
175346
175837
  function isOwnedMembership(desc) {
@@ -175974,6 +176465,22 @@ var ConformanceModel = class {
175974
176465
  };
175975
176466
 
175976
176467
  // ../language-server/out/src/services/validator.js
176468
+ var REDEFINITION_KINDS3 = /* @__PURE__ */ new Set([
176469
+ ":>>",
176470
+ "redefines",
176471
+ ":>",
176472
+ "subsets",
176473
+ "specializes"
176474
+ ]);
176475
+ function isBoundReferencePart(node) {
176476
+ let declaration = node.$container;
176477
+ while (declaration && !isPartDecl(declaration))
176478
+ declaration = declaration.$container;
176479
+ if (!declaration)
176480
+ return false;
176481
+ const modifiers2 = declaration.modifiers ?? [];
176482
+ return modifiers2.includes("ref");
176483
+ }
175977
176484
  var severityOverrides = {};
175978
176485
  function severity(code, defaultSeverity) {
175979
176486
  return severityOverrides[code] ?? defaultSeverity;
@@ -176172,15 +176679,11 @@ var SysmlValidator = class _SysmlValidator {
176172
176679
  // dispatches `checkPathExpr`, so without a shared decision the two would drift
176173
176680
  // and a body would quietly escape a diagnostic the surrounding model receives.
176174
176681
  featurePathFault(node) {
176175
- let declaration = node.$container;
176176
- while (declaration && !isPartDecl(declaration))
176177
- declaration = declaration.$container;
176178
- const modifiers2 = declaration?.modifiers ?? [];
176179
- if (!declaration || !modifiers2.includes("ref"))
176180
- return void 0;
176181
176682
  const resolution = this.featurePaths.resolve(node);
176182
176683
  if (resolution.unresolvedIndex === void 0)
176183
176684
  return void 0;
176685
+ if (resolution.unresolvedIndex > 0 && !isBoundReferencePart(node))
176686
+ return void 0;
176184
176687
  const invalid = resolution.segments[resolution.unresolvedIndex];
176185
176688
  return {
176186
176689
  segment: invalid.text,
@@ -176188,6 +176691,28 @@ var SysmlValidator = class _SysmlValidator {
176188
176691
  range: invalid.cst.range
176189
176692
  };
176190
176693
  }
176694
+ // REQ-317 — issue #259. A redefinition or subsetting target is a written path
176695
+ // too (`attribute :>> maxMass`, `attribute other :> maxMass`), and the grammar
176696
+ // stores it as a plain `RelationPath` STRING rather than a Langium
176697
+ // cross-reference, so nothing else can diagnose it either: a target that names
176698
+ // nothing linked silently, and the model kept a relationship to an element that
176699
+ // does not exist.
176700
+ //
176701
+ // Only the ROOT segment is judged, on the same terms `checkPathExpr` uses: the
176702
+ // resolver reports an absent root only when it could enumerate the surrounding
176703
+ // inventory completely. A later segment depends on the KerML semantic model
176704
+ // this resolver does not evaluate.
176705
+ checkRelationshipTargets(node, accept) {
176706
+ if (!node.kind || !REDEFINITION_KINDS3.has(node.kind))
176707
+ return;
176708
+ for (let ordinal = 0; ordinal < node.targets.length; ordinal += 1) {
176709
+ const resolution = this.featurePaths.resolvePropertyPath(node, "targets", ordinal);
176710
+ if (resolution.unresolvedIndex !== 0)
176711
+ continue;
176712
+ const invalid = resolution.segments[0];
176713
+ 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 } });
176714
+ }
176715
+ }
176191
176716
  // REQ-389 — Namespace qualification versus feature chaining in every written path
176192
176717
  // issue #213 — RES019: `::` binds tighter than `.`. Each dot-separated link of
176193
176718
  // a KerML FeatureChain is a complete QualifiedName, and an
@@ -177579,6 +178104,7 @@ ${baseIndent}}`;
177579
178104
  for (const decl of decls) {
177580
178105
  this.checkCyclicSpecialization(decl, index2, accept);
177581
178106
  this.checkSelfContainment(decl, accept);
178107
+ this.checkEffectiveName(decl, accept);
177582
178108
  }
177583
178109
  for (const stmt of verifyStmts)
177584
178110
  this.checkRelationshipTargetKind(stmt, stmt.target, "verify", index2, aliasMap, accept);
@@ -178213,6 +178739,30 @@ ${baseIndent}}`;
178213
178739
  "PrefixMetadataMember",
178214
178740
  "MetadataAnnotation"
178215
178741
  ]);
178742
+ /**
178743
+ * REQ-404 — RES022: an unnamed redefining usage whose effective name cannot
178744
+ * be derived (issue #155).
178745
+ *
178746
+ * OMG SysML v2 Part 1 §7.6.5 gives such a usage the names of the feature its
178747
+ * first owned redefinition names. Two shapes leave it nameless: a chain that
178748
+ * returns to the usage, and a target answered by elements that disagree
178749
+ * about the name. Both are reported rather than settled, because a name
178750
+ * decides what the feature shadows, what resolves to it and what a diagram
178751
+ * draws it as - a picked one would read as authoritative and be wrong.
178752
+ *
178753
+ * A usage that writes any name of its own is not in question, and a target
178754
+ * that simply does not resolve is not either: the written spelling stands,
178755
+ * and an unresolvable path is RES001's to report.
178756
+ */
178757
+ checkEffectiveName(decl, accept) {
178758
+ if (declName(decl) !== void 0 || shortNameOf(decl) !== void 0)
178759
+ return;
178760
+ const names = effectiveNamesOf(decl, localResolverFor(decl));
178761
+ if (!names.problem)
178762
+ return;
178763
+ const target = names.redefines ?? "";
178764
+ accept(severity("RES022", "error"), names.problem === "cycle" ? DIAGNOSTIC_MESSAGES.RES022_EFFECTIVE_NAME_CYCLE(target) : DIAGNOSTIC_MESSAGES.RES022_EFFECTIVE_NAME_AMBIGUOUS(target), { node: decl, code: "RES022" });
178765
+ }
178216
178766
  // REQ-378 — RES017: indistinguishable members within a namespace (issue #183).
178217
178767
  //
178218
178768
  // KerML's validateNamespaceDistinguishability (Pilot KerMLValidator.checkNamespace)
@@ -178753,6 +179303,10 @@ ${baseIndent}}`;
178753
179303
  Document: this.checkDocument.bind(this),
178754
179304
  PartDecl: this.checkPartDecl.bind(this),
178755
179305
  PathExpr: this.checkPathExpr.bind(this),
179306
+ // issue #259 — the same absent-name rule on a redefinition or
179307
+ // subsetting target, which is a written path string as well.
179308
+ Relationship: this.checkRelationshipTargets.bind(this),
179309
+ LeadingRelationship: this.checkRelationshipTargets.bind(this),
178756
179310
  // issue #213 — RES019: the `::` vs `.` rule on the reference-form
178757
179311
  // declarations that reach their target through OwnedReferenceSubsetting.
178758
179312
  PerformStmt: this.checkChainSeparators.bind(this),
@@ -179926,7 +180480,10 @@ var SysmlScopeComputation = class extends DefaultScopeComputation {
179926
180480
  result.push({
179927
180481
  ...ownAliases[0],
179928
180482
  name,
179929
- derived: start2 > 0 || separator === "." || void 0
180483
+ derived: start2 > 0 || separator === "." || void 0,
180484
+ // REQ-404 — a path THROUGH an effective name is itself
180485
+ // derived from a redefinition, however it is spelled.
180486
+ effective: suffix.some((segment) => segment.aliases.every((alias) => alias.effective)) || void 0
179930
180487
  });
179931
180488
  }
179932
180489
  }
@@ -179946,13 +180503,18 @@ var SysmlScopeComputation = class extends DefaultScopeComputation {
179946
180503
  this.addAlias(aliases, seen, node.name, this.nameNodeOf(node));
179947
180504
  const shortName = node.shortName;
179948
180505
  this.addAlias(aliases, seen, shortName?.name, grammar_utils_exports.findNodeForProperty(shortName?.$cstNode, "name"));
180506
+ const effective = effectiveNamesOf(node, localResolverFor(node));
180507
+ if (effective.origin !== "declared" && effective.origin !== "none") {
180508
+ this.addAlias(aliases, seen, effective.name, void 0, true);
180509
+ this.addAlias(aliases, seen, effective.shortName, void 0, true);
180510
+ }
179949
180511
  return aliases;
179950
180512
  }
179951
- addAlias(aliases, seen, value, cstNode) {
180513
+ addAlias(aliases, seen, value, cstNode, effective = false) {
179952
180514
  if (typeof value !== "string" || value.length === 0 || seen.has(value))
179953
180515
  return;
179954
180516
  seen.add(value);
179955
- aliases.push({ name: value, cstNode });
180517
+ aliases.push({ name: value, cstNode, ...effective ? { effective: true } : {} });
179956
180518
  }
179957
180519
  nameNodeOf(node) {
179958
180520
  return grammar_utils_exports.findNodeForProperty(node.$cstNode, "name");
@@ -179964,6 +180526,10 @@ var SysmlScopeComputation = class extends DefaultScopeComputation {
179964
180526
  ...visibility ? { visibility } : {},
179965
180527
  ...visibility === "private" ? { isPrivate: true } : {},
179966
180528
  ...alias.derived ? { isDerivedAlias: true, derivedKind: "relative" } : {},
180529
+ // REQ-404 — issue #155: the name is the model's, not the text's, so
180530
+ // auto-import must not offer it as a written spelling. It still names
180531
+ // an OWNED member, so a recursive import descends through it.
180532
+ ...alias.effective ? { isDerivedAlias: true, derivedKind: "effective" } : {},
179967
180533
  // REQ-242 — issue #103 — mirrors what the precomputed library index
179968
180534
  // records, so consumers read def-ness the same way for workspace and
179969
180535
  // library symbols.
@@ -180110,9 +180676,13 @@ var SysmlLinker = class extends DefaultLinker {
180110
180676
  // ../language-server/out/src/services/rename-provider.js
180111
180677
  var SysmlRenameProvider = class extends DefaultRenameProvider {
180112
180678
  langiumDocuments;
180679
+ locator;
180680
+ featurePaths;
180113
180681
  constructor(services) {
180114
180682
  super(services);
180115
180683
  this.langiumDocuments = services.shared.workspace.LangiumDocuments;
180684
+ this.locator = services.workspace.AstNodeLocator;
180685
+ this.featurePaths = new FeaturePathResolver(services);
180116
180686
  }
180117
180687
  // REQ-261 — reject a rename request whose cursor resolves to a library
180118
180688
  // declaration: such a symbol has no meaningful "prepare rename" range
@@ -180131,7 +180701,8 @@ var SysmlRenameProvider = class extends DefaultRenameProvider {
180131
180701
  const target = this.resolveDeclarationAt(document2, params.position);
180132
180702
  if (target && isLibraryDocument(ast_utils_exports.getDocument(target)))
180133
180703
  return void 0;
180134
- const edit = await super.rename(document2, { ...params, newName: encodeUnrestrictedName(params.newName) }, cancelToken);
180704
+ const newName = encodeUnrestrictedName(params.newName);
180705
+ const edit = await super.rename(document2, { ...params, newName }, cancelToken);
180135
180706
  if (!edit?.changes)
180136
180707
  return edit;
180137
180708
  const changes = {};
@@ -180141,8 +180712,121 @@ var SysmlRenameProvider = class extends DefaultRenameProvider {
180141
180712
  continue;
180142
180713
  changes[uri] = textEdits;
180143
180714
  }
180715
+ if (target)
180716
+ this.addWrittenPathEdits(changes, target, newName);
180144
180717
  return { ...edit, changes };
180145
180718
  }
180719
+ // issue #255 — the references Langium cannot see. An expression operand
180720
+ // (`require constraint { maxMass > 0 }`) and a redefinition or subsetting
180721
+ // target (`attribute :>> maxMass`) are written as PLAIN PATH STRINGS in the
180722
+ // grammar (PathExpr / RelationPath), not as Langium cross-references, so
180723
+ // `findReferences` reports none of them and a rename left every one of them
180724
+ // spelling the old name.
180725
+ //
180726
+ // They are resolved here the same way go-to-definition resolves them
180727
+ // (`FeaturePathResolver`, the one path-resolution rule in the server), and a
180728
+ // segment is edited ONLY when it resolves to this exact declaration. Matching
180729
+ // by resolution rather than by spelling is what keeps a same-named feature of
180730
+ // another element untouched.
180731
+ // REQ-262 — Rename: workspace edit, library not renamable
180732
+ addWrittenPathEdits(changes, declaration, newName) {
180733
+ const oldName = canonicalEscapedName(declaration.name ?? "");
180734
+ if (!oldName)
180735
+ return;
180736
+ const spelledVerbatim = encodeUnrestrictedName(oldName) === oldName;
180737
+ for (const doc of this.langiumDocuments.all) {
180738
+ if (isLibraryDocument(doc))
180739
+ continue;
180740
+ const root4 = doc.parseResult?.value;
180741
+ if (!root4)
180742
+ continue;
180743
+ if (spelledVerbatim && !doc.textDocument.getText().includes(oldName))
180744
+ continue;
180745
+ const uri = doc.uri.toString();
180746
+ const edits = changes[uri] ?? [];
180747
+ const claimed = new Set(edits.map((edit) => `${edit.range.start.line}:${edit.range.start.character}`));
180748
+ const added = [];
180749
+ for (const segment of this.writtenPathSegments(root4, oldName)) {
180750
+ const resolved = this.resolvedNodeOf(segment);
180751
+ if (!resolved || !this.denotes(resolved, declaration))
180752
+ continue;
180753
+ const key = `${segment.cst.range.start.line}:${segment.cst.range.start.character}`;
180754
+ if (claimed.has(key))
180755
+ continue;
180756
+ claimed.add(key);
180757
+ added.push({ range: segment.cst.range, newText: newName });
180758
+ }
180759
+ if (added.length)
180760
+ changes[uri] = [...edits, ...added];
180761
+ }
180762
+ }
180763
+ // Every written-path segment of one document that SPELLS the old name. The
180764
+ // spelling test comes first because resolving a path is the expensive half.
180765
+ // `FeaturePathResolver` already canonicalises each segment it returns, so the
180766
+ // comparison is against `oldName` directly.
180767
+ *writtenPathSegments(root4, oldName) {
180768
+ const matching = (segments) => segments.filter((segment) => segment.text === oldName);
180769
+ const spellsName = (path10) => !!path10 && pathSegments2(path10).some((step) => canonicalEscapedName(step) === oldName);
180770
+ for (const node of [root4, ...ast_utils_exports.streamAllContents(root4)]) {
180771
+ if (isPathExpr(node)) {
180772
+ if (!spellsName(node.path))
180773
+ continue;
180774
+ yield* matching(this.featurePaths.resolve(node).segments);
180775
+ continue;
180776
+ }
180777
+ if (!isRelationship(node) && !isLeadingRelationship(node))
180778
+ continue;
180779
+ for (let ordinal = 0; ordinal < node.targets.length; ordinal += 1) {
180780
+ if (!spellsName(node.targets[ordinal]))
180781
+ continue;
180782
+ yield* matching(this.featurePaths.resolvePropertyPath(node, "targets", ordinal).segments);
180783
+ }
180784
+ }
180785
+ }
180786
+ // An anonymous redefinition (`attribute :>> maxMass = 1500.0;`) declares NO
180787
+ // name of its own — it carries the name of what it redefines. A later
180788
+ // `other :> maxMass` in the same body therefore resolves to that redefinition
180789
+ // rather than to the original declaration, yet it still spells the renamed
180790
+ // name and still has to be rewritten. Follow the redefinition chain, which is
180791
+ // exactly the chain the name itself travels.
180792
+ denotes(node, declaration, seen = /* @__PURE__ */ new Set()) {
180793
+ if (node === declaration)
180794
+ return true;
180795
+ if (seen.has(node))
180796
+ return false;
180797
+ seen.add(node);
180798
+ const own = node.name;
180799
+ if (typeof own === "string" && own.length > 0)
180800
+ return false;
180801
+ const relational = node;
180802
+ for (const relationship of [
180803
+ ...relational.preRelationships ?? [],
180804
+ ...relational.relationships ?? []
180805
+ ]) {
180806
+ if (relationship.kind !== ":>>" && relationship.kind !== "redefines")
180807
+ continue;
180808
+ const targets = relationship.targets ?? [];
180809
+ for (let ordinal = 0; ordinal < targets.length; ordinal += 1) {
180810
+ const segments = this.featurePaths.resolvePropertyPath(relationship, "targets", ordinal).segments;
180811
+ const last2 = segments[segments.length - 1];
180812
+ const resolved = last2 ? this.resolvedNodeOf(last2) : void 0;
180813
+ if (resolved && this.denotes(resolved, declaration, seen))
180814
+ return true;
180815
+ }
180816
+ }
180817
+ return false;
180818
+ }
180819
+ resolvedNodeOf(segment) {
180820
+ if (segment.target)
180821
+ return segment.target;
180822
+ const description = segment.description;
180823
+ if (!description)
180824
+ return void 0;
180825
+ if (description.node)
180826
+ return description.node;
180827
+ const root4 = this.langiumDocuments.getDocument(description.documentUri)?.parseResult.value;
180828
+ return root4 ? this.locator.getAstNode(root4, description.path) : void 0;
180829
+ }
180146
180830
  // Mirrors DefaultRenameProvider's own leaf-node → declaration resolution
180147
180831
  // (langium/src/lsp/rename-provider.ts) so the library check runs against
180148
180832
  // the SAME target prepareRename/rename would otherwise act on.
@@ -180157,6 +180841,39 @@ var SysmlRenameProvider = class extends DefaultRenameProvider {
180157
180841
  return this.references.findDeclaration(leafNode);
180158
180842
  }
180159
180843
  };
180844
+ function pathSegments2(path10) {
180845
+ const out = [];
180846
+ let current2 = "";
180847
+ let quoted = false;
180848
+ for (let at = 0; at < path10.length; at += 1) {
180849
+ const ch = path10[at];
180850
+ if (quoted) {
180851
+ current2 += ch;
180852
+ if (ch === "\\" && at + 1 < path10.length) {
180853
+ current2 += path10[at + 1];
180854
+ at += 1;
180855
+ } else if (ch === "'") {
180856
+ quoted = false;
180857
+ }
180858
+ continue;
180859
+ }
180860
+ if (ch === "'") {
180861
+ quoted = true;
180862
+ current2 += ch;
180863
+ } else if (ch === ":" && path10[at + 1] === ":") {
180864
+ out.push(current2);
180865
+ current2 = "";
180866
+ at += 1;
180867
+ } else if (ch === ".") {
180868
+ out.push(current2);
180869
+ current2 = "";
180870
+ } else {
180871
+ current2 += ch;
180872
+ }
180873
+ }
180874
+ out.push(current2);
180875
+ return out;
180876
+ }
180160
180877
 
180161
180878
  // ../language-server/out/src/services/code-action-provider.js
180162
180879
  var import_vscode_languageserver18 = __toESM(require_main4(), 1);
@@ -181579,157 +182296,6 @@ var SysmlSemanticTokenProvider = class extends AbstractSemanticTokenProvider {
181579
182296
  // ../language-server/out/src/services/inlay-hint-provider.js
181580
182297
  var import_vscode_languageserver20 = __toESM(require_main4(), 1);
181581
182298
 
181582
- // ../language-server/out/src/services/name-lookup.js
181583
- function unquoteName3(name) {
181584
- return name.replace(/^'(.*)'$/u, "$1");
181585
- }
181586
- function pathSegments(path10) {
181587
- const segments = [];
181588
- let current2 = "";
181589
- let quoted = false;
181590
- for (let index2 = 0; index2 < path10.length; index2++) {
181591
- const char = path10[index2];
181592
- if (char === "'") {
181593
- quoted = !quoted;
181594
- current2 += char;
181595
- continue;
181596
- }
181597
- if (!quoted && char === ":" && path10[index2 + 1] === ":") {
181598
- segments.push(current2);
181599
- current2 = "";
181600
- index2++;
181601
- continue;
181602
- }
181603
- if (!quoted && char === ".") {
181604
- segments.push(current2);
181605
- current2 = "";
181606
- continue;
181607
- }
181608
- current2 += char;
181609
- }
181610
- segments.push(current2);
181611
- return segments;
181612
- }
181613
- function simpleNameOf2(name) {
181614
- return pathSegments(name).at(-1) ?? name;
181615
- }
181616
- var ELEMENT_SEPARATOR = "\0";
181617
- function elementKey2(description) {
181618
- return `${description.documentUri.toString()}${ELEMENT_SEPARATOR}${description.path}`;
181619
- }
181620
- function isDeclaredSpelling(description) {
181621
- const kind = description.derivedKind;
181622
- if (kind === "reexport" || kind === "inherited")
181623
- return false;
181624
- return pathSegments(description.name).length === 1;
181625
- }
181626
- var SysmlNameLookup = class {
181627
- shared;
181628
- byName;
181629
- /** Element key → the declared spellings the index holds for that element. */
181630
- spellings;
181631
- constructor(shared) {
181632
- this.shared = shared;
181633
- this.shared.workspace.DocumentBuilder.onBuildPhase(DocumentState.IndexedContent, () => {
181634
- this.byName = void 0;
181635
- this.spellings = void 0;
181636
- });
181637
- }
181638
- /** Every description indexed under `name`, in either spelling of an escaped name. */
181639
- descriptions(name) {
181640
- return this.index().get(name) ?? [];
181641
- }
181642
- /**
181643
- * The ONE element `name` names, or `undefined` when the answer is not
181644
- * certain: no element, or more than one. `accept` narrows the candidates
181645
- * before ambiguity is judged, so "the only CALLABLE called `f`" is a
181646
- * decidable question even where a part shares the name.
181647
- */
181648
- unique(name, accept) {
181649
- const candidates = this.descriptions(name).filter((candidate) => !accept || accept(candidate));
181650
- let found;
181651
- let key;
181652
- for (const candidate of candidates) {
181653
- const candidateKey = elementKey2(candidate);
181654
- if (found === void 0) {
181655
- found = candidate;
181656
- key = candidateKey;
181657
- continue;
181658
- }
181659
- if (candidateKey !== key)
181660
- return void 0;
181661
- }
181662
- return found;
181663
- }
181664
- /**
181665
- * Resolve a written path: the spelling the index holds verbatim first, then
181666
- * its final segment. Both readings must name exactly one element.
181667
- */
181668
- uniqueForPath(path10, accept) {
181669
- return this.unique(path10, accept) ?? this.unique(simpleNameOf2(path10), accept);
181670
- }
181671
- /**
181672
- * The declared spellings of the element `description` names — its regular
181673
- * name and its `<short>` name — minus `written`.
181674
- */
181675
- otherNames(description, written) {
181676
- const all = this.spellingIndex().get(elementKey2(description)) ?? [];
181677
- const seen = unquoteName3(written);
181678
- return all.filter((name) => unquoteName3(name) !== seen);
181679
- }
181680
- index() {
181681
- if (!this.byName)
181682
- this.build();
181683
- return this.byName;
181684
- }
181685
- spellingIndex() {
181686
- if (!this.spellings)
181687
- this.build();
181688
- return this.spellings;
181689
- }
181690
- /** One pass over the index feeds both maps; neither is worth a second. */
181691
- build() {
181692
- const byName = /* @__PURE__ */ new Map();
181693
- const spellings = /* @__PURE__ */ new Map();
181694
- const add = (key, description) => {
181695
- const bucket = byName.get(key);
181696
- if (bucket)
181697
- bucket.push(description);
181698
- else
181699
- byName.set(key, [description]);
181700
- };
181701
- for (const description of this.shared.workspace.IndexManager.allElements()) {
181702
- add(description.name, description);
181703
- const unquoted = unquoteName3(description.name);
181704
- if (unquoted !== description.name)
181705
- add(unquoted, description);
181706
- if (!isDeclaredSpelling(description))
181707
- continue;
181708
- const key = elementKey2(description);
181709
- const names = spellings.get(key);
181710
- if (names) {
181711
- if (!names.includes(description.name))
181712
- names.push(description.name);
181713
- } else {
181714
- spellings.set(key, [description.name]);
181715
- }
181716
- }
181717
- this.byName = byName;
181718
- this.spellings = spellings;
181719
- }
181720
- };
181721
- var lookups = /* @__PURE__ */ new WeakMap();
181722
- function nameLookupFor(shared) {
181723
- if (!shared)
181724
- return void 0;
181725
- const existing = lookups.get(shared);
181726
- if (existing)
181727
- return existing;
181728
- const created = new SysmlNameLookup(shared);
181729
- lookups.set(shared, created);
181730
- return created;
181731
- }
181732
-
181733
182299
  // ../language-server/out/src/services/callable-resolver.js
181734
182300
  var CALLABLE_TYPES = /* @__PURE__ */ new Set([
181735
182301
  "CalcDecl",
@@ -181756,7 +182322,7 @@ var CallableResolver = class {
181756
182322
  * candidate only when it is the ONLY element with that name.
181757
182323
  */
181758
182324
  candidates(name) {
181759
- const simple = simpleNameOf2(name);
182325
+ const simple = simpleNameOf(name);
181760
182326
  return (this.lookup?.descriptions(simple) ?? []).filter((description) => CALLABLE_TYPES.has(description.type));
181761
182327
  }
181762
182328
  /**
@@ -181772,7 +182338,7 @@ var CallableResolver = class {
181772
182338
  const root4 = document2.parseResult?.value;
181773
182339
  if (!root4)
181774
182340
  return void 0;
181775
- return collectCallables([root4, ...ast_utils_exports.streamAllContents(root4).toArray()]).get(unquoteName3(simpleNameOf2(name)));
182341
+ return collectCallables([root4, ...ast_utils_exports.streamAllContents(root4).toArray()]).get(unquoteName(simpleNameOf(name)));
181776
182342
  }
181777
182343
  /**
181778
182344
  * SYNCHRONOUS resolution: a qualified spelling the index holds verbatim,
@@ -181788,7 +182354,7 @@ var CallableResolver = class {
181788
182354
  if (node)
181789
182355
  return node;
181790
182356
  }
181791
- const found = local ? local(unquoteName3(simpleNameOf2(name))) : this.findLocal(document2, name);
182357
+ const found = local ? local(unquoteName(simpleNameOf(name))) : this.findLocal(document2, name);
181792
182358
  if (found)
181793
182359
  return found;
181794
182360
  const candidate = this.uniqueCandidate(name);
@@ -181885,11 +182451,11 @@ function isAstNode3(value) {
181885
182451
  }
181886
182452
  function nodeName2(node) {
181887
182453
  const value = node?.name;
181888
- return typeof value === "string" && value.length > 0 ? unquoteName3(value) : void 0;
182454
+ return typeof value === "string" && value.length > 0 ? unquoteName(value) : void 0;
181889
182455
  }
181890
182456
  function shortNameOf2(node) {
181891
182457
  const value = node?.shortName?.name;
181892
- return typeof value === "string" && value.length > 0 ? unquoteName3(value) : void 0;
182458
+ return typeof value === "string" && value.length > 0 ? unquoteName(value) : void 0;
181893
182459
  }
181894
182460
  function typingText(node) {
181895
182461
  const text = node?.typing?.type?.$refText;
@@ -181958,7 +182524,7 @@ var EXPLICIT_SPECIALIZATION_KINDS = /* @__PURE__ */ new Set([
181958
182524
  "crosses",
181959
182525
  "conjugates"
181960
182526
  ]);
181961
- var REDEFINITION_KINDS2 = /* @__PURE__ */ new Set([":>>", "redefines"]);
182527
+ var REDEFINITION_KINDS4 = /* @__PURE__ */ new Set([":>>", "redefines"]);
181962
182528
  var CONSTANT_CARRYING_KINDS = /* @__PURE__ */ new Set([
181963
182529
  ":>",
181964
182530
  "subsets",
@@ -182193,6 +182759,15 @@ var SysmlInlayHintProvider = class {
182193
182759
  * the index is rebuilt.
182194
182760
  */
182195
182761
  declaredNameCache = /* @__PURE__ */ new Map();
182762
+ /**
182763
+ * REQ-404 — issue #155: the effective-name resolver for one document, built
182764
+ * once so the shared derivation memoizes across the whole request instead of
182765
+ * once per hint. It reads the document's own declarations first and the
182766
+ * workspace index second, which is what lets a redefinition of a feature in
182767
+ * ANOTHER file, written by that feature's `<short>` name, still print the
182768
+ * regular name. Dropped with the other index-generation caches.
182769
+ */
182770
+ effectiveNameResolvers = /* @__PURE__ */ new WeakMap();
182196
182771
  constructor(services) {
182197
182772
  this.services = services;
182198
182773
  this.lookup = nameLookupFor(services?.shared);
@@ -182202,8 +182777,18 @@ var SysmlInlayHintProvider = class {
182202
182777
  this.baseCache.clear();
182203
182778
  this.constantCache.clear();
182204
182779
  this.declaredNameCache.clear();
182780
+ this.effectiveNameResolvers = /* @__PURE__ */ new WeakMap();
182205
182781
  });
182206
182782
  }
182783
+ /** REQ-404 — issue #155: the shared effective-name derivation for `root`. */
182784
+ effectiveNameResolver(root4) {
182785
+ const existing = this.effectiveNameResolvers.get(root4);
182786
+ if (existing)
182787
+ return existing;
182788
+ const created = chainResolvers(documentLocalResolver(root4), indexResolver(this.lookup, (description) => this.linker?.resolveIndexedNode?.(description)));
182789
+ this.effectiveNameResolvers.set(root4, created);
182790
+ return created;
182791
+ }
182207
182792
  getInlayHints(document2, _params) {
182208
182793
  const root4 = document2.parseResult?.value;
182209
182794
  if (!root4 || !sysmlInlayHintSettings.enabled)
@@ -182286,7 +182871,7 @@ var SysmlInlayHintProvider = class {
182286
182871
  if (settings.redefinition)
182287
182872
  hints.push(...this.parameterRedefinitionHints(decl));
182288
182873
  if (settings.effectiveNames) {
182289
- const effective = effectiveNameHint(decl);
182874
+ const effective = effectiveNameHint(decl, this.effectiveNameResolver(root4));
182290
182875
  if (effective)
182291
182876
  hints.push(effective);
182292
182877
  }
@@ -182353,7 +182938,7 @@ var SysmlInlayHintProvider = class {
182353
182938
  const parameter = mine[index2].node;
182354
182939
  if (!parameter.name || !parameter.$cstNode)
182355
182940
  continue;
182356
- if (allRelationships2(parameter).some((rel2) => rel2.kind && REDEFINITION_KINDS2.has(rel2.kind)))
182941
+ if (allRelationships2(parameter).some((rel2) => rel2.kind && REDEFINITION_KINDS4.has(rel2.kind)))
182357
182942
  continue;
182358
182943
  const target = theirs[index2].node;
182359
182944
  if (!target.name || target.name === parameter.name)
@@ -182415,7 +183000,7 @@ var SysmlInlayHintProvider = class {
182415
183000
  * has more than one name, and memoized until the index is rebuilt.
182416
183001
  */
182417
183002
  declaredNames(description) {
182418
- const key = elementKey2(description);
183003
+ const key = elementKey(description);
182419
183004
  const cached = this.declaredNameCache.get(key);
182420
183005
  if (cached)
182421
183006
  return cached;
@@ -182582,7 +183167,7 @@ var SysmlInlayHintProvider = class {
182582
183167
  const description = this.lookup.uniqueForPath(target);
182583
183168
  if (!description)
182584
183169
  return false;
182585
- const key = elementKey2(description);
183170
+ const key = elementKey(description);
182586
183171
  const cached = this.constantCache.get(key);
182587
183172
  if (cached !== void 0)
182588
183173
  return cached;
@@ -182623,25 +183208,26 @@ var SysmlInlayHintProvider = class {
182623
183208
  return fallback;
182624
183209
  }
182625
183210
  };
182626
- function effectiveNameHint(node) {
183211
+ function effectiveNameHint(node, resolver) {
182627
183212
  if (node.name || node.shortName?.name || !node.$cstNode)
182628
183213
  return void 0;
182629
- const redefinition = allRelationships2(node).find((rel2) => rel2.kind && REDEFINITION_KINDS2.has(rel2.kind) && (rel2.targets?.length ?? 0) > 0);
182630
- const target = redefinition?.targets?.[0];
182631
- if (!target)
183214
+ const redefinition = allRelationships2(node).find((rel2) => rel2.kind && REDEFINITION_KINDS4.has(rel2.kind) && (rel2.targets?.length ?? 0) > 0);
183215
+ if (!redefinition?.targets?.[0])
182632
183216
  return void 0;
182633
- const effective = lastSegment3(target);
182634
- if (!effective)
183217
+ const names = effectiveNamesOf(node, resolver);
183218
+ const effective = names.name ?? names.shortName;
183219
+ if (!effective || names.problem)
182635
183220
  return void 0;
182636
- const operator = cst_utils_exports.flattenCst(node.$cstNode).find((leaf) => !leaf.hidden && redefinition?.kind !== void 0 && leaf.text === redefinition.kind);
183221
+ const operator = cst_utils_exports.flattenCst(node.$cstNode).find((leaf) => !leaf.hidden && redefinition.kind !== void 0 && leaf.text === redefinition.kind);
182637
183222
  if (!operator)
182638
183223
  return void 0;
183224
+ const short = names.shortName && names.shortName !== effective ? ` It is also known by the short name \`<${names.shortName}>\`.` : "";
182639
183225
  return {
182640
183226
  position: operator.range.start,
182641
183227
  label: effective,
182642
183228
  kind: import_vscode_languageserver20.InlayHintKind.Parameter,
182643
183229
  paddingRight: true,
182644
- tooltip: markdown(`Effective name: \`${effective}\`, taken from the feature this one redefines.`)
183230
+ tooltip: markdown(`Effective name: \`${effective}\`, taken from the feature this one redefines.${short}`)
182645
183231
  };
182646
183232
  }
182647
183233
 
@@ -183909,7 +184495,7 @@ function buildIdNameIndex(value, sourceName) {
183909
184495
  const id2 = stringValue(object["@id"]);
183910
184496
  if (!id2)
183911
184497
  return;
183912
- const declared = declaredName(object);
184498
+ const declared = declaredName2(object);
183913
184499
  if (declared) {
183914
184500
  out.set(id2, safeName(declared));
183915
184501
  } else if (!out.has(id2)) {
@@ -183926,7 +184512,7 @@ function renderJsonElement(element, context, depth) {
183926
184512
  if (!spec)
183927
184513
  return [];
183928
184514
  const indent = " ".repeat(depth);
183929
- const rawName = declaredName(element) ?? (element["@id"] ? fallbackNameFromId(String(element["@id"])) : void 0) ?? `${context.sourceName}_${context.seen.size}`;
184515
+ const rawName = declaredName2(element) ?? (element["@id"] ? fallbackNameFromId(String(element["@id"])) : void 0) ?? `${context.sourceName}_${context.seen.size}`;
183930
184516
  const name = safeName(rawName);
183931
184517
  const children2 = ownedRenderableChildren(element);
183932
184518
  const tail = declarationTail(element, context);
@@ -184005,7 +184591,7 @@ function referenceName(value, context) {
184005
184591
  const id2 = stringValue(value["@id"]);
184006
184592
  if (id2 && context.idToName.has(id2))
184007
184593
  return context.idToName.get(id2);
184008
- const name = declaredName(value) ?? stringValue(value.qualifiedName);
184594
+ const name = declaredName2(value) ?? stringValue(value.qualifiedName);
184009
184595
  if (name)
184010
184596
  return safeQualifiedName(name);
184011
184597
  return referenceName(value.target, context);
@@ -184073,7 +184659,7 @@ function dedupeJsonElements(elements) {
184073
184659
  }
184074
184660
  return out;
184075
184661
  }
184076
- function declaredName(value) {
184662
+ function declaredName2(value) {
184077
184663
  return firstString(value.declaredName, value.name, value.effectiveName, value.qualifiedName);
184078
184664
  }
184079
184665
  function firstString(...values2) {
@@ -185248,7 +185834,26 @@ function compartmentWidth(node) {
185248
185834
  }
185249
185835
  return w;
185250
185836
  }
185837
+ var RELATIONSHIP_COMPARTMENTS = /* @__PURE__ */ new Set([
185838
+ "connections",
185839
+ "interfaces",
185840
+ "flows",
185841
+ "state transition",
185842
+ "successions"
185843
+ ]);
185844
+ function withoutRelationshipCompartments(carrier) {
185845
+ const comps = carrier.compartments;
185846
+ if (!comps?.some((compartment) => RELATIONSHIP_COMPARTMENTS.has(compartment.title))) return carrier;
185847
+ const kept = comps.filter((compartment) => !RELATIONSHIP_COMPARTMENTS.has(compartment.title));
185848
+ return { ...carrier, compartments: kept.length ? kept : void 0 };
185849
+ }
185850
+ function frameForCanvas(frame2) {
185851
+ return withoutRelationshipCompartments(frame2);
185852
+ }
185251
185853
  function nodeForCanvas(node) {
185854
+ return withoutRelationshipCompartments(nodeBlockForCanvas(node));
185855
+ }
185856
+ function nodeBlockForCanvas(node) {
185252
185857
  if (node.meta?.connectionUsage === true || node.meta?.interfaceUsage === true) {
185253
185858
  const compartments2 = node.compartments?.filter((compartment) => compartment.title === "doc" || compartment.title === "flows");
185254
185859
  return {
@@ -185782,7 +186387,7 @@ function hideExplicitRelationshipBoxes(model, relationship) {
185782
186387
  bindings: explicitRelationshipBindings(usage, model),
185783
186388
  endCount: usage.ports?.length ?? 0
185784
186389
  }));
185785
- const blocksCompaction = ({ usage, endCount }) => (nodeForCanvas(usage).compartments ?? []).some((compartment) => endCount !== 2 || compartment.title !== "flows");
186390
+ const blocksCompaction = ({ usage, endCount }) => (nodeBlockForCanvas(usage).compartments ?? []).some((compartment) => endCount !== 2 || compartment.title !== "flows");
185786
186391
  const retainedIds = new Set(projections.filter((projection2) => blocksCompaction(projection2) || annotatedUsageIds.has(projection2.usage.id) || projection2.endCount < 2 || projection2.bindings.length !== projection2.endCount).map(({ usage }) => usage.id));
185787
186392
  const hiddenIds = /* @__PURE__ */ new Set();
185788
186393
  for (const { usage } of projections) {
@@ -186365,10 +186970,11 @@ function modelToFlow(model, opts) {
186365
186970
  const visualDepth = (frame2) => frameDepth(frame2.id) + (visualPerformerParent.has(frame2.id) ? 1 : 0);
186366
186971
  const orderedFrames = [...frames].sort((a2, b) => visualDepth(a2) - visualDepth(b));
186367
186972
  for (const f of orderedFrames) {
186368
- const natural = frameMinSize(f);
186369
- const featureH = frameFeatureCompartmentHeight(f);
186370
- const frameHeaderHeight = isBehaviorPartitionLane(f) ? performerLaneHeaderHeight(f) : structuredControlHeaderHeight(f);
186371
- const frameBottomHeight = frameBottomCompartmentHeight(f);
186973
+ const canvasFrame = frameForCanvas(f);
186974
+ const natural = frameMinSize(canvasFrame);
186975
+ const featureH = frameFeatureCompartmentHeight(canvasFrame);
186976
+ const frameHeaderHeight = isBehaviorPartitionLane(canvasFrame) ? performerLaneHeaderHeight(canvasFrame) : structuredControlHeaderHeight(canvasFrame);
186977
+ const frameBottomHeight = frameBottomCompartmentHeight(canvasFrame);
186372
186978
  const size = sizeWithOverride(
186373
186979
  natural,
186374
186980
  ov[f.layoutKey ?? f.id],
@@ -186380,7 +186986,7 @@ function modelToFlow(model, opts) {
186380
186986
  position: { x: 0, y: 0 },
186381
186987
  data: {
186382
186988
  kind: model.kind,
186383
- frame: f,
186989
+ frame: canvasFrame,
186384
186990
  layoutKey: f.layoutKey ?? f.id,
186385
186991
  ports: isBehaviorPartitionLane(f) ? [] : assignPortHandles(f.ports, opts.portOverrides),
186386
186992
  w: size.w,
@@ -186422,7 +187028,7 @@ function modelToFlow(model, opts) {
186422
187028
  position: { x: 0, y: 0 },
186423
187029
  data: {
186424
187030
  kind: model.kind,
186425
- frame: boundary,
187031
+ frame: frameForCanvas(boundary),
186426
187032
  layoutKey: boundary.layoutKey ?? boundary.id,
186427
187033
  ports: assignPortHandles(boundary.ports, opts.portOverrides),
186428
187034
  w: size.w,
@@ -203679,7 +204285,6 @@ function PortGlyph({ ph, w, h, topReserve = 0, showLabels, selected: selected2,
203679
204285
  const x = rect.cx;
203680
204286
  const y = rect.cy;
203681
204287
  const half = rect.across / 2;
203682
- const size = rect.across;
203683
204288
  const d = ph.port.direction;
203684
204289
  const v = ph.side === "top" ? { x: 0, y: -1 } : ph.side === "bottom" ? { x: 0, y: 1 } : ph.side === "left" ? { x: -1, y: 0 } : { x: 1, y: 0 };
203685
204290
  const perp = { x: -v.y, y: v.x };
@@ -205182,7 +205787,7 @@ async function runExport(command) {
205182
205787
  }
205183
205788
 
205184
205789
  // src/main.ts
205185
- var VERSION2 = true ? "0.28.0" : "dev";
205790
+ var VERSION2 = true ? "0.29.0" : "dev";
205186
205791
  function display(file) {
205187
205792
  const rel2 = path9.relative(process.cwd(), file);
205188
205793
  return rel2 && !rel2.startsWith("..") ? rel2.split(path9.sep).join("/") : file;