@likec4/core 1.40.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 (257) 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 +83 -20
  5. package/dist/builder/index.mjs +210 -126
  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 +12 -12
  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.DHQ32OHa.mjs → core.01VTr9qu.mjs} +10 -29
  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.BIAlzwKc.mjs → core.BIqHjQiH.mjs} +85 -45
  25. package/dist/shared/core.BKlholso.mjs +3 -0
  26. package/dist/shared/core.BR4zXDH-.mjs +13 -0
  27. package/dist/shared/{core.yHe79zEl.mjs → core.BYNkXQ8A.mjs} +21 -12
  28. package/dist/shared/core.BazD6cot.mjs +14 -0
  29. package/dist/shared/{core.BuoXfSMj.mjs → core.BbE4y-yl.mjs} +1 -1
  30. package/dist/shared/core.BoYfZOBm.mjs +3 -0
  31. package/dist/shared/core.BsSXS-_R.mjs +7 -0
  32. package/dist/shared/{core.T-eLZTW_.mjs → core.BzTakU3I.mjs} +15 -7
  33. package/dist/shared/{core.4u1dVmfX.mjs → core.C2TiyjI6.mjs} +2 -2
  34. package/dist/shared/{core.DLpidoWc.mjs → core.C3JowhaZ.mjs} +3 -3
  35. package/dist/shared/{core.CNGyqkJh.mjs → core.C4x8aaWa.mjs} +3 -1
  36. package/dist/shared/{core.BB6zA-UU.mjs → core.C8YY6Uub.mjs} +38 -9
  37. package/dist/shared/{core.FPITT8Vx.mjs → core.C8sl5Y8Z.mjs} +144 -61
  38. package/dist/shared/{core.DuR3R-xJ.mjs → core.CNgZvKb8.mjs} +3 -5176
  39. package/dist/shared/{core.BbThmf6M.d.mts → core.CQngdcuj.d.mts} +85 -4
  40. package/dist/shared/{core.Be1n9a0i.mjs → core.C_Ni6yHl.mjs} +5 -4
  41. package/dist/shared/core.CbT8JVYL.mjs +5 -0
  42. package/dist/shared/core.CqAJJpK_.mjs +3 -0
  43. package/dist/shared/{core.CySf-2gP.d.mts → core.D0PjZzIS.d.mts} +52 -15
  44. package/dist/shared/{core.DrvfVXkh.d.mts → core.D5fzJWbF.d.mts} +11 -2
  45. package/dist/shared/{core.DrVOJuxX.d.mts → core.DACpKp35.d.mts} +5 -5
  46. package/dist/shared/core.DFi2dOTl.mjs +39548 -0
  47. package/dist/shared/{core.D704WZES.d.mts → core.DIol3syK.d.mts} +2 -2
  48. package/dist/shared/{core.DlG1xWt2.mjs → core.DMMOWQqc.mjs} +3 -2
  49. package/dist/shared/core.DNbUPnve.mjs +3990 -0
  50. package/dist/shared/{core.CCD1ID81.mjs → core.DRJma0Ol.mjs} +4 -3
  51. package/dist/shared/{core.DgttqsJc.mjs → core.DRhg-gVU.mjs} +9 -9
  52. package/dist/shared/core.DSO_rTC2.mjs +5322 -0
  53. package/dist/shared/{core.vWJTxpLV.d.mts → core.D_vkffV4.d.mts} +4 -2
  54. package/dist/shared/core.DdMJk7nx.d.mts +476 -0
  55. package/dist/shared/{core.D_fI5Lf6.d.mts → core.Dgs6-nuz.d.mts} +24 -4
  56. package/dist/shared/{core.Be4Jy9Qx.mjs → core.FZ305VYd.mjs} +2 -2
  57. package/dist/shared/core.OHD4KXm9.mjs +5 -0
  58. package/dist/shared/{core.GTgsmXS_.mjs → core.QJD_fcrc.mjs} +2 -2
  59. package/dist/shared/core.RfnaEmgA.mjs +7 -0
  60. package/dist/shared/core.fHR_8Tnq.d.mts +450 -0
  61. package/dist/shared/{core.D0EgVMQK.mjs → core.lRvxPoao.mjs} +14 -12
  62. package/dist/shared/{core.CaT0SUUK.mjs → core.rCeaAqgW.mjs} +1 -84
  63. package/dist/shared/{core.kxeJe0OY.d.mts → core.s9uwOt60.d.mts} +4 -4
  64. package/dist/shared/core.yna0OdV5.d.mts +98 -0
  65. package/dist/styles/index.d.mts +106 -0
  66. package/dist/styles/index.mjs +1 -0
  67. package/dist/types/_aux.d.mts +2 -2
  68. package/dist/types/_aux.mjs +1 -5
  69. package/dist/types/expression-model.d.mts +3 -4
  70. package/dist/types/expression.d.mts +3 -4
  71. package/dist/types/fqnRef.d.mts +2 -2
  72. package/dist/types/fqnRef.mjs +3 -3
  73. package/dist/types/index.d.mts +8 -8
  74. package/dist/types/index.mjs +151 -6
  75. package/dist/types/scalar.mjs +3 -2
  76. package/dist/utils/graphology/index.d.mts +1864 -0
  77. package/dist/utils/graphology/index.mjs +1 -0
  78. package/dist/utils/index.d.mts +11 -6
  79. package/dist/utils/index.mjs +21 -37
  80. package/dist/utils/iterable/index.d.mts +1 -1
  81. package/dist/utils/iterable/index.mjs +45 -7
  82. package/model/package.json +4 -0
  83. package/package.json +42 -24
  84. package/styles/package.json +4 -0
  85. package/types/package.json +4 -0
  86. package/utils/graphology/package.json +4 -0
  87. package/utils/package.json +4 -0
  88. package/dist/shared/core.6_Vp2iiN.mjs +0 -172
  89. package/dist/shared/core.Bpou6c2f.d.mts +0 -850
  90. package/dist/shared/core.CUw_2J9j.mjs +0 -47
  91. package/dist/shared/core.CzdwsPmY.d.mts +0 -69
  92. package/dist/shared/core.DoM6aM9N.mjs +0 -7
  93. package/dist/shared/core.ILwny7BV.mjs +0 -38
  94. package/dist/theme/index.d.mts +0 -11
  95. package/dist/theme/index.mjs +0 -232
  96. package/src/builder/Builder.deployment.ts +0 -224
  97. package/src/builder/Builder.deploymentModel.ts +0 -449
  98. package/src/builder/Builder.element.ts +0 -241
  99. package/src/builder/Builder.model.ts +0 -494
  100. package/src/builder/Builder.ts +0 -870
  101. package/src/builder/Builder.view-common.ts +0 -273
  102. package/src/builder/Builder.view-deployment.ts +0 -135
  103. package/src/builder/Builder.view-element.ts +0 -202
  104. package/src/builder/Builder.views.ts +0 -399
  105. package/src/builder/Builder.with.ts +0 -156
  106. package/src/builder/_types.ts +0 -320
  107. package/src/builder/index.ts +0 -11
  108. package/src/compute-view/compute-view.ts +0 -80
  109. package/src/compute-view/deployment-view/_types.ts +0 -38
  110. package/src/compute-view/deployment-view/clean-connections.ts +0 -236
  111. package/src/compute-view/deployment-view/compute.ts +0 -94
  112. package/src/compute-view/deployment-view/memory/index.ts +0 -9
  113. package/src/compute-view/deployment-view/memory/memory.ts +0 -96
  114. package/src/compute-view/deployment-view/predicates/deploymentRefs-where.ts +0 -18
  115. package/src/compute-view/deployment-view/predicates/deploymentRefs.ts +0 -154
  116. package/src/compute-view/deployment-view/predicates/index.ts +0 -8
  117. package/src/compute-view/deployment-view/predicates/relation-direct.ts +0 -243
  118. package/src/compute-view/deployment-view/predicates/relation-in-out.ts +0 -70
  119. package/src/compute-view/deployment-view/predicates/relation-incoming.ts +0 -101
  120. package/src/compute-view/deployment-view/predicates/relation-outgoing.ts +0 -95
  121. package/src/compute-view/deployment-view/predicates/relation-where.ts +0 -18
  122. package/src/compute-view/deployment-view/predicates/utils.ts +0 -282
  123. package/src/compute-view/deployment-view/predicates/wildcard.ts +0 -41
  124. package/src/compute-view/deployment-view/stages/stage-exclude.ts +0 -5
  125. package/src/compute-view/deployment-view/stages/stage-final.ts +0 -245
  126. package/src/compute-view/deployment-view/stages/stage-include.ts +0 -95
  127. package/src/compute-view/deployment-view/utils.ts +0 -286
  128. package/src/compute-view/dynamic-view/compute.ts +0 -312
  129. package/src/compute-view/element-view/_types.ts +0 -47
  130. package/src/compute-view/element-view/clean-connections.ts +0 -117
  131. package/src/compute-view/element-view/compute.ts +0 -324
  132. package/src/compute-view/element-view/memory/NodeGroup.ts +0 -31
  133. package/src/compute-view/element-view/memory/index.ts +0 -10
  134. package/src/compute-view/element-view/memory/memory.ts +0 -178
  135. package/src/compute-view/element-view/memory/stage-exclude.ts +0 -59
  136. package/src/compute-view/element-view/memory/stage-final.ts +0 -129
  137. package/src/compute-view/element-view/memory/stage-include.ts +0 -130
  138. package/src/compute-view/element-view/predicates/_utils.ts +0 -91
  139. package/src/compute-view/element-view/predicates/element-expand.ts +0 -29
  140. package/src/compute-view/element-view/predicates/element-kind-tag.ts +0 -27
  141. package/src/compute-view/element-view/predicates/element-ref.ts +0 -24
  142. package/src/compute-view/element-view/predicates/relation-direct.ts +0 -321
  143. package/src/compute-view/element-view/predicates/relation-in-out.ts +0 -64
  144. package/src/compute-view/element-view/predicates/relation-in.ts +0 -115
  145. package/src/compute-view/element-view/predicates/relation-out.ts +0 -119
  146. package/src/compute-view/element-view/predicates/wildcard.ts +0 -88
  147. package/src/compute-view/element-view/utils.ts +0 -65
  148. package/src/compute-view/index.ts +0 -4
  149. package/src/compute-view/memory/AbstractMemory.ts +0 -45
  150. package/src/compute-view/memory/AbstractStageExclude.ts +0 -215
  151. package/src/compute-view/memory/AbstractStageInclude.ts +0 -200
  152. package/src/compute-view/memory/_types.ts +0 -148
  153. package/src/compute-view/memory/index.ts +0 -5
  154. package/src/compute-view/memory/ops.ts +0 -43
  155. package/src/compute-view/relationships-view/_types.ts +0 -16
  156. package/src/compute-view/relationships-view/compute.ts +0 -159
  157. package/src/compute-view/relationships-view/index.ts +0 -3
  158. package/src/compute-view/relationships-view/layout.ts +0 -357
  159. package/src/compute-view/relationships-view/utils.ts +0 -73
  160. package/src/compute-view/utils/ancestorsOfNode.ts +0 -19
  161. package/src/compute-view/utils/applyCustomElementProperties.ts +0 -107
  162. package/src/compute-view/utils/applyCustomRelationProperties.ts +0 -58
  163. package/src/compute-view/utils/applyViewRuleStyles.ts +0 -73
  164. package/src/compute-view/utils/buildComputedNodes.ts +0 -153
  165. package/src/compute-view/utils/buildElementNotations.ts +0 -63
  166. package/src/compute-view/utils/elementExpressionToPredicate.ts +0 -50
  167. package/src/compute-view/utils/link-nodes-with-edges.ts +0 -56
  168. package/src/compute-view/utils/merge-props-from-relationships.ts +0 -161
  169. package/src/compute-view/utils/relationExpressionToPredicates.ts +0 -55
  170. package/src/compute-view/utils/resolve-extended-views.ts +0 -85
  171. package/src/compute-view/utils/resolve-global-rules.ts +0 -88
  172. package/src/compute-view/utils/topological-sort.ts +0 -256
  173. package/src/compute-view/utils/view-hash.ts +0 -45
  174. package/src/compute-view/utils/with-readable-edges.ts +0 -40
  175. package/src/index.ts +0 -32
  176. package/src/model/DeploymentElementModel.ts +0 -682
  177. package/src/model/DeploymentModel.ts +0 -393
  178. package/src/model/ElementModel.ts +0 -293
  179. package/src/model/LikeC4Model.ts +0 -882
  180. package/src/model/RelationModel.ts +0 -152
  181. package/src/model/connection/Connection.ts +0 -72
  182. package/src/model/connection/deployment/DeploymentConnectionModel.ts +0 -185
  183. package/src/model/connection/deployment/find.ts +0 -120
  184. package/src/model/connection/deployment/index.ts +0 -8
  185. package/src/model/connection/index.ts +0 -22
  186. package/src/model/connection/model/ConnectionModel.ts +0 -158
  187. package/src/model/connection/model/find.ts +0 -117
  188. package/src/model/connection/model/index.ts +0 -8
  189. package/src/model/connection/ops.ts +0 -276
  190. package/src/model/guards.ts +0 -77
  191. package/src/model/index.ts +0 -72
  192. package/src/model/types.ts +0 -67
  193. package/src/model/utils.ts +0 -66
  194. package/src/model/view/EdgeModel.ts +0 -120
  195. package/src/model/view/LikeC4ViewModel.ts +0 -361
  196. package/src/model/view/LikeC4ViewsFolder.ts +0 -151
  197. package/src/model/view/NodeModel.ts +0 -247
  198. package/src/theme/element.ts +0 -61
  199. package/src/theme/index.ts +0 -127
  200. package/src/theme/relationships.ts +0 -54
  201. package/src/types/RichText.ts +0 -206
  202. package/src/types/_aux.ts +0 -291
  203. package/src/types/_common.ts +0 -80
  204. package/src/types/const.ts +0 -34
  205. package/src/types/expression-model.ts +0 -294
  206. package/src/types/expression.ts +0 -313
  207. package/src/types/fqnRef.ts +0 -91
  208. package/src/types/geometry.ts +0 -159
  209. package/src/types/global.ts +0 -21
  210. package/src/types/index.ts +0 -42
  211. package/src/types/model-data.ts +0 -77
  212. package/src/types/model-deployment.ts +0 -88
  213. package/src/types/model-dump.ts +0 -79
  214. package/src/types/model-logical.ts +0 -135
  215. package/src/types/model-spec.ts +0 -85
  216. package/src/types/operators.ts +0 -156
  217. package/src/types/project.ts +0 -14
  218. package/src/types/scalar.ts +0 -162
  219. package/src/types/styles.ts +0 -122
  220. package/src/types/view-changes.ts +0 -32
  221. package/src/types/view-common.ts +0 -157
  222. package/src/types/view-computed.ts +0 -118
  223. package/src/types/view-layouted.ts +0 -98
  224. package/src/types/view-parsed.deployment.ts +0 -39
  225. package/src/types/view-parsed.dynamic.ts +0 -89
  226. package/src/types/view-parsed.element.ts +0 -65
  227. package/src/types/view.ts +0 -113
  228. package/src/utils/common-head.ts +0 -22
  229. package/src/utils/compare-natural.ts +0 -60
  230. package/src/utils/const.ts +0 -1
  231. package/src/utils/fqn.ts +0 -302
  232. package/src/utils/getOrCreate.ts +0 -8
  233. package/src/utils/guards.ts +0 -9
  234. package/src/utils/index.ts +0 -68
  235. package/src/utils/invariant.ts +0 -29
  236. package/src/utils/iterable/_types.ts +0 -5
  237. package/src/utils/iterable/filter.ts +0 -55
  238. package/src/utils/iterable/find.ts +0 -38
  239. package/src/utils/iterable/first.ts +0 -48
  240. package/src/utils/iterable/flat.ts +0 -17
  241. package/src/utils/iterable/head.ts +0 -22
  242. package/src/utils/iterable/index.ts +0 -15
  243. package/src/utils/iterable/map.ts +0 -40
  244. package/src/utils/iterable/reduce.ts +0 -24
  245. package/src/utils/iterable/some.ts +0 -36
  246. package/src/utils/iterable/to.ts +0 -19
  247. package/src/utils/iterable/unique.ts +0 -23
  248. package/src/utils/markdown/index.ts +0 -2
  249. package/src/utils/markdown/to-html.ts +0 -32
  250. package/src/utils/markdown/to-text.ts +0 -14
  251. package/src/utils/memoize-prop.ts +0 -30
  252. package/src/utils/mnemonist.ts +0 -9
  253. package/src/utils/object-hash.ts +0 -14
  254. package/src/utils/promises.ts +0 -24
  255. package/src/utils/relations.ts +0 -36
  256. package/src/utils/set.ts +0 -83
  257. package/src/utils/string-hash.ts +0 -16
