@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
@@ -0,0 +1,176 @@
1
+ import { exact, FqnRef, invariant, isNonEmptyArray, LinkedList, nameFromFqn, nonexhaustive, nonNullable, } from '@likec4/core';
2
+ import { loggable } from '@likec4/log';
3
+ import { filter, first, isDefined, isEmpty, isTruthy, mapToObj, pipe } from 'remeda';
4
+ import { ast, toRelationshipStyle, } from '../../ast';
5
+ import { serverLogger } from '../../logger';
6
+ import { stringHash } from '../../utils/stringHash';
7
+ const logger = serverLogger.getChild('DeploymentModelParser');
8
+ function* streamDeploymentModel(doc) {
9
+ const traverseStack = LinkedList.from(doc.parseResult.value.deployments.flatMap(m => m.elements));
10
+ const relations = [];
11
+ let el;
12
+ while ((el = traverseStack.shift())) {
13
+ if (ast.isDeploymentRelation(el)) {
14
+ relations.push(el);
15
+ continue;
16
+ }
17
+ if (el.body && el.body.elements.length > 0) {
18
+ for (const child of el.body.elements) {
19
+ traverseStack.push(child);
20
+ }
21
+ }
22
+ yield el;
23
+ }
24
+ yield* relations;
25
+ return;
26
+ }
27
+ export function DeploymentModelParser(B) {
28
+ return class DeploymentModelParser extends B {
29
+ parseDeployment() {
30
+ const doc = this.doc;
31
+ for (const el of streamDeploymentModel(doc)) {
32
+ try {
33
+ switch (true) {
34
+ case ast.isDeploymentRelation(el): {
35
+ if (this.isValid(el)) {
36
+ doc.c4DeploymentRelations.push(this.parseDeploymentRelation(el));
37
+ }
38
+ break;
39
+ }
40
+ case ast.isDeployedInstance(el):
41
+ doc.c4Deployments.push(this.parseDeployedInstance(el));
42
+ break;
43
+ case ast.isDeploymentNode(el): {
44
+ doc.c4Deployments.push(this.parseDeploymentNode(el));
45
+ break;
46
+ }
47
+ case ast.isExtendDeployment(el): {
48
+ const parsed = this.parseExtendDeployment(el);
49
+ if (parsed) {
50
+ doc.c4ExtendDeployments.push(parsed);
51
+ }
52
+ break;
53
+ }
54
+ default:
55
+ nonexhaustive(el);
56
+ }
57
+ }
58
+ catch (e) {
59
+ logger.warn(loggable(e));
60
+ }
61
+ }
62
+ }
63
+ parseDeploymentNode(astNode) {
64
+ const isValid = this.isValid;
65
+ const id = this.resolveFqn(astNode);
66
+ const kind = nonNullable(astNode.kind.ref, 'DeploymentKind not resolved').name;
67
+ const tags = this.convertTags(astNode.body);
68
+ const style = this.parseElementStyle(astNode.body?.props);
69
+ const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty));
70
+ const bodyProps = pipe(astNode.body?.props ?? [], filter(isValid), filter(ast.isElementStringProperty), mapToObj(p => [p.key, p.value]));
71
+ const { title, ...descAndTech } = this.parseBaseProps(bodyProps, {
72
+ title: astNode.title,
73
+ summary: astNode.summary,
74
+ });
75
+ const links = this.convertLinks(astNode.body);
76
+ return exact({
77
+ id,
78
+ kind,
79
+ title: title ?? nameFromFqn(id),
80
+ ...descAndTech,
81
+ tags: tags ?? undefined,
82
+ ...(links && isNonEmptyArray(links) && { links }),
83
+ style,
84
+ metadata,
85
+ });
86
+ }
87
+ parseDeployedInstance(astNode) {
88
+ const isValid = this.isValid;
89
+ const id = this.resolveFqn(astNode);
90
+ const target = this.parseFqnRef(astNode.target.modelElement);
91
+ invariant(FqnRef.isModelRef(target) || FqnRef.isImportRef(target), 'Target must be a model reference');
92
+ // const element = FqnRef.toModelFqn(target)
93
+ const tags = this.convertTags(astNode.body);
94
+ const style = this.parseElementStyle(astNode.body?.props);
95
+ const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty));
96
+ const bodyProps = pipe(astNode.body?.props ?? [], filter(isValid), filter(ast.isElementStringProperty), mapToObj(p => [p.key, p.value]));
97
+ const baseProps = this.parseBaseProps(bodyProps, {
98
+ title: astNode.title,
99
+ summary: astNode.summary,
100
+ });
101
+ const links = this.convertLinks(astNode.body);
102
+ return exact({
103
+ id,
104
+ element: target,
105
+ tags: tags ?? undefined,
106
+ ...(links && isNonEmptyArray(links) && { links }),
107
+ ...baseProps,
108
+ style,
109
+ metadata,
110
+ });
111
+ }
112
+ parseExtendDeployment(astNode) {
113
+ if (!this.isValid(astNode)) {
114
+ return null;
115
+ }
116
+ const id = this.resolveFqn(astNode);
117
+ const tags = this.parseTags(astNode.body);
118
+ const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty));
119
+ const astPath = this.getAstNodePath(astNode);
120
+ const links = this.parseLinks(astNode.body) ?? [];
121
+ if (!tags && isEmpty(metadata ?? {}) && isEmpty(links)) {
122
+ return null;
123
+ }
124
+ return {
125
+ id,
126
+ astPath,
127
+ ...(metadata && { metadata }),
128
+ tags,
129
+ links: isNonEmptyArray(links) ? links : null,
130
+ };
131
+ }
132
+ _resolveDeploymentRelationSource(node) {
133
+ if (isDefined(node.source)) {
134
+ return this.parseFqnRef(node.source);
135
+ }
136
+ if (node.$container.$type === 'DeploymentNodeBody' || node.$container.$type === 'DeployedInstanceBody') {
137
+ return {
138
+ deployment: this.resolveFqn(node.$container.$container),
139
+ };
140
+ }
141
+ throw new Error('RelationRefError: Invalid container for sourceless relation');
142
+ }
143
+ parseDeploymentRelation(astNode) {
144
+ const isValid = this.isValid;
145
+ const astPath = this.getAstNodePath(astNode);
146
+ const source = this._resolveDeploymentRelationSource(astNode);
147
+ invariant(FqnRef.isDeploymentRef(source), 'Invalid source for deployment relation');
148
+ const target = this.parseFqnRef(astNode.target);
149
+ invariant(FqnRef.isDeploymentRef(target), 'Invalid target for deployment relation');
150
+ const tags = this.convertTags(astNode) ?? this.convertTags(astNode.body);
151
+ const links = this.convertLinks(astNode.body);
152
+ const kind = (astNode.kind ?? astNode.dotKind?.kind)?.ref?.name;
153
+ const metadata = this.getMetadata(astNode.body?.props.find(ast.isMetadataProperty));
154
+ const bodyProps = pipe(astNode.body?.props ?? [], filter(ast.isRelationStringProperty), filter(p => isTruthy(p.value)), mapToObj(p => [p.key, p.value]));
155
+ const navigateTo = pipe(astNode.body?.props ?? [], filter(ast.isRelationNavigateToProperty), first())?.value.view.ref?.name;
156
+ const titleDescAndTech = this.parseBaseProps(bodyProps, {
157
+ title: astNode.title,
158
+ });
159
+ const styleProp = astNode.body?.props.find(ast.isRelationStyleProperty);
160
+ const id = stringHash('deployment', astPath, source.deployment, target.deployment);
161
+ return exact({
162
+ id,
163
+ source,
164
+ target,
165
+ ...titleDescAndTech,
166
+ metadata,
167
+ kind,
168
+ tags: tags ?? undefined,
169
+ ...(isNonEmptyArray(links) && { links }),
170
+ ...toRelationshipStyle(styleProp?.props, isValid),
171
+ navigateTo,
172
+ astPath,
173
+ });
174
+ }
175
+ };
176
+ }
@@ -31,14 +31,14 @@ export declare function DeploymentViewParser<TBase extends WithExpressionV2 & Wi
31
31
  readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
