@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,85 @@
1
+ import { isEmpty } from 'remeda'
2
+ import type { IteratorLike } from '../types'
3
+ import type { Link, Tag } from '../types/element'
4
+ import type { ModelRelation } from '../types/relation'
5
+ import { commonAncestor } from '../utils/fqn'
6
+ import type { ElementModel } from './ElementModel'
7
+ import type { LikeC4Model } from './LikeC4Model'
8
+ import type { AnyAux } from './types'
9
+ import type { LikeC4ViewModel, ViewsIterator } from './view/LikeC4ViewModel'
10
+
11
+ export type RelationshipsIterator<M extends AnyAux> = IteratorLike<RelationshipModel<M>>
12
+
13
+ export class RelationshipModel<M extends AnyAux = AnyAux> {
14
+ public readonly source: ElementModel<M>
15
+ public readonly target: ElementModel<M>
16
+
17
+ /**
18
+ * Common ancestor of the source and target elements.
19
+ * Represents the boundary of the Relation.
20
+ */
21
+ public readonly boundary: ElementModel<M> | null
22
+
23
+ constructor(
24
+ public readonly model: LikeC4Model<M>,
25
+ public readonly $relationship: ModelRelation,
26
+ ) {
27
+ this.source = model.element($relationship.source)
28
+ this.target = model.element($relationship.target)
29
+ const parent = commonAncestor(this.source.id, this.target.id)
30
+ this.boundary = parent ? this.model.element(parent) : null
31
+ }
32
+
33
+ get id(): M['RelationId'] {
34
+ return this.$relationship.id
35
+ }
36
+
37
+ get expression(): string {
38
+ return `${this.source.id} -> ${this.target.id}`
39
+ }
40
+
41
+ get title(): string | null {
42
+ if (isEmpty(this.$relationship.title)) {
43
+ return null
44
+ }
45
+ return this.$relationship.title
46
+ }
47
+
48
+ get technology(): string | null {
49
+ if (isEmpty(this.$relationship.technology)) {
50
+ return null
51
+ }
52
+ return this.$relationship.technology
53
+ }
54
+
55
+ get description(): string | null {
56
+ if (isEmpty(this.$relationship.description)) {
57
+ return null
58
+ }
59
+ return this.$relationship.description
60
+ }
61
+
62
+ get navigateTo(): LikeC4ViewModel<M> | null {
63
+ return this.$relationship.navigateTo ? this.model.view(this.$relationship.navigateTo) : null
64
+ }
65
+
66
+ get tags(): ReadonlyArray<Tag> {
67
+ return this.$relationship.tags ?? []
68
+ }
69
+
70
+ get links(): ReadonlyArray<Link> {
71
+ return this.$relationship.links ?? []
72
+ }
73
+
74
+ /**
75
+ * Iterate over all views that include this relationship.
76
+ */
77
+ public *views(): ViewsIterator<M> {
78
+ for (const view of this.model.views()) {
79
+ if (view.includesRelation(this.id)) {
80
+ yield view
81
+ }
82
+ }
83
+ return
84
+ }
85
+ }
@@ -1,343 +1,154 @@
1
- import { mapToObj } from 'remeda'
2
- import type { LiteralUnion, Tagged, UnwrapTagged } from 'type-fest'
3
- import {
4
- type ComputedLikeC4Model,
5
- type Element,
6
- type ElementKindSpecification,
7
- type NonEmptyArray,
8
- type Relation,
9
- type RelationshipArrowType,
10
- type RelationshipLineType,
11
- type Tag,
12
- type ThemeColor
13
- } from '../../types'
14
-
15
- /**
16
- ┌──────────────────────────────────────────────────┐
17
- │ cloud │
18
- │ ┌───────────────────────────────────────────┐ │
19
- │ │ frontend │ │
20
- ┏━━━━━━━━━━┓ │ │ ┏━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━━━━┓ │ │ ┏━━━━━━━━━━━┓
21
- ┃ ┃ │ │ ┃ ┃ ┃ ┃ │ │ ┃ ┃
22
- ┃ customer ┃──┼──┼──▶┃ dashboard ┃ ┃ adminpanel ┃◀───┼───┼───┃ support ┃
23
- ┃ ┃ │ │ ┃ ┃ ┃ ┃ │ │ ┃ ┃
24
- ┗━━━━━━━━━━┛ │ │ ┗━━━━━━┳━━━━━━┛ ┗━━━━━━━━┳━━━━━━━┛ │ │ ┗━━━━━━━━━━━┛
25
- │ └──────────┼───────────────────┼────────────┘ │
26
- │ ├───────────────────┘ │
27
- │ │ │
28
- │ ┌──────────┼────────────────────────────────┐ │
29
- │ │ ▼ backend │ │
30
- │ ┏━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━━━┓ │ │
31
- │ │ ┃ ┃ ┃ ┃ │ │
32
- │ ┃ graphlql ┃──────▶┃ storage ┃ │ │
33
- │ │ ┃ ┃ ┃ ┃ │ │
34
- │ │ ┗━━━━━━━━━━━━━┛ ┗━━━━━━┳━━━━━━┛ │ │
35
- │ └────────────────────────────────┼──────────┘ │
36
- └───────────────────────────────────┼──────────────┘
37
-
38
- ┌─────────┼─────────┐
39
- │ amazon │ │
40
- │ ▼ │
41
- │ ┏━━━━━━━━━━━━━━┓ │
42
- │ ┃ ┃ │
43
- │ ┃ s3 ┃ │
44
- │ ┃ ┃ │
45
- │ ┗━━━━━━━━━━━━━━┛ │
46
- └───────────────────┘
47
-
48
- specification {
49
- element actor
50
- element system
51
- element container
52
- element component
53
-
54
- tag old
55
- }
56
-
57
- model {
58
-
59
- actor customer
60
- actor support
61
-
62
- system cloud {
63
- container backend {
64
- component graphql
65
- component storage {
66
- #old
67
- }
68
-
69
- graphql -> storage
70
- }
71
-
72
- container frontend {
73
- component dashboard {
74
- -> graphql
1
+ import { Builder } from '../../builder/Builder'
2
+ import { computeViews } from '../../compute-view/compute-view'
3
+ import { LikeC4Model } from '../LikeC4Model'
4
+
5
+ const {
6
+ builder: b,
7
+ model: {
8
+ person,
9
+ system,
10
+ component,
11
+ webapp,
12
+ mobile,
13
+ ...$m
14
+ },
15
+ deployment: {
16
+ deployment,
17
+ env,
18
+ node,
19
+ zone,
20
+ instanceOf,
21
+ ...$d
22
+ },
23
+ views: {
24
+ view,
25
+ views,
26
+ viewOf,
27
+ deploymentView,
28
+ $rules,
29
+ $include
30
+ }
31
+ } = Builder.forSpecification({
32
+ elements: {
33
+ person: {
34
+ style: {
35
+ shape: 'person'
75
36
  }
76
- component adminPanel {
77
- #old
78
- -> graphql
37
+ },
38
+ system: {},
39
+ component: {},
40
+ webapp: {
41
+ style: {
42
+ shape: 'browser'
79
43
  }
80
- }
81
- }
82
-
83
- customer -> dashboard
84
- support -> adminPanel
85
-
86
- system amazon {
87
- component s3
88
-
89
- cloud.backend.storage -> s3
90
- }
91
-
92
- }
93
-
94
- */
95
- type TestTag = 'old' | 'next' | 'aws' | 'storage' | 'communication' | 'legacy'
96
-
97
- const el = <Id extends string, Kind extends string>({
98
- id,
99
- kind,
100
- title,
101
- style,
102
- tags,
103
- ...props
104
- }: Partial<Omit<Element, 'id' | 'kind' | 'tags'>> & {
105
- id: Id
106
- kind: Kind
107
- tags?: NonEmptyArray<TestTag>
108
- }) =>
109
- ({
110
- id: id as Tagged<Id, 'Fqn'>,
111
- kind: kind as Tagged<Kind, 'ElementKind'>,
112
- title: title ?? id,
113
- description: null,
114
- technology: null,
115
- tags: tags as NonEmptyArray<Tag> ?? null,
116
- links: null,
117
- style: {
118
- ...style
119
44
  },
120
- ...props
121
- }) satisfies Element
122
-
123
- const fakeElementsArr = [
124
- el({
125
- id: 'customer',
126
- kind: 'actor',
127
- title: 'customer',
128
- shape: 'person'
129
- }),
130
- el({
131
- id: 'support',
132
- kind: 'actor',
133
- title: 'support',
134
- shape: 'person'
135
- }),
136
- el({
137
- id: 'cloud',
138
- kind: 'system',
139
- title: 'cloud',
140
- tags: ['next', 'old']
141
- }),
142
- el({
143
- id: 'cloud.backend',
144
- kind: 'container',
145
- title: 'backend'
146
- }),
147
- el({
148
- id: 'cloud.frontend',
149
- kind: 'container',
150
- title: 'frontend',
151
- shape: 'browser'
152
- }),
153
- el({
154
- id: 'cloud.backend.graphql',
155
- kind: 'component',
156
- title: 'graphql'
157
- }),
158
- el({
159
- id: 'email',
160
- kind: 'system',
161
- title: 'email'
162
- }),
163
- el({
164
- id: 'cloud.backend.storage',
165
- kind: 'component',
166
- title: 'storage',
167
- tags: ['storage', 'old']
168
- }),
169
- el({
170
- id: 'cloud.frontend.adminPanel',
171
- kind: 'component',
172
- title: 'adminPanel',
173
- tags: ['old']
174
- }),
175
- el({
176
- id: 'cloud.frontend.dashboard',
177
- kind: 'component',
178
- title: 'dashboard',
179
- tags: ['next']
180
- }),
181
- el({
182
- id: 'amazon',
183
- kind: 'system',
184
- title: 'amazon',
185
- tags: ['aws']
186
- }),
187
- el({
188
- id: 'amazon.s3',
189
- kind: 'component',
190
- title: 's3',
191
- shape: 'storage',
192
- tags: ['aws', 'storage']
193
- })
194
- ] as const
195
-
196
- export type FakeElementIds = UnwrapTagged<(typeof fakeElementsArr)[number]['id']>
197
- export type FakeElementKinds = UnwrapTagged<(typeof fakeElementsArr)[number]['kind']>
198
-
199
- export const fakeElements = mapToObj(fakeElementsArr, e => [e.id as FakeElementIds, e])
200
-
201
- const rel = <Source extends FakeElementIds, Target extends FakeElementIds, Kind extends string>({
202
- source,
203
- target,
204
- title,
205
- kind,
206
- tags,
207
- ...props
208
- }: {
209
- source: LiteralUnion<Source, string>
210
- target: LiteralUnion<Target, string>
211
- title?: string
212
- kind?: LiteralUnion<Kind, string>
213
- color?: ThemeColor
214
- line?: RelationshipLineType
215
- head?: RelationshipArrowType
216
- tail?: RelationshipArrowType
217
- tags?: NonEmptyArray<TestTag>
218
- }) =>
219
- ({
220
- id: `${source}:${target}` as Tagged<`${Source}:${Target}`, 'RelationID'>,
221
- title: title ?? '',
222
- source: source as Tagged<Source, 'Fqn'>,
223
- target: target as Tagged<Target, 'Fqn'>,
224
- ...(kind ? { kind: kind as Tagged<Kind, 'RelationshipKind'> } : {}),
225
- tags: tags as NonEmptyArray<Tag> ?? null,
226
- ...props
227
- }) satisfies Relation
228
-
229
- const fakeRelationsArr = [
230
- rel({
231
- source: 'customer',
232
- target: 'cloud.frontend.dashboard',
233
- title: 'opens in browser'
234
- }),
235
- rel({
236
- source: 'support',
237
- target: 'cloud.frontend.adminPanel',
238
- title: 'manages'
239
- }),
240
- rel({
241
- source: 'cloud.backend.storage',
242
- target: 'amazon.s3',
243
- title: 'uploads',
244
- tags: ['aws', 'storage', 'legacy']
245
- }),
246
- rel({
247
- source: 'customer',
248
- target: 'cloud',
249
- title: 'uses'
250
- }),
251
- rel({
252
- source: 'customer',
253
- target: 'cloud.frontend',
254
- title: 'uses frontend'
255
- }),
256
- rel({
257
- source: 'cloud.backend.graphql',
258
- target: 'cloud.backend.storage',
259
- title: 'stores',
260
- tags: ['old', 'storage']
261
- }),
262
- rel({
263
- source: 'cloud.frontend',
264
- target: 'cloud.backend',
265
- title: 'requests'
266
- }),
267
- rel({
268
- source: 'cloud.frontend.dashboard',
269
- target: 'cloud.backend.graphql',
270
- kind: 'graphlql',
271
- title: 'requests',
272
- line: 'solid',
273
- tags: ['next']
274
- }),
275
- rel({
276
- source: 'cloud.frontend.adminPanel',
277
- target: 'cloud.backend.graphql',
278
- kind: 'graphlql',
279
- title: 'fetches',
280
- line: 'dashed',
281
- tail: 'odiamond',
282
- tags: ['old']
283
- }),
284
- rel({
285
- source: 'cloud',
286
- target: 'amazon',
287
- title: 'uses',
288
- head: 'diamond',
289
- tail: 'odiamond',
290
- tags: ['aws']
291
- }),
292
- rel({
293
- source: 'cloud.backend',
294
- target: 'email',
295
- title: 'schedule',
296
- tags: ['communication']
297
- }),
298
- rel({
299
- source: 'cloud',
300
- target: 'email',
301
- title: 'uses',
302
- tags: ['communication']
303
- }),
304
- rel({
305
- source: 'email',
306
- target: 'cloud',
307
- title: 'notifies',
308
- tags: ['communication']
309
- })
310
- ] as const
311
-
312
- export type FakeRelationIds = UnwrapTagged<(typeof fakeRelationsArr)[number]['id']>
313
-
314
- export const fakeRelations = mapToObj(fakeRelationsArr, r => [r.id as FakeRelationIds, r])
315
-
316
- export const fakeComputedModel = {
317
- specification: {
318
- tags: [],
319
- relationships: {},
320
- elements: {
321
- actor: {
322
- style: {}
323
- },
324
- system: {
325
- style: {}
326
- },
327
- container: {
328
- style: {}
329
- },
330
- component: {
331
- style: {}
45
+ mobile: {
46
+ style: {
47
+ shape: 'mobile'
332
48
  }
333
- } satisfies Record<FakeElementKinds, ElementKindSpecification>
334
- },
335
- elements: fakeElements,
336
- relations: fakeRelations,
337
- globals: {
338
- predicates: {},
339
- dynamicPredicates: {},
340
- styles: {}
49
+ }
341
50
  },
342
- views: {}
343
- } satisfies ComputedLikeC4Model
51
+ deployments: {
52
+ env: {},
53
+ zone: {},
54
+ node: {}
55
+ }
56
+ })
57
+
58
+ const local = b
59
+ .with(
60
+ $m.model(
61
+ person('customer'),
62
+ system('cloud').with(
63
+ component('frontend').with(
64
+ webapp('dashboard'),
65
+ mobile('mobile')
66
+ ),
67
+ component('auth'),
68
+ component('backend').with(
69
+ component('api'),
70
+ component('graphql')
71
+ ),
72
+ component('media', {
73
+ shape: 'storage'
74
+ })
75
+ ),
76
+ system('aws').with(
77
+ component('rds', {
78
+ shape: 'storage'
79
+ }),
80
+ component('s3', {
81
+ shape: 'storage'
82
+ })
83
+ ),
84
+ system('email')
85
+ ),
86
+ $m.model(
87
+ $m.rel('customer', 'cloud', 'uses services'),
88
+ $m.rel('customer', 'cloud.frontend.mobile', 'opens mobile app'),
89
+ $m.rel('customer', 'cloud.frontend.dashboard', 'opens in browser'),
90
+ $m.rel('cloud.frontend.dashboard', 'cloud.auth', 'authenticates'),
91
+ $m.rel('cloud.frontend.dashboard', 'cloud.backend.api', 'fetches data'),
92
+ $m.rel('cloud.frontend.dashboard', 'cloud.media', 'fetches media'),
93
+ $m.rel('cloud.frontend.mobile', 'cloud.auth', 'authenticates'),
94
+ $m.rel('cloud.frontend.mobile', 'cloud.backend.api', 'fetches data'),
95
+ $m.rel('cloud.frontend.mobile', 'cloud.media', 'fetches media'),
96
+ $m.rel('cloud.frontend', 'cloud.backend')
97
+ ),
98
+ $m.model(
99
+ $m.rel('cloud.backend.api', 'cloud.auth', 'authorizes'),
100
+ $m.rel('cloud.backend.api', 'cloud.media', 'uploads media'),
101
+ $m.rel('cloud.backend.api', 'aws.rds', 'reads/writes'),
102
+ $m.rel('cloud.backend.api', 'email', 'sends emails'),
103
+ $m.rel('cloud', 'email', 'uses'),
104
+ $m.rel('cloud.media', 'aws.s3', 'uploads'),
105
+ $m.rel('email', 'customer', 'sends emails')
106
+ ),
107
+ deployment(
108
+ node('customer').with(
109
+ instanceOf('instance', 'customer')
110
+ ),
111
+ env('prod').with(
112
+ zone('eu').with(
113
+ zone('zone1').with(
114
+ instanceOf('ui', 'cloud.frontend.dashboard'),
115
+ instanceOf('api', 'cloud.backend.api')
116
+ ),
117
+ zone('zone2').with(
118
+ instanceOf('ui', 'cloud.frontend.dashboard'),
119
+ instanceOf('api', 'cloud.backend.api')
120
+ ),
121
+ instanceOf('media', 'cloud.media'),
122
+ instanceOf('db', 'aws.rds')
123
+ ),
124
+ zone('us').with(
125
+ instanceOf('db', 'aws.rds')
126
+ )
127
+ ),
128
+ $d.rel('prod.eu.db', 'prod.us.db', 'replicates')
129
+ ),
130
+ views(
131
+ view('index', $include('*')),
132
+ viewOf(
133
+ 'cloud',
134
+ 'cloud',
135
+ $rules(
136
+ $include('*'),
137
+ $include('cloud.frontend.dashboard')
138
+ )
139
+ ),
140
+ deploymentView('prod').with(
141
+ $include('customer.instance'),
142
+ $include('prod.eu.zone1.ui')
143
+ )
144
+ )
145
+ )
146
+
147
+ export const builder = local.clone()
148
+
149
+ export const parsed = local.build()
150
+ export type TestFqn = typeof local.Types.Fqn
151
+
152
+ export const computed = computeViews(parsed)
153
+
154
+ export const model = LikeC4Model.create(computed)
@@ -0,0 +1,72 @@
1
+ import type { Fqn } from '../../types'
2
+ import { isAncestor } from '../../utils'
3
+ import type { DeploymentElementModel } from '../DeploymentElementModel'
4
+ import type { ElementModel } from '../ElementModel'
5
+
6
+ export interface Connection<Elem = ElementModel | DeploymentElementModel, Id = string> {
7
+ readonly id: Id
8
+ readonly source: Elem
9
+ readonly target: Elem
10
+
11
+ /**
12
+ * Common ancestor of the source and target elements.
13
+ * Represents the boundary of the connection.
14
+ */
15
+ readonly boundary: Elem | null
16
+
17
+ /**
18
+ * Human readable expression of the connection
19
+ * Mostly used for testing and debugging
20
+ */
21
+ readonly expression: string
22
+
23
+ mergeWith(this: Connection<Elem, Id>, other: typeof this): typeof this
24
+
25
+ nonEmpty(): boolean
26
+
27
+ difference(this: Connection<Elem, Id>, other: typeof this): typeof this
28
+
29
+ intersect(this: Connection<Elem, Id>, other: typeof this): typeof this
30
+
31
+ equals(other: Connection): boolean
32
+ }
33
+
34
+ export namespace Connection {
35
+ type ConnectionPredicate = <C extends Connection<{ id: string }, any>>(connection: C) => boolean
36
+
37
+ type ElementId = Fqn | string
38
+
39
+ export const isInside = (fqn: ElementId): ConnectionPredicate => {
40
+ return (connection) => isAncestor(fqn, connection.source.id) && isAncestor(fqn, connection.target.id)
41
+ }
42
+
43
+ export const isDirectedBetween = (source: ElementId, target: ElementId): ConnectionPredicate => {
44
+ return (connection) =>
45
+ (connection.source.id === source || isAncestor(source, connection.source.id))
46
+ && (connection.target.id === target || isAncestor(target, connection.target.id))
47
+ }
48
+
49
+ export const isAnyBetween = (source: ElementId, target: ElementId): ConnectionPredicate => {
50
+ const forward = isDirectedBetween(source, target),
51
+ backward = isDirectedBetween(target, source)
52
+ return (connection) => forward(connection) || backward(connection)
53
+ }
54
+
55
+ export const isIncoming = (target: ElementId): ConnectionPredicate => {
56
+ return (connection) =>
57
+ (connection.target.id === target || isAncestor(target, connection.target.id))
58
+ && !isAncestor(target, connection.source.id)
59
+ }
60
+
61
+ export const isOutgoing = (source: ElementId): ConnectionPredicate => {
62
+ return (connection) =>
63
+ (connection.source.id === source || isAncestor(source, connection.source.id))
64
+ && !isAncestor(source, connection.target.id)
65
+ }
66
+
67
+ export const isAnyInOut = (source: ElementId): ConnectionPredicate => {
68
+ const isIn = isIncoming(source),
69
+ isOut = isOutgoing(source)
70
+ return (connection) => isIn(connection) || isOut(connection)
71
+ }
72
+ }