@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,4 +1,4 @@
1
1
  {
2
2
  "types": "../dist/browser.d.ts",
3
- "module": "../dist/browser.mjs"
3
+ "module": "../dist/browser.js"
4
4
  }
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "types": "../dist/browser-worker.d.ts",
3
- "module": "../dist/browser-worker.mjs"
3
+ "module": "../dist/browser-worker.js"
4
4
  }
@@ -1,12 +1,13 @@
1
1
  import type { LikeC4ProjectConfig } from '@likec4/config';
2
- import { type DiagramView, type NonEmptyArray, type ProjectId } from '@likec4/core';
2
+ import { type DiagramView, type NonEmptyArray, type ProjectId, type UnknownComputed, type UnknownLayouted } from '@likec4/core';
3
3
  import { LikeC4Model } from '@likec4/core/model';
4
- import { type LangiumDocument, URI } from 'langium';
5
- import { type Range } from 'vscode-languageserver-types';
4
+ import { URI } from 'langium';
5
+ import type { CancellationToken } from 'vscode-jsonrpc';
6
+ import type { Range } from 'vscode-languageserver-types';
6
7
  import type { LikeC4ModelBuilder } from './model';
7
8
  import type { LikeC4Services } from './module';
8
9
  import type { Locate } from './protocol';
9
- import type { LikeC4Views } from './views/likec4-views';
10
+ import type { LikeC4Views } from './views/LikeC4Views';
10
11
  import { ProjectsManager } from './workspace';
