@likec4/core 1.12.1 → 1.13.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 (35) hide show
  1. package/dist/index.cjs +777 -251
  2. package/dist/index.d.cts +301 -32
  3. package/dist/index.d.mts +301 -32
  4. package/dist/index.d.ts +301 -32
  5. package/dist/index.mjs +774 -252
  6. package/dist/shared/{core.BvFch1jG.mjs → core.BJDxVHFh.mjs} +19 -19
  7. package/dist/shared/{core.dY8efyk0.d.ts → core.C4jDMQ1i.d.cts} +242 -238
  8. package/dist/shared/{core.dY8efyk0.d.cts → core.C4jDMQ1i.d.mts} +242 -238
  9. package/dist/shared/{core.dY8efyk0.d.mts → core.C4jDMQ1i.d.ts} +242 -238
  10. package/dist/shared/{core.CTiE4teS.cjs → core.IR7XOEkQ.cjs} +19 -18
  11. package/dist/types/index.cjs +1 -1
  12. package/dist/types/index.d.cts +1 -1
  13. package/dist/types/index.d.mts +1 -1
  14. package/dist/types/index.d.ts +1 -1
  15. package/dist/types/index.mjs +1 -1
  16. package/package.json +4 -3
  17. package/src/builder/Builder.element.ts +221 -0
  18. package/src/builder/Builder.model.ts +346 -0
  19. package/src/builder/Builder.test-d.ts +69 -0
  20. package/src/builder/Builder.ts +574 -0
  21. package/src/builder/Builder.view.ts +358 -0
  22. package/src/builder/Builder.views.ts +318 -0
  23. package/src/builder/_types.ts +195 -0
  24. package/src/builder/index.ts +5 -0
  25. package/src/index.ts +4 -0
  26. package/src/model/LikeC4DiagramModel.ts +5 -5
  27. package/src/model/LikeC4Model.ts +63 -46
  28. package/src/model/LikeC4ViewModel.ts +7 -7
  29. package/src/model/__test__/fixture.ts +5 -0
  30. package/src/types/element.ts +19 -11
  31. package/src/types/model.ts +13 -8
  32. package/src/types/relation.ts +1 -1
  33. package/src/types/view-changes.ts +6 -2
  34. package/src/types/view.ts +53 -22
  35. package/src/utils/fqn.ts +12 -11
