@likec4/language-server 1.43.0 → 1.44.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 (299) hide show
  1. package/browser/package.json +1 -1
  2. package/browser-worker/package.json +1 -1
  3. package/dist/LikeC4LanguageServices.d.ts +12 -19
  4. package/dist/LikeC4LanguageServices.js +182 -0
  5. package/dist/Rpc.js +245 -0
  6. package/dist/ast.d.ts +5 -1
  7. package/dist/ast.js +253 -0
  8. package/dist/browser-worker.js +4 -0
  9. package/dist/browser.js +35 -0
  10. package/dist/bundled.js +42 -0
  11. package/dist/bundled.mjs +3542 -3896
  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.js +97 -0
  16. package/dist/filesystem/FileSystemWatcher.js +14 -0
  17. package/dist/filesystem/LikeC4FileSystem.d.ts +1 -2
  18. package/dist/filesystem/LikeC4FileSystem.js +126 -0
  19. package/dist/filesystem/index.d.ts +26 -0
  20. package/dist/filesystem/index.js +29 -0
  21. package/dist/formatting/LikeC4Formatter.js +637 -0
  22. package/dist/formatting/utils.js +18 -0
  23. package/dist/generated/ast.js +2155 -0
  24. package/dist/generated/{grammar.mjs → grammar.js} +6 -2
  25. package/dist/generated/module.d.ts +6 -1
  26. package/dist/generated/module.js +27 -0
  27. package/dist/generated-lib/{icons.mjs → icons.js} +11 -7
  28. package/dist/index.d.ts +7 -0
  29. package/dist/index.js +53 -0
  30. package/dist/{likec4lib.mjs → likec4lib.js} +3 -3
  31. package/dist/logger.js +81 -0
  32. package/dist/lsp/CodeActionProvider.d.ts +14 -0
  33. package/dist/lsp/CodeActionProvider.js +33 -0
  34. package/dist/lsp/CodeLensProvider.js +44 -0
  35. package/dist/lsp/CompletionProvider.d.ts +3 -1
  36. package/dist/lsp/CompletionProvider.js +200 -0
  37. package/dist/lsp/DocumentHighlightProvider.js +10 -0
  38. package/dist/lsp/DocumentLinkProvider.js +58 -0
  39. package/dist/lsp/DocumentSymbolProvider.js +306 -0
  40. package/dist/lsp/HoverProvider.js +106 -0
  41. package/dist/lsp/RenameProvider.js +6 -0
  42. package/dist/lsp/SemanticTokenProvider.js +257 -0
  43. package/dist/lsp/index.d.ts +1 -0
  44. package/dist/lsp/index.js +9 -0
  45. package/dist/mcp/MCPServerFactory.js +73 -0
  46. package/dist/mcp/NoopLikeC4MCPServer.js +17 -0
  47. package/dist/mcp/interfaces.js +5 -0
  48. package/dist/mcp/server/StdioLikeC4MCPServer.js +47 -0
  49. package/dist/mcp/server/StreamableLikeC4MCPServer.js +145 -0
  50. package/dist/mcp/server/WithMCPServer.js +56 -0
  51. package/dist/mcp/tools/_common.d.ts +8 -7
  52. package/dist/mcp/tools/_common.js +49 -0
  53. package/dist/mcp/tools/find-relationships.d.ts +7 -8
  54. package/dist/mcp/tools/find-relationships.js +150 -0
  55. package/dist/mcp/tools/list-projects.d.ts +3 -3
  56. package/dist/mcp/tools/list-projects.js +62 -0
  57. package/dist/mcp/tools/open-view.d.ts +6 -7
  58. package/dist/mcp/tools/open-view.js +52 -0
  59. package/dist/mcp/tools/read-deployment.d.ts +6 -7
  60. package/dist/mcp/tools/read-deployment.js +132 -0
  61. package/dist/mcp/tools/read-element.d.ts +6 -7
  62. package/dist/mcp/tools/read-element.js +194 -0
  63. package/dist/mcp/tools/read-project-summary.d.ts +5 -6
  64. package/dist/mcp/tools/read-project-summary.js +176 -0
  65. package/dist/mcp/tools/read-view.d.ts +6 -7
  66. package/dist/mcp/tools/read-view.js +203 -0
  67. package/dist/mcp/tools/search-element.d.ts +3 -3
  68. package/dist/mcp/tools/search-element.js +177 -0
  69. package/dist/mcp/utils.d.ts +2 -2
  70. package/dist/mcp/utils.js +48 -0
  71. package/dist/model/builder/MergedExtends.js +74 -0
  72. package/dist/model/builder/MergedSpecification.js +175 -0
  73. package/dist/model/builder/buildModel.js +176 -0
  74. package/dist/model/deployments-index.js +102 -0
  75. package/dist/model/fqn-index.js +250 -0
  76. package/dist/model/index.js +6 -0
  77. package/dist/model/model-builder.d.ts +13 -11
  78. package/dist/model/model-builder.js +234 -0
  79. package/dist/model/model-locator.d.ts +6 -5
  80. package/dist/model/model-locator.js +240 -0
  81. package/dist/model/model-parser-where.js +81 -0
  82. package/dist/model/model-parser.d.ts +309 -304
  83. package/dist/model/model-parser.js +119 -0
  84. package/dist/model/parser/Base.d.ts +2 -2
  85. package/dist/model/parser/Base.js +367 -0
  86. package/dist/model/parser/DeploymentModelParser.d.ts +2 -2
  87. package/dist/model/parser/DeploymentModelParser.js +176 -0
  88. package/dist/model/parser/DeploymentViewParser.d.ts +3 -3
  89. package/dist/model/parser/DeploymentViewParser.js +86 -0
  90. package/dist/model/parser/FqnRefParser.d.ts +2 -2
  91. package/dist/model/parser/FqnRefParser.js +382 -0
  92. package/dist/model/parser/GlobalsParser.d.ts +6 -6
  93. package/dist/model/parser/GlobalsParser.js +84 -0
  94. package/dist/model/parser/ImportsParser.d.ts +11 -12
  95. package/dist/model/parser/ImportsParser.js +24 -0
  96. package/dist/model/parser/ModelParser.d.ts +2 -2
  97. package/dist/model/parser/ModelParser.js +165 -0
  98. package/dist/model/parser/PredicatesParser.d.ts +2 -2
  99. package/dist/model/parser/PredicatesParser.js +45 -0
  100. package/dist/model/parser/SpecificationParser.d.ts +2 -2
  101. package/dist/model/parser/SpecificationParser.js +109 -0
  102. package/dist/model/parser/ValueConverter.js +12 -0
  103. package/dist/model/parser/ViewsParser.d.ts +3 -3
  104. package/dist/model/parser/ViewsParser.js +477 -0
  105. package/dist/model-change/ModelChanges.d.ts +6 -3
  106. package/dist/model-change/ModelChanges.js +102 -0
  107. package/dist/model-change/changeElementStyle.js +134 -0
  108. package/dist/model-change/changeViewLayout.d.ts +2 -2
  109. package/dist/model-change/changeViewLayout.js +28 -0
  110. package/dist/model-change/removeManualLayoutV1.d.ts +7 -0
  111. package/dist/model-change/removeManualLayoutV1.js +27 -0
  112. package/dist/module.d.ts +10 -5
  113. package/dist/module.js +143 -0
  114. package/dist/protocol.d.ts +1 -17
  115. package/dist/protocol.js +114 -0
  116. package/dist/references/index.js +3 -0
  117. package/dist/references/name-provider.js +37 -0
  118. package/dist/references/scope-computation.js +288 -0
  119. package/dist/references/scope-provider.d.ts +3 -3
  120. package/dist/references/scope-provider.js +242 -0
  121. package/dist/shared/NodeKindProvider.js +57 -0
  122. package/dist/shared/{WorkspaceSymbolProvider.mjs → WorkspaceSymbolProvider.js} +1 -1
  123. package/dist/shared/index.js +2 -0
  124. package/dist/test/index.js +1 -0
  125. package/dist/test/testServices.d.ts +16 -16
  126. package/dist/test/testServices.js +210 -0
  127. package/dist/utils/disposable.js +26 -0
  128. package/dist/utils/elementRef.d.ts +1 -1
  129. package/dist/utils/elementRef.js +27 -0
  130. package/dist/utils/fqnRef.js +63 -0
  131. package/dist/utils/index.js +35 -0
  132. package/dist/utils/printDocs.js +1 -0
  133. package/dist/utils/projectId.js +16 -0
  134. package/dist/utils/stringHash.js +5 -0
  135. package/dist/validation/DocumentValidator.js +17 -0
  136. package/dist/validation/_shared.js +26 -0
  137. package/dist/validation/deployment-checks.js +140 -0
  138. package/dist/validation/dynamic-view.js +67 -0
  139. package/dist/validation/element-ref.js +12 -0
  140. package/dist/validation/element.js +49 -0
  141. package/dist/validation/imports.js +46 -0
  142. package/dist/validation/index.d.ts +1 -1
  143. package/dist/validation/index.js +157 -0
  144. package/dist/validation/property-checks.js +108 -0
  145. package/dist/validation/relation.js +55 -0
  146. package/dist/validation/specification.js +190 -0
  147. package/dist/validation/view-predicates/fqn-expr-with.js +43 -0
  148. package/dist/validation/view-predicates/fqn-ref-expr.js +51 -0
  149. package/dist/validation/view-predicates/incoming.js +16 -0
  150. package/dist/validation/view-predicates/index.js +6 -0
  151. package/dist/validation/view-predicates/outgoing.js +20 -0
  152. package/dist/validation/view-predicates/relation-expr.js +46 -0
  153. package/dist/validation/view-predicates/relation-with.js +16 -0
  154. package/dist/validation/view.d.ts +1 -1
  155. package/dist/validation/view.js +42 -0
  156. package/dist/view-utils/assignNavigateTo.js +27 -0
  157. package/dist/view-utils/index.d.ts +1 -0
  158. package/dist/view-utils/index.js +2 -0
  159. package/dist/view-utils/manual-layout.d.ts +6 -0
  160. package/dist/view-utils/manual-layout.js +151 -0
  161. package/dist/views/ConfigurableLayouter.js +51 -0
  162. package/dist/views/LikeC4ManualLayouts.d.ts +28 -0
  163. package/dist/views/LikeC4ManualLayouts.js +132 -0
  164. package/dist/views/{likec4-views.d.ts → LikeC4Views.d.ts} +9 -8
  165. package/dist/views/LikeC4Views.js +200 -0
  166. package/dist/views/index.d.ts +4 -1
  167. package/dist/views/index.js +11 -0
  168. package/dist/workspace/AstNodeDescriptionProvider.js +15 -0
  169. package/dist/workspace/IndexManager.js +21 -0
  170. package/dist/workspace/LangiumDocuments.d.ts +1 -1
  171. package/dist/workspace/LangiumDocuments.js +58 -0
  172. package/dist/workspace/ProjectsManager.d.ts +8 -3
  173. package/dist/workspace/ProjectsManager.js +373 -0
  174. package/dist/workspace/WorkspaceManager.d.ts +3 -2
  175. package/dist/workspace/WorkspaceManager.js +93 -0
  176. package/dist/workspace/index.js +5 -0
  177. package/likec4lib/package.json +1 -1
  178. package/package.json +25 -24
  179. package/protocol/package.json +1 -1
  180. package/dist/LikeC4LanguageServices.mjs +0 -197
  181. package/dist/Rpc.mjs +0 -296
  182. package/dist/ast.mjs +0 -221
  183. package/dist/browser-worker.mjs +0 -2
  184. package/dist/browser.mjs +0 -32
  185. package/dist/documentation/documentation-provider.mjs +0 -48
  186. package/dist/documentation/index.mjs +0 -1
  187. package/dist/empty.mjs +0 -1
  188. package/dist/filesystem/ChokidarWatcher.mjs +0 -68
  189. package/dist/filesystem/FileSystemWatcher.mjs +0 -11
  190. package/dist/filesystem/LikeC4FileSystem.mjs +0 -64
  191. package/dist/filesystem/index.mjs +0 -19
  192. package/dist/formatting/LikeC4Formatter.mjs +0 -511
  193. package/dist/formatting/utils.mjs +0 -15
  194. package/dist/generated/ast.mjs +0 -2150
  195. package/dist/generated/module.mjs +0 -23
  196. package/dist/index.mjs +0 -50
  197. package/dist/logger.mjs +0 -82
  198. package/dist/lsp/CodeLensProvider.mjs +0 -42
  199. package/dist/lsp/CompletionProvider.mjs +0 -208
  200. package/dist/lsp/DocumentHighlightProvider.mjs +0 -10
  201. package/dist/lsp/DocumentLinkProvider.mjs +0 -53
  202. package/dist/lsp/DocumentSymbolProvider.mjs +0 -287
  203. package/dist/lsp/HoverProvider.mjs +0 -104
  204. package/dist/lsp/RenameProvider.mjs +0 -6
  205. package/dist/lsp/SemanticTokenProvider.mjs +0 -276
  206. package/dist/lsp/index.mjs +0 -7
  207. package/dist/mcp/MCPServerFactory.mjs +0 -70
  208. package/dist/mcp/NoopLikeC4MCPServer.mjs +0 -17
  209. package/dist/mcp/interfaces.mjs +0 -4
  210. package/dist/mcp/server/StdioLikeC4MCPServer.mjs +0 -46
  211. package/dist/mcp/server/StreamableLikeC4MCPServer.mjs +0 -153
  212. package/dist/mcp/server/WithMCPServer.mjs +0 -58
  213. package/dist/mcp/tools/_common.mjs +0 -42
  214. package/dist/mcp/tools/find-relationships.mjs +0 -151
  215. package/dist/mcp/tools/list-projects.mjs +0 -62
  216. package/dist/mcp/tools/open-view.mjs +0 -52
  217. package/dist/mcp/tools/read-deployment.mjs +0 -130
  218. package/dist/mcp/tools/read-element.mjs +0 -198
  219. package/dist/mcp/tools/read-project-summary.mjs +0 -178
  220. package/dist/mcp/tools/read-view.mjs +0 -205
  221. package/dist/mcp/tools/search-element.mjs +0 -171
  222. package/dist/mcp/utils.mjs +0 -47
  223. package/dist/model/builder/MergedExtends.mjs +0 -76
  224. package/dist/model/builder/MergedSpecification.mjs +0 -205
  225. package/dist/model/builder/assignTagColors.d.ts +0 -7
  226. package/dist/model/builder/assignTagColors.mjs +0 -51
  227. package/dist/model/builder/buildModel.mjs +0 -226
  228. package/dist/model/deployments-index.mjs +0 -100
  229. package/dist/model/fqn-index.mjs +0 -243
  230. package/dist/model/index.mjs +0 -6
  231. package/dist/model/model-builder.mjs +0 -285
  232. package/dist/model/model-locator.mjs +0 -239
  233. package/dist/model/model-parser-where.mjs +0 -81
  234. package/dist/model/model-parser.mjs +0 -127
  235. package/dist/model/parser/Base.mjs +0 -376
  236. package/dist/model/parser/DeploymentModelParser.mjs +0 -212
  237. package/dist/model/parser/DeploymentViewParser.mjs +0 -95
  238. package/dist/model/parser/FqnRefParser.mjs +0 -398
  239. package/dist/model/parser/GlobalsParser.mjs +0 -82
  240. package/dist/model/parser/ImportsParser.mjs +0 -28
  241. package/dist/model/parser/ModelParser.mjs +0 -190
  242. package/dist/model/parser/PredicatesParser.mjs +0 -45
  243. package/dist/model/parser/SpecificationParser.mjs +0 -120
  244. package/dist/model/parser/ValueConverter.mjs +0 -12
  245. package/dist/model/parser/ViewsParser.mjs +0 -490
  246. package/dist/model-change/ModelChanges.mjs +0 -89
  247. package/dist/model-change/changeElementStyle.mjs +0 -143
  248. package/dist/model-change/changeViewLayout.mjs +0 -32
  249. package/dist/model-change/saveManualLayout.d.ts +0 -11
  250. package/dist/model-change/saveManualLayout.mjs +0 -27
  251. package/dist/module.mjs +0 -180
  252. package/dist/protocol.mjs +0 -65
  253. package/dist/references/index.mjs +0 -3
  254. package/dist/references/name-provider.mjs +0 -39
  255. package/dist/references/scope-computation.mjs +0 -312
  256. package/dist/references/scope-provider.mjs +0 -239
  257. package/dist/shared/NodeKindProvider.mjs +0 -110
  258. package/dist/shared/index.mjs +0 -2
  259. package/dist/test/index.mjs +0 -1
  260. package/dist/test/testServices.mjs +0 -200
  261. package/dist/utils/disposable.mjs +0 -25
  262. package/dist/utils/elementRef.mjs +0 -20
  263. package/dist/utils/fqnRef.mjs +0 -57
  264. package/dist/utils/index.mjs +0 -33
  265. package/dist/utils/printDocs.mjs +0 -1
  266. package/dist/utils/projectId.mjs +0 -16
  267. package/dist/utils/stringHash.mjs +0 -5
  268. package/dist/validation/DocumentValidator.mjs +0 -16
  269. package/dist/validation/_shared.mjs +0 -25
  270. package/dist/validation/deployment-checks.mjs +0 -146
  271. package/dist/validation/dynamic-view.mjs +0 -67
  272. package/dist/validation/element-ref.mjs +0 -12
  273. package/dist/validation/element.mjs +0 -50
  274. package/dist/validation/imports.mjs +0 -25
  275. package/dist/validation/index.mjs +0 -180
  276. package/dist/validation/property-checks.mjs +0 -107
  277. package/dist/validation/relation.mjs +0 -53
  278. package/dist/validation/specification.mjs +0 -173
  279. package/dist/validation/view-predicates/fqn-expr-with.mjs +0 -43
  280. package/dist/validation/view-predicates/fqn-ref-expr.mjs +0 -53
  281. package/dist/validation/view-predicates/incoming.mjs +0 -16
  282. package/dist/validation/view-predicates/index.mjs +0 -6
  283. package/dist/validation/view-predicates/outgoing.mjs +0 -20
  284. package/dist/validation/view-predicates/relation-expr.mjs +0 -39
  285. package/dist/validation/view-predicates/relation-with.mjs +0 -16
  286. package/dist/validation/view.mjs +0 -25
  287. package/dist/view-utils/assignNavigateTo.mjs +0 -25
  288. package/dist/view-utils/index.mjs +0 -1
  289. package/dist/view-utils/manual-layout.mjs +0 -99
  290. package/dist/views/configurable-layouter.mjs +0 -51
  291. package/dist/views/index.mjs +0 -1
  292. package/dist/views/likec4-views.mjs +0 -166
  293. package/dist/workspace/AstNodeDescriptionProvider.mjs +0 -17
  294. package/dist/workspace/IndexManager.mjs +0 -17
  295. package/dist/workspace/LangiumDocuments.mjs +0 -53
  296. package/dist/workspace/ProjectsManager.mjs +0 -360
  297. package/dist/workspace/WorkspaceManager.mjs +0 -83
  298. package/dist/workspace/index.mjs +0 -5
  299. /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
- }