@likec4/core 1.31.0 → 1.32.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 (185) hide show
  1. package/README.md +407 -5
  2. package/dist/builder/index.d.mts +221 -42
  3. package/dist/builder/index.mjs +118 -65
  4. package/dist/compute-view/index.d.mts +23 -7
  5. package/dist/compute-view/index.mjs +11 -6
  6. package/dist/compute-view/relationships-view/index.d.mts +9 -7
  7. package/dist/compute-view/relationships-view/index.mjs +3 -2
  8. package/dist/index.d.mts +10 -14
  9. package/dist/index.mjs +9 -6
  10. package/dist/model/index.d.mts +173 -19
  11. package/dist/model/index.mjs +6 -1
  12. package/dist/shared/core.BaYE_r29.d.mts +258 -0
  13. package/dist/shared/core.Bk7wEZFG.mjs +276 -0
  14. package/dist/shared/core.BrCnZFTn.mjs +32 -0
  15. package/dist/shared/core.BuO4ncfY.d.mts +146 -0
  16. package/dist/shared/{core.Bq753SYD.mjs → core.CBpKAlhj.mjs} +2012 -4422
  17. package/dist/shared/core.CUYDgv2-.mjs +214 -0
  18. package/dist/shared/{core.Cu-UdkSl.mjs → core.CpXlRyE5.mjs} +7 -494
  19. package/dist/shared/{core.C-YXI-43.mjs → core.Cy9smucx.mjs} +3 -1
  20. package/dist/shared/core.CywrQs86.d.mts +31 -0
  21. package/dist/shared/core.DXzRBkuI.d.mts +1264 -0
  22. package/dist/shared/core.DoK86JEe.mjs +518 -0
  23. package/dist/shared/{core.D2830qgg.d.mts → core.Pf5I9o0e.d.mts} +1 -1
  24. package/dist/shared/core.cbA9VZ02.mjs +2681 -0
  25. package/dist/shared/{core.CQXU9DF7.mjs → core.rmvsy0n3.mjs} +23 -32
  26. package/dist/shared/core.znRaUX_A.d.mts +920 -0
  27. package/dist/types/aux.d.mts +3 -0
  28. package/dist/types/aux.mjs +1 -0
  29. package/dist/types/index.d.mts +7 -45
  30. package/dist/types/index.mjs +130 -3
  31. package/dist/utils/index.d.mts +221 -53
  32. package/dist/utils/index.mjs +14 -10
  33. package/package.json +16 -8
  34. package/src/builder/Builder.deploymentModel.ts +82 -18
  35. package/src/builder/Builder.element.ts +40 -20
  36. package/src/builder/Builder.model.ts +66 -17
  37. package/src/builder/Builder.ts +168 -76
  38. package/src/builder/Builder.view-common.ts +35 -17
  39. package/src/builder/Builder.view-deployment.ts +25 -25
  40. package/src/builder/Builder.view-element.ts +13 -12
  41. package/src/builder/Builder.views.ts +12 -7
  42. package/src/builder/__snapshots__/Builder-style1.spec.ts.snap +62 -34
  43. package/src/builder/__snapshots__/Builder-style2.compute-model.json5 +319 -0
  44. package/src/builder/__snapshots__/Builder-style2.spec.ts.snap +45 -24
  45. package/src/builder/_types.ts +34 -27
  46. package/src/compute-view/compute-view.ts +31 -34
  47. package/src/compute-view/deployment-view/__test__/TestHelper.ts +27 -14
  48. package/src/compute-view/deployment-view/__test__/fixture.ts +15 -13
  49. package/src/compute-view/deployment-view/_types.ts +10 -10
  50. package/src/compute-view/deployment-view/clean-connections.ts +5 -7
  51. package/src/compute-view/deployment-view/compute.ts +16 -13
  52. package/src/compute-view/deployment-view/memory/memory.ts +5 -6
  53. package/src/compute-view/deployment-view/predicates/deploymentRefs.ts +4 -5
  54. package/src/compute-view/deployment-view/predicates/relation-direct.ts +25 -50
  55. package/src/compute-view/deployment-view/predicates/relation-in-out.ts +5 -7
  56. package/src/compute-view/deployment-view/predicates/relation-incoming.ts +7 -11
  57. package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +7 -10
  58. package/src/compute-view/deployment-view/predicates/utils.ts +37 -31
  59. package/src/compute-view/deployment-view/predicates/wildcard.ts +3 -2
  60. package/src/compute-view/deployment-view/stages/stage-final.ts +2 -2
  61. package/src/compute-view/deployment-view/stages/stage-include.ts +1 -1
  62. package/src/compute-view/deployment-view/utils.ts +79 -72
  63. package/src/compute-view/dynamic-view/__test__/fixture.ts +20 -11
  64. package/src/compute-view/dynamic-view/compute.ts +60 -53
  65. package/src/compute-view/element-view/__test__/TestHelper.ts +53 -29
  66. package/src/compute-view/element-view/__test__/__snapshots__/legacy.spec.ts.snap +26 -26
  67. package/src/compute-view/element-view/__test__/fixture.ts +134 -83
  68. package/src/compute-view/element-view/_types.ts +14 -19
  69. package/src/compute-view/element-view/clean-connections.ts +12 -8
  70. package/src/compute-view/element-view/compute.ts +61 -51
  71. package/src/compute-view/element-view/memory/NodeGroup.ts +8 -9
  72. package/src/compute-view/element-view/memory/memory.ts +22 -22
  73. package/src/compute-view/element-view/memory/stage-include.ts +5 -3
  74. package/src/compute-view/element-view/predicates/_utils.ts +18 -14
  75. package/src/compute-view/element-view/predicates/element-expand.ts +4 -5
  76. package/src/compute-view/element-view/predicates/element-kind-tag.ts +3 -4
  77. package/src/compute-view/element-view/predicates/element-ref.ts +3 -4
  78. package/src/compute-view/element-view/predicates/relation-direct.ts +16 -12
  79. package/src/compute-view/element-view/predicates/relation-in-out.ts +7 -8
  80. package/src/compute-view/element-view/predicates/relation-in.ts +19 -26
  81. package/src/compute-view/element-view/predicates/relation-out.ts +20 -21
  82. package/src/compute-view/element-view/predicates/wildcard.ts +3 -3
  83. package/src/compute-view/element-view/utils.ts +25 -23
  84. package/src/compute-view/index.ts +1 -1
  85. package/src/compute-view/memory/AbstractStageExclude.ts +3 -4
  86. package/src/compute-view/memory/AbstractStageInclude.ts +1 -1
  87. package/src/compute-view/memory/_types.ts +3 -2
  88. package/src/compute-view/relationships-view/_types.ts +3 -4
  89. package/src/compute-view/relationships-view/compute.ts +8 -11
  90. package/src/compute-view/relationships-view/layout.ts +6 -6
  91. package/src/compute-view/relationships-view/utils.ts +4 -4
  92. package/src/compute-view/utils/ancestorsOfNode.ts +7 -7
  93. package/src/compute-view/utils/applyCustomElementProperties.ts +16 -8
  94. package/src/compute-view/utils/applyCustomRelationProperties.ts +19 -9
  95. package/src/compute-view/utils/applyViewRuleStyles.ts +18 -10
  96. package/src/compute-view/utils/buildComputedNodes.ts +40 -40
  97. package/src/compute-view/utils/buildElementNotations.ts +14 -14
  98. package/src/compute-view/utils/elementExpressionToPredicate.ts +14 -15
  99. package/src/compute-view/utils/link-nodes-with-edges.ts +6 -4
  100. package/src/compute-view/utils/merge-props-from-relationships.ts +52 -20
  101. package/src/compute-view/utils/relationExpressionToPredicates.ts +19 -19
  102. package/src/compute-view/utils/resolve-extended-views.ts +8 -7
  103. package/src/compute-view/utils/resolve-global-rules.ts +31 -26
  104. package/src/compute-view/utils/topological-sort.ts +14 -14
  105. package/src/compute-view/utils/view-hash.ts +2 -2
  106. package/src/compute-view/utils/with-readable-edges.ts +9 -5
  107. package/src/index.ts +0 -32
  108. package/src/model/DeploymentElementModel.ts +171 -144
  109. package/src/model/DeploymentModel.ts +88 -65
  110. package/src/model/ElementModel.ts +85 -74
  111. package/src/model/LikeC4Model.ts +430 -241
  112. package/src/model/RelationModel.ts +63 -29
  113. package/src/model/__test__/fixture.ts +50 -36
  114. package/src/model/connection/Connection.ts +2 -2
  115. package/src/model/connection/deployment/DeploymentConnectionModel.ts +21 -24
  116. package/src/model/connection/deployment/find.ts +1 -1
  117. package/src/model/connection/model/ConnectionModel.ts +21 -20
  118. package/src/model/connection/model/find.ts +7 -7
  119. package/src/model/connection/ops.ts +6 -6
  120. package/src/model/guards.ts +66 -14
  121. package/src/model/index.ts +20 -7
  122. package/src/model/types.ts +41 -97
  123. package/src/model/view/EdgeModel.ts +47 -41
  124. package/src/model/view/LikeC4ViewModel.ts +130 -80
  125. package/src/model/view/NodeModel.ts +102 -96
  126. package/src/theme/element.ts +1 -1
  127. package/src/theme/index.ts +9 -9
  128. package/src/theme/relationships.ts +1 -1
  129. package/src/types/_common.ts +21 -15
  130. package/src/types/aux.ts +285 -0
  131. package/src/types/const.ts +34 -0
  132. package/src/types/expression-model.ts +292 -0
  133. package/src/types/expression.ts +311 -0
  134. package/src/types/fqnRef.ts +88 -0
  135. package/src/types/geometry.ts +131 -0
  136. package/src/types/global.ts +10 -8
  137. package/src/types/index.ts +39 -201
  138. package/src/types/model-data.ts +52 -84
  139. package/src/types/model-deployment.ts +87 -0
  140. package/src/types/model-dump.ts +72 -0
  141. package/src/types/model-logical.ts +111 -0
  142. package/src/types/model-spec.ts +81 -0
  143. package/src/types/operators.ts +51 -52
  144. package/src/types/scalar.ts +114 -0
  145. package/src/types/{theme.ts → styles.ts} +55 -15
  146. package/src/types/view-changes.ts +4 -5
  147. package/src/types/view-common.ts +157 -0
  148. package/src/types/view-computed.ts +113 -0
  149. package/src/types/view-layouted.ts +82 -0
  150. package/src/types/view-parsed.deployment.ts +40 -0
  151. package/src/types/view-parsed.dynamic.ts +78 -0
  152. package/src/types/view-parsed.element.ts +65 -0
  153. package/src/types/view.ts +122 -542
  154. package/src/utils/compare-natural.ts +43 -1
  155. package/src/utils/getOrCreate.ts +0 -34
  156. package/src/utils/index.ts +7 -12
  157. package/src/utils/iterable/filter.ts +1 -1
  158. package/src/utils/iterable/find.ts +3 -1
  159. package/src/utils/iterable/head.ts +22 -0
  160. package/src/utils/iterable/index.ts +1 -0
  161. package/src/utils/iterable/map.ts +1 -1
  162. package/src/utils/iterable/reduce.ts +1 -1
  163. package/src/utils/iterable/some.ts +1 -1
  164. package/src/utils/memoize-prop.ts +30 -0
  165. package/src/utils/object-hash.ts +1 -1
  166. package/src/utils/relations.ts +14 -11
  167. package/src/utils/string-hash.ts +1 -1
  168. package/dist/shared/core.CQDU11hR.d.mts +0 -753
  169. package/dist/shared/core.DJvmfnEi.d.mts +0 -1153
  170. package/dist/shared/core.DgfwjBtu.mjs +0 -495
  171. package/dist/shared/core.Dx7siloV.d.mts +0 -146
  172. package/dist/shared/core.SjLhMA7a.d.mts +0 -62
  173. package/src/builder/__snapshots__/Builder.spec.ts.snap +0 -374
  174. package/src/compute-view/element-view/predicates.ts +0 -520
  175. package/src/compute-view/utils/uniqueTags.ts +0 -21
  176. package/src/types/deployments.ts +0 -170
  177. package/src/types/element.ts +0 -109
  178. package/src/types/expression-v2-model.ts +0 -314
  179. package/src/types/expression-v2.ts +0 -392
  180. package/src/types/overview-graph.ts +0 -43
  181. package/src/types/relation.ts +0 -61
  182. package/src/types/scalars.ts +0 -39
  183. package/src/types/view-notation.ts +0 -9
  184. package/src/utils/graphlib.ts +0 -10
  185. /package/src/{errors/index.ts → utils/invariant.ts} +0 -0
