@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,59 @@
1
+ import { hasAtLeast } from 'remeda'
2
+ import { invariant } from '../../errors'
3
+ import { type ComputedEdge, type ComputedNode, type Fqn } from '../../types'
4
+ import { buildComputedNodes, type ComputedNodeSource } from '../utils/buildComputedNodes'
5
+ import { mergePropsFromRelationships } from '../utils/merge-props-from-relationships'
6
+ import type { Connection, Elem, Memory } from './_types'
7
+
8
+ export const NoWhere = () => true
9
+ export const NoFilter = <T>(x: T[] | readonly T[]): T[] => x as T[]
10
+
11
+ export function toNodeSource(el: Elem): ComputedNodeSource {
12
+ return {
13
+ ...el.$element,
14
+ modelRef: 1
15
+ }
16
+ }
17
+
18
+ export function toComputedEdges(
19
+ connections: ReadonlyArray<Connection>
20
+ ): ComputedEdge[] {
21
+ return connections.reduce((acc, e) => {
22
+ // const modelRelations = []
23
+ // const deploymentRelations = []
24
+ const relations = [
25
+ ...e.relations
26
+ ]
27
+ invariant(hasAtLeast(relations, 1), 'Edge must have at least one relation')
28
+
29
+ const source = e.source.id
30
+ const target = e.target.id
31
+
32
+ const {
33
+ title,
34
+ ...props
35
+ } = mergePropsFromRelationships(
36
+ relations.map(r => r.$relationship),
37
+ relations.find(r => r.source.id === source && r.target.id === target)?.$relationship
38
+ )
39
+
40
+ const edge: ComputedEdge = {
41
+ id: e.id,
42
+ parent: e.boundary?.id ?? null,
43
+ source,
44
+ target,
45
+ label: title ?? null,
46
+ relations: relations.map((r) => r.id),
47
+ ...props
48
+ }
49
+
50
+ acc.push(edge)
51
+ return acc
52
+ }, [] as ComputedEdge[])
53
+ }
54
+
55
+ export function buildNodes(memory: Memory): ReadonlyMap<Fqn, ComputedNode> {
56
+ // typecast to MutableMemory
57
+ // invariant(memory instanceof MutableMemory, 'Expected MutableMemory')
58
+ return buildComputedNodes([...memory.final].map(toNodeSource), memory.groups)
59
+ }
@@ -0,0 +1,4 @@
1
+ export { computeView, computeViews, unsafeComputeView } from './compute-view'
2
+ export type { ComputeViewResult } from './compute-view'
3
+ export { resolveRulesExtendedViews } from './utils/resolve-extended-views'
4
+ export { viewsWithReadableEdges, withReadableEdges } from './utils/with-readable-edges'
@@ -0,0 +1,45 @@
1
+ import type { AnyCtx, ComputeMemory, GenericCtx, MutableState, StageExpression } from './_types'
2
+
3
+ export abstract class AbstractMemory<T extends AnyCtx = GenericCtx> implements ComputeMemory<T> {
4
+ /**
5
+ * Provides access to context types
6
+ * !IMPORTANT: Should not be called in runtime
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * type State = SomeMemory['Ctx']['MutableState']
11
+ * ```
12
+ */
13
+ public get Ctx(): T {
14
+ throw new Error('Should not be called in runtime')
15
+ }
16
+
17
+ protected constructor(protected state: MutableState<T>) {
18
+ }
19
+
20
+ public get elements(): ReadonlySet<T['Element']> {
21
+ return this.state.elements
22
+ }
23
+ public get explicits(): ReadonlySet<T['Element']> {
24
+ return this.state.explicits
25
+ }
26
+ public get final(): ReadonlySet<T['Element']> {
27
+ return this.state.final
28
+ }
29
+ public get connections(): ReadonlyArray<T['Connection']> {
30
+ return this.state.connections
31
+ }
32
+
33
+ public isEmpty(): boolean {
34
+ return this.elements.size === 0 && this.connections.length === 0
35
+ && this.explicits.size === 0 && this.final.size === 0
36
+ }
37
+
38
+ abstract mutableState(): MutableState<T>
39
+
40
+ abstract stageInclude(expr: StageExpression<T>): T['StageInclude']
41
+
42
+ abstract stageExclude(expr: StageExpression<T>): T['StageExclude']
43
+
44
+ abstract update(newstate: Partial<MutableState<T>>): T['Memory']
45
+ }
@@ -0,0 +1,216 @@
1
+ import { isBoolean, pipe } from 'remeda'
2
+ import { invariant } from '../../errors'
3
+ import { findAscendingConnections } from '../../model/connection'
4
+ import { difference, intersection, isDescendantOf, isIterable } from '../../utils'
5
+ import { ifilter, isome, toSet } from '../../utils/iterable'
6
+ import type { AnyCtx, CtxConnection, CtxElement, MutableState, StageExclude, StageExpression } from './_types'
7
+
8
+ export abstract class AbstractStageExclude<T extends AnyCtx> implements StageExclude<T> {
9
+ // Removed elements
10
+ protected excluded = {
11
+ elements: new Set<CtxElement<T>>(),
12
+ connections: [] as CtxConnection<T>[],
13
+ }
14
+
15
+ constructor(
16
+ public readonly memory: T['Memory'],
17
+ public readonly expression: StageExpression<T>,
18
+ ) {
19
+ }
20
+
21
+ protected markedToMoveExplicitToImplicit = false
22
+
23
+ protected _removeElement(element: CtxElement<T>): void {
24
+ this.excluded.elements.add(element)
25
+ }
26
+
27
+ public exclude(element: CtxElement<T> | Iterable<CtxElement<T>> | false | undefined | null): this {
28
+ if (!element) {
29
+ return this
30
+ }
31
+ if (isIterable(element)) {
32
+ for (const el of element) {
33
+ this._removeElement(el)
34
+ }
35
+ return this
36
+ }
37
+ this._removeElement(element)
38
+ return this
39
+ }
40
+
41
+ protected _removeConnection(connection: CtxConnection<T>): void {
42
+ this.excluded.connections.push(connection)
43
+ }
44
+ /**
45
+ * Excludes from the memory relationships from given connections (still connection may be included, but without given relationships)
46
+ * @param moveExplicitToImplicit - if true, disconnected explicit elements will be moved to implicit
47
+ * @default false
48
+ */
49
+ public excludeConnections(
50
+ connection: CtxConnection<T> | Iterable<CtxConnection<T>>,
51
+ moveExplicitToImplicit?: boolean,
52
+ ) {
53
+ if (isBoolean(moveExplicitToImplicit)) {
54
+ invariant(!this.markedToMoveExplicitToImplicit, 'Already marked to move explicits')
55
+ this.markedToMoveExplicitToImplicit = moveExplicitToImplicit
56
+ }
57
+ if (isIterable(connection)) {
58
+ for (const c of connection) {
59
+ this._removeConnection(c)
60
+ }
61
+ return this
62
+ }
63
+ this._removeConnection(connection)
64
+ return this
65
+ }
66
+
67
+ public isDirty(): boolean {
68
+ return this.excluded.elements.size > 0 || this.excluded.connections.length > 0
69
+ }
70
+
71
+ public isEmpty(): boolean {
72
+ return !this.isDirty()
73
+ }
74
+
75
+ /**
76
+ * Determines whether disconnected explicits should become implicits.
77
+ * By default moves all disconnected explicits to implicits, if there were operation to exclude elements.
78
+ *
79
+ * Override this method to change the behavior.
80
+ */
81
+ protected filterForMoveToImplicits(disconnectedExplicits: Set<CtxElement<T>>): Set<CtxElement<T>> {
82
+ if (this.markedToMoveExplicitToImplicit || this.excluded.elements.size > 0) {
83
+ return disconnectedExplicits
84
+ }
85
+ return new Set()
86
+ }
87
+
88
+ // Check if Leaf EXPLICIT elements are becoming IMPLICIT
89
+ // (it means that they are not connected anymore)
90
+ protected moveDisconnectedExplicitsToImplicits(state: MutableState<T>): MutableState<T> {
91
+ // Check if EXPLICIT elements are becoming IMPLICIT
92
+ let disconnected = difference(
93
+ new Set(this.memory.connections.flatMap(c => [c.source, c.target])),
94
+ new Set(state.connections.flatMap(c => [c.source, c.target])),
95
+ )
96
+ // Ensure existing in implicits
97
+ disconnected = intersection(
98
+ disconnected,
99
+ state.elements,
100
+ )
101
+ // Ensure this is a leaf explici element
102
+ disconnected = pipe(
103
+ disconnected,
104
+ ifilter(el => {
105
+ return state.explicits.has(el) && !isome(state.final, isDescendantOf(el))
106
+ }),
107
+ toSet(),
108
+ )
109
+ if (disconnected.size > 0) {
110
+ disconnected = this.filterForMoveToImplicits(disconnected)
111
+ state.explicits = difference(state.explicits, disconnected)
112
+ // Exclude from final elements
113
+ state.final = difference(state.final, disconnected)
114
+ }
115
+ return state
116
+ }
117
+
118
+ protected removeElements(state: MutableState<T>): MutableState<T> {
119
+ state.elements = difference(state.elements, this.excluded.elements)
120
+ state.explicits = difference(state.explicits, this.excluded.elements)
121
+ state.final = difference(state.final, this.excluded.elements)
122
+ return state
123
+ }
124
+
125
+ protected removeConnections(state: MutableState<T>): MutableState<T> {
126
+ const excludedMap = this.excluded.connections.reduce((acc, c) => {
127
+ const existing = acc.get(c.id)
128
+ if (existing) {
129
+ acc.set(c.id, existing.mergeWith(c) as CtxConnection<T>)
130
+ } else {
131
+ acc.set(c.id, c)
132
+ }
133
+ return acc
134
+ }, new Map<string, CtxConnection<T>>())
135
+
136
+ // were connected before and not anymore
137
+ let disconnected = new Set<CtxElement<T>>()
138
+
139
+ state.connections = state.connections.reduce((acc, c) => {
140
+ const excluded = excludedMap.get(c.id)
141
+ if (excluded) {
142
+ disconnected.add(c.source)
143
+ disconnected.add(c.target)
144
+ const diff = c.difference(excluded) as CtxConnection<T>
145
+ if (diff.nonEmpty()) {
146
+ acc.push(diff)
147
+ }
148
+ } else {
149
+ acc.push(c)
150
+ }
151
+ return acc
152
+ }, [] as CtxConnection<T>[])
153
+
154
+ for (const stillExists of state.connections) {
155
+ disconnected.delete(stillExists.source)
156
+ disconnected.delete(stillExists.target)
157
+ if (stillExists.boundary && state.elements.has(stillExists.boundary)) {
158
+ disconnected.delete(stillExists.boundary)
159
+ }
160
+ }
161
+
162
+ if (disconnected.size === 0) {
163
+ return state
164
+ }
165
+ // Keep explicits
166
+ disconnected = difference(disconnected, state.explicits)
167
+ // Even if not connected, implicit elements should be kept
168
+ // state.elements = difference(state.elements, excludedElements)
169
+ state.final = difference(state.final, disconnected)
170
+
171
+ return state
172
+ }
173
+
174
+ /**
175
+ * Precommit hook
176
+ */
177
+ protected precommit(state: MutableState<T>): MutableState<T> {
178
+ return state
179
+ }
180
+
181
+ /**
182
+ * Postcommit hook
183
+ */
184
+ protected postcommit(state: MutableState<T>): MutableState<T> {
185
+ invariant(difference(state.explicits, state.elements).size === 0, 'Explicits must be subset of elements')
186
+ invariant(difference(state.final, state.elements).size === 0, 'Final elements must be subset of elements')
187
+ return state
188
+ }
189
+
190
+ public commit(): T['Memory'] {
191
+ let state = this.precommit(this.memory.mutableState())
192
+
193
+ // Exclude connections from excluded elements
194
+ if (this.excluded.elements.size > 0) {
195
+ const excludedConnections = state.connections
196
+ .filter(c => this.excluded.elements.has(c.source) || this.excluded.elements.has(c.target))
197
+ .flatMap(c => [
198
+ c,
199
+ ...findAscendingConnections(state.connections, c)
200
+ .map(asc => asc.intersect(c) as CtxConnection<T>),
201
+ ])
202
+ .filter(asc => asc.nonEmpty())
203
+ this.excludeConnections(excludedConnections)
204
+ }
205
+ if (this.excluded.connections.length > 0) {
206
+ state = this.removeConnections(state)
207
+ }
208
+ if (this.excluded.elements.size > 0) {
209
+ state = this.removeElements(state)
210
+ }
211
+
212
+ state = this.moveDisconnectedExplicitsToImplicits(state)
213
+
214
+ return this.memory.update(this.postcommit(state))
215
+ }
216
+ }
@@ -0,0 +1,200 @@
1
+ import { partition } from 'remeda'
2
+ import { mergeConnections } from '../../model/connection'
3
+ import { intersection, isIterable, union } from '../../utils'
4
+ import type {
5
+ AnyCtx,
6
+ CtxConnection as Connection,
7
+ CtxElement as Elem,
8
+ GenericCtx,
9
+ MutableState,
10
+ StageExpression,
11
+ StageInclude,
12
+ } from './_types'
13
+
14
+ export abstract class AbstractStageInclude<T extends AnyCtx = GenericCtx> implements StageInclude<T> {
15
+ // New elements
16
+ protected explicits = new Set<Elem<T>>()
17
+ protected implicits = new Set<Elem<T>>()
18
+
19
+ // Ordered Set of explicit and implicit elements
20
+ protected _ordered = new Set<Elem<T>>()
21
+
22
+ protected _connections = [] as Connection<T>[]
23
+
24
+ constructor(
25
+ public readonly memory: T['Memory'],
26
+ public readonly expression: StageExpression<T>,
27
+ ) {
28
+ }
29
+
30
+ get elements(): ReadonlySet<Elem<T>> {
31
+ return this.explicits
32
+ }
33
+
34
+ /**
35
+ * Connections from this stage
36
+ */
37
+ get connections(): readonly Connection<T>[] {
38
+ return this._connections
39
+ }
40
+
41
+ mergedConnections(): readonly Connection<T>[] {
42
+ return mergeConnections([
43
+ ...this.memory.connections,
44
+ ...this._connections,
45
+ ])
46
+ }
47
+
48
+ public connectWithExisting(
49
+ _element: Elem<T> | Iterable<Elem<T>>,
50
+ _direction?: 'in' | 'out' | 'both',
51
+ ): boolean {
52
+ throw new Error('Method not implements, depends on the model')
53
+ }
54
+
55
+ /**
56
+ * Possible to override
57
+ */
58
+ protected _addExplicit(elements: Elem<T>): void {
59
+ this._ordered.add(elements)
60
+ this.explicits.add(elements)
61
+ this.implicits.delete(elements)
62
+ }
63
+
64
+ public addExplicit(element: Elem<T> | Iterable<Elem<T>> | false | undefined | null): this {
65
+ if (!element) {
66
+ return this
67
+ }
68
+ if (isIterable(element)) {
69
+ for (const el of element) {
70
+ this._addExplicit(el)
71
+ }
72
+ return this
73
+ }
74
+ this._addExplicit(element)
75
+ return this
76
+ }
77
+
78
+ /**
79
+ * Possible to override
80
+ */
81
+ protected _addImplicit(elements: Elem<T>): void {
82
+ if (this.explicits.has(elements)) {
83
+ return
84
+ }
85
+ this._ordered.add(elements)
86
+ this.implicits.add(elements)
87
+ }
88
+
89
+ public addImplicit(elements: Elem<T> | Iterable<Elem<T>> | false | undefined | null): this {
90
+ if (!elements) {
91
+ return this
92
+ }
93
+ if (isIterable(elements)) {
94
+ for (const el of elements) {
95
+ this._addImplicit(el)
96
+ }
97
+ return this
98
+ }
99
+ this._addImplicit(elements)
100
+ return this
101
+ }
102
+
103
+ /**
104
+ * Possible to override
105
+ */
106
+ protected _addConnection(connection: Connection<T>): void {
107
+ this._connections.push(connection)
108
+ this._addImplicit(connection.source)
109
+ this._addImplicit(connection.target)
110
+ }
111
+
112
+ public addConnections(connection: Connection<T> | Iterable<Connection<T>>): this {
113
+ if (isIterable(connection)) {
114
+ for (const c of connection) {
115
+ this._addConnection(c)
116
+ }
117
+ return this
118
+ }
119
+ this._addConnection(connection)
120
+ return this
121
+ }
122
+
123
+ public isDirty(): boolean {
124
+ return this.explicits.size > 0 || this.implicits.size > 0 || this._connections.length > 0
125
+ }
126
+
127
+ public isEmpty(): boolean {
128
+ return !this.isDirty()
129
+ }
130
+
131
+ /**
132
+ * Precommit hook
133
+ */
134
+ protected precommit(state: MutableState<T>): MutableState<T> {
135
+ return state
136
+ }
137
+
138
+ /**
139
+ * Postcommit hook
140
+ */
141
+ protected postcommit(state: MutableState<T>): MutableState<T> {
142
+ return state
143
+ }
144
+
145
+ protected processConnections(connections: Connection<T>[]): Connection<T>[] { // To preserve order, we split new connections into two sets
146
+ return connections
147
+ }
148
+
149
+ public commit(): T['Memory'] {
150
+ let state = this.precommit(this.memory.mutableState())
151
+
152
+ let fromConnections = new Set<Elem<T>>()
153
+
154
+ if (this._connections.length > 0) {
155
+ // To preserve order, we split new connections into two sets
156
+ // First are outgoing from known elements (in memory.elements)
157
+ const [fromKnown, rest] = partition(
158
+ this._connections,
159
+ c => state.final.has(c.source),
160
+ )
161
+
162
+ state.connections = this.processConnections(
163
+ mergeConnections([
164
+ ...state.connections,
165
+ ...fromKnown,
166
+ ...rest,
167
+ ]),
168
+ )
169
+
170
+ fromConnections = new Set(state.connections.flatMap(c => [c.source, c.target]))
171
+ }
172
+
173
+ state.elements = union(
174
+ state.elements,
175
+ this._ordered,
176
+ this.explicits,
177
+ fromConnections,
178
+ this.implicits,
179
+ )
180
+
181
+ state.explicits = intersection(
182
+ state.elements,
183
+ union(
184
+ state.explicits,
185
+ this.explicits,
186
+ ),
187
+ )
188
+
189
+ state.final = intersection(
190
+ state.elements,
191
+ union(
192
+ state.final,
193
+ this.explicits,
194
+ fromConnections,
195
+ ),
196
+ )
197
+
198
+ return this.memory.update(this.postcommit(state))
199
+ }
200
+ }
@@ -0,0 +1,147 @@
1
+ import type { Connection } from '../../model/connection'
2
+ import type { DeploymentElementModel } from '../../model/DeploymentElementModel'
3
+ import type { ElementModel } from '../../model/ElementModel'
4
+
5
+ type Element = ElementModel | DeploymentElementModel
6
+
7
+ export interface ComputeCtx<
8
+ E extends Element,
9
+ C extends Connection<E, any>,
10
+ M extends ComputeMemory<any>,
11
+ Inc extends StageInclude<any>,
12
+ Exc extends StageExclude<any>,
13
+ Expr = unknown,
14
+ > {
15
+ Element: E
16
+ Connection: C
17
+ Memory: M
18
+ StageInclude: Inc
19
+ StageExclude: Exc
20
+ Expr: Expr
21
+ MutableState: State<this>
22
+ }
23
+
24
+ // export type AnyCtx = ComputeCtx<any, any, ComputeMemory<any>, StageInclude<any>, StageExclude<any>, any>
25
+ export type AnyCtx = GenericCtx
26
+
27
+ export type GenericCtx = ComputeCtx<
28
+ any,
29
+ Connection<any, any>,
30
+ ComputeMemory<GenericCtx>,
31
+ StageInclude<GenericCtx>,
32
+ StageExclude<GenericCtx>,
33
+ unknown
34
+ >
35
+
36
+ export interface State<T extends AnyCtx> {
37
+ elements: Set<CtxElement<T>>
38
+ explicits: Set<CtxElement<T>>
39
+ final: Set<CtxElement<T>>
40
+ connections: Array<CtxConnection<T>>
41
+ }
42
+
43
+ export type MutableState<T extends AnyCtx> = T['MutableState']
44
+
45
+ export type StageExpression<T extends AnyCtx> = T['Expr']
46
+
47
+ export type CtxElement<T extends AnyCtx> = T['Element']
48
+ export type CtxConnection<T extends AnyCtx> = T['Connection']
49
+ export type CtxMemory<T extends AnyCtx> = T['Memory']
50
+
51
+ export interface ComputeMemory<T extends AnyCtx> {
52
+ /**
53
+ * All resolved elements, includes:
54
+ * - explicit elements (included by element predicates, always appear in the view unless excluded)
55
+ * - elements from resolved connections (may be excluded, if connection is redundant @see excludeRedundantRelationships
56
+ * - implicit elements (not added directly, not included in the view, used for resolving connections)
57
+ */
58
+ readonly elements: ReadonlySet<CtxElement<T>>
59
+
60
+ /**
61
+ * Explicit elements
62
+ */
63
+ readonly explicits: ReadonlySet<CtxElement<T>>
64
+
65
+ /**
66
+ * Final set of elements to be included in the view
67
+ * (`elements` excluding implicits)
68
+ * Keeps order in which elements were added
69
+ */
70
+ readonly final: ReadonlySet<CtxElement<T>>
71
+
72
+ /**
73
+ * Resolved connections
74
+ */
75
+ readonly connections: ReadonlyArray<CtxConnection<T>>
76
+
77
+ isEmpty(): boolean
78
+
79
+ stageInclude(expression: T['Expr']): T['StageInclude']
80
+
81
+ stageExclude(expression: T['Expr']): T['StageExclude']
82
+
83
+ /**
84
+ * Returns shallow copy of state
85
+ */
86
+ mutableState(): T['MutableState']
87
+
88
+ /**
89
+ * Returns new memory with updated state
90
+ */
91
+ update(newstate: Partial<T['MutableState']>): T['Memory']
92
+ }
93
+
94
+ interface Stage<T extends AnyCtx> {
95
+ readonly memory: CtxMemory<T>
96
+
97
+ readonly expression: StageExpression<T>
98
+
99
+ /**
100
+ * Has changes
101
+ */
102
+ isDirty(): boolean
103
+
104
+ /**
105
+ * Has no changes
106
+ */
107
+ isEmpty(): boolean
108
+
109
+ commit(): T['Memory']
110
+ }
111
+
112
+ export interface StageInclude<T extends AnyCtx> extends Stage<T> {
113
+ readonly elements: ReadonlySet<CtxElement<T>>
114
+
115
+ readonly connections: ReadonlyArray<CtxConnection<T>>
116
+
117
+ addExplicit(element: CtxElement<T> | Iterable<CtxElement<T>> | false | undefined | null): this
118
+
119
+ addImplicit(element: CtxElement<T> | Iterable<CtxElement<T>> | false | undefined | null): this
120
+
121
+ /**
122
+ * Connects element with existing ones in the memory
123
+ *
124
+ * @param direction - direction of the connection
125
+ * @default 'both'
126
+ */
127
+ connectWithExisting(
128
+ element: CtxElement<T> | Iterable<CtxElement<T>>,
129
+ direction?: 'in' | 'out' | 'both',
130
+ ): boolean
131
+
132
+ addConnections(connection: CtxConnection<T> | Iterable<CtxConnection<T>>): this
133
+ }
134
+
135
+ export interface StageExclude<T extends AnyCtx> extends Stage<T> {
136
+ /**
137
+ * Excludes from the memory relationships from given connections (still connection may be included, but without given relationships)
138
+ * @param moveExplicitToImplicit - if true, disconnected explicit elements will be moved to implicit
139
+ * @default false
140
+ */
141
+ excludeConnections(
142
+ connection: CtxConnection<T> | Iterable<CtxConnection<T>>,
143
+ moveExplicitToImplicit?: boolean,
144
+ ): this
145
+
146
+ exclude(element: CtxElement<T> | Iterable<CtxElement<T>> | false | undefined | null): this
147
+ }
@@ -0,0 +1,5 @@
1
+ export type * from './_types'
2
+ export { AbstractMemory } from './AbstractMemory'
3
+ export { AbstractStageExclude } from './AbstractStageExclude'
4
+ export { AbstractStageInclude } from './AbstractStageInclude'
5
+ export { treeFromMemoryState } from './ops'