@likec4/core 1.17.1 → 1.19.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 (184) 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 +22 -0
  6. package/dist/compute-view/index.d.ts +22 -0
  7. package/dist/compute-view/index.js +78 -0
  8. package/dist/index.d.mts +10 -919
  9. package/dist/index.d.ts +10 -919
  10. package/dist/{index.mjs → index.js} +7 -1688
  11. package/dist/model/index.d.mts +254 -0
  12. package/dist/model/index.d.ts +254 -0
  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.CoLQkcYL.d.cts → core.C05RDLhi.d.ts} +460 -362
  18. package/dist/shared/{core.CoLQkcYL.d.mts → core.CmYMqgha.d.mts} +460 -362
  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.-BdzdI2C.js +7443 -0
  24. package/dist/shared/object_hash.CE_oF3I3.js +1222 -0
  25. package/dist/shared/{core.BXTs-8n7.mjs → view.CyZrG8BJ.js} +108 -47
  26. package/dist/types/index.d.mts +71 -1
  27. package/dist/types/index.d.ts +71 -1
  28. package/dist/types/index.js +20 -0
  29. package/dist/utils/index.d.mts +404 -0
  30. package/dist/utils/index.d.ts +404 -0
  31. package/dist/utils/index.js +330 -0
  32. package/package.json +59 -47
  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 +224 -0
  36. package/src/builder/Builder.deploymentModel.ts +385 -0
  37. package/src/builder/Builder.element.ts +19 -19
  38. package/src/builder/Builder.model.ts +67 -42
  39. package/src/builder/Builder.ts +533 -367
  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 +113 -18
  49. package/src/builder/index.ts +10 -4
  50. package/src/colors/index.ts +2 -2
  51. package/src/compute-view/compute-view.ts +83 -0
  52. package/src/compute-view/deployment-view/__test__/TestHelper.ts +236 -0
  53. package/src/compute-view/deployment-view/__test__/fixture.ts +198 -0
  54. package/src/compute-view/deployment-view/_types.ts +37 -0
  55. package/src/compute-view/deployment-view/clean-connections.ts +238 -0
  56. package/src/compute-view/deployment-view/compute.ts +125 -0
  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 +237 -0
  61. package/src/compute-view/deployment-view/predicates/relation-in-out.ts +61 -0
  62. package/src/compute-view/deployment-view/predicates/relation-incoming.ts +95 -0
  63. package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +88 -0
  64. package/src/compute-view/deployment-view/predicates/wildcard.ts +29 -0
  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 +276 -0
  69. package/src/compute-view/dynamic-view/__test__/fixture.ts +58 -0
  70. package/src/compute-view/dynamic-view/compute.ts +324 -0
  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 +458 -0
  73. package/src/compute-view/element-view/__test__/fixture.ts +675 -0
  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 +315 -0
  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 +4 -0
  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/__snapshots__/sortNodes.spec.ts.snap +113 -0
  101. package/src/compute-view/utils/ancestorsOfNode.ts +19 -0
  102. package/src/compute-view/utils/applyCustomElementProperties.ts +66 -0
  103. package/src/compute-view/utils/applyCustomRelationProperties.ts +41 -0
  104. package/src/compute-view/utils/applyViewRuleStyles.ts +53 -0
  105. package/src/compute-view/utils/buildComputedNodes.ts +148 -0
  106. package/src/compute-view/utils/buildElementNotations.ts +63 -0
  107. package/src/compute-view/utils/elementExpressionToPredicate.ts +50 -0
  108. package/src/compute-view/utils/link-nodes-with-edges.ts +54 -0
  109. package/src/compute-view/utils/merge-props-from-relationships.ts +128 -0
  110. package/src/compute-view/utils/relationExpressionToPredicates.ts +55 -0
  111. package/src/compute-view/utils/resolve-extended-views.ts +69 -0
  112. package/src/compute-view/utils/resolve-global-rules.ts +83 -0
  113. package/src/compute-view/utils/topological-sort.ts +256 -0
  114. package/src/compute-view/utils/uniqueTags.test.ts +42 -0
  115. package/src/compute-view/utils/uniqueTags.ts +21 -0
  116. package/src/compute-view/utils/view-hash.ts +27 -0
  117. package/src/compute-view/utils/with-readable-edges.ts +36 -0
  118. package/src/index.ts +22 -12
  119. package/src/model/DeploymentElementModel.ts +599 -0
  120. package/src/model/DeploymentModel.ts +370 -0
  121. package/src/model/ElementModel.ts +221 -0
  122. package/src/model/LikeC4Model.test-d.ts +152 -0
  123. package/src/model/LikeC4Model.ts +336 -457
  124. package/src/model/RelationModel.ts +85 -0
  125. package/src/model/__test__/fixture.ts +149 -338
  126. package/src/model/connection/Connection.ts +72 -0
  127. package/src/model/connection/deployment/DeploymentConnectionModel.ts +178 -0
  128. package/src/model/connection/deployment/find.ts +120 -0
  129. package/src/model/connection/deployment/index.ts +8 -0
  130. package/src/model/connection/index.ts +22 -0
  131. package/src/model/connection/model/ConnectionModel.ts +157 -0
  132. package/src/model/connection/model/find.ts +117 -0
  133. package/src/model/connection/model/index.ts +8 -0
  134. package/src/model/connection/ops.ts +274 -0
  135. package/src/model/guards.ts +9 -0
  136. package/src/model/index.ts +46 -2
  137. package/src/model/types.ts +112 -15
  138. package/src/model/view/EdgeModel.ts +103 -0
  139. package/src/model/view/LikeC4ViewModel.ts +226 -0
  140. package/src/model/view/NodeModel.ts +229 -0
  141. package/src/types/_common.ts +55 -1
  142. package/src/types/deployments.ts +169 -0
  143. package/src/types/element.ts +9 -5
  144. package/src/types/expression-v2.ts +172 -0
  145. package/src/types/expression.ts +17 -11
  146. package/src/types/global.ts +3 -3
  147. package/src/types/index.ts +220 -12
  148. package/src/types/model.ts +75 -12
  149. package/src/types/operators.ts +1 -1
  150. package/src/types/overview-graph.ts +2 -2
  151. package/src/types/relation.ts +18 -14
  152. package/src/types/theme.ts +0 -1
  153. package/src/types/view-notation.ts +2 -2
  154. package/src/types/view.ts +117 -41
  155. package/src/utils/{commonHead.ts → common-head.ts} +2 -0
  156. package/src/utils/const.ts +1 -0
  157. package/src/utils/fqn.ts +203 -56
  158. package/src/utils/getOrCreate.ts +42 -0
  159. package/src/utils/graphlib.ts +10 -0
  160. package/src/utils/index.ts +74 -6
  161. package/src/utils/iterable/_types.ts +5 -0
  162. package/src/utils/iterable/filter.ts +55 -0
  163. package/src/utils/iterable/flat.ts +17 -0
  164. package/src/utils/iterable/index.ts +12 -0
  165. package/src/utils/iterable/map.ts +40 -0
  166. package/src/utils/iterable/reduce.ts +24 -0
  167. package/src/utils/iterable/some.ts +36 -0
  168. package/src/utils/iterable/to.ts +19 -0
  169. package/src/utils/iterable/unique.ts +29 -0
  170. package/src/utils/object-hash.ts +3 -0
  171. package/src/utils/relations.ts +3 -64
  172. package/src/utils/set.ts +78 -0
  173. package/src/utils/string-hash.ts +16 -0
  174. package/dist/index.cjs +0 -5452
  175. package/dist/index.d.cts +0 -1053
  176. package/dist/shared/core.CoLQkcYL.d.ts +0 -734
  177. package/dist/shared/core.DIYZvpVg.cjs +0 -353
  178. package/dist/types/index.cjs +0 -70
  179. package/dist/types/index.d.cts +0 -2
  180. package/dist/types/index.mjs +0 -1
  181. package/src/builder/Builder.test-d.ts +0 -69
  182. package/src/builder/Builder.view.ts +0 -358
  183. package/src/model/LikeC4DiagramModel.ts +0 -338
  184. package/src/model/LikeC4ViewModel.ts +0 -320