11
12
  export interface LikeC4LanguageServices {
12
13
  readonly views: LikeC4Views;
@@ -36,33 +37,22 @@ export interface LikeC4LanguageServices {
36
37
  };
37
38
  /**
38
39
  * Returns diagrams (i.e. views with layout computed) for the specified project
40
+ * if diagram has manual layout, it will be used
39
41
  * If no project is specified, returns diagrams for default project
40
42
  */
41
- diagrams(project?: ProjectId | undefined): Promise<DiagramView[]>;
42
- computedModel(project?: ProjectId | undefined): Promise<LikeC4Model.Computed>;
43
- layoutedModel(project?: ProjectId | undefined): Promise<LikeC4Model.Layouted>;
43
+ diagrams(project?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<DiagramView[]>;
44
+ computedModel(project?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<LikeC4Model<UnknownComputed>>;
45
+ layoutedModel(project?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<LikeC4Model<UnknownLayouted>>;
44
46
  getErrors(): Array<{
45
47
  message: string;
46
48
  line: number;
47
49
  range: Range;
48
50
  sourceFsPath: string;
49
51
  }>;
50
- /**
51
- * Notifies the language server about changes in the workspace
52
- * @deprecated use watcher instead
53
- */
54
- notifyUpdate(update: {
55
- changed?: string;
56
- removed?: string;
57
- }): Promise<boolean>;
58
52
  /**
59
53
  * Returns the location of the specified element, relation, view or deployment element
60
54
  */
61
55
  locate(params: Locate.Params): Locate.Res;
62
- /**
63
- * Checks if the specified document should be excluded from processing.
64
- */
65
- isExcluded(doc: LangiumDocument): boolean;
66
56
  dispose(): Promise<void>;
67
57
  }
68
58
  /**
@@ -91,37 +81,26 @@ export declare class DefaultLikeC4LanguageServices implements LikeC4LanguageServ
91
81
  };
92
82
  /**
93
83
  * Diagram is a computed view, layouted using Graphviz
94
- * Used in React components
84
+ * If diagram has manual layout, it will be used.
95
85
  */
96
- diagrams(): Promise<DiagramView[]>;
86
+ diagrams(project?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<DiagramView[]>;
97
87
  /**
98
88
  * Builds LikeC4Model from all documents
99
89
  * Only computes view predicates {@link ComputedView} - i.e. no layout
100
90
  * Not ready for rendering, but enough to traverse
101
91
  */
102
- computedModel(project?: ProjectId | undefined): Promise<LikeC4Model.Computed>;
92
+ computedModel(project?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<LikeC4Model<UnknownComputed>>;
103
93
  /**
104
94
  * Same as {@link computedModel()}, but also applies layout
105
95
  * Ready for rendering
106
96
  */
107
- layoutedModel(project?: ProjectId | undefined): Promise<LikeC4Model.Layouted>;
97
+ layoutedModel(project?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<LikeC4Model<UnknownLayouted>>;
108
98
  getErrors(): Array<{
109
99
  message: string;
110
100
  line: number;
111
101
  range: Range;
112
102
  sourceFsPath: string;
113
103
  }>;
114
- /**
115
- * TODO Replace with watcher
116
- */
117
- notifyUpdate({ changed, removed }: {
118
- changed?: string;
119
- removed?: string;
120
- }): Promise<boolean>;
121
104
  locate(params: Locate.Params): Locate.Res;
122
- /**
123
- * Checks if the specified document should be excluded from processing.
124
- */
125
- isExcluded(doc: LangiumDocument): boolean;
126
105
  dispose(): Promise<void>;
127
106
  }
@@ -0,0 +1,152 @@
1
+ import { nonexhaustive, } from '@likec4/core';
2
+ import { LikeC4Model } from '@likec4/core/model';
3
+ import { loggable } from '@likec4/log';
4
+ import { URI } from 'langium';
5
+ import { entries, hasAtLeast, indexBy, map, pipe, prop } from 'remeda';
6
+ import { DiagnosticSeverity } from 'vscode-languageserver-types';
7
+ import { logger as mainLogger } from './logger';
8
+ import { ProjectsManager } from './workspace';
9
+ const logger = mainLogger.getChild('LanguageServices');
10
+ /**
11
+ * Public Language Services
12
+ */
13
+ export class DefaultLikeC4LanguageServices {
14
+ services;
15
+ builder;
16
+ projectsManager;
17
+ constructor(services) {
18
+ this.services = services;
19
+ this.builder = services.likec4.ModelBuilder;
20
+ this.projectsManager = services.shared.workspace.ProjectsManager;
21
+ }
22
+ get views() {
23
+ return this.services.likec4.Views;
24
+ }
25
+ get workspaceUri() {
26
+ return this.services.shared.workspace.WorkspaceManager.workspaceUri;
27
+ }
28
+ projects() {
29
+ const projectsManager = this.services.shared.workspace.ProjectsManager;
30
+ const projectsWithDocs = pipe(this.services.shared.workspace.LangiumDocuments.groupedByProject(), entries(), map(([projectId, docs]) => {
31
+ const id = projectId;
32
+ const { folderUri, config } = projectsManager.getProject(id);
33
+ return {
34
+ id,
35
+ folder: folderUri,
36
+ title: config.title ?? config.name,
37
+ documents: map(docs, prop('uri')),
38
+ config,
39
+ };
40
+ }));
41
+ // if there are multiple projects and default project is set, ensure it is first
42
+ if (hasAtLeast(projectsWithDocs, 2) && projectsManager.defaultProjectId) {
43
+ const idx = projectsWithDocs.findIndex(p => p.id === projectsManager.defaultProjectId);
44
+ if (idx > 0) {
45
+ const [defaultProject] = projectsWithDocs.splice(idx, 1);
46
+ return [defaultProject, ...projectsWithDocs];
47
+ }
48
+ return projectsWithDocs;
49
+ }
50
+ if (hasAtLeast(projectsWithDocs, 1)) {
51
+ return projectsWithDocs;
52
+ }
53
+ const { folderUri, config } = projectsManager.getProject(ProjectsManager.DefaultProjectId);
54
+ const documents = map(this.services.shared.workspace.LangiumDocuments.projectDocuments(ProjectsManager.DefaultProjectId).toArray(), prop('uri'));
55
+ return [{
56
+ id: ProjectsManager.DefaultProjectId,
57
+ folder: folderUri,
58
+ title: config.title ?? config.name,
59
+ documents,
60
+ config,
61
+ }];
62
+ }
63
+ project(projectId) {
64
+ projectId = this.projectsManager.ensureProjectId(projectId);
65
+ const projectsManager = this.services.shared.workspace.ProjectsManager;
66
+ const { folderUri, config } = projectsManager.getProject(projectId);
67
+ const documents = map(this.services.shared.workspace.LangiumDocuments.projectDocuments(projectId).toArray(), prop('uri'));
68
+ return {
69
+ id: projectId,
70
+ folder: folderUri,
71
+ title: config.title ?? config.name,
72
+ documents,
73
+ config,
74
+ };
75
+ }
76
+ /**
77
+ * Diagram is a computed view, layouted using Graphviz
78
+ * If diagram has manual layout, it will be used.
79
+ */
80
+ async diagrams(project, cancelToken) {
81
+ const projectId = this.projectsManager.ensureProjectId(project);
82
+ return await this.views.diagrams(projectId, cancelToken);
83
+ }
84
+ /**
85
+ * Builds LikeC4Model from all documents
86
+ * Only computes view predicates {@link ComputedView} - i.e. no layout
87
+ * Not ready for rendering, but enough to traverse
88
+ */
89
+ async computedModel(project, cancelToken) {
90
+ const projectId = this.projectsManager.ensureProjectId(project);
91
+ return await this.builder.computeModel(projectId, cancelToken);
92
+ }
93
+ /**
94
+ * Same as {@link computedModel()}, but also applies layout
95
+ * Ready for rendering
96
+ */
97
+ async layoutedModel(project, cancelToken) {
98
+ const projectId = this.projectsManager.ensureProjectId(project);
99
+ const model = await this.builder.computeModel(projectId, cancelToken);
100
+ if (!model) {
101
+ throw new Error('Failed to compute model, empty project?');
102
+ }
103
+ const layouted = await this.views.layoutAllViews(projectId, cancelToken);
104
+ return LikeC4Model.create({
105
+ ...model.$data,
106
+ _stage: 'layouted',
107
+ views: pipe(layouted, map(prop('diagram')), indexBy(prop('id'))),
108
+ });
109
+ }
110
+ getErrors() {
111
+ const docs = this.services.shared.workspace.LangiumDocuments.allExcludingBuiltin.toArray();
112
+ return docs.flatMap(doc => {
113
+ return (doc.diagnostics ?? [])
114
+ .filter(d => d.severity === DiagnosticSeverity.Error)
115
+ .map(({ message, range }) => ({
116
+ message,
117
+ line: range.start.line,
118
+ range,
119
+ sourceFsPath: doc.uri.fsPath,
120
+ }));
121
+ });
122
+ }
123
+ locate(params) {
124
+ switch (true) {
125
+ case 'element' in params:
126
+ return this.services.likec4.ModelLocator.locateElement(params.element, params.projectId);
127
+ case 'relation' in params:
128
+ return this.services.likec4.ModelLocator.locateRelation(params.relation, params.projectId);
129
+ case 'view' in params:
130
+ return this.services.likec4.ModelLocator.locateView(params.view, params.projectId);
131
+ case 'deployment' in params:
132
+ return this.services.likec4.ModelLocator.locateDeploymentElement(params.deployment, params.projectId);
133
+ default:
134
+ nonexhaustive(params);
135
+ }
136
+ }
137
+ async dispose() {
138
+ try {
139
+ logger.debug('disposing LikeC4LanguageServices');
140
+ await this.services.shared.workspace.FileSystemWatcher.dispose();
141
+ if (this.services.mcp.Server.isStarted) {
142
+ await this.services.mcp.Server.stop();
143
+ }
144
+ this.services.Rpc.dispose();
145
+ this.services.likec4.ModelBuilder.dispose();
146
+ logger.debug('LikeC4LanguageServices disposed');
147
+ }
148
+ catch (e) {
149
+ logger.error(loggable(e));
150
+ }
151
+ }
152
+ }
package/dist/Rpc.js ADDED
@@ -0,0 +1,257 @@
1
+ import { filter, flatMap, funnel, indexBy, keys, map, mapValues, pipe, sort } from 'remeda';
2
+ import { logger as rootLogger } from './logger';
3
+ import { invariant, nonexhaustive, } from '@likec4/core';
4
+ import { LikeC4Model } from '@likec4/core/model';
5
+ import { Disposable, interruptAndCheck, URI, UriUtils } from 'langium';
6
+ import { DiagnosticSeverity } from 'vscode-languageserver-protocol';
7
+ import { BuildDocuments, ChangeView, DidChangeModelNotification, DidChangeSnapshotNotification, DidRequestOpenViewNotification, FetchComputedModel, FetchLayoutedModel, FetchProjects, FetchTelemetryMetrics, FetchViewsFromAllProjects, GetDocumentTags, LayoutView, Locate, RegisterProject, ReloadProjects, ValidateLayout, } from './protocol';
8
+ import { ADisposable } from './utils';
9
+ const logger = rootLogger.getChild('rpc');
10
+ export class Rpc extends ADisposable {
11
+ services;
12
+ constructor(services) {
13
+ super();
14
+ this.services = services;
15
+ }
16
+ init() {
17
+ const connection = this.services.shared.lsp.Connection;
18
+ if (!connection) {
19
+ logger.info(`no connection, skip init ServerRpc`);
20
+ return;
21
+ }
22
+ logger.info(`init ServerRpc`);
23
+ const likec4Services = this.services.likec4;
24
+ const projects = this.services.shared.workspace.ProjectsManager;
25
+ const LangiumDocuments = this.services.shared.workspace.LangiumDocuments;
26
+ const DocumentBuilder = this.services.shared.workspace.DocumentBuilder;
27
+ const notifyModelParsed = funnel((batch) => {
28
+ logger.debug `send onDidChangeModel ${batch > 1 ? '(' + batch + ' batched)' : ''}`;
29
+ connection.sendNotification(DidChangeModelNotification.type, '').catch(error => {
30
+ logger.warn(`[ServerRpc] error sending onDidChangeModel:`, { error });
31
+ return;
32
+ });
33
+ }, {
34
+ reducer: (accumulator, req) => (accumulator ?? 0) + req,
35
+ triggerAt: 'end',
36
+ minQuietPeriodMs: 200,
37
+ maxBurstDurationMs: 400,
38
+ });
39
+ let isFirstBuild = true;
40
+ this.onDispose(likec4Services.ModelBuilder.onModelParsed(() => notifyModelParsed.call(1)), connection.onRequest(FetchComputedModel.req, async ({ projectId, cleanCaches }, cancelToken) => {
41
+ logger.debug `received request ${'fetchComputedModel'} for project ${projectId}`;
42
+ if (cleanCaches) {
43
+ const docs = projectId
44
+ ? LangiumDocuments.projectDocuments(projectId)
45
+ : LangiumDocuments.allExcludingBuiltin;
46
+ const uris = docs.toArray().map(d => d.uri);
47
+ await DocumentBuilder.update(uris, [], cancelToken);
48
+ }
49
+ const likec4model = await likec4Services.ModelBuilder.computeModel(projectId, cancelToken);
50
+ if (likec4model !== LikeC4Model.EMPTY) {
51
+ return { model: likec4model.$model };
52
+ }
53
+ return { model: null };
54
+ }), connection.onNotification(DidChangeSnapshotNotification.type, async ({ snapshotUri }) => {
55
+ logger.debug `received notification ${'onDidChangeSnapshot'} for snapshot ${snapshotUri}`;
56
+ const uri = URI.parse(snapshotUri);
57
+ await projects.rebuidProject(projects.belongsTo(uri.path));
58
+ }), connection.onRequest(FetchLayoutedModel.req, async ({ projectId }, cancelToken) => {
59
+ logger.debug `received request ${'fetchLayoutedModel'} for project ${projectId}`;
60
+ const model = await likec4Services.LanguageServices.layoutedModel(projectId);
61
+ if (model === null) {
62
+ return { model: null };
63
+ }
64
+ const diagrams = await likec4Services.Views.diagrams(projectId, cancelToken);
65
+ return {
66
+ model: {
67
+ ...model.$data,
68
+ _stage: 'layouted',
69
+ views: indexBy(diagrams, d => d.id),
70
+ },
71
+ };
72
+ }), connection.onRequest(LayoutView.req, async ({ viewId, projectId, layoutType, }, cancelToken) => {
73
+ logger
74
+ .debug `received request ${'layoutView'} for ${viewId} from project ${projectId} (layout type: ${layoutType ?? 'not set'})`;
75
+ const result = await likec4Services.Views.layoutView({
76
+ viewId,
77
+ projectId: projectId,
78
+ layoutType,
79
+ cancelToken,
80
+ });
81
+ return { result };
82
+ }), connection.onRequest(ValidateLayout.req, async ({ projectId }, cancelToken) => {
83
+ logger.debug `received request ${'validateLayout'} for project ${projectId}`;
84
+ const layouts = await likec4Services.Views.layoutAllViews(projectId, cancelToken);
85
+ const result = reportLayoutDrift(layouts.map(l => l.diagram));
86
+ return { result };
87
+ }), connection.onRequest(FetchProjects.req, async () => {
88
+ logger.debug `received request ${'FetchProjects'}`;
89
+ const docsByProject = LangiumDocuments.groupedByProject();
90
+ return {
91
+ projects: mapValues(docsByProject, (docs, projectId) => {
92
+ const { folderUri, config: { name, title, }, } = projects.getProject(projectId);
93
+ return {
94
+ folder: folderUri.toString(),
95
+ config: {
96
+ name,
97
+ title,
98
+ },
99
+ docs: map(docs, d => d.uri.toString()),
100
+ };
101
+ }),
102
+ };
103
+ }), connection.onRequest(ReloadProjects.req, async () => {
104
+ logger.debug `received request ${'ReloadProjects'}`;
105
+ likec4Services.ManualLayouts.clearCaches();
106
+ await projects.reloadProjects();
107
+ return;
108
+ }), connection.onRequest(RegisterProject.req, async (params) => {
109
+ logger.debug `received request ${'RegisterProject'}`;
110
+ const project = await projects.registerProject(params);
111
+ return { id: project.id };
112
+ }), connection.onRequest(FetchViewsFromAllProjects.req, async (cancelToken) => {
113
+ logger.debug `received request ${'FetchViewsFromAllProjects'}`;
114
+ const promises = projects.all.map(async (projectId) => {
115
+ const computedViews = await likec4Services.Views.computedViews(projectId, cancelToken);
116
+ return pipe(computedViews, map(v => ({
117
+ id: v.id,
118
+ title: v.title ?? v.id,
119
+ projectId,
120
+ })), sort((a, b) => {
121
+ if (a.id === 'index') {
122
+ return -1;
123
+ }
124
+ if (b.id === 'index') {
125
+ return 1;
126
+ }
127
+ return a.title.localeCompare(b.title);
128
+ }));
129
+ });
130
+ const results = await Promise.allSettled(promises);
131
+ await interruptAndCheck(cancelToken);
132
+ return {
133
+ views: pipe(results, filter(r => r.status === 'fulfilled'), flatMap(r => r.value)),
134
+ };
135
+ }), connection.onRequest(BuildDocuments.req, async ({ docs }, cancelToken) => {
136
+ const changed = docs.map(d => URI.parse(d));
137
+ const notChanged = (uri) => changed.every(c => !UriUtils.equals(c, uri));
138
+ const deleted = LangiumDocuments.allExcludingBuiltin
139
+ .toArray()
140
+ .filter(d => notChanged(d.uri))
141
+ .map(d => d.uri);
142
+ logger.debug(`[ServerRpc] received request to build:
143
+ changed (total ${changed.length}):${docs.map(d => '\n - ' + d).join('')}
144
+ deleted (total ${deleted.length}):${deleted.map(d => '\n - ' + d.toString()).join('\n')}`);
145
+ if (!isFirstBuild && (changed.length + deleted.length) > 0) {
146
+ await Promise.allSettled([...changed, ...deleted].map(async (d) => {
147
+ const uri = d.toString();
148
+ logger.debug(`clear diagnostics for ${uri}`);
149
+ try {
150
+ await connection.sendDiagnostics({
151
+ uri,
152
+ diagnostics: [],
153
+ });
154
+ }
155
+ catch (e) {
156
+ // Ignore
157
+ logger.warn(`error clearing diagnostics for ${uri}: ${e}`);
158
+ }
159
+ }));
160
+ }
161
+ isFirstBuild = false;
162
+ await interruptAndCheck(cancelToken);
163
+ await DocumentBuilder.update(changed, deleted, cancelToken);
164
+ }), connection.onRequest(Locate.req, params => {
165
+ logger.debug `received request ${'locate'}, ${params}`;
166
+ switch (true) {
167
+ case 'element' in params:
168
+ return likec4Services.ModelLocator.locateElement(params.element, params.projectId);
169
+ case 'relation' in params:
170
+ return likec4Services.ModelLocator.locateRelation(params.relation, params.projectId);
171
+ case 'astPath' in params:
172
+ return likec4Services.ModelLocator.locateDynamicViewStep({
173
+ view: params.view,
174
+ astPath: params.astPath,
175
+ projectId: params.projectId,
176
+ });
177
+ case 'view' in params:
178
+ return likec4Services.ModelLocator.locateView(params.view, params.projectId);
179
+ case 'deployment' in params:
180
+ return likec4Services.ModelLocator.locateDeploymentElement(params.deployment, params.projectId);
181
+ default:
182
+ nonexhaustive(params);
183
+ }
184
+ }), connection.onRequest(ChangeView.req, async (request, _cancelToken) => {
185
+ logger.debug `received request ${'changeView'} of ${request.viewId} from project ${request.projectId}`;
186
+ return await likec4Services.ModelChanges.applyChange(request);
187
+ }), connection.onRequest(FetchTelemetryMetrics.req, async (cancelToken) => {
188
+ const projectsIds = [...projects.all];
189
+ const promises = projectsIds.map(async (projectId) => {
190
+ const model = await likec4Services.ModelBuilder.computeModel(projectId, cancelToken);
191
+ if (model === LikeC4Model.EMPTY) {
192
+ return Promise.reject(new Error(`Model is empty`));
193
+ }
194
+ return {
195
+ elementKinds: keys(model.specification.elements).length,
196
+ deploymentKinds: keys(model.specification.deployments).length,
197
+ relationshipKinds: keys(model.specification.relationships).length,
198
+ tags: keys(model.specification.tags).length,
199
+ customColors: keys(model.specification.customColors ?? {}).length,
200
+ elements: keys(model.$data.elements).length,
201
+ deploymentNodes: [...model.deployment.nodes()].length,
202
+ relationships: keys(model.$data.relations).length,
203
+ views: keys(model.$data.views).length,
204
+ projects: 1,
205
+ };
206
+ });
207
+ const results = await Promise.allSettled(promises);
208
+ await interruptAndCheck(cancelToken);
209
+ const values = results.filter(r => r.status === 'fulfilled').map(r => r.value);
210
+ const metrics = values.length > 0
211
+ ? values.reduce((acc, r) => ({
212
+ elementKinds: acc.elementKinds + r.elementKinds,
213
+ deploymentKinds: acc.deploymentKinds + r.deploymentKinds,
214
+ relationshipKinds: acc.relationshipKinds + r.relationshipKinds,
215
+ tags: acc.tags + r.tags,
216
+ customColors: acc.customColors + r.customColors,
217
+ elements: acc.elements + r.elements,
218
+ deploymentNodes: acc.deploymentNodes + r.deploymentNodes,
219
+ relationships: acc.relationships + r.relationships,
220
+ views: acc.views + r.views,
221
+ projects: acc.projects + 1,
222
+ }))
223
+ : null;
224
+ return {
225
+ metrics,
226
+ };
227
+ }), connection.onRequest(GetDocumentTags.req, async ({ documentUri }, cancelToken) => {
228
+ const tags = await likec4Services.ModelLocator.locateDocumentTags(URI.parse(documentUri), cancelToken);
229
+ return {
230
+ tags,
231
+ };
232
+ }), Disposable.create(() => {
233
+ notifyModelParsed.cancel();
234
+ }));
235
+ function reportLayoutDrift(diagrams) {
236
+ return pipe(diagrams, filter(d => !!d.hasLayoutDrift), map(d => {
237
+ const loc = likec4Services.ModelLocator.locateView(d.id);
238
+ invariant(loc, `View ${d.id} not found`);
239
+ return {
240
+ uri: loc.uri,
241
+ viewId: d.id,
242
+ severity: DiagnosticSeverity.Warning,
243
+ message: `Layout drift detected for view '${d.id}'`,
244
+ range: loc.range,
245
+ };
246
+ }));
247
+ }
248
+ }
249
+ async openView(params) {
250
+ const lspConnection = this.services.shared.lsp.Connection;
251
+ if (!lspConnection) {
252
+ logger.warn('No LSP connection');
253
+ return;
254
+ }
255
+ await lspConnection.sendNotification(DidRequestOpenViewNotification.type, params);
256
+ }
257
+ }
package/dist/ast.d.ts CHANGED
@@ -122,6 +122,7 @@ export type ParsedAstDeploymentRelation = c4.DeploymentRelationship & {
122
122
  };
123
123
  export type ParsedAstGlobals = Writable<c4.ModelGlobals>;
124
124
  export interface ParsedAstElementView {
125
+ [c4._type]: 'element';
125
126
  id: c4.ViewId;
126
127
  viewOf?: c4.Fqn;
127
128
  extends?: c4.ViewId;
@@ -134,6 +135,7 @@ export interface ParsedAstElementView {
134
135
  manualLayout?: c4.ViewManualLayout;
135
136
  }
136
137
  export interface ParsedAstDynamicView {
138
+ [c4._type]: 'dynamic';
137
139
  id: c4.ViewId;
138
140
  astPath: string;
139
141
  title: string | null;
@@ -146,6 +148,7 @@ export interface ParsedAstDynamicView {
146
148
  manualLayout?: c4.ViewManualLayout;
147
149
  }
148
150
  export interface ParsedAstDeploymentView {
151
+ [c4._type]: 'deployment';
149
152
  id: c4.ViewId;
150
153
  astPath: string;
151
154
  title: string | null;
@@ -153,6 +156,7 @@ export interface ParsedAstDeploymentView {
153
156
  tags: c4.NonEmptyArray<c4.Tag> | null;
154
157
  links: c4.NonEmptyArray<c4.Link> | null;
155
158
  rules: Array<c4.DeploymentViewRule>;
159
+ manualLayout?: c4.ViewManualLayout;
156
160
  }
157
161
  export type ParsedAstView = ParsedAstElementView | ParsedAstDynamicView | ParsedAstDeploymentView;
158
162
  export declare const ViewOps: {
@@ -161,7 +165,7 @@ export declare const ViewOps: {
161
165
  };
162
166
  export declare const ElementOps: {
163
167
  writeId(node: ast.Element | ast.DeploymentElement, id: c4.Fqn | null): ast.DeploymentElement | ast.Element;
164
- readId(node: ast.Element | ast.DeploymentElement): any;
168
+ readId(node: ast.Element | ast.DeploymentElement): c4.Fqn<string> | undefined;
165
169
  };
166
170
  export interface AstNodeDescriptionWithFqn extends AstNodeDescription {
167
171
  likec4ProjectId: c4.ProjectId;