@likec4/language-server 1.17.1 → 1.19.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 (268) hide show
  1. package/contrib/likec4.tmLanguage.json +1 -1
  2. package/dist/LikeC4FileSystem.d.ts +13 -0
  3. package/dist/LikeC4FileSystem.js +27 -0
  4. package/dist/Rpc.d.ts +9 -0
  5. package/dist/Rpc.js +126 -0
  6. package/dist/ast.d.ts +200 -0
  7. package/dist/ast.js +276 -0
  8. package/dist/browser.d.ts +6 -20
  9. package/dist/browser.js +13 -0
  10. package/dist/formatting/LikeC4Formatter.d.ts +27 -0
  11. package/dist/formatting/LikeC4Formatter.js +261 -0
  12. package/dist/formatting/utils.d.ts +6 -0
  13. package/dist/formatting/utils.js +15 -0
  14. package/dist/generated/ast.d.ts +1242 -0
  15. package/dist/generated/ast.js +1945 -0
  16. package/dist/generated/grammar.d.ts +6 -0
  17. package/dist/generated/grammar.js +3 -0
  18. package/dist/generated/module.d.ts +9 -0
  19. package/dist/generated/module.js +23 -0
  20. package/dist/generated-lib/icons.d.ts +1 -0
  21. package/dist/{likec4lib.mjs → generated-lib/icons.js} +1 -6
  22. package/dist/index.d.ts +8 -31
  23. package/dist/index.js +13 -0
  24. package/dist/like-c4.langium +845 -0
  25. package/dist/likec4lib.d.ts +4 -6
  26. package/dist/likec4lib.js +4 -0
  27. package/dist/logger.d.ts +7 -0
  28. package/dist/logger.js +73 -0
  29. package/dist/lsp/CodeLensProvider.d.ts +9 -0
  30. package/dist/lsp/CodeLensProvider.js +40 -0
  31. package/dist/lsp/CompletionProvider.d.ts +6 -0
  32. package/dist/lsp/CompletionProvider.js +135 -0
  33. package/dist/lsp/DocumentHighlightProvider.d.ts +9 -0
  34. package/dist/lsp/DocumentHighlightProvider.js +10 -0
  35. package/dist/lsp/DocumentLinkProvider.d.ts +11 -0
  36. package/dist/lsp/DocumentLinkProvider.js +49 -0
  37. package/dist/lsp/DocumentSymbolProvider.d.ts +23 -0
  38. package/dist/lsp/DocumentSymbolProvider.js +202 -0
  39. package/dist/lsp/HoverProvider.d.ts +10 -0
  40. package/dist/lsp/HoverProvider.js +69 -0
  41. package/dist/lsp/RenameProvider.d.ts +5 -0
  42. package/dist/lsp/RenameProvider.js +6 -0
  43. package/dist/lsp/SemanticTokenProvider.d.ts +7 -0
  44. package/dist/lsp/SemanticTokenProvider.js +297 -0
  45. package/dist/lsp/index.d.ts +7 -0
  46. package/dist/lsp/index.js +7 -0
  47. package/dist/model/deployments-index.d.ts +60 -0
  48. package/dist/model/deployments-index.js +181 -0
  49. package/dist/model/fqn-computation.d.ts +3 -0
  50. package/dist/model/fqn-computation.js +72 -0
  51. package/dist/model/fqn-index.d.ts +25 -0
  52. package/dist/model/fqn-index.js +96 -0
  53. package/dist/model/index.d.ts +6 -0
  54. package/dist/model/index.js +6 -0
  55. package/dist/model/model-builder.d.ts +32 -0
  56. package/dist/model/model-builder.js +598 -0
  57. package/dist/model/model-locator.d.ts +23 -0
  58. package/dist/model/model-locator.js +126 -0
  59. package/dist/model/model-parser-where.d.ts +3 -0
  60. package/dist/model/model-parser-where.js +70 -0
  61. package/dist/model/model-parser.d.ts +292 -0
  62. package/dist/model/model-parser.js +72 -0
  63. package/dist/model/parser/Base.d.ts +28 -0
  64. package/dist/model/parser/Base.js +87 -0
  65. package/dist/model/parser/DeploymentModelParser.d.ts +33 -0
  66. package/dist/model/parser/DeploymentModelParser.js +162 -0
  67. package/dist/model/parser/DeploymentViewParser.d.ts +38 -0
  68. package/dist/model/parser/DeploymentViewParser.js +98 -0
  69. package/dist/model/parser/FqnRefParser.d.ts +29 -0
  70. package/dist/model/parser/FqnRefParser.js +108 -0
  71. package/dist/model/parser/GlobalsParser.d.ts +66 -0
  72. package/dist/model/parser/GlobalsParser.js +80 -0
  73. package/dist/model/parser/ModelParser.d.ts +27 -0
  74. package/dist/model/parser/ModelParser.js +122 -0
  75. package/dist/model/parser/PredicatesParser.d.ts +34 -0
  76. package/dist/model/parser/PredicatesParser.js +272 -0
  77. package/dist/model/parser/SpecificationParser.d.ts +27 -0
  78. package/dist/model/parser/SpecificationParser.js +120 -0
  79. package/dist/model/parser/ViewsParser.d.ts +64 -0
  80. package/dist/model/parser/ViewsParser.js +377 -0
  81. package/dist/model-change/ModelChanges.d.ts +15 -0
  82. package/dist/model-change/ModelChanges.js +89 -0
  83. package/dist/model-change/changeElementStyle.d.ts +16 -0
  84. package/dist/model-change/changeElementStyle.js +136 -0
  85. package/dist/model-change/changeViewLayout.d.ts +12 -0
  86. package/dist/model-change/changeViewLayout.js +32 -0
  87. package/dist/model-change/saveManualLayout.d.ts +11 -0
  88. package/dist/model-change/saveManualLayout.js +27 -0
  89. package/dist/module.d.ts +62 -0
  90. package/dist/module.js +123 -0
  91. package/dist/protocol.d.ts +27 -27
  92. package/dist/protocol.js +14 -0
  93. package/dist/references/index.d.ts +3 -0
  94. package/dist/references/index.js +3 -0
  95. package/dist/references/name-provider.d.ts +9 -0
  96. package/dist/references/name-provider.js +33 -0
  97. package/dist/references/scope-computation.d.ts +20 -0
  98. package/dist/references/scope-computation.js +281 -0
  99. package/dist/references/scope-provider.d.ts +16 -0
  100. package/dist/references/scope-provider.js +165 -0
  101. package/dist/shared/NodeKindProvider.d.ts +15 -0
  102. package/dist/shared/NodeKindProvider.js +108 -0
  103. package/dist/shared/WorkspaceManager.d.ts +18 -0
  104. package/dist/shared/WorkspaceManager.js +36 -0
  105. package/dist/shared/WorkspaceSymbolProvider.d.ts +3 -0
  106. package/dist/shared/WorkspaceSymbolProvider.js +3 -0
  107. package/dist/shared/index.d.ts +3 -0
  108. package/dist/shared/index.js +3 -0
  109. package/dist/test/index.d.ts +1 -0
  110. package/dist/test/index.js +1 -0
  111. package/dist/test/setup.d.ts +1 -0
  112. package/dist/test/setup.js +7 -0
  113. package/dist/test/testServices.d.ts +22 -0
  114. package/dist/test/testServices.js +119 -0
  115. package/dist/utils/elementRef.d.ts +11 -0
  116. package/dist/utils/elementRef.js +15 -0
  117. package/dist/utils/fqnRef.d.ts +8 -0
  118. package/dist/utils/fqnRef.js +46 -0
  119. package/dist/utils/index.d.ts +1 -0
  120. package/dist/utils/index.js +1 -0
  121. package/dist/utils/printDocs.d.ts +2 -0
  122. package/dist/utils/printDocs.js +1 -0
  123. package/dist/utils/stringHash.d.ts +1 -0
  124. package/dist/utils/stringHash.js +5 -0
  125. package/dist/validation/_shared.d.ts +3 -0
  126. package/dist/validation/_shared.js +22 -0
  127. package/dist/validation/deployment-checks.d.ts +6 -0
  128. package/dist/validation/deployment-checks.js +114 -0
  129. package/dist/validation/dynamic-view-rule.d.ts +4 -0
  130. package/dist/validation/dynamic-view-rule.js +16 -0
  131. package/dist/validation/dynamic-view-step.d.ts +4 -0
  132. package/dist/validation/dynamic-view-step.js +33 -0
  133. package/dist/validation/element.d.ts +4 -0
  134. package/dist/validation/element.js +49 -0
  135. package/dist/validation/index.d.ts +15 -0
  136. package/dist/validation/index.js +152 -0
  137. package/dist/validation/property-checks.d.ts +6 -0
  138. package/dist/validation/property-checks.js +38 -0
  139. package/dist/validation/relation.d.ts +5 -0
  140. package/dist/validation/relation.js +56 -0
  141. package/dist/validation/specification.d.ts +11 -0
  142. package/dist/validation/specification.js +136 -0
  143. package/dist/validation/view-predicates/element-with.d.ts +4 -0
  144. package/dist/validation/view-predicates/element-with.js +30 -0
  145. package/dist/validation/view-predicates/expanded-element.d.ts +4 -0
  146. package/dist/validation/view-predicates/expanded-element.js +11 -0
  147. package/dist/validation/view-predicates/expression-v2.d.ts +5 -0
  148. package/dist/validation/view-predicates/expression-v2.js +83 -0
  149. package/dist/validation/view-predicates/incoming.d.ts +4 -0
  150. package/dist/validation/view-predicates/incoming.js +15 -0
  151. package/dist/validation/view-predicates/index.d.ts +6 -0
  152. package/dist/validation/view-predicates/index.js +6 -0
  153. package/dist/validation/view-predicates/outgoing.d.ts +4 -0
  154. package/dist/validation/view-predicates/outgoing.js +15 -0
  155. package/dist/validation/view-predicates/relation-with.d.ts +4 -0
  156. package/dist/validation/view-predicates/relation-with.js +12 -0
  157. package/dist/validation/view.d.ts +4 -0
  158. package/dist/validation/view.js +23 -0
  159. package/dist/view-utils/assignNavigateTo.d.ts +2 -0
  160. package/dist/view-utils/assignNavigateTo.js +25 -0
  161. package/dist/view-utils/index.d.ts +2 -0
  162. package/dist/view-utils/index.js +2 -0
  163. package/dist/view-utils/manual-layout.d.ts +7 -0
  164. package/dist/view-utils/manual-layout.js +99 -0
  165. package/dist/view-utils/resolve-relative-paths.d.ts +2 -0
  166. package/dist/view-utils/resolve-relative-paths.js +78 -0
  167. package/package.json +42 -73
  168. package/src/LikeC4FileSystem.ts +22 -21
  169. package/src/Rpc.ts +6 -3
  170. package/src/ast.ts +136 -172
  171. package/src/browser.ts +10 -11
  172. package/src/generated/ast.ts +656 -40
  173. package/src/generated/grammar.ts +1 -1
  174. package/src/index.ts +11 -8
  175. package/src/like-c4.langium +173 -22
  176. package/src/logger.ts +41 -57
  177. package/src/lsp/CodeLensProvider.ts +0 -1
  178. package/src/lsp/CompletionProvider.ts +20 -5
  179. package/src/lsp/DocumentSymbolProvider.ts +5 -2
  180. package/src/lsp/HoverProvider.ts +37 -3
  181. package/src/lsp/SemanticTokenProvider.ts +58 -32
  182. package/src/model/deployments-index.ts +222 -0
  183. package/src/model/fqn-computation.ts +1 -1
  184. package/src/model/fqn-index.ts +0 -1
  185. package/src/model/index.ts +1 -0
  186. package/src/model/model-builder.ts +176 -39
  187. package/src/model/model-locator.ts +36 -7
  188. package/src/model/model-parser.ts +69 -1119
  189. package/src/model/parser/Base.ts +107 -0
  190. package/src/model/parser/DeploymentModelParser.ts +192 -0
  191. package/src/model/parser/DeploymentViewParser.ts +116 -0
  192. package/src/model/parser/FqnRefParser.ts +118 -0
  193. package/src/model/parser/GlobalsParser.ts +96 -0
  194. package/src/model/parser/ModelParser.ts +141 -0
  195. package/src/model/parser/PredicatesParser.ts +291 -0
  196. package/src/model/parser/SpecificationParser.ts +133 -0
  197. package/src/model/parser/ViewsParser.ts +428 -0
  198. package/src/model-change/changeViewLayout.ts +2 -2
  199. package/src/module.ts +26 -21
  200. package/src/protocol.ts +10 -6
  201. package/src/references/index.ts +1 -0
  202. package/src/references/name-provider.ts +37 -0
  203. package/src/references/scope-computation.ts +130 -21
  204. package/src/references/scope-provider.ts +68 -35
  205. package/src/shared/NodeKindProvider.ts +15 -3
  206. package/src/{elementRef.ts → utils/elementRef.ts} +1 -1
  207. package/src/utils/fqnRef.ts +56 -0
  208. package/src/utils/stringHash.ts +2 -2
  209. package/src/validation/_shared.ts +6 -5
  210. package/src/validation/deployment-checks.ts +131 -0
  211. package/src/validation/dynamic-view-step.ts +1 -1
  212. package/src/validation/index.ts +104 -6
  213. package/src/validation/relation.ts +1 -1
  214. package/src/validation/view-predicates/expression-v2.ts +101 -0
  215. package/src/validation/view-predicates/index.ts +1 -0
  216. package/src/view-utils/assignNavigateTo.ts +6 -5
  217. package/src/view-utils/index.ts +0 -1
  218. package/src/view-utils/manual-layout.ts +25 -0
  219. package/dist/browser.cjs +0 -25
  220. package/dist/browser.d.cts +0 -23
  221. package/dist/browser.d.mts +0 -23
  222. package/dist/browser.mjs +0 -20
  223. package/dist/index.cjs +0 -53
  224. package/dist/index.d.cts +0 -34
  225. package/dist/index.d.mts +0 -34
  226. package/dist/index.mjs +0 -46
  227. package/dist/likec4lib.cjs +0 -1546
  228. package/dist/likec4lib.d.cts +0 -6
  229. package/dist/likec4lib.d.mts +0 -6
  230. package/dist/model-graph/index.cjs +0 -10
  231. package/dist/model-graph/index.d.cts +0 -81
  232. package/dist/model-graph/index.d.mts +0 -81
  233. package/dist/model-graph/index.d.ts +0 -81
  234. package/dist/model-graph/index.mjs +0 -1
  235. package/dist/protocol.cjs +0 -25
  236. package/dist/protocol.d.cts +0 -45
  237. package/dist/protocol.d.mts +0 -45
  238. package/dist/protocol.mjs +0 -17
  239. package/dist/shared/language-server.BIbAD1T-.mjs +0 -6292
  240. package/dist/shared/language-server.BQRvVmE0.d.cts +0 -1303
  241. package/dist/shared/language-server.BysPcTxr.d.ts +0 -1303
  242. package/dist/shared/language-server.D2QdbOJO.cjs +0 -1995
  243. package/dist/shared/language-server.DGrBGmsd.mjs +0 -1981
  244. package/dist/shared/language-server.DKV_FdPN.cjs +0 -6304
  245. package/dist/shared/language-server._wkyPgso.d.mts +0 -1303
  246. package/src/model-graph/LikeC4ModelGraph.ts +0 -338
  247. package/src/model-graph/compute-view/__test__/fixture.ts +0 -630
  248. package/src/model-graph/compute-view/compute.ts +0 -788
  249. package/src/model-graph/compute-view/index.ts +0 -33
  250. package/src/model-graph/compute-view/predicates.ts +0 -509
  251. package/src/model-graph/dynamic-view/__test__/fixture.ts +0 -61
  252. package/src/model-graph/dynamic-view/compute.ts +0 -313
  253. package/src/model-graph/dynamic-view/index.ts +0 -29
  254. package/src/model-graph/index.ts +0 -3
  255. package/src/model-graph/utils/applyCustomElementProperties.ts +0 -65
  256. package/src/model-graph/utils/applyCustomRelationProperties.ts +0 -41
  257. package/src/model-graph/utils/applyViewRuleStyles.ts +0 -49
  258. package/src/model-graph/utils/buildComputeNodes.ts +0 -113
  259. package/src/model-graph/utils/buildElementNotations.ts +0 -63
  260. package/src/model-graph/utils/elementExpressionToPredicate.ts +0 -39
  261. package/src/model-graph/utils/relationExpressionToPredicates.ts +0 -43
  262. package/src/model-graph/utils/sortNodes.ts +0 -105
  263. package/src/model-graph/utils/uniqueTags.test.ts +0 -42
  264. package/src/model-graph/utils/uniqueTags.ts +0 -19
  265. package/src/utils/graphlib.ts +0 -9
  266. package/src/view-utils/resolve-extended-views.ts +0 -66
  267. package/src/view-utils/resolve-global-rules.ts +0 -88
  268. package/src/view-utils/view-hash.ts +0 -27