@@ -1,15 +1,33 @@
1
1
  import defu from 'defu'
2
- import { fromEntries, hasAtLeast, isFunction, isNonNullish, isNullish, map, mapToObj, mapValues, pickBy } from 'remeda'
2
+ import {
3
+ entries,
4
+ fromEntries,
5
+ hasAtLeast,
6
+ isFunction,
7
+ isNonNullish,
8
+ isNullish,
9
+ map,
10
+ mapToObj,
11
+ mapValues,
12
+ pickBy,
13
+ } from 'remeda'
3
14
  import type { Writable } from 'type-fest'
4
- import { invariant } from '../errors'
15
+ import { computeLikeC4Model } from '../compute-view/compute-view'
5
16
  import { LikeC4Model } from '../model/LikeC4Model'
17
+ import type {
18
+ Any,
19
+ DeployedInstance,
20
+ DeploymentFqn,
21
+ ParsedElementView,
22
+ ParsedLikeC4ModelData,
23
+ Specification,
24
+ } from '../types'
6
25
  import {
7
26
  type Color,
27
+ type DeploymentElement,
8
28
  type DeploymentRelation,
9
- type DeploymentView,
10
29
  type Element,
11
30
  type ElementShape,
12
- type ElementView,
13
31
  type Fqn,
14
32
  type IconUrl,
15
33
  type LikeC4View,
@@ -17,13 +35,17 @@ import {
17
35
  type ModelGlobals,
18
36
  type ModelRelation,
19
37
  type NonEmptyArray,
38
+ type ParsedDeploymentView as DeploymentView,
20
39
  type RelationId,
21
- type Tag,
40
+ _stage,
41
+ _type,
22
42
  DefaultElementShape,
23
43
  DefaultThemeColor,
24
- DeploymentElement,
25
- isScopedElementView,
44
+ FqnRef,
45
+ isDeployedInstance,
46
+ isElementView,
26
47
  } from '../types'
48
+ import { invariant } from '../utils'
27
49
  import { isSameHierarchy, nameFromFqn, parentFqn } from '../utils/fqn'
28
50
  import type { AnyTypes, BuilderSpecification, Types } from './_types'
29
51
  import type { AddDeploymentNode } from './Builder.deployment'
@@ -97,10 +119,11 @@ export interface Builder<T extends AnyTypes> extends BuilderMethods<T> {
97
119
  * )
98
120
  * )
