@likec4/core 1.31.0 → 1.32.1
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/README.md +407 -5
- package/dist/builder/index.d.mts +221 -42
- package/dist/builder/index.mjs +118 -65
- package/dist/compute-view/index.d.mts +23 -7
- package/dist/compute-view/index.mjs +11 -6
- package/dist/compute-view/relationships-view/index.d.mts +9 -7
- package/dist/compute-view/relationships-view/index.mjs +3 -2
- package/dist/index.d.mts +10 -14
- package/dist/index.mjs +9 -6
- package/dist/model/index.d.mts +173 -19
- package/dist/model/index.mjs +6 -1
- package/dist/shared/core.BaYE_r29.d.mts +258 -0
- package/dist/shared/core.Bk7wEZFG.mjs +276 -0
- package/dist/shared/core.BrCnZFTn.mjs +32 -0
- package/dist/shared/core.BuO4ncfY.d.mts +146 -0
- package/dist/shared/{core.Bq753SYD.mjs → core.CBpKAlhj.mjs} +2012 -4422
- package/dist/shared/core.CUYDgv2-.mjs +214 -0
- package/dist/shared/{core.Cu-UdkSl.mjs → core.CpXlRyE5.mjs} +7 -494
- package/dist/shared/{core.C-YXI-43.mjs → core.Cy9smucx.mjs} +3 -1
- package/dist/shared/core.CywrQs86.d.mts +31 -0
- package/dist/shared/core.DXzRBkuI.d.mts +1264 -0
- package/dist/shared/core.DoK86JEe.mjs +518 -0
- package/dist/shared/{core.D2830qgg.d.mts → core.Pf5I9o0e.d.mts} +1 -1
- package/dist/shared/core.cbA9VZ02.mjs +2681 -0
- package/dist/shared/{core.CQXU9DF7.mjs → core.rmvsy0n3.mjs} +23 -32
- package/dist/shared/core.znRaUX_A.d.mts +920 -0
- package/dist/types/aux.d.mts +3 -0
- package/dist/types/aux.mjs +1 -0
- package/dist/types/index.d.mts +7 -45
- package/dist/types/index.mjs +130 -3
- package/dist/utils/index.d.mts +221 -53
- package/dist/utils/index.mjs +14 -10
- package/package.json +16 -8
- package/src/builder/Builder.deploymentModel.ts +82 -18
- package/src/builder/Builder.element.ts +40 -20
- package/src/builder/Builder.model.ts +66 -17
- package/src/builder/Builder.ts +168 -76
- package/src/builder/Builder.view-common.ts +35 -17
- package/src/builder/Builder.view-deployment.ts +25 -25
- package/src/builder/Builder.view-element.ts +13 -12
- package/src/builder/Builder.views.ts +12 -7
- package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +62 -34
- package/src/builder/__snapshots__/Builder-style2.compute-model.json5 +319 -0
- package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +45 -24
- package/src/builder/_types.ts +34 -27
- package/src/compute-view/compute-view.ts +31 -34
- package/src/compute-view/deployment-view/__test__/TestHelper.ts +27 -14
- package/src/compute-view/deployment-view/__test__/fixture.ts +15 -13
- package/src/compute-view/deployment-view/_types.ts +10 -10
- package/src/compute-view/deployment-view/clean-connections.ts +5 -7
- package/src/compute-view/deployment-view/compute.ts +16 -13
- package/src/compute-view/deployment-view/memory/memory.ts +5 -6
- package/src/compute-view/deployment-view/predicates/deploymentRefs.ts +4 -5
- package/src/compute-view/deployment-view/predicates/relation-direct.ts +25 -50
- package/src/compute-view/deployment-view/predicates/relation-in-out.ts +5 -7
- package/src/compute-view/deployment-view/predicates/relation-incoming.ts +7 -11
- package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +7 -10
- package/src/compute-view/deployment-view/predicates/utils.ts +37 -31
- package/src/compute-view/deployment-view/predicates/wildcard.ts +3 -2
- package/src/compute-view/deployment-view/stages/stage-final.ts +2 -2
- package/src/compute-view/deployment-view/stages/stage-include.ts +1 -1
- package/src/compute-view/deployment-view/utils.ts +79 -72
- package/src/compute-view/dynamic-view/__test__/fixture.ts +20 -11
- package/src/compute-view/dynamic-view/compute.ts +60 -53
- package/src/compute-view/element-view/__test__/TestHelper.ts +53 -29
- package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +26 -26
- package/src/compute-view/element-view/__test__/fixture.ts +134 -83
- package/src/compute-view/element-view/_types.ts +14 -19
- package/src/compute-view/element-view/clean-connections.ts +12 -8
- package/src/compute-view/element-view/compute.ts +61 -51
- package/src/compute-view/element-view/memory/NodeGroup.ts +8 -9
- package/src/compute-view/element-view/memory/memory.ts +22 -22
- package/src/compute-view/element-view/memory/stage-include.ts +5 -3
- package/src/compute-view/element-view/predicates/_utils.ts +18 -14
- package/src/compute-view/element-view/predicates/element-expand.ts +4 -5
- package/src/compute-view/element-view/predicates/element-kind-tag.ts +3 -4
- package/src/compute-view/element-view/predicates/element-ref.ts +3 -4
- package/src/compute-view/element-view/predicates/relation-direct.ts +16 -12
- package/src/compute-view/element-view/predicates/relation-in-out.ts +7 -8
- package/src/compute-view/element-view/predicates/relation-in.ts +19 -26
- package/src/compute-view/element-view/predicates/relation-out.ts +20 -21
- package/src/compute-view/element-view/predicates/wildcard.ts +3 -3
- package/src/compute-view/element-view/utils.ts +25 -23
- package/src/compute-view/index.ts +1 -1
- package/src/compute-view/memory/AbstractStageExclude.ts +3 -4
- package/src/compute-view/memory/AbstractStageInclude.ts +1 -1
- package/src/compute-view/memory/_types.ts +3 -2
- package/src/compute-view/relationships-view/_types.ts +3 -4
- package/src/compute-view/relationships-view/compute.ts +8 -11
- package/src/compute-view/relationships-view/layout.ts +6 -6
- package/src/compute-view/relationships-view/utils.ts +4 -4
- package/src/compute-view/utils/ancestorsOfNode.ts +7 -7
- package/src/compute-view/utils/applyCustomElementProperties.ts +16 -8
- package/src/compute-view/utils/applyCustomRelationProperties.ts +19 -9
- package/src/compute-view/utils/applyViewRuleStyles.ts +18 -10
- package/src/compute-view/utils/buildComputedNodes.ts +40 -40
- package/src/compute-view/utils/buildElementNotations.ts +14 -14
- package/src/compute-view/utils/elementExpressionToPredicate.ts +14 -15
- package/src/compute-view/utils/link-nodes-with-edges.ts +6 -4
- package/src/compute-view/utils/merge-props-from-relationships.ts +52 -20
- package/src/compute-view/utils/relationExpressionToPredicates.ts +19 -19
- package/src/compute-view/utils/resolve-extended-views.ts +8 -7
- package/src/compute-view/utils/resolve-global-rules.ts +31 -26
- package/src/compute-view/utils/topological-sort.ts +14 -14
- package/src/compute-view/utils/view-hash.ts +2 -2
- package/src/compute-view/utils/with-readable-edges.ts +9 -5
- package/src/index.ts +0 -32
- package/src/model/DeploymentElementModel.ts +171 -144
- package/src/model/DeploymentModel.ts +88 -65
- package/src/model/ElementModel.ts +85 -74
- package/src/model/LikeC4Model.ts +430 -241
- package/src/model/RelationModel.ts +63 -29
- package/src/model/__test__/fixture.ts +50 -36
- package/src/model/connection/Connection.ts +2 -2
- package/src/model/connection/deployment/DeploymentConnectionModel.ts +21 -24
- package/src/model/connection/deployment/find.ts +1 -1
- package/src/model/connection/model/ConnectionModel.ts +21 -20
- package/src/model/connection/model/find.ts +7 -7
- package/src/model/connection/ops.ts +6 -6
- package/src/model/guards.ts +66 -14
- package/src/model/index.ts +20 -7
- package/src/model/types.ts +41 -97
- package/src/model/view/EdgeModel.ts +47 -41
- package/src/model/view/LikeC4ViewModel.ts +130 -80
- package/src/model/view/NodeModel.ts +102 -96
- package/src/theme/element.ts +1 -1
- package/src/theme/index.ts +9 -9
- package/src/theme/relationships.ts +1 -1
- package/src/types/_common.ts +21 -15
- package/src/types/aux.ts +285 -0
- package/src/types/const.ts +34 -0
- package/src/types/expression-model.ts +292 -0
- package/src/types/expression.ts +311 -0
- package/src/types/fqnRef.ts +88 -0
- package/src/types/geometry.ts +131 -0
- package/src/types/global.ts +10 -8
- package/src/types/index.ts +39 -201
- package/src/types/model-data.ts +52 -84
- package/src/types/model-deployment.ts +87 -0
- package/src/types/model-dump.ts +72 -0
- package/src/types/model-logical.ts +111 -0
- package/src/types/model-spec.ts +81 -0
- package/src/types/operators.ts +51 -52
- package/src/types/scalar.ts +114 -0
- package/src/types/{theme.ts → styles.ts} +55 -15
- package/src/types/view-changes.ts +4 -5
- package/src/types/view-common.ts +157 -0
- package/src/types/view-computed.ts +113 -0
- package/src/types/view-layouted.ts +82 -0
- package/src/types/view-parsed.deployment.ts +40 -0
- package/src/types/view-parsed.dynamic.ts +78 -0
- package/src/types/view-parsed.element.ts +65 -0
- package/src/types/view.ts +122 -542
- package/src/utils/compare-natural.ts +43 -1
- package/src/utils/getOrCreate.ts +0 -34
- package/src/utils/index.ts +7 -12
- package/src/utils/iterable/filter.ts +1 -1
- package/src/utils/iterable/find.ts +3 -1
- package/src/utils/iterable/head.ts +22 -0
- package/src/utils/iterable/index.ts +1 -0
- package/src/utils/iterable/map.ts +1 -1
- package/src/utils/iterable/reduce.ts +1 -1
- package/src/utils/iterable/some.ts +1 -1
- package/src/utils/memoize-prop.ts +30 -0
- package/src/utils/object-hash.ts +1 -1
- package/src/utils/relations.ts +14 -11
- package/src/utils/string-hash.ts +1 -1
- package/dist/shared/core.CQDU11hR.d.mts +0 -753
- package/dist/shared/core.DJvmfnEi.d.mts +0 -1153
- package/dist/shared/core.DgfwjBtu.mjs +0 -495
- package/dist/shared/core.Dx7siloV.d.mts +0 -146
- package/dist/shared/core.SjLhMA7a.d.mts +0 -62
- package/src/builder/__snapshots__/Builder.spec.ts.snap +0 -374
- package/src/compute-view/element-view/predicates.ts +0 -520
- package/src/compute-view/utils/uniqueTags.ts +0 -21
- package/src/types/deployments.ts +0 -170
- package/src/types/element.ts +0 -109
- package/src/types/expression-v2-model.ts +0 -314
- package/src/types/expression-v2.ts +0 -392
- package/src/types/overview-graph.ts +0 -43
- package/src/types/relation.ts +0 -61
- package/src/types/scalars.ts +0 -39
- package/src/types/view-notation.ts +0 -9
- package/src/utils/graphlib.ts +0 -10
- /package/src/{errors/index.ts → utils/invariant.ts} +0 -0
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
import type { Simplify } from 'type-fest'
|
|
2
|
-
import {
|
|
2
|
+
import type { ElementModel } from '../../model'
|
|
3
3
|
import {
|
|
4
|
+
type AnyAux,
|
|
5
|
+
type aux,
|
|
4
6
|
type ComputedNode,
|
|
5
7
|
type Element,
|
|
6
|
-
type
|
|
7
|
-
type
|
|
8
|
+
type scalar,
|
|
9
|
+
type Unknown,
|
|
8
10
|
DefaultElementShape,
|
|
9
11
|
DefaultThemeColor,
|
|
10
|
-
|
|
12
|
+
GroupElementKind,
|
|
11
13
|
} from '../../types'
|
|
14
|
+
import { nonNullable } from '../../utils'
|
|
12
15
|
import { compareByFqnHierarchically, parentFqn } from '../../utils/fqn'
|
|
13
16
|
import { NodesGroup } from '../element-view/memory'
|
|
14
17
|
|
|
15
|
-
function updateDepthOfAncestors(node: ComputedNode, nodes: ReadonlyMap<
|
|
18
|
+
function updateDepthOfAncestors(node: ComputedNode, nodes: ReadonlyMap<string, ComputedNode>) {
|
|
16
19
|
let parentNd
|
|
17
20
|
while (!!node.parent && (parentNd = nodes.get(node.parent))) {
|
|
18
21
|
const depth = parentNd.depth ?? 1
|
|
@@ -25,30 +28,27 @@ function updateDepthOfAncestors(node: ComputedNode, nodes: ReadonlyMap<Fqn, Comp
|
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
modelRef: 1,
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// type ComputedNodeSource = Simplify<SetRequired<Partial<Omit<ComputedNode, 'parent' | 'children' | 'inEdges' | 'outEdges' | 'level' | 'depth'>>, 'id' | 'title' | 'kind'>>
|
|
36
|
-
export type ComputedNodeSource = Simplify<
|
|
37
|
-
& Pick<ComputedNode, 'id' | 'title' | 'kind' | 'deploymentRef' | 'modelRef'>
|
|
38
|
-
& Partial<Omit<Element, 'id' | 'title' | 'kind'>>
|
|
31
|
+
export type ComputedNodeSource<A extends AnyAux = Unknown> = Simplify<
|
|
32
|
+
& Pick<ComputedNode<A>, 'id' | 'title' | 'kind' | 'deploymentRef' | 'modelRef'>
|
|
33
|
+
& Partial<Omit<Element<A>, 'id' | 'title' | 'kind'>>
|
|
39
34
|
>
|
|
40
35
|
|
|
41
|
-
export function
|
|
42
|
-
return
|
|
36
|
+
export function elementModelToNodeSource<A extends AnyAux>(el: ElementModel<A>): ComputedNodeSource<A> {
|
|
37
|
+
return {
|
|
38
|
+
...el.$element,
|
|
39
|
+
tags: [...el.tags],
|
|
40
|
+
id: el.id as scalar.NodeId,
|
|
41
|
+
modelRef: el.id,
|
|
42
|
+
}
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
export function buildComputedNodes(
|
|
46
|
-
elements: ReadonlyArray<ComputedNodeSource
|
|
47
|
-
groups?: ReadonlyArray<NodesGroup
|
|
48
|
-
): ReadonlyMap<
|
|
49
|
-
const nodesMap = new Map<
|
|
45
|
+
export function buildComputedNodes<A extends AnyAux>(
|
|
46
|
+
elements: ReadonlyArray<ComputedNodeSource<A>>,
|
|
47
|
+
groups?: ReadonlyArray<NodesGroup<A>>,
|
|
48
|
+
): ReadonlyMap<scalar.NodeId, ComputedNode<A>> {
|
|
49
|
+
const nodesMap = new Map<scalar.NodeId, ComputedNode<A>>()
|
|
50
50
|
|
|
51
|
-
const elementToGroup = new Map<
|
|
51
|
+
const elementToGroup = new Map<aux.StrictFqn<A>, scalar.NodeId>()
|
|
52
52
|
|
|
53
53
|
groups?.forEach(({ id, parent, viewRule, elements }) => {
|
|
54
54
|
if (parent) {
|
|
@@ -57,8 +57,10 @@ export function buildComputedNodes(
|
|
|
57
57
|
nodesMap.set(id, {
|
|
58
58
|
id,
|
|
59
59
|
parent,
|
|
60
|
-
kind:
|
|
60
|
+
kind: GroupElementKind,
|
|
61
61
|
title: viewRule.title ?? '',
|
|
62
|
+
description: null,
|
|
63
|
+
technology: null,
|
|
62
64
|
color: viewRule.color ?? 'muted',
|
|
63
65
|
shape: 'rectangle',
|
|
64
66
|
children: [],
|
|
@@ -66,10 +68,7 @@ export function buildComputedNodes(
|
|
|
66
68
|
outEdges: [],
|
|
67
69
|
level: 0,
|
|
68
70
|
depth: 0,
|
|
69
|
-
|
|
70
|
-
technology: null,
|
|
71
|
-
tags: null,
|
|
72
|
-
links: null,
|
|
71
|
+
tags: [],
|
|
73
72
|
style: {
|
|
74
73
|
border: viewRule.border ?? 'dashed',
|
|
75
74
|
opacity: viewRule.opacity ?? 0,
|
|
@@ -87,10 +86,10 @@ export function buildComputedNodes(
|
|
|
87
86
|
// Ensure that parent nodes are created before child nodes
|
|
88
87
|
Array.from(elements)
|
|
89
88
|
.sort(compareByFqnHierarchically)
|
|
90
|
-
.forEach(({ id, style, kind, title, color, shape, ...el }) => {
|
|
89
|
+
.forEach(({ id, style, kind, title, color, shape, tags, ...el }) => {
|
|
91
90
|
let parent = parentFqn(id)
|
|
92
91
|
let level = 0
|
|
93
|
-
let parentNd: ComputedNode | undefined
|
|
92
|
+
let parentNd: ComputedNode<A> | undefined
|
|
94
93
|
// Find the first ancestor that is already in the map
|
|
95
94
|
while (parent) {
|
|
96
95
|
parentNd = nodesMap.get(parent)
|
|
@@ -99,10 +98,12 @@ export function buildComputedNodes(
|
|
|
99
98
|
}
|
|
100
99
|
parent = parentFqn(parent)
|
|
101
100
|
}
|
|
101
|
+
const fqn = el.modelRef ?? id as unknown as aux.StrictFqn<A>
|
|
102
102
|
// If parent is not found in the map, check if it is in a group
|
|
103
|
-
if (!parentNd && elementToGroup.has(
|
|
104
|
-
|
|
105
|
-
parentNd = nodesMap.get(
|
|
103
|
+
if (!parentNd && elementToGroup.has(fqn)) {
|
|
104
|
+
const parentGroupId = nonNullable(elementToGroup.get(fqn))
|
|
105
|
+
parentNd = nodesMap.get(parentGroupId)
|
|
106
|
+
parent = parentGroupId
|
|
106
107
|
}
|
|
107
108
|
if (parentNd) {
|
|
108
109
|
// if parent has no children and we are about to add first one
|
|
@@ -115,18 +116,17 @@ export function buildComputedNodes(
|
|
|
115
116
|
parentNd.children.push(id)
|
|
116
117
|
level = parentNd.level + 1
|
|
117
118
|
}
|
|
118
|
-
const node: ComputedNode = {
|
|
119
|
+
const node: ComputedNode<A> = {
|
|
119
120
|
id,
|
|
120
121
|
parent,
|
|
121
122
|
kind,
|
|
122
123
|
title,
|
|
124
|
+
description: null,
|
|
125
|
+
technology: null,
|
|
123
126
|
level,
|
|
124
127
|
color: color ?? DefaultThemeColor,
|
|
125
128
|
shape: shape ?? DefaultElementShape,
|
|
126
|
-
|
|
127
|
-
technology: null,
|
|
128
|
-
tags: null,
|
|
129
|
-
links: null,
|
|
129
|
+
tags: tags ?? [],
|
|
130
130
|
children: [],
|
|
131
131
|
inEdges: [],
|
|
132
132
|
outEdges: [],
|
|
@@ -139,7 +139,7 @@ export function buildComputedNodes(
|
|
|
139
139
|
})
|
|
140
140
|
|
|
141
141
|
// Create new map and add elements in the same order as they were in the input
|
|
142
|
-
const orderedMap = new Map<
|
|
142
|
+
const orderedMap = new Map<aux.NodeId, ComputedNode<A>>()
|
|
143
143
|
|
|
144
144
|
groups?.forEach(({ id }) => {
|
|
145
145
|
orderedMap.set(id, nonNullable(nodesMap.get(id)))
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { entries, flatMap, groupBy, map, mapValues, pipe, piped, prop, sortBy, unique } from 'remeda'
|
|
2
|
-
import type { ComputedNode,
|
|
2
|
+
import type { ComputedNode, NodeNotation } from '../../types'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Build element notations from computed nodes:
|
|
@@ -9,7 +9,7 @@ import type { ComputedNode, ElementNotation } from '../../types'
|
|
|
9
9
|
* 4. For each group get unique kinds
|
|
10
10
|
* 5. Unwind the groups
|
|
11
11
|
*/
|
|
12
|
-
export function buildElementNotations(nodes: ComputedNode[]):
|
|
12
|
+
export function buildElementNotations(nodes: ComputedNode<any>[]): NodeNotation[] {
|
|
13
13
|
return pipe(
|
|
14
14
|
nodes,
|
|
15
15
|
groupBy(prop('notation')),
|
|
@@ -22,25 +22,25 @@ export function buildElementNotations(nodes: ComputedNode[]): ElementNotation[]
|
|
|
22
22
|
mapValues(
|
|
23
23
|
piped(
|
|
24
24
|
map(prop('kind')),
|
|
25
|
-
unique()
|
|
26
|
-
)
|
|
25
|
+
unique(),
|
|
26
|
+
),
|
|
27
27
|
),
|
|
28
28
|
entries(),
|
|
29
29
|
map(([color, kinds]) => ({
|
|
30
30
|
kinds,
|
|
31
|
-
color
|
|
32
|
-
}))
|
|
33
|
-
)
|
|
31
|
+
color,
|
|
32
|
+
})),
|
|
33
|
+
),
|
|
34
34
|
),
|
|
35
35
|
entries(),
|
|
36
36
|
flatMap(([shape, colors]) =>
|
|
37
37
|
colors.map(({ color, kinds }) => ({
|
|
38
38
|
shape,
|
|
39
39
|
color,
|
|
40
|
-
kinds
|
|
40
|
+
kinds,
|
|
41
41
|
}))
|
|
42
|
-
)
|
|
43
|
-
)
|
|
42
|
+
),
|
|
43
|
+
),
|
|
44
44
|
),
|
|
45
45
|
entries(),
|
|
46
46
|
flatMap(([title, shapes]) =>
|
|
@@ -48,7 +48,7 @@ export function buildElementNotations(nodes: ComputedNode[]): ElementNotation[]
|
|
|
48
48
|
title,
|
|
49
49
|
shape,
|
|
50
50
|
color,
|
|
51
|
-
kinds
|
|
51
|
+
kinds,
|
|
52
52
|
}))
|
|
53
53
|
),
|
|
54
54
|
sortBy(
|
|
@@ -56,8 +56,8 @@ export function buildElementNotations(nodes: ComputedNode[]): ElementNotation[]
|
|
|
56
56
|
prop('title'),
|
|
57
57
|
[
|
|
58
58
|
n => n.kinds.length,
|
|
59
|
-
'desc'
|
|
60
|
-
]
|
|
61
|
-
)
|
|
59
|
+
'desc',
|
|
60
|
+
],
|
|
61
|
+
),
|
|
62
62
|
)
|
|
63
63
|
}
|
|
@@ -1,37 +1,36 @@
|
|
|
1
|
-
import { isNullish } from 'remeda'
|
|
2
|
-
import { nonexhaustive } from '../../errors'
|
|
3
1
|
import {
|
|
4
|
-
|
|
2
|
+
FqnRef,
|
|
3
|
+
ModelFqnExpr,
|
|
5
4
|
whereOperatorAsPredicate,
|
|
6
5
|
} from '../../types'
|
|
7
|
-
import { parentFqn } from '../../utils'
|
|
6
|
+
import { nonexhaustive, parentFqn } from '../../utils'
|
|
8
7
|
|
|
9
8
|
type Predicate<T> = (x: T) => boolean
|
|
10
9
|
|
|
11
|
-
export function elementExprToPredicate<T extends { id: string; tags
|
|
12
|
-
target:
|
|
10
|
+
export function elementExprToPredicate<T extends { id: string; tags: readonly string[]; kind: string }>(
|
|
11
|
+
target: ModelFqnExpr.Any,
|
|
13
12
|
): Predicate<T> {
|
|
14
|
-
if (
|
|
13
|
+
if (ModelFqnExpr.isCustom(target)) {
|
|
15
14
|
return elementExprToPredicate(target.custom.expr)
|
|
16
15
|
}
|
|
17
|
-
if (
|
|
16
|
+
if (ModelFqnExpr.isWhere(target)) {
|
|
18
17
|
const predicate = elementExprToPredicate(target.where.expr)
|
|
19
18
|
const where = whereOperatorAsPredicate(target.where.condition)
|
|
20
19
|
return n => predicate(n) && where(n)
|
|
21
20
|
}
|
|
22
|
-
if (
|
|
21
|
+
if (ModelFqnExpr.isElementKindExpr(target)) {
|
|
23
22
|
return target.isEqual ? n => n.kind === target.elementKind : n => n.kind !== target.elementKind
|
|
24
23
|
}
|
|
25
|
-
if (
|
|
24
|
+
if (ModelFqnExpr.isElementTagExpr(target)) {
|
|
26
25
|
return target.isEqual
|
|
27
|
-
? ({ tags }) =>
|
|
28
|
-
: ({ tags }) =>
|
|
26
|
+
? ({ tags }) => tags.includes(target.elementTag)
|
|
27
|
+
: ({ tags }) => !tags.includes(target.elementTag)
|
|
29
28
|
}
|
|
30
|
-
if (
|
|
29
|
+
if (ModelFqnExpr.isWildcard(target)) {
|
|
31
30
|
return () => true
|
|
32
31
|
}
|
|
33
|
-
if (
|
|
34
|
-
const fqn =
|
|
32
|
+
if (ModelFqnExpr.isModelRef(target)) {
|
|
33
|
+
const fqn = FqnRef.flatten(target.ref)
|
|
35
34
|
if (target.selector === 'expanded') {
|
|
36
35
|
return (n) => {
|
|
37
36
|
return n.id === fqn || parentFqn(n.id) === fqn
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { last, reverse } from 'remeda'
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import type { ComputedEdge, ComputedNode } from '../../types/view'
|
|
2
|
+
import type { AnyAux, ComputedEdge, ComputedNode } from '../../types'
|
|
3
|
+
import { invariant } from '../../utils'
|
|
5
4
|
import { commonHead } from '../../utils/common-head'
|
|
6
5
|
import { ancestorsOfNode } from './ancestorsOfNode'
|
|
7
6
|
|
|
@@ -9,7 +8,10 @@ import { ancestorsOfNode } from './ancestorsOfNode'
|
|
|
9
8
|
* Update `inEdges` and `outEdges` props of nodes based on the edges
|
|
10
9
|
* Mutates nodes and updates their in/out edges
|
|
11
10
|
*/
|
|
12
|
-
export function linkNodesWithEdges
|
|
11
|
+
export function linkNodesWithEdges<A extends AnyAux>(
|
|
12
|
+
nodesMap: ReadonlyMap<any, ComputedNode<A>>,
|
|
13
|
+
edges: ComputedEdge<A>[],
|
|
14
|
+
) {
|
|
13
15
|
for (const edge of edges) {
|
|
14
16
|
const source = nodesMap.get(edge.source)
|
|
15
17
|
const target = nodesMap.get(edge.target)
|
|
@@ -1,9 +1,28 @@
|
|
|
1
1
|
import { isTruthy, only, pickBy, pipe, reduce, unique } from 'remeda'
|
|
2
|
-
import type {
|
|
3
|
-
|
|
2
|
+
import type {
|
|
3
|
+
AnyAux,
|
|
4
|
+
aux,
|
|
5
|
+
Color,
|
|
6
|
+
DeploymentRelationship,
|
|
7
|
+
Link,
|
|
8
|
+
NonEmptyArray,
|
|
9
|
+
Relationship,
|
|
10
|
+
RelationshipArrowType,
|
|
11
|
+
RelationshipLineType,
|
|
12
|
+
} from '../../types'
|
|
4
13
|
import { isNonEmptyArray } from '../../utils'
|
|
5
14
|
|
|
6
|
-
function pickRelationshipProps(relation:
|
|
15
|
+
function pickRelationshipProps<A extends AnyAux>(relation: Relationship<A> | DeploymentRelationship<A>): {
|
|
16
|
+
title?: string
|
|
17
|
+
description?: string | null
|
|
18
|
+
technology: string | null
|
|
19
|
+
kind: aux.RelationKind<A> | null
|
|
20
|
+
color: Color | null
|
|
21
|
+
line: RelationshipLineType | null
|
|
22
|
+
head: RelationshipArrowType | null
|
|
23
|
+
tail: RelationshipArrowType | null
|
|
24
|
+
navigateTo: aux.StrictViewId<A> | null
|
|
25
|
+
} {
|
|
7
26
|
const {
|
|
8
27
|
title,
|
|
9
28
|
description = null,
|
|
@@ -13,33 +32,47 @@ function pickRelationshipProps(relation: ModelRelation | DeploymentRelation) {
|
|
|
13
32
|
line = null,
|
|
14
33
|
head = null,
|
|
15
34
|
tail = null,
|
|
16
|
-
navigateTo = null
|
|
35
|
+
navigateTo = null,
|
|
17
36
|
} = relation
|
|
18
37
|
return {
|
|
19
38
|
// Pick description only if title is present
|
|
20
39
|
...(title && {
|
|
21
40
|
title,
|
|
22
|
-
description
|
|
41
|
+
description,
|
|
23
42
|
}),
|
|
24
43
|
technology,
|
|
25
|
-
kind,
|
|
44
|
+
kind: kind as aux.RelationKind<A> | null,
|
|
26
45
|
color,
|
|
27
46
|
line,
|
|
28
47
|
head,
|
|
29
48
|
tail,
|
|
30
|
-
navigateTo
|
|
49
|
+
navigateTo: navigateTo as aux.StrictViewId<A> | null,
|
|
31
50
|
}
|
|
32
51
|
}
|
|
33
52
|
|
|
53
|
+
export type MergedRelationshipProps<A extends AnyAux> = {
|
|
54
|
+
title?: string | null
|
|
55
|
+
description?: string
|
|
56
|
+
technology?: string
|
|
57
|
+
kind?: aux.RelationKind<A>
|
|
58
|
+
color?: Color
|
|
59
|
+
line?: RelationshipLineType
|
|
60
|
+
head?: RelationshipArrowType
|
|
61
|
+
tail?: RelationshipArrowType
|
|
62
|
+
navigateTo?: aux.StrictViewId<A>
|
|
63
|
+
tags?: NonEmptyArray<aux.Tag<A>>
|
|
64
|
+
links?: NonEmptyArray<Link>
|
|
65
|
+
}
|
|
66
|
+
|
|
34
67
|
/**
|
|
35
68
|
* Merges properties from multiple relationships into a single object.
|
|
36
69
|
* @param relations - The relationships to merge.
|
|
37
70
|
* @param prefer - The relationship to prefer when merging.
|
|
38
71
|
*/
|
|
39
|
-
export function mergePropsFromRelationships(
|
|
40
|
-
relations: Array<
|
|
41
|
-
prefer?:
|
|
42
|
-
) {
|
|
72
|
+
export function mergePropsFromRelationships<A extends AnyAux>(
|
|
73
|
+
relations: Array<Relationship<A> | DeploymentRelationship<A>>,
|
|
74
|
+
prefer?: Relationship<A> | DeploymentRelationship<A>,
|
|
75
|
+
): MergedRelationshipProps<A> {
|
|
43
76
|
const allprops = pipe(
|
|
44
77
|
relations,
|
|
45
78
|
reduce(
|
|
@@ -83,16 +116,16 @@ export function mergePropsFromRelationships(
|
|
|
83
116
|
title: [] as string[],
|
|
84
117
|
description: [] as string[],
|
|
85
118
|
technology: [] as string[],
|
|
86
|
-
kind: [] as
|
|
119
|
+
kind: [] as aux.RelationKind<A>[],
|
|
87
120
|
head: [] as RelationshipArrowType[],
|
|
88
121
|
tail: [] as RelationshipArrowType[],
|
|
89
122
|
color: [] as Color[],
|
|
90
|
-
tags: [] as Tag[],
|
|
123
|
+
tags: [] as aux.Tag<A>[],
|
|
91
124
|
links: [] as Link[],
|
|
92
125
|
line: [] as RelationshipLineType[],
|
|
93
|
-
navigateTo: [] as ViewId[]
|
|
94
|
-
}
|
|
95
|
-
)
|
|
126
|
+
navigateTo: [] as aux.ViewId<A>[],
|
|
127
|
+
},
|
|
128
|
+
),
|
|
96
129
|
)
|
|
97
130
|
|
|
98
131
|
let technology = only(allprops.technology)
|
|
@@ -112,17 +145,16 @@ export function mergePropsFromRelationships(
|
|
|
112
145
|
line: only(allprops.line),
|
|
113
146
|
navigateTo: only(allprops.navigateTo),
|
|
114
147
|
...isNonEmptyArray(allprops.links) && { links: allprops.links },
|
|
115
|
-
...isNonEmptyArray(tags) && { tags }
|
|
148
|
+
...isNonEmptyArray(tags) && { tags },
|
|
116
149
|
},
|
|
117
|
-
isTruthy
|
|
150
|
+
isTruthy,
|
|
118
151
|
)
|
|
119
152
|
|
|
120
153
|
if (prefer) {
|
|
121
154
|
return {
|
|
122
155
|
...merged,
|
|
123
|
-
...pickBy(pickRelationshipProps(prefer), isTruthy)
|
|
156
|
+
...pickBy(pickRelationshipProps(prefer), isTruthy),
|
|
124
157
|
}
|
|
125
158
|
}
|
|
126
159
|
return merged
|
|
127
160
|
}
|
|
128
|
-
export type MergedRelationshipProps = ReturnType<typeof mergePropsFromRelationships>
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import type { ModelRelation } from '../../types/relation'
|
|
5
|
-
import type { ComputedNode } from '../../types/view'
|
|
1
|
+
import type { AnyAux, aux, ComputedNode } from '../../types'
|
|
2
|
+
import { ModelRelationExpr, whereOperatorAsPredicate } from '../../types'
|
|
3
|
+
import { nonexhaustive } from '../../utils'
|
|
6
4
|
import { elementExprToPredicate } from './elementExpressionToPredicate'
|
|
7
5
|
|
|
8
6
|
type Predicate<T> = (x: T) => boolean
|
|
9
|
-
export type FilterableEdge
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
export type FilterableEdge<A extends AnyAux> = {
|
|
8
|
+
tags?: aux.Tags<A> | null | undefined
|
|
9
|
+
kind?: string
|
|
10
|
+
source: ComputedNode<A>
|
|
11
|
+
target: ComputedNode<A>
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export function relationExpressionToPredicates<T extends FilterableEdge
|
|
15
|
-
expr:
|
|
14
|
+
export function relationExpressionToPredicates<A extends AnyAux, T extends FilterableEdge<A>>(
|
|
15
|
+
expr: ModelRelationExpr.Any<A>,
|
|
16
16
|
): Predicate<T> {
|
|
17
17
|
switch (true) {
|
|
18
|
-
case
|
|
18
|
+
case ModelRelationExpr.isCustom(expr): {
|
|
19
19
|
return relationExpressionToPredicates(expr.customRelation.expr)
|
|
20
20
|
}
|
|
21
|
-
case
|
|
21
|
+
case ModelRelationExpr.isWhere(expr): {
|
|
22
22
|
const predicate = relationExpressionToPredicates(expr.where.expr)
|
|
23
23
|
const where = whereOperatorAsPredicate(expr.where.condition)
|
|
24
24
|
return e =>
|
|
25
25
|
predicate(e) && where({
|
|
26
|
-
source: { tags: e.source.tags, kind: e.source.kind },
|
|
27
|
-
target: { tags: e.target.tags, kind: e.target.kind },
|
|
26
|
+
source: { tags: e.source.tags, kind: e.source.kind as aux.AllKinds<A> },
|
|
27
|
+
target: { tags: e.target.tags, kind: e.target.kind as aux.AllKinds<A> },
|
|
28
28
|
...(e.tags && { tags: e.tags }),
|
|
29
|
-
...(e.kind && { kind: e.kind }),
|
|
29
|
+
...(e.kind && { kind: e.kind as aux.AllKinds<A> }),
|
|
30
30
|
})
|
|
31
31
|
}
|
|
32
|
-
case
|
|
32
|
+
case ModelRelationExpr.isDirect(expr): {
|
|
33
33
|
const isSource = elementExprToPredicate(expr.source)
|
|
34
34
|
const isTarget = elementExprToPredicate(expr.target)
|
|
35
35
|
return edge => {
|
|
@@ -37,15 +37,15 @@ export function relationExpressionToPredicates<T extends FilterableEdge>(
|
|
|
37
37
|
|| (!!expr.isBidirectional && isSource(edge.target) && isTarget(edge.source))
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
-
case
|
|
40
|
+
case ModelRelationExpr.isInOut(expr): {
|
|
41
41
|
const isInOut = elementExprToPredicate(expr.inout)
|
|
42
42
|
return edge => isInOut(edge.source) || isInOut(edge.target)
|
|
43
43
|
}
|
|
44
|
-
case
|
|
44
|
+
case ModelRelationExpr.isIncoming(expr): {
|
|
45
45
|
const isTarget = elementExprToPredicate(expr.incoming)
|
|
46
46
|
return edge => isTarget(edge.target)
|
|
47
47
|
}
|
|
48
|
-
case
|
|
48
|
+
case ModelRelationExpr.isOutgoing(expr): {
|
|
49
49
|
const isSource = elementExprToPredicate(expr.outgoing)
|
|
50
50
|
return edge => isSource(edge.source)
|
|
51
51
|
}
|
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
import { unique, values } from 'remeda'
|
|
2
|
-
import { type
|
|
2
|
+
import { type LikeC4View, isElementView, isExtendsElementView } from '../../types/view'
|
|
3
3
|
|
|
4
4
|
import Graph from 'graphology'
|
|
5
5
|
import { topologicalSort } from 'graphology-dag/topological-sort'
|
|
6
6
|
import willCreateCycle from 'graphology-dag/will-create-cycle'
|
|
7
|
+
import type { AnyAux, aux, ParsedElementView } from '../../types'
|
|
7
8
|
import { isNonEmptyArray } from '../../utils'
|
|
8
9
|
/**
|
|
9
10
|
* Resolve rules of extended views
|
|
10
11
|
* (Removes invalid views)
|
|
11
12
|
*/
|
|
12
|
-
export function resolveRulesExtendedViews<V extends Record<any, LikeC4View
|
|
13
|
+
export function resolveRulesExtendedViews<A extends AnyAux, V extends Record<any, LikeC4View<A>>>(
|
|
13
14
|
unresolvedViews: V,
|
|
14
15
|
): V {
|
|
15
|
-
const g = new Graph<{ view: LikeC4View }>({
|
|
16
|
+
const g = new Graph<{ view: LikeC4View<A> }>({
|
|
16
17
|
type: 'directed',
|
|
17
18
|
})
|
|
18
|
-
const extendedViews = [] as
|
|
19
|
+
const extendedViews = [] as ParsedElementView<A>[]
|
|
19
20
|
for (const view of values(unresolvedViews)) {
|
|
20
21
|
g.addNode(view.id, { view })
|
|
21
22
|
if (isExtendsElementView(view)) {
|
|
@@ -57,7 +58,7 @@ export function resolveRulesExtendedViews<V extends Record<any, LikeC4View>>(
|
|
|
57
58
|
const tags = unique([
|
|
58
59
|
...(extendsFrom.tags ?? []),
|
|
59
60
|
...(view.tags ?? []),
|
|
60
|
-
])
|
|
61
|
+
]) as aux.Tags<A>
|
|
61
62
|
|
|
62
63
|
const links = [
|
|
63
64
|
...(extendsFrom.links ?? []),
|
|
@@ -69,12 +70,12 @@ export function resolveRulesExtendedViews<V extends Record<any, LikeC4View>>(
|
|
|
69
70
|
...view,
|
|
70
71
|
title: view.title ?? extendsFrom.title ?? null,
|
|
71
72
|
description: view.description ?? extendsFrom.description ?? null,
|
|
72
|
-
tags
|
|
73
|
+
tags,
|
|
73
74
|
links: isNonEmptyArray(links) ? links : null,
|
|
74
75
|
rules: [...extendsFrom.rules, ...view.rules],
|
|
75
76
|
}
|
|
76
77
|
return acc
|
|
77
|
-
}, {} as Record<string, LikeC4View
|
|
78
|
+
}, {} as Record<string, LikeC4View<A>>) as V
|
|
78
79
|
|
|
79
80
|
// forEachNodeInTopologicalOrder(g, (_id, { view }) => {
|
|
80
81
|
|
|
@@ -1,32 +1,37 @@
|
|
|
1
1
|
import { isNullish } from 'remeda'
|
|
2
|
-
import { nonexhaustive } from '../../errors'
|
|
3
2
|
import {
|
|
4
|
-
type
|
|
3
|
+
type AnyAux,
|
|
4
|
+
type DynamicViewIncludeRule,
|
|
5
5
|
type DynamicViewRule,
|
|
6
|
-
type
|
|
6
|
+
type ElementViewPredicate,
|
|
7
|
+
type ElementViewRule,
|
|
8
|
+
type ModelGlobals,
|
|
9
|
+
type ParsedDynamicView,
|
|
10
|
+
type ParsedElementView,
|
|
11
|
+
type ViewRuleGlobalPredicateRef,
|
|
12
|
+
type ViewRuleGlobalStyle,
|
|
7
13
|
isDynamicView,
|
|
8
14
|
isElementView,
|
|
9
15
|
isViewRuleGlobalPredicateRef,
|
|
10
16
|
isViewRuleGlobalStyle,
|
|
11
|
-
type ModelGlobals,
|
|
12
|
-
type ViewRule,
|
|
13
|
-
type ViewRuleGlobalPredicateRef,
|
|
14
|
-
type ViewRuleGlobalStyle
|
|
15
17
|
} from '../../types'
|
|
18
|
+
import { nonexhaustive } from '../../utils'
|
|
16
19
|
|
|
17
|
-
export function resolveGlobalRules<
|
|
18
|
-
view:
|
|
19
|
-
globals: ModelGlobals
|
|
20
|
-
)
|
|
20
|
+
export function resolveGlobalRules<A extends AnyAux>(
|
|
21
|
+
view: ParsedElementView<A> | ParsedDynamicView<A>,
|
|
22
|
+
globals: ModelGlobals<A>,
|
|
23
|
+
) {
|
|
21
24
|
if (isElementView(view)) {
|
|
22
25
|
return {
|
|
23
26
|
...view,
|
|
24
|
-
rules: resolveGlobalRulesInElementView(view.rules, globals)
|
|
27
|
+
rules: resolveGlobalRulesInElementView(view.rules, globals),
|
|
25
28
|
}
|
|
26
|
-
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (isDynamicView(view)) {
|
|
27
32
|
return {
|
|
28
33
|
...view,
|
|
29
|
-
rules: resolveGlobalRulesInDynamicView(view.rules, globals)
|
|
34
|
+
rules: resolveGlobalRulesInDynamicView(view.rules, globals),
|
|
30
35
|
}
|
|
31
36
|
}
|
|
32
37
|
nonexhaustive(view)
|
|
@@ -34,17 +39,17 @@ export function resolveGlobalRules<V extends DynamicView | ElementView>(
|
|
|
34
39
|
|
|
35
40
|
type ViewRuleGlobal = ViewRuleGlobalPredicateRef | ViewRuleGlobalStyle
|
|
36
41
|
|
|
37
|
-
export function resolveGlobalRulesInElementView(
|
|
38
|
-
rules:
|
|
39
|
-
globals: ModelGlobals
|
|
40
|
-
): Array<Exclude<
|
|
42
|
+
export function resolveGlobalRulesInElementView<M extends AnyAux>(
|
|
43
|
+
rules: ElementViewRule<M>[],
|
|
44
|
+
globals: ModelGlobals<M>,
|
|
45
|
+
): Array<Exclude<ElementViewRule<M>, ViewRuleGlobal>> {
|
|
41
46
|
return rules.reduce((acc, rule) => {
|
|
42
47
|
if (isViewRuleGlobalPredicateRef(rule)) {
|
|
43
48
|
const globalPredicates = globals.predicates[rule.predicateId]
|
|
44
49
|
if (isNullish(globalPredicates)) {
|
|
45
50
|
return acc
|
|
46
51
|
}
|
|
47
|
-
return acc.concat(globalPredicates)
|
|
52
|
+
return acc.concat(globalPredicates as ElementViewPredicate<M>[])
|
|
48
53
|
}
|
|
49
54
|
if (isViewRuleGlobalStyle(rule)) {
|
|
50
55
|
const globalStyles = globals.styles[rule.styleId]
|
|
@@ -55,20 +60,20 @@ export function resolveGlobalRulesInElementView(
|
|
|
55
60
|
}
|
|
56
61
|
acc.push(rule)
|
|
57
62
|
return acc
|
|
58
|
-
}, [] as Array<Exclude<
|
|
63
|
+
}, [] as Array<Exclude<ElementViewRule<M>, ViewRuleGlobal>>)
|
|
59
64
|
}
|
|
60
65
|
|
|
61
|
-
export function resolveGlobalRulesInDynamicView(
|
|
62
|
-
rules: DynamicViewRule[],
|
|
63
|
-
globals: ModelGlobals
|
|
64
|
-
): Array<Exclude<DynamicViewRule
|
|
66
|
+
export function resolveGlobalRulesInDynamicView<M extends AnyAux>(
|
|
67
|
+
rules: DynamicViewRule<M>[],
|
|
68
|
+
globals: ModelGlobals<M>,
|
|
69
|
+
): Array<Exclude<DynamicViewRule<M>, ViewRuleGlobal>> {
|
|
65
70
|
return rules.reduce((acc, rule) => {
|
|
66
71
|
if (isViewRuleGlobalPredicateRef(rule)) {
|
|
67
72
|
const globalPredicates = globals.dynamicPredicates[rule.predicateId]
|
|
68
73
|
if (isNullish(globalPredicates)) {
|
|
69
74
|
return acc
|
|
70
75
|
}
|
|
71
|
-
return acc.concat(globalPredicates)
|
|
76
|
+
return acc.concat(globalPredicates as DynamicViewIncludeRule<M>[])
|
|
72
77
|
}
|
|
73
78
|
if (isViewRuleGlobalStyle(rule)) {
|
|
74
79
|
const globalStyles = globals.styles[rule.styleId]
|
|
@@ -79,5 +84,5 @@ export function resolveGlobalRulesInDynamicView(
|
|
|
79
84
|
}
|
|
80
85
|
acc.push(rule)
|
|
81
86
|
return acc
|
|
82
|
-
}, [] as Array<Exclude<DynamicViewRule
|
|
87
|
+
}, [] as Array<Exclude<DynamicViewRule<M>, ViewRuleGlobal>>)
|
|
83
88
|
}
|