@likec4/core 1.47.0 → 1.48.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 (181) hide show
  1. package/LICENSE +1 -1
  2. package/dist/_chunks/Builder.view-element.mjs +3284 -0
  3. package/dist/_chunks/LikeC4Model.d.mts +1287 -0
  4. package/dist/_chunks/LikeC4Styles.mjs +691 -0
  5. package/dist/_chunks/RichText.d.mts +84 -0
  6. package/dist/_chunks/RichText.mjs +148 -0
  7. package/dist/_chunks/_aux.d.mts +289 -0
  8. package/dist/_chunks/_aux.mjs +18 -0
  9. package/dist/_chunks/_types.d.mts +781 -0
  10. package/dist/_chunks/_types2.d.mts +38 -0
  11. package/dist/_chunks/assignTagColors.mjs +24 -0
  12. package/dist/_chunks/calcDriftsFromSnapshot.mjs +379 -0
  13. package/dist/_chunks/connection.mjs +0 -0
  14. package/dist/_chunks/const.d.mts +43 -0
  15. package/dist/_chunks/const.mjs +33 -0
  16. package/dist/_chunks/expression-model.d.mts +192 -0
  17. package/dist/_chunks/expression-model.mjs +103 -0
  18. package/dist/_chunks/expression.d.mts +347 -0
  19. package/dist/_chunks/expression.mjs +107 -0
  20. package/dist/_chunks/find.d.mts +82 -0
  21. package/dist/_chunks/find.mjs +646 -0
  22. package/dist/_chunks/find2.d.mts +78 -0
  23. package/dist/_chunks/find2.mjs +287 -0
  24. package/dist/_chunks/fqnRef.d.mts +58 -0
  25. package/dist/_chunks/fqnRef.mjs +41 -0
  26. package/dist/_chunks/geometry.mjs +335 -0
  27. package/dist/_chunks/index.d.mts +169 -0
  28. package/dist/_chunks/index2.d.mts +937 -0
  29. package/dist/_chunks/index3.d.mts +146 -0
  30. package/dist/_chunks/index4.d.mts +62 -0
  31. package/dist/_chunks/index5.d.mts +42 -0
  32. package/dist/_chunks/index6.d.mts +43 -0
  33. package/dist/{shared/core.OtRNdMxy.d.mts → _chunks/index7.d.mts} +113 -197
  34. package/dist/_chunks/index8.d.mts +144 -0
  35. package/dist/_chunks/invariant.mjs +18 -0
  36. package/dist/_chunks/iterable.mjs +146 -0
  37. package/dist/_chunks/libs/@mantine/colors-generator.mjs +3416 -0
  38. package/dist/_chunks/libs/@ungap/structured-clone.mjs +213 -0
  39. package/dist/_chunks/libs/bail.mjs +14 -0
  40. package/dist/_chunks/libs/ccount.mjs +25 -0
  41. package/dist/_chunks/libs/character-entities-html4.mjs +263 -0
  42. package/dist/_chunks/libs/character-entities-legacy.mjs +117 -0
  43. package/dist/_chunks/libs/character-entities.mjs +2136 -0
  44. package/dist/_chunks/libs/comma-separated-tokens.mjs +18 -0
  45. package/dist/_chunks/libs/decode-named-character-reference.mjs +21 -0
  46. package/dist/_chunks/libs/defu.mjs +42 -0
  47. package/dist/_chunks/libs/devlop.mjs +5 -0
  48. package/dist/_chunks/libs/escape-string-regexp.mjs +8 -0
  49. package/dist/_chunks/libs/extend.mjs +77 -0
  50. package/dist/_chunks/libs/graphology-dag.mjs +703 -0
  51. package/dist/_chunks/libs/graphology-types.d.mts +601 -0
  52. package/dist/_chunks/libs/graphology.d.mts +6 -0
  53. package/dist/_chunks/libs/graphology.mjs +4565 -0
  54. package/dist/_chunks/libs/hast-util-sanitize.mjs +863 -0
  55. package/dist/_chunks/libs/hast-util-to-html.mjs +2696 -0
  56. package/dist/_chunks/libs/is-plain-obj.mjs +9 -0
  57. package/dist/_chunks/libs/longest-streak.mjs +30 -0
  58. package/dist/_chunks/libs/markdown-table.mjs +290 -0
  59. package/dist/_chunks/libs/mdast-util-find-and-replace.mjs +653 -0
  60. package/dist/_chunks/libs/mdast-util-from-markdown.mjs +8522 -0
  61. package/dist/_chunks/libs/mdast-util-gfm.mjs +2393 -0
  62. package/dist/_chunks/libs/mdast-util-to-hast.mjs +1803 -0
  63. package/dist/_chunks/libs/micromark-extension-gfm.mjs +2243 -0
  64. package/dist/_chunks/libs/mnemonist.d.mts +254 -0
  65. package/dist/_chunks/libs/mnemonist.mjs +1978 -0
  66. package/dist/_chunks/libs/natural-compare-lite.mjs +42 -0
  67. package/dist/_chunks/libs/rehype-sanitize.mjs +29 -0
  68. package/dist/_chunks/libs/rehype-stringify.mjs +34 -0
  69. package/dist/_chunks/libs/remark-gfm.mjs +36 -0
  70. package/dist/_chunks/libs/remark-github-blockquote-alert.mjs +100 -0
  71. package/dist/_chunks/libs/remark-parse.mjs +39 -0
  72. package/dist/_chunks/libs/remark-rehype.mjs +171 -0
  73. package/dist/_chunks/libs/remeda.mjs +702 -0
  74. package/dist/_chunks/libs/trough.mjs +158 -0
  75. package/dist/_chunks/libs/unified.mjs +2212 -0
  76. package/dist/_chunks/mnemonist.d.mts +1 -0
  77. package/dist/_chunks/mnemonist.mjs +0 -0
  78. package/dist/_chunks/model.mjs +1898 -0
  79. package/dist/_chunks/model2.mjs +0 -0
  80. package/dist/_chunks/relationships-view.mjs +132 -0
  81. package/dist/_chunks/rolldown-runtime.mjs +42 -0
  82. package/dist/{shared/core.C_3y3eqV.d.mts → _chunks/scalar.d.mts} +13 -43
  83. package/dist/_chunks/scalar.mjs +84 -0
  84. package/dist/_chunks/utils.mjs +483 -0
  85. package/dist/builder/index.d.mts +11 -775
  86. package/dist/builder/index.mjs +631 -1022
  87. package/dist/compute-view/index.d.mts +85 -56
  88. package/dist/compute-view/index.mjs +247 -214
  89. package/dist/compute-view/relationships-view/index.d.mts +16 -51
  90. package/dist/compute-view/relationships-view/index.mjs +6 -184
  91. package/dist/geometry/index.d.mts +2 -109
  92. package/dist/geometry/index.mjs +2 -327
  93. package/dist/index.d.mts +18 -20
  94. package/dist/index.mjs +27 -18
  95. package/dist/model/connection/deployment/index.d.mts +12 -15
  96. package/dist/model/connection/deployment/index.mjs +9 -2
  97. package/dist/model/connection/index.d.mts +14 -75
  98. package/dist/model/connection/index.mjs +10 -3
  99. package/dist/model/connection/model/index.d.mts +12 -15
  100. package/dist/model/connection/model/index.mjs +8 -2
  101. package/dist/model/index.d.mts +15 -57
  102. package/dist/model/index.mjs +11 -4
  103. package/dist/styles/index.d.mts +9 -117
  104. package/dist/styles/index.mjs +26 -59
  105. package/dist/types/RichText.d.mts +3 -0
  106. package/dist/types/RichText.mjs +7 -0
  107. package/dist/types/_aux.d.mts +3 -4
  108. package/dist/types/_aux.mjs +2 -7
  109. package/dist/types/expression-model.d.mts +6 -190
  110. package/dist/types/expression-model.mjs +6 -108
  111. package/dist/types/expression.d.mts +5 -6
  112. package/dist/types/expression.mjs +6 -112
  113. package/dist/types/fqnRef.d.mts +4 -60
  114. package/dist/types/fqnRef.mjs +6 -44
  115. package/dist/types/index.d.mts +9 -47
  116. package/dist/types/index.mjs +14 -16
  117. package/dist/types/scalar.d.mts +2 -2
  118. package/dist/types/scalar.mjs +7 -4
  119. package/dist/utils/graphology/index.d.mts +2 -1864
  120. package/dist/utils/graphology/index.mjs +3 -1
  121. package/dist/utils/index.d.mts +11 -124
  122. package/dist/utils/index.mjs +16 -43
  123. package/dist/utils/iterable/index.d.mts +9 -132
  124. package/dist/utils/iterable/index.mjs +2 -61
  125. package/dist/utils/mnemonist.d.mts +2 -0
  126. package/dist/utils/mnemonist.mjs +12 -0
  127. package/package.json +17 -22
  128. package/compute-view/relationships/package.json +0 -4
  129. package/dist/shared/core.3ZhnKAlZ.mjs +0 -106
  130. package/dist/shared/core.78IWAHAE.mjs +0 -332
  131. package/dist/shared/core.B85MJLTf.mjs +0 -5
  132. package/dist/shared/core.BFd1lU9R.mjs +0 -29
  133. package/dist/shared/core.BKlholso.mjs +0 -3
  134. package/dist/shared/core.BNN-3vPH.mjs +0 -1255
  135. package/dist/shared/core.BPGOjone.d.mts +0 -46
  136. package/dist/shared/core.BP_QHEXs.mjs +0 -785
  137. package/dist/shared/core.BbE4y-yl.mjs +0 -177
  138. package/dist/shared/core.Bdy3hhTc.mjs +0 -28382
  139. package/dist/shared/core.BfCKSW-g.d.mts +0 -1266
  140. package/dist/shared/core.BhNcrwzK.mjs +0 -7
  141. package/dist/shared/core.BkVA6gjl.mjs +0 -5
  142. package/dist/shared/core.BoYfZOBm.mjs +0 -3
  143. package/dist/shared/core.BsSXS-_R.mjs +0 -7
  144. package/dist/shared/core.C3JowhaZ.mjs +0 -32
  145. package/dist/shared/core.C4x8aaWa.mjs +0 -27
  146. package/dist/shared/core.CAgYpDtM.d.mts +0 -98
  147. package/dist/shared/core.CHf8VEa3.mjs +0 -1206
  148. package/dist/shared/core.CLSZtnFh.mjs +0 -69
  149. package/dist/shared/core.CbT8JVYL.mjs +0 -5
  150. package/dist/shared/core.CdNCAwq7.mjs +0 -176
  151. package/dist/shared/core.CmGY9blO.mjs +0 -6717
  152. package/dist/shared/core.CmPXpJ8l.mjs +0 -21
  153. package/dist/shared/core.Coi_LOUZ.mjs +0 -7
  154. package/dist/shared/core.CqAJJpK_.mjs +0 -3
  155. package/dist/shared/core.CywrQs86.d.mts +0 -31
  156. package/dist/shared/core.D00YbOhQ.d.mts +0 -300
  157. package/dist/shared/core.D0WZutNd.mjs +0 -94
  158. package/dist/shared/core.D4npX2q8.mjs +0 -18
  159. package/dist/shared/core.DB0Ue5Wx.d.mts +0 -70
  160. package/dist/shared/core.DC5IAaDT.d.mts +0 -334
  161. package/dist/shared/core.DE9qzhn8.d.mts +0 -83
  162. package/dist/shared/core.DGcIbsj4.mjs +0 -3946
  163. package/dist/shared/core.DH7TXqXf.mjs +0 -136
  164. package/dist/shared/core.DKhRkHRN.d.mts +0 -41
  165. package/dist/shared/core.DRJma0Ol.mjs +0 -22
  166. package/dist/shared/core.DU5SRqNF.mjs +0 -2209
  167. package/dist/shared/core.DXhDWKFZ.d.mts +0 -3
  168. package/dist/shared/core.DbfO90vF.mjs +0 -434
  169. package/dist/shared/core.DcS-0zys.mjs +0 -10
  170. package/dist/shared/core.Dh119QSP.mjs +0 -4995
  171. package/dist/shared/core.DjcWextK.mjs +0 -1371
  172. package/dist/shared/core.Dojz4bvg.d.mts +0 -504
  173. package/dist/shared/core.FZ305VYd.mjs +0 -21
  174. package/dist/shared/core.RfnaEmgA.mjs +0 -7
  175. package/dist/shared/core.btEq3i3f.mjs +0 -300
  176. package/dist/shared/core.oSV6SRfk.mjs +0 -13
  177. package/dist/shared/core.om36dXXW.mjs +0 -41
  178. package/dist/shared/core.osFs8tU7.d.mts +0 -466
  179. package/dist/shared/core.q10OP9oJ.mjs +0 -5
  180. package/dist/shared/core.tpvDGvdC.d.mts +0 -87
  181. package/dist/shared/core.uFk_o9X6.mjs +0 -13
