@likec4/core 1.17.1 → 1.19.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 (184) hide show
  1. package/LICENSE +1 -1
  2. package/dist/builder/index.d.mts +502 -0
  3. package/dist/builder/index.d.ts +502 -0
  4. package/dist/builder/index.js +871 -0
  5. package/dist/compute-view/index.d.mts +22 -0
  6. package/dist/compute-view/index.d.ts +22 -0
  7. package/dist/compute-view/index.js +78 -0
  8. package/dist/index.d.mts +10 -919
  9. package/dist/index.d.ts +10 -919
  10. package/dist/{index.mjs → index.js} +7 -1688
  11. package/dist/model/index.d.mts +254 -0
  12. package/dist/model/index.d.ts +254 -0
  13. package/dist/model/index.js +1 -0
  14. package/dist/shared/chunk-RAAYCPUM.M-JWF7SS.js +21 -0
  15. package/dist/shared/core.BIfgabEw.d.ts +719 -0
  16. package/dist/shared/core.BZ9Msq7w.d.mts +719 -0
  17. package/dist/shared/{core.CoLQkcYL.d.cts → core.C05RDLhi.d.ts} +460 -362
  18. package/dist/shared/{core.CoLQkcYL.d.mts → core.CmYMqgha.d.mts} +460 -362
  19. package/dist/shared/core.D6-fWbM3.d.ts +127 -0
  20. package/dist/shared/core.D74xkKkG.d.mts +148 -0
  21. package/dist/shared/core.D74xkKkG.d.ts +148 -0
  22. package/dist/shared/core.sLaWHBjR.d.mts +127 -0
  23. package/dist/shared/index.-BdzdI2C.js +7443 -0
  24. package/dist/shared/object_hash.CE_oF3I3.js +1222 -0
  25. package/dist/shared/{core.BXTs-8n7.mjs → view.CyZrG8BJ.js} +108 -47
  26. package/dist/types/index.d.mts +71 -1
  27. package/dist/types/index.d.ts +71 -1
  28. package/dist/types/index.js +20 -0
  29. package/dist/utils/index.d.mts +404 -0
  30. package/dist/utils/index.d.ts +404 -0
  31. package/dist/utils/index.js +330 -0
  32. package/package.json +59 -47
  33. package/src/builder/Builder-style1.test-d.ts +190 -0
  34. package/src/builder/Builder-style2.test-d.ts +175 -0
  35. package/src/builder/Builder.deployment.ts +224 -0
  36. package/src/builder/Builder.deploymentModel.ts +385 -0
  37. package/src/builder/Builder.element.ts +19 -19
  38. package/src/builder/Builder.model.ts +67 -42
  39. package/src/builder/Builder.ts +533 -367
  40. package/src/builder/Builder.view-common.ts +234 -0
  41. package/src/builder/Builder.view-deployment.ts +135 -0
  42. package/src/builder/Builder.view-element.ts +189 -0
  43. package/src/builder/Builder.views.ts +109 -33
  44. package/src/builder/Builder.with.ts +475 -0
  45. package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +374 -0
  46. package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +183 -0
  47. package/src/builder/__snapshots__/Builder.spec.ts.snap +374 -0
  48. package/src/builder/_types.ts +113 -18
  49. package/src/builder/index.ts +10 -4
  50. package/src/colors/index.ts +2 -2
  51. package/src/compute-view/compute-view.ts +83 -0
  52. package/src/compute-view/deployment-view/__test__/TestHelper.ts +236 -0
  53. package/src/compute-view/deployment-view/__test__/fixture.ts +198 -0
  54. package/src/compute-view/deployment-view/_types.ts +37 -0
  55. package/src/compute-view/deployment-view/clean-connections.ts +238 -0
  56. package/src/compute-view/deployment-view/compute.ts +125 -0
  57. package/src/compute-view/deployment-view/memory/index.ts +9 -0
  58. package/src/compute-view/deployment-view/memory/memory.ts +97 -0
  59. package/src/compute-view/deployment-view/predicates/elements.ts +144 -0
  60. package/src/compute-view/deployment-view/predicates/relation-direct.ts +237 -0
  61. package/src/compute-view/deployment-view/predicates/relation-in-out.ts +61 -0
  62. package/src/compute-view/deployment-view/predicates/relation-incoming.ts +95 -0
  63. package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +88 -0
  64. package/src/compute-view/deployment-view/predicates/wildcard.ts +29 -0
  65. package/src/compute-view/deployment-view/stages/stage-exclude.ts +5 -0
  66. package/src/compute-view/deployment-view/stages/stage-final.ts +245 -0
  67. package/src/compute-view/deployment-view/stages/stage-include.ts +95 -0
  68. package/src/compute-view/deployment-view/utils.ts +276 -0
  69. package/src/compute-view/dynamic-view/__test__/fixture.ts +58 -0
  70. package/src/compute-view/dynamic-view/compute.ts +324 -0
  71. package/src/compute-view/element-view/__test__/TestHelper.ts +258 -0
  72. package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +458 -0
  73. package/src/compute-view/element-view/__test__/fixture.ts +675 -0
  74. package/src/compute-view/element-view/_types.ts +48 -0
  75. package/src/compute-view/element-view/clean-connections.ts +113 -0
  76. package/src/compute-view/element-view/compute.ts +315 -0
  77. package/src/compute-view/element-view/memory/NodeGroup.ts +31 -0
  78. package/src/compute-view/element-view/memory/index.ts +10 -0
  79. package/src/compute-view/element-view/memory/memory.ts +177 -0
  80. package/src/compute-view/element-view/memory/stage-exclude.ts +59 -0
  81. package/src/compute-view/element-view/memory/stage-final.ts +129 -0
  82. package/src/compute-view/element-view/memory/stage-include.ts +128 -0
  83. package/src/compute-view/element-view/predicates/_utils.ts +86 -0
  84. package/src/compute-view/element-view/predicates/element-expand.ts +33 -0
  85. package/src/compute-view/element-view/predicates/element-kind-tag.ts +26 -0
  86. package/src/compute-view/element-view/predicates/element-ref.ts +37 -0
  87. package/src/compute-view/element-view/predicates/relation-direct.ts +309 -0
  88. package/src/compute-view/element-view/predicates/relation-in-out.ts +66 -0
  89. package/src/compute-view/element-view/predicates/relation-in.ts +118 -0
  90. package/src/compute-view/element-view/predicates/relation-out.ts +116 -0
  91. package/src/compute-view/element-view/predicates/wildcard.ts +88 -0
  92. package/src/compute-view/element-view/utils.ts +59 -0
  93. package/src/compute-view/index.ts +4 -0
  94. package/src/compute-view/memory/AbstractMemory.ts +45 -0
  95. package/src/compute-view/memory/AbstractStageExclude.ts +216 -0
  96. package/src/compute-view/memory/AbstractStageInclude.ts +200 -0
  97. package/src/compute-view/memory/_types.ts +147 -0
  98. package/src/compute-view/memory/index.ts +5 -0
  99. package/src/compute-view/memory/ops.ts +43 -0
  100. package/src/compute-view/utils/__snapshots__/sortNodes.spec.ts.snap +113 -0
  101. package/src/compute-view/utils/ancestorsOfNode.ts +19 -0
  102. package/src/compute-view/utils/applyCustomElementProperties.ts +66 -0
  103. package/src/compute-view/utils/applyCustomRelationProperties.ts +41 -0
  104. package/src/compute-view/utils/applyViewRuleStyles.ts +53 -0
  105. package/src/compute-view/utils/buildComputedNodes.ts +148 -0
  106. package/src/compute-view/utils/buildElementNotations.ts +63 -0
  107. package/src/compute-view/utils/elementExpressionToPredicate.ts +50 -0
  108. package/src/compute-view/utils/link-nodes-with-edges.ts +54 -0
  109. package/src/compute-view/utils/merge-props-from-relationships.ts +128 -0
  110. package/src/compute-view/utils/relationExpressionToPredicates.ts +55 -0
  111. package/src/compute-view/utils/resolve-extended-views.ts +69 -0
  112. package/src/compute-view/utils/resolve-global-rules.ts +83 -0
  113. package/src/compute-view/utils/topological-sort.ts +256 -0
  114. package/src/compute-view/utils/uniqueTags.test.ts +42 -0
  115. package/src/compute-view/utils/uniqueTags.ts +21 -0
  116. package/src/compute-view/utils/view-hash.ts +27 -0
  117. package/src/compute-view/utils/with-readable-edges.ts +36 -0
  118. package/src/index.ts +22 -12
  119. package/src/model/DeploymentElementModel.ts +599 -0
  120. package/src/model/DeploymentModel.ts +370 -0
  121. package/src/model/ElementModel.ts +221 -0
  122. package/src/model/LikeC4Model.test-d.ts +152 -0
  123. package/src/model/LikeC4Model.ts +336 -457
  124. package/src/model/RelationModel.ts +85 -0
  125. package/src/model/__test__/fixture.ts +149 -338
  126. package/src/model/connection/Connection.ts +72 -0
  127. package/src/model/connection/deployment/DeploymentConnectionModel.ts +178 -0
  128. package/src/model/connection/deployment/find.ts +120 -0
  129. package/src/model/connection/deployment/index.ts +8 -0
  130. package/src/model/connection/index.ts +22 -0
  131. package/src/model/connection/model/ConnectionModel.ts +157 -0
  132. package/src/model/connection/model/find.ts +117 -0
  133. package/src/model/connection/model/index.ts +8 -0
  134. package/src/model/connection/ops.ts +274 -0
  135. package/src/model/guards.ts +9 -0
  136. package/src/model/index.ts +46 -2
  137. package/src/model/types.ts +112 -15
  138. package/src/model/view/EdgeModel.ts +103 -0
  139. package/src/model/view/LikeC4ViewModel.ts +226 -0
  140. package/src/model/view/NodeModel.ts +229 -0
  141. package/src/types/_common.ts +55 -1
  142. package/src/types/deployments.ts +169 -0
  143. package/src/types/element.ts +9 -5
  144. package/src/types/expression-v2.ts +172 -0
  145. package/src/types/expression.ts +17 -11
  146. package/src/types/global.ts +3 -3
  147. package/src/types/index.ts +220 -12
  148. package/src/types/model.ts +75 -12
  149. package/src/types/operators.ts +1 -1
  150. package/src/types/overview-graph.ts +2 -2
  151. package/src/types/relation.ts +18 -14
  152. package/src/types/theme.ts +0 -1
  153. package/src/types/view-notation.ts +2 -2
  154. package/src/types/view.ts +117 -41
  155. package/src/utils/{commonHead.ts → common-head.ts} +2 -0
  156. package/src/utils/const.ts +1 -0
  157. package/src/utils/fqn.ts +203 -56
  158. package/src/utils/getOrCreate.ts +42 -0
  159. package/src/utils/graphlib.ts +10 -0
  160. package/src/utils/index.ts +74 -6
  161. package/src/utils/iterable/_types.ts +5 -0
  162. package/src/utils/iterable/filter.ts +55 -0
  163. package/src/utils/iterable/flat.ts +17 -0
  164. package/src/utils/iterable/index.ts +12 -0
  165. package/src/utils/iterable/map.ts +40 -0
  166. package/src/utils/iterable/reduce.ts +24 -0
  167. package/src/utils/iterable/some.ts +36 -0
  168. package/src/utils/iterable/to.ts +19 -0
  169. package/src/utils/iterable/unique.ts +29 -0
  170. package/src/utils/object-hash.ts +3 -0
  171. package/src/utils/relations.ts +3 -64
  172. package/src/utils/set.ts +78 -0
  173. package/src/utils/string-hash.ts +16 -0
  174. package/dist/index.cjs +0 -5452
  175. package/dist/index.d.cts +0 -1053
  176. package/dist/shared/core.CoLQkcYL.d.ts +0 -734
  177. package/dist/shared/core.DIYZvpVg.cjs +0 -353
  178. package/dist/types/index.cjs +0 -70
  179. package/dist/types/index.d.cts +0 -2
  180. package/dist/types/index.mjs +0 -1
  181. package/src/builder/Builder.test-d.ts +0 -69
  182. package/src/builder/Builder.view.ts +0 -358
  183. package/src/model/LikeC4DiagramModel.ts +0 -338
  184. package/src/model/LikeC4ViewModel.ts +0 -320
