@likec4/language-server 1.31.0 → 1.32.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 (75) hide show
  1. package/dist/LikeC4LanguageServices.d.ts +2 -1
  2. package/dist/LikeC4LanguageServices.js +4 -3
  3. package/dist/Rpc.js +11 -4
  4. package/dist/ast.d.ts +11 -15
  5. package/dist/bundled.mjs +2539 -2476
  6. package/dist/formatting/LikeC4Formatter.js +7 -6
  7. package/dist/generated/ast.d.ts +33 -14
  8. package/dist/generated/ast.js +38 -16
  9. package/dist/generated/grammar.js +1 -1
  10. package/dist/lsp/CompletionProvider.js +1 -1
  11. package/dist/lsp/DocumentLinkProvider.js +4 -3
  12. package/dist/lsp/HoverProvider.js +9 -1
  13. package/dist/lsp/SemanticTokenProvider.js +18 -4
  14. package/dist/mcp/LikeC4MCPServerFactory.d.ts +5 -2
  15. package/dist/mcp/LikeC4MCPServerFactory.js +2 -72
  16. package/dist/mcp/LikeC4MCPTools.js +5 -3
  17. package/dist/mcp/sseserver/MCPServerFactory.d.ts +8 -0
  18. package/dist/mcp/sseserver/MCPServerFactory.js +78 -0
  19. package/dist/mcp/sseserver/with-mcp-server.d.ts +2 -0
  20. package/dist/mcp/sseserver/with-mcp-server.js +5 -1
  21. package/dist/mcp/utils.d.ts +5 -4
  22. package/dist/mcp/utils.js +2 -2
  23. package/dist/model/builder/MergedExtends.d.ts +4 -4
  24. package/dist/model/builder/MergedExtends.js +1 -1
  25. package/dist/model/builder/MergedSpecification.d.ts +4 -3
  26. package/dist/model/builder/MergedSpecification.js +9 -8
  27. package/dist/model/builder/assignTagColors.d.ts +7 -0
  28. package/dist/model/builder/assignTagColors.js +51 -0
  29. package/dist/model/builder/buildModel.d.ts +2 -2
  30. package/dist/model/builder/buildModel.js +40 -18
  31. package/dist/model/deployments-index.js +2 -2
  32. package/dist/model/fqn-index.d.ts +1 -1
  33. package/dist/model/fqn-index.js +6 -6
  34. package/dist/model/model-builder.d.ts +10 -4
  35. package/dist/model/model-builder.js +22 -19
  36. package/dist/model/model-locator.d.ts +10 -2
  37. package/dist/model/model-locator.js +65 -9
  38. package/dist/model/model-parser-where.d.ts +1 -1
  39. package/dist/model/model-parser-where.js +1 -1
  40. package/dist/model/model-parser.d.ts +10 -11
  41. package/dist/model/model-parser.js +11 -7
  42. package/dist/model/parser/Base.js +2 -3
  43. package/dist/model/parser/DeploymentModelParser.d.ts +1 -1
  44. package/dist/model/parser/DeploymentModelParser.js +7 -5
  45. package/dist/model/parser/DeploymentViewParser.d.ts +3 -3
  46. package/dist/model/parser/DeploymentViewParser.js +2 -1
  47. package/dist/model/parser/FqnRefParser.d.ts +1 -1
  48. package/dist/model/parser/FqnRefParser.js +2 -5
  49. package/dist/model/parser/GlobalsParser.d.ts +23 -24
  50. package/dist/model/parser/GlobalsParser.js +4 -4
  51. package/dist/model/parser/ModelParser.d.ts +1 -1
  52. package/dist/model/parser/ModelParser.js +1 -1
  53. package/dist/model/parser/PredicatesParser.d.ts +12 -12
  54. package/dist/model/parser/SpecificationParser.d.ts +5 -2
  55. package/dist/model/parser/SpecificationParser.js +18 -30
  56. package/dist/model/parser/ViewsParser.d.ts +23 -23
  57. package/dist/model/parser/ViewsParser.js +12 -19
  58. package/dist/model-change/changeElementStyle.d.ts +2 -2
  59. package/dist/model-change/changeElementStyle.js +6 -2
  60. package/dist/module.d.ts +1 -1
  61. package/dist/module.js +5 -2
  62. package/dist/protocol.d.ts +24 -3
  63. package/dist/protocol.js +4 -0
  64. package/dist/references/scope-computation.js +2 -3
  65. package/dist/test/testServices.d.ts +15 -0
  66. package/dist/test/testServices.js +1 -1
  67. package/dist/validation/relation.js +1 -1
  68. package/dist/validation/specification.js +1 -1
  69. package/dist/view-utils/assignNavigateTo.d.ts +1 -1
  70. package/dist/view-utils/assignNavigateTo.js +3 -3
  71. package/dist/views/likec4-views.d.ts +1 -3
  72. package/dist/views/likec4-views.js +68 -44
  73. package/package.json +21 -19
  74. /package/dist/mcp/sseserver/{SSELikeC4MCPServer.d.ts → MCPServer.d.ts} +0 -0
  75. /package/dist/mcp/sseserver/{SSELikeC4MCPServer.js → MCPServer.js} +0 -0
