sysml-diagram 0.20.3 → 0.21.1

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
@@ -161733,9 +161733,16 @@ function nameOf(node) {
161733
161733
  const name = node?.name;
161734
161734
  if (typeof name === "string" && name.length > 0)
161735
161735
  return name;
161736
- if (node?.$type === "FeatureRedefinitionShorthand") {
161737
- const leading = node.preRelationships?.[0]?.targets?.[0];
161738
- return leading ? lastSegment(leading) : void 0;
161736
+ const relational = node;
161737
+ for (const relationship of [
161738
+ ...relational?.preRelationships ?? [],
161739
+ ...relational?.relationships ?? []
161740
+ ]) {
161741
+ if (relationship.kind !== ":>>" && relationship.kind !== "redefines")
161742
+ continue;
161743
+ const target = relationship.targets?.[0];
161744
+ if (target)
161745
+ return lastSegment(target);
161739
161746
  }
161740
161747
  if (node?.$type === "FeatureShorthand") {
161741
161748
  const text = node.$cstNode?.text;
@@ -161752,9 +161759,16 @@ function nameOf(node) {
161752
161759
  return void 0;
161753
161760
  }
161754
161761
  function unwrap(node) {
161755
- if (node.$type !== "PrefixMetadataMember")
161756
- return node;
161757
- return node.element ?? node;
161762
+ let current2 = node;
161763
+ const seen = /* @__PURE__ */ new Set();
161764
+ while ((current2.$type === "PrefixMetadataMember" || current2.$type === "MemberPrefixDecl") && !seen.has(current2)) {
161765
+ seen.add(current2);
161766
+ const element = current2.element;
161767
+ if (!element)
161768
+ break;
161769
+ current2 = element;
161770
+ }
161771
+ return current2;
161758
161772
  }
161759
161773
  function directNamedChildren(node) {
161760
161774
  const result = [];
@@ -161785,12 +161799,32 @@ function isSelfReference(candidate, node) {
161785
161799
  function lastSegment(path10) {
161786
161800
  return path10.split(/::|\./u).pop() ?? path10;
161787
161801
  }
161802
+ function simpleRelationName(path10) {
161803
+ let quoted = false;
161804
+ for (let index2 = 0; index2 < path10.length; index2 += 1) {
161805
+ const char = path10[index2];
161806
+ if (quoted) {
161807
+ if (char === "\\")
161808
+ index2 += 1;
161809
+ else if (char === "'")
161810
+ quoted = false;
161811
+ continue;
161812
+ }
161813
+ if (char === "'")
161814
+ quoted = true;
161815
+ else if (char === "." || char === ":" && path10[index2 + 1] === ":")
161816
+ return void 0;
161817
+ }
161818
+ const withoutMultiplicity = path10.replace(/\s*\[[^\]]*\]\s*$/u, "").trim();
161819
+ return withoutMultiplicity ? canonicalEscapedName(withoutMultiplicity) : void 0;
161820
+ }
161788
161821
  var FeaturePathResolver = class {
161789
161822
  indexManager;
161790
161823
  descriptions;
161791
161824
  documents;
161792
161825
  locator;
161793
161826
  snapshots = /* @__PURE__ */ new WeakMap();
161827
+ resolvingSpecializations = /* @__PURE__ */ new Set();
161794
161828
  constructor(services) {
161795
161829
  this.indexManager = services?.shared.workspace.IndexManager;
161796
161830
  this.descriptions = services?.workspace.AstNodeDescriptionProvider;
@@ -161893,6 +161927,14 @@ var FeaturePathResolver = class {
161893
161927
  }
161894
161928
  return result;
161895
161929
  }
161930
+ /** Semantic owners reached through typing and specialization. This is used
161931
+ * when an anonymous redefinition has no keyword from which to recover its
161932
+ * feature kind. */
161933
+ // REQ-364: recover the semantic kind of an anonymous local redefinition.
161934
+ inheritedOwners(node) {
161935
+ const root4 = ast_utils_exports.getDocument(node).parseResult.value;
161936
+ return this.typedAndSpecializedOwners(node, this.snapshot(root4));
161937
+ }
161896
161938
  segmentsOf(node) {
161897
161939
  const cst = node.$cstNode;
161898
161940
  if (!cst)
@@ -162038,20 +162080,45 @@ var FeaturePathResolver = class {
162038
162080
  return typed;
162039
162081
  }
162040
162082
  specializationTargets(node, snapshot) {
162083
+ if (this.resolvingSpecializations.has(node))
162084
+ return [];
162085
+ this.resolvingSpecializations.add(node);
162041
162086
  const relNode = node;
162042
162087
  const result = [];
162043
- for (const relation of [...relNode.preRelationships ?? [], ...relNode.relationships ?? []]) {
162044
- if (!relation.kind || !SPECIALIZATION_KINDS.has(relation.kind))
162045
- continue;
162046
- for (const target of relation.targets ?? []) {
162047
- const description = this.pickDescription(snapshot.byName.get(target)) ?? this.pickDescription(snapshot.byName.get(lastSegment(target)));
162048
- const resolved = this.nodeOf(description);
162049
- if (resolved)
162050
- result.push(resolved);
162088
+ try {
162089
+ for (const relation of [...relNode.preRelationships ?? [], ...relNode.relationships ?? []]) {
162090
+ if (!relation.kind || !SPECIALIZATION_KINDS.has(relation.kind))
162091
+ continue;
162092
+ for (const target of relation.targets ?? []) {
162093
+ const simple = simpleRelationName(target);
162094
+ const scoped = simple ? this.scopedSpecializationTarget(node, simple, snapshot) : void 0;
162095
+ const description = scoped ? void 0 : this.pickDescription(snapshot.byName.get(target), node) ?? this.pickDescription(snapshot.byName.get(lastSegment(target)), node);
162096
+ const resolved = scoped ?? this.nodeOf(description);
162097
+ if (resolved)
162098
+ result.push(resolved);
162099
+ }
162051
162100
  }
162101
+ } finally {
162102
+ this.resolvingSpecializations.delete(node);
162052
162103
  }
162053
162104
  return result;
162054
162105
  }
162106
+ /** A simple feature specialization is resolved in the visible inventory of
162107
+ * its lexical owner. Only an absent scoped match may fall back to the global
162108
+ * index, which prevents an unrelated same-named feature from winning. */
162109
+ scopedSpecializationTarget(node, name, snapshot) {
162110
+ for (let scope = node.$container; scope; scope = scope.$container) {
162111
+ const local = directNamedChildren(scope).find((candidate) => candidate !== node && nameOf(candidate) === name);
162112
+ if (local)
162113
+ return local;
162114
+ for (const owner of this.typedAndSpecializedOwners(scope, snapshot)) {
162115
+ const inherited = directNamedChildren(owner).find((candidate) => candidate !== node && nameOf(candidate) === name);
162116
+ if (inherited)
162117
+ return inherited;
162118
+ }
162119
+ }
162120
+ return void 0;
162121
+ }
162055
162122
  memberInventoryKnown(node, snapshot) {
162056
162123
  const record = node;
162057
162124
  if (record.isDef === true || node.$type === "ClassDecl" || node.$type === "StructDecl" || node.$type === "EnumDecl" || node.$type === "DatatypeDecl" || node.$type === "FunctionDecl" || node.$type === "PredicateDecl") {
@@ -162243,14 +162310,21 @@ function sourceOf2(node, uri) {
162243
162310
  return { uri, range };
162244
162311
  }
162245
162312
  }
162313
+ function isAstDescendantOrSelf(node, ancestor) {
162314
+ for (let current2 = node; current2; current2 = current2.$container) {
162315
+ if (current2 === ancestor)
162316
+ return true;
162317
+ }
162318
+ return false;
162319
+ }
162246
162320
  function ivEditMeta(part, instanceId, definition, localUsage, localPath, uri) {
162247
- const declarationId = qnameOf(part) || instanceId;
162321
+ const declarationId = nameOf2(part) ? qnameOf(part) || instanceId : instanceId;
162248
162322
  const definitionId = definition ? qnameOf(definition) : void 0;
162249
162323
  const localUsageId = localUsage ? qnameOf(localUsage) : void 0;
162250
162324
  return {
162251
162325
  instanceId,
162252
162326
  declarationId,
162253
- declarationName: nameOf2(part),
162327
+ declarationName: effectiveNameOf(part),
162254
162328
  declarationSource: sourceOf2(part, uri),
162255
162329
  definitionId,
162256
162330
  definitionName: definition ? nameOf2(definition) : void 0,
@@ -162259,7 +162333,10 @@ function ivEditMeta(part, instanceId, definition, localUsage, localPath, uri) {
162259
162333
  localUsageName: localUsage ? nameOf2(localUsage) : void 0,
162260
162334
  localUsageSource: localUsage ? sourceOf2(localUsage, uri) : void 0,
162261
162335
  localUsagePath: [...localPath],
162262
- expandedFromDefinition: declarationId !== instanceId
162336
+ expandedFromDefinition: declarationId !== instanceId,
162337
+ // A named declaration remains local even when an anonymous `:>>`
162338
+ // wrapper removes its name from the rendered occurrence path.
162339
+ localDeclaration: !!nameOf2(part) && !!localUsage && isAstDescendantOrSelf(part, localUsage)
162263
162340
  };
162264
162341
  }
162265
162342
  var nameOf2 = (node) => {
@@ -162466,6 +162543,16 @@ function specializationTargets(node) {
162466
162543
  }
162467
162544
  return out;
162468
162545
  }
162546
+ function featureInheritanceTargets(node) {
162547
+ const n2 = node;
162548
+ const out = [];
162549
+ for (const rel2 of [...n2.preRelationships ?? [], ...n2.relationships ?? []]) {
162550
+ if (rel2.kind === ":>" || rel2.kind === ":>>" || rel2.kind === "specializes" || rel2.kind === "subsets" || rel2.kind === "redefines") {
162551
+ out.push(...rel2.targets ?? []);
162552
+ }
162553
+ }
162554
+ return out;
162555
+ }
162469
162556
  function specializationFamily(node) {
162470
162557
  const n2 = node;
162471
162558
  const isDef = n2.isDef === true;
@@ -162498,8 +162585,37 @@ function disjointTargets(node) {
162498
162585
  return out;
162499
162586
  }
162500
162587
  var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
162588
+ shared;
162501
162589
  perParseCache = /* @__PURE__ */ new WeakMap();
162502
162590
  featurePaths = new FeaturePathResolver();
162591
+ annotationFeaturePaths = /* @__PURE__ */ new Map();
162592
+ indexEpoch = 0;
162593
+ // REQ-210 — Annotation graphics
162594
+ // Shared services are optional so pure single-document tests stay cheap. In
162595
+ // production they provide both workspace documents and the linker's private
162596
+ // lazy library documents used by inherited members.
162597
+ constructor(shared) {
162598
+ this.shared = shared;
162599
+ shared?.workspace.DocumentBuilder.onBuildPhase(DocumentState.IndexedContent, () => {
162600
+ this.indexEpoch += 1;
162601
+ });
162602
+ }
162603
+ externalDocumentRoot(uri) {
162604
+ if (!this.shared)
162605
+ return void 0;
162606
+ const parsed = URI2.parse(uri);
162607
+ try {
162608
+ const services = this.shared.ServiceRegistry.getServices(parsed);
162609
+ const linker = services.references.Linker;
162610
+ const linked = linker.resolveDocumentRoot?.(parsed);
162611
+ if (linked)
162612
+ return linked;
162613
+ } catch {
162614
+ }
162615
+ if (!this.shared.workspace.LangiumDocuments.hasDocument(parsed))
162616
+ return void 0;
162617
+ return this.shared.workspace.LangiumDocuments.getDocument(parsed)?.parseResult?.value;
162618
+ }
162503
162619
  perParse(root4) {
162504
162620
  let entry = this.perParseCache.get(root4);
162505
162621
  if (!entry) {
@@ -162528,12 +162644,57 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
162528
162644
  const key = `${kind}\0${preferFileOverview ? "F" : "-"}\0${rootSymbol ?? ""}`;
162529
162645
  const cacheKey = kind === "grv" ? `${key}::${gridPreset}${gridPreset === "matrix" ? `::${matrixRelationship}` : ""}` : key;
162530
162646
  const hit = cache.models.get(cacheKey);
162647
+ if (hit && hit.indexEpoch === this.indexEpoch && this.externalRootsAreCurrent(hit.externalRoots))
162648
+ return hit.model;
162531
162649
  if (hit)
162532
- return hit;
162650
+ cache.models.delete(cacheKey);
162533
162651
  const model = this.computeDiagramModel(document2, root4, rootSymbol, kind, preferFileOverview, gridPreset, matrixRelationship);
162534
- cache.models.set(cacheKey, model);
162652
+ const externalRoots = this.externalRootsOf(model, document2.uri.toString());
162653
+ model.dependencies = [document2.uri.toString(), ...externalRoots.keys()];
162654
+ cache.models.set(cacheKey, {
162655
+ model,
162656
+ externalRoots,
162657
+ indexEpoch: this.indexEpoch
162658
+ });
162535
162659
  return model;
162536
162660
  }
162661
+ // REQ-210 — Annotation graphics
162662
+ // A model may project members and notes from another document. The anchor's
162663
+ // parse identity does not change when that source file is edited, so validate
162664
+ // those dependency roots before returning a warm per-anchor cache entry.
162665
+ externalRootsAreCurrent(roots) {
162666
+ for (const [uri, root4] of roots) {
162667
+ if (this.externalDocumentRoot(uri) !== root4)
162668
+ return false;
162669
+ }
162670
+ return true;
162671
+ }
162672
+ externalRootsOf(model, anchorUri) {
162673
+ const uris = /* @__PURE__ */ new Set();
162674
+ const add = (source) => {
162675
+ if (source?.uri && source.uri !== anchorUri)
162676
+ uris.add(source.uri);
162677
+ };
162678
+ const seen = /* @__PURE__ */ new Set();
162679
+ const addSources = (value) => {
162680
+ if (!value || typeof value !== "object" || seen.has(value))
162681
+ return;
162682
+ seen.add(value);
162683
+ if (Array.isArray(value)) {
162684
+ for (const item of value)
162685
+ addSources(item);
162686
+ return;
162687
+ }
162688
+ const record = value;
162689
+ if (typeof record.uri === "string" && record.range && typeof record.range === "object") {
162690
+ add(record);
162691
+ }
162692
+ for (const nested of Object.values(record))
162693
+ addSources(nested);
162694
+ };
162695
+ addSources(model);
162696
+ return new Map([...uris].map((uri) => [uri, this.externalDocumentRoot(uri)]));
162697
+ }
162537
162698
  computeDiagramModel(document2, root4, rootSymbol, kind, preferFileOverview, gridPreset = "requirements", matrixRelationship = "allocation") {
162538
162699
  const uri = document2.uri.toString();
162539
162700
  const empty2 = (note) => ({
@@ -162549,28 +162710,126 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
162549
162710
  return empty2(`No anchor element found for the ${kind.toUpperCase()} view.`);
162550
162711
  const ctx = { uri, index: index2, anchor, gridPreset, matrixRelationship };
162551
162712
  const overview = isPackage(anchor) || isDocument(anchor);
162552
- switch (kind) {
162553
- case "gv":
162554
- return this.buildGeneralView(ctx);
162555
- case "iv":
162556
- return overview ? this.buildInterconnectionOverview(ctx) : this.buildInterconnectionView(ctx);
162557
- case "afv":
162558
- return overview ? this.buildActionFlowOverview(ctx) : this.buildActionFlowView(ctx);
162559
- case "stv":
162560
- return overview ? this.buildStateTransitionOverview(ctx) : this.buildStateTransitionView(ctx);
162561
- case "sv":
162562
- return overview ? this.buildSequenceOverview(ctx) : this.buildSequenceView(ctx);
162563
- case "cv":
162564
- return this.buildCaseView(ctx);
162565
- case "gev":
162566
- return overview ? this.buildGeometryOverview(ctx) : this.buildGeometryView(ctx);
162567
- case "grv":
162568
- return this.buildGridView(ctx);
162569
- case "bv":
162570
- return this.buildBrowserView(ctx);
162571
- default:
162572
- return empty2(`Unsupported diagram kind ${kind}.`);
162713
+ const build = () => {
162714
+ switch (kind) {
162715
+ case "gv":
162716
+ return this.buildGeneralView(ctx);
162717
+ case "iv":
162718
+ return overview ? this.buildInterconnectionOverview(ctx) : this.buildInterconnectionView(ctx);
162719
+ case "afv":
162720
+ return overview ? this.buildActionFlowOverview(ctx) : this.buildActionFlowView(ctx);
162721
+ case "stv":
162722
+ return overview ? this.buildStateTransitionOverview(ctx) : this.buildStateTransitionView(ctx);
162723
+ case "sv":
162724
+ return overview ? this.buildSequenceOverview(ctx) : this.buildSequenceView(ctx);
162725
+ case "cv":
162726
+ return this.buildCaseView(ctx);
162727
+ case "gev":
162728
+ return overview ? this.buildGeometryOverview(ctx) : this.buildGeometryView(ctx);
162729
+ case "grv":
162730
+ return this.buildGridView(ctx);
162731
+ case "bv":
162732
+ return this.buildBrowserView(ctx);
162733
+ default:
162734
+ return empty2(`Unsupported diagram kind ${kind}.`);
162735
+ }
162736
+ };
162737
+ return this.withNotes(build(), root4, index2, uri);
162738
+ }
162739
+ // REQ-210 — Annotation graphics
162740
+ // issue #229: attach the modeled notes of every DRAWN element to that
162741
+ // element, on every view.
162742
+ //
162743
+ // The General View builds its own richer annotation pass (comment + rep +
162744
+ // metadata, with package placement), the Browser View lists annotations as
162745
+ // tree rows, and the Grid View is a table, so all three are left untouched.
162746
+ // Every other view gets its notes here, once, after the builder (and its
162747
+ // overview tiling / id prefixing) has settled the final node ids.
162748
+ //
162749
+ // A `comment` is always a note. A `doc` documents its owner and already has
162750
+ // a textual home in that owner's `doc` compartment (issue #107), so it only
162751
+ // becomes a note on the views that draw no compartments at all.
162752
+ withNotes(model, root4, index2, uri) {
162753
+ if (model.kind === "gv" || model.kind === "bv" || model.kind === "grv")
162754
+ return model;
162755
+ const docAsNote = model.kind === "sv" || model.kind === "gev";
162756
+ const drawn = /* @__PURE__ */ new Map();
162757
+ const externalUris = /* @__PURE__ */ new Set();
162758
+ const key = (source) => source && `${source.uri}:${source.range.start.line}:${source.range.start.character}`;
162759
+ const claim = (source, target) => {
162760
+ const k = key(source);
162761
+ if (!k)
162762
+ return;
162763
+ if (source && source.uri !== uri)
162764
+ externalUris.add(source.uri);
162765
+ const list = drawn.get(k);
162766
+ if (list)
162767
+ list.push(target);
162768
+ else
162769
+ drawn.set(k, [target]);
162770
+ };
162771
+ for (const n2 of model.nodes) {
162772
+ claim(n2.source, { id: n2.id, parent: n2.parent, frame: n2.frame });
162773
+ for (const port of n2.ports ?? []) {
162774
+ claim(port.source, { id: port.id, parent: n2.parent, frame: n2.frame, port: true });
162775
+ }
162573
162776
  }
162777
+ for (const f of model.frames ?? []) {
162778
+ claim(f.source, { id: f.id, frame: f.id });
162779
+ for (const port of f.ports ?? []) {
162780
+ claim(port.source, { id: port.id, frame: f.id, port: true });
162781
+ }
162782
+ }
162783
+ if (model.ivBoundary) {
162784
+ claim(model.ivBoundary.source, { id: model.ivBoundary.id, frame: model.ivBoundary.id });
162785
+ for (const port of model.ivBoundary.ports ?? []) {
162786
+ claim(port.source, { id: port.id, frame: model.ivBoundary.id, port: true });
162787
+ }
162788
+ }
162789
+ if (!drawn.size)
162790
+ return model;
162791
+ const nodes = [...model.nodes];
162792
+ const edges = [...model.edges];
162793
+ let noteCount = 0;
162794
+ let edgeCount = edges.length;
162795
+ const note = (annotation) => {
162796
+ const targets = drawn.get(key(sourceOf2(annotation.owner, uri)) ?? "")?.filter((target) => annotation.keyword !== "doc" || docAsNote || target.port);
162797
+ if (!targets?.length)
162798
+ return;
162799
+ for (const target of targets) {
162800
+ const id2 = `__note_${noteCount++}__`;
162801
+ nodes.push({
162802
+ id: id2,
162803
+ name: annotation.label,
162804
+ keyword: annotation.keyword,
162805
+ isDef: false,
162806
+ shape: "annotation",
162807
+ type: annotation.body,
162808
+ // Sit in the same container as the element the note is about,
162809
+ // so the note travels with it instead of floating at the root.
162810
+ ...target.parent ? { parent: target.parent } : {},
162811
+ ...target.frame ? { frame: target.frame } : {},
162812
+ source: sourceOf2(annotation.annotation, uri)
162813
+ });
162814
+ edges.push({
162815
+ id: `e${edgeCount++}`,
162816
+ from: id2,
162817
+ to: target.id,
162818
+ kind: "annotation",
162819
+ source: sourceOf2(annotation.annotation, uri)
162820
+ });
162821
+ }
162822
+ };
162823
+ for (const annotation of this.semanticAnnotations(root4, index2))
162824
+ note(annotation);
162825
+ for (const externalUri of externalUris) {
162826
+ const externalRoot = this.externalDocumentRoot(externalUri);
162827
+ if (externalRoot) {
162828
+ for (const annotation of this.semanticAnnotations(externalRoot, this.localIndex(externalRoot)))
162829
+ note(annotation);
162830
+ }
162831
+ }
162832
+ return noteCount ? { ...model, nodes, edges } : model;
162574
162833
  }
162575
162834
  // REQ-224 — Detect the file/anchor-specific view kinds that will render
162576
162835
  // substantive diagram content. The extension uses this to limit the
@@ -162649,6 +162908,132 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
162649
162908
  cache.contents = contents;
162650
162909
  return contents;
162651
162910
  }
162911
+ // REQ-210 — Annotation graphics
162912
+ // Keep the whole-document filter out of each view build. Target resolution
162913
+ // remains live because the workspace index can become more complete without
162914
+ // reparsing the document.
162915
+ annotationMembers(root4) {
162916
+ const cache = this.perParse(root4);
162917
+ if (cache.annotations)
162918
+ return cache.annotations;
162919
+ const comments = [];
162920
+ const docs = [];
162921
+ for (const node of [root4, ...this.rootContents(root4)]) {
162922
+ if (node.$type === "CommentStmt")
162923
+ comments.push(node);
162924
+ else if (node.$type === "DocCommentMember")
162925
+ docs.push(node);
162926
+ }
162927
+ cache.annotations = { comments, docs };
162928
+ return cache.annotations;
162929
+ }
162930
+ // REQ-210 — Annotation graphics
162931
+ // Resolve a document's modeled annotations once for every workspace-index
162932
+ // epoch. Different diagram kinds then only match semantic owners to their
162933
+ // rendered source identities instead of walking and resolving the AST again.
162934
+ semanticAnnotations(root4, index2) {
162935
+ const cache = this.perParse(root4);
162936
+ if (cache.semanticAnnotations?.epoch === this.indexEpoch)
162937
+ return cache.semanticAnnotations.values;
162938
+ const members = this.annotationMembers(root4);
162939
+ const values2 = [];
162940
+ for (const comment of members.comments) {
162941
+ const rawTargets = comment.targets ?? [];
162942
+ const owners = rawTargets.length ? this.commentTargets(comment, index2) : [comment.$container];
162943
+ for (const owner of owners) {
162944
+ if (!owner)
162945
+ continue;
162946
+ values2.push({
162947
+ annotation: comment,
162948
+ owner,
162949
+ keyword: "comment",
162950
+ label: nameOf2(comment) ?? "comment",
162951
+ body: annotationText(trailingBlockBody(comment))
162952
+ });
162953
+ }
162954
+ }
162955
+ for (const doc of members.docs) {
162956
+ if (!doc.$container)
162957
+ continue;
162958
+ values2.push({
162959
+ annotation: doc,
162960
+ owner: doc.$container,
162961
+ keyword: "doc",
162962
+ label: nameOf2(doc) ?? "doc",
162963
+ body: annotationText(docCommentBody(doc))
162964
+ });
162965
+ }
162966
+ cache.semanticAnnotations = { epoch: this.indexEpoch, values: values2 };
162967
+ return values2;
162968
+ }
162969
+ annotationPathResolver(node) {
162970
+ if (!this.shared)
162971
+ return this.featurePaths;
162972
+ try {
162973
+ const services = this.shared.ServiceRegistry.getServices(ast_utils_exports.getDocument(node).uri);
162974
+ let resolver = this.annotationFeaturePaths.get(services);
162975
+ if (!resolver) {
162976
+ resolver = new FeaturePathResolver(services);
162977
+ this.annotationFeaturePaths.set(services, resolver);
162978
+ }
162979
+ return resolver;
162980
+ } catch {
162981
+ return this.featurePaths;
162982
+ }
162983
+ }
162984
+ annotationDescriptionNode(context, description) {
162985
+ if (!description)
162986
+ return void 0;
162987
+ if (!this.shared)
162988
+ return description.node;
162989
+ try {
162990
+ const services = this.shared.ServiceRegistry.getServices(ast_utils_exports.getDocument(context).uri);
162991
+ const linker = services.references.Linker;
162992
+ return linker.resolveIndexedNode?.(description) ?? description.node;
162993
+ } catch {
162994
+ return description.node;
162995
+ }
162996
+ }
162997
+ // REQ-210 — Annotation graphics
162998
+ /** Resolve every `comment about` target by semantic path identity. */
162999
+ commentTargets(comment, index2) {
163000
+ const rawTargets = comment.targets ?? [];
163001
+ if (!rawTargets.length)
163002
+ return [];
163003
+ const root4 = this.documentRootOf(comment);
163004
+ const all = [root4, ...this.rootContents(root4)];
163005
+ const resolver = this.annotationPathResolver(comment);
163006
+ const resolved = rawTargets.map((raw, occurrence) => {
163007
+ const segment = resolver.resolvePropertyPath(comment, "targets", occurrence).segments.at(-1);
163008
+ const linked = segment?.target ?? this.annotationDescriptionNode(comment, segment?.description);
163009
+ if (linked)
163010
+ return linked;
163011
+ const path10 = this.featurePath(raw)?.trim();
163012
+ if (!path10)
163013
+ return void 0;
163014
+ const unrooted = path10.replace(/^\s*\$\s*::\s*/u, "");
163015
+ if (!/::|\./u.test(unrooted)) {
163016
+ for (let scope = comment.$container; scope; scope = scope.$container) {
163017
+ const local = membersOf(scope).find((member) => member !== comment && nameOf2(member) === unrooted);
163018
+ if (local)
163019
+ return local;
163020
+ const declaringIndex = this.localIndex(this.documentRootOf(scope));
163021
+ for (const inherited of this.inheritedFeatureOwnersOf(scope, declaringIndex)) {
163022
+ const inheritedMember = membersOf(inherited).find((member) => nameOf2(member) === unrooted);
163023
+ if (inheritedMember)
163024
+ return inheritedMember;
163025
+ }
163026
+ }
163027
+ return index2.get(unrooted);
163028
+ }
163029
+ const qualified = all.filter((candidate) => {
163030
+ const qname = qnameOf(candidate);
163031
+ return qname.length > 0 && pathMatchesQName(unrooted, qname);
163032
+ });
163033
+ return qualified.length === 1 ? qualified[0] : void 0;
163034
+ }).filter((target) => target !== void 0);
163035
+ return [...new Set(resolved)];
163036
+ }
162652
163037
  // REQ-192/REQ-193 — prefer Langium's linked typing target. The diagram's
162653
163038
  // local index deliberately contains only the active document, so consulting
162654
163039
  // it alone drops structure declared in an imported workspace/library file
@@ -162698,6 +163083,98 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
162698
163083
  }
162699
163084
  return chain;
162700
163085
  }
163086
+ // REQ-061/REQ-192/REQ-364 - the effective feature owners inherited by a
163087
+ // definition or usage. A redefining usage specializes both its explicit type
163088
+ // and the feature it redefines. The latter can contribute its own body and its
163089
+ // type's complete inventory, so following only typing definitions turns an
163090
+ // anonymous `part :>> inheritedPart` into an empty leaf.
163091
+ inheritedFeatureOwnersOf(node, index2) {
163092
+ const chain = [];
163093
+ const seen = /* @__PURE__ */ new Set([node]);
163094
+ const queue = [];
163095
+ const add = (candidate) => {
163096
+ if (!candidate || seen.has(candidate))
163097
+ return;
163098
+ seen.add(candidate);
163099
+ chain.push(candidate);
163100
+ queue.push(candidate);
163101
+ };
163102
+ const addTargets = (owner) => {
163103
+ for (const target of featureInheritanceTargets(owner)) {
163104
+ add(this.resolveFeatureInheritanceTarget(owner, target, index2));
163105
+ }
163106
+ };
163107
+ if (node.isDef === true)
163108
+ addTargets(node);
163109
+ else {
163110
+ add(this.resolveType(node, index2));
163111
+ addTargets(node);
163112
+ }
163113
+ while (queue.length > 0) {
163114
+ const owner = queue.shift();
163115
+ if (owner.isDef !== true)
163116
+ add(this.resolveType(owner, index2));
163117
+ addTargets(owner);
163118
+ }
163119
+ return chain;
163120
+ }
163121
+ /** Declaration that an anonymous local redefinition specializes. Direct edits
163122
+ * in definition-sync mode address this feature, while child insertion still
163123
+ * addresses the feature's typing definition. */
163124
+ synchronizationDeclarationOf(node, index2) {
163125
+ if (nameOf2(node))
163126
+ return node;
163127
+ const wanted = effectiveNameOf(node);
163128
+ return this.inheritedFeatureOwnersOf(node, index2).find((candidate) => candidate.isDef !== true && effectiveNameOf(candidate) === wanted && (isPartDecl(node) ? isPartDecl(candidate) : isPortDecl(node) ? isPortDecl(candidate) : true));
163129
+ }
163130
+ /** Resolve a usage specialization in its feature scope. A simple `:>> x`
163131
+ * names a sibling supplied by the containing usage or one of its types. A
163132
+ * global simple-name lookup can select the redeclaration itself or an
163133
+ * unrelated namesake, so the containing feature inventory is checked first. */
163134
+ resolveFeatureInheritanceTarget(owner, target, index2) {
163135
+ const path10 = this.resolvedFeatureInheritancePath(owner, target);
163136
+ if (path10.qualified) {
163137
+ return path10.target === owner ? void 0 : path10.target;
163138
+ }
163139
+ if (owner.isDef !== true) {
163140
+ const wanted = lastSeg(target);
163141
+ const container = owner.$container;
163142
+ if (container) {
163143
+ for (const source of [container, ...this.inheritedFeatureOwnersOf(container, index2)]) {
163144
+ const inherited = membersOf(source).find((member) => member !== owner && effectiveNameOf(member) === wanted);
163145
+ if (inherited)
163146
+ return inherited;
163147
+ }
163148
+ }
163149
+ }
163150
+ const resolved = path10.target ?? this.resolveSpecializationTarget(owner, target, index2);
163151
+ return resolved === owner ? void 0 : resolved;
163152
+ }
163153
+ /** Resolve a relationship target through the shared feature path service.
163154
+ * Qualified paths must retain every segment because a last-segment lookup can
163155
+ * select an unrelated sibling with the same name. */
163156
+ resolvedFeatureInheritancePath(owner, target) {
163157
+ const relationships = [
163158
+ ...owner.preRelationships ?? [],
163159
+ ...owner.relationships ?? []
163160
+ ];
163161
+ const resolver = this.annotationPathResolver(owner);
163162
+ for (const relationship of relationships) {
163163
+ if (!relationship.kind || ![":>", ":>>", "specializes", "subsets", "redefines"].includes(relationship.kind))
163164
+ continue;
163165
+ for (const [occurrence, written] of (relationship.targets ?? []).entries()) {
163166
+ if (written !== target)
163167
+ continue;
163168
+ const resolution = resolver.resolvePropertyPath(relationship, "targets", occurrence);
163169
+ const segment = resolution.segments.at(-1);
163170
+ return {
163171
+ qualified: resolution.segments.length > 1,
163172
+ target: segment?.target ?? this.annotationDescriptionNode(owner, segment?.description)
163173
+ };
163174
+ }
163175
+ }
163176
+ return { qualified: /::|\./u.test(target) };
163177
+ }
162701
163178
  // issue #233 (PR #239 review) — one supertype path, resolved. A specialization
162702
163179
  // target is path TEXT in this grammar, not a cross-reference, so there is no
162703
163180
  // linked node to prefer the way `resolveType` prefers `typing.type.ref`; the
@@ -163173,7 +163650,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
163173
163650
  return this.collectGeometry(node, index2).length > 0;
163174
163651
  }
163175
163652
  hasRenderablePorts(node, index2) {
163176
- return [node, ...this.inheritedTypesOf(node, index2)].some((source) => membersOf(source).some((m) => isPortDecl(m) && m.isDef !== true));
163653
+ return [node, ...this.inheritedFeatureOwnersOf(node, index2)].some((source) => membersOf(source).some((m) => isPortDecl(m) && m.isDef !== true));
163177
163654
  }
163178
163655
  // REQ-192, issue #233 — the named part usages a part shows when expanded: its
163179
163656
  // own and the ones it inherits, through its typing definition or a `:>`
@@ -163181,7 +163658,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
163181
163658
  // The predicate form of `childUsagesOf`, so an anchor that only INHERITS
163182
163659
  // internals is recognised as having them.
163183
163660
  hasNestedPartUsages(node, index2) {
163184
- return [node, ...this.inheritedTypesOf(node, index2)].some((source) => this.nestedUsages(source, isPartDecl).some((n2) => nameOf2(n2) !== void 0));
163661
+ return [node, ...this.inheritedFeatureOwnersOf(node, index2)].some((source) => this.nestedUsages(source, isPartDecl).some((n2) => nameOf2(n2) !== void 0));
163185
163662
  }
163186
163663
  nestedUsages(node, guard) {
163187
163664
  return membersOf(node).filter((m) => guard(m) && m.isDef !== true);
@@ -163723,8 +164200,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
163723
164200
  }
163724
164201
  }
163725
164202
  let annotationCount = 0;
163726
- const annotate = (m, keyword, label, detail, target) => {
163727
- const owner = target ?? m.$container;
164203
+ const annotate = (m, keyword, label, detail, targets) => {
163728
164204
  const annId = `__annotation_${annotationCount++}__`;
163729
164205
  nodes.push({
163730
164206
  id: annId,
@@ -163736,17 +164212,33 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
163736
164212
  ...packageOf2(m),
163737
164213
  source: sourceOf2(m, uri)
163738
164214
  });
163739
- if (owner && ids.has(owner)) {
163740
- edges.push({ id: `e${e++}`, from: annId, to: ids.get(owner), kind: "annotation", source: sourceOf2(m, uri) });
164215
+ const owners = targets?.length ? targets : m.$container ? [m.$container] : [];
164216
+ for (const owner of new Set(owners)) {
164217
+ if (!ids.has(owner))
164218
+ continue;
164219
+ edges.push({
164220
+ id: `e${e++}`,
164221
+ from: annId,
164222
+ to: ids.get(owner),
164223
+ kind: "annotation",
164224
+ source: sourceOf2(m, uri)
164225
+ });
163741
164226
  }
163742
164227
  };
164228
+ const drawnAnnotationTarget = (target) => {
164229
+ for (let current2 = target; current2; current2 = current2.$container) {
164230
+ if (ids.has(current2))
164231
+ return current2;
164232
+ }
164233
+ return void 0;
164234
+ };
163743
164235
  for (const m of all) {
163744
164236
  if (m.$type === "CommentStmt") {
163745
- const targets = m.targets ?? [];
163746
- const target = targets.length ? byName.get(lastSeg(String(this.featurePath(targets[0]) ?? ""))) : void 0;
163747
- if (targets.length && !target)
164237
+ const rawTargets = m.targets ?? [];
164238
+ const targets = rawTargets.length ? this.commentTargets(m, index2).map(drawnAnnotationTarget).filter((target) => target !== void 0) : void 0;
164239
+ if (rawTargets.length && !targets?.length)
163748
164240
  continue;
163749
- annotate(m, "comment", nameOf2(m) ?? "comment", annotationText(trailingBlockBody(m)), target);
164241
+ annotate(m, "comment", nameOf2(m) ?? "comment", annotationText(trailingBlockBody(m)), targets);
163750
164242
  } else if (m.$type === "RepStmt") {
163751
164243
  const lang = `language "${String(m.language ?? "")}"`;
163752
164244
  const body = annotationText(trailingBlockBody(m));
@@ -163757,7 +164249,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
163757
164249
  continue;
163758
164250
  const body = annotationText(docCommentBody(m));
163759
164251
  if (body)
163760
- annotate(m, "doc", nameOf2(m) ?? "doc", body, owner);
164252
+ annotate(m, "doc", nameOf2(m) ?? "doc", body, owner ? [owner] : void 0);
163761
164253
  } else if (isMetadataDecl(m) && m.isDef !== true && (nameOf2(m) || typeText(m)) && !ids.has(m)) {
163762
164254
  const attrs = metadataAttrsText(m);
163763
164255
  const detail = typeText(m) ? `${typeText(m)}${attrs ? ` { ${attrs} }` : ""}` : attrs;
@@ -163836,7 +164328,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
163836
164328
  const childUsagesOf = (part) => {
163837
164329
  const out = this.nestedUsages(part, isPartDecl);
163838
164330
  const have = new Set(out.map(effectiveNameOf).filter((x) => !!x));
163839
- for (const source of this.inheritedTypesOf(part, index2)) {
164331
+ for (const source of this.inheritedFeatureOwnersOf(part, index2)) {
163840
164332
  for (const usage of this.nestedUsages(source, isPartDecl)) {
163841
164333
  const nm = effectiveNameOf(usage);
163842
164334
  if (nm !== void 0) {
@@ -163849,7 +164341,27 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
163849
164341
  }
163850
164342
  return out;
163851
164343
  };
163852
- const effectiveMembersOf = (part) => [part, ...this.inheritedTypesOf(part, index2)].flatMap((source) => membersOf(source));
164344
+ const effectiveMembersOf = (part) => {
164345
+ const effective = [];
164346
+ const claimedNames = /* @__PURE__ */ new Set();
164347
+ for (const source of [part, ...this.inheritedFeatureOwnersOf(part, index2)]) {
164348
+ for (const member of membersOf(source)) {
164349
+ const relationship = member;
164350
+ const emptyPrefixFlow = member.$type === "FlowStmt" && relationship.target !== void 0 && relationship.source === void 0;
164351
+ const emptyPrefixInterface = isInterfaceDecl(member) && relationship.target !== void 0 && relationship.connect === void 0;
164352
+ const namedRelationship = isConnectorDecl(member) || isConnectionDecl(member) || isInterfaceDecl(member) && !emptyPrefixInterface || member.$type === "BindingDecl" || member.$type === "FlowStmt" && !emptyPrefixFlow;
164353
+ if (namedRelationship) {
164354
+ const names = [nameOf2(member), redefinedNameOf(member)].filter((name) => name !== void 0);
164355
+ if (names.some((name) => claimedNames.has(name)))
164356
+ continue;
164357
+ for (const name of names)
164358
+ claimedNames.add(name);
164359
+ }
164360
+ effective.push(member);
164361
+ }
164362
+ }
164363
+ return effective;
164364
+ };
163853
164365
  const childResolver = (childInfos, self2, actionInfos = []) => {
163854
164366
  const localPort = /* @__PURE__ */ new Map();
163855
164367
  const actionPort = /* @__PURE__ */ new Map();
@@ -163927,14 +164439,22 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
163927
164439
  return { resolve: resolve8, actionPinIds };
163928
164440
  };
163929
164441
  const renderInstance = (part, instanceId, parentFrame, seenTypes, depth, inheritedLocalUsage, inheritedLocalPath = []) => {
163930
- const ports = this.portsOf(part, index2, uri, instanceId).ports;
163931
- const typeDef = part.isDef === true ? void 0 : this.resolveType(part, index2);
164442
+ const typeDef = part.isDef === true ? void 0 : this.resolveType(part, index2) ?? this.inheritedFeatureOwnersOf(part, index2).find((owner) => owner.isDef === true);
163932
164443
  const typeQ = typeDef ? qnameOf(typeDef) : void 0;
163933
- const declarationId = qnameOf(part) || instanceId;
163934
- const projected = declarationId !== instanceId;
164444
+ const declarationId = nameOf2(part) ? qnameOf(part) || instanceId : instanceId;
164445
+ const projected = nameOf2(part) === void 0 || declarationId !== instanceId;
163935
164446
  const localUsage = part.isDef !== true && !projected ? part : inheritedLocalUsage;
163936
164447
  const localPath = part.isDef !== true && !projected ? [] : inheritedLocalPath;
163937
- const editMeta = ivEditMeta(part, instanceId, typeDef, localUsage, localPath, uri);
164448
+ const ports = this.portsOf(part, index2, uri, instanceId, localUsage).ports;
164449
+ const syncDeclaration = this.synchronizationDeclarationOf(part, index2);
164450
+ const editMeta = {
164451
+ ...ivEditMeta(part, instanceId, typeDef, localUsage, localPath, uri),
164452
+ ...syncDeclaration && syncDeclaration !== part ? {
164453
+ syncDeclarationId: qnameOf(syncDeclaration),
164454
+ syncDeclarationName: effectiveNameOf(syncDeclaration),
164455
+ syncDeclarationSource: sourceOf2(syncDeclaration, uri)
164456
+ } : {}
164457
+ };
163938
164458
  const children2 = depth < 8 && !(typeQ !== void 0 && seenTypes.has(typeQ)) ? childUsagesOf(part) : [];
163939
164459
  const concretePerformPath = (statement, target) => {
163940
164460
  if (!this.isAnonymousBehaviorReference(statement)) {
@@ -163978,16 +164498,31 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
163978
164498
  }).filter((entry, i, list) => list.findIndex((other) => other.key === entry.key) === i) : [];
163979
164499
  const performedActionInfos = performedActions.map(({ act, pinSource, pathSegments, name, key }) => {
163980
164500
  const id2 = `${instanceId}::__perform_${key}`;
164501
+ const inheritedFromDefinition = !!localUsage && !isAstDescendantOrSelf(act, localUsage);
164502
+ const syncDeclaration2 = this.synchronizationDeclarationOf(act, index2);
163981
164503
  return {
163982
164504
  act,
163983
164505
  name,
163984
164506
  id: id2,
163985
164507
  pathSegments,
163986
- pins: this.actionPinPorts(pinSource, id2, index2, uri)
164508
+ pins: this.actionPinPorts(pinSource, id2, index2, uri),
164509
+ meta: {
164510
+ ...ivEditMeta(act, id2, void 0, localUsage, [...localPath, name], uri),
164511
+ ivAction: true,
164512
+ // A performed action projected from a typed part belongs
164513
+ // to the shared definition. Local IV edits cannot safely
164514
+ // materialize an action redefinition yet.
164515
+ ivInheritedAction: inheritedFromDefinition,
164516
+ ...syncDeclaration2 && syncDeclaration2 !== act ? {
164517
+ syncDeclarationId: qnameOf(syncDeclaration2),
164518
+ syncDeclarationName: effectiveNameOf(syncDeclaration2),
164519
+ syncDeclarationSource: sourceOf2(syncDeclaration2, uri)
164520
+ } : {}
164521
+ }
163987
164522
  };
163988
164523
  });
163989
164524
  const emitOwnedActions = (frameOf) => {
163990
- for (const { act, name, id: actId, pins } of performedActionInfos) {
164525
+ for (const { act, name, id: actId, pins, meta } of performedActionInfos) {
163991
164526
  nodes.push({
163992
164527
  id: actId,
163993
164528
  name,
@@ -163999,7 +164534,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
163999
164534
  ports: pins,
164000
164535
  frame: frameOf,
164001
164536
  source: sourceOf2(act, uri),
164002
- meta: { ivAction: true }
164537
+ meta
164003
164538
  });
164004
164539
  }
164005
164540
  };
@@ -164026,7 +164561,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164026
164561
  }
164027
164562
  emitOwnedActions(instanceId);
164028
164563
  const resolver = childResolver(childInfos, { usage: part, id: instanceId }, performedActionInfos);
164029
- this.emitInterconnectEdges(effectiveMembersOf(part), resolver.resolve, children2, index2, uri, nodes, edges, eRef, instanceId, resolver.actionPinIds);
164564
+ this.emitInterconnectEdges(effectiveMembersOf(part), resolver.resolve, children2, index2, uri, nodes, edges, eRef, instanceId, resolver.actionPinIds, part);
164030
164565
  } else {
164031
164566
  nodes.push({
164032
164567
  id: instanceId,
@@ -164042,12 +164577,37 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164042
164577
  source: sourceOf2(part, uri),
164043
164578
  meta: editMeta
164044
164579
  });
164580
+ const resolver = childResolver([], { usage: part, id: instanceId });
164581
+ this.emitInterconnectEdges(effectiveMembersOf(part), resolver.resolve, [], index2, uri, nodes, edges, eRef, instanceId, resolver.actionPinIds, part);
164045
164582
  }
164046
164583
  };
164047
164584
  const packageOfRoot = (root4) => enclosingPackage(root4) ?? scope;
164585
+ const rootBaseId = (root4) => qnameOf(root4) || nameOf2(root4) || `__root_${root4.$cstNode?.offset ?? 0}__`;
164586
+ const rootsByBaseId = /* @__PURE__ */ new Map();
164587
+ for (const root4 of roots) {
164588
+ const base = rootBaseId(root4);
164589
+ rootsByBaseId.set(base, [...rootsByBaseId.get(base) ?? [], root4]);
164590
+ }
164591
+ const rootOccurrenceIds = /* @__PURE__ */ new Map();
164592
+ for (const [base, sameNameRoots] of rootsByBaseId) {
164593
+ if (sameNameRoots.length === 1) {
164594
+ rootOccurrenceIds.set(sameNameRoots[0], base);
164595
+ continue;
164596
+ }
164597
+ const discriminatorCounts = /* @__PURE__ */ new Map();
164598
+ const inSourceOrder = [...sameNameRoots].sort((a2, b) => (a2.$cstNode?.offset ?? 0) - (b.$cstNode?.offset ?? 0));
164599
+ for (const root4 of inSourceOrder) {
164600
+ const semanticIdentity = [typeText(root4), ...featureInheritanceTargets(root4)].filter((part) => !!part).join("_") || root4.$type;
164601
+ const discriminator = semanticIdentity.replace(/[^A-Za-z0-9_]+/gu, "_").replace(/^_+|_+$/gu, "") || "part";
164602
+ const occurrence = discriminatorCounts.get(discriminator) ?? 0;
164603
+ discriminatorCounts.set(discriminator, occurrence + 1);
164604
+ const suffix = occurrence === 0 ? discriminator : `${discriminator}_${occurrence + 1}`;
164605
+ rootOccurrenceIds.set(root4, `${base}::__occurrence_${suffix}`);
164606
+ }
164607
+ }
164048
164608
  const rootInfos = [];
164049
164609
  for (const root4 of roots) {
164050
- const id2 = qnameOf(root4) || nameOf2(root4) || `__root_${nodes.length + frames.length}__`;
164610
+ const id2 = rootOccurrenceIds.get(root4) ?? rootBaseId(root4);
164051
164611
  renderInstance(root4, id2, opts.packageFrames ? ensurePkgFrame(enclosingPackage(root4)) : void 0, /* @__PURE__ */ new Set(), 0, root4.isDef === true ? void 0 : root4, []);
164052
164612
  rootInfos.push({ usage: root4, id: id2, pkg: packageOfRoot(root4) });
164053
164613
  }
@@ -164056,7 +164616,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164056
164616
  const localInfos = rootInfos.filter((r) => r.pkg === pkg && r.usage.isDef !== true);
164057
164617
  const localRoots = localInfos.map((r) => r.usage);
164058
164618
  const resolver = childResolver(localInfos);
164059
- this.emitInterconnectEdges(membersOf(pkg), resolver.resolve, localRoots, index2, uri, nodes, edges, eRef, void 0, resolver.actionPinIds);
164619
+ this.emitInterconnectEdges(membersOf(pkg), resolver.resolve, localRoots, index2, uri, nodes, edges, eRef, void 0, resolver.actionPinIds, pkg);
164060
164620
  }
164061
164621
  }
164062
164622
  return { nodes, edges, frames };
@@ -164089,8 +164649,23 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164089
164649
  // single Interconnection View (called once over the anchor's whole subtree)
164090
164650
  // and the package overview (called once per container part, tagging any
164091
164651
  // synthetic n-ary dot with that container's frame id).
164092
- emitInterconnectEdges(members, resolveEnd, parts, index2, uri, nodes, edges, eRef, frameId, actionPinIds = /* @__PURE__ */ new Set()) {
164652
+ emitInterconnectEdges(members, resolveEnd, parts, index2, uri, nodes, edges, eRef, frameId, actionPinIds = /* @__PURE__ */ new Set(), memberOwner) {
164093
164653
  const memberList2 = [...members];
164654
+ const relationshipFields = (source) => {
164655
+ let directMember = source;
164656
+ while (directMember.$container && directMember.$container !== memberOwner) {
164657
+ directMember = directMember.$container;
164658
+ }
164659
+ const inherited = !!memberOwner && directMember.$container !== memberOwner;
164660
+ const meta = {
164661
+ ...inherited ? { ivInheritedRelation: true } : {},
164662
+ ...frameId ? { ivRelationshipOwnerId: frameId } : {}
164663
+ };
164664
+ return {
164665
+ source: sourceOf2(source, uri),
164666
+ ...Object.keys(meta).length > 0 ? { meta } : {}
164667
+ };
164668
+ };
164094
164669
  const supportsEndpoints = (kind, ids) => {
164095
164670
  const pinCount = ids.filter((id2) => actionPinIds.has(id2)).length;
164096
164671
  if (pinCount === 0)
@@ -164116,7 +164691,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164116
164691
  label,
164117
164692
  endLabelFrom: multText(resolvedEnds[0].end),
164118
164693
  endLabelTo: multText(resolvedEnds[1].end),
164119
- source: sourceOf2(src, uri)
164694
+ ...relationshipFields(src)
164120
164695
  });
164121
164696
  return;
164122
164697
  }
@@ -164133,7 +164708,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164133
164708
  isDef: false,
164134
164709
  label,
164135
164710
  endLabelTo: multText(end),
164136
- source: sourceOf2(src, uri)
164711
+ ...relationshipFields(src)
164137
164712
  });
164138
164713
  }
164139
164714
  };
@@ -164178,7 +164753,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164178
164753
  to: endId,
164179
164754
  kind: "connect",
164180
164755
  endLabelTo: multText(end),
164181
- source: sourceOf2(m, uri)
164756
+ ...relationshipFields(m)
164182
164757
  });
164183
164758
  }
164184
164759
  }
@@ -164198,7 +164773,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164198
164773
  // REQ-179 — connector end multiplicities (`connect [1] a to [0..*] b;`)
164199
164774
  endLabelFrom: multText(srcEnd),
164200
164775
  endLabelTo: multText(tgtEnd),
164201
- source: sourceOf2(m, uri)
164776
+ ...relationshipFields(m)
164202
164777
  });
164203
164778
  }
164204
164779
  }
@@ -164216,7 +164791,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164216
164791
  to,
164217
164792
  kind: "flow",
164218
164793
  label: this.flowPayloadText(fm) ?? typeText(m) ?? nameOf2(m),
164219
- source: sourceOf2(m, uri)
164794
+ ...relationshipFields(m)
164220
164795
  });
