@likec4/core 1.30.0 → 1.32.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 (186) hide show
  1. package/README.md +407 -5
  2. package/dist/builder/index.d.mts +221 -42
  3. package/dist/builder/index.mjs +118 -65
  4. package/dist/compute-view/index.d.mts +23 -7
  5. package/dist/compute-view/index.mjs +11 -6
  6. package/dist/compute-view/relationships-view/index.d.mts +9 -7
  7. package/dist/compute-view/relationships-view/index.mjs +3 -2
  8. package/dist/index.d.mts +10 -14
  9. package/dist/index.mjs +10 -6
  10. package/dist/model/index.d.mts +173 -19
  11. package/dist/model/index.mjs +6 -1
  12. package/dist/shared/core.BaYE_r29.d.mts +258 -0
  13. package/dist/shared/core.Bk7wEZFG.mjs +276 -0
  14. package/dist/shared/core.BrCnZFTn.mjs +32 -0
  15. package/dist/shared/core.BuO4ncfY.d.mts +146 -0
  16. package/dist/shared/{core.CAcZ6_cP.mjs → core.CBpKAlhj.mjs} +1742 -4128
  17. package/dist/shared/core.CCWXGc6G.d.mts +920 -0
  18. package/dist/shared/core.CUYDgv2-.mjs +214 -0
  19. package/dist/shared/{core.Cu-UdkSl.mjs → core.CpXlRyE5.mjs} +7 -494
  20. package/dist/shared/{core.C-YXI-43.mjs → core.Cy9smucx.mjs} +3 -1
  21. package/dist/shared/core.CywrQs86.d.mts +31 -0
  22. package/dist/shared/core.DoK86JEe.mjs +518 -0
  23. package/dist/shared/core.Dpq3P3YJ.d.mts +1265 -0
  24. package/dist/shared/{core.D2830qgg.d.mts → core.Pf5I9o0e.d.mts} +1 -1
  25. package/dist/shared/core.cbA9VZ02.mjs +2681 -0
  26. package/dist/shared/{core.CQXU9DF7.mjs → core.rmvsy0n3.mjs} +23 -32
  27. package/dist/types/aux.d.mts +3 -0
  28. package/dist/types/aux.mjs +1 -0
  29. package/dist/types/index.d.mts +7 -45
  30. package/dist/types/index.mjs +130 -3
  31. package/dist/utils/index.d.mts +221 -53
  32. package/dist/utils/index.mjs +14 -10
  33. package/package.json +19 -10
  34. package/src/builder/Builder.deploymentModel.ts +82 -18
  35. package/src/builder/Builder.element.ts +40 -20
  36. package/src/builder/Builder.model.ts +66 -17
  37. package/src/builder/Builder.ts +168 -76
  38. package/src/builder/Builder.view-common.ts +35 -17
  39. package/src/builder/Builder.view-deployment.ts +25 -25
  40. package/src/builder/Builder.view-element.ts +13 -12
  41. package/src/builder/Builder.views.ts +12 -7
  42. package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +62 -34
  43. package/src/builder/__snapshots__/Builder-style2.compute-model.json5 +319 -0
  44. package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +45 -24
  45. package/src/builder/_types.ts +34 -27
  46. package/src/compute-view/compute-view.ts +31 -34
  47. package/src/compute-view/deployment-view/__test__/TestHelper.ts +27 -14
  48. package/src/compute-view/deployment-view/__test__/fixture.ts +15 -13
  49. package/src/compute-view/deployment-view/_types.ts +10 -10
  50. package/src/compute-view/deployment-view/clean-connections.ts +5 -7
  51. package/src/compute-view/deployment-view/compute.ts +16 -13
  52. package/src/compute-view/deployment-view/memory/memory.ts +5 -6
  53. package/src/compute-view/deployment-view/predicates/deploymentRefs.ts +4 -5
  54. package/src/compute-view/deployment-view/predicates/relation-direct.ts +25 -50
  55. package/src/compute-view/deployment-view/predicates/relation-in-out.ts +5 -7
  56. package/src/compute-view/deployment-view/predicates/relation-incoming.ts +7 -11
  57. package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +7 -10
  58. package/src/compute-view/deployment-view/predicates/utils.ts +37 -31
  59. package/src/compute-view/deployment-view/predicates/wildcard.ts +3 -2
  60. package/src/compute-view/deployment-view/stages/stage-final.ts +2 -2
  61. package/src/compute-view/deployment-view/stages/stage-include.ts +1 -1
  62. package/src/compute-view/deployment-view/utils.ts +79 -72
  63. package/src/compute-view/dynamic-view/__test__/fixture.ts +20 -11
  64. package/src/compute-view/dynamic-view/compute.ts +60 -53
  65. package/src/compute-view/element-view/__test__/TestHelper.ts +53 -29
  66. package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +26 -26
  67. package/src/compute-view/element-view/__test__/fixture.ts +134 -83
  68. package/src/compute-view/element-view/_types.ts +14 -19
  69. package/src/compute-view/element-view/clean-connections.ts +12 -8
  70. package/src/compute-view/element-view/compute.ts +61 -51
  71. package/src/compute-view/element-view/memory/NodeGroup.ts +8 -9
  72. package/src/compute-view/element-view/memory/memory.ts +22 -22
  73. package/src/compute-view/element-view/memory/stage-include.ts +5 -3
  74. package/src/compute-view/element-view/predicates/_utils.ts +18 -14
  75. package/src/compute-view/element-view/predicates/element-expand.ts +4 -5
  76. package/src/compute-view/element-view/predicates/element-kind-tag.ts +3 -4
  77. package/src/compute-view/element-view/predicates/element-ref.ts +3 -4
  78. package/src/compute-view/element-view/predicates/relation-direct.ts +16 -12
  79. package/src/compute-view/element-view/predicates/relation-in-out.ts +7 -8
  80. package/src/compute-view/element-view/predicates/relation-in.ts +19 -26
  81. package/src/compute-view/element-view/predicates/relation-out.ts +20 -21
  82. package/src/compute-view/element-view/predicates/wildcard.ts +3 -3
  83. package/src/compute-view/element-view/utils.ts +25 -23
  84. package/src/compute-view/index.ts +1 -1
  85. package/src/compute-view/memory/AbstractStageExclude.ts +3 -4
  86. package/src/compute-view/memory/AbstractStageInclude.ts +1 -1
  87. package/src/compute-view/memory/_types.ts +3 -2
  88. package/src/compute-view/relationships-view/_types.ts +3 -4
  89. package/src/compute-view/relationships-view/compute.ts +8 -11
  90. package/src/compute-view/relationships-view/layout.ts +6 -6
  91. package/src/compute-view/relationships-view/utils.ts +4 -4
  92. package/src/compute-view/utils/ancestorsOfNode.ts +7 -7
  93. package/src/compute-view/utils/applyCustomElementProperties.ts +16 -8
  94. package/src/compute-view/utils/applyCustomRelationProperties.ts +19 -9
  95. package/src/compute-view/utils/applyViewRuleStyles.ts +18 -10
  96. package/src/compute-view/utils/buildComputedNodes.ts +40 -40
  97. package/src/compute-view/utils/buildElementNotations.ts +14 -14
  98. package/src/compute-view/utils/elementExpressionToPredicate.ts +14 -15
  99. package/src/compute-view/utils/link-nodes-with-edges.ts +6 -4
  100. package/src/compute-view/utils/merge-props-from-relationships.ts +52 -20
  101. package/src/compute-view/utils/relationExpressionToPredicates.ts +19 -19
  102. package/src/compute-view/utils/resolve-extended-views.ts +8 -7
  103. package/src/compute-view/utils/resolve-global-rules.ts +31 -26
  104. package/src/compute-view/utils/topological-sort.ts +14 -14
  105. package/src/compute-view/utils/view-hash.ts +2 -2
  106. package/src/compute-view/utils/with-readable-edges.ts +9 -5
  107. package/src/index.ts +0 -32
  108. package/src/model/DeploymentElementModel.ts +182 -137
  109. package/src/model/DeploymentModel.ts +88 -65
  110. package/src/model/ElementModel.ts +92 -72
  111. package/src/model/LikeC4Model.ts +430 -241
  112. package/src/model/RelationModel.ts +69 -26
  113. package/src/model/__test__/fixture.ts +50 -36
  114. package/src/model/connection/Connection.ts +2 -2
  115. package/src/model/connection/deployment/DeploymentConnectionModel.ts +21 -24
  116. package/src/model/connection/deployment/find.ts +1 -1
  117. package/src/model/connection/model/ConnectionModel.ts +21 -20
  118. package/src/model/connection/model/find.ts +7 -7
  119. package/src/model/connection/ops.ts +6 -6
  120. package/src/model/guards.ts +66 -14
  121. package/src/model/index.ts +20 -7
  122. package/src/model/types.ts +41 -97
  123. package/src/model/view/EdgeModel.ts +47 -41
  124. package/src/model/view/LikeC4ViewModel.ts +130 -80
  125. package/src/model/view/NodeModel.ts +102 -96
  126. package/src/theme/element.ts +1 -1
  127. package/src/theme/index.ts +9 -9
  128. package/src/theme/relationships.ts +1 -1
  129. package/src/types/_common.ts +21 -15
  130. package/src/types/aux.ts +285 -0
  131. package/src/types/const.ts +34 -0
  132. package/src/types/expression-model.ts +292 -0
  133. package/src/types/expression.ts +311 -0
  134. package/src/types/fqnRef.ts +88 -0
  135. package/src/types/geometry.ts +131 -0
  136. package/src/types/global.ts +10 -8
  137. package/src/types/index.ts +39 -201
  138. package/src/types/model-data.ts +52 -84
  139. package/src/types/model-deployment.ts +87 -0
  140. package/src/types/model-dump.ts +72 -0
  141. package/src/types/model-logical.ts +111 -0
  142. package/src/types/model-spec.ts +81 -0
  143. package/src/types/operators.ts +51 -52
  144. package/src/types/scalar.ts +114 -0
  145. package/src/types/styles.ts +123 -0
  146. package/src/types/view-changes.ts +4 -5
  147. package/src/types/view-common.ts +157 -0
  148. package/src/types/view-computed.ts +113 -0
  149. package/src/types/view-layouted.ts +82 -0
  150. package/src/types/view-parsed.deployment.ts +40 -0
  151. package/src/types/view-parsed.dynamic.ts +78 -0
  152. package/src/types/view-parsed.element.ts +65 -0
  153. package/src/types/view.ts +122 -542
  154. package/src/utils/compare-natural.ts +43 -1
  155. package/src/utils/getOrCreate.ts +0 -34
  156. package/src/utils/index.ts +7 -12
  157. package/src/utils/iterable/filter.ts +1 -1
  158. package/src/utils/iterable/find.ts +3 -1
  159. package/src/utils/iterable/head.ts +22 -0
  160. package/src/utils/iterable/index.ts +1 -0
  161. package/src/utils/iterable/map.ts +1 -1
  162. package/src/utils/iterable/reduce.ts +1 -1
  163. package/src/utils/iterable/some.ts +1 -1
  164. package/src/utils/memoize-prop.ts +30 -0
  165. package/src/utils/object-hash.ts +1 -1
  166. package/src/utils/relations.ts +14 -11
  167. package/src/utils/string-hash.ts +1 -1
  168. package/dist/shared/core.CZR9J1Qx.d.mts +0 -146
  169. package/dist/shared/core.CiFKryGW.d.mts +0 -745
  170. package/dist/shared/core.DJvmfnEi.d.mts +0 -1153
  171. package/dist/shared/core.DgfwjBtu.mjs +0 -495
  172. package/dist/shared/core.SjLhMA7a.d.mts +0 -62
  173. package/src/builder/__snapshots__/Builder.spec.ts.snap +0 -374
  174. package/src/compute-view/element-view/predicates.ts +0 -520
  175. package/src/compute-view/utils/uniqueTags.ts +0 -21
  176. package/src/types/deployments.ts +0 -170
  177. package/src/types/element.ts +0 -109
  178. package/src/types/expression-v2-model.ts +0 -314
  179. package/src/types/expression-v2.ts +0 -392
  180. package/src/types/overview-graph.ts +0 -43
  181. package/src/types/relation.ts +0 -61
  182. package/src/types/scalars.ts +0 -39
  183. package/src/types/theme.ts +0 -82
  184. package/src/types/view-notation.ts +0 -9
  185. package/src/utils/graphlib.ts +0 -10
  186. /package/src/{errors/index.ts → utils/invariant.ts} +0 -0
