@likec4/core 1.17.1 → 1.18.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.
- package/dist/compute-view/index.d.mts +91 -0
- package/dist/compute-view/index.d.ts +91 -0
- package/dist/compute-view/index.mjs +79 -0
- package/dist/index.d.mts +246 -434
- package/dist/index.d.ts +246 -434
- package/dist/index.mjs +418 -1322
- package/dist/model/index.d.mts +642 -0
- package/dist/model/index.d.ts +642 -0
- package/dist/model/index.mjs +2 -0
- package/dist/shared/core.BBgiAAv1.mjs +144 -0
- package/dist/shared/core.BPyJvuMU.mjs +2420 -0
- package/dist/shared/core.BQ4AbfvB.mjs +9228 -0
- package/dist/shared/{core.CoLQkcYL.d.mts → core.DMYY7C8s.d.mts} +398 -249
- package/dist/shared/{core.CoLQkcYL.d.ts → core.DMYY7C8s.d.ts} +398 -249
- package/dist/shared/core.k12s_keD.mjs +203 -0
- package/dist/types/index.d.mts +69 -1
- package/dist/types/index.d.ts +69 -1
- package/dist/types/index.mjs +21 -1
- package/package.json +38 -40
- package/src/builder/Builder.deployment.ts +219 -0
- package/src/builder/Builder.deploymentModel.ts +360 -0
- package/src/builder/Builder.element.ts +17 -19
- package/src/builder/Builder.model.ts +13 -2
- package/src/builder/Builder.test-d.ts +59 -4
- package/src/builder/Builder.ts +238 -53
- package/src/builder/Builder.view.ts +238 -53
- package/src/builder/_types.ts +87 -15
- package/src/compute-view/LikeC4ModelGraph.ts +330 -0
- package/src/compute-view/compute-view.ts +92 -0
- package/src/compute-view/deployment-view/Memory.ts +108 -0
- package/src/compute-view/deployment-view/Stage.ts +145 -0
- package/src/compute-view/deployment-view/__test__/fixture.ts +210 -0
- package/src/compute-view/deployment-view/_types.ts +29 -0
- package/src/compute-view/deployment-view/clean-connections.ts +229 -0
- package/src/compute-view/deployment-view/compute.ts +111 -0
- package/src/compute-view/deployment-view/predicates/deployment-ref.ts +146 -0
- package/src/compute-view/deployment-view/predicates/relation-direct.ts +130 -0
- package/src/compute-view/deployment-view/predicates/relation-in-out.ts +43 -0
- package/src/compute-view/deployment-view/predicates/relation-incoming.ts +46 -0
- package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +49 -0
- package/src/compute-view/deployment-view/predicates/wildcard.ts +29 -0
- package/src/compute-view/deployment-view/utils.ts +212 -0
- package/src/compute-view/dynamic-view/__test__/fixture.ts +58 -0
- package/src/compute-view/dynamic-view/compute.ts +310 -0
- package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +456 -0
- package/src/compute-view/element-view/__test__/fixture.ts +645 -0
- package/src/compute-view/element-view/compute.ts +734 -0
- package/src/compute-view/element-view/predicates.ts +517 -0
- package/src/compute-view/index.ts +5 -0
- package/src/compute-view/utils/__snapshots__/sortNodes.spec.ts.snap +113 -0
- package/src/compute-view/utils/ancestorsOfNode.ts +19 -0
- package/src/compute-view/utils/applyCustomElementProperties.ts +66 -0
- package/src/compute-view/utils/applyCustomRelationProperties.ts +41 -0
- package/src/compute-view/utils/applyViewRuleStyles.ts +53 -0
- package/src/compute-view/utils/buildComputedNodes.ts +148 -0
- package/src/compute-view/utils/buildElementNotations.ts +63 -0
- package/src/compute-view/utils/derive-edge-props-from-relationships.ts +97 -0
- package/src/compute-view/utils/elementExpressionToPredicate.ts +52 -0
- package/src/compute-view/utils/link-nodes-with-edges.ts +58 -0
- package/src/compute-view/utils/relationExpressionToPredicates.ts +55 -0
- package/src/compute-view/utils/resolve-extended-views.ts +65 -0
- package/src/compute-view/utils/resolve-global-rules.ts +83 -0
- package/src/compute-view/utils/sortNodes.ts +101 -0
- package/src/compute-view/utils/topological-sort.ts +160 -0
- package/src/compute-view/utils/uniqueTags.test.ts +42 -0
- package/src/compute-view/utils/uniqueTags.ts +21 -0
- package/src/compute-view/utils/view-hash.ts +27 -0
- package/src/compute-view/utils/with-readable-edges.ts +31 -0
- package/src/index.ts +5 -1
- package/src/model/DeploymentElementModel.ts +534 -0
- package/src/model/DeploymentModel.ts +364 -0
- package/src/model/ElementModel.ts +195 -0
- package/src/model/LikeC4Model.test-d.ts +151 -0
- package/src/model/LikeC4Model.ts +280 -457
- package/src/model/RelationModel.ts +84 -0
- package/src/model/__test__/fixture.ts +153 -338
- package/src/model/connection/ConnectionModel.ts +94 -0
- package/src/model/connection/DeploymentConnectionModel.ts +99 -0
- package/src/model/connection/deployment.ts +124 -0
- package/src/model/connection/model.ts +123 -0
- package/src/model/index.ts +4 -2
- package/src/model/types.ts +95 -15
- package/src/model/view/EdgeModel.ts +103 -0
- package/src/model/view/LikeC4ViewModel.ts +220 -0
- package/src/model/view/NodeModel.ts +228 -0
- package/src/types/_common.ts +2 -0
- package/src/types/deployments.ts +237 -0
- package/src/types/element.ts +7 -3
- package/src/types/expression.ts +8 -6
- package/src/types/index.ts +1 -0
- package/src/types/model.ts +68 -9
- package/src/types/overview-graph.ts +2 -2
- package/src/types/relation.ts +4 -4
- package/src/types/view-notation.ts +2 -2
- package/src/types/view.ts +104 -30
- package/src/utils/{commonHead.ts → common-head.ts} +2 -0
- package/src/utils/fqn.ts +83 -27
- package/src/utils/getOrCreate.ts +42 -0
- package/src/utils/graphlib.ts +10 -0
- package/src/utils/index.ts +4 -1
- package/src/utils/object-hash.ts +3 -0
- package/src/utils/set.ts +76 -0
- package/src/utils/string-hash.ts +16 -0
- package/dist/index.cjs +0 -5452
- package/dist/index.d.cts +0 -1053
- package/dist/shared/core.BXTs-8n7.mjs +0 -293
- package/dist/shared/core.CoLQkcYL.d.cts +0 -734
- package/dist/shared/core.DIYZvpVg.cjs +0 -353
- package/dist/types/index.cjs +0 -70
- package/dist/types/index.d.cts +0 -2
- package/src/model/LikeC4DiagramModel.ts +0 -338
- package/src/model/LikeC4ViewModel.ts +0 -320
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { isEmpty } from 'remeda'
|
|
2
|
+
import type { Link, Tag } from '../types/element'
|
|
3
|
+
import type { Relation } from '../types/relation'
|
|
4
|
+
import { commonAncestor } from '../utils/fqn'
|
|
5
|
+
import type { ElementModel } from './ElementModel'
|
|
6
|
+
import type { LikeC4Model } from './LikeC4Model'
|
|
7
|
+
import type { AnyAux, IteratorLike } from './types'
|
|
8
|
+
import type { LikeC4ViewModel, ViewsIterator } from './view/LikeC4ViewModel'
|
|
9
|
+
|
|
10
|
+
export type RelationshipsIterator<M extends AnyAux> = IteratorLike<RelationshipModel<M>>
|
|
11
|
+
|
|
12
|
+
export class RelationshipModel<M extends AnyAux> {
|
|
13
|
+
public readonly source: ElementModel<M>
|
|
14
|
+
public readonly target: ElementModel<M>
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Common ancestor of the source and target elements.
|
|
18
|
+
* Represents the boundary of the Relation.
|
|
19
|
+
*/
|
|
20
|
+
public readonly boundary: ElementModel<M> | null
|
|
21
|
+
|
|
22
|
+
constructor(
|
|
23
|
+
public readonly model: LikeC4Model<M>,
|
|
24
|
+
public readonly $relationship: Relation
|
|
25
|
+
) {
|
|
26
|
+
this.source = model.element($relationship.source)
|
|
27
|
+
this.target = model.element($relationship.target)
|
|
28
|
+
const parent = commonAncestor(this.source.id, this.target.id)
|
|
29
|
+
this.boundary = parent ? this.model.element(parent) : null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get id(): M['RelationId'] {
|
|
33
|
+
return this.$relationship.id
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get expression(): string {
|
|
37
|
+
return `${this.source.id} -> ${this.target.id}`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get title(): string | null {
|
|
41
|
+
if (isEmpty(this.$relationship.title)) {
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
44
|
+
return this.$relationship.title
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get technology(): string | null {
|
|
48
|
+
if (isEmpty(this.$relationship.technology)) {
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
51
|
+
return this.$relationship.technology
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get description(): string | null {
|
|
55
|
+
if (isEmpty(this.$relationship.description)) {
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
return this.$relationship.description
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get navigateTo(): LikeC4ViewModel<M> | null {
|
|
62
|
+
return this.$relationship.navigateTo ? this.model.view(this.$relationship.navigateTo) : null
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get tags(): ReadonlyArray<Tag> {
|
|
66
|
+
return this.$relationship.tags ?? []
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get links(): ReadonlyArray<Link> {
|
|
70
|
+
return this.$relationship.links ?? []
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Iterate over all views that include this relationship.
|
|
75
|
+
*/
|
|
76
|
+
public *views(): ViewsIterator<M> {
|
|
77
|
+
for (const view of this.model.views()) {
|
|
78
|
+
if (view.includesRelation(this.id)) {
|
|
79
|
+
yield view
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -1,343 +1,158 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
$exclude,
|
|
31
|
+
$style
|
|
32
|
+
}
|
|
33
|
+
} = Builder.forSpecification({
|
|
34
|
+
elements: {
|
|
35
|
+
person: {
|
|
36
|
+
style: {
|
|
37
|
+
shape: 'person'
|
|
75
38
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
39
|
+
},
|
|
40
|
+
system: {},
|
|
41
|
+
component: {},
|
|
42
|
+
webapp: {
|
|
43
|
+
style: {
|
|
44
|
+
shape: 'browser'
|
|
79
45
|
}
|
|
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
46
|
},
|
|
120
|
-
|
|
121
|
-
|
|
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: {}
|
|
47
|
+
mobile: {
|
|
48
|
+
style: {
|
|
49
|
+
shape: 'mobile'
|
|
332
50
|
}
|
|
333
|
-
}
|
|
334
|
-
},
|
|
335
|
-
elements: fakeElements,
|
|
336
|
-
relations: fakeRelations,
|
|
337
|
-
globals: {
|
|
338
|
-
predicates: {},
|
|
339
|
-
dynamicPredicates: {},
|
|
340
|
-
styles: {}
|
|
51
|
+
}
|
|
341
52
|
},
|
|
342
|
-
|
|
343
|
-
}
|
|
53
|
+
deployments: {
|
|
54
|
+
env: {},
|
|
55
|
+
zone: {},
|
|
56
|
+
node: {}
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
const local = b
|
|
61
|
+
.with(
|
|
62
|
+
$m.model(
|
|
63
|
+
person('customer'),
|
|
64
|
+
system('cloud').with(
|
|
65
|
+
component('frontend').with(
|
|
66
|
+
webapp('dashboard'),
|
|
67
|
+
mobile('mobile')
|
|
68
|
+
),
|
|
69
|
+
component('auth'),
|
|
70
|
+
component('backend').with(
|
|
71
|
+
component('api'),
|
|
72
|
+
component('graphql')
|
|
73
|
+
),
|
|
74
|
+
component('media', {
|
|
75
|
+
shape: 'storage'
|
|
76
|
+
})
|
|
77
|
+
),
|
|
78
|
+
system('aws').with(
|
|
79
|
+
component('rds', {
|
|
80
|
+
shape: 'storage'
|
|
81
|
+
}),
|
|
82
|
+
component('s3', {
|
|
83
|
+
shape: 'storage'
|
|
84
|
+
})
|
|
85
|
+
),
|
|
86
|
+
system('email')
|
|
87
|
+
),
|
|
88
|
+
$m.model(
|
|
89
|
+
$m.rel('customer', 'cloud', 'uses services'),
|
|
90
|
+
$m.rel('customer', 'cloud.frontend.mobile', 'opens mobile app'),
|
|
91
|
+
$m.rel('customer', 'cloud.frontend.dashboard', 'opens in browser'),
|
|
92
|
+
$m.rel('cloud.frontend.dashboard', 'cloud.auth', 'authenticates'),
|
|
93
|
+
$m.rel('cloud.frontend.dashboard', 'cloud.backend.api', 'fetches data'),
|
|
94
|
+
$m.rel('cloud.frontend.dashboard', 'cloud.media', 'fetches media'),
|
|
95
|
+
$m.rel('cloud.frontend.mobile', 'cloud.auth', 'authenticates'),
|
|
96
|
+
$m.rel('cloud.frontend.mobile', 'cloud.backend.api', 'fetches data'),
|
|
97
|
+
$m.rel('cloud.frontend.mobile', 'cloud.media', 'fetches media'),
|
|
98
|
+
$m.rel('cloud.frontend', 'cloud.backend')
|
|
99
|
+
),
|
|
100
|
+
$m.model(
|
|
101
|
+
$m.rel('cloud.backend.api', 'cloud.auth', 'authorizes'),
|
|
102
|
+
$m.rel('cloud.backend.api', 'cloud.media', 'uploads media'),
|
|
103
|
+
$m.rel('cloud.backend.api', 'aws.rds', 'reads/writes'),
|
|
104
|
+
$m.rel('cloud.backend.api', 'email', 'sends emails'),
|
|
105
|
+
$m.rel('cloud.media', 'aws.s3', 'uploads'),
|
|
106
|
+
$m.rel('email', 'customer', 'sends emails')
|
|
107
|
+
),
|
|
108
|
+
deployment(
|
|
109
|
+
node('customer').with(
|
|
110
|
+
instanceOf('instance', 'customer')
|
|
111
|
+
),
|
|
112
|
+
env('prod').with(
|
|
113
|
+
zone('eu').with(
|
|
114
|
+
zone('zone1').with(
|
|
115
|
+
instanceOf('ui', 'cloud.frontend.dashboard'),
|
|
116
|
+
instanceOf('api', 'cloud.backend.api')
|
|
117
|
+
),
|
|
118
|
+
zone('zone2').with(
|
|
119
|
+
instanceOf('ui', 'cloud.frontend.dashboard'),
|
|
120
|
+
instanceOf('api', 'cloud.backend.api')
|
|
121
|
+
),
|
|
122
|
+
instanceOf('media', 'cloud.media'),
|
|
123
|
+
instanceOf('db', 'aws.rds')
|
|
124
|
+
),
|
|
125
|
+
zone('us').with(
|
|
126
|
+
instanceOf('db', 'aws.rds')
|
|
127
|
+
)
|
|
128
|
+
),
|
|
129
|
+
$d.rel('prod.eu.db', 'prod.us.db', 'replicates')
|
|
130
|
+
),
|
|
131
|
+
views(
|
|
132
|
+
view('index', $include('*')),
|
|
133
|
+
viewOf(
|
|
134
|
+
'cloud',
|
|
135
|
+
'cloud',
|
|
136
|
+
$rules(
|
|
137
|
+
$include('*'),
|
|
138
|
+
$include('cloud.frontend.dashboard')
|
|
139
|
+
)
|
|
140
|
+
),
|
|
141
|
+
deploymentView(
|
|
142
|
+
'prod',
|
|
143
|
+
$rules(
|
|
144
|
+
$include('customer.instance'),
|
|
145
|
+
$include('prod.eu.zone1.ui')
|
|
146
|
+
)
|
|
147
|
+
)
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
export const builder = local.clone()
|
|
152
|
+
|
|
153
|
+
export const parsed = local.build()
|
|
154
|
+
export type TestFqn = typeof local.Types.Fqn
|
|
155
|
+
|
|
156
|
+
export const computed = computeViews(parsed)
|
|
157
|
+
|
|
158
|
+
export const model = LikeC4Model.create(computed)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { invariant } from '../../errors'
|
|
2
|
+
import { difference, equals, union } from '../../utils/set'
|
|
3
|
+
import { stringHash } from '../../utils/string-hash'
|
|
4
|
+
import type { ElementModel } from '../ElementModel'
|
|
5
|
+
import type { RelationshipModel } from '../RelationModel'
|
|
6
|
+
import type { AnyAux } from '../types'
|
|
7
|
+
|
|
8
|
+
export interface Connection<Elem = any, Id = any> {
|
|
9
|
+
readonly id: Id
|
|
10
|
+
readonly source: Elem
|
|
11
|
+
readonly target: Elem
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Common ancestor of the source and target elements.
|
|
15
|
+
* Represents the boundary of the connection.
|
|
16
|
+
*/
|
|
17
|
+
readonly boundary: Elem | null
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Human readable expression of the connection
|
|
21
|
+
* Mostly used for testing and debugging
|
|
22
|
+
*/
|
|
23
|
+
readonly expression: string
|
|
24
|
+
|
|
25
|
+
mergeWith(this: Connection<any, any>, other: typeof this): typeof this
|
|
26
|
+
|
|
27
|
+
nonEmpty(): boolean
|
|
28
|
+
|
|
29
|
+
difference(this: Connection<Elem, Id>, other: Connection<Elem, Id>): typeof this
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Connection refers to any relationships between two elements,
|
|
34
|
+
* both direct and implicit ones (between their nested elements).
|
|
35
|
+
*
|
|
36
|
+
* Merges relationships together to an single edge on the diagram.
|
|
37
|
+
*/
|
|
38
|
+
export class ConnectionModel<M extends AnyAux = AnyAux> implements Connection<ElementModel<M>, M['EdgeId']> {
|
|
39
|
+
public readonly id: M['EdgeId']
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Common ancestor of the source and target elements.
|
|
43
|
+
* Represents the boundary of the connection.
|
|
44
|
+
*/
|
|
45
|
+
public readonly boundary: ElementModel<M> | null
|
|
46
|
+
|
|
47
|
+
constructor(
|
|
48
|
+
public readonly source: ElementModel<M>,
|
|
49
|
+
public readonly target: ElementModel<M>,
|
|
50
|
+
public readonly relations: ReadonlySet<RelationshipModel<M>>
|
|
51
|
+
) {
|
|
52
|
+
this.id = stringHash(`model:${source.id}:${target.id}`) as M['EdgeId']
|
|
53
|
+
this.boundary = source.commonAncestor(target)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Human readable expression of the connection
|
|
58
|
+
* Mostly used for testing and debugging
|
|
59
|
+
*/
|
|
60
|
+
get expression(): string {
|
|
61
|
+
return `${this.source.id} -> ${this.target.id}`
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
nonEmpty(): boolean {
|
|
65
|
+
return this.relations.size > 0
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
mergeWith(other: ConnectionModel<M>): ConnectionModel<M> {
|
|
69
|
+
invariant(this.source.id === other.source.id, 'Cannot merge connections with different sources')
|
|
70
|
+
invariant(this.target.id === other.target.id, 'Cannot merge connections with different targets')
|
|
71
|
+
return new ConnectionModel(
|
|
72
|
+
this.source,
|
|
73
|
+
this.target,
|
|
74
|
+
union(this.relations, other.relations)
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
difference(other: ConnectionModel<M>): ConnectionModel<M> {
|
|
79
|
+
invariant(this.source.id === other.source.id, 'Cannot difference connection with different sources')
|
|
80
|
+
invariant(this.target.id === other.target.id, 'Cannot difference connection with different targets')
|
|
81
|
+
return new ConnectionModel(
|
|
82
|
+
this.source,
|
|
83
|
+
this.target,
|
|
84
|
+
difference(this.relations, other.relations)
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
equals(other: ConnectionModel<M>): boolean {
|
|
89
|
+
return this.id === other.id
|
|
90
|
+
&& this.source.id === other.source.id
|
|
91
|
+
&& this.target.id === other.target.id
|
|
92
|
+
&& equals(this.relations, other.relations)
|
|
93
|
+
}
|
|
94
|
+
}
|