@@ -0,0 +1,274 @@
1
+ import { map, pipe, prop } from 'remeda'
2
+ import { isString } from '../../utils'
3
+ import {
4
+ type IterableContainer,
5
+ type ReorderedArray,
6
+ isAncestor,
7
+ isDescendantOf,
8
+ sortNaturalByFqn,
9
+ } from '../../utils/fqn'
10
+ import type { Connection } from './Connection'
11
+
12
+ /**
13
+ * Check if connection is nested inside another connection
14
+ * (i.e. between descendants)
15
+ */
16
+ export function isNestedConnection<T extends { id: string }>(
17
+ parent: WithSourceTarget<NoInfer<T>>,
18
+ ): (nested: WithSourceTarget<T>) => boolean
19
+ export function isNestedConnection<T extends { id: string }>(
20
+ nested: WithSourceTarget<T>,
21
+ parent: WithSourceTarget<T>,
22
+ ): boolean
23
+ export function isNestedConnection<T extends { id: string }>(
24
+ nested: WithSourceTarget<T>,
25
+ parent?: WithSourceTarget<T>,
26
+ ) {
27
+ if (!parent) {
28
+ const p = nested
29
+ return (n: WithSourceTarget<T>) => isNestedConnection(n, p)
30
+ }
31
+ const isSameSource = nested.source === parent.source
32
+ const isSameTarget = nested.target === parent.target
33
+ if (isSameSource && isSameTarget) {
34
+ return false
35
+ }
36
+ const isSourceNested = isAncestor(parent.source.id, nested.source.id)
37
+ const isTargetNested = isAncestor(parent.target.id, nested.target.id)
38
+ return (
39
+ (isSourceNested && isTargetNested)
40
+ || (isSameSource && isTargetNested)
41
+ || (isSameTarget && isSourceNested)
42
+ )
43
+ }
44
+
45
+ type ConnectionElemId = Connection<{ readonly id: string }, any>
46
+
47
+ export function findDeepestNestedConnection<C extends ConnectionElemId>(
48
+ connections: ReadonlyArray<C>,
49
+ connection: C,
50
+ ): C | null {
51
+ let deepest = connection
52
+ for (const c of connections) {
53
+ if (isNestedConnection(c, deepest)) {
54
+ deepest = c
55
+ }
56
+ }
57
+ return deepest !== connection ? deepest : null
58
+ }
59
+
60
+ export function sortDeepestFirst<C extends ConnectionElemId>(
61
+ connections: ReadonlyArray<C>,
62
+ ): C[] {
63
+ const sorted = [] as C[]
64
+ const unsorted = connections.slice()
65
+ let next
66
+ while (next = unsorted.shift()) {
67
+ let deepest
68
+ while (deepest = findDeepestNestedConnection(unsorted, next)) {
69
+ const index = unsorted.indexOf(deepest)
70
+ sorted.push(unsorted.splice(index, 1)[0]!)
71
+ }
72
+ sorted.push(next)
73
+ }
74
+ return sorted
75
+ }
76
+
77
+ /**
78
+ * To make {@link sortConnectionsByBoundaryHierarchy} work correctly we add '.' to boundary
79
+ * Othwerwise connection without boundary will be considered same level as connection with top-level boundary
80
+ */
81
+ export const boundaryHierarchy = <C extends WithBoundary>(conn: C) => conn.boundary?.id ? `.${conn.boundary.id}` : ''
82
+
83
+ type WithBoundary = {
84
+ boundary: null | { id: string }
85
+ }
86
+ export function sortConnectionsByBoundaryHierarchy(
87
+ sort?: 'asc' | 'desc',
88
+ ): <T extends WithBoundary, A extends IterableContainer<T>>(array: A) => ReorderedArray<A>
89
+ export function sortConnectionsByBoundaryHierarchy<T extends WithBoundary, A extends IterableContainer<T>>(
90
+ array: A,
91
+ sort?: 'asc' | 'desc',
92
+ ): ReorderedArray<A>
93
+ export function sortConnectionsByBoundaryHierarchy<T extends WithBoundary, A extends IterableContainer<T>>(
94
+ connections?: A | 'asc' | 'desc',
95
+ sort?: 'asc' | 'desc',
96
+ ) {
97
+ if (!connections || isString(connections)) {
98
+ const dir = connections ?? 'asc'
99
+ return (arr: A) => _sortByBoundary(arr, dir)
100
+ }
101
+ return _sortByBoundary(connections, sort ?? 'asc')
102
+ }
103
+
104
+ function _sortByBoundary<C extends WithBoundary>(
105
+ connections: ReadonlyArray<C>,
106
+ order: 'asc' | 'desc',
107
+ ): C[] {
108
+ return pipe(
109
+ connections,
110
+ map(conn => ({
111
+ id: boundaryHierarchy(conn),
112
+ conn,
113
+ })),
114
+ sortNaturalByFqn(order),
115
+ map(prop('conn')),
116
+ )
117
+ }
118
+
119
+ /**
120
+ * Find connections that includes given connection (i.e between it's ancestors)
121
+ */
122
+ export function findAscendingConnections<C extends ConnectionElemId>(
123
+ connections: ReadonlyArray<C>,
124
+ connection: C,
125
+ ): Array<C> {
126
+ return connections.filter(c => isNestedConnection(connection, c))
127
+ }
128
+
129
+ /**
130
+ * Find connections that includes given connection (i.e between it's descendants)
131
+ */
132
+ export function findDescendantConnections<C extends ConnectionElemId>(
133
+ connections: ReadonlyArray<C>,
134
+ connection: C,
135
+ ): Array<C> {
136
+ return connections.filter(isNestedConnection(connection))
137
+ }
138
+
139
+ export function mergeConnections<C extends Connection>(
140
+ connections: ReadonlyArray<C>,
141
+ ): C[] {
142
+ const map = new Map<C['id'], C>()
143
+ for (const conn of connections) {
144
+ const existing = map.get(conn.id)
145
+ if (existing) {
146
+ map.set(conn.id, conn.mergeWith(existing) as C)
147
+ } else {
148
+ map.set(conn.id, conn)
149
+ }
150
+ }
151
+ return [...map.values()]
152
+ }
153
+
154
+ /**
155
+ * Excludes the values existing in `other` array.
156
+ * The output maintains the same order as the input.
157
+ */
158
+ export function differenceConnections<C extends Connection>(
159
+ source: Iterable<C>,
160
+ exclude: Iterable<C>,
161
+ ): C[] {
162
+ const minus = new Map([...exclude].map(c => [c.id, c]))
163
+ return [...source].reduce((acc, c) => {
164
+ const other = minus.get(c.id)
165
+ if (!other) {
166
+ acc.push(c)
167
+ return acc
168
+ }
169
+ const updated = c.difference(other) as C
170
+ if (updated.nonEmpty()) {
171
+ acc.push(updated)
172
+ }
173
+ return acc
174
+ }, [] as C[])
175
+ }
176
+
177
+ type WithSourceTarget<T = unknown> = {
178
+ source: T
179
+ target: T
180
+ }
181
+
182
+ export function hasSameSourceTarget<T>(a: WithSourceTarget<NoInfer<T>>): (b: WithSourceTarget<T>) => boolean
183
+ export function hasSameSourceTarget<T>(a: WithSourceTarget<T>, b: WithSourceTarget<T>): boolean
184
+ export function hasSameSourceTarget(a: WithSourceTarget, b?: WithSourceTarget) {
185
+ if (b) {
186
+ return a.source === b.source && a.target === b.target
187
+ }
188
+ return (b: WithSourceTarget) => a.source === b.source && a.target === b.target
189
+ }
190
+
191
+ export function hasSameSource<T>(a: WithSourceTarget<NoInfer<T>>): (b: WithSourceTarget<T>) => boolean
192
+ export function hasSameSource<T>(a: WithSourceTarget<T>, b: WithSourceTarget<T>): boolean
193
+ export function hasSameSource(a: WithSourceTarget, b?: WithSourceTarget) {
194
+ if (b) {
195
+ return a.source === b.source
196
+ }
197
+ return (b: WithSourceTarget) => a.source === b.source
198
+ }
199
+
200
+ export function hasSameTarget<T>(a: WithSourceTarget<NoInfer<T>>): (b: WithSourceTarget<T>) => boolean
201
+ export function hasSameTarget<T>(a: WithSourceTarget<T>, b: WithSourceTarget<T>): boolean
202
+ export function hasSameTarget(a: WithSourceTarget, b?: WithSourceTarget) {
203
+ if (b) {
204
+ return a.target === b.target
205
+ }
206
+ return (b: WithSourceTarget) => a.target === b.target
207
+ }
208
+
209
+ type WithId<T> = {
210
+ id: T
211
+ }
212
+ export function isOutgoing<T extends string>(source: WithId<NoInfer<T>>): (a: WithSourceTarget<WithId<T>>) => boolean
213
+ export function isOutgoing<T extends string>(a: WithSourceTarget<WithId<T>>, source: WithId<T>): boolean
214
+ export function isOutgoing<T extends string>(a: WithSourceTarget<WithId<T>> | WithId<T>, source?: WithId<T>) {
215
+ if (!source) {
216
+ const _source = a as WithId<T>
217
+ return (b: WithSourceTarget<WithId<T>>) => isOutgoing(b, _source)
218
+ }
219
+ const at = a as WithSourceTarget<WithId<T>>
220
+ return isDescendantOf(at.source, source) && !isDescendantOf(at.target, source)
221
+ }
222
+
223
+ export function isIncoming<T extends string>(target: WithId<NoInfer<T>>): (a: WithSourceTarget<WithId<T>>) => boolean
224
+ export function isIncoming<T extends string>(a: WithSourceTarget<WithId<T>>, target: WithId<T>): boolean
225
+ export function isIncoming<T extends string>(a: WithSourceTarget<WithId<T>> | WithId<T>, target?: WithId<T>) {
226
+ if (!target) {
227
+ const _target = a as WithId<T>
228
+ return (b: WithSourceTarget<WithId<T>>) => isIncoming(b, _target)
229
+ }
230
+ const at = a as WithSourceTarget<WithId<T>>
231
+ return isDescendantOf(at.target, target) && !isDescendantOf(at.source, target)
232
+ }
233
+
234
+ export function isAnyInOut<T extends string>(source: WithId<NoInfer<T>>): (a: WithSourceTarget<WithId<T>>) => boolean
235
+ export function isAnyInOut<T extends string>(a: WithSourceTarget<WithId<T>>, source: WithId<T>): boolean
236
+ export function isAnyInOut<T extends string>(a: WithSourceTarget<WithId<T>> | WithId<T>, source?: WithId<T>) {
237
+ if (!source) {
238
+ const _source = a as WithId<T>
239
+ return (b: WithSourceTarget<WithId<T>>) => isAnyInOut(b, _source)
240
+ }
241
+ const at = a as WithSourceTarget<WithId<T>>
242
+ return isDescendantOf(at.source, source) !== isDescendantOf(at.target, source)
243
+ }
244
+
245
+ export function isInside<T extends string>(source: WithId<NoInfer<T>>): (a: WithSourceTarget<WithId<T>>) => boolean
246
+ export function isInside<T extends string>(a: WithSourceTarget<WithId<T>>, source: WithId<T>): boolean
247
+ export function isInside<T extends string>(a: WithSourceTarget<WithId<T>> | WithId<T>, source?: WithId<T>) {
248
+ if (!source) {
249
+ const _source = a as WithId<T>
250
+ return (b: WithSourceTarget<WithId<T>>) => isInside(b, _source)
251
+ }
252
+ const at = a as WithSourceTarget<WithId<T>>
253
+ return isDescendantOf(at.source, source) && isDescendantOf(at.target, source)
254
+ }
255
+
256
+ // export function isIncoming<T>(target: NoInfer<T>): (a: WithSourceTarget<T>) => boolean
257
+ // export function isIncoming<T>(a: WithSourceTarget<T>, target: T): boolean
258
+ // export function isIncoming<T = unknown>(a: WithSourceTarget<T> | T, target?: T) {
259
+ // if (target) {
260
+ // return (a as WithSourceTarget<T>).target === target
261
+ // }
262
+ // const _target = a as T
263
+ // return (b: WithSourceTarget) => b.target === _target
264
+ // }
265
+
266
+ // export function isAnyInOut<T>(source: NoInfer<T>): (a: WithSourceTarget<T>) => boolean
267
+ // export function isAnyInOut<T>(a: WithSourceTarget<T>, source: T): boolean
268
+ // export function isAnyInOut<T = unknown>(a: WithSourceTarget<T> | T, source?: T) {
269
+ // if (source) {
270
+ // return hasSameSource(a as WithSourceTarget<T>, source) || hasSameTarget(a as WithSourceTarget<T>, source)
271
+ // }
272
+ // const _source = a as T
273
+ // return (b: WithSourceTarget) => hasSameSource(b, _source) || hasSameTarget(b, _source)
274
+ // }
@@ -0,0 +1,9 @@
1
+ import type { DeployedInstanceModel, DeploymentElementModel, DeploymentNodeModel } from './DeploymentElementModel'
2
+
3
+ export function isDeploymentNode(model: DeploymentElementModel): model is DeploymentNodeModel {
4
+ return model.isDeploymentNode()
5
+ }
6
+
7
+ export function isDeployedInstance(model: DeploymentElementModel): model is DeployedInstanceModel {
8
+ return model.isInstance()
9
+ }
@@ -1,3 +1,47 @@
1
- export { LikeC4DiagramModel } from './LikeC4DiagramModel'
1
+ export { ElementModel } from './ElementModel'
2
2
  export { LikeC4Model } from './LikeC4Model'