32
32
  get project(): import("../../workspace").Project;
33
33
  resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
34
- getAstNodePath(node: c4): any;
34
+ getAstNodePath(node: import("langium").AstNode): string;
35
35
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
36
36
  [key: string]: string | string[];
37
37
  } | undefined;
38
38
  parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): c4.MarkdownOrString | undefined;
39
39
  convertTags<E extends {
40
40
  tags?: ast.Tags;
41
- }>(withTags?: E | undefined): any;
41
+ }>(withTags?: E | undefined): c4.NonEmptyArray<c4.Tag<string>> | null;
42
42
  parseTags<E extends {
43
43
  tags?: ast.Tags;
44
44
  }>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
@@ -69,7 +69,7 @@ export declare function DeploymentViewParser<TBase extends WithExpressionV2 & Wi
69
69
  parseDeploymentNode(astNode: ast.DeploymentNode): import("../../ast").ParsedAstDeployment.Node;
70
70
  parseDeployedInstance(astNode: ast.DeployedInstance): import("../../ast").ParsedAstDeployment.Instance;
71
71
  parseExtendDeployment(astNode: ast.ExtendDeployment): import("../../ast").ParsedAstExtend | null;
72
- _resolveDeploymentRelationSource(node: ast.DeploymentRelation): c4;
72
+ _resolveDeploymentRelationSource(node: ast.DeploymentRelation): c4.FqnRef;
73
73
  parseDeploymentRelation(astNode: ast.DeploymentRelation): import("../../ast").ParsedAstDeploymentRelation;
