@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,237 @@
1
+ import { filter, flatMap, isNonNullish, map, pipe } from 'remeda'
2
+ import { invariant } from '../../../errors'
3
+ import type { LikeC4DeploymentModel } from '../../../model'
4
+ import type { DeploymentConnectionModel } from '../../../model/connection/deployment'
5
+ import { findConnection, findConnectionsBetween, findConnectionsWithin } from '../../../model/connection/deployment'
6
+ import { findConnectionsBetween as findModelConnectionsBetween } from '../../../model/connection/model'
7
+ import type { ConnectionModel } from '../../../model/connection/model/ConnectionModel'
8
+ import type { DeploymentElementModel } from '../../../model/DeploymentElementModel'
9
+ import type { RelationshipModel } from '../../../model/RelationModel'
10
+ import type { AnyAux } from '../../../model/types'
11
+ import { type RelationExpr, FqnExpr } from '../../../types'
12
+ import { hasIntersection, intersection } from '../../../utils/set'
13
+ import type { ExcludePredicateCtx, PredicateExecutor } from '../_types'
14
+ import type { StageExclude } from '../memory'
15
+ import { deploymentExpressionToPredicate, resolveElements, resolveModelElements } from '../utils'
16
+ import { filterIncomingConnections, resolveAllImcomingRelations } from './relation-incoming'
17
+ import { filterOutgoingConnections, resolveAllOutgoingRelations } from './relation-outgoing'
18
+
19
+ // const isRef = DeploymentElementExpression.isRef
20
+
21
+ export const resolveAscendingSiblings = (element: DeploymentElementModel) => {
22
+ const siblings = new Set<DeploymentElementModel>()
23
+ for (let sibling of element.descendingSiblings()) {
24
+ // TODO: investigate if this is necessary
25
+ // if (element.isInstance() && sibling.isDeploymentNode()) {
26
+ // // we flatten nodes that contain only one instance
27
+ // sibling = sibling.onlyOneInstance() ?? sibling
28
+ // }
29
+ siblings.add(sibling)
30
+ }
31
+ return siblings
32
+ }
33
+
34
+ const resolveWildcard = (model: LikeC4DeploymentModel, nonWildcard: FqnExpr.DeploymentRef) => {
35
+ const sources = resolveElements(model, nonWildcard)
36
+ return sources.map(source => {
37
+ const targets = resolveAscendingSiblings(source)
38
+ return [source, targets] as const
39
+ })
40
+ }
41
+
42
+ export const DirectRelationPredicate: PredicateExecutor<RelationExpr.Direct> = {
43
+ include: ({ expr: { source, target, isBidirectional = false }, model, stage }) => {
44
+ invariant(!FqnExpr.isModelRef(source), 'Invalid source model ref in direct relation')
45
+ invariant(!FqnExpr.isModelRef(target), 'Invalid target model ref in direct relation')
46
+ const sourceIsWildcard = FqnExpr.isWildcard(source)
47
+ const targetIsWildcard = FqnExpr.isWildcard(target)
48
+
49
+ const dir = isBidirectional ? 'both' : 'directed'
50
+
51
+ let connections
52
+
53
+ switch (true) {
54
+ // * -> *
55
+ case sourceIsWildcard && targetIsWildcard: {
56
+ connections = findConnectionsWithin(model.instances()).map(c => {
57
+ stage.addImplicit(c.boundary)
58
+ return c
59
+ })
60
+ break
61
+ }
62
+
63
+ // source -> *; source <-> *
64
+ case !sourceIsWildcard && targetIsWildcard: {
65
+ const sources = resolveElements(model, source)
66
+ const isSource = filterOutgoingConnections(sources)
67
+
68
+ let postFilter = isSource
69
+ if (isBidirectional) {
70
+ const isTarget = filterIncomingConnections(sources)
71
+ postFilter = c => isSource(c) !== isTarget(c)
72
+ }
73
+
74
+ connections = sources
75
+ .flatMap(source => {
76
+ const targets = resolveAscendingSiblings(source)
77
+ return findConnectionsBetween(source, targets, dir)
78
+ })
79
+ .filter(postFilter)
80
+ break
81
+ }
82
+ // * -> target; * <-> target
83
+ case sourceIsWildcard && !targetIsWildcard: {
84
+ const targets = resolveElements(model, target)
85
+ const isTarget = filterIncomingConnections(targets)
86
+
87
+ let postFilter = isTarget
88
+ if (isBidirectional) {
89
+ const isSource = filterOutgoingConnections(targets)
90
+ postFilter = c => isSource(c) !== isTarget(c)
91
+ }
92
+
93
+ connections = targets
94
+ .flatMap(target => {
95
+ const sources = resolveAscendingSiblings(target)
96
+ return [...sources].flatMap(source => findConnection(source, target, dir))
97
+ })
98
+ .filter(postFilter)
99
+ break
100
+ }
101
+ default: {
102
+ invariant(!sourceIsWildcard, 'Inferrence failed - source should be a deployment ref')
103
+ invariant(!targetIsWildcard, 'Inferrence failed - target should be a deployment ref')
104
+ const sources = resolveElements(model, source)
105
+ const targets = resolveElements(model, target)
106
+
107
+ const isSource = filterOutgoingConnections(sources)
108
+ const isTarget = filterIncomingConnections(targets)
109
+
110
+ connections = pipe(
111
+ sources,
112
+ flatMap(s => findConnectionsBetween(s, targets, dir)),
113
+ filter(c => isSource(c) && isTarget(c)),
114
+ )
115
+ }
116
+ }
117
+
118
+ stage.addConnections(connections)
119
+
120
+ if (FqnExpr.isDeploymentRef(source) && isNonNullish(source.selector)) {
121
+ stage.addImplicit(model.element(source.ref.deployment))
122
+ }
123
+ if (FqnExpr.isDeploymentRef(target) && isNonNullish(target.selector)) {
124
+ stage.addImplicit(model.element(target.ref.deployment))
125
+ }
126
+
127
+ return stage
128
+ },
129
+ exclude: ({ expr, model, memory, stage }) => {
130
+ // * -> *
131
+ // Exclude all connections
132
+ if (
133
+ FqnExpr.isWildcard(expr.source)
134
+ && FqnExpr.isWildcard(expr.target)
135
+ ) {
136
+ stage.excludeConnections(memory.connections)
137
+ return stage
138
+ }
139
+
140
+ if (FqnExpr.isModelRef(expr.source) && FqnExpr.isModelRef(expr.target)) {
141
+ const toExclude = resolveRelationsBetweenModelElements({
142
+ source: expr.source,
143
+ target: expr.target,
144
+ expr,
145
+ model,
146
+ })
147
+ return excludeModelRelations(toExclude, { stage, memory })
148
+ }
149
+
150
+ if (FqnExpr.isModelRef(expr.source)) {
151
+ if (FqnExpr.isWildcard(expr.target)) {
152
+ const toExclude = resolveAllOutgoingRelations(model, expr.source)
153
+ return excludeModelRelations(toExclude, { stage, memory })
154
+ }
155
+ const allOutgoing = resolveAllOutgoingRelations(model, expr.source)
156
+ const isTarget = deploymentExpressionToPredicate(expr.target)
157
+ return excludeModelRelations(
158
+ allOutgoing,
159
+ { stage, memory },
160
+ c => isTarget(c.target),
161
+ )
162
+ }
163
+
164
+ if (FqnExpr.isModelRef(expr.target)) {
165
+ const toExclude = resolveAllImcomingRelations(model, expr.target)
166
+ const isSource = deploymentExpressionToPredicate(expr.source)
167
+ return excludeModelRelations(
168
+ toExclude,
169
+ { stage, memory },
170
+ c => isSource(c.source),
171
+ )
172
+ }
173
+
174
+ const isSource = deploymentExpressionToPredicate(expr.source)
175
+ const isTarget = deploymentExpressionToPredicate(expr.target)
176
+
177
+ const satisfies = (connection: DeploymentConnectionModel) => {
178
+ return (isSource(connection.source) && isTarget(connection.target))
179
+ || (expr.isBidirectional && isSource(connection.target) && isTarget(connection.source))
180
+ }
181
+
182
+ const toExclude = memory.connections.filter(satisfies)
183
+
184
+ stage.excludeConnections(toExclude)
185
+ return stage
186
+ },
187
+ }
188
+
189
+ export function excludeModelRelations(
190
+ relationsToExclude: ReadonlySet<RelationshipModel<AnyAux>>,
191
+ { stage, memory }: Pick<ExcludePredicateCtx, 'stage' | 'memory'>,
192
+ // Optional filter to scope the connections to exclude
193
+ filterConnections: (c: DeploymentConnectionModel) => boolean = () => true,
194
+ ): StageExclude {
195
+ if (relationsToExclude.size === 0) {
196
+ return stage
197
+ }
198
+ const toExclude = pipe(
199
+ memory.connections,
200
+ // Find connections that have at least one relation in common with the excluded relations
201
+ filter(c => filterConnections(c) && hasIntersection(c.relations.model, relationsToExclude)),
202
+ map(c =>
203
+ c.update({
204
+ deployment: null,
205
+ model: intersection(c.relations.model, relationsToExclude),
206
+ })
207
+ ),
208
+ )
209
+ if (toExclude.length === 0) {
210
+ return stage
211
+ }
212
+ return stage.excludeConnections(toExclude)
213
+ }
214
+
215
+ function resolveRelationsBetweenModelElements({
216
+ source,
217
+ target,
218
+ expr,
219
+ model,
220
+ }: {
221
+ source: FqnExpr.ModelRef
222
+ target: FqnExpr.ModelRef
223
+ expr: RelationExpr.Direct
224
+ model: LikeC4DeploymentModel
225
+ }) {
226
+ const sources = resolveModelElements(model, source)
227
+ const targets = resolveModelElements(model, target)
228
+
229
+ const dir = expr.isBidirectional ? 'both' : 'directed'
230
+
231
+ const modelConnections = [] as ConnectionModel[]
232
+ for (const source of sources) {
233
+ modelConnections.push(...findModelConnectionsBetween(source, targets, dir))
234
+ }
235
+
236
+ return new Set(modelConnections.flatMap(c => [...c.relations]))
237
+ }
@@ -0,0 +1,61 @@
1
+ import { invariant } from '../../../errors'
2
+ import { findConnectionsBetween } from '../../../model/connection/deployment'
3
+ import type { RelationshipModel } from '../../../model/RelationModel'
4
+ import type { AnyAux } from '../../../model/types'
5
+ import { FqnExpr, type RelationExpr } from '../../../types/expression-v2'
6
+ import { union } from '../../../utils/set'
7
+ import type { PredicateExecutor } from '../_types'
8
+ import { resolveElements, resolveModelElements } from '../utils'
9
+ import { excludeModelRelations, resolveAscendingSiblings } from './relation-direct'
10
+ import { filterIncomingConnections } from './relation-incoming'
11
+ import { filterOutgoingConnections } from './relation-outgoing'
12
+
13
+ //
14
+ export const InOutRelationPredicate: PredicateExecutor<RelationExpr.InOut> = {
15
+ include: ({ expr, model, memory, stage }) => {
16
+ const sources = [...memory.elements]
17
+
18
+ if (FqnExpr.isWildcard(expr.inout)) {
19
+ for (const source of sources) {
20
+ const targets = [...resolveAscendingSiblings(source)]
21
+ stage.addConnections(findConnectionsBetween(source, targets, 'both'))
22
+ }
23
+ return stage
24
+ }
25
+ invariant(FqnExpr.isDeploymentRef(expr.inout), 'Only deployment refs are supported in include')
26
+
27
+ const targets = resolveElements(model, expr.inout)
28
+ for (const source of sources) {
29
+ stage.addConnections(findConnectionsBetween(source, targets, 'both'))
30
+ }
31
+
32
+ return stage
33
+ },
34
+ exclude: ({ expr, model, memory, stage }) => {
35
+ // Exclude all connections that have model relationshps with the elements
36
+ if (FqnExpr.isModelRef(expr.inout)) {
37
+ const elements = resolveModelElements(model, expr.inout)
38
+ if (elements.length === 0) {
39
+ return stage
40
+ }
41
+ const excludedRelations = union(
42
+ new Set<RelationshipModel<AnyAux>>(),
43
+ ...elements.flatMap(e => [e.allIncoming, e.allOutgoing]),
44
+ )
45
+ return excludeModelRelations(excludedRelations, { stage, memory })
46
+ }
47
+
48
+ if (FqnExpr.isWildcard(expr.inout)) {
49
+ // non-sense
50
+ return stage
51
+ }
52
+
53
+ const elements = resolveElements(model, expr.inout)
54
+ const isIncoming = filterIncomingConnections(elements)
55
+ const isOutgoing = filterOutgoingConnections(elements)
56
+
57
+ const toExclude = memory.connections.filter(c => isIncoming(c) !== isOutgoing(c))
58
+ stage.excludeConnections(toExclude)
59
+ return stage
60
+ },
61
+ }
@@ -0,0 +1,95 @@
1
+ import { anyPass } from 'remeda'
2
+ import { invariant } from '../../../errors'
3
+ import { findConnectionsBetween } from '../../../model/connection/deployment'
4
+ import type { LikeC4DeploymentModel } from '../../../model/DeploymentModel'
5
+ import type { RelationshipModel } from '../../../model/RelationModel'
6
+ import type { AnyAux } from '../../../model/types'
7
+ import { FqnExpr, type RelationExpr } from '../../../types'
8
+ import { isAncestor } from '../../../utils/fqn'
9
+ import type { Connection, Elem, PredicateExecutor } from '../_types'
10
+ import { resolveElements, resolveModelElements } from '../utils'
11
+ import { excludeModelRelations, resolveAscendingSiblings } from './relation-direct'
12
+
13
+ // from visible element incoming to this
14
+ export const IncomingRelationPredicate: PredicateExecutor<RelationExpr.Incoming> = {
15
+ include: ({ expr, model, memory, stage }) => {
16
+ const sources = [...memory.elements]
17
+
18
+ if (FqnExpr.isWildcard(expr.incoming)) {
19
+ for (const source of sources) {
20
+ if (source.allOutgoing.isEmpty) {
21
+ continue
22
+ }
23
+ const targets = [...resolveAscendingSiblings(source)]
24
+ stage.addConnections(findConnectionsBetween(source, targets, 'directed'))
25
+ }
26
+ return stage
27
+ }
28
+ invariant(FqnExpr.isDeploymentRef(expr.incoming), 'Only deployment refs are supported in include')
29
+
30
+ const targets = resolveElements(model, expr.incoming)
31
+ for (const source of sources) {
32
+ stage.addConnections(findConnectionsBetween(source, targets, 'directed'))
33
+ }
34
+
35
+ return stage
36
+ },
37
+ exclude: ({ expr, model, memory, stage }) => {
38
+ // Exclude all connections that have model relationshps with the elements
39
+ if (FqnExpr.isModelRef(expr.incoming)) {
40
+ const excludedRelations = resolveAllImcomingRelations(model, expr.incoming)
41
+ return excludeModelRelations(excludedRelations, { stage, memory })
42
+ }
43
+ if (FqnExpr.isWildcard(expr.incoming)) {
44
+ // non-sense
45
+ return stage
46
+ }
47
+
48
+ const isIncoming = filterIncomingConnections(resolveElements(model, expr.incoming))
49
+ const toExclude = memory.connections.filter(isIncoming)
50
+ stage.excludeConnections(toExclude)
51
+ return stage
52
+ },
53
+ }
54
+
55
+ export function filterIncomingConnections(
56
+ targets: Elem[],
57
+ ): (connection: Connection) => boolean {
58
+ return anyPass(
59
+ targets.map(target => {
60
+ const satisfies = (el: Elem) => el === target || isAncestor(target, el)
61
+ return (connection: Connection) => {
62
+ return !satisfies(connection.source) && satisfies(connection.target)
63
+ }
64
+ }),
65
+ )
66
+ }
67
+ // model: LikeC4DeploymentModel,
68
+ // model: LikeC4DeploymentModel,
69
+ // expr: FqnExpr.DeploymentRef
70
+ // ): (connection: Connection) => boolean {
71
+ // if (FqnExpr.isWildcard(expr)) {
72
+ // return () => true
73
+ // }
74
+ // if (isNullish(expr.selector)) {
75
+ // // -> element
76
+ // const target = model.element(expr.ref.deployment)
77
+ // const isInside = (el: Elem) => el === target || isAncestor(target, el)
78
+ // return (connection) => {
79
+ // return !isInside(connection.source) && isInside(connection.target)
80
+ // }
81
+ // }
82
+
83
+ // const isTarget = deploymentExpressionToPredicate(expr)
84
+ // return (connection) => {
85
+ // return isTarget(connection.target)
86
+ // }
87
+ // }
88
+
89
+ export function resolveAllImcomingRelations(
90
+ model: LikeC4DeploymentModel,
91
+ moodelRef: FqnExpr.ModelRef,
92
+ ): Set<RelationshipModel<AnyAux>> {
93
+ const targets = resolveModelElements(model, moodelRef)
94
+ return new Set(targets.flatMap(e => [...e.allIncoming]))
95
+ }
@@ -0,0 +1,88 @@
1
+ import { anyPass } from 'remeda'
2
+ import { invariant } from '../../../errors'
3
+ import type { LikeC4DeploymentModel } from '../../../model'
4
+ import { findConnection, findConnectionsBetween } from '../../../model/connection/deployment'
5
+ import type { RelationshipModel } from '../../../model/RelationModel'
6
+ import { FqnExpr, type RelationExpr } from '../../../types'
7
+ import { isAncestor } from '../../../utils'
8
+ import type { Connection, Elem, PredicateExecutor } from '../_types'
9
+ import { resolveElements, resolveModelElements } from '../utils'
10
+ import { excludeModelRelations, resolveAscendingSiblings } from './relation-direct'
11
+
12
+ export const OutgoingRelationPredicate: PredicateExecutor<RelationExpr.Outgoing> = {
13
+ include: ({ expr, model, memory, stage }) => {
14
+ const targets = [...memory.elements]
15
+
16
+ // * -> (to visible elements)
17
+ // outgoing from wildcard to visible element
18
+ if (FqnExpr.isWildcard(expr.outgoing)) {
19
+ for (const target of targets) {
20
+ if (target.allIncoming.isEmpty) {
21
+ continue
22
+ }
23
+ for (const source of resolveAscendingSiblings(target)) {
24
+ stage.addConnections(findConnection(source, target, 'directed'))
25
+ }
26
+ }
27
+ return stage
28
+ }
29
+ invariant(FqnExpr.isDeploymentRef(expr.outgoing), 'Only deployment refs are supported in include')
30
+
31
+ const sources = resolveElements(model, expr.outgoing)
32
+ for (const source of sources) {
33
+ stage.addConnections(findConnectionsBetween(source, targets, 'directed'))
34
+ }
35
+
36
+ return stage
37
+ },
38
+ exclude: ({ expr, model, memory, stage }) => {
39
+ // Exclude all connections that have model relationshps with the elements
40
+ if (FqnExpr.isModelRef(expr.outgoing)) {
41
+ const excludedRelations = resolveAllOutgoingRelations(model, expr.outgoing)
42
+ return excludeModelRelations(excludedRelations, { stage, memory })
43
+ }
44
+ if (FqnExpr.isWildcard(expr.outgoing)) {
45
+ // non-sense
46
+ return stage
47
+ }
48
+
49
+ const isOutgoing = filterOutgoingConnections(resolveElements(model, expr.outgoing))
50
+ const toExclude = memory.connections.filter(isOutgoing)
51
+ stage.excludeConnections(toExclude)
52
+ return stage
53
+ },
54
+ }
55
+
56
+ export function filterOutgoingConnections(
57
+ sources: Elem[],
58
+ ): (connection: Connection) => boolean {
59
+ return anyPass(
60
+ sources.map(source => {
61
+ const satisfies = (el: Elem) => el === source || isAncestor(source, el)
62
+ return (connection: Connection) => {
63
+ return satisfies(connection.source) && !satisfies(connection.target)
64
+ }
65
+ }),
66
+ )
67
+ // if (FqnExpr.isDeploymentRef(expr) && isNullish(expr.selector)) {
68
+ // // element ->
69
+ // const source = model.element(expr.ref.deployment)
70
+ // const isInside = (el: Elem) => el === source || isAncestor(source, el)
71
+ // return (connection: Connection) => {
72
+ // return isInside(connection.source) && !isInside(connection.target)
73
+ // }
74
+ // } else {
75
+ // const isSource = deploymentExpressionToPredicate(expr)
76
+ // return (connection: Connection) => {
77
+ // return isSource(connection.source)
78
+ // }
79
+ // }
80
+ }
81
+
82
+ export function resolveAllOutgoingRelations(
83
+ model: LikeC4DeploymentModel,
84
+ moodelRef: FqnExpr.ModelRef,
85
+ ): Set<RelationshipModel> {
86
+ const targets = resolveModelElements(model, moodelRef)
87
+ return new Set(targets.flatMap(e => [...e.allOutgoing]))
88
+ }
@@ -0,0 +1,29 @@
1
+ import { findConnectionsWithin } from '../../../model/connection/deployment'
2
+ import type { FqnExpr } from '../../../types'
3
+ import { type Elem, type PredicateExecutor } from '../_types'
4
+
5
+ export const WildcardPredicate: PredicateExecutor<FqnExpr.Wildcard> = {
6
+ include: ({ model, stage }) => {
7
+ const children = [] as Elem[]
8
+
9
+ const rootElements = [...model.roots()].map(root => {
10
+ if (!root.onlyOneInstance()) {
11
+ children.push(...root.children())
12
+ }
13
+ return root
14
+ })
15
+
16
+ stage.addExplicit(rootElements)
17
+ if (children.length > 1) {
18
+ stage.addConnections(findConnectionsWithin([
19
+ ...rootElements,
20
+ ...children,
21
+ ]))
22
+ }
23
+ return stage
24
+ },
25
+ exclude: ({ stage, memory }) => {
26
+ stage.exclude(memory.elements)
27
+ return stage
28
+ },
29
+ }
@@ -0,0 +1,5 @@
1
+ import { AbstractStageExclude } from '../../memory'
2
+ import { type Ctx } from '../memory/memory'
3
+
4
+ export class StageExclude extends AbstractStageExclude<Ctx> {
5
+ }