@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,99 @@
|
|
|
1
|
+
import { invariant } from '../../errors'
|
|
2
|
+
import { stringHash } from '../../utils'
|
|
3
|
+
import { equals } from '../../utils/set'
|
|
4
|
+
import {
|
|
5
|
+
type DeploymentElementModel,
|
|
6
|
+
DeploymentNodeModel,
|
|
7
|
+
type DeploymentRelationModel,
|
|
8
|
+
RelationshipsAccum
|
|
9
|
+
} from '../DeploymentElementModel'
|
|
10
|
+
import type { RelationshipModel } from '../RelationModel'
|
|
11
|
+
import type { AnyAux, IteratorLike } from '../types'
|
|
12
|
+
import type { Connection } from './ConnectionModel'
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Connection is ephemeral entity, result of a resolving relationships between source and target.
|
|
16
|
+
* Includes direct relationships and/or between their nested elements.
|
|
17
|
+
*/
|
|
18
|
+
export class DeploymentConnectionModel<M extends AnyAux = AnyAux>
|
|
19
|
+
implements Connection<DeploymentElementModel<M>, M['EdgeId']>
|
|
20
|
+
{
|
|
21
|
+
/**
|
|
22
|
+
* Common ancestor of the source and target elements.
|
|
23
|
+
* Represents the boundary of the connection.
|
|
24
|
+
*/
|
|
25
|
+
readonly boundary: DeploymentNodeModel<M> | null
|
|
26
|
+
|
|
27
|
+
constructor(
|
|
28
|
+
public readonly source: DeploymentElementModel<M>,
|
|
29
|
+
public readonly target: DeploymentElementModel<M>,
|
|
30
|
+
public readonly relations: RelationshipsAccum<M>
|
|
31
|
+
) {
|
|
32
|
+
this.id = stringHash(`deployment:${source.id}:${target.id}`) as M['EdgeId']
|
|
33
|
+
this.boundary = source.commonAncestor(target)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
readonly id: M['EdgeId']
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Human readable expression of the connection
|
|
40
|
+
* Mostly used for testing and debugging
|
|
41
|
+
*/
|
|
42
|
+
get expression(): string {
|
|
43
|
+
return `${this.source.id} -> ${this.target.id}`
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
nonEmpty(): boolean {
|
|
47
|
+
return this.relations.nonEmpty
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Check if connection contains deployment relation,
|
|
52
|
+
* that is directly connected to source or target.
|
|
53
|
+
*/
|
|
54
|
+
public hasDirectDeploymentRelation(): boolean {
|
|
55
|
+
for (const relation of this.relations.deployment) {
|
|
56
|
+
if (relation.source.id === this.source.id || relation.target.id === this.target.id) {
|
|
57
|
+
return true
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public *values(): IteratorLike<RelationshipModel<M> | DeploymentRelationModel<M>> {
|
|
64
|
+
yield* this.relations.model
|
|
65
|
+
yield* this.relations.deployment
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Merge with another connection, if it has the same source and target.
|
|
70
|
+
* Returns new connection with union of relationships.
|
|
71
|
+
*/
|
|
72
|
+
public mergeWith(other: DeploymentConnectionModel<M>): DeploymentConnectionModel<M> {
|
|
73
|
+
invariant(this.source.id === other.source.id, 'Cannot merge connections with different sources')
|
|
74
|
+
invariant(this.target.id === other.target.id, 'Cannot merge connections with different targets')
|
|
75
|
+
return new DeploymentConnectionModel(
|
|
76
|
+
this.source,
|
|
77
|
+
this.target,
|
|
78
|
+
this.relations.union(other.relations)
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public difference(other: DeploymentConnectionModel<M>): DeploymentConnectionModel<M> {
|
|
83
|
+
invariant(this.source.id === other.source.id, 'Cannot difference connection with different sources')
|
|
84
|
+
invariant(this.target.id === other.target.id, 'Cannot difference connection with different targets')
|
|
85
|
+
return new DeploymentConnectionModel(
|
|
86
|
+
this.source,
|
|
87
|
+
this.target,
|
|
88
|
+
this.relations.difference(other.relations)
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public equals(other: DeploymentConnectionModel<M>): boolean {
|
|
93
|
+
return this.id === other.id
|
|
94
|
+
&& this.source.id === other.source.id
|
|
95
|
+
&& this.target.id === other.target.id
|
|
96
|
+
&& equals(this.relations.model, other.relations.model)
|
|
97
|
+
&& equals(this.relations.deployment, other.relations.deployment)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { isSameHierarchy } from '../../utils/fqn'
|
|
2
|
+
import { type DeploymentElementModel } from '../DeploymentElementModel'
|
|
3
|
+
import type { AnyAux } from '../types'
|
|
4
|
+
import { DeploymentConnectionModel } from './DeploymentConnectionModel'
|
|
5
|
+
|
|
6
|
+
export { mergeConnections } from './model'
|
|
7
|
+
|
|
8
|
+
export { DeploymentConnectionModel }
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Resolve connection from source to target
|
|
12
|
+
* If direction is `both`, also look for reverse connection
|
|
13
|
+
*
|
|
14
|
+
* @default direction directed
|
|
15
|
+
*/
|
|
16
|
+
export function findConnection<M extends AnyAux>(
|
|
17
|
+
source: DeploymentElementModel<M>,
|
|
18
|
+
target: DeploymentElementModel<NoInfer<M>>,
|
|
19
|
+
direction: 'directed'
|
|
20
|
+
):
|
|
21
|
+
| readonly [DeploymentConnectionModel<M>]
|
|
22
|
+
| readonly []
|
|
23
|
+
export function findConnection<M extends AnyAux>(
|
|
24
|
+
source: DeploymentElementModel<M>,
|
|
25
|
+
target: DeploymentElementModel<NoInfer<M>>,
|
|
26
|
+
direction: 'both'
|
|
27
|
+
):
|
|
28
|
+
| readonly [DeploymentConnectionModel<M>, DeploymentConnectionModel<M>]
|
|
29
|
+
| readonly [DeploymentConnectionModel<M>]
|
|
30
|
+
| readonly []
|
|
31
|
+
export function findConnection<M extends AnyAux>(
|
|
32
|
+
source: DeploymentElementModel<M>,
|
|
33
|
+
target: DeploymentElementModel<NoInfer<M>>,
|
|
34
|
+
direction?: 'directed' | 'both'
|
|
35
|
+
):
|
|
36
|
+
| readonly [DeploymentConnectionModel<M>, DeploymentConnectionModel<M>]
|
|
37
|
+
| readonly [DeploymentConnectionModel<M>]
|
|
38
|
+
| readonly []
|
|
39
|
+
export function findConnection<M extends AnyAux>(
|
|
40
|
+
source: DeploymentElementModel<M>,
|
|
41
|
+
target: DeploymentElementModel<NoInfer<M>>,
|
|
42
|
+
direction: 'directed' | 'both' = 'directed'
|
|
43
|
+
) {
|
|
44
|
+
if (source === target) {
|
|
45
|
+
return []
|
|
46
|
+
}
|
|
47
|
+
if (isSameHierarchy(source, target)) {
|
|
48
|
+
return []
|
|
49
|
+
}
|
|
50
|
+
const directedIntersection = source.allOutgoing.intersect(target.allIncoming)
|
|
51
|
+
|
|
52
|
+
const directed = directedIntersection.nonEmpty
|
|
53
|
+
? [
|
|
54
|
+
new DeploymentConnectionModel<M>(
|
|
55
|
+
source,
|
|
56
|
+
target,
|
|
57
|
+
directedIntersection
|
|
58
|
+
)
|
|
59
|
+
] as const
|
|
60
|
+
: [] as const
|
|
61
|
+
|
|
62
|
+
if (direction === 'directed') {
|
|
63
|
+
return directed
|
|
64
|
+
}
|
|
65
|
+
return [
|
|
66
|
+
...directed,
|
|
67
|
+
...findConnection(target, source, 'directed')
|
|
68
|
+
] as const
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Resolve all connections between element and others
|
|
73
|
+
* By default, look for both directions.
|
|
74
|
+
*
|
|
75
|
+
* @default direction both
|
|
76
|
+
*/
|
|
77
|
+
export function findConnectionsBetween<M extends AnyAux>(
|
|
78
|
+
element: DeploymentElementModel<M>,
|
|
79
|
+
others: Iterable<DeploymentElementModel<NoInfer<M>>>,
|
|
80
|
+
direction: 'directed' | 'both' = 'both'
|
|
81
|
+
): readonly DeploymentConnectionModel<M>[] {
|
|
82
|
+
if (element.allIncoming.isEmpty && element.allOutgoing.isEmpty) {
|
|
83
|
+
return []
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// We separate resolved connection,
|
|
87
|
+
// because we want return outgoing first
|
|
88
|
+
const outgoing = [] as DeploymentConnectionModel<M>[]
|
|
89
|
+
const incoming = [] as DeploymentConnectionModel<M>[]
|
|
90
|
+
for (const _other of others) {
|
|
91
|
+
if (element === _other) {
|
|
92
|
+
continue
|
|
93
|
+
}
|
|
94
|
+
for (const found of findConnection(element, _other, direction)) {
|
|
95
|
+
if (found.source === element) {
|
|
96
|
+
outgoing.push(found)
|
|
97
|
+
} else {
|
|
98
|
+
incoming.push(found)
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return [
|
|
103
|
+
...outgoing,
|
|
104
|
+
...incoming
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Resolve all connections within a given set of elements
|
|
110
|
+
*/
|
|
111
|
+
export function findConnectionsWithin<M extends AnyAux>(
|
|
112
|
+
elements: Iterable<DeploymentElementModel<M>>
|
|
113
|
+
): readonly DeploymentConnectionModel<M>[] {
|
|
114
|
+
return [...elements].reduce((acc, el, index, array) => {
|
|
115
|
+
// skip for last element
|
|
116
|
+
if (index === array.length - 1) {
|
|
117
|
+
return acc
|
|
118
|
+
}
|
|
119
|
+
acc.push(
|
|
120
|
+
...findConnectionsBetween(el, array.slice(index + 1), 'both')
|
|
121
|
+
)
|
|
122
|
+
return acc
|
|
123
|
+
}, [] as DeploymentConnectionModel<M>[])
|
|
124
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { isSameHierarchy } from '../../utils/fqn'
|
|
2
|
+
import { intersection } from '../../utils/set'
|
|
3
|
+
import type { ElementModel } from '../ElementModel'
|
|
4
|
+
import type { AnyAux } from '../types'
|
|
5
|
+
import { type Connection, ConnectionModel } from './ConnectionModel'
|
|
6
|
+
|
|
7
|
+
export function mergeConnections<C extends Connection<any, any>>(
|
|
8
|
+
connections: readonly C[]
|
|
9
|
+
): C[] {
|
|
10
|
+
const map = new Map<C['id'], C>()
|
|
11
|
+
for (const conn of connections) {
|
|
12
|
+
const existing = map.get(conn.id)
|
|
13
|
+
if (existing) {
|
|
14
|
+
map.set(conn.id, existing.mergeWith(conn) as any)
|
|
15
|
+
} else {
|
|
16
|
+
map.set(conn.id, conn)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return [...map.values()]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Resolve connection from source to target
|
|
24
|
+
* If direction is `both`, also look for reverse connection
|
|
25
|
+
*/
|
|
26
|
+
export function findConnection<M extends AnyAux>(
|
|
27
|
+
source: ElementModel<M>,
|
|
28
|
+
target: ElementModel<NoInfer<M>>,
|
|
29
|
+
direction: 'directed' | 'both' = 'directed'
|
|
30
|
+
):
|
|
31
|
+
| readonly [ConnectionModel<M>, ConnectionModel<M>]
|
|
32
|
+
| readonly [ConnectionModel<M>]
|
|
33
|
+
| readonly []
|
|
34
|
+
{
|
|
35
|
+
if (source === target) {
|
|
36
|
+
return []
|
|
37
|
+
}
|
|
38
|
+
if (isSameHierarchy(source, target)) {
|
|
39
|
+
return []
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const directedIntersection = intersection(source.allOutgoing, target.allIncoming)
|
|
43
|
+
|
|
44
|
+
const directed = directedIntersection.size > 0
|
|
45
|
+
? [
|
|
46
|
+
new ConnectionModel(
|
|
47
|
+
source,
|
|
48
|
+
target,
|
|
49
|
+
directedIntersection
|
|
50
|
+
)
|
|
51
|
+
] as const
|
|
52
|
+
: [] as const
|
|
53
|
+
|
|
54
|
+
if (direction === 'directed') {
|
|
55
|
+
return directed
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const reverseIntersection = intersection(source.allIncoming, target.allOutgoing)
|
|
59
|
+
const reverse = reverseIntersection.size > 0
|
|
60
|
+
? [
|
|
61
|
+
new ConnectionModel(
|
|
62
|
+
target,
|
|
63
|
+
source,
|
|
64
|
+
reverseIntersection
|
|
65
|
+
)
|
|
66
|
+
] as const
|
|
67
|
+
: [] as const
|
|
68
|
+
|
|
69
|
+
return [...directed, ...reverse] as const
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Resolve all connections between element and others
|
|
74
|
+
* By default, look for both directions.
|
|
75
|
+
*/
|
|
76
|
+
export function findConnectionsBetween<M extends AnyAux>(
|
|
77
|
+
element: ElementModel<M>,
|
|
78
|
+
others: Iterable<ElementModel<NoInfer<M>>>,
|
|
79
|
+
direction: 'directed' | 'both' = 'both'
|
|
80
|
+
): readonly ConnectionModel<M>[] {
|
|
81
|
+
if (element.allIncoming.size === 0 && element.allOutgoing.size === 0) {
|
|
82
|
+
return []
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// We separate resolved connection,
|
|
86
|
+
// because we want return outgoing first
|
|
87
|
+
const outgoing = [] as ConnectionModel<M>[]
|
|
88
|
+
const incoming = [] as ConnectionModel<M>[]
|
|
89
|
+
for (const _other of others) {
|
|
90
|
+
if (element === _other) {
|
|
91
|
+
continue
|
|
92
|
+
}
|
|
93
|
+
for (const found of findConnection(element, _other, direction)) {
|
|
94
|
+
if (found.source === element) {
|
|
95
|
+
outgoing.push(found)
|
|
96
|
+
} else {
|
|
97
|
+
incoming.push(found)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return [
|
|
102
|
+
...outgoing,
|
|
103
|
+
...incoming
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Resolve all connections within a given set of elements
|
|
109
|
+
*/
|
|
110
|
+
export function findConnectionsWithin<M extends AnyAux>(
|
|
111
|
+
elements: Iterable<ElementModel<M>>
|
|
112
|
+
): readonly ConnectionModel<M>[] {
|
|
113
|
+
return [...elements].reduce((acc, el, index, array) => {
|
|
114
|
+
// skip for last element
|
|
115
|
+
if (index === array.length - 1) {
|
|
116
|
+
return acc
|
|
117
|
+
}
|
|
118
|
+
acc.push(
|
|
119
|
+
...findConnectionsBetween(el, array.slice(index + 1), 'both')
|
|
120
|
+
)
|
|
121
|
+
return acc
|
|
122
|
+
}, [] as ConnectionModel<M>[])
|
|
123
|
+
}
|
package/src/model/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { LikeC4DeploymentModel } from './DeploymentModel'
|
|
2
2
|
export { LikeC4Model } from './LikeC4Model'
|
|
3
|
-
export
|
|
3
|
+
export type * from './LikeC4Model'
|
|
4
|
+
export type { Aux as LikeC4ModelAux } from './types'
|
|
5
|
+
export { LikeC4ViewModel } from './view/LikeC4ViewModel'
|
package/src/model/types.ts
CHANGED
|
@@ -1,23 +1,103 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import type { IsLiteral, LiteralUnion, Simplify } from 'type-fest'
|
|
2
|
+
import type {
|
|
3
|
+
AnyLikeC4Model,
|
|
4
|
+
ComputedView,
|
|
5
|
+
DiagramView,
|
|
6
|
+
EdgeId,
|
|
7
|
+
Fqn,
|
|
8
|
+
KeysOf,
|
|
9
|
+
LayoutedLikeC4Model,
|
|
10
|
+
NodeId,
|
|
11
|
+
ParsedLikeC4ModelDump,
|
|
12
|
+
RelationId,
|
|
13
|
+
ViewId
|
|
14
|
+
} from '../types'
|
|
15
|
+
import { isString } from '../utils/guards'
|
|
12
16
|
|
|
13
17
|
export type IncomingFilter = 'all' | 'direct' | 'to-descendants'
|
|
14
18
|
export type OutgoingFilter = 'all' | 'direct' | 'from-descendants'
|
|
15
19
|
|
|
16
|
-
export type ElementOrFqn = Fqn | { id: Fqn }
|
|
17
|
-
|
|
18
20
|
/**
|
|
19
21
|
* Utility function to extract `id` from the given element.
|
|
20
22
|
*/
|
|
21
|
-
export function getId(element:
|
|
22
|
-
return isString(element) ? element : element.id
|
|
23
|
+
export function getId<Id extends string>(element: string | { id: Id }): Id {
|
|
24
|
+
return isString(element) ? element as Id : element.id
|
|
23
25
|
}
|
|
26
|
+
|
|
27
|
+
export type IteratorLike<T> = IteratorObject<T, BuiltinIteratorReturn>
|
|
28
|
+
|
|
29
|
+
type WithId<Id> = { id: Id }
|
|
30
|
+
|
|
31
|
+
type WithViews<Id extends string, ViewType> = { views: Record<Id, ViewType> }
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Auxilary type to keep track
|
|
35
|
+
*/
|
|
36
|
+
export interface Aux<
|
|
37
|
+
Element extends string,
|
|
38
|
+
Deployment extends string,
|
|
39
|
+
Views extends string,
|
|
40
|
+
ViewType
|
|
41
|
+
> {
|
|
42
|
+
// Model: Model
|
|
43
|
+
|
|
44
|
+
// If Fqn is just a string, then we use generic Fqn to have better hints in the editor
|
|
45
|
+
Fqn: IsLiteral<Element> extends true ? Fqn<Element> : Fqn
|
|
46
|
+
Element: Element
|
|
47
|
+
ElementOrFqn: Element | WithId<this['Fqn']>
|
|
48
|
+
|
|
49
|
+
DeploymentFqn: IsLiteral<Deployment> extends true ? Fqn<Deployment> : Fqn
|
|
50
|
+
Deployment: Deployment
|
|
51
|
+
DeploymentOrFqn: Deployment | WithId<this['DeploymentFqn']>
|
|
52
|
+
|
|
53
|
+
ViewId: IsLiteral<Views> extends true ? ViewId<Views> : ViewId
|
|
54
|
+
ViewIdLiteral: Views
|
|
55
|
+
ViewType: ViewType
|
|
56
|
+
|
|
57
|
+
RelationId: RelationId
|
|
58
|
+
NodeId: NodeId
|
|
59
|
+
NodeIdLiteral: string
|
|
60
|
+
EdgeId: EdgeId
|
|
61
|
+
EdgeIdLiteral: string
|
|
62
|
+
|
|
63
|
+
NodeOrId: LiteralUnion<this['NodeIdLiteral'], string> | WithId<this['NodeId']>
|
|
64
|
+
EdgeOrId: LiteralUnion<this['EdgeIdLiteral'], string> | WithId<this['EdgeId']>
|
|
65
|
+
|
|
66
|
+
Model: Simplify<Omit<AnyLikeC4Model, 'views'> & WithViews<this['ViewId'], ViewType>>
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export type AnyAux = Aux<
|
|
70
|
+
string,
|
|
71
|
+
string,
|
|
72
|
+
string,
|
|
73
|
+
any
|
|
74
|
+
>
|
|
75
|
+
|
|
76
|
+
export namespace Aux {
|
|
77
|
+
export type FromModel<M> = M extends AnyLikeC4Model ? Aux<
|
|
78
|
+
KeysOf<M['elements']>,
|
|
79
|
+
KeysOf<M['deployments']['elements']>,
|
|
80
|
+
KeysOf<M['views']>,
|
|
81
|
+
M extends LayoutedLikeC4Model ? DiagramView<ViewId<KeysOf<M['views']>>, string>
|
|
82
|
+
: ComputedView<ViewId<KeysOf<M['views']>>, string>
|
|
83
|
+
>
|
|
84
|
+
: never
|
|
85
|
+
|
|
86
|
+
export type FromDump<M> = M extends ParsedLikeC4ModelDump ? Aux<
|
|
87
|
+
KeysOf<M['elements']>,
|
|
88
|
+
KeysOf<M['deployments']['elements']>,
|
|
89
|
+
KeysOf<M['views']>,
|
|
90
|
+
DiagramView<ViewId<KeysOf<M['views']>>, string>
|
|
91
|
+
>
|
|
92
|
+
: never
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// export type FromModel<M> = LikeC4Model<
|
|
96
|
+
// M extends AnyLikeC4Model<
|
|
97
|
+
// infer Fqn extends string,
|
|
98
|
+
// infer Deployment extends string,
|
|
99
|
+
// infer ViewId extends string,
|
|
100
|
+
// any
|
|
101
|
+
// > ? Aux<Fqn, Deployment, ViewId, M>
|
|
102
|
+
// : Aux<KeysOf<>, string, string, ComputedLikeC4Model | LayoutedLikeC4Model>
|
|
103
|
+
// >
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { isNonNullish } from 'remeda'
|
|
2
|
+
import type { LiteralUnion } from 'type-fest'
|
|
3
|
+
import {
|
|
4
|
+
type ComputedDynamicView,
|
|
5
|
+
type ComputedView,
|
|
6
|
+
type DiagramView,
|
|
7
|
+
extractStep,
|
|
8
|
+
isStepEdgeId,
|
|
9
|
+
type RelationId as C4RelationID,
|
|
10
|
+
type StepEdgeId,
|
|
11
|
+
type Tag as C4Tag
|
|
12
|
+
} from '../../types'
|
|
13
|
+
import type { DeploymentRelationModel } from '../DeploymentElementModel'
|
|
14
|
+
import type { LikeC4Model } from '../LikeC4Model'
|
|
15
|
+
import type { RelationshipModel } from '../RelationModel'
|
|
16
|
+
import type { AnyAux, IteratorLike } from '../types'
|
|
17
|
+
import type { LikeC4ViewModel } from './LikeC4ViewModel'
|
|
18
|
+
import type { NodeModel } from './NodeModel'
|
|
19
|
+
|
|
20
|
+
export type EdgesIterator<M extends AnyAux, V extends ComputedView | DiagramView> = IteratorLike<EdgeModel<M, V>>
|
|
21
|
+
|
|
22
|
+
export class EdgeModel<M extends AnyAux, V extends ComputedView | DiagramView = M['ViewType']> {
|
|
23
|
+
constructor(
|
|
24
|
+
public readonly view: LikeC4ViewModel<M, V>,
|
|
25
|
+
public readonly $edge: V['edges'][number],
|
|
26
|
+
public readonly source: NodeModel<M, V>,
|
|
27
|
+
public readonly target: NodeModel<M, V>
|
|
28
|
+
) {
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get id(): M['EdgeId'] {
|
|
32
|
+
return this.$edge.id
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get parent(): NodeModel<M, V> | null {
|
|
36
|
+
return this.$edge.parent ? this.view.node(this.$edge.parent) : null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get label(): string | null {
|
|
40
|
+
return this.$edge.label
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get description(): string | null {
|
|
44
|
+
return this.$edge.description ?? null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get technology(): string | null {
|
|
48
|
+
return this.$edge.technology ?? null
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public hasParent(): this is EdgeModel.WithParent<M, V> {
|
|
52
|
+
return this.$edge.parent !== null
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get tags(): ReadonlyArray<C4Tag> {
|
|
56
|
+
return this.$edge.tags ?? []
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
get stepNumber(): number | null {
|
|
60
|
+
return this.isStep() ? extractStep(this.id) : null
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get navigateTo(): LikeC4ViewModel<M> | null {
|
|
64
|
+
return this.$edge.navigateTo ? this.view.$model.view(this.$edge.navigateTo) : null
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public isStep(): this is EdgeModel.StepEdge<M, ComputedDynamicView> {
|
|
68
|
+
return isStepEdgeId(this.id)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public relationships(type: 'model'): IteratorLike<RelationshipModel<M>>
|
|
72
|
+
public relationships(type: 'deployment'): IteratorLike<DeploymentRelationModel<M>>
|
|
73
|
+
public relationships(type?: 'model' | 'deployment'): IteratorLike<LikeC4Model.AnyRelation<M>>
|
|
74
|
+
public *relationships(type: 'model' | 'deployment' | undefined): IteratorLike<LikeC4Model.AnyRelation<M>> {
|
|
75
|
+
for (const id of this.$edge.relations) {
|
|
76
|
+
// if type is provided, then we need to filter relationships
|
|
77
|
+
if (type) {
|
|
78
|
+
yield this.view.$model.relationship(id, type)
|
|
79
|
+
const rel = this.view.$model.findRelationship(id, type)
|
|
80
|
+
if (rel) {
|
|
81
|
+
yield rel
|
|
82
|
+
}
|
|
83
|
+
} else {
|
|
84
|
+
yield this.view.$model.relationship(id)
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public includesRelation(rel: M['RelationId']): boolean {
|
|
91
|
+
return this.$edge.relations.includes(rel as C4RelationID)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
namespace EdgeModel {
|
|
96
|
+
export interface StepEdge<M extends AnyAux, V extends ComputedView | DiagramView> extends EdgeModel<M, V> {
|
|
97
|
+
id: StepEdgeId
|
|
98
|
+
stepNumber: number
|
|
99
|
+
}
|
|
100
|
+
export interface WithParent<M extends AnyAux, V extends ComputedView | DiagramView> extends EdgeModel<M, V> {
|
|
101
|
+
parent: NodeModel<M, V>
|
|
102
|
+
}
|
|
103
|
+
}
|