74
74
  };
75
75
  } & TBase;
@@ -0,0 +1,86 @@
1
+ import * as c4 from '@likec4/core';
2
+ import { invariant, isNonEmptyArray, nonexhaustive } from '@likec4/core';
3
+ import { filter, isNonNullish, mapToObj, pipe } from 'remeda';
4
+ import { ast, parseMarkdownAsString, toAutoLayout, ViewOps } from '../../ast';
5
+ import { logWarnError } from '../../logger';
6
+ import { stringHash } from '../../utils';
7
+ import { parseViewManualLayout } from '../../view-utils/manual-layout';
8
+ import { removeIndent, toSingleLine } from './Base';
9
+ export function DeploymentViewParser(B) {
10
+ return class DeploymentViewParser extends B {
11
+ parseDeploymentView(astNode) {
12
+ const body = astNode.body;
13
+ invariant(body, 'DynamicElementView body is not defined');
14
+ // only valid props
15
+ const props = body.props.filter(this.isValid);
16
+ const astPath = this.getAstNodePath(astNode);
17
+ let id = astNode.name;
18
+ if (!id) {
19
+ id = 'deployment_' + stringHash(this.doc.uri.toString(), astPath);
20
+ }
21
+ const { title = null, description = null, } = this.parseBaseProps(pipe(props, filter(ast.isViewStringProperty), mapToObj(p => [p.key, p.value])));
22
+ const tags = this.convertTags(body);
23
+ const links = this.convertLinks(body);
24
+ ViewOps.writeId(astNode, id);
25
+ const manualLayout = parseViewManualLayout(astNode);
26
+ return {
27
+ [c4._type]: 'deployment',
28
+ id: id,
29
+ astPath,
30
+ title: toSingleLine(title) ?? null,
31
+ description,
32
+ tags,
33
+ links: isNonEmptyArray(links) ? links : null,
34
+ rules: body.rules.flatMap(n => {
35
+ try {
36
+ return this.isValid(n) ? this.parseDeploymentViewRule(n) : [];
37
+ }
38
+ catch (e) {
39
+ logWarnError(e);
40
+ return [];
41
+ }
42
+ }),
43
+ ...(manualLayout && { manualLayout }),
44
+ };
45
+ }
46
+ parseDeploymentViewRule(astRule) {
47
+ if (ast.isDeploymentViewRulePredicate(astRule)) {
48
+ return this.parseDeploymentViewRulePredicate(astRule);
49
+ }
50
+ if (ast.isViewRuleAutoLayout(astRule)) {
51
+ return toAutoLayout(astRule);
52
+ }
53
+ if (ast.isDeploymentViewRuleStyle(astRule)) {
54
+ return this.parseDeploymentViewRuleStyle(astRule);
55
+ }
56
+ nonexhaustive(astRule);
57
+ }
58
+ parseDeploymentViewRulePredicate(astRule) {
59
+ const exprs = [];
60
+ let iterator = astRule.expr;
61
+ while (iterator) {
62
+ try {
63
+ const expr = iterator.value;
64
+ if (isNonNullish(expr) && this.isValid(expr)) {
65
+ exprs.unshift(this.parseExpressionV2(expr));
66
+ }
67
+ }
68
+ catch (e) {
69
+ logWarnError(e);
70
+ }
71
+ iterator = iterator.prev;
72
+ }
73
+ return astRule.isInclude ? { include: exprs } : { exclude: exprs };
74
+ }
75
+ parseDeploymentViewRuleStyle(astRule) {
76
+ const style = this.parseStyleProps(astRule.props.filter(ast.isStyleProperty));
77
+ const notation = removeIndent(parseMarkdownAsString(astRule.props.find(ast.isNotationProperty)?.value));
78
+ const targets = this.parseFqnExpressions(astRule.targets);
79
+ return {
80
+ targets,
81
+ style,
82
+ ...(notation && { notation }),
83
+ };
84
+ }
85
+ };
86
+ }
@@ -28,14 +28,14 @@ export declare function ExpressionV2Parser<TBase extends Base>(B: TBase): {
28
28
  readonly doc: import("../../ast").ParsedLikeC4LangiumDocument;
29
29
  get project(): import("../../workspace").Project;
30
30
  resolveFqn(node: ast.FqnReferenceable): c4.Fqn;
31
- getAstNodePath(node: AstNode): any;
31
+ getAstNodePath(node: AstNode): string;
32
32
  getMetadata(metadataAstNode: ast.MetadataProperty | undefined): {
33
33
  [key: string]: string | string[];
34
34
  } | undefined;
35
35
  parseMarkdownOrString(markdownOrString: ast.MarkdownOrString | undefined): c4.MarkdownOrString | undefined;
36
36
  convertTags<E extends {
37
37
  tags?: ast.Tags;
38
- }>(withTags?: E | undefined): any;
38
+ }>(withTags?: E | undefined): c4.NonEmptyArray<c4.Tag<string>> | null;
39
39
  parseTags<E extends {
40
40
  tags?: ast.Tags;
41
41
  }>(withTags?: E): c4.NonEmptyArray<c4.Tag> | null;