3
- export { LikeC4ViewModel } from './LikeC4ViewModel'
3
+ export { RelationshipModel } from './RelationModel'
4
+
5
+ export {
6
+ Connection,
7
+ ConnectionModel,
8
+ deployment as deploymentConnection,
9
+ DeploymentConnectionModel,
10
+ differenceConnections,
11
+ findAscendingConnections,
12
+ findDeepestNestedConnection,
13
+ findDescendantConnections,
14
+ hasSameSource,
15
+ hasSameSourceTarget,
16
+ hasSameTarget,
17
+ isAnyInOut,
18
+ isIncoming,
19
+ isNestedConnection,
20
+ isOutgoing,
21
+ mergeConnections,
22
+ model as modelConnection,
23
+ sortConnectionsByBoundaryHierarchy,
24
+ sortDeepestFirst,
25
+ } from './connection'
26
+
27
+ export {
28
+ DeployedInstanceModel,
29
+ type DeploymentElementModel,
30
+ DeploymentNodeModel,
31
+ DeploymentRelationModel,
32
+ } from './DeploymentElementModel'
33
+ export { LikeC4DeploymentModel } from './DeploymentModel'
34
+
35
+ export { EdgeModel } from './view/EdgeModel'
36
+ export { LikeC4ViewModel } from './view/LikeC4ViewModel'
37
+ export { NodeModel } from './view/NodeModel'
38
+
39
+ export type {
40
+ AnyAux,
41
+ Aux,
42
+ } from './types'
43
+
44
+ export {
45
+ isDeployedInstance,
46
+ isDeploymentNode,
47
+ } from './guards'
@@ -1,23 +1,120 @@
1
- import type { Fqn as CoreFqn } from '../types/element'
2
- import type { RelationID as CoreRelationID } from '../types/relation'
3
- import type { EdgeId as CoreEdgeId, ViewID as CoreViewID } from '../types/view'
4
-
5
- import { isString } from 'remeda'
6
- import type { LiteralUnion } from 'type-fest'
7
-
8
- export type Fqn = LiteralUnion<CoreFqn, string>
9
- export type RelationID = LiteralUnion<CoreRelationID, string>
10
- export type ViewID = LiteralUnion<CoreViewID, string>
11
- export type EdgeId = LiteralUnion<CoreEdgeId, string>
1
+ import type { IsStringLiteral, LiteralUnion, Simplify } from 'type-fest'
2
+ import type {
3
+ ComputedView,
4
+ DiagramView,
5
+ EdgeId,
6
+ Fqn,
7
+ GenericLikeC4Model,
8
+ IteratorLike,
9
+ KeysOf,
10
+ LayoutedLikeC4Model,
11
+ LikeC4ModelDump,
12
+ NodeId,
13
+ ParsedLikeC4Model,
14
+ RelationId,
15
+ ViewId,
16
+ } from '../types'
17
+ import { isString } from '../utils/guards'
12
18
 
