@likec4/language-server 1.18.0 → 1.19.1

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 (250) hide show
  1. package/dist/LikeC4FileSystem.d.ts +13 -0
  2. package/dist/LikeC4FileSystem.js +27 -0
  3. package/dist/Rpc.d.ts +9 -0
  4. package/dist/Rpc.js +132 -0
  5. package/dist/ast.d.ts +200 -0
  6. package/dist/ast.js +276 -0
  7. package/dist/browser.d.ts +7 -20
  8. package/dist/browser.js +13 -0
  9. package/dist/documentation/documentation-provider.d.ts +8 -0
  10. package/dist/documentation/documentation-provider.js +46 -0
  11. package/dist/documentation/index.d.ts +1 -0
  12. package/dist/documentation/index.js +1 -0
  13. package/dist/formatting/LikeC4Formatter.d.ts +27 -0
  14. package/dist/formatting/LikeC4Formatter.js +261 -0
  15. package/dist/formatting/utils.d.ts +6 -0
  16. package/dist/formatting/utils.js +15 -0
  17. package/dist/generated/ast.d.ts +1242 -0
  18. package/dist/generated/ast.js +1945 -0
  19. package/dist/generated/grammar.d.ts +6 -0
  20. package/dist/generated/grammar.js +3 -0
  21. package/dist/generated/module.d.ts +9 -0
  22. package/dist/generated/module.js +23 -0
  23. package/dist/generated-lib/icons.d.ts +1 -0
  24. package/dist/{likec4lib.mjs → generated-lib/icons.js} +1 -6
  25. package/dist/index.d.ts +9 -31
  26. package/dist/index.js +14 -0
  27. package/dist/like-c4.langium +845 -0
  28. package/dist/likec4lib.d.ts +4 -6
  29. package/dist/likec4lib.js +4 -0
  30. package/dist/logger.d.ts +7 -0
  31. package/dist/logger.js +73 -0
  32. package/dist/lsp/CodeLensProvider.d.ts +9 -0
  33. package/dist/lsp/CodeLensProvider.js +40 -0
  34. package/dist/lsp/CompletionProvider.d.ts +6 -0
  35. package/dist/lsp/CompletionProvider.js +135 -0
  36. package/dist/lsp/DocumentHighlightProvider.d.ts +9 -0
  37. package/dist/lsp/DocumentHighlightProvider.js +10 -0
  38. package/dist/lsp/DocumentLinkProvider.d.ts +11 -0
  39. package/dist/lsp/DocumentLinkProvider.js +49 -0
  40. package/dist/lsp/DocumentSymbolProvider.d.ts +32 -0
  41. package/dist/lsp/DocumentSymbolProvider.js +274 -0
  42. package/dist/lsp/HoverProvider.d.ts +10 -0
  43. package/dist/lsp/HoverProvider.js +69 -0
  44. package/dist/lsp/RenameProvider.d.ts +5 -0
  45. package/dist/lsp/RenameProvider.js +6 -0
  46. package/dist/lsp/SemanticTokenProvider.d.ts +7 -0
  47. package/dist/lsp/SemanticTokenProvider.js +297 -0
  48. package/dist/lsp/index.d.ts +7 -0
  49. package/dist/lsp/index.js +7 -0
  50. package/dist/model/deployments-index.d.ts +60 -0
  51. package/dist/model/deployments-index.js +181 -0
  52. package/dist/model/fqn-computation.d.ts +3 -0
  53. package/dist/model/fqn-computation.js +72 -0
  54. package/dist/model/fqn-index.d.ts +25 -0
  55. package/dist/model/fqn-index.js +96 -0
  56. package/dist/model/index.d.ts +6 -0
  57. package/dist/model/index.js +6 -0
  58. package/dist/model/model-builder.d.ts +32 -0
  59. package/dist/model/model-builder.js +598 -0
  60. package/dist/model/model-locator.d.ts +23 -0
  61. package/dist/model/model-locator.js +126 -0
  62. package/dist/model/model-parser-where.d.ts +3 -0
  63. package/dist/model/model-parser-where.js +70 -0
  64. package/dist/model/model-parser.d.ts +292 -0
  65. package/dist/model/model-parser.js +72 -0
  66. package/dist/model/parser/Base.d.ts +28 -0
  67. package/dist/model/parser/Base.js +87 -0
  68. package/dist/model/parser/DeploymentModelParser.d.ts +33 -0
  69. package/dist/model/parser/DeploymentModelParser.js +162 -0
  70. package/dist/model/parser/DeploymentViewParser.d.ts +38 -0
  71. package/dist/model/parser/DeploymentViewParser.js +98 -0
  72. package/dist/model/parser/FqnRefParser.d.ts +29 -0
  73. package/dist/model/parser/FqnRefParser.js +108 -0
  74. package/dist/model/parser/GlobalsParser.d.ts +66 -0
  75. package/dist/model/parser/GlobalsParser.js +80 -0
  76. package/dist/model/parser/ModelParser.d.ts +27 -0
  77. package/dist/model/parser/ModelParser.js +122 -0
  78. package/dist/model/parser/PredicatesParser.d.ts +34 -0
  79. package/dist/model/parser/PredicatesParser.js +272 -0
  80. package/dist/model/parser/SpecificationParser.d.ts +27 -0
  81. package/dist/model/parser/SpecificationParser.js +120 -0
  82. package/dist/model/parser/ViewsParser.d.ts +64 -0
  83. package/dist/model/parser/ViewsParser.js +377 -0
  84. package/dist/model-change/ModelChanges.d.ts +15 -0
  85. package/dist/model-change/ModelChanges.js +89 -0
  86. package/dist/model-change/changeElementStyle.d.ts +16 -0
  87. package/dist/model-change/changeElementStyle.js +136 -0
  88. package/dist/model-change/changeViewLayout.d.ts +12 -0
  89. package/dist/model-change/changeViewLayout.js +32 -0
  90. package/dist/model-change/saveManualLayout.d.ts +11 -0
  91. package/dist/model-change/saveManualLayout.js +27 -0
  92. package/dist/module.d.ts +70 -0
  93. package/dist/module.js +162 -0
  94. package/dist/protocol.d.ts +38 -23
  95. package/dist/protocol.js +15 -0
  96. package/dist/references/index.d.ts +3 -0
  97. package/dist/references/index.js +3 -0
  98. package/dist/references/name-provider.d.ts +9 -0
  99. package/dist/references/name-provider.js +33 -0
  100. package/dist/references/scope-computation.d.ts +20 -0
  101. package/dist/references/scope-computation.js +281 -0
  102. package/dist/references/scope-provider.d.ts +16 -0
  103. package/dist/references/scope-provider.js +165 -0
  104. package/dist/shared/NodeKindProvider.d.ts +15 -0
  105. package/dist/shared/NodeKindProvider.js +108 -0
  106. package/dist/shared/WorkspaceManager.d.ts +18 -0
  107. package/dist/shared/WorkspaceManager.js +36 -0
  108. package/dist/shared/WorkspaceSymbolProvider.d.ts +3 -0
  109. package/dist/shared/WorkspaceSymbolProvider.js +3 -0
  110. package/dist/shared/index.d.ts +3 -0
  111. package/dist/shared/index.js +3 -0
  112. package/dist/test/index.d.ts +1 -0
  113. package/dist/test/index.js +1 -0
  114. package/dist/test/setup.d.ts +1 -0
  115. package/dist/test/setup.js +7 -0
  116. package/dist/test/testServices.d.ts +22 -0
  117. package/dist/test/testServices.js +119 -0
  118. package/dist/utils/elementRef.d.ts +11 -0
  119. package/dist/utils/elementRef.js +15 -0
  120. package/dist/utils/fqnRef.d.ts +8 -0
  121. package/dist/utils/fqnRef.js +46 -0
  122. package/dist/utils/index.d.ts +1 -0
  123. package/dist/utils/index.js +1 -0
  124. package/dist/utils/printDocs.d.ts +2 -0
  125. package/dist/utils/printDocs.js +1 -0
  126. package/dist/utils/stringHash.d.ts +1 -0
  127. package/dist/utils/stringHash.js +5 -0
  128. package/dist/validation/_shared.d.ts +3 -0
  129. package/dist/validation/_shared.js +22 -0
  130. package/dist/validation/deployment-checks.d.ts +6 -0
  131. package/dist/validation/deployment-checks.js +114 -0
  132. package/dist/validation/dynamic-view-rule.d.ts +4 -0
  133. package/dist/validation/dynamic-view-rule.js +17 -0
  134. package/dist/validation/dynamic-view-step.d.ts +4 -0
  135. package/dist/validation/dynamic-view-step.js +29 -0
  136. package/dist/validation/element.d.ts +4 -0
  137. package/dist/validation/element.js +49 -0
  138. package/dist/validation/index.d.ts +15 -0
  139. package/dist/validation/index.js +152 -0
  140. package/dist/validation/property-checks.d.ts +6 -0
  141. package/dist/validation/property-checks.js +39 -0
  142. package/dist/validation/relation.d.ts +5 -0
  143. package/dist/validation/relation.js +56 -0
  144. package/dist/validation/specification.d.ts +11 -0
  145. package/dist/validation/specification.js +136 -0
  146. package/dist/validation/view-predicates/element-with.d.ts +4 -0
  147. package/dist/validation/view-predicates/element-with.js +31 -0
  148. package/dist/validation/view-predicates/expanded-element.d.ts +4 -0
  149. package/dist/validation/view-predicates/expanded-element.js +12 -0
  150. package/dist/validation/view-predicates/expression-v2.d.ts +5 -0
  151. package/dist/validation/view-predicates/expression-v2.js +83 -0
  152. package/dist/validation/view-predicates/incoming.d.ts +4 -0
  153. package/dist/validation/view-predicates/incoming.js +16 -0
  154. package/dist/validation/view-predicates/index.d.ts +6 -0
  155. package/dist/validation/view-predicates/index.js +6 -0
  156. package/dist/validation/view-predicates/outgoing.d.ts +4 -0
  157. package/dist/validation/view-predicates/outgoing.js +16 -0
  158. package/dist/validation/view-predicates/relation-with.d.ts +4 -0
  159. package/dist/validation/view-predicates/relation-with.js +13 -0
  160. package/dist/validation/view.d.ts +4 -0
  161. package/dist/validation/view.js +23 -0
  162. package/dist/view-utils/assignNavigateTo.d.ts +2 -0
  163. package/dist/view-utils/assignNavigateTo.js +25 -0
  164. package/dist/view-utils/index.d.ts +2 -0
  165. package/dist/view-utils/index.js +2 -0
  166. package/dist/view-utils/manual-layout.d.ts +7 -0
  167. package/dist/view-utils/manual-layout.js +99 -0
  168. package/dist/view-utils/resolve-relative-paths.d.ts +2 -0
  169. package/dist/view-utils/resolve-relative-paths.js +78 -0
  170. package/dist/views/configurable-layouter.d.ts +7 -0
  171. package/dist/views/configurable-layouter.js +55 -0
  172. package/dist/views/index.d.ts +1 -0
  173. package/dist/views/index.js +1 -0
  174. package/dist/views/likec4-views.d.ts +26 -0
  175. package/dist/views/likec4-views.js +113 -0
  176. package/package.json +40 -54
  177. package/src/LikeC4FileSystem.ts +22 -21
  178. package/src/Rpc.ts +13 -7
  179. package/src/ast.ts +44 -133
  180. package/src/browser.ts +11 -11
  181. package/src/documentation/documentation-provider.ts +52 -0
  182. package/src/documentation/index.ts +1 -0
  183. package/src/generated/ast.ts +177 -177
  184. package/src/generated/grammar.ts +1 -1
  185. package/src/index.ts +13 -9
  186. package/src/like-c4.langium +37 -34
  187. package/src/logger.ts +34 -55
  188. package/src/lsp/CompletionProvider.ts +4 -4
  189. package/src/lsp/DocumentSymbolProvider.ts +110 -28
  190. package/src/lsp/HoverProvider.ts +5 -3
  191. package/src/lsp/SemanticTokenProvider.ts +2 -2
  192. package/src/model/deployments-index.ts +18 -14
  193. package/src/model/fqn-computation.ts +8 -8
  194. package/src/model/model-builder.ts +62 -60
  195. package/src/model/model-parser.ts +62 -1574
  196. package/src/model/parser/Base.ts +107 -0
  197. package/src/model/parser/DeploymentModelParser.ts +192 -0
  198. package/src/model/parser/DeploymentViewParser.ts +116 -0
  199. package/src/model/parser/FqnRefParser.ts +118 -0
  200. package/src/model/parser/GlobalsParser.ts +96 -0
  201. package/src/model/parser/ModelParser.ts +141 -0
  202. package/src/model/parser/PredicatesParser.ts +291 -0
  203. package/src/model/parser/SpecificationParser.ts +133 -0
  204. package/src/model/parser/ViewsParser.ts +428 -0
  205. package/src/module.ts +71 -25
  206. package/src/protocol.ts +29 -4
  207. package/src/references/scope-computation.ts +35 -35
  208. package/src/references/scope-provider.ts +13 -7
  209. package/src/utils/{deploymentRef.ts → fqnRef.ts} +27 -2
  210. package/src/validation/_shared.ts +0 -1
  211. package/src/validation/deployment-checks.ts +49 -62
  212. package/src/validation/dynamic-view-rule.ts +5 -4
  213. package/src/validation/dynamic-view-step.ts +23 -26
  214. package/src/validation/index.ts +100 -9
  215. package/src/validation/property-checks.ts +11 -10
  216. package/src/validation/specification.ts +38 -38
  217. package/src/validation/view-predicates/element-with.ts +6 -5
  218. package/src/validation/view-predicates/expanded-element.ts +6 -5
  219. package/src/validation/view-predicates/expression-v2.ts +101 -0
  220. package/src/validation/view-predicates/incoming.ts +6 -5
  221. package/src/validation/view-predicates/index.ts +1 -1
  222. package/src/validation/view-predicates/outgoing.ts +6 -5
  223. package/src/validation/view-predicates/relation-with.ts +6 -5
  224. package/src/validation/view.ts +5 -5
  225. package/src/view-utils/assignNavigateTo.ts +1 -1
  226. package/src/view-utils/manual-layout.ts +25 -0
  227. package/src/views/configurable-layouter.ts +65 -0
  228. package/src/views/index.ts +1 -0
  229. package/src/views/likec4-views.ts +139 -0
  230. package/dist/browser.cjs +0 -25
  231. package/dist/browser.d.cts +0 -23
  232. package/dist/browser.d.mts +0 -23
  233. package/dist/browser.mjs +0 -20
  234. package/dist/index.cjs +0 -53
  235. package/dist/index.d.cts +0 -34
  236. package/dist/index.d.mts +0 -34
  237. package/dist/index.mjs +0 -46
  238. package/dist/likec4lib.cjs +0 -1546
  239. package/dist/likec4lib.d.cts +0 -6
  240. package/dist/likec4lib.d.mts +0 -6
  241. package/dist/protocol.cjs +0 -25
  242. package/dist/protocol.d.cts +0 -48
  243. package/dist/protocol.d.mts +0 -48
  244. package/dist/protocol.mjs +0 -17
  245. package/dist/shared/language-server.CO_nmHiL.cjs +0 -7689
  246. package/dist/shared/language-server.Da6ey08o.d.cts +0 -1619
  247. package/dist/shared/language-server.De7S3e5Z.d.ts +0 -1619
  248. package/dist/shared/language-server.Dj4iDjtB.d.mts +0 -1619
  249. package/dist/shared/language-server.oO_9JoAG.mjs +0 -7666
  250. package/src/validation/view-predicates/deployments.ts +0 -56
