@likec4/language-server 1.32.0 → 1.32.2

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 (45) hide show
  1. package/dist/ast.d.ts +1 -0
  2. package/dist/ast.js +4 -1
  3. package/dist/bundled.mjs +2314 -2312
  4. package/dist/config/schema.d.ts +2 -2
  5. package/dist/config/schema.js +8 -11
  6. package/dist/formatting/LikeC4Formatter.js +2 -2
  7. package/dist/generated/ast.d.ts +30 -6
  8. package/dist/generated/ast.js +44 -9
  9. package/dist/generated/grammar.js +1 -1
  10. package/dist/mcp/LikeC4MCPServerFactory.d.ts +4 -0
  11. package/dist/mcp/LikeC4MCPServerFactory.js +6 -0
  12. package/dist/mcp/sseserver/MCPServer.d.ts +4 -2
  13. package/dist/mcp/sseserver/MCPServer.js +12 -6
  14. package/dist/mcp/sseserver/with-mcp-server.js +22 -6
  15. package/dist/model/model-builder.js +20 -19
  16. package/dist/model/model-parser.d.ts +9 -0
  17. package/dist/model/parser/Base.d.ts +1 -0
  18. package/dist/model/parser/Base.js +22 -0
  19. package/dist/model/parser/DeploymentModelParser.d.ts +1 -0
  20. package/dist/model/parser/DeploymentModelParser.js +7 -5
  21. package/dist/model/parser/DeploymentViewParser.d.ts +1 -0
  22. package/dist/model/parser/FqnRefParser.d.ts +1 -0
  23. package/dist/model/parser/GlobalsParser.d.ts +1 -0
  24. package/dist/model/parser/ImportsParser.d.ts +1 -0
  25. package/dist/model/parser/ModelParser.d.ts +1 -0
  26. package/dist/model/parser/ModelParser.js +7 -5
  27. package/dist/model/parser/PredicatesParser.d.ts +1 -0
  28. package/dist/model/parser/SpecificationParser.d.ts +1 -0
  29. package/dist/model/parser/SpecificationParser.js +4 -2
  30. package/dist/model/parser/ViewsParser.d.ts +1 -0
  31. package/dist/module.d.ts +2 -2
  32. package/dist/module.js +4 -4
  33. package/dist/utils/index.d.ts +5 -0
  34. package/dist/utils/index.js +19 -0
  35. package/dist/validation/index.d.ts +1 -1
  36. package/dist/validation/index.js +10 -3
  37. package/dist/validation/property-checks.d.ts +1 -0
  38. package/dist/validation/property-checks.js +62 -0
  39. package/dist/views/configurable-layouter.d.ts +2 -2
  40. package/dist/views/configurable-layouter.js +4 -2
  41. package/dist/views/likec4-views.d.ts +2 -3
  42. package/dist/views/likec4-views.js +29 -50
  43. package/dist/workspace/ProjectsManager.d.ts +0 -1
  44. package/dist/workspace/ProjectsManager.js +15 -4
  45. package/package.json +16 -16
@@ -1,3 +1,4 @@
1
+ import prettyMs from "pretty-ms";
1
2
  import { logger } from "../logger.js";
2
3
  export * from "./disposable.js";
3
4
  export * from "./elementRef.js";
@@ -12,3 +13,21 @@ export function safeCall(fn) {
12
13
  return void 0;
13
14
  }
14
15
  }
16
+ export function performanceNow() {
17
+ try {
18
+ return performance.now();
19
+ } catch (e) {
20
+ return Date.now();
21
+ }
22
+ }
23
+ export function performanceMark() {
24
+ const t0 = performanceNow();
25
+ return {
26
+ get ms() {
27
+ return performanceNow() - t0;
28
+ },
29
+ get pretty() {
30
+ return prettyMs(performanceNow() - t0);
31
+ }
32
+ };
33
+ }
@@ -3,7 +3,7 @@ import { type LikeC4LangiumDocument, ast } from '../ast';
3
3
  import type { LikeC4Services } from '../module';
