@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.
- package/dist/Rpc.js +66 -64
- package/dist/bundled.mjs +3249 -3173
- package/dist/generated/ast.js +2 -2
- package/dist/generated/grammar.js +1 -1
- package/dist/generated-lib/icons.js +7 -1
- package/dist/model/model-builder.js +6 -14
- package/dist/model-change/ModelChanges.js +69 -72
- package/dist/references/scope-provider.d.ts +1 -1
- package/dist/references/scope-provider.js +18 -21
- package/dist/workspace/IndexManager.js +4 -8
- package/dist/workspace/LangiumDocuments.d.ts +8 -2
- package/dist/workspace/LangiumDocuments.js +33 -25
- package/dist/workspace/ProjectsManager.d.ts +15 -8
- package/dist/workspace/ProjectsManager.js +131 -81
- package/dist/workspace/WorkspaceManager.d.ts +1 -1
- package/dist/workspace/WorkspaceManager.js +2 -6
- package/package.json +12 -12
- package/lib/package.json +0 -159
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
var _a;
|
|
1
2
|
import { isLikeC4Config, normalizeIncludeConfig, validateProjectConfig, } from '@likec4/config';
|
|
2
|
-
import { BiMap,
|
|
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 ??
|
|
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 ===
|
|
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 ??
|
|
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:
|
|
172
|
+
id: _a.DefaultProjectId,
|
|
149
173
|
config: DefaultProject.config,
|
|
150
174
|
folderUri,
|
|
151
175
|
};
|
|
152
176
|
}
|
|
153
|
-
const project = nonNullable(this.#
|
|
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
|
|
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 ===
|
|
168
|
-
return this.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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
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
|
-
|
|
407
|
-
logger.
|
|
460
|
+
catch (error) {
|
|
461
|
+
logger.error('Failed to scanProjectFiles, {folder}', { folder: folder.uri, error });
|
|
408
462
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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
|
-
|
|
421
|
-
|
|
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.
|
|
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
|
|
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
|
|
520
|
+
const docUriStr = normalizeUri(doc.uri);
|
|
471
521
|
if (docUriStr.startsWith(folder)) {
|
|
472
522
|
return true;
|
|
473
523
|
}
|
|
474
|
-
if (
|
|
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
|
-
|
|
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
|
|
551
|
+
const hasThisDoc = isParentFolderFor(documentUri);
|
|
552
|
+
const project = this.#projects.find(hasThisDoc);
|
|
499
553
|
if (project) {
|
|
500
554
|
return project;
|
|
501
555
|
}
|
|
502
|
-
const
|
|
503
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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": "^
|
|
93
|
+
"chokidar": "^5.0.0",
|
|
94
94
|
"defu": "^6.1.4",
|
|
95
95
|
"esm-env": "^1.2.2",
|
|
96
|
-
"fast-equals": "^5.
|
|
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": "^
|
|
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.
|
|
130
|
-
"@likec4/
|
|
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/
|
|
133
|
-
"@likec4/
|
|
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",
|