@@ -1,54 +1,48 @@
1
- import { isEmpty, only } from 'remeda'
1
+ import { isTruthy, only, unique } from 'remeda'
2
2
  import type { SetRequired } from 'type-fest'
3
- import { nonNullable } from '../errors'
4
3
  import {
4
+ type Any,
5
5
  type Color,
6
- type ComputedDeploymentView,
7
6
  type DeployedInstance,
7
+ type DeploymentElement,
8
8
  type DeploymentElementStyle,
9
9
  type DeploymentNode,
10
- type DeploymentNodeKind,
11
- type DeploymentRelation,
12
- type ElementKind,
10
+ type DeploymentRelationship,
13
11
  type ElementShape as C4ElementShape,
14
12
  type IteratorLike,
15
13
  type Link,
16
- type RelationshipKind,
17
14
  type RelationshipLineType,
18
- type Tag,
19
- type Tag as C4Tag,
20
- type ThemeColor,
15
+ type scalar,
21
16
  DefaultElementShape,
22
17
  DefaultLineStyle,
23
- DefaultRelationshipColor,
18
+ DefaultShapeSize,
24
19
  DefaultThemeColor,
25
20
  } from '../types'
26
- import { DefaultShapeSize } from '../types/element'
27
- import { commonAncestor, hierarchyLevel } from '../utils'
21
+ import * as aux from '../types/aux'
22
+ import { commonAncestor, hierarchyLevel, memoizeProp, nonNullable } from '../utils'
28
23
  import { difference, intersection, union } from '../utils/set'
