@likec4/core 1.19.1 → 1.19.2
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.d.mts +3 -3
- package/dist/builder/index.d.ts +3 -3
- package/dist/builder/index.js +2 -2
- package/dist/compute-view/index.d.mts +2 -2
- package/dist/compute-view/index.d.ts +2 -2
- package/dist/compute-view/index.js +3 -3
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/model/index.d.mts +8 -3
- package/dist/model/index.d.ts +8 -3
- package/dist/model/index.js +1 -1
- package/dist/shared/{core.BZ9Msq7w.d.mts → core.2I-l5UtM.d.mts} +5 -1
- package/dist/shared/{core.CmYMqgha.d.mts → core.BL1oTk7-.d.mts} +13 -3
- package/dist/shared/{core.BIfgabEw.d.ts → core.CqXs9Frh.d.ts} +5 -1
- package/dist/shared/{core.C05RDLhi.d.ts → core.DyJ41fBO.d.ts} +13 -3
- package/dist/shared/{index.DafVOuVd.js → index.KOeaSlL8.js} +332 -208
- package/dist/shared/{view.CyZrG8BJ.js → view.DrmaOfjr.js} +3 -0
- package/dist/types/index.d.mts +2 -2
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.js +1 -1
- package/package.json +3 -3
- package/src/builder/Builder.view-common.ts +1 -0
- 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 +117 -88
- 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 +183 -0
- package/src/model/DeploymentElementModel.ts +14 -1
- package/src/model/RelationModel.ts +4 -0
- package/src/model/connection/deployment/DeploymentConnectionModel.ts +11 -1
- 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 +5 -5
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { anyPass } from 'remeda'
|
|
1
|
+
import { anyPass, filter, pipe } from 'remeda'
|
|
2
2
|
import { invariant } from '../../../errors'
|
|
3
|
+
import type { AnyAux, RelationshipModel } from '../../../model'
|
|
3
4
|
import { findConnectionsBetween } from '../../../model/connection/deployment'
|
|
4
5
|
import type { LikeC4DeploymentModel } from '../../../model/DeploymentModel'
|
|
5
|
-
import type
|
|
6
|
-
import
|
|
7
|
-
import { FqnExpr, type RelationExpr } from '../../../types'
|
|
8
|
-
import { isAncestor } from '../../../utils/fqn'
|
|
6
|
+
import { type RelationExpr, FqnExpr } from '../../../types'
|
|
7
|
+
import { isAncestor } from '../../../utils'
|
|
9
8
|
import type { Connection, Elem, PredicateExecutor } from '../_types'
|
|
10
9
|
import { resolveElements, resolveModelElements } from '../utils'
|
|
11
|
-
import {
|
|
10
|
+
import { resolveAscendingSiblings } from './relation-direct'
|
|
11
|
+
import { applyPredicate, excludeModelRelations, matchConnection, matchConnections } from './utils'
|
|
12
12
|
|
|
13
13
|
// from visible element incoming to this
|
|
14
14
|
export const IncomingRelationPredicate: PredicateExecutor<RelationExpr.Incoming> = {
|
|
15
|
-
include: ({ expr, model, memory, stage }) => {
|
|
15
|
+
include: ({ expr, model, memory, stage, where }) => {
|
|
16
16
|
const sources = [...memory.elements]
|
|
17
17
|
|
|
18
18
|
if (FqnExpr.isWildcard(expr.incoming)) {
|
|
@@ -21,7 +21,8 @@ export const IncomingRelationPredicate: PredicateExecutor<RelationExpr.Incoming>
|
|
|
21
21
|
continue
|
|
22
22
|
}
|
|
23
23
|
const targets = [...resolveAscendingSiblings(source)]
|
|
24
|
-
|
|
24
|
+
const toInclude = applyPredicate(findConnectionsBetween(source, targets, 'directed'), where)
|
|
25
|
+
stage.addConnections(toInclude)
|
|
25
26
|
}
|
|
26
27
|
return stage
|
|
27
28
|
}
|
|
@@ -29,16 +30,17 @@ export const IncomingRelationPredicate: PredicateExecutor<RelationExpr.Incoming>
|
|
|
29
30
|
|
|
30
31
|
const targets = resolveElements(model, expr.incoming)
|
|
31
32
|
for (const source of sources) {
|
|
32
|
-
|
|
33
|
+
const toInclude = applyPredicate(findConnectionsBetween(source, targets, 'directed'), where)
|
|
34
|
+
stage.addConnections(toInclude)
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
return stage
|
|
36
38
|
},
|
|
37
|
-
exclude: ({ expr, model, memory, stage }) => {
|
|
39
|
+
exclude: ({ expr, model, memory, stage, where }) => {
|
|
38
40
|
// Exclude all connections that have model relationshps with the elements
|
|
39
41
|
if (FqnExpr.isModelRef(expr.incoming)) {
|
|
40
42
|
const excludedRelations = resolveAllImcomingRelations(model, expr.incoming)
|
|
41
|
-
return excludeModelRelations(excludedRelations, { stage, memory })
|
|
43
|
+
return excludeModelRelations(excludedRelations, { stage, memory }, where)
|
|
42
44
|
}
|
|
43
45
|
if (FqnExpr.isWildcard(expr.incoming)) {
|
|
44
46
|
// non-sense
|
|
@@ -46,7 +48,11 @@ export const IncomingRelationPredicate: PredicateExecutor<RelationExpr.Incoming>
|
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
const isIncoming = filterIncomingConnections(resolveElements(model, expr.incoming))
|
|
49
|
-
const toExclude =
|
|
51
|
+
const toExclude = pipe(
|
|
52
|
+
memory.connections,
|
|
53
|
+
filter(isIncoming),
|
|
54
|
+
applyPredicate(where),
|
|
55
|
+
)
|
|
50
56
|
stage.excludeConnections(toExclude)
|
|
51
57
|
return stage
|
|
52
58
|
},
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
import { anyPass } from 'remeda'
|
|
1
|
+
import { anyPass, filter, pipe } from 'remeda'
|
|
2
2
|
import { invariant } from '../../../errors'
|
|
3
3
|
import type { LikeC4DeploymentModel } from '../../../model'
|
|
4
4
|
import { findConnection, findConnectionsBetween } from '../../../model/connection/deployment'
|
|
5
5
|
import type { RelationshipModel } from '../../../model/RelationModel'
|
|
6
|
-
import {
|
|
6
|
+
import { type RelationExpr, FqnExpr } from '../../../types'
|
|
7
7
|
import { isAncestor } from '../../../utils'
|
|
8
8
|
import type { Connection, Elem, PredicateExecutor } from '../_types'
|
|
9
9
|
import { resolveElements, resolveModelElements } from '../utils'
|
|
10
|
-
import {
|
|
10
|
+
import { resolveAscendingSiblings } from './relation-direct'
|
|
11
|
+
import { applyPredicate, excludeModelRelations } from './utils'
|
|
11
12
|
|
|
12
13
|
export const OutgoingRelationPredicate: PredicateExecutor<RelationExpr.Outgoing> = {
|
|
13
|
-
include: ({ expr, model, memory, stage }) => {
|
|
14
|
+
include: ({ expr, model, memory, stage, where }) => {
|
|
14
15
|
const targets = [...memory.elements]
|
|
15
16
|
|
|
16
17
|
// * -> (to visible elements)
|
|
@@ -21,7 +22,8 @@ export const OutgoingRelationPredicate: PredicateExecutor<RelationExpr.Outgoing>
|
|
|
21
22
|
continue
|
|
22
23
|
}
|
|
23
24
|
for (const source of resolveAscendingSiblings(target)) {
|
|
24
|
-
|
|
25
|
+
const toInclude = applyPredicate(findConnection(source, target, 'directed'), where)
|
|
26
|
+
stage.addConnections(toInclude)
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
return stage
|
|
@@ -30,16 +32,17 @@ export const OutgoingRelationPredicate: PredicateExecutor<RelationExpr.Outgoing>
|
|
|
30
32
|
|
|
31
33
|
const sources = resolveElements(model, expr.outgoing)
|
|
32
34
|
for (const source of sources) {
|
|
33
|
-
|
|
35
|
+
const toInclude = applyPredicate(findConnectionsBetween(source, targets, 'directed'), where)
|
|
36
|
+
stage.addConnections(toInclude)
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
return stage
|
|
37
40
|
},
|
|
38
|
-
exclude: ({ expr, model, memory, stage }) => {
|
|
41
|
+
exclude: ({ expr, model, memory, stage, where }) => {
|
|
39
42
|
// Exclude all connections that have model relationshps with the elements
|
|
40
43
|
if (FqnExpr.isModelRef(expr.outgoing)) {
|
|
41
44
|
const excludedRelations = resolveAllOutgoingRelations(model, expr.outgoing)
|
|
42
|
-
return excludeModelRelations(excludedRelations, { stage, memory })
|
|
45
|
+
return excludeModelRelations(excludedRelations, { stage, memory }, where)
|
|
43
46
|
}
|
|
44
47
|
if (FqnExpr.isWildcard(expr.outgoing)) {
|
|
45
48
|
// non-sense
|
|
@@ -47,7 +50,11 @@ export const OutgoingRelationPredicate: PredicateExecutor<RelationExpr.Outgoing>
|
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
const isOutgoing = filterOutgoingConnections(resolveElements(model, expr.outgoing))
|
|
50
|
-
const toExclude =
|
|
53
|
+
const toExclude = pipe(
|
|
54
|
+
memory.connections,
|
|
55
|
+
filter(isOutgoing),
|
|
56
|
+
applyPredicate(where),
|
|
57
|
+
)
|
|
51
58
|
stage.excludeConnections(toExclude)
|
|
52
59
|
return stage
|
|
53
60
|
},
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { whereOperatorAsPredicate, type RelationExpr } from '../../../types'
|
|
2
|
+
import type { PredicateExecutor } from '../_types'
|
|
3
|
+
import type { StageExclude, StageInclude } from '../memory'
|
|
4
|
+
import { predicateToPatch } from './utils'
|
|
5
|
+
|
|
6
|
+
// relation matches the condition
|
|
7
|
+
export const WhereRelationPredicate: PredicateExecutor<RelationExpr.Where> = {
|
|
8
|
+
include: ({ expr, model, memory, stage }) => {
|
|
9
|
+
const where = whereOperatorAsPredicate(expr.where.condition)
|
|
10
|
+
|
|
11
|
+
return predicateToPatch('include', { expr: expr.where.expr, model, stage, memory, where }) as StageInclude
|
|
12
|
+
},
|
|
13
|
+
exclude: ({ expr, model, memory, stage }) => {
|
|
14
|
+
const where = whereOperatorAsPredicate(expr.where.condition)
|
|
15
|
+
|
|
16
|
+
return predicateToPatch('exclude', { expr: expr.where.expr, model, stage, memory, where }) as StageExclude
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { filter, isArray, map, pick, pipe } from 'remeda'
|
|
2
|
+
import { nonexhaustive } from '../../../errors'
|
|
3
|
+
import type { DeploymentConnectionModel } from '../../../model'
|
|
4
|
+
import type { DeploymentElementModel, DeploymentRelationModel } from '../../../model/DeploymentElementModel'
|
|
5
|
+
import type { RelationshipModel } from '../../../model/RelationModel'
|
|
6
|
+
import type { AnyAux } from '../../../model/types'
|
|
7
|
+
import { type Filterable, type OperatorPredicate, FqnExpr, RelationExpr } from '../../../types'
|
|
8
|
+
import { hasIntersection, intersection } from '../../../utils/set'
|
|
9
|
+
import type { ExcludePredicateCtx, PredicateCtx } from '../_types'
|
|
10
|
+
import type { StageExclude, StageInclude } from '../memory'
|
|
11
|
+
import { DeploymentRefPredicate } from './elements'
|
|
12
|
+
import { DirectRelationPredicate } from './relation-direct'
|
|
13
|
+
import { InOutRelationPredicate } from './relation-in-out'
|
|
14
|
+
import { IncomingRelationPredicate } from './relation-incoming'
|
|
15
|
+
import { OutgoingRelationPredicate } from './relation-outgoing'
|
|
16
|
+
import { WhereRelationPredicate } from './relation-where'
|
|
17
|
+
import { WildcardPredicate } from './wildcard'
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Builds a patch object from an expression
|
|
21
|
+
*/
|
|
22
|
+
export function predicateToPatch(
|
|
23
|
+
op: 'include' | 'exclude',
|
|
24
|
+
{ expr, where, ...ctx }: PredicateCtx,
|
|
25
|
+
): StageExclude | StageInclude | undefined {
|
|
26
|
+
switch (true) {
|
|
27
|
+
case FqnExpr.isModelRef(expr):
|
|
28
|
+
// Ignore model refs in deployment view
|
|
29
|
+
return undefined
|
|
30
|
+
case FqnExpr.isDeploymentRef(expr):
|
|
31
|
+
return DeploymentRefPredicate[op]({ ...ctx, expr, where } as any)
|
|
32
|
+
case FqnExpr.isWildcard(expr):
|
|
33
|
+
return WildcardPredicate[op]({ ...ctx, expr, where } as any)
|
|
34
|
+
case RelationExpr.isDirect(expr):
|
|
35
|
+
return DirectRelationPredicate[op]({ ...ctx, expr, where } as any)
|
|
36
|
+
case RelationExpr.isInOut(expr):
|
|
37
|
+
return InOutRelationPredicate[op]({ ...ctx, expr, where } as any)
|
|
38
|
+
case RelationExpr.isOutgoing(expr):
|
|
39
|
+
return OutgoingRelationPredicate[op]({ ...ctx, expr, where } as any)
|
|
40
|
+
case RelationExpr.isIncoming(expr):
|
|
41
|
+
return IncomingRelationPredicate[op]({ ...ctx, expr, where } as any)
|
|
42
|
+
case RelationExpr.isWhere(expr):
|
|
43
|
+
return WhereRelationPredicate[op]({ ...ctx, expr, where } as any)
|
|
44
|
+
default:
|
|
45
|
+
nonexhaustive(expr)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function excludeModelRelations(
|
|
50
|
+
relationsToExclude: ReadonlySet<RelationshipModel<AnyAux>>,
|
|
51
|
+
{ stage, memory }: Pick<ExcludePredicateCtx, 'stage' | 'memory'>,
|
|
52
|
+
where: OperatorPredicate<Filterable> | null,
|
|
53
|
+
// Optional filter to scope the connections to exclude
|
|
54
|
+
filterConnections: (c: DeploymentConnectionModel) => boolean = () => true,
|
|
55
|
+
): StageExclude {
|
|
56
|
+
if (relationsToExclude.size === 0) {
|
|
57
|
+
return stage
|
|
58
|
+
}
|
|
59
|
+
const toExclude = pipe(
|
|
60
|
+
memory.connections,
|
|
61
|
+
filter(c => filterConnections(c)),
|
|
62
|
+
// Find connections that have at least one relation in common with the excluded relations
|
|
63
|
+
filter(c => hasIntersection(c.relations.model, relationsToExclude)),
|
|
64
|
+
map(c =>
|
|
65
|
+
c.update({
|
|
66
|
+
deployment: null,
|
|
67
|
+
model: intersection(c.relations.model, relationsToExclude),
|
|
68
|
+
})
|
|
69
|
+
),
|
|
70
|
+
applyPredicate(where),
|
|
71
|
+
filter(c => c.nonEmpty()),
|
|
72
|
+
)
|
|
73
|
+
if (toExclude.length === 0) {
|
|
74
|
+
return stage
|
|
75
|
+
}
|
|
76
|
+
return stage.excludeConnections(toExclude)
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function matchConnection<M extends AnyAux>(
|
|
80
|
+
c: DeploymentConnectionModel<M>,
|
|
81
|
+
where: OperatorPredicate<Filterable> | null,
|
|
82
|
+
): boolean {
|
|
83
|
+
return applyPredicate(c, where).nonEmpty()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Filters relations of the provided connections using the provided predicate.
|
|
88
|
+
* And copy of the connection with the filtered relations will be created.
|
|
89
|
+
* Connections left without relations are removed from resulting collection.
|
|
90
|
+
*
|
|
91
|
+
* @param c The connection to apply the predicate to
|
|
92
|
+
* @param where The predicate
|
|
93
|
+
* @returns A copy of the connection with the filtered relations
|
|
94
|
+
*/
|
|
95
|
+
export function applyPredicate<M extends AnyAux>(
|
|
96
|
+
c: readonly DeploymentConnectionModel<M>[],
|
|
97
|
+
where: OperatorPredicate<Filterable> | null,
|
|
98
|
+
): readonly DeploymentConnectionModel<M>[]
|
|
99
|
+
/**
|
|
100
|
+
* Filters relations of the connection using the provided predicate.
|
|
101
|
+
*
|
|
102
|
+
* @param c The connection to apply the predicate to
|
|
103
|
+
* @param where The predicate
|
|
104
|
+
* @returns A deep copy of the original collection with the filtered relations
|
|
105
|
+
*/
|
|
106
|
+
export function applyPredicate<M extends AnyAux>(
|
|
107
|
+
c: DeploymentConnectionModel<M>,
|
|
108
|
+
where: OperatorPredicate<Filterable> | null,
|
|
109
|
+
): DeploymentConnectionModel<M>
|
|
110
|
+
/**
|
|
111
|
+
* Creates a function that filters relations of the provided connections using the provided predicate.
|
|
112
|
+
* Connections left without relations are removed from resulting collection.
|
|
113
|
+
*
|
|
114
|
+
* @param c The connection to apply the predicate to
|
|
115
|
+
* @param where The predicate
|
|
116
|
+
* @returns A function to create a filtered copy of connections
|
|
117
|
+
*/
|
|
118
|
+
export function applyPredicate<M extends AnyAux>(
|
|
119
|
+
where: OperatorPredicate<Filterable> | null,
|
|
120
|
+
): (data: readonly DeploymentConnectionModel<M>[]) => readonly DeploymentConnectionModel<M>[]
|
|
121
|
+
export function applyPredicate<M extends AnyAux>(
|
|
122
|
+
...args:
|
|
123
|
+
| [readonly DeploymentConnectionModel<M>[], OperatorPredicate<Filterable> | null]
|
|
124
|
+
| [OperatorPredicate<Filterable> | null]
|
|
125
|
+
| [c: DeploymentConnectionModel<M>, OperatorPredicate<Filterable> | null]
|
|
126
|
+
):
|
|
127
|
+
| DeploymentConnectionModel<M>
|
|
128
|
+
| readonly DeploymentConnectionModel<M>[]
|
|
129
|
+
| ((data: readonly DeploymentConnectionModel<M>[]) => readonly DeploymentConnectionModel<M>[])
|
|
130
|
+
{
|
|
131
|
+
if (args.length === 1) {
|
|
132
|
+
return x => applyPredicate(x, args[0])
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const [c, where] = args
|
|
136
|
+
if (where === null) {
|
|
137
|
+
return c
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (isArray(c)) {
|
|
141
|
+
return c
|
|
142
|
+
.map(x => applyPredicate(x, where))
|
|
143
|
+
.filter(x => x.nonEmpty())
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const map = toFilterableRelation(c.source, c.target)
|
|
147
|
+
return c.update({
|
|
148
|
+
model: new Set([...c.relations.model.values()].filter(r => where(map(r)))),
|
|
149
|
+
deployment: new Set([...c.relations.deployment.values()].filter(r => where(map(r)))),
|
|
150
|
+
})
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function matchConnections<M extends AnyAux>(
|
|
154
|
+
connections: readonly DeploymentConnectionModel<M>[],
|
|
155
|
+
where: OperatorPredicate<Filterable> | null,
|
|
156
|
+
): readonly DeploymentConnectionModel[] {
|
|
157
|
+
if (!where) {
|
|
158
|
+
return connections
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return pipe(
|
|
162
|
+
connections,
|
|
163
|
+
filter(c => matchConnection(c, where)),
|
|
164
|
+
)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function elementToFilterable<M extends AnyAux>(element: DeploymentElementModel<M>) {
|
|
168
|
+
return pick(element, ['tags', 'kind'])
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function toFilterableRelation<M extends AnyAux>(
|
|
172
|
+
source: DeploymentElementModel<M>,
|
|
173
|
+
target: DeploymentElementModel<M>,
|
|
174
|
+
) {
|
|
175
|
+
return (
|
|
176
|
+
relation: RelationshipModel<M> | DeploymentRelationModel<M>,
|
|
177
|
+
) => ({
|
|
178
|
+
tags: relation.tags,
|
|
179
|
+
kind: relation.kind,
|
|
180
|
+
source: elementToFilterable(source),
|
|
181
|
+
target: elementToFilterable(target),
|
|
182
|
+
})
|
|
183
|
+
}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
type ElementShape as C4ElementShape,
|
|
12
12
|
type IteratorLike,
|
|
13
13
|
type Link,
|
|
14
|
+
type RelationshipKind,
|
|
14
15
|
type Tag,
|
|
15
16
|
type Tag as C4Tag,
|
|
16
17
|
type ThemeColor,
|
|
@@ -62,6 +63,10 @@ abstract class AbstractDeploymentElementModel<M extends AnyAux = AnyAux> {
|
|
|
62
63
|
return this.$node.tags ?? []
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
get kind(): DeploymentNodeKind | string | null {
|
|
67
|
+
return this.$node.kind ?? null
|
|
68
|
+
}
|
|
69
|
+
|
|
65
70
|
get description(): string | null {
|
|
66
71
|
return this.$node.description ?? null
|
|
67
72
|
}
|
|
@@ -223,7 +228,7 @@ export class DeploymentNodeModel<M extends AnyAux = AnyAux> extends AbstractDepl
|
|
|
223
228
|
return this.$model.parent(this)
|
|
224
229
|
}
|
|
225
230
|
|
|
226
|
-
get kind(): DeploymentNodeKind {
|
|
231
|
+
override get kind(): DeploymentNodeKind {
|
|
227
232
|
return this.$node.kind
|
|
228
233
|
}
|
|
229
234
|
|
|
@@ -367,6 +372,10 @@ export class DeployedInstanceModel<M extends AnyAux = AnyAux> extends AbstractDe
|
|
|
367
372
|
return this.$instance.tags ?? []
|
|
368
373
|
}
|
|
369
374
|
|
|
375
|
+
override get kind(): string | null {
|
|
376
|
+
return this.$instance.kind ?? null
|
|
377
|
+
}
|
|
378
|
+
|
|
370
379
|
override get description(): string | null {
|
|
371
380
|
return this.$instance.description ?? this.element.description
|
|
372
381
|
}
|
|
@@ -514,6 +523,10 @@ export class DeploymentRelationModel<M extends AnyAux = AnyAux> {
|
|
|
514
523
|
return this.$relationship.tags ?? []
|
|
515
524
|
}
|
|
516
525
|
|
|
526
|
+
get kind(): RelationshipKind | null {
|
|
527
|
+
return this.$relationship.kind ?? null
|
|
528
|
+
}
|
|
529
|
+
|
|
517
530
|
get navigateTo(): LikeC4ViewModel<M> | null {
|
|
518
531
|
return this.$relationship.navigateTo ? this.$model.$model.view(this.$relationship.navigateTo) : null
|
|
519
532
|
}
|
|
@@ -67,6 +67,10 @@ export class RelationshipModel<M extends AnyAux = AnyAux> {
|
|
|
67
67
|
return this.$relationship.tags ?? []
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
get kind(): string | null {
|
|
71
|
+
return this.$relationship.kind ?? null
|
|
72
|
+
}
|
|
73
|
+
|
|
70
74
|
get links(): ReadonlyArray<Link> {
|
|
71
75
|
return this.$relationship.links ?? []
|
|
72
76
|
}
|
|
@@ -110,11 +110,21 @@ export class DeploymentConnectionModel<M extends AnyAux = AnyAux>
|
|
|
110
110
|
yield* this.relations.deployment
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Merge with another connections, if it has the same source and target.
|
|
115
|
+
* Returns new connection with union of relationships.
|
|
116
|
+
*/
|
|
117
|
+
public mergeWith(others: DeploymentConnectionModel<M>[]): DeploymentConnectionModel<M>
|
|
113
118
|
/**
|
|
114
119
|
* Merge with another connection, if it has the same source and target.
|
|
115
120
|
* Returns new connection with union of relationships.
|
|
116
121
|
*/
|
|
117
|
-
public mergeWith(other: DeploymentConnectionModel<M>)
|
|
122
|
+
public mergeWith(other: DeploymentConnectionModel<M>): DeploymentConnectionModel<M>
|
|
123
|
+
public mergeWith(other: DeploymentConnectionModel<M> | DeploymentConnectionModel<M>[]): DeploymentConnectionModel<M> {
|
|
124
|
+
if (Array.isArray(other)) {
|
|
125
|
+
return other.reduce((acc, o) => acc.mergeWith(o), this)
|
|
126
|
+
}
|
|
127
|
+
|
|
118
128
|
invariant(this.source.id === other.source.id, 'Cannot merge connections with different sources')
|
|
119
129
|
invariant(this.target.id === other.target.id, 'Cannot merge connections with different targets')
|
|
120
130
|
return new DeploymentConnectionModel(
|
package/src/types/deployments.ts
CHANGED
|
@@ -42,6 +42,7 @@ export interface DeployedInstance {
|
|
|
42
42
|
readonly title?: string
|
|
43
43
|
readonly description?: string | null
|
|
44
44
|
readonly technology?: string | null
|
|
45
|
+
readonly kind?: string | null // TODO: ensure the property is set
|
|
45
46
|
readonly tags?: NonEmptyArray<Tag> | null
|
|
46
47
|
readonly links?: NonEmptyArray<Link> | null
|
|
47
48
|
readonly style?: DeploymentElementStyle
|
|
@@ -2,6 +2,7 @@ import { invariant } from '../errors'
|
|
|
2
2
|
import type { ExclusiveUnion } from './_common'
|
|
3
3
|
import type { DeploymentRef as DeploymentModelRef, PredicateSelector } from './deployments'
|
|
4
4
|
import type { Fqn } from './element'
|
|
5
|
+
import type { WhereOperator } from './operators'
|
|
5
6
|
|
|
6
7
|
export namespace FqnRef {
|
|
7
8
|
/**
|
|
@@ -131,6 +132,15 @@ export namespace RelationExpr {
|
|
|
131
132
|
export const isInOut = (expr: ExpressionV2): expr is InOut => {
|
|
132
133
|
return 'inout' in expr
|
|
133
134
|
}
|
|
135
|
+
export type Where<D = Fqn, M = Fqn> = {
|
|
136
|
+
where: {
|
|
137
|
+
expr: ExpressionV2<D, M>
|
|
138
|
+
condition: WhereOperator<string, string>
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
export const isWhere = (expr: ExpressionV2): expr is Where => {
|
|
142
|
+
return 'where' in expr
|
|
143
|
+
}
|
|
134
144
|
}
|
|
135
145
|
|
|
136
146
|
export type RelationExpr<D = Fqn, M = Fqn> = ExclusiveUnion<{
|
|
@@ -138,6 +148,7 @@ export type RelationExpr<D = Fqn, M = Fqn> = ExclusiveUnion<{
|
|
|
138
148
|
Incoming: RelationExpr.Incoming<D, M>
|
|
139
149
|
Outgoing: RelationExpr.Outgoing<D, M>
|
|
140
150
|
InOut: RelationExpr.InOut<D, M>
|
|
151
|
+
Where: RelationExpr.Where<D, M>
|
|
141
152
|
}>
|
|
142
153
|
|
|
143
154
|
/**
|
|
@@ -154,6 +165,7 @@ export type ExpressionV2<D = Fqn, M = Fqn> = ExclusiveUnion<{
|
|
|
154
165
|
Incoming: RelationExpr.Incoming<D, M>
|
|
155
166
|
Outgoing: RelationExpr.Outgoing<D, M>
|
|
156
167
|
InOut: RelationExpr.InOut<D, M>
|
|
168
|
+
RelationPredicateOrWhere: RelationExpr.Where<D, M>
|
|
157
169
|
}>
|
|
158
170
|
|
|
159
171
|
export namespace ExpressionV2 {
|
package/src/types/index.ts
CHANGED
package/src/types/operators.ts
CHANGED
|
@@ -61,19 +61,19 @@ export type WhereOperator<Tag, Kind> =
|
|
|
61
61
|
| OrOperator<Tag, Kind>
|
|
62
62
|
|
|
63
63
|
export type Filterable<
|
|
64
|
-
FTag extends string = string,
|
|
65
|
-
FKind extends string = string
|
|
64
|
+
FTag extends string | null = string | null,
|
|
65
|
+
FKind extends string | null = string | null,
|
|
66
66
|
> = {
|
|
67
67
|
tags?: readonly FTag[] | null
|
|
68
68
|
kind?: FKind
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
type OperatorPredicate<V extends Filterable> = (value: V) => boolean
|
|
71
|
+
export type OperatorPredicate<V extends Filterable> = (value: V) => boolean
|
|
72
72
|
|
|
73
73
|
export function whereOperatorAsPredicate<
|
|
74
74
|
FTag extends string = string,
|
|
75
|
-
FKind extends string = string
|
|
76
|
-
>(operator: WhereOperator<FTag, FKind>): OperatorPredicate<Filterable
|
|
75
|
+
FKind extends string = string,
|
|
76
|
+
>(operator: WhereOperator<FTag, FKind>): OperatorPredicate<Filterable> {
|
|
77
77
|
switch (true) {
|
|
78
78
|
case isTagEqual(operator): {
|
|
79
79
|
if ('eq' in operator.tag) {
|