@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
@@ -0,0 +1,67 @@
1
+ import { isAncestor } from '@likec4/core';
2
+ import { AstUtils } from 'langium';
3
+ import { isEmpty } from 'remeda';
4
+ import { ast } from '../ast';
5
+ import { elementRef } from '../utils/elementRef';
6
+ import { tryOrLog } from './_shared';
7
+ export const dynamicViewStepSingle = (services) => {
8
+ const fqnIndex = services.likec4.FqnIndex;
9
+ return tryOrLog((el, accept) => {
10
+ const sourceEl = elementRef(el.source);
11
+ const source = sourceEl && fqnIndex.getFqn(sourceEl);
12
+ if (!source) {
13
+ accept('error', 'Source not found (not parsed/indexed yet)', {
14
+ node: el,
15
+ property: 'source',
16
+ });
17
+ }
18
+ const targetEl = elementRef(el.target);
19
+ const target = targetEl && fqnIndex.getFqn(targetEl);
20
+ if (!target) {
21
+ accept('error', 'Target not found (not parsed/indexed yet)', {
22
+ node: el,
23
+ property: 'target',
24
+ });
25
+ }
26
+ if (source && target && (isAncestor(source, target) || isAncestor(target, source))) {
27
+ accept('error', 'Invalid parent-child relationship', {
28
+ node: el,
29
+ });
30
+ }
31
+ });
32
+ };
33
+ export const dynamicViewStepChain = (services) => {
34
+ const fqnIndex = services.likec4.FqnIndex;
35
+ return tryOrLog((el, accept) => {
36
+ const source = el.source;
37
+ if (ast.isDynamicStepSingle(source) && source.isBackward) {
38
+ accept('error', 'Invalid chain after backward step', {
39
+ node: el,
40
+ });
41
+ }
42
+ const targetEl = elementRef(el.target);
43
+ const target = targetEl && fqnIndex.getFqn(targetEl);
44
+ if (!target) {
45
+ accept('error', 'Target not found (not parsed/indexed yet)', {
46
+ node: el,
47
+ property: 'target',
48
+ });
49
+ }
50
+ });
51
+ };
52
+ export const dynamicViewDisplayVariant = (_services) => {
53
+ return tryOrLog((prop, accept) => {
54
+ if (isEmpty(prop.value) || (prop.value !== 'diagram' && prop.value !== 'sequence')) {
55
+ accept('error', 'Invalid display variant: "diagram" or "sequence" are allowed', {
56
+ node: prop,
57
+ property: 'value',
58
+ });
59
+ return;
60
+ }
61
+ if (!AstUtils.hasContainerOfType(prop, ast.isDynamicViewBody)) {
62
+ accept('error', `Display mode can be defined only inside dynamic view`, {
63
+ node: prop,
64
+ });
65
+ }
66
+ });
67
+ };
@@ -0,0 +1,12 @@
1
+ import { isReferenceToDeploymentModel } from '../utils';
2
+ import { tryOrLog } from './_shared';
3
+ export const checkElementRef = (_services) => {
4
+ return tryOrLog((el, accept) => {
5
+ if (isReferenceToDeploymentModel(el.modelElement)) {
6
+ accept('error', 'Only model elements allowed here', {
7
+ node: el,
8
+ property: 'modelElement',
9
+ });
10
+ }
11
+ });
12
+ };
@@ -0,0 +1,49 @@
1
+ import { AstUtils } from 'langium';
2
+ import { projectIdFrom } from '../utils';
3
+ import { RESERVED_WORDS, tryOrLog } from './_shared';
4
+ const { getDocument } = AstUtils;
5
+ export const checkElement = (services) => {
6
+ const fqnIndex = services.likec4.FqnIndex;
7
+ const locator = services.workspace.AstNodeLocator;
8
+ return tryOrLog((el, accept) => {
9
+ const fqn = fqnIndex.getFqn(el);
10
+ if (!fqn) {
11
+ accept('error', 'Not indexed element', {
12
+ node: el,
13
+ property: 'name',
14
+ });
15
+ return;
16
+ }
17
+ if (RESERVED_WORDS.includes(el.name)) {
18
+ accept('error', `Reserved word: ${el.name}`, {
19
+ node: el,
20
+ property: 'name',
21
+ });
22
+ }
23
+ const doc = getDocument(el);
24
+ const docUri = doc.uri;
25
+ const elPath = locator.getAstNodePath(el);
26
+ const withSameFqn = fqnIndex
27
+ .byFqn(projectIdFrom(doc), fqn)
28
+ .filter(v => v.documentUri !== docUri || v.path !== elPath)
29
+ .head();
30
+ if (withSameFqn) {
31
+ const isAnotherDoc = withSameFqn.documentUri !== docUri;
32
+ accept('error', `Duplicate element name ${el.name !== fqn ? el.name + ' (' + fqn + ')' : el.name}`, {
33
+ node: el,
34
+ property: 'name',
35
+ ...isAnotherDoc && {
36
+ relatedInformation: [
37
+ {
38
+ location: {
39
+ range: (withSameFqn.nameSegment?.range ?? withSameFqn.selectionSegment?.range),
40
+ uri: withSameFqn.documentUri.toString(),
41
+ },
42
+ message: `conflicting element`,
43
+ },
44
+ ],
45
+ },
46
+ });
47
+ }
48
+ });
49
+ };
@@ -0,0 +1,46 @@
1
+ import { AstUtils } from 'langium';
2
+ import { projectIdFrom } from '../utils';
3
+ import { tryOrLog } from './_shared';
4
+ const { getDocument } = AstUtils;
5
+ export const checkImportsFromPoject = (services) => {
6
+ const projects = services.shared.workspace.ProjectsManager;
7
+ return tryOrLog((el, accept) => {
8
+ const doc = getDocument(el);
9
+ const projectId = projectIdFrom(doc);
10
+ if (el.project === projectId) {
11
+ accept('error', 'Imported project cannot be the same as the current project', {
12
+ node: el,
13
+ property: 'project',
14
+ });
15
+ return;
16
+ }
17
+ if (!projects.all.includes(el.project)) {
18
+ accept('error', 'Imported project not found', {
19
+ node: el,
20
+ property: 'project',
21
+ });
22
+ return;
23
+ }
24
+ });
25
+ };
26
+ // export const checkImported = (services: LikeC4Services): ValidationCheck<ast.Imported> => {
27
+ // const fqnIndex = services.likec4.FqnIndex
28
+ // const projects = services.shared.workspace.ProjectsManager
29
+ // return tryOrLog((el, accept) => {
30
+ // const doc = getDocument(el)
31
+ // const importFromProject = el.$container.project as ProjectId
32
+ // if (importFromProject === projectId || !projects.all.includes(importFromProject)) {
33
+ // accept('error', 'Invalid import', {
34
+ // node: el,
35
+ // })
36
+ // return
37
+ // }
38
+ // const fqn = fqnIndex.byFqn(importFromProject, el.element.$refText as Fqn).head()
39
+ // if (!fqn) {
40
+ // accept('error', `Imported element not found in project "${importFromProject}"`, {
41
+ // node: el,
42
+ // })
43
+ // return
44
+ // }
45
+ // })
46
+ // }
@@ -4,7 +4,7 @@ import type { LikeC4Services } from '../module';
4
4
  export { LikeC4DocumentValidator } from './DocumentValidator';