@@ -1,2209 +0,0 @@
1
- import { t as t$3, e as e$3, a as DeploymentNodeModel, b as DeployedInstanceModel, c as DeploymentRelationModel, N as NestedElementOfDeployedInstanceModel } from './core.BP_QHEXs.mjs';
2
- import { e as e$2 } from './core.BKlholso.mjs';
3
- import { n as n$1 } from './core.BhNcrwzK.mjs';
4
- import { c as splitGlobalFqn, h as extractStep, g as isStepEdgeId, i as isGroupElementKind, b as isGlobalFqn, a as GlobalFqn } from './core.D0WZutNd.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
- import { m as memoizeProp } from './core.CLSZtnFh.mjs';
7
- import { R as RichText, e as exact } from './core.CHf8VEa3.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$4 } 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.DjcWextK.mjs';
16
- import { L as LikeC4Styles } from './core.DGcIbsj4.mjs';
17
- import { g as getOrCreate } from './core.DcS-0zys.mjs';
18
- import { D as DefaultMap } from './core.BbE4y-yl.mjs';
19
- import { i as invariant, a as nonNullable } from './core.D4npX2q8.mjs';
20
- import { FqnRef } from '../types/fqnRef.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';
23
- import { i as ifilter } from './core.DRJma0Ol.mjs';
24
- import './core.BFd1lU9R.mjs';
25
- import './core.78IWAHAE.mjs';
26
-
27
- function e$1(e){if(e==null||e===``)return true;if(typeof e!=`object`)return false;if(`length`in e&&typeof e.length==`number`)return e.length===0;if(`size`in e&&typeof e.size==`number`)return e.size===0;for(let t in e)return false;return Object.getOwnPropertySymbols(e).length===0}
28
-
29
- function t$1(...t){return t$2(n,t)}const n=e=>e.at(-1);
30
-
31
- function e(e,t,n){return typeof t==`number`||t===void 0?n=>n.split(e,t):e.split(t,n)}
32
-
33
- function t(...t){return t$2(Object.values,t)}
34
-
35
- class ElementModel {
36
- constructor($model, $element) {
37
- this.$model = $model;
38
- this.$element = $element;
39
- this.id = this.$element.id;
40
- this._literalId = this.$element.id;
41
- const [projectId, fqn] = splitGlobalFqn(this.id);
42
- if (projectId) {
43
- this.imported = {
44
- from: projectId,
45
- fqn
46
- };
47
- this.hierarchyLevel = hierarchyLevel(fqn);
48
- } else {
49
- this.imported = null;
50
- this.hierarchyLevel = hierarchyLevel(this.id);
51
- }
52
- }
53
- /**
54
- * Don't use in runtime, only for type inference
55
- */
56
- Aux;
57
- id;
58
- _literalId;
59
- hierarchyLevel;
60
- imported;
61
- get name() {
62
- return nameFromFqn(this.id);
63
- }
64
- get parent() {
65
- return this.$model.parent(this);
66
- }
67
- get kind() {
68
- return this.$element.kind;
69
- }
70
- get shape() {
71
- return this.style.shape;
72
- }
73
- get color() {
74
- return this.style.color;
75
- }
76
- get icon() {
77
- return this.style.icon ?? null;
78
- }
79
- /**
80
- * Returns all tags of the element.
81
- * It includes tags from the element and its kind.
82
- */
83
- get tags() {
84
- return memoizeProp(this, /* @__PURE__ */ Symbol.for("tags"), () => {
85
- return n$1([
86
- ...this.$element.tags ?? [],
87
- ...this.$model.specification.elements[this.$element.kind]?.tags ?? []
88
- ]);
89
- });
90
- }
91
- get title() {
92
- return this.$element.title;
93
- }
94
- /**
95
- * Returns true if the element has a summary and a description
96
- * (if one is missing - it falls back to another)
97
- */
98
- get hasSummary() {
99
- return !!this.$element.summary && !!this.$element.description && !t$3(this.$element.summary, this.$element.description);
100
- }
101
- /**
102
- * Short description of the element.
103
- * Falls back to description if summary is not provided.
104
- */
105
- get summary() {
106
- return RichText.memoize(this, "summary", preferSummary(this.$element));
107
- }
108
- /**
109
- * Long description of the element.
110
- * Falls back to summary if description is not provided.
111
- */
112
- get description() {
113
- return RichText.memoize(this, "description", preferDescription(this.$element));
114
- }
115
- get technology() {
116
- return this.$element.technology ?? null;
117
- }
118
- get links() {
119
- return this.$element.links ?? [];
120
- }
121
- get defaultView() {
122
- return memoizeProp(this, /* @__PURE__ */ Symbol.for("defaultView"), () => ihead(this.scopedViews()) ?? null);
123
- }
124
- get isRoot() {
125
- return this.parent === null;
126
- }
127
- get style() {
128
- return memoizeProp(this, "style", () => exact({
129
- shape: this.$model.$styles.defaults.shape,
130
- color: this.$model.$styles.defaults.color,
131
- border: this.$model.$styles.defaults.border,
132
- opacity: this.$model.$styles.defaults.opacity,
133
- size: this.$model.$styles.defaults.size,
134
- padding: this.$model.$styles.defaults.padding,
135
- textSize: this.$model.$styles.defaults.text,
136
- ...this.$element.style
137
- }));
138
- }
139
- get projectId() {
140
- return this.imported?.from ?? this.$model.projectId;
141
- }
142
- isAncestorOf(another) {
143
- return isAncestor(this, another);
144
- }
145
- isDescendantOf(another) {
146
- return isAncestor(another, this);
147
- }
148
- /**
149
- * Get all ancestor elements (i.e. parent, parent’s parent, etc.)
150
- * (from closest to root)
151
- */
152
- ancestors() {
153
- return this.$model.ancestors(this);
154
- }
155
- /**
156
- * Returns the common ancestor of this element and another element.
157
- */
158
- commonAncestor(another) {
159
- const common = commonAncestor(this.id, another.id);
160
- return common ? this.$model.element(common) : null;
161
- }
162
- children() {
163
- return this.$model.children(this);
164
- }
165
- /**
166
- * Get all descendant elements (i.e. children, children’s children, etc.)
167
- */
168
- descendants(sort) {
169
- if (sort) {
170
- const sorted = sortNaturalByFqn([...this.$model.descendants(this)], sort);
171
- return sorted[Symbol.iterator]();
172
- }
173
- return this.$model.descendants(this);
174
- }
175
- /**
176
- * Get all sibling (i.e. same parent)
177
- */
178
- siblings() {
179
- return this.$model.siblings(this);
180
- }
181
- /**
182
- * Resolve siblings of the element and its ancestors
183
- * (from closest parent to root)
184
- */
185
- *ascendingSiblings() {
186
- yield* this.siblings();
187
- for (const ancestor of this.ancestors()) {
188
- yield* ancestor.siblings();
189
- }
190
- return;
191
- }
192
- /**
193
- * Resolve siblings of the element and its ancestors
194
- * (from root to closest)
195
- */
196
- *descendingSiblings() {
197
- for (const ancestor of [...this.ancestors()].reverse()) {
198
- yield* ancestor.siblings();
199
- }
200
- yield* this.siblings();
201
- return;
202
- }
203
- incoming(filter = "all") {
204
- return this.$model.incoming(this, filter);
205
- }
206
- *incomers(filter = "all") {
207
- const unique2 = /* @__PURE__ */ new Set();
208
- for (const r of this.incoming(filter)) {
209
- if (unique2.has(r.source.id)) {
210
- continue;
211
- }
212
- unique2.add(r.source.id);
213
- yield r.source;
214
- }
215
- return;
216
- }
217
- outgoing(filter = "all") {
218
- return this.$model.outgoing(this, filter);
219
- }
220
- *outgoers(filter = "all") {
221
- const unique2 = /* @__PURE__ */ new Set();
222
- for (const r of this.outgoing(filter)) {
223
- if (unique2.has(r.target.id)) {
224
- continue;
225
- }
226
- unique2.add(r.target.id);
227
- yield r.target;
228
- }
229
- return;
230
- }
231
- get allOutgoing() {
232
- return memoizeProp(this, /* @__PURE__ */ Symbol.for("allOutgoing"), () => new Set(this.outgoing()));
233
- }
234
- get allIncoming() {
235
- return memoizeProp(this, /* @__PURE__ */ Symbol.for("allIncoming"), () => new Set(this.incoming()));
236
- }
237
- /**
238
- * Iterate over all views that include this element.
239
- */
240
- views() {
241
- return memoizeProp(this, /* @__PURE__ */ Symbol.for("views"), () => {
242
- const views = /* @__PURE__ */ new Set();
243
- for (const view of this.$model.views()) {
244
- if (view.includesElement(this.id)) {
245
- views.add(view);
246
- }
247
- }
248
- return views;
249
- });
250
- }
251
- /**
252
- * Iterate over all views that scope this element.
253
- * It is possible that element is not included in the view.
254
- */
255
- scopedViews() {
256
- return memoizeProp(this, /* @__PURE__ */ Symbol.for("scopedViews"), () => {
257
- const views = /* @__PURE__ */ new Set();
258
- for (const vm of this.$model.views()) {
259
- if (vm.isScopedElementView() && vm.viewOf.id === this.id) {
260
- views.add(vm);
261
- }
262
- }
263
- return views;
264
- });
265
- }
266
- /**
267
- * @returns true if the element is deployed
268
- */
269
- isDeployed() {
270
- return e$2(ihead(this.deployments()));
271
- }
272
- deployments() {
273
- return this.$model.deployment.instancesOf(this);
274
- }
275
- hasMetadata() {
276
- return !!this.$element.metadata && !e$3(this.$element.metadata);
277
- }
278
- getMetadata(field) {
279
- if (field) {
280
- return this.$element.metadata?.[field];
281
- }
282
- return this.$element.metadata ?? {};
283
- }
284
- /**
285
- * Checks if the element has the given tag.
286
- */
287
- isTagged(tag) {
288
- return this.tags.includes(tag);
289
- }
290
- }
291
-
292
- const getId = (element) => {
293
- return typeof element === "string" ? element : element.id;
294
- };
295
-
296
- const VIEW_FOLDERS_SEPARATOR = "/";
297
- const splitViewTitle = (title) => {
298
- invariant(!title.includes("\n"), "View title cannot contain newlines");
299
- if (title.includes(VIEW_FOLDERS_SEPARATOR)) {
300
- const segments = title.split(VIEW_FOLDERS_SEPARATOR).map((s) => s.trim()).filter((s) => s.length > 0);
301
- if (t$4(segments, 1)) {
302
- return segments;
303
- }
304
- return [""];
305
- }
306
- return [title.trim()];
307
- };
308
- const normalizeViewPath = (title) => {
309
- return splitViewTitle(title).join(VIEW_FOLDERS_SEPARATOR);
310
- };
311
- const getViewFolderPath = (title) => {
312
- const segments = splitViewTitle(title);
313
- if (!t$4(segments, 2)) {
314
- return null;
315
- }
316
- return segments.slice(0, -1).join(VIEW_FOLDERS_SEPARATOR);
317
- };
318
- const extractViewTitleFromPath = (title) => {
319
- if (!title.includes(VIEW_FOLDERS_SEPARATOR)) {
320
- return title.trim();
321
- }
322
- return splitViewTitle(title).pop() ?? title;
323
- };
324
-
325
- class LikeC4DeploymentModel {
326
- constructor($model) {
327
- this.$model = $model;
328
- const $deployments = this.$deployments = $model.$data.deployments;
329
- const elements = t($deployments.elements);
330
- for (const element of sortParentsFirst(elements)) {
331
- const el = this.addElement(element);
332
- for (const tag of el.tags) {
333
- this.#allTags.get(tag).add(el);
334
- }
335
- if (el.isInstance()) {
336
- this.#instancesOf.get(el.element.id).add(el);
337
- }
338
- }
339
- for (const relation of t($deployments.relations)) {
340
- const el = this.addRelation(relation);
341
- for (const tag of el.tags) {
342
- this.#allTags.get(tag).add(el);
343
- }
344
- }
345
- }
346
- #elements = /* @__PURE__ */ new Map();
347
- // Parent element for given FQN
348
- #parents = /* @__PURE__ */ new Map();
349
- // Children elements for given FQN
350
- #children = new DefaultMap(() => /* @__PURE__ */ new Set());
351
- // Keep track of instances of the logical element
352
- #instancesOf = new DefaultMap(() => /* @__PURE__ */ new Set());
353
- #rootElements = /* @__PURE__ */ new Set();
354
- #relations = /* @__PURE__ */ new Map();
355
- // Incoming to an element or its descendants
356
- #incoming = new DefaultMap(() => /* @__PURE__ */ new Set());
357
- // Outgoing from an element or its descendants
358
- #outgoing = new DefaultMap(() => /* @__PURE__ */ new Set());
359
- // Relationships inside the element, among descendants
360
- #internal = new DefaultMap(() => /* @__PURE__ */ new Set());
361
- // readonly #views = new Map<ViewID, LikeC4ViewModel<A>>()
362
- #allTags = new DefaultMap(
363
- () => /* @__PURE__ */ new Set()
364
- );
365
- #nestedElementsOfDeployment = /* @__PURE__ */ new Map();
366
- $deployments;
367
- get $styles() {
368
- return this.$model.$styles;
369
- }
370
- get projectId() {
371
- return this.$model.projectId;
372
- }
373
- element(el) {
374
- if (el instanceof DeploymentNodeModel || el instanceof DeployedInstanceModel) {
375
- return el;
376
- }
377
- const id = getId(el);
378
- return nonNullable(this.#elements.get(id), `Element ${id} not found`);
379
- }
380
- findElement(el) {
381
- return this.#elements.get(el) ?? null;
382
- }
383
- node(el) {
384
- const element = this.element(el);
385
- invariant(element.isDeploymentNode(), `Element ${element.id} is not a deployment node`);
386
- return element;
387
- }
388
- findNode(el) {
389
- const element = this.findElement(el);
390
- if (!element) {
391
- return null;
392
- }
393
- invariant(element.isDeploymentNode(), `Element ${element?.id} is not a deployment node`);
394
- return element;
395
- }
396
- instance(el) {
397
- const element = this.element(el);
398
- invariant(element.isInstance(), `Element ${element.id} is not a deployed instance`);
399
- return element;
400
- }
401
- findInstance(el) {
402
- const element = this.findElement(el);
403
- if (!element) {
404
- return null;
405
- }
406
- invariant(element.isInstance(), `Element ${element?.id} is not a deployed instance`);
407
- return element;
408
- }
409
- /**
410
- * Returns the root elements of the model.
411
- */
412
- roots() {
413
- return this.#rootElements.values();
414
- }
415
- /**
416
- * Returns all elements in the model.
417
- */
418
- elements() {
419
- return this.#elements.values();
420
- }
421
- /**
422
- * Returns all elements in the model.
423
- */
424
- *nodes() {
425
- for (const element of this.#elements.values()) {
426
- if (element.isDeploymentNode()) {
427
- yield element;
428
- }
429
- }
430
- return;
431
- }
432
- *nodesOfKind(kind) {
433
- for (const node of this.#elements.values()) {
434
- if (node.isDeploymentNode() && node.kind === kind) {
435
- yield node;
436
- }
437
- }
438
- return;
439
- }
440
- *instances() {
441
- for (const element of this.#elements.values()) {
442
- if (element.isInstance()) {
443
- yield element;
444
- }
445
- }
446
- return;
447
- }
448
- /**
449
- * Iterate over all instances of the given logical element.
450
- */
451
- *instancesOf(element) {
452
- const id = getId(element);
453
- const instances = this.#instancesOf.get(id);
454
- if (instances) {
455
- yield* instances;
456
- }
457
- return;
458
- }
459
- deploymentRef(ref) {
460
- if (FqnRef.isInsideInstanceRef(ref)) {
461
- const { deployment, element } = ref;
462
- return getOrCreate(this.#nestedElementsOfDeployment, `${deployment}@${element}`, () => {
463
- return new NestedElementOfDeployedInstanceModel(this.instance(deployment), this.$model.element(element));
464
- });
465
- }
466
- return this.element(ref.deployment);
467
- }
468
- /**
469
- * Returns all relationships in the model.
470
- */
471
- relationships() {
472
- return this.#relations.values();
473
- }
474
- /**
475
- * Returns a specific relationship by its ID.
476
- */
477
- relationship(id) {
478
- const relationId = getId(id);
479
- return nonNullable(this.#relations.get(relationId), `DeploymentRelationModel ${relationId} not found`);
480
- }
481
- findRelationship(id) {
482
- return this.#relations.get(id) ?? null;
483
- }
484
- /**
485
- * Returns all deployment views in the model.
486
- */
487
- *views() {
488
- for (const view of this.$model.views()) {
489
- if (view.isDeploymentView()) {
490
- yield view;
491
- }
492
- }
493
- return;
494
- }
495
- /**
496
- * Returns the parent element of given element.
497
- * @see ancestors
498
- */
499
- parent(element) {
500
- const id = getId(element);
501
- return this.#parents.get(id) || null;
502
- }
503
- /**
504
- * Get all children of the element (only direct children),
505
- * @see descendants
506
- */
507
- children(element) {
508
- const id = getId(element);
509
- return this.#children.get(id);
510
- }
511
- /**
512
- * Get all sibling (i.e. same parent)
513
- */
514
- *siblings(element) {
515
- const id = getId(element);
516
- const siblings = this.parent(element)?.children() ?? this.roots();
517
- for (const sibling of siblings) {
518
- if (sibling.id !== id) {
519
- yield sibling;
520
- }
521
- }
522
- return;
523
- }
524
- /**
525
- * Get all ancestor elements (i.e. parent, parent’s parent, etc.)
526
- * (from closest to root)
527
- */
528
- *ancestors(element) {
529
- let id = getId(element);
530
- let parent;
531
- while (parent = this.#parents.get(id)) {
532
- yield parent;
533
- id = parent.id;
534
- }
535
- return;
536
- }
537
- /**
538
- * Get all descendant elements (i.e. children, children’s children, etc.)
539
- */
540
- *descendants(element, sort = "desc") {
541
- for (const child of this.children(element)) {
542
- if (sort === "asc") {
543
- yield child;
544
- yield* this.descendants(child.id);
545
- } else {
546
- yield* this.descendants(child.id);
547
- yield child;
548
- }
549
- }
550
- return;
551
- }
552
- /**
553
- * Incoming relationships to the element and its descendants
554
- * @see incomers
555
- */
556
- *incoming(element, filter = "all") {
557
- const id = getId(element);
558
- for (const rel of this.#incoming.get(id)) {
559
- switch (true) {
560
- case filter === "all":
561
- case (filter === "direct" && rel.target.id === id):
562
- case (filter === "to-descendants" && rel.target.id !== id):
563
- yield rel;
564
- break;
565
- }
566
- }
567
- return;
568
- }
569
- /**
570
- * Outgoing relationships from the element and its descendants
571
- * @see outgoers
572
- */
573
- *outgoing(element, filter = "all") {
574
- const id = getId(element);
575
- for (const rel of this.#outgoing.get(id)) {
576
- switch (true) {
577
- case filter === "all":
578
- case (filter === "direct" && rel.source.id === id):
579
- case (filter === "from-descendants" && rel.source.id !== id):
580
- yield rel;
581
- break;
582
- }
583
- }
584
- return;
585
- }
586
- addElement(element) {
587
- if (this.#elements.has(element.id)) {
588
- throw new Error(`Element ${element.id} already exists`);
589
- }
590
- const el = isDeploymentNode(element) ? new DeploymentNodeModel(this, Object.freeze(element)) : new DeployedInstanceModel(this, Object.freeze(element), this.$model.element(element.element));
591
- this.#elements.set(el.id, el);
592
- const parentId = parentFqn(el.id);
593
- if (parentId) {
594
- invariant(this.#elements.has(parentId), `Parent ${parentId} of ${el.id} not found`);
595
- this.#parents.set(el.id, this.node(parentId));
596
- this.#children.get(parentId).add(el);
597
- } else {
598
- invariant(el.isDeploymentNode(), `Root element ${el.id} is not a deployment node`);
599
- this.#rootElements.add(el);
600
- }
601
- return el;
602
- }
603
- addRelation(relation) {
604
- if (this.#relations.has(relation.id)) {
605
- throw new Error(`Relation ${relation.id} already exists`);
606
- }
607
- const rel = new DeploymentRelationModel(
608
- this,
609
- Object.freeze(relation)
610
- );
611
- this.#relations.set(rel.id, rel);
612
- this.#incoming.get(rel.target.id).add(rel);
613
- this.#outgoing.get(rel.source.id).add(rel);
614
- const relParent = rel.boundary?.id ?? null;
615
- if (relParent) {
616
- for (const ancestor of [relParent, ...ancestorsFqn(relParent)]) {
617
- this.#internal.get(ancestor).add(rel);
618
- }
619
- }
620
- for (const sourceAncestor of ancestorsFqn(rel.source.id)) {
621
- if (sourceAncestor === relParent) {
622
- break;
623
- }
624
- this.#outgoing.get(sourceAncestor).add(rel);
625
- }
626
- for (const targetAncestor of ancestorsFqn(rel.target.id)) {
627
- if (targetAncestor === relParent) {
628
- break;
629
- }
630
- this.#incoming.get(targetAncestor).add(rel);
631
- }
632
- return rel;
633
- }
634
- }
635
-
636
- class RelationshipModel {
637
- constructor(model, $relationship) {
638
- this.model = model;
639
- this.$relationship = $relationship;
640
- this.source = model.element(FqnRef.flatten($relationship.source));
641
- this.target = model.element(FqnRef.flatten($relationship.target));
642
- const parent = commonAncestor(this.source.id, this.target.id);
643
- this.boundary = parent ? this.model.element(parent) : null;
644
- }
645
- source;
646
- target;
647
- /**
648
- * Common ancestor of the source and target elements.
649
- * Represents the boundary of the Relation.
650
- */
651
- boundary;
652
- get id() {
653
- return this.$relationship.id;
654
- }
655
- get expression() {
656
- return `${this.source.id} -> ${this.target.id}`;
657
- }
658
- get title() {
659
- if (!e$2(this.$relationship.title)) {
660
- return null;
661
- }
662
- return this.$relationship.title;
663
- }
664
- get technology() {
665
- if (!e$2(this.$relationship.technology)) {
666
- return null;
667
- }
668
- return this.$relationship.technology;
669
- }
670
- /**
671
- * Returns true if the relationship has a summary and a description
672
- * (if one is missing - it falls back to another)
673
- */
674
- get hasSummary() {
675
- return !!this.$relationship.summary && !!this.$relationship.description && !t$3(this.$relationship.summary, this.$relationship.description);
676
- }
677
- /**
678
- * Short description of the relationship.
679
- * Falls back to description if summary is not provided.
680
- */
681
- get summary() {
682
- return RichText.memoize(this, "summary", preferSummary(this.$relationship));
683
- }
684
- /**
685
- * Long description of the relationship.
686
- * Falls back to summary if description is not provided.
687
- */
688
- get description() {
689
- return RichText.memoize(this, "description", preferDescription(this.$relationship));
690
- }
691
- get navigateTo() {
692
- return this.$relationship.navigateTo ? this.model.view(this.$relationship.navigateTo) : null;
693
- }
694
- get tags() {
695
- return this.$relationship.tags ?? [];
696
- }
697
- get kind() {
698
- return this.$relationship.kind ?? null;
699
- }
700
- get links() {
701
- return this.$relationship.links ?? [];
702
- }
703
- get color() {
704
- return this.$relationship.color ?? this.model.$styles.defaults.relationship.color;
705
- }
706
- get line() {
707
- return this.$relationship.line ?? this.model.$styles.defaults.relationship.line;
708
- }
709
- get head() {
710
- return this.$relationship.head ?? this.model.$styles.defaults.relationship.arrow;
711
- }
712
- get tail() {
713
- return this.$relationship.tail;
714
- }
715
- /**
716
- * Iterate over all views that include this relationship.
717
- */
718
- *views() {
719
- for (const view of this.model.views()) {
720
- if (view.includesRelation(this.id)) {
721
- yield view;
722
- }
723
- }
724
- return;
725
- }
726
- isDeploymentRelation() {
727
- return false;
728
- }
729
- isModelRelation() {
730
- return true;
731
- }
732
- hasMetadata() {
733
- return !!this.$relationship.metadata && !e$3(this.$relationship.metadata);
734
- }
735
- getMetadata(field) {
736
- if (field) {
737
- return this.$relationship.metadata?.[field];
738
- }
739
- return this.$relationship.metadata ?? {};
740
- }
741
- /**
742
- * Checks if the relationship has the given tag.
743
- */
744
- isTagged(tag) {
745
- return this.tags.includes(tag);
746
- }
747
- }
748
-
749
- class EdgeModel {
750
- constructor($viewModel, $edge, source, target) {
751
- this.source = source;
752
- this.target = target;
753
- this.$viewModel = $viewModel;
754
- this.$view = $viewModel.$view;
755
- this.$edge = $edge;
756
- }
757
- Aux;
758
- $viewModel;
759
- $view;
760
- $edge;
761
- get id() {
762
- return this.$edge.id;
763
- }
764
- get parent() {
765
- return this.$edge.parent ? this.$viewModel.node(this.$edge.parent) : null;
766
- }
767
- get label() {
768
- return this.$edge.label ?? null;
769
- }
770
- get description() {
771
- return RichText.memoize(this, "description", this.$edge.description);
772
- }
773
- get technology() {
774
- return this.$edge.technology ?? null;
775
- }
776
- hasParent() {
777
- return this.$edge.parent !== null;
778
- }
779
- get tags() {
780
- return this.$edge.tags ?? [];
781
- }
782
- get stepNumber() {
783
- return this.isStep() ? extractStep(this.id) : null;
784
- }
785
- get navigateTo() {
786
- return this.$edge.navigateTo ? this.$viewModel.$model.view(this.$edge.navigateTo) : null;
787
- }
788
- get color() {
789
- return this.$edge.color;
790
- }
791
- get line() {
792
- return this.$edge.line ?? this.$viewModel.$styles.defaults.relationship.line;
793
- }
794
- get head() {
795
- return this.$edge.head ?? this.$viewModel.$styles.defaults.relationship.arrow;
796
- }
797
- get tail() {
798
- return this.$edge.tail;
799
- }
800
- isStep() {
801
- return isStepEdgeId(this.id);
802
- }
803
- *relationships(type) {
804
- for (const id of this.$edge.relations) {
805
- if (type) {
806
- const rel = this.$viewModel.$model.findRelationship(id, type);
807
- if (rel) {
808
- yield rel;
809
- }
810
- } else {
811
- yield this.$viewModel.$model.relationship(id);
812
- }
813
- }
814
- return;
815
- }
816
- includesRelation(rel) {
817
- const id = typeof rel === "string" ? rel : rel.id;
818
- return this.$edge.relations.includes(id);
819
- }
820
- isTagged(tag) {
821
- return this.tags.includes(tag);
822
- }
823
- }
824
-
825
- class NodeModel {
826
- Aux;
827
- $viewModel;
828
- $view;
829
- $node;
830
- constructor($viewModel, $node) {
831
- this.$viewModel = $viewModel;
832
- this.$view = $viewModel.$view;
833
- this.$node = $node;
834
- }
835
- get id() {
836
- return this.$node.id;
837
- }
838
- get title() {
839
- return this.$node.title;
840
- }
841
- get kind() {
842
- return this.$node.kind;
843
- }
844
- get description() {
845
- return RichText.memoize(this, "description", this.$node.description);
846
- }
847
- get technology() {
848
- return this.$node.technology ?? null;
849
- }
850
- get parent() {
851
- return this.$node.parent ? this.$viewModel.node(this.$node.parent) : null;
852
- }
853
- get element() {
854
- const modelRef = this.$node.modelRef;
855
- return modelRef ? this.$viewModel.$model.element(modelRef) : null;
856
- }
857
- get deployment() {
858
- const modelRef = this.$node.deploymentRef;
859
- return modelRef ? this.$viewModel.$model.deployment.element(modelRef) : null;
860
- }
861
- get shape() {
862
- return this.$node.shape;
863
- }
864
- get color() {
865
- return this.$node.color;
866
- }
867
- get icon() {
868
- return this.$node.icon ?? null;
869
- }
870
- get tags() {
871
- return this.$node.tags;
872
- }
873
- get links() {
874
- return this.$node.links ?? [];
875
- }
876
- get navigateTo() {
877
- return this.$node.navigateTo ? this.$viewModel.$model.view(this.$node.navigateTo) : null;
878
- }
879
- get style() {
880
- return this.$node.style;
881
- }
882
- get x() {
883
- return "x" in this.$node ? this.$node.x : void 0;
884
- }
885
- get y() {
886
- return "y" in this.$node ? this.$node.y : void 0;
887
- }
888
- get width() {
889
- return "width" in this.$node ? this.$node.width : void 0;
890
- }
891
- get height() {
892
- return "height" in this.$node ? this.$node.height : void 0;
893
- }
894
- children() {
895
- return memoizeProp(this, "children", () => new Set(this.$node.children.map((child) => this.$viewModel.node(child))));
896
- }
897
- /**
898
- * Get all ancestor elements (i.e. parent, parent’s parent, etc.)
899
- * (from closest to root)
900
- */
901
- *ancestors() {
902
- let parent = this.parent;
903
- while (parent) {
904
- yield parent;
905
- parent = parent.parent;
906
- }
907
- return;
908
- }
909
- *siblings() {
910
- const siblings = this.parent?.children() ?? this.$viewModel.roots();
911
- for (const sibling of siblings) {
912
- if (sibling.id !== this.id) {
913
- yield sibling;
914
- }
915
- }
916
- return;
917
- }
918
- *incoming(filter = "all") {
919
- for (const edgeId of this.$node.inEdges) {
920
- const edge = this.$viewModel.edge(edgeId);
921
- switch (true) {
922
- case filter === "all":
923
- case (filter === "direct" && edge.target.id === this.id):
924
- case (filter === "to-descendants" && edge.target.id !== this.id):
925
- yield edge;
926
- break;
927
- }
928
- }
929
- return;
930
- }
931
- *incomers(filter = "all") {
932
- const unique = /* @__PURE__ */ new Set();
933
- for (const r of this.incoming(filter)) {
934
- if (unique.has(r.source.id)) {
935
- continue;
936
- }
937
- unique.add(r.source.id);
938
- yield r.source;
939
- }
940
- return;
941
- }
942
- *outgoing(filter = "all") {
943
- for (const edgeId of this.$node.outEdges) {
944
- const edge = this.$viewModel.edge(edgeId);
945
- switch (true) {
946
- case filter === "all":
947
- case (filter === "direct" && edge.source.id === this.id):
948
- case (filter === "from-descendants" && edge.source.id !== this.id):
949
- yield edge;
950
- break;
951
- }
952
- }
953
- return;
954
- }
955
- *outgoers(filter = "all") {
956
- const unique = /* @__PURE__ */ new Set();
957
- for (const r of this.outgoing(filter)) {
958
- if (unique.has(r.target.id)) {
959
- continue;
960
- }
961
- unique.add(r.target.id);
962
- yield r.target;
963
- }
964
- return;
965
- }
966
- isLayouted() {
967
- return "width" in this.$node && "height" in this.$node;
968
- }
969
- hasChildren() {
970
- return this.$node.children.length > 0;
971
- }
972
- hasParent() {
973
- return this.$node.parent !== null;
974
- }
975
- /**
976
- * Check if this node references to logical model element.
977
- */
978
- hasElement() {
979
- return e$2(this.$node.modelRef);
980
- }
981
- /**
982
- * Check if this node references to deployment element (Node or Instance).
983
- */
984
- hasDeployment() {
985
- return e$2(this.$node.deploymentRef);
986
- }
987
- /**
988
- * Check if this node references to deployed instance
989
- * Deployed instance always references to element and deployment element.
990
- */
991
- hasDeployedInstance() {
992
- return this.hasElement() && this.hasDeployment();
993
- }
994
- isGroup() {
995
- return isGroupElementKind(this.$node);
996
- }
997
- /**
998
- * Checks if the node has the given tag.
999
- */
1000
- isTagged(tag) {
1001
- return this.tags.includes(tag);
1002
- }
1003
- }
1004
-
1005
- class LikeC4ViewModel {
1006
- /**
1007
- * Don't use in runtime, only for type inference
1008
- */
1009
- Aux;
1010
- #view;
1011
- #rootnodes = /* @__PURE__ */ new Set();
1012
- #nodes = /* @__PURE__ */ new Map();
1013
- #edges = /* @__PURE__ */ new Map();
1014
- #includeElements = /* @__PURE__ */ new Set();
1015
- #includeDeployments = /* @__PURE__ */ new Set();
1016
- #includeRelations = /* @__PURE__ */ new Set();
1017
- #allTags = new DefaultMap((_key) => /* @__PURE__ */ new Set());
1018
- #manualLayoutSnapshot;
1019
- id;
1020
- /**
1021
- * The model this view belongs to
1022
- */
1023
- $model;
1024
- /**
1025
- * The title of the view
1026
- */
1027
- title;
1028
- /**
1029
- * View folder this view belongs to.
1030
- * If view is top-level, this is the root folder.
1031
- */
1032
- folder;
1033
- /**
1034
- * Path to this view, processed by {@link normalizeViewPath}
1035
- *
1036
- * @example
1037
- * "Group 1/Group 2/View"
1038
- */
1039
- viewPath;
1040
- constructor(model, folder, view, manualLayoutSnapshot) {
1041
- this.$model = model;
1042
- this.#view = view;
1043
- this.id = view.id;
1044
- this.folder = folder;
1045
- this.#manualLayoutSnapshot = manualLayoutSnapshot;
1046
- for (const node of this.#view.nodes) {
1047
- const el = new NodeModel(this, Object.freeze(node));
1048
- this.#nodes.set(node.id, el);
1049
- if (!node.parent) {
1050
- this.#rootnodes.add(el);
1051
- }
1052
- if (node.deploymentRef) {
1053
- this.#includeDeployments.add(node.deploymentRef);
1054
- }
1055
- if (node.modelRef) {
1056
- this.#includeElements.add(node.modelRef);
1057
- }
1058
- for (const tag of el.tags) {
1059
- this.#allTags.get(tag).add(el);
1060
- }
1061
- }
1062
- for (const edge of this.#view.edges) {
1063
- const edgeModel = new EdgeModel(
1064
- this,
1065
- Object.freeze(edge),
1066
- this.node(edge.source),
1067
- this.node(edge.target)
1068
- );
1069
- for (const tag of edgeModel.tags) {
1070
- this.#allTags.get(tag).add(edgeModel);
1071
- }
1072
- for (const rel of edge.relations) {
1073
- this.#includeRelations.add(rel);
1074
- }
1075
- this.#edges.set(edge.id, edgeModel);
1076
- }
1077
- this.title = view.title ? extractViewTitleFromPath(view.title) : null;
1078
- this.viewPath = view.title ? normalizeViewPath(view.title) : view.id;
1079
- }
1080
- /**
1081
- * Returns the styles configuration for the project.
1082
- */
1083
- get $styles() {
1084
- return this.$model.$styles;
1085
- }
1086
- get _type() {
1087
- return this.#view[_type];
1088
- }
1089
- get stage() {
1090
- return this.#view[_stage];
1091
- }
1092
- get bounds() {
1093
- if ("bounds" in this.#view) {
1094
- return this.#view.bounds;
1095
- }
1096
- if (this.#manualLayoutSnapshot) {
1097
- return this.#manualLayoutSnapshot.bounds;
1098
- }
1099
- throw new Error("View is not layouted");
1100
- }
1101
- /**
1102
- * Returns title if defined, otherwise returns title of the element it is based on, otherwise returns its {@link id}
1103
- */
1104
- get titleOrId() {
1105
- return this.title ?? this.viewOf?.title ?? this.id;
1106
- }
1107
- /**
1108
- * Returns title if defined, otherwise returns `Untitled`.
1109
- */
1110
- get titleOrUntitled() {
1111
- return this.title ?? "Untitled";
1112
- }
1113
- /**
1114
- * Returns path to this view as an array of groups and this view as the last element
1115
- * If view is top-level, returns only this view.
1116
- *
1117
- * @example
1118
- * viewPath = "Group 1/Group 2/View"
1119
- *
1120
- * breadcrumbs = [
1121
- * "Group 1", // folder
1122
- * "Group 1/Group 2", // folder
1123
- * "Group 1/Group 2/View" // view
1124
- * ]
1125
- */
1126
- get breadcrumbs() {
1127
- return memoizeProp(this, "breadcrumbs", () => {
1128
- if (!this.folder.isRoot) {
1129
- return [...this.folder.breadcrumbs, this];
1130
- }
1131
- return [this];
1132
- });
1133
- }
1134
- get description() {
1135
- return RichText.memoize(this, "description", this.#view.description);
1136
- }
1137
- get tags() {
1138
- return this.#view.tags ?? [];
1139
- }
1140
- get links() {
1141
- return this.#view.links ?? [];
1142
- }
1143
- get viewOf() {
1144
- if (this.isElementView()) {
1145
- const viewOf = this.#view.viewOf;
1146
- return viewOf ? this.$model.element(viewOf) : null;
1147
- }
1148
- return null;
1149
- }
1150
- /**
1151
- * Available for dynamic views only
1152
- * throws error if view is not dynamic
1153
- */
1154
- get mode() {
1155
- if (this.isDynamicView()) {
1156
- return this.#view.variant ?? "diagram";
1157
- }
1158
- return null;
1159
- }
1160
- /**
1161
- * All tags from nodes and edges.
1162
- */
1163
- get includedTags() {
1164
- return [...this.#allTags.keys()];
1165
- }
1166
- /**
1167
- * The original view from the model.
1168
- * In case of layouted model, this is the latest auto-layouted view without manual changes applied
1169
- * @see {@link $layouted} should be used for rendering in the UI
1170
- */
1171
- get $view() {
1172
- if (!this.isLayouted() || "drifts" in this.#view) {
1173
- return this.#view;
1174
- }
1175
- const snapshot = this.#manualLayoutSnapshot;
1176
- if (snapshot) {
1177
- return memoizeProp(this, "withDriftReasons", () => {
1178
- return calcDriftsFromSnapshot(this.#view, snapshot);
1179
- });
1180
- }
1181
- return this.#view;
1182
- }
1183
- /**
1184
- * Returns the view with manual layout applied if it exists, otherwise returns the original view
1185
- * This should be used for rendering in the UI
1186
- */
1187
- get $layouted() {
1188
- if (!this.isLayouted()) {
1189
- throw new Error("View is not layouted");
1190
- }
1191
- return this.$manual ?? this.#view;
1192
- }
1193
- get hasManualLayout() {
1194
- return this.#manualLayoutSnapshot !== void 0;
1195
- }
1196
- get hasLayoutDrifts() {
1197
- if (!this.isLayouted()) {
1198
- return false;
1199
- }
1200
- const manualLayout = this.$manual;
1201
- return !!manualLayout?.drifts && manualLayout.drifts.length > 0;
1202
- }
1203
- /**
1204
- * If view has manual layout, returns it with manual layout applied
1205
- */
1206
- get $manual() {
1207
- if (!this.isLayouted()) {
1208
- return null;
1209
- }
1210
- const snapshot = this.#manualLayoutSnapshot;
1211
- if (snapshot) {
1212
- return memoizeProp(this, "snapshotWithManualLayout", () => {
1213
- return applyManualLayout(this.#view, snapshot);
1214
- });
1215
- }
1216
- return null;
1217
- }
1218
- get projectId() {
1219
- return this.$model.projectId;
1220
- }
1221
- roots() {
1222
- return this.#rootnodes.values();
1223
- }
1224
- /**
1225
- * Iterate over all nodes that have children.
1226
- */
1227
- *compounds() {
1228
- for (const node of this.#nodes.values()) {
1229
- if (node.hasChildren()) {
1230
- yield node;
1231
- }
1232
- }
1233
- return;
1234
- }
1235
- /**
1236
- * Get node by id.
1237
- * @throws Error if node is not found.
1238
- */
1239
- node(node) {
1240
- const nodeId = getId(node);
1241
- return nonNullable(this.#nodes.get(nodeId), `Node ${nodeId} not found in view ${this.#view.id}`);
1242
- }
1243
- /**
1244
- * Find node by id.
1245
- */
1246
- findNode(node) {
1247
- return this.#nodes.get(getId(node)) ?? null;
1248
- }
1249
- findNodeWithElement(element) {
1250
- const id = getId(element);
1251
- if (!this.#includeElements.has(id)) {
1252
- return null;
1253
- }
1254
- return ifind(
1255
- this.#nodes.values(),
1256
- (node) => node.hasElement() && node.element.id === id
1257
- ) ?? null;
1258
- }
1259
- /**
1260
- * Iterate over all nodes.
1261
- */
1262
- nodes() {
1263
- return this.#nodes.values();
1264
- }
1265
- /**
1266
- * Get edge by id, throws error if edge is not found.
1267
- * Use {@link findEdge} if you are not sure if the edge exists.
1268
- *
1269
- * @param edge Edge or id
1270
- * @returns {@link EdgeModel}
1271
- */
1272
- edge(edge) {
1273
- const edgeId = getId(edge);
1274
- return nonNullable(this.#edges.get(edgeId), `Edge ${edgeId} not found in view ${this.#view.id}`);
1275
- }
1276
- /**
1277
- * Find edge by id.
1278
- * @param edge Edge or id
1279
- * @returns {@link EdgeModel} or null if edge is not found
1280
- */
1281
- findEdge(edge) {
1282
- return this.#edges.get(getId(edge)) ?? null;
1283
- }
1284
- /**
1285
- * Iterate over all edges.
1286
- */
1287
- edges() {
1288
- return this.#edges.values();
1289
- }
1290
- /**
1291
- * Iterate over all edges.
1292
- */
1293
- *edgesWithRelation(relation) {
1294
- for (const edge of this.#edges.values()) {
1295
- if (edge.includesRelation(relation)) {
1296
- yield edge;
1297
- }
1298
- }
1299
- return;
1300
- }
1301
- /**
1302
- * Nodes that have references to elements from logical model.
1303
- */
1304
- *elements() {
1305
- for (const node of this.#nodes.values()) {
1306
- if (node.hasElement()) {
1307
- yield node;
1308
- }
1309
- }
1310
- return;
1311
- }
1312
- /**
1313
- * Checks if the view has the given tag.
1314
- */
1315
- isTagged(tag) {
1316
- return this.tags.includes(tag);
1317
- }
1318
- includesElement(element) {
1319
- return this.#includeElements.has(getId(element));
1320
- }
1321
- includesDeployment(deployment) {
1322
- return this.#includeDeployments.has(getId(deployment));
1323
- }
1324
- includesRelation(relation) {
1325
- return this.#includeRelations.has(getId(relation));
1326
- }
1327
- /**
1328
- * Below are type guards.
1329
- */
1330
- isComputed() {
1331
- return this.#view[_stage] === "computed";
1332
- }
1333
- isLayouted() {
1334
- return this.#view[_stage] === "layouted";
1335
- }
1336
- /**
1337
- * @deprecated Use {@link isLayouted} instead
1338
- */
1339
- isDiagram() {
1340
- return this.#view[_stage] === "layouted";
1341
- }
1342
- isElementView() {
1343
- return this.#view[_type] === "element";
1344
- }
1345
- isScopedElementView() {
1346
- return this.#view[_type] === "element" && e$2(this.#view.viewOf);
1347
- }
1348
- isDeploymentView() {
1349
- return this.#view[_type] === "deployment";
1350
- }
1351
- isDynamicView() {
1352
- return this.#view[_type] === "dynamic";
1353
- }
1354
- }
1355
-
1356
- class LikeC4ViewsFolder {
1357
- $model;
1358
- /**
1359
- * Path to this view folder, processed by {@link normalizeViewPath}
1360
- *
1361
- * @example
1362
- * "Folder 1/Folder 2/Folder 3"
1363
- */
1364
- path;
1365
- /**
1366
- * Title of this view folder.
1367
- *
1368
- * @example
1369
- * // title is the last segment of the path
1370
- * path = "Folder 1/Folder 2/Folder 3"
1371
- * title = "Folder 3"
1372
- */
1373
- title;
1374
- /**
1375
- * Whether this is the root view folder.
1376
- *
1377
- * !NOTE
1378
- * Root folder is special folder with an empty path and used only for internal purposes. \
1379
- * It is not visible to the user and should not be used in the code.
1380
- */
1381
- isRoot;
1382
- parentPath;
1383
- defaultViewId;
1384
- constructor($model, path, defaultViewId) {
1385
- this.$model = $model;
1386
- this.path = path.join("/");
1387
- this.isRoot = this.path === "";
1388
- this.title = t$1(path);
1389
- if (this.isRoot) {
1390
- this.parentPath = void 0;
1391
- } else {
1392
- this.parentPath = path.slice(0, -1).join("/");
1393
- }
1394
- this.defaultViewId = defaultViewId;
1395
- }
1396
- /**
1397
- * Default view of this view folder.\
1398
- * It is for the case when there is a view at the same path as this folder.\
1399
- * (if there are multiple views at the same path, the first one is chosen)
1400
- *
1401
- * @example
1402
- * ```
1403
- * // Assume the following views exist:
1404
- * const views = [
1405
- * "Folder 1/ Folder 2 / View",
1406
- * "Folder 1/ Folder 2 / View / Subview",
1407
- * ]
1408
- * ```
1409
- * Group with path `Folder 1/ Folder 2 / View`\
1410
- * will have default view `Folder 1/ Folder 2 / View`
1411
- */
1412
- get defaultView() {
1413
- if (!this.defaultViewId) {
1414
- return null;
1415
- }
1416
- return this.$model.view(this.defaultViewId);
1417
- }
1418
- /**
1419
- * Returns path to this view folder as an array of ancestors (excluding root) and this view folder as the last element
1420
- *
1421
- * @throws Error if this is the root folder.
1422
- */
1423
- get breadcrumbs() {
1424
- invariant(!this.isRoot, "Root view folder has no breadcrumbs");
1425
- return memoizeProp(this, "breadcrumbs", () => {
1426
- const parent = this.parent;
1427
- if (parent) {
1428
- if (parent.isRoot) {
1429
- return [parent, this];
1430
- }
1431
- return [...parent.breadcrumbs, this];
1432
- }
1433
- return [this];
1434
- });
1435
- }
1436
- /**
1437
- * Returns parent folder
1438
- *
1439
- * @throws Error if this is the root folder.
1440
- */
1441
- get parent() {
1442
- invariant(!this.isRoot, "Root view folder has no parent");
1443
- if (e$1(this.parentPath)) {
1444
- return null;
1445
- }
1446
- return this.$model.viewFolder(this.parentPath);
1447
- }
1448
- /**
1449
- * Returns sorted set of children
1450
- * - First folders
1451
- * - Then views
1452
- */
1453
- get children() {
1454
- return this.$model.viewFolderItems(this.path);
1455
- }
1456
- /**
1457
- * Returns sorted array of children folders
1458
- */
1459
- get folders() {
1460
- return memoizeProp(this, "folders", () => {
1461
- const folders = [];
1462
- for (const child of this.children) {
1463
- if (child instanceof LikeC4ViewsFolder) {
1464
- folders.push(child);
1465
- }
1466
- }
1467
- return folders;
1468
- });
1469
- }
1470
- /**
1471
- * Returns all views in this view folder.
1472
- */
1473
- get views() {
1474
- return memoizeProp(this, "views", () => {
1475
- const views = [];
1476
- for (const child of this.children) {
1477
- if (child instanceof LikeC4ViewModel) {
1478
- views.push(child);
1479
- }
1480
- }
1481
- return views;
1482
- });
1483
- }
1484
- }
1485
-
1486
- class LikeC4Model {
1487
- /**
1488
- * Don't use in runtime, only for type inference
1489
- */
1490
- Aux;
1491
- _elements = /* @__PURE__ */ new Map();
1492
- // Parent element for given FQN
1493
- _parents = /* @__PURE__ */ new Map();
1494
- // Children elements for given FQN
1495
- _children = new DefaultMap(() => /* @__PURE__ */ new Set());
1496
- _rootElements = /* @__PURE__ */ new Set();
1497
- _relations = /* @__PURE__ */ new Map();
1498
- // Incoming to an element or its descendants
1499
- _incoming = new DefaultMap(() => /* @__PURE__ */ new Set());
1500
- // Outgoing from an element or its descendants
1501
- _outgoing = new DefaultMap(() => /* @__PURE__ */ new Set());
1502
- // Relationships inside the element, among descendants
1503
- _internal = new DefaultMap(() => /* @__PURE__ */ new Set());
1504
- _views = /* @__PURE__ */ new Map();
1505
- _rootViewFolder;
1506
- _viewFolders = /* @__PURE__ */ new Map();
1507
- _viewFolderItems = new DefaultMap(() => /* @__PURE__ */ new Set());
1508
- _allTags = new DefaultMap(() => /* @__PURE__ */ new Set());
1509
- static fromParsed(model) {
1510
- return new LikeC4Model(model);
1511
- }
1512
- static create(model) {
1513
- return new LikeC4Model(model);
1514
- }
1515
- /**
1516
- * Creates a new LikeC4Model instance and infers types from a model dump.\
1517
- * Model dump expected to be computed or layouted.
1518
- *
1519
- * @typeParam D - A constant type parameter extending LikeC4ModelDump
1520
- * @param dump - The model dump to create the instance from
1521
- * @returns A new LikeC4Model instance with types inferred from the dump
1522
- */
1523
- static fromDump(dump) {
1524
- const {
1525
- _stage: stage = "layouted",
1526
- projectId = "unknown",
1527
- project,
1528
- globals,
1529
- imports,
1530
- deployments,
1531
- views,
1532
- relations,
1533
- elements,
1534
- specification
1535
- } = dump;
1536
- return new LikeC4Model({
1537
- [_stage]: stage,
1538
- projectId,
1539
- project,
1540
- globals: {
1541
- predicates: globals?.predicates ?? {},
1542
- dynamicPredicates: globals?.dynamicPredicates ?? {},
1543
- styles: globals?.styles ?? {}
1544
- },
1545
- imports: imports ?? {},
1546
- deployments: {
1547
- elements: deployments?.elements ?? {},
1548
- relations: deployments?.relations ?? {}
1549
- },
1550
- views: views ?? {},
1551
- relations: relations ?? {},
1552
- elements: elements ?? {},
1553
- specification
1554
- });
1555
- }
1556
- deployment;
1557
- $data;
1558
- constructor($data) {
1559
- this.$data = $data;
1560
- for (const [, element] of t$5($data.elements)) {
1561
- const el = this.addElement(element);
1562
- for (const tag of el.tags) {
1563
- this._allTags.get(tag).add(el);
1564
- }
1565
- }
1566
- for (const [projectId, elements] of t$5($data.imports ?? {})) {
1567
- for (const element of sortParentsFirst(elements)) {
1568
- const el = this.addImportedElement(projectId, element);
1569
- for (const tag of el.tags) {
1570
- this._allTags.get(tag).add(el);
1571
- }
1572
- }
1573
- }
1574
- for (const relation of t($data.relations)) {
1575
- const el = this.addRelation(relation);
1576
- for (const tag of el.tags) {
1577
- this._allTags.get(tag).add(el);
1578
- }
1579
- }
1580
- this.deployment = new LikeC4DeploymentModel(this);
1581
- if (isOnStage($data, "computed") || isOnStage($data, "layouted")) {
1582
- const compare = compareNaturalHierarchically(VIEW_FOLDERS_SEPARATOR);
1583
- const views = t$6(
1584
- t($data.views),
1585
- t$8((view) => ({
1586
- view,
1587
- path: normalizeViewPath(view.title ?? view.id),
1588
- folderPath: view.title && getViewFolderPath(view.title) || ""
1589
- })),
1590
- // Sort hierarchically by groups, but keep same order within groups
1591
- t$7((a, b) => compare(a.folderPath, b.folderPath))
1592
- );
1593
- const getOrCreateFolder = (path) => {
1594
- let folder = this._viewFolders.get(path);
1595
- if (!folder) {
1596
- const segments = e(path, VIEW_FOLDERS_SEPARATOR);
1597
- invariant(t$4(segments, 1), `View group path "${path}" must have at least one element`);
1598
- let defaultView;
1599
- if (path === "") {
1600
- defaultView = views.find((view) => view.view.id === "index");
1601
- } else {
1602
- defaultView = views.find((view) => view.path === path);
1603
- }
1604
- folder = new LikeC4ViewsFolder(this, segments, defaultView?.view.id);
1605
- this._viewFolders.set(path, folder);
1606
- }
1607
- return folder;
1608
- };
1609
- this._rootViewFolder = getOrCreateFolder("");
1610
- for (const { folderPath } of views) {
1611
- if (this._viewFolders.has(folderPath)) {
1612
- continue;
1613
- }
1614
- e(folderPath, VIEW_FOLDERS_SEPARATOR).reduce((segments, segment) => {
1615
- const parent = segments.join(VIEW_FOLDERS_SEPARATOR);
1616
- const path = e$3(parent) ? segment : parent + VIEW_FOLDERS_SEPARATOR + segment;
1617
- const folder = getOrCreateFolder(path);
1618
- this._viewFolderItems.get(parent).add(folder);
1619
- segments.push(segment);
1620
- return segments;
1621
- }, []);
1622
- }
1623
- for (const { view, folderPath } of views) {
1624
- const vm = new LikeC4ViewModel(
1625
- this,
1626
- getOrCreateFolder(folderPath),
1627
- view,
1628
- $data.manualLayouts?.[view.id]
1629
- );
1630
- this._viewFolderItems.get(folderPath).add(vm);
1631
- this._views.set(view.id, vm);
1632
- for (const tag of vm.tags) {
1633
- this._allTags.get(tag).add(vm);
1634
- }
1635
- }
1636
- } else {
1637
- this._rootViewFolder = new LikeC4ViewsFolder(this, [""], void 0);
1638
- this._viewFolders.set(this._rootViewFolder.path, this._rootViewFolder);
1639
- }
1640
- }
1641
- /**
1642
- * Type narrows the model to the parsed stage.
1643
- * This is useful for tests
1644
- */
1645
- get asParsed() {
1646
- return this;
1647
- }
1648
- /**
1649
- * Type narrows the model to the layouted stage.
1650
- * This is useful for tests
1651
- */
1652
- get asComputed() {
1653
- return this;
1654
- }
1655
- /**
1656
- * Type narrows the model to the layouted stage.
1657
- * This is useful for tests
1658
- */
1659
- get asLayouted() {
1660
- return this;
1661
- }
1662
- /**
1663
- * Returns the styles configuration for the project.
1664
- */
1665
- get $styles() {
1666
- return memoizeProp(
1667
- this,
1668
- "styles",
1669
- () => LikeC4Styles.from(
1670
- this.$data.project.styles,
1671
- this.$data.specification.customColors ? {
1672
- theme: {
1673
- colors: this.$data.specification.customColors
1674
- }
1675
- } : void 0
1676
- )
1677
- );
1678
- }
1679
- /**
1680
- * Type guard the model to the parsed stage.
1681
- */
1682
- isParsed() {
1683
- return this.stage === "parsed";
1684
- }
1685
- /**
1686
- * Type guard the model to the layouted stage.
1687
- */
1688
- isLayouted() {
1689
- return this.stage === "layouted";
1690
- }
1691
- /**
1692
- * Type guard the model to the computed stage.
1693
- */
1694
- isComputed() {
1695
- return this.stage === "computed";
1696
- }
1697
- /**
1698
- * Keeping here for backward compatibility
1699
- * @deprecated use {@link $data}
1700
- */
1701
- get $model() {
1702
- return this.$data;
1703
- }
1704
- get stage() {
1705
- return this.$data[_stage];
1706
- }
1707
- /**
1708
- * Returns the Project ID associated with the model.
1709
- * If the project ID is not defined in the model, it returns "default".
1710
- */
1711
- get projectId() {
1712
- return this.$data.projectId ?? "default";
1713
- }
1714
- /**
1715
- * Returns the project associated with the model.
1716
- * If the project is not defined in the model, it returns a default project with the ID "default".
1717
- */
1718
- get project() {
1719
- return this.$data.project ?? memoizeProp(this, /* @__PURE__ */ Symbol.for("project"), () => ({
1720
- id: this.projectId
1721
- }));
1722
- }
1723
- get specification() {
1724
- return this.$data.specification;
1725
- }
1726
- get globals() {
1727
- return memoizeProp(this, /* @__PURE__ */ Symbol.for("globals"), () => ({
1728
- predicates: {
1729
- ...this.$data.globals?.predicates
1730
- },
1731
- dynamicPredicates: {
1732
- ...this.$data.globals?.dynamicPredicates
1733
- },
1734
- styles: {
1735
- ...this.$data.globals?.styles
1736
- }
1737
- }));
1738
- }
1739
- /**
1740
- * Returns the element with the given FQN.
1741
- *
1742
- * @throws Error if element is not found\
1743
- * Use {@link findElement} if you don't want to throw an error
1744
- *
1745
- * @note Method is type-safe for typed model
1746
-
1747
- * @example
1748
- * model.element('cloud.frontend')
1749
- * // or object with id property of scalar.Fqn
1750
- * model.element({
1751
- * id: 'dashboard',
1752
- * })
1753
- */
1754
- element(el) {
1755
- if (el instanceof ElementModel) {
1756
- return el;
1757
- }
1758
- const id = getId(el);
1759
- return nonNullable(this._elements.get(id), `Element ${id} not found`);
1760
- }
1761
- /**
1762
- * Returns the element with the given FQN.
1763
- *
1764
- * @returns Element if found, null otherwise
1765
- * @note Method is not type-safe as {@link element}
1766
- *
1767
- * @example
1768
- * model.findElement('cloud.frontend')
1769
- */
1770
- findElement(el) {
1771
- return this._elements.get(getId(el)) ?? null;
1772
- }
1773
- /**
1774
- * Returns the root elements of the model.
1775
- */
1776
- roots() {
1777
- return this._rootElements.values();
1778
- }
1779
- /**
1780
- * Returns all elements in the model.
1781
- */
1782
- elements() {
1783
- return this._elements.values();
1784
- }
1785
- /**
1786
- * Returns all relationships in the model.
1787
- */
1788
- relationships() {
1789
- return this._relations.values();
1790
- }
1791
- relationship(rel, type) {
1792
- if (type === "deployment") {
1793
- return this.deployment.relationship(rel);
1794
- }
1795
- const id = getId(rel);
1796
- let model = this._relations.get(id) ?? null;
1797
- if (model || type === "model") {
1798
- return nonNullable(model, `Model relation ${id} not found`);
1799
- }
1800
- return nonNullable(this.deployment.findRelationship(id), `No model/deployment relation ${id} not found`);
1801
- }
1802
- findRelationship(id, type) {
1803
- if (type === "deployment") {
1804
- return this.deployment.findRelationship(id);
1805
- }
1806
- let model = this._relations.get(getId(id)) ?? null;
1807
- if (model || type === "model") {
1808
- return model;
1809
- }
1810
- return this.deployment.findRelationship(id);
1811
- }
1812
- /**
1813
- * Returns all views in the model.
1814
- */
1815
- views() {
1816
- return this._views.values();
1817
- }
1818
- /**
1819
- * Returns a specific view by its ID.
1820
- * @note Method is type-safe for typed model
1821
- * @throws Error if view is not found\
1822
- * Use {@link findView} if you don't want to throw an error
1823
- *
1824
- * @example
1825
- * model.view('index')
1826
- * // or object with id property of scalar.ViewId
1827
- * model.view({
1828
- * id: 'index',
1829
- * })
1830
- */
1831
- view(viewId) {
1832
- const id = getId(viewId);
1833
- return nonNullable(this._views.get(id), `View ${id} not found`);
1834
- }
1835
- /**
1836
- * Returns a specific view by its ID.
1837
- * @note Method is not type-safe as {@link view}
1838
- *
1839
- * @example
1840
- * model.findView('index')
1841
- */
1842
- findView(viewId) {
1843
- return this._views.get(viewId) ?? null;
1844
- }
1845
- /**
1846
- * Returns manual layout snapshot for given view ID, if any.
1847
- */
1848
- findManualLayout(viewId) {
1849
- if ("manualLayouts" in this.$data) {
1850
- const view = this.$data.manualLayouts?.[viewId];
1851
- return view ?? null;
1852
- }
1853
- return null;
1854
- }
1855
- /**
1856
- * Returns a view folder by its path.
1857
- * Path is extracted from the view title, e.g. "Group 1/Group 2/View" -> "Group 1/Group 2"
1858
- * @throws Error if view folder is not found.
1859
- */
1860
- viewFolder(path) {
1861
- return nonNullable(this._viewFolders.get(path), `View folder ${path} not found`);
1862
- }
1863
- /**
1864
- * Root folder is a special one with an empty path and used only for internal purposes.
1865
- * It is not visible to the user and should be used only to get top-level folders and views.
1866
- */
1867
- get rootViewFolder() {
1868
- return this._rootViewFolder;
1869
- }
1870
- /**
1871
- * Whether the model has any view folders.
1872
- */
1873
- get hasViewFolders() {
1874
- return this._viewFolders.size > 1;
1875
- }
1876
- /**
1877
- * Returns all children of a view folder.
1878
- * Path is extracted from the view title, e.g. "Group 1/Group 2/View" -> "Group 1/Group 2"
1879
- *
1880
- * @throws Error if view folder is not found.
1881
- */
1882
- viewFolderItems(path) {
1883
- invariant(this._viewFolders.has(path), `View folder ${path} not found`);
1884
- return this._viewFolderItems.get(path);
1885
- }
1886
- /**
1887
- * Returns the parent element of given element.
1888
- * @see ancestors
1889
- */
1890
- parent(element) {
1891
- const id = getId(element);
1892
- return this._parents.get(id) || null;
1893
- }
1894
- /**
1895
- * Get all children of the element (only direct children),
1896
- * @see descendants
1897
- */
1898
- children(element) {
1899
- const id = getId(element);
1900
- return this._children.get(id);
1901
- }
1902
- /**
1903
- * Get all sibling (i.e. same parent)
1904
- */
1905
- *siblings(element) {
1906
- const id = getId(element);
1907
- const parent = this._parents.get(id);
1908
- const siblings = parent ? this._children.get(parent.id).values() : this.roots();
1909
- for (const sibling of siblings) {
1910
- if (sibling.id !== id) {
1911
- yield sibling;
1912
- }
1913
- }
1914
- return;
1915
- }
1916
- /**
1917
- * Get all ancestor elements (i.e. parent, parent’s parent, etc.)
1918
- * (from closest to root)
1919
- */
1920
- *ancestors(element) {
1921
- let id = getId(element);
1922
- let parent;
1923
- while (parent = this._parents.get(id)) {
1924
- yield parent;
1925
- id = parent.id;
1926
- }
1927
- return;
1928
- }
1929
- /**
1930
- * Get all descendant elements (i.e. children, children’s children, etc.)
1931
- */
1932
- *descendants(element) {
1933
- for (const child of this.children(element)) {
1934
- yield child;
1935
- yield* this.descendants(child.id);
1936
- }
1937
- return;
1938
- }
1939
- /**
1940
- * Incoming relationships to the element and its descendants
1941
- * @see incomers
1942
- */
1943
- *incoming(element, filter = "all") {
1944
- const id = getId(element);
1945
- for (const rel of this._incoming.get(id)) {
1946
- switch (true) {
1947
- case filter === "all":
1948
- case (filter === "direct" && rel.target.id === id):
1949
- case (filter === "to-descendants" && rel.target.id !== id):
1950
- yield rel;
1951
- break;
1952
- }
1953
- }
1954
- return;
1955
- }
1956
- /**
1957
- * Outgoing relationships from the element and its descendants
1958
- * @see outgoers
1959
- */
1960
- *outgoing(element, filter = "all") {
1961
- const id = getId(element);
1962
- for (const rel of this._outgoing.get(id)) {
1963
- switch (true) {
1964
- case filter === "all":
1965
- case (filter === "direct" && rel.source.id === id):
1966
- case (filter === "from-descendants" && rel.source.id !== id):
1967
- yield rel;
1968
- break;
1969
- }
1970
- }
1971
- return;
1972
- }
1973
- /**
1974
- * Returns array of all tags used in the model, sorted naturally.\
1975
- * Use {@link specification.tags} to get all defined tags
1976
- */
1977
- get tags() {
1978
- return memoizeProp(this, "tags", () => t$7([...this._allTags.keys()], compareNatural));
1979
- }
1980
- /**
1981
- * Returns all tags used in the model, sorted by usage count (descending).
1982
- */
1983
- get tagsSortedByUsage() {
1984
- return memoizeProp(this, "tagsSortedByUsage", () => t$6(
1985
- [...this._allTags.entries()],
1986
- t$8(([tag, tagged]) => ({
1987
- tag,
1988
- count: tagged.size,
1989
- tagged
1990
- })),
1991
- t$7((a, b) => compareNatural(a.tag, b.tag)),
1992
- t$9(
1993
- [e$4("count"), "desc"]
1994
- )
1995
- ));
1996
- }
1997
- findByTag(tag, type) {
1998
- return ifilter(this._allTags.get(tag), (el) => {
1999
- if (type === "elements") {
2000
- return el instanceof ElementModel;
2001
- }
2002
- if (type === "views") {
2003
- return el instanceof LikeC4ViewModel;
2004
- }
2005
- if (type === "relationships") {
2006
- return el instanceof RelationshipModel;
2007
- }
2008
- return true;
2009
- });
2010
- }
2011
- /**
2012
- * Returns all elements of the given kind.
2013
- */
2014
- *elementsOfKind(kind) {
2015
- for (const el of this._elements.values()) {
2016
- if (el.kind === kind) {
2017
- yield el;
2018
- }
2019
- }
2020
- return;
2021
- }
2022
- /**
2023
- * Returns all elements that match the given where operator.
2024
- *
2025
- * @example
2026
- * ```ts
2027
- * model.where({
2028
- * and: [
2029
- * { kind: 'component' },
2030
- * {
2031
- * or: [
2032
- * { tag: 'old' },
2033
- * { tag: { neq: 'new' } },
2034
- * ],
2035
- * },
2036
- * ],
2037
- * })
2038
- * ```
2039
- */
2040
- *elementsWhere(where) {
2041
- const predicate = whereOperatorAsPredicate(where);
2042
- for (const el of this._elements.values()) {
2043
- if (predicate(el)) {
2044
- yield el;
2045
- }
2046
- }
2047
- return;
2048
- }
2049
- /**
2050
- * Returns all **model** relationships that match the given where operator.
2051
- *
2052
- * @example
2053
- * ```ts
2054
- * model.relationshipsWhere({
2055
- * and: [
2056
- * { kind: 'uses' },
2057
- * {
2058
- * or: [
2059
- * { tag: 'old' },
2060
- * { tag: { neq: 'new' } },
2061
- * ],
2062
- * },
2063
- * ],
2064
- * })
2065
- * ```
2066
- */
2067
- *relationshipsWhere(where) {
2068
- const predicate = whereOperatorAsPredicate(where);
2069
- for (const rel of this._relations.values()) {
2070
- if (predicate(rel)) {
2071
- yield rel;
2072
- }
2073
- }
2074
- return;
2075
- }
2076
- addElement(element) {
2077
- if (this._elements.has(element.id)) {
2078
- throw new Error(`Element ${element.id} already exists`);
2079
- }
2080
- const el = new ElementModel(this, Object.freeze(element));
2081
- this._elements.set(el.id, el);
2082
- const parentId = parentFqn(el.id);
2083
- if (parentId) {
2084
- invariant(this._elements.has(parentId), `Parent ${parentId} of ${el.id} not found`);
2085
- this._parents.set(el.id, this.element(parentId));
2086
- this._children.get(parentId).add(el);
2087
- } else {
2088
- this._rootElements.add(el);
2089
- }
2090
- return el;
2091
- }
2092
- addImportedElement(projectId, element) {
2093
- invariant(!isGlobalFqn(element.id), `Imported element already has global FQN`);
2094
- const id = GlobalFqn(projectId, element.id);
2095
- if (this._elements.has(id)) {
2096
- throw new Error(`Element ${id} already exists`);
2097
- }
2098
- const el = new ElementModel(
2099
- this,
2100
- Object.freeze({
2101
- ...element,
2102
- id
2103
- })
2104
- );
2105
- this._elements.set(el.id, el);
2106
- let parentId = parentFqn(el.id);
2107
- while (parentId) {
2108
- if (parentId.includes(".") && this._elements.has(parentId)) {
2109
- this._parents.set(el.id, this.element(parentId));
2110
- this._children.get(parentId).add(el);
2111
- return el;
2112
- }
2113
- parentId = parentFqn(parentId);
2114
- }
2115
- this._rootElements.add(el);
2116
- return el;
2117
- }
2118
- addRelation(relation) {
2119
- if (this._relations.has(relation.id)) {
2120
- throw new Error(`Relation ${relation.id} already exists`);
2121
- }
2122
- const rel = new RelationshipModel(
2123
- this,
2124
- Object.freeze(relation)
2125
- );
2126
- const { source, target } = rel;
2127
- this._relations.set(rel.id, rel);
2128
- this._incoming.get(target.id).add(rel);
2129
- this._outgoing.get(source.id).add(rel);
2130
- const relParent = commonAncestor(source.id, target.id);
2131
- if (relParent) {
2132
- for (const ancestor of [relParent, ...ancestorsFqn(relParent)]) {
2133
- this._internal.get(ancestor).add(rel);
2134
- }
2135
- }
2136
- for (const sourceAncestor of ancestorsFqn(source.id)) {
2137
- if (sourceAncestor === relParent) {
2138
- break;
2139
- }
2140
- this._outgoing.get(sourceAncestor).add(rel);
2141
- }
2142
- for (const targetAncestor of ancestorsFqn(target.id)) {
2143
- if (targetAncestor === relParent) {
2144
- break;
2145
- }
2146
- this._incoming.get(targetAncestor).add(rel);
2147
- }
2148
- return rel;
2149
- }
2150
- }
2151
- ((LikeC4Model2) => {
2152
- LikeC4Model2.EMPTY = LikeC4Model2.create({
2153
- _stage: "computed",
2154
- projectId: "default",
2155
- project: { id: "default" },
2156
- specification: {
2157
- elements: {},
2158
- relationships: {},
2159
- deployments: {},
2160
- tags: {}
2161
- },
2162
- globals: {
2163
- predicates: {},
2164
- dynamicPredicates: {},
2165
- styles: {}
2166
- },
2167
- deployments: {
2168
- elements: {},
2169
- relations: {}
2170
- },
2171
- elements: {},
2172
- relations: {},
2173
- views: {},
2174
- imports: {}
2175
- });
2176
- })(LikeC4Model || (LikeC4Model = {}));
2177
-
2178
- function isDeploymentNodeModel(model) {
2179
- return model instanceof DeploymentNodeModel;
2180
- }
2181
- function isDeployedInstanceModel(model) {
2182
- return model instanceof DeployedInstanceModel;
2183
- }
2184
- function isDeploymentElementModel(model) {
2185
- return isDeploymentNodeModel(model) || isDeployedInstanceModel(model);
2186
- }
2187
- function isNestedElementOfDeployedInstanceModel(model) {
2188
- return model instanceof NestedElementOfDeployedInstanceModel;
2189
- }
2190
- function isDeploymentRelationModel(x) {
2191
- return x instanceof DeploymentRelationModel;
2192
- }
2193
- function isRelationModel(x) {
2194
- return x instanceof RelationshipModel;
2195
- }
2196
- function isElementModel(element) {
2197
- return element instanceof ElementModel;
2198
- }
2199
- function isLikeC4ViewModel(view) {
2200
- return view instanceof LikeC4ViewModel;
2201
- }
2202
- function isNodeModel(node) {
2203
- return node instanceof NodeModel;
2204
- }
2205
- function isEdgeModel(edge) {
2206
- return edge instanceof EdgeModel;
2207
- }
2208
-
2209
- 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 };