99
121
  *
122
+ * @example
100
123
  * builder.deployment((_,d) =>
101
124
  * d(
102
125
  * _.node('node1'),
103
- * _.node('node1.child1').with(
126
+ * _.node('node1.child1').with(
104
127
  * _.instanceOf('model.element')
105
128
  * )
106
129
  * )
@@ -114,11 +137,34 @@ export interface Builder<T extends AnyTypes> extends BuilderMethods<T> {
114
137
  * Adds views
115
138
  *
116
139
  * @example
117
- * builder.views(({ view, $include }, _) =>
140
+ * builder.views(({ view, viewOf, deploymentView, $include, $style, $rules }, _) =>
118
141
  * _(
119
- * view('index').with(
142
+ * view('view1').with(
143
+ * $include('a -> b'),
144
+ * ),
145
+ * view('view2', {
146
+ * title: 'View 2',
147
+ * }).with(
148
+ * $include('*')
149
+ * ),
150
+ * view(
151
+ * 'view3',
152
+ * {
153
+ * title: 'View 3',
154
+ * },
155
+ * $rules(
156
+ * $include('*'),
157
+ * $style(['*', 'alice'], {
158
+ * color: 'red',
159
+ * }),
160
+ * ),
161
+ * ),
162
+ * viewOf('viewOfA', 'a').with(
163
+ * $include('*')
164
+ * ),
165
+ * deploymentView('deploymentView1').with(
120
166
  * $include('a -> b')
121
- * )
167
+ * ),
122
168
  * )
123
169
  * )
124
170
  */
@@ -131,12 +177,12 @@ export interface Builder<T extends AnyTypes> extends BuilderMethods<T> {
131
177
  * Views are not computed or layouted
132
178
  * {@link toLikeC4Model} should be used to get model with computed views
133
179
  */
134
- build(): Types.ToParsedLikeC4Model<T>
180
+ build(): ParsedLikeC4ModelData<Types.ToAux<T>>
135
181
 
136
182
  /**
137
- * Returns LikeC4Model with computed views
183
+ * Returns Computed LikeC4Model
138
184
  */
139
- toLikeC4Model(): Types.ToLikeC4Model<T>
185
+ toLikeC4Model(): LikeC4Model.Computed<Types.ToAux<T>>
140
186
  }
141
187
 
142
188
  interface Internals<T extends AnyTypes> extends ViewsBuilder<T>, ModelBuilder<T>, DeploymentModelBuilder<T> {
@@ -144,9 +190,31 @@ interface Internals<T extends AnyTypes> extends ViewsBuilder<T>, ModelBuilder<T>
144
190
 
145
191
  type Op<T> = (b: T) => T
146
192
 
193
+ function validateSpec(specification: BuilderSpecification) {
194
+ for (const [kind, spec] of entries(specification.elements)) {
195
+ if (spec.tags) {
196
+ for (const tag of spec.tags) {
197
+ invariant(specification.tags?.[tag], `Invalid specification for element kind "${kind}": tag "${tag}" not found`)
198
+ }
199
+ }
200
+ }
201
+ if (specification.deployments) {
202
+ for (const [kind, spec] of entries(specification.deployments)) {
203
+ if (spec.tags) {
204
+ for (const tag of spec.tags) {
205
+ invariant(
206
+ specification.tags?.[tag],
207
+ `Invalid specification for deployment kind "${kind}": tag "${tag}" not found`,
208
+ )
209
+ }
210
+ }
211
+ }
212
+ }
213
+ }
214
+
147
215
  function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
148
216
  spec: Spec,
149
- _elements = new Map<string, Element>(),
217
+ _elements = new Map<string, Element<Any>>(),
150
218
  _relations = [] as ModelRelation[],
151
219
  _views = new Map<string, LikeC4View>(),
152
220
  _globals = {
@@ -157,18 +225,26 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
157
225
  _deployments = new Map<string, DeploymentElement>(),
158
226
  _deploymentRelations = [] as DeploymentRelation[],
159
227
  ): Builder<T> {
160
- const toLikeC4Specification = (): Types.ToParsedLikeC4Model<T>['specification'] => ({
161
- elements: {
162
- ...structuredClone(spec.elements) as any,
163
- },
164
- deployments: {
165
- ...structuredClone(spec.deployments) as any,
166
- },
167
- relationships: {
168
- ...structuredClone(spec.relationships) as any,
169
- },
170
- tags: (spec.tags ?? []) as Tag<T['Tag']>[],
171
- })
228
+ const toLikeC4Specification = (): Specification<Types.ToAux<T>> => {
229
+ validateSpec(spec)
230
+ return ({
231
+ elements: {
232
+ ...structuredClone(spec.elements) as any,
233
+ },
234
+ deployments: {
235
+ ...structuredClone(spec.deployments) as any,
236
+ },
237
+ relationships: {
238
+ ...structuredClone(spec.relationships) as any,
239
+ },
240
+ tags: mapValues(spec.tags ?? {}, (tagSpec) => ({
241
+ color: DefaultThemeColor,
242
+ ...tagSpec,
243
+ })) as any,
244
+ ...(!!spec.metadataKeys ? { metadataKeys: spec.metadataKeys as any } : {}),
245
+ customColors: {},
246
+ } as Specification<Types.ToAux<T>>)
247
+ }
172
248
 
173
249
  const mapLinks = (links?: Array<string | { title?: string; url: string }>): NonEmptyArray<Link> | null => {
174
250
  if (!links || !hasAtLeast(links, 1)) {
@@ -181,7 +257,7 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
181
257
  id: string,
182
258
  _props: T['NewViewProps'] | string | B | null,
183
259
  builder: B,
184
- ): [Omit<LikeC4View, 'rules'>, B] => {
260
+ ): [Omit<LikeC4View, 'rules' | '_type'>, B] => {
185
261
  if (isFunction(_props)) {
186
262
  builder = _props as B
187
263
  _props = {}
@@ -191,7 +267,7 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
191
267
  links: _links = [],
192
268
  title = null,
193
269
  description = null,
194
- tags = null,
270
+ tags = [],
195
271
  ...props
196
272
  } = typeof _props === 'string' ? { title: _props } : { ..._props }
197
273
 
@@ -202,7 +278,8 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
202
278
  description,
203
279
  tags,
204
280
  links,
205
- customColorDefinitions: {},
281
+ _stage: 'parsed',
282
+ // customColorDefinitions: {},
206
283
  ...props,
207
284
  }, builder]
208
285
  }
@@ -238,9 +315,9 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
238
315
  return self
239
316
  },
240
317
  __addRelation(relation) {
241
- const sourceEl = _elements.get(relation.source)
318
+ const sourceEl = _elements.get(FqnRef.flatten(relation.source))
242
319
  invariant(sourceEl, `Element with id "${relation.source}" not found`)
243
- const targetEl = _elements.get(relation.target)
320
+ const targetEl = _elements.get(FqnRef.flatten(relation.target))
244
321
  invariant(targetEl, `Element with id "${relation.target}" not found`)
245
322
  invariant(
246
323
  !isSameHierarchy(sourceEl, targetEl),
@@ -252,13 +329,14 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
252
329
  })
253
330
  return self
254
331
  },
255
- /**
256
- * Fully qualified name for nested elements
257
- */
258
332
  __fqn(id) {
259
333
  invariant(id.trim() !== '', 'Id must be non-empty')
260
334
  return id as Fqn
261
335
  },
336
+ __deploymentFqn(id) {
337
+ invariant(id.trim() !== '', 'Id must be non-empty')
338
+ return id as DeploymentFqn
339
+ },
262
340
  __addSourcelessRelation() {
263
341
  throw new Error('Can be called only in nested model')
264
342
  },
@@ -266,7 +344,7 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
266
344
  if (_views.has(view.id)) {
267
345
  throw new Error(`View with id "${view.id}" already exists`)
268
346
  }
269
- if (isScopedElementView(view)) {
347
+ if (isElementView(view) && 'viewOf' in view) {
270
348
  invariant(
271
349
  _elements.get(view.viewOf),
272
350
  `Invalid scoped view ${view.id}, wlement with id "${view.viewOf}" not found`,
@@ -287,7 +365,7 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
287
365
  `Parent element with id "${parent}" not found for node with id "${node.id}"`,
288
366
  )
289
367
  }
290
- if (DeploymentElement.isInstance(node)) {
368
+ if (isDeployedInstance(node)) {
291
369
  invariant(parent, `Instance ${node.id} of ${node.element} must be deployed under a parent node`)
292
370
  invariant(
293
371
  _elements.get(node.element),
@@ -299,17 +377,17 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
299
377
  },
300
378
  __addDeploymentRelation: (relation) => {
301
379
  invariant(
302
- !isSameHierarchy(relation.source.id, relation.target.id),
380
+ !isSameHierarchy(relation.source.deployment, relation.target.deployment),
303
381
  'Cannot create relationship between elements in the same hierarchy',
304
382
  )
305
383
 
306
384
  invariant(
307
- _deployments.has(relation.source.id),
308
- `Relation "${relation.source.id} -> ${relation.target.id}" references non-existing source`,
385
+ _deployments.has(relation.source.deployment),
386
+ `Relation "${relation.source.deployment} -> ${relation.target.deployment}" references non-existing source`,
309
387
  )
310
388
  invariant(
311
- _deployments.has(relation.target.id),
312
- `Relation "${relation.source.id} -> ${relation.target.id}" references non-existing target`,
389
+ _deployments.has(relation.target.deployment),
390
+ `Relation "${relation.source.deployment} -> ${relation.target.deployment}" references non-existing target`,
313
391
  )
314
392
 
315
393
  _deploymentRelations.push({
@@ -319,6 +397,8 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
319
397
  return self
320
398
  },
321
399
  build: () => ({
400
+ [_stage]: 'parsed',
401
+ projectId: 'from-builder',
322
402
  specification: toLikeC4Specification(),
323
403
  elements: fromEntries(
324
404
  structuredClone(
@@ -344,7 +424,7 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
344
424
  } as any),
345
425
  toLikeC4Model: () => {
346
426
  const parsed = self.build()
347
- return LikeC4Model.compute(parsed)
427
+ return computeLikeC4Model(parsed)
348
428
  },
349
429
  helpers: () => ({
350
430
  model: {
@@ -353,7 +433,7 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
353
433
  return ops.reduce((b, op) => op(b), b as any as ModelBuilder<T>) as any
354
434
  }
355
435
  },
356
- rel: (source: string, target: string, _props?: T['NewRelationshipProps'] | string) => {
436
+ rel: (source, target, _props?) => {
357
437
  return <T extends AnyTypes>(b: ModelBuilder<T>) => {
358
438
  const {
359
439
  title = '',
@@ -365,8 +445,12 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
365
445
  )
366
446
  const links = mapLinks(_links)
367
447
  b.__addRelation({
368
- source: source as any,
369
- target: target as any,
448
+ source: {
449
+ model: source,
450
+ },
451
+ target: {
452
+ model: target,
453
+ },
370
454
  title,
371
455
  ...(links && { links }),
372
456
  ...props,
@@ -386,7 +470,9 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
386
470
  )
387
471
  const links = mapLinks(_links)
388
472
  b.__addSourcelessRelation({
389
- target,
473
+ target: {
474
+ model: target,
475
+ },
390
476
  title,
391
477
  ...(links && { links }),
392
478
  ...props,
@@ -422,7 +508,7 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
422
508
  title: title ?? nameFromFqn(_id),
423
509
  description: null,
424
510
  technology: null,
425
- tags: null,
511
+ tags: [],
426
512
  color: specStyle?.color ?? DefaultThemeColor as Color,
427
513
  shape: specStyle?.shape ?? DefaultElementShape as ElementShape,
428
514
  style: pickBy({
@@ -449,7 +535,9 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
449
535
  b.__addSourcelessRelation = (relation) => {
450
536
  return b.__addRelation({
451
537
  ...relation,
452
- source: __fqn(id),
538
+ source: {
539
+ model: __fqn(id),
540
+ },
453
541
  })
454
542
  }
455
543
  ops.reduce((b, op) => op(b), b as any as ModelBuilder<T>) as any
@@ -476,9 +564,9 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
476
564
  _builder?: ElementViewRulesBuilder<any>,
477
565
  ) => {
478
566
  const [generic, builder] = createGenericView(id, _props, _builder)
479
- const view: Writable<ElementView> = {
567
+ const view: Writable<ParsedElementView> = {
480
568
  ...generic,
481
- __: 'element',
569
+ [_type]: 'element',
482
570
  rules: [],
483
571
  }
484
572
 
@@ -507,10 +595,10 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
507
595
  _builder?: ElementViewRulesBuilder<any>,
508
596
  ) => {
509
597
  const [generic, builder] = createGenericView(id, _props, _builder)
510
- const view: Writable<ElementView> = {
598
+ const view: Writable<ParsedElementView> = {
511
599
  ...generic,
512
600
  viewOf: viewOf as Fqn,
513
- __: 'element',
601
+ [_type]: 'element',
514
602
  rules: [],
515
603
  }
516
604
 
@@ -542,7 +630,7 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
542
630
  const [generic, builder] = createGenericView(id, _props, _builder)
543
631
  const view: Writable<DeploymentView> = {
544
632
  ...generic,
545
- __: 'deployment',
633
+ [_type]: 'deployment',
546
634
  rules: [],
547
635
  }
548
636
 
@@ -600,34 +688,34 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
600
688
  title,
601
689
  ...props
602
690
  } = typeof _props === 'string' ? { title: _props } : { ..._props }
603
- const _id = b.__fqn(id)
691
+ const _id = b.__deploymentFqn(id)
604
692
  invariant(_elements.has(target), `Target element with id "${target}" not found`)
605
693
  b.__addDeployment({
606
694
  id: _id,
607
- element: target as any,
695
+ element: target as Fqn,
608
696
  ...title && { title },
609
697
  ...links && { links: mapLinks(links) },
610
698
  ...props,
611
- })
699
+ } as DeployedInstance)
612
700
  return b as any
613
701
  }
614
702
  },
615
703
  rel: (source: string, target: string, _props?: T['NewRelationshipProps'] | string) => {
616
704
  return <T extends AnyTypes>(b: DeploymentModelBuilder<T>) => {
617
705
  const {
618
- title,
706
+ title = null,
619
707
  links,
620
708
  ...props
621
709
  } = typeof _props === 'string' ? { title: _props } : { ..._props }
622
710
 
623
711
  b.__addDeploymentRelation({
624
712
  source: {
625
- id: source as any,
713
+ deployment: source as any,
626
714
  },
627
715
  target: {
628
- id: target as any,
716
+ deployment: target as any,
629
717
  },
630
- ...title && { title },
718
+ title,
631
719
  ...links && { links: mapLinks(links) },
632
720
  ...props,
633
721
  })
@@ -652,7 +740,7 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
652
740
 
653
741
  const icon = _icon ?? specStyle?.icon
654
742
 
655
- const _id = b.__fqn(id)
743
+ const _id = b.__deploymentFqn(id)
656
744
 
657
745
  b.__addDeployment({
658
746
  id: _id,
@@ -661,18 +749,20 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
661
749
  description: null,
662
750
  technology: null,
663
751
  tags: null,
664
- color: specStyle?.color ?? DefaultThemeColor as Color,
665
- shape: specStyle?.shape ?? DefaultElementShape as ElementShape,
666
- style: pickBy({
667
- border: specStyle?.border,
668
- opacity: specStyle?.opacity,
669
- size: specStyle?.size,
670
- padding: specStyle?.padding,
671
- textSize: specStyle?.textSize,
672
- ...style,
673
- }, isNonNullish),
752
+ style: {
753
+ ...icon && { icon: icon as IconUrl },
754
+ color: specStyle?.color ?? DefaultThemeColor as Color,
755
+ shape: specStyle?.shape ?? DefaultElementShape as ElementShape,
756
+ ...pickBy({
757
+ border: specStyle?.border,
758
+ opacity: specStyle?.opacity,
759
+ size: specStyle?.size,
760
+ padding: specStyle?.padding,
761
+ textSize: specStyle?.textSize,
762
+ ...style,
763
+ }, isNonNullish),
764
+ },
674
765
  ...links && { links: mapLinks(links) },
675
- ...icon && { icon: icon as IconUrl },
676
766
  ...spec,
677
767
  ...props,
678
768
  })
@@ -683,12 +773,12 @@ function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
683
773
  (...ops: Array<(input: DeploymentModelBuilder<any>) => DeploymentModelBuilder<any>>) =>
684
774
  (b: DeploymentModelBuilder<any>) => {
685
775
  add(b)
686
- const { __fqn } = b
776
+ const { __deploymentFqn } = b
687
777
  try {
688
- b.__fqn = (child) => `${__fqn(id)}.${child}` as Fqn
778
+ b.__deploymentFqn = (child) => `${__deploymentFqn(id)}.${child}` as DeploymentFqn
689
779
  ops.reduce((b, op) => op(b), b as any as DeploymentModelBuilder<T>) as any
690
780
  } finally {
691
- b.__fqn = __fqn
781
+ b.__deploymentFqn = __deploymentFqn
692
782
  }
693
783
  return b
694
784
  }
@@ -740,6 +830,7 @@ export namespace Builder {
740
830
  deployment: DeloymentModelHelpers<Types.FromSpecification<Spec>>
741
831
  views: ViewsHelpers
742
832
  } {
833
+ validateSpec(spec)
743
834
  const b = builder<Spec, Types.FromSpecification<Spec>>(spec)
744
835
  return {
745
836
  ...b.helpers(),
@@ -750,6 +841,7 @@ export namespace Builder {
750
841
  export function specification<const Spec extends BuilderSpecification>(
751
842
  spec: Spec,
752
843
  ): Builder<Types.FromSpecification<Spec>> {
844
+ validateSpec(spec)
753
845
  return builder<Spec, Types.FromSpecification<Spec>>(spec)
754
846
  }
755
847
  }
@@ -1,14 +1,17 @@
1
1
  import { isArray, isString, map } from 'remeda'
2
2
  import type { LiteralUnion, Simplify } from 'type-fest'
3
3
  import {
4
+ type Any,
5
+ type AnyAux,
6
+ type AnyViewRuleStyle as ViewRuleStyle,
4
7
  type AutoLayoutDirection,
5
- type ExpressionV2,
8
+ type Expression,
9
+ type ModelRelationExpr,
6
10
  type NonEmptyArray,
7
- type ViewRuleStyle,
8
11
  type WhereOperator,
12
+ ModelFqnExpr,
9
13
  } from '../types'
10
- import { ModelLayer } from '../types/expression-v2-model'
11
- import type { KindEqual, Participant, TagEqual } from '../types/operators'
14
+ import type { Participant, ParticipantOperator } from '../types/operators'
12
15
  import type { AnyTypes, Types } from './_types'
13
16
 
14
17
  export interface LikeC4ViewBuilder<
@@ -25,7 +28,7 @@ export interface LikeC4ViewBuilder<
25
28
  $expr(expr: Expr | TypedExpr): TypedExpr
26
29
  include(...exprs: Expr[]): this
27
30
  exclude(...exprs: Expr[]): this
28
- style(rule: ViewRuleStyle): this
31
+ style(rule: ViewRuleStyle<any>): this
29
32
  autoLayout(layout: AutoLayoutDirection): this
30
33
  }
31
34
 
@@ -85,7 +88,7 @@ export namespace ViewPredicate {
85
88
  where?: ViewPredicate.WhereOperator<Types>
86
89
  with?: Simplify<
87
90
  Omit<
88
- ModelLayer.FqnExpr.Custom['custom'] & ModelLayer.RelationExpr.Custom['customRelation'],
91
+ ModelFqnExpr.Custom['custom'] & ModelRelationExpr.Custom['customRelation'],
89
92
  'expr' | 'relation' | 'navigateTo'
90
93
  > & {
91
94
  navigateTo?: Types['ViewId']
@@ -94,7 +97,7 @@ export namespace ViewPredicate {
94
97
  }
95
98
  }
96
99
 
97
- function parseWhere(where: ViewPredicate.WhereOperator<AnyTypes>): WhereOperator<any, any> {
100
+ function parseWhere(where: ViewPredicate.WhereOperator<AnyTypes>): WhereOperator<Any> {
98
101
  if (isString(where)) {
99
102
  const op = where as LiteralUnion<ViewPredicate.WhereEq<AnyTypes>, string>
100
103
  switch (true) {
@@ -124,16 +127,16 @@ function parseWhere(where: ViewPredicate.WhereOperator<AnyTypes>): WhereOperator
124
127
  }
125
128
  case op.startsWith('source.'):
126
129
  return {
127
- operator: parseWhere(op.replace('source.', '') as ViewPredicate.WhereOperator<AnyTypes>) as
128
- | KindEqual<string>
129
- | TagEqual<string>,
130
+ operator: parseWhere(
131
+ op.replace('source.', '') as ViewPredicate.WhereOperator<AnyTypes>,
132
+ ) as ParticipantOperator<AnyAux>['operator'],
130
133
  participant: 'source',
131
134
  }
132
135
  case op.startsWith('target.'):
133
136
  return {
134
- operator: parseWhere(op.replace('target.', '') as ViewPredicate.WhereOperator<AnyTypes>) as
135
- | KindEqual<string>
136
- | TagEqual<string>,
137
+ operator: parseWhere(
138
+ op.replace('target.', '') as ViewPredicate.WhereOperator<AnyTypes>,
139
+ ) as ParticipantOperator<AnyAux>['operator'],
137
140
  participant: 'target',
138
141
  }
139
142
  default:
@@ -181,7 +184,7 @@ function $include<B extends LikeC4ViewBuilder<AnyTypes, any, any>>(
181
184
 
182
185
  const custom = args[1].with
183
186
  if (custom) {
184
- const isElement = ModelLayer.FqnExpr.is(expr)
187
+ const isElement = ModelFqnExpr.is(expr)
185
188
  if (isElement) {
186
189
  expr = {
187
190
  custom: {
@@ -212,7 +215,7 @@ function $exclude<B extends LikeC4ViewBuilder<AnyTypes, any, any>>(
212
215
  | [B['TypedExpr'], ViewPredicate.Custom<B['Types']>]
213
216
  ): (b: B) => B {
214
217
  return (b) => {
215
- let expr = b.$expr(args[0]) as ExpressionV2
218
+ let expr = b.$expr(args[0]) as Expression
216
219
  if (args.length === 2 && args[1].where) {
217
220
  const condition = parseWhere(args[1].where)
218
221
  expr = {
@@ -227,13 +230,28 @@ function $exclude<B extends LikeC4ViewBuilder<AnyTypes, any, any>>(
227
230
  }
228
231
  }
229
232
 
233
+ /**
234
+ * @example
235
+ * builder.views(({ view, $style }, _) =>
236
+ * _(
237
+ * view('view1').with(
238
+ * $style('*', {
239
+ * color: 'red',
240
+ * }),
241
+ * $style(['bob', 'alice'], {
242
+ * color: 'blue',
243
+ * }),
244
+ * ),
245
+ * )
246
+ * )
247
+ */
230
248
  function $style<B extends LikeC4ViewBuilder<AnyTypes, any, any>>(
231
249
  element: B['ElementExpr'] | B['TypedExpr'] | NonEmptyArray<B['ElementExpr']>,
232
- { notation, ...style }: ViewRuleStyle['style'] & { notation?: string },
250
+ { notation, ...style }: ViewRuleStyle<any>['style'] & { notation?: string },
233
251
  ): (b: B) => B {
234
252
  return (b) =>
235
253
  b.style({
236
- targets: (isArray(element) ? element : [element]).map(e => b.$expr(e as any) as ModelLayer.FqnExpr),
254
+ targets: (isArray(element) ? element : [element]).map(e => b.$expr(e as any) as ModelFqnExpr),
237
255
  ...(notation ? { notation } : {}),
238
256
  style: {
239
257
  ...style,