5
5
  type Guard<N extends AstNode> = (n: AstNode) => n is N;
6
6
  type Guarded<G> = G extends Guard<infer N> ? N : never;
7
- declare const isValidatableAstNode: (n: AstNode) => n is ast.DynamicViewDisplayVariantProperty | ast.LinkProperty | ast.ViewStringProperty | ast.ElementStringProperty | ast.ElementStyleProperty | ast.IconProperty | ast.MetadataBody | ast.RelationStringProperty | ast.MetadataAttribute | ast.NotationProperty | ast.NotesProperty | ast.SpecificationElementStringProperty | ast.SpecificationRelationshipStringProperty | ast.HexColor | ast.RGBAColor | ast.DeployedInstance | ast.DeploymentNode | ast.DeploymentViewRulePredicate | ast.DeploymentViewRuleStyle | ast.ViewRuleAutoLayout | ast.DynamicViewGlobalPredicateRef | ast.DynamicViewIncludePredicate | ast.ViewRuleGlobalStyle | ast.ViewRuleStyle | ast.DynamicStepChain | ast.DynamicStepSingle | ast.ElementKindExpression | ast.ElementTagExpression | ast.FqnRefExpr | ast.WildcardExpression | ast.FqnExprWhere | ast.FqnExprWith | ast.DirectedRelationExpr | ast.InOutRelationExpr | ast.IncomingRelationExpr | ast.OutgoingRelationExpr | ast.RelationExprWhere | ast.RelationExprWith | ast.Element | ast.ExtendDeployment | ast.ExtendElement | ast.Imported | ast.DeploymentView | ast.DynamicView | ast.ElementView | ast.ArrowProperty | ast.ColorProperty | ast.LineProperty | ast.PaddingSizeProperty | ast.ShapeSizeProperty | ast.TextSizeProperty | ast.BorderProperty | ast.MultipleProperty | ast.OpacityProperty | ast.ShapeProperty | ast.ViewRuleGlobalPredicateRef | ast.ViewRuleGroup | ast.ViewRulePredicate | ast.DynamicViewParallelSteps | ast.ElementRef | ast.SpecificationRelationshipKind | ast.GlobalStyle | ast.SpecificationColor | ast.NavigateToProperty | ast.DeploymentRelation | ast.Tags | ast.SpecificationDeploymentNodeKind | ast.GlobalDynamicPredicateGroup | ast.Relation | ast.SpecificationElementKind | ast.Globals | ast.GlobalPredicateGroup | ast.GlobalStyleGroup | ast.SpecificationTag | ast.ImportsFromPoject | ast.SpecificationRule;
7
+ declare const isValidatableAstNode: (n: AstNode) => n is ast.DynamicViewDisplayVariantProperty | ast.LinkProperty | ast.ViewStringProperty | ast.ElementStringProperty | ast.ElementStyleProperty | ast.IconProperty | ast.MetadataBody | ast.RelationStringProperty | ast.MetadataAttribute | ast.NotationProperty | ast.NotesProperty | ast.SpecificationElementStringProperty | ast.SpecificationRelationshipStringProperty | ast.HexColor | ast.RGBAColor | ast.DeployedInstance | ast.DeploymentNode | ast.DeploymentViewRulePredicate | ast.DeploymentViewRuleStyle | ast.ViewRuleAutoLayout | ast.DynamicViewGlobalPredicateRef | ast.DynamicViewIncludePredicate | ast.ViewRuleGlobalStyle | ast.ViewRuleStyle | ast.DynamicStepChain | ast.DynamicStepSingle | ast.ElementKindExpression | ast.ElementTagExpression | ast.FqnRefExpr | ast.WildcardExpression | ast.FqnExprWhere | ast.FqnExprWith | ast.DirectedRelationExpr | ast.InOutRelationExpr | ast.IncomingRelationExpr | ast.OutgoingRelationExpr | ast.RelationExprWhere | ast.RelationExprWith | ast.Element | ast.ExtendDeployment | ast.ExtendElement | ast.Imported | ast.DeploymentView | ast.DynamicView | ast.ElementView | ast.ArrowProperty | ast.ColorProperty | ast.LineProperty | ast.PaddingSizeProperty | ast.ShapeSizeProperty | ast.TextSizeProperty | ast.BorderProperty | ast.MultipleProperty | ast.OpacityProperty | ast.ShapeProperty | ast.ViewRuleGlobalPredicateRef | ast.ViewRuleGroup | ast.ViewRulePredicate | ast.DynamicViewParallelSteps | ast.SpecificationRelationshipKind | ast.SpecificationRule | ast.ElementRef | ast.DeploymentRelation | ast.Relation | ast.GlobalDynamicPredicateGroup | ast.Globals | ast.GlobalPredicateGroup | ast.GlobalStyle | ast.SpecificationDeploymentNodeKind | ast.SpecificationElementKind | ast.GlobalStyleGroup | ast.SpecificationColor | ast.NavigateToProperty | ast.Tags | ast.ImportsFromPoject | ast.SpecificationTag;
8
8
  type ValidatableAstNode = Guarded<typeof isValidatableAstNode>;