@@ -1,6 +1,4 @@
1
- declare const LibIcons: string;
2
-
3
- declare const Scheme = "likec4builtin";
4
- declare const Uri: "likec4builtin:///likec4/lib/icons.c4";
5
-
6
- export { LibIcons as Content, Scheme, Uri };
1
+ import { LibIcons } from './generated-lib/icons';
2
+ export declare const Scheme = "likec4builtin";
3
+ export declare const Uri: "likec4builtin:///likec4/lib/icons.c4";
4
+ export { LibIcons as Content };
@@ -0,0 +1,4 @@
1
+ import { LibIcons } from "./generated-lib/icons.js";
2
+ export const Scheme = "likec4builtin";
3
+ export const Uri = `${Scheme}:///likec4/lib/icons.c4`;
4
+ export { LibIcons as Content };
@@ -0,0 +1,7 @@
1
+ import { LogLevels } from '@likec4/log';
2
+ import type { Connection } from 'vscode-languageserver';
3
+ export declare const logger: any;
4
+ export declare function logError(err: unknown): void;
5
+ export declare function logWarnError(err: unknown): void;
6
+ export declare function setLogLevel(level: keyof typeof LogLevels): void;
7
+ export declare function logToLspConnection(connection: Connection): void;
package/dist/logger.js ADDED
@@ -0,0 +1,73 @@
1
+ import { nonexhaustive } from "@likec4/core";
2
+ import { formatLogObj, LogLevels, rootLogger as root } from "@likec4/log";
3
+ import { BROWSER } from "esm-env";
4
+ export const logger = root.withTag("lsp");
5
+ export function logError(err) {
6
+ logger.error(err);
7
+ }
8
+ export function logWarnError(err) {
9
+ if (err instanceof Error) {
10
+ logger.warn(err.stack ?? err.message);
11
+ return;
12
+ }
13
+ logger.warn(err);
14
+ }
15
+ export function setLogLevel(level) {
16
+ logger.level = LogLevels[level];
17
+ }
18
+ export function logToLspConnection(connection) {
19
+ const reporter = {
20
+ log: (logObj, _ctx) => {
21
+ const { message, error } = formatLogObj(logObj);
22
+ switch (logObj.type) {
23
+ case "silent": {
24
+ break;
25
+ }
26
+ case "verbose":
27
+ case "trace": {
28
+ connection.tracer.log(message);
29
+ break;
30
+ }
31
+ case "debug": {
32
+ connection.console.debug(message);
33
+ break;
34
+ }
35
+ case "log": {
36
+ connection.console.log(message);
37
+ break;
38
+ }
39
+ case "info":
40
+ case "box":
41
+ case "ready":
42
+ case "start":
43
+ case "success": {
44
+ connection.console.info(message);
45
+ break;
46
+ }
47
+ case "warn": {
48
+ connection.console.warn(message);
49
+ break;
50
+ }
51
+ case "fail":
52
+ case "error":
53
+ case "fatal": {
54
+ connection.console.error(message);
55
+ if (error) {
56
+ connection.telemetry.logEvent({ eventName: "error", ...error });
57
+ } else {
58
+ connection.telemetry.logEvent({ eventName: "error", message });
59
+ }
60
+ break;
61
+ }
62
+ default:
63
+ nonexhaustive(logObj.type);
64
+ }
65
+ }
66
+ };
67
+ if (BROWSER) {
68
+ root.addReporter(reporter);
69
+ } else {
70
+ root.setReporters([reporter]);
71
+ }
72
+ logger.setReporters(root.options.reporters);
73
+ }
@@ -0,0 +1,9 @@
1
+ import { type LangiumDocument } from 'langium';
2
+ import type { CodeLensProvider } from 'langium/lsp';
3
+ import type { CancellationToken, CodeLens, CodeLensParams } from 'vscode-languageserver';
4
+ import type { LikeC4Services } from '../module';
5
+ export declare class LikeC4CodeLensProvider implements CodeLensProvider {
6
+ private services;
7
+ constructor(services: LikeC4Services);
8
+ provideCodeLens(doc: LangiumDocument, _params: CodeLensParams, cancelToken?: CancellationToken): Promise<CodeLens[] | undefined>;
9
+ }
@@ -0,0 +1,40 @@
1
+ import { DocumentState } from "langium";
2
+ import { isParsedLikeC4LangiumDocument, ViewOps } from "../ast.js";
3
+ import { logger } from "../logger.js";
4
+ export class LikeC4CodeLensProvider {
5
+ constructor(services) {
6
+ this.services = services;
7
+ }
8
+ async provideCodeLens(doc, _params, cancelToken) {
9
+ if (doc.state !== DocumentState.Validated) {
10
+ logger.debug(`Waiting for document ${doc.uri.path} to be validated`);
11
+ await this.services.shared.workspace.DocumentBuilder.waitUntil(DocumentState.Validated, doc.uri, cancelToken);
12
+ logger.debug(`Document ${doc.uri.path} is validated`);
13
+ }
14
+ if (!isParsedLikeC4LangiumDocument(doc)) {
15
+ return;
16
+ }
17
+ const views = doc.parseResult.value.views.flatMap((v) => v.views);
18
+ return views.flatMap((ast) => {
19
+ const viewId = ViewOps.readId(ast);
20
+ const range = ast.$cstNode?.range;
21
+ if (!range || !viewId) {
22
+ return [];
23
+ }
24
+ return {
25
+ range: {
26
+ start: range.start,
27
+ end: {
28
+ line: range.start.line,
29
+ character: range.start.character + 4
30
+ }
31
+ },
32
+ command: {
33
+ command: "likec4.open-preview",
34
+ arguments: [viewId],
35
+ title: "open preview"
36
+ }
37
+ };
38
+ });
39
+ }
40
+ }
@@ -0,0 +1,6 @@
1
+ import { type GrammarAST, type MaybePromise } from 'langium';
2
+ import { type CompletionAcceptor, type CompletionContext, DefaultCompletionProvider } from 'langium/lsp';
3
+ export declare class LikeC4CompletionProvider extends DefaultCompletionProvider {
4
+ readonly completionOptions: CompletionProviderOptions;
5
+ protected completionForKeyword(context: CompletionContext, keyword: GrammarAST.Keyword, acceptor: CompletionAcceptor): MaybePromise<void>;
6
+ }
@@ -0,0 +1,135 @@
1
+ import { AstUtils } from "langium";
2
+ import {
3
+ DefaultCompletionProvider
4
+ } from "langium/lsp";
5
+ import { anyPass } from "remeda";
6
+ import { CompletionItemKind, InsertTextFormat } from "vscode-languageserver-types";
7
+ import { ast } from "../ast.js";
8
+ export class LikeC4CompletionProvider extends DefaultCompletionProvider {
9
+ completionOptions = {
10
+ triggerCharacters: ["."]
11
+ };
12
+ completionForKeyword(context, keyword, acceptor) {
13
+ if (!this.filterKeyword(context, keyword)) {
14
+ return;
15
+ }
16
+ if (keyword.value === "deployment" && AstUtils.hasContainerOfType(context.node, ast.isModelViews)) {
17
+ return acceptor(context, {
18
+ label: keyword.value,
19
+ detail: `Insert deployment view`,
20
+ kind: CompletionItemKind.Class,
21
+ insertTextFormat: InsertTextFormat.Snippet,
22
+ insertText: [
23
+ "deployment view ${1:view_${TM_FILENAME_BASE}_${CURRENT_SECOND}} {",
24
+ " title '${2:Untitled}'",
25
+ " ",
26
+ " include $0",
27
+ "}"
28
+ ].join("\n")
29
+ });
30
+ }
31
+ if (["title", "description", "technology"].includes(keyword.value)) {
32
+ return acceptor(context, {
33
+ label: keyword.value,
34
+ kind: CompletionItemKind.Property,
35
+ insertTextFormat: InsertTextFormat.Snippet,
36
+ insertText: `${keyword.value} '\${0}'`
37
+ });
38
+ }
39
+ if (["views", "specification", "model", "deployment", "with"].includes(keyword.value)) {
40
+ return acceptor(context, {
41
+ label: keyword.value,
42
+ detail: `Insert ${keyword.value} block`,
43
+ kind: CompletionItemKind.Module,
44
+ insertTextFormat: InsertTextFormat.Snippet,
45
+ insertText: `${keyword.value} {
46
+ $0
47
+ }`
48
+ });
49
+ }
50
+ if (keyword.value === "group") {
51
+ return acceptor(context, {
52
+ label: keyword.value,
53
+ detail: `Insert group block`,
54
+ kind: CompletionItemKind.Class,
55
+ insertTextFormat: InsertTextFormat.Snippet,
56
+ insertText: [
57
+ "group '${1:Title}' {",
58
+ " $0",
59
+ "}"
60
+ ].join("\n")
61
+ });
62
+ }
63
+ if (keyword.value === "dynamic" && AstUtils.hasContainerOfType(context.node, ast.isModelViews)) {
64
+ return acceptor(context, {
65
+ label: keyword.value,
66
+ detail: `Insert dynamic view`,
67
+ kind: CompletionItemKind.Class,
68
+ insertTextFormat: InsertTextFormat.Snippet,
69
+ insertText: [
70
+ "dynamic view ${1:view_${TM_FILENAME_BASE}_${CURRENT_SECOND}} {",
71
+ " title '${2:Untitled}'",
72
+ " ",
73
+ " $0",
74
+ "}"
75
+ ].join("\n")
76
+ });
77
+ }
78
+ if (keyword.value === "style" && context.node) {
79
+ if (AstUtils.hasContainerOfType(context.node, ast.isGlobalStyle)) {
80
+ return acceptor(context, {
81
+ label: keyword.value,
82
+ detail: `Insert ${keyword.value} block`,
83
+ kind: CompletionItemKind.Module,
84
+ insertTextFormat: InsertTextFormat.Snippet,
85
+ insertText: `${keyword.value} \${1:name} \${2:*} {
86
+ \${3|color,shape,border,opacity,icon|} $0
87
+ }`
88
+ });
89
+ }
90
+ if (AstUtils.hasContainerOfType(context.node, anyPass([ast.isModelViews, ast.isGlobalStyleGroup]))) {
91
+ return acceptor(context, {
92
+ label: keyword.value,
93
+ detail: `Insert ${keyword.value} block`,
94
+ kind: CompletionItemKind.Module,
95
+ insertTextFormat: InsertTextFormat.Snippet,
96
+ insertText: `${keyword.value} \${1:*} {
97
+ \${2|color,shape,border,opacity,icon|} $0
98
+ }`
99
+ });
100
+ }
101
+ return acceptor(context, {
102
+ label: keyword.value,
103
+ detail: `Insert ${keyword.value} block`,
104
+ kind: CompletionItemKind.Module,
105
+ insertTextFormat: InsertTextFormat.Snippet,
106
+ insertText: `${keyword.value} {
107
+ \${1|color,shape,border,opacity,icon|} $0
108
+ }`
109
+ });
110
+ }
111
+ if (keyword.value === "extend") {
112
+ return acceptor(context, {
113
+ label: keyword.value,
114
+ detail: `Extend another view`,
115
+ kind: CompletionItemKind.Class,
116
+ insertTextFormat: InsertTextFormat.Snippet,
117
+ insertText: "extend ${1:element} {\n $0\n}"
118
+ });
119
+ }
120
+ if (keyword.value === "autoLayout") {
121
+ return acceptor(context, {
122
+ label: keyword.value,
123
+ kind: CompletionItemKind.Class,
124
+ insertTextFormat: InsertTextFormat.Snippet,
125
+ insertText: "autoLayout ${1|TopBottom,BottomTop,LeftRight,RightLeft|}$0"
126
+ });
127
+ }
128
+ acceptor(context, {
129
+ label: keyword.value,
130
+ kind: this.getKeywordCompletionItemKind(keyword),
131
+ detail: "Keyword",
132
+ sortText: "1"
133
+ });
134
+ }
135
+ }
@@ -0,0 +1,9 @@
1
+ import type { ReferenceDescription } from 'langium';
2
+ import { DefaultDocumentHighlightProvider } from 'langium/lsp';
3
+ import { DocumentHighlight } from 'vscode-languageserver';
4
+ export declare class LikeC4DocumentHighlightProvider extends DefaultDocumentHighlightProvider {
5
+ /**
6
+ * Override this method to determine the highlight kind of the given reference.
7
+ */
8
+ protected createDocumentHighlight(reference: ReferenceDescription): DocumentHighlight;
9
+ }
@@ -0,0 +1,10 @@
1
+ import { DefaultDocumentHighlightProvider } from "langium/lsp";
2
+ import { DocumentHighlight, DocumentHighlightKind } from "vscode-languageserver";
3
+ export class LikeC4DocumentHighlightProvider extends DefaultDocumentHighlightProvider {
4
+ /**
5
+ * Override this method to determine the highlight kind of the given reference.
6
+ */
7
+ createDocumentHighlight(reference) {
8
+ return DocumentHighlight.create(reference.segment.range, DocumentHighlightKind.Read);
9
+ }
10
+ }
@@ -0,0 +1,11 @@
1
+ import type { LangiumDocument, MaybePromise } from 'langium';
2
+ import type { DocumentLinkProvider } from 'langium/lsp';
3
+ import type { DocumentLink, DocumentLinkParams } from 'vscode-languageserver';
4
+ import type { LikeC4Services } from '../module';
5
+ export declare class LikeC4DocumentLinkProvider implements DocumentLinkProvider {
6
+ private services;
7
+ constructor(services: LikeC4Services);
8
+ getDocumentLinks(doc: LangiumDocument, _params: DocumentLinkParams): MaybePromise<DocumentLink[]>;
9
+ resolveLink(doc: LangiumDocument, link: string): string;
10
+ relativeLink(doc: LangiumDocument, link: string): string | null;
11
+ }
@@ -0,0 +1,49 @@
1
+ import { AstUtils, GrammarUtils } from "langium";
2
+ import { hasLeadingSlash, hasProtocol, isRelative, withoutBase, withoutLeadingSlash } from "ufo";
3
+ import { ast, isParsedLikeC4LangiumDocument } from "../ast.js";
4
+ import { logWarnError } from "../logger.js";
5
+ export class LikeC4DocumentLinkProvider {
6
+ constructor(services) {
7
+ this.services = services;
8
+ }
9
+ getDocumentLinks(doc, _params) {
10
+ if (!isParsedLikeC4LangiumDocument(doc)) {
11
+ return [];
12
+ }
13
+ return AstUtils.streamAllContents(doc.parseResult.value).filter(ast.isLinkProperty).map((n) => {
14
+ try {
15
+ const range = GrammarUtils.findNodeForProperty(n.$cstNode, "value")?.range;
16
+ const target = this.resolveLink(doc, n.value);
17
+ if (range && hasProtocol(target)) {
18
+ return {
19
+ range,
20
+ target
21
+ };
22
+ }
23
+ } catch (e) {
24
+ logWarnError(e);
25
+ }
26
+ return null;
27
+ }).nonNullable().toArray();
28
+ }
29
+ resolveLink(doc, link) {
30
+ if (hasProtocol(link) || hasLeadingSlash(link)) {
31
+ return link;
32
+ }
33
+ const base = isRelative(link) ? new URL(doc.uri.toString(true)) : this.services.shared.workspace.WorkspaceManager.workspaceURL;
34
+ return new URL(link, base).toString();
35
+ }
36
+ relativeLink(doc, link) {
37
+ if (hasLeadingSlash(link)) {
38
+ return withoutLeadingSlash(link);
39
+ }
40
+ if (isRelative(link)) {
41
+ const base = new URL(doc.uri.toString(true));
42
+ const linkURL = new URL(link, base).toString();
43
+ return withoutLeadingSlash(
44
+ withoutBase(linkURL, this.services.shared.workspace.WorkspaceManager.workspaceURL.toString())
45
+ );
46
+ }
47
+ return null;
48
+ }
49
+ }
@@ -0,0 +1,23 @@
1
+ import { type AstNode, type MaybePromise } from 'langium';
2
+ import type { DocumentSymbolProvider, NodeKindProvider } from 'langium/lsp';
3
+ import { type DocumentSymbol, SymbolKind } from 'vscode-languageserver-types';
4
+ import { ast, type LikeC4LangiumDocument } from '../ast';
5
+ import type { LikeC4Services } from '../module';
6
+ export declare class LikeC4DocumentSymbolProvider implements DocumentSymbolProvider {
7
+ private services;
8
+ protected readonly nodeKindProvider: NodeKindProvider;
9
+ constructor(services: LikeC4Services);
10
+ getSymbols({ parseResult: { value: { specifications, models, views, likec4lib } } }: LikeC4LangiumDocument): MaybePromise<DocumentSymbol[]>;
11
+ protected getLikec4LibSymbol(astLib: ast.LikeC4Lib): DocumentSymbol[];
12
+ protected getSpecSymbol(astSpec: ast.SpecificationRule): DocumentSymbol[];
13
+ protected getModelSymbol(astModel: ast.Model): DocumentSymbol[];
14
+ protected getElementsSymbol(el: ast.Element | ast.Relation | ast.ExtendElement): DocumentSymbol[];
15
+ protected getExtendElementSymbol(astElement: ast.ExtendElement): DocumentSymbol[];
16
+ protected getElementSymbol(astElement: ast.Element): DocumentSymbol[];
17
+ protected getModelViewsSymbol(astViews: ast.ModelViews): DocumentSymbol[];
18
+ protected getKindSymbol(astKind: ast.SpecificationElementKind | ast.SpecificationRelationshipKind): DocumentSymbol | null;
19
+ protected getTagSymbol(astTag: ast.SpecificationTag): DocumentSymbol | null;
20
+ protected getLibIconSymbol(astTag: ast.LibIcon): DocumentSymbol | null;
21
+ protected getViewSymbol(astView: ast.LikeC4View): DocumentSymbol[];
22
+ protected symbolKind(node: AstNode): SymbolKind;
23
+ }
@@ -0,0 +1,202 @@
1
+ import { nonexhaustive } from "@likec4/core";
2
+ import { GrammarUtils } from "langium";
3
+ import { filter, isEmpty, isTruthy, map, pipe } from "remeda";
4
+ import { SymbolKind } from "vscode-languageserver-types";
5
+ import { ast } from "../ast.js";
6
+ import { logError } from "../logger.js";
7
+ import { getFqnElementRef } from "../utils/elementRef.js";
8
+ export class LikeC4DocumentSymbolProvider {
9
+ constructor(services) {
10
+ this.services = services;
11
+ this.nodeKindProvider = services.shared.lsp.NodeKindProvider;
12
+ }
13
+ nodeKindProvider;
14
+ getSymbols({
15
+ parseResult: {
16
+ value: { specifications, models, views, likec4lib }
17
+ }
18
+ }) {
19
+ return [
20
+ ...likec4lib.map((l) => () => this.getLikec4LibSymbol(l)),
21
+ ...specifications.map((s) => () => this.getSpecSymbol(s)),
22
+ ...models.map((s) => () => this.getModelSymbol(s)),
23
+ ...views.map((s) => () => this.getModelViewsSymbol(s))
24
+ ].flatMap((fn) => {
25
+ try {
26
+ return fn() ?? [];
27
+ } catch (e) {
28
+ logError(e);
29
+ return [];
30
+ }
31
+ });
32
+ }
33
+ getLikec4LibSymbol(astLib) {
34
+ const cstModel = astLib?.$cstNode;
35
+ if (!cstModel) return [];
36
+ const children = astLib.icons.map((i) => this.getLibIconSymbol(i)).filter(isTruthy);
37
+ if (children.length === 0) return [];
38
+ return [
39
+ {
40
+ kind: SymbolKind.Namespace,
41
+ name: "icons",
42
+ range: cstModel.range,
43
+ selectionRange: GrammarUtils.findNodeForKeyword(cstModel, "icons")?.range ?? cstModel.range,
44
+ children
45
+ }
46
+ ];
47
+ }
48
+ getSpecSymbol(astSpec) {
49
+ const cstModel = astSpec?.$cstNode;
50
+ if (!cstModel) return [];
51
+ const specKeywordNode = GrammarUtils.findNodeForProperty(cstModel, "name");
52
+ if (!specKeywordNode) return [];
53
+ const specSymbols = pipe(
54
+ [...astSpec.elements, ...astSpec.tags, ...astSpec.relationships],
55
+ map((nd) => {
56
+ try {
57
+ if (ast.isSpecificationElementKind(nd) || ast.isSpecificationRelationshipKind(nd) || ast.isSpecificationDeploymentNodeKind(nd)) {
58
+ return this.getKindSymbol(nd);
59
+ }
60
+ if (ast.isSpecificationTag(nd)) {
61
+ return this.getTagSymbol(nd);
62
+ }
63
+ } catch (e) {
64
+ logError(e);
65
+ return null;
66
+ }
67
+ nonexhaustive(nd);
68
+ }),
69
+ filter(isTruthy)
70
+ );
71
+ if (specSymbols.length === 0) return [];
72
+ return [
73
+ {
74
+ kind: SymbolKind.Namespace,
75
+ name: astSpec.name,
76
+ range: cstModel.range,
77
+ selectionRange: specKeywordNode.range,
78
+ children: specSymbols
79
+ }
80
+ ];
81
+ }
82
+ getModelSymbol(astModel) {
83
+ const cstModel = astModel.$cstNode;
84
+ if (!cstModel) return [];
85
+ const nameNode = GrammarUtils.findNodeForProperty(cstModel, "name");
86
+ if (!nameNode) return [];
87
+ return [
88
+ {
89
+ kind: this.symbolKind(astModel),
90
+ name: astModel.name,
91
+ range: cstModel.range,
92
+ selectionRange: nameNode.range,
93
+ children: astModel.elements.flatMap((e) => this.getElementsSymbol(e))
94
+ }
95
+ ];
96
+ }
97
+ getElementsSymbol(el) {
98
+ try {
99
+ if (ast.isExtendElement(el)) {
100
+ return this.getExtendElementSymbol(el);
101
+ }
102
+ if (ast.isElement(el)) {
103
+ return this.getElementSymbol(el);
104
+ }
105
+ } catch (e) {
106
+ logError(e);
107
+ }
108
+ return [];
109
+ }
110
+ getExtendElementSymbol(astElement) {
111
+ const cst = astElement.$cstNode;
112
+ const nameNode = astElement.element.$cstNode;
113
+ const body = astElement.body;
114
+ if (!cst || !nameNode) return [];
115
+ return [
116
+ {
117
+ kind: this.symbolKind(astElement),
118
+ name: getFqnElementRef(astElement.element),
119
+ range: cst.range,
120
+ selectionRange: nameNode.range,
121
+ children: body.elements.flatMap((e) => this.getElementsSymbol(e))
122
+ }
123
+ ];
124
+ }
125
+ getElementSymbol(astElement) {
126
+ const cst = astElement.$cstNode;
127
+ const nameNode = GrammarUtils.findNodeForProperty(cst, "name");
128
+ if (!nameNode || !cst) return [];
129
+ const name = astElement.name;
130
+ const kind = astElement.kind.$refText;
131
+ const detail = kind;
132
+ return [
133
+ {
134
+ kind: this.symbolKind(astElement),
135
+ name,
136
+ range: cst.range,
137
+ selectionRange: nameNode.range,
138
+ detail,
139
+ children: astElement.body?.elements.flatMap((e) => this.getElementsSymbol(e)) ?? []
140
+ }
141
+ ];
142
+ }
143
+ getModelViewsSymbol(astViews) {
144
+ const cst = astViews.$cstNode;
145
+ const nameNode = GrammarUtils.findNodeForProperty(cst, "name");
146
+ if (!nameNode || !cst) return [];
147
+ return [
148
+ {
149
+ kind: this.symbolKind(astViews),
150
+ name: astViews.name,
151
+ range: cst.range,
152
+ selectionRange: nameNode.range,
153
+ children: astViews.views.flatMap((e) => this.getViewSymbol(e))
154
+ }
155
+ ];
156
+ }
157
+ getKindSymbol(astKind) {
158
+ if (!astKind.$cstNode || !astKind.kind.$cstNode || isEmpty(astKind.kind.name)) return null;
159
+ return {
160
+ kind: this.symbolKind(astKind),
161
+ name: astKind.kind.name,
162
+ range: astKind.$cstNode.range,
163
+ selectionRange: astKind.kind.$cstNode.range
164
+ };
165
+ }
166
+ getTagSymbol(astTag) {
167
+ if (!astTag.$cstNode || !astTag.tag.$cstNode || isEmpty(astTag.tag.name)) return null;
168
+ return {
169
+ kind: this.symbolKind(astTag),
170
+ name: "#" + astTag.tag.name,
171
+ range: astTag.$cstNode.range,
172
+ selectionRange: astTag.tag.$cstNode.range
173
+ };
174
+ }
175
+ getLibIconSymbol(astTag) {
176
+ if (!astTag.$cstNode || isEmpty(astTag.name)) return null;
177
+ return {
178
+ kind: this.symbolKind(astTag),
179
+ name: astTag.name,
180
+ range: astTag.$cstNode.range,
181
+ selectionRange: astTag.$cstNode.range
182
+ };
183
+ }
184
+ getViewSymbol(astView) {
185
+ const cst = astView?.$cstNode;
186
+ if (!cst) return [];
187
+ const nameNode = astView.name ? GrammarUtils.findNodeForProperty(cst, "name") : null;
188
+ if (!nameNode) return [];
189
+ return [
190
+ {
191
+ kind: this.symbolKind(astView),
192
+ name: nameNode.text,
193
+ range: cst.range,
194
+ selectionRange: nameNode.range,
195
+ children: []
196
+ }
197
+ ];
198
+ }
199
+ symbolKind(node) {
200
+ return this.nodeKindProvider.getSymbolKind(node);
201
+ }
202
+ }
@@ -0,0 +1,10 @@
1
+ import { type AstNode, type MaybePromise } from 'langium';
2
+ import { AstNodeHoverProvider } from 'langium/lsp';
3
+ import type { Hover } from 'vscode-languageserver-types';
4
+ import type { LikeC4Services } from '../module';
5
+ export declare class LikeC4HoverProvider extends AstNodeHoverProvider {
6
+ private parser;
7
+ private locator;
8
+ constructor(services: LikeC4Services);
9
+ protected getAstNodeHoverContent(node: AstNode): MaybePromise<Hover | undefined>;
10
+ }
@@ -0,0 +1,69 @@
1
+ import { AstUtils } from "langium";
2
+ import { AstNodeHoverProvider } from "langium/lsp";
3
+ import stripIndent from "strip-indent";
4
+ import { ast } from "../ast.js";
5
+ export class LikeC4HoverProvider extends AstNodeHoverProvider {
6
+ parser;
7
+ locator;
8
+ constructor(services) {
9
+ super(services);
10
+ this.parser = services.likec4.ModelParser;
11
+ this.locator = services.likec4.ModelLocator;
12
+ }
13
+ getAstNodeHoverContent(node) {
14
+ if (ast.isTag(node)) {
15
+ return {
16
+ contents: {
17
+ kind: "markdown",
18
+ value: stripIndent(`
19
+ tag: \`${node.name}\`
20
+ `)
21
+ }
22
+ };
23
+ }
24
+ if (ast.isDeploymentNode(node)) {
25
+ const doc = AstUtils.getDocument(node);
26
+ const el = this.parser.forDocument(doc).parseDeploymentNode(node);
27
+ const lines = [el.id + " "];
28
+ if (el.title !== node.name) {
29
+ lines.push(`### ${el.title}`);
30
+ }
31
+ lines.push("Deployment: `" + el.kind + "` ");
32
+ return {
33
+ contents: {
34
+ kind: "markdown",
35
+ value: lines.join("\n")
36
+ }
37
+ };
38
+ }
39
+ if (ast.isDeployedInstance(node)) {
40
+ const doc = AstUtils.getDocument(node);
41
+ const instance = this.parser.forDocument(doc).parseDeployedInstance(node);
42
+ const el = this.locator.getParsedElement(instance.element);
43
+ const lines = [instance.id + " ", `instance of \`${instance.element}\``];
44
+ if (el) {
45
+ lines.push(`### ${el.title}`, "Element: `" + el.kind + "` ");
46
+ }
47
+ return {
48
+ contents: {
49
+ kind: "markdown",
50
+ value: lines.join("\n")
51
+ }
52
+ };
53
+ }
54
+ if (ast.isElement(node)) {
55
+ const el = this.locator.getParsedElement(node);
56
+ if (!el) {
57
+ return;
58
+ }
59
+ const lines = [el.id, `### ${el.title}`, "Element: `" + el.kind + "` "];
60
+ return {
61
+ contents: {
62
+ kind: "markdown",
63
+ value: lines.join("\n")
64
+ }
65
+ };
66
+ }
67
+ return;
68
+ }
69
+ }