@likec4/language-server 1.17.1 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/contrib/likec4.tmLanguage.json +1 -1
  2. package/dist/LikeC4FileSystem.d.ts +13 -0
  3. package/dist/LikeC4FileSystem.js +27 -0
  4. package/dist/Rpc.d.ts +9 -0
  5. package/dist/Rpc.js +126 -0
  6. package/dist/ast.d.ts +200 -0
  7. package/dist/ast.js +276 -0
  8. package/dist/browser.d.ts +6 -20
  9. package/dist/browser.js +13 -0
  10. package/dist/formatting/LikeC4Formatter.d.ts +27 -0
  11. package/dist/formatting/LikeC4Formatter.js +261 -0
  12. package/dist/formatting/utils.d.ts +6 -0
  13. package/dist/formatting/utils.js +15 -0
  14. package/dist/generated/ast.d.ts +1242 -0
  15. package/dist/generated/ast.js +1945 -0
  16. package/dist/generated/grammar.d.ts +6 -0
  17. package/dist/generated/grammar.js +3 -0
  18. package/dist/generated/module.d.ts +9 -0
  19. package/dist/generated/module.js +23 -0
  20. package/dist/generated-lib/icons.d.ts +1 -0
  21. package/dist/{likec4lib.mjs → generated-lib/icons.js} +1 -6
  22. package/dist/index.d.ts +8 -31
  23. package/dist/index.js +13 -0
  24. package/dist/like-c4.langium +845 -0
  25. package/dist/likec4lib.d.ts +4 -6
  26. package/dist/likec4lib.js +4 -0
  27. package/dist/logger.d.ts +7 -0
  28. package/dist/logger.js +73 -0
  29. package/dist/lsp/CodeLensProvider.d.ts +9 -0
  30. package/dist/lsp/CodeLensProvider.js +40 -0
  31. package/dist/lsp/CompletionProvider.d.ts +6 -0
  32. package/dist/lsp/CompletionProvider.js +135 -0
  33. package/dist/lsp/DocumentHighlightProvider.d.ts +9 -0
  34. package/dist/lsp/DocumentHighlightProvider.js +10 -0
  35. package/dist/lsp/DocumentLinkProvider.d.ts +11 -0
  36. package/dist/lsp/DocumentLinkProvider.js +49 -0
  37. package/dist/lsp/DocumentSymbolProvider.d.ts +23 -0
  38. package/dist/lsp/DocumentSymbolProvider.js +202 -0
  39. package/dist/lsp/HoverProvider.d.ts +10 -0
  40. package/dist/lsp/HoverProvider.js +69 -0
  41. package/dist/lsp/RenameProvider.d.ts +5 -0
  42. package/dist/lsp/RenameProvider.js +6 -0
  43. package/dist/lsp/SemanticTokenProvider.d.ts +7 -0
  44. package/dist/lsp/SemanticTokenProvider.js +297 -0
  45. package/dist/lsp/index.d.ts +7 -0
  46. package/dist/lsp/index.js +7 -0
  47. package/dist/model/deployments-index.d.ts +60 -0
  48. package/dist/model/deployments-index.js +181 -0
  49. package/dist/model/fqn-computation.d.ts +3 -0
  50. package/dist/model/fqn-computation.js +72 -0
  51. package/dist/model/fqn-index.d.ts +25 -0
  52. package/dist/model/fqn-index.js +96 -0
  53. package/dist/model/index.d.ts +6 -0
  54. package/dist/model/index.js +6 -0
  55. package/dist/model/model-builder.d.ts +32 -0
  56. package/dist/model/model-builder.js +598 -0
  57. package/dist/model/model-locator.d.ts +23 -0
  58. package/dist/model/model-locator.js +126 -0
  59. package/dist/model/model-parser-where.d.ts +3 -0
  60. package/dist/model/model-parser-where.js +70 -0
  61. package/dist/model/model-parser.d.ts +292 -0
  62. package/dist/model/model-parser.js +72 -0
  63. package/dist/model/parser/Base.d.ts +28 -0
  64. package/dist/model/parser/Base.js +87 -0
  65. package/dist/model/parser/DeploymentModelParser.d.ts +33 -0
  66. package/dist/model/parser/DeploymentModelParser.js +162 -0
  67. package/dist/model/parser/DeploymentViewParser.d.ts +38 -0
  68. package/dist/model/parser/DeploymentViewParser.js +98 -0
  69. package/dist/model/parser/FqnRefParser.d.ts +29 -0
  70. package/dist/model/parser/FqnRefParser.js +108 -0
  71. package/dist/model/parser/GlobalsParser.d.ts +66 -0
  72. package/dist/model/parser/GlobalsParser.js +80 -0
  73. package/dist/model/parser/ModelParser.d.ts +27 -0
  74. package/dist/model/parser/ModelParser.js +122 -0
  75. package/dist/model/parser/PredicatesParser.d.ts +34 -0
  76. package/dist/model/parser/PredicatesParser.js +272 -0
  77. package/dist/model/parser/SpecificationParser.d.ts +27 -0
  78. package/dist/model/parser/SpecificationParser.js +120 -0
  79. package/dist/model/parser/ViewsParser.d.ts +64 -0
  80. package/dist/model/parser/ViewsParser.js +377 -0
  81. package/dist/model-change/ModelChanges.d.ts +15 -0
  82. package/dist/model-change/ModelChanges.js +89 -0
  83. package/dist/model-change/changeElementStyle.d.ts +16 -0
  84. package/dist/model-change/changeElementStyle.js +136 -0
  85. package/dist/model-change/changeViewLayout.d.ts +12 -0
  86. package/dist/model-change/changeViewLayout.js +32 -0
  87. package/dist/model-change/saveManualLayout.d.ts +11 -0
  88. package/dist/model-change/saveManualLayout.js +27 -0
  89. package/dist/module.d.ts +62 -0
  90. package/dist/module.js +123 -0
  91. package/dist/protocol.d.ts +27 -27
  92. package/dist/protocol.js +14 -0
  93. package/dist/references/index.d.ts +3 -0
  94. package/dist/references/index.js +3 -0
  95. package/dist/references/name-provider.d.ts +9 -0
  96. package/dist/references/name-provider.js +33 -0
  97. package/dist/references/scope-computation.d.ts +20 -0
  98. package/dist/references/scope-computation.js +281 -0
  99. package/dist/references/scope-provider.d.ts +16 -0
  100. package/dist/references/scope-provider.js +165 -0
  101. package/dist/shared/NodeKindProvider.d.ts +15 -0
  102. package/dist/shared/NodeKindProvider.js +108 -0
  103. package/dist/shared/WorkspaceManager.d.ts +18 -0
  104. package/dist/shared/WorkspaceManager.js +36 -0
  105. package/dist/shared/WorkspaceSymbolProvider.d.ts +3 -0
  106. package/dist/shared/WorkspaceSymbolProvider.js +3 -0
  107. package/dist/shared/index.d.ts +3 -0
  108. package/dist/shared/index.js +3 -0
  109. package/dist/test/index.d.ts +1 -0
  110. package/dist/test/index.js +1 -0
  111. package/dist/test/setup.d.ts +1 -0
  112. package/dist/test/setup.js +7 -0
  113. package/dist/test/testServices.d.ts +22 -0
  114. package/dist/test/testServices.js +119 -0
  115. package/dist/utils/elementRef.d.ts +11 -0
  116. package/dist/utils/elementRef.js +15 -0
  117. package/dist/utils/fqnRef.d.ts +8 -0
  118. package/dist/utils/fqnRef.js +46 -0
  119. package/dist/utils/index.d.ts +1 -0
  120. package/dist/utils/index.js +1 -0
  121. package/dist/utils/printDocs.d.ts +2 -0
  122. package/dist/utils/printDocs.js +1 -0
  123. package/dist/utils/stringHash.d.ts +1 -0
  124. package/dist/utils/stringHash.js +5 -0
  125. package/dist/validation/_shared.d.ts +3 -0
  126. package/dist/validation/_shared.js +22 -0
  127. package/dist/validation/deployment-checks.d.ts +6 -0
  128. package/dist/validation/deployment-checks.js +114 -0
  129. package/dist/validation/dynamic-view-rule.d.ts +4 -0
  130. package/dist/validation/dynamic-view-rule.js +16 -0
  131. package/dist/validation/dynamic-view-step.d.ts +4 -0
  132. package/dist/validation/dynamic-view-step.js +33 -0
  133. package/dist/validation/element.d.ts +4 -0
  134. package/dist/validation/element.js +49 -0
  135. package/dist/validation/index.d.ts +15 -0
  136. package/dist/validation/index.js +152 -0
  137. package/dist/validation/property-checks.d.ts +6 -0
  138. package/dist/validation/property-checks.js +38 -0
  139. package/dist/validation/relation.d.ts +5 -0
  140. package/dist/validation/relation.js +56 -0
  141. package/dist/validation/specification.d.ts +11 -0
  142. package/dist/validation/specification.js +136 -0
  143. package/dist/validation/view-predicates/element-with.d.ts +4 -0
  144. package/dist/validation/view-predicates/element-with.js +30 -0
  145. package/dist/validation/view-predicates/expanded-element.d.ts +4 -0
  146. package/dist/validation/view-predicates/expanded-element.js +11 -0
  147. package/dist/validation/view-predicates/expression-v2.d.ts +5 -0
  148. package/dist/validation/view-predicates/expression-v2.js +83 -0
  149. package/dist/validation/view-predicates/incoming.d.ts +4 -0
  150. package/dist/validation/view-predicates/incoming.js +15 -0
  151. package/dist/validation/view-predicates/index.d.ts +6 -0
  152. package/dist/validation/view-predicates/index.js +6 -0
  153. package/dist/validation/view-predicates/outgoing.d.ts +4 -0
  154. package/dist/validation/view-predicates/outgoing.js +15 -0
  155. package/dist/validation/view-predicates/relation-with.d.ts +4 -0
  156. package/dist/validation/view-predicates/relation-with.js +12 -0
  157. package/dist/validation/view.d.ts +4 -0
  158. package/dist/validation/view.js +23 -0
  159. package/dist/view-utils/assignNavigateTo.d.ts +2 -0
  160. package/dist/view-utils/assignNavigateTo.js +25 -0
  161. package/dist/view-utils/index.d.ts +2 -0
  162. package/dist/view-utils/index.js +2 -0
  163. package/dist/view-utils/manual-layout.d.ts +7 -0
  164. package/dist/view-utils/manual-layout.js +99 -0
  165. package/dist/view-utils/resolve-relative-paths.d.ts +2 -0
  166. package/dist/view-utils/resolve-relative-paths.js +78 -0
  167. package/package.json +42 -73
  168. package/src/LikeC4FileSystem.ts +22 -21
  169. package/src/Rpc.ts +6 -3
  170. package/src/ast.ts +136 -172
  171. package/src/browser.ts +10 -11
  172. package/src/generated/ast.ts +656 -40
  173. package/src/generated/grammar.ts +1 -1
  174. package/src/index.ts +11 -8
  175. package/src/like-c4.langium +173 -22
  176. package/src/logger.ts +41 -57
  177. package/src/lsp/CodeLensProvider.ts +0 -1
  178. package/src/lsp/CompletionProvider.ts +20 -5
  179. package/src/lsp/DocumentSymbolProvider.ts +5 -2
  180. package/src/lsp/HoverProvider.ts +37 -3
  181. package/src/lsp/SemanticTokenProvider.ts +58 -32
  182. package/src/model/deployments-index.ts +222 -0
  183. package/src/model/fqn-computation.ts +1 -1
  184. package/src/model/fqn-index.ts +0 -1
  185. package/src/model/index.ts +1 -0
  186. package/src/model/model-builder.ts +176 -39
  187. package/src/model/model-locator.ts +36 -7
  188. package/src/model/model-parser.ts +69 -1119
  189. package/src/model/parser/Base.ts +107 -0
  190. package/src/model/parser/DeploymentModelParser.ts +192 -0
  191. package/src/model/parser/DeploymentViewParser.ts +116 -0
  192. package/src/model/parser/FqnRefParser.ts +118 -0
  193. package/src/model/parser/GlobalsParser.ts +96 -0
  194. package/src/model/parser/ModelParser.ts +141 -0
  195. package/src/model/parser/PredicatesParser.ts +291 -0
  196. package/src/model/parser/SpecificationParser.ts +133 -0
  197. package/src/model/parser/ViewsParser.ts +428 -0
  198. package/src/model-change/changeViewLayout.ts +2 -2
  199. package/src/module.ts +26 -21
  200. package/src/protocol.ts +10 -6
  201. package/src/references/index.ts +1 -0
  202. package/src/references/name-provider.ts +37 -0
  203. package/src/references/scope-computation.ts +130 -21
  204. package/src/references/scope-provider.ts +68 -35
  205. package/src/shared/NodeKindProvider.ts +15 -3
  206. package/src/{elementRef.ts → utils/elementRef.ts} +1 -1
  207. package/src/utils/fqnRef.ts +56 -0
  208. package/src/utils/stringHash.ts +2 -2
  209. package/src/validation/_shared.ts +6 -5
  210. package/src/validation/deployment-checks.ts +131 -0
  211. package/src/validation/dynamic-view-step.ts +1 -1
  212. package/src/validation/index.ts +104 -6
  213. package/src/validation/relation.ts +1 -1
  214. package/src/validation/view-predicates/expression-v2.ts +101 -0
  215. package/src/validation/view-predicates/index.ts +1 -0
  216. package/src/view-utils/assignNavigateTo.ts +6 -5
  217. package/src/view-utils/index.ts +0 -1
  218. package/src/view-utils/manual-layout.ts +25 -0
  219. package/dist/browser.cjs +0 -25
  220. package/dist/browser.d.cts +0 -23
  221. package/dist/browser.d.mts +0 -23
  222. package/dist/browser.mjs +0 -20
  223. package/dist/index.cjs +0 -53
  224. package/dist/index.d.cts +0 -34
  225. package/dist/index.d.mts +0 -34
  226. package/dist/index.mjs +0 -46
  227. package/dist/likec4lib.cjs +0 -1546
  228. package/dist/likec4lib.d.cts +0 -6
  229. package/dist/likec4lib.d.mts +0 -6
  230. package/dist/model-graph/index.cjs +0 -10
  231. package/dist/model-graph/index.d.cts +0 -81
  232. package/dist/model-graph/index.d.mts +0 -81
  233. package/dist/model-graph/index.d.ts +0 -81
  234. package/dist/model-graph/index.mjs +0 -1
  235. package/dist/protocol.cjs +0 -25
  236. package/dist/protocol.d.cts +0 -45
  237. package/dist/protocol.d.mts +0 -45
  238. package/dist/protocol.mjs +0 -17
  239. package/dist/shared/language-server.BIbAD1T-.mjs +0 -6292
  240. package/dist/shared/language-server.BQRvVmE0.d.cts +0 -1303
  241. package/dist/shared/language-server.BysPcTxr.d.ts +0 -1303
  242. package/dist/shared/language-server.D2QdbOJO.cjs +0 -1995
  243. package/dist/shared/language-server.DGrBGmsd.mjs +0 -1981
  244. package/dist/shared/language-server.DKV_FdPN.cjs +0 -6304
  245. package/dist/shared/language-server._wkyPgso.d.mts +0 -1303
  246. package/src/model-graph/LikeC4ModelGraph.ts +0 -338
  247. package/src/model-graph/compute-view/__test__/fixture.ts +0 -630
  248. package/src/model-graph/compute-view/compute.ts +0 -788
  249. package/src/model-graph/compute-view/index.ts +0 -33
  250. package/src/model-graph/compute-view/predicates.ts +0 -509
  251. package/src/model-graph/dynamic-view/__test__/fixture.ts +0 -61
  252. package/src/model-graph/dynamic-view/compute.ts +0 -313
  253. package/src/model-graph/dynamic-view/index.ts +0 -29
  254. package/src/model-graph/index.ts +0 -3
  255. package/src/model-graph/utils/applyCustomElementProperties.ts +0 -65
  256. package/src/model-graph/utils/applyCustomRelationProperties.ts +0 -41
  257. package/src/model-graph/utils/applyViewRuleStyles.ts +0 -49
  258. package/src/model-graph/utils/buildComputeNodes.ts +0 -113
  259. package/src/model-graph/utils/buildElementNotations.ts +0 -63
  260. package/src/model-graph/utils/elementExpressionToPredicate.ts +0 -39
  261. package/src/model-graph/utils/relationExpressionToPredicates.ts +0 -43
  262. package/src/model-graph/utils/sortNodes.ts +0 -105
  263. package/src/model-graph/utils/uniqueTags.test.ts +0 -42
  264. package/src/model-graph/utils/uniqueTags.ts +0 -19
  265. package/src/utils/graphlib.ts +0 -9
  266. package/src/view-utils/resolve-extended-views.ts +0 -66
  267. package/src/view-utils/resolve-global-rules.ts +0 -88
  268. package/src/view-utils/view-hash.ts +0 -27