@@ -1,11 +1,15 @@
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
4
  import { invariant } from '../errors'
5
+ import { LikeC4Model } from '../model/LikeC4Model'
5
6
  import {
6
7
  type Color,
7
8
  DefaultElementShape,
8
9
  DefaultThemeColor,
10
+ DeploymentElement,
11
+ type DeploymentRelation,
12
+ type DeploymentView,
9
13
  type Element,
10
14
  type ElementShape,
11
15
  type ElementView,
@@ -15,30 +19,29 @@ import {
15
19
  type LikeC4View,
16
20
  type Link,
17
21
  type ModelGlobals,
22
+ type ModelRelation,
18
23
  type NonEmptyArray,
19
- type Relation,
20
- type RelationID,
21
- type Tag
24
+ type RelationId,
25
+ type Tag,
22
26
  } from '../types'
23
- import type { ParsedLikeC4Model } from '../types/model'
24
27
  import { isSameHierarchy, nameFromFqn, parentFqn } from '../utils/fqn'
25
28
  import type { AnyTypes, BuilderSpecification, Types } from './_types'
26
- import type { AddElement, AddElementHelpers } from './Builder.element'
27
- import { type ModelBuilder, type ModelHelpers } from './Builder.model'
28
- import {
29
- $autoLayout,
30
- $exclude,
31
- $expr,
32
- $include,
33
- $rules,
34
- $style,
35
- type ViewBuilder,
36
- type ViewHelpers,
37
- type ViewRuleBuilderOp
38
- } from './Builder.view'
39
- import { type ViewsBuilder } from './Builder.views'
40
-
41
- export interface Builder<T extends AnyTypes> {
29
+ import type { AddDeploymentNode } from './Builder.deployment'
30
+ import type {
31
+ AddDeploymentNodeHelpers,
32
+ DeloymentModelBuildFunction,
33
+ DeloymentModelHelpers,
34
+ DeploymentModelBuilder,
35
+ } from './Builder.deploymentModel'
36
+ import type { AddElement } from './Builder.element'
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> {
42
45
  /**
43
46
  * Only available in compile time
44
47
  */
@@ -51,190 +54,120 @@ export interface Builder<T extends AnyTypes> {
51
54
  */
52
55
  helpers(): {
53
56
  model: ModelHelpers<T>
54
- views: ViewHelpers<T['NewViewProps']>
57
+ views: ViewsHelpers
58
+ deployment: DeloymentModelHelpers<T>
55
59
  }
56
60
 
57
- __model(): ModelBuilder<T>
58
- __views(): ViewsBuilder<T>
59
-
60
- build(): ParsedLikeC4Model<
61
- T['ElementKind'],
62
- T['RelationshipKind'],
63
- T['Tag'],
64
- T['Fqn'],
65
- T['ViewId']
66
- >
67
-
68
- with<
69
- A extends AnyTypes
70
- >(
71
- op1: (input: Builder<T>) => Builder<A>
72
- ): Builder<A>
73
-
74
- with<
75
- A extends AnyTypes,
76
- B extends AnyTypes
77
- >(
78
- op1: (input: Builder<T>) => Builder<A>,
79
- op2: (input: Builder<A>) => Builder<B>
80
- ): Builder<B>
81
-
82
- with<
83
- A extends AnyTypes,
84
- B extends AnyTypes,
85
- C extends AnyTypes
86
- >(
87
- op1: (input: Builder<T>) => Builder<A>,
88
- op2: (input: Builder<A>) => Builder<B>,
89
- op3: (input: Builder<B>) => Builder<C>
90
- ): Builder<C>
91
-
92
- with<
93
- A extends AnyTypes,
94
- B extends AnyTypes,
95
- C extends AnyTypes,
96
- D extends AnyTypes
97
- >(
98
- op1: (input: Builder<T>) => Builder<A>,
99
- op2: (input: Builder<A>) => Builder<B>,
100
- op3: (input: Builder<B>) => Builder<C>,
101
- op4: (input: Builder<C>) => Builder<D>
102
- ): Builder<D>
103
-
104
- with<
105
- A extends AnyTypes,
106
- B extends AnyTypes,
107
- C extends AnyTypes,
108
- D extends AnyTypes,
109
- E extends AnyTypes
110
- >(
111
- op1: (input: Builder<T>) => Builder<A>,
112
- op2: (input: Builder<A>) => Builder<B>,
113
- op3: (input: Builder<B>) => Builder<C>,
114
- op4: (input: Builder<C>) => Builder<D>,
115
- op5: (input: Builder<D>) => Builder<E>
116
- ): Builder<E>
117
-
118
- with<
119
- A extends AnyTypes,
120
- B extends AnyTypes,
121
- C extends AnyTypes,
122
- D extends AnyTypes,
123
- E extends AnyTypes,
124
- F extends AnyTypes
125
- >(
126
- op1: (input: Builder<T>) => Builder<A>,
127
- op2: (input: Builder<A>) => Builder<B>,
128
- op3: (input: Builder<B>) => Builder<C>,
129
- op4: (input: Builder<C>) => Builder<D>,
130
- op5: (input: Builder<D>) => Builder<E>,
131
- op6: (input: Builder<E>) => Builder<F>
132
- ): Builder<F>
133
-
134
- with<
135
- A extends AnyTypes,
136
- B extends AnyTypes,
137
- C extends AnyTypes,
138
- D extends AnyTypes,
139
- E extends AnyTypes,
140
- F extends AnyTypes,
141
- G extends AnyTypes
142
- >(
143
- op1: (input: Builder<T>) => Builder<A>,
144
- op2: (input: Builder<A>) => Builder<B>,
145
- op3: (input: Builder<B>) => Builder<C>,
146
- op4: (input: Builder<C>) => Builder<D>,
147
- op5: (input: Builder<D>) => Builder<E>,
148
- op6: (input: Builder<E>) => Builder<F>,
149
- op7: (input: Builder<F>) => Builder<G>
150
- ): Builder<G>
151
-
152
- with<
153
- A extends AnyTypes,
154
- B extends AnyTypes,
155
- C extends AnyTypes,
156
- D extends AnyTypes,
157
- E extends AnyTypes,
158
- F extends AnyTypes,
159
- G extends AnyTypes,
160
- H extends AnyTypes
161
- >(
162
- op1: (input: Builder<T>) => Builder<A>,
163
- op2: (input: Builder<A>) => Builder<B>,
164
- op3: (input: Builder<B>) => Builder<C>,
165
- op4: (input: Builder<C>) => Builder<D>,
166
- op5: (input: Builder<D>) => Builder<E>,
167
- op6: (input: Builder<E>) => Builder<F>,
168
- op7: (input: Builder<F>) => Builder<G>,
169
- op8: (input: Builder<G>) => Builder<H>
170
- ): Builder<H>
171
-
172
- with<
173
- A extends AnyTypes,
174
- B extends AnyTypes,
175
- C extends AnyTypes,
176
- D extends AnyTypes,
177
- E extends AnyTypes,
178
- F extends AnyTypes,
179
- G extends AnyTypes,
180
- H extends AnyTypes,
181
- I extends AnyTypes
182
- >(
183
- op1: (input: Builder<T>) => Builder<A>,
184
- op2: (input: Builder<A>) => Builder<B>,
185
- op3: (input: Builder<B>) => Builder<C>,
186
- op4: (input: Builder<C>) => Builder<D>,
187
- op5: (input: Builder<D>) => Builder<E>,
188
- op6: (input: Builder<E>) => Builder<F>,
189
- op7: (input: Builder<F>) => Builder<G>,
190
- op8: (input: Builder<G>) => Builder<H>,
191
- op9: (input: Builder<H>) => Builder<I>
192
- ): Builder<I>
193
-
194
- with<
195
- A extends AnyTypes,
196
- B extends AnyTypes,
197
- C extends AnyTypes,
198
- D extends AnyTypes,
199
- E extends AnyTypes,
200
- F extends AnyTypes,
201
- G extends AnyTypes,
202
- H extends AnyTypes,
203
- I extends AnyTypes,
204
- J 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
- op10: (input: Builder<I>) => Builder<J>
216
- ): Builder<J>
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>
128
+
129
+ /**
130
+ * Returns model as result of parsing only
131
+ * Views are not computed or layouted
132
+ * {@link toLikeC4Model} should be used to get model with computed views
133
+ */
134
+ build(): Types.ToParsedLikeC4Model<T>
135
+
136
+ /**
137
+ * Returns LikeC4Model with computed views
138
+ */
139
+ toLikeC4Model(): Types.ToLikeC4Model<T>
217
140
  }
218
141
 
142
+ interface Internals<T extends AnyTypes> extends ViewsBuilder<T>, ModelBuilder<T>, DeploymentModelBuilder<T> {
143
+ }
144
+
145
+ type Op<T> = (b: T) => T
146
+
219
147
  function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
220
148
  spec: Spec,
221
149
  _elements = new Map<string, Element>(),
222
- _relations = [] as Relation[],
150
+ _relations = [] as ModelRelation[],
223
151
  _views = new Map<string, LikeC4View>(),
224
152
  _globals = {
225
153
  predicates: {},
226
154
  dynamicPredicates: {},
227
- styles: {}
228
- } as ModelGlobals
155
+ styles: {},
156
+ } as ModelGlobals,
157
+ _deployments = new Map<string, DeploymentElement>(),
158
+ _deploymentRelations = [] as DeploymentRelation[],
229
159
  ): Builder<T> {
230
160
  const toLikeC4Specification = (): Types.ToParsedLikeC4Model<T>['specification'] => ({
231
- tags: (spec.tags ?? []) as Tag<T['Tag']>[],
232
161
  elements: {
233
- ...spec.elements as any
162
+ ...structuredClone(spec.elements) as any,
163
+ },
164
+ deployments: {
165
+ ...structuredClone(spec.deployments) as any,
234
166
  },
235
167
  relationships: {
236
- ...spec.relationships
237
- }
168
+ ...structuredClone(spec.relationships) as any,
169
+ },
170
+ tags: (spec.tags ?? []) as Tag<T['Tag']>[],
238
171
  })
