@likec4/core 1.43.0 → 1.45.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/builder/index.d.mts +15 -14
  2. package/dist/builder/index.mjs +35 -18
  3. package/dist/compute-view/index.d.mts +9 -9
  4. package/dist/compute-view/index.mjs +8 -7
  5. package/dist/compute-view/relationships-view/index.d.mts +7 -7
  6. package/dist/compute-view/relationships-view/index.mjs +2 -2
  7. package/dist/index.d.mts +27 -7
  8. package/dist/index.mjs +8 -7
  9. package/dist/model/connection/deployment/index.d.mts +9 -9
  10. package/dist/model/connection/deployment/index.mjs +2 -2
  11. package/dist/model/connection/index.d.mts +10 -10
  12. package/dist/model/connection/index.mjs +3 -3
  13. package/dist/model/connection/model/index.d.mts +9 -9
  14. package/dist/model/connection/model/index.mjs +2 -2
  15. package/dist/model/index.d.mts +11 -11
  16. package/dist/model/index.mjs +4 -4
  17. package/dist/shared/{core.CDvVInBp.d.mts → core.0zAQeenX.d.mts} +3 -3
  18. package/dist/shared/core.3ZhnKAlZ.mjs +106 -0
  19. package/dist/shared/{core.CwsG7hOw.d.mts → core.5ZQ-r3Oa.d.mts} +1 -1
  20. package/dist/shared/{core.hNWo20Ym.d.mts → core.B73yxfPi.d.mts} +55 -36
  21. package/dist/shared/{core.Cq2kxOI-.d.mts → core.BGFjN3nv.d.mts} +3 -3
  22. package/dist/shared/{core.rCeaAqgW.mjs → core.BdPcbSkN.mjs} +1 -1
  23. package/dist/shared/core.BhNcrwzK.mjs +7 -0
  24. package/dist/shared/core.BkVA6gjl.mjs +5 -0
  25. package/dist/shared/core.BuQZczj6.mjs +38 -0
  26. package/dist/shared/{core.2N_9BzyD.mjs → core.CQPEY2wQ.mjs} +5 -4
  27. package/dist/shared/{core.DFi2dOTl.mjs → core.CR3PmPzr.mjs} +85 -1
  28. package/dist/shared/{core.DyToofsP.mjs → core.CRI1AjFj.mjs} +276 -145
  29. package/dist/shared/{core.CXWsKEDr.mjs → core.CWwSgOzF.mjs} +268 -631
  30. package/dist/shared/{core.727Qoh_W.mjs → core.CdNCAwq7.mjs} +2 -101
  31. package/dist/shared/{core.QJD_fcrc.mjs → core.CmPXpJ8l.mjs} +1 -14
  32. package/dist/shared/{core.DTdfiejA.d.mts → core.Cog93roC.d.mts} +2 -2
  33. package/dist/shared/core.Coi_LOUZ.mjs +7 -0
  34. package/dist/shared/{core.CcJ1FZ7h.d.mts → core.CpURdWRM.d.mts} +174 -76
  35. package/dist/shared/{core.D5fzJWbF.d.mts → core.DB0Ue5Wx.d.mts} +1 -1
  36. package/dist/shared/{core.DNbUPnve.mjs → core.DEieYfbG.mjs} +27 -25
  37. package/dist/shared/{core.BYNkXQ8A.mjs → core.DH7TXqXf.mjs} +30 -1
  38. package/dist/shared/{core.DMMOWQqc.mjs → core.DIE3F6sw.mjs} +2 -2
  39. package/dist/shared/{core.D0NziuvN.mjs → core.DViDmiAu.mjs} +5 -5
  40. package/dist/shared/{core.Be05qJwN.mjs → core.D_f4F48-.mjs} +41 -18
  41. package/dist/shared/{core.C2TiyjI6.mjs → core.DbfO90vF.mjs} +20 -31
  42. package/dist/shared/{core.BT-9gaqQ.d.mts → core.DnCLhN8C.d.mts} +83 -94
  43. package/dist/shared/{core.BouyJs63.mjs → core.DqlrMlsf.mjs} +1 -1
  44. package/dist/shared/{core.CNgZvKb8.mjs → core.DrUt0Lbi.mjs} +1 -1
  45. package/dist/shared/{core.CT1xBp4R.d.mts → core.Dvh1H0T2.d.mts} +2 -2
  46. package/dist/shared/core.M9ayqQZa.mjs +1207 -0
  47. package/dist/shared/{core.CvLjw3bH.d.mts → core.mUnpvHtA.d.mts} +96 -12
  48. package/dist/shared/core.oSV6SRfk.mjs +13 -0
  49. package/dist/shared/core.q10OP9oJ.mjs +5 -0
  50. package/dist/shared/{core.BXs4wY7R.d.mts → core.t3qfsVvn.d.mts} +4 -4
  51. package/dist/shared/core.uFk_o9X6.mjs +13 -0
  52. package/dist/shared/core.vzLtp8i3.mjs +1282 -0
  53. package/dist/styles/index.d.mts +18 -8
  54. package/dist/styles/index.mjs +63 -1
  55. package/dist/types/_aux.d.mts +2 -2
  56. package/dist/types/_aux.mjs +8 -1
  57. package/dist/types/expression-model.d.mts +3 -3
  58. package/dist/types/expression.d.mts +3 -3
  59. package/dist/types/fqnRef.d.mts +7 -8
  60. package/dist/types/index.d.mts +17 -13
  61. package/dist/types/index.mjs +51 -14
  62. package/dist/utils/graphology/index.mjs +1 -1
  63. package/dist/utils/index.d.mts +3 -2
  64. package/dist/utils/index.mjs +9 -6
  65. package/dist/utils/iterable/index.d.mts +1 -1
  66. package/dist/utils/iterable/index.mjs +2 -1
  67. package/package.json +18 -17
  68. package/dist/shared/core.01VTr9qu.mjs +0 -170
  69. package/dist/shared/core.1vX5a9AY.mjs +0 -86
  70. package/dist/shared/core.BazD6cot.mjs +0 -14
  71. package/dist/shared/core.BzTakU3I.mjs +0 -67
  72. package/dist/shared/core.OHD4KXm9.mjs +0 -5