@@ -3,12 +3,14 @@ import {
3
3
  compareRelations,
4
4
  computeColorValues,
5
5
  type CustomColorDefinitions,
6
- isElementView,
6
+ DeploymentElement,
7
7
  isScopedElementView,
8
+ LikeC4Model,
8
9
  parentFqn,
9
10
  sortByFqnHierarchically,
10
- type ViewID
11
+ type ViewId
11
12
  } from '@likec4/core'
13
+ import { resolveRulesExtendedViews } from '@likec4/core/compute-view'
12
14
  import { deepEqual as eq } from 'fast-equals'
13
15
  import type { Cancellation, LangiumDocument, LangiumDocuments, URI, WorkspaceCache } from 'langium'
14
16
  import { Disposable, DocumentState, interruptAndCheck } from 'langium'
@@ -17,6 +19,7 @@ import {
17
19
  flatMap,
18
20
  groupBy,
19
21
  indexBy,
22
+ isDefined,
20
23
  isEmpty,
21
24
  isNonNullish,
22
25
  isNullish,
@@ -25,6 +28,7 @@ import {
25
28
  map,
26
29
  mapToObj,
27
30
  mapValues,
31
+ pick,
28
32
  pipe,
29
33
  prop,
30
34
  reduce,
@@ -33,6 +37,7 @@ import {
33
37
  values
34
38
  } from 'remeda'
35
39
  import type {
40
+ ParsedAstDeploymentRelation,
36
41
  ParsedAstElement,
37
42
  ParsedAstRelation,
38
43
  ParsedAstSpecification,
@@ -42,14 +47,14 @@ import type {
42
47
  } from '../ast'
43
48
  import { isParsedLikeC4LangiumDocument } from '../ast'
44
49
  import { logError, logger, logWarnError } from '../logger'
45
- import { computeDynamicView, computeView, LikeC4ModelGraph } from '../model-graph'
46
50
  import type { LikeC4Services } from '../module'
47
- import { assignNavigateTo, resolveRelativePaths, resolveRulesExtendedViews } from '../view-utils'
51
+ import { assignNavigateTo, resolveRelativePaths } from '../view-utils'
48
52
 
49
53
  function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[]): c4.ParsedLikeC4Model {
50
54
  // Merge specifications and globals from all documents
51
55
  const c4Specification: ParsedAstSpecification = {
52
56
  tags: new Set(),
57
+ deployments: {},
53
58
  elements: {},
54
59
  relationships: {},
55
60
  colors: {}
@@ -69,7 +74,7 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
69
74
  Object.assign(c4Specification.elements, spec.elements)
70
75
  Object.assign(c4Specification.relationships, spec.relationships)
71
76
  Object.assign(c4Specification.colors, spec.colors)
72
-
77
+ Object.assign(c4Specification.deployments, spec.deployments)
73
78
  Object.assign(globals.predicates, c4Globals.predicates)
74
79
  Object.assign(globals.dynamicPredicates, c4Globals.dynamicPredicates)
75
80
  Object.assign(globals.styles, c4Globals.styles)
@@ -186,10 +191,12 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
186
191
  links: unresolvedLinks,
187
192
  id,
188
193
  ...model
189
- }: ParsedAstRelation): c4.Relation | null => {
194
+ }: ParsedAstRelation): c4.ModelRelation | null => {
190
195
  if (isNullish(elements[source]) || isNullish(elements[target])) {
191
196
  logger.warn(
192
- `Invalid relation ${id}, source: ${source}(${!!elements[source]}), target: ${target}(${!!elements[target]})`
197
+ `Invalid relation ${id} at ${doc.uri.path} ${astPath}, source: ${source}(${!!elements[
198
+ source
199
+ ]}), target: ${target}(${!!elements[target]})`
193
200
  )
194
201
  return null
195
202
  }
@@ -204,15 +211,15 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
204
211
  target,
205
212
  kind,
206
213
  id
207
- } satisfies c4.Relation
214
+ } satisfies c4.ModelRelation
208
215
  }
