@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.
Files changed (112) hide show
  1. package/dist/compute-view/index.d.mts +91 -0
  2. package/dist/compute-view/index.d.ts +91 -0
  3. package/dist/compute-view/index.mjs +79 -0
  4. package/dist/index.d.mts +246 -434
  5. package/dist/index.d.ts +246 -434
  6. package/dist/index.mjs +418 -1322
  7. package/dist/model/index.d.mts +642 -0
  8. package/dist/model/index.d.ts +642 -0
  9. package/dist/model/index.mjs +2 -0
  10. package/dist/shared/core.BBgiAAv1.mjs +144 -0
  11. package/dist/shared/core.BPyJvuMU.mjs +2420 -0
  12. package/dist/shared/core.BQ4AbfvB.mjs +9228 -0
  13. package/dist/shared/{core.CoLQkcYL.d.mts → core.DMYY7C8s.d.mts} +398 -249
  14. package/dist/shared/{core.CoLQkcYL.d.ts → core.DMYY7C8s.d.ts} +398 -249
  15. package/dist/shared/core.k12s_keD.mjs +203 -0
  16. package/dist/types/index.d.mts +69 -1
  17. package/dist/types/index.d.ts +69 -1
  18. package/dist/types/index.mjs +21 -1
  19. package/package.json +38 -40
  20. package/src/builder/Builder.deployment.ts +219 -0
  21. package/src/builder/Builder.deploymentModel.ts +360 -0
  22. package/src/builder/Builder.element.ts +17 -19
  23. package/src/builder/Builder.model.ts +13 -2
  24. package/src/builder/Builder.test-d.ts +59 -4
  25. package/src/builder/Builder.ts +238 -53
  26. package/src/builder/Builder.view.ts +238 -53
  27. package/src/builder/_types.ts +87 -15
  28. package/src/compute-view/LikeC4ModelGraph.ts +330 -0
  29. package/src/compute-view/compute-view.ts +92 -0
  30. package/src/compute-view/deployment-view/Memory.ts +108 -0
  31. package/src/compute-view/deployment-view/Stage.ts +145 -0
  32. package/src/compute-view/deployment-view/__test__/fixture.ts +210 -0
  33. package/src/compute-view/deployment-view/_types.ts +29 -0
  34. package/src/compute-view/deployment-view/clean-connections.ts +229 -0
  35. package/src/compute-view/deployment-view/compute.ts +111 -0
  36. package/src/compute-view/deployment-view/predicates/deployment-ref.ts +146 -0
  37. package/src/compute-view/deployment-view/predicates/relation-direct.ts +130 -0
  38. package/src/compute-view/deployment-view/predicates/relation-in-out.ts +43 -0
  39. package/src/compute-view/deployment-view/predicates/relation-incoming.ts +46 -0
  40. package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +49 -0
  41. package/src/compute-view/deployment-view/predicates/wildcard.ts +29 -0
  42. package/src/compute-view/deployment-view/utils.ts +212 -0
  43. package/src/compute-view/dynamic-view/__test__/fixture.ts +58 -0
  44. package/src/compute-view/dynamic-view/compute.ts +310 -0
  45. package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +456 -0
  46. package/src/compute-view/element-view/__test__/fixture.ts +645 -0
  47. package/src/compute-view/element-view/compute.ts +734 -0
  48. package/src/compute-view/element-view/predicates.ts +517 -0
  49. package/src/compute-view/index.ts +5 -0
  50. package/src/compute-view/utils/__snapshots__/sortNodes.spec.ts.snap +113 -0
  51. package/src/compute-view/utils/ancestorsOfNode.ts +19 -0
  52. package/src/compute-view/utils/applyCustomElementProperties.ts +66 -0
  53. package/src/compute-view/utils/applyCustomRelationProperties.ts +41 -0
  54. package/src/compute-view/utils/applyViewRuleStyles.ts +53 -0
  55. package/src/compute-view/utils/buildComputedNodes.ts +148 -0
  56. package/src/compute-view/utils/buildElementNotations.ts +63 -0
  57. package/src/compute-view/utils/derive-edge-props-from-relationships.ts +97 -0
  58. package/src/compute-view/utils/elementExpressionToPredicate.ts +52 -0
  59. package/src/compute-view/utils/link-nodes-with-edges.ts +58 -0
  60. package/src/compute-view/utils/relationExpressionToPredicates.ts +55 -0
  61. package/src/compute-view/utils/resolve-extended-views.ts +65 -0
  62. package/src/compute-view/utils/resolve-global-rules.ts +83 -0
  63. package/src/compute-view/utils/sortNodes.ts +101 -0
  64. package/src/compute-view/utils/topological-sort.ts +160 -0
  65. package/src/compute-view/utils/uniqueTags.test.ts +42 -0
  66. package/src/compute-view/utils/uniqueTags.ts +21 -0
  67. package/src/compute-view/utils/view-hash.ts +27 -0
  68. package/src/compute-view/utils/with-readable-edges.ts +31 -0
  69. package/src/index.ts +5 -1
  70. package/src/model/DeploymentElementModel.ts +534 -0
  71. package/src/model/DeploymentModel.ts +364 -0
  72. package/src/model/ElementModel.ts +195 -0
  73. package/src/model/LikeC4Model.test-d.ts +151 -0
  74. package/src/model/LikeC4Model.ts +280 -457
  75. package/src/model/RelationModel.ts +84 -0
  76. package/src/model/__test__/fixture.ts +153 -338
  77. package/src/model/connection/ConnectionModel.ts +94 -0
  78. package/src/model/connection/DeploymentConnectionModel.ts +99 -0
  79. package/src/model/connection/deployment.ts +124 -0
  80. package/src/model/connection/model.ts +123 -0
  81. package/src/model/index.ts +4 -2
  82. package/src/model/types.ts +95 -15
  83. package/src/model/view/EdgeModel.ts +103 -0
  84. package/src/model/view/LikeC4ViewModel.ts +220 -0
  85. package/src/model/view/NodeModel.ts +228 -0
  86. package/src/types/_common.ts +2 -0
  87. package/src/types/deployments.ts +237 -0
  88. package/src/types/element.ts +7 -3
  89. package/src/types/expression.ts +8 -6
  90. package/src/types/index.ts +1 -0
  91. package/src/types/model.ts +68 -9
  92. package/src/types/overview-graph.ts +2 -2
  93. package/src/types/relation.ts +4 -4
  94. package/src/types/view-notation.ts +2 -2
  95. package/src/types/view.ts +104 -30
  96. package/src/utils/{commonHead.ts → common-head.ts} +2 -0
  97. package/src/utils/fqn.ts +83 -27
  98. package/src/utils/getOrCreate.ts +42 -0
  99. package/src/utils/graphlib.ts +10 -0
  100. package/src/utils/index.ts +4 -1
  101. package/src/utils/object-hash.ts +3 -0
  102. package/src/utils/set.ts +76 -0
  103. package/src/utils/string-hash.ts +16 -0
  104. package/dist/index.cjs +0 -5452
  105. package/dist/index.d.cts +0 -1053
  106. package/dist/shared/core.BXTs-8n7.mjs +0 -293
  107. package/dist/shared/core.CoLQkcYL.d.cts +0 -734
  108. package/dist/shared/core.DIYZvpVg.cjs +0 -353
  109. package/dist/types/index.cjs +0 -70
  110. package/dist/types/index.d.cts +0 -2
  111. package/src/model/LikeC4DiagramModel.ts +0 -338
  112. 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
+ }
@@ -14,3 +14,5 @@ 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
@@ -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
+ }
@@ -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
- // 0-100
37
- opacity?: number
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'>