@@ -1,41 +1,34 @@
1
- import { n as n$4, e as e$4, a as DeploymentNodeModel, b as DeployedInstanceModel, c as DeploymentRelationModel, N as NestedElementOfDeployedInstanceModel } from './core.Be05qJwN.mjs';
2
- import { t as t$8, a as t$9 } from './core.BsSXS-_R.mjs';
3
- import { e as e$3 } from './core.BKlholso.mjs';
1
+ import { t as t$3, e as e$2, a as DeploymentNodeModel, b as DeployedInstanceModel, c as DeploymentRelationModel, N as NestedElementOfDeployedInstanceModel } from './core.D_f4F48-.mjs';
2
+ import { e as e$1 } from './core.BKlholso.mjs';
3
+ import { n as n$1 } from './core.BhNcrwzK.mjs';
4
4
  import { c as splitGlobalFqn, g as extractStep, e as isStepEdgeId, i as isGroupElementKind, b as isGlobalFqn, a as GlobalFqn } from './core.C_Ni6yHl.mjs';
5
- import { q as hierarchyLevel, n as nameFromFqn, i as isAncestor, k as commonAncestor, s as sortNaturalByFqn, f as sortParentsFirst, p as parentFqn, a as ancestorsFqn, j as compareNaturalHierarchically, g as compareNatural } from './core.727Qoh_W.mjs';
5
+ import { m as hierarchyLevel, n as nameFromFqn, i as isAncestor, g as commonAncestor, s as sortNaturalByFqn, f as sortParentsFirst, p as parentFqn, a as ancestorsFqn } from './core.CdNCAwq7.mjs';
6
6
  import { m as memoizeProp } from './core.BR4zXDH-.mjs';
7
- import { R as RichText, e as exact } from './core.01VTr9qu.mjs';
8
- import { a as preferSummary, p as preferDescription } from './core.BazD6cot.mjs';
9
- import { a as ihead, i as ifind } from './core.QJD_fcrc.mjs';
10
- import { t as t$a } from './core.OHD4KXm9.mjs';
11
- import { t as t$b } from './core.CbT8JVYL.mjs';
12
- import { L as LikeC4Styles } from './core.DNbUPnve.mjs';
7
+ import { R as RichText, e as exact } from './core.M9ayqQZa.mjs';
8
+ import { preferSummary, preferDescription } from '../types/_aux.mjs';
9
+ import { i as ihead } from './core.uFk_o9X6.mjs';
10
+ import { t as t$6, b as compareNaturalHierarchically, c as compareNatural } from './core.3ZhnKAlZ.mjs';
11
+ import { t as t$2, a as t$4 } from './core.BsSXS-_R.mjs';
12
+ import { t as t$5, e as e$3 } from './core.Coi_LOUZ.mjs';
13
+ import { t as t$8 } from './core.CbT8JVYL.mjs';
14
+ import { t as t$7 } from './core.BkVA6gjl.mjs';
15
+ import { c as calcDriftsFromSnapshot, a as applyManualLayout, h as t$9 } from './core.vzLtp8i3.mjs';
16
+ import { L as LikeC4Styles } from './core.DEieYfbG.mjs';
13
17
  import { g as getOrCreate } from './core.DcS-0zys.mjs';
14
- import { i as invariant, a as nonNullable } from './core.D4npX2q8.mjs';
15
18
  import { D as DefaultMap } from './core.BbE4y-yl.mjs';
19
+ import { i as invariant, a as nonNullable } from './core.D4npX2q8.mjs';
16
20
  import { FqnRef } from '../types/fqnRef.mjs';
17
- import { b as isDeploymentNode, a as _type, _ as _stage, i as isOnStage, w as whereOperatorAsPredicate } from './core.BYNkXQ8A.mjs';
21
+ import { c as isDeploymentNode, a as _type, _ as _stage, i as isOnStage, w as whereOperatorAsPredicate } from './core.DH7TXqXf.mjs';
22
+ import { i as ifind } from './core.CmPXpJ8l.mjs';
18
23
  import { i as ifilter } from './core.DRJma0Ol.mjs';
19
- import './core.BouyJs63.mjs';
20
- import './core.2N_9BzyD.mjs';
21
-
22
- const e$2={asc:(e,t)=>e>t,desc:(e,t)=>e<t};function t$7(e,t){let[n,...a]=t;if(!i$1(n)){let t=r$1(...a);return e(n,t)}let o=r$1(n,...a);return t=>e(t,o)}function r$1(t,n,...i){let a=typeof t==`function`?t:t[0],o=typeof t==`function`?`asc`:t[1],{[o]:s}=e$2,c=n===void 0?void 0:r$1(n,...i);return (e,t)=>{let n=a(e),r=a(t);return s(n,r)?1:s(r,n)?-1:c?.(e,t)??0}}function i$1(t){if(a(t))return true;if(typeof t!=`object`||!Array.isArray(t))return false;let[n,r,...i]=t;return a(n)&&typeof r==`string`&&r in e$2&&i.length===0}const a=e=>typeof e==`function`&&e.length===1;
23
-
24
- function t$6(...t){return t$8(Object.entries,t)}
25
-
26
- function t$5(...t){return t$8(n$3,t)}function n$3(e,t){if(e===t||Object.is(e,t))return true;if(typeof e!=`object`||!e||typeof t!=`object`||!t)return false;if(e instanceof Map&&t instanceof Map)return r(e,t);if(e instanceof Set&&t instanceof Set)return i(e,t);let n=Object.keys(e);if(n.length!==Object.keys(t).length)return false;for(let r of n){if(!Object.hasOwn(t,r))return false;let{[r]:n}=e,{[r]:i}=t;if(n!==i||!Object.is(n,i))return false}return true}function r(e,t){if(e.size!==t.size)return false;for(let[n,r]of e){let e=t.get(n);if(r!==e||!Object.is(r,e))return false}return true}function i(e,t){if(e.size!==t.size)return false;for(let n of e)if(!t.has(n))return false;return true}
27
-
28
- function t$4(...t){return t$8(n$2,t)}const n$2=e=>e.at(-1);
24
+ import './core.DqlrMlsf.mjs';
25
+ import './core.CQPEY2wQ.mjs';
29
26
 
