@likec4/language-server 1.43.0 → 1.45.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 (301) hide show
  1. package/browser/package.json +1 -1
  2. package/browser-worker/package.json +1 -1
  3. package/dist/LikeC4LanguageServices.d.ts +13 -34
  4. package/dist/LikeC4LanguageServices.js +152 -0
  5. package/dist/Rpc.js +257 -0
  6. package/dist/ast.d.ts +5 -1
  7. package/dist/ast.js +257 -0
  8. package/dist/browser-worker.js +4 -0
  9. package/dist/browser.js +35 -0
  10. package/dist/bundled.js +44 -0
  11. package/dist/bundled.mjs +3568 -3900
  12. package/dist/documentation/documentation-provider.js +51 -0
  13. package/dist/documentation/index.js +1 -0
  14. package/dist/empty.js +2 -0
  15. package/dist/filesystem/ChokidarWatcher.d.ts +2 -0
  16. package/dist/filesystem/ChokidarWatcher.js +108 -0
  17. package/dist/filesystem/FileSystemWatcher.js +14 -0
  18. package/dist/filesystem/LikeC4FileSystem.d.ts +1 -2
  19. package/dist/filesystem/LikeC4FileSystem.js +126 -0
  20. package/dist/filesystem/index.d.ts +26 -0
  21. package/dist/filesystem/index.js +29 -0
  22. package/dist/formatting/LikeC4Formatter.js +637 -0
  23. package/dist/formatting/utils.js +18 -0
  24. package/dist/generated/ast.js +2155 -0
  25. package/dist/generated/{grammar.mjs → grammar.js} +6 -2
  26. package/dist/generated/module.d.ts +6 -1
  27. package/dist/generated/module.js +27 -0
  28. package/dist/generated-lib/{icons.mjs → icons.js} +11 -7
  29. package/dist/index.d.ts +10 -1
  30. package/dist/index.js +55 -0
  31. package/dist/{likec4lib.mjs → likec4lib.js} +3 -3
  32. package/dist/logger.js +81 -0
  33. package/dist/lsp/CodeActionProvider.d.ts +14 -0
  34. package/dist/lsp/CodeActionProvider.js +33 -0
  35. package/dist/lsp/CodeLensProvider.js +44 -0
  36. package/dist/lsp/CompletionProvider.d.ts +3 -1
  37. package/dist/lsp/CompletionProvider.js +200 -0
  38. package/dist/lsp/DocumentHighlightProvider.js +10 -0
  39. package/dist/lsp/DocumentLinkProvider.js +58 -0
  40. package/dist/lsp/DocumentSymbolProvider.js +306 -0
  41. package/dist/lsp/HoverProvider.js +106 -0
  42. package/dist/lsp/RenameProvider.js +6 -0
  43. package/dist/lsp/SemanticTokenProvider.js +257 -0
  44. package/dist/lsp/index.d.ts +1 -0
  45. package/dist/lsp/index.js +9 -0
  46. package/dist/mcp/MCPServerFactory.js +73 -0
  47. package/dist/mcp/NoopLikeC4MCPServer.js +17 -0
  48. package/dist/mcp/interfaces.js +5 -0
  49. package/dist/mcp/server/StdioLikeC4MCPServer.js +51 -0
  50. package/dist/mcp/server/StreamableLikeC4MCPServer.js +145 -0
  51. package/dist/mcp/server/WithMCPServer.js +56 -0
  52. package/dist/mcp/tools/_common.d.ts +8 -7
  53. package/dist/mcp/tools/_common.js +49 -0
  54. package/dist/mcp/tools/find-relationships.d.ts +7 -8
  55. package/dist/mcp/tools/find-relationships.js +150 -0
  56. package/dist/mcp/tools/list-projects.d.ts +3 -3
  57. package/dist/mcp/tools/list-projects.js +62 -0
  58. package/dist/mcp/tools/open-view.d.ts +6 -7
  59. package/dist/mcp/tools/open-view.js +52 -0
  60. package/dist/mcp/tools/read-deployment.d.ts +6 -7
  61. package/dist/mcp/tools/read-deployment.js +132 -0
  62. package/dist/mcp/tools/read-element.d.ts +6 -7
  63. package/dist/mcp/tools/read-element.js +194 -0
  64. package/dist/mcp/tools/read-project-summary.d.ts +5 -6
  65. package/dist/mcp/tools/read-project-summary.js +176 -0
  66. package/dist/mcp/tools/read-view.d.ts +6 -7
  67. package/dist/mcp/tools/read-view.js +203 -0
  68. package/dist/mcp/tools/search-element.d.ts +3 -3
  69. package/dist/mcp/tools/search-element.js +177 -0
  70. package/dist/mcp/utils.d.ts +2 -2
  71. package/dist/mcp/utils.js +48 -0
  72. package/dist/model/builder/MergedExtends.js +74 -0
  73. package/dist/model/builder/MergedSpecification.js +175 -0
  74. package/dist/model/builder/buildModel.js +176 -0
  75. package/dist/model/deployments-index.js +102 -0
  76. package/dist/model/fqn-index.d.ts +1 -2
  77. package/dist/model/fqn-index.js +247 -0
  78. package/dist/model/index.js +6 -0
  79. package/dist/model/model-builder.d.ts +13 -11
  80. package/dist/model/model-builder.js +232 -0
  81. package/dist/model/model-locator.d.ts +6 -5
  82. package/dist/model/model-locator.js +240 -0
  83. package/dist/model/model-parser-where.js +81 -0
  84. package/dist/model/model-parser.d.ts +309 -304
  85. package/dist/model/model-parser.js +126 -0
  86. package/dist/model/parser/Base.d.ts +2 -2
  87. package/dist/model/parser/Base.js +367 -0
  88. package/dist/model/parser/DeploymentModelParser.d.ts +2 -2
  89. package/dist/model/parser/DeploymentModelParser.js +176 -0
  90. package/dist/model/parser/DeploymentViewParser.d.ts +3 -3
  91. package/dist/model/parser/DeploymentViewParser.js +86 -0
  92. package/dist/model/parser/FqnRefParser.d.ts +2 -2
  93. package/dist/model/parser/FqnRefParser.js +382 -0
  94. package/dist/model/parser/GlobalsParser.d.ts +6 -6
  95. package/dist/model/parser/GlobalsParser.js +84 -0
  96. package/dist/model/parser/ImportsParser.d.ts +11 -12
  97. package/dist/model/parser/ImportsParser.js +24 -0
  98. package/dist/model/parser/ModelParser.d.ts +2 -2
  99. package/dist/model/parser/ModelParser.js +165 -0
  100. package/dist/model/parser/PredicatesParser.d.ts +2 -2
  101. package/dist/model/parser/PredicatesParser.js +45 -0
  102. package/dist/model/parser/SpecificationParser.d.ts +2 -2
  103. package/dist/model/parser/SpecificationParser.js +113 -0
  104. package/dist/model/parser/ValueConverter.js +12 -0
  105. package/dist/model/parser/ViewsParser.d.ts +3 -3
  106. package/dist/model/parser/ViewsParser.js +479 -0
  107. package/dist/model-change/ModelChanges.d.ts +8 -5
  108. package/dist/model-change/ModelChanges.js +129 -0
  109. package/dist/model-change/changeElementStyle.js +134 -0
  110. package/dist/model-change/changeViewLayout.d.ts +2 -2
  111. package/dist/model-change/changeViewLayout.js +28 -0
  112. package/dist/model-change/removeManualLayoutV1.d.ts +7 -0
  113. package/dist/model-change/removeManualLayoutV1.js +27 -0
  114. package/dist/module.d.ts +10 -5
  115. package/dist/module.js +143 -0
  116. package/dist/protocol.d.ts +34 -27
  117. package/dist/protocol.js +123 -0
  118. package/dist/references/index.js +3 -0
  119. package/dist/references/name-provider.js +37 -0
  120. package/dist/references/scope-computation.js +288 -0
  121. package/dist/references/scope-provider.d.ts +3 -3
  122. package/dist/references/scope-provider.js +242 -0
  123. package/dist/shared/NodeKindProvider.js +57 -0
  124. package/dist/shared/{WorkspaceSymbolProvider.mjs → WorkspaceSymbolProvider.js} +1 -1
  125. package/dist/shared/index.js +2 -0
  126. package/dist/test/index.js +1 -0
  127. package/dist/test/testServices.d.ts +16 -16
  128. package/dist/test/testServices.js +210 -0
  129. package/dist/utils/disposable.js +26 -0
  130. package/dist/utils/elementRef.d.ts +1 -1
  131. package/dist/utils/elementRef.js +27 -0
  132. package/dist/utils/fqnRef.js +63 -0
  133. package/dist/utils/index.js +35 -0
  134. package/dist/utils/printDocs.js +1 -0
  135. package/dist/utils/projectId.js +16 -0
  136. package/dist/utils/stringHash.js +5 -0
  137. package/dist/validation/DocumentValidator.js +17 -0
  138. package/dist/validation/_shared.js +26 -0
  139. package/dist/validation/deployment-checks.js +140 -0
  140. package/dist/validation/dynamic-view.js +67 -0
  141. package/dist/validation/element-ref.js +12 -0
  142. package/dist/validation/element.js +49 -0
  143. package/dist/validation/imports.js +46 -0
  144. package/dist/validation/index.d.ts +1 -1
  145. package/dist/validation/index.js +157 -0
  146. package/dist/validation/property-checks.js +108 -0
  147. package/dist/validation/relation.js +55 -0
  148. package/dist/validation/specification.js +190 -0
  149. package/dist/validation/view-predicates/fqn-expr-with.js +43 -0
  150. package/dist/validation/view-predicates/fqn-ref-expr.js +51 -0
  151. package/dist/validation/view-predicates/incoming.js +16 -0
  152. package/dist/validation/view-predicates/index.js +6 -0
  153. package/dist/validation/view-predicates/outgoing.js +20 -0
  154. package/dist/validation/view-predicates/relation-expr.js +46 -0
  155. package/dist/validation/view-predicates/relation-with.js +16 -0
  156. package/dist/validation/view.d.ts +1 -1
  157. package/dist/validation/view.js +42 -0
  158. package/dist/view-utils/assignNavigateTo.js +27 -0
  159. package/dist/view-utils/index.d.ts +1 -0
  160. package/dist/view-utils/index.js +2 -0
  161. package/dist/view-utils/manual-layout.d.ts +6 -0
  162. package/dist/view-utils/manual-layout.js +149 -0
  163. package/dist/views/ConfigurableLayouter.js +51 -0
  164. package/dist/views/LikeC4ManualLayouts.d.ts +42 -0
  165. package/dist/views/LikeC4ManualLayouts.js +209 -0
  166. package/dist/views/{likec4-views.d.ts → LikeC4Views.d.ts} +32 -10
  167. package/dist/views/LikeC4Views.js +216 -0
  168. package/dist/views/index.d.ts +4 -1
  169. package/dist/views/index.js +11 -0
  170. package/dist/workspace/AstNodeDescriptionProvider.js +18 -0
  171. package/dist/workspace/IndexManager.js +21 -0
  172. package/dist/workspace/LangiumDocuments.d.ts +4 -3
  173. package/dist/workspace/LangiumDocuments.js +72 -0
  174. package/dist/workspace/ProjectsManager.d.ts +25 -16
  175. package/dist/workspace/ProjectsManager.js +469 -0
  176. package/dist/workspace/WorkspaceManager.d.ts +3 -2
  177. package/dist/workspace/WorkspaceManager.js +98 -0
  178. package/dist/workspace/index.js +5 -0
  179. package/likec4lib/package.json +1 -1
  180. package/package.json +30 -28
  181. package/protocol/package.json +1 -1
  182. package/dist/LikeC4LanguageServices.mjs +0 -197
  183. package/dist/Rpc.mjs +0 -296
  184. package/dist/ast.mjs +0 -221
  185. package/dist/browser-worker.mjs +0 -2
  186. package/dist/browser.mjs +0 -32
  187. package/dist/documentation/documentation-provider.mjs +0 -48
  188. package/dist/documentation/index.mjs +0 -1
  189. package/dist/empty.mjs +0 -1
  190. package/dist/filesystem/ChokidarWatcher.mjs +0 -68
  191. package/dist/filesystem/FileSystemWatcher.mjs +0 -11
  192. package/dist/filesystem/LikeC4FileSystem.mjs +0 -64
  193. package/dist/filesystem/index.mjs +0 -19
  194. package/dist/formatting/LikeC4Formatter.mjs +0 -511
  195. package/dist/formatting/utils.mjs +0 -15
  196. package/dist/generated/ast.mjs +0 -2150
  197. package/dist/generated/module.mjs +0 -23
  198. package/dist/index.mjs +0 -50
  199. package/dist/logger.mjs +0 -82
  200. package/dist/lsp/CodeLensProvider.mjs +0 -42
  201. package/dist/lsp/CompletionProvider.mjs +0 -208
  202. package/dist/lsp/DocumentHighlightProvider.mjs +0 -10
  203. package/dist/lsp/DocumentLinkProvider.mjs +0 -53
  204. package/dist/lsp/DocumentSymbolProvider.mjs +0 -287
  205. package/dist/lsp/HoverProvider.mjs +0 -104
  206. package/dist/lsp/RenameProvider.mjs +0 -6
  207. package/dist/lsp/SemanticTokenProvider.mjs +0 -276
  208. package/dist/lsp/index.mjs +0 -7
  209. package/dist/mcp/MCPServerFactory.mjs +0 -70
  210. package/dist/mcp/NoopLikeC4MCPServer.mjs +0 -17
  211. package/dist/mcp/interfaces.mjs +0 -4
  212. package/dist/mcp/server/StdioLikeC4MCPServer.mjs +0 -46
  213. package/dist/mcp/server/StreamableLikeC4MCPServer.mjs +0 -153
  214. package/dist/mcp/server/WithMCPServer.mjs +0 -58
  215. package/dist/mcp/tools/_common.mjs +0 -42
  216. package/dist/mcp/tools/find-relationships.mjs +0 -151
  217. package/dist/mcp/tools/list-projects.mjs +0 -62
  218. package/dist/mcp/tools/open-view.mjs +0 -52
  219. package/dist/mcp/tools/read-deployment.mjs +0 -130
  220. package/dist/mcp/tools/read-element.mjs +0 -198
  221. package/dist/mcp/tools/read-project-summary.mjs +0 -178
  222. package/dist/mcp/tools/read-view.mjs +0 -205
  223. package/dist/mcp/tools/search-element.mjs +0 -171
  224. package/dist/mcp/utils.mjs +0 -47
  225. package/dist/model/builder/MergedExtends.mjs +0 -76
  226. package/dist/model/builder/MergedSpecification.mjs +0 -205
  227. package/dist/model/builder/assignTagColors.d.ts +0 -7
  228. package/dist/model/builder/assignTagColors.mjs +0 -51
  229. package/dist/model/builder/buildModel.mjs +0 -226
  230. package/dist/model/deployments-index.mjs +0 -100
  231. package/dist/model/fqn-index.mjs +0 -243
  232. package/dist/model/index.mjs +0 -6
  233. package/dist/model/model-builder.mjs +0 -285
  234. package/dist/model/model-locator.mjs +0 -239
  235. package/dist/model/model-parser-where.mjs +0 -81
  236. package/dist/model/model-parser.mjs +0 -127
  237. package/dist/model/parser/Base.mjs +0 -376
  238. package/dist/model/parser/DeploymentModelParser.mjs +0 -212
  239. package/dist/model/parser/DeploymentViewParser.mjs +0 -95
  240. package/dist/model/parser/FqnRefParser.mjs +0 -398
  241. package/dist/model/parser/GlobalsParser.mjs +0 -82
  242. package/dist/model/parser/ImportsParser.mjs +0 -28
  243. package/dist/model/parser/ModelParser.mjs +0 -190
  244. package/dist/model/parser/PredicatesParser.mjs +0 -45
  245. package/dist/model/parser/SpecificationParser.mjs +0 -120
  246. package/dist/model/parser/ValueConverter.mjs +0 -12
  247. package/dist/model/parser/ViewsParser.mjs +0 -490
  248. package/dist/model-change/ModelChanges.mjs +0 -89
  249. package/dist/model-change/changeElementStyle.mjs +0 -143
  250. package/dist/model-change/changeViewLayout.mjs +0 -32
  251. package/dist/model-change/saveManualLayout.d.ts +0 -11
  252. package/dist/model-change/saveManualLayout.mjs +0 -27
  253. package/dist/module.mjs +0 -180
  254. package/dist/protocol.mjs +0 -65
  255. package/dist/references/index.mjs +0 -3
  256. package/dist/references/name-provider.mjs +0 -39
  257. package/dist/references/scope-computation.mjs +0 -312
  258. package/dist/references/scope-provider.mjs +0 -239
  259. package/dist/shared/NodeKindProvider.mjs +0 -110
  260. package/dist/shared/index.mjs +0 -2
  261. package/dist/test/index.mjs +0 -1
  262. package/dist/test/testServices.mjs +0 -200
  263. package/dist/utils/disposable.mjs +0 -25
  264. package/dist/utils/elementRef.mjs +0 -20
  265. package/dist/utils/fqnRef.mjs +0 -57
  266. package/dist/utils/index.mjs +0 -33
  267. package/dist/utils/printDocs.mjs +0 -1
  268. package/dist/utils/projectId.mjs +0 -16
  269. package/dist/utils/stringHash.mjs +0 -5
  270. package/dist/validation/DocumentValidator.mjs +0 -16
  271. package/dist/validation/_shared.mjs +0 -25
  272. package/dist/validation/deployment-checks.mjs +0 -146
  273. package/dist/validation/dynamic-view.mjs +0 -67
  274. package/dist/validation/element-ref.mjs +0 -12
  275. package/dist/validation/element.mjs +0 -50
  276. package/dist/validation/imports.mjs +0 -25
  277. package/dist/validation/index.mjs +0 -180
  278. package/dist/validation/property-checks.mjs +0 -107
  279. package/dist/validation/relation.mjs +0 -53
  280. package/dist/validation/specification.mjs +0 -173
  281. package/dist/validation/view-predicates/fqn-expr-with.mjs +0 -43
  282. package/dist/validation/view-predicates/fqn-ref-expr.mjs +0 -53
  283. package/dist/validation/view-predicates/incoming.mjs +0 -16
  284. package/dist/validation/view-predicates/index.mjs +0 -6
  285. package/dist/validation/view-predicates/outgoing.mjs +0 -20
  286. package/dist/validation/view-predicates/relation-expr.mjs +0 -39
  287. package/dist/validation/view-predicates/relation-with.mjs +0 -16
  288. package/dist/validation/view.mjs +0 -25
  289. package/dist/view-utils/assignNavigateTo.mjs +0 -25
  290. package/dist/view-utils/index.mjs +0 -1
  291. package/dist/view-utils/manual-layout.mjs +0 -99
  292. package/dist/views/configurable-layouter.mjs +0 -51
  293. package/dist/views/index.mjs +0 -1
  294. package/dist/views/likec4-views.mjs +0 -166
  295. package/dist/workspace/AstNodeDescriptionProvider.mjs +0 -17
  296. package/dist/workspace/IndexManager.mjs +0 -17
  297. package/dist/workspace/LangiumDocuments.mjs +0 -53
  298. package/dist/workspace/ProjectsManager.mjs +0 -360
  299. package/dist/workspace/WorkspaceManager.mjs +0 -83
  300. package/dist/workspace/index.mjs +0 -5
  301. /package/dist/views/{configurable-layouter.d.ts → ConfigurableLayouter.d.ts} +0 -0