4
4
  type Guard<N extends AstNode> = (n: AstNode) => n is N;
5
5
  type Guarded<G> = G extends Guard<infer N> ? N : never;
6
- declare const isValidatableAstNode: (n: AstNode) => n is ast.DeployedInstance | ast.DeploymentNode | ast.DeploymentViewRulePredicate | ast.DeploymentViewRuleStyle | ast.ViewRuleAutoLayout | ast.DynamicViewGlobalPredicateRef | ast.DynamicViewIncludePredicate | ast.ViewRuleGlobalStyle | ast.ViewRuleStyle | ast.ElementStringProperty | ast.ElementStyleProperty | ast.IconProperty | ast.LinkProperty | ast.MetadataBody | ast.ElementKindExpression | ast.ElementTagExpression | ast.FqnRefExpr | ast.WildcardExpression | ast.FqnExprWhere | ast.FqnExprWith | ast.DirectedRelationExpr | ast.InOutRelationExpr | ast.IncomingRelationExpr | ast.OutgoingRelationExpr | ast.RelationExprWhere | ast.RelationExprWith | ast.Element | ast.ExtendDeployment | ast.ExtendElement | ast.Imported | ast.DeploymentView | ast.DynamicView | ast.ElementView | ast.RelationStringProperty | ast.ArrowProperty | ast.ColorProperty | ast.LineProperty | ast.PaddingSizeProperty | ast.ShapeSizeProperty | ast.TextSizeProperty | ast.MetadataAttribute | ast.NotationProperty | ast.NotesProperty | ast.SpecificationElementStringProperty | ast.SpecificationRelationshipStringProperty | ast.ViewStringProperty | ast.BorderProperty | ast.MultipleProperty | ast.OpacityProperty | ast.ShapeProperty | ast.ViewRuleGlobalPredicateRef | ast.ViewRuleGroup | ast.ViewRulePredicate | ast.SpecificationRelationshipKind | ast.GlobalStyle | ast.SpecificationColor | ast.NavigateToProperty | ast.DynamicViewStep | ast.ElementRef | ast.DeploymentRelation | ast.Tags | ast.SpecificationDeploymentNodeKind | ast.DynamicViewParallelSteps | ast.GlobalDynamicPredicateGroup | ast.Relation | ast.SpecificationElementKind | ast.Globals | ast.GlobalPredicateGroup | ast.GlobalStyleGroup | ast.ImportsFromPoject | ast.SpecificationRule | ast.SpecificationTag;
6
+ declare const isValidatableAstNode: (n: AstNode) => n is ast.HexColor | ast.RGBAColor | ast.DeployedInstance | ast.DeploymentNode | ast.DeploymentViewRulePredicate | ast.DeploymentViewRuleStyle | ast.ViewRuleAutoLayout | ast.DynamicViewGlobalPredicateRef | ast.DynamicViewIncludePredicate | ast.ViewRuleGlobalStyle | ast.ViewRuleStyle | ast.ElementStringProperty | ast.ElementStyleProperty | ast.IconProperty | ast.LinkProperty | ast.MetadataBody | ast.ElementKindExpression | ast.ElementTagExpression | ast.FqnRefExpr | ast.WildcardExpression | ast.FqnExprWhere | ast.FqnExprWith | ast.DirectedRelationExpr | ast.InOutRelationExpr | ast.IncomingRelationExpr | ast.OutgoingRelationExpr | ast.RelationExprWhere | ast.RelationExprWith | ast.Element | ast.ExtendDeployment | ast.ExtendElement | ast.Imported | ast.DeploymentView | ast.DynamicView | ast.ElementView | ast.RelationStringProperty | ast.ArrowProperty | ast.ColorProperty | ast.LineProperty | ast.PaddingSizeProperty | ast.ShapeSizeProperty | ast.TextSizeProperty | ast.MetadataAttribute | ast.NotationProperty | ast.NotesProperty | ast.SpecificationElementStringProperty | ast.SpecificationRelationshipStringProperty | ast.ViewStringProperty | ast.BorderProperty | ast.MultipleProperty | ast.OpacityProperty | ast.ShapeProperty | ast.ViewRuleGlobalPredicateRef | ast.ViewRuleGroup | ast.ViewRulePredicate | ast.SpecificationRelationshipKind | ast.GlobalStyle | ast.SpecificationColor | ast.NavigateToProperty | ast.DynamicViewStep | ast.ElementRef | ast.DeploymentRelation | ast.Tags | ast.SpecificationDeploymentNodeKind | ast.DynamicViewParallelSteps | ast.GlobalDynamicPredicateGroup | ast.Relation | ast.SpecificationElementKind | ast.Globals | ast.GlobalPredicateGroup | ast.GlobalStyleGroup | ast.SpecificationTag | ast.ImportsFromPoject | ast.SpecificationRule;
7
7
  type ValidatableAstNode = Guarded<typeof isValidatableAstNode>;