13
19
  export type IncomingFilter = 'all' | 'direct' | 'to-descendants'
14
20
  export type OutgoingFilter = 'all' | 'direct' | 'from-descendants'
15
21
 
16
- export type ElementOrFqn = Fqn | { id: Fqn }
17
-
18
22
  /**
19
23
  * Utility function to extract `id` from the given element.
20
24
  */
21
- export function getId(element: ElementOrFqn): Fqn {
22
- return isString(element) ? element : element.id
25
+ export function getId<Id extends string>(element: string | { id: Id }): Id {
26
+ return isString(element) ? element as Id : element.id
27
+ }
28
+
29
+ type WithId<Id> = { id: Id }
30
+
31
+ type WithViews<Id extends string, ViewType> = { views: Record<Id, ViewType> }
32
+
33
+ /**
34
+ * Auxilary type to keep track
35
+ */
36
+ export interface Aux<
37
+ Element extends string,
38
+ Deployment extends string,
39
+ View extends string,
40
+ ViewType,
41
+ > {
42
+ Element: Element
43
+ Deployment: Deployment
44
+ View: View
45
+
46
+ // Wrapped Element
47
+ // If Fqn is just a string, then we use generic Fqn to have better hints in the editor
48
+ Fqn: IsStringLiteral<Element> extends true ? Fqn<Element> : Fqn
49
+ ElementOrFqn: Element | WithId<this['Fqn']>
50
+
51
+ // Wrapped Deployment
52
+ DeploymentFqn: IsStringLiteral<Deployment> extends true ? Fqn<Deployment> : Fqn
53
+ DeploymentOrFqn: Deployment | WithId<this['DeploymentFqn']>
54
+
55
+ // Wrapped View
56
+ ViewId: IsStringLiteral<View> extends true ? ViewId<View> : ViewId
57
+
58
+ ViewType: ViewType
59
+
60
+ RelationId: RelationId
61
+ NodeId: NodeId
62
+ NodeIdLiteral: string
63
+ EdgeId: EdgeId
64
+ EdgeIdLiteral: string
65
+
66
+ NodeOrId: LiteralUnion<this['NodeIdLiteral'], string> | WithId<this['NodeId']>
67
+ EdgeOrId: LiteralUnion<this['EdgeIdLiteral'], string> | WithId<this['EdgeId']>
68
+
69
+ Model: Simplify<Omit<GenericLikeC4Model, 'views'> & WithViews<this['ViewId'], ViewType>>
70
+ }
71
+
72
+ export type AnyAux = Aux<
73
+ string,
74
+ string,
75
+ string,
76
+ any
77
+ >
78
+
79
+ export namespace Strict {
80
+ export type Fqn<A extends AnyAux> = A['Element']
81
+ export type Deployment<A extends AnyAux> = A['Deployment']
82
+ export type ViewId<A extends AnyAux> = A['View']
83
+ }
84
+
85
+ export namespace Aux {
86
+ export type FromParsed<M> = M extends ParsedLikeC4Model ? Aux<
87
+ KeysOf<M['elements']>,
88
+ KeysOf<M['deployments']['elements']>,
89
+ KeysOf<M['views']>,
90
+ ComputedView<ViewId<KeysOf<M['views']>>, string>
91
+ >
92
+ : never
93
+
94
+ export type FromModel<M> = M extends GenericLikeC4Model ? Aux<
95
+ KeysOf<M['elements']>,
96
+ KeysOf<M['deployments']['elements']>,
97
+ KeysOf<M['views']>,
98
+ M extends LayoutedLikeC4Model ? DiagramView<ViewId<KeysOf<M['views']>>, string>
99
+ : ComputedView<ViewId<KeysOf<M['views']>>, string>
100
+ >
101
+ : never
102
+
103
+ export type FromDump<M> = M extends LikeC4ModelDump ? Aux<
104
+ KeysOf<M['elements']>,
105
+ KeysOf<M['deployments']['elements']>,
106
+ KeysOf<M['views']>,
107
+ DiagramView<ViewId<KeysOf<M['views']>>, string>
108
+ >
109
+ : never
23
110
  }
111
+
112
+ // export type FromModel<M> = LikeC4Model<
113
+ // M extends AnyLikeC4Model<
114
+ // infer Fqn extends string,
115
+ // infer Deployment extends string,
116
+ // infer ViewId extends string,
117
+ // any
118
+ // > ? Aux<Fqn, Deployment, ViewId, M>
119
+ // : Aux<KeysOf<>, string, string, ComputedLikeC4Model | LayoutedLikeC4Model>
120
+ // >
@@ -0,0 +1,103 @@
1
+ import { isNonNullish } from 'remeda'
2
+ import type { LiteralUnion } from 'type-fest'
3
+ import {
4
+ type ComputedDynamicView,
5
+ type ComputedView,
6
+ type DiagramView,
7
+ type IteratorLike,
8
+ type RelationId as C4RelationID,
9
+ type StepEdgeId,
10
+ type Tag as C4Tag,
11
+ extractStep,
12
+ isStepEdgeId,
13
+ } from '../../types'
14
+ import type { DeploymentRelationModel } from '../DeploymentElementModel'
15
+ import type { LikeC4Model } from '../LikeC4Model'
16
+ import type { RelationshipModel } from '../RelationModel'
17
+ import type { AnyAux } from '../types'
18
+ import type { LikeC4ViewModel } from './LikeC4ViewModel'
19
+ import type { NodeModel } from './NodeModel'
20
+
21
+ export type EdgesIterator<M extends AnyAux, V extends ComputedView | DiagramView> = IteratorLike<EdgeModel<M, V>>
22
+
23
+ export class EdgeModel<M extends AnyAux, V extends ComputedView | DiagramView = M['ViewType']> {
24
+ constructor(
25
+ public readonly view: LikeC4ViewModel<M, V>,
26
+ public readonly $edge: V['edges'][number],
27
+ public readonly source: NodeModel<M, V>,
28
+ public readonly target: NodeModel<M, V>,
29
+ ) {
30
+ }
31
+
32
+ get id(): M['EdgeId'] {
33
+ return this.$edge.id
34
+ }
35
+
36
+ get parent(): NodeModel<M, V> | null {
37
+ return this.$edge.parent ? this.view.node(this.$edge.parent) : null
38
+ }
39
+
40
+ get label(): string | null {
41
+ return this.$edge.label
42
+ }
43
+
44
+ get description(): string | null {
45
+ return this.$edge.description ?? null
46
+ }
47
+
48
+ get technology(): string | null {
49
+ return this.$edge.technology ?? null
50
+ }
51
+
52
+ public hasParent(): this is EdgeModel.WithParent<M, V> {
53
+ return this.$edge.parent !== null
54
+ }
55
+
56
+ get tags(): ReadonlyArray<C4Tag> {
57
+ return this.$edge.tags ?? []
58
+ }
59
+
60
+ get stepNumber(): number | null {
61
+ return this.isStep() ? extractStep(this.id) : null
62
+ }
63
+
64
+ get navigateTo(): LikeC4ViewModel<M> | null {
65
+ return this.$edge.navigateTo ? this.view.$model.view(this.$edge.navigateTo) : null
66
+ }
67
+
68
+ public isStep(): this is EdgeModel.StepEdge<M, ComputedDynamicView> {
69
+ return isStepEdgeId(this.id)
70
+ }
71
+
72
+ public relationships(type: 'model'): IteratorLike<RelationshipModel<M>>
73
+ public relationships(type: 'deployment'): IteratorLike<DeploymentRelationModel<M>>
74
+ public relationships(type?: 'model' | 'deployment'): IteratorLike<LikeC4Model.AnyRelation<M>>
75
+ public *relationships(type: 'model' | 'deployment' | undefined): IteratorLike<LikeC4Model.AnyRelation<M>> {
76
+ for (const id of this.$edge.relations) {
77
+ // if type is provided, then we need to filter relationships
78
+ if (type) {
79
+ const rel = this.view.$model.findRelationship(id, type)
80
+ if (rel) {
81
+ yield rel
82
+ }
83
+ } else {
84
+ yield this.view.$model.relationship(id)
85
+ }
86
+ }
87
+ return
88
+ }
89
+
90
+ public includesRelation(rel: M['RelationId']): boolean {
91
+ return this.$edge.relations.includes(rel as C4RelationID)
92
+ }
93
+ }
94
+
95
+ namespace EdgeModel {
96
+ export interface StepEdge<M extends AnyAux, V extends ComputedView | DiagramView> extends EdgeModel<M, V> {
97
+ id: StepEdgeId
98
+ stepNumber: number
99
+ }
100
+ export interface WithParent<M extends AnyAux, V extends ComputedView | DiagramView> extends EdgeModel<M, V> {
101
+ parent: NodeModel<M, V>
102
+ }
103
+ }