@likec4/core 1.31.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 +9 -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.Bq753SYD.mjs → core.CBpKAlhj.mjs} +2012 -4422
  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 +15 -7
  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 +171 -144
  109. package/src/model/DeploymentModel.ts +88 -65
  110. package/src/model/ElementModel.ts +85 -74
  111. package/src/model/LikeC4Model.ts +430 -241
  112. package/src/model/RelationModel.ts +63 -29
  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.CQDU11hR.d.mts +0 -753
  169. package/dist/shared/core.DJvmfnEi.d.mts +0 -1153
  170. package/dist/shared/core.DgfwjBtu.mjs +0 -495
  171. package/dist/shared/core.Dx7siloV.d.mts +0 -146
  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,85 +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>
195
-
196
- protected cachedOutgoing: RelationshipsAccum<M> | null = null
197
- protected cachedIncoming: RelationshipsAccum<M> | null = null
183
+ public abstract outgoingModelRelationships(): RelationshipsIterator<A>
184
+ public abstract incomingModelRelationships(): RelationshipsIterator<A>
198
185
 
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
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
+ ))
205
192
  }
206
193
 
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
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
+ ))
213
200
  }
214
201
 
215
- public getMetadata(): Record<string, string>
216
- public getMetadata(field: string): string | undefined
217
- public getMetadata(field?: string) {
202
+ public getMetadata(): aux.Metadata<A>
203
+ public getMetadata(field: aux.MetadataKey<A>): string | undefined
204
+ public getMetadata(field?: aux.MetadataKey<A>) {
218
205
  if (field) {
219
206
  return this.$node.metadata?.[field]
220
207
  }
221
208
  return this.$node.metadata ?? {}
222
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>)
216
+ }
223
217
  }
224
218
 
