@likec4/core 1.17.1 → 1.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/compute-view/index.d.mts +91 -0
- package/dist/compute-view/index.d.ts +91 -0
- package/dist/compute-view/index.mjs +79 -0
- package/dist/index.d.mts +246 -434
- package/dist/index.d.ts +246 -434
- package/dist/index.mjs +418 -1322
- package/dist/model/index.d.mts +642 -0
- package/dist/model/index.d.ts +642 -0
- package/dist/model/index.mjs +2 -0
- package/dist/shared/core.BBgiAAv1.mjs +144 -0
- package/dist/shared/core.BPyJvuMU.mjs +2420 -0
- package/dist/shared/core.BQ4AbfvB.mjs +9228 -0
- package/dist/shared/{core.CoLQkcYL.d.mts → core.DMYY7C8s.d.mts} +398 -249
- package/dist/shared/{core.CoLQkcYL.d.ts → core.DMYY7C8s.d.ts} +398 -249
- package/dist/shared/core.k12s_keD.mjs +203 -0
- package/dist/types/index.d.mts +69 -1
- package/dist/types/index.d.ts +69 -1
- package/dist/types/index.mjs +21 -1
- package/package.json +38 -40
- package/src/builder/Builder.deployment.ts +219 -0
- package/src/builder/Builder.deploymentModel.ts +360 -0
- package/src/builder/Builder.element.ts +17 -19
- package/src/builder/Builder.model.ts +13 -2
- package/src/builder/Builder.test-d.ts +59 -4
- package/src/builder/Builder.ts +238 -53
- package/src/builder/Builder.view.ts +238 -53
- package/src/builder/_types.ts +87 -15
- package/src/compute-view/LikeC4ModelGraph.ts +330 -0
- package/src/compute-view/compute-view.ts +92 -0
- package/src/compute-view/deployment-view/Memory.ts +108 -0
- package/src/compute-view/deployment-view/Stage.ts +145 -0
- package/src/compute-view/deployment-view/__test__/fixture.ts +210 -0
- package/src/compute-view/deployment-view/_types.ts +29 -0
- package/src/compute-view/deployment-view/clean-connections.ts +229 -0
- package/src/compute-view/deployment-view/compute.ts +111 -0
- package/src/compute-view/deployment-view/predicates/deployment-ref.ts +146 -0
- package/src/compute-view/deployment-view/predicates/relation-direct.ts +130 -0
- package/src/compute-view/deployment-view/predicates/relation-in-out.ts +43 -0
- package/src/compute-view/deployment-view/predicates/relation-incoming.ts +46 -0
- package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +49 -0
- package/src/compute-view/deployment-view/predicates/wildcard.ts +29 -0
- package/src/compute-view/deployment-view/utils.ts +212 -0
- package/src/compute-view/dynamic-view/__test__/fixture.ts +58 -0
- package/src/compute-view/dynamic-view/compute.ts +310 -0
- package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +456 -0
- package/src/compute-view/element-view/__test__/fixture.ts +645 -0
- package/src/compute-view/element-view/compute.ts +734 -0
- package/src/compute-view/element-view/predicates.ts +517 -0
- package/src/compute-view/index.ts +5 -0
- package/src/compute-view/utils/__snapshots__/sortNodes.spec.ts.snap +113 -0
- package/src/compute-view/utils/ancestorsOfNode.ts +19 -0
- package/src/compute-view/utils/applyCustomElementProperties.ts +66 -0
- package/src/compute-view/utils/applyCustomRelationProperties.ts +41 -0
- package/src/compute-view/utils/applyViewRuleStyles.ts +53 -0
- package/src/compute-view/utils/buildComputedNodes.ts +148 -0
- package/src/compute-view/utils/buildElementNotations.ts +63 -0
- package/src/compute-view/utils/derive-edge-props-from-relationships.ts +97 -0
- package/src/compute-view/utils/elementExpressionToPredicate.ts +52 -0
- package/src/compute-view/utils/link-nodes-with-edges.ts +58 -0
- package/src/compute-view/utils/relationExpressionToPredicates.ts +55 -0
- package/src/compute-view/utils/resolve-extended-views.ts +65 -0
- package/src/compute-view/utils/resolve-global-rules.ts +83 -0
- package/src/compute-view/utils/sortNodes.ts +101 -0
- package/src/compute-view/utils/topological-sort.ts +160 -0
- package/src/compute-view/utils/uniqueTags.test.ts +42 -0
- package/src/compute-view/utils/uniqueTags.ts +21 -0
- package/src/compute-view/utils/view-hash.ts +27 -0
- package/src/compute-view/utils/with-readable-edges.ts +31 -0
- package/src/index.ts +5 -1
- package/src/model/DeploymentElementModel.ts +534 -0
- package/src/model/DeploymentModel.ts +364 -0
- package/src/model/ElementModel.ts +195 -0
- package/src/model/LikeC4Model.test-d.ts +151 -0
- package/src/model/LikeC4Model.ts +280 -457
- package/src/model/RelationModel.ts +84 -0
- package/src/model/__test__/fixture.ts +153 -338
- package/src/model/connection/ConnectionModel.ts +94 -0
- package/src/model/connection/DeploymentConnectionModel.ts +99 -0
- package/src/model/connection/deployment.ts +124 -0
- package/src/model/connection/model.ts +123 -0
- package/src/model/index.ts +4 -2
- package/src/model/types.ts +95 -15
- package/src/model/view/EdgeModel.ts +103 -0
- package/src/model/view/LikeC4ViewModel.ts +220 -0
- package/src/model/view/NodeModel.ts +228 -0
- package/src/types/_common.ts +2 -0
- package/src/types/deployments.ts +237 -0
- package/src/types/element.ts +7 -3
- package/src/types/expression.ts +8 -6
- package/src/types/index.ts +1 -0
- package/src/types/model.ts +68 -9
- package/src/types/overview-graph.ts +2 -2
- package/src/types/relation.ts +4 -4
- package/src/types/view-notation.ts +2 -2
- package/src/types/view.ts +104 -30
- package/src/utils/{commonHead.ts → common-head.ts} +2 -0
- package/src/utils/fqn.ts +83 -27
- package/src/utils/getOrCreate.ts +42 -0
- package/src/utils/graphlib.ts +10 -0
- package/src/utils/index.ts +4 -1
- package/src/utils/object-hash.ts +3 -0
- package/src/utils/set.ts +76 -0
- package/src/utils/string-hash.ts +16 -0
- package/dist/index.cjs +0 -5452
- package/dist/index.d.cts +0 -1053
- package/dist/shared/core.BXTs-8n7.mjs +0 -293
- package/dist/shared/core.CoLQkcYL.d.cts +0 -734
- package/dist/shared/core.DIYZvpVg.cjs +0 -353
- package/dist/types/index.cjs +0 -70
- package/dist/types/index.d.cts +0 -2
- package/src/model/LikeC4DiagramModel.ts +0 -338
- package/src/model/LikeC4ViewModel.ts +0 -320
|
@@ -0,0 +1,2420 @@
|
|
|
1
|
+
import { u, e as DefaultElementShape, d as DefaultThemeColor, f as nonNullable, b as invariant, D as DeploymentElement, F as extractStep, C as isStepEdgeId, H as ComputedNode, c as isScopedElementView, y as isElementView, w as isDeploymentView, x as isDynamicView } from './core.k12s_keD.mjs';
|
|
2
|
+
|
|
3
|
+
function r(...t){return u(Object.values,t)}
|
|
4
|
+
|
|
5
|
+
var s={done:!1,hasNext:!1},o$2=t=>({hasNext:!0,next:t,done:!1});
|
|
6
|
+
|
|
7
|
+
function x(t,...o){let n=t,u=o.map(e=>"lazy"in e?f(e):void 0),p=0;for(;p<o.length;){if(u[p]===void 0||!B(n)){let i=o[p];n=i(n),p+=1;continue}let r=[];for(let i=p;i<o.length;i++){let l=u[i];if(l===void 0||(r.push(l),l.isSingle))break}let a=[];for(let i of n)if(A(i,a,r))break;let{isSingle:y}=r.at(-1);n=y?a[0]:a,p+=r.length;}return n}function A(t,o,n){if(n.length===0)return o.push(t),!1;let u=t,p=s,e=!1;for(let[r,a]of n.entries()){let{index:y,items:i}=a;if(i.push(u),p=a(u,y,i),a.index+=1,p.hasNext){if(p.hasMany??!1){for(let l of p.next)if(A(l,o,n.slice(r+1)))return !0;return e}u=p.next;}if(!p.hasNext)break;p.done&&(e=!0);}return p.hasNext&&o.push(u),e}function f(t){let{lazy:o,lazyArgs:n}=t,u=o(...n);return Object.assign(u,{isSingle:o.single??!1,index:0,items:[]})}function B(t){return typeof t=="string"||typeof t=="object"&&t!==null&&Symbol.iterator in t}
|
|
8
|
+
|
|
9
|
+
function m(...r){return u(o$1,r)}function o$1(r,t){let e=[...r];return e.sort(t),e}
|
|
10
|
+
|
|
11
|
+
function t$1(...n){return u(o,n)}var o=n=>n.length===1?n[0]:void 0;
|
|
12
|
+
|
|
13
|
+
function t(r){return typeof r=="string"}
|
|
14
|
+
|
|
15
|
+
function n$1(e){return !!e}
|
|
16
|
+
|
|
17
|
+
function n(e){return e===void 0?!0:typeof e=="string"||Array.isArray(e)?e.length===0:Object.keys(e).length===0}
|
|
18
|
+
|
|
19
|
+
function getDefaultExportFromCjs (x) {
|
|
20
|
+
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Mnemonist DefaultMap
|
|
25
|
+
* =====================
|
|
26
|
+
*
|
|
27
|
+
* JavaScript implementation of a default map that will return a constructed
|
|
28
|
+
* value any time one tries to access an inexisting key. It's quite similar
|
|
29
|
+
* to python's defaultdict.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
var defaultMap;
|
|
33
|
+
var hasRequiredDefaultMap;
|
|
34
|
+
|
|
35
|
+
function requireDefaultMap () {
|
|
36
|
+
if (hasRequiredDefaultMap) return defaultMap;
|
|
37
|
+
hasRequiredDefaultMap = 1;
|
|
38
|
+
/**
|
|
39
|
+
* DefaultMap.
|
|
40
|
+
*
|
|
41
|
+
* @constructor
|
|
42
|
+
*/
|
|
43
|
+
function DefaultMap(factory) {
|
|
44
|
+
if (typeof factory !== 'function')
|
|
45
|
+
throw new Error('mnemonist/DefaultMap.constructor: expecting a function.');
|
|
46
|
+
|
|
47
|
+
this.items = new Map();
|
|
48
|
+
this.factory = factory;
|
|
49
|
+
this.size = 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Method used to clear the structure.
|
|
54
|
+
*
|
|
55
|
+
* @return {undefined}
|
|
56
|
+
*/
|
|
57
|
+
DefaultMap.prototype.clear = function() {
|
|
58
|
+
|
|
59
|
+
// Properties
|
|
60
|
+
this.items.clear();
|
|
61
|
+
this.size = 0;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Method used to get the value set for given key. If the key does not exist,
|
|
66
|
+
* the value will be created using the provided factory.
|
|
67
|
+
*
|
|
68
|
+
* @param {any} key - Target key.
|
|
69
|
+
* @return {any}
|
|
70
|
+
*/
|
|
71
|
+
DefaultMap.prototype.get = function(key) {
|
|
72
|
+
var value = this.items.get(key);
|
|
73
|
+
|
|
74
|
+
if (typeof value === 'undefined') {
|
|
75
|
+
value = this.factory(key, this.size);
|
|
76
|
+
this.items.set(key, value);
|
|
77
|
+
this.size++;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return value;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Method used to get the value set for given key. If the key does not exist,
|
|
85
|
+
* a value won't be created.
|
|
86
|
+
*
|
|
87
|
+
* @param {any} key - Target key.
|
|
88
|
+
* @return {any}
|
|
89
|
+
*/
|
|
90
|
+
DefaultMap.prototype.peek = function(key) {
|
|
91
|
+
return this.items.get(key);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Method used to set a value for given key.
|
|
96
|
+
*
|
|
97
|
+
* @param {any} key - Target key.
|
|
98
|
+
* @param {any} value - Value.
|
|
99
|
+
* @return {DefaultMap}
|
|
100
|
+
*/
|
|
101
|
+
DefaultMap.prototype.set = function(key, value) {
|
|
102
|
+
this.items.set(key, value);
|
|
103
|
+
this.size = this.items.size;
|
|
104
|
+
|
|
105
|
+
return this;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Method used to test the existence of a key in the map.
|
|
110
|
+
*
|
|
111
|
+
* @param {any} key - Target key.
|
|
112
|
+
* @return {boolean}
|
|
113
|
+
*/
|
|
114
|
+
DefaultMap.prototype.has = function(key) {
|
|
115
|
+
return this.items.has(key);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Method used to delete target key.
|
|
120
|
+
*
|
|
121
|
+
* @param {any} key - Target key.
|
|
122
|
+
* @return {boolean}
|
|
123
|
+
*/
|
|
124
|
+
DefaultMap.prototype.delete = function(key) {
|
|
125
|
+
var deleted = this.items.delete(key);
|
|
126
|
+
|
|
127
|
+
this.size = this.items.size;
|
|
128
|
+
|
|
129
|
+
return deleted;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Method used to iterate over each of the key/value pairs.
|
|
134
|
+
*
|
|
135
|
+
* @param {function} callback - Function to call for each item.
|
|
136
|
+
* @param {object} scope - Optional scope.
|
|
137
|
+
* @return {undefined}
|
|
138
|
+
*/
|
|
139
|
+
DefaultMap.prototype.forEach = function(callback, scope) {
|
|
140
|
+
scope = arguments.length > 1 ? scope : this;
|
|
141
|
+
|
|
142
|
+
this.items.forEach(callback, scope);
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Iterators.
|
|
147
|
+
*/
|
|
148
|
+
DefaultMap.prototype.entries = function() {
|
|
149
|
+
return this.items.entries();
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
DefaultMap.prototype.keys = function() {
|
|
153
|
+
return this.items.keys();
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
DefaultMap.prototype.values = function() {
|
|
157
|
+
return this.items.values();
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Attaching the #.entries method to Symbol.iterator if possible.
|
|
162
|
+
*/
|
|
163
|
+
if (typeof Symbol !== 'undefined')
|
|
164
|
+
DefaultMap.prototype[Symbol.iterator] = DefaultMap.prototype.entries;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Convenience known methods.
|
|
168
|
+
*/
|
|
169
|
+
DefaultMap.prototype.inspect = function() {
|
|
170
|
+
return this.items;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
if (typeof Symbol !== 'undefined')
|
|
174
|
+
DefaultMap.prototype[Symbol.for('nodejs.util.inspect.custom')] = DefaultMap.prototype.inspect;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Typical factories.
|
|
178
|
+
*/
|
|
179
|
+
DefaultMap.autoIncrement = function() {
|
|
180
|
+
var i = 0;
|
|
181
|
+
|
|
182
|
+
return function() {
|
|
183
|
+
return i++;
|
|
184
|
+
};
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Exporting.
|
|
189
|
+
*/
|
|
190
|
+
defaultMap = DefaultMap;
|
|
191
|
+
return defaultMap;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
var defaultMapExports = requireDefaultMap();
|
|
195
|
+
const DefaultMap = /*@__PURE__*/getDefaultExportFromCjs(defaultMapExports);
|
|
196
|
+
|
|
197
|
+
var naturalCompareLite = {exports: {}};
|
|
198
|
+
|
|
199
|
+
var hasRequiredNaturalCompareLite;
|
|
200
|
+
|
|
201
|
+
function requireNaturalCompareLite () {
|
|
202
|
+
if (hasRequiredNaturalCompareLite) return naturalCompareLite.exports;
|
|
203
|
+
hasRequiredNaturalCompareLite = 1;
|
|
204
|
+
/*
|
|
205
|
+
* @version 1.4.0
|
|
206
|
+
* @date 2015-10-26
|
|
207
|
+
* @stability 3 - Stable
|
|
208
|
+
* @author Lauri Rooden (https://github.com/litejs/natural-compare-lite)
|
|
209
|
+
* @license MIT License
|
|
210
|
+
*/
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
var naturalCompare = function(a, b) {
|
|
214
|
+
var i, codeA
|
|
215
|
+
, codeB = 1
|
|
216
|
+
, posA = 0
|
|
217
|
+
, posB = 0
|
|
218
|
+
, alphabet = String.alphabet;
|
|
219
|
+
|
|
220
|
+
function getCode(str, pos, code) {
|
|
221
|
+
if (code) {
|
|
222
|
+
for (i = pos; code = getCode(str, i), code < 76 && code > 65;) ++i;
|
|
223
|
+
return +str.slice(pos - 1, i)
|
|
224
|
+
}
|
|
225
|
+
code = alphabet && alphabet.indexOf(str.charAt(pos));
|
|
226
|
+
return code > -1 ? code + 76 : ((code = str.charCodeAt(pos) || 0), code < 45 || code > 127) ? code
|
|
227
|
+
: code < 46 ? 65 // -
|
|
228
|
+
: code < 48 ? code - 1
|
|
229
|
+
: code < 58 ? code + 18 // 0-9
|
|
230
|
+
: code < 65 ? code - 11
|
|
231
|
+
: code < 91 ? code + 11 // A-Z
|
|
232
|
+
: code < 97 ? code - 37
|
|
233
|
+
: code < 123 ? code + 5 // a-z
|
|
234
|
+
: code - 63
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
if ((a+="") != (b+="")) for (;codeB;) {
|
|
239
|
+
codeA = getCode(a, posA++);
|
|
240
|
+
codeB = getCode(b, posB++);
|
|
241
|
+
|
|
242
|
+
if (codeA < 76 && codeB < 76 && codeA > 66 && codeB > 66) {
|
|
243
|
+
codeA = getCode(a, posA, posA);
|
|
244
|
+
codeB = getCode(b, posB, posA = i);
|
|
245
|
+
posB = i;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (codeA != codeB) return (codeA < codeB) ? -1 : 1
|
|
249
|
+
}
|
|
250
|
+
return 0
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
naturalCompareLite.exports = naturalCompare;
|
|
255
|
+
} catch (e) {
|
|
256
|
+
String.naturalCompare = naturalCompare;
|
|
257
|
+
}
|
|
258
|
+
return naturalCompareLite.exports;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
var naturalCompareLiteExports = requireNaturalCompareLite();
|
|
262
|
+
const compare = /*@__PURE__*/getDefaultExportFromCjs(naturalCompareLiteExports);
|
|
263
|
+
|
|
264
|
+
function compareNatural(a, b) {
|
|
265
|
+
if (a === b) return 0;
|
|
266
|
+
if (t(a)) {
|
|
267
|
+
if (t(b)) {
|
|
268
|
+
return compare(a, b);
|
|
269
|
+
}
|
|
270
|
+
return 1;
|
|
271
|
+
}
|
|
272
|
+
return t(b) ? -1 : 0;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function isString(value) {
|
|
276
|
+
return value != null && typeof value === "string";
|
|
277
|
+
}
|
|
278
|
+
function isNonEmptyArray(arr) {
|
|
279
|
+
return !!arr && Array.isArray(arr) && arr.length > 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function parentFqn(fqn) {
|
|
283
|
+
const lastDot = fqn.lastIndexOf(".");
|
|
284
|
+
if (lastDot > 0) {
|
|
285
|
+
return fqn.slice(0, lastDot);
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
function parentFqnPredicate(parent) {
|
|
290
|
+
const prefix = parent + ".";
|
|
291
|
+
return (e) => !!e.parent && (e.parent === parent || e.parent.startsWith(prefix));
|
|
292
|
+
}
|
|
293
|
+
function nameFromFqn(fqn) {
|
|
294
|
+
const lastDot = fqn.lastIndexOf(".");
|
|
295
|
+
if (lastDot > 0) {
|
|
296
|
+
return fqn.slice(lastDot + 1);
|
|
297
|
+
} else {
|
|
298
|
+
return fqn;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
function isAncestor(...args) {
|
|
302
|
+
const ancestor = isString(args[0]) ? args[0] : args[0].id;
|
|
303
|
+
const another = isString(args[1]) ? args[1] : args[1].id;
|
|
304
|
+
return another.startsWith(ancestor + ".");
|
|
305
|
+
}
|
|
306
|
+
function isSameHierarchy(one, another) {
|
|
307
|
+
const first = isString(one) ? one : one.id;
|
|
308
|
+
const second = isString(another) ? another : another.id;
|
|
309
|
+
return first === second || second.startsWith(first + ".") || first.startsWith(second + ".");
|
|
310
|
+
}
|
|
311
|
+
function isDescendantOf(ancestors) {
|
|
312
|
+
const predicates = ancestors.flatMap((a) => [(e) => e.id === a.id, (e) => isAncestor(a, e)]);
|
|
313
|
+
return (e) => predicates.some((p) => p(e));
|
|
314
|
+
}
|
|
315
|
+
function notDescendantOf(ancestors) {
|
|
316
|
+
const isDescendant = isDescendantOf(ancestors);
|
|
317
|
+
return (e) => !isDescendant(e);
|
|
318
|
+
}
|
|
319
|
+
function hierarchyDepth(elementOfFqn) {
|
|
320
|
+
const first = isString(elementOfFqn) ? elementOfFqn : elementOfFqn.id;
|
|
321
|
+
return first.split(".").length;
|
|
322
|
+
}
|
|
323
|
+
function hierarchyDistance(one, another) {
|
|
324
|
+
const first = isString(one) ? one : one.id;
|
|
325
|
+
const second = isString(another) ? another : another.id;
|
|
326
|
+
if (first === second) {
|
|
327
|
+
return 0;
|
|
328
|
+
}
|
|
329
|
+
const firstDepth = hierarchyDepth(first);
|
|
330
|
+
const secondDepth = hierarchyDepth(second);
|
|
331
|
+
if (isSameHierarchy(first, second)) {
|
|
332
|
+
return Math.abs(firstDepth - secondDepth);
|
|
333
|
+
}
|
|
334
|
+
const ancestor = commonAncestor(first, second);
|
|
335
|
+
const ancestorDepth = ancestor ? hierarchyDepth(ancestor) : 0;
|
|
336
|
+
return firstDepth + secondDepth - (2 * ancestorDepth + 1);
|
|
337
|
+
}
|
|
338
|
+
function commonAncestor(first, second) {
|
|
339
|
+
const parentA = parentFqn(first);
|
|
340
|
+
const parentB = parentFqn(second);
|
|
341
|
+
if (parentA === parentB) {
|
|
342
|
+
return parentA;
|
|
343
|
+
}
|
|
344
|
+
if (!parentA || !parentB) {
|
|
345
|
+
return null;
|
|
346
|
+
}
|
|
347
|
+
const a = first.split(".");
|
|
348
|
+
const b = second.split(".");
|
|
349
|
+
let ancestor = null;
|
|
350
|
+
while (a.length > 1 && b.length > 1 && !!a[0] && a[0] === b[0]) {
|
|
351
|
+
ancestor = ancestor ? `${ancestor}.${a[0]}` : a[0];
|
|
352
|
+
a.shift();
|
|
353
|
+
b.shift();
|
|
354
|
+
}
|
|
355
|
+
return ancestor;
|
|
356
|
+
}
|
|
357
|
+
function ancestorsFqn(fqn) {
|
|
358
|
+
const path = fqn.split(".");
|
|
359
|
+
path.pop();
|
|
360
|
+
if (path.length === 0) {
|
|
361
|
+
return [];
|
|
362
|
+
}
|
|
363
|
+
return path.reduce((acc, part, idx) => {
|
|
364
|
+
if (idx === 0) {
|
|
365
|
+
acc.push(part);
|
|
366
|
+
return acc;
|
|
367
|
+
}
|
|
368
|
+
acc.unshift(`${acc[0]}.${part}`);
|
|
369
|
+
return acc;
|
|
370
|
+
}, []);
|
|
371
|
+
}
|
|
372
|
+
function compareFqnHierarchically(a, b) {
|
|
373
|
+
const depthA = a.split(".").length;
|
|
374
|
+
const depthB = b.split(".").length;
|
|
375
|
+
switch (true) {
|
|
376
|
+
case depthA > depthB: {
|
|
377
|
+
return 1;
|
|
378
|
+
}
|
|
379
|
+
case depthA < depthB: {
|
|
380
|
+
return -1;
|
|
381
|
+
}
|
|
382
|
+
default: {
|
|
383
|
+
return 0;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
function compareByFqnHierarchically(a, b) {
|
|
388
|
+
return compareFqnHierarchically(a.id, b.id);
|
|
389
|
+
}
|
|
390
|
+
function sortByFqnHierarchically(array) {
|
|
391
|
+
return array.map((item) => ({ item, fqn: item.id.split(".") })).sort((a, b) => {
|
|
392
|
+
return a.fqn.length - b.fqn.length;
|
|
393
|
+
}).map(({ item }) => item);
|
|
394
|
+
}
|
|
395
|
+
function sortParentsFirst(array) {
|
|
396
|
+
const result = [];
|
|
397
|
+
const items = [...array];
|
|
398
|
+
let item;
|
|
399
|
+
while (item = items.shift()) {
|
|
400
|
+
const itemId = item.id;
|
|
401
|
+
let parentIndx;
|
|
402
|
+
while ((parentIndx = items.findIndex((parent) => isAncestor(parent.id, itemId))) !== -1) {
|
|
403
|
+
result.push(...items.splice(parentIndx, 1));
|
|
404
|
+
}
|
|
405
|
+
result.push(item);
|
|
406
|
+
}
|
|
407
|
+
return result;
|
|
408
|
+
}
|
|
409
|
+
function sortNaturalByFqn(array) {
|
|
410
|
+
return array.map((item) => ({ item, fqn: item.id.split(".") })).sort((a, b) => {
|
|
411
|
+
if (a.fqn.length !== b.fqn.length) {
|
|
412
|
+
return a.fqn.length - b.fqn.length;
|
|
413
|
+
}
|
|
414
|
+
for (let i = 0; i < a.fqn.length; i++) {
|
|
415
|
+
const compare = compareNatural(a.fqn[i], b.fqn[i]);
|
|
416
|
+
if (compare !== 0) {
|
|
417
|
+
return compare;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return 0;
|
|
421
|
+
}).map(({ item }) => item);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function getOrCreate(map, key, create) {
|
|
425
|
+
let entry = map.get(key);
|
|
426
|
+
if (!entry) {
|
|
427
|
+
entry = create(key);
|
|
428
|
+
map.set(key, entry);
|
|
429
|
+
}
|
|
430
|
+
return entry;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
var set = {};
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Mnemonist Set
|
|
437
|
+
* ==============
|
|
438
|
+
*
|
|
439
|
+
* Useful function related to sets such as union, intersection and so on...
|
|
440
|
+
*/
|
|
441
|
+
|
|
442
|
+
var hasRequiredSet;
|
|
443
|
+
|
|
444
|
+
function requireSet () {
|
|
445
|
+
if (hasRequiredSet) return set;
|
|
446
|
+
hasRequiredSet = 1;
|
|
447
|
+
(function (exports) {
|
|
448
|
+
// TODO: optimize versions for less variadicities
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Variadic function computing the intersection of multiple sets.
|
|
452
|
+
*
|
|
453
|
+
* @param {...Set} sets - Sets to intersect.
|
|
454
|
+
* @return {Set} - The intesection.
|
|
455
|
+
*/
|
|
456
|
+
exports.intersection = function() {
|
|
457
|
+
if (arguments.length < 2)
|
|
458
|
+
throw new Error('mnemonist/Set.intersection: needs at least two arguments.');
|
|
459
|
+
|
|
460
|
+
var I = new Set();
|
|
461
|
+
|
|
462
|
+
// First we need to find the smallest set
|
|
463
|
+
var smallestSize = Infinity,
|
|
464
|
+
smallestSet = null;
|
|
465
|
+
|
|
466
|
+
var s, i, l = arguments.length;
|
|
467
|
+
|
|
468
|
+
for (i = 0; i < l; i++) {
|
|
469
|
+
s = arguments[i];
|
|
470
|
+
|
|
471
|
+
// If one of the set has no items, we can stop right there
|
|
472
|
+
if (s.size === 0)
|
|
473
|
+
return I;
|
|
474
|
+
|
|
475
|
+
if (s.size < smallestSize) {
|
|
476
|
+
smallestSize = s.size;
|
|
477
|
+
smallestSet = s;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Now we need to intersect this set with the others
|
|
482
|
+
var iterator = smallestSet.values(),
|
|
483
|
+
step,
|
|
484
|
+
item,
|
|
485
|
+
add,
|
|
486
|
+
set;
|
|
487
|
+
|
|
488
|
+
// TODO: we can optimize by iterating each next time over the current intersection
|
|
489
|
+
// but this probably means more RAM to consume since we'll create n-1 sets rather than
|
|
490
|
+
// only the one.
|
|
491
|
+
while ((step = iterator.next(), !step.done)) {
|
|
492
|
+
item = step.value;
|
|
493
|
+
add = true;
|
|
494
|
+
|
|
495
|
+
for (i = 0; i < l; i++) {
|
|
496
|
+
set = arguments[i];
|
|
497
|
+
|
|
498
|
+
if (set === smallestSet)
|
|
499
|
+
continue;
|
|
500
|
+
|
|
501
|
+
if (!set.has(item)) {
|
|
502
|
+
add = false;
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if (add)
|
|
508
|
+
I.add(item);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return I;
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* Variadic function computing the union of multiple sets.
|
|
516
|
+
*
|
|
517
|
+
* @param {...Set} sets - Sets to unite.
|
|
518
|
+
* @return {Set} - The union.
|
|
519
|
+
*/
|
|
520
|
+
exports.union = function() {
|
|
521
|
+
if (arguments.length < 2)
|
|
522
|
+
throw new Error('mnemonist/Set.union: needs at least two arguments.');
|
|
523
|
+
|
|
524
|
+
var U = new Set();
|
|
525
|
+
|
|
526
|
+
var i, l = arguments.length;
|
|
527
|
+
|
|
528
|
+
var iterator,
|
|
529
|
+
step;
|
|
530
|
+
|
|
531
|
+
for (i = 0; i < l; i++) {
|
|
532
|
+
iterator = arguments[i].values();
|
|
533
|
+
|
|
534
|
+
while ((step = iterator.next(), !step.done))
|
|
535
|
+
U.add(step.value);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
return U;
|
|
539
|
+
};
|
|
540
|
+
|
|
541
|
+
/**
|
|
542
|
+
* Function computing the difference between two sets.
|
|
543
|
+
*
|
|
544
|
+
* @param {Set} A - First set.
|
|
545
|
+
* @param {Set} B - Second set.
|
|
546
|
+
* @return {Set} - The difference.
|
|
547
|
+
*/
|
|
548
|
+
exports.difference = function(A, B) {
|
|
549
|
+
|
|
550
|
+
// If first set is empty
|
|
551
|
+
if (!A.size)
|
|
552
|
+
return new Set();
|
|
553
|
+
|
|
554
|
+
if (!B.size)
|
|
555
|
+
return new Set(A);
|
|
556
|
+
|
|
557
|
+
var D = new Set();
|
|
558
|
+
|
|
559
|
+
var iterator = A.values(),
|
|
560
|
+
step;
|
|
561
|
+
|
|
562
|
+
while ((step = iterator.next(), !step.done)) {
|
|
563
|
+
if (!B.has(step.value))
|
|
564
|
+
D.add(step.value);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
return D;
|
|
568
|
+
};
|
|
569
|
+
|
|
570
|
+
/**
|
|
571
|
+
* Function computing the symmetric difference between two sets.
|
|
572
|
+
*
|
|
573
|
+
* @param {Set} A - First set.
|
|
574
|
+
* @param {Set} B - Second set.
|
|
575
|
+
* @return {Set} - The symmetric difference.
|
|
576
|
+
*/
|
|
577
|
+
exports.symmetricDifference = function(A, B) {
|
|
578
|
+
var S = new Set();
|
|
579
|
+
|
|
580
|
+
var iterator = A.values(),
|
|
581
|
+
step;
|
|
582
|
+
|
|
583
|
+
while ((step = iterator.next(), !step.done)) {
|
|
584
|
+
if (!B.has(step.value))
|
|
585
|
+
S.add(step.value);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
iterator = B.values();
|
|
589
|
+
|
|
590
|
+
while ((step = iterator.next(), !step.done)) {
|
|
591
|
+
if (!A.has(step.value))
|
|
592
|
+
S.add(step.value);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
return S;
|
|
596
|
+
};
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Function returning whether A is a subset of B.
|
|
600
|
+
*
|
|
601
|
+
* @param {Set} A - First set.
|
|
602
|
+
* @param {Set} B - Second set.
|
|
603
|
+
* @return {boolean}
|
|
604
|
+
*/
|
|
605
|
+
exports.isSubset = function(A, B) {
|
|
606
|
+
var iterator = A.values(),
|
|
607
|
+
step;
|
|
608
|
+
|
|
609
|
+
// Shortcuts
|
|
610
|
+
if (A === B)
|
|
611
|
+
return true;
|
|
612
|
+
|
|
613
|
+
if (A.size > B.size)
|
|
614
|
+
return false;
|
|
615
|
+
|
|
616
|
+
while ((step = iterator.next(), !step.done)) {
|
|
617
|
+
if (!B.has(step.value))
|
|
618
|
+
return false;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return true;
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Function returning whether A is a superset of B.
|
|
626
|
+
*
|
|
627
|
+
* @param {Set} A - First set.
|
|
628
|
+
* @param {Set} B - Second set.
|
|
629
|
+
* @return {boolean}
|
|
630
|
+
*/
|
|
631
|
+
exports.isSuperset = function(A, B) {
|
|
632
|
+
return exports.isSubset(B, A);
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Function adding the items of set B to the set A.
|
|
637
|
+
*
|
|
638
|
+
* @param {Set} A - First set.
|
|
639
|
+
* @param {Set} B - Second set.
|
|
640
|
+
*/
|
|
641
|
+
exports.add = function(A, B) {
|
|
642
|
+
var iterator = B.values(),
|
|
643
|
+
step;
|
|
644
|
+
|
|
645
|
+
while ((step = iterator.next(), !step.done))
|
|
646
|
+
A.add(step.value);
|
|
647
|
+
|
|
648
|
+
return;
|
|
649
|
+
};
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Function subtracting the items of set B from the set A.
|
|
653
|
+
*
|
|
654
|
+
* @param {Set} A - First set.
|
|
655
|
+
* @param {Set} B - Second set.
|
|
656
|
+
*/
|
|
657
|
+
exports.subtract = function(A, B) {
|
|
658
|
+
var iterator = B.values(),
|
|
659
|
+
step;
|
|
660
|
+
|
|
661
|
+
while ((step = iterator.next(), !step.done))
|
|
662
|
+
A.delete(step.value);
|
|
663
|
+
|
|
664
|
+
return;
|
|
665
|
+
};
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Function intersecting the items of A & B.
|
|
669
|
+
*
|
|
670
|
+
* @param {Set} A - First set.
|
|
671
|
+
* @param {Set} B - Second set.
|
|
672
|
+
*/
|
|
673
|
+
exports.intersect = function(A, B) {
|
|
674
|
+
var iterator = A.values(),
|
|
675
|
+
step;
|
|
676
|
+
|
|
677
|
+
while ((step = iterator.next(), !step.done)) {
|
|
678
|
+
if (!B.has(step.value))
|
|
679
|
+
A.delete(step.value);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
return;
|
|
683
|
+
};
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* Function disjuncting the items of A & B.
|
|
687
|
+
*
|
|
688
|
+
* @param {Set} A - First set.
|
|
689
|
+
* @param {Set} B - Second set.
|
|
690
|
+
*/
|
|
691
|
+
exports.disjunct = function(A, B) {
|
|
692
|
+
var iterator = A.values(),
|
|
693
|
+
step;
|
|
694
|
+
|
|
695
|
+
var toRemove = [];
|
|
696
|
+
|
|
697
|
+
while ((step = iterator.next(), !step.done)) {
|
|
698
|
+
if (B.has(step.value))
|
|
699
|
+
toRemove.push(step.value);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
iterator = B.values();
|
|
703
|
+
|
|
704
|
+
while ((step = iterator.next(), !step.done)) {
|
|
705
|
+
if (!A.has(step.value))
|
|
706
|
+
A.add(step.value);
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
for (var i = 0, l = toRemove.length; i < l; i++)
|
|
710
|
+
A.delete(toRemove[i]);
|
|
711
|
+
|
|
712
|
+
return;
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* Function returning the size of the intersection of A & B.
|
|
717
|
+
*
|
|
718
|
+
* @param {Set} A - First set.
|
|
719
|
+
* @param {Set} B - Second set.
|
|
720
|
+
* @return {number}
|
|
721
|
+
*/
|
|
722
|
+
exports.intersectionSize = function(A, B) {
|
|
723
|
+
var tmp;
|
|
724
|
+
|
|
725
|
+
// We need to know the smallest set
|
|
726
|
+
if (A.size > B.size) {
|
|
727
|
+
tmp = A;
|
|
728
|
+
A = B;
|
|
729
|
+
B = tmp;
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
if (A.size === 0)
|
|
733
|
+
return 0;
|
|
734
|
+
|
|
735
|
+
if (A === B)
|
|
736
|
+
return A.size;
|
|
737
|
+
|
|
738
|
+
var iterator = A.values(),
|
|
739
|
+
step;
|
|
740
|
+
|
|
741
|
+
var I = 0;
|
|
742
|
+
|
|
743
|
+
while ((step = iterator.next(), !step.done)) {
|
|
744
|
+
if (B.has(step.value))
|
|
745
|
+
I++;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
return I;
|
|
749
|
+
};
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* Function returning the size of the union of A & B.
|
|
753
|
+
*
|
|
754
|
+
* @param {Set} A - First set.
|
|
755
|
+
* @param {Set} B - Second set.
|
|
756
|
+
* @return {number}
|
|
757
|
+
*/
|
|
758
|
+
exports.unionSize = function(A, B) {
|
|
759
|
+
var I = exports.intersectionSize(A, B);
|
|
760
|
+
|
|
761
|
+
return A.size + B.size - I;
|
|
762
|
+
};
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* Function returning the Jaccard similarity between A & B.
|
|
766
|
+
*
|
|
767
|
+
* @param {Set} A - First set.
|
|
768
|
+
* @param {Set} B - Second set.
|
|
769
|
+
* @return {number}
|
|
770
|
+
*/
|
|
771
|
+
exports.jaccard = function(A, B) {
|
|
772
|
+
var I = exports.intersectionSize(A, B);
|
|
773
|
+
|
|
774
|
+
if (I === 0)
|
|
775
|
+
return 0;
|
|
776
|
+
|
|
777
|
+
var U = A.size + B.size - I;
|
|
778
|
+
|
|
779
|
+
return I / U;
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Function returning the overlap coefficient between A & B.
|
|
784
|
+
*
|
|
785
|
+
* @param {Set} A - First set.
|
|
786
|
+
* @param {Set} B - Second set.
|
|
787
|
+
* @return {number}
|
|
788
|
+
*/
|
|
789
|
+
exports.overlap = function(A, B) {
|
|
790
|
+
var I = exports.intersectionSize(A, B);
|
|
791
|
+
|
|
792
|
+
if (I === 0)
|
|
793
|
+
return 0;
|
|
794
|
+
|
|
795
|
+
return I / Math.min(A.size, B.size);
|
|
796
|
+
};
|
|
797
|
+
} (set));
|
|
798
|
+
return set;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
var setExports = requireSet();
|
|
802
|
+
|
|
803
|
+
function union(...sets) {
|
|
804
|
+
return setExports.union(...sets);
|
|
805
|
+
}
|
|
806
|
+
function intersection(first, ...sets) {
|
|
807
|
+
let result = /* @__PURE__ */ new Set();
|
|
808
|
+
if (first.size === 0) {
|
|
809
|
+
return result;
|
|
810
|
+
}
|
|
811
|
+
let other = sets.length > 1 ? setExports.intersection(...sets) : sets[0];
|
|
812
|
+
if (other.size === 0) {
|
|
813
|
+
return result;
|
|
814
|
+
}
|
|
815
|
+
for (const value of first) {
|
|
816
|
+
if (other.has(value)) {
|
|
817
|
+
result.add(value);
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
return result;
|
|
821
|
+
}
|
|
822
|
+
function difference(a, b) {
|
|
823
|
+
if (a.size === 0) {
|
|
824
|
+
return /* @__PURE__ */ new Set();
|
|
825
|
+
}
|
|
826
|
+
if (b.size === 0) {
|
|
827
|
+
return new Set(a);
|
|
828
|
+
}
|
|
829
|
+
let result = /* @__PURE__ */ new Set();
|
|
830
|
+
for (const value of a) {
|
|
831
|
+
if (!b.has(value)) {
|
|
832
|
+
result.add(value);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
return result;
|
|
836
|
+
}
|
|
837
|
+
function equals(a, b) {
|
|
838
|
+
return a.size === b.size && [...a].every((value) => b.has(value));
|
|
839
|
+
}
|
|
840
|
+
function symmetricDifference(a, b) {
|
|
841
|
+
return setExports.symmetricDifference(a, b);
|
|
842
|
+
}
|
|
843
|
+
function hasIntersection(a, b) {
|
|
844
|
+
if (a.size === 0 || b.size === 0) {
|
|
845
|
+
return false;
|
|
846
|
+
}
|
|
847
|
+
if (b.size < a.size) {
|
|
848
|
+
[a, b] = [b, a];
|
|
849
|
+
}
|
|
850
|
+
for (const value of a) {
|
|
851
|
+
if (b.has(value)) {
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
return false;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
class DeploymentElementModel {
|
|
859
|
+
get id() {
|
|
860
|
+
return this.$node.id;
|
|
861
|
+
}
|
|
862
|
+
get style() {
|
|
863
|
+
return {
|
|
864
|
+
shape: DefaultElementShape,
|
|
865
|
+
color: DefaultThemeColor,
|
|
866
|
+
...this.$node.style
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
get shape() {
|
|
870
|
+
return this.$node.style?.shape ?? DefaultElementShape;
|
|
871
|
+
}
|
|
872
|
+
get color() {
|
|
873
|
+
return this.$node.style?.color ?? DefaultThemeColor;
|
|
874
|
+
}
|
|
875
|
+
get tags() {
|
|
876
|
+
return this.$node.tags ?? [];
|
|
877
|
+
}
|
|
878
|
+
get title() {
|
|
879
|
+
return this.$node.title ?? nameFromFqn(this.id);
|
|
880
|
+
}
|
|
881
|
+
get description() {
|
|
882
|
+
return this.$node.description ?? null;
|
|
883
|
+
}
|
|
884
|
+
get technology() {
|
|
885
|
+
return this.$node.technology ?? null;
|
|
886
|
+
}
|
|
887
|
+
get parent() {
|
|
888
|
+
return this.$model.parent(this);
|
|
889
|
+
}
|
|
890
|
+
get links() {
|
|
891
|
+
return this.$node.links ?? [];
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
895
|
+
* (from closest to root)
|
|
896
|
+
*/
|
|
897
|
+
ancestors() {
|
|
898
|
+
return this.$model.ancestors(this);
|
|
899
|
+
}
|
|
900
|
+
/**
|
|
901
|
+
* Returns the common ancestor of this element and another element.
|
|
902
|
+
*/
|
|
903
|
+
commonAncestor(another) {
|
|
904
|
+
const common = commonAncestor(this.id, another.id);
|
|
905
|
+
return common ? this.$model.node(common) : null;
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Get all sibling (i.e. same parent)
|
|
909
|
+
*/
|
|
910
|
+
siblings() {
|
|
911
|
+
return this.$model.siblings(this);
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Check if the element is a sibling of another element
|
|
915
|
+
*/
|
|
916
|
+
isSibling(other) {
|
|
917
|
+
return this.parent === other.parent;
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Resolve siblings of the element and its ancestors
|
|
921
|
+
* (from closest to root)
|
|
922
|
+
*/
|
|
923
|
+
*ascendingSiblings() {
|
|
924
|
+
yield* this.siblings();
|
|
925
|
+
for (const ancestor of this.ancestors()) {
|
|
926
|
+
yield* ancestor.siblings();
|
|
927
|
+
}
|
|
928
|
+
return;
|
|
929
|
+
}
|
|
930
|
+
incoming(filter = "all") {
|
|
931
|
+
return this.$model.incoming(this, filter);
|
|
932
|
+
}
|
|
933
|
+
outgoing(filter = "all") {
|
|
934
|
+
return this.$model.outgoing(this, filter);
|
|
935
|
+
}
|
|
936
|
+
*incomers(filter = "all") {
|
|
937
|
+
const unique = /* @__PURE__ */ new Set();
|
|
938
|
+
for (const r of this.incoming(filter)) {
|
|
939
|
+
if (unique.has(r.source.id)) {
|
|
940
|
+
continue;
|
|
941
|
+
}
|
|
942
|
+
unique.add(r.source.id);
|
|
943
|
+
yield r.source;
|
|
944
|
+
}
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
*outgoers(filter = "all") {
|
|
948
|
+
const unique = /* @__PURE__ */ new Set();
|
|
949
|
+
for (const r of this.outgoing(filter)) {
|
|
950
|
+
if (unique.has(r.target.id)) {
|
|
951
|
+
continue;
|
|
952
|
+
}
|
|
953
|
+
unique.add(r.target.id);
|
|
954
|
+
yield r.target;
|
|
955
|
+
}
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Iterate over all views that include this deployment element.
|
|
960
|
+
*/
|
|
961
|
+
*views() {
|
|
962
|
+
for (const view of this.$model.views()) {
|
|
963
|
+
if (view.includesDeployment(this.id)) {
|
|
964
|
+
yield view;
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
// type guard
|
|
969
|
+
isDeploymentNode() {
|
|
970
|
+
return false;
|
|
971
|
+
}
|
|
972
|
+
// type guard
|
|
973
|
+
isInstance() {
|
|
974
|
+
return false;
|
|
975
|
+
}
|
|
976
|
+
cachedOutgoing = null;
|
|
977
|
+
cachedIncoming = null;
|
|
978
|
+
get allOutgoing() {
|
|
979
|
+
this.cachedOutgoing ??= new RelationshipsAccum(
|
|
980
|
+
new Set(this.outgoingFromModel()),
|
|
981
|
+
new Set(this.outgoing())
|
|
982
|
+
);
|
|
983
|
+
return this.cachedOutgoing;
|
|
984
|
+
}
|
|
985
|
+
get allIncoming() {
|
|
986
|
+
this.cachedIncoming ??= new RelationshipsAccum(
|
|
987
|
+
new Set(this.incomingFromModel()),
|
|
988
|
+
new Set(this.incoming())
|
|
989
|
+
);
|
|
990
|
+
return this.cachedIncoming;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
class DeploymentNodeModel extends DeploymentElementModel {
|
|
994
|
+
constructor($model, $node) {
|
|
995
|
+
super();
|
|
996
|
+
this.$model = $model;
|
|
997
|
+
this.$node = $node;
|
|
998
|
+
}
|
|
999
|
+
get kind() {
|
|
1000
|
+
return this.$node.kind;
|
|
1001
|
+
}
|
|
1002
|
+
children() {
|
|
1003
|
+
return this.$model.children(this);
|
|
1004
|
+
}
|
|
1005
|
+
descendants() {
|
|
1006
|
+
return this.$model.descendants(this);
|
|
1007
|
+
}
|
|
1008
|
+
isDeploymentNode() {
|
|
1009
|
+
return true;
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* Iterate over all instances nested in this deployment node.
|
|
1013
|
+
*/
|
|
1014
|
+
*instances() {
|
|
1015
|
+
for (const nested of this.descendants()) {
|
|
1016
|
+
if (nested.isInstance()) {
|
|
1017
|
+
yield nested;
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Returns deployed instance inside this deployment node
|
|
1024
|
+
* if only there are no more instances
|
|
1025
|
+
*/
|
|
1026
|
+
onlyOneInstance() {
|
|
1027
|
+
const children = this.children();
|
|
1028
|
+
if (children.size !== 1) {
|
|
1029
|
+
return null;
|
|
1030
|
+
}
|
|
1031
|
+
const child = t$1([...children]);
|
|
1032
|
+
return child?.isInstance() ? child : null;
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Cached result of relationships from instances
|
|
1036
|
+
*/
|
|
1037
|
+
_relationshipsFromInstances = null;
|
|
1038
|
+
relationshipsFromInstances() {
|
|
1039
|
+
if (this._relationshipsFromInstances) {
|
|
1040
|
+
return this._relationshipsFromInstances;
|
|
1041
|
+
}
|
|
1042
|
+
const {
|
|
1043
|
+
outgoing,
|
|
1044
|
+
incoming
|
|
1045
|
+
} = this._relationshipsFromInstances = {
|
|
1046
|
+
outgoing: /* @__PURE__ */ new Set(),
|
|
1047
|
+
incoming: /* @__PURE__ */ new Set()
|
|
1048
|
+
};
|
|
1049
|
+
for (const instance of this.instances()) {
|
|
1050
|
+
for (const r of instance.$element.outgoing()) {
|
|
1051
|
+
outgoing.add(r);
|
|
1052
|
+
}
|
|
1053
|
+
for (const r of instance.$element.incoming()) {
|
|
1054
|
+
incoming.add(r);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
return this._relationshipsFromInstances;
|
|
1058
|
+
}
|
|
1059
|
+
/**
|
|
1060
|
+
* We return only relationships that are not already present in nested instances
|
|
1061
|
+
*/
|
|
1062
|
+
outgoingFromModel() {
|
|
1063
|
+
const {
|
|
1064
|
+
outgoing,
|
|
1065
|
+
incoming
|
|
1066
|
+
} = this.relationshipsFromInstances();
|
|
1067
|
+
return difference(outgoing, incoming).values();
|
|
1068
|
+
}
|
|
1069
|
+
/**
|
|
1070
|
+
* We return only relationships that are not already present in nested instances
|
|
1071
|
+
*/
|
|
1072
|
+
incomingFromModel() {
|
|
1073
|
+
const {
|
|
1074
|
+
outgoing,
|
|
1075
|
+
incoming
|
|
1076
|
+
} = this.relationshipsFromInstances();
|
|
1077
|
+
return difference(incoming, outgoing).values();
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
class DeployedInstanceModel extends DeploymentElementModel {
|
|
1081
|
+
constructor($model, $instance, $element) {
|
|
1082
|
+
super();
|
|
1083
|
+
this.$model = $model;
|
|
1084
|
+
this.$instance = $instance;
|
|
1085
|
+
this.$element = $element;
|
|
1086
|
+
}
|
|
1087
|
+
get parent() {
|
|
1088
|
+
return nonNullable(this.$model.parent(this), `Parent of ${this.id} not found`);
|
|
1089
|
+
}
|
|
1090
|
+
get $node() {
|
|
1091
|
+
return this.$instance;
|
|
1092
|
+
}
|
|
1093
|
+
get style() {
|
|
1094
|
+
const { icon, style } = this.$element.$element;
|
|
1095
|
+
return {
|
|
1096
|
+
shape: this.$element.shape,
|
|
1097
|
+
color: this.$element.color,
|
|
1098
|
+
...icon && { icon },
|
|
1099
|
+
...style,
|
|
1100
|
+
...this.$instance.style
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
get shape() {
|
|
1104
|
+
return this.$instance.style?.shape ?? this.$element.shape;
|
|
1105
|
+
}
|
|
1106
|
+
get color() {
|
|
1107
|
+
return this.$instance.style?.color ?? this.$element.color;
|
|
1108
|
+
}
|
|
1109
|
+
get tags() {
|
|
1110
|
+
return this.$instance.tags ?? [];
|
|
1111
|
+
}
|
|
1112
|
+
get title() {
|
|
1113
|
+
return this.$instance.title ?? this.$element.title;
|
|
1114
|
+
}
|
|
1115
|
+
get description() {
|
|
1116
|
+
return this.$instance.description ?? this.$element.description;
|
|
1117
|
+
}
|
|
1118
|
+
get technology() {
|
|
1119
|
+
return this.$instance.technology ?? this.$element.technology;
|
|
1120
|
+
}
|
|
1121
|
+
get links() {
|
|
1122
|
+
return this.$instance.links ?? this.$element.links;
|
|
1123
|
+
}
|
|
1124
|
+
isInstance() {
|
|
1125
|
+
return true;
|
|
1126
|
+
}
|
|
1127
|
+
outgoingFromModel() {
|
|
1128
|
+
return this.$element.outgoing();
|
|
1129
|
+
}
|
|
1130
|
+
incomingFromModel() {
|
|
1131
|
+
return this.$element.incoming();
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
class NestedElementOfDeployedInstanceModel {
|
|
1135
|
+
constructor(instance, element) {
|
|
1136
|
+
this.instance = instance;
|
|
1137
|
+
this.element = element;
|
|
1138
|
+
}
|
|
1139
|
+
get id() {
|
|
1140
|
+
return this.instance.id;
|
|
1141
|
+
}
|
|
1142
|
+
get style() {
|
|
1143
|
+
const { icon, style } = this.element.$element;
|
|
1144
|
+
return {
|
|
1145
|
+
shape: this.element.shape,
|
|
1146
|
+
color: this.element.color,
|
|
1147
|
+
...icon && { icon },
|
|
1148
|
+
...style
|
|
1149
|
+
};
|
|
1150
|
+
}
|
|
1151
|
+
get shape() {
|
|
1152
|
+
return this.element.shape;
|
|
1153
|
+
}
|
|
1154
|
+
get color() {
|
|
1155
|
+
return this.element.color;
|
|
1156
|
+
}
|
|
1157
|
+
get title() {
|
|
1158
|
+
return this.element.title;
|
|
1159
|
+
}
|
|
1160
|
+
get description() {
|
|
1161
|
+
return this.element.description;
|
|
1162
|
+
}
|
|
1163
|
+
get technology() {
|
|
1164
|
+
return this.element.technology;
|
|
1165
|
+
}
|
|
1166
|
+
isDeploymentNode() {
|
|
1167
|
+
return false;
|
|
1168
|
+
}
|
|
1169
|
+
isInstance() {
|
|
1170
|
+
return false;
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
class DeploymentRelationModel {
|
|
1174
|
+
constructor($model, $relationship) {
|
|
1175
|
+
this.$model = $model;
|
|
1176
|
+
this.$relationship = $relationship;
|
|
1177
|
+
this.source = $model.deploymentRef($relationship.source);
|
|
1178
|
+
this.target = $model.deploymentRef($relationship.target);
|
|
1179
|
+
const parent = commonAncestor(this.source.id, this.target.id);
|
|
1180
|
+
this.boundary = parent ? this.$model.node(parent) : null;
|
|
1181
|
+
}
|
|
1182
|
+
boundary;
|
|
1183
|
+
source;
|
|
1184
|
+
target;
|
|
1185
|
+
get id() {
|
|
1186
|
+
return this.$relationship.id;
|
|
1187
|
+
}
|
|
1188
|
+
get expression() {
|
|
1189
|
+
return `${this.source.id} -> ${this.target.id}`;
|
|
1190
|
+
}
|
|
1191
|
+
get title() {
|
|
1192
|
+
if (n(this.$relationship.title)) {
|
|
1193
|
+
return null;
|
|
1194
|
+
}
|
|
1195
|
+
return this.$relationship.title;
|
|
1196
|
+
}
|
|
1197
|
+
get technology() {
|
|
1198
|
+
if (n(this.$relationship.technology)) {
|
|
1199
|
+
return null;
|
|
1200
|
+
}
|
|
1201
|
+
return this.$relationship.technology;
|
|
1202
|
+
}
|
|
1203
|
+
get description() {
|
|
1204
|
+
if (n(this.$relationship.description)) {
|
|
1205
|
+
return null;
|
|
1206
|
+
}
|
|
1207
|
+
return this.$relationship.description;
|
|
1208
|
+
}
|
|
1209
|
+
get tags() {
|
|
1210
|
+
return this.$relationship.tags ?? [];
|
|
1211
|
+
}
|
|
1212
|
+
get navigateTo() {
|
|
1213
|
+
return this.$relationship.navigateTo ? this.$model.$model.view(this.$relationship.navigateTo) : null;
|
|
1214
|
+
}
|
|
1215
|
+
get links() {
|
|
1216
|
+
return this.$relationship.links ?? [];
|
|
1217
|
+
}
|
|
1218
|
+
*views() {
|
|
1219
|
+
for (const view of this.$model.views()) {
|
|
1220
|
+
if (view.includesRelation(this.id)) {
|
|
1221
|
+
yield view;
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
return;
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
class RelationshipsAccum {
|
|
1228
|
+
/**
|
|
1229
|
+
* @param model relationships from logical model
|
|
1230
|
+
* @param deployment relationships from deployment model
|
|
1231
|
+
*/
|
|
1232
|
+
constructor(model, deployment) {
|
|
1233
|
+
this.model = model;
|
|
1234
|
+
this.deployment = deployment;
|
|
1235
|
+
}
|
|
1236
|
+
get isEmpty() {
|
|
1237
|
+
return this.model.size === 0 && this.deployment.size === 0;
|
|
1238
|
+
}
|
|
1239
|
+
get nonEmpty() {
|
|
1240
|
+
return this.model.size > 0 || this.deployment.size > 0;
|
|
1241
|
+
}
|
|
1242
|
+
get size() {
|
|
1243
|
+
return this.model.size + this.deployment.size;
|
|
1244
|
+
}
|
|
1245
|
+
/**
|
|
1246
|
+
* Returns new Accum containing all the elements which are both in this and otherAccum
|
|
1247
|
+
*/
|
|
1248
|
+
intersect(otherAccum) {
|
|
1249
|
+
return new RelationshipsAccum(
|
|
1250
|
+
intersection(this.model, otherAccum.model),
|
|
1251
|
+
intersection(this.deployment, otherAccum.deployment)
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
/**
|
|
1255
|
+
* Returns new Accum containing all the elements which are both in this and otherAccum
|
|
1256
|
+
*/
|
|
1257
|
+
difference(otherAccum) {
|
|
1258
|
+
return new RelationshipsAccum(
|
|
1259
|
+
difference(this.model, otherAccum.model),
|
|
1260
|
+
difference(this.deployment, otherAccum.deployment)
|
|
1261
|
+
);
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Returns new Accum containing all the elements from both
|
|
1265
|
+
*/
|
|
1266
|
+
union(otherAccum) {
|
|
1267
|
+
return new RelationshipsAccum(
|
|
1268
|
+
union(this.model, otherAccum.model),
|
|
1269
|
+
union(this.deployment, otherAccum.deployment)
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
function getId(element) {
|
|
1275
|
+
return isString(element) ? element : element.id;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
class LikeC4DeploymentModel {
|
|
1279
|
+
constructor($model, $deployments) {
|
|
1280
|
+
this.$model = $model;
|
|
1281
|
+
this.$deployments = $deployments;
|
|
1282
|
+
for (const element of r($deployments.elements)) {
|
|
1283
|
+
const el = this.addElement(element);
|
|
1284
|
+
for (const tag of el.tags) {
|
|
1285
|
+
this.#allTags.get(tag).add(el);
|
|
1286
|
+
}
|
|
1287
|
+
if (el.isInstance()) {
|
|
1288
|
+
this.#instancesOf.get(el.$element.id).add(el);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
for (const relation of r($deployments.relations)) {
|
|
1292
|
+
const el = this.addRelation(relation);
|
|
1293
|
+
for (const tag of el.tags) {
|
|
1294
|
+
this.#allTags.get(tag).add(el);
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
#elements = /* @__PURE__ */ new Map();
|
|
1299
|
+
// Parent element for given FQN
|
|
1300
|
+
#parents = /* @__PURE__ */ new Map();
|
|
1301
|
+
// Children elements for given FQN
|
|
1302
|
+
#children = new DefaultMap(() => /* @__PURE__ */ new Set());
|
|
1303
|
+
// Keep track of instances of the logical element
|
|
1304
|
+
#instancesOf = new DefaultMap(() => /* @__PURE__ */ new Set());
|
|
1305
|
+
#rootElements = /* @__PURE__ */ new Set();
|
|
1306
|
+
#relations = /* @__PURE__ */ new Map();
|
|
1307
|
+
// Incoming to an element or its descendants
|
|
1308
|
+
#incoming = new DefaultMap(() => /* @__PURE__ */ new Set());
|
|
1309
|
+
// Outgoing from an element or its descendants
|
|
1310
|
+
#outgoing = new DefaultMap(() => /* @__PURE__ */ new Set());
|
|
1311
|
+
// Relationships inside the element, among descendants
|
|
1312
|
+
#internal = new DefaultMap(() => /* @__PURE__ */ new Set());
|
|
1313
|
+
// readonly #views = new Map<ViewID, LikeC4ViewModel<M>>()
|
|
1314
|
+
#allTags = new DefaultMap(
|
|
1315
|
+
() => /* @__PURE__ */ new Set()
|
|
1316
|
+
);
|
|
1317
|
+
#nestedElementsOfDeployment = /* @__PURE__ */ new Map();
|
|
1318
|
+
element(el) {
|
|
1319
|
+
if (el instanceof DeploymentElementModel) {
|
|
1320
|
+
return el;
|
|
1321
|
+
}
|
|
1322
|
+
const id = getId(el);
|
|
1323
|
+
return nonNullable(this.#elements.get(id), `Element ${id} not found`);
|
|
1324
|
+
}
|
|
1325
|
+
findElement(el) {
|
|
1326
|
+
return this.#elements.get(el) ?? null;
|
|
1327
|
+
}
|
|
1328
|
+
node(el) {
|
|
1329
|
+
const element = this.element(el);
|
|
1330
|
+
invariant(element.isDeploymentNode(), `Element ${element.id} is not a deployment node`);
|
|
1331
|
+
return element;
|
|
1332
|
+
}
|
|
1333
|
+
findNode(el) {
|
|
1334
|
+
const element = this.findElement(el);
|
|
1335
|
+
if (!element) {
|
|
1336
|
+
return null;
|
|
1337
|
+
}
|
|
1338
|
+
invariant(element.isDeploymentNode(), `Element ${element?.id} is not a deployment node`);
|
|
1339
|
+
return element;
|
|
1340
|
+
}
|
|
1341
|
+
instance(el) {
|
|
1342
|
+
const element = this.element(el);
|
|
1343
|
+
invariant(element.isInstance(), `Element ${element.id} is not a deployed instance`);
|
|
1344
|
+
return element;
|
|
1345
|
+
}
|
|
1346
|
+
findInstance(el) {
|
|
1347
|
+
const element = this.findElement(el);
|
|
1348
|
+
if (!element) {
|
|
1349
|
+
return null;
|
|
1350
|
+
}
|
|
1351
|
+
invariant(element.isInstance(), `Element ${element?.id} is not a deployed instance`);
|
|
1352
|
+
return element;
|
|
1353
|
+
}
|
|
1354
|
+
/**
|
|
1355
|
+
* Returns the root elements of the model.
|
|
1356
|
+
*/
|
|
1357
|
+
roots() {
|
|
1358
|
+
return this.#rootElements.values();
|
|
1359
|
+
}
|
|
1360
|
+
/**
|
|
1361
|
+
* Returns all elements in the model.
|
|
1362
|
+
*/
|
|
1363
|
+
elements() {
|
|
1364
|
+
return this.#elements.values();
|
|
1365
|
+
}
|
|
1366
|
+
/**
|
|
1367
|
+
* Returns all elements in the model.
|
|
1368
|
+
*/
|
|
1369
|
+
*nodes() {
|
|
1370
|
+
for (const element of this.#elements.values()) {
|
|
1371
|
+
if (element.isDeploymentNode()) {
|
|
1372
|
+
yield element;
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
*instances() {
|
|
1378
|
+
for (const element of this.#elements.values()) {
|
|
1379
|
+
if (element.isInstance()) {
|
|
1380
|
+
yield element;
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
return;
|
|
1384
|
+
}
|
|
1385
|
+
/**
|
|
1386
|
+
* Iterate over all instances of the given logical element.
|
|
1387
|
+
*/
|
|
1388
|
+
*instancesOf(element) {
|
|
1389
|
+
const id = getId(element);
|
|
1390
|
+
const instances = this.#instancesOf.get(id);
|
|
1391
|
+
if (instances) {
|
|
1392
|
+
yield* instances;
|
|
1393
|
+
}
|
|
1394
|
+
return;
|
|
1395
|
+
}
|
|
1396
|
+
deploymentRef(ref) {
|
|
1397
|
+
if ("element" in ref) {
|
|
1398
|
+
const { id, element } = ref;
|
|
1399
|
+
return getOrCreate(this.#nestedElementsOfDeployment, `${id}@${element}`, () => {
|
|
1400
|
+
return new NestedElementOfDeployedInstanceModel(this.instance(id), this.$model.element(element));
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
return this.element(ref);
|
|
1404
|
+
}
|
|
1405
|
+
/**
|
|
1406
|
+
* Returns all relationships in the model.
|
|
1407
|
+
*/
|
|
1408
|
+
relationships() {
|
|
1409
|
+
return this.#relations.values();
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* Returns a specific relationship by its ID.
|
|
1413
|
+
*/
|
|
1414
|
+
relationship(id) {
|
|
1415
|
+
return nonNullable(this.#relations.get(id), `DeploymentRelationModel ${id} not found`);
|
|
1416
|
+
}
|
|
1417
|
+
findRelationship(id) {
|
|
1418
|
+
return this.#relations.get(id) ?? null;
|
|
1419
|
+
}
|
|
1420
|
+
/**
|
|
1421
|
+
* Returns all deployment views in the model.
|
|
1422
|
+
*/
|
|
1423
|
+
*views() {
|
|
1424
|
+
for (const view of this.$model.views()) {
|
|
1425
|
+
if (view.isDeploymentView()) {
|
|
1426
|
+
yield view;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* Returns the parent element of given element.
|
|
1433
|
+
* @see ancestors
|
|
1434
|
+
*/
|
|
1435
|
+
parent(element) {
|
|
1436
|
+
const id = getId(element);
|
|
1437
|
+
return this.#parents.get(id) || null;
|
|
1438
|
+
}
|
|
1439
|
+
/**
|
|
1440
|
+
* Get all children of the element (only direct children),
|
|
1441
|
+
* @see descendants
|
|
1442
|
+
*/
|
|
1443
|
+
children(element) {
|
|
1444
|
+
const id = getId(element);
|
|
1445
|
+
return this.#children.get(id);
|
|
1446
|
+
}
|
|
1447
|
+
/**
|
|
1448
|
+
* Get all sibling (i.e. same parent)
|
|
1449
|
+
*/
|
|
1450
|
+
*siblings(element) {
|
|
1451
|
+
const id = getId(element);
|
|
1452
|
+
const siblings = this.parent(element)?.children() ?? this.roots();
|
|
1453
|
+
for (const sibling of siblings) {
|
|
1454
|
+
if (sibling.id !== id) {
|
|
1455
|
+
yield sibling;
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
return;
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
1462
|
+
* (from closest to root)
|
|
1463
|
+
*/
|
|
1464
|
+
*ancestors(element) {
|
|
1465
|
+
let id = isString(element) ? element : element.id;
|
|
1466
|
+
let parent;
|
|
1467
|
+
while (parent = this.#parents.get(id)) {
|
|
1468
|
+
yield parent;
|
|
1469
|
+
id = parent.id;
|
|
1470
|
+
}
|
|
1471
|
+
return;
|
|
1472
|
+
}
|
|
1473
|
+
/**
|
|
1474
|
+
* Get all descendant elements (i.e. children, children’s children, etc.)
|
|
1475
|
+
*/
|
|
1476
|
+
*descendants(element) {
|
|
1477
|
+
for (const child of this.children(element)) {
|
|
1478
|
+
yield child;
|
|
1479
|
+
yield* this.descendants(child.id);
|
|
1480
|
+
}
|
|
1481
|
+
return;
|
|
1482
|
+
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Incoming relationships to the element and its descendants
|
|
1485
|
+
* @see incomers
|
|
1486
|
+
*/
|
|
1487
|
+
*incoming(element, filter = "all") {
|
|
1488
|
+
const id = getId(element);
|
|
1489
|
+
for (const rel of this.#incoming.get(id)) {
|
|
1490
|
+
switch (true) {
|
|
1491
|
+
case filter === "all":
|
|
1492
|
+
case (filter === "direct" && rel.target.id === id):
|
|
1493
|
+
case (filter === "to-descendants" && rel.target.id !== id):
|
|
1494
|
+
yield rel;
|
|
1495
|
+
break;
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
/**
|
|
1501
|
+
* Outgoing relationships from the element and its descendants
|
|
1502
|
+
* @see outgoers
|
|
1503
|
+
*/
|
|
1504
|
+
*outgoing(element, filter = "all") {
|
|
1505
|
+
const id = getId(element);
|
|
1506
|
+
for (const rel of this.#outgoing.get(id)) {
|
|
1507
|
+
switch (true) {
|
|
1508
|
+
case filter === "all":
|
|
1509
|
+
case (filter === "direct" && rel.source.id === id):
|
|
1510
|
+
case (filter === "from-descendants" && rel.source.id !== id):
|
|
1511
|
+
yield rel;
|
|
1512
|
+
break;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
return;
|
|
1516
|
+
}
|
|
1517
|
+
addElement(element) {
|
|
1518
|
+
if (this.#elements.has(element.id)) {
|
|
1519
|
+
throw new Error(`Element ${element.id} already exists`);
|
|
1520
|
+
}
|
|
1521
|
+
const el = DeploymentElement.isDeploymentNode(element) ? new DeploymentNodeModel(this, element) : new DeployedInstanceModel(this, element, this.$model.element(element.element));
|
|
1522
|
+
this.#elements.set(el.id, el);
|
|
1523
|
+
const parentId = parentFqn(el.id);
|
|
1524
|
+
if (parentId) {
|
|
1525
|
+
invariant(this.#elements.has(parentId), `Parent ${parentId} of ${el.id} not found`);
|
|
1526
|
+
this.#parents.set(el.id, this.node(parentId));
|
|
1527
|
+
this.#children.get(parentId).add(el);
|
|
1528
|
+
} else {
|
|
1529
|
+
invariant(el.isDeploymentNode(), `Root element ${el.id} is not a deployment node`);
|
|
1530
|
+
this.#rootElements.add(el);
|
|
1531
|
+
}
|
|
1532
|
+
return el;
|
|
1533
|
+
}
|
|
1534
|
+
addRelation(relation) {
|
|
1535
|
+
if (this.#relations.has(relation.id)) {
|
|
1536
|
+
throw new Error(`Relation ${relation.id} already exists`);
|
|
1537
|
+
}
|
|
1538
|
+
const rel = new DeploymentRelationModel(
|
|
1539
|
+
this,
|
|
1540
|
+
relation
|
|
1541
|
+
);
|
|
1542
|
+
this.#relations.set(rel.id, rel);
|
|
1543
|
+
this.#incoming.get(rel.target.id).add(rel);
|
|
1544
|
+
this.#outgoing.get(rel.source.id).add(rel);
|
|
1545
|
+
const relParent = rel.boundary?.id ?? null;
|
|
1546
|
+
if (relParent) {
|
|
1547
|
+
for (const ancestor of [relParent, ...ancestorsFqn(relParent)]) {
|
|
1548
|
+
this.#internal.get(ancestor).add(rel);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
for (const sourceAncestor of ancestorsFqn(rel.source.id)) {
|
|
1552
|
+
if (sourceAncestor === relParent) {
|
|
1553
|
+
break;
|
|
1554
|
+
}
|
|
1555
|
+
this.#outgoing.get(sourceAncestor).add(rel);
|
|
1556
|
+
}
|
|
1557
|
+
for (const targetAncestor of ancestorsFqn(rel.target.id)) {
|
|
1558
|
+
if (targetAncestor === relParent) {
|
|
1559
|
+
break;
|
|
1560
|
+
}
|
|
1561
|
+
this.#incoming.get(targetAncestor).add(rel);
|
|
1562
|
+
}
|
|
1563
|
+
return rel;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
class ElementModel {
|
|
1568
|
+
constructor(model, $element) {
|
|
1569
|
+
this.model = model;
|
|
1570
|
+
this.$element = $element;
|
|
1571
|
+
}
|
|
1572
|
+
get id() {
|
|
1573
|
+
return this.$element.id;
|
|
1574
|
+
}
|
|
1575
|
+
get kind() {
|
|
1576
|
+
return this.$element.kind;
|
|
1577
|
+
}
|
|
1578
|
+
get shape() {
|
|
1579
|
+
return this.$element.shape ?? DefaultElementShape;
|
|
1580
|
+
}
|
|
1581
|
+
get color() {
|
|
1582
|
+
return this.$element.color ?? DefaultThemeColor;
|
|
1583
|
+
}
|
|
1584
|
+
get tags() {
|
|
1585
|
+
return this.$element.tags ?? [];
|
|
1586
|
+
}
|
|
1587
|
+
get title() {
|
|
1588
|
+
return this.$element.title;
|
|
1589
|
+
}
|
|
1590
|
+
get description() {
|
|
1591
|
+
return this.$element.description;
|
|
1592
|
+
}
|
|
1593
|
+
get technology() {
|
|
1594
|
+
return this.$element.technology;
|
|
1595
|
+
}
|
|
1596
|
+
get links() {
|
|
1597
|
+
return this.$element.links ?? [];
|
|
1598
|
+
}
|
|
1599
|
+
get parent() {
|
|
1600
|
+
return this.model.parent(this);
|
|
1601
|
+
}
|
|
1602
|
+
get defaultView() {
|
|
1603
|
+
return this.scopedViews().next().value ?? null;
|
|
1604
|
+
}
|
|
1605
|
+
/**
|
|
1606
|
+
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
1607
|
+
* (from closest to root)
|
|
1608
|
+
*/
|
|
1609
|
+
ancestors() {
|
|
1610
|
+
return this.model.ancestors(this);
|
|
1611
|
+
}
|
|
1612
|
+
/**
|
|
1613
|
+
* Returns the common ancestor of this element and another element.
|
|
1614
|
+
*/
|
|
1615
|
+
commonAncestor(another) {
|
|
1616
|
+
const common = commonAncestor(this.id, another.id);
|
|
1617
|
+
return common ? this.model.element(common) : null;
|
|
1618
|
+
}
|
|
1619
|
+
children() {
|
|
1620
|
+
return this.model.children(this);
|
|
1621
|
+
}
|
|
1622
|
+
/**
|
|
1623
|
+
* Get all descendant elements (i.e. children, children’s children, etc.)
|
|
1624
|
+
*/
|
|
1625
|
+
descendants() {
|
|
1626
|
+
return this.model.descendants(this);
|
|
1627
|
+
}
|
|
1628
|
+
/**
|
|
1629
|
+
* Get all sibling (i.e. same parent)
|
|
1630
|
+
*/
|
|
1631
|
+
siblings() {
|
|
1632
|
+
return this.model.siblings(this);
|
|
1633
|
+
}
|
|
1634
|
+
/**
|
|
1635
|
+
* Resolve siblings of the element and its ancestors
|
|
1636
|
+
* (from closest to root)
|
|
1637
|
+
*/
|
|
1638
|
+
*ascendingSiblings() {
|
|
1639
|
+
yield* this.siblings();
|
|
1640
|
+
for (const ancestor of this.ancestors()) {
|
|
1641
|
+
yield* ancestor.siblings();
|
|
1642
|
+
}
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1645
|
+
incoming(filter = "all") {
|
|
1646
|
+
return this.model.incoming(this, filter);
|
|
1647
|
+
}
|
|
1648
|
+
*incomers(filter = "all") {
|
|
1649
|
+
const unique = /* @__PURE__ */ new Set();
|
|
1650
|
+
for (const r of this.incoming(filter)) {
|
|
1651
|
+
if (unique.has(r.source.id)) {
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1654
|
+
unique.add(r.source.id);
|
|
1655
|
+
yield r.source;
|
|
1656
|
+
}
|
|
1657
|
+
return;
|
|
1658
|
+
}
|
|
1659
|
+
outgoing(filter = "all") {
|
|
1660
|
+
return this.model.outgoing(this, filter);
|
|
1661
|
+
}
|
|
1662
|
+
*outgoers(filter = "all") {
|
|
1663
|
+
const unique = /* @__PURE__ */ new Set();
|
|
1664
|
+
for (const r of this.outgoing(filter)) {
|
|
1665
|
+
if (unique.has(r.target.id)) {
|
|
1666
|
+
continue;
|
|
1667
|
+
}
|
|
1668
|
+
unique.add(r.target.id);
|
|
1669
|
+
yield r.target;
|
|
1670
|
+
}
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1673
|
+
cachedOutgoing = null;
|
|
1674
|
+
cachedIncoming = null;
|
|
1675
|
+
get allOutgoing() {
|
|
1676
|
+
this.cachedOutgoing ??= new Set(this.outgoing());
|
|
1677
|
+
return this.cachedOutgoing;
|
|
1678
|
+
}
|
|
1679
|
+
get allIncoming() {
|
|
1680
|
+
this.cachedIncoming ??= new Set(this.incoming());
|
|
1681
|
+
return this.cachedIncoming;
|
|
1682
|
+
}
|
|
1683
|
+
/**
|
|
1684
|
+
* Iterate over all views that include this element.
|
|
1685
|
+
*/
|
|
1686
|
+
*views() {
|
|
1687
|
+
for (const view of this.model.views()) {
|
|
1688
|
+
if (view.includesElement(this.id)) {
|
|
1689
|
+
yield view;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
return;
|
|
1693
|
+
}
|
|
1694
|
+
/**
|
|
1695
|
+
* Iterate over all views that scope this element.
|
|
1696
|
+
* It is possible that element is not included in the view.
|
|
1697
|
+
*/
|
|
1698
|
+
*scopedViews() {
|
|
1699
|
+
for (const vm of this.model.views()) {
|
|
1700
|
+
if (vm.isElementView() && vm.$view.viewOf === this.id) {
|
|
1701
|
+
yield vm;
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
* @returns true if the element is deployed
|
|
1708
|
+
*/
|
|
1709
|
+
isDeployed() {
|
|
1710
|
+
return n$1(this.deployments().next().value);
|
|
1711
|
+
}
|
|
1712
|
+
deployments() {
|
|
1713
|
+
return this.model.deployment.instancesOf(this);
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
class RelationshipModel {
|
|
1718
|
+
constructor(model, $relationship) {
|
|
1719
|
+
this.model = model;
|
|
1720
|
+
this.$relationship = $relationship;
|
|
1721
|
+
this.source = model.element($relationship.source);
|
|
1722
|
+
this.target = model.element($relationship.target);
|
|
1723
|
+
const parent = commonAncestor(this.source.id, this.target.id);
|
|
1724
|
+
this.boundary = parent ? this.model.element(parent) : null;
|
|
1725
|
+
}
|
|
1726
|
+
source;
|
|
1727
|
+
target;
|
|
1728
|
+
/**
|
|
1729
|
+
* Common ancestor of the source and target elements.
|
|
1730
|
+
* Represents the boundary of the Relation.
|
|
1731
|
+
*/
|
|
1732
|
+
boundary;
|
|
1733
|
+
get id() {
|
|
1734
|
+
return this.$relationship.id;
|
|
1735
|
+
}
|
|
1736
|
+
get expression() {
|
|
1737
|
+
return `${this.source.id} -> ${this.target.id}`;
|
|
1738
|
+
}
|
|
1739
|
+
get title() {
|
|
1740
|
+
if (n(this.$relationship.title)) {
|
|
1741
|
+
return null;
|
|
1742
|
+
}
|
|
1743
|
+
return this.$relationship.title;
|
|
1744
|
+
}
|
|
1745
|
+
get technology() {
|
|
1746
|
+
if (n(this.$relationship.technology)) {
|
|
1747
|
+
return null;
|
|
1748
|
+
}
|
|
1749
|
+
return this.$relationship.technology;
|
|
1750
|
+
}
|
|
1751
|
+
get description() {
|
|
1752
|
+
if (n(this.$relationship.description)) {
|
|
1753
|
+
return null;
|
|
1754
|
+
}
|
|
1755
|
+
return this.$relationship.description;
|
|
1756
|
+
}
|
|
1757
|
+
get navigateTo() {
|
|
1758
|
+
return this.$relationship.navigateTo ? this.model.view(this.$relationship.navigateTo) : null;
|
|
1759
|
+
}
|
|
1760
|
+
get tags() {
|
|
1761
|
+
return this.$relationship.tags ?? [];
|
|
1762
|
+
}
|
|
1763
|
+
get links() {
|
|
1764
|
+
return this.$relationship.links ?? [];
|
|
1765
|
+
}
|
|
1766
|
+
/**
|
|
1767
|
+
* Iterate over all views that include this relationship.
|
|
1768
|
+
*/
|
|
1769
|
+
*views() {
|
|
1770
|
+
for (const view of this.model.views()) {
|
|
1771
|
+
if (view.includesRelation(this.id)) {
|
|
1772
|
+
yield view;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
return;
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
class EdgeModel {
|
|
1780
|
+
constructor(view, $edge, source, target) {
|
|
1781
|
+
this.view = view;
|
|
1782
|
+
this.$edge = $edge;
|
|
1783
|
+
this.source = source;
|
|
1784
|
+
this.target = target;
|
|
1785
|
+
}
|
|
1786
|
+
get id() {
|
|
1787
|
+
return this.$edge.id;
|
|
1788
|
+
}
|
|
1789
|
+
get parent() {
|
|
1790
|
+
return this.$edge.parent ? this.view.node(this.$edge.parent) : null;
|
|
1791
|
+
}
|
|
1792
|
+
get label() {
|
|
1793
|
+
return this.$edge.label;
|
|
1794
|
+
}
|
|
1795
|
+
get description() {
|
|
1796
|
+
return this.$edge.description ?? null;
|
|
1797
|
+
}
|
|
1798
|
+
get technology() {
|
|
1799
|
+
return this.$edge.technology ?? null;
|
|
1800
|
+
}
|
|
1801
|
+
hasParent() {
|
|
1802
|
+
return this.$edge.parent !== null;
|
|
1803
|
+
}
|
|
1804
|
+
get tags() {
|
|
1805
|
+
return this.$edge.tags ?? [];
|
|
1806
|
+
}
|
|
1807
|
+
get stepNumber() {
|
|
1808
|
+
return this.isStep() ? extractStep(this.id) : null;
|
|
1809
|
+
}
|
|
1810
|
+
get navigateTo() {
|
|
1811
|
+
return this.$edge.navigateTo ? this.view.$model.view(this.$edge.navigateTo) : null;
|
|
1812
|
+
}
|
|
1813
|
+
isStep() {
|
|
1814
|
+
return isStepEdgeId(this.id);
|
|
1815
|
+
}
|
|
1816
|
+
*relationships(type) {
|
|
1817
|
+
for (const id of this.$edge.relations) {
|
|
1818
|
+
if (type) {
|
|
1819
|
+
yield this.view.$model.relationship(id, type);
|
|
1820
|
+
const rel = this.view.$model.findRelationship(id, type);
|
|
1821
|
+
if (rel) {
|
|
1822
|
+
yield rel;
|
|
1823
|
+
}
|
|
1824
|
+
} else {
|
|
1825
|
+
yield this.view.$model.relationship(id);
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
return;
|
|
1829
|
+
}
|
|
1830
|
+
includesRelation(rel) {
|
|
1831
|
+
return this.$edge.relations.includes(rel);
|
|
1832
|
+
}
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
class NodeModel {
|
|
1836
|
+
constructor($view, $node) {
|
|
1837
|
+
this.$view = $view;
|
|
1838
|
+
this.$node = $node;
|
|
1839
|
+
}
|
|
1840
|
+
get id() {
|
|
1841
|
+
return this.$node.id;
|
|
1842
|
+
}
|
|
1843
|
+
get title() {
|
|
1844
|
+
return this.$node.title;
|
|
1845
|
+
}
|
|
1846
|
+
get kind() {
|
|
1847
|
+
return this.$node.kind;
|
|
1848
|
+
}
|
|
1849
|
+
get description() {
|
|
1850
|
+
return this.$node.description;
|
|
1851
|
+
}
|
|
1852
|
+
get technology() {
|
|
1853
|
+
return this.$node.technology;
|
|
1854
|
+
}
|
|
1855
|
+
get parent() {
|
|
1856
|
+
return this.$node.parent ? this.$view.node(this.$node.parent) : null;
|
|
1857
|
+
}
|
|
1858
|
+
get element() {
|
|
1859
|
+
const modelRef = ComputedNode.modelRef(this.$node);
|
|
1860
|
+
return modelRef ? this.$view.$model.element(modelRef) : null;
|
|
1861
|
+
}
|
|
1862
|
+
get deployment() {
|
|
1863
|
+
const modelRef = ComputedNode.deploymentRef(this.$node);
|
|
1864
|
+
return modelRef ? this.$view.$model.deployment.element(modelRef) : null;
|
|
1865
|
+
}
|
|
1866
|
+
get shape() {
|
|
1867
|
+
return this.$node.shape;
|
|
1868
|
+
}
|
|
1869
|
+
get color() {
|
|
1870
|
+
return this.$node.color;
|
|
1871
|
+
}
|
|
1872
|
+
get tags() {
|
|
1873
|
+
return this.$node.tags ?? [];
|
|
1874
|
+
}
|
|
1875
|
+
get links() {
|
|
1876
|
+
return this.$node.links ?? [];
|
|
1877
|
+
}
|
|
1878
|
+
get navigateTo() {
|
|
1879
|
+
return this.$node.navigateTo ? this.$view.$model.view(this.$node.navigateTo) : null;
|
|
1880
|
+
}
|
|
1881
|
+
/**
|
|
1882
|
+
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
1883
|
+
* (from closest to root)
|
|
1884
|
+
*/
|
|
1885
|
+
*ancestors() {
|
|
1886
|
+
let parent = this.parent;
|
|
1887
|
+
while (parent) {
|
|
1888
|
+
yield parent;
|
|
1889
|
+
parent = parent.parent;
|
|
1890
|
+
}
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
*children() {
|
|
1894
|
+
for (const child of this.$node.children) {
|
|
1895
|
+
yield this.$view.node(child);
|
|
1896
|
+
}
|
|
1897
|
+
return;
|
|
1898
|
+
}
|
|
1899
|
+
*sublings() {
|
|
1900
|
+
const sublings = this.parent?.children() ?? this.$view.roots();
|
|
1901
|
+
for (const subling of sublings) {
|
|
1902
|
+
if (subling.id !== this.id) {
|
|
1903
|
+
yield subling;
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
return;
|
|
1907
|
+
}
|
|
1908
|
+
*incoming(filter = "all") {
|
|
1909
|
+
for (const edgeId of this.$node.inEdges) {
|
|
1910
|
+
const edge = this.$view.edge(edgeId);
|
|
1911
|
+
switch (true) {
|
|
1912
|
+
case filter === "all":
|
|
1913
|
+
case (filter === "direct" && edge.target.id === this.id):
|
|
1914
|
+
case (filter === "to-descendants" && edge.target.id !== this.id):
|
|
1915
|
+
yield edge;
|
|
1916
|
+
break;
|
|
1917
|
+
}
|
|
1918
|
+
}
|
|
1919
|
+
return;
|
|
1920
|
+
}
|
|
1921
|
+
*incomers(filter = "all") {
|
|
1922
|
+
const unique = /* @__PURE__ */ new Set();
|
|
1923
|
+
for (const r of this.incoming(filter)) {
|
|
1924
|
+
if (unique.has(r.source.id)) {
|
|
1925
|
+
continue;
|
|
1926
|
+
}
|
|
1927
|
+
unique.add(r.source.id);
|
|
1928
|
+
yield r.source;
|
|
1929
|
+
}
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
*outgoing(filter = "all") {
|
|
1933
|
+
for (const edgeId of this.$node.outEdges) {
|
|
1934
|
+
const edge = this.$view.edge(edgeId);
|
|
1935
|
+
switch (true) {
|
|
1936
|
+
case filter === "all":
|
|
1937
|
+
case (filter === "direct" && edge.source.id === this.id):
|
|
1938
|
+
case (filter === "from-descendants" && edge.source.id !== this.id):
|
|
1939
|
+
yield edge;
|
|
1940
|
+
break;
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
return;
|
|
1944
|
+
}
|
|
1945
|
+
*outgoers(filter = "all") {
|
|
1946
|
+
const unique = /* @__PURE__ */ new Set();
|
|
1947
|
+
for (const r of this.outgoing(filter)) {
|
|
1948
|
+
if (unique.has(r.target.id)) {
|
|
1949
|
+
continue;
|
|
1950
|
+
}
|
|
1951
|
+
unique.add(r.target.id);
|
|
1952
|
+
yield r.target;
|
|
1953
|
+
}
|
|
1954
|
+
return;
|
|
1955
|
+
}
|
|
1956
|
+
isDiagramNode() {
|
|
1957
|
+
return "width" in this.$node && "height" in this.$node;
|
|
1958
|
+
}
|
|
1959
|
+
hasChildren() {
|
|
1960
|
+
return this.$node.children.length > 0;
|
|
1961
|
+
}
|
|
1962
|
+
hasParent() {
|
|
1963
|
+
return this.$node.parent !== null;
|
|
1964
|
+
}
|
|
1965
|
+
/**
|
|
1966
|
+
* Check if this node references to logical model element.
|
|
1967
|
+
*/
|
|
1968
|
+
hasElement() {
|
|
1969
|
+
return ComputedNode.modelRef(this.$node) !== null;
|
|
1970
|
+
}
|
|
1971
|
+
/**
|
|
1972
|
+
* Check if this node references to deployment element (Node or Instance).
|
|
1973
|
+
*/
|
|
1974
|
+
hasDeployment() {
|
|
1975
|
+
return ComputedNode.deploymentRef(this.$node) !== null;
|
|
1976
|
+
}
|
|
1977
|
+
/**
|
|
1978
|
+
* Check if this node references to deployed instance
|
|
1979
|
+
* Deployed instance always references to element and deployment element.
|
|
1980
|
+
*/
|
|
1981
|
+
hasDeployedInstance() {
|
|
1982
|
+
return this.hasElement() && this.hasDeployment();
|
|
1983
|
+
}
|
|
1984
|
+
isGroup() {
|
|
1985
|
+
return ComputedNode.isNodesGroup(this.$node);
|
|
1986
|
+
}
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
class LikeC4ViewModel {
|
|
1990
|
+
constructor($model, $view) {
|
|
1991
|
+
this.$model = $model;
|
|
1992
|
+
this.$view = $view;
|
|
1993
|
+
for (const node of m($view.nodes, compareByFqnHierarchically)) {
|
|
1994
|
+
const el = new NodeModel(this, node);
|
|
1995
|
+
this.#nodes.set(node.id, el);
|
|
1996
|
+
if (!node.parent) {
|
|
1997
|
+
this.#rootnodes.add(el);
|
|
1998
|
+
}
|
|
1999
|
+
if (el.hasDeployment()) {
|
|
2000
|
+
this.#includeDeployments.add(el.deployment.id);
|
|
2001
|
+
}
|
|
2002
|
+
if (el.hasElement()) {
|
|
2003
|
+
this.#includeElements.add(el.element.id);
|
|
2004
|
+
}
|
|
2005
|
+
for (const tag of el.tags) {
|
|
2006
|
+
getOrCreate(this.#allTags, tag, () => /* @__PURE__ */ new Set()).add(el);
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
for (const edge of $view.edges) {
|
|
2010
|
+
const edgeModel = new EdgeModel(this, edge, this.node(edge.source), this.node(edge.target));
|
|
2011
|
+
for (const tag of edgeModel.tags) {
|
|
2012
|
+
getOrCreate(this.#allTags, tag, () => /* @__PURE__ */ new Set()).add(edgeModel);
|
|
2013
|
+
}
|
|
2014
|
+
for (const rel of edge.relations) {
|
|
2015
|
+
this.#includeRelations.add(rel);
|
|
2016
|
+
}
|
|
2017
|
+
this.#edges.set(edge.id, edgeModel);
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
#rootnodes = /* @__PURE__ */ new Set();
|
|
2021
|
+
#nodes = /* @__PURE__ */ new Map();
|
|
2022
|
+
#edges = /* @__PURE__ */ new Map();
|
|
2023
|
+
#includeElements = /* @__PURE__ */ new Set();
|
|
2024
|
+
#includeDeployments = /* @__PURE__ */ new Set();
|
|
2025
|
+
#includeRelations = /* @__PURE__ */ new Set();
|
|
2026
|
+
#allTags = /* @__PURE__ */ new Map();
|
|
2027
|
+
get __() {
|
|
2028
|
+
return this.$view.__ ?? "element";
|
|
2029
|
+
}
|
|
2030
|
+
get id() {
|
|
2031
|
+
return this.$view.id;
|
|
2032
|
+
}
|
|
2033
|
+
get title() {
|
|
2034
|
+
return this.$view.title;
|
|
2035
|
+
}
|
|
2036
|
+
get tags() {
|
|
2037
|
+
return this.$view.tags ?? [];
|
|
2038
|
+
}
|
|
2039
|
+
get links() {
|
|
2040
|
+
return this.$view.links ?? [];
|
|
2041
|
+
}
|
|
2042
|
+
get viewOf() {
|
|
2043
|
+
const v = this.$view;
|
|
2044
|
+
if (isScopedElementView(v)) {
|
|
2045
|
+
return this.$model.element(v.viewOf);
|
|
2046
|
+
}
|
|
2047
|
+
return null;
|
|
2048
|
+
}
|
|
2049
|
+
/**
|
|
2050
|
+
* All tags from nodes and edges.
|
|
2051
|
+
*/
|
|
2052
|
+
get includedTags() {
|
|
2053
|
+
return [...this.#allTags.keys()];
|
|
2054
|
+
}
|
|
2055
|
+
roots() {
|
|
2056
|
+
return this.#rootnodes.values();
|
|
2057
|
+
}
|
|
2058
|
+
/**
|
|
2059
|
+
* Iterate over all nodes that have children.
|
|
2060
|
+
*/
|
|
2061
|
+
*compounds() {
|
|
2062
|
+
for (const node of this.#nodes.values()) {
|
|
2063
|
+
if (node.hasChildren()) {
|
|
2064
|
+
yield node;
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
return;
|
|
2068
|
+
}
|
|
2069
|
+
/**
|
|
2070
|
+
* Get node by id.
|
|
2071
|
+
* @throws Error if node is not found.
|
|
2072
|
+
*/
|
|
2073
|
+
node(node) {
|
|
2074
|
+
const nodeId = getId(node);
|
|
2075
|
+
return nonNullable(this.#nodes.get(nodeId), `Node ${nodeId} not found in view ${this.$view.id}`);
|
|
2076
|
+
}
|
|
2077
|
+
/**
|
|
2078
|
+
* Find node by id.
|
|
2079
|
+
*/
|
|
2080
|
+
findNode(node) {
|
|
2081
|
+
return this.#nodes.get(getId(node)) ?? null;
|
|
2082
|
+
}
|
|
2083
|
+
/**
|
|
2084
|
+
* Iterate over all nodes.
|
|
2085
|
+
*/
|
|
2086
|
+
nodes() {
|
|
2087
|
+
return this.#nodes.values();
|
|
2088
|
+
}
|
|
2089
|
+
/**
|
|
2090
|
+
* Find edge by id.
|
|
2091
|
+
* @param edge Edge or id
|
|
2092
|
+
* @returns EdgeModel
|
|
2093
|
+
*/
|
|
2094
|
+
edge(edge) {
|
|
2095
|
+
const edgeId = getId(edge);
|
|
2096
|
+
return nonNullable(this.#edges.get(edgeId), `Edge ${edgeId} not found in view ${this.$view.id}`);
|
|
2097
|
+
}
|
|
2098
|
+
findEdge(edge) {
|
|
2099
|
+
return this.#edges.get(getId(edge)) ?? null;
|
|
2100
|
+
}
|
|
2101
|
+
/**
|
|
2102
|
+
* Iterate over all edges.
|
|
2103
|
+
*/
|
|
2104
|
+
edges() {
|
|
2105
|
+
return this.#edges.values();
|
|
2106
|
+
}
|
|
2107
|
+
/**
|
|
2108
|
+
* Iterate over all edges.
|
|
2109
|
+
*/
|
|
2110
|
+
*edgesWithRelation(relation) {
|
|
2111
|
+
for (const edge of this.#edges.values()) {
|
|
2112
|
+
if (edge.includesRelation(relation)) {
|
|
2113
|
+
yield edge;
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
return;
|
|
2117
|
+
}
|
|
2118
|
+
/**
|
|
2119
|
+
* Nodes that have references to elements from logical model.
|
|
2120
|
+
*/
|
|
2121
|
+
*elements() {
|
|
2122
|
+
for (const node of this.#nodes.values()) {
|
|
2123
|
+
if (node.hasElement()) {
|
|
2124
|
+
yield node;
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
return;
|
|
2128
|
+
}
|
|
2129
|
+
includesElement(elementId) {
|
|
2130
|
+
return this.#includeElements.has(elementId);
|
|
2131
|
+
}
|
|
2132
|
+
includesDeployment(deploymentId) {
|
|
2133
|
+
return this.#includeDeployments.has(deploymentId);
|
|
2134
|
+
}
|
|
2135
|
+
includesRelation(relationId) {
|
|
2136
|
+
return this.#includeRelations.has(relationId);
|
|
2137
|
+
}
|
|
2138
|
+
/**
|
|
2139
|
+
* Below are type guards.
|
|
2140
|
+
*/
|
|
2141
|
+
isComputed() {
|
|
2142
|
+
return true;
|
|
2143
|
+
}
|
|
2144
|
+
isDiagram() {
|
|
2145
|
+
return "bounds" in this.$view;
|
|
2146
|
+
}
|
|
2147
|
+
isElementView() {
|
|
2148
|
+
return isElementView(this.$view);
|
|
2149
|
+
}
|
|
2150
|
+
isDeploymentView() {
|
|
2151
|
+
return isDeploymentView(this.$view);
|
|
2152
|
+
}
|
|
2153
|
+
isDynamicView() {
|
|
2154
|
+
return isDynamicView(this.$view);
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
class LikeC4Model {
|
|
2159
|
+
constructor($model) {
|
|
2160
|
+
this.$model = $model;
|
|
2161
|
+
for (const element of r($model.elements)) {
|
|
2162
|
+
const el = this.addElement(element);
|
|
2163
|
+
for (const tag of el.tags) {
|
|
2164
|
+
this.#allTags.get(tag).add(el);
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
for (const relation of r($model.relations)) {
|
|
2168
|
+
const el = this.addRelation(relation);
|
|
2169
|
+
for (const tag of el.tags) {
|
|
2170
|
+
this.#allTags.get(tag).add(el);
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
this.deployment = new LikeC4DeploymentModel(this, $model.deployments);
|
|
2174
|
+
const views = x(
|
|
2175
|
+
r($model.views),
|
|
2176
|
+
m((a, b) => compareNatural(a.title ?? "untitled", b.title ?? "untitled"))
|
|
2177
|
+
);
|
|
2178
|
+
for (const view of views) {
|
|
2179
|
+
const vm = new LikeC4ViewModel(this, view);
|
|
2180
|
+
this.#views.set(view.id, vm);
|
|
2181
|
+
for (const tag of vm.tags) {
|
|
2182
|
+
this.#allTags.get(tag).add(vm);
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
/**
|
|
2187
|
+
* Only available in compile time
|
|
2188
|
+
*/
|
|
2189
|
+
Aux;
|
|
2190
|
+
#elements = /* @__PURE__ */ new Map();
|
|
2191
|
+
// Parent element for given FQN
|
|
2192
|
+
#parents = /* @__PURE__ */ new Map();
|
|
2193
|
+
// Children elements for given FQN
|
|
2194
|
+
#children = new DefaultMap(() => /* @__PURE__ */ new Set());
|
|
2195
|
+
#rootElements = /* @__PURE__ */ new Set();
|
|
2196
|
+
#relations = /* @__PURE__ */ new Map();
|
|
2197
|
+
// Incoming to an element or its descendants
|
|
2198
|
+
#incoming = new DefaultMap(() => /* @__PURE__ */ new Set());
|
|
2199
|
+
// Outgoing from an element or its descendants
|
|
2200
|
+
#outgoing = new DefaultMap(() => /* @__PURE__ */ new Set());
|
|
2201
|
+
// Relationships inside the element, among descendants
|
|
2202
|
+
#internal = new DefaultMap(() => /* @__PURE__ */ new Set());
|
|
2203
|
+
#views = /* @__PURE__ */ new Map();
|
|
2204
|
+
#allTags = new DefaultMap(
|
|
2205
|
+
() => /* @__PURE__ */ new Set()
|
|
2206
|
+
);
|
|
2207
|
+
deployment;
|
|
2208
|
+
static create(model) {
|
|
2209
|
+
return new LikeC4Model(model);
|
|
2210
|
+
}
|
|
2211
|
+
/**
|
|
2212
|
+
* This method is supposed to be used only in dumps
|
|
2213
|
+
*/
|
|
2214
|
+
static fromDump(dump) {
|
|
2215
|
+
return new LikeC4Model(dump);
|
|
2216
|
+
}
|
|
2217
|
+
get type() {
|
|
2218
|
+
return this.$model.__ ?? "computed";
|
|
2219
|
+
}
|
|
2220
|
+
element(el) {
|
|
2221
|
+
if (el instanceof ElementModel) {
|
|
2222
|
+
return el;
|
|
2223
|
+
}
|
|
2224
|
+
const id = getId(el);
|
|
2225
|
+
return nonNullable(this.findElement(id), `Element ${getId(el)} not found`);
|
|
2226
|
+
}
|
|
2227
|
+
findElement(el) {
|
|
2228
|
+
return this.#elements.get(el) ?? null;
|
|
2229
|
+
}
|
|
2230
|
+
/**
|
|
2231
|
+
* Returns the root elements of the model.
|
|
2232
|
+
*/
|
|
2233
|
+
roots() {
|
|
2234
|
+
return this.#rootElements.values();
|
|
2235
|
+
}
|
|
2236
|
+
/**
|
|
2237
|
+
* Returns all elements in the model.
|
|
2238
|
+
*/
|
|
2239
|
+
elements() {
|
|
2240
|
+
return this.#elements.values();
|
|
2241
|
+
}
|
|
2242
|
+
/**
|
|
2243
|
+
* Returns all relationships in the model.
|
|
2244
|
+
*/
|
|
2245
|
+
relationships() {
|
|
2246
|
+
return this.#relations.values();
|
|
2247
|
+
}
|
|
2248
|
+
relationship(id, type) {
|
|
2249
|
+
if (type === "deployment") {
|
|
2250
|
+
return this.deployment.relationship(id);
|
|
2251
|
+
}
|
|
2252
|
+
let model = this.#relations.get(id) ?? null;
|
|
2253
|
+
if (model || type === "model") {
|
|
2254
|
+
return nonNullable(model, `Model relation ${id} not found`);
|
|
2255
|
+
}
|
|
2256
|
+
return nonNullable(this.deployment.findRelationship(id), `No model/deployment relation ${id} not found`);
|
|
2257
|
+
}
|
|
2258
|
+
findRelationship(id, type) {
|
|
2259
|
+
if (type === "deployment") {
|
|
2260
|
+
return this.deployment.findRelationship(id);
|
|
2261
|
+
}
|
|
2262
|
+
let model = this.#relations.get(id) ?? null;
|
|
2263
|
+
if (model || type === "model") {
|
|
2264
|
+
return model;
|
|
2265
|
+
}
|
|
2266
|
+
return this.deployment.findRelationship(id);
|
|
2267
|
+
}
|
|
2268
|
+
/**
|
|
2269
|
+
* Returns all views in the model.
|
|
2270
|
+
*/
|
|
2271
|
+
views() {
|
|
2272
|
+
return this.#views.values();
|
|
2273
|
+
}
|
|
2274
|
+
/**
|
|
2275
|
+
* Returns a specific view by its ID.
|
|
2276
|
+
*/
|
|
2277
|
+
view(viewId) {
|
|
2278
|
+
return nonNullable(this.#views.get(viewId), `View ${viewId} not found`);
|
|
2279
|
+
}
|
|
2280
|
+
findView(viewId) {
|
|
2281
|
+
return nonNullable(this.#views.get(viewId), `View ${viewId} not found`);
|
|
2282
|
+
}
|
|
2283
|
+
/**
|
|
2284
|
+
* Returns the parent element of given element.
|
|
2285
|
+
* @see ancestors
|
|
2286
|
+
*/
|
|
2287
|
+
parent(element) {
|
|
2288
|
+
const id = getId(element);
|
|
2289
|
+
return this.#parents.get(id) || null;
|
|
2290
|
+
}
|
|
2291
|
+
/**
|
|
2292
|
+
* Get all children of the element (only direct children),
|
|
2293
|
+
* @see descendants
|
|
2294
|
+
*/
|
|
2295
|
+
children(element) {
|
|
2296
|
+
const id = getId(element);
|
|
2297
|
+
return this.#children.get(id);
|
|
2298
|
+
}
|
|
2299
|
+
/**
|
|
2300
|
+
* Get all sibling (i.e. same parent)
|
|
2301
|
+
*/
|
|
2302
|
+
*siblings(element) {
|
|
2303
|
+
const id = getId(element);
|
|
2304
|
+
const parent = this.#parents.get(id);
|
|
2305
|
+
const siblings = parent ? this.#children.get(parent.id).values() : this.roots();
|
|
2306
|
+
for (const sibling of siblings) {
|
|
2307
|
+
if (sibling.id !== id) {
|
|
2308
|
+
yield sibling;
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
return;
|
|
2312
|
+
}
|
|
2313
|
+
/**
|
|
2314
|
+
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
2315
|
+
* (from closest to root)
|
|
2316
|
+
*/
|
|
2317
|
+
*ancestors(element) {
|
|
2318
|
+
let id = getId(element);
|
|
2319
|
+
let parent;
|
|
2320
|
+
while (parent = this.#parents.get(id)) {
|
|
2321
|
+
yield parent;
|
|
2322
|
+
id = parent.id;
|
|
2323
|
+
}
|
|
2324
|
+
return;
|
|
2325
|
+
}
|
|
2326
|
+
/**
|
|
2327
|
+
* Get all descendant elements (i.e. children, children’s children, etc.)
|
|
2328
|
+
*/
|
|
2329
|
+
*descendants(element) {
|
|
2330
|
+
for (const child of this.children(element)) {
|
|
2331
|
+
yield child;
|
|
2332
|
+
yield* this.descendants(child.id);
|
|
2333
|
+
}
|
|
2334
|
+
return;
|
|
2335
|
+
}
|
|
2336
|
+
/**
|
|
2337
|
+
* Incoming relationships to the element and its descendants
|
|
2338
|
+
* @see incomers
|
|
2339
|
+
*/
|
|
2340
|
+
*incoming(element, filter = "all") {
|
|
2341
|
+
const id = getId(element);
|
|
2342
|
+
for (const rel of this.#incoming.get(id)) {
|
|
2343
|
+
switch (true) {
|
|
2344
|
+
case filter === "all":
|
|
2345
|
+
case (filter === "direct" && rel.target.id === id):
|
|
2346
|
+
case (filter === "to-descendants" && rel.target.id !== id):
|
|
2347
|
+
yield rel;
|
|
2348
|
+
break;
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
return;
|
|
2352
|
+
}
|
|
2353
|
+
/**
|
|
2354
|
+
* Outgoing relationships from the element and its descendants
|
|
2355
|
+
* @see outgoers
|
|
2356
|
+
*/
|
|
2357
|
+
*outgoing(element, filter = "all") {
|
|
2358
|
+
const id = getId(element);
|
|
2359
|
+
for (const rel of this.#outgoing.get(id)) {
|
|
2360
|
+
switch (true) {
|
|
2361
|
+
case filter === "all":
|
|
2362
|
+
case (filter === "direct" && rel.source.id === id):
|
|
2363
|
+
case (filter === "from-descendants" && rel.source.id !== id):
|
|
2364
|
+
yield rel;
|
|
2365
|
+
break;
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
return;
|
|
2369
|
+
}
|
|
2370
|
+
addElement(element) {
|
|
2371
|
+
if (this.#elements.has(element.id)) {
|
|
2372
|
+
throw new Error(`Element ${element.id} already exists`);
|
|
2373
|
+
}
|
|
2374
|
+
const el = new ElementModel(this, element);
|
|
2375
|
+
this.#elements.set(el.id, el);
|
|
2376
|
+
const parentId = parentFqn(el.id);
|
|
2377
|
+
if (parentId) {
|
|
2378
|
+
invariant(this.#elements.has(parentId), `Parent ${parentId} of ${el.id} not found`);
|
|
2379
|
+
this.#parents.set(el.id, this.element(parentId));
|
|
2380
|
+
this.#children.get(parentId).add(el);
|
|
2381
|
+
} else {
|
|
2382
|
+
this.#rootElements.add(el);
|
|
2383
|
+
}
|
|
2384
|
+
return el;
|
|
2385
|
+
}
|
|
2386
|
+
addRelation(relation) {
|
|
2387
|
+
if (this.#relations.has(relation.id)) {
|
|
2388
|
+
throw new Error(`Relation ${relation.id} already exists`);
|
|
2389
|
+
}
|
|
2390
|
+
const rel = new RelationshipModel(
|
|
2391
|
+
this,
|
|
2392
|
+
relation
|
|
2393
|
+
);
|
|
2394
|
+
const { source, target } = rel;
|
|
2395
|
+
this.#relations.set(rel.id, rel);
|
|
2396
|
+
this.#incoming.get(target.id).add(rel);
|
|
2397
|
+
this.#outgoing.get(source.id).add(rel);
|
|
2398
|
+
const relParent = commonAncestor(source.id, target.id);
|
|
2399
|
+
if (relParent) {
|
|
2400
|
+
for (const ancestor of [relParent, ...ancestorsFqn(relParent)]) {
|
|
2401
|
+
this.#internal.get(ancestor).add(rel);
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
for (const sourceAncestor of ancestorsFqn(relation.source)) {
|
|
2405
|
+
if (sourceAncestor === relParent) {
|
|
2406
|
+
break;
|
|
2407
|
+
}
|
|
2408
|
+
this.#outgoing.get(sourceAncestor).add(rel);
|
|
2409
|
+
}
|
|
2410
|
+
for (const targetAncestor of ancestorsFqn(relation.target)) {
|
|
2411
|
+
if (targetAncestor === relParent) {
|
|
2412
|
+
break;
|
|
2413
|
+
}
|
|
2414
|
+
this.#incoming.get(targetAncestor).add(rel);
|
|
2415
|
+
}
|
|
2416
|
+
return rel;
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
|
|
2420
|
+
export { difference as A, equals as B, symmetricDifference as C, hasIntersection as D, x as E, s as F, o$2 as G, getDefaultExportFromCjs as H, n$1 as I, DefaultMap as J, m as K, LikeC4Model as L, t$1 as M, n as N, RelationshipsAccum as R, LikeC4DeploymentModel as a, LikeC4ViewModel as b, compareNatural as c, parentFqnPredicate as d, isAncestor as e, isDescendantOf as f, notDescendantOf as g, hierarchyDepth as h, isSameHierarchy as i, hierarchyDistance as j, commonAncestor as k, ancestorsFqn as l, compareFqnHierarchically as m, nameFromFqn as n, compareByFqnHierarchically as o, parentFqn as p, sortParentsFirst as q, r, sortByFqnHierarchically as s, t, sortNaturalByFqn as u, getOrCreate as v, isString as w, isNonEmptyArray as x, union as y, intersection as z };
|