@@ -0,0 +1,382 @@
1
+ import { invariant, nonexhaustive, nonNullable } from '@likec4/core';
2
+ import { loggable } from '@likec4/log';
3
+ import { AstUtils } from 'langium';
4
+ import { isBoolean, isDefined, isNonNullish, isTruthy } from 'remeda';
5
+ import { ast, parseAstOpacityProperty, parseAstSizeValue, parseMarkdownAsString, toColor } from '../../ast';
6
+ import { serverLogger } from '../../logger';
7
+ import { projectIdFrom } from '../../utils';
8
+ import { importsRef, instanceRef } from '../../utils/fqnRef';
9
+ import { createBinaryOperator, parseWhereClause } from '../model-parser-where';
10
+ import { removeIndent } from './Base';
11
+ const logger = serverLogger.getChild('ExpressionV2Parser');
12
+ const location = (astNode) => {
13
+ const cst = astNode.$cstNode;
14
+ const position = cst ? `:${cst.range.start.line + 1}:${cst.range.start.character + 1}` : '';
15
+ return `${AstUtils.getDocument(astNode).uri.fsPath}${position}`;
16
+ };
17
+ export function ExpressionV2Parser(B) {
18
+ return class ExpressionV2Parser extends B {
19
+ parseFqnRef(astNode) {
20
+ const refValue = nonNullable(astNode.value?.ref, () => `FqnRef "${astNode.$cstNode?.text}" is empty at ${location(astNode)}`);
21
+ if (ast.isImported(refValue)) {
22
+ const fqnRef = {
23
+ project: projectIdFrom(refValue),
24
+ model: this.resolveFqn(nonNullable(refValue.imported.ref, `FqnRef is empty of imported: ${refValue.$cstNode?.text}`)),
25
+ };
26
+ this.doc.c4Imports.set(fqnRef.project, fqnRef.model);
27
+ return fqnRef;
28
+ }
29
+ if (ast.isElement(refValue)) {
30
+ const imported = importsRef(astNode);
31
+ if (imported) {
32
+ const fqnRef = {
33
+ project: projectIdFrom(imported),
34
+ model: this.resolveFqn(refValue),
35
+ };
36
+ this.doc.c4Imports.set(fqnRef.project, fqnRef.model);
37
+ return fqnRef;
38
+ }
39
+ const deployedInstanceAst = instanceRef(astNode);
40
+ if (!deployedInstanceAst) {
41
+ return {
42
+ model: this.resolveFqn(refValue),
43
+ };
44
+ }
45
+ const deployment = this.resolveFqn(deployedInstanceAst);
46
+ const element = this.resolveFqn(refValue);
47
+ return {
48
+ deployment,
49
+ element,
50
+ };
51
+ }
52
+ if (ast.isDeploymentElement(refValue)) {
53
+ return {
54
+ deployment: this.resolveFqn(refValue),
55
+ };
56
+ }
57
+ nonexhaustive(refValue);
58
+ }
59
+ parseExpressionV2(astNode) {
60
+ if (ast.isFqnExprOrWith(astNode)) {
61
+ return this.parseFqnExprOrWith(astNode);
62
+ }
63
+ if (ast.isRelationExprOrWith(astNode)) {
64
+ return this.parseRelationExprOrWith(astNode);
65
+ }
66
+ nonexhaustive(astNode);
67
+ }
68
+ parseFqnExprOrWith(astNode) {
69
+ if (ast.isFqnExprWith(astNode)) {
70
+ return this.parseFqnExprWith(astNode);
71
+ }
72
+ if (ast.isFqnExprOrWhere(astNode)) {
73
+ return this.parseFqnExprOrWhere(astNode);
74
+ }
75
+ nonexhaustive(astNode);
76
+ }
77
+ parseFqnExprWith(astNode) {
78
+ const expr = this.parseFqnExprOrWhere(astNode.subject);
79
+ const props = astNode.custom?.props ?? [];
80
+ return props.reduce((acc, prop) => {
81
+ if (!this.isValid(prop)) {
82
+ return acc;
83
+ }
84
+ if (ast.isNavigateToProperty(prop)) {
85
+ const viewId = prop.value.view.$refText;
86
+ if (isTruthy(viewId)) {
87
+ acc.custom.navigateTo = viewId;
88
+ }
89
+ return acc;
90
+ }
91
+ if (ast.isElementStringProperty(prop)) {
92
+ if (isDefined(prop.value) && prop.key !== 'summary') {
93
+ if (prop.key === 'description') {
94
+ const parsed = this.parseMarkdownOrString(prop.value);
95
+ if (parsed) {
96
+ acc.custom['description'] = parsed;
97
+ }
98
+ }
99
+ else {
100
+ acc.custom[prop.key] = removeIndent(parseMarkdownAsString(prop.value)) || '';
101
+ }
102
+ }
103
+ return acc;
104
+ }
105
+ if (ast.isIconProperty(prop)) {
106
+ const value = this.parseIconProperty(prop);
107
+ if (isDefined(value)) {
108
+ acc.custom[prop.key] = value;
109
+ }
110
+ return acc;
111
+ }
112
+ if (ast.isColorProperty(prop)) {
113
+ const value = toColor(prop);
114
+ if (isDefined(value)) {
115
+ acc.custom[prop.key] = value;
116
+ }
117
+ return acc;
118
+ }
119
+ if (ast.isShapeProperty(prop)) {
120
+ if (isDefined(prop.value)) {
121
+ acc.custom[prop.key] = prop.value;
122
+ }
123
+ return acc;
124
+ }
125
+ if (ast.isBorderProperty(prop)) {
126
+ if (isDefined(prop.value)) {
127
+ acc.custom[prop.key] = prop.value;
128
+ }
129
+ return acc;
130
+ }
131
+ if (ast.isOpacityProperty(prop)) {
132
+ if (isDefined(prop.value)) {
133
+ acc.custom[prop.key] = parseAstOpacityProperty(prop);
134
+ }
135
+ return acc;
136
+ }
137
+ if (ast.isNotationProperty(prop)) {
138
+ const value = isTruthy(prop.value) ? removeIndent(parseMarkdownAsString(prop.value)) : undefined;
139
+ if (value) {
140
+ acc.custom[prop.key] = value;
141
+ }
142
+ return acc;
143
+ }
144
+ if (ast.isMultipleProperty(prop)) {
145
+ if (isBoolean(prop.value)) {
146
+ acc.custom[prop.key] = prop.value;
147
+ }
148
+ return acc;
149
+ }
150
+ if (ast.isShapeSizeProperty(prop)) {
151
+ if (isTruthy(prop.value)) {
152
+ acc.custom[prop.key] = parseAstSizeValue(prop);
153
+ }
154
+ return acc;
155
+ }
156
+ if (ast.isTextSizeProperty(prop)) {
157
+ if (isTruthy(prop.value)) {
158
+ acc.custom[prop.key] = parseAstSizeValue(prop);
159
+ }
160
+ return acc;
161
+ }
162
+ if (ast.isPaddingSizeProperty(prop)) {
163
+ if (isTruthy(prop.value)) {
164
+ acc.custom[prop.key] = parseAstSizeValue(prop);
165
+ }
166
+ return acc;
167
+ }
168
+ nonexhaustive(prop);
169
+ }, {
170
+ custom: {
171
+ expr,
172
+ },
173
+ });
174
+ }
175
+ parseFqnExprOrWhere(astNode) {
176
+ if (ast.isFqnExprWhere(astNode)) {
177
+ return this.parseFqnExprWhere(astNode);
178
+ }
179
+ if (ast.isFqnExpr(astNode)) {
180
+ return this.parseFqnExpr(astNode);
181
+ }
182
+ nonexhaustive(astNode);
183
+ }
184
+ parseFqnExprWhere(astNode) {
185
+ invariant(!ast.isFqnExprWhere(astNode.subject), 'FqnExprWhere is not allowed as subject of FqnExprWhere');
186
+ return {
187
+ where: {
188
+ expr: this.parseFqnExpr(astNode.subject),
189
+ condition: astNode.where ? parseWhereClause(astNode.where) : {
190
+ kind: { neq: '--always-true--' },
191
+ },
192
+ },
193
+ };
194
+ }
195
+ parseFqnExpr(astNode) {
196
+ if (ast.isWildcardExpression(astNode)) {
197
+ return {
198
+ wildcard: true,
199
+ };
200
+ }
201
+ if (ast.isElementKindExpression(astNode)) {
202
+ invariant(astNode.kind?.ref, 'ElementKindExpr kind is not resolved: ' + astNode.$cstNode?.text);
203
+ return {
204
+ elementKind: astNode.kind.ref.name,
205
+ isEqual: astNode.isEqual,
206
+ };
207
+ }
208
+ if (ast.isElementTagExpression(astNode)) {
209
+ invariant(astNode.tag.tag.ref, 'ElementTagExpr tag is not resolved: ' + astNode.$cstNode?.text);
210
+ let elementTag = astNode.tag.tag.$refText;
211
+ return {
212
+ elementTag: elementTag,
213
+ isEqual: astNode.isEqual,
214
+ };
215
+ }
216
+ if (ast.isFqnRefExpr(astNode)) {
217
+ return this.parseFqnRefExpr(astNode);
218
+ }
219
+ nonexhaustive(astNode);
220
+ }
221
+ parseFqnRefExpr(astNode) {
222
+ const ref = this.parseFqnRef(astNode.ref);
223
+ switch (true) {
224
+ case astNode.selector === '._':
225
+ return {
226
+ ref,
227
+ selector: 'expanded',
228
+ };
229
+ case astNode.selector === '.**':
230
+ return {
231
+ ref,
232
+ selector: 'descendants',
233
+ };
234
+ case astNode.selector === '.*':
235
+ return {
236
+ ref,
237
+ selector: 'children',
238
+ };
239
+ default:
240
+ return { ref };
241
+ }
242
+ }
243
+ parseFqnExpressions(astNode) {
244
+ const exprs = [];
245
+ let iter = astNode;
246
+ while (iter) {
247
+ try {
248
+ if (isNonNullish(iter.value) && this.isValid(iter.value)) {
249
+ exprs.push(this.parseFqnExpr(iter.value));
250
+ }
251
+ }
252
+ catch (e) {
253
+ logger.warn(loggable(e));
254
+ }
255
+ iter = iter.prev;
256
+ }
257
+ return exprs.reverse();
258
+ }
259
+ parseRelationExprOrWith(astNode) {
260
+ if (ast.isRelationExprWith(astNode)) {
261
+ return this.parseRelationExprWith(astNode);
262
+ }
263
+ if (ast.isRelationExprOrWhere(astNode)) {
264
+ return this.parseRelationExprOrWhere(astNode);
265
+ }
266
+ nonexhaustive(astNode);
267
+ }
268
+ parseRelationExprWith(astNode) {
269
+ const expr = this.parseRelationExprOrWhere(astNode.subject);
270
+ const customProps = this.parseCustomRelationProperties(astNode.custom);
271
+ return {
272
+ customRelation: {
273
+ ...customProps,
274
+ expr,
275
+ },
276
+ };
277
+ }
278
+ parseCustomRelationProperties(custom) {
279
+ const props = custom?.props ?? [];
280
+ return props.reduce((acc, prop) => {
281
+ if (ast.isRelationStringProperty(prop) || ast.isNotationProperty(prop) || ast.isNotesProperty(prop)) {
282
+ const value = isTruthy(prop.value) ? removeIndent(parseMarkdownAsString(prop.value)) : undefined;
283
+ if (value) {
284
+ acc[prop.key] = value;
285
+ }
286
+ return acc;
287
+ }
288
+ if (ast.isArrowProperty(prop)) {
289
+ if (isTruthy(prop.value)) {
290
+ acc[prop.key] = prop.value;
291
+ }
292
+ return acc;
293
+ }
294
+ if (ast.isColorProperty(prop)) {
295
+ const value = toColor(prop);
296
+ if (isTruthy(value)) {
297
+ acc[prop.key] = value;
298
+ }
299
+ return acc;
300
+ }
301
+ if (ast.isLineProperty(prop)) {
302
+ if (isTruthy(prop.value)) {
303
+ acc[prop.key] = prop.value;
304
+ }
305
+ return acc;
306
+ }
307
+ if (ast.isRelationNavigateToProperty(prop)) {
308
+ const viewId = prop.value.view.ref?.name;
309
+ if (isTruthy(viewId)) {
310
+ acc[prop.key] = viewId;
311
+ }
312
+ return acc;
313
+ }
314
+ nonexhaustive(prop);
315
+ }, {});
316
+ }
317
+ parseRelationExprOrWhere(astNode) {
318
+ if (ast.isRelationExprWhere(astNode)) {
319
+ return this.parseRelationExprWhere(astNode);
320
+ }
321
+ if (ast.isRelationExpr(astNode)) {
322
+ return this.parseRelationExpr(astNode);
323
+ }
324
+ nonexhaustive(astNode);
325
+ }
326
+ parseRelationExprWhere(astNode) {
327
+ invariant(!ast.isRelationExprWhere(astNode.subject), 'RelationExprWhere is not allowed as subject of RelationExprWhere');
328
+ const relationOrWhereExpr = this.parseRelationExpr(astNode.subject);
329
+ const expr = relationOrWhereExpr.where?.expr ?? relationOrWhereExpr;
330
+ const kindCondition = relationOrWhereExpr.where?.condition;
331
+ const whereCondition = astNode.where ? parseWhereClause(astNode.where) : null;
332
+ let condition;
333
+ if (whereCondition && kindCondition) {
334
+ condition = createBinaryOperator('and', kindCondition, whereCondition);
335
+ }
336
+ else {
337
+ condition = whereCondition
338
+ ?? kindCondition
339
+ ?? { kind: { neq: '--always-true--' } };
340
+ }
341
+ return {
342
+ where: {
343
+ expr: expr,
344
+ condition: condition,
345
+ },
346
+ };
347
+ }
348
+ parseRelationExpr(astNode) {
349
+ switch (astNode.$type) {
350
+ case 'DirectedRelationExpr':
351
+ return this.wrapInWhere({
352
+ source: this.parseFqnExpr(astNode.source.from),
353
+ target: this.parseFqnExpr(astNode.target),
354
+ isBidirectional: astNode.source.isBidirectional,
355
+ }, this.parseInlineKindCondition(astNode.source));
356
+ case 'InOutRelationExpr':
357
+ return {
358
+ inout: this.parseFqnExpr(astNode.inout.to),
359
+ };
360
+ case 'OutgoingRelationExpr':
361
+ return this.wrapInWhere({ outgoing: this.parseFqnExpr(astNode.from) }, this.parseInlineKindCondition(astNode));
362
+ case 'IncomingRelationExpr':
363
+ return {
364
+ incoming: this.parseFqnExpr(astNode.to),
365
+ };
366
+ default:
367
+ nonexhaustive(astNode);
368
+ }
369
+ }
370
+ parseInlineKindCondition(astNode) {
371
+ const kind = astNode.kind ?? astNode.dotKind?.kind;
372
+ if (kind) {
373
+ invariant(kind.ref, 'Kind is not resolved: ' + astNode.$cstNode?.text);
374
+ return { kind: { eq: kind.ref?.name } };
375
+ }
376
+ return null;
377
+ }
378
+ wrapInWhere(expr, condition) {
379
+ return condition ? { where: { expr, condition } } : expr;
380
+ }
381
+ };
382
+ }