@likec4/core 1.27.3 → 1.28.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 (71) hide show
  1. package/dist/builder/index.d.mts +6 -6
  2. package/dist/builder/index.mjs +23 -13
  3. package/dist/compute-view/index.d.mts +3 -3
  4. package/dist/compute-view/index.mjs +3 -3
  5. package/dist/compute-view/relationships-view/index.d.mts +3 -3
  6. package/dist/index.d.mts +6 -6
  7. package/dist/index.mjs +2 -2
  8. package/dist/model/index.d.mts +6 -6
  9. package/dist/model/index.mjs +1 -1
  10. package/dist/shared/{core.RjpTh3vE.mjs → core.Bjl6Kmc8.mjs} +260 -168
  11. package/dist/shared/{core.BpuZeqlX.d.mts → core.CZR9J1Qx.d.mts} +2 -2
  12. package/dist/shared/{core.Djro-kuQ.d.mts → core.CiFKryGW.d.mts} +7 -2
  13. package/dist/shared/{core.HKn0jlo_.d.mts → core.D2830qgg.d.mts} +1 -1
  14. package/dist/shared/{core.CFDwncxs.d.mts → core.DJvmfnEi.d.mts} +481 -186
  15. package/dist/shared/{core.BMep80lJ.mjs → core.DgfwjBtu.mjs} +198 -87
  16. package/dist/shared/core.SjLhMA7a.d.mts +62 -0
  17. package/dist/types/index.d.mts +4 -4
  18. package/dist/types/index.mjs +1 -1
  19. package/dist/utils/index.d.mts +2 -2
  20. package/package.json +6 -6
  21. package/src/builder/Builder.ts +1 -0
  22. package/src/builder/Builder.view-common.ts +10 -10
  23. package/src/builder/Builder.view-element.ts +26 -14
  24. package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +23 -8
  25. package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +9 -4
  26. package/src/compute-view/deployment-view/predicates/deploymentRefs-where.ts +18 -0
  27. package/src/compute-view/deployment-view/predicates/relation-direct.ts +6 -0
  28. package/src/compute-view/deployment-view/predicates/relation-in-out.ts +3 -0
  29. package/src/compute-view/deployment-view/predicates/relation-incoming.ts +3 -0
  30. package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +3 -0
  31. package/src/compute-view/deployment-view/predicates/utils.ts +10 -3
  32. package/src/compute-view/deployment-view/utils.ts +7 -4
  33. package/src/compute-view/element-view/__test__/fixture.ts +72 -65
  34. package/src/compute-view/element-view/_types.ts +13 -9
  35. package/src/compute-view/element-view/compute.ts +27 -27
  36. package/src/compute-view/element-view/memory/NodeGroup.ts +4 -3
  37. package/src/compute-view/element-view/memory/memory.ts +3 -2
  38. package/src/compute-view/element-view/memory/stage-include.ts +2 -2
  39. package/src/compute-view/element-view/predicates/_utils.ts +25 -24
  40. package/src/compute-view/element-view/predicates/element-expand.ts +7 -10
  41. package/src/compute-view/element-view/predicates/element-kind-tag.ts +5 -3
  42. package/src/compute-view/element-view/predicates/element-ref.ts +7 -19
  43. package/src/compute-view/element-view/predicates/relation-direct.ts +15 -13
  44. package/src/compute-view/element-view/predicates/relation-in-out.ts +5 -6
  45. package/src/compute-view/element-view/predicates/relation-in.ts +36 -32
  46. package/src/compute-view/element-view/predicates/relation-out.ts +37 -33
  47. package/src/compute-view/element-view/predicates/wildcard.ts +2 -2
  48. package/src/compute-view/utils/applyCustomElementProperties.ts +9 -4
  49. package/src/compute-view/utils/applyCustomRelationProperties.ts +10 -7
  50. package/src/compute-view/utils/elementExpressionToPredicate.ts +27 -26
  51. package/src/compute-view/utils/link-nodes-with-edges.ts +1 -1
  52. package/src/compute-view/utils/relationExpressionToPredicates.ts +10 -17
  53. package/src/compute-view/utils/uniqueTags.ts +3 -3
  54. package/src/index.ts +0 -2
  55. package/src/model/ElementModel.ts +25 -6
  56. package/src/model/LikeC4Model.ts +44 -6
  57. package/src/model/RelationModel.ts +4 -2
  58. package/src/model/view/LikeC4ViewModel.ts +3 -2
  59. package/src/types/_common.ts +0 -4
  60. package/src/types/deployments.ts +3 -2
  61. package/src/types/element.ts +2 -10
  62. package/src/types/expression-v2-model.ts +314 -0
  63. package/src/types/expression-v2.ts +238 -30
  64. package/src/types/index.ts +15 -46
  65. package/src/types/model-data.ts +4 -1
  66. package/src/types/relation.ts +2 -1
  67. package/src/types/scalars.ts +39 -0
  68. package/src/types/view-changes.ts +2 -1
  69. package/src/types/view.ts +7 -8
  70. package/dist/shared/core.30yYKXcZ.d.mts +0 -186
  71. package/src/types/expression.ts +0 -207
