@likec4/language-server 1.46.2 → 1.46.4

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.
@@ -1,12 +1,12 @@
1
+ var _a;
1
2
  import { isLikeC4Config, normalizeIncludeConfig, validateProjectConfig, } from '@likec4/config';
2
- import { BiMap, delay, invariant, memoizeProp, nonNullable } from '@likec4/core/utils';
3
+ import { BiMap, DefaultMap, invariant, memoizeProp, nonNullable } from '@likec4/core/utils';
3
4
  import { wrapError } from '@likec4/log';
4
5
  import { deepEqual } from 'fast-equals';
5
6
  import { interruptAndCheck, URI, WorkspaceCache, } from 'langium';
6
7
  import picomatch from 'picomatch';
7
8
  import { hasAtLeast, isNullish, map, pipe, prop, sortBy } from 'remeda';
8
- import { joinRelativeURL, parseFilename, withoutProtocol, withTrailingSlash, } from 'ufo';
9
- import { isLikeC4Builtin } from '../likec4lib';
9
+ import { cleanDoubleSlashes, isRelative, joinRelativeURL, joinURL, parseFilename, withoutProtocol, withTrailingSlash, } from 'ufo';
10
10
  import { logger as mainLogger } from '../logger';
11
11
  const logger = mainLogger.getChild('ProjectsManager');
12
12
  function normalizeUri(uri) {
@@ -21,6 +21,13 @@ function normalizeUri(uri) {
21
21
  return uri.uri.toString();
22
22
  }
23
23
  }