209
216
  return {
210
- ...(links && { links }),
217
+ ...links && { links },
211
218
  ...model,
212
219
  source,
213
220
  target,
214
221
  id
215
- } satisfies c4.Relation
222
+ } satisfies c4.ModelRelation
216
223
  }
217
224
  }
218
225
 
@@ -225,6 +232,128 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
225
232
  indexBy(prop('id'))
226
233
  )
227
234
 
235
+ function toDeploymentElement(doc: LangiumDocument) {
236
+ return (parsed: c4.DeploymentElement): c4.DeploymentElement | null => {
237
+ if (!DeploymentElement.isDeploymentNode(parsed)) {
238
+ if (!parsed.links || parsed.links.length === 0) {
239
+ return parsed
240
+ }
241
+ const links = resolveLinks(doc, parsed.links)
242
+ return {
243
+ ...parsed,
244
+ links
245
+ }
246
+ }
247
+ try {
248
+ const __kind = c4Specification.deployments[parsed.kind]
249
+ if (!__kind) {
250
+ logger.warn(`No kind '${parsed.kind}' found for ${parsed.id}`)
251
+ return null
252
+ }
253
+ let {
254
+ technology = __kind.technology,
255
+ notation = __kind.notation,
256
+ links,
257
+ style
258
+ } = parsed
259
+ return {
260
+ ...parsed,
261
+ ...notation && { notation },
262
+ ...technology && { technology },
263
+ style: {
264
+ border: 'dashed',
265
+ opacity: 10,
266
+ ...__kind.style,
267
+ ...style
268
+ },
269
+ links: links ? resolveLinks(doc, links) : null
270
+ }
271
+ } catch (e) {
272
+ logWarnError(e)
273
+ }
274
+ return null
275
+ }
276
+ }
277
+
278
+ const deploymentElements = pipe(
279
+ docs,
280
+ flatMap(d => map(d.c4Deployments, toDeploymentElement(d))),
281
+ filter(isTruthy),
282
+ // sort from root elements to nested, so that parent is always present
283
+ // Import to preserve the order from the source
284
+ sortByFqnHierarchically,
285
+ reduce(
286
+ (acc, el) => {
287
+ const parent = parentFqn(el.id)
288
+ if (parent && isNullish(acc[parent])) {
289
+ logWarnError(`No parent found for deployment element ${el.id}`)
290
+ return acc
291
+ }
292
+ acc[el.id] = el
293
+ return acc
294
+ },
295
+ {} as c4.ParsedLikeC4Model['deployments']['elements']
296
+ )
297
+ )
298
+
299
+ function toDeploymentRelation(doc: LangiumDocument) {
300
+ return ({
301
+ astPath,
302
+ source,
303
+ target,
304
+ kind,
305
+ links: unresolvedLinks,
306
+ id,
307
+ ...model
308
+ }: ParsedAstDeploymentRelation): c4.DeploymentRelation | null => {
309
+ if (isNullish(deploymentElements[source.id]) || isNullish(deploymentElements[target.id])) {
310
+ logger.warn(
311
+ `Invalid deployment relation ${id} at ${doc.uri.path} ${astPath}, source: ${source.id}(${!!deploymentElements[
312
+ source.id
313
+ ]}), target: ${target.id}(${!!deploymentElements[target.id]})`
314
+ )
315
+ return null
316
+ }
317
+ const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null
318
+
319
+ if (isNonNullish(kind) && kind in c4Specification.relationships) {
320
+ return {
321
+ ...c4Specification.relationships[kind],
322
+ ...model,
323
+ ...(links && { links }),
324
+ source,
325
+ target,
326
+ kind,
327
+ id
328
+ } satisfies c4.DeploymentRelation
329
+ }
330
+ return {
331
+ ...links && { links },
332
+ ...model,
333
+ source,
334
+ target,
335
+ id
336
+ } satisfies c4.DeploymentRelation
337
+ }
338
+ }
339
+
340
+ const deploymentRelations = pipe(
341
+ docs,
342
+ flatMap(d => map(d.c4DeploymentRelations, toDeploymentRelation(d))),
343
+ filter(isTruthy),
344
+ reduce(
345
+ (acc, el) => {
346
+ if (isDefined(acc[el.id])) {
347
+ logWarnError(`Duplicate deployment relation ${el.id}`)
348
+ return acc
349
+ }
350
+ acc[el.id] = el
351
+ return acc
352
+ },
353
+ {} as c4.ParsedLikeC4Model['deployments']['relations']
354
+ )
355
+ )
356
+
228
357
  function toC4View(doc: LangiumDocument) {
229
358
  const docUri = doc.uri.toString()
230
359
  return (parsedAstView: ParsedAstView): c4.LikeC4View => {
@@ -273,7 +402,7 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
273
402
  if (!parsedViews.some(v => v.id === 'index')) {
274
403
  parsedViews.unshift({
275
404
  __: 'element',
276
- id: 'index' as ViewID,
405
+ id: 'index' as ViewId,
277
406
  title: 'Landscape view',
278
407
  description: null,
279
408
  tags: null,
@@ -301,12 +430,17 @@ function buildModel(services: LikeC4Services, docs: ParsedLikeC4LangiumDocument[
301
430
  specification: {
302
431
  tags: Array.from(c4Specification.tags),
303
432
  elements: c4Specification.elements,
304
- relationships: c4Specification.relationships
433
+ relationships: c4Specification.relationships,
434
+ deployments: c4Specification.deployments
305
435
  },
306
436
  elements,
307
437
  relations,
308
438
  globals,
309
- views
439
+ views,
440
+ deployments: {
441
+ elements: deploymentElements,
442
+ relations: deploymentRelations
443
+ }
310
444
  }
311
445
  }
312
446
 
@@ -335,8 +469,8 @@ export class LikeC4ModelBuilder {
335
469
  let parsed = [] as URI[]
336
470
  try {
337
471
  logger.debug(`[ModelBuilder] onValidated (${docs.length} docs)`)
338
- for (const doc of parser.parse(docs)) {
339
- parsed.push(doc.uri)
472
+ for (const doc of docs) {
473
+ parsed.push(parser.parse(doc).uri)
340
474
  }
341
475
  } catch (e) {
342
476
  logWarnError(e)
@@ -356,13 +490,13 @@ export class LikeC4ModelBuilder {
356
490
  * Otherwise, the model may be incomplete.
357
491
  */
358
492
  public unsafeSyncBuildModel(): c4.ParsedLikeC4Model | null {
493
+ const docs = this.documents()
494
+ if (docs.length === 0) {
495
+ logger.debug('[ModelBuilder] No documents to build model from')
496
+ return null
497
+ }
359
498
  const cache = this.services.WorkspaceCache as WorkspaceCache<string, c4.ParsedLikeC4Model | null>
360
499
  return cache.get(CACHE_KEY_PARSED_MODEL, () => {
361
- const docs = this.documents()
362
- if (docs.length === 0) {
363
- logger.debug('[ModelBuilder] No documents to build model from')
364
- return null
365
- }
366
500
  logger.debug(`[ModelBuilder] buildModel (${docs.length} docs)`)
367
501
  return buildModel(this.services, docs)
368
502
  })
@@ -370,8 +504,9 @@ export class LikeC4ModelBuilder {
370
504
 
371
505
  public async buildModel(cancelToken?: Cancellation.CancellationToken): Promise<c4.ParsedLikeC4Model | null> {
372
506
  const cache = this.services.WorkspaceCache as WorkspaceCache<string, c4.ParsedLikeC4Model | null>
373
- if (cache.has(CACHE_KEY_PARSED_MODEL)) {
374
- return cache.get(CACHE_KEY_PARSED_MODEL)!
507
+ const cached = cache.get(CACHE_KEY_PARSED_MODEL)
508
+ if (cached) {
509
+ return cached
375
510
  }
376
511
  return await this.services.shared.workspace.WorkspaceLock.read(async () => {
377
512
  if (cancelToken) {
@@ -381,7 +516,7 @@ export class LikeC4ModelBuilder {
381
516
  })
382
517
  }
383
518
 
384
- private previousViews: Record<ViewID, c4.ComputedView> = {}
519
+ private previousViews: Record<ViewId, c4.ComputedView> = {}
385
520
 
386
521
  /**
387
522
  * WARNING:
@@ -392,13 +527,10 @@ export class LikeC4ModelBuilder {
392
527
  const cache = this.services.WorkspaceCache as WorkspaceCache<string, c4.ComputedLikeC4Model>
393
528
  const viewsCache = this.services.WorkspaceCache as WorkspaceCache<string, c4.ComputedView | null>
394
529
  return cache.get(CACHE_KEY_COMPUTED_MODEL, () => {
395
- const index = new LikeC4ModelGraph(model)
396
-
530
+ const computeView = LikeC4Model.makeCompute(model)
397
531
  const allViews = [] as c4.ComputedView[]
398
532
  for (const view of values(model.views)) {
399
- const result = isElementView(view)
400
- ? computeView(view, index)
401
- : computeDynamicView(view, index)
533
+ const result = computeView(view)
402
534
  if (!result.isSuccess) {
403
535
  logWarnError(result.error)
404
536
  continue
@@ -414,10 +546,15 @@ export class LikeC4ModelBuilder {
414
546
  })
415
547
  this.previousViews = { ...views }
416
548
  return {
417
- specification: model.specification,
418
- elements: model.elements,
419
- relations: model.relations,
420
- globals: model.globals,
549
+ ...structuredClone(
550
+ pick(model, [
551
+ 'specification',
552
+ 'elements',
553
+ 'relations',
554
+ 'globals',
555
+ 'deployments'
556
+ ])
557
+ ),
421
558
  views
422
559
  }
423
560
  })
@@ -443,7 +580,7 @@ export class LikeC4ModelBuilder {
443
580
  }
444
581
 
445
582
  public async computeView(
446
- viewId: ViewID,
583
+ viewId: ViewId,
447
584
  cancelToken?: Cancellation.CancellationToken
448
585
  ): Promise<c4.ComputedView | null> {
449
586
  const cache = this.services.WorkspaceCache as WorkspaceCache<string, c4.ComputedView | null>
@@ -462,10 +599,7 @@ export class LikeC4ModelBuilder {
462
599
  logger.warn(`[ModelBuilder] Cannot find view ${viewId}`)
463
600
  return null
464
601
  }
465
- const index = new LikeC4ModelGraph(model)
466
- const result = isElementView(view)
467
- ? computeView(view, index)
468
- : computeDynamicView(view, index)
602
+ const result = LikeC4Model.makeCompute(model)(view)
469
603
  if (!result.isSuccess) {
470
604
  logError(result.error)
471
605
  return null
@@ -490,8 +624,11 @@ export class LikeC4ModelBuilder {
490
624
  }
491
625
 
492
626
  const previous = this.previousViews[viewId]
493
- computedView = previous && eq(computedView, previous) ? previous : computedView
494
- this.previousViews[viewId] = computedView
627
+ if (previous && eq(computedView, previous)) {
628
+ computedView = previous
629
+ } else {
630
+ this.previousViews[viewId] = computedView
631
+ }
495
632
 
496
633
  return computedView
497
634
  })
@@ -1,10 +1,12 @@
1
1
  import type * as c4 from '@likec4/core'
2
2
  import type { LangiumDocuments } from 'langium'
3
3
  import { AstUtils, GrammarUtils } from 'langium'
4
+ import { isString } from 'remeda'
4
5
  import type { Location } from 'vscode-languageserver-types'
5
6
  import type { ParsedAstElement } from '../ast'
6
7
  import { ast, isParsedLikeC4LangiumDocument } from '../ast'
7
8
  import type { LikeC4Services } from '../module'
9
+ import type { DeploymentsIndex } from './deployments-index'
8
10
  import { type FqnIndex } from './fqn-index'
9
11
 
10
12
  const { findNodeForKeyword, findNodeForProperty } = GrammarUtils
@@ -12,10 +14,12 @@ const { getDocument } = AstUtils
12
14
 
13
15
  export class LikeC4ModelLocator {
14
16
  private fqnIndex: FqnIndex
17
+ private deploymentsIndex: DeploymentsIndex
15
18
  private langiumDocuments: LangiumDocuments
16
19
 
17
20
  constructor(private services: LikeC4Services) {
18
21
  this.fqnIndex = services.likec4.FqnIndex
22
+ this.deploymentsIndex = services.likec4.DeploymentsIndex
19
23
  this.langiumDocuments = services.shared.workspace.LangiumDocuments
20
24
  }
21
25
 
@@ -23,10 +27,23 @@ export class LikeC4ModelLocator {
23
27
  return this.langiumDocuments.all.filter(isParsedLikeC4LangiumDocument)
24
28
  }
25
29
 
26
- public getParsedElement(astNode: ast.Element): ParsedAstElement | null {
27
- const fqn = this.fqnIndex.getFqn(astNode)
30
+ public getParsedElement(astNodeOrFqn: ast.Element | c4.Fqn): ParsedAstElement | null {
31
+ if (isString(astNodeOrFqn)) {
32
+ const fqn = astNodeOrFqn
33
+ const entry = this.fqnIndex.byFqn(astNodeOrFqn).head()
34
+ if (!entry) {
35
+ return null
36
+ }
37
+ const doc = this.langiumDocuments.getDocument(entry.documentUri)
38
+ if (!doc || !isParsedLikeC4LangiumDocument(doc)) {
39
+ return null
40
+ }
41
+ return doc.c4Elements.find(e => e.id === fqn) ?? null
42
+ }
43
+
44
+ const fqn = this.fqnIndex.getFqn(astNodeOrFqn)
28
45
  if (!fqn) return null
29
- const doc = getDocument(astNode)
46
+ const doc = getDocument(astNodeOrFqn)
30
47
  if (!isParsedLikeC4LangiumDocument(doc)) {
31
48
  return null
32
49
  }
@@ -44,10 +61,22 @@ export class LikeC4ModelLocator {
44
61
  range: docsegment.range
45
62
  }
46
63
  }
64
+ public locateDeploymentElement(fqn: c4.Fqn, _prop?: string): Location | null {
65
+ const entry = this.deploymentsIndex.byFqn(fqn).head()
66
+ const docsegment = entry?.nameSegment ?? entry?.selectionSegment
67
+ if (!entry || !docsegment) {
68
+ return null
69
+ }
70
+ return {
71
+ uri: entry.documentUri.toString(),
72
+ range: docsegment.range
73
+ }
74
+ }
47
75
 
48
- public locateRelation(relationId: c4.RelationID): Location | null {
76
+ public locateRelation(relationId: c4.RelationId): Location | null {
49
77
  for (const doc of this.documents()) {
50
78
  const relation = doc.c4Relations.find(r => r.id === relationId)
79
+ ?? doc.c4DeploymentRelations.find(r => r.id === relationId)
51
80
  if (!relation) {
52
81
  continue
53
82
  }
@@ -55,7 +84,7 @@ export class LikeC4ModelLocator {
55
84
  doc.parseResult.value,
56
85
  relation.astPath
57
86
  )
58
- if (!ast.isRelation(node)) {
87
+ if (!ast.isRelation(node) && !ast.isDeploymentRelation(node)) {
59
88
  continue
60
89
  }
61
90
 
@@ -76,7 +105,7 @@ export class LikeC4ModelLocator {
76
105
  return null
77
106
  }
78
107
 
79
- public locateViewAst(viewId: c4.ViewID) {
108
+ public locateViewAst(viewId: c4.ViewId) {
80
109
  for (const doc of this.documents()) {
81
110
  const view = doc.c4Views.find(r => r.id === viewId)
82
111
  if (!view) {
@@ -97,7 +126,7 @@ export class LikeC4ModelLocator {
97
126
  return null
98
127
  }
99
128
 
100
- public locateView(viewId: c4.ViewID): Location | null {
129
+ public locateView(viewId: c4.ViewId): Location | null {
101
130
  const res = this.locateViewAst(viewId)
102
131
  if (!res) {
103
132
  return null