@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,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,358 +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, type DiagramView, type Fqn, type NodeId, omitUndefined } 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 omitUndefined({
315
- id: id as NodeId,
316
- parent: parentId as NodeId ?? null,
317
- title: element.title,
318
- x: position.x,
319
- y: position.y,
320
- position: [position.x, position.y],
321
- description: element.$element.summary ?? element.$element.description ?? null,
322
- technology: element.technology,
323
- tags: [],
324
- links: null,
325
- color: element.color,
326
- shape: element.shape,
327
- modelRef: element.id,
328
- kind: element.kind,
329
- level: nodeLevel(id),
330
- labelBBox: {
331
- x: position.x,
332
- y: position.y,
333
- width: width,
334
- height: height,
335
- },
336
- style: {
337
- ...element.$element.style,
338
- },
339
- inEdges: [],
340
- outEdges: [],
341
- depth: children.length > 0 ? nodeDepth(id) : 0,
342
- children,
343
- width,
344
- height,
345
- })
346
- })
347
-
348
- return {
349
- bounds: {
350
- x: 0,
351
- y: 0,
352
- width: g.graph().width ?? 100,
353
- height: g.graph().height ?? 100,
354
- },
355
- nodes,
356
- edges: [],
357
- }
358
- }
@@ -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
- }