164221
164796
  }
164222
164797
  } else if (m.$type === "BindStmt" || m.$type === "BindingConnectorStmt" || m.$type === "BindingDecl") {
@@ -164239,7 +164814,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164239
164814
  // of its own (issue #120 review).
164240
164815
  endLabelFrom: multText(leftEnd) ?? multText(bn),
164241
164816
  endLabelTo: multText(rightEnd),
164242
- source: sourceOf2(m, uri)
164817
+ ...relationshipFields(m)
164243
164818
  });
164244
164819
  }
164245
164820
  } else if (isInterfaceDecl(m) && m.isDef !== true) {
@@ -164262,7 +164837,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164262
164837
  label,
164263
164838
  endLabelFrom: multText(clause.source),
164264
164839
  endLabelTo: multText(clause.target),
164265
- source: sourceOf2(m, uri)
164840
+ ...relationshipFields(m)
164266
164841
  });
164267
164842
  }
164268
164843
  }
@@ -164289,7 +164864,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164289
164864
  isDef: false,
164290
164865
  label,
164291
164866
  endLabelTo: multText(end),
164292
- source: sourceOf2(m, uri)
164867
+ ...relationshipFields(m)
164293
164868
  });
164294
164869
  }
164295
164870
  }
@@ -164308,7 +164883,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164308
164883
  label,
