@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,220 @@
|
|
|
1
|
+
import { sort } from 'remeda'
|
|
2
|
+
import { nonNullable } from '../../errors'
|
|
3
|
+
import type { Link, Tag } from '../../types/element'
|
|
4
|
+
import {
|
|
5
|
+
type ComputedDeploymentView,
|
|
6
|
+
type ComputedDynamicView,
|
|
7
|
+
type ComputedElementView,
|
|
8
|
+
type ComputedView,
|
|
9
|
+
type DiagramView,
|
|
10
|
+
type EdgeId as C4EdgeId,
|
|
11
|
+
isDeploymentView,
|
|
12
|
+
isDynamicView,
|
|
13
|
+
isElementView,
|
|
14
|
+
isScopedElementView,
|
|
15
|
+
type LikeC4View,
|
|
16
|
+
type NodeId as C4NodeId
|
|
17
|
+
} from '../../types/view'
|
|
18
|
+
import { compareByFqnHierarchically, getOrCreate } from '../../utils'
|
|
19
|
+
import type { ElementModel } from '../ElementModel'
|
|
20
|
+
import type { LikeC4Model } from '../LikeC4Model'
|
|
21
|
+
import { type AnyAux, getId, type IteratorLike } from '../types'
|
|
22
|
+
import { EdgeModel, type EdgesIterator } from './EdgeModel'
|
|
23
|
+
import { NodeModel, type NodesIterator } from './NodeModel'
|
|
24
|
+
|
|
25
|
+
export type ViewsIterator<M extends AnyAux> = IteratorLike<LikeC4ViewModel<M>>
|
|
26
|
+
|
|
27
|
+
export class LikeC4ViewModel<M extends AnyAux, V extends ComputedView | DiagramView = M['ViewType']> {
|
|
28
|
+
readonly #rootnodes = new Set<NodeModel<M, V>>()
|
|
29
|
+
readonly #nodes = new Map<C4NodeId, NodeModel<M, V>>()
|
|
30
|
+
readonly #edges = new Map<C4EdgeId, EdgeModel<M, V>>()
|
|
31
|
+
readonly #includeElements = new Set<M['Element']>()
|
|
32
|
+
readonly #includeDeployments = new Set<M['Deployment']>()
|
|
33
|
+
readonly #includeRelations = new Set<M['RelationId']>()
|
|
34
|
+
readonly #allTags = new Map<Tag, Set<NodeModel<M, V> | EdgeModel<M, V>>>()
|
|
35
|
+
|
|
36
|
+
constructor(
|
|
37
|
+
public readonly $model: LikeC4Model<M>,
|
|
38
|
+
public readonly $view: V
|
|
39
|
+
) {
|
|
40
|
+
for (const node of sort($view.nodes, compareByFqnHierarchically)) {
|
|
41
|
+
const el = new NodeModel(this, node)
|
|
42
|
+
this.#nodes.set(node.id, el)
|
|
43
|
+
if (!node.parent) {
|
|
44
|
+
this.#rootnodes.add(el)
|
|
45
|
+
}
|
|
46
|
+
if (el.hasDeployment()) {
|
|
47
|
+
this.#includeDeployments.add(el.deployment.id)
|
|
48
|
+
}
|
|
49
|
+
if (el.hasElement()) {
|
|
50
|
+
this.#includeElements.add(el.element.id)
|
|
51
|
+
}
|
|
52
|
+
for (const tag of el.tags) {
|
|
53
|
+
getOrCreate(this.#allTags, tag, () => new Set()).add(el)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
for (const edge of $view.edges) {
|
|
58
|
+
const edgeModel = new EdgeModel(this, edge, this.node(edge.source), this.node(edge.target))
|
|
59
|
+
for (const tag of edgeModel.tags) {
|
|
60
|
+
getOrCreate(this.#allTags, tag, () => new Set()).add(edgeModel)
|
|
61
|
+
}
|
|
62
|
+
for (const rel of edge.relations) {
|
|
63
|
+
this.#includeRelations.add(rel)
|
|
64
|
+
}
|
|
65
|
+
this.#edges.set(edge.id, edgeModel)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get __(): NonNullable<M['ViewType']['__']> {
|
|
70
|
+
return this.$view.__ ?? 'element'
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
get id(): M['ViewId'] {
|
|
74
|
+
return this.$view.id
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get title(): string | null {
|
|
78
|
+
return this.$view.title
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get tags(): ReadonlyArray<Tag> {
|
|
82
|
+
return this.$view.tags ?? []
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get links(): ReadonlyArray<Link> {
|
|
86
|
+
return this.$view.links ?? []
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get viewOf(): ElementModel<M> | null {
|
|
90
|
+
const v = this.$view as LikeC4View
|
|
91
|
+
if (isScopedElementView(v)) {
|
|
92
|
+
return this.$model.element(v.viewOf)
|
|
93
|
+
}
|
|
94
|
+
return null
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* All tags from nodes and edges.
|
|
99
|
+
*/
|
|
100
|
+
get includedTags(): ReadonlyArray<Tag> {
|
|
101
|
+
return [...this.#allTags.keys()]
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public roots(): NodesIterator<M, V> {
|
|
105
|
+
return this.#rootnodes.values()
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Iterate over all nodes that have children.
|
|
110
|
+
*/
|
|
111
|
+
public *compounds(): NodesIterator<M, V> {
|
|
112
|
+
for (const node of this.#nodes.values()) {
|
|
113
|
+
if (node.hasChildren()) {
|
|
114
|
+
yield node
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get node by id.
|
|
122
|
+
* @throws Error if node is not found.
|
|
123
|
+
*/
|
|
124
|
+
public node(node: M['NodeOrId']): NodeModel<M, V> {
|
|
125
|
+
const nodeId = getId(node)
|
|
126
|
+
return nonNullable(this.#nodes.get(nodeId), `Node ${nodeId} not found in view ${this.$view.id}`)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Find node by id.
|
|
131
|
+
*/
|
|
132
|
+
public findNode(node: M['NodeOrId']): NodeModel<M, V> | null {
|
|
133
|
+
return this.#nodes.get(getId(node) as C4NodeId) ?? null
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Iterate over all nodes.
|
|
137
|
+
*/
|
|
138
|
+
public nodes(): NodesIterator<M, V> {
|
|
139
|
+
return this.#nodes.values()
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Find edge by id.
|
|
144
|
+
* @param edge Edge or id
|
|
145
|
+
* @returns EdgeModel
|
|
146
|
+
*/
|
|
147
|
+
public edge(edge: M['EdgeOrId']): EdgeModel<M, V> {
|
|
148
|
+
const edgeId = getId(edge) as C4EdgeId
|
|
149
|
+
return nonNullable(this.#edges.get(edgeId), `Edge ${edgeId} not found in view ${this.$view.id}`)
|
|
150
|
+
}
|
|
151
|
+
public findEdge(edge: M['EdgeOrId']): EdgeModel<M, V> | null {
|
|
152
|
+
return this.#edges.get(getId(edge) as C4EdgeId) ?? null
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Iterate over all edges.
|
|
156
|
+
*/
|
|
157
|
+
public edges(): EdgesIterator<M, V> {
|
|
158
|
+
return this.#edges.values()
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Iterate over all edges.
|
|
163
|
+
*/
|
|
164
|
+
public *edgesWithRelation(relation: M['RelationId']): EdgesIterator<M, V> {
|
|
165
|
+
for (const edge of this.#edges.values()) {
|
|
166
|
+
if (edge.includesRelation(relation)) {
|
|
167
|
+
yield edge
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Nodes that have references to elements from logical model.
|
|
175
|
+
*/
|
|
176
|
+
public *elements(): IteratorLike<NodeModel.WithElement<M, V>> {
|
|
177
|
+
// return this.#nodes.values().filter(node => node.hasElement())
|
|
178
|
+
for (const node of this.#nodes.values()) {
|
|
179
|
+
if (node.hasElement()) {
|
|
180
|
+
yield node
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
public includesElement(elementId: M['Element']): boolean {
|
|
187
|
+
return this.#includeElements.has(elementId)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
public includesDeployment(deploymentId: M['Deployment']): boolean {
|
|
191
|
+
return this.#includeDeployments.has(deploymentId)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public includesRelation(relationId: M['RelationId']): boolean {
|
|
195
|
+
return this.#includeRelations.has(relationId)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Below are type guards.
|
|
200
|
+
*/
|
|
201
|
+
public isComputed(): this is LikeC4ViewModel<M, ComputedView> {
|
|
202
|
+
return true // Diagram view is a computed view
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
public isDiagram(): this is LikeC4ViewModel<M, DiagramView> {
|
|
206
|
+
return 'bounds' in this.$view
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
public isElementView(): this is LikeC4ViewModel<M, ComputedElementView> {
|
|
210
|
+
return isElementView(this.$view as LikeC4View)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
public isDeploymentView(): this is LikeC4ViewModel<M, ComputedDeploymentView> {
|
|
214
|
+
return isDeploymentView(this.$view as LikeC4View)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
public isDynamicView(): this is LikeC4ViewModel<M, ComputedDynamicView> {
|
|
218
|
+
return isDynamicView(this.$view as LikeC4View)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type Color as C4Color,
|
|
3
|
+
ComputedNode,
|
|
4
|
+
type ComputedView,
|
|
5
|
+
type DeploymentNodeKind,
|
|
6
|
+
type DiagramView,
|
|
7
|
+
ElementKind,
|
|
8
|
+
type ElementShape as C4ElementShape,
|
|
9
|
+
type Link,
|
|
10
|
+
type NodeId,
|
|
11
|
+
type Tag as C4Tag
|
|
12
|
+
} from '../../types'
|
|
13
|
+
import type { DeployedInstanceModel, DeploymentElementModel } from '../DeploymentElementModel'
|
|
14
|
+
import type { ElementModel } from '../ElementModel'
|
|
15
|
+
import type { AnyAux, IncomingFilter, IteratorLike, OutgoingFilter } from '../types'
|
|
16
|
+
import type { EdgesIterator } from './EdgeModel'
|
|
17
|
+
import type { LikeC4ViewModel } from './LikeC4ViewModel'
|
|
18
|
+
|
|
19
|
+
export type NodesIterator<M extends AnyAux, V extends ComputedView | DiagramView> = IteratorLike<NodeModel<M, V>>
|
|
20
|
+
|
|
21
|
+
export namespace NodeModel {
|
|
22
|
+
export interface WithParent<M extends AnyAux, V extends ComputedView | DiagramView> extends NodeModel<M, V> {
|
|
23
|
+
parent: NodeModel<M, V>
|
|
24
|
+
}
|
|
25
|
+
export interface WithElement<M extends AnyAux, V extends ComputedView | DiagramView> extends NodeModel<M, V> {
|
|
26
|
+
kind: ElementKind
|
|
27
|
+
element: ElementModel<M>
|
|
28
|
+
}
|
|
29
|
+
export interface WithDeploymentElement<M extends AnyAux, V extends ComputedView | DiagramView>
|
|
30
|
+
extends NodeModel<M, V>
|
|
31
|
+
{
|
|
32
|
+
kind: DeploymentNodeKind
|
|
33
|
+
deployment: DeploymentElementModel<M>
|
|
34
|
+
}
|
|
35
|
+
export interface WithDeployedInstance<M extends AnyAux, V extends ComputedView | DiagramView>
|
|
36
|
+
extends NodeModel<M, V>
|
|
37
|
+
{
|
|
38
|
+
kind: 'instance'
|
|
39
|
+
element: ElementModel<M>
|
|
40
|
+
deployment: DeployedInstanceModel<M>
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface IsGroup<M extends AnyAux, V extends ComputedView | DiagramView> extends NodeModel<M, V> {
|
|
44
|
+
kind: typeof ElementKind.Group
|
|
45
|
+
element: null
|
|
46
|
+
deployment: null
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export class NodeModel<M extends AnyAux, V extends ComputedView | DiagramView = M['ViewType']> {
|
|
51
|
+
constructor(
|
|
52
|
+
public readonly $view: LikeC4ViewModel<M, V>,
|
|
53
|
+
public readonly $node: V['nodes'][number]
|
|
54
|
+
) {
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get id(): NodeId {
|
|
58
|
+
return this.$node.id
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get title(): string {
|
|
62
|
+
return this.$node.title
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get kind(): ElementKind | DeploymentNodeKind | typeof ElementKind.Group | 'instance' {
|
|
66
|
+
return this.$node.kind as any
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get description(): string | null {
|
|
70
|
+
return this.$node.description
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
get technology(): string | null {
|
|
74
|
+
return this.$node.technology
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get parent(): NodeModel<M, V> | null {
|
|
78
|
+
return this.$node.parent ? this.$view.node(this.$node.parent) : null
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
get element(): ElementModel<M> | null {
|
|
82
|
+
const modelRef = ComputedNode.modelRef(this.$node)
|
|
83
|
+
return modelRef ? this.$view.$model.element(modelRef) : null
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
get deployment(): DeploymentElementModel<M> | null {
|
|
87
|
+
const modelRef = ComputedNode.deploymentRef(this.$node)
|
|
88
|
+
return modelRef ? this.$view.$model.deployment.element(modelRef) : null
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
get shape(): C4ElementShape {
|
|
92
|
+
return this.$node.shape
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get color(): C4Color {
|
|
96
|
+
return this.$node.color
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
get tags(): ReadonlyArray<C4Tag> {
|
|
100
|
+
return this.$node.tags ?? []
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
get links(): ReadonlyArray<Link> {
|
|
104
|
+
return this.$node.links ?? []
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
get navigateTo(): LikeC4ViewModel<M> | null {
|
|
108
|
+
return this.$node.navigateTo ? this.$view.$model.view(this.$node.navigateTo) : null
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get all ancestor elements (i.e. parent, parent’s parent, etc.)
|
|
113
|
+
* (from closest to root)
|
|
114
|
+
*/
|
|
115
|
+
public *ancestors(): NodesIterator<M, V> {
|
|
116
|
+
let parent = this.parent
|
|
117
|
+
while (parent) {
|
|
118
|
+
yield parent
|
|
119
|
+
parent = parent.parent
|
|
120
|
+
}
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public *children(): NodesIterator<M, V> {
|
|
125
|
+
for (const child of this.$node.children) {
|
|
126
|
+
yield this.$view.node(child)
|
|
127
|
+
}
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
public *sublings(): NodesIterator<M, V> {
|
|
132
|
+
const sublings = this.parent?.children() ?? this.$view.roots()
|
|
133
|
+
for (const subling of sublings) {
|
|
134
|
+
if (subling.id !== this.id) {
|
|
135
|
+
yield subling
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public *incoming(filter: IncomingFilter = 'all'): EdgesIterator<M, V> {
|
|
142
|
+
for (const edgeId of this.$node.inEdges) {
|
|
143
|
+
const edge = this.$view.edge(edgeId)
|
|
144
|
+
switch (true) {
|
|
145
|
+
case filter === 'all':
|
|
146
|
+
case filter === 'direct' && edge.target.id === this.id:
|
|
147
|
+
case filter === 'to-descendants' && edge.target.id !== this.id:
|
|
148
|
+
yield edge
|
|
149
|
+
break
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
public *incomers(filter: IncomingFilter = 'all'): NodesIterator<M, V> {
|
|
156
|
+
const unique = new Set<NodeId>()
|
|
157
|
+
for (const r of this.incoming(filter)) {
|
|
158
|
+
if (unique.has(r.source.id)) {
|
|
159
|
+
continue
|
|
160
|
+
}
|
|
161
|
+
unique.add(r.source.id)
|
|
162
|
+
yield r.source
|
|
163
|
+
}
|
|
164
|
+
return
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public *outgoing(filter: OutgoingFilter = 'all'): EdgesIterator<M, V> {
|
|
168
|
+
for (const edgeId of this.$node.outEdges) {
|
|
169
|
+
const edge = this.$view.edge(edgeId)
|
|
170
|
+
switch (true) {
|
|
171
|
+
case filter === 'all':
|
|
172
|
+
case filter === 'direct' && edge.source.id === this.id:
|
|
173
|
+
case filter === 'from-descendants' && edge.source.id !== this.id:
|
|
174
|
+
yield edge
|
|
175
|
+
break
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public *outgoers(filter: OutgoingFilter = 'all'): NodesIterator<M, V> {
|
|
182
|
+
const unique = new Set<NodeId>()
|
|
183
|
+
for (const r of this.outgoing(filter)) {
|
|
184
|
+
if (unique.has(r.target.id)) {
|
|
185
|
+
continue
|
|
186
|
+
}
|
|
187
|
+
unique.add(r.target.id)
|
|
188
|
+
yield r.target
|
|
189
|
+
}
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
public isDiagramNode(): this is NodeModel<M, DiagramView> {
|
|
194
|
+
return 'width' in this.$node && 'height' in this.$node
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
public hasChildren(): boolean {
|
|
198
|
+
return this.$node.children.length > 0
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
public hasParent(): this is NodeModel.WithParent<M, V> {
|
|
202
|
+
return this.$node.parent !== null
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Check if this node references to logical model element.
|
|
207
|
+
*/
|
|
208
|
+
public hasElement(): this is NodeModel.WithElement<M, V> {
|
|
209
|
+
return ComputedNode.modelRef(this.$node) !== null
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Check if this node references to deployment element (Node or Instance).
|
|
213
|
+
*/
|
|
214
|
+
public hasDeployment(): this is NodeModel.WithDeploymentElement<M, V> {
|
|
215
|
+
return ComputedNode.deploymentRef(this.$node) !== null
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Check if this node references to deployed instance
|
|
219
|
+
* Deployed instance always references to element and deployment element.
|
|
220
|
+
*/
|
|
221
|
+
public hasDeployedInstance(): this is NodeModel.WithDeployedInstance<M, V> {
|
|
222
|
+
return this.hasElement() && this.hasDeployment()
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
public isGroup(): this is NodeModel.IsGroup<M, V> {
|
|
226
|
+
return ComputedNode.isNodesGroup(this.$node)
|
|
227
|
+
}
|
|
228
|
+
}
|
package/src/types/_common.ts
CHANGED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import type { MergeExclusive, Simplify, Tagged, UnionToIntersection } from 'type-fest'
|
|
2
|
+
import type { IconUrl, NonEmptyArray } from './_common'
|
|
3
|
+
import type { ElementShape, ElementStyle, Fqn, Link, Tag } from './element'
|
|
4
|
+
import type { RelationId, RelationshipArrowType, RelationshipKind, RelationshipLineType } from './relation'
|
|
5
|
+
import type { Color } from './theme'
|
|
6
|
+
import type { ViewId } from './view'
|
|
7
|
+
|
|
8
|
+
export type DeploymentNodeKind<Kinds extends string = string> = Tagged<Kinds, 'DeploymentNodeKind'>
|
|
9
|
+
|
|
10
|
+
export type PhysicalElementStyle = ElementStyle & {
|
|
11
|
+
readonly icon?: IconUrl
|
|
12
|
+
readonly shape?: ElementShape
|
|
13
|
+
readonly color?: Color
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface DeploymentNodeKindSpecification {
|
|
17
|
+
readonly technology?: string
|
|
18
|
+
readonly notation?: string
|
|
19
|
+
readonly style: PhysicalElementStyle
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface DeploymentNode {
|
|
23
|
+
// Full-qualified-name for Deployment model
|
|
24
|
+
readonly id: Fqn
|
|
25
|
+
readonly kind: DeploymentNodeKind
|
|
26
|
+
readonly title: string
|
|
27
|
+
readonly description?: string | null
|
|
28
|
+
readonly technology?: string | null
|
|
29
|
+
readonly tags?: NonEmptyArray<Tag> | null
|
|
30
|
+
readonly links?: NonEmptyArray<Link> | null
|
|
31
|
+
readonly style?: PhysicalElementStyle
|
|
32
|
+
readonly notation?: string
|
|
33
|
+
readonly metadata?: Record<string, string>
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface DeployedInstance {
|
|
37
|
+
/**
|
|
38
|
+
* Format: `<DeploymentNode Fqn>.<Instance Id>`
|
|
39
|
+
* i.e parent fqn is deployment target
|
|
40
|
+
*/
|
|
41
|
+
readonly id: Fqn
|
|
42
|
+
readonly element: Fqn
|
|
43
|
+
readonly title?: string
|
|
44
|
+
readonly description?: string | null
|
|
45
|
+
readonly technology?: string | null
|
|
46
|
+
readonly tags?: NonEmptyArray<Tag> | null
|
|
47
|
+
readonly links?: NonEmptyArray<Link> | null
|
|
48
|
+
readonly style?: PhysicalElementStyle
|
|
49
|
+
readonly notation?: string
|
|
50
|
+
readonly metadata?: Record<string, string>
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type DeploymentElement = Simplify<MergeExclusive<DeploymentNode, DeployedInstance>>
|
|
54
|
+
|
|
55
|
+
export namespace DeploymentElement {
|
|
56
|
+
export const isDeploymentNode = (el: DeploymentElement): el is DeploymentNode => {
|
|
57
|
+
return 'kind' in el && !('element' in el)
|
|
58
|
+
}
|
|
59
|
+
export const isInstance = (el: DeploymentElement): el is DeployedInstance => {
|
|
60
|
+
return 'element' in el && !('kind' in el)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface DeploymentRef {
|
|
65
|
+
// Reference to DeploymentNode or DeployedInstance
|
|
66
|
+
readonly id: Fqn
|
|
67
|
+
// Reference to element within DeployedInstance
|
|
68
|
+
readonly element?: Fqn
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// export namespace DeploymentRef {
|
|
72
|
+
// export interface Node {
|
|
73
|
+
// readonly id: Fqn
|
|
74
|
+
// }
|
|
75
|
+
// export interface Instance {
|
|
76
|
+
// readonly id: Fqn
|
|
77
|
+
// readonly element?: Fqn
|
|
78
|
+
// }
|
|
79
|
+
// export interface LogicalElement {
|
|
80
|
+
// readonly element: Fqn
|
|
81
|
+
// }
|
|
82
|
+
|
|
83
|
+
// export const isDeploymentElement = (ref: DeploymentRef): ref is Node | Instance => {
|
|
84
|
+
// return 'id' in ref
|
|
85
|
+
// }
|
|
86
|
+
|
|
87
|
+
// export const isLogicalElement = (ref: DeploymentRef): ref is LogicalElement => {
|
|
88
|
+
// return 'element' in ref && !('id' in ref)
|
|
89
|
+
// }
|
|
90
|
+
// }
|
|
91
|
+
// export type DeploymentRef = ExclusiveUnion<{
|
|
92
|
+
// Node: DeploymentRef.Node
|
|
93
|
+
// Instance: DeploymentRef.Instance
|
|
94
|
+
// Element: DeploymentRef.LogicalElement
|
|
95
|
+
// }>
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* NOTE:
|
|
99
|
+
*/
|
|
100
|
+
export interface DeploymentRelation {
|
|
101
|
+
readonly id: RelationId
|
|
102
|
+
readonly source: DeploymentRef
|
|
103
|
+
readonly target: DeploymentRef
|
|
104
|
+
readonly title?: string
|
|
105
|
+
readonly tags?: NonEmptyArray<Tag> | null
|
|
106
|
+
readonly description?: string
|
|
107
|
+
readonly technology?: string
|
|
108
|
+
readonly kind?: RelationshipKind
|
|
109
|
+
readonly color?: Color
|
|
110
|
+
readonly line?: RelationshipLineType
|
|
111
|
+
readonly head?: RelationshipArrowType
|
|
112
|
+
readonly tail?: RelationshipArrowType
|
|
113
|
+
readonly links?: NonEmptyArray<Link> | null
|
|
114
|
+
// Link to dynamic view
|
|
115
|
+
readonly navigateTo?: ViewId
|
|
116
|
+
readonly metadata?: { [key: string]: string }
|
|
117
|
+
}
|
|
118
|
+
// export interface DeploymentRelation
|
|
119
|
+
|
|
120
|
+
// interface Expressions {
|
|
121
|
+
// DeploymentRef: {
|
|
122
|
+
// ref: DeploymentRef
|
|
123
|
+
// isExpanded?: boolean
|
|
124
|
+
// isNested?: never
|
|
125
|
+
// } | {
|
|
126
|
+
// ref: DeploymentRef
|
|
127
|
+
// isExpanded?: never
|
|
128
|
+
// isNested?: boolean
|
|
129
|
+
// }
|
|
130
|
+
|
|
131
|
+
// Wildcard: {
|
|
132
|
+
// wildcard: true
|
|
133
|
+
// }
|
|
134
|
+
// }
|
|
135
|
+
|
|
136
|
+
type AllNever<Expressions> = UnionToIntersection<
|
|
137
|
+
{
|
|
138
|
+
[Name in keyof Expressions]: {
|
|
139
|
+
-readonly [Key in keyof Expressions[Name]]?: never
|
|
140
|
+
}
|
|
141
|
+
}[keyof Expressions]
|
|
142
|
+
>
|
|
143
|
+
|
|
144
|
+
type ExclusiveUnion<Expressions> = Expressions extends object ? {
|
|
145
|
+
[Name in keyof Expressions]: Simplify<Omit<AllNever<Expressions>, keyof Expressions[Name]> & Expressions[Name]>
|
|
146
|
+
}[keyof Expressions]
|
|
147
|
+
: Expressions
|
|
148
|
+
|
|
149
|
+
export namespace DeploymentRelationExpression {
|
|
150
|
+
// type LogicalRefEndpoint = {
|
|
151
|
+
// logicalRef: ElementRefExpr
|
|
152
|
+
// }
|
|
153
|
+
// export type DirectEndpoint = ExclusiveUnion<{
|
|
154
|
+
// DeploymentElementExpression: DeploymentElementExpression
|
|
155
|
+
// Logical: LogicalRefEndpoint
|
|
156
|
+
// }>
|
|
157
|
+
|
|
158
|
+
// export const isLogicalEndpoint = (expr: DirectEndpoint): expr is LogicalRefEndpoint => {
|
|
159
|
+
// return 'logicalRef' in expr
|
|
160
|
+
// }
|
|
161
|
+
|
|
162
|
+
export type Direct = {
|
|
163
|
+
source: DeploymentElementExpression
|
|
164
|
+
target: DeploymentElementExpression
|
|
165
|
+
isBidirectional?: boolean
|
|
166
|
+
}
|
|
167
|
+
export const isDirect = (expr: DeploymentExpression): expr is Direct => {
|
|
168
|
+
return 'source' in expr && 'target' in expr
|
|
169
|
+
}
|
|
170
|
+
export type Incoming = {
|
|
171
|
+
incoming: DeploymentElementExpression
|
|
172
|
+
}
|
|
173
|
+
export const isIncoming = (expr: DeploymentExpression): expr is Incoming => {
|
|
174
|
+
return 'incoming' in expr
|
|
175
|
+
}
|
|
176
|
+
export type Outgoing = {
|
|
177
|
+
outgoing: DeploymentElementExpression
|
|
178
|
+
}
|
|
179
|
+
export const isOutgoing = (expr: DeploymentExpression): expr is Outgoing => {
|
|
180
|
+
return 'outgoing' in expr
|
|
181
|
+
}
|
|
182
|
+
export type InOut = {
|
|
183
|
+
inout: DeploymentElementExpression
|
|
184
|
+
}
|
|
185
|
+
export const isInOut = (expr: DeploymentExpression): expr is InOut => {
|
|
186
|
+
return 'inout' in expr
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export type DeploymentRelationExpression = ExclusiveUnion<{
|
|
191
|
+
Direct: DeploymentRelationExpression.Direct
|
|
192
|
+
Incoming: DeploymentRelationExpression.Incoming
|
|
193
|
+
Outgoing: DeploymentRelationExpression.Outgoing
|
|
194
|
+
InOut: DeploymentRelationExpression.InOut
|
|
195
|
+
}>
|
|
196
|
+
|
|
197
|
+
export namespace DeploymentElementExpression {
|
|
198
|
+
export type Ref = {
|
|
199
|
+
ref: DeploymentRef
|
|
200
|
+
selector?:
|
|
201
|
+
| 'children' // ele.*
|
|
202
|
+
| 'expanded' // ele._
|
|
203
|
+
| 'descendants' // ele.**
|
|
204
|
+
}
|
|
205
|
+
export const isRef = (expr: DeploymentExpression): expr is Ref => {
|
|
206
|
+
return 'ref' in expr
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
export type Wildcard = {
|
|
210
|
+
wildcard: true
|
|
211
|
+
}
|
|
212
|
+
export const isWildcard = (expr: DeploymentExpression): expr is Wildcard => {
|
|
213
|
+
return 'wildcard' in expr && expr.wildcard === true
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export type DeploymentElementExpression = ExclusiveUnion<{
|
|
218
|
+
DeploymentRef: DeploymentElementExpression.Ref
|
|
219
|
+
Wildcard: DeploymentElementExpression.Wildcard
|
|
220
|
+
}>
|
|
221
|
+
|
|
222
|
+
export type DeploymentExpression = ExclusiveUnion<{
|
|
223
|
+
Element: DeploymentElementExpression
|
|
224
|
+
Relation: DeploymentRelationExpression
|
|
225
|
+
}>
|
|
226
|
+
|
|
227
|
+
export namespace DeploymentExpression {
|
|
228
|
+
export type Element = DeploymentElementExpression
|
|
229
|
+
export type Relation = DeploymentRelationExpression
|
|
230
|
+
|
|
231
|
+
export const isElement = (expr: DeploymentExpression): expr is DeploymentElementExpression => {
|
|
232
|
+
return DeploymentElementExpression.isRef(expr) || DeploymentElementExpression.isWildcard(expr)
|
|
233
|
+
}
|
|
234
|
+
export const isRelation = (expr: DeploymentExpression): expr is DeploymentRelationExpression => {
|
|
235
|
+
return !DeploymentExpression.isElement(expr)
|
|
236
|
+
}
|
|
237
|
+
}
|
package/src/types/element.ts
CHANGED
|
@@ -32,9 +32,13 @@ export const DefaultThemeColor = 'primary' satisfies ThemeColor
|
|
|
32
32
|
export const DefaultElementShape = 'rectangle' satisfies ElementShape
|
|
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'>
|