@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
@@ -1,7 +1,6 @@
1
1
  import defu from 'defu'
2
- import { fromEntries, hasAtLeast, isFunction, isNonNullish, map, mapToObj, mapValues, pickBy } from 'remeda'
2
+ import { fromEntries, hasAtLeast, isFunction, isNonNullish, isNullish, map, mapToObj, mapValues, pickBy } from 'remeda'
3
3
  import type { Writable } from 'type-fest'
4
- import { computeViews } from '../compute-view'
5
4
  import { invariant } from '../errors'
6
5
  import { LikeC4Model } from '../model/LikeC4Model'
7
6
  import {
@@ -20,32 +19,29 @@ import {
20
19
  type LikeC4View,
21
20
  type Link,
22
21
  type ModelGlobals,
22
+ type ModelRelation,
23
23
  type NonEmptyArray,
24
- type Relation,
25
24
  type RelationId,
26
- type Tag
25
+ type Tag,
27
26
  } from '../types'
28
- import type { ParsedLikeC4Model } from '../types/model'
29
27
  import { isSameHierarchy, nameFromFqn, parentFqn } from '../utils/fqn'
30
28
  import type { AnyTypes, BuilderSpecification, Types } from './_types'
31
29
  import type { AddDeploymentNode } from './Builder.deployment'
32
- import type { AddDeploymentNodeHelpers, DeloymentModelHelpers, DeploymentModelBuilder } from './Builder.deploymentModel'
30
+ import type {
31
+ AddDeploymentNodeHelpers,
32
+ DeloymentModelBuildFunction,
33
+ DeloymentModelHelpers,
34
+ DeploymentModelBuilder,
35
+ } from './Builder.deploymentModel'
33
36
  import type { AddElement } from './Builder.element'
34
- import type { AddElementHelpers, ModelBuilder, ModelHelpers } from './Builder.model'
35
- import {
36
- $autoLayout,
37
- $exclude,
38
- $include,
39
- $rules,
40
- $style,
41
- type DeploymentViewRuleBuilderOp,
42
- mkViewBuilder,
43
- type ViewHelpers,
44
- type ViewRuleBuilderOp
45
- } from './Builder.view'
46
- import { type ViewsBuilder } from './Builder.views'
47
-
48
- export interface Builder<T extends AnyTypes> {
37
+ import type { AddElementHelpers, ModelBuilder, ModelBuilderFunction, ModelHelpers } from './Builder.model'
38
+ import { $autoLayout, $exclude, $include, $rules, $style } from './Builder.view-common'
39
+ import type { DeploymentRulesBuilderOp } from './Builder.view-deployment'
40
+ import type { ElementViewRulesBuilder } from './Builder.view-element'
41
+ import { mkViewBuilder, type ViewsBuilder, type ViewsBuilderFunction, type ViewsHelpers } from './Builder.views'
42
+ import type { BuilderMethods } from './Builder.with'
43
+
44
+ export interface Builder<T extends AnyTypes> extends BuilderMethods<T> {
49
45
  /**
50
46
  * Only available in compile time
51
47
  */
@@ -58,211 +54,120 @@ export interface Builder<T extends AnyTypes> {
58
54
  */
59
55
  helpers(): {
60
56
  model: ModelHelpers<T>
61
- views: ViewHelpers<T['NewViewProps']>
57
+ views: ViewsHelpers
62
58
  deployment: DeloymentModelHelpers<T>
63
59
  }
64
60
 
65
- __model(): ModelBuilder<T>
66
- __views(): ViewsBuilder<T>
67
- __deployment(): DeploymentModelBuilder<T>
61
+ /**
62
+ * Adds model elements
63
+ *
64
+ * @example
65
+ * builder.model(({ el }, _) =>
66
+ * _(
67
+ * el('a'),
68
+ * el('a.b').with(
69
+ * el('c')
70
+ * )
71
+ * )
72
+ * )
73
+ *
74
+ * builder.model((_, m) =>
75
+ * m(
76
+ * _.el('a'),
77
+ * _.el('a.b').with(
78
+ * _.el('c')
79
+ * )
80
+ * )
81
+ * )
82
+ */
83
+ model<Out extends AnyTypes>(
84
+ callback: ModelBuilderFunction<T, Out>,
85
+ ): Builder<Out>
86
+
87
+ /**
88
+ * Adds deployment model
89
+ *
90
+ * @example
91
+ * builder.deployment(({ node, instanceOf }, _) =>
92
+ * _(
93
+ * node('node1'),
94
+ * node('node1.child1').with(
95
+ * instanceOf('model.element')
96
+ * )
97
+ * )
98
+ * )
99
+ *
100
+ * builder.deployment((_,d) =>
101
+ * d(
102
+ * _.node('node1'),
103
+ * _.node('node1.child1').with(
104
+ * _.instanceOf('model.element')
105
+ * )
106
+ * )
107
+ * )
108
+ */
109
+ deployment<Out extends AnyTypes>(
110
+ callback: DeloymentModelBuildFunction<T, Out>,
111
+ ): Builder<Out>
112
+
113
+ /**
114
+ * Adds views
115
+ *
116
+ * @example
117
+ * builder.views(({ view, $include }, _) =>
118
+ * _(
119
+ * view('index').with(
120
+ * $include('a -> b')
121
+ * )
122
+ * )
123
+ * )
124
+ */
125
+ views<Out extends AnyTypes>(
126
+ callback: ViewsBuilderFunction<T, Out>,
127
+ ): Builder<Out>
68
128
 
69
129
  /**
70
130
  * Returns model as result of parsing only
71
- * Model is not computed or layouted
131
+ * Views are not computed or layouted
132
+ * {@link toLikeC4Model} should be used to get model with computed views
72
133
  */
73
- build(): ParsedLikeC4Model<
74
- T['ElementKind'],
75
- T['RelationshipKind'],
76
- T['Tag'],
77
- T['Fqn'],
78
- T['ViewId'],
79
- T['DeploymentFqn']
80
- >
134
+ build(): Types.ToParsedLikeC4Model<T>
81
135
 
82
136
  /**
83
- * Returns model with computed views
137
+ * Returns LikeC4Model with computed views
84
138
  */
85
- buildComputedModel(): LikeC4Model.Computed<
86
- T['Fqn'],
87
- T['DeploymentFqn'],
88
- T['ViewId']
89
- >
90
-
91
- with<
92
- A extends AnyTypes
93
- >(
94
- op1: (input: Builder<T>) => Builder<A>
95
- ): Builder<A>
96
-
97
- with<
98
- A extends AnyTypes,
99
- B extends AnyTypes
100
- >(
101
- op1: (input: Builder<T>) => Builder<A>,
102
- op2: (input: Builder<A>) => Builder<B>
103
- ): Builder<B>
104
-
105
- with<
106
- A extends AnyTypes,
107
- B extends AnyTypes,
108
- C extends AnyTypes
109
- >(
110
- op1: (input: Builder<T>) => Builder<A>,
111
- op2: (input: Builder<A>) => Builder<B>,
112
- op3: (input: Builder<B>) => Builder<C>
113
- ): Builder<C>
114
-
115
- with<
116
- A extends AnyTypes,
117
- B extends AnyTypes,
118
- C extends AnyTypes,
119
- D extends AnyTypes
120
- >(
121
- op1: (input: Builder<T>) => Builder<A>,
122
- op2: (input: Builder<A>) => Builder<B>,
123
- op3: (input: Builder<B>) => Builder<C>,
124
- op4: (input: Builder<C>) => Builder<D>
125
- ): Builder<D>
126
-
127
- with<
128
- A extends AnyTypes,
129
- B extends AnyTypes,
130
- C extends AnyTypes,
131
- D extends AnyTypes,
132
- E extends AnyTypes
133
- >(
134
- op1: (input: Builder<T>) => Builder<A>,
135
- op2: (input: Builder<A>) => Builder<B>,
136
- op3: (input: Builder<B>) => Builder<C>,
137
- op4: (input: Builder<C>) => Builder<D>,
138
- op5: (input: Builder<D>) => Builder<E>
139
- ): Builder<E>
140
-
141
- with<
142
- A extends AnyTypes,
143
- B extends AnyTypes,
144
- C extends AnyTypes,
145
- D extends AnyTypes,
146
- E extends AnyTypes,
147
- F extends AnyTypes
148
- >(
149
- op1: (input: Builder<T>) => Builder<A>,
150
- op2: (input: Builder<A>) => Builder<B>,
151
- op3: (input: Builder<B>) => Builder<C>,
152
- op4: (input: Builder<C>) => Builder<D>,
153
- op5: (input: Builder<D>) => Builder<E>,
154
- op6: (input: Builder<E>) => Builder<F>
155
- ): Builder<F>
156
-
157
- with<
158
- A extends AnyTypes,
159
- B extends AnyTypes,
160
- C extends AnyTypes,
161
- D extends AnyTypes,
162
- E extends AnyTypes,
163
- F extends AnyTypes,
164
- G extends AnyTypes
165
- >(
166
- op1: (input: Builder<T>) => Builder<A>,
167
- op2: (input: Builder<A>) => Builder<B>,
168
- op3: (input: Builder<B>) => Builder<C>,
169
- op4: (input: Builder<C>) => Builder<D>,
170
- op5: (input: Builder<D>) => Builder<E>,
171
- op6: (input: Builder<E>) => Builder<F>,
172
- op7: (input: Builder<F>) => Builder<G>
173
- ): Builder<G>
174
-
175
- with<
176
- A extends AnyTypes,
177
- B extends AnyTypes,
178
- C extends AnyTypes,
179
- D extends AnyTypes,
180
- E extends AnyTypes,
181
- F extends AnyTypes,
182
- G extends AnyTypes,
183
- H extends AnyTypes
184
- >(
185
- op1: (input: Builder<T>) => Builder<A>,
186
- op2: (input: Builder<A>) => Builder<B>,
187
- op3: (input: Builder<B>) => Builder<C>,
188
- op4: (input: Builder<C>) => Builder<D>,
189
- op5: (input: Builder<D>) => Builder<E>,
190
- op6: (input: Builder<E>) => Builder<F>,
191
- op7: (input: Builder<F>) => Builder<G>,
192
- op8: (input: Builder<G>) => Builder<H>
193
- ): Builder<H>
194
-
195
- with<
196
- A extends AnyTypes,
197
- B extends AnyTypes,
198
- C extends AnyTypes,
199
- D extends AnyTypes,
200
- E extends AnyTypes,
201
- F extends AnyTypes,
202
- G extends AnyTypes,
203
- H extends AnyTypes,
204
- I extends AnyTypes
205
- >(
206
- op1: (input: Builder<T>) => Builder<A>,
207
- op2: (input: Builder<A>) => Builder<B>,
208
- op3: (input: Builder<B>) => Builder<C>,
209
- op4: (input: Builder<C>) => Builder<D>,
210
- op5: (input: Builder<D>) => Builder<E>,
211
- op6: (input: Builder<E>) => Builder<F>,
212
- op7: (input: Builder<F>) => Builder<G>,
213
- op8: (input: Builder<G>) => Builder<H>,
214
- op9: (input: Builder<H>) => Builder<I>
215
- ): Builder<I>
216
-
217
- with<
218
- A extends AnyTypes,
219
- B extends AnyTypes,
220
- C extends AnyTypes,
221
- D extends AnyTypes,
222
- E extends AnyTypes,
223
- F extends AnyTypes,
224
- G extends AnyTypes,
225
- H extends AnyTypes,
226
- I extends AnyTypes,
227
- J extends AnyTypes
228
- >(
229
- op1: (input: Builder<T>) => Builder<A>,
230
- op2: (input: Builder<A>) => Builder<B>,
231
- op3: (input: Builder<B>) => Builder<C>,
232
- op4: (input: Builder<C>) => Builder<D>,
233
- op5: (input: Builder<D>) => Builder<E>,
234
- op6: (input: Builder<E>) => Builder<F>,
235
- op7: (input: Builder<F>) => Builder<G>,
236
- op8: (input: Builder<G>) => Builder<H>,
237
- op9: (input: Builder<H>) => Builder<I>,
238
- op10: (input: Builder<I>) => Builder<J>
239
- ): Builder<J>
139
+ toLikeC4Model(): Types.ToLikeC4Model<T>
240
140
  }
241
141
 
142
+ interface Internals<T extends AnyTypes> extends ViewsBuilder<T>, ModelBuilder<T>, DeploymentModelBuilder<T> {
143
+ }
144
+
145
+ type Op<T> = (b: T) => T
146
+
242
147
  function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
243
148
  spec: Spec,
244
149
  _elements = new Map<string, Element>(),
245
- _relations = [] as Relation[],
150
+ _relations = [] as ModelRelation[],
246
151
  _views = new Map<string, LikeC4View>(),
247
152
  _globals = {
248
153
  predicates: {},
249
154
  dynamicPredicates: {},
250
- styles: {}
155
+ styles: {},
251
156
  } as ModelGlobals,
252
157
  _deployments = new Map<string, DeploymentElement>(),
253
- _deploymentRelations = [] as DeploymentRelation[]
158
+ _deploymentRelations = [] as DeploymentRelation[],
254
159
  ): Builder<T> {
255
160
  const toLikeC4Specification = (): Types.ToParsedLikeC4Model<T>['specification'] => ({
256
161
  elements: {
257
- ...spec.elements as any
162
+ ...structuredClone(spec.elements) as any,
258
163
  },
259
164
  deployments: {
260
- ...spec.deployments as any
165
+ ...structuredClone(spec.deployments) as any,
261
166
  },
262
167
  relationships: {
263
- ...spec.relationships
168
+ ...structuredClone(spec.relationships) as any,
264
169
  },
265
- tags: (spec.tags ?? []) as Tag<T['Tag']>[]
170
+ tags: (spec.tags ?? []) as Tag<T['Tag']>[],
266
171
  })
267
172
 
268
173
  const mapLinks = (links?: Array<string | { title?: string; url: string }>): NonEmptyArray<Link> | null => {
@@ -272,7 +177,37 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
272
177
  return map(links, l => (typeof l === 'string' ? { url: l } : l))
273
178
  }
274
179
 
275
- const self: Builder<T> = {
180
+ const createGenericView = <B extends Op<any> | undefined>(
181
+ id: string,
182
+ _props: T['NewViewProps'] | string | B | null,
183
+ builder: B,
184
+ ): [Omit<LikeC4View, 'rules'>, B] => {
185
+ if (isFunction(_props)) {
186
+ builder = _props as B
187
+ _props = {}
188
+ }
189
+ _props ??= {}
190
+ const {
191
+ links: _links = [],
192
+ title = null,
193
+ description = null,
194
+ tags = null,
195
+ ...props
196
+ } = typeof _props === 'string' ? { title: _props } : { ..._props }
197
+
198
+ const links = mapLinks(_links)
199
+ return [{
200
+ id: id as any,
201
+ title,
202
+ description,
203
+ tags,
204
+ links,
205
+ customColorDefinitions: {},
206
+ ...props,
207
+ }, builder]
208
+ }
209
+
210
+ const self: Builder<T> & Internals<T> = {
276
211
  get Types(): T {
277
212
  throw new Error('Types are not available in runtime')
278
213
  },
@@ -284,114 +219,137 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
284
219
  structuredClone(_views),
285
220
  structuredClone(_globals),
286
221
  structuredClone(_deployments),
287
- structuredClone(_deploymentRelations)
222
+ structuredClone(_deploymentRelations),
288
223
  )
289
224
  },
290
- __model: () => ({
291
- addElement: (element) => {
292
- const parent = parentFqn(element.id)
293
- if (parent) {
294
- invariant(
295
- _elements.get(parent),
296
- `Parent element with id "${parent}" not found for element with id "${element.id}"`
297
- )
298
- }
299
- if (_elements.has(element.id)) {
300
- throw new Error(`Element with id "${element.id}" already exists`)
301
- }
302
- _elements.set(element.id, element)
303
- return self
304
- },
305
- addRelation(relation) {
306
- const sourceEl = _elements.get(relation.source)
307
- invariant(sourceEl, `Element with id "${relation.source}" not found`)
308
- const targetEl = _elements.get(relation.target)
309
- invariant(targetEl, `Element with id "${relation.target}" not found`)
225
+
226
+ __addElement: (element) => {
227
+ const parent = parentFqn(element.id)
228
+ if (parent) {
310
229
  invariant(
311
- !isSameHierarchy(sourceEl, targetEl),
312
- 'Cannot create relationship between elements in the same hierarchy'
230
+ _elements.get(parent),
231
+ `Parent element with id "${parent}" not found for element with id "${element.id}"`,
313
232
  )
314
- _relations.push({
315
- id: `rel${_relations.length + 1}` as RelationId,
316
- ...relation
317
- })
318
- return self
319
- },
320
- /**
321
- * Fully qualified name for nested elements
322
- */
323
- fqn(id) {
324
- return id as Fqn
325
- },
326
- addSourcelessRelation() {
327
- throw new Error('Can be called only in nested model')
328
233
  }
329
- }),
330
- __views: () => ({
331
- addView: (view) => {
332
- if (isScopedElementView(view)) {
333
- invariant(_elements.get(view.viewOf), `Invalid view ${view.id}, wlement with id "${view.viewOf}" not found`)
334
- }
335
- _views.set(view.id, view)
336
- return self
234
+ if (_elements.has(element.id)) {
235
+ throw new Error(`Element with id "${element.id}" already exists`)
337
236
  }
338
- }),
339
- __deployment: () => ({
340
- addDeployment: (node: DeploymentElement) => {
341
- if (_deployments.has(node.id)) {
342
- throw new Error(`Deployment with id "${node.id}" already exists`)
343
- }
344
- const parent = parentFqn(node.id)
345
- if (parent) {
346
- invariant(
347
- _deployments.get(parent),
348
- `Parent element with id "${parent}" not found for node with id "${node.id}"`
349
- )
350
- }
351
- if (DeploymentElement.isInstance(node)) {
352
- invariant(parent, 'Instance must have parent')
353
- }
354
- _deployments.set(node.id, node)
355
- return self
356
- },
357
- addDeploymentRelation: (relation) => {
237
+ _elements.set(element.id, element)
238
+ return self
239
+ },
240
+ __addRelation(relation) {
241
+ const sourceEl = _elements.get(relation.source)
242
+ invariant(sourceEl, `Element with id "${relation.source}" not found`)
243
+ const targetEl = _elements.get(relation.target)
244
+ invariant(targetEl, `Element with id "${relation.target}" not found`)
245
+ invariant(
246
+ !isSameHierarchy(sourceEl, targetEl),
247
+ 'Cannot create relationship between elements in the same hierarchy',
248
+ )
249
+ _relations.push({
250
+ id: `rel${_relations.length + 1}` as RelationId,
251
+ ...relation,
252
+ })
253
+ return self
254
+ },
255
+ /**
256
+ * Fully qualified name for nested elements
257
+ */
258
+ __fqn(id) {
259
+ invariant(id.trim() !== '', 'Id must be non-empty')
260
+ return id as Fqn
261
+ },
262
+ __addSourcelessRelation() {
263
+ throw new Error('Can be called only in nested model')
264
+ },
265
+ __addView: (view) => {
266
+ if (_views.has(view.id)) {
267
+ throw new Error(`View with id "${view.id}" already exists`)
268
+ }
269
+ if (isScopedElementView(view)) {
358
270
  invariant(
359
- !isSameHierarchy(relation.source.id, relation.target.id),
360
- 'Cannot create relationship between elements in the same hierarchy'
271
+ _elements.get(view.viewOf),
272
+ `Invalid scoped view ${view.id}, wlement with id "${view.viewOf}" not found`,
361
273
  )
362
- _deploymentRelations.push({
363
- id: `deploy_rel${_deploymentRelations.length + 1}` as RelationId,
364
- ...relation
365
- })
366
- return self
367
- },
368
- fqn: (id) => id as Fqn
369
- }),
274
+ }
275
+ _views.set(view.id, view)
276
+ return self
277
+ },
278
+
279
+ __addDeployment: (node: DeploymentElement) => {
280
+ if (_deployments.has(node.id)) {
281
+ throw new Error(`Deployment with id "${node.id}" already exists`)
282
+ }
283
+ const parent = parentFqn(node.id)
284
+ if (parent) {
285
+ invariant(
286
+ _deployments.get(parent),
287
+ `Parent element with id "${parent}" not found for node with id "${node.id}"`,
288
+ )
289
+ }
290
+ if (DeploymentElement.isInstance(node)) {
291
+ invariant(parent, `Instance ${node.id} of ${node.element} must be deployed under a parent node`)
292
+ invariant(
293
+ _elements.get(node.element),
294
+ `Instance "${node.id}" references non-existing element "${node.element}"`,
295
+ )
296
+ }
297
+ _deployments.set(node.id, node)
298
+ return self
299
+ },
300
+ __addDeploymentRelation: (relation) => {
301
+ invariant(
302
+ !isSameHierarchy(relation.source.id, relation.target.id),
303
+ 'Cannot create relationship between elements in the same hierarchy',
304
+ )
305
+
306
+ invariant(
307
+ _deployments.has(relation.source.id),
308
+ `Relation "${relation.source.id} -> ${relation.target.id}" references non-existing source`,
309
+ )
310
+ invariant(
311
+ _deployments.has(relation.target.id),
312
+ `Relation "${relation.source.id} -> ${relation.target.id}" references non-existing target`,
313
+ )
314
+
315
+ _deploymentRelations.push({
316
+ id: `deploy_rel${_deploymentRelations.length + 1}` as RelationId,
317
+ ...relation,
318
+ })
319
+ return self
320
+ },
370
321
  build: () => ({
371
322
  specification: toLikeC4Specification(),
372
- elements: fromEntries(Array.from(_elements.entries())) as any,
373
- relations: mapToObj(_relations, r => [r.id, r]),
323
+ elements: fromEntries(
324
+ structuredClone(
325
+ Array.from(_elements.entries()),
326
+ ),
327
+ ),
328
+ relations: mapToObj(_relations, r => [r.id, structuredClone(r)]),
374
329
  globals: structuredClone(_globals),
375
330
  deployments: {
376
- elements: fromEntries(Array.from(_deployments.entries())) as any,
377
- relations: mapToObj(_deploymentRelations, r => [r.id, r])
331
+ elements: fromEntries(
332
+ structuredClone(
333
+ Array.from(_deployments.entries()),
334
+ ),
335
+ ),
336
+ relations: mapToObj(_deploymentRelations, r => [r.id, structuredClone(r)]),
378
337
  },
379
- views: fromEntries(Array.from(_views.entries())) as any
380
- }),
381
- buildComputedModel: () => {
338
+ views: fromEntries(
339
+ structuredClone(
340
+ Array.from(_views.entries()),
341
+ ),
342
+ ),
343
+ } as any),
344
+ toLikeC4Model: () => {
382
345
  const parsed = self.build()
383
- const computed = computeViews(parsed)
384
- return LikeC4Model.create(computed)
346
+ return LikeC4Model.compute(parsed)
385
347
  },
386
348
  helpers: () => ({
387
349
  model: {
388
350
  model: (...ops: ((b: ModelBuilder<T>) => ModelBuilder<T>)[]) => {
389
351
  return (b: Builder<T>) => {
390
- const v = b.__model()
391
- for (const op of ops) {
392
- op(v)
393
- }
394
- return b
352
+ return ops.reduce((b, op) => op(b), b as any as ModelBuilder<T>) as any
395
353
  }
396
354
  },
397
355
  rel: (source: string, target: string, _props?: T['NewRelationshipProps'] | string) => {
@@ -402,15 +360,15 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
402
360
  ...props
403
361
  } = defu(
404
362
  typeof _props === 'string' ? { title: _props } : { ..._props },
405
- { title: null, links: null }
363
+ { title: null, links: null },
406
364
  )
407
365
  const links = mapLinks(_links)
408
- b.addRelation({
366
+ b.__addRelation({
409
367
  source: source as any,
410
368
  target: target as any,
411
369
  title,
412
370
  ...(links && { links }),
413
- ...props
371
+ ...props,
414
372
  })
415
373
  return b
416
374
  }
@@ -423,14 +381,14 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
423
381
  ...props
424
382
  } = defu(
425
383
  typeof _props === 'string' ? { title: _props } : { ..._props },
426
- { title: null, links: null }
384
+ { title: null, links: null },
427
385
  )
428
386
  const links = mapLinks(_links)
429
- b.addSourcelessRelation({
387
+ b.__addSourcelessRelation({
430
388
  target,
431
389
  title,
432
390
  ...(links && { links }),
433
- ...props
391
+ ...props,
434
392
  })
435
393
  return b
436
394
  }
@@ -440,7 +398,7 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
440
398
  ({ style: specStyle, ...spec }, kind) =>
441
399
  <Id extends string>(
442
400
  id: Id,
443
- _props?: T['NewElementProps'] | string
401
+ _props?: T['NewElementProps'] | string,
444
402
  ): AddElement<Id> => {
445
403
  const add = (<T extends AnyTypes>(b: ModelBuilder<T>) => {
446
404
  const {
@@ -455,9 +413,9 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
455
413
 
456
414
  const icon = _icon ?? specStyle?.icon
457
415
 
458
- const _id = b.fqn(id)
416
+ const _id = b.__fqn(id)
459
417
 
460
- b.addElement({
418
+ b.__addElement({
461
419
  id: _id,
462
420
  kind: kind as any,
463
421
  title: title ?? nameFromFqn(_id),
@@ -469,192 +427,183 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
469
427
  style: pickBy({
470
428
  border: specStyle?.border,
471
429
  opacity: specStyle?.opacity,
472
- ...style
430
+ ...style,
473
431
  }, isNonNullish),
474
432
  links,
475
433
  ...icon && { icon: icon as IconUrl },
476
434
  ...spec,
477
- ...props
435
+ ...props,
478
436
  })
479
437
  return b
480
438
  }) as AddElement<Id>
481
439
 
482
440
  add.with = (...ops: Array<(input: ModelBuilder<any>) => ModelBuilder<any>>) => (b: ModelBuilder<any>) => {
483
441
  add(b)
484
- const nestedBuilder: ModelBuilder<any> = {
485
- ...b,
486
- fqn: (child) => `${b.fqn(id)}.${child}` as Fqn,
487
- addSourcelessRelation: (relation) => {
488
- return b.addRelation({
442
+ const { __fqn, __addSourcelessRelation } = b
443
+ try {
444
+ b.__fqn = (child) => `${__fqn(id)}.${child}` as Fqn
445
+ b.__addSourcelessRelation = (relation) => {
446
+ return b.__addRelation({
489
447
  ...relation,
490
- source: b.fqn(id)
448
+ source: __fqn(id),
491
449
  })
492
450
  }
493
- }
494
- for (const op of ops) {
495
- op(nestedBuilder)
451
+ ops.reduce((b, op) => op(b), b as any as ModelBuilder<T>) as any
452
+ } finally {
453
+ b.__fqn = __fqn
454
+ b.__addSourcelessRelation = __addSourcelessRelation
496
455
  }
497
456
  return b
498
457
  }
458
+
499
459
  return add
500
- }
501
- ) as AddElementHelpers<T>
460
+ },
461
+ ) as AddElementHelpers<T>,
502
462
  },
503
463
  views: {
504
464
  views: (...ops: ((b: ViewsBuilder<T>) => ViewsBuilder<T>)[]) => {
505
465
  return (b: Builder<T>) => {
506
- const v = b.__views()
507
- for (const op of ops) {
508
- op(v)
509
- }
510
- return b
466
+ return ops.reduce((b, op) => op(b), b as any as ViewsBuilder<T>) as any
511
467
  }
512
468
  },
513
- view: (id, _props, builder?: ViewRuleBuilderOp<any>) => {
514
- if (isFunction(_props)) {
515
- builder = _props
516
- _props = {}
469
+ view: (
470
+ id: string,
471
+ _props?: T['NewViewProps'] | string | ElementViewRulesBuilder<any>,
472
+ _builder?: ElementViewRulesBuilder<any>,
473
+ ) => {
474
+ const [generic, builder] = createGenericView(id, _props, _builder)
475
+ const view: Writable<ElementView> = {
476
+ ...generic,
477
+ __: 'element',
478
+ rules: [],
517
479
  }
518
- return <T extends AnyTypes>(b: ViewsBuilder<T>): ViewsBuilder<T> => {
519
- const {
520
- links: _links = [],
521
- title = null,
522
- ...props
523
- } = typeof _props === 'string' ? { title: _props } : { ..._props }
524
-
525
- const links = mapLinks(_links)
526
-
527
- const view: Writable<ElementView> = {
528
- id: id as any,
529
- __: 'element',
530
- title,
531
- description: null,
532
- tags: null,
533
- rules: [],
534
- links,
535
- customColorDefinitions: {},
536
- ...props
537
- }
538
- b.addView(view)
539
480
 
481
+ const add = (b: ViewsBuilder<any>): ViewsBuilder<any> => {
482
+ b.__addView(view)
540
483
  if (builder) {
541
484
  builder(mkViewBuilder(view))
542
485
  }
543
-
544
486
  return b
545
487
  }
488
+ add.with = (...ops: ElementViewRulesBuilder<any>[]) => (b: ViewsBuilder<any>) => {
489
+ add(b)
490
+ const elementViewBuilder = mkViewBuilder(view)
491
+ for (const op of ops) {
492
+ op(elementViewBuilder)
493
+ }
494
+ return b
495
+ }
496
+
497
+ return add
546
498
  },
547
499
  viewOf: (
548
500
  id,
549
- viewOf,
550
- _props?: T['NewViewProps'] | string | ViewRuleBuilderOp<any>,
551
- builder?: ViewRuleBuilderOp<any>
501
+ viewOf: string,
502
+ _props?: T['NewViewProps'] | string | ElementViewRulesBuilder<any>,
503
+ _builder?: ElementViewRulesBuilder<any>,
552
504
  ) => {
553
- if (isFunction(_props)) {
554
- builder = _props
555
- _props = {}
505
+ const [generic, builder] = createGenericView(id, _props, _builder)
506
+ const view: Writable<ElementView> = {
507
+ ...generic,
508
+ viewOf: viewOf as Fqn,
509
+ __: 'element',
510
+ rules: [],
556
511
  }
557
- return <T extends AnyTypes>(b: ViewsBuilder<T>): ViewsBuilder<T> => {
558
- const {
559
- links: _links = [],
560
- title = null,
561
- ...props
562
- } = typeof _props === 'string' ? { title: _props } : { ..._props }
563
-
564
- const links = mapLinks(_links)
565
-
566
- const view: Writable<ElementView> = {
567
- id: id as any,
568
- __: 'element',
569
- viewOf,
570
- title,
571
- description: null,
572
- tags: null,
573
- rules: [],
574
- links,
575
- customColorDefinitions: {},
576
- ...props
577
- }
578
- b.addView(view)
579
512
 
513
+ const add = (b: ViewsBuilder<any>): ViewsBuilder<any> => {
514
+ b.__addView(view)
580
515
  if (builder) {
581
516
  builder(mkViewBuilder(view))
582
517
  }
518
+ return b
519
+ }
583
520
 
521
+ add.with = (...ops: ElementViewRulesBuilder<any>[]) => (b: ViewsBuilder<any>) => {
522
+ add(b)
523
+ const elementViewBuilder = mkViewBuilder(view)
524
+ for (const op of ops) {
525
+ op(elementViewBuilder)
526
+ }
584
527
  return b
585
528
  }
529
+
530
+ return add
586
531
  },
532
+
587
533
  deploymentView: (
588
- id,
589
- _props?: T['NewViewProps'] | string | DeploymentViewRuleBuilderOp<any>,
590
- builder?: DeploymentViewRuleBuilderOp<any>
534
+ id: string,
535
+ _props?: T['NewViewProps'] | string | DeploymentRulesBuilderOp<any>,
536
+ _builder?: DeploymentRulesBuilderOp<any>,
591
537
  ) => {
592
- if (isFunction(_props)) {
593
- builder = _props as any
594
- _props = {}
538
+ const [generic, builder] = createGenericView(id, _props, _builder)
539
+ const view: Writable<DeploymentView> = {
540
+ ...generic,
541
+ __: 'deployment',
542
+ rules: [],
595
543
  }
596
- return <T extends AnyTypes>(b: ViewsBuilder<T>): ViewsBuilder<T> => {
597
- const {
598
- links: _links = [],
599
- title = null,
600
- ...props
601
- } = typeof _props === 'string' ? { title: _props } : { ..._props }
602
-
603
- const links = mapLinks(_links)
604
-
605
- const view: Writable<DeploymentView> = {
606
- id: id as any,
607
- __: 'deployment',
608
- title,
609
- description: null,
610
- tags: null,
611
- rules: [],
612
- links,
613
- customColorDefinitions: {},
614
- ...props
615
- }
616
- b.addView(view)
617
544
 
545
+ const add = (b: ViewsBuilder<any>): ViewsBuilder<any> => {
546
+ b.__addView(view)
618
547
  if (builder) {
619
548
  builder(mkViewBuilder(view))
620
549
  }
550
+ return b
551
+ }
621
552
 
553
+ add.with = (...ops: DeploymentRulesBuilderOp<any>[]) => (b: ViewsBuilder<any>) => {
554
+ add(b)
555
+ const elementViewBuilder = mkViewBuilder(view)
556
+ for (const op of ops) {
557
+ op(elementViewBuilder)
558
+ }
622
559
  return b
623
560
  }
561
+
562
+ return add
624
563
  },
625
564
  $autoLayout,
626
565
  $exclude,
627
566
  $include,
628
567
  $rules,
629
- $style
568
+ $style,
630
569
  },
631
570
  deployment: {
632
571
  deployment: (...ops: ((b: DeploymentModelBuilder<T>) => DeploymentModelBuilder<T>)[]) => {
633
572
  return (b: Builder<T>) => {
634
- const v = b.__deployment()
635
- for (const op of ops) {
636
- op(v)
637
- }
638
- return b
573
+ return ops.reduce((b, op) => op(b), b as any as DeploymentModelBuilder<T>) as any
639
574
  }
640
575
  },
641
- instanceOf: (id, to, _props?: string | T['NewDeploymentNodeProps']) => {
576
+ instanceOf: (
577
+ id: string,
578
+ target?: string | T['NewDeploymentNodeProps'],
579
+ _props?: string | T['NewDeploymentNodeProps'],
580
+ ) => {
642
581
  return <T extends AnyTypes>(
643
- b: DeploymentModelBuilder<T>
582
+ b: DeploymentModelBuilder<T>,
644
583
  ): DeploymentModelBuilder<Types.AddDeploymentFqn<T, any>> => {
584
+ if (isNullish(target)) {
585
+ target = id
586
+ id = nameFromFqn(id)
587
+ } else if (typeof target === 'string') {
588
+ _props ??= {}
589
+ } else {
590
+ _props = target
591
+ target = id
592
+ id = nameFromFqn(id)
593
+ }
645
594
  const {
646
595
  links,
647
596
  title,
648
597
  ...props
649
598
  } = typeof _props === 'string' ? { title: _props } : { ..._props }
650
- const _id = b.fqn(id)
651
- invariant(_elements.has(to), `Target element with id "${to}" not found`)
652
- b.addDeployment({
599
+ const _id = b.__fqn(id)
600
+ invariant(_elements.has(target), `Target element with id "${target}" not found`)
601
+ b.__addDeployment({
653
602
  id: _id,
654
- element: to as any,
603
+ element: target as any,
655
604
  ...title && { title },
656
605
  ...links && { links: mapLinks(links) },
657
- ...props
606
+ ...props,
658
607
  })
659
608
  return b as any
660
609
  }
@@ -667,16 +616,16 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
667
616
  ...props
668
617
  } = typeof _props === 'string' ? { title: _props } : { ..._props }
669
618
 
670
- b.addDeploymentRelation({
619
+ b.__addDeploymentRelation({
671
620
  source: {
672
- id: source as any
621
+ id: source as any,
673
622
  },
674
623
  target: {
675
- id: target as any
624
+ id: target as any,
676
625
  },
677
626
  ...title && { title },
678
627
  ...links && { links: mapLinks(links) },
679
- ...props
628
+ ...props,
680
629
  })
681
630
  return b
682
631
  }
@@ -686,7 +635,7 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
686
635
  ({ style: specStyle, ...spec }, kind) =>
687
636
  <Id extends string>(
688
637
  id: Id,
689
- _props?: T['NewDeploymentNodeProps'] | string
638
+ _props?: T['NewDeploymentNodeProps'] | string,
690
639
  ): AddDeploymentNode<Id> => {
691
640
  const add = (<T extends AnyTypes>(b: DeploymentModelBuilder<T>) => {
692
641
  const {
@@ -699,9 +648,9 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
699
648
 
700
649
  const icon = _icon ?? specStyle?.icon
701
650
 
702
- const _id = b.fqn(id)
651
+ const _id = b.__fqn(id)
703
652
 
704
- b.addDeployment({
653
+ b.__addDeployment({
705
654
  id: _id,
706
655
  kind: kind as any,
707
656
  title: title ?? nameFromFqn(_id),
@@ -713,12 +662,12 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
713
662
  style: pickBy({
714
663
  border: specStyle?.border,
715
664
  opacity: specStyle?.opacity,
716
- ...style
665
+ ...style,
717
666
  }, isNonNullish),
718
667
  ...links && { links: mapLinks(links) },
719
668
  ...icon && { icon: icon as IconUrl },
720
669
  ...spec,
721
- ...props
670
+ ...props,
722
671
  })
723
672
  return b
724
673
  }) as AddDeploymentNode<Id>
@@ -727,41 +676,73 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
727
676
  (...ops: Array<(input: DeploymentModelBuilder<any>) => DeploymentModelBuilder<any>>) =>
728
677
  (b: DeploymentModelBuilder<any>) => {
729
678
  add(b)
730
- const nestedBuilder: DeploymentModelBuilder<any> = {
731
- ...b,
732
- fqn: (child) => `${b.fqn(id)}.${child}` as Fqn
733
- }
734
- for (const op of ops) {
735
- op(nestedBuilder)
679
+ const { __fqn } = b
680
+ try {
681
+ b.__fqn = (child) => `${__fqn(id)}.${child}` as Fqn
682
+ ops.reduce((b, op) => op(b), b as any as DeploymentModelBuilder<T>) as any
683
+ } finally {
684
+ b.__fqn = __fqn
736
685
  }
737
686
  return b
738
687
  }
739
688
  return add
740
- }
741
- ) as AddDeploymentNodeHelpers<T>
742
- }
689
+ },
690
+ ) as AddDeploymentNodeHelpers<T>,
691
+ },
692
+ } as {
693
+ model: ModelHelpers<T>
694
+ views: ViewsHelpers
695
+ deployment: DeloymentModelHelpers<T>
743
696
  }),
744
697
  with: (...ops: ((b: Builder<T>) => Builder<T>)[]) => {
745
- return ops.reduce((b, op) => op(b), self).clone()
746
- }
698
+ return ops.reduce((b, op) => op(b), self as Builder<T>).clone()
699
+ },
700
+ model: <Out extends AnyTypes>(cb: ModelBuilderFunction<T, Out>) => {
701
+ const b = self.clone()
702
+ const helpers = b.helpers().model
703
+ const _ = helpers.model as any
704
+ return cb({ ...helpers, _ }, _)(b as Internals<T>) as any
705
+ },
706
+ deployment: <Out extends AnyTypes>(cb: DeloymentModelBuildFunction<T, Out>) => {
707
+ const b = self.clone()
708
+ const helpers = b.helpers().deployment
709
+ const _ = helpers.deployment as any
710
+ return cb({ ...helpers, _ }, _)(b as Internals<T>) as any
711
+ },
712
+ views: <Out extends AnyTypes>(cb: ViewsBuilderFunction<T, Out>) => {
713
+ const b = self.clone()
714
+ const helpers = b.helpers().views
715
+ return cb({
716
+ ...helpers,
717
+ _: helpers.views as any,
718
+ } as any, helpers.views as any)(b as Internals<T>) as any
719
+ },
747
720
  }
748
721
 
749
722
  return self
750
723
  }
751
724
 
752
725
  export namespace Builder {
726
+ export type Any = Builder<AnyTypes>
727
+
753
728
  export function forSpecification<const Spec extends BuilderSpecification>(
754
- spec: Spec
729
+ spec: Spec,
755
730
  ): {
756
731
  builder: Builder<Types.FromSpecification<Spec>>
757
732
  model: ModelHelpers<Types.FromSpecification<Spec>>
758
733
  deployment: DeloymentModelHelpers<Types.FromSpecification<Spec>>
759
- views: ViewHelpers<Types.FromSpecification<Spec>['NewViewProps']>
734
+ views: ViewsHelpers
760
735
  } {
761
736
  const b = builder<Spec, Types.FromSpecification<Spec>>(spec)
762
737
  return {
763
738
  ...b.helpers(),
764
- builder: b
739
+ builder: b,
765
740
  }
766
741
  }
742
+
743
+ export function specification<const Spec extends BuilderSpecification>(
744
+ spec: Spec,
745
+ ): Builder<Types.FromSpecification<Spec>> {
746
+ return builder<Spec, Types.FromSpecification<Spec>>(spec)
747
+ }
767
748
  }