@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.
Files changed (112) hide show
  1. package/dist/compute-view/index.d.mts +91 -0
  2. package/dist/compute-view/index.d.ts +91 -0
  3. package/dist/compute-view/index.mjs +79 -0
  4. package/dist/index.d.mts +246 -434
  5. package/dist/index.d.ts +246 -434
  6. package/dist/index.mjs +418 -1322
  7. package/dist/model/index.d.mts +642 -0
  8. package/dist/model/index.d.ts +642 -0
  9. package/dist/model/index.mjs +2 -0
  10. package/dist/shared/core.BBgiAAv1.mjs +144 -0
  11. package/dist/shared/core.BPyJvuMU.mjs +2420 -0
  12. package/dist/shared/core.BQ4AbfvB.mjs +9228 -0
  13. package/dist/shared/{core.CoLQkcYL.d.mts → core.DMYY7C8s.d.mts} +398 -249
  14. package/dist/shared/{core.CoLQkcYL.d.ts → core.DMYY7C8s.d.ts} +398 -249
  15. package/dist/shared/core.k12s_keD.mjs +203 -0
  16. package/dist/types/index.d.mts +69 -1
  17. package/dist/types/index.d.ts +69 -1
  18. package/dist/types/index.mjs +21 -1
  19. package/package.json +38 -40
  20. package/src/builder/Builder.deployment.ts +219 -0
  21. package/src/builder/Builder.deploymentModel.ts +360 -0
  22. package/src/builder/Builder.element.ts +17 -19
  23. package/src/builder/Builder.model.ts +13 -2
  24. package/src/builder/Builder.test-d.ts +59 -4
  25. package/src/builder/Builder.ts +238 -53
  26. package/src/builder/Builder.view.ts +238 -53
  27. package/src/builder/_types.ts +87 -15
  28. package/src/compute-view/LikeC4ModelGraph.ts +330 -0
  29. package/src/compute-view/compute-view.ts +92 -0
  30. package/src/compute-view/deployment-view/Memory.ts +108 -0
  31. package/src/compute-view/deployment-view/Stage.ts +145 -0
  32. package/src/compute-view/deployment-view/__test__/fixture.ts +210 -0
  33. package/src/compute-view/deployment-view/_types.ts +29 -0
  34. package/src/compute-view/deployment-view/clean-connections.ts +229 -0
  35. package/src/compute-view/deployment-view/compute.ts +111 -0
  36. package/src/compute-view/deployment-view/predicates/deployment-ref.ts +146 -0
  37. package/src/compute-view/deployment-view/predicates/relation-direct.ts +130 -0
  38. package/src/compute-view/deployment-view/predicates/relation-in-out.ts +43 -0
  39. package/src/compute-view/deployment-view/predicates/relation-incoming.ts +46 -0
  40. package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +49 -0
  41. package/src/compute-view/deployment-view/predicates/wildcard.ts +29 -0
  42. package/src/compute-view/deployment-view/utils.ts +212 -0
  43. package/src/compute-view/dynamic-view/__test__/fixture.ts +58 -0
  44. package/src/compute-view/dynamic-view/compute.ts +310 -0
  45. package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +456 -0
  46. package/src/compute-view/element-view/__test__/fixture.ts +645 -0
  47. package/src/compute-view/element-view/compute.ts +734 -0
  48. package/src/compute-view/element-view/predicates.ts +517 -0
  49. package/src/compute-view/index.ts +5 -0
  50. package/src/compute-view/utils/__snapshots__/sortNodes.spec.ts.snap +113 -0
  51. package/src/compute-view/utils/ancestorsOfNode.ts +19 -0
  52. package/src/compute-view/utils/applyCustomElementProperties.ts +66 -0
  53. package/src/compute-view/utils/applyCustomRelationProperties.ts +41 -0
  54. package/src/compute-view/utils/applyViewRuleStyles.ts +53 -0
  55. package/src/compute-view/utils/buildComputedNodes.ts +148 -0
  56. package/src/compute-view/utils/buildElementNotations.ts +63 -0
  57. package/src/compute-view/utils/derive-edge-props-from-relationships.ts +97 -0
  58. package/src/compute-view/utils/elementExpressionToPredicate.ts +52 -0
  59. package/src/compute-view/utils/link-nodes-with-edges.ts +58 -0
  60. package/src/compute-view/utils/relationExpressionToPredicates.ts +55 -0
  61. package/src/compute-view/utils/resolve-extended-views.ts +65 -0
  62. package/src/compute-view/utils/resolve-global-rules.ts +83 -0
  63. package/src/compute-view/utils/sortNodes.ts +101 -0
  64. package/src/compute-view/utils/topological-sort.ts +160 -0
  65. package/src/compute-view/utils/uniqueTags.test.ts +42 -0
  66. package/src/compute-view/utils/uniqueTags.ts +21 -0
  67. package/src/compute-view/utils/view-hash.ts +27 -0
  68. package/src/compute-view/utils/with-readable-edges.ts +31 -0
  69. package/src/index.ts +5 -1
  70. package/src/model/DeploymentElementModel.ts +534 -0
  71. package/src/model/DeploymentModel.ts +364 -0
  72. package/src/model/ElementModel.ts +195 -0
  73. package/src/model/LikeC4Model.test-d.ts +151 -0
  74. package/src/model/LikeC4Model.ts +280 -457
  75. package/src/model/RelationModel.ts +84 -0
  76. package/src/model/__test__/fixture.ts +153 -338
  77. package/src/model/connection/ConnectionModel.ts +94 -0
  78. package/src/model/connection/DeploymentConnectionModel.ts +99 -0
  79. package/src/model/connection/deployment.ts +124 -0
  80. package/src/model/connection/model.ts +123 -0
  81. package/src/model/index.ts +4 -2
  82. package/src/model/types.ts +95 -15
  83. package/src/model/view/EdgeModel.ts +103 -0
  84. package/src/model/view/LikeC4ViewModel.ts +220 -0
  85. package/src/model/view/NodeModel.ts +228 -0
  86. package/src/types/_common.ts +2 -0
  87. package/src/types/deployments.ts +237 -0
  88. package/src/types/element.ts +7 -3
  89. package/src/types/expression.ts +8 -6
  90. package/src/types/index.ts +1 -0
  91. package/src/types/model.ts +68 -9
  92. package/src/types/overview-graph.ts +2 -2
  93. package/src/types/relation.ts +4 -4
  94. package/src/types/view-notation.ts +2 -2
  95. package/src/types/view.ts +104 -30
  96. package/src/utils/{commonHead.ts → common-head.ts} +2 -0
  97. package/src/utils/fqn.ts +83 -27
  98. package/src/utils/getOrCreate.ts +42 -0
  99. package/src/utils/graphlib.ts +10 -0
  100. package/src/utils/index.ts +4 -1
  101. package/src/utils/object-hash.ts +3 -0
  102. package/src/utils/set.ts +76 -0
  103. package/src/utils/string-hash.ts +16 -0
  104. package/dist/index.cjs +0 -5452
  105. package/dist/index.d.cts +0 -1053
  106. package/dist/shared/core.BXTs-8n7.mjs +0 -293
  107. package/dist/shared/core.CoLQkcYL.d.cts +0 -734
  108. package/dist/shared/core.DIYZvpVg.cjs +0 -353
  109. package/dist/types/index.cjs +0 -70
  110. package/dist/types/index.d.cts +0 -2
  111. package/src/model/LikeC4DiagramModel.ts +0 -338
  112. package/src/model/LikeC4ViewModel.ts +0 -320
