@likec4/core 1.18.0 → 1.19.1

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 (177) hide show
  1. package/LICENSE +1 -1
  2. package/dist/builder/index.d.mts +502 -0
  3. package/dist/builder/index.d.ts +502 -0
  4. package/dist/builder/index.js +871 -0
  5. package/dist/compute-view/index.d.mts +9 -78
  6. package/dist/compute-view/index.d.ts +9 -78
  7. package/dist/compute-view/index.js +78 -0
  8. package/dist/index.d.mts +9 -730
  9. package/dist/index.d.ts +9 -730
  10. package/dist/{index.mjs → index.js} +7 -784
  11. package/dist/model/index.d.mts +218 -606
  12. package/dist/model/index.d.ts +218 -606
  13. package/dist/model/index.js +1 -0
  14. package/dist/shared/chunk-RAAYCPUM.M-JWF7SS.js +21 -0
  15. package/dist/shared/core.BIfgabEw.d.ts +719 -0
  16. package/dist/shared/core.BZ9Msq7w.d.mts +719 -0
  17. package/dist/shared/{core.DMYY7C8s.d.mts → core.C05RDLhi.d.ts} +179 -230
  18. package/dist/shared/{core.DMYY7C8s.d.ts → core.CmYMqgha.d.mts} +179 -230
  19. package/dist/shared/core.D6-fWbM3.d.ts +127 -0
  20. package/dist/shared/core.D74xkKkG.d.mts +148 -0
  21. package/dist/shared/core.D74xkKkG.d.ts +148 -0
  22. package/dist/shared/core.sLaWHBjR.d.mts +127 -0
  23. package/dist/shared/index.DafVOuVd.js +7443 -0
  24. package/dist/shared/object_hash.CE_oF3I3.js +1222 -0
  25. package/dist/shared/view.CyZrG8BJ.js +354 -0
  26. package/dist/types/index.d.mts +4 -2
  27. package/dist/types/index.d.ts +4 -2
  28. package/dist/types/index.js +20 -0
  29. package/dist/utils/index.d.mts +419 -0
  30. package/dist/utils/index.d.ts +419 -0
  31. package/dist/utils/index.js +347 -0
  32. package/package.json +47 -33
  33. package/src/builder/Builder-style1.test-d.ts +190 -0
  34. package/src/builder/Builder-style2.test-d.ts +175 -0
  35. package/src/builder/Builder.deployment.ts +25 -20
  36. package/src/builder/Builder.deploymentModel.ts +80 -55
  37. package/src/builder/Builder.element.ts +2 -0
  38. package/src/builder/Builder.model.ts +57 -43
  39. package/src/builder/Builder.ts +412 -431
  40. package/src/builder/Builder.view-common.ts +234 -0
  41. package/src/builder/Builder.view-deployment.ts +135 -0
  42. package/src/builder/Builder.view-element.ts +189 -0
  43. package/src/builder/Builder.views.ts +109 -33
  44. package/src/builder/Builder.with.ts +475 -0
  45. package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +374 -0
  46. package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +183 -0
  47. package/src/builder/__snapshots__/Builder.spec.ts.snap +374 -0
  48. package/src/builder/_types.ts +28 -5
  49. package/src/builder/index.ts +10 -4
  50. package/src/colors/index.ts +2 -2
  51. package/src/compute-view/compute-view.ts +45 -54
  52. package/src/compute-view/deployment-view/__test__/TestHelper.ts +236 -0
  53. package/src/compute-view/deployment-view/__test__/fixture.ts +50 -62
  54. package/src/compute-view/deployment-view/_types.ts +26 -18
  55. package/src/compute-view/deployment-view/clean-connections.ts +173 -164
  56. package/src/compute-view/deployment-view/compute.ts +51 -37
  57. package/src/compute-view/deployment-view/memory/index.ts +9 -0
  58. package/src/compute-view/deployment-view/memory/memory.ts +97 -0
  59. package/src/compute-view/deployment-view/predicates/elements.ts +144 -0
  60. package/src/compute-view/deployment-view/predicates/relation-direct.ts +183 -76
  61. package/src/compute-view/deployment-view/predicates/relation-in-out.ts +38 -20
  62. package/src/compute-view/deployment-view/predicates/relation-incoming.ts +72 -23
  63. package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +61 -22
  64. package/src/compute-view/deployment-view/predicates/wildcard.ts +15 -15
  65. package/src/compute-view/deployment-view/stages/stage-exclude.ts +5 -0
  66. package/src/compute-view/deployment-view/stages/stage-final.ts +245 -0
  67. package/src/compute-view/deployment-view/stages/stage-include.ts +95 -0
  68. package/src/compute-view/deployment-view/utils.ts +95 -31
  69. package/src/compute-view/dynamic-view/__test__/fixture.ts +4 -4
  70. package/src/compute-view/dynamic-view/compute.ts +59 -45
  71. package/src/compute-view/element-view/__test__/TestHelper.ts +258 -0
  72. package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +64 -62
  73. package/src/compute-view/element-view/__test__/fixture.ts +147 -117
  74. package/src/compute-view/element-view/_types.ts +48 -0
  75. package/src/compute-view/element-view/clean-connections.ts +113 -0
  76. package/src/compute-view/element-view/compute.ts +264 -683
  77. package/src/compute-view/element-view/memory/NodeGroup.ts +31 -0
  78. package/src/compute-view/element-view/memory/index.ts +10 -0
  79. package/src/compute-view/element-view/memory/memory.ts +177 -0
  80. package/src/compute-view/element-view/memory/stage-exclude.ts +59 -0
  81. package/src/compute-view/element-view/memory/stage-final.ts +129 -0
  82. package/src/compute-view/element-view/memory/stage-include.ts +128 -0
  83. package/src/compute-view/element-view/predicates/_utils.ts +86 -0
  84. package/src/compute-view/element-view/predicates/element-expand.ts +33 -0
  85. package/src/compute-view/element-view/predicates/element-kind-tag.ts +26 -0
  86. package/src/compute-view/element-view/predicates/element-ref.ts +37 -0
  87. package/src/compute-view/element-view/predicates/relation-direct.ts +309 -0
  88. package/src/compute-view/element-view/predicates/relation-in-out.ts +66 -0
  89. package/src/compute-view/element-view/predicates/relation-in.ts +118 -0
  90. package/src/compute-view/element-view/predicates/relation-out.ts +116 -0
  91. package/src/compute-view/element-view/predicates/wildcard.ts +88 -0
  92. package/src/compute-view/element-view/utils.ts +59 -0
  93. package/src/compute-view/index.ts +3 -4
  94. package/src/compute-view/memory/AbstractMemory.ts +45 -0
  95. package/src/compute-view/memory/AbstractStageExclude.ts +216 -0
  96. package/src/compute-view/memory/AbstractStageInclude.ts +200 -0
  97. package/src/compute-view/memory/_types.ts +147 -0
  98. package/src/compute-view/memory/index.ts +5 -0
  99. package/src/compute-view/memory/ops.ts +43 -0
  100. package/src/compute-view/utils/buildComputedNodes.ts +4 -4
  101. package/src/compute-view/utils/elementExpressionToPredicate.ts +1 -3
  102. package/src/compute-view/utils/link-nodes-with-edges.ts +3 -7
  103. package/src/compute-view/utils/{derive-edge-props-from-relationships.ts → merge-props-from-relationships.ts} +54 -23
  104. package/src/compute-view/utils/relationExpressionToPredicates.ts +2 -2
  105. package/src/compute-view/utils/resolve-extended-views.ts +44 -40
  106. package/src/compute-view/utils/resolve-global-rules.ts +6 -6
  107. package/src/compute-view/utils/topological-sort.ts +167 -71
  108. package/src/compute-view/utils/with-readable-edges.ts +14 -9
  109. package/src/index.ts +22 -16
  110. package/src/model/DeploymentElementModel.ts +150 -85
  111. package/src/model/DeploymentModel.ts +27 -21
  112. package/src/model/ElementModel.ts +51 -25
  113. package/src/model/LikeC4Model.test-d.ts +4 -3
  114. package/src/model/LikeC4Model.ts +98 -42
  115. package/src/model/RelationModel.ts +5 -4
  116. package/src/model/__test__/fixture.ts +5 -9
  117. package/src/model/connection/Connection.ts +72 -0
  118. package/src/model/connection/deployment/DeploymentConnectionModel.ts +178 -0
  119. package/src/model/connection/{deployment.ts → deployment/find.ts} +14 -18
  120. package/src/model/connection/deployment/index.ts +8 -0
  121. package/src/model/connection/index.ts +22 -0
  122. package/src/model/connection/model/ConnectionModel.ts +157 -0
  123. package/src/model/connection/{model.ts → model/find.ts} +43 -49
  124. package/src/model/connection/model/index.ts +8 -0
  125. package/src/model/connection/ops.ts +274 -0
  126. package/src/model/guards.ts +9 -0
  127. package/src/model/index.ts +45 -3
  128. package/src/model/types.ts +35 -18
  129. package/src/model/view/EdgeModel.ts +6 -6
  130. package/src/model/view/LikeC4ViewModel.ts +14 -8
  131. package/src/model/view/NodeModel.ts +6 -5
  132. package/src/types/_common.ts +53 -1
  133. package/src/types/deployments.ts +88 -156
  134. package/src/types/element.ts +2 -2
  135. package/src/types/expression-v2.ts +172 -0
  136. package/src/types/expression.ts +9 -5
  137. package/src/types/global.ts +3 -3
  138. package/src/types/index.ts +220 -13
  139. package/src/types/model.ts +28 -24
  140. package/src/types/operators.ts +1 -1
  141. package/src/types/relation.ts +14 -10
  142. package/src/types/theme.ts +0 -1
  143. package/src/types/view.ts +20 -18
  144. package/src/utils/const.ts +1 -0
  145. package/src/utils/fqn.ts +140 -49
  146. package/src/utils/getOrCreate.ts +1 -1
  147. package/src/utils/index.ts +75 -9
  148. package/src/utils/iterable/_types.ts +5 -0
  149. package/src/utils/iterable/filter.ts +55 -0
  150. package/src/utils/iterable/find.ts +36 -0
  151. package/src/utils/iterable/flat.ts +17 -0
  152. package/src/utils/iterable/index.ts +13 -0
  153. package/src/utils/iterable/map.ts +40 -0
  154. package/src/utils/iterable/reduce.ts +24 -0
  155. package/src/utils/iterable/some.ts +36 -0
  156. package/src/utils/iterable/to.ts +19 -0
  157. package/src/utils/iterable/unique.ts +29 -0
  158. package/src/utils/relations.ts +3 -64
  159. package/src/utils/set.ts +11 -9
  160. package/src/utils/string-hash.ts +1 -1
  161. package/dist/compute-view/index.mjs +0 -79
  162. package/dist/model/index.mjs +0 -2
  163. package/dist/shared/core.BBgiAAv1.mjs +0 -144
  164. package/dist/shared/core.BPyJvuMU.mjs +0 -2420
  165. package/dist/shared/core.BQ4AbfvB.mjs +0 -9228
  166. package/dist/shared/core.k12s_keD.mjs +0 -203
  167. package/dist/types/index.mjs +0 -21
  168. package/src/builder/Builder.test-d.ts +0 -124
  169. package/src/builder/Builder.view.ts +0 -543
  170. package/src/compute-view/LikeC4ModelGraph.ts +0 -330
  171. package/src/compute-view/deployment-view/Memory.ts +0 -108
  172. package/src/compute-view/deployment-view/Stage.ts +0 -145
  173. package/src/compute-view/deployment-view/predicates/deployment-ref.ts +0 -146
  174. package/src/compute-view/element-view/predicates.ts +0 -517
  175. package/src/compute-view/utils/sortNodes.ts +0 -101
  176. package/src/model/connection/ConnectionModel.ts +0 -94
  177. package/src/model/connection/DeploymentConnectionModel.ts +0 -99