8
8
  export declare function checksFromDiagnostics(doc: LikeC4LangiumDocument): {
9
9
  isValid: (n: ValidatableAstNode) => boolean;
@@ -13,7 +13,12 @@ import { dynamicViewStep } from "./dynamic-view-step.js";
13
13
  import { checkElement } from "./element.js";
14
14
  import { checkElementRef } from "./element-ref.js";
15
15
  import { checkImported, checkImportsFromPoject } from "./imports.js";
16
- import { iconPropertyRuleChecks, notesPropertyRuleChecks, opacityPropertyRuleChecks } from "./property-checks.js";
16
+ import {
17
+ colorLiteralRuleChecks,
18
+ iconPropertyRuleChecks,
19
+ notesPropertyRuleChecks,
20
+ opacityPropertyRuleChecks
21
+ } from "./property-checks.js";
17
22
  import { checkRelationBody, relationChecks } from "./relation.js";
18
23
  import {
19
24
  checkDeploymentNodeKind,
@@ -82,7 +87,8 @@ const isValidatableAstNode = validatableAstNodeGuards([
82
87
  ast.isSpecificationDeploymentNodeKind,
83
88
  ast.isSpecificationTag,
84
89
  ast.isSpecificationColor,
85
- ast.isSpecificationRule
90
+ ast.isSpecificationRule,
91
+ ast.isColorLiteral
86
92
  ]);
87
93
  const findInvalidContainer = (node) => {
88
94
  let nd = node;
@@ -147,7 +153,8 @@ export function registerValidationChecks(services) {
147
153
  IncomingRelationExpr: checkIncomingRelationExpr(services),
148
154
  OutgoingRelationExpr: checkOutgoingRelationExpr(services),
149
155
  ImportsFromPoject: checkImportsFromPoject(services),
150
- Imported: checkImported(services)
156
+ Imported: checkImported(services),
157
+ ColorLiteral: colorLiteralRuleChecks(services)
151
158
  });
152
159
  const connection = services.shared.lsp.Connection;
153
160
  if (connection) {
@@ -4,3 +4,4 @@ import type { LikeC4Services } from '../module';
4
4
  export declare const opacityPropertyRuleChecks: (_: LikeC4Services) => ValidationCheck<ast.OpacityProperty>;
5
5
  export declare const iconPropertyRuleChecks: (_: LikeC4Services) => ValidationCheck<ast.IconProperty>;
6
6
  export declare const notesPropertyRuleChecks: (_: LikeC4Services) => ValidationCheck<ast.NotesProperty>;
7
+ export declare const colorLiteralRuleChecks: (_: LikeC4Services) => ValidationCheck<ast.ColorLiteral>;
@@ -1,4 +1,6 @@
1
+ import { nonexhaustive } from "@likec4/core";
1
2
  import { AstUtils } from "langium";
3
+ import { isNumber, isString } from "remeda";
2
4
  import { ast } from "../ast.js";
3
5
  import { tryOrLog } from "./_shared.js";
4
6
  export const opacityPropertyRuleChecks = (_) => {
@@ -43,3 +45,63 @@ export const notesPropertyRuleChecks = (_) => {
43
45
  }
44
46
  };
45
47
  };
48
+ export const colorLiteralRuleChecks = (_) => {
49
+ return (node, accept) => {
50
+ if (node.$type === "HexColor") {
51
+ if (node.hex === void 0) {
52
+ accept("error", `Invalid HEX`, {
53
+ node,
54
+ property: "hex"
55
+ });
56
+ return;
57
+ }
58
+ const length = isNumber(node.hex) ? node.hex.toString().length : node.hex.length;
59
+ if (length !== 6 && length !== 3 && length !== 8) {
60
+ accept("error", `Invalid value "${node.$cstNode?.text}", must be 3, 6 or 8 characters long`, {
61
+ node,
62
+ property: "hex"
63
+ });
64
+ }
65
+ return;
66
+ }
67
+ if (node.$type === "RGBAColor") {
68
+ if (!isNumber(node.red) || node.red < 0 || node.red > 255) {
69
+ accept("error", `Invalid value, must be between 0 and 255`, {
70
+ node,
71
+ property: "red"
72
+ });
73
+ }
74
+ if (!isNumber(node.green) || node.green < 0 || node.green > 255) {
75
+ accept("error", `Invalid value, must be between 0 and 255`, {
76
+ node,
77
+ property: "green"
78
+ });
79
+ }
80
+ if (!isNumber(node.blue) || node.blue < 0 || node.blue > 255) {
81
+ accept("error", `Invalid value, must be between 0 and 255`, {
82
+ node,
83
+ property: "blue"
84
+ });
85
+ }
86
+ if (isNumber(node.alpha)) {
87
+ if (node.alpha < 0 || node.alpha > 1) {
88
+ accept("error", `Invalid value, must be between 0 and 1`, {
89
+ node,
90
+ property: "alpha"
91
+ });
92
+ }
93
+ }
94
+ if (isString(node.alpha)) {
95
+ const alpha = parseFloat(node.alpha);
96
+ if (alpha < 0 || alpha > 100) {
97
+ accept("error", `Invalid value, must be between 0% and 100%`, {
98
+ node,
99
+ property: "alpha"
100
+ });
101
+ }
102
+ }
103
+ return;
104
+ }
105
+ nonexhaustive(node);
106
+ };
107
+ };
@@ -1,7 +1,7 @@
1
- import { GraphvizLayouter } from '@likec4/layouts';
1
+ import { QueueGraphvizLayoter } from '@likec4/layouts';
2
2
  import type { LikeC4Services } from '../module';
3
3
  export declare const ConfigurableLayouter: {
4
4
  likec4: {
5
- Layouter(services: LikeC4Services): GraphvizLayouter;
5
+ Layouter(services: LikeC4Services): QueueGraphvizLayoter;
6
6
  };
7
7
  };
@@ -1,4 +1,4 @@
1
- import { GraphvizLayouter, GraphvizWasmAdapter } from "@likec4/layouts";
1
+ import { GraphvizWasmAdapter, QueueGraphvizLayoter } from "@likec4/layouts";
2
2
  import { GraphvizBinaryAdapter } from "@likec4/layouts/graphviz/binary";
3
3
  import { isEmpty } from "remeda";
4
4
  import which from "which";
@@ -16,7 +16,9 @@ export const ConfigurableLayouter = {
16
16
  Layouter(services) {
17
17
  logger.debug("Creating ConfigurableLayouter");
18
18
  const wasmAdapter = new GraphvizWasmAdapter();
19
- const layouter = new GraphvizLayouter(wasmAdapter);
19
+ const layouter = new QueueGraphvizLayoter({
20
+ graphviz: wasmAdapter
21
+ });
20
22
  const langId = services.LanguageMetaData.languageId;
21
23
  services.shared.workspace.ConfigurationProvider.onConfigurationSectionUpdate((update) => {
22
24
  logger.debug("Configuration update: {update}", { update });
@@ -1,5 +1,5 @@
1
1
  import type { ComputedView, DiagramView, ProjectId, ViewId } from '@likec4/core';
2
- import { GraphvizLayouter } from '@likec4/layouts';
2
+ import { type QueueGraphvizLayoter, GraphvizLayouter } from '@likec4/layouts';
3
3
  import { CancellationToken } from 'vscode-jsonrpc';
4
4
  import type { LikeC4Services } from '../module';
5
5
  export type GraphvizOut = {
@@ -24,9 +24,8 @@ export declare class DefaultLikeC4Views implements LikeC4Views {
24
24
  private cache;
25
25
  private viewsWithReportedErrors;
26
26
  private ModelBuilder;
27
- private queue;
28
27
  constructor(services: LikeC4Services);
29
- get layouter(): GraphvizLayouter;
28
+ get layouter(): QueueGraphvizLayoter;
30
29
  computedViews(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<ComputedView[]>;
31
30
  layoutAllViews(projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<Array<Readonly<GraphvizOut>>>;
32
31
  layoutView(viewId: ViewId, projectId?: ProjectId | undefined, cancelToken?: CancellationToken): Promise<GraphvizOut | null>;
@@ -1,9 +1,9 @@
1
1
  import { loggable } from "@likec4/log";
2
- import PQueue from "p-queue";
3
- import prettyMs from "pretty-ms";
4
2
  import { values } from "remeda";
5
3
  import { CancellationToken } from "vscode-jsonrpc";
6
4
  import { logError, logger as rootLogger, logWarnError } from "../logger.js";
5
+ import { performanceMark } from "../utils/index.js";
6
+ const viewsLogger = rootLogger.getChild("views");
7
7
  export class DefaultLikeC4Views {
8
8
  constructor(services) {
9
9
  this.services = services;
@@ -12,7 +12,6 @@ export class DefaultLikeC4Views {
12
12
  cache = /* @__PURE__ */ new WeakMap();
13
13
  viewsWithReportedErrors = /* @__PURE__ */ new Set();
14
14
  ModelBuilder;
15
- queue = new PQueue({ concurrency: 2, timeout: 2e4, throwOnTimeout: true });
16
15
  get layouter() {
17
16
  return this.services.likec4.Layouter;
18
17
  }
@@ -26,16 +25,10 @@ export class DefaultLikeC4Views {
26
25
  if (views.length === 0) {
27
26
  return [];
28
27
  }
29
- const logger = rootLogger.getChild(["views", projectId ?? ""]);
28
+ const m0 = performanceMark();
29
+ const logger = projectId ? viewsLogger.getChild(projectId) : viewsLogger;
30
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
- }
31
+ const tasks = [];
39
32
  const specification = likeC4Model.$data.specification;
40
33
  const results = [];
41
34
  for (const view of views) {
@@ -45,40 +38,36 @@ export class DefaultLikeC4Views {
45
38
  results.push(cached);
46
39
  continue;
47
40
  }
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}`);
41
+ tasks.push({
42
+ view,
43
+ specification
44
+ });
45
+ }
46
+ if (tasks.length > 0) {
47
+ await this.layouter.batchLayout({
48
+ batch: tasks,
49
+ onSuccess: (task, result) => {
50
+ this.viewsWithReportedErrors.delete(task.view.id);
51
+ this.cache.set(task.view, result);
52
+ results.push(result);
53
+ },
54
+ onError: (task, error) => {
55
+ logger.warn(`Fail layout view ${task.view.id}`, { error });
56
+ this.cache.delete(task.view);
60
57
  }
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
58
  });
69
59
  }
70
- await this.queue.onIdle();
71
60
  if (results.length !== views.length) {
72
- logger.warn`layouted ${results.length} of ${views.length} views`;
61
+ logger.warn`layouted ${results.length} of ${views.length} views in ${m0.pretty}`;
73
62
  } else if (results.length > 0) {
74
- logger.debug`layouted all ${results.length} views`;
63
+ logger.debug`layouted all ${results.length} views in ${m0.pretty}`;
75
64
  }
76
65
  return results;
77
66
  }
78
67
  async layoutView(viewId, projectId, cancelToken = CancellationToken.None) {
79
68
  const model = await this.ModelBuilder.buildLikeC4Model(projectId, cancelToken);
80
69
  const view = model.findView(viewId)?.$view;
81
- const logger = rootLogger.getChild(["views", projectId ?? ""]);
70
+ const logger = projectId ? viewsLogger.getChild(projectId) : viewsLogger;
82
71
  if (!view) {
83
72
  logger.warn`layoutView ${viewId} not found`;
84
73
  return null;
@@ -89,24 +78,14 @@ export class DefaultLikeC4Views {
89
78
  return await Promise.resolve(cached);
90
79
  }
91
80
  try {
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
- }
97
- const result = await this.queue.add(async () => {
98
- logger.debug`layouting view ${view.id}...`;
99
- return await this.layouter.layout({
100
- view,
101
- specification: model.$data.specification
102
- });
81
+ const m0 = performanceMark();
82
+ const result = await this.layouter.layout({
83
+ view,
84
+ specification: model.$data.specification
103
85
  });
104
- if (!result) {
105
- throw new Error(`Failed to layout view ${viewId}`);
106
- }
107
86
  this.viewsWithReportedErrors.delete(viewId);
108
87
  this.cache.set(view, result);
109
- logger.debug(`layout {viewId} ready in ${prettyMs(performance.now() - start)}`, { viewId });
88
+ logger.debug(`layout {viewId} ready in ${m0.pretty}`, { viewId });
110
89
  return result;
111
90
  } catch (e) {
112
91
  if (!this.viewsWithReportedErrors.has(viewId)) {
@@ -50,7 +50,6 @@ export declare class ProjectsManager {
50
50
  * Checks if the provided file system entry is a valid project config file.
51
51
  *
52
52
  * @param entry The file system entry to check
53
- * @returns {boolean} Returns true if the entry is a valid config file, false otherwise.
54
53
  */
55
54
  loadConfigFile(entry: FileSystemNode): Promise<Project | undefined>;
56
55
  registerProject(configFile: URI): Promise<Project>;
@@ -1,4 +1,5 @@
1
1
  import { BiMap, invariant, nonNullable } from "@likec4/core";
2
+ import { loggable } from "@likec4/log";
2
3
  import { URI, WorkspaceCache } from "langium";
3
4
  import picomatch from "picomatch/posix";
4
5
  import { hasAtLeast, isNullish, map, pipe, prop, sortBy } from "remeda";
@@ -9,7 +10,7 @@ import {
9
10
  withoutProtocol,
10
11
  withProtocol
11
12
  } from "ufo";
12
- import { parseConfigJson } from "../config/index.js";
13
+ import { parseConfigJson, validateConfig } from "../config/index.js";
13
14
  import { logger as mainLogger } from "../logger.js";
14
15
  const logger = mainLogger.getChild("ProjectsManager");
15
16
  export class ProjectsManager {
@@ -115,14 +116,23 @@ export class ProjectsManager {
115
116
  * Checks if the provided file system entry is a valid project config file.
116
117
  *
117
118
  * @param entry The file system entry to check
118
- * @returns {boolean} Returns true if the entry is a valid config file, false otherwise.
119
119
  */
120
120
  async loadConfigFile(entry) {
121
121
  if (entry.isDirectory) {
122
122
  return void 0;
123
123
  }
124
124
  if (this.isConfigFile(entry)) {
125
- return await this.registerProject(entry.uri);
125
+ try {
126
+ return await this.registerProject(entry.uri);
127
+ } catch (error) {
128
+ this.services.lsp.Connection?.window.showErrorMessage(
129
+ `LikeC4: Failed to register project at ${entry.uri.toString()}
130
+
131
+ ${loggable(error)}`
132
+ );
133
+ logger.error("Failed to register project at {uri}", { uri: entry.uri.toString(), error });
134
+ return void 0;
135
+ }
126
136
  }
127
137
  return void 0;
128
138
  }
@@ -135,7 +145,8 @@ export class ProjectsManager {
135
145
  const folderUri2 = configFile.with({ path });
136
146
  return this.registerProject({ config: config2, folderUri: folderUri2 });
137
147
  }
138
- const { config, folderUri } = opts;
148
+ const config = validateConfig(opts.config);
149
+ const { folderUri } = opts;
139
150
  let id = config.name;
140
151
  let i = 1;
141
152
  while (this.projectIdToFolder.has(id)) {
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.32.0",
4
+ "version": "1.32.2",
5
5
  "license": "MIT",
6
6
  "bugs": "https://github.com/likec4/likec4/issues",
7
7
  "homepage": "https://likec4.dev",
@@ -93,11 +93,11 @@
93
93
  },
94
94
  "devDependencies": {
95
95
  "@types/chroma-js": "^3.1.1",
96
- "@modelcontextprotocol/sdk": "^1.10.2",
96
+ "@modelcontextprotocol/sdk": "^1.12.1",
97
97
  "@msgpack/msgpack": "^3.1.1",
98
98
  "@smithy/util-base64": "^4.0.0",
99
99
  "@types/express": "^5.0.2",
100
- "@types/node": "^20.19.0",
100
+ "@types/node": "~20.19.0",
101
101
  "@types/picomatch": "^4.0.0",
102
102
  "@types/which": "^3.0.4",
103
103
  "chroma-js": "^3.1.2",
@@ -117,26 +117,26 @@
117
117
  "pretty-ms": "^9.2.0",
118
118
  "remeda": "^2.23.0",
119
119
  "strip-indent": "^4.0.0",
120
- "tsx": "~4.19.4",
121
- "turbo": "^2.5.4",
120
+ "tsx": "4.19.4",
121
+ "turbo": "2.5.4",
122
122
  "type-fest": "^4.41.0",
123
- "typescript": "^5.8.3",
123
+ "typescript": "5.8.3",
124
124
  "ufo": "^1.6.1",
125
- "unbuild": "^3.5.0",
126
- "valibot": "^1.0.0",
127
- "vitest": "^3.2.3",
125
+ "unbuild": "3.5.0",
126
+ "valibot": "^1.1.0",
127
+ "vitest": "3.2.3",
128
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
132
  "vscode-uri": "3.1.0",
133
133
  "which": "^5.0.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"
134
+ "zod": "^3.25.64",
135
+ "@likec4/icons": "1.32.2",
136
+ "@likec4/core": "1.32.2",
137
+ "@likec4/tsconfig": "1.32.2",
138
+ "@likec4/layouts": "1.32.2",
139
+ "@likec4/log": "1.32.2"
140
140
  },
141
141
  "scripts": {
142
142
  "typecheck": "tsc -b --verbose",
@@ -148,7 +148,7 @@
148
148
  "generate": "langium generate && tsx scripts/generate-icons.ts",
149
149
  "dev": "run-p \"watch:*\"",
150
150
  "lint": "run -T eslint src/ --fix",
151
- "clean": "rm -r -f dist contrib",
151
+ "clean": "pnpm rimraf dist contrib lib src/generated src/generated-lib",
152
152
  "test": "vitest run --no-isolate",
153
153
  "test-dbg": "vitest run --no-isolate -t formating",
154
154
  "vitest:ui": "vitest --no-isolate --ui",