@@ -1,43 +0,0 @@
1
- import { Connection } from '../../model'
2
- import { isAncestor, sortParentsFirst } from '../../utils'
3
- import { toArray } from '../../utils/iterable'
4
- import { DefaultMap } from '../../utils/mnemonist'
5
- import type { AnyCtx, ComputeMemory, CtxElement } from './_types'
6
-
7
- export function treeFromMemoryState<T extends AnyCtx, M extends ComputeMemory<T> = ComputeMemory<T>>(
8
- memory: M,
9
- filter: 'all' | 'final' = 'final',
10
- ) {
11
- const sorted = sortParentsFirst(toArray(filter === 'final' ? memory.final : memory.elements))
12
- const connected = new Set(memory.connections.flatMap(c => [c.source, c.target]))
13
- const root = new Set(sorted)
14
- const parents = new DefaultMap<CtxElement<T>, CtxElement<T> | null>(() => null)
15
- const children = sorted.reduce((acc, parent, index, all) => {
16
- acc.set(
17
- parent,
18
- all
19
- .slice(index + 1)
20
- .filter(e => isAncestor(parent, e))
21
- .map(e => {
22
- root.delete(e)
23
- return e
24
- })
25
- .reduce((acc, el) => {
26
- if (!acc.some(e => isAncestor(e, el))) {
27
- acc.push(el)
28
- parents.set(el, parent)
29
- }
30
- return acc
31
- }, [] as CtxElement<T>[]),
32
- )
33
- return acc
34
- }, new DefaultMap<CtxElement<T>, ReadonlyArray<CtxElement<T>>>(() => []))
35
-
36
- return {
37
- root: root as ReadonlySet<CtxElement<T>>,
38
- connected: connected as ReadonlySet<CtxElement<T>>,
39
- hasInOut: (el: CtxElement<T>) => memory.connections.some(Connection.isAnyInOut(el.id)),
40
- parent: (el: CtxElement<T>) => parents.get(el),
41
- children: (el: CtxElement<T>) => children.get(el),
42
- }
43
- }
@@ -1,16 +0,0 @@
1
- import type { ElementModel, RelationshipModel } from '../../model'
2
- import type { AnyAux, Unknown } from '../../types'
3
-
4
- // type Pair = {
5
- // left: ReadonlySet<ElementModel>
6
- // relationships: ReadonlySet<RelationshipModel>
7
- // right: ReadonlySet<ElementModel>
8
- // }
9
-
10
- export type RelationshipsViewData<M extends AnyAux = Unknown> = {
11
- incomers: ReadonlySet<ElementModel<M>>
12
- incoming: ReadonlySet<RelationshipModel<M>>
13
- subjects: ReadonlySet<ElementModel<M>>
14
- outgoing: ReadonlySet<RelationshipModel<M>>
15
- outgoers: ReadonlySet<ElementModel<M>>
16
- }
@@ -1,159 +0,0 @@
1
- import { pipe } from 'remeda'
2
- import type { ElementModel, LikeC4Model, LikeC4ViewModel, RelationshipModel } from '../../model'
3
- import type { AnyAux, aux } from '../../types'
4
- import { invariant } from '../../utils'
5
- import { isDescendantOf, sortParentsFirst } from '../../utils/fqn'
6
- import { ifilter, imap, toArray, toSet } from '../../utils/iterable'
7
- import type { RelationshipsViewData } from './_types'
8
- import { treeFromElements } from './utils'
9
-
10
- const finalize = <M extends AnyAux>(
11
- elements: Set<ElementModel<M>>,
12
- explicits: Set<ElementModel<M>>,
13
- ): Set<ElementModel<M>> => {
14
- if (elements.size > 2 && explicits.size !== elements.size) {
15
- return new Set(sortParentsFirst([
16
- ...treeFromElements(elements).flatten(),
17
- ...explicits,
18
- ]))
19
- }
20
- if (elements.size > 1) {
21
- return new Set(sortParentsFirst([...elements]))
22
- }
23
- return elements
24
- }
25
-
26
- function computeRelationships<const M extends AnyAux>(
27
- subject: ElementModel<M>,
28
- others: Set<ElementModel<M>>,
29
- relationships: {
30
- incoming: ReadonlyArray<RelationshipModel<M>>
31
- outgoing: ReadonlyArray<RelationshipModel<M>>
32
- },
33
- ): Omit<RelationshipsViewData<M>, 'subjectExistsInScope'> {
34
- const isOther = (e: ElementModel<M>) => others.has(e)
35
- let subjects = new Set([subject])
36
- const explicits = {
37
- incomers: new Set<ElementModel<M>>(),
38
- subjects: new Set([subject]),
39
- outgoers: new Set<ElementModel<M>>(),
40
- }
41
-
42
- // Iterate over incoming and outgoing relationships
43
- // and add the source and target elements to appropriate sets.
44
- // If element is deeper in the hierarchy - add all ancestors until that is a sibling of the subject
45
- let incomers = new Set(relationships.incoming.flatMap((r) => {
46
- explicits.subjects.add(r.target)
47
- explicits.incomers.add(r.source)
48
-
49
- subjects.add(r.target)
50
- if (r.target !== subject) {
51
- let target = r.target.parent
52
- while (target && target !== subject) {
53
- subjects.add(target)
54
- target = target.parent
55
- }
56
- }
57
-
58
- let source = r.source
59
- const incomerBranch = [] as ElementModel<M>[]
60
- while (true) {
61
- incomerBranch.push(source)
62
- if (isOther(source) || !source.parent) {
63
- break
64
- }
65
- source = source.parent
66
- }
67
- return incomerBranch
68
- }))
69
-
70
- let outgoers = new Set(relationships.outgoing.flatMap((r) => {
71
- explicits.subjects.add(r.source)
72
- explicits.outgoers.add(r.target)
73
-
74
- subjects.add(r.source)
75
- if (r.source !== subject) {
76
- let source = r.source.parent
77
- while (source && source !== subject) {
78
- subjects.add(source)
79
- source = source.parent
80
- }
81
- }
82
-
83
- let target = r.target
84
- const outgoerBranch = [] as ElementModel<M>[]
85
- while (true) {
86
- outgoerBranch.push(target)
87
- if (isOther(target) || !target.parent) {
88
- break
89
- }
90
- target = target.parent
91
- }
92
- return outgoerBranch
93
- }))
94
-
95
- return {
96
- incomers: finalize(incomers, explicits.incomers),
97
- incoming: new Set(relationships.incoming),
98
- subjects: finalize(subjects, explicits.subjects),
99
- outgoing: new Set(relationships.outgoing),
100
- outgoers: finalize(outgoers, explicits.outgoers),
101
- }
102
- }
103
-
104
- export function computeRelationshipsView<M extends AnyAux>(
105
- subjectId: aux.ElementId<M>,
106
- likec4model: LikeC4Model<M>,
107
- scopeViewId: aux.ViewId<M> | null,
108
- scope: 'global' | 'view' = 'global',
109
- ): RelationshipsViewData<M> {
110
- let subjectExistsInScope = true
111
- const view = scopeViewId ? likec4model.findView(scopeViewId) : null
112
- if (scope === 'view') {
113
- invariant(
114
- view,
115
- 'Scope view id is required when scope is "view"',
116
- )
117
- return computeScopedRelationshipsView(subjectId, view, likec4model)
118
- }
119
-
120
- const subject = likec4model.element(subjectId)
121
- const subjectSiblings = toSet(subject.ascendingSiblings())
122
- return computeRelationships(
123
- subject,
124
- subjectSiblings,
125
- {
126
- incoming: [...subject.incoming()],
127
- outgoing: [...subject.outgoing()],
128
- },
129
- )
130
- }
131
-
132
- function computeScopedRelationshipsView<M extends AnyAux>(
133
- subjectId: NoInfer<aux.ElementId<M>>,
134
- view: LikeC4ViewModel<M>,
135
- likec4model: LikeC4Model<M>,
136
- ): RelationshipsViewData<M> {
137
- const subject = likec4model.element(subjectId)
138
- let relationships = {
139
- incoming: toArray(ifilter(subject.incoming(), (r) => view.includesRelation(r.id))),
140
- outgoing: toArray(ifilter(subject.outgoing(), (r) => view.includesRelation(r.id))),
141
- }
142
-
143
- const isDescendant = isDescendantOf(subject)
144
-
145
- const others = new Set([
146
- ...subject.ascendingSiblings(),
147
- ...pipe(
148
- view.elements(),
149
- imap((e) => e.element),
150
- ifilter((e): e is ElementModel<M> => e !== subject && isDescendant(e)),
151
- ),
152
- ])
153
-
154
- return computeRelationships(
155
- subject,
156
- others,
157
- relationships,
158
- )
159
- }
@@ -1,3 +0,0 @@
1
- export type { RelationshipsViewData } from './_types'
2
- export { computeRelationshipsView } from './compute'
3
- export { treeFromElements } from './utils'
@@ -1,357 +0,0 @@
1
- import dagre, { type EdgeConfig, type GraphLabel } from '@dagrejs/dagre'
2
- import { concat, filter, forEachObj, groupBy, map, mapToObj, pipe, prop, reduce, tap } from 'remeda'
3
- import type { ElementModel } from '../../model/ElementModel'
4
- import type { RelationshipModel } from '../../model/RelationModel'
5
- import type { DiagramNode, DiagramView, Fqn, NodeId } from '../../types'
6
- import { invariant, sortParentsFirst } from '../../utils'
7
- import { toArray } from '../../utils/iterable'
8
- import { DefaultMap } from '../../utils/mnemonist'
9
- import type { RelationshipsViewData } from './_types'
10
- import { treeFromElements } from './utils'
11
-
12
- /**
13
- * All constants related to the layout
14
- */
15
- const Sizes = {
16
- dagre: {
17
- ranksep: 60,
18
- nodesep: 35,
19
- edgesep: 25,
20
- } satisfies GraphLabel,
21
- edgeLabel: {
22
- width: 120,
23
- height: 10,
24
- minlen: 1,
25
- weight: 1,
26
- } satisfies EdgeConfig,
27
-
28
- emptyNodeOffset: 120,
29
-
30
- nodeWidth: 320,
31
- nodeHeight: 180,
32
-
33
- // Spacer between elements in a compound node
34
- // 0 means no spacer
35
- spacerHeight: 0,
36
-
37
- compound: {
38
- labelHeight: 1,
39
- paddingTop: 60,
40
- paddingBottom: 32,
41
- },
42
- }
43
- type NodeData = {
44
- portId: string
45
- element: ElementModel<any>
46
- isCompound: boolean
47
- }
48
- function createGraph() {
49
- const g = new dagre.graphlib.Graph<NodeData>({
50
- directed: true,
51
- compound: true,
52
- multigraph: true,
53
- })
54
- g.setGraph({
55
- ...Sizes.dagre,
56
- rankdir: 'LR',
57
- })
58
- g.setDefaultEdgeLabel(() => ({ ...Sizes.edgeLabel }))
59
- g.setDefaultNodeLabel(() => ({}))
60
-
61
- // columns.reduce((prev, column) => {
62
- // const c = graphColumn(column)
63
- // g.setNode(c.id, {})
64
- // g.setNode(c.anchor, { width: 40, height: 2 })
65
- // g.setParent(c.anchor, c.id)
66
- // if (prev) {
67
- // g.setEdge(prev, c.anchor, {
68
- // width: 0
69
- // })
70
- // }
71
- // return c.anchor
72
- // }, null as string | null)
73
-
74
- return g
75
- }
76
- type G = ReturnType<typeof createGraph>
77
-
78
- const PortSuffix = '-port'
79
-
80
- function createNodes(
81
- prefix: string,
82
- elements: ReadonlySet<ElementModel<any>>,
83
- g: G,
84
- ) {
85
- const graphNodes = new DefaultMap<Fqn, { id: string; portId: string }>(key => ({
86
- id: `${prefix}-${key}`,
87
- portId: `${prefix}-${key}`,
88
- }))
89
- const tree = treeFromElements(elements)
90
- for (const element of tree.sorted) {
91
- const isCompound = tree.children(element).length > 0
92
- const fqn = element.id
93
- const id = `${prefix}-${fqn}`
94
- const portId = isCompound ? `${id}${PortSuffix}` : id
95
- graphNodes.set(fqn, {
96
- id,
97
- portId,
98
- })
99
- g.setNode(id, {
100
- element,
101
- isCompound,
102
- portId,
103
- width: Sizes.nodeWidth,
104
- height: Sizes.nodeHeight,
105
- })
106
-
107
- if (isCompound) {
108
- g.setNode(portId, {
109
- element,
110
- portId,
111
- isCompound,
112
- width: Sizes.nodeWidth - Sizes.dagre.ranksep,
113
- height: Sizes.compound.labelHeight,
114
- })
115
- g.setParent(portId, id)
116
- // g.node(id).padding = 60
117
- }
118
-
119
- const parent = tree.parent(element)
120
- if (parent) {
121
- g.setParent(id, `${prefix}-${parent.id}`)
122
- }
123
- }
124
- return {
125
- ...tree,
126
- byId: (id: string) => {
127
- const element = tree.byId(id)
128
- const graph = graphNodes.get(element.id)
129
- return {
130
- element,
131
- graph,
132
- }
133
- },
134
- graphNodes,
135
- }
136
- }
137
-
138
- /**
139
- * Apply dagre layout to the graph
140
- * And return a function to get node bounds for xyflow
141
- */
142
- function applyDagreLayout(g: G) {
143
- dagre.layout(g, {
144
- // disableOptimalOrderHeuristic: true,
145
- })
146
- return (nodeId: string) => {
147
- const node = g.node(nodeId)
148
- const { x, y, width, height } = node
149
- return {
150
- position: {
151
- x: x - Math.round(width / 2),
152
- y: y - Math.round(height / 2),
153
- },
154
- width,
155
- height,
156
- }
157
- }
158
- }
159
-
160
- export function layoutRelationshipsView(data: RelationshipsViewData): Pick<DiagramView, 'nodes' | 'edges' | 'bounds'> {
161
- const g = createGraph()
162
-
163
- const incomers = createNodes('in', data.incomers, g),
164
- subjects = createNodes('subject', data.subjects, g),
165
- outgoers = createNodes('out', data.outgoers, g)
166
-
167
- const edges = [] as Array<{
168
- name: string
169
- source: string // node id
170
- target: string // node id
171
- relations: RelationshipModel[]
172
- }>
173
-
174
- pipe(
175
- concat(
176
- pipe(
177
- toArray(data.incoming),
178
- map(r => ({
179
- id: r.source.id,
180
- source: incomers.byId(r.source.id).graph,
181
- target: subjects.byId(r.target.id).graph,
182
- relation: r,
183
- })),
184
- // Sort by source
185
- sortParentsFirst,
186
- ),
187
- pipe(
188
- toArray(data.outgoing),
189
- map(r => ({
190
- id: r.target.id,
191
- source: subjects.byId(r.source.id).graph,
192
- target: outgoers.byId(r.target.id).graph,
193
- relation: r,
194
- })),
195
- // Sort by target
196
- sortParentsFirst,
197
- ),
198
- ),
199
- map(r => ({
200
- ...r,
201
- expr: `${r.source.id}->${r.target.id}`,
202
- })),
203
- // Group if same source and target
204
- groupBy(prop('expr')),
205
- forEachObj((grouped) => {
206
- const source = grouped[0].source
207
- const target = grouped[0].target
208
- const name = grouped[0].expr
209
-
210
- g.setEdge(source.portId, target.portId, {
211
- ...Sizes.edgeLabel,
212
- }, name)
213
- edges.push({
214
- name,
215
- source: source.id,
216
- target: target.id,
217
- relations: map(grouped, prop('relation')),
218
- })
219
- }),
220
- )
221
-
222
- // Grow nodes with more than 2 ports
223
- for (const subjectNode of subjects.graphNodes.values()) {
224
- const nodeId = subjectNode.id
225
- const node = g.node(nodeId)
226
- if (node.isCompound) {
227
- continue
228
- }
229
- const edgeCount = Math.max(g.inEdges(nodeId)?.length ?? 0, g.outEdges(nodeId)?.length ?? 0)
230
- if (edgeCount > 2) {
231
- node.height = node.height + (edgeCount - 3) * 14
232
- }
233
- }
234
-
235
- const dagreBounds = applyDagreLayout(g)
236
-
237
- const nodeIds = [
238
- ...incomers.graphNodes.values(),
239
- ...subjects.graphNodes.values(),
240
- ...outgoers.graphNodes.values(),
241
- ]
242
-
243
- // Calculate bounds for all nodes except compounds
244
- // We shrink compounds to fit their children
245
- const _calculatedNodeBounds = pipe(
246
- nodeIds,
247
- // Compound nodes have different portId
248
- filter(n => n.id === n.portId),
249
- mapToObj(n => [n.id, dagreBounds(n.id)]),
250
- )
251
-
252
- function nodeBounds(nodeId: string): ReturnType<typeof dagreBounds> {
253
- return _calculatedNodeBounds[nodeId] ??= pipe(
254
- g.children(nodeId) as string[] | undefined ?? [],
255
- filter(id => !id.endsWith(PortSuffix)),
256
- map(id => nodeBounds(id)),
257
- tap(bounds => {
258
- invariant(bounds.length > 0, `Node ${nodeId} has no nested nodes`)
259
- }),
260
- reduce((acc, bounds) => {
261
- return {
262
- minY: Math.min(acc.minY, bounds.position.y),
263
- maxY: Math.max(acc.maxY, bounds.position.y + bounds.height),
264
- }
265
- }, { minY: Infinity, maxY: -Infinity }),
266
- ({ minY, maxY }) => {
267
- const {
268
- position: { x },
269
- width,
270
- } = dagreBounds(nodeId)
271
- minY = minY - Sizes.compound.paddingTop
272
- maxY = maxY + Sizes.compound.paddingBottom
273
-
274
- return {
275
- position: {
276
- x,
277
- y: minY,
278
- },
279
- width,
280
- height: maxY - minY,
281
- }
282
- },
283
- )
284
- }
285
-
286
- function nodeLevel(nodeId: string): number {
287
- const parent = g.parent(nodeId)
288
- if (parent) {
289
- return nodeLevel(parent) + 1
290
- }
291
- return 0
292
- }
293
- function nodeDepth(nodeId: string): number {
294
- const children = g.children(nodeId) as string[] | undefined ?? []
295
- if (children.length === 0) {
296
- return 0
297
- }
298
- return 1 + Math.max(...children.map(nodeDepth))
299
- }
300
-
301
- const nodes = nodeIds.map(({ id }): DiagramNode => {
302
- const { element } = g.node(id)
303
- let { position, width, height } = nodeBounds(id)
304
- const parentId = g.parent(id)
305
- // if (parentId) {
306
- // const parentPos = nodeBounds(parentId).position
307
- // position = {
308
- // x: position.x - parentPos.x,
309
- // y: position.y - parentPos.y,
310
- // }
311
- // }
312
- const children = (g.children(id) as NodeId[] | undefined ?? []).filter(c => !c.endsWith(PortSuffix))
313
-
314
- return {
315
- id: id as NodeId,
316
- parent: parentId as NodeId ?? null,
317
- title: element.title,
318
- ...position,
319
- position: [position.x, position.y],
320
- description: element.description?.$source ?? null,
321
- technology: element.technology,
322
- tags: [],
323
- links: null,
324
- color: element.color,
325
- shape: element.shape,
326
- modelRef: element.id,
327
- kind: element.kind,
328
- level: nodeLevel(id),
329
- labelBBox: {
330
- x: position.x,
331
- y: position.y,
332
- width: width,
333
- height: height,
334
- },
335
- style: {
336
- ...element.$element.style,
337
- },
338
- inEdges: [],
339
- outEdges: [],
340
- ...(children.length > 0 && { depth: nodeDepth(id) }),
341
- children,
342
- width,
343
- height,
344
- }
345
- })
346
-
347
- return {
348
- bounds: {
349
- x: 0,
350
- y: 0,
351
- width: g.graph().width ?? 100,
352
- height: g.graph().height ?? 100,
353
- },
354
- nodes,
355
- edges: [],
356
- }
357
- }
@@ -1,73 +0,0 @@
1
- import type { ElementModel } from '../../model/ElementModel'
2
- import type { AnyAux, aux } from '../../types'
3
- import { nonNullable } from '../../utils'
4
- import { isAncestor, isDescendantOf, sortParentsFirst } from '../../utils/fqn'
5
- import { DefaultMap } from '../../utils/mnemonist'
6
-
7
- export function treeFromElements<M extends AnyAux>(elements: Iterable<ElementModel<M>>) {
8
- const sorted = sortParentsFirst([...elements]) as ReadonlyArray<ElementModel<M>>
9
- const root = new Set(sorted)
10
- const map = new Map(sorted.map(e => [e._literalId, e]))
11
- const parents = new DefaultMap<ElementModel<M>, ElementModel<M> | null>(() => null)
12
- const children = sorted.reduce((acc, parent, index, all) => {
13
- acc.set(
14
- parent,
15
- all
16
- .slice(index + 1)
17
- .filter(isDescendantOf(parent))
18
- .map(e => {
19
- root.delete(e)
20
- return e
21
- })
22
- .reduce((acc, el) => {
23
- if (!acc.some(isAncestor(el))) {
24
- acc.push(el)
25
- parents.set(el, parent)
26
- }
27
- return acc
28
- }, [] as ElementModel<M>[]),
29
- )
30
- return acc
31
- }, new DefaultMap<ElementModel<M>, ElementModel<M>[]>(() => []))
32
-
33
- return {
34
- sorted,
35
- byId: (id: aux.ElementId<M>): ElementModel<M> => nonNullable(map.get(id), `Element not found by id: ${id}`),
36
- root: root as ReadonlySet<ElementModel<M>>,
37
- parent: (el: ElementModel<M>): ElementModel<M> | null => parents.get(el),
38
- children: (el: ElementModel<M>): ReadonlyArray<ElementModel<M>> => children.get(el),
39
- /**
40
- * Flattens the tree structure by removing redundant hierarchy levels.
41
- * @example
42
- * A
43
- * └── B
44
- * ├── C
45
- * │ └── D
46
- * │ └── E
47
- * └── F
48
- * └── G
49
- * becomes
50
- * A
51
- * ├── C
52
- * │ └── E
53
- * └── F
54
- * └── G
55
- */
56
- flatten: (): Set<ElementModel<M>> => {
57
- return new Set([
58
- ...root,
59
- ...sorted.reduce((acc, el) => {
60
- const _children = children.get(el)
61
- if (_children.length === 0) {
62
- acc.push(el)
63
- return acc
64
- }
65
- if (_children.length > 1) {
66
- acc.push(..._children)
67
- }
68
- return acc
69
- }, [] as ElementModel<M>[]),
70
- ])
71
- },
72
- }
73
- }
@@ -1,19 +0,0 @@
1
- import type { AnyAux, ComputedNode } from '../../types'
2
- import { nonNullable } from '../../utils'
3
-
4
- /**
5
- * Returns the ancestors of given computed node, starting with the direct parent and ending with the root node.
6
- */
7
- export function ancestorsOfNode<A extends AnyAux>(
8
- node: ComputedNode<A>,
9
- nodes: ReadonlyMap<string, ComputedNode<A>>,
10
- ): ReadonlyArray<ComputedNode<A>> {
11
- const ancestors = [] as ComputedNode<A>[]
12
- let parentId = node.parent
13
- while (parentId) {
14
- const parentNode = nonNullable(nodes.get(parentId), `Parent node ${parentId} not found`)
15
- ancestors.push(parentNode)
16
- parentId = parentNode.parent
17
- }
18
- return ancestors
19
- }