225
- export class DeploymentNodeModel<M extends AnyAux = AnyAux> extends AbstractDeploymentElementModel<M> {
226
- 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>
227
222
  override title: string
228
223
  override hierarchyLevel: number
229
224
 
230
225
  constructor(
231
- public readonly $model: LikeC4DeploymentModel<M>,
232
- public readonly $node: DeploymentNode,
226
+ public readonly $model: LikeC4DeploymentModel<A>,
227
+ public readonly $node: DeploymentNode<A>,
233
228
  ) {
234
229
  super()
235
230
  this.id = $node.id
231
+ this._literalId = $node.id
236
232
  this.title = $node.title
237
233
  this.hierarchyLevel = hierarchyLevel($node.id)
238
234
  }
239
235
 
240
- get parent(): DeploymentNodeModel<M> | null {
236
+ get parent(): DeploymentNodeModel<A> | null {
241
237
  return this.$model.parent(this)
242
238
  }
243
239
 
244
- override get kind(): DeploymentNodeKind {
240
+ get kind(): aux.DeploymentKind<A> {
245
241
  return this.$node.kind
246
242
  }
247
243
 
248
- 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>> {
249
254
  return this.$model.children(this)
250
255
  }
251
256
 
252
- public descendants(sort: 'asc' | 'desc' = 'desc'): DeploymentElementsIterator<M> {
257
+ public descendants(sort: 'asc' | 'desc' = 'desc'): DeploymentElementsIterator<A> {
253
258
  return this.$model.descendants(this, sort)
254
259
  }
255
260
 
256
- public override isDeploymentNode(): this is DeploymentNodeModel<M> {
261
+ public override isDeploymentNode(): this is DeploymentNodeModel<A> {
257
262
  return true
258
263
  }
259
264
 
260
265
  /**
261
266
  * Iterate over all instances nested in this deployment node.
262
267
  */
263
- public *instances(): DeployedInstancesIterator<M> {
268
+ public *instances(): DeployedInstancesIterator<A> {
264
269
  for (const nested of this.descendants('desc')) {
265
270
  if (nested.isInstance()) {
266
271
  yield nested
@@ -273,7 +278,7 @@ export class DeploymentNodeModel<M extends AnyAux = AnyAux> extends AbstractDepl
273
278
  * Returns deployed instance inside this deployment node
274
279
  * if only there are no more instances
275
280
  */
276
- public onlyOneInstance(): DeployedInstanceModel<M> | null {
281
+ public onlyOneInstance(): DeployedInstanceModel<A> | null {
277
282
  const children = this.children()
278
283
  if (children.size !== 1) {
279
284
  return null
@@ -286,8 +291,8 @@ export class DeploymentNodeModel<M extends AnyAux = AnyAux> extends AbstractDepl
286
291
  * Cached result of relationships from instances
287
292
  */
288
293
  private _relationshipsFromInstances: {
289
- outgoing: ReadonlySet<RelationshipModel<M>>
290
- incoming: ReadonlySet<RelationshipModel<M>>
294
+ outgoing: ReadonlySet<RelationshipModel<A>>
295
+ incoming: ReadonlySet<RelationshipModel<A>>
291
296
  } | null = null
292
297
 
293
298
  private relationshipsFromInstances() {
@@ -298,8 +303,8 @@ export class DeploymentNodeModel<M extends AnyAux = AnyAux> extends AbstractDepl
298
303
  outgoing,
299
304
  incoming,
300
305
  } = (this._relationshipsFromInstances = {
301
- outgoing: new Set<RelationshipModel<M>>(),
302
- incoming: new Set<RelationshipModel<M>>(),
306
+ outgoing: new Set<RelationshipModel<A>>(),
307
+ incoming: new Set<RelationshipModel<A>>(),
303
308
  })
304
309
  for (const instance of this.instances()) {
305
310
  for (const r of instance.element.outgoing()) {
@@ -315,21 +320,21 @@ export class DeploymentNodeModel<M extends AnyAux = AnyAux> extends AbstractDepl
315
320
  /**
316
321
  * We return only relationships that are not already present in nested instances
317
322
  */
318
- public override outgoingModelRelationships(): RelationshipsIterator<M> {
323
+ public override outgoingModelRelationships(): RelationshipsIterator<A> {
319
324
  return this.relationshipsFromInstances().outgoing.values()
320
325
  }
321
326
 
322
327
  /**
323
328
  * We return only relationships that are not already present in nested instances
324
329
  */
325
- public override incomingModelRelationships(): RelationshipsIterator<M> {
330
+ public override incomingModelRelationships(): RelationshipsIterator<A> {
326
331
  return this.relationshipsFromInstances().incoming.values()
327
332
  }
328
333
 
329
334
  /**
330
335
  * Returns an iterator of relationships between nested instances
331
336
  */
332
- public internalModelRelationships(): ReadonlySet<RelationshipModel<M>> {
337
+ public internalModelRelationships(): ReadonlySet<RelationshipModel<A>> {
333
338
  const {
334
339
  outgoing,
335
340
  incoming,
@@ -338,27 +343,29 @@ export class DeploymentNodeModel<M extends AnyAux = AnyAux> extends AbstractDepl
338
343
  }
339
344
  }
340
345
 
341
- export class DeployedInstanceModel<M extends AnyAux = AnyAux> extends AbstractDeploymentElementModel<M> {
342
- 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>
343
349
  override readonly title: string
344
350
  override readonly hierarchyLevel: number
345
351
 
346
352
  constructor(
347
- public readonly $model: LikeC4DeploymentModel<M>,
348
- public readonly $instance: DeployedInstance,
349
- public readonly element: ElementModel<M>,
353
+ public readonly $model: LikeC4DeploymentModel<A>,
354
+ public readonly $instance: DeployedInstance<A>,
355
+ public readonly element: ElementModel<A>,
350
356
  ) {
351
357
  super()
352
358
  this.id = $instance.id
359
+ this._literalId = $instance.id
353
360
  this.title = $instance.title ?? element.title
354
361
  this.hierarchyLevel = hierarchyLevel($instance.id)
355
362
  }
356
363
 
357
- get $node(): DeployedInstance {
364
+ get $node(): DeployedInstance<A> {
358
365
  return this.$instance
359
366
  }
360
367
 
361
- get parent(): DeploymentNodeModel<M> {
368
+ get parent(): DeploymentNodeModel<A> {
362
369
  return nonNullable(this.$model.parent(this), `Parent of ${this.id} not found`)
363
370
  }
364
371
 
@@ -378,15 +385,20 @@ export class DeployedInstanceModel<M extends AnyAux = AnyAux> extends AbstractDe
378
385
  return this.$instance.style?.shape ?? this.element.shape
379
386
  }
380
387
 
381
- override get color(): ThemeColor {
382
- 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
383
390
  }
384
391
 
385
- override get tags(): ReadonlyArray<C4Tag> {
386
- 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
+ })
387
399
  }
388
400
 
389
- override get kind(): ElementKind {
401
+ get kind(): aux.ElementKind<A> {
390
402
  return this.element.kind
391
403
  }
392
404
 
@@ -402,14 +414,14 @@ export class DeployedInstanceModel<M extends AnyAux = AnyAux> extends AbstractDe
402
414
  return this.$instance.links ?? this.element.links
403
415
  }
404
416
 
405
- public override isInstance(): this is DeployedInstanceModel<M> {
417
+ public override isInstance(): this is DeployedInstanceModel<A> {
406
418
  return true
407
419
  }
408
420
 
409
- public override outgoingModelRelationships(): RelationshipsIterator<M> {
421
+ public override outgoingModelRelationships(): RelationshipsIterator<A> {
410
422
  return this.element.outgoing()
411
423
  }
412
- public override incomingModelRelationships(): RelationshipsIterator<M> {
424
+ public override incomingModelRelationships(): RelationshipsIterator<A> {
413
425
  return this.element.incoming()
414
426
  }
415
427
 
@@ -417,9 +429,9 @@ export class DeployedInstanceModel<M extends AnyAux = AnyAux> extends AbstractDe
417
429
  * Iterate over all views that include this instance.
418
430
  * (Some views may include the parent deployment node instead of the instance.)
419
431
  */
420
- public override *views(): IteratorLike<LikeC4ViewModel<M, ComputedDeploymentView>> {
432
+ public override *views(): IteratorLike<LikeC4ViewModel.DeploymentView<A>> {
421
433
  for (const view of this.$model.views()) {
422
- if (!view.isDeploymentView()) {
434
+ if (view._type !== 'deployment') {
423
435
  continue
424
436
  }
425
437
  if (view.includesDeployment(this.id)) {
@@ -437,14 +449,18 @@ export class DeployedInstanceModel<M extends AnyAux = AnyAux> extends AbstractDe
437
449
  }
438
450
  }
439
451
 
440
- export class NestedElementOfDeployedInstanceModel<M extends AnyAux> {
452
+ export class NestedElementOfDeployedInstanceModel<A extends Any = Any> {
441
453
  constructor(
442
- public readonly instance: DeployedInstanceModel<M>,
443
- public readonly element: ElementModel<M>,
454
+ public readonly instance: DeployedInstanceModel<A>,
455
+ public readonly element: ElementModel<A>,
444
456
  ) {
445
457
  }
446
458
 
447
- get id(): M['DeploymentFqn'] {
459
+ get id(): aux.DeploymentFqn<A> {
460
+ return this.instance.id
461
+ }
462
+
463
+ get _literalId(): aux.DeploymentId<A> {
448
464
  return this.instance.id
449
465
  }
450
466
 
@@ -462,7 +478,7 @@ export class NestedElementOfDeployedInstanceModel<M extends AnyAux> {
462
478
  return this.element.shape
463
479
  }
464
480
 
465
- get color(): ThemeColor {
481
+ get color(): Color {
466
482
  return this.element.color
467
483
  }
468
484
 
@@ -478,33 +494,33 @@ export class NestedElementOfDeployedInstanceModel<M extends AnyAux> {
478
494
  return this.element.technology
479
495
  }
480
496
 
481
- public isDeploymentNode(): this is DeploymentNodeModel<M> {
497
+ public isDeploymentNode(): this is DeploymentNodeModel<A> {
482
498
  return false
483
499
  }
484
- public isInstance(): this is DeployedInstanceModel<M> {
500
+ public isInstance(): this is DeployedInstanceModel<A> {
485
501
  return false
486
502
  }
487
503
  }
488
504
 
489
- export type DeploymentRelationEndpoint<M extends AnyAux> =
490
- | DeploymentElementModel<M>
491
- | NestedElementOfDeployedInstanceModel<M>
505
+ export type DeploymentRelationEndpoint<A extends Any = Any> =
506
+ | DeploymentElementModel<A>
507
+ | NestedElementOfDeployedInstanceModel<A>
492
508
 
493
- export class DeploymentRelationModel<M extends AnyAux = AnyAux> {
494
- public boundary: DeploymentNodeModel<M> | null
495
- public source: DeploymentRelationEndpoint<M>
496
- 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>
497
513
 
498
514
  constructor(
499
- public readonly $model: LikeC4DeploymentModel<M>,
500
- public readonly $relationship: DeploymentRelation,
515
+ public readonly $model: LikeC4DeploymentModel<A>,
516
+ public readonly $relationship: DeploymentRelationship<A>,
501
517
  ) {
502
518
  this.source = $model.deploymentRef($relationship.source)
503
519
  this.target = $model.deploymentRef($relationship.target)
504
520
  const parent = commonAncestor(this.source.id, this.target.id)
505
521
  this.boundary = parent ? this.$model.node(parent) : null
506
522
  }
507
- get id(): M['RelationId'] {
523
+ get id(): scalar.RelationId {
508
524
  return this.$relationship.id
509
525
  }
510
526
 
@@ -513,35 +529,35 @@ export class DeploymentRelationModel<M extends AnyAux = AnyAux> {
513
529
  }
514
530
 
515
531
  get title(): string | null {
516
- if (isEmpty(this.$relationship.title)) {
532
+ if (!isTruthy(this.$relationship.title)) {
517
533
  return null
518
534
  }
519
535
  return this.$relationship.title
520
536
  }
521
537
 
522
538
  get technology(): string | null {
523
- if (isEmpty(this.$relationship.technology)) {
539
+ if (!isTruthy(this.$relationship.technology)) {
524
540
  return null
525
541
  }
526
542
  return this.$relationship.technology
527
543
  }
528
544
 
529
545
  get description(): string | null {
530
- if (isEmpty(this.$relationship.description)) {
546
+ if (!isTruthy(this.$relationship.description)) {
531
547
  return null
532
548
  }
533
549
  return this.$relationship.description
534
550
  }
535
551
 
536
- get tags(): ReadonlyArray<Tag> {
552
+ get tags(): aux.Tags<A> {
537
553
  return this.$relationship.tags ?? []
538
554
  }
539
555
 
540
- get kind(): RelationshipKind | null {
556
+ get kind(): aux.RelationKind<A> | null {
541
557
  return this.$relationship.kind ?? null
542
558
  }
543
559
 
544
- get navigateTo(): LikeC4ViewModel<M> | null {
560
+ get navigateTo(): LikeC4ViewModel<A> | null {
545
561
  return this.$relationship.navigateTo ? this.$model.$model.view(this.$relationship.navigateTo) : null
546
562
  }
547
563
 
@@ -550,14 +566,14 @@ export class DeploymentRelationModel<M extends AnyAux = AnyAux> {
550
566
  }
551
567
 
552
568
  get color(): Color {
553
- return this.$relationship.color ?? DefaultRelationshipColor
569
+ return this.$relationship.color ?? DefaultThemeColor
554
570
  }
555
571
 
556
572
  get line(): RelationshipLineType {
557
573
  return this.$relationship.line ?? DefaultLineStyle
558
574
  }
559
575
 
560
- public *views(): IteratorLike<LikeC4ViewModel<M, ComputedDeploymentView>> {
576
+ public *views(): IteratorLike<LikeC4ViewModel.DeploymentView<A>> {
561
577
  for (const view of this.$model.views()) {
562
578
  if (view.includesRelation(this.id)) {
563
579
  yield view
@@ -566,28 +582,39 @@ export class DeploymentRelationModel<M extends AnyAux = AnyAux> {
566
582
  return
567
583
  }
568
584
 
569
- public isDeploymentRelation(): this is DeploymentRelationModel<M> {
585
+ public isDeploymentRelation(): this is DeploymentRelationModel<A> {
570
586
  return true
571
587
  }
572
588
 
573
- public getMetadata(): Record<string, string>
574
- public getMetadata(field: string): string | undefined
575
- public getMetadata(field?: string) {
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>) {
576
596
  if (field) {
577
597
  return this.$relationship.metadata?.[field]
578
598
  }
579
599
  return this.$relationship.metadata ?? {}
580
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
+ }
581
608
  }
582
609
 
583
- export class RelationshipsAccum<M extends AnyAux> {
584
- static empty<M extends AnyAux>(): RelationshipsAccum<M> {
610
+ export class RelationshipsAccum<A extends Any = Any> {
611
+ static empty<A extends Any>(): RelationshipsAccum<A> {
585
612
  return new RelationshipsAccum()
586
613
  }
587
- static from<M extends AnyAux>(
588
- model: Iterable<RelationshipModel<M>> | undefined,
589
- deployment?: Iterable<DeploymentRelationModel<M>>,
590
- ): RelationshipsAccum<M> {
614
+ static from<A extends Any>(
615
+ model: Iterable<RelationshipModel<A>> | undefined,
616
+ deployment?: Iterable<DeploymentRelationModel<A>>,
617
+ ): RelationshipsAccum<A> {
591
618
  return new RelationshipsAccum(
592
619
  new Set(model),
593
620
  new Set(deployment),
@@ -598,8 +625,8 @@ export class RelationshipsAccum<M extends AnyAux> {
598
625
  * @param deployment relationships from deployment model
599
626
  */
600
627
  constructor(
601
- public readonly model: ReadonlySet<RelationshipModel<M>> = new Set(),
602
- 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(),
603
630
  ) {
604
631
  }
605
632
 
@@ -618,7 +645,7 @@ export class RelationshipsAccum<M extends AnyAux> {
618
645
  /**
619
646
  * Returns new Accum containing all the elements which are both in this and otherAccum
620
647
  */
621
- public intersect(otherAccum: RelationshipsAccum<M>): RelationshipsAccum<M> {
648
+ public intersect(otherAccum: RelationshipsAccum<A>): RelationshipsAccum<A> {
622
649
  return RelationshipsAccum.from(
623
650
  intersection(this.model, otherAccum.model),
624
651
  intersection(this.deployment, otherAccum.deployment),
@@ -628,7 +655,7 @@ export class RelationshipsAccum<M extends AnyAux> {
628
655
  /**
629
656
  * Returns new Accum containing all the elements which are both in this and otherAccum
630
657
  */
631
- public difference(otherAccum: RelationshipsAccum<M>): RelationshipsAccum<M> {
658
+ public difference(otherAccum: RelationshipsAccum<A>): RelationshipsAccum<A> {
632
659
  return RelationshipsAccum.from(
633
660
  difference(this.model, otherAccum.model),
634
661
  difference(this.deployment, otherAccum.deployment),
@@ -638,7 +665,7 @@ export class RelationshipsAccum<M extends AnyAux> {
638
665
  /**
639
666
  * Returns new Accum containing all the elements from both
640
667
  */
641
- public union(otherAccum: RelationshipsAccum<M>): RelationshipsAccum<M> {
668
+ public union(otherAccum: RelationshipsAccum<A>): RelationshipsAccum<A> {
642
669
  return RelationshipsAccum.from(
643
670
  union(this.model, otherAccum.model),
644
671
  union(this.deployment, otherAccum.deployment),