@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,83 @@
1
+ import { mapValues } from 'remeda'
2
+ import { nonexhaustive } from '../errors'
3
+ import { LikeC4Model } from '../model'
4
+ import {
5
+ type ComputedLikeC4Model,
6
+ type ComputedView,
7
+ isDeploymentView,
8
+ isDynamicView,
9
+ isElementView,
10
+ type LikeC4View,
11
+ type ParsedLikeC4Model
12
+ } from '../types'
13
+ import { computeDeploymentView } from './deployment-view/compute'
14
+ import { computeDynamicView } from './dynamic-view/compute'
15
+ import { computeElementView } from './element-view/compute'
16
+
17
+ export type ComputeViewResult<V extends ComputedView = ComputedView> =
18
+ | {
19
+ isSuccess: true
20
+ error?: undefined
21
+ view: V
22
+ }
23
+ | {
24
+ isSuccess: false
25
+ error: Error
26
+ view: undefined
27
+ }
28
+
29
+ export function unsafeComputeView(
30
+ viewsource: LikeC4View,
31
+ likec4model: LikeC4Model
32
+ ): ComputedView {
33
+ switch (true) {
34
+ case isDeploymentView(viewsource): {
35
+ return computeDeploymentView(likec4model, viewsource)
36
+ }
37
+ case isDynamicView(viewsource):
38
+ return computeDynamicView(likec4model, viewsource)
39
+ case isElementView(viewsource):
40
+ return computeElementView(likec4model, viewsource)
41
+ default:
42
+ nonexhaustive(viewsource)
43
+ }
44
+ }
45
+
46
+ export function computeView<V extends LikeC4View>(
47
+ viewsource: V,
48
+ likec4model: LikeC4Model
49
+ ): ComputeViewResult {
50
+ try {
51
+ return {
52
+ isSuccess: true,
53
+ view: unsafeComputeView(viewsource, likec4model)
54
+ }
55
+ } catch (e) {
56
+ return {
57
+ isSuccess: false,
58
+ error: e instanceof Error ? e : new Error(`Unknown error: ${e}`),
59
+ view: undefined
60
+ }
61
+ }
62
+ }
63
+
64
+ export function computeViews<P extends ParsedLikeC4Model>(parsed: P): ComputedLikeC4Model {
65
+ const { views, ...rest } = parsed as Omit<P, '__'>
66
+ const likec4model = LikeC4Model.create({
67
+ ...rest,
68
+ views: {}
69
+ })
70
+ const compute = (source: LikeC4View): ComputedView => {
71
+ const result = computeView(source, likec4model)
72
+ if (result.isSuccess) {
73
+ return result.view
74
+ } else {
75
+ throw result.error
76
+ }
77
+ }
78
+ return {
79
+ ...rest,
80
+ __: 'computed',
81
+ views: mapValues(parsed.views, compute)
82
+ }
83
+ }
@@ -0,0 +1,236 @@
1
+ import { indexBy, isArray, isString, map, mapValues, pipe, prop } from 'remeda'
2
+ import type { Writable } from 'type-fest'
3
+ import type { ExpectStatic } from 'vitest'
4
+ import { expect as vitestExpect } from 'vitest'
5
+ import {
6
+ type AnyTypes,
7
+ type Builder,
8
+ type DeploymentRulesBuilderOp,
9
+ type Types,
10
+ type ViewPredicate,
11
+ } from '../../../builder'
12
+ import * as viewhelpers from '../../../builder/Builder.view-common'
13
+ import { mkViewBuilder } from '../../../builder/Builder.views'
14
+ import { differenceConnections } from '../../../model/connection'
15
+ import type { ComputedDeploymentView, DeploymentView, DeploymentViewRule, ViewId } from '../../../types'
16
+ import { imap, toArray } from '../../../utils/iterable'
17
+ import { difference as differenceSet } from '../../../utils/set'
18
+ import { withReadableEdges } from '../../utils/with-readable-edges'
19
+ import { processPredicates as processPredicatesImpl } from '../compute'
20
+ import { Memory } from '../memory'
21
+
22
+ type ConnectionExpression<T extends AnyTypes> = `${T['DeploymentFqn']} -> ${T['DeploymentFqn']}`
23
+
24
+ type ConnectionsDeepMatcher<M extends string, D extends string> = {
25
+ [K in `${D} -> ${D}`]?: {
26
+ model?: Array<`${M} -> ${M}`>
27
+ deployment?: Array<`${D} -> ${D}`>
28
+ }
29
+ }
30
+
31
+ type ToDeepMatcher<T extends AnyTypes> = ConnectionsDeepMatcher<T['Fqn'], T['DeploymentFqn']>
32
+
33
+ type ConnectionEqual<T extends AnyTypes> = [ToDeepMatcher<T>] | [ConnectionExpression<T>, ...ConnectionExpression<T>[]]
34
+
35
+ type Elem = Memory['Ctx']['Element']
36
+ type Connection = Memory['Ctx']['Connection']
37
+
38
+ export class TestHelper<T extends AnyTypes> {
39
+ model: Types.ToLikeC4Model<T>
40
+
41
+ static $include = viewhelpers.$include
42
+ static $exclude = viewhelpers.$exclude
43
+ static $style = viewhelpers.$style
44
+
45
+ $include = viewhelpers.$include
46
+ $exclude = viewhelpers.$exclude
47
+ $style = viewhelpers.$style
48
+
49
+ static from<const T extends AnyTypes>(builder: Builder<T>, expect = vitestExpect): TestHelper<T> {
50
+ return new TestHelper(builder, expect)
51
+ }
52
+
53
+ constructor(
54
+ private builder: Builder<T>,
55
+ private _expect: ExpectStatic,
56
+ ) {
57
+ this.model = builder.toLikeC4Model() as Types.ToLikeC4Model<T>
58
+ }
59
+
60
+ computeView = (...rules: DeploymentRulesBuilderOp<T>[]) => {
61
+ return withReadableEdges(
62
+ this.builder
63
+ .clone()
64
+ .views(_ => _.deploymentView('dev').with(...rules))
65
+ .toLikeC4Model()
66
+ .view('dev')
67
+ .$view as ComputedDeploymentView<'dev'>,
68
+ ' -> ',
69
+ )
70
+ }
71
+
72
+ processPredicates(...rules: DeploymentRulesBuilderOp<T>[]) {
73
+ return ProcessPredicates.execute(this, ...rules)
74
+ }
75
+
76
+ expectView(view: ComputedDeploymentView) {
77
+ return {
78
+ toHave: (nodesAndEdges: { nodes: Array<T['DeploymentFqn']>; edges: Array<ConnectionExpression<T>> }) => {
79
+ const actual = {
80
+ nodes: view.nodes.map(prop('id')),
81
+ edges: view.edges.map(prop('id')),
82
+ }
83
+ this._expect(actual).toEqual(nodesAndEdges)
84
+ },
85
+ toHaveNodes: <Id extends T['DeploymentFqn']>(...nodes: Id[]) => {
86
+ this._expect(view.nodes.map(prop('id'))).toEqual(nodes)
87
+ },
88
+ toHaveEdges: <Id extends ConnectionExpression<T>>(...edges: Id[]) => {
89
+ this._expect(view.edges.map(prop('id'))).toEqual(edges)
90
+ },
91
+ }
92
+ }
93
+
94
+ expectComputedView(...rules: DeploymentRulesBuilderOp<T>[]) {
95
+ return this.expectView(this.computeView(...rules))
96
+ }
97
+
98
+ expectMemory = (memory: Memory) => ({
99
+ toHaveAllElements: <Id extends T['DeploymentFqn']>(...ids: Id[]) => {
100
+ this._expect(map([...memory.elements], prop('id'))).toEqual(ids)
101
+ },
102
+ toHaveElements: <Id extends T['DeploymentFqn']>(...ids: Id[]) => {
103
+ this._expect(map([...memory.final], prop('id'))).toEqual(ids)
104
+ },
105
+ toHaveConnections: (...matchers: ConnectionEqual<T>) => {
106
+ this.expectConnections(memory.connections).toEqual(...matchers)
107
+ },
108
+ })
109
+
110
+ expectElements = (elements: ReadonlySet<Elem>) => ({
111
+ toEqual: <const Id extends ViewPredicate.DeploymentConnectionExpression<T>>(...ids: Id[]) => {
112
+ this._expect(toArray(imap(elements, prop('id')))).toEqual(ids)
113
+ },
114
+ })
115
+
116
+ expectConnections = (connections: ReadonlyArray<Connection>) => ({
117
+ toBeEmpty: () => {
118
+ this._expect(connections.map(c => c.expression)).to.be.empty
119
+ },
120
+ toEqual: (...matchers: ConnectionEqual<T>) => {
121
+ const [matcher, ...rest] = matchers
122
+ if (isString(matcher)) {
123
+ this._expect(connections.map(c => c.expression)).toEqual([matcher, ...rest])
124
+ return
125
+ }
126
+ const obj = pipe(
127
+ connections,
128
+ indexBy(prop('expression')),
129
+ mapValues(c => ({
130
+ model: toArray(imap(c.relations.model, prop('expression'))).sort(),
131
+ deployment: toArray(imap(c.relations.deployment, prop('expression'))).sort(),
132
+ })),
133
+ )
134
+ const expected = mapValues(matcher, (v: any) => ({
135
+ ...v,
136
+ model: v.model ? [...v.model].sort() : [],
137
+ deployment: v.deployment ? [...v.deployment].sort() : [],
138
+ }))
139
+ this._expect(obj).toEqual(expected)
140
+ },
141
+ })
142
+
143
+ expectStep = (step: ProcessPredicates<T>) => ({
144
+ ...this.expectMemory(step.memory),
145
+ })
146
+
147
+ expect(value: ComputedDeploymentView): ReturnType<typeof this['expectView']>
148
+ expect(value: Set<Elem>): ReturnType<typeof this['expectElements']>
149
+ expect(value: ReadonlyArray<Connection>): ReturnType<typeof this['expectConnections']>
150
+ expect(value: Memory | ProcessPredicates<T>): ReturnType<typeof this['expectMemory']>
151
+ expect(value: Memory | ProcessPredicates<T> | Set<Elem> | ComputedDeploymentView | ReadonlyArray<Connection>) {
152
+ if (value instanceof Memory) {
153
+ return this.expectMemory(value)
154
+ }
155
+ if (value instanceof ProcessPredicates) {
156
+ return this.expectStep(value)
157
+ }
158
+ if (value instanceof Set) {
159
+ return this.expectElements(value)
160
+ }
161
+ if (isArray(value)) {
162
+ return this.expectConnections(value)
163
+ }
164
+ return this.expectView(value)
165
+ }
166
+ }
167
+
168
+ class ProcessPredicates<T extends AnyTypes> {
169
+ static execute<A extends AnyTypes>(
170
+ test: TestHelper<A>,
171
+ ...rules: DeploymentRulesBuilderOp<A>[]
172
+ ): ProcessPredicates<A> {
173
+ const processor = new ProcessPredicates(test)
174
+ processor.next(...rules)
175
+ return processor
176
+ }
177
+
178
+ public viewrules: ReadonlyArray<DeploymentViewRule> = []
179
+
180
+ public previousMemory: Memory = Memory.empty()
181
+ public memory: Memory = Memory.empty()
182
+ public predicates: DeploymentRulesBuilderOp<T>[] = []
183
+
184
+ constructor(
185
+ public readonly t: TestHelper<T>,
186
+ protected age = 0,
187
+ ) {}
188
+
189
+ get elements() {
190
+ return toArray(imap(this.memory.elements, prop('id')))
191
+ }
192
+
193
+ get connections() {
194
+ return this.memory.connections.map(c => c.expression)
195
+ }
196
+
197
+ diff() {
198
+ const prevState = this.previousMemory
199
+ const state = this.memory
200
+ return {
201
+ added: this.memory.update({
202
+ elements: differenceSet(state.elements, prevState.elements),
203
+ explicits: differenceSet(state.explicits, prevState.explicits),
204
+ final: differenceSet(state.final, prevState.final),
205
+ connections: differenceConnections(state.connections, prevState.connections),
206
+ }),
207
+ removed: this.memory.update({
208
+ elements: differenceSet(prevState.elements, state.elements),
209
+ explicits: differenceSet(prevState.explicits, state.explicits),
210
+ final: differenceSet(prevState.final, state.final),
211
+ connections: differenceConnections(prevState.connections, state.connections),
212
+ }),
213
+ }
214
+ }
215
+
216
+ next(...predicates: DeploymentRulesBuilderOp<T>[]): this {
217
+ const view = {
218
+ id: 'test' as ViewId,
219
+ __: 'deployment',
220
+ rules: [],
221
+ } as any as Writable<DeploymentView>
222
+ let vb = mkViewBuilder(view) as any
223
+ this.predicates = [
224
+ ...this.predicates,
225
+ ...predicates,
226
+ ]
227
+ for (const rule of this.predicates) {
228
+ rule(vb)
229
+ }
230
+ this.previousMemory = this.memory
231
+ this.viewrules = view.rules
232
+ this.memory = processPredicatesImpl(this.t.model.deployment, view.rules)
233
+ this.age++
234
+ return this
235
+ }
236
+ }
@@ -0,0 +1,198 @@
1
+ import { map, prop } from 'remeda'
2
+ import type { DeploymentRulesBuilderOp } from '../../../builder'
3
+ import { Builder } from '../../../builder'
4
+ import { LikeC4Model } from '../../../model'
5
+ import type { DeploymentView } from '../../../types'
6
+ import { withReadableEdges } from '../../utils/with-readable-edges'
7
+ import { computeDeploymentView } from '../compute'
8
+
9
+ const {
10
+ builder: b,
11
+ model: {
12
+ model,
13
+ person,
14
+ system,
15
+ component,
16
+ webapp,
17
+ mobile,
18
+ ...$m
19
+ },
20
+ deployment: {
21
+ deployment,
22
+ env,
23
+ node,
24
+ zone,
25
+ instanceOf,
26
+ ...$d
27
+ },
28
+ views: {
29
+ views,
30
+ deploymentView,
31
+ $rules,
32
+ $include,
33
+ $exclude,
34
+ },
35
+ } = Builder.forSpecification({
36
+ elements: {
37
+ person: {
38
+ style: {
39
+ shape: 'person',
40
+ },
41
+ },
42
+ system: {},
43
+ component: {},
44
+ webapp: {
45
+ style: {
46
+ shape: 'browser',
47
+ },
48
+ },
49
+ mobile: {
50
+ style: {
51
+ shape: 'mobile',
52
+ },
53
+ },
54
+ },
55
+ deployments: {
56
+ env: {},
57
+ zone: {},
58
+ node: {},
59
+ },
60
+ })
61
+
62
+ export const builder = b
63
+ .with(
64
+ model(
65
+ person('customer', {
66
+ title: 'Happy Customer',
67
+ }),
68
+ system('cloud').with(
69
+ component('frontend').with(
70
+ webapp('dashboard'),
71
+ mobile('mobile'),
72
+ ),
73
+ component('auth'),
74
+ component('backend').with(
75
+ component('api'),
76
+ ),
77
+ component('media', {
78
+ shape: 'storage',
79
+ }),
80
+ ),
81
+ system('aws').with(
82
+ component('rds', {
83
+ shape: 'storage',
84
+ }),
85
+ component('s3', {
86
+ shape: 'storage',
87
+ }),
88
+ ),
89
+ system('email'),
90
+ ),
91
+ model(
92
+ $m.rel('customer', 'cloud', 'uses services'),
93
+ $m.rel('customer', 'cloud.frontend.mobile', 'opens mobile app'),
94
+ $m.rel('customer', 'cloud.frontend.dashboard', 'opens in browser'),
95
+ $m.rel('cloud.frontend.dashboard', 'cloud.auth', {
96
+ title: 'authenticates',
97
+ color: 'green',
98
+ }),
99
+ $m.rel('cloud.frontend.dashboard', 'cloud.backend.api', 'fetches data'),
100
+ $m.rel('cloud.frontend.dashboard', 'cloud.media', 'fetches media'),
101
+ $m.rel('cloud.frontend.mobile', 'cloud.auth', {
102
+ title: 'authenticates',
103
+ color: 'amber',
104
+ }),
105
+ $m.rel('cloud.frontend.mobile', 'cloud.backend.api', 'fetches data'),
106
+ $m.rel('cloud.frontend.mobile', 'cloud.media', 'fetches media'),
107
+ $m.rel('cloud.backend.api', 'cloud.auth', 'authorizes'),
108
+ $m.rel('cloud.backend.api', 'cloud.media', 'uploads media'),
109
+ $m.rel('cloud.backend.api', 'aws.rds', 'reads/writes'),
110
+ $m.rel('cloud.backend.api', 'email', 'sends emails'),
111
+ $m.rel('cloud.media', 'aws.s3', 'uploads'),
112
+ $m.rel('email', 'customer', 'sends emails'),
113
+ ),
114
+ deployment(
115
+ node('customer').with(
116
+ instanceOf('instance', 'customer'),
117
+ ),
118
+ env('prod').with(
119
+ zone('eu').with(
120
+ zone('zone1').with(
121
+ instanceOf('api', 'cloud.backend.api'),
122
+ instanceOf('ui', 'cloud.frontend.dashboard'),
123
+ ),
124
+ zone('zone2').with(
125
+ instanceOf('api', 'cloud.backend.api'),
126
+ instanceOf('ui', 'cloud.frontend.dashboard'),
127
+ ),
128
+ instanceOf('auth', 'cloud.auth'),
129
+ instanceOf('media', 'cloud.media'),
130
+ instanceOf('db', 'aws.rds'),
131
+ ),
132
+ zone('us').with(
133
+ zone('zone1').with(
134
+ instanceOf('api', 'cloud.backend.api'),
135
+ instanceOf('ui', 'cloud.frontend.dashboard'),
136
+ ),
137
+ instanceOf('db', 'aws.rds'),
138
+ ),
139
+ ),
140
+ env('acc').with(
141
+ node('testCustomer').with(
142
+ instanceOf('instance', 'customer'),
143
+ ),
144
+ zone('eu').with(
145
+ instanceOf('api', 'cloud.backend.api'),
146
+ instanceOf('ui', 'cloud.frontend.dashboard'),
147
+ instanceOf('auth', 'cloud.auth'),
148
+ instanceOf('db', 'aws.rds'),
149
+ ),
150
+ ),
151
+ env('global').with(
152
+ instanceOf('email', 'email'),
153
+ ),
154
+ $d.rel('prod.eu.db', 'prod.us.db', {
155
+ title: 'replicates',
156
+ color: 'green',
157
+ }),
158
+ $d.rel('prod.us.db', 'prod.eu.db', {
159
+ title: 'replicates',
160
+ color: 'amber',
161
+ }),
162
+ ),
163
+ )
164
+ .clone()
165
+
166
+ export type Types = typeof builder['Types']
167
+
168
+ export { $exclude, $include }
169
+
170
+ export function computeView(...rules: DeploymentRulesBuilderOp<Types>[]) {
171
+ const modelsource = builder.clone()
172
+ .with(
173
+ views(
174
+ deploymentView('index', $rules(...rules)),
175
+ ),
176
+ ).build()
177
+
178
+ const model = LikeC4Model.create({
179
+ ...modelsource,
180
+ views: {},
181
+ })
182
+
183
+ const view = withReadableEdges(computeDeploymentView(model, modelsource.views.index as DeploymentView))
184
+
185
+ return Object.assign(view, {
186
+ nodeIds: map(view.nodes, prop('id')) as string[],
187
+ edgeIds: map(view.edges, prop('id')) as string[],
188
+ })
189
+ }
190
+
191
+ export function computeNodesAndEdges(...rules: DeploymentRulesBuilderOp<Types>[]) {
192
+ const { nodeIds, edgeIds } = computeView(...rules)
193
+ return {
194
+ // Starts with capital letter to be first in snapshot
195
+ Nodes: nodeIds,
196
+ edges: edgeIds,
197
+ }
198
+ }
@@ -0,0 +1,37 @@
1
+ import { LikeC4DeploymentModel } from '../../model'
2
+ import type { RelationshipModel } from '../../model/RelationModel'
3
+ import type { ExpressionV2 } from '../../types'
4
+ import type { Ctx, Memory, Stage, StageExclude, StageInclude } from './memory'
5
+
6
+ export { Memory, type Stage } from './memory'
7
+
8
+ export type Where<T extends {}> = (x: T) => boolean
9
+
10
+ export type Elem = Ctx['Element']
11
+ export type Connection = Ctx['Connection']
12
+
13
+ export type ElementWhere = Where<Elem>
14
+ export type ElementWhereFilter = (elements: readonly Elem[]) => Elem[]
15
+ export type ConnectionWhere = Where<Connection>
16
+ export type RelationshipWhere = Where<RelationshipModel>
17
+ export type ConnectionWhereFilter = (connections: readonly Connection[]) => Connection[]
18
+
19
+ export type Connections = ReadonlyArray<Connection>
20
+
21
+ export interface PredicateCtx<Expr extends ExpressionV2 = ExpressionV2> {
22
+ expr: Expr
23
+ stage: Stage
24
+ model: LikeC4DeploymentModel
25
+ memory: Memory
26
+ }
27
+ export interface IncludePredicateCtx<Expr extends ExpressionV2 = ExpressionV2> extends PredicateCtx<Expr> {
28
+ stage: StageInclude
29
+ }
30
+ export interface ExcludePredicateCtx<Expr extends ExpressionV2 = ExpressionV2> extends PredicateCtx<Expr> {
31
+ stage: StageExclude
32
+ }
33
+
34
+ export interface PredicateExecutor<Expr extends ExpressionV2> {
35
+ include(ctx: IncludePredicateCtx<Expr>): StageInclude | undefined
36
+ exclude(ctx: ExcludePredicateCtx<Expr>): StageExclude | undefined
37
+ }