@@ -1,285 +0,0 @@
1
- import {
2
- _stage,
3
- isScopedElementView
4
- } from "@likec4/core";
5
- import { computeView } from "@likec4/core/compute-view";
6
- import { LikeC4Model } from "@likec4/core/model";
7
- import { loggable } from "@likec4/log";
8
- import { deepEqual as eq } from "fast-equals";
9
- import {
10
- Disposable,
11
- DocumentState,
12
- interruptAndCheck
13
- } from "langium";
14
- import {
15
- filter,
16
- flatMap,
17
- groupBy,
18
- hasAtLeast,
19
- isNot,
20
- mapToObj,
21
- pipe,
22
- prop,
23
- values
24
- } from "remeda";
25
- import { isLikeC4Builtin } from "../likec4lib.mjs";
26
- import { logger as mainLogger, logWarnError } from "../logger.mjs";
27
- import { ADisposable, performanceMark } from "../utils/index.mjs";
28
- import { assignNavigateTo } from "../view-utils/index.mjs";
29
- import { buildModelData } from "./builder/buildModel.mjs";
30
- const parsedWithoutImportsCacheKey = (projectId) => `parsed-without-imports-${projectId}`;
31
- const parsedModelCacheKey = (projectId) => `parsed-model-${projectId}`;
32
- const computedModelCacheKey = (projectId) => `computed-model-${projectId}`;
33
- const builderLogger = mainLogger.getChild("model-builder");
34
- export class DefaultLikeC4ModelBuilder extends ADisposable {
35
- projects;
36
- parser;
37
- listeners = [];
38
- cache;
39
- DocumentBuilder;
40
- mutex;
41
- constructor(services) {
42
- super();
43
- this.projects = services.shared.workspace.ProjectsManager;
44
- this.parser = services.likec4.ModelParser;
45
- this.cache = services.ValidatedWorkspaceCache;
46
- this.DocumentBuilder = services.shared.workspace.DocumentBuilder;
47
- this.mutex = services.shared.workspace.WorkspaceLock;
48
- this.onDispose(
49
- this.DocumentBuilder.onUpdate((_changed, deleted) => {
50
- if (deleted.length > 0) {
51
- this.notifyListeners(deleted);
52
- }
53
- })
54
- );
55
- this.onDispose(
56
- this.DocumentBuilder.onBuildPhase(
57
- DocumentState.Validated,
58
- (docs, _cancelToken) => {
59
- const validated = docs.map(prop("uri")).filter(isNot(isLikeC4Builtin));
60
- if (validated.length > 0) {
61
- this.notifyListeners(validated);
62
- }
63
- }
64
- )
65
- );
66
- builderLogger.debug`created`;
67
- }
68
- /**
69
- * WARNING:
70
- * This method is internal and should to be called only when all documents are known to be parsed.
71
- * Otherwise, the model may be incomplete.
72
- *
73
- * To avoid circular dependencies, we do not resolve imports here.
74
- */
75
- unsafeSyncParseModelData(projectId) {
76
- const cache = this.cache;
77
- const logger = builderLogger.getChild(projectId);
78
- const key = parsedWithoutImportsCacheKey(projectId);
79
- if (cache.has(key)) {
80
- logger.debug`unsafeSyncBuildModelData from cache`;
81
- }
82
- return cache.get(key, () => {
83
- try {
84
- const project = this.projects.getProject(projectId);
85
- const docs = this.documents(projectId);
86
- if (docs.length === 0) {
87
- logger.debug`no documents to build model`;
88
- return null;
89
- }
90
- logger.debug`unsafeSyncBuildModelData`;
91
- return buildModelData(project, docs);
92
- } catch (e) {
93
- logWarnError(e);
94
- return null;
95
- }
96
- });
97
- }
98
- /**
99
- * To avoid circular dependencies, first we parse all documents and then we join them.
100
- */
101
- unsafeSyncJoinedModelData(projectId) {
102
- const logger = builderLogger.getChild(projectId);
103
- const cache = this.cache;
104
- const key = parsedModelCacheKey(projectId);
105
- return cache.get(key, () => {
106
- const result = this.unsafeSyncParseModelData(projectId);
107
- if (!result) {
108
- return null;
109
- }
110
- let parsedData = result.data;
111
- if (result.imports.size > 0) {
112
- logger.debug`processing imports of ${projectId}`;
113
- const imports = [...result.imports.associations()].reduce((acc, [projectId2, fqns]) => {
114
- const anotherProject = this.unsafeSyncParseModelData(projectId2);
115
- if (anotherProject) {
116
- const imported = pipe(
117
- [...fqns],
118
- flatMap((fqn) => anotherProject.data.elements[fqn] ?? [])
119
- );
120
- if (hasAtLeast(imported, 1)) {
121
- acc[projectId2] = imported;
122
- }
123
- }
124
- return acc;
125
- }, {});
126
- parsedData = {
127
- ...result.data,
128
- imports
129
- };
130
- }
131
- return LikeC4Model.create(parsedData);
132
- });
133
- }
134
- async parseModel(projectId, cancelToken) {
135
- const project = this.projects.ensureProjectId(projectId);
136
- const logger = builderLogger.getChild(project);
137
- const cache = this.cache;
138
- const cached = cache.get(parsedModelCacheKey(project));
139
- if (cached) {
140
- logger.debug`parseModel from cache`;
141
- return cached;
142
- }
143
- const t0 = performanceMark();
144
- return await this.mutex.read(async () => {
145
- if (cancelToken) {
146
- await interruptAndCheck(cancelToken);
147
- }
148
- const result = this.unsafeSyncJoinedModelData(project);
149
- logger.debug`parseModel in ${t0.pretty}`;
150
- return result;
151
- });
152
- }
153
- previousViews = {};
154
- /**
155
- * WARNING:
156
- * This method is internal and should to be called only when all documents are known to be parsed.
157
- * Otherwise, the model may be incomplete.
158
- */
159
- unsafeSyncBuildModel(projectId) {
160
- const logger = builderLogger.getChild(projectId);
161
- const cache = this.cache;
162
- const viewsCache = this.cache;
163
- return cache.get(computedModelCacheKey(projectId), () => {
164
- const parsedModel = this.unsafeSyncJoinedModelData(projectId);
165
- if (!parsedModel) {
166
- return LikeC4Model.EMPTY;
167
- }
168
- const allViews = [];
169
- for (const view of values(parsedModel.$data.views)) {
170
- const result = computeView(view, parsedModel);
171
- if (!result.isSuccess) {
172
- logger.warn(loggable(result.error));
173
- continue;
174
- }
175
- allViews.push(result.view);
176
- }
177
- assignNavigateTo(allViews);
178
- const views = mapToObj(allViews, (v) => {
179
- const key = computedViewKey(projectId, v.id);
180
- const previous = this.previousViews[key];
181
- const view = previous && eq(v, previous) ? previous : v;
182
- this.previousViews[key] = view;
183
- viewsCache.set(key, view);
184
- return [v.id, view];
185
- });
186
- return LikeC4Model.create({
187
- ...parsedModel.$data,
188
- [_stage]: "computed",
189
- views
190
- });
191
- });
192
- }
193
- async buildLikeC4Model(projectId, cancelToken) {
194
- const project = this.projects.ensureProjectId(projectId);
195
- const logger = builderLogger.getChild(project);
196
- const cache = this.cache;
197
- const cached = cache.get(computedModelCacheKey(project));
198
- if (cached) {
199
- logger.debug("buildLikeC4Model from cache");
200
- return cached;
201
- }
202
- const t0 = performanceMark();
203
- return await this.mutex.read(async () => {
204
- if (cancelToken) {
205
- await interruptAndCheck(cancelToken);
206
- }
207
- const result = this.unsafeSyncBuildModel(project);
208
- logger.debug(`buildLikeC4Model in ${t0.pretty}`);
209
- return result;
210
- });
211
- }
212
- async computeView(viewId, projectId, cancelToken) {
213
- const project = this.projects.ensureProjectId(projectId);
214
- const logger = builderLogger.getChild(project);
215
- const cache = this.cache;
216
- const cacheKey = computedViewKey(project, viewId);
217
- if (cache.has(cacheKey)) {
218
- return cache.get(cacheKey);
219
- }
220
- const parsed = await this.parseModel(project, cancelToken);
221
- if (!parsed) {
222
- return null;
223
- }
224
- return cache.get(cacheKey, () => {
225
- const view = parsed.$data.views[viewId];
226
- if (!view) {
227
- logger.warn`computeView: cant find view ${viewId}`;
228
- return null;
229
- }
230
- logger.debug`computeView: ${viewId}`;
231
- const result = computeView(view, parsed);
232
- if (!result.isSuccess) {
233
- logWarnError(result.error);
234
- return null;
235
- }
236
- let computedView = result.view;
237
- const allElementViews = pipe(
238
- parsed.$data.views,
239
- values(),
240
- filter(isScopedElementView),
241
- filter((v) => v.id !== viewId),
242
- groupBy((v) => v.viewOf)
243
- );
244
- for (const node of computedView.nodes) {
245
- if (!node.navigateTo) {
246
- const viewsOfNode = allElementViews[node.id];
247
- if (viewsOfNode) {
248
- node.navigateTo = viewsOfNode[0].id;
249
- }
250
- }
251
- }
252
- const previous = this.previousViews[cacheKey];
253
- if (previous && eq(computedView, previous)) {
254
- computedView = previous;
255
- } else {
256
- this.previousViews[cacheKey] = computedView;
257
- }
258
- return computedView;
259
- });
260
- }
261
- onModelParsed(callback) {
262
- this.listeners.push(callback);
263
- return Disposable.create(() => {
264
- const index = this.listeners.indexOf(callback);
265
- if (index >= 0) {
266
- this.listeners.splice(index, 1);
267
- }
268
- });
269
- }
270
- documents(projectId) {
271
- return this.parser.documents(projectId).toArray();
272
- }
273
- notifyListeners(docs) {
274
- for (const listener of this.listeners) {
275
- try {
276
- listener(docs);
277
- } catch (e) {
278
- logWarnError(e);
279
- }
280
- }
281
- }
282
- }
283
- function computedViewKey(projectId, viewId) {
284
- return `computed-view-${projectId}-${viewId}`;
285
- }
@@ -1,239 +0,0 @@
1
- import { splitGlobalFqn } from "@likec4/core";
2
- import { ifilter, invariant, toArray } from "@likec4/core/utils";
3
- import { loggable } from "@likec4/log";
4
- import { AstUtils, DocumentState, GrammarUtils } from "langium";
5
- import { flatMap, isString, pipe } from "remeda";
6
- import { ast, isLikeC4LangiumDocument } from "../ast.mjs";
7
- import { logger as serverLogger } from "../logger.mjs";
8
- import { projectIdFrom } from "../utils/index.mjs";
9
- import { MergedSpecification } from "./builder/MergedSpecification.mjs";
10
- const { findNodeForKeyword, findNodeForProperty } = GrammarUtils;
11
- const { getDocument, streamAllContents } = AstUtils;
12
- const logger = serverLogger.getChild("ModelLocator");
13
- export class LikeC4ModelLocator {
14
- constructor(services) {
15
- this.services = services;
16
- this.fqnIndex = services.likec4.FqnIndex;
17
- this.deploymentsIndex = services.likec4.DeploymentsIndex;
18
- this.langiumDocuments = services.shared.workspace.LangiumDocuments;
19
- this.parser = services.likec4.ModelParser;
20
- this.projects = services.shared.workspace.ProjectsManager;
21
- }
22
- fqnIndex;
23
- deploymentsIndex;
24
- langiumDocuments;
25
- parser;
26
- projects;
27
- documents(projectId) {
28
- return this.parser.documents(projectId);
29
- }
30
- // public getParsedElement(astNodeOrFqn: ast.Element): ParsedAstElement | null
31
- // public getParsedElement(astNodeOrFqn: c4.Fqn, projectId?: c4.ProjectId): ParsedAstElement | null
32
- getParsedElement(...args) {
33
- let astNodeOrFqn;
34
- let projectId;
35
- if (args.length === 2) {
36
- astNodeOrFqn = args[0];
37
- projectId = args[1];
38
- } else {
39
- astNodeOrFqn = args[0];
40
- projectId = isString(astNodeOrFqn) ? this.projects.ensureProjectId() : projectIdFrom(astNodeOrFqn);
41
- }
42
- if (isString(astNodeOrFqn)) {
43
- const fqn2 = astNodeOrFqn;
44
- const entry = this.fqnIndex.byFqn(projectId, astNodeOrFqn).head();
45
- if (!entry) {
46
- return null;
47
- }
48
- const doc2 = this.langiumDocuments.getDocument(entry.documentUri);
49
- if (!doc2) {
50
- return null;
51
- }
52
- return this.parser.parse(doc2).c4Elements.find((e) => e.id === fqn2) ?? null;
53
- }
54
- const fqn = this.fqnIndex.getFqn(astNodeOrFqn);
55
- const doc = this.parser.parse(getDocument(astNodeOrFqn));
56
- return doc.c4Elements.find((e) => e.id === fqn) ?? null;
57
- }
58
- locateElement(fqn, projectId) {
59
- let [_projectId, _fqn] = splitGlobalFqn(fqn);
60
- _projectId ??= this.projects.ensureProjectId(projectId);
61
- const entry = this.fqnIndex.byFqn(_projectId, _fqn).head();
62
- const docsegment = entry?.nameSegment ?? entry?.selectionSegment;
63
- if (!entry || !docsegment) {
64
- return null;
65
- }
66
- return {
67
- uri: entry.documentUri.toString(),
68
- range: docsegment.range
69
- };
70
- }
71
- locateDeploymentElement(deploymentFqn, projectId) {
72
- const _projectId = this.projects.ensureProjectId(projectId);
73
- const fqn = deploymentFqn;
74
- const entry = this.deploymentsIndex.byFqn(_projectId, fqn).head();
75
- const docsegment = entry?.nameSegment ?? entry?.selectionSegment;
76
- if (!entry || !docsegment) {
77
- return null;
78
- }
79
- return {
80
- uri: entry.documentUri.toString(),
81
- range: docsegment.range
82
- };
83
- }
84
- locateRelation(relationId, projectId) {
85
- const project = this.projects.ensureProjectId(projectId);
86
- for (const doc of this.documents(project)) {
87
- const relation = doc.c4Relations.find((r) => r.id === relationId) ?? doc.c4DeploymentRelations.find((r) => r.id === relationId);
88
- if (!relation) {
89
- continue;
90
- }
91
- const node = this.services.workspace.AstNodeLocator.getAstNode(
92
- doc.parseResult.value,
93
- relation.astPath
94
- );
95
- if (!ast.isRelation(node) && !ast.isDeploymentRelation(node)) {
96
- continue;
97
- }
98
- let targetNode = node.kind ? findNodeForProperty(node.$cstNode, "kind") : void 0;
99
- targetNode ??= node.dotKind ? findNodeForProperty(node.$cstNode, "dotKind") : void 0;
100
- targetNode ??= findNodeForKeyword(node.$cstNode, "->");
101
- targetNode ??= findNodeForProperty(node.$cstNode, "title");
102
- targetNode ??= findNodeForProperty(node.$cstNode, "target");
103
- targetNode ??= node.$cstNode;
104
- if (!targetNode) {
105
- continue;
106
- }
107
- return {
108
- uri: doc.uri.toString(),
109
- range: {
110
- start: targetNode.range.start,
111
- end: targetNode.range.start
112
- }
113
- };
114
- }
115
- return null;
116
- }
117
- locateViewAst(viewId, projectId) {
118
- const project = this.projects.ensureProjectId(projectId);
119
- for (const doc of this.documents(project)) {
120
- const view = doc.c4Views.find((r) => r.id === viewId);
121
- if (!view) {
122
- continue;
123
- }
124
- const viewAst = this.services.workspace.AstNodeLocator.getAstNode(
125
- doc.parseResult.value,
126
- view.astPath
127
- );
128
- if (ast.isLikeC4View(viewAst)) {
129
- return {
130
- doc,
131
- view,
132
- viewAst
133
- };
134
- }
135
- }
136
- return null;
137
- }
138
- locateView(viewId, projectId) {
139
- const res = this.locateViewAst(viewId, projectId);
140
- if (!res) {
141
- return null;
142
- }
143
- const node = res.viewAst;
144
- let targetNode = node.name ? findNodeForProperty(node.$cstNode, "name") : void 0;
145
- targetNode ??= findNodeForKeyword(node.$cstNode, "view");
146
- targetNode ??= node.$cstNode;
147
- if (!targetNode) {
148
- return null;
149
- }
150
- return {
151
- uri: res.doc.uri.toString(),
152
- range: targetNode.range
153
- };
154
- }
155
- async locateDocumentTags(documentUri, cancelToken) {
156
- const doc = this.langiumDocuments.getDocument(documentUri);
157
- if (!doc || !isLikeC4LangiumDocument(doc)) {
158
- return [];
159
- }
160
- if (doc.state < DocumentState.Validated) {
161
- logger.debug(`Waiting for document ${doc.uri.path} to be Validated`);
162
- await this.services.shared.workspace.DocumentBuilder.waitUntil(DocumentState.Validated, doc.uri, cancelToken);
163
- }
164
- const projectId = projectIdFrom(doc);
165
- logger.debug(`locate document tags for ${doc.uri.path} in project ${projectId}`);
166
- try {
167
- const tagSpecs = new MergedSpecification(this.documents(projectId).toArray()).tags;
168
- logger.debug(`Assigned colors to tags`, { tagSpecs });
169
- const tags = pipe(
170
- streamAllContents(doc.parseResult.value),
171
- ifilter((astNode) => ast.isTag(astNode) || ast.isTagRef(astNode)),
172
- toArray(),
173
- flatMap((tagRef) => {
174
- let name;
175
- let $cstNode;
176
- try {
177
- if (ast.isTag(tagRef)) {
178
- name = tagRef.name;
179
- $cstNode = tagRef.$cstNode;
180
- } else {
181
- name = tagRef.tag.$refText;
182
- $cstNode = tagRef.tag.$refNode;
183
- }
184
- const specification = tagSpecs[name];
185
- invariant(specification, `Tag ${name} not found in merged specification`);
186
- invariant($cstNode, `Tag ${name} does not have a $cstNode`);
187
- return {
188
- name,
189
- color: specification.color,
190
- range: $cstNode.range,
191
- isSpecification: ast.isTag(tagRef)
192
- };
193
- } catch (err) {
194
- logger.warn(`Fail on tag ${name}`, { err });
195
- return [];
196
- }
197
- })
198
- );
199
- logger.debug(`Found ${tags.length} tags in document ${doc.uri.path}`);
200
- return tags;
201
- } catch (e) {
202
- logger.warn(loggable(e));
203
- return [];
204
- }
205
- }
206
- locateDynamicViewStep(params) {
207
- const { doc, viewAst } = this.locateViewAst(params.view, params.projectId) ?? {};
208
- if (!doc || !viewAst) {
209
- return null;
210
- }
211
- if (!ast.isDynamicView(viewAst) || !viewAst.body) {
212
- logger.warn(`View ${params.view} is not a dynamic view`);
213
- return null;
214
- }
215
- const astPath = this.services.workspace.AstNodeLocator.getAstNodePath(viewAst.body) + params.astPath;
216
- const node = this.services.workspace.AstNodeLocator.getAstNode(doc.parseResult.value, astPath);
217
- if (!node || !ast.isDynamicViewStep(node)) {
218
- logger.warn(`Failed to locate dynamic view step ${astPath} in view ${params.view}`);
219
- return null;
220
- }
221
- let targetNode = node.kind ? findNodeForProperty(node.$cstNode, "kind") : void 0;
222
- targetNode ??= node.dotKind ? findNodeForProperty(node.$cstNode, "dotKind") : void 0;
223
- targetNode ??= findNodeForKeyword(node.$cstNode, "->");
224
- targetNode ??= findNodeForKeyword(node.$cstNode, "<-");
225
- targetNode ??= findNodeForProperty(node.$cstNode, "title");
226
- targetNode ??= findNodeForProperty(node.$cstNode, "target");
227
- targetNode ??= node.$cstNode;
228
- if (!targetNode) {
229
- return null;
230
- }
231
- return {
232
- uri: doc.uri.toString(),
233
- range: {
234
- start: targetNode.range.start,
235
- end: targetNode.range.start
236
- }
237
- };
238
- }
239
- }
@@ -1,81 +0,0 @@
1
- import { invariant, isAndOperator, isNonEmptyArray, isOrOperator, nonexhaustive } from "@likec4/core";
2
- import { ast } from "../ast.mjs";
3
- const parseEquals = ({ operator, not }, value) => {
4
- if (operator.startsWith("!=")) {
5
- return {
6
- neq: value
7
- };
8
- }
9
- if (operator.startsWith("=")) {
10
- return {
11
- eq: value
12
- };
13
- }
14
- return not ? { neq: value } : { eq: value };
15
- };
16
- function parseParticipant(astNode) {
17
- if (!ast.isWhereRelationParticipantKind(astNode) && !ast.isWhereRelationParticipantTag(astNode)) {
18
- return null;
19
- }
20
- return astNode.participant;
21
- }
22
- export function parseWhereClause(astNode) {
23
- switch (true) {
24
- case ast.isWhereTagEqual(astNode): {
25
- const tag = astNode.value.tag.ref?.name;
26
- const participant = parseParticipant(astNode);
27
- invariant(tag, "Expected tag name");
28
- const tagOperator = { tag: parseEquals(astNode, tag) };
29
- return participant ? { participant, operator: tagOperator } : tagOperator;
30
- }
31
- case ast.isWhereKindEqual(astNode): {
32
- const kind = astNode.value?.ref?.name;
33
- const participant = parseParticipant(astNode);
34
- invariant(kind, "Expected kind name");
35
- const kindOperator = { kind: parseEquals(astNode, kind) };
36
- return participant ? { participant, operator: kindOperator } : kindOperator;
37
- }
38
- case (ast.isWhereElementNegation(astNode) || ast.isWhereRelationNegation(astNode)): {
39
- return {
40
- not: parseWhereClause(astNode.value)
41
- };
42
- }
43
- case ast.isWhereBinaryExpression(astNode): {
44
- const left = parseWhereClause(astNode.left);
45
- const right = parseWhereClause(astNode.right);
46
- const operator = astNode.operator.toLowerCase();
47
- return createBinaryOperator(operator, left, right);
48
- }
49
- default:
50
- nonexhaustive(astNode);
51
- }
52
- }
53
- export function createBinaryOperator(operator, left, right) {
54
- if (right === null) {
55
- return left;
56
- }
57
- switch (operator) {
58
- case "and": {
59
- const operands = [
60
- isAndOperator(left) ? left.and : left,
61
- isAndOperator(right) ? right.and : right
62
- ].flat();
63
- invariant(isNonEmptyArray(operands), "Expected non-empty array");
64
- return {
65
- and: operands
66
- };
67
- }
68
- case "or": {
69
- const operands = [
70
- isOrOperator(left) ? left.or : left,
71
- isOrOperator(right) ? right.or : right
72
- ].flat();
73
- invariant(isNonEmptyArray(operands), "Expected non-empty array");
74
- return {
75
- or: operands
76
- };
77
- }
78
- default:
79
- nonexhaustive(operator);
80
- }
81
- }