package/dist/index.mjs CHANGED
@@ -1,5 +1,720 @@
1
- import { u, e, n as nonNullable, D as DefaultRelationshipColor, a as DefaultElementShape, b as DefaultThemeColor } from './shared/core.BvFch1jG.mjs';
2
- export { A as AsFqn, B as BorderStyles, K as DefaultArrowType, J as DefaultLineStyle, E as ElementShapes, c as Expr, W as StepEdgeId, Y as extractStep, a0 as getBBoxCenter, Z as getParallelStepsPrefix, i as invariant, G as isAndOperator, O as isAutoLayoutDirection, _ as isComputedDynamicView, $ as isComputedElementView, h as isCustomElement, x as isCustomRelationExpr, S as isDynamicView, Q as isDynamicViewIncludeRule, R as isDynamicViewParallelSteps, m as isElement, k as isElementKindExpr, p as isElementPredicateExpr, f as isElementRef, l as isElementTagExpr, T as isElementView, o as isElementWhere, g as isExpandedElementExpr, U as isExtendsElementView, r as isInOut, s as isIncoming, C as isKindEqual, F as isNotOperator, H as isOrOperator, t as isOutgoing, q as isRelation, v as isRelationExpression, y as isRelationPredicateExpr, w as isRelationWhere, V as isScopedElementView, X as isStepEdgeId, z as isTagEqual, L as isThemeColor, P as isViewRuleAutoLayout, M as isViewRulePredicate, N as isViewRuleStyle, j as isWildcard, d as nonexhaustive, I as whereOperatorAsPredicate } from './shared/core.BvFch1jG.mjs';
1
+ import { u as u$1, i as isElementPredicateExpr, n as n$2, a as invariant, b as isScopedElementView, D as DefaultThemeColor, c as DefaultElementShape, e, d as nonNullable, f as DefaultRelationshipColor } from './shared/core.BJDxVHFh.mjs';
2
+ export { A as AsFqn, B as BorderStyles, M as DefaultArrowType, L as DefaultLineStyle, E as ElementShapes, g as Expr, X as StepEdgeId, Z as extractStep, a1 as getBBoxCenter, _ as getParallelStepsPrefix, I as isAndOperator, Q as isAutoLayoutDirection, $ as isComputedDynamicView, a0 as isComputedElementView, l as isCustomElement, z as isCustomRelationExpr, U as isDynamicView, S as isDynamicViewIncludeRule, T as isDynamicViewParallelSteps, q as isElement, o as isElementKindExpr, j as isElementRef, p as isElementTagExpr, V as isElementView, r as isElementWhere, k as isExpandedElementExpr, W as isExtendsElementView, t as isInOut, v as isIncoming, G as isKindEqual, H as isNotOperator, J as isOrOperator, w as isOutgoing, s as isRelation, x as isRelationExpression, C as isRelationPredicateExpr, y as isRelationWhere, Y as isStepEdgeId, F as isTagEqual, N as isThemeColor, R as isViewRuleAutoLayout, O as isViewRulePredicate, P as isViewRuleStyle, m as isWildcard, h as nonexhaustive, K as whereOperatorAsPredicate } from './shared/core.BJDxVHFh.mjs';
3
+ import defu from 'defu';
4
+
5
+ function r$1(...n){return u$1(Object.values,n)}
6
+
7
+ function i$2(...e){return u$1(r,e)}var r=(e,t)=>e.length>=t;
8
+
9
+ function o$2(r,n){let e=Math.ceil(r),t=Math.floor(n);if(t<e)throw new RangeError(`randomInteger: The range [${r.toString()},${n.toString()}] contains no integer`);return Math.floor(Math.random()*(t-e+1)+e)}
10
+
11
+ function i$1(...e){return u$1(u,e)}function u(e,o){let t={};for(let[r,n]of Object.entries(e))o(n,r,e)&&(t[r]=n);return t}
12
+
13
+ function m(...a){return u$1(o$1,a,p)}var o$1=(a,e)=>a.map(e),p=a=>(e,r,t)=>({done:!1,hasNext:!0,next:a(e,r,t)});
14
+
15
+ function l$1(...n){return u$1(d,n)}function d(n,o){let e={};for(let[a,t]of n.entries()){let[y,u]=o(t,a,n);e[y]=u;}return e}
16
+
17
+ function i(...e){return u$1(o,e)}function o(e,u){let a={};for(let[n,r]of Object.entries(e)){let l=u(r,n,e);a[n]=l;}return a}
18
+
19
+ function t$1(r){return typeof r=="string"}
20
+
21
+ function n$1(e){return !!e}
22
+
23
+ function t(n){return typeof n=="function"}
24
+
25
+ function l(n){return n!=null}
26
+
27
+ function n(...r){return u$1(Object.fromEntries,r)}
28
+
29
+ function getDefaultExportFromCjs (x) {
30
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
31
+ }
32
+
33
+ var naturalCompareLite = {exports: {}};
34
+
35
+ var hasRequiredNaturalCompareLite;
36
+
37
+ function requireNaturalCompareLite () {
38
+ if (hasRequiredNaturalCompareLite) return naturalCompareLite.exports;
39
+ hasRequiredNaturalCompareLite = 1;
40
+ /*
41
+ * @version 1.4.0
42
+ * @date 2015-10-26
43
+ * @stability 3 - Stable
44
+ * @author Lauri Rooden (https://github.com/litejs/natural-compare-lite)
45
+ * @license MIT License
46
+ */
47
+
48
+
49
+ var naturalCompare = function(a, b) {
50
+ var i, codeA
51
+ , codeB = 1
52
+ , posA = 0
53
+ , posB = 0
54
+ , alphabet = String.alphabet;
55
+
56
+ function getCode(str, pos, code) {
57
+ if (code) {
58
+ for (i = pos; code = getCode(str, i), code < 76 && code > 65;) ++i;
59
+ return +str.slice(pos - 1, i)
60
+ }
61
+ code = alphabet && alphabet.indexOf(str.charAt(pos));
62
+ return code > -1 ? code + 76 : ((code = str.charCodeAt(pos) || 0), code < 45 || code > 127) ? code
63
+ : code < 46 ? 65 // -
64
+ : code < 48 ? code - 1
65
+ : code < 58 ? code + 18 // 0-9
66
+ : code < 65 ? code - 11
67
+ : code < 91 ? code + 11 // A-Z
68
+ : code < 97 ? code - 37
69
+ : code < 123 ? code + 5 // a-z
70
+ : code - 63
71
+ }
72
+
73
+
74
+ if ((a+="") != (b+="")) for (;codeB;) {
75
+ codeA = getCode(a, posA++);
76
+ codeB = getCode(b, posB++);
77
+
78
+ if (codeA < 76 && codeB < 76 && codeA > 66 && codeB > 66) {
79
+ codeA = getCode(a, posA, posA);
80
+ codeB = getCode(b, posB, posA = i);
81
+ posB = i;
82
+ }
83
+
84
+ if (codeA != codeB) return (codeA < codeB) ? -1 : 1
85
+ }
86
+ return 0
87
+ };
88
+
89
+ try {
90
+ naturalCompareLite.exports = naturalCompare;
91
+ } catch (e) {
92
+ String.naturalCompare = naturalCompare;
93
+ }
94
+ return naturalCompareLite.exports;
95
+ }
96
+
97
+ var naturalCompareLiteExports = requireNaturalCompareLite();
98
+ const compare = /*@__PURE__*/getDefaultExportFromCjs(naturalCompareLiteExports);
99
+
100
+ function compareNatural(a, b) {
101
+ if (a === b) return 0;
102
+ if (t$1(a)) {
103
+ if (t$1(b)) {
104
+ return compare(a, b);
105
+ }
106
+ return 1;
107
+ }
108
+ return t$1(b) ? -1 : 0;
109
+ }
110
+
111
+ function isString(value) {
112
+ return value != null && typeof value === "string";
113
+ }
114
+ function isNonEmptyArray(arr) {
115
+ return !!arr && Array.isArray(arr) && arr.length > 0;
116
+ }
117
+
118
+ function nameFromFqn(fqn) {
119
+ const lastDot = fqn.lastIndexOf(".");
120
+ if (lastDot > 0) {
121
+ return fqn.slice(lastDot + 1);
122
+ } else {
123
+ return fqn;
124
+ }
125
+ }
126
+ function isAncestor(...args) {
127
+ const ancestor = isString(args[0]) ? args[0] : args[0].id;
128
+ const another = isString(args[1]) ? args[1] : args[1].id;
129
+ return another.startsWith(ancestor + ".");
130
+ }
131
+ function isSameHierarchy(one, another) {
132
+ const first = isString(one) ? one : one.id;
133
+ const second = isString(another) ? another : another.id;
134
+ return first === second || second.startsWith(first + ".") || first.startsWith(second + ".");
135
+ }
136
+ function isDescendantOf(ancestors) {
137
+ const predicates = ancestors.flatMap((a) => [(e) => e.id === a.id, (e) => isAncestor(a, e)]);
138
+ return (e) => predicates.some((p) => p(e));
139
+ }
140
+ function notDescendantOf(ancestors) {
141
+ const isDescendant = isDescendantOf(ancestors);
142
+ return (e) => !isDescendant(e);
143
+ }
144
+ function commonAncestor(first, second) {
145
+ const parentA = parentFqn(first);
146
+ const parentB = parentFqn(second);
147
+ if (parentA === parentB) {
148
+ return parentA;
149
+ }
150
+ if (!parentA || !parentB) {
151
+ return null;
152
+ }
153
+ const a = first.split(".");
154
+ const b = second.split(".");
155
+ let ancestor = null;
156
+ while (a.length > 1 && b.length > 1 && !!a[0] && a[0] === b[0]) {
157
+ ancestor = ancestor ? `${ancestor}.${a[0]}` : a[0];
158
+ a.shift();
159
+ b.shift();
160
+ }
161
+ return ancestor;
162
+ }
163
+ function parentFqn(fqn) {
164
+ const lastDot = fqn.lastIndexOf(".");
165
+ if (lastDot > 0) {
166
+ return fqn.slice(0, lastDot);
167
+ }
168
+ return null;
169
+ }
170
+ function parentFqnPredicate(parent) {
171
+ const prefix = parent + ".";
172
+ return (e) => !!e.parent && (e.parent === parent || e.parent.startsWith(prefix));
173
+ }
174
+ function ancestorsFqn(fqn) {
175
+ const path = fqn.split(".");
176
+ path.pop();
177
+ if (path.length === 0) {
178
+ return [];
179
+ }
180
+ return path.reduce((acc, part, idx) => {
181
+ if (idx === 0) {
182
+ acc.push(part);
183
+ return acc;
184
+ }
185
+ acc.unshift(`${acc[0]}.${part}`);
186
+ return acc;
187
+ }, []);
188
+ }
189
+ function compareFqnHierarchically(a, b) {
190
+ const depthA = a.split(".").length;
191
+ const depthB = b.split(".").length;
192
+ switch (true) {
193
+ case depthA > depthB: {
194
+ return 1;
195
+ }
196
+ case depthA < depthB: {
197
+ return -1;
198
+ }
199
+ default: {
200
+ return 0;
201
+ }
202
+ }
203
+ }
204
+ function compareByFqnHierarchically(a, b) {
205
+ return compareFqnHierarchically(a.id, b.id);
206
+ }
207
+ function sortByFqnHierarchically(array) {
208
+ return array.map((item) => ({ item, fqn: item.id.split(".") })).sort((a, b) => {
209
+ return a.fqn.length - b.fqn.length;
210
+ }).map(({ item }) => item);
211
+ }
212
+ function sortNaturalByFqn(array) {
213
+ return array.map((item) => ({ item, fqn: item.id.split(".") })).sort((a, b) => {
214
+ if (a.fqn.length !== b.fqn.length) {
215
+ return a.fqn.length - b.fqn.length;
216
+ }
217
+ for (let i = 0; i < a.fqn.length; i++) {
218
+ const compare = compareNatural(a.fqn[i], b.fqn[i]);
219
+ if (compare !== 0) {
220
+ return compare;
221
+ }
222
+ }
223
+ return 0;
224
+ }).map(({ item }) => item);
225
+ }
226
+
227
+ function parseWhere(where) {
228
+ if (t$1(where)) {
229
+ const op = where;
230
+ switch (true) {
231
+ case op.startsWith("tag is not #"):
232
+ return {
233
+ tag: {
234
+ neq: op.replace("tag is not #", "")
235
+ }
236
+ };
237
+ case op.startsWith("tag is #"):
238
+ return {
239
+ tag: {
240
+ eq: op.replace("tag is #", "")
241
+ }
242
+ };
243
+ case op.startsWith("kind is not "):
244
+ return {
245
+ kind: {
246
+ neq: op.replace("kind is not ", "")
247
+ }
248
+ };
249
+ case op.startsWith("kind is "):
250
+ return {
251
+ kind: {
252
+ eq: op.replace("kind is ", "")
253
+ }
254
+ };
255
+ default:
256
+ throw new Error(`Unknown where operator: ${where}`);
257
+ }
258
+ }
259
+ if (where.and) {
260
+ return {
261
+ and: m(where.and, parseWhere)
262
+ };
263
+ }
264
+ if (where.or) {
265
+ return {
266
+ or: m(where.or, parseWhere)
267
+ };
268
+ }
269
+ if (where.not) {
270
+ return {
271
+ not: parseWhere(where.not)
272
+ };
273
+ }
274
+ throw new Error(`Unknown where operator: ${where}`);
275
+ }
276
+ function $include(...args) {
277
+ return (b) => {
278
+ let expr = $expr(args[0]);
279
+ const isElement = isElementPredicateExpr(expr);
280
+ if (args.length === 2) {
281
+ const condition = args[1].where ? parseWhere(args[1].where) : void 0;
282
+ if (condition) {
283
+ expr = {
284
+ where: {
285
+ expr,
286
+ condition
287
+ }
288
+ };
289
+ }
290
+ const custom = args[1].with;
291
+ if (custom) {
292
+ if (isElement) {
293
+ expr = {
294
+ custom: {
295
+ ...custom,
296
+ expr
297
+ }
298
+ };
299
+ } else {
300
+ expr = {
301
+ customRelation: {
302
+ ...custom,
303
+ relation: expr
304
+ }
305
+ };
306
+ }
307
+ }
308
+ }
309
+ b.include(expr);
310
+ return b;
311
+ };
312
+ }
313
+ function $exclude(...args) {
314
+ return (b) => {
315
+ let expr = $expr(args[0]);
316
+ if (args.length === 2 && args[1].where) {
317
+ const condition = parseWhere(args[1].where);
318
+ expr = {
319
+ where: {
320
+ expr,
321
+ condition
322
+ }
323
+ };
324
+ }
325
+ b.exclude(expr);
326
+ return b;
327
+ };
328
+ }
329
+ function $expr(expr) {
330
+ if (!t$1(expr)) {
331
+ return expr;
332
+ }
333
+ if (expr === "*") {
334
+ return { wildcard: true };
335
+ }
336
+ if (expr.startsWith("->")) {
337
+ if (expr.endsWith("->")) {
338
+ return {
339
+ inout: $expr(expr.replace(/->/g, "").trim())
340
+ };
341
+ }
342
+ return {
343
+ incoming: $expr(expr.replace("-> ", ""))
344
+ };
345
+ }
346
+ if (expr.endsWith(" ->")) {
347
+ return {
348
+ outgoing: $expr(expr.replace(" ->", ""))
349
+ };
350
+ }
351
+ if (expr.includes(" <-> ")) {
352
+ const [source, target] = expr.split(" <-> ");
353
+ return {
354
+ source: $expr(source),
355
+ target: $expr(target),
356
+ isBidirectional: true
357
+ };
358
+ }
359
+ if (expr.includes(" -> ")) {
360
+ const [source, target] = expr.split(" -> ");
361
+ return {
362
+ source: $expr(source),
363
+ target: $expr(target)
364
+ };
365
+ }
366
+ if (expr.endsWith("._")) {
367
+ return {
368
+ expanded: expr.replace("._", "")
369
+ };
370
+ }
371
+ if (expr.endsWith(".*")) {
372
+ return {
373
+ element: expr.replace(".*", ""),
374
+ isDescedants: true
375
+ };
376
+ }
377
+ return {
378
+ element: expr,
379
+ isDescedants: false
380
+ };
381
+ }
382
+ function $style(element, { notation, ...style }) {
383
+ return (b) => b.style({
384
+ targets: (n$2(element) ? element : [element]).map((e) => $expr(e)),
385
+ ...notation ? { notation } : {},
386
+ style: {
387
+ ...style
388
+ }
389
+ });
390
+ }
391
+ function $autoLayout(layout) {
392
+ return (b) => b.autoLayout(layout);
393
+ }
394
+ function $rules(...rules) {
395
+ return (b) => rules.reduce((b2, rule) => rule(b2), b);
396
+ }
397
+
398
+ function builder(spec, _elements = /* @__PURE__ */ new Map(), _relations = [], _views = /* @__PURE__ */ new Map()) {
399
+ const toLikeC4Specification = () => ({
400
+ tags: spec.tags ?? [],
401
+ elements: {
402
+ ...spec.elements
403
+ },
404
+ relationships: {
405
+ ...spec.relationships
406
+ }
407
+ });
408
+ const mapLinks = (links) => {
409
+ if (!links || !i$2(links, 1)) {
410
+ return null;
411
+ }
412
+ return m(links, (l) => typeof l === "string" ? { url: l } : l);
413
+ };
414
+ const mkViewBuilder = (view) => {
415
+ const viewBuilder = {
416
+ autoLayout(autoLayout) {
417
+ view.rules.push({
418
+ direction: autoLayout
419
+ });
420
+ return viewBuilder;
421
+ },
422
+ exclude(expr) {
423
+ view.rules.push({
424
+ exclude: [expr]
425
+ });
426
+ return viewBuilder;
427
+ },
428
+ include(expr) {
429
+ view.rules.push({
430
+ include: [expr]
431
+ });
432
+ return viewBuilder;
433
+ },
434
+ style(rule) {
435
+ view.rules.push(rule);
436
+ return viewBuilder;
437
+ }
438
+ // title(title: string) {
439
+ // view.title = title
440
+ // return viewBuilder
441
+ // },
442
+ // description(description: string) {
443
+ // view.description = description
444
+ // return viewBuilder
445
+ // }
446
+ };
447
+ return viewBuilder;
448
+ };
449
+ const self = {
450
+ get Types() {
451
+ throw new Error("Types are not available in runtime");
452
+ },
453
+ clone: () => builder(
454
+ structuredClone(spec),
455
+ structuredClone(_elements),
456
+ structuredClone(_relations),
457
+ structuredClone(_views)
458
+ ),
459
+ __model: () => ({
460
+ addElement: (element) => {
461
+ const parent = parentFqn(element.id);
462
+ if (parent) {
463
+ invariant(
464
+ _elements.get(parent),
465
+ `Parent element with id "${parent}" not found for element with id "${element.id}"`
466
+ );
467
+ }
468
+ if (_elements.has(element.id)) {
469
+ throw new Error(`Element with id "${element.id}" already exists`);
470
+ }
471
+ _elements.set(element.id, element);
472
+ return self;
473
+ },
474
+ addRelation(relation) {
475
+ const sourceEl = _elements.get(relation.source);
476
+ invariant(sourceEl, `Element with id "${relation.source}" not found`);
477
+ const targetEl = _elements.get(relation.target);
478
+ invariant(targetEl, `Element with id "${relation.target}" not found`);
479
+ invariant(
480
+ !isSameHierarchy(sourceEl, targetEl),
481
+ "Cannot create relationship between elements in the same hierarchy"
482
+ );
483
+ _relations.push({
484
+ id: `rel${_relations.length + 1}`,
485
+ ...relation
486
+ });
487
+ return self;
488
+ },
489
+ /**
490
+ * Fully qualified name for nested elements
491
+ */
492
+ fqn(id) {
493
+ return id;
494
+ },
495
+ addSourcelessRelation() {
496
+ throw new Error("Can be called only in nested model");
497
+ }
498
+ }),
499
+ __views: () => ({
500
+ addView: (view) => {
501
+ if (isScopedElementView(view)) {
502
+ invariant(_elements.get(view.viewOf), `Invalid view ${view.id}, wlement with id "${view.viewOf}" not found`);
503
+ }
504
+ _views.set(view.id, view);
505
+ return self;
506
+ }
507
+ }),
508
+ build: () => ({
509
+ specification: toLikeC4Specification(),
510
+ elements: n(Array.from(_elements.entries())),
511
+ relations: l$1(_relations, (r) => [r.id, r]),
512
+ views: n(Array.from(_views.entries()))
513
+ }),
514
+ helpers: () => ({
515
+ model: {
516
+ model: (...ops) => {
517
+ return (b) => {
518
+ const v = b.__model();
519
+ for (const op of ops) {
520
+ op(v);
521
+ }
522
+ return b;
523
+ };
524
+ },
525
+ rel: (source, target, _props) => {
526
+ return (b) => {
527
+ const {
528
+ title = "",
529
+ links: _links = [],
530
+ ...props
531
+ } = defu(
532
+ typeof _props === "string" ? { title: _props } : { ..._props },
533
+ { title: null, links: null }
534
+ );
535
+ const links = mapLinks(_links);
536
+ b.addRelation({
537
+ source,
538
+ target,
539
+ title,
540
+ ...links && { links },
541
+ ...props
542
+ });
543
+ return b;
544
+ };
545
+ },
546
+ relTo: (target, _props) => {
547
+ return (b) => {
548
+ const {
549
+ title = "",
550
+ links: _links = [],
551
+ ...props
552
+ } = defu(
553
+ typeof _props === "string" ? { title: _props } : { ..._props },
554
+ { title: null, links: null }
555
+ );
556
+ const links = mapLinks(_links);
557
+ b.addSourcelessRelation({
558
+ target,
559
+ title,
560
+ ...links && { links },
561
+ ...props
562
+ });
563
+ return b;
564
+ };
565
+ },
566
+ ...i(
567
+ spec.elements,
568
+ ({ style: specStyle, ...spec2 }, kind) => (id, _props) => {
569
+ const add = (b) => {
570
+ const {
571
+ links: _links,
572
+ icon: _icon,
573
+ style,
574
+ title,
575
+ ...props
576
+ } = typeof _props === "string" ? { title: _props } : { ..._props };
577
+ const links = mapLinks(_links);
578
+ const icon = _icon ?? specStyle?.icon;
579
+ const _id = b.fqn(id);
580
+ b.addElement({
581
+ id: _id,
582
+ kind,
583
+ title: title ?? nameFromFqn(_id),
584
+ description: null,
585
+ technology: null,
586
+ tags: null,
587
+ color: specStyle?.color ?? DefaultThemeColor,
588
+ shape: specStyle?.shape ?? DefaultElementShape,
589
+ style: i$1({
590
+ border: specStyle?.border,
591
+ opacity: specStyle?.opacity,
592
+ ...style
593
+ }, l),
594
+ links,
595
+ ...icon && { icon },
596
+ ...spec2,
597
+ ...props
598
+ });
599
+ return b;
600
+ };
601
+ add.with = (...ops) => (b) => {
602
+ add(b);
603
+ const nestedBuilder = {
604
+ ...b,
605
+ fqn: (child) => `${b.fqn(id)}.${child}`,
606
+ addSourcelessRelation: (relation) => {
607
+ return b.addRelation({
608
+ ...relation,
609
+ source: b.fqn(id)
610
+ });
611
+ }
612
+ };
613
+ for (const op of ops) {
614
+ op(nestedBuilder);
615
+ }
616
+ return b;
617
+ };
618
+ return add;
619
+ }
620
+ )
621
+ },
622
+ views: {
623
+ views: (...ops) => {
624
+ return (b) => {
625
+ const v = b.__views();
626
+ for (const op of ops) {
627
+ op(v);
628
+ }
629
+ return b;
630
+ };
631
+ },
632
+ view: (id, _props, builder2) => {
633
+ if (t(_props)) {
634
+ builder2 = _props;
635
+ _props = {};
636
+ }
637
+ return (b) => {
638
+ const {
639
+ links: _links = [],
640
+ title = null,
641
+ ...props
642
+ } = typeof _props === "string" ? { title: _props } : { ..._props };
643
+ const links = mapLinks(_links);
644
+ const view = {
645
+ id,
646
+ __: "element",
647
+ title,
648
+ description: null,
649
+ tags: null,
650
+ rules: [],
651
+ links,
652
+ customColorDefinitions: {},
653
+ ...props
654
+ };
655
+ b.addView(view);
656
+ if (builder2) {
657
+ builder2(mkViewBuilder(view));
658
+ }
659
+ return b;
660
+ };
661
+ },
662
+ viewOf: (id, viewOf, _props, builder2) => {
663
+ if (t(_props)) {
664
+ builder2 = _props;
665
+ _props = {};
666
+ }
667
+ return (b) => {
668
+ const {
669
+ links: _links = [],
670
+ title = null,
671
+ ...props
672
+ } = typeof _props === "string" ? { title: _props } : { ..._props };
673
+ const links = mapLinks(_links);
674
+ const view = {
675
+ id,
676
+ __: "element",
677
+ viewOf,
678
+ title,
679
+ description: null,
680
+ tags: null,
681
+ rules: [],
682
+ links,
683
+ customColorDefinitions: {},
684
+ ...props
685
+ };
686
+ b.addView(view);
687
+ if (builder2) {
688
+ builder2(mkViewBuilder(view));
689
+ }
690
+ return b;
691
+ };
692
+ },
693
+ $autoLayout,
694
+ $exclude,
695
+ $expr,
696
+ $include,
697
+ $rules,
698
+ $style
699
+ }
700
+ }),
701
+ with: (...ops) => {
702
+ return ops.reduce((b, op) => op(b), self).clone();
703
+ }
704
+ };
705
+ return self;
706
+ }
707
+ var Builder;
708
+ ((Builder2) => {
709
+ function forSpecification(spec) {
710
+ const b = builder(spec);
711
+ return {
712
+ ...b.helpers(),
713
+ builder: b
714
+ };
715
+ }
716
+ Builder2.forSpecification = forSpecification;
717
+ })(Builder || (Builder = {}));
3
718
 