9
9
  export declare function checksFromDiagnostics(doc: LikeC4LangiumDocument): {
10
10
  isValid: (n: ValidatableAstNode) => boolean;
@@ -0,0 +1,157 @@
1
+ import { onNextTick } from '@likec4/core/utils';
2
+ import { loggable } from '@likec4/log';
3
+ import { DocumentState } from 'langium';
4
+ import { isNullish } from 'remeda';
5
+ import { DiagnosticSeverity } from 'vscode-languageserver-types';
6
+ import { ast } from '../ast';
7
+ import { logger } from '../logger';
8
+ import { deployedInstanceChecks, deploymentNodeChecks, deploymentRelationChecks, extendDeploymentChecks, } from './deployment-checks';
9
+ import { dynamicViewDisplayVariant, dynamicViewStepChain, dynamicViewStepSingle } from './dynamic-view';
10
+ import { checkElement } from './element';
11
+ import { checkElementRef } from './element-ref';
12
+ import { checkImportsFromPoject } from './imports';
13
+ import { colorLiteralRuleChecks, iconPropertyRuleChecks, notesPropertyRuleChecks, opacityPropertyRuleChecks, } from './property-checks';
14
+ import { checkRelationBody, relationChecks } from './relation';
15
+ import { checkDeploymentNodeKind, checkElementKind, checkGlobalPredicate, checkGlobals, checkGlobalStyleId, checkModel, checkRelationshipKind, checkSpecificationRule, checkTag, } from './specification';
16
+ import { viewChecks } from './view';
17
+ import { checkFqnExprWith, checkFqnRefExpr, checkIncomingRelationExpr, checkOutgoingRelationExpr, checkRelationExpr, checkRelationExprWith, } from './view-predicates';
18
+ export { LikeC4DocumentValidator } from './DocumentValidator';
19
+ function validatableAstNodeGuards(predicates) {
20
+ return (n) => predicates.some(p => p(n));
21
+ }
22
+ const isValidatableAstNode = validatableAstNodeGuards([
23
+ ast.isImportsFromPoject,
24
+ ast.isImported,
25
+ ast.isGlobals,
26
+ ast.isGlobalPredicateGroup,
27
+ ast.isGlobalDynamicPredicateGroup,
28
+ ast.isGlobalStyle,
29
+ ast.isGlobalStyleGroup,
30
+ ast.isFqnExprWith,
31
+ ast.isRelationExprWith,
32
+ ast.isFqnExpr,
33
+ ast.isRelationExpr,
34
+ ast.isDynamicViewParallelSteps,
35
+ ast.isDynamicStepChain,
36
+ ast.isDynamicStepSingle,
37
+ ast.isDeploymentViewRule,
38
+ ast.isDeploymentViewRulePredicate,
39
+ ast.isExpressionV2,
40
+ ast.isRelationExpr,
41
+ ast.isFqnRefExpr,
42
+ ast.isViewProperty,
43
+ ast.isStyleProperty,
44
+ ast.isTags,
45
+ ast.isViewRule,
46
+ ast.isDynamicViewRule,
47
+ ast.isLikeC4View,
48
+ ast.isViewRuleStyleOrGlobalRef,
49
+ ast.isDeployedInstance,
50
+ ast.isDeploymentNode,
51
+ ast.isDeploymentRelation,
52
+ ast.isRelationshipStyleProperty,
53
+ ast.isDynamicViewDisplayVariantProperty,
54
+ ast.isMetadataProperty,
55
+ ast.isRelation,
56
+ ast.isElementProperty,
57
+ ast.isStringProperty,
58
+ ast.isNavigateToProperty,
59
+ ast.isElement,
60
+ ast.isElementRef,
61
+ ast.isExtendElement,
62
+ ast.isExtendDeployment,
63
+ ast.isSpecificationElementKind,
64
+ ast.isSpecificationRelationshipKind,
65
+ ast.isSpecificationDeploymentNodeKind,
66
+ ast.isSpecificationTag,
67
+ ast.isSpecificationColor,
68
+ ast.isSpecificationRule,
69
+ ast.isColorLiteral,
70
+ ]);
71
+ const findInvalidContainer = (node) => {
72
+ let nd = node;
73
+ while (nd && !ast.isLikeC4Grammar(nd)) {
74
+ if (isValidatableAstNode(nd)) {
75
+ return nd;
76
+ }
77
+ nd = nd.$container;
78
+ }
79
+ return undefined;
80
+ };
81
+ export function checksFromDiagnostics(doc) {
82
+ const errors = doc.state >= DocumentState.Validated
83
+ ? (doc.diagnostics?.filter(d => d.severity === DiagnosticSeverity.Error) ?? [])
84
+ : [];
85
+ const invalidNodes = new WeakSet();
86
+ for (const { node } of errors) {
87
+ if (isNullish(node) || invalidNodes.has(node)) {
88
+ continue;
89
+ }
90
+ invalidNodes.add(node);
91
+ const container = findInvalidContainer(node);
92
+ if (container) {
93
+ invalidNodes.add(container);
94
+ }
95
+ }
96
+ const isValid = (n) => !invalidNodes.has(n);
97
+ return {
98
+ isValid,
99
+ invalidNodes,
100
+ };
101
+ }
102
+ export function registerValidationChecks(services) {
103
+ logger.debug('registerValidationChecks');
104
+ const registry = services.validation.ValidationRegistry;
105
+ registry.register({
106
+ DeployedInstance: deployedInstanceChecks(services),
107
+ DeploymentNodeKind: checkDeploymentNodeKind(services),
108
+ DeploymentNode: deploymentNodeChecks(services),
109
+ DeploymentRelation: deploymentRelationChecks(services),
110
+ ExtendDeployment: extendDeploymentChecks(services),
111
+ FqnRefExpr: checkFqnRefExpr(services),
112
+ RelationExpr: checkRelationExpr(services),
113
+ NotesProperty: notesPropertyRuleChecks(services),
114
+ OpacityProperty: opacityPropertyRuleChecks(services),
115
+ IconProperty: iconPropertyRuleChecks(services),
116
+ SpecificationRule: checkSpecificationRule(services),
117
+ Model: checkModel(services),
118
+ Globals: checkGlobals(services),
119
+ GlobalPredicateGroup: checkGlobalPredicate(services),
120
+ GlobalDynamicPredicateGroup: checkGlobalPredicate(services),
121
+ GlobalStyleId: checkGlobalStyleId(services),
122
+ DynamicStepSingle: dynamicViewStepSingle(services),
123
+ DynamicStepChain: dynamicViewStepChain(services),
124
+ LikeC4View: viewChecks(services),
125
+ Element: checkElement(services),
126
+ ElementRef: checkElementRef(services),
127
+ ElementKind: checkElementKind(services),
128
+ Relation: relationChecks(services),
129
+ RelationBody: checkRelationBody(services),
130
+ Tag: checkTag(services),
131
+ FqnExprWith: checkFqnExprWith(services),
132
+ RelationExprWith: checkRelationExprWith(services),
133
+ RelationshipKind: checkRelationshipKind(services),
134
+ IncomingRelationExpr: checkIncomingRelationExpr(services),
135
+ OutgoingRelationExpr: checkOutgoingRelationExpr(services),
136
+ ImportsFromPoject: checkImportsFromPoject(services),
137
+ // Imported: checkImported(services),
138
+ ColorLiteral: colorLiteralRuleChecks(services),
139
+ DynamicViewDisplayVariantProperty: dynamicViewDisplayVariant(services),
140
+ });
141
+ const connection = services.shared.lsp.Connection;
142
+ if (connection) {
143
+ // delay initialization
144
+ onNextTick(() => {
145
+ // workaround for bug in langium
146
+ services.shared.workspace.DocumentBuilder.onUpdate((_, deleted) => {
147
+ for (const uri of deleted) {
148
+ logger.debug(`clear diagnostics for deleted ${uri.path}`);
149
+ connection.sendDiagnostics({
150
+ uri: uri.toString(),
151
+ diagnostics: [],
152
+ }).catch(e => logger.error(loggable(e)));
153
+ }
154
+ });
155
+ });
156
+ }
157
+ }
@@ -0,0 +1,108 @@
1
+ import { nonexhaustive } from '@likec4/core';
2
+ import { AstUtils } from 'langium';
3
+ import { isNumber, isString } from 'remeda';
4
+ import { ast } from '../ast';
5
+ import { tryOrLog } from './_shared';
6
+ export const opacityPropertyRuleChecks = (_) => {
7
+ return tryOrLog((node, accept) => {
8
+ const opacity = parseFloat(node.value);
9
+ if (isNaN(opacity) || opacity < 0 || opacity > 100) {
10
+ accept('warning', `Value ignored, must be between 0% and 100%`, {
11
+ node,
12
+ property: 'value',
13
+ });
14
+ }
15
+ });
16
+ };
17
+ export const iconPropertyRuleChecks = (_) => {
18
+ return (node, accept) => {
19
+ const container = node.$container;
20
+ const anotherIcon = container.props.some(p => ast.isIconProperty(p) && p !== node);
21
+ if (anotherIcon) {
22
+ accept('error', `Icon must be defined once`, {
23
+ node,
24
+ });
25
+ }
26
+ if (ast.isElementStyleProperty(container) && ast.isElementBody(container.$container)
27
+ && container.$container.props.some(p => ast.isIconProperty(p))) {
28
+ accept('warning', `Redundant as icon defined on element`, {
29
+ node,
30
+ });
31
+ }
32
+ if (node.value?.startsWith('file://')) {
33
+ accept('error', `Icon URI must not start with file://`, {
34
+ node,
35
+ property: 'value',
36
+ });
37
+ }
38
+ };
39
+ };
40
+ export const notesPropertyRuleChecks = (_) => {
41
+ return (node, accept) => {
42
+ if (!AstUtils.hasContainerOfType(node, ast.isDynamicViewStep)) {
43
+ accept('error', `Notes can be defined only inside dynamic view`, {
44
+ node,
45
+ });
46
+ }
47
+ };
48
+ };
49
+ export const colorLiteralRuleChecks = (_) => {
50
+ return (node, accept) => {
51
+ if (node.$type === 'HexColor') {
52
+ if (node.hex === undefined || (isString(node.hex) && !node.hex.match(/^[a-fA-F0-9]+$/))) {
53
+ accept('error', `Invalid HEX`, {
54
+ node,
55
+ property: 'hex',
56
+ });
57
+ return;
58
+ }
59
+ const length = isNumber(node.hex) ? node.hex.toString().length : node.hex.length;
60
+ if (length !== 6 && length !== 3 && length !== 8) {
61
+ accept('error', `Invalid value "${node.$cstNode?.text}", must be 3, 6 or 8 characters long`, {
62
+ node,
63
+ property: 'hex',
64
+ });
65
+ }
66
+ return;
67
+ }
68
+ if (node.$type === 'RGBAColor') {
69
+ if (!isNumber(node.red) || node.red < 0 || node.red > 255) {
70
+ accept('error', `Invalid value, must be between 0 and 255`, {
71
+ node,
72
+ property: 'red',
73
+ });
74
+ }
75
+ if (!isNumber(node.green) || node.green < 0 || node.green > 255) {
76
+ accept('error', `Invalid value, must be between 0 and 255`, {
77
+ node,
78
+ property: 'green',
79
+ });
80
+ }
81
+ if (!isNumber(node.blue) || node.blue < 0 || node.blue > 255) {
82
+ accept('error', `Invalid value, must be between 0 and 255`, {
83
+ node,
84
+ property: 'blue',
85
+ });
86
+ }
87
+ if (isNumber(node.alpha)) {
88
+ if (node.alpha < 0 || node.alpha > 1) {
89
+ accept('error', `Invalid value, must be between 0 and 1`, {
90
+ node,
91
+ property: 'alpha',
92
+ });
93
+ }
94
+ }
95
+ if (isString(node.alpha)) {
96
+ const alpha = parseFloat(node.alpha);
97
+ if (alpha < 0 || alpha > 100) {
98
+ accept('error', `Invalid value, must be between 0% and 100%`, {
99
+ node,
100
+ property: 'alpha',
101
+ });
102
+ }
103
+ }
104
+ return;
105
+ }
106
+ nonexhaustive(node);
107
+ };
108
+ };
@@ -0,0 +1,55 @@
1
+ import { FqnRef, isSameHierarchy } from '@likec4/core';
2
+ import { AstUtils } from 'langium';
3
+ import { ast } from '../ast';
4
+ import { safeCall } from '../utils';
5
+ import { tryOrLog } from './_shared';
6
+ export const relationChecks = (services) => {
7
+ const modelParser = services.likec4.ModelParser;
8
+ return tryOrLog((el, accept) => {
9
+ const parser = modelParser.forDocument(AstUtils.getDocument(el));
10
+ const source = safeCall(() => parser._resolveRelationSource(el));
11
+ if (!source) {
12
+ accept('error', 'Source not resolved', {
13
+ node: el,
14
+ property: 'source',
15
+ });
16
+ return;
17
+ }
18
+ const target = safeCall(() => parser.parseFqnRef(el.target));
19
+ if (!target) {
20
+ accept('error', 'Target not resolved', {
21
+ node: el,
22
+ property: 'target',
23
+ });
24
+ return;
25
+ }
26
+ if (FqnRef.isImportRef(source)) {
27
+ if (FqnRef.isImportRef(target)) {
28
+ accept('warning', 'Relationship between imported elements may not be visible in origin projects', {
29
+ node: el,
30
+ });
31
+ }
32
+ else {
33
+ accept('warning', 'Relationship from imported element to local element may not be visible in origin project', {
34
+ node: el,
35
+ property: 'source',
36
+ });
37
+ }
38
+ }
39
+ if (isSameHierarchy(FqnRef.flatten(source), FqnRef.flatten(target))) {
40
+ accept('error', 'Invalid parent-child relationship', {
41
+ node: el,
42
+ });
43
+ }
44
+ });
45
+ };
46
+ export const checkRelationBody = (_services) => {
47
+ return tryOrLog((body, accept) => {
48
+ const relation = body.$container;
49
+ if (relation.tags?.values && body.tags?.values) {
50
+ accept('error', 'Relation cannot have tags in both header and body', {
51
+ node: body.tags,
52
+ });
53
+ }
54
+ });
55
+ };