164309
164884
  endLabelFrom: multText(clause.source),
164310
164885
  endLabelTo: multText(clause.target),
164311
- source: sourceOf2(m, uri)
164886
+ ...relationshipFields(m)
164312
164887
  });
164313
164888
  }
164314
164889
  }
@@ -164329,7 +164904,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
164329
164904
  const all = [...ast_utils_exports.streamAllContents(scope)];
164330
164905
  const isUsagePart = (n2) => isPartDecl(n2) && n2.isDef !== true && nameOf2(n2) !== void 0;
164331
164906
  const isDefPart = (n2) => isPartDecl(n2) && n2.isDef === true && nameOf2(n2) !== void 0;
164332
- const hasInternalParts = (d) => [d, ...this.inheritedTypesOf(d, index2)].some((source) => this.nestedUsages(source, isPartDecl).length > 0);
164907
+ const hasInternalParts = (d) => [d, ...this.inheritedFeatureOwnersOf(d, index2)].some((source) => this.nestedUsages(source, isPartDecl).length > 0);
164333
164908
  const insideAPart = (n2) => {
164334
164909
  let c = n2.$container;
164335
164910
  while (c && c !== scope) {
@@ -168046,7 +168621,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
168046
168621
  }
168047
168622
  // REQ-175, REQ-193 — collect a node's ports (own + inherited from its type
168048
168623
  // def) as stubs, plus a "usageName.portName" → portId resolution map.
168049
- portsOf(node, index2, uri, ownerId) {
168624
+ portsOf(node, index2, uri, ownerId, localUsage) {
168050
168625
  const ports = [];
168051
168626
  const map3 = /* @__PURE__ */ new Map();
168052
168627
  const visibleNames = /* @__PURE__ */ new Set();
@@ -168058,23 +168633,50 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
168058
168633
  const portId = parentPortId ? `${parentPortId}.${pn}` : `${ownerId}.${pn}`;
168059
168634
  const rel2 = parentPath ? `${parentPath}.${pn}` : pn;
168060
168635
  let direction = directionOf(portNode);
168061
- const portTypeDef = this.resolveType(portNode, index2);
168636
+ const inheritedOwners = this.inheritedFeatureOwnersOf(portNode, index2);
168637
+ const directPortTypeDef = this.resolveType(portNode, index2);
168638
+ const inheritedPortUsages = inheritedOwners.filter((owner) => isPortDecl(owner) && owner.isDef !== true);
168639
+ const inheritedTyping = inheritedPortUsages.map((owner) => ({ owner, type: this.resolveType(owner, index2) })).find((entry) => entry.type !== void 0);
168640
+ const portTypeDef = directPortTypeDef ?? inheritedTyping?.type ?? inheritedOwners.find((owner) => isPortDecl(owner) && owner.isDef === true);
168641
+ const inheritedDirection = inheritedPortUsages.map(directionOf).find((candidate) => candidate !== void 0);
168642
+ direction ??= inheritedDirection;
168643
+ const referenceTraitOf = (candidate) => {
168644
+ const modifiers2 = candidate.modifiers ?? [];
168645
+ if (modifiers2.includes("ref"))
168646
+ return true;
168647
+ if (modifiers2.includes("composite"))
168648
+ return false;
168649
+ return void 0;
168650
+ };
168651
+ const inheritedReference = inheritedPortUsages.map(referenceTraitOf).find((candidate) => candidate !== void 0);
168652
+ const reference = referenceTraitOf(portNode) ?? inheritedReference;
168653
+ const hasDirectTyping = portNode.typing !== void 0;
168654
+ const effectiveConjugated = hasDirectTyping ? isConjugated(portNode) : inheritedTyping ? isConjugated(inheritedTyping.owner) : false;
168062
168655
  if (!direction) {
168063
168656
  const conjugated = isConjugated(portNode);
168064
- const dirs = /* @__PURE__ */ new Set([
168065
- ...this.ownDirectedFeatureDirections(portNode, conjugated),
168066
- ...portTypeDef ? this.effectivePortDirections(portTypeDef, index2, conjugated) : []
168067
- ]);
168657
+ const dirs = this.ownDirectedFeatureDirections(portNode, conjugated);
168658
+ for (const inheritedUsage of inheritedPortUsages) {
168659
+ const inheritedConjugated = conjugated !== isConjugated(inheritedUsage);
168660
+ for (const inheritedDirection2 of this.ownDirectedFeatureDirections(inheritedUsage, inheritedConjugated)) {
168661
+ dirs.add(inheritedDirection2);
168662
+ }
168663
+ }
168664
+ const typeConjugated = directPortTypeDef ? conjugated : inheritedTyping ? conjugated !== isConjugated(inheritedTyping.owner) : conjugated;
168665
+ if (portTypeDef) {
168666
+ for (const inheritedDirection2 of this.effectivePortDirections(portTypeDef, index2, typeConjugated)) {
168667
+ dirs.add(inheritedDirection2);
168668
+ }
168669
+ }
168068
168670
  direction = dirs.size === 1 ? [...dirs][0] : dirs.size > 1 ? "inout" : void 0;
168069
168671
  }
168070
168672
  const port = {
168071
168673
  id: portId,
168072
168674
  name: pn,
168073
- type: typeText(portNode),
168675
+ type: typeText(portNode) ?? (inheritedTyping ? typeText(inheritedTyping.owner) : void 0),
168074
168676
  direction,
168075
- conjugated: isConjugated(portNode) || void 0,
168677
+ conjugated: effectiveConjugated || void 0,
168076
168678
  // REQ-194 — reference ports render with a dashed outline
168077
- ref: (portNode.modifiers ?? []).includes("ref") || void 0,
168679
+ ref: reference || void 0,
168078
168680
  isDef: portNode.isDef === true,
168079
168681
  // issue #108 — a nested port carries its parent's id so the webview
168080
168682
  // stacks it on the parent glyph and docks connectors on it.
@@ -168089,18 +168691,27 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
168089
168691
  // projection origin to choose a direct edit or a usage-local
168090
168692
  // `port :>> name { ... }` materialization.
168091
168693
  meta: {
168092
- declarationId: qnameOf(portNode) || portId,
168694
+ declarationId: nameOf2(portNode) ? qnameOf(portNode) || portId : portId,
168093
168695
  declarationName: pn,
168094
168696
  inheritedFromType,
168697
+ localDeclaration: !inheritedFromType && !!nameOf2(portNode) && !!localUsage && isAstDescendantOrSelf(portNode, localUsage),
168095
168698
  definitionId: portTypeDef ? qnameOf(portTypeDef) : void 0,
168096
168699
  definitionName: portTypeDef ? nameOf2(portTypeDef) : void 0,
168097
- definitionSource: portTypeDef ? sourceOf2(portTypeDef, uri) : void 0
168700
+ definitionSource: portTypeDef ? sourceOf2(portTypeDef, uri) : void 0,
168701
+ ...(() => {
168702
+ const syncDeclaration = this.synchronizationDeclarationOf(portNode, index2);
168703
+ return syncDeclaration && syncDeclaration !== portNode ? {
168704
+ syncDeclarationId: qnameOf(syncDeclaration),
168705
+ syncDeclarationName: effectiveNameOf(syncDeclaration),
168706
+ syncDeclarationSource: sourceOf2(syncDeclaration, uri)
168707
+ } : {};
168708
+ })()
168098
168709
  }
168099
168710
  };
168100
168711
  if (usageName)
168101
168712
  map3.set(`${usageName}.${rel2}`, portId);
168102
168713
  map3.set(`${ownerId}.${rel2}`, portId);
168103
- return { port, portTypeDef };
168714
+ return { port, portTypeDef, inheritedOwners };
168104
168715
  };
168105
168716
  const addNested = (portNode, made, inheritedFromType, path10, depth, seenTypes) => {
168106
168717
  if (depth > NESTED_PORT_MAX_DEPTH)
@@ -168112,8 +168723,8 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
168112
168723
  const nestedSources = [
168113
168724
  // declared in this port usage's body: as local as its parent is
168114
168725
  ...membersOf(portNode).map((member) => ({ member, inherited: inheritedFromType })),
168115
- // declared in the port's type: always a projection of that type
168116
- ...made.portTypeDef && !repeatedType ? membersOf(made.portTypeDef).map((member) => ({ member, inherited: true })) : []
168726
+ // every effective owner contributes its body, nearest first
168727
+ ...!repeatedType ? made.inheritedOwners.flatMap((owner) => membersOf(owner).map((member) => ({ member, inherited: true }))) : []
168117
168728
  ];
168118
168729
  for (const { member, inherited } of nestedSources) {
168119
168730
  if (!isPortDecl(member) || member.isDef === true)
@@ -168143,7 +168754,7 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
168143
168754
  for (const m of membersOf(node))
168144
168755
  if (isPortDecl(m) && m.isDef !== true)
168145
168756
  addPort(m, false);
168146
- for (const inherited of this.inheritedTypesOf(node, index2)) {
168757
+ for (const inherited of this.inheritedFeatureOwnersOf(node, index2)) {
168147
168758
  for (const m of membersOf(inherited))
168148
168759
  if (isPortDecl(m) && m.isDef !== true)
168149
168760
  addPort(m, true);
@@ -168246,20 +168857,20 @@ var SysmlDiagramModelProvider = class _SysmlDiagramModelProvider {
168246
168857
  inheritedItems(node, index2, uri) {
168247
168858
  if (node.isDef === true)
168248
168859
  return [];
168249
- const def = this.resolveType(node, index2);
168250
- if (!def)
168251
- return [];
168252
- const localRedefined = /* @__PURE__ */ new Set();
168253
- for (const m of membersOf(node)) {
168254
- for (const rel2 of [...m.preRelationships ?? [], ...m.relationships ?? []]) {
168255
- if (rel2.kind === ":>>" || rel2.kind === "redefines") {
168256
- for (const t of rel2.targets ?? [])
168257
- localRedefined.add(lastSeg(t));
168258
- }
168860
+ const hiddenNames = new Set(membersOf(node).map(effectiveNameOf).filter((name) => name !== void 0));
168861
+ const inherited = [];
168862
+ for (const owner of this.inheritedFeatureOwnersOf(node, index2)) {
168863
+ for (const member of membersOf(owner)) {
168864
+ const name = effectiveNameOf(member);
168865
+ if (!name || hiddenNames.has(name))
168866
+ continue;
168867
+ hiddenNames.add(name);
168868
+ if (!isAttributeDecl(member) || member.isDef === true)
168869
+ continue;
168870
+ inherited.push({ member, source: sourceOf2(member, uri) });
168259
168871
  }
168260
168872
  }
168261
- const localNames = new Set(membersOf(node).map((m) => nameOf2(m)).filter(Boolean));
168262
- return membersOf(def).filter((m) => isAttributeDecl(m) && m.isDef !== true && nameOf2(m)).filter((m) => !localRedefined.has(nameOf2(m)) && !localNames.has(nameOf2(m))).map((member) => ({ member, source: sourceOf2(member, uri) }));
168873
+ return inherited;
168263
168874
  }
168264
168875
  compartmentsFor(node, uri, index2, featureRows = false, includeInherited = true) {
168265
168876
  const members = membersOf(node);
@@ -178003,6 +178614,20 @@ var SysmlLinker = class extends DefaultLinker {
178003
178614
  resolveIndexedNode(nodeDescription) {
178004
178615
  return this.loadAstNode(nodeDescription);
178005
178616
  }
178617
+ // REQ-210 — Annotation graphics
178618
+ /**
178619
+ * Return the parsed root for a live workspace or lazily loaded library file.
178620
+ * Diagram projection uses this to collect annotations declared beside an
178621
+ * inherited member without adding standard-library files to the workspace.
178622
+ */
178623
+ resolveDocumentRoot(uri) {
178624
+ const live = this.langiumDocuments().getDocument(uri)?.parseResult?.value;
178625
+ if (live)
178626
+ return live;
178627
+ if (!isStandardLibraryUri(uri))
178628
+ return void 0;
178629
+ return this.parsedLibraryDocument(uri)?.parseResult?.value;
178630
+ }
178006
178631
  /** Parse (once) the standard-library file a precomputed description points at.
178007
178632
  * Prefers an already-live workspace document when one exists (runtime-loaded
178008
178633
  * library, or the user opened the file) so there is never a second copy. */
@@ -181882,7 +182507,8 @@ function portGlyphRect(g, w, h, topReserve = 0) {
181882
182507
  y: cy - height / 2,
181883
182508
  width,
181884
182509
  height,
181885
- elongated: across > natural
182510
+ elongated: across > natural,
182511
+ proxy: g.port.meta?.proxy === true
181886
182512
  };
181887
182513
  }
181888
182514
  function hostMarkAcrossShift(rect) {
@@ -181890,7 +182516,7 @@ function hostMarkAcrossShift(rect) {
181890
182516
  return -(rect.across / 2 - NESTED_PORT_HOST_CLEAR / 2);
181891
182517
  }
181892
182518
  function portDockAlongShift(rect) {
181893
- if (!rect.elongated) return 0;
182519
+ if (!rect.elongated || rect.proxy) return 0;
181894
182520
  return rect.along / 2 - NESTED_PORT_END_PAD / 2;
181895
182521
  }
181896
182522
  function portDockAt(rect, side, dockSide) {
@@ -182200,6 +182826,7 @@ function portLabelPlacement(side, x, y, label, half = PORT_GLYPH_HALF, alongHalf
182200
182826
  }
182201
182827
  var SEQ_MSG_TOP = 76;
182202
182828
  var SEQ_MSG_GAP = 46;
182829
+ var SEQ_NOTE_GAP = 40;
182203
182830
  function sequenceSlotBoundaryY(slot) {
182204
182831
  return SEQ_MSG_TOP + (slot - 0.5) * SEQ_MSG_GAP;
182205
182832
  }
@@ -182298,6 +182925,12 @@ function gvNodeCategory(node) {
182298
182925
  };
182299
182926
  return alias[k] ?? "other";
182300
182927
  }
182928
+ function withoutOrphanedAnnotations(original, nodes, edges) {
182929
+ const originallyAttached = new Set(original.edges.filter((edge) => edge.kind === "annotation").map((edge) => edge.from));
182930
+ if (originallyAttached.size === 0) return nodes;
182931
+ const stillAttached = new Set(edges.filter((edge) => edge.kind === "annotation").map((edge) => edge.from));
182932
+ return nodes.filter((node) => node.shape !== "annotation" || !originallyAttached.has(node.id) || stillAttached.has(node.id));
182933
+ }
182301
182934
  function applyGvFilters(model, hidden) {
182302
182935
  if (model.kind !== "gv" || hidden.size === 0) return model;
182303
182936
  const nodes = model.nodes.filter((n2) => n2.shape === "package" || !hidden.has(gvNodeCategory(n2)));
@@ -182308,7 +182941,7 @@ function applyGvFilters(model, hidden) {
182308
182941
  for (const p of n2.ports ?? []) keptIds.add(p.id);
182309
182942
  }
182310
182943
  const edges = model.edges.filter((e) => keptIds.has(e.from) && keptIds.has(e.to));
182311
- return { ...model, nodes, edges };
182944
+ return { ...model, nodes: withoutOrphanedAnnotations(model, nodes, edges), edges };
182312
182945
  }
182313
182946
  var PAD = 10;
182314
182947
  var NODE_W = 168;
@@ -182577,8 +183210,8 @@ function collapseNestedPorts(model, expanded2) {
182577
183210
  }).filter((e) => {
182578
183211
  if (e.from === e.to) return false;
182579
183212
  const key = `${e.from}\0${e.to}\0${e.kind}\0${e.label ?? ""}`;
182580
- if (seenEdge.has(key)) return false;
182581
- seenEdge.add(key);
183213
+ if (seenEdge.has(`${key}:${e.id}`)) return false;
183214
+ seenEdge.add(`${key}:${e.id}`);
182582
183215
  return true;
182583
183216
  });
182584
183217
  return {
@@ -182627,11 +183260,17 @@ function assignPortHandles(ports, overrides, ownerShape) {
182627
183260
  label + reserved
182628
183261
  ),
182629
183262
  across: portGlyphAcross(kidMetrics.map((k) => k.across))
183263
+ } : isProxyPort(port) ? {
183264
+ along: Math.max(
183265
+ natural,
183266
+ tw(`${port.conjugated ? "~" : ""}${port.name}`, 9) + 2 * NESTED_PORT_END_PAD + (port.direction ? NESTED_PORT_CHEVRON_RUN : 0)
183267
+ ),
183268
+ across: portGlyphAcross()
182630
183269
  } : { along: natural + reserved, across: natural };
182631
183270
  metrics.set(port.id, m);
182632
183271
  return m;
182633
183272
  };
182634
- const alongOf = (port) => hasToggle(port) ? metricsOf(port).along : void 0;
183273
+ const alongOf = (port) => hasToggle(port) || isProxyPort(port) ? metricsOf(port).along : void 0;
182635
183274
  const place = (list, side) => {
182636
183275
  const n2 = list.length;
182637
183276
  const alongs = list.map(alongOf);
@@ -182805,9 +183444,10 @@ function applyCaseDefs(model, show) {
182805
183444
  if (hidden.size === 0) return model;
182806
183445
  const edges = model.edges.filter((e) => !hidden.has(e.from) && !hidden.has(e.to));
182807
183446
  const retainedEndpoints = new Set(edges.flatMap((edge) => [edge.from, edge.to]));
183447
+ const nodes = model.nodes.filter((n2) => !hidden.has(n2.id) && (n2.meta?.cvAuxiliary !== true || retainedEndpoints.has(n2.id)));
182808
183448
  return {
182809
183449
  ...model,
182810
- nodes: model.nodes.filter((n2) => !hidden.has(n2.id) && (n2.meta?.cvAuxiliary !== true || retainedEndpoints.has(n2.id))),
183450
+ nodes: withoutOrphanedAnnotations(model, nodes, edges),
182811
183451
  edges
182812
183452
  };
182813
183453
  }
@@ -182887,7 +183527,51 @@ function applyBehaviorFilters(model, filters) {
182887
183527
  ...nextFrames.flatMap((f) => (f.ports ?? []).map((p) => p.id))
182888
183528
  ]);
182889
183529
  const edges = model.edges.filter((e) => !(model.kind === "afv" && !filters.definedBy && e.kind === "definedBy") && !hiddenPortIds.has(e.from) && !hiddenPortIds.has(e.to) && liveIds.has(e.from) && liveIds.has(e.to));
182890
- return { ...model, frames: nextFrames, nodes, edges };
183530
+ return { ...model, frames: nextFrames, nodes: withoutOrphanedAnnotations(model, nodes, edges), edges };
183531
+ }
183532
+ function isProxyPort(port) {
183533
+ return port.meta?.proxy === true;
183534
+ }
183535
+ var PROXY_LAYOUT_PREFIX = "proxy:";
183536
+ function proxyPortFor(port, path10, hostId) {
183537
+ const stand = {
183538
+ ...port,
183539
+ name: path10,
183540
+ layoutKey: `${PROXY_LAYOUT_PREFIX}${hostId}:${port.layoutKey ?? port.id}`,
183541
+ meta: { ...port.meta, proxy: true, proxyFor: port.id, proxyPath: path10, proxyName: port.name }
183542
+ };
183543
+ delete stand.parentPort;
183544
+ return stand;
183545
+ }
183546
+ function proxyPathOf(port, ownerId, hostId, containerLabel, containerOf, portById) {
183547
+ const segments = [port.name];
183548
+ const seenPorts = /* @__PURE__ */ new Set([port.id]);
183549
+ for (let cur = port.parentPort; cur !== void 0 && !seenPorts.has(cur); cur = portById.get(cur)?.parentPort) {
183550
+ seenPorts.add(cur);
183551
+ const parent = portById.get(cur);
183552
+ if (!parent) break;
183553
+ segments.unshift(parent.name);
183554
+ }
183555
+ const seen = /* @__PURE__ */ new Set();
183556
+ for (let cur = ownerId; cur !== void 0 && cur !== hostId && !seen.has(cur); cur = containerOf(cur)) {
183557
+ seen.add(cur);
183558
+ const label = containerLabel(cur);
183559
+ if (label) segments.unshift(label);
183560
+ }
183561
+ return segments.join(".");
183562
+ }
183563
+ function proxyPortsByHost(referenced, hostOf, ownerOf, containerLabel, containerOf, portById) {
183564
+ const byHost = /* @__PURE__ */ new Map();
183565
+ for (const portId of referenced) {
183566
+ const host = hostOf.get(portId);
183567
+ const entry = ownerOf.get(portId);
183568
+ if (host === void 0 || entry === void 0) continue;
183569
+ const path10 = proxyPathOf(entry.port, entry.owner, host, containerLabel, containerOf, portById);
183570
+ const list = byHost.get(host);
183571
+ if (list) list.push(proxyPortFor(entry.port, path10, host));
183572
+ else byHost.set(host, [proxyPortFor(entry.port, path10, host)]);
183573
+ }
183574
+ return byHost;
182891
183575
  }
182892
183576
  function collapseIvModel(model, hiddenInternals) {
182893
183577
  const frames = model.frames ?? [];
@@ -182918,12 +183602,72 @@ function collapseIvModel(model, hiddenInternals) {
182918
183602
  };
182919
183603
  const hiddenFrameIds = new Set(frames.filter((f) => belongsToCollapsedRoot(f.id, false)).map((f) => f.id));
182920
183604
  const hiddenNodeIds = new Set(model.nodes.filter((n2) => belongsToCollapsedRoot(n2.frame ?? n2.parent, true)).map((n2) => n2.id));
182921
- const hiddenEndpoints = /* @__PURE__ */ new Set([...hiddenFrameIds, ...hiddenNodeIds]);
182922
- for (const f of frames) if (hiddenFrameIds.has(f.id)) for (const p of f.ports ?? []) hiddenEndpoints.add(p.id);
182923
- for (const n2 of model.nodes) if (hiddenNodeIds.has(n2.id)) for (const p of n2.ports ?? []) hiddenEndpoints.add(p.id);
183605
+ const nodeById = new Map(model.nodes.map((n2) => [n2.id, n2]));
183606
+ const containerOf = (id2) => {
183607
+ const frame2 = frameById.get(id2);
183608
+ if (frame2) return frame2.parent;
183609
+ const node = nodeById.get(id2);
183610
+ return node ? node.frame ?? node.parent : void 0;
183611
+ };
183612
+ const containerLabel = (id2) => frameById.get(id2)?.label ?? nodeById.get(id2)?.name;
183613
+ const rootFor = (id2) => {
183614
+ const seen = /* @__PURE__ */ new Set();
183615
+ for (let cur = id2; cur !== void 0 && !seen.has(cur); cur = containerOf(cur)) {
183616
+ if (roots.has(cur)) return cur;
183617
+ seen.add(cur);
183618
+ }
183619
+ return void 0;
183620
+ };
183621
+ const ownerOfHiddenPort = /* @__PURE__ */ new Map();
183622
+ for (const f of frames) if (hiddenFrameIds.has(f.id)) for (const p of f.ports ?? []) ownerOfHiddenPort.set(p.id, { port: p, owner: f.id });
183623
+ for (const n2 of model.nodes) if (hiddenNodeIds.has(n2.id)) for (const p of n2.ports ?? []) ownerOfHiddenPort.set(p.id, { port: p, owner: n2.id });
183624
+ const hiddenPortById = new Map([...ownerOfHiddenPort].map(([id2, entry]) => [id2, entry.port]));
183625
+ const proxyHost = /* @__PURE__ */ new Map();
183626
+ for (const [portId, entry] of ownerOfHiddenPort) {
183627
+ const root4 = rootFor(entry.owner);
183628
+ if (root4 !== void 0) proxyHost.set(portId, root4);
183629
+ }
183630
+ const bodyDock = /* @__PURE__ */ new Map();
183631
+ for (const id2 of [...hiddenFrameIds, ...hiddenNodeIds]) {
183632
+ const root4 = rootFor(id2);
183633
+ if (root4 !== void 0) bodyDock.set(id2, root4);
183634
+ }
183635
+ const hidden = /* @__PURE__ */ new Set([...hiddenFrameIds, ...hiddenNodeIds, ...ownerOfHiddenPort.keys()]);
183636
+ const containerRootOf = (id2) => proxyHost.get(id2) ?? bodyDock.get(id2);
183637
+ const seenEdge = /* @__PURE__ */ new Set();
183638
+ const edges = model.edges.filter((e) => {
183639
+ const fromRoot = containerRootOf(e.from);
183640
+ const toRoot = containerRootOf(e.to);
183641
+ if (fromRoot !== void 0 && fromRoot === toRoot) return false;
183642
+ return !(hidden.has(e.from) && fromRoot === void 0) && !(hidden.has(e.to) && toRoot === void 0);
183643
+ }).map((e) => {
183644
+ const from = bodyDock.get(e.from) ?? e.from;
183645
+ const to = bodyDock.get(e.to) ?? e.to;
183646
+ return from === e.from && to === e.to ? e : { ...e, from, to };
183647
+ }).filter((e) => {
183648
+ if (e.from === e.to) return false;
183649
+ const key = `${e.from}\0${e.to}\0${e.kind}\0${e.label ?? ""}`;
183650
+ if (seenEdge.has(`${key}:${e.id}`)) return false;
183651
+ seenEdge.add(`${key}:${e.id}`);
183652
+ return true;
183653
+ });
183654
+ const referenced = /* @__PURE__ */ new Set();
183655
+ for (const e of edges) {
183656
+ if (proxyHost.has(e.from)) referenced.add(e.from);
183657
+ if (proxyHost.has(e.to)) referenced.add(e.to);
183658
+ }
183659
+ const proxies = proxyPortsByHost(
183660
+ referenced,
183661
+ proxyHost,
183662
+ ownerOfHiddenPort,
183663
+ containerLabel,
183664
+ containerOf,
183665
+ hiddenPortById
183666
+ );
182924
183667
  const collapsedNodes = [...roots].flatMap((id2) => {
182925
183668
  const f = frameById.get(id2);
182926
183669
  if (!f) return [];
183670
+ const stand = proxies.get(id2) ?? [];
182927
183671
  return [{
182928
183672
  id: f.id,
182929
183673
  layoutKey: f.layoutKey,
@@ -182933,7 +183677,7 @@ function collapseIvModel(model, hiddenInternals) {
182933
183677
  shape: "box",
182934
183678
  type: f.type,
182935
183679
  multiplicity: f.multiplicity,
182936
- ports: f.ports,
183680
+ ports: stand.length ? [...f.ports ?? [], ...stand] : f.ports,
182937
183681
  compartments: f.compartments,
182938
183682
  frame: f.parent,
182939
183683
  source: f.source,
@@ -182944,7 +183688,7 @@ function collapseIvModel(model, hiddenInternals) {
182944
183688
  ...model,
182945
183689
  nodes: [...model.nodes.filter((n2) => !hiddenNodeIds.has(n2.id)), ...collapsedNodes],
182946
183690
  frames: frames.filter((f) => !roots.has(f.id) && !hiddenFrameIds.has(f.id)),
182947
- edges: model.edges.filter((e) => !hiddenEndpoints.has(e.from) && !hiddenEndpoints.has(e.to))
183691
+ edges
182948
183692
  };
182949
183693
  }
182950
183694
  function isCollapsibleActionFrame(frame2) {
@@ -183026,13 +183770,18 @@ function collapseActionFrames(model, hiddenInternals, isHost = isCollapsibleActi
183026
183770
  };
183027
183771
  const roots = new Set([...requested].filter((id2) => rootOf(frameById.get(id2)?.parent) === void 0));
183028
183772
  const dockOf = /* @__PURE__ */ new Map();
183773
+ const proxyHost = /* @__PURE__ */ new Map();
183774
+ const ownerOfHiddenPort = /* @__PURE__ */ new Map();
183029
183775
  const hiddenFrameIds = /* @__PURE__ */ new Set();
183030
183776
  for (const f of frames) {
183031
183777
  const root4 = roots.has(f.id) ? rootOf(f.parent) : rootOf(f.id);
183032
183778
  if (root4 === void 0) continue;
183033
183779
  hiddenFrameIds.add(f.id);
183034
183780
  dockOf.set(f.id, root4);
183035
- for (const p of f.ports ?? []) dockOf.set(p.id, root4);
183781
+ for (const p of f.ports ?? []) {
183782
+ proxyHost.set(p.id, root4);
183783
+ ownerOfHiddenPort.set(p.id, { port: p, owner: f.id });
183784
+ }
183036
183785
  }
183037
183786
  const hiddenNodeIds = /* @__PURE__ */ new Set();
183038
183787
  for (const n2 of model.nodes) {
@@ -183040,15 +183789,59 @@ function collapseActionFrames(model, hiddenInternals, isHost = isCollapsibleActi
183040
183789
  if (root4 === void 0) continue;
183041
183790
  hiddenNodeIds.add(n2.id);
183042
183791
  dockOf.set(n2.id, root4);
183043
- for (const p of n2.ports ?? []) dockOf.set(p.id, root4);
183792
+ for (const p of n2.ports ?? []) {
183793
+ proxyHost.set(p.id, root4);
183794
+ ownerOfHiddenPort.set(p.id, { port: p, owner: n2.id });
183795
+ }
183044
183796
  }
183045
183797
  for (const id2 of roots) {
183046
183798
  dockOf.delete(id2);
183047
- for (const p of frameById.get(id2)?.ports ?? []) dockOf.delete(p.id);
183799
+ for (const p of frameById.get(id2)?.ports ?? []) {
183800
+ proxyHost.delete(p.id);
183801
+ ownerOfHiddenPort.delete(p.id);
183802
+ }
183048
183803
  }
183804
+ const nodeById = new Map(model.nodes.map((n2) => [n2.id, n2]));
183805
+ const containerOf = (id2) => {
183806
+ const frame2 = frameById.get(id2);
183807
+ if (frame2) return frame2.parent;
183808
+ return nodeById.get(id2)?.frame;
183809
+ };
183810
+ const containerLabel = (id2) => frameById.get(id2)?.label ?? nodeById.get(id2)?.name;
183811
+ const hiddenPortById = new Map([...ownerOfHiddenPort].map(([id2, entry]) => [id2, entry.port]));
183812
+ const containerRootOf = (id2) => proxyHost.get(id2) ?? dockOf.get(id2);
183813
+ const seenEdge = /* @__PURE__ */ new Set();
183814
+ const edges = model.edges.filter((e) => {
183815
+ const fromRoot = containerRootOf(e.from);
183816
+ return fromRoot === void 0 || fromRoot !== containerRootOf(e.to);
183817
+ }).map((e) => {
183818
+ const from = dockOf.get(e.from) ?? e.from;
183819
+ const to = dockOf.get(e.to) ?? e.to;
183820
+ return from === e.from && to === e.to ? e : { ...e, from, to };
183821
+ }).filter((e) => {
183822
+ if (e.from === e.to) return false;
183823
+ const key = `${e.from}\0${e.to}\0${e.kind}\0${e.label ?? ""}`;
183824
+ if (seenEdge.has(`${key}:${e.id}`)) return false;
183825
+ seenEdge.add(`${key}:${e.id}`);
183826
+ return true;
183827
+ });
183828
+ const referenced = /* @__PURE__ */ new Set();
183829
+ for (const e of edges) {
183830
+ if (proxyHost.has(e.from)) referenced.add(e.from);
183831
+ if (proxyHost.has(e.to)) referenced.add(e.to);
183832
+ }
183833
+ const proxies = proxyPortsByHost(
183834
+ referenced,
183835
+ proxyHost,
183836
+ ownerOfHiddenPort,
183837
+ containerLabel,
183838
+ containerOf,
183839
+ hiddenPortById
183840
+ );
183049
183841
  const collapsedNodes = [...roots].flatMap((id2) => {
183050
183842
  const f = frameById.get(id2);
183051
183843
  if (!f) return [];
183844
+ const stand = proxies.get(id2) ?? [];
183052
183845
  return [{
183053
183846
  id: f.id,
183054
183847
  layoutKey: f.layoutKey,
@@ -183058,25 +183851,13 @@ function collapseActionFrames(model, hiddenInternals, isHost = isCollapsibleActi
183058
183851
  shape: collapsedShape,
183059
183852
  type: f.type,
183060
183853
  multiplicity: f.multiplicity,
183061
- ports: f.ports,
183854
+ ports: stand.length ? [...f.ports ?? [], ...stand] : f.ports,
183062
183855
  compartments: f.compartments,
183063
183856
  frame: f.parent,
183064
183857
  source: f.source,
183065
183858
  meta: { ...f.meta, internalsHidden: true }
183066
183859
  }];
183067
183860
  });
183068
- const seenEdge = /* @__PURE__ */ new Set();
183069
- const edges = model.edges.map((e) => {
183070
- const from = dockOf.get(e.from) ?? e.from;
183071
- const to = dockOf.get(e.to) ?? e.to;
183072
- return from === e.from && to === e.to ? e : { ...e, from, to };
183073
- }).filter((e) => {
183074
- if (e.from === e.to) return false;
183075
- const key = `${e.from} ${e.to} ${e.kind} ${e.label ?? ""}`;
183076
- if (seenEdge.has(key)) return false;
183077
- seenEdge.add(key);
183078
- return true;
183079
- });
183080
183861
  return {
183081
183862
  ...model,
183082
183863
  nodes: [...model.nodes.filter((n2) => !hiddenNodeIds.has(n2.id)), ...collapsedNodes],
@@ -183234,7 +184015,7 @@ function modelToFlow(model, opts) {
183234
184015
  const base = isGeo ? { w: 24, h: 24 } : nodeSize(canvasNode, opts.direction);
183235
184016
  const sizeOverride = ov[n2.layoutKey ?? n2.id];
183236
184017
  const compactCollapsed = canvasNode.meta?.internalsHidden === true;
183237
- const presentationOverride = compactCollapsed && sizeOverride ? { ...sizeOverride, h: void 0 } : sizeOverride;
184018
+ const presentationOverride = compactCollapsed && sizeOverride ? { ...sizeOverride, w: void 0, h: void 0 } : sizeOverride;
183238
184019
  const projectedSize = isCircularControlShape(canvasNode.shape) ? base : isForkJoinShape(canvasNode.shape) ? forkJoinSizeWithOverride(presentationOverride, opts.direction) : sizeWithOverride(
183239
184020
  base,
183240
184021
  presentationOverride,
@@ -183243,7 +184024,20 @@ function modelToFlow(model, opts) {
183243
184024
  h: visibleFeatureH > 0 ? base.h : 24
183244
184025
  }
183245
184026
  );
183246
- const size = model.kind === "gv" && canvasNode.shape !== "package" ? { ...projectedSize, w: Math.min(projectedSize.w, GV_NODE_MAX_WIDTH) } : projectedSize;
184027
+ const compactPortHandles = compactCollapsed ? assignPortHandles(canvasNode.ports, opts.portOverrides, canvasNode.shape) : [];
184028
+ const compactPortWidth = Math.max(
184029
+ portedSideLength(compactPortHandles, "top"),
184030
+ portedSideLength(compactPortHandles, "bottom")
184031
+ );
184032
+ const compactPortHeight = Math.max(
184033
+ portedSideLength(compactPortHandles, "left"),
184034
+ portedSideLength(compactPortHandles, "right")
184035
+ );
184036
+ const size = model.kind === "gv" && canvasNode.shape !== "package" ? { ...projectedSize, w: Math.min(projectedSize.w, GV_NODE_MAX_WIDTH) } : compactCollapsed ? {
184037
+ ...projectedSize,
184038
+ w: Math.max(compactPortWidth, Math.min(projectedSize.w, GV_NODE_MAX_WIDTH)),
184039
+ h: Math.max(compactPortHeight, projectedSize.h)
184040
+ } : projectedSize;
183247
184041
  const parentId = n2.frame ?? (model.kind === "gv" && n2.parent && gvPackageIds.has(n2.parent) ? n2.parent : void 0) ?? (boundary ? boundary.id : void 0);
183248
184042
  nodes.push({
183249
184043
  id: n2.id,
@@ -183496,6 +184290,7 @@ var GEO_TARGET_H = 520;
183496
184290
  var GEO_DEF_W = 400;
183497
184291
  var GEO_DEF_H = 300;
183498
184292
  var GEO_STRIP_GAP = 16;
184293
+ var GEO_STRIP_INSET = 16;
183499
184294
  var GEO_FRAME_ID = "__geoframe__";
183500
184295
  var GEO_EMPTY_W = 560;
183501
184296
  var GEO_EMPTY_H = 320;
@@ -183564,7 +184359,7 @@ function layoutGeometry(nodes, edges, meta) {
183564
184359
  const frame2 = makeGeoFrameNode(kind, GEO_EMPTY_W, GEO_EMPTY_H, {
183565
184360
  geoEmpty: { hLabel: axes.h ?? "x", vLabel: axes.v ?? "z", unit }
183566
184361
  });
183567
- placeStrip(strip, GEO_MARGIN_LEFT + 16, GEO_EMPTY_H + GEO_STRIP_GAP);
184362
+ placeStrip(strip, GEO_MARGIN_LEFT + GEO_STRIP_INSET, GEO_EMPTY_H + GEO_STRIP_GAP);
183568
184363
  return { nodes: [frame2, ...strip], edges };
183569
184364
  }
183570
184365
  const is3d = placed.some((n2) => n2.data.node.geo.shape !== void 0 || n2.data.node.geo.z !== void 0);
@@ -195490,13 +196285,18 @@ var SEQ_EVENT_GAP = 22;
195490
196285
  function layoutSequence(nodes, edges, overrides) {
195491
196286
  const ov = overrides ?? {};
195492
196287
  const lifelines = nodes.filter((n2) => n2.data.node?.shape === "lifeline").sort((a2, b) => Number(a2.data.node?.meta?.order ?? 0) - Number(b.data.node?.meta?.order ?? 0));
196288
+ const lifelineIds = new Set(lifelines.map((n2) => n2.id));
196289
+ const noteNodes = nodes.filter((n2) => n2.data.node?.shape === "annotation");
196290
+ const isMessage = (edge) => edge.data?.edge.kind === "message" && lifelineIds.has(edge.source) && lifelineIds.has(edge.target);
196291
+ const nonMessageEdges = edges.filter((edge) => !isMessage(edge));
196292
+ const msgs = edges.filter(isMessage);
195493
196293
  const slotFor = (e, i) => {
195494
196294
  const s = e.data?.edge.meta?.slot;
195495
196295
  return typeof s === "number" && Number.isFinite(s) && s >= 0 ? s : i;
195496
196296
  };
195497
- const msgY = edges.map((e, i) => MSG_TOP + slotFor(e, i) * MSG_GAP);
195498
- const lastMsgY = edges.length ? Math.max(...msgY) : MSG_TOP;
195499
- let maxSlot = edges.length ? Math.max(...edges.map(slotFor)) : -1;
196297
+ const msgY = msgs.map((e, i) => MSG_TOP + slotFor(e, i) * MSG_GAP);
196298
+ const lastMsgY = msgs.length ? Math.max(...msgY) : MSG_TOP;
196299
+ let maxSlot = msgs.length ? Math.max(...msgs.map(slotFor)) : -1;
195500
196300
  const eventBase = lastMsgY + 22;
195501
196301
  let maxEventY = 0;
195502
196302
  const eventsByLifeline = /* @__PURE__ */ new Map();
@@ -195519,7 +196319,7 @@ function layoutSequence(nodes, edges, overrides) {
195519
196319
  baseX.push(cursorX);
195520
196320
  cursorX += n2.data.w + LIFELINE_MIN_GAP;
195521
196321
  }
195522
- const msgHandles = edges.map((_edge, i) => ({ id: `m${i}`, y: msgY[i] }));
196322
+ const msgHandles = msgs.map((_edge, i) => ({ id: `m${i}`, y: msgY[i] }));
195523
196323
  const insertHandles = Array.from({ length: Math.max(maxSlot, -1) + 2 }, (_2, k) => ({
195524
196324
  id: `d${k}`,
195525
196325
  y: sequenceSlotBoundaryY(k),
@@ -195530,7 +196330,7 @@ function layoutSequence(nodes, edges, overrides) {
195530
196330
  const w = n2.data.w;
195531
196331
  const x = overrideFor(n2, ov)?.x ?? baseX[i];
195532
196332
  xOf.set(n2.id, x + w / 2);
195533
- const ys = edges.map((e, idx) => e.source === n2.id || e.target === n2.id ? msgY[idx] : void 0).filter((y) => y != null);
196333
+ const ys = msgs.map((e, idx) => e.source === n2.id || e.target === n2.id ? msgY[idx] : void 0).filter((y) => y != null);
195534
196334
  const activation = ys.length ? { from: Math.min(...ys) - 6, to: Math.max(...ys) + 6 } : void 0;
195535
196335
  return {
195536
196336
  ...n2,
@@ -195549,7 +196349,7 @@ function layoutSequence(nodes, edges, overrides) {
195549
196349
  draggable: true
195550
196350
  };
195551
196351
  });
195552
- const outEdges = edges.map((e, i) => {
196352
+ const outEdges = msgs.map((e, i) => {
195553
196353
  const y = msgY[i];
195554
196354
  return {
195555
196355
  ...e,
@@ -195586,7 +196386,21 @@ function layoutSequence(nodes, edges, overrides) {
195586
196386
  const h = Math.max(40, bottom - top);
195587
196387
  return { ...n2, position: { x: left, y: top }, width: w, height: h, data: { ...n2.data, w, h }, zIndex: 0 };
195588
196388
  });
195589
- return { nodes: [...fragmentNodes, ...out], edges: outEdges, height: bodyH };
196389
+ const noteX = out.length ? Math.max(...out.map((node) => node.position.x + (node.width ?? node.data.w))) + SEQ_NOTE_GAP : 20 + SEQ_NOTE_GAP;
196390
+ let noteY = MSG_TOP;
196391
+ const placedNotes = noteNodes.map((n2) => {
196392
+ const o = overrideFor(n2, ov);
196393
+ const y = o?.y ?? noteY;
196394
+ noteY = Math.max(noteY, y + n2.data.h + SEQ_NOTE_GAP);
196395
+ return { ...n2, position: { x: o?.x ?? noteX, y }, draggable: true };
196396
+ });
196397
+ const sequenceNodes = [...fragmentNodes, ...out, ...placedNotes];
196398
+ assignEdgeSides(sequenceNodes, nonMessageEdges);
196399
+ return {
196400
+ nodes: sequenceNodes,
196401
+ edges: [...outEdges, ...nonMessageEdges],
196402
+ height: Math.max(bodyH, noteY)
196403
+ };
195590
196404
  }
195591
196405
  var TILE_PAD = 22;
195592
196406
  var TILE_HEADER = 38;
@@ -195650,7 +196464,12 @@ async function layoutTiledOverview(model, nodes, edges, args) {
195650
196464
  }));
195651
196465
  const localOverrides = overrideSubset(members, args.overrides);
195652
196466
  const meta = tileMeta[frame2.id];
195653
- const laidPromise = model.kind === "sv" ? Promise.resolve(layoutSequence(detached, tileEdges, localOverrides)) : model.kind === "gev" ? Promise.resolve(layoutGeometry(detached, tileEdges, meta ?? model.meta)) : layoutFlow(detached, tileEdges, {
196467
+ const laidPromise = model.kind === "sv" ? Promise.resolve(layoutSequence(detached, tileEdges, localOverrides)) : model.kind === "gev" ? Promise.resolve(layoutGeometryWithAnnotationEdges(
196468
+ detached,
196469
+ tileEdges,
196470
+ meta ?? model.meta,
196471
+ args.connectPointSpacing
196472
+ )) : layoutFlow(detached, tileEdges, {
195654
196473
  ...args,
195655
196474
  overrides: localOverrides,
195656
196475
  kind: args.kind ?? model.kind,
@@ -196104,13 +196923,25 @@ async function layoutBands(nodes, edges, overrides, direction = "TB", connectPoi
196104
196923
  assignEdgeSides(all, edges, false, connectPointSpacing);
196105
196924
  return { nodes: all, edges };
196106
196925
  }
196926
+ function layoutGeometryWithAnnotationEdges(nodes, edges, meta, connectPointSpacing = CONNECT_POINT_SPACING_DEFAULT) {
196927
+ const laid = layoutGeometry(nodes, edges, meta);
196928
+ assignEdgeSides(
196929
+ laid.nodes,
196930
+ laid.edges.filter((edge) => edge.data?.edge.kind === "annotation"),
196931
+ false,
196932
+ connectPointSpacing
196933
+ );
196934
+ return laid;
196935
+ }
196107
196936
  async function layoutDiagram(model, nodes, edges, args) {
196108
196937
  const { kind, direction, overrides, connectPointSpacing } = args;
196109
196938
  if (model.meta?.groupMode === "tiled-h" || model.meta?.groupMode === "tiled-v") {
196110
196939
  return layoutTiledOverview(model, nodes, edges, { direction, overrides, kind, connectPointSpacing });
196111
196940
  }
196112
196941
  const profile2 = profileFor(kind);
196113
- if (profile2.layout === "geometry") return layoutGeometry(nodes, edges, model.meta);
196942
+ if (profile2.layout === "geometry") {
196943
+ return layoutGeometryWithAnnotationEdges(nodes, edges, model.meta, connectPointSpacing);
196944
+ }
196114
196945
  if (profile2.layout === "sequence") return layoutSequence(nodes, edges, overrides);
196115
196946
  if (kind === "gv" && (args.gvMode ?? "group") === "group") {
196116
196947
  return layoutBands(nodes, edges, overrides, direction, connectPointSpacing);
@@ -197182,6 +198013,12 @@ body {
197182
198013
 
197183
198014
  /* REQ-194 \u2014 port variants: dashed reference ports, direction chevrons */
197184
198015
  .dnode-port.ref { stroke-dasharray: 2 2; }
198016
+ /* REQ-400 \u2014 a PROXY stands in for a port inside collapsed contents.
198017
+ * It is drawn hollow with a fine dotted outline, so it reads as a place a
198018
+ * connector docks rather than as an element that is really on the boundary. Its
198019
+ * dot pattern is deliberately finer than the reference port's dash. */
198020
+ .dnode-port.proxy { fill: none; stroke-dasharray: 1 2; stroke-width: 1.2; }
198021
+ .dnode-port.proxy.selected { fill: var(--accent); fill-opacity: 0.35; }
197185
198022
  /* REQ-376 \u2014 an action pin takes the OUTLINE and explicit fill of the action it sits
197186
198023
  * on rather than the flow colour (user direction 2026-08-09). Its rounded corners and its
197187
198024
  * direction arrow come from the shared port path in nodes.tsx. */
@@ -198167,6 +199004,21 @@ function sizeOf(node) {
198167
199004
  h: node.measured?.height ?? node.height ?? node.data.h
198168
199005
  };
198169
199006
  }
199007
+ function exportedNodeColorClass(node) {
199008
+ const frame2 = node.data.frame;
199009
+ if (frame2) {
199010
+ return diagramElementColorClass(diagramElementColorTypeForFrame(frame2.keyword, {
199011
+ boundary: frame2.meta?.boundaryBox === true,
199012
+ exhibitor: frame2.meta?.exhibitBoundary === true,
199013
+ loop: frame2.meta?.loop === true,
199014
+ parallel: frame2.meta?.parallel === true,
199015
+ performer: frame2.meta?.performerLane === true,
199016
+ structured: frame2.meta?.structuredControl === true
199017
+ }));
199018
+ }
199019
+ const semantic = node.data.node;
199020
+ return diagramElementColorClass(semantic ? diagramElementColorTypeForNode(semantic.shape, semantic.keyword) : "default");
199021
+ }
198170
199022
  function labelExtent(text) {
198171
199023
  return { w: Math.max(8, text.length * 6.2) / 2, h: 7 };
198172
199024
  }
@@ -198202,7 +199054,7 @@ function buildDiagramSvg(options) {
198202
199054
  extend2(p.x + background.x, p.y + background.y, background.width, background.height);
198203
199055
  }
198204
199056
  const body = nodeMarkup(node);
198205
- if (body) nodeParts.push(`<g transform="translate(${Math.round(p.x)},${Math.round(p.y)})">${body}</g>`);
199057
+ if (body) nodeParts.push(`<g transform="translate(${Math.round(p.x)},${Math.round(p.y)})" class="${exportedNodeColorClass(node)}">${body}</g>`);
198206
199058
  }
198207
199059
  if (!isFinite(minX)) return null;
198208
199060
  const edgeParts = [];
@@ -198585,6 +199437,7 @@ function normalizeSideCar(value) {
198585
199437
  const next = {};
198586
199438
  if (state.mode !== void 0) next.mode = state.mode;
198587
199439
  if (state.zoom !== void 0) next.zoom = state.zoom;
199440
+ if (state.showGrid !== void 0) next.showGrid = state.showGrid;
198588
199441
  const dir = sanitizeDirection(state.direction);
198589
199442
  if (dir !== void 0) next.direction = dir;
198590
199443
  if (state.hiddenInternals !== void 0) next.hiddenInternals = state.hiddenInternals;
@@ -198610,7 +199463,7 @@ function getViewState(sc, anchor, kind) {
198610
199463
  }
198611
199464
 
198612
199465
  // src/node-markup.tsx
198613
- var import_react10 = __toESM(require_react(), 1);
199466
+ var import_react11 = __toESM(require_react(), 1);
198614
199467
  var import_server = __toESM(require_server_node(), 1);
198615
199468
 
198616
199469
  // ../extension/src/webview/diagram/flow/context.ts
@@ -198661,7 +199514,7 @@ function useDiagram() {
198661
199514
  }
198662
199515
 
198663
199516
  // ../extension/src/webview/diagram/flow/nodes.tsx
198664
- var import_react8 = __toESM(require_react());
199517
+ var import_react9 = __toESM(require_react());
198665
199518
 
198666
199519
  // ../extension/src/webview/diagram/derive.ts
198667
199520
  function edgeKindLabel(kind) {
@@ -199014,6 +199867,7 @@ var DIRECT_NAME_RE = new RegExp(`^${DIRECT_NAME_SEGMENT}$`);
199014
199867
  var DIRECT_PATH_RE = new RegExp(`^${DIRECT_NAME_SEGMENT}(?:\\.${DIRECT_NAME_SEGMENT})*$`);
199015
199868
  function isWritableRelationEndpoint(endpoint) {
199016
199869
  if (!endpoint) return false;
199870
+ if (endpoint.shape === "annotation") return false;
199017
199871
  if (pseudostateEndpointPath(endpoint.keyword)) return true;
199018
199872
  if (!endpoint.source || /^__flow_\d+__(?:\.|$)/u.test(endpoint.id)) return false;
199019
199873
  if (!endpoint.name.trim() && ["if", "while", "loop", "for"].includes(endpoint.keyword.trim().toLowerCase())) return true;
@@ -199034,6 +199888,7 @@ var TERMINAL_RELATION = "finish";
199034
199888
  function relationToolsForNode(keyword, viewKind, shape) {
199035
199889
  const { base, isDefinition, isDecision } = normalizedElementKeyword(keyword);
199036
199890
  const tools = TOOLBOX[viewKind]?.relations ?? [];
199891
+ if (shape === "annotation") return [];
199037
199892
  if (viewKind === "afv" && ["if", "while", "loop", "for"].includes(base)) {
199038
199893
  return tools.filter((tool) => tool.kind === "terminate");
199039
199894
  }
@@ -199110,6 +199965,12 @@ function relationToolsForNode(keyword, viewKind, shape) {
199110
199965
  var import_react7 = __toESM(require_react());
199111
199966
  var import_jsx_runtime3 = __toESM(require_jsx_runtime());
199112
199967
  var ptStr = (pts) => pts.map((p) => `${p[0].toFixed(1)},${p[1].toFixed(1)}`).join(" ");
199968
+ var GEO_HANDLE_POSITION = {
199969
+ top: Position3.Top,
199970
+ right: Position3.Right,
199971
+ bottom: Position3.Bottom,
199972
+ left: Position3.Left
199973
+ };
199113
199974
  function niceStep(range, target = 5) {
199114
199975
  if (!(range > 0)) return 1;
199115
199976
  const raw = range / target;
@@ -199324,7 +200185,7 @@ function GeoShapeNode({ id: id2, data, selected: selected2 }) {
199324
200185
  const origin = data.origin;
199325
200186
  const iso = data.geo3d && node.geo && origin;
199326
200187
  const approx = node.geo?.approx;
199327
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
200188
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
199328
200189
  "div",
199329
200190
  {
199330
200191
  className: `rf-node rf-geo${selected2 ? " selected" : ""}${approx ? " dgeo-approx" : ""}`,
@@ -199334,19 +200195,38 @@ function GeoShapeNode({ id: id2, data, selected: selected2 }) {
199334
200195
  e.stopPropagation();
199335
200196
  ctx.onContextNode(id2, e.clientX, e.clientY);
199336
200197
  },
199337
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { className: "rf-node-svg", width: w, height: h, style: { overflow: "visible" }, children: [
199338
- iso ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
199339
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("g", { className: `dgeo3d-node${selected2 ? " selected" : ""}`, transform: `translate(${-origin.x},${-origin.y})`, children: geoShapeBody(node, data.geo3d) }),
199340
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("text", { className: "dgeo3d-name", x: w / 2, y: -3, textAnchor: "middle", children: node.name })
199341
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
199342
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("rect", { className: `dnode-rect${selected2 ? " selected" : ""}`, x: 0, y: 0, width: w, height: h, rx: node.isDef ? 0 : 12 }),
199343
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("text", { className: "dnode-label", x: w / 2, y: h / 2 + 3, textAnchor: "middle", children: node.name })
200198
+ children: [
200199
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { className: "rf-node-svg", width: w, height: h, style: { overflow: "visible" }, children: [
200200
+ iso ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
200201
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("g", { className: `dgeo3d-node${selected2 ? " selected" : ""}`, transform: `translate(${-origin.x},${-origin.y})`, children: geoShapeBody(node, data.geo3d) }),
200202
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("text", { className: "dgeo3d-name", x: w / 2, y: -3, textAnchor: "middle", children: node.name })
200203
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
200204
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("rect", { className: `dnode-rect${selected2 ? " selected" : ""}`, x: 0, y: 0, width: w, height: h, rx: node.isDef ? 0 : 12 }),
200205
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("text", { className: "dnode-label", x: w / 2, y: h / 2 + 3, textAnchor: "middle", children: node.name })
200206
+ ] }),
200207
+ approx ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("text", { className: "dgeo-approx-mark", x: w - 2, y: -3, textAnchor: "end", children: [
200208
+ "\u26A0",
200209
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("title", { children: `${node.name}: ${approx}` })
200210
+ ] }) : null
199344
200211
  ] }),
199345
- approx ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("text", { className: "dgeo-approx-mark", x: w - 2, y: -3, textAnchor: "end", children: [
199346
- "\u26A0",
199347
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("title", { children: `${node.name}: ${approx}` })
199348
- ] }) : null
199349
- ] })
200212
+ PORT_DOCK_SIDES.flatMap((side) => (data.edgeSideAnchors?.[side] ?? []).map((offset2) => {
200213
+ const point = sidePoint(side, offset2, w, h);
200214
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
200215
+ Handle,
200216
+ {
200217
+ type: "target",
200218
+ id: sideAnchorHandleId(side, offset2),
200219
+ position: GEO_HANDLE_POSITION[side],
200220
+ style: { left: point.x, top: point.y, transform: "translate(-50%,-50%)" },
200221
+ className: "rf-handle rf-handle-side",
200222
+ isConnectable: true,
200223
+ isConnectableStart: false,
200224
+ isConnectableEnd: true
200225
+ },
200226
+ `${side}-${offset2}`
200227
+ );
200228
+ }))
200229
+ ]
199350
200230
  }
199351
200231
  );
199352
200232
  }
@@ -199475,8 +200355,8 @@ function mountedNodeSidePointOffsets(data, side, connectable, exposeAll) {
199475
200355
  function useMountedHandleRegistration(id2, sideOffsets) {
199476
200356
  const mountedKey = mountedHandleKey(sideOffsets);
199477
200357
  const updateNodeInternals2 = useUpdateNodeInternals();
199478
- const lastKeyRef = (0, import_react8.useRef)(mountedKey);
199479
- (0, import_react8.useEffect)(() => {
200358
+ const lastKeyRef = (0, import_react9.useRef)(mountedKey);
200359
+ (0, import_react9.useEffect)(() => {
199480
200360
  if (lastKeyRef.current === mountedKey) return;
199481
200361
  lastKeyRef.current = mountedKey;
199482
200362
  updateNodeInternals2(id2);
@@ -199493,9 +200373,9 @@ var SIDE_NORMAL = {
199493
200373
  };
199494
200374
  var clampOffset = (v) => Math.max(0.06, Math.min(0.94, v));
199495
200375
  function usePortDrag(containerRef, w, h, topReserve, onPortMove, onPortPreview, onSelect) {
199496
- const [dragId, setDragId] = (0, import_react8.useState)(void 0);
199497
- const gestureRef = (0, import_react8.useRef)(void 0);
199498
- (0, import_react8.useEffect)(() => () => gestureRef.current?.abort(), []);
200376
+ const [dragId, setDragId] = (0, import_react9.useState)(void 0);
200377
+ const gestureRef = (0, import_react9.useRef)(void 0);
200378
+ (0, import_react9.useEffect)(() => () => gestureRef.current?.abort(), []);
199499
200379
  const onPortPointerDown = (portId, e, origin, draggable = true) => {
199500
200380
  if (e.button !== 0) return;
199501
200381
  e.stopPropagation();
@@ -199979,6 +200859,7 @@ function PortGlyph({ ph, w, h, topReserve = 0, showLabels, selected: selected2,
199979
200859
  len
199980
200860
  };
199981
200861
  })() : void 0;
200862
+ const proxy = rect.proxy;
199982
200863
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
199983
200864
  "g",
199984
200865
  {
@@ -199988,7 +200869,7 @@ function PortGlyph({ ph, w, h, topReserve = 0, showLabels, selected: selected2,
199988
200869
  e.stopPropagation();
199989
200870
  onSelect(ph.port.id);
199990
200871
  } : void 0,
199991
- onContextMenu: onContext ? (e) => {
200872
+ onContextMenu: onContext && !proxy ? (e) => {
199992
200873
  e.preventDefault();
199993
200874
  e.stopPropagation();
199994
200875
  onContext(ph.port.id, e.clientX, e.clientY);
@@ -200011,7 +200892,7 @@ function PortGlyph({ ph, w, h, topReserve = 0, showLabels, selected: selected2,
200011
200892
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
200012
200893
  "rect",
200013
200894
  {
200014
- className: `dnode-port${ph.port.pin ? " pin" : ""}${ph.port.ref ? " ref" : ""}${rect.elongated ? " host" : ""}${selected2 ? " selected" : ""}${hovered ? " hovered" : ""}${moving ? " moving" : ""}${connectTargetSide ? " connect-target" : ""}`,
200895
+ className: `dnode-port${ph.port.pin ? " pin" : ""}${ph.port.ref ? " ref" : ""}${rect.elongated ? " host" : ""}${proxy ? " proxy" : ""}${selected2 ? " selected" : ""}${hovered ? " hovered" : ""}${moving ? " moving" : ""}${connectTargetSide ? " connect-target" : ""}`,
200015
200896
  x: rect.x,
200016
200897
  y: rect.y,
200017
200898
  width: rect.width,
@@ -200024,7 +200905,7 @@ function PortGlyph({ ph, w, h, topReserve = 0, showLabels, selected: selected2,
200024
200905
  d === "out" || d === "inout" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { className: "dport-dir head", d: arrowHead(1) }) : "",
200025
200906
  d === "in" || d === "inout" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { className: "dport-dir head", d: arrowHead(-1) }) : ""
200026
200907
  ] }) : "",
200027
- selected2 && connectStart && !connectTargetSide ? (() => {
200908
+ selected2 && connectStart && !connectTargetSide && !proxy ? (() => {
200028
200909
  const px = x + v.x * (half + PORT_PLUS_GAP);
200029
200910
  const py = y + v.y * (half + PORT_PLUS_GAP);
200030
200911
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("g", { className: "dport-plus", children: [
@@ -200170,8 +201051,8 @@ function ContainerControls({
200170
201051
  ] });
200171
201052
  }
200172
201053
  function InlineEditor({ initial, mode, elementKind, onCommit, onCancel, w }) {
200173
- const ref = (0, import_react8.useRef)(null);
200174
- (0, import_react8.useEffect)(() => {
201054
+ const ref = (0, import_react9.useRef)(null);
201055
+ (0, import_react9.useEffect)(() => {
200175
201056
  const el2 = ref.current;
200176
201057
  if (el2) {
200177
201058
  el2.focus();
@@ -200269,7 +201150,7 @@ function shapeBody(node, data) {
200269
201150
  var CLIP_EXEMPT = /* @__PURE__ */ new Set(["fork", "join", "dot", "initial", "final", "terminate", "lifeline", "actor"]);
200270
201151
  function NodeBody({ node, data, selectedPortId, hoveredPortId, movingPortId, connectTargetPortId, connectTargetPortSide, showPortConnectStart, onPortSelect, onPortContext }) {
200271
201152
  const { w, h } = data;
200272
- const rawId = (0, import_react8.useId)();
201153
+ const rawId = (0, import_react9.useId)();
200273
201154
  const clipId = `dnode-clip-${rawId.replace(/[^a-zA-Z0-9_-]/g, "")}`;
200274
201155
  const clip = !CLIP_EXEMPT.has(node.shape) || data.kind === "gv" && node.shape === "actor";
200275
201156
  const elementColorClass = diagramElementColorClass(diagramElementColorTypeForNode(node.shape, node.keyword));
@@ -200316,7 +201197,7 @@ function SysmlNode({ id: id2, data, draggable, selected: selected2, width, heigh
200316
201197
  const internalNoun = INTERNAL_NOUN[data.kind] ?? "internal parts";
200317
201198
  const featureCompartmentsVisible = node.meta?.featureCompartmentsVisible === true;
200318
201199
  const featureCompartmentHeight = featureBandTopReserve(data);
200319
- const containerRef = (0, import_react8.useRef)(null);
201200
+ const containerRef = (0, import_react9.useRef)(null);
200320
201201
  const portSource = (pid) => {
200321
201202
  const p = node.ports?.find((pp) => pp.id === pid);
200322
201203
  ctx.onPortSelected?.();
@@ -200343,8 +201224,8 @@ function SysmlNode({ id: id2, data, draggable, selected: selected2, width, heigh
200343
201224
  const nodeSideStartable = directRelation !== void 0 && data.kind !== "sv" && node.shape !== "lifeline" && !isPackageEndpoint(node.shape, node.keyword);
200344
201225
  const selectedPortId = useInteraction(ctx.store, (s) => typeof s.selectedId === "string" && myPortIds.includes(s.selectedId) ? s.selectedId : void 0);
200345
201226
  const dropClass = useDropState(ctx.store, id2);
200346
- const [hoveredPortId, setHoveredPortId] = (0, import_react8.useState)(void 0);
200347
- const [sidePointsHovered, setSidePointsHovered] = (0, import_react8.useState)(false);
201227
+ const [hoveredPortId, setHoveredPortId] = (0, import_react9.useState)(void 0);
201228
+ const [sidePointsHovered, setSidePointsHovered] = (0, import_react9.useState)(false);
200348
201229
  const isPackageNode = isPackageEndpoint(node.shape, node.keyword);
200349
201230
  const sideConnectable = data.kind !== "sv" && !isPackageNode;
200350
201231
  const perimeterControl = keepsPerimeterSidePointsMounted(node.shape);
@@ -200474,7 +201355,8 @@ function SysmlNode({ id: id2, data, draggable, selected: selected2, width, heigh
200474
201355
  node.shape === "initial" || node.shape === "final" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "rf-circular-control-hit", "aria-hidden": "true" }) : null,
200475
201356
  ports.flatMap((ph) => {
200476
201357
  const rect = portGlyphRect(ph, w, h, featureCompartmentHeight);
200477
- const startable = directRelationForHandle(data.kind, {
201358
+ const proxied = isProxyPort(ph.port);
201359
+ const startable = !proxied && directRelationForHandle(data.kind, {
200478
201360
  id: ph.port.id,
200479
201361
  name: ph.port.name,
200480
201362
  keyword: ph.port.pin ? "pin" : "port",
@@ -200495,7 +201377,8 @@ function SysmlNode({ id: id2, data, draggable, selected: selected2, width, heigh
200495
201377
  x: outer.x,
200496
201378
  y: outer.y,
200497
201379
  kind: "port",
200498
- active: revealBoth || ph.port.id === connectTargetPortId && connectTargetPortSide === ph.side,
201380
+ connectable: !proxied,
201381
+ active: !proxied && (revealBoth || ph.port.id === connectTargetPortId && connectTargetPortSide === ph.side),
200499
201382
  startable
200500
201383
  },
200501
201384
  `${ph.port.id}-out`
@@ -200508,7 +201391,8 @@ function SysmlNode({ id: id2, data, draggable, selected: selected2, width, heigh
200508
201391
  x: inner.x,
200509
201392
  y: inner.y,
200510
201393
  kind: "port",
200511
- active: revealBoth || ph.port.id === connectTargetPortId && connectTargetPortSide === innerSide,
201394
+ connectable: !proxied,
201395
+ active: !proxied && (revealBoth || ph.port.id === connectTargetPortId && connectTargetPortSide === innerSide),
200512
201396
  startable
200513
201397
  },
200514
201398
  `${ph.port.id}-in`
@@ -200518,17 +201402,21 @@ function SysmlNode({ id: id2, data, draggable, selected: selected2, width, heigh
200518
201402
  ctx.onPortMove ? ports.map((ph) => {
200519
201403
  const rect = portGlyphRect(ph, w, h, featureCompartmentHeight);
200520
201404
  const nestedChild = ph.port.parentPort !== void 0;
201405
+ const proxyPort = isProxyPort(ph.port);
200521
201406
  const strip = portInteractionStrip(rect, ph.side);
200522
201407
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
200523
201408
  "div",
200524
201409
  {
200525
201410
  className: "port-drag-hit nodrag",
200526
201411
  style: { position: "absolute", left: strip.cx, top: strip.cy, width: strip.w, height: strip.h, transform: "translate(-50%,-50%)" },
200527
- title: nestedChild ? `${ph.port.name} - click to select; drag a dot to connect (moves with its parent port)` : `${ph.port.name} - drag the centre to move along the edge; drag a dot to connect; click to select`,
201412
+ title: proxyPort ? `${ph.port.name} - a proxy for a port inside the collapsed contents; drag the centre to move it, click to select the port it stands for` : nestedChild ? `${ph.port.name} - click to select; drag a dot to connect (moves with its parent port)` : `${ph.port.name} - drag the centre to move along the edge; drag a dot to connect; click to select`,
200528
201413
  onPointerEnter: () => setHoveredPortId(ph.port.id),
200529
201414
  onPointerLeave: () => setHoveredPortId((cur) => cur === ph.port.id ? void 0 : cur),
200530
201415
  onPointerDown: (e) => onPortPointerDown(ph.port.id, e, { side: ph.side, offset: ph.offset }, !nestedChild),
200531
- onContextMenu: (e) => {
201416
+ onContextMenu: proxyPort ? (e) => {
201417
+ e.preventDefault();
201418
+ e.stopPropagation();
201419
+ } : (e) => {
200532
201420
  e.preventDefault();
200533
201421
  e.stopPropagation();
200534
201422
  ctx.onContextNode(ph.port.id, e.clientX, e.clientY);
@@ -200655,7 +201543,7 @@ function FrameNode({ id: id2, data, selected: selected2, width, height }) {
200655
201543
  const h = height ?? data.h;
200656
201544
  const partitionKindFull = isExhibitLane ? "\xABexhibited by\xBB" : "\xABperformer\xBB";
200657
201545
  const partitionKindShown = fitKind(partitionKindFull, Math.max(1, w - 20));
200658
- const rawClipId = (0, import_react8.useId)();
201546
+ const rawClipId = (0, import_react9.useId)();
200659
201547
  const clipId = `dframe-clip-${rawClipId.replace(/[^a-zA-Z0-9_-]/g, "")}`;
200660
201548
  const structuredPrefix = `\xAB${structuredKeyword}\xBB`;
200661
201549
  const structuredConditionShown = structuredCondition ? fitText(structuredCondition, Math.max(1, w - 24 - structuredPrefix.length * 9 * 0.78), 11) : "";
@@ -200683,7 +201571,7 @@ function FrameNode({ id: id2, data, selected: selected2, width, height }) {
200683
201571
  performer: frame2.meta?.performerLane === true,
200684
201572
  structured: frame2.meta?.structuredControl === true
200685
201573
  }));
200686
- const containerRef = (0, import_react8.useRef)(null);
201574
+ const containerRef = (0, import_react9.useRef)(null);
200687
201575
  const portSource = (pid) => {
200688
201576
  ctx.onPortSelected?.();
200689
201577
  ctx.onReveal(frame2.ports?.find((p) => p.id === pid)?.source, pid);
@@ -200711,8 +201599,8 @@ function FrameNode({ id: id2, data, selected: selected2, width, height }) {
200711
201599
  const selectedPortId = useInteraction(ctx.store, (s) => typeof s.selectedId === "string" && myPortIds.includes(s.selectedId) ? s.selectedId : void 0);
200712
201600
  const dropClass = useDropState(ctx.store, id2);
200713
201601
  const editing = useInteraction(ctx.store, (s) => s.editing?.nodeId === id2 && !s.editing?.at && !s.editing?.edgeId ? s.editing : void 0);
200714
- const [hoveredPortId, setHoveredPortId] = (0, import_react8.useState)(void 0);
200715
- const [sidePointsHovered, setSidePointsHovered] = (0, import_react8.useState)(false);
201602
+ const [hoveredPortId, setHoveredPortId] = (0, import_react9.useState)(void 0);
201603
+ const [sidePointsHovered, setSidePointsHovered] = (0, import_react9.useState)(false);
200716
201604
  const sideConnectable = data.kind !== "sv" && !isPackageFrame && !isPartitionLane && !isOuterViewFrame;
200717
201605
  const sideOffsets = isPartitionLane ? SIDES.map(() => []) : SIDES.map((side) => mountedNodeSidePointOffsets(
200718
201606
  data,
@@ -200955,7 +201843,8 @@ function FrameNode({ id: id2, data, selected: selected2, width, height }) {
200955
201843
  }),
200956
201844
  showPorts ? ports.flatMap((ph) => {
200957
201845
  const rect = portGlyphRect(ph, w, h, featureCompartmentHeight);
200958
- const startable = directRelationForHandle(data.kind, {
201846
+ const proxied = isProxyPort(ph.port);
201847
+ const startable = !proxied && directRelationForHandle(data.kind, {
200959
201848
  id: ph.port.id,
200960
201849
  name: ph.port.name,
200961
201850
  keyword: ph.port.pin ? "pin" : "port",
@@ -200976,7 +201865,8 @@ function FrameNode({ id: id2, data, selected: selected2, width, height }) {
200976
201865
  x: outer.x,
200977
201866
  y: outer.y,
200978
201867
  kind: "port",
200979
- active: revealBoth || ph.port.id === connectTargetPortId && connectTargetPortSide === ph.side,
201868
+ connectable: !proxied,
201869
+ active: !proxied && (revealBoth || ph.port.id === connectTargetPortId && connectTargetPortSide === ph.side),
200980
201870
  startable
200981
201871
  },
200982
201872
  `${ph.port.id}-out`
@@ -200989,7 +201879,8 @@ function FrameNode({ id: id2, data, selected: selected2, width, height }) {
200989
201879
  x: inner.x,
200990
201880
  y: inner.y,
200991
201881
  kind: "port",
200992
- active: revealBoth || ph.port.id === connectTargetPortId && connectTargetPortSide === innerSide,
201882
+ connectable: !proxied,
201883
+ active: !proxied && (revealBoth || ph.port.id === connectTargetPortId && connectTargetPortSide === innerSide),
200993
201884
  startable
200994
201885
  },
200995
201886
  `${ph.port.id}-in`
@@ -200999,17 +201890,21 @@ function FrameNode({ id: id2, data, selected: selected2, width, height }) {
200999
201890
  ctx.onPortMove ? ports.map((ph) => {
201000
201891
  const rect = portGlyphRect(ph, w, h, featureCompartmentHeight);
201001
201892
  const nestedChild = ph.port.parentPort !== void 0;
201893
+ const proxyPort = isProxyPort(ph.port);
201002
201894
  const strip = portInteractionStrip(rect, ph.side);
201003
201895
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
201004
201896
  "div",
201005
201897
  {
201006
201898
  className: "port-drag-hit nodrag",
201007
201899
  style: { position: "absolute", left: strip.cx, top: strip.cy, width: strip.w, height: strip.h, transform: "translate(-50%,-50%)" },
201008
- title: nestedChild ? `${ph.port.name} - click to select; drag a dot to connect (moves with its parent port)` : `${ph.port.name} - drag the centre to move along the edge; drag a dot to connect; click to select`,
201900
+ title: proxyPort ? `${ph.port.name} - a proxy for a port inside the collapsed contents; drag the centre to move it, click to select the port it stands for` : nestedChild ? `${ph.port.name} - click to select; drag a dot to connect (moves with its parent port)` : `${ph.port.name} - drag the centre to move along the edge; drag a dot to connect; click to select`,
201009
201901
  onPointerEnter: () => setHoveredPortId(ph.port.id),
201010
201902
  onPointerLeave: () => setHoveredPortId((cur) => cur === ph.port.id ? void 0 : cur),
201011
201903
  onPointerDown: (e) => onPortPointerDown(ph.port.id, e, { side: ph.side, offset: ph.offset }, !nestedChild),
201012
- onContextMenu: (e) => {
201904
+ onContextMenu: proxyPort ? (e) => {
201905
+ e.preventDefault();
201906
+ e.stopPropagation();
201907
+ } : (e) => {
201013
201908
  e.preventDefault();
201014
201909
  e.stopPropagation();
201015
201910
  ctx.onContextNode(ph.port.id, e.clientX, e.clientY);
@@ -201100,12 +201995,12 @@ function SeqFragmentNode({ data, width, height }) {
201100
201995
  ] }) });
201101
201996
  }
201102
201997
  var nodeTypes = {
201103
- sysml: (0, import_react8.memo)(SysmlNode),
201104
- frame: (0, import_react8.memo)(FrameNode),
201105
- lane: (0, import_react8.memo)(LaneNode),
201106
- seqfragment: (0, import_react8.memo)(SeqFragmentNode),
201107
- geo: (0, import_react8.memo)(GeoShapeNode),
201108
- geoframe: (0, import_react8.memo)(GeoFrameNode)
201998
+ sysml: (0, import_react9.memo)(SysmlNode),
201999
+ frame: (0, import_react9.memo)(FrameNode),
202000
+ lane: (0, import_react9.memo)(LaneNode),
202001
+ seqfragment: (0, import_react9.memo)(SeqFragmentNode),
202002
+ geo: (0, import_react9.memo)(GeoShapeNode),
202003
+ geoframe: (0, import_react9.memo)(GeoFrameNode)
201109
202004
  };
201110
202005
 
201111
202006
  // src/node-markup.tsx
@@ -201169,13 +202064,13 @@ function renderNodeBody(node, lineStyle, index2) {
201169
202064
  width: node.width ?? node.measured?.width ?? node.data.w,
201170
202065
  height: node.height ?? node.measured?.height ?? node.data.h
201171
202066
  };
201172
- const markup = (0, import_server.renderToStaticMarkup)((0, import_react10.createElement)(
202067
+ const markup = (0, import_server.renderToStaticMarkup)((0, import_react11.createElement)(
201173
202068
  ReactFlowProvider,
201174
202069
  null,
201175
- (0, import_react10.createElement)(
202070
+ (0, import_react11.createElement)(
201176
202071
  DiagramContext.Provider,
201177
202072
  { value: exportContext(lineStyle) },
201178
- (0, import_react10.createElement)(Component, props)
202073
+ (0, import_react11.createElement)(Component, props)
201179
202074
  )
201180
202075
  ));
201181
202076
  const inner = extractNodeSvgInner(markup);
@@ -201355,7 +202250,7 @@ async function runExport(command) {
201355
202250
  const root4 = command.workspace ? path8.resolve(command.workspace) : findWorkspaceRoot(file);
201356
202251
  const settings = diagramSettingsFor(readProjectConfig(root4));
201357
202252
  const sideCar = command.autoLayout ? emptySideCar() : readSideCar(root4, file);
201358
- const provider = new SysmlDiagramModelProvider();
202253
+ const provider = new SysmlDiagramModelProvider(services.shared);
201359
202254
  const kinds = command.all ? CANVAS_KINDS.filter((kind) => provider.buildAvailableDiagramKinds(document2, command.anchor).some((available) => available.kind === kind)) : [command.view ?? settings.defaultKind];
201360
202255
  const written = [];
201361
202256
  const empty2 = [];
@@ -201383,7 +202278,7 @@ async function runExport(command) {
201383
202278
  }
201384
202279
 
201385
202280
  // src/main.ts
201386
- var VERSION2 = true ? "0.20.3" : "dev";
202281
+ var VERSION2 = true ? "0.21.1" : "dev";
201387
202282
  function display(file) {
201388
202283
  const rel2 = path9.relative(process.cwd(), file);
201389
202284
  return rel2 && !rel2.startsWith("..") ? rel2.split(path9.sep).join("/") : file;