@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
@@ -0,0 +1,598 @@
1
+ import {
2
+ compareRelations,
3
+ computeColorValues,
4
+ DeploymentElement,
5
+ isScopedElementView,
6
+ LikeC4Model,
7
+ parentFqn,
8
+ sortByFqnHierarchically
9
+ } from "@likec4/core";
10
+ import { resolveRulesExtendedViews } from "@likec4/core/compute-view";
11
+ import { deepEqual as eq } from "fast-equals";
12
+ import { Disposable, DocumentState, interruptAndCheck } from "langium";
13
+ import {
14
+ filter,
15
+ flatMap,
16
+ groupBy,
17
+ indexBy,
18
+ isDefined,
19
+ isEmpty,
20
+ isNonNullish,
21
+ isNullish,
22
+ isNumber,
23
+ isTruthy,
24
+ map,
25
+ mapToObj,
26
+ mapValues,
27
+ pick,
28
+ pipe,
29
+ prop,
30
+ reduce,
31
+ reverse,
32
+ sort,
33
+ values
34
+ } from "remeda";
35
+ import { isParsedLikeC4LangiumDocument } from "../ast.js";
36
+ import { logError, logger, logWarnError } from "../logger.js";
37
+ import { assignNavigateTo, resolveRelativePaths } from "../view-utils/index.js";
38
+ function buildModel(services, docs) {
39
+ const c4Specification = {
40
+ tags: /* @__PURE__ */ new Set(),
41
+ deployments: {},
42
+ elements: {},
43
+ relationships: {},
44
+ colors: {}
45
+ };
46
+ const globals = {
47
+ predicates: {},
48
+ dynamicPredicates: {},
49
+ styles: {}
50
+ };
51
+ for (const doc of docs) {
52
+ const {
53
+ c4Specification: spec,
54
+ c4Globals
55
+ } = doc;
56
+ spec.tags.forEach((t) => c4Specification.tags.add(t));
57
+ Object.assign(c4Specification.elements, spec.elements);
58
+ Object.assign(c4Specification.relationships, spec.relationships);
59
+ Object.assign(c4Specification.colors, spec.colors);
60
+ Object.assign(c4Specification.deployments, spec.deployments);
61
+ Object.assign(globals.predicates, c4Globals.predicates);
62
+ Object.assign(globals.dynamicPredicates, c4Globals.dynamicPredicates);
63
+ Object.assign(globals.styles, c4Globals.styles);
64
+ }
65
+ function resolveLinks(doc, links) {
66
+ return map(
67
+ links,
68
+ (link) => {
69
+ try {
70
+ const relative = services.lsp.DocumentLinkProvider.relativeLink(doc, link.url);
71
+ if (relative && relative !== link.url) {
72
+ return {
73
+ ...link,
74
+ relative
75
+ };
76
+ }
77
+ } catch (e) {
78
+ logWarnError(e);
79
+ }
80
+ return link;
81
+ }
82
+ );
83
+ }
84
+ const customColorDefinitions = mapValues(
85
+ c4Specification.colors,
86
+ (c) => computeColorValues(c.color)
87
+ );
88
+ function toModelElement(doc) {
89
+ return ({
90
+ tags,
91
+ links: unresolvedLinks,
92
+ style: {
93
+ color,
94
+ shape,
95
+ icon,
96
+ opacity,
97
+ border
98
+ },
99
+ id,
100
+ kind,
101
+ title,
102
+ description,
103
+ technology,
104
+ metadata
105
+ }) => {
106
+ try {
107
+ const __kind = c4Specification.elements[kind];
108
+ if (!__kind) {
109
+ logger.warn(`No kind '${kind}' found for ${id}`);
110
+ return null;
111
+ }
112
+ const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null;
113
+ color ??= __kind.style.color;
114
+ shape ??= __kind.style.shape;
115
+ icon ??= __kind.style.icon;
116
+ opacity ??= __kind.style.opacity;
117
+ border ??= __kind.style.border;
118
+ technology ??= __kind.technology;
119
+ return {
120
+ ...color && { color },
121
+ ...shape && { shape },
122
+ ...icon && { icon },
123
+ ...metadata && !isEmpty(metadata) && { metadata },
124
+ ...__kind.notation && { notation: __kind.notation },
125
+ style: {
126
+ ...border && { border },
127
+ ...isNumber(opacity) && { opacity }
128
+ },
129
+ links,
130
+ tags: tags ?? null,
131
+ technology: technology ?? null,
132
+ description: description ?? null,
133
+ title,
134
+ kind,
135
+ id
136
+ };
137
+ } catch (e) {
138
+ logWarnError(e);
139
+ }
140
+ return null;
141
+ };
142
+ }
143
+ const elements = pipe(
144
+ docs,
145
+ flatMap((d) => map(d.c4Elements, toModelElement(d))),
146
+ filter(isTruthy),
147
+ // sort from root elements to nested, so that parent is always present
148
+ // Import to preserve the order from the source
149
+ sortByFqnHierarchically,
150
+ reduce(
151
+ (acc, el) => {
152
+ const parent = parentFqn(el.id);
153
+ if (parent && isNullish(acc[parent])) {
154
+ logWarnError(`No parent found for ${el.id}`);
155
+ return acc;
156
+ }
157
+ acc[el.id] = el;
158
+ return acc;
159
+ },
160
+ {}
161
+ )
162
+ );
163
+ function toModelRelation(doc) {
164
+ return ({
165
+ astPath,
166
+ source,
167
+ target,
168
+ kind,
169
+ links: unresolvedLinks,
170
+ id,
171
+ ...model
172
+ }) => {
173
+ if (isNullish(elements[source]) || isNullish(elements[target])) {
174
+ logger.warn(
175
+ `Invalid relation ${id} at ${doc.uri.path} ${astPath}, source: ${source}(${!!elements[source]}), target: ${target}(${!!elements[target]})`
176
+ );
177
+ return null;
178
+ }
179
+ const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null;
180
+ if (isNonNullish(kind) && kind in c4Specification.relationships) {
181
+ return {
182
+ ...c4Specification.relationships[kind],
183
+ ...model,
184
+ ...links && { links },
185
+ source,
186
+ target,
187
+ kind,
188
+ id
189
+ };
190
+ }
191
+ return {
192
+ ...links && { links },
193
+ ...model,
194
+ source,
195
+ target,
196
+ id
197
+ };
198
+ };
199
+ }
200
+ const relations = pipe(
201
+ docs,
202
+ flatMap((d) => map(d.c4Relations, toModelRelation(d))),
203
+ filter(isTruthy),
204
+ sort(compareRelations),
205
+ reverse(),
206
+ indexBy(prop("id"))
207
+ );
208
+ function toDeploymentElement(doc) {
209
+ return (parsed) => {
210
+ if (!DeploymentElement.isDeploymentNode(parsed)) {
211
+ if (!parsed.links || parsed.links.length === 0) {
212
+ return parsed;
213
+ }
214
+ const links = resolveLinks(doc, parsed.links);
215
+ return {
216
+ ...parsed,
217
+ links
218
+ };
219
+ }
220
+ try {
221
+ const __kind = c4Specification.deployments[parsed.kind];
222
+ if (!__kind) {
223
+ logger.warn(`No kind '${parsed.kind}' found for ${parsed.id}`);
224
+ return null;
225
+ }
226
+ let {
227
+ technology = __kind.technology,
228
+ notation = __kind.notation,
229
+ links,
230
+ style
231
+ } = parsed;
232
+ return {
233
+ ...parsed,
234
+ ...notation && { notation },
235
+ ...technology && { technology },
236
+ style: {
237
+ border: "dashed",
238
+ opacity: 10,
239
+ ...__kind.style,
240
+ ...style
241
+ },
242
+ links: links ? resolveLinks(doc, links) : null
243
+ };
244
+ } catch (e) {
245
+ logWarnError(e);
246
+ }
247
+ return null;
248
+ };
249
+ }
250
+ const deploymentElements = pipe(
251
+ docs,
252
+ flatMap((d) => map(d.c4Deployments, toDeploymentElement(d))),
253
+ filter(isTruthy),
254
+ // sort from root elements to nested, so that parent is always present
255
+ // Import to preserve the order from the source
256
+ sortByFqnHierarchically,
257
+ reduce(
258
+ (acc, el) => {
259
+ const parent = parentFqn(el.id);
260
+ if (parent && isNullish(acc[parent])) {
261
+ logWarnError(`No parent found for deployment element ${el.id}`);
262
+ return acc;
263
+ }
264
+ acc[el.id] = el;
265
+ return acc;
266
+ },
267
+ {}
268
+ )
269
+ );
270
+ function toDeploymentRelation(doc) {
271
+ return ({
272
+ astPath,
273
+ source,
274
+ target,
275
+ kind,
276
+ links: unresolvedLinks,
277
+ id,
278
+ ...model
279
+ }) => {
280
+ if (isNullish(deploymentElements[source.id]) || isNullish(deploymentElements[target.id])) {
281
+ logger.warn(
282
+ `Invalid deployment relation ${id} at ${doc.uri.path} ${astPath}, source: ${source.id}(${!!deploymentElements[source.id]}), target: ${target.id}(${!!deploymentElements[target.id]})`
283
+ );
284
+ return null;
285
+ }
286
+ const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null;
287
+ if (isNonNullish(kind) && kind in c4Specification.relationships) {
288
+ return {
289
+ ...c4Specification.relationships[kind],
290
+ ...model,
291
+ ...links && { links },
292
+ source,
293
+ target,
294
+ kind,
295
+ id
296
+ };
297
+ }
298
+ return {
299
+ ...links && { links },
300
+ ...model,
301
+ source,
302
+ target,
303
+ id
304
+ };
305
+ };
306
+ }
307
+ const deploymentRelations = pipe(
308
+ docs,
309
+ flatMap((d) => map(d.c4DeploymentRelations, toDeploymentRelation(d))),
310
+ filter(isTruthy),
311
+ reduce(
312
+ (acc, el) => {
313
+ if (isDefined(acc[el.id])) {
314
+ logWarnError(`Duplicate deployment relation ${el.id}`);
315
+ return acc;
316
+ }
317
+ acc[el.id] = el;
318
+ return acc;
319
+ },
320
+ {}
321
+ )
322
+ );
323
+ function toC4View(doc) {
324
+ const docUri = doc.uri.toString();
325
+ return (parsedAstView) => {
326
+ let {
327
+ id,
328
+ title,
329
+ description,
330
+ tags,
331
+ links: unresolvedLinks,
332
+ // ignore this property
333
+ astPath: _ignore,
334
+ // model should include discriminant __
335
+ ...model
336
+ } = parsedAstView;
337
+ if (parsedAstView.__ === "element" && isNullish(title) && "viewOf" in parsedAstView) {
338
+ title = elements[parsedAstView.viewOf]?.title ?? null;
339
+ }
340
+ if (isNullish(title) && id === "index") {
341
+ title = "Landscape view";
342
+ }
343
+ const links = unresolvedLinks ? resolveLinks(doc, unresolvedLinks) : null;
344
+ return {
345
+ ...model,
346
+ customColorDefinitions,
347
+ tags,
348
+ links,
349
+ docUri,
350
+ description,
351
+ title,
352
+ id
353
+ };
354
+ };
355
+ }
356
+ const parsedViews = pipe(
357
+ docs,
358
+ flatMap((d) => map(d.c4Views, toC4View(d))),
359
+ // Resolve relative paths and sort by
360
+ resolveRelativePaths
361
+ );
362
+ if (!parsedViews.some((v) => v.id === "index")) {
363
+ parsedViews.unshift({
364
+ __: "element",
365
+ id: "index",
366
+ title: "Landscape view",
367
+ description: null,
368
+ tags: null,
369
+ links: null,
370
+ customColorDefinitions,
371
+ rules: [
372
+ {
373
+ include: [
374
+ {
375
+ wildcard: true
376
+ }
377
+ ]
378
+ }
379
+ ]
380
+ });
381
+ }
382
+ const views = pipe(
383
+ parsedViews,
384
+ indexBy(prop("id")),
385
+ resolveRulesExtendedViews
386
+ );
387
+ return {
388
+ specification: {
389
+ tags: Array.from(c4Specification.tags),
390
+ elements: c4Specification.elements,
391
+ relationships: c4Specification.relationships,
392
+ deployments: c4Specification.deployments
393
+ },
394
+ elements,
395
+ relations,
396
+ globals,
397
+ views,
398
+ deployments: {
399
+ elements: deploymentElements,
400
+ relations: deploymentRelations
401
+ }
402
+ };
403
+ }
404
+ const CACHE_KEY_PARSED_MODEL = "ParsedLikeC4Model";
405
+ const CACHE_KEY_COMPUTED_MODEL = "ComputedLikeC4Model";
406
+ export class LikeC4ModelBuilder {
407
+ constructor(services) {
408
+ this.services = services;
409
+ this.langiumDocuments = services.shared.workspace.LangiumDocuments;
410
+ const parser = services.likec4.ModelParser;
411
+ services.shared.workspace.DocumentBuilder.onUpdate((_changed, deleted) => {
412
+ if (deleted.length > 0) {
413
+ this.notifyListeners(deleted);
414
+ }
415
+ });
416
+ services.shared.workspace.DocumentBuilder.onBuildPhase(
417
+ DocumentState.Validated,
418
+ async (docs, _cancelToken) => {
419
+ let parsed = [];
420
+ try {
421
+ logger.debug(`[ModelBuilder] onValidated (${docs.length} docs)`);
422
+ for (const doc of docs) {
423
+ parsed.push(parser.parse(doc).uri);
424
+ }
425
+ } catch (e) {
426
+ logWarnError(e);
427
+ }
428
+ if (parsed.length > 0) {
429
+ this.notifyListeners(parsed);
430
+ }
431
+ return await Promise.resolve();
432
+ }
433
+ );
434
+ logger.debug(`[ModelBuilder] Created`);
435
+ }
436
+ langiumDocuments;
437
+ listeners = [];
438
+ /**
439
+ * WARNING:
440
+ * This method is internal and should to be called only when all documents are known to be parsed.
441
+ * Otherwise, the model may be incomplete.
442
+ */
443
+ unsafeSyncBuildModel() {
444
+ const docs = this.documents();
445
+ if (docs.length === 0) {
446
+ logger.debug("[ModelBuilder] No documents to build model from");
447
+ return null;
448
+ }
449
+ const cache = this.services.WorkspaceCache;
450
+ return cache.get(CACHE_KEY_PARSED_MODEL, () => {
451
+ logger.debug(`[ModelBuilder] buildModel (${docs.length} docs)`);
452
+ return buildModel(this.services, docs);
453
+ });
454
+ }
455
+ async buildModel(cancelToken) {
456
+ const cache = this.services.WorkspaceCache;
457
+ const cached = cache.get(CACHE_KEY_PARSED_MODEL);
458
+ if (cached) {
459
+ return cached;
460
+ }
461
+ return await this.services.shared.workspace.WorkspaceLock.read(async () => {
462
+ if (cancelToken) {
463
+ await interruptAndCheck(cancelToken);
464
+ }
465
+ return this.unsafeSyncBuildModel();
466
+ });
467
+ }
468
+ previousViews = {};
469
+ /**
470
+ * WARNING:
471
+ * This method is internal and should to be called only when all documents are known to be parsed.
472
+ * Otherwise, the model may be incomplete.
473
+ */
474
+ unsafeSyncBuildComputedModel(model) {
475
+ const cache = this.services.WorkspaceCache;
476
+ const viewsCache = this.services.WorkspaceCache;
477
+ return cache.get(CACHE_KEY_COMPUTED_MODEL, () => {
478
+ const computeView = LikeC4Model.makeCompute(model);
479
+ const allViews = [];
480
+ for (const view of values(model.views)) {
481
+ const result = computeView(view);
482
+ if (!result.isSuccess) {
483
+ logWarnError(result.error);
484
+ continue;
485
+ }
486
+ allViews.push(result.view);
487
+ }
488
+ assignNavigateTo(allViews);
489
+ const views = mapToObj(allViews, (v) => {
490
+ const previous = this.previousViews[v.id];
491
+ const view = previous && eq(v, previous) ? previous : v;
492
+ viewsCache.set(computedViewKey(v.id), view);
493
+ return [v.id, view];
494
+ });
495
+ this.previousViews = { ...views };
496
+ return {
497
+ ...structuredClone(
498
+ pick(model, [
499
+ "specification",
500
+ "elements",
501
+ "relations",
502
+ "globals",
503
+ "deployments"
504
+ ])
505
+ ),
506
+ views
507
+ };
508
+ });
509
+ }
510
+ async buildComputedModel(cancelToken) {
511
+ const cache = this.services.WorkspaceCache;
512
+ if (cache.has(CACHE_KEY_COMPUTED_MODEL)) {
513
+ return cache.get(CACHE_KEY_COMPUTED_MODEL);
514
+ }
515
+ return await this.services.shared.workspace.WorkspaceLock.read(async () => {
516
+ if (cancelToken) {
517
+ await interruptAndCheck(cancelToken);
518
+ }
519
+ const model = this.unsafeSyncBuildModel();
520
+ if (!model) {
521
+ return null;
522
+ }
523
+ return this.unsafeSyncBuildComputedModel(model);
524
+ });
525
+ }
526
+ async computeView(viewId, cancelToken) {
527
+ const cache = this.services.WorkspaceCache;
528
+ const cacheKey = computedViewKey(viewId);
529
+ if (cache.has(cacheKey)) {
530
+ return cache.get(cacheKey);
531
+ }
532
+ return await this.services.shared.workspace.WorkspaceLock.read(async () => {
533
+ if (cancelToken) {
534
+ await interruptAndCheck(cancelToken);
535
+ }
536
+ return cache.get(cacheKey, () => {
537
+ const model = this.unsafeSyncBuildModel();
538
+ const view = model?.views[viewId];
539
+ if (!view) {
540
+ logger.warn(`[ModelBuilder] Cannot find view ${viewId}`);
541
+ return null;
542
+ }
543
+ const result = LikeC4Model.makeCompute(model)(view);
544
+ if (!result.isSuccess) {
545
+ logError(result.error);
546
+ return null;
547
+ }
548
+ let computedView = result.view;
549
+ const allElementViews = pipe(
550
+ model.views,
551
+ values(),
552
+ filter(isScopedElementView),
553
+ filter((v) => v.id !== viewId),
554
+ groupBy((v) => v.viewOf)
555
+ );
556
+ for (const node of computedView.nodes) {
557
+ if (!node.navigateTo) {
558
+ const viewsOfNode = allElementViews[node.id];
559
+ if (viewsOfNode) {
560
+ node.navigateTo = viewsOfNode[0].id;
561
+ }
562
+ }
563
+ }
564
+ const previous = this.previousViews[viewId];
565
+ if (previous && eq(computedView, previous)) {
566
+ computedView = previous;
567
+ } else {
568
+ this.previousViews[viewId] = computedView;
569
+ }
570
+ return computedView;
571
+ });
572
+ });
573
+ }
574
+ onModelParsed(callback) {
575
+ this.listeners.push(callback);
576
+ return Disposable.create(() => {
577
+ const index = this.listeners.indexOf(callback);
578
+ if (index >= 0) {
579
+ this.listeners.splice(index, 1);
580
+ }
581
+ });
582
+ }
583
+ documents() {
584
+ return this.langiumDocuments.all.filter(isParsedLikeC4LangiumDocument).toArray();
585
+ }
586
+ notifyListeners(docs) {
587
+ for (const listener of this.listeners) {
588
+ try {
589
+ listener(docs);
590
+ } catch (e) {
591
+ logError(e);
592
+ }
593
+ }
594
+ }
595
+ }
596
+ function computedViewKey(viewId) {
597
+ return `computed-view-${viewId}`;
598
+ }
@@ -0,0 +1,23 @@
1
+ import type * as c4 from '@likec4/core';
2
+ import type { Location } from 'vscode-languageserver-types';
3
+ import type { ParsedAstElement } from '../ast';
4
+ import { ast } from '../ast';
5
+ import type { LikeC4Services } from '../module';
6
+ export declare class LikeC4ModelLocator {
7
+ private services;
8
+ private fqnIndex;
9
+ private deploymentsIndex;
10
+ private langiumDocuments;
11
+ constructor(services: LikeC4Services);
12
+ private documents;
13
+ getParsedElement(astNodeOrFqn: ast.Element | c4.Fqn): ParsedAstElement | null;
14
+ locateElement(fqn: c4.Fqn, _prop?: string): Location | null;
15
+ locateDeploymentElement(fqn: c4.Fqn, _prop?: string): Location | null;
16
+ locateRelation(relationId: c4.RelationId): Location | null;
17
+ locateViewAst(viewId: c4.ViewId): {
18
+ doc: any;
19
+ view: any;
20
+ viewAst: ast.LikeC4View;
21
+ } | null;
22
+ locateView(viewId: c4.ViewId): Location | null;
23
+ }