29
24
  import type { LikeC4DeploymentModel } from './DeploymentModel'
30
25
  import type { ElementModel } from './ElementModel'
31
- import type { RelationshipModel, RelationshipsIterator } from './RelationModel'
32
- import type { AnyAux, IncomingFilter, OutgoingFilter } from './types'
26
+ import type { AnyRelationshipModel, RelationshipModel, RelationshipsIterator } from './RelationModel'
27
+ import type { IncomingFilter, OutgoingFilter } from './types'
33
28
  import type { LikeC4ViewModel } from './view/LikeC4ViewModel'
34
29
 
35
- export type DeploymentElementsIterator<M extends AnyAux> = IteratorLike<
36
- DeploymentNodeModel<M> | DeployedInstanceModel<M>
37
- >
38
- export type DeployedInstancesIterator<M extends AnyAux> = IteratorLike<DeployedInstanceModel<M>>
39
- export type DeploymentNodesIterator<M extends AnyAux> = IteratorLike<DeploymentNodeModel<M>>
30
+ export type DeploymentElementsIterator<A extends Any> = IteratorLike<DeploymentElementModel<A>>
31
+ export type DeployedInstancesIterator<A extends Any> = IteratorLike<DeployedInstanceModel<A>>
32
+ export type DeploymentNodesIterator<A extends Any> = IteratorLike<DeploymentNodeModel<A>>
40
33
 
41
- export type DeploymentElementModel<M extends AnyAux = AnyAux> = DeploymentNodeModel<M> | DeployedInstanceModel<M>
34
+ export type DeploymentElementModel<A extends Any = Any> = DeploymentNodeModel<A> | DeployedInstanceModel<A>
42
35
 