@@ -0,0 +1,234 @@
1
+ import { isArray, isString, map } from 'remeda'
2
+ import type { LiteralUnion, Simplify } from 'type-fest'
3
+ import {
4
+ type AutoLayoutDirection,
5
+ type CustomElementExpr,
6
+ type CustomRelationExpr,
7
+ type ElementExpression as C4ElementExpression,
8
+ type Expression as C4Expression,
9
+ isElementPredicateExpr,
10
+ type NonEmptyArray,
11
+ type ViewRuleStyle,
12
+ type WhereOperator,
13
+ } from '../types'
14
+ import type { AnyTypes, Types } from './_types'
15
+
16
+ export interface LikeC4ViewBuilder<
17
+ Types extends AnyTypes,
18
+ Fqn extends string,
19
+ TypedExpr,
20
+ ElementExpr extends string = ViewPredicate.ElementExpr<Fqn>,
21
+ Expr extends string = ViewPredicate.AllExpression<ElementExpr>,
22
+ > {
23
+ Types: Types
24
+ ElementExpr: ElementExpr
25
+ Expr: Expr
26
+ TypedExpr: TypedExpr
27
+ $expr(expr: Expr | TypedExpr): TypedExpr
28
+ include(...exprs: Expr[]): this
29
+ exclude(...exprs: Expr[]): this
30
+ style(rule: ViewRuleStyle): this
31
+ autoLayout(layout: AutoLayoutDirection): this
32
+ }
33
+
34
+ export namespace ViewPredicate {
35
+ export type ElementExpr<Fqn extends string> = '*' | Fqn | `${Fqn}.*` | `${Fqn}._` | `${Fqn}.**`
36
+
37
+ export type AllExpression<ElementExpr extends string> =
38
+ | ElementExpr
39
+ | `-> ${ElementExpr} ->`
40
+ | `-> ${ElementExpr}`
41
+ | `${ElementExpr} ->`
42
+ | `${ElementExpr} ${'->' | '<->'} ${ElementExpr}`
43
+
44
+ export type Expression<T extends AnyTypes> = T extends
45
+ Types<any, infer F extends string, any, any, any, any, any, any> ? AllExpression<ViewPredicate.ElementExpr<F>>
46
+ : never
47
+
48
+ export type ConnectionExpression<T extends AnyTypes> = T extends
49
+ Types<any, infer F extends string, any, any, any, any, any, any> ? `${F} -> ${F}`
50
+ : never
51
+
52
+ export type DeploymentExpression<T extends AnyTypes> = T extends
53
+ Types<any, any, any, any, any, any, any, infer F extends string> ? AllExpression<ViewPredicate.ElementExpr<F>>
54
+ : never
55
+
56
+ export type DeploymentConnectionExpression<T extends AnyTypes> = T extends
57
+ Types<any, any, any, any, any, any, any, infer F extends string> ? `${F} -> ${F}`
58
+ : never
59
+
60
+ export type WhereTag<Tag extends string> = `tag ${'is' | 'is not'} #${Tag}`
61
+ export type WhereKind<Kind extends string> = `kind ${'is' | 'is not'} ${Kind}`
62
+
63
+ export type WhereEq<Types extends AnyTypes> =
64
+ | ViewPredicate.WhereTag<Types['Tag']>
65
+ | ViewPredicate.WhereKind<Types['ElementKind']>
66
+
67
+ export type WhereOperator<Types extends AnyTypes> = ViewPredicate.WhereEq<Types> | {
68
+ and: NonEmptyArray<ViewPredicate.WhereOperator<Types>>
69
+ or?: never
70
+ not?: never
71
+ } | {
72
+ or: NonEmptyArray<ViewPredicate.WhereOperator<Types>>
73
+ and?: never
74
+ not?: never
75
+ } | {
76
+ not: ViewPredicate.WhereOperator<Types>
77
+ and?: never
78
+ or?: never
79
+ }
80
+
81
+ export type Custom<Types extends AnyTypes> = {
82
+ where?: ViewPredicate.WhereOperator<Types>
83
+ with?: Simplify<
84
+ Omit<CustomElementExpr['custom'] & CustomRelationExpr['customRelation'], 'expr' | 'relation' | 'navigateTo'> & {
85
+ navigateTo?: Types['ViewId']
86
+ }
87
+ >
88
+ }
89
+ }
90
+
91
+ function parseWhere(where: ViewPredicate.WhereOperator<AnyTypes>): WhereOperator<any, any> {
92
+ if (isString(where)) {
93
+ const op = where as LiteralUnion<ViewPredicate.WhereEq<AnyTypes>, string>
94
+ switch (true) {
95
+ case op.startsWith('tag is not #'):
96
+ return {
97
+ tag: {
98
+ neq: op.replace('tag is not #', ''),
99
+ },
100
+ }
101
+ case op.startsWith('tag is #'):
102
+ return {
103
+ tag: {
104
+ eq: op.replace('tag is #', ''),
105
+ },
106
+ }
107
+ case op.startsWith('kind is not '):
108
+ return {
109
+ kind: {
110
+ neq: op.replace('kind is not ', ''),
111
+ },
112
+ }
113
+ case op.startsWith('kind is '):
114
+ return {
115
+ kind: {
116
+ eq: op.replace('kind is ', ''),
117
+ },
118
+ }
119
+ default:
120
+ throw new Error(`Unknown where operator: ${where}`)
121
+ }
122
+ }
123
+
124
+ if (where.and) {
125
+ return {
126
+ and: map(where.and, parseWhere),
127
+ }
128
+ }
129
+ if (where.or) {
130
+ return {
131
+ or: map(where.or, parseWhere),
132
+ }
133
+ }
134
+ if (where.not) {
135
+ return {
136
+ not: parseWhere(where.not),
137
+ }
138
+ }
139
+
140
+ throw new Error(`Unknown where operator: ${where}`)
141
+ }
142
+
143
+ function $include<B extends LikeC4ViewBuilder<AnyTypes, any, any>>(
144
+ ...args:
145
+ | [B['Expr']]
146
+ | [B['TypedExpr']]
147
+ | [B['Expr'], ViewPredicate.Custom<B['Types']>]
148
+ ): (b: B) => B {
149
+ return (b) => {
150
+ let expr = b.$expr(args[0])
151
+ if (args.length === 2) {
152
+ const condition = args[1].where ? parseWhere(args[1].where) : undefined
153
+ if (condition) {
154
+ expr = {
155
+ where: {
156
+ expr: expr as any,
157
+ condition,
158
+ },
159
+ }
160
+ }
161
+
162
+ const custom = args[1].with
163
+ if (custom) {
164
+ const isElement = isElementPredicateExpr(expr)
165
+ if (isElement) {
166
+ expr = {
167
+ custom: {
168
+ ...custom,
169
+ expr: expr as any,
170
+ },
171
+ }
172
+ } else {
173
+ expr = {
174
+ customRelation: {
175
+ ...custom,
176
+ relation: expr as any,
177
+ },
178
+ }
179
+ }
180
+ }
181
+ }
182
+ b.include(expr as any)
183
+ return b
184
+ }
185
+ }
186
+
187
+ function $exclude<B extends LikeC4ViewBuilder<AnyTypes, any, any>>(
188
+ ...args:
189
+ | [B['Expr']]
190
+ | [B['TypedExpr']]
191
+ | [B['Expr'], ViewPredicate.Custom<B['Types']>]
192
+ ): (b: B) => B {
193
+ return (b) => {
194
+ let expr = b.$expr(args[0]) as C4Expression
195
+ if (args.length === 2 && args[1].where) {
196
+ const condition = parseWhere(args[1].where)
197
+ expr = {
198
+ where: {
199
+ expr: expr as any,
200
+ condition,
201
+ },
202
+ }
203
+ }
204
+ b.exclude(expr)
205
+ return b
206
+ }
207
+ }
208
+
209
+ function $style<B extends LikeC4ViewBuilder<AnyTypes, any, any>>(
210
+ element: B['ElementExpr'] | B['TypedExpr'] | NonEmptyArray<B['ElementExpr']>,
211
+ { notation, ...style }: ViewRuleStyle['style'] & { notation?: string },
212
+ ): (b: B) => B {
213
+ return (b) =>
214
+ b.style({
215
+ targets: (isArray(element) ? element : [element]).map(e => b.$expr(e as any) as C4ElementExpression),
216
+ ...(notation ? { notation } : {}),
217
+ style: {
218
+ ...style,
219
+ },
220
+ })
221
+ }
222
+
223
+ function $autoLayout<B extends LikeC4ViewBuilder<AnyTypes, any, any>>(
224
+ layout: AutoLayoutDirection,
225
+ ): (b: B) => B {
226
+ return (b) => b.autoLayout(layout)
227
+ }
228
+
229
+ type Op<T> = (b: T) => T
230
+ function $rules<B extends LikeC4ViewBuilder<AnyTypes, any, any>>(...rules: Op<B>[]): (b: B) => B {
231
+ return (b) => rules.reduce((b, rule) => rule(b), b)
232
+ }
233
+
234
+ export { $autoLayout, $exclude, $include, $rules, $style }
@@ -0,0 +1,135 @@
1
+ import { isString } from 'remeda'
2
+ import { type ExpressionV2, type Fqn } from '../types'
3
+ import type { AnyTypes, Types } from './_types'
4
+ import type { LikeC4ViewBuilder, ViewPredicate } from './Builder.view-common'
5
+ import type { ViewsBuilder } from './Builder.views'
6
+
7
+ export interface DeploymentViewBuilder<T extends AnyTypes>
8
+ extends LikeC4ViewBuilder<T, T['DeploymentFqn'], Types.ToExpression<T>>
9
+ {
10
+ }
11
+
12
+ export type DeploymentRulesBuilderOp<Types extends AnyTypes> = (
13
+ b: DeploymentViewBuilder<Types>
14
+ ) => DeploymentViewBuilder<Types>
15
+
16
+ export interface AddDeploymentViewRules<Id extends string> {
17
+ with<S extends AnyTypes>(
18
+ ...rules: DeploymentRulesBuilderOp<S>[]
19
+ ): (builder: ViewsBuilder<S>) => ViewsBuilder<Types.AddView<S, Id>>
20
+ }
21
+
22
+ /**
23
+ * Chainable builder to create element
24
+ */
25
+ export interface AddDeploymentViewHelper {
26
+ <
27
+ const Id extends string,
28
+ T extends AnyTypes
29
+ >(
30
+ id: Id
31
+ ): AddDeploymentViewRules<Id> & {
32
+ (builder: ViewsBuilder<T>): ViewsBuilder<Types.AddView<T, Id>>
33
+ }
34
+
35
+ <
36
+ const Id extends string,
37
+ T extends AnyTypes
38
+ >(
39
+ id: Id,
40
+ bulder: (b: DeploymentViewBuilder<T>) => DeploymentViewBuilder<T>
41
+ ): (builder: ViewsBuilder<T>) => ViewsBuilder<Types.AddView<T, Id>>
42
+
43
+ <
44
+ const Id extends string,
45
+ T extends AnyTypes
46
+ >(
47
+ id: Id,
48
+ propsOrTitle: T['NewViewProps'] | string
49
+ ): AddDeploymentViewRules<Id> & {
50
+ (builder: ViewsBuilder<T>): ViewsBuilder<Types.AddView<T, Id>>
51
+ }
52
+
53
+ <
54
+ const Id extends string,
55
+ T extends AnyTypes
56
+ >(
57
+ id: Id,
58
+ propsOrTitle: T['NewViewProps'] | string,
59
+ bulder: (b: DeploymentViewBuilder<T>) => DeploymentViewBuilder<T>
60
+ ): (builder: ViewsBuilder<T>) => ViewsBuilder<Types.AddView<T, Id>>
61
+ }
62
+
63
+ export function $deploymentExpr<T extends AnyTypes>(
64
+ expr: ViewPredicate.DeploymentExpression<T> | ExpressionV2
65
+ ): Types.ToExpression<T> {
66
+ if (!isString(expr)) {
67
+ return expr as any
68
+ }
69
+ const asTypedDeploymentExpression = (expr: ExpressionV2): Types.ToExpression<T> => {
70
+ return expr as any
71
+ }
72
+
73
+ if (expr === '*') {
74
+ return asTypedDeploymentExpression({ wildcard: true })
75
+ }
76
+ if (expr.startsWith('->')) {
77
+ if (expr.endsWith('->')) {
78
+ return asTypedDeploymentExpression({
79
+ inout: $deploymentExpr(expr.replace(/->/g, '').trim()) as any
80
+ })
81
+ }
82
+ return asTypedDeploymentExpression({
83
+ incoming: $deploymentExpr(expr.replace('-> ', '')) as any
84
+ })
85
+ }
86
+ if (expr.endsWith(' ->')) {
87
+ return asTypedDeploymentExpression({
88
+ outgoing: $deploymentExpr(expr.replace(' ->', '')) as any
89
+ })
90
+ }
91
+ if (expr.includes(' <-> ')) {
92
+ const [source, target] = expr.split(' <-> ')
93
+ return asTypedDeploymentExpression({
94
+ source: $deploymentExpr(source) as any,
95
+ target: $deploymentExpr(target) as any,
96
+ isBidirectional: true
97
+ })
98
+ }
99
+ if (expr.includes(' -> ')) {
100
+ const [source, target] = expr.split(' -> ')
101
+ return asTypedDeploymentExpression({
102
+ source: $deploymentExpr(source) as any,
103
+ target: $deploymentExpr(target) as any
104
+ })
105
+ }
106
+ if (expr.endsWith('._')) {
107
+ return asTypedDeploymentExpression({
108
+ ref: {
109
+ deployment: expr.replace('._', '') as Fqn
110
+ },
111
+ selector: 'expanded'
112
+ })
113
+ }
114
+ if (expr.endsWith('.**')) {
115
+ return asTypedDeploymentExpression({
116
+ ref: {
117
+ deployment: expr.replace('.**', '') as Fqn
118
+ },
119
+ selector: 'descendants'
120
+ })
121
+ }
122
+ if (expr.endsWith('.*')) {
123
+ return asTypedDeploymentExpression({
124
+ ref: {
125
+ deployment: expr.replace('.*', '') as Fqn
126
+ },
127
+ selector: 'children'
128
+ })
129
+ }
130
+ return asTypedDeploymentExpression({
131
+ ref: {
132
+ deployment: expr as any as Fqn
133
+ }
134
+ })
135
+ }
@@ -0,0 +1,189 @@
1
+ import { isString } from 'remeda'
2
+ import type { IsStringLiteral } from 'type-fest/source/is-literal'
3
+ import { type Expression as C4Expression, type Fqn } from '../types'
4
+ import type { AnyTypes, Invalid, Types } from './_types'
5
+ import type { LikeC4ViewBuilder, ViewPredicate } from './Builder.view-common'
6
+ import type { ViewsBuilder } from './Builder.views'
7
+
8
+ export interface ElementViewBuilder<T extends AnyTypes> extends LikeC4ViewBuilder<T, T['Fqn'], C4Expression> {
9
+ }
10
+
11
+ export type ElementViewRulesBuilder<T extends AnyTypes> = (b: ElementViewBuilder<T>) => ElementViewBuilder<T>
12
+
13
+ export interface AddViewRules<Id extends string> {
14
+ with<S extends AnyTypes>(
15
+ ...rules: ElementViewRulesBuilder<S>[]
16
+ ): (builder: ViewsBuilder<S>) => ViewsBuilder<Types.AddView<S, Id>>
17
+ }
18
+
19
+ export interface AddViewHelper {
20
+ <
21
+ const Id extends string,
22
+ T extends AnyTypes,
23
+ >(
24
+ id: Id,
25
+ ): AddViewRules<Id> & {
26
+ (builder: ViewsBuilder<T>): ViewsBuilder<Types.AddView<T, Id>>
27
+ }
28
+
29
+ <
30
+ const Id extends string,
31
+ T extends AnyTypes,
32
+ >(
33
+ id: Id,
34
+ builder: (b: ElementViewBuilder<T>) => ElementViewBuilder<T>,
35
+ ): AddViewRules<Id> & {
36
+ (builder: ViewsBuilder<T>): ViewsBuilder<Types.AddView<T, Id>>
37
+ }
38
+
39
+ <
40
+ const Id extends string,
41
+ T extends AnyTypes,
42
+ >(
43
+ id: Id,
44
+ propsOrTitle: NoInfer<T['NewViewProps']> | string,
45
+ ): AddViewRules<Id> & {
46
+ (builder: ViewsBuilder<T>): ViewsBuilder<Types.AddView<T, Id>>
47
+ }
48
+
49
+ <
50
+ const Id extends string,
51
+ T extends AnyTypes,
52
+ >(
53
+ id: Id,
54
+ propsOrTitle: NoInfer<T['NewViewProps']> | string | undefined,
55
+ builder: (b: ElementViewBuilder<T>) => ElementViewBuilder<T>,
56
+ ): AddViewRules<Id> & {
57
+ (builder: ViewsBuilder<T>): ViewsBuilder<Types.AddView<T, Id>>
58
+ }
59
+ }
60
+
61
+ type ValidFqn<T extends AnyTypes> = IsStringLiteral<T['Fqn']> extends true ? T['Fqn']
62
+ : Invalid<'Fqn must be from known'>
63
+
64
+ export interface AddViewOfHelper {
65
+ <
66
+ const Id extends string,
67
+ T extends AnyTypes,
68
+ >(
69
+ id: Id,
70
+ of: ValidFqn<T>,
71
+ ): (builder: ViewsBuilder<T>) => ViewsBuilder<Types.AddView<T, Id>>
72
+
73
+ <
74
+ const Id extends string,
75
+ T extends AnyTypes,
76
+ >(
77
+ id: Id,
78
+ of: ValidFqn<T>,
79
+ propsOrTitle: T['NewViewProps'] | string | ElementViewRulesBuilder<T>,
80
+ ): (builder: ViewsBuilder<T>) => ViewsBuilder<Types.AddView<T, Id>>
81
+
82
+ <
83
+ const Id extends string,
84
+ T extends AnyTypes,
85
+ >(
86
+ id: Id,
87
+ of: ValidFqn<T>,
88
+ propsOrTitle: NoInfer<T>['NewViewProps'] | string,
89
+ builder: (b: ElementViewBuilder<T>) => ElementViewBuilder<T>,
90
+ ): (builder: ViewsBuilder<T>) => ViewsBuilder<Types.AddView<T, Id>>
91
+ }
92
+
93
+ export interface TypedAddViewOfHelper<A extends AnyTypes> {
94
+ <
95
+ const Id extends string,
96
+ T extends AnyTypes,
97
+ >(
98
+ id: Id,
99
+ of: ValidFqn<A>,
100
+ ): AddViewRules<Id> & {
101
+ (builder: ViewsBuilder<T>): ViewsBuilder<Types.AddView<T, Id>>
102
+ }
103
+
104
+ <
105
+ const Id extends string,
106
+ T extends AnyTypes,
107
+ >(
108
+ id: Id,
109
+ of: ValidFqn<A>,
110
+ builder: ((b: ElementViewBuilder<A>) => ElementViewBuilder<A>) | A['NewViewProps'] | string,
111
+ ): AddViewRules<Id> & {
112
+ (builder: ViewsBuilder<T>): ViewsBuilder<Types.AddView<T, Id>>
113
+ }
114
+
115
+ <
116
+ const Id extends string,
117
+ T extends AnyTypes,
118
+ >(
119
+ id: Id,
120
+ of: ValidFqn<A>,
121
+ propsOrTitle: A['NewViewProps'] | string,
122
+ builder: (b: ElementViewBuilder<A>) => ElementViewBuilder<A>,
123
+ ): AddViewRules<Id> & {
124
+ (builder: ViewsBuilder<T>): ViewsBuilder<Types.AddView<T, Id>>
125
+ }
126
+ }
127
+ // To hook types
128
+ const asTypedExpr = (expr: C4Expression): C4Expression => {
129
+ return expr as C4Expression
130
+ }
131
+
132
+ export function $expr<Types extends AnyTypes>(expr: ViewPredicate.Expression<Types> | C4Expression): C4Expression {
133
+ if (!isString(expr)) {
134
+ return expr as C4Expression
135
+ }
136
+ if (expr === '*') {
137
+ return asTypedExpr({ wildcard: true })
138
+ }
139
+ if (expr.startsWith('->')) {
140
+ if (expr.endsWith('->')) {
141
+ return asTypedExpr({
142
+ inout: $expr(expr.replace(/->/g, '').trim()) as any,
143
+ })
144
+ }
145
+ return asTypedExpr({
146
+ incoming: $expr(expr.replace('-> ', '')) as any,
147
+ })
148
+ }
149
+ if (expr.endsWith(' ->')) {
150
+ return asTypedExpr({
151
+ outgoing: $expr(expr.replace(' ->', '')) as any,
152
+ })
153
+ }
154
+ if (expr.includes(' <-> ')) {
155
+ const [source, target] = expr.split(' <-> ')
156
+ return asTypedExpr({
157
+ source: $expr(source) as any,
158
+ target: $expr(target) as any,
159
+ isBidirectional: true,
160
+ })
161
+ }
162
+ if (expr.includes(' -> ')) {
163
+ const [source, target] = expr.split(' -> ')
164
+ return asTypedExpr({
165
+ source: $expr(source) as any,
166
+ target: $expr(target) as any,
167
+ })
168
+ }
169
+ if (expr.endsWith('._')) {
170
+ return asTypedExpr({
171
+ expanded: expr.replace('._', '') as Fqn,
172
+ })
173
+ }
174
+ if (expr.endsWith('.*')) {
175
+ return asTypedExpr({
176
+ element: expr.replace('.*', '') as Fqn,
177
+ isChildren: true,
178
+ })
179
+ }
180
+ if (expr.endsWith('.**')) {
181
+ return asTypedExpr({
182
+ element: expr.replace('.**', '') as Fqn,
183
+ isDescendants: true,
184
+ })
185
+ }
186
+ return asTypedExpr({
187
+ element: expr as any as Fqn,
188
+ })
189
+ }