4
719
  const { min: min$4, max: max$4 } = Math;
5
720
 
@@ -3655,18 +4370,8 @@ function computeColorValues(color) {
3655
4370
  }
3656
4371
  }
3657
4372
 
3658
- function r$1(...n){return u(Object.values,n)}
3659
-
3660
- function i(...e){return u(r,e)}var r=(e,t)=>e.length>=t;
3661
-
3662
- function o(r,n){let e=Math.ceil(r),t=Math.floor(n);if(t<e)throw new RangeError(`randomInteger: The range [${r.toString()},${n.toString()}] contains no integer`);return Math.floor(Math.random()*(t-e+1)+e)}
3663
-
3664
- function t(r){return typeof r=="string"}
3665
-
3666
- function n(e){return !!e}
3667
-
3668
4373
  function getId(element) {
3669
- return t(element) ? element : element.id;
4374
+ return t$1(element) ? element : element.id;
3670
4375
  }
3671
4376
 
3672
4377
  class LikeC4DiagramModel {
@@ -3905,204 +4610,6 @@ class LikeC4DiagramModel {
3905
4610
  LikeC4DiagramModel2.Connection = Connection;
3906
4611
  })(LikeC4DiagramModel || (LikeC4DiagramModel = {}));
3907
4612
 
3908
- function getDefaultExportFromCjs (x) {
3909
- return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
3910
- }
3911
-
3912
- var naturalCompareLite = {exports: {}};
3913
-
3914
- var hasRequiredNaturalCompareLite;
3915
-
3916
- function requireNaturalCompareLite () {
3917
- if (hasRequiredNaturalCompareLite) return naturalCompareLite.exports;
3918
- hasRequiredNaturalCompareLite = 1;
3919
- /*
3920
- * @version 1.4.0
3921
- * @date 2015-10-26
3922
- * @stability 3 - Stable
3923
- * @author Lauri Rooden (https://github.com/litejs/natural-compare-lite)
3924
- * @license MIT License
3925
- */
3926
-
3927
-
3928
- var naturalCompare = function(a, b) {
3929
- var i, codeA
3930
- , codeB = 1
3931
- , posA = 0
3932
- , posB = 0
3933
- , alphabet = String.alphabet;
3934
-
3935
- function getCode(str, pos, code) {
3936
- if (code) {
3937
- for (i = pos; code = getCode(str, i), code < 76 && code > 65;) ++i;
3938
- return +str.slice(pos - 1, i)
3939
- }
3940
- code = alphabet && alphabet.indexOf(str.charAt(pos));
3941
- return code > -1 ? code + 76 : ((code = str.charCodeAt(pos) || 0), code < 45 || code > 127) ? code
3942
- : code < 46 ? 65 // -
3943
- : code < 48 ? code - 1
3944
- : code < 58 ? code + 18 // 0-9
3945
- : code < 65 ? code - 11
3946
- : code < 91 ? code + 11 // A-Z
3947
- : code < 97 ? code - 37
3948
- : code < 123 ? code + 5 // a-z
3949
- : code - 63
3950
- }
3951
-
3952
-
3953
- if ((a+="") != (b+="")) for (;codeB;) {
3954
- codeA = getCode(a, posA++);
3955
- codeB = getCode(b, posB++);
3956
-
3957
- if (codeA < 76 && codeB < 76 && codeA > 66 && codeB > 66) {
3958
- codeA = getCode(a, posA, posA);
3959
- codeB = getCode(b, posB, posA = i);
3960
- posB = i;
3961
- }
3962
-
3963
- if (codeA != codeB) return (codeA < codeB) ? -1 : 1
3964
- }
3965
- return 0
3966
- };
3967
-
3968
- try {
3969
- naturalCompareLite.exports = naturalCompare;
3970
- } catch (e) {
3971
- String.naturalCompare = naturalCompare;
3972
- }
3973
- return naturalCompareLite.exports;
3974
- }
3975
-
3976
- var naturalCompareLiteExports = requireNaturalCompareLite();
3977
- const compare = /*@__PURE__*/getDefaultExportFromCjs(naturalCompareLiteExports);
3978
-
3979
- function compareNatural(a, b) {
3980
- if (a === b) return 0;
3981
- if (t(a)) {
3982
- if (t(b)) {
3983
- return compare(a, b);
3984
- }
3985
- return 1;
3986
- }
3987
- return t(b) ? -1 : 0;
3988
- }
3989
-
3990
- function isString(value) {
3991
- return value != null && typeof value === "string";
3992
- }
3993
- function isNonEmptyArray(arr) {
3994
- return !!arr && Array.isArray(arr) && arr.length > 0;
3995
- }
3996
-
3997
- function nameFromFqn(fqn) {
3998
- const lastDot = fqn.lastIndexOf(".");
3999
- if (lastDot > 0) {
4000
- return fqn.slice(lastDot + 1);
4001
- } else {
4002
- return fqn;
4003
- }
4004
- }
4005
- function isAncestor(...args) {
4006
- const ancestor = isString(args[0]) ? args[0] : args[0].id;
4007
- const another = isString(args[1]) ? args[1] : args[1].id;
4008
- return another.startsWith(ancestor + ".");
4009
- }
4010
- function isSameHierarchy(one, another) {
4011
- const first = isString(one) ? one : one.id;
4012
- const second = isString(another) ? another : another.id;
4013
- return first === second || second.startsWith(first + ".") || first.startsWith(second + ".");
4014
- }
4015
- function isDescendantOf(ancestors) {
4016
- const predicates = ancestors.flatMap((a) => [(e) => e.id === a.id, (e) => isAncestor(a, e)]);
4017
- return (e) => predicates.some((p) => p(e));
4018
- }
4019
- function notDescendantOf(ancestors) {
4020
- const isDescendant = isDescendantOf(ancestors);
4021
- return (e) => !isDescendant(e);
4022
- }
4023
- function commonAncestor(first, second) {
4024
- const parentA = parentFqn(first);
4025
- const parentB = parentFqn(second);
4026
- if (parentA === parentB) {
4027
- return parentA;
4028
- }
4029
- if (!parentA || !parentB) {
4030
- return null;
4031
- }
4032
- const a = first.split(".");
4033
- const b = second.split(".");
4034
- let ancestor = null;
4035
- while (a.length > 1 && b.length > 1 && !!a[0] && a[0] === b[0]) {
4036
- ancestor = ancestor ? `${ancestor}.${a[0]}` : a[0];
4037
- a.shift();
4038
- b.shift();
4039
- }
4040
- return ancestor;
4041
- }
4042
- function parentFqn(fqn) {
4043
- const lastDot = fqn.lastIndexOf(".");
4044
- if (lastDot > 0) {
4045
- return fqn.slice(0, lastDot);
4046
- }
4047
- return null;
4048
- }
4049
- function parentFqnPredicate(parent) {
4050
- const prefix = parent + ".";
4051
- return (e) => !!e.parent && (e.parent === parent || e.parent.startsWith(prefix));
4052
- }
4053
- function ancestorsFqn(fqn) {
4054
- const path = fqn.split(".");
4055
- path.pop();
4056
- if (path.length === 0) {
4057
- return [];
4058
- }
4059
- return path.reduce((acc, part, idx) => {
4060
- if (idx === 0) {
4061
- acc.push(part);
4062
- return acc;
4063
- }
4064
- acc.unshift(`${acc[0]}.${part}`);
4065
- return acc;
4066
- }, []);
4067
- }
4068
- function compareFqnHierarchically(a, b) {
4069
- const depthA = a.split(".").length;
4070
- const depthB = b.split(".").length;
4071
- switch (true) {
4072
- case depthA > depthB: {
4073
- return 1;
4074
- }
4075
- case depthA < depthB: {
4076
- return -1;
4077
- }
4078
- default: {
4079
- return 0;
4080
- }
4081
- }
4082
- }
4083
- function compareByFqnHierarchically(a, b) {
4084
- return compareFqnHierarchically(a.id, b.id);
4085
- }
4086
- function sortByFqnHierarchically(array) {
4087
- return array.map((item) => ({ item, fqn: item.id.split(".") })).sort((a, b) => {
4088
- return a.fqn.length - b.fqn.length;
4089
- }).map(({ item }) => item);
4090
- }
4091
- function sortNaturalByFqn(array) {
4092
- return array.map((item) => ({ item, fqn: item.id.split(".") })).sort((a, b) => {
4093
- if (a.fqn.length !== b.fqn.length) {
4094
- return a.fqn.length - b.fqn.length;
4095
- }
4096
- for (let i = 0; i < a.fqn.length; i++) {
4097
- const compare = compareNatural(a.fqn[i], b.fqn[i]);
4098
- if (compare !== 0) {
4099
- return compare;
4100
- }
4101
- }
4102
- return 0;
4103
- }).map(({ item }) => item);
4104
- }
4105
-
4106
4613
  class LikeC4ViewModel {
4107
4614
  constructor(view, model) {
4108
4615
  this.view = view;
@@ -4206,7 +4713,7 @@ class LikeC4ViewModel {
4206
4713
  });
4207
4714
  }