@@ -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,32 @@
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 { type LikeC4LangiumDocument, ast } from '../ast';
5
+ import type { LikeC4ModelLocator, LikeC4ModelParser } from '../model';
6
+ import type { LikeC4Services } from '../module';
7
+ import type { LikeC4NameProvider } from '../references';
8
+ export declare class LikeC4DocumentSymbolProvider implements DocumentSymbolProvider {
9
+ private services;
10
+ protected readonly nodeKindProvider: NodeKindProvider;
11
+ protected readonly nameProvider: LikeC4NameProvider;
12
+ protected readonly parser: LikeC4ModelParser;
13
+ protected readonly locator: LikeC4ModelLocator;
14
+ constructor(services: LikeC4Services);
15
+ getSymbols({ parseResult: { value: { specifications, models, deployments, views, likec4lib }, }, }: LikeC4LangiumDocument): MaybePromise<DocumentSymbol[]>;
16
+ protected getLikec4LibSymbol(astLib: ast.LikeC4Lib): DocumentSymbol[];
17
+ protected getSpecSymbol(astSpec: ast.SpecificationRule): DocumentSymbol[];
18
+ protected getModelSymbol(astModel: ast.Model): DocumentSymbol[];
19
+ protected getDeploymentModelSymbol(astModel: ast.ModelDeployments): DocumentSymbol[];
20
+ protected getElementsSymbol(el: ast.Element | ast.Relation | ast.ExtendElement): DocumentSymbol[];
21
+ protected getExtendElementSymbol(astElement: ast.ExtendElement): DocumentSymbol[];
22
+ protected getElementSymbol(astElement: ast.Element): DocumentSymbol[];
23
+ protected getModelViewsSymbol(astViews: ast.ModelViews): DocumentSymbol[];
24
+ protected getKindSymbol(astKind: ast.SpecificationElementKind | ast.SpecificationRelationshipKind): DocumentSymbol | null;
25
+ protected getTagSymbol(astTag: ast.SpecificationTag): DocumentSymbol | null;
26
+ protected getLibIconSymbol(astTag: ast.LibIcon): DocumentSymbol | null;
27
+ protected getViewSymbol(astView: ast.LikeC4View): DocumentSymbol[];
28
+ protected getDeploymentElementSymbol(el: ast.DeploymentElement | ast.DeploymentRelation): DocumentSymbol[];
29
+ protected getDeploymentNodeSymbol(astElement: ast.DeploymentNode): DocumentSymbol[];
30
+ protected getDeployedInstanceSymbol(astElement: ast.DeployedInstance): DocumentSymbol[];
31
+ protected symbolKind(node: AstNode): SymbolKind;
32
+ }
@@ -0,0 +1,274 @@
1
+ import { nonexhaustive } from "@likec4/core";
2
+ import { AstUtils, 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 { logWarnError } 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
+ this.parser = services.likec4.ModelParser;
13
+ this.locator = services.likec4.ModelLocator;
14
+ this.nameProvider = services.references.NameProvider;
15
+ }
16
+ nodeKindProvider;
17
+ nameProvider;
18
+ parser;
19
+ locator;
20
+ getSymbols({
21
+ parseResult: {
22
+ value: { specifications, models, deployments, views, likec4lib }
23
+ }
24
+ }) {
25
+ return [
26
+ ...likec4lib.map((l) => () => this.getLikec4LibSymbol(l)),
27
+ ...specifications.map((s) => () => this.getSpecSymbol(s)),
28
+ ...models.map((s) => () => this.getModelSymbol(s)),
29
+ ...deployments.map((s) => () => this.getDeploymentModelSymbol(s)),
30
+ ...views.map((s) => () => this.getModelViewsSymbol(s))
31
+ ].flatMap((fn) => {
32
+ try {
33
+ return fn() ?? [];
34
+ } catch (e) {
35
+ logWarnError(e);
36
+ return [];
37
+ }
38
+ });
39
+ }
40
+ getLikec4LibSymbol(astLib) {
41
+ const cstModel = astLib?.$cstNode;
42
+ if (!cstModel) return [];
43
+ const children = astLib.icons.map((i) => this.getLibIconSymbol(i)).filter(isTruthy);
44
+ if (children.length === 0) return [];
45
+ return [
46
+ {
47
+ kind: SymbolKind.Namespace,
48
+ name: "icons",
49
+ range: cstModel.range,
50
+ selectionRange: GrammarUtils.findNodeForKeyword(cstModel, "icons")?.range ?? cstModel.range,
51
+ children
52
+ }
53
+ ];
54
+ }
55
+ getSpecSymbol(astSpec) {
56
+ const cstModel = astSpec?.$cstNode;
57
+ if (!cstModel) return [];
58
+ const specKeywordNode = GrammarUtils.findNodeForProperty(cstModel, "name");
59
+ if (!specKeywordNode) return [];
60
+ const specSymbols = pipe(
61
+ [...astSpec.elements, ...astSpec.tags, ...astSpec.relationships],
62
+ map((nd) => {
63
+ try {
64
+ if (ast.isSpecificationElementKind(nd) || ast.isSpecificationRelationshipKind(nd) || ast.isSpecificationDeploymentNodeKind(nd)) {
65
+ return this.getKindSymbol(nd);
66
+ }
67
+ if (ast.isSpecificationTag(nd)) {
68
+ return this.getTagSymbol(nd);
69
+ }
70
+ } catch (e) {
71
+ logWarnError(e);
72
+ return null;
73
+ }
74
+ nonexhaustive(nd);
75
+ }),
76
+ filter(isTruthy)
77
+ );
78
+ if (specSymbols.length === 0) return [];
79
+ return [
80
+ {
81
+ kind: SymbolKind.Namespace,
82
+ name: astSpec.name,
83
+ range: cstModel.range,
84
+ selectionRange: specKeywordNode.range,
85
+ children: specSymbols
86
+ }
87
+ ];
88
+ }
89
+ getModelSymbol(astModel) {
90
+ const cstModel = astModel.$cstNode;
91
+ if (!cstModel) return [];
92
+ const nameNode = GrammarUtils.findNodeForProperty(cstModel, "name");
93
+ if (!nameNode) return [];
94
+ return [
95
+ {
96
+ kind: this.symbolKind(astModel),
97
+ name: astModel.name,
98
+ range: cstModel.range,
99
+ selectionRange: nameNode.range,
100
+ children: astModel.elements.flatMap((e) => this.getElementsSymbol(e))
101
+ }
102
+ ];
103
+ }
104
+ getDeploymentModelSymbol(astModel) {
105
+ const cstModel = astModel.$cstNode;
106
+ if (!cstModel) return [];
107
+ const nameNode = GrammarUtils.findNodeForProperty(cstModel, "name");
108
+ if (!nameNode) return [];
109
+ return [
110
+ {
111
+ kind: this.symbolKind(astModel),
112
+ name: astModel.name,
113
+ range: cstModel.range,
114
+ selectionRange: nameNode.range,
115
+ children: astModel.elements.flatMap((e) => this.getDeploymentElementSymbol(e))
116
+ }
117
+ ];
118
+ }
119
+ getElementsSymbol(el) {
120
+ try {
121
+ if (ast.isExtendElement(el)) {
122
+ return this.getExtendElementSymbol(el);
123
+ }
124
+ if (ast.isElement(el)) {
125
+ return this.getElementSymbol(el);
126
+ }
127
+ } catch (e) {
128
+ logWarnError(e);
129
+ }
130
+ return [];
131
+ }
132
+ getExtendElementSymbol(astElement) {
133
+ const cst = astElement.$cstNode;
134
+ const nameNode = astElement.element.$cstNode;
135
+ const body = astElement.body;
136
+ if (!cst || !nameNode) return [];
137
+ return [
138
+ {
139
+ kind: this.symbolKind(astElement),
140
+ name: getFqnElementRef(astElement.element),
141
+ range: cst.range,
142
+ selectionRange: nameNode.range,
143
+ children: body.elements.flatMap((e) => this.getElementsSymbol(e))
144
+ }
145
+ ];
146
+ }
147
+ getElementSymbol(astElement) {
148
+ const cst = astElement.$cstNode;
149
+ const nameNode = GrammarUtils.findNodeForProperty(cst, "name");
150
+ if (!nameNode || !cst) return [];
151
+ const name = astElement.name;
152
+ const kind = astElement.kind.$refText;
153
+ const detail = kind;
154
+ return [
155
+ {
156
+ kind: this.symbolKind(astElement),
157
+ name,
158
+ range: cst.range,
159
+ selectionRange: nameNode.range,
160
+ detail,
161
+ children: astElement.body?.elements.flatMap((e) => this.getElementsSymbol(e)) ?? []
162
+ }
163
+ ];
164
+ }
165
+ getModelViewsSymbol(astViews) {
166
+ const cst = astViews.$cstNode;
167
+ const nameNode = GrammarUtils.findNodeForProperty(cst, "name");
168
+ if (!nameNode || !cst) return [];
169
+ return [
170
+ {
171
+ kind: this.symbolKind(astViews),
172
+ name: astViews.name,
173
+ range: cst.range,
174
+ selectionRange: nameNode.range,
175
+ children: astViews.views.flatMap((e) => this.getViewSymbol(e))
176
+ }
177
+ ];
178
+ }
179
+ getKindSymbol(astKind) {
180
+ if (!astKind.$cstNode || !astKind.kind.$cstNode || isEmpty(astKind.kind.name)) return null;
181
+ return {
182
+ kind: this.symbolKind(astKind),
183
+ name: astKind.kind.name,
184
+ range: astKind.$cstNode.range,
185
+ selectionRange: astKind.kind.$cstNode.range
186
+ };
187
+ }
188
+ getTagSymbol(astTag) {
189
+ if (!astTag.$cstNode || !astTag.tag.$cstNode || isEmpty(astTag.tag.name)) return null;
190
+ return {
191
+ kind: this.symbolKind(astTag),
192
+ name: "#" + astTag.tag.name,
193
+ range: astTag.$cstNode.range,
194
+ selectionRange: astTag.tag.$cstNode.range
195
+ };
196
+ }
197
+ getLibIconSymbol(astTag) {
198
+ if (!astTag.$cstNode || isEmpty(astTag.name)) return null;
199
+ return {
200
+ kind: this.symbolKind(astTag),
201
+ name: astTag.name,
202
+ range: astTag.$cstNode.range,
203
+ selectionRange: astTag.$cstNode.range
204
+ };
205
+ }
206
+ getViewSymbol(astView) {
207
+ const cst = astView?.$cstNode;
208
+ if (!cst) return [];
209
+ const nameNode = astView.name ? GrammarUtils.findNodeForProperty(cst, "name") : null;
210
+ if (!nameNode) return [];
211
+ return [
212
+ {
213
+ kind: this.symbolKind(astView),
214
+ name: nameNode.text,
215
+ range: cst.range,
216
+ selectionRange: nameNode.range,
217
+ children: []
218
+ }
219
+ ];
220
+ }
221
+ getDeploymentElementSymbol(el) {
222
+ try {
223
+ if (ast.isDeploymentNode(el)) {
224
+ return this.getDeploymentNodeSymbol(el);
225
+ }
226
+ if (ast.isDeployedInstance(el)) {
227
+ return this.getDeployedInstanceSymbol(el);
228
+ }
229
+ } catch (e) {
230
+ logWarnError(e);
231
+ }
232
+ return [];
233
+ }
234
+ getDeploymentNodeSymbol(astElement) {
235
+ const cst = astElement.$cstNode;
236
+ const nameNode = this.nameProvider.getNameNode(astElement);
237
+ if (!nameNode || !cst) return [];
238
+ const name = this.nameProvider.getNameStrict(astElement);
239
+ const kind = astElement.kind.$refText;
240
+ const detail = kind;
241
+ return [
242
+ {
243
+ kind: this.symbolKind(astElement),
244
+ name,
245
+ range: cst.range,
246
+ selectionRange: nameNode.range,
247
+ detail,
248
+ children: astElement.body?.elements.flatMap((e) => this.getDeploymentElementSymbol(e)) ?? []
249
+ }
250
+ ];
251
+ }
252
+ getDeployedInstanceSymbol(astElement) {
253
+ const cst = astElement.$cstNode;
254
+ const nameNode = this.nameProvider.getNameNode(astElement);
255
+ if (!nameNode || !cst) return [];
256
+ const doc = AstUtils.getDocument(astElement);
257
+ const instance = this.parser.forDocument(doc).parseDeployedInstance(astElement);
258
+ const name = this.nameProvider.getNameStrict(astElement);
259
+ const detail = "instance of " + instance.element;
260
+ return [
261
+ {
262
+ kind: this.symbolKind(astElement),
263
+ name,
264
+ range: cst.range,
265
+ selectionRange: nameNode.range,
266
+ detail,
267
+ children: []
268
+ }
269
+ ];
270
+ }
271
+ symbolKind(node) {
272
+ return this.nodeKindProvider.getSymbolKind(node);
273
+ }
274
+ }