@likec4/core 1.17.1 → 1.19.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/LICENSE +1 -1
- package/dist/builder/index.d.mts +502 -0
- package/dist/builder/index.d.ts +502 -0
- package/dist/builder/index.js +871 -0
- package/dist/compute-view/index.d.mts +22 -0
- package/dist/compute-view/index.d.ts +22 -0
- package/dist/compute-view/index.js +78 -0
- package/dist/index.d.mts +10 -919
- package/dist/index.d.ts +10 -919
- package/dist/{index.mjs → index.js} +7 -1688
- package/dist/model/index.d.mts +254 -0
- package/dist/model/index.d.ts +254 -0
- package/dist/model/index.js +1 -0
- package/dist/shared/chunk-RAAYCPUM.M-JWF7SS.js +21 -0
- package/dist/shared/core.BIfgabEw.d.ts +719 -0
- package/dist/shared/core.BZ9Msq7w.d.mts +719 -0
- package/dist/shared/{core.CoLQkcYL.d.cts → core.C05RDLhi.d.ts} +460 -362
- package/dist/shared/{core.CoLQkcYL.d.mts → core.CmYMqgha.d.mts} +460 -362
- package/dist/shared/core.D6-fWbM3.d.ts +127 -0
- package/dist/shared/core.D74xkKkG.d.mts +148 -0
- package/dist/shared/core.D74xkKkG.d.ts +148 -0
- package/dist/shared/core.sLaWHBjR.d.mts +127 -0
- package/dist/shared/index.-BdzdI2C.js +7443 -0
- package/dist/shared/object_hash.CE_oF3I3.js +1222 -0
- package/dist/shared/{core.BXTs-8n7.mjs → view.CyZrG8BJ.js} +108 -47
- package/dist/types/index.d.mts +71 -1
- package/dist/types/index.d.ts +71 -1
- package/dist/types/index.js +20 -0
- package/dist/utils/index.d.mts +404 -0
- package/dist/utils/index.d.ts +404 -0
- package/dist/utils/index.js +330 -0
- package/package.json +59 -47
- package/src/builder/Builder-style1.test-d.ts +190 -0
- package/src/builder/Builder-style2.test-d.ts +175 -0
- package/src/builder/Builder.deployment.ts +224 -0
- package/src/builder/Builder.deploymentModel.ts +385 -0
- package/src/builder/Builder.element.ts +19 -19
- package/src/builder/Builder.model.ts +67 -42
- package/src/builder/Builder.ts +533 -367
- package/src/builder/Builder.view-common.ts +234 -0
- package/src/builder/Builder.view-deployment.ts +135 -0
- package/src/builder/Builder.view-element.ts +189 -0
- package/src/builder/Builder.views.ts +109 -33
- package/src/builder/Builder.with.ts +475 -0
- package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +374 -0
- package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +183 -0
- package/src/builder/__snapshots__/Builder.spec.ts.snap +374 -0
- package/src/builder/_types.ts +113 -18
- package/src/builder/index.ts +10 -4
- package/src/colors/index.ts +2 -2
- package/src/compute-view/compute-view.ts +83 -0
- package/src/compute-view/deployment-view/__test__/TestHelper.ts +236 -0
- package/src/compute-view/deployment-view/__test__/fixture.ts +198 -0
- package/src/compute-view/deployment-view/_types.ts +37 -0
- package/src/compute-view/deployment-view/clean-connections.ts +238 -0
- package/src/compute-view/deployment-view/compute.ts +125 -0
- package/src/compute-view/deployment-view/memory/index.ts +9 -0
- package/src/compute-view/deployment-view/memory/memory.ts +97 -0
- package/src/compute-view/deployment-view/predicates/elements.ts +144 -0
- package/src/compute-view/deployment-view/predicates/relation-direct.ts +237 -0
- package/src/compute-view/deployment-view/predicates/relation-in-out.ts +61 -0
- package/src/compute-view/deployment-view/predicates/relation-incoming.ts +95 -0
- package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +88 -0
- package/src/compute-view/deployment-view/predicates/wildcard.ts +29 -0
- package/src/compute-view/deployment-view/stages/stage-exclude.ts +5 -0
- package/src/compute-view/deployment-view/stages/stage-final.ts +245 -0
- package/src/compute-view/deployment-view/stages/stage-include.ts +95 -0
- package/src/compute-view/deployment-view/utils.ts +276 -0
- package/src/compute-view/dynamic-view/__test__/fixture.ts +58 -0
- package/src/compute-view/dynamic-view/compute.ts +324 -0
- package/src/compute-view/element-view/__test__/TestHelper.ts +258 -0
- package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +458 -0
- package/src/compute-view/element-view/__test__/fixture.ts +675 -0
- package/src/compute-view/element-view/_types.ts +48 -0
- package/src/compute-view/element-view/clean-connections.ts +113 -0
- package/src/compute-view/element-view/compute.ts +315 -0
- package/src/compute-view/element-view/memory/NodeGroup.ts +31 -0
- package/src/compute-view/element-view/memory/index.ts +10 -0
- package/src/compute-view/element-view/memory/memory.ts +177 -0
- package/src/compute-view/element-view/memory/stage-exclude.ts +59 -0
- package/src/compute-view/element-view/memory/stage-final.ts +129 -0
- package/src/compute-view/element-view/memory/stage-include.ts +128 -0
- package/src/compute-view/element-view/predicates/_utils.ts +86 -0
- package/src/compute-view/element-view/predicates/element-expand.ts +33 -0
- package/src/compute-view/element-view/predicates/element-kind-tag.ts +26 -0
- package/src/compute-view/element-view/predicates/element-ref.ts +37 -0
- package/src/compute-view/element-view/predicates/relation-direct.ts +309 -0
- package/src/compute-view/element-view/predicates/relation-in-out.ts +66 -0
- package/src/compute-view/element-view/predicates/relation-in.ts +118 -0
- package/src/compute-view/element-view/predicates/relation-out.ts +116 -0
- package/src/compute-view/element-view/predicates/wildcard.ts +88 -0
- package/src/compute-view/element-view/utils.ts +59 -0
- package/src/compute-view/index.ts +4 -0
- package/src/compute-view/memory/AbstractMemory.ts +45 -0
- package/src/compute-view/memory/AbstractStageExclude.ts +216 -0
- package/src/compute-view/memory/AbstractStageInclude.ts +200 -0
- package/src/compute-view/memory/_types.ts +147 -0
- package/src/compute-view/memory/index.ts +5 -0
- package/src/compute-view/memory/ops.ts +43 -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/elementExpressionToPredicate.ts +50 -0
- package/src/compute-view/utils/link-nodes-with-edges.ts +54 -0
- package/src/compute-view/utils/merge-props-from-relationships.ts +128 -0
- package/src/compute-view/utils/relationExpressionToPredicates.ts +55 -0
- package/src/compute-view/utils/resolve-extended-views.ts +69 -0
- package/src/compute-view/utils/resolve-global-rules.ts +83 -0
- package/src/compute-view/utils/topological-sort.ts +256 -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 +36 -0
- package/src/index.ts +22 -12
- package/src/model/DeploymentElementModel.ts +599 -0
- package/src/model/DeploymentModel.ts +370 -0
- package/src/model/ElementModel.ts +221 -0
- package/src/model/LikeC4Model.test-d.ts +152 -0
- package/src/model/LikeC4Model.ts +336 -457
- package/src/model/RelationModel.ts +85 -0
- package/src/model/__test__/fixture.ts +149 -338
- package/src/model/connection/Connection.ts +72 -0
- package/src/model/connection/deployment/DeploymentConnectionModel.ts +178 -0
- package/src/model/connection/deployment/find.ts +120 -0
- package/src/model/connection/deployment/index.ts +8 -0
- package/src/model/connection/index.ts +22 -0
- package/src/model/connection/model/ConnectionModel.ts +157 -0
- package/src/model/connection/model/find.ts +117 -0
- package/src/model/connection/model/index.ts +8 -0
- package/src/model/connection/ops.ts +274 -0
- package/src/model/guards.ts +9 -0
- package/src/model/index.ts +46 -2
- package/src/model/types.ts +112 -15
- package/src/model/view/EdgeModel.ts +103 -0
- package/src/model/view/LikeC4ViewModel.ts +226 -0
- package/src/model/view/NodeModel.ts +229 -0
- package/src/types/_common.ts +55 -1
- package/src/types/deployments.ts +169 -0
- package/src/types/element.ts +9 -5
- package/src/types/expression-v2.ts +172 -0
- package/src/types/expression.ts +17 -11
- package/src/types/global.ts +3 -3
- package/src/types/index.ts +220 -12
- package/src/types/model.ts +75 -12
- package/src/types/operators.ts +1 -1
- package/src/types/overview-graph.ts +2 -2
- package/src/types/relation.ts +18 -14
- package/src/types/theme.ts +0 -1
- package/src/types/view-notation.ts +2 -2
- package/src/types/view.ts +117 -41
- package/src/utils/{commonHead.ts → common-head.ts} +2 -0
- package/src/utils/const.ts +1 -0
- package/src/utils/fqn.ts +203 -56
- package/src/utils/getOrCreate.ts +42 -0
- package/src/utils/graphlib.ts +10 -0
- package/src/utils/index.ts +74 -6
- package/src/utils/iterable/_types.ts +5 -0
- package/src/utils/iterable/filter.ts +55 -0
- package/src/utils/iterable/flat.ts +17 -0
- package/src/utils/iterable/index.ts +12 -0
- package/src/utils/iterable/map.ts +40 -0
- package/src/utils/iterable/reduce.ts +24 -0
- package/src/utils/iterable/some.ts +36 -0
- package/src/utils/iterable/to.ts +19 -0
- package/src/utils/iterable/unique.ts +29 -0
- package/src/utils/object-hash.ts +3 -0
- package/src/utils/relations.ts +3 -64
- package/src/utils/set.ts +78 -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.CoLQkcYL.d.ts +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/dist/types/index.mjs +0 -1
- package/src/builder/Builder.test-d.ts +0 -69
- package/src/builder/Builder.view.ts +0 -358
- package/src/model/LikeC4DiagramModel.ts +0 -338
- package/src/model/LikeC4ViewModel.ts +0 -320
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { sort } from 'remeda'
|
|
2
|
+
import { nonNullable } from '../../errors'
|
|
3
|
+
import type { IteratorLike } from '../../types'
|
|
4
|
+
import type { Link, Tag } from '../../types/element'
|
|
5
|
+
import {
|
|
6
|
+
type ComputedDeploymentView,
|
|
7
|
+
type ComputedDynamicView,
|
|
8
|
+
type ComputedElementView,
|
|
9
|
+
type ComputedView,
|
|
10
|
+
type DiagramView,
|
|
11
|
+
type EdgeId as C4EdgeId,
|
|
12
|
+
type LikeC4View,
|
|
13
|
+
type NodeId as C4NodeId,
|
|
14
|
+
isDeploymentView,
|
|
15
|
+
isDynamicView,
|
|
16
|
+
isElementView,
|
|
17
|
+
isScopedElementView,
|
|
18
|
+
} from '../../types/view'
|
|
19
|
+
import { compareByFqnHierarchically, getOrCreate } from '../../utils'
|
|
20
|
+
import type { ElementModel } from '../ElementModel'
|
|
21
|
+
import type { LikeC4Model } from '../LikeC4Model'
|
|
22
|
+
import { type AnyAux, getId } from '../types'
|
|
23
|
+
import { type EdgesIterator, EdgeModel } from './EdgeModel'
|
|
24
|
+
import { type NodesIterator, NodeModel } from './NodeModel'
|
|
25
|
+
|
|
26
|
+
export type ViewsIterator<M extends AnyAux> = IteratorLike<LikeC4ViewModel<M>>
|
|
27
|
+
|
|
28
|
+
export class LikeC4ViewModel<M extends AnyAux, V extends ComputedView | DiagramView = M['ViewType']> {
|
|
29
|
+
readonly #rootnodes = new Set<NodeModel<M, V>>()
|
|
30
|
+
readonly #nodes = new Map<C4NodeId, NodeModel<M, V>>()
|
|
31
|
+
readonly #edges = new Map<C4EdgeId, EdgeModel<M, V>>()
|
|
32
|
+
readonly #includeElements = new Set<M['Element']>()
|
|
33
|
+
readonly #includeDeployments = new Set<M['Deployment']>()
|
|
34
|
+
readonly #includeRelations = new Set<M['RelationId']>()
|
|
35
|
+
readonly #allTags = new Map<Tag, Set<NodeModel<M, V> | EdgeModel<M, V>>>()
|
|
36
|
+
|
|
37
|
+
constructor(
|
|
38
|
+
public readonly $model: LikeC4Model<M>,
|
|
39
|
+
public readonly $view: V,
|
|
40
|
+
) {
|
|
41
|
+
for (const node of sort($view.nodes, compareByFqnHierarchically)) {
|
|
42
|
+
const el = new NodeModel(this, Object.freeze(node))
|
|
43
|
+
this.#nodes.set(node.id, el)
|
|
44
|
+
if (!node.parent) {
|
|
45
|
+
this.#rootnodes.add(el)
|
|
46
|
+
}
|
|
47
|
+
if (el.hasDeployment()) {
|
|
48
|
+
this.#includeDeployments.add(el.deployment.id)
|
|
49
|
+
}
|
|
50
|
+
if (el.hasElement()) {
|
|
51
|
+
this.#includeElements.add(el.element.id)
|
|
52
|
+
}
|
|
53
|
+
for (const tag of el.tags) {
|
|
54
|
+
getOrCreate(this.#allTags, tag, () => new Set()).add(el)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (const edge of $view.edges) {
|
|
59
|
+
const edgeModel = new EdgeModel(
|
|
60
|
+
this,
|
|
61
|
+
Object.freeze(edge),
|
|
62
|
+
this.node(edge.source),
|
|
63
|
+
this.node(edge.target),
|
|
64
|
+
)
|
|
65
|
+
for (const tag of edgeModel.tags) {
|
|
66
|
+
getOrCreate(this.#allTags, tag, () => new Set()).add(edgeModel)
|
|
67
|
+
}
|
|
68
|
+
for (const rel of edge.relations) {
|
|
69
|
+
this.#includeRelations.add(rel)
|
|
70
|
+
}
|
|
71
|
+
this.#edges.set(edge.id, edgeModel)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
get __(): NonNullable<M['ViewType']['__']> {
|
|
76
|
+
return this.$view.__ ?? 'element'
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
get id(): M['ViewId'] {
|
|
80
|
+
return this.$view.id
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
get title(): string | null {
|
|
84
|
+
return this.$view.title
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get tags(): ReadonlyArray<Tag> {
|
|
88
|
+
return this.$view.tags ?? []
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get links(): ReadonlyArray<Link> {
|
|
92
|
+
return this.$view.links ?? []
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get viewOf(): ElementModel<M> | null {
|
|
96
|
+
const v = this.$view as LikeC4View
|
|
97
|
+
if (isScopedElementView(v)) {
|
|
98
|
+
return this.$model.element(v.viewOf)
|
|
99
|
+
}
|
|
100
|
+
return null
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* All tags from nodes and edges.
|
|
105
|
+
*/
|
|
106
|
+
get includedTags(): ReadonlyArray<Tag> {
|
|
107
|
+
return [...this.#allTags.keys()]
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
public roots(): NodesIterator<M, V> {
|
|
111
|
+
return this.#rootnodes.values()
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Iterate over all nodes that have children.
|
|
116
|
+
*/
|
|
117
|
+
public *compounds(): NodesIterator<M, V> {
|
|
118
|
+
for (const node of this.#nodes.values()) {
|
|
119
|
+
if (node.hasChildren()) {
|
|
120
|
+
yield node
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Get node by id.
|
|
128
|
+
* @throws Error if node is not found.
|
|
129
|
+
*/
|
|
130
|
+
public node(node: M['NodeOrId']): NodeModel<M, V> {
|
|
131
|
+
const nodeId = getId(node)
|
|
132
|
+
return nonNullable(this.#nodes.get(nodeId), `Node ${nodeId} not found in view ${this.$view.id}`)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Find node by id.
|
|
137
|
+
*/
|
|
138
|
+
public findNode(node: M['NodeOrId']): NodeModel<M, V> | null {
|
|
139
|
+
return this.#nodes.get(getId(node) as C4NodeId) ?? null
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Iterate over all nodes.
|
|
143
|
+
*/
|
|
144
|
+
public nodes(): NodesIterator<M, V> {
|
|
145
|
+
return this.#nodes.values()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Find edge by id.
|
|
150
|
+
* @param edge Edge or id
|
|
151
|
+
* @returns EdgeModel
|
|
152
|
+
*/
|
|
153
|
+
public edge(edge: M['EdgeOrId']): EdgeModel<M, V> {
|
|
154
|
+
const edgeId = getId(edge) as C4EdgeId
|
|
155
|
+
return nonNullable(this.#edges.get(edgeId), `Edge ${edgeId} not found in view ${this.$view.id}`)
|
|
156
|
+
}
|
|
157
|
+
public findEdge(edge: M['EdgeOrId']): EdgeModel<M, V> | null {
|
|
158
|
+
return this.#edges.get(getId(edge) as C4EdgeId) ?? null
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Iterate over all edges.
|
|
162
|
+
*/
|
|
163
|
+
public edges(): EdgesIterator<M, V> {
|
|
164
|
+
return this.#edges.values()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Iterate over all edges.
|
|
169
|
+
*/
|
|
170
|
+
public *edgesWithRelation(relation: M['RelationId']): EdgesIterator<M, V> {
|
|
171
|
+
for (const edge of this.#edges.values()) {
|
|
172
|
+
if (edge.includesRelation(relation)) {
|
|
173
|
+
yield edge
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Nodes that have references to elements from logical model.
|
|
181
|
+
*/
|
|
182
|
+
public *elements(): IteratorLike<NodeModel.WithElement<M, V>> {
|
|
183
|
+
// return this.#nodes.values().filter(node => node.hasElement())
|
|
184
|
+
for (const node of this.#nodes.values()) {
|
|
185
|
+
if (node.hasElement()) {
|
|
186
|
+
yield node
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
public includesElement(elementId: M['Element']): boolean {
|
|
193
|
+
return this.#includeElements.has(elementId)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public includesDeployment(deploymentId: M['Deployment']): boolean {
|
|
197
|
+
return this.#includeDeployments.has(deploymentId)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public includesRelation(relationId: M['RelationId']): boolean {
|
|
201
|
+
return this.#includeRelations.has(relationId)
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Below are type guards.
|
|
206
|
+
*/
|
|
207
|
+
public isComputed(): this is LikeC4ViewModel<M, ComputedView> {
|
|
208
|
+
return true // Diagram view is a computed view
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
public isDiagram(): this is LikeC4ViewModel<M, DiagramView> {
|
|
212
|
+
return 'bounds' in this.$view
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
public isElementView(): this is LikeC4ViewModel<M, ComputedElementView> {
|
|
216
|
+
return isElementView(this.$view as LikeC4View)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
public isDeploymentView(): this is LikeC4ViewModel<M, ComputedDeploymentView> {
|
|
220
|
+
return isDeploymentView(this.$view as LikeC4View)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
public isDynamicView(): this is LikeC4ViewModel<M, ComputedDynamicView> {
|
|
224
|
+
return isDynamicView(this.$view as LikeC4View)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Color as C4Color,
|
|
3
|
+
type ComputedView,
|
|
4
|
+
type DeploymentNodeKind,
|
|
5
|
+
type DiagramView,
|
|
6
|
+
type ElementShape as C4ElementShape,
|
|
7
|
+
type IteratorLike,
|
|
8
|
+
type Link,
|
|
9
|
+
type NodeId,
|
|
10
|
+
type Tag as C4Tag,
|
|
11
|
+
ComputedNode,
|
|
12
|
+
ElementKind,
|
|
13
|
+
} from '../../types'
|
|
14
|
+
import type { DeployedInstanceModel, DeploymentElementModel } from '../DeploymentElementModel'
|
|
15
|
+
import type { ElementModel } from '../ElementModel'
|
|
16
|
+
import type { AnyAux, IncomingFilter, OutgoingFilter } from '../types'
|
|
17
|
+
import type { EdgesIterator } from './EdgeModel'
|
|
18
|
+
import type { LikeC4ViewModel } from './LikeC4ViewModel'
|
|
19
|
+
|
|
20
|
+
export type NodesIterator<M extends AnyAux, V extends ComputedView | DiagramView> = IteratorLike<NodeModel<M, V>>
|
|
21
|
+
|
|
22
|
+
export namespace NodeModel {
|
|
23
|
+
export interface WithParent<M extends AnyAux, V extends ComputedView | DiagramView> extends NodeModel<M, V> {
|
|
24
|
+
parent: NodeModel<M, V>
|
|
25
|
+
}
|
|
26
|
+
export interface WithElement<M extends AnyAux, V extends ComputedView | DiagramView> extends NodeModel<M, V> {
|
|
27
|
+
kind: ElementKind
|
|
28
|
+
element: ElementModel<M>
|
|
29
|
+
}
|
|
30
|
+
export interface WithDeploymentElement<M extends AnyAux, V extends ComputedView | DiagramView>
|
|
31
|
+
extends NodeModel<M, V>
|
|
32
|
+
{
|
|
33
|
+
kind: DeploymentNodeKind
|
|
34
|
+
deployment: DeploymentElementModel<M>
|
|
35
|
+
}
|
|
36
|
+
export interface WithDeployedInstance<M extends AnyAux, V extends ComputedView | DiagramView>
|
|
37
|
+
extends NodeModel<M, V>
|
|
38
|
+
{
|
|
39
|
+
kind: 'instance'
|
|
40
|
+
element: ElementModel<M>
|
|
41
|
+
deployment: DeployedInstanceModel<M>
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface IsGroup<M extends AnyAux, V extends ComputedView | DiagramView> extends NodeModel<M, V> {
|
|
45
|
+
kind: typeof ElementKind.Group
|
|
46
|
+
element: null
|
|
47
|
+
deployment: null
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class NodeModel<M extends AnyAux, V extends ComputedView | DiagramView = M['ViewType']> {
|
|
52
|
+
constructor(
|
|
53
|
+
public readonly $view: LikeC4ViewModel<M, V>,
|
|
54
|
+
public readonly $node: V['nodes'][number],
|
|
55
|
+
) {
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get id(): NodeId {
|
|
59
|
+
return this.$node.id
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get title(): string {
|
|
63
|
+
return this.$node.title
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get kind(): ElementKind | DeploymentNodeKind | typeof ElementKind.Group | 'instance' {
|
|
67
|
+
return this.$node.kind as any
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get description(): string | null {
|
|
71
|
+
return this.$node.description
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
get technology(): string | null {
|
|
75
|
+
return this.$node.technology
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
get parent(): NodeModel<M, V> | null {
|
|
79
|
+
return this.$node.parent ? this.$view.node(this.$node.parent) : null
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get element(): ElementModel<M> | null {
|
|
83
|
+
const modelRef = ComputedNode.modelRef(this.$node)
|
|
84
|
+
return modelRef ? this.$view.$model.element(modelRef) : null
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
get deployment(): DeploymentElementModel<M> | null {
|
|
88
|
+
const modelRef = ComputedNode.deploymentRef(this.$node)
|
|
89
|
+
return modelRef ? this.$view.$model.deployment.element(modelRef) : null
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
get shape(): C4ElementShape {
|
|
93
|
+
return this.$node.shape
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get color(): C4Color {
|
|
97
|
+
return this.$node.color
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
get tags(): ReadonlyArray<C4Tag> {
|
|
101
|
+
return this.$node.tags ?? []
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
get links(): ReadonlyArray<Link> {
|
|
105
|
+
return this.$node.links ?? []
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get navigateTo(): LikeC4ViewModel<M> | null {
|
|
109
|
+
return this.$node.navigateTo ? this.$view.$model.view(this.$node.navigateTo) : null
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
114
|
+
* (from closest to root)
|
|
115
|
+
*/
|
|
116
|
+
public *ancestors(): NodesIterator<M, V> {
|
|
117
|
+
let parent = this.parent
|
|
118
|
+
while (parent) {
|
|
119
|
+
yield parent
|
|
120
|
+
parent = parent.parent
|
|
121
|
+
}
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
public *children(): NodesIterator<M, V> {
|
|
126
|
+
for (const child of this.$node.children) {
|
|
127
|
+
yield this.$view.node(child)
|
|
128
|
+
}
|
|
129
|
+
return
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
public *sublings(): NodesIterator<M, V> {
|
|
133
|
+
const sublings = this.parent?.children() ?? this.$view.roots()
|
|
134
|
+
for (const subling of sublings) {
|
|
135
|
+
if (subling.id !== this.id) {
|
|
136
|
+
yield subling
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public *incoming(filter: IncomingFilter = 'all'): EdgesIterator<M, V> {
|
|
143
|
+
for (const edgeId of this.$node.inEdges) {
|
|
144
|
+
const edge = this.$view.edge(edgeId)
|
|
145
|
+
switch (true) {
|
|
146
|
+
case filter === 'all':
|
|
147
|
+
case filter === 'direct' && edge.target.id === this.id:
|
|
148
|
+
case filter === 'to-descendants' && edge.target.id !== this.id:
|
|
149
|
+
yield edge
|
|
150
|
+
break
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public *incomers(filter: IncomingFilter = 'all'): NodesIterator<M, V> {
|
|
157
|
+
const unique = new Set<NodeId>()
|
|
158
|
+
for (const r of this.incoming(filter)) {
|
|
159
|
+
if (unique.has(r.source.id)) {
|
|
160
|
+
continue
|
|
161
|
+
}
|
|
162
|
+
unique.add(r.source.id)
|
|
163
|
+
yield r.source
|
|
164
|
+
}
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public *outgoing(filter: OutgoingFilter = 'all'): EdgesIterator<M, V> {
|
|
169
|
+
for (const edgeId of this.$node.outEdges) {
|
|
170
|
+
const edge = this.$view.edge(edgeId)
|
|
171
|
+
switch (true) {
|
|
172
|
+
case filter === 'all':
|
|
173
|
+
case filter === 'direct' && edge.source.id === this.id:
|
|
174
|
+
case filter === 'from-descendants' && edge.source.id !== this.id:
|
|
175
|
+
yield edge
|
|
176
|
+
break
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public *outgoers(filter: OutgoingFilter = 'all'): NodesIterator<M, V> {
|
|
183
|
+
const unique = new Set<NodeId>()
|
|
184
|
+
for (const r of this.outgoing(filter)) {
|
|
185
|
+
if (unique.has(r.target.id)) {
|
|
186
|
+
continue
|
|
187
|
+
}
|
|
188
|
+
unique.add(r.target.id)
|
|
189
|
+
yield r.target
|
|
190
|
+
}
|
|
191
|
+
return
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public isDiagramNode(): this is NodeModel<M, DiagramView> {
|
|
195
|
+
return 'width' in this.$node && 'height' in this.$node
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public hasChildren(): boolean {
|
|
199
|
+
return this.$node.children.length > 0
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
public hasParent(): this is NodeModel.WithParent<M, V> {
|
|
203
|
+
return this.$node.parent !== null
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Check if this node references to logical model element.
|
|
208
|
+
*/
|
|
209
|
+
public hasElement(): this is NodeModel.WithElement<M, V> {
|
|
210
|
+
return ComputedNode.modelRef(this.$node) !== null
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Check if this node references to deployment element (Node or Instance).
|
|
214
|
+
*/
|
|
215
|
+
public hasDeployment(): this is NodeModel.WithDeploymentElement<M, V> {
|
|
216
|
+
return ComputedNode.deploymentRef(this.$node) !== null
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Check if this node references to deployed instance
|
|
220
|
+
* Deployed instance always references to element and deployment element.
|
|
221
|
+
*/
|
|
222
|
+
public hasDeployedInstance(): this is NodeModel.WithDeployedInstance<M, V> {
|
|
223
|
+
return this.hasElement() && this.hasDeployment()
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
public isGroup(): this is NodeModel.IsGroup<M, V> {
|
|
227
|
+
return ComputedNode.isNodesGroup(this.$node)
|
|
228
|
+
}
|
|
229
|
+
}
|
package/src/types/_common.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Tagged } from 'type-fest'
|
|
1
|
+
import type { Simplify, Tagged, UnionToIntersection } from 'type-fest'
|
|
2
2
|
|
|
3
3
|
export type NonEmptyArray<T> = [T, ...T[]]
|
|
4
4
|
|
|
@@ -14,3 +14,57 @@ export interface XYPoint {
|
|
|
14
14
|
x: number
|
|
15
15
|
y: number
|
|
16
16
|
}
|
|
17
|
+
|
|
18
|
+
export type KeysOf<T> = keyof T extends infer K extends string ? K : never
|
|
19
|
+
|
|
20
|
+
type AllNever<Expressions> = UnionToIntersection<
|
|
21
|
+
{
|
|
22
|
+
[Name in keyof Expressions]: {
|
|
23
|
+
-readonly [Key in keyof Expressions[Name]]?: never
|
|
24
|
+
}
|
|
25
|
+
}[keyof Expressions]
|
|
26
|
+
>
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @example
|
|
30
|
+
* type Variant1 = {
|
|
31
|
+
* a: string
|
|
32
|
+
* }
|
|
33
|
+
* type Variant2 = {
|
|
34
|
+
* b: number
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* type Variants = ExclusiveUnion<{
|
|
38
|
+
* Variant1: Variant1,
|
|
39
|
+
* Variant2: Variant2
|
|
40
|
+
* }>
|
|
41
|
+
*
|
|
42
|
+
* Fail here
|
|
43
|
+
* const variant1: Variants = {
|
|
44
|
+
* a: 'one',
|
|
45
|
+
* b: 1
|
|
46
|
+
* }
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
export type ExclusiveUnion<Expressions> = Expressions extends object ? {
|
|
50
|
+
[Name in keyof Expressions]: Simplify<Omit<AllNever<Expressions>, keyof Expressions[Name]> & Expressions[Name]>
|
|
51
|
+
}[keyof Expressions]
|
|
52
|
+
: Expressions
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Copy from https://github.com/remeda/remeda/blob/main/src/internal/types/NTuple.ts
|
|
56
|
+
* An array with *exactly* N elements in it.
|
|
57
|
+
*
|
|
58
|
+
* Only literal N values are supported. For very large N the type might result
|
|
59
|
+
* in a recurse depth error. For negative N the type would result in an infinite
|
|
60
|
+
* recursion. None of these have protections because this is an internal type!
|
|
61
|
+
*/
|
|
62
|
+
export type NTuple<
|
|
63
|
+
T,
|
|
64
|
+
N extends number,
|
|
65
|
+
Result extends Array<unknown> = [],
|
|
66
|
+
> = Result['length'] extends N ? Result : NTuple<T, N, [...Result, T]>
|
|
67
|
+
|
|
68
|
+
export type IteratorLike<T> = IteratorObject<T, BuiltinIteratorReturn>
|
|
69
|
+
|
|
70
|
+
export type Predicate<T> = (x: T) => boolean
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import type { MergeExclusive, Simplify, Tagged } from 'type-fest'
|
|
2
|
+
import type { IconUrl, NonEmptyArray } from './_common'
|
|
3
|
+
import type { ElementShape, ElementStyle, Fqn, Link, Tag } from './element'
|
|
4
|
+
import type { AbstractRelation, RelationId } from './relation'
|
|
5
|
+
import type { Color } from './theme'
|
|
6
|
+
|
|
7
|
+
export type DeploymentNodeKind<Kinds extends string = string> = Tagged<Kinds, 'DeploymentNodeKind'>
|
|
8
|
+
|
|
9
|
+
export type DeploymentElementStyle = ElementStyle & {
|
|
10
|
+
readonly icon?: IconUrl
|
|
11
|
+
readonly shape?: ElementShape
|
|
12
|
+
readonly color?: Color
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface DeploymentNodeKindSpecification {
|
|
16
|
+
readonly technology?: string
|
|
17
|
+
readonly notation?: string
|
|
18
|
+
readonly style: DeploymentElementStyle
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface DeploymentNode {
|
|
22
|
+
// Full-qualified-name for Deployment model
|
|
23
|
+
readonly id: Fqn
|
|
24
|
+
readonly kind: DeploymentNodeKind
|
|
25
|
+
readonly title: string
|
|
26
|
+
readonly description?: string | null
|
|
27
|
+
readonly technology?: string | null
|
|
28
|
+
readonly tags?: NonEmptyArray<Tag> | null
|
|
29
|
+
readonly links?: NonEmptyArray<Link> | null
|
|
30
|
+
readonly style?: DeploymentElementStyle
|
|
31
|
+
readonly notation?: string
|
|
32
|
+
readonly metadata?: Record<string, string>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface DeployedInstance {
|
|
36
|
+
/**
|
|
37
|
+
* Format: `<DeploymentNode Fqn>.<Instance Id>`
|
|
38
|
+
* i.e parent fqn is deployment target
|
|
39
|
+
*/
|
|
40
|
+
readonly id: Fqn
|
|
41
|
+
readonly element: Fqn
|
|
42
|
+
readonly title?: string
|
|
43
|
+
readonly description?: string | null
|
|
44
|
+
readonly technology?: string | null
|
|
45
|
+
readonly tags?: NonEmptyArray<Tag> | null
|
|
46
|
+
readonly links?: NonEmptyArray<Link> | null
|
|
47
|
+
readonly style?: DeploymentElementStyle
|
|
48
|
+
readonly notation?: string
|
|
49
|
+
readonly metadata?: Record<string, string>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type DeploymentElement = Simplify<MergeExclusive<DeploymentNode, DeployedInstance>>
|
|
53
|
+
|
|
54
|
+
export namespace DeploymentElement {
|
|
55
|
+
export const isDeploymentNode = (el: DeploymentElement): el is DeploymentNode => {
|
|
56
|
+
return 'kind' in el && !('element' in el)
|
|
57
|
+
}
|
|
58
|
+
export const isInstance = (el: DeploymentElement): el is DeployedInstance => {
|
|
59
|
+
return 'element' in el && !('kind' in el)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type PredicateSelector =
|
|
64
|
+
| 'children' // ele.*
|
|
65
|
+
| 'expanded' // ele._
|
|
66
|
+
| 'descendants' // ele.**
|
|
67
|
+
|
|
68
|
+
export interface DeploymentRef {
|
|
69
|
+
// Reference to DeploymentNode or DeployedInstance
|
|
70
|
+
readonly id: Fqn
|
|
71
|
+
// Reference to element within DeployedInstance
|
|
72
|
+
readonly element?: Fqn
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* NOTE:
|
|
77
|
+
*/
|
|
78
|
+
export interface DeploymentRelation extends AbstractRelation {
|
|
79
|
+
readonly id: RelationId
|
|
80
|
+
readonly source: DeploymentRef
|
|
81
|
+
readonly target: DeploymentRef
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// export namespace DeploymentRelationExpression {
|
|
85
|
+
// // type LogicalRefEndpoint = {
|
|
86
|
+
// // logicalRef: ElementRefExpr
|
|
87
|
+
// // }
|
|
88
|
+
// // export type DirectEndpoint = ExclusiveUnion<{
|
|
89
|
+
// // DeploymentElementExpression: DeploymentElementExpression
|
|
90
|
+
// // Logical: LogicalRefEndpoint
|
|
91
|
+
// // }>
|
|
92
|
+
|
|
93
|
+
// // export const isLogicalEndpoint = (expr: DirectEndpoint): expr is LogicalRefEndpoint => {
|
|
94
|
+
// // return 'logicalRef' in expr
|
|
95
|
+
// // }
|
|
96
|
+
|
|
97
|
+
// export type Direct = {
|
|
98
|
+
// source: FqnExpression.Element
|
|
99
|
+
// target: FqnExpression.Element
|
|
100
|
+
// isBidirectional?: boolean
|
|
101
|
+
// }
|
|
102
|
+
// export const isDirect = (expr: DeploymentExpression): expr is Direct => {
|
|
103
|
+
// return 'source' in expr && 'target' in expr
|
|
104
|
+
// }
|
|
105
|
+
// export type Incoming = {
|
|
106
|
+
// incoming: FqnExpression.Element
|
|
107
|
+
// }
|
|
108
|
+
// export const isIncoming = (expr: DeploymentExpression): expr is Incoming => {
|
|
109
|
+
// return 'incoming' in expr
|
|
110
|
+
// }
|
|
111
|
+
// export type Outgoing = {
|
|
112
|
+
// outgoing: FqnExpression.Element
|
|
113
|
+
// }
|
|
114
|
+
// export const isOutgoing = (expr: DeploymentExpression): expr is Outgoing => {
|
|
115
|
+
// return 'outgoing' in expr
|
|
116
|
+
// }
|
|
117
|
+
// export type InOut = {
|
|
118
|
+
// inout: FqnExpression.Element
|
|
119
|
+
// }
|
|
120
|
+
// export const isInOut = (expr: DeploymentExpression): expr is InOut => {
|
|
121
|
+
// return 'inout' in expr
|
|
122
|
+
// }
|
|
123
|
+
// }
|
|
124
|
+
|
|
125
|
+
// export type DeploymentRelationExpression = ExclusiveUnion<{
|
|
126
|
+
// Direct: DeploymentRelationExpression.Direct
|
|
127
|
+
// Incoming: DeploymentRelationExpression.Incoming
|
|
128
|
+
// Outgoing: DeploymentRelationExpression.Outgoing
|
|
129
|
+
// InOut: DeploymentRelationExpression.InOut
|
|
130
|
+
// }>
|
|
131
|
+
|
|
132
|
+
// export namespace DeploymentElementExpression {
|
|
133
|
+
// export type Ref = {
|
|
134
|
+
// ref: DeploymentRef
|
|
135
|
+
// selector?: PredicateSelector
|
|
136
|
+
// }
|
|
137
|
+
// export const isRef = (expr: DeploymentExpression): expr is Ref => {
|
|
138
|
+
// return 'ref' in expr
|
|
139
|
+
// }
|
|
140
|
+
|
|
141
|
+
// export type Wildcard = {
|
|
142
|
+
// wildcard: true
|
|
143
|
+
// }
|
|
144
|
+
// export const isWildcard = (expr: DeploymentExpression): expr is Wildcard => {
|
|
145
|
+
// return 'wildcard' in expr && expr.wildcard === true
|
|
146
|
+
// }
|
|
147
|
+
// }
|
|
148
|
+
|
|
149
|
+
// export type DeploymentElementExpression = ExclusiveUnion<{
|
|
150
|
+
// DeploymentRef: DeploymentElementExpression.Ref
|
|
151
|
+
// Wildcard: DeploymentElementExpression.Wildcard
|
|
152
|
+
// }>
|
|
153
|
+
|
|
154
|
+
// export type DeploymentExpression = ExclusiveUnion<{
|
|
155
|
+
// Element: DeploymentElementExpression
|
|
156
|
+
// Relation: DeploymentRelationExpression
|
|
157
|
+
// }>
|
|
158
|
+
|
|
159
|
+
// export namespace DeploymentExpression {
|
|
160
|
+
// export type Element = DeploymentElementExpression
|
|
161
|
+
// export type Relation = DeploymentRelationExpression
|
|
162
|
+
|
|
163
|
+
// export const isElement = (expr: DeploymentExpression): expr is DeploymentElementExpression => {
|
|
164
|
+
// return DeploymentElementExpression.isRef(expr) || DeploymentElementExpression.isWildcard(expr)
|
|
165
|
+
// }
|
|
166
|
+
// export const isRelation = (expr: DeploymentExpression): expr is DeploymentRelationExpression => {
|
|
167
|
+
// return !DeploymentExpression.isElement(expr)
|
|
168
|
+
// }
|
|
169
|
+
// }
|
package/src/types/element.ts
CHANGED
|
@@ -28,13 +28,17 @@ export const ElementShapes = [
|
|
|
28
28
|
] as const
|
|
29
29
|
|
|
30
30
|
export type ElementShape = TupleToUnion<typeof ElementShapes>
|
|
31
|
-
export const DefaultThemeColor = 'primary'
|
|
32
|
-
export const DefaultElementShape = 'rectangle'
|
|
31
|
+
export const DefaultThemeColor: ThemeColor = 'primary'
|
|
32
|
+
export const DefaultElementShape: ElementShape = 'rectangle'
|
|
33
33
|
|
|
34
34
|
export interface ElementStyle {
|
|
35
|
-
border?: BorderStyle
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
readonly border?: BorderStyle
|
|
36
|
+
/**
|
|
37
|
+
* In percentage 0-100, 0 is fully transparent
|
|
38
|
+
*
|
|
39
|
+
* @default 100
|
|
40
|
+
*/
|
|
41
|
+
readonly opacity?: number
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
export type Tag<Tags extends string = string> = Tagged<Tags, 'Tag'>
|