239
172
 
240
173
  const mapLinks = (links?: Array<string | { title?: string; url: string }>): NonEmptyArray<Link> | null => {
@@ -244,119 +177,179 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
244
177
  return map(links, l => (typeof l === 'string' ? { url: l } : l))
245
178
  }
246
179
 
247
- const mkViewBuilder = (view: Writable<ElementView>): ViewBuilder<T> => {
248
- const viewBuilder: ViewBuilder<T> = {
249
- autoLayout(autoLayout) {
250
- view.rules.push({
251
- direction: autoLayout
252
- })
253
- return viewBuilder
254
- },
255
- exclude(expr) {
256
- view.rules.push({
257
- exclude: [expr]
258
- })
259
- return viewBuilder
260
- },
261
- include(expr) {
262
- view.rules.push({
263
- include: [expr]
264
- })
265
- return viewBuilder
266
- },
267
- style(rule) {
268
- view.rules.push(rule)
269
- return viewBuilder
270
- }
271
- // title(title: string) {
272
- // view.title = title
273
- // return viewBuilder
274
- // },
275
- // description(description: string) {
276
- // view.description = description
277
- // return viewBuilder
278
- // }
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 = {}
279
188
  }
280
- return viewBuilder
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]
281
208
  }
282
209
 
283
- const self: Builder<T> = {
210
+ const self: Builder<T> & Internals<T> = {
284
211
  get Types(): T {
285
212
  throw new Error('Types are not available in runtime')
286
213
  },
287
- clone: () =>
288
- builder(
214
+ clone: () => {
215
+ return builder(
289
216
  structuredClone(spec),
290
217
  structuredClone(_elements),
291
218
  structuredClone(_relations),
292
219
  structuredClone(_views),
293
- structuredClone(_globals)
294
- ),
295
- __model: () => ({
296
- addElement: (element) => {
297
- const parent = parentFqn(element.id)
298
- if (parent) {
299
- invariant(
300
- _elements.get(parent),
301
- `Parent element with id "${parent}" not found for element with id "${element.id}"`
302
- )
303
- }
304
- if (_elements.has(element.id)) {
305
- throw new Error(`Element with id "${element.id}" already exists`)
306
- }
307
- _elements.set(element.id, element)
308
- return self
309
- },
310
- addRelation(relation) {
311
- const sourceEl = _elements.get(relation.source)
312
- invariant(sourceEl, `Element with id "${relation.source}" not found`)
313
- const targetEl = _elements.get(relation.target)
314
- invariant(targetEl, `Element with id "${relation.target}" not found`)
220
+ structuredClone(_globals),
221
+ structuredClone(_deployments),
222
+ structuredClone(_deploymentRelations),
223
+ )
224
+ },
225
+
226
+ __addElement: (element) => {
227
+ const parent = parentFqn(element.id)
228
+ if (parent) {
315
229
  invariant(
316
- !isSameHierarchy(sourceEl, targetEl),
317
- '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}"`,
318
232
  )
319
- _relations.push({
320
- id: `rel${_relations.length + 1}` as RelationID,
321
- ...relation
322
- })
323
- return self
324
- },
325
- /**
326
- * Fully qualified name for nested elements
327
- */
328
- fqn(id) {
329
- return id as Fqn
330
- },
331
- addSourcelessRelation() {
332
- throw new Error('Can be called only in nested model')
333
233
  }
334
- }),
335
- __views: () => ({
336
- addView: (view) => {
337
- if (isScopedElementView(view)) {
338
- invariant(_elements.get(view.viewOf), `Invalid view ${view.id}, wlement with id "${view.viewOf}" not found`)
339
- }
340
- _views.set(view.id, view)
341
- return self
234
+ if (_elements.has(element.id)) {
235
+ throw new Error(`Element with id "${element.id}" already exists`)
342
236
  }
343
- }),
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)) {
270
+ invariant(
271
+ _elements.get(view.viewOf),
272
+ `Invalid scoped view ${view.id}, wlement with id "${view.viewOf}" not found`,
273
+ )
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
+ },
344
321
  build: () => ({
345
322
  specification: toLikeC4Specification(),
346
- elements: fromEntries(Array.from(_elements.entries())) as any,
347
- 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)]),
348
329
  globals: structuredClone(_globals),
349
- views: fromEntries(Array.from(_views.entries())) as any
350
- }),
330
+ deployments: {
331
+ elements: fromEntries(
332
+ structuredClone(
333
+ Array.from(_deployments.entries()),
334
+ ),
335
+ ),
336
+ relations: mapToObj(_deploymentRelations, r => [r.id, structuredClone(r)]),
337
+ },
338
+ views: fromEntries(
339
+ structuredClone(
340
+ Array.from(_views.entries()),
341
+ ),
342
+ ),
343
+ } as any),
344
+ toLikeC4Model: () => {
345
+ const parsed = self.build()
346
+ return LikeC4Model.compute(parsed)
347
+ },
351
348
  helpers: () => ({
352
349
  model: {
353
350
  model: (...ops: ((b: ModelBuilder<T>) => ModelBuilder<T>)[]) => {
354
351
  return (b: Builder<T>) => {
355
- const v = b.__model()
356
- for (const op of ops) {
357
- op(v)
358
- }
359
- return b
352
+ return ops.reduce((b, op) => op(b), b as any as ModelBuilder<T>) as any
360
353
  }
361
354
  },
362
355
  rel: (source: string, target: string, _props?: T['NewRelationshipProps'] | string) => {
@@ -367,15 +360,15 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
367
360
  ...props
368
361
  } = defu(
369
362
  typeof _props === 'string' ? { title: _props } : { ..._props },
370
- { title: null, links: null }
363
+ { title: null, links: null },
371
364
  )
372
365
  const links = mapLinks(_links)
373
- b.addRelation({
366
+ b.__addRelation({
374
367
  source: source as any,
375
368
  target: target as any,
376
369
  title,
377
370
  ...(links && { links }),
378
- ...props
371
+ ...props,
379
372
  })
380
373
  return b
381
374
  }
@@ -388,14 +381,14 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
388
381
  ...props
389
382
  } = defu(
390
383
  typeof _props === 'string' ? { title: _props } : { ..._props },
391
- { title: null, links: null }
384
+ { title: null, links: null },
392
385
  )
393
386
  const links = mapLinks(_links)
394
- b.addSourcelessRelation({
387
+ b.__addSourcelessRelation({
395
388
  target,
396
389
  title,
397
390
  ...(links && { links }),
398
- ...props
391
+ ...props,
399
392
  })
400
393
  return b
401
394
  }
@@ -405,7 +398,7 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
405
398
  ({ style: specStyle, ...spec }, kind) =>
406
399
  <Id extends string>(
407
400
  id: Id,
408
- _props?: T['NewElementProps'] | string
401
+ _props?: T['NewElementProps'] | string,
409
402
  ): AddElement<Id> => {
410
403
  const add = (<T extends AnyTypes>(b: ModelBuilder<T>) => {
411
404
  const {
@@ -420,9 +413,9 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
420
413
 
421
414
  const icon = _icon ?? specStyle?.icon
422
415
 
423
- const _id = b.fqn(id)
416
+ const _id = b.__fqn(id)
424
417
 
425
- b.addElement({
418
+ b.__addElement({
426
419
  id: _id,
427
420
  kind: kind as any,
428
421
  title: title ?? nameFromFqn(_id),
@@ -434,149 +427,322 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
434
427
  style: pickBy({
435
428
  border: specStyle?.border,
436
429
  opacity: specStyle?.opacity,
437
- ...style
430
+ ...style,
438
431
  }, isNonNullish),
439
432
  links,
440
433
  ...icon && { icon: icon as IconUrl },
441
434
  ...spec,
442
- ...props
435
+ ...props,
443
436
  })
444
437
  return b
445
438
  }) as AddElement<Id>
446
439
 
447
440
  add.with = (...ops: Array<(input: ModelBuilder<any>) => ModelBuilder<any>>) => (b: ModelBuilder<any>) => {
448
441
  add(b)
449
- const nestedBuilder: ModelBuilder<any> = {
450
- ...b,
451
- fqn: (child) => `${b.fqn(id)}.${child}` as Fqn,
452
- addSourcelessRelation: (relation) => {
453
- 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({
454
447
  ...relation,
455
- source: b.fqn(id)
448
+ source: __fqn(id),
456
449
  })
457
450
  }
458
- }
459
- for (const op of ops) {
460
- 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
461
455
  }
462
456
  return b
463
457
  }
458
+
464
459
  return add
465
- }
466
- ) as AddElementHelpers<T>
460
+ },
461
+ ) as AddElementHelpers<T>,
467
462
  },
468
463
  views: {
469
464
  views: (...ops: ((b: ViewsBuilder<T>) => ViewsBuilder<T>)[]) => {
470
465
  return (b: Builder<T>) => {
471
- const v = b.__views()
472
- for (const op of ops) {
473
- op(v)
474
- }
475
- return b
466
+ return ops.reduce((b, op) => op(b), b as any as ViewsBuilder<T>) as any
476
467
  }
477
468
  },
478
- view: (id, _props, builder?: ViewRuleBuilderOp<T>) => {
479
- if (isFunction(_props)) {
480
- builder = _props
481
- _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: [],
482
479
  }
483
- return <T extends AnyTypes>(b: ViewsBuilder<T>): ViewsBuilder<T> => {
484
- const {
485
- links: _links = [],
486
- title = null,
487
- ...props
488
- } = typeof _props === 'string' ? { title: _props } : { ..._props }
489
-
490
- const links = mapLinks(_links)
491
-
492
- const view: Writable<ElementView> = {
493
- id: id as any,
494
- __: 'element',
495
- title,
496
- description: null,
497
- tags: null,
498
- rules: [],
499
- links,
500
- customColorDefinitions: {},
501
- ...props
502
- }
503
- b.addView(view)
504
480
 
481
+ const add = (b: ViewsBuilder<any>): ViewsBuilder<any> => {
482
+ b.__addView(view)
505
483
  if (builder) {
506
484
  builder(mkViewBuilder(view))
507
485
  }
508
-
509
486
  return b
510
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
511
498
  },
512
499
  viewOf: (
513
500
  id,
514
- viewOf,
515
- _props?: T['NewViewProps'] | string | ViewRuleBuilderOp<T>,
516
- builder?: ViewRuleBuilderOp<T>
501
+ viewOf: string,
502
+ _props?: T['NewViewProps'] | string | ElementViewRulesBuilder<any>,
503
+ _builder?: ElementViewRulesBuilder<any>,
517
504
  ) => {
518
- if (isFunction(_props)) {
519
- builder = _props
520
- _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: [],
521
511
  }
522
- return <T extends AnyTypes>(b: ViewsBuilder<T>): ViewsBuilder<T> => {
523
- const {
524
- links: _links = [],
525
- title = null,
526
- ...props
527
- } = typeof _props === 'string' ? { title: _props } : { ..._props }
528
512
 
529
- const links = mapLinks(_links)
513
+ const add = (b: ViewsBuilder<any>): ViewsBuilder<any> => {
514
+ b.__addView(view)
515
+ if (builder) {
516
+ builder(mkViewBuilder(view))
517
+ }
518
+ return b
519
+ }
530
520
 
531
- const view: Writable<ElementView> = {
532
- id: id as any,
533
- __: 'element',
534
- viewOf,
535
- title,
536
- description: null,
537
- tags: null,
538
- rules: [],
539
- links,
540
- customColorDefinitions: {},
541
- ...props
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)
542
526
  }
543
- b.addView(view)
527
+ return b
528
+ }
529
+
530
+ return add
531
+ },
532
+
533
+ deploymentView: (
534
+ id: string,
535
+ _props?: T['NewViewProps'] | string | DeploymentRulesBuilderOp<any>,
536
+ _builder?: DeploymentRulesBuilderOp<any>,
537
+ ) => {
538
+ const [generic, builder] = createGenericView(id, _props, _builder)
539
+ const view: Writable<DeploymentView> = {
540
+ ...generic,
541
+ __: 'deployment',
542
+ rules: [],
543
+ }
544
544
 
545
+ const add = (b: ViewsBuilder<any>): ViewsBuilder<any> => {
546
+ b.__addView(view)
545
547
  if (builder) {
546
548
  builder(mkViewBuilder(view))
547
549
  }
550
+ return b
551
+ }
548
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
+ }
549
559
  return b
550
560
  }
561
+
562
+ return add
551
563
  },
552
564
  $autoLayout,
553
565
  $exclude,
554
- $expr,
555
566
  $include,
556
567
  $rules,
557
- $style
558
- }
568
+ $style,
569
+ },
570
+ deployment: {
571
+ deployment: (...ops: ((b: DeploymentModelBuilder<T>) => DeploymentModelBuilder<T>)[]) => {
572
+ return (b: Builder<T>) => {
573
+ return ops.reduce((b, op) => op(b), b as any as DeploymentModelBuilder<T>) as any
574
+ }
575
+ },
576
+ instanceOf: (
577
+ id: string,
578
+ target?: string | T['NewDeploymentNodeProps'],
579
+ _props?: string | T['NewDeploymentNodeProps'],
580
+ ) => {
581
+ return <T extends AnyTypes>(
582
+ b: DeploymentModelBuilder<T>,
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
+ }
594
+ const {
595
+ links,
596
+ title,
597
+ ...props
598
+ } = typeof _props === 'string' ? { title: _props } : { ..._props }
599
+ const _id = b.__fqn(id)
600
+ invariant(_elements.has(target), `Target element with id "${target}" not found`)
601
+ b.__addDeployment({
602
+ id: _id,
603
+ element: target as any,
604
+ ...title && { title },
605
+ ...links && { links: mapLinks(links) },
606
+ ...props,
607
+ })
608
+ return b as any
609
+ }
610
+ },
611
+ rel: (source: string, target: string, _props?: T['NewRelationshipProps'] | string) => {
612
+ return <T extends AnyTypes>(b: DeploymentModelBuilder<T>) => {
613
+ const {
614
+ title,
615
+ links,
616
+ ...props
617
+ } = typeof _props === 'string' ? { title: _props } : { ..._props }
618
+
619
+ b.__addDeploymentRelation({
620
+ source: {
621
+ id: source as any,
622
+ },
623
+ target: {
624
+ id: target as any,
625
+ },
626
+ ...title && { title },
627
+ ...links && { links: mapLinks(links) },
628
+ ...props,
629
+ })
630
+ return b
631
+ }
632
+ },
633
+ ...mapValues(
634
+ spec.deployments ?? {},
635
+ ({ style: specStyle, ...spec }, kind) =>
636
+ <Id extends string>(
637
+ id: Id,
638
+ _props?: T['NewDeploymentNodeProps'] | string,
639
+ ): AddDeploymentNode<Id> => {
640
+ const add = (<T extends AnyTypes>(b: DeploymentModelBuilder<T>) => {
641
+ const {
642
+ links,
643
+ icon: _icon,
644
+ style,
645
+ title,
646
+ ...props
647
+ } = typeof _props === 'string' ? { title: _props } : { ..._props }
648
+
649
+ const icon = _icon ?? specStyle?.icon
650
+
651
+ const _id = b.__fqn(id)
652
+
653
+ b.__addDeployment({
654
+ id: _id,
655
+ kind: kind as any,
656
+ title: title ?? nameFromFqn(_id),
657
+ description: null,
658
+ technology: null,
659
+ tags: null,
660
+ color: specStyle?.color ?? DefaultThemeColor as Color,
661
+ shape: specStyle?.shape ?? DefaultElementShape as ElementShape,
662
+ style: pickBy({
663
+ border: specStyle?.border,
664
+ opacity: specStyle?.opacity,
665
+ ...style,
666
+ }, isNonNullish),
667
+ ...links && { links: mapLinks(links) },
668
+ ...icon && { icon: icon as IconUrl },
669
+ ...spec,
670
+ ...props,
671
+ })
672
+ return b
673
+ }) as AddDeploymentNode<Id>
674
+
675
+ add.with =
676
+ (...ops: Array<(input: DeploymentModelBuilder<any>) => DeploymentModelBuilder<any>>) =>
677
+ (b: DeploymentModelBuilder<any>) => {
678
+ add(b)
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
685
+ }
686
+ return b
687
+ }
688
+ return add
689
+ },
690
+ ) as AddDeploymentNodeHelpers<T>,
691
+ },
692
+ } as {
693
+ model: ModelHelpers<T>
694
+ views: ViewsHelpers
695
+ deployment: DeloymentModelHelpers<T>
559
696
  }),
560
697
  with: (...ops: ((b: Builder<T>) => Builder<T>)[]) => {
561
- return ops.reduce((b, op) => op(b), self).clone()
562
- }
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
+ },
563
720
  }
564
721
 
565
722
  return self
566
723
  }
567
724
 
568
725
  export namespace Builder {
726
+ export type Any = Builder<AnyTypes>
727
+
569
728
  export function forSpecification<const Spec extends BuilderSpecification>(
570
- spec: Spec
729
+ spec: Spec,
571
730
  ): {
572
731
  builder: Builder<Types.FromSpecification<Spec>>
573
732
  model: ModelHelpers<Types.FromSpecification<Spec>>
574
- views: ViewHelpers<Types.FromSpecification<Spec>['NewViewProps']>
733
+ deployment: DeloymentModelHelpers<Types.FromSpecification<Spec>>
734
+ views: ViewsHelpers
575
735
  } {
576
736
  const b = builder<Spec, Types.FromSpecification<Spec>>(spec)
577
737
  return {
578
738
  ...b.helpers(),
579
- builder: b
739
+ builder: b,
580
740
  }
581
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
+ }
582
748
  }