@@ -132,7 +132,7 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
132
132
  case ast.isSpecificationTag(spec): {
133
133
  if (isTruthy(spec.tag.name)) {
134
134
  docExports.push(
135
- this.descriptions.createDescription(spec.tag, "#" + spec.tag.name, document)
135
+ this.descriptions.createDescription(spec.tag, spec.tag.name, document)
136
136
  );
137
137
  }
138
138
  continue;
@@ -140,8 +140,7 @@ export class LikeC4ScopeComputation extends DefaultScopeComputation {
140
140
  case ast.isSpecificationRelationshipKind(spec): {
141
141
  if (isTruthy(spec.kind.name)) {
142
142
  docExports.push(
143
- this.descriptions.createDescription(spec.kind, spec.kind.name, document),
144
- this.descriptions.createDescription(spec.kind, "." + spec.kind.name, document)
143
+ this.descriptions.createDescription(spec.kind, spec.kind.name, document)
145
144
  );
146
145
  }
147
146
  continue;
@@ -1,3 +1,4 @@
1
+ import type { ComputedLikeC4ModelData } from '@likec4/core';
1
2
  import type { LikeC4LangiumDocument } from '../ast';
2
3
  export declare function createTestServices(workspace?: string): {
3
4
  services: any;
@@ -19,6 +20,20 @@ export declare function createTestServices(workspace?: string): {
19
20
  resetState: () => Promise<void>;
20
21
  format: (input: string | LikeC4LangiumDocument, uri?: string) => Promise<any>;
21
22
  };
23
+ /**
24
+ * @example
25
+ * ```ts
26
+ * const { projects } = await createMultiProjectTestServices({
27
+ * project1: {
28
+ * doc1: `...`,
29
+ * doc2: `...`,
30
+ * },
31
+ * project2: {
32
+ * doc1: `...`,
33
+ * },
34
+ * })
35
+ * ```
36
+ */
22
37
  export declare function createMultiProjectTestServices<const Projects extends Record<string, Record<string, string>>>(data: Projects): Promise<{
23
38
  services: any;
24
39
  projects: { readonly [K in keyof Projects]: { readonly [L in keyof Projects[K]]: LikeC4LangiumDocument; }; };
@@ -104,7 +104,7 @@ export function createTestServices(workspace = "file:///test/workspace") {
104
104
  }
105
105
  const likec4model = await modelBuilder.buildLikeC4Model();
106
106
  if (!likec4model) throw new Error("No model found");
107
- return likec4model.$model;
107
+ return likec4model.$data;
108
108
  };
109
109
  const buildLikeC4Model = async () => {
110
110
  if (langiumDocuments.all.some((doc) => doc.state < DocumentState.Validated)) {
@@ -34,7 +34,7 @@ export const relationChecks = (services) => {
34
34
  });
35
35
  }
36
36
  }
37
- if (isSameHierarchy(FqnRef.toModelFqn(source), FqnRef.toModelFqn(target))) {
37
+ if (isSameHierarchy(FqnRef.flatten(source), FqnRef.flatten(target))) {
38
38
  accept("error", "Invalid parent-child relationship", {
39
39
  node: el
40
40
  });
@@ -97,7 +97,7 @@ export const checkDeploymentNodeKind = (services) => {
97
97
  export const checkTag = (services) => {
98
98
  const index = services.shared.workspace.IndexManager;
99
99
  return tryOrLog((node, accept) => {
100
- const tagname = "#" + node.name;
100
+ const tagname = node.name;
101
101
  const projectId = projectIdFrom(node);
102
102
  const sameTag = index.projectElements(projectId, ast.Tag).filter((n) => n.name === tagname && n.node !== node).head();
103
103
  if (sameTag) {
@@ -1,2 +1,2 @@
1
- import { ComputedView } from '@likec4/core';
1
+ import { type ComputedView } from '@likec4/core';
2
2
  export declare function assignNavigateTo<R extends Iterable<ComputedView>>(views: R): R;
@@ -1,9 +1,9 @@
1
- import { ComputedNode, ComputedView } from "@likec4/core";
1
+ import { isElementView } from "@likec4/core";
2
2
  import { find, isNullish } from "remeda";
3
3
  export function assignNavigateTo(views) {
4
4
  const allElementViews = /* @__PURE__ */ new Map();
5
5
  for (const v of views) {
6
- if (ComputedView.isElement(v) && v.viewOf && isNullish(v.extends)) {
6
+ if (isElementView(v) && v.viewOf && isNullish(v.extends)) {
7
7
  const viewsOf = allElementViews.get(v.viewOf) ?? [];
8
8
  viewsOf.push(v.id);
9
9
  allElementViews.set(v.viewOf, viewsOf);
@@ -11,7 +11,7 @@ export function assignNavigateTo(views) {
11
11
  }
12
12
  for (const { id, nodes } of views) {
13
13
  for (const node of nodes) {
14
- const modelRef = ComputedNode.modelRef(node);
14
+ const modelRef = node.modelRef;
15
15
  if (node.navigateTo || !modelRef) {
16
16
  continue;
17
17
  }
@@ -1,4 +1,4 @@
1
- import type { ComputedView, DiagramView, OverviewGraph, ProjectId, ViewId } from '@likec4/core';
1
+ import type { ComputedView, DiagramView, ProjectId, ViewId } from '@likec4/core';
2
2
  import { GraphvizLayouter } from '@likec4/layouts';
3
3
  import { CancellationToken } from 'vscode-jsonrpc';
4
4
  import type { LikeC4Services } from '../module';
@@ -18,7 +18,6 @@ export interface LikeC4Views {
18
18
  layoutView(viewId: ViewId, projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<GraphvizOut | null>;
19
19
  diagrams(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<Array<DiagramView>>;
20
20
  viewsAsGraphvizOut(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<Array<GraphvizSvgOut>>;
21
- overviewGraph(): Promise<OverviewGraph>;
22
21
  }
23
22
  export declare class DefaultLikeC4Views implements LikeC4Views {
24
23
  private services;
@@ -33,6 +32,5 @@ export declare class DefaultLikeC4Views implements LikeC4Views {
33
32
  layoutView(viewId: ViewId, projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<GraphvizOut | null>;
34
33
  diagrams(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<Array<DiagramView>>;
35
34
  viewsAsGraphvizOut(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<Array<GraphvizSvgOut>>;
36
- overviewGraph(): Promise<OverviewGraph>;
37
35
  }
38
36
  export {};
@@ -12,52 +12,62 @@ export class DefaultLikeC4Views {
12
12
  cache = /* @__PURE__ */ new WeakMap();
13
13
  viewsWithReportedErrors = /* @__PURE__ */ new Set();
14
14
  ModelBuilder;
15
- queue = new PQueue({ concurrency: 4, timeout: 1e4, throwOnTimeout: true });
15
+ queue = new PQueue({ concurrency: 2, timeout: 2e4, throwOnTimeout: true });
16
16
  get layouter() {
17
17
  return this.services.likec4.Layouter;
18
18
  }
19
19
  async computedViews(projectId, cancelToken = CancellationToken.None) {
20
20
  const likeC4Model = await this.ModelBuilder.buildLikeC4Model(projectId, cancelToken);
21
- return values(likeC4Model.$model.views);
21
+ return values(likeC4Model.$data.views);
22
22
  }
23
23
  async layoutAllViews(projectId, cancelToken = CancellationToken.None) {
24
- const views = await this.computedViews(projectId, cancelToken);
24
+ const likeC4Model = await this.ModelBuilder.buildLikeC4Model(projectId, cancelToken);
25
+ const views = values(likeC4Model.$data.views);
25
26
  if (views.length === 0) {
26
27
  return [];
27
28
  }
28
29
  const logger = rootLogger.getChild(["views", projectId ?? ""]);
29
30
  logger.debug`layoutAll: ${views.length} views`;
31
+ if (this.queue.pending + this.queue.size > 0) {
32
+ logger.debug`wait for previous layouts to finish`;
33
+ await this.queue.onIdle();
34
+ }
35
+ if (this.layouter.port.concurrency !== this.queue.concurrency) {
36
+ this.queue.concurrency = this.layouter.port.concurrency;
37
+ logger.debug`set queue concurrency to ${this.layouter.port.concurrency}`;
38
+ }
39
+ const specification = likeC4Model.$data.specification;
30
40
  const results = [];
31
- const tasks = [];
32
41
  for (const view of views) {
33
- this.viewsWithReportedErrors.delete(view.id);
34
- tasks.push(
35
- Promise.resolve().then(async () => {
36
- const result = await this.queue.add(async () => {
37
- logger.debug`layouting view ${view.id}...`;
38
- return await this.layouter.layout(view);
39
- });
40
- if (!result) {
41
- return Promise.reject(new Error(`Failed to layout view ${view.id}`));
42
- }
43
- logger.debug`done layout view ${view.id}`;
44
- this.viewsWithReportedErrors.delete(view.id);
45
- this.cache.set(view, result);
46
- return result;
47
- }).catch((e) => {
48
- logger.warn(`fail layout view ${view.id}`, { e });
49
- this.cache.delete(view);
50
- return Promise.reject(e);
51
- })
52
- );
53
- }
54
- for (const task of await Promise.allSettled(tasks)) {
55
- if (task.status === "fulfilled") {
56
- results.push(task.value);
57
- } else {
58
- logger.error(loggable(task.reason));
42
+ let cached = this.cache.get(view);
43
+ if (cached) {
44
+ logger.debug`layout ${view.id} from cache`;
45
+ results.push(cached);
46
+ continue;
59
47
  }
48
+ if (this.queue.pending > this.queue.concurrency + 4) {
49
+ await this.queue.onSizeLessThan(this.queue.concurrency + 1);
50
+ }
51
+ this.queue.add(async () => {
52
+ logger.debug`layouting view ${view.id}...`;
53
+ return await this.layouter.layout({
54
+ view,
55
+ specification
56
+ });
57
+ }).then((result) => {
58
+ if (!result) {
59
+ throw new Error(`Layout queue returned null for view ${view.id}`);
60
+ }
61
+ this.viewsWithReportedErrors.delete(view.id);
62
+ logger.debug`done layout view ${view.id}`;
63
+ this.cache.set(view, result);
64
+ results.push(result);
65
+ }).catch((e) => {
66
+ logger.error(`Fail layout view ${view.id}`, { e });
67
+ this.cache.delete(view);
68
+ });
60
69
  }
70
+ await this.queue.onIdle();
61
71
  if (results.length !== views.length) {
62
72
  logger.warn`layouted ${results.length} of ${views.length} views`;
63
73
  } else if (results.length > 0) {
@@ -80,9 +90,16 @@ export class DefaultLikeC4Views {
80
90
  }
81
91
  try {
82
92
  const start = performance.now();
93
+ if (this.queue.pending + this.queue.size > 0) {
94
+ logger.debug`wait for previous layouts to finish`;
95
+ await this.queue.onIdle();
96
+ }
83
97
  const result = await this.queue.add(async () => {
84
98
  logger.debug`layouting view ${view.id}...`;
85
- return await this.layouter.layout(view);
99
+ return await this.layouter.layout({
100
+ view,
101
+ specification: model.$data.specification
102
+ });
86
103
  });
87
104
  if (!result) {
88
105
  throw new Error(`Failed to layout view ${viewId}`);
@@ -111,9 +128,16 @@ export class DefaultLikeC4Views {
111
128
  if (cache.has(KEY)) {
112
129
  return await Promise.resolve(cache.get(KEY));
113
130
  }
114
- const views = await this.computedViews(projectId, cancelToken);
131
+ const likeC4Model = await this.ModelBuilder.buildLikeC4Model(projectId, cancelToken);
132
+ const views = values(likeC4Model.$data.views);
133
+ if (views.length === 0) {
134
+ return [];
135
+ }
115
136
  const tasks = views.map(async (view) => {
116
- const { dot, svg } = await this.layouter.svg(view);
137
+ const { dot, svg } = await this.layouter.svg({
138
+ view,
139
+ specification: likeC4Model.$data.specification
140
+ });
117
141
  return {
118
142
  id: view.id,
119
143
  dot,
@@ -132,15 +156,15 @@ export class DefaultLikeC4Views {
132
156
  cache.set(KEY, succeed);
133
157
  return succeed;
134
158
  }
135
- async overviewGraph() {
136
- const KEY = "OverviewGraph";
137
- const cache = this.services.ValidatedWorkspaceCache;
138
- if (cache.has(KEY)) {
139
- return await Promise.resolve(cache.get(KEY));
140
- }
141
- const views = await this.computedViews();
142
- const overviewGraph = await this.layouter.layoutOverviewGraph(views);
143
- cache.set(KEY, overviewGraph);
144
- return overviewGraph;
145
- }
159
+ // async overviewGraph(): Promise<OverviewGraph> {
160
+ // const KEY = 'OverviewGraph'
161
+ // const cache = this.services.ValidatedWorkspaceCache as WorkspaceCache<string, OverviewGraph>
162
+ // if (cache.has(KEY)) {
163
+ // return await Promise.resolve(cache.get(KEY)!)
164
+ // }
165
+ // const views = await this.computedViews()
166
+ // const overviewGraph = await this.layouter.layoutOverviewGraph(views)
167
+ // cache.set(KEY, overviewGraph)
168
+ // return overviewGraph
169
+ // }
146
170
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@likec4/language-server",
3
3
  "description": "LikeC4 Language Server",
4
- "version": "1.31.0",
4
+ "version": "1.32.0",
5
5
  "license": "MIT",
6
6
  "bugs": "https://github.com/likec4/likec4/issues",
7
7
  "homepage": "https://likec4.dev",
@@ -89,21 +89,20 @@
89
89
  "access": "public"
90
90
  },
91
91
  "dependencies": {
92
- "@hpcc-js/wasm-graphviz": "1.7.0",
93
- "vscode-jsonrpc": "8.2.0",
94
- "vscode-uri": "3.1.0"
92
+ "@hpcc-js/wasm-graphviz": "1.7.0"
95
93
  },
96
94
  "devDependencies": {
95
+ "@types/chroma-js": "^3.1.1",
97
96
  "@modelcontextprotocol/sdk": "^1.10.2",
98
- "express": "^5.1.0",
99
97
  "@msgpack/msgpack": "^3.1.1",
100
98
  "@smithy/util-base64": "^4.0.0",
101
- "@types/express": "^5.0.1",
102
- "@types/node": "^20.17.30",
99
+ "@types/express": "^5.0.2",
100
+ "@types/node": "^20.19.0",
103
101
  "@types/picomatch": "^4.0.0",
104
- "picomatch": "^4.0.2",
105
102
  "@types/which": "^3.0.4",
103
+ "chroma-js": "^3.1.2",
106
104
  "esm-env": "^1.2.2",
105
+ "express": "^5.1.0",
107
106
  "fast-equals": "^5.2.2",
108
107
  "fdir": "^6.4.4",
109
108
  "indent-string": "^5.0.0",
@@ -114,27 +113,30 @@
114
113
  "p-debounce": "^4.0.0",
115
114
  "p-queue": "^8.1.0",
116
115
  "p-timeout": "^6.1.4",
116
+ "picomatch": "^4.0.2",
117
117
  "pretty-ms": "^9.2.0",
118
- "remeda": "^2.21.3",
118
+ "remeda": "^2.23.0",
119
119
  "strip-indent": "^4.0.0",
120
- "tsx": "~4.19.3",
121
- "turbo": "^2.5.2",
122
- "type-fest": "^4.40.0",
120
+ "tsx": "~4.19.4",
121
+ "turbo": "^2.5.4",
122
+ "type-fest": "^4.41.0",
123
123
  "typescript": "^5.8.3",
124
124
  "ufo": "^1.6.1",
125
125
  "unbuild": "^3.5.0",
126
126
  "valibot": "^1.0.0",
127
- "zod": "^3.24.3",
128
- "vitest": "^3.1.2",
127
+ "vitest": "^3.2.3",
128
+ "vscode-jsonrpc": "8.2.0",
129
129
  "vscode-languageserver": "9.0.1",
130
130
  "vscode-languageserver-protocol": "3.17.5",
131
131
  "vscode-languageserver-types": "3.17.5",
132
+ "vscode-uri": "3.1.0",
132
133
  "which": "^5.0.0",
133
- "@likec4/core": "1.31.0",
134
- "@likec4/icons": "1.31.0",
135
- "@likec4/layouts": "1.31.0",
136
- "@likec4/log": "1.31.0",
137
- "@likec4/tsconfig": "1.31.0"
134
+ "zod": "^3.24.3",
135
+ "@likec4/core": "1.32.0",
136
+ "@likec4/icons": "1.32.0",
137
+ "@likec4/layouts": "1.32.0",
138
+ "@likec4/log": "1.32.0",
139
+ "@likec4/tsconfig": "1.32.0"
138
140
  },
139
141
  "scripts": {
140
142
  "typecheck": "tsc -b --verbose",