@likec4/core 1.41.0 → 1.42.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 (255) hide show
  1. package/builder/package.json +4 -0
  2. package/compute-view/package.json +4 -0
  3. package/compute-view/relationships/package.json +4 -0
  4. package/dist/builder/index.d.mts +13 -11
  5. package/dist/builder/index.mjs +111 -91
  6. package/dist/compute-view/index.d.mts +8 -7
  7. package/dist/compute-view/index.mjs +14 -11
  8. package/dist/compute-view/relationships-view/index.d.mts +9 -8
  9. package/dist/compute-view/relationships-view/index.mjs +6 -6
  10. package/dist/index.d.mts +7 -7
  11. package/dist/index.mjs +11 -11
  12. package/dist/model/connection/deployment/index.d.mts +11 -10
  13. package/dist/model/connection/deployment/index.mjs +2 -2
  14. package/dist/model/connection/index.d.mts +12 -11
  15. package/dist/model/connection/index.mjs +3 -3
  16. package/dist/model/connection/model/index.d.mts +11 -10
  17. package/dist/model/connection/model/index.mjs +2 -2
  18. package/dist/model/index.d.mts +14 -14
  19. package/dist/model/index.mjs +4 -5
  20. package/dist/shared/{core.Ae86Y3tB.mjs → core.01VTr9qu.mjs} +8 -26
  21. package/dist/shared/core.1vX5a9AY.mjs +86 -0
  22. package/dist/shared/{core.BVNaR17u.mjs → core.B7KhhkRY.mjs} +1 -1
  23. package/dist/shared/core.B85MJLTf.mjs +5 -0
  24. package/dist/shared/{core.DA5vzwZ9.mjs → core.BIqHjQiH.mjs} +56 -42
  25. package/dist/shared/core.BKlholso.mjs +3 -0
  26. package/dist/shared/core.BR4zXDH-.mjs +13 -0
  27. package/dist/shared/{core.CXy1NLUG.mjs → core.BYNkXQ8A.mjs} +21 -12
  28. package/dist/shared/{core.BuoXfSMj.mjs → core.BbE4y-yl.mjs} +1 -1
  29. package/dist/shared/core.BoYfZOBm.mjs +3 -0
  30. package/dist/shared/core.BsSXS-_R.mjs +7 -0
  31. package/dist/shared/{core.DJp8fgok.mjs → core.BzTakU3I.mjs} +14 -10
  32. package/dist/shared/{core.4u1dVmfX.mjs → core.C2TiyjI6.mjs} +2 -2
  33. package/dist/shared/{core.DLpidoWc.mjs → core.C3JowhaZ.mjs} +3 -3
  34. package/dist/shared/{core.CNGyqkJh.mjs → core.C4x8aaWa.mjs} +3 -1
  35. package/dist/shared/{core.BB6zA-UU.mjs → core.C8YY6Uub.mjs} +38 -9
  36. package/dist/shared/{core.Asc11Mjy.mjs → core.C8sl5Y8Z.mjs} +122 -58
  37. package/dist/shared/{core.BvMRMo7Z.mjs → core.CNgZvKb8.mjs} +3 -5198
  38. package/dist/shared/{core.CUG6vpyL.d.mts → core.CQngdcuj.d.mts} +85 -4
  39. package/dist/shared/{core.Be1n9a0i.mjs → core.C_Ni6yHl.mjs} +5 -4
  40. package/dist/shared/core.CbT8JVYL.mjs +5 -0
  41. package/dist/shared/core.CqAJJpK_.mjs +3 -0
  42. package/dist/shared/{core.BXsxn-hf.d.mts → core.D0PjZzIS.d.mts} +27 -15
  43. package/dist/shared/{core.DgesAwC8.d.mts → core.D5fzJWbF.d.mts} +2 -2
  44. package/dist/shared/{core.hfOE3RfK.d.mts → core.DACpKp35.d.mts} +5 -5
  45. package/dist/shared/core.DFi2dOTl.mjs +39548 -0
  46. package/dist/shared/{core.xSQO0XYD.d.mts → core.DIol3syK.d.mts} +2 -2
  47. package/dist/shared/{core.DlG1xWt2.mjs → core.DMMOWQqc.mjs} +3 -2
  48. package/dist/shared/core.DNbUPnve.mjs +3990 -0
  49. package/dist/shared/{core.CCD1ID81.mjs → core.DRJma0Ol.mjs} +4 -3
  50. package/dist/shared/{core.DgttqsJc.mjs → core.DRhg-gVU.mjs} +9 -9
  51. package/dist/shared/core.DSO_rTC2.mjs +5322 -0
  52. package/dist/shared/{core.FUPplpae.d.mts → core.D_vkffV4.d.mts} +4 -2
  53. package/dist/shared/core.DdMJk7nx.d.mts +476 -0
  54. package/dist/shared/{core.BhpgpOep.d.mts → core.Dgs6-nuz.d.mts} +2 -2
  55. package/dist/shared/{core.Be4Jy9Qx.mjs → core.FZ305VYd.mjs} +2 -2
  56. package/dist/shared/core.OHD4KXm9.mjs +5 -0
  57. package/dist/shared/{core.GTgsmXS_.mjs → core.QJD_fcrc.mjs} +2 -2
  58. package/dist/shared/core.RfnaEmgA.mjs +7 -0
  59. package/dist/shared/core.fHR_8Tnq.d.mts +450 -0
  60. package/dist/shared/{core.D0EgVMQK.mjs → core.lRvxPoao.mjs} +14 -12
  61. package/dist/shared/{core.CaT0SUUK.mjs → core.rCeaAqgW.mjs} +1 -84
  62. package/dist/shared/{core.zxTBF_PD.d.mts → core.s9uwOt60.d.mts} +4 -4
  63. package/dist/shared/core.yna0OdV5.d.mts +98 -0
  64. package/dist/styles/index.d.mts +106 -0
  65. package/dist/styles/index.mjs +1 -0
  66. package/dist/types/_aux.d.mts +2 -2
  67. package/dist/types/expression-model.d.mts +3 -4
  68. package/dist/types/expression.d.mts +3 -4
  69. package/dist/types/fqnRef.d.mts +2 -2
  70. package/dist/types/fqnRef.mjs +3 -3
  71. package/dist/types/index.d.mts +8 -8
  72. package/dist/types/index.mjs +150 -5
  73. package/dist/types/scalar.mjs +3 -2
  74. package/dist/utils/graphology/index.d.mts +1864 -0
  75. package/dist/utils/graphology/index.mjs +1 -0
  76. package/dist/utils/index.d.mts +11 -6
  77. package/dist/utils/index.mjs +21 -37
  78. package/dist/utils/iterable/index.d.mts +1 -1
  79. package/dist/utils/iterable/index.mjs +45 -7
  80. package/model/package.json +4 -0
  81. package/package.json +42 -24
  82. package/styles/package.json +4 -0
  83. package/types/package.json +4 -0
  84. package/utils/graphology/package.json +4 -0
  85. package/utils/package.json +4 -0
  86. package/dist/shared/core.6_Vp2iiN.mjs +0 -172
  87. package/dist/shared/core.CUw_2J9j.mjs +0 -47
  88. package/dist/shared/core.CzdwsPmY.d.mts +0 -69
  89. package/dist/shared/core.D-ZGWDDt.d.mts +0 -831
  90. package/dist/shared/core.DoM6aM9N.mjs +0 -7
  91. package/dist/shared/core.ILwny7BV.mjs +0 -38
  92. package/dist/theme/index.d.mts +0 -11
  93. package/dist/theme/index.mjs +0 -232
  94. package/src/builder/Builder.deployment.ts +0 -224
  95. package/src/builder/Builder.deploymentModel.ts +0 -449
  96. package/src/builder/Builder.element.ts +0 -241
  97. package/src/builder/Builder.model.ts +0 -494
  98. package/src/builder/Builder.ts +0 -946
  99. package/src/builder/Builder.view-common.ts +0 -273
  100. package/src/builder/Builder.view-deployment.ts +0 -135
  101. package/src/builder/Builder.view-element.ts +0 -202
  102. package/src/builder/Builder.views.ts +0 -399
  103. package/src/builder/Builder.with.ts +0 -156
  104. package/src/builder/_types.ts +0 -324
  105. package/src/builder/index.ts +0 -11
  106. package/src/compute-view/compute-view.ts +0 -80
  107. package/src/compute-view/deployment-view/_types.ts +0 -38
  108. package/src/compute-view/deployment-view/clean-connections.ts +0 -236
  109. package/src/compute-view/deployment-view/compute.ts +0 -94
  110. package/src/compute-view/deployment-view/memory/index.ts +0 -9
  111. package/src/compute-view/deployment-view/memory/memory.ts +0 -96
  112. package/src/compute-view/deployment-view/predicates/deploymentRefs-where.ts +0 -18
  113. package/src/compute-view/deployment-view/predicates/deploymentRefs.ts +0 -154
  114. package/src/compute-view/deployment-view/predicates/index.ts +0 -8
  115. package/src/compute-view/deployment-view/predicates/relation-direct.ts +0 -243
  116. package/src/compute-view/deployment-view/predicates/relation-in-out.ts +0 -70
  117. package/src/compute-view/deployment-view/predicates/relation-incoming.ts +0 -101
  118. package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +0 -95
  119. package/src/compute-view/deployment-view/predicates/relation-where.ts +0 -18
  120. package/src/compute-view/deployment-view/predicates/utils.ts +0 -282
  121. package/src/compute-view/deployment-view/predicates/wildcard.ts +0 -41
  122. package/src/compute-view/deployment-view/stages/stage-exclude.ts +0 -5
  123. package/src/compute-view/deployment-view/stages/stage-final.ts +0 -245
  124. package/src/compute-view/deployment-view/stages/stage-include.ts +0 -95
  125. package/src/compute-view/deployment-view/utils.ts +0 -297
  126. package/src/compute-view/dynamic-view/compute.ts +0 -312
  127. package/src/compute-view/element-view/_types.ts +0 -47
  128. package/src/compute-view/element-view/clean-connections.ts +0 -117
  129. package/src/compute-view/element-view/compute.ts +0 -324
  130. package/src/compute-view/element-view/memory/NodeGroup.ts +0 -31
  131. package/src/compute-view/element-view/memory/index.ts +0 -10
  132. package/src/compute-view/element-view/memory/memory.ts +0 -178
  133. package/src/compute-view/element-view/memory/stage-exclude.ts +0 -59
  134. package/src/compute-view/element-view/memory/stage-final.ts +0 -129
  135. package/src/compute-view/element-view/memory/stage-include.ts +0 -130
  136. package/src/compute-view/element-view/predicates/_utils.ts +0 -91
  137. package/src/compute-view/element-view/predicates/element-expand.ts +0 -29
  138. package/src/compute-view/element-view/predicates/element-kind-tag.ts +0 -27
  139. package/src/compute-view/element-view/predicates/element-ref.ts +0 -24
  140. package/src/compute-view/element-view/predicates/relation-direct.ts +0 -321
  141. package/src/compute-view/element-view/predicates/relation-in-out.ts +0 -64
  142. package/src/compute-view/element-view/predicates/relation-in.ts +0 -115
  143. package/src/compute-view/element-view/predicates/relation-out.ts +0 -119
  144. package/src/compute-view/element-view/predicates/wildcard.ts +0 -88
  145. package/src/compute-view/element-view/utils.ts +0 -65
  146. package/src/compute-view/index.ts +0 -4
  147. package/src/compute-view/memory/AbstractMemory.ts +0 -45
  148. package/src/compute-view/memory/AbstractStageExclude.ts +0 -215
  149. package/src/compute-view/memory/AbstractStageInclude.ts +0 -200
  150. package/src/compute-view/memory/_types.ts +0 -148
  151. package/src/compute-view/memory/index.ts +0 -5
  152. package/src/compute-view/memory/ops.ts +0 -43
  153. package/src/compute-view/relationships-view/_types.ts +0 -16
  154. package/src/compute-view/relationships-view/compute.ts +0 -159
  155. package/src/compute-view/relationships-view/index.ts +0 -3
  156. package/src/compute-view/relationships-view/layout.ts +0 -358
  157. package/src/compute-view/relationships-view/utils.ts +0 -73
  158. package/src/compute-view/utils/ancestorsOfNode.ts +0 -19
  159. package/src/compute-view/utils/applyCustomElementProperties.ts +0 -107
  160. package/src/compute-view/utils/applyCustomRelationProperties.ts +0 -58
  161. package/src/compute-view/utils/applyViewRuleStyles.ts +0 -73
  162. package/src/compute-view/utils/buildComputedNodes.ts +0 -166
  163. package/src/compute-view/utils/buildElementNotations.ts +0 -64
  164. package/src/compute-view/utils/elementExpressionToPredicate.ts +0 -50
  165. package/src/compute-view/utils/link-nodes-with-edges.ts +0 -56
  166. package/src/compute-view/utils/merge-props-from-relationships.ts +0 -161
  167. package/src/compute-view/utils/relationExpressionToPredicates.ts +0 -55
  168. package/src/compute-view/utils/resolve-extended-views.ts +0 -85
  169. package/src/compute-view/utils/resolve-global-rules.ts +0 -88
  170. package/src/compute-view/utils/topological-sort.ts +0 -256
  171. package/src/compute-view/utils/view-hash.ts +0 -45
  172. package/src/compute-view/utils/with-readable-edges.ts +0 -40
  173. package/src/index.ts +0 -32
  174. package/src/model/DeploymentElementModel.ts +0 -712
  175. package/src/model/DeploymentModel.ts +0 -393
  176. package/src/model/ElementModel.ts +0 -316
  177. package/src/model/LikeC4Model.ts +0 -882
  178. package/src/model/RelationModel.ts +0 -152
  179. package/src/model/connection/Connection.ts +0 -72
  180. package/src/model/connection/deployment/DeploymentConnectionModel.ts +0 -185
  181. package/src/model/connection/deployment/find.ts +0 -120
  182. package/src/model/connection/deployment/index.ts +0 -8
  183. package/src/model/connection/index.ts +0 -22
  184. package/src/model/connection/model/ConnectionModel.ts +0 -158
  185. package/src/model/connection/model/find.ts +0 -117
  186. package/src/model/connection/model/index.ts +0 -8
  187. package/src/model/connection/ops.ts +0 -276
  188. package/src/model/guards.ts +0 -77
  189. package/src/model/index.ts +0 -72
  190. package/src/model/types.ts +0 -67
  191. package/src/model/utils.ts +0 -66
  192. package/src/model/view/EdgeModel.ts +0 -121
  193. package/src/model/view/LikeC4ViewModel.ts +0 -361
  194. package/src/model/view/LikeC4ViewsFolder.ts +0 -151
  195. package/src/model/view/NodeModel.ts +0 -247
  196. package/src/theme/element.ts +0 -61
  197. package/src/theme/index.ts +0 -127
  198. package/src/theme/relationships.ts +0 -54
  199. package/src/types/RichText.ts +0 -205
  200. package/src/types/_aux.ts +0 -317
  201. package/src/types/_common.ts +0 -102
  202. package/src/types/const.ts +0 -34
  203. package/src/types/expression-model.ts +0 -294
  204. package/src/types/expression.ts +0 -313
  205. package/src/types/fqnRef.ts +0 -91
  206. package/src/types/geometry.ts +0 -159
  207. package/src/types/global.ts +0 -21
  208. package/src/types/index.ts +0 -44
  209. package/src/types/model-data.ts +0 -77
  210. package/src/types/model-deployment.ts +0 -78
  211. package/src/types/model-dump.ts +0 -79
  212. package/src/types/model-logical.ts +0 -126
  213. package/src/types/model-spec.ts +0 -88
  214. package/src/types/operators.ts +0 -156
  215. package/src/types/project.ts +0 -14
  216. package/src/types/scalar.ts +0 -162
  217. package/src/types/styles.ts +0 -122
  218. package/src/types/view-changes.ts +0 -32
  219. package/src/types/view-common.ts +0 -157
  220. package/src/types/view-computed.ts +0 -126
  221. package/src/types/view-layouted.ts +0 -94
  222. package/src/types/view-parsed.deployment.ts +0 -39
  223. package/src/types/view-parsed.dynamic.ts +0 -89
  224. package/src/types/view-parsed.element.ts +0 -65
  225. package/src/types/view.ts +0 -113
  226. package/src/utils/common-head.ts +0 -22
  227. package/src/utils/compare-natural.ts +0 -60
  228. package/src/utils/const.ts +0 -1
  229. package/src/utils/fqn.ts +0 -302
  230. package/src/utils/getOrCreate.ts +0 -8
  231. package/src/utils/guards.ts +0 -9
  232. package/src/utils/index.ts +0 -68
  233. package/src/utils/invariant.ts +0 -29
  234. package/src/utils/iterable/_types.ts +0 -5
  235. package/src/utils/iterable/filter.ts +0 -55
  236. package/src/utils/iterable/find.ts +0 -38
  237. package/src/utils/iterable/first.ts +0 -48
  238. package/src/utils/iterable/flat.ts +0 -17
  239. package/src/utils/iterable/head.ts +0 -22
  240. package/src/utils/iterable/index.ts +0 -15
  241. package/src/utils/iterable/map.ts +0 -40
  242. package/src/utils/iterable/reduce.ts +0 -24
  243. package/src/utils/iterable/some.ts +0 -36
  244. package/src/utils/iterable/to.ts +0 -19
  245. package/src/utils/iterable/unique.ts +0 -23
  246. package/src/utils/markdown/index.ts +0 -2
  247. package/src/utils/markdown/to-html.ts +0 -32
  248. package/src/utils/markdown/to-text.ts +0 -14
  249. package/src/utils/memoize-prop.ts +0 -30
  250. package/src/utils/mnemonist.ts +0 -9
  251. package/src/utils/object-hash.ts +0 -14
  252. package/src/utils/promises.ts +0 -24
  253. package/src/utils/relations.ts +0 -36
  254. package/src/utils/set.ts +0 -83
  255. package/src/utils/string-hash.ts +0 -16