4208
4715
  incomers(element, filter = "all") {
4209
- return this.incoming(element, filter).map((r) => r.source);
4716
+ return [...new Set(this.incoming(element, filter).map((r) => r.source))];
4210
4717
  }
4211
4718
  /**
4212
4719
  * Outgoing relationships from the element and its descendants
@@ -4225,7 +4732,7 @@ class LikeC4ViewModel {
4225
4732
  });
4226
4733
  }
4227
4734
  outgoers(element, filter = "all") {
4228
- return this.outgoing(element, filter).map((r) => r.target);
4735
+ return [...new Set(this.outgoing(element, filter).map((r) => r.target))];
4229
4736
  }
4230
4737
  }
4231
4738
  ((LikeC4ViewModel2) => {
@@ -4327,7 +4834,7 @@ class LikeC4ViewModel {
4327
4834
  })(LikeC4ViewModel || (LikeC4ViewModel = {}));
4328
4835
 
4329
4836
  class LikeC4Model {
4330
- constructor(type, sourcemodel, elements, relations) {
4837
+ constructor(type, sourcemodel, elements, relations, views, ViewModelClass) {
4331
4838
  this.type = type;
4332
4839
  this.sourcemodel = sourcemodel;
4333
4840
  for (const el of elements) {
@@ -4336,6 +4843,9 @@ class LikeC4Model {
4336
4843
  for (const rel of relations) {
4337
4844
  this.addRelation(rel);
4338
4845
  }
4846
+ this._views = new Map(
4847
+ r$1(views).map((view) => [view.id, new ViewModelClass(view, this)])
4848
+ );
4339
4849
  }
4340
4850
  _elements = /* @__PURE__ */ new Map();