@@ -0,0 +1,314 @@
1
+ import type { ExclusiveUnion } from './_common'
2
+ import type { PredicateSelector } from './deployments'
3
+ import type { BorderStyle, ElementKind, ElementShape } from './element'
4
+ import type { WhereOperator } from './operators'
5
+ import type { RelationshipArrowType, RelationshipLineType } from './relation'
6
+ import { type Fqn, type IconUrl, type ProjectId, type Tag, GlobalFqn } from './scalars'
7
+ import type { Color, ShapeSize } from './theme'
8
+ import type { ViewId } from './view'
9
+
10
+ export namespace ModelLayer {
11
+ export namespace FqnRef {
12
+ /**
13
+ * Reference to logical model element
14
+ */
15
+ export type ModelRef<F = Fqn> = {
16
+ model: F
17
+ }
18
+ export const isModelRef = (ref: FqnRef): ref is ModelRef => {
19
+ return 'model' in ref && !('project' in ref)
20
+ }
21
+
22
+ /**
23
+ * Reference to imported logical model element
24
+ */
25
+ export type ImportRef<F = Fqn> = {
26
+ project: ProjectId
27
+ model: F
28
+ }
29
+ export const isImportRef = (ref: FqnRef): ref is ImportRef => {
30
+ return 'project' in ref && 'model' in ref
31
+ }
32
+
33
+ export const toFqn = (ref: FqnRef): Fqn => {
34
+ if (isImportRef(ref)) {
35
+ return GlobalFqn(ref.project, ref.model)
36
+ }
37
+ if (isModelRef(ref)) {
38
+ return ref.model
39
+ }
40
+ throw new Error('Expected FqnRef.ModelRef or FqnRef.ImportRef')
41
+ }
42
+ }
43
+
44
+ export type FqnRef<M = Fqn> = ExclusiveUnion<{
45
+ ModelRef: FqnRef.ModelRef<M>
46
+ ImportRef: FqnRef.ImportRef<M>
47
+ }>
48
+
49
+ export namespace FqnExpr {
50
+ export type Wildcard = {
51
+ wildcard: true
52
+ }
53
+ export const isWildcard = (expr: Expression): expr is FqnExpr.Wildcard => {
54
+ return 'wildcard' in expr && expr.wildcard === true
55
+ }
56
+
57
+ export type ModelRef<M = Fqn> = {
58
+ ref: FqnRef.ModelRef<M> | FqnRef.ImportRef<M>
59
+ selector?: PredicateSelector
60
+ }
61
+ export const isModelRef = (ref: Expression): ref is FqnExpr.ModelRef => {
62
+ return 'ref' in ref
63
+ }
64
+
65
+ export type ElementKindExpr = {
66
+ elementKind: ElementKind
67
+ isEqual: boolean
68
+ }
69
+ export function isElementKindExpr(expr: Expression): expr is ElementKindExpr {
70
+ return 'elementKind' in expr && 'isEqual' in expr
71
+ }
72
+
73
+ export type ElementTagExpr = {
74
+ elementTag: Tag
75
+ isEqual: boolean
76
+ }
77
+ export function isElementTagExpr(expr: Expression): expr is ElementTagExpr {
78
+ return 'elementTag' in expr && 'isEqual' in expr
79
+ }
80
+
81
+ export type NonWildcard<M = Fqn> = ExclusiveUnion<{
82
+ ModelRef: ModelRef<M>
83
+ ElementKind: ElementKindExpr
84
+ ElementTag: ElementTagExpr
85
+ }>
86
+
87
+ export type Where<M = Fqn> = {
88
+ where: {
89
+ expr: ExclusiveUnion<{
90
+ Wildcard: Wildcard
91
+ ModelRef: ModelRef<M>
92
+ ElementKind: ElementKindExpr
93
+ ElementTag: ElementTagExpr
94
+ }>
95
+ condition: WhereOperator<string, string>
96
+ }
97
+ }
98
+
99
+ export const isWhere = (expr: Expression): expr is FqnExpr.Where => {
100
+ return 'where' in expr && is(expr.where.expr)
101
+ }
102
+
103
+ export type Custom<M = Fqn> = {
104
+ custom: {
105
+ expr: FqnExprOrWhere<M>
106
+ title?: string
107
+ description?: string
108
+ technology?: string
109
+ notation?: string
110
+ shape?: ElementShape
111
+ color?: Color
112
+ icon?: IconUrl
113
+ border?: BorderStyle
114
+ opacity?: number
115
+ navigateTo?: ViewId
116
+ multiple?: boolean
117
+ size?: ShapeSize
118
+ padding?: ShapeSize
119
+ textSize?: ShapeSize
120
+ }
121
+ }
122
+
123
+ export const isCustom = (expr: Expression): expr is FqnExpr.Custom => {
124
+ return 'custom' in expr && (is(expr.custom.expr) || isWhere(expr.custom.expr))
125
+ }
126
+
127
+ export const is = (expr: Expression): expr is FqnExpr => {
128
+ return isWildcard(expr)
129
+ || isModelRef(expr)
130
+ || isElementKindExpr(expr)
131
+ || isElementTagExpr(expr)
132
+ }
133
+ }
134
+
135
+ export type FqnExpr<M = Fqn> = ExclusiveUnion<{
136
+ Wildcard: FqnExpr.Wildcard
137
+ ModelRef: FqnExpr.ModelRef<M>
138
+ ElementKind: FqnExpr.ElementKindExpr
139
+ ElementTag: FqnExpr.ElementTagExpr
140
+ }>
141
+
142
+ export type FqnExprOrWhere<M = Fqn> = ExclusiveUnion<{
143
+ Wildcard: FqnExpr.Wildcard
144
+ ModelRef: FqnExpr.ModelRef<M>
145
+ ElementKind: FqnExpr.ElementKindExpr
146
+ ElementTag: FqnExpr.ElementTagExpr
147
+ Where: FqnExpr.Where<M>
148
+ }>
149
+
150
+ export type AnyFqnExpr<M = Fqn> = ExclusiveUnion<{
151
+ Wildcard: FqnExpr.Wildcard
152
+ ModelRef: FqnExpr.ModelRef<M>
153
+ ElementKind: FqnExpr.ElementKindExpr
154
+ ElementTag: FqnExpr.ElementTagExpr
155
+ Where: FqnExpr.Where<M>
156
+ Custom: FqnExpr.Custom<M>
157
+ }>
158
+
159
+ export function isAnyFqnExpr(expr: Expression): expr is AnyFqnExpr {
160
+ return FqnExpr.is(expr)
161
+ || FqnExpr.isWhere(expr)
162
+ || FqnExpr.isCustom(expr)
163
+ }
164
+
165
+ export namespace RelationExpr {
166
+ export type Direct<M = Fqn> = {
167
+ source: FqnExpr<M>
168
+ target: FqnExpr<M>
169
+ isBidirectional?: boolean
170
+ }
171
+ export const isDirect = (expr: Expression): expr is RelationExpr.Direct => {
172
+ return 'source' in expr && 'target' in expr
173
+ }
174
+ export type Incoming<M = Fqn> = {
175
+ incoming: FqnExpr<M>
176
+ }
177
+ export const isIncoming = (expr: Expression): expr is RelationExpr.Incoming => {
178
+ return 'incoming' in expr
179
+ }
180
+ export type Outgoing<M = Fqn> = {
181
+ outgoing: FqnExpr<M>
182
+ }
183
+ export const isOutgoing = (expr: Expression): expr is RelationExpr.Outgoing => {
184
+ return 'outgoing' in expr
185
+ }
186
+ export type InOut<M = Fqn> = {
187
+ inout: FqnExpr<M>
188
+ }
189
+ export const isInOut = (expr: Expression): expr is RelationExpr.InOut => {
190
+ return 'inout' in expr
191
+ }
192
+ export type Where<M = Fqn> = {
193
+ where: {
194
+ expr: ExclusiveUnion<{
195
+ Direct: RelationExpr.Direct<M>
196
+ Incoming: RelationExpr.Incoming<M>
197
+ Outgoing: RelationExpr.Outgoing<M>
198
+ InOut: RelationExpr.InOut<M>
199
+ }>
200
+ condition: WhereOperator<string, string>
201
+ }
202
+ }
203
+ export const isWhere = (expr: Expression): expr is RelationExpr.Where => {
204
+ return 'where' in expr && is(expr.where.expr)
205
+ }
206
+
207
+ export type Custom<M = Fqn> = {
208
+ customRelation: {
209
+ expr: RelationExprOrWhere<M>
210
+ title?: string
211
+ description?: string
212
+ technology?: string
213
+ notation?: string
214
+ // Link to dynamic view
215
+ navigateTo?: ViewId
216
+ // Notes for walkthrough
217
+ notes?: string
218
+ color?: Color
219
+ line?: RelationshipLineType
220
+ head?: RelationshipArrowType
221
+ tail?: RelationshipArrowType
222
+ }
223
+ }
224
+
225
+ export const isCustom = (expr: Expression): expr is Custom => {
226
+ return 'customRelation' in expr
227
+ }
228
+
229
+ export const is = (expr: Expression): expr is RelationExpr => {
230
+ return isDirect(expr)
231
+ || isIncoming(expr)
232
+ || isOutgoing(expr)
233
+ || isInOut(expr)
234
+ }
235
+ }
236
+
237
+ export type RelationExpr<M = Fqn> = ExclusiveUnion<{
238
+ Direct: RelationExpr.Direct<M>
239
+ Incoming: RelationExpr.Incoming<M>
240
+ Outgoing: RelationExpr.Outgoing<M>
241
+ InOut: RelationExpr.InOut<M>
242
+ }>
243
+
244
+ export type RelationExprOrWhere<M = Fqn> = ExclusiveUnion<{
245
+ Direct: RelationExpr.Direct<M>
246
+ Incoming: RelationExpr.Incoming<M>
247
+ Outgoing: RelationExpr.Outgoing<M>
248
+ InOut: RelationExpr.InOut<M>
249
+ Where: RelationExpr.Where<M>
250
+ }>
251
+
252
+ export type AnyRelationExpr<M = Fqn> = ExclusiveUnion<{
253
+ Direct: RelationExpr.Direct<M>
254
+ Incoming: RelationExpr.Incoming<M>
255
+ Outgoing: RelationExpr.Outgoing<M>
256
+ InOut: RelationExpr.InOut<M>
257
+ Where: RelationExpr.Where<M>
258
+ CustomRelation: RelationExpr.Custom<M>
259
+ }>
260
+
261
+ export function isAnyRelationExpr(expr: Expression): expr is AnyRelationExpr {
262
+ return RelationExpr.is(expr)
263
+ || RelationExpr.isWhere(expr)
264
+ || RelationExpr.isCustom(expr)
265
+ }
266
+
267
+ /**
268
+ * Represents a version 2 expression which can be one of several types.
269
+ *
270
+ * @template M - The type for the model FQN, defaults to `Fqn`.
271
+ */
272
+ export type Expression<M = Fqn> = ExclusiveUnion<{
273
+ Wildcard: FqnExpr.Wildcard
274
+ ModelRef: FqnExpr.ModelRef<M>
275
+ ElementKind: FqnExpr.ElementKindExpr
276
+ ElementTag: FqnExpr.ElementTagExpr
277
+ Custom: FqnExpr.Custom<M>
278
+ Direct: RelationExpr.Direct<M>
279
+ Incoming: RelationExpr.Incoming<M>
280
+ Outgoing: RelationExpr.Outgoing<M>
281
+ InOut: RelationExpr.InOut<M>
282
+ CustomRelation: RelationExpr.Custom<M>
283
+ Where: Expression.Where<M>
284
+ }>
285
+
286
+ export function isExpression(expr: any): expr is Expression {
287
+ return isAnyFqnExpr(expr)
288
+ || isAnyRelationExpr(expr)
289
+ }
290
+
291
+ export namespace Expression {
292
+ export type Where<M = Fqn> = FqnExpr.Where<M> | RelationExpr.Where<M>
293
+
294
+ export const isWhere = (expr: Expression): expr is Expression.Where => {
295
+ return 'where' in expr
296
+ }
297
+
298
+ export const isCustomFqnExpr = (expr: Expression): expr is FqnExpr.Custom => {
299
+ return FqnExpr.isCustom(expr)
300
+ }
301
+
302
+ export const isCustomRelationExpr = (expr: Expression): expr is RelationExpr.Custom => {
303
+ return RelationExpr.isCustom(expr)
304
+ }
305
+
306
+ export const isFqnExpr = (expr: Expression): expr is FqnExpr => {
307
+ return FqnExpr.is(expr)
308
+ }
309
+
310
+ export const isRelation = (expr: Expression): expr is RelationExpr => {
311
+ return RelationExpr.is(expr)
312
+ }
313
+ }
314
+ }
@@ -1,8 +1,12 @@
1
1
  import { invariant } from '../errors'