30
- function e$1(e,...n){return typeof e==`string`||typeof e==`number`||typeof e==`symbol`?r=>t$3(r,e,...n):t$3(e,...n)}function t$3(e,...t){let n=e;for(let e of t){if(n==null)return;n=n[e];}return n}
31
-
32
- function t$2(...t){return t$8(n$1,t)}function n$1(e,t){let n=[...e];return n.sort(t),n}
33
-
34
- function t$1(...t){return t$7(n,t)}const n=(e,t)=>[...e].sort(t);
27
+ function t$1(...t){return t$2(n,t)}const n=e=>e.at(-1);
35
28
 
36
29
  function e(e,t,n){return typeof t==`number`||t===void 0?n=>n.split(e,t):e.split(t,n)}
37
30
 
38
- function t(...t){return t$8(Object.values,t)}
31
+ function t(...t){return t$2(Object.values,t)}
39
32
 
40
33
  class ElementModel {
41
34
  constructor($model, $element) {
@@ -55,6 +48,10 @@ class ElementModel {
55
48
  this.hierarchyLevel = hierarchyLevel(this.id);
56
49
  }
57
50
  }
51
+ /**
52
+ * Don't use in runtime, only for type inference
53
+ */
54
+ Aux;
58
55
  id;
59
56
  _literalId;
60
57
  hierarchyLevel;
@@ -83,7 +80,7 @@ class ElementModel {
83
80
  */
84
81
  get tags() {
85
82
  return memoizeProp(this, Symbol.for("tags"), () => {
86
- return n$4([
83
+ return n$1([
87
84
  ...this.$element.tags ?? [],
88
85
  ...this.$model.specification.elements[this.$element.kind]?.tags ?? []
89
86
  ]);
@@ -97,7 +94,7 @@ class ElementModel {
97
94
  * (if one is missing - it falls back to another)
98
95
  */
99
96
  get hasSummary() {
100
- return !!this.$element.summary && !!this.$element.description && !t$5(this.$element.summary, this.$element.description);
97
+ return !!this.$element.summary && !!this.$element.description && !t$3(this.$element.summary, this.$element.description);
101
98
  }
102
99
  /**
103
100
  * Short description of the element.
@@ -265,13 +262,13 @@ class ElementModel {
265
262
  * @returns true if the element is deployed
266
263
  */
267
264
  isDeployed() {
268
- return e$3(ihead(this.deployments()));
265
+ return e$1(ihead(this.deployments()));
269
266
  }
270
267
  deployments() {
271
268
  return this.$model.deployment.instancesOf(this);
272
269
  }
273
270
  hasMetadata() {
274
- return !!this.$element.metadata && !e$4(this.$element.metadata);
271
+ return !!this.$element.metadata && !e$2(this.$element.metadata);
275
272
  }
276
273
  getMetadata(field) {
277
274
  if (field) {
@@ -290,12 +287,13 @@ class ElementModel {
290
287
  const getId = (element) => {
291
288
  return typeof element === "string" ? element : element.id;
292
289
  };
290
+
293
291
  const VIEW_FOLDERS_SEPARATOR = "/";
294
292
  const splitViewTitle = (title) => {
295
293
  invariant(!title.includes("\n"), "View title cannot contain newlines");
296
294
  if (title.includes(VIEW_FOLDERS_SEPARATOR)) {
297
295
  const segments = title.split(VIEW_FOLDERS_SEPARATOR).map((s) => s.trim()).filter((s) => s.length > 0);
298
- if (t$9(segments, 1)) {
296
+ if (t$4(segments, 1)) {
299
297
  return segments;
300
298
  }
301
299
  return [""];
@@ -307,7 +305,7 @@ const normalizeViewPath = (title) => {
307
305
  };
308
306
  const getViewFolderPath = (title) => {
309
307
  const segments = splitViewTitle(title);
310
- if (!t$9(segments, 2)) {
308
+ if (!t$4(segments, 2)) {
311
309
  return null;
312
310
  }
313
311
  return segments.slice(0, -1).join(VIEW_FOLDERS_SEPARATOR);
@@ -649,19 +647,37 @@ class RelationshipModel {
649
647
  return `${this.source.id} -> ${this.target.id}`;
650
648
  }
651
649
  get title() {
652
- if (!e$3(this.$relationship.title)) {
650
+ if (!e$1(this.$relationship.title)) {
653
651
  return null;
654
652
  }
655
653
  return this.$relationship.title;
656
654
  }
657
655
  get technology() {
658
- if (!e$3(this.$relationship.technology)) {
656
+ if (!e$1(this.$relationship.technology)) {
659
657
  return null;
660
658
  }
661
659
  return this.$relationship.technology;
662
660
  }
661
+ /**
662
+ * Returns true if the relationship has a summary and a description
663
+ * (if one is missing - it falls back to another)
664
+ */
665
+ get hasSummary() {
666
+ return !!this.$relationship.summary && !!this.$relationship.description && !t$3(this.$relationship.summary, this.$relationship.description);
667
+ }
668
+ /**
669
+ * Short description of the relationship.
670
+ * Falls back to description if summary is not provided.
671
+ */
672
+ get summary() {
673
+ return RichText.memoize(this, "summary", preferSummary(this.$relationship));
674
+ }
675
+ /**
676
+ * Long description of the relationship.
677
+ * Falls back to summary if description is not provided.
678
+ */
663
679
  get description() {
664
- return RichText.memoize(this, "description", this.$relationship.description);
680
+ return RichText.memoize(this, "description", preferDescription(this.$relationship));
665
681
  }
666
682
  get navigateTo() {
667
683
  return this.$relationship.navigateTo ? this.model.view(this.$relationship.navigateTo) : null;
@@ -705,7 +721,7 @@ class RelationshipModel {
705
721
  return true;
706
722
  }
707
723
  hasMetadata() {
708
- return !!this.$relationship.metadata && !e$4(this.$relationship.metadata);
724
+ return !!this.$relationship.metadata && !e$2(this.$relationship.metadata);
709
725
  }
710
726
  getMetadata(field) {
711
727
  if (field) {
@@ -722,72 +738,75 @@ class RelationshipModel {
722
738
  }
723
739
 
724
740
  class EdgeModel {
725
- constructor(view, $edge, source, target) {
726
- this.view = view;
727
- this.$edge = $edge;
741
+ constructor($viewModel, $edge, source, target) {
728
742
  this.source = source;
729
743
  this.target = target;
730
- this.#edge = $edge;
744
+ this.$viewModel = $viewModel;
745
+ this.$view = $viewModel.$view;
746
+ this.$edge = $edge;
731
747
  }
732
- #edge;
748
+ Aux;
749
+ $viewModel;
750
+ $view;
751
+ $edge;
733
752
  get id() {
734
- return this.#edge.id;
753
+ return this.$edge.id;
735
754
  }
736
755
  get parent() {
737
- return this.#edge.parent ? this.view.node(this.#edge.parent) : null;
756
+ return this.$edge.parent ? this.$viewModel.node(this.$edge.parent) : null;
738
757
  }
739
758
  get label() {
740
- return this.#edge.label ?? null;
759
+ return this.$edge.label ?? null;
741
760
  }
742
761
  get description() {
743
- return RichText.memoize(this, "description", this.#edge.description);
762
+ return RichText.memoize(this, "description", this.$edge.description);
744
763
  }
745
764
  get technology() {
746
- return this.#edge.technology ?? null;
765
+ return this.$edge.technology ?? null;
747
766
  }
748
767
  hasParent() {
749
- return this.#edge.parent !== null;
768
+ return this.$edge.parent !== null;
750
769
  }
751
770
  get tags() {
752
- return this.#edge.tags ?? [];
771
+ return this.$edge.tags ?? [];
753
772
  }
754
773
  get stepNumber() {
755
774
  return this.isStep() ? extractStep(this.id) : null;
756
775
  }
757
776
  get navigateTo() {
758
- return this.#edge.navigateTo ? this.view.$model.view(this.#edge.navigateTo) : null;
777
+ return this.$edge.navigateTo ? this.$viewModel.$model.view(this.$edge.navigateTo) : null;
759
778
  }
760
779
  get color() {
761
- return this.#edge.color;
780
+ return this.$edge.color;
762
781
  }
763
782
  get line() {
764
- return this.#edge.line ?? this.view.$model.$styles.defaults.relationship.line;
783
+ return this.$edge.line ?? this.$viewModel.$styles.defaults.relationship.line;
765
784
  }
766
785
  get head() {
767
- return this.#edge.head ?? this.view.$model.$styles.defaults.relationship.arrow;
786
+ return this.$edge.head ?? this.$viewModel.$styles.defaults.relationship.arrow;
768
787
  }
769
788
  get tail() {
770
- return this.#edge.tail;
789
+ return this.$edge.tail;
771
790
  }
772
791
  isStep() {
773
792
  return isStepEdgeId(this.id);
774
793
  }
775
794
  *relationships(type) {
776
- for (const id of this.#edge.relations) {
795
+ for (const id of this.$edge.relations) {
777
796
  if (type) {
778
- const rel = this.view.$model.findRelationship(id, type);
797
+ const rel = this.$viewModel.$model.findRelationship(id, type);
779
798
  if (rel) {
780
799
  yield rel;
781
800
  }
782
801
  } else {
783
- yield this.view.$model.relationship(id);
802
+ yield this.$viewModel.$model.relationship(id);
784
803
  }
785
804
  }
786
805
  return;
787
806
  }
788
807
  includesRelation(rel) {
789
808
  const id = typeof rel === "string" ? rel : rel.id;
790
- return this.#edge.relations.includes(id);
809
+ return this.$edge.relations.includes(id);
791
810
  }
792
811
  isTagged(tag) {
793
812
  return this.tags.includes(tag);
@@ -795,61 +814,76 @@ class EdgeModel {
795
814
  }
796
815
 
797
816
  class NodeModel {
798
- constructor($view, $node) {
799
- this.$view = $view;
817
+ Aux;
818
+ $viewModel;
819
+ $view;
820
+ $node;
821
+ constructor($viewModel, $node) {
822
+ this.$viewModel = $viewModel;
823
+ this.$view = $viewModel.$view;
800
824
  this.$node = $node;
801
- this.#node = $node;
802
825
  }
803
- #node;
804
826
  get id() {
805
- return this.#node.id;
827
+ return this.$node.id;
806
828
  }
807
829
  get title() {
808
- return this.#node.title;
830
+ return this.$node.title;
809
831
  }
810
832
  get kind() {
811
- return this.#node.kind;
833
+ return this.$node.kind;
812
834
  }
813
835
  get description() {
814
- return RichText.memoize(this, "description", this.#node.description);
836
+ return RichText.memoize(this, "description", this.$node.description);
815
837
  }
816
838
  get technology() {
817
- return this.#node.technology ?? null;
839
+ return this.$node.technology ?? null;
818
840
  }
819
841
  get parent() {
820
- return this.#node.parent ? this.$view.node(this.#node.parent) : null;
842
+ return this.$node.parent ? this.$viewModel.node(this.$node.parent) : null;
821
843
  }
822
844
  get element() {
823
- const modelRef = this.#node.modelRef;
824
- return modelRef ? this.$view.$model.element(modelRef) : null;
845
+ const modelRef = this.$node.modelRef;
846
+ return modelRef ? this.$viewModel.$model.element(modelRef) : null;
825
847
  }
826
848
  get deployment() {
827
- const modelRef = this.#node.deploymentRef;
828
- return modelRef ? this.$view.$model.deployment.element(modelRef) : null;
849
+ const modelRef = this.$node.deploymentRef;
850
+ return modelRef ? this.$viewModel.$model.deployment.element(modelRef) : null;
829
851
  }
830
852
  get shape() {
831
- return this.#node.shape;
853
+ return this.$node.shape;
832
854
  }
833
855
  get color() {
834
- return this.#node.color;
856
+ return this.$node.color;
835
857
  }
836
858
  get icon() {
837
- return this.#node.icon ?? null;
859
+ return this.$node.icon ?? null;
838
860
  }
839
861
  get tags() {
840
- return this.#node.tags;
862
+ return this.$node.tags;
841
863
  }
842
864
  get links() {
843
- return this.#node.links ?? [];
865
+ return this.$node.links ?? [];
844
866
  }
845
867
  get navigateTo() {
846
- return this.#node.navigateTo ? this.$view.$model.view(this.#node.navigateTo) : null;
868
+ return this.$node.navigateTo ? this.$viewModel.$model.view(this.$node.navigateTo) : null;
847
869
  }
848
870
  get style() {
849
- return this.#node.style;
871
+ return this.$node.style;
872
+ }
873
+ get x() {
874
+ return "x" in this.$node ? this.$node.x : void 0;
875
+ }
876
+ get y() {
877
+ return "y" in this.$node ? this.$node.y : void 0;
878
+ }
879
+ get width() {
880
+ return "width" in this.$node ? this.$node.width : void 0;
881
+ }
882
+ get height() {
883
+ return "height" in this.$node ? this.$node.height : void 0;
850
884
  }
851
885
  children() {
852
- return memoizeProp(this, "children", () => new Set(this.#node.children.map((child) => this.$view.node(child))));
886
+ return memoizeProp(this, "children", () => new Set(this.$node.children.map((child) => this.$viewModel.node(child))));
853
887
  }
854
888
  /**
855
889
  * Get all ancestor elements (i.e. parent, parent’s parent, etc.)
@@ -864,7 +898,7 @@ class NodeModel {
864
898
  return;
865
899
  }
866
900
  *siblings() {
867
- const siblings = this.parent?.children() ?? this.$view.roots();
901
+ const siblings = this.parent?.children() ?? this.$viewModel.roots();
868
902
  for (const sibling of siblings) {
869
903
  if (sibling.id !== this.id) {
870
904
  yield sibling;
@@ -873,8 +907,8 @@ class NodeModel {
873
907
  return;
874
908
  }
875
909
  *incoming(filter = "all") {
876
- for (const edgeId of this.#node.inEdges) {
877
- const edge = this.$view.edge(edgeId);
910
+ for (const edgeId of this.$node.inEdges) {
911
+ const edge = this.$viewModel.edge(edgeId);
878
912
  switch (true) {
879
913
  case filter === "all":
880
914
  case (filter === "direct" && edge.target.id === this.id):
@@ -897,8 +931,8 @@ class NodeModel {
897
931
  return;
898
932
  }
899
933
  *outgoing(filter = "all") {
900
- for (const edgeId of this.#node.outEdges) {
901
- const edge = this.$view.edge(edgeId);
934
+ for (const edgeId of this.$node.outEdges) {
935
+ const edge = this.$viewModel.edge(edgeId);
902
936
  switch (true) {
903
937
  case filter === "all":
904
938
  case (filter === "direct" && edge.source.id === this.id):
@@ -920,26 +954,26 @@ class NodeModel {
920
954
  }
921
955
  return;
922
956
  }
923
- isDiagramNode() {
924
- return "width" in this.#node && "height" in this.#node;
957
+ isLayouted() {
958
+ return "width" in this.$node && "height" in this.$node;
925
959
  }
926
960
  hasChildren() {
927
- return this.#node.children.length > 0;
961
+ return this.$node.children.length > 0;
928
962
  }
929
963
  hasParent() {
930
- return this.#node.parent !== null;
964
+ return this.$node.parent !== null;
931
965
  }
932
966
  /**
933
967
  * Check if this node references to logical model element.
934
968
  */
935
969
  hasElement() {
936
- return e$3(this.#node.modelRef);
970
+ return e$1(this.$node.modelRef);
937
971
  }
938
972
  /**
939
973
  * Check if this node references to deployment element (Node or Instance).
940
974
  */
941
975
  hasDeployment() {
942
- return e$3(this.#node.deploymentRef);
976
+ return e$1(this.$node.deploymentRef);
943
977
  }
944
978
  /**
945
979
  * Check if this node references to deployed instance
@@ -949,7 +983,7 @@ class NodeModel {
949
983
  return this.hasElement() && this.hasDeployment();
950
984
  }
951
985
  isGroup() {
952
- return isGroupElementKind(this.#node);
986
+ return isGroupElementKind(this.$node);
953
987
  }
954
988
  /**
955
989
  * Checks if the node has the given tag.
@@ -964,6 +998,7 @@ class LikeC4ViewModel {
964
998
  * Don't use in runtime, only for type inference
965
999
  */
966
1000
  Aux;
1001
+ #view;
967
1002
  #rootnodes = /* @__PURE__ */ new Set();
968
1003
  #nodes = /* @__PURE__ */ new Map();
969
1004
  #edges = /* @__PURE__ */ new Map();
@@ -971,8 +1006,15 @@ class LikeC4ViewModel {
971
1006
  #includeDeployments = /* @__PURE__ */ new Set();
972
1007
  #includeRelations = /* @__PURE__ */ new Set();
973
1008
  #allTags = new DefaultMap((_key) => /* @__PURE__ */ new Set());
974
- $view;
1009
+ #manualLayoutSnapshot;
1010
+ id;
1011
+ /**
1012
+ * The model this view belongs to
1013
+ */
975
1014
  $model;
1015
+ /**
1016
+ * The title of the view
1017
+ */
976
1018
  title;
977
1019
  /**
978
1020
  * View folder this view belongs to.
@@ -986,27 +1028,29 @@ class LikeC4ViewModel {
986
1028
  * "Group 1/Group 2/View"
987
1029
  */
988
1030
  viewPath;
989
- constructor(model, view, folder) {
1031
+ constructor(model, folder, view, manualLayoutSnapshot) {
990
1032
  this.$model = model;
991
- this.$view = view;
1033
+ this.#view = view;
1034
+ this.id = view.id;
992
1035
  this.folder = folder;
993
- for (const node of view.nodes) {
1036
+ this.#manualLayoutSnapshot = manualLayoutSnapshot;
1037
+ for (const node of this.#view.nodes) {
994
1038
  const el = new NodeModel(this, Object.freeze(node));
995
1039
  this.#nodes.set(node.id, el);
996
1040
  if (!node.parent) {
997
1041
  this.#rootnodes.add(el);
998
1042
  }
999
- if (el.hasDeployment()) {
1000
- this.#includeDeployments.add(el.deployment.id);
1043
+ if (node.deploymentRef) {
1044
+ this.#includeDeployments.add(node.deploymentRef);
1001
1045
  }
1002
- if (el.hasElement()) {
1003
- this.#includeElements.add(el.element.id);
1046
+ if (node.modelRef) {
1047
+ this.#includeElements.add(node.modelRef);
1004
1048
  }
1005
1049
  for (const tag of el.tags) {
1006
1050
  this.#allTags.get(tag).add(el);
1007
1051
  }
1008
1052
  }
1009
- for (const edge of view.edges) {
1053
+ for (const edge of this.#view.edges) {
1010
1054
  const edgeModel = new EdgeModel(
1011
1055
  this,
1012
1056
  Object.freeze(edge),
@@ -1021,14 +1065,29 @@ class LikeC4ViewModel {
1021
1065
  }
1022
1066
  this.#edges.set(edge.id, edgeModel);
1023
1067
  }
1024
- this.title = this.$view.title ? extractViewTitleFromPath(this.$view.title) : null;
1025
- this.viewPath = this.$view.title ? normalizeViewPath(this.$view.title) : this.$view.id;
1068
+ this.title = view.title ? extractViewTitleFromPath(view.title) : null;
1069
+ this.viewPath = view.title ? normalizeViewPath(view.title) : view.id;
1070
+ }
1071
+ /**
1072
+ * Returns the styles configuration for the project.
1073
+ */
1074
+ get $styles() {
1075
+ return this.$model.$styles;
1026
1076
  }
1027
1077
  get _type() {
1028
- return this.$view[_type];
1078
+ return this.#view[_type];
1029
1079
  }
1030
- get id() {
1031
- return this.$view.id;
1080
+ get stage() {
1081
+ return this.#view[_stage];
1082
+ }
1083
+ get bounds() {
1084
+ if ("bounds" in this.#view) {
1085
+ return this.#view.bounds;
1086
+ }
1087
+ if (this.#manualLayoutSnapshot) {
1088
+ return this.#manualLayoutSnapshot.bounds;
1089
+ }
1090
+ throw new Error("View is not layouted");
1032
1091
  }
1033
1092
  /**
1034
1093
  * Returns title if defined, otherwise returns title of the element it is based on, otherwise returns its {@link id}
@@ -1064,17 +1123,17 @@ class LikeC4ViewModel {
1064
1123
  });
1065
1124
  }
1066
1125
  get description() {
1067
- return RichText.memoize(this, "description", this.$view.description);
1126
+ return RichText.memoize(this, "description", this.#view.description);
1068
1127
  }
1069
1128
  get tags() {
1070
- return this.$view.tags ?? [];
1129
+ return this.#view.tags ?? [];
1071
1130
  }
1072
1131
  get links() {
1073
- return this.$view.links ?? [];
1132
+ return this.#view.links ?? [];
1074
1133
  }
1075
1134
  get viewOf() {
1076
1135
  if (this.isElementView()) {
1077
- const viewOf = this.$view.viewOf;
1136
+ const viewOf = this.#view.viewOf;
1078
1137
  return viewOf ? this.$model.element(viewOf) : null;
1079
1138
  }
1080
1139
  return null;
@@ -1085,9 +1144,9 @@ class LikeC4ViewModel {
1085
1144
  */
1086
1145
  get mode() {
1087
1146
  if (this.isDynamicView()) {
1088
- return this.$view.variant ?? "diagram";
1147
+ return this.#view.variant ?? "diagram";
1089
1148
  }
1090
- throw new Error("View is not dynamic");
1149
+ return null;
1091
1150
  }
1092
1151
  /**
1093
1152
  * All tags from nodes and edges.
@@ -1095,6 +1154,58 @@ class LikeC4ViewModel {
1095
1154
  get includedTags() {
1096
1155
  return [...this.#allTags.keys()];
1097
1156
  }
1157
+ /**
1158
+ * The original view from the model.
1159
+ * In case of layouted model, this is the latest auto-layouted view without manual changes applied
1160
+ * @see {@link $layouted} should be used for rendering in the UI
1161
+ */
1162
+ get $view() {
1163
+ if (!this.isLayouted() || "drifts" in this.#view) {
1164
+ return this.#view;
1165
+ }
1166
+ const snapshot = this.#manualLayoutSnapshot;
1167
+ if (snapshot) {
1168
+ return memoizeProp(this, "withDriftReasons", () => {
1169
+ return calcDriftsFromSnapshot(this.#view, snapshot);
1170
+ });
1171
+ }
1172
+ return this.#view;
1173
+ }
1174
+ /**
1175
+ * Returns the view with manual layout applied if it exists, otherwise returns the original view
1176
+ * This should be used for rendering in the UI
1177
+ */
1178
+ get $layouted() {
1179
+ if (!this.isLayouted()) {
1180
+ throw new Error("View is not layouted");
1181
+ }
1182
+ return this.$manual ?? this.#view;
1183
+ }
1184
+ get hasManualLayout() {
1185
+ return this.#manualLayoutSnapshot !== void 0;
1186
+ }
1187
+ get hasLayoutDrifts() {
1188
+ if (!this.isLayouted()) {
1189
+ return false;
1190
+ }
1191
+ const manualLayout = this.$manual;
1192
+ return !!manualLayout?.drifts && manualLayout.drifts.length > 0;
1193
+ }
1194
+ /**
1195
+ * If view has manual layout, returns it with manual layout applied
1196
+ */
1197
+ get $manual() {
1198
+ if (!this.isLayouted()) {
1199
+ return null;
1200
+ }
1201
+ const snapshot = this.#manualLayoutSnapshot;
1202
+ if (snapshot) {
1203
+ return memoizeProp(this, "snapshotWithManualLayout", () => {
1204
+ return applyManualLayout(this.#view, snapshot);
1205
+ });
1206
+ }
1207
+ return null;
1208
+ }
1098
1209
  roots() {
1099
1210
  return this.#rootnodes.values();
1100
1211
  }
@@ -1115,7 +1226,7 @@ class LikeC4ViewModel {
1115
1226
  */
1116
1227
  node(node) {
1117
1228
  const nodeId = getId(node);
1118
- return nonNullable(this.#nodes.get(nodeId), `Node ${nodeId} not found in view ${this.$view.id}`);
1229
+ return nonNullable(this.#nodes.get(nodeId), `Node ${nodeId} not found in view ${this.#view.id}`);
1119
1230
  }
1120
1231
  /**
1121
1232
  * Find node by id.
@@ -1125,6 +1236,9 @@ class LikeC4ViewModel {
1125
1236
  }
1126
1237
  findNodeWithElement(element) {
1127
1238
  const id = getId(element);
1239
+ if (!this.#includeElements.has(id)) {
1240
+ return null;
1241
+ }
1128
1242
  return ifind(
1129
1243
  this.#nodes.values(),
1130
1244
  (node) => node.hasElement() && node.element.id === id
@@ -1145,7 +1259,7 @@ class LikeC4ViewModel {
1145
1259
  */
1146
1260
  edge(edge) {
1147
1261
  const edgeId = getId(edge);
1148
- return nonNullable(this.#edges.get(edgeId), `Edge ${edgeId} not found in view ${this.$view.id}`);
1262
+ return nonNullable(this.#edges.get(edgeId), `Edge ${edgeId} not found in view ${this.#view.id}`);
1149
1263
  }
1150
1264
  /**
1151
1265
  * Find edge by id.
@@ -1202,22 +1316,28 @@ class LikeC4ViewModel {
1202
1316
  * Below are type guards.
1203
1317
  */
1204
1318
  isComputed() {
1205
- return this.$view[_stage] === "computed";
1319
+ return this.#view[_stage] === "computed";
1320
+ }
1321
+ isLayouted() {
1322
+ return this.#view[_stage] === "layouted";
1206
1323
  }
1324
+ /**
1325
+ * @deprecated Use {@link isLayouted} instead
1326
+ */
1207
1327
  isDiagram() {
1208
- return this.$view[_stage] === "layouted";
1328
+ return this.#view[_stage] === "layouted";
1209
1329
  }
1210
1330
  isElementView() {
1211
- return this.$view[_type] === "element";
1331
+ return this.#view[_type] === "element";
1212
1332
  }
1213
1333
  isScopedElementView() {
1214
- return this.$view[_type] === "element" && e$3(this.$view.viewOf);
1334
+ return this.#view[_type] === "element" && e$1(this.#view.viewOf);
1215
1335
  }
1216
1336
  isDeploymentView() {
1217
- return this.$view[_type] === "deployment";
1337
+ return this.#view[_type] === "deployment";
1218
1338
  }
1219
1339
  isDynamicView() {
1220
- return this.$view[_type] === "dynamic";
1340
+ return this.#view[_type] === "dynamic";
1221
1341
  }
1222
1342
  }
1223
1343
 
@@ -1253,7 +1373,7 @@ class LikeC4ViewsFolder {
1253
1373
  this.$model = $model;
1254
1374
  this.path = path.join("/");
1255
1375
  this.isRoot = this.path === "";
1256
- this.title = t$4(path);
1376
+ this.title = t$1(path);
1257
1377
  if (this.isRoot) {
1258
1378
  this.parentPath = void 0;
1259
1379
  } else {
@@ -1308,7 +1428,7 @@ class LikeC4ViewsFolder {
1308
1428
  */
1309
1429
  get parent() {
1310
1430
  invariant(!this.isRoot, "Root view folder has no parent");
1311
- if (e$4(this.parentPath)) {
1431
+ if (e$2(this.parentPath)) {
1312
1432
  return null;
1313
1433
  }
1314
1434
  return this.$model.viewFolder(this.parentPath);
@@ -1372,14 +1492,10 @@ class LikeC4Model {
1372
1492
  _views = /* @__PURE__ */ new Map();
1373
1493
  _rootViewFolder;
1374
1494
  _viewFolders = /* @__PURE__ */ new Map();
1375
- _viewFolderItems = new DefaultMap(
1376
- () => /* @__PURE__ */ new Set()
1377
- );
1378
- _allTags = new DefaultMap(
1379
- () => /* @__PURE__ */ new Set()
1380
- );
1495
+ _viewFolderItems = new DefaultMap(() => /* @__PURE__ */ new Set());
1496
+ _allTags = new DefaultMap(() => /* @__PURE__ */ new Set());
1381
1497
  static fromParsed(model) {
1382
- return new LikeC4Model(model).asParsed;
1498
+ return new LikeC4Model(model);
1383
1499
  }
1384
1500
  static create(model) {
1385
1501
  return new LikeC4Model(model);
@@ -1429,13 +1545,13 @@ class LikeC4Model {
1429
1545
  $data;
1430
1546
  constructor($data) {
1431
1547
  this.$data = $data;
1432
- for (const [, element] of t$6($data.elements)) {
1548
+ for (const [, element] of t$5($data.elements)) {
1433
1549
  const el = this.addElement(element);
1434
1550
  for (const tag of el.tags) {
1435
1551
  this._allTags.get(tag).add(el);
1436
1552
  }
1437
1553
  }
1438
- for (const [projectId, elements] of t$6($data.imports ?? {})) {
1554
+ for (const [projectId, elements] of t$5($data.imports ?? {})) {
1439
1555
  for (const element of sortParentsFirst(elements)) {
1440
1556
  const el = this.addImportedElement(projectId, element);
1441
1557
  for (const tag of el.tags) {
@@ -1452,21 +1568,21 @@ class LikeC4Model {
1452
1568
  this.deployment = new LikeC4DeploymentModel(this);
1453
1569
  if (isOnStage($data, "computed") || isOnStage($data, "layouted")) {
1454
1570
  const compare = compareNaturalHierarchically(VIEW_FOLDERS_SEPARATOR);
1455
- const views = t$a(
1571
+ const views = t$6(
1456
1572
  t($data.views),
1457
- t$b((view) => ({
1573
+ t$8((view) => ({
1458
1574
  view,
1459
1575
  path: normalizeViewPath(view.title ?? view.id),
1460
1576
  folderPath: view.title && getViewFolderPath(view.title) || ""
1461
1577
  })),
1462
1578
  // Sort hierarchically by groups, but keep same order within groups
1463
- t$2((a, b) => compare(a.folderPath, b.folderPath))
1579
+ t$7((a, b) => compare(a.folderPath, b.folderPath))
1464
1580
  );
1465
1581
  const getOrCreateFolder = (path) => {
1466
1582
  let folder = this._viewFolders.get(path);
1467
1583
  if (!folder) {
1468
1584
  const segments = e(path, VIEW_FOLDERS_SEPARATOR);
1469
- invariant(t$9(segments, 1), `View group path "${path}" must have at least one element`);
1585
+ invariant(t$4(segments, 1), `View group path "${path}" must have at least one element`);
1470
1586
  let defaultView;
1471
1587
  if (path === "") {
1472
1588
  defaultView = views.find((view) => view.view.id === "index");
@@ -1485,7 +1601,7 @@ class LikeC4Model {
1485
1601
  }
1486
1602
  e(folderPath, VIEW_FOLDERS_SEPARATOR).reduce((segments, segment) => {
1487
1603
  const parent = segments.join(VIEW_FOLDERS_SEPARATOR);
1488
- const path = e$4(parent) ? segment : parent + VIEW_FOLDERS_SEPARATOR + segment;
1604
+ const path = e$2(parent) ? segment : parent + VIEW_FOLDERS_SEPARATOR + segment;
1489
1605
  const folder = getOrCreateFolder(path);
1490
1606
  this._viewFolderItems.get(parent).add(folder);
1491
1607
  segments.push(segment);
@@ -1493,7 +1609,12 @@ class LikeC4Model {
1493
1609
  }, []);
1494
1610
  }
1495
1611
  for (const { view, folderPath } of views) {
1496
- const vm = new LikeC4ViewModel(this, view, getOrCreateFolder(folderPath));
1612
+ const vm = new LikeC4ViewModel(
1613
+ this,
1614
+ getOrCreateFolder(folderPath),
1615
+ view,
1616
+ $data.manualLayouts?.[view.id]
1617
+ );
1497
1618
  this._viewFolderItems.get(folderPath).add(vm);
1498
1619
  this._views.set(view.id, vm);
1499
1620
  for (const tag of vm.tags) {
@@ -1709,6 +1830,16 @@ class LikeC4Model {
1709
1830
  findView(viewId) {
1710
1831
  return this._views.get(viewId) ?? null;
1711
1832
  }
1833
+ /**
1834
+ * Returns manual layout snapshot for given view ID, if any.
1835
+ */
1836
+ findManualLayout(viewId) {
1837
+ if ("manualLayouts" in this.$data) {
1838
+ const view = this.$data.manualLayouts?.[viewId];
1839
+ return view ?? null;
1840
+ }
1841
+ return null;
1842
+ }
1712
1843
  /**
1713
1844
  * Returns a view folder by its path.
1714
1845
  * Path is extracted from the view title, e.g. "Group 1/Group 2/View" -> "Group 1/Group 2"
@@ -1832,22 +1963,22 @@ class LikeC4Model {
1832
1963
  * Use {@link specification.tags} to get all defined tags
1833
1964
  */
1834
1965
  get tags() {
1835
- return memoizeProp(this, "tags", () => t$2([...this._allTags.keys()], compareNatural));
1966
+ return memoizeProp(this, "tags", () => t$7([...this._allTags.keys()], compareNatural));
1836
1967
  }
1837
1968
  /**
1838
1969
  * Returns all tags used in the model, sorted by usage count (descending).
1839
1970
  */
1840
1971
  get tagsSortedByUsage() {
1841
- return memoizeProp(this, "tagsSortedByUsage", () => t$a(
1972
+ return memoizeProp(this, "tagsSortedByUsage", () => t$6(
1842
1973
  [...this._allTags.entries()],
1843
- t$b(([tag, tagged]) => ({
1974
+ t$8(([tag, tagged]) => ({
1844
1975
  tag,
1845
1976
  count: tagged.size,
1846
1977
  tagged
1847
1978
  })),
1848
- t$2((a, b) => compareNatural(a.tag, b.tag)),
1849
- t$1(
1850
- [e$1("count"), "desc"]
1979
+ t$7((a, b) => compareNatural(a.tag, b.tag)),
1980
+ t$9(
1981
+ [e$3("count"), "desc"]
1851
1982
  )
1852
1983
  ));
1853
1984
  }
@@ -2063,4 +2194,4 @@ function isEdgeModel(edge) {
2063
2194
  return edge instanceof EdgeModel;
2064
2195
  }
2065
2196
 
2066
- export { ElementModel as E, LikeC4Model as L, NodeModel as N, RelationshipModel as R, VIEW_FOLDERS_SEPARATOR as V, t$6 as a, t$1 as b, t$4 as c, isNestedElementOfDeployedInstanceModel as d, e$1 as e, isDeployedInstanceModel as f, isDeploymentNodeModel as g, isDeploymentElementModel as h, isElementModel as i, LikeC4DeploymentModel as j, EdgeModel as k, LikeC4ViewModel as l, LikeC4ViewsFolder as m, extractViewTitleFromPath as n, getViewFolderPath as o, normalizeViewPath as p, isDeploymentRelationModel as q, isRelationModel as r, isLikeC4ViewModel as s, t, isNodeModel as u, isEdgeModel as v };
2197
+ export { ElementModel as E, LikeC4Model as L, NodeModel as N, RelationshipModel as R, VIEW_FOLDERS_SEPARATOR as V, t$1 as a, isNestedElementOfDeployedInstanceModel as b, isDeployedInstanceModel as c, isDeploymentNodeModel as d, isDeploymentElementModel as e, LikeC4DeploymentModel as f, EdgeModel as g, LikeC4ViewModel as h, isElementModel as i, LikeC4ViewsFolder as j, extractViewTitleFromPath as k, getViewFolderPath as l, isDeploymentRelationModel as m, normalizeViewPath as n, isRelationModel as o, isLikeC4ViewModel as p, isNodeModel as q, isEdgeModel as r, t };