@likec4/core 1.19.1 → 1.20.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/builder/index.cjs +881 -0
- package/dist/builder/index.d.cts +503 -0
- package/dist/builder/index.d.mts +5 -4
- package/dist/builder/index.d.ts +5 -4
- package/dist/builder/{index.js → index.mjs} +14 -4
- package/dist/compute-view/index.cjs +86 -0
- package/dist/compute-view/index.d.cts +23 -0
- package/dist/compute-view/index.d.mts +3 -2
- package/dist/compute-view/index.d.ts +3 -2
- package/dist/compute-view/{index.js → index.mjs} +6 -5
- package/dist/index.cjs +4320 -0
- package/dist/index.d.cts +270 -0
- package/dist/index.d.mts +130 -4
- package/dist/index.d.ts +130 -4
- package/dist/{index.js → index.mjs} +512 -7
- package/dist/model/index.cjs +40 -0
- package/dist/model/index.d.cts +259 -0
- package/dist/model/index.d.mts +8 -3
- package/dist/model/index.d.ts +8 -3
- package/dist/model/index.mjs +1 -0
- package/dist/shared/core.B2QYWlYe.cjs +435 -0
- package/dist/shared/core.B72vUaNB.d.cts +850 -0
- package/dist/shared/core.BGus30EM.cjs +8027 -0
- package/dist/shared/core.BRuJ3Wzf.d.mts +12 -0
- package/dist/shared/{core.BZ9Msq7w.d.mts → core.BdbFkE_p.d.cts} +14 -4
- package/dist/shared/core.BvdNMbcA.d.cts +12 -0
- package/dist/shared/{object_hash.CE_oF3I3.js → core.BxvDITEI.mjs} +26 -389
- package/dist/shared/core.ByNgh-mC.d.cts +127 -0
- package/dist/shared/core.C9DCnJh8.cjs +908 -0
- package/dist/shared/{index.DafVOuVd.js → core.CqCTxzMY.mjs} +1111 -572
- package/dist/shared/core.D74xkKkG.d.cts +148 -0
- package/dist/shared/{core.C05RDLhi.d.ts → core.D_Gc58Gt.d.ts} +23 -5
- package/dist/shared/core.Damrzla-.d.ts +12 -0
- package/dist/shared/{core.CmYMqgha.d.mts → core.Dfzrh1VA.d.mts} +23 -5
- package/dist/shared/core.DsoCu540.cjs +26 -0
- package/dist/shared/{view.CyZrG8BJ.js → core.DunIMHRf.mjs} +27 -1
- package/dist/shared/{core.BIfgabEw.d.ts → core.ZWiGANIJ.d.ts} +14 -4
- package/dist/shared/core.gv1bMwCC.cjs +39 -0
- package/dist/shared/core.jy6z2iRn.d.mts +729 -0
- package/dist/shared/core.m3rCQAv6.mjs +37 -0
- package/dist/types/index.cjs +107 -0
- package/dist/types/index.d.cts +72 -0
- package/dist/types/index.d.mts +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/{index.js → index.mjs} +1 -1
- package/dist/utils/index.cjs +95 -0
- package/dist/utils/index.d.cts +356 -0
- package/dist/utils/index.d.mts +1 -64
- package/dist/utils/index.d.ts +1 -64
- package/dist/utils/index.mjs +56 -0
- package/package.json +52 -26
- package/src/builder/Builder.view-common.ts +21 -1
- package/src/compute-view/deployment-view/__test__/fixture.ts +31 -3
- package/src/compute-view/deployment-view/_types.ts +2 -1
- package/src/compute-view/deployment-view/compute.ts +4 -36
- package/src/compute-view/deployment-view/predicates/index.ts +8 -0
- package/src/compute-view/deployment-view/predicates/relation-direct.ts +125 -99
- package/src/compute-view/deployment-view/predicates/relation-in-out.ts +16 -8
- package/src/compute-view/deployment-view/predicates/relation-incoming.ts +18 -12
- package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +16 -9
- package/src/compute-view/deployment-view/predicates/relation-where.ts +18 -0
- package/src/compute-view/deployment-view/predicates/utils.ts +214 -0
- package/src/compute-view/element-view/__test__/fixture.ts +17 -4
- package/src/compute-view/element-view/compute.ts +3 -2
- package/src/compute-view/element-view/predicates.ts +520 -0
- package/src/compute-view/element-view/utils.ts +11 -7
- package/src/compute-view/index.ts +1 -0
- package/src/compute-view/relationships-view/_types.ts +16 -0
- package/src/compute-view/relationships-view/compute.ts +74 -0
- package/src/compute-view/relationships-view/layout.ts +357 -0
- package/src/compute-view/relationships-view/utils.ts +40 -0
- package/src/compute-view/utils/relationExpressionToPredicates.ts +11 -4
- package/src/index.ts +16 -0
- package/src/model/DeploymentElementModel.ts +18 -1
- package/src/model/ElementModel.ts +13 -0
- package/src/model/LikeC4Model.ts +2 -2
- package/src/model/RelationModel.ts +9 -0
- package/src/model/connection/deployment/DeploymentConnectionModel.ts +11 -1
- package/src/model/guards.ts +17 -1
- package/src/model/view/LikeC4ViewModel.ts +7 -1
- package/src/model/view/NodeModel.ts +5 -0
- package/src/types/deployments.ts +1 -0
- package/src/types/expression-v2.ts +12 -0
- package/src/types/index.ts +1 -0
- package/src/types/operators.ts +46 -6
- package/src/types/view.ts +2 -2
- package/src/utils/index.ts +0 -5
- package/src/utils/iterable/unique.ts +1 -7
- package/dist/model/index.js +0 -1
- package/dist/utils/index.js +0 -347
- /package/dist/shared/{chunk-RAAYCPUM.M-JWF7SS.js → core.M-JWF7SS.mjs} +0 -0
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@likec4/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"homepage": "https://likec4.dev",
|
|
6
6
|
"author": "Denis Davydkov <denis@davydkov.com>",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/likec4/likec4.git",
|
|
9
|
+
"url": "git+https://github.com/likec4/likec4.git",
|
|
10
10
|
"directory": "packages/core"
|
|
11
11
|
},
|
|
12
12
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"lint": "run -T eslint src/ --fix",
|
|
17
17
|
"test": "vitest run --no-isolate",
|
|
18
18
|
"test:watch": "vitest",
|
|
19
|
-
"clean": "rm -r -f dist"
|
|
19
|
+
"clean": "rm -r -f dist",
|
|
20
|
+
"package": "yarn pack"
|
|
20
21
|
},
|
|
21
22
|
"files": [
|
|
22
23
|
"dist",
|
|
@@ -30,50 +31,74 @@
|
|
|
30
31
|
"exports": {
|
|
31
32
|
".": {
|
|
32
33
|
"sources": "./src/index.ts",
|
|
34
|
+
"require": {
|
|
35
|
+
"types": "./dist/index.d.cts",
|
|
36
|
+
"default": "./dist/index.cjs"
|
|
37
|
+
},
|
|
33
38
|
"default": {
|
|
34
|
-
"types": "./dist/index.d.
|
|
35
|
-
"import": "./dist/index.
|
|
36
|
-
"default": "./dist/index.
|
|
39
|
+
"types": "./dist/index.d.mts",
|
|
40
|
+
"import": "./dist/index.mjs",
|
|
41
|
+
"default": "./dist/index.mjs"
|
|
37
42
|
}
|
|
38
43
|
},
|
|
39
44
|
"./builder": {
|
|
40
45
|
"sources": "./src/builder/index.ts",
|
|
46
|
+
"require": {
|
|
47
|
+
"types": "./dist/builder/index.d.cts",
|
|
48
|
+
"default": "./dist/builder/index.cjs"
|
|
49
|
+
},
|
|
41
50
|
"default": {
|
|
42
|
-
"types": "./dist/builder/index.d.
|
|
43
|
-
"import": "./dist/builder/index.
|
|
44
|
-
"default": "./dist/builder/index.
|
|
51
|
+
"types": "./dist/builder/index.d.mts",
|
|
52
|
+
"import": "./dist/builder/index.mjs",
|
|
53
|
+
"default": "./dist/builder/index.mjs"
|
|
45
54
|
}
|
|
46
55
|
},
|
|
47
56
|
"./compute-view": {
|
|
48
57
|
"sources": "./src/compute-view/index.ts",
|
|
58
|
+
"require": {
|
|
59
|
+
"types": "./dist/compute-view/index.d.cts",
|
|
60
|
+
"default": "./dist/compute-view/index.cjs"
|
|
61
|
+
},
|
|
49
62
|
"default": {
|
|
50
|
-
"types": "./dist/compute-view/index.d.
|
|
51
|
-
"import": "./dist/compute-view/index.
|
|
52
|
-
"default": "./dist/compute-view/index.
|
|
63
|
+
"types": "./dist/compute-view/index.d.mts",
|
|
64
|
+
"import": "./dist/compute-view/index.mjs",
|
|
65
|
+
"default": "./dist/compute-view/index.mjs"
|
|
53
66
|
}
|
|
54
67
|
},
|
|
55
68
|
"./model": {
|
|
56
69
|
"sources": "./src/model/index.ts",
|
|
70
|
+
"require": {
|
|
71
|
+
"types": "./dist/model/index.d.cts",
|
|
72
|
+
"default": "./dist/model/index.cjs"
|
|
73
|
+
},
|
|
57
74
|
"default": {
|
|
58
|
-
"types": "./dist/model/index.d.
|
|
59
|
-
"import": "./dist/model/index.
|
|
60
|
-
"default": "./dist/model/index.
|
|
75
|
+
"types": "./dist/model/index.d.mts",
|
|
76
|
+
"import": "./dist/model/index.mjs",
|
|
77
|
+
"default": "./dist/model/index.mjs"
|
|
61
78
|
}
|
|
62
79
|
},
|
|
63
80
|
"./utils": {
|
|
64
81
|
"sources": "./src/utils/index.ts",
|
|
82
|
+
"require": {
|
|
83
|
+
"types": "./dist/utils/index.d.cts",
|
|
84
|
+
"default": "./dist/utils/index.cjs"
|
|
85
|
+
},
|
|
65
86
|
"default": {
|
|
66
|
-
"types": "./dist/utils/index.d.
|
|
67
|
-
"import": "./dist/utils/index.
|
|
68
|
-
"default": "./dist/utils/index.
|
|
87
|
+
"types": "./dist/utils/index.d.mts",
|
|
88
|
+
"import": "./dist/utils/index.mjs",
|
|
89
|
+
"default": "./dist/utils/index.mjs"
|
|
69
90
|
}
|
|
70
91
|
},
|
|
71
92
|
"./types": {
|
|
72
93
|
"sources": "./src/types/index.ts",
|
|
94
|
+
"require": {
|
|
95
|
+
"types": "./dist/types/index.d.cts",
|
|
96
|
+
"default": "./dist/types/index.cjs"
|
|
97
|
+
},
|
|
73
98
|
"default": {
|
|
74
|
-
"types": "./dist/types/index.d.
|
|
75
|
-
"import": "./dist/types/index.
|
|
76
|
-
"default": "./dist/types/index.
|
|
99
|
+
"types": "./dist/types/index.d.mts",
|
|
100
|
+
"import": "./dist/types/index.mjs",
|
|
101
|
+
"default": "./dist/types/index.mjs"
|
|
77
102
|
}
|
|
78
103
|
}
|
|
79
104
|
},
|
|
@@ -85,7 +110,8 @@
|
|
|
85
110
|
"type-fest": "4.28.1"
|
|
86
111
|
},
|
|
87
112
|
"devDependencies": {
|
|
88
|
-
"@
|
|
113
|
+
"@dagrejs/dagre": "1.1.4",
|
|
114
|
+
"@likec4/tsconfig": "1.20.0",
|
|
89
115
|
"@mantine/colors-generator": "7.15.2",
|
|
90
116
|
"@types/natural-compare-lite": "^1.4.2",
|
|
91
117
|
"@types/object-hash": "^3.0.6",
|
|
@@ -98,11 +124,11 @@
|
|
|
98
124
|
"natural-compare-lite": "^1.4.0",
|
|
99
125
|
"object-hash": "^3.0.0",
|
|
100
126
|
"obliterator": "^2.0.4",
|
|
101
|
-
"remeda": "^2.
|
|
127
|
+
"remeda": "^2.19.0",
|
|
102
128
|
"turbo": "^2.3.3",
|
|
103
|
-
"typescript": "^5.7.
|
|
104
|
-
"unbuild": "^3.
|
|
129
|
+
"typescript": "^5.7.3",
|
|
130
|
+
"unbuild": "^3.2.0",
|
|
105
131
|
"vitest": "^2.1.8"
|
|
106
132
|
},
|
|
107
|
-
"packageManager": "yarn@4.
|
|
133
|
+
"packageManager": "yarn@4.6.0"
|
|
108
134
|
}
|
|
@@ -6,11 +6,12 @@ import {
|
|
|
6
6
|
type CustomRelationExpr,
|
|
7
7
|
type ElementExpression as C4ElementExpression,
|
|
8
8
|
type Expression as C4Expression,
|
|
9
|
-
isElementPredicateExpr,
|
|
10
9
|
type NonEmptyArray,
|
|
11
10
|
type ViewRuleStyle,
|
|
12
11
|
type WhereOperator,
|
|
12
|
+
isElementPredicateExpr,
|
|
13
13
|
} from '../types'
|
|
14
|
+
import type { KindEqual, Participant, TagEqual } from '../types/operators'
|
|
14
15
|
import type { AnyTypes, Types } from './_types'
|
|
15
16
|
|
|
16
17
|
export interface LikeC4ViewBuilder<
|
|
@@ -59,10 +60,14 @@ export namespace ViewPredicate {
|
|
|
59
60
|
|
|
60
61
|
export type WhereTag<Tag extends string> = `tag ${'is' | 'is not'} #${Tag}`
|
|
61
62
|
export type WhereKind<Kind extends string> = `kind ${'is' | 'is not'} ${Kind}`
|
|
63
|
+
export type WhereParticipant<Types extends AnyTypes> = `${Participant}.${
|
|
64
|
+
| WhereTag<Types['Tag']>
|
|
65
|
+
| WhereKind<Types['ElementKind']>}`
|
|
62
66
|
|
|
63
67
|
export type WhereEq<Types extends AnyTypes> =
|
|
64
68
|
| ViewPredicate.WhereTag<Types['Tag']>
|
|
65
69
|
| ViewPredicate.WhereKind<Types['ElementKind']>
|
|
70
|
+
| ViewPredicate.WhereParticipant<Types>
|
|
66
71
|
|
|
67
72
|
export type WhereOperator<Types extends AnyTypes> = ViewPredicate.WhereEq<Types> | {
|
|
68
73
|
and: NonEmptyArray<ViewPredicate.WhereOperator<Types>>
|
|
@@ -116,6 +121,20 @@ function parseWhere(where: ViewPredicate.WhereOperator<AnyTypes>): WhereOperator
|
|
|
116
121
|
eq: op.replace('kind is ', ''),
|
|
117
122
|
},
|
|
118
123
|
}
|
|
124
|
+
case op.startsWith('source.'):
|
|
125
|
+
return {
|
|
126
|
+
operator: parseWhere(op.replace('source.', '') as ViewPredicate.WhereOperator<AnyTypes>) as
|
|
127
|
+
| KindEqual<string>
|
|
128
|
+
| TagEqual<string>,
|
|
129
|
+
participant: 'source',
|
|
130
|
+
}
|
|
131
|
+
case op.startsWith('target.'):
|
|
132
|
+
return {
|
|
133
|
+
operator: parseWhere(op.replace('target.', '') as ViewPredicate.WhereOperator<AnyTypes>) as
|
|
134
|
+
| KindEqual<string>
|
|
135
|
+
| TagEqual<string>,
|
|
136
|
+
participant: 'target',
|
|
137
|
+
}
|
|
119
138
|
default:
|
|
120
139
|
throw new Error(`Unknown where operator: ${where}`)
|
|
121
140
|
}
|
|
@@ -189,6 +208,7 @@ function $exclude<B extends LikeC4ViewBuilder<AnyTypes, any, any>>(
|
|
|
189
208
|
| [B['Expr']]
|
|
190
209
|
| [B['TypedExpr']]
|
|
191
210
|
| [B['Expr'], ViewPredicate.Custom<B['Types']>]
|
|
211
|
+
| [B['TypedExpr'], ViewPredicate.Custom<B['Types']>]
|
|
192
212
|
): (b: B) => B {
|
|
193
213
|
return (b) => {
|
|
194
214
|
let expr = b.$expr(args[0]) as C4Expression
|
|
@@ -57,6 +57,8 @@ const {
|
|
|
57
57
|
zone: {},
|
|
58
58
|
node: {},
|
|
59
59
|
},
|
|
60
|
+
tags: ['old', 'next', 'temp'],
|
|
61
|
+
relationships: { 'https': {} },
|
|
60
62
|
})
|
|
61
63
|
|
|
62
64
|
export const builder = b
|
|
@@ -91,13 +93,22 @@ export const builder = b
|
|
|
91
93
|
model(
|
|
92
94
|
$m.rel('customer', 'cloud', 'uses services'),
|
|
93
95
|
$m.rel('customer', 'cloud.frontend.mobile', 'opens mobile app'),
|
|
94
|
-
$m.rel('customer', 'cloud.frontend.dashboard',
|
|
96
|
+
$m.rel('customer', 'cloud.frontend.dashboard', {
|
|
97
|
+
title: 'opens in browser',
|
|
98
|
+
tags: ['old'],
|
|
99
|
+
}),
|
|
95
100
|
$m.rel('cloud.frontend.dashboard', 'cloud.auth', {
|
|
96
101
|
title: 'authenticates',
|
|
97
102
|
color: 'green',
|
|
98
103
|
}),
|
|
99
|
-
$m.rel('cloud.frontend.dashboard', 'cloud.backend.api',
|
|
100
|
-
|
|
104
|
+
$m.rel('cloud.frontend.dashboard', 'cloud.backend.api', {
|
|
105
|
+
title: 'fetches data',
|
|
106
|
+
tags: ['old'],
|
|
107
|
+
}),
|
|
108
|
+
$m.rel('cloud.frontend.dashboard', 'cloud.media', {
|
|
109
|
+
title: 'fetches media',
|
|
110
|
+
tags: ['temp'],
|
|
111
|
+
}),
|
|
101
112
|
$m.rel('cloud.frontend.mobile', 'cloud.auth', {
|
|
102
113
|
title: 'authenticates',
|
|
103
114
|
color: 'amber',
|
|
@@ -137,6 +148,14 @@ export const builder = b
|
|
|
137
148
|
instanceOf('db', 'aws.rds'),
|
|
138
149
|
),
|
|
139
150
|
),
|
|
151
|
+
env('dev').with(
|
|
152
|
+
node('devCustomer').with(
|
|
153
|
+
instanceOf('instance', 'customer'),
|
|
154
|
+
),
|
|
155
|
+
node('devCloud').with(
|
|
156
|
+
instanceOf('instance', 'cloud'),
|
|
157
|
+
),
|
|
158
|
+
),
|
|
140
159
|
env('acc').with(
|
|
141
160
|
node('testCustomer').with(
|
|
142
161
|
instanceOf('instance', 'customer'),
|
|
@@ -196,3 +215,12 @@ export function computeNodesAndEdges(...rules: DeploymentRulesBuilderOp<Types>[]
|
|
|
196
215
|
edges: edgeIds,
|
|
197
216
|
}
|
|
198
217
|
}
|
|
218
|
+
|
|
219
|
+
export function createModel() {
|
|
220
|
+
const modelsource = builder.build()
|
|
221
|
+
|
|
222
|
+
return LikeC4Model.create({
|
|
223
|
+
...modelsource,
|
|
224
|
+
views: {},
|
|
225
|
+
})
|
|
226
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { LikeC4DeploymentModel } from '../../model'
|
|
2
2
|
import type { RelationshipModel } from '../../model/RelationModel'
|
|
3
|
-
import type { ExpressionV2 } from '../../types'
|
|
3
|
+
import type { ExpressionV2, Filterable, OperatorPredicate } from '../../types'
|
|
4
4
|
import type { Ctx, Memory, Stage, StageExclude, StageInclude } from './memory'
|
|
5
5
|
|
|
6
6
|
export { Memory, type Stage } from './memory'
|
|
@@ -23,6 +23,7 @@ export interface PredicateCtx<Expr extends ExpressionV2 = ExpressionV2> {
|
|
|
23
23
|
stage: Stage
|
|
24
24
|
model: LikeC4DeploymentModel
|
|
25
25
|
memory: Memory
|
|
26
|
+
where: OperatorPredicate<Filterable> | null
|
|
26
27
|
}
|
|
27
28
|
export interface IncludePredicateCtx<Expr extends ExpressionV2 = ExpressionV2> extends PredicateCtx<Expr> {
|
|
28
29
|
stage: StageInclude
|
|
@@ -1,27 +1,19 @@
|
|
|
1
1
|
import { findLast, map } from 'remeda'
|
|
2
|
-
import { nonexhaustive } from '../../errors'
|
|
3
2
|
import { type LikeC4DeploymentModel, LikeC4Model } from '../../model'
|
|
4
3
|
import type { AnyAux } from '../../model/types'
|
|
5
4
|
import type { DeploymentViewRule } from '../../types'
|
|
6
5
|
import {
|
|
7
6
|
type ComputedDeploymentView,
|
|
8
7
|
type DeploymentView,
|
|
9
|
-
FqnExpr,
|
|
10
8
|
isViewRuleAutoLayout,
|
|
11
9
|
isViewRulePredicate,
|
|
12
10
|
} from '../../types'
|
|
13
|
-
import { RelationExpr } from '../../types/expression-v2'
|
|
14
11
|
import { buildElementNotations } from '../utils/buildElementNotations'
|
|
15
12
|
import { linkNodesWithEdges } from '../utils/link-nodes-with-edges'
|
|
16
13
|
import { topologicalSort } from '../utils/topological-sort'
|
|
17
14
|
import { calcViewLayoutHash } from '../utils/view-hash'
|
|
18
15
|
import { Memory } from './memory'
|
|
19
|
-
import {
|
|
20
|
-
import { DirectRelationPredicate } from './predicates/relation-direct'
|
|
21
|
-
import { InOutRelationPredicate } from './predicates/relation-in-out'
|
|
22
|
-
import { IncomingRelationPredicate } from './predicates/relation-incoming'
|
|
23
|
-
import { OutgoingRelationPredicate } from './predicates/relation-outgoing'
|
|
24
|
-
import { WildcardPredicate } from './predicates/wildcard'
|
|
16
|
+
import { predicateToPatch } from './predicates'
|
|
25
17
|
import { StageFinal } from './stages/stage-final'
|
|
26
18
|
import { applyDeploymentViewRuleStyles, buildNodes, toComputedEdges } from './utils'
|
|
27
19
|
|
|
@@ -37,32 +29,8 @@ export function processPredicates<M extends AnyAux>(
|
|
|
37
29
|
const exprs = rule.include ?? rule.exclude
|
|
38
30
|
for (const expr of exprs) {
|
|
39
31
|
let stage = op === 'include' ? memory.stageInclude(expr) : memory.stageExclude(expr)
|
|
40
|
-
const ctx = { model, stage, memory }
|
|
41
|
-
|
|
42
|
-
case FqnExpr.isModelRef(expr):
|
|
43
|
-
// Ignore model refs in deployment view
|
|
44
|
-
break
|
|
45
|
-
case FqnExpr.isDeploymentRef(expr):
|
|
46
|
-
stage = DeploymentRefPredicate[op]({ ...ctx, expr } as any) ?? stage
|
|
47
|
-
break
|
|
48
|
-
case FqnExpr.isWildcard(expr):
|
|
49
|
-
stage = WildcardPredicate[op]({ ...ctx, expr } as any) ?? stage
|
|
50
|
-
break
|
|
51
|
-
case RelationExpr.isDirect(expr):
|
|
52
|
-
stage = DirectRelationPredicate[op]({ ...ctx, expr } as any) ?? stage
|
|
53
|
-
break
|
|
54
|
-
case RelationExpr.isInOut(expr):
|
|
55
|
-
stage = InOutRelationPredicate[op]({ ...ctx, expr } as any) ?? stage
|
|
56
|
-
break
|
|
57
|
-
case RelationExpr.isOutgoing(expr):
|
|
58
|
-
stage = OutgoingRelationPredicate[op]({ ...ctx, expr } as any) ?? stage
|
|
59
|
-
break
|
|
60
|
-
case RelationExpr.isIncoming(expr):
|
|
61
|
-
stage = IncomingRelationPredicate[op]({ ...ctx, expr } as any) ?? stage
|
|
62
|
-
break
|
|
63
|
-
default:
|
|
64
|
-
nonexhaustive(expr)
|
|
65
|
-
}
|
|
32
|
+
const ctx = { expr, model, stage, memory, where: null }
|
|
33
|
+
stage = predicateToPatch(op, ctx) ?? stage
|
|
66
34
|
memory = stage.commit()
|
|
67
35
|
}
|
|
68
36
|
}
|
|
@@ -78,7 +46,7 @@ export function computeDeploymentView<M extends AnyAux>(
|
|
|
78
46
|
...view
|
|
79
47
|
}: DeploymentView,
|
|
80
48
|
): ComputedDeploymentView<M['ViewId']> {
|
|
81
|
-
|
|
49
|
+
const memory = processPredicates<M>(likec4model.deployment, rules)
|
|
82
50
|
|
|
83
51
|
const nodesMap = buildNodes(memory)
|
|
84
52
|
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { filter, flatMap, isNonNullish, map, pipe } from 'remeda'
|
|
1
|
+
import { filter, flatMap, isNonNullish, map, pick, pipe } from 'remeda'
|
|
2
2
|
import { invariant } from '../../../errors'
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
ConnectionModel,
|
|
5
|
+
DeploymentElementModel,
|
|
6
|
+
DeploymentRelationModel,
|
|
7
|
+
LikeC4DeploymentModel,
|
|
8
|
+
} from '../../../model'
|
|
4
9
|
import type { DeploymentConnectionModel } from '../../../model/connection/deployment'
|
|
5
10
|
import { findConnection, findConnectionsBetween, findConnectionsWithin } from '../../../model/connection/deployment'
|
|
6
11
|
import { findConnectionsBetween as findModelConnectionsBetween } from '../../../model/connection/model'
|
|
7
|
-
import type { ConnectionModel } from '../../../model/connection/model/ConnectionModel'
|
|
8
|
-
import type { DeploymentElementModel } from '../../../model/DeploymentElementModel'
|
|
9
12
|
import type { RelationshipModel } from '../../../model/RelationModel'
|
|
10
13
|
import type { AnyAux } from '../../../model/types'
|
|
11
|
-
import { type RelationExpr, FqnExpr } from '../../../types'
|
|
12
|
-
import {
|
|
13
|
-
import type { ExcludePredicateCtx, PredicateExecutor } from '../_types'
|
|
14
|
-
import type { StageExclude } from '../memory'
|
|
14
|
+
import { type Filterable, type OperatorPredicate, type RelationExpr, FqnExpr } from '../../../types'
|
|
15
|
+
import type { PredicateExecutor } from '../_types'
|
|
15
16
|
import { deploymentExpressionToPredicate, resolveElements, resolveModelElements } from '../utils'
|
|
16
17
|
import { filterIncomingConnections, resolveAllImcomingRelations } from './relation-incoming'
|
|
17
18
|
import { filterOutgoingConnections, resolveAllOutgoingRelations } from './relation-outgoing'
|
|
18
|
-
|
|
19
|
-
// const isRef = DeploymentElementExpression.isRef
|
|
19
|
+
import { applyPredicate, excludeModelRelations } from './utils'
|
|
20
20
|
|
|
21
21
|
export const resolveAscendingSiblings = (element: DeploymentElementModel) => {
|
|
22
22
|
const siblings = new Set<DeploymentElementModel>()
|
|
@@ -40,7 +40,7 @@ const resolveWildcard = (model: LikeC4DeploymentModel, nonWildcard: FqnExpr.Depl
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
export const DirectRelationPredicate: PredicateExecutor<RelationExpr.Direct> = {
|
|
43
|
-
include: ({ expr: { source, target, isBidirectional = false }, model, stage }) => {
|
|
43
|
+
include: ({ expr: { source, target, isBidirectional = false }, model, stage, where }) => {
|
|
44
44
|
invariant(!FqnExpr.isModelRef(source), 'Invalid source model ref in direct relation')
|
|
45
45
|
invariant(!FqnExpr.isModelRef(target), 'Invalid target model ref in direct relation')
|
|
46
46
|
const sourceIsWildcard = FqnExpr.isWildcard(source)
|
|
@@ -53,10 +53,14 @@ export const DirectRelationPredicate: PredicateExecutor<RelationExpr.Direct> = {
|
|
|
53
53
|
switch (true) {
|
|
54
54
|
// * -> *
|
|
55
55
|
case sourceIsWildcard && targetIsWildcard: {
|
|
56
|
-
connections =
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
56
|
+
connections = pipe(
|
|
57
|
+
findConnectionsWithin(model.instances()),
|
|
58
|
+
applyPredicate(where),
|
|
59
|
+
map(c => {
|
|
60
|
+
stage.addImplicit(c.boundary)
|
|
61
|
+
return c
|
|
62
|
+
}),
|
|
63
|
+
)
|
|
60
64
|
break
|
|
61
65
|
}
|
|
62
66
|
|
|
@@ -71,12 +75,15 @@ export const DirectRelationPredicate: PredicateExecutor<RelationExpr.Direct> = {
|
|
|
71
75
|
postFilter = c => isSource(c) !== isTarget(c)
|
|
72
76
|
}
|
|
73
77
|
|
|
74
|
-
connections =
|
|
75
|
-
|
|
78
|
+
connections = pipe(
|
|
79
|
+
sources,
|
|
80
|
+
flatMap(source => {
|
|
76
81
|
const targets = resolveAscendingSiblings(source)
|
|
77
82
|
return findConnectionsBetween(source, targets, dir)
|
|
78
|
-
})
|
|
79
|
-
|
|
83
|
+
}),
|
|
84
|
+
filter(postFilter),
|
|
85
|
+
applyPredicate(where),
|
|
86
|
+
)
|
|
80
87
|
break
|
|
81
88
|
}
|
|
82
89
|
// * -> target; * <-> target
|
|
@@ -90,12 +97,15 @@ export const DirectRelationPredicate: PredicateExecutor<RelationExpr.Direct> = {
|
|
|
90
97
|
postFilter = c => isSource(c) !== isTarget(c)
|
|
91
98
|
}
|
|
92
99
|
|
|
93
|
-
connections =
|
|
94
|
-
|
|
100
|
+
connections = pipe(
|
|
101
|
+
targets,
|
|
102
|
+
flatMap(target => {
|
|
95
103
|
const sources = resolveAscendingSiblings(target)
|
|
96
104
|
return [...sources].flatMap(source => findConnection(source, target, dir))
|
|
97
|
-
})
|
|
98
|
-
|
|
105
|
+
}),
|
|
106
|
+
filter(postFilter),
|
|
107
|
+
applyPredicate(where),
|
|
108
|
+
)
|
|
99
109
|
break
|
|
100
110
|
}
|
|
101
111
|
default: {
|
|
@@ -111,6 +121,7 @@ export const DirectRelationPredicate: PredicateExecutor<RelationExpr.Direct> = {
|
|
|
111
121
|
sources,
|
|
112
122
|
flatMap(s => findConnectionsBetween(s, targets, dir)),
|
|
113
123
|
filter(c => isSource(c) && isTarget(c)),
|
|
124
|
+
applyPredicate(where),
|
|
114
125
|
)
|
|
115
126
|
}
|
|
116
127
|
}
|
|
@@ -126,90 +137,72 @@ export const DirectRelationPredicate: PredicateExecutor<RelationExpr.Direct> = {
|
|
|
126
137
|
|
|
127
138
|
return stage
|
|
128
139
|
},
|
|
129
|
-
exclude: ({ expr, model, memory, stage }) => {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (
|
|
133
|
-
FqnExpr.isWildcard(expr.source)
|
|
134
|
-
&& FqnExpr.isWildcard(expr.target)
|
|
135
|
-
) {
|
|
136
|
-
stage.excludeConnections(memory.connections)
|
|
137
|
-
return stage
|
|
138
|
-
}
|
|
140
|
+
exclude: ({ expr, model, memory, stage, where }) => {
|
|
141
|
+
const isTarget = deploymentExpressionToPredicate(expr.target)
|
|
142
|
+
const isSource = deploymentExpressionToPredicate(expr.source)
|
|
139
143
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
})
|
|
147
|
-
return excludeModelRelations(toExclude, { stage, memory })
|
|
148
|
-
}
|
|
144
|
+
let modelRelationsToExclude: ReadonlySet<RelationshipModel<AnyAux>>
|
|
145
|
+
switch (true) {
|
|
146
|
+
// * -> *
|
|
147
|
+
case FqnExpr.isWildcard(expr.source) && FqnExpr.isWildcard(expr.target):
|
|
148
|
+
stage.excludeConnections(applyPredicate(memory.connections, where))
|
|
149
|
+
return stage
|
|
149
150
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
{ stage, memory },
|
|
160
|
-
c => isTarget(c.target),
|
|
161
|
-
)
|
|
162
|
-
}
|
|
151
|
+
// model -> model
|
|
152
|
+
case FqnExpr.isModelRef(expr.source) && FqnExpr.isModelRef(expr.target):
|
|
153
|
+
modelRelationsToExclude = resolveRelationsBetweenModelElements({
|
|
154
|
+
source: expr.source,
|
|
155
|
+
target: expr.target,
|
|
156
|
+
expr,
|
|
157
|
+
model,
|
|
158
|
+
})
|
|
159
|
+
return excludeModelRelations(modelRelationsToExclude, { stage, memory }, where)
|
|
163
160
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
toExclude,
|
|
169
|
-
{ stage, memory },
|
|
170
|
-
c => isSource(c.source),
|
|
171
|
-
)
|
|
172
|
-
}
|
|
161
|
+
// model -> *
|
|
162
|
+
case FqnExpr.isModelRef(expr.source) && FqnExpr.isWildcard(expr.target):
|
|
163
|
+
modelRelationsToExclude = resolveAllOutgoingRelations(model, expr.source)
|
|
164
|
+
return excludeModelRelations(modelRelationsToExclude, { stage, memory }, where)
|
|
173
165
|
|
|
174
|
-
|
|
175
|
-
|
|
166
|
+
// model -> deployment
|
|
167
|
+
case FqnExpr.isModelRef(expr.source):
|
|
168
|
+
modelRelationsToExclude = resolveAllOutgoingRelations(model, expr.source)
|
|
169
|
+
return excludeModelRelations(
|
|
170
|
+
modelRelationsToExclude,
|
|
171
|
+
{ stage, memory },
|
|
172
|
+
where,
|
|
173
|
+
c => isTarget(c.target),
|
|
174
|
+
)
|
|
176
175
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
176
|
+
// deployment -> model
|
|
177
|
+
case FqnExpr.isModelRef(expr.target):
|
|
178
|
+
modelRelationsToExclude = resolveAllImcomingRelations(model, expr.target)
|
|
179
|
+
return excludeModelRelations(
|
|
180
|
+
modelRelationsToExclude,
|
|
181
|
+
{ stage, memory },
|
|
182
|
+
where,
|
|
183
|
+
c => isSource(c.source),
|
|
184
|
+
)
|
|
181
185
|
|
|
182
|
-
|
|
186
|
+
// deployment -> deployment
|
|
187
|
+
default:
|
|
188
|
+
const satisfies = (connection: DeploymentConnectionModel) => {
|
|
189
|
+
return (isSource(connection.source) && isTarget(connection.target))
|
|
190
|
+
|| (expr.isBidirectional === true && isSource(connection.target) && isTarget(connection.source))
|
|
191
|
+
}
|
|
183
192
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
193
|
+
const deploymentRelationsToExclude = pipe(
|
|
194
|
+
memory.connections,
|
|
195
|
+
filter(satisfies),
|
|
196
|
+
applyPredicate(where),
|
|
197
|
+
)
|
|
198
|
+
if (deploymentRelationsToExclude.length === 0) {
|
|
199
|
+
return stage
|
|
200
|
+
}
|
|
188
201
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
filterConnections: (c: DeploymentConnectionModel) => boolean = () => true,
|
|
194
|
-
): StageExclude {
|
|
195
|
-
if (relationsToExclude.size === 0) {
|
|
196
|
-
return stage
|
|
197
|
-
}
|
|
198
|
-
const toExclude = pipe(
|
|
199
|
-
memory.connections,
|
|
200
|
-
// Find connections that have at least one relation in common with the excluded relations
|
|
201
|
-
filter(c => filterConnections(c) && hasIntersection(c.relations.model, relationsToExclude)),
|
|
202
|
-
map(c =>
|
|
203
|
-
c.update({
|
|
204
|
-
deployment: null,
|
|
205
|
-
model: intersection(c.relations.model, relationsToExclude),
|
|
206
|
-
})
|
|
207
|
-
),
|
|
208
|
-
)
|
|
209
|
-
if (toExclude.length === 0) {
|
|
210
|
-
return stage
|
|
211
|
-
}
|
|
212
|
-
return stage.excludeConnections(toExclude)
|
|
202
|
+
stage.excludeConnections(deploymentRelationsToExclude)
|
|
203
|
+
return stage
|
|
204
|
+
}
|
|
205
|
+
},
|
|
213
206
|
}
|
|
214
207
|
|
|
215
208
|
function resolveRelationsBetweenModelElements({
|
|
@@ -235,3 +228,36 @@ function resolveRelationsBetweenModelElements({
|
|
|
235
228
|
|
|
236
229
|
return new Set(modelConnections.flatMap(c => [...c.relations]))
|
|
237
230
|
}
|
|
231
|
+
|
|
232
|
+
function elementToFilterable<M extends AnyAux>(element: DeploymentElementModel<M>) {
|
|
233
|
+
return pick(element, ['tags', 'kind'])
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function toFilterableRelation<M extends AnyAux>(
|
|
237
|
+
source: DeploymentElementModel<M>,
|
|
238
|
+
target: DeploymentElementModel<M>,
|
|
239
|
+
) {
|
|
240
|
+
return (
|
|
241
|
+
relation: RelationshipModel<M> | DeploymentRelationModel<M>,
|
|
242
|
+
) => ({
|
|
243
|
+
tags: relation.tags,
|
|
244
|
+
kind: relation.kind,
|
|
245
|
+
source: elementToFilterable(source),
|
|
246
|
+
target: elementToFilterable(target),
|
|
247
|
+
})
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function matchConnection<M extends AnyAux>(
|
|
251
|
+
c: DeploymentConnectionModel<M>,
|
|
252
|
+
where: OperatorPredicate<Filterable> | null,
|
|
253
|
+
): boolean {
|
|
254
|
+
if (!where) {
|
|
255
|
+
return true
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return [
|
|
259
|
+
...Array.from(c.relations.deployment.values()).map(toFilterableRelation(c.source, c.target)),
|
|
260
|
+
...Array.from(c.relations.model.values()).map(toFilterableRelation(c.source, c.target)),
|
|
261
|
+
]
|
|
262
|
+
.filter(where).length > 0
|
|
263
|
+
}
|