2
2
  import type { ExclusiveUnion } from './_common'
3
3
  import type { DeploymentRef as DeploymentModelRef, PredicateSelector } from './deployments'
4
- import type { Fqn } from './element'
4
+ import type { BorderStyle, ElementKind, ElementShape } from './element'
5
5
  import type { WhereOperator } from './operators'
6
+ import type { RelationshipArrowType, RelationshipLineType } from './relation'
7
+ import { type Fqn, type IconUrl, type ProjectId, type Tag, GlobalFqn } from './scalars'
8
+ import type { Color, ShapeSize } from './theme'
9
+ import type { ViewId } from './view'
6
10
 
7
11
  export namespace FqnRef {
8
12
  /**
@@ -37,7 +41,7 @@ export namespace FqnRef {
37
41
 
38
42
  export type DeploymentRef<D = Fqn, M = Fqn> = DeploymentElementRef<D> | InsideInstanceRef<D, M>
39
43
  export const isDeploymentRef = (ref: FqnRef): ref is DeploymentRef => {
40
- return !isModelRef(ref)
44
+ return !isModelRef(ref) && !isImportRef(ref)
41
45
  }
42
46
 
43
47
  /**
@@ -47,7 +51,18 @@ export namespace FqnRef {
47
51
  model: F
48
52
  }
49
53
  export const isModelRef = (ref: FqnRef): ref is ModelRef => {
50
- return 'model' in ref
54
+ return 'model' in ref && !('project' in ref)
55
+ }
56
+
57
+ /**
58
+ * Reference to imported logical model element
59
+ */
60
+ export type ImportRef<F = Fqn> = {
61
+ project: ProjectId
62
+ model: F
63
+ }
64
+ export const isImportRef = (ref: FqnRef): ref is ImportRef => {
65
+ return 'project' in ref && 'model' in ref
51
66
  }
52
67
 
53
68
  export const toDeploymentRef = (ref: FqnRef): DeploymentModelRef => {
@@ -61,28 +76,39 @@ export namespace FqnRef {
61
76
  id: ref.deployment,
62
77
  }
63
78
  }
79
+
80
+ export const toModelFqn = (ref: FqnRef): Fqn => {
81
+ if (isImportRef(ref)) {
82
+ return GlobalFqn(ref.project, ref.model)
83
+ }
84
+ if (isModelRef(ref)) {
85
+ return ref.model
86
+ }
87
+ throw new Error('Expected FqnRef.ModelRef or FqnRef.ImportRef')
88
+ }
64
89
  }