4341
4851
  // Parent element for given FQN
@@ -4351,37 +4861,7 @@ class LikeC4Model {
4351
4861
  // Relationships inside the element, among descendants
4352
4862
  _internal = /* @__PURE__ */ new Map();
4353
4863
  _cacheAscendingSiblings = /* @__PURE__ */ new Map();
4354
- _views = /* @__PURE__ */ new Map();
4355
- static create(source) {
4356
- if (source.__ === "layouted") {
4357
- return LikeC4Model.layouted(source);
4358
- }
4359
- return LikeC4Model.computed(source);
4360
- }
4361
- static computed(source) {
4362
- const instance = new LikeC4Model(
4363
- "computed",
4364
- source,
4365
- r$1(source.elements),
4366
- r$1(source.relations)
4367
- );
4368
- for (const view of r$1(source.views)) {
4369
- instance._views.set(view.id, new LikeC4ViewModel(view, instance));
4370
- }
4371
- return instance;
4372
- }
4373
- static layouted(source) {
4374
- const instance = new LikeC4Model(
4375
- "layouted",
4376
- source,
4377
- r$1(source.elements),
4378
- r$1(source.relations)
4379
- );
4380
- for (const view of r$1(source.views)) {
4381
- instance._views.set(view.id, new LikeC4DiagramModel(view, instance));
4382
- }
4383
- return instance;
4384
- }
4864
+ _views;
4385
4865
  /**
4386
4866
  * Returns the root elements of the model.
4387
4867
  */
@@ -4454,7 +4934,7 @@ class LikeC4Model {
4454
4934
  * (from closest to root)
4455
4935
  */
4456
4936
  ancestors(element) {
4457
- let id = t(element) ? element : element.id;
4937
+ let id = t$1(element) ? element : element.id;
4458
4938
  const result = [];
4459
4939
  let parent;
4460
4940
  while (parent = this._parents.get(id)) {
@@ -4492,7 +4972,7 @@ class LikeC4Model {
4492
4972
  * Source elements of incoming relationships
4493
4973
  */
4494
4974
  incomers(element, filter = "all") {
4495
- return this.incoming(element, filter).map((r) => r.source);
4975
+ return [...new Set(this.incoming(element, filter).map((r) => r.source))];
4496
4976
  }
4497
4977
  /**
4498
4978
  * Outgoing relationships from the element and its descendants
@@ -4515,7 +4995,7 @@ class LikeC4Model {
4515
4995
  * Target elements of outgoing relationships
4516
4996
  */
4517
4997
  outgoers(element, filter = "all") {
4518
- return this.outgoing(element, filter).map((r) => r.target);
4998
+ return [...new Set(this.outgoing(element, filter).map((r) => r.target))];
4519
4999
  }
4520
5000
  /**
4521
5001
  * Relationships inside the element, among descendants
@@ -4622,6 +5102,35 @@ class LikeC4Model {
4622
5102
  }
4623
5103
  }
4624
5104
  ((LikeC4Model2) => {
5105
+ function create(source) {
5106
+ if (source.__ === "layouted") {
5107
+ return LikeC4Model2.layouted(source);
5108
+ }
5109
+ return LikeC4Model2.computed(source);
5110
+ }
5111
+ LikeC4Model2.create = create;
5112
+ function computed(source) {
5113
+ return new LikeC4Model2(
5114
+ "computed",
5115
+ source,
5116
+ r$1(source.elements),
5117
+ r$1(source.relations),
5118
+ source.views,
5119
+ LikeC4ViewModel
5120
+ );
5121
+ }
5122
+ LikeC4Model2.computed = computed;
5123
+ function layouted(source) {
5124
+ return new LikeC4Model2(
5125
+ "layouted",
5126
+ source,
5127
+ r$1(source.elements),
5128
+ r$1(source.relations),
5129
+ source.views,
5130
+ LikeC4DiagramModel
5131
+ );
5132
+ }
5133
+ LikeC4Model2.layouted = layouted;
4625
5134
  function isModel(model) {
4626
5135
  return model instanceof LikeC4Model2;
4627
5136
  }
@@ -4663,7 +5172,7 @@ class LikeC4Model {
4663
5172
  return this.relationship.metadata?.[key] ?? defaultValue;
4664
5173
  }
4665
5174
  hasMetadata(key) {
4666
- return n(this.relationship.metadata?.[key]);
5175
+ return n$1(this.relationship.metadata?.[key]);
4667
5176
  }
4668
5177
  }
4669
5178
  LikeC4Model2.Relationship = Relationship;
@@ -4703,7 +5212,7 @@ class LikeC4Model {
4703
5212
  return this.element.metadata?.[key] ?? defaultValue;
4704
5213
  }
4705
5214
  hasMetadata(key) {
4706
- return n(this.element.metadata?.[key]);
5215
+ return n$1(this.element.metadata?.[key]);
4707
5216
  }
4708
5217
  ancestors() {
4709
5218
  return this.model.ancestors(this);
@@ -4717,6 +5226,12 @@ class LikeC4Model {
4717
5226
  children() {
4718
5227
  return this.model.children(this);
4719
5228
  }
5229
+ /**
5230
+ * All views 'view of' current element
5231
+ */
5232
+ viewsOf() {
5233
+ return this.model.views().filter((v) => v.viewOf?.id === this.id);
5234
+ }
4720
5235
  /**
4721
5236
  * Views that contain this element
4722
5237
  */
@@ -4738,6 +5253,13 @@ class LikeC4Model {
4738
5253
  internal() {
4739
5254
  return this.model.internal(this);
4740
5255
  }
5256
+ /**
5257
+ * Resolve siblings of the element and siblings of ancestors
5258
+ * (from closest to root)
5259
+ */
5260
+ ascendingSiblings() {
5261
+ return this.model.ascendingSiblings(this);
5262
+ }
4741
5263
  // public *descendants(): IterableIterator<LikeC4Element> {
4742
5264
  // return
4743
5265
  // }
@@ -4749,7 +5271,7 @@ const DELAY = "LIKEC4_DELAY";
4749
5271
  function delay(...args) {
4750
5272
  let ms = 100;
4751
5273
  if (args.length === 2) {
4752
- ms = o(args[0], args[1]);
5274
+ ms = o$2(args[0], args[1]);
4753
5275
  } else if (args.length === 1) {
4754
5276
  ms = args[0];
4755
5277
  }
@@ -4780,4 +5302,4 @@ const compareRelations = (a, b) => {
4780
5302
  return compareFqnHierarchically(a.target, b.target);
4781
5303
  };
4782
5304
 
4783
- export { DefaultElementShape, DefaultRelationshipColor, DefaultThemeColor, ElementColors, LikeC4DiagramModel, LikeC4Model, LikeC4ViewModel, RelationshipColors, ancestorsFqn, commonAncestor, compareByFqnHierarchically, compareFqnHierarchically, compareNatural, compareRelations, computeColorValues, defaultTheme, delay, i as hasAtLeast, isAncestor, isDescendantOf, isNonEmptyArray, isSameHierarchy, isString, nameFromFqn, nonNullable, notDescendantOf, parentFqn, parentFqnPredicate, sortByFqnHierarchically, sortNaturalByFqn };
5305
+ export { Builder, DefaultElementShape, DefaultRelationshipColor, DefaultThemeColor, ElementColors, LikeC4DiagramModel, LikeC4Model, LikeC4ViewModel, RelationshipColors, ancestorsFqn, commonAncestor, compareByFqnHierarchically, compareFqnHierarchically, compareNatural, compareRelations, computeColorValues, defaultTheme, delay, i$2 as hasAtLeast, invariant, isAncestor, isDescendantOf, isElementPredicateExpr, isNonEmptyArray, isSameHierarchy, isScopedElementView, isString, nameFromFqn, nonNullable, notDescendantOf, parentFqn, parentFqnPredicate, sortByFqnHierarchically, sortNaturalByFqn };