package/src/utils/fqn.ts CHANGED
@@ -1,11 +1,23 @@
1
- import type { LiteralUnion } from 'type-fest'
2
1
  import type { Element, Fqn } from '../types'
3
2
  import { compareNatural } from './compare-natural'
4
3
  import { isString } from './guards'
5
4
 
6
5
  type Predicate<T> = (x: T) => boolean
7
6
 
8
- export function nameFromFqn(fqn: LiteralUnion<Fqn, string>) {
7
+ export function parentFqn<E extends string>(fqn: E): E | null {
8
+ const lastDot = fqn.lastIndexOf('.')
9
+ if (lastDot > 0) {
10
+ return fqn.slice(0, lastDot) as E
11
+ }
12
+ return null
13
+ }
14
+
15
+ export function parentFqnPredicate<T extends { parent: Fqn | null }>(parent: Fqn): Predicate<T> {
16
+ const prefix = parent + '.'
17
+ return (e: T) => !!e.parent && (e.parent === parent || e.parent.startsWith(prefix))
18
+ }
19
+
20
+ export function nameFromFqn<E extends string>(fqn: E) {
9
21
  const lastDot = fqn.lastIndexOf('.')
10
22
  if (lastDot > 0) {
11
23
  return fqn.slice(lastDot + 1)
@@ -14,7 +26,7 @@ export function nameFromFqn(fqn: LiteralUnion<Fqn, string>) {
14
26
  }
15
27
  }
16
28
 
17
- export function isAncestor<E extends { id: Fqn }>(
29
+ export function isAncestor<E extends { id: string }>(
18
30
  ...args: [ancestor: string, another: string] | [ancestor: E, another: E]
19
31
  ) {
20
32
  const ancestor = isString(args[0]) ? args[0] : args[0].id
@@ -22,7 +34,7 @@ export function isAncestor<E extends { id: Fqn }>(
22
34
  return another.startsWith(ancestor + '.')
23
35
  }
24
36
 
25
- export function isSameHierarchy<E extends { id: Fqn }>(one: E | Fqn, another: E | Fqn) {
37
+ export function isSameHierarchy<E extends string | { id: Fqn }>(one: E, another: E) {
26
38
  const first = isString(one) ? one : one.id
27
39
  const second = isString(another) ? another : another.id
28
40
  return first === second || second.startsWith(first + '.') || first.startsWith(second + '.')
@@ -38,7 +50,44 @@ export function notDescendantOf(ancestors: Element[]): (e: Element) => boolean {
38
50
  return (e: Element) => !isDescendant(e)
39
51
  }
40
52
 
41
- export function commonAncestor<IDs extends string>(first: Fqn<IDs>, second: Fqn<IDs>) {
53
+ /**
54
+ * How deep in the hierarchy the element is.
55
+ * Root element has depth 1
56
+ */
57
+ export function hierarchyDepth<E extends string | { id: Fqn }>(elementOfFqn: E): number {
58
+ const first = isString(elementOfFqn) ? elementOfFqn : elementOfFqn.id
59
+ return first.split('.').length
60
+ }
61
+
62
+ /**
63
+ * Calculate the distance as number of steps from one element to another, i.e.
64
+ * going up to the common ancestor, then going down to the other element.
65
+ * Sibling distance is always 1
66
+ *
67
+ * Can be used for hierarchical clustering
68
+ */
69
+ export function hierarchyDistance<E extends string | { id: Fqn }>(one: E, another: E) {
70
+ const first = isString(one) ? one as Fqn : one.id
71
+ const second = isString(another) ? another as Fqn : another.id
72
+
73
+ if (first === second) {
74
+ return 0
75
+ }
76
+
77
+ const firstDepth = hierarchyDepth(first)
78
+ const secondDepth = hierarchyDepth(second)
79
+
80
+ if (isSameHierarchy(first, second)) {
81
+ return Math.abs(firstDepth - secondDepth)
82
+ }
83
+
84
+ const ancestor = commonAncestor(first as Fqn, second as Fqn)
85
+ const ancestorDepth = ancestor ? hierarchyDepth(ancestor) : 0
86
+
87
+ return firstDepth + secondDepth - (2 * ancestorDepth + 1)
88
+ }
89
+
90
+ export function commonAncestor<E extends string>(first: E, second: E) {
42
91
  const parentA = parentFqn(first)
43
92
  const parentB = parentFqn(second)
44
93
  if (parentA === parentB) {
@@ -50,35 +99,22 @@ export function commonAncestor<IDs extends string>(first: Fqn<IDs>, second: Fqn<
50
99
 
51
100
  const a = first.split('.')
52
101
  const b = second.split('.')
53
- let ancestor: Fqn<IDs> | null = null
102
+ let ancestor: E | null = null
54
103
 
55
104
  while (a.length > 1 && b.length > 1 && !!a[0] && a[0] === b[0]) {
56
- ancestor = (ancestor ? `${ancestor}.${a[0]}` : a[0]) as Fqn<IDs>
105
+ ancestor = (ancestor ? `${ancestor}.${a[0]}` : a[0]) as E
57
106
  a.shift()
58
107
  b.shift()
59
108
  }
60
109
  return ancestor
61
110
  }
62
111
 
63
- export function parentFqn<IDs extends string>(fqn: Fqn<IDs>): Fqn<IDs> | null {
64
- const lastDot = fqn.lastIndexOf('.')
65
- if (lastDot > 0) {
66
- return fqn.slice(0, lastDot) as Fqn<IDs>
67
- }
68
- return null
69
- }
70
-
71
- export function parentFqnPredicate<T extends { parent: Fqn | null }>(parent: Fqn): Predicate<T> {
72
- const prefix = parent + '.'
73
- return (e: T) => !!e.parent && (e.parent === parent || e.parent.startsWith(prefix))
74
- }
75
-
76
112
  /**
77
113
  * Get all ancestor elements (i.e. parent, parent’s parent, etc.)
78
- * (from closest to root)
114
+ * going up from parent to the root
79
115
  */
80
- export function ancestorsFqn<IDs extends string>(fqn: Fqn<IDs>): Fqn<IDs>[] {
81
- const path = fqn.split('.') as Fqn<IDs>[]
116
+ export function ancestorsFqn<Id extends string>(fqn: Id): Id[] {
117
+ const path = fqn.split('.') as Id[]
82
118
  path.pop()
83
119
  if (path.length === 0) {
84
120
  return []
@@ -88,9 +124,9 @@ export function ancestorsFqn<IDs extends string>(fqn: Fqn<IDs>): Fqn<IDs>[] {
88
124
  acc.push(part)
89
125
  return acc
90
126
  }
91
- acc.unshift(`${acc[0]}.${part}` as Fqn<IDs>)
127
+ acc.unshift(`${acc[0]}.${part}` as Id)
92
128
  return acc
93
- }, [] as Fqn<IDs>[])
129
+ }, [] as Id[])
94
130
  }
95
131
 
96
132
  /**
@@ -123,8 +159,8 @@ export function compareByFqnHierarchically<T extends { id: string }>(a: T, b: T)
123
159
  return compareFqnHierarchically(a.id, b.id)
124
160
  }
125
161
 
126
- type IterableContainer<T = unknown> = ReadonlyArray<T> | readonly []
127
- type ReorderedArray<T extends IterableContainer> = {
162
+ export type IterableContainer<T = unknown> = ReadonlyArray<T> | readonly []
163
+ export type ReorderedArray<T extends IterableContainer> = {
128
164
  -readonly [P in keyof T]: T[number]
129
165
  }
130
166
 
@@ -139,6 +175,26 @@ export function sortByFqnHierarchically<T extends { id: string }, A extends Iter
139
175
  .map(({ item }) => item) as ReorderedArray<A>
140
176
  }
141
177
 
178
+ /**
179
+ * Keeps initial order of the elements, but ensures that parents are before children
180
+ */
181
+ export function sortParentsFirst<T extends { id: string }, A extends IterableContainer<T>>(
182
+ array: A
183
+ ): ReorderedArray<A> {
184
+ const result = [] as T[]
185
+ const items = [...array]
186
+ let item
187
+ while ((item = items.shift())) {
188
+ const itemId = item.id
189
+ let parentIndx
190
+ while ((parentIndx = items.findIndex(parent => isAncestor(parent.id, itemId))) !== -1) {
191
+ result.push(...items.splice(parentIndx, 1))
192
+ }
193
+ result.push(item)
194
+ }
195
+ return result as ReorderedArray<A>
196
+ }
197
+
142
198
  export function sortNaturalByFqn<T extends { id: string }, A extends IterableContainer<T>>(
143
199
  array: A
144
200
  ): ReorderedArray<A> {
@@ -0,0 +1,42 @@
1
+ // export function getOrCreate<K, V>(map: Map<K, V>): Map<K, V> & {
2
+ // get(key: K, create: (key: K) => V): V
3
+ // get(key: K): V | undefined
4
+ // }
5
+ // export function getOrCreate<K, V>(map: Map<K, V>, key: K, create: (key: K) => V): V
6
+ // export function getOrCreate<K, V>(map: Map<K, V>, key?: K, create?: (key: K) => V) {
7
+ export function getOrCreate<K, V>(map: Map<K, V>, key: K, create: (key: K) => V) {
8
+ let entry = map.get(key)
9
+ if (!entry) {
10
+ entry = create(key)
11
+ map.set(key, entry)
12
+ }
13
+ return entry
14
+ }
15
+
16
+ // export class BetterMap<K, V> extends Map<K, V> {
17
+ // constructor(iterable?: Iterable<readonly [K, V]> | null) {
18
+ // super(iterable)
19
+ // }
20
+
21
+ // /**
22
+ // * Returns the element associated with the specified key.
23
+ // * If no element is associated with the specified key, and a create function is provided, a new element will be created and stored.
24
+ // * @example
25
+ // * ```ts
26
+ // * const map = new BetterMap<Fqn, Element>()
27
+ // *
28
+ // * map.get(fqn, () => factory.createElement(fqn))
29
+ // *
30
+ // */
31
+ // override get(key: K, create: (key: K) => V): V
32
+ // override get(key: K): V | undefined
33
+ // override get(key: K, create?: (key: K) => V) {
34
+ // const entry = super.get(key)
35
+ // if (!entry && create) {
36
+ // const newEntry = create(key)
37
+ // this.set(key, newEntry)
38
+ // return newEntry
39
+ // }
40
+ // return entry
41
+ // }
42
+ // }
@@ -0,0 +1,10 @@
1
+ import dagre from '@dagrejs/dagre'
2
+
3
+ const Graph = dagre.graphlib.Graph
4
+
5
+ export { Graph }
6
+
7
+ export const postorder = dagre.graphlib.alg.postorder
8
+ export const preorder = dagre.graphlib.alg.preorder
9
+ export const findCycles = dagre.graphlib.alg.findCycles
10
+ export const isAcyclic = dagre.graphlib.alg.isAcyclic
@@ -1,6 +1,9 @@
1
- export * from './commonHead'
1
+ export * from './common-head'
2
2
  export * from './compare-natural'
3
3
  export * from './fqn'
4
+ export * from './getOrCreate'
4
5
  export * from './guards'
5
6
  export * from './promises'
6
7
  export * from './relations'
8
+ export * from './set'
9
+ export * from './string-hash'
@@ -0,0 +1,3 @@
1
+ import objectHash from 'object-hash'
2
+
3
+ export { objectHash }
@@ -0,0 +1,76 @@
1
+ import {
2
+ intersection as _intersection,
3
+ symmetricDifference as _symmetricDifference,
4
+ union as _union
5
+ } from 'mnemonist/set'
6
+ import type { NonEmptyArray } from '../types/_common'
7
+
8
+ /**
9
+ * Returns new set as a union of given sets
10
+ * Keeps order of elements
11
+ */
12
+ export function union<T>(...sets: NonEmptyArray<ReadonlySet<T>>): Set<T> {
13
+ return _union(...sets as any)
14
+ }
15
+
16
+ /**
17
+ * Returns new set as an intersection of all sets
18
+ * Keeps order from the first set
19
+ */
20
+ export function intersection<T>(first: ReadonlySet<T>, ...sets: NonEmptyArray<ReadonlySet<T>>): Set<T> {
21
+ let result = new Set<T>()
22
+ // If first set is empty, return empty set
23
+ if (first.size === 0) {
24
+ return result
25
+ }
26
+ let other = sets.length > 1 ? _intersection(...sets as any) : sets[0]
27
+ if (other.size === 0) {
28
+ return result
29
+ }
30
+ for (const value of first) {
31
+ if (other.has(value)) {
32
+ result.add(value)
33
+ }
34
+ }
35
+ return result
36
+ }
37
+
38
+ export function difference<T>(a: ReadonlySet<T>, b: ReadonlySet<T>): Set<T> {
39
+ if (a.size === 0) {
40
+ return new Set<T>()
41
+ }
42
+ if (b.size === 0) {
43
+ return new Set(a)
44
+ }
45
+ let result = new Set<T>()
46
+ for (const value of a) {
47
+ if (!b.has(value)) {
48
+ result.add(value)
49
+ }
50
+ }
51
+ return result
52
+ }
53
+
54
+ export function equals<T>(a: ReadonlySet<T>, b: ReadonlySet<T>): boolean {
55
+ return a.size === b.size && [...a].every(value => b.has(value))
56
+ }
57
+
58
+ export function symmetricDifference<T>(a: ReadonlySet<T>, b: ReadonlySet<T>): Set<T> {
59
+ return _symmetricDifference(a as Set<T>, b as Set<T>)
60
+ }
61
+
62
+ export function hasIntersection<T>(a: ReadonlySet<T>, b: ReadonlySet<T>): boolean {
63
+ if (a.size === 0 || b.size === 0) {
64
+ return false
65
+ }
66
+ // Swap sets to iterate over smaller set
67
+ if (b.size < a.size) {
68
+ ;[a, b] = [b, a]
69
+ }
70
+ for (const value of a) {
71
+ if (b.has(value)) {
72
+ return true
73
+ }
74
+ }
75
+ return false
76
+ }
@@ -0,0 +1,16 @@
1
+ import { invariant } from '../errors'
2
+
3
+ /**
4
+ * @see https://gist.github.com/victor-homyakov/bcb7d7911e4a388b1c810f8c3ce17bcf
5
+ */
6
+ export function stringHash(str: string) {
7
+ let hash = 5381
8
+ const len = str.length
9
+ invariant(len > 0, 'stringHash: empty string')
10
+
11
+ for (let i = 0; i < len; i++) {
12
+ hash = (hash * 33) ^ str.charCodeAt(i)
13
+ }
14
+
15
+ return (hash >>> 0).toString(36)
16
+ }