@@ -1,946 +0,0 @@
1
- import defu from 'defu'
2
- import {
3
- entries,
4
- fromEntries,
5
- fromKeys,
6
- hasAtLeast,
7
- isArray,
8
- isFunction,
9
- isNonNullish,
10
- isNullish,
11
- map,
12
- mapToObj,
13
- mapValues,
14
- pickBy,
15
- } from 'remeda'
16
- import type { Writable } from 'type-fest'
17
- import { computeLikeC4Model } from '../compute-view/compute-view'
18
- import { LikeC4Model } from '../model/LikeC4Model'
19
- import type {
20
- Any,
21
- aux,
22
- DeployedInstance,
23
- DeploymentFqn,
24
- LikeC4Project,
25
- ParsedElementView,
26
- ParsedLikeC4ModelData,
27
- Specification,
28
- TagSpecification,
29
- } from '../types'
30
- import {
31
- type Color,
32
- type DeploymentElement,
33
- type DeploymentRelation,
34
- type Element,
35
- type ElementShape,
36
- type Fqn,
37
- type IconUrl,
38
- type LikeC4View,
39
- type Link,
40
- type ModelGlobals,
41
- type ModelRelation,
42
- type NonEmptyArray,
43
- type ParsedDeploymentView as DeploymentView,
44
- type RelationId,
45
- _stage,
46
- _type,
47
- DefaultElementShape,
48
- DefaultThemeColor,
49
- FqnRef,
50
- isDeployedInstance,
51
- isElementView,
52
- } from '../types'
53
- import { invariant } from '../utils'
54
- import { isSameHierarchy, nameFromFqn, parentFqn } from '../utils/fqn'
55
- import type { AnyTypes, BuilderProjectSpecification, BuilderSpecification, Types } from './_types'
56
- import type { AddDeploymentNode } from './Builder.deployment'
57
- import type {
58
- AddDeploymentNodeHelpers,
59
- DeloymentModelBuildFunction,
60
- DeloymentModelHelpers,
61
- DeploymentModelBuilder,
62
- } from './Builder.deploymentModel'
63
- import type { AddElement } from './Builder.element'
64
- import type { AddElementHelpers, ModelBuilder, ModelBuilderFunction, ModelHelpers } from './Builder.model'
65
- import { $autoLayout, $exclude, $include, $rules, $style } from './Builder.view-common'
66
- import type { DeploymentRulesBuilderOp } from './Builder.view-deployment'
67
- import type { ElementViewRulesBuilder } from './Builder.view-element'
68
- import { type ViewsBuilder, type ViewsBuilderFunction, type ViewsHelpers, mkViewBuilder } from './Builder.views'
69
- import type { BuilderMethods } from './Builder.with'
70
-
71
- export interface Builder<T extends AnyTypes> extends BuilderMethods<T> {
72
- /**
73
- * Only available in compile time
74
- */
75
- readonly Types: T
76
-
77
- clone(): Builder<T>
78
-
79
- /**
80
- * Builders for each element kind
81
- */
82
- helpers(): {
83
- model: ModelHelpers<T>
84
- views: ViewsHelpers
85
- deployment: DeloymentModelHelpers<T>
86
- }
87
-
88
- /**
89
- * Adds model elements
90
- *
91
- * @example
92
- * builder.model(({ el }, _) =>
93
- * _(
94
- * el('a'),
95
- * el('a.b').with(
96
- * el('c')
97
- * )
98
- * )
99
- * )
100
- *
101
- * builder.model((_, m) =>
102
- * m(
103
- * _.el('a'),
104
- * _.el('a.b').with(
105
- * _.el('c')
106
- * )
107
- * )
108
- * )
109
- */
110
- model<Out extends AnyTypes>(
111
- callback: ModelBuilderFunction<T, Out>,
112
- ): Builder<Out>
113
-
114
- /**
115
- * Adds deployment model
116
- *
117
- * @example
118
- * builder.deployment(({ node, instanceOf }, _) =>
119
- * _(
120
- * node('node1'),
121
- * node('node1.child1').with(
122
- * instanceOf('model.element')
123
- * )
124
- * )
125
- * )
126
- *
127
- * @example
128
- * builder.deployment((_,d) =>
129
- * d(
130
- * _.node('node1'),
131
- * _.node('node1.child1').with(
132
- * _.instanceOf('model.element')
133
- * )
134
- * )
135
- * )
136
- */
137
- deployment<Out extends AnyTypes>(
138
- callback: DeloymentModelBuildFunction<T, Out>,
139
- ): Builder<Out>
140
-
141
- /**
142
- * Adds views
143
- *
144
- * @example
145
- * builder.views(({ view, viewOf, deploymentView, $include, $style, $rules }, _) =>
146
- * _(
147
- * view('view1').with(
148
- * $include('a -> b'),
149
- * ),
150
- * view('view2', {
151
- * title: 'View 2',
152
- * }).with(
153
- * $include('*')
154
- * ),
155
- * view(
156
- * 'view3',
157
- * {
158
- * title: 'View 3',
159
- * },
160
- * $rules(
161
- * $include('*'),
162
- * $style(['*', 'alice'], {
163
- * color: 'red',
164
- * }),
165
- * ),
166
- * ),
167
- * viewOf('viewOfA', 'a').with(
168
- * $include('*')
169
- * ),
170
- * deploymentView('deploymentView1').with(
171
- * $include('a -> b')
172
- * ),
173
- * )
174
- * )
175
- */
176
- views<Out extends AnyTypes>(
177
- callback: ViewsBuilderFunction<T, Out>,
178
- ): Builder<Out>
179
-
180
- /**
181
- * Returns model as result of parsing only
182
- * Views are not computed or layouted
183
- * {@link toLikeC4Model} should be used to get model with computed views
184
- */
185
- build<const Project extends BuilderProjectSpecification>(
186
- project: Project,
187
- ): ParsedLikeC4ModelData<aux.setProject<Types.ToAux<T>, Project['id']>>
188
-
189
- build(): ParsedLikeC4ModelData<Types.ToAux<T>>
190
-
191
- /**
192
- * Returns Computed LikeC4Model
193
- */
194
- toLikeC4Model<const Project extends BuilderProjectSpecification>(
195
- project: Project,
196
- ): LikeC4Model.Computed<aux.setProject<Types.ToAux<T>, Project['id']>>
197
-
198
- toLikeC4Model(): LikeC4Model.Computed<Types.ToAux<T>>
199
- }
200
-
201
- interface Internals<T extends AnyTypes> extends ViewsBuilder<T>, ModelBuilder<T>, DeploymentModelBuilder<T> {
202
- }
203
-
204
- type Op<T> = (b: T) => T
205
-
206
- function ensureObj<T>(value: string[] | Record<string, Partial<T>>): Record<string, Partial<T>> {
207
- return isArray(value) ? fromKeys(value, v => ({})) : value
208
- }
209
-
210
- function validateSpec({ tags, elements, deployments, relationships, ...specification }: BuilderSpecification) {
211
- const spectags = {} as Record<string, Partial<TagSpecification>>
212
- if (tags) {
213
- Object.assign(
214
- spectags,
215
- ensureObj(tags),
216
- )
217
- }
218
- const _elements = ensureObj(elements)
219
-
220
- for (const [kind, spec] of entries(_elements)) {
221
- if (spec.tags) {
222
- for (const tag of spec.tags) {
223
- invariant(tag in spectags, `Invalid specification for element kind "${kind}": tag "${tag}" not found`)
224
- }
225
- }
226
- }
227
- const _deployments = ensureObj(deployments ?? {})
228
-
229
- for (const [kind, spec] of entries(_deployments)) {
230
- if (spec.tags) {
231
- for (const tag of spec.tags) {
232
- invariant(
233
- tag in spectags,
234
- `Invalid specification for deployment kind "${kind}": tag "${tag}" not found`,
235
- )
236
- }
237
- }
238
- }
239
-
240
- return {
241
- ...specification,
242
- tags: spectags,
243
- elements: _elements,
244
- deployments: _deployments,
245
- relationships: ensureObj(relationships ?? {}),
246
- }
247
- }
248
-
249
- function builder<Spec extends BuilderSpecification, T extends AnyTypes>(
250
- _spec: Spec,
251
- _elements = new Map<string, Element<Any>>(),
252
- _relations = [] as ModelRelation[],
253
- _views = new Map<string, LikeC4View>(),
254
- _globals = {
255
- predicates: {},
256
- dynamicPredicates: {},
257
- styles: {},
258
- } as ModelGlobals,
259
- _deployments = new Map<string, DeploymentElement>(),
260
- _deploymentRelations = [] as DeploymentRelation[],
261
- ): Builder<T> {
262
- const spec = validateSpec(_spec)
263
-
264
- const toLikeC4Specification = (): Specification<Types.ToAux<T>> => {
265
- return ({
266
- elements: structuredClone(spec.elements),
267
- deployments: structuredClone(spec.deployments),
268
- relationships: structuredClone(spec.relationships),
269
- tags: mapValues(spec.tags, (tagSpec) => ({
270
- color: DefaultThemeColor,
271
- ...tagSpec,
272
- })),
273
- ...(!!spec.metadataKeys ? { metadataKeys: spec.metadataKeys as any } : {}),
274
- customColors: {},
275
- } as Specification<Types.ToAux<T>>)
276
- }
277
-
278
- const mapLinks = (links?: Array<string | { title?: string; url: string }>): NonEmptyArray<Link> | null => {
279
- if (!links || !hasAtLeast(links, 1)) {
280
- return null
281
- }
282
- return map(links, l => (typeof l === 'string' ? { url: l } : l))
283
- }
284
-
285
- const createGenericView = <B extends Op<any> | undefined>(
286
- id: string,
287
- _props: T['NewViewProps'] | string | B | null,
288
- builder: B,
289
- ): [Omit<LikeC4View, 'rules' | '_type'>, B] => {
290
- if (isFunction(_props)) {
291
- builder = _props as B
292
- _props = {}
293
- }
294
- _props ??= {}
295
- const {
296
- links: _links = [],
297
- title = null,
298
- description = null,
299
- tags = [],
300
- ...props
301
- } = typeof _props === 'string' ? { title: _props } : { ..._props }
302
-
303
- const links = mapLinks(_links)
304
- return [{
305
- id: id as any,
306
- title,
307
- description: description ? { txt: description } : null,
308
- tags,
309
- links,
310
- _stage: 'parsed',
311
- ...props,
312
- }, builder]
313
- }
314
-
315
- const self: Builder<T> & Internals<T> = {
316
- get Types(): T {
317
- throw new Error('Types are not available in runtime')
318
- },
319
- clone: () => {
320
- return builder(
321
- structuredClone(spec),
322
- structuredClone(_elements),
323
- structuredClone(_relations),
324
- structuredClone(_views),
325
- structuredClone(_globals),
326
- structuredClone(_deployments),
327
- structuredClone(_deploymentRelations),
328
- )
329
- },
330
-
331
- __addElement: (element) => {
332
- const parent = parentFqn(element.id)
333
- if (parent) {
334
- invariant(
335
- _elements.get(parent),
336
- `Parent element with id "${parent}" not found for element with id "${element.id}"`,
337
- )
338
- }
339
- if (_elements.has(element.id)) {
340
- throw new Error(`Element with id "${element.id}" already exists`)
341
- }
342
- _elements.set(element.id, element)
343
- return self
344
- },
345
- __addRelation(relation) {
346
- const sourceEl = _elements.get(FqnRef.flatten(relation.source))
347
- invariant(sourceEl, `Element with id "${relation.source}" not found`)
348
- const targetEl = _elements.get(FqnRef.flatten(relation.target))
349
- invariant(targetEl, `Element with id "${relation.target}" not found`)
350
- invariant(
351
- !isSameHierarchy(sourceEl, targetEl),
352
- 'Cannot create relationship between elements in the same hierarchy',
353
- )
354
- _relations.push({
355
- id: `rel${_relations.length + 1}` as RelationId,
356
- ...relation,
357
- })
358
- return self
359
- },
360
- __fqn(id) {
361
- invariant(id.trim() !== '', 'Id must be non-empty')
362
- return id as Fqn
363
- },
364
- __deploymentFqn(id) {
365
- invariant(id.trim() !== '', 'Id must be non-empty')
366
- return id as DeploymentFqn
367
- },
368
- __addSourcelessRelation() {
369
- throw new Error('Can be called only in nested model')
370
- },
371
- __addView: (view) => {
372
- if (_views.has(view.id)) {
373
- throw new Error(`View with id "${view.id}" already exists`)
374
- }
375
- if (isElementView(view) && 'viewOf' in view) {
376
- invariant(
377
- _elements.get(view.viewOf),
378
- `Invalid scoped view ${view.id}, wlement with id "${view.viewOf}" not found`,
379
- )
380
- }
381
- _views.set(view.id, view)
382
- return self
383
- },
384
-
385
- __addDeployment: (node: DeploymentElement) => {
386
- if (_deployments.has(node.id)) {
387
- throw new Error(`Deployment with id "${node.id}" already exists`)
388
- }
389
- const parent = parentFqn(node.id)
390
- if (parent) {
391
- invariant(
392
- _deployments.get(parent),
393
- `Parent element with id "${parent}" not found for node with id "${node.id}"`,
394
- )
395
- }
396
- if (isDeployedInstance(node)) {
397
- invariant(parent, `Instance ${node.id} of ${node.element} must be deployed under a parent node`)
398
- invariant(
399
- _elements.get(node.element),
400
- `Instance "${node.id}" references non-existing element "${node.element}"`,
401
- )
402
- }
403
- _deployments.set(node.id, node)
404
- return self
405
- },
406
- __addDeploymentRelation: (relation) => {
407
- invariant(
408
- !isSameHierarchy(relation.source.deployment, relation.target.deployment),
409
- 'Cannot create relationship between elements in the same hierarchy',
410
- )
411
-
412
- invariant(
413
- _deployments.has(relation.source.deployment),
414
- `Relation "${relation.source.deployment} -> ${relation.target.deployment}" references non-existing source`,
415
- )
416
- invariant(
417
- _deployments.has(relation.target.deployment),
418
- `Relation "${relation.source.deployment} -> ${relation.target.deployment}" references non-existing target`,
419
- )
420
-
421
- _deploymentRelations.push({
422
- id: `deploy_rel${_deploymentRelations.length + 1}` as RelationId,
423
- ...relation,
424
- })
425
- return self
426
- },
427
- build: (project?: LikeC4Project) => ({
428
- [_stage]: 'parsed',
429
- projectId: project?.id ?? 'from-builder',
430
- project: {
431
- id: 'from-builder',
432
- ...project,
433
- },
434
- specification: toLikeC4Specification(),
435
- elements: fromEntries(
436
- structuredClone(
437
- Array.from(_elements.entries()),
438
- ),
439
- ),
440
- relations: mapToObj(_relations, r => [r.id, structuredClone(r)]),
441
- globals: structuredClone(_globals),
442
- deployments: {
443
- elements: fromEntries(
444
- structuredClone(
445
- Array.from(_deployments.entries()),
446
- ),
447
- ),
448
- relations: mapToObj(_deploymentRelations, r => [r.id, structuredClone(r)]),
449
- },
450
- views: fromEntries(
451
- structuredClone(
452
- Array.from(_views.entries()),
453
- ),
454
- ),
455
- imports: {},
456
- } as any),
457
- toLikeC4Model: (project?: LikeC4Project) => {
458
- const parsed = self.build(project as any)
459
- return computeLikeC4Model(parsed) as any
460
- },
461
- helpers: () => ({
462
- model: {
463
- model: (...ops: ((b: ModelBuilder<T>) => ModelBuilder<T>)[]) => {
464
- return (b: Builder<T>) => {
465
- return ops.reduce((b, op) => op(b), b as any as ModelBuilder<T>) as any
466
- }
467
- },
468
- rel: (source, target, _props?) => {
469
- return <T extends AnyTypes>(b: ModelBuilder<T>) => {
470
- const {
471
- title = '',
472
- links: _links = [],
473
- description = null,
474
- ...props
475
- } = defu(
476
- typeof _props === 'string' ? { title: _props } : { ..._props },
477
- { title: null, links: null },
478
- )
479
- const links = mapLinks(_links)
480
- b.__addRelation({
481
- source: {
482
- model: source,
483
- },
484
- target: {
485
- model: target,
486
- },
487
- title,
488
- ...(description && { description: { txt: description } }),
489
- ...(links && { links }),
490
- ...props,
491
- })
492
- return b
493
- }
494
- },
495
- relTo: (target, _props?) => {
496
- return <T extends AnyTypes>(b: ModelBuilder<T>) => {
497
- const {
498
- title = '',
499
- links: _links = [],
500
- description = null,
501
- ...props
502
- } = defu(
503
- typeof _props === 'string' ? { title: _props } : { ..._props },
504
- { title: null, links: null },
505
- )
506
- const links = mapLinks(_links)
507
- b.__addSourcelessRelation({
508
- target: {
509
- model: target,
510
- },
511
- title,
512
- ...(description && { description: { txt: description } }),
513
- ...(links && { links }),
514
- ...props,
515
- })
516
- return b
517
- }
518
- },
519
- ...mapValues(
520
- spec.elements,
521
- ({ style: specStyle, ...spec }, kind) =>
522
- <Id extends string>(
523
- id: Id,
524
- _props?: T['NewElementProps'] | string,
525
- ): AddElement<Id> => {
526
- const add = (<T extends AnyTypes>(b: ModelBuilder<T>) => {
527
- const {
528
- links: _links,
529
- icon: _icon,
530
- style,
531
- title,
532
- description,
533
- summary,
534
- ...props
535
- } = typeof _props === 'string' ? { title: _props } : { ..._props }
536
-
537
- const links = mapLinks(_links)
538
-
539
- const icon = _icon ?? specStyle?.icon
540
-
541
- const _id = b.__fqn(id)
542
-
543
- b.__addElement({
544
- id: _id,
545
- kind: kind as any,
546
- title: title ?? nameFromFqn(_id),
547
- ...(description && { description: { txt: description } }),
548
- ...(summary && { summary: { txt: summary } }),
549
- color: specStyle?.color ?? DefaultThemeColor as Color,
550
- shape: specStyle?.shape ?? DefaultElementShape as ElementShape,
551
- style: pickBy({
552
- border: specStyle?.border,
553
- opacity: specStyle?.opacity,
554
- size: specStyle?.size,
555
- padding: specStyle?.padding,
556
- textSize: specStyle?.textSize,
557
- ...style,
558
- }, isNonNullish),
559
- ...(links && { links }),
560
- ...icon && { icon: icon as IconUrl },
561
- ...spec,
562
- ...props,
563
- })
564
- return b
565
- }) as AddElement<Id>
566
-
567
- add.with = (...ops: Array<(input: ModelBuilder<any>) => ModelBuilder<any>>) => (b: ModelBuilder<any>) => {
568
- add(b)
569
- const { __fqn, __addSourcelessRelation } = b
570
- try {
571
- b.__fqn = (child) => `${__fqn(id)}.${child}` as Fqn
572
- b.__addSourcelessRelation = (relation) => {
573
- return b.__addRelation({
574
- ...relation,
575
- source: {
576
- model: __fqn(id),
577
- },
578
- })
579
- }
580
- ops.reduce((b, op) => op(b), b as any as ModelBuilder<T>) as any
581
- } finally {
582
- b.__fqn = __fqn
583
- b.__addSourcelessRelation = __addSourcelessRelation
584
- }
585
- return b
586
- }
587
-
588
- return add
589
- },
590
- ) as AddElementHelpers<T>,
591
- },
592
- views: {
593
- views: (...ops: ((b: ViewsBuilder<T>) => ViewsBuilder<T>)[]) => {
594
- return (b: Builder<T>) => {
595
- return ops.reduce((b, op) => op(b), b as any as ViewsBuilder<T>) as any
596
- }
597
- },
598
- view: (
599
- id: string,
600
- _props?: T['NewViewProps'] | string | ElementViewRulesBuilder<any>,
601
- _builder?: ElementViewRulesBuilder<any>,
602
- ) => {
603
- const [generic, builder] = createGenericView(id, _props, _builder)
604
- const view: Writable<ParsedElementView> = {
605
- ...generic,
606
- [_type]: 'element',
607
- rules: [],
608
- }
609
-
610
- const add = (b: ViewsBuilder<any>): ViewsBuilder<any> => {
611
- b.__addView(view)
612
- if (builder) {
613
- builder(mkViewBuilder(view))
614
- }
615
- return b
616
- }
617
- add.with = (...ops: ElementViewRulesBuilder<any>[]) => (b: ViewsBuilder<any>) => {
618
- add(b)
619
- const elementViewBuilder = mkViewBuilder(view)
620
- for (const op of ops) {
621
- op(elementViewBuilder)
622
- }
623
- return b
624
- }
625
-
626
- return add
627
- },
628
- viewOf: (
629
- id,
630
- viewOf: string,
631
- _props?: T['NewViewProps'] | string | ElementViewRulesBuilder<any>,
632
- _builder?: ElementViewRulesBuilder<any>,
633
- ) => {
634
- const [generic, builder] = createGenericView(id, _props, _builder)
635
- const view: Writable<ParsedElementView> = {
636
- ...generic,
637
- viewOf: viewOf as Fqn,
638
- [_type]: 'element',
639
- rules: [],
640
- }
641
-
642
- const add = (b: ViewsBuilder<any>): ViewsBuilder<any> => {
643
- b.__addView(view)
644
- if (builder) {
645
- builder(mkViewBuilder(view))
646
- }
647
- return b
648
- }
649
-
650
- add.with = (...ops: ElementViewRulesBuilder<any>[]) => (b: ViewsBuilder<any>) => {
651
- add(b)
652
- const elementViewBuilder = mkViewBuilder(view)
653
- for (const op of ops) {
654
- op(elementViewBuilder)
655
- }
656
- return b
657
- }
658
-
659
- return add
660
- },
661
-
662
- deploymentView: (
663
- id: string,
664
- _props?: T['NewViewProps'] | string | DeploymentRulesBuilderOp<any>,
665
- _builder?: DeploymentRulesBuilderOp<any>,
666
- ) => {
667
- const [generic, builder] = createGenericView(id, _props, _builder)
668
- const view: Writable<DeploymentView> = {
669
- ...generic,
670
- [_type]: 'deployment',
671
- rules: [],
672
- }
673
-
674
- const add = (b: ViewsBuilder<any>): ViewsBuilder<any> => {
675
- b.__addView(view)
676
- if (builder) {
677
- builder(mkViewBuilder(view))
678
- }
679
- return b
680
- }
681
-
682
- add.with = (...ops: DeploymentRulesBuilderOp<any>[]) => (b: ViewsBuilder<any>) => {
683
- add(b)
684
- const elementViewBuilder = mkViewBuilder(view)
685
- for (const op of ops) {
686
- op(elementViewBuilder)
687
- }
688
- return b
689
- }
690
-
691
- return add
692
- },
693
- $autoLayout,
694
- $exclude,
695
- $include,
696
- $rules,
697
- $style,
698
- },
699
- deployment: {
700
- deployment: (...ops: ((b: DeploymentModelBuilder<T>) => DeploymentModelBuilder<T>)[]) => {
701
- return (b: Builder<T>) => {
702
- return ops.reduce((b, op) => op(b), b as any as DeploymentModelBuilder<T>) as any
703
- }
704
- },
705
- instanceOf: (
706
- id: string,
707
- target?: string | T['NewDeploymentNodeProps'],
708
- _props?: string | T['NewDeploymentNodeProps'],
709
- ) => {
710
- return <T extends AnyTypes>(
711
- b: DeploymentModelBuilder<T>,
712
- ): DeploymentModelBuilder<Types.AddDeploymentFqn<T, any>> => {
713
- if (isNullish(target)) {
714
- target = id
715
- id = nameFromFqn(id)
716
- } else if (typeof target === 'string') {
717
- _props ??= {}
718
- } else {
719
- _props = target
720
- target = id
721
- id = nameFromFqn(id)
722
- }
723
- const {
724
- links,
725
- title,
726
- description,
727
- summary,
728
- ...props
729
- } = typeof _props === 'string' ? { title: _props } : { ..._props }
730
- const _id = b.__deploymentFqn(id)
731
- invariant(_elements.has(target), `Target element with id "${target}" not found`)
732
- b.__addDeployment({
733
- id: _id,
734
- element: target as Fqn,
735
- ...title && { title },
736
- ...(summary && { summary: { txt: summary } }),
737
- ...(description && { description: { txt: description } }),
738
- ...links && { links: mapLinks(links) },
739
- ...props,
740
- } as DeployedInstance)
741
- return b as any
742
- }
743
- },
744
- rel: (source: string, target: string, _props?: T['NewRelationshipProps'] | string) => {
745
- return <T extends AnyTypes>(b: DeploymentModelBuilder<T>) => {
746
- const {
747
- title = null,
748
- links,
749
- description = null,
750
- ...props
751
- } = typeof _props === 'string' ? { title: _props } : { ..._props }
752
-
753
- b.__addDeploymentRelation({
754
- source: {
755
- deployment: source as any,
756
- },
757
- target: {
758
- deployment: target as any,
759
- },
760
- title,
761
- ...description && { description: { txt: description } },
762
- ...links && { links: mapLinks(links) },
763
- ...props,
764
- })
765
- return b
766
- }
767
- },
768
- ...mapValues(
769
- spec.deployments ?? {},
770
- ({ style: specStyle, ...spec }, kind) =>
771
- <Id extends string>(
772
- id: Id,
773
- _props?: T['NewDeploymentNodeProps'] | string,
774
- ): AddDeploymentNode<Id> => {
775
- const add = (<T extends AnyTypes>(b: DeploymentModelBuilder<T>) => {
776
- const {
777
- links,
778
- icon: _icon,
779
- style,
780
- title,
781
- description,
782
- summary,
783
- ...props
784
- } = typeof _props === 'string' ? { title: _props } : { ..._props }
785
-
786
- const icon = _icon ?? specStyle?.icon
787
-
788
- const _id = b.__deploymentFqn(id)
789
-
790
- b.__addDeployment({
791
- id: _id,
792
- kind: kind as any,
793
- title: title ?? nameFromFqn(_id),
794
- ...(description && { description: { txt: description } }),
795
- ...(summary && { summary: { txt: summary } }),
796
- style: {
797
- ...icon && { icon: icon as IconUrl },
798
- color: specStyle?.color ?? DefaultThemeColor as Color,
799
- shape: specStyle?.shape ?? DefaultElementShape as ElementShape,
800
- ...pickBy({
801
- border: specStyle?.border,
802
- opacity: specStyle?.opacity,
803
- size: specStyle?.size,
804
- padding: specStyle?.padding,
805
- textSize: specStyle?.textSize,
806
- ...style,
807
- }, isNonNullish),
808
- },
809
- ...links && { links: mapLinks(links) },
810
- ...spec,
811
- ...props,
812
- })
813
- return b
814
- }) as AddDeploymentNode<Id>
815
-
816
- add.with =
817
- (...ops: Array<(input: DeploymentModelBuilder<any>) => DeploymentModelBuilder<any>>) =>
818
- (b: DeploymentModelBuilder<any>) => {
819
- add(b)
820
- const { __deploymentFqn } = b
821
- try {
822
- b.__deploymentFqn = (child) => `${__deploymentFqn(id)}.${child}` as DeploymentFqn
823
- ops.reduce((b, op) => op(b), b as any as DeploymentModelBuilder<T>) as any
824
- } finally {
825
- b.__deploymentFqn = __deploymentFqn
826
- }
827
- return b
828
- }
829
- return add
830
- },
831
- ) as AddDeploymentNodeHelpers<T>,
832
- },
833
- } as {
834
- model: ModelHelpers<T>
835
- views: ViewsHelpers
836
- deployment: DeloymentModelHelpers<T>
837
- }),
838
- with: (...ops: ((b: Builder<T>) => Builder<T>)[]) => {
839
- return ops.reduce((b, op) => op(b), self as Builder<T>).clone()
840
- },
841
- model: <Out extends AnyTypes>(cb: ModelBuilderFunction<T, Out>) => {
842
- const b = self.clone()
843
- const helpers = b.helpers().model
844
- const _ = helpers.model as any
845
- return cb({ ...helpers, _ }, _)(b as Internals<T>) as any
846
- },
847
- deployment: <Out extends AnyTypes>(cb: DeloymentModelBuildFunction<T, Out>) => {
848
- const b = self.clone()
849
- const helpers = b.helpers().deployment
850
- const _ = helpers.deployment as any
851
- return cb({ ...helpers, _ }, _)(b as Internals<T>) as any
852
- },
853
- views: <Out extends AnyTypes>(cb: ViewsBuilderFunction<T, Out>) => {
854
- const b = self.clone()
855
- const helpers = b.helpers().views
856
- return cb({
857
- ...helpers,
858
- _: helpers.views as any,
859
- } as any, helpers.views as any)(b as Internals<T>) as any
860
- },
861
- }
862
-
863
- return self
864
- }
865
- export const Builder = {
866
- /**
867
- * Creates a builder with compositional methods
868
- *
869
- * @example
870
- * ```ts
871
- * const {
872
- * model: { model, system, component, relTo },
873
- * deployment: { env, vm},
874
- * views: { view, $include },
875
- * builder,
876
- * } = Builder.forSpecification({
877
- * elements: {
878
- * system: {},
879
- * component: {},
880
- * },
881
- * deployments: ['env', 'vm'],
882
- * })
883
- *
884
- * const b = builder
885
- * .with(
886
- * model(
887
- * system('cloud').with(
888
- * component('backend'),
889
- * component('backend.api'),
890
- * component('frontend').with(
891
- * relTo('cloud.backend.api'),
892
- * ),
893
- * ),
894
- * ),
895
- * )
896
- * ```
897
- */
898
- forSpecification<const Spec extends BuilderSpecification>(
899
- spec: Spec,
900
- ): {
901
- builder: Builder<Types.FromSpecification<Spec>>
902
- model: ModelHelpers<Types.FromSpecification<Spec>>
903
- deployment: DeloymentModelHelpers<Types.FromSpecification<Spec>>
904
- views: ViewsHelpers
905
- } {
906
- const b = builder<Spec, Types.FromSpecification<Spec>>(spec)
907
- return {
908
- ...b.helpers(),
909
- builder: b,
910
- }
911
- },
912
-
913
- /**
914
- * Creates a builder with chainable methods
915
- *
916
- * @example
917
- * ```ts
918
- * const b = Builder
919
- * .specification({
920
- * elements: ['system', 'component'],
921
- * deployments: ['env', 'vm'],
922
- * })
923
- * .model(({ system, component, relTo }, _) =>
924
- * _(
925
- * system('cloud').with(
926
- * component('backend').with(
927
- * component('api'),
928
- * ),
929
- * component('frontend').with(
930
- * relTo('cloud.backend.api'),
931
- * )
932
- * )
933
- * )
934
- * )
935
- * ```
936
- */
937
- specification<const Spec extends BuilderSpecification>(
938
- spec: Spec,
939
- ): Builder<Types.FromSpecification<Spec>> {
940
- return builder<Spec, Types.FromSpecification<Spec>>(spec)
941
- },
942
- }
943
-
944
- export namespace Builder {
945
- export type Any = Builder<AnyTypes>
946
- }