65
90
 
66
91
  export type FqnRef<D = Fqn, M = Fqn> = ExclusiveUnion<{
67
92
  InsideInstanceRef: FqnRef.InsideInstanceRef<D, M>
68
93
  DeploymentRef: FqnRef.DeploymentRef<D>
69
94
  ModelRef: FqnRef.ModelRef<M>
95
+ ImportRef: FqnRef.ImportRef<M>
70
96
  }>
71
97
 
72
98
  export namespace FqnExpr {
73
99
  export type Wildcard = {
74
100
  wildcard: true
75
101
  }
76
- export const isWildcard = (expr: ExpressionV2): expr is Wildcard => {
102
+ export const isWildcard = (expr: ExpressionV2): expr is FqnExpr.Wildcard => {
77
103
  return 'wildcard' in expr && expr.wildcard === true
78
104
  }
79
105
 
80
106
  export type ModelRef<M = Fqn> = {
81
- ref: FqnRef.ModelRef<M>
107
+ ref: FqnRef.ModelRef<M> | FqnRef.ImportRef<M>
82
108
  selector?: PredicateSelector
83
109
  }
84
- export const isModelRef = (ref: ExpressionV2): ref is ModelRef => {
85
- return 'ref' in ref && FqnRef.isModelRef(ref.ref)
110
+ export const isModelRef = (ref: ExpressionV2): ref is FqnExpr.ModelRef => {
111
+ return 'ref' in ref && (FqnRef.isModelRef(ref.ref) || FqnRef.isImportRef(ref.ref))
86
112
  }
87
113
 
88
114
  export type DeploymentRef<D = Fqn, M = Fqn> = {
@@ -93,53 +119,216 @@ export namespace FqnExpr {
93
119
  return 'ref' in ref && FqnRef.isDeploymentRef(ref.ref)
94
120
  }
95
121
 
122
+ export type ElementKindExpr = {
123
+ elementKind: ElementKind
124
+ isEqual: boolean
125
+ }
126
+ export function isElementKindExpr(expr: ExpressionV2): expr is ElementKindExpr {
127
+ return 'elementKind' in expr && 'isEqual' in expr
128
+ }
129
+
130
+ export type ElementTagExpr = {
131
+ elementTag: Tag
132
+ isEqual: boolean
133
+ }
134
+ export function isElementTagExpr(expr: ExpressionV2): expr is ElementTagExpr {
135
+ return 'elementTag' in expr && 'isEqual' in expr
136
+ }
137
+
96
138
  export type NonWildcard<D = Fqn, M = Fqn> = ExclusiveUnion<{
97
139
  ModelRef: ModelRef<M>
98
140
  DeploymentRef: DeploymentRef<D, M>
141
+ ElementKind: ElementKindExpr
142
+ ElementTag: ElementTagExpr
143
+ }>
144
+
145
+ export type Where<D = Fqn, M = Fqn> = {
146
+ where: {
147
+ expr: ExclusiveUnion<{
148
+ Wildcard: Wildcard
149
+ ModelRef: ModelRef<M>
150
+ DeploymentRef: DeploymentRef<D, M>
151
+ ElementKind: ElementKindExpr
152
+ ElementTag: ElementTagExpr
153
+ }>
154
+ condition: WhereOperator<string, string>
155
+ }
156
+ }
157
+
158
+ export const isWhere = (expr: ExpressionV2): expr is FqnExpr.Where => {
159
+ return 'where' in expr && is(expr.where.expr)
160
+ }
161
+
162
+ export type Custom<D = Fqn, M = Fqn> = {
163
+ custom: {
164
+ expr: OrWhere<D, M>
165
+ title?: string
166
+ description?: string
167
+ technology?: string
168
+ notation?: string
169
+ shape?: ElementShape
170
+ color?: Color
171
+ icon?: IconUrl
172
+ border?: BorderStyle
173
+ opacity?: number
174
+ navigateTo?: ViewId
175
+ multiple?: boolean
176
+ size?: ShapeSize
177
+ padding?: ShapeSize
178
+ textSize?: ShapeSize
179
+ }
180
+ }
181
+
182
+ export const isCustom = (expr: ExpressionV2): expr is Custom => {
183
+ return 'custom' in expr && (is(expr.custom.expr) || isWhere(expr.custom.expr))
184
+ }
185
+
186
+ export const is = (expr: ExpressionV2): expr is FqnExpr => {
187
+ return isWildcard(expr)
188
+ || isModelRef(expr)
189
+ || isDeploymentRef(expr)
190
+ || isElementKindExpr(expr)
191
+ || isElementTagExpr(expr)
192
+ }
193
+
194
+ export type OrWhere<D = Fqn, M = Fqn> = ExclusiveUnion<{
195
+ Wildcard: FqnExpr.Wildcard
196
+ ModelRef: FqnExpr.ModelRef<M>
197
+ DeploymentRef: FqnExpr.DeploymentRef<D, M>
198
+ ElementKind: ElementKindExpr
199
+ ElementTag: ElementTagExpr
200
+ Where: FqnExpr.Where<D, M>
201
+ }>
202
+
203
+ export type Any<D = Fqn, M = Fqn> = ExclusiveUnion<{
204
+ Wildcard: Wildcard
205
+ ModelRef: ModelRef<M>
206
+ DeploymentRef: DeploymentRef<D, M>
207
+ ElementKind: ElementKindExpr
208
+ ElementTag: ElementTagExpr
209
+ Where: Where<D, M>
210
+ Custom: Custom<D, M>
99
211
  }>
212
+
213
+ export const unwrap = (expr: FqnExpr): Wildcard | ModelRef | DeploymentRef | ElementKindExpr | ElementTagExpr => {
214
+ if (isCustom(expr)) {
215
+ expr = expr.custom.expr
216
+ }
217
+ if (isWhere(expr)) {
218
+ expr = expr.where.expr
219
+ }
220
+ return expr
221
+ }
100
222
  }
101
223
 
102
224
  export type FqnExpr<D = Fqn, M = Fqn> = ExclusiveUnion<{
103
225
  Wildcard: FqnExpr.Wildcard
104
226
  ModelRef: FqnExpr.ModelRef<M>
105
227
  DeploymentRef: FqnExpr.DeploymentRef<D, M>
228
+ ElementKind: FqnExpr.ElementKindExpr
229
+ ElementTag: FqnExpr.ElementTagExpr
106
230
  }>
107
231
 
108
232
  export namespace RelationExpr {
233
+ export type Endpoint<D = Fqn, M = Fqn> = FqnExpr.Where<D, M>['where']['expr']
234
+
109
235
  export type Direct<D = Fqn, M = Fqn> = {
110
- source: FqnExpr<D, M>
111
- target: FqnExpr<D, M>
236
+ source: Endpoint<D, M>
237
+ target: Endpoint<D, M>
112
238
  isBidirectional?: boolean
113
239
  }
114
- export const isDirect = (expr: ExpressionV2): expr is Direct => {
240
+ export const isDirect = (expr: ExpressionV2): expr is RelationExpr.Direct => {
115
241
  return 'source' in expr && 'target' in expr
116
242
  }
117
243
  export type Incoming<D = Fqn, M = Fqn> = {
118
- incoming: FqnExpr<D, M>
244
+ incoming: Endpoint<D, M>
119
245
  }
120
- export const isIncoming = (expr: ExpressionV2): expr is Incoming => {
246
+ export const isIncoming = (expr: ExpressionV2): expr is RelationExpr.Incoming => {
121
247
  return 'incoming' in expr
122
248
  }
123
249
  export type Outgoing<D = Fqn, M = Fqn> = {
124
- outgoing: FqnExpr<D, M>
250
+ outgoing: Endpoint<D, M>
125
251
  }
126
- export const isOutgoing = (expr: ExpressionV2): expr is Outgoing => {
252
+ export const isOutgoing = (expr: ExpressionV2): expr is RelationExpr.Outgoing => {
127
253
  return 'outgoing' in expr
128
254
  }
129
255
  export type InOut<D = Fqn, M = Fqn> = {
130
- inout: FqnExpr<D, M>
256
+ inout: Endpoint<D, M>
131
257
  }
132
- export const isInOut = (expr: ExpressionV2): expr is InOut => {
258
+ export const isInOut = (expr: ExpressionV2): expr is RelationExpr.InOut => {
133
259
  return 'inout' in expr
134
260
  }
135
261
  export type Where<D = Fqn, M = Fqn> = {
136
262
  where: {
137
- expr: ExpressionV2<D, M>
263
+ expr: ExclusiveUnion<{
264
+ Direct: RelationExpr.Direct<D, M>
265
+ Incoming: RelationExpr.Incoming<D, M>
266
+ Outgoing: RelationExpr.Outgoing<D, M>
267
+ InOut: RelationExpr.InOut<D, M>
268
+ }>
138
269
  condition: WhereOperator<string, string>
139
270
  }
140
271
  }
141
- export const isWhere = (expr: ExpressionV2): expr is Where => {
142
- return 'where' in expr
272
+ export const isWhere = (expr: ExpressionV2): expr is RelationExpr.Where => {
273
+ return 'where' in expr &&
274
+ (isDirect(expr.where.expr) || isIncoming(expr.where.expr) || isOutgoing(expr.where.expr) ||
275
+ isInOut(expr.where.expr))
276
+ }
277
+
278
+ export type Custom<D = Fqn, M = Fqn> = {
279
+ customRelation: {
280
+ expr: OrWhere<D, M>
281
+ title?: string
282
+ description?: string
283
+ technology?: string
284
+ notation?: string
285
+ // Link to dynamic view
286
+ navigateTo?: ViewId
287
+ // Notes for walkthrough
288
+ notes?: string
289
+ color?: Color
290
+ line?: RelationshipLineType
291
+ head?: RelationshipArrowType
292
+ tail?: RelationshipArrowType
293
+ }
294
+ }
295
+
296
+ export const isCustom = (expr: ExpressionV2): expr is Custom => {
297
+ return 'customRelation' in expr
298
+ }
299
+
300
+ export const is = (expr: ExpressionV2): expr is RelationExpr => {
301
+ return isDirect(expr)
302
+ || isIncoming(expr)
303
+ || isOutgoing(expr)
304
+ || isInOut(expr)
305
+ }
306
+
307
+ export type OrWhere<D = Fqn, M = Fqn> = ExclusiveUnion<{
308
+ Direct: Direct<D, M>
309
+ Incoming: Incoming<D, M>
310
+ Outgoing: Outgoing<D, M>
311
+ InOut: InOut<D, M>
312
+ Where: Where<D, M>
313
+ }>
314
+
315
+ export type Any<D = Fqn, M = Fqn> = ExclusiveUnion<{
316
+ Direct: Direct<D, M>
317
+ Incoming: Incoming<D, M>
318
+ Outgoing: Outgoing<D, M>
319
+ InOut: InOut<D, M>
320
+ Where: Where<D, M>
321
+ Custom: Custom<D, M>
322
+ }>
323
+
324
+ export const unwrap = (expr: RelationExpr): Direct | Incoming | Outgoing | InOut => {
325
+ if (isCustom(expr)) {
326
+ expr = expr.customRelation.expr
327
+ }
328
+ if (isWhere(expr)) {
329
+ expr = expr.where.expr
330
+ }
331
+ return expr
143
332
  }
144
333
  }
145
334
 
@@ -148,7 +337,6 @@ export type RelationExpr<D = Fqn, M = Fqn> = ExclusiveUnion<{
148
337
  Incoming: RelationExpr.Incoming<D, M>
149
338
  Outgoing: RelationExpr.Outgoing<D, M>
150
339
  InOut: RelationExpr.InOut<D, M>
151
- Where: RelationExpr.Where<D, M>
152
340
  }>
153
341
 
154
342
  /**
@@ -161,24 +349,44 @@ export type ExpressionV2<D = Fqn, M = Fqn> = ExclusiveUnion<{
161
349
  Wildcard: FqnExpr.Wildcard
162
350
  ModelRef: FqnExpr.ModelRef<M>
163
351
  DeploymentRef: FqnExpr.DeploymentRef<D, M>
352
+ ElementKind: FqnExpr.ElementKindExpr
353
+ ElementTag: FqnExpr.ElementTagExpr
354
+ Custom: FqnExpr.Custom<D, M>
164
355
  Direct: RelationExpr.Direct<D, M>
165
356
  Incoming: RelationExpr.Incoming<D, M>
166
357
  Outgoing: RelationExpr.Outgoing<D, M>
167
358
  InOut: RelationExpr.InOut<D, M>
168
- RelationPredicateOrWhere: RelationExpr.Where<D, M>
359
+ Where: ExpressionV2.Where<D, M>
360
+ CustomRelation: RelationExpr.Custom<D, M>
169
361
  }>
170
362
 
171
363
  export namespace ExpressionV2 {
172
- export const isFqnExpr = (expr: ExpressionV2): expr is FqnExpr => {
173
- return FqnExpr.isWildcard(expr)
174
- || FqnExpr.isModelRef(expr)
175
- || FqnExpr.isDeploymentRef(expr)
364
+ export type Where<D = Fqn, M = Fqn> = FqnExpr.Where<D, M> | RelationExpr.Where<D, M>
365
+ // export type Where<D = Fqn, M = Fqn> = {
366
+ // where: ExclusiveUnion<{
367
+ // Fqn: FqnExpr.Where<D, M>['where']['expr']
368
+ // Relation: RelationExpr.Where<D, M>['where']['expr']
369
+ // }>
370
+ // condition: WhereOperator<string, string>
371
+ // }
372
+
373
+ export const isWhere = (expr: ExpressionV2): expr is ExpressionV2.Where => {
374
+ return 'where' in expr
375
+ }
376
+
377
+ export const isRelationWhere = (expr: ExpressionV2): expr is RelationExpr.Where => {
378
+ return RelationExpr.isWhere(expr)
379
+ }
380
+
381
+ export const isFqnExprWhere = (expr: ExpressionV2): expr is FqnExpr.Where => {
382
+ return FqnExpr.isWhere(expr)
383
+ }
384
+
385
+ export const isFqnExpr = (expr: ExpressionV2): expr is FqnExpr.Any => {
386
+ return FqnExpr.is(expr) || FqnExpr.isWhere(expr) || FqnExpr.isCustom(expr)
176
387
  }
177
388
 
178
- export const isRelation = (expr: ExpressionV2): expr is RelationExpr => {
179
- return RelationExpr.isDirect(expr)
180
- || RelationExpr.isIncoming(expr)
181
- || RelationExpr.isOutgoing(expr)
182
- || RelationExpr.isInOut(expr)
389
+ export const isRelation = (expr: ExpressionV2): expr is RelationExpr.Any => {
390
+ return RelationExpr.is(expr) || RelationExpr.isWhere(expr) || RelationExpr.isCustom(expr)
183
391
  }
184
392
  }