43
- abstract class AbstractDeploymentElementModel<M extends AnyAux = AnyAux> {
44
- abstract readonly id: M['DeploymentFqn']
45
- abstract readonly parent: DeploymentNodeModel<M> | null
36
+ abstract class AbstractDeploymentElementModel<A extends Any> {
37
+ abstract readonly id: aux.DeploymentFqn<A>
38
+ abstract readonly _literalId: aux.DeploymentId<A>
39
+ abstract readonly parent: DeploymentNodeModel<A> | null
46
40
  abstract readonly title: string
47
41
  abstract readonly hierarchyLevel: number
48
42
 
49
- abstract readonly $model: LikeC4DeploymentModel<M>
50
- abstract readonly $node: DeploymentNode | DeployedInstance
51
- abstract readonly kind: DeploymentNodeKind | ElementKind
43
+ abstract readonly $model: LikeC4DeploymentModel<A>
44
+ abstract readonly $node: DeploymentElement<A>
45
+ abstract readonly tags: aux.Tags<A>
52
46
 
53
47
  get style(): SetRequired<DeploymentElementStyle, 'shape' | 'color' | 'size'> {
54
48
  return {
@@ -63,12 +57,8 @@ abstract class AbstractDeploymentElementModel<M extends AnyAux = AnyAux> {
63
57
  return this.$node.style?.shape ?? DefaultElementShape
64
58
  }
65
59
 
66
- get color(): ThemeColor {
67
- return this.$node.style?.color as ThemeColor ?? DefaultThemeColor
68
- }
69
-
70
- get tags(): ReadonlyArray<C4Tag> {
71
- return this.$node.tags ?? []
60
+ get color(): Color {
61
+ return this.$node.style?.color as Color ?? DefaultThemeColor
72
62
  }
73
63
 
74
64
  get description(): string | null {
@@ -87,14 +77,14 @@ abstract class AbstractDeploymentElementModel<M extends AnyAux = AnyAux> {
87
77
  * Get all ancestor elements (i.e. parent, parent’s parent, etc.)
88
78
  * (from closest to root)
89
79
  */
90
- public ancestors(): DeploymentNodesIterator<M> {
80
+ public ancestors(): DeploymentNodesIterator<A> {
91
81
  return this.$model.ancestors(this)
92
82
  }
93
83
 
94
84
  /**
95
85
  * Returns the common ancestor of this element and another element.
96
86
  */
97
- public commonAncestor(another: DeploymentElementModel<M>): DeploymentNodeModel<M> | null {
87
+ public commonAncestor(another: DeploymentElementModel<A>): DeploymentNodeModel<A> | null {
98
88
  const common = commonAncestor(this.id, another.id)
99
89
  return common ? this.$model.node(common) : null
100
90
  }
@@ -102,14 +92,14 @@ abstract class AbstractDeploymentElementModel<M extends AnyAux = AnyAux> {
102
92
  /**
103
93
  * Get all sibling (i.e. same parent)
104
94
  */
105
- public siblings(): DeploymentElementsIterator<M> {
95
+ public siblings(): DeploymentElementsIterator<A> {
106
96
  return this.$model.siblings(this)
107
97
  }
108
98
 
109
99
  /**
110
100
  * Check if the element is a sibling of another element
111
101
  */
112
- public isSibling(other: DeploymentElementModel<M>): boolean {
102
+ public isSibling(other: DeploymentElementModel<A>): boolean {
113
103
  return this.parent === other.parent
114
104
  }
115
105
 
@@ -117,7 +107,7 @@ abstract class AbstractDeploymentElementModel<M extends AnyAux = AnyAux> {
117
107
  * Resolve siblings of the element and its ancestors
118
108
  * (from closest to root)
119
109
  */
120
- public *ascendingSiblings(): DeploymentElementsIterator<M> {
110
+ public *ascendingSiblings(): DeploymentElementsIterator<A> {
121
111
  yield* this.siblings()
122
112
  for (const ancestor of this.ancestors()) {
123
113
  yield* ancestor.siblings()
@@ -129,7 +119,7 @@ abstract class AbstractDeploymentElementModel<M extends AnyAux = AnyAux> {
129
119
  * Resolve siblings of the element and its ancestors
130
120
  * (from root to closest)
131
121
  */
132
- public *descendingSiblings(): DeploymentElementsIterator<M> {
122
+ public *descendingSiblings(): DeploymentElementsIterator<A> {
133
123
  for (const ancestor of [...this.ancestors()].reverse()) {
134
124
  yield* ancestor.siblings()
135
125
  }
@@ -137,15 +127,15 @@ abstract class AbstractDeploymentElementModel<M extends AnyAux = AnyAux> {
137
127
  return
138
128
  }
139
129
 
140
- public incoming(filter: IncomingFilter = 'all'): IteratorLike<DeploymentRelationModel<M>> {
130
+ public incoming(filter: IncomingFilter = 'all'): IteratorLike<DeploymentRelationModel<A>> {
141
131
  return this.$model.incoming(this, filter)
142
132
  }
143
- public outgoing(filter: OutgoingFilter = 'all'): IteratorLike<DeploymentRelationModel<M>> {
133
+ public outgoing(filter: OutgoingFilter = 'all'): IteratorLike<DeploymentRelationModel<A>> {
144
134
  return this.$model.outgoing(this, filter)
145
135
  }
146
136
 
147
- public *incomers(filter: IncomingFilter = 'all'): IteratorLike<DeploymentRelationEndpoint<M>> {
148
- const unique = new Set<M['Deployment']>()
137
+ public *incomers(filter: IncomingFilter = 'all'): IteratorLike<DeploymentRelationEndpoint<A>> {
138
+ const unique = new Set<aux.DeploymentFqn<A>>()
149
139
  for (const r of this.incoming(filter)) {
150
140
  if (unique.has(r.source.id)) {
151
141
  continue
@@ -155,8 +145,8 @@ abstract class AbstractDeploymentElementModel<M extends AnyAux = AnyAux> {
155
145
  }
156
146
  return
157
147
  }
158
- public *outgoers(filter: OutgoingFilter = 'all'): IteratorLike<DeploymentRelationEndpoint<M>> {
159
- const unique = new Set<M['Deployment']>()
148
+ public *outgoers(filter: OutgoingFilter = 'all'): IteratorLike<DeploymentRelationEndpoint<A>> {
149
+ const unique = new Set<aux.DeploymentFqn<A>>()
160
150
  for (const r of this.outgoing(filter)) {
161
151
  if (unique.has(r.target.id)) {
162
152
  continue
@@ -170,9 +160,9 @@ abstract class AbstractDeploymentElementModel<M extends AnyAux = AnyAux> {
170
160
  /**
171
161
  * Iterate over all views that include this deployment element.
172
162
  */
173
- public *views(): IteratorLike<LikeC4ViewModel<M, ComputedDeploymentView>> {
163
+ public *views(): IteratorLike<LikeC4ViewModel.DeploymentView<A>> {
174
164
  for (const view of this.$model.views()) {
175
- if (!view.isDeploymentView()) {
165
+ if (view._type !== 'deployment') {
176
166
  continue
177
167
  }
178
168
  if (view.includesDeployment(this.id)) {
@@ -182,76 +172,100 @@ abstract class AbstractDeploymentElementModel<M extends AnyAux = AnyAux> {
182
172
  }
183
173
 
184
174
  // type guard
185
- public isDeploymentNode(): this is DeploymentNodeModel<M> {
175
+ public isDeploymentNode(): this is DeploymentNodeModel<A> {
186
176
  return false
187
177
  }
188
178
  // type guard
189
- public isInstance(): this is DeployedInstanceModel<M> {
179
+ public isInstance(): this is DeployedInstanceModel<A> {
190
180
  return false
191
181
  }
192
182
 
193
- public abstract outgoingModelRelationships(): RelationshipsIterator<M>
194
- public abstract incomingModelRelationships(): RelationshipsIterator<M>
183
+ public abstract outgoingModelRelationships(): RelationshipsIterator<A>
184
+ public abstract incomingModelRelationships(): RelationshipsIterator<A>
195
185
 
196
- protected cachedOutgoing: RelationshipsAccum<M> | null = null
197
- protected cachedIncoming: RelationshipsAccum<M> | null = null
186
+ public get allOutgoing(): RelationshipsAccum<A> {
187
+ return memoizeProp(this, Symbol.for('allOutgoing'), () =>
188
+ RelationshipsAccum.from(
189
+ new Set(this.outgoingModelRelationships()),
190
+ new Set(this.outgoing()),
191
+ ))
192
+ }
198
193
 
199
- public get allOutgoing(): RelationshipsAccum<M> {
200
- this.cachedOutgoing ??= RelationshipsAccum.from(
201
- new Set(this.outgoingModelRelationships()),
202
- new Set(this.outgoing()),
203
- )
204
- return this.cachedOutgoing
194
+ public get allIncoming(): RelationshipsAccum<A> {
195
+ return memoizeProp(this, Symbol.for('allIncoming'), () =>
196
+ RelationshipsAccum.from(
197
+ new Set(this.incomingModelRelationships()),
198
+ new Set(this.incoming()),
199
+ ))
205
200
  }
206
201
 
207
- public get allIncoming(): RelationshipsAccum<M> {
208
- this.cachedIncoming ??= RelationshipsAccum.from(
209
- new Set(this.incomingModelRelationships()),
210
- new Set(this.incoming()),
211
- )
212
- return this.cachedIncoming
202
+ public getMetadata(): aux.Metadata<A>
203
+ public getMetadata(field: aux.MetadataKey<A>): string | undefined
204
+ public getMetadata(field?: aux.MetadataKey<A>) {
205
+ if (field) {
206
+ return this.$node.metadata?.[field]
207
+ }
208
+ return this.$node.metadata ?? {}
209
+ }
210
+
211
+ /**
212
+ * Checks if the deployment element has the given tag.
213
+ */
214
+ public isTagged(tag: aux.LooseTag<A>): boolean {
215
+ return this.tags.includes(tag as aux.Tag<A>)
213
216
  }
214
217
  }
215
218
 
216
- export class DeploymentNodeModel<M extends AnyAux = AnyAux> extends AbstractDeploymentElementModel<M> {
217
- override id: M['DeploymentFqn']
219
+ export class DeploymentNodeModel<A extends Any = Any> extends AbstractDeploymentElementModel<A> {
220
+ override id: aux.DeploymentFqn<A>
221
+ override _literalId: aux.DeploymentId<A>
218
222
  override title: string
219
223
  override hierarchyLevel: number
220
224
 
221
225
  constructor(
222
- public readonly $model: LikeC4DeploymentModel<M>,
223
- public readonly $node: DeploymentNode,
226
+ public readonly $model: LikeC4DeploymentModel<A>,
227
+ public readonly $node: DeploymentNode<A>,
224
228
  ) {
225
229
  super()
226
230
  this.id = $node.id
231
+ this._literalId = $node.id
227
232
  this.title = $node.title
228
233
  this.hierarchyLevel = hierarchyLevel($node.id)
229
234
  }
230
235
 
231
- get parent(): DeploymentNodeModel<M> | null {
236
+ get parent(): DeploymentNodeModel<A> | null {
232
237
  return this.$model.parent(this)
233
238
  }
234
239
 
235
- override get kind(): DeploymentNodeKind {
240
+ get kind(): aux.DeploymentKind<A> {
236
241
  return this.$node.kind
237
242
  }
238
243
 
239
- public children(): ReadonlySet<DeploymentElementModel<M>> {
244
+ override get tags(): aux.Tags<A> {
245
+ return memoizeProp(this, Symbol.for('tags'), () => {
246
+ return unique([
247
+ ...(this.$node.tags ?? []),
248
+ ...(this.$model.$model.specification.deployments[this.kind]?.tags ?? []),
249
+ ] as aux.Tags<A>)
250
+ })
251
+ }
252
+
253
+ public children(): ReadonlySet<DeploymentElementModel<A>> {
240
254
  return this.$model.children(this)
241
255
  }
242
256
 
243
- public descendants(sort: 'asc' | 'desc' = 'desc'): DeploymentElementsIterator<M> {
257
+ public descendants(sort: 'asc' | 'desc' = 'desc'): DeploymentElementsIterator<A> {
244
258
  return this.$model.descendants(this, sort)
245
259
  }
246
260
 
247
- public override isDeploymentNode(): this is DeploymentNodeModel<M> {
261
+ public override isDeploymentNode(): this is DeploymentNodeModel<A> {
248
262
  return true
249
263
  }
250
264
 
251
265
  /**
252
266
  * Iterate over all instances nested in this deployment node.
253
267
  */
254
- public *instances(): DeployedInstancesIterator<M> {
268
+ public *instances(): DeployedInstancesIterator<A> {
255
269
  for (const nested of this.descendants('desc')) {
256
270
  if (nested.isInstance()) {
257
271
  yield nested
@@ -264,7 +278,7 @@ export class DeploymentNodeModel<M extends AnyAux = AnyAux> extends AbstractDepl
264
278
  * Returns deployed instance inside this deployment node
265
279
  * if only there are no more instances
266
280
  */
267
- public onlyOneInstance(): DeployedInstanceModel<M> | null {
281
+ public onlyOneInstance(): DeployedInstanceModel<A> | null {
268
282
  const children = this.children()
269
283
  if (children.size !== 1) {
270
284
  return null
@@ -277,8 +291,8 @@ export class DeploymentNodeModel<M extends AnyAux = AnyAux> extends AbstractDepl
277
291
  * Cached result of relationships from instances
278
292
  */
279
293
  private _relationshipsFromInstances: {
280
- outgoing: ReadonlySet<RelationshipModel<M>>
281
- incoming: ReadonlySet<RelationshipModel<M>>
294
+ outgoing: ReadonlySet<RelationshipModel<A>>
295
+ incoming: ReadonlySet<RelationshipModel<A>>
282
296
  } | null = null
283
297
 
284
298
  private relationshipsFromInstances() {
@@ -289,8 +303,8 @@ export class DeploymentNodeModel<M extends AnyAux = AnyAux> extends AbstractDepl
289
303
  outgoing,
290
304
  incoming,
291
305
  } = (this._relationshipsFromInstances = {
292
- outgoing: new Set<RelationshipModel<M>>(),
293
- incoming: new Set<RelationshipModel<M>>(),
306
+ outgoing: new Set<RelationshipModel<A>>(),
307
+ incoming: new Set<RelationshipModel<A>>(),
294
308
  })
295
309
  for (const instance of this.instances()) {
296
310
  for (const r of instance.element.outgoing()) {
@@ -306,21 +320,21 @@ export class DeploymentNodeModel<M extends AnyAux = AnyAux> extends AbstractDepl
306
320
  /**
307
321
  * We return only relationships that are not already present in nested instances
308
322
  */
309
- public override outgoingModelRelationships(): RelationshipsIterator<M> {
323
+ public override outgoingModelRelationships(): RelationshipsIterator<A> {
310
324
  return this.relationshipsFromInstances().outgoing.values()
311
325
  }
312
326
 
313
327
  /**
314
328
  * We return only relationships that are not already present in nested instances
315
329
  */
316
- public override incomingModelRelationships(): RelationshipsIterator<M> {
330
+ public override incomingModelRelationships(): RelationshipsIterator<A> {
317
331
  return this.relationshipsFromInstances().incoming.values()
318
332
  }
319
333
 
320
334
  /**
321
335
  * Returns an iterator of relationships between nested instances
322
336
  */
323
- public internalModelRelationships(): ReadonlySet<RelationshipModel<M>> {
337
+ public internalModelRelationships(): ReadonlySet<RelationshipModel<A>> {
324
338
  const {
325
339
  outgoing,
326
340
  incoming,
@@ -329,27 +343,29 @@ export class DeploymentNodeModel<M extends AnyAux = AnyAux> extends AbstractDepl
329
343
  }
330
344
  }
331
345
 
332
- export class DeployedInstanceModel<M extends AnyAux = AnyAux> extends AbstractDeploymentElementModel<M> {
333
- override readonly id: M['DeploymentFqn']
346
+ export class DeployedInstanceModel<A extends Any = Any> extends AbstractDeploymentElementModel<A> {
347
+ override readonly id: aux.DeploymentFqn<A>
348
+ override readonly _literalId: aux.DeploymentId<A>
334
349
  override readonly title: string
335
350
  override readonly hierarchyLevel: number
336
351
 
337
352
  constructor(
338
- public readonly $model: LikeC4DeploymentModel<M>,
339
- public readonly $instance: DeployedInstance,
340
- public readonly element: ElementModel<M>,
353
+ public readonly $model: LikeC4DeploymentModel<A>,
354
+ public readonly $instance: DeployedInstance<A>,
355
+ public readonly element: ElementModel<A>,
341
356
  ) {
342
357
  super()
343
358
  this.id = $instance.id
359
+ this._literalId = $instance.id
344
360
  this.title = $instance.title ?? element.title
345
361
  this.hierarchyLevel = hierarchyLevel($instance.id)
346
362
  }
347
363
 
348
- get $node(): DeployedInstance {
364
+ get $node(): DeployedInstance<A> {
349
365
  return this.$instance
350
366
  }
351
367
 
352
- get parent(): DeploymentNodeModel<M> {
368
+ get parent(): DeploymentNodeModel<A> {
353
369
  return nonNullable(this.$model.parent(this), `Parent of ${this.id} not found`)
354
370
  }
355
371
 
@@ -369,15 +385,20 @@ export class DeployedInstanceModel<M extends AnyAux = AnyAux> extends AbstractDe
369
385
  return this.$instance.style?.shape ?? this.element.shape
370
386
  }
371
387
 
372
- override get color(): ThemeColor {
373
- return this.$instance.style?.color as ThemeColor ?? this.element.color
388
+ override get color(): Color {
389
+ return this.$instance.style?.color as Color ?? this.element.color
374
390
  }
375
391
 
376
- override get tags(): ReadonlyArray<C4Tag> {
377
- return this.$instance.tags ?? []
392
+ override get tags(): aux.Tags<A> {
393
+ return memoizeProp(this, Symbol.for('tags'), () => {
394
+ return unique([
395
+ ...(this.$instance.tags ?? []),
396
+ ...this.element.tags,
397
+ ] as aux.Tags<A>)
398
+ })
378
399
  }
379
400
 
380
- override get kind(): ElementKind {
401
+ get kind(): aux.ElementKind<A> {
381
402
  return this.element.kind
382
403
  }
383
404
 
@@ -393,14 +414,14 @@ export class DeployedInstanceModel<M extends AnyAux = AnyAux> extends AbstractDe
393
414
  return this.$instance.links ?? this.element.links
394
415
  }
395
416
 
396
- public override isInstance(): this is DeployedInstanceModel<M> {
417
+ public override isInstance(): this is DeployedInstanceModel<A> {
397
418
  return true
398
419
  }
399
420
 
400
- public override outgoingModelRelationships(): RelationshipsIterator<M> {
421
+ public override outgoingModelRelationships(): RelationshipsIterator<A> {
401
422
  return this.element.outgoing()
402
423
  }
403
- public override incomingModelRelationships(): RelationshipsIterator<M> {
424
+ public override incomingModelRelationships(): RelationshipsIterator<A> {
404
425
  return this.element.incoming()
405
426
  }
406
427
 
@@ -408,9 +429,9 @@ export class DeployedInstanceModel<M extends AnyAux = AnyAux> extends AbstractDe
408
429
  * Iterate over all views that include this instance.
409
430
  * (Some views may include the parent deployment node instead of the instance.)
410
431
  */
411
- public override *views(): IteratorLike<LikeC4ViewModel<M, ComputedDeploymentView>> {
432
+ public override *views(): IteratorLike<LikeC4ViewModel.DeploymentView<A>> {
412
433
  for (const view of this.$model.views()) {
413
- if (!view.isDeploymentView()) {
434
+ if (view._type !== 'deployment') {
414
435
  continue
415
436
  }
416
437
  if (view.includesDeployment(this.id)) {
@@ -428,14 +449,18 @@ export class DeployedInstanceModel<M extends AnyAux = AnyAux> extends AbstractDe
428
449
  }
429
450
  }
430
451
 
431
- export class NestedElementOfDeployedInstanceModel<M extends AnyAux> {
452
+ export class NestedElementOfDeployedInstanceModel<A extends Any = Any> {
432
453
  constructor(
433
- public readonly instance: DeployedInstanceModel<M>,
434
- public readonly element: ElementModel<M>,
454
+ public readonly instance: DeployedInstanceModel<A>,
455
+ public readonly element: ElementModel<A>,
435
456
  ) {
436
457
  }
437
458
 
438
- get id(): M['DeploymentFqn'] {
459
+ get id(): aux.DeploymentFqn<A> {
460
+ return this.instance.id
461
+ }
462
+
463
+ get _literalId(): aux.DeploymentId<A> {
439
464
  return this.instance.id
440
465
  }
441
466
 
@@ -453,7 +478,7 @@ export class NestedElementOfDeployedInstanceModel<M extends AnyAux> {
453
478
  return this.element.shape
454
479
  }
455
480
 
456
- get color(): ThemeColor {
481
+ get color(): Color {
457
482
  return this.element.color
458
483
  }
459
484
 
@@ -469,33 +494,33 @@ export class NestedElementOfDeployedInstanceModel<M extends AnyAux> {
469
494
  return this.element.technology
470
495
  }
471
496
 
472
- public isDeploymentNode(): this is DeploymentNodeModel<M> {
497
+ public isDeploymentNode(): this is DeploymentNodeModel<A> {
473
498
  return false
474
499
  }
475
- public isInstance(): this is DeployedInstanceModel<M> {
500
+ public isInstance(): this is DeployedInstanceModel<A> {
476
501
  return false
477
502
  }
478
503
  }
479
504
 
480
- export type DeploymentRelationEndpoint<M extends AnyAux> =
481
- | DeploymentElementModel<M>
482
- | NestedElementOfDeployedInstanceModel<M>
505
+ export type DeploymentRelationEndpoint<A extends Any = Any> =
506
+ | DeploymentElementModel<A>
507
+ | NestedElementOfDeployedInstanceModel<A>
483
508
 
484
- export class DeploymentRelationModel<M extends AnyAux = AnyAux> {
485
- public boundary: DeploymentNodeModel<M> | null
486
- public source: DeploymentRelationEndpoint<M>
487
- public target: DeploymentRelationEndpoint<M>
509
+ export class DeploymentRelationModel<A extends Any = Any> implements AnyRelationshipModel<A> {
510
+ public boundary: DeploymentNodeModel<A> | null
511
+ public source: DeploymentRelationEndpoint<A>
512
+ public target: DeploymentRelationEndpoint<A>
488
513
 
489
514
  constructor(
490
- public readonly $model: LikeC4DeploymentModel<M>,
491
- public readonly $relationship: DeploymentRelation,
515
+ public readonly $model: LikeC4DeploymentModel<A>,
516
+ public readonly $relationship: DeploymentRelationship<A>,
492
517
  ) {
493
518
  this.source = $model.deploymentRef($relationship.source)
494
519
  this.target = $model.deploymentRef($relationship.target)
495
520
  const parent = commonAncestor(this.source.id, this.target.id)
496
521
  this.boundary = parent ? this.$model.node(parent) : null
497
522
  }
498
- get id(): M['RelationId'] {
523
+ get id(): scalar.RelationId {
499
524
  return this.$relationship.id
500
525
  }
501
526
 
@@ -504,35 +529,35 @@ export class DeploymentRelationModel<M extends AnyAux = AnyAux> {
504
529
  }
505
530
 
506
531
  get title(): string | null {
507
- if (isEmpty(this.$relationship.title)) {
532
+ if (!isTruthy(this.$relationship.title)) {
508
533
  return null
509
534
  }
510
535
  return this.$relationship.title
511
536
  }
512
537
 
513
538
  get technology(): string | null {
514
- if (isEmpty(this.$relationship.technology)) {
539
+ if (!isTruthy(this.$relationship.technology)) {
515
540
  return null
516
541
  }
517
542
  return this.$relationship.technology
518
543
  }
519
544
 
520
545
  get description(): string | null {
521
- if (isEmpty(this.$relationship.description)) {
546
+ if (!isTruthy(this.$relationship.description)) {
522
547
  return null
523
548
  }
524
549
  return this.$relationship.description
525
550
  }
526
551
 
527
- get tags(): ReadonlyArray<Tag> {
552
+ get tags(): aux.Tags<A> {
528
553
  return this.$relationship.tags ?? []
529
554
  }
530
555
 
531
- get kind(): RelationshipKind | null {
556
+ get kind(): aux.RelationKind<A> | null {
532
557
  return this.$relationship.kind ?? null
533
558
  }
534
559
 
535
- get navigateTo(): LikeC4ViewModel<M> | null {
560
+ get navigateTo(): LikeC4ViewModel<A> | null {
536
561
  return this.$relationship.navigateTo ? this.$model.$model.view(this.$relationship.navigateTo) : null
537
562
  }
538
563
 
@@ -541,14 +566,14 @@ export class DeploymentRelationModel<M extends AnyAux = AnyAux> {
541
566
  }
542
567
 
543
568
  get color(): Color {
544
- return this.$relationship.color ?? DefaultRelationshipColor
569
+ return this.$relationship.color ?? DefaultThemeColor
545
570
  }
546
571
 
547
572
  get line(): RelationshipLineType {
548
573
  return this.$relationship.line ?? DefaultLineStyle
549
574
  }
550
575
 
551
- public *views(): IteratorLike<LikeC4ViewModel<M, ComputedDeploymentView>> {
576
+ public *views(): IteratorLike<LikeC4ViewModel.DeploymentView<A>> {
552
577
  for (const view of this.$model.views()) {
553
578
  if (view.includesRelation(this.id)) {
554
579
  yield view
@@ -557,19 +582,39 @@ export class DeploymentRelationModel<M extends AnyAux = AnyAux> {
557
582
  return
558
583
  }
559
584
 
560
- public isDeploymentRelation(): this is DeploymentRelationModel<M> {
585
+ public isDeploymentRelation(): this is DeploymentRelationModel<A> {
561
586
  return true
562
587
  }
588
+
589
+ public isModelRelation(): this is RelationshipModel<A> {
590
+ return false
591
+ }
592
+
593
+ public getMetadata(): aux.Metadata<A>
594
+ public getMetadata(field: aux.MetadataKey<A>): string | undefined
595
+ public getMetadata(field?: aux.MetadataKey<A>) {
596
+ if (field) {
597
+ return this.$relationship.metadata?.[field]
598
+ }
599
+ return this.$relationship.metadata ?? {}
600
+ }
601
+
602
+ /**
603
+ * Checks if the relationship has the given tag.
604
+ */
605
+ public isTagged(tag: aux.LooseTag<A>): boolean {
606
+ return this.tags.includes(tag as aux.Tag<A>)
607
+ }
563
608
  }
564
609
 
565
- export class RelationshipsAccum<M extends AnyAux> {
566
- static empty<M extends AnyAux>(): RelationshipsAccum<M> {
610
+ export class RelationshipsAccum<A extends Any = Any> {
611
+ static empty<A extends Any>(): RelationshipsAccum<A> {
567
612
  return new RelationshipsAccum()
568
613
  }
569
- static from<M extends AnyAux>(
570
- model: Iterable<RelationshipModel<M>> | undefined,
571
- deployment?: Iterable<DeploymentRelationModel<M>>,
572
- ): RelationshipsAccum<M> {
614
+ static from<A extends Any>(
615
+ model: Iterable<RelationshipModel<A>> | undefined,
616
+ deployment?: Iterable<DeploymentRelationModel<A>>,
617
+ ): RelationshipsAccum<A> {
573
618
  return new RelationshipsAccum(
574
619
  new Set(model),
575
620
  new Set(deployment),
@@ -580,8 +625,8 @@ export class RelationshipsAccum<M extends AnyAux> {
580
625
  * @param deployment relationships from deployment model
581
626
  */
582
627
  constructor(
583
- public readonly model: ReadonlySet<RelationshipModel<M>> = new Set(),
584
- public readonly deployment: ReadonlySet<DeploymentRelationModel<M>> = new Set(),
628
+ public readonly model: ReadonlySet<RelationshipModel<A>> = new Set(),
629
+ public readonly deployment: ReadonlySet<DeploymentRelationModel<A>> = new Set(),
585
630
  ) {
586
631
  }
587
632
 
@@ -600,7 +645,7 @@ export class RelationshipsAccum<M extends AnyAux> {
600
645
  /**
601
646
  * Returns new Accum containing all the elements which are both in this and otherAccum
602
647
  */
603
- public intersect(otherAccum: RelationshipsAccum<M>): RelationshipsAccum<M> {
648
+ public intersect(otherAccum: RelationshipsAccum<A>): RelationshipsAccum<A> {
604
649
  return RelationshipsAccum.from(
605
650
  intersection(this.model, otherAccum.model),
606
651
  intersection(this.deployment, otherAccum.deployment),
@@ -610,7 +655,7 @@ export class RelationshipsAccum<M extends AnyAux> {
610
655
  /**
611
656
  * Returns new Accum containing all the elements which are both in this and otherAccum
612
657
  */
613
- public difference(otherAccum: RelationshipsAccum<M>): RelationshipsAccum<M> {
658
+ public difference(otherAccum: RelationshipsAccum<A>): RelationshipsAccum<A> {
614
659
  return RelationshipsAccum.from(
615
660
  difference(this.model, otherAccum.model),
616
661
  difference(this.deployment, otherAccum.deployment),
@@ -620,7 +665,7 @@ export class RelationshipsAccum<M extends AnyAux> {
620
665
  /**
621
666
  * Returns new Accum containing all the elements from both
622
667
  */
623
- public union(otherAccum: RelationshipsAccum<M>): RelationshipsAccum<M> {
668
+ public union(otherAccum: RelationshipsAccum<A>): RelationshipsAccum<A> {
624
669
  return RelationshipsAccum.from(
625
670
  union(this.model, otherAccum.model),
626
671
  union(this.deployment, otherAccum.deployment),