24
+ /**
25
+ * Returns a predicate that checks if the given path is included in the project folder.
26
+ */
27
+ function isParentFolderFor(uri) {
28
+ const path = normalizeUri(uri);
29
+ return (p) => path.startsWith(p.folder);
30
+ }
24
31
  export function ProjectFolder(folder) {
25
32
  folder = normalizeUri(folder);
26
33
  return withTrailingSlash(folder);
@@ -60,6 +67,23 @@ export class ProjectsManager {
60
67
  * This ensures that the most specific project is used for a document.
61
68
  */
62
69
  #projects = [];
70
+ /**
71
+ * This is a cached lookup for performance.
72
+ */
73
+ #lookupById = new DefaultMap((id) => {
74
+ if (id === _a.DefaultProjectId) {
75
+ const folderUri = this.getWorkspaceFolder();
76
+ return {
77
+ id,
78
+ config: DefaultProject.config,
79
+ folder: ProjectFolder(folderUri),
80
+ folderUri,
81
+ exclude: DefaultProject.exclude,
82
+ includeConfig: DefaultProject.includeConfig,
83
+ };
84
+ }
85
+ return nonNullable(this.#projects.find(p => p.id === id), `Project ${id} not found`);
86
+ });
63
87
  #excludedDocuments = new WeakMap();
64
88
  constructor(services) {
65
89
  this.services = services;
@@ -79,14 +103,14 @@ export class ProjectsManager {
79
103
  if (this.#projects.length > 1) {
80
104
  return undefined;
81
105
  }
82
- return this.#projects[0]?.id ?? ProjectsManager.DefaultProjectId;
106
+ return this.#projects[0]?.id ?? _a.DefaultProjectId;
83
107
  }
84
108
  set defaultProjectId(id) {
85
109
  if (id === this.#defaultProjectId) {
86
110
  return;
87
111
  }
88
112
  this.#defaultProject = undefined;
89
- if (!id || id === ProjectsManager.DefaultProjectId) {
113
+ if (!id || id === _a.DefaultProjectId) {
90
114
  logger.debug `reset default project ID`;
91
115
  this.#defaultProjectId = undefined;
92
116
  return;
@@ -97,7 +121,7 @@ export class ProjectsManager {
97
121
  }
98
122
  get default() {
99
123
  if (!this.#defaultProject) {
100
- const id = this.defaultProjectId ?? ProjectsManager.DefaultProjectId;
124
+ const id = this.defaultProjectId ?? _a.DefaultProjectId;
101
125
  let project = this.#projects.find(p => p.id === id);
102
126
  if (!project) {
103
127
  const folderUri = this.getWorkspaceFolder();
@@ -145,17 +169,17 @@ export class ProjectsManager {
145
169
  // ignore - workspace not initialized
146
170
  }
147
171
  return {
148
- id: ProjectsManager.DefaultProjectId,
172
+ id: _a.DefaultProjectId,
149
173
  config: DefaultProject.config,
150
174
  folderUri,
151
175
  };
152
176
  }
153
- const project = nonNullable(this.#projects.find(p => p.id === id), `Project "${id}" not found`);
177
+ const project = nonNullable(this.#lookupById.get(id), `Project ${id} not found`);
154
178
  return {
155
179
  id,
156
180
  folderUri: project.folderUri,
157
181
  config: project.config,
158
- ...(project.includePaths && { includePaths: project.includePaths.map(p => p.uri) }),
182
+ ...(project.includePaths && { includePaths: map(project.includePaths, prop('uri')) }),
159
183
  };
160
184
  }
161
185
  /**
@@ -164,8 +188,8 @@ export class ProjectsManager {
164
188
  * If there are multiple projects and default project is not set, throws an error
165
189
  */
166
190
  ensureProjectId(projectId) {
167
- if (projectId === ProjectsManager.DefaultProjectId) {
168
- return this.defaultProjectId ?? ProjectsManager.DefaultProjectId;
191
+ if (projectId === _a.DefaultProjectId) {
192
+ return this.defaultProjectId ?? _a.DefaultProjectId;
169
193
  }
170
194
  if (projectId) {
171
195
  invariant(this.#projectIdToFolder.has(projectId), `Project ID ${projectId} is not registered`);
@@ -190,7 +214,11 @@ export class ProjectsManager {
190
214
  if (typeof document === 'string' || URI.isUri(document)) {
191
215
  let docUriAsString = normalizeUri(document);
192
216
  const project = this.findProjectForDocument(docUriAsString);
193
- return project.exclude ? project.exclude(withoutProtocol(docUriAsString)) : false;
217
+ if (!project.exclude) {
218
+ return false;
219
+ }
220
+ const input = withoutProtocol(docUriAsString);
221
+ return project.exclude(input);
194
222
  }
195
223
  let isExcluded = this.#excludedDocuments.get(document);
196
224
  if (isExcluded === undefined) {
@@ -199,6 +227,25 @@ export class ProjectsManager {
199
227
  }
200
228
  return isExcluded;
201
229
  }
230
+ /**
231
+ * Checks if the specified document is included by the project:
232
+ * - if the document belongs to the project and is not excluded
233
+ * - if the document is included by the project
234
+ */
235
+ isIncluded(projectId, document) {
236
+ if (typeof document !== 'string' && !URI.isUri(document)) {
237
+ return this.isIncluded(projectId, document.uri);
238
+ }
239
+ const belongsTo = this.belongsTo(document);
240
+ if (belongsTo === projectId) {
241
+ return !this.isExcluded(document);
242
+ }
243
+ let includePaths = this.#lookupById.get(projectId)?.includePaths;
244
+ if (!includePaths) {
245
+ return false;
246
+ }
247
+ return includePaths.some(isParentFolderFor(document));
248
+ }
202
249
  /**
203
250
  * Checks if it is a config file and it is not excluded by default exclude pattern
204
251
  *
@@ -218,7 +265,7 @@ export class ProjectsManager {
218
265
  /**
219
266
  * Registers likec4 project by config file.
220
267
  */
221
- async registerConfigFile(configFile) {
268
+ async registerConfigFile(configFile, cancelToken) {
222
269
  if (DefaultProject.exclude(configFile.path)) {
223
270
  throw new Error(`Path to ${configFile.fsPath} is excluded by: ${DefaultProject.config.exclude.join(', ')}`);
224
271
  }
@@ -229,7 +276,7 @@ export class ProjectsManager {
229
276
  const config = await this.services.workspace.FileSystemProvider.loadProjectConfig(configFile);
230
277
  const path = joinRelativeURL(configFile.path, '..');
231
278
  const folderUri = configFile.with({ path });
232
- return await this.registerProject({ config, folderUri });
279
+ return await this.registerProject({ config, folderUri }, cancelToken);
233
280
  }
234
281
  catch (error) {
235
282
  this.services.lsp.Connection?.window.showErrorMessage(`LikeC4: Failed to register project at ${configFile.fsPath}`);
@@ -240,7 +287,7 @@ export class ProjectsManager {
240
287
  * Registers (or reloads) likec4 project by config file or config object.
241
288
  * If there is some project registered at same folder, it will be reloaded.
242
289
  */
243
- async registerProject(opts) {
290
+ async registerProject(opts, cancelToken) {
244
291
  const config = validateProjectConfig(opts.config);
245
292
  const folder = ProjectFolder(opts.folderUri);
246
293
  let project = this.#projects.find(p => p.folder === folder);
@@ -265,7 +312,9 @@ export class ProjectsManager {
265
312
  // if there is any project within subfolder or parent folder
266
313
  // we need to reset assigned to documents project IDs
267
314
  mustReset = this.#projects.some(p => p.folder.startsWith(folder) || folder.startsWith(p.folder));
268
- this.#projects = pipe([...this.#projects, project], sortBy([({ folder }) => withoutProtocol(folder).split('/').length, 'desc']));
315
+ this.#projects = pipe([...this.#projects, project], sortBy(
316
+ // sort by folder depth (longest first)
317
+ [({ folder }) => withoutProtocol(folder).split('/').length, 'desc']));
269
318
  logger.info `register project ${project.id} folder: ${folder}`;
270
319
  }
271
320
  else {
@@ -292,11 +341,20 @@ export class ProjectsManager {
292
341
  project.exclude = DefaultProject.exclude;
293
342
  }
294
343
  else if (hasAtLeast(config.exclude, 1)) {
295
- project.exclude = picomatch(config.exclude, { dot: true });
344
+ const patterns = map(config.exclude, p => {
345
+ if (!isRelative(p) && !p.startsWith('**')) {
346
+ p = joinURL('**', p);
347
+ }
348
+ return cleanDoubleSlashes(joinRelativeURL(project.folderUri.path, p));
349
+ });
350
+ project.exclude = picomatch(patterns, {
351
+ contains: true,
352
+ dot: true,
353
+ });
296
354
  }
297
355
  // Resolve include paths relative to project folder
298
356
  if (project.includeConfig.paths && hasAtLeast(project.includeConfig.paths, 1)) {
299
- project.includePaths = project.includeConfig.paths.map(includePath => {
357
+ project.includePaths = map(project.includeConfig.paths, includePath => {
300
358
  const resolvedPath = joinRelativeURL(project.folderUri.path, includePath);
301
359
  const uri = project.folderUri.with({ path: resolvedPath });
302
360
  return {
@@ -312,6 +370,7 @@ export class ProjectsManager {
312
370
  if (otherProject.id === project.id)
313
371
  continue;
314
372
  if (includePath.folder.startsWith(otherProject.folder) || otherProject.folder.startsWith(includePath.folder)) {
373
+ mustReset = true;
315
374
  logger.warn('Project "{projectId}" include path "{includePath}" overlaps with project "{otherProjectId}" folder. ' +
316
375
  'Files in overlapping areas will only belong to one project.', { projectId: project.id, includePath: includePath.folder, otherProjectId: otherProject.id });
317
376
  }
@@ -320,6 +379,7 @@ export class ProjectsManager {
320
379
  for (const otherIncludePath of otherProject.includePaths) {
321
380
  if (includePath.folder.startsWith(otherIncludePath.folder)
322
381
  || otherIncludePath.folder.startsWith(includePath.folder)) {
382
+ mustReset = true;
323
383
  logger.warn('Project "{projectId}" include path "{includePath}" overlaps with project "{otherProjectId}" ' +
324
384
  'include path "{otherIncludePath}". Files in overlapping areas will only belong to one project.', {
325
385
  projectId: project.id,
@@ -337,9 +397,10 @@ export class ProjectsManager {
337
397
  delete project.includePaths;
338
398
  }
339
399
  this.#projectIdToFolder.set(project.id, folder);
400
+ this.#lookupById.clear();
340
401
  // Reset assigned project IDs if no projects reload is active
341
402
  if (mustReset && !this.#activeReload) {
342
- await this.rebuidProject(project.id).catch(error => {
403
+ await this.rebuidProject(project.id, cancelToken).catch(error => {
343
404
  logger.warn('Failed to rebuild project {projectId} after config change', {
344
405
  projectId: project.id,
345
406
  error,
@@ -362,11 +423,11 @@ export class ProjectsManager {
362
423
  }).id;
363
424
  }
364
425
  #activeReload = null;
365
- async reloadProjects() {
426
+ async reloadProjects(cancelToken) {
366
427
  try {
367
428
  if (!this.#activeReload) {
368
429
  logger.debug `schedule reload projects`;
369
- this.#activeReload = this._reloadProjects();
430
+ this.#activeReload = this._reloadProjects(cancelToken);
370
431
  }
371
432
  else {
372
433
  logger.debug `reload projects is already in progress, waiting`;
@@ -377,49 +438,48 @@ export class ProjectsManager {
377
438
  this.#activeReload = null;
378
439
  }
379
440
  }
380
- async _reloadProjects() {
381
- // debounce reload projects
382
- await delay(200);
441
+ async _reloadProjects(cancelToken) {
383
442
  const folders = this.services.workspace.WorkspaceManager.workspaceFolders;
384
443
  if (!folders) {
385
444
  logger.warn('No workspace folders found');
386
445
  return;
387
446
  }
388
- await this.services.workspace.WorkspaceLock.write(async (cancelToken) => {
389
- logger.debug `start reload projects`;
390
- const configFiles = [];
391
- for (const folder of folders) {
392
- try {
393
- logger.debug `scan projects in folder ${folder.uri}`;
394
- const files = await this.services.workspace.FileSystemProvider.scanProjectFiles(URI.parse(folder.uri));
395
- for (const file of files) {
396
- if (file.isFile && this.isConfigFile(file.uri)) {
397
- logger.debug `found config ${file.uri.fsPath}`;
398
- configFiles.push(file.uri);
399
- }
447
+ logger.debug `start reload projects`;
448
+ const configFiles = [];
449
+ for (const folder of folders) {
450
+ try {
451
+ logger.debug `scan projects in folder ${folder.uri}`;
452
+ const files = await this.services.workspace.FileSystemProvider.scanProjectFiles(URI.parse(folder.uri));
453
+ for (const file of files) {
454
+ if (file.isFile && this.isConfigFile(file.uri)) {
455
+ logger.debug `found config ${file.uri.fsPath}`;
456
+ configFiles.push(file.uri);
400
457
  }
401
458
  }
402
- catch (error) {
403
- logger.error('Failed to scanProjectFiles, {folder}', { folder: folder.uri, error });
404
- }
405
459
  }
406
- if (configFiles.length === 0 && this.#projects.length !== 0) {
407
- logger.warning('No config files found, but some projects were registered before');
460
+ catch (error) {
461
+ logger.error('Failed to scanProjectFiles, {folder}', { folder: folder.uri, error });
408
462
  }
409
- await interruptAndCheck(cancelToken);
410
- this.#projects = [];
411
- this.#projectIdToFolder.clear();
412
- for (const uri of configFiles) {
413
- try {
414
- await this.registerConfigFile(uri);
415
- }
416
- catch (error) {
417
- logger.error('Failed to load config file {uri}', { uri: uri.fsPath, error });
418
- }
463
+ }
464
+ if (configFiles.length === 0 && this.#projects.length !== 0) {
465
+ logger.warning('No config files found, but some projects were registered before');
466
+ }
467
+ this.#projects = [];
468
+ this.#projectIdToFolder.clear();
469
+ this.#lookupById.clear();
470
+ for (const uri of configFiles) {
471
+ if (cancelToken) {
472
+ await interruptAndCheck(cancelToken);
419
473
  }
420
- this.reset();
421
- await this.services.workspace.WorkspaceManager.rebuildAll(cancelToken);
422
- });
474
+ try {
475
+ await this.registerConfigFile(uri, cancelToken);
476
+ }
477
+ catch (error) {
478
+ logger.error('Failed to load config file {uri}', { uri: uri.fsPath, error });
479
+ }
480
+ }
481
+ this.reset();
482
+ await this.services.workspace.WorkspaceManager.rebuildAll(cancelToken);
423
483
  }
424
484
  uniqueProjectId(name) {
425
485
  let id = name;
@@ -430,28 +490,18 @@ export class ProjectsManager {
430
490
  return id;
431
491
  }
432
492
  reset() {
493
+ logger.debug('reset');
433
494
  this.#defaultProject = undefined;
434
495
  if (this.#defaultProjectId && !this.#projectIdToFolder.has(this.#defaultProjectId)) {
435
496
  this.#defaultProjectId = undefined;
436
497
  }
437
- this.services.workspace.LangiumDocuments.all.forEach(doc => {
438
- if (isLikeC4Builtin(doc.uri)) {
439
- return;
440
- }
441
- // Remove assigned project ID to force re-calculation
442
- delete doc.likec4ProjectId;
443
- });
498
+ this.services.workspace.LangiumDocuments.resetProjectIds();
444
499
  this.documentBelongsTo.clear();
445
500
  this.mappingsToProject.clear();
501
+ this.#lookupById.clear();
446
502
  this.#excludedDocuments = new WeakMap();
447
503
  }
448
504
  async rebuidProject(projectId, cancelToken) {
449
- if (!cancelToken) {
450
- return await this.services.workspace.WorkspaceLock.write(async (ct) => {
451
- await this.rebuidProject(projectId, ct);
452
- });
453
- }
454
- logger.info `rebuild project ${projectId}`;
455
505
  // reset default project cache
456
506
  this.#defaultProject = undefined;
457
507
  const project = this.#projects.find(p => p.id === projectId) ?? this.default;
@@ -460,18 +510,18 @@ export class ProjectsManager {
460
510
  }
461
511
  const log = logger.getChild(project.id);
462
512
  const folder = project.folder;
463
- const includePathStrings = project.includePaths?.map(p => p.folder) ?? [];
513
+ const includePaths = project.includePaths;
464
514
  const docs = this.services.workspace.LangiumDocuments
465
515
  .all
466
516
  .filter(doc => {
467
517
  if (project.exclude?.(doc.uri.path)) {
468
518
  return false;
469
519
  }
470
- const docUriStr = doc.uri.toString();
520
+ const docUriStr = normalizeUri(doc.uri);
471
521
  if (docUriStr.startsWith(folder)) {
472
522
  return true;
473
523
  }
474
- if (includePathStrings.some(includePath => docUriStr.startsWith(includePath))) {
524
+ if (includePaths && includePaths.some(isParentFolderFor(docUriStr))) {
475
525
  return true;
476
526
  }
477
527
  const docdir = withTrailingSlash(joinRelativeURL(docUriStr, '..'));
@@ -480,10 +530,10 @@ export class ProjectsManager {
480
530
  .map(d => d.uri)
481
531
  .toArray();
482
532
  if (docs.length > 0) {
483
- this.reset();
484
- log.info('rebuild documents: {docs}', {
533
+ log.info('rebuild project documents: {docs}', {
485
534
  docs: docs.length,
486
535
  });
536
+ this.reset();
487
537
  await this.services.workspace.DocumentBuilder
488
538
  .update(docs, [], cancelToken)
489
539
  .catch(error => {
@@ -492,23 +542,22 @@ export class ProjectsManager {
492
542
  });
493
543
  });
494
544
  }
545
+ else {
546
+ log.debug('no documents in project, skipping rebuild');
547
+ }
495
548
  }
496
549
  findProjectForDocument(documentUri) {
497
550
  return this.mappingsToProject.get(documentUri, () => {
498
- const project = this.#projects.find(({ folder }) => documentUri.startsWith(folder));
551
+ const hasThisDoc = isParentFolderFor(documentUri);
552
+ const project = this.#projects.find(hasThisDoc);
499
553
  if (project) {
500
554
  return project;
501
555
  }
502
- const projectWithInclude = this.#projects.find(({ includePaths }) => {
503
- if (!includePaths)
504
- return false;
505
- return includePaths.some(includePath => documentUri.startsWith(includePath.folder));
556
+ const projectIncludingThisDoc = this.#projects.find(({ includePaths }) => {
557
+ return !!includePaths && includePaths.some(hasThisDoc);
506
558
  });
507
- if (projectWithInclude) {
508
- return projectWithInclude;
509
- }
510
559
  // If the document is not part of any project, assign it to the global project ID
511
- return this.default;
560
+ return projectIncludingThisDoc ?? this.default;
512
561
  });
513
562
  }
514
563
  // The mapping between document URIs and their corresponding project ID
@@ -553,3 +602,4 @@ export class ProjectsManager {
553
602
  }
554
603
  }
555
604
  }
605
+ _a = ProjectsManager;
@@ -1,6 +1,6 @@
1
1
  import type { BuildOptions, Cancellation, FileSelector, FileSystemNode, LangiumDocument, LangiumDocumentFactory } from 'langium';
2
2
  import { DefaultWorkspaceManager } from 'langium';
3
- import type { WorkspaceFolder } from 'vscode-languageserver';
3
+ import { type WorkspaceFolder } from 'vscode-languageserver';
4
4
  import { URI } from 'vscode-uri';
5
5
  import type { FileSystemProvider } from '../filesystem';
6
6
  import type { LikeC4SharedServices } from '../module';
@@ -1,6 +1,7 @@
1
1
  import { invariant } from '@likec4/core';
2
2
  import { DefaultWorkspaceManager } from 'langium';
3
3
  import { hasAtLeast } from 'remeda';
4
+ import { CancellationToken } from 'vscode-languageserver';
4
5
  import { URI } from 'vscode-uri';
5
6
  import * as BuiltIn from '../likec4lib';
6
7
  import { logger, logWarnError } from '../logger';
@@ -39,7 +40,7 @@ export class LikeC4WorkspaceManager extends DefaultWorkspaceManager {
39
40
  const projects = this.services.workspace.ProjectsManager;
40
41
  for (const entry of configFiles) {
41
42
  try {
42
- await projects.registerConfigFile(entry.uri);
43
+ await projects.registerConfigFile(entry.uri, CancellationToken.None);
43
44
  }
44
45
  catch (error) {
45
46
  logWarnError(error);
@@ -113,11 +114,6 @@ export class LikeC4WorkspaceManager extends DefaultWorkspaceManager {
113
114
  return null;
114
115
  }
115
116
  async rebuildAll(cancelToken) {
116
- if (!cancelToken) {
117
- return await this.services.workspace.WorkspaceLock.write(async (ct) => {
118
- await this.rebuildAll(ct);
119
- });
120
- }
121
117
  const docs = this.services.workspace.LangiumDocuments.all.map(d => d.uri).toArray();
122
118
  logger.info('invalidate and rebuild all {docs} documents', { docs: docs.length });
123
119
  this.services.workspace.Cache.clear();
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.46.2",
4
+ "version": "1.46.4",
5
5
  "license": "MIT",
6
6
  "bugs": "https://github.com/likec4/likec4/issues",
7
7
  "homepage": "https://likec4.dev",
@@ -76,7 +76,7 @@
76
76
  "access": "public"
77
77
  },
78
78
  "dependencies": {
79
- "@hpcc-js/wasm-graphviz": "1.16.0",
79
+ "@hpcc-js/wasm-graphviz": "1.17.0",
80
80
  "bundle-require": "^5.1.0",
81
81
  "esbuild": "0.27.1"
82
82
  },
@@ -86,14 +86,14 @@
86
86
  "@msgpack/msgpack": "^3.1.2",
87
87
  "@smithy/util-base64": "^4.3.0",
88
88
  "@types/natural-compare-lite": "^1.4.2",
89
- "@types/node": "~22.19.1",
89
+ "@types/node": "~22.19.3",
90
90
  "@types/picomatch": "^4.0.2",
91
91
  "@types/vscode": "^1.106.1",
92
92
  "@types/which": "^3.0.4",
93
- "chokidar": "^4.0.3",
93
+ "chokidar": "^5.0.0",
94
94
  "defu": "^6.1.4",
95
95
  "esm-env": "^1.2.2",
96
- "fast-equals": "^5.3.3",
96
+ "fast-equals": "^5.4.0",
97
97
  "fdir": "6.4.0",
98
98
  "fetch-to-node": "^2.1.0",
99
99
  "hono": "^4.11.1",
@@ -102,7 +102,7 @@
102
102
  "json5": "^2.2.3",
103
103
  "langium": "3.5.0",
104
104
  "langium-cli": "3.5.2",
105
- "nano-spawn": "^1.0.3",
105
+ "nano-spawn": "^2.0.0",
106
106
  "natural-compare-lite": "^1.4.0",
107
107
  "oxlint": "1.33.0",
108
108
  "p-debounce": "4.0.0",
@@ -126,13 +126,13 @@
126
126
  "vscode-uri": "3.1.0",
127
127
  "which": "^5.0.0",
128
128
  "zod": "^3.25.76",
129
- "@likec4/config": "1.46.2",
130
- "@likec4/layouts": "1.46.2",
129
+ "@likec4/config": "1.46.4",
130
+ "@likec4/core": "1.46.4",
131
+ "@likec4/devops": "1.42.0",
132
+ "@likec4/icons": "1.46.4",
131
133
  "@likec4/log": "1.46.1",
132
- "@likec4/icons": "1.46.1",
133
- "@likec4/core": "1.46.2",
134
- "@likec4/tsconfig": "1.46.1",
135
- "@likec4/devops": "1.42.0"
134
+ "@likec4/layouts": "1.46.4",
135
+ "@likec4/tsconfig": "1.46.1"
136
136
  },
137
137
  "scripts": {
138
138
  "typecheck": "tsc -b --verbose",